From 4e5b97895447cc10f0477c8953925c1b22d76eb1 Mon Sep 17 00:00:00 2001 From: mturk Date: Thu, 20 Jul 2006 12:50:34 +0000 Subject: [PATCH] Phase 1: Setting eol and mime types @echo off if "%OS%" == "Windows_NT" setlocal if "%1" == "" ( set SCRIPT_NAME=%~f0 ) else ( set SCRIPT_NAME=%~f1 ) for /D %%i in (*) do ( cd %%i svn propset svn:eol-style native *.java svn propset svn:eol-style native *.properties svn propset svn:eol-style native *.xml svn propset svn:eol-style native *.xsd svn propset svn:eol-style native *.xsl svn propset svn:eol-style native *.dtd svn propset svn:eol-style native *.tld svn propset svn:eol-style native *.html svn propset svn:eol-style native *.txt svn propset svn:eol-style native *.jsp svn propset svn:eol-style native *.jspx svn propset svn:eol-style native *.jspf svn propset svn:eol-style native *.sh svn propset svn:eol-style native *.bat svn propset svn:eol-style native *.svg svn propset svn:mime-type image/gif *.gif svn propset svn:mime-type image/jpeg *.jpg svn propset svn:mime-type image/bmp *.bmp svn propset svn:mime-type application/pdf *.pdf svn propset svn:mime-type application/pdf *.pdf svn propset svn:mime-type image/x-icon *.ico call %SCRIPT_NAME% %SCRIPT_NAME% cd .. ) git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@423920 13f79535-47bb-0310-9956-ffa450edef68 --- BUILDING.txt | 4 +- README.txt | 4 +- build.xml | 886 +- java/javax/annotation/Generated.java | 68 +- java/javax/annotation/PostConstruct.java | 58 +- java/javax/annotation/PreDestroy.java | 58 +- java/javax/annotation/Resource.java | 78 +- java/javax/annotation/Resources.java | 60 +- java/javax/annotation/security/DenyAll.java | 58 +- java/javax/annotation/security/PermitAll.java | 58 +- java/javax/annotation/security/RolesAllowed.java | 60 +- java/javax/annotation/security/RunAs.java | 60 +- java/javax/el/ArrayELResolver.java | 304 +- java/javax/el/BeanELResolver.java | 660 +- java/javax/el/CompositeELResolver.java | 348 +- java/javax/el/ELContext.java | 162 +- java/javax/el/ELContextEvent.java | 74 +- java/javax/el/ELContextListener.java | 54 +- java/javax/el/ELException.java | 130 +- java/javax/el/ELResolver.java | 136 +- java/javax/el/Expression.java | 68 +- java/javax/el/ExpressionFactory.java | 78 +- java/javax/el/FunctionMapper.java | 56 +- java/javax/el/ListELResolver.java | 336 +- java/javax/el/LocalStrings.properties | 44 +- java/javax/el/MapELResolver.java | 280 +- java/javax/el/MethodExpression.java | 54 +- java/javax/el/MethodInfo.java | 102 +- java/javax/el/MethodNotFoundException.java | 104 +- java/javax/el/PropertyNotFoundException.java | 106 +- java/javax/el/PropertyNotWritableException.java | 104 +- java/javax/el/ResourceBundleELResolver.java | 254 +- java/javax/el/ValueExpression.java | 68 +- java/javax/el/VariableMapper.java | 54 +- java/javax/mail/Authenticator.java | 10 +- java/javax/mail/PasswordAuthentication.java | 12 +- java/javax/mail/Session.java | 24 +- java/javax/mail/internet/InternetAddress.java | 12 +- java/javax/mail/internet/MimeMessage.java | 24 +- java/javax/mail/internet/MimePart.java | 8 +- java/javax/mail/internet/MimePartDataSource.java | 12 +- java/javax/persistence/PersistenceContext.java | 72 +- java/javax/persistence/PersistenceContexts.java | 60 +- java/javax/persistence/PersistenceUnit.java | 62 +- java/javax/persistence/PersistenceUnits.java | 62 +- java/javax/servlet/Filter.java | 182 +- java/javax/servlet/FilterChain.java | 90 +- java/javax/servlet/FilterConfig.java | 182 +- java/javax/servlet/GenericServlet.java | 646 +- java/javax/servlet/LocalStrings.properties | 40 +- java/javax/servlet/LocalStrings_fr.properties | 44 +- java/javax/servlet/LocalStrings_ja.properties | 40 +- java/javax/servlet/RequestDispatcher.java | 276 +- java/javax/servlet/Servlet.java | 384 +- java/javax/servlet/ServletConfig.java | 188 +- java/javax/servlet/ServletContext.java | 1290 +-- .../servlet/ServletContextAttributeEvent.java | 118 +- .../servlet/ServletContextAttributeListener.java | 72 +- java/javax/servlet/ServletContextEvent.java | 92 +- java/javax/servlet/ServletContextListener.java | 100 +- java/javax/servlet/ServletException.java | 282 +- java/javax/servlet/ServletInputStream.java | 210 +- java/javax/servlet/ServletOutputStream.java | 726 +- java/javax/servlet/ServletRequest.java | 1194 +- .../servlet/ServletRequestAttributeEvent.java | 132 +- .../servlet/ServletRequestAttributeListener.java | 98 +- java/javax/servlet/ServletRequestEvent.java | 110 +- java/javax/servlet/ServletRequestListener.java | 78 +- java/javax/servlet/ServletRequestWrapper.java | 800 +- java/javax/servlet/ServletResponse.java | 904 +- java/javax/servlet/ServletResponseWrapper.java | 434 +- java/javax/servlet/SingleThreadModel.java | 96 +- java/javax/servlet/UnavailableException.java | 410 +- java/javax/servlet/http/Cookie.java | 1072 +- java/javax/servlet/http/HttpServlet.java | 2036 ++-- java/javax/servlet/http/HttpServletRequest.java | 1320 +-- .../servlet/http/HttpServletRequestWrapper.java | 524 +- java/javax/servlet/http/HttpServletResponse.java | 1272 +-- .../servlet/http/HttpServletResponseWrapper.java | 390 +- java/javax/servlet/http/HttpSession.java | 846 +- .../http/HttpSessionActivationListener.java | 72 +- .../servlet/http/HttpSessionAttributeListener.java | 70 +- .../servlet/http/HttpSessionBindingEvent.java | 302 +- .../servlet/http/HttpSessionBindingListener.java | 154 +- java/javax/servlet/http/HttpSessionContext.java | 140 +- java/javax/servlet/http/HttpSessionEvent.java | 66 +- java/javax/servlet/http/HttpSessionListener.java | 88 +- java/javax/servlet/http/HttpUtils.java | 612 +- java/javax/servlet/http/LocalStrings.properties | 54 +- java/javax/servlet/http/LocalStrings_es.properties | 58 +- java/javax/servlet/http/LocalStrings_fr.properties | 54 +- java/javax/servlet/http/LocalStrings_ja.properties | 54 +- java/javax/servlet/http/package.html | 46 +- java/javax/servlet/jsp/ErrorData.java | 176 +- java/javax/servlet/jsp/HttpJspPage.java | 114 +- java/javax/servlet/jsp/JspApplicationContext.java | 152 +- java/javax/servlet/jsp/JspContext.java | 548 +- java/javax/servlet/jsp/JspEngineInfo.java | 94 +- java/javax/servlet/jsp/JspException.java | 224 +- java/javax/servlet/jsp/JspFactory.java | 310 +- java/javax/servlet/jsp/JspPage.java | 178 +- java/javax/servlet/jsp/JspTagException.java | 184 +- java/javax/servlet/jsp/JspWriter.java | 884 +- java/javax/servlet/jsp/PageContext.java | 1044 +- java/javax/servlet/jsp/SkipPageException.java | 150 +- java/javax/servlet/jsp/el/ELException.java | 184 +- java/javax/servlet/jsp/el/ELParseException.java | 100 +- java/javax/servlet/jsp/el/Expression.java | 104 +- java/javax/servlet/jsp/el/ExpressionEvaluator.java | 214 +- java/javax/servlet/jsp/el/FunctionMapper.java | 78 +- .../servlet/jsp/el/ImplicitObjectELResolver.java | 1076 +- .../servlet/jsp/el/ScopedAttributeELResolver.java | 364 +- java/javax/servlet/jsp/el/VariableResolver.java | 100 +- java/javax/servlet/jsp/el/package.html | 150 +- java/javax/servlet/jsp/package.html | 134 +- java/javax/servlet/jsp/tagext/BodyContent.java | 276 +- java/javax/servlet/jsp/tagext/BodyTag.java | 370 +- java/javax/servlet/jsp/tagext/BodyTagSupport.java | 318 +- .../servlet/jsp/tagext/DynamicAttributes.java | 102 +- java/javax/servlet/jsp/tagext/FunctionInfo.java | 160 +- java/javax/servlet/jsp/tagext/IterationTag.java | 238 +- java/javax/servlet/jsp/tagext/JspFragment.java | 164 +- java/javax/servlet/jsp/tagext/JspIdConsumer.java | 10 +- java/javax/servlet/jsp/tagext/JspTag.java | 50 +- java/javax/servlet/jsp/tagext/PageData.java | 96 +- java/javax/servlet/jsp/tagext/SimpleTag.java | 278 +- .../javax/servlet/jsp/tagext/SimpleTagSupport.java | 424 +- java/javax/servlet/jsp/tagext/Tag.java | 524 +- java/javax/servlet/jsp/tagext/TagAdapter.java | 316 +- .../javax/servlet/jsp/tagext/TagAttributeInfo.java | 468 +- java/javax/servlet/jsp/tagext/TagData.java | 306 +- java/javax/servlet/jsp/tagext/TagExtraInfo.java | 286 +- java/javax/servlet/jsp/tagext/TagFileInfo.java | 170 +- java/javax/servlet/jsp/tagext/TagInfo.java | 892 +- java/javax/servlet/jsp/tagext/TagLibraryInfo.java | 572 +- .../servlet/jsp/tagext/TagLibraryValidator.java | 286 +- java/javax/servlet/jsp/tagext/TagSupport.java | 586 +- java/javax/servlet/jsp/tagext/TagVariableInfo.java | 240 +- java/javax/servlet/jsp/tagext/TryCatchFinally.java | 196 +- .../servlet/jsp/tagext/ValidationMessage.java | 170 +- java/javax/servlet/jsp/tagext/VariableInfo.java | 566 +- java/javax/servlet/jsp/tagext/package.html | 170 +- java/javax/servlet/package.html | 46 +- java/javax/xml/ws/WebServiceRef.java | 68 +- java/javax/xml/ws/WebServiceRefs.java | 60 +- java/org/apache/catalina/Authenticator.java | 70 +- java/org/apache/catalina/Cluster.java | 356 +- java/org/apache/catalina/Contained.java | 106 +- java/org/apache/catalina/Container.java | 884 +- java/org/apache/catalina/ContainerEvent.java | 222 +- java/org/apache/catalina/ContainerListener.java | 86 +- java/org/apache/catalina/ContainerServlet.java | 104 +- java/org/apache/catalina/Context.java | 2122 ++-- java/org/apache/catalina/Engine.java | 190 +- java/org/apache/catalina/Globals.java | 648 +- java/org/apache/catalina/Group.java | 244 +- java/org/apache/catalina/Host.java | 436 +- java/org/apache/catalina/InstanceEvent.java | 896 +- java/org/apache/catalina/InstanceListener.java | 82 +- java/org/apache/catalina/Lifecycle.java | 282 +- java/org/apache/catalina/LifecycleEvent.java | 250 +- java/org/apache/catalina/LifecycleException.java | 288 +- java/org/apache/catalina/LifecycleListener.java | 86 +- java/org/apache/catalina/Loader.java | 336 +- java/org/apache/catalina/Manager.java | 730 +- java/org/apache/catalina/Pipeline.java | 240 +- java/org/apache/catalina/Realm.java | 402 +- java/org/apache/catalina/Role.java | 150 +- java/org/apache/catalina/Server.java | 304 +- java/org/apache/catalina/ServerFactory.java | 152 +- java/org/apache/catalina/Service.java | 262 +- java/org/apache/catalina/Session.java | 604 +- java/org/apache/catalina/SessionEvent.java | 222 +- java/org/apache/catalina/SessionListener.java | 82 +- java/org/apache/catalina/Store.java | 288 +- java/org/apache/catalina/User.java | 346 +- java/org/apache/catalina/UserDatabase.java | 346 +- java/org/apache/catalina/Valve.java | 264 +- java/org/apache/catalina/Wrapper.java | 660 +- .../apache/catalina/ant/AbstractCatalinaTask.java | 576 +- .../catalina/ant/BaseRedirectorHelperTask.java | 740 +- java/org/apache/catalina/ant/DeployTask.java | 410 +- java/org/apache/catalina/ant/InstallTask.java | 236 +- .../apache/catalina/ant/JKStatusUpdateTask.java | 828 +- java/org/apache/catalina/ant/JMXGetTask.java | 190 +- java/org/apache/catalina/ant/JMXQueryTask.java | 156 +- java/org/apache/catalina/ant/JMXSetTask.java | 236 +- java/org/apache/catalina/ant/ListTask.java | 108 +- java/org/apache/catalina/ant/ReloadTask.java | 162 +- java/org/apache/catalina/ant/RemoveTask.java | 148 +- java/org/apache/catalina/ant/ResourcesTask.java | 146 +- java/org/apache/catalina/ant/RolesTask.java | 108 +- java/org/apache/catalina/ant/ServerinfoTask.java | 94 +- java/org/apache/catalina/ant/SessionsTask.java | 150 +- java/org/apache/catalina/ant/StartTask.java | 160 +- java/org/apache/catalina/ant/StopTask.java | 160 +- java/org/apache/catalina/ant/UndeployTask.java | 142 +- java/org/apache/catalina/ant/ValidatorTask.java | 228 +- java/org/apache/catalina/ant/antlib.xml | 82 +- java/org/apache/catalina/ant/jmx/Arg.java | 92 +- .../catalina/ant/jmx/JMXAccessorCondition.java | 800 +- .../catalina/ant/jmx/JMXAccessorCreateTask.java | 412 +- .../ant/jmx/JMXAccessorEqualsCondition.java | 500 +- .../catalina/ant/jmx/JMXAccessorGetTask.java | 288 +- .../catalina/ant/jmx/JMXAccessorInvokeTask.java | 412 +- .../catalina/ant/jmx/JMXAccessorQueryTask.java | 428 +- .../catalina/ant/jmx/JMXAccessorSetTask.java | 440 +- .../apache/catalina/ant/jmx/JMXAccessorTask.java | 1462 +-- .../ant/jmx/JMXAccessorUnregisterTask.java | 224 +- java/org/apache/catalina/ant/jmx/antlib.xml | 58 +- java/org/apache/catalina/ant/jmx/package.html | 122 +- java/org/apache/catalina/ant/package.html | 172 +- .../catalina/authenticator/AuthenticatorBase.java | 1760 +-- .../catalina/authenticator/BasicAuthenticator.java | 422 +- .../apache/catalina/authenticator/Constants.java | 274 +- .../authenticator/DigestAuthenticator.java | 848 +- .../catalina/authenticator/FormAuthenticator.java | 1048 +- .../catalina/authenticator/LocalStrings.properties | 28 +- .../authenticator/LocalStrings_es.properties | 24 +- .../authenticator/LocalStrings_fr.properties | 24 +- .../authenticator/LocalStrings_ja.properties | 26 +- .../authenticator/NonLoginAuthenticator.java | 204 +- .../catalina/authenticator/SSLAuthenticator.java | 392 +- .../catalina/authenticator/SavedRequest.java | 360 +- .../catalina/authenticator/SingleSignOn.java | 1402 +-- .../catalina/authenticator/SingleSignOnEntry.java | 378 +- .../catalina/authenticator/mbeans-descriptors.xml | 296 +- .../org/apache/catalina/authenticator/package.html | 76 +- .../catalina/connector/ClientAbortException.java | 288 +- java/org/apache/catalina/connector/Constants.java | 96 +- .../apache/catalina/connector/CoyoteAdapter.java | 1414 +-- .../catalina/connector/CoyoteInputStream.java | 466 +- .../catalina/connector/CoyoteOutputStream.java | 234 +- .../apache/catalina/connector/CoyotePrincipal.java | 148 +- .../apache/catalina/connector/CoyoteReader.java | 414 +- .../apache/catalina/connector/CoyoteWriter.java | 576 +- .../org/apache/catalina/connector/InputBuffer.java | 1010 +- .../catalina/connector/LocalStrings.properties | 128 +- .../catalina/connector/LocalStrings_es.properties | 112 +- .../catalina/connector/LocalStrings_fr.properties | 116 +- .../catalina/connector/LocalStrings_ja.properties | 116 +- .../apache/catalina/connector/MapperListener.java | 1008 +- .../apache/catalina/connector/OutputBuffer.java | 1158 +- java/org/apache/catalina/connector/Request.java | 5100 ++++----- .../apache/catalina/connector/RequestFacade.java | 1866 ++-- java/org/apache/catalina/connector/Response.java | 3126 +++--- .../apache/catalina/connector/ResponseFacade.java | 1106 +- .../catalina/connector/mbeans-descriptors.xml | 396 +- .../apache/catalina/core/ApplicationContext.java | 1948 ++-- .../catalina/core/ApplicationContextFacade.java | 1016 +- .../catalina/core/ApplicationDispatcher.java | 1922 ++-- .../catalina/core/ApplicationFilterChain.java | 684 +- .../catalina/core/ApplicationFilterConfig.java | 692 +- .../catalina/core/ApplicationFilterFactory.java | 738 +- .../catalina/core/ApplicationHttpRequest.java | 1900 ++-- .../catalina/core/ApplicationHttpResponse.java | 786 +- .../apache/catalina/core/ApplicationRequest.java | 418 +- .../apache/catalina/core/ApplicationResponse.java | 402 +- .../apache/catalina/core/AprLifecycleListener.java | 236 +- java/org/apache/catalina/core/Constants.java | 62 +- java/org/apache/catalina/core/ContainerBase.java | 3172 +++--- java/org/apache/catalina/core/DummyRequest.java | 534 +- java/org/apache/catalina/core/DummyResponse.java | 248 +- .../apache/catalina/core/LocalStrings.properties | 374 +- .../catalina/core/LocalStrings_es.properties | 344 +- .../catalina/core/LocalStrings_fr.properties | 328 +- .../catalina/core/LocalStrings_ja.properties | 344 +- .../catalina/core/NamingContextListener.java | 2050 ++-- java/org/apache/catalina/core/StandardContext.java | 11162 +++++++++---------- .../apache/catalina/core/StandardContextValve.java | 540 +- java/org/apache/catalina/core/StandardEngine.java | 1074 +- .../apache/catalina/core/StandardEngineValve.java | 222 +- java/org/apache/catalina/core/StandardHost.java | 1644 +-- .../apache/catalina/core/StandardHostValve.java | 764 +- .../org/apache/catalina/core/StandardPipeline.java | 1122 +- java/org/apache/catalina/core/StandardServer.java | 1652 +-- java/org/apache/catalina/core/StandardService.java | 1260 +-- java/org/apache/catalina/core/StandardWrapper.java | 3768 +++---- .../catalina/core/StandardWrapperFacade.java | 176 +- .../apache/catalina/core/StandardWrapperValve.java | 772 +- .../apache/catalina/core/mbeans-descriptors.xml | 1388 +-- .../catalina/deploy/ApplicationParameter.java | 242 +- java/org/apache/catalina/deploy/ContextEjb.java | 236 +- .../apache/catalina/deploy/ContextEnvironment.java | 310 +- .../apache/catalina/deploy/ContextLocalEjb.java | 230 +- .../apache/catalina/deploy/ContextResource.java | 198 +- .../catalina/deploy/ContextResourceEnvRef.java | 150 +- .../catalina/deploy/ContextResourceLink.java | 152 +- .../org/apache/catalina/deploy/ContextService.java | 470 +- .../apache/catalina/deploy/ContextTransaction.java | 210 +- java/org/apache/catalina/deploy/ErrorPage.java | 340 +- java/org/apache/catalina/deploy/FilterDef.java | 342 +- java/org/apache/catalina/deploy/FilterMap.java | 468 +- java/org/apache/catalina/deploy/LoginConfig.java | 332 +- .../apache/catalina/deploy/MessageDestination.java | 280 +- .../catalina/deploy/MessageDestinationRef.java | 318 +- .../apache/catalina/deploy/NamingResources.java | 1566 +-- java/org/apache/catalina/deploy/ResourceBase.java | 264 +- .../apache/catalina/deploy/SecurityCollection.java | 696 +- .../apache/catalina/deploy/SecurityConstraint.java | 918 +- .../apache/catalina/deploy/mbeans-descriptors.xml | 370 +- java/org/apache/catalina/deploy/package.html | 20 +- java/org/apache/catalina/loader/Constants.java | 50 +- .../catalina/loader/LocaStrings_fr.properties | 60 +- .../apache/catalina/loader/LocalStrings.properties | 62 +- .../catalina/loader/LocalStrings_es.properties | 62 +- .../catalina/loader/LocalStrings_ja.properties | 62 +- java/org/apache/catalina/loader/Reloader.java | 122 +- java/org/apache/catalina/loader/ResourceEntry.java | 154 +- .../catalina/loader/StandardClassLoader.java | 120 +- .../catalina/loader/StandardClassLoaderMBean.java | 56 +- .../apache/catalina/loader/WebappClassLoader.java | 4694 ++++---- java/org/apache/catalina/loader/WebappLoader.java | 2454 ++-- .../apache/catalina/loader/mbeans-descriptors.xml | 118 +- java/org/apache/catalina/mbeans-descriptors.xml | 300 +- .../org/apache/catalina/mbeans/ClassNameMBean.java | 152 +- .../org/apache/catalina/mbeans/ConnectorMBean.java | 280 +- .../catalina/mbeans/ContextEnvironmentMBean.java | 210 +- .../catalina/mbeans/ContextResourceLinkMBean.java | 210 +- .../catalina/mbeans/ContextResourceMBean.java | 368 +- .../catalina/mbeans/DefaultContextMBean.java | 656 +- .../mbeans/GlobalResourcesLifecycleListener.java | 472 +- java/org/apache/catalina/mbeans/GroupMBean.java | 382 +- java/org/apache/catalina/mbeans/MBeanFactory.java | 2152 ++-- java/org/apache/catalina/mbeans/MBeanUtils.java | 3746 +++---- .../catalina/mbeans/MemoryUserDatabaseMBean.java | 790 +- .../catalina/mbeans/NamingResourcesMBean.java | 646 +- java/org/apache/catalina/mbeans/RoleMBean.java | 176 +- .../catalina/mbeans/ServerLifecycleListener.java | 2822 ++--- .../catalina/mbeans/StandardContextMBean.java | 714 +- .../catalina/mbeans/StandardEngineMBean.java | 138 +- .../apache/catalina/mbeans/StandardHostMBean.java | 298 +- .../catalina/mbeans/StandardServerMBean.java | 204 +- .../catalina/mbeans/StandardServiceMBean.java | 138 +- java/org/apache/catalina/mbeans/UserMBean.java | 466 +- .../apache/catalina/mbeans/mbeans-descriptors.xml | 810 +- java/org/apache/catalina/realm/Constants.java | 88 +- .../org/apache/catalina/realm/DataSourceRealm.java | 1324 +-- .../apache/catalina/realm/GenericPrincipal.java | 398 +- .../apache/catalina/realm/JAASCallbackHandler.java | 288 +- .../catalina/realm/JAASMemoryLoginModule.java | 772 +- java/org/apache/catalina/realm/JAASRealm.java | 1142 +- java/org/apache/catalina/realm/JDBCRealm.java | 1582 +-- java/org/apache/catalina/realm/JNDIRealm.java | 3594 +++--- .../apache/catalina/realm/LocalStrings.properties | 144 +- .../catalina/realm/LocalStrings_es.properties | 94 +- .../catalina/realm/LocalStrings_fr.properties | 82 +- .../catalina/realm/LocalStrings_ja.properties | 94 +- java/org/apache/catalina/realm/MemoryRealm.java | 680 +- java/org/apache/catalina/realm/MemoryRuleSet.java | 268 +- java/org/apache/catalina/realm/RealmBase.java | 2852 ++--- .../apache/catalina/realm/UserDatabaseRealm.java | 570 +- .../apache/catalina/realm/mbeans-descriptors.xml | 596 +- java/org/apache/catalina/realm/package.html | 128 +- .../catalina/security/LocalStrings.properties | 4 +- .../catalina/security/LocalStrings_es.properties | 4 +- .../catalina/security/LocalStrings_fr.properties | 4 +- .../catalina/security/LocalStrings_ja.properties | 4 +- .../catalina/security/SecurityClassLoad.java | 402 +- .../apache/catalina/security/SecurityConfig.java | 266 +- .../org/apache/catalina/security/SecurityUtil.java | 768 +- java/org/apache/catalina/servlets/CGIServlet.java | 3904 +++---- java/org/apache/catalina/servlets/Constants.java | 52 +- .../apache/catalina/servlets/DefaultServlet.java | 4410 ++++---- .../catalina/servlets/InvokerHttpRequest.java | 396 +- .../apache/catalina/servlets/InvokerServlet.java | 994 +- .../catalina/servlets/LocalStrings.properties | 38 +- .../catalina/servlets/LocalStrings_es.properties | 36 +- .../catalina/servlets/LocalStrings_fr.properties | 36 +- .../catalina/servlets/LocalStrings_ja.properties | 36 +- .../apache/catalina/servlets/WebdavServlet.java | 6164 +++++----- java/org/apache/catalina/servlets/package.html | 34 +- java/org/apache/catalina/session/Constants.java | 62 +- java/org/apache/catalina/session/FileStore.java | 878 +- java/org/apache/catalina/session/JDBCStore.java | 1976 ++-- .../catalina/session/LocalStrings.properties | 134 +- .../catalina/session/LocalStrings_es.properties | 132 +- .../catalina/session/LocalStrings_fr.properties | 130 +- .../catalina/session/LocalStrings_ja.properties | 134 +- java/org/apache/catalina/session/ManagerBase.java | 2504 ++--- .../apache/catalina/session/PersistentManager.java | 152 +- .../catalina/session/PersistentManagerBase.java | 2260 ++-- .../apache/catalina/session/StandardManager.java | 1506 +-- .../apache/catalina/session/StandardSession.java | 3426 +++--- .../catalina/session/StandardSessionFacade.java | 316 +- java/org/apache/catalina/session/StoreBase.java | 530 +- .../apache/catalina/session/mbeans-descriptors.xml | 584 +- java/org/apache/catalina/session/package.html | 104 +- .../catalina/ssi/ByteArrayServletOutputStream.java | 124 +- .../apache/catalina/ssi/ExpressionParseTree.java | 764 +- .../apache/catalina/ssi/ExpressionTokenizer.java | 338 +- .../catalina/ssi/ResponseIncludeWrapper.java | 476 +- java/org/apache/catalina/ssi/SSICommand.java | 88 +- java/org/apache/catalina/ssi/SSIConditional.java | 264 +- .../apache/catalina/ssi/SSIConditionalState.java | 74 +- java/org/apache/catalina/ssi/SSIConfig.java | 104 +- java/org/apache/catalina/ssi/SSIEcho.java | 136 +- java/org/apache/catalina/ssi/SSIExec.java | 150 +- .../apache/catalina/ssi/SSIExternalResolver.java | 140 +- java/org/apache/catalina/ssi/SSIFilter.java | 384 +- java/org/apache/catalina/ssi/SSIFlastmod.java | 138 +- java/org/apache/catalina/ssi/SSIFsize.java | 230 +- java/org/apache/catalina/ssi/SSIInclude.java | 118 +- java/org/apache/catalina/ssi/SSIMediator.java | 648 +- java/org/apache/catalina/ssi/SSIPrintenv.java | 112 +- java/org/apache/catalina/ssi/SSIProcessor.java | 624 +- java/org/apache/catalina/ssi/SSIServlet.java | 462 +- .../catalina/ssi/SSIServletExternalResolver.java | 1132 +- .../apache/catalina/ssi/SSIServletRequestUtil.java | 140 +- java/org/apache/catalina/ssi/SSISet.java | 114 +- .../catalina/ssi/SSIStopProcessingException.java | 46 +- java/org/apache/catalina/ssi/package.html | 32 +- .../catalina/startup/Authenticators.properties | 10 +- java/org/apache/catalina/startup/Catalina.java | 1376 +-- .../catalina/startup/CatalinaProperties.java | 342 +- .../catalina/startup/ConnectorCreateRule.java | 110 +- java/org/apache/catalina/startup/Constants.java | 190 +- .../org/apache/catalina/startup/ContextConfig.java | 2752 ++--- .../apache/catalina/startup/ContextRuleSet.java | 584 +- .../startup/CopyParentClassLoaderRule.java | 152 +- .../apache/catalina/startup/DigesterFactory.java | 328 +- java/org/apache/catalina/startup/Embedded.java | 1986 ++-- java/org/apache/catalina/startup/EngineConfig.java | 222 +- .../org/apache/catalina/startup/EngineRuleSet.java | 298 +- java/org/apache/catalina/startup/ExpandWar.java | 668 +- .../apache/catalina/startup/HomesUserDatabase.java | 286 +- java/org/apache/catalina/startup/HostConfig.java | 2630 ++--- java/org/apache/catalina/startup/HostRuleSet.java | 290 +- .../catalina/startup/LifecycleListenerRule.java | 204 +- .../catalina/startup/LocalStrings.properties | 154 +- .../catalina/startup/LocalStrings_es.properties | 122 +- .../catalina/startup/LocalStrings_fr.properties | 118 +- .../catalina/startup/LocalStrings_ja.properties | 128 +- .../org/apache/catalina/startup/NamingRuleSet.java | 270 +- .../catalina/startup/PasswdUserDatabase.java | 386 +- .../catalina/startup/SetAllPropertiesRule.java | 128 +- .../catalina/startup/SetContextPropertiesRule.java | 136 +- .../apache/catalina/startup/SetNextNamingRule.java | 238 +- java/org/apache/catalina/startup/TldConfig.java | 1444 +-- java/org/apache/catalina/startup/TldRuleSet.java | 190 +- java/org/apache/catalina/startup/Tool.java | 486 +- java/org/apache/catalina/startup/UserConfig.java | 676 +- java/org/apache/catalina/startup/UserDatabase.java | 138 +- .../apache/catalina/startup/WebAnnotationSet.java | 738 +- java/org/apache/catalina/startup/WebRuleSet.java | 1586 +-- .../apache/catalina/startup/catalina.properties | 132 +- .../apache/catalina/startup/mbeans-descriptors.xml | 222 +- java/org/apache/catalina/users/AbstractGroup.java | 336 +- java/org/apache/catalina/users/AbstractRole.java | 244 +- java/org/apache/catalina/users/AbstractUser.java | 448 +- java/org/apache/catalina/users/Constants.java | 68 +- .../apache/catalina/users/LocalStrings.properties | 10 +- .../catalina/users/LocalStrings_es.properties | 8 +- .../catalina/users/LocalStrings_fr.properties | 8 +- .../catalina/users/LocalStrings_ja.properties | 8 +- java/org/apache/catalina/users/MemoryGroup.java | 426 +- java/org/apache/catalina/users/MemoryRole.java | 204 +- java/org/apache/catalina/users/MemoryUser.java | 592 +- .../apache/catalina/users/MemoryUserDatabase.java | 1606 +-- .../catalina/users/MemoryUserDatabaseFactory.java | 218 +- .../apache/catalina/users/mbeans-descriptors.xml | 560 +- .../apache/catalina/util/AnnotationProcessor.java | 460 +- java/org/apache/catalina/util/Base64.java | 572 +- java/org/apache/catalina/util/CharsetMapper.java | 262 +- .../catalina/util/CharsetMapperDefault.properties | 4 +- java/org/apache/catalina/util/CookieTools.java | 316 +- .../catalina/util/CustomObjectInputStream.java | 202 +- java/org/apache/catalina/util/DOMWriter.java | 696 +- java/org/apache/catalina/util/DateTool.java | 196 +- java/org/apache/catalina/util/Enumerator.java | 350 +- java/org/apache/catalina/util/Extension.java | 606 +- .../apache/catalina/util/ExtensionValidator.java | 846 +- java/org/apache/catalina/util/FastDateFormat.java | 246 +- java/org/apache/catalina/util/HexUtils.java | 352 +- java/org/apache/catalina/util/IOTools.java | 172 +- java/org/apache/catalina/util/InstanceSupport.java | 722 +- .../org/apache/catalina/util/LifecycleSupport.java | 308 +- .../apache/catalina/util/LocalStrings.properties | 22 +- .../catalina/util/LocalStrings_es.properties | 20 +- .../catalina/util/LocalStrings_fr.properties | 20 +- .../catalina/util/LocalStrings_ja.properties | 22 +- java/org/apache/catalina/util/MD5Encoder.java | 144 +- java/org/apache/catalina/util/MIME2Java.java | 1204 +- .../org/apache/catalina/util/ManifestResource.java | 482 +- java/org/apache/catalina/util/ParameterMap.java | 422 +- java/org/apache/catalina/util/Queue.java | 174 +- java/org/apache/catalina/util/RequestUtil.java | 1018 +- java/org/apache/catalina/util/ResourceSet.java | 368 +- java/org/apache/catalina/util/SchemaResolver.java | 266 +- java/org/apache/catalina/util/ServerInfo.java | 248 +- .../org/apache/catalina/util/ServerInfo.properties | 4 +- java/org/apache/catalina/util/Strftime.java | 524 +- java/org/apache/catalina/util/StringManager.java | 504 +- java/org/apache/catalina/util/StringParser.java | 646 +- java/org/apache/catalina/util/TomcatCSS.java | 72 +- java/org/apache/catalina/util/URL.java | 1414 +-- java/org/apache/catalina/util/URLEncoder.java | 200 +- java/org/apache/catalina/util/XMLWriter.java | 486 +- .../org/apache/catalina/valves/AccessLogValve.java | 2262 ++-- java/org/apache/catalina/valves/Constants.java | 80 +- .../apache/catalina/valves/ErrorReportValve.java | 612 +- .../catalina/valves/ExtendedAccessLogValve.java | 2858 ++--- .../catalina/valves/FastCommonAccessLogValve.java | 1710 +-- .../apache/catalina/valves/JDBCAccessLogValve.java | 1362 +-- .../apache/catalina/valves/LocalStrings.properties | 142 +- .../catalina/valves/LocalStrings_es.properties | 138 +- .../catalina/valves/LocalStrings_fr.properties | 134 +- .../catalina/valves/LocalStrings_ja.properties | 48 +- .../apache/catalina/valves/PersistentValve.java | 420 +- .../apache/catalina/valves/RemoteAddrValve.java | 170 +- .../apache/catalina/valves/RemoteHostValve.java | 170 +- .../apache/catalina/valves/RequestDumperValve.java | 382 +- .../apache/catalina/valves/RequestFilterValve.java | 570 +- .../org/apache/catalina/valves/SemaphoreValve.java | 552 +- java/org/apache/catalina/valves/ValveBase.java | 640 +- .../apache/catalina/valves/mbeans-descriptors.xml | 584 +- java/org/apache/catalina/valves/package.html | 24 +- java/org/apache/coyote/ActionCode.java | 306 +- java/org/apache/coyote/ActionHook.java | 94 +- java/org/apache/coyote/Adapter.java | 102 +- java/org/apache/coyote/Constants.java | 110 +- java/org/apache/coyote/InputBuffer.java | 90 +- java/org/apache/coyote/OutputBuffer.java | 92 +- java/org/apache/coyote/Processor.java | 88 +- java/org/apache/coyote/ProtocolHandler.java | 168 +- java/org/apache/coyote/Request.java | 1042 +- java/org/apache/coyote/RequestGroupInfo.java | 326 +- java/org/apache/coyote/RequestInfo.java | 430 +- java/org/apache/coyote/Response.java | 1182 +- java/org/apache/coyote/ajp/AjpAprProcessor.java | 2540 ++--- java/org/apache/coyote/ajp/AjpAprProtocol.java | 1076 +- java/org/apache/coyote/ajp/AjpMessage.java | 898 +- java/org/apache/coyote/ajp/Constants.java | 674 +- java/org/apache/coyote/ajp/LocalStrings.properties | 74 +- java/org/apache/coyote/http11/Constants.java | 428 +- .../apache/coyote/http11/Http11AprProcessor.java | 3608 +++--- .../apache/coyote/http11/Http11AprProtocol.java | 1548 +-- .../apache/coyote/http11/Http11NioProcessor.java | 3582 +++--- .../apache/coyote/http11/Http11NioProtocol.java | 1516 +-- java/org/apache/coyote/http11/Http11Processor.java | 3342 +++--- java/org/apache/coyote/http11/InputFilter.java | 162 +- .../coyote/http11/InternalAprInputBuffer.java | 1678 +-- .../coyote/http11/InternalAprOutputBuffer.java | 1476 +-- .../apache/coyote/http11/InternalInputBuffer.java | 1586 +-- .../coyote/http11/InternalNioInputBuffer.java | 1752 +-- .../coyote/http11/InternalNioOutputBuffer.java | 1542 +-- .../apache/coyote/http11/InternalOutputBuffer.java | 1566 +-- .../apache/coyote/http11/LocalStrings.properties | 102 +- .../coyote/http11/LocalStrings_es.properties | 68 +- .../coyote/http11/LocalStrings_fr.properties | 72 +- .../coyote/http11/LocalStrings_ja.properties | 78 +- java/org/apache/coyote/http11/OutputFilter.java | 164 +- .../coyote/http11/filters/BufferedInputFilter.java | 244 +- .../coyote/http11/filters/ChunkedInputFilter.java | 682 +- .../coyote/http11/filters/ChunkedOutputFilter.java | 372 +- .../coyote/http11/filters/GzipOutputFilter.java | 340 +- .../coyote/http11/filters/IdentityInputFilter.java | 402 +- .../http11/filters/IdentityOutputFilter.java | 378 +- .../http11/filters/SavedRequestInputFilter.java | 198 +- .../coyote/http11/filters/VoidInputFilter.java | 236 +- .../coyote/http11/filters/VoidOutputFilter.java | 254 +- .../coyote/memory/MemoryProtocolHandler.java | 332 +- java/org/apache/el/ExpressionFactoryImpl.java | 156 +- java/org/apache/el/Messages.properties | 94 +- java/org/apache/el/MethodExpressionImpl.java | 628 +- java/org/apache/el/MethodExpressionLiteral.java | 190 +- java/org/apache/el/ValueExpressionImpl.java | 524 +- java/org/apache/el/ValueExpressionLiteral.java | 224 +- java/org/apache/el/lang/ELArithmetic.java | 752 +- java/org/apache/el/lang/ELSupport.java | 884 +- java/org/apache/el/lang/EvaluationContext.java | 140 +- java/org/apache/el/lang/ExpressionBuilder.java | 426 +- java/org/apache/el/lang/FunctionMapperFactory.java | 116 +- java/org/apache/el/lang/FunctionMapperImpl.java | 364 +- java/org/apache/el/lang/VariableMapperFactory.java | 104 +- java/org/apache/el/lang/VariableMapperImpl.java | 110 +- java/org/apache/el/parser/ArithmeticNode.java | 82 +- java/org/apache/el/parser/AstAnd.java | 60 +- java/org/apache/el/parser/AstBracketSuffix.java | 46 +- java/org/apache/el/parser/AstChoice.java | 62 +- .../apache/el/parser/AstCompositeExpression.java | 78 +- .../apache/el/parser/AstDeferredExpression.java | 76 +- java/org/apache/el/parser/AstDiv.java | 52 +- java/org/apache/el/parser/AstDotSuffix.java | 46 +- .../org/apache/el/parser/AstDynamicExpression.java | 76 +- java/org/apache/el/parser/AstEmpty.java | 86 +- java/org/apache/el/parser/AstEqual.java | 50 +- java/org/apache/el/parser/AstFalse.java | 46 +- java/org/apache/el/parser/AstFloatingPoint.java | 86 +- java/org/apache/el/parser/AstFunction.java | 236 +- java/org/apache/el/parser/AstGreaterThan.java | 62 +- java/org/apache/el/parser/AstGreaterThanEqual.java | 62 +- java/org/apache/el/parser/AstIdentifier.java | 276 +- java/org/apache/el/parser/AstInteger.java | 86 +- java/org/apache/el/parser/AstLessThan.java | 62 +- java/org/apache/el/parser/AstLessThanEqual.java | 62 +- .../org/apache/el/parser/AstLiteralExpression.java | 96 +- java/org/apache/el/parser/AstMinus.java | 52 +- java/org/apache/el/parser/AstMod.java | 52 +- java/org/apache/el/parser/AstMult.java | 52 +- java/org/apache/el/parser/AstNegative.java | 136 +- java/org/apache/el/parser/AstNot.java | 60 +- java/org/apache/el/parser/AstNotEqual.java | 50 +- java/org/apache/el/parser/AstNull.java | 56 +- java/org/apache/el/parser/AstOr.java | 60 +- java/org/apache/el/parser/AstPlus.java | 52 +- java/org/apache/el/parser/AstString.java | 118 +- java/org/apache/el/parser/AstTrue.java | 46 +- java/org/apache/el/parser/AstValue.java | 278 +- java/org/apache/el/parser/BooleanNode.java | 76 +- java/org/apache/el/parser/ELParser.java | 3344 +++--- java/org/apache/el/parser/ELParserConstants.java | 252 +- .../org/apache/el/parser/ELParserTokenManager.java | 2562 ++--- .../apache/el/parser/ELParserTreeConstants.java | 154 +- java/org/apache/el/parser/JJTELParserState.java | 246 +- java/org/apache/el/parser/Node.java | 140 +- java/org/apache/el/parser/NodeVisitor.java | 48 +- java/org/apache/el/parser/ParseException.java | 384 +- java/org/apache/el/parser/SimpleCharStream.java | 802 +- java/org/apache/el/parser/SimpleNode.java | 288 +- java/org/apache/el/parser/Token.java | 162 +- java/org/apache/el/parser/TokenMgrError.java | 266 +- java/org/apache/el/util/ConcurrentCache.java | 78 +- java/org/apache/el/util/MessageFactory.java | 138 +- java/org/apache/el/util/ReflectionUtil.java | 366 +- java/org/apache/jasper/Constants.java | 388 +- java/org/apache/jasper/EmbeddedServletOptions.java | 1336 +-- java/org/apache/jasper/JasperException.java | 90 +- java/org/apache/jasper/JspC.java | 2830 ++--- java/org/apache/jasper/JspCompilationContext.java | 1410 +-- java/org/apache/jasper/Options.java | 386 +- java/org/apache/jasper/compiler/AntCompiler.java | 550 +- .../org/apache/jasper/compiler/BeanRepository.java | 228 +- java/org/apache/jasper/compiler/Collector.java | 406 +- java/org/apache/jasper/compiler/Compiler.java | 1002 +- .../jasper/compiler/DefaultErrorHandler.java | 200 +- java/org/apache/jasper/compiler/Dumper.java | 412 +- .../apache/jasper/compiler/ELFunctionMapper.java | 564 +- java/org/apache/jasper/compiler/ELNode.java | 494 +- java/org/apache/jasper/compiler/ELParser.java | 760 +- .../apache/jasper/compiler/ErrorDispatcher.java | 1164 +- java/org/apache/jasper/compiler/ErrorHandler.java | 144 +- java/org/apache/jasper/compiler/Generator.java | 8252 +++++++------- .../jasper/compiler/ImplicitTagLibraryInfo.java | 282 +- java/org/apache/jasper/compiler/JDTCompiler.java | 870 +- java/org/apache/jasper/compiler/JasperTagInfo.java | 114 +- .../apache/jasper/compiler/JavacErrorDetail.java | 244 +- java/org/apache/jasper/compiler/JspConfig.java | 968 +- .../apache/jasper/compiler/JspDocumentParser.java | 2878 ++--- java/org/apache/jasper/compiler/JspReader.java | 1312 +-- .../apache/jasper/compiler/JspRuntimeContext.java | 1048 +- java/org/apache/jasper/compiler/JspUtil.java | 2266 ++-- java/org/apache/jasper/compiler/Localizer.java | 318 +- java/org/apache/jasper/compiler/Mark.java | 562 +- java/org/apache/jasper/compiler/Node.java | 5054 ++++----- java/org/apache/jasper/compiler/PageDataImpl.java | 1420 +-- java/org/apache/jasper/compiler/PageInfo.java | 1420 +-- java/org/apache/jasper/compiler/Parser.java | 3552 +++--- .../apache/jasper/compiler/ParserController.java | 1164 +- .../apache/jasper/compiler/ScriptingVariabler.java | 294 +- java/org/apache/jasper/compiler/ServletWriter.java | 350 +- java/org/apache/jasper/compiler/SmapGenerator.java | 340 +- java/org/apache/jasper/compiler/SmapStratum.java | 670 +- java/org/apache/jasper/compiler/SmapUtil.java | 1456 +-- java/org/apache/jasper/compiler/TagConstants.java | 230 +- .../apache/jasper/compiler/TagFileProcessor.java | 1292 +-- .../apache/jasper/compiler/TagLibraryInfoImpl.java | 1514 +-- .../apache/jasper/compiler/TagPluginManager.java | 478 +- java/org/apache/jasper/compiler/TextOptimizer.java | 224 +- .../apache/jasper/compiler/TldLocationsCache.java | 1108 +- java/org/apache/jasper/compiler/Validator.java | 3218 +++--- .../jasper/compiler/tagplugin/TagPlugin.java | 72 +- .../compiler/tagplugin/TagPluginContext.java | 246 +- java/org/apache/jasper/el/ELContextImpl.java | 196 +- java/org/apache/jasper/el/ELContextWrapper.java | 154 +- java/org/apache/jasper/el/ELResolverImpl.java | 288 +- .../apache/jasper/el/ExpressionEvaluatorImpl.java | 114 +- java/org/apache/jasper/el/ExpressionImpl.java | 82 +- java/org/apache/jasper/el/FunctionMapperImpl.java | 68 +- java/org/apache/jasper/el/JspELException.java | 50 +- java/org/apache/jasper/el/JspMethodExpression.java | 214 +- .../jasper/el/JspMethodNotFoundException.java | 50 +- .../jasper/el/JspPropertyNotFoundException.java | 54 +- .../jasper/el/JspPropertyNotWritableException.java | 52 +- java/org/apache/jasper/el/JspValueExpression.java | 272 +- .../org/apache/jasper/el/VariableResolverImpl.java | 68 +- .../jasper/resources/LocalStrings.properties | 844 +- .../jasper/resources/LocalStrings_es.properties | 816 +- .../jasper/resources/LocalStrings_fr.properties | 610 +- .../jasper/resources/LocalStrings_ja.properties | 814 +- .../org/apache/jasper/runtime/BodyContentImpl.java | 1216 +- java/org/apache/jasper/runtime/HttpJspBase.java | 230 +- .../jasper/runtime/JspApplicationContextImpl.java | 274 +- .../apache/jasper/runtime/JspContextWrapper.java | 924 +- java/org/apache/jasper/runtime/JspFactoryImpl.java | 382 +- .../apache/jasper/runtime/JspFragmentHelper.java | 128 +- .../apache/jasper/runtime/JspRuntimeLibrary.java | 2090 ++-- .../apache/jasper/runtime/JspSourceDependent.java | 76 +- java/org/apache/jasper/runtime/JspWriterImpl.java | 1178 +- .../org/apache/jasper/runtime/PageContextImpl.java | 1928 ++-- .../jasper/runtime/PerThreadTagHandlerPool.java | 266 +- .../jasper/runtime/ProtectedFunctionMapper.java | 390 +- .../runtime/ServletResponseWrapperInclude.java | 150 +- java/org/apache/jasper/runtime/TagHandlerPool.java | 386 +- .../apache/jasper/security/SecurityClassLoad.java | 220 +- java/org/apache/jasper/security/SecurityUtil.java | 82 +- java/org/apache/jasper/servlet/JasperLoader.java | 342 +- .../apache/jasper/servlet/JspCServletContext.java | 880 +- java/org/apache/jasper/servlet/JspServlet.java | 636 +- .../apache/jasper/servlet/JspServletWrapper.java | 1060 +- .../apache/jasper/servlet/mbeans-descriptors.xml | 38 +- java/org/apache/jasper/tagplugins/jstl/Util.java | 650 +- .../apache/jasper/tagplugins/jstl/core/Catch.java | 142 +- .../apache/jasper/tagplugins/jstl/core/Choose.java | 66 +- .../jasper/tagplugins/jstl/core/ForEach.java | 686 +- .../jasper/tagplugins/jstl/core/ForTokens.java | 236 +- .../org/apache/jasper/tagplugins/jstl/core/If.java | 98 +- .../apache/jasper/tagplugins/jstl/core/Import.java | 762 +- .../jasper/tagplugins/jstl/core/Otherwise.java | 62 +- .../apache/jasper/tagplugins/jstl/core/Out.java | 178 +- .../apache/jasper/tagplugins/jstl/core/Param.java | 152 +- .../jasper/tagplugins/jstl/core/Redirect.java | 164 +- .../apache/jasper/tagplugins/jstl/core/Remove.java | 88 +- .../apache/jasper/tagplugins/jstl/core/Set.java | 332 +- .../apache/jasper/tagplugins/jstl/core/Url.java | 200 +- .../apache/jasper/tagplugins/jstl/core/When.java | 98 +- .../apache/jasper/tagplugins/jstl/tagPlugins.xml | 92 +- java/org/apache/jasper/util/FastDateFormat.java | 266 +- java/org/apache/jasper/util/Queue.java | 176 +- java/org/apache/jasper/util/SimplePool.java | 170 +- java/org/apache/jasper/util/SystemLogHandler.java | 442 +- java/org/apache/jasper/xmlparser/ASCIIReader.java | 406 +- java/org/apache/jasper/xmlparser/EncodingMap.java | 2038 ++-- java/org/apache/jasper/xmlparser/ParserUtils.java | 474 +- java/org/apache/jasper/xmlparser/SymbolTable.java | 602 +- java/org/apache/jasper/xmlparser/TreeNode.java | 718 +- java/org/apache/jasper/xmlparser/UCSReader.java | 600 +- java/org/apache/jasper/xmlparser/UTF8Reader.java | 1268 +-- java/org/apache/jasper/xmlparser/XMLChar.java | 2060 ++-- .../jasper/xmlparser/XMLEncodingDetector.java | 3248 +++--- java/org/apache/jasper/xmlparser/XMLString.java | 392 +- .../apache/jasper/xmlparser/XMLStringBuffer.java | 350 +- java/org/apache/jk/apr/AprImpl.java | 632 +- java/org/apache/jk/apr/TomcatStarter.java | 186 +- java/org/apache/jk/common/AjpConstants.java | 384 +- java/org/apache/jk/common/ChannelJni.java | 382 +- java/org/apache/jk/common/ChannelNioSocket.java | 2362 ++-- java/org/apache/jk/common/ChannelShm.java | 64 +- java/org/apache/jk/common/ChannelSocket.java | 1764 +-- java/org/apache/jk/common/ChannelUn.java | 788 +- java/org/apache/jk/common/HandlerDispatch.java | 200 +- java/org/apache/jk/common/HandlerRequest.java | 1332 +-- java/org/apache/jk/common/JkInputStream.java | 636 +- java/org/apache/jk/common/JkMX.java | 788 +- java/org/apache/jk/common/JniHandler.java | 634 +- java/org/apache/jk/common/MsgAjp.java | 658 +- java/org/apache/jk/common/Shm.java | 660 +- java/org/apache/jk/common/Shm14.java | 192 +- java/org/apache/jk/common/WorkerDummy.java | 180 +- java/org/apache/jk/config/ApacheConfig.java | 1146 +- java/org/apache/jk/config/BaseJkConfig.java | 1030 +- java/org/apache/jk/config/GeneratorApache2.java | 386 +- java/org/apache/jk/config/GeneratorJk1.java | 224 +- java/org/apache/jk/config/GeneratorJk2.java | 286 +- java/org/apache/jk/config/IISConfig.java | 610 +- java/org/apache/jk/config/NSConfig.java | 656 +- java/org/apache/jk/config/WebXml2Jk.java | 902 +- java/org/apache/jk/core/JkChannel.java | 152 +- java/org/apache/jk/core/JkHandler.java | 392 +- java/org/apache/jk/core/Msg.java | 306 +- java/org/apache/jk/core/MsgContext.java | 762 +- java/org/apache/jk/core/WorkerEnv.java | 288 +- java/org/apache/jk/core/package.html | 32 +- java/org/apache/jk/mbeans-descriptors.xml | 1076 +- java/org/apache/jk/server/JkCoyoteHandler.java | 454 +- java/org/apache/jk/server/JkMain.java | 1386 +-- java/org/apache/juli/ClassLoaderLogManager.java | 1142 +- java/org/apache/juli/FileHandler.java | 532 +- java/org/apache/naming/Constants.java | 58 +- .../org/apache/naming/ContextAccessController.java | 256 +- java/org/apache/naming/ContextBindings.java | 724 +- java/org/apache/naming/EjbRef.java | 274 +- java/org/apache/naming/JndiPermission.java | 122 +- java/org/apache/naming/LocalStrings.properties | 20 +- java/org/apache/naming/LocalStrings_es.properties | 32 +- java/org/apache/naming/LocalStrings_fr.properties | 20 +- java/org/apache/naming/LocalStrings_ja.properties | 22 +- java/org/apache/naming/NameParserImpl.java | 112 +- java/org/apache/naming/NamingContext.java | 1814 +-- .../naming/NamingContextBindingsEnumeration.java | 256 +- .../apache/naming/NamingContextEnumeration.java | 190 +- java/org/apache/naming/NamingEntry.java | 160 +- java/org/apache/naming/NamingService.java | 458 +- java/org/apache/naming/NamingServiceMBean.java | 194 +- java/org/apache/naming/ResourceEnvRef.java | 196 +- java/org/apache/naming/ResourceLinkRef.java | 220 +- java/org/apache/naming/ResourceRef.java | 334 +- java/org/apache/naming/SelectorContext.java | 1388 +-- java/org/apache/naming/StringManager.java | 434 +- java/org/apache/naming/TransactionRef.java | 188 +- java/org/apache/naming/factory/BeanFactory.java | 490 +- java/org/apache/naming/factory/Constants.java | 108 +- java/org/apache/naming/factory/EjbFactory.java | 342 +- .../apache/naming/factory/MailSessionFactory.java | 312 +- java/org/apache/naming/factory/OpenEjbFactory.java | 178 +- .../apache/naming/factory/ResourceEnvFactory.java | 248 +- .../org/apache/naming/factory/ResourceFactory.java | 306 +- .../apache/naming/factory/ResourceLinkFactory.java | 214 +- .../org/apache/naming/factory/SendMailFactory.java | 250 +- .../apache/naming/factory/TransactionFactory.java | 248 +- java/org/apache/naming/factory/package.html | 14 +- .../apache/naming/java/javaURLContextFactory.java | 222 +- java/org/apache/naming/java/package.html | 14 +- java/org/apache/naming/package.html | 14 +- .../apache/naming/resources/BaseDirContext.java | 2416 ++-- java/org/apache/naming/resources/CacheEntry.java | 134 +- java/org/apache/naming/resources/Constants.java | 70 +- .../naming/resources/DirContextURLConnection.java | 716 +- .../resources/DirContextURLStreamHandler.java | 522 +- .../DirContextURLStreamHandlerFactory.java | 130 +- .../apache/naming/resources/FileDirContext.java | 2258 ++-- .../resources/ImmutableNameNotFoundException.java | 78 +- .../naming/resources/LocalStrings.properties | 42 +- .../naming/resources/LocalStrings_es.properties | 40 +- .../naming/resources/LocalStrings_fr.properties | 40 +- .../naming/resources/LocalStrings_ja.properties | 42 +- .../apache/naming/resources/ProxyDirContext.java | 3240 +++--- .../resources/RecyclableNamingEnumeration.java | 224 +- java/org/apache/naming/resources/Resource.java | 222 +- .../naming/resources/ResourceAttributes.java | 1830 +-- .../org/apache/naming/resources/ResourceCache.java | 840 +- .../org/apache/naming/resources/WARDirContext.java | 1906 ++-- java/org/apache/naming/resources/jndi/Handler.java | 76 +- java/org/apache/naming/resources/package.html | 30 +- java/org/apache/tomcat/Apr.java | 80 +- java/org/apache/tomcat/apr.properties | 2 +- java/org/apache/tomcat/jni/Address.java | 226 +- java/org/apache/tomcat/jni/BIOCallback.java | 110 +- java/org/apache/tomcat/jni/Directory.java | 192 +- java/org/apache/tomcat/jni/Error.java | 190 +- java/org/apache/tomcat/jni/File.java | 1404 +-- java/org/apache/tomcat/jni/FileInfo.java | 132 +- java/org/apache/tomcat/jni/Global.java | 190 +- java/org/apache/tomcat/jni/Library.java | 414 +- java/org/apache/tomcat/jni/Local.java | 150 +- java/org/apache/tomcat/jni/Lock.java | 244 +- java/org/apache/tomcat/jni/Mmap.java | 144 +- java/org/apache/tomcat/jni/Multicast.java | 154 +- java/org/apache/tomcat/jni/OS.java | 254 +- java/org/apache/tomcat/jni/PasswordCallback.java | 66 +- java/org/apache/tomcat/jni/Poll.java | 314 +- java/org/apache/tomcat/jni/Pool.java | 326 +- java/org/apache/tomcat/jni/PoolCallback.java | 64 +- java/org/apache/tomcat/jni/Proc.java | 418 +- java/org/apache/tomcat/jni/ProcErrorCallback.java | 74 +- java/org/apache/tomcat/jni/Procattr.java | 342 +- java/org/apache/tomcat/jni/Registry.java | 468 +- java/org/apache/tomcat/jni/SSL.java | 638 +- java/org/apache/tomcat/jni/SSLContext.java | 552 +- java/org/apache/tomcat/jni/SSLSocket.java | 176 +- java/org/apache/tomcat/jni/Shm.java | 246 +- java/org/apache/tomcat/jni/Sockaddr.java | 82 +- java/org/apache/tomcat/jni/Socket.java | 1056 +- java/org/apache/tomcat/jni/Status.java | 528 +- java/org/apache/tomcat/jni/Stdlib.java | 178 +- java/org/apache/tomcat/jni/Time.java | 146 +- java/org/apache/tomcat/jni/User.java | 252 +- java/org/apache/tomcat/util/DomUtil.java | 538 +- .../org/apache/tomcat/util/IntrospectionUtils.java | 2004 ++-- java/org/apache/tomcat/util/buf/Ascii.java | 492 +- java/org/apache/tomcat/util/buf/B2CConverter.java | 546 +- java/org/apache/tomcat/util/buf/Base64.java | 536 +- java/org/apache/tomcat/util/buf/ByteChunk.java | 1648 +-- java/org/apache/tomcat/util/buf/C2BConverter.java | 534 +- java/org/apache/tomcat/util/buf/CharChunk.java | 1440 +-- java/org/apache/tomcat/util/buf/DateTool.java | 328 +- java/org/apache/tomcat/util/buf/HexUtils.java | 386 +- java/org/apache/tomcat/util/buf/MessageBytes.java | 1464 +-- java/org/apache/tomcat/util/buf/StringCache.java | 1338 +-- java/org/apache/tomcat/util/buf/TimeStamp.java | 310 +- java/org/apache/tomcat/util/buf/UDecoder.java | 552 +- java/org/apache/tomcat/util/buf/UEncoder.java | 362 +- java/org/apache/tomcat/util/buf/UTF8Decoder.java | 298 +- java/org/apache/tomcat/util/buf/package.html | 44 +- .../tomcat/util/buf/res/LocalStrings.properties | 6 +- .../tomcat/util/buf/res/LocalStrings_es.properties | 8 +- .../tomcat/util/buf/res/LocalStrings_fr.properties | 6 +- .../tomcat/util/buf/res/LocalStrings_ja.properties | 6 +- .../tomcat/util/collections/EmptyEnumeration.java | 82 +- .../apache/tomcat/util/collections/LRUCache.java | 300 +- .../apache/tomcat/util/collections/MultiMap.java | 470 +- .../util/collections/MultiMapNamesEnumeration.java | 160 +- .../collections/MultiMapValuesEnumeration.java | 126 +- java/org/apache/tomcat/util/collections/Queue.java | 204 +- .../tomcat/util/collections/SimpleHashtable.java | 646 +- .../apache/tomcat/util/collections/SimplePool.java | 254 +- .../apache/tomcat/util/collections/package.html | 34 +- .../digester/AbstractObjectCreationFactory.java | 156 +- .../tomcat/util/digester/AbstractRulesImpl.java | 332 +- .../apache/tomcat/util/digester/ArrayStack.java | 336 +- .../tomcat/util/digester/CallMethodRule.java | 1258 +-- .../apache/tomcat/util/digester/CallParamRule.java | 524 +- java/org/apache/tomcat/util/digester/Digester.java | 5648 +++++----- .../tomcat/util/digester/FactoryCreateRule.java | 990 +- .../apache/tomcat/util/digester/GenericParser.java | 170 +- .../tomcat/util/digester/NodeCreateRule.java | 856 +- .../tomcat/util/digester/ObjectCreateRule.java | 482 +- .../util/digester/ObjectCreationFactory.java | 118 +- .../tomcat/util/digester/ObjectParamRule.java | 248 +- .../util/digester/ParserFeatureSetterFactory.java | 146 +- .../tomcat/util/digester/PathCallParamRule.java | 186 +- java/org/apache/tomcat/util/digester/Rule.java | 488 +- java/org/apache/tomcat/util/digester/RuleSet.java | 132 +- .../apache/tomcat/util/digester/RuleSetBase.java | 140 +- java/org/apache/tomcat/util/digester/Rules.java | 254 +- .../org/apache/tomcat/util/digester/RulesBase.java | 586 +- .../apache/tomcat/util/digester/SetNextRule.java | 428 +- .../tomcat/util/digester/SetPropertiesRule.java | 522 +- .../tomcat/util/digester/SetPropertyRule.java | 298 +- .../apache/tomcat/util/digester/SetRootRule.java | 430 +- .../apache/tomcat/util/digester/SetTopRule.java | 430 +- .../util/digester/WithDefaultsRulesWrapper.java | 326 +- .../apache/tomcat/util/digester/XercesParser.java | 378 +- java/org/apache/tomcat/util/digester/package.html | 2550 ++--- .../apache/tomcat/util/http/AcceptLanguage.java | 294 +- java/org/apache/tomcat/util/http/BaseRequest.java | 690 +- java/org/apache/tomcat/util/http/ContentType.java | 184 +- java/org/apache/tomcat/util/http/Cookies.java | 962 +- .../tomcat/util/http/FastHttpDateFormat.java | 446 +- java/org/apache/tomcat/util/http/HttpMessages.java | 212 +- java/org/apache/tomcat/util/http/MimeHeaders.java | 912 +- java/org/apache/tomcat/util/http/MimeMap.java | 374 +- java/org/apache/tomcat/util/http/Parameters.java | 1222 +- java/org/apache/tomcat/util/http/ServerCookie.java | 640 +- .../org/apache/tomcat/util/http/mapper/Mapper.java | 2792 ++--- .../tomcat/util/http/mapper/MappingData.java | 104 +- java/org/apache/tomcat/util/http/package.html | 28 +- .../tomcat/util/http/res/LocalStrings.properties | 92 +- .../util/http/res/LocalStrings_es.properties | 94 +- .../util/http/res/LocalStrings_fr.properties | 88 +- java/org/apache/tomcat/util/log/CaptureLog.java | 98 +- .../apache/tomcat/util/log/SystemLogHandler.java | 488 +- .../apache/tomcat/util/modeler/AttributeInfo.java | 326 +- .../tomcat/util/modeler/BaseAttributeFilter.java | 318 +- .../apache/tomcat/util/modeler/BaseModelMBean.java | 2348 ++-- .../util/modeler/BaseNotificationBroadcaster.java | 528 +- .../tomcat/util/modeler/ConstructorInfo.java | 110 +- .../apache/tomcat/util/modeler/FeatureInfo.java | 170 +- .../util/modeler/FixedNotificationFilter.java | 188 +- .../apache/tomcat/util/modeler/ManagedBean.java | 1254 +-- .../tomcat/util/modeler/NotificationInfo.java | 280 +- .../apache/tomcat/util/modeler/OperationInfo.java | 320 +- .../apache/tomcat/util/modeler/ParameterInfo.java | 118 +- java/org/apache/tomcat/util/modeler/Registry.java | 2068 ++-- .../apache/tomcat/util/modeler/RegistryMBean.java | 276 +- .../tomcat/util/modeler/mbeans-descriptors.dtd | 466 +- .../modules/MbeansDescriptorsDOMSource.java | 604 +- .../modules/MbeansDescriptorsDigesterSource.java | 470 +- .../MbeansDescriptorsIntrospectionSource.java | 834 +- .../modules/MbeansDescriptorsSerSource.java | 176 +- .../tomcat/util/modeler/modules/MbeansSource.java | 700 +- .../util/modeler/modules/MbeansSourceMBean.java | 84 +- .../tomcat/util/modeler/modules/ModelerSource.java | 140 +- .../tomcat/util/modeler/modules/package.html | 86 +- java/org/apache/tomcat/util/modeler/package.html | 464 +- java/org/apache/tomcat/util/net/AprEndpoint.java | 3786 +++---- .../util/net/DefaultServerSocketFactory.java | 138 +- .../util/net/LeaderFollowerWorkerThread.java | 172 +- .../tomcat/util/net/MasterSlaveWorkerThread.java | 300 +- java/org/apache/tomcat/util/net/NioEndpoint.java | 3054 ++--- .../apache/tomcat/util/net/PoolTcpEndpoint.java | 1366 +-- .../apache/tomcat/util/net/SSLImplementation.java | 172 +- java/org/apache/tomcat/util/net/SSLSupport.java | 254 +- .../tomcat/util/net/ServerSocketFactory.java | 344 +- java/org/apache/tomcat/util/net/TcpConnection.java | 218 +- .../tomcat/util/net/TcpConnectionHandler.java | 130 +- java/org/apache/tomcat/util/net/URL.java | 1462 +-- .../apache/tomcat/util/net/jsse/JSSEFactory.java | 98 +- .../tomcat/util/net/jsse/JSSEImplementation.java | 122 +- .../tomcat/util/net/jsse/JSSEKeyManager.java | 286 +- .../tomcat/util/net/jsse/JSSESocketFactory.java | 1332 +-- .../apache/tomcat/util/net/jsse/JSSESupport.java | 464 +- .../util/net/jsse/res/LocalStrings.properties | 2 +- .../util/net/jsse/res/LocalStrings_es.properties | 2 +- .../util/net/jsse/res/LocalStrings_fr.properties | 2 +- .../util/net/jsse/res/LocalStrings_ja.properties | 4 +- .../util/net/puretls/PureTLSImplementation.java | 114 +- .../tomcat/util/net/puretls/PureTLSSocket.java | 84 +- .../util/net/puretls/PureTLSSocketFactory.java | 458 +- .../tomcat/util/net/puretls/PureTLSSupport.java | 286 +- .../tomcat/util/net/res/LocalStrings.properties | 50 +- .../tomcat/util/net/res/LocalStrings_es.properties | 12 +- .../tomcat/util/net/res/LocalStrings_fr.properties | 12 +- .../tomcat/util/net/res/LocalStrings_ja.properties | 12 +- java/org/apache/tomcat/util/res/StringManager.java | 570 +- .../org/apache/tomcat/util/threads/ThreadPool.java | 1676 +-- .../tomcat/util/threads/ThreadPoolRunnable.java | 76 +- .../tomcat/util/threads/ThreadWithAttributes.java | 200 +- .../util/threads/res/LocalStrings.properties | 6 +- .../util/threads/res/LocalStrings_es.properties | 6 +- .../util/threads/res/LocalStrings_fr.properties | 6 +- .../util/threads/res/LocalStrings_ja.properties | 6 +- webapps/ROOT/WEB-INF/web.xml | 56 +- webapps/ROOT/index.html | 396 +- webapps/examples/jsp/jsp2/jspx/basic.jspx | 60 +- webapps/examples/jsp/jsp2/jspx/textRotate.jspx | 72 +- webapps/examples/jsp/jsp2/misc/coda.jspf | 10 +- webapps/examples/jsp/jsp2/misc/prelude.jspf | 10 +- 1008 files changed, 273329 insertions(+), 273329 deletions(-) diff --git a/BUILDING.txt b/BUILDING.txt index 99a809136..139597f9c 100644 --- a/BUILDING.txt +++ b/BUILDING.txt @@ -1,2 +1,2 @@ - - + + diff --git a/README.txt b/README.txt index 99a809136..139597f9c 100644 --- a/README.txt +++ b/README.txt @@ -1,2 +1,2 @@ - - + + diff --git a/build.xml b/build.xml index a5cfb292f..0853f8996 100644 --- a/build.xml +++ b/build.xml @@ -1,443 +1,443 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/javax/annotation/Generated.java b/java/javax/annotation/Generated.java index a0da75626..409435ddd 100644 --- a/java/javax/annotation/Generated.java +++ b/java/javax/annotation/Generated.java @@ -1,34 +1,34 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, - ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, - ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE}) -@Retention(RetentionPolicy.SOURCE) - -public @interface Generated { - public String[] value(); - public String date() default ""; - public String comment() default ""; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, + ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, + ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE}) +@Retention(RetentionPolicy.SOURCE) + +public @interface Generated { + public String[] value(); + public String date() default ""; + public String comment() default ""; +} diff --git a/java/javax/annotation/PostConstruct.java b/java/javax/annotation/PostConstruct.java index 43fcbce38..11ce7878a 100644 --- a/java/javax/annotation/PostConstruct.java +++ b/java/javax/annotation/PostConstruct.java @@ -1,29 +1,29 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PostConstruct { -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PostConstruct { +} diff --git a/java/javax/annotation/PreDestroy.java b/java/javax/annotation/PreDestroy.java index 609ae2006..2020298c5 100644 --- a/java/javax/annotation/PreDestroy.java +++ b/java/javax/annotation/PreDestroy.java @@ -1,29 +1,29 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PreDestroy { -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PreDestroy { +} diff --git a/java/javax/annotation/Resource.java b/java/javax/annotation/Resource.java index 50da1ece3..f58b8cfd0 100644 --- a/java/javax/annotation/Resource.java +++ b/java/javax/annotation/Resource.java @@ -1,39 +1,39 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface Resource { - public enum AuthenticationType { - CONTAINER, - APPLICATION - } - public String name() default ""; - public Class type() default Object.class; - public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; - public boolean shareable() default true; - public String description() default ""; - public String mappedName() default ""; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface Resource { + public enum AuthenticationType { + CONTAINER, + APPLICATION + } + public String name() default ""; + public Class type() default Object.class; + public AuthenticationType authenticationType() default AuthenticationType.CONTAINER; + public boolean shareable() default true; + public String description() default ""; + public String mappedName() default ""; +} diff --git a/java/javax/annotation/Resources.java b/java/javax/annotation/Resources.java index 512868d2e..96b8d3e0b 100644 --- a/java/javax/annotation/Resources.java +++ b/java/javax/annotation/Resources.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface Resources { - public Resource[] value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface Resources { + public Resource[] value(); +} diff --git a/java/javax/annotation/security/DenyAll.java b/java/javax/annotation/security/DenyAll.java index 030971abc..dfc2051d4 100644 --- a/java/javax/annotation/security/DenyAll.java +++ b/java/javax/annotation/security/DenyAll.java @@ -1,29 +1,29 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation.security; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface DenyAll { -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface DenyAll { +} diff --git a/java/javax/annotation/security/PermitAll.java b/java/javax/annotation/security/PermitAll.java index a5a03c1e6..c34a34e4d 100644 --- a/java/javax/annotation/security/PermitAll.java +++ b/java/javax/annotation/security/PermitAll.java @@ -1,29 +1,29 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation.security; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PermitAll { -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PermitAll { +} diff --git a/java/javax/annotation/security/RolesAllowed.java b/java/javax/annotation/security/RolesAllowed.java index 4138ca2dc..a8d7a50a2 100644 --- a/java/javax/annotation/security/RolesAllowed.java +++ b/java/javax/annotation/security/RolesAllowed.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation.security; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface RolesAllowed { - public String[] value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface RolesAllowed { + public String[] value(); +} diff --git a/java/javax/annotation/security/RunAs.java b/java/javax/annotation/security/RunAs.java index 70fa273a2..e59bb1cc3 100644 --- a/java/javax/annotation/security/RunAs.java +++ b/java/javax/annotation/security/RunAs.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.annotation.security; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface RunAs { - public String value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.annotation.security; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface RunAs { + public String value(); +} diff --git a/java/javax/el/ArrayELResolver.java b/java/javax/el/ArrayELResolver.java index d92d8e8c4..ec812983c 100644 --- a/java/javax/el/ArrayELResolver.java +++ b/java/javax/el/ArrayELResolver.java @@ -1,152 +1,152 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.beans.FeatureDescriptor; -import java.lang.reflect.Array; -import java.util.Arrays; -import java.util.Iterator; - -public class ArrayELResolver extends ELResolver { - - private final boolean readOnly; - - public ArrayELResolver() { - this.readOnly = false; - } - - public ArrayELResolver(boolean readOnly) { - this.readOnly = readOnly; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base != null && base.getClass().isArray()) { - context.setPropertyResolved(true); - int idx = coerce(property); - checkBounds(base, idx); - return Array.get(base, idx); - } - - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base != null && base.getClass().isArray()) { - context.setPropertyResolved(true); - int idx = coerce(property); - checkBounds(base, idx); - return base.getClass().getComponentType(); - } - - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base != null && base.getClass().isArray()) { - context.setPropertyResolved(true); - - if (this.readOnly) { - throw new PropertyNotWritableException(message(context, - "resolverNotWriteable", new Object[] { base.getClass() - .getName() })); - } - - int idx = coerce(property); - checkBounds(base, idx); - Array.set(base, idx, value); - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base != null && base.getClass().isArray()) { - context.setPropertyResolved(true); - int idx = coerce(property); - checkBounds(base, idx); - } - - return this.readOnly; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - if (base != null && base.getClass().isArray()) { - FeatureDescriptor[] descs = new FeatureDescriptor[Array.getLength(base)]; - for (int i = 0; i < descs.length; i++) { - descs[i] = new FeatureDescriptor(); - descs[i].setDisplayName("["+i+"]"); - descs[i].setExpert(false); - descs[i].setHidden(false); - descs[i].setName(""+i); - descs[i].setPreferred(true); - descs[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); - descs[i].setValue(TYPE, Integer.class); - } - return Arrays.asList(descs).iterator(); - } - return null; - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base != null && base.getClass().isArray()) { - return Integer.class; - } - return null; - } - - private final static void checkBounds(Object base, int idx) { - if (idx < 0 || idx >= Array.getLength(base)) { - throw new PropertyNotFoundException( - new ArrayIndexOutOfBoundsException(idx).getMessage()); - } - } - - private final static int coerce(Object property) { - if (property instanceof Number) { - return ((Number) property).intValue(); - } - if (property instanceof Character) { - return ((Character) property).charValue(); - } - if (property instanceof Boolean) { - return (((Boolean) property).booleanValue() ? 1 : 0); - } - throw new IllegalArgumentException(property != null ? property - .toString() : "null"); - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.beans.FeatureDescriptor; +import java.lang.reflect.Array; +import java.util.Arrays; +import java.util.Iterator; + +public class ArrayELResolver extends ELResolver { + + private final boolean readOnly; + + public ArrayELResolver() { + this.readOnly = false; + } + + public ArrayELResolver(boolean readOnly) { + this.readOnly = readOnly; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base != null && base.getClass().isArray()) { + context.setPropertyResolved(true); + int idx = coerce(property); + checkBounds(base, idx); + return Array.get(base, idx); + } + + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base != null && base.getClass().isArray()) { + context.setPropertyResolved(true); + int idx = coerce(property); + checkBounds(base, idx); + return base.getClass().getComponentType(); + } + + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base != null && base.getClass().isArray()) { + context.setPropertyResolved(true); + + if (this.readOnly) { + throw new PropertyNotWritableException(message(context, + "resolverNotWriteable", new Object[] { base.getClass() + .getName() })); + } + + int idx = coerce(property); + checkBounds(base, idx); + Array.set(base, idx, value); + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base != null && base.getClass().isArray()) { + context.setPropertyResolved(true); + int idx = coerce(property); + checkBounds(base, idx); + } + + return this.readOnly; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + if (base != null && base.getClass().isArray()) { + FeatureDescriptor[] descs = new FeatureDescriptor[Array.getLength(base)]; + for (int i = 0; i < descs.length; i++) { + descs[i] = new FeatureDescriptor(); + descs[i].setDisplayName("["+i+"]"); + descs[i].setExpert(false); + descs[i].setHidden(false); + descs[i].setName(""+i); + descs[i].setPreferred(true); + descs[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); + descs[i].setValue(TYPE, Integer.class); + } + return Arrays.asList(descs).iterator(); + } + return null; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base != null && base.getClass().isArray()) { + return Integer.class; + } + return null; + } + + private final static void checkBounds(Object base, int idx) { + if (idx < 0 || idx >= Array.getLength(base)) { + throw new PropertyNotFoundException( + new ArrayIndexOutOfBoundsException(idx).getMessage()); + } + } + + private final static int coerce(Object property) { + if (property instanceof Number) { + return ((Number) property).intValue(); + } + if (property instanceof Character) { + return ((Character) property).charValue(); + } + if (property instanceof Boolean) { + return (((Boolean) property).booleanValue() ? 1 : 0); + } + throw new IllegalArgumentException(property != null ? property + .toString() : "null"); + } + +} diff --git a/java/javax/el/BeanELResolver.java b/java/javax/el/BeanELResolver.java index 7a05331de..95bcafe52 100644 --- a/java/javax/el/BeanELResolver.java +++ b/java/javax/el/BeanELResolver.java @@ -1,330 +1,330 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; - -public class BeanELResolver extends ELResolver { - - private final boolean readOnly; - - private final ConcurrentCache cache = new ConcurrentCache( - 1000); - - public BeanELResolver() { - this.readOnly = false; - } - - public BeanELResolver(boolean readOnly) { - this.readOnly = readOnly; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - if (base == null || property == null) { - return null; - } - - context.setPropertyResolved(true); - Method m = this.property(context, base, property).read(context); - try { - return m.invoke(base, (Object[]) null); - } catch (IllegalAccessException e) { - throw new ELException(e); - } catch (InvocationTargetException e) { - throw new ELException(message(context, "propertyReadError", - new Object[] { base.getClass().getName(), - property.toString() }), e.getCause()); - } catch (Exception e) { - throw new ELException(e); - } - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - if (base == null || property == null) { - return null; - } - - context.setPropertyResolved(true); - return this.property(context, base, property).getType(); - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - if (base == null || property == null) { - return; - } - - context.setPropertyResolved(true); - - if (this.readOnly) { - throw new PropertyNotWritableException(message(context, - "resolverNotWriteable", new Object[] { base.getClass() - .getName() })); - } - - Method m = this.property(context, base, property).write(context); - try { - m.invoke(base, new Object[] { value }); - } catch (IllegalAccessException e) { - throw new ELException(e); - } catch (InvocationTargetException e) { - throw new ELException(message(context, "propertyWriteError", - new Object[] { base.getClass().getName(), - property.toString() }), e.getCause()); - } catch (Exception e) { - throw new ELException(e); - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - if (base == null || property == null) { - return false; - } - - context.setPropertyResolved(true); - return this.readOnly - || this.property(context, base, property).isReadOnly(); - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - return null; - } - - try { - BeanInfo info = Introspector.getBeanInfo(base.getClass()); - PropertyDescriptor[] pds = info.getPropertyDescriptors(); - for (int i = 0; i < pds.length; i++) { - pds[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); - pds[i].setValue(TYPE, pds[i].getPropertyType()); - } - return Arrays.asList(pds).iterator(); - } catch (IntrospectionException e) { - // - } - - return null; - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (context == null) { - throw new NullPointerException(); - } - - if (base != null) { - return Object.class; - } - - return null; - } - - private final static class BeanProperties { - private final Map properties; - - private final Class type; - - public BeanProperties(Class type) throws ELException { - this.type = type; - this.properties = new HashMap(); - try { - BeanInfo info = Introspector.getBeanInfo(this.type); - PropertyDescriptor[] pds = info.getPropertyDescriptors(); - for (int i = 0; i < pds.length; i++) { - this.properties.put(pds[i].getName(), new BeanProperty( - type, pds[i])); - } - } catch (IntrospectionException ie) { - throw new ELException(ie); - } - } - - public BeanProperty get(ELContext ctx, String name) { - BeanProperty property = this.properties.get(name); - if (property == null) { - throw new PropertyNotFoundException(message(ctx, - "propertyNotFound", - new Object[] { type.getName(), name })); - } - return property; - } - - public Class getType() { - return type; - } - } - - private final static class BeanProperty { - private final Class type; - - private final Class owner; - - private final PropertyDescriptor descriptor; - - private Method read; - - private Method write; - - public BeanProperty(Class owner, PropertyDescriptor descriptor) { - this.owner = owner; - this.descriptor = descriptor; - this.type = descriptor.getPropertyType(); - } - - public Class getType() { - return this.type; - } - - public boolean isReadOnly() { - return this.write != null - || null == getMethod(type, descriptor.getWriteMethod()); - } - - public Method write(ELContext ctx) { - if (this.write == null) { - this.write = getMethod(this.owner, descriptor.getWriteMethod()); - if (this.write == null) { - throw new PropertyNotFoundException(message(ctx, - "propertyNotWritable", new Object[] { - type.getName(), descriptor.getName() })); - } - } - return this.write; - } - - public Method read(ELContext ctx) { - if (this.read == null) { - this.read = getMethod(this.owner, descriptor.getReadMethod()); - if (this.read == null) { - throw new PropertyNotFoundException(message(ctx, - "propertyNotReadable", new Object[] { - type.getName(), descriptor.getName() })); - } - } - return this.read; - } - } - - private final BeanProperty property(ELContext ctx, Object base, - Object property) { - Class type = base.getClass(); - String prop = property.toString(); - - BeanProperties props = this.cache.get(type.getName()); - if (props == null || type != props.getType()) { - props = new BeanProperties(type); - this.cache.put(type.getName(), props); - } - - return props.get(ctx, prop); - } - - private final static Method getMethod(Class type, Method m) { - if (m == null || Modifier.isPublic(type.getModifiers())) { - return m; - } - Class[] inf = type.getInterfaces(); - Method mp = null; - for (int i = 0; i < inf.length; i++) { - try { - mp = inf[i].getMethod(m.getName(), (Class[]) m.getParameterTypes()); - mp = getMethod(mp.getDeclaringClass(), mp); - if (mp != null) { - return mp; - } - } catch (NoSuchMethodException e) { - } - } - Class sup = type.getSuperclass(); - if (sup != null) { - try { - mp = sup.getMethod(m.getName(), (Class[]) m.getParameterTypes()); - mp = getMethod(mp.getDeclaringClass(), mp); - if (mp != null) { - return mp; - } - } catch (NoSuchMethodException e) { - } - } - return null; - } - - private final static class ConcurrentCache { - - private final int size; - private final Map eden; - private final Map longterm; - - public ConcurrentCache(int size) { - this.size = size; - this.eden = new ConcurrentHashMap(size); - this.longterm = new WeakHashMap(size); - } - - public V get(K key) { - V value = this.eden.get(key); - if (value == null) { - value = this.longterm.get(key); - if (value != null) { - this.eden.put(key, value); - } - } - return value; - } - - public void put(K key, V value) { - if (this.eden.size() >= this.size) { - this.longterm.putAll(this.eden); - this.eden.clear(); - } - this.eden.put(key, value); - } - - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; + +public class BeanELResolver extends ELResolver { + + private final boolean readOnly; + + private final ConcurrentCache cache = new ConcurrentCache( + 1000); + + public BeanELResolver() { + this.readOnly = false; + } + + public BeanELResolver(boolean readOnly) { + this.readOnly = readOnly; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + if (base == null || property == null) { + return null; + } + + context.setPropertyResolved(true); + Method m = this.property(context, base, property).read(context); + try { + return m.invoke(base, (Object[]) null); + } catch (IllegalAccessException e) { + throw new ELException(e); + } catch (InvocationTargetException e) { + throw new ELException(message(context, "propertyReadError", + new Object[] { base.getClass().getName(), + property.toString() }), e.getCause()); + } catch (Exception e) { + throw new ELException(e); + } + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + if (base == null || property == null) { + return null; + } + + context.setPropertyResolved(true); + return this.property(context, base, property).getType(); + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + if (base == null || property == null) { + return; + } + + context.setPropertyResolved(true); + + if (this.readOnly) { + throw new PropertyNotWritableException(message(context, + "resolverNotWriteable", new Object[] { base.getClass() + .getName() })); + } + + Method m = this.property(context, base, property).write(context); + try { + m.invoke(base, new Object[] { value }); + } catch (IllegalAccessException e) { + throw new ELException(e); + } catch (InvocationTargetException e) { + throw new ELException(message(context, "propertyWriteError", + new Object[] { base.getClass().getName(), + property.toString() }), e.getCause()); + } catch (Exception e) { + throw new ELException(e); + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + if (base == null || property == null) { + return false; + } + + context.setPropertyResolved(true); + return this.readOnly + || this.property(context, base, property).isReadOnly(); + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + return null; + } + + try { + BeanInfo info = Introspector.getBeanInfo(base.getClass()); + PropertyDescriptor[] pds = info.getPropertyDescriptors(); + for (int i = 0; i < pds.length; i++) { + pds[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); + pds[i].setValue(TYPE, pds[i].getPropertyType()); + } + return Arrays.asList(pds).iterator(); + } catch (IntrospectionException e) { + // + } + + return null; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (context == null) { + throw new NullPointerException(); + } + + if (base != null) { + return Object.class; + } + + return null; + } + + private final static class BeanProperties { + private final Map properties; + + private final Class type; + + public BeanProperties(Class type) throws ELException { + this.type = type; + this.properties = new HashMap(); + try { + BeanInfo info = Introspector.getBeanInfo(this.type); + PropertyDescriptor[] pds = info.getPropertyDescriptors(); + for (int i = 0; i < pds.length; i++) { + this.properties.put(pds[i].getName(), new BeanProperty( + type, pds[i])); + } + } catch (IntrospectionException ie) { + throw new ELException(ie); + } + } + + public BeanProperty get(ELContext ctx, String name) { + BeanProperty property = this.properties.get(name); + if (property == null) { + throw new PropertyNotFoundException(message(ctx, + "propertyNotFound", + new Object[] { type.getName(), name })); + } + return property; + } + + public Class getType() { + return type; + } + } + + private final static class BeanProperty { + private final Class type; + + private final Class owner; + + private final PropertyDescriptor descriptor; + + private Method read; + + private Method write; + + public BeanProperty(Class owner, PropertyDescriptor descriptor) { + this.owner = owner; + this.descriptor = descriptor; + this.type = descriptor.getPropertyType(); + } + + public Class getType() { + return this.type; + } + + public boolean isReadOnly() { + return this.write != null + || null == getMethod(type, descriptor.getWriteMethod()); + } + + public Method write(ELContext ctx) { + if (this.write == null) { + this.write = getMethod(this.owner, descriptor.getWriteMethod()); + if (this.write == null) { + throw new PropertyNotFoundException(message(ctx, + "propertyNotWritable", new Object[] { + type.getName(), descriptor.getName() })); + } + } + return this.write; + } + + public Method read(ELContext ctx) { + if (this.read == null) { + this.read = getMethod(this.owner, descriptor.getReadMethod()); + if (this.read == null) { + throw new PropertyNotFoundException(message(ctx, + "propertyNotReadable", new Object[] { + type.getName(), descriptor.getName() })); + } + } + return this.read; + } + } + + private final BeanProperty property(ELContext ctx, Object base, + Object property) { + Class type = base.getClass(); + String prop = property.toString(); + + BeanProperties props = this.cache.get(type.getName()); + if (props == null || type != props.getType()) { + props = new BeanProperties(type); + this.cache.put(type.getName(), props); + } + + return props.get(ctx, prop); + } + + private final static Method getMethod(Class type, Method m) { + if (m == null || Modifier.isPublic(type.getModifiers())) { + return m; + } + Class[] inf = type.getInterfaces(); + Method mp = null; + for (int i = 0; i < inf.length; i++) { + try { + mp = inf[i].getMethod(m.getName(), (Class[]) m.getParameterTypes()); + mp = getMethod(mp.getDeclaringClass(), mp); + if (mp != null) { + return mp; + } + } catch (NoSuchMethodException e) { + } + } + Class sup = type.getSuperclass(); + if (sup != null) { + try { + mp = sup.getMethod(m.getName(), (Class[]) m.getParameterTypes()); + mp = getMethod(mp.getDeclaringClass(), mp); + if (mp != null) { + return mp; + } + } catch (NoSuchMethodException e) { + } + } + return null; + } + + private final static class ConcurrentCache { + + private final int size; + private final Map eden; + private final Map longterm; + + public ConcurrentCache(int size) { + this.size = size; + this.eden = new ConcurrentHashMap(size); + this.longterm = new WeakHashMap(size); + } + + public V get(K key) { + V value = this.eden.get(key); + if (value == null) { + value = this.longterm.get(key); + if (value != null) { + this.eden.put(key, value); + } + } + return value; + } + + public void put(K key, V value) { + if (this.eden.size() >= this.size) { + this.longterm.putAll(this.eden); + this.eden.clear(); + } + this.eden.put(key, value); + } + + } +} diff --git a/java/javax/el/CompositeELResolver.java b/java/javax/el/CompositeELResolver.java index e6066aa81..84789b7ae 100644 --- a/java/javax/el/CompositeELResolver.java +++ b/java/javax/el/CompositeELResolver.java @@ -1,174 +1,174 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.util.Iterator; - -public class CompositeELResolver extends ELResolver { - - private int size; - - private ELResolver[] resolvers; - - public CompositeELResolver() { - this.size = 0; - this.resolvers = new ELResolver[2]; - } - - public void add(ELResolver elResolver) { - if (elResolver == null) { - throw new NullPointerException(); - } - - if (this.size >= this.resolvers.length) { - ELResolver[] nr = new ELResolver[this.size * 2]; - System.arraycopy(this.resolvers, 0, nr, 0, this.size); - this.resolvers = nr; - } - this.resolvers[this.size++] = elResolver; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - context.setPropertyResolved(false); - int sz = this.size; - Object result = null; - for (int i = 0; i < sz; i++) { - result = this.resolvers[i].getValue(context, base, property); - if (context.isPropertyResolved()) { - return result; - } - } - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - context.setPropertyResolved(false); - int sz = this.size; - for (int i = 0; i < sz; i++) { - this.resolvers[i].setValue(context, base, property, value); - if (context.isPropertyResolved()) { - return; - } - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - context.setPropertyResolved(false); - int sz = this.size; - boolean readOnly = false; - for (int i = 0; i < sz; i++) { - readOnly = this.resolvers[i].isReadOnly(context, base, property); - if (context.isPropertyResolved()) { - return readOnly; - } - } - return false; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - return new FeatureIterator(context, base, this.resolvers, this.size); - } - - public Class getCommonPropertyType(ELContext context, Object base) { - int sz = this.size; - Class commonType = null, type = null; - for (int i = 0; i < sz; i++) { - type = this.resolvers[i].getCommonPropertyType(context, base); - if (type != null - && (commonType == null || commonType.isAssignableFrom(type))) { - commonType = type; - } - } - return commonType; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - context.setPropertyResolved(false); - int sz = this.size; - Class type; - for (int i = 0; i < sz; i++) { - type = this.resolvers[i].getType(context, base, property); - if (context.isPropertyResolved()) { - return type; - } - } - return null; - } - - private final static class FeatureIterator implements Iterator { - - private final ELContext context; - - private final Object base; - - private final ELResolver[] resolvers; - - private final int size; - - private Iterator itr; - - private int idx; - - public FeatureIterator(ELContext context, Object base, - ELResolver[] resolvers, int size) { - this.context = context; - this.base = base; - this.resolvers = resolvers; - this.size = size; - - this.idx = 0; - this.guaranteeIterator(); - } - - private void guaranteeIterator() { - while (this.itr == null && this.idx < this.size) { - this.itr = this.resolvers[this.idx].getFeatureDescriptors( - this.context, this.base); - this.idx++; - } - } - - public boolean hasNext() { - return this.itr != null; - } - - public Object next() { - Object result = null; - if (this.itr != null) { - if (this.itr.hasNext()) { - result = this.itr.next(); - if (!this.itr.hasNext()) { - this.itr = null; - this.guaranteeIterator(); - } - } - } - return result; - } - - public void remove() { - throw new UnsupportedOperationException(); - } - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.util.Iterator; + +public class CompositeELResolver extends ELResolver { + + private int size; + + private ELResolver[] resolvers; + + public CompositeELResolver() { + this.size = 0; + this.resolvers = new ELResolver[2]; + } + + public void add(ELResolver elResolver) { + if (elResolver == null) { + throw new NullPointerException(); + } + + if (this.size >= this.resolvers.length) { + ELResolver[] nr = new ELResolver[this.size * 2]; + System.arraycopy(this.resolvers, 0, nr, 0, this.size); + this.resolvers = nr; + } + this.resolvers[this.size++] = elResolver; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + context.setPropertyResolved(false); + int sz = this.size; + Object result = null; + for (int i = 0; i < sz; i++) { + result = this.resolvers[i].getValue(context, base, property); + if (context.isPropertyResolved()) { + return result; + } + } + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + context.setPropertyResolved(false); + int sz = this.size; + for (int i = 0; i < sz; i++) { + this.resolvers[i].setValue(context, base, property, value); + if (context.isPropertyResolved()) { + return; + } + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + context.setPropertyResolved(false); + int sz = this.size; + boolean readOnly = false; + for (int i = 0; i < sz; i++) { + readOnly = this.resolvers[i].isReadOnly(context, base, property); + if (context.isPropertyResolved()) { + return readOnly; + } + } + return false; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + return new FeatureIterator(context, base, this.resolvers, this.size); + } + + public Class getCommonPropertyType(ELContext context, Object base) { + int sz = this.size; + Class commonType = null, type = null; + for (int i = 0; i < sz; i++) { + type = this.resolvers[i].getCommonPropertyType(context, base); + if (type != null + && (commonType == null || commonType.isAssignableFrom(type))) { + commonType = type; + } + } + return commonType; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + context.setPropertyResolved(false); + int sz = this.size; + Class type; + for (int i = 0; i < sz; i++) { + type = this.resolvers[i].getType(context, base, property); + if (context.isPropertyResolved()) { + return type; + } + } + return null; + } + + private final static class FeatureIterator implements Iterator { + + private final ELContext context; + + private final Object base; + + private final ELResolver[] resolvers; + + private final int size; + + private Iterator itr; + + private int idx; + + public FeatureIterator(ELContext context, Object base, + ELResolver[] resolvers, int size) { + this.context = context; + this.base = base; + this.resolvers = resolvers; + this.size = size; + + this.idx = 0; + this.guaranteeIterator(); + } + + private void guaranteeIterator() { + while (this.itr == null && this.idx < this.size) { + this.itr = this.resolvers[this.idx].getFeatureDescriptors( + this.context, this.base); + this.idx++; + } + } + + public boolean hasNext() { + return this.itr != null; + } + + public Object next() { + Object result = null; + if (this.itr != null) { + if (this.itr.hasNext()) { + result = this.itr.next(); + if (!this.itr.hasNext()) { + this.itr = null; + this.guaranteeIterator(); + } + } + } + return result; + } + + public void remove() { + throw new UnsupportedOperationException(); + } + } + +} diff --git a/java/javax/el/ELContext.java b/java/javax/el/ELContext.java index dd2f832e9..6d6890d47 100644 --- a/java/javax/el/ELContext.java +++ b/java/javax/el/ELContext.java @@ -1,81 +1,81 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; - -/** - * - */ -public abstract class ELContext { - - private Locale locale; - - private Map, Object> map; - - private boolean resolved; - - /** - * - */ - public ELContext() { - this.resolved = false; - } - - public Object getContext(Class key) { - if (this.map == null) { - return null; - } - return this.map.get(key); - } - - public void putContext(Class key, Object contextObject) throws NullPointerException { - if (key == null || contextObject == null) { - throw new NullPointerException(); - } - - if (this.map == null) { - this.map = new HashMap, Object>(); - } - - this.map.put(key, contextObject); - } - - public void setPropertyResolved(boolean resolved) { - this.resolved = resolved; - } - - public boolean isPropertyResolved() { - return this.resolved; - } - - public abstract ELResolver getELResolver(); - - public abstract FunctionMapper getFunctionMapper(); - - public abstract VariableMapper getVariableMapper(); - - public Locale getLocale() { - return this.locale; - } - - public void setLocale(Locale locale) { - this.locale = locale; - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +/** + * + */ +public abstract class ELContext { + + private Locale locale; + + private Map, Object> map; + + private boolean resolved; + + /** + * + */ + public ELContext() { + this.resolved = false; + } + + public Object getContext(Class key) { + if (this.map == null) { + return null; + } + return this.map.get(key); + } + + public void putContext(Class key, Object contextObject) throws NullPointerException { + if (key == null || contextObject == null) { + throw new NullPointerException(); + } + + if (this.map == null) { + this.map = new HashMap, Object>(); + } + + this.map.put(key, contextObject); + } + + public void setPropertyResolved(boolean resolved) { + this.resolved = resolved; + } + + public boolean isPropertyResolved() { + return this.resolved; + } + + public abstract ELResolver getELResolver(); + + public abstract FunctionMapper getFunctionMapper(); + + public abstract VariableMapper getVariableMapper(); + + public Locale getLocale() { + return this.locale; + } + + public void setLocale(Locale locale) { + this.locale = locale; + } +} diff --git a/java/javax/el/ELContextEvent.java b/java/javax/el/ELContextEvent.java index 5e38fa2cf..8f8607265 100644 --- a/java/javax/el/ELContextEvent.java +++ b/java/javax/el/ELContextEvent.java @@ -1,37 +1,37 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.util.EventObject; - -/** - * - */ -public class ELContextEvent extends EventObject { - - /** - * @param source - */ - public ELContextEvent(ELContext source) { - super(source); - } - - public ELContext getELContext() { - return (ELContext) this.getSource(); - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.util.EventObject; + +/** + * + */ +public class ELContextEvent extends EventObject { + + /** + * @param source + */ + public ELContextEvent(ELContext source) { + super(source); + } + + public ELContext getELContext() { + return (ELContext) this.getSource(); + } + +} diff --git a/java/javax/el/ELContextListener.java b/java/javax/el/ELContextListener.java index e070b4bd9..5ddfa55eb 100644 --- a/java/javax/el/ELContextListener.java +++ b/java/javax/el/ELContextListener.java @@ -1,27 +1,27 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * @author Jacob Hookom [jacob/hookom.net] - * - */ -public interface ELContextListener { - - public void contextCreated(ELContextEvent event); - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * @author Jacob Hookom [jacob/hookom.net] + * + */ +public interface ELContextListener { + + public void contextCreated(ELContextEvent event); + +} diff --git a/java/javax/el/ELException.java b/java/javax/el/ELException.java index cdc0c027f..d1e195211 100644 --- a/java/javax/el/ELException.java +++ b/java/javax/el/ELException.java @@ -1,65 +1,65 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * Represents any of the exception conditions that can arise during expression - * evaluation. - * - * @since 2.1 - */ -public class ELException extends RuntimeException { - - /** - * Creates an ELException with no detail message - */ - public ELException() { - super(); - } - - /** - * Creates an ELException with the provided detail message. - * - * @param message - * the detail message - */ - public ELException(String message) { - super(message); - } - - /** - * Creates an ELException with the given detail message and root cause. - * - * @param message - * the detail message - * @param cause - * the originating cause of this exception - */ - public ELException(String message, Throwable cause) { - super(message, cause); - } - - /** - * Creates an ELException with the given cause - * - * @param cause - * the originating cause of this exception - */ - public ELException(Throwable cause) { - super(cause); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * Represents any of the exception conditions that can arise during expression + * evaluation. + * + * @since 2.1 + */ +public class ELException extends RuntimeException { + + /** + * Creates an ELException with no detail message + */ + public ELException() { + super(); + } + + /** + * Creates an ELException with the provided detail message. + * + * @param message + * the detail message + */ + public ELException(String message) { + super(message); + } + + /** + * Creates an ELException with the given detail message and root cause. + * + * @param message + * the detail message + * @param cause + * the originating cause of this exception + */ + public ELException(String message, Throwable cause) { + super(message, cause); + } + + /** + * Creates an ELException with the given cause + * + * @param cause + * the originating cause of this exception + */ + public ELException(Throwable cause) { + super(cause); + } +} diff --git a/java/javax/el/ELResolver.java b/java/javax/el/ELResolver.java index e804734d1..722e934a7 100644 --- a/java/javax/el/ELResolver.java +++ b/java/javax/el/ELResolver.java @@ -1,68 +1,68 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.text.MessageFormat; -import java.util.Iterator; -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -/** - * @author Jacob Hookom [jacob/hookom.net] - * - */ -public abstract class ELResolver { - - static String message(ELContext context, String name, Object[] props) { - Locale locale = context.getLocale(); - if (locale == null) { - locale = Locale.getDefault(); - if (locale == null) { - return ""; - } - } - ResourceBundle bundle = ResourceBundle.getBundle( - "javax.el.LocalStrings", locale); - try { - String template = bundle.getString(name); - if (props != null) { - template = MessageFormat.format(template, props); - } - return template; - } catch (MissingResourceException e) { - return "Missing Resource: '" + name + "' for Locale " - + locale.getDisplayName(); - } - } - - public final static String RESOLVABLE_AT_DESIGN_TIME = "resolvableAtDesignTime"; - - public final static String TYPE = "type"; - - public abstract Object getValue(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; - - public abstract Class getType(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; - - public abstract void setValue(ELContext context, Object base, Object property, Object value) throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException; - - public abstract boolean isReadOnly(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; - - public abstract Iterator getFeatureDescriptors(ELContext context, Object base); - - public abstract Class getCommonPropertyType(ELContext context, Object base); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.text.MessageFormat; +import java.util.Iterator; +import java.util.Locale; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * @author Jacob Hookom [jacob/hookom.net] + * + */ +public abstract class ELResolver { + + static String message(ELContext context, String name, Object[] props) { + Locale locale = context.getLocale(); + if (locale == null) { + locale = Locale.getDefault(); + if (locale == null) { + return ""; + } + } + ResourceBundle bundle = ResourceBundle.getBundle( + "javax.el.LocalStrings", locale); + try { + String template = bundle.getString(name); + if (props != null) { + template = MessageFormat.format(template, props); + } + return template; + } catch (MissingResourceException e) { + return "Missing Resource: '" + name + "' for Locale " + + locale.getDisplayName(); + } + } + + public final static String RESOLVABLE_AT_DESIGN_TIME = "resolvableAtDesignTime"; + + public final static String TYPE = "type"; + + public abstract Object getValue(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; + + public abstract Class getType(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; + + public abstract void setValue(ELContext context, Object base, Object property, Object value) throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException; + + public abstract boolean isReadOnly(ELContext context, Object base, Object property) throws NullPointerException, PropertyNotFoundException, ELException; + + public abstract Iterator getFeatureDescriptors(ELContext context, Object base); + + public abstract Class getCommonPropertyType(ELContext context, Object base); +} diff --git a/java/javax/el/Expression.java b/java/javax/el/Expression.java index c0a0a8546..ed1a2e5fe 100644 --- a/java/javax/el/Expression.java +++ b/java/javax/el/Expression.java @@ -1,34 +1,34 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.io.Serializable; - -/** - * - */ -public abstract class Expression implements Serializable { - - public abstract boolean equals(Object obj); - - public abstract int hashCode(); - - public abstract String getExpressionString(); - - public abstract boolean isLiteralText(); - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.io.Serializable; + +/** + * + */ +public abstract class Expression implements Serializable { + + public abstract boolean equals(Object obj); + + public abstract int hashCode(); + + public abstract String getExpressionString(); + + public abstract boolean isLiteralText(); + +} diff --git a/java/javax/el/ExpressionFactory.java b/java/javax/el/ExpressionFactory.java index f56de55c3..53e340b57 100644 --- a/java/javax/el/ExpressionFactory.java +++ b/java/javax/el/ExpressionFactory.java @@ -1,39 +1,39 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - * @since 2.1 - */ -public abstract class ExpressionFactory { - - public abstract Object coerceToType(Object obj, Class expectedType) - throws ELException; - - public abstract ValueExpression createValueExpression(ELContext context, - String expression, Class expectedType) - throws NullPointerException, ELException; - - public abstract ValueExpression createValueExpression(Object instance, - Class expectedType); - - public abstract MethodExpression createMethodExpression(ELContext context, - String expression, Class expectedReturnType, - Class[] expectedParamTypes) throws ELException, - NullPointerException; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + * @since 2.1 + */ +public abstract class ExpressionFactory { + + public abstract Object coerceToType(Object obj, Class expectedType) + throws ELException; + + public abstract ValueExpression createValueExpression(ELContext context, + String expression, Class expectedType) + throws NullPointerException, ELException; + + public abstract ValueExpression createValueExpression(Object instance, + Class expectedType); + + public abstract MethodExpression createMethodExpression(ELContext context, + String expression, Class expectedReturnType, + Class[] expectedParamTypes) throws ELException, + NullPointerException; +} diff --git a/java/javax/el/FunctionMapper.java b/java/javax/el/FunctionMapper.java index d02189e4e..09f55b94e 100644 --- a/java/javax/el/FunctionMapper.java +++ b/java/javax/el/FunctionMapper.java @@ -1,28 +1,28 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.lang.reflect.Method; - -/** - * - */ -public abstract class FunctionMapper { - - public abstract Method resolveFunction(String prefix, String localName); - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.lang.reflect.Method; + +/** + * + */ +public abstract class FunctionMapper { + + public abstract Method resolveFunction(String prefix, String localName); + +} diff --git a/java/javax/el/ListELResolver.java b/java/javax/el/ListELResolver.java index e72518583..0d86446a6 100644 --- a/java/javax/el/ListELResolver.java +++ b/java/javax/el/ListELResolver.java @@ -1,168 +1,168 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.beans.FeatureDescriptor; -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Iterator; -import java.util.List; - -public class ListELResolver extends ELResolver { - - private final boolean readOnly; - - private final static Class UNMODIFIABLE = Collections.unmodifiableList( - new ArrayList()).getClass(); - - public ListELResolver() { - this.readOnly = true; - } - - public ListELResolver(boolean readOnly) { - this.readOnly = readOnly; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof List) { - context.setPropertyResolved(true); - List list = (List) base; - int idx = coerce(property); - if (idx < 0 || idx >= list.size()) { - return null; - } - return list.get(idx); - } - - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof List) { - context.setPropertyResolved(true); - List list = (List) base; - int idx = coerce(property); - if (idx < 0 || idx >= list.size()) { - return null; - } - Object obj = list.get(idx); - return (obj != null) ? obj.getClass() : null; - } - - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof List) { - context.setPropertyResolved(true); - List list = (List) base; - - if (this.readOnly) { - throw new PropertyNotWritableException(message(context, - "resolverNotWriteable", new Object[] { base.getClass() - .getName() })); - } - - int idx = coerce(property); - try { - list.set(idx, value); - } catch (UnsupportedOperationException e) { - throw new PropertyNotWritableException(e); - } catch (IndexOutOfBoundsException e) { - throw new PropertyNotFoundException(e); - } - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof List) { - context.setPropertyResolved(true); - List list = (List) base; - int idx = coerce(property); - if (idx < 0 || idx >= list.size()) { - throw new PropertyNotFoundException( - new ArrayIndexOutOfBoundsException(idx).getMessage()); - } - return this.readOnly || UNMODIFIABLE.equals(list.getClass()); - } - - return this.readOnly; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - if (base instanceof List) { - FeatureDescriptor[] descs = new FeatureDescriptor[((List) base).size()]; - for (int i = 0; i < descs.length; i++) { - descs[i] = new FeatureDescriptor(); - descs[i].setDisplayName("["+i+"]"); - descs[i].setExpert(false); - descs[i].setHidden(false); - descs[i].setName(""+i); - descs[i].setPreferred(true); - descs[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); - descs[i].setValue(TYPE, Integer.class); - } - return Arrays.asList(descs).iterator(); - } - return null; - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base != null && base instanceof List) { - return Integer.class; - } - return null; - } - - private final static int coerce(Object property) { - if (property instanceof Number) { - return ((Number) property).intValue(); - } - if (property instanceof Character) { - return ((Character) property).charValue(); - } - if (property instanceof Boolean) { - return (((Boolean) property).booleanValue() ? 1 : 0); - } - throw new IllegalArgumentException(property != null ? property - .toString() : "null"); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.beans.FeatureDescriptor; +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +public class ListELResolver extends ELResolver { + + private final boolean readOnly; + + private final static Class UNMODIFIABLE = Collections.unmodifiableList( + new ArrayList()).getClass(); + + public ListELResolver() { + this.readOnly = true; + } + + public ListELResolver(boolean readOnly) { + this.readOnly = readOnly; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof List) { + context.setPropertyResolved(true); + List list = (List) base; + int idx = coerce(property); + if (idx < 0 || idx >= list.size()) { + return null; + } + return list.get(idx); + } + + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof List) { + context.setPropertyResolved(true); + List list = (List) base; + int idx = coerce(property); + if (idx < 0 || idx >= list.size()) { + return null; + } + Object obj = list.get(idx); + return (obj != null) ? obj.getClass() : null; + } + + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof List) { + context.setPropertyResolved(true); + List list = (List) base; + + if (this.readOnly) { + throw new PropertyNotWritableException(message(context, + "resolverNotWriteable", new Object[] { base.getClass() + .getName() })); + } + + int idx = coerce(property); + try { + list.set(idx, value); + } catch (UnsupportedOperationException e) { + throw new PropertyNotWritableException(e); + } catch (IndexOutOfBoundsException e) { + throw new PropertyNotFoundException(e); + } + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof List) { + context.setPropertyResolved(true); + List list = (List) base; + int idx = coerce(property); + if (idx < 0 || idx >= list.size()) { + throw new PropertyNotFoundException( + new ArrayIndexOutOfBoundsException(idx).getMessage()); + } + return this.readOnly || UNMODIFIABLE.equals(list.getClass()); + } + + return this.readOnly; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + if (base instanceof List) { + FeatureDescriptor[] descs = new FeatureDescriptor[((List) base).size()]; + for (int i = 0; i < descs.length; i++) { + descs[i] = new FeatureDescriptor(); + descs[i].setDisplayName("["+i+"]"); + descs[i].setExpert(false); + descs[i].setHidden(false); + descs[i].setName(""+i); + descs[i].setPreferred(true); + descs[i].setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); + descs[i].setValue(TYPE, Integer.class); + } + return Arrays.asList(descs).iterator(); + } + return null; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base != null && base instanceof List) { + return Integer.class; + } + return null; + } + + private final static int coerce(Object property) { + if (property instanceof Number) { + return ((Number) property).intValue(); + } + if (property instanceof Character) { + return ((Character) property).charValue(); + } + if (property instanceof Boolean) { + return (((Boolean) property).booleanValue() ? 1 : 0); + } + throw new IllegalArgumentException(property != null ? property + .toString() : "null"); + } +} diff --git a/java/javax/el/LocalStrings.properties b/java/javax/el/LocalStrings.properties index 64df6eb23..23726c001 100644 --- a/java/javax/el/LocalStrings.properties +++ b/java/javax/el/LocalStrings.properties @@ -1,23 +1,23 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale en_US - -propertyNotFound=Property '{1}' not found on type {0} -propertyNotReadable=Property '{1}' not readable on type {0} -propertyNotWritable=Property '{1}' not writable on type {0} -propertyReadError=Error reading '{1}' on type {0} -propertyWriteError=Error writing '{1}' on type {0} +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale en_US + +propertyNotFound=Property '{1}' not found on type {0} +propertyNotReadable=Property '{1}' not readable on type {0} +propertyNotWritable=Property '{1}' not writable on type {0} +propertyReadError=Error reading '{1}' on type {0} +propertyWriteError=Error writing '{1}' on type {0} resolverNotWritable=ELResolver not writable for type {0} \ No newline at end of file diff --git a/java/javax/el/MapELResolver.java b/java/javax/el/MapELResolver.java index 9868b5212..fb9592619 100644 --- a/java/javax/el/MapELResolver.java +++ b/java/javax/el/MapELResolver.java @@ -1,140 +1,140 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.beans.FeatureDescriptor; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -public class MapELResolver extends ELResolver { - - private final static Class UNMODIFIABLE = Collections.unmodifiableMap( - new HashMap()).getClass(); - - private final boolean readOnly; - - public MapELResolver() { - this.readOnly = false; - } - - public MapELResolver(boolean readOnly) { - this.readOnly = readOnly; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof Map) { - context.setPropertyResolved(true); - return ((Map) base).get(property); - } - - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof Map) { - context.setPropertyResolved(true); - Object obj = ((Map) base).get(property); - return (obj != null) ? obj.getClass() : null; - } - - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof Map) { - context.setPropertyResolved(true); - - if (this.readOnly) { - throw new PropertyNotWritableException(message(context, - "resolverNotWriteable", new Object[] { base.getClass() - .getName() })); - } - - try { - ((Map) base).put(property, value); - } catch (UnsupportedOperationException e) { - throw new PropertyNotWritableException(e); - } - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof Map) { - context.setPropertyResolved(true); - return this.readOnly || UNMODIFIABLE.equals(base.getClass()); - } - - return this.readOnly; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - if (base instanceof Map) { - Iterator itr = ((Map) base).keySet().iterator(); - List feats = new ArrayList(); - Object key; - FeatureDescriptor desc; - while (itr.hasNext()) { - key = itr.next(); - desc = new FeatureDescriptor(); - desc.setDisplayName(key.toString()); - desc.setExpert(false); - desc.setHidden(false); - desc.setName(key.toString()); - desc.setPreferred(true); - desc.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); - desc.setValue(TYPE, key.getClass()); - feats.add(desc); - } - return feats.iterator(); - } - return null; - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base instanceof Map) { - return Object.class; - } - return null; - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.beans.FeatureDescriptor; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class MapELResolver extends ELResolver { + + private final static Class UNMODIFIABLE = Collections.unmodifiableMap( + new HashMap()).getClass(); + + private final boolean readOnly; + + public MapELResolver() { + this.readOnly = false; + } + + public MapELResolver(boolean readOnly) { + this.readOnly = readOnly; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof Map) { + context.setPropertyResolved(true); + return ((Map) base).get(property); + } + + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof Map) { + context.setPropertyResolved(true); + Object obj = ((Map) base).get(property); + return (obj != null) ? obj.getClass() : null; + } + + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof Map) { + context.setPropertyResolved(true); + + if (this.readOnly) { + throw new PropertyNotWritableException(message(context, + "resolverNotWriteable", new Object[] { base.getClass() + .getName() })); + } + + try { + ((Map) base).put(property, value); + } catch (UnsupportedOperationException e) { + throw new PropertyNotWritableException(e); + } + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof Map) { + context.setPropertyResolved(true); + return this.readOnly || UNMODIFIABLE.equals(base.getClass()); + } + + return this.readOnly; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + if (base instanceof Map) { + Iterator itr = ((Map) base).keySet().iterator(); + List feats = new ArrayList(); + Object key; + FeatureDescriptor desc; + while (itr.hasNext()) { + key = itr.next(); + desc = new FeatureDescriptor(); + desc.setDisplayName(key.toString()); + desc.setExpert(false); + desc.setHidden(false); + desc.setName(key.toString()); + desc.setPreferred(true); + desc.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.FALSE); + desc.setValue(TYPE, key.getClass()); + feats.add(desc); + } + return feats.iterator(); + } + return null; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base instanceof Map) { + return Object.class; + } + return null; + } + +} diff --git a/java/javax/el/MethodExpression.java b/java/javax/el/MethodExpression.java index 81fa6a315..90b0d60a8 100644 --- a/java/javax/el/MethodExpression.java +++ b/java/javax/el/MethodExpression.java @@ -1,27 +1,27 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public abstract class MethodExpression extends Expression { - - public abstract MethodInfo getMethodInfo(ELContext context) throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException; - - public abstract Object invoke(ELContext context, Object[] params) throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public abstract class MethodExpression extends Expression { + + public abstract MethodInfo getMethodInfo(ELContext context) throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException; + + public abstract Object invoke(ELContext context, Object[] params) throws NullPointerException, PropertyNotFoundException, MethodNotFoundException, ELException; +} diff --git a/java/javax/el/MethodInfo.java b/java/javax/el/MethodInfo.java index 51057e7aa..3aa3fa2c4 100644 --- a/java/javax/el/MethodInfo.java +++ b/java/javax/el/MethodInfo.java @@ -1,51 +1,51 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public class MethodInfo { - - private final String name; - - private final Class[] paramTypes; - - private final Class returnType; - - /** - * - */ - public MethodInfo(String name, Class returnType, Class[] paramTypes) { - this.name = name; - this.returnType = returnType; - this.paramTypes = paramTypes; - } - - public String getName() { - return this.name; - } - - public Class[] getParamTypes() { - return this.paramTypes; - } - - public Class getReturnType() { - return this.returnType; - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public class MethodInfo { + + private final String name; + + private final Class[] paramTypes; + + private final Class returnType; + + /** + * + */ + public MethodInfo(String name, Class returnType, Class[] paramTypes) { + this.name = name; + this.returnType = returnType; + this.paramTypes = paramTypes; + } + + public String getName() { + return this.name; + } + + public Class[] getParamTypes() { + return this.paramTypes; + } + + public Class getReturnType() { + return this.returnType; + } + +} diff --git a/java/javax/el/MethodNotFoundException.java b/java/javax/el/MethodNotFoundException.java index 0610d066d..f4389de1a 100644 --- a/java/javax/el/MethodNotFoundException.java +++ b/java/javax/el/MethodNotFoundException.java @@ -1,52 +1,52 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public class MethodNotFoundException extends ELException { - - /** - * - */ - public MethodNotFoundException() { - super(); - } - - /** - * @param message - */ - public MethodNotFoundException(String message) { - super(message); - } - - /** - * @param message - * @param cause - */ - public MethodNotFoundException(String message, Throwable cause) { - super(message, cause); - } - - /** - * @param cause - */ - public MethodNotFoundException(Throwable cause) { - super(cause); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public class MethodNotFoundException extends ELException { + + /** + * + */ + public MethodNotFoundException() { + super(); + } + + /** + * @param message + */ + public MethodNotFoundException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public MethodNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param cause + */ + public MethodNotFoundException(Throwable cause) { + super(cause); + } +} diff --git a/java/javax/el/PropertyNotFoundException.java b/java/javax/el/PropertyNotFoundException.java index a2e7b60a6..3ded8904b 100644 --- a/java/javax/el/PropertyNotFoundException.java +++ b/java/javax/el/PropertyNotFoundException.java @@ -1,53 +1,53 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public class PropertyNotFoundException extends ELException { - - /** - * - */ - public PropertyNotFoundException() { - super(); - } - - /** - * @param message - */ - public PropertyNotFoundException(String message) { - super(message); - } - - /** - * @param message - * @param cause - */ - public PropertyNotFoundException(String message, Throwable cause) { - super(message, cause); - } - - /** - * @param cause - */ - public PropertyNotFoundException(Throwable cause) { - super(cause); - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public class PropertyNotFoundException extends ELException { + + /** + * + */ + public PropertyNotFoundException() { + super(); + } + + /** + * @param message + */ + public PropertyNotFoundException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public PropertyNotFoundException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param cause + */ + public PropertyNotFoundException(Throwable cause) { + super(cause); + } + +} diff --git a/java/javax/el/PropertyNotWritableException.java b/java/javax/el/PropertyNotWritableException.java index 0042227a9..ee4a0e32c 100644 --- a/java/javax/el/PropertyNotWritableException.java +++ b/java/javax/el/PropertyNotWritableException.java @@ -1,52 +1,52 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public class PropertyNotWritableException extends ELException { - - /** - * - */ - public PropertyNotWritableException() { - super(); - } - - /** - * @param message - */ - public PropertyNotWritableException(String message) { - super(message); - } - - /** - * @param message - * @param cause - */ - public PropertyNotWritableException(String message, Throwable cause) { - super(message, cause); - } - - /** - * @param cause - */ - public PropertyNotWritableException(Throwable cause) { - super(cause); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public class PropertyNotWritableException extends ELException { + + /** + * + */ + public PropertyNotWritableException() { + super(); + } + + /** + * @param message + */ + public PropertyNotWritableException(String message) { + super(message); + } + + /** + * @param message + * @param cause + */ + public PropertyNotWritableException(String message, Throwable cause) { + super(message, cause); + } + + /** + * @param cause + */ + public PropertyNotWritableException(Throwable cause) { + super(cause); + } +} diff --git a/java/javax/el/ResourceBundleELResolver.java b/java/javax/el/ResourceBundleELResolver.java index 23092c609..7ce0d10b3 100644 --- a/java/javax/el/ResourceBundleELResolver.java +++ b/java/javax/el/ResourceBundleELResolver.java @@ -1,127 +1,127 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -import java.beans.FeatureDescriptor; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -public class ResourceBundleELResolver extends ELResolver { - - public ResourceBundleELResolver() { - super(); - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof ResourceBundle) { - context.setPropertyResolved(true); - - if (property != null) { - try { - return ((ResourceBundle) base).getObject(property - .toString()); - } catch (MissingResourceException mre) { - return "???" + property.toString() + "???"; - } - } - } - - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof ResourceBundle) { - context.setPropertyResolved(true); - } - - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof ResourceBundle) { - context.setPropertyResolved(true); - throw new PropertyNotWritableException(message(context, - "resolverNotWriteable", new Object[] { base.getClass() - .getName() })); - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base instanceof ResourceBundle) { - context.setPropertyResolved(true); - } - - return true; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - if (base instanceof ResourceBundle) { - List feats = new ArrayList(); - Enumeration e = ((ResourceBundle) base).getKeys(); - FeatureDescriptor feat; - String key; - while (e.hasMoreElements()) { - key = (String) e.nextElement(); - feat = new FeatureDescriptor(); - feat.setDisplayName(key); - feat.setExpert(false); - feat.setHidden(false); - feat.setName(key); - feat.setPreferred(true); - feat.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); - feat.setValue(TYPE, String.class); - feats.add(feat); - } - return feats.iterator(); - } - return null; - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base instanceof ResourceBundle) { - return String.class; - } - return null; - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +import java.beans.FeatureDescriptor; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +public class ResourceBundleELResolver extends ELResolver { + + public ResourceBundleELResolver() { + super(); + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof ResourceBundle) { + context.setPropertyResolved(true); + + if (property != null) { + try { + return ((ResourceBundle) base).getObject(property + .toString()); + } catch (MissingResourceException mre) { + return "???" + property.toString() + "???"; + } + } + } + + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof ResourceBundle) { + context.setPropertyResolved(true); + } + + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof ResourceBundle) { + context.setPropertyResolved(true); + throw new PropertyNotWritableException(message(context, + "resolverNotWriteable", new Object[] { base.getClass() + .getName() })); + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base instanceof ResourceBundle) { + context.setPropertyResolved(true); + } + + return true; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + if (base instanceof ResourceBundle) { + List feats = new ArrayList(); + Enumeration e = ((ResourceBundle) base).getKeys(); + FeatureDescriptor feat; + String key; + while (e.hasMoreElements()) { + key = (String) e.nextElement(); + feat = new FeatureDescriptor(); + feat.setDisplayName(key); + feat.setExpert(false); + feat.setHidden(false); + feat.setName(key); + feat.setPreferred(true); + feat.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); + feat.setValue(TYPE, String.class); + feats.add(feat); + } + return feats.iterator(); + } + return null; + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base instanceof ResourceBundle) { + return String.class; + } + return null; + } + +} diff --git a/java/javax/el/ValueExpression.java b/java/javax/el/ValueExpression.java index 87334f9e5..b4fc413d6 100644 --- a/java/javax/el/ValueExpression.java +++ b/java/javax/el/ValueExpression.java @@ -1,34 +1,34 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public abstract class ValueExpression extends Expression { - - public abstract Class getExpectedType(); - - public abstract Class getType(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; - - public abstract boolean isReadOnly(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; - - public abstract void setValue(ELContext context, Object value) throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException; - - public abstract Object getValue(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public abstract class ValueExpression extends Expression { + + public abstract Class getExpectedType(); + + public abstract Class getType(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; + + public abstract boolean isReadOnly(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; + + public abstract void setValue(ELContext context, Object value) throws NullPointerException, PropertyNotFoundException, PropertyNotWritableException, ELException; + + public abstract Object getValue(ELContext context) throws NullPointerException, PropertyNotFoundException, ELException; + +} diff --git a/java/javax/el/VariableMapper.java b/java/javax/el/VariableMapper.java index c47a185b8..3ee6ca282 100644 --- a/java/javax/el/VariableMapper.java +++ b/java/javax/el/VariableMapper.java @@ -1,27 +1,27 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.el; - -/** - * - */ -public abstract class VariableMapper { - - public abstract ValueExpression resolveVariable(String variable); - - public abstract ValueExpression setVariable(String variable, ValueExpression expression); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.el; + +/** + * + */ +public abstract class VariableMapper { + + public abstract ValueExpression resolveVariable(String variable); + + public abstract ValueExpression setVariable(String variable, ValueExpression expression); +} diff --git a/java/javax/mail/Authenticator.java b/java/javax/mail/Authenticator.java index 4a49baed0..6fff081aa 100644 --- a/java/javax/mail/Authenticator.java +++ b/java/javax/mail/Authenticator.java @@ -1,5 +1,5 @@ -package javax.mail; - -public class Authenticator { - -} +package javax.mail; + +public class Authenticator { + +} diff --git a/java/javax/mail/PasswordAuthentication.java b/java/javax/mail/PasswordAuthentication.java index 8ab17547b..a6f4cbf67 100644 --- a/java/javax/mail/PasswordAuthentication.java +++ b/java/javax/mail/PasswordAuthentication.java @@ -1,6 +1,6 @@ -package javax.mail; - -public class PasswordAuthentication { - public PasswordAuthentication(String user, String password) { - } -} +package javax.mail; + +public class PasswordAuthentication { + public PasswordAuthentication(String user, String password) { + } +} diff --git a/java/javax/mail/Session.java b/java/javax/mail/Session.java index 5175f88da..e848b0b4f 100644 --- a/java/javax/mail/Session.java +++ b/java/javax/mail/Session.java @@ -1,12 +1,12 @@ -package javax.mail; - -import java.util.Properties; - -public class Session { - public static Session getInstance(Properties props, Authenticator auth) { - return null; - } - public static Session getInstance(Properties props) { - return null; - } -} +package javax.mail; + +import java.util.Properties; + +public class Session { + public static Session getInstance(Properties props, Authenticator auth) { + return null; + } + public static Session getInstance(Properties props) { + return null; + } +} diff --git a/java/javax/mail/internet/InternetAddress.java b/java/javax/mail/internet/InternetAddress.java index c88b2837e..49bcf1adb 100644 --- a/java/javax/mail/internet/InternetAddress.java +++ b/java/javax/mail/internet/InternetAddress.java @@ -1,6 +1,6 @@ -package javax.mail.internet; - -public class InternetAddress { - public InternetAddress(String from) { - } -} +package javax.mail.internet; + +public class InternetAddress { + public InternetAddress(String from) { + } +} diff --git a/java/javax/mail/internet/MimeMessage.java b/java/javax/mail/internet/MimeMessage.java index 48c0f9af8..eca326872 100644 --- a/java/javax/mail/internet/MimeMessage.java +++ b/java/javax/mail/internet/MimeMessage.java @@ -1,12 +1,12 @@ -package javax.mail.internet; - -import javax.mail.Session; - -public class MimeMessage { - public MimeMessage(Session session) { - } - public void setFrom(InternetAddress from) { - } - public void setSubject(String subject) { - } -} +package javax.mail.internet; + +import javax.mail.Session; + +public class MimeMessage { + public MimeMessage(Session session) { + } + public void setFrom(InternetAddress from) { + } + public void setSubject(String subject) { + } +} diff --git a/java/javax/mail/internet/MimePart.java b/java/javax/mail/internet/MimePart.java index 94ae94ac7..1a98c472d 100644 --- a/java/javax/mail/internet/MimePart.java +++ b/java/javax/mail/internet/MimePart.java @@ -1,4 +1,4 @@ -package javax.mail.internet; - -public interface MimePart { -} +package javax.mail.internet; + +public interface MimePart { +} diff --git a/java/javax/mail/internet/MimePartDataSource.java b/java/javax/mail/internet/MimePartDataSource.java index f2de2a036..b1223efa0 100644 --- a/java/javax/mail/internet/MimePartDataSource.java +++ b/java/javax/mail/internet/MimePartDataSource.java @@ -1,6 +1,6 @@ -package javax.mail.internet; - -public class MimePartDataSource { - public MimePartDataSource(MimePart part) { - } -} +package javax.mail.internet; + +public class MimePartDataSource { + public MimePartDataSource(MimePart part) { + } +} diff --git a/java/javax/persistence/PersistenceContext.java b/java/javax/persistence/PersistenceContext.java index bd6d62f17..80d58f306 100644 --- a/java/javax/persistence/PersistenceContext.java +++ b/java/javax/persistence/PersistenceContext.java @@ -1,36 +1,36 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.persistence; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PersistenceContext { - public enum PersistenceContextType { - TRANSACTION, - EXTENDED - } - String name() default ""; - String unitName() default ""; - PersistenceContextType type() default PersistenceContextType.TRANSACTION; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PersistenceContext { + public enum PersistenceContextType { + TRANSACTION, + EXTENDED + } + String name() default ""; + String unitName() default ""; + PersistenceContextType type() default PersistenceContextType.TRANSACTION; +} diff --git a/java/javax/persistence/PersistenceContexts.java b/java/javax/persistence/PersistenceContexts.java index 9617fd338..dcbd68bdb 100644 --- a/java/javax/persistence/PersistenceContexts.java +++ b/java/javax/persistence/PersistenceContexts.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.persistence; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ ElementType.TYPE }) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PersistenceContexts { - PersistenceContext[] value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ ElementType.TYPE }) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PersistenceContexts { + PersistenceContext[] value(); +} diff --git a/java/javax/persistence/PersistenceUnit.java b/java/javax/persistence/PersistenceUnit.java index a5be36394..1b150ecb9 100644 --- a/java/javax/persistence/PersistenceUnit.java +++ b/java/javax/persistence/PersistenceUnit.java @@ -1,31 +1,31 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.persistence; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PersistenceUnit { - String name() default ""; - String unitName() default ""; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PersistenceUnit { + String name() default ""; + String unitName() default ""; +} diff --git a/java/javax/persistence/PersistenceUnits.java b/java/javax/persistence/PersistenceUnits.java index 224d52d1e..8a00831a5 100644 --- a/java/javax/persistence/PersistenceUnits.java +++ b/java/javax/persistence/PersistenceUnits.java @@ -1,31 +1,31 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.persistence; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import javax.persistence.PersistenceUnit; - -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface PersistenceUnits { - PersistenceUnit[] value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.persistence; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import javax.persistence.PersistenceUnit; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface PersistenceUnits { + PersistenceUnit[] value(); +} diff --git a/java/javax/servlet/Filter.java b/java/javax/servlet/Filter.java index 9068ca0c9..db6d6b7e7 100644 --- a/java/javax/servlet/Filter.java +++ b/java/javax/servlet/Filter.java @@ -1,91 +1,91 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.IOException; - - /** - * A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both. - *

- * Filters perform filtering in the doFilter method. Every Filter has access to - ** a FilterConfig object from which it can obtain its initialization parameters, a - ** reference to the ServletContext which it can use, for example, to load resources - ** needed for filtering tasks. - **

- ** Filters are configured in the deployment descriptor of a web application - **

- ** Examples that have been identified for this design are
- ** 1) Authentication Filters
- ** 2) Logging and Auditing Filters
- ** 3) Image conversion Filters
- ** 4) Data compression Filters
- ** 5) Encryption Filters
- ** 6) Tokenizing Filters
- ** 7) Filters that trigger resource access events
- ** 8) XSL/T filters
- ** 9) Mime-type chain Filter
- * @since Servlet 2.3 - */ - -public interface Filter { - - /** - * Called by the web container to indicate to a filter that it is being placed into - * service. The servlet container calls the init method exactly once after instantiating the - * filter. The init method must complete successfully before the filter is asked to do any - * filtering work.

- - * The web container cannot place the filter into service if the init method either
- * 1.Throws a ServletException
- * 2.Does not return within a time period defined by the web container - */ - public void init(FilterConfig filterConfig) throws ServletException; - - - /** - * The doFilter method of the Filter is called by the container - * each time a request/response pair is passed through the chain due - * to a client request for a resource at the end of the chain. The FilterChain passed in to this - * method allows the Filter to pass on the request and response to the next entity in the - * chain.

- * A typical implementation of this method would follow the following pattern:-
- * 1. Examine the request
- * 2. Optionally wrap the request object with a custom implementation to - * filter content or headers for input filtering
- * 3. Optionally wrap the response object with a custom implementation to - * filter content or headers for output filtering
- * 4. a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()),
- ** 4. b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
- ** 5. Directly set headers on the response after invocation of the next entity in the filter chain. - **/ - public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException; - - /** - * Called by the web container to indicate to a filter that it is being taken out of service. This - * method is only called once all threads within the filter's doFilter method have exited or after - * a timeout period has passed. After the web container calls this method, it will not call the - * doFilter method again on this instance of the filter.

- * - * This method gives the filter an opportunity to clean up any resources that are being held (for - * example, memory, file handles, threads) and make sure that any persistent state is synchronized - * with the filter's current state in memory. - */ - - public void destroy(); - - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.IOException; + + /** + * A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both. + *

+ * Filters perform filtering in the doFilter method. Every Filter has access to + ** a FilterConfig object from which it can obtain its initialization parameters, a + ** reference to the ServletContext which it can use, for example, to load resources + ** needed for filtering tasks. + **

+ ** Filters are configured in the deployment descriptor of a web application + **

+ ** Examples that have been identified for this design are
+ ** 1) Authentication Filters
+ ** 2) Logging and Auditing Filters
+ ** 3) Image conversion Filters
+ ** 4) Data compression Filters
+ ** 5) Encryption Filters
+ ** 6) Tokenizing Filters
+ ** 7) Filters that trigger resource access events
+ ** 8) XSL/T filters
+ ** 9) Mime-type chain Filter
+ * @since Servlet 2.3 + */ + +public interface Filter { + + /** + * Called by the web container to indicate to a filter that it is being placed into + * service. The servlet container calls the init method exactly once after instantiating the + * filter. The init method must complete successfully before the filter is asked to do any + * filtering work.

+ + * The web container cannot place the filter into service if the init method either
+ * 1.Throws a ServletException
+ * 2.Does not return within a time period defined by the web container + */ + public void init(FilterConfig filterConfig) throws ServletException; + + + /** + * The doFilter method of the Filter is called by the container + * each time a request/response pair is passed through the chain due + * to a client request for a resource at the end of the chain. The FilterChain passed in to this + * method allows the Filter to pass on the request and response to the next entity in the + * chain.

+ * A typical implementation of this method would follow the following pattern:-
+ * 1. Examine the request
+ * 2. Optionally wrap the request object with a custom implementation to + * filter content or headers for input filtering
+ * 3. Optionally wrap the response object with a custom implementation to + * filter content or headers for output filtering
+ * 4. a) Either invoke the next entity in the chain using the FilterChain object (chain.doFilter()),
+ ** 4. b) or not pass on the request/response pair to the next entity in the filter chain to block the request processing
+ ** 5. Directly set headers on the response after invocation of the next entity in the filter chain. + **/ + public void doFilter ( ServletRequest request, ServletResponse response, FilterChain chain ) throws IOException, ServletException; + + /** + * Called by the web container to indicate to a filter that it is being taken out of service. This + * method is only called once all threads within the filter's doFilter method have exited or after + * a timeout period has passed. After the web container calls this method, it will not call the + * doFilter method again on this instance of the filter.

+ * + * This method gives the filter an opportunity to clean up any resources that are being held (for + * example, memory, file handles, threads) and make sure that any persistent state is synchronized + * with the filter's current state in memory. + */ + + public void destroy(); + + +} + diff --git a/java/javax/servlet/FilterChain.java b/java/javax/servlet/FilterChain.java index 1c60c9f5a..d6210d5e5 100644 --- a/java/javax/servlet/FilterChain.java +++ b/java/javax/servlet/FilterChain.java @@ -1,45 +1,45 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.IOException; - - /** - * A FilterChain is an object provided by the servlet container to the developer - * giving a view into the invocation chain of a filtered request for a resource. Filters - * use the FilterChain to invoke the next filter in the chain, or if the calling filter - * is the last filter in the chain, to invoke the resource at the end of the chain. - * - * @see Filter - * @since Servlet 2.3 - **/ - -public interface FilterChain { - - /** - * Causes the next filter in the chain to be invoked, or if the calling filter is the last filter - * in the chain, causes the resource at the end of the chain to be invoked. - * - * @param request the request to pass along the chain. - * @param response the response to pass along the chain. - * - * @since 2.3 - */ - - public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException; - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.IOException; + + /** + * A FilterChain is an object provided by the servlet container to the developer + * giving a view into the invocation chain of a filtered request for a resource. Filters + * use the FilterChain to invoke the next filter in the chain, or if the calling filter + * is the last filter in the chain, to invoke the resource at the end of the chain. + * + * @see Filter + * @since Servlet 2.3 + **/ + +public interface FilterChain { + + /** + * Causes the next filter in the chain to be invoked, or if the calling filter is the last filter + * in the chain, causes the resource at the end of the chain to be invoked. + * + * @param request the request to pass along the chain. + * @param response the response to pass along the chain. + * + * @since 2.3 + */ + + public void doFilter ( ServletRequest request, ServletResponse response ) throws IOException, ServletException; + +} + diff --git a/java/javax/servlet/FilterConfig.java b/java/javax/servlet/FilterConfig.java index 58eeb2471..05c609d3b 100644 --- a/java/javax/servlet/FilterConfig.java +++ b/java/javax/servlet/FilterConfig.java @@ -1,91 +1,91 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet; - - -import java.util.Enumeration; - - /** - * - * A filter configuration object used by a servlet container - * to pass information to a filter during initialization. - * @see Filter - * @since Servlet 2.3 - * - */ - - -public interface FilterConfig { - - /** - * Returns the filter-name of this filter as defined in the deployment descriptor. - */ - - public String getFilterName(); - - - /** - * Returns a reference to the {@link ServletContext} in which the caller - * is executing. - * - * - * @return a {@link ServletContext} object, used - * by the caller to interact with its servlet - * container - * - * @see ServletContext - * - */ - - public ServletContext getServletContext(); - - /** - * Returns a String containing the value of the - * named initialization parameter, or null if - * the parameter does not exist. - * - * @param name a String specifying the name - * of the initialization parameter - * - * @return a String containing the value - * of the initialization parameter - * - */ - - public String getInitParameter(String name); - - - /** - * Returns the names of the filter's initialization parameters - * as an Enumeration of String objects, - * or an empty Enumeration if the filter has - * no initialization parameters. - * - * @return an Enumeration of String - * objects containing the names of the filter's - * initialization parameters - * - * - * - */ - - public Enumeration getInitParameterNames(); - - - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet; + + +import java.util.Enumeration; + + /** + * + * A filter configuration object used by a servlet container + * to pass information to a filter during initialization. + * @see Filter + * @since Servlet 2.3 + * + */ + + +public interface FilterConfig { + + /** + * Returns the filter-name of this filter as defined in the deployment descriptor. + */ + + public String getFilterName(); + + + /** + * Returns a reference to the {@link ServletContext} in which the caller + * is executing. + * + * + * @return a {@link ServletContext} object, used + * by the caller to interact with its servlet + * container + * + * @see ServletContext + * + */ + + public ServletContext getServletContext(); + + /** + * Returns a String containing the value of the + * named initialization parameter, or null if + * the parameter does not exist. + * + * @param name a String specifying the name + * of the initialization parameter + * + * @return a String containing the value + * of the initialization parameter + * + */ + + public String getInitParameter(String name); + + + /** + * Returns the names of the filter's initialization parameters + * as an Enumeration of String objects, + * or an empty Enumeration if the filter has + * no initialization parameters. + * + * @return an Enumeration of String + * objects containing the names of the filter's + * initialization parameters + * + * + * + */ + + public Enumeration getInitParameterNames(); + + + + +} diff --git a/java/javax/servlet/GenericServlet.java b/java/javax/servlet/GenericServlet.java index 57134d715..d4081d76d 100644 --- a/java/javax/servlet/GenericServlet.java +++ b/java/javax/servlet/GenericServlet.java @@ -1,323 +1,323 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.IOException; -import java.util.Enumeration; - -/** - * - * Defines a generic, protocol-independent - * servlet. To write an HTTP servlet for use on the - * Web, extend {@link javax.servlet.http.HttpServlet} instead. - * - *

GenericServlet implements the Servlet - * and ServletConfig interfaces. GenericServlet - * may be directly extended by a servlet, although it's more common to extend - * a protocol-specific subclass such as HttpServlet. - * - *

GenericServlet makes writing servlets - * easier. It provides simple versions of the lifecycle methods - * init and destroy and of the methods - * in the ServletConfig interface. GenericServlet - * also implements the log method, declared in the - * ServletContext interface. - * - *

To write a generic servlet, you need only - * override the abstract service method. - * - * - * @author Various - * @version $Version$ - * - * - * - */ - - -public abstract class GenericServlet - implements Servlet, ServletConfig, java.io.Serializable -{ - - private transient ServletConfig config; - - - /** - * - * Does nothing. All of the servlet initialization - * is done by one of the init methods. - * - */ - - public GenericServlet() { } - - - - /** - * Called by the servlet container to indicate to a servlet that the - * servlet is being taken out of service. See {@link Servlet#destroy}. - * - * - */ - - public void destroy() { - } - - - - /** - * Returns a String containing the value of the named - * initialization parameter, or null if the parameter does - * not exist. See {@link ServletConfig#getInitParameter}. - * - *

This method is supplied for convenience. It gets the - * value of the named parameter from the servlet's - * ServletConfig object. - * - * @param name a String specifying the name - * of the initialization parameter - * - * @return String a String containing the value - * of the initialization parameter - * - */ - - public String getInitParameter(String name) { - return getServletConfig().getInitParameter(name); - } - - - - /** - * Returns the names of the servlet's initialization parameters - * as an Enumeration of String objects, - * or an empty Enumeration if the servlet has no - * initialization parameters. See {@link - * ServletConfig#getInitParameterNames}. - * - *

This method is supplied for convenience. It gets the - * parameter names from the servlet's ServletConfig object. - * - * - * @return Enumeration an enumeration of String - * objects containing the names of - * the servlet's initialization parameters - * - */ - - public Enumeration getInitParameterNames() { - return getServletConfig().getInitParameterNames(); - } - - - - - - /** - * Returns this servlet's {@link ServletConfig} object. - * - * @return ServletConfig the ServletConfig object - * that initialized this servlet - * - */ - - public ServletConfig getServletConfig() { - return config; - } - - - - - /** - * Returns a reference to the {@link ServletContext} in which this servlet - * is running. See {@link ServletConfig#getServletContext}. - * - *

This method is supplied for convenience. It gets the - * context from the servlet's ServletConfig object. - * - * - * @return ServletContext the ServletContext object - * passed to this servlet by the init - * method - * - */ - - public ServletContext getServletContext() { - return getServletConfig().getServletContext(); - } - - - - - - /** - * Returns information about the servlet, such as - * author, version, and copyright. - * By default, this method returns an empty string. Override this method - * to have it return a meaningful value. See {@link - * Servlet#getServletInfo}. - * - * - * @return String information about this servlet, by default an - * empty string - * - */ - - public String getServletInfo() { - return ""; - } - - - - - /** - * - * Called by the servlet container to indicate to a servlet that the - * servlet is being placed into service. See {@link Servlet#init}. - * - *

This implementation stores the {@link ServletConfig} - * object it receives from the servlet container for later use. - * When overriding this form of the method, call - * super.init(config). - * - * @param config the ServletConfig object - * that contains configutation - * information for this servlet - * - * @exception ServletException if an exception occurs that - * interrupts the servlet's normal - * operation - * - * - * @see UnavailableException - * - */ - - public void init(ServletConfig config) throws ServletException { - this.config = config; - this.init(); - } - - - - - - /** - * - * A convenience method which can be overridden so that there's no need - * to call super.init(config). - * - *

Instead of overriding {@link #init(ServletConfig)}, simply override - * this method and it will be called by - * GenericServlet.init(ServletConfig config). - * The ServletConfig object can still be retrieved via {@link - * #getServletConfig}. - * - * @exception ServletException if an exception occurs that - * interrupts the servlet's - * normal operation - * - */ - - public void init() throws ServletException { - - } - - - - - /** - * - * Writes the specified message to a servlet log file, prepended by the - * servlet's name. See {@link ServletContext#log(String)}. - * - * @param msg a String specifying - * the message to be written to the log file - * - */ - - public void log(String msg) { - getServletContext().log(getServletName() + ": "+ msg); - } - - - - - /** - * Writes an explanatory message and a stack trace - * for a given Throwable exception - * to the servlet log file, prepended by the servlet's name. - * See {@link ServletContext#log(String, Throwable)}. - * - * - * @param message a String that describes - * the error or exception - * - * @param t the java.lang.Throwable error - * or exception - * - * - */ - - public void log(String message, Throwable t) { - getServletContext().log(getServletName() + ": " + message, t); - } - - - - /** - * Called by the servlet container to allow the servlet to respond to - * a request. See {@link Servlet#service}. - * - *

This method is declared abstract so subclasses, such as - * HttpServlet, must override it. - * - * - * - * @param req the ServletRequest object - * that contains the client's request - * - * @param res the ServletResponse object - * that will contain the servlet's response - * - * @exception ServletException if an exception occurs that - * interferes with the servlet's - * normal operation occurred - * - * @exception IOException if an input or output - * exception occurs - * - */ - - public abstract void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException; - - - - /** - * Returns the name of this servlet instance. - * See {@link ServletConfig#getServletName}. - * - * @return the name of this servlet instance - * - * - * - */ - - public String getServletName() { - return config.getServletName(); - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.IOException; +import java.util.Enumeration; + +/** + * + * Defines a generic, protocol-independent + * servlet. To write an HTTP servlet for use on the + * Web, extend {@link javax.servlet.http.HttpServlet} instead. + * + *

GenericServlet implements the Servlet + * and ServletConfig interfaces. GenericServlet + * may be directly extended by a servlet, although it's more common to extend + * a protocol-specific subclass such as HttpServlet. + * + *

GenericServlet makes writing servlets + * easier. It provides simple versions of the lifecycle methods + * init and destroy and of the methods + * in the ServletConfig interface. GenericServlet + * also implements the log method, declared in the + * ServletContext interface. + * + *

To write a generic servlet, you need only + * override the abstract service method. + * + * + * @author Various + * @version $Version$ + * + * + * + */ + + +public abstract class GenericServlet + implements Servlet, ServletConfig, java.io.Serializable +{ + + private transient ServletConfig config; + + + /** + * + * Does nothing. All of the servlet initialization + * is done by one of the init methods. + * + */ + + public GenericServlet() { } + + + + /** + * Called by the servlet container to indicate to a servlet that the + * servlet is being taken out of service. See {@link Servlet#destroy}. + * + * + */ + + public void destroy() { + } + + + + /** + * Returns a String containing the value of the named + * initialization parameter, or null if the parameter does + * not exist. See {@link ServletConfig#getInitParameter}. + * + *

This method is supplied for convenience. It gets the + * value of the named parameter from the servlet's + * ServletConfig object. + * + * @param name a String specifying the name + * of the initialization parameter + * + * @return String a String containing the value + * of the initialization parameter + * + */ + + public String getInitParameter(String name) { + return getServletConfig().getInitParameter(name); + } + + + + /** + * Returns the names of the servlet's initialization parameters + * as an Enumeration of String objects, + * or an empty Enumeration if the servlet has no + * initialization parameters. See {@link + * ServletConfig#getInitParameterNames}. + * + *

This method is supplied for convenience. It gets the + * parameter names from the servlet's ServletConfig object. + * + * + * @return Enumeration an enumeration of String + * objects containing the names of + * the servlet's initialization parameters + * + */ + + public Enumeration getInitParameterNames() { + return getServletConfig().getInitParameterNames(); + } + + + + + + /** + * Returns this servlet's {@link ServletConfig} object. + * + * @return ServletConfig the ServletConfig object + * that initialized this servlet + * + */ + + public ServletConfig getServletConfig() { + return config; + } + + + + + /** + * Returns a reference to the {@link ServletContext} in which this servlet + * is running. See {@link ServletConfig#getServletContext}. + * + *

This method is supplied for convenience. It gets the + * context from the servlet's ServletConfig object. + * + * + * @return ServletContext the ServletContext object + * passed to this servlet by the init + * method + * + */ + + public ServletContext getServletContext() { + return getServletConfig().getServletContext(); + } + + + + + + /** + * Returns information about the servlet, such as + * author, version, and copyright. + * By default, this method returns an empty string. Override this method + * to have it return a meaningful value. See {@link + * Servlet#getServletInfo}. + * + * + * @return String information about this servlet, by default an + * empty string + * + */ + + public String getServletInfo() { + return ""; + } + + + + + /** + * + * Called by the servlet container to indicate to a servlet that the + * servlet is being placed into service. See {@link Servlet#init}. + * + *

This implementation stores the {@link ServletConfig} + * object it receives from the servlet container for later use. + * When overriding this form of the method, call + * super.init(config). + * + * @param config the ServletConfig object + * that contains configutation + * information for this servlet + * + * @exception ServletException if an exception occurs that + * interrupts the servlet's normal + * operation + * + * + * @see UnavailableException + * + */ + + public void init(ServletConfig config) throws ServletException { + this.config = config; + this.init(); + } + + + + + + /** + * + * A convenience method which can be overridden so that there's no need + * to call super.init(config). + * + *

Instead of overriding {@link #init(ServletConfig)}, simply override + * this method and it will be called by + * GenericServlet.init(ServletConfig config). + * The ServletConfig object can still be retrieved via {@link + * #getServletConfig}. + * + * @exception ServletException if an exception occurs that + * interrupts the servlet's + * normal operation + * + */ + + public void init() throws ServletException { + + } + + + + + /** + * + * Writes the specified message to a servlet log file, prepended by the + * servlet's name. See {@link ServletContext#log(String)}. + * + * @param msg a String specifying + * the message to be written to the log file + * + */ + + public void log(String msg) { + getServletContext().log(getServletName() + ": "+ msg); + } + + + + + /** + * Writes an explanatory message and a stack trace + * for a given Throwable exception + * to the servlet log file, prepended by the servlet's name. + * See {@link ServletContext#log(String, Throwable)}. + * + * + * @param message a String that describes + * the error or exception + * + * @param t the java.lang.Throwable error + * or exception + * + * + */ + + public void log(String message, Throwable t) { + getServletContext().log(getServletName() + ": " + message, t); + } + + + + /** + * Called by the servlet container to allow the servlet to respond to + * a request. See {@link Servlet#service}. + * + *

This method is declared abstract so subclasses, such as + * HttpServlet, must override it. + * + * + * + * @param req the ServletRequest object + * that contains the client's request + * + * @param res the ServletResponse object + * that will contain the servlet's response + * + * @exception ServletException if an exception occurs that + * interferes with the servlet's + * normal operation occurred + * + * @exception IOException if an input or output + * exception occurs + * + */ + + public abstract void service(ServletRequest req, ServletResponse res) + throws ServletException, IOException; + + + + /** + * Returns the name of this servlet instance. + * See {@link ServletConfig#getServletName}. + * + * @return the name of this servlet instance + * + * + * + */ + + public String getServletName() { + return config.getServletName(); + } +} diff --git a/java/javax/servlet/LocalStrings.properties b/java/javax/servlet/LocalStrings.properties index bd4a59a6a..c1dcf48da 100644 --- a/java/javax/servlet/LocalStrings.properties +++ b/java/javax/servlet/LocalStrings.properties @@ -1,20 +1,20 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale en_US - -err.not_iso8859_1=Not an ISO 8859-1 character: {0} -value.true=true -value.false=false +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale en_US + +err.not_iso8859_1=Not an ISO 8859-1 character: {0} +value.true=true +value.false=false diff --git a/java/javax/servlet/LocalStrings_fr.properties b/java/javax/servlet/LocalStrings_fr.properties index 0e4477ba3..987309bd9 100644 --- a/java/javax/servlet/LocalStrings_fr.properties +++ b/java/javax/servlet/LocalStrings_fr.properties @@ -1,22 +1,22 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale fr_FR - -err.not_iso8859_1={0} n''est pas un caractère ISO 8859-1 -value.true=true -value.false=false - - +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale fr_FR + +err.not_iso8859_1={0} n''est pas un caractère ISO 8859-1 +value.true=true +value.false=false + + diff --git a/java/javax/servlet/LocalStrings_ja.properties b/java/javax/servlet/LocalStrings_ja.properties index f63ab7a31..4ed3709f9 100644 --- a/java/javax/servlet/LocalStrings_ja.properties +++ b/java/javax/servlet/LocalStrings_ja.properties @@ -1,20 +1,20 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale ja_JP - -err.not_iso8859_1=ISO 8859-1 \u306e\u6587\u5b57\u3067\u306f\u3042\u308a\u307e\u305b\u3093: {0} -value.true=true -value.false=false +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale ja_JP + +err.not_iso8859_1=ISO 8859-1 \u306e\u6587\u5b57\u3067\u306f\u3042\u308a\u307e\u305b\u3093: {0} +value.true=true +value.false=false diff --git a/java/javax/servlet/RequestDispatcher.java b/java/javax/servlet/RequestDispatcher.java index 17880c753..1993728e7 100644 --- a/java/javax/servlet/RequestDispatcher.java +++ b/java/javax/servlet/RequestDispatcher.java @@ -1,138 +1,138 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet; - -import java.io.IOException; - - -/** - * Defines an object that receives requests from the client - * and sends them to any resource (such as a servlet, - * HTML file, or JSP file) on the server. The servlet - * container creates the RequestDispatcher object, - * which is used as a wrapper around a server resource located - * at a particular path or given by a particular name. - * - *

This interface is intended to wrap servlets, - * but a servlet container can create RequestDispatcher - * objects to wrap any type of resource. - * - * @author Various - * @version $Version$ - * - * @see ServletContext#getRequestDispatcher(java.lang.String) - * @see ServletContext#getNamedDispatcher(java.lang.String) - * @see ServletRequest#getRequestDispatcher(java.lang.String) - * - */ - -public interface RequestDispatcher { - - - - - -/** - * Forwards a request from - * a servlet to another resource (servlet, JSP file, or - * HTML file) on the server. This method allows - * one servlet to do preliminary processing of - * a request and another resource to generate - * the response. - * - *

For a RequestDispatcher obtained via - * getRequestDispatcher(), the ServletRequest - * object has its path elements and parameters adjusted to match - * the path of the target resource. - * - *

forward should be called before the response has been - * committed to the client (before response body output has been flushed). - * If the response already has been committed, this method throws - * an IllegalStateException. - * Uncommitted output in the response buffer is automatically cleared - * before the forward. - * - *

The request and response parameters must be either the same - * objects as were passed to the calling servlet's service method or be - * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes - * that wrap them. - * - * - * @param request a {@link ServletRequest} object - * that represents the request the client - * makes of the servlet - * - * @param response a {@link ServletResponse} object - * that represents the response the servlet - * returns to the client - * - * @exception ServletException if the target resource throws this exception - * - * @exception IOException if the target resource throws this exception - * - * @exception IllegalStateException if the response was already committed - * - */ - - public void forward(ServletRequest request, ServletResponse response) - throws ServletException, IOException; - - - - - /** - * - * Includes the content of a resource (servlet, JSP page, - * HTML file) in the response. In essence, this method enables - * programmatic server-side includes. - * - *

The {@link ServletResponse} object has its path elements - * and parameters remain unchanged from the caller's. The included - * servlet cannot change the response status code or set headers; - * any attempt to make a change is ignored. - * - *

The request and response parameters must be either the same - * objects as were passed to the calling servlet's service method or be - * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes - * that wrap them. - * - * - * - * @param request a {@link ServletRequest} object - * that contains the client's request - * - * @param response a {@link ServletResponse} object - * that contains the servlet's response - * - * @exception ServletException if the included resource throws this exception - * - * @exception IOException if the included resource throws this exception - * - * - */ - - public void include(ServletRequest request, ServletResponse response) - throws ServletException, IOException; -} - - - - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet; + +import java.io.IOException; + + +/** + * Defines an object that receives requests from the client + * and sends them to any resource (such as a servlet, + * HTML file, or JSP file) on the server. The servlet + * container creates the RequestDispatcher object, + * which is used as a wrapper around a server resource located + * at a particular path or given by a particular name. + * + *

This interface is intended to wrap servlets, + * but a servlet container can create RequestDispatcher + * objects to wrap any type of resource. + * + * @author Various + * @version $Version$ + * + * @see ServletContext#getRequestDispatcher(java.lang.String) + * @see ServletContext#getNamedDispatcher(java.lang.String) + * @see ServletRequest#getRequestDispatcher(java.lang.String) + * + */ + +public interface RequestDispatcher { + + + + + +/** + * Forwards a request from + * a servlet to another resource (servlet, JSP file, or + * HTML file) on the server. This method allows + * one servlet to do preliminary processing of + * a request and another resource to generate + * the response. + * + *

For a RequestDispatcher obtained via + * getRequestDispatcher(), the ServletRequest + * object has its path elements and parameters adjusted to match + * the path of the target resource. + * + *

forward should be called before the response has been + * committed to the client (before response body output has been flushed). + * If the response already has been committed, this method throws + * an IllegalStateException. + * Uncommitted output in the response buffer is automatically cleared + * before the forward. + * + *

The request and response parameters must be either the same + * objects as were passed to the calling servlet's service method or be + * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes + * that wrap them. + * + * + * @param request a {@link ServletRequest} object + * that represents the request the client + * makes of the servlet + * + * @param response a {@link ServletResponse} object + * that represents the response the servlet + * returns to the client + * + * @exception ServletException if the target resource throws this exception + * + * @exception IOException if the target resource throws this exception + * + * @exception IllegalStateException if the response was already committed + * + */ + + public void forward(ServletRequest request, ServletResponse response) + throws ServletException, IOException; + + + + + /** + * + * Includes the content of a resource (servlet, JSP page, + * HTML file) in the response. In essence, this method enables + * programmatic server-side includes. + * + *

The {@link ServletResponse} object has its path elements + * and parameters remain unchanged from the caller's. The included + * servlet cannot change the response status code or set headers; + * any attempt to make a change is ignored. + * + *

The request and response parameters must be either the same + * objects as were passed to the calling servlet's service method or be + * subclasses of the {@link ServletRequestWrapper} or {@link ServletResponseWrapper} classes + * that wrap them. + * + * + * + * @param request a {@link ServletRequest} object + * that contains the client's request + * + * @param response a {@link ServletResponse} object + * that contains the servlet's response + * + * @exception ServletException if the included resource throws this exception + * + * @exception IOException if the included resource throws this exception + * + * + */ + + public void include(ServletRequest request, ServletResponse response) + throws ServletException, IOException; +} + + + + + + + + diff --git a/java/javax/servlet/Servlet.java b/java/javax/servlet/Servlet.java index 0153838d6..3d568deb5 100644 --- a/java/javax/servlet/Servlet.java +++ b/java/javax/servlet/Servlet.java @@ -1,192 +1,192 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet; - -import java.io.IOException; - - -/** - * Defines methods that all servlets must implement. - * - *

A servlet is a small Java program that runs within a Web server. - * Servlets receive and respond to requests from Web clients, - * usually across HTTP, the HyperText Transfer Protocol. - * - *

To implement this interface, you can write a generic servlet - * that extends - * javax.servlet.GenericServlet or an HTTP servlet that - * extends javax.servlet.http.HttpServlet. - * - *

This interface defines methods to initialize a servlet, - * to service requests, and to remove a servlet from the server. - * These are known as life-cycle methods and are called in the - * following sequence: - *

    - *
  1. The servlet is constructed, then initialized with the init method. - *
  2. Any calls from clients to the service method are handled. - *
  3. The servlet is taken out of service, then destroyed with the - * destroy method, then garbage collected and finalized. - *
- * - *

In addition to the life-cycle methods, this interface - * provides the getServletConfig method, which the servlet - * can use to get any startup information, and the getServletInfo - * method, which allows the servlet to return basic information about itself, - * such as author, version, and copyright. - * - * @author Various - * @version $Version$ - * - * @see GenericServlet - * @see javax.servlet.http.HttpServlet - * - */ - - -public interface Servlet { - - /** - * Called by the servlet container to indicate to a servlet that the - * servlet is being placed into service. - * - *

The servlet container calls the init - * method exactly once after instantiating the servlet. - * The init method must complete successfully - * before the servlet can receive any requests. - * - *

The servlet container cannot place the servlet into service - * if the init method - *

    - *
  1. Throws a ServletException - *
  2. Does not return within a time period defined by the Web server - *
- * - * - * @param config a ServletConfig object - * containing the servlet's - * configuration and initialization parameters - * - * @exception ServletException if an exception has occurred that - * interferes with the servlet's normal - * operation - * - * @see UnavailableException - * @see #getServletConfig - * - */ - - public void init(ServletConfig config) throws ServletException; - - - - /** - * - * Returns a {@link ServletConfig} object, which contains - * initialization and startup parameters for this servlet. - * The ServletConfig object returned is the one - * passed to the init method. - * - *

Implementations of this interface are responsible for storing the - * ServletConfig object so that this - * method can return it. The {@link GenericServlet} - * class, which implements this interface, already does this. - * - * @return the ServletConfig object - * that initializes this servlet - * - * @see #init - * - */ - - public ServletConfig getServletConfig(); - - - - /** - * Called by the servlet container to allow the servlet to respond to - * a request. - * - *

This method is only called after the servlet's init() - * method has completed successfully. - * - *

The status code of the response always should be set for a servlet - * that throws or sends an error. - * - * - *

Servlets typically run inside multithreaded servlet containers - * that can handle multiple requests concurrently. Developers must - * be aware to synchronize access to any shared resources such as files, - * network connections, and as well as the servlet's class and instance - * variables. - * More information on multithreaded programming in Java is available in - * - * the Java tutorial on multi-threaded programming. - * - * - * @param req the ServletRequest object that contains - * the client's request - * - * @param res the ServletResponse object that contains - * the servlet's response - * - * @exception ServletException if an exception occurs that interferes - * with the servlet's normal operation - * - * @exception IOException if an input or output exception occurs - * - */ - - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException; - - - - /** - * Returns information about the servlet, such - * as author, version, and copyright. - * - *

The string that this method returns should - * be plain text and not markup of any kind (such as HTML, XML, - * etc.). - * - * @return a String containing servlet information - * - */ - - public String getServletInfo(); - - - - /** - * - * Called by the servlet container to indicate to a servlet that the - * servlet is being taken out of service. This method is - * only called once all threads within the servlet's - * service method have exited or after a timeout - * period has passed. After the servlet container calls this - * method, it will not call the service method again - * on this servlet. - * - *

This method gives the servlet an opportunity - * to clean up any resources that are being held (for example, memory, - * file handles, threads) and make sure that any persistent state is - * synchronized with the servlet's current state in memory. - * - */ - - public void destroy(); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet; + +import java.io.IOException; + + +/** + * Defines methods that all servlets must implement. + * + *

A servlet is a small Java program that runs within a Web server. + * Servlets receive and respond to requests from Web clients, + * usually across HTTP, the HyperText Transfer Protocol. + * + *

To implement this interface, you can write a generic servlet + * that extends + * javax.servlet.GenericServlet or an HTTP servlet that + * extends javax.servlet.http.HttpServlet. + * + *

This interface defines methods to initialize a servlet, + * to service requests, and to remove a servlet from the server. + * These are known as life-cycle methods and are called in the + * following sequence: + *

    + *
  1. The servlet is constructed, then initialized with the init method. + *
  2. Any calls from clients to the service method are handled. + *
  3. The servlet is taken out of service, then destroyed with the + * destroy method, then garbage collected and finalized. + *
+ * + *

In addition to the life-cycle methods, this interface + * provides the getServletConfig method, which the servlet + * can use to get any startup information, and the getServletInfo + * method, which allows the servlet to return basic information about itself, + * such as author, version, and copyright. + * + * @author Various + * @version $Version$ + * + * @see GenericServlet + * @see javax.servlet.http.HttpServlet + * + */ + + +public interface Servlet { + + /** + * Called by the servlet container to indicate to a servlet that the + * servlet is being placed into service. + * + *

The servlet container calls the init + * method exactly once after instantiating the servlet. + * The init method must complete successfully + * before the servlet can receive any requests. + * + *

The servlet container cannot place the servlet into service + * if the init method + *

    + *
  1. Throws a ServletException + *
  2. Does not return within a time period defined by the Web server + *
+ * + * + * @param config a ServletConfig object + * containing the servlet's + * configuration and initialization parameters + * + * @exception ServletException if an exception has occurred that + * interferes with the servlet's normal + * operation + * + * @see UnavailableException + * @see #getServletConfig + * + */ + + public void init(ServletConfig config) throws ServletException; + + + + /** + * + * Returns a {@link ServletConfig} object, which contains + * initialization and startup parameters for this servlet. + * The ServletConfig object returned is the one + * passed to the init method. + * + *

Implementations of this interface are responsible for storing the + * ServletConfig object so that this + * method can return it. The {@link GenericServlet} + * class, which implements this interface, already does this. + * + * @return the ServletConfig object + * that initializes this servlet + * + * @see #init + * + */ + + public ServletConfig getServletConfig(); + + + + /** + * Called by the servlet container to allow the servlet to respond to + * a request. + * + *

This method is only called after the servlet's init() + * method has completed successfully. + * + *

The status code of the response always should be set for a servlet + * that throws or sends an error. + * + * + *

Servlets typically run inside multithreaded servlet containers + * that can handle multiple requests concurrently. Developers must + * be aware to synchronize access to any shared resources such as files, + * network connections, and as well as the servlet's class and instance + * variables. + * More information on multithreaded programming in Java is available in + * + * the Java tutorial on multi-threaded programming. + * + * + * @param req the ServletRequest object that contains + * the client's request + * + * @param res the ServletResponse object that contains + * the servlet's response + * + * @exception ServletException if an exception occurs that interferes + * with the servlet's normal operation + * + * @exception IOException if an input or output exception occurs + * + */ + + public void service(ServletRequest req, ServletResponse res) + throws ServletException, IOException; + + + + /** + * Returns information about the servlet, such + * as author, version, and copyright. + * + *

The string that this method returns should + * be plain text and not markup of any kind (such as HTML, XML, + * etc.). + * + * @return a String containing servlet information + * + */ + + public String getServletInfo(); + + + + /** + * + * Called by the servlet container to indicate to a servlet that the + * servlet is being taken out of service. This method is + * only called once all threads within the servlet's + * service method have exited or after a timeout + * period has passed. After the servlet container calls this + * method, it will not call the service method again + * on this servlet. + * + *

This method gives the servlet an opportunity + * to clean up any resources that are being held (for example, memory, + * file handles, threads) and make sure that any persistent state is + * synchronized with the servlet's current state in memory. + * + */ + + public void destroy(); +} diff --git a/java/javax/servlet/ServletConfig.java b/java/javax/servlet/ServletConfig.java index 094e418cd..e5f9b1b6e 100644 --- a/java/javax/servlet/ServletConfig.java +++ b/java/javax/servlet/ServletConfig.java @@ -1,94 +1,94 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.util.Enumeration; - - - -/** - * - * A servlet configuration object used by a servlet container - * to pass information to a servlet during initialization. - * - */ - -public interface ServletConfig { - - - /** - * Returns the name of this servlet instance. - * The name may be provided via server administration, assigned in the - * web application deployment descriptor, or for an unregistered (and thus - * unnamed) servlet instance it will be the servlet's class name. - * - * @return the name of the servlet instance - * - * - * - */ - - public String getServletName(); - - /** - * Returns a reference to the {@link ServletContext} in which the caller - * is executing. - * - * - * @return a {@link ServletContext} object, used - * by the caller to interact with its servlet - * container - * - * @see ServletContext - * - */ - - public ServletContext getServletContext(); - - /** - * Returns a String containing the value of the - * named initialization parameter, or null if - * the parameter does not exist. - * - * @param name a String specifying the name - * of the initialization parameter - * - * @return a String containing the value - * of the initialization parameter - * - */ - - public String getInitParameter(String name); - - - /** - * Returns the names of the servlet's initialization parameters - * as an Enumeration of String objects, - * or an empty Enumeration if the servlet has - * no initialization parameters. - * - * @return an Enumeration of String - * objects containing the names of the servlet's - * initialization parameters - * - * - * - */ - - public Enumeration getInitParameterNames(); - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.util.Enumeration; + + + +/** + * + * A servlet configuration object used by a servlet container + * to pass information to a servlet during initialization. + * + */ + +public interface ServletConfig { + + + /** + * Returns the name of this servlet instance. + * The name may be provided via server administration, assigned in the + * web application deployment descriptor, or for an unregistered (and thus + * unnamed) servlet instance it will be the servlet's class name. + * + * @return the name of the servlet instance + * + * + * + */ + + public String getServletName(); + + /** + * Returns a reference to the {@link ServletContext} in which the caller + * is executing. + * + * + * @return a {@link ServletContext} object, used + * by the caller to interact with its servlet + * container + * + * @see ServletContext + * + */ + + public ServletContext getServletContext(); + + /** + * Returns a String containing the value of the + * named initialization parameter, or null if + * the parameter does not exist. + * + * @param name a String specifying the name + * of the initialization parameter + * + * @return a String containing the value + * of the initialization parameter + * + */ + + public String getInitParameter(String name); + + + /** + * Returns the names of the servlet's initialization parameters + * as an Enumeration of String objects, + * or an empty Enumeration if the servlet has + * no initialization parameters. + * + * @return an Enumeration of String + * objects containing the names of the servlet's + * initialization parameters + * + * + * + */ + + public Enumeration getInitParameterNames(); + + +} diff --git a/java/javax/servlet/ServletContext.java b/java/javax/servlet/ServletContext.java index 952575a28..855d62c1f 100644 --- a/java/javax/servlet/ServletContext.java +++ b/java/javax/servlet/ServletContext.java @@ -1,645 +1,645 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Enumeration; -import java.util.Set; - - -/** - * - * Defines a set of methods that a servlet uses to communicate with its - * servlet container, for example, to get the MIME type of a file, dispatch - * requests, or write to a log file. - * - *

There is one context per "web application" per Java Virtual Machine. (A - * "web application" is a collection of servlets and content installed under a - * specific subset of the server's URL namespace such as /catalog - * and possibly installed via a .war file.) - * - *

In the case of a web - * application marked "distributed" in its deployment descriptor, there will - * be one context instance for each virtual machine. In this situation, the - * context cannot be used as a location to share global information (because - * the information won't be truly global). Use an external resource like - * a database instead. - * - *

The ServletContext object is contained within - * the {@link ServletConfig} object, which the Web server provides the - * servlet when the servlet is initialized. - * - * @author Various - * @version $Version$ - * - * @see Servlet#getServletConfig - * @see ServletConfig#getServletContext - * - */ - -public interface ServletContext { - - - /** - * Returns a ServletContext object that - * corresponds to a specified URL on the server. - * - *

This method allows servlets to gain - * access to the context for various parts of the server, and as - * needed obtain {@link RequestDispatcher} objects from the context. - * The given path must be begin with "/", is interpreted relative - * to the server's document root and is matched against the context roots of - * other web applications hosted on this container. - * - *

In a security conscious environment, the servlet container may - * return null for a given URL. - * - * @param uripath a String specifying the context path of - * another web application in the container. - * @return the ServletContext object that - * corresponds to the named URL, or null if either - none exists or the container wishes to restrict - * this access. - * - * @see RequestDispatcher - * - */ - - public ServletContext getContext(String uripath); - - - public String getContextPath(); - - - /** - * Returns the major version of the Java Servlet API that this - * servlet container supports. All implementations that comply - * with Version 2.4 must have this method - * return the integer 2. - * - * @return 2 - * - */ - - public int getMajorVersion(); - - - - /** - * Returns the minor version of the Servlet API that this - * servlet container supports. All implementations that comply - * with Version 2.4 must have this method - * return the integer 4. - * - * @return 4 - * - */ - - public int getMinorVersion(); - - - - /** - * Returns the MIME type of the specified file, or null if - * the MIME type is not known. The MIME type is determined - * by the configuration of the servlet container, and may be specified - * in a web application deployment descriptor. Common MIME - * types are "text/html" and "image/gif". - * - * - * @param file a String specifying the name - * of a file - * - * @return a String specifying the file's MIME type - * - */ - - public String getMimeType(String file); - - /** - * Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path - * matches the supplied path argument. Paths indicating subdirectory paths end with a '/'. The returned paths are all - * relative to the root of the web application and have a leading '/'. For example, for a web application - * containing

- - * /welcome.html
- * /catalog/index.html
- * /catalog/products.html
- * /catalog/offers/books.html
- * /catalog/offers/music.html
- * /customer/login.jsp
- * /WEB-INF/web.xml
- * /WEB-INF/classes/com.acme.OrderServlet.class,

- * - * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}
- * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}.
- - - - *@param path the partial path used to match the resources, - * which must start with a / - *@return a Set containing the directory listing, or null if there are no resources in the web application whose path - * begins with the supplied path. - - * @since Servlet 2.3 - */ - - public Set getResourcePaths(String path); - - - - /** - * Returns a URL to the resource that is mapped to a specified - * path. The path must begin with a "/" and is interpreted - * as relative to the current context root. - * - *

This method allows the servlet container to make a resource - * available to servlets from any source. Resources - * can be located on a local or remote - * file system, in a database, or in a .war file. - * - *

The servlet container must implement the URL handlers - * and URLConnection objects that are necessary - * to access the resource. - * - *

This method returns null - * if no resource is mapped to the pathname. - * - *

Some containers may allow writing to the URL returned by - * this method using the methods of the URL class. - * - *

The resource content is returned directly, so be aware that - * requesting a .jsp page returns the JSP source code. - * Use a RequestDispatcher instead to include results of - * an execution. - * - *

This method has a different purpose than - * java.lang.Class.getResource, - * which looks up resources based on a class loader. This - * method does not use class loaders. - * - * @param path a String specifying - * the path to the resource - * - * @return the resource located at the named path, - * or null if there is no resource - * at that path - * - * @exception MalformedURLException if the pathname is not given in - * the correct form - * - */ - - public URL getResource(String path) throws MalformedURLException; - - - - /** - * Returns the resource located at the named path as - * an InputStream object. - * - *

The data in the InputStream can be - * of any type or length. The path must be specified according - * to the rules given in getResource. - * This method returns null if no resource exists at - * the specified path. - * - *

Meta-information such as content length and content type - * that is available via getResource - * method is lost when using this method. - * - *

The servlet container must implement the URL handlers - * and URLConnection objects necessary to access - * the resource. - * - *

This method is different from - * java.lang.Class.getResourceAsStream, - * which uses a class loader. This method allows servlet containers - * to make a resource available - * to a servlet from any location, without using a class loader. - * - * - * @param path a String specifying the path - * to the resource - * - * @return the InputStream returned to the - * servlet, or null if no resource - * exists at the specified path - * - * - */ - - public InputStream getResourceAsStream(String path); - - - - - /** - * - * Returns a {@link RequestDispatcher} object that acts - * as a wrapper for the resource located at the given path. - * A RequestDispatcher object can be used to forward - * a request to the resource or to include the resource in a response. - * The resource can be dynamic or static. - * - *

The pathname must begin with a "/" and is interpreted as relative - * to the current context root. Use getContext to obtain - * a RequestDispatcher for resources in foreign contexts. - * This method returns null if the ServletContext - * cannot return a RequestDispatcher. - * - * @param path a String specifying the pathname - * to the resource - * - * @return a RequestDispatcher object - * that acts as a wrapper for the resource - * at the specified path, or null if - * the ServletContext cannot return - * a RequestDispatcher - * - * @see RequestDispatcher - * @see ServletContext#getContext - * - */ - - public RequestDispatcher getRequestDispatcher(String path); - - - - /** - * Returns a {@link RequestDispatcher} object that acts - * as a wrapper for the named servlet. - * - *

Servlets (and JSP pages also) may be given names via server - * administration or via a web application deployment descriptor. - * A servlet instance can determine its name using - * {@link ServletConfig#getServletName}. - * - *

This method returns null if the - * ServletContext - * cannot return a RequestDispatcher for any reason. - * - * @param name a String specifying the name - * of a servlet to wrap - * - * @return a RequestDispatcher object - * that acts as a wrapper for the named servlet, - * or null if the ServletContext - * cannot return a RequestDispatcher - * - * @see RequestDispatcher - * @see ServletContext#getContext - * @see ServletConfig#getServletName - * - */ - - public RequestDispatcher getNamedDispatcher(String name); - - - - - /** - * - * @deprecated As of Java Servlet API 2.1, with no direct replacement. - * - *

This method was originally defined to retrieve a servlet - * from a ServletContext. In this version, this method - * always returns null and remains only to preserve - * binary compatibility. This method will be permanently removed - * in a future version of the Java Servlet API. - * - *

In lieu of this method, servlets can share information using the - * ServletContext class and can perform shared business logic - * by invoking methods on common non-servlet classes. - * - */ - - public Servlet getServlet(String name) throws ServletException; - - - - - - - /** - * - * @deprecated As of Java Servlet API 2.0, with no replacement. - * - *

This method was originally defined to return an Enumeration - * of all the servlets known to this servlet context. In this - * version, this method always returns an empty enumeration and - * remains only to preserve binary compatibility. This method - * will be permanently removed in a future version of the Java - * Servlet API. - * - */ - - public Enumeration getServlets(); - - - - - - - /** - * @deprecated As of Java Servlet API 2.1, with no replacement. - * - *

This method was originally defined to return an - * Enumeration - * of all the servlet names known to this context. In this version, - * this method always returns an empty Enumeration and - * remains only to preserve binary compatibility. This method will - * be permanently removed in a future version of the Java Servlet API. - * - */ - - public Enumeration getServletNames(); - - - - - - /** - * - * Writes the specified message to a servlet log file, usually - * an event log. The name and type of the servlet log file is - * specific to the servlet container. - * - * - * @param msg a String specifying the - * message to be written to the log file - * - */ - - public void log(String msg); - - - - - - /** - * @deprecated As of Java Servlet API 2.1, use - * {@link #log(String message, Throwable throwable)} - * instead. - * - *

This method was originally defined to write an - * exception's stack trace and an explanatory error message - * to the servlet log file. - * - */ - - public void log(Exception exception, String msg); - - - - - - /** - * Writes an explanatory message and a stack trace - * for a given Throwable exception - * to the servlet log file. The name and type of the servlet log - * file is specific to the servlet container, usually an event log. - * - * - * @param message a String that - * describes the error or exception - * - * @param throwable the Throwable error - * or exception - * - */ - - public void log(String message, Throwable throwable); - - - - - - /** - * Returns a String containing the real path - * for a given virtual path. For example, the path "/index.html" - * returns the absolute file path on the server's filesystem would be - * served by a request for "http://host/contextPath/index.html", - * where contextPath is the context path of this ServletContext.. - * - *

The real path returned will be in a form - * appropriate to the computer and operating system on - * which the servlet container is running, including the - * proper path separators. This method returns null - * if the servlet container cannot translate the virtual path - * to a real path for any reason (such as when the content is - * being made available from a .war archive). - * - * - * @param path a String specifying a virtual path - * - * - * @return a String specifying the real path, - * or null if the translation cannot be performed - * - * - */ - - public String getRealPath(String path); - - - - - /** - * Returns the name and version of the servlet container on which - * the servlet is running. - * - *

The form of the returned string is - * servername/versionnumber. - * For example, the JavaServer Web Development Kit may return the string - * JavaServer Web Dev Kit/1.0. - * - *

The servlet container may return other optional information - * after the primary string in parentheses, for example, - * JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86). - * - * - * @return a String containing at least the - * servlet container name and version number - * - */ - - public String getServerInfo(); - - - - - /** - * Returns a String containing the value of the named - * context-wide initialization parameter, or null if the - * parameter does not exist. - * - *

This method can make available configuration information useful - * to an entire "web application". For example, it can provide a - * webmaster's email address or the name of a system that holds - * critical data. - * - * @param name a String containing the name of the - * parameter whose value is requested - * - * @return a String containing at least the - * servlet container name and version number - * - * @see ServletConfig#getInitParameter - */ - - public String getInitParameter(String name); - - - - - /** - * Returns the names of the context's initialization parameters as an - * Enumeration of String objects, or an - * empty Enumeration if the context has no initialization - * parameters. - * - * @return an Enumeration of String - * objects containing the names of the context's - * initialization parameters - * - * @see ServletConfig#getInitParameter - */ - - public Enumeration getInitParameterNames(); - - - - /** - * Returns the servlet container attribute with the given name, - * or null if there is no attribute by that name. - * An attribute allows a servlet container to give the - * servlet additional information not - * already provided by this interface. See your - * server documentation for information about its attributes. - * A list of supported attributes can be retrieved using - * getAttributeNames. - * - *

The attribute is returned as a java.lang.Object - * or some subclass. - * Attribute names should follow the same convention as package - * names. The Java Servlet API specification reserves names - * matching java.*, javax.*, - * and sun.*. - * - * - * @param name a String specifying the name - * of the attribute - * - * @return an Object containing the value - * of the attribute, or null - * if no attribute exists matching the given - * name - * - * @see ServletContext#getAttributeNames - * - */ - - public Object getAttribute(String name); - - - - - /** - * Returns an Enumeration containing the - * attribute names available - * within this servlet context. Use the - * {@link #getAttribute} method with an attribute name - * to get the value of an attribute. - * - * @return an Enumeration of attribute - * names - * - * @see #getAttribute - * - */ - - public Enumeration getAttributeNames(); - - - - - /** - * - * Binds an object to a given attribute name in this servlet context. If - * the name specified is already used for an attribute, this - * method will replace the attribute with the new to the new attribute. - *

If listeners are configured on the ServletContext the - * container notifies them accordingly. - *

- * If a null value is passed, the effect is the same as calling - * removeAttribute(). - * - *

Attribute names should follow the same convention as package - * names. The Java Servlet API specification reserves names - * matching java.*, javax.*, and - * sun.*. - * - * - * @param name a String specifying the name - * of the attribute - * - * @param object an Object representing the - * attribute to be bound - * - * - * - */ - - public void setAttribute(String name, Object object); - - - - - - /** - * Removes the attribute with the given name from - * the servlet context. After removal, subsequent calls to - * {@link #getAttribute} to retrieve the attribute's value - * will return null. - - *

If listeners are configured on the ServletContext the - * container notifies them accordingly. - - * - * - * @param name a String specifying the name - * of the attribute to be removed - * - */ - - public void removeAttribute(String name); - - /** - * Returns the name of this web application corresponding to this ServletContext as specified in the deployment - * descriptor for this web application by the display-name element. - * - * - * @return The name of the web application or null if no name has been declared in the deployment descriptor. - * @since Servlet 2.3 - */ - - public String getServletContextName(); -} - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Set; + + +/** + * + * Defines a set of methods that a servlet uses to communicate with its + * servlet container, for example, to get the MIME type of a file, dispatch + * requests, or write to a log file. + * + *

There is one context per "web application" per Java Virtual Machine. (A + * "web application" is a collection of servlets and content installed under a + * specific subset of the server's URL namespace such as /catalog + * and possibly installed via a .war file.) + * + *

In the case of a web + * application marked "distributed" in its deployment descriptor, there will + * be one context instance for each virtual machine. In this situation, the + * context cannot be used as a location to share global information (because + * the information won't be truly global). Use an external resource like + * a database instead. + * + *

The ServletContext object is contained within + * the {@link ServletConfig} object, which the Web server provides the + * servlet when the servlet is initialized. + * + * @author Various + * @version $Version$ + * + * @see Servlet#getServletConfig + * @see ServletConfig#getServletContext + * + */ + +public interface ServletContext { + + + /** + * Returns a ServletContext object that + * corresponds to a specified URL on the server. + * + *

This method allows servlets to gain + * access to the context for various parts of the server, and as + * needed obtain {@link RequestDispatcher} objects from the context. + * The given path must be begin with "/", is interpreted relative + * to the server's document root and is matched against the context roots of + * other web applications hosted on this container. + * + *

In a security conscious environment, the servlet container may + * return null for a given URL. + * + * @param uripath a String specifying the context path of + * another web application in the container. + * @return the ServletContext object that + * corresponds to the named URL, or null if either + none exists or the container wishes to restrict + * this access. + * + * @see RequestDispatcher + * + */ + + public ServletContext getContext(String uripath); + + + public String getContextPath(); + + + /** + * Returns the major version of the Java Servlet API that this + * servlet container supports. All implementations that comply + * with Version 2.4 must have this method + * return the integer 2. + * + * @return 2 + * + */ + + public int getMajorVersion(); + + + + /** + * Returns the minor version of the Servlet API that this + * servlet container supports. All implementations that comply + * with Version 2.4 must have this method + * return the integer 4. + * + * @return 4 + * + */ + + public int getMinorVersion(); + + + + /** + * Returns the MIME type of the specified file, or null if + * the MIME type is not known. The MIME type is determined + * by the configuration of the servlet container, and may be specified + * in a web application deployment descriptor. Common MIME + * types are "text/html" and "image/gif". + * + * + * @param file a String specifying the name + * of a file + * + * @return a String specifying the file's MIME type + * + */ + + public String getMimeType(String file); + + /** + * Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path + * matches the supplied path argument. Paths indicating subdirectory paths end with a '/'. The returned paths are all + * relative to the root of the web application and have a leading '/'. For example, for a web application + * containing

+ + * /welcome.html
+ * /catalog/index.html
+ * /catalog/products.html
+ * /catalog/offers/books.html
+ * /catalog/offers/music.html
+ * /customer/login.jsp
+ * /WEB-INF/web.xml
+ * /WEB-INF/classes/com.acme.OrderServlet.class,

+ * + * getResourcePaths("/") returns {"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}
+ * getResourcePaths("/catalog/") returns {"/catalog/index.html", "/catalog/products.html", "/catalog/offers/"}.
+ + + + *@param path the partial path used to match the resources, + * which must start with a / + *@return a Set containing the directory listing, or null if there are no resources in the web application whose path + * begins with the supplied path. + + * @since Servlet 2.3 + */ + + public Set getResourcePaths(String path); + + + + /** + * Returns a URL to the resource that is mapped to a specified + * path. The path must begin with a "/" and is interpreted + * as relative to the current context root. + * + *

This method allows the servlet container to make a resource + * available to servlets from any source. Resources + * can be located on a local or remote + * file system, in a database, or in a .war file. + * + *

The servlet container must implement the URL handlers + * and URLConnection objects that are necessary + * to access the resource. + * + *

This method returns null + * if no resource is mapped to the pathname. + * + *

Some containers may allow writing to the URL returned by + * this method using the methods of the URL class. + * + *

The resource content is returned directly, so be aware that + * requesting a .jsp page returns the JSP source code. + * Use a RequestDispatcher instead to include results of + * an execution. + * + *

This method has a different purpose than + * java.lang.Class.getResource, + * which looks up resources based on a class loader. This + * method does not use class loaders. + * + * @param path a String specifying + * the path to the resource + * + * @return the resource located at the named path, + * or null if there is no resource + * at that path + * + * @exception MalformedURLException if the pathname is not given in + * the correct form + * + */ + + public URL getResource(String path) throws MalformedURLException; + + + + /** + * Returns the resource located at the named path as + * an InputStream object. + * + *

The data in the InputStream can be + * of any type or length. The path must be specified according + * to the rules given in getResource. + * This method returns null if no resource exists at + * the specified path. + * + *

Meta-information such as content length and content type + * that is available via getResource + * method is lost when using this method. + * + *

The servlet container must implement the URL handlers + * and URLConnection objects necessary to access + * the resource. + * + *

This method is different from + * java.lang.Class.getResourceAsStream, + * which uses a class loader. This method allows servlet containers + * to make a resource available + * to a servlet from any location, without using a class loader. + * + * + * @param path a String specifying the path + * to the resource + * + * @return the InputStream returned to the + * servlet, or null if no resource + * exists at the specified path + * + * + */ + + public InputStream getResourceAsStream(String path); + + + + + /** + * + * Returns a {@link RequestDispatcher} object that acts + * as a wrapper for the resource located at the given path. + * A RequestDispatcher object can be used to forward + * a request to the resource or to include the resource in a response. + * The resource can be dynamic or static. + * + *

The pathname must begin with a "/" and is interpreted as relative + * to the current context root. Use getContext to obtain + * a RequestDispatcher for resources in foreign contexts. + * This method returns null if the ServletContext + * cannot return a RequestDispatcher. + * + * @param path a String specifying the pathname + * to the resource + * + * @return a RequestDispatcher object + * that acts as a wrapper for the resource + * at the specified path, or null if + * the ServletContext cannot return + * a RequestDispatcher + * + * @see RequestDispatcher + * @see ServletContext#getContext + * + */ + + public RequestDispatcher getRequestDispatcher(String path); + + + + /** + * Returns a {@link RequestDispatcher} object that acts + * as a wrapper for the named servlet. + * + *

Servlets (and JSP pages also) may be given names via server + * administration or via a web application deployment descriptor. + * A servlet instance can determine its name using + * {@link ServletConfig#getServletName}. + * + *

This method returns null if the + * ServletContext + * cannot return a RequestDispatcher for any reason. + * + * @param name a String specifying the name + * of a servlet to wrap + * + * @return a RequestDispatcher object + * that acts as a wrapper for the named servlet, + * or null if the ServletContext + * cannot return a RequestDispatcher + * + * @see RequestDispatcher + * @see ServletContext#getContext + * @see ServletConfig#getServletName + * + */ + + public RequestDispatcher getNamedDispatcher(String name); + + + + + /** + * + * @deprecated As of Java Servlet API 2.1, with no direct replacement. + * + *

This method was originally defined to retrieve a servlet + * from a ServletContext. In this version, this method + * always returns null and remains only to preserve + * binary compatibility. This method will be permanently removed + * in a future version of the Java Servlet API. + * + *

In lieu of this method, servlets can share information using the + * ServletContext class and can perform shared business logic + * by invoking methods on common non-servlet classes. + * + */ + + public Servlet getServlet(String name) throws ServletException; + + + + + + + /** + * + * @deprecated As of Java Servlet API 2.0, with no replacement. + * + *

This method was originally defined to return an Enumeration + * of all the servlets known to this servlet context. In this + * version, this method always returns an empty enumeration and + * remains only to preserve binary compatibility. This method + * will be permanently removed in a future version of the Java + * Servlet API. + * + */ + + public Enumeration getServlets(); + + + + + + + /** + * @deprecated As of Java Servlet API 2.1, with no replacement. + * + *

This method was originally defined to return an + * Enumeration + * of all the servlet names known to this context. In this version, + * this method always returns an empty Enumeration and + * remains only to preserve binary compatibility. This method will + * be permanently removed in a future version of the Java Servlet API. + * + */ + + public Enumeration getServletNames(); + + + + + + /** + * + * Writes the specified message to a servlet log file, usually + * an event log. The name and type of the servlet log file is + * specific to the servlet container. + * + * + * @param msg a String specifying the + * message to be written to the log file + * + */ + + public void log(String msg); + + + + + + /** + * @deprecated As of Java Servlet API 2.1, use + * {@link #log(String message, Throwable throwable)} + * instead. + * + *

This method was originally defined to write an + * exception's stack trace and an explanatory error message + * to the servlet log file. + * + */ + + public void log(Exception exception, String msg); + + + + + + /** + * Writes an explanatory message and a stack trace + * for a given Throwable exception + * to the servlet log file. The name and type of the servlet log + * file is specific to the servlet container, usually an event log. + * + * + * @param message a String that + * describes the error or exception + * + * @param throwable the Throwable error + * or exception + * + */ + + public void log(String message, Throwable throwable); + + + + + + /** + * Returns a String containing the real path + * for a given virtual path. For example, the path "/index.html" + * returns the absolute file path on the server's filesystem would be + * served by a request for "http://host/contextPath/index.html", + * where contextPath is the context path of this ServletContext.. + * + *

The real path returned will be in a form + * appropriate to the computer and operating system on + * which the servlet container is running, including the + * proper path separators. This method returns null + * if the servlet container cannot translate the virtual path + * to a real path for any reason (such as when the content is + * being made available from a .war archive). + * + * + * @param path a String specifying a virtual path + * + * + * @return a String specifying the real path, + * or null if the translation cannot be performed + * + * + */ + + public String getRealPath(String path); + + + + + /** + * Returns the name and version of the servlet container on which + * the servlet is running. + * + *

The form of the returned string is + * servername/versionnumber. + * For example, the JavaServer Web Development Kit may return the string + * JavaServer Web Dev Kit/1.0. + * + *

The servlet container may return other optional information + * after the primary string in parentheses, for example, + * JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86). + * + * + * @return a String containing at least the + * servlet container name and version number + * + */ + + public String getServerInfo(); + + + + + /** + * Returns a String containing the value of the named + * context-wide initialization parameter, or null if the + * parameter does not exist. + * + *

This method can make available configuration information useful + * to an entire "web application". For example, it can provide a + * webmaster's email address or the name of a system that holds + * critical data. + * + * @param name a String containing the name of the + * parameter whose value is requested + * + * @return a String containing at least the + * servlet container name and version number + * + * @see ServletConfig#getInitParameter + */ + + public String getInitParameter(String name); + + + + + /** + * Returns the names of the context's initialization parameters as an + * Enumeration of String objects, or an + * empty Enumeration if the context has no initialization + * parameters. + * + * @return an Enumeration of String + * objects containing the names of the context's + * initialization parameters + * + * @see ServletConfig#getInitParameter + */ + + public Enumeration getInitParameterNames(); + + + + /** + * Returns the servlet container attribute with the given name, + * or null if there is no attribute by that name. + * An attribute allows a servlet container to give the + * servlet additional information not + * already provided by this interface. See your + * server documentation for information about its attributes. + * A list of supported attributes can be retrieved using + * getAttributeNames. + * + *

The attribute is returned as a java.lang.Object + * or some subclass. + * Attribute names should follow the same convention as package + * names. The Java Servlet API specification reserves names + * matching java.*, javax.*, + * and sun.*. + * + * + * @param name a String specifying the name + * of the attribute + * + * @return an Object containing the value + * of the attribute, or null + * if no attribute exists matching the given + * name + * + * @see ServletContext#getAttributeNames + * + */ + + public Object getAttribute(String name); + + + + + /** + * Returns an Enumeration containing the + * attribute names available + * within this servlet context. Use the + * {@link #getAttribute} method with an attribute name + * to get the value of an attribute. + * + * @return an Enumeration of attribute + * names + * + * @see #getAttribute + * + */ + + public Enumeration getAttributeNames(); + + + + + /** + * + * Binds an object to a given attribute name in this servlet context. If + * the name specified is already used for an attribute, this + * method will replace the attribute with the new to the new attribute. + *

If listeners are configured on the ServletContext the + * container notifies them accordingly. + *

+ * If a null value is passed, the effect is the same as calling + * removeAttribute(). + * + *

Attribute names should follow the same convention as package + * names. The Java Servlet API specification reserves names + * matching java.*, javax.*, and + * sun.*. + * + * + * @param name a String specifying the name + * of the attribute + * + * @param object an Object representing the + * attribute to be bound + * + * + * + */ + + public void setAttribute(String name, Object object); + + + + + + /** + * Removes the attribute with the given name from + * the servlet context. After removal, subsequent calls to + * {@link #getAttribute} to retrieve the attribute's value + * will return null. + + *

If listeners are configured on the ServletContext the + * container notifies them accordingly. + + * + * + * @param name a String specifying the name + * of the attribute to be removed + * + */ + + public void removeAttribute(String name); + + /** + * Returns the name of this web application corresponding to this ServletContext as specified in the deployment + * descriptor for this web application by the display-name element. + * + * + * @return The name of the web application or null if no name has been declared in the deployment descriptor. + * @since Servlet 2.3 + */ + + public String getServletContextName(); +} + + diff --git a/java/javax/servlet/ServletContextAttributeEvent.java b/java/javax/servlet/ServletContextAttributeEvent.java index 5ba383670..e7af9a9da 100644 --- a/java/javax/servlet/ServletContextAttributeEvent.java +++ b/java/javax/servlet/ServletContextAttributeEvent.java @@ -1,59 +1,59 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - - - /** - * This is the event class for notifications about changes to the attributes of the - * servlet context of a web application. - * @see ServletContextAttributeListener - * @since v 2.3 - */ - -public class ServletContextAttributeEvent extends ServletContextEvent { - private String name; - private Object value; - - /** Construct a ServletContextAttributeEvent from the given context for the - ** given attribute name and attribute value. - */ - public ServletContextAttributeEvent(ServletContext source, String name, Object value) { - super(source); - this.name = name; - this.value = value; - } - - /** - * Return the name of the attribute that changed on the ServletContext. - * - */ - public String getName() { - return this.name; - } - - /** - * Returns the value of the attribute that has been added, removed, or replaced. - * If the attribute was added, this is the value of the attribute. If the attribute was - * removed, this is the value of the removed attribute. If the attribute was replaced, this - * is the old value of the attribute. - * - */ - - public Object getValue() { - return this.value; - } -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + + + /** + * This is the event class for notifications about changes to the attributes of the + * servlet context of a web application. + * @see ServletContextAttributeListener + * @since v 2.3 + */ + +public class ServletContextAttributeEvent extends ServletContextEvent { + private String name; + private Object value; + + /** Construct a ServletContextAttributeEvent from the given context for the + ** given attribute name and attribute value. + */ + public ServletContextAttributeEvent(ServletContext source, String name, Object value) { + super(source); + this.name = name; + this.value = value; + } + + /** + * Return the name of the attribute that changed on the ServletContext. + * + */ + public String getName() { + return this.name; + } + + /** + * Returns the value of the attribute that has been added, removed, or replaced. + * If the attribute was added, this is the value of the attribute. If the attribute was + * removed, this is the value of the removed attribute. If the attribute was replaced, this + * is the old value of the attribute. + * + */ + + public Object getValue() { + return this.value; + } +} + diff --git a/java/javax/servlet/ServletContextAttributeListener.java b/java/javax/servlet/ServletContextAttributeListener.java index 7f039830f..3d8b938fa 100644 --- a/java/javax/servlet/ServletContextAttributeListener.java +++ b/java/javax/servlet/ServletContextAttributeListener.java @@ -1,36 +1,36 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.util.EventListener; - - /** Implementations of this interface receive notifications of - ** changes to the attribute list on the servlet context of a web application. - * To receive notification events, the implementation class - * must be configured in the deployment descriptor for the web application. - * @see ServletContextAttributeEvent - * @since v 2.3 - */ - -public interface ServletContextAttributeListener extends EventListener { - /** Notification that a new attribute was added to the servlet context. Called after the attribute is added.*/ -public void attributeAdded(ServletContextAttributeEvent scab); - /** Notification that an existing attribute has been removed from the servlet context. Called after the attribute is removed.*/ -public void attributeRemoved(ServletContextAttributeEvent scab); - /** Notification that an attribute on the servlet context has been replaced. Called after the attribute is replaced. */ -public void attributeReplaced(ServletContextAttributeEvent scab); -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.util.EventListener; + + /** Implementations of this interface receive notifications of + ** changes to the attribute list on the servlet context of a web application. + * To receive notification events, the implementation class + * must be configured in the deployment descriptor for the web application. + * @see ServletContextAttributeEvent + * @since v 2.3 + */ + +public interface ServletContextAttributeListener extends EventListener { + /** Notification that a new attribute was added to the servlet context. Called after the attribute is added.*/ +public void attributeAdded(ServletContextAttributeEvent scab); + /** Notification that an existing attribute has been removed from the servlet context. Called after the attribute is removed.*/ +public void attributeRemoved(ServletContextAttributeEvent scab); + /** Notification that an attribute on the servlet context has been replaced. Called after the attribute is replaced. */ +public void attributeReplaced(ServletContextAttributeEvent scab); +} + diff --git a/java/javax/servlet/ServletContextEvent.java b/java/javax/servlet/ServletContextEvent.java index a69241595..cb7b8878c 100644 --- a/java/javax/servlet/ServletContextEvent.java +++ b/java/javax/servlet/ServletContextEvent.java @@ -1,46 +1,46 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - - - /** - * This is the event class for notifications about changes to - * the servlet context of a web application. - * @see ServletContextListener - * @since v 2.3 - */ - -public class ServletContextEvent extends java.util.EventObject { - - /** Construct a ServletContextEvent from the given context. - * - * @param source - the ServletContext that is sending the event. - */ - public ServletContextEvent(ServletContext source) { - super(source); - } - - /** - * Return the ServletContext that changed. - * - * @return the ServletContext that sent the event. - */ - public ServletContext getServletContext () { - return (ServletContext) super.getSource(); - } - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + + + /** + * This is the event class for notifications about changes to + * the servlet context of a web application. + * @see ServletContextListener + * @since v 2.3 + */ + +public class ServletContextEvent extends java.util.EventObject { + + /** Construct a ServletContextEvent from the given context. + * + * @param source - the ServletContext that is sending the event. + */ + public ServletContextEvent(ServletContext source) { + super(source); + } + + /** + * Return the ServletContext that changed. + * + * @return the ServletContext that sent the event. + */ + public ServletContext getServletContext () { + return (ServletContext) super.getSource(); + } + +} + diff --git a/java/javax/servlet/ServletContextListener.java b/java/javax/servlet/ServletContextListener.java index 0dc655c54..693d2c16e 100644 --- a/java/javax/servlet/ServletContextListener.java +++ b/java/javax/servlet/ServletContextListener.java @@ -1,50 +1,50 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.util.EventListener; - - /** - * Implementations of this interface receive notifications about - * changes to the servlet context of the web application they are - * part of. - * To receive notification events, the implementation class - * must be configured in the deployment descriptor for the web - * application. - * @see ServletContextEvent - * @since v 2.3 - */ - -public interface ServletContextListener extends EventListener { - /** - ** Notification that the web application initialization - ** process is starting. - ** All ServletContextListeners are notified of context - ** initialization before any filter or servlet in the web - ** application is initialized. - */ - - public void contextInitialized ( ServletContextEvent sce ); - - /** - ** Notification that the servlet context is about to be shut down. - ** All servlets and filters have been destroy()ed before any - ** ServletContextListeners are notified of context - ** destruction. - */ - public void contextDestroyed ( ServletContextEvent sce ); -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.util.EventListener; + + /** + * Implementations of this interface receive notifications about + * changes to the servlet context of the web application they are + * part of. + * To receive notification events, the implementation class + * must be configured in the deployment descriptor for the web + * application. + * @see ServletContextEvent + * @since v 2.3 + */ + +public interface ServletContextListener extends EventListener { + /** + ** Notification that the web application initialization + ** process is starting. + ** All ServletContextListeners are notified of context + ** initialization before any filter or servlet in the web + ** application is initialized. + */ + + public void contextInitialized ( ServletContextEvent sce ); + + /** + ** Notification that the servlet context is about to be shut down. + ** All servlets and filters have been destroy()ed before any + ** ServletContextListeners are notified of context + ** destruction. + */ + public void contextDestroyed ( ServletContextEvent sce ); +} + diff --git a/java/javax/servlet/ServletException.java b/java/javax/servlet/ServletException.java index 06e07c5aa..29533cb0f 100644 --- a/java/javax/servlet/ServletException.java +++ b/java/javax/servlet/ServletException.java @@ -1,141 +1,141 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - - -/** - * Defines a general exception a servlet can throw when it - * encounters difficulty. - * - * @author Various - * @version $Version$ - * - */ - - -public class ServletException extends Exception { - - private Throwable rootCause; - - - - - - /** - * Constructs a new servlet exception. - * - */ - - public ServletException() { - super(); - } - - - - - - /** - * Constructs a new servlet exception with the - * specified message. The message can be written - * to the server log and/or displayed for the user. - * - * @param message a String - * specifying the text of - * the exception message - * - */ - - public ServletException(String message) { - super(message); - } - - - - - - /** - * Constructs a new servlet exception when the servlet - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation, including a description message. - * - * - * @param message a String containing - * the text of the exception message - * - * @param rootCause the Throwable exception - * that interfered with the servlet's - * normal operation, making this servlet - * exception necessary - * - */ - - public ServletException(String message, Throwable rootCause) { - super(message); - this.rootCause = rootCause; - } - - - - - - /** - * Constructs a new servlet exception when the servlet - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation. The exception's message is based on the localized - * message of the underlying exception. - * - *

This method calls the getLocalizedMessage method - * on the Throwable exception to get a localized exception - * message. When subclassing ServletException, - * this method can be overridden to create an exception message - * designed for a specific locale. - * - * @param rootCause the Throwable exception - * that interfered with the servlet's - * normal operation, making the servlet exception - * necessary - * - */ - - public ServletException(Throwable rootCause) { - super(rootCause.getLocalizedMessage()); - this.rootCause = rootCause; - } - - - - - - /** - * Returns the exception that caused this servlet exception. - * - * - * @return the Throwable - * that caused this servlet exception - * - */ - - public Throwable getRootCause() { - return rootCause; - } -} - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + + +/** + * Defines a general exception a servlet can throw when it + * encounters difficulty. + * + * @author Various + * @version $Version$ + * + */ + + +public class ServletException extends Exception { + + private Throwable rootCause; + + + + + + /** + * Constructs a new servlet exception. + * + */ + + public ServletException() { + super(); + } + + + + + + /** + * Constructs a new servlet exception with the + * specified message. The message can be written + * to the server log and/or displayed for the user. + * + * @param message a String + * specifying the text of + * the exception message + * + */ + + public ServletException(String message) { + super(message); + } + + + + + + /** + * Constructs a new servlet exception when the servlet + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation, including a description message. + * + * + * @param message a String containing + * the text of the exception message + * + * @param rootCause the Throwable exception + * that interfered with the servlet's + * normal operation, making this servlet + * exception necessary + * + */ + + public ServletException(String message, Throwable rootCause) { + super(message); + this.rootCause = rootCause; + } + + + + + + /** + * Constructs a new servlet exception when the servlet + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation. The exception's message is based on the localized + * message of the underlying exception. + * + *

This method calls the getLocalizedMessage method + * on the Throwable exception to get a localized exception + * message. When subclassing ServletException, + * this method can be overridden to create an exception message + * designed for a specific locale. + * + * @param rootCause the Throwable exception + * that interfered with the servlet's + * normal operation, making the servlet exception + * necessary + * + */ + + public ServletException(Throwable rootCause) { + super(rootCause.getLocalizedMessage()); + this.rootCause = rootCause; + } + + + + + + /** + * Returns the exception that caused this servlet exception. + * + * + * @return the Throwable + * that caused this servlet exception + * + */ + + public Throwable getRootCause() { + return rootCause; + } +} + + + + + diff --git a/java/javax/servlet/ServletInputStream.java b/java/javax/servlet/ServletInputStream.java index b4aecdc7b..bcc3a45d6 100644 --- a/java/javax/servlet/ServletInputStream.java +++ b/java/javax/servlet/ServletInputStream.java @@ -1,105 +1,105 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.InputStream; -import java.io.IOException; - -/** - * - * Provides an input stream for reading binary data from a client - * request, including an efficient readLine method - * for reading data one line at a time. With some protocols, such - * as HTTP POST and PUT, a ServletInputStream - * object can be used to read data sent from the client. - * - *

A ServletInputStream object is normally retrieved via - * the {@link ServletRequest#getInputStream} method. - * - * - *

This is an abstract class that a servlet container implements. - * Subclasses of this class - * must implement the java.io.InputStream.read() method. - * - * - * @author Various - * @version $Version$ - * - * @see ServletRequest - * - */ - -public abstract class ServletInputStream extends InputStream { - - - - /** - * Does nothing, because this is an abstract class. - * - */ - - protected ServletInputStream() { } - - - - - /** - * - * Reads the input stream, one line at a time. Starting at an - * offset, reads bytes into an array, until it reads a certain number - * of bytes or reaches a newline character, which it reads into the - * array as well. - * - *

This method returns -1 if it reaches the end of the input - * stream before reading the maximum number of bytes. - * - * - * - * @param b an array of bytes into which data is read - * - * @param off an integer specifying the character at which - * this method begins reading - * - * @param len an integer specifying the maximum number of - * bytes to read - * - * @return an integer specifying the actual number of bytes - * read, or -1 if the end of the stream is reached - * - * @exception IOException if an input or output exception has occurred - * - */ - - public int readLine(byte[] b, int off, int len) throws IOException { - - if (len <= 0) { - return 0; - } - int count = 0, c; - - while ((c = read()) != -1) { - b[off++] = (byte)c; - count++; - if (c == '\n' || count == len) { - break; - } - } - return count > 0 ? count : -1; - } -} - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.InputStream; +import java.io.IOException; + +/** + * + * Provides an input stream for reading binary data from a client + * request, including an efficient readLine method + * for reading data one line at a time. With some protocols, such + * as HTTP POST and PUT, a ServletInputStream + * object can be used to read data sent from the client. + * + *

A ServletInputStream object is normally retrieved via + * the {@link ServletRequest#getInputStream} method. + * + * + *

This is an abstract class that a servlet container implements. + * Subclasses of this class + * must implement the java.io.InputStream.read() method. + * + * + * @author Various + * @version $Version$ + * + * @see ServletRequest + * + */ + +public abstract class ServletInputStream extends InputStream { + + + + /** + * Does nothing, because this is an abstract class. + * + */ + + protected ServletInputStream() { } + + + + + /** + * + * Reads the input stream, one line at a time. Starting at an + * offset, reads bytes into an array, until it reads a certain number + * of bytes or reaches a newline character, which it reads into the + * array as well. + * + *

This method returns -1 if it reaches the end of the input + * stream before reading the maximum number of bytes. + * + * + * + * @param b an array of bytes into which data is read + * + * @param off an integer specifying the character at which + * this method begins reading + * + * @param len an integer specifying the maximum number of + * bytes to read + * + * @return an integer specifying the actual number of bytes + * read, or -1 if the end of the stream is reached + * + * @exception IOException if an input or output exception has occurred + * + */ + + public int readLine(byte[] b, int off, int len) throws IOException { + + if (len <= 0) { + return 0; + } + int count = 0, c; + + while ((c = read()) != -1) { + b[off++] = (byte)c; + count++; + if (c == '\n' || count == len) { + break; + } + } + return count > 0 ? count : -1; + } +} + + + diff --git a/java/javax/servlet/ServletOutputStream.java b/java/javax/servlet/ServletOutputStream.java index 9d32fb5d0..865b1d192 100644 --- a/java/javax/servlet/ServletOutputStream.java +++ b/java/javax/servlet/ServletOutputStream.java @@ -1,363 +1,363 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.OutputStream; -import java.io.IOException; -import java.io.CharConversionException; -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * Provides an output stream for sending binary data to the - * client. A ServletOutputStream object is normally retrieved - * via the {@link ServletResponse#getOutputStream} method. - * - *

This is an abstract class that the servlet container implements. - * Subclasses of this class - * must implement the java.io.OutputStream.write(int) - * method. - * - * - * @author Various - * @version $Version$ - * - * @see ServletResponse - * - */ - -public abstract class ServletOutputStream extends OutputStream { - - private static final String LSTRING_FILE = "javax.servlet.LocalStrings"; - private static ResourceBundle lStrings = - ResourceBundle.getBundle(LSTRING_FILE); - - - - /** - * - * Does nothing, because this is an abstract class. - * - */ - - protected ServletOutputStream() { } - - - /** - * Writes a String to the client, - * without a carriage return-line feed (CRLF) - * character at the end. - * - * - * @param s the String to send to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void print(String s) throws IOException { - if (s==null) s="null"; - int len = s.length(); - for (int i = 0; i < len; i++) { - char c = s.charAt (i); - - // - // XXX NOTE: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - // - if ((c & 0xff00) != 0) { // high order byte must be zero - String errMsg = lStrings.getString("err.not_iso8859_1"); - Object[] errArgs = new Object[1]; - errArgs[0] = new Character(c); - errMsg = MessageFormat.format(errMsg, errArgs); - throw new CharConversionException(errMsg); - } - write (c); - } - } - - - - /** - * Writes a boolean value to the client, - * with no carriage return-line feed (CRLF) - * character at the end. - * - * @param b the boolean value - * to send to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void print(boolean b) throws IOException { - String msg; - if (b) { - msg = lStrings.getString("value.true"); - } else { - msg = lStrings.getString("value.false"); - } - print(msg); - } - - - - /** - * Writes a character to the client, - * with no carriage return-line feed (CRLF) - * at the end. - * - * @param c the character to send to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void print(char c) throws IOException { - print(String.valueOf(c)); - } - - - - - /** - * - * Writes an int to the client, - * with no carriage return-line feed (CRLF) - * at the end. - * - * @param i the int to send to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void print(int i) throws IOException { - print(String.valueOf(i)); - } - - - - - /** - * - * Writes a long value to the client, - * with no carriage return-line feed (CRLF) at the end. - * - * @param l the long value - * to send to the client - * - * @exception IOException if an input or output exception - * occurred - * - */ - - public void print(long l) throws IOException { - print(String.valueOf(l)); - } - - - - /** - * - * Writes a float value to the client, - * with no carriage return-line feed (CRLF) at the end. - * - * @param f the float value - * to send to the client - * - * @exception IOException if an input or output exception occurred - * - * - */ - - public void print(float f) throws IOException { - print(String.valueOf(f)); - } - - - - /** - * - * Writes a double value to the client, - * with no carriage return-line feed (CRLF) at the end. - * - * @param d the double value - * to send to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void print(double d) throws IOException { - print(String.valueOf(d)); - } - - - - /** - * Writes a carriage return-line feed (CRLF) - * to the client. - * - * - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println() throws IOException { - print("\r\n"); - } - - - - /** - * Writes a String to the client, - * followed by a carriage return-line feed (CRLF). - * - * - * @param s the String to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(String s) throws IOException { - print(s); - println(); - } - - - - - /** - * - * Writes a boolean value to the client, - * followed by a - * carriage return-line feed (CRLF). - * - * - * @param b the boolean value - * to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(boolean b) throws IOException { - print(b); - println(); - } - - - - /** - * - * Writes a character to the client, followed by a carriage - * return-line feed (CRLF). - * - * @param c the character to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(char c) throws IOException { - print(c); - println(); - } - - - - /** - * - * Writes an int to the client, followed by a - * carriage return-line feed (CRLF) character. - * - * - * @param i the int to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(int i) throws IOException { - print(i); - println(); - } - - - - /** - * - * Writes a long value to the client, followed by a - * carriage return-line feed (CRLF). - * - * - * @param l the long value to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(long l) throws IOException { - print(l); - println(); - } - - - - /** - * - * Writes a float value to the client, - * followed by a carriage return-line feed (CRLF). - * - * @param f the float value - * to write to the client - * - * - * @exception IOException if an input or output exception - * occurred - * - */ - - public void println(float f) throws IOException { - print(f); - println(); - } - - - - /** - * - * Writes a double value to the client, - * followed by a carriage return-line feed (CRLF). - * - * - * @param d the double value - * to write to the client - * - * @exception IOException if an input or output exception occurred - * - */ - - public void println(double d) throws IOException { - print(d); - println(); - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.OutputStream; +import java.io.IOException; +import java.io.CharConversionException; +import java.text.MessageFormat; +import java.util.ResourceBundle; + +/** + * Provides an output stream for sending binary data to the + * client. A ServletOutputStream object is normally retrieved + * via the {@link ServletResponse#getOutputStream} method. + * + *

This is an abstract class that the servlet container implements. + * Subclasses of this class + * must implement the java.io.OutputStream.write(int) + * method. + * + * + * @author Various + * @version $Version$ + * + * @see ServletResponse + * + */ + +public abstract class ServletOutputStream extends OutputStream { + + private static final String LSTRING_FILE = "javax.servlet.LocalStrings"; + private static ResourceBundle lStrings = + ResourceBundle.getBundle(LSTRING_FILE); + + + + /** + * + * Does nothing, because this is an abstract class. + * + */ + + protected ServletOutputStream() { } + + + /** + * Writes a String to the client, + * without a carriage return-line feed (CRLF) + * character at the end. + * + * + * @param s the String to send to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void print(String s) throws IOException { + if (s==null) s="null"; + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt (i); + + // + // XXX NOTE: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + // + if ((c & 0xff00) != 0) { // high order byte must be zero + String errMsg = lStrings.getString("err.not_iso8859_1"); + Object[] errArgs = new Object[1]; + errArgs[0] = new Character(c); + errMsg = MessageFormat.format(errMsg, errArgs); + throw new CharConversionException(errMsg); + } + write (c); + } + } + + + + /** + * Writes a boolean value to the client, + * with no carriage return-line feed (CRLF) + * character at the end. + * + * @param b the boolean value + * to send to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void print(boolean b) throws IOException { + String msg; + if (b) { + msg = lStrings.getString("value.true"); + } else { + msg = lStrings.getString("value.false"); + } + print(msg); + } + + + + /** + * Writes a character to the client, + * with no carriage return-line feed (CRLF) + * at the end. + * + * @param c the character to send to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void print(char c) throws IOException { + print(String.valueOf(c)); + } + + + + + /** + * + * Writes an int to the client, + * with no carriage return-line feed (CRLF) + * at the end. + * + * @param i the int to send to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void print(int i) throws IOException { + print(String.valueOf(i)); + } + + + + + /** + * + * Writes a long value to the client, + * with no carriage return-line feed (CRLF) at the end. + * + * @param l the long value + * to send to the client + * + * @exception IOException if an input or output exception + * occurred + * + */ + + public void print(long l) throws IOException { + print(String.valueOf(l)); + } + + + + /** + * + * Writes a float value to the client, + * with no carriage return-line feed (CRLF) at the end. + * + * @param f the float value + * to send to the client + * + * @exception IOException if an input or output exception occurred + * + * + */ + + public void print(float f) throws IOException { + print(String.valueOf(f)); + } + + + + /** + * + * Writes a double value to the client, + * with no carriage return-line feed (CRLF) at the end. + * + * @param d the double value + * to send to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void print(double d) throws IOException { + print(String.valueOf(d)); + } + + + + /** + * Writes a carriage return-line feed (CRLF) + * to the client. + * + * + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println() throws IOException { + print("\r\n"); + } + + + + /** + * Writes a String to the client, + * followed by a carriage return-line feed (CRLF). + * + * + * @param s the String to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(String s) throws IOException { + print(s); + println(); + } + + + + + /** + * + * Writes a boolean value to the client, + * followed by a + * carriage return-line feed (CRLF). + * + * + * @param b the boolean value + * to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(boolean b) throws IOException { + print(b); + println(); + } + + + + /** + * + * Writes a character to the client, followed by a carriage + * return-line feed (CRLF). + * + * @param c the character to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(char c) throws IOException { + print(c); + println(); + } + + + + /** + * + * Writes an int to the client, followed by a + * carriage return-line feed (CRLF) character. + * + * + * @param i the int to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(int i) throws IOException { + print(i); + println(); + } + + + + /** + * + * Writes a long value to the client, followed by a + * carriage return-line feed (CRLF). + * + * + * @param l the long value to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(long l) throws IOException { + print(l); + println(); + } + + + + /** + * + * Writes a float value to the client, + * followed by a carriage return-line feed (CRLF). + * + * @param f the float value + * to write to the client + * + * + * @exception IOException if an input or output exception + * occurred + * + */ + + public void println(float f) throws IOException { + print(f); + println(); + } + + + + /** + * + * Writes a double value to the client, + * followed by a carriage return-line feed (CRLF). + * + * + * @param d the double value + * to write to the client + * + * @exception IOException if an input or output exception occurred + * + */ + + public void println(double d) throws IOException { + print(d); + println(); + } +} diff --git a/java/javax/servlet/ServletRequest.java b/java/javax/servlet/ServletRequest.java index 40ad0312f..a2cf60de6 100644 --- a/java/javax/servlet/ServletRequest.java +++ b/java/javax/servlet/ServletRequest.java @@ -1,597 +1,597 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; - - - -/** - * Defines an object to provide client request information to a servlet. The - * servlet container creates a ServletRequest object and passes - * it as an argument to the servlet's service method. - * - *

A ServletRequest object provides data including - * parameter name and values, attributes, and an input stream. - * Interfaces that extend ServletRequest can provide - * additional protocol-specific data (for example, HTTP data is - * provided by {@link javax.servlet.http.HttpServletRequest}. - * - * @author Various - * @version $Version$ - * - * @see javax.servlet.http.HttpServletRequest - * - */ - -public interface ServletRequest { - - - - - /** - * - * Returns the value of the named attribute as an Object, - * or null if no attribute of the given name exists. - * - *

Attributes can be set two ways. The servlet container may set - * attributes to make available custom information about a request. - * For example, for requests made using HTTPS, the attribute - * javax.servlet.request.X509Certificate can be used to - * retrieve information on the certificate of the client. Attributes - * can also be set programatically using - * {@link ServletRequest#setAttribute}. This allows information to be - * embedded into a request before a {@link RequestDispatcher} call. - * - *

Attribute names should follow the same conventions as package - * names. This specification reserves names matching java.*, - * javax.*, and sun.*. - * - * @param name a String specifying the name of - * the attribute - * - * @return an Object containing the value - * of the attribute, or null if - * the attribute does not exist - * - */ - - public Object getAttribute(String name); - - - - /** - * Returns an Enumeration containing the - * names of the attributes available to this request. - * This method returns an empty Enumeration - * if the request has no attributes available to it. - * - * - * @return an Enumeration of strings - * containing the names - * of the request's attributes - * - */ - - public Enumeration getAttributeNames(); - - - - - /** - * Returns the name of the character encoding used in the body of this - * request. This method returns null if the request - * does not specify a character encoding - * - * - * @return a String containing the name of - * the character encoding, or null - * if the request does not specify a character encoding - * - */ - - public String getCharacterEncoding(); - - /** - * Overrides the name of the character encoding used in the body of this - * request. This method must be called prior to reading request parameters - * or reading input using getReader(). - * - * - * @param env a String containing the name of - * the character encoding. - * @throws java.io.UnsupportedEncodingException if this is not a valid encoding - */ - - public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException; - - - - - - /** - * Returns the length, in bytes, of the request body - * and made available by the input stream, or -1 if the - * length is not known. For HTTP servlets, same as the value - * of the CGI variable CONTENT_LENGTH. - * - * @return an integer containing the length of the - * request body or -1 if the length is not known - * - */ - - public int getContentLength(); - - - - - /** - * Returns the MIME type of the body of the request, or - * null if the type is not known. For HTTP servlets, - * same as the value of the CGI variable CONTENT_TYPE. - * - * @return a String containing the name - * of the MIME type of - * the request, or null if the type is not known - * - */ - - public String getContentType(); - - - - - /** - * Retrieves the body of the request as binary data using - * a {@link ServletInputStream}. Either this method or - * {@link #getReader} may be called to read the body, not both. - * - * @return a {@link ServletInputStream} object containing - * the body of the request - * - * @exception IllegalStateException if the {@link #getReader} method - * has already been called for this request - * - * @exception IOException if an input or output exception occurred - * - */ - - public ServletInputStream getInputStream() throws IOException; - - - - - /** - * Returns the value of a request parameter as a String, - * or null if the parameter does not exist. Request parameters - * are extra information sent with the request. For HTTP servlets, - * parameters are contained in the query string or posted form data. - * - *

You should only use this method when you are sure the - * parameter has only one value. If the parameter might have - * more than one value, use {@link #getParameterValues}. - * - *

If you use this method with a multivalued - * parameter, the value returned is equal to the first value - * in the array returned by getParameterValues. - * - *

If the parameter data was sent in the request body, such as occurs - * with an HTTP POST request, then reading the body directly via {@link - * #getInputStream} or {@link #getReader} can interfere - * with the execution of this method. - * - * @param name a String specifying the - * name of the parameter - * - * @return a String representing the - * single value of the parameter - * - * @see #getParameterValues - * - */ - - public String getParameter(String name); - - - - - /** - * - * Returns an Enumeration of String - * objects containing the names of the parameters contained - * in this request. If the request has - * no parameters, the method returns an - * empty Enumeration. - * - * @return an Enumeration of String - * objects, each String containing - * the name of a request parameter; or an - * empty Enumeration if the - * request has no parameters - * - */ - - public Enumeration getParameterNames(); - - - - - /** - * Returns an array of String objects containing - * all of the values the given request parameter has, or - * null if the parameter does not exist. - * - *

If the parameter has a single value, the array has a length - * of 1. - * - * @param name a String containing the name of - * the parameter whose value is requested - * - * @return an array of String objects - * containing the parameter's values - * - * @see #getParameter - * - */ - - public String[] getParameterValues(String name); - - /** Returns a java.util.Map of the parameters of this request. - * Request parameters - * are extra information sent with the request. For HTTP servlets, - * parameters are contained in the query string or posted form data. - * - * @return an immutable java.util.Map containing parameter names as - * keys and parameter values as map values. The keys in the parameter - * map are of type String. The values in the parameter map are of type - * String array. - * - */ - - public Map getParameterMap(); - - - - /** - * Returns the name and version of the protocol the request uses - * in the form protocol/majorVersion.minorVersion, for - * example, HTTP/1.1. For HTTP servlets, the value - * returned is the same as the value of the CGI variable - * SERVER_PROTOCOL. - * - * @return a String containing the protocol - * name and version number - * - */ - - public String getProtocol(); - - - - - /** - * Returns the name of the scheme used to make this request, - * for example, - * http, https, or ftp. - * Different schemes have different rules for constructing URLs, - * as noted in RFC 1738. - * - * @return a String containing the name - * of the scheme used to make this request - * - */ - - public String getScheme(); - - - - - /** - * Returns the host name of the server to which the request was sent. - * It is the value of the part before ":" in the Host - * header value, if any, or the resolved server name, or the server IP address. - * - * @return a String containing the name - * of the server - */ - - public String getServerName(); - - - - - /** - * Returns the port number to which the request was sent. - * It is the value of the part after ":" in the Host - * header value, if any, or the server port where the client connection - * was accepted on. - * - * @return an integer specifying the port number - * - */ - - public int getServerPort(); - - - - /** - * Retrieves the body of the request as character data using - * a BufferedReader. The reader translates the character - * data according to the character encoding used on the body. - * Either this method or {@link #getInputStream} may be called to read the - * body, not both. - * - * - * @return a BufferedReader - * containing the body of the request - * - * @exception UnsupportedEncodingException if the character set encoding - * used is not supported and the - * text cannot be decoded - * - * @exception IllegalStateException if {@link #getInputStream} method - * has been called on this request - * - * @exception IOException if an input or output exception occurred - * - * @see #getInputStream - * - */ - - public BufferedReader getReader() throws IOException; - - - - - /** - * Returns the Internet Protocol (IP) address of the client - * or last proxy that sent the request. - * For HTTP servlets, same as the value of the - * CGI variable REMOTE_ADDR. - * - * @return a String containing the - * IP address of the client that sent the request - * - */ - - public String getRemoteAddr(); - - - - - /** - * Returns the fully qualified name of the client - * or the last proxy that sent the request. - * If the engine cannot or chooses not to resolve the hostname - * (to improve performance), this method returns the dotted-string form of - * the IP address. For HTTP servlets, same as the value of the CGI variable - * REMOTE_HOST. - * - * @return a String containing the fully - * qualified name of the client - * - */ - - public String getRemoteHost(); - - - - - /** - * - * Stores an attribute in this request. - * Attributes are reset between requests. This method is most - * often used in conjunction with {@link RequestDispatcher}. - * - *

Attribute names should follow the same conventions as - * package names. Names beginning with java.*, - * javax.*, and com.sun.*, are - * reserved for use by Sun Microsystems. - *
If the object passed in is null, the effect is the same as - * calling {@link #removeAttribute}. - *
It is warned that when the request is dispatched from the - * servlet resides in a different web application by - * RequestDispatcher, the object set by this method - * may not be correctly retrieved in the caller servlet. - * - * - * @param name a String specifying - * the name of the attribute - * - * @param o the Object to be stored - * - */ - - public void setAttribute(String name, Object o); - - - - - /** - * - * Removes an attribute from this request. This method is not - * generally needed as attributes only persist as long as the request - * is being handled. - * - *

Attribute names should follow the same conventions as - * package names. Names beginning with java.*, - * javax.*, and com.sun.*, are - * reserved for use by Sun Microsystems. - * - * - * @param name a String specifying - * the name of the attribute to remove - * - */ - - public void removeAttribute(String name); - - - - - /** - * - * Returns the preferred Locale that the client will - * accept content in, based on the Accept-Language header. - * If the client request doesn't provide an Accept-Language header, - * this method returns the default locale for the server. - * - * - * @return the preferred Locale for the client - * - */ - - public Locale getLocale(); - - - - - /** - * - * Returns an Enumeration of Locale objects - * indicating, in decreasing order starting with the preferred locale, the - * locales that are acceptable to the client based on the Accept-Language - * header. - * If the client request doesn't provide an Accept-Language header, - * this method returns an Enumeration containing one - * Locale, the default locale for the server. - * - * - * @return an Enumeration of preferred - * Locale objects for the client - * - */ - - public Enumeration getLocales(); - - - - - /** - * - * Returns a boolean indicating whether this request was made using a - * secure channel, such as HTTPS. - * - * - * @return a boolean indicating if the request was made using a - * secure channel - * - */ - - public boolean isSecure(); - - - - - /** - * - * Returns a {@link RequestDispatcher} object that acts as a wrapper for - * the resource located at the given path. - * A RequestDispatcher object can be used to forward - * a request to the resource or to include the resource in a response. - * The resource can be dynamic or static. - * - *

The pathname specified may be relative, although it cannot extend - * outside the current servlet context. If the path begins with - * a "/" it is interpreted as relative to the current context root. - * This method returns null if the servlet container - * cannot return a RequestDispatcher. - * - *

The difference between this method and {@link - * ServletContext#getRequestDispatcher} is that this method can take a - * relative path. - * - * @param path a String specifying the pathname - * to the resource. If it is relative, it must be - * relative against the current servlet. - * - * @return a RequestDispatcher object - * that acts as a wrapper for the resource - * at the specified path, or null - * if the servlet container cannot return a - * RequestDispatcher - * - * @see RequestDispatcher - * @see ServletContext#getRequestDispatcher - * - */ - - public RequestDispatcher getRequestDispatcher(String path); - - - - - /** - * - * @deprecated As of Version 2.1 of the Java Servlet API, - * use {@link ServletContext#getRealPath} instead. - * - */ - - public String getRealPath(String path); - - - /** - * Returns the Internet Protocol (IP) source port of the client - * or last proxy that sent the request. - * - * @return an integer specifying the port number - * - * @since 2.4 - */ - public int getRemotePort(); - - - /** - * Returns the host name of the Internet Protocol (IP) interface on - * which the request was received. - * - * @return a String containing the host - * name of the IP on which the request was received. - * - * @since 2.4 - */ - public String getLocalName(); - - /** - * Returns the Internet Protocol (IP) address of the interface on - * which the request was received. - * - * @return a String containing the - * IP address on which the request was received. - * - * @since 2.4 - * - */ - public String getLocalAddr(); - - - /** - * Returns the Internet Protocol (IP) port number of the interface - * on which the request was received. - * - * @return an integer specifying the port number - * - * @since 2.4 - */ - public int getLocalPort(); - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + + + +/** + * Defines an object to provide client request information to a servlet. The + * servlet container creates a ServletRequest object and passes + * it as an argument to the servlet's service method. + * + *

A ServletRequest object provides data including + * parameter name and values, attributes, and an input stream. + * Interfaces that extend ServletRequest can provide + * additional protocol-specific data (for example, HTTP data is + * provided by {@link javax.servlet.http.HttpServletRequest}. + * + * @author Various + * @version $Version$ + * + * @see javax.servlet.http.HttpServletRequest + * + */ + +public interface ServletRequest { + + + + + /** + * + * Returns the value of the named attribute as an Object, + * or null if no attribute of the given name exists. + * + *

Attributes can be set two ways. The servlet container may set + * attributes to make available custom information about a request. + * For example, for requests made using HTTPS, the attribute + * javax.servlet.request.X509Certificate can be used to + * retrieve information on the certificate of the client. Attributes + * can also be set programatically using + * {@link ServletRequest#setAttribute}. This allows information to be + * embedded into a request before a {@link RequestDispatcher} call. + * + *

Attribute names should follow the same conventions as package + * names. This specification reserves names matching java.*, + * javax.*, and sun.*. + * + * @param name a String specifying the name of + * the attribute + * + * @return an Object containing the value + * of the attribute, or null if + * the attribute does not exist + * + */ + + public Object getAttribute(String name); + + + + /** + * Returns an Enumeration containing the + * names of the attributes available to this request. + * This method returns an empty Enumeration + * if the request has no attributes available to it. + * + * + * @return an Enumeration of strings + * containing the names + * of the request's attributes + * + */ + + public Enumeration getAttributeNames(); + + + + + /** + * Returns the name of the character encoding used in the body of this + * request. This method returns null if the request + * does not specify a character encoding + * + * + * @return a String containing the name of + * the character encoding, or null + * if the request does not specify a character encoding + * + */ + + public String getCharacterEncoding(); + + /** + * Overrides the name of the character encoding used in the body of this + * request. This method must be called prior to reading request parameters + * or reading input using getReader(). + * + * + * @param env a String containing the name of + * the character encoding. + * @throws java.io.UnsupportedEncodingException if this is not a valid encoding + */ + + public void setCharacterEncoding(String env) throws java.io.UnsupportedEncodingException; + + + + + + /** + * Returns the length, in bytes, of the request body + * and made available by the input stream, or -1 if the + * length is not known. For HTTP servlets, same as the value + * of the CGI variable CONTENT_LENGTH. + * + * @return an integer containing the length of the + * request body or -1 if the length is not known + * + */ + + public int getContentLength(); + + + + + /** + * Returns the MIME type of the body of the request, or + * null if the type is not known. For HTTP servlets, + * same as the value of the CGI variable CONTENT_TYPE. + * + * @return a String containing the name + * of the MIME type of + * the request, or null if the type is not known + * + */ + + public String getContentType(); + + + + + /** + * Retrieves the body of the request as binary data using + * a {@link ServletInputStream}. Either this method or + * {@link #getReader} may be called to read the body, not both. + * + * @return a {@link ServletInputStream} object containing + * the body of the request + * + * @exception IllegalStateException if the {@link #getReader} method + * has already been called for this request + * + * @exception IOException if an input or output exception occurred + * + */ + + public ServletInputStream getInputStream() throws IOException; + + + + + /** + * Returns the value of a request parameter as a String, + * or null if the parameter does not exist. Request parameters + * are extra information sent with the request. For HTTP servlets, + * parameters are contained in the query string or posted form data. + * + *

You should only use this method when you are sure the + * parameter has only one value. If the parameter might have + * more than one value, use {@link #getParameterValues}. + * + *

If you use this method with a multivalued + * parameter, the value returned is equal to the first value + * in the array returned by getParameterValues. + * + *

If the parameter data was sent in the request body, such as occurs + * with an HTTP POST request, then reading the body directly via {@link + * #getInputStream} or {@link #getReader} can interfere + * with the execution of this method. + * + * @param name a String specifying the + * name of the parameter + * + * @return a String representing the + * single value of the parameter + * + * @see #getParameterValues + * + */ + + public String getParameter(String name); + + + + + /** + * + * Returns an Enumeration of String + * objects containing the names of the parameters contained + * in this request. If the request has + * no parameters, the method returns an + * empty Enumeration. + * + * @return an Enumeration of String + * objects, each String containing + * the name of a request parameter; or an + * empty Enumeration if the + * request has no parameters + * + */ + + public Enumeration getParameterNames(); + + + + + /** + * Returns an array of String objects containing + * all of the values the given request parameter has, or + * null if the parameter does not exist. + * + *

If the parameter has a single value, the array has a length + * of 1. + * + * @param name a String containing the name of + * the parameter whose value is requested + * + * @return an array of String objects + * containing the parameter's values + * + * @see #getParameter + * + */ + + public String[] getParameterValues(String name); + + /** Returns a java.util.Map of the parameters of this request. + * Request parameters + * are extra information sent with the request. For HTTP servlets, + * parameters are contained in the query string or posted form data. + * + * @return an immutable java.util.Map containing parameter names as + * keys and parameter values as map values. The keys in the parameter + * map are of type String. The values in the parameter map are of type + * String array. + * + */ + + public Map getParameterMap(); + + + + /** + * Returns the name and version of the protocol the request uses + * in the form protocol/majorVersion.minorVersion, for + * example, HTTP/1.1. For HTTP servlets, the value + * returned is the same as the value of the CGI variable + * SERVER_PROTOCOL. + * + * @return a String containing the protocol + * name and version number + * + */ + + public String getProtocol(); + + + + + /** + * Returns the name of the scheme used to make this request, + * for example, + * http, https, or ftp. + * Different schemes have different rules for constructing URLs, + * as noted in RFC 1738. + * + * @return a String containing the name + * of the scheme used to make this request + * + */ + + public String getScheme(); + + + + + /** + * Returns the host name of the server to which the request was sent. + * It is the value of the part before ":" in the Host + * header value, if any, or the resolved server name, or the server IP address. + * + * @return a String containing the name + * of the server + */ + + public String getServerName(); + + + + + /** + * Returns the port number to which the request was sent. + * It is the value of the part after ":" in the Host + * header value, if any, or the server port where the client connection + * was accepted on. + * + * @return an integer specifying the port number + * + */ + + public int getServerPort(); + + + + /** + * Retrieves the body of the request as character data using + * a BufferedReader. The reader translates the character + * data according to the character encoding used on the body. + * Either this method or {@link #getInputStream} may be called to read the + * body, not both. + * + * + * @return a BufferedReader + * containing the body of the request + * + * @exception UnsupportedEncodingException if the character set encoding + * used is not supported and the + * text cannot be decoded + * + * @exception IllegalStateException if {@link #getInputStream} method + * has been called on this request + * + * @exception IOException if an input or output exception occurred + * + * @see #getInputStream + * + */ + + public BufferedReader getReader() throws IOException; + + + + + /** + * Returns the Internet Protocol (IP) address of the client + * or last proxy that sent the request. + * For HTTP servlets, same as the value of the + * CGI variable REMOTE_ADDR. + * + * @return a String containing the + * IP address of the client that sent the request + * + */ + + public String getRemoteAddr(); + + + + + /** + * Returns the fully qualified name of the client + * or the last proxy that sent the request. + * If the engine cannot or chooses not to resolve the hostname + * (to improve performance), this method returns the dotted-string form of + * the IP address. For HTTP servlets, same as the value of the CGI variable + * REMOTE_HOST. + * + * @return a String containing the fully + * qualified name of the client + * + */ + + public String getRemoteHost(); + + + + + /** + * + * Stores an attribute in this request. + * Attributes are reset between requests. This method is most + * often used in conjunction with {@link RequestDispatcher}. + * + *

Attribute names should follow the same conventions as + * package names. Names beginning with java.*, + * javax.*, and com.sun.*, are + * reserved for use by Sun Microsystems. + *
If the object passed in is null, the effect is the same as + * calling {@link #removeAttribute}. + *
It is warned that when the request is dispatched from the + * servlet resides in a different web application by + * RequestDispatcher, the object set by this method + * may not be correctly retrieved in the caller servlet. + * + * + * @param name a String specifying + * the name of the attribute + * + * @param o the Object to be stored + * + */ + + public void setAttribute(String name, Object o); + + + + + /** + * + * Removes an attribute from this request. This method is not + * generally needed as attributes only persist as long as the request + * is being handled. + * + *

Attribute names should follow the same conventions as + * package names. Names beginning with java.*, + * javax.*, and com.sun.*, are + * reserved for use by Sun Microsystems. + * + * + * @param name a String specifying + * the name of the attribute to remove + * + */ + + public void removeAttribute(String name); + + + + + /** + * + * Returns the preferred Locale that the client will + * accept content in, based on the Accept-Language header. + * If the client request doesn't provide an Accept-Language header, + * this method returns the default locale for the server. + * + * + * @return the preferred Locale for the client + * + */ + + public Locale getLocale(); + + + + + /** + * + * Returns an Enumeration of Locale objects + * indicating, in decreasing order starting with the preferred locale, the + * locales that are acceptable to the client based on the Accept-Language + * header. + * If the client request doesn't provide an Accept-Language header, + * this method returns an Enumeration containing one + * Locale, the default locale for the server. + * + * + * @return an Enumeration of preferred + * Locale objects for the client + * + */ + + public Enumeration getLocales(); + + + + + /** + * + * Returns a boolean indicating whether this request was made using a + * secure channel, such as HTTPS. + * + * + * @return a boolean indicating if the request was made using a + * secure channel + * + */ + + public boolean isSecure(); + + + + + /** + * + * Returns a {@link RequestDispatcher} object that acts as a wrapper for + * the resource located at the given path. + * A RequestDispatcher object can be used to forward + * a request to the resource or to include the resource in a response. + * The resource can be dynamic or static. + * + *

The pathname specified may be relative, although it cannot extend + * outside the current servlet context. If the path begins with + * a "/" it is interpreted as relative to the current context root. + * This method returns null if the servlet container + * cannot return a RequestDispatcher. + * + *

The difference between this method and {@link + * ServletContext#getRequestDispatcher} is that this method can take a + * relative path. + * + * @param path a String specifying the pathname + * to the resource. If it is relative, it must be + * relative against the current servlet. + * + * @return a RequestDispatcher object + * that acts as a wrapper for the resource + * at the specified path, or null + * if the servlet container cannot return a + * RequestDispatcher + * + * @see RequestDispatcher + * @see ServletContext#getRequestDispatcher + * + */ + + public RequestDispatcher getRequestDispatcher(String path); + + + + + /** + * + * @deprecated As of Version 2.1 of the Java Servlet API, + * use {@link ServletContext#getRealPath} instead. + * + */ + + public String getRealPath(String path); + + + /** + * Returns the Internet Protocol (IP) source port of the client + * or last proxy that sent the request. + * + * @return an integer specifying the port number + * + * @since 2.4 + */ + public int getRemotePort(); + + + /** + * Returns the host name of the Internet Protocol (IP) interface on + * which the request was received. + * + * @return a String containing the host + * name of the IP on which the request was received. + * + * @since 2.4 + */ + public String getLocalName(); + + /** + * Returns the Internet Protocol (IP) address of the interface on + * which the request was received. + * + * @return a String containing the + * IP address on which the request was received. + * + * @since 2.4 + * + */ + public String getLocalAddr(); + + + /** + * Returns the Internet Protocol (IP) port number of the interface + * on which the request was received. + * + * @return an integer specifying the port number + * + * @since 2.4 + */ + public int getLocalPort(); + +} + diff --git a/java/javax/servlet/ServletRequestAttributeEvent.java b/java/javax/servlet/ServletRequestAttributeEvent.java index b0dfbe58f..8ca9eb457 100644 --- a/java/javax/servlet/ServletRequestAttributeEvent.java +++ b/java/javax/servlet/ServletRequestAttributeEvent.java @@ -1,66 +1,66 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - - - /** - * This is the event class for notifications of changes to the - * attributes of the servlet request in an application. - * @see ServletRequestAttributeListener - * @since Servlet 2.4 - */ - -public class ServletRequestAttributeEvent extends ServletRequestEvent { - private String name; - private Object value; - - /** Construct a ServletRequestAttributeEvent giving the servlet context - * of this web application, the ServletRequest whose attributes are - * changing and the name and value of the attribute. - * - * @param sc the ServletContext that is sending the event. - * @param request the ServletRequest that is sending the event. - * @param name the name of the request attribute. - * @param value the value of the request attribute. - */ - public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) { - super(sc, request); - this.name = name; - this.value = value; - } - - /** - * Return the name of the attribute that changed on the ServletRequest. - * - * @return the name of the changed request attribute - */ - public String getName() { - return this.name; - } - - /** - * Returns the value of the attribute that has been added, removed or - * replaced. If the attribute was added, this is the value of the - * attribute. If the attribute was removed, this is the value of the - * removed attribute. If the attribute was replaced, this is the old - * value of the attribute. - * - * @return the value of the changed request attribute - */ - public Object getValue() { - return this.value; - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + + + /** + * This is the event class for notifications of changes to the + * attributes of the servlet request in an application. + * @see ServletRequestAttributeListener + * @since Servlet 2.4 + */ + +public class ServletRequestAttributeEvent extends ServletRequestEvent { + private String name; + private Object value; + + /** Construct a ServletRequestAttributeEvent giving the servlet context + * of this web application, the ServletRequest whose attributes are + * changing and the name and value of the attribute. + * + * @param sc the ServletContext that is sending the event. + * @param request the ServletRequest that is sending the event. + * @param name the name of the request attribute. + * @param value the value of the request attribute. + */ + public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) { + super(sc, request); + this.name = name; + this.value = value; + } + + /** + * Return the name of the attribute that changed on the ServletRequest. + * + * @return the name of the changed request attribute + */ + public String getName() { + return this.name; + } + + /** + * Returns the value of the attribute that has been added, removed or + * replaced. If the attribute was added, this is the value of the + * attribute. If the attribute was removed, this is the value of the + * removed attribute. If the attribute was replaced, this is the old + * value of the attribute. + * + * @return the value of the changed request attribute + */ + public Object getValue() { + return this.value; + } +} diff --git a/java/javax/servlet/ServletRequestAttributeListener.java b/java/javax/servlet/ServletRequestAttributeListener.java index f7735a1f6..b68bbc5cf 100644 --- a/java/javax/servlet/ServletRequestAttributeListener.java +++ b/java/javax/servlet/ServletRequestAttributeListener.java @@ -1,49 +1,49 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.util.EventListener; - - /** - * A ServletRequestAttributeListener can be implemented by the - * developer interested in being notified of request attribute - * changes. Notifications will be generated while the request - * is within the scope of the web application in which the listener - * is registered. A request is defined as coming into scope when - * it is about to enter the first servlet or filter in each web - * application, as going out of scope when it exits the last servlet - * or the first filter in the chain. - * - * @since Servlet 2.4 - */ - -public interface ServletRequestAttributeListener extends EventListener { - /** Notification that a new attribute was added to the - ** servlet request. Called after the attribute is added. - */ - public void attributeAdded(ServletRequestAttributeEvent srae); - - /** Notification that an existing attribute has been removed from the - ** servlet request. Called after the attribute is removed. - */ - public void attributeRemoved(ServletRequestAttributeEvent srae); - - /** Notification that an attribute was replaced on the - ** servlet request. Called after the attribute is replaced. - */ - public void attributeReplaced(ServletRequestAttributeEvent srae); -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.util.EventListener; + + /** + * A ServletRequestAttributeListener can be implemented by the + * developer interested in being notified of request attribute + * changes. Notifications will be generated while the request + * is within the scope of the web application in which the listener + * is registered. A request is defined as coming into scope when + * it is about to enter the first servlet or filter in each web + * application, as going out of scope when it exits the last servlet + * or the first filter in the chain. + * + * @since Servlet 2.4 + */ + +public interface ServletRequestAttributeListener extends EventListener { + /** Notification that a new attribute was added to the + ** servlet request. Called after the attribute is added. + */ + public void attributeAdded(ServletRequestAttributeEvent srae); + + /** Notification that an existing attribute has been removed from the + ** servlet request. Called after the attribute is removed. + */ + public void attributeRemoved(ServletRequestAttributeEvent srae); + + /** Notification that an attribute was replaced on the + ** servlet request. Called after the attribute is replaced. + */ + public void attributeReplaced(ServletRequestAttributeEvent srae); +} + diff --git a/java/javax/servlet/ServletRequestEvent.java b/java/javax/servlet/ServletRequestEvent.java index 03da745e0..a75b21362 100644 --- a/java/javax/servlet/ServletRequestEvent.java +++ b/java/javax/servlet/ServletRequestEvent.java @@ -1,55 +1,55 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - - - /** - * Events of this kind indicate lifecycle - * events for a ServletRequest. - * The source of the event - * is the ServletContext of this web application. - * @see ServletRequestListener - * @since Servlet 2.4 - */ - -public class ServletRequestEvent extends java.util.EventObject { - private ServletRequest request; - - /** Construct a ServletRequestEvent for the given ServletContext - * and ServletRequest. - * - * @param sc the ServletContext of the web application. - * @param request the ServletRequest that is sending the event. - */ - public ServletRequestEvent(ServletContext sc, ServletRequest request) { - super(sc); - this.request = request; - } - - /** - * Returns the ServletRequest that is changing. - */ - public ServletRequest getServletRequest () { - return this.request; - } - - /** - * Returns the ServletContext of this web application. - */ - public ServletContext getServletContext () { - return (ServletContext) super.getSource(); - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + + + /** + * Events of this kind indicate lifecycle + * events for a ServletRequest. + * The source of the event + * is the ServletContext of this web application. + * @see ServletRequestListener + * @since Servlet 2.4 + */ + +public class ServletRequestEvent extends java.util.EventObject { + private ServletRequest request; + + /** Construct a ServletRequestEvent for the given ServletContext + * and ServletRequest. + * + * @param sc the ServletContext of the web application. + * @param request the ServletRequest that is sending the event. + */ + public ServletRequestEvent(ServletContext sc, ServletRequest request) { + super(sc); + this.request = request; + } + + /** + * Returns the ServletRequest that is changing. + */ + public ServletRequest getServletRequest () { + return this.request; + } + + /** + * Returns the ServletContext of this web application. + */ + public ServletContext getServletContext () { + return (ServletContext) super.getSource(); + } +} diff --git a/java/javax/servlet/ServletRequestListener.java b/java/javax/servlet/ServletRequestListener.java index 542e82a23..3518b19ba 100644 --- a/java/javax/servlet/ServletRequestListener.java +++ b/java/javax/servlet/ServletRequestListener.java @@ -1,39 +1,39 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.util.EventListener; - - /** - * A ServletRequestListener can be implemented by the developer - * interested in being notified of requests coming in and out of - * scope in a web component. A request is defined as coming into - * scope when it is about to enter the first servlet or filter - * in each web application, as going out of scope when it exits - * the last servlet or the first filter in the chain. - * - * @since Servlet 2.4 - */ - - -public interface ServletRequestListener extends EventListener { - - /** The request is about to go out of scope of the web application. */ - public void requestDestroyed ( ServletRequestEvent sre ); - - /** The request is about to come into scope of the web application. */ - public void requestInitialized ( ServletRequestEvent sre ); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.util.EventListener; + + /** + * A ServletRequestListener can be implemented by the developer + * interested in being notified of requests coming in and out of + * scope in a web component. A request is defined as coming into + * scope when it is about to enter the first servlet or filter + * in each web application, as going out of scope when it exits + * the last servlet or the first filter in the chain. + * + * @since Servlet 2.4 + */ + + +public interface ServletRequestListener extends EventListener { + + /** The request is about to go out of scope of the web application. */ + public void requestDestroyed ( ServletRequestEvent sre ); + + /** The request is about to come into scope of the web application. */ + public void requestInitialized ( ServletRequestEvent sre ); +} diff --git a/java/javax/servlet/ServletRequestWrapper.java b/java/javax/servlet/ServletRequestWrapper.java index a5fced6c9..d5f232e9b 100644 --- a/java/javax/servlet/ServletRequestWrapper.java +++ b/java/javax/servlet/ServletRequestWrapper.java @@ -1,400 +1,400 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.BufferedReader; -import java.io.IOException; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; - - - -/** - * - * Provides a convenient implementation of the ServletRequest interface that - * can be subclassed by developers wishing to adapt the request to a Servlet. - * This class implements the Wrapper or Decorator pattern. Methods default to - * calling through to the wrapped request object. - * @since v 2.3 - * - * - * - * @see javax.servlet.ServletRequest - * - */ - -public class ServletRequestWrapper implements ServletRequest { - private ServletRequest request; - - /** - * Creates a ServletRequest adaptor wrapping the given request object. - * @throws java.lang.IllegalArgumentException if the request is null - */ - - public ServletRequestWrapper(ServletRequest request) { - if (request == null) { - throw new IllegalArgumentException("Request cannot be null"); - } - this.request = request; - } - - /** - * Return the wrapped request object. - */ - public ServletRequest getRequest() { - return this.request; - } - - /** - * Sets the request object being wrapped. - * @throws java.lang.IllegalArgumentException if the request is null. - */ - - public void setRequest(ServletRequest request) { - if (request == null) { - throw new IllegalArgumentException("Request cannot be null"); - } - this.request = request; - } - - /** - * - * The default behavior of this method is to call getAttribute(String name) - * on the wrapped request object. - */ - - public Object getAttribute(String name) { - return this.request.getAttribute(name); - } - - - - /** - * The default behavior of this method is to return getAttributeNames() - * on the wrapped request object. - */ - - public Enumeration getAttributeNames() { - return this.request.getAttributeNames(); - } - - - - /** - * The default behavior of this method is to return getCharacterEncoding() - * on the wrapped request object. - */ - - public String getCharacterEncoding() { - return this.request.getCharacterEncoding(); - } - - /** - * The default behavior of this method is to set the character encoding - * on the wrapped request object. - */ - - public void setCharacterEncoding(String enc) throws java.io.UnsupportedEncodingException { - this.request.setCharacterEncoding(enc); - } - - - /** - * The default behavior of this method is to return getContentLength() - * on the wrapped request object. - */ - - public int getContentLength() { - return this.request.getContentLength(); - } - - - - - /** - * The default behavior of this method is to return getContentType() - * on the wrapped request object. - */ - public String getContentType() { - return this.request.getContentType(); - } - - - - - /** - * The default behavior of this method is to return getInputStream() - * on the wrapped request object. - */ - - public ServletInputStream getInputStream() throws IOException { - return this.request.getInputStream(); - } - - - - - /** - * The default behavior of this method is to return getParameter(String name) - * on the wrapped request object. - */ - - public String getParameter(String name) { - return this.request.getParameter(name); - } - - /** - * The default behavior of this method is to return getParameterMap() - * on the wrapped request object. - */ - public Map getParameterMap() { - return this.request.getParameterMap(); - } - - - - - /** - * The default behavior of this method is to return getParameterNames() - * on the wrapped request object. - */ - - public Enumeration getParameterNames() { - return this.request.getParameterNames(); - } - - - - - /** - * The default behavior of this method is to return getParameterValues(String name) - * on the wrapped request object. - */ - public String[] getParameterValues(String name) { - return this.request.getParameterValues(name); - } - - - - - /** - * The default behavior of this method is to return getProtocol() - * on the wrapped request object. - */ - - public String getProtocol() { - return this.request.getProtocol(); - } - - - - - /** - * The default behavior of this method is to return getScheme() - * on the wrapped request object. - */ - - - public String getScheme() { - return this.request.getScheme(); - } - - - - - /** - * The default behavior of this method is to return getServerName() - * on the wrapped request object. - */ - public String getServerName() { - return this.request.getServerName(); - } - - - - - /** - * The default behavior of this method is to return getServerPort() - * on the wrapped request object. - */ - - public int getServerPort() { - return this.request.getServerPort(); - } - - - - /** - * The default behavior of this method is to return getReader() - * on the wrapped request object. - */ - - public BufferedReader getReader() throws IOException { - return this.request.getReader(); - } - - - - - /** - * The default behavior of this method is to return getRemoteAddr() - * on the wrapped request object. - */ - - public String getRemoteAddr() { - return this.request.getRemoteAddr(); - } - - - - - /** - * The default behavior of this method is to return getRemoteHost() - * on the wrapped request object. - */ - - public String getRemoteHost() { - return this.request.getRemoteHost(); - } - - - - - /** - * The default behavior of this method is to return setAttribute(String name, Object o) - * on the wrapped request object. - */ - - public void setAttribute(String name, Object o) { - this.request.setAttribute(name, o); - } - - - - - /** - * The default behavior of this method is to call removeAttribute(String name) - * on the wrapped request object. - */ - public void removeAttribute(String name) { - this.request.removeAttribute(name); - } - - - - - /** - * The default behavior of this method is to return getLocale() - * on the wrapped request object. - */ - - public Locale getLocale() { - return this.request.getLocale(); - } - - - - - /** - * The default behavior of this method is to return getLocales() - * on the wrapped request object. - */ - - public Enumeration getLocales() { - return this.request.getLocales(); - } - - - - - /** - * The default behavior of this method is to return isSecure() - * on the wrapped request object. - */ - - public boolean isSecure() { - return this.request.isSecure(); - } - - - - - /** - * The default behavior of this method is to return getRequestDispatcher(String path) - * on the wrapped request object. - */ - - public RequestDispatcher getRequestDispatcher(String path) { - return this.request.getRequestDispatcher(path); - } - - - - - /** - * The default behavior of this method is to return getRealPath(String path) - * on the wrapped request object. - */ - - public String getRealPath(String path) { - return this.request.getRealPath(path); - } - - /** - * The default behavior of this method is to return - * getRemotePort() on the wrapped request object. - * - * @since 2.4 - */ - public int getRemotePort(){ - return this.request.getRemotePort(); - } - - - /** - * The default behavior of this method is to return - * getLocalName() on the wrapped request object. - * - * @since 2.4 - */ - public String getLocalName(){ - return this.request.getLocalName(); - } - - /** - * The default behavior of this method is to return - * getLocalAddr() on the wrapped request object. - * - * @since 2.4 - */ - public String getLocalAddr(){ - return this.request.getLocalAddr(); - } - - - /** - * The default behavior of this method is to return - * getLocalPort() on the wrapped request object. - * - * @since 2.4 - */ - public int getLocalPort(){ - return this.request.getLocalPort(); - } - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + + + +/** + * + * Provides a convenient implementation of the ServletRequest interface that + * can be subclassed by developers wishing to adapt the request to a Servlet. + * This class implements the Wrapper or Decorator pattern. Methods default to + * calling through to the wrapped request object. + * @since v 2.3 + * + * + * + * @see javax.servlet.ServletRequest + * + */ + +public class ServletRequestWrapper implements ServletRequest { + private ServletRequest request; + + /** + * Creates a ServletRequest adaptor wrapping the given request object. + * @throws java.lang.IllegalArgumentException if the request is null + */ + + public ServletRequestWrapper(ServletRequest request) { + if (request == null) { + throw new IllegalArgumentException("Request cannot be null"); + } + this.request = request; + } + + /** + * Return the wrapped request object. + */ + public ServletRequest getRequest() { + return this.request; + } + + /** + * Sets the request object being wrapped. + * @throws java.lang.IllegalArgumentException if the request is null. + */ + + public void setRequest(ServletRequest request) { + if (request == null) { + throw new IllegalArgumentException("Request cannot be null"); + } + this.request = request; + } + + /** + * + * The default behavior of this method is to call getAttribute(String name) + * on the wrapped request object. + */ + + public Object getAttribute(String name) { + return this.request.getAttribute(name); + } + + + + /** + * The default behavior of this method is to return getAttributeNames() + * on the wrapped request object. + */ + + public Enumeration getAttributeNames() { + return this.request.getAttributeNames(); + } + + + + /** + * The default behavior of this method is to return getCharacterEncoding() + * on the wrapped request object. + */ + + public String getCharacterEncoding() { + return this.request.getCharacterEncoding(); + } + + /** + * The default behavior of this method is to set the character encoding + * on the wrapped request object. + */ + + public void setCharacterEncoding(String enc) throws java.io.UnsupportedEncodingException { + this.request.setCharacterEncoding(enc); + } + + + /** + * The default behavior of this method is to return getContentLength() + * on the wrapped request object. + */ + + public int getContentLength() { + return this.request.getContentLength(); + } + + + + + /** + * The default behavior of this method is to return getContentType() + * on the wrapped request object. + */ + public String getContentType() { + return this.request.getContentType(); + } + + + + + /** + * The default behavior of this method is to return getInputStream() + * on the wrapped request object. + */ + + public ServletInputStream getInputStream() throws IOException { + return this.request.getInputStream(); + } + + + + + /** + * The default behavior of this method is to return getParameter(String name) + * on the wrapped request object. + */ + + public String getParameter(String name) { + return this.request.getParameter(name); + } + + /** + * The default behavior of this method is to return getParameterMap() + * on the wrapped request object. + */ + public Map getParameterMap() { + return this.request.getParameterMap(); + } + + + + + /** + * The default behavior of this method is to return getParameterNames() + * on the wrapped request object. + */ + + public Enumeration getParameterNames() { + return this.request.getParameterNames(); + } + + + + + /** + * The default behavior of this method is to return getParameterValues(String name) + * on the wrapped request object. + */ + public String[] getParameterValues(String name) { + return this.request.getParameterValues(name); + } + + + + + /** + * The default behavior of this method is to return getProtocol() + * on the wrapped request object. + */ + + public String getProtocol() { + return this.request.getProtocol(); + } + + + + + /** + * The default behavior of this method is to return getScheme() + * on the wrapped request object. + */ + + + public String getScheme() { + return this.request.getScheme(); + } + + + + + /** + * The default behavior of this method is to return getServerName() + * on the wrapped request object. + */ + public String getServerName() { + return this.request.getServerName(); + } + + + + + /** + * The default behavior of this method is to return getServerPort() + * on the wrapped request object. + */ + + public int getServerPort() { + return this.request.getServerPort(); + } + + + + /** + * The default behavior of this method is to return getReader() + * on the wrapped request object. + */ + + public BufferedReader getReader() throws IOException { + return this.request.getReader(); + } + + + + + /** + * The default behavior of this method is to return getRemoteAddr() + * on the wrapped request object. + */ + + public String getRemoteAddr() { + return this.request.getRemoteAddr(); + } + + + + + /** + * The default behavior of this method is to return getRemoteHost() + * on the wrapped request object. + */ + + public String getRemoteHost() { + return this.request.getRemoteHost(); + } + + + + + /** + * The default behavior of this method is to return setAttribute(String name, Object o) + * on the wrapped request object. + */ + + public void setAttribute(String name, Object o) { + this.request.setAttribute(name, o); + } + + + + + /** + * The default behavior of this method is to call removeAttribute(String name) + * on the wrapped request object. + */ + public void removeAttribute(String name) { + this.request.removeAttribute(name); + } + + + + + /** + * The default behavior of this method is to return getLocale() + * on the wrapped request object. + */ + + public Locale getLocale() { + return this.request.getLocale(); + } + + + + + /** + * The default behavior of this method is to return getLocales() + * on the wrapped request object. + */ + + public Enumeration getLocales() { + return this.request.getLocales(); + } + + + + + /** + * The default behavior of this method is to return isSecure() + * on the wrapped request object. + */ + + public boolean isSecure() { + return this.request.isSecure(); + } + + + + + /** + * The default behavior of this method is to return getRequestDispatcher(String path) + * on the wrapped request object. + */ + + public RequestDispatcher getRequestDispatcher(String path) { + return this.request.getRequestDispatcher(path); + } + + + + + /** + * The default behavior of this method is to return getRealPath(String path) + * on the wrapped request object. + */ + + public String getRealPath(String path) { + return this.request.getRealPath(path); + } + + /** + * The default behavior of this method is to return + * getRemotePort() on the wrapped request object. + * + * @since 2.4 + */ + public int getRemotePort(){ + return this.request.getRemotePort(); + } + + + /** + * The default behavior of this method is to return + * getLocalName() on the wrapped request object. + * + * @since 2.4 + */ + public String getLocalName(){ + return this.request.getLocalName(); + } + + /** + * The default behavior of this method is to return + * getLocalAddr() on the wrapped request object. + * + * @since 2.4 + */ + public String getLocalAddr(){ + return this.request.getLocalAddr(); + } + + + /** + * The default behavior of this method is to return + * getLocalPort() on the wrapped request object. + * + * @since 2.4 + */ + public int getLocalPort(){ + return this.request.getLocalPort(); + } + +} + diff --git a/java/javax/servlet/ServletResponse.java b/java/javax/servlet/ServletResponse.java index c807f741c..770d9a090 100644 --- a/java/javax/servlet/ServletResponse.java +++ b/java/javax/servlet/ServletResponse.java @@ -1,452 +1,452 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Locale; - - -/** - * Defines an object to assist a servlet in sending a response to the client. - * The servlet container creates a ServletResponse object and - * passes it as an argument to the servlet's service method. - * - *

To send binary data in a MIME body response, use - * the {@link ServletOutputStream} returned by {@link #getOutputStream}. - * To send character data, use the PrintWriter object - * returned by {@link #getWriter}. To mix binary and text data, - * for example, to create a multipart response, use a - * ServletOutputStream and manage the character sections - * manually. - * - *

The charset for the MIME body response can be specified - * explicitly using the {@link #setCharacterEncoding} and - * {@link #setContentType} methods, or implicitly - * using the {@link #setLocale} method. - * Explicit specifications take precedence over - * implicit specifications. If no charset is specified, ISO-8859-1 will be - * used. The setCharacterEncoding, - * setContentType, or setLocale method must - * be called before getWriter and before committing - * the response for the character encoding to be used. - * - *

See the Internet RFCs such as - * - * RFC 2045 for more information on MIME. Protocols such as SMTP - * and HTTP define profiles of MIME, and those standards - * are still evolving. - * - * @author Various - * @version $Version$ - * - * @see ServletOutputStream - * - */ - -public interface ServletResponse { - - - - /** - * Returns the name of the character encoding (MIME charset) - * used for the body sent in this response. - * The character encoding may have been specified explicitly - * using the {@link #setCharacterEncoding} or - * {@link #setContentType} methods, or implicitly using the - * {@link #setLocale} method. Explicit specifications take - * precedence over implicit specifications. Calls made - * to these methods after getWriter has been - * called or after the response has been committed have no - * effect on the character encoding. If no character encoding - * has been specified, ISO-8859-1 is returned. - *

See RFC 2047 (http://www.ietf.org/rfc/rfc2047.txt) - * for more information about character encoding and MIME. - * - * @return a String specifying the - * name of the character encoding, for - * example, UTF-8 - * - */ - - public String getCharacterEncoding(); - - - - /** - * Returns the content type used for the MIME body - * sent in this response. The content type proper must - * have been specified using {@link #setContentType} - * before the response is committed. If no content type - * has been specified, this method returns null. - * If a content type has been specified and a - * character encoding has been explicitly or implicitly - * specified as described in {@link #getCharacterEncoding}, - * the charset parameter is included in the string returned. - * If no character encoding has been specified, the - * charset parameter is omitted. - * - * @return a String specifying the - * content type, for example, - * text/html; charset=UTF-8, - * or null - * - * @since 2.4 - */ - - public String getContentType(); - - - - /** - * Returns a {@link ServletOutputStream} suitable for writing binary - * data in the response. The servlet container does not encode the - * binary data. - - *

Calling flush() on the ServletOutputStream commits the response. - - * Either this method or {@link #getWriter} may - * be called to write the body, not both. - * - * @return a {@link ServletOutputStream} for writing binary data - * - * @exception IllegalStateException if the getWriter method - * has been called on this response - * - * @exception IOException if an input or output exception occurred - * - * @see #getWriter - * - */ - - public ServletOutputStream getOutputStream() throws IOException; - - - - /** - * Returns a PrintWriter object that - * can send character text to the client. - * The PrintWriter uses the character - * encoding returned by {@link #getCharacterEncoding}. - * If the response's character encoding has not been - * specified as described in getCharacterEncoding - * (i.e., the method just returns the default value - * ISO-8859-1), getWriter - * updates it to ISO-8859-1. - *

Calling flush() on the PrintWriter - * commits the response. - *

Either this method or {@link #getOutputStream} may be called - * to write the body, not both. - * - * - * @return a PrintWriter object that - * can return character data to the client - * - * @exception UnsupportedEncodingException - * if the character encoding returned - * by getCharacterEncoding cannot be used - * - * @exception IllegalStateException - * if the getOutputStream - * method has already been called for this - * response object - * - * @exception IOException - * if an input or output exception occurred - * - * @see #getOutputStream - * @see #setCharacterEncoding - * - */ - - public PrintWriter getWriter() throws IOException; - - - - - /** - * Sets the character encoding (MIME charset) of the response - * being sent to the client, for example, to UTF-8. - * If the character encoding has already been set by - * {@link #setContentType} or {@link #setLocale}, - * this method overrides it. - * Calling {@link #setContentType} with the String - * of text/html and calling - * this method with the String of UTF-8 - * is equivalent with calling - * setContentType with the String of - * text/html; charset=UTF-8. - *

This method can be called repeatedly to change the character - * encoding. - * This method has no effect if it is called after - * getWriter has been - * called or after the response has been committed. - *

Containers must communicate the character encoding used for - * the servlet response's writer to the client if the protocol - * provides a way for doing so. In the case of HTTP, the character - * encoding is communicated as part of the Content-Type - * header for text media types. Note that the character encoding - * cannot be communicated via HTTP headers if the servlet does not - * specify a content type; however, it is still used to encode text - * written via the servlet response's writer. - * - * @param charset a String specifying only the character set - * defined by IANA Character Sets - * (http://www.iana.org/assignments/character-sets) - * - * @see #setContentType - * #setLocale - * - * @since 2.4 - * - */ - - public void setCharacterEncoding(String charset); - - - - - /** - * Sets the length of the content body in the response - * In HTTP servlets, this method sets the HTTP Content-Length header. - * - * - * @param len an integer specifying the length of the - * content being returned to the client; sets - * the Content-Length header - * - */ - - public void setContentLength(int len); - - - - /** - * Sets the content type of the response being sent to - * the client, if the response has not been committed yet. - * The given content type may include a character encoding - * specification, for example, text/html;charset=UTF-8. - * The response's character encoding is only set from the given - * content type if this method is called before getWriter - * is called. - *

This method may be called repeatedly to change content type and - * character encoding. - * This method has no effect if called after the response - * has been committed. It does not set the response's character - * encoding if it is called after getWriter - * has been called or after the response has been committed. - *

Containers must communicate the content type and the character - * encoding used for the servlet response's writer to the client if - * the protocol provides a way for doing so. In the case of HTTP, - * the Content-Type header is used. - * - * @param type a String specifying the MIME - * type of the content - * - * @see #setLocale - * @see #setCharacterEncoding - * @see #getOutputStream - * @see #getWriter - * - */ - - public void setContentType(String type); - - - /** - * Sets the preferred buffer size for the body of the response. - * The servlet container will use a buffer at least as large as - * the size requested. The actual buffer size used can be found - * using getBufferSize. - * - *

A larger buffer allows more content to be written before anything is - * actually sent, thus providing the servlet with more time to set - * appropriate status codes and headers. A smaller buffer decreases - * server memory load and allows the client to start receiving data more - * quickly. - * - *

This method must be called before any response body content is - * written; if content has been written or the response object has - * been committed, this method throws an - * IllegalStateException. - * - * @param size the preferred buffer size - * - * @exception IllegalStateException if this method is called after - * content has been written - * - * @see #getBufferSize - * @see #flushBuffer - * @see #isCommitted - * @see #reset - * - */ - - public void setBufferSize(int size); - - - - /** - * Returns the actual buffer size used for the response. If no buffering - * is used, this method returns 0. - * - * @return the actual buffer size used - * - * @see #setBufferSize - * @see #flushBuffer - * @see #isCommitted - * @see #reset - * - */ - - public int getBufferSize(); - - - - /** - * Forces any content in the buffer to be written to the client. A call - * to this method automatically commits the response, meaning the status - * code and headers will be written. - * - * @see #setBufferSize - * @see #getBufferSize - * @see #isCommitted - * @see #reset - * - */ - - public void flushBuffer() throws IOException; - - - - /** - * Clears the content of the underlying buffer in the response without - * clearing headers or status code. If the - * response has been committed, this method throws an - * IllegalStateException. - * - * @see #setBufferSize - * @see #getBufferSize - * @see #isCommitted - * @see #reset - * - * @since 2.3 - */ - - public void resetBuffer(); - - - /** - * Returns a boolean indicating if the response has been - * committed. A committed response has already had its status - * code and headers written. - * - * @return a boolean indicating if the response has been - * committed - * - * @see #setBufferSize - * @see #getBufferSize - * @see #flushBuffer - * @see #reset - * - */ - - public boolean isCommitted(); - - - - /** - * Clears any data that exists in the buffer as well as the status code and - * headers. If the response has been committed, this method throws an - * IllegalStateException. - * - * @exception IllegalStateException if the response has already been - * committed - * - * @see #setBufferSize - * @see #getBufferSize - * @see #flushBuffer - * @see #isCommitted - * - */ - - public void reset(); - - - - /** - * Sets the locale of the response, if the response has not been - * committed yet. It also sets the response's character encoding - * appropriately for the locale, if the character encoding has not - * been explicitly set using {@link #setContentType} or - * {@link #setCharacterEncoding}, getWriter hasn't - * been called yet, and the response hasn't been committed yet. - * If the deployment descriptor contains a - * locale-encoding-mapping-list element, and that - * element provides a mapping for the given locale, that mapping - * is used. Otherwise, the mapping from locale to character - * encoding is container dependent. - *

This method may be called repeatedly to change locale and - * character encoding. The method has no effect if called after the - * response has been committed. It does not set the response's - * character encoding if it is called after {@link #setContentType} - * has been called with a charset specification, after - * {@link #setCharacterEncoding} has been called, after - * getWriter has been called, or after the response - * has been committed. - *

Containers must communicate the locale and the character encoding - * used for the servlet response's writer to the client if the protocol - * provides a way for doing so. In the case of HTTP, the locale is - * communicated via the Content-Language header, - * the character encoding as part of the Content-Type - * header for text media types. Note that the character encoding - * cannot be communicated via HTTP headers if the servlet does not - * specify a content type; however, it is still used to encode text - * written via the servlet response's writer. - * - * @param loc the locale of the response - * - * @see #getLocale - * @see #setContentType - * @see #setCharacterEncoding - * - */ - - public void setLocale(Locale loc); - - - - /** - * Returns the locale specified for this response - * using the {@link #setLocale} method. Calls made to - * setLocale after the response is committed - * have no effect. If no locale has been specified, - * the container's default locale is returned. - * - * @see #setLocale - * - */ - - public Locale getLocale(); - - - -} - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + + +/** + * Defines an object to assist a servlet in sending a response to the client. + * The servlet container creates a ServletResponse object and + * passes it as an argument to the servlet's service method. + * + *

To send binary data in a MIME body response, use + * the {@link ServletOutputStream} returned by {@link #getOutputStream}. + * To send character data, use the PrintWriter object + * returned by {@link #getWriter}. To mix binary and text data, + * for example, to create a multipart response, use a + * ServletOutputStream and manage the character sections + * manually. + * + *

The charset for the MIME body response can be specified + * explicitly using the {@link #setCharacterEncoding} and + * {@link #setContentType} methods, or implicitly + * using the {@link #setLocale} method. + * Explicit specifications take precedence over + * implicit specifications. If no charset is specified, ISO-8859-1 will be + * used. The setCharacterEncoding, + * setContentType, or setLocale method must + * be called before getWriter and before committing + * the response for the character encoding to be used. + * + *

See the Internet RFCs such as + * + * RFC 2045 for more information on MIME. Protocols such as SMTP + * and HTTP define profiles of MIME, and those standards + * are still evolving. + * + * @author Various + * @version $Version$ + * + * @see ServletOutputStream + * + */ + +public interface ServletResponse { + + + + /** + * Returns the name of the character encoding (MIME charset) + * used for the body sent in this response. + * The character encoding may have been specified explicitly + * using the {@link #setCharacterEncoding} or + * {@link #setContentType} methods, or implicitly using the + * {@link #setLocale} method. Explicit specifications take + * precedence over implicit specifications. Calls made + * to these methods after getWriter has been + * called or after the response has been committed have no + * effect on the character encoding. If no character encoding + * has been specified, ISO-8859-1 is returned. + *

See RFC 2047 (http://www.ietf.org/rfc/rfc2047.txt) + * for more information about character encoding and MIME. + * + * @return a String specifying the + * name of the character encoding, for + * example, UTF-8 + * + */ + + public String getCharacterEncoding(); + + + + /** + * Returns the content type used for the MIME body + * sent in this response. The content type proper must + * have been specified using {@link #setContentType} + * before the response is committed. If no content type + * has been specified, this method returns null. + * If a content type has been specified and a + * character encoding has been explicitly or implicitly + * specified as described in {@link #getCharacterEncoding}, + * the charset parameter is included in the string returned. + * If no character encoding has been specified, the + * charset parameter is omitted. + * + * @return a String specifying the + * content type, for example, + * text/html; charset=UTF-8, + * or null + * + * @since 2.4 + */ + + public String getContentType(); + + + + /** + * Returns a {@link ServletOutputStream} suitable for writing binary + * data in the response. The servlet container does not encode the + * binary data. + + *

Calling flush() on the ServletOutputStream commits the response. + + * Either this method or {@link #getWriter} may + * be called to write the body, not both. + * + * @return a {@link ServletOutputStream} for writing binary data + * + * @exception IllegalStateException if the getWriter method + * has been called on this response + * + * @exception IOException if an input or output exception occurred + * + * @see #getWriter + * + */ + + public ServletOutputStream getOutputStream() throws IOException; + + + + /** + * Returns a PrintWriter object that + * can send character text to the client. + * The PrintWriter uses the character + * encoding returned by {@link #getCharacterEncoding}. + * If the response's character encoding has not been + * specified as described in getCharacterEncoding + * (i.e., the method just returns the default value + * ISO-8859-1), getWriter + * updates it to ISO-8859-1. + *

Calling flush() on the PrintWriter + * commits the response. + *

Either this method or {@link #getOutputStream} may be called + * to write the body, not both. + * + * + * @return a PrintWriter object that + * can return character data to the client + * + * @exception UnsupportedEncodingException + * if the character encoding returned + * by getCharacterEncoding cannot be used + * + * @exception IllegalStateException + * if the getOutputStream + * method has already been called for this + * response object + * + * @exception IOException + * if an input or output exception occurred + * + * @see #getOutputStream + * @see #setCharacterEncoding + * + */ + + public PrintWriter getWriter() throws IOException; + + + + + /** + * Sets the character encoding (MIME charset) of the response + * being sent to the client, for example, to UTF-8. + * If the character encoding has already been set by + * {@link #setContentType} or {@link #setLocale}, + * this method overrides it. + * Calling {@link #setContentType} with the String + * of text/html and calling + * this method with the String of UTF-8 + * is equivalent with calling + * setContentType with the String of + * text/html; charset=UTF-8. + *

This method can be called repeatedly to change the character + * encoding. + * This method has no effect if it is called after + * getWriter has been + * called or after the response has been committed. + *

Containers must communicate the character encoding used for + * the servlet response's writer to the client if the protocol + * provides a way for doing so. In the case of HTTP, the character + * encoding is communicated as part of the Content-Type + * header for text media types. Note that the character encoding + * cannot be communicated via HTTP headers if the servlet does not + * specify a content type; however, it is still used to encode text + * written via the servlet response's writer. + * + * @param charset a String specifying only the character set + * defined by IANA Character Sets + * (http://www.iana.org/assignments/character-sets) + * + * @see #setContentType + * #setLocale + * + * @since 2.4 + * + */ + + public void setCharacterEncoding(String charset); + + + + + /** + * Sets the length of the content body in the response + * In HTTP servlets, this method sets the HTTP Content-Length header. + * + * + * @param len an integer specifying the length of the + * content being returned to the client; sets + * the Content-Length header + * + */ + + public void setContentLength(int len); + + + + /** + * Sets the content type of the response being sent to + * the client, if the response has not been committed yet. + * The given content type may include a character encoding + * specification, for example, text/html;charset=UTF-8. + * The response's character encoding is only set from the given + * content type if this method is called before getWriter + * is called. + *

This method may be called repeatedly to change content type and + * character encoding. + * This method has no effect if called after the response + * has been committed. It does not set the response's character + * encoding if it is called after getWriter + * has been called or after the response has been committed. + *

Containers must communicate the content type and the character + * encoding used for the servlet response's writer to the client if + * the protocol provides a way for doing so. In the case of HTTP, + * the Content-Type header is used. + * + * @param type a String specifying the MIME + * type of the content + * + * @see #setLocale + * @see #setCharacterEncoding + * @see #getOutputStream + * @see #getWriter + * + */ + + public void setContentType(String type); + + + /** + * Sets the preferred buffer size for the body of the response. + * The servlet container will use a buffer at least as large as + * the size requested. The actual buffer size used can be found + * using getBufferSize. + * + *

A larger buffer allows more content to be written before anything is + * actually sent, thus providing the servlet with more time to set + * appropriate status codes and headers. A smaller buffer decreases + * server memory load and allows the client to start receiving data more + * quickly. + * + *

This method must be called before any response body content is + * written; if content has been written or the response object has + * been committed, this method throws an + * IllegalStateException. + * + * @param size the preferred buffer size + * + * @exception IllegalStateException if this method is called after + * content has been written + * + * @see #getBufferSize + * @see #flushBuffer + * @see #isCommitted + * @see #reset + * + */ + + public void setBufferSize(int size); + + + + /** + * Returns the actual buffer size used for the response. If no buffering + * is used, this method returns 0. + * + * @return the actual buffer size used + * + * @see #setBufferSize + * @see #flushBuffer + * @see #isCommitted + * @see #reset + * + */ + + public int getBufferSize(); + + + + /** + * Forces any content in the buffer to be written to the client. A call + * to this method automatically commits the response, meaning the status + * code and headers will be written. + * + * @see #setBufferSize + * @see #getBufferSize + * @see #isCommitted + * @see #reset + * + */ + + public void flushBuffer() throws IOException; + + + + /** + * Clears the content of the underlying buffer in the response without + * clearing headers or status code. If the + * response has been committed, this method throws an + * IllegalStateException. + * + * @see #setBufferSize + * @see #getBufferSize + * @see #isCommitted + * @see #reset + * + * @since 2.3 + */ + + public void resetBuffer(); + + + /** + * Returns a boolean indicating if the response has been + * committed. A committed response has already had its status + * code and headers written. + * + * @return a boolean indicating if the response has been + * committed + * + * @see #setBufferSize + * @see #getBufferSize + * @see #flushBuffer + * @see #reset + * + */ + + public boolean isCommitted(); + + + + /** + * Clears any data that exists in the buffer as well as the status code and + * headers. If the response has been committed, this method throws an + * IllegalStateException. + * + * @exception IllegalStateException if the response has already been + * committed + * + * @see #setBufferSize + * @see #getBufferSize + * @see #flushBuffer + * @see #isCommitted + * + */ + + public void reset(); + + + + /** + * Sets the locale of the response, if the response has not been + * committed yet. It also sets the response's character encoding + * appropriately for the locale, if the character encoding has not + * been explicitly set using {@link #setContentType} or + * {@link #setCharacterEncoding}, getWriter hasn't + * been called yet, and the response hasn't been committed yet. + * If the deployment descriptor contains a + * locale-encoding-mapping-list element, and that + * element provides a mapping for the given locale, that mapping + * is used. Otherwise, the mapping from locale to character + * encoding is container dependent. + *

This method may be called repeatedly to change locale and + * character encoding. The method has no effect if called after the + * response has been committed. It does not set the response's + * character encoding if it is called after {@link #setContentType} + * has been called with a charset specification, after + * {@link #setCharacterEncoding} has been called, after + * getWriter has been called, or after the response + * has been committed. + *

Containers must communicate the locale and the character encoding + * used for the servlet response's writer to the client if the protocol + * provides a way for doing so. In the case of HTTP, the locale is + * communicated via the Content-Language header, + * the character encoding as part of the Content-Type + * header for text media types. Note that the character encoding + * cannot be communicated via HTTP headers if the servlet does not + * specify a content type; however, it is still used to encode text + * written via the servlet response's writer. + * + * @param loc the locale of the response + * + * @see #getLocale + * @see #setContentType + * @see #setCharacterEncoding + * + */ + + public void setLocale(Locale loc); + + + + /** + * Returns the locale specified for this response + * using the {@link #setLocale} method. Calls made to + * setLocale after the response is committed + * have no effect. If no locale has been specified, + * the container's default locale is returned. + * + * @see #setLocale + * + */ + + public Locale getLocale(); + + + +} + + + + + diff --git a/java/javax/servlet/ServletResponseWrapper.java b/java/javax/servlet/ServletResponseWrapper.java index 829bb3058..7a95e28c6 100644 --- a/java/javax/servlet/ServletResponseWrapper.java +++ b/java/javax/servlet/ServletResponseWrapper.java @@ -1,217 +1,217 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Locale; - -/** - * - * Provides a convenient implementation of the ServletResponse interface that - * can be subclassed by developers wishing to adapt the response from a Servlet. - * This class implements the Wrapper or Decorator pattern. Methods default to - * calling through to the wrapped response object. - * - * @author Various - * @version $Version$ - * @since v 2.3 - * - * @see javax.servlet.ServletResponse - * - */ - - -public class ServletResponseWrapper implements ServletResponse { - private ServletResponse response; - /** - * Creates a ServletResponse adaptor wrapping the given response object. - * @throws java.lang.IllegalArgumentException if the response is null. - */ - - - public ServletResponseWrapper(ServletResponse response) { - if (response == null) { - throw new IllegalArgumentException("Response cannot be null"); - } - this.response = response; - } - - /** - * Return the wrapped ServletResponse object. - */ - - public ServletResponse getResponse() { - return this.response; - } - - - /** - * Sets the response being wrapped. - * @throws java.lang.IllegalArgumentException if the response is null. - */ - - public void setResponse(ServletResponse response) { - if (response == null) { - throw new IllegalArgumentException("Response cannot be null"); - } - this.response = response; - } - - /** - * The default behavior of this method is to call setCharacterEncoding(String charset) - * on the wrapped response object. - * - * @since 2.4 - */ - - public void setCharacterEncoding(String charset) { - this.response.setCharacterEncoding(charset); - } - - /** - * The default behavior of this method is to return getCharacterEncoding() - * on the wrapped response object. - */ - - public String getCharacterEncoding() { - return this.response.getCharacterEncoding(); - } - - - /** - * The default behavior of this method is to return getOutputStream() - * on the wrapped response object. - */ - - public ServletOutputStream getOutputStream() throws IOException { - return this.response.getOutputStream(); - } - - /** - * The default behavior of this method is to return getWriter() - * on the wrapped response object. - */ - - - public PrintWriter getWriter() throws IOException { - return this.response.getWriter(); - } - - /** - * The default behavior of this method is to call setContentLength(int len) - * on the wrapped response object. - */ - - public void setContentLength(int len) { - this.response.setContentLength(len); - } - - /** - * The default behavior of this method is to call setContentType(String type) - * on the wrapped response object. - */ - - public void setContentType(String type) { - this.response.setContentType(type); - } - - /** - * The default behavior of this method is to return getContentType() - * on the wrapped response object. - * - * @since 2.4 - */ - - public String getContentType() { - return this.response.getContentType(); - } - - /** - * The default behavior of this method is to call setBufferSize(int size) - * on the wrapped response object. - */ - public void setBufferSize(int size) { - this.response.setBufferSize(size); - } - - /** - * The default behavior of this method is to return getBufferSize() - * on the wrapped response object. - */ - public int getBufferSize() { - return this.response.getBufferSize(); - } - - /** - * The default behavior of this method is to call flushBuffer() - * on the wrapped response object. - */ - - public void flushBuffer() throws IOException { - this.response.flushBuffer(); - } - - /** - * The default behavior of this method is to return isCommitted() - * on the wrapped response object. - */ - public boolean isCommitted() { - return this.response.isCommitted(); - } - - /** - * The default behavior of this method is to call reset() - * on the wrapped response object. - */ - - public void reset() { - this.response.reset(); - } - - /** - * The default behavior of this method is to call resetBuffer() - * on the wrapped response object. - */ - - public void resetBuffer() { - this.response.resetBuffer(); - } - - /** - * The default behavior of this method is to call setLocale(Locale loc) - * on the wrapped response object. - */ - - public void setLocale(Locale loc) { - this.response.setLocale(loc); - } - - /** - * The default behavior of this method is to return getLocale() - * on the wrapped response object. - */ - public Locale getLocale() { - return this.response.getLocale(); - } - - -} - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Locale; + +/** + * + * Provides a convenient implementation of the ServletResponse interface that + * can be subclassed by developers wishing to adapt the response from a Servlet. + * This class implements the Wrapper or Decorator pattern. Methods default to + * calling through to the wrapped response object. + * + * @author Various + * @version $Version$ + * @since v 2.3 + * + * @see javax.servlet.ServletResponse + * + */ + + +public class ServletResponseWrapper implements ServletResponse { + private ServletResponse response; + /** + * Creates a ServletResponse adaptor wrapping the given response object. + * @throws java.lang.IllegalArgumentException if the response is null. + */ + + + public ServletResponseWrapper(ServletResponse response) { + if (response == null) { + throw new IllegalArgumentException("Response cannot be null"); + } + this.response = response; + } + + /** + * Return the wrapped ServletResponse object. + */ + + public ServletResponse getResponse() { + return this.response; + } + + + /** + * Sets the response being wrapped. + * @throws java.lang.IllegalArgumentException if the response is null. + */ + + public void setResponse(ServletResponse response) { + if (response == null) { + throw new IllegalArgumentException("Response cannot be null"); + } + this.response = response; + } + + /** + * The default behavior of this method is to call setCharacterEncoding(String charset) + * on the wrapped response object. + * + * @since 2.4 + */ + + public void setCharacterEncoding(String charset) { + this.response.setCharacterEncoding(charset); + } + + /** + * The default behavior of this method is to return getCharacterEncoding() + * on the wrapped response object. + */ + + public String getCharacterEncoding() { + return this.response.getCharacterEncoding(); + } + + + /** + * The default behavior of this method is to return getOutputStream() + * on the wrapped response object. + */ + + public ServletOutputStream getOutputStream() throws IOException { + return this.response.getOutputStream(); + } + + /** + * The default behavior of this method is to return getWriter() + * on the wrapped response object. + */ + + + public PrintWriter getWriter() throws IOException { + return this.response.getWriter(); + } + + /** + * The default behavior of this method is to call setContentLength(int len) + * on the wrapped response object. + */ + + public void setContentLength(int len) { + this.response.setContentLength(len); + } + + /** + * The default behavior of this method is to call setContentType(String type) + * on the wrapped response object. + */ + + public void setContentType(String type) { + this.response.setContentType(type); + } + + /** + * The default behavior of this method is to return getContentType() + * on the wrapped response object. + * + * @since 2.4 + */ + + public String getContentType() { + return this.response.getContentType(); + } + + /** + * The default behavior of this method is to call setBufferSize(int size) + * on the wrapped response object. + */ + public void setBufferSize(int size) { + this.response.setBufferSize(size); + } + + /** + * The default behavior of this method is to return getBufferSize() + * on the wrapped response object. + */ + public int getBufferSize() { + return this.response.getBufferSize(); + } + + /** + * The default behavior of this method is to call flushBuffer() + * on the wrapped response object. + */ + + public void flushBuffer() throws IOException { + this.response.flushBuffer(); + } + + /** + * The default behavior of this method is to return isCommitted() + * on the wrapped response object. + */ + public boolean isCommitted() { + return this.response.isCommitted(); + } + + /** + * The default behavior of this method is to call reset() + * on the wrapped response object. + */ + + public void reset() { + this.response.reset(); + } + + /** + * The default behavior of this method is to call resetBuffer() + * on the wrapped response object. + */ + + public void resetBuffer() { + this.response.resetBuffer(); + } + + /** + * The default behavior of this method is to call setLocale(Locale loc) + * on the wrapped response object. + */ + + public void setLocale(Locale loc) { + this.response.setLocale(loc); + } + + /** + * The default behavior of this method is to return getLocale() + * on the wrapped response object. + */ + public Locale getLocale() { + return this.response.getLocale(); + } + + +} + + + + + diff --git a/java/javax/servlet/SingleThreadModel.java b/java/javax/servlet/SingleThreadModel.java index acf4ef049..646ff0270 100644 --- a/java/javax/servlet/SingleThreadModel.java +++ b/java/javax/servlet/SingleThreadModel.java @@ -1,48 +1,48 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet; - -/** - * Ensures that servlets handle - * only one request at a time. This interface has no methods. - * - *

If a servlet implements this interface, you are guaranteed - * that no two threads will execute concurrently in the - * servlet's service method. The servlet container - * can make this guarantee by synchronizing access to a single - * instance of the servlet, or by maintaining a pool of servlet - * instances and dispatching each new request to a free servlet. - * - *

Note that SingleThreadModel does not solve all thread safety - * issues. For example, session attributes and static variables can - * still be accessed by multiple requests on multiple threads - * at the same time, even when SingleThreadModel servlets are used. - * It is recommended that a developer take other means to resolve - * those issues instead of implementing this interface, such as - * avoiding the usage of an instance variable or synchronizing - * the block of the code accessing those resources. - * This interface is deprecated in Servlet API version 2.4. - * - * - * @author Various - * @version $Version$ - * - * @deprecated As of Java Servlet API 2.4, with no direct - * replacement. - */ - -public interface SingleThreadModel { -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet; + +/** + * Ensures that servlets handle + * only one request at a time. This interface has no methods. + * + *

If a servlet implements this interface, you are guaranteed + * that no two threads will execute concurrently in the + * servlet's service method. The servlet container + * can make this guarantee by synchronizing access to a single + * instance of the servlet, or by maintaining a pool of servlet + * instances and dispatching each new request to a free servlet. + * + *

Note that SingleThreadModel does not solve all thread safety + * issues. For example, session attributes and static variables can + * still be accessed by multiple requests on multiple threads + * at the same time, even when SingleThreadModel servlets are used. + * It is recommended that a developer take other means to resolve + * those issues instead of implementing this interface, such as + * avoiding the usage of an instance variable or synchronizing + * the block of the code accessing those resources. + * This interface is deprecated in Servlet API version 2.4. + * + * + * @author Various + * @version $Version$ + * + * @deprecated As of Java Servlet API 2.4, with no direct + * replacement. + */ + +public interface SingleThreadModel { +} diff --git a/java/javax/servlet/UnavailableException.java b/java/javax/servlet/UnavailableException.java index ab2dff8a3..cc0d7e55d 100644 --- a/java/javax/servlet/UnavailableException.java +++ b/java/javax/servlet/UnavailableException.java @@ -1,205 +1,205 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet; - - -/** - * Defines an exception that a servlet or filter throws to indicate - * that it is permanently or temporarily unavailable. - * - *

When a servlet or filter is permanently unavailable, something is wrong - * with it, and it cannot handle - * requests until some action is taken. For example, a servlet - * might be configured incorrectly, or a filter's state may be corrupted. - * The component should log both the error and the corrective action - * that is needed. - * - *

A servlet or filter is temporarily unavailable if it cannot handle - * requests momentarily due to some system-wide problem. For example, - * a third-tier server might not be accessible, or there may be - * insufficient memory or disk storage to handle requests. A system - * administrator may need to take corrective action. - * - *

Servlet containers can safely treat both types of unavailable - * exceptions in the same way. However, treating temporary unavailability - * effectively makes the servlet container more robust. Specifically, - * the servlet container might block requests to the servlet or filter for a period - * of time suggested by the exception, rather than rejecting them until - * the servlet container restarts. - * - * - * @author Various - * @version $Version$ - * - */ - -public class UnavailableException -extends ServletException { - - private Servlet servlet; // what's unavailable - private boolean permanent; // needs admin action? - private int seconds; // unavailability estimate - - /** - * - * @deprecated As of Java Servlet API 2.2, use {@link - * #UnavailableException(String)} instead. - * - * @param servlet the Servlet instance that is - * unavailable - * - * @param msg a String specifying the - * descriptive message - * - */ - - public UnavailableException(Servlet servlet, String msg) { - super(msg); - this.servlet = servlet; - permanent = true; - } - - /** - * @deprecated As of Java Servlet API 2.2, use {@link - * #UnavailableException(String, int)} instead. - * - * @param seconds an integer specifying the number of seconds - * the servlet expects to be unavailable; if - * zero or negative, indicates that the servlet - * can't make an estimate - * - * @param servlet the Servlet that is unavailable - * - * @param msg a String specifying the descriptive - * message, which can be written to a log file or - * displayed for the user. - * - */ - - public UnavailableException(int seconds, Servlet servlet, String msg) { - super(msg); - this.servlet = servlet; - if (seconds <= 0) - this.seconds = -1; - else - this.seconds = seconds; - permanent = false; - } - - /** - * - * Constructs a new exception with a descriptive - * message indicating that the servlet is permanently - * unavailable. - * - * @param msg a String specifying the - * descriptive message - * - */ - - public UnavailableException(String msg) { - super(msg); - - permanent = true; - } - - /** - * Constructs a new exception with a descriptive message - * indicating that the servlet is temporarily unavailable - * and giving an estimate of how long it will be unavailable. - * - *

In some cases, the servlet cannot make an estimate. For - * example, the servlet might know that a server it needs is - * not running, but not be able to report how long it will take - * to be restored to functionality. This can be indicated with - * a negative or zero value for the seconds argument. - * - * @param msg a String specifying the - * descriptive message, which can be written - * to a log file or displayed for the user. - * - * @param seconds an integer specifying the number of seconds - * the servlet expects to be unavailable; if - * zero or negative, indicates that the servlet - * can't make an estimate - * - */ - - public UnavailableException(String msg, int seconds) { - super(msg); - - if (seconds <= 0) - this.seconds = -1; - else - this.seconds = seconds; - - permanent = false; - } - - /** - * - * Returns a boolean indicating - * whether the servlet is permanently unavailable. - * If so, something is wrong with the servlet, and the - * system administrator must take some corrective action. - * - * @return true if the servlet is - * permanently unavailable; false - * if the servlet is available or temporarily - * unavailable - * - */ - - public boolean isPermanent() { - return permanent; - } - - /** - * @deprecated As of Java Servlet API 2.2, with no replacement. - * - * Returns the servlet that is reporting its unavailability. - * - * @return the Servlet object that is - * throwing the UnavailableException - * - */ - - public Servlet getServlet() { - return servlet; - } - - /** - * Returns the number of seconds the servlet expects to - * be temporarily unavailable. - * - *

If this method returns a negative number, the servlet - * is permanently unavailable or cannot provide an estimate of - * how long it will be unavailable. No effort is - * made to correct for the time elapsed since the exception was - * first reported. - * - * @return an integer specifying the number of seconds - * the servlet will be temporarily unavailable, - * or a negative number if the servlet is permanently - * unavailable or cannot make an estimate - * - */ - - public int getUnavailableSeconds() { - return permanent ? -1 : seconds; - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet; + + +/** + * Defines an exception that a servlet or filter throws to indicate + * that it is permanently or temporarily unavailable. + * + *

When a servlet or filter is permanently unavailable, something is wrong + * with it, and it cannot handle + * requests until some action is taken. For example, a servlet + * might be configured incorrectly, or a filter's state may be corrupted. + * The component should log both the error and the corrective action + * that is needed. + * + *

A servlet or filter is temporarily unavailable if it cannot handle + * requests momentarily due to some system-wide problem. For example, + * a third-tier server might not be accessible, or there may be + * insufficient memory or disk storage to handle requests. A system + * administrator may need to take corrective action. + * + *

Servlet containers can safely treat both types of unavailable + * exceptions in the same way. However, treating temporary unavailability + * effectively makes the servlet container more robust. Specifically, + * the servlet container might block requests to the servlet or filter for a period + * of time suggested by the exception, rather than rejecting them until + * the servlet container restarts. + * + * + * @author Various + * @version $Version$ + * + */ + +public class UnavailableException +extends ServletException { + + private Servlet servlet; // what's unavailable + private boolean permanent; // needs admin action? + private int seconds; // unavailability estimate + + /** + * + * @deprecated As of Java Servlet API 2.2, use {@link + * #UnavailableException(String)} instead. + * + * @param servlet the Servlet instance that is + * unavailable + * + * @param msg a String specifying the + * descriptive message + * + */ + + public UnavailableException(Servlet servlet, String msg) { + super(msg); + this.servlet = servlet; + permanent = true; + } + + /** + * @deprecated As of Java Servlet API 2.2, use {@link + * #UnavailableException(String, int)} instead. + * + * @param seconds an integer specifying the number of seconds + * the servlet expects to be unavailable; if + * zero or negative, indicates that the servlet + * can't make an estimate + * + * @param servlet the Servlet that is unavailable + * + * @param msg a String specifying the descriptive + * message, which can be written to a log file or + * displayed for the user. + * + */ + + public UnavailableException(int seconds, Servlet servlet, String msg) { + super(msg); + this.servlet = servlet; + if (seconds <= 0) + this.seconds = -1; + else + this.seconds = seconds; + permanent = false; + } + + /** + * + * Constructs a new exception with a descriptive + * message indicating that the servlet is permanently + * unavailable. + * + * @param msg a String specifying the + * descriptive message + * + */ + + public UnavailableException(String msg) { + super(msg); + + permanent = true; + } + + /** + * Constructs a new exception with a descriptive message + * indicating that the servlet is temporarily unavailable + * and giving an estimate of how long it will be unavailable. + * + *

In some cases, the servlet cannot make an estimate. For + * example, the servlet might know that a server it needs is + * not running, but not be able to report how long it will take + * to be restored to functionality. This can be indicated with + * a negative or zero value for the seconds argument. + * + * @param msg a String specifying the + * descriptive message, which can be written + * to a log file or displayed for the user. + * + * @param seconds an integer specifying the number of seconds + * the servlet expects to be unavailable; if + * zero or negative, indicates that the servlet + * can't make an estimate + * + */ + + public UnavailableException(String msg, int seconds) { + super(msg); + + if (seconds <= 0) + this.seconds = -1; + else + this.seconds = seconds; + + permanent = false; + } + + /** + * + * Returns a boolean indicating + * whether the servlet is permanently unavailable. + * If so, something is wrong with the servlet, and the + * system administrator must take some corrective action. + * + * @return true if the servlet is + * permanently unavailable; false + * if the servlet is available or temporarily + * unavailable + * + */ + + public boolean isPermanent() { + return permanent; + } + + /** + * @deprecated As of Java Servlet API 2.2, with no replacement. + * + * Returns the servlet that is reporting its unavailability. + * + * @return the Servlet object that is + * throwing the UnavailableException + * + */ + + public Servlet getServlet() { + return servlet; + } + + /** + * Returns the number of seconds the servlet expects to + * be temporarily unavailable. + * + *

If this method returns a negative number, the servlet + * is permanently unavailable or cannot provide an estimate of + * how long it will be unavailable. No effort is + * made to correct for the time elapsed since the exception was + * first reported. + * + * @return an integer specifying the number of seconds + * the servlet will be temporarily unavailable, + * or a negative number if the servlet is permanently + * unavailable or cannot make an estimate + * + */ + + public int getUnavailableSeconds() { + return permanent ? -1 : seconds; + } +} diff --git a/java/javax/servlet/http/Cookie.java b/java/javax/servlet/http/Cookie.java index a7b54b7fe..7cbc6b46c 100644 --- a/java/javax/servlet/http/Cookie.java +++ b/java/javax/servlet/http/Cookie.java @@ -1,536 +1,536 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * - * Creates a cookie, a small amount of information sent by a servlet to - * a Web browser, saved by the browser, and later sent back to the server. - * A cookie's value can uniquely - * identify a client, so cookies are commonly used for session management. - * - *

A cookie has a name, a single value, and optional attributes - * such as a comment, path and domain qualifiers, a maximum age, and a - * version number. Some Web browsers have bugs in how they handle the - * optional attributes, so use them sparingly to improve the interoperability - * of your servlets. - * - *

The servlet sends cookies to the browser by using the - * {@link HttpServletResponse#addCookie} method, which adds - * fields to HTTP response headers to send cookies to the - * browser, one at a time. The browser is expected to - * support 20 cookies for each Web server, 300 cookies total, and - * may limit cookie size to 4 KB each. - * - *

The browser returns cookies to the servlet by adding - * fields to HTTP request headers. Cookies can be retrieved - * from a request by using the {@link HttpServletRequest#getCookies} method. - * Several cookies might have the same name but different path attributes. - * - *

Cookies affect the caching of the Web pages that use them. - * HTTP 1.0 does not cache pages that use cookies created with - * this class. This class does not support the cache control - * defined with HTTP 1.1. - * - *

This class supports both the Version 0 (by Netscape) and Version 1 - * (by RFC 2109) cookie specifications. By default, cookies are - * created using Version 0 to ensure the best interoperability. - * - * - * @author Various - * @version $Version$ - * - */ - -// XXX would implement java.io.Serializable too, but can't do that -// so long as sun.servlet.* must run on older JDK 1.02 JVMs which -// don't include that support. - -public class Cookie implements Cloneable { - - private static final String LSTRING_FILE = - "javax.servlet.http.LocalStrings"; - private static ResourceBundle lStrings = - ResourceBundle.getBundle(LSTRING_FILE); - - // - // The value of the cookie itself. - // - - private String name; // NAME= ... "$Name" style is reserved - private String value; // value of NAME - - // - // Attributes encoded in the header's cookie fields. - // - - private String comment; // ;Comment=VALUE ... describes cookie's use - // ;Discard ... implied by maxAge < 0 - private String domain; // ;Domain=VALUE ... domain that sees cookie - private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire - private String path; // ;Path=VALUE ... URLs that see the cookie - private boolean secure; // ;Secure ... e.g. use SSL - private int version = 0; // ;Version=1 ... means RFC 2109++ style - - - - /** - * Constructs a cookie with a specified name and value. - * - *

The name must conform to RFC 2109. That means it can contain - * only ASCII alphanumeric characters and cannot contain commas, - * semicolons, or white space or begin with a $ character. The cookie's - * name cannot be changed after creation. - * - *

The value can be anything the server chooses to send. Its - * value is probably of interest only to the server. The cookie's - * value can be changed after creation with the - * setValue method. - * - *

By default, cookies are created according to the Netscape - * cookie specification. The version can be changed with the - * setVersion method. - * - * - * @param name a String specifying the name of the cookie - * - * @param value a String specifying the value of the cookie - * - * @throws IllegalArgumentException if the cookie name contains illegal characters - * (for example, a comma, space, or semicolon) - * or it is one of the tokens reserved for use - * by the cookie protocol - * @see #setValue - * @see #setVersion - * - */ - - public Cookie(String name, String value) { - if (!isToken(name) - || name.equalsIgnoreCase("Comment") // rfc2019 - || name.equalsIgnoreCase("Discard") // 2019++ - || name.equalsIgnoreCase("Domain") - || name.equalsIgnoreCase("Expires") // (old cookies) - || name.equalsIgnoreCase("Max-Age") // rfc2019 - || name.equalsIgnoreCase("Path") - || name.equalsIgnoreCase("Secure") - || name.equalsIgnoreCase("Version") - || name.startsWith("$") - ) { - String errMsg = lStrings.getString("err.cookie_name_is_token"); - Object[] errArgs = new Object[1]; - errArgs[0] = name; - errMsg = MessageFormat.format(errMsg, errArgs); - throw new IllegalArgumentException(errMsg); - } - - this.name = name; - this.value = value; - } - - - - - - /** - * - * Specifies a comment that describes a cookie's purpose. - * The comment is useful if the browser presents the cookie - * to the user. Comments - * are not supported by Netscape Version 0 cookies. - * - * @param purpose a String specifying the comment - * to display to the user - * - * @see #getComment - * - */ - - public void setComment(String purpose) { - comment = purpose; - } - - - - - /** - * Returns the comment describing the purpose of this cookie, or - * null if the cookie has no comment. - * - * @return a String containing the comment, - * or null if none - * - * @see #setComment - * - */ - - public String getComment() { - return comment; - } - - - - - - /** - * - * Specifies the domain within which this cookie should be presented. - * - *

The form of the domain name is specified by RFC 2109. A domain - * name begins with a dot (.foo.com) and means that - * the cookie is visible to servers in a specified Domain Name System - * (DNS) zone (for example, www.foo.com, but not - * a.b.foo.com). By default, cookies are only returned - * to the server that sent them. - * - * - * @param pattern a String containing the domain name - * within which this cookie is visible; - * form is according to RFC 2109 - * - * @see #getDomain - * - */ - - public void setDomain(String pattern) { - domain = pattern.toLowerCase(); // IE allegedly needs this - } - - - - - - /** - * Returns the domain name set for this cookie. The form of - * the domain name is set by RFC 2109. - * - * @return a String containing the domain name - * - * @see #setDomain - * - */ - - public String getDomain() { - return domain; - } - - - - - /** - * Sets the maximum age of the cookie in seconds. - * - *

A positive value indicates that the cookie will expire - * after that many seconds have passed. Note that the value is - * the maximum age when the cookie will expire, not the cookie's - * current age. - * - *

A negative value means - * that the cookie is not stored persistently and will be deleted - * when the Web browser exits. A zero value causes the cookie - * to be deleted. - * - * @param expiry an integer specifying the maximum age of the - * cookie in seconds; if negative, means - * the cookie is not stored; if zero, deletes - * the cookie - * - * - * @see #getMaxAge - * - */ - - public void setMaxAge(int expiry) { - maxAge = expiry; - } - - - - - /** - * Returns the maximum age of the cookie, specified in seconds, - * By default, -1 indicating the cookie will persist - * until browser shutdown. - * - * - * @return an integer specifying the maximum age of the - * cookie in seconds; if negative, means - * the cookie persists until browser shutdown - * - * - * @see #setMaxAge - * - */ - - public int getMaxAge() { - return maxAge; - } - - - - - /** - * Specifies a path for the cookie - * to which the client should return the cookie. - * - *

The cookie is visible to all the pages in the directory - * you specify, and all the pages in that directory's subdirectories. - * A cookie's path must include the servlet that set the cookie, - * for example, /catalog, which makes the cookie - * visible to all directories on the server under /catalog. - * - *

Consult RFC 2109 (available on the Internet) for more - * information on setting path names for cookies. - * - * - * @param uri a String specifying a path - * - * - * @see #getPath - * - */ - - public void setPath(String uri) { - path = uri; - } - - - - - /** - * Returns the path on the server - * to which the browser returns this cookie. The - * cookie is visible to all subpaths on the server. - * - * - * @return a String specifying a path that contains - * a servlet name, for example, /catalog - * - * @see #setPath - * - */ - - public String getPath() { - return path; - } - - - - - - /** - * Indicates to the browser whether the cookie should only be sent - * using a secure protocol, such as HTTPS or SSL. - * - *

The default value is false. - * - * @param flag if true, sends the cookie from the browser - * to the server only when using a secure protocol; - * if false, sent on any protocol - * - * @see #getSecure - * - */ - - public void setSecure(boolean flag) { - secure = flag; - } - - - - - /** - * Returns true if the browser is sending cookies - * only over a secure protocol, or false if the - * browser can send cookies using any protocol. - * - * @return true if the browser uses a secure protocol; - * otherwise, true - * - * @see #setSecure - * - */ - - public boolean getSecure() { - return secure; - } - - - - - - /** - * Returns the name of the cookie. The name cannot be changed after - * creation. - * - * @return a String specifying the cookie's name - * - */ - - public String getName() { - return name; - } - - - - - - /** - * - * Assigns a new value to a cookie after the cookie is created. - * If you use a binary value, you may want to use BASE64 encoding. - * - *

With Version 0 cookies, values should not contain white - * space, brackets, parentheses, equals signs, commas, - * double quotes, slashes, question marks, at signs, colons, - * and semicolons. Empty values may not behave the same way - * on all browsers. - * - * @param newValue a String specifying the new value - * - * - * @see #getValue - * @see Cookie - * - */ - - public void setValue(String newValue) { - value = newValue; - } - - - - - /** - * Returns the value of the cookie. - * - * @return a String containing the cookie's - * present value - * - * @see #setValue - * @see Cookie - * - */ - - public String getValue() { - return value; - } - - - - - /** - * Returns the version of the protocol this cookie complies - * with. Version 1 complies with RFC 2109, - * and version 0 complies with the original - * cookie specification drafted by Netscape. Cookies provided - * by a browser use and identify the browser's cookie version. - * - * - * @return 0 if the cookie complies with the - * original Netscape specification; 1 - * if the cookie complies with RFC 2109 - * - * @see #setVersion - * - */ - - public int getVersion() { - return version; - } - - - - - /** - * Sets the version of the cookie protocol this cookie complies - * with. Version 0 complies with the original Netscape cookie - * specification. Version 1 complies with RFC 2109. - * - *

Since RFC 2109 is still somewhat new, consider - * version 1 as experimental; do not use it yet on production sites. - * - * - * @param v 0 if the cookie should comply with - * the original Netscape specification; - * 1 if the cookie should comply with RFC 2109 - * - * @see #getVersion - * - */ - - public void setVersion(int v) { - version = v; - } - - // Note -- disabled for now to allow full Netscape compatibility - // from RFC 2068, token special case characters - // - // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; - - private static final String tspecials = ",; "; - - - - - /* - * Tests a string and returns true if the string counts as a - * reserved token in the Java language. - * - * @param value the String to be tested - * - * @return true if the String is - * a reserved token; false - * if it is not - */ - - private boolean isToken(String value) { - int len = value.length(); - - for (int i = 0; i < len; i++) { - char c = value.charAt(i); - - if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) - return false; - } - return true; - } - - - - - - - /** - * - * Overrides the standard java.lang.Object.clone - * method to return a copy of this cookie. - * - * - */ - - public Object clone() { - try { - return super.clone(); - } catch (CloneNotSupportedException e) { - throw new RuntimeException(e.getMessage()); - } - } -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +/** + * + * Creates a cookie, a small amount of information sent by a servlet to + * a Web browser, saved by the browser, and later sent back to the server. + * A cookie's value can uniquely + * identify a client, so cookies are commonly used for session management. + * + *

A cookie has a name, a single value, and optional attributes + * such as a comment, path and domain qualifiers, a maximum age, and a + * version number. Some Web browsers have bugs in how they handle the + * optional attributes, so use them sparingly to improve the interoperability + * of your servlets. + * + *

The servlet sends cookies to the browser by using the + * {@link HttpServletResponse#addCookie} method, which adds + * fields to HTTP response headers to send cookies to the + * browser, one at a time. The browser is expected to + * support 20 cookies for each Web server, 300 cookies total, and + * may limit cookie size to 4 KB each. + * + *

The browser returns cookies to the servlet by adding + * fields to HTTP request headers. Cookies can be retrieved + * from a request by using the {@link HttpServletRequest#getCookies} method. + * Several cookies might have the same name but different path attributes. + * + *

Cookies affect the caching of the Web pages that use them. + * HTTP 1.0 does not cache pages that use cookies created with + * this class. This class does not support the cache control + * defined with HTTP 1.1. + * + *

This class supports both the Version 0 (by Netscape) and Version 1 + * (by RFC 2109) cookie specifications. By default, cookies are + * created using Version 0 to ensure the best interoperability. + * + * + * @author Various + * @version $Version$ + * + */ + +// XXX would implement java.io.Serializable too, but can't do that +// so long as sun.servlet.* must run on older JDK 1.02 JVMs which +// don't include that support. + +public class Cookie implements Cloneable { + + private static final String LSTRING_FILE = + "javax.servlet.http.LocalStrings"; + private static ResourceBundle lStrings = + ResourceBundle.getBundle(LSTRING_FILE); + + // + // The value of the cookie itself. + // + + private String name; // NAME= ... "$Name" style is reserved + private String value; // value of NAME + + // + // Attributes encoded in the header's cookie fields. + // + + private String comment; // ;Comment=VALUE ... describes cookie's use + // ;Discard ... implied by maxAge < 0 + private String domain; // ;Domain=VALUE ... domain that sees cookie + private int maxAge = -1; // ;Max-Age=VALUE ... cookies auto-expire + private String path; // ;Path=VALUE ... URLs that see the cookie + private boolean secure; // ;Secure ... e.g. use SSL + private int version = 0; // ;Version=1 ... means RFC 2109++ style + + + + /** + * Constructs a cookie with a specified name and value. + * + *

The name must conform to RFC 2109. That means it can contain + * only ASCII alphanumeric characters and cannot contain commas, + * semicolons, or white space or begin with a $ character. The cookie's + * name cannot be changed after creation. + * + *

The value can be anything the server chooses to send. Its + * value is probably of interest only to the server. The cookie's + * value can be changed after creation with the + * setValue method. + * + *

By default, cookies are created according to the Netscape + * cookie specification. The version can be changed with the + * setVersion method. + * + * + * @param name a String specifying the name of the cookie + * + * @param value a String specifying the value of the cookie + * + * @throws IllegalArgumentException if the cookie name contains illegal characters + * (for example, a comma, space, or semicolon) + * or it is one of the tokens reserved for use + * by the cookie protocol + * @see #setValue + * @see #setVersion + * + */ + + public Cookie(String name, String value) { + if (!isToken(name) + || name.equalsIgnoreCase("Comment") // rfc2019 + || name.equalsIgnoreCase("Discard") // 2019++ + || name.equalsIgnoreCase("Domain") + || name.equalsIgnoreCase("Expires") // (old cookies) + || name.equalsIgnoreCase("Max-Age") // rfc2019 + || name.equalsIgnoreCase("Path") + || name.equalsIgnoreCase("Secure") + || name.equalsIgnoreCase("Version") + || name.startsWith("$") + ) { + String errMsg = lStrings.getString("err.cookie_name_is_token"); + Object[] errArgs = new Object[1]; + errArgs[0] = name; + errMsg = MessageFormat.format(errMsg, errArgs); + throw new IllegalArgumentException(errMsg); + } + + this.name = name; + this.value = value; + } + + + + + + /** + * + * Specifies a comment that describes a cookie's purpose. + * The comment is useful if the browser presents the cookie + * to the user. Comments + * are not supported by Netscape Version 0 cookies. + * + * @param purpose a String specifying the comment + * to display to the user + * + * @see #getComment + * + */ + + public void setComment(String purpose) { + comment = purpose; + } + + + + + /** + * Returns the comment describing the purpose of this cookie, or + * null if the cookie has no comment. + * + * @return a String containing the comment, + * or null if none + * + * @see #setComment + * + */ + + public String getComment() { + return comment; + } + + + + + + /** + * + * Specifies the domain within which this cookie should be presented. + * + *

The form of the domain name is specified by RFC 2109. A domain + * name begins with a dot (.foo.com) and means that + * the cookie is visible to servers in a specified Domain Name System + * (DNS) zone (for example, www.foo.com, but not + * a.b.foo.com). By default, cookies are only returned + * to the server that sent them. + * + * + * @param pattern a String containing the domain name + * within which this cookie is visible; + * form is according to RFC 2109 + * + * @see #getDomain + * + */ + + public void setDomain(String pattern) { + domain = pattern.toLowerCase(); // IE allegedly needs this + } + + + + + + /** + * Returns the domain name set for this cookie. The form of + * the domain name is set by RFC 2109. + * + * @return a String containing the domain name + * + * @see #setDomain + * + */ + + public String getDomain() { + return domain; + } + + + + + /** + * Sets the maximum age of the cookie in seconds. + * + *

A positive value indicates that the cookie will expire + * after that many seconds have passed. Note that the value is + * the maximum age when the cookie will expire, not the cookie's + * current age. + * + *

A negative value means + * that the cookie is not stored persistently and will be deleted + * when the Web browser exits. A zero value causes the cookie + * to be deleted. + * + * @param expiry an integer specifying the maximum age of the + * cookie in seconds; if negative, means + * the cookie is not stored; if zero, deletes + * the cookie + * + * + * @see #getMaxAge + * + */ + + public void setMaxAge(int expiry) { + maxAge = expiry; + } + + + + + /** + * Returns the maximum age of the cookie, specified in seconds, + * By default, -1 indicating the cookie will persist + * until browser shutdown. + * + * + * @return an integer specifying the maximum age of the + * cookie in seconds; if negative, means + * the cookie persists until browser shutdown + * + * + * @see #setMaxAge + * + */ + + public int getMaxAge() { + return maxAge; + } + + + + + /** + * Specifies a path for the cookie + * to which the client should return the cookie. + * + *

The cookie is visible to all the pages in the directory + * you specify, and all the pages in that directory's subdirectories. + * A cookie's path must include the servlet that set the cookie, + * for example, /catalog, which makes the cookie + * visible to all directories on the server under /catalog. + * + *

Consult RFC 2109 (available on the Internet) for more + * information on setting path names for cookies. + * + * + * @param uri a String specifying a path + * + * + * @see #getPath + * + */ + + public void setPath(String uri) { + path = uri; + } + + + + + /** + * Returns the path on the server + * to which the browser returns this cookie. The + * cookie is visible to all subpaths on the server. + * + * + * @return a String specifying a path that contains + * a servlet name, for example, /catalog + * + * @see #setPath + * + */ + + public String getPath() { + return path; + } + + + + + + /** + * Indicates to the browser whether the cookie should only be sent + * using a secure protocol, such as HTTPS or SSL. + * + *

The default value is false. + * + * @param flag if true, sends the cookie from the browser + * to the server only when using a secure protocol; + * if false, sent on any protocol + * + * @see #getSecure + * + */ + + public void setSecure(boolean flag) { + secure = flag; + } + + + + + /** + * Returns true if the browser is sending cookies + * only over a secure protocol, or false if the + * browser can send cookies using any protocol. + * + * @return true if the browser uses a secure protocol; + * otherwise, true + * + * @see #setSecure + * + */ + + public boolean getSecure() { + return secure; + } + + + + + + /** + * Returns the name of the cookie. The name cannot be changed after + * creation. + * + * @return a String specifying the cookie's name + * + */ + + public String getName() { + return name; + } + + + + + + /** + * + * Assigns a new value to a cookie after the cookie is created. + * If you use a binary value, you may want to use BASE64 encoding. + * + *

With Version 0 cookies, values should not contain white + * space, brackets, parentheses, equals signs, commas, + * double quotes, slashes, question marks, at signs, colons, + * and semicolons. Empty values may not behave the same way + * on all browsers. + * + * @param newValue a String specifying the new value + * + * + * @see #getValue + * @see Cookie + * + */ + + public void setValue(String newValue) { + value = newValue; + } + + + + + /** + * Returns the value of the cookie. + * + * @return a String containing the cookie's + * present value + * + * @see #setValue + * @see Cookie + * + */ + + public String getValue() { + return value; + } + + + + + /** + * Returns the version of the protocol this cookie complies + * with. Version 1 complies with RFC 2109, + * and version 0 complies with the original + * cookie specification drafted by Netscape. Cookies provided + * by a browser use and identify the browser's cookie version. + * + * + * @return 0 if the cookie complies with the + * original Netscape specification; 1 + * if the cookie complies with RFC 2109 + * + * @see #setVersion + * + */ + + public int getVersion() { + return version; + } + + + + + /** + * Sets the version of the cookie protocol this cookie complies + * with. Version 0 complies with the original Netscape cookie + * specification. Version 1 complies with RFC 2109. + * + *

Since RFC 2109 is still somewhat new, consider + * version 1 as experimental; do not use it yet on production sites. + * + * + * @param v 0 if the cookie should comply with + * the original Netscape specification; + * 1 if the cookie should comply with RFC 2109 + * + * @see #getVersion + * + */ + + public void setVersion(int v) { + version = v; + } + + // Note -- disabled for now to allow full Netscape compatibility + // from RFC 2068, token special case characters + // + // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; + + private static final String tspecials = ",; "; + + + + + /* + * Tests a string and returns true if the string counts as a + * reserved token in the Java language. + * + * @param value the String to be tested + * + * @return true if the String is + * a reserved token; false + * if it is not + */ + + private boolean isToken(String value) { + int len = value.length(); + + for (int i = 0; i < len; i++) { + char c = value.charAt(i); + + if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) + return false; + } + return true; + } + + + + + + + /** + * + * Overrides the standard java.lang.Object.clone + * method to return a copy of this cookie. + * + * + */ + + public Object clone() { + try { + return super.clone(); + } catch (CloneNotSupportedException e) { + throw new RuntimeException(e.getMessage()); + } + } +} + diff --git a/java/javax/servlet/http/HttpServlet.java b/java/javax/servlet/http/HttpServlet.java index fd61cf441..08479b9f6 100644 --- a/java/javax/servlet/http/HttpServlet.java +++ b/java/javax/servlet/http/HttpServlet.java @@ -1,1018 +1,1018 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.lang.reflect.Method; -import java.text.MessageFormat; -import java.util.Enumeration; -import java.util.Locale; -import java.util.ResourceBundle; - -import javax.servlet.GenericServlet; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - - -/** - * - * Provides an abstract class to be subclassed to create - * an HTTP servlet suitable for a Web site. A subclass of - * HttpServlet must override at least - * one method, usually one of these: - * - *

    - *
  • doGet, if the servlet supports HTTP GET requests - *
  • doPost, for HTTP POST requests - *
  • doPut, for HTTP PUT requests - *
  • doDelete, for HTTP DELETE requests - *
  • init and destroy, - * to manage resources that are held for the life of the servlet - *
  • getServletInfo, which the servlet uses to - * provide information about itself - *
- * - *

There's almost no reason to override the service - * method. service handles standard HTTP - * requests by dispatching them to the handler methods - * for each HTTP request type (the doXXX - * methods listed above). - * - *

Likewise, there's almost no reason to override the - * doOptions and doTrace methods. - * - *

Servlets typically run on multithreaded servers, - * so be aware that a servlet must handle concurrent - * requests and be careful to synchronize access to shared resources. - * Shared resources include in-memory data such as - * instance or class variables and external objects - * such as files, database connections, and network - * connections. - * See the - * - * Java Tutorial on Multithreaded Programming for more - * information on handling multiple threads in a Java program. - * - * @author Various - * @version $Version$ - * - */ - - - -public abstract class HttpServlet extends GenericServlet - implements java.io.Serializable -{ - private static final String METHOD_DELETE = "DELETE"; - private static final String METHOD_HEAD = "HEAD"; - private static final String METHOD_GET = "GET"; - private static final String METHOD_OPTIONS = "OPTIONS"; - private static final String METHOD_POST = "POST"; - private static final String METHOD_PUT = "PUT"; - private static final String METHOD_TRACE = "TRACE"; - - private static final String HEADER_IFMODSINCE = "If-Modified-Since"; - private static final String HEADER_LASTMOD = "Last-Modified"; - - private static final String LSTRING_FILE = - "javax.servlet.http.LocalStrings"; - private static ResourceBundle lStrings = - ResourceBundle.getBundle(LSTRING_FILE); - - - - - /** - * Does nothing, because this is an abstract class. - * - */ - - public HttpServlet() { } - - - - /** - * - * Called by the server (via the service method) to - * allow a servlet to handle a GET request. - * - *

Overriding this method to support a GET request also - * automatically supports an HTTP HEAD request. A HEAD - * request is a GET request that returns no body in the - * response, only the request header fields. - * - *

When overriding this method, read the request data, - * write the response headers, get the response's writer or - * output stream object, and finally, write the response data. - * It's best to include content type and encoding. When using - * a PrintWriter object to return the response, - * set the content type before accessing the - * PrintWriter object. - * - *

The servlet container must write the headers before - * committing the response, because in HTTP the headers must be sent - * before the response body. - * - *

Where possible, set the Content-Length header (with the - * {@link javax.servlet.ServletResponse#setContentLength} method), - * to allow the servlet container to use a persistent connection - * to return its response to the client, improving performance. - * The content length is automatically set if the entire response fits - * inside the response buffer. - * - *

When using HTTP 1.1 chunked encoding (which means that the response - * has a Transfer-Encoding header), do not set the Content-Length header. - * - *

The GET method should be safe, that is, without - * any side effects for which users are held responsible. - * For example, most form queries have no side effects. - * If a client request is intended to change stored data, - * the request should use some other HTTP method. - * - *

The GET method should also be idempotent, meaning - * that it can be safely repeated. Sometimes making a - * method safe also makes it idempotent. For example, - * repeating queries is both safe and idempotent, but - * buying a product online or modifying data is neither - * safe nor idempotent. - * - *

If the request is incorrectly formatted, doGet - * returns an HTTP "Bad Request" message. - * - * - * @param req an {@link HttpServletRequest} object that - * contains the request the client has made - * of the servlet - * - * @param resp an {@link HttpServletResponse} object that - * contains the response the servlet sends - * to the client - * - * @exception IOException if an input or output error is - * detected when the servlet handles - * the GET request - * - * @exception ServletException if the request for the GET - * could not be handled - * - * - * @see javax.servlet.ServletResponse#setContentType - * - */ - - protected void doGet(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - String protocol = req.getProtocol(); - String msg = lStrings.getString("http.method_get_not_supported"); - if (protocol.endsWith("1.1")) { - resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); - } else { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); - } - } - - - - - - /** - * - * Returns the time the HttpServletRequest - * object was last modified, - * in milliseconds since midnight January 1, 1970 GMT. - * If the time is unknown, this method returns a negative - * number (the default). - * - *

Servlets that support HTTP GET requests and can quickly determine - * their last modification time should override this method. - * This makes browser and proxy caches work more effectively, - * reducing the load on server and network resources. - * - * - * @param req the HttpServletRequest - * object that is sent to the servlet - * - * @return a long integer specifying - * the time the HttpServletRequest - * object was last modified, in milliseconds - * since midnight, January 1, 1970 GMT, or - * -1 if the time is not known - * - */ - - protected long getLastModified(HttpServletRequest req) { - return -1; - } - - - - - /** - * - * - *

Receives an HTTP HEAD request from the protected - * service method and handles the - * request. - * The client sends a HEAD request when it wants - * to see only the headers of a response, such as - * Content-Type or Content-Length. The HTTP HEAD - * method counts the output bytes in the response - * to set the Content-Length header accurately. - * - *

If you override this method, you can avoid computing - * the response body and just set the response headers - * directly to improve performance. Make sure that the - * doHead method you write is both safe - * and idempotent (that is, protects itself from being - * called multiple times for one HTTP HEAD request). - * - *

If the HTTP HEAD request is incorrectly formatted, - * doHead returns an HTTP "Bad Request" - * message. - * - * - * @param req the request object that is passed - * to the servlet - * - * @param resp the response object that the servlet - * uses to return the headers to the clien - * - * @exception IOException if an input or output error occurs - * - * @exception ServletException if the request for the HEAD - * could not be handled - */ - - protected void doHead(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - NoBodyResponse response = new NoBodyResponse(resp); - - doGet(req, response); - response.setContentLength(); - } - - - - - - /** - * - * Called by the server (via the service method) - * to allow a servlet to handle a POST request. - * - * The HTTP POST method allows the client to send - * data of unlimited length to the Web server a single time - * and is useful when posting information such as - * credit card numbers. - * - *

When overriding this method, read the request data, - * write the response headers, get the response's writer or output - * stream object, and finally, write the response data. It's best - * to include content type and encoding. When using a - * PrintWriter object to return the response, set the - * content type before accessing the PrintWriter object. - * - *

The servlet container must write the headers before committing the - * response, because in HTTP the headers must be sent before the - * response body. - * - *

Where possible, set the Content-Length header (with the - * {@link javax.servlet.ServletResponse#setContentLength} method), - * to allow the servlet container to use a persistent connection - * to return its response to the client, improving performance. - * The content length is automatically set if the entire response fits - * inside the response buffer. - * - *

When using HTTP 1.1 chunked encoding (which means that the response - * has a Transfer-Encoding header), do not set the Content-Length header. - * - *

This method does not need to be either safe or idempotent. - * Operations requested through POST can have side effects for - * which the user can be held accountable, for example, - * updating stored data or buying items online. - * - *

If the HTTP POST request is incorrectly formatted, - * doPost returns an HTTP "Bad Request" message. - * - * - * @param req an {@link HttpServletRequest} object that - * contains the request the client has made - * of the servlet - * - * @param resp an {@link HttpServletResponse} object that - * contains the response the servlet sends - * to the client - * - * @exception IOException if an input or output error is - * detected when the servlet handles - * the request - * - * @exception ServletException if the request for the POST - * could not be handled - * - * - * @see javax.servlet.ServletOutputStream - * @see javax.servlet.ServletResponse#setContentType - * - * - */ - - protected void doPost(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - String protocol = req.getProtocol(); - String msg = lStrings.getString("http.method_post_not_supported"); - if (protocol.endsWith("1.1")) { - resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); - } else { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); - } - } - - - - - /** - * Called by the server (via the service method) - * to allow a servlet to handle a PUT request. - * - * The PUT operation allows a client to - * place a file on the server and is similar to - * sending a file by FTP. - * - *

When overriding this method, leave intact - * any content headers sent with the request (including - * Content-Length, Content-Type, Content-Transfer-Encoding, - * Content-Encoding, Content-Base, Content-Language, Content-Location, - * Content-MD5, and Content-Range). If your method cannot - * handle a content header, it must issue an error message - * (HTTP 501 - Not Implemented) and discard the request. - * For more information on HTTP 1.1, see RFC 2616 - * . - * - *

This method does not need to be either safe or idempotent. - * Operations that doPut performs can have side - * effects for which the user can be held accountable. When using - * this method, it may be useful to save a copy of the - * affected URL in temporary storage. - * - *

If the HTTP PUT request is incorrectly formatted, - * doPut returns an HTTP "Bad Request" message. - * - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * @param resp the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * PUT request - * - * @exception ServletException if the request for the PUT - * cannot be handled - * - */ - - protected void doPut(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - String protocol = req.getProtocol(); - String msg = lStrings.getString("http.method_put_not_supported"); - if (protocol.endsWith("1.1")) { - resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); - } else { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); - } - } - - - - - /** - * - * Called by the server (via the service method) - * to allow a servlet to handle a DELETE request. - * - * The DELETE operation allows a client to remove a document - * or Web page from the server. - * - *

This method does not need to be either safe - * or idempotent. Operations requested through - * DELETE can have side effects for which users - * can be held accountable. When using - * this method, it may be useful to save a copy of the - * affected URL in temporary storage. - * - *

If the HTTP DELETE request is incorrectly formatted, - * doDelete returns an HTTP "Bad Request" - * message. - * - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * - * @param resp the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * DELETE request - * - * @exception ServletException if the request for the - * DELETE cannot be handled - * - */ - - protected void doDelete(HttpServletRequest req, - HttpServletResponse resp) - throws ServletException, IOException - { - String protocol = req.getProtocol(); - String msg = lStrings.getString("http.method_delete_not_supported"); - if (protocol.endsWith("1.1")) { - resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); - } else { - resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); - } - } - - - private static Method[] getAllDeclaredMethods(Class c) { - - if (c.equals(javax.servlet.http.HttpServlet.class)) { - return null; - } - - Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); - Method[] thisMethods = c.getDeclaredMethods(); - - if ((parentMethods != null) && (parentMethods.length > 0)) { - Method[] allMethods = - new Method[parentMethods.length + thisMethods.length]; - System.arraycopy(parentMethods, 0, allMethods, 0, - parentMethods.length); - System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, - thisMethods.length); - - thisMethods = allMethods; - } - - return thisMethods; - } - - - /** - * Called by the server (via the service method) - * to allow a servlet to handle a OPTIONS request. - * - * The OPTIONS request determines which HTTP methods - * the server supports and - * returns an appropriate header. For example, if a servlet - * overrides doGet, this method returns the - * following header: - * - *

Allow: GET, HEAD, TRACE, OPTIONS - * - *

There's no need to override this method unless the - * servlet implements new HTTP methods, beyond those - * implemented by HTTP 1.1. - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * - * @param resp the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * OPTIONS request - * - * @exception ServletException if the request for the - * OPTIONS cannot be handled - * - */ - - protected void doOptions(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - Method[] methods = getAllDeclaredMethods(this.getClass()); - - boolean ALLOW_GET = false; - boolean ALLOW_HEAD = false; - boolean ALLOW_POST = false; - boolean ALLOW_PUT = false; - boolean ALLOW_DELETE = false; - boolean ALLOW_TRACE = true; - boolean ALLOW_OPTIONS = true; - - for (int i=0; iservice method) - * to allow a servlet to handle a TRACE request. - * - * A TRACE returns the headers sent with the TRACE - * request to the client, so that they can be used in - * debugging. There's no need to override this method. - * - * - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * - * @param resp the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * TRACE request - * - * @exception ServletException if the request for the - * TRACE cannot be handled - * - */ - - protected void doTrace(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - - int responseLength; - - String CRLF = "\r\n"; - String responseString = "TRACE "+ req.getRequestURI()+ - " " + req.getProtocol(); - - Enumeration reqHeaderEnum = req.getHeaderNames(); - - while( reqHeaderEnum.hasMoreElements() ) { - String headerName = (String)reqHeaderEnum.nextElement(); - responseString += CRLF + headerName + ": " + - req.getHeader(headerName); - } - - responseString += CRLF; - - responseLength = responseString.length(); - - resp.setContentType("message/http"); - resp.setContentLength(responseLength); - ServletOutputStream out = resp.getOutputStream(); - out.print(responseString); - out.close(); - return; - } - - - - - - /** - * - * Receives standard HTTP requests from the public - * service method and dispatches - * them to the doXXX methods defined in - * this class. This method is an HTTP-specific version of the - * {@link javax.servlet.Servlet#service} method. There's no - * need to override this method. - * - * - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * - * @param resp the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * HTTP request - * - * @exception ServletException if the HTTP request - * cannot be handled - * - * @see javax.servlet.Servlet#service - * - */ - - protected void service(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException - { - String method = req.getMethod(); - - if (method.equals(METHOD_GET)) { - long lastModified = getLastModified(req); - if (lastModified == -1) { - // servlet doesn't support if-modified-since, no reason - // to go through further expensive logic - doGet(req, resp); - } else { - long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); - if (ifModifiedSince < (lastModified / 1000 * 1000)) { - // If the servlet mod time is later, call doGet() - // Round down to the nearest second for a proper compare - // A ifModifiedSince of -1 will always be less - maybeSetLastModified(resp, lastModified); - doGet(req, resp); - } else { - resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - } - } - - } else if (method.equals(METHOD_HEAD)) { - long lastModified = getLastModified(req); - maybeSetLastModified(resp, lastModified); - doHead(req, resp); - - } else if (method.equals(METHOD_POST)) { - doPost(req, resp); - - } else if (method.equals(METHOD_PUT)) { - doPut(req, resp); - - } else if (method.equals(METHOD_DELETE)) { - doDelete(req, resp); - - } else if (method.equals(METHOD_OPTIONS)) { - doOptions(req,resp); - - } else if (method.equals(METHOD_TRACE)) { - doTrace(req,resp); - - } else { - // - // Note that this means NO servlet supports whatever - // method was requested, anywhere on this server. - // - - String errMsg = lStrings.getString("http.method_not_implemented"); - Object[] errArgs = new Object[1]; - errArgs[0] = method; - errMsg = MessageFormat.format(errMsg, errArgs); - - resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); - } - } - - - - - - /* - * Sets the Last-Modified entity header field, if it has not - * already been set and if the value is meaningful. Called before - * doGet, to ensure that headers are set before response data is - * written. A subclass might have set this header already, so we - * check. - */ - - private void maybeSetLastModified(HttpServletResponse resp, - long lastModified) { - if (resp.containsHeader(HEADER_LASTMOD)) - return; - if (lastModified >= 0) - resp.setDateHeader(HEADER_LASTMOD, lastModified); - } - - - - - /** - * - * Dispatches client requests to the protected - * service method. There's no need to - * override this method. - * - * - * @param req the {@link HttpServletRequest} object that - * contains the request the client made of - * the servlet - * - * - * @param res the {@link HttpServletResponse} object that - * contains the response the servlet returns - * to the client - * - * - * @exception IOException if an input or output error occurs - * while the servlet is handling the - * HTTP request - * - * @exception ServletException if the HTTP request cannot - * be handled - * - * - * @see javax.servlet.Servlet#service - * - */ - - public void service(ServletRequest req, ServletResponse res) - throws ServletException, IOException - { - HttpServletRequest request; - HttpServletResponse response; - - try { - request = (HttpServletRequest) req; - response = (HttpServletResponse) res; - } catch (ClassCastException e) { - throw new ServletException("non-HTTP request or response"); - } - service(request, response); - } -} - - - - -/* - * A response that includes no body, for use in (dumb) "HEAD" support. - * This just swallows that body, counting the bytes in order to set - * the content length appropriately. All other methods delegate directly - * to the HTTP Servlet Response object used to construct this one. - */ -// file private -class NoBodyResponse implements HttpServletResponse { - private HttpServletResponse resp; - private NoBodyOutputStream noBody; - private PrintWriter writer; - private boolean didSetContentLength; - - // file private - NoBodyResponse(HttpServletResponse r) { - resp = r; - noBody = new NoBodyOutputStream(); - } - - // file private - void setContentLength() { - if (!didSetContentLength) - resp.setContentLength(noBody.getContentLength()); - } - - - // SERVLET RESPONSE interface methods - - public void setContentLength(int len) { - resp.setContentLength(len); - didSetContentLength = true; - } - - public void setCharacterEncoding(String charset) - { resp.setCharacterEncoding(charset); } - - public void setContentType(String type) - { resp.setContentType(type); } - - public String getContentType() - { return resp.getContentType(); } - - public ServletOutputStream getOutputStream() throws IOException - { return noBody; } - - public String getCharacterEncoding() - { return resp.getCharacterEncoding(); } - - public PrintWriter getWriter() throws UnsupportedEncodingException - { - if (writer == null) { - OutputStreamWriter w; - - w = new OutputStreamWriter(noBody, getCharacterEncoding()); - writer = new PrintWriter(w); - } - return writer; - } - - public void setBufferSize(int size) throws IllegalStateException - { resp.setBufferSize(size); } - - public int getBufferSize() - { return resp.getBufferSize(); } - - public void reset() throws IllegalStateException - { resp.reset(); } - - public void resetBuffer() throws IllegalStateException - { resp.resetBuffer(); } - - public boolean isCommitted() - { return resp.isCommitted(); } - - public void flushBuffer() throws IOException - { resp.flushBuffer(); } - - public void setLocale(Locale loc) - { resp.setLocale(loc); } - - public Locale getLocale() - { return resp.getLocale(); } - - - // HTTP SERVLET RESPONSE interface methods - - public void addCookie(Cookie cookie) - { resp.addCookie(cookie); } - - public boolean containsHeader(String name) - { return resp.containsHeader(name); } - - /** @deprecated */ - public void setStatus(int sc, String sm) - { resp.setStatus(sc, sm); } - - public void setStatus(int sc) - { resp.setStatus(sc); } - - public void setHeader(String name, String value) - { resp.setHeader(name, value); } - - public void setIntHeader(String name, int value) - { resp.setIntHeader(name, value); } - - public void setDateHeader(String name, long date) - { resp.setDateHeader(name, date); } - - public void sendError(int sc, String msg) throws IOException - { resp.sendError(sc, msg); } - - public void sendError(int sc) throws IOException - { resp.sendError(sc); } - - public void sendRedirect(String location) throws IOException - { resp.sendRedirect(location); } - - public String encodeURL(String url) - { return resp.encodeURL(url); } - - public String encodeRedirectURL(String url) - { return resp.encodeRedirectURL(url); } - - public void addHeader(String name, String value) - { resp.addHeader(name, value); } - - public void addDateHeader(String name, long value) - { resp.addDateHeader(name, value); } - - public void addIntHeader(String name, int value) - { resp.addIntHeader(name, value); } - - - - - /** - * @deprecated As of Version 2.1, replaced by - * {@link HttpServletResponse#encodeURL}. - * - */ - - - public String encodeUrl(String url) - { return this.encodeURL(url); } - - - - - - - - - /** - * @deprecated As of Version 2.1, replaced by - * {@link HttpServletResponse#encodeRedirectURL}. - * - */ - - - public String encodeRedirectUrl(String url) - { return this.encodeRedirectURL(url); } - -} - - - - - - - -/* - * Servlet output stream that gobbles up all its data. - */ - -// file private -class NoBodyOutputStream extends ServletOutputStream { - - private static final String LSTRING_FILE = - "javax.servlet.http.LocalStrings"; - private static ResourceBundle lStrings = - ResourceBundle.getBundle(LSTRING_FILE); - - private int contentLength = 0; - - // file private - NoBodyOutputStream() {} - - // file private - int getContentLength() { - return contentLength; - } - - public void write(int b) { - contentLength++; - } - - public void write(byte buf[], int offset, int len) - throws IOException - { - if (len >= 0) { - contentLength += len; - } else { - // XXX - // isn't this really an IllegalArgumentException? - - String msg = lStrings.getString("err.io.negativelength"); - throw new IOException("negative length"); - } - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Method; +import java.text.MessageFormat; +import java.util.Enumeration; +import java.util.Locale; +import java.util.ResourceBundle; + +import javax.servlet.GenericServlet; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + + +/** + * + * Provides an abstract class to be subclassed to create + * an HTTP servlet suitable for a Web site. A subclass of + * HttpServlet must override at least + * one method, usually one of these: + * + *

    + *
  • doGet, if the servlet supports HTTP GET requests + *
  • doPost, for HTTP POST requests + *
  • doPut, for HTTP PUT requests + *
  • doDelete, for HTTP DELETE requests + *
  • init and destroy, + * to manage resources that are held for the life of the servlet + *
  • getServletInfo, which the servlet uses to + * provide information about itself + *
+ * + *

There's almost no reason to override the service + * method. service handles standard HTTP + * requests by dispatching them to the handler methods + * for each HTTP request type (the doXXX + * methods listed above). + * + *

Likewise, there's almost no reason to override the + * doOptions and doTrace methods. + * + *

Servlets typically run on multithreaded servers, + * so be aware that a servlet must handle concurrent + * requests and be careful to synchronize access to shared resources. + * Shared resources include in-memory data such as + * instance or class variables and external objects + * such as files, database connections, and network + * connections. + * See the + * + * Java Tutorial on Multithreaded Programming for more + * information on handling multiple threads in a Java program. + * + * @author Various + * @version $Version$ + * + */ + + + +public abstract class HttpServlet extends GenericServlet + implements java.io.Serializable +{ + private static final String METHOD_DELETE = "DELETE"; + private static final String METHOD_HEAD = "HEAD"; + private static final String METHOD_GET = "GET"; + private static final String METHOD_OPTIONS = "OPTIONS"; + private static final String METHOD_POST = "POST"; + private static final String METHOD_PUT = "PUT"; + private static final String METHOD_TRACE = "TRACE"; + + private static final String HEADER_IFMODSINCE = "If-Modified-Since"; + private static final String HEADER_LASTMOD = "Last-Modified"; + + private static final String LSTRING_FILE = + "javax.servlet.http.LocalStrings"; + private static ResourceBundle lStrings = + ResourceBundle.getBundle(LSTRING_FILE); + + + + + /** + * Does nothing, because this is an abstract class. + * + */ + + public HttpServlet() { } + + + + /** + * + * Called by the server (via the service method) to + * allow a servlet to handle a GET request. + * + *

Overriding this method to support a GET request also + * automatically supports an HTTP HEAD request. A HEAD + * request is a GET request that returns no body in the + * response, only the request header fields. + * + *

When overriding this method, read the request data, + * write the response headers, get the response's writer or + * output stream object, and finally, write the response data. + * It's best to include content type and encoding. When using + * a PrintWriter object to return the response, + * set the content type before accessing the + * PrintWriter object. + * + *

The servlet container must write the headers before + * committing the response, because in HTTP the headers must be sent + * before the response body. + * + *

Where possible, set the Content-Length header (with the + * {@link javax.servlet.ServletResponse#setContentLength} method), + * to allow the servlet container to use a persistent connection + * to return its response to the client, improving performance. + * The content length is automatically set if the entire response fits + * inside the response buffer. + * + *

When using HTTP 1.1 chunked encoding (which means that the response + * has a Transfer-Encoding header), do not set the Content-Length header. + * + *

The GET method should be safe, that is, without + * any side effects for which users are held responsible. + * For example, most form queries have no side effects. + * If a client request is intended to change stored data, + * the request should use some other HTTP method. + * + *

The GET method should also be idempotent, meaning + * that it can be safely repeated. Sometimes making a + * method safe also makes it idempotent. For example, + * repeating queries is both safe and idempotent, but + * buying a product online or modifying data is neither + * safe nor idempotent. + * + *

If the request is incorrectly formatted, doGet + * returns an HTTP "Bad Request" message. + * + * + * @param req an {@link HttpServletRequest} object that + * contains the request the client has made + * of the servlet + * + * @param resp an {@link HttpServletResponse} object that + * contains the response the servlet sends + * to the client + * + * @exception IOException if an input or output error is + * detected when the servlet handles + * the GET request + * + * @exception ServletException if the request for the GET + * could not be handled + * + * + * @see javax.servlet.ServletResponse#setContentType + * + */ + + protected void doGet(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String protocol = req.getProtocol(); + String msg = lStrings.getString("http.method_get_not_supported"); + if (protocol.endsWith("1.1")) { + resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); + } else { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); + } + } + + + + + + /** + * + * Returns the time the HttpServletRequest + * object was last modified, + * in milliseconds since midnight January 1, 1970 GMT. + * If the time is unknown, this method returns a negative + * number (the default). + * + *

Servlets that support HTTP GET requests and can quickly determine + * their last modification time should override this method. + * This makes browser and proxy caches work more effectively, + * reducing the load on server and network resources. + * + * + * @param req the HttpServletRequest + * object that is sent to the servlet + * + * @return a long integer specifying + * the time the HttpServletRequest + * object was last modified, in milliseconds + * since midnight, January 1, 1970 GMT, or + * -1 if the time is not known + * + */ + + protected long getLastModified(HttpServletRequest req) { + return -1; + } + + + + + /** + * + * + *

Receives an HTTP HEAD request from the protected + * service method and handles the + * request. + * The client sends a HEAD request when it wants + * to see only the headers of a response, such as + * Content-Type or Content-Length. The HTTP HEAD + * method counts the output bytes in the response + * to set the Content-Length header accurately. + * + *

If you override this method, you can avoid computing + * the response body and just set the response headers + * directly to improve performance. Make sure that the + * doHead method you write is both safe + * and idempotent (that is, protects itself from being + * called multiple times for one HTTP HEAD request). + * + *

If the HTTP HEAD request is incorrectly formatted, + * doHead returns an HTTP "Bad Request" + * message. + * + * + * @param req the request object that is passed + * to the servlet + * + * @param resp the response object that the servlet + * uses to return the headers to the clien + * + * @exception IOException if an input or output error occurs + * + * @exception ServletException if the request for the HEAD + * could not be handled + */ + + protected void doHead(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + NoBodyResponse response = new NoBodyResponse(resp); + + doGet(req, response); + response.setContentLength(); + } + + + + + + /** + * + * Called by the server (via the service method) + * to allow a servlet to handle a POST request. + * + * The HTTP POST method allows the client to send + * data of unlimited length to the Web server a single time + * and is useful when posting information such as + * credit card numbers. + * + *

When overriding this method, read the request data, + * write the response headers, get the response's writer or output + * stream object, and finally, write the response data. It's best + * to include content type and encoding. When using a + * PrintWriter object to return the response, set the + * content type before accessing the PrintWriter object. + * + *

The servlet container must write the headers before committing the + * response, because in HTTP the headers must be sent before the + * response body. + * + *

Where possible, set the Content-Length header (with the + * {@link javax.servlet.ServletResponse#setContentLength} method), + * to allow the servlet container to use a persistent connection + * to return its response to the client, improving performance. + * The content length is automatically set if the entire response fits + * inside the response buffer. + * + *

When using HTTP 1.1 chunked encoding (which means that the response + * has a Transfer-Encoding header), do not set the Content-Length header. + * + *

This method does not need to be either safe or idempotent. + * Operations requested through POST can have side effects for + * which the user can be held accountable, for example, + * updating stored data or buying items online. + * + *

If the HTTP POST request is incorrectly formatted, + * doPost returns an HTTP "Bad Request" message. + * + * + * @param req an {@link HttpServletRequest} object that + * contains the request the client has made + * of the servlet + * + * @param resp an {@link HttpServletResponse} object that + * contains the response the servlet sends + * to the client + * + * @exception IOException if an input or output error is + * detected when the servlet handles + * the request + * + * @exception ServletException if the request for the POST + * could not be handled + * + * + * @see javax.servlet.ServletOutputStream + * @see javax.servlet.ServletResponse#setContentType + * + * + */ + + protected void doPost(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String protocol = req.getProtocol(); + String msg = lStrings.getString("http.method_post_not_supported"); + if (protocol.endsWith("1.1")) { + resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); + } else { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); + } + } + + + + + /** + * Called by the server (via the service method) + * to allow a servlet to handle a PUT request. + * + * The PUT operation allows a client to + * place a file on the server and is similar to + * sending a file by FTP. + * + *

When overriding this method, leave intact + * any content headers sent with the request (including + * Content-Length, Content-Type, Content-Transfer-Encoding, + * Content-Encoding, Content-Base, Content-Language, Content-Location, + * Content-MD5, and Content-Range). If your method cannot + * handle a content header, it must issue an error message + * (HTTP 501 - Not Implemented) and discard the request. + * For more information on HTTP 1.1, see RFC 2616 + * . + * + *

This method does not need to be either safe or idempotent. + * Operations that doPut performs can have side + * effects for which the user can be held accountable. When using + * this method, it may be useful to save a copy of the + * affected URL in temporary storage. + * + *

If the HTTP PUT request is incorrectly formatted, + * doPut returns an HTTP "Bad Request" message. + * + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * @param resp the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * PUT request + * + * @exception ServletException if the request for the PUT + * cannot be handled + * + */ + + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String protocol = req.getProtocol(); + String msg = lStrings.getString("http.method_put_not_supported"); + if (protocol.endsWith("1.1")) { + resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); + } else { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); + } + } + + + + + /** + * + * Called by the server (via the service method) + * to allow a servlet to handle a DELETE request. + * + * The DELETE operation allows a client to remove a document + * or Web page from the server. + * + *

This method does not need to be either safe + * or idempotent. Operations requested through + * DELETE can have side effects for which users + * can be held accountable. When using + * this method, it may be useful to save a copy of the + * affected URL in temporary storage. + * + *

If the HTTP DELETE request is incorrectly formatted, + * doDelete returns an HTTP "Bad Request" + * message. + * + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * + * @param resp the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * DELETE request + * + * @exception ServletException if the request for the + * DELETE cannot be handled + * + */ + + protected void doDelete(HttpServletRequest req, + HttpServletResponse resp) + throws ServletException, IOException + { + String protocol = req.getProtocol(); + String msg = lStrings.getString("http.method_delete_not_supported"); + if (protocol.endsWith("1.1")) { + resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg); + } else { + resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg); + } + } + + + private static Method[] getAllDeclaredMethods(Class c) { + + if (c.equals(javax.servlet.http.HttpServlet.class)) { + return null; + } + + Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); + Method[] thisMethods = c.getDeclaredMethods(); + + if ((parentMethods != null) && (parentMethods.length > 0)) { + Method[] allMethods = + new Method[parentMethods.length + thisMethods.length]; + System.arraycopy(parentMethods, 0, allMethods, 0, + parentMethods.length); + System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, + thisMethods.length); + + thisMethods = allMethods; + } + + return thisMethods; + } + + + /** + * Called by the server (via the service method) + * to allow a servlet to handle a OPTIONS request. + * + * The OPTIONS request determines which HTTP methods + * the server supports and + * returns an appropriate header. For example, if a servlet + * overrides doGet, this method returns the + * following header: + * + *

Allow: GET, HEAD, TRACE, OPTIONS + * + *

There's no need to override this method unless the + * servlet implements new HTTP methods, beyond those + * implemented by HTTP 1.1. + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * + * @param resp the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * OPTIONS request + * + * @exception ServletException if the request for the + * OPTIONS cannot be handled + * + */ + + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + Method[] methods = getAllDeclaredMethods(this.getClass()); + + boolean ALLOW_GET = false; + boolean ALLOW_HEAD = false; + boolean ALLOW_POST = false; + boolean ALLOW_PUT = false; + boolean ALLOW_DELETE = false; + boolean ALLOW_TRACE = true; + boolean ALLOW_OPTIONS = true; + + for (int i=0; iservice method) + * to allow a servlet to handle a TRACE request. + * + * A TRACE returns the headers sent with the TRACE + * request to the client, so that they can be used in + * debugging. There's no need to override this method. + * + * + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * + * @param resp the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * TRACE request + * + * @exception ServletException if the request for the + * TRACE cannot be handled + * + */ + + protected void doTrace(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + + int responseLength; + + String CRLF = "\r\n"; + String responseString = "TRACE "+ req.getRequestURI()+ + " " + req.getProtocol(); + + Enumeration reqHeaderEnum = req.getHeaderNames(); + + while( reqHeaderEnum.hasMoreElements() ) { + String headerName = (String)reqHeaderEnum.nextElement(); + responseString += CRLF + headerName + ": " + + req.getHeader(headerName); + } + + responseString += CRLF; + + responseLength = responseString.length(); + + resp.setContentType("message/http"); + resp.setContentLength(responseLength); + ServletOutputStream out = resp.getOutputStream(); + out.print(responseString); + out.close(); + return; + } + + + + + + /** + * + * Receives standard HTTP requests from the public + * service method and dispatches + * them to the doXXX methods defined in + * this class. This method is an HTTP-specific version of the + * {@link javax.servlet.Servlet#service} method. There's no + * need to override this method. + * + * + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * + * @param resp the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * HTTP request + * + * @exception ServletException if the HTTP request + * cannot be handled + * + * @see javax.servlet.Servlet#service + * + */ + + protected void service(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException + { + String method = req.getMethod(); + + if (method.equals(METHOD_GET)) { + long lastModified = getLastModified(req); + if (lastModified == -1) { + // servlet doesn't support if-modified-since, no reason + // to go through further expensive logic + doGet(req, resp); + } else { + long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE); + if (ifModifiedSince < (lastModified / 1000 * 1000)) { + // If the servlet mod time is later, call doGet() + // Round down to the nearest second for a proper compare + // A ifModifiedSince of -1 will always be less + maybeSetLastModified(resp, lastModified); + doGet(req, resp); + } else { + resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + } + } + + } else if (method.equals(METHOD_HEAD)) { + long lastModified = getLastModified(req); + maybeSetLastModified(resp, lastModified); + doHead(req, resp); + + } else if (method.equals(METHOD_POST)) { + doPost(req, resp); + + } else if (method.equals(METHOD_PUT)) { + doPut(req, resp); + + } else if (method.equals(METHOD_DELETE)) { + doDelete(req, resp); + + } else if (method.equals(METHOD_OPTIONS)) { + doOptions(req,resp); + + } else if (method.equals(METHOD_TRACE)) { + doTrace(req,resp); + + } else { + // + // Note that this means NO servlet supports whatever + // method was requested, anywhere on this server. + // + + String errMsg = lStrings.getString("http.method_not_implemented"); + Object[] errArgs = new Object[1]; + errArgs[0] = method; + errMsg = MessageFormat.format(errMsg, errArgs); + + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg); + } + } + + + + + + /* + * Sets the Last-Modified entity header field, if it has not + * already been set and if the value is meaningful. Called before + * doGet, to ensure that headers are set before response data is + * written. A subclass might have set this header already, so we + * check. + */ + + private void maybeSetLastModified(HttpServletResponse resp, + long lastModified) { + if (resp.containsHeader(HEADER_LASTMOD)) + return; + if (lastModified >= 0) + resp.setDateHeader(HEADER_LASTMOD, lastModified); + } + + + + + /** + * + * Dispatches client requests to the protected + * service method. There's no need to + * override this method. + * + * + * @param req the {@link HttpServletRequest} object that + * contains the request the client made of + * the servlet + * + * + * @param res the {@link HttpServletResponse} object that + * contains the response the servlet returns + * to the client + * + * + * @exception IOException if an input or output error occurs + * while the servlet is handling the + * HTTP request + * + * @exception ServletException if the HTTP request cannot + * be handled + * + * + * @see javax.servlet.Servlet#service + * + */ + + public void service(ServletRequest req, ServletResponse res) + throws ServletException, IOException + { + HttpServletRequest request; + HttpServletResponse response; + + try { + request = (HttpServletRequest) req; + response = (HttpServletResponse) res; + } catch (ClassCastException e) { + throw new ServletException("non-HTTP request or response"); + } + service(request, response); + } +} + + + + +/* + * A response that includes no body, for use in (dumb) "HEAD" support. + * This just swallows that body, counting the bytes in order to set + * the content length appropriately. All other methods delegate directly + * to the HTTP Servlet Response object used to construct this one. + */ +// file private +class NoBodyResponse implements HttpServletResponse { + private HttpServletResponse resp; + private NoBodyOutputStream noBody; + private PrintWriter writer; + private boolean didSetContentLength; + + // file private + NoBodyResponse(HttpServletResponse r) { + resp = r; + noBody = new NoBodyOutputStream(); + } + + // file private + void setContentLength() { + if (!didSetContentLength) + resp.setContentLength(noBody.getContentLength()); + } + + + // SERVLET RESPONSE interface methods + + public void setContentLength(int len) { + resp.setContentLength(len); + didSetContentLength = true; + } + + public void setCharacterEncoding(String charset) + { resp.setCharacterEncoding(charset); } + + public void setContentType(String type) + { resp.setContentType(type); } + + public String getContentType() + { return resp.getContentType(); } + + public ServletOutputStream getOutputStream() throws IOException + { return noBody; } + + public String getCharacterEncoding() + { return resp.getCharacterEncoding(); } + + public PrintWriter getWriter() throws UnsupportedEncodingException + { + if (writer == null) { + OutputStreamWriter w; + + w = new OutputStreamWriter(noBody, getCharacterEncoding()); + writer = new PrintWriter(w); + } + return writer; + } + + public void setBufferSize(int size) throws IllegalStateException + { resp.setBufferSize(size); } + + public int getBufferSize() + { return resp.getBufferSize(); } + + public void reset() throws IllegalStateException + { resp.reset(); } + + public void resetBuffer() throws IllegalStateException + { resp.resetBuffer(); } + + public boolean isCommitted() + { return resp.isCommitted(); } + + public void flushBuffer() throws IOException + { resp.flushBuffer(); } + + public void setLocale(Locale loc) + { resp.setLocale(loc); } + + public Locale getLocale() + { return resp.getLocale(); } + + + // HTTP SERVLET RESPONSE interface methods + + public void addCookie(Cookie cookie) + { resp.addCookie(cookie); } + + public boolean containsHeader(String name) + { return resp.containsHeader(name); } + + /** @deprecated */ + public void setStatus(int sc, String sm) + { resp.setStatus(sc, sm); } + + public void setStatus(int sc) + { resp.setStatus(sc); } + + public void setHeader(String name, String value) + { resp.setHeader(name, value); } + + public void setIntHeader(String name, int value) + { resp.setIntHeader(name, value); } + + public void setDateHeader(String name, long date) + { resp.setDateHeader(name, date); } + + public void sendError(int sc, String msg) throws IOException + { resp.sendError(sc, msg); } + + public void sendError(int sc) throws IOException + { resp.sendError(sc); } + + public void sendRedirect(String location) throws IOException + { resp.sendRedirect(location); } + + public String encodeURL(String url) + { return resp.encodeURL(url); } + + public String encodeRedirectURL(String url) + { return resp.encodeRedirectURL(url); } + + public void addHeader(String name, String value) + { resp.addHeader(name, value); } + + public void addDateHeader(String name, long value) + { resp.addDateHeader(name, value); } + + public void addIntHeader(String name, int value) + { resp.addIntHeader(name, value); } + + + + + /** + * @deprecated As of Version 2.1, replaced by + * {@link HttpServletResponse#encodeURL}. + * + */ + + + public String encodeUrl(String url) + { return this.encodeURL(url); } + + + + + + + + + /** + * @deprecated As of Version 2.1, replaced by + * {@link HttpServletResponse#encodeRedirectURL}. + * + */ + + + public String encodeRedirectUrl(String url) + { return this.encodeRedirectURL(url); } + +} + + + + + + + +/* + * Servlet output stream that gobbles up all its data. + */ + +// file private +class NoBodyOutputStream extends ServletOutputStream { + + private static final String LSTRING_FILE = + "javax.servlet.http.LocalStrings"; + private static ResourceBundle lStrings = + ResourceBundle.getBundle(LSTRING_FILE); + + private int contentLength = 0; + + // file private + NoBodyOutputStream() {} + + // file private + int getContentLength() { + return contentLength; + } + + public void write(int b) { + contentLength++; + } + + public void write(byte buf[], int offset, int len) + throws IOException + { + if (len >= 0) { + contentLength += len; + } else { + // XXX + // isn't this really an IllegalArgumentException? + + String msg = lStrings.getString("err.io.negativelength"); + throw new IOException("negative length"); + } + } +} diff --git a/java/javax/servlet/http/HttpServletRequest.java b/java/javax/servlet/http/HttpServletRequest.java index 7d3a7ecde..c0a5d36ee 100644 --- a/java/javax/servlet/http/HttpServletRequest.java +++ b/java/javax/servlet/http/HttpServletRequest.java @@ -1,660 +1,660 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.http; - -import javax.servlet.ServletRequest; -import java.util.Enumeration; - -/** - * - * Extends the {@link javax.servlet.ServletRequest} interface - * to provide request information for HTTP servlets. - * - *

The servlet container creates an HttpServletRequest - * object and passes it as an argument to the servlet's service - * methods (doGet, doPost, etc). - * - * - * @author Various - * @version $Version$ - * - * - */ - -public interface HttpServletRequest extends ServletRequest { - - /** - * String identifier for Basic authentication. Value "BASIC" - */ - public static final String BASIC_AUTH = "BASIC"; - /** - * String identifier for Form authentication. Value "FORM" - */ - public static final String FORM_AUTH = "FORM"; - /** - * String identifier for Client Certificate authentication. Value "CLIENT_CERT" - */ - public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; - /** - * String identifier for Digest authentication. Value "DIGEST" - */ - public static final String DIGEST_AUTH = "DIGEST"; - - /** - * Returns the name of the authentication scheme used to protect - * the servlet. All servlet containers support basic, form and client - * certificate authentication, and may additionally support digest - * authentication. - * If the servlet is not authenticated null is returned. - * - *

Same as the value of the CGI variable AUTH_TYPE. - * - * - * @return one of the static members BASIC_AUTH, - * FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH - * (suitable for == comparison) or - * the container-specific string indicating - * the authentication scheme, or - * null if the request was - * not authenticated. - * - */ - - public String getAuthType(); - - - - - /** - * - * Returns an array containing all of the Cookie - * objects the client sent with this request. - * This method returns null if no cookies were sent. - * - * @return an array of all the Cookies - * included with this request, or null - * if the request has no cookies - * - * - */ - - public Cookie[] getCookies(); - - - - - /** - * - * Returns the value of the specified request header - * as a long value that represents a - * Date object. Use this method with - * headers that contain dates, such as - * If-Modified-Since. - * - *

The date is returned as - * the number of milliseconds since January 1, 1970 GMT. - * The header name is case insensitive. - * - *

If the request did not have a header of the - * specified name, this method returns -1. If the header - * can't be converted to a date, the method throws - * an IllegalArgumentException. - * - * @param name a String specifying the - * name of the header - * - * @return a long value - * representing the date specified - * in the header expressed as - * the number of milliseconds - * since January 1, 1970 GMT, - * or -1 if the named header - * was not included with the - * request - * - * @exception IllegalArgumentException If the header value - * can't be converted - * to a date - * - */ - - public long getDateHeader(String name); - - - - - /** - * - * Returns the value of the specified request header - * as a String. If the request did not include a header - * of the specified name, this method returns null. - * If there are multiple headers with the same name, this method - * returns the first head in the request. - * The header name is case insensitive. You can use - * this method with any request header. - * - * @param name a String specifying the - * header name - * - * @return a String containing the - * value of the requested - * header, or null - * if the request does not - * have a header of that name - * - */ - - public String getHeader(String name); - - - - - /** - * - * Returns all the values of the specified request header - * as an Enumeration of String objects. - * - *

Some headers, such as Accept-Language can be sent - * by clients as several headers each with a different value rather than - * sending the header as a comma separated list. - * - *

If the request did not include any headers - * of the specified name, this method returns an empty - * Enumeration. - * The header name is case insensitive. You can use - * this method with any request header. - * - * @param name a String specifying the - * header name - * - * @return an Enumeration containing - * the values of the requested header. If - * the request does not have any headers of - * that name return an empty - * enumeration. If - * the container does not allow access to - * header information, return null - * - */ - - public Enumeration getHeaders(String name); - - - - - - /** - * - * Returns an enumeration of all the header names - * this request contains. If the request has no - * headers, this method returns an empty enumeration. - * - *

Some servlet containers do not allow - * servlets to access headers using this method, in - * which case this method returns null - * - * @return an enumeration of all the - * header names sent with this - * request; if the request has - * no headers, an empty enumeration; - * if the servlet container does not - * allow servlets to use this method, - * null - * - * - */ - - public Enumeration getHeaderNames(); - - - - - /** - * - * Returns the value of the specified request header - * as an int. If the request does not have a header - * of the specified name, this method returns -1. If the - * header cannot be converted to an integer, this method - * throws a NumberFormatException. - * - *

The header name is case insensitive. - * - * @param name a String specifying the name - * of a request header - * - * @return an integer expressing the value - * of the request header or -1 - * if the request doesn't have a - * header of this name - * - * @exception NumberFormatException If the header value - * can't be converted - * to an int - */ - - public int getIntHeader(String name); - - - - - /** - * - * Returns the name of the HTTP method with which this - * request was made, for example, GET, POST, or PUT. - * Same as the value of the CGI variable REQUEST_METHOD. - * - * @return a String - * specifying the name - * of the method with which - * this request was made - * - */ - - public String getMethod(); - - - - - /** - * - * Returns any extra path information associated with - * the URL the client sent when it made this request. - * The extra path information follows the servlet path - * but precedes the query string and will start with - * a "/" character. - * - *

This method returns null if there - * was no extra path information. - * - *

Same as the value of the CGI variable PATH_INFO. - * - * - * @return a String, decoded by the - * web container, specifying - * extra path information that comes - * after the servlet path but before - * the query string in the request URL; - * or null if the URL does not have - * any extra path information - * - */ - - public String getPathInfo(); - - - - - /** - * - * Returns any extra path information after the servlet name - * but before the query string, and translates it to a real - * path. Same as the value of the CGI variable PATH_TRANSLATED. - * - *

If the URL does not have any extra path information, - * this method returns null or the servlet container - * cannot translate the virtual path to a real path for any reason - * (such as when the web application is executed from an archive). - * - * The web container does not decode this string. - * - * - * @return a String specifying the - * real path, or null if - * the URL does not have any extra path - * information - * - * - */ - - public String getPathTranslated(); - - - - - /** - * - * Returns the portion of the request URI that indicates the context - * of the request. The context path always comes first in a request - * URI. The path starts with a "/" character but does not end with a "/" - * character. For servlets in the default (root) context, this method - * returns "". The container does not decode this string. - * - * - * @return a String specifying the - * portion of the request URI that indicates the context - * of the request - * - * - */ - - public String getContextPath(); - - - - - /** - * - * Returns the query string that is contained in the request - * URL after the path. This method returns null - * if the URL does not have a query string. Same as the value - * of the CGI variable QUERY_STRING. - * - * @return a String containing the query - * string or null if the URL - * contains no query string. The value is not - * decoded by the container. - * - */ - - public String getQueryString(); - - - - - /** - * - * Returns the login of the user making this request, if the - * user has been authenticated, or null if the user - * has not been authenticated. - * Whether the user name is sent with each subsequent request - * depends on the browser and type of authentication. Same as the - * value of the CGI variable REMOTE_USER. - * - * @return a String specifying the login - * of the user making this request, or null - * if the user login is not known - * - */ - - public String getRemoteUser(); - - - - - /** - * - * Returns a boolean indicating whether the authenticated user is included - * in the specified logical "role". Roles and role membership can be - * defined using deployment descriptors. If the user has not been - * authenticated, the method returns false. - * - * @param role a String specifying the name - * of the role - * - * @return a boolean indicating whether - * the user making this request belongs to a given role; - * false if the user has not been - * authenticated - * - */ - - public boolean isUserInRole(String role); - - - - - /** - * - * Returns a java.security.Principal object containing - * the name of the current authenticated user. If the user has not been - * authenticated, the method returns null. - * - * @return a java.security.Principal containing - * the name of the user making this request; - * null if the user has not been - * authenticated - * - */ - - public java.security.Principal getUserPrincipal(); - - - - - /** - * - * Returns the session ID specified by the client. This may - * not be the same as the ID of the current valid session - * for this request. - * If the client did not specify a session ID, this method returns - * null. - * - * - * @return a String specifying the session - * ID, or null if the request did - * not specify a session ID - * - * @see #isRequestedSessionIdValid - * - */ - - public String getRequestedSessionId(); - - - - - /** - * - * Returns the part of this request's URL from the protocol - * name up to the query string in the first line of the HTTP request. - * The web container does not decode this String. - * For example: - * - * - - * - * - * - *
First line of HTTP request Returned Value
POST /some/path.html HTTP/1.1/some/path.html - *
GET http://foo.bar/a.html HTTP/1.0 - * /a.html - *
HEAD /xyz?a=b HTTP/1.1/xyz - *
- * - *

To reconstruct an URL with a scheme and host, use - * {@link HttpUtils#getRequestURL}. - * - * @return a String containing - * the part of the URL from the - * protocol name up to the query string - * - * @see HttpUtils#getRequestURL - * - */ - - public String getRequestURI(); - - /** - * - * Reconstructs the URL the client used to make the request. - * The returned URL contains a protocol, server name, port - * number, and server path, but it does not include query - * string parameters. - * - *

Because this method returns a StringBuffer, - * not a string, you can modify the URL easily, for example, - * to append query parameters. - * - *

This method is useful for creating redirect messages - * and for reporting errors. - * - * @return a StringBuffer object containing - * the reconstructed URL - * - */ - public StringBuffer getRequestURL(); - - - /** - * - * Returns the part of this request's URL that calls - * the servlet. This path starts with a "/" character - * and includes either the servlet name or a path to - * the servlet, but does not include any extra path - * information or a query string. Same as the value of - * the CGI variable SCRIPT_NAME. - * - *

This method will return an empty string ("") if the - * servlet used to process this request was matched using - * the "/*" pattern. - * - * @return a String containing - * the name or path of the servlet being - * called, as specified in the request URL, - * decoded, or an empty string if the servlet - * used to process the request is matched - * using the "/*" pattern. - * - */ - - public String getServletPath(); - - - - - /** - * - * Returns the current HttpSession - * associated with this request or, if there is no - * current session and create is true, returns - * a new session. - * - *

If create is false - * and the request has no valid HttpSession, - * this method returns null. - * - *

To make sure the session is properly maintained, - * you must call this method before - * the response is committed. If the container is using cookies - * to maintain session integrity and is asked to create a new session - * when the response is committed, an IllegalStateException is thrown. - * - * - * - * - * @param create true to create - * a new session for this request if necessary; - * false to return null - * if there's no current session - * - * - * @return the HttpSession associated - * with this request or null if - * create is false - * and the request has no valid session - * - * @see #getSession() - * - * - */ - - public HttpSession getSession(boolean create); - - - - - - /** - * - * Returns the current session associated with this request, - * or if the request does not have a session, creates one. - * - * @return the HttpSession associated - * with this request - * - * @see #getSession(boolean) - * - */ - - public HttpSession getSession(); - - - - - - - /** - * - * Checks whether the requested session ID is still valid. - * - * @return true if this - * request has an id for a valid session - * in the current session context; - * false otherwise - * - * @see #getRequestedSessionId - * @see #getSession - * @see HttpSessionContext - * - */ - - public boolean isRequestedSessionIdValid(); - - - - - /** - * - * Checks whether the requested session ID came in as a cookie. - * - * @return true if the session ID - * came in as a - * cookie; otherwise, false - * - * - * @see #getSession - * - */ - - public boolean isRequestedSessionIdFromCookie(); - - - - - /** - * - * Checks whether the requested session ID came in as part of the - * request URL. - * - * @return true if the session ID - * came in as part of a URL; otherwise, - * false - * - * - * @see #getSession - * - */ - - public boolean isRequestedSessionIdFromURL(); - - - - - - /** - * - * @deprecated As of Version 2.1 of the Java Servlet - * API, use {@link #isRequestedSessionIdFromURL} - * instead. - * - */ - - public boolean isRequestedSessionIdFromUrl(); - - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.http; + +import javax.servlet.ServletRequest; +import java.util.Enumeration; + +/** + * + * Extends the {@link javax.servlet.ServletRequest} interface + * to provide request information for HTTP servlets. + * + *

The servlet container creates an HttpServletRequest + * object and passes it as an argument to the servlet's service + * methods (doGet, doPost, etc). + * + * + * @author Various + * @version $Version$ + * + * + */ + +public interface HttpServletRequest extends ServletRequest { + + /** + * String identifier for Basic authentication. Value "BASIC" + */ + public static final String BASIC_AUTH = "BASIC"; + /** + * String identifier for Form authentication. Value "FORM" + */ + public static final String FORM_AUTH = "FORM"; + /** + * String identifier for Client Certificate authentication. Value "CLIENT_CERT" + */ + public static final String CLIENT_CERT_AUTH = "CLIENT_CERT"; + /** + * String identifier for Digest authentication. Value "DIGEST" + */ + public static final String DIGEST_AUTH = "DIGEST"; + + /** + * Returns the name of the authentication scheme used to protect + * the servlet. All servlet containers support basic, form and client + * certificate authentication, and may additionally support digest + * authentication. + * If the servlet is not authenticated null is returned. + * + *

Same as the value of the CGI variable AUTH_TYPE. + * + * + * @return one of the static members BASIC_AUTH, + * FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH + * (suitable for == comparison) or + * the container-specific string indicating + * the authentication scheme, or + * null if the request was + * not authenticated. + * + */ + + public String getAuthType(); + + + + + /** + * + * Returns an array containing all of the Cookie + * objects the client sent with this request. + * This method returns null if no cookies were sent. + * + * @return an array of all the Cookies + * included with this request, or null + * if the request has no cookies + * + * + */ + + public Cookie[] getCookies(); + + + + + /** + * + * Returns the value of the specified request header + * as a long value that represents a + * Date object. Use this method with + * headers that contain dates, such as + * If-Modified-Since. + * + *

The date is returned as + * the number of milliseconds since January 1, 1970 GMT. + * The header name is case insensitive. + * + *

If the request did not have a header of the + * specified name, this method returns -1. If the header + * can't be converted to a date, the method throws + * an IllegalArgumentException. + * + * @param name a String specifying the + * name of the header + * + * @return a long value + * representing the date specified + * in the header expressed as + * the number of milliseconds + * since January 1, 1970 GMT, + * or -1 if the named header + * was not included with the + * request + * + * @exception IllegalArgumentException If the header value + * can't be converted + * to a date + * + */ + + public long getDateHeader(String name); + + + + + /** + * + * Returns the value of the specified request header + * as a String. If the request did not include a header + * of the specified name, this method returns null. + * If there are multiple headers with the same name, this method + * returns the first head in the request. + * The header name is case insensitive. You can use + * this method with any request header. + * + * @param name a String specifying the + * header name + * + * @return a String containing the + * value of the requested + * header, or null + * if the request does not + * have a header of that name + * + */ + + public String getHeader(String name); + + + + + /** + * + * Returns all the values of the specified request header + * as an Enumeration of String objects. + * + *

Some headers, such as Accept-Language can be sent + * by clients as several headers each with a different value rather than + * sending the header as a comma separated list. + * + *

If the request did not include any headers + * of the specified name, this method returns an empty + * Enumeration. + * The header name is case insensitive. You can use + * this method with any request header. + * + * @param name a String specifying the + * header name + * + * @return an Enumeration containing + * the values of the requested header. If + * the request does not have any headers of + * that name return an empty + * enumeration. If + * the container does not allow access to + * header information, return null + * + */ + + public Enumeration getHeaders(String name); + + + + + + /** + * + * Returns an enumeration of all the header names + * this request contains. If the request has no + * headers, this method returns an empty enumeration. + * + *

Some servlet containers do not allow + * servlets to access headers using this method, in + * which case this method returns null + * + * @return an enumeration of all the + * header names sent with this + * request; if the request has + * no headers, an empty enumeration; + * if the servlet container does not + * allow servlets to use this method, + * null + * + * + */ + + public Enumeration getHeaderNames(); + + + + + /** + * + * Returns the value of the specified request header + * as an int. If the request does not have a header + * of the specified name, this method returns -1. If the + * header cannot be converted to an integer, this method + * throws a NumberFormatException. + * + *

The header name is case insensitive. + * + * @param name a String specifying the name + * of a request header + * + * @return an integer expressing the value + * of the request header or -1 + * if the request doesn't have a + * header of this name + * + * @exception NumberFormatException If the header value + * can't be converted + * to an int + */ + + public int getIntHeader(String name); + + + + + /** + * + * Returns the name of the HTTP method with which this + * request was made, for example, GET, POST, or PUT. + * Same as the value of the CGI variable REQUEST_METHOD. + * + * @return a String + * specifying the name + * of the method with which + * this request was made + * + */ + + public String getMethod(); + + + + + /** + * + * Returns any extra path information associated with + * the URL the client sent when it made this request. + * The extra path information follows the servlet path + * but precedes the query string and will start with + * a "/" character. + * + *

This method returns null if there + * was no extra path information. + * + *

Same as the value of the CGI variable PATH_INFO. + * + * + * @return a String, decoded by the + * web container, specifying + * extra path information that comes + * after the servlet path but before + * the query string in the request URL; + * or null if the URL does not have + * any extra path information + * + */ + + public String getPathInfo(); + + + + + /** + * + * Returns any extra path information after the servlet name + * but before the query string, and translates it to a real + * path. Same as the value of the CGI variable PATH_TRANSLATED. + * + *

If the URL does not have any extra path information, + * this method returns null or the servlet container + * cannot translate the virtual path to a real path for any reason + * (such as when the web application is executed from an archive). + * + * The web container does not decode this string. + * + * + * @return a String specifying the + * real path, or null if + * the URL does not have any extra path + * information + * + * + */ + + public String getPathTranslated(); + + + + + /** + * + * Returns the portion of the request URI that indicates the context + * of the request. The context path always comes first in a request + * URI. The path starts with a "/" character but does not end with a "/" + * character. For servlets in the default (root) context, this method + * returns "". The container does not decode this string. + * + * + * @return a String specifying the + * portion of the request URI that indicates the context + * of the request + * + * + */ + + public String getContextPath(); + + + + + /** + * + * Returns the query string that is contained in the request + * URL after the path. This method returns null + * if the URL does not have a query string. Same as the value + * of the CGI variable QUERY_STRING. + * + * @return a String containing the query + * string or null if the URL + * contains no query string. The value is not + * decoded by the container. + * + */ + + public String getQueryString(); + + + + + /** + * + * Returns the login of the user making this request, if the + * user has been authenticated, or null if the user + * has not been authenticated. + * Whether the user name is sent with each subsequent request + * depends on the browser and type of authentication. Same as the + * value of the CGI variable REMOTE_USER. + * + * @return a String specifying the login + * of the user making this request, or null + * if the user login is not known + * + */ + + public String getRemoteUser(); + + + + + /** + * + * Returns a boolean indicating whether the authenticated user is included + * in the specified logical "role". Roles and role membership can be + * defined using deployment descriptors. If the user has not been + * authenticated, the method returns false. + * + * @param role a String specifying the name + * of the role + * + * @return a boolean indicating whether + * the user making this request belongs to a given role; + * false if the user has not been + * authenticated + * + */ + + public boolean isUserInRole(String role); + + + + + /** + * + * Returns a java.security.Principal object containing + * the name of the current authenticated user. If the user has not been + * authenticated, the method returns null. + * + * @return a java.security.Principal containing + * the name of the user making this request; + * null if the user has not been + * authenticated + * + */ + + public java.security.Principal getUserPrincipal(); + + + + + /** + * + * Returns the session ID specified by the client. This may + * not be the same as the ID of the current valid session + * for this request. + * If the client did not specify a session ID, this method returns + * null. + * + * + * @return a String specifying the session + * ID, or null if the request did + * not specify a session ID + * + * @see #isRequestedSessionIdValid + * + */ + + public String getRequestedSessionId(); + + + + + /** + * + * Returns the part of this request's URL from the protocol + * name up to the query string in the first line of the HTTP request. + * The web container does not decode this String. + * For example: + * + * + + * + * + * + *
First line of HTTP request Returned Value
POST /some/path.html HTTP/1.1/some/path.html + *
GET http://foo.bar/a.html HTTP/1.0 + * /a.html + *
HEAD /xyz?a=b HTTP/1.1/xyz + *
+ * + *

To reconstruct an URL with a scheme and host, use + * {@link HttpUtils#getRequestURL}. + * + * @return a String containing + * the part of the URL from the + * protocol name up to the query string + * + * @see HttpUtils#getRequestURL + * + */ + + public String getRequestURI(); + + /** + * + * Reconstructs the URL the client used to make the request. + * The returned URL contains a protocol, server name, port + * number, and server path, but it does not include query + * string parameters. + * + *

Because this method returns a StringBuffer, + * not a string, you can modify the URL easily, for example, + * to append query parameters. + * + *

This method is useful for creating redirect messages + * and for reporting errors. + * + * @return a StringBuffer object containing + * the reconstructed URL + * + */ + public StringBuffer getRequestURL(); + + + /** + * + * Returns the part of this request's URL that calls + * the servlet. This path starts with a "/" character + * and includes either the servlet name or a path to + * the servlet, but does not include any extra path + * information or a query string. Same as the value of + * the CGI variable SCRIPT_NAME. + * + *

This method will return an empty string ("") if the + * servlet used to process this request was matched using + * the "/*" pattern. + * + * @return a String containing + * the name or path of the servlet being + * called, as specified in the request URL, + * decoded, or an empty string if the servlet + * used to process the request is matched + * using the "/*" pattern. + * + */ + + public String getServletPath(); + + + + + /** + * + * Returns the current HttpSession + * associated with this request or, if there is no + * current session and create is true, returns + * a new session. + * + *

If create is false + * and the request has no valid HttpSession, + * this method returns null. + * + *

To make sure the session is properly maintained, + * you must call this method before + * the response is committed. If the container is using cookies + * to maintain session integrity and is asked to create a new session + * when the response is committed, an IllegalStateException is thrown. + * + * + * + * + * @param create true to create + * a new session for this request if necessary; + * false to return null + * if there's no current session + * + * + * @return the HttpSession associated + * with this request or null if + * create is false + * and the request has no valid session + * + * @see #getSession() + * + * + */ + + public HttpSession getSession(boolean create); + + + + + + /** + * + * Returns the current session associated with this request, + * or if the request does not have a session, creates one. + * + * @return the HttpSession associated + * with this request + * + * @see #getSession(boolean) + * + */ + + public HttpSession getSession(); + + + + + + + /** + * + * Checks whether the requested session ID is still valid. + * + * @return true if this + * request has an id for a valid session + * in the current session context; + * false otherwise + * + * @see #getRequestedSessionId + * @see #getSession + * @see HttpSessionContext + * + */ + + public boolean isRequestedSessionIdValid(); + + + + + /** + * + * Checks whether the requested session ID came in as a cookie. + * + * @return true if the session ID + * came in as a + * cookie; otherwise, false + * + * + * @see #getSession + * + */ + + public boolean isRequestedSessionIdFromCookie(); + + + + + /** + * + * Checks whether the requested session ID came in as part of the + * request URL. + * + * @return true if the session ID + * came in as part of a URL; otherwise, + * false + * + * + * @see #getSession + * + */ + + public boolean isRequestedSessionIdFromURL(); + + + + + + /** + * + * @deprecated As of Version 2.1 of the Java Servlet + * API, use {@link #isRequestedSessionIdFromURL} + * instead. + * + */ + + public boolean isRequestedSessionIdFromUrl(); + + + +} diff --git a/java/javax/servlet/http/HttpServletRequestWrapper.java b/java/javax/servlet/http/HttpServletRequestWrapper.java index 5e681a5ff..361e38f46 100644 --- a/java/javax/servlet/http/HttpServletRequestWrapper.java +++ b/java/javax/servlet/http/HttpServletRequestWrapper.java @@ -1,262 +1,262 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import javax.servlet.ServletRequestWrapper; -import java.util.Enumeration; - -/** - * - * Provides a convenient implementation of the HttpServletRequest interface that - * can be subclassed by developers wishing to adapt the request to a Servlet. - * This class implements the Wrapper or Decorator pattern. Methods default to - * calling through to the wrapped request object. - * - * - * @see javax.servlet.http.HttpServletRequest - * @since v 2.3 - * - */ - - -public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest { - - /** - * Constructs a request object wrapping the given request. - * @throws java.lang.IllegalArgumentException if the request is null - */ - public HttpServletRequestWrapper(HttpServletRequest request) { - super(request); - } - - private HttpServletRequest _getHttpServletRequest() { - return (HttpServletRequest) super.getRequest(); - } - - /** - * The default behavior of this method is to return getAuthType() - * on the wrapped request object. - */ - - public String getAuthType() { - return this._getHttpServletRequest().getAuthType(); - } - - /** - * The default behavior of this method is to return getCookies() - * on the wrapped request object. - */ - public Cookie[] getCookies() { - return this._getHttpServletRequest().getCookies(); - } - - /** - * The default behavior of this method is to return getDateHeader(String name) - * on the wrapped request object. - */ - public long getDateHeader(String name) { - return this._getHttpServletRequest().getDateHeader(name); - } - - /** - * The default behavior of this method is to return getHeader(String name) - * on the wrapped request object. - */ - public String getHeader(String name) { - return this._getHttpServletRequest().getHeader(name); - } - - /** - * The default behavior of this method is to return getHeaders(String name) - * on the wrapped request object. - */ - public Enumeration getHeaders(String name) { - return this._getHttpServletRequest().getHeaders(name); - } - - /** - * The default behavior of this method is to return getHeaderNames() - * on the wrapped request object. - */ - - public Enumeration getHeaderNames() { - return this._getHttpServletRequest().getHeaderNames(); - } - - /** - * The default behavior of this method is to return getIntHeader(String name) - * on the wrapped request object. - */ - - public int getIntHeader(String name) { - return this._getHttpServletRequest().getIntHeader(name); - } - - /** - * The default behavior of this method is to return getMethod() - * on the wrapped request object. - */ - public String getMethod() { - return this._getHttpServletRequest().getMethod(); - } - - /** - * The default behavior of this method is to return getPathInfo() - * on the wrapped request object. - */ - public String getPathInfo() { - return this._getHttpServletRequest().getPathInfo(); - } - - /** - * The default behavior of this method is to return getPathTranslated() - * on the wrapped request object. - */ - - public String getPathTranslated() { - return this._getHttpServletRequest().getPathTranslated(); - } - - /** - * The default behavior of this method is to return getContextPath() - * on the wrapped request object. - */ - public String getContextPath() { - return this._getHttpServletRequest().getContextPath(); - } - - /** - * The default behavior of this method is to return getQueryString() - * on the wrapped request object. - */ - public String getQueryString() { - return this._getHttpServletRequest().getQueryString(); - } - - /** - * The default behavior of this method is to return getRemoteUser() - * on the wrapped request object. - */ - public String getRemoteUser() { - return this._getHttpServletRequest().getRemoteUser(); - } - - - /** - * The default behavior of this method is to return isUserInRole(String role) - * on the wrapped request object. - */ - public boolean isUserInRole(String role) { - return this._getHttpServletRequest().isUserInRole(role); - } - - - - /** - * The default behavior of this method is to return getUserPrincipal() - * on the wrapped request object. - */ - public java.security.Principal getUserPrincipal() { - return this._getHttpServletRequest().getUserPrincipal(); - } - - - /** - * The default behavior of this method is to return getRequestedSessionId() - * on the wrapped request object. - */ - public String getRequestedSessionId() { - return this._getHttpServletRequest().getRequestedSessionId(); - } - - /** - * The default behavior of this method is to return getRequestURI() - * on the wrapped request object. - */ - public String getRequestURI() { - return this._getHttpServletRequest().getRequestURI(); - } - /** - * The default behavior of this method is to return getRequestURL() - * on the wrapped request object. - */ - public StringBuffer getRequestURL() { - return this._getHttpServletRequest().getRequestURL(); - } - - - /** - * The default behavior of this method is to return getServletPath() - * on the wrapped request object. - */ - public String getServletPath() { - return this._getHttpServletRequest().getServletPath(); - } - - - /** - * The default behavior of this method is to return getSession(boolean create) - * on the wrapped request object. - */ - public HttpSession getSession(boolean create) { - return this._getHttpServletRequest().getSession(create); - } - - /** - * The default behavior of this method is to return getSession() - * on the wrapped request object. - */ - public HttpSession getSession() { - return this._getHttpServletRequest().getSession(); - } - - /** - * The default behavior of this method is to return isRequestedSessionIdValid() - * on the wrapped request object. - */ - - public boolean isRequestedSessionIdValid() { - return this._getHttpServletRequest().isRequestedSessionIdValid(); - } - - - /** - * The default behavior of this method is to return isRequestedSessionIdFromCookie() - * on the wrapped request object. - */ - public boolean isRequestedSessionIdFromCookie() { - return this._getHttpServletRequest().isRequestedSessionIdFromCookie(); - } - - /** - * The default behavior of this method is to return isRequestedSessionIdFromURL() - * on the wrapped request object. - */ - public boolean isRequestedSessionIdFromURL() { - return this._getHttpServletRequest().isRequestedSessionIdFromURL(); - } - - /** - * The default behavior of this method is to return isRequestedSessionIdFromUrl() - * on the wrapped request object. - */ - public boolean isRequestedSessionIdFromUrl() { - return this._getHttpServletRequest().isRequestedSessionIdFromUrl(); - } - - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import javax.servlet.ServletRequestWrapper; +import java.util.Enumeration; + +/** + * + * Provides a convenient implementation of the HttpServletRequest interface that + * can be subclassed by developers wishing to adapt the request to a Servlet. + * This class implements the Wrapper or Decorator pattern. Methods default to + * calling through to the wrapped request object. + * + * + * @see javax.servlet.http.HttpServletRequest + * @since v 2.3 + * + */ + + +public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest { + + /** + * Constructs a request object wrapping the given request. + * @throws java.lang.IllegalArgumentException if the request is null + */ + public HttpServletRequestWrapper(HttpServletRequest request) { + super(request); + } + + private HttpServletRequest _getHttpServletRequest() { + return (HttpServletRequest) super.getRequest(); + } + + /** + * The default behavior of this method is to return getAuthType() + * on the wrapped request object. + */ + + public String getAuthType() { + return this._getHttpServletRequest().getAuthType(); + } + + /** + * The default behavior of this method is to return getCookies() + * on the wrapped request object. + */ + public Cookie[] getCookies() { + return this._getHttpServletRequest().getCookies(); + } + + /** + * The default behavior of this method is to return getDateHeader(String name) + * on the wrapped request object. + */ + public long getDateHeader(String name) { + return this._getHttpServletRequest().getDateHeader(name); + } + + /** + * The default behavior of this method is to return getHeader(String name) + * on the wrapped request object. + */ + public String getHeader(String name) { + return this._getHttpServletRequest().getHeader(name); + } + + /** + * The default behavior of this method is to return getHeaders(String name) + * on the wrapped request object. + */ + public Enumeration getHeaders(String name) { + return this._getHttpServletRequest().getHeaders(name); + } + + /** + * The default behavior of this method is to return getHeaderNames() + * on the wrapped request object. + */ + + public Enumeration getHeaderNames() { + return this._getHttpServletRequest().getHeaderNames(); + } + + /** + * The default behavior of this method is to return getIntHeader(String name) + * on the wrapped request object. + */ + + public int getIntHeader(String name) { + return this._getHttpServletRequest().getIntHeader(name); + } + + /** + * The default behavior of this method is to return getMethod() + * on the wrapped request object. + */ + public String getMethod() { + return this._getHttpServletRequest().getMethod(); + } + + /** + * The default behavior of this method is to return getPathInfo() + * on the wrapped request object. + */ + public String getPathInfo() { + return this._getHttpServletRequest().getPathInfo(); + } + + /** + * The default behavior of this method is to return getPathTranslated() + * on the wrapped request object. + */ + + public String getPathTranslated() { + return this._getHttpServletRequest().getPathTranslated(); + } + + /** + * The default behavior of this method is to return getContextPath() + * on the wrapped request object. + */ + public String getContextPath() { + return this._getHttpServletRequest().getContextPath(); + } + + /** + * The default behavior of this method is to return getQueryString() + * on the wrapped request object. + */ + public String getQueryString() { + return this._getHttpServletRequest().getQueryString(); + } + + /** + * The default behavior of this method is to return getRemoteUser() + * on the wrapped request object. + */ + public String getRemoteUser() { + return this._getHttpServletRequest().getRemoteUser(); + } + + + /** + * The default behavior of this method is to return isUserInRole(String role) + * on the wrapped request object. + */ + public boolean isUserInRole(String role) { + return this._getHttpServletRequest().isUserInRole(role); + } + + + + /** + * The default behavior of this method is to return getUserPrincipal() + * on the wrapped request object. + */ + public java.security.Principal getUserPrincipal() { + return this._getHttpServletRequest().getUserPrincipal(); + } + + + /** + * The default behavior of this method is to return getRequestedSessionId() + * on the wrapped request object. + */ + public String getRequestedSessionId() { + return this._getHttpServletRequest().getRequestedSessionId(); + } + + /** + * The default behavior of this method is to return getRequestURI() + * on the wrapped request object. + */ + public String getRequestURI() { + return this._getHttpServletRequest().getRequestURI(); + } + /** + * The default behavior of this method is to return getRequestURL() + * on the wrapped request object. + */ + public StringBuffer getRequestURL() { + return this._getHttpServletRequest().getRequestURL(); + } + + + /** + * The default behavior of this method is to return getServletPath() + * on the wrapped request object. + */ + public String getServletPath() { + return this._getHttpServletRequest().getServletPath(); + } + + + /** + * The default behavior of this method is to return getSession(boolean create) + * on the wrapped request object. + */ + public HttpSession getSession(boolean create) { + return this._getHttpServletRequest().getSession(create); + } + + /** + * The default behavior of this method is to return getSession() + * on the wrapped request object. + */ + public HttpSession getSession() { + return this._getHttpServletRequest().getSession(); + } + + /** + * The default behavior of this method is to return isRequestedSessionIdValid() + * on the wrapped request object. + */ + + public boolean isRequestedSessionIdValid() { + return this._getHttpServletRequest().isRequestedSessionIdValid(); + } + + + /** + * The default behavior of this method is to return isRequestedSessionIdFromCookie() + * on the wrapped request object. + */ + public boolean isRequestedSessionIdFromCookie() { + return this._getHttpServletRequest().isRequestedSessionIdFromCookie(); + } + + /** + * The default behavior of this method is to return isRequestedSessionIdFromURL() + * on the wrapped request object. + */ + public boolean isRequestedSessionIdFromURL() { + return this._getHttpServletRequest().isRequestedSessionIdFromURL(); + } + + /** + * The default behavior of this method is to return isRequestedSessionIdFromUrl() + * on the wrapped request object. + */ + public boolean isRequestedSessionIdFromUrl() { + return this._getHttpServletRequest().isRequestedSessionIdFromUrl(); + } + + + +} diff --git a/java/javax/servlet/http/HttpServletResponse.java b/java/javax/servlet/http/HttpServletResponse.java index 89d5710c7..617905020 100644 --- a/java/javax/servlet/http/HttpServletResponse.java +++ b/java/javax/servlet/http/HttpServletResponse.java @@ -1,636 +1,636 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.io.IOException; - -import javax.servlet.ServletResponse; - -/** - * - * Extends the {@link ServletResponse} interface to provide HTTP-specific - * functionality in sending a response. For example, it has methods - * to access HTTP headers and cookies. - * - *

The servlet container creates an HttpServletResponse object - * and passes it as an argument to the servlet's service methods - * (doGet, doPost, etc). - * - * - * @author Various - * @version $Version$ - * - * @see javax.servlet.ServletResponse - * - */ - - - -public interface HttpServletResponse extends ServletResponse { - - /** - * Adds the specified cookie to the response. This method can be called - * multiple times to set more than one cookie. - * - * @param cookie the Cookie to return to the client - * - */ - - public void addCookie(Cookie cookie); - - /** - * Returns a boolean indicating whether the named response header - * has already been set. - * - * @param name the header name - * @return true if the named response header - * has already been set; - * false otherwise - */ - - public boolean containsHeader(String name); - - /** - * Encodes the specified URL by including the session ID in it, - * or, if encoding is not needed, returns the URL unchanged. - * The implementation of this method includes the logic to - * determine whether the session ID needs to be encoded in the URL. - * For example, if the browser supports cookies, or session - * tracking is turned off, URL encoding is unnecessary. - * - *

For robust session tracking, all URLs emitted by a servlet - * should be run through this - * method. Otherwise, URL rewriting cannot be used with browsers - * which do not support cookies. - * - * @param url the url to be encoded. - * @return the encoded URL if encoding is needed; - * the unchanged URL otherwise. - */ - - public String encodeURL(String url); - - /** - * Encodes the specified URL for use in the - * sendRedirect method or, if encoding is not needed, - * returns the URL unchanged. The implementation of this method - * includes the logic to determine whether the session ID - * needs to be encoded in the URL. Because the rules for making - * this determination can differ from those used to decide whether to - * encode a normal link, this method is separated from the - * encodeURL method. - * - *

All URLs sent to the HttpServletResponse.sendRedirect - * method should be run through this method. Otherwise, URL - * rewriting cannot be used with browsers which do not support - * cookies. - * - * @param url the url to be encoded. - * @return the encoded URL if encoding is needed; - * the unchanged URL otherwise. - * - * @see #sendRedirect - * @see #encodeUrl - */ - - public String encodeRedirectURL(String url); - - /** - * @deprecated As of version 2.1, use encodeURL(String url) instead - * - * @param url the url to be encoded. - * @return the encoded URL if encoding is needed; - * the unchanged URL otherwise. - */ - - public String encodeUrl(String url); - - /** - * @deprecated As of version 2.1, use - * encodeRedirectURL(String url) instead - * - * @param url the url to be encoded. - * @return the encoded URL if encoding is needed; - * the unchanged URL otherwise. - */ - - public String encodeRedirectUrl(String url); - - /** - * Sends an error response to the client using the specified - * status. The server defaults to creating the - * response to look like an HTML-formatted server error page - * containing the specified message, setting the content type - * to "text/html", leaving cookies and other headers unmodified. - * - * If an error-page declaration has been made for the web application - * corresponding to the status code passed in, it will be served back in - * preference to the suggested msg parameter. - * - *

If the response has already been committed, this method throws - * an IllegalStateException. - * After using this method, the response should be considered - * to be committed and should not be written to. - * - * @param sc the error status code - * @param msg the descriptive message - * @exception IOException If an input or output exception occurs - * @exception IllegalStateException If the response was committed - */ - - public void sendError(int sc, String msg) throws IOException; - - /** - * Sends an error response to the client using the specified status - * code and clearing the buffer. - *

If the response has already been committed, this method throws - * an IllegalStateException. - * After using this method, the response should be considered - * to be committed and should not be written to. - * - * @param sc the error status code - * @exception IOException If an input or output exception occurs - * @exception IllegalStateException If the response was committed - * before this method call - */ - - public void sendError(int sc) throws IOException; - - /** - * Sends a temporary redirect response to the client using the - * specified redirect location URL. This method can accept relative URLs; - * the servlet container must convert the relative URL to an absolute URL - * before sending the response to the client. If the location is relative - * without a leading '/' the container interprets it as relative to - * the current request URI. If the location is relative with a leading - * '/' the container interprets it as relative to the servlet container root. - * - *

If the response has already been committed, this method throws - * an IllegalStateException. - * After using this method, the response should be considered - * to be committed and should not be written to. - * - * @param location the redirect location URL - * @exception IOException If an input or output exception occurs - * @exception IllegalStateException If the response was committed or - if a partial URL is given and cannot be converted into a valid URL - */ - - public void sendRedirect(String location) throws IOException; - - /** - * - * Sets a response header with the given name and - * date-value. The date is specified in terms of - * milliseconds since the epoch. If the header had already - * been set, the new value overwrites the previous one. The - * containsHeader method can be used to test for the - * presence of a header before setting its value. - * - * @param name the name of the header to set - * @param date the assigned date value - * - * @see #containsHeader - * @see #addDateHeader - */ - - public void setDateHeader(String name, long date); - - /** - * - * Adds a response header with the given name and - * date-value. The date is specified in terms of - * milliseconds since the epoch. This method allows response headers - * to have multiple values. - * - * @param name the name of the header to set - * @param date the additional date value - * - * @see #setDateHeader - */ - - public void addDateHeader(String name, long date); - - /** - * - * Sets a response header with the given name and value. - * If the header had already been set, the new value overwrites the - * previous one. The containsHeader method can be - * used to test for the presence of a header before setting its - * value. - * - * @param name the name of the header - * @param value the header value If it contains octet string, - * it should be encoded according to RFC 2047 - * (http://www.ietf.org/rfc/rfc2047.txt) - * - * @see #containsHeader - * @see #addHeader - */ - - public void setHeader(String name, String value); - - /** - * Adds a response header with the given name and value. - * This method allows response headers to have multiple values. - * - * @param name the name of the header - * @param value the additional header value If it contains - * octet string, it should be encoded - * according to RFC 2047 - * (http://www.ietf.org/rfc/rfc2047.txt) - * - * @see #setHeader - */ - - public void addHeader(String name, String value); - - /** - * Sets a response header with the given name and - * integer value. If the header had already been set, the new value - * overwrites the previous one. The containsHeader - * method can be used to test for the presence of a header before - * setting its value. - * - * @param name the name of the header - * @param value the assigned integer value - * - * @see #containsHeader - * @see #addIntHeader - */ - - public void setIntHeader(String name, int value); - - /** - * Adds a response header with the given name and - * integer value. This method allows response headers to have multiple - * values. - * - * @param name the name of the header - * @param value the assigned integer value - * - * @see #setIntHeader - */ - - public void addIntHeader(String name, int value); - - - - /** - * Sets the status code for this response. This method is used to - * set the return status code when there is no error (for example, - * for the status codes SC_OK or SC_MOVED_TEMPORARILY). If there - * is an error, and the caller wishes to invoke an error-page defined - * in the web application, the sendError method should be used - * instead. - *

The container clears the buffer and sets the Location header, preserving - * cookies and other headers. - * - * @param sc the status code - * - * @see #sendError - */ - - public void setStatus(int sc); - - /** - * @deprecated As of version 2.1, due to ambiguous meaning of the - * message parameter. To set a status code - * use setStatus(int), to send an error with a description - * use sendError(int, String). - * - * Sets the status code and message for this response. - * - * @param sc the status code - * @param sm the status message - */ - - public void setStatus(int sc, String sm); - - - /* - * Server status codes; see RFC 2068. - */ - - /** - * Status code (100) indicating the client can continue. - */ - - public static final int SC_CONTINUE = 100; - - - /** - * Status code (101) indicating the server is switching protocols - * according to Upgrade header. - */ - - public static final int SC_SWITCHING_PROTOCOLS = 101; - - /** - * Status code (200) indicating the request succeeded normally. - */ - - public static final int SC_OK = 200; - - /** - * Status code (201) indicating the request succeeded and created - * a new resource on the server. - */ - - public static final int SC_CREATED = 201; - - /** - * Status code (202) indicating that a request was accepted for - * processing, but was not completed. - */ - - public static final int SC_ACCEPTED = 202; - - /** - * Status code (203) indicating that the meta information presented - * by the client did not originate from the server. - */ - - public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; - - /** - * Status code (204) indicating that the request succeeded but that - * there was no new information to return. - */ - - public static final int SC_NO_CONTENT = 204; - - /** - * Status code (205) indicating that the agent SHOULD reset - * the document view which caused the request to be sent. - */ - - public static final int SC_RESET_CONTENT = 205; - - /** - * Status code (206) indicating that the server has fulfilled - * the partial GET request for the resource. - */ - - public static final int SC_PARTIAL_CONTENT = 206; - - /** - * Status code (300) indicating that the requested resource - * corresponds to any one of a set of representations, each with - * its own specific location. - */ - - public static final int SC_MULTIPLE_CHOICES = 300; - - /** - * Status code (301) indicating that the resource has permanently - * moved to a new location, and that future references should use a - * new URI with their requests. - */ - - public static final int SC_MOVED_PERMANENTLY = 301; - - /** - * Status code (302) indicating that the resource has temporarily - * moved to another location, but that future references should - * still use the original URI to access the resource. - * - * This definition is being retained for backwards compatibility. - * SC_FOUND is now the preferred definition. - */ - - public static final int SC_MOVED_TEMPORARILY = 302; - - /** - * Status code (302) indicating that the resource reside - * temporarily under a different URI. Since the redirection might - * be altered on occasion, the client should continue to use the - * Request-URI for future requests.(HTTP/1.1) To represent the - * status code (302), it is recommended to use this variable. - */ - - public static final int SC_FOUND = 302; - - /** - * Status code (303) indicating that the response to the request - * can be found under a different URI. - */ - - public static final int SC_SEE_OTHER = 303; - - /** - * Status code (304) indicating that a conditional GET operation - * found that the resource was available and not modified. - */ - - public static final int SC_NOT_MODIFIED = 304; - - /** - * Status code (305) indicating that the requested resource - * MUST be accessed through the proxy given by the - * Location field. - */ - - public static final int SC_USE_PROXY = 305; - - /** - * Status code (307) indicating that the requested resource - * resides temporarily under a different URI. The temporary URI - * SHOULD be given by the Location - * field in the response. - */ - - public static final int SC_TEMPORARY_REDIRECT = 307; - - /** - * Status code (400) indicating the request sent by the client was - * syntactically incorrect. - */ - - public static final int SC_BAD_REQUEST = 400; - - /** - * Status code (401) indicating that the request requires HTTP - * authentication. - */ - - public static final int SC_UNAUTHORIZED = 401; - - /** - * Status code (402) reserved for future use. - */ - - public static final int SC_PAYMENT_REQUIRED = 402; - - /** - * Status code (403) indicating the server understood the request - * but refused to fulfill it. - */ - - public static final int SC_FORBIDDEN = 403; - - /** - * Status code (404) indicating that the requested resource is not - * available. - */ - - public static final int SC_NOT_FOUND = 404; - - /** - * Status code (405) indicating that the method specified in the - * Request-Line is not allowed for the resource - * identified by the Request-URI. - */ - - public static final int SC_METHOD_NOT_ALLOWED = 405; - - /** - * Status code (406) indicating that the resource identified by the - * request is only capable of generating response entities which have - * content characteristics not acceptable according to the accept - * headers sent in the request. - */ - - public static final int SC_NOT_ACCEPTABLE = 406; - - /** - * Status code (407) indicating that the client MUST first - * authenticate itself with the proxy. - */ - - public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; - - /** - * Status code (408) indicating that the client did not produce a - * request within the time that the server was prepared to wait. - */ - - public static final int SC_REQUEST_TIMEOUT = 408; - - /** - * Status code (409) indicating that the request could not be - * completed due to a conflict with the current state of the - * resource. - */ - - public static final int SC_CONFLICT = 409; - - /** - * Status code (410) indicating that the resource is no longer - * available at the server and no forwarding address is known. - * This condition SHOULD be considered permanent. - */ - - public static final int SC_GONE = 410; - - /** - * Status code (411) indicating that the request cannot be handled - * without a defined Content-Length. - */ - - public static final int SC_LENGTH_REQUIRED = 411; - - /** - * Status code (412) indicating that the precondition given in one - * or more of the request-header fields evaluated to false when it - * was tested on the server. - */ - - public static final int SC_PRECONDITION_FAILED = 412; - - /** - * Status code (413) indicating that the server is refusing to process - * the request because the request entity is larger than the server is - * willing or able to process. - */ - - public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; - - /** - * Status code (414) indicating that the server is refusing to service - * the request because the Request-URI is longer - * than the server is willing to interpret. - */ - - public static final int SC_REQUEST_URI_TOO_LONG = 414; - - /** - * Status code (415) indicating that the server is refusing to service - * the request because the entity of the request is in a format not - * supported by the requested resource for the requested method. - */ - - public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; - - /** - * Status code (416) indicating that the server cannot serve the - * requested byte range. - */ - - public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; - - /** - * Status code (417) indicating that the server could not meet the - * expectation given in the Expect request header. - */ - - public static final int SC_EXPECTATION_FAILED = 417; - - /** - * Status code (500) indicating an error inside the HTTP server - * which prevented it from fulfilling the request. - */ - - public static final int SC_INTERNAL_SERVER_ERROR = 500; - - /** - * Status code (501) indicating the HTTP server does not support - * the functionality needed to fulfill the request. - */ - - public static final int SC_NOT_IMPLEMENTED = 501; - - /** - * Status code (502) indicating that the HTTP server received an - * invalid response from a server it consulted when acting as a - * proxy or gateway. - */ - - public static final int SC_BAD_GATEWAY = 502; - - /** - * Status code (503) indicating that the HTTP server is - * temporarily overloaded, and unable to handle the request. - */ - - public static final int SC_SERVICE_UNAVAILABLE = 503; - - /** - * Status code (504) indicating that the server did not receive - * a timely response from the upstream server while acting as - * a gateway or proxy. - */ - - public static final int SC_GATEWAY_TIMEOUT = 504; - - /** - * Status code (505) indicating that the server does not support - * or refuses to support the HTTP protocol version that was used - * in the request message. - */ - - public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.io.IOException; + +import javax.servlet.ServletResponse; + +/** + * + * Extends the {@link ServletResponse} interface to provide HTTP-specific + * functionality in sending a response. For example, it has methods + * to access HTTP headers and cookies. + * + *

The servlet container creates an HttpServletResponse object + * and passes it as an argument to the servlet's service methods + * (doGet, doPost, etc). + * + * + * @author Various + * @version $Version$ + * + * @see javax.servlet.ServletResponse + * + */ + + + +public interface HttpServletResponse extends ServletResponse { + + /** + * Adds the specified cookie to the response. This method can be called + * multiple times to set more than one cookie. + * + * @param cookie the Cookie to return to the client + * + */ + + public void addCookie(Cookie cookie); + + /** + * Returns a boolean indicating whether the named response header + * has already been set. + * + * @param name the header name + * @return true if the named response header + * has already been set; + * false otherwise + */ + + public boolean containsHeader(String name); + + /** + * Encodes the specified URL by including the session ID in it, + * or, if encoding is not needed, returns the URL unchanged. + * The implementation of this method includes the logic to + * determine whether the session ID needs to be encoded in the URL. + * For example, if the browser supports cookies, or session + * tracking is turned off, URL encoding is unnecessary. + * + *

For robust session tracking, all URLs emitted by a servlet + * should be run through this + * method. Otherwise, URL rewriting cannot be used with browsers + * which do not support cookies. + * + * @param url the url to be encoded. + * @return the encoded URL if encoding is needed; + * the unchanged URL otherwise. + */ + + public String encodeURL(String url); + + /** + * Encodes the specified URL for use in the + * sendRedirect method or, if encoding is not needed, + * returns the URL unchanged. The implementation of this method + * includes the logic to determine whether the session ID + * needs to be encoded in the URL. Because the rules for making + * this determination can differ from those used to decide whether to + * encode a normal link, this method is separated from the + * encodeURL method. + * + *

All URLs sent to the HttpServletResponse.sendRedirect + * method should be run through this method. Otherwise, URL + * rewriting cannot be used with browsers which do not support + * cookies. + * + * @param url the url to be encoded. + * @return the encoded URL if encoding is needed; + * the unchanged URL otherwise. + * + * @see #sendRedirect + * @see #encodeUrl + */ + + public String encodeRedirectURL(String url); + + /** + * @deprecated As of version 2.1, use encodeURL(String url) instead + * + * @param url the url to be encoded. + * @return the encoded URL if encoding is needed; + * the unchanged URL otherwise. + */ + + public String encodeUrl(String url); + + /** + * @deprecated As of version 2.1, use + * encodeRedirectURL(String url) instead + * + * @param url the url to be encoded. + * @return the encoded URL if encoding is needed; + * the unchanged URL otherwise. + */ + + public String encodeRedirectUrl(String url); + + /** + * Sends an error response to the client using the specified + * status. The server defaults to creating the + * response to look like an HTML-formatted server error page + * containing the specified message, setting the content type + * to "text/html", leaving cookies and other headers unmodified. + * + * If an error-page declaration has been made for the web application + * corresponding to the status code passed in, it will be served back in + * preference to the suggested msg parameter. + * + *

If the response has already been committed, this method throws + * an IllegalStateException. + * After using this method, the response should be considered + * to be committed and should not be written to. + * + * @param sc the error status code + * @param msg the descriptive message + * @exception IOException If an input or output exception occurs + * @exception IllegalStateException If the response was committed + */ + + public void sendError(int sc, String msg) throws IOException; + + /** + * Sends an error response to the client using the specified status + * code and clearing the buffer. + *

If the response has already been committed, this method throws + * an IllegalStateException. + * After using this method, the response should be considered + * to be committed and should not be written to. + * + * @param sc the error status code + * @exception IOException If an input or output exception occurs + * @exception IllegalStateException If the response was committed + * before this method call + */ + + public void sendError(int sc) throws IOException; + + /** + * Sends a temporary redirect response to the client using the + * specified redirect location URL. This method can accept relative URLs; + * the servlet container must convert the relative URL to an absolute URL + * before sending the response to the client. If the location is relative + * without a leading '/' the container interprets it as relative to + * the current request URI. If the location is relative with a leading + * '/' the container interprets it as relative to the servlet container root. + * + *

If the response has already been committed, this method throws + * an IllegalStateException. + * After using this method, the response should be considered + * to be committed and should not be written to. + * + * @param location the redirect location URL + * @exception IOException If an input or output exception occurs + * @exception IllegalStateException If the response was committed or + if a partial URL is given and cannot be converted into a valid URL + */ + + public void sendRedirect(String location) throws IOException; + + /** + * + * Sets a response header with the given name and + * date-value. The date is specified in terms of + * milliseconds since the epoch. If the header had already + * been set, the new value overwrites the previous one. The + * containsHeader method can be used to test for the + * presence of a header before setting its value. + * + * @param name the name of the header to set + * @param date the assigned date value + * + * @see #containsHeader + * @see #addDateHeader + */ + + public void setDateHeader(String name, long date); + + /** + * + * Adds a response header with the given name and + * date-value. The date is specified in terms of + * milliseconds since the epoch. This method allows response headers + * to have multiple values. + * + * @param name the name of the header to set + * @param date the additional date value + * + * @see #setDateHeader + */ + + public void addDateHeader(String name, long date); + + /** + * + * Sets a response header with the given name and value. + * If the header had already been set, the new value overwrites the + * previous one. The containsHeader method can be + * used to test for the presence of a header before setting its + * value. + * + * @param name the name of the header + * @param value the header value If it contains octet string, + * it should be encoded according to RFC 2047 + * (http://www.ietf.org/rfc/rfc2047.txt) + * + * @see #containsHeader + * @see #addHeader + */ + + public void setHeader(String name, String value); + + /** + * Adds a response header with the given name and value. + * This method allows response headers to have multiple values. + * + * @param name the name of the header + * @param value the additional header value If it contains + * octet string, it should be encoded + * according to RFC 2047 + * (http://www.ietf.org/rfc/rfc2047.txt) + * + * @see #setHeader + */ + + public void addHeader(String name, String value); + + /** + * Sets a response header with the given name and + * integer value. If the header had already been set, the new value + * overwrites the previous one. The containsHeader + * method can be used to test for the presence of a header before + * setting its value. + * + * @param name the name of the header + * @param value the assigned integer value + * + * @see #containsHeader + * @see #addIntHeader + */ + + public void setIntHeader(String name, int value); + + /** + * Adds a response header with the given name and + * integer value. This method allows response headers to have multiple + * values. + * + * @param name the name of the header + * @param value the assigned integer value + * + * @see #setIntHeader + */ + + public void addIntHeader(String name, int value); + + + + /** + * Sets the status code for this response. This method is used to + * set the return status code when there is no error (for example, + * for the status codes SC_OK or SC_MOVED_TEMPORARILY). If there + * is an error, and the caller wishes to invoke an error-page defined + * in the web application, the sendError method should be used + * instead. + *

The container clears the buffer and sets the Location header, preserving + * cookies and other headers. + * + * @param sc the status code + * + * @see #sendError + */ + + public void setStatus(int sc); + + /** + * @deprecated As of version 2.1, due to ambiguous meaning of the + * message parameter. To set a status code + * use setStatus(int), to send an error with a description + * use sendError(int, String). + * + * Sets the status code and message for this response. + * + * @param sc the status code + * @param sm the status message + */ + + public void setStatus(int sc, String sm); + + + /* + * Server status codes; see RFC 2068. + */ + + /** + * Status code (100) indicating the client can continue. + */ + + public static final int SC_CONTINUE = 100; + + + /** + * Status code (101) indicating the server is switching protocols + * according to Upgrade header. + */ + + public static final int SC_SWITCHING_PROTOCOLS = 101; + + /** + * Status code (200) indicating the request succeeded normally. + */ + + public static final int SC_OK = 200; + + /** + * Status code (201) indicating the request succeeded and created + * a new resource on the server. + */ + + public static final int SC_CREATED = 201; + + /** + * Status code (202) indicating that a request was accepted for + * processing, but was not completed. + */ + + public static final int SC_ACCEPTED = 202; + + /** + * Status code (203) indicating that the meta information presented + * by the client did not originate from the server. + */ + + public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203; + + /** + * Status code (204) indicating that the request succeeded but that + * there was no new information to return. + */ + + public static final int SC_NO_CONTENT = 204; + + /** + * Status code (205) indicating that the agent SHOULD reset + * the document view which caused the request to be sent. + */ + + public static final int SC_RESET_CONTENT = 205; + + /** + * Status code (206) indicating that the server has fulfilled + * the partial GET request for the resource. + */ + + public static final int SC_PARTIAL_CONTENT = 206; + + /** + * Status code (300) indicating that the requested resource + * corresponds to any one of a set of representations, each with + * its own specific location. + */ + + public static final int SC_MULTIPLE_CHOICES = 300; + + /** + * Status code (301) indicating that the resource has permanently + * moved to a new location, and that future references should use a + * new URI with their requests. + */ + + public static final int SC_MOVED_PERMANENTLY = 301; + + /** + * Status code (302) indicating that the resource has temporarily + * moved to another location, but that future references should + * still use the original URI to access the resource. + * + * This definition is being retained for backwards compatibility. + * SC_FOUND is now the preferred definition. + */ + + public static final int SC_MOVED_TEMPORARILY = 302; + + /** + * Status code (302) indicating that the resource reside + * temporarily under a different URI. Since the redirection might + * be altered on occasion, the client should continue to use the + * Request-URI for future requests.(HTTP/1.1) To represent the + * status code (302), it is recommended to use this variable. + */ + + public static final int SC_FOUND = 302; + + /** + * Status code (303) indicating that the response to the request + * can be found under a different URI. + */ + + public static final int SC_SEE_OTHER = 303; + + /** + * Status code (304) indicating that a conditional GET operation + * found that the resource was available and not modified. + */ + + public static final int SC_NOT_MODIFIED = 304; + + /** + * Status code (305) indicating that the requested resource + * MUST be accessed through the proxy given by the + * Location field. + */ + + public static final int SC_USE_PROXY = 305; + + /** + * Status code (307) indicating that the requested resource + * resides temporarily under a different URI. The temporary URI + * SHOULD be given by the Location + * field in the response. + */ + + public static final int SC_TEMPORARY_REDIRECT = 307; + + /** + * Status code (400) indicating the request sent by the client was + * syntactically incorrect. + */ + + public static final int SC_BAD_REQUEST = 400; + + /** + * Status code (401) indicating that the request requires HTTP + * authentication. + */ + + public static final int SC_UNAUTHORIZED = 401; + + /** + * Status code (402) reserved for future use. + */ + + public static final int SC_PAYMENT_REQUIRED = 402; + + /** + * Status code (403) indicating the server understood the request + * but refused to fulfill it. + */ + + public static final int SC_FORBIDDEN = 403; + + /** + * Status code (404) indicating that the requested resource is not + * available. + */ + + public static final int SC_NOT_FOUND = 404; + + /** + * Status code (405) indicating that the method specified in the + * Request-Line is not allowed for the resource + * identified by the Request-URI. + */ + + public static final int SC_METHOD_NOT_ALLOWED = 405; + + /** + * Status code (406) indicating that the resource identified by the + * request is only capable of generating response entities which have + * content characteristics not acceptable according to the accept + * headers sent in the request. + */ + + public static final int SC_NOT_ACCEPTABLE = 406; + + /** + * Status code (407) indicating that the client MUST first + * authenticate itself with the proxy. + */ + + public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407; + + /** + * Status code (408) indicating that the client did not produce a + * request within the time that the server was prepared to wait. + */ + + public static final int SC_REQUEST_TIMEOUT = 408; + + /** + * Status code (409) indicating that the request could not be + * completed due to a conflict with the current state of the + * resource. + */ + + public static final int SC_CONFLICT = 409; + + /** + * Status code (410) indicating that the resource is no longer + * available at the server and no forwarding address is known. + * This condition SHOULD be considered permanent. + */ + + public static final int SC_GONE = 410; + + /** + * Status code (411) indicating that the request cannot be handled + * without a defined Content-Length. + */ + + public static final int SC_LENGTH_REQUIRED = 411; + + /** + * Status code (412) indicating that the precondition given in one + * or more of the request-header fields evaluated to false when it + * was tested on the server. + */ + + public static final int SC_PRECONDITION_FAILED = 412; + + /** + * Status code (413) indicating that the server is refusing to process + * the request because the request entity is larger than the server is + * willing or able to process. + */ + + public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413; + + /** + * Status code (414) indicating that the server is refusing to service + * the request because the Request-URI is longer + * than the server is willing to interpret. + */ + + public static final int SC_REQUEST_URI_TOO_LONG = 414; + + /** + * Status code (415) indicating that the server is refusing to service + * the request because the entity of the request is in a format not + * supported by the requested resource for the requested method. + */ + + public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; + + /** + * Status code (416) indicating that the server cannot serve the + * requested byte range. + */ + + public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416; + + /** + * Status code (417) indicating that the server could not meet the + * expectation given in the Expect request header. + */ + + public static final int SC_EXPECTATION_FAILED = 417; + + /** + * Status code (500) indicating an error inside the HTTP server + * which prevented it from fulfilling the request. + */ + + public static final int SC_INTERNAL_SERVER_ERROR = 500; + + /** + * Status code (501) indicating the HTTP server does not support + * the functionality needed to fulfill the request. + */ + + public static final int SC_NOT_IMPLEMENTED = 501; + + /** + * Status code (502) indicating that the HTTP server received an + * invalid response from a server it consulted when acting as a + * proxy or gateway. + */ + + public static final int SC_BAD_GATEWAY = 502; + + /** + * Status code (503) indicating that the HTTP server is + * temporarily overloaded, and unable to handle the request. + */ + + public static final int SC_SERVICE_UNAVAILABLE = 503; + + /** + * Status code (504) indicating that the server did not receive + * a timely response from the upstream server while acting as + * a gateway or proxy. + */ + + public static final int SC_GATEWAY_TIMEOUT = 504; + + /** + * Status code (505) indicating that the server does not support + * or refuses to support the HTTP protocol version that was used + * in the request message. + */ + + public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505; +} diff --git a/java/javax/servlet/http/HttpServletResponseWrapper.java b/java/javax/servlet/http/HttpServletResponseWrapper.java index a68bb6426..751e4bcf3 100644 --- a/java/javax/servlet/http/HttpServletResponseWrapper.java +++ b/java/javax/servlet/http/HttpServletResponseWrapper.java @@ -1,195 +1,195 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.io.IOException; - -import javax.servlet.ServletResponseWrapper; - -/** - * - * Provides a convenient implementation of the HttpServletResponse interface that - * can be subclassed by developers wishing to adapt the response from a Servlet. - * This class implements the Wrapper or Decorator pattern. Methods default to - * calling through to the wrapped response object. - * - * @author Various - * @version $Version$ - * @since v 2.3 - * - * @see javax.servlet.http.HttpServletResponse - * - */ - -public class HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse { - - - /** - * Constructs a response adaptor wrapping the given response. - * @throws java.lang.IllegalArgumentException if the response is null - */ - public HttpServletResponseWrapper(HttpServletResponse response) { - super(response); - } - - private HttpServletResponse _getHttpServletResponse() { - return (HttpServletResponse) super.getResponse(); - } - - /** - * The default behavior of this method is to call addCookie(Cookie cookie) - * on the wrapped response object. - */ - public void addCookie(Cookie cookie) { - this._getHttpServletResponse().addCookie(cookie); - } - - /** - * The default behavior of this method is to call containsHeader(String name) - * on the wrapped response object. - */ - - - public boolean containsHeader(String name) { - return this._getHttpServletResponse().containsHeader(name); - } - - /** - * The default behavior of this method is to call encodeURL(String url) - * on the wrapped response object. - */ - public String encodeURL(String url) { - return this._getHttpServletResponse().encodeURL(url); - } - - /** - * The default behavior of this method is to return encodeRedirectURL(String url) - * on the wrapped response object. - */ - public String encodeRedirectURL(String url) { - return this._getHttpServletResponse().encodeRedirectURL(url); - } - - /** - * The default behavior of this method is to call encodeUrl(String url) - * on the wrapped response object. - */ - public String encodeUrl(String url) { - return this._getHttpServletResponse().encodeUrl(url); - } - - /** - * The default behavior of this method is to return encodeRedirectUrl(String url) - * on the wrapped response object. - */ - public String encodeRedirectUrl(String url) { - return this._getHttpServletResponse().encodeRedirectUrl(url); - } - - /** - * The default behavior of this method is to call sendError(int sc, String msg) - * on the wrapped response object. - */ - public void sendError(int sc, String msg) throws IOException { - this._getHttpServletResponse().sendError(sc, msg); - } - - /** - * The default behavior of this method is to call sendError(int sc) - * on the wrapped response object. - */ - - - public void sendError(int sc) throws IOException { - this._getHttpServletResponse().sendError(sc); - } - - /** - * The default behavior of this method is to return sendRedirect(String location) - * on the wrapped response object. - */ - public void sendRedirect(String location) throws IOException { - this._getHttpServletResponse().sendRedirect(location); - } - - /** - * The default behavior of this method is to call setDateHeader(String name, long date) - * on the wrapped response object. - */ - public void setDateHeader(String name, long date) { - this._getHttpServletResponse().setDateHeader(name, date); - } - - /** - * The default behavior of this method is to call addDateHeader(String name, long date) - * on the wrapped response object. - */ - public void addDateHeader(String name, long date) { - this._getHttpServletResponse().addDateHeader(name, date); - } - - /** - * The default behavior of this method is to return setHeader(String name, String value) - * on the wrapped response object. - */ - public void setHeader(String name, String value) { - this._getHttpServletResponse().setHeader(name, value); - } - - /** - * The default behavior of this method is to return addHeader(String name, String value) - * on the wrapped response object. - */ - public void addHeader(String name, String value) { - this._getHttpServletResponse().addHeader(name, value); - } - - /** - * The default behavior of this method is to call setIntHeader(String name, int value) - * on the wrapped response object. - */ - public void setIntHeader(String name, int value) { - this._getHttpServletResponse().setIntHeader(name, value); - } - - /** - * The default behavior of this method is to call addIntHeader(String name, int value) - * on the wrapped response object. - */ - public void addIntHeader(String name, int value) { - this._getHttpServletResponse().addIntHeader(name, value); - } - - /** - * The default behavior of this method is to call setStatus(int sc) - * on the wrapped response object. - */ - - - public void setStatus(int sc) { - this._getHttpServletResponse().setStatus(sc); - } - - /** - * The default behavior of this method is to call setStatus(int sc, String sm) - * on the wrapped response object. - */ - public void setStatus(int sc, String sm) { - this._getHttpServletResponse().setStatus(sc, sm); - } - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.io.IOException; + +import javax.servlet.ServletResponseWrapper; + +/** + * + * Provides a convenient implementation of the HttpServletResponse interface that + * can be subclassed by developers wishing to adapt the response from a Servlet. + * This class implements the Wrapper or Decorator pattern. Methods default to + * calling through to the wrapped response object. + * + * @author Various + * @version $Version$ + * @since v 2.3 + * + * @see javax.servlet.http.HttpServletResponse + * + */ + +public class HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse { + + + /** + * Constructs a response adaptor wrapping the given response. + * @throws java.lang.IllegalArgumentException if the response is null + */ + public HttpServletResponseWrapper(HttpServletResponse response) { + super(response); + } + + private HttpServletResponse _getHttpServletResponse() { + return (HttpServletResponse) super.getResponse(); + } + + /** + * The default behavior of this method is to call addCookie(Cookie cookie) + * on the wrapped response object. + */ + public void addCookie(Cookie cookie) { + this._getHttpServletResponse().addCookie(cookie); + } + + /** + * The default behavior of this method is to call containsHeader(String name) + * on the wrapped response object. + */ + + + public boolean containsHeader(String name) { + return this._getHttpServletResponse().containsHeader(name); + } + + /** + * The default behavior of this method is to call encodeURL(String url) + * on the wrapped response object. + */ + public String encodeURL(String url) { + return this._getHttpServletResponse().encodeURL(url); + } + + /** + * The default behavior of this method is to return encodeRedirectURL(String url) + * on the wrapped response object. + */ + public String encodeRedirectURL(String url) { + return this._getHttpServletResponse().encodeRedirectURL(url); + } + + /** + * The default behavior of this method is to call encodeUrl(String url) + * on the wrapped response object. + */ + public String encodeUrl(String url) { + return this._getHttpServletResponse().encodeUrl(url); + } + + /** + * The default behavior of this method is to return encodeRedirectUrl(String url) + * on the wrapped response object. + */ + public String encodeRedirectUrl(String url) { + return this._getHttpServletResponse().encodeRedirectUrl(url); + } + + /** + * The default behavior of this method is to call sendError(int sc, String msg) + * on the wrapped response object. + */ + public void sendError(int sc, String msg) throws IOException { + this._getHttpServletResponse().sendError(sc, msg); + } + + /** + * The default behavior of this method is to call sendError(int sc) + * on the wrapped response object. + */ + + + public void sendError(int sc) throws IOException { + this._getHttpServletResponse().sendError(sc); + } + + /** + * The default behavior of this method is to return sendRedirect(String location) + * on the wrapped response object. + */ + public void sendRedirect(String location) throws IOException { + this._getHttpServletResponse().sendRedirect(location); + } + + /** + * The default behavior of this method is to call setDateHeader(String name, long date) + * on the wrapped response object. + */ + public void setDateHeader(String name, long date) { + this._getHttpServletResponse().setDateHeader(name, date); + } + + /** + * The default behavior of this method is to call addDateHeader(String name, long date) + * on the wrapped response object. + */ + public void addDateHeader(String name, long date) { + this._getHttpServletResponse().addDateHeader(name, date); + } + + /** + * The default behavior of this method is to return setHeader(String name, String value) + * on the wrapped response object. + */ + public void setHeader(String name, String value) { + this._getHttpServletResponse().setHeader(name, value); + } + + /** + * The default behavior of this method is to return addHeader(String name, String value) + * on the wrapped response object. + */ + public void addHeader(String name, String value) { + this._getHttpServletResponse().addHeader(name, value); + } + + /** + * The default behavior of this method is to call setIntHeader(String name, int value) + * on the wrapped response object. + */ + public void setIntHeader(String name, int value) { + this._getHttpServletResponse().setIntHeader(name, value); + } + + /** + * The default behavior of this method is to call addIntHeader(String name, int value) + * on the wrapped response object. + */ + public void addIntHeader(String name, int value) { + this._getHttpServletResponse().addIntHeader(name, value); + } + + /** + * The default behavior of this method is to call setStatus(int sc) + * on the wrapped response object. + */ + + + public void setStatus(int sc) { + this._getHttpServletResponse().setStatus(sc); + } + + /** + * The default behavior of this method is to call setStatus(int sc, String sm) + * on the wrapped response object. + */ + public void setStatus(int sc, String sm) { + this._getHttpServletResponse().setStatus(sc, sm); + } + + +} diff --git a/java/javax/servlet/http/HttpSession.java b/java/javax/servlet/http/HttpSession.java index 973c8c846..295797595 100644 --- a/java/javax/servlet/http/HttpSession.java +++ b/java/javax/servlet/http/HttpSession.java @@ -1,423 +1,423 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.util.Enumeration; -import javax.servlet.ServletContext; - -/** - * - * Provides a way to identify a user across more than one page - * request or visit to a Web site and to store information about that user. - * - *

The servlet container uses this interface to create a session - * between an HTTP client and an HTTP server. The session persists - * for a specified time period, across more than one connection or - * page request from the user. A session usually corresponds to one - * user, who may visit a site many times. The server can maintain a - * session in many ways such as using cookies or rewriting URLs. - * - *

This interface allows servlets to - *

    - *
  • View and manipulate information about a session, such as - * the session identifier, creation time, and last accessed time - *
  • Bind objects to sessions, allowing user information to persist - * across multiple user connections - *
- * - *

When an application stores an object in or removes an object from a - * session, the session checks whether the object implements - * {@link HttpSessionBindingListener}. If it does, - * the servlet notifies the object that it has been bound to or unbound - * from the session. Notifications are sent after the binding methods complete. - * For session that are invalidated or expire, notifications are sent after - * the session has been invalidated or expired. - * - *

When container migrates a session between VMs in a distributed container - * setting, all session attributes implementing the {@link HttpSessionActivationListener} - * interface are notified. - * - *

A servlet should be able to handle cases in which - * the client does not choose to join a session, such as when cookies are - * intentionally turned off. Until the client joins the session, - * isNew returns true. If the client chooses - * not to join - * the session, getSession will return a different session - * on each request, and isNew will always return - * true. - * - *

Session information is scoped only to the current web application - * (ServletContext), so information stored in one context - * will not be directly visible in another. - * - * @author Various - * @version $Version$ - * - * - * @see HttpSessionBindingListener - * @see HttpSessionContext - * - */ - -public interface HttpSession { - - - - - /** - * - * Returns the time when this session was created, measured - * in milliseconds since midnight January 1, 1970 GMT. - * - * @return a long specifying - * when this session was created, - * expressed in - * milliseconds since 1/1/1970 GMT - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public long getCreationTime(); - - - - - /** - * - * Returns a string containing the unique identifier assigned - * to this session. The identifier is assigned - * by the servlet container and is implementation dependent. - * - * @return a string specifying the identifier - * assigned to this session - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public String getId(); - - - - - /** - * - * Returns the last time the client sent a request associated with - * this session, as the number of milliseconds since midnight - * January 1, 1970 GMT, and marked by the time the container received the request. - * - *

Actions that your application takes, such as getting or setting - * a value associated with the session, do not affect the access - * time. - * - * @return a long - * representing the last time - * the client sent a request associated - * with this session, expressed in - * milliseconds since 1/1/1970 GMT - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public long getLastAccessedTime(); - - - /** - * Returns the ServletContext to which this session belongs. - * - * @return The ServletContext object for the web application - * @since 2.3 - */ - - public ServletContext getServletContext(); - - - /** - * - * Specifies the time, in seconds, between client requests before the - * servlet container will invalidate this session. A negative time - * indicates the session should never timeout. - * - * @param interval An integer specifying the number - * of seconds - * - */ - - public void setMaxInactiveInterval(int interval); - - - - - /** - * Returns the maximum time interval, in seconds, that - * the servlet container will keep this session open between - * client accesses. After this interval, the servlet container - * will invalidate the session. The maximum time interval can be set - * with the setMaxInactiveInterval method. - * A negative time indicates the session should never timeout. - * - * - * @return an integer specifying the number of - * seconds this session remains open - * between client requests - * - * @see #setMaxInactiveInterval - * - * - */ - - public int getMaxInactiveInterval(); - - - - - /** - * - * @deprecated As of Version 2.1, this method is - * deprecated and has no replacement. - * It will be removed in a future - * version of the Java Servlet API. - * - */ - - public HttpSessionContext getSessionContext(); - - - - - /** - * - * Returns the object bound with the specified name in this session, or - * null if no object is bound under the name. - * - * @param name a string specifying the name of the object - * - * @return the object with the specified name - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public Object getAttribute(String name); - - - - - /** - * - * @deprecated As of Version 2.2, this method is - * replaced by {@link #getAttribute}. - * - * @param name a string specifying the name of the object - * - * @return the object with the specified name - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public Object getValue(String name); - - - - - /** - * - * Returns an Enumeration of String objects - * containing the names of all the objects bound to this session. - * - * @return an Enumeration of - * String objects specifying the - * names of all the objects bound to - * this session - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public Enumeration getAttributeNames(); - - - - - /** - * - * @deprecated As of Version 2.2, this method is - * replaced by {@link #getAttributeNames} - * - * @return an array of String - * objects specifying the - * names of all the objects bound to - * this session - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public String[] getValueNames(); - - - - - /** - * Binds an object to this session, using the name specified. - * If an object of the same name is already bound to the session, - * the object is replaced. - * - *

After this method executes, and if the new object - * implements HttpSessionBindingListener, - * the container calls - * HttpSessionBindingListener.valueBound. The container then - * notifies any HttpSessionAttributeListeners in the web - * application. - - *

If an object was already bound to this session of this name - * that implements HttpSessionBindingListener, its - * HttpSessionBindingListener.valueUnbound method is called. - * - *

If the value passed in is null, this has the same effect as calling - * removeAttribute(). - * - * - * @param name the name to which the object is bound; - * cannot be null - * - * @param value the object to be bound - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public void setAttribute(String name, Object value); - - - - - - /** - * - * @deprecated As of Version 2.2, this method is - * replaced by {@link #setAttribute} - * - * @param name the name to which the object is bound; - * cannot be null - * - * @param value the object to be bound; cannot be null - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - */ - - public void putValue(String name, Object value); - - - - - - /** - * - * Removes the object bound with the specified name from - * this session. If the session does not have an object - * bound with the specified name, this method does nothing. - * - *

After this method executes, and if the object - * implements HttpSessionBindingListener, - * the container calls - * HttpSessionBindingListener.valueUnbound. The container - * then notifies any HttpSessionAttributeListeners in the web - * application. - * - * - * - * @param name the name of the object to - * remove from this session - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - - public void removeAttribute(String name); - - - - - - /** - * - * @deprecated As of Version 2.2, this method is - * replaced by {@link #removeAttribute} - * - * @param name the name of the object to - * remove from this session - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - - public void removeValue(String name); - - - - - /** - * - * Invalidates this session then unbinds any objects bound - * to it. - * - * @exception IllegalStateException if this method is called on an - * already invalidated session - * - */ - - public void invalidate(); - - - - - /** - * - * Returns true if the client does not yet know about the - * session or if the client chooses not to join the session. For - * example, if the server used only cookie-based sessions, and - * the client had disabled the use of cookies, then a session would - * be new on each request. - * - * @return true if the - * server has created a session, - * but the client has not yet joined - * - * @exception IllegalStateException if this method is called on an - * already invalidated session - * - */ - - public boolean isNew(); - - - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.util.Enumeration; +import javax.servlet.ServletContext; + +/** + * + * Provides a way to identify a user across more than one page + * request or visit to a Web site and to store information about that user. + * + *

The servlet container uses this interface to create a session + * between an HTTP client and an HTTP server. The session persists + * for a specified time period, across more than one connection or + * page request from the user. A session usually corresponds to one + * user, who may visit a site many times. The server can maintain a + * session in many ways such as using cookies or rewriting URLs. + * + *

This interface allows servlets to + *

    + *
  • View and manipulate information about a session, such as + * the session identifier, creation time, and last accessed time + *
  • Bind objects to sessions, allowing user information to persist + * across multiple user connections + *
+ * + *

When an application stores an object in or removes an object from a + * session, the session checks whether the object implements + * {@link HttpSessionBindingListener}. If it does, + * the servlet notifies the object that it has been bound to or unbound + * from the session. Notifications are sent after the binding methods complete. + * For session that are invalidated or expire, notifications are sent after + * the session has been invalidated or expired. + * + *

When container migrates a session between VMs in a distributed container + * setting, all session attributes implementing the {@link HttpSessionActivationListener} + * interface are notified. + * + *

A servlet should be able to handle cases in which + * the client does not choose to join a session, such as when cookies are + * intentionally turned off. Until the client joins the session, + * isNew returns true. If the client chooses + * not to join + * the session, getSession will return a different session + * on each request, and isNew will always return + * true. + * + *

Session information is scoped only to the current web application + * (ServletContext), so information stored in one context + * will not be directly visible in another. + * + * @author Various + * @version $Version$ + * + * + * @see HttpSessionBindingListener + * @see HttpSessionContext + * + */ + +public interface HttpSession { + + + + + /** + * + * Returns the time when this session was created, measured + * in milliseconds since midnight January 1, 1970 GMT. + * + * @return a long specifying + * when this session was created, + * expressed in + * milliseconds since 1/1/1970 GMT + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public long getCreationTime(); + + + + + /** + * + * Returns a string containing the unique identifier assigned + * to this session. The identifier is assigned + * by the servlet container and is implementation dependent. + * + * @return a string specifying the identifier + * assigned to this session + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public String getId(); + + + + + /** + * + * Returns the last time the client sent a request associated with + * this session, as the number of milliseconds since midnight + * January 1, 1970 GMT, and marked by the time the container received the request. + * + *

Actions that your application takes, such as getting or setting + * a value associated with the session, do not affect the access + * time. + * + * @return a long + * representing the last time + * the client sent a request associated + * with this session, expressed in + * milliseconds since 1/1/1970 GMT + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public long getLastAccessedTime(); + + + /** + * Returns the ServletContext to which this session belongs. + * + * @return The ServletContext object for the web application + * @since 2.3 + */ + + public ServletContext getServletContext(); + + + /** + * + * Specifies the time, in seconds, between client requests before the + * servlet container will invalidate this session. A negative time + * indicates the session should never timeout. + * + * @param interval An integer specifying the number + * of seconds + * + */ + + public void setMaxInactiveInterval(int interval); + + + + + /** + * Returns the maximum time interval, in seconds, that + * the servlet container will keep this session open between + * client accesses. After this interval, the servlet container + * will invalidate the session. The maximum time interval can be set + * with the setMaxInactiveInterval method. + * A negative time indicates the session should never timeout. + * + * + * @return an integer specifying the number of + * seconds this session remains open + * between client requests + * + * @see #setMaxInactiveInterval + * + * + */ + + public int getMaxInactiveInterval(); + + + + + /** + * + * @deprecated As of Version 2.1, this method is + * deprecated and has no replacement. + * It will be removed in a future + * version of the Java Servlet API. + * + */ + + public HttpSessionContext getSessionContext(); + + + + + /** + * + * Returns the object bound with the specified name in this session, or + * null if no object is bound under the name. + * + * @param name a string specifying the name of the object + * + * @return the object with the specified name + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public Object getAttribute(String name); + + + + + /** + * + * @deprecated As of Version 2.2, this method is + * replaced by {@link #getAttribute}. + * + * @param name a string specifying the name of the object + * + * @return the object with the specified name + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public Object getValue(String name); + + + + + /** + * + * Returns an Enumeration of String objects + * containing the names of all the objects bound to this session. + * + * @return an Enumeration of + * String objects specifying the + * names of all the objects bound to + * this session + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public Enumeration getAttributeNames(); + + + + + /** + * + * @deprecated As of Version 2.2, this method is + * replaced by {@link #getAttributeNames} + * + * @return an array of String + * objects specifying the + * names of all the objects bound to + * this session + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public String[] getValueNames(); + + + + + /** + * Binds an object to this session, using the name specified. + * If an object of the same name is already bound to the session, + * the object is replaced. + * + *

After this method executes, and if the new object + * implements HttpSessionBindingListener, + * the container calls + * HttpSessionBindingListener.valueBound. The container then + * notifies any HttpSessionAttributeListeners in the web + * application. + + *

If an object was already bound to this session of this name + * that implements HttpSessionBindingListener, its + * HttpSessionBindingListener.valueUnbound method is called. + * + *

If the value passed in is null, this has the same effect as calling + * removeAttribute(). + * + * + * @param name the name to which the object is bound; + * cannot be null + * + * @param value the object to be bound + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public void setAttribute(String name, Object value); + + + + + + /** + * + * @deprecated As of Version 2.2, this method is + * replaced by {@link #setAttribute} + * + * @param name the name to which the object is bound; + * cannot be null + * + * @param value the object to be bound; cannot be null + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + */ + + public void putValue(String name, Object value); + + + + + + /** + * + * Removes the object bound with the specified name from + * this session. If the session does not have an object + * bound with the specified name, this method does nothing. + * + *

After this method executes, and if the object + * implements HttpSessionBindingListener, + * the container calls + * HttpSessionBindingListener.valueUnbound. The container + * then notifies any HttpSessionAttributeListeners in the web + * application. + * + * + * + * @param name the name of the object to + * remove from this session + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + + public void removeAttribute(String name); + + + + + + /** + * + * @deprecated As of Version 2.2, this method is + * replaced by {@link #removeAttribute} + * + * @param name the name of the object to + * remove from this session + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + + public void removeValue(String name); + + + + + /** + * + * Invalidates this session then unbinds any objects bound + * to it. + * + * @exception IllegalStateException if this method is called on an + * already invalidated session + * + */ + + public void invalidate(); + + + + + /** + * + * Returns true if the client does not yet know about the + * session or if the client chooses not to join the session. For + * example, if the server used only cookie-based sessions, and + * the client had disabled the use of cookies, then a session would + * be new on each request. + * + * @return true if the + * server has created a session, + * but the client has not yet joined + * + * @exception IllegalStateException if this method is called on an + * already invalidated session + * + */ + + public boolean isNew(); + + + +} + diff --git a/java/javax/servlet/http/HttpSessionActivationListener.java b/java/javax/servlet/http/HttpSessionActivationListener.java index 4f1a4370b..95963ae29 100644 --- a/java/javax/servlet/http/HttpSessionActivationListener.java +++ b/java/javax/servlet/http/HttpSessionActivationListener.java @@ -1,36 +1,36 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.util.EventListener; - - /** Objects that are bound to a session may listen to container - ** events notifying them that sessions will be passivated and that - ** session will be activated. A container that migrates session between VMs - ** or persists sessions is required to notify all attributes bound to sessions - ** implementing HttpSessionActivationListener. - ** - * @since 2.3 - */ - -public interface HttpSessionActivationListener extends EventListener { - - /** Notification that the session is about to be passivated.*/ - public void sessionWillPassivate(HttpSessionEvent se); - /** Notification that the session has just been activated.*/ - public void sessionDidActivate(HttpSessionEvent se); -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.util.EventListener; + + /** Objects that are bound to a session may listen to container + ** events notifying them that sessions will be passivated and that + ** session will be activated. A container that migrates session between VMs + ** or persists sessions is required to notify all attributes bound to sessions + ** implementing HttpSessionActivationListener. + ** + * @since 2.3 + */ + +public interface HttpSessionActivationListener extends EventListener { + + /** Notification that the session is about to be passivated.*/ + public void sessionWillPassivate(HttpSessionEvent se); + /** Notification that the session has just been activated.*/ + public void sessionDidActivate(HttpSessionEvent se); +} + diff --git a/java/javax/servlet/http/HttpSessionAttributeListener.java b/java/javax/servlet/http/HttpSessionAttributeListener.java index e83333a58..b70e9f58c 100644 --- a/java/javax/servlet/http/HttpSessionAttributeListener.java +++ b/java/javax/servlet/http/HttpSessionAttributeListener.java @@ -1,35 +1,35 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.util.EventListener; - - /** This listener interface can be implemented in order to - * get notifications of changes to the attribute lists of sessions within - * this web application. - * @since v 2.3 -*/ - -public interface HttpSessionAttributeListener extends EventListener { - /** Notification that an attribute has been added to a session. Called after the attribute is added.*/ - public void attributeAdded ( HttpSessionBindingEvent se ); - /** Notification that an attribute has been removed from a session. Called after the attribute is removed. */ - public void attributeRemoved ( HttpSessionBindingEvent se ); - /** Notification that an attribute has been replaced in a session. Called after the attribute is replaced. */ - public void attributeReplaced ( HttpSessionBindingEvent se ); - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.util.EventListener; + + /** This listener interface can be implemented in order to + * get notifications of changes to the attribute lists of sessions within + * this web application. + * @since v 2.3 +*/ + +public interface HttpSessionAttributeListener extends EventListener { + /** Notification that an attribute has been added to a session. Called after the attribute is added.*/ + public void attributeAdded ( HttpSessionBindingEvent se ); + /** Notification that an attribute has been removed from a session. Called after the attribute is removed. */ + public void attributeRemoved ( HttpSessionBindingEvent se ); + /** Notification that an attribute has been replaced in a session. Called after the attribute is replaced. */ + public void attributeReplaced ( HttpSessionBindingEvent se ); + +} + diff --git a/java/javax/servlet/http/HttpSessionBindingEvent.java b/java/javax/servlet/http/HttpSessionBindingEvent.java index 76c18d8d3..5e84f32cf 100644 --- a/java/javax/servlet/http/HttpSessionBindingEvent.java +++ b/java/javax/servlet/http/HttpSessionBindingEvent.java @@ -1,151 +1,151 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.http; - - - -/** - * - * Events of this type are either sent to an object that implements - * {@link HttpSessionBindingListener} when it is bound or - * unbound from a session, or to a {@link HttpSessionAttributeListener} - * that has been configured in the deployment descriptor when any attribute is - * bound, unbound or replaced in a session. - * - *

The session binds the object by a call to - * HttpSession.setAttribute and unbinds the object - * by a call to HttpSession.removeAttribute. - * - * - * - * @author Various - * @version $Version$ - * - * @see HttpSession - * @see HttpSessionBindingListener - * @see HttpSessionAttributeListener - */ - -public class HttpSessionBindingEvent extends HttpSessionEvent { - - - - - /* The name to which the object is being bound or unbound */ - - private String name; - - /* The object is being bound or unbound */ - - private Object value; - - - - /** - * - * Constructs an event that notifies an object that it - * has been bound to or unbound from a session. - * To receive the event, the object must implement - * {@link HttpSessionBindingListener}. - * - * - * - * @param session the session to which the object is bound or unbound - * - * @param name the name with which the object is bound or unbound - * - * @see #getName - * @see #getSession - * - */ - - public HttpSessionBindingEvent(HttpSession session, String name) { - super(session); - this.name = name; - } - - /** - * - * Constructs an event that notifies an object that it - * has been bound to or unbound from a session. - * To receive the event, the object must implement - * {@link HttpSessionBindingListener}. - * - * - * - * @param session the session to which the object is bound or unbound - * - * @param name the name with which the object is bound or unbound - * - * @see #getName - * @see #getSession - * - */ - - public HttpSessionBindingEvent(HttpSession session, String name, Object value) { - super(session); - this.name = name; - this.value = value; - } - - - /** Return the session that changed. */ - public HttpSession getSession () { - return super.getSession(); - } - - - - - /** - * - * Returns the name with which the attribute is bound to or - * unbound from the session. - * - * - * @return a string specifying the name with which - * the object is bound to or unbound from - * the session - * - * - */ - - public String getName() { - return name; - } - - /** - * Returns the value of the attribute that has been added, removed or replaced. - * If the attribute was added (or bound), this is the value of the attribute. If the attribute was - * removed (or unbound), this is the value of the removed attribute. If the attribute was replaced, this - * is the old value of the attribute. - * - * @since 2.3 - */ - - public Object getValue() { - return this.value; - } - -} - - - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.http; + + + +/** + * + * Events of this type are either sent to an object that implements + * {@link HttpSessionBindingListener} when it is bound or + * unbound from a session, or to a {@link HttpSessionAttributeListener} + * that has been configured in the deployment descriptor when any attribute is + * bound, unbound or replaced in a session. + * + *

The session binds the object by a call to + * HttpSession.setAttribute and unbinds the object + * by a call to HttpSession.removeAttribute. + * + * + * + * @author Various + * @version $Version$ + * + * @see HttpSession + * @see HttpSessionBindingListener + * @see HttpSessionAttributeListener + */ + +public class HttpSessionBindingEvent extends HttpSessionEvent { + + + + + /* The name to which the object is being bound or unbound */ + + private String name; + + /* The object is being bound or unbound */ + + private Object value; + + + + /** + * + * Constructs an event that notifies an object that it + * has been bound to or unbound from a session. + * To receive the event, the object must implement + * {@link HttpSessionBindingListener}. + * + * + * + * @param session the session to which the object is bound or unbound + * + * @param name the name with which the object is bound or unbound + * + * @see #getName + * @see #getSession + * + */ + + public HttpSessionBindingEvent(HttpSession session, String name) { + super(session); + this.name = name; + } + + /** + * + * Constructs an event that notifies an object that it + * has been bound to or unbound from a session. + * To receive the event, the object must implement + * {@link HttpSessionBindingListener}. + * + * + * + * @param session the session to which the object is bound or unbound + * + * @param name the name with which the object is bound or unbound + * + * @see #getName + * @see #getSession + * + */ + + public HttpSessionBindingEvent(HttpSession session, String name, Object value) { + super(session); + this.name = name; + this.value = value; + } + + + /** Return the session that changed. */ + public HttpSession getSession () { + return super.getSession(); + } + + + + + /** + * + * Returns the name with which the attribute is bound to or + * unbound from the session. + * + * + * @return a string specifying the name with which + * the object is bound to or unbound from + * the session + * + * + */ + + public String getName() { + return name; + } + + /** + * Returns the value of the attribute that has been added, removed or replaced. + * If the attribute was added (or bound), this is the value of the attribute. If the attribute was + * removed (or unbound), this is the value of the removed attribute. If the attribute was replaced, this + * is the old value of the attribute. + * + * @since 2.3 + */ + + public Object getValue() { + return this.value; + } + +} + + + + + + + diff --git a/java/javax/servlet/http/HttpSessionBindingListener.java b/java/javax/servlet/http/HttpSessionBindingListener.java index bf31092cb..a07674409 100644 --- a/java/javax/servlet/http/HttpSessionBindingListener.java +++ b/java/javax/servlet/http/HttpSessionBindingListener.java @@ -1,77 +1,77 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.http; - -import java.util.EventListener; - - - - - -/** - * Causes an object to be notified when it is bound to - * or unbound from a session. The object is notified - * by an {@link HttpSessionBindingEvent} object. This may be as a result - * of a servlet programmer explicitly unbinding an attribute from a session, - * due to a session being invalidated, or due to a session timing out. - * - * - * @author Various - * @version $Version$ - * - * @see HttpSession - * @see HttpSessionBindingEvent - * - */ - -public interface HttpSessionBindingListener extends EventListener { - - - - /** - * - * Notifies the object that it is being bound to - * a session and identifies the session. - * - * @param event the event that identifies the - * session - * - * @see #valueUnbound - * - */ - - public void valueBound(HttpSessionBindingEvent event); - - - - /** - * - * Notifies the object that it is being unbound - * from a session and identifies the session. - * - * @param event the event that identifies - * the session - * - * @see #valueBound - * - */ - - public void valueUnbound(HttpSessionBindingEvent event); - - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.http; + +import java.util.EventListener; + + + + + +/** + * Causes an object to be notified when it is bound to + * or unbound from a session. The object is notified + * by an {@link HttpSessionBindingEvent} object. This may be as a result + * of a servlet programmer explicitly unbinding an attribute from a session, + * due to a session being invalidated, or due to a session timing out. + * + * + * @author Various + * @version $Version$ + * + * @see HttpSession + * @see HttpSessionBindingEvent + * + */ + +public interface HttpSessionBindingListener extends EventListener { + + + + /** + * + * Notifies the object that it is being bound to + * a session and identifies the session. + * + * @param event the event that identifies the + * session + * + * @see #valueUnbound + * + */ + + public void valueBound(HttpSessionBindingEvent event); + + + + /** + * + * Notifies the object that it is being unbound + * from a session and identifies the session. + * + * @param event the event that identifies + * the session + * + * @see #valueBound + * + */ + + public void valueUnbound(HttpSessionBindingEvent event); + + +} + diff --git a/java/javax/servlet/http/HttpSessionContext.java b/java/javax/servlet/http/HttpSessionContext.java index acaf64894..dd7bfe6e4 100644 --- a/java/javax/servlet/http/HttpSessionContext.java +++ b/java/javax/servlet/http/HttpSessionContext.java @@ -1,70 +1,70 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.http; - -import java.util.Enumeration; - -/** - * - * @author Various - * @version $Version$ - * - * @deprecated As of Java(tm) Servlet API 2.1 - * for security reasons, with no replacement. - * This interface will be removed in a future - * version of this API. - * - * @see HttpSession - * @see HttpSessionBindingEvent - * @see HttpSessionBindingListener - * - */ - - -public interface HttpSessionContext { - - /** - * - * @deprecated As of Java Servlet API 2.1 with - * no replacement. This method must - * return null and will be removed in - * a future version of this API. - * - */ - - public HttpSession getSession(String sessionId); - - - - - /** - * - * @deprecated As of Java Servlet API 2.1 with - * no replacement. This method must return - * an empty Enumeration and will be removed - * in a future version of this API. - * - */ - - public Enumeration getIds(); -} - - - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.http; + +import java.util.Enumeration; + +/** + * + * @author Various + * @version $Version$ + * + * @deprecated As of Java(tm) Servlet API 2.1 + * for security reasons, with no replacement. + * This interface will be removed in a future + * version of this API. + * + * @see HttpSession + * @see HttpSessionBindingEvent + * @see HttpSessionBindingListener + * + */ + + +public interface HttpSessionContext { + + /** + * + * @deprecated As of Java Servlet API 2.1 with + * no replacement. This method must + * return null and will be removed in + * a future version of this API. + * + */ + + public HttpSession getSession(String sessionId); + + + + + /** + * + * @deprecated As of Java Servlet API 2.1 with + * no replacement. This method must return + * an empty Enumeration and will be removed + * in a future version of this API. + * + */ + + public Enumeration getIds(); +} + + + + + diff --git a/java/javax/servlet/http/HttpSessionEvent.java b/java/javax/servlet/http/HttpSessionEvent.java index fe39428d8..8aa85f9a5 100644 --- a/java/javax/servlet/http/HttpSessionEvent.java +++ b/java/javax/servlet/http/HttpSessionEvent.java @@ -1,33 +1,33 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - - - /** This is the class representing event notifications for - * changes to sessions within a web application. - * @since v 2.3 - */ -public class HttpSessionEvent extends java.util.EventObject { - /** Construct a session event from the given source.*/ - public HttpSessionEvent(HttpSession source) { - super(source); -} - /** Return the session that changed.*/ - public HttpSession getSession () { - return (HttpSession) super.getSource(); - } -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + + + /** This is the class representing event notifications for + * changes to sessions within a web application. + * @since v 2.3 + */ +public class HttpSessionEvent extends java.util.EventObject { + /** Construct a session event from the given source.*/ + public HttpSessionEvent(HttpSession source) { + super(source); +} + /** Return the session that changed.*/ + public HttpSession getSession () { + return (HttpSession) super.getSource(); + } +} + diff --git a/java/javax/servlet/http/HttpSessionListener.java b/java/javax/servlet/http/HttpSessionListener.java index 6f2c7e3b3..b1a922481 100644 --- a/java/javax/servlet/http/HttpSessionListener.java +++ b/java/javax/servlet/http/HttpSessionListener.java @@ -1,44 +1,44 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.http; - -import java.util.EventListener; - - /** - * Implementations of this interface are notified of changes to the - * list of active sessions in a web application. - * To receive notification events, the implementation class - * must be configured in the deployment descriptor for the web application. - * @see HttpSessionEvent - * @since v 2.3 - */ - -public interface HttpSessionListener extends EventListener { - - /** - * Notification that a session was created. - * @param se the notification event - */ - public void sessionCreated ( HttpSessionEvent se ); - - /** - * Notification that a session is about to be invalidated. - * @param se the notification event - */ - public void sessionDestroyed ( HttpSessionEvent se ); - -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.http; + +import java.util.EventListener; + + /** + * Implementations of this interface are notified of changes to the + * list of active sessions in a web application. + * To receive notification events, the implementation class + * must be configured in the deployment descriptor for the web application. + * @see HttpSessionEvent + * @since v 2.3 + */ + +public interface HttpSessionListener extends EventListener { + + /** + * Notification that a session was created. + * @param se the notification event + */ + public void sessionCreated ( HttpSessionEvent se ); + + /** + * Notification that a session is about to be invalidated. + * @param se the notification event + */ + public void sessionDestroyed ( HttpSessionEvent se ); + +} + diff --git a/java/javax/servlet/http/HttpUtils.java b/java/javax/servlet/http/HttpUtils.java index bee397b89..abc5d90d0 100644 --- a/java/javax/servlet/http/HttpUtils.java +++ b/java/javax/servlet/http/HttpUtils.java @@ -1,306 +1,306 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.http; - -import javax.servlet.ServletInputStream; -import java.util.Hashtable; -import java.util.ResourceBundle; -import java.util.StringTokenizer; -import java.io.IOException; - -/** - * @deprecated As of Java(tm) Servlet API 2.3. - * These methods were only useful - * with the default encoding and have been moved - * to the request interfaces. - * -*/ - - -public class HttpUtils { - - private static final String LSTRING_FILE = - "javax.servlet.http.LocalStrings"; - private static ResourceBundle lStrings = - ResourceBundle.getBundle(LSTRING_FILE); - - - - /** - * Constructs an empty HttpUtils object. - * - */ - - public HttpUtils() {} - - - - - - /** - * - * Parses a query string passed from the client to the - * server and builds a HashTable object - * with key-value pairs. - * The query string should be in the form of a string - * packaged by the GET or POST method, that is, it - * should have key-value pairs in the form key=value, - * with each pair separated from the next by a & character. - * - *

A key can appear more than once in the query string - * with different values. However, the key appears only once in - * the hashtable, with its value being - * an array of strings containing the multiple values sent - * by the query string. - * - *

The keys and values in the hashtable are stored in their - * decoded form, so - * any + characters are converted to spaces, and characters - * sent in hexadecimal notation (like %xx) are - * converted to ASCII characters. - * - * @param s a string containing the query to be parsed - * - * @return a HashTable object built - * from the parsed key-value pairs - * - * @exception IllegalArgumentException if the query string - * is invalid - * - */ - - static public Hashtable parseQueryString(String s) { - - String valArray[] = null; - - if (s == null) { - throw new IllegalArgumentException(); - } - Hashtable ht = new Hashtable(); - StringBuffer sb = new StringBuffer(); - StringTokenizer st = new StringTokenizer(s, "&"); - while (st.hasMoreTokens()) { - String pair = (String)st.nextToken(); - int pos = pair.indexOf('='); - if (pos == -1) { - // XXX - // should give more detail about the illegal argument - throw new IllegalArgumentException(); - } - String key = parseName(pair.substring(0, pos), sb); - String val = parseName(pair.substring(pos+1, pair.length()), sb); - if (ht.containsKey(key)) { - String oldVals[] = (String []) ht.get(key); - valArray = new String[oldVals.length + 1]; - for (int i = 0; i < oldVals.length; i++) - valArray[i] = oldVals[i]; - valArray[oldVals.length] = val; - } else { - valArray = new String[1]; - valArray[0] = val; - } - ht.put(key, valArray); - } - return ht; - } - - - - - /** - * - * Parses data from an HTML form that the client sends to - * the server using the HTTP POST method and the - * application/x-www-form-urlencoded MIME type. - * - *

The data sent by the POST method contains key-value - * pairs. A key can appear more than once in the POST data - * with different values. However, the key appears only once in - * the hashtable, with its value being - * an array of strings containing the multiple values sent - * by the POST method. - * - *

The keys and values in the hashtable are stored in their - * decoded form, so - * any + characters are converted to spaces, and characters - * sent in hexadecimal notation (like %xx) are - * converted to ASCII characters. - * - * - * - * @param len an integer specifying the length, - * in characters, of the - * ServletInputStream - * object that is also passed to this - * method - * - * @param in the ServletInputStream - * object that contains the data sent - * from the client - * - * @return a HashTable object built - * from the parsed key-value pairs - * - * - * @exception IllegalArgumentException if the data - * sent by the POST method is invalid - * - */ - - - static public Hashtable parsePostData(int len, - ServletInputStream in) - { - // XXX - // should a length of 0 be an IllegalArgumentException - - if (len <=0) - return new Hashtable(); // cheap hack to return an empty hash - - if (in == null) { - throw new IllegalArgumentException(); - } - - // - // Make sure we read the entire POSTed body. - // - byte[] postedBytes = new byte [len]; - try { - int offset = 0; - - do { - int inputLen = in.read (postedBytes, offset, len - offset); - if (inputLen <= 0) { - String msg = lStrings.getString("err.io.short_read"); - throw new IllegalArgumentException (msg); - } - offset += inputLen; - } while ((len - offset) > 0); - - } catch (IOException e) { - throw new IllegalArgumentException(e.getMessage()); - } - - // XXX we shouldn't assume that the only kind of POST body - // is FORM data encoded using ASCII or ISO Latin/1 ... or - // that the body should always be treated as FORM data. - // - - try { - String postedBody = new String(postedBytes, 0, len, "8859_1"); - return parseQueryString(postedBody); - } catch (java.io.UnsupportedEncodingException e) { - // XXX function should accept an encoding parameter & throw this - // exception. Otherwise throw something expected. - throw new IllegalArgumentException(e.getMessage()); - } - } - - - - - /* - * Parse a name in the query string. - */ - - static private String parseName(String s, StringBuffer sb) { - sb.setLength(0); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - switch (c) { - case '+': - sb.append(' '); - break; - case '%': - try { - sb.append((char) Integer.parseInt(s.substring(i+1, i+3), - 16)); - i += 2; - } catch (NumberFormatException e) { - // XXX - // need to be more specific about illegal arg - throw new IllegalArgumentException(); - } catch (StringIndexOutOfBoundsException e) { - String rest = s.substring(i); - sb.append(rest); - if (rest.length()==2) - i++; - } - - break; - default: - sb.append(c); - break; - } - } - return sb.toString(); - } - - - - - /** - * - * Reconstructs the URL the client used to make the request, - * using information in the HttpServletRequest object. - * The returned URL contains a protocol, server name, port - * number, and server path, but it does not include query - * string parameters. - * - *

Because this method returns a StringBuffer, - * not a string, you can modify the URL easily, for example, - * to append query parameters. - * - *

This method is useful for creating redirect messages - * and for reporting errors. - * - * @param req a HttpServletRequest object - * containing the client's request - * - * @return a StringBuffer object containing - * the reconstructed URL - * - */ - - public static StringBuffer getRequestURL (HttpServletRequest req) { - StringBuffer url = new StringBuffer (); - String scheme = req.getScheme (); - int port = req.getServerPort (); - String urlPath = req.getRequestURI(); - - //String servletPath = req.getServletPath (); - //String pathInfo = req.getPathInfo (); - - url.append (scheme); // http, https - url.append ("://"); - url.append (req.getServerName ()); - if ((scheme.equals ("http") && port != 80) - || (scheme.equals ("https") && port != 443)) { - url.append (':'); - url.append (req.getServerPort ()); - } - //if (servletPath != null) - // url.append (servletPath); - //if (pathInfo != null) - // url.append (pathInfo); - url.append(urlPath); - return url; - } -} - - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.http; + +import javax.servlet.ServletInputStream; +import java.util.Hashtable; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import java.io.IOException; + +/** + * @deprecated As of Java(tm) Servlet API 2.3. + * These methods were only useful + * with the default encoding and have been moved + * to the request interfaces. + * +*/ + + +public class HttpUtils { + + private static final String LSTRING_FILE = + "javax.servlet.http.LocalStrings"; + private static ResourceBundle lStrings = + ResourceBundle.getBundle(LSTRING_FILE); + + + + /** + * Constructs an empty HttpUtils object. + * + */ + + public HttpUtils() {} + + + + + + /** + * + * Parses a query string passed from the client to the + * server and builds a HashTable object + * with key-value pairs. + * The query string should be in the form of a string + * packaged by the GET or POST method, that is, it + * should have key-value pairs in the form key=value, + * with each pair separated from the next by a & character. + * + *

A key can appear more than once in the query string + * with different values. However, the key appears only once in + * the hashtable, with its value being + * an array of strings containing the multiple values sent + * by the query string. + * + *

The keys and values in the hashtable are stored in their + * decoded form, so + * any + characters are converted to spaces, and characters + * sent in hexadecimal notation (like %xx) are + * converted to ASCII characters. + * + * @param s a string containing the query to be parsed + * + * @return a HashTable object built + * from the parsed key-value pairs + * + * @exception IllegalArgumentException if the query string + * is invalid + * + */ + + static public Hashtable parseQueryString(String s) { + + String valArray[] = null; + + if (s == null) { + throw new IllegalArgumentException(); + } + Hashtable ht = new Hashtable(); + StringBuffer sb = new StringBuffer(); + StringTokenizer st = new StringTokenizer(s, "&"); + while (st.hasMoreTokens()) { + String pair = (String)st.nextToken(); + int pos = pair.indexOf('='); + if (pos == -1) { + // XXX + // should give more detail about the illegal argument + throw new IllegalArgumentException(); + } + String key = parseName(pair.substring(0, pos), sb); + String val = parseName(pair.substring(pos+1, pair.length()), sb); + if (ht.containsKey(key)) { + String oldVals[] = (String []) ht.get(key); + valArray = new String[oldVals.length + 1]; + for (int i = 0; i < oldVals.length; i++) + valArray[i] = oldVals[i]; + valArray[oldVals.length] = val; + } else { + valArray = new String[1]; + valArray[0] = val; + } + ht.put(key, valArray); + } + return ht; + } + + + + + /** + * + * Parses data from an HTML form that the client sends to + * the server using the HTTP POST method and the + * application/x-www-form-urlencoded MIME type. + * + *

The data sent by the POST method contains key-value + * pairs. A key can appear more than once in the POST data + * with different values. However, the key appears only once in + * the hashtable, with its value being + * an array of strings containing the multiple values sent + * by the POST method. + * + *

The keys and values in the hashtable are stored in their + * decoded form, so + * any + characters are converted to spaces, and characters + * sent in hexadecimal notation (like %xx) are + * converted to ASCII characters. + * + * + * + * @param len an integer specifying the length, + * in characters, of the + * ServletInputStream + * object that is also passed to this + * method + * + * @param in the ServletInputStream + * object that contains the data sent + * from the client + * + * @return a HashTable object built + * from the parsed key-value pairs + * + * + * @exception IllegalArgumentException if the data + * sent by the POST method is invalid + * + */ + + + static public Hashtable parsePostData(int len, + ServletInputStream in) + { + // XXX + // should a length of 0 be an IllegalArgumentException + + if (len <=0) + return new Hashtable(); // cheap hack to return an empty hash + + if (in == null) { + throw new IllegalArgumentException(); + } + + // + // Make sure we read the entire POSTed body. + // + byte[] postedBytes = new byte [len]; + try { + int offset = 0; + + do { + int inputLen = in.read (postedBytes, offset, len - offset); + if (inputLen <= 0) { + String msg = lStrings.getString("err.io.short_read"); + throw new IllegalArgumentException (msg); + } + offset += inputLen; + } while ((len - offset) > 0); + + } catch (IOException e) { + throw new IllegalArgumentException(e.getMessage()); + } + + // XXX we shouldn't assume that the only kind of POST body + // is FORM data encoded using ASCII or ISO Latin/1 ... or + // that the body should always be treated as FORM data. + // + + try { + String postedBody = new String(postedBytes, 0, len, "8859_1"); + return parseQueryString(postedBody); + } catch (java.io.UnsupportedEncodingException e) { + // XXX function should accept an encoding parameter & throw this + // exception. Otherwise throw something expected. + throw new IllegalArgumentException(e.getMessage()); + } + } + + + + + /* + * Parse a name in the query string. + */ + + static private String parseName(String s, StringBuffer sb) { + sb.setLength(0); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + switch (c) { + case '+': + sb.append(' '); + break; + case '%': + try { + sb.append((char) Integer.parseInt(s.substring(i+1, i+3), + 16)); + i += 2; + } catch (NumberFormatException e) { + // XXX + // need to be more specific about illegal arg + throw new IllegalArgumentException(); + } catch (StringIndexOutOfBoundsException e) { + String rest = s.substring(i); + sb.append(rest); + if (rest.length()==2) + i++; + } + + break; + default: + sb.append(c); + break; + } + } + return sb.toString(); + } + + + + + /** + * + * Reconstructs the URL the client used to make the request, + * using information in the HttpServletRequest object. + * The returned URL contains a protocol, server name, port + * number, and server path, but it does not include query + * string parameters. + * + *

Because this method returns a StringBuffer, + * not a string, you can modify the URL easily, for example, + * to append query parameters. + * + *

This method is useful for creating redirect messages + * and for reporting errors. + * + * @param req a HttpServletRequest object + * containing the client's request + * + * @return a StringBuffer object containing + * the reconstructed URL + * + */ + + public static StringBuffer getRequestURL (HttpServletRequest req) { + StringBuffer url = new StringBuffer (); + String scheme = req.getScheme (); + int port = req.getServerPort (); + String urlPath = req.getRequestURI(); + + //String servletPath = req.getServletPath (); + //String pathInfo = req.getPathInfo (); + + url.append (scheme); // http, https + url.append ("://"); + url.append (req.getServerName ()); + if ((scheme.equals ("http") && port != 80) + || (scheme.equals ("https") && port != 443)) { + url.append (':'); + url.append (req.getServerPort ()); + } + //if (servletPath != null) + // url.append (servletPath); + //if (pathInfo != null) + // url.append (pathInfo); + url.append(urlPath); + return url; + } +} + + + diff --git a/java/javax/servlet/http/LocalStrings.properties b/java/javax/servlet/http/LocalStrings.properties index a12d8ed84..bf4d4c8f8 100644 --- a/java/javax/servlet/http/LocalStrings.properties +++ b/java/javax/servlet/http/LocalStrings.properties @@ -1,27 +1,27 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale en_US - -err.cookie_name_is_token=Cookie name \"{0}\" is a reserved token -err.io.negativelength=Negative Length given in write method -err.io.short_read=Short Read - -http.method_not_implemented=Method {0} is not defined in RFC 2068 and is not supported by the Servlet API - -http.method_get_not_supported=HTTP method GET is not supported by this URL -http.method_post_not_supported=HTTP method POST is not supported by this URL -http.method_put_not_supported=HTTP method PUT is not supported by this URL -http.method_delete_not_supported=Http method DELETE is not supported by this URL +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale en_US + +err.cookie_name_is_token=Cookie name \"{0}\" is a reserved token +err.io.negativelength=Negative Length given in write method +err.io.short_read=Short Read + +http.method_not_implemented=Method {0} is not defined in RFC 2068 and is not supported by the Servlet API + +http.method_get_not_supported=HTTP method GET is not supported by this URL +http.method_post_not_supported=HTTP method POST is not supported by this URL +http.method_put_not_supported=HTTP method PUT is not supported by this URL +http.method_delete_not_supported=Http method DELETE is not supported by this URL diff --git a/java/javax/servlet/http/LocalStrings_es.properties b/java/javax/servlet/http/LocalStrings_es.properties index e186e94e1..36c2c22fa 100644 --- a/java/javax/servlet/http/LocalStrings_es.properties +++ b/java/javax/servlet/http/LocalStrings_es.properties @@ -1,29 +1,29 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# $Id: LocalStrings_es.properties 267129 2004-03-18 16:40:35Z jfarcand $ -# -# Default localized string information -# Localized para Locale es_ES - -err.cookie_name_is_token=El Nombre de Cookie {0} es una palabra reservada -err.io.negativelength=Longitud Negativa en el metodo write -err.io.short_read=Lectura Corta - -http.method_not_implemented=El Metodo {0} no esta definido en la especificacion RFC 2068 y no es soportado por la API Servlet - -http.method_get_not_supported=El Metodo HTTP GET no es soportado por esta URL -http.method_post_not_supported=El Metodo HTTP POST no es soportado por esta URL -http.method_put_not_supported=El Metodo HTTP PUT no es soportado por esta URL -http.method_delete_not_supported=El Metodo HTTP DELETE no es soportado por esta URL +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# $Id: LocalStrings_es.properties 267129 2004-03-18 16:40:35Z jfarcand $ +# +# Default localized string information +# Localized para Locale es_ES + +err.cookie_name_is_token=El Nombre de Cookie {0} es una palabra reservada +err.io.negativelength=Longitud Negativa en el metodo write +err.io.short_read=Lectura Corta + +http.method_not_implemented=El Metodo {0} no esta definido en la especificacion RFC 2068 y no es soportado por la API Servlet + +http.method_get_not_supported=El Metodo HTTP GET no es soportado por esta URL +http.method_post_not_supported=El Metodo HTTP POST no es soportado por esta URL +http.method_put_not_supported=El Metodo HTTP PUT no es soportado por esta URL +http.method_delete_not_supported=El Metodo HTTP DELETE no es soportado por esta URL diff --git a/java/javax/servlet/http/LocalStrings_fr.properties b/java/javax/servlet/http/LocalStrings_fr.properties index e955e41f2..b2bc09cb4 100644 --- a/java/javax/servlet/http/LocalStrings_fr.properties +++ b/java/javax/servlet/http/LocalStrings_fr.properties @@ -1,27 +1,27 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale fr_FR - -err.cookie_name_is_token=Le nom de cookie \"{0}\" est un \"token\" réservé -err.io.negativelength=Taille négative donnée dans la méthode \"write\" -err.io.short_read=Lecture partielle - -http.method_not_implemented=Le méthode {0} n''est pas définie dans la RFC 2068 et n''est pas supportée par l''API Servlet - -http.method_get_not_supported=La méthode HTTP GET n''est pas supportée par cette URL -http.method_post_not_supported=La méthode HTTP POST n''est pas supportée par cette URL -http.method_put_not_supported=La méthode HTTP PUT n''est pas supportée par cette URL -http.method_delete_not_supported=La méthode HTTP DELETE n''est pas supportée par cette URL +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale fr_FR + +err.cookie_name_is_token=Le nom de cookie \"{0}\" est un \"token\" réservé +err.io.negativelength=Taille négative donnée dans la méthode \"write\" +err.io.short_read=Lecture partielle + +http.method_not_implemented=Le méthode {0} n''est pas définie dans la RFC 2068 et n''est pas supportée par l''API Servlet + +http.method_get_not_supported=La méthode HTTP GET n''est pas supportée par cette URL +http.method_post_not_supported=La méthode HTTP POST n''est pas supportée par cette URL +http.method_put_not_supported=La méthode HTTP PUT n''est pas supportée par cette URL +http.method_delete_not_supported=La méthode HTTP DELETE n''est pas supportée par cette URL diff --git a/java/javax/servlet/http/LocalStrings_ja.properties b/java/javax/servlet/http/LocalStrings_ja.properties index dbff17e5a..edfbdd51d 100644 --- a/java/javax/servlet/http/LocalStrings_ja.properties +++ b/java/javax/servlet/http/LocalStrings_ja.properties @@ -1,27 +1,27 @@ -# Copyright 2004 The Apache Software Foundation -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Default localized string information -# Localized for Locale ja_JP - -err.cookie_name_is_token=\u30af\u30c3\u30ad\u30fc\u540d \"{0}\" \u306f\u4e88\u7d04\u6e08\u306e\u30c8\u30fc\u30af\u30f3\u3067\u3059\u3002 -err.io.negativelength=write\u30e1\u30bd\u30c3\u30c9\u306b\u8ca0\u306e\u9577\u3055\u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002 -err.io.short_read=\u8aad\u307f\u8fbc\u307f\u304c\u3059\u3050\u306b\u7d42\u308f\u308a\u307e\u3057\u305f\u3002 - -http.method_not_implemented=\u30e1\u30bd\u30c3\u30c9 {0} \u306fRFC 2068\u306b\u306f\u5b9a\u7fa9\u3055\u308c\u3066\u304a\u3089\u305a\u3001\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8API\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093\u3002 - -http.method_get_not_supported=HTTP\u306eGET\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 -http.method_post_not_supported=HTTP\u306ePOST\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 -http.method_put_not_supported=HTTP\u306ePUT\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 -http.method_delete_not_supported=HTTP\u306eDELETE\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +# Copyright 2004 The Apache Software Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# Default localized string information +# Localized for Locale ja_JP + +err.cookie_name_is_token=\u30af\u30c3\u30ad\u30fc\u540d \"{0}\" \u306f\u4e88\u7d04\u6e08\u306e\u30c8\u30fc\u30af\u30f3\u3067\u3059\u3002 +err.io.negativelength=write\u30e1\u30bd\u30c3\u30c9\u306b\u8ca0\u306e\u9577\u3055\u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002 +err.io.short_read=\u8aad\u307f\u8fbc\u307f\u304c\u3059\u3050\u306b\u7d42\u308f\u308a\u307e\u3057\u305f\u3002 + +http.method_not_implemented=\u30e1\u30bd\u30c3\u30c9 {0} \u306fRFC 2068\u306b\u306f\u5b9a\u7fa9\u3055\u308c\u3066\u304a\u3089\u305a\u3001\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8API\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093\u3002 + +http.method_get_not_supported=HTTP\u306eGET\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +http.method_post_not_supported=HTTP\u306ePOST\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +http.method_put_not_supported=HTTP\u306ePUT\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +http.method_delete_not_supported=HTTP\u306eDELETE\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 diff --git a/java/javax/servlet/http/package.html b/java/javax/servlet/http/package.html index 3b5c6c2e4..efdbdf6ab 100644 --- a/java/javax/servlet/http/package.html +++ b/java/javax/servlet/http/package.html @@ -1,23 +1,23 @@ - - - - - - - - -The javax.servlet.http package contains a number of classes and interfaces -that describe and define the contracts between a servlet class -running under the HTTP protocol and the runtime environment provided -for an instance of such a class by a conforming servlet container. - - - - + + + + + + + + +The javax.servlet.http package contains a number of classes and interfaces +that describe and define the contracts between a servlet class +running under the HTTP protocol and the runtime environment provided +for an instance of such a class by a conforming servlet container. + + + + diff --git a/java/javax/servlet/jsp/ErrorData.java b/java/javax/servlet/jsp/ErrorData.java index f6c623409..e36c07301 100644 --- a/java/javax/servlet/jsp/ErrorData.java +++ b/java/javax/servlet/jsp/ErrorData.java @@ -1,88 +1,88 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -/** - * Contains information about an error, for error pages. - * The information contained in this instance is meaningless if not used - * in the context of an error page. To indicate a JSP is an error page, - * the page author must set the isErrorPage attribute of the page directive - * to "true". - * - * @see PageContext#getErrorData - * @since 2.0 - */ - -public final class ErrorData { - - private Throwable throwable; - private int statusCode; - private String uri; - private String servletName; - - /** - * Creates a new ErrorData object. - * - * @param throwable The Throwable that is the cause of the error - * @param statusCode The status code of the error - * @param uri The request URI - * @param servletName The name of the servlet invoked - */ - public ErrorData( Throwable throwable, int statusCode, String uri, - String servletName ) - { - this.throwable = throwable; - this.statusCode = statusCode; - this.uri = uri; - this.servletName = servletName; - } - - /** - * Returns the Throwable that caused the error. - * - * @return The Throwable that caused the error - */ - public Throwable getThrowable() { - return this.throwable; - } - - /** - * Returns the status code of the error. - * - * @return The status code of the error - */ - public int getStatusCode() { - return this.statusCode; - } - - /** - * Returns the request URI. - * - * @return The request URI - */ - public String getRequestURI() { - return this.uri; - } - - /** - * Returns the name of the servlet invoked. - * - * @return The name of the servlet invoked - */ - public String getServletName() { - return this.servletName; - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +/** + * Contains information about an error, for error pages. + * The information contained in this instance is meaningless if not used + * in the context of an error page. To indicate a JSP is an error page, + * the page author must set the isErrorPage attribute of the page directive + * to "true". + * + * @see PageContext#getErrorData + * @since 2.0 + */ + +public final class ErrorData { + + private Throwable throwable; + private int statusCode; + private String uri; + private String servletName; + + /** + * Creates a new ErrorData object. + * + * @param throwable The Throwable that is the cause of the error + * @param statusCode The status code of the error + * @param uri The request URI + * @param servletName The name of the servlet invoked + */ + public ErrorData( Throwable throwable, int statusCode, String uri, + String servletName ) + { + this.throwable = throwable; + this.statusCode = statusCode; + this.uri = uri; + this.servletName = servletName; + } + + /** + * Returns the Throwable that caused the error. + * + * @return The Throwable that caused the error + */ + public Throwable getThrowable() { + return this.throwable; + } + + /** + * Returns the status code of the error. + * + * @return The status code of the error + */ + public int getStatusCode() { + return this.statusCode; + } + + /** + * Returns the request URI. + * + * @return The request URI + */ + public String getRequestURI() { + return this.uri; + } + + /** + * Returns the name of the servlet invoked. + * + * @return The name of the servlet invoked + */ + public String getServletName() { + return this.servletName; + } +} diff --git a/java/javax/servlet/jsp/HttpJspPage.java b/java/javax/servlet/jsp/HttpJspPage.java index 1568c7ef8..50cd1475d 100644 --- a/java/javax/servlet/jsp/HttpJspPage.java +++ b/java/javax/servlet/jsp/HttpJspPage.java @@ -1,57 +1,57 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp; - -import javax.servlet.*; -import javax.servlet.http.*; -import java.io.IOException; - -/** - * The HttpJspPage interface describes the interaction that a JSP Page - * Implementation Class must satisfy when using the HTTP protocol. - * - *

- * The behaviour is identical to that of the JspPage, except for the signature - * of the _jspService method, which is now expressible in the Java type - * system and included explicitly in the interface. - * - * @see JspPage - */ - -public interface HttpJspPage extends JspPage { - - /** The _jspService()method corresponds to the body of the JSP page. This - * method is defined automatically by the JSP container and should never - * be defined by the JSP page author. - *

- * If a superclass is specified using the extends attribute, that - * superclass may choose to perform some actions in its service() method - * before or after calling the _jspService() method. See using the extends - * attribute in the JSP_Engine chapter of the JSP specification. - * - * @param request Provides client request information to the JSP. - * @param response Assists the JSP in sending a response to the client. - * @throws ServletException Thrown if an error occurred during the - * processing of the JSP and that the container should take - * appropriate action to clean up the request. - * @throws IOException Thrown if an error occurred while writing the - * response for this page. - */ - public void _jspService(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp; + +import javax.servlet.*; +import javax.servlet.http.*; +import java.io.IOException; + +/** + * The HttpJspPage interface describes the interaction that a JSP Page + * Implementation Class must satisfy when using the HTTP protocol. + * + *

+ * The behaviour is identical to that of the JspPage, except for the signature + * of the _jspService method, which is now expressible in the Java type + * system and included explicitly in the interface. + * + * @see JspPage + */ + +public interface HttpJspPage extends JspPage { + + /** The _jspService()method corresponds to the body of the JSP page. This + * method is defined automatically by the JSP container and should never + * be defined by the JSP page author. + *

+ * If a superclass is specified using the extends attribute, that + * superclass may choose to perform some actions in its service() method + * before or after calling the _jspService() method. See using the extends + * attribute in the JSP_Engine chapter of the JSP specification. + * + * @param request Provides client request information to the JSP. + * @param response Assists the JSP in sending a response to the client. + * @throws ServletException Thrown if an error occurred during the + * processing of the JSP and that the container should take + * appropriate action to clean up the request. + * @throws IOException Thrown if an error occurred while writing the + * response for this page. + */ + public void _jspService(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException; +} diff --git a/java/javax/servlet/jsp/JspApplicationContext.java b/java/javax/servlet/jsp/JspApplicationContext.java index a51bf49ee..252ac23a0 100644 --- a/java/javax/servlet/jsp/JspApplicationContext.java +++ b/java/javax/servlet/jsp/JspApplicationContext.java @@ -1,76 +1,76 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -import javax.el.ELContextListener; -import javax.el.ELResolver; -import javax.el.ExpressionFactory; - -/** - *

- * Stores application-scoped information for the JSP container. - *

- * @since 2.1 - */ -public interface JspApplicationContext { - - /** - *

- * Registers an ELContextListener that will notified whenever - * a new ELContext is created. - *

- *

- * At the very least, any ELContext instantiated will have reference - * to the JspContext under JspContext.class. - *

- * - * @param listener - */ - public void addELContextListener(ELContextListener listener); - - /** - *

- * Adds an ELResolver to the chain of EL variable and property management - * within JSP pages and Tag files. - *

- *

- * JSP has a default set of ELResolvers to chain for all EL evaluation: - *

    - *
  • ImplicitObjectELResolver
  • - *
  • ELResolver instances registered with this method
  • - *
  • MapELResolver
  • - *
  • ListELResolver
  • - *
  • ArrayELResolver
  • - *
  • BeanELResolver
  • - *
  • ScopedAttributeELResolver
  • - *
- *

- * - * @param resolver an additional resolver - * @throws IllegalStateException if called after the application's ServletContextListeners have been initialized. - */ - public void addELResolver(ELResolver resolver) throws IllegalStateException; - - /** - *

- * Returns the JSP container's ExpressionFactory implementation for EL use. - *

- * - * @return an ExpressionFactory implementation - */ - public ExpressionFactory getExpressionFactory(); - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +import javax.el.ELContextListener; +import javax.el.ELResolver; +import javax.el.ExpressionFactory; + +/** + *

+ * Stores application-scoped information for the JSP container. + *

+ * @since 2.1 + */ +public interface JspApplicationContext { + + /** + *

+ * Registers an ELContextListener that will notified whenever + * a new ELContext is created. + *

+ *

+ * At the very least, any ELContext instantiated will have reference + * to the JspContext under JspContext.class. + *

+ * + * @param listener + */ + public void addELContextListener(ELContextListener listener); + + /** + *

+ * Adds an ELResolver to the chain of EL variable and property management + * within JSP pages and Tag files. + *

+ *

+ * JSP has a default set of ELResolvers to chain for all EL evaluation: + *

    + *
  • ImplicitObjectELResolver
  • + *
  • ELResolver instances registered with this method
  • + *
  • MapELResolver
  • + *
  • ListELResolver
  • + *
  • ArrayELResolver
  • + *
  • BeanELResolver
  • + *
  • ScopedAttributeELResolver
  • + *
+ *

+ * + * @param resolver an additional resolver + * @throws IllegalStateException if called after the application's ServletContextListeners have been initialized. + */ + public void addELResolver(ELResolver resolver) throws IllegalStateException; + + /** + *

+ * Returns the JSP container's ExpressionFactory implementation for EL use. + *

+ * + * @return an ExpressionFactory implementation + */ + public ExpressionFactory getExpressionFactory(); + +} diff --git a/java/javax/servlet/jsp/JspContext.java b/java/javax/servlet/jsp/JspContext.java index 23b7954d5..6db775df1 100644 --- a/java/javax/servlet/jsp/JspContext.java +++ b/java/javax/servlet/jsp/JspContext.java @@ -1,274 +1,274 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -import java.util.Enumeration; - -import javax.el.ELContext; -import javax.servlet.jsp.el.ExpressionEvaluator; -import javax.servlet.jsp.el.VariableResolver; - -/** - *

- * JspContext serves as the base class for the - * PageContext class and abstracts all information that is not specific - * to servlets. This allows for Simple Tag Extensions to be used - * outside of the context of a request/response Servlet. - *

- * The JspContext provides a number of facilities to the - * page/component author and page implementor, including: - *

    - *
  • a single API to manage the various scoped namespaces - *
  • a mechanism to obtain the JspWriter for output - *
  • a mechanism to expose page directive attributes to the - * scripting environment - *
- * - *

Methods Intended for Container Generated Code - *

- * The following methods enable the management of nested JspWriter - * streams to implement Tag Extensions: pushBody() and - * popBody() - * - *

Methods Intended for JSP authors - *

- * Some methods provide uniform access to the diverse objects - * representing scopes. - * The implementation must use the underlying machinery - * corresponding to that scope, so information can be passed back and - * forth between the underlying environment (e.g. Servlets) and JSP pages. - * The methods are: - * setAttribute(), getAttribute(), - * findAttribute(), removeAttribute(), - * getAttributesScope() and - * getAttributeNamesInScope(). - * - *

- * The following methods provide convenient access to implicit objects: - * getOut() - * - *

- * The following methods provide programmatic access to the - * Expression Language evaluator: - * getExpressionEvaluator(), getVariableResolver() - * - * @since 2.0 - */ - -public abstract class JspContext { - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public JspContext() { - } - - /** - * Register the name and value specified with page scope semantics. - * If the value passed in is null, this has the same - * effect as calling - * removeAttribute( name, PageContext.PAGE_SCOPE ). - * - * @param name the name of the attribute to set - * @param value the value to associate with the name, or null if the - * attribute is to be removed from the page scope. - * @throws NullPointerException if the name is null - */ - - abstract public void setAttribute(String name, Object value); - - /** - * Register the name and value specified with appropriate - * scope semantics. If the value passed in is null, - * this has the same effect as calling - * removeAttribute( name, scope ). - * - * @param name the name of the attribute to set - * @param value the object to associate with the name, or null if - * the attribute is to be removed from the specified scope. - * @param scope the scope with which to associate the name/object - * - * @throws NullPointerException if the name is null - * @throws IllegalArgumentException if the scope is invalid - * @throws IllegalStateException if the scope is - * PageContext.SESSION_SCOPE but the page that was requested - * does not participate in a session or the session has been - * invalidated. - */ - - abstract public void setAttribute(String name, Object value, int scope); - - /** - * Returns the object associated with the name in the page scope or null - * if not found. - * - * @param name the name of the attribute to get - * @return the object associated with the name in the page scope - * or null if not found. - * - * @throws NullPointerException if the name is null - */ - - abstract public Object getAttribute(String name); - - /** - * Return the object associated with the name in the specified - * scope or null if not found. - * - * @param name the name of the attribute to set - * @param scope the scope with which to associate the name/object - * @return the object associated with the name in the specified - * scope or null if not found. - * - * @throws NullPointerException if the name is null - * @throws IllegalArgumentException if the scope is invalid - * @throws IllegalStateException if the scope is - * PageContext.SESSION_SCOPE but the page that was requested - * does not participate in a session or the session has been - * invalidated. - */ - - abstract public Object getAttribute(String name, int scope); - - /** - * Searches for the named attribute in page, request, session (if valid), - * and application scope(s) in order and returns the value associated or - * null. - * - * @param name the name of the attribute to search for - * @return the value associated or null - * @throws NullPointerException if the name is null - */ - - abstract public Object findAttribute(String name); - - /** - * Remove the object reference associated with the given name - * from all scopes. Does nothing if there is no such object. - * - * @param name The name of the object to remove. - * @throws NullPointerException if the name is null - */ - - abstract public void removeAttribute(String name); - - /** - * Remove the object reference associated with the specified name - * in the given scope. Does nothing if there is no such object. - * - * @param name The name of the object to remove. - * @param scope The scope where to look. - * @throws IllegalArgumentException if the scope is invalid - * @throws IllegalStateException if the scope is - * PageContext.SESSION_SCOPE but the page that was requested - * does not participate in a session or the session has been - * invalidated. - * @throws NullPointerException if the name is null - */ - - abstract public void removeAttribute(String name, int scope); - - /** - * Get the scope where a given attribute is defined. - * - * @param name the name of the attribute to return the scope for - * @return the scope of the object associated with the name specified or 0 - * @throws NullPointerException if the name is null - */ - - abstract public int getAttributesScope(String name); - - /** - * Enumerate all the attributes in a given scope. - * - * @param scope the scope to enumerate all the attributes for - * @return an enumeration of names (java.lang.String) of all the - * attributes the specified scope - * @throws IllegalArgumentException if the scope is invalid - * @throws IllegalStateException if the scope is - * PageContext.SESSION_SCOPE but the page that was requested - * does not participate in a session or the session has been - * invalidated. - */ - - abstract public Enumeration getAttributeNamesInScope(int scope); - - /** - * The current value of the out object (a JspWriter). - * - * @return the current JspWriter stream being used for client response - */ - abstract public JspWriter getOut(); - - /** - * Provides programmatic access to the ExpressionEvaluator. - * The JSP Container must return a valid instance of an - * ExpressionEvaluator that can parse EL expressions. - * - * @return A valid instance of an ExpressionEvaluator. - * @since 2.0 - */ - public abstract ExpressionEvaluator getExpressionEvaluator(); - - - public abstract ELContext getELContext(); - - /** - * Returns an instance of a VariableResolver that provides access to the - * implicit objects specified in the JSP specification using this JspContext - * as the context object. - * - * @return A valid instance of a VariableResolver. - * @since 2.0 - */ - public abstract VariableResolver getVariableResolver(); - - /** - * Return a new JspWriter object that sends output to the - * provided Writer. Saves the current "out" JspWriter, - * and updates the value of the "out" attribute in the - * page scope attribute namespace of the JspContext. - *

The returned JspWriter must implement all methods and - * behave as though it were unbuffered. More specifically: - *

    - *
  • clear() must throw an IOException
  • - *
  • clearBuffer() does nothing
  • - *
  • getBufferSize() always returns 0
  • - *
  • getRemaining() always returns 0
  • - *
- *

- * - * @param writer The Writer for the returned JspWriter to send - * output to. - * @return a new JspWriter that writes to the given Writer. - * @since 2.0 - */ - public JspWriter pushBody( java.io.Writer writer ) { - return null; // XXX to implement - } - - /** - * Return the previous JspWriter "out" saved by the matching - * pushBody(), and update the value of the "out" attribute in - * the page scope attribute namespace of the JspContext. - * - * @return the saved JspWriter. - */ - public JspWriter popBody() { - return null; // XXX to implement - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +import java.util.Enumeration; + +import javax.el.ELContext; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.VariableResolver; + +/** + *

+ * JspContext serves as the base class for the + * PageContext class and abstracts all information that is not specific + * to servlets. This allows for Simple Tag Extensions to be used + * outside of the context of a request/response Servlet. + *

+ * The JspContext provides a number of facilities to the + * page/component author and page implementor, including: + *

    + *
  • a single API to manage the various scoped namespaces + *
  • a mechanism to obtain the JspWriter for output + *
  • a mechanism to expose page directive attributes to the + * scripting environment + *
+ * + *

Methods Intended for Container Generated Code + *

+ * The following methods enable the management of nested JspWriter + * streams to implement Tag Extensions: pushBody() and + * popBody() + * + *

Methods Intended for JSP authors + *

+ * Some methods provide uniform access to the diverse objects + * representing scopes. + * The implementation must use the underlying machinery + * corresponding to that scope, so information can be passed back and + * forth between the underlying environment (e.g. Servlets) and JSP pages. + * The methods are: + * setAttribute(), getAttribute(), + * findAttribute(), removeAttribute(), + * getAttributesScope() and + * getAttributeNamesInScope(). + * + *

+ * The following methods provide convenient access to implicit objects: + * getOut() + * + *

+ * The following methods provide programmatic access to the + * Expression Language evaluator: + * getExpressionEvaluator(), getVariableResolver() + * + * @since 2.0 + */ + +public abstract class JspContext { + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public JspContext() { + } + + /** + * Register the name and value specified with page scope semantics. + * If the value passed in is null, this has the same + * effect as calling + * removeAttribute( name, PageContext.PAGE_SCOPE ). + * + * @param name the name of the attribute to set + * @param value the value to associate with the name, or null if the + * attribute is to be removed from the page scope. + * @throws NullPointerException if the name is null + */ + + abstract public void setAttribute(String name, Object value); + + /** + * Register the name and value specified with appropriate + * scope semantics. If the value passed in is null, + * this has the same effect as calling + * removeAttribute( name, scope ). + * + * @param name the name of the attribute to set + * @param value the object to associate with the name, or null if + * the attribute is to be removed from the specified scope. + * @param scope the scope with which to associate the name/object + * + * @throws NullPointerException if the name is null + * @throws IllegalArgumentException if the scope is invalid + * @throws IllegalStateException if the scope is + * PageContext.SESSION_SCOPE but the page that was requested + * does not participate in a session or the session has been + * invalidated. + */ + + abstract public void setAttribute(String name, Object value, int scope); + + /** + * Returns the object associated with the name in the page scope or null + * if not found. + * + * @param name the name of the attribute to get + * @return the object associated with the name in the page scope + * or null if not found. + * + * @throws NullPointerException if the name is null + */ + + abstract public Object getAttribute(String name); + + /** + * Return the object associated with the name in the specified + * scope or null if not found. + * + * @param name the name of the attribute to set + * @param scope the scope with which to associate the name/object + * @return the object associated with the name in the specified + * scope or null if not found. + * + * @throws NullPointerException if the name is null + * @throws IllegalArgumentException if the scope is invalid + * @throws IllegalStateException if the scope is + * PageContext.SESSION_SCOPE but the page that was requested + * does not participate in a session or the session has been + * invalidated. + */ + + abstract public Object getAttribute(String name, int scope); + + /** + * Searches for the named attribute in page, request, session (if valid), + * and application scope(s) in order and returns the value associated or + * null. + * + * @param name the name of the attribute to search for + * @return the value associated or null + * @throws NullPointerException if the name is null + */ + + abstract public Object findAttribute(String name); + + /** + * Remove the object reference associated with the given name + * from all scopes. Does nothing if there is no such object. + * + * @param name The name of the object to remove. + * @throws NullPointerException if the name is null + */ + + abstract public void removeAttribute(String name); + + /** + * Remove the object reference associated with the specified name + * in the given scope. Does nothing if there is no such object. + * + * @param name The name of the object to remove. + * @param scope The scope where to look. + * @throws IllegalArgumentException if the scope is invalid + * @throws IllegalStateException if the scope is + * PageContext.SESSION_SCOPE but the page that was requested + * does not participate in a session or the session has been + * invalidated. + * @throws NullPointerException if the name is null + */ + + abstract public void removeAttribute(String name, int scope); + + /** + * Get the scope where a given attribute is defined. + * + * @param name the name of the attribute to return the scope for + * @return the scope of the object associated with the name specified or 0 + * @throws NullPointerException if the name is null + */ + + abstract public int getAttributesScope(String name); + + /** + * Enumerate all the attributes in a given scope. + * + * @param scope the scope to enumerate all the attributes for + * @return an enumeration of names (java.lang.String) of all the + * attributes the specified scope + * @throws IllegalArgumentException if the scope is invalid + * @throws IllegalStateException if the scope is + * PageContext.SESSION_SCOPE but the page that was requested + * does not participate in a session or the session has been + * invalidated. + */ + + abstract public Enumeration getAttributeNamesInScope(int scope); + + /** + * The current value of the out object (a JspWriter). + * + * @return the current JspWriter stream being used for client response + */ + abstract public JspWriter getOut(); + + /** + * Provides programmatic access to the ExpressionEvaluator. + * The JSP Container must return a valid instance of an + * ExpressionEvaluator that can parse EL expressions. + * + * @return A valid instance of an ExpressionEvaluator. + * @since 2.0 + */ + public abstract ExpressionEvaluator getExpressionEvaluator(); + + + public abstract ELContext getELContext(); + + /** + * Returns an instance of a VariableResolver that provides access to the + * implicit objects specified in the JSP specification using this JspContext + * as the context object. + * + * @return A valid instance of a VariableResolver. + * @since 2.0 + */ + public abstract VariableResolver getVariableResolver(); + + /** + * Return a new JspWriter object that sends output to the + * provided Writer. Saves the current "out" JspWriter, + * and updates the value of the "out" attribute in the + * page scope attribute namespace of the JspContext. + *

The returned JspWriter must implement all methods and + * behave as though it were unbuffered. More specifically: + *

    + *
  • clear() must throw an IOException
  • + *
  • clearBuffer() does nothing
  • + *
  • getBufferSize() always returns 0
  • + *
  • getRemaining() always returns 0
  • + *
+ *

+ * + * @param writer The Writer for the returned JspWriter to send + * output to. + * @return a new JspWriter that writes to the given Writer. + * @since 2.0 + */ + public JspWriter pushBody( java.io.Writer writer ) { + return null; // XXX to implement + } + + /** + * Return the previous JspWriter "out" saved by the matching + * pushBody(), and update the value of the "out" attribute in + * the page scope attribute namespace of the JspContext. + * + * @return the saved JspWriter. + */ + public JspWriter popBody() { + return null; // XXX to implement + } +} diff --git a/java/javax/servlet/jsp/JspEngineInfo.java b/java/javax/servlet/jsp/JspEngineInfo.java index 4a54fb08e..736f00eff 100644 --- a/java/javax/servlet/jsp/JspEngineInfo.java +++ b/java/javax/servlet/jsp/JspEngineInfo.java @@ -1,47 +1,47 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -/** - * The JspEngineInfo is an abstract class that provides information on the - * current JSP engine. - */ - -public abstract class JspEngineInfo { - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public JspEngineInfo() { - } - - /** - * Return the version number of the JSP specification that is supported by - * this JSP engine. - *

- * Specification version numbers that consists of positive decimal integers - * separated by periods ".", for example, "2.0" or "1.2.3.4.5.6.7". - * This allows an extensible number to be used to - * represent major, minor, micro, etc versions. - * The version number must begin with a number. - *

- * - * @return the specification version, null is returned if it is not known - */ - - public abstract String getSpecificationVersion(); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +/** + * The JspEngineInfo is an abstract class that provides information on the + * current JSP engine. + */ + +public abstract class JspEngineInfo { + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public JspEngineInfo() { + } + + /** + * Return the version number of the JSP specification that is supported by + * this JSP engine. + *

+ * Specification version numbers that consists of positive decimal integers + * separated by periods ".", for example, "2.0" or "1.2.3.4.5.6.7". + * This allows an extensible number to be used to + * represent major, minor, micro, etc versions. + * The version number must begin with a number. + *

+ * + * @return the specification version, null is returned if it is not known + */ + + public abstract String getSpecificationVersion(); +} diff --git a/java/javax/servlet/jsp/JspException.java b/java/javax/servlet/jsp/JspException.java index 61e66db8f..e2eb9443e 100644 --- a/java/javax/servlet/jsp/JspException.java +++ b/java/javax/servlet/jsp/JspException.java @@ -1,112 +1,112 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -/** - * A generic exception known to the JSP engine; uncaught - * JspExceptions will result in an invocation of the errorpage - * machinery. - */ - -public class JspException extends Exception { - - private Throwable rootCause; - - - /** - * Construct a JspException. - */ - public JspException() { - } - - - /** - * Constructs a new JSP exception with the - * specified message. The message can be written - * to the server log and/or displayed for the user. - * - * @param msg a String - * specifying the text of - * the exception message - * - */ - public JspException(String msg) { - super(msg); - } - - - /** - * Constructs a new JSP exception when the JSP - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation, including a description message. - * - * - * @param message a String containing - * the text of the exception message - * - * @param rootCause the Throwable exception - * that interfered with the servlet's - * normal operation, making this servlet - * exception necessary - * - */ - - public JspException(String message, Throwable rootCause) { - super(message); - this.rootCause = rootCause; - } - - - /** - * Constructs a new JSP exception when the JSP - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation. The exception's message is based on the localized - * message of the underlying exception. - * - *

This method calls the getLocalizedMessage method - * on the Throwable exception to get a localized exception - * message. When subclassing JspException, - * this method can be overridden to create an exception message - * designed for a specific locale. - * - * @param rootCause the Throwable exception - * that interfered with the JSP's - * normal operation, making the JSP exception - * necessary - * - */ - - public JspException(Throwable rootCause) { - super(rootCause.getLocalizedMessage()); - this.rootCause = rootCause; - } - - - /** - * Returns the exception that caused this JSP exception. - * - * - * @return the Throwable - * that caused this JSP exception - * - */ - - public Throwable getRootCause() { - return rootCause; - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +/** + * A generic exception known to the JSP engine; uncaught + * JspExceptions will result in an invocation of the errorpage + * machinery. + */ + +public class JspException extends Exception { + + private Throwable rootCause; + + + /** + * Construct a JspException. + */ + public JspException() { + } + + + /** + * Constructs a new JSP exception with the + * specified message. The message can be written + * to the server log and/or displayed for the user. + * + * @param msg a String + * specifying the text of + * the exception message + * + */ + public JspException(String msg) { + super(msg); + } + + + /** + * Constructs a new JSP exception when the JSP + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation, including a description message. + * + * + * @param message a String containing + * the text of the exception message + * + * @param rootCause the Throwable exception + * that interfered with the servlet's + * normal operation, making this servlet + * exception necessary + * + */ + + public JspException(String message, Throwable rootCause) { + super(message); + this.rootCause = rootCause; + } + + + /** + * Constructs a new JSP exception when the JSP + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation. The exception's message is based on the localized + * message of the underlying exception. + * + *

This method calls the getLocalizedMessage method + * on the Throwable exception to get a localized exception + * message. When subclassing JspException, + * this method can be overridden to create an exception message + * designed for a specific locale. + * + * @param rootCause the Throwable exception + * that interfered with the JSP's + * normal operation, making the JSP exception + * necessary + * + */ + + public JspException(Throwable rootCause) { + super(rootCause.getLocalizedMessage()); + this.rootCause = rootCause; + } + + + /** + * Returns the exception that caused this JSP exception. + * + * + * @return the Throwable + * that caused this JSP exception + * + */ + + public Throwable getRootCause() { + return rootCause; + } +} diff --git a/java/javax/servlet/jsp/JspFactory.java b/java/javax/servlet/jsp/JspFactory.java index 3380023d5..5d3003fc3 100644 --- a/java/javax/servlet/jsp/JspFactory.java +++ b/java/javax/servlet/jsp/JspFactory.java @@ -1,155 +1,155 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.jsp.PageContext; - -/** - *

- * The JspFactory is an abstract class that defines a number of factory - * methods available to a JSP page at runtime for the purposes of creating - * instances of various interfaces and classes used to support the JSP - * implementation. - *

- * A conformant JSP Engine implementation will, during it's initialization - * instantiate an implementation dependent subclass of this class, and make - * it globally available for use by JSP implementation classes by registering - * the instance created with this class via the - * static setDefaultFactory() method. - *

- * The PageContext and the JspEngineInfo classes are the only implementation-dependent - * classes that can be created from the factory. - *

- * JspFactory objects should not be used by JSP page authors. - */ - -public abstract class JspFactory { - - private static JspFactory deflt = null; - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public JspFactory() { - } - - /** - *

- * set the default factory for this implementation. It is illegal for - * any principal other than the JSP Engine runtime to call this method. - *

- * - * @param deflt The default factory implementation - */ - - public static synchronized void setDefaultFactory(JspFactory deflt) { - JspFactory.deflt = deflt; - } - - /** - * Returns the default factory for this implementation. - * - * @return the default factory for this implementation - */ - - public static synchronized JspFactory getDefaultFactory() { - return deflt; - } - - /** - *

- * obtains an instance of an implementation dependent - * javax.servlet.jsp.PageContext abstract class for the calling Servlet - * and currently pending request and response. - *

- * - *

- * This method is typically called early in the processing of the - * _jspService() method of a JSP implementation class in order to - * obtain a PageContext object for the request being processed. - *

- *

- * Invoking this method shall result in the PageContext.initialize() - * method being invoked. The PageContext returned is properly initialized. - *

- *

- * All PageContext objects obtained via this method shall be released - * by invoking releasePageContext(). - *

- * - * @param servlet the requesting servlet - * @param request the current request pending on the servlet - * @param response the current response pending on the servlet - * @param errorPageURL the URL of the error page for the requesting JSP, or null - * @param needsSession true if the JSP participates in a session - * @param buffer size of buffer in bytes, PageContext.NO_BUFFER if no buffer, - * PageContext.DEFAULT_BUFFER if implementation default. - * @param autoflush should the buffer autoflush to the output stream on buffer - * overflow, or throw an IOException? - * - * @return the page context - * - * @see javax.servlet.jsp.PageContext - */ - - public abstract PageContext getPageContext(Servlet servlet, - ServletRequest request, - ServletResponse response, - String errorPageURL, - boolean needsSession, - int buffer, - boolean autoflush); - - /** - *

- * called to release a previously allocated PageContext object. - * Results in PageContext.release() being invoked. - * This method should be invoked prior to returning from the _jspService() method of a JSP implementation - * class. - *

- * - * @param pc A PageContext previously obtained by getPageContext() - */ - - public abstract void releasePageContext(PageContext pc); - - /** - *

- * called to get implementation-specific information on the current JSP engine. - *

- * - * @return a JspEngineInfo object describing the current JSP engine - */ - - public abstract JspEngineInfo getEngineInfo(); - - /** - *

- * Obtain the JspApplicationContext instance that was associated - * within the passed ServletContext for this web application. - *

- * - * @param context the current web application's ServletContext - * @return JspApplicationContext instance - * @since 2.1 - */ - public abstract JspApplicationContext getJspApplicationContext(ServletContext context); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.jsp.PageContext; + +/** + *

+ * The JspFactory is an abstract class that defines a number of factory + * methods available to a JSP page at runtime for the purposes of creating + * instances of various interfaces and classes used to support the JSP + * implementation. + *

+ * A conformant JSP Engine implementation will, during it's initialization + * instantiate an implementation dependent subclass of this class, and make + * it globally available for use by JSP implementation classes by registering + * the instance created with this class via the + * static setDefaultFactory() method. + *

+ * The PageContext and the JspEngineInfo classes are the only implementation-dependent + * classes that can be created from the factory. + *

+ * JspFactory objects should not be used by JSP page authors. + */ + +public abstract class JspFactory { + + private static JspFactory deflt = null; + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public JspFactory() { + } + + /** + *

+ * set the default factory for this implementation. It is illegal for + * any principal other than the JSP Engine runtime to call this method. + *

+ * + * @param deflt The default factory implementation + */ + + public static synchronized void setDefaultFactory(JspFactory deflt) { + JspFactory.deflt = deflt; + } + + /** + * Returns the default factory for this implementation. + * + * @return the default factory for this implementation + */ + + public static synchronized JspFactory getDefaultFactory() { + return deflt; + } + + /** + *

+ * obtains an instance of an implementation dependent + * javax.servlet.jsp.PageContext abstract class for the calling Servlet + * and currently pending request and response. + *

+ * + *

+ * This method is typically called early in the processing of the + * _jspService() method of a JSP implementation class in order to + * obtain a PageContext object for the request being processed. + *

+ *

+ * Invoking this method shall result in the PageContext.initialize() + * method being invoked. The PageContext returned is properly initialized. + *

+ *

+ * All PageContext objects obtained via this method shall be released + * by invoking releasePageContext(). + *

+ * + * @param servlet the requesting servlet + * @param request the current request pending on the servlet + * @param response the current response pending on the servlet + * @param errorPageURL the URL of the error page for the requesting JSP, or null + * @param needsSession true if the JSP participates in a session + * @param buffer size of buffer in bytes, PageContext.NO_BUFFER if no buffer, + * PageContext.DEFAULT_BUFFER if implementation default. + * @param autoflush should the buffer autoflush to the output stream on buffer + * overflow, or throw an IOException? + * + * @return the page context + * + * @see javax.servlet.jsp.PageContext + */ + + public abstract PageContext getPageContext(Servlet servlet, + ServletRequest request, + ServletResponse response, + String errorPageURL, + boolean needsSession, + int buffer, + boolean autoflush); + + /** + *

+ * called to release a previously allocated PageContext object. + * Results in PageContext.release() being invoked. + * This method should be invoked prior to returning from the _jspService() method of a JSP implementation + * class. + *

+ * + * @param pc A PageContext previously obtained by getPageContext() + */ + + public abstract void releasePageContext(PageContext pc); + + /** + *

+ * called to get implementation-specific information on the current JSP engine. + *

+ * + * @return a JspEngineInfo object describing the current JSP engine + */ + + public abstract JspEngineInfo getEngineInfo(); + + /** + *

+ * Obtain the JspApplicationContext instance that was associated + * within the passed ServletContext for this web application. + *

+ * + * @param context the current web application's ServletContext + * @return JspApplicationContext instance + * @since 2.1 + */ + public abstract JspApplicationContext getJspApplicationContext(ServletContext context); +} diff --git a/java/javax/servlet/jsp/JspPage.java b/java/javax/servlet/jsp/JspPage.java index 85c8d8c69..e93074d7e 100644 --- a/java/javax/servlet/jsp/JspPage.java +++ b/java/javax/servlet/jsp/JspPage.java @@ -1,89 +1,89 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -import javax.servlet.*; - -/** - * The JspPage interface describes the generic interaction that a JSP Page - * Implementation class must satisfy; pages that use the HTTP protocol - * are described by the HttpJspPage interface. - * - *

Two plus One Methods - *

- * The interface defines a protocol with 3 methods; only two of - * them: jspInit() and jspDestroy() are part of this interface as - * the signature of the third method: _jspService() depends on - * the specific protocol used and cannot be expressed in a generic - * way in Java. - *

- * A class implementing this interface is responsible for invoking - * the above methods at the appropriate time based on the - * corresponding Servlet-based method invocations. - *

- * The jspInit() and jspDestroy() methods can be defined by a JSP - * author, but the _jspService() method is defined automatically - * by the JSP processor based on the contents of the JSP page. - * - *

_jspService() - *

- * The _jspService()method corresponds to the body of the JSP page. This - * method is defined automatically by the JSP container and should never - * be defined by the JSP page author. - *

- * If a superclass is specified using the extends attribute, that - * superclass may choose to perform some actions in its service() method - * before or after calling the _jspService() method. See using the extends - * attribute in the JSP_Engine chapter of the JSP specification. - *

- * The specific signature depends on the protocol supported by the JSP page. - * - *

- * public void _jspService(ServletRequestSubtype request,
- *                             ServletResponseSubtype response)
- *        throws ServletException, IOException;
- * 
- */ - - -public interface JspPage extends Servlet { - - /** - * The jspInit() method is invoked when the JSP page is initialized. It - * is the responsibility of the JSP implementation (and of the class - * mentioned by the extends attribute, if present) that at this point - * invocations to the getServletConfig() method will return the desired - * value. - * - * A JSP page can override this method by including a definition for it - * in a declaration element. - * - * A JSP page should redefine the init() method from Servlet. - */ - public void jspInit(); - - /** - * The jspDestroy() method is invoked when the JSP page is about to be - * destroyed. - * - * A JSP page can override this method by including a definition for it - * in a declaration element. - * - * A JSP page should redefine the destroy() method from Servlet. - */ - public void jspDestroy(); - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +import javax.servlet.*; + +/** + * The JspPage interface describes the generic interaction that a JSP Page + * Implementation class must satisfy; pages that use the HTTP protocol + * are described by the HttpJspPage interface. + * + *

Two plus One Methods + *

+ * The interface defines a protocol with 3 methods; only two of + * them: jspInit() and jspDestroy() are part of this interface as + * the signature of the third method: _jspService() depends on + * the specific protocol used and cannot be expressed in a generic + * way in Java. + *

+ * A class implementing this interface is responsible for invoking + * the above methods at the appropriate time based on the + * corresponding Servlet-based method invocations. + *

+ * The jspInit() and jspDestroy() methods can be defined by a JSP + * author, but the _jspService() method is defined automatically + * by the JSP processor based on the contents of the JSP page. + * + *

_jspService() + *

+ * The _jspService()method corresponds to the body of the JSP page. This + * method is defined automatically by the JSP container and should never + * be defined by the JSP page author. + *

+ * If a superclass is specified using the extends attribute, that + * superclass may choose to perform some actions in its service() method + * before or after calling the _jspService() method. See using the extends + * attribute in the JSP_Engine chapter of the JSP specification. + *

+ * The specific signature depends on the protocol supported by the JSP page. + * + *

+ * public void _jspService(ServletRequestSubtype request,
+ *                             ServletResponseSubtype response)
+ *        throws ServletException, IOException;
+ * 
+ */ + + +public interface JspPage extends Servlet { + + /** + * The jspInit() method is invoked when the JSP page is initialized. It + * is the responsibility of the JSP implementation (and of the class + * mentioned by the extends attribute, if present) that at this point + * invocations to the getServletConfig() method will return the desired + * value. + * + * A JSP page can override this method by including a definition for it + * in a declaration element. + * + * A JSP page should redefine the init() method from Servlet. + */ + public void jspInit(); + + /** + * The jspDestroy() method is invoked when the JSP page is about to be + * destroyed. + * + * A JSP page can override this method by including a definition for it + * in a declaration element. + * + * A JSP page should redefine the destroy() method from Servlet. + */ + public void jspDestroy(); + +} diff --git a/java/javax/servlet/jsp/JspTagException.java b/java/javax/servlet/jsp/JspTagException.java index 548e4645e..35d876940 100644 --- a/java/javax/servlet/jsp/JspTagException.java +++ b/java/javax/servlet/jsp/JspTagException.java @@ -1,92 +1,92 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -/** - * Exception to be used by a Tag Handler to indicate some unrecoverable - * error. - * This error is to be caught by the top level of the JSP page and will result - * in an error page. - */ - -public class JspTagException extends JspException { - /** - * Constructs a new JspTagException with the specified message. - * The message can be written to the server log and/or displayed - * for the user. - * - * @param msg a String specifying the text of - * the exception message - */ - public JspTagException(String msg) { - super( msg ); - } - - /** - * Constructs a new JspTagException with no message. - */ - public JspTagException() { - super(); - } - - /** - * Constructs a new JspTagException when the JSP Tag - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation, including a description message. - * - * - * @param message a String containing - * the text of the exception message - * - * @param rootCause the Throwable exception - * that interfered with the JSP Tag's - * normal operation, making this JSP Tag - * exception necessary - * - * @since 2.0 - */ - public JspTagException(String message, Throwable rootCause) { - super( message, rootCause ); - } - - - /** - * Constructs a new JSP Tag exception when the JSP Tag - * needs to throw an exception and include a message - * about the "root cause" exception that interfered with its - * normal operation. The exception's message is based on the localized - * message of the underlying exception. - * - *

This method calls the getLocalizedMessage method - * on the Throwable exception to get a localized exception - * message. When subclassing JspTagException, - * this method can be overridden to create an exception message - * designed for a specific locale. - * - * @param rootCause the Throwable exception - * that interfered with the JSP Tag's - * normal operation, making the JSP Tag - * exception necessary - * - * @since 2.0 - */ - - public JspTagException(Throwable rootCause) { - super( rootCause ); - } - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +/** + * Exception to be used by a Tag Handler to indicate some unrecoverable + * error. + * This error is to be caught by the top level of the JSP page and will result + * in an error page. + */ + +public class JspTagException extends JspException { + /** + * Constructs a new JspTagException with the specified message. + * The message can be written to the server log and/or displayed + * for the user. + * + * @param msg a String specifying the text of + * the exception message + */ + public JspTagException(String msg) { + super( msg ); + } + + /** + * Constructs a new JspTagException with no message. + */ + public JspTagException() { + super(); + } + + /** + * Constructs a new JspTagException when the JSP Tag + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation, including a description message. + * + * + * @param message a String containing + * the text of the exception message + * + * @param rootCause the Throwable exception + * that interfered with the JSP Tag's + * normal operation, making this JSP Tag + * exception necessary + * + * @since 2.0 + */ + public JspTagException(String message, Throwable rootCause) { + super( message, rootCause ); + } + + + /** + * Constructs a new JSP Tag exception when the JSP Tag + * needs to throw an exception and include a message + * about the "root cause" exception that interfered with its + * normal operation. The exception's message is based on the localized + * message of the underlying exception. + * + *

This method calls the getLocalizedMessage method + * on the Throwable exception to get a localized exception + * message. When subclassing JspTagException, + * this method can be overridden to create an exception message + * designed for a specific locale. + * + * @param rootCause the Throwable exception + * that interfered with the JSP Tag's + * normal operation, making the JSP Tag + * exception necessary + * + * @since 2.0 + */ + + public JspTagException(Throwable rootCause) { + super( rootCause ); + } + +} diff --git a/java/javax/servlet/jsp/JspWriter.java b/java/javax/servlet/jsp/JspWriter.java index bbc434a1c..b11050d30 100644 --- a/java/javax/servlet/jsp/JspWriter.java +++ b/java/javax/servlet/jsp/JspWriter.java @@ -1,442 +1,442 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp; - -import java.io.IOException; - -/** - *

- * The actions and template data in a JSP page is written using the - * JspWriter object that is referenced by the implicit variable out which - * is initialized automatically using methods in the PageContext object. - *

- * This abstract class emulates some of the functionality found in the - * java.io.BufferedWriter and java.io.PrintWriter classes, - * however it differs in that it throws java.io.IOException from the print - * methods while PrintWriter does not. - *

Buffering - *

- * The initial JspWriter object is associated with the PrintWriter object - * of the ServletResponse in a way that depends on whether the page is or - * is not buffered. If the page is not buffered, output written to this - * JspWriter object will be written through to the PrintWriter directly, - * which will be created if necessary by invoking the getWriter() method - * on the response object. But if the page is buffered, the PrintWriter - * object will not be created until the buffer is flushed and - * operations like setContentType() are legal. Since this flexibility - * simplifies programming substantially, buffering is the default for JSP - * pages. - *

- * Buffering raises the issue of what to do when the buffer is - * exceeded. Two approaches can be taken: - *

    - *
  • - * Exceeding the buffer is not a fatal error; when the buffer is - * exceeded, just flush the output. - *
  • - * Exceeding the buffer is a fatal error; when the buffer is exceeded, - * raise an exception. - *
- *

- * Both approaches are valid, and thus both are supported in the JSP - * technology. The behavior of a page is controlled by the autoFlush - * attribute, which defaults to true. In general, JSP pages that need to - * be sure that correct and complete data has been sent to their client - * may want to set autoFlush to false, with a typical case being that - * where the client is an application itself. On the other hand, JSP - * pages that send data that is meaningful even when partially - * constructed may want to set autoFlush to true; such as when the - * data is sent for immediate display through a browser. Each application - * will need to consider their specific needs. - *

- * An alternative considered was to make the buffer size unbounded; but, - * this had the disadvantage that runaway computations would consume an - * unbounded amount of resources. - *

- * The "out" implicit variable of a JSP implementation class is of this type. - * If the page directive selects autoflush="true" then all the I/O operations - * on this class shall automatically flush the contents of the buffer if an - * overflow condition would result if the current operation were performed - * without a flush. If autoflush="false" then all the I/O operations on this - * class shall throw an IOException if performing the current operation would - * result in a buffer overflow condition. - * - * @see java.io.Writer - * @see java.io.BufferedWriter - * @see java.io.PrintWriter - */ - -abstract public class JspWriter extends java.io.Writer { - - /** - * Constant indicating that the Writer is not buffering output. - */ - - public static final int NO_BUFFER = 0; - - /** - * Constant indicating that the Writer is buffered and is using the - * implementation default buffer size. - */ - - public static final int DEFAULT_BUFFER = -1; - - /** - * Constant indicating that the Writer is buffered and is unbounded; this - * is used in BodyContent. - */ - - public static final int UNBOUNDED_BUFFER = -2; - - /** - * Protected constructor. - * - * @param bufferSize the size of the buffer to be used by the JspWriter - * @param autoFlush whether the JspWriter should be autoflushing - */ - - protected JspWriter(int bufferSize, boolean autoFlush) { - this.bufferSize = bufferSize; - this.autoFlush = autoFlush; - } - - /** - * Write a line separator. The line separator string is defined by the - * system property line.separator, and is not necessarily a single - * newline ('\n') character. - * - * @exception IOException If an I/O error occurs - */ - - abstract public void newLine() throws IOException; - - /** - * Print a boolean value. The string produced by {@link - * java.lang.String#valueOf(boolean)} is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param b The boolean to be printed - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(boolean b) throws IOException; - - /** - * Print a character. The character is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param c The char to be printed - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(char c) throws IOException; - - /** - * Print an integer. The string produced by {@link - * java.lang.String#valueOf(int)} is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param i The int to be printed - * @see java.lang.Integer#toString(int) - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(int i) throws IOException; - - /** - * Print a long integer. The string produced by {@link - * java.lang.String#valueOf(long)} is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param l The long to be printed - * @see java.lang.Long#toString(long) - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(long l) throws IOException; - - /** - * Print a floating-point number. The string produced by {@link - * java.lang.String#valueOf(float)} is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param f The float to be printed - * @see java.lang.Float#toString(float) - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(float f) throws IOException; - - /** - * Print a double-precision floating-point number. The string produced by - * {@link java.lang.String#valueOf(double)} is written to - * the JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param d The double to be printed - * @see java.lang.Double#toString(double) - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(double d) throws IOException; - - /** - * Print an array of characters. The characters are written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param s The array of chars to be printed - * - * @throws NullPointerException If s is null - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(char s[]) throws IOException; - - /** - * Print a string. If the argument is null then the string - * "null" is printed. Otherwise, the string's characters are - * written to the JspWriter's buffer or, if no buffer is used, directly - * to the underlying writer. - * - * @param s The String to be printed - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(String s) throws IOException; - - /** - * Print an object. The string produced by the {@link - * java.lang.String#valueOf(Object)} method is written to the - * JspWriter's buffer or, if no buffer is used, directly to the - * underlying writer. - * - * @param obj The Object to be printed - * @see java.lang.Object#toString() - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void print(Object obj) throws IOException; - - /** - * Terminate the current line by writing the line separator string. The - * line separator string is defined by the system property - * line.separator, and is not necessarily a single newline - * character ('\n'). - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println() throws IOException; - - /** - * Print a boolean value and then terminate the line. This method behaves - * as though it invokes {@link #print(boolean)} and then - * {@link #println()}. - * - * @param x the boolean to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(boolean x) throws IOException; - - /** - * Print a character and then terminate the line. This method behaves as - * though it invokes {@link #print(char)} and then {@link - * #println()}. - * - * @param x the char to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(char x) throws IOException; - - /** - * Print an integer and then terminate the line. This method behaves as - * though it invokes {@link #print(int)} and then {@link - * #println()}. - * - * @param x the int to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(int x) throws IOException; - - /** - * Print a long integer and then terminate the line. This method behaves - * as though it invokes {@link #print(long)} and then - * {@link #println()}. - * - * @param x the long to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(long x) throws IOException; - - /** - * Print a floating-point number and then terminate the line. This method - * behaves as though it invokes {@link #print(float)} and then - * {@link #println()}. - * - * @param x the float to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(float x) throws IOException; - - /** - * Print a double-precision floating-point number and then terminate the - * line. This method behaves as though it invokes {@link - * #print(double)} and then {@link #println()}. - * - * @param x the double to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(double x) throws IOException; - - /** - * Print an array of characters and then terminate the line. This method - * behaves as though it invokes print(char[]) and then - * println(). - * - * @param x the char[] to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(char x[]) throws IOException; - - /** - * Print a String and then terminate the line. This method behaves as - * though it invokes {@link #print(String)} and then - * {@link #println()}. - * - * @param x the String to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(String x) throws IOException; - - /** - * Print an Object and then terminate the line. This method behaves as - * though it invokes {@link #print(Object)} and then - * {@link #println()}. - * - * @param x the Object to write - * @throws java.io.IOException If an error occured while writing - */ - - abstract public void println(Object x) throws IOException; - - - /** - * Clear the contents of the buffer. If the buffer has been already - * been flushed then the clear operation shall throw an IOException - * to signal the fact that some data has already been irrevocably - * written to the client response stream. - * - * @throws IOException If an I/O error occurs - */ - - abstract public void clear() throws IOException; - - /** - * Clears the current contents of the buffer. Unlike clear(), this - * method will not throw an IOException if the buffer has already been - * flushed. It merely clears the current content of the buffer and - * returns. - * - * @throws IOException If an I/O error occurs - */ - - abstract public void clearBuffer() throws IOException; - - /** - * Flush the stream. If the stream has saved any characters from the - * various write() methods in a buffer, write them immediately to their - * intended destination. Then, if that destination is another character or - * byte stream, flush it. Thus one flush() invocation will flush all the - * buffers in a chain of Writers and OutputStreams. - *

- * The method may be invoked indirectly if the buffer size is exceeded. - *

- * Once a stream has been closed, - * further write() or flush() invocations will cause an IOException to be - * thrown. - * - * @exception IOException If an I/O error occurs - */ - - abstract public void flush() throws IOException; - - /** - * Close the stream, flushing it first. - *

- * This method needs not be invoked explicitly for the initial JspWriter - * as the code generated by the JSP container will automatically - * include a call to close(). - *

- * Closing a previously-closed stream, unlike flush(), has no effect. - * - * @exception IOException If an I/O error occurs - */ - - abstract public void close() throws IOException; - - /** - * This method returns the size of the buffer used by the JspWriter. - * - * @return the size of the buffer in bytes, or 0 is unbuffered. - */ - - public int getBufferSize() { return bufferSize; } - - /** - * This method returns the number of unused bytes in the buffer. - * - * @return the number of bytes unused in the buffer - */ - - abstract public int getRemaining(); - - /** - * This method indicates whether the JspWriter is autoFlushing. - * - * @return if this JspWriter is auto flushing or throwing IOExceptions - * on buffer overflow conditions - */ - - public boolean isAutoFlush() { return autoFlush; } - - /* - * fields - */ - - /** - * The size of the buffer used by the JspWriter. - */ - protected int bufferSize; - - /** - * Whether the JspWriter is autoflushing. - */ - protected boolean autoFlush; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp; + +import java.io.IOException; + +/** + *

+ * The actions and template data in a JSP page is written using the + * JspWriter object that is referenced by the implicit variable out which + * is initialized automatically using methods in the PageContext object. + *

+ * This abstract class emulates some of the functionality found in the + * java.io.BufferedWriter and java.io.PrintWriter classes, + * however it differs in that it throws java.io.IOException from the print + * methods while PrintWriter does not. + *

Buffering + *

+ * The initial JspWriter object is associated with the PrintWriter object + * of the ServletResponse in a way that depends on whether the page is or + * is not buffered. If the page is not buffered, output written to this + * JspWriter object will be written through to the PrintWriter directly, + * which will be created if necessary by invoking the getWriter() method + * on the response object. But if the page is buffered, the PrintWriter + * object will not be created until the buffer is flushed and + * operations like setContentType() are legal. Since this flexibility + * simplifies programming substantially, buffering is the default for JSP + * pages. + *

+ * Buffering raises the issue of what to do when the buffer is + * exceeded. Two approaches can be taken: + *

    + *
  • + * Exceeding the buffer is not a fatal error; when the buffer is + * exceeded, just flush the output. + *
  • + * Exceeding the buffer is a fatal error; when the buffer is exceeded, + * raise an exception. + *
+ *

+ * Both approaches are valid, and thus both are supported in the JSP + * technology. The behavior of a page is controlled by the autoFlush + * attribute, which defaults to true. In general, JSP pages that need to + * be sure that correct and complete data has been sent to their client + * may want to set autoFlush to false, with a typical case being that + * where the client is an application itself. On the other hand, JSP + * pages that send data that is meaningful even when partially + * constructed may want to set autoFlush to true; such as when the + * data is sent for immediate display through a browser. Each application + * will need to consider their specific needs. + *

+ * An alternative considered was to make the buffer size unbounded; but, + * this had the disadvantage that runaway computations would consume an + * unbounded amount of resources. + *

+ * The "out" implicit variable of a JSP implementation class is of this type. + * If the page directive selects autoflush="true" then all the I/O operations + * on this class shall automatically flush the contents of the buffer if an + * overflow condition would result if the current operation were performed + * without a flush. If autoflush="false" then all the I/O operations on this + * class shall throw an IOException if performing the current operation would + * result in a buffer overflow condition. + * + * @see java.io.Writer + * @see java.io.BufferedWriter + * @see java.io.PrintWriter + */ + +abstract public class JspWriter extends java.io.Writer { + + /** + * Constant indicating that the Writer is not buffering output. + */ + + public static final int NO_BUFFER = 0; + + /** + * Constant indicating that the Writer is buffered and is using the + * implementation default buffer size. + */ + + public static final int DEFAULT_BUFFER = -1; + + /** + * Constant indicating that the Writer is buffered and is unbounded; this + * is used in BodyContent. + */ + + public static final int UNBOUNDED_BUFFER = -2; + + /** + * Protected constructor. + * + * @param bufferSize the size of the buffer to be used by the JspWriter + * @param autoFlush whether the JspWriter should be autoflushing + */ + + protected JspWriter(int bufferSize, boolean autoFlush) { + this.bufferSize = bufferSize; + this.autoFlush = autoFlush; + } + + /** + * Write a line separator. The line separator string is defined by the + * system property line.separator, and is not necessarily a single + * newline ('\n') character. + * + * @exception IOException If an I/O error occurs + */ + + abstract public void newLine() throws IOException; + + /** + * Print a boolean value. The string produced by {@link + * java.lang.String#valueOf(boolean)} is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param b The boolean to be printed + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(boolean b) throws IOException; + + /** + * Print a character. The character is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param c The char to be printed + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(char c) throws IOException; + + /** + * Print an integer. The string produced by {@link + * java.lang.String#valueOf(int)} is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param i The int to be printed + * @see java.lang.Integer#toString(int) + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(int i) throws IOException; + + /** + * Print a long integer. The string produced by {@link + * java.lang.String#valueOf(long)} is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param l The long to be printed + * @see java.lang.Long#toString(long) + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(long l) throws IOException; + + /** + * Print a floating-point number. The string produced by {@link + * java.lang.String#valueOf(float)} is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param f The float to be printed + * @see java.lang.Float#toString(float) + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(float f) throws IOException; + + /** + * Print a double-precision floating-point number. The string produced by + * {@link java.lang.String#valueOf(double)} is written to + * the JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param d The double to be printed + * @see java.lang.Double#toString(double) + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(double d) throws IOException; + + /** + * Print an array of characters. The characters are written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param s The array of chars to be printed + * + * @throws NullPointerException If s is null + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(char s[]) throws IOException; + + /** + * Print a string. If the argument is null then the string + * "null" is printed. Otherwise, the string's characters are + * written to the JspWriter's buffer or, if no buffer is used, directly + * to the underlying writer. + * + * @param s The String to be printed + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(String s) throws IOException; + + /** + * Print an object. The string produced by the {@link + * java.lang.String#valueOf(Object)} method is written to the + * JspWriter's buffer or, if no buffer is used, directly to the + * underlying writer. + * + * @param obj The Object to be printed + * @see java.lang.Object#toString() + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void print(Object obj) throws IOException; + + /** + * Terminate the current line by writing the line separator string. The + * line separator string is defined by the system property + * line.separator, and is not necessarily a single newline + * character ('\n'). + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println() throws IOException; + + /** + * Print a boolean value and then terminate the line. This method behaves + * as though it invokes {@link #print(boolean)} and then + * {@link #println()}. + * + * @param x the boolean to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(boolean x) throws IOException; + + /** + * Print a character and then terminate the line. This method behaves as + * though it invokes {@link #print(char)} and then {@link + * #println()}. + * + * @param x the char to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(char x) throws IOException; + + /** + * Print an integer and then terminate the line. This method behaves as + * though it invokes {@link #print(int)} and then {@link + * #println()}. + * + * @param x the int to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(int x) throws IOException; + + /** + * Print a long integer and then terminate the line. This method behaves + * as though it invokes {@link #print(long)} and then + * {@link #println()}. + * + * @param x the long to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(long x) throws IOException; + + /** + * Print a floating-point number and then terminate the line. This method + * behaves as though it invokes {@link #print(float)} and then + * {@link #println()}. + * + * @param x the float to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(float x) throws IOException; + + /** + * Print a double-precision floating-point number and then terminate the + * line. This method behaves as though it invokes {@link + * #print(double)} and then {@link #println()}. + * + * @param x the double to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(double x) throws IOException; + + /** + * Print an array of characters and then terminate the line. This method + * behaves as though it invokes print(char[]) and then + * println(). + * + * @param x the char[] to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(char x[]) throws IOException; + + /** + * Print a String and then terminate the line. This method behaves as + * though it invokes {@link #print(String)} and then + * {@link #println()}. + * + * @param x the String to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(String x) throws IOException; + + /** + * Print an Object and then terminate the line. This method behaves as + * though it invokes {@link #print(Object)} and then + * {@link #println()}. + * + * @param x the Object to write + * @throws java.io.IOException If an error occured while writing + */ + + abstract public void println(Object x) throws IOException; + + + /** + * Clear the contents of the buffer. If the buffer has been already + * been flushed then the clear operation shall throw an IOException + * to signal the fact that some data has already been irrevocably + * written to the client response stream. + * + * @throws IOException If an I/O error occurs + */ + + abstract public void clear() throws IOException; + + /** + * Clears the current contents of the buffer. Unlike clear(), this + * method will not throw an IOException if the buffer has already been + * flushed. It merely clears the current content of the buffer and + * returns. + * + * @throws IOException If an I/O error occurs + */ + + abstract public void clearBuffer() throws IOException; + + /** + * Flush the stream. If the stream has saved any characters from the + * various write() methods in a buffer, write them immediately to their + * intended destination. Then, if that destination is another character or + * byte stream, flush it. Thus one flush() invocation will flush all the + * buffers in a chain of Writers and OutputStreams. + *

+ * The method may be invoked indirectly if the buffer size is exceeded. + *

+ * Once a stream has been closed, + * further write() or flush() invocations will cause an IOException to be + * thrown. + * + * @exception IOException If an I/O error occurs + */ + + abstract public void flush() throws IOException; + + /** + * Close the stream, flushing it first. + *

+ * This method needs not be invoked explicitly for the initial JspWriter + * as the code generated by the JSP container will automatically + * include a call to close(). + *

+ * Closing a previously-closed stream, unlike flush(), has no effect. + * + * @exception IOException If an I/O error occurs + */ + + abstract public void close() throws IOException; + + /** + * This method returns the size of the buffer used by the JspWriter. + * + * @return the size of the buffer in bytes, or 0 is unbuffered. + */ + + public int getBufferSize() { return bufferSize; } + + /** + * This method returns the number of unused bytes in the buffer. + * + * @return the number of bytes unused in the buffer + */ + + abstract public int getRemaining(); + + /** + * This method indicates whether the JspWriter is autoFlushing. + * + * @return if this JspWriter is auto flushing or throwing IOExceptions + * on buffer overflow conditions + */ + + public boolean isAutoFlush() { return autoFlush; } + + /* + * fields + */ + + /** + * The size of the buffer used by the JspWriter. + */ + protected int bufferSize; + + /** + * Whether the JspWriter is autoflushing. + */ + protected boolean autoFlush; +} diff --git a/java/javax/servlet/jsp/PageContext.java b/java/javax/servlet/jsp/PageContext.java index 6af01f206..b1906192d 100644 --- a/java/javax/servlet/jsp/PageContext.java +++ b/java/javax/servlet/jsp/PageContext.java @@ -1,522 +1,522 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp; - -import java.io.IOException; - -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import javax.servlet.http.HttpSession; - -import javax.servlet.jsp.tagext.BodyContent; - -/** - *

- * PageContext extends JspContext to provide useful context information for - * when JSP technology is used in a Servlet environment. - *

- * A PageContext instance provides access to all the namespaces associated - * with a JSP page, provides access to several page attributes, as well as - * a layer above the implementation details. Implicit objects are added - * to the pageContext automatically. - * - *

The PageContext class is an abstract class, designed to be - * extended to provide implementation dependent implementations thereof, by - * conformant JSP engine runtime environments. A PageContext instance is - * obtained by a JSP implementation class by calling the - * JspFactory.getPageContext() method, and is released by calling - * JspFactory.releasePageContext(). - * - *

An example of how PageContext, JspFactory, and other classes can be - * used within a JSP Page Implementation object is given elsewhere. - * - *

- * The PageContext provides a number of facilities to the page/component - * author and page implementor, including: - *

    - *
  • a single API to manage the various scoped namespaces - *
  • a number of convenience API's to access various public objects - *
  • a mechanism to obtain the JspWriter for output - *
  • a mechanism to manage session usage by the page - *
  • a mechanism to expose page directive attributes to the scripting - * environment - *
  • mechanisms to forward or include the current request to other active - * components in the application - *
  • a mechanism to handle errorpage exception processing - *
- * - *

Methods Intended for Container Generated Code - *

Some methods are intended to be used by the code generated by the - * container, not by code written by JSP page authors, or JSP tag library - * authors. - *

The methods supporting lifecycle are initialize() - * and release() - * - *

- * The following methods enable the management of nested JspWriter - * streams to implement Tag Extensions: pushBody() - * - *

Methods Intended for JSP authors - *

- * The following methods provide convenient access to implicit objects: - * getException(), getPage() - * getRequest(), getResponse(), - * getSession(), getServletConfig() - * and getServletContext(). - * - *

- * The following methods provide support for forwarding, inclusion - * and error handling: - * forward(), include(), - * and handlePageException(). - */ - -abstract public class PageContext - extends JspContext -{ - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public PageContext() { - } - - /** - * Page scope: (this is the default) the named reference remains available - * in this PageContext until the return from the current Servlet.service() - * invocation. - */ - - public static final int PAGE_SCOPE = 1; - - /** - * Request scope: the named reference remains available from the - * ServletRequest associated with the Servlet until the current request - * is completed. - */ - - public static final int REQUEST_SCOPE = 2; - - /** - * Session scope (only valid if this page participates in a session): - * the named reference remains available from the HttpSession (if any) - * associated with the Servlet until the HttpSession is invalidated. - */ - - public static final int SESSION_SCOPE = 3; - - /** - * Application scope: named reference remains available in the - * ServletContext until it is reclaimed. - */ - - public static final int APPLICATION_SCOPE = 4; - - /** - * Name used to store the Servlet in this PageContext's nametables. - */ - - public static final String PAGE = "javax.servlet.jsp.jspPage"; - - /** - * Name used to store this PageContext in it's own name table. - */ - - public static final String PAGECONTEXT = "javax.servlet.jsp.jspPageContext"; - - /** - * Name used to store ServletRequest in PageContext name table. - */ - - public static final String REQUEST = "javax.servlet.jsp.jspRequest"; - - /** - * Name used to store ServletResponse in PageContext name table. - */ - - public static final String RESPONSE = "javax.servlet.jsp.jspResponse"; - - /** - * Name used to store ServletConfig in PageContext name table. - */ - - public static final String CONFIG = "javax.servlet.jsp.jspConfig"; - - /** - * Name used to store HttpSession in PageContext name table. - */ - - public static final String SESSION = "javax.servlet.jsp.jspSession"; - /** - * Name used to store current JspWriter in PageContext name table. - */ - - public static final String OUT = "javax.servlet.jsp.jspOut"; - - /** - * Name used to store ServletContext in PageContext name table. - */ - - public static final String APPLICATION = "javax.servlet.jsp.jspApplication"; - - /** - * Name used to store uncaught exception in ServletRequest attribute - * list and PageContext name table. - */ - - public static final String EXCEPTION = "javax.servlet.jsp.jspException"; - - /** - *

- * The initialize method is called to initialize an uninitialized PageContext - * so that it may be used by a JSP Implementation class to service an - * incoming request and response within it's _jspService() method. - * - *

- * This method is typically called from JspFactory.getPageContext() in - * order to initialize state. - * - *

- * This method is required to create an initial JspWriter, and associate - * the "out" name in page scope with this newly created object. - * - *

- * This method should not be used by page or tag library authors. - * - * @param servlet The Servlet that is associated with this PageContext - * @param request The currently pending request for this Servlet - * @param response The currently pending response for this Servlet - * @param errorPageURL The value of the errorpage attribute from the page - * directive or null - * @param needsSession The value of the session attribute from the - * page directive - * @param bufferSize The value of the buffer attribute from the page - * directive - * @param autoFlush The value of the autoflush attribute from the page - * directive - * - * @throws IOException during creation of JspWriter - * @throws IllegalStateException if out not correctly initialized - * @throws IllegalArgumentException If one of the given parameters - * is invalid - */ - - abstract public void initialize(Servlet servlet, ServletRequest request, - ServletResponse response, String errorPageURL, boolean needsSession, - int bufferSize, boolean autoFlush) - throws IOException, IllegalStateException, IllegalArgumentException; - - /** - *

- * This method shall "reset" the internal state of a PageContext, releasing - * all internal references, and preparing the PageContext for potential - * reuse by a later invocation of initialize(). This method is typically - * called from JspFactory.releasePageContext(). - * - *

- * Subclasses shall envelope this method. - * - *

- * This method should not be used by page or tag library authors. - * - */ - - abstract public void release(); - - /** - * The current value of the session object (an HttpSession). - * - * @return the HttpSession for this PageContext or null - */ - - abstract public HttpSession getSession(); - - /** - * The current value of the page object (In a Servlet environment, - * this is an instance of javax.servlet.Servlet). - * - * @return the Page implementation class instance associated - * with this PageContext - */ - - abstract public Object getPage(); - - - /** - * The current value of the request object (a ServletRequest). - * - * @return The ServletRequest for this PageContext - */ - - abstract public ServletRequest getRequest(); - - /** - * The current value of the response object (a ServletResponse). - * - * @return the ServletResponse for this PageContext - */ - - abstract public ServletResponse getResponse(); - - /** - * The current value of the exception object (an Exception). - * - * @return any exception passed to this as an errorpage - */ - - abstract public Exception getException(); - - /** - * The ServletConfig instance. - * - * @return the ServletConfig for this PageContext - */ - - abstract public ServletConfig getServletConfig(); - - /** - * The ServletContext instance. - * - * @return the ServletContext for this PageContext - */ - - abstract public ServletContext getServletContext(); - - /** - *

- * This method is used to re-direct, or "forward" the current - * ServletRequest and ServletResponse to another active component in - * the application. - *

- *

- * If the relativeUrlPath begins with a "/" then the URL specified - * is calculated relative to the DOCROOT of the ServletContext - * for this JSP. If the path does not begin with a "/" then the URL - * specified is calculated relative to the URL of the request that was - * mapped to the calling JSP. - *

- *

- * It is only valid to call this method from a Thread - * executing within a _jspService(...) method of a JSP. - *

- *

- * Once this method has been called successfully, it is illegal for the - * calling Thread to attempt to modify the - * ServletResponse object. Any such attempt to do so, shall result - * in undefined behavior. Typically, callers immediately return from - * _jspService(...) after calling this method. - *

- * - * @param relativeUrlPath specifies the relative URL path to the target - * resource as described above - * - * @throws IllegalStateException if ServletResponse is not - * in a state where a forward can be performed - * @throws ServletException if the page that was forwarded to throws - * a ServletException - * @throws IOException if an I/O error occurred while forwarding - */ - - abstract public void forward(String relativeUrlPath) - throws ServletException, IOException; - - /** - *

- * Causes the resource specified to be processed as part of the current - * ServletRequest and ServletResponse being processed by the calling Thread. - * The output of the target resources processing of the request is written - * directly to the ServletResponse output stream. - *

- *

- * The current JspWriter "out" for this JSP is flushed as a side-effect - * of this call, prior to processing the include. - *

- *

- * If the relativeUrlPath begins with a "/" then the URL specified - * is calculated relative to the DOCROOT of the ServletContext - * for this JSP. If the path does not begin with a "/" then the URL - * specified is calculated relative to the URL of the request that was - * mapped to the calling JSP. - *

- *

- * It is only valid to call this method from a Thread - * executing within a _jspService(...) method of a JSP. - *

- * - * @param relativeUrlPath specifies the relative URL path to the target - * resource to be included - * - * @throws ServletException if the page that was forwarded to throws - * a ServletException - * @throws IOException if an I/O error occurred while forwarding - */ - abstract public void include(String relativeUrlPath) - throws ServletException, IOException; - - /** - *

- * Causes the resource specified to be processed as part of the current - * ServletRequest and ServletResponse being processed by the calling Thread. - * The output of the target resources processing of the request is written - * directly to the current JspWriter returned by a call to getOut(). - *

- *

- * If flush is true, The current JspWriter "out" for this JSP - * is flushed as a side-effect of this call, prior to processing - * the include. Otherwise, the JspWriter "out" is not flushed. - *

- *

- * If the relativeUrlPath begins with a "/" then the URL specified - * is calculated relative to the DOCROOT of the ServletContext - * for this JSP. If the path does not begin with a "/" then the URL - * specified is calculated relative to the URL of the request that was - * mapped to the calling JSP. - *

- *

- * It is only valid to call this method from a Thread - * executing within a _jspService(...) method of a JSP. - *

- * - * @param relativeUrlPath specifies the relative URL path to the - * target resource to be included - * @param flush True if the JspWriter is to be flushed before the include, - * or false if not. - * - * @throws ServletException if the page that was forwarded to throws - * a ServletException - * @throws IOException if an I/O error occurred while forwarding - * @since 2.0 - */ - abstract public void include(String relativeUrlPath, boolean flush) - throws ServletException, IOException; - - /** - *

- * This method is intended to process an unhandled 'page' level - * exception by forwarding the exception to the specified - * error page for this JSP. If forwarding is not possible (for - * example because the response has already been committed), an - * implementation dependent mechanism should be used to invoke - * the error page (e.g. "including" the error page instead). - * - *

- * If no error page is defined in the page, the exception should - * be rethrown so that the standard servlet error handling - * takes over. - * - *

- * A JSP implementation class shall typically clean up any local state - * prior to invoking this and will return immediately thereafter. It is - * illegal to generate any output to the client, or to modify any - * ServletResponse state after invoking this call. - * - *

- * This method is kept for backwards compatiblity reasons. Newly - * generated code should use PageContext.handlePageException(Throwable). - * - * @param e the exception to be handled - * - * @throws ServletException if an error occurs while invoking the error page - * @throws IOException if an I/O error occurred while invoking the error - * page - * @throws NullPointerException if the exception is null - * - * @see #handlePageException(Throwable) - */ - - abstract public void handlePageException(Exception e) - throws ServletException, IOException; - - /** - *

- * This method is intended to process an unhandled 'page' level - * exception by forwarding the exception to the specified - * error page for this JSP. If forwarding is not possible (for - * example because the response has already been committed), an - * implementation dependent mechanism should be used to invoke - * the error page (e.g. "including" the error page instead). - * - *

- * If no error page is defined in the page, the exception should - * be rethrown so that the standard servlet error handling - * takes over. - * - *

- * This method is intended to process an unhandled "page" level exception - * by redirecting the exception to either the specified error page for this - * JSP, or if none was specified, to perform some implementation dependent - * action. - * - *

- * A JSP implementation class shall typically clean up any local state - * prior to invoking this and will return immediately thereafter. It is - * illegal to generate any output to the client, or to modify any - * ServletResponse state after invoking this call. - * - * @param t the throwable to be handled - * - * @throws ServletException if an error occurs while invoking the error page - * @throws IOException if an I/O error occurred while invoking the error - * page - * @throws NullPointerException if the exception is null - * - * @see #handlePageException(Exception) - */ - - abstract public void handlePageException(Throwable t) - throws ServletException, IOException; - - /** - * Return a new BodyContent object, save the current "out" JspWriter, - * and update the value of the "out" attribute in the page scope - * attribute namespace of the PageContext. - * - * @return the new BodyContent - */ - - public BodyContent pushBody() { - return null; // XXX to implement - } - - - /** - * Provides convenient access to error information. - * - * @return an ErrorData instance containing information about the - * error, as obtained from the request attributes, as per the - * Servlet specification. If this is not an error page (that is, - * if the isErrorPage attribute of the page directive is not set - * to "true"), the information is meaningless. - * - * @since 2.0 - */ - public ErrorData getErrorData() { - return new ErrorData( - (Throwable)getRequest().getAttribute( "javax.servlet.error.exception" ), - ((Integer)getRequest().getAttribute( - "javax.servlet.error.status_code" )).intValue(), - (String)getRequest().getAttribute( "javax.servlet.error.request_uri" ), - (String)getRequest().getAttribute( "javax.servlet.error.servlet_name" ) ); - } - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp; + +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + +import javax.servlet.http.HttpSession; + +import javax.servlet.jsp.tagext.BodyContent; + +/** + *

+ * PageContext extends JspContext to provide useful context information for + * when JSP technology is used in a Servlet environment. + *

+ * A PageContext instance provides access to all the namespaces associated + * with a JSP page, provides access to several page attributes, as well as + * a layer above the implementation details. Implicit objects are added + * to the pageContext automatically. + * + *

The PageContext class is an abstract class, designed to be + * extended to provide implementation dependent implementations thereof, by + * conformant JSP engine runtime environments. A PageContext instance is + * obtained by a JSP implementation class by calling the + * JspFactory.getPageContext() method, and is released by calling + * JspFactory.releasePageContext(). + * + *

An example of how PageContext, JspFactory, and other classes can be + * used within a JSP Page Implementation object is given elsewhere. + * + *

+ * The PageContext provides a number of facilities to the page/component + * author and page implementor, including: + *

    + *
  • a single API to manage the various scoped namespaces + *
  • a number of convenience API's to access various public objects + *
  • a mechanism to obtain the JspWriter for output + *
  • a mechanism to manage session usage by the page + *
  • a mechanism to expose page directive attributes to the scripting + * environment + *
  • mechanisms to forward or include the current request to other active + * components in the application + *
  • a mechanism to handle errorpage exception processing + *
+ * + *

Methods Intended for Container Generated Code + *

Some methods are intended to be used by the code generated by the + * container, not by code written by JSP page authors, or JSP tag library + * authors. + *

The methods supporting lifecycle are initialize() + * and release() + * + *

+ * The following methods enable the management of nested JspWriter + * streams to implement Tag Extensions: pushBody() + * + *

Methods Intended for JSP authors + *

+ * The following methods provide convenient access to implicit objects: + * getException(), getPage() + * getRequest(), getResponse(), + * getSession(), getServletConfig() + * and getServletContext(). + * + *

+ * The following methods provide support for forwarding, inclusion + * and error handling: + * forward(), include(), + * and handlePageException(). + */ + +abstract public class PageContext + extends JspContext +{ + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public PageContext() { + } + + /** + * Page scope: (this is the default) the named reference remains available + * in this PageContext until the return from the current Servlet.service() + * invocation. + */ + + public static final int PAGE_SCOPE = 1; + + /** + * Request scope: the named reference remains available from the + * ServletRequest associated with the Servlet until the current request + * is completed. + */ + + public static final int REQUEST_SCOPE = 2; + + /** + * Session scope (only valid if this page participates in a session): + * the named reference remains available from the HttpSession (if any) + * associated with the Servlet until the HttpSession is invalidated. + */ + + public static final int SESSION_SCOPE = 3; + + /** + * Application scope: named reference remains available in the + * ServletContext until it is reclaimed. + */ + + public static final int APPLICATION_SCOPE = 4; + + /** + * Name used to store the Servlet in this PageContext's nametables. + */ + + public static final String PAGE = "javax.servlet.jsp.jspPage"; + + /** + * Name used to store this PageContext in it's own name table. + */ + + public static final String PAGECONTEXT = "javax.servlet.jsp.jspPageContext"; + + /** + * Name used to store ServletRequest in PageContext name table. + */ + + public static final String REQUEST = "javax.servlet.jsp.jspRequest"; + + /** + * Name used to store ServletResponse in PageContext name table. + */ + + public static final String RESPONSE = "javax.servlet.jsp.jspResponse"; + + /** + * Name used to store ServletConfig in PageContext name table. + */ + + public static final String CONFIG = "javax.servlet.jsp.jspConfig"; + + /** + * Name used to store HttpSession in PageContext name table. + */ + + public static final String SESSION = "javax.servlet.jsp.jspSession"; + /** + * Name used to store current JspWriter in PageContext name table. + */ + + public static final String OUT = "javax.servlet.jsp.jspOut"; + + /** + * Name used to store ServletContext in PageContext name table. + */ + + public static final String APPLICATION = "javax.servlet.jsp.jspApplication"; + + /** + * Name used to store uncaught exception in ServletRequest attribute + * list and PageContext name table. + */ + + public static final String EXCEPTION = "javax.servlet.jsp.jspException"; + + /** + *

+ * The initialize method is called to initialize an uninitialized PageContext + * so that it may be used by a JSP Implementation class to service an + * incoming request and response within it's _jspService() method. + * + *

+ * This method is typically called from JspFactory.getPageContext() in + * order to initialize state. + * + *

+ * This method is required to create an initial JspWriter, and associate + * the "out" name in page scope with this newly created object. + * + *

+ * This method should not be used by page or tag library authors. + * + * @param servlet The Servlet that is associated with this PageContext + * @param request The currently pending request for this Servlet + * @param response The currently pending response for this Servlet + * @param errorPageURL The value of the errorpage attribute from the page + * directive or null + * @param needsSession The value of the session attribute from the + * page directive + * @param bufferSize The value of the buffer attribute from the page + * directive + * @param autoFlush The value of the autoflush attribute from the page + * directive + * + * @throws IOException during creation of JspWriter + * @throws IllegalStateException if out not correctly initialized + * @throws IllegalArgumentException If one of the given parameters + * is invalid + */ + + abstract public void initialize(Servlet servlet, ServletRequest request, + ServletResponse response, String errorPageURL, boolean needsSession, + int bufferSize, boolean autoFlush) + throws IOException, IllegalStateException, IllegalArgumentException; + + /** + *

+ * This method shall "reset" the internal state of a PageContext, releasing + * all internal references, and preparing the PageContext for potential + * reuse by a later invocation of initialize(). This method is typically + * called from JspFactory.releasePageContext(). + * + *

+ * Subclasses shall envelope this method. + * + *

+ * This method should not be used by page or tag library authors. + * + */ + + abstract public void release(); + + /** + * The current value of the session object (an HttpSession). + * + * @return the HttpSession for this PageContext or null + */ + + abstract public HttpSession getSession(); + + /** + * The current value of the page object (In a Servlet environment, + * this is an instance of javax.servlet.Servlet). + * + * @return the Page implementation class instance associated + * with this PageContext + */ + + abstract public Object getPage(); + + + /** + * The current value of the request object (a ServletRequest). + * + * @return The ServletRequest for this PageContext + */ + + abstract public ServletRequest getRequest(); + + /** + * The current value of the response object (a ServletResponse). + * + * @return the ServletResponse for this PageContext + */ + + abstract public ServletResponse getResponse(); + + /** + * The current value of the exception object (an Exception). + * + * @return any exception passed to this as an errorpage + */ + + abstract public Exception getException(); + + /** + * The ServletConfig instance. + * + * @return the ServletConfig for this PageContext + */ + + abstract public ServletConfig getServletConfig(); + + /** + * The ServletContext instance. + * + * @return the ServletContext for this PageContext + */ + + abstract public ServletContext getServletContext(); + + /** + *

+ * This method is used to re-direct, or "forward" the current + * ServletRequest and ServletResponse to another active component in + * the application. + *

+ *

+ * If the relativeUrlPath begins with a "/" then the URL specified + * is calculated relative to the DOCROOT of the ServletContext + * for this JSP. If the path does not begin with a "/" then the URL + * specified is calculated relative to the URL of the request that was + * mapped to the calling JSP. + *

+ *

+ * It is only valid to call this method from a Thread + * executing within a _jspService(...) method of a JSP. + *

+ *

+ * Once this method has been called successfully, it is illegal for the + * calling Thread to attempt to modify the + * ServletResponse object. Any such attempt to do so, shall result + * in undefined behavior. Typically, callers immediately return from + * _jspService(...) after calling this method. + *

+ * + * @param relativeUrlPath specifies the relative URL path to the target + * resource as described above + * + * @throws IllegalStateException if ServletResponse is not + * in a state where a forward can be performed + * @throws ServletException if the page that was forwarded to throws + * a ServletException + * @throws IOException if an I/O error occurred while forwarding + */ + + abstract public void forward(String relativeUrlPath) + throws ServletException, IOException; + + /** + *

+ * Causes the resource specified to be processed as part of the current + * ServletRequest and ServletResponse being processed by the calling Thread. + * The output of the target resources processing of the request is written + * directly to the ServletResponse output stream. + *

+ *

+ * The current JspWriter "out" for this JSP is flushed as a side-effect + * of this call, prior to processing the include. + *

+ *

+ * If the relativeUrlPath begins with a "/" then the URL specified + * is calculated relative to the DOCROOT of the ServletContext + * for this JSP. If the path does not begin with a "/" then the URL + * specified is calculated relative to the URL of the request that was + * mapped to the calling JSP. + *

+ *

+ * It is only valid to call this method from a Thread + * executing within a _jspService(...) method of a JSP. + *

+ * + * @param relativeUrlPath specifies the relative URL path to the target + * resource to be included + * + * @throws ServletException if the page that was forwarded to throws + * a ServletException + * @throws IOException if an I/O error occurred while forwarding + */ + abstract public void include(String relativeUrlPath) + throws ServletException, IOException; + + /** + *

+ * Causes the resource specified to be processed as part of the current + * ServletRequest and ServletResponse being processed by the calling Thread. + * The output of the target resources processing of the request is written + * directly to the current JspWriter returned by a call to getOut(). + *

+ *

+ * If flush is true, The current JspWriter "out" for this JSP + * is flushed as a side-effect of this call, prior to processing + * the include. Otherwise, the JspWriter "out" is not flushed. + *

+ *

+ * If the relativeUrlPath begins with a "/" then the URL specified + * is calculated relative to the DOCROOT of the ServletContext + * for this JSP. If the path does not begin with a "/" then the URL + * specified is calculated relative to the URL of the request that was + * mapped to the calling JSP. + *

+ *

+ * It is only valid to call this method from a Thread + * executing within a _jspService(...) method of a JSP. + *

+ * + * @param relativeUrlPath specifies the relative URL path to the + * target resource to be included + * @param flush True if the JspWriter is to be flushed before the include, + * or false if not. + * + * @throws ServletException if the page that was forwarded to throws + * a ServletException + * @throws IOException if an I/O error occurred while forwarding + * @since 2.0 + */ + abstract public void include(String relativeUrlPath, boolean flush) + throws ServletException, IOException; + + /** + *

+ * This method is intended to process an unhandled 'page' level + * exception by forwarding the exception to the specified + * error page for this JSP. If forwarding is not possible (for + * example because the response has already been committed), an + * implementation dependent mechanism should be used to invoke + * the error page (e.g. "including" the error page instead). + * + *

+ * If no error page is defined in the page, the exception should + * be rethrown so that the standard servlet error handling + * takes over. + * + *

+ * A JSP implementation class shall typically clean up any local state + * prior to invoking this and will return immediately thereafter. It is + * illegal to generate any output to the client, or to modify any + * ServletResponse state after invoking this call. + * + *

+ * This method is kept for backwards compatiblity reasons. Newly + * generated code should use PageContext.handlePageException(Throwable). + * + * @param e the exception to be handled + * + * @throws ServletException if an error occurs while invoking the error page + * @throws IOException if an I/O error occurred while invoking the error + * page + * @throws NullPointerException if the exception is null + * + * @see #handlePageException(Throwable) + */ + + abstract public void handlePageException(Exception e) + throws ServletException, IOException; + + /** + *

+ * This method is intended to process an unhandled 'page' level + * exception by forwarding the exception to the specified + * error page for this JSP. If forwarding is not possible (for + * example because the response has already been committed), an + * implementation dependent mechanism should be used to invoke + * the error page (e.g. "including" the error page instead). + * + *

+ * If no error page is defined in the page, the exception should + * be rethrown so that the standard servlet error handling + * takes over. + * + *

+ * This method is intended to process an unhandled "page" level exception + * by redirecting the exception to either the specified error page for this + * JSP, or if none was specified, to perform some implementation dependent + * action. + * + *

+ * A JSP implementation class shall typically clean up any local state + * prior to invoking this and will return immediately thereafter. It is + * illegal to generate any output to the client, or to modify any + * ServletResponse state after invoking this call. + * + * @param t the throwable to be handled + * + * @throws ServletException if an error occurs while invoking the error page + * @throws IOException if an I/O error occurred while invoking the error + * page + * @throws NullPointerException if the exception is null + * + * @see #handlePageException(Exception) + */ + + abstract public void handlePageException(Throwable t) + throws ServletException, IOException; + + /** + * Return a new BodyContent object, save the current "out" JspWriter, + * and update the value of the "out" attribute in the page scope + * attribute namespace of the PageContext. + * + * @return the new BodyContent + */ + + public BodyContent pushBody() { + return null; // XXX to implement + } + + + /** + * Provides convenient access to error information. + * + * @return an ErrorData instance containing information about the + * error, as obtained from the request attributes, as per the + * Servlet specification. If this is not an error page (that is, + * if the isErrorPage attribute of the page directive is not set + * to "true"), the information is meaningless. + * + * @since 2.0 + */ + public ErrorData getErrorData() { + return new ErrorData( + (Throwable)getRequest().getAttribute( "javax.servlet.error.exception" ), + ((Integer)getRequest().getAttribute( + "javax.servlet.error.status_code" )).intValue(), + (String)getRequest().getAttribute( "javax.servlet.error.request_uri" ), + (String)getRequest().getAttribute( "javax.servlet.error.servlet_name" ) ); + } + +} diff --git a/java/javax/servlet/jsp/SkipPageException.java b/java/javax/servlet/jsp/SkipPageException.java index bfb80d609..b0ea0cd42 100644 --- a/java/javax/servlet/jsp/SkipPageException.java +++ b/java/javax/servlet/jsp/SkipPageException.java @@ -1,75 +1,75 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp; - -/** - * Exception to indicate the calling page must cease evaluation. - * Thrown by a simple tag handler to indicate that the remainder of - * the page must not be evaluated. The result is propagated back to - * the pagein the case where one tag invokes another (as can be - * the case with tag files). The effect is similar to that of a - * Classic Tag Handler returning Tag.SKIP_PAGE from doEndTag(). - * Jsp Fragments may also throw this exception. This exception - * should not be thrown manually in a JSP page or tag file - the behavior is - * undefined. The exception is intended to be thrown inside - * SimpleTag handlers and in JSP fragments. - * - * @see javax.servlet.jsp.tagext.SimpleTag#doTag - * @see javax.servlet.jsp.tagext.JspFragment#invoke - * @see javax.servlet.jsp.tagext.Tag#doEndTag - * @since 2.0 - */ -public class SkipPageException - extends JspException -{ - /** - * Creates a SkipPageException with no message. - */ - public SkipPageException() { - super(); - } - - /** - * Creates a SkipPageException with the provided message. - * - * @param message the detail message - */ - public SkipPageException( String message ) { - super( message ); - } - - /** - * Creates a SkipPageException with the provided message and root cause. - * - * @param message the detail message - * @param rootCause the originating cause of this exception - */ - public SkipPageException( String message, Throwable rootCause ) { - super( message, rootCause ); - } - - /** - * Creates a SkipPageException with the provided root cause. - * - * @param rootCause the originating cause of this exception - */ - public SkipPageException( Throwable rootCause ) { - super( rootCause ); - } - -} - - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp; + +/** + * Exception to indicate the calling page must cease evaluation. + * Thrown by a simple tag handler to indicate that the remainder of + * the page must not be evaluated. The result is propagated back to + * the pagein the case where one tag invokes another (as can be + * the case with tag files). The effect is similar to that of a + * Classic Tag Handler returning Tag.SKIP_PAGE from doEndTag(). + * Jsp Fragments may also throw this exception. This exception + * should not be thrown manually in a JSP page or tag file - the behavior is + * undefined. The exception is intended to be thrown inside + * SimpleTag handlers and in JSP fragments. + * + * @see javax.servlet.jsp.tagext.SimpleTag#doTag + * @see javax.servlet.jsp.tagext.JspFragment#invoke + * @see javax.servlet.jsp.tagext.Tag#doEndTag + * @since 2.0 + */ +public class SkipPageException + extends JspException +{ + /** + * Creates a SkipPageException with no message. + */ + public SkipPageException() { + super(); + } + + /** + * Creates a SkipPageException with the provided message. + * + * @param message the detail message + */ + public SkipPageException( String message ) { + super( message ); + } + + /** + * Creates a SkipPageException with the provided message and root cause. + * + * @param message the detail message + * @param rootCause the originating cause of this exception + */ + public SkipPageException( String message, Throwable rootCause ) { + super( message, rootCause ); + } + + /** + * Creates a SkipPageException with the provided root cause. + * + * @param rootCause the originating cause of this exception + */ + public SkipPageException( Throwable rootCause ) { + super( rootCause ); + } + +} + + diff --git a/java/javax/servlet/jsp/el/ELException.java b/java/javax/servlet/jsp/el/ELException.java index eb6de839c..3d3b796b0 100644 --- a/java/javax/servlet/jsp/el/ELException.java +++ b/java/javax/servlet/jsp/el/ELException.java @@ -1,92 +1,92 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.el; - - -/** - * Represents any of the exception conditions that arise during the - * operation evaluation of the evaluator. - * - * @since 2.0 - * @deprecated - */ -public class ELException - extends Exception -{ - //------------------------------------- - // Member variables - //------------------------------------- - - private Throwable mRootCause; - - //------------------------------------- - /** - * Creates an ELException with no detail message. - **/ - public ELException () - { - super (); - } - - //------------------------------------- - /** - * Creates an ELException with the provided detail message. - * - * @param pMessage the detail message - **/ - public ELException (String pMessage) - { - super (pMessage); - } - - //------------------------------------- - /** - * Creates an ELException with the given root cause. - * - * @param pRootCause the originating cause of this exception - **/ - public ELException (Throwable pRootCause) - { - super( pRootCause.getLocalizedMessage() ); - mRootCause = pRootCause; - } - - //------------------------------------- - /** - * Creates an ELException with the given detail message and root cause. - * - * @param pMessage the detail message - * @param pRootCause the originating cause of this exception - **/ - public ELException (String pMessage, - Throwable pRootCause) - { - super (pMessage); - mRootCause = pRootCause; - } - - //------------------------------------- - /** - * Returns the root cause. - * - * @return the root cause of this exception - */ - public Throwable getRootCause () - { - return mRootCause; - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.el; + + +/** + * Represents any of the exception conditions that arise during the + * operation evaluation of the evaluator. + * + * @since 2.0 + * @deprecated + */ +public class ELException + extends Exception +{ + //------------------------------------- + // Member variables + //------------------------------------- + + private Throwable mRootCause; + + //------------------------------------- + /** + * Creates an ELException with no detail message. + **/ + public ELException () + { + super (); + } + + //------------------------------------- + /** + * Creates an ELException with the provided detail message. + * + * @param pMessage the detail message + **/ + public ELException (String pMessage) + { + super (pMessage); + } + + //------------------------------------- + /** + * Creates an ELException with the given root cause. + * + * @param pRootCause the originating cause of this exception + **/ + public ELException (Throwable pRootCause) + { + super( pRootCause.getLocalizedMessage() ); + mRootCause = pRootCause; + } + + //------------------------------------- + /** + * Creates an ELException with the given detail message and root cause. + * + * @param pMessage the detail message + * @param pRootCause the originating cause of this exception + **/ + public ELException (String pMessage, + Throwable pRootCause) + { + super (pMessage); + mRootCause = pRootCause; + } + + //------------------------------------- + /** + * Returns the root cause. + * + * @return the root cause of this exception + */ + public Throwable getRootCause () + { + return mRootCause; + } +} diff --git a/java/javax/servlet/jsp/el/ELParseException.java b/java/javax/servlet/jsp/el/ELParseException.java index 6e65cf778..901f2720d 100644 --- a/java/javax/servlet/jsp/el/ELParseException.java +++ b/java/javax/servlet/jsp/el/ELParseException.java @@ -1,50 +1,50 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.el; - - -/** - * Represents a parsing error encountered while parsing an EL expression. - * - * @since 2.0 - * @deprecated - */ - -public class ELParseException extends ELException { - - //------------------------------------- - /** - * Creates an ELParseException with no detail message. - */ - public ELParseException () - { - super (); - } - - //------------------------------------- - /** - * Creates an ELParseException with the provided detail message. - * - * @param pMessage the detail message - **/ - public ELParseException (String pMessage) - { - super (pMessage); - } - - //------------------------------------- -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.el; + + +/** + * Represents a parsing error encountered while parsing an EL expression. + * + * @since 2.0 + * @deprecated + */ + +public class ELParseException extends ELException { + + //------------------------------------- + /** + * Creates an ELParseException with no detail message. + */ + public ELParseException () + { + super (); + } + + //------------------------------------- + /** + * Creates an ELParseException with the provided detail message. + * + * @param pMessage the detail message + **/ + public ELParseException (String pMessage) + { + super (pMessage); + } + + //------------------------------------- +} diff --git a/java/javax/servlet/jsp/el/Expression.java b/java/javax/servlet/jsp/el/Expression.java index 3d5c13417..78e3603ee 100644 --- a/java/javax/servlet/jsp/el/Expression.java +++ b/java/javax/servlet/jsp/el/Expression.java @@ -1,52 +1,52 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.el; - - -/** - *

The abstract class for a prepared expression.

- * - *

An instance of an Expression can be obtained via from an - * ExpressionEvaluator instance.

- * - *

An Expression may or not have done a syntactic parse of the expression. - * A client invoking the evaluate() method should be ready for the case - * where ELParseException exceptions are raised.

- * - * @since 2.0 - * @deprecated - */ -public abstract class Expression { - - /** - * Evaluates an expression that was previously prepared. In some - * implementations preparing an expression involves full syntactic - * validation, but others may not do so. Evaluating the expression may - * raise an ELParseException as well as other ELExceptions due to - * run-time evaluation. - * - * @param vResolver A VariableResolver instance that can be used at - * runtime to resolve the name of implicit objects into Objects. - * @return The result of the expression evaluation. - * - * @exception ELException Thrown if the expression evaluation failed. - */ - public abstract Object evaluate( VariableResolver vResolver ) - throws ELException; -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.el; + + +/** + *

The abstract class for a prepared expression.

+ * + *

An instance of an Expression can be obtained via from an + * ExpressionEvaluator instance.

+ * + *

An Expression may or not have done a syntactic parse of the expression. + * A client invoking the evaluate() method should be ready for the case + * where ELParseException exceptions are raised.

+ * + * @since 2.0 + * @deprecated + */ +public abstract class Expression { + + /** + * Evaluates an expression that was previously prepared. In some + * implementations preparing an expression involves full syntactic + * validation, but others may not do so. Evaluating the expression may + * raise an ELParseException as well as other ELExceptions due to + * run-time evaluation. + * + * @param vResolver A VariableResolver instance that can be used at + * runtime to resolve the name of implicit objects into Objects. + * @return The result of the expression evaluation. + * + * @exception ELException Thrown if the expression evaluation failed. + */ + public abstract Object evaluate( VariableResolver vResolver ) + throws ELException; +} + diff --git a/java/javax/servlet/jsp/el/ExpressionEvaluator.java b/java/javax/servlet/jsp/el/ExpressionEvaluator.java index 5cb95fa62..48c61634c 100644 --- a/java/javax/servlet/jsp/el/ExpressionEvaluator.java +++ b/java/javax/servlet/jsp/el/ExpressionEvaluator.java @@ -1,107 +1,107 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.el; - - -/** - *

The abstract base class for an expression-language evaluator. - * Classes that implement an expression language expose their functionality - * via this abstract class.

- * - *

An instance of the ExpressionEvaluator can be obtained via the - * JspContext / PageContext

- * - *

The parseExpression() and evaluate() methods must be thread-safe. - * That is, multiple threads may call these methods on the same - * ExpressionEvaluator object simultaneously. Implementations should - * synchronize access if they depend on transient state. Implementations - * should not, however, assume that only one object of each - * ExpressionEvaluator type will be instantiated; global caching should - * therefore be static.

- * - *

Only a single EL expression, starting with '${' and ending with - * '}', can be parsed or evaluated at a time. EL expressions - * cannot be mixed with static text. For example, attempting to - * parse or evaluate "abc${1+1}def${1+1}ghi" or even - * "${1+1}${1+1}" will cause an ELException to - * be thrown.

- * - *

The following are examples of syntactically legal EL expressions: - * - *

    - *
  • ${person.lastName}
  • - *
  • ${8 * 8}
  • - *
  • ${my:reverse('hello')}
  • - *
- *

- * - * @since 2.0 - * @deprecated - */ -public abstract class ExpressionEvaluator { - - /** - * Prepare an expression for later evaluation. This method should perform - * syntactic validation of the expression; if in doing so it detects - * errors, it should raise an ELParseException. - * - * @param expression The expression to be evaluated. - * @param expectedType The expected type of the result of the evaluation - * @param fMapper A FunctionMapper to resolve functions found in - * the expression. It can be null, in which case no functions - * are supported for this invocation. The ExpressionEvaluator - * must not hold on to the FunctionMapper reference after - * returning from parseExpression(). The - * Expression object returned must invoke the same - * functions regardless of whether the mappings in the - * provided FunctionMapper instance change between - * calling ExpressionEvaluator.parseExpression() - * and Expression.evaluate(). - * @return The Expression object encapsulating the arguments. - * - * @exception ELException Thrown if parsing errors were found. - */ - public abstract Expression parseExpression( String expression, - Class expectedType, - FunctionMapper fMapper ) - throws ELException; - - - /** - * Evaluates an expression. This method may perform some syntactic - * validation and, if so, it should raise an ELParseException error if - * it encounters syntactic errors. EL evaluation errors should cause - * an ELException to be raised. - * - * @param expression The expression to be evaluated. - * @param expectedType The expected type of the result of the evaluation - * @param vResolver A VariableResolver instance that can be used at - * runtime to resolve the name of implicit objects into Objects. - * @param fMapper A FunctionMapper to resolve functions found in - * the expression. It can be null, in which case no functions - * are supported for this invocation. - * @return The result of the expression evaluation. - * - * @exception ELException Thrown if the expression evaluation failed. - */ - public abstract Object evaluate( String expression, - Class expectedType, - VariableResolver vResolver, - FunctionMapper fMapper ) - throws ELException; -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.el; + + +/** + *

The abstract base class for an expression-language evaluator. + * Classes that implement an expression language expose their functionality + * via this abstract class.

+ * + *

An instance of the ExpressionEvaluator can be obtained via the + * JspContext / PageContext

+ * + *

The parseExpression() and evaluate() methods must be thread-safe. + * That is, multiple threads may call these methods on the same + * ExpressionEvaluator object simultaneously. Implementations should + * synchronize access if they depend on transient state. Implementations + * should not, however, assume that only one object of each + * ExpressionEvaluator type will be instantiated; global caching should + * therefore be static.

+ * + *

Only a single EL expression, starting with '${' and ending with + * '}', can be parsed or evaluated at a time. EL expressions + * cannot be mixed with static text. For example, attempting to + * parse or evaluate "abc${1+1}def${1+1}ghi" or even + * "${1+1}${1+1}" will cause an ELException to + * be thrown.

+ * + *

The following are examples of syntactically legal EL expressions: + * + *

    + *
  • ${person.lastName}
  • + *
  • ${8 * 8}
  • + *
  • ${my:reverse('hello')}
  • + *
+ *

+ * + * @since 2.0 + * @deprecated + */ +public abstract class ExpressionEvaluator { + + /** + * Prepare an expression for later evaluation. This method should perform + * syntactic validation of the expression; if in doing so it detects + * errors, it should raise an ELParseException. + * + * @param expression The expression to be evaluated. + * @param expectedType The expected type of the result of the evaluation + * @param fMapper A FunctionMapper to resolve functions found in + * the expression. It can be null, in which case no functions + * are supported for this invocation. The ExpressionEvaluator + * must not hold on to the FunctionMapper reference after + * returning from parseExpression(). The + * Expression object returned must invoke the same + * functions regardless of whether the mappings in the + * provided FunctionMapper instance change between + * calling ExpressionEvaluator.parseExpression() + * and Expression.evaluate(). + * @return The Expression object encapsulating the arguments. + * + * @exception ELException Thrown if parsing errors were found. + */ + public abstract Expression parseExpression( String expression, + Class expectedType, + FunctionMapper fMapper ) + throws ELException; + + + /** + * Evaluates an expression. This method may perform some syntactic + * validation and, if so, it should raise an ELParseException error if + * it encounters syntactic errors. EL evaluation errors should cause + * an ELException to be raised. + * + * @param expression The expression to be evaluated. + * @param expectedType The expected type of the result of the evaluation + * @param vResolver A VariableResolver instance that can be used at + * runtime to resolve the name of implicit objects into Objects. + * @param fMapper A FunctionMapper to resolve functions found in + * the expression. It can be null, in which case no functions + * are supported for this invocation. + * @return The result of the expression evaluation. + * + * @exception ELException Thrown if the expression evaluation failed. + */ + public abstract Object evaluate( String expression, + Class expectedType, + VariableResolver vResolver, + FunctionMapper fMapper ) + throws ELException; +} + diff --git a/java/javax/servlet/jsp/el/FunctionMapper.java b/java/javax/servlet/jsp/el/FunctionMapper.java index 078ed7150..f518eaf95 100644 --- a/java/javax/servlet/jsp/el/FunctionMapper.java +++ b/java/javax/servlet/jsp/el/FunctionMapper.java @@ -1,39 +1,39 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.el; - -/** - *

The interface to a map between EL function names and methods.

- * - *

Classes implementing this interface may, for instance, consult tag library - * information to resolve the map.

- * - * @since 2.0 - * @deprecated - */ -public interface FunctionMapper { - /** - * Resolves the specified local name and prefix into a Java.lang.Method. - * Returns null if the prefix and local name are not found. - * - * @param prefix the prefix of the function, or "" if no prefix. - * @param localName the short name of the function - * @return the result of the method mapping. Null means no entry found. - **/ - public java.lang.reflect.Method resolveFunction(String prefix, - String localName); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.el; + +/** + *

The interface to a map between EL function names and methods.

+ * + *

Classes implementing this interface may, for instance, consult tag library + * information to resolve the map.

+ * + * @since 2.0 + * @deprecated + */ +public interface FunctionMapper { + /** + * Resolves the specified local name and prefix into a Java.lang.Method. + * Returns null if the prefix and local name are not found. + * + * @param prefix the prefix of the function, or "" if no prefix. + * @param localName the short name of the function + * @return the result of the method mapping. Null means no entry found. + **/ + public java.lang.reflect.Method resolveFunction(String prefix, + String localName); +} diff --git a/java/javax/servlet/jsp/el/ImplicitObjectELResolver.java b/java/javax/servlet/jsp/el/ImplicitObjectELResolver.java index 0dbb304c8..339ed29b3 100644 --- a/java/javax/servlet/jsp/el/ImplicitObjectELResolver.java +++ b/java/javax/servlet/jsp/el/ImplicitObjectELResolver.java @@ -1,538 +1,538 @@ -package javax.servlet.jsp.el; - -import java.beans.FeatureDescriptor; -import java.util.AbstractMap; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.Vector; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.PropertyNotFoundException; -import javax.el.PropertyNotWritableException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.PageContext; - -/** - * - * @since 2.1 - */ -public class ImplicitObjectELResolver extends ELResolver { - - private final static String[] SCOPE_NAMES = new String[] { - "applicationScope", "cookie", "header", "headerValues", - "initParam", "pageContext", "pageScope", "param", "paramValues", - "requestScope", "sessionScope" }; - - private final static int APPLICATIONSCOPE = 0; - - private final static int COOKIE = 1; - - private final static int HEADER = 2; - - private final static int HEADERVALUES = 3; - - private final static int INITPARAM = 4; - - private final static int PAGECONTEXT = 5; - - private final static int PAGESCOPE = 6; - - private final static int PARAM = 7; - - private final static int PARAM_VALUES = 8; - - private final static int REQUEST_SCOPE = 9; - - private final static int SESSION_SCOPE = 10; - - public ImplicitObjectELResolver() { - super(); - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null && property != null) { - int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); - - if (idx >= 0) { - PageContext page = (PageContext) context - .getContext(JspContext.class); - context.setPropertyResolved(true); - switch (idx) { - case APPLICATIONSCOPE: - return ScopeManager.get(page).getApplicationScope(); - case COOKIE: - return ScopeManager.get(page).getCookie(); - case HEADER: - return ScopeManager.get(page).getHeader(); - case HEADERVALUES: - return ScopeManager.get(page).getHeaderValues(); - case INITPARAM: - return ScopeManager.get(page).getInitParam(); - case PAGECONTEXT: - return ScopeManager.get(page).getPageContext(); - case PAGESCOPE: - return ScopeManager.get(page).getPageScope(); - case PARAM: - return ScopeManager.get(page).getParam(); - case PARAM_VALUES: - return ScopeManager.get(page).getParamValues(); - case REQUEST_SCOPE: - return ScopeManager.get(page).getRequestScope(); - case SESSION_SCOPE: - return ScopeManager.get(page).getSessionScope(); - } - } - } - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null && property != null) { - int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); - if (idx >= 0) { - context.setPropertyResolved(true); - } - } - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null && property != null) { - int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); - if (idx >= 0) { - context.setPropertyResolved(true); - throw new PropertyNotWritableException(); - } - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null && property != null) { - int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); - if (idx >= 0) { - context.setPropertyResolved(true); - return true; - } - } - return false; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - List feats = new ArrayList( - SCOPE_NAMES.length); - FeatureDescriptor feat; - for (int i = 0; i < SCOPE_NAMES.length; i++) { - feat = new FeatureDescriptor(); - feat.setDisplayName(SCOPE_NAMES[i]); - feat.setExpert(false); - feat.setHidden(false); - feat.setName(SCOPE_NAMES[i]); - feat.setPreferred(true); - feat.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); - feat.setValue(TYPE, String.class); - feats.add(feat); - } - return feats.iterator(); - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base == null) { - return String.class; - } - return null; - } - - private static class ScopeManager { - private final static String MNGR_KEY = ScopeManager.class.getName(); - - private final PageContext page; - - private Map applicationScope; - - private Map cookie; - - private Map header; - - private Map headerValues; - - private Map initParam; - - private Map pageScope; - - private Map param; - - private Map paramValues; - - private Map requestScope; - - private Map sessionScope; - - public ScopeManager(PageContext page) { - this.page = page; - } - - public static ScopeManager get(PageContext page) { - ScopeManager mngr = (ScopeManager) page.getAttribute(MNGR_KEY); - if (mngr == null) { - mngr = new ScopeManager(page); - page.setAttribute(MNGR_KEY, mngr); - } - return mngr; - } - - public Map getApplicationScope() { - if (this.applicationScope == null) { - this.applicationScope = new ScopeMap() { - protected void setAttribute(String name, Object value) { - page.getServletContext().setAttribute(name, value); - } - - protected void removeAttribute(String name) { - page.getServletContext().removeAttribute(name); - } - - protected Enumeration getAttributeNames() { - return page.getServletContext().getAttributeNames(); - } - - protected Object getAttribute(String name) { - return page.getServletContext().getAttribute(name); - } - }; - } - return this.applicationScope; - } - - public Map getCookie() { - if (this.cookie == null) { - this.cookie = new ScopeMap() { - protected Enumeration getAttributeNames() { - Cookie[] c = ((HttpServletRequest) page.getRequest()) - .getCookies(); - if (c != null) { - Vector v = new Vector(); - for (int i = 0; i < c.length; i++) { - v.add(c[i].getName()); - } - return v.elements(); - } - return null; - } - - protected Object getAttribute(String name) { - Cookie[] c = ((HttpServletRequest) page.getRequest()) - .getCookies(); - if (c != null) { - for (int i = 0; i < c.length; i++) { - if (name.equals(c[i].getName())) { - return c[i]; - } - } - } - return null; - } - - }; - } - return this.cookie; - } - - public Map getHeader() { - if (this.header == null) { - this.header = new ScopeMap() { - protected Enumeration getAttributeNames() { - return ((HttpServletRequest) page.getRequest()) - .getHeaderNames(); - } - - protected Object getAttribute(String name) { - return ((HttpServletRequest) page.getRequest()) - .getHeader(name); - } - }; - } - return this.header; - } - - public Map getHeaderValues() { - if (this.headerValues == null) { - this.headerValues = new ScopeMap() { - protected Enumeration getAttributeNames() { - return ((HttpServletRequest) page.getRequest()) - .getHeaderNames(); - } - - protected Object getAttribute(String name) { - Enumeration e = ((HttpServletRequest) page.getRequest()) - .getHeaders(name); - if (e != null) { - List list = new ArrayList(); - while (e.hasMoreElements()) { - list.add(e.nextElement().toString()); - } - return (String[]) list.toArray(new String[list - .size()]); - } - return null; - } - - }; - } - return this.headerValues; - } - - public Map getInitParam() { - if (this.initParam == null) { - this.initParam = new ScopeMap() { - protected Enumeration getAttributeNames() { - return page.getServletContext().getInitParameterNames(); - } - - protected Object getAttribute(String name) { - return page.getServletContext().getInitParameter(name); - } - }; - } - return this.initParam; - } - - public PageContext getPageContext() { - return this.page; - } - - public Map getPageScope() { - if (this.pageScope == null) { - this.pageScope = new ScopeMap() { - protected void setAttribute(String name, Object value) { - page.setAttribute(name, value); - } - - protected void removeAttribute(String name) { - page.removeAttribute(name); - } - - protected Enumeration getAttributeNames() { - return page - .getAttributeNamesInScope(PageContext.PAGE_SCOPE); - } - - protected Object getAttribute(String name) { - return page.getAttribute(name); - } - }; - } - return this.pageScope; - } - - public Map getParam() { - if (this.param == null) { - this.param = new ScopeMap() { - protected Enumeration getAttributeNames() { - return page.getRequest().getParameterNames(); - } - - protected Object getAttribute(String name) { - return page.getRequest().getParameter(name); - } - }; - } - return this.param; - } - - public Map getParamValues() { - if (this.paramValues == null) { - this.paramValues = new ScopeMap() { - protected Object getAttribute(String name) { - return page.getRequest().getParameterValues(name); - } - - protected Enumeration getAttributeNames() { - return page.getRequest().getParameterNames(); - } - }; - } - return this.paramValues; - } - - public Map getRequestScope() { - if (this.requestScope == null) { - this.requestScope = new ScopeMap() { - protected void setAttribute(String name, Object value) { - page.getRequest().setAttribute(name, value); - } - - protected void removeAttribute(String name) { - page.getRequest().removeAttribute(name); - } - - protected Enumeration getAttributeNames() { - return page.getRequest().getAttributeNames(); - } - - protected Object getAttribute(String name) { - return page.getAttribute(name); - } - }; - } - return this.requestScope; - } - - public Map getSessionScope() { - if (this.sessionScope == null) { - this.sessionScope = new ScopeMap() { - protected void setAttribute(String name, Object value) { - ((HttpServletRequest) page.getRequest()).getSession() - .setAttribute(name, value); - } - - protected void removeAttribute(String name) { - HttpSession session = page.getSession(); - if (session != null) { - session.removeAttribute(name); - } - } - - protected Enumeration getAttributeNames() { - HttpSession session = page.getSession(); - if (session != null) { - return session.getAttributeNames(); - } - return null; - } - - protected Object getAttribute(String name) { - HttpSession session = page.getSession(); - if (session != null) { - return session.getAttribute(name); - } - return null; - } - }; - } - return this.sessionScope; - } - } - - private abstract static class ScopeMap extends AbstractMap { - - protected abstract Enumeration getAttributeNames(); - - protected abstract Object getAttribute(String name); - - protected void removeAttribute(String name) { - throw new UnsupportedOperationException(); - } - - protected void setAttribute(String name, Object value) { - throw new UnsupportedOperationException(); - } - - public final Set entrySet() { - Enumeration e = getAttributeNames(); - Set set = new HashSet(); - if (e != null) { - while (e.hasMoreElements()) { - set.add(new ScopeEntry((String) e.nextElement())); - } - } - return set; - } - - private class ScopeEntry implements Map.Entry { - - private final String key; - - public ScopeEntry(String key) { - this.key = key; - } - - public Object getKey() { - return (Object) this.key; - } - - public Object getValue() { - return getAttribute(this.key); - } - - public Object setValue(Object value) { - if (value == null) { - removeAttribute(this.key); - } else { - setAttribute(this.key, value); - } - return null; - } - - public boolean equals(Object obj) { - return (obj != null && this.hashCode() == obj.hashCode()); - } - - public int hashCode() { - return this.key.hashCode(); - } - - } - - public final Object get(Object key) { - if (key != null) { - return getAttribute(key.toString()); - } - return null; - } - - public final Object put(Object key, Object value) { - if (key == null) { - throw new NullPointerException(); - } - if (value == null) { - this.removeAttribute(key.toString()); - } else { - this.setAttribute(key.toString(), value); - } - return null; - } - - public final Object remove(Object key) { - if (key == null) { - throw new NullPointerException(); - } - this.removeAttribute(key.toString()); - return null; - } - - } - -} +package javax.servlet.jsp.el; + +import java.beans.FeatureDescriptor; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Vector; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.PropertyNotFoundException; +import javax.el.PropertyNotWritableException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.PageContext; + +/** + * + * @since 2.1 + */ +public class ImplicitObjectELResolver extends ELResolver { + + private final static String[] SCOPE_NAMES = new String[] { + "applicationScope", "cookie", "header", "headerValues", + "initParam", "pageContext", "pageScope", "param", "paramValues", + "requestScope", "sessionScope" }; + + private final static int APPLICATIONSCOPE = 0; + + private final static int COOKIE = 1; + + private final static int HEADER = 2; + + private final static int HEADERVALUES = 3; + + private final static int INITPARAM = 4; + + private final static int PAGECONTEXT = 5; + + private final static int PAGESCOPE = 6; + + private final static int PARAM = 7; + + private final static int PARAM_VALUES = 8; + + private final static int REQUEST_SCOPE = 9; + + private final static int SESSION_SCOPE = 10; + + public ImplicitObjectELResolver() { + super(); + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null && property != null) { + int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); + + if (idx >= 0) { + PageContext page = (PageContext) context + .getContext(JspContext.class); + context.setPropertyResolved(true); + switch (idx) { + case APPLICATIONSCOPE: + return ScopeManager.get(page).getApplicationScope(); + case COOKIE: + return ScopeManager.get(page).getCookie(); + case HEADER: + return ScopeManager.get(page).getHeader(); + case HEADERVALUES: + return ScopeManager.get(page).getHeaderValues(); + case INITPARAM: + return ScopeManager.get(page).getInitParam(); + case PAGECONTEXT: + return ScopeManager.get(page).getPageContext(); + case PAGESCOPE: + return ScopeManager.get(page).getPageScope(); + case PARAM: + return ScopeManager.get(page).getParam(); + case PARAM_VALUES: + return ScopeManager.get(page).getParamValues(); + case REQUEST_SCOPE: + return ScopeManager.get(page).getRequestScope(); + case SESSION_SCOPE: + return ScopeManager.get(page).getSessionScope(); + } + } + } + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null && property != null) { + int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); + if (idx >= 0) { + context.setPropertyResolved(true); + } + } + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null && property != null) { + int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); + if (idx >= 0) { + context.setPropertyResolved(true); + throw new PropertyNotWritableException(); + } + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null && property != null) { + int idx = Arrays.binarySearch(SCOPE_NAMES, property.toString()); + if (idx >= 0) { + context.setPropertyResolved(true); + return true; + } + } + return false; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + List feats = new ArrayList( + SCOPE_NAMES.length); + FeatureDescriptor feat; + for (int i = 0; i < SCOPE_NAMES.length; i++) { + feat = new FeatureDescriptor(); + feat.setDisplayName(SCOPE_NAMES[i]); + feat.setExpert(false); + feat.setHidden(false); + feat.setName(SCOPE_NAMES[i]); + feat.setPreferred(true); + feat.setValue(RESOLVABLE_AT_DESIGN_TIME, Boolean.TRUE); + feat.setValue(TYPE, String.class); + feats.add(feat); + } + return feats.iterator(); + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base == null) { + return String.class; + } + return null; + } + + private static class ScopeManager { + private final static String MNGR_KEY = ScopeManager.class.getName(); + + private final PageContext page; + + private Map applicationScope; + + private Map cookie; + + private Map header; + + private Map headerValues; + + private Map initParam; + + private Map pageScope; + + private Map param; + + private Map paramValues; + + private Map requestScope; + + private Map sessionScope; + + public ScopeManager(PageContext page) { + this.page = page; + } + + public static ScopeManager get(PageContext page) { + ScopeManager mngr = (ScopeManager) page.getAttribute(MNGR_KEY); + if (mngr == null) { + mngr = new ScopeManager(page); + page.setAttribute(MNGR_KEY, mngr); + } + return mngr; + } + + public Map getApplicationScope() { + if (this.applicationScope == null) { + this.applicationScope = new ScopeMap() { + protected void setAttribute(String name, Object value) { + page.getServletContext().setAttribute(name, value); + } + + protected void removeAttribute(String name) { + page.getServletContext().removeAttribute(name); + } + + protected Enumeration getAttributeNames() { + return page.getServletContext().getAttributeNames(); + } + + protected Object getAttribute(String name) { + return page.getServletContext().getAttribute(name); + } + }; + } + return this.applicationScope; + } + + public Map getCookie() { + if (this.cookie == null) { + this.cookie = new ScopeMap() { + protected Enumeration getAttributeNames() { + Cookie[] c = ((HttpServletRequest) page.getRequest()) + .getCookies(); + if (c != null) { + Vector v = new Vector(); + for (int i = 0; i < c.length; i++) { + v.add(c[i].getName()); + } + return v.elements(); + } + return null; + } + + protected Object getAttribute(String name) { + Cookie[] c = ((HttpServletRequest) page.getRequest()) + .getCookies(); + if (c != null) { + for (int i = 0; i < c.length; i++) { + if (name.equals(c[i].getName())) { + return c[i]; + } + } + } + return null; + } + + }; + } + return this.cookie; + } + + public Map getHeader() { + if (this.header == null) { + this.header = new ScopeMap() { + protected Enumeration getAttributeNames() { + return ((HttpServletRequest) page.getRequest()) + .getHeaderNames(); + } + + protected Object getAttribute(String name) { + return ((HttpServletRequest) page.getRequest()) + .getHeader(name); + } + }; + } + return this.header; + } + + public Map getHeaderValues() { + if (this.headerValues == null) { + this.headerValues = new ScopeMap() { + protected Enumeration getAttributeNames() { + return ((HttpServletRequest) page.getRequest()) + .getHeaderNames(); + } + + protected Object getAttribute(String name) { + Enumeration e = ((HttpServletRequest) page.getRequest()) + .getHeaders(name); + if (e != null) { + List list = new ArrayList(); + while (e.hasMoreElements()) { + list.add(e.nextElement().toString()); + } + return (String[]) list.toArray(new String[list + .size()]); + } + return null; + } + + }; + } + return this.headerValues; + } + + public Map getInitParam() { + if (this.initParam == null) { + this.initParam = new ScopeMap() { + protected Enumeration getAttributeNames() { + return page.getServletContext().getInitParameterNames(); + } + + protected Object getAttribute(String name) { + return page.getServletContext().getInitParameter(name); + } + }; + } + return this.initParam; + } + + public PageContext getPageContext() { + return this.page; + } + + public Map getPageScope() { + if (this.pageScope == null) { + this.pageScope = new ScopeMap() { + protected void setAttribute(String name, Object value) { + page.setAttribute(name, value); + } + + protected void removeAttribute(String name) { + page.removeAttribute(name); + } + + protected Enumeration getAttributeNames() { + return page + .getAttributeNamesInScope(PageContext.PAGE_SCOPE); + } + + protected Object getAttribute(String name) { + return page.getAttribute(name); + } + }; + } + return this.pageScope; + } + + public Map getParam() { + if (this.param == null) { + this.param = new ScopeMap() { + protected Enumeration getAttributeNames() { + return page.getRequest().getParameterNames(); + } + + protected Object getAttribute(String name) { + return page.getRequest().getParameter(name); + } + }; + } + return this.param; + } + + public Map getParamValues() { + if (this.paramValues == null) { + this.paramValues = new ScopeMap() { + protected Object getAttribute(String name) { + return page.getRequest().getParameterValues(name); + } + + protected Enumeration getAttributeNames() { + return page.getRequest().getParameterNames(); + } + }; + } + return this.paramValues; + } + + public Map getRequestScope() { + if (this.requestScope == null) { + this.requestScope = new ScopeMap() { + protected void setAttribute(String name, Object value) { + page.getRequest().setAttribute(name, value); + } + + protected void removeAttribute(String name) { + page.getRequest().removeAttribute(name); + } + + protected Enumeration getAttributeNames() { + return page.getRequest().getAttributeNames(); + } + + protected Object getAttribute(String name) { + return page.getAttribute(name); + } + }; + } + return this.requestScope; + } + + public Map getSessionScope() { + if (this.sessionScope == null) { + this.sessionScope = new ScopeMap() { + protected void setAttribute(String name, Object value) { + ((HttpServletRequest) page.getRequest()).getSession() + .setAttribute(name, value); + } + + protected void removeAttribute(String name) { + HttpSession session = page.getSession(); + if (session != null) { + session.removeAttribute(name); + } + } + + protected Enumeration getAttributeNames() { + HttpSession session = page.getSession(); + if (session != null) { + return session.getAttributeNames(); + } + return null; + } + + protected Object getAttribute(String name) { + HttpSession session = page.getSession(); + if (session != null) { + return session.getAttribute(name); + } + return null; + } + }; + } + return this.sessionScope; + } + } + + private abstract static class ScopeMap extends AbstractMap { + + protected abstract Enumeration getAttributeNames(); + + protected abstract Object getAttribute(String name); + + protected void removeAttribute(String name) { + throw new UnsupportedOperationException(); + } + + protected void setAttribute(String name, Object value) { + throw new UnsupportedOperationException(); + } + + public final Set entrySet() { + Enumeration e = getAttributeNames(); + Set set = new HashSet(); + if (e != null) { + while (e.hasMoreElements()) { + set.add(new ScopeEntry((String) e.nextElement())); + } + } + return set; + } + + private class ScopeEntry implements Map.Entry { + + private final String key; + + public ScopeEntry(String key) { + this.key = key; + } + + public Object getKey() { + return (Object) this.key; + } + + public Object getValue() { + return getAttribute(this.key); + } + + public Object setValue(Object value) { + if (value == null) { + removeAttribute(this.key); + } else { + setAttribute(this.key, value); + } + return null; + } + + public boolean equals(Object obj) { + return (obj != null && this.hashCode() == obj.hashCode()); + } + + public int hashCode() { + return this.key.hashCode(); + } + + } + + public final Object get(Object key) { + if (key != null) { + return getAttribute(key.toString()); + } + return null; + } + + public final Object put(Object key, Object value) { + if (key == null) { + throw new NullPointerException(); + } + if (value == null) { + this.removeAttribute(key.toString()); + } else { + this.setAttribute(key.toString(), value); + } + return null; + } + + public final Object remove(Object key) { + if (key == null) { + throw new NullPointerException(); + } + this.removeAttribute(key.toString()); + return null; + } + + } + +} diff --git a/java/javax/servlet/jsp/el/ScopedAttributeELResolver.java b/java/javax/servlet/jsp/el/ScopedAttributeELResolver.java index 8930f33c9..d57ca4ac0 100644 --- a/java/javax/servlet/jsp/el/ScopedAttributeELResolver.java +++ b/java/javax/servlet/jsp/el/ScopedAttributeELResolver.java @@ -1,182 +1,182 @@ -package javax.servlet.jsp.el; - -import java.beans.FeatureDescriptor; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.PropertyNotFoundException; -import javax.el.PropertyNotWritableException; -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.PageContext; - -public class ScopedAttributeELResolver extends ELResolver { - - public ScopedAttributeELResolver() { - super(); - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - if (property != null) { - String key = property.toString(); - PageContext page = (PageContext) context - .getContext(JspContext.class); - return page.findAttribute(key); - } - } - - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - return Object.class; - } - - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - if (property != null) { - String key = property.toString(); - PageContext page = (PageContext) context - .getContext(JspContext.class); - int scope = page.getAttributesScope(key); - if (scope != 0) { - page.setAttribute(key, value, scope); - } else { - page.setAttribute(key, value); - } - } - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - } - - return false; - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - - PageContext ctxt = (PageContext) context.getContext(JspContext.class); - List list = new ArrayList(); - Enumeration e; - Object value; - String name; - - e = ctxt.getAttributeNamesInScope(PageContext.PAGE_SCOPE); - while (e.hasMoreElements()) { - name = (String) e.nextElement(); - value = ctxt.getAttribute(name, PageContext.PAGE_SCOPE); - FeatureDescriptor descriptor = new FeatureDescriptor(); - descriptor.setName(name); - descriptor.setDisplayName(name); - descriptor.setExpert(false); - descriptor.setHidden(false); - descriptor.setPreferred(true); - descriptor.setShortDescription("page scoped attribute"); - descriptor.setValue("type", value.getClass()); - descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); - list.add(descriptor); - } - - e = ctxt.getAttributeNamesInScope(PageContext.REQUEST_SCOPE); - while (e.hasMoreElements()) { - name = (String) e.nextElement(); - value = ctxt.getAttribute(name, PageContext.REQUEST_SCOPE); - FeatureDescriptor descriptor = new FeatureDescriptor(); - descriptor.setName(name); - descriptor.setDisplayName(name); - descriptor.setExpert(false); - descriptor.setHidden(false); - descriptor.setPreferred(true); - descriptor.setShortDescription("request scope attribute"); - descriptor.setValue("type", value.getClass()); - descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); - list.add(descriptor); - } - - if (ctxt.getSession() != null) { - e = ctxt.getAttributeNamesInScope(PageContext.SESSION_SCOPE); - while (e.hasMoreElements()) { - name = (String) e.nextElement(); - value = ctxt.getAttribute(name, PageContext.SESSION_SCOPE); - FeatureDescriptor descriptor = new FeatureDescriptor(); - descriptor.setName(name); - descriptor.setDisplayName(name); - descriptor.setExpert(false); - descriptor.setHidden(false); - descriptor.setPreferred(true); - descriptor.setShortDescription("session scoped attribute"); - descriptor.setValue("type", value.getClass()); - descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); - list.add(descriptor); - } - } - - e = ctxt.getAttributeNamesInScope(PageContext.APPLICATION_SCOPE); - while (e.hasMoreElements()) { - name = (String) e.nextElement(); - value = ctxt.getAttribute(name, PageContext.APPLICATION_SCOPE); - FeatureDescriptor descriptor = new FeatureDescriptor(); - descriptor.setName(name); - descriptor.setDisplayName(name); - descriptor.setExpert(false); - descriptor.setHidden(false); - descriptor.setPreferred(true); - descriptor.setShortDescription("application scoped attribute"); - descriptor.setValue("type", value.getClass()); - descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); - list.add(descriptor); - } - return list.iterator(); - } - - private static void appendEnumeration(Collection c, Enumeration e) { - while (e.hasMoreElements()) { - c.add(e.nextElement()); - } - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base == null) { - return String.class; - } - return null; - } -} +package javax.servlet.jsp.el; + +import java.beans.FeatureDescriptor; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.PropertyNotFoundException; +import javax.el.PropertyNotWritableException; +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.PageContext; + +public class ScopedAttributeELResolver extends ELResolver { + + public ScopedAttributeELResolver() { + super(); + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + if (property != null) { + String key = property.toString(); + PageContext page = (PageContext) context + .getContext(JspContext.class); + return page.findAttribute(key); + } + } + + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + return Object.class; + } + + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + if (property != null) { + String key = property.toString(); + PageContext page = (PageContext) context + .getContext(JspContext.class); + int scope = page.getAttributesScope(key); + if (scope != 0) { + page.setAttribute(key, value, scope); + } else { + page.setAttribute(key, value); + } + } + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + } + + return false; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + + PageContext ctxt = (PageContext) context.getContext(JspContext.class); + List list = new ArrayList(); + Enumeration e; + Object value; + String name; + + e = ctxt.getAttributeNamesInScope(PageContext.PAGE_SCOPE); + while (e.hasMoreElements()) { + name = (String) e.nextElement(); + value = ctxt.getAttribute(name, PageContext.PAGE_SCOPE); + FeatureDescriptor descriptor = new FeatureDescriptor(); + descriptor.setName(name); + descriptor.setDisplayName(name); + descriptor.setExpert(false); + descriptor.setHidden(false); + descriptor.setPreferred(true); + descriptor.setShortDescription("page scoped attribute"); + descriptor.setValue("type", value.getClass()); + descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(descriptor); + } + + e = ctxt.getAttributeNamesInScope(PageContext.REQUEST_SCOPE); + while (e.hasMoreElements()) { + name = (String) e.nextElement(); + value = ctxt.getAttribute(name, PageContext.REQUEST_SCOPE); + FeatureDescriptor descriptor = new FeatureDescriptor(); + descriptor.setName(name); + descriptor.setDisplayName(name); + descriptor.setExpert(false); + descriptor.setHidden(false); + descriptor.setPreferred(true); + descriptor.setShortDescription("request scope attribute"); + descriptor.setValue("type", value.getClass()); + descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(descriptor); + } + + if (ctxt.getSession() != null) { + e = ctxt.getAttributeNamesInScope(PageContext.SESSION_SCOPE); + while (e.hasMoreElements()) { + name = (String) e.nextElement(); + value = ctxt.getAttribute(name, PageContext.SESSION_SCOPE); + FeatureDescriptor descriptor = new FeatureDescriptor(); + descriptor.setName(name); + descriptor.setDisplayName(name); + descriptor.setExpert(false); + descriptor.setHidden(false); + descriptor.setPreferred(true); + descriptor.setShortDescription("session scoped attribute"); + descriptor.setValue("type", value.getClass()); + descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(descriptor); + } + } + + e = ctxt.getAttributeNamesInScope(PageContext.APPLICATION_SCOPE); + while (e.hasMoreElements()) { + name = (String) e.nextElement(); + value = ctxt.getAttribute(name, PageContext.APPLICATION_SCOPE); + FeatureDescriptor descriptor = new FeatureDescriptor(); + descriptor.setName(name); + descriptor.setDisplayName(name); + descriptor.setExpert(false); + descriptor.setHidden(false); + descriptor.setPreferred(true); + descriptor.setShortDescription("application scoped attribute"); + descriptor.setValue("type", value.getClass()); + descriptor.setValue("resolvableAtDesignTime", Boolean.FALSE); + list.add(descriptor); + } + return list.iterator(); + } + + private static void appendEnumeration(Collection c, Enumeration e) { + while (e.hasMoreElements()) { + c.add(e.nextElement()); + } + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base == null) { + return String.class; + } + return null; + } +} diff --git a/java/javax/servlet/jsp/el/VariableResolver.java b/java/javax/servlet/jsp/el/VariableResolver.java index e1f1ca3b5..c377b7229 100644 --- a/java/javax/servlet/jsp/el/VariableResolver.java +++ b/java/javax/servlet/jsp/el/VariableResolver.java @@ -1,50 +1,50 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.el; - -/** - *

This class is used to customize the way an ExpressionEvaluator resolves - * variable references at evaluation time. For example, instances of this class can - * implement their own variable lookup mechanisms, or introduce the - * notion of "implicit variables" which override any other variables. - * An instance of this class should be passed when evaluating - * an expression.

- * - *

An instance of this class includes the context against which resolution - * will happen

- * - * @since 2.0 - * @deprecated - */ -public interface VariableResolver -{ - //------------------------------------- - /** - * Resolves the specified variable. - * Returns null if the variable is not found. - * - * @param pName the name of the variable to resolve - * @return the result of the variable resolution - * - * @throws ELException if a failure occurred while trying to resolve - * the given variable - **/ - public Object resolveVariable (String pName) - throws ELException; - - //------------------------------------- -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.el; + +/** + *

This class is used to customize the way an ExpressionEvaluator resolves + * variable references at evaluation time. For example, instances of this class can + * implement their own variable lookup mechanisms, or introduce the + * notion of "implicit variables" which override any other variables. + * An instance of this class should be passed when evaluating + * an expression.

+ * + *

An instance of this class includes the context against which resolution + * will happen

+ * + * @since 2.0 + * @deprecated + */ +public interface VariableResolver +{ + //------------------------------------- + /** + * Resolves the specified variable. + * Returns null if the variable is not found. + * + * @param pName the name of the variable to resolve + * @return the result of the variable resolution + * + * @throws ELException if a failure occurred while trying to resolve + * the given variable + **/ + public Object resolveVariable (String pName) + throws ELException; + + //------------------------------------- +} diff --git a/java/javax/servlet/jsp/el/package.html b/java/javax/servlet/jsp/el/package.html index c7a18ba63..f0eafbb4a 100644 --- a/java/javax/servlet/jsp/el/package.html +++ b/java/javax/servlet/jsp/el/package.html @@ -1,75 +1,75 @@ - - - - - - - -Classes and interfaces for the JSP 2.0 Expression Language API. - -

-The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable -API for evaluating "EL Expressions". As of JSP 2.0, EL expressions can -be placed directly in the template text of JSP pages and tag files. -

-This package contains a number of classes and interfaces that describe -and define programmatic access to the Expression Language evaluator. -This API can also be used by an implementation of JSP to evaluate the -expressions, but other implementations, like open-coding into Java -bytecodes, are allowed. This package is intended to have no dependencies -on other portions of the JSP 2.0 specification. - - + + + + + + + +Classes and interfaces for the JSP 2.0 Expression Language API. + +

+The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable +API for evaluating "EL Expressions". As of JSP 2.0, EL expressions can +be placed directly in the template text of JSP pages and tag files. +

+This package contains a number of classes and interfaces that describe +and define programmatic access to the Expression Language evaluator. +This API can also be used by an implementation of JSP to evaluate the +expressions, but other implementations, like open-coding into Java +bytecodes, are allowed. This package is intended to have no dependencies +on other portions of the JSP 2.0 specification. + + diff --git a/java/javax/servlet/jsp/package.html b/java/javax/servlet/jsp/package.html index 7a5c4d978..f0eafb965 100644 --- a/java/javax/servlet/jsp/package.html +++ b/java/javax/servlet/jsp/package.html @@ -1,67 +1,67 @@ - - - - - - -Classes and interfaces for the Core JSP 2.0 API. -

-The javax.servlet.jsp package contains a number of classes and -interfaces that describe and define the contracts between a JSP page -implementation class and the runtime environment provided for an -instance of such a class by a conforming JSP container. - - + + + + + + +Classes and interfaces for the Core JSP 2.0 API. +

+The javax.servlet.jsp package contains a number of classes and +interfaces that describe and define the contracts between a JSP page +implementation class and the runtime environment provided for an +instance of such a class by a conforming JSP container. + + diff --git a/java/javax/servlet/jsp/tagext/BodyContent.java b/java/javax/servlet/jsp/tagext/BodyContent.java index f34d297bb..ca09e2f1d 100644 --- a/java/javax/servlet/jsp/tagext/BodyContent.java +++ b/java/javax/servlet/jsp/tagext/BodyContent.java @@ -1,138 +1,138 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import java.io.Reader; -import java.io.Writer; -import java.io.IOException; -import javax.servlet.jsp.*; - -/** - * An encapsulation of the evaluation of the body of an action so it is - * available to a tag handler. BodyContent is a subclass of JspWriter. - * - *

- * Note that the content of BodyContent is the result of evaluation, so - * it will not contain actions and the like, but the result of their - * invocation. - * - *

- * BodyContent has methods to convert its contents into - * a String, to read its contents, and to clear the contents. - * - *

- * The buffer size of a BodyContent object is unbounded. A - * BodyContent object cannot be in autoFlush mode. It is not possible to - * invoke flush on a BodyContent object, as there is no backing stream. - * - *

- * Instances of BodyContent are created by invoking the pushBody and - * popBody methods of the PageContext class. A BodyContent is enclosed - * within another JspWriter (maybe another BodyContent object) following - * the structure of their associated actions. - * - *

- * A BodyContent is made available to a BodyTag through a setBodyContent() - * call. The tag handler can use the object until after the call to - * doEndTag(). - */ - -public abstract class BodyContent extends JspWriter { - - /** - * Protected constructor. - * - * Unbounded buffer, no autoflushing. - * - * @param e the enclosing JspWriter - */ - - protected BodyContent(JspWriter e) { - super(UNBOUNDED_BUFFER , false); - this.enclosingWriter = e; - } - - /** - * Redefined flush() so it is not legal. - * - *

- * It is not valid to flush a BodyContent because there is no backing - * stream behind it. - * - * @throws IOException always thrown - */ - - public void flush() throws IOException { - throw new IOException("Illegal to flush within a custom tag"); - } - - /** - * Clear the body without throwing any exceptions. - */ - - public void clearBody() { - try { - this.clear(); - } catch (IOException ex) { - // TODO -- clean this one up. - throw new Error("internal error!;"); - } - } - - /** - * Return the value of this BodyContent as a Reader. - * - * @return the value of this BodyContent as a Reader - */ - public abstract Reader getReader(); - - - /** - * Return the value of the BodyContent as a String. - * - * @return the value of the BodyContent as a String - */ - public abstract String getString(); - - - /** - * Write the contents of this BodyContent into a Writer. - * Subclasses may optimize common invocation patterns. - * - * @param out The writer into which to place the contents of - * this body evaluation - * @throws IOException if an I/O error occurred while writing the - * contents of this BodyContent to the given Writer - */ - - public abstract void writeOut(Writer out) throws IOException; - - - /** - * Get the enclosing JspWriter. - * - * @return the enclosing JspWriter passed at construction time - */ - - public JspWriter getEnclosingWriter() { - return enclosingWriter; - } - - - // private fields - - private JspWriter enclosingWriter; - } +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import java.io.Reader; +import java.io.Writer; +import java.io.IOException; +import javax.servlet.jsp.*; + +/** + * An encapsulation of the evaluation of the body of an action so it is + * available to a tag handler. BodyContent is a subclass of JspWriter. + * + *

+ * Note that the content of BodyContent is the result of evaluation, so + * it will not contain actions and the like, but the result of their + * invocation. + * + *

+ * BodyContent has methods to convert its contents into + * a String, to read its contents, and to clear the contents. + * + *

+ * The buffer size of a BodyContent object is unbounded. A + * BodyContent object cannot be in autoFlush mode. It is not possible to + * invoke flush on a BodyContent object, as there is no backing stream. + * + *

+ * Instances of BodyContent are created by invoking the pushBody and + * popBody methods of the PageContext class. A BodyContent is enclosed + * within another JspWriter (maybe another BodyContent object) following + * the structure of their associated actions. + * + *

+ * A BodyContent is made available to a BodyTag through a setBodyContent() + * call. The tag handler can use the object until after the call to + * doEndTag(). + */ + +public abstract class BodyContent extends JspWriter { + + /** + * Protected constructor. + * + * Unbounded buffer, no autoflushing. + * + * @param e the enclosing JspWriter + */ + + protected BodyContent(JspWriter e) { + super(UNBOUNDED_BUFFER , false); + this.enclosingWriter = e; + } + + /** + * Redefined flush() so it is not legal. + * + *

+ * It is not valid to flush a BodyContent because there is no backing + * stream behind it. + * + * @throws IOException always thrown + */ + + public void flush() throws IOException { + throw new IOException("Illegal to flush within a custom tag"); + } + + /** + * Clear the body without throwing any exceptions. + */ + + public void clearBody() { + try { + this.clear(); + } catch (IOException ex) { + // TODO -- clean this one up. + throw new Error("internal error!;"); + } + } + + /** + * Return the value of this BodyContent as a Reader. + * + * @return the value of this BodyContent as a Reader + */ + public abstract Reader getReader(); + + + /** + * Return the value of the BodyContent as a String. + * + * @return the value of the BodyContent as a String + */ + public abstract String getString(); + + + /** + * Write the contents of this BodyContent into a Writer. + * Subclasses may optimize common invocation patterns. + * + * @param out The writer into which to place the contents of + * this body evaluation + * @throws IOException if an I/O error occurred while writing the + * contents of this BodyContent to the given Writer + */ + + public abstract void writeOut(Writer out) throws IOException; + + + /** + * Get the enclosing JspWriter. + * + * @return the enclosing JspWriter passed at construction time + */ + + public JspWriter getEnclosingWriter() { + return enclosingWriter; + } + + + // private fields + + private JspWriter enclosingWriter; + } diff --git a/java/javax/servlet/jsp/tagext/BodyTag.java b/java/javax/servlet/jsp/tagext/BodyTag.java index 04ec7d991..fa2d4f4e3 100644 --- a/java/javax/servlet/jsp/tagext/BodyTag.java +++ b/java/javax/servlet/jsp/tagext/BodyTag.java @@ -1,185 +1,185 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.*; - -/** - * The BodyTag interface extends IterationTag by defining additional - * methods that let a tag handler manipulate the content of evaluating its body. - * - *

- * It is the responsibility of the tag handler to manipulate the body - * content. For example the tag handler may take the body content, - * convert it into a String using the bodyContent.getString - * method and then use it. Or the tag handler may take the body - * content and write it out into its enclosing JspWriter using - * the bodyContent.writeOut method. - * - *

A tag handler that implements BodyTag is treated as one that - * implements IterationTag, except that the doStartTag method can - * return SKIP_BODY, EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED. - * - *

- * If EVAL_BODY_INCLUDE is returned, then evaluation happens - * as in IterationTag. - * - *

- * If EVAL_BODY_BUFFERED is returned, then a BodyContent object will be - * created (by code generated by the JSP compiler) to capture the body - * evaluation. - * The code generated by the JSP compiler obtains the BodyContent object by - * calling the pushBody method of the current pageContext, which - * additionally has the effect of saving the previous out value. - * The page compiler returns this object by calling the popBody - * method of the PageContext class; - * the call also restores the value of out. - * - *

- * The interface provides one new property with a setter method and one - * new action method. - * - *

Properties - *

There is a new property: bodyContent, to contain the BodyContent - * object, where the JSP Page implementation object will place the - * evaluation (and reevaluation, if appropriate) of the body. The setter - * method (setBodyContent) will only be invoked if doStartTag() returns - * EVAL_BODY_BUFFERED and the corresponding action element does not have - * an empty body. - * - *

Methods - *

In addition to the setter method for the bodyContent property, there - * is a new action method: doInitBody(), which is invoked right after - * setBodyContent() and before the body evaluation. This method is only - * invoked if doStartTag() returns EVAL_BODY_BUFFERED. - * - *

Lifecycle - *

Lifecycle details are described by the transition diagram below. - * Exceptions that are thrown during the computation of doStartTag(), - * setBodyContent(), doInitBody(), BODY, doAfterBody() interrupt the - * execution sequence and are propagated up the stack, unless the - * tag handler implements the TryCatchFinally interface; see that - * interface for details. - *

- * Lifecycle Details Transition Diagram for BodyTag - * - *

Empty and Non-Empty Action - *

If the TagLibraryDescriptor file indicates that the action must - * always have an empty element body, by an <body-content> entry - * of "empty", then the doStartTag() method must return SKIP_BODY. - * Otherwise, the doStartTag() method may return SKIP_BODY, - * EVAL_BODY_INCLUDE, or EVAL_BODY_BUFFERED. - * - *

Note that which methods are invoked after the doStartTag() depends on - * both the return value and on if the custom action element is empty - * or not in the JSP page, not how it's declared in the TLD. - * - *

- * If SKIP_BODY is returned the body is not evaluated, and doEndTag() is - * invoked. - * - *

- * If EVAL_BODY_INCLUDE is returned, and the custom action element is not - * empty, setBodyContent() is not invoked, - * doInitBody() is not invoked, the body is evaluated and - * "passed through" to the current out, doAfterBody() is invoked - * and then, after zero or more iterations, doEndTag() is invoked. - * If the custom action element is empty, only doStart() and - * doEndTag() are invoked. - * - *

- * If EVAL_BODY_BUFFERED is returned, and the custom action element is not - * empty, setBodyContent() is invoked, - * doInitBody() is invoked, the body is evaluated, doAfterBody() is - * invoked, and then, after zero or more iterations, doEndTag() is invoked. - * If the custom action element is empty, only doStart() and doEndTag() - * are invoked. - */ - -public interface BodyTag extends IterationTag { - - /** - * Deprecated constant that has the same value as EVAL_BODY_BUFFERED - * and EVAL_BODY_AGAIN. This name has been marked as deprecated - * to encourage the use of the two different terms, which are much - * more descriptive. - * - * @deprecated As of Java JSP API 1.2, use BodyTag.EVAL_BODY_BUFFERED - * or IterationTag.EVAL_BODY_AGAIN. - */ - - public final static int EVAL_BODY_TAG = 2; - - /** - * Request the creation of new buffer, a BodyContent on which to - * evaluate the body of this tag. - * - * Returned from doStartTag when it implements BodyTag. - * This is an illegal return value for doStartTag when the class - * does not implement BodyTag. - */ - - public final static int EVAL_BODY_BUFFERED = 2; - - - /** - * Set the bodyContent property. - * This method is invoked by the JSP page implementation object at - * most once per action invocation. - * This method will be invoked before doInitBody. - * This method will not be invoked for empty tags or for non-empty - * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE. - * - *

- * When setBodyContent is invoked, the value of the implicit object out - * has already been changed in the pageContext object. The BodyContent - * object passed will have not data on it but may have been reused - * (and cleared) from some previous invocation. - * - *

- * The BodyContent object is available and with the appropriate content - * until after the invocation of the doEndTag method, at which case it - * may be reused. - * - * @param b the BodyContent - * @see #doInitBody - * @see #doAfterBody - */ - - void setBodyContent(BodyContent b); - - - /** - * Prepare for evaluation of the body. - * This method is invoked by the JSP page implementation object - * after setBodyContent and before the first time - * the body is to be evaluated. - * This method will not be invoked for empty tags or for non-empty - * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE. - * - *

- * The JSP container will resynchronize the values of any AT_BEGIN and - * NESTED variables (defined by the associated TagExtraInfo or TLD) after - * the invocation of doInitBody(). - * - * @throws JspException if an error occurred while processing this tag - * @see #doAfterBody - */ - - void doInitBody() throws JspException; - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.*; + +/** + * The BodyTag interface extends IterationTag by defining additional + * methods that let a tag handler manipulate the content of evaluating its body. + * + *

+ * It is the responsibility of the tag handler to manipulate the body + * content. For example the tag handler may take the body content, + * convert it into a String using the bodyContent.getString + * method and then use it. Or the tag handler may take the body + * content and write it out into its enclosing JspWriter using + * the bodyContent.writeOut method. + * + *

A tag handler that implements BodyTag is treated as one that + * implements IterationTag, except that the doStartTag method can + * return SKIP_BODY, EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED. + * + *

+ * If EVAL_BODY_INCLUDE is returned, then evaluation happens + * as in IterationTag. + * + *

+ * If EVAL_BODY_BUFFERED is returned, then a BodyContent object will be + * created (by code generated by the JSP compiler) to capture the body + * evaluation. + * The code generated by the JSP compiler obtains the BodyContent object by + * calling the pushBody method of the current pageContext, which + * additionally has the effect of saving the previous out value. + * The page compiler returns this object by calling the popBody + * method of the PageContext class; + * the call also restores the value of out. + * + *

+ * The interface provides one new property with a setter method and one + * new action method. + * + *

Properties + *

There is a new property: bodyContent, to contain the BodyContent + * object, where the JSP Page implementation object will place the + * evaluation (and reevaluation, if appropriate) of the body. The setter + * method (setBodyContent) will only be invoked if doStartTag() returns + * EVAL_BODY_BUFFERED and the corresponding action element does not have + * an empty body. + * + *

Methods + *

In addition to the setter method for the bodyContent property, there + * is a new action method: doInitBody(), which is invoked right after + * setBodyContent() and before the body evaluation. This method is only + * invoked if doStartTag() returns EVAL_BODY_BUFFERED. + * + *

Lifecycle + *

Lifecycle details are described by the transition diagram below. + * Exceptions that are thrown during the computation of doStartTag(), + * setBodyContent(), doInitBody(), BODY, doAfterBody() interrupt the + * execution sequence and are propagated up the stack, unless the + * tag handler implements the TryCatchFinally interface; see that + * interface for details. + *

+ * Lifecycle Details Transition Diagram for BodyTag + * + *

Empty and Non-Empty Action + *

If the TagLibraryDescriptor file indicates that the action must + * always have an empty element body, by an <body-content> entry + * of "empty", then the doStartTag() method must return SKIP_BODY. + * Otherwise, the doStartTag() method may return SKIP_BODY, + * EVAL_BODY_INCLUDE, or EVAL_BODY_BUFFERED. + * + *

Note that which methods are invoked after the doStartTag() depends on + * both the return value and on if the custom action element is empty + * or not in the JSP page, not how it's declared in the TLD. + * + *

+ * If SKIP_BODY is returned the body is not evaluated, and doEndTag() is + * invoked. + * + *

+ * If EVAL_BODY_INCLUDE is returned, and the custom action element is not + * empty, setBodyContent() is not invoked, + * doInitBody() is not invoked, the body is evaluated and + * "passed through" to the current out, doAfterBody() is invoked + * and then, after zero or more iterations, doEndTag() is invoked. + * If the custom action element is empty, only doStart() and + * doEndTag() are invoked. + * + *

+ * If EVAL_BODY_BUFFERED is returned, and the custom action element is not + * empty, setBodyContent() is invoked, + * doInitBody() is invoked, the body is evaluated, doAfterBody() is + * invoked, and then, after zero or more iterations, doEndTag() is invoked. + * If the custom action element is empty, only doStart() and doEndTag() + * are invoked. + */ + +public interface BodyTag extends IterationTag { + + /** + * Deprecated constant that has the same value as EVAL_BODY_BUFFERED + * and EVAL_BODY_AGAIN. This name has been marked as deprecated + * to encourage the use of the two different terms, which are much + * more descriptive. + * + * @deprecated As of Java JSP API 1.2, use BodyTag.EVAL_BODY_BUFFERED + * or IterationTag.EVAL_BODY_AGAIN. + */ + + public final static int EVAL_BODY_TAG = 2; + + /** + * Request the creation of new buffer, a BodyContent on which to + * evaluate the body of this tag. + * + * Returned from doStartTag when it implements BodyTag. + * This is an illegal return value for doStartTag when the class + * does not implement BodyTag. + */ + + public final static int EVAL_BODY_BUFFERED = 2; + + + /** + * Set the bodyContent property. + * This method is invoked by the JSP page implementation object at + * most once per action invocation. + * This method will be invoked before doInitBody. + * This method will not be invoked for empty tags or for non-empty + * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE. + * + *

+ * When setBodyContent is invoked, the value of the implicit object out + * has already been changed in the pageContext object. The BodyContent + * object passed will have not data on it but may have been reused + * (and cleared) from some previous invocation. + * + *

+ * The BodyContent object is available and with the appropriate content + * until after the invocation of the doEndTag method, at which case it + * may be reused. + * + * @param b the BodyContent + * @see #doInitBody + * @see #doAfterBody + */ + + void setBodyContent(BodyContent b); + + + /** + * Prepare for evaluation of the body. + * This method is invoked by the JSP page implementation object + * after setBodyContent and before the first time + * the body is to be evaluated. + * This method will not be invoked for empty tags or for non-empty + * tags whose doStartTag() method returns SKIP_BODY or EVAL_BODY_INCLUDE. + * + *

+ * The JSP container will resynchronize the values of any AT_BEGIN and + * NESTED variables (defined by the associated TagExtraInfo or TLD) after + * the invocation of doInitBody(). + * + * @throws JspException if an error occurred while processing this tag + * @see #doAfterBody + */ + + void doInitBody() throws JspException; + +} diff --git a/java/javax/servlet/jsp/tagext/BodyTagSupport.java b/java/javax/servlet/jsp/tagext/BodyTagSupport.java index a9da03d66..d6bdc6b1c 100644 --- a/java/javax/servlet/jsp/tagext/BodyTagSupport.java +++ b/java/javax/servlet/jsp/tagext/BodyTagSupport.java @@ -1,159 +1,159 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.JspWriter; - -/** - * A base class for defining tag handlers implementing BodyTag. - * - *

- * The BodyTagSupport class implements the BodyTag interface and adds - * additional convenience methods including getter methods for the - * bodyContent property and methods to get at the previous out JspWriter. - * - *

- * Many tag handlers will extend BodyTagSupport and only redefine a - * few methods. - */ - -public class BodyTagSupport extends TagSupport implements BodyTag { - - /** - * Default constructor, all subclasses are required to only define - * a public constructor with the same signature, and to call the - * superclass constructor. - * - * This constructor is called by the code generated by the JSP - * translator. - */ - - public BodyTagSupport() { - super(); - } - - /** - * Default processing of the start tag returning EVAL_BODY_BUFFERED. - * - * @return EVAL_BODY_BUFFERED - * @throws JspException if an error occurred while processing this tag - * @see BodyTag#doStartTag - */ - - public int doStartTag() throws JspException { - return EVAL_BODY_BUFFERED; - } - - - /** - * Default processing of the end tag returning EVAL_PAGE. - * - * @return EVAL_PAGE - * @throws JspException if an error occurred while processing this tag - * @see Tag#doEndTag - */ - - public int doEndTag() throws JspException { - return super.doEndTag(); - } - - - // Actions related to body evaluation - - /** - * Prepare for evaluation of the body: stash the bodyContent away. - * - * @param b the BodyContent - * @see #doAfterBody - * @see #doInitBody() - * @see BodyTag#setBodyContent - */ - - public void setBodyContent(BodyContent b) { - this.bodyContent = b; - } - - - /** - * Prepare for evaluation of the body just before the first body evaluation: - * no action. - * - * @throws JspException if an error occurred while processing this tag - * @see #setBodyContent - * @see #doAfterBody - * @see BodyTag#doInitBody - */ - - public void doInitBody() throws JspException { - } - - - /** - * After the body evaluation: do not reevaluate and continue with the page. - * By default nothing is done with the bodyContent data (if any). - * - * @return SKIP_BODY - * @throws JspException if an error occurred while processing this tag - * @see #doInitBody - * @see BodyTag#doAfterBody - */ - - public int doAfterBody() throws JspException { - return SKIP_BODY; - } - - - /** - * Release state. - * - * @see Tag#release - */ - - public void release() { - bodyContent = null; - - super.release(); - } - - /** - * Get current bodyContent. - * - * @return the body content. - */ - - public BodyContent getBodyContent() { - return bodyContent; - } - - - /** - * Get surrounding out JspWriter. - * - * @return the enclosing JspWriter, from the bodyContent. - */ - - public JspWriter getPreviousOut() { - return bodyContent.getEnclosingWriter(); - } - - // protected fields - - /** - * The current BodyContent for this BodyTag. - */ - protected BodyContent bodyContent; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspWriter; + +/** + * A base class for defining tag handlers implementing BodyTag. + * + *

+ * The BodyTagSupport class implements the BodyTag interface and adds + * additional convenience methods including getter methods for the + * bodyContent property and methods to get at the previous out JspWriter. + * + *

+ * Many tag handlers will extend BodyTagSupport and only redefine a + * few methods. + */ + +public class BodyTagSupport extends TagSupport implements BodyTag { + + /** + * Default constructor, all subclasses are required to only define + * a public constructor with the same signature, and to call the + * superclass constructor. + * + * This constructor is called by the code generated by the JSP + * translator. + */ + + public BodyTagSupport() { + super(); + } + + /** + * Default processing of the start tag returning EVAL_BODY_BUFFERED. + * + * @return EVAL_BODY_BUFFERED + * @throws JspException if an error occurred while processing this tag + * @see BodyTag#doStartTag + */ + + public int doStartTag() throws JspException { + return EVAL_BODY_BUFFERED; + } + + + /** + * Default processing of the end tag returning EVAL_PAGE. + * + * @return EVAL_PAGE + * @throws JspException if an error occurred while processing this tag + * @see Tag#doEndTag + */ + + public int doEndTag() throws JspException { + return super.doEndTag(); + } + + + // Actions related to body evaluation + + /** + * Prepare for evaluation of the body: stash the bodyContent away. + * + * @param b the BodyContent + * @see #doAfterBody + * @see #doInitBody() + * @see BodyTag#setBodyContent + */ + + public void setBodyContent(BodyContent b) { + this.bodyContent = b; + } + + + /** + * Prepare for evaluation of the body just before the first body evaluation: + * no action. + * + * @throws JspException if an error occurred while processing this tag + * @see #setBodyContent + * @see #doAfterBody + * @see BodyTag#doInitBody + */ + + public void doInitBody() throws JspException { + } + + + /** + * After the body evaluation: do not reevaluate and continue with the page. + * By default nothing is done with the bodyContent data (if any). + * + * @return SKIP_BODY + * @throws JspException if an error occurred while processing this tag + * @see #doInitBody + * @see BodyTag#doAfterBody + */ + + public int doAfterBody() throws JspException { + return SKIP_BODY; + } + + + /** + * Release state. + * + * @see Tag#release + */ + + public void release() { + bodyContent = null; + + super.release(); + } + + /** + * Get current bodyContent. + * + * @return the body content. + */ + + public BodyContent getBodyContent() { + return bodyContent; + } + + + /** + * Get surrounding out JspWriter. + * + * @return the enclosing JspWriter, from the bodyContent. + */ + + public JspWriter getPreviousOut() { + return bodyContent.getEnclosingWriter(); + } + + // protected fields + + /** + * The current BodyContent for this BodyTag. + */ + protected BodyContent bodyContent; +} diff --git a/java/javax/servlet/jsp/tagext/DynamicAttributes.java b/java/javax/servlet/jsp/tagext/DynamicAttributes.java index 740af78fa..6fbbc1199 100644 --- a/java/javax/servlet/jsp/tagext/DynamicAttributes.java +++ b/java/javax/servlet/jsp/tagext/DynamicAttributes.java @@ -1,51 +1,51 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.JspException; - -/** - * For a tag to declare that it accepts dynamic attributes, it must implement - * this interface. The entry for the tag in the Tag Library Descriptor must - * also be configured to indicate dynamic attributes are accepted. - *
- * For any attribute that is not declared in the Tag Library Descriptor for - * this tag, instead of getting an error at translation time, the - * setDynamicAttribute() method is called, with the name and - * value of the attribute. It is the responsibility of the tag to - * remember the names and values of the dynamic attributes. - * - * @since 2.0 - */ -public interface DynamicAttributes { - - /** - * Called when a tag declared to accept dynamic attributes is passed - * an attribute that is not declared in the Tag Library Descriptor. - * - * @param uri the namespace of the attribute, or null if in the default - * namespace. - * @param localName the name of the attribute being set. - * @param value the value of the attribute - * @throws JspException if the tag handler wishes to - * signal that it does not accept the given attribute. The - * container must not call doStartTag() or doTag() for this tag. - */ - public void setDynamicAttribute( - String uri, String localName, Object value ) - throws JspException; - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.JspException; + +/** + * For a tag to declare that it accepts dynamic attributes, it must implement + * this interface. The entry for the tag in the Tag Library Descriptor must + * also be configured to indicate dynamic attributes are accepted. + *
+ * For any attribute that is not declared in the Tag Library Descriptor for + * this tag, instead of getting an error at translation time, the + * setDynamicAttribute() method is called, with the name and + * value of the attribute. It is the responsibility of the tag to + * remember the names and values of the dynamic attributes. + * + * @since 2.0 + */ +public interface DynamicAttributes { + + /** + * Called when a tag declared to accept dynamic attributes is passed + * an attribute that is not declared in the Tag Library Descriptor. + * + * @param uri the namespace of the attribute, or null if in the default + * namespace. + * @param localName the name of the attribute being set. + * @param value the value of the attribute + * @throws JspException if the tag handler wishes to + * signal that it does not accept the given attribute. The + * container must not call doStartTag() or doTag() for this tag. + */ + public void setDynamicAttribute( + String uri, String localName, Object value ) + throws JspException; + +} diff --git a/java/javax/servlet/jsp/tagext/FunctionInfo.java b/java/javax/servlet/jsp/tagext/FunctionInfo.java index aff078a33..1c984a3bd 100644 --- a/java/javax/servlet/jsp/tagext/FunctionInfo.java +++ b/java/javax/servlet/jsp/tagext/FunctionInfo.java @@ -1,80 +1,80 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -/** - * Information for a function in a Tag Library. - * This class is instantiated from the Tag Library Descriptor file (TLD) - * and is available only at translation time. - * - * @since 2.0 - */ -public class FunctionInfo { - - /** - * Constructor for FunctionInfo. - * - * @param name The name of the function - * @param klass The class of the function - * @param signature The signature of the function - */ - - public FunctionInfo(String name, String klass, String signature) { - - this.name = name; - this.functionClass = klass; - this.functionSignature = signature; - } - - /** - * The name of the function. - * - * @return The name of the function - */ - - public String getName() { - return name; - } - - /** - * The class of the function. - * - * @return The class of the function - */ - - public String getFunctionClass() { - return functionClass; - } - - /** - * The signature of the function. - * - * @return The signature of the function - */ - - public String getFunctionSignature() { - return functionSignature; - } - - /* - * fields - */ - - private String name; - private String functionClass; - private String functionSignature; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +/** + * Information for a function in a Tag Library. + * This class is instantiated from the Tag Library Descriptor file (TLD) + * and is available only at translation time. + * + * @since 2.0 + */ +public class FunctionInfo { + + /** + * Constructor for FunctionInfo. + * + * @param name The name of the function + * @param klass The class of the function + * @param signature The signature of the function + */ + + public FunctionInfo(String name, String klass, String signature) { + + this.name = name; + this.functionClass = klass; + this.functionSignature = signature; + } + + /** + * The name of the function. + * + * @return The name of the function + */ + + public String getName() { + return name; + } + + /** + * The class of the function. + * + * @return The class of the function + */ + + public String getFunctionClass() { + return functionClass; + } + + /** + * The signature of the function. + * + * @return The signature of the function + */ + + public String getFunctionSignature() { + return functionSignature; + } + + /* + * fields + */ + + private String name; + private String functionClass; + private String functionSignature; +} diff --git a/java/javax/servlet/jsp/tagext/IterationTag.java b/java/javax/servlet/jsp/tagext/IterationTag.java index cd640ba0c..da643bc79 100644 --- a/java/javax/servlet/jsp/tagext/IterationTag.java +++ b/java/javax/servlet/jsp/tagext/IterationTag.java @@ -1,119 +1,119 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.*; - -/** - * The IterationTag interface extends Tag by defining one additional - * method that controls the reevaluation of its body. - * - *

A tag handler that implements IterationTag is treated as one that - * implements Tag regarding the doStartTag() and doEndTag() methods. - * IterationTag provides a new method: doAfterBody(). - * - *

The doAfterBody() method is invoked after every body evaluation - * to control whether the body will be reevaluated or not. If doAfterBody() - * returns IterationTag.EVAL_BODY_AGAIN, then the body will be reevaluated. - * If doAfterBody() returns Tag.SKIP_BODY, then the body will be skipped - * and doEndTag() will be evaluated instead. - * - *

Properties - * There are no new properties in addition to those in Tag. - * - *

Methods - * There is one new methods: doAfterBody(). - * - *

Lifecycle - * - *

Lifecycle details are described by the transition diagram - * below. Exceptions that are thrown during the computation of - * doStartTag(), BODY and doAfterBody() interrupt the execution - * sequence and are propagated up the stack, unless the tag handler - * implements the TryCatchFinally interface; see that interface for - * details. - * - *

- * Lifecycle Details Transition Diagram for IterationTag - * - *

Empty and Non-Empty Action - *

If the TagLibraryDescriptor file indicates that the action must - * always have an empty element body, by a <body-content> entry of - * "empty", then the doStartTag() method must return SKIP_BODY. - * - *

Note that which methods are invoked after the doStartTag() depends on - * both the return value and on if the custom action element is empty - * or not in the JSP page, not on how it's declared in the TLD. - * - *

- * If SKIP_BODY is returned the body is not evaluated, and then doEndTag() - * is invoked. - * - *

- * If EVAL_BODY_INCLUDE is returned, and the custom action element is not - * empty, the body is evaluated and "passed through" to the current out, - * then doAfterBody() is invoked and, after zero or more iterations, - * doEndTag() is invoked. - */ - -public interface IterationTag extends Tag { - - /** - * Request the reevaluation of some body. - * Returned from doAfterBody. - * - * For compatibility with JSP 1.1, the value is carefully selected - * to be the same as the, now deprecated, BodyTag.EVAL_BODY_TAG, - * - */ - - public final static int EVAL_BODY_AGAIN = 2; - - /** - * Process body (re)evaluation. This method is invoked by the - * JSP Page implementation object after every evaluation of - * the body into the BodyEvaluation object. The method is - * not invoked if there is no body evaluation. - * - *

- * If doAfterBody returns EVAL_BODY_AGAIN, a new evaluation of the - * body will happen (followed by another invocation of doAfterBody). - * If doAfterBody returns SKIP_BODY, no more body evaluations will occur, - * and the doEndTag method will be invoked. - * - *

- * If this tag handler implements BodyTag and doAfterBody returns - * SKIP_BODY, the value of out will be restored using the popBody - * method in pageContext prior to invoking doEndTag. - * - *

- * The method re-invocations may be lead to different actions because - * there might have been some changes to shared state, or because - * of external computation. - * - *

- * The JSP container will resynchronize the values of any AT_BEGIN and - * NESTED variables (defined by the associated TagExtraInfo or TLD) after - * the invocation of doAfterBody(). - * - * @return whether additional evaluations of the body are desired - * @throws JspException if an error occurred while processing this tag - */ - - int doAfterBody() throws JspException; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.*; + +/** + * The IterationTag interface extends Tag by defining one additional + * method that controls the reevaluation of its body. + * + *

A tag handler that implements IterationTag is treated as one that + * implements Tag regarding the doStartTag() and doEndTag() methods. + * IterationTag provides a new method: doAfterBody(). + * + *

The doAfterBody() method is invoked after every body evaluation + * to control whether the body will be reevaluated or not. If doAfterBody() + * returns IterationTag.EVAL_BODY_AGAIN, then the body will be reevaluated. + * If doAfterBody() returns Tag.SKIP_BODY, then the body will be skipped + * and doEndTag() will be evaluated instead. + * + *

Properties + * There are no new properties in addition to those in Tag. + * + *

Methods + * There is one new methods: doAfterBody(). + * + *

Lifecycle + * + *

Lifecycle details are described by the transition diagram + * below. Exceptions that are thrown during the computation of + * doStartTag(), BODY and doAfterBody() interrupt the execution + * sequence and are propagated up the stack, unless the tag handler + * implements the TryCatchFinally interface; see that interface for + * details. + * + *

+ * Lifecycle Details Transition Diagram for IterationTag + * + *

Empty and Non-Empty Action + *

If the TagLibraryDescriptor file indicates that the action must + * always have an empty element body, by a <body-content> entry of + * "empty", then the doStartTag() method must return SKIP_BODY. + * + *

Note that which methods are invoked after the doStartTag() depends on + * both the return value and on if the custom action element is empty + * or not in the JSP page, not on how it's declared in the TLD. + * + *

+ * If SKIP_BODY is returned the body is not evaluated, and then doEndTag() + * is invoked. + * + *

+ * If EVAL_BODY_INCLUDE is returned, and the custom action element is not + * empty, the body is evaluated and "passed through" to the current out, + * then doAfterBody() is invoked and, after zero or more iterations, + * doEndTag() is invoked. + */ + +public interface IterationTag extends Tag { + + /** + * Request the reevaluation of some body. + * Returned from doAfterBody. + * + * For compatibility with JSP 1.1, the value is carefully selected + * to be the same as the, now deprecated, BodyTag.EVAL_BODY_TAG, + * + */ + + public final static int EVAL_BODY_AGAIN = 2; + + /** + * Process body (re)evaluation. This method is invoked by the + * JSP Page implementation object after every evaluation of + * the body into the BodyEvaluation object. The method is + * not invoked if there is no body evaluation. + * + *

+ * If doAfterBody returns EVAL_BODY_AGAIN, a new evaluation of the + * body will happen (followed by another invocation of doAfterBody). + * If doAfterBody returns SKIP_BODY, no more body evaluations will occur, + * and the doEndTag method will be invoked. + * + *

+ * If this tag handler implements BodyTag and doAfterBody returns + * SKIP_BODY, the value of out will be restored using the popBody + * method in pageContext prior to invoking doEndTag. + * + *

+ * The method re-invocations may be lead to different actions because + * there might have been some changes to shared state, or because + * of external computation. + * + *

+ * The JSP container will resynchronize the values of any AT_BEGIN and + * NESTED variables (defined by the associated TagExtraInfo or TLD) after + * the invocation of doAfterBody(). + * + * @return whether additional evaluations of the body are desired + * @throws JspException if an error occurred while processing this tag + */ + + int doAfterBody() throws JspException; +} diff --git a/java/javax/servlet/jsp/tagext/JspFragment.java b/java/javax/servlet/jsp/tagext/JspFragment.java index ceb5731ec..00f52bc24 100644 --- a/java/javax/servlet/jsp/tagext/JspFragment.java +++ b/java/javax/servlet/jsp/tagext/JspFragment.java @@ -1,82 +1,82 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import java.io.IOException; -import java.io.Writer; -import javax.servlet.jsp.*; - -/** - * Encapsulates a portion of JSP code in an object that - * can be invoked as many times as needed. JSP Fragments are defined - * using JSP syntax as the body of a tag for an invocation to a SimpleTag - * handler, or as the body of a <jsp:attribute> standard action - * specifying the value of an attribute that is declared as a fragment, - * or to be of type JspFragment in the TLD. - *

- * The definition of the JSP fragment must only contain template - * text and JSP action elements. In other words, it must not contain - * scriptlets or scriptlet expressions. At translation time, the - * container generates an implementation of the JspFragment abstract class - * capable of executing the defined fragment. - *

- * A tag handler can invoke the fragment zero or more times, or - * pass it along to other tags, before returning. To communicate values - * to/from a JSP fragment, tag handlers store/retrieve values in - * the JspContext associated with the fragment. - *

- * Note that tag library developers and page authors should not generate - * JspFragment implementations manually. - *

- * Implementation Note: It is not necessary to generate a - * separate class for each fragment. One possible implementation is - * to generate a single helper class for each page that implements - * JspFragment. Upon construction, a discriminator can be passed to - * select which fragment that instance will execute. - * - * @since 2.0 - */ -public abstract class JspFragment { - - /** - * Executes the fragment and directs all output to the given Writer, - * or the JspWriter returned by the getOut() method of the JspContext - * associated with the fragment if out is null. - * - * @param out The Writer to output the fragment to, or null if - * output should be sent to JspContext.getOut(). - * @throws javax.servlet.jsp.JspException Thrown if an error occured - * while invoking this fragment. - * @throws javax.servlet.jsp.SkipPageException Thrown if the page - * that (either directly or indirectly) invoked the tag handler that - * invoked this fragment is to cease evaluation. The container - * must throw this exception if a Classic Tag Handler returned - * Tag.SKIP_PAGE or if a Simple Tag Handler threw SkipPageException. - * @throws java.io.IOException If there was an error writing to the - * stream. - */ - public abstract void invoke( Writer out ) - throws JspException, IOException; - - /** - * Returns the JspContext that is bound to this JspFragment. - * - * @return The JspContext used by this fragment at invocation time. - */ - public abstract JspContext getJspContext(); - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import java.io.IOException; +import java.io.Writer; +import javax.servlet.jsp.*; + +/** + * Encapsulates a portion of JSP code in an object that + * can be invoked as many times as needed. JSP Fragments are defined + * using JSP syntax as the body of a tag for an invocation to a SimpleTag + * handler, or as the body of a <jsp:attribute> standard action + * specifying the value of an attribute that is declared as a fragment, + * or to be of type JspFragment in the TLD. + *

+ * The definition of the JSP fragment must only contain template + * text and JSP action elements. In other words, it must not contain + * scriptlets or scriptlet expressions. At translation time, the + * container generates an implementation of the JspFragment abstract class + * capable of executing the defined fragment. + *

+ * A tag handler can invoke the fragment zero or more times, or + * pass it along to other tags, before returning. To communicate values + * to/from a JSP fragment, tag handlers store/retrieve values in + * the JspContext associated with the fragment. + *

+ * Note that tag library developers and page authors should not generate + * JspFragment implementations manually. + *

+ * Implementation Note: It is not necessary to generate a + * separate class for each fragment. One possible implementation is + * to generate a single helper class for each page that implements + * JspFragment. Upon construction, a discriminator can be passed to + * select which fragment that instance will execute. + * + * @since 2.0 + */ +public abstract class JspFragment { + + /** + * Executes the fragment and directs all output to the given Writer, + * or the JspWriter returned by the getOut() method of the JspContext + * associated with the fragment if out is null. + * + * @param out The Writer to output the fragment to, or null if + * output should be sent to JspContext.getOut(). + * @throws javax.servlet.jsp.JspException Thrown if an error occured + * while invoking this fragment. + * @throws javax.servlet.jsp.SkipPageException Thrown if the page + * that (either directly or indirectly) invoked the tag handler that + * invoked this fragment is to cease evaluation. The container + * must throw this exception if a Classic Tag Handler returned + * Tag.SKIP_PAGE or if a Simple Tag Handler threw SkipPageException. + * @throws java.io.IOException If there was an error writing to the + * stream. + */ + public abstract void invoke( Writer out ) + throws JspException, IOException; + + /** + * Returns the JspContext that is bound to this JspFragment. + * + * @return The JspContext used by this fragment at invocation time. + */ + public abstract JspContext getJspContext(); + +} diff --git a/java/javax/servlet/jsp/tagext/JspIdConsumer.java b/java/javax/servlet/jsp/tagext/JspIdConsumer.java index 221439a46..d0bfcd090 100644 --- a/java/javax/servlet/jsp/tagext/JspIdConsumer.java +++ b/java/javax/servlet/jsp/tagext/JspIdConsumer.java @@ -1,5 +1,5 @@ -package javax.servlet.jsp.tagext; - -public interface JspIdConsumer { - public void setJspId(String jspId); -} +package javax.servlet.jsp.tagext; + +public interface JspIdConsumer { + public void setJspId(String jspId); +} diff --git a/java/javax/servlet/jsp/tagext/JspTag.java b/java/javax/servlet/jsp/tagext/JspTag.java index adfd9b1bc..3e1d48245 100644 --- a/java/javax/servlet/jsp/tagext/JspTag.java +++ b/java/javax/servlet/jsp/tagext/JspTag.java @@ -1,25 +1,25 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -/** - * Serves as a base class for Tag and SimpleTag. - * This is mostly for organizational and type-safety purposes. - * - * @since 2.0 - */ -public interface JspTag { -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +/** + * Serves as a base class for Tag and SimpleTag. + * This is mostly for organizational and type-safety purposes. + * + * @since 2.0 + */ +public interface JspTag { +} diff --git a/java/javax/servlet/jsp/tagext/PageData.java b/java/javax/servlet/jsp/tagext/PageData.java index c57487b0f..50e62d6fe 100644 --- a/java/javax/servlet/jsp/tagext/PageData.java +++ b/java/javax/servlet/jsp/tagext/PageData.java @@ -1,48 +1,48 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -import java.io.InputStream; - -/** - * Translation-time information on a JSP page. The information - * corresponds to the XML view of the JSP page. - * - *

- * Objects of this type are generated by the JSP translator, e.g. - * when being pased to a TagLibraryValidator instance. - */ - -abstract public class PageData { - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public PageData() { - } - - /** - * Returns an input stream on the XML view of a JSP page. - * The stream is encoded in UTF-8. Recall tht the XML view of a - * JSP page has the include directives expanded. - * - * @return An input stream on the document. - */ - abstract public InputStream getInputStream(); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +import java.io.InputStream; + +/** + * Translation-time information on a JSP page. The information + * corresponds to the XML view of the JSP page. + * + *

+ * Objects of this type are generated by the JSP translator, e.g. + * when being pased to a TagLibraryValidator instance. + */ + +abstract public class PageData { + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public PageData() { + } + + /** + * Returns an input stream on the XML view of a JSP page. + * The stream is encoded in UTF-8. Recall tht the XML view of a + * JSP page has the include directives expanded. + * + * @return An input stream on the document. + */ + abstract public InputStream getInputStream(); +} diff --git a/java/javax/servlet/jsp/tagext/SimpleTag.java b/java/javax/servlet/jsp/tagext/SimpleTag.java index d608ba201..a9a414f7a 100644 --- a/java/javax/servlet/jsp/tagext/SimpleTag.java +++ b/java/javax/servlet/jsp/tagext/SimpleTag.java @@ -1,139 +1,139 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.JspContext; - -/** - * Interface for defining Simple Tag Handlers. - * - *

Simple Tag Handlers differ from Classic Tag Handlers in that instead - * of supporting doStartTag() and doEndTag(), - * the SimpleTag interface provides a simple - * doTag() method, which is called once and only once for any - * given tag invocation. All tag logic, iteration, body evaluations, etc. - * are to be performed in this single method. Thus, simple tag handlers - * have the equivalent power of BodyTag, but with a much - * simpler lifecycle and interface.

- * - *

To support body content, the setJspBody() - * method is provided. The container invokes the setJspBody() - * method with a JspFragment object encapsulating the body of - * the tag. The tag handler implementation can call - * invoke() on that fragment to evaluate the body as - * many times as it needs.

- * - *

A SimpleTag handler must have a public no-args constructor. Most - * SimpleTag handlers should extend SimpleTagSupport.

- * - *

Lifecycle

- * - *

The following is a non-normative, brief overview of the - * SimpleTag lifecycle. Refer to the JSP Specification for details.

- * - *
    - *
  1. A new tag handler instance is created each time by the container - * by calling the provided zero-args constructor. Unlike classic - * tag handlers, simple tag handlers are never cached and reused by - * the JSP container.
  2. - *
  3. The setJspContext() and setParent() - * methods are called by the container. The setParent() - * method is only called if the element is nested within another tag - * invocation.
  4. - *
  5. The setters for each attribute defined for this tag are called - * by the container.
  6. - *
  7. If a body exists, the setJspBody() method is called - * by the container to set the body of this tag, as a - * JspFragment. If the action element is empty in - * the page, this method is not called at all.
  8. - *
  9. The doTag() method is called by the container. All - * tag logic, iteration, body evaluations, etc. occur in this - * method.
  10. - *
  11. The doTag() method returns and all variables are - * synchronized.
  12. - *
- * - * @see SimpleTagSupport - * @since 2.0 - */ -public interface SimpleTag extends JspTag { - - /** - * Called by the container to invoke this tag. - * The implementation of this method is provided by the tag library - * developer, and handles all tag processing, body iteration, etc. - * - *

- * The JSP container will resynchronize any AT_BEGIN and AT_END - * variables (defined by the associated tag file, TagExtraInfo, or TLD) - * after the invocation of doTag(). - * - * @throws javax.servlet.jsp.JspException If an error occurred - * while processing this tag. - * @throws javax.servlet.jsp.SkipPageException If the page that - * (either directly or indirectly) invoked this tag is to - * cease evaluation. A Simple Tag Handler generated from a - * tag file must throw this exception if an invoked Classic - * Tag Handler returned SKIP_PAGE or if an invoked Simple - * Tag Handler threw SkipPageException or if an invoked Jsp Fragment - * threw a SkipPageException. - * @throws java.io.IOException If there was an error writing to the - * output stream. - */ - public void doTag() - throws javax.servlet.jsp.JspException, java.io.IOException; - - /** - * Sets the parent of this tag, for collaboration purposes. - *

- * The container invokes this method only if this tag invocation is - * nested within another tag invocation. - * - * @param parent the tag that encloses this tag - */ - public void setParent( JspTag parent ); - - /** - * Returns the parent of this tag, for collaboration purposes. - * - * @return the parent of this tag - */ - public JspTag getParent(); - - /** - * Called by the container to provide this tag handler with - * the JspContext for this invocation. - * An implementation should save this value. - * - * @param pc the page context for this invocation - * @see Tag#setPageContext - */ - public void setJspContext( JspContext pc ); - - /** - * Provides the body of this tag as a JspFragment object, able to be - * invoked zero or more times by the tag handler. - *

- * This method is invoked by the JSP page implementation - * object prior to doTag(). If the action element is - * empty in the page, this method is not called at all. - * - * @param jspBody The fragment encapsulating the body of this tag. - */ - public void setJspBody( JspFragment jspBody ); - - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.JspContext; + +/** + * Interface for defining Simple Tag Handlers. + * + *

Simple Tag Handlers differ from Classic Tag Handlers in that instead + * of supporting doStartTag() and doEndTag(), + * the SimpleTag interface provides a simple + * doTag() method, which is called once and only once for any + * given tag invocation. All tag logic, iteration, body evaluations, etc. + * are to be performed in this single method. Thus, simple tag handlers + * have the equivalent power of BodyTag, but with a much + * simpler lifecycle and interface.

+ * + *

To support body content, the setJspBody() + * method is provided. The container invokes the setJspBody() + * method with a JspFragment object encapsulating the body of + * the tag. The tag handler implementation can call + * invoke() on that fragment to evaluate the body as + * many times as it needs.

+ * + *

A SimpleTag handler must have a public no-args constructor. Most + * SimpleTag handlers should extend SimpleTagSupport.

+ * + *

Lifecycle

+ * + *

The following is a non-normative, brief overview of the + * SimpleTag lifecycle. Refer to the JSP Specification for details.

+ * + *
    + *
  1. A new tag handler instance is created each time by the container + * by calling the provided zero-args constructor. Unlike classic + * tag handlers, simple tag handlers are never cached and reused by + * the JSP container.
  2. + *
  3. The setJspContext() and setParent() + * methods are called by the container. The setParent() + * method is only called if the element is nested within another tag + * invocation.
  4. + *
  5. The setters for each attribute defined for this tag are called + * by the container.
  6. + *
  7. If a body exists, the setJspBody() method is called + * by the container to set the body of this tag, as a + * JspFragment. If the action element is empty in + * the page, this method is not called at all.
  8. + *
  9. The doTag() method is called by the container. All + * tag logic, iteration, body evaluations, etc. occur in this + * method.
  10. + *
  11. The doTag() method returns and all variables are + * synchronized.
  12. + *
+ * + * @see SimpleTagSupport + * @since 2.0 + */ +public interface SimpleTag extends JspTag { + + /** + * Called by the container to invoke this tag. + * The implementation of this method is provided by the tag library + * developer, and handles all tag processing, body iteration, etc. + * + *

+ * The JSP container will resynchronize any AT_BEGIN and AT_END + * variables (defined by the associated tag file, TagExtraInfo, or TLD) + * after the invocation of doTag(). + * + * @throws javax.servlet.jsp.JspException If an error occurred + * while processing this tag. + * @throws javax.servlet.jsp.SkipPageException If the page that + * (either directly or indirectly) invoked this tag is to + * cease evaluation. A Simple Tag Handler generated from a + * tag file must throw this exception if an invoked Classic + * Tag Handler returned SKIP_PAGE or if an invoked Simple + * Tag Handler threw SkipPageException or if an invoked Jsp Fragment + * threw a SkipPageException. + * @throws java.io.IOException If there was an error writing to the + * output stream. + */ + public void doTag() + throws javax.servlet.jsp.JspException, java.io.IOException; + + /** + * Sets the parent of this tag, for collaboration purposes. + *

+ * The container invokes this method only if this tag invocation is + * nested within another tag invocation. + * + * @param parent the tag that encloses this tag + */ + public void setParent( JspTag parent ); + + /** + * Returns the parent of this tag, for collaboration purposes. + * + * @return the parent of this tag + */ + public JspTag getParent(); + + /** + * Called by the container to provide this tag handler with + * the JspContext for this invocation. + * An implementation should save this value. + * + * @param pc the page context for this invocation + * @see Tag#setPageContext + */ + public void setJspContext( JspContext pc ); + + /** + * Provides the body of this tag as a JspFragment object, able to be + * invoked zero or more times by the tag handler. + *

+ * This method is invoked by the JSP page implementation + * object prior to doTag(). If the action element is + * empty in the page, this method is not called at all. + * + * @param jspBody The fragment encapsulating the body of this tag. + */ + public void setJspBody( JspFragment jspBody ); + + +} diff --git a/java/javax/servlet/jsp/tagext/SimpleTagSupport.java b/java/javax/servlet/jsp/tagext/SimpleTagSupport.java index 0264cc57d..1824639ff 100644 --- a/java/javax/servlet/jsp/tagext/SimpleTagSupport.java +++ b/java/javax/servlet/jsp/tagext/SimpleTagSupport.java @@ -1,212 +1,212 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.JspException; -import java.io.IOException; - -/** - * A base class for defining tag handlers implementing SimpleTag. - *

- * The SimpleTagSupport class is a utility class intended to be used - * as the base class for new simple tag handlers. The SimpleTagSupport - * class implements the SimpleTag interface and adds additional - * convenience methods including getter methods for the properties in - * SimpleTag. - * - * @since 2.0 - */ -public class SimpleTagSupport - implements SimpleTag -{ - /** Reference to the enclosing tag. */ - private JspTag parentTag; - - /** The JSP context for the upcoming tag invocation. */ - private JspContext jspContext; - - /** The body of the tag. */ - private JspFragment jspBody; - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public SimpleTagSupport() { - } - - /** - * Default processing of the tag does nothing. - * - * @throws JspException Subclasses can throw JspException to indicate - * an error occurred while processing this tag. - * @throws javax.servlet.jsp.SkipPageException If the page that - * (either directly or indirectly) invoked this tag is to - * cease evaluation. A Simple Tag Handler generated from a - * tag file must throw this exception if an invoked Classic - * Tag Handler returned SKIP_PAGE or if an invoked Simple - * Tag Handler threw SkipPageException or if an invoked Jsp Fragment - * threw a SkipPageException. - * @throws IOException Subclasses can throw IOException if there was - * an error writing to the output stream - * @see SimpleTag#doTag() - */ - public void doTag() - throws JspException, IOException - { - } - - /** - * Sets the parent of this tag, for collaboration purposes. - *

- * The container invokes this method only if this tag invocation is - * nested within another tag invocation. - * - * @param parent the tag that encloses this tag - */ - public void setParent( JspTag parent ) { - this.parentTag = parent; - } - - /** - * Returns the parent of this tag, for collaboration purposes. - * - * @return the parent of this tag - */ - public JspTag getParent() { - return this.parentTag; - } - - /** - * Stores the provided JSP context in the private jspContext field. - * Subclasses can access the JspContext via - * getJspContext(). - * - * @param pc the page context for this invocation - * @see SimpleTag#setJspContext - */ - public void setJspContext( JspContext pc ) { - this.jspContext = pc; - } - - /** - * Returns the page context passed in by the container via - * setJspContext. - * - * @return the page context for this invocation - */ - protected JspContext getJspContext() { - return this.jspContext; - } - - /** - * Stores the provided JspFragment. - * - * @param jspBody The fragment encapsulating the body of this tag. - * If the action element is empty in the page, this method is - * not called at all. - * @see SimpleTag#setJspBody - */ - public void setJspBody( JspFragment jspBody ) { - this.jspBody = jspBody; - } - - /** - * Returns the body passed in by the container via setJspBody. - * - * @return the fragment encapsulating the body of this tag, or - * null if the action element is empty in the page. - */ - protected JspFragment getJspBody() { - return this.jspBody; - } - - /** - * Find the instance of a given class type that is closest to a given - * instance. - * This method uses the getParent method from the Tag and/or SimpleTag - * interfaces. This method is used for coordination among - * cooperating tags. - * - *

For every instance of TagAdapter - * encountered while traversing the ancestors, the tag handler returned by - * TagAdapter.getAdaptee() - instead of the TagAdpater itself - - * is compared to klass. If the tag handler matches, it - and - * not its TagAdapter - is returned. - * - *

- * The current version of the specification only provides one formal - * way of indicating the observable type of a tag handler: its - * tag handler implementation class, described in the tag-class - * subelement of the tag element. This is extended in an - * informal manner by allowing the tag library author to - * indicate in the description subelement an observable type. - * The type should be a subtype of the tag handler implementation - * class or void. - * This addititional constraint can be exploited by a - * specialized container that knows about that specific tag library, - * as in the case of the JSP standard tag library. - * - *

- * When a tag library author provides information on the - * observable type of a tag handler, client programmatic code - * should adhere to that constraint. Specifically, the Class - * passed to findAncestorWithClass should be a subtype of the - * observable type. - * - * - * @param from The instance from where to start looking. - * @param klass The subclass of JspTag or interface to be matched - * @return the nearest ancestor that implements the interface - * or is an instance of the class specified - */ - public static final JspTag findAncestorWithClass( - JspTag from, Class klass) - { - boolean isInterface = false; - - if (from == null || klass == null - || (!JspTag.class.isAssignableFrom(klass) - && !(isInterface = klass.isInterface()))) { - return null; - } - - for (;;) { - JspTag parent = null; - if( from instanceof SimpleTag ) { - parent = ((SimpleTag)from).getParent(); - } - else if( from instanceof Tag ) { - parent = ((Tag)from).getParent(); - } - if (parent == null) { - return null; - } - - if (parent instanceof TagAdapter) { - parent = ((TagAdapter) parent).getAdaptee(); - } - - if ((isInterface && klass.isInstance(parent)) - || klass.isAssignableFrom(parent.getClass())) { - return parent; - } - - from = parent; - } - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.JspException; +import java.io.IOException; + +/** + * A base class for defining tag handlers implementing SimpleTag. + *

+ * The SimpleTagSupport class is a utility class intended to be used + * as the base class for new simple tag handlers. The SimpleTagSupport + * class implements the SimpleTag interface and adds additional + * convenience methods including getter methods for the properties in + * SimpleTag. + * + * @since 2.0 + */ +public class SimpleTagSupport + implements SimpleTag +{ + /** Reference to the enclosing tag. */ + private JspTag parentTag; + + /** The JSP context for the upcoming tag invocation. */ + private JspContext jspContext; + + /** The body of the tag. */ + private JspFragment jspBody; + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public SimpleTagSupport() { + } + + /** + * Default processing of the tag does nothing. + * + * @throws JspException Subclasses can throw JspException to indicate + * an error occurred while processing this tag. + * @throws javax.servlet.jsp.SkipPageException If the page that + * (either directly or indirectly) invoked this tag is to + * cease evaluation. A Simple Tag Handler generated from a + * tag file must throw this exception if an invoked Classic + * Tag Handler returned SKIP_PAGE or if an invoked Simple + * Tag Handler threw SkipPageException or if an invoked Jsp Fragment + * threw a SkipPageException. + * @throws IOException Subclasses can throw IOException if there was + * an error writing to the output stream + * @see SimpleTag#doTag() + */ + public void doTag() + throws JspException, IOException + { + } + + /** + * Sets the parent of this tag, for collaboration purposes. + *

+ * The container invokes this method only if this tag invocation is + * nested within another tag invocation. + * + * @param parent the tag that encloses this tag + */ + public void setParent( JspTag parent ) { + this.parentTag = parent; + } + + /** + * Returns the parent of this tag, for collaboration purposes. + * + * @return the parent of this tag + */ + public JspTag getParent() { + return this.parentTag; + } + + /** + * Stores the provided JSP context in the private jspContext field. + * Subclasses can access the JspContext via + * getJspContext(). + * + * @param pc the page context for this invocation + * @see SimpleTag#setJspContext + */ + public void setJspContext( JspContext pc ) { + this.jspContext = pc; + } + + /** + * Returns the page context passed in by the container via + * setJspContext. + * + * @return the page context for this invocation + */ + protected JspContext getJspContext() { + return this.jspContext; + } + + /** + * Stores the provided JspFragment. + * + * @param jspBody The fragment encapsulating the body of this tag. + * If the action element is empty in the page, this method is + * not called at all. + * @see SimpleTag#setJspBody + */ + public void setJspBody( JspFragment jspBody ) { + this.jspBody = jspBody; + } + + /** + * Returns the body passed in by the container via setJspBody. + * + * @return the fragment encapsulating the body of this tag, or + * null if the action element is empty in the page. + */ + protected JspFragment getJspBody() { + return this.jspBody; + } + + /** + * Find the instance of a given class type that is closest to a given + * instance. + * This method uses the getParent method from the Tag and/or SimpleTag + * interfaces. This method is used for coordination among + * cooperating tags. + * + *

For every instance of TagAdapter + * encountered while traversing the ancestors, the tag handler returned by + * TagAdapter.getAdaptee() - instead of the TagAdpater itself - + * is compared to klass. If the tag handler matches, it - and + * not its TagAdapter - is returned. + * + *

+ * The current version of the specification only provides one formal + * way of indicating the observable type of a tag handler: its + * tag handler implementation class, described in the tag-class + * subelement of the tag element. This is extended in an + * informal manner by allowing the tag library author to + * indicate in the description subelement an observable type. + * The type should be a subtype of the tag handler implementation + * class or void. + * This addititional constraint can be exploited by a + * specialized container that knows about that specific tag library, + * as in the case of the JSP standard tag library. + * + *

+ * When a tag library author provides information on the + * observable type of a tag handler, client programmatic code + * should adhere to that constraint. Specifically, the Class + * passed to findAncestorWithClass should be a subtype of the + * observable type. + * + * + * @param from The instance from where to start looking. + * @param klass The subclass of JspTag or interface to be matched + * @return the nearest ancestor that implements the interface + * or is an instance of the class specified + */ + public static final JspTag findAncestorWithClass( + JspTag from, Class klass) + { + boolean isInterface = false; + + if (from == null || klass == null + || (!JspTag.class.isAssignableFrom(klass) + && !(isInterface = klass.isInterface()))) { + return null; + } + + for (;;) { + JspTag parent = null; + if( from instanceof SimpleTag ) { + parent = ((SimpleTag)from).getParent(); + } + else if( from instanceof Tag ) { + parent = ((Tag)from).getParent(); + } + if (parent == null) { + return null; + } + + if (parent instanceof TagAdapter) { + parent = ((TagAdapter) parent).getAdaptee(); + } + + if ((isInterface && klass.isInstance(parent)) + || klass.isAssignableFrom(parent.getClass())) { + return parent; + } + + from = parent; + } + } +} diff --git a/java/javax/servlet/jsp/tagext/Tag.java b/java/javax/servlet/jsp/tagext/Tag.java index 7abf782e8..28cbcf708 100644 --- a/java/javax/servlet/jsp/tagext/Tag.java +++ b/java/javax/servlet/jsp/tagext/Tag.java @@ -1,262 +1,262 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.*; - - -/** - * The interface of a classic tag handler that does not want to manipulate - * its body. The Tag interface defines the basic protocol between a Tag - * handler and JSP page implementation class. It defines the life cycle - * and the methods to be invoked at start and end tag. - * - *

Properties

- * - *

The Tag interface specifies the setter and getter methods for the core - * pageContext and parent properties.

- * - *

The JSP page implementation object invokes setPageContext and - * setParent, in that order, before invoking doStartTag() or doEndTag().

- * - *

Methods

- * - *

There are two main actions: doStartTag and doEndTag. Once all - * appropriate properties have been initialized, the doStartTag and - * doEndTag methods can be invoked on the tag handler. Between these - * invocations, the tag handler is assumed to hold a state that must - * be preserved. After the doEndTag invocation, the tag handler is - * available for further invocations (and it is expected to have - * retained its properties).

- * - *

Lifecycle

- * - *

Lifecycle details are described by the transition diagram below, - * with the following comments: - *

    - *
  • [1] This transition is intended to be for releasing long-term data. - * no guarantees are assumed on whether any properties have been retained - * or not. - *
  • [2] This transition happens if and only if the tag ends normally - * without raising an exception - *
  • [3] Some setters may be called again before a tag handler is - * reused. For instance, setParent() is called if it's - * reused within the same page but at a different level, - * setPageContext() is called if it's used in another page, - * and attribute setters are called if the values differ or are expressed - * as request-time attribute values. - *
  • Check the TryCatchFinally interface for additional details related - * to exception handling and resource management. - *

- * - * Lifecycle Details Transition Diagram for Tag - * - *

Once all invocations on the tag handler - * are completed, the release method is invoked on it. Once a release - * method is invoked all properties, including parent and - * pageContext, are assumed to have been reset to an unspecified value. - * The page compiler guarantees that release() will be invoked on the Tag - * handler before the handler is released to the GC.

- * - *

Empty and Non-Empty Action

- *

If the TagLibraryDescriptor file indicates that the action must - * always have an empty action, by an <body-content> entry of "empty", - * then the doStartTag() method must return SKIP_BODY.

- * - *

Otherwise, the doStartTag() method may return SKIP_BODY or - * EVAL_BODY_INCLUDE.

- * - *

If SKIP_BODY is returned the body, if present, is not evaluated.

- * - *

If EVAL_BODY_INCLUDE is returned, the body is evaluated and - * "passed through" to the current out.

-*/ - -public interface Tag extends JspTag { - - /** - * Skip body evaluation. - * Valid return value for doStartTag and doAfterBody. - */ - - public final static int SKIP_BODY = 0; - - /** - * Evaluate body into existing out stream. - * Valid return value for doStartTag. - */ - - public final static int EVAL_BODY_INCLUDE = 1; - - /** - * Skip the rest of the page. - * Valid return value for doEndTag. - */ - - public final static int SKIP_PAGE = 5; - - /** - * Continue evaluating the page. - * Valid return value for doEndTag(). - */ - - public final static int EVAL_PAGE = 6; - - // Setters for Tag handler data - - - /** - * Set the current page context. - * This method is invoked by the JSP page implementation object - * prior to doStartTag(). - *

- * This value is *not* reset by doEndTag() and must be explicitly reset - * by a page implementation if it changes between calls to doStartTag(). - * - * @param pc The page context for this tag handler. - */ - - void setPageContext(PageContext pc); - - - /** - * Set the parent (closest enclosing tag handler) of this tag handler. - * Invoked by the JSP page implementation object prior to doStartTag(). - *

- * This value is *not* reset by doEndTag() and must be explicitly reset - * by a page implementation. - * - * @param t The parent tag, or null. - */ - - - void setParent(Tag t); - - - /** - * Get the parent (closest enclosing tag handler) for this tag handler. - * - *

- * The getParent() method can be used to navigate the nested tag - * handler structure at runtime for cooperation among custom actions; - * for example, the findAncestorWithClass() method in TagSupport - * provides a convenient way of doing this. - * - *

- * The current version of the specification only provides one formal - * way of indicating the observable type of a tag handler: its - * tag handler implementation class, described in the tag-class - * subelement of the tag element. This is extended in an - * informal manner by allowing the tag library author to - * indicate in the description subelement an observable type. - * The type should be a subtype of the tag handler implementation - * class or void. - * This addititional constraint can be exploited by a - * specialized container that knows about that specific tag library, - * as in the case of the JSP standard tag library. - * - * @return the current parent, or null if none. - * @see TagSupport#findAncestorWithClass - */ - - Tag getParent(); - - - // Actions for basic start/end processing. - - - /** - * Process the start tag for this instance. - * This method is invoked by the JSP page implementation object. - * - *

- * The doStartTag method assumes that the properties pageContext and - * parent have been set. It also assumes that any properties exposed as - * attributes have been set too. When this method is invoked, the body - * has not yet been evaluated. - * - *

- * This method returns Tag.EVAL_BODY_INCLUDE or - * BodyTag.EVAL_BODY_BUFFERED to indicate - * that the body of the action should be evaluated or SKIP_BODY to - * indicate otherwise. - * - *

- * When a Tag returns EVAL_BODY_INCLUDE the result of evaluating - * the body (if any) is included into the current "out" JspWriter as it - * happens and then doEndTag() is invoked. - * - *

- * BodyTag.EVAL_BODY_BUFFERED is only valid if the tag handler - * implements BodyTag. - * - *

- * The JSP container will resynchronize the values of any AT_BEGIN and - * NESTED variables (defined by the associated TagExtraInfo or TLD) - * after the invocation of doStartTag(), except for a tag handler - * implementing BodyTag whose doStartTag() method returns - * BodyTag.EVAL_BODY_BUFFERED. - * - * @return EVAL_BODY_INCLUDE if the tag wants to process body, SKIP_BODY - * if it does not want to process it. - * @throws JspException if an error occurred while processing this tag - * @see BodyTag - */ - - int doStartTag() throws JspException; - - - /** - * Process the end tag for this instance. - * This method is invoked by the JSP page implementation object - * on all Tag handlers. - * - *

- * This method will be called after returning from doStartTag. The - * body of the action may or may not have been evaluated, depending on - * the return value of doStartTag. - * - *

- * If this method returns EVAL_PAGE, the rest of the page continues - * to be evaluated. If this method returns SKIP_PAGE, the rest of - * the page is not evaluated, the request is completed, and - * the doEndTag() methods of enclosing tags are not invoked. If this - * request was forwarded or included from another page (or Servlet), - * only the current page evaluation is stopped. - * - *

- * The JSP container will resynchronize the values of any AT_BEGIN and - * AT_END variables (defined by the associated TagExtraInfo or TLD) - * after the invocation of doEndTag(). - * - * @return indication of whether to continue evaluating the JSP page. - * @throws JspException if an error occurred while processing this tag - */ - - int doEndTag() throws JspException; - - /** - * Called on a Tag handler to release state. - * The page compiler guarantees that JSP page implementation - * objects will invoke this method on all tag handlers, - * but there may be multiple invocations on doStartTag and doEndTag in between. - */ - - void release(); - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.*; + + +/** + * The interface of a classic tag handler that does not want to manipulate + * its body. The Tag interface defines the basic protocol between a Tag + * handler and JSP page implementation class. It defines the life cycle + * and the methods to be invoked at start and end tag. + * + *

Properties

+ * + *

The Tag interface specifies the setter and getter methods for the core + * pageContext and parent properties.

+ * + *

The JSP page implementation object invokes setPageContext and + * setParent, in that order, before invoking doStartTag() or doEndTag().

+ * + *

Methods

+ * + *

There are two main actions: doStartTag and doEndTag. Once all + * appropriate properties have been initialized, the doStartTag and + * doEndTag methods can be invoked on the tag handler. Between these + * invocations, the tag handler is assumed to hold a state that must + * be preserved. After the doEndTag invocation, the tag handler is + * available for further invocations (and it is expected to have + * retained its properties).

+ * + *

Lifecycle

+ * + *

Lifecycle details are described by the transition diagram below, + * with the following comments: + *

    + *
  • [1] This transition is intended to be for releasing long-term data. + * no guarantees are assumed on whether any properties have been retained + * or not. + *
  • [2] This transition happens if and only if the tag ends normally + * without raising an exception + *
  • [3] Some setters may be called again before a tag handler is + * reused. For instance, setParent() is called if it's + * reused within the same page but at a different level, + * setPageContext() is called if it's used in another page, + * and attribute setters are called if the values differ or are expressed + * as request-time attribute values. + *
  • Check the TryCatchFinally interface for additional details related + * to exception handling and resource management. + *

+ * + * Lifecycle Details Transition Diagram for Tag + * + *

Once all invocations on the tag handler + * are completed, the release method is invoked on it. Once a release + * method is invoked all properties, including parent and + * pageContext, are assumed to have been reset to an unspecified value. + * The page compiler guarantees that release() will be invoked on the Tag + * handler before the handler is released to the GC.

+ * + *

Empty and Non-Empty Action

+ *

If the TagLibraryDescriptor file indicates that the action must + * always have an empty action, by an <body-content> entry of "empty", + * then the doStartTag() method must return SKIP_BODY.

+ * + *

Otherwise, the doStartTag() method may return SKIP_BODY or + * EVAL_BODY_INCLUDE.

+ * + *

If SKIP_BODY is returned the body, if present, is not evaluated.

+ * + *

If EVAL_BODY_INCLUDE is returned, the body is evaluated and + * "passed through" to the current out.

+*/ + +public interface Tag extends JspTag { + + /** + * Skip body evaluation. + * Valid return value for doStartTag and doAfterBody. + */ + + public final static int SKIP_BODY = 0; + + /** + * Evaluate body into existing out stream. + * Valid return value for doStartTag. + */ + + public final static int EVAL_BODY_INCLUDE = 1; + + /** + * Skip the rest of the page. + * Valid return value for doEndTag. + */ + + public final static int SKIP_PAGE = 5; + + /** + * Continue evaluating the page. + * Valid return value for doEndTag(). + */ + + public final static int EVAL_PAGE = 6; + + // Setters for Tag handler data + + + /** + * Set the current page context. + * This method is invoked by the JSP page implementation object + * prior to doStartTag(). + *

+ * This value is *not* reset by doEndTag() and must be explicitly reset + * by a page implementation if it changes between calls to doStartTag(). + * + * @param pc The page context for this tag handler. + */ + + void setPageContext(PageContext pc); + + + /** + * Set the parent (closest enclosing tag handler) of this tag handler. + * Invoked by the JSP page implementation object prior to doStartTag(). + *

+ * This value is *not* reset by doEndTag() and must be explicitly reset + * by a page implementation. + * + * @param t The parent tag, or null. + */ + + + void setParent(Tag t); + + + /** + * Get the parent (closest enclosing tag handler) for this tag handler. + * + *

+ * The getParent() method can be used to navigate the nested tag + * handler structure at runtime for cooperation among custom actions; + * for example, the findAncestorWithClass() method in TagSupport + * provides a convenient way of doing this. + * + *

+ * The current version of the specification only provides one formal + * way of indicating the observable type of a tag handler: its + * tag handler implementation class, described in the tag-class + * subelement of the tag element. This is extended in an + * informal manner by allowing the tag library author to + * indicate in the description subelement an observable type. + * The type should be a subtype of the tag handler implementation + * class or void. + * This addititional constraint can be exploited by a + * specialized container that knows about that specific tag library, + * as in the case of the JSP standard tag library. + * + * @return the current parent, or null if none. + * @see TagSupport#findAncestorWithClass + */ + + Tag getParent(); + + + // Actions for basic start/end processing. + + + /** + * Process the start tag for this instance. + * This method is invoked by the JSP page implementation object. + * + *

+ * The doStartTag method assumes that the properties pageContext and + * parent have been set. It also assumes that any properties exposed as + * attributes have been set too. When this method is invoked, the body + * has not yet been evaluated. + * + *

+ * This method returns Tag.EVAL_BODY_INCLUDE or + * BodyTag.EVAL_BODY_BUFFERED to indicate + * that the body of the action should be evaluated or SKIP_BODY to + * indicate otherwise. + * + *

+ * When a Tag returns EVAL_BODY_INCLUDE the result of evaluating + * the body (if any) is included into the current "out" JspWriter as it + * happens and then doEndTag() is invoked. + * + *

+ * BodyTag.EVAL_BODY_BUFFERED is only valid if the tag handler + * implements BodyTag. + * + *

+ * The JSP container will resynchronize the values of any AT_BEGIN and + * NESTED variables (defined by the associated TagExtraInfo or TLD) + * after the invocation of doStartTag(), except for a tag handler + * implementing BodyTag whose doStartTag() method returns + * BodyTag.EVAL_BODY_BUFFERED. + * + * @return EVAL_BODY_INCLUDE if the tag wants to process body, SKIP_BODY + * if it does not want to process it. + * @throws JspException if an error occurred while processing this tag + * @see BodyTag + */ + + int doStartTag() throws JspException; + + + /** + * Process the end tag for this instance. + * This method is invoked by the JSP page implementation object + * on all Tag handlers. + * + *

+ * This method will be called after returning from doStartTag. The + * body of the action may or may not have been evaluated, depending on + * the return value of doStartTag. + * + *

+ * If this method returns EVAL_PAGE, the rest of the page continues + * to be evaluated. If this method returns SKIP_PAGE, the rest of + * the page is not evaluated, the request is completed, and + * the doEndTag() methods of enclosing tags are not invoked. If this + * request was forwarded or included from another page (or Servlet), + * only the current page evaluation is stopped. + * + *

+ * The JSP container will resynchronize the values of any AT_BEGIN and + * AT_END variables (defined by the associated TagExtraInfo or TLD) + * after the invocation of doEndTag(). + * + * @return indication of whether to continue evaluating the JSP page. + * @throws JspException if an error occurred while processing this tag + */ + + int doEndTag() throws JspException; + + /** + * Called on a Tag handler to release state. + * The page compiler guarantees that JSP page implementation + * objects will invoke this method on all tag handlers, + * but there may be multiple invocations on doStartTag and doEndTag in between. + */ + + void release(); + +} diff --git a/java/javax/servlet/jsp/tagext/TagAdapter.java b/java/javax/servlet/jsp/tagext/TagAdapter.java index 4b375a169..d325f93e4 100644 --- a/java/javax/servlet/jsp/tagext/TagAdapter.java +++ b/java/javax/servlet/jsp/tagext/TagAdapter.java @@ -1,158 +1,158 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.*; - - -/** - * Wraps any SimpleTag and exposes it using a Tag interface. This is used - * to allow collaboration between classic Tag handlers and SimpleTag - * handlers. - *

- * Because SimpleTag does not extend Tag, and because Tag.setParent() - * only accepts a Tag instance, a classic tag handler (one - * that implements Tag) cannot have a SimpleTag as its parent. To remedy - * this, a TagAdapter is created to wrap the SimpleTag parent, and the - * adapter is passed to setParent() instead. A classic Tag Handler can - * call getAdaptee() to retrieve the encapsulated SimpleTag instance. - * - * @since 2.0 - */ -public class TagAdapter - implements Tag -{ - /** The simple tag that's being adapted. */ - private SimpleTag simpleTagAdaptee; - - /** The parent, of this tag, converted (if necessary) to be of type Tag. */ - private Tag parent; - - // Flag indicating whether we have already determined the parent - private boolean parentDetermined; - - /** - * Creates a new TagAdapter that wraps the given SimpleTag and - * returns the parent tag when getParent() is called. - * - * @param adaptee The SimpleTag being adapted as a Tag. - */ - public TagAdapter( SimpleTag adaptee ) { - if( adaptee == null ) { - // Cannot wrap a null adaptee. - throw new IllegalArgumentException(); - } - this.simpleTagAdaptee = adaptee; - } - - /** - * Must not be called. - * - * @param pc ignored. - * @throws UnsupportedOperationException Must not be called - */ - public void setPageContext(PageContext pc) { - throw new UnsupportedOperationException( - "Illegal to invoke setPageContext() on TagAdapter wrapper" ); - } - - - /** - * Must not be called. The parent of this tag is always - * getAdaptee().getParent(). - * - * @param parentTag ignored. - * @throws UnsupportedOperationException Must not be called. - */ - public void setParent( Tag parentTag ) { - throw new UnsupportedOperationException( - "Illegal to invoke setParent() on TagAdapter wrapper" ); - } - - - /** - * Returns the parent of this tag, which is always - * getAdaptee().getParent(). - * - * This will either be the enclosing Tag (if getAdaptee().getParent() - * implements Tag), or an adapter to the enclosing Tag (if - * getAdaptee().getParent() does not implement Tag). - * - * @return The parent of the tag being adapted. - */ - public Tag getParent() { - if (!parentDetermined) { - JspTag adapteeParent = simpleTagAdaptee.getParent(); - if (adapteeParent != null) { - if (adapteeParent instanceof Tag) { - this.parent = (Tag) adapteeParent; - } else { - // Must be SimpleTag - no other types defined. - this.parent = new TagAdapter((SimpleTag) adapteeParent); - } - } - parentDetermined = true; - } - - return this.parent; - } - - /** - * Gets the tag that is being adapted to the Tag interface. - * This should be an instance of SimpleTag in JSP 2.0, but room - * is left for other kinds of tags in future spec versions. - * - * @return the tag that is being adapted - */ - public JspTag getAdaptee() { - return this.simpleTagAdaptee; - } - - /** - * Must not be called. - * - * @return always throws UnsupportedOperationException - * @throws UnsupportedOperationException Must not be called - * @throws JspException never thrown - */ - public int doStartTag() throws JspException { - throw new UnsupportedOperationException( - "Illegal to invoke doStartTag() on TagAdapter wrapper" ); - } - - /** - * Must not be called. - * - * @return always throws UnsupportedOperationException - * @throws UnsupportedOperationException Must not be called - * @throws JspException never thrown - */ - public int doEndTag() throws JspException { - throw new UnsupportedOperationException( - "Illegal to invoke doEndTag() on TagAdapter wrapper" ); - } - - /** - * Must not be called. - * - * @throws UnsupportedOperationException Must not be called - */ - public void release() { - throw new UnsupportedOperationException( - "Illegal to invoke release() on TagAdapter wrapper" ); - } -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.*; + + +/** + * Wraps any SimpleTag and exposes it using a Tag interface. This is used + * to allow collaboration between classic Tag handlers and SimpleTag + * handlers. + *

+ * Because SimpleTag does not extend Tag, and because Tag.setParent() + * only accepts a Tag instance, a classic tag handler (one + * that implements Tag) cannot have a SimpleTag as its parent. To remedy + * this, a TagAdapter is created to wrap the SimpleTag parent, and the + * adapter is passed to setParent() instead. A classic Tag Handler can + * call getAdaptee() to retrieve the encapsulated SimpleTag instance. + * + * @since 2.0 + */ +public class TagAdapter + implements Tag +{ + /** The simple tag that's being adapted. */ + private SimpleTag simpleTagAdaptee; + + /** The parent, of this tag, converted (if necessary) to be of type Tag. */ + private Tag parent; + + // Flag indicating whether we have already determined the parent + private boolean parentDetermined; + + /** + * Creates a new TagAdapter that wraps the given SimpleTag and + * returns the parent tag when getParent() is called. + * + * @param adaptee The SimpleTag being adapted as a Tag. + */ + public TagAdapter( SimpleTag adaptee ) { + if( adaptee == null ) { + // Cannot wrap a null adaptee. + throw new IllegalArgumentException(); + } + this.simpleTagAdaptee = adaptee; + } + + /** + * Must not be called. + * + * @param pc ignored. + * @throws UnsupportedOperationException Must not be called + */ + public void setPageContext(PageContext pc) { + throw new UnsupportedOperationException( + "Illegal to invoke setPageContext() on TagAdapter wrapper" ); + } + + + /** + * Must not be called. The parent of this tag is always + * getAdaptee().getParent(). + * + * @param parentTag ignored. + * @throws UnsupportedOperationException Must not be called. + */ + public void setParent( Tag parentTag ) { + throw new UnsupportedOperationException( + "Illegal to invoke setParent() on TagAdapter wrapper" ); + } + + + /** + * Returns the parent of this tag, which is always + * getAdaptee().getParent(). + * + * This will either be the enclosing Tag (if getAdaptee().getParent() + * implements Tag), or an adapter to the enclosing Tag (if + * getAdaptee().getParent() does not implement Tag). + * + * @return The parent of the tag being adapted. + */ + public Tag getParent() { + if (!parentDetermined) { + JspTag adapteeParent = simpleTagAdaptee.getParent(); + if (adapteeParent != null) { + if (adapteeParent instanceof Tag) { + this.parent = (Tag) adapteeParent; + } else { + // Must be SimpleTag - no other types defined. + this.parent = new TagAdapter((SimpleTag) adapteeParent); + } + } + parentDetermined = true; + } + + return this.parent; + } + + /** + * Gets the tag that is being adapted to the Tag interface. + * This should be an instance of SimpleTag in JSP 2.0, but room + * is left for other kinds of tags in future spec versions. + * + * @return the tag that is being adapted + */ + public JspTag getAdaptee() { + return this.simpleTagAdaptee; + } + + /** + * Must not be called. + * + * @return always throws UnsupportedOperationException + * @throws UnsupportedOperationException Must not be called + * @throws JspException never thrown + */ + public int doStartTag() throws JspException { + throw new UnsupportedOperationException( + "Illegal to invoke doStartTag() on TagAdapter wrapper" ); + } + + /** + * Must not be called. + * + * @return always throws UnsupportedOperationException + * @throws UnsupportedOperationException Must not be called + * @throws JspException never thrown + */ + public int doEndTag() throws JspException { + throw new UnsupportedOperationException( + "Illegal to invoke doEndTag() on TagAdapter wrapper" ); + } + + /** + * Must not be called. + * + * @throws UnsupportedOperationException Must not be called + */ + public void release() { + throw new UnsupportedOperationException( + "Illegal to invoke release() on TagAdapter wrapper" ); + } +} diff --git a/java/javax/servlet/jsp/tagext/TagAttributeInfo.java b/java/javax/servlet/jsp/tagext/TagAttributeInfo.java index 05a76976b..0cabe8b8f 100644 --- a/java/javax/servlet/jsp/tagext/TagAttributeInfo.java +++ b/java/javax/servlet/jsp/tagext/TagAttributeInfo.java @@ -1,234 +1,234 @@ -/* - * Copyright 2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package javax.servlet.jsp.tagext; - -/** - * Information on the attributes of a Tag, available at translation time. This - * class is instantiated from the Tag Library Descriptor file (TLD). - * - *

- * Only the information needed to generate code is included here. Other - * information like SCHEMA for validation belongs elsewhere. - */ - -public class TagAttributeInfo { - /** - * "id" is wired in to be ID. There is no real benefit in having it be - * something else IDREFs are not handled any differently. - */ - - public static final String ID = "id"; - - /** - * Constructor for TagAttributeInfo. This class is to be instantiated only - * from the TagLibrary code under request from some JSP code that is parsing - * a TLD (Tag Library Descriptor). - * - * @param name - * The name of the attribute. - * @param required - * If this attribute is required in tag instances. - * @param type - * The name of the type of the attribute. - * @param reqTime - * Whether this attribute holds a request-time Attribute. - */ - - public TagAttributeInfo(String name, boolean required, String type, - boolean reqTime) { - this.name = name; - this.required = required; - this.type = type; - this.reqTime = reqTime; - } - - /** - * JSP 2.0 Constructor for TagAttributeInfo. This class is to be - * instantiated only from the TagLibrary code under request from some JSP - * code that is parsing a TLD (Tag Library Descriptor). - * - * @param name - * The name of the attribute. - * @param required - * If this attribute is required in tag instances. - * @param type - * The name of the type of the attribute. - * @param reqTime - * Whether this attribute holds a request-time Attribute. - * @param fragment - * Whether this attribute is of type JspFragment - * - * @since 2.0 - */ - - public TagAttributeInfo(String name, boolean required, String type, - boolean reqTime, boolean fragment) { - this(name, required, type, reqTime); - this.fragment = fragment; - } - - /** - * @since JSP 2.1 - */ - public TagAttributeInfo(String name, boolean required, String type, - boolean reqTime, boolean fragment, String description, - boolean deferredValue, boolean deferredMethod, - String expectedTypeName, String methodSignature) { - this(name, required, type, reqTime, fragment); - this.description = description; - this.deferredValue = deferredValue; - this.deferredMethod = deferredMethod; - this.expectedTypeName = expectedTypeName; - this.methodSignature = methodSignature; - } - - /** - * The name of this attribute. - * - * @return the name of the attribute - */ - - public String getName() { - return name; - } - - /** - * The type (as a String) of this attribute. - * - * @return the type of the attribute - */ - - public String getTypeName() { - return type; - } - - /** - * Whether this attribute can hold a request-time value. - * - * @return if the attribute can hold a request-time value. - */ - - public boolean canBeRequestTime() { - return reqTime; - } - - /** - * Whether this attribute is required. - * - * @return if the attribute is required. - */ - public boolean isRequired() { - return required; - } - - /** - * Convenience static method that goes through an array of TagAttributeInfo - * objects and looks for "id". - * - * @param a - * An array of TagAttributeInfo - * @return The TagAttributeInfo reference with name "id" - */ - public static TagAttributeInfo getIdAttribute(TagAttributeInfo a[]) { - for (int i = 0; i < a.length; i++) { - if (a[i].getName().equals(ID)) { - return a[i]; - } - } - return null; // no such attribute - } - - /** - * Whether this attribute is of type JspFragment. - * - * @return if the attribute is of type JspFragment - * - * @since 2.0 - */ - public boolean isFragment() { - return fragment; - } - - /** - * Returns a String representation of this TagAttributeInfo, suitable for - * debugging purposes. - * - * @return a String representation of this TagAttributeInfo - */ - public String toString() { - StringBuffer b = new StringBuffer(64); - b.append("name = " + name + " "); - b.append("type = " + type + " "); - b.append("reqTime = " + reqTime + " "); - b.append("required = " + required + " "); - b.append("fragment = " + fragment + " "); - b.append("deferredValue = " + deferredValue + " "); - b.append("expectedTypeName = " + expectedTypeName + " "); - b.append("deferredMethod = " + deferredMethod + " "); - b.append("methodSignature = " + methodSignature); - return b.toString(); - } - - /* - * private fields - */ - private String name; - - private String type; - - private boolean reqTime; - - private boolean required; - - /* - * private fields for JSP 2.0 - */ - private boolean fragment; - - /* - * private fields for JSP 2.1 - */ - private String description; - - private boolean deferredValue; - - private boolean deferredMethod; - - private String expectedTypeName; - - private String methodSignature; - - public boolean isDeferredMethod() { - return deferredMethod; - } - - public boolean isDeferredValue() { - return deferredValue; - } - - public String getDescription() { - return description; - } - - public String getExpectedTypeName() { - return expectedTypeName; - } - - public String getMethodSignature() { - return methodSignature; - } -} +/* + * Copyright 2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package javax.servlet.jsp.tagext; + +/** + * Information on the attributes of a Tag, available at translation time. This + * class is instantiated from the Tag Library Descriptor file (TLD). + * + *

+ * Only the information needed to generate code is included here. Other + * information like SCHEMA for validation belongs elsewhere. + */ + +public class TagAttributeInfo { + /** + * "id" is wired in to be ID. There is no real benefit in having it be + * something else IDREFs are not handled any differently. + */ + + public static final String ID = "id"; + + /** + * Constructor for TagAttributeInfo. This class is to be instantiated only + * from the TagLibrary code under request from some JSP code that is parsing + * a TLD (Tag Library Descriptor). + * + * @param name + * The name of the attribute. + * @param required + * If this attribute is required in tag instances. + * @param type + * The name of the type of the attribute. + * @param reqTime + * Whether this attribute holds a request-time Attribute. + */ + + public TagAttributeInfo(String name, boolean required, String type, + boolean reqTime) { + this.name = name; + this.required = required; + this.type = type; + this.reqTime = reqTime; + } + + /** + * JSP 2.0 Constructor for TagAttributeInfo. This class is to be + * instantiated only from the TagLibrary code under request from some JSP + * code that is parsing a TLD (Tag Library Descriptor). + * + * @param name + * The name of the attribute. + * @param required + * If this attribute is required in tag instances. + * @param type + * The name of the type of the attribute. + * @param reqTime + * Whether this attribute holds a request-time Attribute. + * @param fragment + * Whether this attribute is of type JspFragment + * + * @since 2.0 + */ + + public TagAttributeInfo(String name, boolean required, String type, + boolean reqTime, boolean fragment) { + this(name, required, type, reqTime); + this.fragment = fragment; + } + + /** + * @since JSP 2.1 + */ + public TagAttributeInfo(String name, boolean required, String type, + boolean reqTime, boolean fragment, String description, + boolean deferredValue, boolean deferredMethod, + String expectedTypeName, String methodSignature) { + this(name, required, type, reqTime, fragment); + this.description = description; + this.deferredValue = deferredValue; + this.deferredMethod = deferredMethod; + this.expectedTypeName = expectedTypeName; + this.methodSignature = methodSignature; + } + + /** + * The name of this attribute. + * + * @return the name of the attribute + */ + + public String getName() { + return name; + } + + /** + * The type (as a String) of this attribute. + * + * @return the type of the attribute + */ + + public String getTypeName() { + return type; + } + + /** + * Whether this attribute can hold a request-time value. + * + * @return if the attribute can hold a request-time value. + */ + + public boolean canBeRequestTime() { + return reqTime; + } + + /** + * Whether this attribute is required. + * + * @return if the attribute is required. + */ + public boolean isRequired() { + return required; + } + + /** + * Convenience static method that goes through an array of TagAttributeInfo + * objects and looks for "id". + * + * @param a + * An array of TagAttributeInfo + * @return The TagAttributeInfo reference with name "id" + */ + public static TagAttributeInfo getIdAttribute(TagAttributeInfo a[]) { + for (int i = 0; i < a.length; i++) { + if (a[i].getName().equals(ID)) { + return a[i]; + } + } + return null; // no such attribute + } + + /** + * Whether this attribute is of type JspFragment. + * + * @return if the attribute is of type JspFragment + * + * @since 2.0 + */ + public boolean isFragment() { + return fragment; + } + + /** + * Returns a String representation of this TagAttributeInfo, suitable for + * debugging purposes. + * + * @return a String representation of this TagAttributeInfo + */ + public String toString() { + StringBuffer b = new StringBuffer(64); + b.append("name = " + name + " "); + b.append("type = " + type + " "); + b.append("reqTime = " + reqTime + " "); + b.append("required = " + required + " "); + b.append("fragment = " + fragment + " "); + b.append("deferredValue = " + deferredValue + " "); + b.append("expectedTypeName = " + expectedTypeName + " "); + b.append("deferredMethod = " + deferredMethod + " "); + b.append("methodSignature = " + methodSignature); + return b.toString(); + } + + /* + * private fields + */ + private String name; + + private String type; + + private boolean reqTime; + + private boolean required; + + /* + * private fields for JSP 2.0 + */ + private boolean fragment; + + /* + * private fields for JSP 2.1 + */ + private String description; + + private boolean deferredValue; + + private boolean deferredMethod; + + private String expectedTypeName; + + private String methodSignature; + + public boolean isDeferredMethod() { + return deferredMethod; + } + + public boolean isDeferredValue() { + return deferredValue; + } + + public String getDescription() { + return description; + } + + public String getExpectedTypeName() { + return expectedTypeName; + } + + public String getMethodSignature() { + return methodSignature; + } +} diff --git a/java/javax/servlet/jsp/tagext/TagData.java b/java/javax/servlet/jsp/tagext/TagData.java index 30b962f58..58003ea44 100644 --- a/java/javax/servlet/jsp/tagext/TagData.java +++ b/java/javax/servlet/jsp/tagext/TagData.java @@ -1,153 +1,153 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import java.util.Hashtable; - -/** - * The (translation-time only) attribute/value information for a tag instance. - * - *

- * TagData is only used as an argument to the isValid, validate, and - * getVariableInfo methods of TagExtraInfo, which are invoked at - * translation time. - */ - -public class TagData implements Cloneable { - - /** - * Distinguished value for an attribute to indicate its value - * is a request-time expression (which is not yet available because - * TagData instances are used at translation-time). - */ - - public static final Object REQUEST_TIME_VALUE = new Object(); - - - /** - * Constructor for TagData. - * - *

- * A typical constructor may be - *

-     * static final Object[][] att = {{"connection", "conn0"}, {"id", "query0"}};
-     * static final TagData td = new TagData(att);
-     * 
- * - * All values must be Strings except for those holding the - * distinguished object REQUEST_TIME_VALUE. - - * @param atts the static attribute and values. May be null. - */ - public TagData(Object[] atts[]) { - if (atts == null) { - attributes = new Hashtable(); - } else { - attributes = new Hashtable(atts.length); - } - - if (atts != null) { - for (int i = 0; i < atts.length; i++) { - attributes.put(atts[i][0], atts[i][1]); - } - } - } - - /** - * Constructor for a TagData. - * - * If you already have the attributes in a hashtable, use this - * constructor. - * - * @param attrs A hashtable to get the values from. - */ - public TagData(Hashtable attrs) { - this.attributes = attrs; - } - - /** - * The value of the tag's id attribute. - * - * @return the value of the tag's id attribute, or null if no such - * attribute was specified. - */ - - public String getId() { - return getAttributeString(TagAttributeInfo.ID); - } - - /** - * The value of the attribute. - * If a static value is specified for an attribute that accepts a - * request-time attribute expression then that static value is returned, - * even if the value is provided in the body of a action. - * The distinguished object REQUEST_TIME_VALUE is only returned if - * the value is specified as a request-time attribute expression - * or via the <jsp:attribute> action with a body that contains - * dynamic content (scriptlets, scripting expressions, EL expressions, - * standard actions, or custom actions). Returns null if the attribute - * is not set. - * - * @param attName the name of the attribute - * @return the attribute's value - */ - - public Object getAttribute(String attName) { - return attributes.get(attName); - } - - /** - * Set the value of an attribute. - * - * @param attName the name of the attribute - * @param value the value. - */ - public void setAttribute(String attName, - Object value) { - attributes.put(attName, value); - } - - /** - * Get the value for a given attribute. - * - * @param attName the name of the attribute - * @return the attribute value string - * @throws ClassCastException if attribute value is not a String - */ - - public String getAttributeString(String attName) { - Object o = attributes.get(attName); - if (o == null) { - return null; - } else { - return (String) o; - } - } - - /** - * Enumerates the attributes. - * - *@return An enumeration of the attributes in a TagData - */ - public java.util.Enumeration getAttributes() { - return attributes.keys(); - }; - - // private data - - private Hashtable attributes; // the tagname/value map -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import java.util.Hashtable; + +/** + * The (translation-time only) attribute/value information for a tag instance. + * + *

+ * TagData is only used as an argument to the isValid, validate, and + * getVariableInfo methods of TagExtraInfo, which are invoked at + * translation time. + */ + +public class TagData implements Cloneable { + + /** + * Distinguished value for an attribute to indicate its value + * is a request-time expression (which is not yet available because + * TagData instances are used at translation-time). + */ + + public static final Object REQUEST_TIME_VALUE = new Object(); + + + /** + * Constructor for TagData. + * + *

+ * A typical constructor may be + *

+     * static final Object[][] att = {{"connection", "conn0"}, {"id", "query0"}};
+     * static final TagData td = new TagData(att);
+     * 
+ * + * All values must be Strings except for those holding the + * distinguished object REQUEST_TIME_VALUE. + + * @param atts the static attribute and values. May be null. + */ + public TagData(Object[] atts[]) { + if (atts == null) { + attributes = new Hashtable(); + } else { + attributes = new Hashtable(atts.length); + } + + if (atts != null) { + for (int i = 0; i < atts.length; i++) { + attributes.put(atts[i][0], atts[i][1]); + } + } + } + + /** + * Constructor for a TagData. + * + * If you already have the attributes in a hashtable, use this + * constructor. + * + * @param attrs A hashtable to get the values from. + */ + public TagData(Hashtable attrs) { + this.attributes = attrs; + } + + /** + * The value of the tag's id attribute. + * + * @return the value of the tag's id attribute, or null if no such + * attribute was specified. + */ + + public String getId() { + return getAttributeString(TagAttributeInfo.ID); + } + + /** + * The value of the attribute. + * If a static value is specified for an attribute that accepts a + * request-time attribute expression then that static value is returned, + * even if the value is provided in the body of a action. + * The distinguished object REQUEST_TIME_VALUE is only returned if + * the value is specified as a request-time attribute expression + * or via the <jsp:attribute> action with a body that contains + * dynamic content (scriptlets, scripting expressions, EL expressions, + * standard actions, or custom actions). Returns null if the attribute + * is not set. + * + * @param attName the name of the attribute + * @return the attribute's value + */ + + public Object getAttribute(String attName) { + return attributes.get(attName); + } + + /** + * Set the value of an attribute. + * + * @param attName the name of the attribute + * @param value the value. + */ + public void setAttribute(String attName, + Object value) { + attributes.put(attName, value); + } + + /** + * Get the value for a given attribute. + * + * @param attName the name of the attribute + * @return the attribute value string + * @throws ClassCastException if attribute value is not a String + */ + + public String getAttributeString(String attName) { + Object o = attributes.get(attName); + if (o == null) { + return null; + } else { + return (String) o; + } + } + + /** + * Enumerates the attributes. + * + *@return An enumeration of the attributes in a TagData + */ + public java.util.Enumeration getAttributes() { + return attributes.keys(); + }; + + // private data + + private Hashtable attributes; // the tagname/value map +} diff --git a/java/javax/servlet/jsp/tagext/TagExtraInfo.java b/java/javax/servlet/jsp/tagext/TagExtraInfo.java index ebc56f33a..78858f175 100644 --- a/java/javax/servlet/jsp/tagext/TagExtraInfo.java +++ b/java/javax/servlet/jsp/tagext/TagExtraInfo.java @@ -1,143 +1,143 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -/** - * Optional class provided by the tag library author to describe additional - * translation-time information not described in the TLD. - * The TagExtraInfo class is mentioned in the Tag Library Descriptor file (TLD). - * - *

- * This class can be used: - *

    - *
  • to indicate that the tag defines scripting variables - *
  • to perform translation-time validation of the tag attributes. - *
- * - *

- * It is the responsibility of the JSP translator that the initial value - * to be returned by calls to getTagInfo() corresponds to a TagInfo - * object for the tag being translated. If an explicit call to - * setTagInfo() is done, then the object passed will be returned in - * subsequent calls to getTagInfo(). - * - *

- * The only way to affect the value returned by getTagInfo() - * is through a setTagInfo() call, and thus, TagExtraInfo.setTagInfo() is - * to be called by the JSP translator, with a TagInfo object that - * corresponds to the tag being translated. The call should happen before - * any invocation on validate() and before any invocation on - * getVariableInfo(). - * - *

- * NOTE: It is a (translation time) error for a tag definition - * in a TLD with one or more variable subelements to have an associated - * TagExtraInfo implementation that returns a VariableInfo array with - * one or more elements from a call to getVariableInfo(). - */ - -public abstract class TagExtraInfo { - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public TagExtraInfo() { - } - - /** - * information on scripting variables defined by the tag associated with - * this TagExtraInfo instance. - * Request-time attributes are indicated as such in the TagData parameter. - * - * @param data The TagData instance. - * @return An array of VariableInfo data, or null or a zero length array - * if no scripting variables are to be defined. - */ - public VariableInfo[] getVariableInfo(TagData data) { - return ZERO_VARIABLE_INFO; - } - - /** - * Translation-time validation of the attributes. - * Request-time attributes are indicated as such in the TagData parameter. - * Note that the preferred way to do validation is with the validate() - * method, since it can return more detailed information. - * - * @param data The TagData instance. - * @return Whether this tag instance is valid. - * @see TagExtraInfo#validate - */ - - public boolean isValid(TagData data) { - return true; - } - - /** - * Translation-time validation of the attributes. - * Request-time attributes are indicated as such in the TagData parameter. - * Because of the higher quality validation messages possible, - * this is the preferred way to do validation (although isValid() - * still works). - * - *

JSP 2.0 and higher containers call validate() instead of isValid(). - * The default implementation of this method is to call isValid(). If - * isValid() returns false, a generic ValidationMessage[] is returned - * indicating isValid() returned false.

- * - * @param data The TagData instance. - * @return A null object, or zero length array if no errors, an - * array of ValidationMessages otherwise. - * @since 2.0 - */ - public ValidationMessage[] validate( TagData data ) { - ValidationMessage[] result = null; - - if( !isValid( data ) ) { - result = new ValidationMessage[] { - new ValidationMessage( data.getId(), "isValid() == false" ) }; - } - - return result; - } - - /** - * Set the TagInfo for this class. - * - * @param tagInfo The TagInfo this instance is extending - */ - public final void setTagInfo(TagInfo tagInfo) { - this.tagInfo = tagInfo; - } - - /** - * Get the TagInfo for this class. - * - * @return the taginfo instance this instance is extending - */ - public final TagInfo getTagInfo() { - return tagInfo; - } - - // private data - private TagInfo tagInfo; - - // zero length VariableInfo array - private static final VariableInfo[] ZERO_VARIABLE_INFO = { }; -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +/** + * Optional class provided by the tag library author to describe additional + * translation-time information not described in the TLD. + * The TagExtraInfo class is mentioned in the Tag Library Descriptor file (TLD). + * + *

+ * This class can be used: + *

    + *
  • to indicate that the tag defines scripting variables + *
  • to perform translation-time validation of the tag attributes. + *
+ * + *

+ * It is the responsibility of the JSP translator that the initial value + * to be returned by calls to getTagInfo() corresponds to a TagInfo + * object for the tag being translated. If an explicit call to + * setTagInfo() is done, then the object passed will be returned in + * subsequent calls to getTagInfo(). + * + *

+ * The only way to affect the value returned by getTagInfo() + * is through a setTagInfo() call, and thus, TagExtraInfo.setTagInfo() is + * to be called by the JSP translator, with a TagInfo object that + * corresponds to the tag being translated. The call should happen before + * any invocation on validate() and before any invocation on + * getVariableInfo(). + * + *

+ * NOTE: It is a (translation time) error for a tag definition + * in a TLD with one or more variable subelements to have an associated + * TagExtraInfo implementation that returns a VariableInfo array with + * one or more elements from a call to getVariableInfo(). + */ + +public abstract class TagExtraInfo { + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public TagExtraInfo() { + } + + /** + * information on scripting variables defined by the tag associated with + * this TagExtraInfo instance. + * Request-time attributes are indicated as such in the TagData parameter. + * + * @param data The TagData instance. + * @return An array of VariableInfo data, or null or a zero length array + * if no scripting variables are to be defined. + */ + public VariableInfo[] getVariableInfo(TagData data) { + return ZERO_VARIABLE_INFO; + } + + /** + * Translation-time validation of the attributes. + * Request-time attributes are indicated as such in the TagData parameter. + * Note that the preferred way to do validation is with the validate() + * method, since it can return more detailed information. + * + * @param data The TagData instance. + * @return Whether this tag instance is valid. + * @see TagExtraInfo#validate + */ + + public boolean isValid(TagData data) { + return true; + } + + /** + * Translation-time validation of the attributes. + * Request-time attributes are indicated as such in the TagData parameter. + * Because of the higher quality validation messages possible, + * this is the preferred way to do validation (although isValid() + * still works). + * + *

JSP 2.0 and higher containers call validate() instead of isValid(). + * The default implementation of this method is to call isValid(). If + * isValid() returns false, a generic ValidationMessage[] is returned + * indicating isValid() returned false.

+ * + * @param data The TagData instance. + * @return A null object, or zero length array if no errors, an + * array of ValidationMessages otherwise. + * @since 2.0 + */ + public ValidationMessage[] validate( TagData data ) { + ValidationMessage[] result = null; + + if( !isValid( data ) ) { + result = new ValidationMessage[] { + new ValidationMessage( data.getId(), "isValid() == false" ) }; + } + + return result; + } + + /** + * Set the TagInfo for this class. + * + * @param tagInfo The TagInfo this instance is extending + */ + public final void setTagInfo(TagInfo tagInfo) { + this.tagInfo = tagInfo; + } + + /** + * Get the TagInfo for this class. + * + * @return the taginfo instance this instance is extending + */ + public final TagInfo getTagInfo() { + return tagInfo; + } + + // private data + private TagInfo tagInfo; + + // zero length VariableInfo array + private static final VariableInfo[] ZERO_VARIABLE_INFO = { }; +} + diff --git a/java/javax/servlet/jsp/tagext/TagFileInfo.java b/java/javax/servlet/jsp/tagext/TagFileInfo.java index b6f22cef0..4a93d0248 100644 --- a/java/javax/servlet/jsp/tagext/TagFileInfo.java +++ b/java/javax/servlet/jsp/tagext/TagFileInfo.java @@ -1,85 +1,85 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -/** - * Tag information for a tag file in a Tag Library; - * This class is instantiated from the Tag Library Descriptor file (TLD) - * and is available only at translation time. - * - * @since 2.0 - */ -public class TagFileInfo { - - /** - * Constructor for TagFileInfo from data in the JSP 2.0 format for TLD. - * This class is to be instantiated only from the TagLibrary code - * under request from some JSP code that is parsing a - * TLD (Tag Library Descriptor). - * - * Note that, since TagLibibraryInfo reflects both TLD information - * and taglib directive information, a TagFileInfo instance is - * dependent on a taglib directive. This is probably a - * design error, which may be fixed in the future. - * - * @param name The unique action name of this tag - * @param path Where to find the .tag file implementing this - * action, relative to the location of the TLD file. - * @param tagInfo The detailed information about this tag, as parsed - * from the directives in the tag file. - */ - public TagFileInfo( String name, String path, TagInfo tagInfo ) { - this.name = name; - this.path = path; - this.tagInfo = tagInfo; - } - - /** - * The unique action name of this tag. - * - * @return The (short) name of the tag. - */ - public String getName() { - return name; - } - - /** - * Where to find the .tag file implementing this action. - * - * @return The path of the tag file, relative to the TLD, or "." if - * the tag file was defined in an implicit tag file. - */ - public String getPath() { - return path; - } - - /** - * Returns information about this tag, parsed from the directives - * in the tag file. - * - * @return a TagInfo object containing information about this tag - */ - public TagInfo getTagInfo() { - return tagInfo; - } - - // private fields for 2.0 info - private String name; - private String path; - private TagInfo tagInfo; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +/** + * Tag information for a tag file in a Tag Library; + * This class is instantiated from the Tag Library Descriptor file (TLD) + * and is available only at translation time. + * + * @since 2.0 + */ +public class TagFileInfo { + + /** + * Constructor for TagFileInfo from data in the JSP 2.0 format for TLD. + * This class is to be instantiated only from the TagLibrary code + * under request from some JSP code that is parsing a + * TLD (Tag Library Descriptor). + * + * Note that, since TagLibibraryInfo reflects both TLD information + * and taglib directive information, a TagFileInfo instance is + * dependent on a taglib directive. This is probably a + * design error, which may be fixed in the future. + * + * @param name The unique action name of this tag + * @param path Where to find the .tag file implementing this + * action, relative to the location of the TLD file. + * @param tagInfo The detailed information about this tag, as parsed + * from the directives in the tag file. + */ + public TagFileInfo( String name, String path, TagInfo tagInfo ) { + this.name = name; + this.path = path; + this.tagInfo = tagInfo; + } + + /** + * The unique action name of this tag. + * + * @return The (short) name of the tag. + */ + public String getName() { + return name; + } + + /** + * Where to find the .tag file implementing this action. + * + * @return The path of the tag file, relative to the TLD, or "." if + * the tag file was defined in an implicit tag file. + */ + public String getPath() { + return path; + } + + /** + * Returns information about this tag, parsed from the directives + * in the tag file. + * + * @return a TagInfo object containing information about this tag + */ + public TagInfo getTagInfo() { + return tagInfo; + } + + // private fields for 2.0 info + private String name; + private String path; + private TagInfo tagInfo; +} diff --git a/java/javax/servlet/jsp/tagext/TagInfo.java b/java/javax/servlet/jsp/tagext/TagInfo.java index 8f53930f2..e4d341f95 100644 --- a/java/javax/servlet/jsp/tagext/TagInfo.java +++ b/java/javax/servlet/jsp/tagext/TagInfo.java @@ -1,446 +1,446 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -/** - * Tag information for a tag in a Tag Library; - * This class is instantiated from the Tag Library Descriptor file (TLD) - * and is available only at translation time. - * - * -*/ - -public class TagInfo { - - /** - * Static constant for getBodyContent() when it is JSP. - */ - - public static final String BODY_CONTENT_JSP = "JSP"; - - /** - * Static constant for getBodyContent() when it is Tag dependent. - */ - - public static final String BODY_CONTENT_TAG_DEPENDENT = "TAGDEPENDENT"; - - - /** - * Static constant for getBodyContent() when it is empty. - */ - - public static final String BODY_CONTENT_EMPTY = "EMPTY"; - - /** - * Static constant for getBodyContent() when it is scriptless. - * - * @since 2.0 - */ - public static final String BODY_CONTENT_SCRIPTLESS = "SCRIPTLESS"; - - /** - * Constructor for TagInfo from data in the JSP 1.1 format for TLD. - * This class is to be instantiated only from the TagLibrary code - * under request from some JSP code that is parsing a - * TLD (Tag Library Descriptor). - * - * Note that, since TagLibibraryInfo reflects both TLD information - * and taglib directive information, a TagInfo instance is - * dependent on a taglib directive. This is probably a - * design error, which may be fixed in the future. - * - * @param tagName The name of this tag - * @param tagClassName The name of the tag handler class - * @param bodycontent Information on the body content of these tags - * @param infoString The (optional) string information for this tag - * @param taglib The instance of the tag library that contains us. - * @param tagExtraInfo The instance providing extra Tag info. May be null - * @param attributeInfo An array of AttributeInfo data from descriptor. - * May be null; - * - */ - public TagInfo(String tagName, - String tagClassName, - String bodycontent, - String infoString, - TagLibraryInfo taglib, - TagExtraInfo tagExtraInfo, - TagAttributeInfo[] attributeInfo) { - this.tagName = tagName; - this.tagClassName = tagClassName; - this.bodyContent = bodycontent; - this.infoString = infoString; - this.tagLibrary = taglib; - this.tagExtraInfo = tagExtraInfo; - this.attributeInfo = attributeInfo; - - if (tagExtraInfo != null) - tagExtraInfo.setTagInfo(this); - } - - /** - * Constructor for TagInfo from data in the JSP 1.2 format for TLD. - * This class is to be instantiated only from the TagLibrary code - * under request from some JSP code that is parsing a - * TLD (Tag Library Descriptor). - * - * Note that, since TagLibibraryInfo reflects both TLD information - * and taglib directive information, a TagInfo instance is - * dependent on a taglib directive. This is probably a - * design error, which may be fixed in the future. - * - * @param tagName The name of this tag - * @param tagClassName The name of the tag handler class - * @param bodycontent Information on the body content of these tags - * @param infoString The (optional) string information for this tag - * @param taglib The instance of the tag library that contains us. - * @param tagExtraInfo The instance providing extra Tag info. May be null - * @param attributeInfo An array of AttributeInfo data from descriptor. - * May be null; - * @param displayName A short name to be displayed by tools - * @param smallIcon Path to a small icon to be displayed by tools - * @param largeIcon Path to a large icon to be displayed by tools - * @param tvi An array of a TagVariableInfo (or null) - */ - public TagInfo(String tagName, - String tagClassName, - String bodycontent, - String infoString, - TagLibraryInfo taglib, - TagExtraInfo tagExtraInfo, - TagAttributeInfo[] attributeInfo, - String displayName, - String smallIcon, - String largeIcon, - TagVariableInfo[] tvi) { - this.tagName = tagName; - this.tagClassName = tagClassName; - this.bodyContent = bodycontent; - this.infoString = infoString; - this.tagLibrary = taglib; - this.tagExtraInfo = tagExtraInfo; - this.attributeInfo = attributeInfo; - this.displayName = displayName; - this.smallIcon = smallIcon; - this.largeIcon = largeIcon; - this.tagVariableInfo = tvi; - - if (tagExtraInfo != null) - tagExtraInfo.setTagInfo(this); - } - - /** - * Constructor for TagInfo from data in the JSP 2.0 format for TLD. - * This class is to be instantiated only from the TagLibrary code - * under request from some JSP code that is parsing a - * TLD (Tag Library Descriptor). - * - * Note that, since TagLibibraryInfo reflects both TLD information - * and taglib directive information, a TagInfo instance is - * dependent on a taglib directive. This is probably a - * design error, which may be fixed in the future. - * - * @param tagName The name of this tag - * @param tagClassName The name of the tag handler class - * @param bodycontent Information on the body content of these tags - * @param infoString The (optional) string information for this tag - * @param taglib The instance of the tag library that contains us. - * @param tagExtraInfo The instance providing extra Tag info. May be null - * @param attributeInfo An array of AttributeInfo data from descriptor. - * May be null; - * @param displayName A short name to be displayed by tools - * @param smallIcon Path to a small icon to be displayed by tools - * @param largeIcon Path to a large icon to be displayed by tools - * @param tvi An array of a TagVariableInfo (or null) - * @param dynamicAttributes True if supports dynamic attributes - * - * @since 2.0 - */ - public TagInfo(String tagName, - String tagClassName, - String bodycontent, - String infoString, - TagLibraryInfo taglib, - TagExtraInfo tagExtraInfo, - TagAttributeInfo[] attributeInfo, - String displayName, - String smallIcon, - String largeIcon, - TagVariableInfo[] tvi, - boolean dynamicAttributes) { - this.tagName = tagName; - this.tagClassName = tagClassName; - this.bodyContent = bodycontent; - this.infoString = infoString; - this.tagLibrary = taglib; - this.tagExtraInfo = tagExtraInfo; - this.attributeInfo = attributeInfo; - this.displayName = displayName; - this.smallIcon = smallIcon; - this.largeIcon = largeIcon; - this.tagVariableInfo = tvi; - this.dynamicAttributes = dynamicAttributes; - - if (tagExtraInfo != null) - tagExtraInfo.setTagInfo(this); - } - - /** - * The name of the Tag. - * - * @return The (short) name of the tag. - */ - - public String getTagName() { - return tagName; - } - - /** - * Attribute information (in the TLD) on this tag. - * The return is an array describing the attributes of this tag, as - * indicated in the TLD. - * - * @return The array of TagAttributeInfo for this tag, or a - * zero-length array if the tag has no attributes. - */ - - public TagAttributeInfo[] getAttributes() { - return attributeInfo; - } - - /** - * Information on the scripting objects created by this tag at runtime. - * This is a convenience method on the associated TagExtraInfo class. - * - * @param data TagData describing this action. - * @return if a TagExtraInfo object is associated with this TagInfo, the - * result of getTagExtraInfo().getVariableInfo( data ), otherwise - * null. - */ - public VariableInfo[] getVariableInfo(TagData data) { - VariableInfo[] result = null; - TagExtraInfo tei = getTagExtraInfo(); - if (tei != null) { - result = tei.getVariableInfo( data ); - } - return result; - } - - /** - * Translation-time validation of the attributes. - * This is a convenience method on the associated TagExtraInfo class. - * - * @param data The translation-time TagData instance. - * @return Whether the data is valid. - */ - public boolean isValid(TagData data) { - TagExtraInfo tei = getTagExtraInfo(); - if (tei == null) { - return true; - } - return tei.isValid(data); - } - - /** - * Translation-time validation of the attributes. - * This is a convenience method on the associated TagExtraInfo class. - * - * @param data The translation-time TagData instance. - * @return A null object, or zero length array if no errors, an - * array of ValidationMessages otherwise. - * @since 2.0 - */ - public ValidationMessage[] validate( TagData data ) { - TagExtraInfo tei = getTagExtraInfo(); - if( tei == null ) { - return null; - } - return tei.validate( data ); - } - - /** - * Set the instance for extra tag information. - * - * @param tei the TagExtraInfo instance - */ - public void setTagExtraInfo(TagExtraInfo tei) { - tagExtraInfo = tei; - } - - - /** - * The instance (if any) for extra tag information. - * - * @return The TagExtraInfo instance, if any. - */ - public TagExtraInfo getTagExtraInfo() { - return tagExtraInfo; - } - - - /** - * Name of the class that provides the handler for this tag. - * - * @return The name of the tag handler class. - */ - - public String getTagClassName() { - return tagClassName; - } - - - /** - * The bodycontent information for this tag. - * If the bodycontent is not defined for this - * tag, the default of JSP will be returned. - * - * @return the body content string. - */ - - public String getBodyContent() { - return bodyContent; - } - - - /** - * The information string for the tag. - * - * @return the info string, or null if - * not defined - */ - - public String getInfoString() { - return infoString; - } - - - /** - * Set the TagLibraryInfo property. - * - * Note that a TagLibraryInfo element is dependent - * not just on the TLD information but also on the - * specific taglib instance used. This means that - * a fair amount of work needs to be done to construct - * and initialize TagLib objects. - * - * If used carefully, this setter can be used to avoid having to - * create new TagInfo elements for each taglib directive. - * - * @param tl the TagLibraryInfo to assign - */ - - public void setTagLibrary(TagLibraryInfo tl) { - tagLibrary = tl; - } - - /** - * The instance of TabLibraryInfo we belong to. - * - * @return the tag library instance we belong to - */ - - public TagLibraryInfo getTagLibrary() { - return tagLibrary; - } - - - // ============== JSP 2.0 TLD Information ======== - - - /** - * Get the displayName. - * - * @return A short name to be displayed by tools, - * or null if not defined - */ - - public String getDisplayName() { - return displayName; - } - - /** - * Get the path to the small icon. - * - * @return Path to a small icon to be displayed by tools, - * or null if not defined - */ - - public String getSmallIcon() { - return smallIcon; - } - - /** - * Get the path to the large icon. - * - * @return Path to a large icon to be displayed by tools, - * or null if not defined - */ - - public String getLargeIcon() { - return largeIcon; - } - - /** - * Get TagVariableInfo objects associated with this TagInfo. - * - * @return Array of TagVariableInfo objects corresponding to - * variables declared by this tag, or a zero length - * array if no variables have been declared - */ - - public TagVariableInfo[] getTagVariableInfos() { - return tagVariableInfo; - } - - - // ============== JSP 2.0 TLD Information ======== - - /** - * Get dynamicAttributes associated with this TagInfo. - * - * @return True if tag handler supports dynamic attributes - * @since 2.0 - */ - public boolean hasDynamicAttributes() { - return dynamicAttributes; - } - - /* - * private fields for 1.1 info - */ - private String tagName; // the name of the tag - private String tagClassName; - private String bodyContent; - private String infoString; - private TagLibraryInfo tagLibrary; - private TagExtraInfo tagExtraInfo; // instance of TagExtraInfo - private TagAttributeInfo[] attributeInfo; - - /* - * private fields for 1.2 info - */ - private String displayName; - private String smallIcon; - private String largeIcon; - private TagVariableInfo[] tagVariableInfo; - - /* - * Additional private fields for 2.0 info - */ - private boolean dynamicAttributes; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +/** + * Tag information for a tag in a Tag Library; + * This class is instantiated from the Tag Library Descriptor file (TLD) + * and is available only at translation time. + * + * +*/ + +public class TagInfo { + + /** + * Static constant for getBodyContent() when it is JSP. + */ + + public static final String BODY_CONTENT_JSP = "JSP"; + + /** + * Static constant for getBodyContent() when it is Tag dependent. + */ + + public static final String BODY_CONTENT_TAG_DEPENDENT = "TAGDEPENDENT"; + + + /** + * Static constant for getBodyContent() when it is empty. + */ + + public static final String BODY_CONTENT_EMPTY = "EMPTY"; + + /** + * Static constant for getBodyContent() when it is scriptless. + * + * @since 2.0 + */ + public static final String BODY_CONTENT_SCRIPTLESS = "SCRIPTLESS"; + + /** + * Constructor for TagInfo from data in the JSP 1.1 format for TLD. + * This class is to be instantiated only from the TagLibrary code + * under request from some JSP code that is parsing a + * TLD (Tag Library Descriptor). + * + * Note that, since TagLibibraryInfo reflects both TLD information + * and taglib directive information, a TagInfo instance is + * dependent on a taglib directive. This is probably a + * design error, which may be fixed in the future. + * + * @param tagName The name of this tag + * @param tagClassName The name of the tag handler class + * @param bodycontent Information on the body content of these tags + * @param infoString The (optional) string information for this tag + * @param taglib The instance of the tag library that contains us. + * @param tagExtraInfo The instance providing extra Tag info. May be null + * @param attributeInfo An array of AttributeInfo data from descriptor. + * May be null; + * + */ + public TagInfo(String tagName, + String tagClassName, + String bodycontent, + String infoString, + TagLibraryInfo taglib, + TagExtraInfo tagExtraInfo, + TagAttributeInfo[] attributeInfo) { + this.tagName = tagName; + this.tagClassName = tagClassName; + this.bodyContent = bodycontent; + this.infoString = infoString; + this.tagLibrary = taglib; + this.tagExtraInfo = tagExtraInfo; + this.attributeInfo = attributeInfo; + + if (tagExtraInfo != null) + tagExtraInfo.setTagInfo(this); + } + + /** + * Constructor for TagInfo from data in the JSP 1.2 format for TLD. + * This class is to be instantiated only from the TagLibrary code + * under request from some JSP code that is parsing a + * TLD (Tag Library Descriptor). + * + * Note that, since TagLibibraryInfo reflects both TLD information + * and taglib directive information, a TagInfo instance is + * dependent on a taglib directive. This is probably a + * design error, which may be fixed in the future. + * + * @param tagName The name of this tag + * @param tagClassName The name of the tag handler class + * @param bodycontent Information on the body content of these tags + * @param infoString The (optional) string information for this tag + * @param taglib The instance of the tag library that contains us. + * @param tagExtraInfo The instance providing extra Tag info. May be null + * @param attributeInfo An array of AttributeInfo data from descriptor. + * May be null; + * @param displayName A short name to be displayed by tools + * @param smallIcon Path to a small icon to be displayed by tools + * @param largeIcon Path to a large icon to be displayed by tools + * @param tvi An array of a TagVariableInfo (or null) + */ + public TagInfo(String tagName, + String tagClassName, + String bodycontent, + String infoString, + TagLibraryInfo taglib, + TagExtraInfo tagExtraInfo, + TagAttributeInfo[] attributeInfo, + String displayName, + String smallIcon, + String largeIcon, + TagVariableInfo[] tvi) { + this.tagName = tagName; + this.tagClassName = tagClassName; + this.bodyContent = bodycontent; + this.infoString = infoString; + this.tagLibrary = taglib; + this.tagExtraInfo = tagExtraInfo; + this.attributeInfo = attributeInfo; + this.displayName = displayName; + this.smallIcon = smallIcon; + this.largeIcon = largeIcon; + this.tagVariableInfo = tvi; + + if (tagExtraInfo != null) + tagExtraInfo.setTagInfo(this); + } + + /** + * Constructor for TagInfo from data in the JSP 2.0 format for TLD. + * This class is to be instantiated only from the TagLibrary code + * under request from some JSP code that is parsing a + * TLD (Tag Library Descriptor). + * + * Note that, since TagLibibraryInfo reflects both TLD information + * and taglib directive information, a TagInfo instance is + * dependent on a taglib directive. This is probably a + * design error, which may be fixed in the future. + * + * @param tagName The name of this tag + * @param tagClassName The name of the tag handler class + * @param bodycontent Information on the body content of these tags + * @param infoString The (optional) string information for this tag + * @param taglib The instance of the tag library that contains us. + * @param tagExtraInfo The instance providing extra Tag info. May be null + * @param attributeInfo An array of AttributeInfo data from descriptor. + * May be null; + * @param displayName A short name to be displayed by tools + * @param smallIcon Path to a small icon to be displayed by tools + * @param largeIcon Path to a large icon to be displayed by tools + * @param tvi An array of a TagVariableInfo (or null) + * @param dynamicAttributes True if supports dynamic attributes + * + * @since 2.0 + */ + public TagInfo(String tagName, + String tagClassName, + String bodycontent, + String infoString, + TagLibraryInfo taglib, + TagExtraInfo tagExtraInfo, + TagAttributeInfo[] attributeInfo, + String displayName, + String smallIcon, + String largeIcon, + TagVariableInfo[] tvi, + boolean dynamicAttributes) { + this.tagName = tagName; + this.tagClassName = tagClassName; + this.bodyContent = bodycontent; + this.infoString = infoString; + this.tagLibrary = taglib; + this.tagExtraInfo = tagExtraInfo; + this.attributeInfo = attributeInfo; + this.displayName = displayName; + this.smallIcon = smallIcon; + this.largeIcon = largeIcon; + this.tagVariableInfo = tvi; + this.dynamicAttributes = dynamicAttributes; + + if (tagExtraInfo != null) + tagExtraInfo.setTagInfo(this); + } + + /** + * The name of the Tag. + * + * @return The (short) name of the tag. + */ + + public String getTagName() { + return tagName; + } + + /** + * Attribute information (in the TLD) on this tag. + * The return is an array describing the attributes of this tag, as + * indicated in the TLD. + * + * @return The array of TagAttributeInfo for this tag, or a + * zero-length array if the tag has no attributes. + */ + + public TagAttributeInfo[] getAttributes() { + return attributeInfo; + } + + /** + * Information on the scripting objects created by this tag at runtime. + * This is a convenience method on the associated TagExtraInfo class. + * + * @param data TagData describing this action. + * @return if a TagExtraInfo object is associated with this TagInfo, the + * result of getTagExtraInfo().getVariableInfo( data ), otherwise + * null. + */ + public VariableInfo[] getVariableInfo(TagData data) { + VariableInfo[] result = null; + TagExtraInfo tei = getTagExtraInfo(); + if (tei != null) { + result = tei.getVariableInfo( data ); + } + return result; + } + + /** + * Translation-time validation of the attributes. + * This is a convenience method on the associated TagExtraInfo class. + * + * @param data The translation-time TagData instance. + * @return Whether the data is valid. + */ + public boolean isValid(TagData data) { + TagExtraInfo tei = getTagExtraInfo(); + if (tei == null) { + return true; + } + return tei.isValid(data); + } + + /** + * Translation-time validation of the attributes. + * This is a convenience method on the associated TagExtraInfo class. + * + * @param data The translation-time TagData instance. + * @return A null object, or zero length array if no errors, an + * array of ValidationMessages otherwise. + * @since 2.0 + */ + public ValidationMessage[] validate( TagData data ) { + TagExtraInfo tei = getTagExtraInfo(); + if( tei == null ) { + return null; + } + return tei.validate( data ); + } + + /** + * Set the instance for extra tag information. + * + * @param tei the TagExtraInfo instance + */ + public void setTagExtraInfo(TagExtraInfo tei) { + tagExtraInfo = tei; + } + + + /** + * The instance (if any) for extra tag information. + * + * @return The TagExtraInfo instance, if any. + */ + public TagExtraInfo getTagExtraInfo() { + return tagExtraInfo; + } + + + /** + * Name of the class that provides the handler for this tag. + * + * @return The name of the tag handler class. + */ + + public String getTagClassName() { + return tagClassName; + } + + + /** + * The bodycontent information for this tag. + * If the bodycontent is not defined for this + * tag, the default of JSP will be returned. + * + * @return the body content string. + */ + + public String getBodyContent() { + return bodyContent; + } + + + /** + * The information string for the tag. + * + * @return the info string, or null if + * not defined + */ + + public String getInfoString() { + return infoString; + } + + + /** + * Set the TagLibraryInfo property. + * + * Note that a TagLibraryInfo element is dependent + * not just on the TLD information but also on the + * specific taglib instance used. This means that + * a fair amount of work needs to be done to construct + * and initialize TagLib objects. + * + * If used carefully, this setter can be used to avoid having to + * create new TagInfo elements for each taglib directive. + * + * @param tl the TagLibraryInfo to assign + */ + + public void setTagLibrary(TagLibraryInfo tl) { + tagLibrary = tl; + } + + /** + * The instance of TabLibraryInfo we belong to. + * + * @return the tag library instance we belong to + */ + + public TagLibraryInfo getTagLibrary() { + return tagLibrary; + } + + + // ============== JSP 2.0 TLD Information ======== + + + /** + * Get the displayName. + * + * @return A short name to be displayed by tools, + * or null if not defined + */ + + public String getDisplayName() { + return displayName; + } + + /** + * Get the path to the small icon. + * + * @return Path to a small icon to be displayed by tools, + * or null if not defined + */ + + public String getSmallIcon() { + return smallIcon; + } + + /** + * Get the path to the large icon. + * + * @return Path to a large icon to be displayed by tools, + * or null if not defined + */ + + public String getLargeIcon() { + return largeIcon; + } + + /** + * Get TagVariableInfo objects associated with this TagInfo. + * + * @return Array of TagVariableInfo objects corresponding to + * variables declared by this tag, or a zero length + * array if no variables have been declared + */ + + public TagVariableInfo[] getTagVariableInfos() { + return tagVariableInfo; + } + + + // ============== JSP 2.0 TLD Information ======== + + /** + * Get dynamicAttributes associated with this TagInfo. + * + * @return True if tag handler supports dynamic attributes + * @since 2.0 + */ + public boolean hasDynamicAttributes() { + return dynamicAttributes; + } + + /* + * private fields for 1.1 info + */ + private String tagName; // the name of the tag + private String tagClassName; + private String bodyContent; + private String infoString; + private TagLibraryInfo tagLibrary; + private TagExtraInfo tagExtraInfo; // instance of TagExtraInfo + private TagAttributeInfo[] attributeInfo; + + /* + * private fields for 1.2 info + */ + private String displayName; + private String smallIcon; + private String largeIcon; + private TagVariableInfo[] tagVariableInfo; + + /* + * Additional private fields for 2.0 info + */ + private boolean dynamicAttributes; +} diff --git a/java/javax/servlet/jsp/tagext/TagLibraryInfo.java b/java/javax/servlet/jsp/tagext/TagLibraryInfo.java index 1e42da02c..8a548bf5a 100644 --- a/java/javax/servlet/jsp/tagext/TagLibraryInfo.java +++ b/java/javax/servlet/jsp/tagext/TagLibraryInfo.java @@ -1,286 +1,286 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagFileInfo; - -/** - * Translation-time information associated with a taglib directive, and its - * underlying TLD file. - * - * Most of the information is directly from the TLD, except for - * the prefix and the uri values used in the taglib directive - * - * - */ - -abstract public class TagLibraryInfo { - - /** - * Constructor. - * - * This will invoke the constructors for TagInfo, and TagAttributeInfo - * after parsing the TLD file. - * - * @param prefix the prefix actually used by the taglib directive - * @param uri the URI actually used by the taglib directive - */ - protected TagLibraryInfo(String prefix, String uri) { - this.prefix = prefix; - this.uri = uri; - } - - // ==== methods accessing taglib information ======= - - /** - * The value of the uri attribute from the taglib directive for - * this library. - * - * @return the value of the uri attribute - */ - - public String getURI() { - return uri; - } - - /** - * The prefix assigned to this taglib from the taglib directive - * - * @return the prefix assigned to this taglib from the taglib directive - */ - - public String getPrefixString() { - return prefix; - } - - // ==== methods using the TLD data ======= - - /** - * The preferred short name (prefix) as indicated in the TLD. - * This may be used by authoring tools as the preferred prefix - * to use when creating an taglib directive for this library. - * - * @return the preferred short name for the library - */ - public String getShortName() { - return shortname; - } - - /** - * The "reliable" URN indicated in the TLD (the uri element). - * This may be used by authoring tools as a global identifier - * to use when creating a taglib directive for this library. - * - * @return a reliable URN to a TLD like this - */ - public String getReliableURN() { - return urn; - } - - - /** - * Information (documentation) for this TLD. - * - * @return the info string for this tag lib - */ - - public String getInfoString() { - return info; - } - - - /** - * A string describing the required version of the JSP container. - * - * @return the (minimal) required version of the JSP container. - * @see javax.servlet.jsp.JspEngineInfo - */ - - public String getRequiredVersion() { - return jspversion; - } - - - /** - * An array describing the tags that are defined in this tag library. - * - * @return the TagInfo objects corresponding to the tags defined by this - * tag library, or a zero length array if this tag library - * defines no tags - */ - public TagInfo[] getTags() { - return tags; - } - - /** - * An array describing the tag files that are defined in this tag library. - * - * @return the TagFileInfo objects corresponding to the tag files defined - * by this tag library, or a zero length array if this - * tag library defines no tags files - * @since 2.0 - */ - public TagFileInfo[] getTagFiles() { - return tagFiles; - } - - - /** - * Get the TagInfo for a given tag name, looking through all the - * tags in this tag library. - * - * @param shortname The short name (no prefix) of the tag - * @return the TagInfo for the tag with the specified short name, or - * null if no such tag is found - */ - - public TagInfo getTag(String shortname) { - TagInfo tags[] = getTags(); - - if (tags == null || tags.length == 0) { - return null; - } - - for (int i=0; i < tags.length; i++) { - if (tags[i].getTagName().equals(shortname)) { - return tags[i]; - } - } - return null; - } - - /** - * Get the TagFileInfo for a given tag name, looking through all the - * tag files in this tag library. - * - * @param shortname The short name (no prefix) of the tag - * @return the TagFileInfo for the specified Tag file, or null - * if no Tag file is found - * @since 2.0 - */ - public TagFileInfo getTagFile(String shortname) { - TagFileInfo tagFiles[] = getTagFiles(); - - if (tagFiles == null || tagFiles.length == 0) { - return null; - } - - for (int i=0; i < tagFiles.length; i++) { - if (tagFiles[i].getName().equals(shortname)) { - return tagFiles[i]; - } - } - return null; - } - - /** - * An array describing the functions that are defined in this tag library. - * - * @return the functions defined in this tag library, or a zero - * length array if the tag library defines no functions. - * @since 2.0 - */ - public FunctionInfo[] getFunctions() { - return functions; - } - - - /** - * Get the FunctionInfo for a given function name, looking through all the - * functions in this tag library. - * - * @param name The name (no prefix) of the function - * @return the FunctionInfo for the function with the given name, or null - * if no such function exists - * @since 2.0 - */ - public FunctionInfo getFunction(String name) { - - if (functions == null || functions.length == 0) { - System.err.println("No functions"); - return null; - } - - for (int i=0; i < functions.length; i++) { - if (functions[i].getName().equals(name)) { - return functions[i]; - } - } - return null; - } - - - // Protected fields - - /** - * The prefix assigned to this taglib from the taglib directive. - */ - protected String prefix; - - /** - * The value of the uri attribute from the taglib directive for - * this library. - */ - protected String uri; - - /** - * An array describing the tags that are defined in this tag library. - */ - protected TagInfo[] tags; - - /** - * An array describing the tag files that are defined in this tag library. - * - * @since 2.0 - */ - protected TagFileInfo[] tagFiles; - - /** - * An array describing the functions that are defined in this tag library. - * - * @since 2.0 - */ - protected FunctionInfo[] functions; - - // Tag Library Data - - /** - * The version of the tag library. - */ - protected String tlibversion; // required - - /** - * The version of the JSP specification this tag library is written to. - */ - protected String jspversion; // required - - /** - * The preferred short name (prefix) as indicated in the TLD. - */ - protected String shortname; // required - - /** - * The "reliable" URN indicated in the TLD. - */ - protected String urn; // required - - /** - * Information (documentation) for this TLD. - */ - protected String info; // optional -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagFileInfo; + +/** + * Translation-time information associated with a taglib directive, and its + * underlying TLD file. + * + * Most of the information is directly from the TLD, except for + * the prefix and the uri values used in the taglib directive + * + * + */ + +abstract public class TagLibraryInfo { + + /** + * Constructor. + * + * This will invoke the constructors for TagInfo, and TagAttributeInfo + * after parsing the TLD file. + * + * @param prefix the prefix actually used by the taglib directive + * @param uri the URI actually used by the taglib directive + */ + protected TagLibraryInfo(String prefix, String uri) { + this.prefix = prefix; + this.uri = uri; + } + + // ==== methods accessing taglib information ======= + + /** + * The value of the uri attribute from the taglib directive for + * this library. + * + * @return the value of the uri attribute + */ + + public String getURI() { + return uri; + } + + /** + * The prefix assigned to this taglib from the taglib directive + * + * @return the prefix assigned to this taglib from the taglib directive + */ + + public String getPrefixString() { + return prefix; + } + + // ==== methods using the TLD data ======= + + /** + * The preferred short name (prefix) as indicated in the TLD. + * This may be used by authoring tools as the preferred prefix + * to use when creating an taglib directive for this library. + * + * @return the preferred short name for the library + */ + public String getShortName() { + return shortname; + } + + /** + * The "reliable" URN indicated in the TLD (the uri element). + * This may be used by authoring tools as a global identifier + * to use when creating a taglib directive for this library. + * + * @return a reliable URN to a TLD like this + */ + public String getReliableURN() { + return urn; + } + + + /** + * Information (documentation) for this TLD. + * + * @return the info string for this tag lib + */ + + public String getInfoString() { + return info; + } + + + /** + * A string describing the required version of the JSP container. + * + * @return the (minimal) required version of the JSP container. + * @see javax.servlet.jsp.JspEngineInfo + */ + + public String getRequiredVersion() { + return jspversion; + } + + + /** + * An array describing the tags that are defined in this tag library. + * + * @return the TagInfo objects corresponding to the tags defined by this + * tag library, or a zero length array if this tag library + * defines no tags + */ + public TagInfo[] getTags() { + return tags; + } + + /** + * An array describing the tag files that are defined in this tag library. + * + * @return the TagFileInfo objects corresponding to the tag files defined + * by this tag library, or a zero length array if this + * tag library defines no tags files + * @since 2.0 + */ + public TagFileInfo[] getTagFiles() { + return tagFiles; + } + + + /** + * Get the TagInfo for a given tag name, looking through all the + * tags in this tag library. + * + * @param shortname The short name (no prefix) of the tag + * @return the TagInfo for the tag with the specified short name, or + * null if no such tag is found + */ + + public TagInfo getTag(String shortname) { + TagInfo tags[] = getTags(); + + if (tags == null || tags.length == 0) { + return null; + } + + for (int i=0; i < tags.length; i++) { + if (tags[i].getTagName().equals(shortname)) { + return tags[i]; + } + } + return null; + } + + /** + * Get the TagFileInfo for a given tag name, looking through all the + * tag files in this tag library. + * + * @param shortname The short name (no prefix) of the tag + * @return the TagFileInfo for the specified Tag file, or null + * if no Tag file is found + * @since 2.0 + */ + public TagFileInfo getTagFile(String shortname) { + TagFileInfo tagFiles[] = getTagFiles(); + + if (tagFiles == null || tagFiles.length == 0) { + return null; + } + + for (int i=0; i < tagFiles.length; i++) { + if (tagFiles[i].getName().equals(shortname)) { + return tagFiles[i]; + } + } + return null; + } + + /** + * An array describing the functions that are defined in this tag library. + * + * @return the functions defined in this tag library, or a zero + * length array if the tag library defines no functions. + * @since 2.0 + */ + public FunctionInfo[] getFunctions() { + return functions; + } + + + /** + * Get the FunctionInfo for a given function name, looking through all the + * functions in this tag library. + * + * @param name The name (no prefix) of the function + * @return the FunctionInfo for the function with the given name, or null + * if no such function exists + * @since 2.0 + */ + public FunctionInfo getFunction(String name) { + + if (functions == null || functions.length == 0) { + System.err.println("No functions"); + return null; + } + + for (int i=0; i < functions.length; i++) { + if (functions[i].getName().equals(name)) { + return functions[i]; + } + } + return null; + } + + + // Protected fields + + /** + * The prefix assigned to this taglib from the taglib directive. + */ + protected String prefix; + + /** + * The value of the uri attribute from the taglib directive for + * this library. + */ + protected String uri; + + /** + * An array describing the tags that are defined in this tag library. + */ + protected TagInfo[] tags; + + /** + * An array describing the tag files that are defined in this tag library. + * + * @since 2.0 + */ + protected TagFileInfo[] tagFiles; + + /** + * An array describing the functions that are defined in this tag library. + * + * @since 2.0 + */ + protected FunctionInfo[] functions; + + // Tag Library Data + + /** + * The version of the tag library. + */ + protected String tlibversion; // required + + /** + * The version of the JSP specification this tag library is written to. + */ + protected String jspversion; // required + + /** + * The preferred short name (prefix) as indicated in the TLD. + */ + protected String shortname; // required + + /** + * The "reliable" URN indicated in the TLD. + */ + protected String urn; // required + + /** + * Information (documentation) for this TLD. + */ + protected String info; // optional +} diff --git a/java/javax/servlet/jsp/tagext/TagLibraryValidator.java b/java/javax/servlet/jsp/tagext/TagLibraryValidator.java index eb2ff072b..41acb8127 100644 --- a/java/javax/servlet/jsp/tagext/TagLibraryValidator.java +++ b/java/javax/servlet/jsp/tagext/TagLibraryValidator.java @@ -1,143 +1,143 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -package javax.servlet.jsp.tagext; - -import java.util.Map; - -/** - * Translation-time validator class for a JSP page. - * A validator operates on the XML view associated with the JSP page. - * - *

- * The TLD file associates a TagLibraryValidator class and some init - * arguments with a tag library. - * - *

- * The JSP container is reponsible for locating an appropriate - * instance of the appropriate subclass by - * - *

    - *
  • new a fresh instance, or reuse an available one - *
  • invoke the setInitParams(Map) method on the instance - *
- * - * once initialized, the validate(String, String, PageData) method will - * be invoked, where the first two arguments are the prefix - * and uri for this tag library in the XML View. The prefix is intended - * to make it easier to produce an error message. However, it is not - * always accurate. In the case where a single URI is mapped to more - * than one prefix in the XML view, the prefix of the first URI is provided. - * Therefore, to provide high quality error messages in cases where the - * tag elements themselves are checked, the prefix parameter should be - * ignored and the actual prefix of the element should be used instead. - * TagLibraryValidators should always use the uri to identify elements - * as beloning to the tag library, not the prefix. - * - *

- * A TagLibraryValidator instance - * may create auxiliary objects internally to perform - * the validation (e.g. an XSchema validator) and may reuse it for all - * the pages in a given translation run. - * - *

- * The JSP container is not guaranteed to serialize invocations of - * validate() method, and TagLibraryValidators should perform any - * synchronization they may require. - * - *

- * As of JSP 2.0, a JSP container must provide a jsp:id attribute to - * provide higher quality validation errors. - * The container will track the JSP pages - * as passed to the container, and will assign to each element - * a unique "id", which is passed as the value of the jsp:id - * attribute. Each XML element in the XML view available will - * be extended with this attribute. The TagLibraryValidator - * can then use the attribute in one or more ValidationMessage - * objects. The container then, in turn, can use these - * values to provide more precise information on the location - * of an error. - * - *

- * The actual prefix of the id attribute may or may not be - * jsp but it will always map to the namespace - * http://java.sun.com/JSP/Page. A TagLibraryValidator - * implementation must rely on the uri, not the prefix, of the id - * attribute. - */ - -abstract public class TagLibraryValidator { - - /** - * Sole constructor. (For invocation by subclass constructors, - * typically implicit.) - */ - public TagLibraryValidator() { - } - - /** - * Set the init data in the TLD for this validator. - * Parameter names are keys, and parameter values are the values. - * - * @param map A Map describing the init parameters - */ - public void setInitParameters(Map map) { - initParameters = map; - } - - - /** - * Get the init parameters data as an immutable Map. - * Parameter names are keys, and parameter values are the values. - * - * @return The init parameters as an immutable map. - */ - public Map getInitParameters() { - return initParameters; - } - - /** - * Validate a JSP page. - * This will get invoked once per unique tag library URI in the - * XML view. This method will return null if the page is valid; otherwise - * the method should return an array of ValidationMessage objects. - * An array of length zero is also interpreted as no errors. - * - * @param prefix the first prefix with which the tag library is - * associated, in the XML view. Note that some tags may use - * a different prefix if the namespace is redefined. - * @param uri the tag library's unique identifier - * @param page the JspData page object - * @return A null object, or zero length array if no errors, an array - * of ValidationMessages otherwise. - */ - public ValidationMessage[] validate(String prefix, String uri, - PageData page) - { - return null; - } - - /** - * Release any data kept by this instance for validation purposes. - */ - public void release() { - initParameters = null; - } - - // Private data - private Map initParameters; - -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +package javax.servlet.jsp.tagext; + +import java.util.Map; + +/** + * Translation-time validator class for a JSP page. + * A validator operates on the XML view associated with the JSP page. + * + *

+ * The TLD file associates a TagLibraryValidator class and some init + * arguments with a tag library. + * + *

+ * The JSP container is reponsible for locating an appropriate + * instance of the appropriate subclass by + * + *

    + *
  • new a fresh instance, or reuse an available one + *
  • invoke the setInitParams(Map) method on the instance + *
+ * + * once initialized, the validate(String, String, PageData) method will + * be invoked, where the first two arguments are the prefix + * and uri for this tag library in the XML View. The prefix is intended + * to make it easier to produce an error message. However, it is not + * always accurate. In the case where a single URI is mapped to more + * than one prefix in the XML view, the prefix of the first URI is provided. + * Therefore, to provide high quality error messages in cases where the + * tag elements themselves are checked, the prefix parameter should be + * ignored and the actual prefix of the element should be used instead. + * TagLibraryValidators should always use the uri to identify elements + * as beloning to the tag library, not the prefix. + * + *

+ * A TagLibraryValidator instance + * may create auxiliary objects internally to perform + * the validation (e.g. an XSchema validator) and may reuse it for all + * the pages in a given translation run. + * + *

+ * The JSP container is not guaranteed to serialize invocations of + * validate() method, and TagLibraryValidators should perform any + * synchronization they may require. + * + *

+ * As of JSP 2.0, a JSP container must provide a jsp:id attribute to + * provide higher quality validation errors. + * The container will track the JSP pages + * as passed to the container, and will assign to each element + * a unique "id", which is passed as the value of the jsp:id + * attribute. Each XML element in the XML view available will + * be extended with this attribute. The TagLibraryValidator + * can then use the attribute in one or more ValidationMessage + * objects. The container then, in turn, can use these + * values to provide more precise information on the location + * of an error. + * + *

+ * The actual prefix of the id attribute may or may not be + * jsp but it will always map to the namespace + * http://java.sun.com/JSP/Page. A TagLibraryValidator + * implementation must rely on the uri, not the prefix, of the id + * attribute. + */ + +abstract public class TagLibraryValidator { + + /** + * Sole constructor. (For invocation by subclass constructors, + * typically implicit.) + */ + public TagLibraryValidator() { + } + + /** + * Set the init data in the TLD for this validator. + * Parameter names are keys, and parameter values are the values. + * + * @param map A Map describing the init parameters + */ + public void setInitParameters(Map map) { + initParameters = map; + } + + + /** + * Get the init parameters data as an immutable Map. + * Parameter names are keys, and parameter values are the values. + * + * @return The init parameters as an immutable map. + */ + public Map getInitParameters() { + return initParameters; + } + + /** + * Validate a JSP page. + * This will get invoked once per unique tag library URI in the + * XML view. This method will return null if the page is valid; otherwise + * the method should return an array of ValidationMessage objects. + * An array of length zero is also interpreted as no errors. + * + * @param prefix the first prefix with which the tag library is + * associated, in the XML view. Note that some tags may use + * a different prefix if the namespace is redefined. + * @param uri the tag library's unique identifier + * @param page the JspData page object + * @return A null object, or zero length array if no errors, an array + * of ValidationMessages otherwise. + */ + public ValidationMessage[] validate(String prefix, String uri, + PageData page) + { + return null; + } + + /** + * Release any data kept by this instance for validation purposes. + */ + public void release() { + initParameters = null; + } + + // Private data + private Map initParameters; + +} diff --git a/java/javax/servlet/jsp/tagext/TagSupport.java b/java/javax/servlet/jsp/tagext/TagSupport.java index 5a109963e..1e6ca3c66 100644 --- a/java/javax/servlet/jsp/tagext/TagSupport.java +++ b/java/javax/servlet/jsp/tagext/TagSupport.java @@ -1,293 +1,293 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ -package javax.servlet.jsp.tagext; - -import java.io.Serializable; -import java.util.Enumeration; -import java.util.Hashtable; - -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.PageContext; - -/** - * A base class for defining new tag handlers implementing Tag. - * - *

The TagSupport class is a utility class intended to be used as - * the base class for new tag handlers. The TagSupport class - * implements the Tag and IterationTag interfaces and adds additional - * convenience methods including getter methods for the properties in - * Tag. TagSupport has one static method that is included to - * facilitate coordination among cooperating tags. - * - *

Many tag handlers will extend TagSupport and only redefine a - * few methods. - */ - -public class TagSupport implements IterationTag, Serializable { - - /** - * Find the instance of a given class type that is closest to a given - * instance. - * This method uses the getParent method from the Tag - * interface. - * This method is used for coordination among cooperating tags. - * - *

- * The current version of the specification only provides one formal - * way of indicating the observable type of a tag handler: its - * tag handler implementation class, described in the tag-class - * subelement of the tag element. This is extended in an - * informal manner by allowing the tag library author to - * indicate in the description subelement an observable type. - * The type should be a subtype of the tag handler implementation - * class or void. - * This addititional constraint can be exploited by a - * specialized container that knows about that specific tag library, - * as in the case of the JSP standard tag library. - * - *

- * When a tag library author provides information on the - * observable type of a tag handler, client programmatic code - * should adhere to that constraint. Specifically, the Class - * passed to findAncestorWithClass should be a subtype of the - * observable type. - * - * - * @param from The instance from where to start looking. - * @param klass The subclass of Tag or interface to be matched - * @return the nearest ancestor that implements the interface - * or is an instance of the class specified - */ - - public static final Tag findAncestorWithClass(Tag from, Class klass) { - boolean isInterface = false; - - if (from == null || - klass == null || - (!Tag.class.isAssignableFrom(klass) && - !(isInterface = klass.isInterface()))) { - return null; - } - - for (;;) { - Tag tag = from.getParent(); - - if (tag == null) { - return null; - } - - if ((isInterface && klass.isInstance(tag)) || - klass.isAssignableFrom(tag.getClass())) - return tag; - else - from = tag; - } - } - - /** - * Default constructor, all subclasses are required to define only - * a public constructor with the same signature, and to call the - * superclass constructor. - * - * This constructor is called by the code generated by the JSP - * translator. - */ - - public TagSupport() { } - - /** - * Default processing of the start tag, returning SKIP_BODY. - * - * @return SKIP_BODY - * @throws JspException if an error occurs while processing this tag - * - * @see Tag#doStartTag() - */ - - public int doStartTag() throws JspException { - return SKIP_BODY; - } - - /** - * Default processing of the end tag returning EVAL_PAGE. - * - * @return EVAL_PAGE - * @throws JspException if an error occurs while processing this tag - * - * @see Tag#doEndTag() - */ - - public int doEndTag() throws JspException { - return EVAL_PAGE; - } - - - /** - * Default processing for a body. - * - * @return SKIP_BODY - * @throws JspException if an error occurs while processing this tag - * - * @see IterationTag#doAfterBody() - */ - - public int doAfterBody() throws JspException { - return SKIP_BODY; - } - - // Actions related to body evaluation - - - /** - * Release state. - * - * @see Tag#release() - */ - - public void release() { - parent = null; - id = null; - if( values != null ) { - values.clear(); - } - values = null; - } - - /** - * Set the nesting tag of this tag. - * - * @param t The parent Tag. - * @see Tag#setParent(Tag) - */ - - public void setParent(Tag t) { - parent = t; - } - - /** - * The Tag instance most closely enclosing this tag instance. - * @see Tag#getParent() - * - * @return the parent tag instance or null - */ - - public Tag getParent() { - return parent; - } - - /** - * Set the id attribute for this tag. - * - * @param id The String for the id. - */ - - public void setId(String id) { - this.id = id; - } - - /** - * The value of the id attribute of this tag; or null. - * - * @return the value of the id attribute, or null - */ - - public String getId() { - return id; - } - - /** - * Set the page context. - * - * @param pageContext The PageContext. - * @see Tag#setPageContext - */ - - public void setPageContext(PageContext pageContext) { - this.pageContext = pageContext; - } - - /** - * Associate a value with a String key. - * - * @param k The key String. - * @param o The value to associate. - */ - - public void setValue(String k, Object o) { - if (values == null) { - values = new Hashtable(); - } - values.put(k, o); - } - - /** - * Get a the value associated with a key. - * - * @param k The string key. - * @return The value associated with the key, or null. - */ - - public Object getValue(String k) { - if (values == null) { - return null; - } else { - return values.get(k); - } - } - - /** - * Remove a value associated with a key. - * - * @param k The string key. - */ - - public void removeValue(String k) { - if (values != null) { - values.remove(k); - } - } - - /** - * Enumerate the keys for the values kept by this tag handler. - * - * @return An enumeration of all the keys for the values set, - * or null or an empty Enumeration if no values have been set. - */ - - public Enumeration getValues() { - if (values == null) { - return null; - } - return values.keys(); - } - - // private fields - - private Tag parent; - private Hashtable values; - /** - * The value of the id attribute of this tag; or null. - */ - protected String id; - - // protected fields - - /** - * The PageContext. - */ - protected PageContext pageContext; -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ +package javax.servlet.jsp.tagext; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.PageContext; + +/** + * A base class for defining new tag handlers implementing Tag. + * + *

The TagSupport class is a utility class intended to be used as + * the base class for new tag handlers. The TagSupport class + * implements the Tag and IterationTag interfaces and adds additional + * convenience methods including getter methods for the properties in + * Tag. TagSupport has one static method that is included to + * facilitate coordination among cooperating tags. + * + *

Many tag handlers will extend TagSupport and only redefine a + * few methods. + */ + +public class TagSupport implements IterationTag, Serializable { + + /** + * Find the instance of a given class type that is closest to a given + * instance. + * This method uses the getParent method from the Tag + * interface. + * This method is used for coordination among cooperating tags. + * + *

+ * The current version of the specification only provides one formal + * way of indicating the observable type of a tag handler: its + * tag handler implementation class, described in the tag-class + * subelement of the tag element. This is extended in an + * informal manner by allowing the tag library author to + * indicate in the description subelement an observable type. + * The type should be a subtype of the tag handler implementation + * class or void. + * This addititional constraint can be exploited by a + * specialized container that knows about that specific tag library, + * as in the case of the JSP standard tag library. + * + *

+ * When a tag library author provides information on the + * observable type of a tag handler, client programmatic code + * should adhere to that constraint. Specifically, the Class + * passed to findAncestorWithClass should be a subtype of the + * observable type. + * + * + * @param from The instance from where to start looking. + * @param klass The subclass of Tag or interface to be matched + * @return the nearest ancestor that implements the interface + * or is an instance of the class specified + */ + + public static final Tag findAncestorWithClass(Tag from, Class klass) { + boolean isInterface = false; + + if (from == null || + klass == null || + (!Tag.class.isAssignableFrom(klass) && + !(isInterface = klass.isInterface()))) { + return null; + } + + for (;;) { + Tag tag = from.getParent(); + + if (tag == null) { + return null; + } + + if ((isInterface && klass.isInstance(tag)) || + klass.isAssignableFrom(tag.getClass())) + return tag; + else + from = tag; + } + } + + /** + * Default constructor, all subclasses are required to define only + * a public constructor with the same signature, and to call the + * superclass constructor. + * + * This constructor is called by the code generated by the JSP + * translator. + */ + + public TagSupport() { } + + /** + * Default processing of the start tag, returning SKIP_BODY. + * + * @return SKIP_BODY + * @throws JspException if an error occurs while processing this tag + * + * @see Tag#doStartTag() + */ + + public int doStartTag() throws JspException { + return SKIP_BODY; + } + + /** + * Default processing of the end tag returning EVAL_PAGE. + * + * @return EVAL_PAGE + * @throws JspException if an error occurs while processing this tag + * + * @see Tag#doEndTag() + */ + + public int doEndTag() throws JspException { + return EVAL_PAGE; + } + + + /** + * Default processing for a body. + * + * @return SKIP_BODY + * @throws JspException if an error occurs while processing this tag + * + * @see IterationTag#doAfterBody() + */ + + public int doAfterBody() throws JspException { + return SKIP_BODY; + } + + // Actions related to body evaluation + + + /** + * Release state. + * + * @see Tag#release() + */ + + public void release() { + parent = null; + id = null; + if( values != null ) { + values.clear(); + } + values = null; + } + + /** + * Set the nesting tag of this tag. + * + * @param t The parent Tag. + * @see Tag#setParent(Tag) + */ + + public void setParent(Tag t) { + parent = t; + } + + /** + * The Tag instance most closely enclosing this tag instance. + * @see Tag#getParent() + * + * @return the parent tag instance or null + */ + + public Tag getParent() { + return parent; + } + + /** + * Set the id attribute for this tag. + * + * @param id The String for the id. + */ + + public void setId(String id) { + this.id = id; + } + + /** + * The value of the id attribute of this tag; or null. + * + * @return the value of the id attribute, or null + */ + + public String getId() { + return id; + } + + /** + * Set the page context. + * + * @param pageContext The PageContext. + * @see Tag#setPageContext + */ + + public void setPageContext(PageContext pageContext) { + this.pageContext = pageContext; + } + + /** + * Associate a value with a String key. + * + * @param k The key String. + * @param o The value to associate. + */ + + public void setValue(String k, Object o) { + if (values == null) { + values = new Hashtable(); + } + values.put(k, o); + } + + /** + * Get a the value associated with a key. + * + * @param k The string key. + * @return The value associated with the key, or null. + */ + + public Object getValue(String k) { + if (values == null) { + return null; + } else { + return values.get(k); + } + } + + /** + * Remove a value associated with a key. + * + * @param k The string key. + */ + + public void removeValue(String k) { + if (values != null) { + values.remove(k); + } + } + + /** + * Enumerate the keys for the values kept by this tag handler. + * + * @return An enumeration of all the keys for the values set, + * or null or an empty Enumeration if no values have been set. + */ + + public Enumeration getValues() { + if (values == null) { + return null; + } + return values.keys(); + } + + // private fields + + private Tag parent; + private Hashtable values; + /** + * The value of the id attribute of this tag; or null. + */ + protected String id; + + // protected fields + + /** + * The PageContext. + */ + protected PageContext pageContext; +} + diff --git a/java/javax/servlet/jsp/tagext/TagVariableInfo.java b/java/javax/servlet/jsp/tagext/TagVariableInfo.java index 729550a4a..ba1759fbc 100644 --- a/java/javax/servlet/jsp/tagext/TagVariableInfo.java +++ b/java/javax/servlet/jsp/tagext/TagVariableInfo.java @@ -1,120 +1,120 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -/** - * Variable information for a tag in a Tag Library; - * This class is instantiated from the Tag Library Descriptor file (TLD) - * and is available only at translation time. - * - * This object should be immutable. - * - * This information is only available in JSP 1.2 format TLDs or above. - */ - -public class TagVariableInfo { - - /** - * Constructor for TagVariableInfo. - * - * @param nameGiven value of <name-given> - * @param nameFromAttribute value of <name-from-attribute> - * @param className value of <variable-class> - * @param declare value of <declare> - * @param scope value of <scope> - */ - public TagVariableInfo( - String nameGiven, - String nameFromAttribute, - String className, - boolean declare, - int scope) { - this.nameGiven = nameGiven; - this.nameFromAttribute = nameFromAttribute; - this.className = className; - this.declare = declare; - this.scope = scope; - } - - /** - * The body of the <name-given> element. - * - * @return The variable name as a constant - */ - - public String getNameGiven() { - return nameGiven; - } - - /** - * The body of the <name-from-attribute> element. - * This is the name of an attribute whose (translation-time) - * value will give the name of the variable. One of - * <name-given> or <name-from-attribute> is required. - * - * @return The attribute whose value defines the variable name - */ - - public String getNameFromAttribute() { - return nameFromAttribute; - } - - /** - * The body of the <variable-class> element. - * - * @return The name of the class of the variable or - * 'java.lang.String' if not defined in the TLD. - */ - - public String getClassName() { - return className; - } - - /** - * The body of the <declare> element. - * - * @return Whether the variable is to be declared or not. - * If not defined in the TLD, 'true' will be returned. - */ - - public boolean getDeclare() { - return declare; - } - - /** - * The body of the <scope> element. - * - * @return The scope to give the variable. NESTED - * scope will be returned if not defined in - * the TLD. - */ - - public int getScope() { - return scope; - } - - - /* - * private fields - */ - private String nameGiven; // - private String nameFromAttribute; // - private String className; // - private boolean declare; // - private int scope; // -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +/** + * Variable information for a tag in a Tag Library; + * This class is instantiated from the Tag Library Descriptor file (TLD) + * and is available only at translation time. + * + * This object should be immutable. + * + * This information is only available in JSP 1.2 format TLDs or above. + */ + +public class TagVariableInfo { + + /** + * Constructor for TagVariableInfo. + * + * @param nameGiven value of <name-given> + * @param nameFromAttribute value of <name-from-attribute> + * @param className value of <variable-class> + * @param declare value of <declare> + * @param scope value of <scope> + */ + public TagVariableInfo( + String nameGiven, + String nameFromAttribute, + String className, + boolean declare, + int scope) { + this.nameGiven = nameGiven; + this.nameFromAttribute = nameFromAttribute; + this.className = className; + this.declare = declare; + this.scope = scope; + } + + /** + * The body of the <name-given> element. + * + * @return The variable name as a constant + */ + + public String getNameGiven() { + return nameGiven; + } + + /** + * The body of the <name-from-attribute> element. + * This is the name of an attribute whose (translation-time) + * value will give the name of the variable. One of + * <name-given> or <name-from-attribute> is required. + * + * @return The attribute whose value defines the variable name + */ + + public String getNameFromAttribute() { + return nameFromAttribute; + } + + /** + * The body of the <variable-class> element. + * + * @return The name of the class of the variable or + * 'java.lang.String' if not defined in the TLD. + */ + + public String getClassName() { + return className; + } + + /** + * The body of the <declare> element. + * + * @return Whether the variable is to be declared or not. + * If not defined in the TLD, 'true' will be returned. + */ + + public boolean getDeclare() { + return declare; + } + + /** + * The body of the <scope> element. + * + * @return The scope to give the variable. NESTED + * scope will be returned if not defined in + * the TLD. + */ + + public int getScope() { + return scope; + } + + + /* + * private fields + */ + private String nameGiven; // + private String nameFromAttribute; // + private String className; // + private boolean declare; // + private int scope; // +} diff --git a/java/javax/servlet/jsp/tagext/TryCatchFinally.java b/java/javax/servlet/jsp/tagext/TryCatchFinally.java index b800af340..cd849eb4c 100644 --- a/java/javax/servlet/jsp/tagext/TryCatchFinally.java +++ b/java/javax/servlet/jsp/tagext/TryCatchFinally.java @@ -1,98 +1,98 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - - - -/** - * The auxiliary interface of a Tag, IterationTag or BodyTag tag - * handler that wants additional hooks for managing resources. - * - *

This interface provides two new methods: doCatch(Throwable) - * and doFinally(). The prototypical invocation is as follows: - * - *

- * h = get a Tag();  // get a tag handler, perhaps from pool
- *
- * h.setPageContext(pc);  // initialize as desired
- * h.setParent(null);
- * h.setFoo("foo");
- * 
- * // tag invocation protocol; see Tag.java
- * try {
- *   doStartTag()...
- *   ....
- *   doEndTag()...
- * } catch (Throwable t) {
- *   // react to exceptional condition
- *   h.doCatch(t);
- * } finally {
- *   // restore data invariants and release per-invocation resources
- *   h.doFinally();
- * }
- * 
- * ... other invocations perhaps with some new setters
- * ...
- * h.release();  // release long-term resources
- * 
- */ - -public interface TryCatchFinally { - - /** - * Invoked if a Throwable occurs while evaluating the BODY - * inside a tag or in any of the following methods: - * Tag.doStartTag(), Tag.doEndTag(), - * IterationTag.doAfterBody() and BodyTag.doInitBody(). - * - *

This method is not invoked if the Throwable occurs during - * one of the setter methods. - * - *

This method may throw an exception (the same or a new one) - * that will be propagated further up the nest chain. If an exception - * is thrown, doFinally() will be invoked. - * - *

This method is intended to be used to respond to an exceptional - * condition. - * - * @param t The throwable exception navigating through this tag. - * @throws Throwable if the exception is to be rethrown further up - * the nest chain. - */ - - void doCatch(Throwable t) throws Throwable; - - /** - * Invoked in all cases after doEndTag() for any class implementing - * Tag, IterationTag or BodyTag. This method is invoked even if - * an exception has occurred in the BODY of the tag, - * or in any of the following methods: - * Tag.doStartTag(), Tag.doEndTag(), - * IterationTag.doAfterBody() and BodyTag.doInitBody(). - * - *

This method is not invoked if the Throwable occurs during - * one of the setter methods. - * - *

This method should not throw an Exception. - * - *

This method is intended to maintain per-invocation data - * integrity and resource management actions. - */ - - void doFinally(); -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + + + +/** + * The auxiliary interface of a Tag, IterationTag or BodyTag tag + * handler that wants additional hooks for managing resources. + * + *

This interface provides two new methods: doCatch(Throwable) + * and doFinally(). The prototypical invocation is as follows: + * + *

+ * h = get a Tag();  // get a tag handler, perhaps from pool
+ *
+ * h.setPageContext(pc);  // initialize as desired
+ * h.setParent(null);
+ * h.setFoo("foo");
+ * 
+ * // tag invocation protocol; see Tag.java
+ * try {
+ *   doStartTag()...
+ *   ....
+ *   doEndTag()...
+ * } catch (Throwable t) {
+ *   // react to exceptional condition
+ *   h.doCatch(t);
+ * } finally {
+ *   // restore data invariants and release per-invocation resources
+ *   h.doFinally();
+ * }
+ * 
+ * ... other invocations perhaps with some new setters
+ * ...
+ * h.release();  // release long-term resources
+ * 
+ */ + +public interface TryCatchFinally { + + /** + * Invoked if a Throwable occurs while evaluating the BODY + * inside a tag or in any of the following methods: + * Tag.doStartTag(), Tag.doEndTag(), + * IterationTag.doAfterBody() and BodyTag.doInitBody(). + * + *

This method is not invoked if the Throwable occurs during + * one of the setter methods. + * + *

This method may throw an exception (the same or a new one) + * that will be propagated further up the nest chain. If an exception + * is thrown, doFinally() will be invoked. + * + *

This method is intended to be used to respond to an exceptional + * condition. + * + * @param t The throwable exception navigating through this tag. + * @throws Throwable if the exception is to be rethrown further up + * the nest chain. + */ + + void doCatch(Throwable t) throws Throwable; + + /** + * Invoked in all cases after doEndTag() for any class implementing + * Tag, IterationTag or BodyTag. This method is invoked even if + * an exception has occurred in the BODY of the tag, + * or in any of the following methods: + * Tag.doStartTag(), Tag.doEndTag(), + * IterationTag.doAfterBody() and BodyTag.doInitBody(). + * + *

This method is not invoked if the Throwable occurs during + * one of the setter methods. + * + *

This method should not throw an Exception. + * + *

This method is intended to maintain per-invocation data + * integrity and resource management actions. + */ + + void doFinally(); +} diff --git a/java/javax/servlet/jsp/tagext/ValidationMessage.java b/java/javax/servlet/jsp/tagext/ValidationMessage.java index 86bcbba06..c54455383 100644 --- a/java/javax/servlet/jsp/tagext/ValidationMessage.java +++ b/java/javax/servlet/jsp/tagext/ValidationMessage.java @@ -1,85 +1,85 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - - -/** - * A validation message from either TagLibraryValidator or TagExtraInfo. - *

- * As of JSP 2.0, a JSP container must support a jsp:id attribute - * to provide higher quality validation errors. - * The container will track the JSP pages - * as passed to the container, and will assign to each element - * a unique "id", which is passed as the value of the jsp:id - * attribute. Each XML element in the XML view available will - * be extended with this attribute. The TagLibraryValidator - * can then use the attribute in one or more ValidationMessage - * objects. The container then, in turn, can use these - * values to provide more precise information on the location - * of an error. - * - *

- * The actual prefix of the id attribute may or may not be - * jsp but it will always map to the namespace - * http://java.sun.com/JSP/Page. A TagLibraryValidator - * implementation must rely on the uri, not the prefix, of the id - * attribute. - */ - -public class ValidationMessage { - - /** - * Create a ValidationMessage. The message String should be - * non-null. The value of id may be null, if the message - * is not specific to any XML element, or if no jsp:id - * attributes were passed on. If non-null, the value of - * id must be the value of a jsp:id attribute for the PageData - * passed into the validate() method. - * - * @param id Either null, or the value of a jsp:id attribute. - * @param message A localized validation message. - */ - public ValidationMessage(String id, String message) { - this.id = id; - this.message = message; - } - - - /** - * Get the jsp:id. - * Null means that there is no information available. - * - * @return The jsp:id information. - */ - public String getId() { - return id; - } - - /** - * Get the localized validation message. - * - * @return A validation message - */ - public String getMessage(){ - return message; - } - - // Private data - private String id; - private String message; -} +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + + +/** + * A validation message from either TagLibraryValidator or TagExtraInfo. + *

+ * As of JSP 2.0, a JSP container must support a jsp:id attribute + * to provide higher quality validation errors. + * The container will track the JSP pages + * as passed to the container, and will assign to each element + * a unique "id", which is passed as the value of the jsp:id + * attribute. Each XML element in the XML view available will + * be extended with this attribute. The TagLibraryValidator + * can then use the attribute in one or more ValidationMessage + * objects. The container then, in turn, can use these + * values to provide more precise information on the location + * of an error. + * + *

+ * The actual prefix of the id attribute may or may not be + * jsp but it will always map to the namespace + * http://java.sun.com/JSP/Page. A TagLibraryValidator + * implementation must rely on the uri, not the prefix, of the id + * attribute. + */ + +public class ValidationMessage { + + /** + * Create a ValidationMessage. The message String should be + * non-null. The value of id may be null, if the message + * is not specific to any XML element, or if no jsp:id + * attributes were passed on. If non-null, the value of + * id must be the value of a jsp:id attribute for the PageData + * passed into the validate() method. + * + * @param id Either null, or the value of a jsp:id attribute. + * @param message A localized validation message. + */ + public ValidationMessage(String id, String message) { + this.id = id; + this.message = message; + } + + + /** + * Get the jsp:id. + * Null means that there is no information available. + * + * @return The jsp:id information. + */ + public String getId() { + return id; + } + + /** + * Get the localized validation message. + * + * @return A validation message + */ + public String getMessage(){ + return message; + } + + // Private data + private String id; + private String message; +} diff --git a/java/javax/servlet/jsp/tagext/VariableInfo.java b/java/javax/servlet/jsp/tagext/VariableInfo.java index 19e95a3ba..1cf6d11dc 100644 --- a/java/javax/servlet/jsp/tagext/VariableInfo.java +++ b/java/javax/servlet/jsp/tagext/VariableInfo.java @@ -1,283 +1,283 @@ -/* -* Copyright 2004 The Apache Software Foundation -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - - -package javax.servlet.jsp.tagext; - -/** - * Information on the scripting variables that are created/modified by - * a tag (at run-time). This information is provided by TagExtraInfo - * classes and it is used by the translation phase of JSP. - * - *

- * Scripting variables generated by a custom action have an associated - * scope of either AT_BEGIN, NESTED, or AT_END. - * - *

- * The class name (VariableInfo.getClassName) in the returned objects - * is used to determine the types of the scripting variables. - * Note that because scripting variables are assigned their values - * from scoped attributes which cannot be of primitive types, - * "boxed" types such as java.lang.Integer must - * be used instead of primitives. - * - *

- * The class name may be a Fully Qualified Class Name, or a short - * class name. - * - *

- * If a Fully Qualified Class Name is provided, it should refer to a - * class that should be in the CLASSPATH for the Web Application (see - * Servlet 2.4 specification - essentially it is WEB-INF/lib and - * WEB-INF/classes). Failure to be so will lead to a translation-time - * error. - * - *

- * If a short class name is given in the VariableInfo objects, then - * the class name must be that of a public class in the context of the - * import directives of the page where the custom action appears. - * The class must also be in the CLASSPATH for the Web Application - * (see Servlet 2.4 specification - essentially it is WEB-INF/lib and - * WEB-INF/classes). Failure to be so will lead to a translation-time - * error. - * - *

Usage Comments - *

- * Frequently a fully qualified class name will refer to a class that - * is known to the tag library and thus, delivered in the same JAR - * file as the tag handlers. In most other remaining cases it will - * refer to a class that is in the platform on which the JSP processor - * is built (like J2EE). Using fully qualified class names in this - * manner makes the usage relatively resistant to configuration - * errors. - * - *

- * A short name is usually generated by the tag library based on some - * attributes passed through from the custom action user (the author), - * and it is thus less robust: for instance a missing import directive - * in the referring JSP page will lead to an invalid short name class - * and a translation error. - * - *

Synchronization Protocol - * - *

- * The result of the invocation on getVariableInfo is an array of - * VariableInfo objects. Each such object describes a scripting - * variable by providing its name, its type, whether the variable is - * new or not, and what its scope is. Scope is best described through - * a picture: - * - *

- * NESTED, AT_BEGIN and AT_END Variable Scopes - * - *

- * The JSP 2.0 specification defines the interpretation of 3 values: - * - *

    - *
  • NESTED, if the scripting variable is available between - * the start tag and the end tag of the action that defines it. - *
  • - * AT_BEGIN, if the scripting variable is available from the start tag - * of the action that defines it until the end of the scope. - *
  • AT_END, if the scripting variable is available after the end tag - * of the action that defines it until the end of the scope. - *
- * - * The scope value for a variable implies what methods may affect its - * value and thus where synchronization is needed as illustrated by - * the table below. Note: the synchronization of the variable(s) - * will occur after the respective method has been called. - * - *
- * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
Variable Synchronization - * Points
- *
 doStartTag()doInitBody()doAfterBody()doEndTag()doTag()
Tag
- *
AT_BEGIN, NESTED
- *

- *

- *
AT_BEGIN, AT_END
- *

- *
IterationTag
- *
AT_BEGIN, NESTED
- *

- *
AT_BEGIN, NESTED
- *
AT_BEGIN, AT_END
- *

- *
BodyTag
- *
AT_BEGIN, NESTED1
- *
AT_BEGIN, NESTED1
- *
AT_BEGIN, NESTED
- *
AT_BEGIN, AT_END
- *

- *
SimpleTag
- *

- *

- *

- *

- *
AT_BEGIN, AT_END
- *
- * 1 Called after doStartTag() if - * EVAL_BODY_INCLUDE is returned, or after - * doInitBody() otherwise. - *
- * - *

Variable Information in the TLD - *

- * Scripting variable information can also be encoded directly for most cases - * into the Tag Library Descriptor using the <variable> subelement of the - * <tag> element. See the JSP specification. - */ - -public class VariableInfo { - - /** - * Scope information that scripting variable is visible only within the - * start/end tags. - */ - public static final int NESTED = 0; - - /** - * Scope information that scripting variable is visible after start tag. - */ - public static final int AT_BEGIN = 1; - - /** - * Scope information that scripting variable is visible after end tag. - */ - public static final int AT_END = 2; - - - /** - * Constructor - * These objects can be created (at translation time) by the TagExtraInfo - * instances. - * - * @param varName The name of the scripting variable - * @param className The type of this variable - * @param declare If true, it is a new variable (in some languages this will - * require a declaration) - * @param scope Indication on the lexical scope of the variable - */ - - public VariableInfo(String varName, - String className, - boolean declare, - int scope) { - this.varName = varName; - this.className = className; - this.declare = declare; - this.scope = scope; - } - - // Accessor methods - - /** - * Returns the name of the scripting variable. - * - * @return the name of the scripting variable - */ - public String getVarName() { - return varName; - } - - /** - * Returns the type of this variable. - * - * @return the type of this variable - */ - public String getClassName() { - return className; - } - - /** - * Returns whether this is a new variable. - * If so, in some languages this will require a declaration. - * - * @return whether this is a new variable. - */ - public boolean getDeclare() { - return declare; - } - - /** - * Returns the lexical scope of the variable. - * - * @return the lexical scope of the variable, either AT_BEGIN, AT_END, - * or NESTED. - * @see #AT_BEGIN - * @see #AT_END - * @see #NESTED - */ - public int getScope() { - return scope; - } - - - // == private data - private String varName; - private String className; - private boolean declare; - private int scope; -} - +/* +* Copyright 2004 The Apache Software Foundation +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + + +package javax.servlet.jsp.tagext; + +/** + * Information on the scripting variables that are created/modified by + * a tag (at run-time). This information is provided by TagExtraInfo + * classes and it is used by the translation phase of JSP. + * + *

+ * Scripting variables generated by a custom action have an associated + * scope of either AT_BEGIN, NESTED, or AT_END. + * + *

+ * The class name (VariableInfo.getClassName) in the returned objects + * is used to determine the types of the scripting variables. + * Note that because scripting variables are assigned their values + * from scoped attributes which cannot be of primitive types, + * "boxed" types such as java.lang.Integer must + * be used instead of primitives. + * + *

+ * The class name may be a Fully Qualified Class Name, or a short + * class name. + * + *

+ * If a Fully Qualified Class Name is provided, it should refer to a + * class that should be in the CLASSPATH for the Web Application (see + * Servlet 2.4 specification - essentially it is WEB-INF/lib and + * WEB-INF/classes). Failure to be so will lead to a translation-time + * error. + * + *

+ * If a short class name is given in the VariableInfo objects, then + * the class name must be that of a public class in the context of the + * import directives of the page where the custom action appears. + * The class must also be in the CLASSPATH for the Web Application + * (see Servlet 2.4 specification - essentially it is WEB-INF/lib and + * WEB-INF/classes). Failure to be so will lead to a translation-time + * error. + * + *

Usage Comments + *

+ * Frequently a fully qualified class name will refer to a class that + * is known to the tag library and thus, delivered in the same JAR + * file as the tag handlers. In most other remaining cases it will + * refer to a class that is in the platform on which the JSP processor + * is built (like J2EE). Using fully qualified class names in this + * manner makes the usage relatively resistant to configuration + * errors. + * + *

+ * A short name is usually generated by the tag library based on some + * attributes passed through from the custom action user (the author), + * and it is thus less robust: for instance a missing import directive + * in the referring JSP page will lead to an invalid short name class + * and a translation error. + * + *

Synchronization Protocol + * + *

+ * The result of the invocation on getVariableInfo is an array of + * VariableInfo objects. Each such object describes a scripting + * variable by providing its name, its type, whether the variable is + * new or not, and what its scope is. Scope is best described through + * a picture: + * + *

+ * NESTED, AT_BEGIN and AT_END Variable Scopes + * + *

+ * The JSP 2.0 specification defines the interpretation of 3 values: + * + *

    + *
  • NESTED, if the scripting variable is available between + * the start tag and the end tag of the action that defines it. + *
  • + * AT_BEGIN, if the scripting variable is available from the start tag + * of the action that defines it until the end of the scope. + *
  • AT_END, if the scripting variable is available after the end tag + * of the action that defines it until the end of the scope. + *
+ * + * The scope value for a variable implies what methods may affect its + * value and thus where synchronization is needed as illustrated by + * the table below. Note: the synchronization of the variable(s) + * will occur after the respective method has been called. + * + *
+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Variable Synchronization + * Points
+ *
 doStartTag()doInitBody()doAfterBody()doEndTag()doTag()
Tag
+ *
AT_BEGIN, NESTED
+ *

+ *

+ *
AT_BEGIN, AT_END
+ *

+ *
IterationTag
+ *
AT_BEGIN, NESTED
+ *

+ *
AT_BEGIN, NESTED
+ *
AT_BEGIN, AT_END
+ *

+ *
BodyTag
+ *
AT_BEGIN, NESTED1
+ *
AT_BEGIN, NESTED1
+ *
AT_BEGIN, NESTED
+ *
AT_BEGIN, AT_END
+ *

+ *
SimpleTag
+ *

+ *

+ *

+ *

+ *
AT_BEGIN, AT_END
+ *
+ * 1 Called after doStartTag() if + * EVAL_BODY_INCLUDE is returned, or after + * doInitBody() otherwise. + *
+ * + *

Variable Information in the TLD + *

+ * Scripting variable information can also be encoded directly for most cases + * into the Tag Library Descriptor using the <variable> subelement of the + * <tag> element. See the JSP specification. + */ + +public class VariableInfo { + + /** + * Scope information that scripting variable is visible only within the + * start/end tags. + */ + public static final int NESTED = 0; + + /** + * Scope information that scripting variable is visible after start tag. + */ + public static final int AT_BEGIN = 1; + + /** + * Scope information that scripting variable is visible after end tag. + */ + public static final int AT_END = 2; + + + /** + * Constructor + * These objects can be created (at translation time) by the TagExtraInfo + * instances. + * + * @param varName The name of the scripting variable + * @param className The type of this variable + * @param declare If true, it is a new variable (in some languages this will + * require a declaration) + * @param scope Indication on the lexical scope of the variable + */ + + public VariableInfo(String varName, + String className, + boolean declare, + int scope) { + this.varName = varName; + this.className = className; + this.declare = declare; + this.scope = scope; + } + + // Accessor methods + + /** + * Returns the name of the scripting variable. + * + * @return the name of the scripting variable + */ + public String getVarName() { + return varName; + } + + /** + * Returns the type of this variable. + * + * @return the type of this variable + */ + public String getClassName() { + return className; + } + + /** + * Returns whether this is a new variable. + * If so, in some languages this will require a declaration. + * + * @return whether this is a new variable. + */ + public boolean getDeclare() { + return declare; + } + + /** + * Returns the lexical scope of the variable. + * + * @return the lexical scope of the variable, either AT_BEGIN, AT_END, + * or NESTED. + * @see #AT_BEGIN + * @see #AT_END + * @see #NESTED + */ + public int getScope() { + return scope; + } + + + // == private data + private String varName; + private String className; + private boolean declare; + private int scope; +} + diff --git a/java/javax/servlet/jsp/tagext/package.html b/java/javax/servlet/jsp/tagext/package.html index f17b0cffc..e74afc845 100644 --- a/java/javax/servlet/jsp/tagext/package.html +++ b/java/javax/servlet/jsp/tagext/package.html @@ -1,85 +1,85 @@ - - - - - - - -Classes and interfaces for the definition of JavaServer Pages Tag Libraries. - -

-The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable -mechanism for the description of tag libraries. -

-A JSP tag library contains -

    -
  • A Tag Library Descriptor
  • -
  • A number of Tag Files or Tag handler classes defining - request-time behavior
  • -
  • Additional classes and resources used at runtime
  • -
  • Possibly some additional classes to provide extra translation - information
  • -
-

-The JSP 2.0 specification and the reference implementation both contain -simple and moderately complex examples of actions defined using this -mechanism. These are available at JSP's web site, at -http://java.sun.com/products/jsp. -Some readers may want to consult those to get a quick feel for how -the mechanisms work together. - - - + + + + + + + +Classes and interfaces for the definition of JavaServer Pages Tag Libraries. + +

+The JavaServer Pages(tm) (JSP) 2.0 specification provides a portable +mechanism for the description of tag libraries. +

+A JSP tag library contains +

    +
  • A Tag Library Descriptor
  • +
  • A number of Tag Files or Tag handler classes defining + request-time behavior
  • +
  • Additional classes and resources used at runtime
  • +
  • Possibly some additional classes to provide extra translation + information
  • +
+

+The JSP 2.0 specification and the reference implementation both contain +simple and moderately complex examples of actions defined using this +mechanism. These are available at JSP's web site, at +http://java.sun.com/products/jsp. +Some readers may want to consult those to get a quick feel for how +the mechanisms work together. + + + diff --git a/java/javax/servlet/package.html b/java/javax/servlet/package.html index 5f01c3902..9a720a8c7 100644 --- a/java/javax/servlet/package.html +++ b/java/javax/servlet/package.html @@ -1,23 +1,23 @@ - - - - - - - - -The javax.servlet package contains a number of classes and interfaces that -describe and define the contracts between a servlet class and the -runtime environment provided for an instance of such a class by a -conforming servlet container. - - - - + + + + + + + + +The javax.servlet package contains a number of classes and interfaces that +describe and define the contracts between a servlet class and the +runtime environment provided for an instance of such a class by a +conforming servlet container. + + + + diff --git a/java/javax/xml/ws/WebServiceRef.java b/java/javax/xml/ws/WebServiceRef.java index f6a6cb513..5c60078e7 100644 --- a/java/javax/xml/ws/WebServiceRef.java +++ b/java/javax/xml/ws/WebServiceRef.java @@ -1,34 +1,34 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.xml.ws; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface WebServiceRef { - public String name() default ""; - public Class type() default java.lang.Object.class; - public Class value() default java.lang.Object.class; - public String wsdlLocation() default ""; - public String mappedName() default ""; -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.xml.ws; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface WebServiceRef { + public String name() default ""; + public Class type() default java.lang.Object.class; + public Class value() default java.lang.Object.class; + public String wsdlLocation() default ""; + public String mappedName() default ""; +} diff --git a/java/javax/xml/ws/WebServiceRefs.java b/java/javax/xml/ws/WebServiceRefs.java index ea6a8382d..c34d61383 100644 --- a/java/javax/xml/ws/WebServiceRefs.java +++ b/java/javax/xml/ws/WebServiceRefs.java @@ -1,30 +1,30 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package javax.xml.ws; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -@Target({ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) - -public @interface WebServiceRefs { - public WebServiceRef[] value(); -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package javax.xml.ws; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME) + +public @interface WebServiceRefs { + public WebServiceRef[] value(); +} diff --git a/java/org/apache/catalina/Authenticator.java b/java/org/apache/catalina/Authenticator.java index 460333864..b3bdbcbb8 100644 --- a/java/org/apache/catalina/Authenticator.java +++ b/java/org/apache/catalina/Authenticator.java @@ -1,35 +1,35 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * An Authenticator is a component (usually a Valve or Container) that - * provides some sort of authentication service. The interface itself has no - * functional significance, but is used as a tagging mechanism so that other - * components can detect the presence (via an "instanceof Authenticator" test) - * of an already configured authentication service. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface Authenticator { - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * An Authenticator is a component (usually a Valve or Container) that + * provides some sort of authentication service. The interface itself has no + * functional significance, but is used as a tagging mechanism so that other + * components can detect the presence (via an "instanceof Authenticator" test) + * of an already configured authentication service. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface Authenticator { + + +} diff --git a/java/org/apache/catalina/Cluster.java b/java/org/apache/catalina/Cluster.java index 42999d5e9..bb4ef144a 100644 --- a/java/org/apache/catalina/Cluster.java +++ b/java/org/apache/catalina/Cluster.java @@ -1,178 +1,178 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina; - -import java.io.IOException; -import java.net.URL; -/** - * A Cluster works as a Cluster client/server for the local host - * Different Cluster implementations can be used to support different - * ways to communicate within the Cluster. A Cluster implementation is - * responsible for setting up a way to communicate within the Cluster - * and also supply "ClientApplications" with ClusterSender - * used when sending information in the Cluster and - * ClusterInfo used for receiving information in the Cluster. - * - * @author Bip Thelin - * @author Remy Maucherat - * @author Filip Hanik - * @version $Revision: 303857 $, $Date: 2005-04-15 22:15:45 +0200 (ven., 15 avr. 2005) $ - */ - -public interface Cluster { - - // ------------------------------------------------------------- Properties - - /** - * Return descriptive information about this Cluster implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - /** - * Return the name of the cluster that this Server is currently - * configured to operate within. - * - * @return The name of the cluster associated with this server - */ - public String getClusterName(); - - /** - * Set the name of the cluster to join, if no cluster with - * this name is present create one. - * - * @param clusterName The clustername to join - */ - public void setClusterName(String clusterName); - - /** - * Set the Container associated with our Cluster - * - * @param container The Container to use - */ - public void setContainer(Container container); - - /** - * Get the Container associated with our Cluster - * - * @return The Container associated with our Cluster - */ - public Container getContainer(); - - /** - * Set the protocol parameters. - * - * @param protocol The protocol used by the cluster - * @deprecated - */ - public void setProtocol(String protocol); - - /** - * Get the protocol used by the cluster. - * - * @return The protocol - * @deprecated - */ - public String getProtocol(); - - // --------------------------------------------------------- Public Methods - - /** - * Create a new manager which will use this cluster to replicate its - * sessions. - * - * @param name Name (key) of the application with which the manager is - * associated - */ - public Manager createManager(String name); - - // --------------------------------------------------------- Cluster Wide Deployments - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess(); - - - /** - * Start an existing web application, attached to the specified context - * path in all the other nodes in the cluster. - * Only starts a web application if it is not running. - * - * @param contextPath The context path of the application to be started - * - * @exception IllegalArgumentException if the specified context path - * is malformed (it must be "" or start with a slash) - * @exception IllegalArgumentException if the specified context path does - * not identify a currently installed web application - * @exception IOException if an input/output error occurs during - * startup - * @deprecated - */ - public void startContext(String contextPath) throws IOException; - - - /** - * Install a new web application, whose web application archive is at the - * specified URL, into this container with the specified context path. - * A context path of "" (the empty string) should be used for the root - * application for this container. Otherwise, the context path must - * start with a slash. - *

- * If this application is successfully installed, a ContainerEvent of type - * PRE_INSTALL_EVENT will be sent to registered listeners - * before the associated Context is started, and a ContainerEvent of type - * INSTALL_EVENT will be sent to all registered listeners - * after the associated Context is started, with the newly created - * Context as an argument. - * - * @param contextPath The context path to which this application should - * be installed (must be unique) - * @param war A URL of type "jar:" that points to a WAR file, or type - * "file:" that points to an unpacked directory structure containing - * the web application to be installed - * - * @exception IllegalArgumentException if the specified context path - * is malformed (it must be "" or start with a slash) - * @exception IllegalStateException if the specified context path - * is already attached to an existing web application - * @deprecated - */ - public void installContext(String contextPath, URL war); - - /** - * Stop an existing web application, attached to the specified context - * path. Only stops a web application if it is running. - * - * @param contextPath The context path of the application to be stopped - * - * @exception IllegalArgumentException if the specified context path - * is malformed (it must be "" or start with a slash) - * @exception IllegalArgumentException if the specified context path does - * not identify a currently installed web application - * @exception IOException if an input/output error occurs while stopping - * the web application - * @deprecated - */ - public void stop(String contextPath) throws IOException; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina; + +import java.io.IOException; +import java.net.URL; +/** + * A Cluster works as a Cluster client/server for the local host + * Different Cluster implementations can be used to support different + * ways to communicate within the Cluster. A Cluster implementation is + * responsible for setting up a way to communicate within the Cluster + * and also supply "ClientApplications" with ClusterSender + * used when sending information in the Cluster and + * ClusterInfo used for receiving information in the Cluster. + * + * @author Bip Thelin + * @author Remy Maucherat + * @author Filip Hanik + * @version $Revision: 303857 $, $Date: 2005-04-15 22:15:45 +0200 (ven., 15 avr. 2005) $ + */ + +public interface Cluster { + + // ------------------------------------------------------------- Properties + + /** + * Return descriptive information about this Cluster implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + /** + * Return the name of the cluster that this Server is currently + * configured to operate within. + * + * @return The name of the cluster associated with this server + */ + public String getClusterName(); + + /** + * Set the name of the cluster to join, if no cluster with + * this name is present create one. + * + * @param clusterName The clustername to join + */ + public void setClusterName(String clusterName); + + /** + * Set the Container associated with our Cluster + * + * @param container The Container to use + */ + public void setContainer(Container container); + + /** + * Get the Container associated with our Cluster + * + * @return The Container associated with our Cluster + */ + public Container getContainer(); + + /** + * Set the protocol parameters. + * + * @param protocol The protocol used by the cluster + * @deprecated + */ + public void setProtocol(String protocol); + + /** + * Get the protocol used by the cluster. + * + * @return The protocol + * @deprecated + */ + public String getProtocol(); + + // --------------------------------------------------------- Public Methods + + /** + * Create a new manager which will use this cluster to replicate its + * sessions. + * + * @param name Name (key) of the application with which the manager is + * associated + */ + public Manager createManager(String name); + + // --------------------------------------------------------- Cluster Wide Deployments + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess(); + + + /** + * Start an existing web application, attached to the specified context + * path in all the other nodes in the cluster. + * Only starts a web application if it is not running. + * + * @param contextPath The context path of the application to be started + * + * @exception IllegalArgumentException if the specified context path + * is malformed (it must be "" or start with a slash) + * @exception IllegalArgumentException if the specified context path does + * not identify a currently installed web application + * @exception IOException if an input/output error occurs during + * startup + * @deprecated + */ + public void startContext(String contextPath) throws IOException; + + + /** + * Install a new web application, whose web application archive is at the + * specified URL, into this container with the specified context path. + * A context path of "" (the empty string) should be used for the root + * application for this container. Otherwise, the context path must + * start with a slash. + *

+ * If this application is successfully installed, a ContainerEvent of type + * PRE_INSTALL_EVENT will be sent to registered listeners + * before the associated Context is started, and a ContainerEvent of type + * INSTALL_EVENT will be sent to all registered listeners + * after the associated Context is started, with the newly created + * Context as an argument. + * + * @param contextPath The context path to which this application should + * be installed (must be unique) + * @param war A URL of type "jar:" that points to a WAR file, or type + * "file:" that points to an unpacked directory structure containing + * the web application to be installed + * + * @exception IllegalArgumentException if the specified context path + * is malformed (it must be "" or start with a slash) + * @exception IllegalStateException if the specified context path + * is already attached to an existing web application + * @deprecated + */ + public void installContext(String contextPath, URL war); + + /** + * Stop an existing web application, attached to the specified context + * path. Only stops a web application if it is running. + * + * @param contextPath The context path of the application to be stopped + * + * @exception IllegalArgumentException if the specified context path + * is malformed (it must be "" or start with a slash) + * @exception IllegalArgumentException if the specified context path does + * not identify a currently installed web application + * @exception IOException if an input/output error occurs while stopping + * the web application + * @deprecated + */ + public void stop(String contextPath) throws IOException; + + +} diff --git a/java/org/apache/catalina/Contained.java b/java/org/apache/catalina/Contained.java index 4163c5a99..aa6fd5298 100644 --- a/java/org/apache/catalina/Contained.java +++ b/java/org/apache/catalina/Contained.java @@ -1,53 +1,53 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - *

Decoupling interface which specifies that an implementing class is - * associated with at most one Container instance.

- * - * @author Craig R. McClanahan - * @author Peter Donald - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface Contained { - - - //-------------------------------------------------------------- Properties - - - /** - * Return the Container with which this instance is associated - * (if any); otherwise return null. - */ - public Container getContainer(); - - - /** - * Set the Container with which this instance is associated. - * - * @param container The Container instance with which this instance is to - * be associated, or null to disassociate this instance - * from any Container - */ - public void setContainer(Container container); - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + *

Decoupling interface which specifies that an implementing class is + * associated with at most one Container instance.

+ * + * @author Craig R. McClanahan + * @author Peter Donald + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface Contained { + + + //-------------------------------------------------------------- Properties + + + /** + * Return the Container with which this instance is associated + * (if any); otherwise return null. + */ + public Container getContainer(); + + + /** + * Set the Container with which this instance is associated. + * + * @param container The Container instance with which this instance is to + * be associated, or null to disassociate this instance + * from any Container + */ + public void setContainer(Container container); + + +} diff --git a/java/org/apache/catalina/Container.java b/java/org/apache/catalina/Container.java index 2f2acc449..df2a7506d 100644 --- a/java/org/apache/catalina/Container.java +++ b/java/org/apache/catalina/Container.java @@ -1,442 +1,442 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.beans.PropertyChangeListener; -import java.io.IOException; -import javax.servlet.ServletException; -import javax.naming.directory.DirContext; - -import org.apache.commons.logging.Log; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; - - -/** - * A Container is an object that can execute requests received from - * a client, and return responses based on those requests. A Container may - * optionally support a pipeline of Valves that process the request in an - * order configured at runtime, by implementing the Pipeline interface - * as well. - *

- * Containers will exist at several conceptual levels within Catalina. The - * following examples represent common cases: - *

    - *
  • Engine - Representation of the entire Catalina servlet engine, - * most likely containing one or more subcontainers that are either Host - * or Context implementations, or other custom groups. - *
  • Host - Representation of a virtual host containing a number - * of Contexts. - *
  • Context - Representation of a single ServletContext, which will - * typically contain one or more Wrappers for the supported servlets. - *
  • Wrapper - Representation of an individual servlet definition - * (which may support multiple servlet instances if the servlet itself - * implements SingleThreadModel). - *
- * A given deployment of Catalina need not include Containers at all of the - * levels described above. For example, an administration application - * embedded within a network device (such as a router) might only contain - * a single Context and a few Wrappers, or even a single Wrapper if the - * application is relatively small. Therefore, Container implementations - * need to be designed so that they will operate correctly in the absence - * of parent Containers in a given deployment. - *

- * A Container may also be associated with a number of support components - * that provide functionality which might be shared (by attaching it to a - * parent Container) or individually customized. The following support - * components are currently recognized: - *

    - *
  • Loader - Class loader to use for integrating new Java classes - * for this Container into the JVM in which Catalina is running. - *
  • Logger - Implementation of the log() method - * signatures of the ServletContext interface. - *
  • Manager - Manager for the pool of Sessions associated with - * this Container. - *
  • Realm - Read-only interface to a security domain, for - * authenticating user identities and their corresponding roles. - *
  • Resources - JNDI directory context enabling access to static - * resources, enabling custom linkages to existing server components when - * Catalina is embedded in a larger server. - *
- * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303037 $ $Date: 2004-07-27 09:17:21 +0200 (mar., 27 juil. 2004) $ - */ - -public interface Container { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The ContainerEvent event type sent when a child container is added - * by addChild(). - */ - public static final String ADD_CHILD_EVENT = "addChild"; - - - /** - * The ContainerEvent event type sent when a Mapper is added - * by addMapper(). - */ - public static final String ADD_MAPPER_EVENT = "addMapper"; - - - /** - * The ContainerEvent event type sent when a valve is added - * by addValve(), if this Container supports pipelines. - */ - public static final String ADD_VALVE_EVENT = "addValve"; - - - /** - * The ContainerEvent event type sent when a child container is removed - * by removeChild(). - */ - public static final String REMOVE_CHILD_EVENT = "removeChild"; - - - /** - * The ContainerEvent event type sent when a Mapper is removed - * by removeMapper(). - */ - public static final String REMOVE_MAPPER_EVENT = "removeMapper"; - - - /** - * The ContainerEvent event type sent when a valve is removed - * by removeValve(), if this Container supports pipelines. - */ - public static final String REMOVE_VALVE_EVENT = "removeValve"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the Loader with which this Container is associated. If there is - * no associated Loader, return the Loader associated with our parent - * Container (if any); otherwise, return null. - */ - public Loader getLoader(); - - - /** - * Set the Loader with which this Container is associated. - * - * @param loader The newly associated loader - */ - public void setLoader(Loader loader); - - - /** - * Return the Logger with which this Container is associated. If there is - * no associated Logger, return the Logger associated with our parent - * Container (if any); otherwise return null. - */ - public Log getLogger(); - - - /** - * Return the Manager with which this Container is associated. If there is - * no associated Manager, return the Manager associated with our parent - * Container (if any); otherwise return null. - */ - public Manager getManager(); - - - /** - * Set the Manager with which this Container is associated. - * - * @param manager The newly associated Manager - */ - public void setManager(Manager manager); - - - /** - * Return an object which may be utilized for mapping to this component. - */ - public Object getMappingObject(); - - - /** - * Return the JMX name associated with this container. - */ - public String getObjectName(); - - /** - * Return the Pipeline object that manages the Valves associated with - * this Container. - */ - public Pipeline getPipeline(); - - - /** - * Return the Cluster with which this Container is associated. If there is - * no associated Cluster, return the Cluster associated with our parent - * Container (if any); otherwise return null. - */ - public Cluster getCluster(); - - - /** - * Set the Cluster with which this Container is associated. - * - * @param cluster the Cluster with which this Container is associated. - */ - public void setCluster(Cluster cluster); - - - /** - * Get the delay between the invocation of the backgroundProcess method on - * this container and its children. Child containers will not be invoked - * if their delay value is not negative (which would mean they are using - * their own thread). Setting this to a positive value will cause - * a thread to be spawn. After waiting the specified amount of time, - * the thread will invoke the executePeriodic method on this container - * and all its children. - */ - public int getBackgroundProcessorDelay(); - - - /** - * Set the delay between the invocation of the execute method on this - * container and its children. - * - * @param delay The delay in seconds between the invocation of - * backgroundProcess methods - */ - public void setBackgroundProcessorDelay(int delay); - - - /** - * Return a name string (suitable for use by humans) that describes this - * Container. Within the set of child containers belonging to a particular - * parent, Container names must be unique. - */ - public String getName(); - - - /** - * Set a name string (suitable for use by humans) that describes this - * Container. Within the set of child containers belonging to a particular - * parent, Container names must be unique. - * - * @param name New name of this container - * - * @exception IllegalStateException if this Container has already been - * added to the children of a parent Container (after which the name - * may not be changed) - */ - public void setName(String name); - - - /** - * Return the Container for which this Container is a child, if there is - * one. If there is no defined parent, return null. - */ - public Container getParent(); - - - /** - * Set the parent Container to which this Container is being added as a - * child. This Container may refuse to become attached to the specified - * Container by throwing an exception. - * - * @param container Container to which this Container is being added - * as a child - * - * @exception IllegalArgumentException if this Container refuses to become - * attached to the specified Container - */ - public void setParent(Container container); - - - /** - * Return the parent class loader (if any) for web applications. - */ - public ClassLoader getParentClassLoader(); - - - /** - * Set the parent class loader (if any) for web applications. - * This call is meaningful only before a Loader has - * been configured, and the specified value (if non-null) should be - * passed as an argument to the class loader constructor. - * - * @param parent The new parent class loader - */ - public void setParentClassLoader(ClassLoader parent); - - - /** - * Return the Realm with which this Container is associated. If there is - * no associated Realm, return the Realm associated with our parent - * Container (if any); otherwise return null. - */ - public Realm getRealm(); - - - /** - * Set the Realm with which this Container is associated. - * - * @param realm The newly associated Realm - */ - public void setRealm(Realm realm); - - - /** - * Return the Resources with which this Container is associated. If there - * is no associated Resources object, return the Resources associated with - * our parent Container (if any); otherwise return null. - */ - public DirContext getResources(); - - - /** - * Set the Resources object with which this Container is associated. - * - * @param resources The newly associated Resources - */ - public void setResources(DirContext resources); - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess(); - - - /** - * Add a new child Container to those associated with this Container, - * if supported. Prior to adding this Container to the set of children, - * the child's setParent() method must be called, with this - * Container as an argument. This method may thrown an - * IllegalArgumentException if this Container chooses not - * to be attached to the specified Container, in which case it is not added - * - * @param child New child Container to be added - * - * @exception IllegalArgumentException if this exception is thrown by - * the setParent() method of the child Container - * @exception IllegalArgumentException if the new child does not have - * a name unique from that of existing children of this Container - * @exception IllegalStateException if this Container does not support - * child Containers - */ - public void addChild(Container child); - - - /** - * Add a container event listener to this component. - * - * @param listener The listener to add - */ - public void addContainerListener(ContainerListener listener); - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener); - - - /** - * Return the child Container, associated with this Container, with - * the specified name (if any); otherwise, return null - * - * @param name Name of the child Container to be retrieved - */ - public Container findChild(String name); - - - /** - * Return the set of children Containers associated with this Container. - * If this Container has no children, a zero-length array is returned. - */ - public Container[] findChildren(); - - - /** - * Return the set of container listeners associated with this Container. - * If this Container has no registered container listeners, a zero-length - * array is returned. - */ - public ContainerListener[] findContainerListeners(); - - - /** - * Process the specified Request, and generate the corresponding Response, - * according to the design of this particular Container. - * - * @param request Request to be processed - * @param response Response to be produced - * - * @exception IOException if an input/output error occurred while - * processing - * @exception ServletException if a ServletException was thrown - * while processing this request - */ - public void invoke(Request request, Response response) - throws IOException, ServletException; - - - /** - * Remove an existing child Container from association with this parent - * Container. - * - * @param child Existing child Container to be removed - */ - public void removeChild(Container child); - - - /** - * Remove a container event listener from this component. - * - * @param listener The listener to remove - */ - public void removeContainerListener(ContainerListener listener); - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.beans.PropertyChangeListener; +import java.io.IOException; +import javax.servlet.ServletException; +import javax.naming.directory.DirContext; + +import org.apache.commons.logging.Log; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + + +/** + * A Container is an object that can execute requests received from + * a client, and return responses based on those requests. A Container may + * optionally support a pipeline of Valves that process the request in an + * order configured at runtime, by implementing the Pipeline interface + * as well. + *

+ * Containers will exist at several conceptual levels within Catalina. The + * following examples represent common cases: + *

    + *
  • Engine - Representation of the entire Catalina servlet engine, + * most likely containing one or more subcontainers that are either Host + * or Context implementations, or other custom groups. + *
  • Host - Representation of a virtual host containing a number + * of Contexts. + *
  • Context - Representation of a single ServletContext, which will + * typically contain one or more Wrappers for the supported servlets. + *
  • Wrapper - Representation of an individual servlet definition + * (which may support multiple servlet instances if the servlet itself + * implements SingleThreadModel). + *
+ * A given deployment of Catalina need not include Containers at all of the + * levels described above. For example, an administration application + * embedded within a network device (such as a router) might only contain + * a single Context and a few Wrappers, or even a single Wrapper if the + * application is relatively small. Therefore, Container implementations + * need to be designed so that they will operate correctly in the absence + * of parent Containers in a given deployment. + *

+ * A Container may also be associated with a number of support components + * that provide functionality which might be shared (by attaching it to a + * parent Container) or individually customized. The following support + * components are currently recognized: + *

    + *
  • Loader - Class loader to use for integrating new Java classes + * for this Container into the JVM in which Catalina is running. + *
  • Logger - Implementation of the log() method + * signatures of the ServletContext interface. + *
  • Manager - Manager for the pool of Sessions associated with + * this Container. + *
  • Realm - Read-only interface to a security domain, for + * authenticating user identities and their corresponding roles. + *
  • Resources - JNDI directory context enabling access to static + * resources, enabling custom linkages to existing server components when + * Catalina is embedded in a larger server. + *
+ * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303037 $ $Date: 2004-07-27 09:17:21 +0200 (mar., 27 juil. 2004) $ + */ + +public interface Container { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The ContainerEvent event type sent when a child container is added + * by addChild(). + */ + public static final String ADD_CHILD_EVENT = "addChild"; + + + /** + * The ContainerEvent event type sent when a Mapper is added + * by addMapper(). + */ + public static final String ADD_MAPPER_EVENT = "addMapper"; + + + /** + * The ContainerEvent event type sent when a valve is added + * by addValve(), if this Container supports pipelines. + */ + public static final String ADD_VALVE_EVENT = "addValve"; + + + /** + * The ContainerEvent event type sent when a child container is removed + * by removeChild(). + */ + public static final String REMOVE_CHILD_EVENT = "removeChild"; + + + /** + * The ContainerEvent event type sent when a Mapper is removed + * by removeMapper(). + */ + public static final String REMOVE_MAPPER_EVENT = "removeMapper"; + + + /** + * The ContainerEvent event type sent when a valve is removed + * by removeValve(), if this Container supports pipelines. + */ + public static final String REMOVE_VALVE_EVENT = "removeValve"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the Loader with which this Container is associated. If there is + * no associated Loader, return the Loader associated with our parent + * Container (if any); otherwise, return null. + */ + public Loader getLoader(); + + + /** + * Set the Loader with which this Container is associated. + * + * @param loader The newly associated loader + */ + public void setLoader(Loader loader); + + + /** + * Return the Logger with which this Container is associated. If there is + * no associated Logger, return the Logger associated with our parent + * Container (if any); otherwise return null. + */ + public Log getLogger(); + + + /** + * Return the Manager with which this Container is associated. If there is + * no associated Manager, return the Manager associated with our parent + * Container (if any); otherwise return null. + */ + public Manager getManager(); + + + /** + * Set the Manager with which this Container is associated. + * + * @param manager The newly associated Manager + */ + public void setManager(Manager manager); + + + /** + * Return an object which may be utilized for mapping to this component. + */ + public Object getMappingObject(); + + + /** + * Return the JMX name associated with this container. + */ + public String getObjectName(); + + /** + * Return the Pipeline object that manages the Valves associated with + * this Container. + */ + public Pipeline getPipeline(); + + + /** + * Return the Cluster with which this Container is associated. If there is + * no associated Cluster, return the Cluster associated with our parent + * Container (if any); otherwise return null. + */ + public Cluster getCluster(); + + + /** + * Set the Cluster with which this Container is associated. + * + * @param cluster the Cluster with which this Container is associated. + */ + public void setCluster(Cluster cluster); + + + /** + * Get the delay between the invocation of the backgroundProcess method on + * this container and its children. Child containers will not be invoked + * if their delay value is not negative (which would mean they are using + * their own thread). Setting this to a positive value will cause + * a thread to be spawn. After waiting the specified amount of time, + * the thread will invoke the executePeriodic method on this container + * and all its children. + */ + public int getBackgroundProcessorDelay(); + + + /** + * Set the delay between the invocation of the execute method on this + * container and its children. + * + * @param delay The delay in seconds between the invocation of + * backgroundProcess methods + */ + public void setBackgroundProcessorDelay(int delay); + + + /** + * Return a name string (suitable for use by humans) that describes this + * Container. Within the set of child containers belonging to a particular + * parent, Container names must be unique. + */ + public String getName(); + + + /** + * Set a name string (suitable for use by humans) that describes this + * Container. Within the set of child containers belonging to a particular + * parent, Container names must be unique. + * + * @param name New name of this container + * + * @exception IllegalStateException if this Container has already been + * added to the children of a parent Container (after which the name + * may not be changed) + */ + public void setName(String name); + + + /** + * Return the Container for which this Container is a child, if there is + * one. If there is no defined parent, return null. + */ + public Container getParent(); + + + /** + * Set the parent Container to which this Container is being added as a + * child. This Container may refuse to become attached to the specified + * Container by throwing an exception. + * + * @param container Container to which this Container is being added + * as a child + * + * @exception IllegalArgumentException if this Container refuses to become + * attached to the specified Container + */ + public void setParent(Container container); + + + /** + * Return the parent class loader (if any) for web applications. + */ + public ClassLoader getParentClassLoader(); + + + /** + * Set the parent class loader (if any) for web applications. + * This call is meaningful only before a Loader has + * been configured, and the specified value (if non-null) should be + * passed as an argument to the class loader constructor. + * + * @param parent The new parent class loader + */ + public void setParentClassLoader(ClassLoader parent); + + + /** + * Return the Realm with which this Container is associated. If there is + * no associated Realm, return the Realm associated with our parent + * Container (if any); otherwise return null. + */ + public Realm getRealm(); + + + /** + * Set the Realm with which this Container is associated. + * + * @param realm The newly associated Realm + */ + public void setRealm(Realm realm); + + + /** + * Return the Resources with which this Container is associated. If there + * is no associated Resources object, return the Resources associated with + * our parent Container (if any); otherwise return null. + */ + public DirContext getResources(); + + + /** + * Set the Resources object with which this Container is associated. + * + * @param resources The newly associated Resources + */ + public void setResources(DirContext resources); + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess(); + + + /** + * Add a new child Container to those associated with this Container, + * if supported. Prior to adding this Container to the set of children, + * the child's setParent() method must be called, with this + * Container as an argument. This method may thrown an + * IllegalArgumentException if this Container chooses not + * to be attached to the specified Container, in which case it is not added + * + * @param child New child Container to be added + * + * @exception IllegalArgumentException if this exception is thrown by + * the setParent() method of the child Container + * @exception IllegalArgumentException if the new child does not have + * a name unique from that of existing children of this Container + * @exception IllegalStateException if this Container does not support + * child Containers + */ + public void addChild(Container child); + + + /** + * Add a container event listener to this component. + * + * @param listener The listener to add + */ + public void addContainerListener(ContainerListener listener); + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + + /** + * Return the child Container, associated with this Container, with + * the specified name (if any); otherwise, return null + * + * @param name Name of the child Container to be retrieved + */ + public Container findChild(String name); + + + /** + * Return the set of children Containers associated with this Container. + * If this Container has no children, a zero-length array is returned. + */ + public Container[] findChildren(); + + + /** + * Return the set of container listeners associated with this Container. + * If this Container has no registered container listeners, a zero-length + * array is returned. + */ + public ContainerListener[] findContainerListeners(); + + + /** + * Process the specified Request, and generate the corresponding Response, + * according to the design of this particular Container. + * + * @param request Request to be processed + * @param response Response to be produced + * + * @exception IOException if an input/output error occurred while + * processing + * @exception ServletException if a ServletException was thrown + * while processing this request + */ + public void invoke(Request request, Response response) + throws IOException, ServletException; + + + /** + * Remove an existing child Container from association with this parent + * Container. + * + * @param child Existing child Container to be removed + */ + public void removeChild(Container child); + + + /** + * Remove a container event listener from this component. + * + * @param listener The listener to remove + */ + public void removeContainerListener(ContainerListener listener); + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + +} diff --git a/java/org/apache/catalina/ContainerEvent.java b/java/org/apache/catalina/ContainerEvent.java index b1f288591..3fc0bc62a 100644 --- a/java/org/apache/catalina/ContainerEvent.java +++ b/java/org/apache/catalina/ContainerEvent.java @@ -1,111 +1,111 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.util.EventObject; - - -/** - * General event for notifying listeners of significant changes on a Container. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class ContainerEvent - extends EventObject { - - - /** - * The Container on which this event occurred. - */ - private Container container = null; - - - /** - * The event data associated with this event. - */ - private Object data = null; - - - /** - * The event type this instance represents. - */ - private String type = null; - - - /** - * Construct a new ContainerEvent with the specified parameters. - * - * @param container Container on which this event occurred - * @param type Event type - * @param data Event data - */ - public ContainerEvent(Container container, String type, Object data) { - - super(container); - this.container = container; - this.type = type; - this.data = data; - - } - - - /** - * Return the event data of this event. - */ - public Object getData() { - - return (this.data); - - } - - - /** - * Return the Container on which this event occurred. - */ - public Container getContainer() { - - return (this.container); - - } - - - /** - * Return the event type of this event. - */ - public String getType() { - - return (this.type); - - } - - - /** - * Return a string representation of this event. - */ - public String toString() { - - return ("ContainerEvent['" + getContainer() + "','" + - getType() + "','" + getData() + "']"); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.util.EventObject; + + +/** + * General event for notifying listeners of significant changes on a Container. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class ContainerEvent + extends EventObject { + + + /** + * The Container on which this event occurred. + */ + private Container container = null; + + + /** + * The event data associated with this event. + */ + private Object data = null; + + + /** + * The event type this instance represents. + */ + private String type = null; + + + /** + * Construct a new ContainerEvent with the specified parameters. + * + * @param container Container on which this event occurred + * @param type Event type + * @param data Event data + */ + public ContainerEvent(Container container, String type, Object data) { + + super(container); + this.container = container; + this.type = type; + this.data = data; + + } + + + /** + * Return the event data of this event. + */ + public Object getData() { + + return (this.data); + + } + + + /** + * Return the Container on which this event occurred. + */ + public Container getContainer() { + + return (this.container); + + } + + + /** + * Return the event type of this event. + */ + public String getType() { + + return (this.type); + + } + + + /** + * Return a string representation of this event. + */ + public String toString() { + + return ("ContainerEvent['" + getContainer() + "','" + + getType() + "','" + getData() + "']"); + + } + + +} diff --git a/java/org/apache/catalina/ContainerListener.java b/java/org/apache/catalina/ContainerListener.java index 8ad94a28b..fc7384a48 100644 --- a/java/org/apache/catalina/ContainerListener.java +++ b/java/org/apache/catalina/ContainerListener.java @@ -1,43 +1,43 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - - - -/** - * Interface defining a listener for significant Container generated events. - * Note that "container start" and "container stop" events are normally - * LifecycleEvents, not ContainerEvents. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface ContainerListener { - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event ContainerEvent that has occurred - */ - public void containerEvent(ContainerEvent event); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + + + +/** + * Interface defining a listener for significant Container generated events. + * Note that "container start" and "container stop" events are normally + * LifecycleEvents, not ContainerEvents. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface ContainerListener { + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event ContainerEvent that has occurred + */ + public void containerEvent(ContainerEvent event); + + +} diff --git a/java/org/apache/catalina/ContainerServlet.java b/java/org/apache/catalina/ContainerServlet.java index e3807b675..5efd7b2f3 100644 --- a/java/org/apache/catalina/ContainerServlet.java +++ b/java/org/apache/catalina/ContainerServlet.java @@ -1,52 +1,52 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * A ContainerServlet is a servlet that has access to Catalina - * internal functionality, and is loaded from the Catalina class loader - * instead of the web application class loader. The property setter - * methods must be called by the container whenever a new instance of - * this servlet is put into service. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface ContainerServlet { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Wrapper with which this Servlet is associated. - */ - public Wrapper getWrapper(); - - - /** - * Set the Wrapper with which this Servlet is associated. - * - * @param wrapper The new associated Wrapper - */ - public void setWrapper(Wrapper wrapper); - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * A ContainerServlet is a servlet that has access to Catalina + * internal functionality, and is loaded from the Catalina class loader + * instead of the web application class loader. The property setter + * methods must be called by the container whenever a new instance of + * this servlet is put into service. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface ContainerServlet { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Wrapper with which this Servlet is associated. + */ + public Wrapper getWrapper(); + + + /** + * Set the Wrapper with which this Servlet is associated. + * + * @param wrapper The new associated Wrapper + */ + public void setWrapper(Wrapper wrapper); + + +} diff --git a/java/org/apache/catalina/Context.java b/java/org/apache/catalina/Context.java index 778d2aead..fc0711310 100644 --- a/java/org/apache/catalina/Context.java +++ b/java/org/apache/catalina/Context.java @@ -1,1061 +1,1061 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import javax.servlet.ServletContext; - -import org.apache.tomcat.util.http.mapper.Mapper; - -import org.apache.catalina.deploy.ApplicationParameter; -import org.apache.catalina.deploy.ErrorPage; -import org.apache.catalina.deploy.FilterDef; -import org.apache.catalina.deploy.FilterMap; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.deploy.NamingResources; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.util.CharsetMapper; - - -/** - * A Context is a Container that represents a servlet context, and - * therefore an individual web application, in the Catalina servlet engine. - * It is therefore useful in almost every deployment of Catalina (even if a - * Connector attached to a web server (such as Apache) uses the web server's - * facilities to identify the appropriate Wrapper to handle this request. - * It also provides a convenient mechanism to use Interceptors that see - * every request processed by this particular web application. - *

- * The parent Container attached to a Context is generally a Host, but may - * be some other implementation, or may be omitted if it is not necessary. - *

- * The child containers attached to a Context are generally implementations - * of Wrapper (representing individual servlet definitions). - *

- * - * @author Craig R. McClanahan - * @version $Revision: 303431 $ $Date: 2004-10-26 17:42:05 +0200 (mar., 26 oct. 2004) $ - */ - -public interface Context extends Container { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The LifecycleEvent type sent when a context is reloaded. - */ - public static final String RELOAD_EVENT = "reload"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the set of initialized application event listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @exception IllegalStateException if this method is called before - * this application has started, or after it has been stopped - */ - public Object[] getApplicationEventListeners(); - - - /** - * Store the set of initialized application event listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @param listeners The set of instantiated listener objects. - */ - public void setApplicationEventListeners(Object listeners[]); - - - /** - * Return the set of initialized application lifecycle listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @exception IllegalStateException if this method is called before - * this application has started, or after it has been stopped - */ - public Object[] getApplicationLifecycleListeners(); - - - /** - * Store the set of initialized application lifecycle listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @param listeners The set of instantiated listener objects. - */ - public void setApplicationLifecycleListeners(Object listeners[]); - - - /** - * Return the application available flag for this Context. - */ - public boolean getAvailable(); - - - /** - * Set the application available flag for this Context. - * - * @param available The new application available flag - */ - public void setAvailable(boolean available); - - - /** - * Return the Locale to character set mapper for this Context. - */ - public CharsetMapper getCharsetMapper(); - - - /** - * Set the Locale to character set mapper for this Context. - * - * @param mapper The new mapper - */ - public void setCharsetMapper(CharsetMapper mapper); - - - /** - * Return the path to a file to save this Context information. - */ - public String getConfigFile(); - - - /** - * Set the path to a file to save this Context information. - * - * @param configFile The path to a file to save this Context information. - */ - public void setConfigFile(String configFile); - - - /** - * Return the "correctly configured" flag for this Context. - */ - public boolean getConfigured(); - - - /** - * Set the "correctly configured" flag for this Context. This can be - * set to false by startup listeners that detect a fatal configuration - * error to avoid the application from being made available. - * - * @param configured The new correctly configured flag - */ - public void setConfigured(boolean configured); - - - /** - * Return the "use cookies for session ids" flag. - */ - public boolean getCookies(); - - - /** - * Set the "use cookies for session ids" flag. - * - * @param cookies The new flag - */ - public void setCookies(boolean cookies); - - - /** - * Return the "allow crossing servlet contexts" flag. - */ - public boolean getCrossContext(); - - - - /** - * Return the alternate Deployment Descriptor name. - */ - public String getAltDDName(); - - - /** - * Set an alternate Deployment Descriptor name. - */ - public void setAltDDName(String altDDName) ; - - - /** - * Set the "allow crossing servlet contexts" flag. - * - * @param crossContext The new cross contexts flag - */ - public void setCrossContext(boolean crossContext); - - - /** - * Return the display name of this web application. - */ - public String getDisplayName(); - - - /** - * Set the display name of this web application. - * - * @param displayName The new display name - */ - public void setDisplayName(String displayName); - - - /** - * Return the distributable flag for this web application. - */ - public boolean getDistributable(); - - - /** - * Set the distributable flag for this web application. - * - * @param distributable The new distributable flag - */ - public void setDistributable(boolean distributable); - - - /** - * Return the document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - */ - public String getDocBase(); - - - /** - * Set the document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - * - * @param docBase The new document root - */ - public void setDocBase(String docBase); - - - /** - * Return the URL encoded context path, using UTF-8. - */ - public String getEncodedPath(); - - - /** - * Return the boolean on the annotations parsing. - */ - public boolean getIgnoreAnnotations(); - - - /** - * Set the boolean on the annotations parsing for this web - * application. - * - * @param ignoreAnnotations The boolean on the annotations parsing - */ - public void setIgnoreAnnotations(boolean ignoreAnnotations); - - - /** - * Return the login configuration descriptor for this web application. - */ - public LoginConfig getLoginConfig(); - - - /** - * Set the login configuration descriptor for this web application. - * - * @param config The new login configuration - */ - public void setLoginConfig(LoginConfig config); - - - /** - * Get the request dispatcher mapper. - */ - public Mapper getMapper(); - - - /** - * Return the naming resources associated with this web application. - */ - public NamingResources getNamingResources(); - - - /** - * Set the naming resources for this web application. - * - * @param namingResources The new naming resources - */ - public void setNamingResources(NamingResources namingResources); - - - /** - * Return the context path for this web application. - */ - public String getPath(); - - - /** - * Set the context path for this web application. - * - * @param path The new context path - */ - public void setPath(String path); - - - /** - * Return the public identifier of the deployment descriptor DTD that is - * currently being parsed. - */ - public String getPublicId(); - - - /** - * Set the public identifier of the deployment descriptor DTD that is - * currently being parsed. - * - * @param publicId The public identifier - */ - public void setPublicId(String publicId); - - - /** - * Return the reloadable flag for this web application. - */ - public boolean getReloadable(); - - - /** - * Set the reloadable flag for this web application. - * - * @param reloadable The new reloadable flag - */ - public void setReloadable(boolean reloadable); - - - /** - * Return the override flag for this web application. - */ - public boolean getOverride(); - - - /** - * Set the override flag for this web application. - * - * @param override The new override flag - */ - public void setOverride(boolean override); - - - /** - * Return the privileged flag for this web application. - */ - public boolean getPrivileged(); - - - /** - * Set the privileged flag for this web application. - * - * @param privileged The new privileged flag - */ - public void setPrivileged(boolean privileged); - - - /** - * Return the servlet context for which this Context is a facade. - */ - public ServletContext getServletContext(); - - - /** - * Return the default session timeout (in minutes) for this - * web application. - */ - public int getSessionTimeout(); - - - /** - * Set the default session timeout (in minutes) for this - * web application. - * - * @param timeout The new default session timeout - */ - public void setSessionTimeout(int timeout); - - - /** - * Return the value of the swallowOutput flag. - */ - public boolean getSwallowOutput(); - - - /** - * Set the value of the swallowOutput flag. If set to true, the system.out - * and system.err will be redirected to the logger during a servlet - * execution. - * - * @param swallowOutput The new value - */ - public void setSwallowOutput(boolean swallowOutput); - - - /** - * Return the Java class name of the Wrapper implementation used - * for servlets registered in this Context. - */ - public String getWrapperClass(); - - - /** - * Set the Java class name of the Wrapper implementation used - * for servlets registered in this Context. - * - * @param wrapperClass The new wrapper class - */ - public void setWrapperClass(String wrapperClass); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new Listener class name to the set of Listeners - * configured for this application. - * - * @param listener Java class name of a listener class - */ - public void addApplicationListener(String listener); - - - /** - * Add a new application parameter for this application. - * - * @param parameter The new application parameter - */ - public void addApplicationParameter(ApplicationParameter parameter); - - - /** - * Add a security constraint to the set for this web application. - */ - public void addConstraint(SecurityConstraint constraint); - - - /** - * Add an error page for the specified error or Java exception. - * - * @param errorPage The error page definition to be added - */ - public void addErrorPage(ErrorPage errorPage); - - - /** - * Add a filter definition to this Context. - * - * @param filterDef The filter definition to be added - */ - public void addFilterDef(FilterDef filterDef); - - - /** - * Add a filter mapping to this Context. - * - * @param filterMap The filter mapping to be added - */ - public void addFilterMap(FilterMap filterMap); - - - /** - * Add the classname of an InstanceListener to be added to each - * Wrapper appended to this Context. - * - * @param listener Java class name of an InstanceListener class - */ - public void addInstanceListener(String listener); - - - /** - * Add the given URL pattern as a jsp-property-group. This maps - * resources that match the given pattern so they will be passed - * to the JSP container. Though there are other elements in the - * property group, we only care about the URL pattern here. The - * JSP container will parse the rest. - * - * @param pattern URL pattern to be mapped - */ - public void addJspMapping(String pattern); - - - /** - * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4) - * - * @param locale locale to map an encoding for - * @param encoding encoding to be used for a give locale - */ - public void addLocaleEncodingMappingParameter(String locale, String encoding); - - - /** - * Add a new MIME mapping, replacing any existing mapping for - * the specified extension. - * - * @param extension Filename extension being mapped - * @param mimeType Corresponding MIME type - */ - public void addMimeMapping(String extension, String mimeType); - - - /** - * Add a new context initialization parameter, replacing any existing - * value for the specified name. - * - * @param name Name of the new parameter - * @param value Value of the new parameter - */ - public void addParameter(String name, String value); - - - /** - * Add a security role reference for this web application. - * - * @param role Security role used in the application - * @param link Actual security role to check for - */ - public void addRoleMapping(String role, String link); - - - /** - * Add a new security role for this web application. - * - * @param role New security role - */ - public void addSecurityRole(String role); - - - /** - * Add a new servlet mapping, replacing any existing mapping for - * the specified pattern. - * - * @param pattern URL pattern to be mapped - * @param name Name of the corresponding servlet to execute - */ - public void addServletMapping(String pattern, String name); - - - /** - * Add a JSP tag library for the specified URI. - * - * @param uri URI, relative to the web.xml file, of this tag library - * @param location Location of the tag library descriptor - */ - public void addTaglib(String uri, String location); - - - /** - * Add a resource which will be watched for reloading by the host auto - * deployer. Note: this will not be used in embedded mode. - * - * @param name Path to the resource, relative to docBase - */ - public void addWatchedResource(String name); - - - /** - * Add a new welcome file to the set recognized by this Context. - * - * @param name New welcome file name - */ - public void addWelcomeFile(String name); - - - /** - * Add the classname of a LifecycleListener to be added to each - * Wrapper appended to this Context. - * - * @param listener Java class name of a LifecycleListener class - */ - public void addWrapperLifecycle(String listener); - - - /** - * Add the classname of a ContainerListener to be added to each - * Wrapper appended to this Context. - * - * @param listener Java class name of a ContainerListener class - */ - public void addWrapperListener(String listener); - - - /** - * Factory method to create and return a new Wrapper instance, of - * the Java implementation class appropriate for this Context - * implementation. The constructor of the instantiated Wrapper - * will have been called, but no properties will have been set. - */ - public Wrapper createWrapper(); - - - /** - * Return the set of application listener class names configured - * for this application. - */ - public String[] findApplicationListeners(); - - - /** - * Return the set of application parameters for this application. - */ - public ApplicationParameter[] findApplicationParameters(); - - - /** - * Return the set of security constraints for this web application. - * If there are none, a zero-length array is returned. - */ - public SecurityConstraint[] findConstraints(); - - - /** - * Return the error page entry for the specified HTTP error code, - * if any; otherwise return null. - * - * @param errorCode Error code to look up - */ - public ErrorPage findErrorPage(int errorCode); - - - /** - * Return the error page entry for the specified Java exception type, - * if any; otherwise return null. - * - * @param exceptionType Exception type to look up - */ - public ErrorPage findErrorPage(String exceptionType); - - - - /** - * Return the set of defined error pages for all specified error codes - * and exception types. - */ - public ErrorPage[] findErrorPages(); - - - /** - * Return the filter definition for the specified filter name, if any; - * otherwise return null. - * - * @param filterName Filter name to look up - */ - public FilterDef findFilterDef(String filterName); - - - /** - * Return the set of defined filters for this Context. - */ - public FilterDef[] findFilterDefs(); - - - /** - * Return the set of filter mappings for this Context. - */ - public FilterMap[] findFilterMaps(); - - - /** - * Return the set of InstanceListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findInstanceListeners(); - - - /** - * Return the MIME type to which the specified extension is mapped, - * if any; otherwise return null. - * - * @param extension Extension to map to a MIME type - */ - public String findMimeMapping(String extension); - - - /** - * Return the extensions for which MIME mappings are defined. If there - * are none, a zero-length array is returned. - */ - public String[] findMimeMappings(); - - - /** - * Return the value for the specified context initialization - * parameter name, if any; otherwise return null. - * - * @param name Name of the parameter to return - */ - public String findParameter(String name); - - - /** - * Return the names of all defined context initialization parameters - * for this Context. If no parameters are defined, a zero-length - * array is returned. - */ - public String[] findParameters(); - - - /** - * For the given security role (as used by an application), return the - * corresponding role name (as defined by the underlying Realm) if there - * is one. Otherwise, return the specified role unchanged. - * - * @param role Security role to map - */ - public String findRoleMapping(String role); - - - /** - * Return true if the specified security role is defined - * for this application; otherwise return false. - * - * @param role Security role to verify - */ - public boolean findSecurityRole(String role); - - - /** - * Return the security roles defined for this application. If none - * have been defined, a zero-length array is returned. - */ - public String[] findSecurityRoles(); - - - /** - * Return the servlet name mapped by the specified pattern (if any); - * otherwise return null. - * - * @param pattern Pattern for which a mapping is requested - */ - public String findServletMapping(String pattern); - - - /** - * Return the patterns of all defined servlet mappings for this - * Context. If no mappings are defined, a zero-length array is returned. - */ - public String[] findServletMappings(); - - - /** - * Return the context-relative URI of the error page for the specified - * HTTP status code, if any; otherwise return null. - * - * @param status HTTP status code to look up - */ - public String findStatusPage(int status); - - - /** - * Return the set of HTTP status codes for which error pages have - * been specified. If none are specified, a zero-length array - * is returned. - */ - public int[] findStatusPages(); - - - /** - * Return the tag library descriptor location for the specified taglib - * URI, if any; otherwise, return null. - * - * @param uri URI, relative to the web.xml file - */ - public String findTaglib(String uri); - - - /** - * Return the URIs of all tag libraries for which a tag library - * descriptor location has been specified. If none are specified, - * a zero-length array is returned. - */ - public String[] findTaglibs(); - - - /** - * Return the set of watched resources for this Context. If none are - * defined, a zero length array will be returned. - */ - public String[] findWatchedResources(); - - - /** - * Return true if the specified welcome file is defined - * for this Context; otherwise return false. - * - * @param name Welcome file to verify - */ - public boolean findWelcomeFile(String name); - - - /** - * Return the set of welcome files defined for this Context. If none are - * defined, a zero-length array is returned. - */ - public String[] findWelcomeFiles(); - - - /** - * Return the set of LifecycleListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findWrapperLifecycles(); - - - /** - * Return the set of ContainerListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findWrapperListeners(); - - - /** - * Reload this web application, if reloading is supported. - * - * @exception IllegalStateException if the reloadable - * property is set to false. - */ - public void reload(); - - - /** - * Remove the specified application listener class from the set of - * listeners for this application. - * - * @param listener Java class name of the listener to be removed - */ - public void removeApplicationListener(String listener); - - - /** - * Remove the application parameter with the specified name from - * the set for this application. - * - * @param name Name of the application parameter to remove - */ - public void removeApplicationParameter(String name); - - - /** - * Remove the specified security constraint from this web application. - * - * @param constraint Constraint to be removed - */ - public void removeConstraint(SecurityConstraint constraint); - - - /** - * Remove the error page for the specified error code or - * Java language exception, if it exists; otherwise, no action is taken. - * - * @param errorPage The error page definition to be removed - */ - public void removeErrorPage(ErrorPage errorPage); - - - /** - * Remove the specified filter definition from this Context, if it exists; - * otherwise, no action is taken. - * - * @param filterDef Filter definition to be removed - */ - public void removeFilterDef(FilterDef filterDef); - - - /** - * Remove a filter mapping from this Context. - * - * @param filterMap The filter mapping to be removed - */ - public void removeFilterMap(FilterMap filterMap); - - - /** - * Remove a class name from the set of InstanceListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of an InstanceListener class to be removed - */ - public void removeInstanceListener(String listener); - - - /** - * Remove the MIME mapping for the specified extension, if it exists; - * otherwise, no action is taken. - * - * @param extension Extension to remove the mapping for - */ - public void removeMimeMapping(String extension); - - - /** - * Remove the context initialization parameter with the specified - * name, if it exists; otherwise, no action is taken. - * - * @param name Name of the parameter to remove - */ - public void removeParameter(String name); - - - /** - * Remove any security role reference for the specified name - * - * @param role Security role (as used in the application) to remove - */ - public void removeRoleMapping(String role); - - - /** - * Remove any security role with the specified name. - * - * @param role Security role to remove - */ - public void removeSecurityRole(String role); - - - /** - * Remove any servlet mapping for the specified pattern, if it exists; - * otherwise, no action is taken. - * - * @param pattern URL pattern of the mapping to remove - */ - public void removeServletMapping(String pattern); - - - /** - * Remove the tag library location forthe specified tag library URI. - * - * @param uri URI, relative to the web.xml file - */ - public void removeTaglib(String uri); - - - /** - * Remove the specified watched resource name from the list associated - * with this Context. - * - * @param name Name of the watched resource to be removed - */ - public void removeWatchedResource(String name); - - - /** - * Remove the specified welcome file name from the list recognized - * by this Context. - * - * @param name Name of the welcome file to be removed - */ - public void removeWelcomeFile(String name); - - - /** - * Remove a class name from the set of LifecycleListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of a LifecycleListener class to be removed - */ - public void removeWrapperLifecycle(String listener); - - - /** - * Remove a class name from the set of ContainerListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of a ContainerListener class to be removed - */ - public void removeWrapperListener(String listener); - - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - * - */ - public boolean getXmlNamespaceAware(); - - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getXmlValidation(); - - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param xmlValidation true to enable xml instance validation - */ - public void setXmlValidation(boolean xmlValidation); - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param xmlNamespaceAware true to enable namespace awareness - */ - public void setXmlNamespaceAware(boolean xmlNamespaceAware); - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - */ - - - /** - * Set the validation feature of the XML parser used when - * parsing tlds files. - * @param tldValidation true to enable xml instance validation - */ - public void setTldValidation(boolean tldValidation); - - - /** - * Get the server.xml attribute's webXmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getTldValidation(); - - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - */ - public boolean getTldNamespaceAware(); - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param tldNamespaceAware true to enable namespace awareness - */ - public void setTldNamespaceAware(boolean tldNamespaceAware); - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import javax.servlet.ServletContext; + +import org.apache.tomcat.util.http.mapper.Mapper; + +import org.apache.catalina.deploy.ApplicationParameter; +import org.apache.catalina.deploy.ErrorPage; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.deploy.NamingResources; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.util.CharsetMapper; + + +/** + * A Context is a Container that represents a servlet context, and + * therefore an individual web application, in the Catalina servlet engine. + * It is therefore useful in almost every deployment of Catalina (even if a + * Connector attached to a web server (such as Apache) uses the web server's + * facilities to identify the appropriate Wrapper to handle this request. + * It also provides a convenient mechanism to use Interceptors that see + * every request processed by this particular web application. + *

+ * The parent Container attached to a Context is generally a Host, but may + * be some other implementation, or may be omitted if it is not necessary. + *

+ * The child containers attached to a Context are generally implementations + * of Wrapper (representing individual servlet definitions). + *

+ * + * @author Craig R. McClanahan + * @version $Revision: 303431 $ $Date: 2004-10-26 17:42:05 +0200 (mar., 26 oct. 2004) $ + */ + +public interface Context extends Container { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The LifecycleEvent type sent when a context is reloaded. + */ + public static final String RELOAD_EVENT = "reload"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the set of initialized application event listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @exception IllegalStateException if this method is called before + * this application has started, or after it has been stopped + */ + public Object[] getApplicationEventListeners(); + + + /** + * Store the set of initialized application event listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @param listeners The set of instantiated listener objects. + */ + public void setApplicationEventListeners(Object listeners[]); + + + /** + * Return the set of initialized application lifecycle listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @exception IllegalStateException if this method is called before + * this application has started, or after it has been stopped + */ + public Object[] getApplicationLifecycleListeners(); + + + /** + * Store the set of initialized application lifecycle listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @param listeners The set of instantiated listener objects. + */ + public void setApplicationLifecycleListeners(Object listeners[]); + + + /** + * Return the application available flag for this Context. + */ + public boolean getAvailable(); + + + /** + * Set the application available flag for this Context. + * + * @param available The new application available flag + */ + public void setAvailable(boolean available); + + + /** + * Return the Locale to character set mapper for this Context. + */ + public CharsetMapper getCharsetMapper(); + + + /** + * Set the Locale to character set mapper for this Context. + * + * @param mapper The new mapper + */ + public void setCharsetMapper(CharsetMapper mapper); + + + /** + * Return the path to a file to save this Context information. + */ + public String getConfigFile(); + + + /** + * Set the path to a file to save this Context information. + * + * @param configFile The path to a file to save this Context information. + */ + public void setConfigFile(String configFile); + + + /** + * Return the "correctly configured" flag for this Context. + */ + public boolean getConfigured(); + + + /** + * Set the "correctly configured" flag for this Context. This can be + * set to false by startup listeners that detect a fatal configuration + * error to avoid the application from being made available. + * + * @param configured The new correctly configured flag + */ + public void setConfigured(boolean configured); + + + /** + * Return the "use cookies for session ids" flag. + */ + public boolean getCookies(); + + + /** + * Set the "use cookies for session ids" flag. + * + * @param cookies The new flag + */ + public void setCookies(boolean cookies); + + + /** + * Return the "allow crossing servlet contexts" flag. + */ + public boolean getCrossContext(); + + + + /** + * Return the alternate Deployment Descriptor name. + */ + public String getAltDDName(); + + + /** + * Set an alternate Deployment Descriptor name. + */ + public void setAltDDName(String altDDName) ; + + + /** + * Set the "allow crossing servlet contexts" flag. + * + * @param crossContext The new cross contexts flag + */ + public void setCrossContext(boolean crossContext); + + + /** + * Return the display name of this web application. + */ + public String getDisplayName(); + + + /** + * Set the display name of this web application. + * + * @param displayName The new display name + */ + public void setDisplayName(String displayName); + + + /** + * Return the distributable flag for this web application. + */ + public boolean getDistributable(); + + + /** + * Set the distributable flag for this web application. + * + * @param distributable The new distributable flag + */ + public void setDistributable(boolean distributable); + + + /** + * Return the document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + */ + public String getDocBase(); + + + /** + * Set the document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + * + * @param docBase The new document root + */ + public void setDocBase(String docBase); + + + /** + * Return the URL encoded context path, using UTF-8. + */ + public String getEncodedPath(); + + + /** + * Return the boolean on the annotations parsing. + */ + public boolean getIgnoreAnnotations(); + + + /** + * Set the boolean on the annotations parsing for this web + * application. + * + * @param ignoreAnnotations The boolean on the annotations parsing + */ + public void setIgnoreAnnotations(boolean ignoreAnnotations); + + + /** + * Return the login configuration descriptor for this web application. + */ + public LoginConfig getLoginConfig(); + + + /** + * Set the login configuration descriptor for this web application. + * + * @param config The new login configuration + */ + public void setLoginConfig(LoginConfig config); + + + /** + * Get the request dispatcher mapper. + */ + public Mapper getMapper(); + + + /** + * Return the naming resources associated with this web application. + */ + public NamingResources getNamingResources(); + + + /** + * Set the naming resources for this web application. + * + * @param namingResources The new naming resources + */ + public void setNamingResources(NamingResources namingResources); + + + /** + * Return the context path for this web application. + */ + public String getPath(); + + + /** + * Set the context path for this web application. + * + * @param path The new context path + */ + public void setPath(String path); + + + /** + * Return the public identifier of the deployment descriptor DTD that is + * currently being parsed. + */ + public String getPublicId(); + + + /** + * Set the public identifier of the deployment descriptor DTD that is + * currently being parsed. + * + * @param publicId The public identifier + */ + public void setPublicId(String publicId); + + + /** + * Return the reloadable flag for this web application. + */ + public boolean getReloadable(); + + + /** + * Set the reloadable flag for this web application. + * + * @param reloadable The new reloadable flag + */ + public void setReloadable(boolean reloadable); + + + /** + * Return the override flag for this web application. + */ + public boolean getOverride(); + + + /** + * Set the override flag for this web application. + * + * @param override The new override flag + */ + public void setOverride(boolean override); + + + /** + * Return the privileged flag for this web application. + */ + public boolean getPrivileged(); + + + /** + * Set the privileged flag for this web application. + * + * @param privileged The new privileged flag + */ + public void setPrivileged(boolean privileged); + + + /** + * Return the servlet context for which this Context is a facade. + */ + public ServletContext getServletContext(); + + + /** + * Return the default session timeout (in minutes) for this + * web application. + */ + public int getSessionTimeout(); + + + /** + * Set the default session timeout (in minutes) for this + * web application. + * + * @param timeout The new default session timeout + */ + public void setSessionTimeout(int timeout); + + + /** + * Return the value of the swallowOutput flag. + */ + public boolean getSwallowOutput(); + + + /** + * Set the value of the swallowOutput flag. If set to true, the system.out + * and system.err will be redirected to the logger during a servlet + * execution. + * + * @param swallowOutput The new value + */ + public void setSwallowOutput(boolean swallowOutput); + + + /** + * Return the Java class name of the Wrapper implementation used + * for servlets registered in this Context. + */ + public String getWrapperClass(); + + + /** + * Set the Java class name of the Wrapper implementation used + * for servlets registered in this Context. + * + * @param wrapperClass The new wrapper class + */ + public void setWrapperClass(String wrapperClass); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new Listener class name to the set of Listeners + * configured for this application. + * + * @param listener Java class name of a listener class + */ + public void addApplicationListener(String listener); + + + /** + * Add a new application parameter for this application. + * + * @param parameter The new application parameter + */ + public void addApplicationParameter(ApplicationParameter parameter); + + + /** + * Add a security constraint to the set for this web application. + */ + public void addConstraint(SecurityConstraint constraint); + + + /** + * Add an error page for the specified error or Java exception. + * + * @param errorPage The error page definition to be added + */ + public void addErrorPage(ErrorPage errorPage); + + + /** + * Add a filter definition to this Context. + * + * @param filterDef The filter definition to be added + */ + public void addFilterDef(FilterDef filterDef); + + + /** + * Add a filter mapping to this Context. + * + * @param filterMap The filter mapping to be added + */ + public void addFilterMap(FilterMap filterMap); + + + /** + * Add the classname of an InstanceListener to be added to each + * Wrapper appended to this Context. + * + * @param listener Java class name of an InstanceListener class + */ + public void addInstanceListener(String listener); + + + /** + * Add the given URL pattern as a jsp-property-group. This maps + * resources that match the given pattern so they will be passed + * to the JSP container. Though there are other elements in the + * property group, we only care about the URL pattern here. The + * JSP container will parse the rest. + * + * @param pattern URL pattern to be mapped + */ + public void addJspMapping(String pattern); + + + /** + * Add a Locale Encoding Mapping (see Sec 5.4 of Servlet spec 2.4) + * + * @param locale locale to map an encoding for + * @param encoding encoding to be used for a give locale + */ + public void addLocaleEncodingMappingParameter(String locale, String encoding); + + + /** + * Add a new MIME mapping, replacing any existing mapping for + * the specified extension. + * + * @param extension Filename extension being mapped + * @param mimeType Corresponding MIME type + */ + public void addMimeMapping(String extension, String mimeType); + + + /** + * Add a new context initialization parameter, replacing any existing + * value for the specified name. + * + * @param name Name of the new parameter + * @param value Value of the new parameter + */ + public void addParameter(String name, String value); + + + /** + * Add a security role reference for this web application. + * + * @param role Security role used in the application + * @param link Actual security role to check for + */ + public void addRoleMapping(String role, String link); + + + /** + * Add a new security role for this web application. + * + * @param role New security role + */ + public void addSecurityRole(String role); + + + /** + * Add a new servlet mapping, replacing any existing mapping for + * the specified pattern. + * + * @param pattern URL pattern to be mapped + * @param name Name of the corresponding servlet to execute + */ + public void addServletMapping(String pattern, String name); + + + /** + * Add a JSP tag library for the specified URI. + * + * @param uri URI, relative to the web.xml file, of this tag library + * @param location Location of the tag library descriptor + */ + public void addTaglib(String uri, String location); + + + /** + * Add a resource which will be watched for reloading by the host auto + * deployer. Note: this will not be used in embedded mode. + * + * @param name Path to the resource, relative to docBase + */ + public void addWatchedResource(String name); + + + /** + * Add a new welcome file to the set recognized by this Context. + * + * @param name New welcome file name + */ + public void addWelcomeFile(String name); + + + /** + * Add the classname of a LifecycleListener to be added to each + * Wrapper appended to this Context. + * + * @param listener Java class name of a LifecycleListener class + */ + public void addWrapperLifecycle(String listener); + + + /** + * Add the classname of a ContainerListener to be added to each + * Wrapper appended to this Context. + * + * @param listener Java class name of a ContainerListener class + */ + public void addWrapperListener(String listener); + + + /** + * Factory method to create and return a new Wrapper instance, of + * the Java implementation class appropriate for this Context + * implementation. The constructor of the instantiated Wrapper + * will have been called, but no properties will have been set. + */ + public Wrapper createWrapper(); + + + /** + * Return the set of application listener class names configured + * for this application. + */ + public String[] findApplicationListeners(); + + + /** + * Return the set of application parameters for this application. + */ + public ApplicationParameter[] findApplicationParameters(); + + + /** + * Return the set of security constraints for this web application. + * If there are none, a zero-length array is returned. + */ + public SecurityConstraint[] findConstraints(); + + + /** + * Return the error page entry for the specified HTTP error code, + * if any; otherwise return null. + * + * @param errorCode Error code to look up + */ + public ErrorPage findErrorPage(int errorCode); + + + /** + * Return the error page entry for the specified Java exception type, + * if any; otherwise return null. + * + * @param exceptionType Exception type to look up + */ + public ErrorPage findErrorPage(String exceptionType); + + + + /** + * Return the set of defined error pages for all specified error codes + * and exception types. + */ + public ErrorPage[] findErrorPages(); + + + /** + * Return the filter definition for the specified filter name, if any; + * otherwise return null. + * + * @param filterName Filter name to look up + */ + public FilterDef findFilterDef(String filterName); + + + /** + * Return the set of defined filters for this Context. + */ + public FilterDef[] findFilterDefs(); + + + /** + * Return the set of filter mappings for this Context. + */ + public FilterMap[] findFilterMaps(); + + + /** + * Return the set of InstanceListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findInstanceListeners(); + + + /** + * Return the MIME type to which the specified extension is mapped, + * if any; otherwise return null. + * + * @param extension Extension to map to a MIME type + */ + public String findMimeMapping(String extension); + + + /** + * Return the extensions for which MIME mappings are defined. If there + * are none, a zero-length array is returned. + */ + public String[] findMimeMappings(); + + + /** + * Return the value for the specified context initialization + * parameter name, if any; otherwise return null. + * + * @param name Name of the parameter to return + */ + public String findParameter(String name); + + + /** + * Return the names of all defined context initialization parameters + * for this Context. If no parameters are defined, a zero-length + * array is returned. + */ + public String[] findParameters(); + + + /** + * For the given security role (as used by an application), return the + * corresponding role name (as defined by the underlying Realm) if there + * is one. Otherwise, return the specified role unchanged. + * + * @param role Security role to map + */ + public String findRoleMapping(String role); + + + /** + * Return true if the specified security role is defined + * for this application; otherwise return false. + * + * @param role Security role to verify + */ + public boolean findSecurityRole(String role); + + + /** + * Return the security roles defined for this application. If none + * have been defined, a zero-length array is returned. + */ + public String[] findSecurityRoles(); + + + /** + * Return the servlet name mapped by the specified pattern (if any); + * otherwise return null. + * + * @param pattern Pattern for which a mapping is requested + */ + public String findServletMapping(String pattern); + + + /** + * Return the patterns of all defined servlet mappings for this + * Context. If no mappings are defined, a zero-length array is returned. + */ + public String[] findServletMappings(); + + + /** + * Return the context-relative URI of the error page for the specified + * HTTP status code, if any; otherwise return null. + * + * @param status HTTP status code to look up + */ + public String findStatusPage(int status); + + + /** + * Return the set of HTTP status codes for which error pages have + * been specified. If none are specified, a zero-length array + * is returned. + */ + public int[] findStatusPages(); + + + /** + * Return the tag library descriptor location for the specified taglib + * URI, if any; otherwise, return null. + * + * @param uri URI, relative to the web.xml file + */ + public String findTaglib(String uri); + + + /** + * Return the URIs of all tag libraries for which a tag library + * descriptor location has been specified. If none are specified, + * a zero-length array is returned. + */ + public String[] findTaglibs(); + + + /** + * Return the set of watched resources for this Context. If none are + * defined, a zero length array will be returned. + */ + public String[] findWatchedResources(); + + + /** + * Return true if the specified welcome file is defined + * for this Context; otherwise return false. + * + * @param name Welcome file to verify + */ + public boolean findWelcomeFile(String name); + + + /** + * Return the set of welcome files defined for this Context. If none are + * defined, a zero-length array is returned. + */ + public String[] findWelcomeFiles(); + + + /** + * Return the set of LifecycleListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findWrapperLifecycles(); + + + /** + * Return the set of ContainerListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findWrapperListeners(); + + + /** + * Reload this web application, if reloading is supported. + * + * @exception IllegalStateException if the reloadable + * property is set to false. + */ + public void reload(); + + + /** + * Remove the specified application listener class from the set of + * listeners for this application. + * + * @param listener Java class name of the listener to be removed + */ + public void removeApplicationListener(String listener); + + + /** + * Remove the application parameter with the specified name from + * the set for this application. + * + * @param name Name of the application parameter to remove + */ + public void removeApplicationParameter(String name); + + + /** + * Remove the specified security constraint from this web application. + * + * @param constraint Constraint to be removed + */ + public void removeConstraint(SecurityConstraint constraint); + + + /** + * Remove the error page for the specified error code or + * Java language exception, if it exists; otherwise, no action is taken. + * + * @param errorPage The error page definition to be removed + */ + public void removeErrorPage(ErrorPage errorPage); + + + /** + * Remove the specified filter definition from this Context, if it exists; + * otherwise, no action is taken. + * + * @param filterDef Filter definition to be removed + */ + public void removeFilterDef(FilterDef filterDef); + + + /** + * Remove a filter mapping from this Context. + * + * @param filterMap The filter mapping to be removed + */ + public void removeFilterMap(FilterMap filterMap); + + + /** + * Remove a class name from the set of InstanceListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of an InstanceListener class to be removed + */ + public void removeInstanceListener(String listener); + + + /** + * Remove the MIME mapping for the specified extension, if it exists; + * otherwise, no action is taken. + * + * @param extension Extension to remove the mapping for + */ + public void removeMimeMapping(String extension); + + + /** + * Remove the context initialization parameter with the specified + * name, if it exists; otherwise, no action is taken. + * + * @param name Name of the parameter to remove + */ + public void removeParameter(String name); + + + /** + * Remove any security role reference for the specified name + * + * @param role Security role (as used in the application) to remove + */ + public void removeRoleMapping(String role); + + + /** + * Remove any security role with the specified name. + * + * @param role Security role to remove + */ + public void removeSecurityRole(String role); + + + /** + * Remove any servlet mapping for the specified pattern, if it exists; + * otherwise, no action is taken. + * + * @param pattern URL pattern of the mapping to remove + */ + public void removeServletMapping(String pattern); + + + /** + * Remove the tag library location forthe specified tag library URI. + * + * @param uri URI, relative to the web.xml file + */ + public void removeTaglib(String uri); + + + /** + * Remove the specified watched resource name from the list associated + * with this Context. + * + * @param name Name of the watched resource to be removed + */ + public void removeWatchedResource(String name); + + + /** + * Remove the specified welcome file name from the list recognized + * by this Context. + * + * @param name Name of the welcome file to be removed + */ + public void removeWelcomeFile(String name); + + + /** + * Remove a class name from the set of LifecycleListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of a LifecycleListener class to be removed + */ + public void removeWrapperLifecycle(String listener); + + + /** + * Remove a class name from the set of ContainerListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of a ContainerListener class to be removed + */ + public void removeWrapperListener(String listener); + + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + * + */ + public boolean getXmlNamespaceAware(); + + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getXmlValidation(); + + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param xmlValidation true to enable xml instance validation + */ + public void setXmlValidation(boolean xmlValidation); + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param xmlNamespaceAware true to enable namespace awareness + */ + public void setXmlNamespaceAware(boolean xmlNamespaceAware); + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + */ + + + /** + * Set the validation feature of the XML parser used when + * parsing tlds files. + * @param tldValidation true to enable xml instance validation + */ + public void setTldValidation(boolean tldValidation); + + + /** + * Get the server.xml attribute's webXmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getTldValidation(); + + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + */ + public boolean getTldNamespaceAware(); + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param tldNamespaceAware true to enable namespace awareness + */ + public void setTldNamespaceAware(boolean tldNamespaceAware); + + +} + diff --git a/java/org/apache/catalina/Engine.java b/java/org/apache/catalina/Engine.java index 57081b647..991c03429 100644 --- a/java/org/apache/catalina/Engine.java +++ b/java/org/apache/catalina/Engine.java @@ -1,95 +1,95 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - -/** - * An Engine is a Container that represents the entire Catalina servlet - * engine. It is useful in the following types of scenarios: - *

    - *
  • You wish to use Interceptors that see every single request processed - * by the entire engine. - *
  • You wish to run Catalina in with a standalone HTTP connector, but still - * want support for multiple virtual hosts. - *
- * In general, you would not use an Engine when deploying Catalina connected - * to a web server (such as Apache), because the Connector will have - * utilized the web server's facilities to determine which Context (or - * perhaps even which Wrapper) should be utilized to process this request. - *

- * The child containers attached to an Engine are generally implementations - * of Host (representing a virtual host) or Context (representing individual - * an individual servlet context), depending upon the Engine implementation. - *

- * If used, an Engine is always the top level Container in a Catalina - * hierarchy. Therefore, the implementation's setParent() method - * should throw IllegalArgumentException. - * - * @author Craig R. McClanahan - * @version $Revision: 303092 $ $Date: 2004-08-16 11:31:09 +0200 (lun., 16 août 2004) $ - */ - -public interface Engine extends Container { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the default hostname for this Engine. - */ - public String getDefaultHost(); - - - /** - * Set the default hostname for this Engine. - * - * @param defaultHost The new default host - */ - public void setDefaultHost(String defaultHost); - - - /** - * Retrieve the JvmRouteId for this engine. - */ - public String getJvmRoute(); - - - /** - * Set the JvmRouteId for this engine. - * - * @param jvmRouteId the (new) JVM Route ID. Each Engine within a cluster - * must have a unique JVM Route ID. - */ - public void setJvmRoute(String jvmRouteId); - - - /** - * Return the Service with which we are associated (if any). - */ - public Service getService(); - - - /** - * Set the Service with which we are associated (if any). - * - * @param service The service that owns this Engine - */ - public void setService(Service service); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + +/** + * An Engine is a Container that represents the entire Catalina servlet + * engine. It is useful in the following types of scenarios: + *

    + *
  • You wish to use Interceptors that see every single request processed + * by the entire engine. + *
  • You wish to run Catalina in with a standalone HTTP connector, but still + * want support for multiple virtual hosts. + *
+ * In general, you would not use an Engine when deploying Catalina connected + * to a web server (such as Apache), because the Connector will have + * utilized the web server's facilities to determine which Context (or + * perhaps even which Wrapper) should be utilized to process this request. + *

+ * The child containers attached to an Engine are generally implementations + * of Host (representing a virtual host) or Context (representing individual + * an individual servlet context), depending upon the Engine implementation. + *

+ * If used, an Engine is always the top level Container in a Catalina + * hierarchy. Therefore, the implementation's setParent() method + * should throw IllegalArgumentException. + * + * @author Craig R. McClanahan + * @version $Revision: 303092 $ $Date: 2004-08-16 11:31:09 +0200 (lun., 16 août 2004) $ + */ + +public interface Engine extends Container { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the default hostname for this Engine. + */ + public String getDefaultHost(); + + + /** + * Set the default hostname for this Engine. + * + * @param defaultHost The new default host + */ + public void setDefaultHost(String defaultHost); + + + /** + * Retrieve the JvmRouteId for this engine. + */ + public String getJvmRoute(); + + + /** + * Set the JvmRouteId for this engine. + * + * @param jvmRouteId the (new) JVM Route ID. Each Engine within a cluster + * must have a unique JVM Route ID. + */ + public void setJvmRoute(String jvmRouteId); + + + /** + * Return the Service with which we are associated (if any). + */ + public Service getService(); + + + /** + * Set the Service with which we are associated (if any). + * + * @param service The service that owns this Engine + */ + public void setService(Service service); + + +} diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java index 4ab50cf16..2de06db7e 100644 --- a/java/org/apache/catalina/Globals.java +++ b/java/org/apache/catalina/Globals.java @@ -1,324 +1,324 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * Global constants that are applicable to multiple packages within Catalina. - * - * @author Craig R. McClanahan - * @version $Revision: 303495 $ $Date: 2004-11-19 07:07:56 +0100 (ven., 19 nov. 2004) $ - */ - -public final class Globals { - - /** - * The servlet context attribute under which we store the alternate - * deployment descriptor for this web application - */ - public static final String ALT_DD_ATTR = - "org.apache.catalina.deploy.alt_dd"; - - /** - * The request attribute under which we store the array of X509Certificate - * objects representing the certificate chain presented by our client, - * if any. - */ - public static final String CERTIFICATES_ATTR = - "javax.servlet.request.X509Certificate"; - - /** - * The request attribute under which we store the name of the cipher suite - * being used on an SSL connection (as an object of type - * java.lang.String). - */ - public static final String CIPHER_SUITE_ATTR = - "javax.servlet.request.cipher_suite"; - - - /** - * The servlet context attribute under which we store the class loader - * used for loading servlets (as an object of type java.lang.ClassLoader). - */ - public static final String CLASS_LOADER_ATTR = - "org.apache.catalina.classloader"; - - /** - * Request dispatcher state. - */ - public static final String DISPATCHER_TYPE_ATTR = - "org.apache.catalina.core.DISPATCHER_TYPE"; - - /** - * Request dispatcher path. - */ - public static final String DISPATCHER_REQUEST_PATH_ATTR = - "org.apache.catalina.core.DISPATCHER_REQUEST_PATH"; - - /** - * The JNDI directory context which is associated with the context. This - * context can be used to manipulate static files. - */ - public static final String RESOURCES_ATTR = - "org.apache.catalina.resources"; - - - /** - * The servlet context attribute under which we store the class path - * for our application class loader (as an object of type String), - * delimited with the appropriate path delimiter for this platform. - */ - public static final String CLASS_PATH_ATTR = - "org.apache.catalina.jsp_classpath"; - - - /** - * The request attribute under which we forward a Java exception - * (as an object of type Throwable) to an error page. - */ - public static final String EXCEPTION_ATTR = - "javax.servlet.error.exception"; - - - /** - * The request attribute under which we forward the request URI - * (as an object of type String) of the page on which an error occurred. - */ - public static final String EXCEPTION_PAGE_ATTR = - "javax.servlet.error.request_uri"; - - - /** - * The request attribute under which we forward a Java exception type - * (as an object of type Class) to an error page. - */ - public static final String EXCEPTION_TYPE_ATTR = - "javax.servlet.error.exception_type"; - - - /** - * The request attribute under which we forward an HTTP status message - * (as an object of type STring) to an error page. - */ - public static final String ERROR_MESSAGE_ATTR = - "javax.servlet.error.message"; - - - /** - * The request attribute under which the Invoker servlet will store - * the invoking servlet path, if it was used to execute a servlet - * indirectly instead of through a servlet mapping. - */ - public static final String INVOKED_ATTR = - "org.apache.catalina.INVOKED"; - - - /** - * The request attribute under which we expose the value of the - * <jsp-file> value associated with this servlet, - * if any. - */ - public static final String JSP_FILE_ATTR = - "org.apache.catalina.jsp_file"; - - - /** - * The request attribute under which we store the key size being used for - * this SSL connection (as an object of type java.lang.Integer). - */ - public static final String KEY_SIZE_ATTR = - "javax.servlet.request.key_size"; - - /** - * The request attribute under which we store the session id being used - * for this SSL connection (as an object of type java.lang.String). - */ - public static final String SSL_SESSION_ID_ATTR = - "javax.servlet.request.ssl_session"; - - - /** - * The servlet context attribute under which the managed bean Registry - * will be stored for privileged contexts (if enabled). - */ - public static final String MBEAN_REGISTRY_ATTR = - "org.apache.catalina.Registry"; - - - /** - * The servlet context attribute under which the MBeanServer will be stored - * for privileged contexts (if enabled). - */ - public static final String MBEAN_SERVER_ATTR = - "org.apache.catalina.MBeanServer"; - - - /** - * The request attribute under which we store the servlet name on a - * named dispatcher request. - */ - public static final String NAMED_DISPATCHER_ATTR = - "org.apache.catalina.NAMED"; - - - /** - * The request attribute under which the request URI of the included - * servlet is stored on an included dispatcher request. - */ - public static final String INCLUDE_REQUEST_URI_ATTR = - "javax.servlet.include.request_uri"; - - - /** - * The request attribute under which the context path of the included - * servlet is stored on an included dispatcher request. - */ - public static final String INCLUDE_CONTEXT_PATH_ATTR = - "javax.servlet.include.context_path"; - - - /** - * The request attribute under which the path info of the included - * servlet is stored on an included dispatcher request. - */ - public static final String INCLUDE_PATH_INFO_ATTR = - "javax.servlet.include.path_info"; - - - /** - * The request attribute under which the servlet path of the included - * servlet is stored on an included dispatcher request. - */ - public static final String INCLUDE_SERVLET_PATH_ATTR = - "javax.servlet.include.servlet_path"; - - - /** - * The request attribute under which the query string of the included - * servlet is stored on an included dispatcher request. - */ - public static final String INCLUDE_QUERY_STRING_ATTR = - "javax.servlet.include.query_string"; - - - /** - * The request attribute under which the original request URI is stored - * on an forwarded dispatcher request. - */ - public static final String FORWARD_REQUEST_URI_ATTR = - "javax.servlet.forward.request_uri"; - - - /** - * The request attribute under which the original context path is stored - * on an forwarded dispatcher request. - */ - public static final String FORWARD_CONTEXT_PATH_ATTR = - "javax.servlet.forward.context_path"; - - - /** - * The request attribute under which the original path info is stored - * on an forwarded dispatcher request. - */ - public static final String FORWARD_PATH_INFO_ATTR = - "javax.servlet.forward.path_info"; - - - /** - * The request attribute under which the original servlet path is stored - * on an forwarded dispatcher request. - */ - public static final String FORWARD_SERVLET_PATH_ATTR = - "javax.servlet.forward.servlet_path"; - - - /** - * The request attribute under which the original query string is stored - * on an forwarded dispatcher request. - */ - public static final String FORWARD_QUERY_STRING_ATTR = - "javax.servlet.forward.query_string"; - - - /** - * The request attribute under which we forward a servlet name to - * an error page. - */ - public static final String SERVLET_NAME_ATTR = - "javax.servlet.error.servlet_name"; - - - /** - * The name of the cookie used to pass the session identifier back - * and forth with the client. - */ - public static final String SESSION_COOKIE_NAME = "JSESSIONID"; - - - /** - * The name of the path parameter used to pass the session identifier - * back and forth with the client. - */ - public static final String SESSION_PARAMETER_NAME = "jsessionid"; - - - /** - * The servlet context attribute under which we store a flag used - * to mark this request as having been processed by the SSIServlet. - * We do this because of the pathInfo mangling happening when using - * the CGIServlet in conjunction with the SSI servlet. (value stored - * as an object of type String) - */ - public static final String SSI_FLAG_ATTR = - "org.apache.catalina.ssi.SSIServlet"; - - - /** - * The request attribute under which we forward an HTTP status code - * (as an object of type Integer) to an error page. - */ - public static final String STATUS_CODE_ATTR = - "javax.servlet.error.status_code"; - - - /** - * The subject under which the AccessControlContext is running. - */ - public static final String SUBJECT_ATTR = - "javax.security.auth.subject"; - - - /** - * The servlet context attribute under which we record the set of - * welcome files (as an object of type String[]) for this application. - */ - public static final String WELCOME_FILES_ATTR = - "org.apache.catalina.WELCOME_FILES"; - - - /** - * The servlet context attribute under which we store a temporary - * working directory (as an object of type File) for use by servlets - * within this web application. - */ - public static final String WORK_DIR_ATTR = - "javax.servlet.context.tempdir"; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * Global constants that are applicable to multiple packages within Catalina. + * + * @author Craig R. McClanahan + * @version $Revision: 303495 $ $Date: 2004-11-19 07:07:56 +0100 (ven., 19 nov. 2004) $ + */ + +public final class Globals { + + /** + * The servlet context attribute under which we store the alternate + * deployment descriptor for this web application + */ + public static final String ALT_DD_ATTR = + "org.apache.catalina.deploy.alt_dd"; + + /** + * The request attribute under which we store the array of X509Certificate + * objects representing the certificate chain presented by our client, + * if any. + */ + public static final String CERTIFICATES_ATTR = + "javax.servlet.request.X509Certificate"; + + /** + * The request attribute under which we store the name of the cipher suite + * being used on an SSL connection (as an object of type + * java.lang.String). + */ + public static final String CIPHER_SUITE_ATTR = + "javax.servlet.request.cipher_suite"; + + + /** + * The servlet context attribute under which we store the class loader + * used for loading servlets (as an object of type java.lang.ClassLoader). + */ + public static final String CLASS_LOADER_ATTR = + "org.apache.catalina.classloader"; + + /** + * Request dispatcher state. + */ + public static final String DISPATCHER_TYPE_ATTR = + "org.apache.catalina.core.DISPATCHER_TYPE"; + + /** + * Request dispatcher path. + */ + public static final String DISPATCHER_REQUEST_PATH_ATTR = + "org.apache.catalina.core.DISPATCHER_REQUEST_PATH"; + + /** + * The JNDI directory context which is associated with the context. This + * context can be used to manipulate static files. + */ + public static final String RESOURCES_ATTR = + "org.apache.catalina.resources"; + + + /** + * The servlet context attribute under which we store the class path + * for our application class loader (as an object of type String), + * delimited with the appropriate path delimiter for this platform. + */ + public static final String CLASS_PATH_ATTR = + "org.apache.catalina.jsp_classpath"; + + + /** + * The request attribute under which we forward a Java exception + * (as an object of type Throwable) to an error page. + */ + public static final String EXCEPTION_ATTR = + "javax.servlet.error.exception"; + + + /** + * The request attribute under which we forward the request URI + * (as an object of type String) of the page on which an error occurred. + */ + public static final String EXCEPTION_PAGE_ATTR = + "javax.servlet.error.request_uri"; + + + /** + * The request attribute under which we forward a Java exception type + * (as an object of type Class) to an error page. + */ + public static final String EXCEPTION_TYPE_ATTR = + "javax.servlet.error.exception_type"; + + + /** + * The request attribute under which we forward an HTTP status message + * (as an object of type STring) to an error page. + */ + public static final String ERROR_MESSAGE_ATTR = + "javax.servlet.error.message"; + + + /** + * The request attribute under which the Invoker servlet will store + * the invoking servlet path, if it was used to execute a servlet + * indirectly instead of through a servlet mapping. + */ + public static final String INVOKED_ATTR = + "org.apache.catalina.INVOKED"; + + + /** + * The request attribute under which we expose the value of the + * <jsp-file> value associated with this servlet, + * if any. + */ + public static final String JSP_FILE_ATTR = + "org.apache.catalina.jsp_file"; + + + /** + * The request attribute under which we store the key size being used for + * this SSL connection (as an object of type java.lang.Integer). + */ + public static final String KEY_SIZE_ATTR = + "javax.servlet.request.key_size"; + + /** + * The request attribute under which we store the session id being used + * for this SSL connection (as an object of type java.lang.String). + */ + public static final String SSL_SESSION_ID_ATTR = + "javax.servlet.request.ssl_session"; + + + /** + * The servlet context attribute under which the managed bean Registry + * will be stored for privileged contexts (if enabled). + */ + public static final String MBEAN_REGISTRY_ATTR = + "org.apache.catalina.Registry"; + + + /** + * The servlet context attribute under which the MBeanServer will be stored + * for privileged contexts (if enabled). + */ + public static final String MBEAN_SERVER_ATTR = + "org.apache.catalina.MBeanServer"; + + + /** + * The request attribute under which we store the servlet name on a + * named dispatcher request. + */ + public static final String NAMED_DISPATCHER_ATTR = + "org.apache.catalina.NAMED"; + + + /** + * The request attribute under which the request URI of the included + * servlet is stored on an included dispatcher request. + */ + public static final String INCLUDE_REQUEST_URI_ATTR = + "javax.servlet.include.request_uri"; + + + /** + * The request attribute under which the context path of the included + * servlet is stored on an included dispatcher request. + */ + public static final String INCLUDE_CONTEXT_PATH_ATTR = + "javax.servlet.include.context_path"; + + + /** + * The request attribute under which the path info of the included + * servlet is stored on an included dispatcher request. + */ + public static final String INCLUDE_PATH_INFO_ATTR = + "javax.servlet.include.path_info"; + + + /** + * The request attribute under which the servlet path of the included + * servlet is stored on an included dispatcher request. + */ + public static final String INCLUDE_SERVLET_PATH_ATTR = + "javax.servlet.include.servlet_path"; + + + /** + * The request attribute under which the query string of the included + * servlet is stored on an included dispatcher request. + */ + public static final String INCLUDE_QUERY_STRING_ATTR = + "javax.servlet.include.query_string"; + + + /** + * The request attribute under which the original request URI is stored + * on an forwarded dispatcher request. + */ + public static final String FORWARD_REQUEST_URI_ATTR = + "javax.servlet.forward.request_uri"; + + + /** + * The request attribute under which the original context path is stored + * on an forwarded dispatcher request. + */ + public static final String FORWARD_CONTEXT_PATH_ATTR = + "javax.servlet.forward.context_path"; + + + /** + * The request attribute under which the original path info is stored + * on an forwarded dispatcher request. + */ + public static final String FORWARD_PATH_INFO_ATTR = + "javax.servlet.forward.path_info"; + + + /** + * The request attribute under which the original servlet path is stored + * on an forwarded dispatcher request. + */ + public static final String FORWARD_SERVLET_PATH_ATTR = + "javax.servlet.forward.servlet_path"; + + + /** + * The request attribute under which the original query string is stored + * on an forwarded dispatcher request. + */ + public static final String FORWARD_QUERY_STRING_ATTR = + "javax.servlet.forward.query_string"; + + + /** + * The request attribute under which we forward a servlet name to + * an error page. + */ + public static final String SERVLET_NAME_ATTR = + "javax.servlet.error.servlet_name"; + + + /** + * The name of the cookie used to pass the session identifier back + * and forth with the client. + */ + public static final String SESSION_COOKIE_NAME = "JSESSIONID"; + + + /** + * The name of the path parameter used to pass the session identifier + * back and forth with the client. + */ + public static final String SESSION_PARAMETER_NAME = "jsessionid"; + + + /** + * The servlet context attribute under which we store a flag used + * to mark this request as having been processed by the SSIServlet. + * We do this because of the pathInfo mangling happening when using + * the CGIServlet in conjunction with the SSI servlet. (value stored + * as an object of type String) + */ + public static final String SSI_FLAG_ATTR = + "org.apache.catalina.ssi.SSIServlet"; + + + /** + * The request attribute under which we forward an HTTP status code + * (as an object of type Integer) to an error page. + */ + public static final String STATUS_CODE_ATTR = + "javax.servlet.error.status_code"; + + + /** + * The subject under which the AccessControlContext is running. + */ + public static final String SUBJECT_ATTR = + "javax.security.auth.subject"; + + + /** + * The servlet context attribute under which we record the set of + * welcome files (as an object of type String[]) for this application. + */ + public static final String WELCOME_FILES_ATTR = + "org.apache.catalina.WELCOME_FILES"; + + + /** + * The servlet context attribute under which we store a temporary + * working directory (as an object of type File) for use by servlets + * within this web application. + */ + public static final String WORK_DIR_ATTR = + "javax.servlet.context.tempdir"; + + +} diff --git a/java/org/apache/catalina/Group.java b/java/org/apache/catalina/Group.java index 7ed17807a..c22e3125e 100644 --- a/java/org/apache/catalina/Group.java +++ b/java/org/apache/catalina/Group.java @@ -1,122 +1,122 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.security.Principal; -import java.util.Iterator; - - -/** - *

Abstract representation of a group of {@link User}s in a - * {@link UserDatabase}. Each user that is a member of this group - * inherits the {@link Role}s assigned to the group.

- * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public interface Group extends Principal { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the description of this group. - */ - public String getDescription(); - - - /** - * Set the description of this group. - * - * @param description The new description - */ - public void setDescription(String description); - - - /** - * Return the group name of this group, which must be unique - * within the scope of a {@link UserDatabase}. - */ - public String getGroupname(); - - - /** - * Set the group name of this group, which must be unique - * within the scope of a {@link UserDatabase}. - * - * @param groupname The new group name - */ - public void setGroupname(String groupname); - - - /** - * Return the set of {@link Role}s assigned specifically to this group. - */ - public Iterator getRoles(); - - - /** - * Return the {@link UserDatabase} within which this Group is defined. - */ - public UserDatabase getUserDatabase(); - - - /** - * Return the set of {@link User}s that are members of this group. - */ - public Iterator getUsers(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Role} to those assigned specifically to this group. - * - * @param role The new role - */ - public void addRole(Role role); - - - /** - * Is this group specifically assigned the specified {@link Role}? - * - * @param role The role to check - */ - public boolean isInRole(Role role); - - - /** - * Remove a {@link Role} from those assigned to this group. - * - * @param role The old role - */ - public void removeRole(Role role); - - - /** - * Remove all {@link Role}s from those assigned to this group. - */ - public void removeRoles(); - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.security.Principal; +import java.util.Iterator; + + +/** + *

Abstract representation of a group of {@link User}s in a + * {@link UserDatabase}. Each user that is a member of this group + * inherits the {@link Role}s assigned to the group.

+ * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public interface Group extends Principal { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the description of this group. + */ + public String getDescription(); + + + /** + * Set the description of this group. + * + * @param description The new description + */ + public void setDescription(String description); + + + /** + * Return the group name of this group, which must be unique + * within the scope of a {@link UserDatabase}. + */ + public String getGroupname(); + + + /** + * Set the group name of this group, which must be unique + * within the scope of a {@link UserDatabase}. + * + * @param groupname The new group name + */ + public void setGroupname(String groupname); + + + /** + * Return the set of {@link Role}s assigned specifically to this group. + */ + public Iterator getRoles(); + + + /** + * Return the {@link UserDatabase} within which this Group is defined. + */ + public UserDatabase getUserDatabase(); + + + /** + * Return the set of {@link User}s that are members of this group. + */ + public Iterator getUsers(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Role} to those assigned specifically to this group. + * + * @param role The new role + */ + public void addRole(Role role); + + + /** + * Is this group specifically assigned the specified {@link Role}? + * + * @param role The role to check + */ + public boolean isInRole(Role role); + + + /** + * Remove a {@link Role} from those assigned to this group. + * + * @param role The old role + */ + public void removeRole(Role role); + + + /** + * Remove all {@link Role}s from those assigned to this group. + */ + public void removeRoles(); + + +} diff --git a/java/org/apache/catalina/Host.java b/java/org/apache/catalina/Host.java index ce831ffd4..fe78e4569 100644 --- a/java/org/apache/catalina/Host.java +++ b/java/org/apache/catalina/Host.java @@ -1,218 +1,218 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - - -/** - * A Host is a Container that represents a virtual host in the - * Catalina servlet engine. It is useful in the following types of scenarios: - *
    - *
  • You wish to use Interceptors that see every single request processed - * by this particular virtual host. - *
  • You wish to run Catalina in with a standalone HTTP connector, but still - * want support for multiple virtual hosts. - *
- * In general, you would not use a Host when deploying Catalina connected - * to a web server (such as Apache), because the Connector will have - * utilized the web server's facilities to determine which Context (or - * perhaps even which Wrapper) should be utilized to process this request. - *

- * The parent Container attached to a Host is generally an Engine, but may - * be some other implementation, or may be omitted if it is not necessary. - *

- * The child containers attached to a Host are generally implementations - * of Context (representing an individual servlet context). - * - * @author Craig R. McClanahan - * @version $Revision: 303092 $ $Date: 2004-08-16 11:31:09 +0200 (lun., 16 août 2004) $ - */ - -public interface Host extends Container { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The ContainerEvent event type sent when a new alias is added - * by addAlias(). - */ - public static final String ADD_ALIAS_EVENT = "addAlias"; - - - /** - * The ContainerEvent event type sent when an old alias is removed - * by removeAlias(). - */ - public static final String REMOVE_ALIAS_EVENT = "removeAlias"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the application root for this Host. This can be an absolute - * pathname, a relative pathname, or a URL. - */ - public String getAppBase(); - - - /** - * Set the application root for this Host. This can be an absolute - * pathname, a relative pathname, or a URL. - * - * @param appBase The new application root - */ - public void setAppBase(String appBase); - - - /** - * Return the value of the auto deploy flag. If true, it indicates that - * this host's child webapps should be discovred and automatically - * deployed dynamically. - */ - public boolean getAutoDeploy(); - - - /** - * Set the auto deploy flag value for this host. - * - * @param autoDeploy The new auto deploy flag - */ - public void setAutoDeploy(boolean autoDeploy); - - - /** - * Return the Java class name of the context configuration class - * for new web applications. - */ - public String getConfigClass(); - - - /** - * Set the Java class name of the context configuration class - * for new web applications. - * - * @param configClass The new context configuration class - */ - public void setConfigClass(String configClass); - - - /** - * Return the value of the deploy on startup flag. If true, it indicates - * that this host's child webapps should be discovred and automatically - * deployed. - */ - public boolean getDeployOnStartup(); - - - /** - * Set the deploy on startup flag value for this host. - * - * @param deployOnStartup The new deploy on startup flag - */ - public void setDeployOnStartup(boolean deployOnStartup); - - - /** - * Return the canonical, fully qualified, name of the virtual host - * this Container represents. - */ - public String getName(); - - - /** - * Set the canonical, fully qualified, name of the virtual host - * this Container represents. - * - * @param name Virtual host name - * - * @exception IllegalArgumentException if name is null - */ - public void setName(String name); - - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - * - */ - public boolean getXmlNamespaceAware(); - - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getXmlValidation(); - - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param xmlValidation true to enable xml instance validation - */ - public void setXmlValidation(boolean xmlValidation); - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param xmlNamespaceAware true to enable namespace awareness - */ - public void setXmlNamespaceAware(boolean xmlNamespaceAware); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an alias name that should be mapped to this same Host. - * - * @param alias The alias to be added - */ - public void addAlias(String alias); - - - /** - * Return the set of alias names for this Host. If none are defined, - * a zero length array is returned. - */ - public String[] findAliases(); - - - /** - * Return the Context that would be used to process the specified - * host-relative request URI, if any; otherwise return null. - * - * @param uri Request URI to be mapped - */ - public Context map(String uri); - - - /** - * Remove the specified alias name from the aliases for this Host. - * - * @param alias Alias name to be removed - */ - public void removeAlias(String alias); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + + +/** + * A Host is a Container that represents a virtual host in the + * Catalina servlet engine. It is useful in the following types of scenarios: + *

    + *
  • You wish to use Interceptors that see every single request processed + * by this particular virtual host. + *
  • You wish to run Catalina in with a standalone HTTP connector, but still + * want support for multiple virtual hosts. + *
+ * In general, you would not use a Host when deploying Catalina connected + * to a web server (such as Apache), because the Connector will have + * utilized the web server's facilities to determine which Context (or + * perhaps even which Wrapper) should be utilized to process this request. + *

+ * The parent Container attached to a Host is generally an Engine, but may + * be some other implementation, or may be omitted if it is not necessary. + *

+ * The child containers attached to a Host are generally implementations + * of Context (representing an individual servlet context). + * + * @author Craig R. McClanahan + * @version $Revision: 303092 $ $Date: 2004-08-16 11:31:09 +0200 (lun., 16 août 2004) $ + */ + +public interface Host extends Container { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The ContainerEvent event type sent when a new alias is added + * by addAlias(). + */ + public static final String ADD_ALIAS_EVENT = "addAlias"; + + + /** + * The ContainerEvent event type sent when an old alias is removed + * by removeAlias(). + */ + public static final String REMOVE_ALIAS_EVENT = "removeAlias"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the application root for this Host. This can be an absolute + * pathname, a relative pathname, or a URL. + */ + public String getAppBase(); + + + /** + * Set the application root for this Host. This can be an absolute + * pathname, a relative pathname, or a URL. + * + * @param appBase The new application root + */ + public void setAppBase(String appBase); + + + /** + * Return the value of the auto deploy flag. If true, it indicates that + * this host's child webapps should be discovred and automatically + * deployed dynamically. + */ + public boolean getAutoDeploy(); + + + /** + * Set the auto deploy flag value for this host. + * + * @param autoDeploy The new auto deploy flag + */ + public void setAutoDeploy(boolean autoDeploy); + + + /** + * Return the Java class name of the context configuration class + * for new web applications. + */ + public String getConfigClass(); + + + /** + * Set the Java class name of the context configuration class + * for new web applications. + * + * @param configClass The new context configuration class + */ + public void setConfigClass(String configClass); + + + /** + * Return the value of the deploy on startup flag. If true, it indicates + * that this host's child webapps should be discovred and automatically + * deployed. + */ + public boolean getDeployOnStartup(); + + + /** + * Set the deploy on startup flag value for this host. + * + * @param deployOnStartup The new deploy on startup flag + */ + public void setDeployOnStartup(boolean deployOnStartup); + + + /** + * Return the canonical, fully qualified, name of the virtual host + * this Container represents. + */ + public String getName(); + + + /** + * Set the canonical, fully qualified, name of the virtual host + * this Container represents. + * + * @param name Virtual host name + * + * @exception IllegalArgumentException if name is null + */ + public void setName(String name); + + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + * + */ + public boolean getXmlNamespaceAware(); + + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getXmlValidation(); + + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param xmlValidation true to enable xml instance validation + */ + public void setXmlValidation(boolean xmlValidation); + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param xmlNamespaceAware true to enable namespace awareness + */ + public void setXmlNamespaceAware(boolean xmlNamespaceAware); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an alias name that should be mapped to this same Host. + * + * @param alias The alias to be added + */ + public void addAlias(String alias); + + + /** + * Return the set of alias names for this Host. If none are defined, + * a zero length array is returned. + */ + public String[] findAliases(); + + + /** + * Return the Context that would be used to process the specified + * host-relative request URI, if any; otherwise return null. + * + * @param uri Request URI to be mapped + */ + public Context map(String uri); + + + /** + * Remove the specified alias name from the aliases for this Host. + * + * @param alias Alias name to be removed + */ + public void removeAlias(String alias); + + +} diff --git a/java/org/apache/catalina/InstanceEvent.java b/java/org/apache/catalina/InstanceEvent.java index 5898a3168..541ec7cbc 100644 --- a/java/org/apache/catalina/InstanceEvent.java +++ b/java/org/apache/catalina/InstanceEvent.java @@ -1,448 +1,448 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.util.EventObject; -import javax.servlet.Filter; -import javax.servlet.Servlet; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - - -/** - * General event for notifying listeners of significant events related to - * a specific instance of a Servlet, or a specific instance of a Filter, - * as opposed to the Wrapper component that manages it. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class InstanceEvent - extends EventObject { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The event indicating that the init() method is about - * to be called for this instance. - */ - public static final String BEFORE_INIT_EVENT = "beforeInit"; - - - /** - * The event indicating that the init() method has returned. - */ - public static final String AFTER_INIT_EVENT = "afterInit"; - - - /** - * The event indicating that the service() method is about - * to be called on a servlet. The servlet property contains - * the servlet being called, and the request and - * response properties contain the current request and - * response being processed. - */ - public static final String BEFORE_SERVICE_EVENT = "beforeService"; - - - /** - * The event indicating that the service() method has - * returned. The servlet property contains the servlet - * that was called, and the request and - * response properties contain the current request and - * response being processed. - */ - public static final String AFTER_SERVICE_EVENT = "afterService"; - - - /** - * The event indicating that the destroy method is about - * to be called for this instance. - */ - public static final String BEFORE_DESTROY_EVENT = "beforeDestroy"; - - - /** - * The event indicating that the destroy() method has - * returned. - */ - public static final String AFTER_DESTROY_EVENT = "afterDestroy"; - - - /** - * The event indicating that the service() method of a - * servlet accessed via a request dispatcher is about to be called. - * The servlet property contains a reference to the - * dispatched-to servlet instance, and the request and - * response properties contain the current request and - * response being processed. The wrapper property will - * contain a reference to the dispatched-to Wrapper. - */ - public static final String BEFORE_DISPATCH_EVENT = "beforeDispatch"; - - - /** - * The event indicating that the service() method of a - * servlet accessed via a request dispatcher has returned. The - * servlet property contains a reference to the - * dispatched-to servlet instance, and the request and - * response properties contain the current request and - * response being processed. The wrapper property will - * contain a reference to the dispatched-to Wrapper. - */ - public static final String AFTER_DISPATCH_EVENT = "afterDispatch"; - - - /** - * The event indicating that the doFilter() method of a - * Filter is about to be called. The filter property - * contains a reference to the relevant filter instance, and the - * request and response properties contain - * the current request and response being processed. - */ - public static final String BEFORE_FILTER_EVENT = "beforeFilter"; - - - /** - * The event indicating that the doFilter() method of a - * Filter has returned. The filter property contains - * a reference to the relevant filter instance, and the - * request and response properties contain - * the current request and response being processed. - */ - public static final String AFTER_FILTER_EVENT = "afterFilter"; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for filter lifecycle events. - * - * @param wrapper Wrapper managing this servlet instance - * @param filter Filter instance for which this event occurred - * @param type Event type (required) - */ - public InstanceEvent(Wrapper wrapper, Filter filter, String type) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = filter; - this.servlet = null; - this.type = type; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for filter lifecycle events. - * - * @param wrapper Wrapper managing this servlet instance - * @param filter Filter instance for which this event occurred - * @param type Event type (required) - * @param exception Exception that occurred - */ - public InstanceEvent(Wrapper wrapper, Filter filter, String type, - Throwable exception) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = filter; - this.servlet = null; - this.type = type; - this.exception = exception; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for filter processing events. - * - * @param wrapper Wrapper managing this servlet instance - * @param filter Filter instance for which this event occurred - * @param type Event type (required) - * @param request Servlet request we are processing - * @param response Servlet response we are processing - */ - public InstanceEvent(Wrapper wrapper, Filter filter, String type, - ServletRequest request, ServletResponse response) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = filter; - this.servlet = null; - this.type = type; - this.request = request; - this.response = response; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for filter processing events. - * - * @param wrapper Wrapper managing this servlet instance - * @param filter Filter instance for which this event occurred - * @param type Event type (required) - * @param request Servlet request we are processing - * @param response Servlet response we are processing - * @param exception Exception that occurred - */ - public InstanceEvent(Wrapper wrapper, Filter filter, String type, - ServletRequest request, ServletResponse response, - Throwable exception) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = filter; - this.servlet = null; - this.type = type; - this.request = request; - this.response = response; - this.exception = exception; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for processing servlet lifecycle events. - * - * @param wrapper Wrapper managing this servlet instance - * @param servlet Servlet instance for which this event occurred - * @param type Event type (required) - */ - public InstanceEvent(Wrapper wrapper, Servlet servlet, String type) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = null; - this.servlet = servlet; - this.type = type; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for processing servlet lifecycle events. - * - * @param wrapper Wrapper managing this servlet instance - * @param servlet Servlet instance for which this event occurred - * @param type Event type (required) - * @param exception Exception that occurred - */ - public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, - Throwable exception) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = null; - this.servlet = servlet; - this.type = type; - this.exception = exception; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for processing servlet processing events. - * - * @param wrapper Wrapper managing this servlet instance - * @param servlet Servlet instance for which this event occurred - * @param type Event type (required) - * @param request Servlet request we are processing - * @param response Servlet response we are processing - */ - public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, - ServletRequest request, ServletResponse response) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = null; - this.servlet = servlet; - this.type = type; - this.request = request; - this.response = response; - - } - - - /** - * Construct a new InstanceEvent with the specified parameters. This - * constructor is used for processing servlet processing events. - * - * @param wrapper Wrapper managing this servlet instance - * @param servlet Servlet instance for which this event occurred - * @param type Event type (required) - * @param request Servlet request we are processing - * @param response Servlet response we are processing - * @param exception Exception that occurred - */ - public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, - ServletRequest request, ServletResponse response, - Throwable exception) { - - super(wrapper); - this.wrapper = wrapper; - this.filter = null; - this.servlet = servlet; - this.type = type; - this.request = request; - this.response = response; - this.exception = exception; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The exception that was thrown during the processing being reported - * by this event (AFTER_INIT_EVENT, AFTER_SERVICE_EVENT, - * AFTER_DESTROY_EVENT, AFTER_DISPATCH_EVENT, and AFTER_FILTER_EVENT only). - */ - private Throwable exception = null; - - - /** - * The Filter instance for which this event occurred (BEFORE_FILTER_EVENT - * and AFTER_FILTER_EVENT only). - */ - private Filter filter = null; - - - /** - * The servlet request being processed (BEFORE_FILTER_EVENT, - * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). - */ - private ServletRequest request = null; - - - /** - * The servlet response being processed (BEFORE_FILTER_EVENT, - * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). - */ - private ServletResponse response = null; - - - /** - * The Servlet instance for which this event occurred (not present on - * BEFORE_FILTER_EVENT or AFTER_FILTER_EVENT events). - */ - private Servlet servlet = null; - - - /** - * The event type this instance represents. - */ - private String type = null; - - - /** - * The Wrapper managing the servlet instance for which this event occurred. - */ - private Wrapper wrapper = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the exception that occurred during the processing - * that was reported by this event. - */ - public Throwable getException() { - - return (this.exception); - - } - - - /** - * Return the filter instance for which this event occurred. - */ - public Filter getFilter() { - - return (this.filter); - - } - - - /** - * Return the servlet request for which this event occurred. - */ - public ServletRequest getRequest() { - - return (this.request); - - } - - - /** - * Return the servlet response for which this event occurred. - */ - public ServletResponse getResponse() { - - return (this.response); - - } - - - /** - * Return the servlet instance for which this event occurred. - */ - public Servlet getServlet() { - - return (this.servlet); - - } - - - /** - * Return the event type of this event. - */ - public String getType() { - - return (this.type); - - } - - - /** - * Return the Wrapper managing the servlet instance for which this - * event occurred. - */ - public Wrapper getWrapper() { - - return (this.wrapper); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.util.EventObject; +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + + +/** + * General event for notifying listeners of significant events related to + * a specific instance of a Servlet, or a specific instance of a Filter, + * as opposed to the Wrapper component that manages it. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class InstanceEvent + extends EventObject { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The event indicating that the init() method is about + * to be called for this instance. + */ + public static final String BEFORE_INIT_EVENT = "beforeInit"; + + + /** + * The event indicating that the init() method has returned. + */ + public static final String AFTER_INIT_EVENT = "afterInit"; + + + /** + * The event indicating that the service() method is about + * to be called on a servlet. The servlet property contains + * the servlet being called, and the request and + * response properties contain the current request and + * response being processed. + */ + public static final String BEFORE_SERVICE_EVENT = "beforeService"; + + + /** + * The event indicating that the service() method has + * returned. The servlet property contains the servlet + * that was called, and the request and + * response properties contain the current request and + * response being processed. + */ + public static final String AFTER_SERVICE_EVENT = "afterService"; + + + /** + * The event indicating that the destroy method is about + * to be called for this instance. + */ + public static final String BEFORE_DESTROY_EVENT = "beforeDestroy"; + + + /** + * The event indicating that the destroy() method has + * returned. + */ + public static final String AFTER_DESTROY_EVENT = "afterDestroy"; + + + /** + * The event indicating that the service() method of a + * servlet accessed via a request dispatcher is about to be called. + * The servlet property contains a reference to the + * dispatched-to servlet instance, and the request and + * response properties contain the current request and + * response being processed. The wrapper property will + * contain a reference to the dispatched-to Wrapper. + */ + public static final String BEFORE_DISPATCH_EVENT = "beforeDispatch"; + + + /** + * The event indicating that the service() method of a + * servlet accessed via a request dispatcher has returned. The + * servlet property contains a reference to the + * dispatched-to servlet instance, and the request and + * response properties contain the current request and + * response being processed. The wrapper property will + * contain a reference to the dispatched-to Wrapper. + */ + public static final String AFTER_DISPATCH_EVENT = "afterDispatch"; + + + /** + * The event indicating that the doFilter() method of a + * Filter is about to be called. The filter property + * contains a reference to the relevant filter instance, and the + * request and response properties contain + * the current request and response being processed. + */ + public static final String BEFORE_FILTER_EVENT = "beforeFilter"; + + + /** + * The event indicating that the doFilter() method of a + * Filter has returned. The filter property contains + * a reference to the relevant filter instance, and the + * request and response properties contain + * the current request and response being processed. + */ + public static final String AFTER_FILTER_EVENT = "afterFilter"; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for filter lifecycle events. + * + * @param wrapper Wrapper managing this servlet instance + * @param filter Filter instance for which this event occurred + * @param type Event type (required) + */ + public InstanceEvent(Wrapper wrapper, Filter filter, String type) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = filter; + this.servlet = null; + this.type = type; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for filter lifecycle events. + * + * @param wrapper Wrapper managing this servlet instance + * @param filter Filter instance for which this event occurred + * @param type Event type (required) + * @param exception Exception that occurred + */ + public InstanceEvent(Wrapper wrapper, Filter filter, String type, + Throwable exception) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = filter; + this.servlet = null; + this.type = type; + this.exception = exception; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for filter processing events. + * + * @param wrapper Wrapper managing this servlet instance + * @param filter Filter instance for which this event occurred + * @param type Event type (required) + * @param request Servlet request we are processing + * @param response Servlet response we are processing + */ + public InstanceEvent(Wrapper wrapper, Filter filter, String type, + ServletRequest request, ServletResponse response) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = filter; + this.servlet = null; + this.type = type; + this.request = request; + this.response = response; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for filter processing events. + * + * @param wrapper Wrapper managing this servlet instance + * @param filter Filter instance for which this event occurred + * @param type Event type (required) + * @param request Servlet request we are processing + * @param response Servlet response we are processing + * @param exception Exception that occurred + */ + public InstanceEvent(Wrapper wrapper, Filter filter, String type, + ServletRequest request, ServletResponse response, + Throwable exception) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = filter; + this.servlet = null; + this.type = type; + this.request = request; + this.response = response; + this.exception = exception; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for processing servlet lifecycle events. + * + * @param wrapper Wrapper managing this servlet instance + * @param servlet Servlet instance for which this event occurred + * @param type Event type (required) + */ + public InstanceEvent(Wrapper wrapper, Servlet servlet, String type) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = null; + this.servlet = servlet; + this.type = type; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for processing servlet lifecycle events. + * + * @param wrapper Wrapper managing this servlet instance + * @param servlet Servlet instance for which this event occurred + * @param type Event type (required) + * @param exception Exception that occurred + */ + public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, + Throwable exception) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = null; + this.servlet = servlet; + this.type = type; + this.exception = exception; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for processing servlet processing events. + * + * @param wrapper Wrapper managing this servlet instance + * @param servlet Servlet instance for which this event occurred + * @param type Event type (required) + * @param request Servlet request we are processing + * @param response Servlet response we are processing + */ + public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, + ServletRequest request, ServletResponse response) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = null; + this.servlet = servlet; + this.type = type; + this.request = request; + this.response = response; + + } + + + /** + * Construct a new InstanceEvent with the specified parameters. This + * constructor is used for processing servlet processing events. + * + * @param wrapper Wrapper managing this servlet instance + * @param servlet Servlet instance for which this event occurred + * @param type Event type (required) + * @param request Servlet request we are processing + * @param response Servlet response we are processing + * @param exception Exception that occurred + */ + public InstanceEvent(Wrapper wrapper, Servlet servlet, String type, + ServletRequest request, ServletResponse response, + Throwable exception) { + + super(wrapper); + this.wrapper = wrapper; + this.filter = null; + this.servlet = servlet; + this.type = type; + this.request = request; + this.response = response; + this.exception = exception; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The exception that was thrown during the processing being reported + * by this event (AFTER_INIT_EVENT, AFTER_SERVICE_EVENT, + * AFTER_DESTROY_EVENT, AFTER_DISPATCH_EVENT, and AFTER_FILTER_EVENT only). + */ + private Throwable exception = null; + + + /** + * The Filter instance for which this event occurred (BEFORE_FILTER_EVENT + * and AFTER_FILTER_EVENT only). + */ + private Filter filter = null; + + + /** + * The servlet request being processed (BEFORE_FILTER_EVENT, + * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). + */ + private ServletRequest request = null; + + + /** + * The servlet response being processed (BEFORE_FILTER_EVENT, + * AFTER_FILTER_EVENT, BEFORE_SERVICE_EVENT, and AFTER_SERVICE_EVENT). + */ + private ServletResponse response = null; + + + /** + * The Servlet instance for which this event occurred (not present on + * BEFORE_FILTER_EVENT or AFTER_FILTER_EVENT events). + */ + private Servlet servlet = null; + + + /** + * The event type this instance represents. + */ + private String type = null; + + + /** + * The Wrapper managing the servlet instance for which this event occurred. + */ + private Wrapper wrapper = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the exception that occurred during the processing + * that was reported by this event. + */ + public Throwable getException() { + + return (this.exception); + + } + + + /** + * Return the filter instance for which this event occurred. + */ + public Filter getFilter() { + + return (this.filter); + + } + + + /** + * Return the servlet request for which this event occurred. + */ + public ServletRequest getRequest() { + + return (this.request); + + } + + + /** + * Return the servlet response for which this event occurred. + */ + public ServletResponse getResponse() { + + return (this.response); + + } + + + /** + * Return the servlet instance for which this event occurred. + */ + public Servlet getServlet() { + + return (this.servlet); + + } + + + /** + * Return the event type of this event. + */ + public String getType() { + + return (this.type); + + } + + + /** + * Return the Wrapper managing the servlet instance for which this + * event occurred. + */ + public Wrapper getWrapper() { + + return (this.wrapper); + + } + + +} diff --git a/java/org/apache/catalina/InstanceListener.java b/java/org/apache/catalina/InstanceListener.java index 7de8b1d94..1b1550750 100644 --- a/java/org/apache/catalina/InstanceListener.java +++ b/java/org/apache/catalina/InstanceListener.java @@ -1,41 +1,41 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * Interface defining a listener for significant events related to a - * specific servlet instance, rather than to the Wrapper component that - * is managing that instance. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface InstanceListener { - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event InstanceEvent that has occurred - */ - public void instanceEvent(InstanceEvent event); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * Interface defining a listener for significant events related to a + * specific servlet instance, rather than to the Wrapper component that + * is managing that instance. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface InstanceListener { + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event InstanceEvent that has occurred + */ + public void instanceEvent(InstanceEvent event); + + +} diff --git a/java/org/apache/catalina/Lifecycle.java b/java/org/apache/catalina/Lifecycle.java index f5d40d70a..19750bf75 100644 --- a/java/org/apache/catalina/Lifecycle.java +++ b/java/org/apache/catalina/Lifecycle.java @@ -1,141 +1,141 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * Common interface for component life cycle methods. Catalina components - * may, but are not required to, implement this interface (as well as the - * appropriate interface(s) for the functionality they support) in order to - * provide a consistent mechanism to start and stop the component. - * - * @author Craig R. McClanahan - * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ - */ - -public interface Lifecycle { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The LifecycleEvent type for the "component init" event. - */ - public static final String INIT_EVENT = "init"; - - - /** - * The LifecycleEvent type for the "component start" event. - */ - public static final String START_EVENT = "start"; - - - /** - * The LifecycleEvent type for the "component before start" event. - */ - public static final String BEFORE_START_EVENT = "before_start"; - - - /** - * The LifecycleEvent type for the "component after start" event. - */ - public static final String AFTER_START_EVENT = "after_start"; - - - /** - * The LifecycleEvent type for the "component stop" event. - */ - public static final String STOP_EVENT = "stop"; - - - /** - * The LifecycleEvent type for the "component before stop" event. - */ - public static final String BEFORE_STOP_EVENT = "before_stop"; - - - /** - * The LifecycleEvent type for the "component after stop" event. - */ - public static final String AFTER_STOP_EVENT = "after_stop"; - - - /** - * The LifecycleEvent type for the "component destroy" event. - */ - public static final String DESTROY_EVENT = "destroy"; - - - /** - * The LifecycleEvent type for the "periodic" event. - */ - public static final String PERIODIC_EVENT = "periodic"; - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a LifecycleEvent listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener); - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners(); - - - /** - * Remove a LifecycleEvent listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener); - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called before any of the public - * methods of this component are utilized. It should also send a - * LifecycleEvent of type START_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException; - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. It should also send a LifecycleEvent - * of type STOP_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * Common interface for component life cycle methods. Catalina components + * may, but are not required to, implement this interface (as well as the + * appropriate interface(s) for the functionality they support) in order to + * provide a consistent mechanism to start and stop the component. + * + * @author Craig R. McClanahan + * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ + */ + +public interface Lifecycle { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The LifecycleEvent type for the "component init" event. + */ + public static final String INIT_EVENT = "init"; + + + /** + * The LifecycleEvent type for the "component start" event. + */ + public static final String START_EVENT = "start"; + + + /** + * The LifecycleEvent type for the "component before start" event. + */ + public static final String BEFORE_START_EVENT = "before_start"; + + + /** + * The LifecycleEvent type for the "component after start" event. + */ + public static final String AFTER_START_EVENT = "after_start"; + + + /** + * The LifecycleEvent type for the "component stop" event. + */ + public static final String STOP_EVENT = "stop"; + + + /** + * The LifecycleEvent type for the "component before stop" event. + */ + public static final String BEFORE_STOP_EVENT = "before_stop"; + + + /** + * The LifecycleEvent type for the "component after stop" event. + */ + public static final String AFTER_STOP_EVENT = "after_stop"; + + + /** + * The LifecycleEvent type for the "component destroy" event. + */ + public static final String DESTROY_EVENT = "destroy"; + + + /** + * The LifecycleEvent type for the "periodic" event. + */ + public static final String PERIODIC_EVENT = "periodic"; + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a LifecycleEvent listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener); + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners(); + + + /** + * Remove a LifecycleEvent listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener); + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called before any of the public + * methods of this component are utilized. It should also send a + * LifecycleEvent of type START_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException; + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. It should also send a LifecycleEvent + * of type STOP_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException; + + +} diff --git a/java/org/apache/catalina/LifecycleEvent.java b/java/org/apache/catalina/LifecycleEvent.java index 241586437..4b921ea0b 100644 --- a/java/org/apache/catalina/LifecycleEvent.java +++ b/java/org/apache/catalina/LifecycleEvent.java @@ -1,125 +1,125 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.util.EventObject; - - -/** - * General event for notifying listeners of significant changes on a component - * that implements the Lifecycle interface. In particular, this will be useful - * on Containers, where these events replace the ContextInterceptor concept in - * Tomcat 3.x. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class LifecycleEvent - extends EventObject { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new LifecycleEvent with the specified parameters. - * - * @param lifecycle Component on which this event occurred - * @param type Event type (required) - */ - public LifecycleEvent(Lifecycle lifecycle, String type) { - - this(lifecycle, type, null); - - } - - - /** - * Construct a new LifecycleEvent with the specified parameters. - * - * @param lifecycle Component on which this event occurred - * @param type Event type (required) - * @param data Event data (if any) - */ - public LifecycleEvent(Lifecycle lifecycle, String type, Object data) { - - super(lifecycle); - this.lifecycle = lifecycle; - this.type = type; - this.data = data; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The event data associated with this event. - */ - private Object data = null; - - - /** - * The Lifecycle on which this event occurred. - */ - private Lifecycle lifecycle = null; - - - /** - * The event type this instance represents. - */ - private String type = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the event data of this event. - */ - public Object getData() { - - return (this.data); - - } - - - /** - * Return the Lifecycle on which this event occurred. - */ - public Lifecycle getLifecycle() { - - return (this.lifecycle); - - } - - - /** - * Return the event type of this event. - */ - public String getType() { - - return (this.type); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.util.EventObject; + + +/** + * General event for notifying listeners of significant changes on a component + * that implements the Lifecycle interface. In particular, this will be useful + * on Containers, where these events replace the ContextInterceptor concept in + * Tomcat 3.x. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class LifecycleEvent + extends EventObject { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new LifecycleEvent with the specified parameters. + * + * @param lifecycle Component on which this event occurred + * @param type Event type (required) + */ + public LifecycleEvent(Lifecycle lifecycle, String type) { + + this(lifecycle, type, null); + + } + + + /** + * Construct a new LifecycleEvent with the specified parameters. + * + * @param lifecycle Component on which this event occurred + * @param type Event type (required) + * @param data Event data (if any) + */ + public LifecycleEvent(Lifecycle lifecycle, String type, Object data) { + + super(lifecycle); + this.lifecycle = lifecycle; + this.type = type; + this.data = data; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The event data associated with this event. + */ + private Object data = null; + + + /** + * The Lifecycle on which this event occurred. + */ + private Lifecycle lifecycle = null; + + + /** + * The event type this instance represents. + */ + private String type = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the event data of this event. + */ + public Object getData() { + + return (this.data); + + } + + + /** + * Return the Lifecycle on which this event occurred. + */ + public Lifecycle getLifecycle() { + + return (this.lifecycle); + + } + + + /** + * Return the event type of this event. + */ + public String getType() { + + return (this.type); + + } + + +} diff --git a/java/org/apache/catalina/LifecycleException.java b/java/org/apache/catalina/LifecycleException.java index f1883841d..e03d5602f 100644 --- a/java/org/apache/catalina/LifecycleException.java +++ b/java/org/apache/catalina/LifecycleException.java @@ -1,144 +1,144 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - * General purpose exception that is thrown to indicate a lifecycle related - * problem. Such exceptions should generally be considered fatal to the - * operation of the application containing this component. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class LifecycleException extends Exception { - - - //------------------------------------------------------------ Constructors - - - /** - * Construct a new LifecycleException with no other information. - */ - public LifecycleException() { - - this(null, null); - - } - - - /** - * Construct a new LifecycleException for the specified message. - * - * @param message Message describing this exception - */ - public LifecycleException(String message) { - - this(message, null); - - } - - - /** - * Construct a new LifecycleException for the specified throwable. - * - * @param throwable Throwable that caused this exception - */ - public LifecycleException(Throwable throwable) { - - this(null, throwable); - - } - - - /** - * Construct a new LifecycleException for the specified message - * and throwable. - * - * @param message Message describing this exception - * @param throwable Throwable that caused this exception - */ - public LifecycleException(String message, Throwable throwable) { - - super(); - this.message = message; - this.throwable = throwable; - - } - - - //------------------------------------------------------ Instance Variables - - - /** - * The error message passed to our constructor (if any) - */ - protected String message = null; - - - /** - * The underlying exception or error passed to our constructor (if any) - */ - protected Throwable throwable = null; - - - //---------------------------------------------------------- Public Methods - - - /** - * Returns the message associated with this exception, if any. - */ - public String getMessage() { - - return (message); - - } - - - /** - * Returns the throwable that caused this exception, if any. - */ - public Throwable getThrowable() { - - return (throwable); - - } - - - /** - * Return a formatted string that describes this exception. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("LifecycleException: "); - if (message != null) { - sb.append(message); - if (throwable != null) { - sb.append(": "); - } - } - if (throwable != null) { - sb.append(throwable.toString()); - } - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + * General purpose exception that is thrown to indicate a lifecycle related + * problem. Such exceptions should generally be considered fatal to the + * operation of the application containing this component. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class LifecycleException extends Exception { + + + //------------------------------------------------------------ Constructors + + + /** + * Construct a new LifecycleException with no other information. + */ + public LifecycleException() { + + this(null, null); + + } + + + /** + * Construct a new LifecycleException for the specified message. + * + * @param message Message describing this exception + */ + public LifecycleException(String message) { + + this(message, null); + + } + + + /** + * Construct a new LifecycleException for the specified throwable. + * + * @param throwable Throwable that caused this exception + */ + public LifecycleException(Throwable throwable) { + + this(null, throwable); + + } + + + /** + * Construct a new LifecycleException for the specified message + * and throwable. + * + * @param message Message describing this exception + * @param throwable Throwable that caused this exception + */ + public LifecycleException(String message, Throwable throwable) { + + super(); + this.message = message; + this.throwable = throwable; + + } + + + //------------------------------------------------------ Instance Variables + + + /** + * The error message passed to our constructor (if any) + */ + protected String message = null; + + + /** + * The underlying exception or error passed to our constructor (if any) + */ + protected Throwable throwable = null; + + + //---------------------------------------------------------- Public Methods + + + /** + * Returns the message associated with this exception, if any. + */ + public String getMessage() { + + return (message); + + } + + + /** + * Returns the throwable that caused this exception, if any. + */ + public Throwable getThrowable() { + + return (throwable); + + } + + + /** + * Return a formatted string that describes this exception. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("LifecycleException: "); + if (message != null) { + sb.append(message); + if (throwable != null) { + sb.append(": "); + } + } + if (throwable != null) { + sb.append(throwable.toString()); + } + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/LifecycleListener.java b/java/org/apache/catalina/LifecycleListener.java index 1fb8237e0..5fd32380b 100644 --- a/java/org/apache/catalina/LifecycleListener.java +++ b/java/org/apache/catalina/LifecycleListener.java @@ -1,43 +1,43 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - - - -/** - * Interface defining a listener for significant events (including "component - * start" and "component stop" generated by a component that implements the - * Lifecycle interface. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface LifecycleListener { - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event LifecycleEvent that has occurred - */ - public void lifecycleEvent(LifecycleEvent event); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + + + +/** + * Interface defining a listener for significant events (including "component + * start" and "component stop" generated by a component that implements the + * Lifecycle interface. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface LifecycleListener { + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event LifecycleEvent that has occurred + */ + public void lifecycleEvent(LifecycleEvent event); + + +} diff --git a/java/org/apache/catalina/Loader.java b/java/org/apache/catalina/Loader.java index 216f51d23..b075e0a0d 100644 --- a/java/org/apache/catalina/Loader.java +++ b/java/org/apache/catalina/Loader.java @@ -1,168 +1,168 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.beans.PropertyChangeListener; - - -/** - * A Loader represents a Java ClassLoader implementation that can - * be used by a Container to load class files (within a repository associated - * with the Loader) that are designed to be reloaded upon request, as well as - * a mechanism to detect whether changes have occurred in the underlying - * repository. - *

- * In order for a Loader implementation to successfully operate - * with a Context implementation that implements reloading, it - * must obey the following constraints: - *

    - *
  • Must implement Lifecycle so that the Context can indicate - * that a new class loader is required. - *
  • The start() method must unconditionally create a new - * ClassLoader implementation. - *
  • The stop() method must throw away its reference to the - * ClassLoader previously utilized, so that the class loader, - * all classes loaded by it, and all objects of those classes, can be - * garbage collected. - *
  • Must allow a call to stop() to be followed by a call to - * start() on the same Loader instance. - *
  • Based on a policy chosen by the implementation, must call the - * Context.reload() method on the owning Context - * when a change to one or more of the class files loaded by this class - * loader is detected. - *
- * - * @author Craig R. McClanahan - * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ - */ - -public interface Loader { - - - // ------------------------------------------------------------- Properties - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess(); - - - /** - * Return the Java class loader to be used by this Container. - */ - public ClassLoader getClassLoader(); - - - /** - * Return the Container with which this Loader has been associated. - */ - public Container getContainer(); - - - /** - * Set the Container with which this Loader has been associated. - * - * @param container The associated Container - */ - public void setContainer(Container container); - - - /** - * Return the "follow standard delegation model" flag used to configure - * our ClassLoader. - */ - public boolean getDelegate(); - - - /** - * Set the "follow standard delegation model" flag used to configure - * our ClassLoader. - * - * @param delegate The new flag - */ - public void setDelegate(boolean delegate); - - - /** - * Return descriptive information about this Loader implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the reloadable flag for this Loader. - */ - public boolean getReloadable(); - - - /** - * Set the reloadable flag for this Loader. - * - * @param reloadable The new reloadable flag - */ - public void setReloadable(boolean reloadable); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener); - - - /** - * Add a new repository to the set of repositories for this class loader. - * - * @param repository Repository to be added - */ - public void addRepository(String repository); - - - /** - * Return the set of repositories defined for this class loader. - * If none are defined, a zero-length array is returned. - */ - public String[] findRepositories(); - - - /** - * Has the internal repository associated with this Loader been modified, - * such that the loaded classes should be reloaded? - */ - public boolean modified(); - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.beans.PropertyChangeListener; + + +/** + * A Loader represents a Java ClassLoader implementation that can + * be used by a Container to load class files (within a repository associated + * with the Loader) that are designed to be reloaded upon request, as well as + * a mechanism to detect whether changes have occurred in the underlying + * repository. + *

+ * In order for a Loader implementation to successfully operate + * with a Context implementation that implements reloading, it + * must obey the following constraints: + *

    + *
  • Must implement Lifecycle so that the Context can indicate + * that a new class loader is required. + *
  • The start() method must unconditionally create a new + * ClassLoader implementation. + *
  • The stop() method must throw away its reference to the + * ClassLoader previously utilized, so that the class loader, + * all classes loaded by it, and all objects of those classes, can be + * garbage collected. + *
  • Must allow a call to stop() to be followed by a call to + * start() on the same Loader instance. + *
  • Based on a policy chosen by the implementation, must call the + * Context.reload() method on the owning Context + * when a change to one or more of the class files loaded by this class + * loader is detected. + *
+ * + * @author Craig R. McClanahan + * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ + */ + +public interface Loader { + + + // ------------------------------------------------------------- Properties + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess(); + + + /** + * Return the Java class loader to be used by this Container. + */ + public ClassLoader getClassLoader(); + + + /** + * Return the Container with which this Loader has been associated. + */ + public Container getContainer(); + + + /** + * Set the Container with which this Loader has been associated. + * + * @param container The associated Container + */ + public void setContainer(Container container); + + + /** + * Return the "follow standard delegation model" flag used to configure + * our ClassLoader. + */ + public boolean getDelegate(); + + + /** + * Set the "follow standard delegation model" flag used to configure + * our ClassLoader. + * + * @param delegate The new flag + */ + public void setDelegate(boolean delegate); + + + /** + * Return descriptive information about this Loader implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the reloadable flag for this Loader. + */ + public boolean getReloadable(); + + + /** + * Set the reloadable flag for this Loader. + * + * @param reloadable The new reloadable flag + */ + public void setReloadable(boolean reloadable); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + + /** + * Add a new repository to the set of repositories for this class loader. + * + * @param repository Repository to be added + */ + public void addRepository(String repository); + + + /** + * Return the set of repositories defined for this class loader. + * If none are defined, a zero-length array is returned. + */ + public String[] findRepositories(); + + + /** + * Has the internal repository associated with this Loader been modified, + * such that the loaded classes should be reloaded? + */ + public boolean modified(); + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + +} diff --git a/java/org/apache/catalina/Manager.java b/java/org/apache/catalina/Manager.java index 0cfe060c1..017b99a01 100644 --- a/java/org/apache/catalina/Manager.java +++ b/java/org/apache/catalina/Manager.java @@ -1,365 +1,365 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.beans.PropertyChangeListener; -import java.io.IOException; - - -/** - * A Manager manages the pool of Sessions that are associated with a - * particular Container. Different Manager implementations may support - * value-added features such as the persistent storage of session data, - * as well as migrating sessions for distributable web applications. - *

- * In order for a Manager implementation to successfully operate - * with a Context implementation that implements reloading, it - * must obey the following constraints: - *

    - *
  • Must implement Lifecycle so that the Context can indicate - * that a restart is required. - *
  • Must allow a call to stop() to be followed by a call to - * start() on the same Manager instance. - *
- * - * @author Craig R. McClanahan - * @version $Revision: 303682 $ $Date: 2005-02-07 22:56:32 +0100 (lun., 07 févr. 2005) $ - */ - -public interface Manager { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Container with which this Manager is associated. - */ - public Container getContainer(); - - - /** - * Set the Container with which this Manager is associated. - * - * @param container The newly associated Container - */ - public void setContainer(Container container); - - - /** - * Return the distributable flag for the sessions supported by - * this Manager. - */ - public boolean getDistributable(); - - - /** - * Set the distributable flag for the sessions supported by this - * Manager. If this flag is set, all user data objects added to - * sessions associated with this manager must implement Serializable. - * - * @param distributable The new distributable flag - */ - public void setDistributable(boolean distributable); - - - /** - * Return descriptive information about this Manager implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the default maximum inactive interval (in seconds) - * for Sessions created by this Manager. - */ - public int getMaxInactiveInterval(); - - - /** - * Set the default maximum inactive interval (in seconds) - * for Sessions created by this Manager. - * - * @param interval The new default value - */ - public void setMaxInactiveInterval(int interval); - - - /** - * Gets the session id length (in bytes) of Sessions created by - * this Manager. - * - * @return The session id length - */ - public int getSessionIdLength(); - - - /** - * Sets the session id length (in bytes) for Sessions created by this - * Manager. - * - * @param idLength The session id length - */ - public void setSessionIdLength(int idLength); - - - /** - * Returns the total number of sessions created by this manager. - * - * @return Total number of sessions created by this manager. - */ - public int getSessionCounter(); - - - /** - * Sets the total number of sessions created by this manager. - * - * @param sessionCounter Total number of sessions created by this manager. - */ - public void setSessionCounter(int sessionCounter); - - - /** - * Gets the maximum number of sessions that have been active at the same - * time. - * - * @return Maximum number of sessions that have been active at the same - * time - */ - public int getMaxActive(); - - - /** - * (Re)sets the maximum number of sessions that have been active at the - * same time. - * - * @param maxActive Maximum number of sessions that have been active at - * the same time. - */ - public void setMaxActive(int maxActive); - - - /** - * Gets the number of currently active sessions. - * - * @return Number of currently active sessions - */ - public int getActiveSessions(); - - - /** - * Gets the number of sessions that have expired. - * - * @return Number of sessions that have expired - */ - public int getExpiredSessions(); - - - /** - * Sets the number of sessions that have expired. - * - * @param expiredSessions Number of sessions that have expired - */ - public void setExpiredSessions(int expiredSessions); - - - /** - * Gets the number of sessions that were not created because the maximum - * number of active sessions was reached. - * - * @return Number of rejected sessions - */ - public int getRejectedSessions(); - - - /** - * Sets the number of sessions that were not created because the maximum - * number of active sessions was reached. - * - * @param rejectedSessions Number of rejected sessions - */ - public void setRejectedSessions(int rejectedSessions); - - - /** - * Gets the longest time (in seconds) that an expired session had been - * alive. - * - * @return Longest time (in seconds) that an expired session had been - * alive. - */ - public int getSessionMaxAliveTime(); - - - /** - * Sets the longest time (in seconds) that an expired session had been - * alive. - * - * @param sessionMaxAliveTime Longest time (in seconds) that an expired - * session had been alive. - */ - public void setSessionMaxAliveTime(int sessionMaxAliveTime); - - - /** - * Gets the average time (in seconds) that expired sessions had been - * alive. - * - * @return Average time (in seconds) that expired sessions had been - * alive. - */ - public int getSessionAverageAliveTime(); - - - /** - * Sets the average time (in seconds) that expired sessions had been - * alive. - * - * @param sessionAverageAliveTime Average time (in seconds) that expired - * sessions had been alive. - */ - public void setSessionAverageAliveTime(int sessionAverageAliveTime); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add this Session to the set of active Sessions for this Manager. - * - * @param session Session to be added - */ - public void add(Session session); - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener); - - - /** - * Get a session from the recycled ones or create a new empty one. - * The PersistentManager manager does not need to create session data - * because it reads it from the Store. - */ - public Session createEmptySession(); - - - /** - * Construct and return a new session object, based on the default - * settings specified by this Manager's properties. The session - * id will be assigned by this method, and available via the getId() - * method of the returned session. If a new session cannot be created - * for any reason, return null. - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @deprecated - */ - public Session createSession(); - - - /** - * Construct and return a new session object, based on the default - * settings specified by this Manager's properties. The session - * id specified will be used as the session id. - * If a new session cannot be created for any reason, return - * null. - * - * @param sessionId The session id which should be used to create the - * new session; if null, the session - * id will be assigned by this method, and available via the getId() - * method of the returned session. - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - */ - public Session createSession(String sessionId); - - - /** - * Return the active Session, associated with this Manager, with the - * specified session id (if any); otherwise return null. - * - * @param id The session id for the session to be returned - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @exception IOException if an input/output error occurs while - * processing this request - */ - public Session findSession(String id) throws IOException; - - - /** - * Return the set of active Sessions associated with this Manager. - * If this Manager has no active Sessions, a zero-length array is returned. - */ - public Session[] findSessions(); - - - /** - * Load any currently active sessions that were previously unloaded - * to the appropriate persistence mechanism, if any. If persistence is not - * supported, this method returns without doing anything. - * - * @exception ClassNotFoundException if a serialized class cannot be - * found during the reload - * @exception IOException if an input/output error occurs - */ - public void load() throws ClassNotFoundException, IOException; - - - /** - * Remove this Session from the active Sessions for this Manager. - * - * @param session Session to be removed - */ - public void remove(Session session); - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener); - - - /** - * Save any currently active sessions in the appropriate persistence - * mechanism, if any. If persistence is not supported, this method - * returns without doing anything. - * - * @exception IOException if an input/output error occurs - */ - public void unload() throws IOException; - - /** - * This method will be invoked by the context/container on a periodic - * basis and allows the manager to implement - * a method that executes periodic tasks, such as expiring sessions etc. - */ - public void backgroundProcess(); - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.beans.PropertyChangeListener; +import java.io.IOException; + + +/** + * A Manager manages the pool of Sessions that are associated with a + * particular Container. Different Manager implementations may support + * value-added features such as the persistent storage of session data, + * as well as migrating sessions for distributable web applications. + *

+ * In order for a Manager implementation to successfully operate + * with a Context implementation that implements reloading, it + * must obey the following constraints: + *

    + *
  • Must implement Lifecycle so that the Context can indicate + * that a restart is required. + *
  • Must allow a call to stop() to be followed by a call to + * start() on the same Manager instance. + *
+ * + * @author Craig R. McClanahan + * @version $Revision: 303682 $ $Date: 2005-02-07 22:56:32 +0100 (lun., 07 févr. 2005) $ + */ + +public interface Manager { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Container with which this Manager is associated. + */ + public Container getContainer(); + + + /** + * Set the Container with which this Manager is associated. + * + * @param container The newly associated Container + */ + public void setContainer(Container container); + + + /** + * Return the distributable flag for the sessions supported by + * this Manager. + */ + public boolean getDistributable(); + + + /** + * Set the distributable flag for the sessions supported by this + * Manager. If this flag is set, all user data objects added to + * sessions associated with this manager must implement Serializable. + * + * @param distributable The new distributable flag + */ + public void setDistributable(boolean distributable); + + + /** + * Return descriptive information about this Manager implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the default maximum inactive interval (in seconds) + * for Sessions created by this Manager. + */ + public int getMaxInactiveInterval(); + + + /** + * Set the default maximum inactive interval (in seconds) + * for Sessions created by this Manager. + * + * @param interval The new default value + */ + public void setMaxInactiveInterval(int interval); + + + /** + * Gets the session id length (in bytes) of Sessions created by + * this Manager. + * + * @return The session id length + */ + public int getSessionIdLength(); + + + /** + * Sets the session id length (in bytes) for Sessions created by this + * Manager. + * + * @param idLength The session id length + */ + public void setSessionIdLength(int idLength); + + + /** + * Returns the total number of sessions created by this manager. + * + * @return Total number of sessions created by this manager. + */ + public int getSessionCounter(); + + + /** + * Sets the total number of sessions created by this manager. + * + * @param sessionCounter Total number of sessions created by this manager. + */ + public void setSessionCounter(int sessionCounter); + + + /** + * Gets the maximum number of sessions that have been active at the same + * time. + * + * @return Maximum number of sessions that have been active at the same + * time + */ + public int getMaxActive(); + + + /** + * (Re)sets the maximum number of sessions that have been active at the + * same time. + * + * @param maxActive Maximum number of sessions that have been active at + * the same time. + */ + public void setMaxActive(int maxActive); + + + /** + * Gets the number of currently active sessions. + * + * @return Number of currently active sessions + */ + public int getActiveSessions(); + + + /** + * Gets the number of sessions that have expired. + * + * @return Number of sessions that have expired + */ + public int getExpiredSessions(); + + + /** + * Sets the number of sessions that have expired. + * + * @param expiredSessions Number of sessions that have expired + */ + public void setExpiredSessions(int expiredSessions); + + + /** + * Gets the number of sessions that were not created because the maximum + * number of active sessions was reached. + * + * @return Number of rejected sessions + */ + public int getRejectedSessions(); + + + /** + * Sets the number of sessions that were not created because the maximum + * number of active sessions was reached. + * + * @param rejectedSessions Number of rejected sessions + */ + public void setRejectedSessions(int rejectedSessions); + + + /** + * Gets the longest time (in seconds) that an expired session had been + * alive. + * + * @return Longest time (in seconds) that an expired session had been + * alive. + */ + public int getSessionMaxAliveTime(); + + + /** + * Sets the longest time (in seconds) that an expired session had been + * alive. + * + * @param sessionMaxAliveTime Longest time (in seconds) that an expired + * session had been alive. + */ + public void setSessionMaxAliveTime(int sessionMaxAliveTime); + + + /** + * Gets the average time (in seconds) that expired sessions had been + * alive. + * + * @return Average time (in seconds) that expired sessions had been + * alive. + */ + public int getSessionAverageAliveTime(); + + + /** + * Sets the average time (in seconds) that expired sessions had been + * alive. + * + * @param sessionAverageAliveTime Average time (in seconds) that expired + * sessions had been alive. + */ + public void setSessionAverageAliveTime(int sessionAverageAliveTime); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add this Session to the set of active Sessions for this Manager. + * + * @param session Session to be added + */ + public void add(Session session); + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + + /** + * Get a session from the recycled ones or create a new empty one. + * The PersistentManager manager does not need to create session data + * because it reads it from the Store. + */ + public Session createEmptySession(); + + + /** + * Construct and return a new session object, based on the default + * settings specified by this Manager's properties. The session + * id will be assigned by this method, and available via the getId() + * method of the returned session. If a new session cannot be created + * for any reason, return null. + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + * @deprecated + */ + public Session createSession(); + + + /** + * Construct and return a new session object, based on the default + * settings specified by this Manager's properties. The session + * id specified will be used as the session id. + * If a new session cannot be created for any reason, return + * null. + * + * @param sessionId The session id which should be used to create the + * new session; if null, the session + * id will be assigned by this method, and available via the getId() + * method of the returned session. + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + */ + public Session createSession(String sessionId); + + + /** + * Return the active Session, associated with this Manager, with the + * specified session id (if any); otherwise return null. + * + * @param id The session id for the session to be returned + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + * @exception IOException if an input/output error occurs while + * processing this request + */ + public Session findSession(String id) throws IOException; + + + /** + * Return the set of active Sessions associated with this Manager. + * If this Manager has no active Sessions, a zero-length array is returned. + */ + public Session[] findSessions(); + + + /** + * Load any currently active sessions that were previously unloaded + * to the appropriate persistence mechanism, if any. If persistence is not + * supported, this method returns without doing anything. + * + * @exception ClassNotFoundException if a serialized class cannot be + * found during the reload + * @exception IOException if an input/output error occurs + */ + public void load() throws ClassNotFoundException, IOException; + + + /** + * Remove this Session from the active Sessions for this Manager. + * + * @param session Session to be removed + */ + public void remove(Session session); + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + + /** + * Save any currently active sessions in the appropriate persistence + * mechanism, if any. If persistence is not supported, this method + * returns without doing anything. + * + * @exception IOException if an input/output error occurs + */ + public void unload() throws IOException; + + /** + * This method will be invoked by the context/container on a periodic + * basis and allows the manager to implement + * a method that executes periodic tasks, such as expiring sessions etc. + */ + public void backgroundProcess(); + +} diff --git a/java/org/apache/catalina/Pipeline.java b/java/org/apache/catalina/Pipeline.java index a3cdd4b7e..0e6137ad2 100644 --- a/java/org/apache/catalina/Pipeline.java +++ b/java/org/apache/catalina/Pipeline.java @@ -1,120 +1,120 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -/** - *

Interface describing a collection of Valves that should be executed - * in sequence when the invoke() method is invoked. It is - * required that a Valve somewhere in the pipeline (usually the last one) - * must process the request and create the corresponding response, rather - * than trying to pass the request on.

- * - *

There is generally a single Pipeline instance associated with each - * Container. The container's normal request processing functionality is - * generally encapsulated in a container-specific Valve, which should always - * be executed at the end of a pipeline. To facilitate this, the - * setBasic() method is provided to set the Valve instance that - * will always be executed last. Other Valves will be executed in the order - * that they were added, before the basic Valve is executed.

- * - * @author Craig R. McClanahan - * @author Peter Donald - * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ - */ - -public interface Pipeline { - - - // ------------------------------------------------------------- Properties - - - /** - *

Return the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). - */ - public Valve getBasic(); - - - /** - *

Set the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). Prioer to setting the basic Valve, - * the Valve's setContainer() will be called, if it - * implements Contained, with the owning Container as an - * argument. The method may throw an IllegalArgumentException - * if this Valve chooses not to be associated with this Container, or - * IllegalStateException if it is already associated with - * a different Container.

- * - * @param valve Valve to be distinguished as the basic Valve - */ - public void setBasic(Valve valve); - - - // --------------------------------------------------------- Public Methods - - - /** - *

Add a new Valve to the end of the pipeline associated with this - * Container. Prior to adding the Valve, the Valve's - * setContainer() method will be called, if it implements - * Contained, with the owning Container as an argument. - * The method may throw an - * IllegalArgumentException if this Valve chooses not to - * be associated with this Container, or IllegalStateException - * if it is already associated with a different Container.

- * - * @param valve Valve to be added - * - * @exception IllegalArgumentException if this Container refused to - * accept the specified Valve - * @exception IllegalArgumentException if the specifie Valve refuses to be - * associated with this Container - * @exception IllegalStateException if the specified Valve is already - * associated with a different Container - */ - public void addValve(Valve valve); - - - /** - * Return the set of Valves in the pipeline associated with this - * Container, including the basic Valve (if any). If there are no - * such Valves, a zero-length array is returned. - */ - public Valve[] getValves(); - - - /** - * Remove the specified Valve from the pipeline associated with this - * Container, if it is found; otherwise, do nothing. If the Valve is - * found and removed, the Valve's setContainer(null) method - * will be called if it implements Contained. - * - * @param valve Valve to be removed - */ - public void removeValve(Valve valve); - - - /** - *

Return the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). - */ - public Valve getFirst(); - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +/** + *

Interface describing a collection of Valves that should be executed + * in sequence when the invoke() method is invoked. It is + * required that a Valve somewhere in the pipeline (usually the last one) + * must process the request and create the corresponding response, rather + * than trying to pass the request on.

+ * + *

There is generally a single Pipeline instance associated with each + * Container. The container's normal request processing functionality is + * generally encapsulated in a container-specific Valve, which should always + * be executed at the end of a pipeline. To facilitate this, the + * setBasic() method is provided to set the Valve instance that + * will always be executed last. Other Valves will be executed in the order + * that they were added, before the basic Valve is executed.

+ * + * @author Craig R. McClanahan + * @author Peter Donald + * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ + */ + +public interface Pipeline { + + + // ------------------------------------------------------------- Properties + + + /** + *

Return the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). + */ + public Valve getBasic(); + + + /** + *

Set the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). Prioer to setting the basic Valve, + * the Valve's setContainer() will be called, if it + * implements Contained, with the owning Container as an + * argument. The method may throw an IllegalArgumentException + * if this Valve chooses not to be associated with this Container, or + * IllegalStateException if it is already associated with + * a different Container.

+ * + * @param valve Valve to be distinguished as the basic Valve + */ + public void setBasic(Valve valve); + + + // --------------------------------------------------------- Public Methods + + + /** + *

Add a new Valve to the end of the pipeline associated with this + * Container. Prior to adding the Valve, the Valve's + * setContainer() method will be called, if it implements + * Contained, with the owning Container as an argument. + * The method may throw an + * IllegalArgumentException if this Valve chooses not to + * be associated with this Container, or IllegalStateException + * if it is already associated with a different Container.

+ * + * @param valve Valve to be added + * + * @exception IllegalArgumentException if this Container refused to + * accept the specified Valve + * @exception IllegalArgumentException if the specifie Valve refuses to be + * associated with this Container + * @exception IllegalStateException if the specified Valve is already + * associated with a different Container + */ + public void addValve(Valve valve); + + + /** + * Return the set of Valves in the pipeline associated with this + * Container, including the basic Valve (if any). If there are no + * such Valves, a zero-length array is returned. + */ + public Valve[] getValves(); + + + /** + * Remove the specified Valve from the pipeline associated with this + * Container, if it is found; otherwise, do nothing. If the Valve is + * found and removed, the Valve's setContainer(null) method + * will be called if it implements Contained. + * + * @param valve Valve to be removed + */ + public void removeValve(Valve valve); + + + /** + *

Return the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). + */ + public Valve getFirst(); + + +} diff --git a/java/org/apache/catalina/Realm.java b/java/org/apache/catalina/Realm.java index e6e304618..698056327 100644 --- a/java/org/apache/catalina/Realm.java +++ b/java/org/apache/catalina/Realm.java @@ -1,201 +1,201 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.security.Principal; -import java.security.cert.X509Certificate; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.SecurityConstraint; -/** - * A Realm is a read-only facade for an underlying security realm - * used to authenticate individual users, and identify the security roles - * associated with those users. Realms can be attached at any Container - * level, but will typically only be attached to a Context, or higher level, - * Container. - * - * @author Craig R. McClanahan - * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ - */ - -public interface Realm { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Container with which this Realm has been associated. - */ - public Container getContainer(); - - - /** - * Set the Container with which this Realm has been associated. - * - * @param container The associated Container - */ - public void setContainer(Container container); - - - /** - * Return descriptive information about this Realm implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener); - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials); - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, byte[] credentials); - - - /** - * Return the Principal associated with the specified username, which - * matches the digest calculated using the given parameters using the - * method described in RFC 2069; otherwise return null. - * - * @param username Username of the Principal to look up - * @param digest Digest which has been submitted by the client - * @param nonce Unique (or supposedly unique) token which has been used - * for this request - * @param realm Realm name - * @param md5a2 Second MD5 digest used to calculate the digest : - * MD5(Method + ":" + uri) - */ - public Principal authenticate(String username, String digest, - String nonce, String nc, String cnonce, - String qop, String realm, - String md5a2); - - - /** - * Return the Principal associated with the specified chain of X509 - * client certificates. If there is none, return null. - * - * @param certs Array of client certificates, with the first one in - * the array being the certificate of the client itself. - */ - public Principal authenticate(X509Certificate certs[]); - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess(); - - - /** - * Return the SecurityConstraints configured to guard the request URI for - * this request, or null if there is no such constraint. - * - * @param request Request we are processing - */ - public SecurityConstraint [] findSecurityConstraints(Request request, - Context context); - - - /** - * Perform access control based on the specified authorization constraint. - * Return true if this constraint is satisfied and processing - * should continue, or false otherwise. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraint Security constraint we are enforcing - * @param context The Context to which client of this class is attached. - * - * @exception IOException if an input/output error occurs - */ - public boolean hasResourcePermission(Request request, - Response response, - SecurityConstraint [] constraint, - Context context) - throws IOException; - - - /** - * Return true if the specified Principal has the specified - * security role, within the context of this Realm; otherwise return - * false. - * - * @param principal Principal for whom the role is to be checked - * @param role Security role to be checked - */ - public boolean hasRole(Principal principal, String role); - - /** - * Enforce any user data constraint required by the security constraint - * guarding this request URI. Return true if this constraint - * was not violated and processing should continue, or false - * if we have created a response already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraint Security constraint being checked - * - * @exception IOException if an input/output error occurs - */ - public boolean hasUserDataPermission(Request request, - Response response, - SecurityConstraint []constraint) - throws IOException; - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.security.Principal; +import java.security.cert.X509Certificate; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.SecurityConstraint; +/** + * A Realm is a read-only facade for an underlying security realm + * used to authenticate individual users, and identify the security roles + * associated with those users. Realms can be attached at any Container + * level, but will typically only be attached to a Context, or higher level, + * Container. + * + * @author Craig R. McClanahan + * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ + */ + +public interface Realm { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Container with which this Realm has been associated. + */ + public Container getContainer(); + + + /** + * Set the Container with which this Realm has been associated. + * + * @param container The associated Container + */ + public void setContainer(Container container); + + + /** + * Return descriptive information about this Realm implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials); + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, byte[] credentials); + + + /** + * Return the Principal associated with the specified username, which + * matches the digest calculated using the given parameters using the + * method described in RFC 2069; otherwise return null. + * + * @param username Username of the Principal to look up + * @param digest Digest which has been submitted by the client + * @param nonce Unique (or supposedly unique) token which has been used + * for this request + * @param realm Realm name + * @param md5a2 Second MD5 digest used to calculate the digest : + * MD5(Method + ":" + uri) + */ + public Principal authenticate(String username, String digest, + String nonce, String nc, String cnonce, + String qop, String realm, + String md5a2); + + + /** + * Return the Principal associated with the specified chain of X509 + * client certificates. If there is none, return null. + * + * @param certs Array of client certificates, with the first one in + * the array being the certificate of the client itself. + */ + public Principal authenticate(X509Certificate certs[]); + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess(); + + + /** + * Return the SecurityConstraints configured to guard the request URI for + * this request, or null if there is no such constraint. + * + * @param request Request we are processing + */ + public SecurityConstraint [] findSecurityConstraints(Request request, + Context context); + + + /** + * Perform access control based on the specified authorization constraint. + * Return true if this constraint is satisfied and processing + * should continue, or false otherwise. + * + * @param request Request we are processing + * @param response Response we are creating + * @param constraint Security constraint we are enforcing + * @param context The Context to which client of this class is attached. + * + * @exception IOException if an input/output error occurs + */ + public boolean hasResourcePermission(Request request, + Response response, + SecurityConstraint [] constraint, + Context context) + throws IOException; + + + /** + * Return true if the specified Principal has the specified + * security role, within the context of this Realm; otherwise return + * false. + * + * @param principal Principal for whom the role is to be checked + * @param role Security role to be checked + */ + public boolean hasRole(Principal principal, String role); + + /** + * Enforce any user data constraint required by the security constraint + * guarding this request URI. Return true if this constraint + * was not violated and processing should continue, or false + * if we have created a response already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param constraint Security constraint being checked + * + * @exception IOException if an input/output error occurs + */ + public boolean hasUserDataPermission(Request request, + Response response, + SecurityConstraint []constraint) + throws IOException; + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + +} diff --git a/java/org/apache/catalina/Role.java b/java/org/apache/catalina/Role.java index 09d790c77..a45c29688 100644 --- a/java/org/apache/catalina/Role.java +++ b/java/org/apache/catalina/Role.java @@ -1,75 +1,75 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.security.Principal; - - -/** - *

Abstract representation of a security role, suitable for use in - * environments like JAAS that want to deal with Principals.

- * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public interface Role extends Principal { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the description of this role. - */ - public String getDescription(); - - - /** - * Set the description of this role. - * - * @param description The new description - */ - public void setDescription(String description); - - - /** - * Return the role name of this role, which must be unique - * within the scope of a {@link UserDatabase}. - */ - public String getRolename(); - - - /** - * Set the role name of this role, which must be unique - * within the scope of a {@link UserDatabase}. - * - * @param rolename The new role name - */ - public void setRolename(String rolename); - - - /** - * Return the {@link UserDatabase} within which this Role is defined. - */ - public UserDatabase getUserDatabase(); - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.security.Principal; + + +/** + *

Abstract representation of a security role, suitable for use in + * environments like JAAS that want to deal with Principals.

+ * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public interface Role extends Principal { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the description of this role. + */ + public String getDescription(); + + + /** + * Set the description of this role. + * + * @param description The new description + */ + public void setDescription(String description); + + + /** + * Return the role name of this role, which must be unique + * within the scope of a {@link UserDatabase}. + */ + public String getRolename(); + + + /** + * Set the role name of this role, which must be unique + * within the scope of a {@link UserDatabase}. + * + * @param rolename The new role name + */ + public void setRolename(String rolename); + + + /** + * Return the {@link UserDatabase} within which this Role is defined. + */ + public UserDatabase getUserDatabase(); + + +} diff --git a/java/org/apache/catalina/Server.java b/java/org/apache/catalina/Server.java index e670a0a63..e08b9f597 100644 --- a/java/org/apache/catalina/Server.java +++ b/java/org/apache/catalina/Server.java @@ -1,152 +1,152 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - -import org.apache.catalina.deploy.NamingResources; - -/** - * A Server element represents the entire Catalina - * servlet container. Its attributes represent the characteristics of - * the servlet container as a whole. A Server may contain - * one or more Services, and the top level set of naming - * resources. - *

- * Normally, an implementation of this interface will also implement - * Lifecycle, such that when the start() and - * stop() methods are called, all of the defined - * Services are also started or stopped. - *

- * In between, the implementation must open a server socket on the port number - * specified by the port property. When a connection is accepted, - * the first line is read and compared with the specified shutdown command. - * If the command matches, shutdown of the server is initiated. - *

- * NOTE - The concrete implementation of this class should - * register the (singleton) instance with the ServerFactory - * class in its constructor(s). - * - * @author Craig R. McClanahan - * @version $Revision: 302899 $ $Date: 2004-05-26 17:29:30 +0200 (mer., 26 mai 2004) $ - */ - -public interface Server { - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Server implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the global naming resources. - */ - public NamingResources getGlobalNamingResources(); - - - /** - * Set the global naming resources. - * - * @param globalNamingResources The new global naming resources - */ - public void setGlobalNamingResources - (NamingResources globalNamingResources); - - - /** - * Return the port number we listen to for shutdown commands. - */ - public int getPort(); - - - /** - * Set the port number we listen to for shutdown commands. - * - * @param port The new port number - */ - public void setPort(int port); - - - /** - * Return the shutdown command string we are waiting for. - */ - public String getShutdown(); - - - /** - * Set the shutdown command we are waiting for. - * - * @param shutdown The new shutdown command - */ - public void setShutdown(String shutdown); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new Service to the set of defined Services. - * - * @param service The Service to be added - */ - public void addService(Service service); - - - /** - * Wait until a proper shutdown command is received, then return. - */ - public void await(); - - - /** - * Return the specified Service (if it exists); otherwise return - * null. - * - * @param name Name of the Service to be returned - */ - public Service findService(String name); - - - /** - * Return the set of Services defined within this Server. - */ - public Service[] findServices(); - - - /** - * Remove the specified Service from the set associated from this - * Server. - * - * @param service The Service to be removed - */ - public void removeService(Service service); - - /** - * Invoke a pre-startup initialization. This is used to allow connectors - * to bind to restricted ports under Unix operating environments. - * - * @exception LifecycleException If this server was already initialized. - */ - public void initialize() - throws LifecycleException; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + +import org.apache.catalina.deploy.NamingResources; + +/** + * A Server element represents the entire Catalina + * servlet container. Its attributes represent the characteristics of + * the servlet container as a whole. A Server may contain + * one or more Services, and the top level set of naming + * resources. + *

+ * Normally, an implementation of this interface will also implement + * Lifecycle, such that when the start() and + * stop() methods are called, all of the defined + * Services are also started or stopped. + *

+ * In between, the implementation must open a server socket on the port number + * specified by the port property. When a connection is accepted, + * the first line is read and compared with the specified shutdown command. + * If the command matches, shutdown of the server is initiated. + *

+ * NOTE - The concrete implementation of this class should + * register the (singleton) instance with the ServerFactory + * class in its constructor(s). + * + * @author Craig R. McClanahan + * @version $Revision: 302899 $ $Date: 2004-05-26 17:29:30 +0200 (mer., 26 mai 2004) $ + */ + +public interface Server { + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Server implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the global naming resources. + */ + public NamingResources getGlobalNamingResources(); + + + /** + * Set the global naming resources. + * + * @param globalNamingResources The new global naming resources + */ + public void setGlobalNamingResources + (NamingResources globalNamingResources); + + + /** + * Return the port number we listen to for shutdown commands. + */ + public int getPort(); + + + /** + * Set the port number we listen to for shutdown commands. + * + * @param port The new port number + */ + public void setPort(int port); + + + /** + * Return the shutdown command string we are waiting for. + */ + public String getShutdown(); + + + /** + * Set the shutdown command we are waiting for. + * + * @param shutdown The new shutdown command + */ + public void setShutdown(String shutdown); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new Service to the set of defined Services. + * + * @param service The Service to be added + */ + public void addService(Service service); + + + /** + * Wait until a proper shutdown command is received, then return. + */ + public void await(); + + + /** + * Return the specified Service (if it exists); otherwise return + * null. + * + * @param name Name of the Service to be returned + */ + public Service findService(String name); + + + /** + * Return the set of Services defined within this Server. + */ + public Service[] findServices(); + + + /** + * Remove the specified Service from the set associated from this + * Server. + * + * @param service The Service to be removed + */ + public void removeService(Service service); + + /** + * Invoke a pre-startup initialization. This is used to allow connectors + * to bind to restricted ports under Unix operating environments. + * + * @exception LifecycleException If this server was already initialized. + */ + public void initialize() + throws LifecycleException; +} diff --git a/java/org/apache/catalina/ServerFactory.java b/java/org/apache/catalina/ServerFactory.java index e94cb10e3..aead33915 100644 --- a/java/org/apache/catalina/ServerFactory.java +++ b/java/org/apache/catalina/ServerFactory.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - -import org.apache.catalina.core.StandardServer; - - -/** - *

ServerFactory allows the registration of the - * (singleton) Server instance for this JVM, so that it - * can be accessed independently of any existing reference to the - * component hierarchy. This is important for administration tools - * that are built around the internal component implementation classes. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ServerFactory { - - - // ------------------------------------------------------- Static Variables - - - /** - * The singleton Server instance for this JVM. - */ - private static Server server = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the singleton Server instance for this JVM. - */ - public static Server getServer() { - if( server==null ) - server=new StandardServer(); - return (server); - - } - - - /** - * Set the singleton Server instance for this JVM. This - * method must only be called from a constructor of - * the (singleton) Server instance that is created for - * this execution of Catalina. - * - * @param theServer The new singleton instance - */ - public static void setServer(Server theServer) { - - if (server == null) - server = theServer; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + +import org.apache.catalina.core.StandardServer; + + +/** + *

ServerFactory allows the registration of the + * (singleton) Server instance for this JVM, so that it + * can be accessed independently of any existing reference to the + * component hierarchy. This is important for administration tools + * that are built around the internal component implementation classes. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ServerFactory { + + + // ------------------------------------------------------- Static Variables + + + /** + * The singleton Server instance for this JVM. + */ + private static Server server = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the singleton Server instance for this JVM. + */ + public static Server getServer() { + if( server==null ) + server=new StandardServer(); + return (server); + + } + + + /** + * Set the singleton Server instance for this JVM. This + * method must only be called from a constructor of + * the (singleton) Server instance that is created for + * this execution of Catalina. + * + * @param theServer The new singleton instance + */ + public static void setServer(Server theServer) { + + if (server == null) + server = theServer; + + } + + +} diff --git a/java/org/apache/catalina/Service.java b/java/org/apache/catalina/Service.java index 21c5ae716..3086ea80a 100644 --- a/java/org/apache/catalina/Service.java +++ b/java/org/apache/catalina/Service.java @@ -1,131 +1,131 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - -import org.apache.catalina.connector.Connector; - - -/** - * A Service is a group of one or more - * Connectors that share a single Container - * to process their incoming requests. This arrangement allows, for example, - * a non-SSL and SSL connector to share the same population of web apps. - *

- * A given JVM can contain any number of Service instances; however, they are - * completely independent of each other and share only the basic JVM facilities - * and classes on the system class path. - * - * @author Craig R. McClanahan - * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ - */ - -public interface Service { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Container that handles requests for all - * Connectors associated with this Service. - */ - public Container getContainer(); - - - /** - * Set the Container that handles requests for all - * Connectors associated with this Service. - * - * @param container The new Container - */ - public void setContainer(Container container); - - - /** - * Return descriptive information about this Service implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the name of this Service. - */ - public String getName(); - - - /** - * Set the name of this Service. - * - * @param name The new service name - */ - public void setName(String name); - - - /** - * Return the Server with which we are associated (if any). - */ - public Server getServer(); - - - /** - * Set the Server with which we are associated (if any). - * - * @param server The server that owns this Service - */ - public void setServer(Server server); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new Connector to the set of defined Connectors, and associate it - * with this Service's Container. - * - * @param connector The Connector to be added - */ - public void addConnector(Connector connector); - - - /** - * Find and return the set of Connectors associated with this Service. - */ - public Connector[] findConnectors(); - - - /** - * Remove the specified Connector from the set associated from this - * Service. The removed Connector will also be disassociated from our - * Container. - * - * @param connector The Connector to be removed - */ - public void removeConnector(Connector connector); - - /** - * Invoke a pre-startup initialization. This is used to allow connectors - * to bind to restricted ports under Unix operating environments. - * - * @exception LifecycleException If this server was already initialized. - */ - public void initialize() - throws LifecycleException; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + +import org.apache.catalina.connector.Connector; + + +/** + * A Service is a group of one or more + * Connectors that share a single Container + * to process their incoming requests. This arrangement allows, for example, + * a non-SSL and SSL connector to share the same population of web apps. + *

+ * A given JVM can contain any number of Service instances; however, they are + * completely independent of each other and share only the basic JVM facilities + * and classes on the system class path. + * + * @author Craig R. McClanahan + * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ + */ + +public interface Service { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Container that handles requests for all + * Connectors associated with this Service. + */ + public Container getContainer(); + + + /** + * Set the Container that handles requests for all + * Connectors associated with this Service. + * + * @param container The new Container + */ + public void setContainer(Container container); + + + /** + * Return descriptive information about this Service implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the name of this Service. + */ + public String getName(); + + + /** + * Set the name of this Service. + * + * @param name The new service name + */ + public void setName(String name); + + + /** + * Return the Server with which we are associated (if any). + */ + public Server getServer(); + + + /** + * Set the Server with which we are associated (if any). + * + * @param server The server that owns this Service + */ + public void setServer(Server server); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new Connector to the set of defined Connectors, and associate it + * with this Service's Container. + * + * @param connector The Connector to be added + */ + public void addConnector(Connector connector); + + + /** + * Find and return the set of Connectors associated with this Service. + */ + public Connector[] findConnectors(); + + + /** + * Remove the specified Connector from the set associated from this + * Service. The removed Connector will also be disassociated from our + * Container. + * + * @param connector The Connector to be removed + */ + public void removeConnector(Connector connector); + + /** + * Invoke a pre-startup initialization. This is used to allow connectors + * to bind to restricted ports under Unix operating environments. + * + * @exception LifecycleException If this server was already initialized. + */ + public void initialize() + throws LifecycleException; + +} diff --git a/java/org/apache/catalina/Session.java b/java/org/apache/catalina/Session.java index 083831f68..3f531f6a5 100644 --- a/java/org/apache/catalina/Session.java +++ b/java/org/apache/catalina/Session.java @@ -1,302 +1,302 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.security.Principal; -import java.util.Iterator; - -import javax.servlet.http.HttpSession; - - -/** - * A Session is the Catalina-internal facade for an - * HttpSession that is used to maintain state information - * between requests for a particular user of a web application. - * - * @author Craig R. McClanahan - * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ - */ - -public interface Session { - - - // ----------------------------------------------------- Manifest Constants - - - /** - * The SessionEvent event type when a session is created. - */ - public static final String SESSION_CREATED_EVENT = "createSession"; - - - /** - * The SessionEvent event type when a session is destroyed. - */ - public static final String SESSION_DESTROYED_EVENT = "destroySession"; - - - /** - * The SessionEvent event type when a session is activated. - */ - public static final String SESSION_ACTIVATED_EVENT = "activateSession"; - - - /** - * The SessionEvent event type when a session is passivated. - */ - public static final String SESSION_PASSIVATED_EVENT = "passivateSession"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the authentication type used to authenticate our cached - * Principal, if any. - */ - public String getAuthType(); - - - /** - * Set the authentication type used to authenticate our cached - * Principal, if any. - * - * @param authType The new cached authentication type - */ - public void setAuthType(String authType); - - - /** - * Return the creation time for this session. - */ - public long getCreationTime(); - - - /** - * Set the creation time for this session. This method is called by the - * Manager when an existing Session instance is reused. - * - * @param time The new creation time - */ - public void setCreationTime(long time); - - - /** - * Return the session identifier for this session. - */ - public String getId(); - - - /** - * Return the session identifier for this session. - */ - public String getIdInternal(); - - - /** - * Set the session identifier for this session. - * - * @param id The new session identifier - */ - public void setId(String id); - - - /** - * Return descriptive information about this Session implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the last time the client sent a request associated with this - * session, as the number of milliseconds since midnight, January 1, 1970 - * GMT. Actions that your application takes, such as getting or setting - * a value associated with the session, do not affect the access time. - */ - public long getLastAccessedTime(); - - /** - * Return the last client access time without invalidation check - * @see #getLastAccessedTime(). - */ - public long getLastAccessedTimeInternal(); - - /** - * Return the Manager within which this Session is valid. - */ - public Manager getManager(); - - - /** - * Set the Manager within which this Session is valid. - * - * @param manager The new Manager - */ - public void setManager(Manager manager); - - - /** - * Return the maximum time interval, in seconds, between client requests - * before the servlet container will invalidate the session. A negative - * time indicates that the session should never time out. - */ - public int getMaxInactiveInterval(); - - - /** - * Set the maximum time interval, in seconds, between client requests - * before the servlet container will invalidate the session. A negative - * time indicates that the session should never time out. - * - * @param interval The new maximum interval - */ - public void setMaxInactiveInterval(int interval); - - - /** - * Set the isNew flag for this session. - * - * @param isNew The new value for the isNew flag - */ - public void setNew(boolean isNew); - - - /** - * Return the authenticated Principal that is associated with this Session. - * This provides an Authenticator with a means to cache a - * previously authenticated Principal, and avoid potentially expensive - * Realm.authenticate() calls on every request. If there - * is no current associated Principal, return null. - */ - public Principal getPrincipal(); - - - /** - * Set the authenticated Principal that is associated with this Session. - * This provides an Authenticator with a means to cache a - * previously authenticated Principal, and avoid potentially expensive - * Realm.authenticate() calls on every request. - * - * @param principal The new Principal, or null if none - */ - public void setPrincipal(Principal principal); - - - /** - * Return the HttpSession for which this object - * is the facade. - */ - public HttpSession getSession(); - - - /** - * Set the isValid flag for this session. - * - * @param isValid The new value for the isValid flag - */ - public void setValid(boolean isValid); - - - /** - * Return the isValid flag for this session. - */ - public boolean isValid(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Update the accessed time information for this session. This method - * should be called by the context when a request comes in for a particular - * session, even if the application does not reference it. - */ - public void access(); - - - /** - * Add a session event listener to this component. - */ - public void addSessionListener(SessionListener listener); - - - /** - * End access to the session. - */ - public void endAccess(); - - - /** - * Perform the internal processing required to invalidate this session, - * without triggering an exception if the session has already expired. - */ - public void expire(); - - - /** - * Return the object bound with the specified name to the internal notes - * for this session, or null if no such binding exists. - * - * @param name Name of the note to be returned - */ - public Object getNote(String name); - - - /** - * Return an Iterator containing the String names of all notes bindings - * that exist for this session. - */ - public Iterator getNoteNames(); - - - /** - * Release all object references, and initialize instance variables, in - * preparation for reuse of this object. - */ - public void recycle(); - - - /** - * Remove any object bound to the specified name in the internal notes - * for this session. - * - * @param name Name of the note to be removed - */ - public void removeNote(String name); - - - /** - * Remove a session event listener from this component. - */ - public void removeSessionListener(SessionListener listener); - - - /** - * Bind an object to a specified name in the internal notes associated - * with this session, replacing any existing binding for this name. - * - * @param name Name to which the object should be bound - * @param value Object to be bound to the specified name - */ - public void setNote(String name, Object value); - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.security.Principal; +import java.util.Iterator; + +import javax.servlet.http.HttpSession; + + +/** + * A Session is the Catalina-internal facade for an + * HttpSession that is used to maintain state information + * between requests for a particular user of a web application. + * + * @author Craig R. McClanahan + * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ + */ + +public interface Session { + + + // ----------------------------------------------------- Manifest Constants + + + /** + * The SessionEvent event type when a session is created. + */ + public static final String SESSION_CREATED_EVENT = "createSession"; + + + /** + * The SessionEvent event type when a session is destroyed. + */ + public static final String SESSION_DESTROYED_EVENT = "destroySession"; + + + /** + * The SessionEvent event type when a session is activated. + */ + public static final String SESSION_ACTIVATED_EVENT = "activateSession"; + + + /** + * The SessionEvent event type when a session is passivated. + */ + public static final String SESSION_PASSIVATED_EVENT = "passivateSession"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the authentication type used to authenticate our cached + * Principal, if any. + */ + public String getAuthType(); + + + /** + * Set the authentication type used to authenticate our cached + * Principal, if any. + * + * @param authType The new cached authentication type + */ + public void setAuthType(String authType); + + + /** + * Return the creation time for this session. + */ + public long getCreationTime(); + + + /** + * Set the creation time for this session. This method is called by the + * Manager when an existing Session instance is reused. + * + * @param time The new creation time + */ + public void setCreationTime(long time); + + + /** + * Return the session identifier for this session. + */ + public String getId(); + + + /** + * Return the session identifier for this session. + */ + public String getIdInternal(); + + + /** + * Set the session identifier for this session. + * + * @param id The new session identifier + */ + public void setId(String id); + + + /** + * Return descriptive information about this Session implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the last time the client sent a request associated with this + * session, as the number of milliseconds since midnight, January 1, 1970 + * GMT. Actions that your application takes, such as getting or setting + * a value associated with the session, do not affect the access time. + */ + public long getLastAccessedTime(); + + /** + * Return the last client access time without invalidation check + * @see #getLastAccessedTime(). + */ + public long getLastAccessedTimeInternal(); + + /** + * Return the Manager within which this Session is valid. + */ + public Manager getManager(); + + + /** + * Set the Manager within which this Session is valid. + * + * @param manager The new Manager + */ + public void setManager(Manager manager); + + + /** + * Return the maximum time interval, in seconds, between client requests + * before the servlet container will invalidate the session. A negative + * time indicates that the session should never time out. + */ + public int getMaxInactiveInterval(); + + + /** + * Set the maximum time interval, in seconds, between client requests + * before the servlet container will invalidate the session. A negative + * time indicates that the session should never time out. + * + * @param interval The new maximum interval + */ + public void setMaxInactiveInterval(int interval); + + + /** + * Set the isNew flag for this session. + * + * @param isNew The new value for the isNew flag + */ + public void setNew(boolean isNew); + + + /** + * Return the authenticated Principal that is associated with this Session. + * This provides an Authenticator with a means to cache a + * previously authenticated Principal, and avoid potentially expensive + * Realm.authenticate() calls on every request. If there + * is no current associated Principal, return null. + */ + public Principal getPrincipal(); + + + /** + * Set the authenticated Principal that is associated with this Session. + * This provides an Authenticator with a means to cache a + * previously authenticated Principal, and avoid potentially expensive + * Realm.authenticate() calls on every request. + * + * @param principal The new Principal, or null if none + */ + public void setPrincipal(Principal principal); + + + /** + * Return the HttpSession for which this object + * is the facade. + */ + public HttpSession getSession(); + + + /** + * Set the isValid flag for this session. + * + * @param isValid The new value for the isValid flag + */ + public void setValid(boolean isValid); + + + /** + * Return the isValid flag for this session. + */ + public boolean isValid(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Update the accessed time information for this session. This method + * should be called by the context when a request comes in for a particular + * session, even if the application does not reference it. + */ + public void access(); + + + /** + * Add a session event listener to this component. + */ + public void addSessionListener(SessionListener listener); + + + /** + * End access to the session. + */ + public void endAccess(); + + + /** + * Perform the internal processing required to invalidate this session, + * without triggering an exception if the session has already expired. + */ + public void expire(); + + + /** + * Return the object bound with the specified name to the internal notes + * for this session, or null if no such binding exists. + * + * @param name Name of the note to be returned + */ + public Object getNote(String name); + + + /** + * Return an Iterator containing the String names of all notes bindings + * that exist for this session. + */ + public Iterator getNoteNames(); + + + /** + * Release all object references, and initialize instance variables, in + * preparation for reuse of this object. + */ + public void recycle(); + + + /** + * Remove any object bound to the specified name in the internal notes + * for this session. + * + * @param name Name of the note to be removed + */ + public void removeNote(String name); + + + /** + * Remove a session event listener from this component. + */ + public void removeSessionListener(SessionListener listener); + + + /** + * Bind an object to a specified name in the internal notes associated + * with this session, replacing any existing binding for this name. + * + * @param name Name to which the object should be bound + * @param value Object to be bound to the specified name + */ + public void setNote(String name, Object value); + + +} diff --git a/java/org/apache/catalina/SessionEvent.java b/java/org/apache/catalina/SessionEvent.java index f9403d3b9..eacd06c96 100644 --- a/java/org/apache/catalina/SessionEvent.java +++ b/java/org/apache/catalina/SessionEvent.java @@ -1,111 +1,111 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.util.EventObject; - - -/** - * General event for notifying listeners of significant changes on a Session. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class SessionEvent - extends EventObject { - - - /** - * The event data associated with this event. - */ - private Object data = null; - - - /** - * The Session on which this event occurred. - */ - private Session session = null; - - - /** - * The event type this instance represents. - */ - private String type = null; - - - /** - * Construct a new SessionEvent with the specified parameters. - * - * @param session Session on which this event occurred - * @param type Event type - * @param data Event data - */ - public SessionEvent(Session session, String type, Object data) { - - super(session); - this.session = session; - this.type = type; - this.data = data; - - } - - - /** - * Return the event data of this event. - */ - public Object getData() { - - return (this.data); - - } - - - /** - * Return the Session on which this event occurred. - */ - public Session getSession() { - - return (this.session); - - } - - - /** - * Return the event type of this event. - */ - public String getType() { - - return (this.type); - - } - - - /** - * Return a string representation of this event. - */ - public String toString() { - - return ("SessionEvent['" + getSession() + "','" + - getType() + "']"); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.util.EventObject; + + +/** + * General event for notifying listeners of significant changes on a Session. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class SessionEvent + extends EventObject { + + + /** + * The event data associated with this event. + */ + private Object data = null; + + + /** + * The Session on which this event occurred. + */ + private Session session = null; + + + /** + * The event type this instance represents. + */ + private String type = null; + + + /** + * Construct a new SessionEvent with the specified parameters. + * + * @param session Session on which this event occurred + * @param type Event type + * @param data Event data + */ + public SessionEvent(Session session, String type, Object data) { + + super(session); + this.session = session; + this.type = type; + this.data = data; + + } + + + /** + * Return the event data of this event. + */ + public Object getData() { + + return (this.data); + + } + + + /** + * Return the Session on which this event occurred. + */ + public Session getSession() { + + return (this.session); + + } + + + /** + * Return the event type of this event. + */ + public String getType() { + + return (this.type); + + } + + + /** + * Return a string representation of this event. + */ + public String toString() { + + return ("SessionEvent['" + getSession() + "','" + + getType() + "']"); + + } + + +} diff --git a/java/org/apache/catalina/SessionListener.java b/java/org/apache/catalina/SessionListener.java index e46ce64f0..61215b343 100644 --- a/java/org/apache/catalina/SessionListener.java +++ b/java/org/apache/catalina/SessionListener.java @@ -1,41 +1,41 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - - - -/** - * Interface defining a listener for significant Session generated events. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface SessionListener { - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event SessionEvent that has occurred - */ - public void sessionEvent(SessionEvent event); - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + + + +/** + * Interface defining a listener for significant Session generated events. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface SessionListener { + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event SessionEvent that has occurred + */ + public void sessionEvent(SessionEvent event); + + +} diff --git a/java/org/apache/catalina/Store.java b/java/org/apache/catalina/Store.java index 49245db23..92e773d6b 100644 --- a/java/org/apache/catalina/Store.java +++ b/java/org/apache/catalina/Store.java @@ -1,144 +1,144 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.beans.PropertyChangeListener; -import java.io.IOException; - - -/** - * A Store is the abstraction of a Catalina component that provides - * persistent storage and loading of Sessions and their associated user data. - * Implementations are free to save and load the Sessions to any media they - * wish, but it is assumed that saved Sessions are persistent across - * server or context restarts. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface Store { - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Store implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo(); - - - /** - * Return the Manager instance associated with this Store. - */ - public Manager getManager(); - - - /** - * Set the Manager associated with this Store. - * - * @param manager The Manager which will use this Store. - */ - public void setManager(Manager manager); - - - /** - * Return the number of Sessions present in this Store. - * - * @exception IOException if an input/output error occurs - */ - public int getSize() throws IOException; - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener); - - - /** - * Return an array containing the session identifiers of all Sessions - * currently saved in this Store. If there are no such Sessions, a - * zero-length array is returned. - * - * @exception IOException if an input/output error occurred - */ - public String[] keys() throws IOException; - - - /** - * Load and return the Session associated with the specified session - * identifier from this Store, without removing it. If there is no - * such stored Session, return null. - * - * @param id Session identifier of the session to load - * - * @exception ClassNotFoundException if a deserialization error occurs - * @exception IOException if an input/output error occurs - */ - public Session load(String id) - throws ClassNotFoundException, IOException; - - - /** - * Remove the Session with the specified session identifier from - * this Store, if present. If no such Session is present, this method - * takes no action. - * - * @param id Session identifier of the Session to be removed - * - * @exception IOException if an input/output error occurs - */ - public void remove(String id) throws IOException; - - - /** - * Remove all Sessions from this Store. - */ - public void clear() throws IOException; - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener); - - - /** - * Save the specified Session into this Store. Any previously saved - * information for the associated session identifier is replaced. - * - * @param session Session to be saved - * - * @exception IOException if an input/output error occurs - */ - public void save(Session session) throws IOException; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.beans.PropertyChangeListener; +import java.io.IOException; + + +/** + * A Store is the abstraction of a Catalina component that provides + * persistent storage and loading of Sessions and their associated user data. + * Implementations are free to save and load the Sessions to any media they + * wish, but it is assumed that saved Sessions are persistent across + * server or context restarts. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface Store { + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Store implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo(); + + + /** + * Return the Manager instance associated with this Store. + */ + public Manager getManager(); + + + /** + * Set the Manager associated with this Store. + * + * @param manager The Manager which will use this Store. + */ + public void setManager(Manager manager); + + + /** + * Return the number of Sessions present in this Store. + * + * @exception IOException if an input/output error occurs + */ + public int getSize() throws IOException; + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener); + + + /** + * Return an array containing the session identifiers of all Sessions + * currently saved in this Store. If there are no such Sessions, a + * zero-length array is returned. + * + * @exception IOException if an input/output error occurred + */ + public String[] keys() throws IOException; + + + /** + * Load and return the Session associated with the specified session + * identifier from this Store, without removing it. If there is no + * such stored Session, return null. + * + * @param id Session identifier of the session to load + * + * @exception ClassNotFoundException if a deserialization error occurs + * @exception IOException if an input/output error occurs + */ + public Session load(String id) + throws ClassNotFoundException, IOException; + + + /** + * Remove the Session with the specified session identifier from + * this Store, if present. If no such Session is present, this method + * takes no action. + * + * @param id Session identifier of the Session to be removed + * + * @exception IOException if an input/output error occurs + */ + public void remove(String id) throws IOException; + + + /** + * Remove all Sessions from this Store. + */ + public void clear() throws IOException; + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener); + + + /** + * Save the specified Session into this Store. Any previously saved + * information for the associated session identifier is replaced. + * + * @param session Session to be saved + * + * @exception IOException if an input/output error occurs + */ + public void save(Session session) throws IOException; + + +} diff --git a/java/org/apache/catalina/User.java b/java/org/apache/catalina/User.java index 15aea865e..8ae33ee54 100644 --- a/java/org/apache/catalina/User.java +++ b/java/org/apache/catalina/User.java @@ -1,173 +1,173 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.security.Principal; -import java.util.Iterator; - - -/** - *

Abstract representation of a user in a {@link UserDatabase}. Each user - * is optionally associated with a set of {@link Group}s through which he or - * she inherits additional security roles, and is optionally assigned a set - * of specific {@link Role}s.

- * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public interface User extends Principal { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the full name of this user. - */ - public String getFullName(); - - - /** - * Set the full name of this user. - * - * @param fullName The new full name - */ - public void setFullName(String fullName); - - - /** - * Return the set of {@link Group}s to which this user belongs. - */ - public Iterator getGroups(); - - - /** - * Return the logon password of this user, optionally prefixed with the - * identifier of an encoding scheme surrounded by curly braces, such as - * {md5}xxxxx. - */ - public String getPassword(); - - - /** - * Set the logon password of this user, optionally prefixed with the - * identifier of an encoding scheme surrounded by curly braces, such as - * {md5}xxxxx. - * - * @param password The new logon password - */ - public void setPassword(String password); - - - /** - * Return the set of {@link Role}s assigned specifically to this user. - */ - public Iterator getRoles(); - - - /** - * Return the {@link UserDatabase} within which this User is defined. - */ - public UserDatabase getUserDatabase(); - - - /** - * Return the logon username of this user, which must be unique - * within the scope of a {@link UserDatabase}. - */ - public String getUsername(); - - - /** - * Set the logon username of this user, which must be unique within - * the scope of a {@link UserDatabase}. - * - * @param username The new logon username - */ - public void setUsername(String username); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Group} to those this user belongs to. - * - * @param group The new group - */ - public void addGroup(Group group); - - - /** - * Add a {@link Role} to those assigned specifically to this user. - * - * @param role The new role - */ - public void addRole(Role role); - - - /** - * Is this user in the specified {@link Group}? - * - * @param group The group to check - */ - public boolean isInGroup(Group group); - - - /** - * Is this user specifically assigned the specified {@link Role}? This - * method does NOT check for roles inherited based on - * {@link Group} membership. - * - * @param role The role to check - */ - public boolean isInRole(Role role); - - - /** - * Remove a {@link Group} from those this user belongs to. - * - * @param group The old group - */ - public void removeGroup(Group group); - - - /** - * Remove all {@link Group}s from those this user belongs to. - */ - public void removeGroups(); - - - /** - * Remove a {@link Role} from those assigned to this user. - * - * @param role The old role - */ - public void removeRole(Role role); - - - /** - * Remove all {@link Role}s from those assigned to this user. - */ - public void removeRoles(); - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.security.Principal; +import java.util.Iterator; + + +/** + *

Abstract representation of a user in a {@link UserDatabase}. Each user + * is optionally associated with a set of {@link Group}s through which he or + * she inherits additional security roles, and is optionally assigned a set + * of specific {@link Role}s.

+ * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public interface User extends Principal { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the full name of this user. + */ + public String getFullName(); + + + /** + * Set the full name of this user. + * + * @param fullName The new full name + */ + public void setFullName(String fullName); + + + /** + * Return the set of {@link Group}s to which this user belongs. + */ + public Iterator getGroups(); + + + /** + * Return the logon password of this user, optionally prefixed with the + * identifier of an encoding scheme surrounded by curly braces, such as + * {md5}xxxxx. + */ + public String getPassword(); + + + /** + * Set the logon password of this user, optionally prefixed with the + * identifier of an encoding scheme surrounded by curly braces, such as + * {md5}xxxxx. + * + * @param password The new logon password + */ + public void setPassword(String password); + + + /** + * Return the set of {@link Role}s assigned specifically to this user. + */ + public Iterator getRoles(); + + + /** + * Return the {@link UserDatabase} within which this User is defined. + */ + public UserDatabase getUserDatabase(); + + + /** + * Return the logon username of this user, which must be unique + * within the scope of a {@link UserDatabase}. + */ + public String getUsername(); + + + /** + * Set the logon username of this user, which must be unique within + * the scope of a {@link UserDatabase}. + * + * @param username The new logon username + */ + public void setUsername(String username); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Group} to those this user belongs to. + * + * @param group The new group + */ + public void addGroup(Group group); + + + /** + * Add a {@link Role} to those assigned specifically to this user. + * + * @param role The new role + */ + public void addRole(Role role); + + + /** + * Is this user in the specified {@link Group}? + * + * @param group The group to check + */ + public boolean isInGroup(Group group); + + + /** + * Is this user specifically assigned the specified {@link Role}? This + * method does NOT check for roles inherited based on + * {@link Group} membership. + * + * @param role The role to check + */ + public boolean isInRole(Role role); + + + /** + * Remove a {@link Group} from those this user belongs to. + * + * @param group The old group + */ + public void removeGroup(Group group); + + + /** + * Remove all {@link Group}s from those this user belongs to. + */ + public void removeGroups(); + + + /** + * Remove a {@link Role} from those assigned to this user. + * + * @param role The old role + */ + public void removeRole(Role role); + + + /** + * Remove all {@link Role}s from those assigned to this user. + */ + public void removeRoles(); + + +} diff --git a/java/org/apache/catalina/UserDatabase.java b/java/org/apache/catalina/UserDatabase.java index e83515b20..7f96f80ae 100644 --- a/java/org/apache/catalina/UserDatabase.java +++ b/java/org/apache/catalina/UserDatabase.java @@ -1,173 +1,173 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.util.Iterator; - - -/** - *

Abstract representation of a database of {@link User}s and - * {@link Group}s that can be maintained by an application, - * along with definitions of corresponding {@link Role}s, and - * referenced by a {@link Realm} for authentication and access control.

- * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public interface UserDatabase { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the set of {@link Group}s defined in this user database. - */ - public Iterator getGroups(); - - - /** - * Return the unique global identifier of this user database. - */ - public String getId(); - - - /** - * Return the set of {@link Role}s defined in this user database. - */ - public Iterator getRoles(); - - - /** - * Return the set of {@link User}s defined in this user database. - */ - public Iterator getUsers(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Finalize access to this user database. - * - * @exception Exception if any exception is thrown during closing - */ - public void close() throws Exception; - - - /** - * Create and return a new {@link Group} defined in this user database. - * - * @param groupname The group name of the new group (must be unique) - * @param description The description of this group - */ - public Group createGroup(String groupname, String description); - - - /** - * Create and return a new {@link Role} defined in this user database. - * - * @param rolename The role name of the new role (must be unique) - * @param description The description of this role - */ - public Role createRole(String rolename, String description); - - - /** - * Create and return a new {@link User} defined in this user database. - * - * @param username The logon username of the new user (must be unique) - * @param password The logon password of the new user - * @param fullName The full name of the new user - */ - public User createUser(String username, String password, - String fullName); - - - /** - * Return the {@link Group} with the specified group name, if any; - * otherwise return null. - * - * @param groupname Name of the group to return - */ - public Group findGroup(String groupname); - - - /** - * Return the {@link Role} with the specified role name, if any; - * otherwise return null. - * - * @param rolename Name of the role to return - */ - public Role findRole(String rolename); - - - /** - * Return the {@link User} with the specified user name, if any; - * otherwise return null. - * - * @param username Name of the user to return - */ - public User findUser(String username); - - - /** - * Initialize access to this user database. - * - * @exception Exception if any exception is thrown during opening - */ - public void open() throws Exception; - - - /** - * Remove the specified {@link Group} from this user database. - * - * @param group The group to be removed - */ - public void removeGroup(Group group); - - - /** - * Remove the specified {@link Role} from this user database. - * - * @param role The role to be removed - */ - public void removeRole(Role role); - - - /** - * Remove the specified {@link User} from this user database. - * - * @param user The user to be removed - */ - public void removeUser(User user); - - - /** - * Save any updated information to the persistent storage location for - * this user database. - * - * @exception Exception if any exception is thrown during saving - */ - public void save() throws Exception; - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.util.Iterator; + + +/** + *

Abstract representation of a database of {@link User}s and + * {@link Group}s that can be maintained by an application, + * along with definitions of corresponding {@link Role}s, and + * referenced by a {@link Realm} for authentication and access control.

+ * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public interface UserDatabase { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the set of {@link Group}s defined in this user database. + */ + public Iterator getGroups(); + + + /** + * Return the unique global identifier of this user database. + */ + public String getId(); + + + /** + * Return the set of {@link Role}s defined in this user database. + */ + public Iterator getRoles(); + + + /** + * Return the set of {@link User}s defined in this user database. + */ + public Iterator getUsers(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Finalize access to this user database. + * + * @exception Exception if any exception is thrown during closing + */ + public void close() throws Exception; + + + /** + * Create and return a new {@link Group} defined in this user database. + * + * @param groupname The group name of the new group (must be unique) + * @param description The description of this group + */ + public Group createGroup(String groupname, String description); + + + /** + * Create and return a new {@link Role} defined in this user database. + * + * @param rolename The role name of the new role (must be unique) + * @param description The description of this role + */ + public Role createRole(String rolename, String description); + + + /** + * Create and return a new {@link User} defined in this user database. + * + * @param username The logon username of the new user (must be unique) + * @param password The logon password of the new user + * @param fullName The full name of the new user + */ + public User createUser(String username, String password, + String fullName); + + + /** + * Return the {@link Group} with the specified group name, if any; + * otherwise return null. + * + * @param groupname Name of the group to return + */ + public Group findGroup(String groupname); + + + /** + * Return the {@link Role} with the specified role name, if any; + * otherwise return null. + * + * @param rolename Name of the role to return + */ + public Role findRole(String rolename); + + + /** + * Return the {@link User} with the specified user name, if any; + * otherwise return null. + * + * @param username Name of the user to return + */ + public User findUser(String username); + + + /** + * Initialize access to this user database. + * + * @exception Exception if any exception is thrown during opening + */ + public void open() throws Exception; + + + /** + * Remove the specified {@link Group} from this user database. + * + * @param group The group to be removed + */ + public void removeGroup(Group group); + + + /** + * Remove the specified {@link Role} from this user database. + * + * @param role The role to be removed + */ + public void removeRole(Role role); + + + /** + * Remove the specified {@link User} from this user database. + * + * @param user The user to be removed + */ + public void removeUser(User user); + + + /** + * Save any updated information to the persistent storage location for + * this user database. + * + * @exception Exception if any exception is thrown during saving + */ + public void save() throws Exception; + + +} diff --git a/java/org/apache/catalina/Valve.java b/java/org/apache/catalina/Valve.java index 71de7a7a4..b988ac4d0 100644 --- a/java/org/apache/catalina/Valve.java +++ b/java/org/apache/catalina/Valve.java @@ -1,132 +1,132 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import java.io.IOException; -import javax.servlet.ServletException; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; - - -/** - *

A Valve is a request processing component associated with a - * particular Container. A series of Valves are generally associated with - * each other into a Pipeline. The detailed contract for a Valve is included - * in the description of the invoke() method below.

- * - * HISTORICAL NOTE: The "Valve" name was assigned to this concept - * because a valve is what you use in a real world pipeline to control and/or - * modify flows through it. - * - * @author Craig R. McClanahan - * @author Gunnar Rjnning - * @author Peter Donald - * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ - */ - -public interface Valve { - - - //-------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo(); - - - /** - * Return the next Valve in the pipeline containing this Valve, if any. - */ - public Valve getNext(); - - - /** - * Set the next Valve in the pipeline containing this Valve. - * - * @param valve The new next valve, or null if none - */ - public void setNext(Valve valve); - - - //---------------------------------------------------------- Public Methods - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess(); - - - /** - *

Perform request processing as required by this Valve.

- * - *

An individual Valve MAY perform the following actions, in - * the specified order:

- *
    - *
  • Examine and/or modify the properties of the specified Request and - * Response. - *
  • Examine the properties of the specified Request, completely generate - * the corresponding Response, and return control to the caller. - *
  • Examine the properties of the specified Request and Response, wrap - * either or both of these objects to supplement their functionality, - * and pass them on. - *
  • If the corresponding Response was not generated (and control was not - * returned, call the next Valve in the pipeline (if there is one) by - * executing context.invokeNext(). - *
  • Examine, but not modify, the properties of the resulting Response - * (which was created by a subsequently invoked Valve or Container). - *
- * - *

A Valve MUST NOT do any of the following things:

- *
    - *
  • Change request properties that have already been used to direct - * the flow of processing control for this request (for instance, - * trying to change the virtual host to which a Request should be - * sent from a pipeline attached to a Host or Context in the - * standard implementation). - *
  • Create a completed Response AND pass this - * Request and Response on to the next Valve in the pipeline. - *
  • Consume bytes from the input stream associated with the Request, - * unless it is completely generating the response, or wrapping the - * request before passing it on. - *
  • Modify the HTTP headers included with the Response after the - * invokeNext() method has returned. - *
  • Perform any actions on the output stream associated with the - * specified Response after the invokeNext() method has - * returned. - *
- * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs, or is thrown - * by a subsequently invoked Valve, Filter, or Servlet - * @exception ServletException if a servlet error occurs, or is thrown - * by a subsequently invoked Valve, Filter, or Servlet - */ - public void invoke(Request request, Response response) - throws IOException, ServletException; - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import java.io.IOException; +import javax.servlet.ServletException; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + + +/** + *

A Valve is a request processing component associated with a + * particular Container. A series of Valves are generally associated with + * each other into a Pipeline. The detailed contract for a Valve is included + * in the description of the invoke() method below.

+ * + * HISTORICAL NOTE: The "Valve" name was assigned to this concept + * because a valve is what you use in a real world pipeline to control and/or + * modify flows through it. + * + * @author Craig R. McClanahan + * @author Gunnar Rjnning + * @author Peter Donald + * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ + */ + +public interface Valve { + + + //-------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo(); + + + /** + * Return the next Valve in the pipeline containing this Valve, if any. + */ + public Valve getNext(); + + + /** + * Set the next Valve in the pipeline containing this Valve. + * + * @param valve The new next valve, or null if none + */ + public void setNext(Valve valve); + + + //---------------------------------------------------------- Public Methods + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess(); + + + /** + *

Perform request processing as required by this Valve.

+ * + *

An individual Valve MAY perform the following actions, in + * the specified order:

+ *
    + *
  • Examine and/or modify the properties of the specified Request and + * Response. + *
  • Examine the properties of the specified Request, completely generate + * the corresponding Response, and return control to the caller. + *
  • Examine the properties of the specified Request and Response, wrap + * either or both of these objects to supplement their functionality, + * and pass them on. + *
  • If the corresponding Response was not generated (and control was not + * returned, call the next Valve in the pipeline (if there is one) by + * executing context.invokeNext(). + *
  • Examine, but not modify, the properties of the resulting Response + * (which was created by a subsequently invoked Valve or Container). + *
+ * + *

A Valve MUST NOT do any of the following things:

+ *
    + *
  • Change request properties that have already been used to direct + * the flow of processing control for this request (for instance, + * trying to change the virtual host to which a Request should be + * sent from a pipeline attached to a Host or Context in the + * standard implementation). + *
  • Create a completed Response AND pass this + * Request and Response on to the next Valve in the pipeline. + *
  • Consume bytes from the input stream associated with the Request, + * unless it is completely generating the response, or wrapping the + * request before passing it on. + *
  • Modify the HTTP headers included with the Response after the + * invokeNext() method has returned. + *
  • Perform any actions on the output stream associated with the + * specified Response after the invokeNext() method has + * returned. + *
+ * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs, or is thrown + * by a subsequently invoked Valve, Filter, or Servlet + * @exception ServletException if a servlet error occurs, or is thrown + * by a subsequently invoked Valve, Filter, or Servlet + */ + public void invoke(Request request, Response response) + throws IOException, ServletException; + + +} diff --git a/java/org/apache/catalina/Wrapper.java b/java/org/apache/catalina/Wrapper.java index 57a8c3181..8950c27a1 100644 --- a/java/org/apache/catalina/Wrapper.java +++ b/java/org/apache/catalina/Wrapper.java @@ -1,330 +1,330 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina; - - -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.UnavailableException; - - -/** - * A Wrapper is a Container that represents an individual servlet - * definition from the deployment descriptor of the web application. It - * provides a convenient mechanism to use Interceptors that see every single - * request to the servlet represented by this definition. - *

- * Implementations of Wrapper are responsible for managing the servlet life - * cycle for their underlying servlet class, including calling init() and - * destroy() at appropriate times, as well as respecting the existence of - * the SingleThreadModel declaration on the servlet class itself. - *

- * The parent Container attached to a Wrapper will generally be an - * implementation of Context, representing the servlet context (and - * therefore the web application) within which this servlet executes. - *

- * Child Containers are not allowed on Wrapper implementations, so the - * addChild() method should throw an - * IllegalArgumentException. - * - * @author Craig R. McClanahan - * @version $Revision: 303442 $ $Date: 2004-10-28 00:58:17 +0200 (jeu., 28 oct. 2004) $ - */ - -public interface Wrapper extends Container { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the available date/time for this servlet, in milliseconds since - * the epoch. If this date/time is in the future, any request for this - * servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, - * the servlet is currently available. A value equal to Long.MAX_VALUE - * is considered to mean that unavailability is permanent. - */ - public long getAvailable(); - - - /** - * Set the available date/time for this servlet, in milliseconds since the - * epoch. If this date/time is in the future, any request for this servlet - * will return an SC_SERVICE_UNAVAILABLE error. A value equal to - * Long.MAX_VALUE is considered to mean that unavailability is permanent. - * - * @param available The new available date/time - */ - public void setAvailable(long available); - - - /** - * Return the context-relative URI of the JSP file for this servlet. - */ - public String getJspFile(); - - - /** - * Set the context-relative URI of the JSP file for this servlet. - * - * @param jspFile JSP file URI - */ - public void setJspFile(String jspFile); - - - /** - * Return the load-on-startup order value (negative value means - * load on first call). - */ - public int getLoadOnStartup(); - - - /** - * Set the load-on-startup order value (negative value means - * load on first call). - * - * @param value New load-on-startup value - */ - public void setLoadOnStartup(int value); - - - /** - * Return the run-as identity for this servlet. - */ - public String getRunAs(); - - - /** - * Set the run-as identity for this servlet. - * - * @param runAs New run-as identity value - */ - public void setRunAs(String runAs); - - - /** - * Return the fully qualified servlet class name for this servlet. - */ - public String getServletClass(); - - - /** - * Set the fully qualified servlet class name for this servlet. - * - * @param servletClass Servlet class name - */ - public void setServletClass(String servletClass); - - - /** - * Gets the names of the methods supported by the underlying servlet. - * - * This is the same set of methods included in the Allow response header - * in response to an OPTIONS request method processed by the underlying - * servlet. - * - * @return Array of names of the methods supported by the underlying - * servlet - */ - public String[] getServletMethods() throws ServletException; - - - /** - * Is this servlet currently unavailable? - */ - public boolean isUnavailable(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new servlet initialization parameter for this servlet. - * - * @param name Name of this initialization parameter to add - * @param value Value of this initialization parameter to add - */ - public void addInitParameter(String name, String value); - - - /** - * Add a new listener interested in InstanceEvents. - * - * @param listener The new listener - */ - public void addInstanceListener(InstanceListener listener); - - - /** - * Add a mapping associated with the Wrapper. - * - * @param mapping The new wrapper mapping - */ - public void addMapping(String mapping); - - - /** - * Add a new security role reference record to the set of records for - * this servlet. - * - * @param name Role name used within this servlet - * @param link Role name used within the web application - */ - public void addSecurityReference(String name, String link); - - - /** - * Allocate an initialized instance of this Servlet that is ready to have - * its service() method called. If the servlet class does - * not implement SingleThreadModel, the (only) initialized - * instance may be returned immediately. If the servlet class implements - * SingleThreadModel, the Wrapper implementation must ensure - * that this instance is not allocated again until it is deallocated by a - * call to deallocate(). - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if a loading error occurs - */ - public Servlet allocate() throws ServletException; - - - /** - * Return this previously allocated servlet to the pool of available - * instances. If this servlet class does not implement SingleThreadModel, - * no action is actually required. - * - * @param servlet The servlet to be returned - * - * @exception ServletException if a deallocation error occurs - */ - public void deallocate(Servlet servlet) throws ServletException; - - - /** - * Return the value for the specified initialization parameter name, - * if any; otherwise return null. - * - * @param name Name of the requested initialization parameter - */ - public String findInitParameter(String name); - - - /** - * Return the names of all defined initialization parameters for this - * servlet. - */ - public String[] findInitParameters(); - - - /** - * Return the mappings associated with this wrapper. - */ - public String[] findMappings(); - - - /** - * Return the security role link for the specified security role - * reference name, if any; otherwise return null. - * - * @param name Security role reference used within this servlet - */ - public String findSecurityReference(String name); - - - /** - * Return the set of security role reference names associated with - * this servlet, if any; otherwise return a zero-length array. - */ - public String[] findSecurityReferences(); - - - /** - * Increment the error count value used when monitoring. - */ - public void incrementErrorCount(); - - - /** - * Load and initialize an instance of this servlet, if there is not already - * at least one initialized instance. This can be used, for example, to - * load servlets that are marked in the deployment descriptor to be loaded - * at server startup time. - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if some other loading problem occurs - */ - public void load() throws ServletException; - - - /** - * Remove the specified initialization parameter from this servlet. - * - * @param name Name of the initialization parameter to remove - */ - public void removeInitParameter(String name); - - - /** - * Remove a listener no longer interested in InstanceEvents. - * - * @param listener The listener to remove - */ - public void removeInstanceListener(InstanceListener listener); - - - /** - * Remove a mapping associated with the wrapper. - * - * @param mapping The pattern to remove - */ - public void removeMapping(String mapping); - - - /** - * Remove any security role reference for the specified role name. - * - * @param name Security role used within this servlet to be removed - */ - public void removeSecurityReference(String name); - - - /** - * Process an UnavailableException, marking this servlet as unavailable - * for the specified amount of time. - * - * @param unavailable The exception that occurred, or null - * to mark this servlet as permanently unavailable - */ - public void unavailable(UnavailableException unavailable); - - - /** - * Unload all initialized instances of this servlet, after calling the - * destroy() method for each instance. This can be used, - * for example, prior to shutting down the entire servlet engine, or - * prior to reloading all of the classes from the Loader associated with - * our Loader's repository. - * - * @exception ServletException if an unload error occurs - */ - public void unload() throws ServletException; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina; + + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; + + +/** + * A Wrapper is a Container that represents an individual servlet + * definition from the deployment descriptor of the web application. It + * provides a convenient mechanism to use Interceptors that see every single + * request to the servlet represented by this definition. + *

+ * Implementations of Wrapper are responsible for managing the servlet life + * cycle for their underlying servlet class, including calling init() and + * destroy() at appropriate times, as well as respecting the existence of + * the SingleThreadModel declaration on the servlet class itself. + *

+ * The parent Container attached to a Wrapper will generally be an + * implementation of Context, representing the servlet context (and + * therefore the web application) within which this servlet executes. + *

+ * Child Containers are not allowed on Wrapper implementations, so the + * addChild() method should throw an + * IllegalArgumentException. + * + * @author Craig R. McClanahan + * @version $Revision: 303442 $ $Date: 2004-10-28 00:58:17 +0200 (jeu., 28 oct. 2004) $ + */ + +public interface Wrapper extends Container { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the available date/time for this servlet, in milliseconds since + * the epoch. If this date/time is in the future, any request for this + * servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, + * the servlet is currently available. A value equal to Long.MAX_VALUE + * is considered to mean that unavailability is permanent. + */ + public long getAvailable(); + + + /** + * Set the available date/time for this servlet, in milliseconds since the + * epoch. If this date/time is in the future, any request for this servlet + * will return an SC_SERVICE_UNAVAILABLE error. A value equal to + * Long.MAX_VALUE is considered to mean that unavailability is permanent. + * + * @param available The new available date/time + */ + public void setAvailable(long available); + + + /** + * Return the context-relative URI of the JSP file for this servlet. + */ + public String getJspFile(); + + + /** + * Set the context-relative URI of the JSP file for this servlet. + * + * @param jspFile JSP file URI + */ + public void setJspFile(String jspFile); + + + /** + * Return the load-on-startup order value (negative value means + * load on first call). + */ + public int getLoadOnStartup(); + + + /** + * Set the load-on-startup order value (negative value means + * load on first call). + * + * @param value New load-on-startup value + */ + public void setLoadOnStartup(int value); + + + /** + * Return the run-as identity for this servlet. + */ + public String getRunAs(); + + + /** + * Set the run-as identity for this servlet. + * + * @param runAs New run-as identity value + */ + public void setRunAs(String runAs); + + + /** + * Return the fully qualified servlet class name for this servlet. + */ + public String getServletClass(); + + + /** + * Set the fully qualified servlet class name for this servlet. + * + * @param servletClass Servlet class name + */ + public void setServletClass(String servletClass); + + + /** + * Gets the names of the methods supported by the underlying servlet. + * + * This is the same set of methods included in the Allow response header + * in response to an OPTIONS request method processed by the underlying + * servlet. + * + * @return Array of names of the methods supported by the underlying + * servlet + */ + public String[] getServletMethods() throws ServletException; + + + /** + * Is this servlet currently unavailable? + */ + public boolean isUnavailable(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new servlet initialization parameter for this servlet. + * + * @param name Name of this initialization parameter to add + * @param value Value of this initialization parameter to add + */ + public void addInitParameter(String name, String value); + + + /** + * Add a new listener interested in InstanceEvents. + * + * @param listener The new listener + */ + public void addInstanceListener(InstanceListener listener); + + + /** + * Add a mapping associated with the Wrapper. + * + * @param mapping The new wrapper mapping + */ + public void addMapping(String mapping); + + + /** + * Add a new security role reference record to the set of records for + * this servlet. + * + * @param name Role name used within this servlet + * @param link Role name used within the web application + */ + public void addSecurityReference(String name, String link); + + + /** + * Allocate an initialized instance of this Servlet that is ready to have + * its service() method called. If the servlet class does + * not implement SingleThreadModel, the (only) initialized + * instance may be returned immediately. If the servlet class implements + * SingleThreadModel, the Wrapper implementation must ensure + * that this instance is not allocated again until it is deallocated by a + * call to deallocate(). + * + * @exception ServletException if the servlet init() method threw + * an exception + * @exception ServletException if a loading error occurs + */ + public Servlet allocate() throws ServletException; + + + /** + * Return this previously allocated servlet to the pool of available + * instances. If this servlet class does not implement SingleThreadModel, + * no action is actually required. + * + * @param servlet The servlet to be returned + * + * @exception ServletException if a deallocation error occurs + */ + public void deallocate(Servlet servlet) throws ServletException; + + + /** + * Return the value for the specified initialization parameter name, + * if any; otherwise return null. + * + * @param name Name of the requested initialization parameter + */ + public String findInitParameter(String name); + + + /** + * Return the names of all defined initialization parameters for this + * servlet. + */ + public String[] findInitParameters(); + + + /** + * Return the mappings associated with this wrapper. + */ + public String[] findMappings(); + + + /** + * Return the security role link for the specified security role + * reference name, if any; otherwise return null. + * + * @param name Security role reference used within this servlet + */ + public String findSecurityReference(String name); + + + /** + * Return the set of security role reference names associated with + * this servlet, if any; otherwise return a zero-length array. + */ + public String[] findSecurityReferences(); + + + /** + * Increment the error count value used when monitoring. + */ + public void incrementErrorCount(); + + + /** + * Load and initialize an instance of this servlet, if there is not already + * at least one initialized instance. This can be used, for example, to + * load servlets that are marked in the deployment descriptor to be loaded + * at server startup time. + * + * @exception ServletException if the servlet init() method threw + * an exception + * @exception ServletException if some other loading problem occurs + */ + public void load() throws ServletException; + + + /** + * Remove the specified initialization parameter from this servlet. + * + * @param name Name of the initialization parameter to remove + */ + public void removeInitParameter(String name); + + + /** + * Remove a listener no longer interested in InstanceEvents. + * + * @param listener The listener to remove + */ + public void removeInstanceListener(InstanceListener listener); + + + /** + * Remove a mapping associated with the wrapper. + * + * @param mapping The pattern to remove + */ + public void removeMapping(String mapping); + + + /** + * Remove any security role reference for the specified role name. + * + * @param name Security role used within this servlet to be removed + */ + public void removeSecurityReference(String name); + + + /** + * Process an UnavailableException, marking this servlet as unavailable + * for the specified amount of time. + * + * @param unavailable The exception that occurred, or null + * to mark this servlet as permanently unavailable + */ + public void unavailable(UnavailableException unavailable); + + + /** + * Unload all initialized instances of this servlet, after calling the + * destroy() method for each instance. This can be used, + * for example, prior to shutting down the entire servlet engine, or + * prior to reloading all of the classes from the Loader associated with + * our Loader's repository. + * + * @exception ServletException if an unload error occurs + */ + public void unload() throws ServletException; + + +} diff --git a/java/org/apache/catalina/ant/AbstractCatalinaTask.java b/java/org/apache/catalina/ant/AbstractCatalinaTask.java index a10a67f9f..5e1150bc4 100644 --- a/java/org/apache/catalina/ant/AbstractCatalinaTask.java +++ b/java/org/apache/catalina/ant/AbstractCatalinaTask.java @@ -1,288 +1,288 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.BufferedOutputStream; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.HttpURLConnection; -import java.net.URL; -import java.net.URLConnection; -import org.apache.catalina.util.Base64; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; - - -/** - * Abstract base class for Ant tasks that interact with the - * Manager web application for dynamically deploying and - * undeploying applications. These tasks require Ant 1.4 or later. - * - * @author Craig R. McClanahan - * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ - * @since 4.1 - */ - -public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask { - - - // ----------------------------------------------------- Instance Variables - - - /** - * manager webapp's encoding. - */ - private static String CHARSET = "utf-8"; - - - // ------------------------------------------------------------- Properties - - - /** - * The charset used during URL encoding. - */ - protected String charset = "ISO-8859-1"; - - public String getCharset() { - return (this.charset); - } - - public void setCharset(String charset) { - this.charset = charset; - } - - - /** - * The login password for the Manager application. - */ - protected String password = null; - - public String getPassword() { - return (this.password); - } - - public void setPassword(String password) { - this.password = password; - } - - - /** - * The URL of the Manager application to be used. - */ - protected String url = "http://localhost:8080/manager"; - - public String getUrl() { - return (this.url); - } - - public void setUrl(String url) { - this.url = url; - } - - - /** - * The login username for the Manager application. - */ - protected String username = null; - - public String getUsername() { - return (this.username); - } - - public void setUsername(String username) { - this.username = username; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the specified command. This logic only performs the common - * attribute validation required by all subclasses; it does not perform - * any functional logic directly. - * - * @exception BuildException if a validation error occurs - */ - public void execute() throws BuildException { - - if ((username == null) || (password == null) || (url == null)) { - throw new BuildException - ("Must specify all of 'username', 'password', and 'url'"); - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Execute the specified command, based on the configured properties. - * - * @param command Command to be executed - * - * @exception BuildException if an error occurs - */ - public void execute(String command) throws BuildException { - - execute(command, null, null, -1); - - } - - - /** - * Execute the specified command, based on the configured properties. - * The input stream will be closed upon completion of this task, whether - * it was executed successfully or not. - * - * @param command Command to be executed - * @param istream InputStream to include in an HTTP PUT, if any - * @param contentType Content type to specify for the input, if any - * @param contentLength Content length to specify for the input, if any - * - * @exception BuildException if an error occurs - */ - public void execute(String command, InputStream istream, - String contentType, int contentLength) - throws BuildException { - - URLConnection conn = null; - InputStreamReader reader = null; - try { - - // Create a connection for this command - conn = (new URL(url + command)).openConnection(); - HttpURLConnection hconn = (HttpURLConnection) conn; - - // Set up standard connection characteristics - hconn.setAllowUserInteraction(false); - hconn.setDoInput(true); - hconn.setUseCaches(false); - if (istream != null) { - hconn.setDoOutput(true); - hconn.setRequestMethod("PUT"); - if (contentType != null) { - hconn.setRequestProperty("Content-Type", contentType); - } - if (contentLength >= 0) { - hconn.setRequestProperty("Content-Length", - "" + contentLength); - } - } else { - hconn.setDoOutput(false); - hconn.setRequestMethod("GET"); - } - hconn.setRequestProperty("User-Agent", - "Catalina-Ant-Task/1.0"); - - // Set up an authorization header with our credentials - String input = username + ":" + password; - String output = new String(Base64.encode(input.getBytes())); - hconn.setRequestProperty("Authorization", - "Basic " + output); - - // Establish the connection with the server - hconn.connect(); - - // Send the request data (if any) - if (istream != null) { - BufferedOutputStream ostream = - new BufferedOutputStream(hconn.getOutputStream(), 1024); - byte buffer[] = new byte[1024]; - while (true) { - int n = istream.read(buffer); - if (n < 0) { - break; - } - ostream.write(buffer, 0, n); - } - ostream.flush(); - ostream.close(); - istream.close(); - } - - // Process the response message - reader = new InputStreamReader(hconn.getInputStream(), CHARSET); - StringBuffer buff = new StringBuffer(); - String error = null; - int msgPriority = Project.MSG_INFO; - boolean first = true; - while (true) { - int ch = reader.read(); - if (ch < 0) { - break; - } else if ((ch == '\r') || (ch == '\n')) { - // in Win \r\n would cause handleOutput() to be called - // twice, the second time with an empty string, - // producing blank lines - if (buff.length() > 0) { - String line = buff.toString(); - buff.setLength(0); - if (first) { - if (!line.startsWith("OK -")) { - error = line; - msgPriority = Project.MSG_ERR; - } - first = false; - } - handleOutput(line, msgPriority); - } - } else { - buff.append((char) ch); - } - } - if (buff.length() > 0) { - handleOutput(buff.toString(), msgPriority); - } - if (error != null && isFailOnError()) { - // exception should be thrown only if failOnError == true - // or error line will be logged twice - throw new BuildException(error); - } - } catch (Throwable t) { - if (isFailOnError()) { - throw new BuildException(t); - } else { - handleErrorOutput(t.getMessage()); - } - } finally { - closeRedirector(); - if (reader != null) { - try { - reader.close(); - } catch (Throwable u) { - ; - } - reader = null; - } - if (istream != null) { - try { - istream.close(); - } catch (Throwable u) { - ; - } - istream = null; - } - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.BufferedOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.URLConnection; +import org.apache.catalina.util.Base64; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; + + +/** + * Abstract base class for Ant tasks that interact with the + * Manager web application for dynamically deploying and + * undeploying applications. These tasks require Ant 1.4 or later. + * + * @author Craig R. McClanahan + * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ + * @since 4.1 + */ + +public abstract class AbstractCatalinaTask extends BaseRedirectorHelperTask { + + + // ----------------------------------------------------- Instance Variables + + + /** + * manager webapp's encoding. + */ + private static String CHARSET = "utf-8"; + + + // ------------------------------------------------------------- Properties + + + /** + * The charset used during URL encoding. + */ + protected String charset = "ISO-8859-1"; + + public String getCharset() { + return (this.charset); + } + + public void setCharset(String charset) { + this.charset = charset; + } + + + /** + * The login password for the Manager application. + */ + protected String password = null; + + public String getPassword() { + return (this.password); + } + + public void setPassword(String password) { + this.password = password; + } + + + /** + * The URL of the Manager application to be used. + */ + protected String url = "http://localhost:8080/manager"; + + public String getUrl() { + return (this.url); + } + + public void setUrl(String url) { + this.url = url; + } + + + /** + * The login username for the Manager application. + */ + protected String username = null; + + public String getUsername() { + return (this.username); + } + + public void setUsername(String username) { + this.username = username; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the specified command. This logic only performs the common + * attribute validation required by all subclasses; it does not perform + * any functional logic directly. + * + * @exception BuildException if a validation error occurs + */ + public void execute() throws BuildException { + + if ((username == null) || (password == null) || (url == null)) { + throw new BuildException + ("Must specify all of 'username', 'password', and 'url'"); + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Execute the specified command, based on the configured properties. + * + * @param command Command to be executed + * + * @exception BuildException if an error occurs + */ + public void execute(String command) throws BuildException { + + execute(command, null, null, -1); + + } + + + /** + * Execute the specified command, based on the configured properties. + * The input stream will be closed upon completion of this task, whether + * it was executed successfully or not. + * + * @param command Command to be executed + * @param istream InputStream to include in an HTTP PUT, if any + * @param contentType Content type to specify for the input, if any + * @param contentLength Content length to specify for the input, if any + * + * @exception BuildException if an error occurs + */ + public void execute(String command, InputStream istream, + String contentType, int contentLength) + throws BuildException { + + URLConnection conn = null; + InputStreamReader reader = null; + try { + + // Create a connection for this command + conn = (new URL(url + command)).openConnection(); + HttpURLConnection hconn = (HttpURLConnection) conn; + + // Set up standard connection characteristics + hconn.setAllowUserInteraction(false); + hconn.setDoInput(true); + hconn.setUseCaches(false); + if (istream != null) { + hconn.setDoOutput(true); + hconn.setRequestMethod("PUT"); + if (contentType != null) { + hconn.setRequestProperty("Content-Type", contentType); + } + if (contentLength >= 0) { + hconn.setRequestProperty("Content-Length", + "" + contentLength); + } + } else { + hconn.setDoOutput(false); + hconn.setRequestMethod("GET"); + } + hconn.setRequestProperty("User-Agent", + "Catalina-Ant-Task/1.0"); + + // Set up an authorization header with our credentials + String input = username + ":" + password; + String output = new String(Base64.encode(input.getBytes())); + hconn.setRequestProperty("Authorization", + "Basic " + output); + + // Establish the connection with the server + hconn.connect(); + + // Send the request data (if any) + if (istream != null) { + BufferedOutputStream ostream = + new BufferedOutputStream(hconn.getOutputStream(), 1024); + byte buffer[] = new byte[1024]; + while (true) { + int n = istream.read(buffer); + if (n < 0) { + break; + } + ostream.write(buffer, 0, n); + } + ostream.flush(); + ostream.close(); + istream.close(); + } + + // Process the response message + reader = new InputStreamReader(hconn.getInputStream(), CHARSET); + StringBuffer buff = new StringBuffer(); + String error = null; + int msgPriority = Project.MSG_INFO; + boolean first = true; + while (true) { + int ch = reader.read(); + if (ch < 0) { + break; + } else if ((ch == '\r') || (ch == '\n')) { + // in Win \r\n would cause handleOutput() to be called + // twice, the second time with an empty string, + // producing blank lines + if (buff.length() > 0) { + String line = buff.toString(); + buff.setLength(0); + if (first) { + if (!line.startsWith("OK -")) { + error = line; + msgPriority = Project.MSG_ERR; + } + first = false; + } + handleOutput(line, msgPriority); + } + } else { + buff.append((char) ch); + } + } + if (buff.length() > 0) { + handleOutput(buff.toString(), msgPriority); + } + if (error != null && isFailOnError()) { + // exception should be thrown only if failOnError == true + // or error line will be logged twice + throw new BuildException(error); + } + } catch (Throwable t) { + if (isFailOnError()) { + throw new BuildException(t); + } else { + handleErrorOutput(t.getMessage()); + } + } finally { + closeRedirector(); + if (reader != null) { + try { + reader.close(); + } catch (Throwable u) { + ; + } + reader = null; + } + if (istream != null) { + try { + istream.close(); + } catch (Throwable u) { + ; + } + istream = null; + } + } + + } + + +} diff --git a/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java b/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java index 3efdc233b..5c8a5b4e0 100644 --- a/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java +++ b/java/org/apache/catalina/ant/BaseRedirectorHelperTask.java @@ -1,370 +1,370 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintStream; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.taskdefs.Redirector; -import org.apache.tools.ant.types.RedirectorElement; - - -/** - * Abstract base class to add output redirection support for Catalina - * Ant tasks. These tasks require Ant 1.5 or later. - *
- * WARNING: due to depends chain, Ant could call a Task - * more than once and this can affect the output redirection when configured. - * If you are collecting the output in a property, it will collect the output - * of only the first run, since Ant properties are immutable and once created - * they cannot be changed. - *
- * If you are collecting output in a file the file will be overwritten with the - * output of the last run, unless you set append="true", in which case each run - * will append it's output to the file. - * - * - * @author Gabriele Garuglieri - * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ - * @since 5.5 - */ - -public abstract class BaseRedirectorHelperTask extends Task { - - // ------------------------------------------------------------- Properties - - /** Redirector helper */ - protected Redirector redirector = new Redirector(this); - //protected Redirector redirector = null; - /** Redirector element for this task */ - protected RedirectorElement redirectorElement = null; - /** The stream for info output */ - protected OutputStream redirectOutStream = null; - /** The stream for error output */ - protected OutputStream redirectErrStream = null; - /** The print stream for info output */ - PrintStream redirectOutPrintStream = null; - /** The print stream for error output */ - PrintStream redirectErrPrintStream = null; - - /** - * Whether to fail (with a BuildException) if - * ManagerServlet returns an error. The default behavior is - * to do so. - * - * This flag does not control parameters checking. If the task is called - * with wrong or invalid parameters, it will throw BuildException - * independently from the setting of this flag. - */ - protected boolean failOnError = true; - - /** - * true true when output redirection is requested for this task . - * Default is to log on Ant log. - */ - protected boolean redirectOutput = false; - - /** - * will be set to true when the configuration of the Redirector is - * complete. - */ - protected boolean redirectorConfigured = false; - - /** - * Flag which indicates that, if redirected, output should also be - * always sent to the log. Default is that otput is sent only to - * redirected streams. - */ - protected boolean alwaysLog = false; - - /** - * Whether to fail (with a BuildException) if - * ManagerServlet returns an error. The default behavior is - * to do so. - */ - public void setFailonerror(boolean fail) { - failOnError = fail; - } - - /** - * Returns the value of the failOnError - * property. - */ - public boolean isFailOnError() { - return failOnError; - } - - - /** - * File the output of the task is redirected to. - * - * @param out name of the output file - */ - public void setOutput(File out) { - redirector.setOutput(out); - redirectOutput = true; - } - - /** - * File the error output of the task is redirected to. - * - * @param error name of the error file - * - */ - public void setError(File error) { - redirector.setError(error); - redirectOutput = true; - } - - /** - * Controls whether error output is logged. This is only useful - * when output is being redirected and error output is desired in the - * Ant log - * - * @param logError if true the standard error is sent to the Ant log system - * and not sent to output stream. - */ - public void setLogError(boolean logError) { - redirector.setLogError(logError); - redirectOutput = true; - } - - /** - * Property name whose value should be set to the output of - * the task. - * - * @param outputProperty property name - * - */ - public void setOutputproperty(String outputProperty) { - redirector.setOutputProperty(outputProperty); - redirectOutput = true; - } - - /** - * Property name whose value should be set to the error of - * the task.. - * - * @param errorProperty property name - * - */ - public void setErrorProperty(String errorProperty) { - redirector.setErrorProperty(errorProperty); - redirectOutput = true; - } - - /** - * If true, append output to existing file. - * - * @param append if true, append output to existing file - * - */ - public void setAppend(boolean append) { - redirector.setAppend(append); - redirectOutput = true; - } - - /** - * If true, (error and non-error) output will be redirected - * as specified while being sent to Ant's logging mechanism as if no - * redirection had taken place. Defaults to false. - *
- * Actually handled internally, with Ant 1.6.3 it will be handled by - * the Redirector itself. - * @param alwaysLog boolean - */ - public void setAlwaysLog(boolean alwaysLog) { - this.alwaysLog = alwaysLog; - //redirector.setAlwaysLog(alwaysLog); - redirectOutput = true; - } - - /** - * Whether output and error files should be created even when empty. - * Defaults to true. - * @param createEmptyFiles boolean. - */ - public void setCreateEmptyFiles(boolean createEmptyFiles) { - redirector.setCreateEmptyFiles(createEmptyFiles); - redirectOutput = true; - } - - /** - * Add a RedirectorElement to this task. - * @param redirectorElement RedirectorElement. - */ - public void addConfiguredRedirector(RedirectorElement redirectorElement) { - if (this.redirectorElement != null) { - throw new BuildException("Cannot have > 1 nested s"); - } else { - this.redirectorElement = redirectorElement; - } - } - - /** - * Set up properties on the Redirector from RedirectorElement if present. - */ - private void configureRedirector() { - if (redirectorElement != null) { - redirectorElement.configure(redirector); - redirectOutput = true; - } - /* - * Due to depends chain, Ant could call the Task more than once, - * this is to prevent that we attempt to configure uselessly - * more than once the Redirector. - */ - redirectorConfigured = true; - } - - /** - * Set up properties on the Redirector and create output streams. - */ - protected void openRedirector() { - if (! redirectorConfigured) { - configureRedirector(); - } - if (redirectOutput) { - redirector.createStreams(); - redirectOutStream = redirector.getOutputStream(); - redirectOutPrintStream = new PrintStream(redirectOutStream); - redirectErrStream = redirector.getErrorStream(); - redirectErrPrintStream = new PrintStream(redirectErrStream); - } - } - - /** - * Ask redirector to close all the streams. It is necessary to call this method - * before leaving the Task to have the Streams flush their contents. If you are - * collecting output in a property, it will be created only if this method is - * called, otherwise you'll find it unset. - */ - protected void closeRedirector() { - try { - if (redirectOutput) { - redirector.complete(); - } - } catch (IOException ioe) { - log("Error closing redirector: " - + ioe.getMessage(), Project.MSG_ERR); - } - /* - * Due to depends chain, Ant could call the Task more than once, - * this is to prevent that we attempt to reuse the previuosly - * closed Streams. - */ - redirectOutStream = null; - redirectOutPrintStream = null; - redirectErrStream = null; - redirectErrPrintStream = null; - } - - /** - * Handles output with the INFO priority. - * - * @param output The output to log. Should not be null. - */ - protected void handleOutput(String output) { - if (redirectOutput) { - if (redirectOutPrintStream == null) { - openRedirector(); - } - redirectOutPrintStream.println(output); - if (alwaysLog) { - log(output, Project.MSG_INFO); - } - } else { - log(output, Project.MSG_INFO); - } - } - - /** - * Handles output with the INFO priority and flushes the stream. - * - * @param output The output to log. Should not be null. - * - */ - protected void handleFlush(String output) { - handleOutput(output); - redirectOutPrintStream.flush(); - } - - /** - * Handles error output with the ERR priority. - * - * @param output The error output to log. Should not be null. - */ - protected void handleErrorOutput(String output) { - if (redirectOutput) { - if (redirectErrPrintStream == null) { - openRedirector(); - } - redirectErrPrintStream.println(output); - if (alwaysLog) { - log(output, Project.MSG_ERR); - } - } else { - log(output, Project.MSG_ERR); - } - } - - /** - * Handles error output with the ERR priority and flushes the stream. - * - * @param output The error output to log. Should not be null. - * - */ - protected void handleErrorFlush(String output) { - handleErrorOutput(output); - redirectErrPrintStream.flush(); - } - - /** - * Handles output with ERR priority to error stream and all other - * pritorities to output stream. - * - * @param output The output to log. Should not be null. - */ - protected void handleOutput(String output, int priority) { - if (priority == Project.MSG_ERR) { - handleErrorOutput(output); - } else { - handleOutput(output); - } - } - - /** - * Handles output with ERR priority to error stream and all other - * pritorities to output stream, then flushes the stream. - * - * @param output The output to log. Should not be null. - */ - protected void handleFlush(String output, int priority) { - if (priority == Project.MSG_ERR) { - handleErrorFlush(output); - } else { - handleFlush(output); - } - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintStream; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.Task; +import org.apache.tools.ant.taskdefs.Redirector; +import org.apache.tools.ant.types.RedirectorElement; + + +/** + * Abstract base class to add output redirection support for Catalina + * Ant tasks. These tasks require Ant 1.5 or later. + *
+ * WARNING: due to depends chain, Ant could call a Task + * more than once and this can affect the output redirection when configured. + * If you are collecting the output in a property, it will collect the output + * of only the first run, since Ant properties are immutable and once created + * they cannot be changed. + *
+ * If you are collecting output in a file the file will be overwritten with the + * output of the last run, unless you set append="true", in which case each run + * will append it's output to the file. + * + * + * @author Gabriele Garuglieri + * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ + * @since 5.5 + */ + +public abstract class BaseRedirectorHelperTask extends Task { + + // ------------------------------------------------------------- Properties + + /** Redirector helper */ + protected Redirector redirector = new Redirector(this); + //protected Redirector redirector = null; + /** Redirector element for this task */ + protected RedirectorElement redirectorElement = null; + /** The stream for info output */ + protected OutputStream redirectOutStream = null; + /** The stream for error output */ + protected OutputStream redirectErrStream = null; + /** The print stream for info output */ + PrintStream redirectOutPrintStream = null; + /** The print stream for error output */ + PrintStream redirectErrPrintStream = null; + + /** + * Whether to fail (with a BuildException) if + * ManagerServlet returns an error. The default behavior is + * to do so. + * + * This flag does not control parameters checking. If the task is called + * with wrong or invalid parameters, it will throw BuildException + * independently from the setting of this flag. + */ + protected boolean failOnError = true; + + /** + * true true when output redirection is requested for this task . + * Default is to log on Ant log. + */ + protected boolean redirectOutput = false; + + /** + * will be set to true when the configuration of the Redirector is + * complete. + */ + protected boolean redirectorConfigured = false; + + /** + * Flag which indicates that, if redirected, output should also be + * always sent to the log. Default is that otput is sent only to + * redirected streams. + */ + protected boolean alwaysLog = false; + + /** + * Whether to fail (with a BuildException) if + * ManagerServlet returns an error. The default behavior is + * to do so. + */ + public void setFailonerror(boolean fail) { + failOnError = fail; + } + + /** + * Returns the value of the failOnError + * property. + */ + public boolean isFailOnError() { + return failOnError; + } + + + /** + * File the output of the task is redirected to. + * + * @param out name of the output file + */ + public void setOutput(File out) { + redirector.setOutput(out); + redirectOutput = true; + } + + /** + * File the error output of the task is redirected to. + * + * @param error name of the error file + * + */ + public void setError(File error) { + redirector.setError(error); + redirectOutput = true; + } + + /** + * Controls whether error output is logged. This is only useful + * when output is being redirected and error output is desired in the + * Ant log + * + * @param logError if true the standard error is sent to the Ant log system + * and not sent to output stream. + */ + public void setLogError(boolean logError) { + redirector.setLogError(logError); + redirectOutput = true; + } + + /** + * Property name whose value should be set to the output of + * the task. + * + * @param outputProperty property name + * + */ + public void setOutputproperty(String outputProperty) { + redirector.setOutputProperty(outputProperty); + redirectOutput = true; + } + + /** + * Property name whose value should be set to the error of + * the task.. + * + * @param errorProperty property name + * + */ + public void setErrorProperty(String errorProperty) { + redirector.setErrorProperty(errorProperty); + redirectOutput = true; + } + + /** + * If true, append output to existing file. + * + * @param append if true, append output to existing file + * + */ + public void setAppend(boolean append) { + redirector.setAppend(append); + redirectOutput = true; + } + + /** + * If true, (error and non-error) output will be redirected + * as specified while being sent to Ant's logging mechanism as if no + * redirection had taken place. Defaults to false. + *
+ * Actually handled internally, with Ant 1.6.3 it will be handled by + * the Redirector itself. + * @param alwaysLog boolean + */ + public void setAlwaysLog(boolean alwaysLog) { + this.alwaysLog = alwaysLog; + //redirector.setAlwaysLog(alwaysLog); + redirectOutput = true; + } + + /** + * Whether output and error files should be created even when empty. + * Defaults to true. + * @param createEmptyFiles boolean. + */ + public void setCreateEmptyFiles(boolean createEmptyFiles) { + redirector.setCreateEmptyFiles(createEmptyFiles); + redirectOutput = true; + } + + /** + * Add a RedirectorElement to this task. + * @param redirectorElement RedirectorElement. + */ + public void addConfiguredRedirector(RedirectorElement redirectorElement) { + if (this.redirectorElement != null) { + throw new BuildException("Cannot have > 1 nested s"); + } else { + this.redirectorElement = redirectorElement; + } + } + + /** + * Set up properties on the Redirector from RedirectorElement if present. + */ + private void configureRedirector() { + if (redirectorElement != null) { + redirectorElement.configure(redirector); + redirectOutput = true; + } + /* + * Due to depends chain, Ant could call the Task more than once, + * this is to prevent that we attempt to configure uselessly + * more than once the Redirector. + */ + redirectorConfigured = true; + } + + /** + * Set up properties on the Redirector and create output streams. + */ + protected void openRedirector() { + if (! redirectorConfigured) { + configureRedirector(); + } + if (redirectOutput) { + redirector.createStreams(); + redirectOutStream = redirector.getOutputStream(); + redirectOutPrintStream = new PrintStream(redirectOutStream); + redirectErrStream = redirector.getErrorStream(); + redirectErrPrintStream = new PrintStream(redirectErrStream); + } + } + + /** + * Ask redirector to close all the streams. It is necessary to call this method + * before leaving the Task to have the Streams flush their contents. If you are + * collecting output in a property, it will be created only if this method is + * called, otherwise you'll find it unset. + */ + protected void closeRedirector() { + try { + if (redirectOutput) { + redirector.complete(); + } + } catch (IOException ioe) { + log("Error closing redirector: " + + ioe.getMessage(), Project.MSG_ERR); + } + /* + * Due to depends chain, Ant could call the Task more than once, + * this is to prevent that we attempt to reuse the previuosly + * closed Streams. + */ + redirectOutStream = null; + redirectOutPrintStream = null; + redirectErrStream = null; + redirectErrPrintStream = null; + } + + /** + * Handles output with the INFO priority. + * + * @param output The output to log. Should not be null. + */ + protected void handleOutput(String output) { + if (redirectOutput) { + if (redirectOutPrintStream == null) { + openRedirector(); + } + redirectOutPrintStream.println(output); + if (alwaysLog) { + log(output, Project.MSG_INFO); + } + } else { + log(output, Project.MSG_INFO); + } + } + + /** + * Handles output with the INFO priority and flushes the stream. + * + * @param output The output to log. Should not be null. + * + */ + protected void handleFlush(String output) { + handleOutput(output); + redirectOutPrintStream.flush(); + } + + /** + * Handles error output with the ERR priority. + * + * @param output The error output to log. Should not be null. + */ + protected void handleErrorOutput(String output) { + if (redirectOutput) { + if (redirectErrPrintStream == null) { + openRedirector(); + } + redirectErrPrintStream.println(output); + if (alwaysLog) { + log(output, Project.MSG_ERR); + } + } else { + log(output, Project.MSG_ERR); + } + } + + /** + * Handles error output with the ERR priority and flushes the stream. + * + * @param output The error output to log. Should not be null. + * + */ + protected void handleErrorFlush(String output) { + handleErrorOutput(output); + redirectErrPrintStream.flush(); + } + + /** + * Handles output with ERR priority to error stream and all other + * pritorities to output stream. + * + * @param output The output to log. Should not be null. + */ + protected void handleOutput(String output, int priority) { + if (priority == Project.MSG_ERR) { + handleErrorOutput(output); + } else { + handleOutput(output); + } + } + + /** + * Handles output with ERR priority to error stream and all other + * pritorities to output stream, then flushes the stream. + * + * @param output The output to log. Should not be null. + */ + protected void handleFlush(String output, int priority) { + if (priority == Project.MSG_ERR) { + handleErrorFlush(output); + } else { + handleFlush(output); + } + } + +} diff --git a/java/org/apache/catalina/ant/DeployTask.java b/java/org/apache/catalina/ant/DeployTask.java index 10d423214..62b32ed27 100644 --- a/java/org/apache/catalina/ant/DeployTask.java +++ b/java/org/apache/catalina/ant/DeployTask.java @@ -1,205 +1,205 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.BufferedInputStream; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /deploy command, supported by - * the Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ - * @since 4.1 - */ -public class DeployTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * URL of the context configuration file for this application, if any. - */ - protected String config = null; - - public String getConfig() { - return (this.config); - } - - public void setConfig(String config) { - this.config = config; - } - - - /** - * URL of the server local web application archive (WAR) file - * to be deployed. - */ - protected String localWar = null; - - public String getLocalWar() { - return (this.localWar); - } - - public void setLocalWar(String localWar) { - this.localWar = localWar; - } - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - /** - * Tag to associate with this to be deployed webapp. - */ - protected String tag = null; - - public String getTag() { - return (this.tag); - } - - public void setTag(String tag) { - this.tag = tag; - } - - - /** - * Update existing webapps. - */ - protected boolean update = false; - - public boolean getUpdate() { - return (this.update); - } - - public void setUpdate(boolean update) { - this.update = update; - } - - - /** - * URL of the web application archive (WAR) file to be deployed. - */ - protected String war = null; - - public String getWar() { - return (this.war); - } - - public void setWar(String war) { - this.war = war; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - if ((war == null) && (localWar == null) && (config == null) && (tag == null)) { - throw new BuildException - ("Must specify either 'war', 'localWar', 'config', or 'tag' attribute"); - } - - // Building an input stream on the WAR to upload, if any - BufferedInputStream stream = null; - String contentType = null; - int contentLength = -1; - if (war != null) { - if (war.startsWith("file:")) { - try { - URL url = new URL(war); - URLConnection conn = url.openConnection(); - contentLength = conn.getContentLength(); - stream = new BufferedInputStream - (conn.getInputStream(), 1024); - } catch (IOException e) { - throw new BuildException(e); - } - } else { - try { - stream = new BufferedInputStream - (new FileInputStream(war), 1024); - } catch (IOException e) { - throw new BuildException(e); - } - } - contentType = "application/octet-stream"; - } - - // Building URL - StringBuffer sb = new StringBuffer("/deploy?path="); - try { - sb.append(URLEncoder.encode(this.path, getCharset())); - if ((war == null) && (config != null)) { - sb.append("&config="); - sb.append(URLEncoder.encode(config, getCharset())); - } - if ((war == null) && (localWar != null)) { - sb.append("&war="); - sb.append(URLEncoder.encode(localWar, getCharset())); - } - if (update) { - sb.append("&update=true"); - } - if (tag != null) { - sb.append("&tag="); - sb.append(URLEncoder.encode(tag, getCharset())); - } - } catch (UnsupportedEncodingException e) { - throw new BuildException("Invalid 'charset' attribute: " + getCharset()); - } - - execute(sb.toString(), stream, contentType, contentLength); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /deploy command, supported by + * the Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ + * @since 4.1 + */ +public class DeployTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * URL of the context configuration file for this application, if any. + */ + protected String config = null; + + public String getConfig() { + return (this.config); + } + + public void setConfig(String config) { + this.config = config; + } + + + /** + * URL of the server local web application archive (WAR) file + * to be deployed. + */ + protected String localWar = null; + + public String getLocalWar() { + return (this.localWar); + } + + public void setLocalWar(String localWar) { + this.localWar = localWar; + } + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + /** + * Tag to associate with this to be deployed webapp. + */ + protected String tag = null; + + public String getTag() { + return (this.tag); + } + + public void setTag(String tag) { + this.tag = tag; + } + + + /** + * Update existing webapps. + */ + protected boolean update = false; + + public boolean getUpdate() { + return (this.update); + } + + public void setUpdate(boolean update) { + this.update = update; + } + + + /** + * URL of the web application archive (WAR) file to be deployed. + */ + protected String war = null; + + public String getWar() { + return (this.war); + } + + public void setWar(String war) { + this.war = war; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + if ((war == null) && (localWar == null) && (config == null) && (tag == null)) { + throw new BuildException + ("Must specify either 'war', 'localWar', 'config', or 'tag' attribute"); + } + + // Building an input stream on the WAR to upload, if any + BufferedInputStream stream = null; + String contentType = null; + int contentLength = -1; + if (war != null) { + if (war.startsWith("file:")) { + try { + URL url = new URL(war); + URLConnection conn = url.openConnection(); + contentLength = conn.getContentLength(); + stream = new BufferedInputStream + (conn.getInputStream(), 1024); + } catch (IOException e) { + throw new BuildException(e); + } + } else { + try { + stream = new BufferedInputStream + (new FileInputStream(war), 1024); + } catch (IOException e) { + throw new BuildException(e); + } + } + contentType = "application/octet-stream"; + } + + // Building URL + StringBuffer sb = new StringBuffer("/deploy?path="); + try { + sb.append(URLEncoder.encode(this.path, getCharset())); + if ((war == null) && (config != null)) { + sb.append("&config="); + sb.append(URLEncoder.encode(config, getCharset())); + } + if ((war == null) && (localWar != null)) { + sb.append("&war="); + sb.append(URLEncoder.encode(localWar, getCharset())); + } + if (update) { + sb.append("&update=true"); + } + if (tag != null) { + sb.append("&tag="); + sb.append(URLEncoder.encode(tag, getCharset())); + } + } catch (UnsupportedEncodingException e) { + throw new BuildException("Invalid 'charset' attribute: " + getCharset()); + } + + execute(sb.toString(), stream, contentType, contentLength); + + } + + +} diff --git a/java/org/apache/catalina/ant/InstallTask.java b/java/org/apache/catalina/ant/InstallTask.java index 287d7eccc..2dffe2ed7 100644 --- a/java/org/apache/catalina/ant/InstallTask.java +++ b/java/org/apache/catalina/ant/InstallTask.java @@ -1,118 +1,118 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /install command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - * @deprecated Replaced by DeployTask - */ -public class InstallTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * URL of the context configuration file for this application, if any. - */ - protected String config = null; - - public String getConfig() { - return (this.config); - } - - public void setConfig(String config) { - this.config = config; - } - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - /** - * URL of the web application archive (WAR) file, or the unpacked directory - * containing this application, if any. - */ - protected String war = null; - - public String getWar() { - return (this.war); - } - - public void setWar(String war) { - this.war = war; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - if ((config == null) && (war == null)) { - throw new BuildException - ("Must specify at least one of 'config' and 'war'"); - } - StringBuffer sb = new StringBuffer("/install?path="); - sb.append(URLEncoder.encode(this.path)); - if (config != null) { - sb.append("&config="); - sb.append(URLEncoder.encode(config)); - } - if (war != null) { - sb.append("&war="); - sb.append(URLEncoder.encode(war)); - } - execute(sb.toString()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /install command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + * @deprecated Replaced by DeployTask + */ +public class InstallTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * URL of the context configuration file for this application, if any. + */ + protected String config = null; + + public String getConfig() { + return (this.config); + } + + public void setConfig(String config) { + this.config = config; + } + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + /** + * URL of the web application archive (WAR) file, or the unpacked directory + * containing this application, if any. + */ + protected String war = null; + + public String getWar() { + return (this.war); + } + + public void setWar(String war) { + this.war = war; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + if ((config == null) && (war == null)) { + throw new BuildException + ("Must specify at least one of 'config' and 'war'"); + } + StringBuffer sb = new StringBuffer("/install?path="); + sb.append(URLEncoder.encode(this.path)); + if (config != null) { + sb.append("&config="); + sb.append(URLEncoder.encode(config)); + } + if (war != null) { + sb.append("&war="); + sb.append(URLEncoder.encode(war)); + } + execute(sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/ant/JKStatusUpdateTask.java b/java/org/apache/catalina/ant/JKStatusUpdateTask.java index 81ef5e984..ff4ea312e 100644 --- a/java/org/apache/catalina/ant/JKStatusUpdateTask.java +++ b/java/org/apache/catalina/ant/JKStatusUpdateTask.java @@ -1,415 +1,415 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ant; - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - -/** - * Ant task that implements the /status command, supported by the - * mod_jk status (1.2.9) application. - * - * @author Peter Rossbach - * @version $Revision: 303886 $ - * @since 5.5.9 - */ -public class JKStatusUpdateTask extends AbstractCatalinaTask { - - private String worker = "lb"; - - private String workerType = "lb"; - - private int internalid = 0; - - private Integer lbRetries; - - private Integer lbRecovertime; - - private Boolean lbStickySession = Boolean.TRUE; - - private Boolean lbForceSession = Boolean.FALSE; - - private Integer workerLoadFactor; - - private String workerRedirect; - - private String workerClusterDomain; - - private Boolean workerDisabled = Boolean.FALSE; - - private Boolean workerStopped = Boolean.FALSE; - - private boolean isLBMode = true; - - private String workerLb; - - /** - * - */ - public JKStatusUpdateTask() { - super(); - setUrl("http://localhost/status"); - } - - /** - * @return Returns the internalid. - */ - public int getInternalid() { - return internalid; - } - - /** - * @param internalid - * The internalid to set. - */ - public void setInternalid(int internalid) { - this.internalid = internalid; - } - - /** - * @return Returns the lbForceSession. - */ - public Boolean getLbForceSession() { - return lbForceSession; - } - - /** - * @param lbForceSession - * The lbForceSession to set. - */ - public void setLbForceSession(Boolean lbForceSession) { - this.lbForceSession = lbForceSession; - } - - /** - * @return Returns the lbRecovertime. - */ - public Integer getLbRecovertime() { - return lbRecovertime; - } - - /** - * @param lbRecovertime - * The lbRecovertime to set. - */ - public void setLbRecovertime(Integer lbRecovertime) { - this.lbRecovertime = lbRecovertime; - } - - /** - * @return Returns the lbRetries. - */ - public Integer getLbRetries() { - return lbRetries; - } - - /** - * @param lbRetries - * The lbRetries to set. - */ - public void setLbRetries(Integer lbRetries) { - this.lbRetries = lbRetries; - } - - /** - * @return Returns the lbStickySession. - */ - public Boolean getLbStickySession() { - return lbStickySession; - } - - /** - * @param lbStickySession - * The lbStickySession to set. - */ - public void setLbStickySession(Boolean lbStickySession) { - this.lbStickySession = lbStickySession; - } - - /** - * @return Returns the worker. - */ - public String getWorker() { - return worker; - } - - /** - * @param worker - * The worker to set. - */ - public void setWorker(String worker) { - this.worker = worker; - } - - /** - * @return Returns the workerType. - */ - public String getWorkerType() { - return workerType; - } - - /** - * @param workerType - * The workerType to set. - */ - public void setWorkerType(String workerType) { - this.workerType = workerType; - } - - /** - * @return Returns the workerLb. - */ - public String getWorkerLb() { - return workerLb; - } - - /** - * @param workerLb - * The workerLb to set. - */ - public void setWorkerLb(String workerLb) { - this.workerLb = workerLb; - } - - /** - * @return Returns the workerClusterDomain. - */ - public String getWorkerClusterDomain() { - return workerClusterDomain; - } - - /** - * @param workerClusterDomain - * The workerClusterDomain to set. - */ - public void setWorkerClusterDomain(String workerClusterDomain) { - this.workerClusterDomain = workerClusterDomain; - } - - /** - * @return Returns the workerDisabled. - */ - public Boolean getWorkerDisabled() { - return workerDisabled; - } - - /** - * @param workerDisabled - * The workerDisabled to set. - */ - public void setWorkerDisabled(Boolean workerDisabled) { - this.workerDisabled = workerDisabled; - } - - /** - * @return Returns the workerStopped. - */ - public Boolean getWorkerStopped() { - return workerStopped; - } - - /** - * @param workerStopped The workerStopped to set. - */ - public void setWorkerStopped(Boolean workerStopped) { - this.workerStopped = workerStopped; - } - - /** - * @return Returns the workerLoadFactor. - */ - public Integer getWorkerLoadFactor() { - return workerLoadFactor; - } - - /** - * @param workerLoadFactor - * The workerLoadFactor to set. - */ - public void setWorkerLoadFactor(Integer workerLoadFactor) { - this.workerLoadFactor = workerLoadFactor; - } - - /** - * @return Returns the workerRedirect. - */ - public String getWorkerRedirect() { - return workerRedirect; - } - - /** - * @param workerRedirect - * The workerRedirect to set. - */ - public void setWorkerRedirect(String workerRedirect) { - this.workerRedirect = workerRedirect; - } - - /** - * Execute the requested operation. - * - * @exception BuildException - * if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - checkParameter(); - StringBuffer sb = createLink(); - execute(sb.toString(), null, null, -1); - - } - - /** - * Create JkStatus link - *

    - *
  • load balance example: - * http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true
  • - *
  • worker example: - * http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false - *
  • - *
- * - * @return create jkstatus link - */ - private StringBuffer createLink() { - // Building URL - StringBuffer sb = new StringBuffer(); - try { - sb.append("?cmd=update&mime=txt"); - sb.append("&w="); - sb.append(URLEncoder.encode(worker, getCharset())); - - if (isLBMode) { - //http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true - if ((lbRetries != null)) { // > 0 - sb.append("&lr="); - sb.append(lbRetries); - } - if ((lbRecovertime != null)) { // > 59 - sb.append("<="); - sb.append(lbRecovertime); - } - if ((lbStickySession != null)) { - sb.append("&ls="); - sb.append(lbStickySession); - } - if ((lbForceSession != null)) { - sb.append("&lf="); - sb.append(lbForceSession); - } - } else { - //http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false - if ((workerLb != null)) { // must be configured - sb.append("&l="); - sb.append(URLEncoder.encode(workerLb, getCharset())); - } - if ((workerLoadFactor != null)) { // >= 1 - sb.append("&wf="); - sb.append(workerLoadFactor); - } - if ((workerDisabled != null)) { - sb.append("&wd="); - sb.append(workerDisabled); - } - if ((workerStopped != null)) { - sb.append("&ws="); - sb.append(workerStopped); - } - if ((workerRedirect != null)) { // other worker conrecte lb's - sb.append("&wr="); - } - if ((workerClusterDomain != null)) { - sb.append("&wc="); - sb.append(URLEncoder.encode(workerClusterDomain, - getCharset())); - } - } - - } catch (UnsupportedEncodingException e) { - throw new BuildException("Invalid 'charset' attribute: " - + getCharset()); - } - return sb; - } - - /** - * check correct lb and worker pararmeter - */ - protected void checkParameter() { - if (worker == null) { - throw new BuildException("Must specify 'worker' attribute"); - } - if (workerType == null) { - throw new BuildException("Must specify 'workerType' attribute"); - } - if ("lb".equals(workerType)) { - if (lbRecovertime == null && lbRetries == null) { - throw new BuildException( - "Must specify at a lb worker either 'lbRecovertime' or" - + "'lbRetries' attribute"); - } - if (lbStickySession == null || lbForceSession == null) { - throw new BuildException("Must specify at a lb worker either" - + "'lbStickySession' and 'lbForceSession' attribute"); - } - if (null != lbRecovertime && 60 < lbRecovertime.intValue()) { - throw new BuildException( - "The 'lbRecovertime' must be greater than 59"); - } - if (null != lbRetries && 1 < lbRetries.intValue()) { - throw new BuildException( - "The 'lbRetries' must be greater than 1"); - } - isLBMode = true; - } else if ("worker".equals(workerType)) { - if (workerDisabled == null) { - throw new BuildException( - "Must specify at a node worker 'workerDisabled' attribute"); - } - if (workerStopped == null) { - throw new BuildException( - "Must specify at a node worker 'workerStopped' attribute"); - } - if (workerLoadFactor == null ) { - throw new BuildException( - "Must specify at a node worker 'workerLoadFactor' attribute"); - } - if (workerClusterDomain == null) { - throw new BuildException( - "Must specify at a node worker 'workerClusterDomain' attribute"); - } - if (workerRedirect == null) { - throw new BuildException( - "Must specify at a node worker 'workerRedirect' attribute"); - } - if (workerLb == null) { - throw new BuildException("Must specify 'workerLb' attribute"); - } - if (workerLoadFactor.intValue() < 1) { - throw new BuildException( - "The 'workerLoadFactor' must be greater or equal 1"); - } - isLBMode = false; - } else { - throw new BuildException( - "Only 'lb' and 'worker' supported as workerType attribute"); - } - } +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ant; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + +/** + * Ant task that implements the /status command, supported by the + * mod_jk status (1.2.9) application. + * + * @author Peter Rossbach + * @version $Revision: 303886 $ + * @since 5.5.9 + */ +public class JKStatusUpdateTask extends AbstractCatalinaTask { + + private String worker = "lb"; + + private String workerType = "lb"; + + private int internalid = 0; + + private Integer lbRetries; + + private Integer lbRecovertime; + + private Boolean lbStickySession = Boolean.TRUE; + + private Boolean lbForceSession = Boolean.FALSE; + + private Integer workerLoadFactor; + + private String workerRedirect; + + private String workerClusterDomain; + + private Boolean workerDisabled = Boolean.FALSE; + + private Boolean workerStopped = Boolean.FALSE; + + private boolean isLBMode = true; + + private String workerLb; + + /** + * + */ + public JKStatusUpdateTask() { + super(); + setUrl("http://localhost/status"); + } + + /** + * @return Returns the internalid. + */ + public int getInternalid() { + return internalid; + } + + /** + * @param internalid + * The internalid to set. + */ + public void setInternalid(int internalid) { + this.internalid = internalid; + } + + /** + * @return Returns the lbForceSession. + */ + public Boolean getLbForceSession() { + return lbForceSession; + } + + /** + * @param lbForceSession + * The lbForceSession to set. + */ + public void setLbForceSession(Boolean lbForceSession) { + this.lbForceSession = lbForceSession; + } + + /** + * @return Returns the lbRecovertime. + */ + public Integer getLbRecovertime() { + return lbRecovertime; + } + + /** + * @param lbRecovertime + * The lbRecovertime to set. + */ + public void setLbRecovertime(Integer lbRecovertime) { + this.lbRecovertime = lbRecovertime; + } + + /** + * @return Returns the lbRetries. + */ + public Integer getLbRetries() { + return lbRetries; + } + + /** + * @param lbRetries + * The lbRetries to set. + */ + public void setLbRetries(Integer lbRetries) { + this.lbRetries = lbRetries; + } + + /** + * @return Returns the lbStickySession. + */ + public Boolean getLbStickySession() { + return lbStickySession; + } + + /** + * @param lbStickySession + * The lbStickySession to set. + */ + public void setLbStickySession(Boolean lbStickySession) { + this.lbStickySession = lbStickySession; + } + + /** + * @return Returns the worker. + */ + public String getWorker() { + return worker; + } + + /** + * @param worker + * The worker to set. + */ + public void setWorker(String worker) { + this.worker = worker; + } + + /** + * @return Returns the workerType. + */ + public String getWorkerType() { + return workerType; + } + + /** + * @param workerType + * The workerType to set. + */ + public void setWorkerType(String workerType) { + this.workerType = workerType; + } + + /** + * @return Returns the workerLb. + */ + public String getWorkerLb() { + return workerLb; + } + + /** + * @param workerLb + * The workerLb to set. + */ + public void setWorkerLb(String workerLb) { + this.workerLb = workerLb; + } + + /** + * @return Returns the workerClusterDomain. + */ + public String getWorkerClusterDomain() { + return workerClusterDomain; + } + + /** + * @param workerClusterDomain + * The workerClusterDomain to set. + */ + public void setWorkerClusterDomain(String workerClusterDomain) { + this.workerClusterDomain = workerClusterDomain; + } + + /** + * @return Returns the workerDisabled. + */ + public Boolean getWorkerDisabled() { + return workerDisabled; + } + + /** + * @param workerDisabled + * The workerDisabled to set. + */ + public void setWorkerDisabled(Boolean workerDisabled) { + this.workerDisabled = workerDisabled; + } + + /** + * @return Returns the workerStopped. + */ + public Boolean getWorkerStopped() { + return workerStopped; + } + + /** + * @param workerStopped The workerStopped to set. + */ + public void setWorkerStopped(Boolean workerStopped) { + this.workerStopped = workerStopped; + } + + /** + * @return Returns the workerLoadFactor. + */ + public Integer getWorkerLoadFactor() { + return workerLoadFactor; + } + + /** + * @param workerLoadFactor + * The workerLoadFactor to set. + */ + public void setWorkerLoadFactor(Integer workerLoadFactor) { + this.workerLoadFactor = workerLoadFactor; + } + + /** + * @return Returns the workerRedirect. + */ + public String getWorkerRedirect() { + return workerRedirect; + } + + /** + * @param workerRedirect + * The workerRedirect to set. + */ + public void setWorkerRedirect(String workerRedirect) { + this.workerRedirect = workerRedirect; + } + + /** + * Execute the requested operation. + * + * @exception BuildException + * if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + checkParameter(); + StringBuffer sb = createLink(); + execute(sb.toString(), null, null, -1); + + } + + /** + * Create JkStatus link + *
    + *
  • load balance example: + * http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true
  • + *
  • worker example: + * http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false + *
  • + *
+ * + * @return create jkstatus link + */ + private StringBuffer createLink() { + // Building URL + StringBuffer sb = new StringBuffer(); + try { + sb.append("?cmd=update&mime=txt"); + sb.append("&w="); + sb.append(URLEncoder.encode(worker, getCharset())); + + if (isLBMode) { + //http://localhost/status?cmd=update&mime=txt&w=lb&lf=false&ls=true + if ((lbRetries != null)) { // > 0 + sb.append("&lr="); + sb.append(lbRetries); + } + if ((lbRecovertime != null)) { // > 59 + sb.append("<="); + sb.append(lbRecovertime); + } + if ((lbStickySession != null)) { + sb.append("&ls="); + sb.append(lbStickySession); + } + if ((lbForceSession != null)) { + sb.append("&lf="); + sb.append(lbForceSession); + } + } else { + //http://localhost/status?cmd=update&mime=txt&w=node1&l=lb&wf=1&wd=false&ws=false + if ((workerLb != null)) { // must be configured + sb.append("&l="); + sb.append(URLEncoder.encode(workerLb, getCharset())); + } + if ((workerLoadFactor != null)) { // >= 1 + sb.append("&wf="); + sb.append(workerLoadFactor); + } + if ((workerDisabled != null)) { + sb.append("&wd="); + sb.append(workerDisabled); + } + if ((workerStopped != null)) { + sb.append("&ws="); + sb.append(workerStopped); + } + if ((workerRedirect != null)) { // other worker conrecte lb's + sb.append("&wr="); + } + if ((workerClusterDomain != null)) { + sb.append("&wc="); + sb.append(URLEncoder.encode(workerClusterDomain, + getCharset())); + } + } + + } catch (UnsupportedEncodingException e) { + throw new BuildException("Invalid 'charset' attribute: " + + getCharset()); + } + return sb; + } + + /** + * check correct lb and worker pararmeter + */ + protected void checkParameter() { + if (worker == null) { + throw new BuildException("Must specify 'worker' attribute"); + } + if (workerType == null) { + throw new BuildException("Must specify 'workerType' attribute"); + } + if ("lb".equals(workerType)) { + if (lbRecovertime == null && lbRetries == null) { + throw new BuildException( + "Must specify at a lb worker either 'lbRecovertime' or" + + "'lbRetries' attribute"); + } + if (lbStickySession == null || lbForceSession == null) { + throw new BuildException("Must specify at a lb worker either" + + "'lbStickySession' and 'lbForceSession' attribute"); + } + if (null != lbRecovertime && 60 < lbRecovertime.intValue()) { + throw new BuildException( + "The 'lbRecovertime' must be greater than 59"); + } + if (null != lbRetries && 1 < lbRetries.intValue()) { + throw new BuildException( + "The 'lbRetries' must be greater than 1"); + } + isLBMode = true; + } else if ("worker".equals(workerType)) { + if (workerDisabled == null) { + throw new BuildException( + "Must specify at a node worker 'workerDisabled' attribute"); + } + if (workerStopped == null) { + throw new BuildException( + "Must specify at a node worker 'workerStopped' attribute"); + } + if (workerLoadFactor == null ) { + throw new BuildException( + "Must specify at a node worker 'workerLoadFactor' attribute"); + } + if (workerClusterDomain == null) { + throw new BuildException( + "Must specify at a node worker 'workerClusterDomain' attribute"); + } + if (workerRedirect == null) { + throw new BuildException( + "Must specify at a node worker 'workerRedirect' attribute"); + } + if (workerLb == null) { + throw new BuildException("Must specify 'workerLb' attribute"); + } + if (workerLoadFactor.intValue() < 1) { + throw new BuildException( + "The 'workerLoadFactor' must be greater or equal 1"); + } + isLBMode = false; + } else { + throw new BuildException( + "Only 'lb' and 'worker' supported as workerType attribute"); + } + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ant/JMXGetTask.java b/java/org/apache/catalina/ant/JMXGetTask.java index ff38b310d..33a810fdd 100644 --- a/java/org/apache/catalina/ant/JMXGetTask.java +++ b/java/org/apache/catalina/ant/JMXGetTask.java @@ -1,95 +1,95 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the JMX Get command (/jmxproxy/?get) - * supported by the Tomcat manager application. - * - * @author Peter Rossbach - * @version $Revision: 303880 $ - */ -public class JMXGetTask extends AbstractCatalinaTask { - - // Properties - - /** - * The full bean name - */ - protected String bean = null; - - /** - * The attribute you wish to alter - */ - protected String attribute = null; - - // Public Methods - - /** - * Get method for the bean name - * @return Bean name - */ - public String getBean () { - return this.bean; - } - - /** - * Set method for the bean name - * @param bean Bean name - */ - public void setBean (String bean) { - this.bean = bean; - } - - /** - * Get method for the attribute name - * @return Attribute name - */ - public String getAttribute () { - return this.attribute; - } - - /** - * Set method for the attribute name - * @param attribute Attribute name - */ - public void setAttribute (String attribute) { - this.attribute = attribute; - } - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - super.execute(); - if (bean == null || attribute == null) { - throw new BuildException - ("Must specify 'bean' and 'attribute' attributes"); - } - log("Getting attribute " + attribute + - " in bean " + bean ); - execute("/jmxproxy/?get=" + bean - + "&att=" + attribute ); - } -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the JMX Get command (/jmxproxy/?get) + * supported by the Tomcat manager application. + * + * @author Peter Rossbach + * @version $Revision: 303880 $ + */ +public class JMXGetTask extends AbstractCatalinaTask { + + // Properties + + /** + * The full bean name + */ + protected String bean = null; + + /** + * The attribute you wish to alter + */ + protected String attribute = null; + + // Public Methods + + /** + * Get method for the bean name + * @return Bean name + */ + public String getBean () { + return this.bean; + } + + /** + * Set method for the bean name + * @param bean Bean name + */ + public void setBean (String bean) { + this.bean = bean; + } + + /** + * Get method for the attribute name + * @return Attribute name + */ + public String getAttribute () { + return this.attribute; + } + + /** + * Set method for the attribute name + * @param attribute Attribute name + */ + public void setAttribute (String attribute) { + this.attribute = attribute; + } + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + super.execute(); + if (bean == null || attribute == null) { + throw new BuildException + ("Must specify 'bean' and 'attribute' attributes"); + } + log("Getting attribute " + attribute + + " in bean " + bean ); + execute("/jmxproxy/?get=" + bean + + "&att=" + attribute ); + } +} diff --git a/java/org/apache/catalina/ant/JMXQueryTask.java b/java/org/apache/catalina/ant/JMXQueryTask.java index f9505a34a..61b82a3af 100644 --- a/java/org/apache/catalina/ant/JMXQueryTask.java +++ b/java/org/apache/catalina/ant/JMXQueryTask.java @@ -1,78 +1,78 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the JMX Query command - * (/jmxproxy/?qry) supported by the Tomcat manager application. - * - * @author Vivek Chopra - * @version $Revision: 303236 $ - */ -public class JMXQueryTask extends AbstractCatalinaTask { - - // Properties - - /** - * The JMX query string - * @see #setQuery(String) - */ - protected String query = null; - - // Public Methods - - /** - * Get method for the JMX query string - * @return Query string - */ - public String getQuery () { - return this.query; - } - - /** - * Set method for the JMX query string. - *

Examples of query format: - *

    - *
  • *:*
  • - *
  • *:type=RequestProcessor,*
  • - *
  • *:j2eeType=Servlet,*
  • - *
  • Catalina:type=Environment,resourcetype=Global,name=simpleValue
  • - *
- *

- * @param query JMX Query string - */ - public void setQuery (String query) { - this.query = query; - } - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - super.execute(); - String queryString = (query == null) ? "":("?qry="+query); - log("Query string is " + queryString); - execute ("/jmxproxy/" + queryString); - } -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the JMX Query command + * (/jmxproxy/?qry) supported by the Tomcat manager application. + * + * @author Vivek Chopra + * @version $Revision: 303236 $ + */ +public class JMXQueryTask extends AbstractCatalinaTask { + + // Properties + + /** + * The JMX query string + * @see #setQuery(String) + */ + protected String query = null; + + // Public Methods + + /** + * Get method for the JMX query string + * @return Query string + */ + public String getQuery () { + return this.query; + } + + /** + * Set method for the JMX query string. + *

Examples of query format: + *

    + *
  • *:*
  • + *
  • *:type=RequestProcessor,*
  • + *
  • *:j2eeType=Servlet,*
  • + *
  • Catalina:type=Environment,resourcetype=Global,name=simpleValue
  • + *
+ *

+ * @param query JMX Query string + */ + public void setQuery (String query) { + this.query = query; + } + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + super.execute(); + String queryString = (query == null) ? "":("?qry="+query); + log("Query string is " + queryString); + execute ("/jmxproxy/" + queryString); + } +} diff --git a/java/org/apache/catalina/ant/JMXSetTask.java b/java/org/apache/catalina/ant/JMXSetTask.java index 64660e371..7c12cc0bd 100644 --- a/java/org/apache/catalina/ant/JMXSetTask.java +++ b/java/org/apache/catalina/ant/JMXSetTask.java @@ -1,118 +1,118 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the JMX Set command (/jmxproxy/?set) - * supported by the Tomcat manager application. - * - * @author Vivek Chopra - * @version $Revision: 303236 $ - */ -public class JMXSetTask extends AbstractCatalinaTask { - - // Properties - - /** - * The full bean name - */ - protected String bean = null; - - /** - * The attribute you wish to alter - */ - protected String attribute = null; - - /** - * The new value for the attribute - */ - protected String value = null; - - // Public Methods - - /** - * Get method for the bean name - * @return Bean name - */ - public String getBean () { - return this.bean; - } - - /** - * Set method for the bean name - * @param bean Bean name - */ - public void setBean (String bean) { - this.bean = bean; - } - - /** - * Get method for the attribute name - * @return Attribute name - */ - public String getAttribute () { - return this.attribute; - } - - /** - * Set method for the attribute name - * @param attribute Attribute name - */ - public void setAttribute (String attribute) { - this.attribute = attribute; - } - - /** - * Get method for the attribute value - * @return Attribute value - */ - public String getValue () { - return this.value; - } - - /** - * Set method for the attribute value. - * @param value Attribute value - */ - public void setValue (String value) { - this.value = value; - } - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - super.execute(); - if (bean == null || attribute == null || value == null) { - throw new BuildException - ("Must specify 'bean', 'attribute' and 'value' attributes"); - } - log("Setting attribute " + attribute + - " in bean " + bean + - " to " + value); - execute("/jmxproxy/?set=" + bean - + "&att=" + attribute - + "&val=" + value); - } -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the JMX Set command (/jmxproxy/?set) + * supported by the Tomcat manager application. + * + * @author Vivek Chopra + * @version $Revision: 303236 $ + */ +public class JMXSetTask extends AbstractCatalinaTask { + + // Properties + + /** + * The full bean name + */ + protected String bean = null; + + /** + * The attribute you wish to alter + */ + protected String attribute = null; + + /** + * The new value for the attribute + */ + protected String value = null; + + // Public Methods + + /** + * Get method for the bean name + * @return Bean name + */ + public String getBean () { + return this.bean; + } + + /** + * Set method for the bean name + * @param bean Bean name + */ + public void setBean (String bean) { + this.bean = bean; + } + + /** + * Get method for the attribute name + * @return Attribute name + */ + public String getAttribute () { + return this.attribute; + } + + /** + * Set method for the attribute name + * @param attribute Attribute name + */ + public void setAttribute (String attribute) { + this.attribute = attribute; + } + + /** + * Get method for the attribute value + * @return Attribute value + */ + public String getValue () { + return this.value; + } + + /** + * Set method for the attribute value. + * @param value Attribute value + */ + public void setValue (String value) { + this.value = value; + } + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + super.execute(); + if (bean == null || attribute == null || value == null) { + throw new BuildException + ("Must specify 'bean', 'attribute' and 'value' attributes"); + } + log("Setting attribute " + attribute + + " in bean " + bean + + " to " + value); + execute("/jmxproxy/?set=" + bean + + "&att=" + attribute + + "&val=" + value); + } +} diff --git a/java/org/apache/catalina/ant/ListTask.java b/java/org/apache/catalina/ant/ListTask.java index 7fa34b7f4..e67e53940 100644 --- a/java/org/apache/catalina/ant/ListTask.java +++ b/java/org/apache/catalina/ant/ListTask.java @@ -1,54 +1,54 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /list command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ -public class ListTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - execute("/list"); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /list command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ +public class ListTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + execute("/list"); + + } + + +} diff --git a/java/org/apache/catalina/ant/ReloadTask.java b/java/org/apache/catalina/ant/ReloadTask.java index 25ea5e144..84d81a871 100644 --- a/java/org/apache/catalina/ant/ReloadTask.java +++ b/java/org/apache/catalina/ant/ReloadTask.java @@ -1,81 +1,81 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /reload command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ - * @since 4.1 - */ -public class ReloadTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - try { - execute("/reload?path=" + URLEncoder.encode(this.path, getCharset())); - } catch (UnsupportedEncodingException e) { - throw new BuildException - ("Invalid 'charset' attribute: " + getCharset()); - } - - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /reload command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ + * @since 4.1 + */ +public class ReloadTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + try { + execute("/reload?path=" + URLEncoder.encode(this.path, getCharset())); + } catch (UnsupportedEncodingException e) { + throw new BuildException + ("Invalid 'charset' attribute: " + getCharset()); + } + + + } + + +} diff --git a/java/org/apache/catalina/ant/RemoveTask.java b/java/org/apache/catalina/ant/RemoveTask.java index 93f2681a2..c3c5ad8ab 100644 --- a/java/org/apache/catalina/ant/RemoveTask.java +++ b/java/org/apache/catalina/ant/RemoveTask.java @@ -1,74 +1,74 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /remove command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @deprecated Replaced by UndeployTask - */ -public class RemoveTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - execute("/remove?path=" + URLEncoder.encode(this.path)); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /remove command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @deprecated Replaced by UndeployTask + */ +public class RemoveTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + execute("/remove?path=" + URLEncoder.encode(this.path)); + + } + + +} diff --git a/java/org/apache/catalina/ant/ResourcesTask.java b/java/org/apache/catalina/ant/ResourcesTask.java index ae1ee87e2..ea8a42733 100644 --- a/java/org/apache/catalina/ant/ResourcesTask.java +++ b/java/org/apache/catalina/ant/ResourcesTask.java @@ -1,73 +1,73 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /resources command, supported by - * the Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ -public class ResourcesTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * The fully qualified class name of the resource type being requested - * (if any). - */ - protected String type = null; - - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (type != null) { - execute("/resources?type=" + type); - } else { - execute("/resources"); - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /resources command, supported by + * the Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ +public class ResourcesTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * The fully qualified class name of the resource type being requested + * (if any). + */ + protected String type = null; + + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (type != null) { + execute("/resources?type=" + type); + } else { + execute("/resources"); + } + + } + + +} diff --git a/java/org/apache/catalina/ant/RolesTask.java b/java/org/apache/catalina/ant/RolesTask.java index 864504740..1b0496aef 100644 --- a/java/org/apache/catalina/ant/RolesTask.java +++ b/java/org/apache/catalina/ant/RolesTask.java @@ -1,54 +1,54 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /roles command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ -public class RolesTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - execute("/roles"); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /roles command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ +public class RolesTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + execute("/roles"); + + } + + +} diff --git a/java/org/apache/catalina/ant/ServerinfoTask.java b/java/org/apache/catalina/ant/ServerinfoTask.java index 40ba32e84..1757a4c9c 100644 --- a/java/org/apache/catalina/ant/ServerinfoTask.java +++ b/java/org/apache/catalina/ant/ServerinfoTask.java @@ -1,47 +1,47 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /serverinfo command - * supported by the Tomcat manager application. - * - * @author Vivek Chopra - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ -public class ServerinfoTask extends AbstractCatalinaTask { - - // Public Methods - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - execute("/serverinfo"); - - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /serverinfo command + * supported by the Tomcat manager application. + * + * @author Vivek Chopra + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ +public class ServerinfoTask extends AbstractCatalinaTask { + + // Public Methods + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + execute("/serverinfo"); + + } + +} diff --git a/java/org/apache/catalina/ant/SessionsTask.java b/java/org/apache/catalina/ant/SessionsTask.java index 1b099679c..9e1af74ce 100644 --- a/java/org/apache/catalina/ant/SessionsTask.java +++ b/java/org/apache/catalina/ant/SessionsTask.java @@ -1,75 +1,75 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /sessions command - * supported by the Tomcat manager application. - * - * @author Vivek Chopra - * @version $Revision: 303657 $ - */ -public class SessionsTask extends AbstractCatalinaTask { - - // Properties - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - // Public Methods - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - - try { - execute("/sessions?path=" + URLEncoder.encode(this.path, getCharset())); - } catch (UnsupportedEncodingException e) { - throw new BuildException - ("Invalid 'charset' attribute: " + getCharset()); - } - - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /sessions command + * supported by the Tomcat manager application. + * + * @author Vivek Chopra + * @version $Revision: 303657 $ + */ +public class SessionsTask extends AbstractCatalinaTask { + + // Properties + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + // Public Methods + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + + try { + execute("/sessions?path=" + URLEncoder.encode(this.path, getCharset())); + } catch (UnsupportedEncodingException e) { + throw new BuildException + ("Invalid 'charset' attribute: " + getCharset()); + } + + } + +} diff --git a/java/org/apache/catalina/ant/StartTask.java b/java/org/apache/catalina/ant/StartTask.java index 3424d2e16..c2f4a5b38 100644 --- a/java/org/apache/catalina/ant/StartTask.java +++ b/java/org/apache/catalina/ant/StartTask.java @@ -1,80 +1,80 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /start command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ - * @since 4.1 - */ -public class StartTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - try { - execute("/start?path=" + URLEncoder.encode(this.path, getCharset())); - } catch (UnsupportedEncodingException e) { - throw new BuildException - ("Invalid 'charset' attribute: " + getCharset()); - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /start command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ + * @since 4.1 + */ +public class StartTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + try { + execute("/start?path=" + URLEncoder.encode(this.path, getCharset())); + } catch (UnsupportedEncodingException e) { + throw new BuildException + ("Invalid 'charset' attribute: " + getCharset()); + } + + } + + +} diff --git a/java/org/apache/catalina/ant/StopTask.java b/java/org/apache/catalina/ant/StopTask.java index ac4490e09..6101f1d42 100644 --- a/java/org/apache/catalina/ant/StopTask.java +++ b/java/org/apache/catalina/ant/StopTask.java @@ -1,80 +1,80 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.UnsupportedEncodingException; -import java.net.URLEncoder; - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /stop command, supported by the - * Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ - * @since 4.1 - */ -public class StopTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - try { - execute("/stop?path=" + URLEncoder.encode(this.path, getCharset())); - } catch (UnsupportedEncodingException e) { - throw new BuildException - ("Invalid 'charset' attribute: " + getCharset()); - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /stop command, supported by the + * Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 303657 $ $Date: 2005-01-22 17:34:47 +0100 (sam., 22 janv. 2005) $ + * @since 4.1 + */ +public class StopTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + try { + execute("/stop?path=" + URLEncoder.encode(this.path, getCharset())); + } catch (UnsupportedEncodingException e) { + throw new BuildException + ("Invalid 'charset' attribute: " + getCharset()); + } + + } + + +} diff --git a/java/org/apache/catalina/ant/UndeployTask.java b/java/org/apache/catalina/ant/UndeployTask.java index 37f7bd455..6f42e4689 100644 --- a/java/org/apache/catalina/ant/UndeployTask.java +++ b/java/org/apache/catalina/ant/UndeployTask.java @@ -1,71 +1,71 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import org.apache.tools.ant.BuildException; - - -/** - * Ant task that implements the /undeploy command, supported by - * the Tomcat manager application. - * - * @author Craig R. McClanahan - * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ - * @since 4.1 - */ -public class UndeployTask extends AbstractCatalinaTask { - - - // ------------------------------------------------------------- Properties - - /** - * The context path of the web application we are managing. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the requested operation. - * - * @exception BuildException if an error occurs - */ - public void execute() throws BuildException { - - super.execute(); - if (path == null) { - throw new BuildException - ("Must specify 'path' attribute"); - } - - execute("/undeploy?path=" + this.path); - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import org.apache.tools.ant.BuildException; + + +/** + * Ant task that implements the /undeploy command, supported by + * the Tomcat manager application. + * + * @author Craig R. McClanahan + * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ + * @since 4.1 + */ +public class UndeployTask extends AbstractCatalinaTask { + + + // ------------------------------------------------------------- Properties + + /** + * The context path of the web application we are managing. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the requested operation. + * + * @exception BuildException if an error occurs + */ + public void execute() throws BuildException { + + super.execute(); + if (path == null) { + throw new BuildException + ("Must specify 'path' attribute"); + } + + execute("/undeploy?path=" + this.path); + } + + +} diff --git a/java/org/apache/catalina/ant/ValidatorTask.java b/java/org/apache/catalina/ant/ValidatorTask.java index f1734db49..a9fd0a382 100644 --- a/java/org/apache/catalina/ant/ValidatorTask.java +++ b/java/org/apache/catalina/ant/ValidatorTask.java @@ -1,114 +1,114 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant; - - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; - -import org.apache.catalina.startup.Constants; -import org.apache.catalina.startup.DigesterFactory; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tools.ant.BuildException; -import org.xml.sax.InputSource; - - -/** - * Task for validating a web application deployment descriptor, using XML - * schema validation. - * - * @author Remy Maucherat - * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ - * @since 5.0 - */ - -public class ValidatorTask extends BaseRedirectorHelperTask { - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------------- Properties - - - /** - * The path to the webapp directory. - */ - protected String path = null; - - public String getPath() { - return (this.path); - } - - public void setPath(String path) { - this.path = path; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Execute the specified command. This logic only performs the common - * attribute validation required by all subclasses; it does not perform - * any functional logic directly. - * - * @exception BuildException if a validation error occurs - */ - public void execute() throws BuildException { - - if (path == null) { - throw new BuildException("Must specify 'path'"); - } - - File file = new File(path, Constants.ApplicationWebXml); - if ((!file.exists()) || (!file.canRead())) { - throw new BuildException("Cannot find web.xml"); - } - - // Commons-logging likes having the context classloader set - ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader - (ValidatorTask.class.getClassLoader()); - - Digester digester = DigesterFactory.newDigester(true, true, null); - try { - file = file.getCanonicalFile(); - InputStream stream = - new BufferedInputStream(new FileInputStream(file)); - InputSource is = new InputSource(file.toURL().toExternalForm()); - is.setByteStream(stream); - digester.parse(is); - handleOutput("web.xml validated"); - } catch (Throwable t) { - if (isFailOnError()) { - throw new BuildException("Validation failure", t); - } else { - handleErrorOutput("Validation failure: " + t); - } - } finally { - Thread.currentThread().setContextClassLoader(oldCL); - closeRedirector(); - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant; + + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; + +import org.apache.catalina.startup.Constants; +import org.apache.catalina.startup.DigesterFactory; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tools.ant.BuildException; +import org.xml.sax.InputSource; + + +/** + * Task for validating a web application deployment descriptor, using XML + * schema validation. + * + * @author Remy Maucherat + * @version $Revision: 303609 $ $Date: 2005-01-03 17:21:21 +0100 (lun., 03 janv. 2005) $ + * @since 5.0 + */ + +public class ValidatorTask extends BaseRedirectorHelperTask { + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------------- Properties + + + /** + * The path to the webapp directory. + */ + protected String path = null; + + public String getPath() { + return (this.path); + } + + public void setPath(String path) { + this.path = path; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Execute the specified command. This logic only performs the common + * attribute validation required by all subclasses; it does not perform + * any functional logic directly. + * + * @exception BuildException if a validation error occurs + */ + public void execute() throws BuildException { + + if (path == null) { + throw new BuildException("Must specify 'path'"); + } + + File file = new File(path, Constants.ApplicationWebXml); + if ((!file.exists()) || (!file.canRead())) { + throw new BuildException("Cannot find web.xml"); + } + + // Commons-logging likes having the context classloader set + ClassLoader oldCL = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader + (ValidatorTask.class.getClassLoader()); + + Digester digester = DigesterFactory.newDigester(true, true, null); + try { + file = file.getCanonicalFile(); + InputStream stream = + new BufferedInputStream(new FileInputStream(file)); + InputSource is = new InputSource(file.toURL().toExternalForm()); + is.setByteStream(stream); + digester.parse(is); + handleOutput("web.xml validated"); + } catch (Throwable t) { + if (isFailOnError()) { + throw new BuildException("Validation failure", t); + } else { + handleErrorOutput("Validation failure: " + t); + } + } finally { + Thread.currentThread().setContextClassLoader(oldCL); + closeRedirector(); + } + + } + + +} diff --git a/java/org/apache/catalina/ant/antlib.xml b/java/org/apache/catalina/ant/antlib.xml index 831c76a04..1a2e12ce5 100644 --- a/java/org/apache/catalina/ant/antlib.xml +++ b/java/org/apache/catalina/ant/antlib.xml @@ -1,42 +1,42 @@ - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/java/org/apache/catalina/ant/jmx/Arg.java b/java/org/apache/catalina/ant/jmx/Arg.java index 5a61d6ff7..7bf5c63f7 100644 --- a/java/org/apache/catalina/ant/jmx/Arg.java +++ b/java/org/apache/catalina/ant/jmx/Arg.java @@ -1,46 +1,46 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ant.jmx; - -/** - * - * @author Peter Rossbach - * @version $Revision: 303958 $ $Date: 2005-06-24 13:53:42 +0200 (ven., 24 juin 2005) $ - * @since 5.5.10 - */ -public class Arg { - String type; - String value; - - public void setType( String type) { - this.type=type; - } - public void setValue( String value ) { - this.value=value; - } - public void addText( String text ) { - this.value=text; - } - - public String getValue() { - return value; - } - - public String getType() { - return type; - } -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ant.jmx; + +/** + * + * @author Peter Rossbach + * @version $Revision: 303958 $ $Date: 2005-06-24 13:53:42 +0200 (ven., 24 juin 2005) $ + * @since 5.5.10 + */ +public class Arg { + String type; + String value; + + public void setType( String type) { + this.type=type; + } + public void setValue( String value ) { + this.value=value; + } + public void addText( String text ) { + this.value=text; + } + + public String getValue() { + return value; + } + + public String getType() { + return type; + } +} diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java b/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java index 41f547822..a2e794eac 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorCondition.java @@ -1,400 +1,400 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ant.jmx; - -import java.io.IOException; -import java.net.MalformedURLException; - -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.ProjectComponent; -import org.apache.tools.ant.taskdefs.condition.Condition; - -/** - * - * Definition: - *
 
- *   <path id="catalina_ant">
- *       <fileset dir="${catalina.home}/server/lib">
- *           <include name="catalina-ant.jar"/>
- *           <include name="catalina-ant-jmx.jar"/>
- *       </fileset>
- *   </path>
- *
- *   <typedef
- *       name="jmxCondition"
- *       classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
- *       classpathref="catalina_ant"/>
- *   <taskdef
- *       name="jmxOpen"
- *       classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
- *       classpathref="catalina_ant"/>
- * 
- * - * Usage: Wait for start backup node - *
- *     <target name="wait">
- *       <jmxOpen
- *               host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" />
- *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
- *           <and>
- *               <socket server="${server.name}" port="${server.port}"/>
- *               <http url="${url}"/>
- *               <jmxCondition
- *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
- *                   operation="==" 
- *                   attribute="connected" value="true"
- *               />
- *               <jmxCondition
- *                   operation="&lt;"
- *                   name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
- *                   attribute="startupTime" value="250"
- *               />
- *           </and>
- *       </waitfor>
- *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
- *       <echo message="Server ${url} alive" />
- *   </target>
- *
- * 
- * Allowed operation between jmx attribute and reference value: - *
    - *
  • == equals
  • - *
  • != not equals
  • - *
  • > greater than (&gt;)
  • - *
  • >= greater than or equals (&gt;=)
  • - *
  • < lesser than (&lt;)
  • - *
  • <= lesser than or equals (&lt;=)
  • - *
- * NOTE: For numeric expressions the type must be set and use xml entities as operations.
- * As type we currently support long and double. - * @author Peter Rossbach - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - * @since 5.5.10 - * - */ -public class JMXAccessorCondition extends ProjectComponent implements Condition { - - // ----------------------------------------------------- Instance Variables - - private String url = null; - private String host = "localhost"; - private String port = "8050"; - private String password = null; - private String username = null; - private String name = null; - private String attribute; - private String value; - private String operation = "==" ; - private String type = "long" ; - private String ref = "jmx.server"; - private String unlessCondition; - private String ifCondition; - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - // ----------------------------------------------------- Properties - - /** - * @return Returns the operation. - */ - public String getOperation() { - return operation; - } - /** - * @param operation The operation to set. - */ - public void setOperation(String operation) { - this.operation = operation; - } - - /** - * @return Returns the type. - */ - public String getType() { - return type; - } - /** - * @param type The type to set. - */ - public void setType(String type) { - this.type = type; - } - /** - * @return Returns the attribute. - */ - public String getAttribute() { - return attribute; - } - /** - * @param attribute The attribute to set. - */ - public void setAttribute(String attribute) { - this.attribute = attribute; - } - /** - * @return Returns the host. - */ - public String getHost() { - return host; - } - /** - * @param host The host to set. - */ - public void setHost(String host) { - this.host = host; - } - /** - * @return Returns the name. - */ - public String getName() { - return name; - } - /** - * @param objectName The name to set. - */ - public void setName(String objectName) { - this.name = objectName; - } - /** - * @return Returns the password. - */ - public String getPassword() { - return password; - } - /** - * @param password The password to set. - */ - public void setPassword(String password) { - this.password = password; - } - /** - * @return Returns the port. - */ - public String getPort() { - return port; - } - /** - * @param port The port to set. - */ - public void setPort(String port) { - this.port = port; - } - /** - * @return Returns the url. - */ - public String getUrl() { - return url; - } - /** - * @param url The url to set. - */ - public void setUrl(String url) { - this.url = url; - } - /** - * @return Returns the username. - */ - public String getUsername() { - return username; - } - /** - * @param username The username to set. - */ - public void setUsername(String username) { - this.username = username; - } - /** - * @return Returns the value. - */ - public String getValue() { - return value; - } - // The setter for the "value" attribute - public void setValue(String value) { - this.value = value; - } - - /** - * @return Returns the ref. - */ - public String getRef() { - return ref; - } - /** - * @param refId The ref to set. - */ - public void setRef(String refId) { - this.ref = refId; - } - /** - * @return Returns the ifCondition. - */ - public String getIf() { - return ifCondition; - } - /** - * Only execute if a property of the given name exists in the current project. - * @param c property name - */ - public void setIf(String c) { - ifCondition = c; - } - /** - * @return Returns the unlessCondition. - */ - public String getUnless() { - return unlessCondition; - } - - /** - * Only execute if a property of the given name does not - * exist in the current project. - * @param c property name - */ - public void setUnless(String c) { - unlessCondition = c; - } - - /** - * Get JMXConnection (default look at jmx.server project reference from jmxOpen Task) - * @return active JMXConnection - * @throws MalformedURLException - * @throws IOException - */ - protected MBeanServerConnection getJMXConnection() - throws MalformedURLException, IOException { - return JMXAccessorTask.accessJMXConnection( - getProject(), - getUrl(), getHost(), - getPort(), getUsername(), getPassword(), ref); - } - - /** - * Get value from MBeans attribute - * @return The value - */ - protected String accessJMXValue() { - try { - Object result = getJMXConnection().getAttribute( - new ObjectName(name), attribute); - if(result != null) - return result.toString(); - } catch (Exception e) { - // ignore access or connection open errors - } - return null; - } - - /** - * test the if condition - * @return true if there is no if condition, or the named property exists - */ - protected boolean testIfCondition() { - if (ifCondition == null || "".equals(ifCondition)) { - return true; - } - return getProject().getProperty(ifCondition) != null; - } - - /** - * test the unless condition - * @return true if there is no unless condition, - * or there is a named property but it doesn't exist - */ - protected boolean testUnlessCondition() { - if (unlessCondition == null || "".equals(unlessCondition)) { - return true; - } - return getProject().getProperty(unlessCondition) == null; - } - - /** - * This method evaluates the condition - * It support for operation ">,>=,<,<=" the types long and double. - * @return expression jmxValue operation value - */ - public boolean eval() { - if (operation == null) { - throw new BuildException("operation attribute is not set"); - } - if (value == null) { - throw new BuildException("value attribute is not set"); - } - if ((name == null || attribute == null)) { - throw new BuildException( - "Must specify a 'attribute', name for equals condition"); - } - if (testIfCondition() && testUnlessCondition()) { - String jmxValue = accessJMXValue(); - if (jmxValue != null) { - String op = getOperation(); - if ("==".equals(op)) { - return jmxValue.equals(value); - } else if ("!=".equals(op)) { - return !jmxValue.equals(value); - } else { - if ("long".equals(type)) { - long jvalue = Long.parseLong(jmxValue); - long lvalue = Long.parseLong(value); - if (">".equals(op)) { - return jvalue > lvalue; - } else if (">=".equals(op)) { - return jvalue >= lvalue; - } else if ("<".equals(op)) { - return jvalue < lvalue; - } else if ("<=".equals(op)) { - return jvalue <= lvalue; - } - } else if ("double".equals(type)) { - double jvalue = Double.parseDouble(jmxValue); - double dvalue = Double.parseDouble(value); - if (">".equals(op)) { - return jvalue > dvalue; - } else if (">=".equals(op)) { - return jvalue >= dvalue; - } else if ("<".equals(op)) { - return jvalue < dvalue; - } else if ("<=".equals(op)) { - return jvalue <= dvalue; - } - } - } - } - return false; - } - return true; - } - } - +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ant.jmx; + +import java.io.IOException; +import java.net.MalformedURLException; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.taskdefs.condition.Condition; + +/** + * + * Definition: + *
 
+ *   <path id="catalina_ant">
+ *       <fileset dir="${catalina.home}/server/lib">
+ *           <include name="catalina-ant.jar"/>
+ *           <include name="catalina-ant-jmx.jar"/>
+ *       </fileset>
+ *   </path>
+ *
+ *   <typedef
+ *       name="jmxCondition"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorCondition"
+ *       classpathref="catalina_ant"/>
+ *   <taskdef
+ *       name="jmxOpen"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorTask"
+ *       classpathref="catalina_ant"/>
+ * 
+ * + * Usage: Wait for start backup node + *
+ *     <target name="wait">
+ *       <jmxOpen
+ *               host="${jmx.host}" port="${jmx.port}" username="${jmx.username}" password="${jmx.password}" />
+ *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
+ *           <and>
+ *               <socket server="${server.name}" port="${server.port}"/>
+ *               <http url="${url}"/>
+ *               <jmxCondition
+ *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+ *                   operation="==" 
+ *                   attribute="connected" value="true"
+ *               />
+ *               <jmxCondition
+ *                   operation="&lt;"
+ *                   name="Catalina:j2eeType=WebModule,name=//${tomcat.application.host}${tomcat.application.path},J2EEApplication=none,J2EEServer=none"
+ *                   attribute="startupTime" value="250"
+ *               />
+ *           </and>
+ *       </waitfor>
+ *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
+ *       <echo message="Server ${url} alive" />
+ *   </target>
+ *
+ * 
+ * Allowed operation between jmx attribute and reference value: + *
    + *
  • == equals
  • + *
  • != not equals
  • + *
  • > greater than (&gt;)
  • + *
  • >= greater than or equals (&gt;=)
  • + *
  • < lesser than (&lt;)
  • + *
  • <= lesser than or equals (&lt;=)
  • + *
+ * NOTE: For numeric expressions the type must be set and use xml entities as operations.
+ * As type we currently support long and double. + * @author Peter Rossbach + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + * @since 5.5.10 + * + */ +public class JMXAccessorCondition extends ProjectComponent implements Condition { + + // ----------------------------------------------------- Instance Variables + + private String url = null; + private String host = "localhost"; + private String port = "8050"; + private String password = null; + private String username = null; + private String name = null; + private String attribute; + private String value; + private String operation = "==" ; + private String type = "long" ; + private String ref = "jmx.server"; + private String unlessCondition; + private String ifCondition; + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorCondition/1.1"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + // ----------------------------------------------------- Properties + + /** + * @return Returns the operation. + */ + public String getOperation() { + return operation; + } + /** + * @param operation The operation to set. + */ + public void setOperation(String operation) { + this.operation = operation; + } + + /** + * @return Returns the type. + */ + public String getType() { + return type; + } + /** + * @param type The type to set. + */ + public void setType(String type) { + this.type = type; + } + /** + * @return Returns the attribute. + */ + public String getAttribute() { + return attribute; + } + /** + * @param attribute The attribute to set. + */ + public void setAttribute(String attribute) { + this.attribute = attribute; + } + /** + * @return Returns the host. + */ + public String getHost() { + return host; + } + /** + * @param host The host to set. + */ + public void setHost(String host) { + this.host = host; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param objectName The name to set. + */ + public void setName(String objectName) { + this.name = objectName; + } + /** + * @return Returns the password. + */ + public String getPassword() { + return password; + } + /** + * @param password The password to set. + */ + public void setPassword(String password) { + this.password = password; + } + /** + * @return Returns the port. + */ + public String getPort() { + return port; + } + /** + * @param port The port to set. + */ + public void setPort(String port) { + this.port = port; + } + /** + * @return Returns the url. + */ + public String getUrl() { + return url; + } + /** + * @param url The url to set. + */ + public void setUrl(String url) { + this.url = url; + } + /** + * @return Returns the username. + */ + public String getUsername() { + return username; + } + /** + * @param username The username to set. + */ + public void setUsername(String username) { + this.username = username; + } + /** + * @return Returns the value. + */ + public String getValue() { + return value; + } + // The setter for the "value" attribute + public void setValue(String value) { + this.value = value; + } + + /** + * @return Returns the ref. + */ + public String getRef() { + return ref; + } + /** + * @param refId The ref to set. + */ + public void setRef(String refId) { + this.ref = refId; + } + /** + * @return Returns the ifCondition. + */ + public String getIf() { + return ifCondition; + } + /** + * Only execute if a property of the given name exists in the current project. + * @param c property name + */ + public void setIf(String c) { + ifCondition = c; + } + /** + * @return Returns the unlessCondition. + */ + public String getUnless() { + return unlessCondition; + } + + /** + * Only execute if a property of the given name does not + * exist in the current project. + * @param c property name + */ + public void setUnless(String c) { + unlessCondition = c; + } + + /** + * Get JMXConnection (default look at jmx.server project reference from jmxOpen Task) + * @return active JMXConnection + * @throws MalformedURLException + * @throws IOException + */ + protected MBeanServerConnection getJMXConnection() + throws MalformedURLException, IOException { + return JMXAccessorTask.accessJMXConnection( + getProject(), + getUrl(), getHost(), + getPort(), getUsername(), getPassword(), ref); + } + + /** + * Get value from MBeans attribute + * @return The value + */ + protected String accessJMXValue() { + try { + Object result = getJMXConnection().getAttribute( + new ObjectName(name), attribute); + if(result != null) + return result.toString(); + } catch (Exception e) { + // ignore access or connection open errors + } + return null; + } + + /** + * test the if condition + * @return true if there is no if condition, or the named property exists + */ + protected boolean testIfCondition() { + if (ifCondition == null || "".equals(ifCondition)) { + return true; + } + return getProject().getProperty(ifCondition) != null; + } + + /** + * test the unless condition + * @return true if there is no unless condition, + * or there is a named property but it doesn't exist + */ + protected boolean testUnlessCondition() { + if (unlessCondition == null || "".equals(unlessCondition)) { + return true; + } + return getProject().getProperty(unlessCondition) == null; + } + + /** + * This method evaluates the condition + * It support for operation ">,>=,<,<=" the types long and double. + * @return expression jmxValue operation value + */ + public boolean eval() { + if (operation == null) { + throw new BuildException("operation attribute is not set"); + } + if (value == null) { + throw new BuildException("value attribute is not set"); + } + if ((name == null || attribute == null)) { + throw new BuildException( + "Must specify a 'attribute', name for equals condition"); + } + if (testIfCondition() && testUnlessCondition()) { + String jmxValue = accessJMXValue(); + if (jmxValue != null) { + String op = getOperation(); + if ("==".equals(op)) { + return jmxValue.equals(value); + } else if ("!=".equals(op)) { + return !jmxValue.equals(value); + } else { + if ("long".equals(type)) { + long jvalue = Long.parseLong(jmxValue); + long lvalue = Long.parseLong(value); + if (">".equals(op)) { + return jvalue > lvalue; + } else if (">=".equals(op)) { + return jvalue >= lvalue; + } else if ("<".equals(op)) { + return jvalue < lvalue; + } else if ("<=".equals(op)) { + return jvalue <= lvalue; + } + } else if ("double".equals(type)) { + double jvalue = Double.parseDouble(jmxValue); + double dvalue = Double.parseDouble(value); + if (">".equals(op)) { + return jvalue > dvalue; + } else if (">=".equals(op)) { + return jvalue >= dvalue; + } else if ("<".equals(op)) { + return jvalue < dvalue; + } else if ("<=".equals(op)) { + return jvalue <= dvalue; + } + } + } + } + return false; + } + return true; + } + } + diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java index c136fd4b0..bde89241d 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorCreateTask.java @@ -1,206 +1,206 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.ant.jmx; - -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; - -/** - * Create new MBean at JMX JSR 160 MBeans Server. - *
    - *
  • Create Mbeans
  • - *
  • Create Mbeans with parameter
  • - *
  • Create remote Mbeans with different classloader
  • - *
- *

- * Examples: - *
- * create a new Mbean at jmx.server connection - *

- *   <jmx:create
- *           ref="jmx.server"
- *           name="Catalina:type=MBeanFactory"
- *           className="org.apache.catalina.mbeans.MBeanFactory"
- *           classLoader="Catalina:type=ServerClassLoader,name=server">
- *            <Arg value="org.apache.catalina.mbeans.MBeanFactory" />
- *   </jmxCreate/>
- * 
- *

- *

- * WARNINGNot all Tomcat MBeans can create remotely and autoregister by its parents! - * Please, use the MBeanFactory operation to generate valves and realms. - *

- *

- * First call to a remote MBeanserver save the JMXConnection a reference jmx.server - *

- * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304089 $ - * @since 5.5.12 - */ -public class JMXAccessorCreateTask extends JMXAccessorTask { - // ----------------------------------------------------- Instance Variables - - private String className; - private String classLoader; - private List args=new ArrayList(); - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorCreateTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - * @return Returns the class info. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * @return Returns the classLoader. - */ - public String getClassLoader() { - return classLoader; - } - - /** - * @param classLoader The classLoader to set. - */ - public void setClassLoader(String classLoaderName) { - this.classLoader = classLoaderName; - } - - /** - * @return Returns the className. - */ - public String getClassName() { - return className; - } - - /** - * @param className The className to set. - */ - public void setClassName(String className) { - this.className = className; - } - - public void addArg(Arg arg ) { - args.add(arg); - } - - /** - * @return Returns the args. - */ - public List getArgs() { - return args; - } - /** - * @param args The args to set. - */ - public void setArgs(List args) { - this.args = args; - } - - // ------------------------------------------------------ protected Methods - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception Exception - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - if ((className == null)) { - throw new BuildException( - "Must specify a 'className' for get"); - } - return jmxCreate(jmxServerConnection, getName()); - } - - /** - * create new Mbean and when set from ClassLoader Objectname - * @param jmxServerConnection - * @param name - * @return The value of the given named attribute - * @throws Exception - */ - protected String jmxCreate(MBeanServerConnection jmxServerConnection, - String name) throws Exception { - String error = null; - Object argsA[] = null; - String sigA[] = null; - if (args != null) { - argsA = new Object[ args.size()]; - sigA = new String[args.size()]; - for( int i=0; iJMX JSR 160 MBeans Server. + *
    + *
  • Create Mbeans
  • + *
  • Create Mbeans with parameter
  • + *
  • Create remote Mbeans with different classloader
  • + *
+ *

+ * Examples: + *
+ * create a new Mbean at jmx.server connection + *

+ *   <jmx:create
+ *           ref="jmx.server"
+ *           name="Catalina:type=MBeanFactory"
+ *           className="org.apache.catalina.mbeans.MBeanFactory"
+ *           classLoader="Catalina:type=ServerClassLoader,name=server">
+ *            <Arg value="org.apache.catalina.mbeans.MBeanFactory" />
+ *   </jmxCreate/>
+ * 
+ *

+ *

+ * WARNINGNot all Tomcat MBeans can create remotely and autoregister by its parents! + * Please, use the MBeanFactory operation to generate valves and realms. + *

+ *

+ * First call to a remote MBeanserver save the JMXConnection a reference jmx.server + *

+ * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304089 $ + * @since 5.5.12 + */ +public class JMXAccessorCreateTask extends JMXAccessorTask { + // ----------------------------------------------------- Instance Variables + + private String className; + private String classLoader; + private List args=new ArrayList(); + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorCreateTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + * @return Returns the class info. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * @return Returns the classLoader. + */ + public String getClassLoader() { + return classLoader; + } + + /** + * @param classLoader The classLoader to set. + */ + public void setClassLoader(String classLoaderName) { + this.classLoader = classLoaderName; + } + + /** + * @return Returns the className. + */ + public String getClassName() { + return className; + } + + /** + * @param className The className to set. + */ + public void setClassName(String className) { + this.className = className; + } + + public void addArg(Arg arg ) { + args.add(arg); + } + + /** + * @return Returns the args. + */ + public List getArgs() { + return args; + } + /** + * @param args The args to set. + */ + public void setArgs(List args) { + this.args = args; + } + + // ------------------------------------------------------ protected Methods + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception Exception + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + if ((className == null)) { + throw new BuildException( + "Must specify a 'className' for get"); + } + return jmxCreate(jmxServerConnection, getName()); + } + + /** + * create new Mbean and when set from ClassLoader Objectname + * @param jmxServerConnection + * @param name + * @return The value of the given named attribute + * @throws Exception + */ + protected String jmxCreate(MBeanServerConnection jmxServerConnection, + String name) throws Exception { + String error = null; + Object argsA[] = null; + String sigA[] = null; + if (args != null) { + argsA = new Object[ args.size()]; + sigA = new String[args.size()]; + for( int i=0; i - * <path id="catalina_ant"> - * <fileset dir="${catalina.home}/server/lib"> - * <include name="catalina-ant.jar"/> - * <include name="catalina-ant-jmx.jar"/> - * </fileset> - * </path> - * - * <typedef - * name="jmxEquals" - * classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition" - * classpathref="catalina_ant"/> - * - * - * usage: Wait for start backup node - *
- *     <target name="wait">
- *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
- *           <and>
- *               <socket server="${server.name}" port="${server.port}"/>
- *               <http url="${url}"/>
- *               <jmxEquals 
- *                   host="localhost" port="9014" username="controlRole" password="tomcat"
- *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
- *                   attribute="connected" value="true"
- *               />
- *           </and>
- *       </waitfor>
- *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
- *       <echo message="Server ${url} alive" />
- *   </target>
- *
- * 
- * - * @author Peter Rossbach - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - * @since 5.5.10 - * - */ -public class JMXAccessorEqualsCondition extends ProjectComponent implements Condition { - - // ----------------------------------------------------- Instance Variables - - private String url = null; - private String host = "localhost"; - private String port = "8050"; - private String password = null; - private String username = null; - private String name = null; - private String attribute; - private String value; - private String ref = "jmx.server" ; - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorEqualsCondition/1.1"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - // ----------------------------------------------------- Properties - - /** - * @return Returns the attribute. - */ - public String getAttribute() { - return attribute; - } - /** - * @param attribute The attribute to set. - */ - public void setAttribute(String attribute) { - this.attribute = attribute; - } - /** - * @return Returns the host. - */ - public String getHost() { - return host; - } - /** - * @param host The host to set. - */ - public void setHost(String host) { - this.host = host; - } - /** - * @return Returns the name. - */ - public String getName() { - return name; - } - /** - * @param objectName The name to set. - */ - public void setName(String objectName) { - this.name = objectName; - } - /** - * @return Returns the password. - */ - public String getPassword() { - return password; - } - /** - * @param password The password to set. - */ - public void setPassword(String password) { - this.password = password; - } - /** - * @return Returns the port. - */ - public String getPort() { - return port; - } - /** - * @param port The port to set. - */ - public void setPort(String port) { - this.port = port; - } - /** - * @return Returns the url. - */ - public String getUrl() { - return url; - } - /** - * @param url The url to set. - */ - public void setUrl(String url) { - this.url = url; - } - /** - * @return Returns the username. - */ - public String getUsername() { - return username; - } - /** - * @param username The username to set. - */ - public void setUsername(String username) { - this.username = username; - } - /** - * @return Returns the value. - */ - public String getValue() { - return value; - } - // The setter for the "value" attribute - public void setValue(String value) { - this.value = value; - } - - /** - * @return Returns the ref. - */ - public String getRef() { - return ref; - } - /** - * @param refId The ref to set. - */ - public void setRef(String refId) { - this.ref = refId; - } - - protected MBeanServerConnection getJMXConnection() - throws MalformedURLException, IOException { - return JMXAccessorTask.accessJMXConnection( - getProject(), - getUrl(), getHost(), - getPort(), getUsername(), getPassword(), ref); - } - - /** - * @return The value - */ - protected String accessJMXValue() { - try { - Object result = getJMXConnection().getAttribute( - new ObjectName(name), attribute); - if(result != null) - return result.toString(); - } catch (Exception e) { - // ignore access or connection open errors - } - return null; - } - - // This method evaluates the condition - public boolean eval() { - if (value == null) { - throw new BuildException("value attribute is not set"); - } - if ((name == null || attribute == null)) { - throw new BuildException( - "Must specify a 'attribute', name for equals condition"); - } - //FIXME check url or host/parameter - String jmxValue = accessJMXValue(); - if(jmxValue != null) - return jmxValue.equals(value); - return false; - } -} - +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ant.jmx; + +import java.io.IOException; +import java.net.MalformedURLException; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.ProjectComponent; +import org.apache.tools.ant.taskdefs.condition.Condition; + +/** + * + * Definition + *
 
+ *   <path id="catalina_ant">
+ *       <fileset dir="${catalina.home}/server/lib">
+ *           <include name="catalina-ant.jar"/>
+ *           <include name="catalina-ant-jmx.jar"/>
+ *       </fileset>
+ *   </path>
+ *
+ *   <typedef
+ *       name="jmxEquals"
+ *       classname="org.apache.catalina.ant.jmx.JMXAccessorEqualsCondition"
+ *       classpathref="catalina_ant"/>
+ * 
+ * + * usage: Wait for start backup node + *
+ *     <target name="wait">
+ *        <waitfor maxwait="${maxwait}" maxwaitunit="second" timeoutproperty="server.timeout" >
+ *           <and>
+ *               <socket server="${server.name}" port="${server.port}"/>
+ *               <http url="${url}"/>
+ *               <jmxEquals 
+ *                   host="localhost" port="9014" username="controlRole" password="tomcat"
+ *                   name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.111.1,senderPort=9025"
+ *                   attribute="connected" value="true"
+ *               />
+ *           </and>
+ *       </waitfor>
+ *       <fail if="server.timeout" message="Server ${url} don't answer inside ${maxwait} sec" />
+ *       <echo message="Server ${url} alive" />
+ *   </target>
+ *
+ * 
+ * + * @author Peter Rossbach + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + * @since 5.5.10 + * + */ +public class JMXAccessorEqualsCondition extends ProjectComponent implements Condition { + + // ----------------------------------------------------- Instance Variables + + private String url = null; + private String host = "localhost"; + private String port = "8050"; + private String password = null; + private String username = null; + private String name = null; + private String attribute; + private String value; + private String ref = "jmx.server" ; + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorEqualsCondition/1.1"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + // ----------------------------------------------------- Properties + + /** + * @return Returns the attribute. + */ + public String getAttribute() { + return attribute; + } + /** + * @param attribute The attribute to set. + */ + public void setAttribute(String attribute) { + this.attribute = attribute; + } + /** + * @return Returns the host. + */ + public String getHost() { + return host; + } + /** + * @param host The host to set. + */ + public void setHost(String host) { + this.host = host; + } + /** + * @return Returns the name. + */ + public String getName() { + return name; + } + /** + * @param objectName The name to set. + */ + public void setName(String objectName) { + this.name = objectName; + } + /** + * @return Returns the password. + */ + public String getPassword() { + return password; + } + /** + * @param password The password to set. + */ + public void setPassword(String password) { + this.password = password; + } + /** + * @return Returns the port. + */ + public String getPort() { + return port; + } + /** + * @param port The port to set. + */ + public void setPort(String port) { + this.port = port; + } + /** + * @return Returns the url. + */ + public String getUrl() { + return url; + } + /** + * @param url The url to set. + */ + public void setUrl(String url) { + this.url = url; + } + /** + * @return Returns the username. + */ + public String getUsername() { + return username; + } + /** + * @param username The username to set. + */ + public void setUsername(String username) { + this.username = username; + } + /** + * @return Returns the value. + */ + public String getValue() { + return value; + } + // The setter for the "value" attribute + public void setValue(String value) { + this.value = value; + } + + /** + * @return Returns the ref. + */ + public String getRef() { + return ref; + } + /** + * @param refId The ref to set. + */ + public void setRef(String refId) { + this.ref = refId; + } + + protected MBeanServerConnection getJMXConnection() + throws MalformedURLException, IOException { + return JMXAccessorTask.accessJMXConnection( + getProject(), + getUrl(), getHost(), + getPort(), getUsername(), getPassword(), ref); + } + + /** + * @return The value + */ + protected String accessJMXValue() { + try { + Object result = getJMXConnection().getAttribute( + new ObjectName(name), attribute); + if(result != null) + return result.toString(); + } catch (Exception e) { + // ignore access or connection open errors + } + return null; + } + + // This method evaluates the condition + public boolean eval() { + if (value == null) { + throw new BuildException("value attribute is not set"); + } + if ((name == null || attribute == null)) { + throw new BuildException( + "Must specify a 'attribute', name for equals condition"); + } + //FIXME check url or host/parameter + String jmxValue = accessJMXValue(); + if(jmxValue != null) + return jmxValue.equals(value); + return false; + } +} + diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java index ff8472fd0..f134f8ca1 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorGetTask.java @@ -1,144 +1,144 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant.jmx; - - -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; - - -/** - * Access JMX JSR 160 MBeans Server. - *
    - *
  • Get Mbeans attributes
  • - *
  • Show Get result as Ant console log
  • - *
  • Bind Get result as Ant properties
  • - *
- *

- * Examples: - *
- * Get a Mbean IDataSender attribute nrOfRequests and create a new ant property IDataSender.9025.nrOfRequests - *

- *   <jmx:get
- *           ref="jmx.server"
- *           name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.1.2,senderPort=9025" 
- *           attribute="nrOfRequests"
- *           resultproperty="IDataSender.9025.nrOfRequests"
- *           echo="false">
- *       />
- * 
- *

- *

- * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server - *

- * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - * @since 5.5.10 - */ - -public class JMXAccessorGetTask extends JMXAccessorTask { - - - // ----------------------------------------------------- Instance Variables - - private String attribute; - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorGetTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * @return Returns the attribute. - */ - public String getAttribute() { - return attribute; - } - - /** - * @param attribute The attribute to set. - */ - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - - // ------------------------------------------------------ protected Methods - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception BuildException - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - if ((attribute == null)) { - throw new BuildException( - "Must specify a 'attribute' for get"); - } - return jmxGet(jmxServerConnection, getName()); - } - - - /** - * @param jmxServerConnection - * @param name - * @return The value of the given named attribute - * @throws Exception - */ - protected String jmxGet(MBeanServerConnection jmxServerConnection,String name) throws Exception { - String error = null; - if(isEcho()) { - handleOutput("MBean " + name + " get attribute " + attribute ); - } - Object result = jmxServerConnection.getAttribute( - new ObjectName(name), attribute); - if (result != null) { - echoResult(attribute,result); - createProperty(result); - } else - error = "Attribute " + attribute + " is empty"; - return error; - } -} +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant.jmx; + + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; + + +/** + * Access JMX JSR 160 MBeans Server. + *
    + *
  • Get Mbeans attributes
  • + *
  • Show Get result as Ant console log
  • + *
  • Bind Get result as Ant properties
  • + *
+ *

+ * Examples: + *
+ * Get a Mbean IDataSender attribute nrOfRequests and create a new ant property IDataSender.9025.nrOfRequests + *

+ *   <jmx:get
+ *           ref="jmx.server"
+ *           name="Catalina:type=IDataSender,host=localhost,senderAddress=192.168.1.2,senderPort=9025" 
+ *           attribute="nrOfRequests"
+ *           resultproperty="IDataSender.9025.nrOfRequests"
+ *           echo="false">
+ *       />
+ * 
+ *

+ *

+ * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server + *

+ * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + * @since 5.5.10 + */ + +public class JMXAccessorGetTask extends JMXAccessorTask { + + + // ----------------------------------------------------- Instance Variables + + private String attribute; + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorGetTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * @return Returns the attribute. + */ + public String getAttribute() { + return attribute; + } + + /** + * @param attribute The attribute to set. + */ + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + + // ------------------------------------------------------ protected Methods + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception BuildException + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + if ((attribute == null)) { + throw new BuildException( + "Must specify a 'attribute' for get"); + } + return jmxGet(jmxServerConnection, getName()); + } + + + /** + * @param jmxServerConnection + * @param name + * @return The value of the given named attribute + * @throws Exception + */ + protected String jmxGet(MBeanServerConnection jmxServerConnection,String name) throws Exception { + String error = null; + if(isEcho()) { + handleOutput("MBean " + name + " get attribute " + attribute ); + } + Object result = jmxServerConnection.getAttribute( + new ObjectName(name), attribute); + if (result != null) { + echoResult(attribute,result); + createProperty(result); + } else + error = "Attribute " + attribute + " is empty"; + return error; + } +} diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java index cb3521ada..cc5c5c1e5 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorInvokeTask.java @@ -1,206 +1,206 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant.jmx; - - -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; - - -/** - * Access JMX JSR 160 MBeans Server. - *
    - *
  • open more then one JSR 160 rmi connection
  • - *
  • Get/Set Mbeans attributes
  • - *
  • Call Mbean Operation with arguments
  • - *
  • Argument values can be converted from string to int,long,float,double,boolean,ObjectName or InetAddress
  • - *
  • Query Mbeans
  • - *
  • Show Get, Call, Query result at Ant console log
  • - *
  • Bind Get, Call, Query result at Ant properties
  • - *
- * - * Examples: - *
    - *
  • - * Get a session attribute hello from session with ref ${sessionid.0} form - * app Catalina:type=Manager,path=/ClusterTest,host=localhost - *
    - *   <jmx:invoke
    - *           name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
    - *           operation="getSessionAttribute"
    - *           resultproperty="hello">
    - *         <arg value="${sessionid.0}"/>
    - *         <arg value="Hello"/>
    - *   </jmx:invoke>
    - * 
    - *
  • - *
  • - * Create new AccessLogger at localhost - * - * <jmx:invoke - * name="Catalina:type=MBeanFactory" - * operation="createAcccesLoggerValve" - * resultproperty="acccesLoggerObjectName" - * > - * <arg value="Catalina:type=Host,host=localhost"/> - * </jmx:invoke> - * - * - *
  • - *
  • - * Remove existing AccessLogger at localhost - * - * <jmx:invoke - * name="Catalina:type=MBeanFactory" - * operation="removeValve" - * > - * <arg value="Catalina:type=Valve,name=AccessLogValve,host=localhost"/> - * </jmx:invoke> - * - * - *
  • - *
- *

- * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server - *

- * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304013 $ $Date: 2005-07-22 13:39:08 +0200 (ven., 22 juil. 2005) $ - * @since 5.5.10 - */ - -public class JMXAccessorInvokeTask extends JMXAccessorTask { - - - // ----------------------------------------------------- Instance Variables - - private String operation ; - private List args=new ArrayList(); - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorInvokeTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * @return Returns the operation. - */ - public String getOperation() { - return operation; - } - /** - * @param operation The operation to set. - */ - public void setOperation(String operation) { - this.operation = operation; - } - - public void addArg(Arg arg ) { - args.add(arg); - } - - /** - * @return Returns the args. - */ - public List getArgs() { - return args; - } - /** - * @param args The args to set. - */ - public void setArgs(List args) { - this.args = args; - } - - // ------------------------------------------------------ protected Methods - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception BuildException - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - if ((operation == null)) { - throw new BuildException( - "Must specify a 'operation' for call"); - } - return jmxInvoke(jmxServerConnection, getName()); - } - - /** - * @param jmxServerConnection - * @throws Exception - */ - protected String jmxInvoke(MBeanServerConnection jmxServerConnection, String name) throws Exception { - Object result ; - if (args == null) { - result = jmxServerConnection.invoke(new ObjectName(name), - operation, null, null); - } else { - Object argsA[]=new Object[ args.size()]; - String sigA[]=new String[args.size()]; - for( int i=0; iJMX JSR 160 MBeans Server. + *
    + *
  • open more then one JSR 160 rmi connection
  • + *
  • Get/Set Mbeans attributes
  • + *
  • Call Mbean Operation with arguments
  • + *
  • Argument values can be converted from string to int,long,float,double,boolean,ObjectName or InetAddress
  • + *
  • Query Mbeans
  • + *
  • Show Get, Call, Query result at Ant console log
  • + *
  • Bind Get, Call, Query result at Ant properties
  • + *
+ * + * Examples: + *
    + *
  • + * Get a session attribute hello from session with ref ${sessionid.0} form + * app Catalina:type=Manager,path=/ClusterTest,host=localhost + *
    + *   <jmx:invoke
    + *           name="Catalina:type=Manager,path=/ClusterTest,host=localhost" 
    + *           operation="getSessionAttribute"
    + *           resultproperty="hello">
    + *         <arg value="${sessionid.0}"/>
    + *         <arg value="Hello"/>
    + *   </jmx:invoke>
    + * 
    + *
  • + *
  • + * Create new AccessLogger at localhost + * + * <jmx:invoke + * name="Catalina:type=MBeanFactory" + * operation="createAcccesLoggerValve" + * resultproperty="acccesLoggerObjectName" + * > + * <arg value="Catalina:type=Host,host=localhost"/> + * </jmx:invoke> + * + * + *
  • + *
  • + * Remove existing AccessLogger at localhost + * + * <jmx:invoke + * name="Catalina:type=MBeanFactory" + * operation="removeValve" + * > + * <arg value="Catalina:type=Valve,name=AccessLogValve,host=localhost"/> + * </jmx:invoke> + * + * + *
  • + *
+ *

+ * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server + *

+ * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304013 $ $Date: 2005-07-22 13:39:08 +0200 (ven., 22 juil. 2005) $ + * @since 5.5.10 + */ + +public class JMXAccessorInvokeTask extends JMXAccessorTask { + + + // ----------------------------------------------------- Instance Variables + + private String operation ; + private List args=new ArrayList(); + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorInvokeTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * @return Returns the operation. + */ + public String getOperation() { + return operation; + } + /** + * @param operation The operation to set. + */ + public void setOperation(String operation) { + this.operation = operation; + } + + public void addArg(Arg arg ) { + args.add(arg); + } + + /** + * @return Returns the args. + */ + public List getArgs() { + return args; + } + /** + * @param args The args to set. + */ + public void setArgs(List args) { + this.args = args; + } + + // ------------------------------------------------------ protected Methods + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception BuildException + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + if ((operation == null)) { + throw new BuildException( + "Must specify a 'operation' for call"); + } + return jmxInvoke(jmxServerConnection, getName()); + } + + /** + * @param jmxServerConnection + * @throws Exception + */ + protected String jmxInvoke(MBeanServerConnection jmxServerConnection, String name) throws Exception { + Object result ; + if (args == null) { + result = jmxServerConnection.invoke(new ObjectName(name), + operation, null, null); + } else { + Object argsA[]=new Object[ args.size()]; + String sigA[]=new String[args.size()]; + for( int i=0; i - *
  • open no existing JSR 160 rmi jmx connection
  • - *
  • Get all Mbeans attributes
  • - *
  • Get only the Query Mbeans ObjectNames
  • - *
  • Show query result as Ant console log
  • - *
  • Bind query result as Ant properties
  • - * - *
    - * Query a list of Mbeans. - *
    - *   <jmxQuery
    - *           host="127.0.0.1"
    - *           port="9014"
    - *           name="Catalina:type=Manager,* 
    - *           resultproperty="manager" />
    - * 
    - * with attribute attributebinding="true" you can get - * all attributes also from result objects.
    - * The poperty manager.lenght show the size of the result - * and with manager.[0..lenght].name the - * resulted ObjectNames are saved. - * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ - * @since 5.5.10 - */ - -public class JMXAccessorQueryTask extends JMXAccessorTask { - - // ----------------------------------------------------- Instance Variables - - private boolean attributebinding = false; - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorQueryTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * @return Returns the attributebinding. - */ - public boolean isAttributebinding() { - return attributebinding; - } - /** - * @param attributeBinding The attributebinding to set. - */ - public void setAttributebinding(boolean attributeBinding) { - this.attributebinding = attributeBinding; - } - - // ------------------------------------------------------ protected Methods - - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception Exception - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - return jmxQuery(jmxServerConnection, getName()); - - } - - - /** - * Call Mbean server for some mbeans with same domain, attributes. - * with attributebindung=true you can save all attributes from all found objects - * as your ant properties - * @param jmxServerConnection - * @param qry - * @return The query result - */ - protected String jmxQuery(MBeanServerConnection jmxServerConnection, - String qry) { - String isError = null; - Set names = null; - String resultproperty = getResultproperty(); - try { - names = jmxServerConnection.queryNames(new ObjectName(qry), null); - if (resultproperty != null) { - setProperty(resultproperty + ".Length",Integer.toString(names.size())); - } - } catch (Exception e) { - if (isEcho()) - handleErrorOutput(e.getMessage()); - return "Can't query mbeans " + qry; - } - - if (resultproperty != null) { - Iterator it = names.iterator(); - int oindex = 0; - String pname = null; - while (it.hasNext()) { - ObjectName oname = (ObjectName) it.next(); - pname = resultproperty + "." + Integer.toString(oindex) + "."; - oindex++; - setProperty(pname + "Name", oname.toString()); - if (isAttributebinding()) { - bindAttributes(jmxServerConnection, resultproperty, pname, oname); - - } - } - } - return isError; - } - - /** - * @param jmxServerConnection - * @param resultproperty - * @param pname - * @param oname - */ - protected void bindAttributes(MBeanServerConnection jmxServerConnection, String resultproperty, String pname, ObjectName oname) { - if (jmxServerConnection != null && resultproperty != null - && pname != null && oname != null ) { - try { - MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); - String code = minfo.getClassName(); - if ("org.apache.tomcat.util.modeler.BaseModelMBean".equals(code)) { - code = (String) jmxServerConnection.getAttribute(oname, - "modelerType"); - } - MBeanAttributeInfo attrs[] = minfo.getAttributes(); - Object value = null; - - for (int i = 0; i < attrs.length; i++) { - if (!attrs[i].isReadable()) - continue; - String attName = attrs[i].getName(); - if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 - || attName.indexOf(" ") >= 0) { - continue; - } - - try { - value = jmxServerConnection - .getAttribute(oname, attName); - } catch (Throwable t) { - if (isEcho()) - handleErrorOutput("Error getting attribute " - + oname + " " + pname + attName + " " - + t.toString()); - continue; - } - if (value == null) - continue; - if ("modelerType".equals(attName)) - continue; - createProperty(pname + attName, value); - } - } catch (Exception e) { - // Ignore - } - } - } -} +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant.jmx; + + +import java.util.Iterator; +import java.util.Set; + +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; + + +/** + * Query for Mbeans. + *
      + *
    • open no existing JSR 160 rmi jmx connection
    • + *
    • Get all Mbeans attributes
    • + *
    • Get only the Query Mbeans ObjectNames
    • + *
    • Show query result as Ant console log
    • + *
    • Bind query result as Ant properties
    • + *
    + *
    + * Query a list of Mbeans. + *
    + *   <jmxQuery
    + *           host="127.0.0.1"
    + *           port="9014"
    + *           name="Catalina:type=Manager,* 
    + *           resultproperty="manager" />
    + * 
    + * with attribute attributebinding="true" you can get + * all attributes also from result objects.
    + * The poperty manager.lenght show the size of the result + * and with manager.[0..lenght].name the + * resulted ObjectNames are saved. + * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ + * @since 5.5.10 + */ + +public class JMXAccessorQueryTask extends JMXAccessorTask { + + // ----------------------------------------------------- Instance Variables + + private boolean attributebinding = false; + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorQueryTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * @return Returns the attributebinding. + */ + public boolean isAttributebinding() { + return attributebinding; + } + /** + * @param attributeBinding The attributebinding to set. + */ + public void setAttributebinding(boolean attributeBinding) { + this.attributebinding = attributeBinding; + } + + // ------------------------------------------------------ protected Methods + + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception Exception + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + return jmxQuery(jmxServerConnection, getName()); + + } + + + /** + * Call Mbean server for some mbeans with same domain, attributes. + * with attributebindung=true you can save all attributes from all found objects + * as your ant properties + * @param jmxServerConnection + * @param qry + * @return The query result + */ + protected String jmxQuery(MBeanServerConnection jmxServerConnection, + String qry) { + String isError = null; + Set names = null; + String resultproperty = getResultproperty(); + try { + names = jmxServerConnection.queryNames(new ObjectName(qry), null); + if (resultproperty != null) { + setProperty(resultproperty + ".Length",Integer.toString(names.size())); + } + } catch (Exception e) { + if (isEcho()) + handleErrorOutput(e.getMessage()); + return "Can't query mbeans " + qry; + } + + if (resultproperty != null) { + Iterator it = names.iterator(); + int oindex = 0; + String pname = null; + while (it.hasNext()) { + ObjectName oname = (ObjectName) it.next(); + pname = resultproperty + "." + Integer.toString(oindex) + "."; + oindex++; + setProperty(pname + "Name", oname.toString()); + if (isAttributebinding()) { + bindAttributes(jmxServerConnection, resultproperty, pname, oname); + + } + } + } + return isError; + } + + /** + * @param jmxServerConnection + * @param resultproperty + * @param pname + * @param oname + */ + protected void bindAttributes(MBeanServerConnection jmxServerConnection, String resultproperty, String pname, ObjectName oname) { + if (jmxServerConnection != null && resultproperty != null + && pname != null && oname != null ) { + try { + MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); + String code = minfo.getClassName(); + if ("org.apache.tomcat.util.modeler.BaseModelMBean".equals(code)) { + code = (String) jmxServerConnection.getAttribute(oname, + "modelerType"); + } + MBeanAttributeInfo attrs[] = minfo.getAttributes(); + Object value = null; + + for (int i = 0; i < attrs.length; i++) { + if (!attrs[i].isReadable()) + continue; + String attName = attrs[i].getName(); + if (attName.indexOf("=") >= 0 || attName.indexOf(":") >= 0 + || attName.indexOf(" ") >= 0) { + continue; + } + + try { + value = jmxServerConnection + .getAttribute(oname, attName); + } catch (Throwable t) { + if (isEcho()) + handleErrorOutput("Error getting attribute " + + oname + " " + pname + attName + " " + + t.toString()); + continue; + } + if (value == null) + continue; + if ("modelerType".equals(attName)) + continue; + createProperty(pname + attName, value); + } + } catch (Exception e) { + // Ignore + } + } + } +} diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java index b9e6ea00d..6daa8b257 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorSetTask.java @@ -1,220 +1,220 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.ant.jmx; - - -import javax.management.Attribute; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; - - -/** - * Access JMX JSR 160 MBeans Server. - *
      - *
    • Get Mbeans attributes
    • - *
    • Show Get result as Ant console log
    • - *
    • Bind Get result as Ant properties
    • - *
    - *

    - * Examples: - * Set a Mbean Manager attribute maxActiveSessions. - * Set this attribute with fresh jmx connection without save reference - *

    - *   <jmx:set
    - *           host="127.0.0.1"
    - *           port="9014"
    - *           ref=""
    - *           name="Catalina:type=Manager,path="/ClusterTest",host=localhost" 
    - *           attribute="maxActiveSessions"
    - *           value="100"
    - *           type="int"
    - *           echo="false">
    - *       />
    - * 
    - *

    - *

    - * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server - *

    - * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ - * @since 5.5.10 - */ - -public class JMXAccessorSetTask extends JMXAccessorTask { - - // ----------------------------------------------------- Instance Variables - - private String attribute; - private String value; - private String type; - private boolean convert = false ; - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorSetTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * @return Returns the attribute. - */ - public String getAttribute() { - return attribute; - } - - /** - * @param attribute The attribute to set. - */ - public void setAttribute(String attribute) { - this.attribute = attribute; - } - - /** - * @return Returns the value. - */ - public String getValue() { - return value; - } - /** - * @param value The value to set. - */ - public void setValue(String value) { - this.value = value; - } - - - /** - * @return Returns the type. - */ - public String getType() { - return type; - } - - /** - * @param valueType The type to set. - */ - public void setType(String valueType) { - this.type = valueType; - } - - - /** - * @return Returns the convert. - */ - public boolean isConvert() { - return convert; - } - /** - * @param convert The convert to set. - */ - public void setConvert(boolean convert) { - this.convert = convert; - } - // ------------------------------------------------------ protected Methods - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception Exception - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - if ((attribute == null || value == null)) { - throw new BuildException( - "Must specify a 'attribute' and 'value' for set"); - } - return jmxSet(jmxServerConnection, getName()); - } - - /** - * @param jmxServerConnection - * @param name - * @throws Exception - */ - protected String jmxSet(MBeanServerConnection jmxServerConnection, - String name) throws Exception { - Object realValue; - if (type != null) { - realValue = convertStringToType(value, type); - } else { - if (isConvert()) { - String mType = getMBeanAttributeType(jmxServerConnection, name, - attribute); - realValue = convertStringToType(value, mType); - } else - realValue = value; - } - jmxServerConnection.setAttribute(new ObjectName(name), new Attribute( - attribute, realValue)); - return null; - } - - - - /** - * Get MBean Attriute from Mbean Server - * @param jmxServerConnection - * @param name - * @param attribute - * @return The type - * @throws Exception - */ - protected String getMBeanAttributeType( - MBeanServerConnection jmxServerConnection, - String name, - String attribute) throws Exception { - ObjectName oname = new ObjectName(name); - String mattrType = null; - MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); - MBeanAttributeInfo attrs[] = minfo.getAttributes(); - if (attrs != null) { - for (int i = 0; mattrType == null && i < attrs.length; i++) { - if (attribute.equals(attrs[i].getName())) - mattrType = attrs[i].getType(); - } - } - return mattrType; - } - } +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.ant.jmx; + + +import javax.management.Attribute; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; + + +/** + * Access JMX JSR 160 MBeans Server. + *
      + *
    • Get Mbeans attributes
    • + *
    • Show Get result as Ant console log
    • + *
    • Bind Get result as Ant properties
    • + *
    + *

    + * Examples: + * Set a Mbean Manager attribute maxActiveSessions. + * Set this attribute with fresh jmx connection without save reference + *

    + *   <jmx:set
    + *           host="127.0.0.1"
    + *           port="9014"
    + *           ref=""
    + *           name="Catalina:type=Manager,path="/ClusterTest",host=localhost" 
    + *           attribute="maxActiveSessions"
    + *           value="100"
    + *           type="int"
    + *           echo="false">
    + *       />
    + * 
    + *

    + *

    + * First call to a remote MBeanserver save the JMXConnection a referenz jmx.server + *

    + * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ + * @since 5.5.10 + */ + +public class JMXAccessorSetTask extends JMXAccessorTask { + + // ----------------------------------------------------- Instance Variables + + private String attribute; + private String value; + private String type; + private boolean convert = false ; + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorSetTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * @return Returns the attribute. + */ + public String getAttribute() { + return attribute; + } + + /** + * @param attribute The attribute to set. + */ + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + /** + * @return Returns the value. + */ + public String getValue() { + return value; + } + /** + * @param value The value to set. + */ + public void setValue(String value) { + this.value = value; + } + + + /** + * @return Returns the type. + */ + public String getType() { + return type; + } + + /** + * @param valueType The type to set. + */ + public void setType(String valueType) { + this.type = valueType; + } + + + /** + * @return Returns the convert. + */ + public boolean isConvert() { + return convert; + } + /** + * @param convert The convert to set. + */ + public void setConvert(boolean convert) { + this.convert = convert; + } + // ------------------------------------------------------ protected Methods + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception Exception + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + if ((attribute == null || value == null)) { + throw new BuildException( + "Must specify a 'attribute' and 'value' for set"); + } + return jmxSet(jmxServerConnection, getName()); + } + + /** + * @param jmxServerConnection + * @param name + * @throws Exception + */ + protected String jmxSet(MBeanServerConnection jmxServerConnection, + String name) throws Exception { + Object realValue; + if (type != null) { + realValue = convertStringToType(value, type); + } else { + if (isConvert()) { + String mType = getMBeanAttributeType(jmxServerConnection, name, + attribute); + realValue = convertStringToType(value, mType); + } else + realValue = value; + } + jmxServerConnection.setAttribute(new ObjectName(name), new Attribute( + attribute, realValue)); + return null; + } + + + + /** + * Get MBean Attriute from Mbean Server + * @param jmxServerConnection + * @param name + * @param attribute + * @return The type + * @throws Exception + */ + protected String getMBeanAttributeType( + MBeanServerConnection jmxServerConnection, + String name, + String attribute) throws Exception { + ObjectName oname = new ObjectName(name); + String mattrType = null; + MBeanInfo minfo = jmxServerConnection.getMBeanInfo(oname); + MBeanAttributeInfo attrs[] = minfo.getAttributes(); + if (attrs != null) { + for (int i = 0; mattrType == null && i < attrs.length; i++) { + if (attribute.equals(attrs[i].getName())) + mattrType = attrs[i].getType(); + } + } + return mattrType; + } + } diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java index 4661b6a4a..6a3266130 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorTask.java @@ -1,731 +1,731 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ant.jmx; - -import java.io.IOException; -import java.lang.reflect.Array; -import java.net.InetAddress; -import java.net.MalformedURLException; -import java.net.UnknownHostException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; - -import javax.management.MBeanServerConnection; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.openmbean.CompositeData; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.remote.JMXConnector; -import javax.management.remote.JMXConnectorFactory; -import javax.management.remote.JMXServiceURL; - -import org.apache.catalina.ant.BaseRedirectorHelperTask; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; - -/** - * Access JMX JSR 160 MBeans Server. - *
      - *
    • open more then one JSR 160 rmi connection
    • - *
    • Get/Set Mbeans attributes
    • - *
    • Call Mbean Operation with arguments
    • - *
    • Argument values can be converted from string to - * int,long,float,double,boolean,ObjectName or InetAddress
    • - *
    • Query Mbeans
    • - *
    • Show Get, Call, Query result at Ant console log
    • - *
    • Bind Get, Call, Query result at Ant properties
    • - *
    - * - * Examples: open server with reference and autorisation - * - *
    - * 
    - *    <jmxOpen
    - *            host="127.0.0.1"
    - *            port="9014"
    - *            username="monitorRole"
    - *            password="mysecret"
    - *            ref="jmx.myserver" 
    - *        />
    - *  
    - * 
    - * - * All calls after opening with same refid reuse the connection. - *

    - * First call to a remote MBeanserver save the JMXConnection a referenz - * jmx.server - *

    - * All JMXAccessorXXXTask support the attribute if and - * unless. With if the task is only execute when property - * exist and with unless when property not exists.
    NOTE - * : These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ - * @since 5.5.10 - */ - -public class JMXAccessorTask extends BaseRedirectorHelperTask { - - // ----------------------------------------------------- Instance Variables - - public static String JMX_SERVICE_PREFIX = "service:jmx:rmi:///jndi/rmi://"; - - public static String JMX_SERVICE_SUFFIX = "/jmxrmi"; - - private String name = null; - - private String resultproperty; - - private String url = null; - - private String host = "localhost"; - - private String port = "8050"; - - private String password = null; - - private String username = null; - - private String ref = "jmx.server"; - - private boolean echo = false; - - private boolean separatearrayresults = true; - - private String delimiter; - - private String unlessCondition; - - private String ifCondition; - - private Properties properties = new Properties(); - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorTask/1.1"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - // ------------------------------------------------------------- Properties - - /** - * The name used at remote MbeanServer - */ - - public String getName() { - return (this.name); - } - - public void setName(String objectName) { - this.name = objectName; - } - - /** - * @return Returns the resultproperty. - */ - public String getResultproperty() { - return resultproperty; - } - - /** - * @param propertyName The resultproperty to set. - */ - public void setResultproperty(String propertyName) { - this.resultproperty = propertyName; - } - - /** - * @return Returns the delimiter. - */ - public String getDelimiter() { - return delimiter; - } - - /** - * @param separator The delimiter to set. - */ - public void setDelimiter(String separator) { - this.delimiter = separator; - } - - /** - * @return Returns the echo. - */ - public boolean isEcho() { - return echo; - } - - /** - * @param echo - * The echo to set. - */ - public void setEcho(boolean echo) { - this.echo = echo; - } - - /** - * @return Returns the separatearrayresults. - */ - public boolean isSeparatearrayresults() { - return separatearrayresults; - } - - /** - * @param separateArrayResults - * The separatearrayresults to set. - */ - public void setSeparatearrayresults(boolean separateArrayResults) { - this.separatearrayresults = separateArrayResults; - } - - /** - * The login password for the Manager application. - */ - public String getPassword() { - return (this.password); - } - - public void setPassword(String password) { - this.password = password; - } - - /** - * The login username for the JMX MBeanServer. - */ - public String getUsername() { - return (this.username); - } - - public void setUsername(String username) { - this.username = username; - } - - /** - * The URL of the JMX JSR 160 MBeanServer to be used. - */ - - public String getUrl() { - return (this.url); - } - - public void setUrl(String url) { - this.url = url; - } - - /** - * The Host of the JMX JSR 160 MBeanServer to be used. - */ - - public String getHost() { - return (this.host); - } - - public void setHost(String host) { - this.host = host; - } - - /** - * The Port of the JMX JSR 160 MBeanServer to be used. - */ - - public String getPort() { - return (this.port); - } - - public void setPort(String port) { - this.port = port; - } - - /** - * @return Returns the useRef. - */ - public boolean isUseRef() { - return ref != null && !"".equals(ref); - } - - /** - * @return Returns the ref. - */ - public String getRef() { - return ref; - } - - /** - * @param refId The ref to set. - */ - public void setRef(String refId) { - this.ref = refId; - } - - /** - * @return Returns the ifCondition. - */ - public String getIf() { - return ifCondition; - } - - /** - * Only execute if a property of the given name exists in the current - * project. - * - * @param c property name - */ - public void setIf(String c) { - ifCondition = c; - } - - /** - * @return Returns the unlessCondition. - */ - public String getUnless() { - return unlessCondition; - } - - /** - * Only execute if a property of the given name does not exist in the - * current project. - * - * @param c property name - */ - public void setUnless(String c) { - unlessCondition = c; - } - - // --------------------------------------------------------- Public Methods - - /** - * Execute the specified command. This logic only performs the common - * attribute validation required by all subclasses; it does not perform any - * functional logic directly. - * - * @exception BuildException - * if a validation error occurs - */ - public void execute() throws BuildException { - if (testIfCondition() && testUnlessCondition()) { - try { - String error = null; - - MBeanServerConnection jmxServerConnection = getJMXConnection(); - error = jmxExecute(jmxServerConnection); - if (error != null && isFailOnError()) { - // exception should be thrown only if failOnError == true - // or error line will be logged twice - throw new BuildException(error); - } - } catch (Throwable t) { - if (isFailOnError()) { - throw new BuildException(t); - } else { - handleErrorOutput(t.getMessage()); - } - } finally { - closeRedirector(); - } - } - } - - /** - * create a new JMX Connection with auth when username and password is set. - */ - public static MBeanServerConnection createJMXConnection(String url, - String host, String port, String username, String password) - throws MalformedURLException, IOException { - String urlForJMX; - if (url != null) - urlForJMX = url; - else - urlForJMX = JMX_SERVICE_PREFIX + host + ":" + port - + JMX_SERVICE_SUFFIX; - Map environment = null; - if (username != null && password != null) { - String[] credentials = new String[2]; - credentials[0] = username; - credentials[1] = password; - environment = new HashMap(); - environment.put(JMXConnector.CREDENTIALS, credentials); - } - return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), - environment).getMBeanServerConnection(); - - } - - /** - * test the if condition - * - * @return true if there is no if condition, or the named property exists - */ - protected boolean testIfCondition() { - if (ifCondition == null || "".equals(ifCondition)) { - return true; - } - return getProperty(ifCondition) != null; - } - - /** - * test the unless condition - * - * @return true if there is no unless condition, or there is a named - * property but it doesn't exist - */ - protected boolean testUnlessCondition() { - if (unlessCondition == null || "".equals(unlessCondition)) { - return true; - } - return getProperty(unlessCondition) == null; - } - - /** - * Get Current Connection from ref parameter or create a new one! - * - * @return The server connection - * @throws MalformedURLException - * @throws IOException - */ - public static MBeanServerConnection accessJMXConnection(Project project, - String url, String host, String port, String username, - String password, String refId) throws MalformedURLException, - IOException { - MBeanServerConnection jmxServerConnection = null; - boolean isRef = project != null && refId != null && refId.length() > 0; - if (isRef) { - Object pref = project.getReference(refId); - try { - jmxServerConnection = (MBeanServerConnection) pref; - } catch (ClassCastException cce) { - if (project != null) { - project.log("wrong object reference " + refId + " - " - + pref.getClass()); - } - return null; - } - } - if (jmxServerConnection == null) { - jmxServerConnection = createJMXConnection(url, host, port, - username, password); - } - if (isRef && jmxServerConnection != null) { - project.addReference(refId, jmxServerConnection); - } - return jmxServerConnection; - } - - // ------------------------------------------------------ protected Methods - - /** - * get JMXConnection - * - * @return The connection - * @throws MalformedURLException - * @throws IOException - */ - protected MBeanServerConnection getJMXConnection() - throws MalformedURLException, IOException { - - MBeanServerConnection jmxServerConnection = null; - if (isUseRef()) { - Object pref = null ; - if(getProject() != null) { - pref = getProject().getReference(getRef()); - if (pref != null) { - try { - jmxServerConnection = (MBeanServerConnection) pref; - } catch (ClassCastException cce) { - getProject().log( - "Wrong object reference " + getRef() + " - " - + pref.getClass()); - return null; - } - } - } - if (jmxServerConnection == null) { - jmxServerConnection = accessJMXConnection(getProject(), - getUrl(), getHost(), getPort(), getUsername(), - getPassword(), getRef()); - } - } else { - jmxServerConnection = accessJMXConnection(getProject(), getUrl(), - getHost(), getPort(), getUsername(), getPassword(), null); - } - return jmxServerConnection; - } - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception Exception - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if ((jmxServerConnection == null)) { - throw new BuildException("Must open a connection!"); - } else if (isEcho()) { - handleOutput("JMX Connection ref=" + ref + " is open!"); - } - return null; - } - - /** - * Convert string to datatype FIXME How we can transfer values from ant - * project reference store (ref)? - * - * @param value The value - * @param valueType The type - * @return The converted object - */ - protected Object convertStringToType(String value, String valueType) { - if ("java.lang.String".equals(valueType)) - return value; - - Object convertValue = value; - if ("java.lang.Integer".equals(valueType) || "int".equals(valueType)) { - try { - convertValue = new Integer(value); - } catch (NumberFormatException ex) { - if (isEcho()) - handleErrorOutput("Unable to convert to integer:" + value); - } - } else if ("java.lang.Long".equals(valueType) - || "long".equals(valueType)) { - try { - convertValue = new Long(value); - } catch (NumberFormatException ex) { - if (isEcho()) - handleErrorOutput("Unable to convert to long:" + value); - } - } else if ("java.lang.Boolean".equals(valueType) - || "boolean".equals(valueType)) { - convertValue = new Boolean(value); - } else if ("java.lang.Float".equals(valueType) - || "float".equals(valueType)) { - try { - convertValue = new Float(value); - } catch (NumberFormatException ex) { - if (isEcho()) - handleErrorOutput("Unable to convert to float:" + value); - } - } else if ("java.lang.Double".equals(valueType) - || "double".equals(valueType)) { - try { - convertValue = new Double(value); - } catch (NumberFormatException ex) { - if (isEcho()) - handleErrorOutput("Unable to convert to double:" + value); - } - } else if ("javax.management.ObjectName".equals(valueType) - || "name".equals(valueType)) { - try { - convertValue = new ObjectName(value); - } catch (MalformedObjectNameException e) { - if (isEcho()) - handleErrorOutput("Unable to convert to ObjectName:" - + value); - } - } else if ("java.net.InetAddress".equals(valueType)) { - try { - convertValue = InetAddress.getByName(value); - } catch (UnknownHostException exc) { - if (isEcho()) - handleErrorOutput("Unable to resolve host name:" + value); - } - } - return convertValue; - } - - /** - * @param name context of result - * @param result - */ - protected void echoResult(String name, Object result) { - if (isEcho()) { - if (result.getClass().isArray()) { - for (int i = 0; i < Array.getLength(result); i++) { - handleOutput(name + "." + i + "=" + Array.get(result, i)); - } - } else - handleOutput(name + "=" + result); - } - } - - /** - * create result as property with name from attribute resultproperty - * - * @param result The result - * @see #createProperty(String, Object) - */ - protected void createProperty(Object result) { - if (resultproperty != null) { - createProperty(resultproperty, result); - } - } - - /** - * create result as property with name from property prefix When result is - * an array and isSeparateArrayResults is true, resultproperty used as - * prefix (resultproperty.0-array.length and store the - * result array length at resultproperty.length. Other - * option is that you delemit your result with a delimiter - * (java.util.StringTokenizer is used). - * - * @param propertyPrefix - * @param result - */ - protected void createProperty(String propertyPrefix, Object result) { - if (propertyPrefix == null) - propertyPrefix = ""; - if (result instanceof CompositeDataSupport) { - CompositeDataSupport data = (CompositeDataSupport) result; - CompositeType compositeType = data.getCompositeType(); - Set keys = compositeType.keySet(); - for (Iterator iter = keys.iterator(); iter.hasNext();) { - String key = (String) iter.next(); - Object value = data.get(key); - OpenType type = compositeType.getType(key); - if (type instanceof SimpleType) { - setProperty(propertyPrefix + "." + key, value); - } else { - createProperty(propertyPrefix + "." + key, value); - } - } - } else if (result instanceof TabularDataSupport) { - TabularDataSupport data = (TabularDataSupport) result; - for (Iterator iter = data.keySet().iterator(); iter.hasNext();) { - Object key = iter.next(); - for (Iterator iter1 = ((List) key).iterator(); iter1.hasNext();) { - Object key1 = iter1.next(); - CompositeData valuedata = data.get(new Object[] { key1 }); - Object value = valuedata.get("value"); - OpenType type = valuedata.getCompositeType().getType( - "value"); - if (type instanceof SimpleType) { - setProperty(propertyPrefix + "." + key1, value); - } else { - createProperty(propertyPrefix + "." + key1, value); - } - } - } - } else if (result.getClass().isArray()) { - if (isSeparatearrayresults()) { - int size = 0; - for (int i = 0; i < Array.getLength(result); i++) { - if (setProperty(propertyPrefix + "." + size, Array.get( - result, i))) { - size++; - } - } - if (size > 0) { - setProperty(propertyPrefix + ".Length", Integer - .toString(size)); - } - } - } else { - String delim = getDelimiter(); - if (delim != null) { - StringTokenizer tokenizer = new StringTokenizer(result - .toString(), delim); - int size = 0; - for (; tokenizer.hasMoreTokens();) { - String token = tokenizer.nextToken(); - if (setProperty(propertyPrefix + "." + size, token)) { - size++; - } - } - if (size > 0) - setProperty(propertyPrefix + ".Length", Integer - .toString(size)); - } else { - setProperty(propertyPrefix, result.toString()); - } - } - } - - /** - * get all properties, when project is there got all project Properties - * @return properties - */ - public Map getProperties() { - Project currentProject = getProject(); - if (currentProject != null) { - return currentProject.getProperties(); - } else { - return properties; - } - } - - /** - * get all Properties - * @param property - * @return The property - */ - public String getProperty(String property) { - Project currentProject = getProject(); - if (currentProject != null) { - return currentProject.getProperty(property); - } else { - return properties.getProperty(property); - } - } - - /** - * @param property The property - * @param value The value - * @return True if successful - */ - public boolean setProperty(String property, Object value) { - if (property != null) { - if (value == null) - value = ""; - if (isEcho()) { - handleOutput(property + "=" + value.toString()); - } - Project currentProject = getProject(); - if (currentProject != null) { - currentProject.setNewProperty(property, value.toString()); - } else { - properties.setProperty(property, value.toString()); - } - return true; - } - return false; - } -} +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ant.jmx; + +import java.io.IOException; +import java.lang.reflect.Array; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; + +import javax.management.MBeanServerConnection; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.remote.JMXConnector; +import javax.management.remote.JMXConnectorFactory; +import javax.management.remote.JMXServiceURL; + +import org.apache.catalina.ant.BaseRedirectorHelperTask; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.Project; + +/** + * Access JMX JSR 160 MBeans Server. + *
      + *
    • open more then one JSR 160 rmi connection
    • + *
    • Get/Set Mbeans attributes
    • + *
    • Call Mbean Operation with arguments
    • + *
    • Argument values can be converted from string to + * int,long,float,double,boolean,ObjectName or InetAddress
    • + *
    • Query Mbeans
    • + *
    • Show Get, Call, Query result at Ant console log
    • + *
    • Bind Get, Call, Query result at Ant properties
    • + *
    + * + * Examples: open server with reference and autorisation + * + *
    + * 
    + *    <jmxOpen
    + *            host="127.0.0.1"
    + *            port="9014"
    + *            username="monitorRole"
    + *            password="mysecret"
    + *            ref="jmx.myserver" 
    + *        />
    + *  
    + * 
    + * + * All calls after opening with same refid reuse the connection. + *

    + * First call to a remote MBeanserver save the JMXConnection a referenz + * jmx.server + *

    + * All JMXAccessorXXXTask support the attribute if and + * unless. With if the task is only execute when property + * exist and with unless when property not exists.
    NOTE + * : These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304089 $ $Date: 2005-09-14 15:28:29 +0200 (mer., 14 sept. 2005) $ + * @since 5.5.10 + */ + +public class JMXAccessorTask extends BaseRedirectorHelperTask { + + // ----------------------------------------------------- Instance Variables + + public static String JMX_SERVICE_PREFIX = "service:jmx:rmi:///jndi/rmi://"; + + public static String JMX_SERVICE_SUFFIX = "/jmxrmi"; + + private String name = null; + + private String resultproperty; + + private String url = null; + + private String host = "localhost"; + + private String port = "8050"; + + private String password = null; + + private String username = null; + + private String ref = "jmx.server"; + + private boolean echo = false; + + private boolean separatearrayresults = true; + + private String delimiter; + + private String unlessCondition; + + private String ifCondition; + + private Properties properties = new Properties(); + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorTask/1.1"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + // ------------------------------------------------------------- Properties + + /** + * The name used at remote MbeanServer + */ + + public String getName() { + return (this.name); + } + + public void setName(String objectName) { + this.name = objectName; + } + + /** + * @return Returns the resultproperty. + */ + public String getResultproperty() { + return resultproperty; + } + + /** + * @param propertyName The resultproperty to set. + */ + public void setResultproperty(String propertyName) { + this.resultproperty = propertyName; + } + + /** + * @return Returns the delimiter. + */ + public String getDelimiter() { + return delimiter; + } + + /** + * @param separator The delimiter to set. + */ + public void setDelimiter(String separator) { + this.delimiter = separator; + } + + /** + * @return Returns the echo. + */ + public boolean isEcho() { + return echo; + } + + /** + * @param echo + * The echo to set. + */ + public void setEcho(boolean echo) { + this.echo = echo; + } + + /** + * @return Returns the separatearrayresults. + */ + public boolean isSeparatearrayresults() { + return separatearrayresults; + } + + /** + * @param separateArrayResults + * The separatearrayresults to set. + */ + public void setSeparatearrayresults(boolean separateArrayResults) { + this.separatearrayresults = separateArrayResults; + } + + /** + * The login password for the Manager application. + */ + public String getPassword() { + return (this.password); + } + + public void setPassword(String password) { + this.password = password; + } + + /** + * The login username for the JMX MBeanServer. + */ + public String getUsername() { + return (this.username); + } + + public void setUsername(String username) { + this.username = username; + } + + /** + * The URL of the JMX JSR 160 MBeanServer to be used. + */ + + public String getUrl() { + return (this.url); + } + + public void setUrl(String url) { + this.url = url; + } + + /** + * The Host of the JMX JSR 160 MBeanServer to be used. + */ + + public String getHost() { + return (this.host); + } + + public void setHost(String host) { + this.host = host; + } + + /** + * The Port of the JMX JSR 160 MBeanServer to be used. + */ + + public String getPort() { + return (this.port); + } + + public void setPort(String port) { + this.port = port; + } + + /** + * @return Returns the useRef. + */ + public boolean isUseRef() { + return ref != null && !"".equals(ref); + } + + /** + * @return Returns the ref. + */ + public String getRef() { + return ref; + } + + /** + * @param refId The ref to set. + */ + public void setRef(String refId) { + this.ref = refId; + } + + /** + * @return Returns the ifCondition. + */ + public String getIf() { + return ifCondition; + } + + /** + * Only execute if a property of the given name exists in the current + * project. + * + * @param c property name + */ + public void setIf(String c) { + ifCondition = c; + } + + /** + * @return Returns the unlessCondition. + */ + public String getUnless() { + return unlessCondition; + } + + /** + * Only execute if a property of the given name does not exist in the + * current project. + * + * @param c property name + */ + public void setUnless(String c) { + unlessCondition = c; + } + + // --------------------------------------------------------- Public Methods + + /** + * Execute the specified command. This logic only performs the common + * attribute validation required by all subclasses; it does not perform any + * functional logic directly. + * + * @exception BuildException + * if a validation error occurs + */ + public void execute() throws BuildException { + if (testIfCondition() && testUnlessCondition()) { + try { + String error = null; + + MBeanServerConnection jmxServerConnection = getJMXConnection(); + error = jmxExecute(jmxServerConnection); + if (error != null && isFailOnError()) { + // exception should be thrown only if failOnError == true + // or error line will be logged twice + throw new BuildException(error); + } + } catch (Throwable t) { + if (isFailOnError()) { + throw new BuildException(t); + } else { + handleErrorOutput(t.getMessage()); + } + } finally { + closeRedirector(); + } + } + } + + /** + * create a new JMX Connection with auth when username and password is set. + */ + public static MBeanServerConnection createJMXConnection(String url, + String host, String port, String username, String password) + throws MalformedURLException, IOException { + String urlForJMX; + if (url != null) + urlForJMX = url; + else + urlForJMX = JMX_SERVICE_PREFIX + host + ":" + port + + JMX_SERVICE_SUFFIX; + Map environment = null; + if (username != null && password != null) { + String[] credentials = new String[2]; + credentials[0] = username; + credentials[1] = password; + environment = new HashMap(); + environment.put(JMXConnector.CREDENTIALS, credentials); + } + return JMXConnectorFactory.connect(new JMXServiceURL(urlForJMX), + environment).getMBeanServerConnection(); + + } + + /** + * test the if condition + * + * @return true if there is no if condition, or the named property exists + */ + protected boolean testIfCondition() { + if (ifCondition == null || "".equals(ifCondition)) { + return true; + } + return getProperty(ifCondition) != null; + } + + /** + * test the unless condition + * + * @return true if there is no unless condition, or there is a named + * property but it doesn't exist + */ + protected boolean testUnlessCondition() { + if (unlessCondition == null || "".equals(unlessCondition)) { + return true; + } + return getProperty(unlessCondition) == null; + } + + /** + * Get Current Connection from ref parameter or create a new one! + * + * @return The server connection + * @throws MalformedURLException + * @throws IOException + */ + public static MBeanServerConnection accessJMXConnection(Project project, + String url, String host, String port, String username, + String password, String refId) throws MalformedURLException, + IOException { + MBeanServerConnection jmxServerConnection = null; + boolean isRef = project != null && refId != null && refId.length() > 0; + if (isRef) { + Object pref = project.getReference(refId); + try { + jmxServerConnection = (MBeanServerConnection) pref; + } catch (ClassCastException cce) { + if (project != null) { + project.log("wrong object reference " + refId + " - " + + pref.getClass()); + } + return null; + } + } + if (jmxServerConnection == null) { + jmxServerConnection = createJMXConnection(url, host, port, + username, password); + } + if (isRef && jmxServerConnection != null) { + project.addReference(refId, jmxServerConnection); + } + return jmxServerConnection; + } + + // ------------------------------------------------------ protected Methods + + /** + * get JMXConnection + * + * @return The connection + * @throws MalformedURLException + * @throws IOException + */ + protected MBeanServerConnection getJMXConnection() + throws MalformedURLException, IOException { + + MBeanServerConnection jmxServerConnection = null; + if (isUseRef()) { + Object pref = null ; + if(getProject() != null) { + pref = getProject().getReference(getRef()); + if (pref != null) { + try { + jmxServerConnection = (MBeanServerConnection) pref; + } catch (ClassCastException cce) { + getProject().log( + "Wrong object reference " + getRef() + " - " + + pref.getClass()); + return null; + } + } + } + if (jmxServerConnection == null) { + jmxServerConnection = accessJMXConnection(getProject(), + getUrl(), getHost(), getPort(), getUsername(), + getPassword(), getRef()); + } + } else { + jmxServerConnection = accessJMXConnection(getProject(), getUrl(), + getHost(), getPort(), getUsername(), getPassword(), null); + } + return jmxServerConnection; + } + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception Exception + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if ((jmxServerConnection == null)) { + throw new BuildException("Must open a connection!"); + } else if (isEcho()) { + handleOutput("JMX Connection ref=" + ref + " is open!"); + } + return null; + } + + /** + * Convert string to datatype FIXME How we can transfer values from ant + * project reference store (ref)? + * + * @param value The value + * @param valueType The type + * @return The converted object + */ + protected Object convertStringToType(String value, String valueType) { + if ("java.lang.String".equals(valueType)) + return value; + + Object convertValue = value; + if ("java.lang.Integer".equals(valueType) || "int".equals(valueType)) { + try { + convertValue = new Integer(value); + } catch (NumberFormatException ex) { + if (isEcho()) + handleErrorOutput("Unable to convert to integer:" + value); + } + } else if ("java.lang.Long".equals(valueType) + || "long".equals(valueType)) { + try { + convertValue = new Long(value); + } catch (NumberFormatException ex) { + if (isEcho()) + handleErrorOutput("Unable to convert to long:" + value); + } + } else if ("java.lang.Boolean".equals(valueType) + || "boolean".equals(valueType)) { + convertValue = new Boolean(value); + } else if ("java.lang.Float".equals(valueType) + || "float".equals(valueType)) { + try { + convertValue = new Float(value); + } catch (NumberFormatException ex) { + if (isEcho()) + handleErrorOutput("Unable to convert to float:" + value); + } + } else if ("java.lang.Double".equals(valueType) + || "double".equals(valueType)) { + try { + convertValue = new Double(value); + } catch (NumberFormatException ex) { + if (isEcho()) + handleErrorOutput("Unable to convert to double:" + value); + } + } else if ("javax.management.ObjectName".equals(valueType) + || "name".equals(valueType)) { + try { + convertValue = new ObjectName(value); + } catch (MalformedObjectNameException e) { + if (isEcho()) + handleErrorOutput("Unable to convert to ObjectName:" + + value); + } + } else if ("java.net.InetAddress".equals(valueType)) { + try { + convertValue = InetAddress.getByName(value); + } catch (UnknownHostException exc) { + if (isEcho()) + handleErrorOutput("Unable to resolve host name:" + value); + } + } + return convertValue; + } + + /** + * @param name context of result + * @param result + */ + protected void echoResult(String name, Object result) { + if (isEcho()) { + if (result.getClass().isArray()) { + for (int i = 0; i < Array.getLength(result); i++) { + handleOutput(name + "." + i + "=" + Array.get(result, i)); + } + } else + handleOutput(name + "=" + result); + } + } + + /** + * create result as property with name from attribute resultproperty + * + * @param result The result + * @see #createProperty(String, Object) + */ + protected void createProperty(Object result) { + if (resultproperty != null) { + createProperty(resultproperty, result); + } + } + + /** + * create result as property with name from property prefix When result is + * an array and isSeparateArrayResults is true, resultproperty used as + * prefix (resultproperty.0-array.length and store the + * result array length at resultproperty.length. Other + * option is that you delemit your result with a delimiter + * (java.util.StringTokenizer is used). + * + * @param propertyPrefix + * @param result + */ + protected void createProperty(String propertyPrefix, Object result) { + if (propertyPrefix == null) + propertyPrefix = ""; + if (result instanceof CompositeDataSupport) { + CompositeDataSupport data = (CompositeDataSupport) result; + CompositeType compositeType = data.getCompositeType(); + Set keys = compositeType.keySet(); + for (Iterator iter = keys.iterator(); iter.hasNext();) { + String key = (String) iter.next(); + Object value = data.get(key); + OpenType type = compositeType.getType(key); + if (type instanceof SimpleType) { + setProperty(propertyPrefix + "." + key, value); + } else { + createProperty(propertyPrefix + "." + key, value); + } + } + } else if (result instanceof TabularDataSupport) { + TabularDataSupport data = (TabularDataSupport) result; + for (Iterator iter = data.keySet().iterator(); iter.hasNext();) { + Object key = iter.next(); + for (Iterator iter1 = ((List) key).iterator(); iter1.hasNext();) { + Object key1 = iter1.next(); + CompositeData valuedata = data.get(new Object[] { key1 }); + Object value = valuedata.get("value"); + OpenType type = valuedata.getCompositeType().getType( + "value"); + if (type instanceof SimpleType) { + setProperty(propertyPrefix + "." + key1, value); + } else { + createProperty(propertyPrefix + "." + key1, value); + } + } + } + } else if (result.getClass().isArray()) { + if (isSeparatearrayresults()) { + int size = 0; + for (int i = 0; i < Array.getLength(result); i++) { + if (setProperty(propertyPrefix + "." + size, Array.get( + result, i))) { + size++; + } + } + if (size > 0) { + setProperty(propertyPrefix + ".Length", Integer + .toString(size)); + } + } + } else { + String delim = getDelimiter(); + if (delim != null) { + StringTokenizer tokenizer = new StringTokenizer(result + .toString(), delim); + int size = 0; + for (; tokenizer.hasMoreTokens();) { + String token = tokenizer.nextToken(); + if (setProperty(propertyPrefix + "." + size, token)) { + size++; + } + } + if (size > 0) + setProperty(propertyPrefix + ".Length", Integer + .toString(size)); + } else { + setProperty(propertyPrefix, result.toString()); + } + } + } + + /** + * get all properties, when project is there got all project Properties + * @return properties + */ + public Map getProperties() { + Project currentProject = getProject(); + if (currentProject != null) { + return currentProject.getProperties(); + } else { + return properties; + } + } + + /** + * get all Properties + * @param property + * @return The property + */ + public String getProperty(String property) { + Project currentProject = getProject(); + if (currentProject != null) { + return currentProject.getProperty(property); + } else { + return properties.getProperty(property); + } + } + + /** + * @param property The property + * @param value The value + * @return True if successful + */ + public boolean setProperty(String property, Object value) { + if (property != null) { + if (value == null) + value = ""; + if (isEcho()) { + handleOutput(property + "=" + value.toString()); + } + Project currentProject = getProject(); + if (currentProject != null) { + currentProject.setNewProperty(property, value.toString()); + } else { + properties.setProperty(property, value.toString()); + } + return true; + } + return false; + } +} diff --git a/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java b/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java index ea1eea954..daa5530f9 100644 --- a/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java +++ b/java/org/apache/catalina/ant/jmx/JMXAccessorUnregisterTask.java @@ -1,112 +1,112 @@ -/* - * Copyright 2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.ant.jmx; - -import java.util.ArrayList; -import java.util.List; - -import javax.management.MBeanServerConnection; -import javax.management.ObjectName; - -import org.apache.tools.ant.BuildException; - -/** - * unregister a MBean at JMX JSR 160 MBeans Server. - *
      - *
    • unregister Mbeans
    • - *
    - *

    - * Examples: - *
    - * unregister an existing Mbean at jmx.server connection - *

    - *   <jmx:unregister
    - *           ref="jmx.server"
    - *           name="Catalina:type=MBeanFactory" />
    - * 
    - *

    - *

    - * WARNINGNot all Tomcat MBeans can successfully unregister remotely. The mbean - * unregistration don't remove valves, realm, .. from parent class. - * Please, use the MBeanFactory operation to remove valves and realms. - *

    - *

    - * First call to a remote MBeanserver save the JMXConnection a reference jmx.server - *

    - * These tasks require Ant 1.6 or later interface. - * - * @author Peter Rossbach - * @version $Revision: 304089 $ - * @since 5.5.12 - */ -public class JMXAccessorUnregisterTask extends JMXAccessorTask { - - // ----------------------------------------------------- Instance Info - - /** - * Descriptive information describing this implementation. - */ - private static final String info = "org.apache.catalina.ant.JMXAccessorUnregisterTask/1.0"; - - /** - * Return descriptive information about this implementation and the - * corresponding version number, in the format - * <description>/<version>. - * @return Returns the class info. - */ - public String getInfo() { - - return (info); - - } - // ------------------------------------------------------ protected Methods - - /** - * Execute the specified command, based on the configured properties. The - * input stream will be closed upon completion of this task, whether it was - * executed successfully or not. - * - * @exception Exception - * if an error occurs - */ - public String jmxExecute(MBeanServerConnection jmxServerConnection) - throws Exception { - - if (getName() == null) { - throw new BuildException("Must specify a 'name'"); - } - return jmxUuregister(jmxServerConnection, getName()); - } - - - /** - * Unregister Mbean - * @param jmxServerConnection - * @param name - * @return The value of the given named attribute - * @throws Exception - */ - protected String jmxUuregister(MBeanServerConnection jmxServerConnection,String name) throws Exception { - String error = null; - if(isEcho()) { - handleOutput("Unregister MBean " + name ); - } - jmxServerConnection.unregisterMBean( - new ObjectName(name)); - return error; - } - -} +/* + * Copyright 2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.ant.jmx; + +import java.util.ArrayList; +import java.util.List; + +import javax.management.MBeanServerConnection; +import javax.management.ObjectName; + +import org.apache.tools.ant.BuildException; + +/** + * unregister a MBean at JMX JSR 160 MBeans Server. + *
      + *
    • unregister Mbeans
    • + *
    + *

    + * Examples: + *
    + * unregister an existing Mbean at jmx.server connection + *

    + *   <jmx:unregister
    + *           ref="jmx.server"
    + *           name="Catalina:type=MBeanFactory" />
    + * 
    + *

    + *

    + * WARNINGNot all Tomcat MBeans can successfully unregister remotely. The mbean + * unregistration don't remove valves, realm, .. from parent class. + * Please, use the MBeanFactory operation to remove valves and realms. + *

    + *

    + * First call to a remote MBeanserver save the JMXConnection a reference jmx.server + *

    + * These tasks require Ant 1.6 or later interface. + * + * @author Peter Rossbach + * @version $Revision: 304089 $ + * @since 5.5.12 + */ +public class JMXAccessorUnregisterTask extends JMXAccessorTask { + + // ----------------------------------------------------- Instance Info + + /** + * Descriptive information describing this implementation. + */ + private static final String info = "org.apache.catalina.ant.JMXAccessorUnregisterTask/1.0"; + + /** + * Return descriptive information about this implementation and the + * corresponding version number, in the format + * <description>/<version>. + * @return Returns the class info. + */ + public String getInfo() { + + return (info); + + } + // ------------------------------------------------------ protected Methods + + /** + * Execute the specified command, based on the configured properties. The + * input stream will be closed upon completion of this task, whether it was + * executed successfully or not. + * + * @exception Exception + * if an error occurs + */ + public String jmxExecute(MBeanServerConnection jmxServerConnection) + throws Exception { + + if (getName() == null) { + throw new BuildException("Must specify a 'name'"); + } + return jmxUuregister(jmxServerConnection, getName()); + } + + + /** + * Unregister Mbean + * @param jmxServerConnection + * @param name + * @return The value of the given named attribute + * @throws Exception + */ + protected String jmxUuregister(MBeanServerConnection jmxServerConnection,String name) throws Exception { + String error = null; + if(isEcho()) { + handleOutput("Unregister MBean " + name ); + } + jmxServerConnection.unregisterMBean( + new ObjectName(name)); + return error; + } + +} diff --git a/java/org/apache/catalina/ant/jmx/antlib.xml b/java/org/apache/catalina/ant/jmx/antlib.xml index f6b1cc411..bcd277ab2 100644 --- a/java/org/apache/catalina/ant/jmx/antlib.xml +++ b/java/org/apache/catalina/ant/jmx/antlib.xml @@ -1,30 +1,30 @@ - - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/java/org/apache/catalina/ant/jmx/package.html b/java/org/apache/catalina/ant/jmx/package.html index 50c3d7af1..299dc89da 100644 --- a/java/org/apache/catalina/ant/jmx/package.html +++ b/java/org/apache/catalina/ant/jmx/package.html @@ -1,61 +1,61 @@ - - -

    This package contains a set of JMX Task implementations for -Ant (version 1.6 or later) that can be used to interact with the -Remote JMX JSR 160 RMI Adaptor to get/set attributes, invoke MBean operations -and query for Mbeans inside a running instance of Tomcat. For more information, see - -http://jakarta.apache.org/tomcat/tomcat-5.5-doc/monitoring.html.

    - -

    Each task element can open a new jmx connection or reference an - existing one. The following attribute are exists in every tasks: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AttributeDescription
    url - The JMX Connection URL of the remote Tomcat MBeansServer. -
    username - The username of a MBeanServer auth, when configured. -
    password - The password of a MBeanServer auth, when configured. -
    host - The JMX Connection host. -
    port - The JMX Connection port. -
    ref - The name of the ant internal reference for a jmx connection. -
    - -

    NOTE - This Tasks only work, - when JSR 160 MBean Adaptor as remote jvm is configured.

    - - + + +

    This package contains a set of JMX Task implementations for +Ant (version 1.6 or later) that can be used to interact with the +Remote JMX JSR 160 RMI Adaptor to get/set attributes, invoke MBean operations +and query for Mbeans inside a running instance of Tomcat. For more information, see + +http://jakarta.apache.org/tomcat/tomcat-5.5-doc/monitoring.html.

    + +

    Each task element can open a new jmx connection or reference an + existing one. The following attribute are exists in every tasks: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeDescription
    url + The JMX Connection URL of the remote Tomcat MBeansServer. +
    username + The username of a MBeanServer auth, when configured. +
    password + The password of a MBeanServer auth, when configured. +
    host + The JMX Connection host. +
    port + The JMX Connection port. +
    ref + The name of the ant internal reference for a jmx connection. +
    + +

    NOTE - This Tasks only work, + when JSR 160 MBean Adaptor as remote jvm is configured.

    + + diff --git a/java/org/apache/catalina/ant/package.html b/java/org/apache/catalina/ant/package.html index 44f38c9cf..eaaa40d13 100644 --- a/java/org/apache/catalina/ant/package.html +++ b/java/org/apache/catalina/ant/package.html @@ -1,86 +1,86 @@ - - -

    This package contains a set of Task implementations for -Ant (version 1.6.x or later) that can be used to interact with the -Manager application to deploy, undeploy, list, reload, start and stop web applications -from a running instance of Tomcat. For more information, see - -http://jakarta.apache.org/tomcat/tomcat-5.5-doc/manager-howto.html.

    - -

    The attributes of each task element correspond -exactly to the request parameters that are included with an HTTP request -sent directly to the Manager application. They are summarized as follows: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    AttributeDescription
    url - The URL of the Manager web application you will use to - perform the requested operations. If not specified, defaults to - http://localhost:8080/manager (which corresponds - to a standard installation of Tomcat 5). -
    username - The username of a Tomcat user that has been configured with the - manager role, as required to execute Manager - application commands. This attribute is required. -
    password - The password of a Tomcat user that has been configured with the - manager role, as required to execute Manager - application commands. This attribute is required. -
    config - A URL pointing at the context configuration file (i.e. a file - containing only the <Context> element, and - its nested elements, from server.xml for a particular - web application). This attribute is supported only on the - install target, and is required only if you wish to - install an application with non-default configuration characteristics. -
    path - The context path (including the leading slash) of the web application - this command is intended to manage, or a zero-length string for the - ROOT web application. This attribute is valid for the - install, reload, remove, - start, and stop tasks only, and is - required in all of those cases. -
    war - A jar: URL that points at a web application archive (WAR) - file, or a file: URL that points at an unpacked directory - containing the web application. This attribute is supported only on - the install target. You must specify at least one of the - config and war attributes; if you specify - both, the war attribute overrides the docBase - attribute in the context configuration file. -
    - -

    NOTE - Commands executed through the Manager -application are NOT reflected in updates to the Tomcat -server.xml configuration file, so they do not persist past the -next time you restart the entire Tomcat container.

    - - + + +

    This package contains a set of Task implementations for +Ant (version 1.6.x or later) that can be used to interact with the +Manager application to deploy, undeploy, list, reload, start and stop web applications +from a running instance of Tomcat. For more information, see + +http://jakarta.apache.org/tomcat/tomcat-5.5-doc/manager-howto.html.

    + +

    The attributes of each task element correspond +exactly to the request parameters that are included with an HTTP request +sent directly to the Manager application. They are summarized as follows: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    AttributeDescription
    url + The URL of the Manager web application you will use to + perform the requested operations. If not specified, defaults to + http://localhost:8080/manager (which corresponds + to a standard installation of Tomcat 5). +
    username + The username of a Tomcat user that has been configured with the + manager role, as required to execute Manager + application commands. This attribute is required. +
    password + The password of a Tomcat user that has been configured with the + manager role, as required to execute Manager + application commands. This attribute is required. +
    config + A URL pointing at the context configuration file (i.e. a file + containing only the <Context> element, and + its nested elements, from server.xml for a particular + web application). This attribute is supported only on the + install target, and is required only if you wish to + install an application with non-default configuration characteristics. +
    path + The context path (including the leading slash) of the web application + this command is intended to manage, or a zero-length string for the + ROOT web application. This attribute is valid for the + install, reload, remove, + start, and stop tasks only, and is + required in all of those cases. +
    war + A jar: URL that points at a web application archive (WAR) + file, or a file: URL that points at an unpacked directory + containing the web application. This attribute is supported only on + the install target. You must specify at least one of the + config and war attributes; if you specify + both, the war attribute overrides the docBase + attribute in the context configuration file. +
    + +

    NOTE - Commands executed through the Manager +application are NOT reflected in updates to the Tomcat +server.xml configuration file, so they do not persist past the +next time you restart the entire Tomcat container.

    + + diff --git a/java/org/apache/catalina/authenticator/AuthenticatorBase.java b/java/org/apache/catalina/authenticator/AuthenticatorBase.java index 2dcc64024..80c24aaed 100644 --- a/java/org/apache/catalina/authenticator/AuthenticatorBase.java +++ b/java/org/apache/catalina/authenticator/AuthenticatorBase.java @@ -1,880 +1,880 @@ -/* - * Copyright 1999-2001,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.Random; - -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; - -import org.apache.catalina.Authenticator; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Pipeline; -import org.apache.catalina.Realm; -import org.apache.catalina.Session; -import org.apache.catalina.Valve; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.util.DateTool; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Basic implementation of the Valve interface that enforces the - * <security-constraint> elements in the web application - * deployment descriptor. This functionality is implemented as a Valve - * so that it can be ommitted in environments that do not require these - * features. Individual implementations of each supported authentication - * method can subclass this base class as required. - *

    - * USAGE CONSTRAINT: When this class is utilized, the Context to - * which it is attached (or a parent Container in a hierarchy) must have an - * associated Realm that can be used for authenticating users and enumerating - * the roles to which they have been assigned. - *

    - * USAGE CONSTRAINT: This Valve is only useful when processing HTTP - * requests. Requests of any other type will simply be passed through. - * - * @author Craig R. McClanahan - * @version $Revision: 357143 $ $Date: 2005-12-16 09:13:19 +0100 (ven., 16 déc. 2005) $ - */ - - -public abstract class AuthenticatorBase - extends ValveBase - implements Authenticator, Lifecycle { - private static Log log = LogFactory.getLog(AuthenticatorBase.class); - - - // ----------------------------------------------------- Instance Variables - - - /** - * The default message digest algorithm to use if we cannot use - * the requested one. - */ - protected static final String DEFAULT_ALGORITHM = "MD5"; - - - /** - * The number of random bytes to include when generating a - * session identifier. - */ - protected static final int SESSION_ID_BYTES = 16; - - - /** - * The message digest algorithm to be used when generating session - * identifiers. This must be an algorithm supported by the - * java.security.MessageDigest class on your platform. - */ - protected String algorithm = DEFAULT_ALGORITHM; - - - /** - * Should we cache authenticated Principals if the request is part of - * an HTTP session? - */ - protected boolean cache = true; - - - /** - * The Context to which this Valve is attached. - */ - protected Context context = null; - - - /** - * Return the MessageDigest implementation to be used when - * creating session identifiers. - */ - protected MessageDigest digest = null; - - - /** - * A String initialization parameter used to increase the entropy of - * the initialization of our random number generator. - */ - protected String entropy = null; - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.authenticator.AuthenticatorBase/1.0"; - - /** - * Flag to determine if we disable proxy caching, or leave the issue - * up to the webapp developer. - */ - protected boolean disableProxyCaching = true; - - /** - * Flag to determine if we disable proxy caching with headers incompatible - * with IE - */ - protected boolean securePagesWithPragma = true; - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * A random number generator to use when generating session identifiers. - */ - protected Random random = null; - - - /** - * The Java class name of the random number generator class to be used - * when generating session identifiers. - */ - protected String randomClass = "java.security.SecureRandom"; - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The SingleSignOn implementation in our request processing chain, - * if there is one. - */ - protected SingleSignOn sso = null; - - - /** - * Has this component been started? - */ - protected boolean started = false; - - - /** - * "Expires" header always set to Date(1), so generate once only - */ - private static final String DATE_ONE = - (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, - Locale.US)).format(new Date(1)); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the message digest algorithm for this Manager. - */ - public String getAlgorithm() { - - return (this.algorithm); - - } - - - /** - * Set the message digest algorithm for this Manager. - * - * @param algorithm The new message digest algorithm - */ - public void setAlgorithm(String algorithm) { - - this.algorithm = algorithm; - - } - - - /** - * Return the cache authenticated Principals flag. - */ - public boolean getCache() { - - return (this.cache); - - } - - - /** - * Set the cache authenticated Principals flag. - * - * @param cache The new cache flag - */ - public void setCache(boolean cache) { - - this.cache = cache; - - } - - - /** - * Return the Container to which this Valve is attached. - */ - public Container getContainer() { - - return (this.context); - - } - - - /** - * Set the Container to which this Valve is attached. - * - * @param container The container to which we are attached - */ - public void setContainer(Container container) { - - if (!(container instanceof Context)) - throw new IllegalArgumentException - (sm.getString("authenticator.notContext")); - - super.setContainer(container); - this.context = (Context) container; - - } - - - /** - * Return the entropy increaser value, or compute a semi-useful value - * if this String has not yet been set. - */ - public String getEntropy() { - - // Calculate a semi-useful value if this has not been set - if (this.entropy == null) - setEntropy(this.toString()); - - return (this.entropy); - - } - - - /** - * Set the entropy increaser value. - * - * @param entropy The new entropy increaser value - */ - public void setEntropy(String entropy) { - - this.entropy = entropy; - - } - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the random number generator class name. - */ - public String getRandomClass() { - - return (this.randomClass); - - } - - - /** - * Set the random number generator class name. - * - * @param randomClass The new random number generator class name - */ - public void setRandomClass(String randomClass) { - - this.randomClass = randomClass; - - } - - /** - * Return the flag that states if we add headers to disable caching by - * proxies. - */ - public boolean getDisableProxyCaching() { - return disableProxyCaching; - } - - /** - * Set the value of the flag that states if we add headers to disable - * caching by proxies. - * @param nocache true if we add headers to disable proxy - * caching, false if we leave the headers alone. - */ - public void setDisableProxyCaching(boolean nocache) { - disableProxyCaching = nocache; - } - - /** - * Return the flag that states, if proxy caching is disabled, what headers - * we add to disable the caching. - */ - public boolean getSecurePagesWithPragma() { - return securePagesWithPragma; - } - - /** - * Set the value of the flag that states what headers we add to disable - * proxy caching. - * @param securePagesWithPragma true if we add headers which - * are incompatible with downloading office documents in IE under SSL but - * which fix a caching problem in Mozilla. - */ - public void setSecurePagesWithPragma(boolean securePagesWithPragma) { - this.securePagesWithPragma = securePagesWithPragma; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Enforce the security restrictions in the web application deployment - * descriptor of our associated Context. - * - * @param request Request to be processed - * @param response Response to be processed - * - * @exception IOException if an input/output error occurs - * @exception ServletException if thrown by a processing element - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - if (log.isDebugEnabled()) - log.debug("Security checking request " + - request.getMethod() + " " + request.getRequestURI()); - LoginConfig config = this.context.getLoginConfig(); - - // Have we got a cached authenticated Principal to record? - if (cache) { - Principal principal = request.getUserPrincipal(); - if (principal == null) { - Session session = request.getSessionInternal(false); - if (session != null) { - principal = session.getPrincipal(); - if (principal != null) { - if (log.isDebugEnabled()) - log.debug("We have cached auth type " + - session.getAuthType() + - " for principal " + - session.getPrincipal()); - request.setAuthType(session.getAuthType()); - request.setUserPrincipal(principal); - } - } - } - } - - // Special handling for form-based logins to deal with the case - // where the login form (and therefore the "j_security_check" URI - // to which it submits) might be outside the secured area - String contextPath = this.context.getPath(); - String requestURI = request.getDecodedRequestURI(); - if (requestURI.startsWith(contextPath) && - requestURI.endsWith(Constants.FORM_ACTION)) { - if (!authenticate(request, response, config)) { - if (log.isDebugEnabled()) - log.debug(" Failed authenticate() test ??" + requestURI ); - return; - } - } - - Realm realm = this.context.getRealm(); - // Is this request URI subject to a security constraint? - SecurityConstraint [] constraints - = realm.findSecurityConstraints(request, this.context); - - if ((constraints == null) /* && - (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) { - if (log.isDebugEnabled()) - log.debug(" Not subject to any constraint"); - getNext().invoke(request, response); - return; - } - - // Make sure that constrained resources are not cached by web proxies - // or browsers as caching can provide a security hole - if (disableProxyCaching && - // FIXME: Disabled for Mozilla FORM support over SSL - // (improper caching issue) - //!request.isSecure() && - !"POST".equalsIgnoreCase(request.getMethod())) { - if (securePagesWithPragma) { - // FIXME: These cause problems with downloading office docs - // from IE under SSL and may not be needed for newer Mozilla - // clients. - response.setHeader("Pragma", "No-cache"); - response.setHeader("Cache-Control", "no-cache"); - } else { - response.setHeader("Cache-Control", "private"); - } - response.setHeader("Expires", DATE_ONE); - } - - int i; - // Enforce any user data constraint for this security constraint - if (log.isDebugEnabled()) { - log.debug(" Calling hasUserDataPermission()"); - } - if (!realm.hasUserDataPermission(request, response, - constraints)) { - if (log.isDebugEnabled()) { - log.debug(" Failed hasUserDataPermission() test"); - } - /* - * ASSERT: Authenticator already set the appropriate - * HTTP status code, so we do not have to do anything special - */ - return; - } - - // Since authenticate modifies the response on failure, - // we have to check for allow-from-all first. - boolean authRequired = true; - for(i=0; i < constraints.length && authRequired; i++) { - if(!constraints[i].getAuthConstraint()) { - authRequired = false; - } else if(!constraints[i].getAllRoles()) { - String [] roles = constraints[i].findAuthRoles(); - if(roles == null || roles.length == 0) { - authRequired = false; - } - } - } - - if(authRequired) { - if (log.isDebugEnabled()) { - log.debug(" Calling authenticate()"); - } - if (!authenticate(request, response, config)) { - if (log.isDebugEnabled()) { - log.debug(" Failed authenticate() test"); - } - /* - * ASSERT: Authenticator already set the appropriate - * HTTP status code, so we do not have to do anything - * special - */ - return; - } - } - - if (log.isDebugEnabled()) { - log.debug(" Calling accessControl()"); - } - if (!realm.hasResourcePermission(request, response, - constraints, - this.context)) { - if (log.isDebugEnabled()) { - log.debug(" Failed accessControl() test"); - } - /* - * ASSERT: AccessControl method has already set the - * appropriate HTTP status code, so we do not have to do - * anything special - */ - return; - } - - // Any and all specified constraints have been satisfied - if (log.isDebugEnabled()) { - log.debug(" Successfully passed all security constraints"); - } - getNext().invoke(request, response); - - } - - - // ------------------------------------------------------ Protected Methods - - - - - /** - * Associate the specified single sign on identifier with the - * specified Session. - * - * @param ssoId Single sign on identifier - * @param session Session to be associated - */ - protected void associate(String ssoId, Session session) { - - if (sso == null) - return; - sso.associate(ssoId, session); - - } - - - /** - * Authenticate the user making this request, based on the specified - * login configuration. Return true if any specified - * constraint has been satisfied, or false if we have - * created a response challenge already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - protected abstract boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException; - - - /** - * Generate and return a new session identifier for the cookie that - * identifies an SSO principal. - */ - protected synchronized String generateSessionId() { - - // Generate a byte array containing a session identifier - byte bytes[] = new byte[SESSION_ID_BYTES]; - getRandom().nextBytes(bytes); - bytes = getDigest().digest(bytes); - - // Render the result as a String of hexadecimal digits - StringBuffer result = new StringBuffer(); - for (int i = 0; i < bytes.length; i++) { - byte b1 = (byte) ((bytes[i] & 0xf0) >> 4); - byte b2 = (byte) (bytes[i] & 0x0f); - if (b1 < 10) - result.append((char) ('0' + b1)); - else - result.append((char) ('A' + (b1 - 10))); - if (b2 < 10) - result.append((char) ('0' + b2)); - else - result.append((char) ('A' + (b2 - 10))); - } - return (result.toString()); - - } - - - /** - * Return the MessageDigest object to be used for calculating - * session identifiers. If none has been created yet, initialize - * one the first time this method is called. - */ - protected synchronized MessageDigest getDigest() { - - if (this.digest == null) { - try { - this.digest = MessageDigest.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - try { - this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); - } catch (NoSuchAlgorithmException f) { - this.digest = null; - } - } - } - - return (this.digest); - - } - - - /** - * Return the random number generator instance we should use for - * generating session identifiers. If there is no such generator - * currently defined, construct and seed a new one. - */ - protected synchronized Random getRandom() { - - if (this.random == null) { - try { - Class clazz = Class.forName(randomClass); - this.random = (Random) clazz.newInstance(); - long seed = System.currentTimeMillis(); - char entropy[] = getEntropy().toCharArray(); - for (int i = 0; i < entropy.length; i++) { - long update = ((byte) entropy[i]) << ((i % 8) * 8); - seed ^= update; - } - this.random.setSeed(seed); - } catch (Exception e) { - this.random = new java.util.Random(); - } - } - - return (this.random); - - } - - - /** - * Attempts reauthentication to the Realm using - * the credentials included in argument entry. - * - * @param ssoId identifier of SingleSignOn session with which the - * caller is associated - * @param request the request that needs to be authenticated - */ - protected boolean reauthenticateFromSSO(String ssoId, Request request) { - - if (sso == null || ssoId == null) - return false; - - boolean reauthenticated = false; - - Container parent = getContainer(); - if (parent != null) { - Realm realm = parent.getRealm(); - if (realm != null) { - reauthenticated = sso.reauthenticate(ssoId, realm, request); - } - } - - if (reauthenticated) { - associate(ssoId, request.getSessionInternal(true)); - - if (log.isDebugEnabled()) { - log.debug(" Reauthenticated cached principal '" + - request.getUserPrincipal().getName() + - "' with auth type '" + request.getAuthType() + "'"); - } - } - - return reauthenticated; - } - - - /** - * Register an authenticated Principal and authentication type in our - * request, in the current session (if there is one), and with our - * SingleSignOn valve, if there is one. Set the appropriate cookie - * to be returned. - * - * @param request The servlet request we are processing - * @param response The servlet response we are generating - * @param principal The authenticated Principal to be registered - * @param authType The authentication type to be registered - * @param username Username used to authenticate (if any) - * @param password Password used to authenticate (if any) - */ - protected void register(Request request, Response response, - Principal principal, String authType, - String username, String password) { - - if (log.isDebugEnabled()) - log.debug("Authenticated '" + principal.getName() + "' with type '" - + authType + "'"); - - // Cache the authentication information in our request - request.setAuthType(authType); - request.setUserPrincipal(principal); - - Session session = request.getSessionInternal(false); - // Cache the authentication information in our session, if any - if (cache) { - if (session != null) { - session.setAuthType(authType); - session.setPrincipal(principal); - if (username != null) - session.setNote(Constants.SESS_USERNAME_NOTE, username); - else - session.removeNote(Constants.SESS_USERNAME_NOTE); - if (password != null) - session.setNote(Constants.SESS_PASSWORD_NOTE, password); - else - session.removeNote(Constants.SESS_PASSWORD_NOTE); - } - } - - // Construct a cookie to be returned to the client - if (sso == null) - return; - - // Only create a new SSO entry if the SSO did not already set a note - // for an existing entry (as it would do with subsequent requests - // for DIGEST and SSL authenticated contexts) - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (ssoId == null) { - // Construct a cookie to be returned to the client - ssoId = generateSessionId(); - Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId); - cookie.setMaxAge(-1); - cookie.setPath("/"); - - // Bugzilla 34724 - String ssoDomain = sso.getCookieDomain(); - if(ssoDomain != null) { - cookie.setDomain(ssoDomain); - } - - response.addCookie(cookie); - - // Register this principal with our SSO valve - sso.register(ssoId, principal, authType, username, password); - request.setNote(Constants.REQ_SSOID_NOTE, ssoId); - - } else { - // Update the SSO session with the latest authentication data - sso.update(ssoId, principal, authType, username, password); - } - - // Fix for Bug 10040 - // Always associate a session with a new SSO reqistration. - // SSO entries are only removed from the SSO registry map when - // associated sessions are destroyed; if a new SSO entry is created - // above for this request and the user never revisits the context, the - // SSO entry will never be cleared if we don't associate the session - if (session == null) - session = request.getSessionInternal(true); - sso.associate(ssoId, session); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("authenticator.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Look up the SingleSignOn implementation in our request processing - // path, if there is one - Container parent = context.getParent(); - while ((sso == null) && (parent != null)) { - if (!(parent instanceof Pipeline)) { - parent = parent.getParent(); - continue; - } - Valve valves[] = ((Pipeline) parent).getValves(); - for (int i = 0; i < valves.length; i++) { - if (valves[i] instanceof SingleSignOn) { - sso = (SingleSignOn) valves[i]; - break; - } - } - if (sso == null) - parent = parent.getParent(); - } - if (log.isDebugEnabled()) { - if (sso != null) - log.debug("Found SingleSignOn Valve at " + sso); - else - log.debug("No SingleSignOn Valve is present"); - } - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("authenticator.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - sso = null; - - } - - -} +/* + * Copyright 1999-2001,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.Random; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; + +import org.apache.catalina.Authenticator; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Pipeline; +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.Valve; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.util.DateTool; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Basic implementation of the Valve interface that enforces the + * <security-constraint> elements in the web application + * deployment descriptor. This functionality is implemented as a Valve + * so that it can be ommitted in environments that do not require these + * features. Individual implementations of each supported authentication + * method can subclass this base class as required. + *

    + * USAGE CONSTRAINT: When this class is utilized, the Context to + * which it is attached (or a parent Container in a hierarchy) must have an + * associated Realm that can be used for authenticating users and enumerating + * the roles to which they have been assigned. + *

    + * USAGE CONSTRAINT: This Valve is only useful when processing HTTP + * requests. Requests of any other type will simply be passed through. + * + * @author Craig R. McClanahan + * @version $Revision: 357143 $ $Date: 2005-12-16 09:13:19 +0100 (ven., 16 déc. 2005) $ + */ + + +public abstract class AuthenticatorBase + extends ValveBase + implements Authenticator, Lifecycle { + private static Log log = LogFactory.getLog(AuthenticatorBase.class); + + + // ----------------------------------------------------- Instance Variables + + + /** + * The default message digest algorithm to use if we cannot use + * the requested one. + */ + protected static final String DEFAULT_ALGORITHM = "MD5"; + + + /** + * The number of random bytes to include when generating a + * session identifier. + */ + protected static final int SESSION_ID_BYTES = 16; + + + /** + * The message digest algorithm to be used when generating session + * identifiers. This must be an algorithm supported by the + * java.security.MessageDigest class on your platform. + */ + protected String algorithm = DEFAULT_ALGORITHM; + + + /** + * Should we cache authenticated Principals if the request is part of + * an HTTP session? + */ + protected boolean cache = true; + + + /** + * The Context to which this Valve is attached. + */ + protected Context context = null; + + + /** + * Return the MessageDigest implementation to be used when + * creating session identifiers. + */ + protected MessageDigest digest = null; + + + /** + * A String initialization parameter used to increase the entropy of + * the initialization of our random number generator. + */ + protected String entropy = null; + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.authenticator.AuthenticatorBase/1.0"; + + /** + * Flag to determine if we disable proxy caching, or leave the issue + * up to the webapp developer. + */ + protected boolean disableProxyCaching = true; + + /** + * Flag to determine if we disable proxy caching with headers incompatible + * with IE + */ + protected boolean securePagesWithPragma = true; + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * A random number generator to use when generating session identifiers. + */ + protected Random random = null; + + + /** + * The Java class name of the random number generator class to be used + * when generating session identifiers. + */ + protected String randomClass = "java.security.SecureRandom"; + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The SingleSignOn implementation in our request processing chain, + * if there is one. + */ + protected SingleSignOn sso = null; + + + /** + * Has this component been started? + */ + protected boolean started = false; + + + /** + * "Expires" header always set to Date(1), so generate once only + */ + private static final String DATE_ONE = + (new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, + Locale.US)).format(new Date(1)); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the message digest algorithm for this Manager. + */ + public String getAlgorithm() { + + return (this.algorithm); + + } + + + /** + * Set the message digest algorithm for this Manager. + * + * @param algorithm The new message digest algorithm + */ + public void setAlgorithm(String algorithm) { + + this.algorithm = algorithm; + + } + + + /** + * Return the cache authenticated Principals flag. + */ + public boolean getCache() { + + return (this.cache); + + } + + + /** + * Set the cache authenticated Principals flag. + * + * @param cache The new cache flag + */ + public void setCache(boolean cache) { + + this.cache = cache; + + } + + + /** + * Return the Container to which this Valve is attached. + */ + public Container getContainer() { + + return (this.context); + + } + + + /** + * Set the Container to which this Valve is attached. + * + * @param container The container to which we are attached + */ + public void setContainer(Container container) { + + if (!(container instanceof Context)) + throw new IllegalArgumentException + (sm.getString("authenticator.notContext")); + + super.setContainer(container); + this.context = (Context) container; + + } + + + /** + * Return the entropy increaser value, or compute a semi-useful value + * if this String has not yet been set. + */ + public String getEntropy() { + + // Calculate a semi-useful value if this has not been set + if (this.entropy == null) + setEntropy(this.toString()); + + return (this.entropy); + + } + + + /** + * Set the entropy increaser value. + * + * @param entropy The new entropy increaser value + */ + public void setEntropy(String entropy) { + + this.entropy = entropy; + + } + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the random number generator class name. + */ + public String getRandomClass() { + + return (this.randomClass); + + } + + + /** + * Set the random number generator class name. + * + * @param randomClass The new random number generator class name + */ + public void setRandomClass(String randomClass) { + + this.randomClass = randomClass; + + } + + /** + * Return the flag that states if we add headers to disable caching by + * proxies. + */ + public boolean getDisableProxyCaching() { + return disableProxyCaching; + } + + /** + * Set the value of the flag that states if we add headers to disable + * caching by proxies. + * @param nocache true if we add headers to disable proxy + * caching, false if we leave the headers alone. + */ + public void setDisableProxyCaching(boolean nocache) { + disableProxyCaching = nocache; + } + + /** + * Return the flag that states, if proxy caching is disabled, what headers + * we add to disable the caching. + */ + public boolean getSecurePagesWithPragma() { + return securePagesWithPragma; + } + + /** + * Set the value of the flag that states what headers we add to disable + * proxy caching. + * @param securePagesWithPragma true if we add headers which + * are incompatible with downloading office documents in IE under SSL but + * which fix a caching problem in Mozilla. + */ + public void setSecurePagesWithPragma(boolean securePagesWithPragma) { + this.securePagesWithPragma = securePagesWithPragma; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Enforce the security restrictions in the web application deployment + * descriptor of our associated Context. + * + * @param request Request to be processed + * @param response Response to be processed + * + * @exception IOException if an input/output error occurs + * @exception ServletException if thrown by a processing element + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + if (log.isDebugEnabled()) + log.debug("Security checking request " + + request.getMethod() + " " + request.getRequestURI()); + LoginConfig config = this.context.getLoginConfig(); + + // Have we got a cached authenticated Principal to record? + if (cache) { + Principal principal = request.getUserPrincipal(); + if (principal == null) { + Session session = request.getSessionInternal(false); + if (session != null) { + principal = session.getPrincipal(); + if (principal != null) { + if (log.isDebugEnabled()) + log.debug("We have cached auth type " + + session.getAuthType() + + " for principal " + + session.getPrincipal()); + request.setAuthType(session.getAuthType()); + request.setUserPrincipal(principal); + } + } + } + } + + // Special handling for form-based logins to deal with the case + // where the login form (and therefore the "j_security_check" URI + // to which it submits) might be outside the secured area + String contextPath = this.context.getPath(); + String requestURI = request.getDecodedRequestURI(); + if (requestURI.startsWith(contextPath) && + requestURI.endsWith(Constants.FORM_ACTION)) { + if (!authenticate(request, response, config)) { + if (log.isDebugEnabled()) + log.debug(" Failed authenticate() test ??" + requestURI ); + return; + } + } + + Realm realm = this.context.getRealm(); + // Is this request URI subject to a security constraint? + SecurityConstraint [] constraints + = realm.findSecurityConstraints(request, this.context); + + if ((constraints == null) /* && + (!Constants.FORM_METHOD.equals(config.getAuthMethod())) */ ) { + if (log.isDebugEnabled()) + log.debug(" Not subject to any constraint"); + getNext().invoke(request, response); + return; + } + + // Make sure that constrained resources are not cached by web proxies + // or browsers as caching can provide a security hole + if (disableProxyCaching && + // FIXME: Disabled for Mozilla FORM support over SSL + // (improper caching issue) + //!request.isSecure() && + !"POST".equalsIgnoreCase(request.getMethod())) { + if (securePagesWithPragma) { + // FIXME: These cause problems with downloading office docs + // from IE under SSL and may not be needed for newer Mozilla + // clients. + response.setHeader("Pragma", "No-cache"); + response.setHeader("Cache-Control", "no-cache"); + } else { + response.setHeader("Cache-Control", "private"); + } + response.setHeader("Expires", DATE_ONE); + } + + int i; + // Enforce any user data constraint for this security constraint + if (log.isDebugEnabled()) { + log.debug(" Calling hasUserDataPermission()"); + } + if (!realm.hasUserDataPermission(request, response, + constraints)) { + if (log.isDebugEnabled()) { + log.debug(" Failed hasUserDataPermission() test"); + } + /* + * ASSERT: Authenticator already set the appropriate + * HTTP status code, so we do not have to do anything special + */ + return; + } + + // Since authenticate modifies the response on failure, + // we have to check for allow-from-all first. + boolean authRequired = true; + for(i=0; i < constraints.length && authRequired; i++) { + if(!constraints[i].getAuthConstraint()) { + authRequired = false; + } else if(!constraints[i].getAllRoles()) { + String [] roles = constraints[i].findAuthRoles(); + if(roles == null || roles.length == 0) { + authRequired = false; + } + } + } + + if(authRequired) { + if (log.isDebugEnabled()) { + log.debug(" Calling authenticate()"); + } + if (!authenticate(request, response, config)) { + if (log.isDebugEnabled()) { + log.debug(" Failed authenticate() test"); + } + /* + * ASSERT: Authenticator already set the appropriate + * HTTP status code, so we do not have to do anything + * special + */ + return; + } + } + + if (log.isDebugEnabled()) { + log.debug(" Calling accessControl()"); + } + if (!realm.hasResourcePermission(request, response, + constraints, + this.context)) { + if (log.isDebugEnabled()) { + log.debug(" Failed accessControl() test"); + } + /* + * ASSERT: AccessControl method has already set the + * appropriate HTTP status code, so we do not have to do + * anything special + */ + return; + } + + // Any and all specified constraints have been satisfied + if (log.isDebugEnabled()) { + log.debug(" Successfully passed all security constraints"); + } + getNext().invoke(request, response); + + } + + + // ------------------------------------------------------ Protected Methods + + + + + /** + * Associate the specified single sign on identifier with the + * specified Session. + * + * @param ssoId Single sign on identifier + * @param session Session to be associated + */ + protected void associate(String ssoId, Session session) { + + if (sso == null) + return; + sso.associate(ssoId, session); + + } + + + /** + * Authenticate the user making this request, based on the specified + * login configuration. Return true if any specified + * constraint has been satisfied, or false if we have + * created a response challenge already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + protected abstract boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException; + + + /** + * Generate and return a new session identifier for the cookie that + * identifies an SSO principal. + */ + protected synchronized String generateSessionId() { + + // Generate a byte array containing a session identifier + byte bytes[] = new byte[SESSION_ID_BYTES]; + getRandom().nextBytes(bytes); + bytes = getDigest().digest(bytes); + + // Render the result as a String of hexadecimal digits + StringBuffer result = new StringBuffer(); + for (int i = 0; i < bytes.length; i++) { + byte b1 = (byte) ((bytes[i] & 0xf0) >> 4); + byte b2 = (byte) (bytes[i] & 0x0f); + if (b1 < 10) + result.append((char) ('0' + b1)); + else + result.append((char) ('A' + (b1 - 10))); + if (b2 < 10) + result.append((char) ('0' + b2)); + else + result.append((char) ('A' + (b2 - 10))); + } + return (result.toString()); + + } + + + /** + * Return the MessageDigest object to be used for calculating + * session identifiers. If none has been created yet, initialize + * one the first time this method is called. + */ + protected synchronized MessageDigest getDigest() { + + if (this.digest == null) { + try { + this.digest = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + try { + this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); + } catch (NoSuchAlgorithmException f) { + this.digest = null; + } + } + } + + return (this.digest); + + } + + + /** + * Return the random number generator instance we should use for + * generating session identifiers. If there is no such generator + * currently defined, construct and seed a new one. + */ + protected synchronized Random getRandom() { + + if (this.random == null) { + try { + Class clazz = Class.forName(randomClass); + this.random = (Random) clazz.newInstance(); + long seed = System.currentTimeMillis(); + char entropy[] = getEntropy().toCharArray(); + for (int i = 0; i < entropy.length; i++) { + long update = ((byte) entropy[i]) << ((i % 8) * 8); + seed ^= update; + } + this.random.setSeed(seed); + } catch (Exception e) { + this.random = new java.util.Random(); + } + } + + return (this.random); + + } + + + /** + * Attempts reauthentication to the Realm using + * the credentials included in argument entry. + * + * @param ssoId identifier of SingleSignOn session with which the + * caller is associated + * @param request the request that needs to be authenticated + */ + protected boolean reauthenticateFromSSO(String ssoId, Request request) { + + if (sso == null || ssoId == null) + return false; + + boolean reauthenticated = false; + + Container parent = getContainer(); + if (parent != null) { + Realm realm = parent.getRealm(); + if (realm != null) { + reauthenticated = sso.reauthenticate(ssoId, realm, request); + } + } + + if (reauthenticated) { + associate(ssoId, request.getSessionInternal(true)); + + if (log.isDebugEnabled()) { + log.debug(" Reauthenticated cached principal '" + + request.getUserPrincipal().getName() + + "' with auth type '" + request.getAuthType() + "'"); + } + } + + return reauthenticated; + } + + + /** + * Register an authenticated Principal and authentication type in our + * request, in the current session (if there is one), and with our + * SingleSignOn valve, if there is one. Set the appropriate cookie + * to be returned. + * + * @param request The servlet request we are processing + * @param response The servlet response we are generating + * @param principal The authenticated Principal to be registered + * @param authType The authentication type to be registered + * @param username Username used to authenticate (if any) + * @param password Password used to authenticate (if any) + */ + protected void register(Request request, Response response, + Principal principal, String authType, + String username, String password) { + + if (log.isDebugEnabled()) + log.debug("Authenticated '" + principal.getName() + "' with type '" + + authType + "'"); + + // Cache the authentication information in our request + request.setAuthType(authType); + request.setUserPrincipal(principal); + + Session session = request.getSessionInternal(false); + // Cache the authentication information in our session, if any + if (cache) { + if (session != null) { + session.setAuthType(authType); + session.setPrincipal(principal); + if (username != null) + session.setNote(Constants.SESS_USERNAME_NOTE, username); + else + session.removeNote(Constants.SESS_USERNAME_NOTE); + if (password != null) + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + else + session.removeNote(Constants.SESS_PASSWORD_NOTE); + } + } + + // Construct a cookie to be returned to the client + if (sso == null) + return; + + // Only create a new SSO entry if the SSO did not already set a note + // for an existing entry (as it would do with subsequent requests + // for DIGEST and SSL authenticated contexts) + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (ssoId == null) { + // Construct a cookie to be returned to the client + ssoId = generateSessionId(); + Cookie cookie = new Cookie(Constants.SINGLE_SIGN_ON_COOKIE, ssoId); + cookie.setMaxAge(-1); + cookie.setPath("/"); + + // Bugzilla 34724 + String ssoDomain = sso.getCookieDomain(); + if(ssoDomain != null) { + cookie.setDomain(ssoDomain); + } + + response.addCookie(cookie); + + // Register this principal with our SSO valve + sso.register(ssoId, principal, authType, username, password); + request.setNote(Constants.REQ_SSOID_NOTE, ssoId); + + } else { + // Update the SSO session with the latest authentication data + sso.update(ssoId, principal, authType, username, password); + } + + // Fix for Bug 10040 + // Always associate a session with a new SSO reqistration. + // SSO entries are only removed from the SSO registry map when + // associated sessions are destroyed; if a new SSO entry is created + // above for this request and the user never revisits the context, the + // SSO entry will never be cleared if we don't associate the session + if (session == null) + session = request.getSessionInternal(true); + sso.associate(ssoId, session); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("authenticator.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Look up the SingleSignOn implementation in our request processing + // path, if there is one + Container parent = context.getParent(); + while ((sso == null) && (parent != null)) { + if (!(parent instanceof Pipeline)) { + parent = parent.getParent(); + continue; + } + Valve valves[] = ((Pipeline) parent).getValves(); + for (int i = 0; i < valves.length; i++) { + if (valves[i] instanceof SingleSignOn) { + sso = (SingleSignOn) valves[i]; + break; + } + } + if (sso == null) + parent = parent.getParent(); + } + if (log.isDebugEnabled()) { + if (sso != null) + log.debug("Found SingleSignOn Valve at " + sso); + else + log.debug("No SingleSignOn Valve is present"); + } + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("authenticator.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + sso = null; + + } + + +} diff --git a/java/org/apache/catalina/authenticator/BasicAuthenticator.java b/java/org/apache/catalina/authenticator/BasicAuthenticator.java index 63fb82d4c..45f15c923 100644 --- a/java/org/apache/catalina/authenticator/BasicAuthenticator.java +++ b/java/org/apache/catalina/authenticator/BasicAuthenticator.java @@ -1,211 +1,211 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.security.Principal; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.util.Base64; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; - - - -/** - * An Authenticator and Valve implementation of HTTP BASIC - * Authentication, as outlined in RFC 2617: "HTTP Authentication: Basic - * and Digest Access Authentication." - * - * @author Craig R. McClanahan - * @version $Revision: 370985 $ $Date: 2006-01-21 06:21:15 +0100 (sam., 21 janv. 2006) $ - */ - -public class BasicAuthenticator - extends AuthenticatorBase { - private static Log log = LogFactory.getLog(BasicAuthenticator.class); - - - - /** - * Authenticate bytes. - */ - public static final byte[] AUTHENTICATE_BYTES = { - (byte) 'W', - (byte) 'W', - (byte) 'W', - (byte) '-', - (byte) 'A', - (byte) 'u', - (byte) 't', - (byte) 'h', - (byte) 'e', - (byte) 'n', - (byte) 't', - (byte) 'i', - (byte) 'c', - (byte) 'a', - (byte) 't', - (byte) 'e' - }; - - - // ----------------------------------------------------- Instance Variables - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.authenticator.BasicAuthenticator/1.0"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Authenticate the user making this request, based on the specified - * login configuration. Return true if any specified - * constraint has been satisfied, or false if we have - * created a response challenge already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - public boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException { - - // Have we already authenticated someone? - Principal principal = request.getUserPrincipal(); - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (principal != null) { - if (log.isDebugEnabled()) - log.debug("Already authenticated '" + principal.getName() + "'"); - // Associate the session with any existing SSO session - if (ssoId != null) - associate(ssoId, request.getSessionInternal(true)); - return (true); - } - - // Is there an SSO session against which we can try to reauthenticate? - if (ssoId != null) { - if (log.isDebugEnabled()) - log.debug("SSO Id " + ssoId + " set; attempting " + - "reauthentication"); - /* Try to reauthenticate using data cached by SSO. If this fails, - either the original SSO logon was of DIGEST or SSL (which - we can't reauthenticate ourselves because there is no - cached username and password), or the realm denied - the user's reauthentication for some reason. - In either case we have to prompt the user for a logon */ - if (reauthenticateFromSSO(ssoId, request)) - return true; - } - - // Validate any credentials already included with this request - String username = null; - String password = null; - - MessageBytes authorization = - request.getCoyoteRequest().getMimeHeaders() - .getValue("authorization"); - - if (authorization != null) { - authorization.toBytes(); - ByteChunk authorizationBC = authorization.getByteChunk(); - if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { - authorizationBC.setOffset(authorizationBC.getOffset() + 6); - // FIXME: Add trimming - // authorizationBC.trim(); - - CharChunk authorizationCC = authorization.getCharChunk(); - Base64.decode(authorizationBC, authorizationCC); - - // Get username and password - int colon = authorizationCC.indexOf(':'); - if (colon < 0) { - username = authorizationCC.toString(); - } else { - char[] buf = authorizationCC.getBuffer(); - username = new String(buf, 0, colon); - password = new String(buf, colon + 1, - authorizationCC.getEnd() - colon - 1); - } - - authorizationBC.setOffset(authorizationBC.getOffset() - 6); - } - - principal = context.getRealm().authenticate(username, password); - if (principal != null) { - register(request, response, principal, Constants.BASIC_METHOD, - username, password); - return (true); - } - } - - - // Send an "unauthorized" response and an appropriate challenge - MessageBytes authenticate = - response.getCoyoteResponse().getMimeHeaders() - .addValue(AUTHENTICATE_BYTES, 0, AUTHENTICATE_BYTES.length); - CharChunk authenticateCC = authenticate.getCharChunk(); - authenticateCC.append("Basic realm=\""); - if (config.getRealmName() == null) { - authenticateCC.append(request.getServerName()); - authenticateCC.append(':'); - authenticateCC.append(Integer.toString(request.getServerPort())); - } else { - authenticateCC.append(config.getRealmName()); - } - authenticateCC.append('\"'); - authenticate.toChars(); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - //response.flushBuffer(); - return (false); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.security.Principal; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.util.Base64; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; + + + +/** + * An Authenticator and Valve implementation of HTTP BASIC + * Authentication, as outlined in RFC 2617: "HTTP Authentication: Basic + * and Digest Access Authentication." + * + * @author Craig R. McClanahan + * @version $Revision: 370985 $ $Date: 2006-01-21 06:21:15 +0100 (sam., 21 janv. 2006) $ + */ + +public class BasicAuthenticator + extends AuthenticatorBase { + private static Log log = LogFactory.getLog(BasicAuthenticator.class); + + + + /** + * Authenticate bytes. + */ + public static final byte[] AUTHENTICATE_BYTES = { + (byte) 'W', + (byte) 'W', + (byte) 'W', + (byte) '-', + (byte) 'A', + (byte) 'u', + (byte) 't', + (byte) 'h', + (byte) 'e', + (byte) 'n', + (byte) 't', + (byte) 'i', + (byte) 'c', + (byte) 'a', + (byte) 't', + (byte) 'e' + }; + + + // ----------------------------------------------------- Instance Variables + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.authenticator.BasicAuthenticator/1.0"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Authenticate the user making this request, based on the specified + * login configuration. Return true if any specified + * constraint has been satisfied, or false if we have + * created a response challenge already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + public boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException { + + // Have we already authenticated someone? + Principal principal = request.getUserPrincipal(); + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (principal != null) { + if (log.isDebugEnabled()) + log.debug("Already authenticated '" + principal.getName() + "'"); + // Associate the session with any existing SSO session + if (ssoId != null) + associate(ssoId, request.getSessionInternal(true)); + return (true); + } + + // Is there an SSO session against which we can try to reauthenticate? + if (ssoId != null) { + if (log.isDebugEnabled()) + log.debug("SSO Id " + ssoId + " set; attempting " + + "reauthentication"); + /* Try to reauthenticate using data cached by SSO. If this fails, + either the original SSO logon was of DIGEST or SSL (which + we can't reauthenticate ourselves because there is no + cached username and password), or the realm denied + the user's reauthentication for some reason. + In either case we have to prompt the user for a logon */ + if (reauthenticateFromSSO(ssoId, request)) + return true; + } + + // Validate any credentials already included with this request + String username = null; + String password = null; + + MessageBytes authorization = + request.getCoyoteRequest().getMimeHeaders() + .getValue("authorization"); + + if (authorization != null) { + authorization.toBytes(); + ByteChunk authorizationBC = authorization.getByteChunk(); + if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { + authorizationBC.setOffset(authorizationBC.getOffset() + 6); + // FIXME: Add trimming + // authorizationBC.trim(); + + CharChunk authorizationCC = authorization.getCharChunk(); + Base64.decode(authorizationBC, authorizationCC); + + // Get username and password + int colon = authorizationCC.indexOf(':'); + if (colon < 0) { + username = authorizationCC.toString(); + } else { + char[] buf = authorizationCC.getBuffer(); + username = new String(buf, 0, colon); + password = new String(buf, colon + 1, + authorizationCC.getEnd() - colon - 1); + } + + authorizationBC.setOffset(authorizationBC.getOffset() - 6); + } + + principal = context.getRealm().authenticate(username, password); + if (principal != null) { + register(request, response, principal, Constants.BASIC_METHOD, + username, password); + return (true); + } + } + + + // Send an "unauthorized" response and an appropriate challenge + MessageBytes authenticate = + response.getCoyoteResponse().getMimeHeaders() + .addValue(AUTHENTICATE_BYTES, 0, AUTHENTICATE_BYTES.length); + CharChunk authenticateCC = authenticate.getCharChunk(); + authenticateCC.append("Basic realm=\""); + if (config.getRealmName() == null) { + authenticateCC.append(request.getServerName()); + authenticateCC.append(':'); + authenticateCC.append(Integer.toString(request.getServerPort())); + } else { + authenticateCC.append(config.getRealmName()); + } + authenticateCC.append('\"'); + authenticate.toChars(); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + //response.flushBuffer(); + return (false); + + } + + +} diff --git a/java/org/apache/catalina/authenticator/Constants.java b/java/org/apache/catalina/authenticator/Constants.java index cc21df7fb..77259978b 100644 --- a/java/org/apache/catalina/authenticator/Constants.java +++ b/java/org/apache/catalina/authenticator/Constants.java @@ -1,137 +1,137 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -public class Constants { - - public static final String Package = "org.apache.catalina.authenticator"; - - // Authentication methods for login configuration - public static final String BASIC_METHOD = "BASIC"; - public static final String CERT_METHOD = "CLIENT-CERT"; - public static final String DIGEST_METHOD = "DIGEST"; - public static final String FORM_METHOD = "FORM"; - - // User data constraints for transport guarantee - public static final String NONE_TRANSPORT = "NONE"; - public static final String INTEGRAL_TRANSPORT = "INTEGRAL"; - public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL"; - - // Form based authentication constants - public static final String FORM_ACTION = "/j_security_check"; - public static final String FORM_PASSWORD = "j_password"; - public static final String FORM_USERNAME = "j_username"; - - // Cookie name for single sign on support - public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO"; - - - // --------------------------------------------------------- Request Notes - - - /** - *

    If a user has been authenticated by the web layer, by means of a - * login method other than CLIENT_CERT, the username and password - * used to authenticate the user will be attached to the request as - * Notes for use by other server components. A server component can - * also call several existing methods on Request to determine whether - * or not any user has been authenticated:

    - *
      - *
    • request.getAuthType() - * will return BASIC, CLIENT-CERT, DIGEST, FORM, or null - * if there is no authenticated user.
    • - *
    • request.getUserPrincipal() - * will return the authenticated Principal returned by the - * Realm that authenticated this user.
    • - *
    - *

    If CLIENT_CERT authentication was performed, the certificate chain - * will be available as a request attribute, as defined in the - * servlet specification.

    - */ - - - /** - * The notes key for the password used to authenticate this user. - */ - public static final String REQ_PASSWORD_NOTE = - "org.apache.catalina.request.PASSWORD"; - - - /** - * The notes key for the username used to authenticate this user. - */ - public static final String REQ_USERNAME_NOTE = - "org.apache.catalina.request.USERNAME"; - - - /** - * The notes key to track the single-sign-on identity with which this - * request is associated. - */ - public static final String REQ_SSOID_NOTE = - "org.apache.catalina.request.SSOID"; - - - // ---------------------------------------------------------- Session Notes - - - /** - * If the cache property of our authenticator is set, and - * the current request is part of a session, authentication information - * will be cached to avoid the need for repeated calls to - * Realm.authenticate(), under the following keys: - */ - - - /** - * The notes key for the password used to authenticate this user. - */ - public static final String SESS_PASSWORD_NOTE = - "org.apache.catalina.session.PASSWORD"; - - - /** - * The notes key for the username used to authenticate this user. - */ - public static final String SESS_USERNAME_NOTE = - "org.apache.catalina.session.USERNAME"; - - - /** - * The following note keys are used during form login processing to - * cache required information prior to the completion of authentication. - */ - - - /** - * The previously authenticated principal (if caching is disabled). - */ - public static final String FORM_PRINCIPAL_NOTE = - "org.apache.catalina.authenticator.PRINCIPAL"; - - - /** - * The original request information, to which the user will be - * redirected if authentication succeeds. - */ - public static final String FORM_REQUEST_NOTE = - "org.apache.catalina.authenticator.REQUEST"; - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +public class Constants { + + public static final String Package = "org.apache.catalina.authenticator"; + + // Authentication methods for login configuration + public static final String BASIC_METHOD = "BASIC"; + public static final String CERT_METHOD = "CLIENT-CERT"; + public static final String DIGEST_METHOD = "DIGEST"; + public static final String FORM_METHOD = "FORM"; + + // User data constraints for transport guarantee + public static final String NONE_TRANSPORT = "NONE"; + public static final String INTEGRAL_TRANSPORT = "INTEGRAL"; + public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL"; + + // Form based authentication constants + public static final String FORM_ACTION = "/j_security_check"; + public static final String FORM_PASSWORD = "j_password"; + public static final String FORM_USERNAME = "j_username"; + + // Cookie name for single sign on support + public static final String SINGLE_SIGN_ON_COOKIE = "JSESSIONIDSSO"; + + + // --------------------------------------------------------- Request Notes + + + /** + *

    If a user has been authenticated by the web layer, by means of a + * login method other than CLIENT_CERT, the username and password + * used to authenticate the user will be attached to the request as + * Notes for use by other server components. A server component can + * also call several existing methods on Request to determine whether + * or not any user has been authenticated:

    + *
      + *
    • request.getAuthType() + * will return BASIC, CLIENT-CERT, DIGEST, FORM, or null + * if there is no authenticated user.
    • + *
    • request.getUserPrincipal() + * will return the authenticated Principal returned by the + * Realm that authenticated this user.
    • + *
    + *

    If CLIENT_CERT authentication was performed, the certificate chain + * will be available as a request attribute, as defined in the + * servlet specification.

    + */ + + + /** + * The notes key for the password used to authenticate this user. + */ + public static final String REQ_PASSWORD_NOTE = + "org.apache.catalina.request.PASSWORD"; + + + /** + * The notes key for the username used to authenticate this user. + */ + public static final String REQ_USERNAME_NOTE = + "org.apache.catalina.request.USERNAME"; + + + /** + * The notes key to track the single-sign-on identity with which this + * request is associated. + */ + public static final String REQ_SSOID_NOTE = + "org.apache.catalina.request.SSOID"; + + + // ---------------------------------------------------------- Session Notes + + + /** + * If the cache property of our authenticator is set, and + * the current request is part of a session, authentication information + * will be cached to avoid the need for repeated calls to + * Realm.authenticate(), under the following keys: + */ + + + /** + * The notes key for the password used to authenticate this user. + */ + public static final String SESS_PASSWORD_NOTE = + "org.apache.catalina.session.PASSWORD"; + + + /** + * The notes key for the username used to authenticate this user. + */ + public static final String SESS_USERNAME_NOTE = + "org.apache.catalina.session.USERNAME"; + + + /** + * The following note keys are used during form login processing to + * cache required information prior to the completion of authentication. + */ + + + /** + * The previously authenticated principal (if caching is disabled). + */ + public static final String FORM_PRINCIPAL_NOTE = + "org.apache.catalina.authenticator.PRINCIPAL"; + + + /** + * The original request information, to which the user will be + * redirected if authentication succeeds. + */ + public static final String FORM_REQUEST_NOTE = + "org.apache.catalina.authenticator.REQUEST"; + + +} diff --git a/java/org/apache/catalina/authenticator/DigestAuthenticator.java b/java/org/apache/catalina/authenticator/DigestAuthenticator.java index 0f1423af6..78822a095 100644 --- a/java/org/apache/catalina/authenticator/DigestAuthenticator.java +++ b/java/org/apache/catalina/authenticator/DigestAuthenticator.java @@ -1,424 +1,424 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.util.StringTokenizer; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.catalina.Realm; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.util.MD5Encoder; - - - -/** - * An Authenticator and Valve implementation of HTTP DIGEST - * Authentication (see RFC 2069). - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 370985 $ $Date: 2006-01-21 06:21:15 +0100 (sam., 21 janv. 2006) $ - */ - -public class DigestAuthenticator - extends AuthenticatorBase { - private static Log log = LogFactory.getLog(DigestAuthenticator.class); - - - // -------------------------------------------------------------- Constants - - /** - * The MD5 helper object for this class. - */ - protected static final MD5Encoder md5Encoder = new MD5Encoder(); - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.authenticator.DigestAuthenticator/1.0"; - - - // ----------------------------------------------------------- Constructors - - - public DigestAuthenticator() { - super(); - try { - if (md5Helper == null) - md5Helper = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - e.printStackTrace(); - throw new IllegalStateException(); - } - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * MD5 message digest provider. - */ - protected static MessageDigest md5Helper; - - - /** - * Private key. - */ - protected String key = "Catalina"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Authenticate the user making this request, based on the specified - * login configuration. Return true if any specified - * constraint has been satisfied, or false if we have - * created a response challenge already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - public boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException { - - // Have we already authenticated someone? - Principal principal = request.getUserPrincipal(); - //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (principal != null) { - if (log.isDebugEnabled()) - log.debug("Already authenticated '" + principal.getName() + "'"); - // Associate the session with any existing SSO session in order - // to get coordinated session invalidation at logout - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (ssoId != null) - associate(ssoId, request.getSessionInternal(true)); - return (true); - } - - // NOTE: We don't try to reauthenticate using any existing SSO session, - // because that will only work if the original authentication was - // BASIC or FORM, which are less secure than the DIGEST auth-type - // specified for this webapp - // - // Uncomment below to allow previous FORM or BASIC authentications - // to authenticate users for this webapp - // TODO make this a configurable attribute (in SingleSignOn??) - /* - // Is there an SSO session against which we can try to reauthenticate? - if (ssoId != null) { - if (log.isDebugEnabled()) - log.debug("SSO Id " + ssoId + " set; attempting " + - "reauthentication"); - // Try to reauthenticate using data cached by SSO. If this fails, - // either the original SSO logon was of DIGEST or SSL (which - // we can't reauthenticate ourselves because there is no - // cached username and password), or the realm denied - // the user's reauthentication for some reason. - // In either case we have to prompt the user for a logon - if (reauthenticateFromSSO(ssoId, request)) - return true; - } - */ - - // Validate any credentials already included with this request - String authorization = request.getHeader("authorization"); - if (authorization != null) { - principal = findPrincipal(request, authorization, context.getRealm()); - if (principal != null) { - String username = parseUsername(authorization); - register(request, response, principal, - Constants.DIGEST_METHOD, - username, null); - return (true); - } - } - - // Send an "unauthorized" response and an appropriate challenge - - // Next, generate a nOnce token (that is a token which is supposed - // to be unique). - String nOnce = generateNOnce(request); - - setAuthenticateHeader(request, response, config, nOnce); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED); - // hres.flushBuffer(); - return (false); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Parse the specified authorization credentials, and return the - * associated Principal that these credentials authenticate (if any) - * from the specified Realm. If there is no such Principal, return - * null. - * - * @param request HTTP servlet request - * @param authorization Authorization credentials from this request - * @param realm Realm used to authenticate Principals - */ - protected static Principal findPrincipal(Request request, - String authorization, - Realm realm) { - - //System.out.println("Authorization token : " + authorization); - // Validate the authorization credentials format - if (authorization == null) - return (null); - if (!authorization.startsWith("Digest ")) - return (null); - authorization = authorization.substring(7).trim(); - - // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132 - String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)"); - - String userName = null; - String realmName = null; - String nOnce = null; - String nc = null; - String cnonce = null; - String qop = null; - String uri = null; - String response = null; - String method = request.getMethod(); - - for (int i = 0; i < tokens.length; i++) { - String currentToken = tokens[i]; - if (currentToken.length() == 0) - continue; - - int equalSign = currentToken.indexOf('='); - if (equalSign < 0) - return null; - String currentTokenName = - currentToken.substring(0, equalSign).trim(); - String currentTokenValue = - currentToken.substring(equalSign + 1).trim(); - if ("username".equals(currentTokenName)) - userName = removeQuotes(currentTokenValue); - if ("realm".equals(currentTokenName)) - realmName = removeQuotes(currentTokenValue, true); - if ("nonce".equals(currentTokenName)) - nOnce = removeQuotes(currentTokenValue); - if ("nc".equals(currentTokenName)) - nc = removeQuotes(currentTokenValue); - if ("cnonce".equals(currentTokenName)) - cnonce = removeQuotes(currentTokenValue); - if ("qop".equals(currentTokenName)) - qop = removeQuotes(currentTokenValue); - if ("uri".equals(currentTokenName)) - uri = removeQuotes(currentTokenValue); - if ("response".equals(currentTokenName)) - response = removeQuotes(currentTokenValue); - } - - if ( (userName == null) || (realmName == null) || (nOnce == null) - || (uri == null) || (response == null) ) - return null; - - // Second MD5 digest used to calculate the digest : - // MD5(Method + ":" + uri) - String a2 = method + ":" + uri; - //System.out.println("A2:" + a2); - - byte[] buffer = null; - synchronized (md5Helper) { - buffer = md5Helper.digest(a2.getBytes()); - } - String md5a2 = md5Encoder.encode(buffer); - - return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop, - realmName, md5a2)); - - } - - - /** - * Parse the username from the specified authorization string. If none - * can be identified, return null - * - * @param authorization Authorization string to be parsed - */ - protected String parseUsername(String authorization) { - - //System.out.println("Authorization token : " + authorization); - // Validate the authorization credentials format - if (authorization == null) - return (null); - if (!authorization.startsWith("Digest ")) - return (null); - authorization = authorization.substring(7).trim(); - - StringTokenizer commaTokenizer = - new StringTokenizer(authorization, ","); - - while (commaTokenizer.hasMoreTokens()) { - String currentToken = commaTokenizer.nextToken(); - int equalSign = currentToken.indexOf('='); - if (equalSign < 0) - return null; - String currentTokenName = - currentToken.substring(0, equalSign).trim(); - String currentTokenValue = - currentToken.substring(equalSign + 1).trim(); - if ("username".equals(currentTokenName)) - return (removeQuotes(currentTokenValue)); - } - - return (null); - - } - - - /** - * Removes the quotes on a string. RFC2617 states quotes are optional for - * all parameters except realm. - */ - protected static String removeQuotes(String quotedString, - boolean quotesRequired) { - //support both quoted and non-quoted - if (quotedString.length() > 0 && quotedString.charAt(0) != '"' && - !quotesRequired) { - return quotedString; - } else if (quotedString.length() > 2) { - return quotedString.substring(1, quotedString.length() - 1); - } else { - return new String(); - } - } - - /** - * Removes the quotes on a string. - */ - protected static String removeQuotes(String quotedString) { - return removeQuotes(quotedString, false); - } - - /** - * Generate a unique token. The token is generated according to the - * following pattern. NOnceToken = Base64 ( MD5 ( client-IP ":" - * time-stamp ":" private-key ) ). - * - * @param request HTTP Servlet request - */ - protected String generateNOnce(Request request) { - - long currentTime = System.currentTimeMillis(); - - String nOnceValue = request.getRemoteAddr() + ":" + - currentTime + ":" + key; - - byte[] buffer = null; - synchronized (md5Helper) { - buffer = md5Helper.digest(nOnceValue.getBytes()); - } - nOnceValue = md5Encoder.encode(buffer); - - return nOnceValue; - } - - - /** - * Generates the WWW-Authenticate header. - *

    - * The header MUST follow this template : - *

    -     *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
    -     *                            digest-challenge
    -     *
    -     *      digest-challenge    = 1#( realm | [ domain ] | nOnce |
    -     *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
    -     *
    -     *      realm               = "realm" "=" realm-value
    -     *      realm-value         = quoted-string
    -     *      domain              = "domain" "=" <"> 1#URI <">
    -     *      nonce               = "nonce" "=" nonce-value
    -     *      nonce-value         = quoted-string
    -     *      opaque              = "opaque" "=" quoted-string
    -     *      stale               = "stale" "=" ( "true" | "false" )
    -     *      algorithm           = "algorithm" "=" ( "MD5" | token )
    -     * 
    - * - * @param request HTTP Servlet request - * @param response HTTP Servlet response - * @param config Login configuration describing how authentication - * should be performed - * @param nOnce nonce token - */ - protected void setAuthenticateHeader(Request request, - Response response, - LoginConfig config, - String nOnce) { - - // Get the realm name - String realmName = config.getRealmName(); - if (realmName == null) - realmName = request.getServerName() + ":" - + request.getServerPort(); - - byte[] buffer = null; - synchronized (md5Helper) { - buffer = md5Helper.digest(nOnce.getBytes()); - } - - String authenticateHeader = "Digest realm=\"" + realmName + "\", " - + "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\"" - + md5Encoder.encode(buffer) + "\""; - response.setHeader("WWW-Authenticate", authenticateHeader); - - } - - -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.util.StringTokenizer; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.catalina.Realm; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.util.MD5Encoder; + + + +/** + * An Authenticator and Valve implementation of HTTP DIGEST + * Authentication (see RFC 2069). + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 370985 $ $Date: 2006-01-21 06:21:15 +0100 (sam., 21 janv. 2006) $ + */ + +public class DigestAuthenticator + extends AuthenticatorBase { + private static Log log = LogFactory.getLog(DigestAuthenticator.class); + + + // -------------------------------------------------------------- Constants + + /** + * The MD5 helper object for this class. + */ + protected static final MD5Encoder md5Encoder = new MD5Encoder(); + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.authenticator.DigestAuthenticator/1.0"; + + + // ----------------------------------------------------------- Constructors + + + public DigestAuthenticator() { + super(); + try { + if (md5Helper == null) + md5Helper = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + throw new IllegalStateException(); + } + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * MD5 message digest provider. + */ + protected static MessageDigest md5Helper; + + + /** + * Private key. + */ + protected String key = "Catalina"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Authenticate the user making this request, based on the specified + * login configuration. Return true if any specified + * constraint has been satisfied, or false if we have + * created a response challenge already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + public boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException { + + // Have we already authenticated someone? + Principal principal = request.getUserPrincipal(); + //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (principal != null) { + if (log.isDebugEnabled()) + log.debug("Already authenticated '" + principal.getName() + "'"); + // Associate the session with any existing SSO session in order + // to get coordinated session invalidation at logout + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (ssoId != null) + associate(ssoId, request.getSessionInternal(true)); + return (true); + } + + // NOTE: We don't try to reauthenticate using any existing SSO session, + // because that will only work if the original authentication was + // BASIC or FORM, which are less secure than the DIGEST auth-type + // specified for this webapp + // + // Uncomment below to allow previous FORM or BASIC authentications + // to authenticate users for this webapp + // TODO make this a configurable attribute (in SingleSignOn??) + /* + // Is there an SSO session against which we can try to reauthenticate? + if (ssoId != null) { + if (log.isDebugEnabled()) + log.debug("SSO Id " + ssoId + " set; attempting " + + "reauthentication"); + // Try to reauthenticate using data cached by SSO. If this fails, + // either the original SSO logon was of DIGEST or SSL (which + // we can't reauthenticate ourselves because there is no + // cached username and password), or the realm denied + // the user's reauthentication for some reason. + // In either case we have to prompt the user for a logon + if (reauthenticateFromSSO(ssoId, request)) + return true; + } + */ + + // Validate any credentials already included with this request + String authorization = request.getHeader("authorization"); + if (authorization != null) { + principal = findPrincipal(request, authorization, context.getRealm()); + if (principal != null) { + String username = parseUsername(authorization); + register(request, response, principal, + Constants.DIGEST_METHOD, + username, null); + return (true); + } + } + + // Send an "unauthorized" response and an appropriate challenge + + // Next, generate a nOnce token (that is a token which is supposed + // to be unique). + String nOnce = generateNOnce(request); + + setAuthenticateHeader(request, response, config, nOnce); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED); + // hres.flushBuffer(); + return (false); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Parse the specified authorization credentials, and return the + * associated Principal that these credentials authenticate (if any) + * from the specified Realm. If there is no such Principal, return + * null. + * + * @param request HTTP servlet request + * @param authorization Authorization credentials from this request + * @param realm Realm used to authenticate Principals + */ + protected static Principal findPrincipal(Request request, + String authorization, + Realm realm) { + + //System.out.println("Authorization token : " + authorization); + // Validate the authorization credentials format + if (authorization == null) + return (null); + if (!authorization.startsWith("Digest ")) + return (null); + authorization = authorization.substring(7).trim(); + + // Bugzilla 37132: http://issues.apache.org/bugzilla/show_bug.cgi?id=37132 + String[] tokens = authorization.split(",(?=(?:[^\"]*\"[^\"]*\")+$)"); + + String userName = null; + String realmName = null; + String nOnce = null; + String nc = null; + String cnonce = null; + String qop = null; + String uri = null; + String response = null; + String method = request.getMethod(); + + for (int i = 0; i < tokens.length; i++) { + String currentToken = tokens[i]; + if (currentToken.length() == 0) + continue; + + int equalSign = currentToken.indexOf('='); + if (equalSign < 0) + return null; + String currentTokenName = + currentToken.substring(0, equalSign).trim(); + String currentTokenValue = + currentToken.substring(equalSign + 1).trim(); + if ("username".equals(currentTokenName)) + userName = removeQuotes(currentTokenValue); + if ("realm".equals(currentTokenName)) + realmName = removeQuotes(currentTokenValue, true); + if ("nonce".equals(currentTokenName)) + nOnce = removeQuotes(currentTokenValue); + if ("nc".equals(currentTokenName)) + nc = removeQuotes(currentTokenValue); + if ("cnonce".equals(currentTokenName)) + cnonce = removeQuotes(currentTokenValue); + if ("qop".equals(currentTokenName)) + qop = removeQuotes(currentTokenValue); + if ("uri".equals(currentTokenName)) + uri = removeQuotes(currentTokenValue); + if ("response".equals(currentTokenName)) + response = removeQuotes(currentTokenValue); + } + + if ( (userName == null) || (realmName == null) || (nOnce == null) + || (uri == null) || (response == null) ) + return null; + + // Second MD5 digest used to calculate the digest : + // MD5(Method + ":" + uri) + String a2 = method + ":" + uri; + //System.out.println("A2:" + a2); + + byte[] buffer = null; + synchronized (md5Helper) { + buffer = md5Helper.digest(a2.getBytes()); + } + String md5a2 = md5Encoder.encode(buffer); + + return (realm.authenticate(userName, response, nOnce, nc, cnonce, qop, + realmName, md5a2)); + + } + + + /** + * Parse the username from the specified authorization string. If none + * can be identified, return null + * + * @param authorization Authorization string to be parsed + */ + protected String parseUsername(String authorization) { + + //System.out.println("Authorization token : " + authorization); + // Validate the authorization credentials format + if (authorization == null) + return (null); + if (!authorization.startsWith("Digest ")) + return (null); + authorization = authorization.substring(7).trim(); + + StringTokenizer commaTokenizer = + new StringTokenizer(authorization, ","); + + while (commaTokenizer.hasMoreTokens()) { + String currentToken = commaTokenizer.nextToken(); + int equalSign = currentToken.indexOf('='); + if (equalSign < 0) + return null; + String currentTokenName = + currentToken.substring(0, equalSign).trim(); + String currentTokenValue = + currentToken.substring(equalSign + 1).trim(); + if ("username".equals(currentTokenName)) + return (removeQuotes(currentTokenValue)); + } + + return (null); + + } + + + /** + * Removes the quotes on a string. RFC2617 states quotes are optional for + * all parameters except realm. + */ + protected static String removeQuotes(String quotedString, + boolean quotesRequired) { + //support both quoted and non-quoted + if (quotedString.length() > 0 && quotedString.charAt(0) != '"' && + !quotesRequired) { + return quotedString; + } else if (quotedString.length() > 2) { + return quotedString.substring(1, quotedString.length() - 1); + } else { + return new String(); + } + } + + /** + * Removes the quotes on a string. + */ + protected static String removeQuotes(String quotedString) { + return removeQuotes(quotedString, false); + } + + /** + * Generate a unique token. The token is generated according to the + * following pattern. NOnceToken = Base64 ( MD5 ( client-IP ":" + * time-stamp ":" private-key ) ). + * + * @param request HTTP Servlet request + */ + protected String generateNOnce(Request request) { + + long currentTime = System.currentTimeMillis(); + + String nOnceValue = request.getRemoteAddr() + ":" + + currentTime + ":" + key; + + byte[] buffer = null; + synchronized (md5Helper) { + buffer = md5Helper.digest(nOnceValue.getBytes()); + } + nOnceValue = md5Encoder.encode(buffer); + + return nOnceValue; + } + + + /** + * Generates the WWW-Authenticate header. + *

    + * The header MUST follow this template : + *

    +     *      WWW-Authenticate    = "WWW-Authenticate" ":" "Digest"
    +     *                            digest-challenge
    +     *
    +     *      digest-challenge    = 1#( realm | [ domain ] | nOnce |
    +     *                  [ digest-opaque ] |[ stale ] | [ algorithm ] )
    +     *
    +     *      realm               = "realm" "=" realm-value
    +     *      realm-value         = quoted-string
    +     *      domain              = "domain" "=" <"> 1#URI <">
    +     *      nonce               = "nonce" "=" nonce-value
    +     *      nonce-value         = quoted-string
    +     *      opaque              = "opaque" "=" quoted-string
    +     *      stale               = "stale" "=" ( "true" | "false" )
    +     *      algorithm           = "algorithm" "=" ( "MD5" | token )
    +     * 
    + * + * @param request HTTP Servlet request + * @param response HTTP Servlet response + * @param config Login configuration describing how authentication + * should be performed + * @param nOnce nonce token + */ + protected void setAuthenticateHeader(Request request, + Response response, + LoginConfig config, + String nOnce) { + + // Get the realm name + String realmName = config.getRealmName(); + if (realmName == null) + realmName = request.getServerName() + ":" + + request.getServerPort(); + + byte[] buffer = null; + synchronized (md5Helper) { + buffer = md5Helper.digest(nOnce.getBytes()); + } + + String authenticateHeader = "Digest realm=\"" + realmName + "\", " + + "qop=\"auth\", nonce=\"" + nOnce + "\", " + "opaque=\"" + + md5Encoder.encode(buffer) + "\""; + response.setHeader("WWW-Authenticate", authenticateHeader); + + } + + +} diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java index 52c177550..e4dd68f85 100644 --- a/java/org/apache/catalina/authenticator/FormAuthenticator.java +++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java @@ -1,524 +1,524 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.io.InputStream; -import java.security.Principal; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Locale; - -import javax.servlet.RequestDispatcher; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Realm; -import org.apache.catalina.Session; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.coyote.ActionCode; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.MimeHeaders; - - -/** - * An Authenticator and Valve implementation of FORM BASED - * Authentication, as described in the Servlet API Specification, Version 2.2. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 320670 $ $Date: 2005-10-13 07:39:55 +0200 (jeu., 13 oct. 2005) $ - */ - -public class FormAuthenticator - extends AuthenticatorBase { - - private static Log log = LogFactory.getLog(FormAuthenticator.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.authenticator.FormAuthenticator/1.0"; - - /** - * Character encoding to use to read the username and password parameters - * from the request. If not set, the encoding of the request body will be - * used. - */ - protected String characterEncoding = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the character encoding to use to read the username and password. - */ - public String getCharacterEncoding() { - return characterEncoding; - } - - - /** - * Set the character encoding to be used to read the username and password. - */ - public void setCharacterEncoding(String encoding) { - characterEncoding = encoding; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Authenticate the user making this request, based on the specified - * login configuration. Return true if any specified - * constraint has been satisfied, or false if we have - * created a response challenge already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - public boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException { - - // References to objects we will need later - Session session = null; - - // Have we already authenticated someone? - Principal principal = request.getUserPrincipal(); - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (principal != null) { - if (log.isDebugEnabled()) - log.debug("Already authenticated '" + - principal.getName() + "'"); - // Associate the session with any existing SSO session - if (ssoId != null) - associate(ssoId, request.getSessionInternal(true)); - return (true); - } - - // Is there an SSO session against which we can try to reauthenticate? - if (ssoId != null) { - if (log.isDebugEnabled()) - log.debug("SSO Id " + ssoId + " set; attempting " + - "reauthentication"); - // Try to reauthenticate using data cached by SSO. If this fails, - // either the original SSO logon was of DIGEST or SSL (which - // we can't reauthenticate ourselves because there is no - // cached username and password), or the realm denied - // the user's reauthentication for some reason. - // In either case we have to prompt the user for a logon */ - if (reauthenticateFromSSO(ssoId, request)) - return true; - } - - // Have we authenticated this user before but have caching disabled? - if (!cache) { - session = request.getSessionInternal(true); - if (log.isDebugEnabled()) - log.debug("Checking for reauthenticate in session " + session); - String username = - (String) session.getNote(Constants.SESS_USERNAME_NOTE); - String password = - (String) session.getNote(Constants.SESS_PASSWORD_NOTE); - if ((username != null) && (password != null)) { - if (log.isDebugEnabled()) - log.debug("Reauthenticating username '" + username + "'"); - principal = - context.getRealm().authenticate(username, password); - if (principal != null) { - session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); - if (!matchRequest(request)) { - register(request, response, principal, - Constants.FORM_METHOD, - username, password); - return (true); - } - } - if (log.isDebugEnabled()) - log.debug("Reauthentication failed, proceed normally"); - } - } - - // Is this the re-submit of the original request URI after successful - // authentication? If so, forward the *original* request instead. - if (matchRequest(request)) { - session = request.getSessionInternal(true); - if (log.isDebugEnabled()) - log.debug("Restore request from session '" - + session.getIdInternal() - + "'"); - principal = (Principal) - session.getNote(Constants.FORM_PRINCIPAL_NOTE); - register(request, response, principal, Constants.FORM_METHOD, - (String) session.getNote(Constants.SESS_USERNAME_NOTE), - (String) session.getNote(Constants.SESS_PASSWORD_NOTE)); - // If we're caching principals we no longer need the username - // and password in the session, so remove them - if (cache) { - session.removeNote(Constants.SESS_USERNAME_NOTE); - session.removeNote(Constants.SESS_PASSWORD_NOTE); - } - if (restoreRequest(request, session)) { - if (log.isDebugEnabled()) - log.debug("Proceed to restored request"); - return (true); - } else { - if (log.isDebugEnabled()) - log.debug("Restore of original request failed"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return (false); - } - } - - // Acquire references to objects we will need to evaluate - MessageBytes uriMB = MessageBytes.newInstance(); - CharChunk uriCC = uriMB.getCharChunk(); - uriCC.setLimit(-1); - String contextPath = request.getContextPath(); - String requestURI = request.getDecodedRequestURI(); - response.setContext(request.getContext()); - - // Is this the action request from the login page? - boolean loginAction = - requestURI.startsWith(contextPath) && - requestURI.endsWith(Constants.FORM_ACTION); - - // No -- Save this request and redirect to the form login page - if (!loginAction) { - session = request.getSessionInternal(true); - if (log.isDebugEnabled()) - log.debug("Save request in session '" + session.getIdInternal() + "'"); - try { - saveRequest(request, session); - } catch (IOException ioe) { - log.debug("Request body too big to save during authentication"); - response.sendError(HttpServletResponse.SC_FORBIDDEN, - sm.getString("authenticator.requestBodyTooBig")); - return (false); - } - forwardToLoginPage(request, response, config); - return (false); - } - - // Yes -- Validate the specified credentials and redirect - // to the error page if they are not correct - Realm realm = context.getRealm(); - if (characterEncoding != null) { - request.setCharacterEncoding(characterEncoding); - } - String username = request.getParameter(Constants.FORM_USERNAME); - String password = request.getParameter(Constants.FORM_PASSWORD); - if (log.isDebugEnabled()) - log.debug("Authenticating username '" + username + "'"); - principal = realm.authenticate(username, password); - if (principal == null) { - forwardToErrorPage(request, response, config); - return (false); - } - - if (log.isDebugEnabled()) - log.debug("Authentication of '" + username + "' was successful"); - - if (session == null) - session = request.getSessionInternal(false); - if (session == null) { - if (containerLog.isDebugEnabled()) - containerLog.debug - ("User took so long to log on the session expired"); - response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, - sm.getString("authenticator.sessionExpired")); - return (false); - } - - // Save the authenticated Principal in our session - session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); - - // Save the username and password as well - session.setNote(Constants.SESS_USERNAME_NOTE, username); - session.setNote(Constants.SESS_PASSWORD_NOTE, password); - - // Redirect the user to the original request URI (which will cause - // the original request to be restored) - requestURI = savedRequestURL(session); - if (log.isDebugEnabled()) - log.debug("Redirecting to original '" + requestURI + "'"); - if (requestURI == null) - response.sendError(HttpServletResponse.SC_BAD_REQUEST, - sm.getString("authenticator.formlogin")); - else - response.sendRedirect(response.encodeRedirectURL(requestURI)); - return (false); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Called to forward to the login page - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - */ - protected void forwardToLoginPage(Request request, Response response, LoginConfig config) { - RequestDispatcher disp = - context.getServletContext().getRequestDispatcher - (config.getLoginPage()); - try { - disp.forward(request.getRequest(), response.getResponse()); - response.finishResponse(); - } catch (Throwable t) { - log.warn("Unexpected error forwarding to login page", t); - } - } - - - /** - * Called to forward to the error page - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - */ - protected void forwardToErrorPage(Request request, Response response, LoginConfig config) { - RequestDispatcher disp = - context.getServletContext().getRequestDispatcher - (config.getErrorPage()); - try { - disp.forward(request.getRequest(), response.getResponse()); - } catch (Throwable t) { - log.warn("Unexpected error forwarding to error page", t); - } - } - - - /** - * Does this request match the saved one (so that it must be the redirect - * we signalled after successful authentication? - * - * @param request The request to be verified - */ - protected boolean matchRequest(Request request) { - - // Has a session been created? - Session session = request.getSessionInternal(false); - if (session == null) - return (false); - - // Is there a saved request? - SavedRequest sreq = (SavedRequest) - session.getNote(Constants.FORM_REQUEST_NOTE); - if (sreq == null) - return (false); - - // Is there a saved principal? - if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) - return (false); - - // Does the request URI match? - String requestURI = request.getRequestURI(); - if (requestURI == null) - return (false); - return (requestURI.equals(request.getRequestURI())); - - } - - - /** - * Restore the original request from information stored in our session. - * If the original request is no longer present (because the session - * timed out), return false; otherwise, return - * true. - * - * @param request The request to be restored - * @param session The session containing the saved information - */ - protected boolean restoreRequest(Request request, Session session) - throws IOException { - - // Retrieve and remove the SavedRequest object from our session - SavedRequest saved = (SavedRequest) - session.getNote(Constants.FORM_REQUEST_NOTE); - session.removeNote(Constants.FORM_REQUEST_NOTE); - session.removeNote(Constants.FORM_PRINCIPAL_NOTE); - if (saved == null) - return (false); - - // Modify our current request to reflect the original one - request.clearCookies(); - Iterator cookies = saved.getCookies(); - while (cookies.hasNext()) { - request.addCookie((Cookie) cookies.next()); - } - - MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders(); - rmh.recycle(); - Iterator names = saved.getHeaderNames(); - while (names.hasNext()) { - String name = (String) names.next(); - Iterator values = saved.getHeaderValues(name); - while (values.hasNext()) { - rmh.addValue(name).setString( (String)values.next() ); - } - } - - request.clearLocales(); - Iterator locales = saved.getLocales(); - while (locales.hasNext()) { - request.addLocale((Locale) locales.next()); - } - - request.getCoyoteRequest().getParameters().recycle(); - - if ("POST".equalsIgnoreCase(saved.getMethod())) { - ByteChunk body = saved.getBody(); - - if (body != null) { - request.getCoyoteRequest().action - (ActionCode.ACTION_REQ_SET_BODY_REPLAY, body); - - // Set content type - MessageBytes contentType = MessageBytes.newInstance(); - contentType.setString("application/x-www-form-urlencoded"); - request.getCoyoteRequest().setContentType(contentType); - } - } - request.getCoyoteRequest().method().setString(saved.getMethod()); - - request.getCoyoteRequest().queryString().setString - (saved.getQueryString()); - - request.getCoyoteRequest().requestURI().setString - (saved.getRequestURI()); - return (true); - - } - - - /** - * Save the original request information into our session. - * - * @param request The request to be saved - * @param session The session to contain the saved information - * @throws IOException - */ - protected void saveRequest(Request request, Session session) - throws IOException { - - // Create and populate a SavedRequest object for this request - SavedRequest saved = new SavedRequest(); - Cookie cookies[] = request.getCookies(); - if (cookies != null) { - for (int i = 0; i < cookies.length; i++) - saved.addCookie(cookies[i]); - } - Enumeration names = request.getHeaderNames(); - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - Enumeration values = request.getHeaders(name); - while (values.hasMoreElements()) { - String value = (String) values.nextElement(); - saved.addHeader(name, value); - } - } - Enumeration locales = request.getLocales(); - while (locales.hasMoreElements()) { - Locale locale = (Locale) locales.nextElement(); - saved.addLocale(locale); - } - - if ("POST".equalsIgnoreCase(request.getMethod())) { - ByteChunk body = new ByteChunk(); - body.setLimit(request.getConnector().getMaxSavePostSize()); - - byte[] buffer = new byte[4096]; - int bytesRead; - InputStream is = request.getInputStream(); - - while ( (bytesRead = is.read(buffer) ) >= 0) { - body.append(buffer, 0, bytesRead); - } - saved.setBody(body); - } - - saved.setMethod(request.getMethod()); - saved.setQueryString(request.getQueryString()); - saved.setRequestURI(request.getRequestURI()); - - // Stash the SavedRequest in our session for later use - session.setNote(Constants.FORM_REQUEST_NOTE, saved); - - } - - - /** - * Return the request URI (with the corresponding query string, if any) - * from the saved request so that we can redirect to it. - * - * @param session Our current session - */ - protected String savedRequestURL(Session session) { - - SavedRequest saved = - (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); - if (saved == null) - return (null); - StringBuffer sb = new StringBuffer(saved.getRequestURI()); - if (saved.getQueryString() != null) { - sb.append('?'); - sb.append(saved.getQueryString()); - } - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.io.InputStream; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Locale; + +import javax.servlet.RequestDispatcher; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.coyote.ActionCode; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; + + +/** + * An Authenticator and Valve implementation of FORM BASED + * Authentication, as described in the Servlet API Specification, Version 2.2. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 320670 $ $Date: 2005-10-13 07:39:55 +0200 (jeu., 13 oct. 2005) $ + */ + +public class FormAuthenticator + extends AuthenticatorBase { + + private static Log log = LogFactory.getLog(FormAuthenticator.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.authenticator.FormAuthenticator/1.0"; + + /** + * Character encoding to use to read the username and password parameters + * from the request. If not set, the encoding of the request body will be + * used. + */ + protected String characterEncoding = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the character encoding to use to read the username and password. + */ + public String getCharacterEncoding() { + return characterEncoding; + } + + + /** + * Set the character encoding to be used to read the username and password. + */ + public void setCharacterEncoding(String encoding) { + characterEncoding = encoding; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Authenticate the user making this request, based on the specified + * login configuration. Return true if any specified + * constraint has been satisfied, or false if we have + * created a response challenge already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + public boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException { + + // References to objects we will need later + Session session = null; + + // Have we already authenticated someone? + Principal principal = request.getUserPrincipal(); + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (principal != null) { + if (log.isDebugEnabled()) + log.debug("Already authenticated '" + + principal.getName() + "'"); + // Associate the session with any existing SSO session + if (ssoId != null) + associate(ssoId, request.getSessionInternal(true)); + return (true); + } + + // Is there an SSO session against which we can try to reauthenticate? + if (ssoId != null) { + if (log.isDebugEnabled()) + log.debug("SSO Id " + ssoId + " set; attempting " + + "reauthentication"); + // Try to reauthenticate using data cached by SSO. If this fails, + // either the original SSO logon was of DIGEST or SSL (which + // we can't reauthenticate ourselves because there is no + // cached username and password), or the realm denied + // the user's reauthentication for some reason. + // In either case we have to prompt the user for a logon */ + if (reauthenticateFromSSO(ssoId, request)) + return true; + } + + // Have we authenticated this user before but have caching disabled? + if (!cache) { + session = request.getSessionInternal(true); + if (log.isDebugEnabled()) + log.debug("Checking for reauthenticate in session " + session); + String username = + (String) session.getNote(Constants.SESS_USERNAME_NOTE); + String password = + (String) session.getNote(Constants.SESS_PASSWORD_NOTE); + if ((username != null) && (password != null)) { + if (log.isDebugEnabled()) + log.debug("Reauthenticating username '" + username + "'"); + principal = + context.getRealm().authenticate(username, password); + if (principal != null) { + session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); + if (!matchRequest(request)) { + register(request, response, principal, + Constants.FORM_METHOD, + username, password); + return (true); + } + } + if (log.isDebugEnabled()) + log.debug("Reauthentication failed, proceed normally"); + } + } + + // Is this the re-submit of the original request URI after successful + // authentication? If so, forward the *original* request instead. + if (matchRequest(request)) { + session = request.getSessionInternal(true); + if (log.isDebugEnabled()) + log.debug("Restore request from session '" + + session.getIdInternal() + + "'"); + principal = (Principal) + session.getNote(Constants.FORM_PRINCIPAL_NOTE); + register(request, response, principal, Constants.FORM_METHOD, + (String) session.getNote(Constants.SESS_USERNAME_NOTE), + (String) session.getNote(Constants.SESS_PASSWORD_NOTE)); + // If we're caching principals we no longer need the username + // and password in the session, so remove them + if (cache) { + session.removeNote(Constants.SESS_USERNAME_NOTE); + session.removeNote(Constants.SESS_PASSWORD_NOTE); + } + if (restoreRequest(request, session)) { + if (log.isDebugEnabled()) + log.debug("Proceed to restored request"); + return (true); + } else { + if (log.isDebugEnabled()) + log.debug("Restore of original request failed"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return (false); + } + } + + // Acquire references to objects we will need to evaluate + MessageBytes uriMB = MessageBytes.newInstance(); + CharChunk uriCC = uriMB.getCharChunk(); + uriCC.setLimit(-1); + String contextPath = request.getContextPath(); + String requestURI = request.getDecodedRequestURI(); + response.setContext(request.getContext()); + + // Is this the action request from the login page? + boolean loginAction = + requestURI.startsWith(contextPath) && + requestURI.endsWith(Constants.FORM_ACTION); + + // No -- Save this request and redirect to the form login page + if (!loginAction) { + session = request.getSessionInternal(true); + if (log.isDebugEnabled()) + log.debug("Save request in session '" + session.getIdInternal() + "'"); + try { + saveRequest(request, session); + } catch (IOException ioe) { + log.debug("Request body too big to save during authentication"); + response.sendError(HttpServletResponse.SC_FORBIDDEN, + sm.getString("authenticator.requestBodyTooBig")); + return (false); + } + forwardToLoginPage(request, response, config); + return (false); + } + + // Yes -- Validate the specified credentials and redirect + // to the error page if they are not correct + Realm realm = context.getRealm(); + if (characterEncoding != null) { + request.setCharacterEncoding(characterEncoding); + } + String username = request.getParameter(Constants.FORM_USERNAME); + String password = request.getParameter(Constants.FORM_PASSWORD); + if (log.isDebugEnabled()) + log.debug("Authenticating username '" + username + "'"); + principal = realm.authenticate(username, password); + if (principal == null) { + forwardToErrorPage(request, response, config); + return (false); + } + + if (log.isDebugEnabled()) + log.debug("Authentication of '" + username + "' was successful"); + + if (session == null) + session = request.getSessionInternal(false); + if (session == null) { + if (containerLog.isDebugEnabled()) + containerLog.debug + ("User took so long to log on the session expired"); + response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, + sm.getString("authenticator.sessionExpired")); + return (false); + } + + // Save the authenticated Principal in our session + session.setNote(Constants.FORM_PRINCIPAL_NOTE, principal); + + // Save the username and password as well + session.setNote(Constants.SESS_USERNAME_NOTE, username); + session.setNote(Constants.SESS_PASSWORD_NOTE, password); + + // Redirect the user to the original request URI (which will cause + // the original request to be restored) + requestURI = savedRequestURL(session); + if (log.isDebugEnabled()) + log.debug("Redirecting to original '" + requestURI + "'"); + if (requestURI == null) + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + sm.getString("authenticator.formlogin")); + else + response.sendRedirect(response.encodeRedirectURL(requestURI)); + return (false); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Called to forward to the login page + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + */ + protected void forwardToLoginPage(Request request, Response response, LoginConfig config) { + RequestDispatcher disp = + context.getServletContext().getRequestDispatcher + (config.getLoginPage()); + try { + disp.forward(request.getRequest(), response.getResponse()); + response.finishResponse(); + } catch (Throwable t) { + log.warn("Unexpected error forwarding to login page", t); + } + } + + + /** + * Called to forward to the error page + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + */ + protected void forwardToErrorPage(Request request, Response response, LoginConfig config) { + RequestDispatcher disp = + context.getServletContext().getRequestDispatcher + (config.getErrorPage()); + try { + disp.forward(request.getRequest(), response.getResponse()); + } catch (Throwable t) { + log.warn("Unexpected error forwarding to error page", t); + } + } + + + /** + * Does this request match the saved one (so that it must be the redirect + * we signalled after successful authentication? + * + * @param request The request to be verified + */ + protected boolean matchRequest(Request request) { + + // Has a session been created? + Session session = request.getSessionInternal(false); + if (session == null) + return (false); + + // Is there a saved request? + SavedRequest sreq = (SavedRequest) + session.getNote(Constants.FORM_REQUEST_NOTE); + if (sreq == null) + return (false); + + // Is there a saved principal? + if (session.getNote(Constants.FORM_PRINCIPAL_NOTE) == null) + return (false); + + // Does the request URI match? + String requestURI = request.getRequestURI(); + if (requestURI == null) + return (false); + return (requestURI.equals(request.getRequestURI())); + + } + + + /** + * Restore the original request from information stored in our session. + * If the original request is no longer present (because the session + * timed out), return false; otherwise, return + * true. + * + * @param request The request to be restored + * @param session The session containing the saved information + */ + protected boolean restoreRequest(Request request, Session session) + throws IOException { + + // Retrieve and remove the SavedRequest object from our session + SavedRequest saved = (SavedRequest) + session.getNote(Constants.FORM_REQUEST_NOTE); + session.removeNote(Constants.FORM_REQUEST_NOTE); + session.removeNote(Constants.FORM_PRINCIPAL_NOTE); + if (saved == null) + return (false); + + // Modify our current request to reflect the original one + request.clearCookies(); + Iterator cookies = saved.getCookies(); + while (cookies.hasNext()) { + request.addCookie((Cookie) cookies.next()); + } + + MimeHeaders rmh = request.getCoyoteRequest().getMimeHeaders(); + rmh.recycle(); + Iterator names = saved.getHeaderNames(); + while (names.hasNext()) { + String name = (String) names.next(); + Iterator values = saved.getHeaderValues(name); + while (values.hasNext()) { + rmh.addValue(name).setString( (String)values.next() ); + } + } + + request.clearLocales(); + Iterator locales = saved.getLocales(); + while (locales.hasNext()) { + request.addLocale((Locale) locales.next()); + } + + request.getCoyoteRequest().getParameters().recycle(); + + if ("POST".equalsIgnoreCase(saved.getMethod())) { + ByteChunk body = saved.getBody(); + + if (body != null) { + request.getCoyoteRequest().action + (ActionCode.ACTION_REQ_SET_BODY_REPLAY, body); + + // Set content type + MessageBytes contentType = MessageBytes.newInstance(); + contentType.setString("application/x-www-form-urlencoded"); + request.getCoyoteRequest().setContentType(contentType); + } + } + request.getCoyoteRequest().method().setString(saved.getMethod()); + + request.getCoyoteRequest().queryString().setString + (saved.getQueryString()); + + request.getCoyoteRequest().requestURI().setString + (saved.getRequestURI()); + return (true); + + } + + + /** + * Save the original request information into our session. + * + * @param request The request to be saved + * @param session The session to contain the saved information + * @throws IOException + */ + protected void saveRequest(Request request, Session session) + throws IOException { + + // Create and populate a SavedRequest object for this request + SavedRequest saved = new SavedRequest(); + Cookie cookies[] = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) + saved.addCookie(cookies[i]); + } + Enumeration names = request.getHeaderNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + Enumeration values = request.getHeaders(name); + while (values.hasMoreElements()) { + String value = (String) values.nextElement(); + saved.addHeader(name, value); + } + } + Enumeration locales = request.getLocales(); + while (locales.hasMoreElements()) { + Locale locale = (Locale) locales.nextElement(); + saved.addLocale(locale); + } + + if ("POST".equalsIgnoreCase(request.getMethod())) { + ByteChunk body = new ByteChunk(); + body.setLimit(request.getConnector().getMaxSavePostSize()); + + byte[] buffer = new byte[4096]; + int bytesRead; + InputStream is = request.getInputStream(); + + while ( (bytesRead = is.read(buffer) ) >= 0) { + body.append(buffer, 0, bytesRead); + } + saved.setBody(body); + } + + saved.setMethod(request.getMethod()); + saved.setQueryString(request.getQueryString()); + saved.setRequestURI(request.getRequestURI()); + + // Stash the SavedRequest in our session for later use + session.setNote(Constants.FORM_REQUEST_NOTE, saved); + + } + + + /** + * Return the request URI (with the corresponding query string, if any) + * from the saved request so that we can redirect to it. + * + * @param session Our current session + */ + protected String savedRequestURL(Session session) { + + SavedRequest saved = + (SavedRequest) session.getNote(Constants.FORM_REQUEST_NOTE); + if (saved == null) + return (null); + StringBuffer sb = new StringBuffer(saved.getRequestURI()); + if (saved.getQueryString() != null) { + sb.append('?'); + sb.append(saved.getQueryString()); + } + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/authenticator/LocalStrings.properties b/java/org/apache/catalina/authenticator/LocalStrings.properties index 84e91b3b9..e606f6bd8 100644 --- a/java/org/apache/catalina/authenticator/LocalStrings.properties +++ b/java/org/apache/catalina/authenticator/LocalStrings.properties @@ -1,14 +1,14 @@ -authenticator.alreadyStarted=Security Interceptor has already been started -authenticator.certificates=No client certificate chain in this request -authenticator.forbidden=Access to the requested resource has been denied -authenticator.formlogin=Invalid direct reference to form login page -authenticator.invalid=Invalid client certificate chain in this request -authenticator.keystore=Exception loading key store -authenticator.manager=Exception initializing trust managers -authenticator.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal -authenticator.notContext=Configuration error: Must be attached to a Context -authenticator.notStarted=Security Interceptor has not yet been started -authenticator.requestBodyTooBig=The request body was too large to be cached during the authentication process -authenticator.sessionExpired=The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser -authenticator.unauthorized=Cannot authenticate with the provided credentials -authenticator.userDataConstraint=This request violates a User Data constraint for this application +authenticator.alreadyStarted=Security Interceptor has already been started +authenticator.certificates=No client certificate chain in this request +authenticator.forbidden=Access to the requested resource has been denied +authenticator.formlogin=Invalid direct reference to form login page +authenticator.invalid=Invalid client certificate chain in this request +authenticator.keystore=Exception loading key store +authenticator.manager=Exception initializing trust managers +authenticator.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal +authenticator.notContext=Configuration error: Must be attached to a Context +authenticator.notStarted=Security Interceptor has not yet been started +authenticator.requestBodyTooBig=The request body was too large to be cached during the authentication process +authenticator.sessionExpired=The time allowed for the login process has been exceeded. If you wish to continue you must either click back twice and re-click the link you requested or close and re-open your browser +authenticator.unauthorized=Cannot authenticate with the provided credentials +authenticator.userDataConstraint=This request violates a User Data constraint for this application diff --git a/java/org/apache/catalina/authenticator/LocalStrings_es.properties b/java/org/apache/catalina/authenticator/LocalStrings_es.properties index b38497c92..37da93c17 100644 --- a/java/org/apache/catalina/authenticator/LocalStrings_es.properties +++ b/java/org/apache/catalina/authenticator/LocalStrings_es.properties @@ -1,12 +1,12 @@ -authenticator.alreadyStarted=El interceptor de seguridad ya ha sido arrancado -authenticator.certificates=No hay cadena de certificados del cliente en esta petición -authenticator.forbidden=El acceso al recurso pedido ha sido denegado -authenticator.formlogin=Referencia directa al formulario de conexión (página de formulario de login) inválida -authenticator.invalid=No es válida la cadena de certificados del cliente en esta petición -authenticator.keystore=Excepción cargando el almacén de claves -authenticator.manager=Excepción inicializando administradores de confianza -authenticator.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autenticado -authenticator.notContext=Error de Configuración: Debe de estar unido a un Contexto -authenticator.notStarted=El Interceptor de seguridad no sido aún iniciado -authenticator.unauthorized=Imposible autenticar mediante las credenciales suministradas -authenticator.userDataConstraint=Esta petición viola una Restrición de Datos de usuario para esta aplicación +authenticator.alreadyStarted=El interceptor de seguridad ya ha sido arrancado +authenticator.certificates=No hay cadena de certificados del cliente en esta petición +authenticator.forbidden=El acceso al recurso pedido ha sido denegado +authenticator.formlogin=Referencia directa al formulario de conexión (página de formulario de login) inválida +authenticator.invalid=No es válida la cadena de certificados del cliente en esta petición +authenticator.keystore=Excepción cargando el almacén de claves +authenticator.manager=Excepción inicializando administradores de confianza +authenticator.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autenticado +authenticator.notContext=Error de Configuración: Debe de estar unido a un Contexto +authenticator.notStarted=El Interceptor de seguridad no sido aún iniciado +authenticator.unauthorized=Imposible autenticar mediante las credenciales suministradas +authenticator.userDataConstraint=Esta petición viola una Restrición de Datos de usuario para esta aplicación diff --git a/java/org/apache/catalina/authenticator/LocalStrings_fr.properties b/java/org/apache/catalina/authenticator/LocalStrings_fr.properties index ed45aaaff..04e5d6be1 100644 --- a/java/org/apache/catalina/authenticator/LocalStrings_fr.properties +++ b/java/org/apache/catalina/authenticator/LocalStrings_fr.properties @@ -1,12 +1,12 @@ -authenticator.alreadyStarted=L''intercepteur de sécurité (security interceptor) a déjà été démarré -authenticator.certificates=Aucune chaîne de certificat client (client certificate chain) dans cette requête -authenticator.forbidden=L''accès à la ressource demandée a été interdit -authenticator.formlogin=Référence directe à la form de connexion (form login page) invalide -authenticator.invalid=Chaîne de certificat client invalide dans cette requête -authenticator.keystore=Exception lors du chargement du référentiel de clefs (key store) -authenticator.manager=Exception lors de l''initialisation des gestionnaires d''authentification (trust managers) -authenticator.notAuthenticated=Erreur de configuration: Impossible de procéder à un contrôle d''accès sans un principal authentifié (authenticated principal) -authenticator.notContext=Erreur de configuration: Doit être attaché à un contexte -authenticator.notStarted=L''intercepteur de sécurité (security interceptor) n''a pas encore été démarré -authenticator.unauthorized=Impossible d''authentifier avec les crédits fournis (provided credentials) -authenticator.userDataConstraint=Cette requête viole une contrainte donnée utilisateur (user data constraint) pour cette application +authenticator.alreadyStarted=L''intercepteur de sécurité (security interceptor) a déjà été démarré +authenticator.certificates=Aucune chaîne de certificat client (client certificate chain) dans cette requête +authenticator.forbidden=L''accès à la ressource demandée a été interdit +authenticator.formlogin=Référence directe à la form de connexion (form login page) invalide +authenticator.invalid=Chaîne de certificat client invalide dans cette requête +authenticator.keystore=Exception lors du chargement du référentiel de clefs (key store) +authenticator.manager=Exception lors de l''initialisation des gestionnaires d''authentification (trust managers) +authenticator.notAuthenticated=Erreur de configuration: Impossible de procéder à un contrôle d''accès sans un principal authentifié (authenticated principal) +authenticator.notContext=Erreur de configuration: Doit être attaché à un contexte +authenticator.notStarted=L''intercepteur de sécurité (security interceptor) n''a pas encore été démarré +authenticator.unauthorized=Impossible d''authentifier avec les crédits fournis (provided credentials) +authenticator.userDataConstraint=Cette requête viole une contrainte donnée utilisateur (user data constraint) pour cette application diff --git a/java/org/apache/catalina/authenticator/LocalStrings_ja.properties b/java/org/apache/catalina/authenticator/LocalStrings_ja.properties index 707a9719f..5d7fd5813 100644 --- a/java/org/apache/catalina/authenticator/LocalStrings_ja.properties +++ b/java/org/apache/catalina/authenticator/LocalStrings_ja.properties @@ -1,13 +1,13 @@ -authenticator.alreadyStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -authenticator.certificates=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u305b\u3093 -authenticator.forbidden=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f -authenticator.formlogin=\u30d5\u30a9\u30fc\u30e0\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8\u3078\u306e\u7121\u52b9\u306a\u76f4\u63a5\u53c2\u7167\u3067\u3059 -authenticator.invalid=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u7121\u52b9\u306a\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u3059 -authenticator.keystore=\u30ad\u30fc\u30b9\u30c8\u30a2\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -authenticator.manager=\u30c8\u30e9\u30b9\u30c8\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -authenticator.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u306b\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 -authenticator.notContext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -authenticator.notStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -authenticator.sessionExpired=\u30ed\u30b0\u30a4\u30f3\u30d7\u30ed\u30bb\u30b9\u306b\u8a8d\u3081\u3089\u308c\u3066\u3044\u305f\u6642\u9593\u304c\u904e\u304e\u307e\u3057\u305f\u3002\u7d99\u7d9a\u3057\u305f\u3044\u306a\u3089\u3070\uff0c\u30d0\u30c3\u30af\u30dc\u30bf\u30f3\u30922\u5ea6\u62bc\u3057\u3066\u304b\u3089\u518d\u5ea6\u30ea\u30f3\u30af\u3092\u62bc\u3059\u304b\uff0c\u30d6\u30e9\u30a6\u30b6\u3092\u7acb\u3061\u4e0a\u3052\u76f4\u3057\u3066\u304f\u3060\u3055\u3044 -authenticator.unauthorized=\u7528\u610f\u3055\u308c\u305f\u8a3c\u660e\u66f8\u3067\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093 -authenticator.userDataConstraint=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306f\u3001\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u306e\u5236\u9650\u306b\u9055\u53cd\u3057\u3066\u3044\u307e\u3059 +authenticator.alreadyStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +authenticator.certificates=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u306f\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u305b\u3093 +authenticator.forbidden=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f +authenticator.formlogin=\u30d5\u30a9\u30fc\u30e0\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8\u3078\u306e\u7121\u52b9\u306a\u76f4\u63a5\u53c2\u7167\u3067\u3059 +authenticator.invalid=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u7121\u52b9\u306a\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u8a8d\u8a3c\u30c1\u30a7\u30fc\u30f3\u304c\u3042\u308a\u307e\u3059 +authenticator.keystore=\u30ad\u30fc\u30b9\u30c8\u30a2\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +authenticator.manager=\u30c8\u30e9\u30b9\u30c8\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +authenticator.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u306b\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u3092\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 +authenticator.notContext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +authenticator.notStarted=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +authenticator.sessionExpired=\u30ed\u30b0\u30a4\u30f3\u30d7\u30ed\u30bb\u30b9\u306b\u8a8d\u3081\u3089\u308c\u3066\u3044\u305f\u6642\u9593\u304c\u904e\u304e\u307e\u3057\u305f\u3002\u7d99\u7d9a\u3057\u305f\u3044\u306a\u3089\u3070\uff0c\u30d0\u30c3\u30af\u30dc\u30bf\u30f3\u30922\u5ea6\u62bc\u3057\u3066\u304b\u3089\u518d\u5ea6\u30ea\u30f3\u30af\u3092\u62bc\u3059\u304b\uff0c\u30d6\u30e9\u30a6\u30b6\u3092\u7acb\u3061\u4e0a\u3052\u76f4\u3057\u3066\u304f\u3060\u3055\u3044 +authenticator.unauthorized=\u7528\u610f\u3055\u308c\u305f\u8a3c\u660e\u66f8\u3067\u8a8d\u8a3c\u3067\u304d\u307e\u305b\u3093 +authenticator.userDataConstraint=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306f\u3001\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u306e\u5236\u9650\u306b\u9055\u53cd\u3057\u3066\u3044\u307e\u3059 diff --git a/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java b/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java index e98452b64..878ccd3e0 100644 --- a/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java +++ b/java/org/apache/catalina/authenticator/NonLoginAuthenticator.java @@ -1,102 +1,102 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; - - - -/** - * An Authenticator and Valve implementation that checks - * only security constraints not involving user authentication. - * - * @author Craig R. McClanahan - * @version $Revision: 303721 $ $Date: 2005-02-23 20:27:56 +0100 (mer., 23 févr. 2005) $ - */ - -public final class NonLoginAuthenticator - extends AuthenticatorBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * Descriptive information about this implementation. - */ - private static final String info = - "org.apache.catalina.authenticator.NonLoginAuthenticator/1.0"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Authenticate the user making this request, based on the specified - * login configuration. Return true if any specified - * constraint has been satisfied, or false if we have - * created a response challenge already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - public boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException { - - /* Associating this request's session with an SSO would allow - coordinated session invalidation, but should the session for - a webapp that the user didn't log into be invalidated when - another session is logged out? - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (ssoId != null) - associate(ssoId, getSession(request, true)); - */ - - if (containerLog.isDebugEnabled()) - containerLog.debug("User authentication is not required"); - return (true); - - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; + + + +/** + * An Authenticator and Valve implementation that checks + * only security constraints not involving user authentication. + * + * @author Craig R. McClanahan + * @version $Revision: 303721 $ $Date: 2005-02-23 20:27:56 +0100 (mer., 23 févr. 2005) $ + */ + +public final class NonLoginAuthenticator + extends AuthenticatorBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * Descriptive information about this implementation. + */ + private static final String info = + "org.apache.catalina.authenticator.NonLoginAuthenticator/1.0"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Authenticate the user making this request, based on the specified + * login configuration. Return true if any specified + * constraint has been satisfied, or false if we have + * created a response challenge already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + public boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException { + + /* Associating this request's session with an SSO would allow + coordinated session invalidation, but should the session for + a webapp that the user didn't log into be invalidated when + another session is logged out? + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (ssoId != null) + associate(ssoId, getSession(request, true)); + */ + + if (containerLog.isDebugEnabled()) + containerLog.debug("User authentication is not required"); + return (true); + + + } + + +} diff --git a/java/org/apache/catalina/authenticator/SSLAuthenticator.java b/java/org/apache/catalina/authenticator/SSLAuthenticator.java index 153fbf312..fc1ca3682 100644 --- a/java/org/apache/catalina/authenticator/SSLAuthenticator.java +++ b/java/org/apache/catalina/authenticator/SSLAuthenticator.java @@ -1,196 +1,196 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.security.Principal; -import java.security.cert.X509Certificate; - -import javax.servlet.http.HttpServletResponse; - -import org.apache.coyote.ActionCode; -import org.apache.catalina.Globals; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.deploy.LoginConfig; - - - -/** - * An Authenticator and Valve implementation of authentication - * that utilizes SSL certificates to identify client users. - * - * @author Craig R. McClanahan - * @version $Revision: 303721 $ $Date: 2005-02-23 20:27:56 +0100 (mer., 23 févr. 2005) $ - */ - -public class SSLAuthenticator - extends AuthenticatorBase { - - - // ------------------------------------------------------------- Properties - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.authenticator.SSLAuthenticator/1.0"; - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Authenticate the user by checking for the existence of a certificate - * chain, and optionally asking a trust manager to validate that we trust - * this user. - * - * @param request Request we are processing - * @param response Response we are creating - * @param config Login configuration describing how authentication - * should be performed - * - * @exception IOException if an input/output error occurs - */ - public boolean authenticate(Request request, - Response response, - LoginConfig config) - throws IOException { - - // Have we already authenticated someone? - Principal principal = request.getUserPrincipal(); - //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (principal != null) { - if (containerLog.isDebugEnabled()) - containerLog.debug("Already authenticated '" + principal.getName() + "'"); - // Associate the session with any existing SSO session in order - // to get coordinated session invalidation at logout - String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); - if (ssoId != null) - associate(ssoId, request.getSessionInternal(true)); - return (true); - } - - // NOTE: We don't try to reauthenticate using any existing SSO session, - // because that will only work if the original authentication was - // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type - // specified for this webapp - // - // Uncomment below to allow previous FORM or BASIC authentications - // to authenticate users for this webapp - // TODO make this a configurable attribute (in SingleSignOn??) - /* - // Is there an SSO session against which we can try to reauthenticate? - if (ssoId != null) { - if (log.isDebugEnabled()) - log.debug("SSO Id " + ssoId + " set; attempting " + - "reauthentication"); - // Try to reauthenticate using data cached by SSO. If this fails, - // either the original SSO logon was of DIGEST or SSL (which - // we can't reauthenticate ourselves because there is no - // cached username and password), or the realm denied - // the user's reauthentication for some reason. - // In either case we have to prompt the user for a logon - if (reauthenticateFromSSO(ssoId, request)) - return true; - } - */ - - // Retrieve the certificate chain for this client - if (containerLog.isDebugEnabled()) - containerLog.debug(" Looking up certificates"); - - X509Certificate certs[] = (X509Certificate[]) - request.getAttribute(Globals.CERTIFICATES_ATTR); - if ((certs == null) || (certs.length < 1)) { - request.getCoyoteRequest().action - (ActionCode.ACTION_REQ_SSL_CERTIFICATE, null); - certs = (X509Certificate[]) - request.getAttribute(Globals.CERTIFICATES_ATTR); - } - if ((certs == null) || (certs.length < 1)) { - if (containerLog.isDebugEnabled()) - containerLog.debug(" No certificates included with this request"); - response.sendError(HttpServletResponse.SC_BAD_REQUEST, - sm.getString("authenticator.certificates")); - return (false); - } - - // Authenticate the specified certificate chain - principal = context.getRealm().authenticate(certs); - if (principal == null) { - if (containerLog.isDebugEnabled()) - containerLog.debug(" Realm.authenticate() returned false"); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, - sm.getString("authenticator.unauthorized")); - return (false); - } - - // Cache the principal (if requested) and record this authentication - register(request, response, principal, Constants.CERT_METHOD, - null, null); - return (true); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Initialize the database we will be using for client verification - * and certificate validation (if any). - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - super.start(); - - } - - - /** - * Finalize the database we used for client verification and - * certificate validation (if any). - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void stop() throws LifecycleException { - - super.stop(); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.security.Principal; +import java.security.cert.X509Certificate; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.coyote.ActionCode; +import org.apache.catalina.Globals; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.LoginConfig; + + + +/** + * An Authenticator and Valve implementation of authentication + * that utilizes SSL certificates to identify client users. + * + * @author Craig R. McClanahan + * @version $Revision: 303721 $ $Date: 2005-02-23 20:27:56 +0100 (mer., 23 févr. 2005) $ + */ + +public class SSLAuthenticator + extends AuthenticatorBase { + + + // ------------------------------------------------------------- Properties + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.authenticator.SSLAuthenticator/1.0"; + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Authenticate the user by checking for the existence of a certificate + * chain, and optionally asking a trust manager to validate that we trust + * this user. + * + * @param request Request we are processing + * @param response Response we are creating + * @param config Login configuration describing how authentication + * should be performed + * + * @exception IOException if an input/output error occurs + */ + public boolean authenticate(Request request, + Response response, + LoginConfig config) + throws IOException { + + // Have we already authenticated someone? + Principal principal = request.getUserPrincipal(); + //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (principal != null) { + if (containerLog.isDebugEnabled()) + containerLog.debug("Already authenticated '" + principal.getName() + "'"); + // Associate the session with any existing SSO session in order + // to get coordinated session invalidation at logout + String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); + if (ssoId != null) + associate(ssoId, request.getSessionInternal(true)); + return (true); + } + + // NOTE: We don't try to reauthenticate using any existing SSO session, + // because that will only work if the original authentication was + // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type + // specified for this webapp + // + // Uncomment below to allow previous FORM or BASIC authentications + // to authenticate users for this webapp + // TODO make this a configurable attribute (in SingleSignOn??) + /* + // Is there an SSO session against which we can try to reauthenticate? + if (ssoId != null) { + if (log.isDebugEnabled()) + log.debug("SSO Id " + ssoId + " set; attempting " + + "reauthentication"); + // Try to reauthenticate using data cached by SSO. If this fails, + // either the original SSO logon was of DIGEST or SSL (which + // we can't reauthenticate ourselves because there is no + // cached username and password), or the realm denied + // the user's reauthentication for some reason. + // In either case we have to prompt the user for a logon + if (reauthenticateFromSSO(ssoId, request)) + return true; + } + */ + + // Retrieve the certificate chain for this client + if (containerLog.isDebugEnabled()) + containerLog.debug(" Looking up certificates"); + + X509Certificate certs[] = (X509Certificate[]) + request.getAttribute(Globals.CERTIFICATES_ATTR); + if ((certs == null) || (certs.length < 1)) { + request.getCoyoteRequest().action + (ActionCode.ACTION_REQ_SSL_CERTIFICATE, null); + certs = (X509Certificate[]) + request.getAttribute(Globals.CERTIFICATES_ATTR); + } + if ((certs == null) || (certs.length < 1)) { + if (containerLog.isDebugEnabled()) + containerLog.debug(" No certificates included with this request"); + response.sendError(HttpServletResponse.SC_BAD_REQUEST, + sm.getString("authenticator.certificates")); + return (false); + } + + // Authenticate the specified certificate chain + principal = context.getRealm().authenticate(certs); + if (principal == null) { + if (containerLog.isDebugEnabled()) + containerLog.debug(" Realm.authenticate() returned false"); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, + sm.getString("authenticator.unauthorized")); + return (false); + } + + // Cache the principal (if requested) and record this authentication + register(request, response, principal, Constants.CERT_METHOD, + null, null); + return (true); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Initialize the database we will be using for client verification + * and certificate validation (if any). + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + super.start(); + + } + + + /** + * Finalize the database we used for client verification and + * certificate validation (if any). + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void stop() throws LifecycleException { + + super.stop(); + + } + + +} diff --git a/java/org/apache/catalina/authenticator/SavedRequest.java b/java/org/apache/catalina/authenticator/SavedRequest.java index 327da8f05..13cb8ed94 100644 --- a/java/org/apache/catalina/authenticator/SavedRequest.java +++ b/java/org/apache/catalina/authenticator/SavedRequest.java @@ -1,180 +1,180 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; - -import javax.servlet.http.Cookie; - -import org.apache.tomcat.util.buf.ByteChunk; - - -/** - * Object that saves the critical information from a request so that - * form-based authentication can reproduce it once the user has been - * authenticated. - *

    - * IMPLEMENTATION NOTE - It is assumed that this object is accessed - * only from the context of a single thread, so no synchronization around - * internal collection classes is performed. - * - * @author Craig R. McClanahan - * @version $Revision: 303925 $ $Date: 2005-05-11 23:39:41 +0200 (mer., 11 mai 2005) $ - */ - -public final class SavedRequest { - - - /** - * The set of Cookies associated with this Request. - */ - private ArrayList cookies = new ArrayList(); - - public void addCookie(Cookie cookie) { - cookies.add(cookie); - } - - public Iterator getCookies() { - return (cookies.iterator()); - } - - - /** - * The set of Headers associated with this Request. Each key is a header - * name, while the value is a ArrayList containing one or more actual - * values for this header. The values are returned as an Iterator when - * you ask for them. - */ - private HashMap headers = new HashMap(); - - public void addHeader(String name, String value) { - ArrayList values = (ArrayList) headers.get(name); - if (values == null) { - values = new ArrayList(); - headers.put(name, values); - } - values.add(value); - } - - public Iterator getHeaderNames() { - return (headers.keySet().iterator()); - } - - public Iterator getHeaderValues(String name) { - ArrayList values = (ArrayList) headers.get(name); - if (values == null) - return ((new ArrayList()).iterator()); - else - return (values.iterator()); - } - - - /** - * The set of Locales associated with this Request. - */ - private ArrayList locales = new ArrayList(); - - public void addLocale(Locale locale) { - locales.add(locale); - } - - public Iterator getLocales() { - return (locales.iterator()); - } - - - /** - * The request method used on this Request. - */ - private String method = null; - - public String getMethod() { - return (this.method); - } - - public void setMethod(String method) { - this.method = method; - } - - - - /** - * The set of request parameters associated with this Request. Each - * entry is keyed by the parameter name, pointing at a String array of - * the corresponding values. - */ - private HashMap parameters = new HashMap(); - - public void addParameter(String name, String values[]) { - parameters.put(name, values); - } - - public Iterator getParameterNames() { - return (parameters.keySet().iterator()); - } - - public String[] getParameterValues(String name) { - return ((String[]) parameters.get(name)); - } - - - /** - * The query string associated with this Request. - */ - private String queryString = null; - - public String getQueryString() { - return (this.queryString); - } - - public void setQueryString(String queryString) { - this.queryString = queryString; - } - - - /** - * The request URI associated with this Request. - */ - private String requestURI = null; - - public String getRequestURI() { - return (this.requestURI); - } - - public void setRequestURI(String requestURI) { - this.requestURI = requestURI; - } - - - /** - * The body of this request. - */ - private ByteChunk body = null; - - public ByteChunk getBody() { - return (this.body); - } - - public void setBody(ByteChunk body) { - this.body = body; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; + +import javax.servlet.http.Cookie; + +import org.apache.tomcat.util.buf.ByteChunk; + + +/** + * Object that saves the critical information from a request so that + * form-based authentication can reproduce it once the user has been + * authenticated. + *

    + * IMPLEMENTATION NOTE - It is assumed that this object is accessed + * only from the context of a single thread, so no synchronization around + * internal collection classes is performed. + * + * @author Craig R. McClanahan + * @version $Revision: 303925 $ $Date: 2005-05-11 23:39:41 +0200 (mer., 11 mai 2005) $ + */ + +public final class SavedRequest { + + + /** + * The set of Cookies associated with this Request. + */ + private ArrayList cookies = new ArrayList(); + + public void addCookie(Cookie cookie) { + cookies.add(cookie); + } + + public Iterator getCookies() { + return (cookies.iterator()); + } + + + /** + * The set of Headers associated with this Request. Each key is a header + * name, while the value is a ArrayList containing one or more actual + * values for this header. The values are returned as an Iterator when + * you ask for them. + */ + private HashMap headers = new HashMap(); + + public void addHeader(String name, String value) { + ArrayList values = (ArrayList) headers.get(name); + if (values == null) { + values = new ArrayList(); + headers.put(name, values); + } + values.add(value); + } + + public Iterator getHeaderNames() { + return (headers.keySet().iterator()); + } + + public Iterator getHeaderValues(String name) { + ArrayList values = (ArrayList) headers.get(name); + if (values == null) + return ((new ArrayList()).iterator()); + else + return (values.iterator()); + } + + + /** + * The set of Locales associated with this Request. + */ + private ArrayList locales = new ArrayList(); + + public void addLocale(Locale locale) { + locales.add(locale); + } + + public Iterator getLocales() { + return (locales.iterator()); + } + + + /** + * The request method used on this Request. + */ + private String method = null; + + public String getMethod() { + return (this.method); + } + + public void setMethod(String method) { + this.method = method; + } + + + + /** + * The set of request parameters associated with this Request. Each + * entry is keyed by the parameter name, pointing at a String array of + * the corresponding values. + */ + private HashMap parameters = new HashMap(); + + public void addParameter(String name, String values[]) { + parameters.put(name, values); + } + + public Iterator getParameterNames() { + return (parameters.keySet().iterator()); + } + + public String[] getParameterValues(String name) { + return ((String[]) parameters.get(name)); + } + + + /** + * The query string associated with this Request. + */ + private String queryString = null; + + public String getQueryString() { + return (this.queryString); + } + + public void setQueryString(String queryString) { + this.queryString = queryString; + } + + + /** + * The request URI associated with this Request. + */ + private String requestURI = null; + + public String getRequestURI() { + return (this.requestURI); + } + + public void setRequestURI(String requestURI) { + this.requestURI = requestURI; + } + + + /** + * The body of this request. + */ + private ByteChunk body = null; + + public ByteChunk getBody() { + return (this.body); + } + + public void setBody(ByteChunk body) { + this.body = body; + } +} diff --git a/java/org/apache/catalina/authenticator/SingleSignOn.java b/java/org/apache/catalina/authenticator/SingleSignOn.java index b175a33b7..0263db44e 100644 --- a/java/org/apache/catalina/authenticator/SingleSignOn.java +++ b/java/org/apache/catalina/authenticator/SingleSignOn.java @@ -1,701 +1,701 @@ -/* - * Copyright 1999-2001,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.authenticator; - - -import java.io.IOException; -import java.security.Principal; -import java.util.HashMap; -import java.util.Map; - -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Realm; -import org.apache.catalina.Session; -import org.apache.catalina.SessionEvent; -import org.apache.catalina.SessionListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.valves.ValveBase; - - -/** - * A Valve that supports a "single sign on" user experience, - * where the security identity of a user who successfully authenticates to one - * web application is propogated to other web applications in the same - * security domain. For successful use, the following requirements must - * be met: - *

      - *
    • This Valve must be configured on the Container that represents a - * virtual host (typically an implementation of Host).
    • - *
    • The Realm that contains the shared user and role - * information must be configured on the same Container (or a higher - * one), and not overridden at the web application level.
    • - *
    • The web applications themselves must use one of the standard - * Authenticators found in the - * org.apache.catalina.authenticator package.
    • - *
    - * - * @author Craig R. McClanahan - * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ - */ - -public class SingleSignOn - extends ValveBase - implements Lifecycle, SessionListener { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The cache of SingleSignOnEntry instances for authenticated Principals, - * keyed by the cookie value that is used to select them. - */ - protected Map cache = new HashMap(); - - - /** - * Descriptive information about this Valve implementation. - */ - protected static String info = - "org.apache.catalina.authenticator.SingleSignOn"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - /** - * Indicates whether this valve should require a downstream Authenticator to - * reauthenticate each request, or if it itself can bind a UserPrincipal - * and AuthType object to the request. - */ - private boolean requireReauthentication = false; - - /** - * The cache of single sign on identifiers, keyed by the Session that is - * associated with them. - */ - protected Map reverse = new HashMap(); - - - /** - * The string manager for this package. - */ - protected final static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Component started flag. - */ - protected boolean started = false; - - /** - * Optional SSO cookie domain. - */ - private String cookieDomain; - - // ------------------------------------------------------------- Properties - - /** - * Returns the optional cookie domain. - * May return null. - * - * @return The cookie domain - */ - public String getCookieDomain() { - return cookieDomain; - } - /** - * Sets the domain to be used for sso cookies. - * - * @param cookieDomain cookie domain name - */ - public void setCookieDomain(String cookieDomain) { - if (cookieDomain != null && cookieDomain.trim().length() == 0) { - cookieDomain = null; - } - this.cookieDomain = cookieDomain; - } - - /** - * Gets whether each request needs to be reauthenticated (by an - * Authenticator downstream in the pipeline) to the security - * Realm, or if this Valve can itself bind security info - * to the request based on the presence of a valid SSO entry without - * rechecking with the Realmtrue if it is required that a downstream - * Authenticator reauthenticate each request before calls to - * HttpServletRequest.setUserPrincipal() - * and HttpServletRequest.setAuthType() are made; - * false if the Valve can itself make - * those calls relying on the presence of a valid SingleSignOn - * entry associated with the request. - * - * @see #setRequireReauthentication - */ - public boolean getRequireReauthentication() - { - return requireReauthentication; - } - - - /** - * Sets whether each request needs to be reauthenticated (by an - * Authenticator downstream in the pipeline) to the security - * Realm, or if this Valve can itself bind security info - * to the request, based on the presence of a valid SSO entry, without - * rechecking with the Realm - * If this property is false (the default), this - * Valve will bind a UserPrincipal and AuthType to the request - * if a valid SSO entry is associated with the request. It will not notify - * the security Realm of the incoming request. - *

    - * This property should be set to true if the overall server - * configuration requires that the Realm reauthenticate each - * request thread. An example of such a configuration would be one where - * the Realm implementation provides security for both a - * web tier and an associated EJB tier, and needs to set security - * credentials on each request thread in order to support EJB access. - *

    - * If this property is set to true, this Valve will set flags - * on the request notifying the downstream Authenticator that the request - * is associated with an SSO session. The Authenticator will then call its - * {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO} - * method to attempt to reauthenticate the request to the - * Realm, using any credentials that were cached with this - * Valve. - *

    - * The default value of this property is false, in order - * to maintain backward compatibility with previous versions of Tomcat. - * - * @param required true if it is required that a downstream - * Authenticator reauthenticate each request before calls - * to HttpServletRequest.setUserPrincipal() - * and HttpServletRequest.setAuthType() are - * made; false if the Valve can - * itself make those calls relying on the presence of a - * valid SingleSignOn entry associated with the request. - * - * @see AuthenticatorBase#reauthenticateFromSSO - */ - public void setRequireReauthentication(boolean required) - { - this.requireReauthentication = required; - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("authenticator.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("authenticator.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - } - - - // ------------------------------------------------ SessionListener Methods - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event SessionEvent that has occurred - */ - public void sessionEvent(SessionEvent event) { - - // We only care about session destroyed events - if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()) - && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) - return; - - // Look up the single session id associated with this session (if any) - Session session = event.getSession(); - if (containerLog.isDebugEnabled()) - containerLog.debug("Process session destroyed on " + session); - - String ssoId = null; - synchronized (reverse) { - ssoId = (String) reverse.get(session); - } - if (ssoId == null) - return; - - // Was the session destroyed as the result of a timeout? - // If so, we'll just remove the expired session from the - // SSO. If the session was logged out, we'll log out - // of all session associated with the SSO. - if (((session.getMaxInactiveInterval() > 0) - && (System.currentTimeMillis() - session.getLastAccessedTimeInternal() >= - session.getMaxInactiveInterval() * 1000)) - || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) { - removeSession(ssoId, session); - } else { - // The session was logged out. - // Deregister this single session id, invalidating - // associated sessions - deregister(ssoId); - } - - } - - - // ---------------------------------------------------------- Valve Methods - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Perform single-sign-on support processing for this request. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - request.removeNote(Constants.REQ_SSOID_NOTE); - - // Has a valid user already been authenticated? - if (containerLog.isDebugEnabled()) - containerLog.debug("Process request for '" + request.getRequestURI() + "'"); - if (request.getUserPrincipal() != null) { - if (containerLog.isDebugEnabled()) - containerLog.debug(" Principal '" + request.getUserPrincipal().getName() + - "' has already been authenticated"); - getNext().invoke(request, response); - return; - } - - // Check for the single sign on cookie - if (containerLog.isDebugEnabled()) - containerLog.debug(" Checking for SSO cookie"); - Cookie cookie = null; - Cookie cookies[] = request.getCookies(); - if (cookies == null) - cookies = new Cookie[0]; - for (int i = 0; i < cookies.length; i++) { - if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) { - cookie = cookies[i]; - break; - } - } - if (cookie == null) { - if (containerLog.isDebugEnabled()) - containerLog.debug(" SSO cookie is not present"); - getNext().invoke(request, response); - return; - } - - // Look up the cached Principal associated with this cookie value - if (containerLog.isDebugEnabled()) - containerLog.debug(" Checking for cached principal for " + cookie.getValue()); - SingleSignOnEntry entry = lookup(cookie.getValue()); - if (entry != null) { - if (containerLog.isDebugEnabled()) - containerLog.debug(" Found cached principal '" + - entry.getPrincipal().getName() + "' with auth type '" + - entry.getAuthType() + "'"); - request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); - // Only set security elements if reauthentication is not required - if (!getRequireReauthentication()) { - request.setAuthType(entry.getAuthType()); - request.setUserPrincipal(entry.getPrincipal()); - } - } else { - if (containerLog.isDebugEnabled()) - containerLog.debug(" No cached principal found, erasing SSO cookie"); - cookie.setMaxAge(0); - response.addCookie(cookie); - } - - // Invoke the next Valve in our pipeline - getNext().invoke(request, response); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String rendering of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SingleSignOn["); - if (container == null ) - sb.append("Container is null"); - else - sb.append(container.getName()); - sb.append("]"); - return (sb.toString()); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Associate the specified single sign on identifier with the - * specified Session. - * - * @param ssoId Single sign on identifier - * @param session Session to be associated - */ - protected void associate(String ssoId, Session session) { - - if (containerLog.isDebugEnabled()) - containerLog.debug("Associate sso id " + ssoId + " with session " + session); - - SingleSignOnEntry sso = lookup(ssoId); - if (sso != null) - sso.addSession(this, session); - synchronized (reverse) { - reverse.put(session, ssoId); - } - - } - - /** - * Deregister the specified session. If it is the last session, - * then also get rid of the single sign on identifier - * - * @param ssoId Single sign on identifier - * @param session Session to be deregistered - */ - protected void deregister(String ssoId, Session session) { - - synchronized (reverse) { - reverse.remove(session); - } - - SingleSignOnEntry sso = lookup(ssoId); - if ( sso == null ) - return; - - sso.removeSession( session ); - - // see if we are the last session, if so blow away ssoId - Session sessions[] = sso.findSessions(); - if ( sessions == null || sessions.length == 0 ) { - synchronized (cache) { - sso = (SingleSignOnEntry) cache.remove(ssoId); - } - } - - } - - - /** - * Deregister the specified single sign on identifier, and invalidate - * any associated sessions. - * - * @param ssoId Single sign on identifier to deregister - */ - protected void deregister(String ssoId) { - - if (containerLog.isDebugEnabled()) - containerLog.debug("Deregistering sso id '" + ssoId + "'"); - - // Look up and remove the corresponding SingleSignOnEntry - SingleSignOnEntry sso = null; - synchronized (cache) { - sso = (SingleSignOnEntry) cache.remove(ssoId); - } - - if (sso == null) - return; - - // Expire any associated sessions - Session sessions[] = sso.findSessions(); - for (int i = 0; i < sessions.length; i++) { - if (containerLog.isTraceEnabled()) - containerLog.trace(" Invalidating session " + sessions[i]); - // Remove from reverse cache first to avoid recursion - synchronized (reverse) { - reverse.remove(sessions[i]); - } - // Invalidate this session - sessions[i].expire(); - } - - // NOTE: Clients may still possess the old single sign on cookie, - // but it will be removed on the next request since it is no longer - // in the cache - - } - - - /** - * Attempts reauthentication to the given Realm using - * the credentials associated with the single sign-on session - * identified by argument ssoId. - *

    - * If reauthentication is successful, the Principal and - * authorization type associated with the SSO session will be bound - * to the given Request object via calls to - * {@link Request#setAuthType Request.setAuthType()} and - * {@link Request#setUserPrincipal Request.setUserPrincipal()} - *

    - * - * @param ssoId identifier of SingleSignOn session with which the - * caller is associated - * @param realm Realm implementation against which the caller is to - * be authenticated - * @param request the request that needs to be authenticated - * - * @return true if reauthentication was successful, - * false otherwise. - */ - protected boolean reauthenticate(String ssoId, Realm realm, - Request request) { - - if (ssoId == null || realm == null) - return false; - - boolean reauthenticated = false; - - SingleSignOnEntry entry = lookup(ssoId); - if (entry != null && entry.getCanReauthenticate()) { - - String username = entry.getUsername(); - if (username != null) { - Principal reauthPrincipal = - realm.authenticate(username, entry.getPassword()); - if (reauthPrincipal != null) { - reauthenticated = true; - // Bind the authorization credentials to the request - request.setAuthType(entry.getAuthType()); - request.setUserPrincipal(reauthPrincipal); - } - } - } - - return reauthenticated; - } - - - /** - * Register the specified Principal as being associated with the specified - * value for the single sign on identifier. - * - * @param ssoId Single sign on identifier to register - * @param principal Associated user principal that is identified - * @param authType Authentication type used to authenticate this - * user principal - * @param username Username used to authenticate this user - * @param password Password used to authenticate this user - */ - protected void register(String ssoId, Principal principal, String authType, - String username, String password) { - - if (containerLog.isDebugEnabled()) - containerLog.debug("Registering sso id '" + ssoId + "' for user '" + - principal.getName() + "' with auth type '" + authType + "'"); - - synchronized (cache) { - cache.put(ssoId, new SingleSignOnEntry(principal, authType, - username, password)); - } - - } - - - /** - * Updates any SingleSignOnEntry found under key - * ssoId with the given authentication data. - *

    - * The purpose of this method is to allow an SSO entry that was - * established without a username/password combination (i.e. established - * following DIGEST or CLIENT-CERT authentication) to be updated with - * a username and password if one becomes available through a subsequent - * BASIC or FORM authentication. The SSO entry will then be usable for - * reauthentication. - *

    - * NOTE: Only updates the SSO entry if a call to - * SingleSignOnEntry.getCanReauthenticate() returns - * false; otherwise, it is assumed that the SSO entry already - * has sufficient information to allow reauthentication and that no update - * is needed. - * - * @param ssoId identifier of Single sign to be updated - * @param principal the Principal returned by the latest - * call to Realm.authenticate. - * @param authType the type of authenticator used (BASIC, CLIENT-CERT, - * DIGEST or FORM) - * @param username the username (if any) used for the authentication - * @param password the password (if any) used for the authentication - */ - protected void update(String ssoId, Principal principal, String authType, - String username, String password) { - - SingleSignOnEntry sso = lookup(ssoId); - if (sso != null && !sso.getCanReauthenticate()) { - if (containerLog.isDebugEnabled()) - containerLog.debug("Update sso id " + ssoId + " to auth type " + authType); - - synchronized(sso) { - sso.updateCredentials(principal, authType, username, password); - } - - } - } - - - /** - * Look up and return the cached SingleSignOn entry associated with this - * sso id value, if there is one; otherwise return null. - * - * @param ssoId Single sign on identifier to look up - */ - protected SingleSignOnEntry lookup(String ssoId) { - - synchronized (cache) { - return ((SingleSignOnEntry) cache.get(ssoId)); - } - - } - - - /** - * Remove a single Session from a SingleSignOn. Called when - * a session is timed out and no longer active. - * - * @param ssoId Single sign on identifier from which to remove the session. - * @param session the session to be removed. - */ - protected void removeSession(String ssoId, Session session) { - - if (containerLog.isDebugEnabled()) - containerLog.debug("Removing session " + session.toString() + " from sso id " + - ssoId ); - - // Get a reference to the SingleSignOn - SingleSignOnEntry entry = lookup(ssoId); - if (entry == null) - return; - - // Remove the inactive session from SingleSignOnEntry - entry.removeSession(session); - - // Remove the inactive session from the 'reverse' Map. - synchronized(reverse) { - reverse.remove(session); - } - - // If there are not sessions left in the SingleSignOnEntry, - // deregister the entry. - if (entry.findSessions().length == 0) { - deregister(ssoId); - } - } - -} +/* + * Copyright 1999-2001,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.authenticator; + + +import java.io.IOException; +import java.security.Principal; +import java.util.HashMap; +import java.util.Map; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; + + +/** + * A Valve that supports a "single sign on" user experience, + * where the security identity of a user who successfully authenticates to one + * web application is propogated to other web applications in the same + * security domain. For successful use, the following requirements must + * be met: + *

      + *
    • This Valve must be configured on the Container that represents a + * virtual host (typically an implementation of Host).
    • + *
    • The Realm that contains the shared user and role + * information must be configured on the same Container (or a higher + * one), and not overridden at the web application level.
    • + *
    • The web applications themselves must use one of the standard + * Authenticators found in the + * org.apache.catalina.authenticator package.
    • + *
    + * + * @author Craig R. McClanahan + * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ + */ + +public class SingleSignOn + extends ValveBase + implements Lifecycle, SessionListener { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The cache of SingleSignOnEntry instances for authenticated Principals, + * keyed by the cookie value that is used to select them. + */ + protected Map cache = new HashMap(); + + + /** + * Descriptive information about this Valve implementation. + */ + protected static String info = + "org.apache.catalina.authenticator.SingleSignOn"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + /** + * Indicates whether this valve should require a downstream Authenticator to + * reauthenticate each request, or if it itself can bind a UserPrincipal + * and AuthType object to the request. + */ + private boolean requireReauthentication = false; + + /** + * The cache of single sign on identifiers, keyed by the Session that is + * associated with them. + */ + protected Map reverse = new HashMap(); + + + /** + * The string manager for this package. + */ + protected final static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Component started flag. + */ + protected boolean started = false; + + /** + * Optional SSO cookie domain. + */ + private String cookieDomain; + + // ------------------------------------------------------------- Properties + + /** + * Returns the optional cookie domain. + * May return null. + * + * @return The cookie domain + */ + public String getCookieDomain() { + return cookieDomain; + } + /** + * Sets the domain to be used for sso cookies. + * + * @param cookieDomain cookie domain name + */ + public void setCookieDomain(String cookieDomain) { + if (cookieDomain != null && cookieDomain.trim().length() == 0) { + cookieDomain = null; + } + this.cookieDomain = cookieDomain; + } + + /** + * Gets whether each request needs to be reauthenticated (by an + * Authenticator downstream in the pipeline) to the security + * Realm, or if this Valve can itself bind security info + * to the request based on the presence of a valid SSO entry without + * rechecking with the Realmtrue if it is required that a downstream + * Authenticator reauthenticate each request before calls to + * HttpServletRequest.setUserPrincipal() + * and HttpServletRequest.setAuthType() are made; + * false if the Valve can itself make + * those calls relying on the presence of a valid SingleSignOn + * entry associated with the request. + * + * @see #setRequireReauthentication + */ + public boolean getRequireReauthentication() + { + return requireReauthentication; + } + + + /** + * Sets whether each request needs to be reauthenticated (by an + * Authenticator downstream in the pipeline) to the security + * Realm, or if this Valve can itself bind security info + * to the request, based on the presence of a valid SSO entry, without + * rechecking with the Realm + * If this property is false (the default), this + * Valve will bind a UserPrincipal and AuthType to the request + * if a valid SSO entry is associated with the request. It will not notify + * the security Realm of the incoming request. + *

    + * This property should be set to true if the overall server + * configuration requires that the Realm reauthenticate each + * request thread. An example of such a configuration would be one where + * the Realm implementation provides security for both a + * web tier and an associated EJB tier, and needs to set security + * credentials on each request thread in order to support EJB access. + *

    + * If this property is set to true, this Valve will set flags + * on the request notifying the downstream Authenticator that the request + * is associated with an SSO session. The Authenticator will then call its + * {@link AuthenticatorBase#reauthenticateFromSSO reauthenticateFromSSO} + * method to attempt to reauthenticate the request to the + * Realm, using any credentials that were cached with this + * Valve. + *

    + * The default value of this property is false, in order + * to maintain backward compatibility with previous versions of Tomcat. + * + * @param required true if it is required that a downstream + * Authenticator reauthenticate each request before calls + * to HttpServletRequest.setUserPrincipal() + * and HttpServletRequest.setAuthType() are + * made; false if the Valve can + * itself make those calls relying on the presence of a + * valid SingleSignOn entry associated with the request. + * + * @see AuthenticatorBase#reauthenticateFromSSO + */ + public void setRequireReauthentication(boolean required) + { + this.requireReauthentication = required; + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("authenticator.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("authenticator.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + } + + + // ------------------------------------------------ SessionListener Methods + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event SessionEvent that has occurred + */ + public void sessionEvent(SessionEvent event) { + + // We only care about session destroyed events + if (!Session.SESSION_DESTROYED_EVENT.equals(event.getType()) + && (!Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) + return; + + // Look up the single session id associated with this session (if any) + Session session = event.getSession(); + if (containerLog.isDebugEnabled()) + containerLog.debug("Process session destroyed on " + session); + + String ssoId = null; + synchronized (reverse) { + ssoId = (String) reverse.get(session); + } + if (ssoId == null) + return; + + // Was the session destroyed as the result of a timeout? + // If so, we'll just remove the expired session from the + // SSO. If the session was logged out, we'll log out + // of all session associated with the SSO. + if (((session.getMaxInactiveInterval() > 0) + && (System.currentTimeMillis() - session.getLastAccessedTimeInternal() >= + session.getMaxInactiveInterval() * 1000)) + || (Session.SESSION_PASSIVATED_EVENT.equals(event.getType()))) { + removeSession(ssoId, session); + } else { + // The session was logged out. + // Deregister this single session id, invalidating + // associated sessions + deregister(ssoId); + } + + } + + + // ---------------------------------------------------------- Valve Methods + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Perform single-sign-on support processing for this request. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + request.removeNote(Constants.REQ_SSOID_NOTE); + + // Has a valid user already been authenticated? + if (containerLog.isDebugEnabled()) + containerLog.debug("Process request for '" + request.getRequestURI() + "'"); + if (request.getUserPrincipal() != null) { + if (containerLog.isDebugEnabled()) + containerLog.debug(" Principal '" + request.getUserPrincipal().getName() + + "' has already been authenticated"); + getNext().invoke(request, response); + return; + } + + // Check for the single sign on cookie + if (containerLog.isDebugEnabled()) + containerLog.debug(" Checking for SSO cookie"); + Cookie cookie = null; + Cookie cookies[] = request.getCookies(); + if (cookies == null) + cookies = new Cookie[0]; + for (int i = 0; i < cookies.length; i++) { + if (Constants.SINGLE_SIGN_ON_COOKIE.equals(cookies[i].getName())) { + cookie = cookies[i]; + break; + } + } + if (cookie == null) { + if (containerLog.isDebugEnabled()) + containerLog.debug(" SSO cookie is not present"); + getNext().invoke(request, response); + return; + } + + // Look up the cached Principal associated with this cookie value + if (containerLog.isDebugEnabled()) + containerLog.debug(" Checking for cached principal for " + cookie.getValue()); + SingleSignOnEntry entry = lookup(cookie.getValue()); + if (entry != null) { + if (containerLog.isDebugEnabled()) + containerLog.debug(" Found cached principal '" + + entry.getPrincipal().getName() + "' with auth type '" + + entry.getAuthType() + "'"); + request.setNote(Constants.REQ_SSOID_NOTE, cookie.getValue()); + // Only set security elements if reauthentication is not required + if (!getRequireReauthentication()) { + request.setAuthType(entry.getAuthType()); + request.setUserPrincipal(entry.getPrincipal()); + } + } else { + if (containerLog.isDebugEnabled()) + containerLog.debug(" No cached principal found, erasing SSO cookie"); + cookie.setMaxAge(0); + response.addCookie(cookie); + } + + // Invoke the next Valve in our pipeline + getNext().invoke(request, response); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String rendering of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SingleSignOn["); + if (container == null ) + sb.append("Container is null"); + else + sb.append(container.getName()); + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Associate the specified single sign on identifier with the + * specified Session. + * + * @param ssoId Single sign on identifier + * @param session Session to be associated + */ + protected void associate(String ssoId, Session session) { + + if (containerLog.isDebugEnabled()) + containerLog.debug("Associate sso id " + ssoId + " with session " + session); + + SingleSignOnEntry sso = lookup(ssoId); + if (sso != null) + sso.addSession(this, session); + synchronized (reverse) { + reverse.put(session, ssoId); + } + + } + + /** + * Deregister the specified session. If it is the last session, + * then also get rid of the single sign on identifier + * + * @param ssoId Single sign on identifier + * @param session Session to be deregistered + */ + protected void deregister(String ssoId, Session session) { + + synchronized (reverse) { + reverse.remove(session); + } + + SingleSignOnEntry sso = lookup(ssoId); + if ( sso == null ) + return; + + sso.removeSession( session ); + + // see if we are the last session, if so blow away ssoId + Session sessions[] = sso.findSessions(); + if ( sessions == null || sessions.length == 0 ) { + synchronized (cache) { + sso = (SingleSignOnEntry) cache.remove(ssoId); + } + } + + } + + + /** + * Deregister the specified single sign on identifier, and invalidate + * any associated sessions. + * + * @param ssoId Single sign on identifier to deregister + */ + protected void deregister(String ssoId) { + + if (containerLog.isDebugEnabled()) + containerLog.debug("Deregistering sso id '" + ssoId + "'"); + + // Look up and remove the corresponding SingleSignOnEntry + SingleSignOnEntry sso = null; + synchronized (cache) { + sso = (SingleSignOnEntry) cache.remove(ssoId); + } + + if (sso == null) + return; + + // Expire any associated sessions + Session sessions[] = sso.findSessions(); + for (int i = 0; i < sessions.length; i++) { + if (containerLog.isTraceEnabled()) + containerLog.trace(" Invalidating session " + sessions[i]); + // Remove from reverse cache first to avoid recursion + synchronized (reverse) { + reverse.remove(sessions[i]); + } + // Invalidate this session + sessions[i].expire(); + } + + // NOTE: Clients may still possess the old single sign on cookie, + // but it will be removed on the next request since it is no longer + // in the cache + + } + + + /** + * Attempts reauthentication to the given Realm using + * the credentials associated with the single sign-on session + * identified by argument ssoId. + *

    + * If reauthentication is successful, the Principal and + * authorization type associated with the SSO session will be bound + * to the given Request object via calls to + * {@link Request#setAuthType Request.setAuthType()} and + * {@link Request#setUserPrincipal Request.setUserPrincipal()} + *

    + * + * @param ssoId identifier of SingleSignOn session with which the + * caller is associated + * @param realm Realm implementation against which the caller is to + * be authenticated + * @param request the request that needs to be authenticated + * + * @return true if reauthentication was successful, + * false otherwise. + */ + protected boolean reauthenticate(String ssoId, Realm realm, + Request request) { + + if (ssoId == null || realm == null) + return false; + + boolean reauthenticated = false; + + SingleSignOnEntry entry = lookup(ssoId); + if (entry != null && entry.getCanReauthenticate()) { + + String username = entry.getUsername(); + if (username != null) { + Principal reauthPrincipal = + realm.authenticate(username, entry.getPassword()); + if (reauthPrincipal != null) { + reauthenticated = true; + // Bind the authorization credentials to the request + request.setAuthType(entry.getAuthType()); + request.setUserPrincipal(reauthPrincipal); + } + } + } + + return reauthenticated; + } + + + /** + * Register the specified Principal as being associated with the specified + * value for the single sign on identifier. + * + * @param ssoId Single sign on identifier to register + * @param principal Associated user principal that is identified + * @param authType Authentication type used to authenticate this + * user principal + * @param username Username used to authenticate this user + * @param password Password used to authenticate this user + */ + protected void register(String ssoId, Principal principal, String authType, + String username, String password) { + + if (containerLog.isDebugEnabled()) + containerLog.debug("Registering sso id '" + ssoId + "' for user '" + + principal.getName() + "' with auth type '" + authType + "'"); + + synchronized (cache) { + cache.put(ssoId, new SingleSignOnEntry(principal, authType, + username, password)); + } + + } + + + /** + * Updates any SingleSignOnEntry found under key + * ssoId with the given authentication data. + *

    + * The purpose of this method is to allow an SSO entry that was + * established without a username/password combination (i.e. established + * following DIGEST or CLIENT-CERT authentication) to be updated with + * a username and password if one becomes available through a subsequent + * BASIC or FORM authentication. The SSO entry will then be usable for + * reauthentication. + *

    + * NOTE: Only updates the SSO entry if a call to + * SingleSignOnEntry.getCanReauthenticate() returns + * false; otherwise, it is assumed that the SSO entry already + * has sufficient information to allow reauthentication and that no update + * is needed. + * + * @param ssoId identifier of Single sign to be updated + * @param principal the Principal returned by the latest + * call to Realm.authenticate. + * @param authType the type of authenticator used (BASIC, CLIENT-CERT, + * DIGEST or FORM) + * @param username the username (if any) used for the authentication + * @param password the password (if any) used for the authentication + */ + protected void update(String ssoId, Principal principal, String authType, + String username, String password) { + + SingleSignOnEntry sso = lookup(ssoId); + if (sso != null && !sso.getCanReauthenticate()) { + if (containerLog.isDebugEnabled()) + containerLog.debug("Update sso id " + ssoId + " to auth type " + authType); + + synchronized(sso) { + sso.updateCredentials(principal, authType, username, password); + } + + } + } + + + /** + * Look up and return the cached SingleSignOn entry associated with this + * sso id value, if there is one; otherwise return null. + * + * @param ssoId Single sign on identifier to look up + */ + protected SingleSignOnEntry lookup(String ssoId) { + + synchronized (cache) { + return ((SingleSignOnEntry) cache.get(ssoId)); + } + + } + + + /** + * Remove a single Session from a SingleSignOn. Called when + * a session is timed out and no longer active. + * + * @param ssoId Single sign on identifier from which to remove the session. + * @param session the session to be removed. + */ + protected void removeSession(String ssoId, Session session) { + + if (containerLog.isDebugEnabled()) + containerLog.debug("Removing session " + session.toString() + " from sso id " + + ssoId ); + + // Get a reference to the SingleSignOn + SingleSignOnEntry entry = lookup(ssoId); + if (entry == null) + return; + + // Remove the inactive session from SingleSignOnEntry + entry.removeSession(session); + + // Remove the inactive session from the 'reverse' Map. + synchronized(reverse) { + reverse.remove(session); + } + + // If there are not sessions left in the SingleSignOnEntry, + // deregister the entry. + if (entry.findSessions().length == 0) { + deregister(ssoId); + } + } + +} diff --git a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java index 3d7b9613d..bd1d2bb5e 100644 --- a/java/org/apache/catalina/authenticator/SingleSignOnEntry.java +++ b/java/org/apache/catalina/authenticator/SingleSignOnEntry.java @@ -1,189 +1,189 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.authenticator; - -import java.security.Principal; - -import org.apache.catalina.Session; -import org.apache.catalina.authenticator.Constants; - -/** - * A class that represents entries in the cache of authenticated users. - * This is necessary to make it available to - * AuthenticatorBase subclasses that need it in order to perform - * reauthentications when SingleSignOn is in use. - * - * @author B Stansberry, based on work by Craig R. McClanahan - * @version $Revision: 302885 $ - * - * @see SingleSignOn - * @see AuthenticatorBase#reauthenticateFromSSO - */ -public class SingleSignOnEntry -{ - // ------------------------------------------------------ Instance Fields - - protected String authType = null; - - protected String password = null; - - protected Principal principal = null; - - protected Session sessions[] = new Session[0]; - - protected String username = null; - - protected boolean canReauthenticate = false; - - // --------------------------------------------------------- Constructors - - /** - * Creates a new SingleSignOnEntry - * - * @param principal the Principal returned by the latest - * call to Realm.authenticate. - * @param authType the type of authenticator used (BASIC, CLIENT-CERT, - * DIGEST or FORM) - * @param username the username (if any) used for the authentication - * @param password the password (if any) used for the authentication - */ - public SingleSignOnEntry(Principal principal, String authType, - String username, String password) { - super(); - updateCredentials(principal, authType, username, password); - } - - public SingleSignOnEntry() { - } - - // ------------------------------------------------------- Package Methods - - /** - * Adds a Session to the list of those associated with - * this SSO. - * - * @param sso The SingleSignOn valve that is managing - * the SSO session. - * @param session The Session being associated with the SSO. - */ - public synchronized void addSession(SingleSignOn sso, Session session) { - for (int i = 0; i < sessions.length; i++) { - if (session == sessions[i]) - return; - } - Session results[] = new Session[sessions.length + 1]; - System.arraycopy(sessions, 0, results, 0, sessions.length); - results[sessions.length] = session; - sessions = results; - session.addSessionListener(sso); - } - - /** - * Removes the given Session from the list of those - * associated with this SSO. - * - * @param session the Session to remove. - */ - public synchronized void removeSession(Session session) { - Session[] nsessions = new Session[sessions.length - 1]; - for (int i = 0, j = 0; i < sessions.length; i++) { - if (session == sessions[i]) - continue; - nsessions[j++] = sessions[i]; - } - sessions = nsessions; - } - - /** - * Returns the Sessions associated with this SSO. - */ - public synchronized Session[] findSessions() { - return (this.sessions); - } - - /** - * Gets the name of the authentication type originally used to authenticate - * the user associated with the SSO. - * - * @return "BASIC", "CLIENT-CERT", "DIGEST", "FORM" or "NONE" - */ - public String getAuthType() { - return (this.authType); - } - - /** - * Gets whether the authentication type associated with the original - * authentication supports reauthentication. - * - * @return true if getAuthType returns - * "BASIC" or "FORM", false otherwise. - */ - public boolean getCanReauthenticate() { - return (this.canReauthenticate); - } - - /** - * Gets the password credential (if any) associated with the SSO. - * - * @return the password credential associated with the SSO, or - * null if the original authentication type - * does not involve a password. - */ - public String getPassword() { - return (this.password); - } - - /** - * Gets the Principal that has been authenticated by - * the SSO. - */ - public Principal getPrincipal() { - return (this.principal); - } - - /** - * Gets the username provided by the user as part of the authentication - * process. - */ - public String getUsername() { - return (this.username); - } - - - /** - * Updates the SingleSignOnEntry to reflect the latest security - * information associated with the caller. - * - * @param principal the Principal returned by the latest - * call to Realm.authenticate. - * @param authType the type of authenticator used (BASIC, CLIENT-CERT, - * DIGEST or FORM) - * @param username the username (if any) used for the authentication - * @param password the password (if any) used for the authentication - */ - public void updateCredentials(Principal principal, String authType, - String username, String password) { - - this.principal = principal; - this.authType = authType; - this.username = username; - this.password = password; - this.canReauthenticate = - (Constants.BASIC_METHOD.equals(authType) - || Constants.FORM_METHOD.equals(authType)); - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.authenticator; + +import java.security.Principal; + +import org.apache.catalina.Session; +import org.apache.catalina.authenticator.Constants; + +/** + * A class that represents entries in the cache of authenticated users. + * This is necessary to make it available to + * AuthenticatorBase subclasses that need it in order to perform + * reauthentications when SingleSignOn is in use. + * + * @author B Stansberry, based on work by Craig R. McClanahan + * @version $Revision: 302885 $ + * + * @see SingleSignOn + * @see AuthenticatorBase#reauthenticateFromSSO + */ +public class SingleSignOnEntry +{ + // ------------------------------------------------------ Instance Fields + + protected String authType = null; + + protected String password = null; + + protected Principal principal = null; + + protected Session sessions[] = new Session[0]; + + protected String username = null; + + protected boolean canReauthenticate = false; + + // --------------------------------------------------------- Constructors + + /** + * Creates a new SingleSignOnEntry + * + * @param principal the Principal returned by the latest + * call to Realm.authenticate. + * @param authType the type of authenticator used (BASIC, CLIENT-CERT, + * DIGEST or FORM) + * @param username the username (if any) used for the authentication + * @param password the password (if any) used for the authentication + */ + public SingleSignOnEntry(Principal principal, String authType, + String username, String password) { + super(); + updateCredentials(principal, authType, username, password); + } + + public SingleSignOnEntry() { + } + + // ------------------------------------------------------- Package Methods + + /** + * Adds a Session to the list of those associated with + * this SSO. + * + * @param sso The SingleSignOn valve that is managing + * the SSO session. + * @param session The Session being associated with the SSO. + */ + public synchronized void addSession(SingleSignOn sso, Session session) { + for (int i = 0; i < sessions.length; i++) { + if (session == sessions[i]) + return; + } + Session results[] = new Session[sessions.length + 1]; + System.arraycopy(sessions, 0, results, 0, sessions.length); + results[sessions.length] = session; + sessions = results; + session.addSessionListener(sso); + } + + /** + * Removes the given Session from the list of those + * associated with this SSO. + * + * @param session the Session to remove. + */ + public synchronized void removeSession(Session session) { + Session[] nsessions = new Session[sessions.length - 1]; + for (int i = 0, j = 0; i < sessions.length; i++) { + if (session == sessions[i]) + continue; + nsessions[j++] = sessions[i]; + } + sessions = nsessions; + } + + /** + * Returns the Sessions associated with this SSO. + */ + public synchronized Session[] findSessions() { + return (this.sessions); + } + + /** + * Gets the name of the authentication type originally used to authenticate + * the user associated with the SSO. + * + * @return "BASIC", "CLIENT-CERT", "DIGEST", "FORM" or "NONE" + */ + public String getAuthType() { + return (this.authType); + } + + /** + * Gets whether the authentication type associated with the original + * authentication supports reauthentication. + * + * @return true if getAuthType returns + * "BASIC" or "FORM", false otherwise. + */ + public boolean getCanReauthenticate() { + return (this.canReauthenticate); + } + + /** + * Gets the password credential (if any) associated with the SSO. + * + * @return the password credential associated with the SSO, or + * null if the original authentication type + * does not involve a password. + */ + public String getPassword() { + return (this.password); + } + + /** + * Gets the Principal that has been authenticated by + * the SSO. + */ + public Principal getPrincipal() { + return (this.principal); + } + + /** + * Gets the username provided by the user as part of the authentication + * process. + */ + public String getUsername() { + return (this.username); + } + + + /** + * Updates the SingleSignOnEntry to reflect the latest security + * information associated with the caller. + * + * @param principal the Principal returned by the latest + * call to Realm.authenticate. + * @param authType the type of authenticator used (BASIC, CLIENT-CERT, + * DIGEST or FORM) + * @param username the username (if any) used for the authentication + * @param password the password (if any) used for the authentication + */ + public void updateCredentials(Principal principal, String authType, + String username, String password) { + + this.principal = principal; + this.authType = authType; + this.username = username; + this.password = password; + this.canReauthenticate = + (Constants.BASIC_METHOD.equals(authType) + || Constants.FORM_METHOD.equals(authType)); + } + +} diff --git a/java/org/apache/catalina/authenticator/mbeans-descriptors.xml b/java/org/apache/catalina/authenticator/mbeans-descriptors.xml index 6a55b7e7d..218954ccd 100644 --- a/java/org/apache/catalina/authenticator/mbeans-descriptors.xml +++ b/java/org/apache/catalina/authenticator/mbeans-descriptors.xml @@ -1,148 +1,148 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/authenticator/package.html b/java/org/apache/catalina/authenticator/package.html index 6c554d47d..65814f258 100644 --- a/java/org/apache/catalina/authenticator/package.html +++ b/java/org/apache/catalina/authenticator/package.html @@ -1,38 +1,38 @@ - - -

    This package contains Authenticator implementations for the -various supported authentication methods (BASIC, DIGEST, and FORM). In -addition, there is a convenience base class, -AuthenticatorBase, for customized Authenticator -implementations.

    - -

    If you are using the standard context configuration class -(org.apache.catalina.startup.ContextConfig) to configure the -Authenticator associated with a particular context, you can register the Java -class to be used for each possible authentication method by modifying the -following Properties file:

    -
    -    src/share/org/apache/catalina/startup/Authenticators.properties
    -
    - -

    Each of the standard implementations extends a common base class -(AuthenticatorBase), which is configured by setting the -following JavaBeans properties (with default values in square brackets):

    -
      -
    • cache - Should we cache authenticated Principals (thus avoiding - per-request lookups in our underyling Realm) if this request - is part of an HTTP session? [true]
    • -
    • debug - Debugging detail level for this component. [0]
    • -
    - -

    The standard authentication methods that are currently provided include:

    -
      -
    • BasicAuthenticator - Implements HTTP BASIC authentication, as - described in RFC 2617.
    • -
    • DigestAuthenticator - Implements HTTP DIGEST authentication, as - described in RFC 2617.
    • -
    • FormAuthenticator - Implements FORM-BASED authentication, as - described in the Servlet API Specification, version 2.2.
    • -
    - - + + +

    This package contains Authenticator implementations for the +various supported authentication methods (BASIC, DIGEST, and FORM). In +addition, there is a convenience base class, +AuthenticatorBase, for customized Authenticator +implementations.

    + +

    If you are using the standard context configuration class +(org.apache.catalina.startup.ContextConfig) to configure the +Authenticator associated with a particular context, you can register the Java +class to be used for each possible authentication method by modifying the +following Properties file:

    +
    +    src/share/org/apache/catalina/startup/Authenticators.properties
    +
    + +

    Each of the standard implementations extends a common base class +(AuthenticatorBase), which is configured by setting the +following JavaBeans properties (with default values in square brackets):

    +
      +
    • cache - Should we cache authenticated Principals (thus avoiding + per-request lookups in our underyling Realm) if this request + is part of an HTTP session? [true]
    • +
    • debug - Debugging detail level for this component. [0]
    • +
    + +

    The standard authentication methods that are currently provided include:

    +
      +
    • BasicAuthenticator - Implements HTTP BASIC authentication, as + described in RFC 2617.
    • +
    • DigestAuthenticator - Implements HTTP DIGEST authentication, as + described in RFC 2617.
    • +
    • FormAuthenticator - Implements FORM-BASED authentication, as + described in the Servlet API Specification, version 2.2.
    • +
    + + diff --git a/java/org/apache/catalina/connector/ClientAbortException.java b/java/org/apache/catalina/connector/ClientAbortException.java index 0ed96c69d..4bfaf6c04 100644 --- a/java/org/apache/catalina/connector/ClientAbortException.java +++ b/java/org/apache/catalina/connector/ClientAbortException.java @@ -1,144 +1,144 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; - -/** - * Wrap an IOException identifying it as being caused by an abort - * of a request by a remote client. - * - * @author Glenn L. Nielsen - * @version $Revision: 304063 $ $Date: 2005-08-18 15:25:18 +0200 (jeu., 18 août 2005) $ - */ - -public final class ClientAbortException extends IOException { - - - //------------------------------------------------------------ Constructors - - - /** - * Construct a new ClientAbortException with no other information. - */ - public ClientAbortException() { - - this(null, null); - - } - - - /** - * Construct a new ClientAbortException for the specified message. - * - * @param message Message describing this exception - */ - public ClientAbortException(String message) { - - this(message, null); - - } - - - /** - * Construct a new ClientAbortException for the specified throwable. - * - * @param throwable Throwable that caused this exception - */ - public ClientAbortException(Throwable throwable) { - - this(null, throwable); - - } - - - /** - * Construct a new ClientAbortException for the specified message - * and throwable. - * - * @param message Message describing this exception - * @param throwable Throwable that caused this exception - */ - public ClientAbortException(String message, Throwable throwable) { - - super(); - this.message = message; - this.throwable = throwable; - - } - - - //------------------------------------------------------ Instance Variables - - - /** - * The error message passed to our constructor (if any) - */ - protected String message = null; - - - /** - * The underlying exception or error passed to our constructor (if any) - */ - protected Throwable throwable = null; - - - //---------------------------------------------------------- Public Methods - - - /** - * Returns the message associated with this exception, if any. - */ - public String getMessage() { - - return (message); - - } - - - /** - * Returns the cause that caused this exception, if any. - */ - public Throwable getCause() { - - return (throwable); - - } - - - /** - * Return a formatted string that describes this exception. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ClientAbortException: "); - if (message != null) { - sb.append(message); - if (throwable != null) { - sb.append(": "); - } - } - if (throwable != null) { - sb.append(throwable.toString()); - } - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; + +/** + * Wrap an IOException identifying it as being caused by an abort + * of a request by a remote client. + * + * @author Glenn L. Nielsen + * @version $Revision: 304063 $ $Date: 2005-08-18 15:25:18 +0200 (jeu., 18 août 2005) $ + */ + +public final class ClientAbortException extends IOException { + + + //------------------------------------------------------------ Constructors + + + /** + * Construct a new ClientAbortException with no other information. + */ + public ClientAbortException() { + + this(null, null); + + } + + + /** + * Construct a new ClientAbortException for the specified message. + * + * @param message Message describing this exception + */ + public ClientAbortException(String message) { + + this(message, null); + + } + + + /** + * Construct a new ClientAbortException for the specified throwable. + * + * @param throwable Throwable that caused this exception + */ + public ClientAbortException(Throwable throwable) { + + this(null, throwable); + + } + + + /** + * Construct a new ClientAbortException for the specified message + * and throwable. + * + * @param message Message describing this exception + * @param throwable Throwable that caused this exception + */ + public ClientAbortException(String message, Throwable throwable) { + + super(); + this.message = message; + this.throwable = throwable; + + } + + + //------------------------------------------------------ Instance Variables + + + /** + * The error message passed to our constructor (if any) + */ + protected String message = null; + + + /** + * The underlying exception or error passed to our constructor (if any) + */ + protected Throwable throwable = null; + + + //---------------------------------------------------------- Public Methods + + + /** + * Returns the message associated with this exception, if any. + */ + public String getMessage() { + + return (message); + + } + + + /** + * Returns the cause that caused this exception, if any. + */ + public Throwable getCause() { + + return (throwable); + + } + + + /** + * Return a formatted string that describes this exception. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ClientAbortException: "); + if (message != null) { + sb.append(message); + if (throwable != null) { + sb.append(": "); + } + } + if (throwable != null) { + sb.append(throwable.toString()); + } + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/connector/Constants.java b/java/org/apache/catalina/connector/Constants.java index 26ca62702..7f49bb9d0 100644 --- a/java/org/apache/catalina/connector/Constants.java +++ b/java/org/apache/catalina/connector/Constants.java @@ -1,48 +1,48 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - - -/** - * Static constants for this package. - */ - -public final class Constants { - - - // -------------------------------------------------------------- Constants - - - public static final String Package = "org.apache.catalina.connector"; - - public static final int DEFAULT_CONNECTION_LINGER = -1; - public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; - public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; - public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; - - public static final int PROCESSOR_IDLE = 0; - public static final int PROCESSOR_ACTIVE = 1; - - /** - * Security flag. - */ - public static final boolean SECURITY = - (System.getSecurityManager() != null); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + + +/** + * Static constants for this package. + */ + +public final class Constants { + + + // -------------------------------------------------------------- Constants + + + public static final String Package = "org.apache.catalina.connector"; + + public static final int DEFAULT_CONNECTION_LINGER = -1; + public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; + public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; + public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; + + public static final int PROCESSOR_IDLE = 0; + public static final int PROCESSOR_ACTIVE = 1; + + /** + * Security flag. + */ + public static final boolean SECURITY = + (System.getSecurityManager() != null); + + +} diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java index 6c9696b43..5fc051971 100644 --- a/java/org/apache/catalina/connector/CoyoteAdapter.java +++ b/java/org/apache/catalina/connector/CoyoteAdapter.java @@ -1,707 +1,707 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; - -import org.apache.catalina.CometProcessor; -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Wrapper; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.coyote.ActionCode; -import org.apache.coyote.Adapter; -import org.apache.tomcat.util.buf.B2CConverter; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.Cookies; -import org.apache.tomcat.util.http.ServerCookie; - - -/** - * Implementation of a request processor which delegates the processing to a - * Coyote processor. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 331249 $ $Date: 2005-11-07 10:57:55 +0100 (lun., 07 nov. 2005) $ - */ - -public class CoyoteAdapter - implements Adapter - { - private static Log log = LogFactory.getLog(CoyoteAdapter.class); - - // -------------------------------------------------------------- Constants - - - public static final int ADAPTER_NOTES = 1; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new CoyoteProcessor associated with the specified connector. - * - * @param connector CoyoteConnector that owns this processor - */ - public CoyoteAdapter(Connector connector) { - - super(); - this.connector = connector; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The CoyoteConnector with which this processor is associated. - */ - private Connector connector = null; - - - /** - * The match string for identifying a session ID parameter. - */ - private static final String match = - ";" + Globals.SESSION_PARAMETER_NAME + "="; - - - /** - * The match string for identifying a session ID parameter. - */ - private static final char[] SESSION_ID = match.toCharArray(); - - - /** - * The string manager for this package. - */ - protected StringManager sm = - StringManager.getManager(Constants.Package); - - - // -------------------------------------------------------- Adapter Methods - - - /** - * Event method. - * - * @return false to indicate an error, expected or not - */ - public boolean event(org.apache.coyote.Request req, - org.apache.coyote.Response res, boolean error) { - - Request request = (Request) req.getNote(ADAPTER_NOTES); - Response response = (Response) res.getNote(ADAPTER_NOTES); - - if (request.getWrapper() != null) { - - // Bind the context CL to the current thread - if (request.getContext().getLoader() != null ) { - Thread.currentThread().setContextClassLoader - (request.getContext().getLoader().getClassLoader()); - } - - CometProcessor servlet = null; - try { - servlet = (CometProcessor) request.getWrapper().allocate(); - } catch (Throwable t) { - log.error(sm.getString("coyoteAdapter.service"), t); - request.removeAttribute("org.apache.tomcat.comet"); - // Restore the context classloader - Thread.currentThread().setContextClassLoader - (CoyoteAdapter.class.getClassLoader()); - return false; - } - try { - if (error) { - servlet.error(request.getRequest(), response.getResponse()); - } else { - if (!servlet.read(request.getRequest(), response.getResponse())) { - error = true; - request.removeAttribute("org.apache.tomcat.comet"); - try { - servlet.error(request.getRequest(), response.getResponse()); - } catch (Throwable th) { - log.error(sm.getString("coyoteAdapter.service"), th); - } - } - } - return (!error); - } catch (Throwable t) { - if (!(t instanceof IOException)) { - log.error(sm.getString("coyoteAdapter.service"), t); - } - request.removeAttribute("org.apache.tomcat.comet"); - try { - servlet.error(request.getRequest(), response.getResponse()); - } catch (Throwable th) { - log.error(sm.getString("coyoteAdapter.service"), th); - } - return false; - } finally { - // Recycle the wrapper request and response - if (request.getAttribute("org.apache.tomcat.comet") == null) { - request.recycle(); - response.recycle(); - } - // Restore the context classloader - Thread.currentThread().setContextClassLoader - (CoyoteAdapter.class.getClassLoader()); - } - } - return true; - } - - - /** - * Service method. - */ - public void service(org.apache.coyote.Request req, - org.apache.coyote.Response res) - throws Exception { - - Request request = (Request) req.getNote(ADAPTER_NOTES); - Response response = (Response) res.getNote(ADAPTER_NOTES); - - if (request == null) { - - // Create objects - request = (Request) connector.createRequest(); - request.setCoyoteRequest(req); - response = (Response) connector.createResponse(); - response.setCoyoteResponse(res); - - // Link objects - request.setResponse(response); - response.setRequest(request); - - // Set as notes - req.setNote(ADAPTER_NOTES, request); - res.setNote(ADAPTER_NOTES, response); - - // Set query string encoding - req.getParameters().setQueryStringEncoding - (connector.getURIEncoding()); - - } - - if (connector.getXpoweredBy()) { - response.addHeader("X-Powered-By", "Servlet/2.5"); - } - - boolean comet = false; - - try { - - // Parse and set Catalina and configuration specific - // request parameters - if ( postParseRequest(req, request, res, response) ) { - // Calling the container - connector.getContainer().getPipeline().getFirst().invoke(request, response); - } - - if (request.getAttribute("org.apache.tomcat.comet") == Boolean.TRUE - && request.getWrapper().allocate() instanceof CometProcessor) { - comet = true; - } - - if (!comet) { - response.finishResponse(); - req.action( ActionCode.ACTION_POST_REQUEST , null); - } - - } catch (IOException e) { - ; - } catch (Throwable t) { - log.error(sm.getString("coyoteAdapter.service"), t); - } finally { - // Recycle the wrapper request and response - if (!comet) { - request.recycle(); - response.recycle(); - } else { - // Clear converters so that the minimum amount of memory - // is used by this processor - request.clearEncoders(); - response.clearEncoders(); - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Parse additional request parameters. - */ - protected boolean postParseRequest(org.apache.coyote.Request req, - Request request, - org.apache.coyote.Response res, - Response response) - throws Exception { - - // XXX the processor needs to set a correct scheme and port prior to this point, - // in ajp13 protocols dont make sense to get the port from the connector.. - // XXX the processor may have set a correct scheme and port prior to this point, - // in ajp13 protocols dont make sense to get the port from the connector... - // otherwise, use connector configuration - if (! req.scheme().isNull()) { - // use processor specified scheme to determine secure state - request.setSecure(req.scheme().equals("https")); - } else { - // use connector scheme and secure configuration, (defaults to - // "http" and false respectively) - req.scheme().setString(connector.getScheme()); - request.setSecure(connector.getSecure()); - } - - // FIXME: the code below doesnt belongs to here, - // this is only have sense - // in Http11, not in ajp13.. - // At this point the Host header has been processed. - // Override if the proxyPort/proxyHost are set - String proxyName = connector.getProxyName(); - int proxyPort = connector.getProxyPort(); - if (proxyPort != 0) { - req.setServerPort(proxyPort); - } - if (proxyName != null) { - req.serverName().setString(proxyName); - } - - // URI decoding - MessageBytes decodedURI = req.decodedURI(); - decodedURI.duplicate(req.requestURI()); - - if (decodedURI.getType() == MessageBytes.T_BYTES) { - // %xx decoding of the URL - try { - req.getURLDecoder().convert(decodedURI, false); - } catch (IOException ioe) { - res.setStatus(400); - res.setMessage("Invalid URI"); - throw ioe; - } - // Normalization - if (!normalize(req.decodedURI())) { - res.setStatus(400); - res.setMessage("Invalid URI"); - return false; - } - // Character decoding - convertURI(decodedURI, request); - } else { - // The URL is chars or String, and has been sent using an in-memory - // protocol handler, we have to assume the URL has been properly - // decoded already - decodedURI.toChars(); - } - - // Set the remote principal - String principal = req.getRemoteUser().toString(); - if (principal != null) { - request.setUserPrincipal(new CoyotePrincipal(principal)); - } - - // Set the authorization type - String authtype = req.getAuthType().toString(); - if (authtype != null) { - request.setAuthType(authtype); - } - - // Parse session Id - parseSessionId(req, request); - - // Remove any remaining parameters (other than session id, which has - // already been removed in parseSessionId()) from the URI, so they - // won't be considered by the mapping algorithm. - CharChunk uriCC = decodedURI.getCharChunk(); - int semicolon = uriCC.indexOf(';'); - if (semicolon > 0) { - decodedURI.setChars - (uriCC.getBuffer(), uriCC.getStart(), semicolon); - } - - // Request mapping. - MessageBytes serverName; - if (connector.getUseIPVHosts()) { - serverName = req.localName(); - if (serverName.isNull()) { - // well, they did ask for it - res.action(ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, null); - } - } else { - serverName = req.serverName(); - } - connector.getMapper().map(serverName, decodedURI, - request.getMappingData()); - request.setContext((Context) request.getMappingData().context); - request.setWrapper((Wrapper) request.getMappingData().wrapper); - - // Filter trace method - if (!connector.getAllowTrace() - && req.method().equalsIgnoreCase("TRACE")) { - Wrapper wrapper = request.getWrapper(); - String header = null; - if (wrapper != null) { - String[] methods = wrapper.getServletMethods(); - if (methods != null) { - for (int i=0; i 0) { - - // Parse session ID, and extract it from the decoded request URI - int start = uriCC.getStart(); - int end = uriCC.getEnd(); - - int sessionIdStart = start + semicolon + match.length(); - int semicolon2 = uriCC.indexOf(';', sessionIdStart); - if (semicolon2 >= 0) { - request.setRequestedSessionId - (new String(uriCC.getBuffer(), sessionIdStart, - semicolon2 - semicolon - match.length())); - } else { - request.setRequestedSessionId - (new String(uriCC.getBuffer(), sessionIdStart, - end - sessionIdStart)); - } - request.setRequestedSessionURL(true); - - // Extract session ID from request URI - ByteChunk uriBC = req.requestURI().getByteChunk(); - start = uriBC.getStart(); - end = uriBC.getEnd(); - semicolon = uriBC.indexOf(match, 0, match.length(), 0); - - if (semicolon > 0) { - sessionIdStart = start + semicolon; - semicolon2 = uriCC.indexOf - (';', start + semicolon + match.length()); - uriBC.setEnd(start + semicolon); - byte[] buf = uriBC.getBuffer(); - if (semicolon2 >= 0) { - for (int i = 0; i < end - start - semicolon2; i++) { - buf[start + semicolon + i] - = buf[start + i + semicolon2]; - } - uriBC.setBytes(buf, start, semicolon - + (end - start - semicolon2)); - } - } - - } else { - request.setRequestedSessionId(null); - request.setRequestedSessionURL(false); - } - - } - - - /** - * Parse session id in URL. - */ - protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { - - // Parse session id from cookies - Cookies serverCookies = req.getCookies(); - int count = serverCookies.getCookieCount(); - if (count <= 0) - return; - - for (int i = 0; i < count; i++) { - ServerCookie scookie = serverCookies.getCookie(i); - if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { - // Override anything requested in the URL - if (!request.isRequestedSessionIdFromCookie()) { - // Accept only the first session id cookie - convertMB(scookie.getValue()); - request.setRequestedSessionId - (scookie.getValue().toString()); - request.setRequestedSessionCookie(true); - request.setRequestedSessionURL(false); - if (log.isDebugEnabled()) - log.debug(" Requested cookie session id is " + - request.getRequestedSessionId()); - } else { - if (!request.isRequestedSessionIdValid()) { - // Replace the session id until one is valid - convertMB(scookie.getValue()); - request.setRequestedSessionId - (scookie.getValue().toString()); - } - } - } - } - - } - - - /** - * Character conversion of the URI. - */ - protected void convertURI(MessageBytes uri, Request request) - throws Exception { - - ByteChunk bc = uri.getByteChunk(); - CharChunk cc = uri.getCharChunk(); - cc.allocate(bc.getLength(), -1); - - String enc = connector.getURIEncoding(); - if (enc != null) { - B2CConverter conv = request.getURIConverter(); - try { - if (conv == null) { - conv = new B2CConverter(enc); - request.setURIConverter(conv); - } else { - conv.recycle(); - } - } catch (IOException e) { - // Ignore - log.error("Invalid URI encoding; using HTTP default"); - connector.setURIEncoding(null); - } - if (conv != null) { - try { - conv.convert(bc, cc); - uri.setChars(cc.getBuffer(), cc.getStart(), - cc.getLength()); - return; - } catch (IOException e) { - log.error("Invalid URI character encoding; trying ascii"); - cc.recycle(); - } - } - } - - // Default encoding: fast conversion - byte[] bbuf = bc.getBuffer(); - char[] cbuf = cc.getBuffer(); - int start = bc.getStart(); - for (int i = 0; i < bc.getLength(); i++) { - cbuf[i] = (char) (bbuf[i + start] & 0xff); - } - uri.setChars(cbuf, 0, bc.getLength()); - - } - - - /** - * Character conversion of the a US-ASCII MessageBytes. - */ - protected void convertMB(MessageBytes mb) { - - // This is of course only meaningful for bytes - if (mb.getType() != MessageBytes.T_BYTES) - return; - - ByteChunk bc = mb.getByteChunk(); - CharChunk cc = mb.getCharChunk(); - cc.allocate(bc.getLength(), -1); - - // Default encoding: fast conversion - byte[] bbuf = bc.getBuffer(); - char[] cbuf = cc.getBuffer(); - int start = bc.getStart(); - for (int i = 0; i < bc.getLength(); i++) { - cbuf[i] = (char) (bbuf[i + start] & 0xff); - } - mb.setChars(cbuf, 0, bc.getLength()); - - } - - - /** - * Normalize URI. - *

    - * This method normalizes "\", "//", "/./" and "/../". This method will - * return false when trying to go above the root, or if the URI contains - * a null byte. - * - * @param uriMB URI to be normalized - */ - public static boolean normalize(MessageBytes uriMB) { - - ByteChunk uriBC = uriMB.getByteChunk(); - byte[] b = uriBC.getBytes(); - int start = uriBC.getStart(); - int end = uriBC.getEnd(); - - // URL * is acceptable - if ((end - start == 1) && b[start] == (byte) '*') - return true; - - int pos = 0; - int index = 0; - - // Replace '\' with '/' - // Check for null byte - for (pos = start; pos < end; pos++) { - if (b[pos] == (byte) '\\') - b[pos] = (byte) '/'; - if (b[pos] == (byte) 0) - return false; - } - - // The URL must start with '/' - if (b[start] != (byte) '/') { - return false; - } - - // Replace "//" with "/" - for (pos = start; pos < (end - 1); pos++) { - if (b[pos] == (byte) '/') { - while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) { - copyBytes(b, pos, pos + 1, end - pos - 1); - end--; - } - } - } - - // If the URI ends with "/." or "/..", then we append an extra "/" - // Note: It is possible to extend the URI by 1 without any side effect - // as the next character is a non-significant WS. - if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) { - if ((b[end - 2] == (byte) '/') - || ((b[end - 2] == (byte) '.') - && (b[end - 3] == (byte) '/'))) { - b[end] = (byte) '/'; - end++; - } - } - - uriBC.setEnd(end); - - index = 0; - - // Resolve occurrences of "/./" in the normalized path - while (true) { - index = uriBC.indexOf("/./", 0, 3, index); - if (index < 0) - break; - copyBytes(b, start + index, start + index + 2, - end - start - index - 2); - end = end - 2; - uriBC.setEnd(end); - } - - index = 0; - - // Resolve occurrences of "/../" in the normalized path - while (true) { - index = uriBC.indexOf("/../", 0, 4, index); - if (index < 0) - break; - // Prevent from going outside our context - if (index == 0) - return false; - int index2 = -1; - for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { - if (b[pos] == (byte) '/') { - index2 = pos; - } - } - copyBytes(b, start + index2, start + index + 3, - end - start - index - 3); - end = end + index2 - index - 3; - uriBC.setEnd(end); - index = index2; - } - - uriBC.setBytes(b, start, end); - - return true; - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Copy an array of bytes to a different position. Used during - * normalization. - */ - protected static void copyBytes(byte[] b, int dest, int src, int len) { - for (int pos = 0; pos < len; pos++) { - b[pos + dest] = b[pos + src]; - } - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; + +import org.apache.catalina.CometProcessor; +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Wrapper; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.coyote.ActionCode; +import org.apache.coyote.Adapter; +import org.apache.tomcat.util.buf.B2CConverter; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.Cookies; +import org.apache.tomcat.util.http.ServerCookie; + + +/** + * Implementation of a request processor which delegates the processing to a + * Coyote processor. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 331249 $ $Date: 2005-11-07 10:57:55 +0100 (lun., 07 nov. 2005) $ + */ + +public class CoyoteAdapter + implements Adapter + { + private static Log log = LogFactory.getLog(CoyoteAdapter.class); + + // -------------------------------------------------------------- Constants + + + public static final int ADAPTER_NOTES = 1; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new CoyoteProcessor associated with the specified connector. + * + * @param connector CoyoteConnector that owns this processor + */ + public CoyoteAdapter(Connector connector) { + + super(); + this.connector = connector; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The CoyoteConnector with which this processor is associated. + */ + private Connector connector = null; + + + /** + * The match string for identifying a session ID parameter. + */ + private static final String match = + ";" + Globals.SESSION_PARAMETER_NAME + "="; + + + /** + * The match string for identifying a session ID parameter. + */ + private static final char[] SESSION_ID = match.toCharArray(); + + + /** + * The string manager for this package. + */ + protected StringManager sm = + StringManager.getManager(Constants.Package); + + + // -------------------------------------------------------- Adapter Methods + + + /** + * Event method. + * + * @return false to indicate an error, expected or not + */ + public boolean event(org.apache.coyote.Request req, + org.apache.coyote.Response res, boolean error) { + + Request request = (Request) req.getNote(ADAPTER_NOTES); + Response response = (Response) res.getNote(ADAPTER_NOTES); + + if (request.getWrapper() != null) { + + // Bind the context CL to the current thread + if (request.getContext().getLoader() != null ) { + Thread.currentThread().setContextClassLoader + (request.getContext().getLoader().getClassLoader()); + } + + CometProcessor servlet = null; + try { + servlet = (CometProcessor) request.getWrapper().allocate(); + } catch (Throwable t) { + log.error(sm.getString("coyoteAdapter.service"), t); + request.removeAttribute("org.apache.tomcat.comet"); + // Restore the context classloader + Thread.currentThread().setContextClassLoader + (CoyoteAdapter.class.getClassLoader()); + return false; + } + try { + if (error) { + servlet.error(request.getRequest(), response.getResponse()); + } else { + if (!servlet.read(request.getRequest(), response.getResponse())) { + error = true; + request.removeAttribute("org.apache.tomcat.comet"); + try { + servlet.error(request.getRequest(), response.getResponse()); + } catch (Throwable th) { + log.error(sm.getString("coyoteAdapter.service"), th); + } + } + } + return (!error); + } catch (Throwable t) { + if (!(t instanceof IOException)) { + log.error(sm.getString("coyoteAdapter.service"), t); + } + request.removeAttribute("org.apache.tomcat.comet"); + try { + servlet.error(request.getRequest(), response.getResponse()); + } catch (Throwable th) { + log.error(sm.getString("coyoteAdapter.service"), th); + } + return false; + } finally { + // Recycle the wrapper request and response + if (request.getAttribute("org.apache.tomcat.comet") == null) { + request.recycle(); + response.recycle(); + } + // Restore the context classloader + Thread.currentThread().setContextClassLoader + (CoyoteAdapter.class.getClassLoader()); + } + } + return true; + } + + + /** + * Service method. + */ + public void service(org.apache.coyote.Request req, + org.apache.coyote.Response res) + throws Exception { + + Request request = (Request) req.getNote(ADAPTER_NOTES); + Response response = (Response) res.getNote(ADAPTER_NOTES); + + if (request == null) { + + // Create objects + request = (Request) connector.createRequest(); + request.setCoyoteRequest(req); + response = (Response) connector.createResponse(); + response.setCoyoteResponse(res); + + // Link objects + request.setResponse(response); + response.setRequest(request); + + // Set as notes + req.setNote(ADAPTER_NOTES, request); + res.setNote(ADAPTER_NOTES, response); + + // Set query string encoding + req.getParameters().setQueryStringEncoding + (connector.getURIEncoding()); + + } + + if (connector.getXpoweredBy()) { + response.addHeader("X-Powered-By", "Servlet/2.5"); + } + + boolean comet = false; + + try { + + // Parse and set Catalina and configuration specific + // request parameters + if ( postParseRequest(req, request, res, response) ) { + // Calling the container + connector.getContainer().getPipeline().getFirst().invoke(request, response); + } + + if (request.getAttribute("org.apache.tomcat.comet") == Boolean.TRUE + && request.getWrapper().allocate() instanceof CometProcessor) { + comet = true; + } + + if (!comet) { + response.finishResponse(); + req.action( ActionCode.ACTION_POST_REQUEST , null); + } + + } catch (IOException e) { + ; + } catch (Throwable t) { + log.error(sm.getString("coyoteAdapter.service"), t); + } finally { + // Recycle the wrapper request and response + if (!comet) { + request.recycle(); + response.recycle(); + } else { + // Clear converters so that the minimum amount of memory + // is used by this processor + request.clearEncoders(); + response.clearEncoders(); + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Parse additional request parameters. + */ + protected boolean postParseRequest(org.apache.coyote.Request req, + Request request, + org.apache.coyote.Response res, + Response response) + throws Exception { + + // XXX the processor needs to set a correct scheme and port prior to this point, + // in ajp13 protocols dont make sense to get the port from the connector.. + // XXX the processor may have set a correct scheme and port prior to this point, + // in ajp13 protocols dont make sense to get the port from the connector... + // otherwise, use connector configuration + if (! req.scheme().isNull()) { + // use processor specified scheme to determine secure state + request.setSecure(req.scheme().equals("https")); + } else { + // use connector scheme and secure configuration, (defaults to + // "http" and false respectively) + req.scheme().setString(connector.getScheme()); + request.setSecure(connector.getSecure()); + } + + // FIXME: the code below doesnt belongs to here, + // this is only have sense + // in Http11, not in ajp13.. + // At this point the Host header has been processed. + // Override if the proxyPort/proxyHost are set + String proxyName = connector.getProxyName(); + int proxyPort = connector.getProxyPort(); + if (proxyPort != 0) { + req.setServerPort(proxyPort); + } + if (proxyName != null) { + req.serverName().setString(proxyName); + } + + // URI decoding + MessageBytes decodedURI = req.decodedURI(); + decodedURI.duplicate(req.requestURI()); + + if (decodedURI.getType() == MessageBytes.T_BYTES) { + // %xx decoding of the URL + try { + req.getURLDecoder().convert(decodedURI, false); + } catch (IOException ioe) { + res.setStatus(400); + res.setMessage("Invalid URI"); + throw ioe; + } + // Normalization + if (!normalize(req.decodedURI())) { + res.setStatus(400); + res.setMessage("Invalid URI"); + return false; + } + // Character decoding + convertURI(decodedURI, request); + } else { + // The URL is chars or String, and has been sent using an in-memory + // protocol handler, we have to assume the URL has been properly + // decoded already + decodedURI.toChars(); + } + + // Set the remote principal + String principal = req.getRemoteUser().toString(); + if (principal != null) { + request.setUserPrincipal(new CoyotePrincipal(principal)); + } + + // Set the authorization type + String authtype = req.getAuthType().toString(); + if (authtype != null) { + request.setAuthType(authtype); + } + + // Parse session Id + parseSessionId(req, request); + + // Remove any remaining parameters (other than session id, which has + // already been removed in parseSessionId()) from the URI, so they + // won't be considered by the mapping algorithm. + CharChunk uriCC = decodedURI.getCharChunk(); + int semicolon = uriCC.indexOf(';'); + if (semicolon > 0) { + decodedURI.setChars + (uriCC.getBuffer(), uriCC.getStart(), semicolon); + } + + // Request mapping. + MessageBytes serverName; + if (connector.getUseIPVHosts()) { + serverName = req.localName(); + if (serverName.isNull()) { + // well, they did ask for it + res.action(ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, null); + } + } else { + serverName = req.serverName(); + } + connector.getMapper().map(serverName, decodedURI, + request.getMappingData()); + request.setContext((Context) request.getMappingData().context); + request.setWrapper((Wrapper) request.getMappingData().wrapper); + + // Filter trace method + if (!connector.getAllowTrace() + && req.method().equalsIgnoreCase("TRACE")) { + Wrapper wrapper = request.getWrapper(); + String header = null; + if (wrapper != null) { + String[] methods = wrapper.getServletMethods(); + if (methods != null) { + for (int i=0; i 0) { + + // Parse session ID, and extract it from the decoded request URI + int start = uriCC.getStart(); + int end = uriCC.getEnd(); + + int sessionIdStart = start + semicolon + match.length(); + int semicolon2 = uriCC.indexOf(';', sessionIdStart); + if (semicolon2 >= 0) { + request.setRequestedSessionId + (new String(uriCC.getBuffer(), sessionIdStart, + semicolon2 - semicolon - match.length())); + } else { + request.setRequestedSessionId + (new String(uriCC.getBuffer(), sessionIdStart, + end - sessionIdStart)); + } + request.setRequestedSessionURL(true); + + // Extract session ID from request URI + ByteChunk uriBC = req.requestURI().getByteChunk(); + start = uriBC.getStart(); + end = uriBC.getEnd(); + semicolon = uriBC.indexOf(match, 0, match.length(), 0); + + if (semicolon > 0) { + sessionIdStart = start + semicolon; + semicolon2 = uriCC.indexOf + (';', start + semicolon + match.length()); + uriBC.setEnd(start + semicolon); + byte[] buf = uriBC.getBuffer(); + if (semicolon2 >= 0) { + for (int i = 0; i < end - start - semicolon2; i++) { + buf[start + semicolon + i] + = buf[start + i + semicolon2]; + } + uriBC.setBytes(buf, start, semicolon + + (end - start - semicolon2)); + } + } + + } else { + request.setRequestedSessionId(null); + request.setRequestedSessionURL(false); + } + + } + + + /** + * Parse session id in URL. + */ + protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { + + // Parse session id from cookies + Cookies serverCookies = req.getCookies(); + int count = serverCookies.getCookieCount(); + if (count <= 0) + return; + + for (int i = 0; i < count; i++) { + ServerCookie scookie = serverCookies.getCookie(i); + if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { + // Override anything requested in the URL + if (!request.isRequestedSessionIdFromCookie()) { + // Accept only the first session id cookie + convertMB(scookie.getValue()); + request.setRequestedSessionId + (scookie.getValue().toString()); + request.setRequestedSessionCookie(true); + request.setRequestedSessionURL(false); + if (log.isDebugEnabled()) + log.debug(" Requested cookie session id is " + + request.getRequestedSessionId()); + } else { + if (!request.isRequestedSessionIdValid()) { + // Replace the session id until one is valid + convertMB(scookie.getValue()); + request.setRequestedSessionId + (scookie.getValue().toString()); + } + } + } + } + + } + + + /** + * Character conversion of the URI. + */ + protected void convertURI(MessageBytes uri, Request request) + throws Exception { + + ByteChunk bc = uri.getByteChunk(); + CharChunk cc = uri.getCharChunk(); + cc.allocate(bc.getLength(), -1); + + String enc = connector.getURIEncoding(); + if (enc != null) { + B2CConverter conv = request.getURIConverter(); + try { + if (conv == null) { + conv = new B2CConverter(enc); + request.setURIConverter(conv); + } else { + conv.recycle(); + } + } catch (IOException e) { + // Ignore + log.error("Invalid URI encoding; using HTTP default"); + connector.setURIEncoding(null); + } + if (conv != null) { + try { + conv.convert(bc, cc); + uri.setChars(cc.getBuffer(), cc.getStart(), + cc.getLength()); + return; + } catch (IOException e) { + log.error("Invalid URI character encoding; trying ascii"); + cc.recycle(); + } + } + } + + // Default encoding: fast conversion + byte[] bbuf = bc.getBuffer(); + char[] cbuf = cc.getBuffer(); + int start = bc.getStart(); + for (int i = 0; i < bc.getLength(); i++) { + cbuf[i] = (char) (bbuf[i + start] & 0xff); + } + uri.setChars(cbuf, 0, bc.getLength()); + + } + + + /** + * Character conversion of the a US-ASCII MessageBytes. + */ + protected void convertMB(MessageBytes mb) { + + // This is of course only meaningful for bytes + if (mb.getType() != MessageBytes.T_BYTES) + return; + + ByteChunk bc = mb.getByteChunk(); + CharChunk cc = mb.getCharChunk(); + cc.allocate(bc.getLength(), -1); + + // Default encoding: fast conversion + byte[] bbuf = bc.getBuffer(); + char[] cbuf = cc.getBuffer(); + int start = bc.getStart(); + for (int i = 0; i < bc.getLength(); i++) { + cbuf[i] = (char) (bbuf[i + start] & 0xff); + } + mb.setChars(cbuf, 0, bc.getLength()); + + } + + + /** + * Normalize URI. + *

    + * This method normalizes "\", "//", "/./" and "/../". This method will + * return false when trying to go above the root, or if the URI contains + * a null byte. + * + * @param uriMB URI to be normalized + */ + public static boolean normalize(MessageBytes uriMB) { + + ByteChunk uriBC = uriMB.getByteChunk(); + byte[] b = uriBC.getBytes(); + int start = uriBC.getStart(); + int end = uriBC.getEnd(); + + // URL * is acceptable + if ((end - start == 1) && b[start] == (byte) '*') + return true; + + int pos = 0; + int index = 0; + + // Replace '\' with '/' + // Check for null byte + for (pos = start; pos < end; pos++) { + if (b[pos] == (byte) '\\') + b[pos] = (byte) '/'; + if (b[pos] == (byte) 0) + return false; + } + + // The URL must start with '/' + if (b[start] != (byte) '/') { + return false; + } + + // Replace "//" with "/" + for (pos = start; pos < (end - 1); pos++) { + if (b[pos] == (byte) '/') { + while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) { + copyBytes(b, pos, pos + 1, end - pos - 1); + end--; + } + } + } + + // If the URI ends with "/." or "/..", then we append an extra "/" + // Note: It is possible to extend the URI by 1 without any side effect + // as the next character is a non-significant WS. + if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) { + if ((b[end - 2] == (byte) '/') + || ((b[end - 2] == (byte) '.') + && (b[end - 3] == (byte) '/'))) { + b[end] = (byte) '/'; + end++; + } + } + + uriBC.setEnd(end); + + index = 0; + + // Resolve occurrences of "/./" in the normalized path + while (true) { + index = uriBC.indexOf("/./", 0, 3, index); + if (index < 0) + break; + copyBytes(b, start + index, start + index + 2, + end - start - index - 2); + end = end - 2; + uriBC.setEnd(end); + } + + index = 0; + + // Resolve occurrences of "/../" in the normalized path + while (true) { + index = uriBC.indexOf("/../", 0, 4, index); + if (index < 0) + break; + // Prevent from going outside our context + if (index == 0) + return false; + int index2 = -1; + for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { + if (b[pos] == (byte) '/') { + index2 = pos; + } + } + copyBytes(b, start + index2, start + index + 3, + end - start - index - 3); + end = end + index2 - index - 3; + uriBC.setEnd(end); + index = index2; + } + + uriBC.setBytes(b, start, end); + + return true; + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Copy an array of bytes to a different position. Used during + * normalization. + */ + protected static void copyBytes(byte[] b, int dest, int src, int len) { + for (int pos = 0; pos < len; pos++) { + b[pos + dest] = b[pos + src]; + } + } + + +} diff --git a/java/org/apache/catalina/connector/CoyoteInputStream.java b/java/org/apache/catalina/connector/CoyoteInputStream.java index a0dfeb80d..6d8ad7c68 100644 --- a/java/org/apache/catalina/connector/CoyoteInputStream.java +++ b/java/org/apache/catalina/connector/CoyoteInputStream.java @@ -1,233 +1,233 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -import javax.servlet.ServletInputStream; - -import org.apache.catalina.security.SecurityUtil; - -/** - * This class handles reading bytes. - * - * @author Remy Maucherat - * @author Jean-Francois Arcand - */ -public class CoyoteInputStream - extends ServletInputStream { - - - // ----------------------------------------------------- Instance Variables - - - protected InputBuffer ib; - - - // ----------------------------------------------------------- Constructors - - - protected CoyoteInputStream(InputBuffer ib) { - this.ib = ib; - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Clear facade. - */ - void clear() { - ib = null; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - // --------------------------------------------- ServletInputStream Methods - - - public int read() - throws IOException { - if (SecurityUtil.isPackageProtectionEnabled()){ - - try{ - Integer result = - (Integer)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - Integer integer = new Integer(ib.readByte()); - return integer; - } - - }); - return result.intValue(); - } catch(PrivilegedActionException pae){ - Exception e = pae.getException(); - if (e instanceof IOException){ - throw (IOException)e; - } else { - throw new RuntimeException(e.getMessage()); - } - } - } else { - return ib.readByte(); - } - } - - public int available() throws IOException { - - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - Integer result = - (Integer)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - Integer integer = new Integer(ib.available()); - return integer; - } - - }); - return result.intValue(); - } catch(PrivilegedActionException pae){ - Exception e = pae.getException(); - if (e instanceof IOException){ - throw (IOException)e; - } else { - throw new RuntimeException(e.getMessage()); - } - } - } else { - return ib.available(); - } - } - - public int read(final byte[] b) throws IOException { - - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - Integer result = - (Integer)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - Integer integer = - new Integer(ib.read(b, 0, b.length)); - return integer; - } - - }); - return result.intValue(); - } catch(PrivilegedActionException pae){ - Exception e = pae.getException(); - if (e instanceof IOException){ - throw (IOException)e; - } else { - throw new RuntimeException(e.getMessage()); - } - } - } else { - return ib.read(b, 0, b.length); - } - } - - - public int read(final byte[] b, final int off, final int len) - throws IOException { - - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - Integer result = - (Integer)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - Integer integer = - new Integer(ib.read(b, off, len)); - return integer; - } - - }); - return result.intValue(); - } catch(PrivilegedActionException pae){ - Exception e = pae.getException(); - if (e instanceof IOException){ - throw (IOException)e; - } else { - throw new RuntimeException(e.getMessage()); - } - } - } else { - return ib.read(b, off, len); - } - } - - - public int readLine(byte[] b, int off, int len) throws IOException { - return super.readLine(b, off, len); - } - - - /** - * Close the stream - * Since we re-cycle, we can't allow the call to super.close() - * which would permantely disable us. - */ - public void close() throws IOException { - - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - ib.close(); - return null; - } - - }); - } catch(PrivilegedActionException pae){ - Exception e = pae.getException(); - if (e instanceof IOException){ - throw (IOException)e; - } else { - throw new RuntimeException(e.getMessage()); - } - } - } else { - ib.close(); - } - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +import javax.servlet.ServletInputStream; + +import org.apache.catalina.security.SecurityUtil; + +/** + * This class handles reading bytes. + * + * @author Remy Maucherat + * @author Jean-Francois Arcand + */ +public class CoyoteInputStream + extends ServletInputStream { + + + // ----------------------------------------------------- Instance Variables + + + protected InputBuffer ib; + + + // ----------------------------------------------------------- Constructors + + + protected CoyoteInputStream(InputBuffer ib) { + this.ib = ib; + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Clear facade. + */ + void clear() { + ib = null; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + // --------------------------------------------- ServletInputStream Methods + + + public int read() + throws IOException { + if (SecurityUtil.isPackageProtectionEnabled()){ + + try{ + Integer result = + (Integer)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + Integer integer = new Integer(ib.readByte()); + return integer; + } + + }); + return result.intValue(); + } catch(PrivilegedActionException pae){ + Exception e = pae.getException(); + if (e instanceof IOException){ + throw (IOException)e; + } else { + throw new RuntimeException(e.getMessage()); + } + } + } else { + return ib.readByte(); + } + } + + public int available() throws IOException { + + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + Integer result = + (Integer)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + Integer integer = new Integer(ib.available()); + return integer; + } + + }); + return result.intValue(); + } catch(PrivilegedActionException pae){ + Exception e = pae.getException(); + if (e instanceof IOException){ + throw (IOException)e; + } else { + throw new RuntimeException(e.getMessage()); + } + } + } else { + return ib.available(); + } + } + + public int read(final byte[] b) throws IOException { + + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + Integer result = + (Integer)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + Integer integer = + new Integer(ib.read(b, 0, b.length)); + return integer; + } + + }); + return result.intValue(); + } catch(PrivilegedActionException pae){ + Exception e = pae.getException(); + if (e instanceof IOException){ + throw (IOException)e; + } else { + throw new RuntimeException(e.getMessage()); + } + } + } else { + return ib.read(b, 0, b.length); + } + } + + + public int read(final byte[] b, final int off, final int len) + throws IOException { + + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + Integer result = + (Integer)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + Integer integer = + new Integer(ib.read(b, off, len)); + return integer; + } + + }); + return result.intValue(); + } catch(PrivilegedActionException pae){ + Exception e = pae.getException(); + if (e instanceof IOException){ + throw (IOException)e; + } else { + throw new RuntimeException(e.getMessage()); + } + } + } else { + return ib.read(b, off, len); + } + } + + + public int readLine(byte[] b, int off, int len) throws IOException { + return super.readLine(b, off, len); + } + + + /** + * Close the stream + * Since we re-cycle, we can't allow the call to super.close() + * which would permantely disable us. + */ + public void close() throws IOException { + + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + ib.close(); + return null; + } + + }); + } catch(PrivilegedActionException pae){ + Exception e = pae.getException(); + if (e instanceof IOException){ + throw (IOException)e; + } else { + throw new RuntimeException(e.getMessage()); + } + } + } else { + ib.close(); + } + } + +} diff --git a/java/org/apache/catalina/connector/CoyoteOutputStream.java b/java/org/apache/catalina/connector/CoyoteOutputStream.java index e51190078..0dc4c3185 100644 --- a/java/org/apache/catalina/connector/CoyoteOutputStream.java +++ b/java/org/apache/catalina/connector/CoyoteOutputStream.java @@ -1,117 +1,117 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; - -import javax.servlet.ServletOutputStream; - -/** - * Coyote implementation of the servlet output stream. - * - * @author Costin Manolache - * @author Remy Maucherat - */ -public class CoyoteOutputStream - extends ServletOutputStream { - - - // ----------------------------------------------------- Instance Variables - - - protected OutputBuffer ob; - - - // ----------------------------------------------------------- Constructors - - - protected CoyoteOutputStream(OutputBuffer ob) { - this.ob = ob; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Clear facade. - */ - void clear() { - ob = null; - } - - - // --------------------------------------------------- OutputStream Methods - - - public void write(int i) - throws IOException { - ob.writeByte(i); - } - - - public void write(byte[] b) - throws IOException { - write(b, 0, b.length); - } - - - public void write(byte[] b, int off, int len) - throws IOException { - ob.write(b, off, len); - } - - - /** - * Will send the buffer to the client. - */ - public void flush() - throws IOException { - ob.flush(); - } - - - public void close() - throws IOException { - ob.close(); - } - - - // -------------------------------------------- ServletOutputStream Methods - - - public void print(String s) - throws IOException { - ob.write(s); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; + +import javax.servlet.ServletOutputStream; + +/** + * Coyote implementation of the servlet output stream. + * + * @author Costin Manolache + * @author Remy Maucherat + */ +public class CoyoteOutputStream + extends ServletOutputStream { + + + // ----------------------------------------------------- Instance Variables + + + protected OutputBuffer ob; + + + // ----------------------------------------------------------- Constructors + + + protected CoyoteOutputStream(OutputBuffer ob) { + this.ob = ob; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Clear facade. + */ + void clear() { + ob = null; + } + + + // --------------------------------------------------- OutputStream Methods + + + public void write(int i) + throws IOException { + ob.writeByte(i); + } + + + public void write(byte[] b) + throws IOException { + write(b, 0, b.length); + } + + + public void write(byte[] b, int off, int len) + throws IOException { + ob.write(b, off, len); + } + + + /** + * Will send the buffer to the client. + */ + public void flush() + throws IOException { + ob.flush(); + } + + + public void close() + throws IOException { + ob.close(); + } + + + // -------------------------------------------- ServletOutputStream Methods + + + public void print(String s) + throws IOException { + ob.write(s); + } + + +} + diff --git a/java/org/apache/catalina/connector/CoyotePrincipal.java b/java/org/apache/catalina/connector/CoyotePrincipal.java index 3fda99295..aca49dc3f 100644 --- a/java/org/apache/catalina/connector/CoyotePrincipal.java +++ b/java/org/apache/catalina/connector/CoyotePrincipal.java @@ -1,74 +1,74 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.security.Principal; - -/** - * Generic implementation of java.security.Principal that - * is used to represent principals authenticated at the protocol handler level. - * - * @author Remy Maucherat - * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ - */ - -public class CoyotePrincipal - implements Principal { - - - // ----------------------------------------------------------- Constructors - - - public CoyotePrincipal(String name) { - - this.name = name; - - } - - - // ------------------------------------------------------------- Properties - - - /** - * The username of the user represented by this Principal. - */ - protected String name = null; - - public String getName() { - return (this.name); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object, which exposes only - * information that should be public. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("CoyotePrincipal["); - sb.append(this.name); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.security.Principal; + +/** + * Generic implementation of java.security.Principal that + * is used to represent principals authenticated at the protocol handler level. + * + * @author Remy Maucherat + * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ + */ + +public class CoyotePrincipal + implements Principal { + + + // ----------------------------------------------------------- Constructors + + + public CoyotePrincipal(String name) { + + this.name = name; + + } + + + // ------------------------------------------------------------- Properties + + + /** + * The username of the user represented by this Principal. + */ + protected String name = null; + + public String getName() { + return (this.name); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object, which exposes only + * information that should be public. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("CoyotePrincipal["); + sb.append(this.name); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/connector/CoyoteReader.java b/java/org/apache/catalina/connector/CoyoteReader.java index a513bc590..120ddce15 100644 --- a/java/org/apache/catalina/connector/CoyoteReader.java +++ b/java/org/apache/catalina/connector/CoyoteReader.java @@ -1,207 +1,207 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.BufferedReader; -import java.io.IOException; - - -/** - * Coyote implementation of the buffred reader. - * - * @author Remy Maucherat - */ -public class CoyoteReader - extends BufferedReader { - - - // -------------------------------------------------------------- Constants - - - private static final char[] LINE_SEP = { '\r', '\n' }; - private static final int MAX_LINE_LENGTH = 4096; - - - // ----------------------------------------------------- Instance Variables - - - protected InputBuffer ib; - - - protected char[] lineBuffer = null; - - - // ----------------------------------------------------------- Constructors - - - public CoyoteReader(InputBuffer ib) { - super(ib, 1); - this.ib = ib; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Clear facade. - */ - void clear() { - ib = null; - } - - - // --------------------------------------------------------- Reader Methods - - - public void close() - throws IOException { - ib.close(); - } - - - public int read() - throws IOException { - return ib.read(); - } - - - public int read(char[] cbuf) - throws IOException { - return ib.read(cbuf, 0, cbuf.length); - } - - - public int read(char[] cbuf, int off, int len) - throws IOException { - return ib.read(cbuf, off, len); - } - - - public long skip(long n) - throws IOException { - return ib.skip(n); - } - - - public boolean ready() - throws IOException { - return ib.ready(); - } - - - public boolean markSupported() { - return true; - } - - - public void mark(int readAheadLimit) - throws IOException { - ib.mark(readAheadLimit); - } - - - public void reset() - throws IOException { - ib.reset(); - } - - - public String readLine() - throws IOException { - - if (lineBuffer == null) { - lineBuffer = new char[MAX_LINE_LENGTH]; - } - - String result = null; - - int pos = 0; - int end = -1; - int skip = -1; - StringBuffer aggregator = null; - while (end < 0) { - mark(MAX_LINE_LENGTH); - while ((pos < MAX_LINE_LENGTH) && (end < 0)) { - int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos); - if (nRead < 0) { - if (pos == 0) { - return null; - } - end = pos; - skip = pos; - } - for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) { - if (lineBuffer[i] == LINE_SEP[0]) { - end = i; - skip = i + 1; - char nextchar; - if (i == (pos + nRead - 1)) { - nextchar = (char) read(); - } else { - nextchar = lineBuffer[i+1]; - } - if (nextchar == LINE_SEP[1]) { - skip++; - } - } else if (lineBuffer[i] == LINE_SEP[1]) { - end = i; - skip = i + 1; - } - } - if (nRead > 0) { - pos += nRead; - } - } - if (end < 0) { - if (aggregator == null) { - aggregator = new StringBuffer(); - } - aggregator.append(lineBuffer); - pos = 0; - } else { - reset(); - skip(skip); - } - } - - if (aggregator == null) { - result = new String(lineBuffer, 0, end); - } else { - aggregator.append(lineBuffer, 0, end); - result = aggregator.toString(); - } - - return result; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.BufferedReader; +import java.io.IOException; + + +/** + * Coyote implementation of the buffred reader. + * + * @author Remy Maucherat + */ +public class CoyoteReader + extends BufferedReader { + + + // -------------------------------------------------------------- Constants + + + private static final char[] LINE_SEP = { '\r', '\n' }; + private static final int MAX_LINE_LENGTH = 4096; + + + // ----------------------------------------------------- Instance Variables + + + protected InputBuffer ib; + + + protected char[] lineBuffer = null; + + + // ----------------------------------------------------------- Constructors + + + public CoyoteReader(InputBuffer ib) { + super(ib, 1); + this.ib = ib; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Clear facade. + */ + void clear() { + ib = null; + } + + + // --------------------------------------------------------- Reader Methods + + + public void close() + throws IOException { + ib.close(); + } + + + public int read() + throws IOException { + return ib.read(); + } + + + public int read(char[] cbuf) + throws IOException { + return ib.read(cbuf, 0, cbuf.length); + } + + + public int read(char[] cbuf, int off, int len) + throws IOException { + return ib.read(cbuf, off, len); + } + + + public long skip(long n) + throws IOException { + return ib.skip(n); + } + + + public boolean ready() + throws IOException { + return ib.ready(); + } + + + public boolean markSupported() { + return true; + } + + + public void mark(int readAheadLimit) + throws IOException { + ib.mark(readAheadLimit); + } + + + public void reset() + throws IOException { + ib.reset(); + } + + + public String readLine() + throws IOException { + + if (lineBuffer == null) { + lineBuffer = new char[MAX_LINE_LENGTH]; + } + + String result = null; + + int pos = 0; + int end = -1; + int skip = -1; + StringBuffer aggregator = null; + while (end < 0) { + mark(MAX_LINE_LENGTH); + while ((pos < MAX_LINE_LENGTH) && (end < 0)) { + int nRead = read(lineBuffer, pos, MAX_LINE_LENGTH - pos); + if (nRead < 0) { + if (pos == 0) { + return null; + } + end = pos; + skip = pos; + } + for (int i = pos; (i < (pos + nRead)) && (end < 0); i++) { + if (lineBuffer[i] == LINE_SEP[0]) { + end = i; + skip = i + 1; + char nextchar; + if (i == (pos + nRead - 1)) { + nextchar = (char) read(); + } else { + nextchar = lineBuffer[i+1]; + } + if (nextchar == LINE_SEP[1]) { + skip++; + } + } else if (lineBuffer[i] == LINE_SEP[1]) { + end = i; + skip = i + 1; + } + } + if (nRead > 0) { + pos += nRead; + } + } + if (end < 0) { + if (aggregator == null) { + aggregator = new StringBuffer(); + } + aggregator.append(lineBuffer); + pos = 0; + } else { + reset(); + skip(skip); + } + } + + if (aggregator == null) { + result = new String(lineBuffer, 0, end); + } else { + aggregator.append(lineBuffer, 0, end); + result = aggregator.toString(); + } + + return result; + + } + + +} diff --git a/java/org/apache/catalina/connector/CoyoteWriter.java b/java/org/apache/catalina/connector/CoyoteWriter.java index 4651736cd..edd6603e6 100644 --- a/java/org/apache/catalina/connector/CoyoteWriter.java +++ b/java/org/apache/catalina/connector/CoyoteWriter.java @@ -1,288 +1,288 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; -import java.io.PrintWriter; - -/** - * Coyote implementation of the servlet writer. - * - * @author Remy Maucherat - */ -public class CoyoteWriter - extends PrintWriter { - - - // -------------------------------------------------------------- Constants - - - private static final char[] LINE_SEP = { '\r', '\n' }; - - - // ----------------------------------------------------- Instance Variables - - - protected OutputBuffer ob; - protected boolean error = false; - - - // ----------------------------------------------------------- Constructors - - - public CoyoteWriter(OutputBuffer ob) { - super(ob); - this.ob = ob; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Clear facade. - */ - void clear() { - ob = null; - } - - - /** - * Recycle. - */ - void recycle() { - error = false; - } - - - // --------------------------------------------------------- Writer Methods - - - public void flush() { - - if (error) - return; - - try { - ob.flush(); - } catch (IOException e) { - error = true; - } - - } - - - public void close() { - - // We don't close the PrintWriter - super() is not called, - // so the stream can be reused. We close ob. - try { - ob.close(); - } catch (IOException ex ) { - ; - } - error = false; - - } - - - public boolean checkError() { - flush(); - return error; - } - - - public void write(int c) { - - if (error) - return; - - try { - ob.write(c); - } catch (IOException e) { - error = true; - } - - } - - - public void write(char buf[], int off, int len) { - - if (error) - return; - - try { - ob.write(buf, off, len); - } catch (IOException e) { - error = true; - } - - } - - - public void write(char buf[]) { - write(buf, 0, buf.length); - } - - - public void write(String s, int off, int len) { - - if (error) - return; - - try { - ob.write(s, off, len); - } catch (IOException e) { - error = true; - } - - } - - - public void write(String s) { - write(s, 0, s.length()); - } - - - // ---------------------------------------------------- PrintWriter Methods - - - public void print(boolean b) { - if (b) { - write("true"); - } else { - write("false"); - } - } - - - public void print(char c) { - write(c); - } - - - public void print(int i) { - write(String.valueOf(i)); - } - - - public void print(long l) { - write(String.valueOf(l)); - } - - - public void print(float f) { - write(String.valueOf(f)); - } - - - public void print(double d) { - write(String.valueOf(d)); - } - - - public void print(char s[]) { - write(s); - } - - - public void print(String s) { - if (s == null) { - s = "null"; - } - write(s); - } - - - public void print(Object obj) { - write(String.valueOf(obj)); - } - - - public void println() { - write(LINE_SEP); - } - - - public void println(boolean b) { - print(b); - println(); - } - - - public void println(char c) { - print(c); - println(); - } - - - public void println(int i) { - print(i); - println(); - } - - - public void println(long l) { - print(l); - println(); - } - - - public void println(float f) { - print(f); - println(); - } - - - public void println(double d) { - print(d); - println(); - } - - - public void println(char c[]) { - print(c); - println(); - } - - - public void println(String s) { - print(s); - println(); - } - - - public void println(Object o) { - print(o); - println(); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; +import java.io.PrintWriter; + +/** + * Coyote implementation of the servlet writer. + * + * @author Remy Maucherat + */ +public class CoyoteWriter + extends PrintWriter { + + + // -------------------------------------------------------------- Constants + + + private static final char[] LINE_SEP = { '\r', '\n' }; + + + // ----------------------------------------------------- Instance Variables + + + protected OutputBuffer ob; + protected boolean error = false; + + + // ----------------------------------------------------------- Constructors + + + public CoyoteWriter(OutputBuffer ob) { + super(ob); + this.ob = ob; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Clear facade. + */ + void clear() { + ob = null; + } + + + /** + * Recycle. + */ + void recycle() { + error = false; + } + + + // --------------------------------------------------------- Writer Methods + + + public void flush() { + + if (error) + return; + + try { + ob.flush(); + } catch (IOException e) { + error = true; + } + + } + + + public void close() { + + // We don't close the PrintWriter - super() is not called, + // so the stream can be reused. We close ob. + try { + ob.close(); + } catch (IOException ex ) { + ; + } + error = false; + + } + + + public boolean checkError() { + flush(); + return error; + } + + + public void write(int c) { + + if (error) + return; + + try { + ob.write(c); + } catch (IOException e) { + error = true; + } + + } + + + public void write(char buf[], int off, int len) { + + if (error) + return; + + try { + ob.write(buf, off, len); + } catch (IOException e) { + error = true; + } + + } + + + public void write(char buf[]) { + write(buf, 0, buf.length); + } + + + public void write(String s, int off, int len) { + + if (error) + return; + + try { + ob.write(s, off, len); + } catch (IOException e) { + error = true; + } + + } + + + public void write(String s) { + write(s, 0, s.length()); + } + + + // ---------------------------------------------------- PrintWriter Methods + + + public void print(boolean b) { + if (b) { + write("true"); + } else { + write("false"); + } + } + + + public void print(char c) { + write(c); + } + + + public void print(int i) { + write(String.valueOf(i)); + } + + + public void print(long l) { + write(String.valueOf(l)); + } + + + public void print(float f) { + write(String.valueOf(f)); + } + + + public void print(double d) { + write(String.valueOf(d)); + } + + + public void print(char s[]) { + write(s); + } + + + public void print(String s) { + if (s == null) { + s = "null"; + } + write(s); + } + + + public void print(Object obj) { + write(String.valueOf(obj)); + } + + + public void println() { + write(LINE_SEP); + } + + + public void println(boolean b) { + print(b); + println(); + } + + + public void println(char c) { + print(c); + println(); + } + + + public void println(int i) { + print(i); + println(); + } + + + public void println(long l) { + print(l); + println(); + } + + + public void println(float f) { + print(f); + println(); + } + + + public void println(double d) { + print(d); + println(); + } + + + public void println(char c[]) { + print(c); + println(); + } + + + public void println(String s) { + print(s); + println(); + } + + + public void println(Object o) { + print(o); + println(); + } + + +} diff --git a/java/org/apache/catalina/connector/InputBuffer.java b/java/org/apache/catalina/connector/InputBuffer.java index b02c61374..ef0941a8c 100644 --- a/java/org/apache/catalina/connector/InputBuffer.java +++ b/java/org/apache/catalina/connector/InputBuffer.java @@ -1,505 +1,505 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.connector; - -import java.io.IOException; -import java.io.Reader; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.HashMap; - -import org.apache.catalina.security.SecurityUtil; -import org.apache.coyote.Request; -import org.apache.tomcat.util.buf.B2CConverter; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; - - -/** - * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3 - * OutputBuffer, adapted to handle input instead of output. This allows - * complete recycling of the facade objects (the ServletInputStream and the - * BufferedReader). - * - * @author Remy Maucherat - */ -public class InputBuffer extends Reader - implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel, - CharChunk.CharOutputChannel { - - - // -------------------------------------------------------------- Constants - - - public static final String DEFAULT_ENCODING = - org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; - public static final int DEFAULT_BUFFER_SIZE = 8*1024; - - // The buffer can be used for byte[] and char[] reading - // ( this is needed to support ServletInputStream and BufferedReader ) - public final int INITIAL_STATE = 0; - public final int CHAR_STATE = 1; - public final int BYTE_STATE = 2; - - - // ----------------------------------------------------- Instance Variables - - - /** - * The byte buffer. - */ - private ByteChunk bb; - - - /** - * The chunk buffer. - */ - private CharChunk cb; - - - /** - * State of the output buffer. - */ - private int state = 0; - - - /** - * Number of bytes read. - */ - private int bytesRead = 0; - - - /** - * Number of chars read. - */ - private int charsRead = 0; - - - /** - * Flag which indicates if the input buffer is closed. - */ - private boolean closed = false; - - - /** - * Byte chunk used to input bytes. - */ - private ByteChunk inputChunk = new ByteChunk(); - - - /** - * Encoding to use. - */ - private String enc; - - - /** - * Encoder is set. - */ - private boolean gotEnc = false; - - - /** - * List of encoders. - */ - protected HashMap encoders = new HashMap(); - - - /** - * Current byte to char converter. - */ - protected B2CConverter conv; - - - /** - * Associated Coyote request. - */ - private Request coyoteRequest; - - - /** - * Buffer position. - */ - private int markPos = -1; - - - /** - * Buffer size. - */ - private int size = -1; - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. Allocate the buffer with the default buffer size. - */ - public InputBuffer() { - - this(DEFAULT_BUFFER_SIZE); - - } - - - /** - * Alternate constructor which allows specifying the initial buffer size. - * - * @param size Buffer size to use - */ - public InputBuffer(int size) { - - this.size = size; - bb = new ByteChunk(size); - bb.setLimit(size); - bb.setByteInputChannel(this); - cb = new CharChunk(size); - cb.setLimit(size); - cb.setOptimizedWrite(false); - cb.setCharInputChannel(this); - cb.setCharOutputChannel(this); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * Associated Coyote request. - * - * @param coyoteRequest Associated Coyote request - */ - public void setRequest(Request coyoteRequest) { - this.coyoteRequest = coyoteRequest; - } - - - /** - * Get associated Coyote request. - * - * @return the associated Coyote request - */ - public Request getRequest() { - return this.coyoteRequest; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Recycle the output buffer. - */ - public void recycle() { - - state = INITIAL_STATE; - bytesRead = 0; - charsRead = 0; - - // If usage of mark made the buffer too big, reallocate it - if (cb.getChars().length > size) { - cb = new CharChunk(size); - cb.setLimit(size); - cb.setOptimizedWrite(false); - cb.setCharInputChannel(this); - cb.setCharOutputChannel(this); - } else { - cb.recycle(); - } - markPos = -1; - bb.recycle(); - closed = false; - - if (conv != null) { - conv.recycle(); - } - - gotEnc = false; - enc = null; - - } - - - /** - * Clear cached encoders (to save memory for Comet requests). - */ - public void clearEncoders() { - encoders.clear(); - } - - - /** - * Close the input buffer. - * - * @throws IOException An underlying IOException occurred - */ - public void close() - throws IOException { - closed = true; - } - - - public int available() - throws IOException { - if (state == BYTE_STATE) { - return bb.getLength(); - } else if (state == CHAR_STATE) { - return cb.getLength(); - } else { - return 0; - } - } - - - // ------------------------------------------------- Bytes Handling Methods - - - /** - * Reads new bytes in the byte chunk. - * - * @param cbuf Byte buffer to be written to the response - * @param off Offset - * @param len Length - * - * @throws IOException An underlying IOException occurred - */ - public int realReadBytes(byte cbuf[], int off, int len) - throws IOException { - - if (closed) - return -1; - if (coyoteRequest == null) - return -1; - - state = BYTE_STATE; - - int result = coyoteRequest.doRead(bb); - - return result; - - } - - - public int readByte() - throws IOException { - return bb.substract(); - } - - - public int read(byte[] b, int off, int len) - throws IOException { - return bb.substract(b, off, len); - } - - - // ------------------------------------------------- Chars Handling Methods - - - /** - * Since the converter will use append, it is possible to get chars to - * be removed from the buffer for "writing". Since the chars have already - * been read before, they are ignored. If a mark was set, then the - * mark is lost. - */ - public void realWriteChars(char c[], int off, int len) - throws IOException { - markPos = -1; - } - - - public void setEncoding(String s) { - enc = s; - } - - - public int realReadChars(char cbuf[], int off, int len) - throws IOException { - - if (!gotEnc) - setConverter(); - - if (bb.getLength() <= 0) { - int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length); - if (nRead < 0) { - return -1; - } - } - - if (markPos == -1) { - cb.setOffset(0); - cb.setEnd(0); - } - - int limit = bb.getLength()+cb.getStart(); - if( cb.getLimit() < limit ) - cb.setLimit(limit); - conv.convert(bb, cb); - bb.setOffset(bb.getEnd()); - state = CHAR_STATE; - - return cb.getLength(); - - } - - - public int read() - throws IOException { - return cb.substract(); - } - - - public int read(char[] cbuf) - throws IOException { - return read(cbuf, 0, cbuf.length); - } - - - public int read(char[] cbuf, int off, int len) - throws IOException { - return cb.substract(cbuf, off, len); - } - - - public long skip(long n) - throws IOException { - - if (n < 0) { - throw new IllegalArgumentException(); - } - - long nRead = 0; - while (nRead < n) { - if (cb.getLength() >= n) { - cb.setOffset(cb.getStart() + (int) n); - nRead = n; - } else { - nRead += cb.getLength(); - cb.setOffset(cb.getEnd()); - int toRead = 0; - if (cb.getChars().length < (n - nRead)) { - toRead = cb.getChars().length; - } else { - toRead = (int) (n - nRead); - } - int nb = realReadChars(cb.getChars(), 0, toRead); - if (nb < 0) - break; - } - } - - return nRead; - - } - - - public boolean ready() - throws IOException { - return (cb.getLength() > 0); - } - - - public boolean markSupported() { - return true; - } - - - public void mark(int readAheadLimit) - throws IOException { - if (cb.getLength() <= 0) { - cb.setOffset(0); - cb.setEnd(0); - } else { - if ((cb.getBuffer().length > (2 * size)) - && (cb.getLength()) < (cb.getStart())) { - System.arraycopy(cb.getBuffer(), cb.getStart(), - cb.getBuffer(), 0, cb.getLength()); - cb.setEnd(cb.getLength()); - cb.setOffset(0); - } - } - int offset = readAheadLimit; - if (offset < size) { - offset = size; - } - cb.setLimit(cb.getStart() + offset); - markPos = cb.getStart(); - } - - - public void reset() - throws IOException { - if (state == CHAR_STATE) { - if (markPos < 0) { - cb.recycle(); - markPos = -1; - throw new IOException(); - } else { - cb.setOffset(markPos); - } - } else { - bb.recycle(); - } - } - - - public void checkConverter() - throws IOException { - - if (!gotEnc) - setConverter(); - - } - - - protected void setConverter() - throws IOException { - - if (coyoteRequest != null) - enc = coyoteRequest.getCharacterEncoding(); - - gotEnc = true; - if (enc == null) - enc = DEFAULT_ENCODING; - conv = (B2CConverter) encoders.get(enc); - if (conv == null) { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - conv = (B2CConverter)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - return new B2CConverter(enc); - } - - } - ); - }catch(PrivilegedActionException ex){ - Exception e = ex.getException(); - if (e instanceof IOException) - throw (IOException)e; - } - } else { - conv = new B2CConverter(enc); - } - encoders.put(enc, conv); - } - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.connector; + +import java.io.IOException; +import java.io.Reader; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; + +import org.apache.catalina.security.SecurityUtil; +import org.apache.coyote.Request; +import org.apache.tomcat.util.buf.B2CConverter; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; + + +/** + * The buffer used by Tomcat request. This is a derivative of the Tomcat 3.3 + * OutputBuffer, adapted to handle input instead of output. This allows + * complete recycling of the facade objects (the ServletInputStream and the + * BufferedReader). + * + * @author Remy Maucherat + */ +public class InputBuffer extends Reader + implements ByteChunk.ByteInputChannel, CharChunk.CharInputChannel, + CharChunk.CharOutputChannel { + + + // -------------------------------------------------------------- Constants + + + public static final String DEFAULT_ENCODING = + org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; + public static final int DEFAULT_BUFFER_SIZE = 8*1024; + + // The buffer can be used for byte[] and char[] reading + // ( this is needed to support ServletInputStream and BufferedReader ) + public final int INITIAL_STATE = 0; + public final int CHAR_STATE = 1; + public final int BYTE_STATE = 2; + + + // ----------------------------------------------------- Instance Variables + + + /** + * The byte buffer. + */ + private ByteChunk bb; + + + /** + * The chunk buffer. + */ + private CharChunk cb; + + + /** + * State of the output buffer. + */ + private int state = 0; + + + /** + * Number of bytes read. + */ + private int bytesRead = 0; + + + /** + * Number of chars read. + */ + private int charsRead = 0; + + + /** + * Flag which indicates if the input buffer is closed. + */ + private boolean closed = false; + + + /** + * Byte chunk used to input bytes. + */ + private ByteChunk inputChunk = new ByteChunk(); + + + /** + * Encoding to use. + */ + private String enc; + + + /** + * Encoder is set. + */ + private boolean gotEnc = false; + + + /** + * List of encoders. + */ + protected HashMap encoders = new HashMap(); + + + /** + * Current byte to char converter. + */ + protected B2CConverter conv; + + + /** + * Associated Coyote request. + */ + private Request coyoteRequest; + + + /** + * Buffer position. + */ + private int markPos = -1; + + + /** + * Buffer size. + */ + private int size = -1; + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Allocate the buffer with the default buffer size. + */ + public InputBuffer() { + + this(DEFAULT_BUFFER_SIZE); + + } + + + /** + * Alternate constructor which allows specifying the initial buffer size. + * + * @param size Buffer size to use + */ + public InputBuffer(int size) { + + this.size = size; + bb = new ByteChunk(size); + bb.setLimit(size); + bb.setByteInputChannel(this); + cb = new CharChunk(size); + cb.setLimit(size); + cb.setOptimizedWrite(false); + cb.setCharInputChannel(this); + cb.setCharOutputChannel(this); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * Associated Coyote request. + * + * @param coyoteRequest Associated Coyote request + */ + public void setRequest(Request coyoteRequest) { + this.coyoteRequest = coyoteRequest; + } + + + /** + * Get associated Coyote request. + * + * @return the associated Coyote request + */ + public Request getRequest() { + return this.coyoteRequest; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the output buffer. + */ + public void recycle() { + + state = INITIAL_STATE; + bytesRead = 0; + charsRead = 0; + + // If usage of mark made the buffer too big, reallocate it + if (cb.getChars().length > size) { + cb = new CharChunk(size); + cb.setLimit(size); + cb.setOptimizedWrite(false); + cb.setCharInputChannel(this); + cb.setCharOutputChannel(this); + } else { + cb.recycle(); + } + markPos = -1; + bb.recycle(); + closed = false; + + if (conv != null) { + conv.recycle(); + } + + gotEnc = false; + enc = null; + + } + + + /** + * Clear cached encoders (to save memory for Comet requests). + */ + public void clearEncoders() { + encoders.clear(); + } + + + /** + * Close the input buffer. + * + * @throws IOException An underlying IOException occurred + */ + public void close() + throws IOException { + closed = true; + } + + + public int available() + throws IOException { + if (state == BYTE_STATE) { + return bb.getLength(); + } else if (state == CHAR_STATE) { + return cb.getLength(); + } else { + return 0; + } + } + + + // ------------------------------------------------- Bytes Handling Methods + + + /** + * Reads new bytes in the byte chunk. + * + * @param cbuf Byte buffer to be written to the response + * @param off Offset + * @param len Length + * + * @throws IOException An underlying IOException occurred + */ + public int realReadBytes(byte cbuf[], int off, int len) + throws IOException { + + if (closed) + return -1; + if (coyoteRequest == null) + return -1; + + state = BYTE_STATE; + + int result = coyoteRequest.doRead(bb); + + return result; + + } + + + public int readByte() + throws IOException { + return bb.substract(); + } + + + public int read(byte[] b, int off, int len) + throws IOException { + return bb.substract(b, off, len); + } + + + // ------------------------------------------------- Chars Handling Methods + + + /** + * Since the converter will use append, it is possible to get chars to + * be removed from the buffer for "writing". Since the chars have already + * been read before, they are ignored. If a mark was set, then the + * mark is lost. + */ + public void realWriteChars(char c[], int off, int len) + throws IOException { + markPos = -1; + } + + + public void setEncoding(String s) { + enc = s; + } + + + public int realReadChars(char cbuf[], int off, int len) + throws IOException { + + if (!gotEnc) + setConverter(); + + if (bb.getLength() <= 0) { + int nRead = realReadBytes(bb.getBytes(), 0, bb.getBytes().length); + if (nRead < 0) { + return -1; + } + } + + if (markPos == -1) { + cb.setOffset(0); + cb.setEnd(0); + } + + int limit = bb.getLength()+cb.getStart(); + if( cb.getLimit() < limit ) + cb.setLimit(limit); + conv.convert(bb, cb); + bb.setOffset(bb.getEnd()); + state = CHAR_STATE; + + return cb.getLength(); + + } + + + public int read() + throws IOException { + return cb.substract(); + } + + + public int read(char[] cbuf) + throws IOException { + return read(cbuf, 0, cbuf.length); + } + + + public int read(char[] cbuf, int off, int len) + throws IOException { + return cb.substract(cbuf, off, len); + } + + + public long skip(long n) + throws IOException { + + if (n < 0) { + throw new IllegalArgumentException(); + } + + long nRead = 0; + while (nRead < n) { + if (cb.getLength() >= n) { + cb.setOffset(cb.getStart() + (int) n); + nRead = n; + } else { + nRead += cb.getLength(); + cb.setOffset(cb.getEnd()); + int toRead = 0; + if (cb.getChars().length < (n - nRead)) { + toRead = cb.getChars().length; + } else { + toRead = (int) (n - nRead); + } + int nb = realReadChars(cb.getChars(), 0, toRead); + if (nb < 0) + break; + } + } + + return nRead; + + } + + + public boolean ready() + throws IOException { + return (cb.getLength() > 0); + } + + + public boolean markSupported() { + return true; + } + + + public void mark(int readAheadLimit) + throws IOException { + if (cb.getLength() <= 0) { + cb.setOffset(0); + cb.setEnd(0); + } else { + if ((cb.getBuffer().length > (2 * size)) + && (cb.getLength()) < (cb.getStart())) { + System.arraycopy(cb.getBuffer(), cb.getStart(), + cb.getBuffer(), 0, cb.getLength()); + cb.setEnd(cb.getLength()); + cb.setOffset(0); + } + } + int offset = readAheadLimit; + if (offset < size) { + offset = size; + } + cb.setLimit(cb.getStart() + offset); + markPos = cb.getStart(); + } + + + public void reset() + throws IOException { + if (state == CHAR_STATE) { + if (markPos < 0) { + cb.recycle(); + markPos = -1; + throw new IOException(); + } else { + cb.setOffset(markPos); + } + } else { + bb.recycle(); + } + } + + + public void checkConverter() + throws IOException { + + if (!gotEnc) + setConverter(); + + } + + + protected void setConverter() + throws IOException { + + if (coyoteRequest != null) + enc = coyoteRequest.getCharacterEncoding(); + + gotEnc = true; + if (enc == null) + enc = DEFAULT_ENCODING; + conv = (B2CConverter) encoders.get(enc); + if (conv == null) { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + conv = (B2CConverter)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + return new B2CConverter(enc); + } + + } + ); + }catch(PrivilegedActionException ex){ + Exception e = ex.getException(); + if (e instanceof IOException) + throw (IOException)e; + } + } else { + conv = new B2CConverter(enc); + } + encoders.put(enc, conv); + } + + } + +} diff --git a/java/org/apache/catalina/connector/LocalStrings.properties b/java/org/apache/catalina/connector/LocalStrings.properties index 10c46cf79..a85f68848 100644 --- a/java/org/apache/catalina/connector/LocalStrings.properties +++ b/java/org/apache/catalina/connector/LocalStrings.properties @@ -1,64 +1,64 @@ - -# -# CoyoteConnector -# - -coyoteConnector.alreadyInitialized=The connector has already been initialized -coyoteConnector.alreadyStarted=The connector has already been started -coyoteConnector.cannotRegisterProtocol=Cannot register MBean for the Protocol -coyoteConnector.notStarted=Coyote connector has not been started -coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0} -coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0} -coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0} -coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0} -coyoteConnector.protocolRegistrationFailed=Protocol JMX registration failed -coyoteConnector.protocolHandlerPauseFailed=Protocol handler pause failed -coyoteConnector.protocolHandlerResumeFailed=Protocol handler resume failed -coyoteConnector.MapperRegistration=register Mapper: {0} -coyoteConnector.protocolUnregistrationFailed=Protocol handler stop failed - - -# -# CoyoteAdapter -# - -coyoteAdapter.service=An exception or error occurred in the container during the request processing - -# -# CoyoteResponse -# - -coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response -coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response -coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed -coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed -coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed -coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written - -# -# CoyoteRequest -# - -coyoteRequest.getInputStream.ise=getReader() has already been called for this request -coyoteRequest.getReader.ise=getInputStream() has already been called for this request -coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed -coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name -coyoteRequest.listenerStart=Exception sending context initialized event to listener instance of class {0} -coyoteRequest.listenerStop=Exception sending context destroyed event to listener instance of class {0} -coyoteRequest.attributeEvent=Exception thrown by attributes event listener -coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs. -requestFacade.nullRequest=Null request object -responseFacade.nullResponse=Null response object - -# -# MapperListener -# -mapperListener.unknownDefaultHost=Unknown default host: {0} -mapperListener.registerHost=Register host {0} at domain {1} -mapperListener.unregisterHost=Unregister host {0} at domain {1} -mapperListener.registerContext=Register Context {0} -mapperListener.unregisterContext=Unregister Context {0} -mapperListener.registerWrapper=Register Wrapper {0} in Context {1} - - - + +# +# CoyoteConnector +# + +coyoteConnector.alreadyInitialized=The connector has already been initialized +coyoteConnector.alreadyStarted=The connector has already been started +coyoteConnector.cannotRegisterProtocol=Cannot register MBean for the Protocol +coyoteConnector.notStarted=Coyote connector has not been started +coyoteConnector.protocolHandlerDestroyFailed=Protocol handler destroy failed: {0} +coyoteConnector.protocolHandlerInitializationFailed=Protocol handler initialization failed: {0} +coyoteConnector.protocolHandlerInstantiationFailed=Protocol handler instantiation failed: {0} +coyoteConnector.protocolHandlerStartFailed=Protocol handler start failed: {0} +coyoteConnector.protocolRegistrationFailed=Protocol JMX registration failed +coyoteConnector.protocolHandlerPauseFailed=Protocol handler pause failed +coyoteConnector.protocolHandlerResumeFailed=Protocol handler resume failed +coyoteConnector.MapperRegistration=register Mapper: {0} +coyoteConnector.protocolUnregistrationFailed=Protocol handler stop failed + + +# +# CoyoteAdapter +# + +coyoteAdapter.service=An exception or error occurred in the container during the request processing + +# +# CoyoteResponse +# + +coyoteResponse.getOutputStream.ise=getWriter() has already been called for this response +coyoteResponse.getWriter.ise=getOutputStream() has already been called for this response +coyoteResponse.resetBuffer.ise=Cannot reset buffer after response has been committed +coyoteResponse.sendError.ise=Cannot call sendError() after the response has been committed +coyoteResponse.sendRedirect.ise=Cannot call sendRedirect() after the response has been committed +coyoteResponse.setBufferSize.ise=Cannot change buffer size after data has been written + +# +# CoyoteRequest +# + +coyoteRequest.getInputStream.ise=getReader() has already been called for this request +coyoteRequest.getReader.ise=getInputStream() has already been called for this request +coyoteRequest.sessionCreateCommitted=Cannot create a session after the response has been committed +coyoteRequest.setAttribute.namenull=Cannot call setAttribute with a null name +coyoteRequest.listenerStart=Exception sending context initialized event to listener instance of class {0} +coyoteRequest.listenerStop=Exception sending context destroyed event to listener instance of class {0} +coyoteRequest.attributeEvent=Exception thrown by attributes event listener +coyoteRequest.postTooLarge=Parameters were not parsed because the size of the posted data was too big. Use the maxPostSize attribute of the connector to resolve this if the application should accept large POSTs. +requestFacade.nullRequest=Null request object +responseFacade.nullResponse=Null response object + +# +# MapperListener +# +mapperListener.unknownDefaultHost=Unknown default host: {0} +mapperListener.registerHost=Register host {0} at domain {1} +mapperListener.unregisterHost=Unregister host {0} at domain {1} +mapperListener.registerContext=Register Context {0} +mapperListener.unregisterContext=Unregister Context {0} +mapperListener.registerWrapper=Register Wrapper {0} in Context {1} + + + diff --git a/java/org/apache/catalina/connector/LocalStrings_es.properties b/java/org/apache/catalina/connector/LocalStrings_es.properties index a305490e6..6bca4bfe7 100644 --- a/java/org/apache/catalina/connector/LocalStrings_es.properties +++ b/java/org/apache/catalina/connector/LocalStrings_es.properties @@ -1,56 +1,56 @@ - -# -# CoyoteConnector -# - -coyoteConnector.alreadyInitialized=Ya ha sido inicializado el conector -coyoteConnector.alreadyStarted=Ya ha sido arrancado el conector -coyoteConnector.cannotRegisterProtocol=No puedo registrar MBean para el Protocolo -coyoteConnector.notStarted=El conector Coyote no ha sido arrancado -coyoteConnector.protocolHandlerDestroyFailed=Falló la destrucción del manejador de protocolo: {0} -coyoteConnector.protocolHandlerInitializationFailed=Falló la inicialización del manejador de protocolo: {0} -coyoteConnector.protocolHandlerInstantiationFailed=Falló la instanciación del manejador de protocolo: {0} -coyoteConnector.protocolHandlerStartFailed=Falló el arranque del manejador de protocolo: {0} -coyoteConnector.protocolRegistrationFailed=Falló el registro de JMX - -# -# CoyoteAdapter -# - -coyoteAdapter.service=Ha tenido lugar una excepción o error en el contenedor durante el procesamiento del requerimiento - -# -# CoyoteResponse -# - -coyoteResponse.getOutputStream.ise=getWriter() ya ha sido llamado para esta respuesta -coyoteResponse.getWriter.ise=getOutputStream() ya ha sido llamado para esta respuesta -coyoteResponse.resetBuffer.ise=No puedo limpiar el búfer después de que la repuesta ha sido llevada a cabo -coyoteResponse.sendError.ise=No puedo llamar a sendError() tras llevar a cabo la respuesta -coyoteResponse.sendRedirect.ise=No puedo llamar a sendRedirect() tras llevar a cabo la respuesta -coyoteResponse.setBufferSize.ise=No puedo cambiar la medida del búfer tras escribir los datos - -# -# CoyoteRequest -# - -coyoteRequest.getInputStream.ise=getReader() ya ha sido llamado para este requerimiento -coyoteRequest.getReader.ise=getInputStream() ya ha sido llamado para este requerimiento -coyoteRequest.sessionCreateCommitted=No puedo crear una sesión después de llevar a cabo la respueta -coyoteRequest.setAttribute.namenull=No pudeo llamar a setAttribute con un nombre nulo -coyoteRequest.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0} -coyoteRequest.listenerStop=Excepción enviando evento destruído de contexto a instancia de escuchador de clase {0} -coyoteRequest.attributeEvent=Excepción lanzada mediante el escuchador de eventos de atributos -coyoteRequest.postTooLarge=No se analizaron los parámetros porque la medida de los datos enviados era demasiado grande. Usa el atributo maxPostSize del conector para resolver esto en caso de que la aplicación debiera de aceptar POSTs más grandes. - - -# -# MapperListener -# - -mapperListener.registerContext=Registrar Contexto {0} -mapperListener.unregisterContext=Desregistrar Contexto {0} -mapperListener.registerWrapper=Registrar Arropador (Wrapper) {0} en Contexto {1} - - - + +# +# CoyoteConnector +# + +coyoteConnector.alreadyInitialized=Ya ha sido inicializado el conector +coyoteConnector.alreadyStarted=Ya ha sido arrancado el conector +coyoteConnector.cannotRegisterProtocol=No puedo registrar MBean para el Protocolo +coyoteConnector.notStarted=El conector Coyote no ha sido arrancado +coyoteConnector.protocolHandlerDestroyFailed=Falló la destrucción del manejador de protocolo: {0} +coyoteConnector.protocolHandlerInitializationFailed=Falló la inicialización del manejador de protocolo: {0} +coyoteConnector.protocolHandlerInstantiationFailed=Falló la instanciación del manejador de protocolo: {0} +coyoteConnector.protocolHandlerStartFailed=Falló el arranque del manejador de protocolo: {0} +coyoteConnector.protocolRegistrationFailed=Falló el registro de JMX + +# +# CoyoteAdapter +# + +coyoteAdapter.service=Ha tenido lugar una excepción o error en el contenedor durante el procesamiento del requerimiento + +# +# CoyoteResponse +# + +coyoteResponse.getOutputStream.ise=getWriter() ya ha sido llamado para esta respuesta +coyoteResponse.getWriter.ise=getOutputStream() ya ha sido llamado para esta respuesta +coyoteResponse.resetBuffer.ise=No puedo limpiar el búfer después de que la repuesta ha sido llevada a cabo +coyoteResponse.sendError.ise=No puedo llamar a sendError() tras llevar a cabo la respuesta +coyoteResponse.sendRedirect.ise=No puedo llamar a sendRedirect() tras llevar a cabo la respuesta +coyoteResponse.setBufferSize.ise=No puedo cambiar la medida del búfer tras escribir los datos + +# +# CoyoteRequest +# + +coyoteRequest.getInputStream.ise=getReader() ya ha sido llamado para este requerimiento +coyoteRequest.getReader.ise=getInputStream() ya ha sido llamado para este requerimiento +coyoteRequest.sessionCreateCommitted=No puedo crear una sesión después de llevar a cabo la respueta +coyoteRequest.setAttribute.namenull=No pudeo llamar a setAttribute con un nombre nulo +coyoteRequest.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0} +coyoteRequest.listenerStop=Excepción enviando evento destruído de contexto a instancia de escuchador de clase {0} +coyoteRequest.attributeEvent=Excepción lanzada mediante el escuchador de eventos de atributos +coyoteRequest.postTooLarge=No se analizaron los parámetros porque la medida de los datos enviados era demasiado grande. Usa el atributo maxPostSize del conector para resolver esto en caso de que la aplicación debiera de aceptar POSTs más grandes. + + +# +# MapperListener +# + +mapperListener.registerContext=Registrar Contexto {0} +mapperListener.unregisterContext=Desregistrar Contexto {0} +mapperListener.registerWrapper=Registrar Arropador (Wrapper) {0} en Contexto {1} + + + diff --git a/java/org/apache/catalina/connector/LocalStrings_fr.properties b/java/org/apache/catalina/connector/LocalStrings_fr.properties index 4010c179e..069058d92 100644 --- a/java/org/apache/catalina/connector/LocalStrings_fr.properties +++ b/java/org/apache/catalina/connector/LocalStrings_fr.properties @@ -1,58 +1,58 @@ - -# -# CoyoteConnector -# - -coyoteConnector.alreadyInitialized=Le connecteur a déjà été initialisé -coyoteConnector.alreadyStarted=Le connecteur a déjà été démarré -coyoteConnector.cannotRegisterProtocol=Impossible d''enregistrer le MBean pour le Protocol -coyoteConnector.notStarted=Le connecteur Coyote n''a pas été démarré -coyoteConnector.protocolHandlerDestroyFailed=La destruction du gestionnaire de protocole a échouée: {0} -coyoteConnector.protocolHandlerInitializationFailed=L''initialisation du gestionnaire de protocole a échoué: {0} -coyoteConnector.protocolHandlerInstantiationFailed=L''instantiation du gestionnaire de protocole a échoué: {0} -coyoteConnector.protocolHandlerStartFailed=Le démarrage du gestionnaire de protocole a échoué: {0} -coyoteConnector.protocolRegistrationFailed=L''enregistrement du protocol JMX a échoué -coyoteConnector.protocolHandlerPauseFailed=La suspension du gestionnaire de protocole a échouée -coyoteConnector.protocolHandlerResumeFailed=Le redémarrage du gestionnaire de protocole a échoué - -# -# CoyoteAdapter -# - -coyoteAdapter.service=Une exception ou une erreur s''est produite dans le conteneur durant le traitement de la requête - -# -# CoyoteResponse -# - -coyoteResponse.getOutputStream.ise="getWriter()" a déjà été appelé pour cette réponse -coyoteResponse.getWriter.ise="getOutputStream()" a déjà été appelé pour cette réponse -coyoteResponse.resetBuffer.ise=Impossible de remettre à zéro le tampon après que la réponse ait été envoyée -coyoteResponse.sendError.ise=Impossible d''appeler "sendError()" après que la réponse ait été envoyée -coyoteResponse.sendRedirect.ise=Impossible d''appeler "sendRedirect()" après que la réponse ait été envoyée -coyoteResponse.setBufferSize.ise=Impossible de changer la taille du tampon après que les données aient été écrites - -# -# CoyoteRequest -# - -coyoteRequest.getInputStream.ise="getReader()" a déjà été appelé pour cette requête -coyoteRequest.getReader.ise="getInputStream()" a déjà été appelé pour cette requête -coyoteRequest.sessionCreateCommitted=Impossible de créer une sessionaprès que la réponse ait été envoyée -coyoteRequest.setAttribute.namenull=Impossible d''appeler "setAttribute" avec un nom nul -coyoteRequest.listenerStart=Une exception s''est produite lors de l''envoi de l''évènement contexte initialisé à l''instance de classe d''écoute {0} -coyoteRequest.listenerStop=Une exception s''est produite lors de l''envoi de l''évènement contexte détruit à l''instance de classe d''écoute {0} -coyoteRequest.attributeEvent=Une exception a été lancée par l''instance d''écoute pour l''évènement attributs (attributes) -coyoteRequest.postTooLarge=Les paramètres n''ont pas été évalué car la taille des données postées est trop important. Utilisez l''attribut maxPostSize du connecteur pour corriger ce problème si votre application doit accepter des POSTs importants. - - -# -# MapperListener -# - -mapperListener.registerContext=Enregistrement du contexte {0} -mapperListener.unregisterContext=Désenregistrement du contexte {0} -mapperListener.registerWrapper=Enregistrement de l''enrobeur (wrapper) {0} dans le contexte {1} - - - + +# +# CoyoteConnector +# + +coyoteConnector.alreadyInitialized=Le connecteur a déjà été initialisé +coyoteConnector.alreadyStarted=Le connecteur a déjà été démarré +coyoteConnector.cannotRegisterProtocol=Impossible d''enregistrer le MBean pour le Protocol +coyoteConnector.notStarted=Le connecteur Coyote n''a pas été démarré +coyoteConnector.protocolHandlerDestroyFailed=La destruction du gestionnaire de protocole a échouée: {0} +coyoteConnector.protocolHandlerInitializationFailed=L''initialisation du gestionnaire de protocole a échoué: {0} +coyoteConnector.protocolHandlerInstantiationFailed=L''instantiation du gestionnaire de protocole a échoué: {0} +coyoteConnector.protocolHandlerStartFailed=Le démarrage du gestionnaire de protocole a échoué: {0} +coyoteConnector.protocolRegistrationFailed=L''enregistrement du protocol JMX a échoué +coyoteConnector.protocolHandlerPauseFailed=La suspension du gestionnaire de protocole a échouée +coyoteConnector.protocolHandlerResumeFailed=Le redémarrage du gestionnaire de protocole a échoué + +# +# CoyoteAdapter +# + +coyoteAdapter.service=Une exception ou une erreur s''est produite dans le conteneur durant le traitement de la requête + +# +# CoyoteResponse +# + +coyoteResponse.getOutputStream.ise="getWriter()" a déjà été appelé pour cette réponse +coyoteResponse.getWriter.ise="getOutputStream()" a déjà été appelé pour cette réponse +coyoteResponse.resetBuffer.ise=Impossible de remettre à zéro le tampon après que la réponse ait été envoyée +coyoteResponse.sendError.ise=Impossible d''appeler "sendError()" après que la réponse ait été envoyée +coyoteResponse.sendRedirect.ise=Impossible d''appeler "sendRedirect()" après que la réponse ait été envoyée +coyoteResponse.setBufferSize.ise=Impossible de changer la taille du tampon après que les données aient été écrites + +# +# CoyoteRequest +# + +coyoteRequest.getInputStream.ise="getReader()" a déjà été appelé pour cette requête +coyoteRequest.getReader.ise="getInputStream()" a déjà été appelé pour cette requête +coyoteRequest.sessionCreateCommitted=Impossible de créer une sessionaprès que la réponse ait été envoyée +coyoteRequest.setAttribute.namenull=Impossible d''appeler "setAttribute" avec un nom nul +coyoteRequest.listenerStart=Une exception s''est produite lors de l''envoi de l''évènement contexte initialisé à l''instance de classe d''écoute {0} +coyoteRequest.listenerStop=Une exception s''est produite lors de l''envoi de l''évènement contexte détruit à l''instance de classe d''écoute {0} +coyoteRequest.attributeEvent=Une exception a été lancée par l''instance d''écoute pour l''évènement attributs (attributes) +coyoteRequest.postTooLarge=Les paramètres n''ont pas été évalué car la taille des données postées est trop important. Utilisez l''attribut maxPostSize du connecteur pour corriger ce problème si votre application doit accepter des POSTs importants. + + +# +# MapperListener +# + +mapperListener.registerContext=Enregistrement du contexte {0} +mapperListener.unregisterContext=Désenregistrement du contexte {0} +mapperListener.registerWrapper=Enregistrement de l''enrobeur (wrapper) {0} dans le contexte {1} + + + diff --git a/java/org/apache/catalina/connector/LocalStrings_ja.properties b/java/org/apache/catalina/connector/LocalStrings_ja.properties index 7a75aa0ec..1b3bd81af 100644 --- a/java/org/apache/catalina/connector/LocalStrings_ja.properties +++ b/java/org/apache/catalina/connector/LocalStrings_ja.properties @@ -1,58 +1,58 @@ - -# -# CoyoteConnector -# - -coyoteConnector.alreadyInitialized=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteConnector.alreadyStarted=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteConnector.cannotRegisterProtocol=\u305d\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u306bMBean\u3092\u767b\u9332\u3067\u304d\u307e\u305b\u3093 -coyoteConnector.notStarted=Coyote\u30b3\u30cd\u30af\u30bf\u306f\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -coyoteConnector.protocolHandlerDestroyFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u5ec3\u68c4\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -coyoteConnector.protocolHandlerInitializationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -coyoteConnector.protocolHandlerInstantiationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -coyoteConnector.protocolHandlerStartFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -coyoteConnector.protocolRegistrationFailed=\u30d7\u30ed\u30c8\u30b3\u30ebJMX\u306e\u767b\u9332\u306b\u5931\u6557\u3057\u307e\u3057\u305f -coyoteConnector.protocolHandlerPauseFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u4e00\u6642\u505c\u6b62\u306b\u5931\u6557\u3057\u307e\u3057\u305f -coyoteConnector.protocolHandlerResumeFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u518d\u958b\u306b\u5931\u6557\u3057\u307e\u3057\u305f - -# -# CoyoteAdapter -# - -coyoteAdapter.service=\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u51e6\u7406\u4e2d\u306b\u30b3\u30cd\u30af\u30bf\u3067\u4f8b\u5916\u307e\u305f\u306f\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f - -# -# CoyoteResponse -# - -coyoteResponse.getOutputStream.ise=getWriter()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteResponse.getWriter.ise=getOutputStream()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteResponse.resetBuffer.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -coyoteResponse.sendError.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendError()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -coyoteResponse.sendRedirect.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendRedirect()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -coyoteResponse.setBufferSize.ise=\u30c7\u30fc\u30bf\u304c\u65e2\u306b\u66f8\u304d\u8fbc\u307e\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3092\u5909\u66f4\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 - -# -# CoyoteRequest -# - -coyoteRequest.getInputStream.ise=getReader()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteRequest.getReader.ise=getInputStream()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 -coyoteRequest.sessionCreateCommitted=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 -coyoteRequest.setAttribute.namenull=setAttribute\u3092\u540d\u524d\u3092\u6307\u5b9a\u305b\u305a\u306b\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -coyoteRequest.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f -coyoteRequest.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f -coyoteRequest.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f -coyoteRequest.postTooLarge=POST\u3055\u308c\u305f\u30c7\u30fc\u30bf\u304c\u5927\u304d\u3059\u304e\u305f\u306e\u3067\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u69cb\u6587\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u305d\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u5de8\u5927\u306aPOST\u3092\u53d7\u3051\u4ed8\u3051\u306d\u3070\u306a\u3089\u306a\u3044\u5834\u5408\u306b\u306f\u3001\u3053\u308c\u3092\u89e3\u6c7a\u3059\u308b\u305f\u3081\u306b\u30b3\u30cd\u30af\u30bf\u306emaxPostSize\u5c5e\u6027\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002 - - -# -# MapperListener -# - -mapperListener.registerContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0}\u3000\u3092\u767b\u9332\u3057\u307e\u3059 -mapperListener.unregisterContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u767b\u9332\u3092\u62b9\u6d88\u3057\u307e\u3059 -mapperListener.registerWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {1} \u306b\u30e9\u30c3\u30d1 {0} \u3092\u767b\u9332\u3057\u307e\u3059 - - - + +# +# CoyoteConnector +# + +coyoteConnector.alreadyInitialized=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteConnector.alreadyStarted=\u30b3\u30cd\u30af\u30bf\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteConnector.cannotRegisterProtocol=\u305d\u306e\u30d7\u30ed\u30c8\u30b3\u30eb\u306bMBean\u3092\u767b\u9332\u3067\u304d\u307e\u305b\u3093 +coyoteConnector.notStarted=Coyote\u30b3\u30cd\u30af\u30bf\u306f\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +coyoteConnector.protocolHandlerDestroyFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u5ec3\u68c4\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +coyoteConnector.protocolHandlerInitializationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +coyoteConnector.protocolHandlerInstantiationFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +coyoteConnector.protocolHandlerStartFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +coyoteConnector.protocolRegistrationFailed=\u30d7\u30ed\u30c8\u30b3\u30ebJMX\u306e\u767b\u9332\u306b\u5931\u6557\u3057\u307e\u3057\u305f +coyoteConnector.protocolHandlerPauseFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u4e00\u6642\u505c\u6b62\u306b\u5931\u6557\u3057\u307e\u3057\u305f +coyoteConnector.protocolHandlerResumeFailed=\u30d7\u30ed\u30c8\u30b3\u30eb\u30cf\u30f3\u30c9\u30e9\u306e\u518d\u958b\u306b\u5931\u6557\u3057\u307e\u3057\u305f + +# +# CoyoteAdapter +# + +coyoteAdapter.service=\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u51e6\u7406\u4e2d\u306b\u30b3\u30cd\u30af\u30bf\u3067\u4f8b\u5916\u307e\u305f\u306f\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f + +# +# CoyoteResponse +# + +coyoteResponse.getOutputStream.ise=getWriter()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteResponse.getWriter.ise=getOutputStream()\u306f\u3053\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteResponse.resetBuffer.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u3092\u30ea\u30bb\u30c3\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +coyoteResponse.sendError.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendError()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +coyoteResponse.sendRedirect.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u304c\u30b3\u30df\u30c3\u30c8\u3055\u308c\u305f\u5f8c\u3067sendRedirect()\u3092\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +coyoteResponse.setBufferSize.ise=\u30c7\u30fc\u30bf\u304c\u65e2\u306b\u66f8\u304d\u8fbc\u307e\u308c\u305f\u5f8c\u3067\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3092\u5909\u66f4\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 + +# +# CoyoteRequest +# + +coyoteRequest.getInputStream.ise=getReader()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteRequest.getReader.ise=getInputStream()\u306f\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u306b\u5bfe\u3057\u3066\u65e2\u306b\u547c\u3073\u51fa\u3055\u308c\u3066\u3044\u307e\u3059 +coyoteRequest.sessionCreateCommitted=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 +coyoteRequest.setAttribute.namenull=setAttribute\u3092\u540d\u524d\u3092\u6307\u5b9a\u305b\u305a\u306b\u547c\u3073\u51fa\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +coyoteRequest.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f +coyoteRequest.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306b\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f +coyoteRequest.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f +coyoteRequest.postTooLarge=POST\u3055\u308c\u305f\u30c7\u30fc\u30bf\u304c\u5927\u304d\u3059\u304e\u305f\u306e\u3067\u3001\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u69cb\u6587\u89e3\u6790\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002\u305d\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u304c\u5de8\u5927\u306aPOST\u3092\u53d7\u3051\u4ed8\u3051\u306d\u3070\u306a\u3089\u306a\u3044\u5834\u5408\u306b\u306f\u3001\u3053\u308c\u3092\u89e3\u6c7a\u3059\u308b\u305f\u3081\u306b\u30b3\u30cd\u30af\u30bf\u306emaxPostSize\u5c5e\u6027\u3092\u4f7f\u7528\u3057\u3066\u304f\u3060\u3055\u3044\u3002 + + +# +# MapperListener +# + +mapperListener.registerContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0}\u3000\u3092\u767b\u9332\u3057\u307e\u3059 +mapperListener.unregisterContext=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u767b\u9332\u3092\u62b9\u6d88\u3057\u307e\u3059 +mapperListener.registerWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {1} \u306b\u30e9\u30c3\u30d1 {0} \u3092\u767b\u9332\u3057\u307e\u3059 + + + diff --git a/java/org/apache/catalina/connector/MapperListener.java b/java/org/apache/catalina/connector/MapperListener.java index 8e06b644c..f07af9d8b 100644 --- a/java/org/apache/catalina/connector/MapperListener.java +++ b/java/org/apache/catalina/connector/MapperListener.java @@ -1,504 +1,504 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.connector; - -import java.util.Iterator; -import java.util.Set; - -import javax.management.MBeanServer; -import javax.management.MBeanServerNotification; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectInstance; -import javax.management.ObjectName; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -import org.apache.tomcat.util.http.mapper.Mapper; -import org.apache.tomcat.util.modeler.Registry; - -import org.apache.tomcat.util.res.StringManager; - - -/** - * Mapper listener. - * - * @author Remy Maucherat - * @author Costin Manolache - */ -public class MapperListener - implements NotificationListener - { - private static Log log = LogFactory.getLog(MapperListener.class); - - - // ----------------------------------------------------- Instance Variables - /** - * Associated mapper. - */ - protected Mapper mapper = null; - - /** - * MBean server. - */ - protected MBeanServer mBeanServer = null; - - - /** - * The string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - // It should be null - and fail if not set - private String domain="*"; - private String engine="*"; - - // ----------------------------------------------------------- Constructors - - - /** - * Create mapper listener. - */ - public MapperListener(Mapper mapper) { - this.mapper = mapper; - } - - - // --------------------------------------------------------- Public Methods - - public String getDomain() { - return domain; - } - - public void setDomain(String domain) { - this.domain = domain; - } - - public String getEngine() { - return engine; - } - - public void setEngine(String engine) { - this.engine = engine; - } - - /** - * Initialize associated mapper. - */ - public void init() { - - try { - - mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); - - registerEngine(); - - // Query hosts - String onStr = domain + ":type=Host,*"; - ObjectName objectName = new ObjectName(onStr); - Set set = mBeanServer.queryMBeans(objectName, null); - Iterator iterator = set.iterator(); - while (iterator.hasNext()) { - ObjectInstance oi = (ObjectInstance) iterator.next(); - registerHost(oi.getObjectName()); - } - - - // Query contexts - onStr = "*:j2eeType=WebModule,*"; - objectName = new ObjectName(onStr); - set = mBeanServer.queryMBeans(objectName, null); - iterator = set.iterator(); - while (iterator.hasNext()) { - ObjectInstance oi = (ObjectInstance) iterator.next(); - registerContext(oi.getObjectName()); - } - - // Query wrappers - onStr = "*:j2eeType=Servlet,*"; - objectName = new ObjectName(onStr); - set = mBeanServer.queryMBeans(objectName, null); - iterator = set.iterator(); - while (iterator.hasNext()) { - ObjectInstance oi = (ObjectInstance) iterator.next(); - registerWrapper(oi.getObjectName()); - } - - onStr = "JMImplementation:type=MBeanServerDelegate"; - objectName = new ObjectName(onStr); - mBeanServer.addNotificationListener(objectName, this, null, null); - - } catch (Exception e) { - log.warn("Error registering contexts",e); - } - - } - - /** - * unregister this from JMImplementation:type=MBeanServerDelegate - */ - public void destroy() { - try { - - ObjectName objectName = new ObjectName( - "JMImplementation:type=MBeanServerDelegate"); - mBeanServer.removeNotificationListener(objectName, this); - } catch (Exception e) { - log.warn("Error unregistering MBeanServerDelegate", e); - } - } - - // ------------------------------------------- NotificationListener Methods - - - public void handleNotification(Notification notification, - java.lang.Object handback) { - - if (notification instanceof MBeanServerNotification) { - ObjectName objectName = - ((MBeanServerNotification) notification).getMBeanName(); - String j2eeType = objectName.getKeyProperty("j2eeType"); - String engineName = null; - if (j2eeType != null) { - if ((j2eeType.equals("WebModule")) || - (j2eeType.equals("Servlet"))) { - if (mBeanServer.isRegistered(objectName)) { - try { - engineName = (String) - mBeanServer.getAttribute(objectName, "engineName"); - } catch (Exception e) { - // Ignore - } - } - } - } - - // At deployment time, engineName is always = null. - if ( (!"*".equals(domain)) && - ( !domain.equals(objectName.getDomain()) ) && - ( (!domain.equals(engineName) ) && - (engineName != null) ) ) { - return; - } - if(log.isDebugEnabled()) - log.debug( "Handle " + objectName + " type : " + notification.getType()); - if (notification.getType().equals - (MBeanServerNotification.REGISTRATION_NOTIFICATION)) { - String type=objectName.getKeyProperty("type"); - if( "Host".equals( type ) && domain.equals(objectName.getDomain())) { - try { - registerHost(objectName); - } catch (Exception e) { - log.warn("Error registering Host " + objectName, e); - } - } - - if (j2eeType != null) { - if (j2eeType.equals("WebModule")) { - try { - registerContext(objectName); - } catch (Throwable t) { - log.warn("Error registering Context " + objectName,t); - } - } else if (j2eeType.equals("Servlet")) { - try { - registerWrapper(objectName); - } catch (Throwable t) { - log.warn("Error registering Wrapper " + objectName,t); - } - } - } - } else if (notification.getType().equals - (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) { - String type=objectName.getKeyProperty("type"); - if( "Host".equals( type )&& domain.equals(objectName.getDomain())) { - try { - unregisterHost(objectName); - } catch (Exception e) { - log.warn("Error unregistering Host " + objectName,e); - } - } - - if (j2eeType != null) { - if (j2eeType.equals("WebModule")) { - try { - unregisterContext(objectName); - } catch (Throwable t) { - log.warn("Error unregistering webapp " + objectName,t); - } - } - } - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - private void registerEngine() - throws Exception - { - ObjectName engineName = new ObjectName - (domain + ":type=Engine"); - if ( ! mBeanServer.isRegistered(engineName)) return; - String defaultHost = - (String) mBeanServer.getAttribute(engineName, "defaultHost"); - ObjectName hostName = new ObjectName - (domain + ":type=Host," + "host=" + defaultHost); - if (!mBeanServer.isRegistered(hostName)) { - - // Get the hosts' list - String onStr = domain + ":type=Host,*"; - ObjectName objectName = new ObjectName(onStr); - Set set = mBeanServer.queryMBeans(objectName, null); - Iterator iterator = set.iterator(); - String[] aliases; - boolean isRegisteredWithAlias = false; - - while (iterator.hasNext()) { - - if (isRegisteredWithAlias) break; - - ObjectInstance oi = (ObjectInstance) iterator.next(); - hostName = oi.getObjectName(); - aliases = (String[]) - mBeanServer.invoke(hostName, "findAliases", null, null); - - for (int i=0; i < aliases.length; i++){ - if (aliases[i].equalsIgnoreCase(defaultHost)){ - isRegisteredWithAlias = true; - break; - } - } - } - - if (!isRegisteredWithAlias && log.isWarnEnabled()) - log.warn(sm.getString("mapperListener.unknownDefaultHost", defaultHost)); - } - // This should probablt be called later - if( defaultHost != null ) { - mapper.setDefaultHostName(defaultHost); - } - } - - /** - * Register host. - */ - private void registerHost(ObjectName objectName) - throws Exception { - String name=objectName.getKeyProperty("host"); - if( name != null ) { - String[] aliases = (String[]) - mBeanServer.invoke(objectName, "findAliases", null, null); - mapper.addHost(name, aliases, objectName); - if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.registerHost", name, domain)); - - } - } - - - /** - * Unregister host. - */ - private void unregisterHost(ObjectName objectName) - throws Exception { - String name=objectName.getKeyProperty("host"); - mapper.removeHost(name); - if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.unregisterHost", name, domain)); - } - - - /** - * Register context. - */ - private void registerContext(ObjectName objectName) - throws Exception { - - String name = objectName.getKeyProperty("name"); - - // If the domain is the same with ours or the engine - // name attribute is the same... - then it's ours - String targetDomain=objectName.getDomain(); - if( ! domain.equals( targetDomain )) { - try { - targetDomain = (String) mBeanServer.getAttribute - (objectName, "engineName"); - } catch (Exception e) { - // Ignore - } - if( ! domain.equals( targetDomain )) { - // not ours - return; - } - } - - String hostName = null; - String contextName = null; - if (name.startsWith("//")) { - name = name.substring(2); - } - int slash = name.indexOf("/"); - if (slash != -1) { - hostName = name.substring(0, slash); - contextName = name.substring(slash); - } else { - return; - } - // Special case for the root context - if (contextName.equals("/")) { - contextName = ""; - } - - if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.registerContext", contextName)); - - Object context = - mBeanServer.invoke(objectName, "findMappingObject", null, null); - //mBeanServer.getAttribute(objectName, "mappingObject"); - javax.naming.Context resources = (javax.naming.Context) - mBeanServer.invoke(objectName, "findStaticResources", null, null); - //mBeanServer.getAttribute(objectName, "staticResources"); - String[] welcomeFiles = (String[]) - mBeanServer.getAttribute(objectName, "welcomeFiles"); - - mapper.addContext(hostName, contextName, context, - welcomeFiles, resources); - - } - - - /** - * Unregister context. - */ - private void unregisterContext(ObjectName objectName) - throws Exception { - - String name = objectName.getKeyProperty("name"); - - // If the domain is the same with ours or the engine - // name attribute is the same... - then it's ours - String targetDomain=objectName.getDomain(); - if( ! domain.equals( targetDomain )) { - try { - targetDomain = (String) mBeanServer.getAttribute - (objectName, "engineName"); - } catch (Exception e) { - // Ignore - } - if( ! domain.equals( targetDomain )) { - // not ours - return; - } - } - - String hostName = null; - String contextName = null; - if (name.startsWith("//")) { - name = name.substring(2); - } - int slash = name.indexOf("/"); - if (slash != -1) { - hostName = name.substring(0, slash); - contextName = name.substring(slash); - } else { - return; - } - // Special case for the root context - if (contextName.equals("/")) { - contextName = ""; - } - if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.unregisterContext", contextName)); - - mapper.removeContext(hostName, contextName); - - } - - - /** - * Register wrapper. - */ - private void registerWrapper(ObjectName objectName) - throws Exception { - - // If the domain is the same with ours or the engine - // name attribute is the same... - then it's ours - String targetDomain=objectName.getDomain(); - if( ! domain.equals( targetDomain )) { - try { - targetDomain=(String) mBeanServer.getAttribute(objectName, "engineName"); - } catch (Exception e) { - // Ignore - } - if( ! domain.equals( targetDomain )) { - // not ours - return; - } - - } - - String wrapperName = objectName.getKeyProperty("name"); - String name = objectName.getKeyProperty("WebModule"); - - String hostName = null; - String contextName = null; - if (name.startsWith("//")) { - name = name.substring(2); - } - int slash = name.indexOf("/"); - if (slash != -1) { - hostName = name.substring(0, slash); - contextName = name.substring(slash); - } else { - return; - } - // Special case for the root context - if (contextName.equals("/")) { - contextName = ""; - } - if(log.isDebugEnabled()) - log.debug(sm.getString - ("mapperListener.registerWrapper", - wrapperName, contextName)); - - String[] mappings = (String[]) - mBeanServer.invoke(objectName, "findMappings", null, null); - Object wrapper = - mBeanServer.invoke(objectName, "findMappingObject", null, null); - - for (int i = 0; i < mappings.length; i++) { - boolean jspWildCard = (wrapperName.equals("jsp") - && mappings[i].endsWith("/*")); - mapper.addWrapper(hostName, contextName, mappings[i], wrapper, - jspWildCard); - } - - } - - - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.connector; + +import java.util.Iterator; +import java.util.Set; + +import javax.management.MBeanServer; +import javax.management.MBeanServerNotification; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +import org.apache.tomcat.util.http.mapper.Mapper; +import org.apache.tomcat.util.modeler.Registry; + +import org.apache.tomcat.util.res.StringManager; + + +/** + * Mapper listener. + * + * @author Remy Maucherat + * @author Costin Manolache + */ +public class MapperListener + implements NotificationListener + { + private static Log log = LogFactory.getLog(MapperListener.class); + + + // ----------------------------------------------------- Instance Variables + /** + * Associated mapper. + */ + protected Mapper mapper = null; + + /** + * MBean server. + */ + protected MBeanServer mBeanServer = null; + + + /** + * The string manager for this package. + */ + private StringManager sm = + StringManager.getManager(Constants.Package); + + // It should be null - and fail if not set + private String domain="*"; + private String engine="*"; + + // ----------------------------------------------------------- Constructors + + + /** + * Create mapper listener. + */ + public MapperListener(Mapper mapper) { + this.mapper = mapper; + } + + + // --------------------------------------------------------- Public Methods + + public String getDomain() { + return domain; + } + + public void setDomain(String domain) { + this.domain = domain; + } + + public String getEngine() { + return engine; + } + + public void setEngine(String engine) { + this.engine = engine; + } + + /** + * Initialize associated mapper. + */ + public void init() { + + try { + + mBeanServer = Registry.getRegistry(null, null).getMBeanServer(); + + registerEngine(); + + // Query hosts + String onStr = domain + ":type=Host,*"; + ObjectName objectName = new ObjectName(onStr); + Set set = mBeanServer.queryMBeans(objectName, null); + Iterator iterator = set.iterator(); + while (iterator.hasNext()) { + ObjectInstance oi = (ObjectInstance) iterator.next(); + registerHost(oi.getObjectName()); + } + + + // Query contexts + onStr = "*:j2eeType=WebModule,*"; + objectName = new ObjectName(onStr); + set = mBeanServer.queryMBeans(objectName, null); + iterator = set.iterator(); + while (iterator.hasNext()) { + ObjectInstance oi = (ObjectInstance) iterator.next(); + registerContext(oi.getObjectName()); + } + + // Query wrappers + onStr = "*:j2eeType=Servlet,*"; + objectName = new ObjectName(onStr); + set = mBeanServer.queryMBeans(objectName, null); + iterator = set.iterator(); + while (iterator.hasNext()) { + ObjectInstance oi = (ObjectInstance) iterator.next(); + registerWrapper(oi.getObjectName()); + } + + onStr = "JMImplementation:type=MBeanServerDelegate"; + objectName = new ObjectName(onStr); + mBeanServer.addNotificationListener(objectName, this, null, null); + + } catch (Exception e) { + log.warn("Error registering contexts",e); + } + + } + + /** + * unregister this from JMImplementation:type=MBeanServerDelegate + */ + public void destroy() { + try { + + ObjectName objectName = new ObjectName( + "JMImplementation:type=MBeanServerDelegate"); + mBeanServer.removeNotificationListener(objectName, this); + } catch (Exception e) { + log.warn("Error unregistering MBeanServerDelegate", e); + } + } + + // ------------------------------------------- NotificationListener Methods + + + public void handleNotification(Notification notification, + java.lang.Object handback) { + + if (notification instanceof MBeanServerNotification) { + ObjectName objectName = + ((MBeanServerNotification) notification).getMBeanName(); + String j2eeType = objectName.getKeyProperty("j2eeType"); + String engineName = null; + if (j2eeType != null) { + if ((j2eeType.equals("WebModule")) || + (j2eeType.equals("Servlet"))) { + if (mBeanServer.isRegistered(objectName)) { + try { + engineName = (String) + mBeanServer.getAttribute(objectName, "engineName"); + } catch (Exception e) { + // Ignore + } + } + } + } + + // At deployment time, engineName is always = null. + if ( (!"*".equals(domain)) && + ( !domain.equals(objectName.getDomain()) ) && + ( (!domain.equals(engineName) ) && + (engineName != null) ) ) { + return; + } + if(log.isDebugEnabled()) + log.debug( "Handle " + objectName + " type : " + notification.getType()); + if (notification.getType().equals + (MBeanServerNotification.REGISTRATION_NOTIFICATION)) { + String type=objectName.getKeyProperty("type"); + if( "Host".equals( type ) && domain.equals(objectName.getDomain())) { + try { + registerHost(objectName); + } catch (Exception e) { + log.warn("Error registering Host " + objectName, e); + } + } + + if (j2eeType != null) { + if (j2eeType.equals("WebModule")) { + try { + registerContext(objectName); + } catch (Throwable t) { + log.warn("Error registering Context " + objectName,t); + } + } else if (j2eeType.equals("Servlet")) { + try { + registerWrapper(objectName); + } catch (Throwable t) { + log.warn("Error registering Wrapper " + objectName,t); + } + } + } + } else if (notification.getType().equals + (MBeanServerNotification.UNREGISTRATION_NOTIFICATION)) { + String type=objectName.getKeyProperty("type"); + if( "Host".equals( type )&& domain.equals(objectName.getDomain())) { + try { + unregisterHost(objectName); + } catch (Exception e) { + log.warn("Error unregistering Host " + objectName,e); + } + } + + if (j2eeType != null) { + if (j2eeType.equals("WebModule")) { + try { + unregisterContext(objectName); + } catch (Throwable t) { + log.warn("Error unregistering webapp " + objectName,t); + } + } + } + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + private void registerEngine() + throws Exception + { + ObjectName engineName = new ObjectName + (domain + ":type=Engine"); + if ( ! mBeanServer.isRegistered(engineName)) return; + String defaultHost = + (String) mBeanServer.getAttribute(engineName, "defaultHost"); + ObjectName hostName = new ObjectName + (domain + ":type=Host," + "host=" + defaultHost); + if (!mBeanServer.isRegistered(hostName)) { + + // Get the hosts' list + String onStr = domain + ":type=Host,*"; + ObjectName objectName = new ObjectName(onStr); + Set set = mBeanServer.queryMBeans(objectName, null); + Iterator iterator = set.iterator(); + String[] aliases; + boolean isRegisteredWithAlias = false; + + while (iterator.hasNext()) { + + if (isRegisteredWithAlias) break; + + ObjectInstance oi = (ObjectInstance) iterator.next(); + hostName = oi.getObjectName(); + aliases = (String[]) + mBeanServer.invoke(hostName, "findAliases", null, null); + + for (int i=0; i < aliases.length; i++){ + if (aliases[i].equalsIgnoreCase(defaultHost)){ + isRegisteredWithAlias = true; + break; + } + } + } + + if (!isRegisteredWithAlias && log.isWarnEnabled()) + log.warn(sm.getString("mapperListener.unknownDefaultHost", defaultHost)); + } + // This should probablt be called later + if( defaultHost != null ) { + mapper.setDefaultHostName(defaultHost); + } + } + + /** + * Register host. + */ + private void registerHost(ObjectName objectName) + throws Exception { + String name=objectName.getKeyProperty("host"); + if( name != null ) { + String[] aliases = (String[]) + mBeanServer.invoke(objectName, "findAliases", null, null); + mapper.addHost(name, aliases, objectName); + if(log.isDebugEnabled()) + log.debug(sm.getString + ("mapperListener.registerHost", name, domain)); + + } + } + + + /** + * Unregister host. + */ + private void unregisterHost(ObjectName objectName) + throws Exception { + String name=objectName.getKeyProperty("host"); + mapper.removeHost(name); + if(log.isDebugEnabled()) + log.debug(sm.getString + ("mapperListener.unregisterHost", name, domain)); + } + + + /** + * Register context. + */ + private void registerContext(ObjectName objectName) + throws Exception { + + String name = objectName.getKeyProperty("name"); + + // If the domain is the same with ours or the engine + // name attribute is the same... - then it's ours + String targetDomain=objectName.getDomain(); + if( ! domain.equals( targetDomain )) { + try { + targetDomain = (String) mBeanServer.getAttribute + (objectName, "engineName"); + } catch (Exception e) { + // Ignore + } + if( ! domain.equals( targetDomain )) { + // not ours + return; + } + } + + String hostName = null; + String contextName = null; + if (name.startsWith("//")) { + name = name.substring(2); + } + int slash = name.indexOf("/"); + if (slash != -1) { + hostName = name.substring(0, slash); + contextName = name.substring(slash); + } else { + return; + } + // Special case for the root context + if (contextName.equals("/")) { + contextName = ""; + } + + if(log.isDebugEnabled()) + log.debug(sm.getString + ("mapperListener.registerContext", contextName)); + + Object context = + mBeanServer.invoke(objectName, "findMappingObject", null, null); + //mBeanServer.getAttribute(objectName, "mappingObject"); + javax.naming.Context resources = (javax.naming.Context) + mBeanServer.invoke(objectName, "findStaticResources", null, null); + //mBeanServer.getAttribute(objectName, "staticResources"); + String[] welcomeFiles = (String[]) + mBeanServer.getAttribute(objectName, "welcomeFiles"); + + mapper.addContext(hostName, contextName, context, + welcomeFiles, resources); + + } + + + /** + * Unregister context. + */ + private void unregisterContext(ObjectName objectName) + throws Exception { + + String name = objectName.getKeyProperty("name"); + + // If the domain is the same with ours or the engine + // name attribute is the same... - then it's ours + String targetDomain=objectName.getDomain(); + if( ! domain.equals( targetDomain )) { + try { + targetDomain = (String) mBeanServer.getAttribute + (objectName, "engineName"); + } catch (Exception e) { + // Ignore + } + if( ! domain.equals( targetDomain )) { + // not ours + return; + } + } + + String hostName = null; + String contextName = null; + if (name.startsWith("//")) { + name = name.substring(2); + } + int slash = name.indexOf("/"); + if (slash != -1) { + hostName = name.substring(0, slash); + contextName = name.substring(slash); + } else { + return; + } + // Special case for the root context + if (contextName.equals("/")) { + contextName = ""; + } + if(log.isDebugEnabled()) + log.debug(sm.getString + ("mapperListener.unregisterContext", contextName)); + + mapper.removeContext(hostName, contextName); + + } + + + /** + * Register wrapper. + */ + private void registerWrapper(ObjectName objectName) + throws Exception { + + // If the domain is the same with ours or the engine + // name attribute is the same... - then it's ours + String targetDomain=objectName.getDomain(); + if( ! domain.equals( targetDomain )) { + try { + targetDomain=(String) mBeanServer.getAttribute(objectName, "engineName"); + } catch (Exception e) { + // Ignore + } + if( ! domain.equals( targetDomain )) { + // not ours + return; + } + + } + + String wrapperName = objectName.getKeyProperty("name"); + String name = objectName.getKeyProperty("WebModule"); + + String hostName = null; + String contextName = null; + if (name.startsWith("//")) { + name = name.substring(2); + } + int slash = name.indexOf("/"); + if (slash != -1) { + hostName = name.substring(0, slash); + contextName = name.substring(slash); + } else { + return; + } + // Special case for the root context + if (contextName.equals("/")) { + contextName = ""; + } + if(log.isDebugEnabled()) + log.debug(sm.getString + ("mapperListener.registerWrapper", + wrapperName, contextName)); + + String[] mappings = (String[]) + mBeanServer.invoke(objectName, "findMappings", null, null); + Object wrapper = + mBeanServer.invoke(objectName, "findMappingObject", null, null); + + for (int i = 0; i < mappings.length; i++) { + boolean jspWildCard = (wrapperName.equals("jsp") + && mappings[i].endsWith("/*")); + mapper.addWrapper(hostName, contextName, mappings[i], wrapper, + jspWildCard); + } + + } + + + + +} diff --git a/java/org/apache/catalina/connector/OutputBuffer.java b/java/org/apache/catalina/connector/OutputBuffer.java index 18a1a33b8..47b0ae041 100644 --- a/java/org/apache/catalina/connector/OutputBuffer.java +++ b/java/org/apache/catalina/connector/OutputBuffer.java @@ -1,579 +1,579 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.connector; - - -import java.io.IOException; -import java.io.Writer; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.HashMap; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.Response; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.C2BConverter; - - -/** - * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3 - * OutputBuffer, with the removal of some of the state handling (which in - * Coyote is mostly the Processor's responsability). - * - * @author Costin Manolache - * @author Remy Maucherat - */ -public class OutputBuffer extends Writer - implements ByteChunk.ByteOutputChannel { - - - // -------------------------------------------------------------- Constants - - - public static final String DEFAULT_ENCODING = - org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; - public static final int DEFAULT_BUFFER_SIZE = 8*1024; - - - // ----------------------------------------------------- Instance Variables - - - /** - * The byte buffer. - */ - private ByteChunk bb; - - - /** - * State of the output buffer. - */ - private boolean initial = true; - - - /** - * Number of bytes written. - */ - private int bytesWritten = 0; - - - /** - * Number of chars written. - */ - private int charsWritten = 0; - - - /** - * Flag which indicates if the output buffer is closed. - */ - private boolean closed = false; - - - /** - * Do a flush on the next operation. - */ - private boolean doFlush = false; - - - /** - * Byte chunk used to output bytes. - */ - private ByteChunk outputChunk = new ByteChunk(); - - - /** - * Encoding to use. - */ - private String enc; - - - /** - * Encoder is set. - */ - private boolean gotEnc = false; - - - /** - * List of encoders. - */ - protected HashMap encoders = new HashMap(); - - - /** - * Current char to byte converter. - */ - protected C2BConverter conv; - - - /** - * Associated Coyote response. - */ - private Response coyoteResponse; - - - /** - * Suspended flag. All output bytes will be swallowed if this is true. - */ - private boolean suspended = false; - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. Allocate the buffer with the default buffer size. - */ - public OutputBuffer() { - - this(DEFAULT_BUFFER_SIZE); - - } - - - /** - * Alternate constructor which allows specifying the initial buffer size. - * - * @param size Buffer size to use - */ - public OutputBuffer(int size) { - - bb = new ByteChunk(size); - bb.setLimit(size); - bb.setByteOutputChannel(this); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * Associated Coyote response. - * - * @param coyoteResponse Associated Coyote response - */ - public void setResponse(Response coyoteResponse) { - this.coyoteResponse = coyoteResponse; - } - - - /** - * Get associated Coyote response. - * - * @return the associated Coyote response - */ - public Response getResponse() { - return this.coyoteResponse; - } - - - /** - * Is the response output suspended ? - * - * @return suspended flag value - */ - public boolean isSuspended() { - return this.suspended; - } - - - /** - * Set the suspended flag. - * - * @param suspended New suspended flag value - */ - public void setSuspended(boolean suspended) { - this.suspended = suspended; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Recycle the output buffer. - */ - public void recycle() { - - initial = true; - bytesWritten = 0; - charsWritten = 0; - - bb.recycle(); - closed = false; - suspended = false; - - if (conv!= null) { - conv.recycle(); - } - - gotEnc = false; - enc = null; - - } - - - /** - * Clear cached encoders (to save memory for Comet requests). - */ - public void clearEncoders() { - encoders.clear(); - } - - - /** - * Close the output buffer. This tries to calculate the response size if - * the response has not been committed yet. - * - * @throws IOException An underlying IOException occurred - */ - public void close() - throws IOException { - - if (closed) - return; - if (suspended) - return; - - if ((!coyoteResponse.isCommitted()) - && (coyoteResponse.getContentLengthLong() == -1)) { - // If this didn't cause a commit of the response, the final content - // length can be calculated - if (!coyoteResponse.isCommitted()) { - coyoteResponse.setContentLength(bb.getLength()); - } - } - - doFlush(false); - closed = true; - - coyoteResponse.finish(); - - } - - - /** - * Flush bytes or chars contained in the buffer. - * - * @throws IOException An underlying IOException occurred - */ - public void flush() - throws IOException { - doFlush(true); - } - - - /** - * Flush bytes or chars contained in the buffer. - * - * @throws IOException An underlying IOException occurred - */ - protected void doFlush(boolean realFlush) - throws IOException { - - if (suspended) - return; - - doFlush = true; - if (initial) { - coyoteResponse.sendHeaders(); - initial = false; - } - if (bb.getLength() > 0) { - bb.flushBuffer(); - } - doFlush = false; - - if (realFlush) { - coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH, - coyoteResponse); - // If some exception occurred earlier, or if some IOE occurred - // here, notify the servlet with an IOE - if (coyoteResponse.isExceptionPresent()) { - throw new ClientAbortException - (coyoteResponse.getErrorException()); - } - } - - } - - - // ------------------------------------------------- Bytes Handling Methods - - - /** - * Sends the buffer data to the client output, checking the - * state of Response and calling the right interceptors. - * - * @param buf Byte buffer to be written to the response - * @param off Offset - * @param cnt Length - * - * @throws IOException An underlying IOException occurred - */ - public void realWriteBytes(byte buf[], int off, int cnt) - throws IOException { - - if (closed) - return; - if (coyoteResponse == null) - return; - - // If we really have something to write - if (cnt > 0) { - // real write to the adapter - outputChunk.setBytes(buf, off, cnt); - try { - coyoteResponse.doWrite(outputChunk); - } catch (IOException e) { - // An IOException on a write is almost always due to - // the remote client aborting the request. Wrap this - // so that it can be handled better by the error dispatcher. - throw new ClientAbortException(e); - } - } - - } - - - public void write(byte b[], int off, int len) throws IOException { - - if (suspended) - return; - - writeBytes(b, off, len); - - } - - - private void writeBytes(byte b[], int off, int len) - throws IOException { - - if (closed) - return; - - bb.append(b, off, len); - bytesWritten += len; - - // if called from within flush(), then immediately flush - // remaining bytes - if (doFlush) { - bb.flushBuffer(); - } - - } - - - public void writeByte(int b) - throws IOException { - - if (suspended) - return; - - bb.append((byte) b); - bytesWritten++; - - } - - - // ------------------------------------------------- Chars Handling Methods - - - public void write(int c) - throws IOException { - - if (suspended) - return; - - conv.convert((char) c); - conv.flushBuffer(); - charsWritten++; - - } - - - public void write(char c[]) - throws IOException { - - if (suspended) - return; - - write(c, 0, c.length); - - } - - - public void write(char c[], int off, int len) - throws IOException { - - if (suspended) - return; - - conv.convert(c, off, len); - conv.flushBuffer(); - charsWritten += len; - - } - - - /** - * Append a string to the buffer - */ - public void write(String s, int off, int len) - throws IOException { - - if (suspended) - return; - - charsWritten += len; - if (s == null) - s = "null"; - conv.convert(s, off, len); - conv.flushBuffer(); - - } - - - public void write(String s) - throws IOException { - - if (suspended) - return; - - if (s == null) - s = "null"; - conv.convert(s); - conv.flushBuffer(); - - } - - - public void setEncoding(String s) { - enc = s; - } - - - public void checkConverter() - throws IOException { - - if (!gotEnc) - setConverter(); - - } - - - protected void setConverter() - throws IOException { - - if (coyoteResponse != null) - enc = coyoteResponse.getCharacterEncoding(); - - gotEnc = true; - if (enc == null) - enc = DEFAULT_ENCODING; - conv = (C2BConverter) encoders.get(enc); - if (conv == null) { - - if (System.getSecurityManager() != null){ - try{ - conv = (C2BConverter)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - return new C2BConverter(bb, enc); - } - - } - ); - }catch(PrivilegedActionException ex){ - Exception e = ex.getException(); - if (e instanceof IOException) - throw (IOException)e; - } - } else { - conv = new C2BConverter(bb, enc); - } - - encoders.put(enc, conv); - - } - } - - - // -------------------- BufferedOutputStream compatibility - - - /** - * Real write - this buffer will be sent to the client - */ - public void flushBytes() - throws IOException { - - bb.flushBuffer(); - - } - - - public int getBytesWritten() { - return bytesWritten; - } - - - public int getCharsWritten() { - return charsWritten; - } - - - public int getContentWritten() { - return bytesWritten + charsWritten; - } - - - /** - * True if this buffer hasn't been used ( since recycle() ) - - * i.e. no chars or bytes have been added to the buffer. - */ - public boolean isNew() { - return (bytesWritten == 0) && (charsWritten == 0); - } - - - public void setBufferSize(int size) { - if (size > bb.getLimit()) {// ?????? - bb.setLimit(size); - } - } - - - public void reset() { - - bb.recycle(); - bytesWritten = 0; - charsWritten = 0; - gotEnc = false; - enc = null; - initial = true; - - } - - - public int getBufferSize() { - return bb.getLimit(); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.connector; + + +import java.io.IOException; +import java.io.Writer; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.Response; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.C2BConverter; + + +/** + * The buffer used by Tomcat response. This is a derivative of the Tomcat 3.3 + * OutputBuffer, with the removal of some of the state handling (which in + * Coyote is mostly the Processor's responsability). + * + * @author Costin Manolache + * @author Remy Maucherat + */ +public class OutputBuffer extends Writer + implements ByteChunk.ByteOutputChannel { + + + // -------------------------------------------------------------- Constants + + + public static final String DEFAULT_ENCODING = + org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING; + public static final int DEFAULT_BUFFER_SIZE = 8*1024; + + + // ----------------------------------------------------- Instance Variables + + + /** + * The byte buffer. + */ + private ByteChunk bb; + + + /** + * State of the output buffer. + */ + private boolean initial = true; + + + /** + * Number of bytes written. + */ + private int bytesWritten = 0; + + + /** + * Number of chars written. + */ + private int charsWritten = 0; + + + /** + * Flag which indicates if the output buffer is closed. + */ + private boolean closed = false; + + + /** + * Do a flush on the next operation. + */ + private boolean doFlush = false; + + + /** + * Byte chunk used to output bytes. + */ + private ByteChunk outputChunk = new ByteChunk(); + + + /** + * Encoding to use. + */ + private String enc; + + + /** + * Encoder is set. + */ + private boolean gotEnc = false; + + + /** + * List of encoders. + */ + protected HashMap encoders = new HashMap(); + + + /** + * Current char to byte converter. + */ + protected C2BConverter conv; + + + /** + * Associated Coyote response. + */ + private Response coyoteResponse; + + + /** + * Suspended flag. All output bytes will be swallowed if this is true. + */ + private boolean suspended = false; + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Allocate the buffer with the default buffer size. + */ + public OutputBuffer() { + + this(DEFAULT_BUFFER_SIZE); + + } + + + /** + * Alternate constructor which allows specifying the initial buffer size. + * + * @param size Buffer size to use + */ + public OutputBuffer(int size) { + + bb = new ByteChunk(size); + bb.setLimit(size); + bb.setByteOutputChannel(this); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * Associated Coyote response. + * + * @param coyoteResponse Associated Coyote response + */ + public void setResponse(Response coyoteResponse) { + this.coyoteResponse = coyoteResponse; + } + + + /** + * Get associated Coyote response. + * + * @return the associated Coyote response + */ + public Response getResponse() { + return this.coyoteResponse; + } + + + /** + * Is the response output suspended ? + * + * @return suspended flag value + */ + public boolean isSuspended() { + return this.suspended; + } + + + /** + * Set the suspended flag. + * + * @param suspended New suspended flag value + */ + public void setSuspended(boolean suspended) { + this.suspended = suspended; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the output buffer. + */ + public void recycle() { + + initial = true; + bytesWritten = 0; + charsWritten = 0; + + bb.recycle(); + closed = false; + suspended = false; + + if (conv!= null) { + conv.recycle(); + } + + gotEnc = false; + enc = null; + + } + + + /** + * Clear cached encoders (to save memory for Comet requests). + */ + public void clearEncoders() { + encoders.clear(); + } + + + /** + * Close the output buffer. This tries to calculate the response size if + * the response has not been committed yet. + * + * @throws IOException An underlying IOException occurred + */ + public void close() + throws IOException { + + if (closed) + return; + if (suspended) + return; + + if ((!coyoteResponse.isCommitted()) + && (coyoteResponse.getContentLengthLong() == -1)) { + // If this didn't cause a commit of the response, the final content + // length can be calculated + if (!coyoteResponse.isCommitted()) { + coyoteResponse.setContentLength(bb.getLength()); + } + } + + doFlush(false); + closed = true; + + coyoteResponse.finish(); + + } + + + /** + * Flush bytes or chars contained in the buffer. + * + * @throws IOException An underlying IOException occurred + */ + public void flush() + throws IOException { + doFlush(true); + } + + + /** + * Flush bytes or chars contained in the buffer. + * + * @throws IOException An underlying IOException occurred + */ + protected void doFlush(boolean realFlush) + throws IOException { + + if (suspended) + return; + + doFlush = true; + if (initial) { + coyoteResponse.sendHeaders(); + initial = false; + } + if (bb.getLength() > 0) { + bb.flushBuffer(); + } + doFlush = false; + + if (realFlush) { + coyoteResponse.action(ActionCode.ACTION_CLIENT_FLUSH, + coyoteResponse); + // If some exception occurred earlier, or if some IOE occurred + // here, notify the servlet with an IOE + if (coyoteResponse.isExceptionPresent()) { + throw new ClientAbortException + (coyoteResponse.getErrorException()); + } + } + + } + + + // ------------------------------------------------- Bytes Handling Methods + + + /** + * Sends the buffer data to the client output, checking the + * state of Response and calling the right interceptors. + * + * @param buf Byte buffer to be written to the response + * @param off Offset + * @param cnt Length + * + * @throws IOException An underlying IOException occurred + */ + public void realWriteBytes(byte buf[], int off, int cnt) + throws IOException { + + if (closed) + return; + if (coyoteResponse == null) + return; + + // If we really have something to write + if (cnt > 0) { + // real write to the adapter + outputChunk.setBytes(buf, off, cnt); + try { + coyoteResponse.doWrite(outputChunk); + } catch (IOException e) { + // An IOException on a write is almost always due to + // the remote client aborting the request. Wrap this + // so that it can be handled better by the error dispatcher. + throw new ClientAbortException(e); + } + } + + } + + + public void write(byte b[], int off, int len) throws IOException { + + if (suspended) + return; + + writeBytes(b, off, len); + + } + + + private void writeBytes(byte b[], int off, int len) + throws IOException { + + if (closed) + return; + + bb.append(b, off, len); + bytesWritten += len; + + // if called from within flush(), then immediately flush + // remaining bytes + if (doFlush) { + bb.flushBuffer(); + } + + } + + + public void writeByte(int b) + throws IOException { + + if (suspended) + return; + + bb.append((byte) b); + bytesWritten++; + + } + + + // ------------------------------------------------- Chars Handling Methods + + + public void write(int c) + throws IOException { + + if (suspended) + return; + + conv.convert((char) c); + conv.flushBuffer(); + charsWritten++; + + } + + + public void write(char c[]) + throws IOException { + + if (suspended) + return; + + write(c, 0, c.length); + + } + + + public void write(char c[], int off, int len) + throws IOException { + + if (suspended) + return; + + conv.convert(c, off, len); + conv.flushBuffer(); + charsWritten += len; + + } + + + /** + * Append a string to the buffer + */ + public void write(String s, int off, int len) + throws IOException { + + if (suspended) + return; + + charsWritten += len; + if (s == null) + s = "null"; + conv.convert(s, off, len); + conv.flushBuffer(); + + } + + + public void write(String s) + throws IOException { + + if (suspended) + return; + + if (s == null) + s = "null"; + conv.convert(s); + conv.flushBuffer(); + + } + + + public void setEncoding(String s) { + enc = s; + } + + + public void checkConverter() + throws IOException { + + if (!gotEnc) + setConverter(); + + } + + + protected void setConverter() + throws IOException { + + if (coyoteResponse != null) + enc = coyoteResponse.getCharacterEncoding(); + + gotEnc = true; + if (enc == null) + enc = DEFAULT_ENCODING; + conv = (C2BConverter) encoders.get(enc); + if (conv == null) { + + if (System.getSecurityManager() != null){ + try{ + conv = (C2BConverter)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + return new C2BConverter(bb, enc); + } + + } + ); + }catch(PrivilegedActionException ex){ + Exception e = ex.getException(); + if (e instanceof IOException) + throw (IOException)e; + } + } else { + conv = new C2BConverter(bb, enc); + } + + encoders.put(enc, conv); + + } + } + + + // -------------------- BufferedOutputStream compatibility + + + /** + * Real write - this buffer will be sent to the client + */ + public void flushBytes() + throws IOException { + + bb.flushBuffer(); + + } + + + public int getBytesWritten() { + return bytesWritten; + } + + + public int getCharsWritten() { + return charsWritten; + } + + + public int getContentWritten() { + return bytesWritten + charsWritten; + } + + + /** + * True if this buffer hasn't been used ( since recycle() ) - + * i.e. no chars or bytes have been added to the buffer. + */ + public boolean isNew() { + return (bytesWritten == 0) && (charsWritten == 0); + } + + + public void setBufferSize(int size) { + if (size > bb.getLimit()) {// ?????? + bb.setLimit(size); + } + } + + + public void reset() { + + bb.recycle(); + bytesWritten = 0; + charsWritten = 0; + gotEnc = false; + enc = null; + initial = true; + + } + + + public int getBufferSize() { + return bb.getLimit(); + } + + +} diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java index 48928227e..184179031 100644 --- a/java/org/apache/catalina/connector/Request.java +++ b/java/org/apache/catalina/connector/Request.java @@ -1,2550 +1,2550 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - - -import java.io.InputStream; -import java.io.IOException; -import java.io.BufferedReader; -import java.io.UnsupportedEncodingException; -import java.security.Principal; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; -import java.util.TreeMap; - -import javax.security.auth.Subject; -import javax.servlet.FilterChain; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequestAttributeEvent; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.tomcat.util.buf.B2CConverter; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.StringCache; -import org.apache.tomcat.util.http.Cookies; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.Parameters; -import org.apache.tomcat.util.http.ServerCookie; -import org.apache.tomcat.util.http.mapper.MappingData; - -import org.apache.coyote.ActionCode; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Host; -import org.apache.catalina.Manager; -import org.apache.catalina.Realm; -import org.apache.catalina.Session; -import org.apache.catalina.Wrapper; -import org.apache.catalina.core.ApplicationFilterFactory; -import org.apache.catalina.realm.GenericPrincipal; -import org.apache.catalina.util.Enumerator; -import org.apache.catalina.util.ParameterMap; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.util.StringParser; - - -/** - * Wrapper object for the Coyote request. - * - * @author Remy Maucherat - * @author Craig R. McClanahan - * @version $Revision: 382659 $ $Date: 2006-03-03 06:01:16 +0100 (ven., 03 mars 2006) $ - */ - -public class Request - implements HttpServletRequest { - - - // ----------------------------------------------------------- Constructors - - - static { - // Ensure that classes are loaded for SM - new StringCache.ByteEntry(); - new StringCache.CharEntry(); - } - - public Request() { - - formats[0].setTimeZone(GMT_ZONE); - formats[1].setTimeZone(GMT_ZONE); - formats[2].setTimeZone(GMT_ZONE); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * Coyote request. - */ - protected org.apache.coyote.Request coyoteRequest; - - /** - * Set the Coyote request. - * - * @param coyoteRequest The Coyote request - */ - public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) { - this.coyoteRequest = coyoteRequest; - inputBuffer.setRequest(coyoteRequest); - } - - /** - * Get the Coyote request. - */ - public org.apache.coyote.Request getCoyoteRequest() { - return (this.coyoteRequest); - } - - - // ----------------------------------------------------- Variables - - - protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The set of cookies associated with this Request. - */ - protected Cookie[] cookies = null; - - - /** - * The set of SimpleDateFormat formats to use in getDateHeader(). - * - * Notice that because SimpleDateFormat is not thread-safe, we can't - * declare formats[] as a static variable. - */ - protected SimpleDateFormat formats[] = { - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - - - /** - * The default Locale if none are specified. - */ - protected static Locale defaultLocale = Locale.getDefault(); - - - /** - * The attributes associated with this Request, keyed by attribute name. - */ - protected HashMap attributes = new HashMap(); - - - /** - * List of read only attributes for this Request. - */ - private HashMap readOnlyAttributes = new HashMap(); - - - /** - * The preferred Locales assocaited with this Request. - */ - protected ArrayList locales = new ArrayList(); - - - /** - * Internal notes associated with this request by Catalina components - * and event listeners. - */ - private transient HashMap notes = new HashMap(); - - - /** - * Authentication type. - */ - protected String authType = null; - - - /** - * The current dispatcher type. - */ - protected Object dispatcherType = null; - - - /** - * The associated input buffer. - */ - protected InputBuffer inputBuffer = new InputBuffer(); - - - /** - * ServletInputStream. - */ - protected CoyoteInputStream inputStream = - new CoyoteInputStream(inputBuffer); - - - /** - * Reader. - */ - protected CoyoteReader reader = new CoyoteReader(inputBuffer); - - - /** - * Using stream flag. - */ - protected boolean usingInputStream = false; - - - /** - * Using writer flag. - */ - protected boolean usingReader = false; - - - /** - * User principal. - */ - protected Principal userPrincipal = null; - - - /** - * Session parsed flag. - */ - protected boolean sessionParsed = false; - - - /** - * Request parameters parsed flag. - */ - protected boolean parametersParsed = false; - - - /** - * Cookies parsed flag. - */ - protected boolean cookiesParsed = false; - - - /** - * Secure flag. - */ - protected boolean secure = false; - - - /** - * The Subject associated with the current AccessControllerContext - */ - protected transient Subject subject = null; - - - /** - * Post data buffer. - */ - protected static int CACHED_POST_LEN = 8192; - protected byte[] postData = null; - - - /** - * Hash map used in the getParametersMap method. - */ - protected ParameterMap parameterMap = new ParameterMap(); - - - /** - * The currently active session for this request. - */ - protected Session session = null; - - - /** - * The current request dispatcher path. - */ - protected Object requestDispatcherPath = null; - - - /** - * Was the requested session ID received in a cookie? - */ - protected boolean requestedSessionCookie = false; - - - /** - * The requested session ID (if any) for this request. - */ - protected String requestedSessionId = null; - - - /** - * Was the requested session ID received in a URL? - */ - protected boolean requestedSessionURL = false; - - - /** - * Parse locales. - */ - protected boolean localesParsed = false; - - - /** - * The string parser we will use for parsing request lines. - */ - private StringParser parser = new StringParser(); - - - /** - * Local port - */ - protected int localPort = -1; - - /** - * Remote address. - */ - protected String remoteAddr = null; - - - /** - * Remote host. - */ - protected String remoteHost = null; - - - /** - * Remote port - */ - protected int remotePort = -1; - - /** - * Local address - */ - protected String localAddr = null; - - - /** - * Local address - */ - protected String localName = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Release all object references, and initialize instance variables, in - * preparation for reuse of this object. - */ - public void recycle() { - - context = null; - wrapper = null; - - dispatcherType = null; - requestDispatcherPath = null; - - authType = null; - inputBuffer.recycle(); - usingInputStream = false; - usingReader = false; - userPrincipal = null; - subject = null; - sessionParsed = false; - parametersParsed = false; - cookiesParsed = false; - locales.clear(); - localesParsed = false; - secure = false; - remoteAddr = null; - remoteHost = null; - remotePort = -1; - localPort = -1; - localAddr = null; - localName = null; - - attributes.clear(); - notes.clear(); - cookies = null; - - if (session != null) { - session.endAccess(); - } - session = null; - requestedSessionCookie = false; - requestedSessionId = null; - requestedSessionURL = false; - - if (Constants.SECURITY) { - parameterMap = new ParameterMap(); - } else { - parameterMap.setLocked(false); - parameterMap.clear(); - } - - mappingData.recycle(); - - if (Constants.SECURITY) { - if (facade != null) { - facade.clear(); - facade = null; - } - if (inputStream != null) { - inputStream.clear(); - inputStream = null; - } - if (reader != null) { - reader.clear(); - reader = null; - } - } - - } - - - /** - * Clear cached encoders (to save memory for Comet requests). - */ - public void clearEncoders() { - inputBuffer.clearEncoders(); - } - - - // -------------------------------------------------------- Request Methods - - - /** - * Associated Catalina connector. - */ - protected Connector connector; - - /** - * Return the Connector through which this Request was received. - */ - public Connector getConnector() { - return (this.connector); - } - - /** - * Set the Connector through which this Request was received. - * - * @param connector The new connector - */ - public void setConnector(Connector connector) { - this.connector = connector; - } - - - /** - * Associated context. - */ - protected Context context = null; - - /** - * Return the Context within which this Request is being processed. - */ - public Context getContext() { - return (this.context); - } - - - /** - * Set the Context within which this Request is being processed. This - * must be called as soon as the appropriate Context is identified, because - * it identifies the value to be returned by getContextPath(), - * and thus enables parsing of the request URI. - * - * @param context The newly associated Context - */ - public void setContext(Context context) { - this.context = context; - } - - - /** - * Filter chain associated with the request. - */ - protected FilterChain filterChain = null; - - /** - * Get filter chain associated with the request. - */ - public FilterChain getFilterChain() { - return (this.filterChain); - } - - /** - * Set filter chain associated with the request. - * - * @param filterChain new filter chain - */ - public void setFilterChain(FilterChain filterChain) { - this.filterChain = filterChain; - } - - - /** - * Return the Host within which this Request is being processed. - */ - public Host getHost() { - if (getContext() == null) - return null; - return (Host) getContext().getParent(); - //return ((Host) mappingData.host); - } - - - /** - * Set the Host within which this Request is being processed. This - * must be called as soon as the appropriate Host is identified, and - * before the Request is passed to a context. - * - * @param host The newly associated Host - */ - public void setHost(Host host) { - mappingData.host = host; - } - - - /** - * Descriptive information about this Request implementation. - */ - protected static final String info = - "org.apache.coyote.catalina.CoyoteRequest/1.0"; - - /** - * Return descriptive information about this Request implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - return (info); - } - - - /** - * Mapping data. - */ - protected MappingData mappingData = new MappingData(); - - /** - * Return mapping data. - */ - public MappingData getMappingData() { - return (mappingData); - } - - - /** - * The facade associated with this request. - */ - protected RequestFacade facade = null; - - /** - * Return the ServletRequest for which this object - * is the facade. This method must be implemented by a subclass. - */ - public HttpServletRequest getRequest() { - if (facade == null) { - facade = new RequestFacade(this); - } - return (facade); - } - - - /** - * The response with which this request is associated. - */ - protected org.apache.catalina.connector.Response response = null; - - /** - * Return the Response with which this Request is associated. - */ - public org.apache.catalina.connector.Response getResponse() { - return (this.response); - } - - /** - * Set the Response with which this Request is associated. - * - * @param response The new associated response - */ - public void setResponse(org.apache.catalina.connector.Response response) { - this.response = response; - } - - /** - * Return the input stream associated with this Request. - */ - public InputStream getStream() { - if (inputStream == null) { - inputStream = new CoyoteInputStream(inputBuffer); - } - return inputStream; - } - - /** - * Set the input stream associated with this Request. - * - * @param stream The new input stream - */ - public void setStream(InputStream stream) { - // Ignore - } - - - /** - * URI byte to char converter (not recycled). - */ - protected B2CConverter URIConverter = null; - - /** - * Return the URI converter. - */ - protected B2CConverter getURIConverter() { - return URIConverter; - } - - /** - * Set the URI converter. - * - * @param URIConverter the new URI connverter - */ - protected void setURIConverter(B2CConverter URIConverter) { - this.URIConverter = URIConverter; - } - - - /** - * Associated wrapper. - */ - protected Wrapper wrapper = null; - - /** - * Return the Wrapper within which this Request is being processed. - */ - public Wrapper getWrapper() { - return (this.wrapper); - } - - - /** - * Set the Wrapper within which this Request is being processed. This - * must be called as soon as the appropriate Wrapper is identified, and - * before the Request is ultimately passed to an application servlet. - * @param wrapper The newly associated Wrapper - */ - public void setWrapper(Wrapper wrapper) { - this.wrapper = wrapper; - } - - - // ------------------------------------------------- Request Public Methods - - - /** - * Create and return a ServletInputStream to read the content - * associated with this Request. - * - * @exception IOException if an input/output error occurs - */ - public ServletInputStream createInputStream() - throws IOException { - if (inputStream == null) { - inputStream = new CoyoteInputStream(inputBuffer); - } - return inputStream; - } - - - /** - * Perform whatever actions are required to flush and close the input - * stream or reader, in a single operation. - * - * @exception IOException if an input/output error occurs - */ - public void finishRequest() throws IOException { - // The reader and input stream don't need to be closed - } - - - /** - * Return the object bound with the specified name to the internal notes - * for this request, or null if no such binding exists. - * - * @param name Name of the note to be returned - */ - public Object getNote(String name) { - return (notes.get(name)); - } - - - /** - * Return an Iterator containing the String names of all notes bindings - * that exist for this request. - */ - public Iterator getNoteNames() { - return (notes.keySet().iterator()); - } - - - /** - * Remove any object bound to the specified name in the internal notes - * for this request. - * - * @param name Name of the note to be removed - */ - public void removeNote(String name) { - notes.remove(name); - } - - - /** - * Bind an object to a specified name in the internal notes associated - * with this request, replacing any existing binding for this name. - * - * @param name Name to which the object should be bound - * @param value Object to be bound to the specified name - */ - public void setNote(String name, Object value) { - notes.put(name, value); - } - - - /** - * Set the content length associated with this Request. - * - * @param length The new content length - */ - public void setContentLength(int length) { - // Not used - } - - - /** - * Set the content type (and optionally the character encoding) - * associated with this Request. For example, - * text/html; charset=ISO-8859-4. - * - * @param type The new content type - */ - public void setContentType(String type) { - // Not used - } - - - /** - * Set the protocol name and version associated with this Request. - * - * @param protocol Protocol name and version - */ - public void setProtocol(String protocol) { - // Not used - } - - - /** - * Set the IP address of the remote client associated with this Request. - * - * @param remoteAddr The remote IP address - */ - public void setRemoteAddr(String remoteAddr) { - // Not used - } - - - /** - * Set the fully qualified name of the remote client associated with this - * Request. - * - * @param remoteHost The remote host name - */ - public void setRemoteHost(String remoteHost) { - // Not used - } - - - /** - * Set the name of the scheme associated with this request. Typical values - * are http, https, and ftp. - * - * @param scheme The scheme - */ - public void setScheme(String scheme) { - // Not used - } - - - /** - * Set the value to be returned by isSecure() - * for this Request. - * - * @param secure The new isSecure value - */ - public void setSecure(boolean secure) { - this.secure = secure; - } - - - /** - * Set the name of the server (virtual host) to process this request. - * - * @param name The server name - */ - public void setServerName(String name) { - coyoteRequest.serverName().setString(name); - } - - - /** - * Set the port number of the server to process this request. - * - * @param port The server port - */ - public void setServerPort(int port) { - coyoteRequest.setServerPort(port); - } - - - // ------------------------------------------------- ServletRequest Methods - - - /** - * Return the specified request attribute if it exists; otherwise, return - * null. - * - * @param name Name of the request attribute to return - */ - public Object getAttribute(String name) { - - if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { - return (dispatcherType == null) - ? ApplicationFilterFactory.REQUEST_INTEGER - : dispatcherType; - } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { - return (requestDispatcherPath == null) - ? getRequestPathMB().toString() - : requestDispatcherPath.toString(); - } - - Object attr=attributes.get(name); - - if(attr!=null) - return(attr); - - attr = coyoteRequest.getAttribute(name); - if(attr != null) - return attr; - if( isSSLAttribute(name) ) { - coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, - coyoteRequest); - attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR); - if( attr != null) { - attributes.put(Globals.CERTIFICATES_ATTR, attr); - } - attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR); - if(attr != null) { - attributes.put(Globals.CIPHER_SUITE_ATTR, attr); - } - attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR); - if(attr != null) { - attributes.put(Globals.KEY_SIZE_ATTR, attr); - } - attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR); - if(attr != null) { - attributes.put(Globals.SSL_SESSION_ID_ATTR, attr); - } - attr = attributes.get(name); - } - return attr; - } - - - /** - * Test if a given name is one of the special Servlet-spec SSL attributes. - */ - static boolean isSSLAttribute(String name) { - return Globals.CERTIFICATES_ATTR.equals(name) || - Globals.CIPHER_SUITE_ATTR.equals(name) || - Globals.KEY_SIZE_ATTR.equals(name) || - Globals.SSL_SESSION_ID_ATTR.equals(name); - } - - /** - * Return the names of all request attributes for this Request, or an - * empty Enumeration if there are none. - */ - public Enumeration getAttributeNames() { - if (isSecure()) { - getAttribute(Globals.CERTIFICATES_ATTR); - } - return new Enumerator(attributes.keySet(), true); - } - - - /** - * Return the character encoding for this Request. - */ - public String getCharacterEncoding() { - return (coyoteRequest.getCharacterEncoding()); - } - - - /** - * Return the content length for this Request. - */ - public int getContentLength() { - return (coyoteRequest.getContentLength()); - } - - - /** - * Return the content type for this Request. - */ - public String getContentType() { - return (coyoteRequest.getContentType()); - } - - - /** - * Return the servlet input stream for this Request. The default - * implementation returns a servlet input stream created by - * createInputStream(). - * - * @exception IllegalStateException if getReader() has - * already been called for this request - * @exception IOException if an input/output error occurs - */ - public ServletInputStream getInputStream() throws IOException { - - if (usingReader) - throw new IllegalStateException - (sm.getString("coyoteRequest.getInputStream.ise")); - - usingInputStream = true; - if (inputStream == null) { - inputStream = new CoyoteInputStream(inputBuffer); - } - return inputStream; - - } - - - /** - * Return the preferred Locale that the client will accept content in, - * based on the value for the first Accept-Language header - * that was encountered. If the request did not specify a preferred - * language, the server's default Locale is returned. - */ - public Locale getLocale() { - - if (!localesParsed) - parseLocales(); - - if (locales.size() > 0) { - return ((Locale) locales.get(0)); - } else { - return (defaultLocale); - } - - } - - - /** - * Return the set of preferred Locales that the client will accept - * content in, based on the values for any Accept-Language - * headers that were encountered. If the request did not specify a - * preferred language, the server's default Locale is returned. - */ - public Enumeration getLocales() { - - if (!localesParsed) - parseLocales(); - - if (locales.size() > 0) - return (new Enumerator(locales)); - ArrayList results = new ArrayList(); - results.add(defaultLocale); - return (new Enumerator(results)); - - } - - - /** - * Return the value of the specified request parameter, if any; otherwise, - * return null. If there is more than one value defined, - * return only the first one. - * - * @param name Name of the desired request parameter - */ - public String getParameter(String name) { - - if (!parametersParsed) - parseParameters(); - - return coyoteRequest.getParameters().getParameter(name); - - } - - - - /** - * Returns a Map of the parameters of this request. - * Request parameters are extra information sent with the request. - * For HTTP servlets, parameters are contained in the query string - * or posted form data. - * - * @return A Map containing parameter names as keys - * and parameter values as map values. - */ - public Map getParameterMap() { - - if (parameterMap.isLocked()) - return parameterMap; - - Enumeration enumeration = getParameterNames(); - while (enumeration.hasMoreElements()) { - String name = enumeration.nextElement().toString(); - String[] values = getParameterValues(name); - parameterMap.put(name, values); - } - - parameterMap.setLocked(true); - - return parameterMap; - - } - - - /** - * Return the names of all defined request parameters for this request. - */ - public Enumeration getParameterNames() { - - if (!parametersParsed) - parseParameters(); - - return coyoteRequest.getParameters().getParameterNames(); - - } - - - /** - * Return the defined values for the specified request parameter, if any; - * otherwise, return null. - * - * @param name Name of the desired request parameter - */ - public String[] getParameterValues(String name) { - - if (!parametersParsed) - parseParameters(); - - return coyoteRequest.getParameters().getParameterValues(name); - - } - - - /** - * Return the protocol and version used to make this Request. - */ - public String getProtocol() { - return coyoteRequest.protocol().toString(); - } - - - /** - * Read the Reader wrapping the input stream for this Request. The - * default implementation wraps a BufferedReader around the - * servlet input stream returned by createInputStream(). - * - * @exception IllegalStateException if getInputStream() - * has already been called for this request - * @exception IOException if an input/output error occurs - */ - public BufferedReader getReader() throws IOException { - - if (usingInputStream) - throw new IllegalStateException - (sm.getString("coyoteRequest.getReader.ise")); - - usingReader = true; - inputBuffer.checkConverter(); - if (reader == null) { - reader = new CoyoteReader(inputBuffer); - } - return reader; - - } - - - /** - * Return the real path of the specified virtual path. - * - * @param path Path to be translated - * - * @deprecated As of version 2.1 of the Java Servlet API, use - * ServletContext.getRealPath(). - */ - public String getRealPath(String path) { - - if (context == null) - return (null); - ServletContext servletContext = context.getServletContext(); - if (servletContext == null) - return (null); - else { - try { - return (servletContext.getRealPath(path)); - } catch (IllegalArgumentException e) { - return (null); - } - } - - } - - - /** - * Return the remote IP address making this Request. - */ - public String getRemoteAddr() { - if (remoteAddr == null) { - coyoteRequest.action - (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest); - remoteAddr = coyoteRequest.remoteAddr().toString(); - } - return remoteAddr; - } - - - /** - * Return the remote host name making this Request. - */ - public String getRemoteHost() { - if (remoteHost == null) { - if (!connector.getEnableLookups()) { - remoteHost = getRemoteAddr(); - } else { - coyoteRequest.action - (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest); - remoteHost = coyoteRequest.remoteHost().toString(); - } - } - return remoteHost; - } - - /** - * Returns the Internet Protocol (IP) source port of the client - * or last proxy that sent the request. - */ - public int getRemotePort(){ - if (remotePort == -1) { - coyoteRequest.action - (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest); - remotePort = coyoteRequest.getRemotePort(); - } - return remotePort; - } - - /** - * Returns the host name of the Internet Protocol (IP) interface on - * which the request was received. - */ - public String getLocalName(){ - if (localName == null) { - coyoteRequest.action - (ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest); - localName = coyoteRequest.localName().toString(); - } - return localName; - } - - /** - * Returns the Internet Protocol (IP) address of the interface on - * which the request was received. - */ - public String getLocalAddr(){ - if (localAddr == null) { - coyoteRequest.action - (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest); - localAddr = coyoteRequest.localAddr().toString(); - } - return localAddr; - } - - - /** - * Returns the Internet Protocol (IP) port number of the interface - * on which the request was received. - */ - public int getLocalPort(){ - if (localPort == -1){ - coyoteRequest.action - (ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, coyoteRequest); - localPort = coyoteRequest.getLocalPort(); - } - return localPort; - } - - /** - * Return a RequestDispatcher that wraps the resource at the specified - * path, which may be interpreted as relative to the current request path. - * - * @param path Path of the resource to be wrapped - */ - public RequestDispatcher getRequestDispatcher(String path) { - - if (context == null) - return (null); - - // If the path is already context-relative, just pass it through - if (path == null) - return (null); - else if (path.startsWith("/")) - return (context.getServletContext().getRequestDispatcher(path)); - - // Convert a request-relative path to a context-relative one - String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); - if (servletPath == null) - servletPath = getServletPath(); - - // Add the path info, if there is any - String pathInfo = getPathInfo(); - String requestPath = null; - - if (pathInfo == null) { - requestPath = servletPath; - } else { - requestPath = servletPath + pathInfo; - } - - int pos = requestPath.lastIndexOf('/'); - String relative = null; - if (pos >= 0) { - relative = RequestUtil.normalize - (requestPath.substring(0, pos + 1) + path); - } else { - relative = RequestUtil.normalize(requestPath + path); - } - - return (context.getServletContext().getRequestDispatcher(relative)); - - } - - - /** - * Return the scheme used to make this Request. - */ - public String getScheme() { - return (coyoteRequest.scheme().toString()); - } - - - /** - * Return the server name responding to this Request. - */ - public String getServerName() { - return (coyoteRequest.serverName().toString()); - } - - - /** - * Return the server port responding to this Request. - */ - public int getServerPort() { - return (coyoteRequest.getServerPort()); - } - - - /** - * Was this request received on a secure connection? - */ - public boolean isSecure() { - return (secure); - } - - - /** - * Remove the specified request attribute if it exists. - * - * @param name Name of the request attribute to remove - */ - public void removeAttribute(String name) { - Object value = null; - boolean found = false; - - // Remove the specified attribute - // Check for read only attribute - // requests are per thread so synchronization unnecessary - if (readOnlyAttributes.containsKey(name)) { - return; - } - - // Pass special attributes to the native layer - if (name.startsWith("org.apache.tomcat.")) { - coyoteRequest.getAttributes().remove(name); - } - - found = attributes.containsKey(name); - if (found) { - value = attributes.get(name); - attributes.remove(name); - } else { - return; - } - - // Notify interested application event listeners - Object listeners[] = context.getApplicationEventListeners(); - if ((listeners == null) || (listeners.length == 0)) - return; - ServletRequestAttributeEvent event = - new ServletRequestAttributeEvent(context.getServletContext(), - getRequest(), name, value); - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof ServletRequestAttributeListener)) - continue; - ServletRequestAttributeListener listener = - (ServletRequestAttributeListener) listeners[i]; - try { - listener.attributeRemoved(event); - } catch (Throwable t) { - context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); - // Error valve will pick this execption up and display it to user - attributes.put( Globals.EXCEPTION_ATTR, t ); - } - } - } - - - /** - * Set the specified request attribute to the specified value. - * - * @param name Name of the request attribute to set - * @param value The associated value - */ - public void setAttribute(String name, Object value) { - - // Name cannot be null - if (name == null) - throw new IllegalArgumentException - (sm.getString("coyoteRequest.setAttribute.namenull")); - - // Null value is the same as removeAttribute() - if (value == null) { - removeAttribute(name); - return; - } - - if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { - dispatcherType = value; - return; - } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { - requestDispatcherPath = value; - return; - } - - Object oldValue = null; - boolean replaced = false; - - // Add or replace the specified attribute - // Check for read only attribute - // requests are per thread so synchronization unnecessary - if (readOnlyAttributes.containsKey(name)) { - return; - } - - oldValue = attributes.put(name, value); - if (oldValue != null) { - replaced = true; - } - - // Pass special attributes to the native layer - if (name.startsWith("org.apache.tomcat.")) { - coyoteRequest.setAttribute(name, value); - } - - // Notify interested application event listeners - Object listeners[] = context.getApplicationEventListeners(); - if ((listeners == null) || (listeners.length == 0)) - return; - ServletRequestAttributeEvent event = null; - if (replaced) - event = - new ServletRequestAttributeEvent(context.getServletContext(), - getRequest(), name, oldValue); - else - event = - new ServletRequestAttributeEvent(context.getServletContext(), - getRequest(), name, value); - - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof ServletRequestAttributeListener)) - continue; - ServletRequestAttributeListener listener = - (ServletRequestAttributeListener) listeners[i]; - try { - if (replaced) { - listener.attributeReplaced(event); - } else { - listener.attributeAdded(event); - } - } catch (Throwable t) { - context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); - // Error valve will pick this execption up and display it to user - attributes.put( Globals.EXCEPTION_ATTR, t ); - } - } - } - - - /** - * Overrides the name of the character encoding used in the body of - * this request. This method must be called prior to reading request - * parameters or reading input using getReader(). - * - * @param enc The character encoding to be used - * - * @exception UnsupportedEncodingException if the specified encoding - * is not supported - * - * @since Servlet 2.3 - */ - public void setCharacterEncoding(String enc) - throws UnsupportedEncodingException { - - if (usingReader) - return; - - // Ensure that the specified encoding is valid - byte buffer[] = new byte[1]; - buffer[0] = (byte) 'a'; - String dummy = new String(buffer, enc); - - // Save the validated encoding - coyoteRequest.setCharacterEncoding(enc); - - } - - - // ---------------------------------------------------- HttpRequest Methods - - - /** - * Add a Cookie to the set of Cookies associated with this Request. - * - * @param cookie The new cookie - */ - public void addCookie(Cookie cookie) { - - if (!cookiesParsed) - parseCookies(); - - int size = 0; - if (cookies != null) { - size = cookies.length; - } - - Cookie[] newCookies = new Cookie[size + 1]; - for (int i = 0; i < size; i++) { - newCookies[i] = cookies[i]; - } - newCookies[size] = cookie; - - cookies = newCookies; - - } - - - /** - * Add a Header to the set of Headers associated with this Request. - * - * @param name The new header name - * @param value The new header value - */ - public void addHeader(String name, String value) { - // Not used - } - - - /** - * Add a Locale to the set of preferred Locales for this Request. The - * first added Locale will be the first one returned by getLocales(). - * - * @param locale The new preferred Locale - */ - public void addLocale(Locale locale) { - locales.add(locale); - } - - - /** - * Add a parameter name and corresponding set of values to this Request. - * (This is used when restoring the original request on a form based - * login). - * - * @param name Name of this request parameter - * @param values Corresponding values for this request parameter - */ - public void addParameter(String name, String values[]) { - coyoteRequest.getParameters().addParameterValues(name, values); - } - - - /** - * Clear the collection of Cookies associated with this Request. - */ - public void clearCookies() { - cookiesParsed = true; - cookies = null; - } - - - /** - * Clear the collection of Headers associated with this Request. - */ - public void clearHeaders() { - // Not used - } - - - /** - * Clear the collection of Locales associated with this Request. - */ - public void clearLocales() { - locales.clear(); - } - - - /** - * Clear the collection of parameters associated with this Request. - */ - public void clearParameters() { - // Not used - } - - - /** - * Set the authentication type used for this request, if any; otherwise - * set the type to null. Typical values are "BASIC", - * "DIGEST", or "SSL". - * - * @param type The authentication type used - */ - public void setAuthType(String type) { - this.authType = type; - } - - - /** - * Set the context path for this Request. This will normally be called - * when the associated Context is mapping the Request to a particular - * Wrapper. - * - * @param path The context path - */ - public void setContextPath(String path) { - - if (path == null) { - mappingData.contextPath.setString(""); - } else { - mappingData.contextPath.setString(path); - } - - } - - - /** - * Set the HTTP request method used for this Request. - * - * @param method The request method - */ - public void setMethod(String method) { - // Not used - } - - - /** - * Set the query string for this Request. This will normally be called - * by the HTTP Connector, when it parses the request headers. - * - * @param query The query string - */ - public void setQueryString(String query) { - // Not used - } - - - /** - * Set the path information for this Request. This will normally be called - * when the associated Context is mapping the Request to a particular - * Wrapper. - * - * @param path The path information - */ - public void setPathInfo(String path) { - mappingData.pathInfo.setString(path); - } - - - /** - * Set a flag indicating whether or not the requested session ID for this - * request came in through a cookie. This is normally called by the - * HTTP Connector, when it parses the request headers. - * - * @param flag The new flag - */ - public void setRequestedSessionCookie(boolean flag) { - - this.requestedSessionCookie = flag; - - } - - - /** - * Set the requested session ID for this request. This is normally called - * by the HTTP Connector, when it parses the request headers. - * - * @param id The new session id - */ - public void setRequestedSessionId(String id) { - - this.requestedSessionId = id; - - } - - - /** - * Set a flag indicating whether or not the requested session ID for this - * request came in through a URL. This is normally called by the - * HTTP Connector, when it parses the request headers. - * - * @param flag The new flag - */ - public void setRequestedSessionURL(boolean flag) { - - this.requestedSessionURL = flag; - - } - - - /** - * Set the unparsed request URI for this Request. This will normally be - * called by the HTTP Connector, when it parses the request headers. - * - * @param uri The request URI - */ - public void setRequestURI(String uri) { - // Not used - } - - - /** - * Set the decoded request URI. - * - * @param uri The decoded request URI - */ - public void setDecodedRequestURI(String uri) { - // Not used - } - - - /** - * Get the decoded request URI. - * - * @return the URL decoded request URI - */ - public String getDecodedRequestURI() { - return (coyoteRequest.decodedURI().toString()); - } - - - /** - * Get the decoded request URI. - * - * @return the URL decoded request URI - */ - public MessageBytes getDecodedRequestURIMB() { - return (coyoteRequest.decodedURI()); - } - - - /** - * Set the servlet path for this Request. This will normally be called - * when the associated Context is mapping the Request to a particular - * Wrapper. - * - * @param path The servlet path - */ - public void setServletPath(String path) { - if (path != null) - mappingData.wrapperPath.setString(path); - } - - - /** - * Set the Principal who has been authenticated for this Request. This - * value is also used to calculate the value to be returned by the - * getRemoteUser() method. - * - * @param principal The user Principal - */ - public void setUserPrincipal(Principal principal) { - - if (System.getSecurityManager() != null){ - HttpSession session = getSession(false); - if ( (subject != null) && - (!subject.getPrincipals().contains(principal)) ){ - subject.getPrincipals().add(principal); - } else if (session != null && - session.getAttribute(Globals.SUBJECT_ATTR) == null) { - subject = new Subject(); - subject.getPrincipals().add(principal); - } - if (session != null){ - session.setAttribute(Globals.SUBJECT_ATTR, subject); - } - } - - this.userPrincipal = principal; - } - - - // --------------------------------------------- HttpServletRequest Methods - - - /** - * Return the authentication type used for this Request. - */ - public String getAuthType() { - return (authType); - } - - - /** - * Return the portion of the request URI used to select the Context - * of the Request. - */ - public String getContextPath() { - return (mappingData.contextPath.toString()); - } - - - /** - * Get the context path. - * - * @return the context path - */ - public MessageBytes getContextPathMB() { - return (mappingData.contextPath); - } - - - /** - * Return the set of Cookies received with this Request. - */ - public Cookie[] getCookies() { - - if (!cookiesParsed) - parseCookies(); - - return cookies; - - } - - - /** - * Set the set of cookies recieved with this Request. - */ - public void setCookies(Cookie[] cookies) { - - this.cookies = cookies; - - } - - - /** - * Return the value of the specified date header, if any; otherwise - * return -1. - * - * @param name Name of the requested date header - * - * @exception IllegalArgumentException if the specified header value - * cannot be converted to a date - */ - public long getDateHeader(String name) { - - String value = getHeader(name); - if (value == null) - return (-1L); - - // Attempt to convert the date header in a variety of formats - long result = FastHttpDateFormat.parseDate(value, formats); - if (result != (-1L)) { - return result; - } - throw new IllegalArgumentException(value); - - } - - - /** - * Return the first value of the specified header, if any; otherwise, - * return null - * - * @param name Name of the requested header - */ - public String getHeader(String name) { - return coyoteRequest.getHeader(name); - } - - - /** - * Return all of the values of the specified header, if any; otherwise, - * return an empty enumeration. - * - * @param name Name of the requested header - */ - public Enumeration getHeaders(String name) { - return coyoteRequest.getMimeHeaders().values(name); - } - - - /** - * Return the names of all headers received with this request. - */ - public Enumeration getHeaderNames() { - return coyoteRequest.getMimeHeaders().names(); - } - - - /** - * Return the value of the specified header as an integer, or -1 if there - * is no such header for this request. - * - * @param name Name of the requested header - * - * @exception IllegalArgumentException if the specified header value - * cannot be converted to an integer - */ - public int getIntHeader(String name) { - - String value = getHeader(name); - if (value == null) { - return (-1); - } else { - return (Integer.parseInt(value)); - } - - } - - - /** - * Return the HTTP request method used in this Request. - */ - public String getMethod() { - return coyoteRequest.method().toString(); - } - - - /** - * Return the path information associated with this Request. - */ - public String getPathInfo() { - return (mappingData.pathInfo.toString()); - } - - - /** - * Get the path info. - * - * @return the path info - */ - public MessageBytes getPathInfoMB() { - return (mappingData.pathInfo); - } - - - /** - * Return the extra path information for this request, translated - * to a real path. - */ - public String getPathTranslated() { - - if (context == null) - return (null); - - if (getPathInfo() == null) { - return (null); - } else { - return (context.getServletContext().getRealPath(getPathInfo())); - } - - } - - - /** - * Return the query string associated with this request. - */ - public String getQueryString() { - String queryString = coyoteRequest.queryString().toString(); - if (queryString == null || queryString.equals("")) { - return (null); - } else { - return queryString; - } - } - - - /** - * Return the name of the remote user that has been authenticated - * for this Request. - */ - public String getRemoteUser() { - - if (userPrincipal != null) { - return (userPrincipal.getName()); - } else { - return (null); - } - - } - - - /** - * Get the request path. - * - * @return the request path - */ - public MessageBytes getRequestPathMB() { - return (mappingData.requestPath); - } - - - /** - * Return the session identifier included in this request, if any. - */ - public String getRequestedSessionId() { - return (requestedSessionId); - } - - - /** - * Return the request URI for this request. - */ - public String getRequestURI() { - return coyoteRequest.requestURI().toString(); - } - - - /** - * Reconstructs the URL the client used to make the request. - * The returned URL contains a protocol, server name, port - * number, and server path, but it does not include query - * string parameters. - *

    - * Because this method returns a StringBuffer, - * not a String, you can modify the URL easily, - * for example, to append query parameters. - *

    - * This method is useful for creating redirect messages and - * for reporting errors. - * - * @return A StringBuffer object containing the - * reconstructed URL - */ - public StringBuffer getRequestURL() { - - StringBuffer url = new StringBuffer(); - String scheme = getScheme(); - int port = getServerPort(); - if (port < 0) - port = 80; // Work around java.net.URL bug - - url.append(scheme); - url.append("://"); - url.append(getServerName()); - if ((scheme.equals("http") && (port != 80)) - || (scheme.equals("https") && (port != 443))) { - url.append(':'); - url.append(port); - } - url.append(getRequestURI()); - - return (url); - - } - - - /** - * Return the portion of the request URI used to select the servlet - * that will process this request. - */ - public String getServletPath() { - return (mappingData.wrapperPath.toString()); - } - - - /** - * Get the servlet path. - * - * @return the servlet path - */ - public MessageBytes getServletPathMB() { - return (mappingData.wrapperPath); - } - - - /** - * Return the session associated with this Request, creating one - * if necessary. - */ - public HttpSession getSession() { - Session session = doGetSession(true); - if (session != null) { - return session.getSession(); - } else { - return null; - } - } - - - /** - * Return the session associated with this Request, creating one - * if necessary and requested. - * - * @param create Create a new session if one does not exist - */ - public HttpSession getSession(boolean create) { - Session session = doGetSession(create); - if (session != null) { - return session.getSession(); - } else { - return null; - } - } - - - /** - * Return true if the session identifier included in this - * request came from a cookie. - */ - public boolean isRequestedSessionIdFromCookie() { - - if (requestedSessionId != null) - return (requestedSessionCookie); - else - return (false); - - } - - - /** - * Return true if the session identifier included in this - * request came from the request URI. - */ - public boolean isRequestedSessionIdFromURL() { - - if (requestedSessionId != null) - return (requestedSessionURL); - else - return (false); - - } - - - /** - * Return true if the session identifier included in this - * request came from the request URI. - * - * @deprecated As of Version 2.1 of the Java Servlet API, use - * isRequestedSessionIdFromURL() instead. - */ - public boolean isRequestedSessionIdFromUrl() { - return (isRequestedSessionIdFromURL()); - } - - - /** - * Return true if the session identifier included in this - * request identifies a valid session. - */ - public boolean isRequestedSessionIdValid() { - - if (requestedSessionId == null) - return (false); - if (context == null) - return (false); - Manager manager = context.getManager(); - if (manager == null) - return (false); - Session session = null; - try { - session = manager.findSession(requestedSessionId); - } catch (IOException e) { - session = null; - } - if ((session != null) && session.isValid()) - return (true); - else - return (false); - - } - - - /** - * Return true if the authenticated user principal - * possesses the specified role name. - * - * @param role Role name to be validated - */ - public boolean isUserInRole(String role) { - - // Have we got an authenticated principal at all? - if (userPrincipal == null) - return (false); - - // Identify the Realm we will use for checking role assignmenets - if (context == null) - return (false); - Realm realm = context.getRealm(); - if (realm == null) - return (false); - - // Check for a role alias defined in a element - if (wrapper != null) { - String realRole = wrapper.findSecurityReference(role); - if ((realRole != null) && - realm.hasRole(userPrincipal, realRole)) - return (true); - } - - // Check for a role defined directly as a - return (realm.hasRole(userPrincipal, role)); - - } - - - /** - * Return the principal that has been authenticated for this Request. - */ - public Principal getPrincipal() { - return (userPrincipal); - } - - - /** - * Return the principal that has been authenticated for this Request. - */ - public Principal getUserPrincipal() { - if (userPrincipal instanceof GenericPrincipal) { - return ((GenericPrincipal) userPrincipal).getUserPrincipal(); - } else { - return (userPrincipal); - } - } - - - /** - * Return the session associated with this Request, creating one - * if necessary. - */ - public Session getSessionInternal() { - return doGetSession(true); - } - - - /** - * Return the session associated with this Request, creating one - * if necessary and requested. - * - * @param create Create a new session if one does not exist - */ - public Session getSessionInternal(boolean create) { - return doGetSession(create); - } - - - // ------------------------------------------------------ Protected Methods - - - protected Session doGetSession(boolean create) { - - // There cannot be a session if no context has been assigned yet - if (context == null) - return (null); - - // Return the current session if it exists and is valid - if ((session != null) && !session.isValid()) - session = null; - if (session != null) - return (session); - - // Return the requested session if it exists and is valid - Manager manager = null; - if (context != null) - manager = context.getManager(); - if (manager == null) - return (null); // Sessions are not supported - if (requestedSessionId != null) { - try { - session = manager.findSession(requestedSessionId); - } catch (IOException e) { - session = null; - } - if ((session != null) && !session.isValid()) - session = null; - if (session != null) { - session.access(); - return (session); - } - } - - // Create a new session if requested and the response is not committed - if (!create) - return (null); - if ((context != null) && (response != null) && - context.getCookies() && - response.getResponse().isCommitted()) { - throw new IllegalStateException - (sm.getString("coyoteRequest.sessionCreateCommitted")); - } - - // Attempt to reuse session id if one was submitted in a cookie - // Do not reuse the session id if it is from a URL, to prevent possible - // phishing attacks - if (connector.getEmptySessionPath() - && isRequestedSessionIdFromCookie()) { - session = manager.createSession(getRequestedSessionId()); - } else { - session = manager.createSession(null); - } - - // Creating a new session cookie based on that session - if ((session != null) && (getContext() != null) - && getContext().getCookies()) { - Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, - session.getIdInternal()); - configureSessionCookie(cookie); - response.addCookieInternal(cookie); - } - - if (session != null) { - session.access(); - return (session); - } else { - return (null); - } - - } - - /** - * Configures the given JSESSIONID cookie. - * - * @param cookie The JSESSIONID cookie to be configured - */ - protected void configureSessionCookie(Cookie cookie) { - cookie.setMaxAge(-1); - String contextPath = null; - if (!connector.getEmptySessionPath() && (getContext() != null)) { - contextPath = getContext().getEncodedPath(); - } - if ((contextPath != null) && (contextPath.length() > 0)) { - cookie.setPath(contextPath); - } else { - cookie.setPath("/"); - } - if (isSecure()) { - cookie.setSecure(true); - } - } - - /** - * Parse cookies. - */ - protected void parseCookies() { - - cookiesParsed = true; - - Cookies serverCookies = coyoteRequest.getCookies(); - int count = serverCookies.getCookieCount(); - if (count <= 0) - return; - - cookies = new Cookie[count]; - - int idx=0; - for (int i = 0; i < count; i++) { - ServerCookie scookie = serverCookies.getCookie(i); - try { - Cookie cookie = new Cookie(scookie.getName().toString(), - scookie.getValue().toString()); - cookie.setPath(scookie.getPath().toString()); - cookie.setVersion(scookie.getVersion()); - String domain = scookie.getDomain().toString(); - if (domain != null) { - cookie.setDomain(scookie.getDomain().toString()); - } - cookies[idx++] = cookie; - } catch(IllegalArgumentException e) { - // Ignore bad cookie - } - } - if( idx < count ) { - Cookie [] ncookies = new Cookie[idx]; - System.arraycopy(cookies, 0, ncookies, 0, idx); - cookies = ncookies; - } - - } - - /** - * Parse request parameters. - */ - protected void parseParameters() { - - parametersParsed = true; - - Parameters parameters = coyoteRequest.getParameters(); - - // getCharacterEncoding() may have been overridden to search for - // hidden form field containing request encoding - String enc = getCharacterEncoding(); - - boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); - if (enc != null) { - parameters.setEncoding(enc); - if (useBodyEncodingForURI) { - parameters.setQueryStringEncoding(enc); - } - } else { - parameters.setEncoding - (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); - if (useBodyEncodingForURI) { - parameters.setQueryStringEncoding - (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); - } - } - - parameters.handleQueryParameters(); - - if (usingInputStream || usingReader) - return; - - if (!getMethod().equalsIgnoreCase("POST")) - return; - - String contentType = getContentType(); - if (contentType == null) - contentType = ""; - int semicolon = contentType.indexOf(';'); - if (semicolon >= 0) { - contentType = contentType.substring(0, semicolon).trim(); - } else { - contentType = contentType.trim(); - } - if (!("application/x-www-form-urlencoded".equals(contentType))) - return; - - int len = getContentLength(); - - if (len > 0) { - int maxPostSize = connector.getMaxPostSize(); - if ((maxPostSize > 0) && (len > maxPostSize)) { - context.getLogger().info - (sm.getString("coyoteRequest.postTooLarge")); - throw new IllegalStateException("Post too large"); - } - try { - byte[] formData = null; - if (len < CACHED_POST_LEN) { - if (postData == null) - postData = new byte[CACHED_POST_LEN]; - formData = postData; - } else { - formData = new byte[len]; - } - int actualLen = readPostBody(formData, len); - if (actualLen == len) { - parameters.processParameters(formData, 0, len); - } - } catch (Throwable t) { - ; // Ignore - } - } - - } - - - /** - * Read post body in an array. - */ - protected int readPostBody(byte body[], int len) - throws IOException { - - int offset = 0; - do { - int inputLen = getStream().read(body, offset, len - offset); - if (inputLen <= 0) { - return offset; - } - offset += inputLen; - } while ((len - offset) > 0); - return len; - - } - - - /** - * Parse request locales. - */ - protected void parseLocales() { - - localesParsed = true; - - Enumeration values = getHeaders("accept-language"); - - while (values.hasMoreElements()) { - String value = values.nextElement().toString(); - parseLocalesHeader(value); - } - - } - - - /** - * Parse accept-language header value. - */ - protected void parseLocalesHeader(String value) { - - // Store the accumulated languages that have been requested in - // a local collection, sorted by the quality value (so we can - // add Locales in descending order). The values will be ArrayLists - // containing the corresponding Locales to be added - TreeMap locales = new TreeMap(); - - // Preprocess the value to remove all whitespace - int white = value.indexOf(' '); - if (white < 0) - white = value.indexOf('\t'); - if (white >= 0) { - StringBuffer sb = new StringBuffer(); - int len = value.length(); - for (int i = 0; i < len; i++) { - char ch = value.charAt(i); - if ((ch != ' ') && (ch != '\t')) - sb.append(ch); - } - value = sb.toString(); - } - - // Process each comma-delimited language specification - parser.setString(value); // ASSERT: parser is available to us - int length = parser.getLength(); - while (true) { - - // Extract the next comma-delimited entry - int start = parser.getIndex(); - if (start >= length) - break; - int end = parser.findChar(','); - String entry = parser.extract(start, end).trim(); - parser.advance(); // For the following entry - - // Extract the quality factor for this entry - double quality = 1.0; - int semi = entry.indexOf(";q="); - if (semi >= 0) { - try { - quality = Double.parseDouble(entry.substring(semi + 3)); - } catch (NumberFormatException e) { - quality = 0.0; - } - entry = entry.substring(0, semi); - } - - // Skip entries we are not going to keep track of - if (quality < 0.00005) - continue; // Zero (or effectively zero) quality factors - if ("*".equals(entry)) - continue; // FIXME - "*" entries are not handled - - // Extract the language and country for this entry - String language = null; - String country = null; - String variant = null; - int dash = entry.indexOf('-'); - if (dash < 0) { - language = entry; - country = ""; - variant = ""; - } else { - language = entry.substring(0, dash); - country = entry.substring(dash + 1); - int vDash = country.indexOf('-'); - if (vDash > 0) { - String cTemp = country.substring(0, vDash); - variant = country.substring(vDash + 1); - country = cTemp; - } else { - variant = ""; - } - } - - // Add a new Locale to the list of Locales for this quality level - Locale locale = new Locale(language, country, variant); - Double key = new Double(-quality); // Reverse the order - ArrayList values = (ArrayList) locales.get(key); - if (values == null) { - values = new ArrayList(); - locales.put(key, values); - } - values.add(locale); - - } - - // Process the quality values in highest->lowest order (due to - // negating the Double value when creating the key) - Iterator keys = locales.keySet().iterator(); - while (keys.hasNext()) { - Double key = (Double) keys.next(); - ArrayList list = (ArrayList) locales.get(key); - Iterator values = list.iterator(); - while (values.hasNext()) { - Locale locale = (Locale) values.next(); - addLocale(locale); - } - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + + +import java.io.InputStream; +import java.io.IOException; +import java.io.BufferedReader; +import java.io.UnsupportedEncodingException; +import java.security.Principal; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.TreeMap; + +import javax.security.auth.Subject; +import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequestAttributeEvent; +import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.tomcat.util.buf.B2CConverter; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.buf.StringCache; +import org.apache.tomcat.util.http.Cookies; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.Parameters; +import org.apache.tomcat.util.http.ServerCookie; +import org.apache.tomcat.util.http.mapper.MappingData; + +import org.apache.coyote.ActionCode; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Host; +import org.apache.catalina.Manager; +import org.apache.catalina.Realm; +import org.apache.catalina.Session; +import org.apache.catalina.Wrapper; +import org.apache.catalina.core.ApplicationFilterFactory; +import org.apache.catalina.realm.GenericPrincipal; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.ParameterMap; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.util.StringParser; + + +/** + * Wrapper object for the Coyote request. + * + * @author Remy Maucherat + * @author Craig R. McClanahan + * @version $Revision: 382659 $ $Date: 2006-03-03 06:01:16 +0100 (ven., 03 mars 2006) $ + */ + +public class Request + implements HttpServletRequest { + + + // ----------------------------------------------------------- Constructors + + + static { + // Ensure that classes are loaded for SM + new StringCache.ByteEntry(); + new StringCache.CharEntry(); + } + + public Request() { + + formats[0].setTimeZone(GMT_ZONE); + formats[1].setTimeZone(GMT_ZONE); + formats[2].setTimeZone(GMT_ZONE); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * Coyote request. + */ + protected org.apache.coyote.Request coyoteRequest; + + /** + * Set the Coyote request. + * + * @param coyoteRequest The Coyote request + */ + public void setCoyoteRequest(org.apache.coyote.Request coyoteRequest) { + this.coyoteRequest = coyoteRequest; + inputBuffer.setRequest(coyoteRequest); + } + + /** + * Get the Coyote request. + */ + public org.apache.coyote.Request getCoyoteRequest() { + return (this.coyoteRequest); + } + + + // ----------------------------------------------------- Variables + + + protected static final TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The set of cookies associated with this Request. + */ + protected Cookie[] cookies = null; + + + /** + * The set of SimpleDateFormat formats to use in getDateHeader(). + * + * Notice that because SimpleDateFormat is not thread-safe, we can't + * declare formats[] as a static variable. + */ + protected SimpleDateFormat formats[] = { + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) + }; + + + /** + * The default Locale if none are specified. + */ + protected static Locale defaultLocale = Locale.getDefault(); + + + /** + * The attributes associated with this Request, keyed by attribute name. + */ + protected HashMap attributes = new HashMap(); + + + /** + * List of read only attributes for this Request. + */ + private HashMap readOnlyAttributes = new HashMap(); + + + /** + * The preferred Locales assocaited with this Request. + */ + protected ArrayList locales = new ArrayList(); + + + /** + * Internal notes associated with this request by Catalina components + * and event listeners. + */ + private transient HashMap notes = new HashMap(); + + + /** + * Authentication type. + */ + protected String authType = null; + + + /** + * The current dispatcher type. + */ + protected Object dispatcherType = null; + + + /** + * The associated input buffer. + */ + protected InputBuffer inputBuffer = new InputBuffer(); + + + /** + * ServletInputStream. + */ + protected CoyoteInputStream inputStream = + new CoyoteInputStream(inputBuffer); + + + /** + * Reader. + */ + protected CoyoteReader reader = new CoyoteReader(inputBuffer); + + + /** + * Using stream flag. + */ + protected boolean usingInputStream = false; + + + /** + * Using writer flag. + */ + protected boolean usingReader = false; + + + /** + * User principal. + */ + protected Principal userPrincipal = null; + + + /** + * Session parsed flag. + */ + protected boolean sessionParsed = false; + + + /** + * Request parameters parsed flag. + */ + protected boolean parametersParsed = false; + + + /** + * Cookies parsed flag. + */ + protected boolean cookiesParsed = false; + + + /** + * Secure flag. + */ + protected boolean secure = false; + + + /** + * The Subject associated with the current AccessControllerContext + */ + protected transient Subject subject = null; + + + /** + * Post data buffer. + */ + protected static int CACHED_POST_LEN = 8192; + protected byte[] postData = null; + + + /** + * Hash map used in the getParametersMap method. + */ + protected ParameterMap parameterMap = new ParameterMap(); + + + /** + * The currently active session for this request. + */ + protected Session session = null; + + + /** + * The current request dispatcher path. + */ + protected Object requestDispatcherPath = null; + + + /** + * Was the requested session ID received in a cookie? + */ + protected boolean requestedSessionCookie = false; + + + /** + * The requested session ID (if any) for this request. + */ + protected String requestedSessionId = null; + + + /** + * Was the requested session ID received in a URL? + */ + protected boolean requestedSessionURL = false; + + + /** + * Parse locales. + */ + protected boolean localesParsed = false; + + + /** + * The string parser we will use for parsing request lines. + */ + private StringParser parser = new StringParser(); + + + /** + * Local port + */ + protected int localPort = -1; + + /** + * Remote address. + */ + protected String remoteAddr = null; + + + /** + * Remote host. + */ + protected String remoteHost = null; + + + /** + * Remote port + */ + protected int remotePort = -1; + + /** + * Local address + */ + protected String localAddr = null; + + + /** + * Local address + */ + protected String localName = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Release all object references, and initialize instance variables, in + * preparation for reuse of this object. + */ + public void recycle() { + + context = null; + wrapper = null; + + dispatcherType = null; + requestDispatcherPath = null; + + authType = null; + inputBuffer.recycle(); + usingInputStream = false; + usingReader = false; + userPrincipal = null; + subject = null; + sessionParsed = false; + parametersParsed = false; + cookiesParsed = false; + locales.clear(); + localesParsed = false; + secure = false; + remoteAddr = null; + remoteHost = null; + remotePort = -1; + localPort = -1; + localAddr = null; + localName = null; + + attributes.clear(); + notes.clear(); + cookies = null; + + if (session != null) { + session.endAccess(); + } + session = null; + requestedSessionCookie = false; + requestedSessionId = null; + requestedSessionURL = false; + + if (Constants.SECURITY) { + parameterMap = new ParameterMap(); + } else { + parameterMap.setLocked(false); + parameterMap.clear(); + } + + mappingData.recycle(); + + if (Constants.SECURITY) { + if (facade != null) { + facade.clear(); + facade = null; + } + if (inputStream != null) { + inputStream.clear(); + inputStream = null; + } + if (reader != null) { + reader.clear(); + reader = null; + } + } + + } + + + /** + * Clear cached encoders (to save memory for Comet requests). + */ + public void clearEncoders() { + inputBuffer.clearEncoders(); + } + + + // -------------------------------------------------------- Request Methods + + + /** + * Associated Catalina connector. + */ + protected Connector connector; + + /** + * Return the Connector through which this Request was received. + */ + public Connector getConnector() { + return (this.connector); + } + + /** + * Set the Connector through which this Request was received. + * + * @param connector The new connector + */ + public void setConnector(Connector connector) { + this.connector = connector; + } + + + /** + * Associated context. + */ + protected Context context = null; + + /** + * Return the Context within which this Request is being processed. + */ + public Context getContext() { + return (this.context); + } + + + /** + * Set the Context within which this Request is being processed. This + * must be called as soon as the appropriate Context is identified, because + * it identifies the value to be returned by getContextPath(), + * and thus enables parsing of the request URI. + * + * @param context The newly associated Context + */ + public void setContext(Context context) { + this.context = context; + } + + + /** + * Filter chain associated with the request. + */ + protected FilterChain filterChain = null; + + /** + * Get filter chain associated with the request. + */ + public FilterChain getFilterChain() { + return (this.filterChain); + } + + /** + * Set filter chain associated with the request. + * + * @param filterChain new filter chain + */ + public void setFilterChain(FilterChain filterChain) { + this.filterChain = filterChain; + } + + + /** + * Return the Host within which this Request is being processed. + */ + public Host getHost() { + if (getContext() == null) + return null; + return (Host) getContext().getParent(); + //return ((Host) mappingData.host); + } + + + /** + * Set the Host within which this Request is being processed. This + * must be called as soon as the appropriate Host is identified, and + * before the Request is passed to a context. + * + * @param host The newly associated Host + */ + public void setHost(Host host) { + mappingData.host = host; + } + + + /** + * Descriptive information about this Request implementation. + */ + protected static final String info = + "org.apache.coyote.catalina.CoyoteRequest/1.0"; + + /** + * Return descriptive information about this Request implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + return (info); + } + + + /** + * Mapping data. + */ + protected MappingData mappingData = new MappingData(); + + /** + * Return mapping data. + */ + public MappingData getMappingData() { + return (mappingData); + } + + + /** + * The facade associated with this request. + */ + protected RequestFacade facade = null; + + /** + * Return the ServletRequest for which this object + * is the facade. This method must be implemented by a subclass. + */ + public HttpServletRequest getRequest() { + if (facade == null) { + facade = new RequestFacade(this); + } + return (facade); + } + + + /** + * The response with which this request is associated. + */ + protected org.apache.catalina.connector.Response response = null; + + /** + * Return the Response with which this Request is associated. + */ + public org.apache.catalina.connector.Response getResponse() { + return (this.response); + } + + /** + * Set the Response with which this Request is associated. + * + * @param response The new associated response + */ + public void setResponse(org.apache.catalina.connector.Response response) { + this.response = response; + } + + /** + * Return the input stream associated with this Request. + */ + public InputStream getStream() { + if (inputStream == null) { + inputStream = new CoyoteInputStream(inputBuffer); + } + return inputStream; + } + + /** + * Set the input stream associated with this Request. + * + * @param stream The new input stream + */ + public void setStream(InputStream stream) { + // Ignore + } + + + /** + * URI byte to char converter (not recycled). + */ + protected B2CConverter URIConverter = null; + + /** + * Return the URI converter. + */ + protected B2CConverter getURIConverter() { + return URIConverter; + } + + /** + * Set the URI converter. + * + * @param URIConverter the new URI connverter + */ + protected void setURIConverter(B2CConverter URIConverter) { + this.URIConverter = URIConverter; + } + + + /** + * Associated wrapper. + */ + protected Wrapper wrapper = null; + + /** + * Return the Wrapper within which this Request is being processed. + */ + public Wrapper getWrapper() { + return (this.wrapper); + } + + + /** + * Set the Wrapper within which this Request is being processed. This + * must be called as soon as the appropriate Wrapper is identified, and + * before the Request is ultimately passed to an application servlet. + * @param wrapper The newly associated Wrapper + */ + public void setWrapper(Wrapper wrapper) { + this.wrapper = wrapper; + } + + + // ------------------------------------------------- Request Public Methods + + + /** + * Create and return a ServletInputStream to read the content + * associated with this Request. + * + * @exception IOException if an input/output error occurs + */ + public ServletInputStream createInputStream() + throws IOException { + if (inputStream == null) { + inputStream = new CoyoteInputStream(inputBuffer); + } + return inputStream; + } + + + /** + * Perform whatever actions are required to flush and close the input + * stream or reader, in a single operation. + * + * @exception IOException if an input/output error occurs + */ + public void finishRequest() throws IOException { + // The reader and input stream don't need to be closed + } + + + /** + * Return the object bound with the specified name to the internal notes + * for this request, or null if no such binding exists. + * + * @param name Name of the note to be returned + */ + public Object getNote(String name) { + return (notes.get(name)); + } + + + /** + * Return an Iterator containing the String names of all notes bindings + * that exist for this request. + */ + public Iterator getNoteNames() { + return (notes.keySet().iterator()); + } + + + /** + * Remove any object bound to the specified name in the internal notes + * for this request. + * + * @param name Name of the note to be removed + */ + public void removeNote(String name) { + notes.remove(name); + } + + + /** + * Bind an object to a specified name in the internal notes associated + * with this request, replacing any existing binding for this name. + * + * @param name Name to which the object should be bound + * @param value Object to be bound to the specified name + */ + public void setNote(String name, Object value) { + notes.put(name, value); + } + + + /** + * Set the content length associated with this Request. + * + * @param length The new content length + */ + public void setContentLength(int length) { + // Not used + } + + + /** + * Set the content type (and optionally the character encoding) + * associated with this Request. For example, + * text/html; charset=ISO-8859-4. + * + * @param type The new content type + */ + public void setContentType(String type) { + // Not used + } + + + /** + * Set the protocol name and version associated with this Request. + * + * @param protocol Protocol name and version + */ + public void setProtocol(String protocol) { + // Not used + } + + + /** + * Set the IP address of the remote client associated with this Request. + * + * @param remoteAddr The remote IP address + */ + public void setRemoteAddr(String remoteAddr) { + // Not used + } + + + /** + * Set the fully qualified name of the remote client associated with this + * Request. + * + * @param remoteHost The remote host name + */ + public void setRemoteHost(String remoteHost) { + // Not used + } + + + /** + * Set the name of the scheme associated with this request. Typical values + * are http, https, and ftp. + * + * @param scheme The scheme + */ + public void setScheme(String scheme) { + // Not used + } + + + /** + * Set the value to be returned by isSecure() + * for this Request. + * + * @param secure The new isSecure value + */ + public void setSecure(boolean secure) { + this.secure = secure; + } + + + /** + * Set the name of the server (virtual host) to process this request. + * + * @param name The server name + */ + public void setServerName(String name) { + coyoteRequest.serverName().setString(name); + } + + + /** + * Set the port number of the server to process this request. + * + * @param port The server port + */ + public void setServerPort(int port) { + coyoteRequest.setServerPort(port); + } + + + // ------------------------------------------------- ServletRequest Methods + + + /** + * Return the specified request attribute if it exists; otherwise, return + * null. + * + * @param name Name of the request attribute to return + */ + public Object getAttribute(String name) { + + if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { + return (dispatcherType == null) + ? ApplicationFilterFactory.REQUEST_INTEGER + : dispatcherType; + } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { + return (requestDispatcherPath == null) + ? getRequestPathMB().toString() + : requestDispatcherPath.toString(); + } + + Object attr=attributes.get(name); + + if(attr!=null) + return(attr); + + attr = coyoteRequest.getAttribute(name); + if(attr != null) + return attr; + if( isSSLAttribute(name) ) { + coyoteRequest.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, + coyoteRequest); + attr = coyoteRequest.getAttribute(Globals.CERTIFICATES_ATTR); + if( attr != null) { + attributes.put(Globals.CERTIFICATES_ATTR, attr); + } + attr = coyoteRequest.getAttribute(Globals.CIPHER_SUITE_ATTR); + if(attr != null) { + attributes.put(Globals.CIPHER_SUITE_ATTR, attr); + } + attr = coyoteRequest.getAttribute(Globals.KEY_SIZE_ATTR); + if(attr != null) { + attributes.put(Globals.KEY_SIZE_ATTR, attr); + } + attr = coyoteRequest.getAttribute(Globals.SSL_SESSION_ID_ATTR); + if(attr != null) { + attributes.put(Globals.SSL_SESSION_ID_ATTR, attr); + } + attr = attributes.get(name); + } + return attr; + } + + + /** + * Test if a given name is one of the special Servlet-spec SSL attributes. + */ + static boolean isSSLAttribute(String name) { + return Globals.CERTIFICATES_ATTR.equals(name) || + Globals.CIPHER_SUITE_ATTR.equals(name) || + Globals.KEY_SIZE_ATTR.equals(name) || + Globals.SSL_SESSION_ID_ATTR.equals(name); + } + + /** + * Return the names of all request attributes for this Request, or an + * empty Enumeration if there are none. + */ + public Enumeration getAttributeNames() { + if (isSecure()) { + getAttribute(Globals.CERTIFICATES_ATTR); + } + return new Enumerator(attributes.keySet(), true); + } + + + /** + * Return the character encoding for this Request. + */ + public String getCharacterEncoding() { + return (coyoteRequest.getCharacterEncoding()); + } + + + /** + * Return the content length for this Request. + */ + public int getContentLength() { + return (coyoteRequest.getContentLength()); + } + + + /** + * Return the content type for this Request. + */ + public String getContentType() { + return (coyoteRequest.getContentType()); + } + + + /** + * Return the servlet input stream for this Request. The default + * implementation returns a servlet input stream created by + * createInputStream(). + * + * @exception IllegalStateException if getReader() has + * already been called for this request + * @exception IOException if an input/output error occurs + */ + public ServletInputStream getInputStream() throws IOException { + + if (usingReader) + throw new IllegalStateException + (sm.getString("coyoteRequest.getInputStream.ise")); + + usingInputStream = true; + if (inputStream == null) { + inputStream = new CoyoteInputStream(inputBuffer); + } + return inputStream; + + } + + + /** + * Return the preferred Locale that the client will accept content in, + * based on the value for the first Accept-Language header + * that was encountered. If the request did not specify a preferred + * language, the server's default Locale is returned. + */ + public Locale getLocale() { + + if (!localesParsed) + parseLocales(); + + if (locales.size() > 0) { + return ((Locale) locales.get(0)); + } else { + return (defaultLocale); + } + + } + + + /** + * Return the set of preferred Locales that the client will accept + * content in, based on the values for any Accept-Language + * headers that were encountered. If the request did not specify a + * preferred language, the server's default Locale is returned. + */ + public Enumeration getLocales() { + + if (!localesParsed) + parseLocales(); + + if (locales.size() > 0) + return (new Enumerator(locales)); + ArrayList results = new ArrayList(); + results.add(defaultLocale); + return (new Enumerator(results)); + + } + + + /** + * Return the value of the specified request parameter, if any; otherwise, + * return null. If there is more than one value defined, + * return only the first one. + * + * @param name Name of the desired request parameter + */ + public String getParameter(String name) { + + if (!parametersParsed) + parseParameters(); + + return coyoteRequest.getParameters().getParameter(name); + + } + + + + /** + * Returns a Map of the parameters of this request. + * Request parameters are extra information sent with the request. + * For HTTP servlets, parameters are contained in the query string + * or posted form data. + * + * @return A Map containing parameter names as keys + * and parameter values as map values. + */ + public Map getParameterMap() { + + if (parameterMap.isLocked()) + return parameterMap; + + Enumeration enumeration = getParameterNames(); + while (enumeration.hasMoreElements()) { + String name = enumeration.nextElement().toString(); + String[] values = getParameterValues(name); + parameterMap.put(name, values); + } + + parameterMap.setLocked(true); + + return parameterMap; + + } + + + /** + * Return the names of all defined request parameters for this request. + */ + public Enumeration getParameterNames() { + + if (!parametersParsed) + parseParameters(); + + return coyoteRequest.getParameters().getParameterNames(); + + } + + + /** + * Return the defined values for the specified request parameter, if any; + * otherwise, return null. + * + * @param name Name of the desired request parameter + */ + public String[] getParameterValues(String name) { + + if (!parametersParsed) + parseParameters(); + + return coyoteRequest.getParameters().getParameterValues(name); + + } + + + /** + * Return the protocol and version used to make this Request. + */ + public String getProtocol() { + return coyoteRequest.protocol().toString(); + } + + + /** + * Read the Reader wrapping the input stream for this Request. The + * default implementation wraps a BufferedReader around the + * servlet input stream returned by createInputStream(). + * + * @exception IllegalStateException if getInputStream() + * has already been called for this request + * @exception IOException if an input/output error occurs + */ + public BufferedReader getReader() throws IOException { + + if (usingInputStream) + throw new IllegalStateException + (sm.getString("coyoteRequest.getReader.ise")); + + usingReader = true; + inputBuffer.checkConverter(); + if (reader == null) { + reader = new CoyoteReader(inputBuffer); + } + return reader; + + } + + + /** + * Return the real path of the specified virtual path. + * + * @param path Path to be translated + * + * @deprecated As of version 2.1 of the Java Servlet API, use + * ServletContext.getRealPath(). + */ + public String getRealPath(String path) { + + if (context == null) + return (null); + ServletContext servletContext = context.getServletContext(); + if (servletContext == null) + return (null); + else { + try { + return (servletContext.getRealPath(path)); + } catch (IllegalArgumentException e) { + return (null); + } + } + + } + + + /** + * Return the remote IP address making this Request. + */ + public String getRemoteAddr() { + if (remoteAddr == null) { + coyoteRequest.action + (ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, coyoteRequest); + remoteAddr = coyoteRequest.remoteAddr().toString(); + } + return remoteAddr; + } + + + /** + * Return the remote host name making this Request. + */ + public String getRemoteHost() { + if (remoteHost == null) { + if (!connector.getEnableLookups()) { + remoteHost = getRemoteAddr(); + } else { + coyoteRequest.action + (ActionCode.ACTION_REQ_HOST_ATTRIBUTE, coyoteRequest); + remoteHost = coyoteRequest.remoteHost().toString(); + } + } + return remoteHost; + } + + /** + * Returns the Internet Protocol (IP) source port of the client + * or last proxy that sent the request. + */ + public int getRemotePort(){ + if (remotePort == -1) { + coyoteRequest.action + (ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE, coyoteRequest); + remotePort = coyoteRequest.getRemotePort(); + } + return remotePort; + } + + /** + * Returns the host name of the Internet Protocol (IP) interface on + * which the request was received. + */ + public String getLocalName(){ + if (localName == null) { + coyoteRequest.action + (ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, coyoteRequest); + localName = coyoteRequest.localName().toString(); + } + return localName; + } + + /** + * Returns the Internet Protocol (IP) address of the interface on + * which the request was received. + */ + public String getLocalAddr(){ + if (localAddr == null) { + coyoteRequest.action + (ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE, coyoteRequest); + localAddr = coyoteRequest.localAddr().toString(); + } + return localAddr; + } + + + /** + * Returns the Internet Protocol (IP) port number of the interface + * on which the request was received. + */ + public int getLocalPort(){ + if (localPort == -1){ + coyoteRequest.action + (ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE, coyoteRequest); + localPort = coyoteRequest.getLocalPort(); + } + return localPort; + } + + /** + * Return a RequestDispatcher that wraps the resource at the specified + * path, which may be interpreted as relative to the current request path. + * + * @param path Path of the resource to be wrapped + */ + public RequestDispatcher getRequestDispatcher(String path) { + + if (context == null) + return (null); + + // If the path is already context-relative, just pass it through + if (path == null) + return (null); + else if (path.startsWith("/")) + return (context.getServletContext().getRequestDispatcher(path)); + + // Convert a request-relative path to a context-relative one + String servletPath = (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); + if (servletPath == null) + servletPath = getServletPath(); + + // Add the path info, if there is any + String pathInfo = getPathInfo(); + String requestPath = null; + + if (pathInfo == null) { + requestPath = servletPath; + } else { + requestPath = servletPath + pathInfo; + } + + int pos = requestPath.lastIndexOf('/'); + String relative = null; + if (pos >= 0) { + relative = RequestUtil.normalize + (requestPath.substring(0, pos + 1) + path); + } else { + relative = RequestUtil.normalize(requestPath + path); + } + + return (context.getServletContext().getRequestDispatcher(relative)); + + } + + + /** + * Return the scheme used to make this Request. + */ + public String getScheme() { + return (coyoteRequest.scheme().toString()); + } + + + /** + * Return the server name responding to this Request. + */ + public String getServerName() { + return (coyoteRequest.serverName().toString()); + } + + + /** + * Return the server port responding to this Request. + */ + public int getServerPort() { + return (coyoteRequest.getServerPort()); + } + + + /** + * Was this request received on a secure connection? + */ + public boolean isSecure() { + return (secure); + } + + + /** + * Remove the specified request attribute if it exists. + * + * @param name Name of the request attribute to remove + */ + public void removeAttribute(String name) { + Object value = null; + boolean found = false; + + // Remove the specified attribute + // Check for read only attribute + // requests are per thread so synchronization unnecessary + if (readOnlyAttributes.containsKey(name)) { + return; + } + + // Pass special attributes to the native layer + if (name.startsWith("org.apache.tomcat.")) { + coyoteRequest.getAttributes().remove(name); + } + + found = attributes.containsKey(name); + if (found) { + value = attributes.get(name); + attributes.remove(name); + } else { + return; + } + + // Notify interested application event listeners + Object listeners[] = context.getApplicationEventListeners(); + if ((listeners == null) || (listeners.length == 0)) + return; + ServletRequestAttributeEvent event = + new ServletRequestAttributeEvent(context.getServletContext(), + getRequest(), name, value); + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof ServletRequestAttributeListener)) + continue; + ServletRequestAttributeListener listener = + (ServletRequestAttributeListener) listeners[i]; + try { + listener.attributeRemoved(event); + } catch (Throwable t) { + context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); + // Error valve will pick this execption up and display it to user + attributes.put( Globals.EXCEPTION_ATTR, t ); + } + } + } + + + /** + * Set the specified request attribute to the specified value. + * + * @param name Name of the request attribute to set + * @param value The associated value + */ + public void setAttribute(String name, Object value) { + + // Name cannot be null + if (name == null) + throw new IllegalArgumentException + (sm.getString("coyoteRequest.setAttribute.namenull")); + + // Null value is the same as removeAttribute() + if (value == null) { + removeAttribute(name); + return; + } + + if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { + dispatcherType = value; + return; + } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { + requestDispatcherPath = value; + return; + } + + Object oldValue = null; + boolean replaced = false; + + // Add or replace the specified attribute + // Check for read only attribute + // requests are per thread so synchronization unnecessary + if (readOnlyAttributes.containsKey(name)) { + return; + } + + oldValue = attributes.put(name, value); + if (oldValue != null) { + replaced = true; + } + + // Pass special attributes to the native layer + if (name.startsWith("org.apache.tomcat.")) { + coyoteRequest.setAttribute(name, value); + } + + // Notify interested application event listeners + Object listeners[] = context.getApplicationEventListeners(); + if ((listeners == null) || (listeners.length == 0)) + return; + ServletRequestAttributeEvent event = null; + if (replaced) + event = + new ServletRequestAttributeEvent(context.getServletContext(), + getRequest(), name, oldValue); + else + event = + new ServletRequestAttributeEvent(context.getServletContext(), + getRequest(), name, value); + + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof ServletRequestAttributeListener)) + continue; + ServletRequestAttributeListener listener = + (ServletRequestAttributeListener) listeners[i]; + try { + if (replaced) { + listener.attributeReplaced(event); + } else { + listener.attributeAdded(event); + } + } catch (Throwable t) { + context.getLogger().error(sm.getString("coyoteRequest.attributeEvent"), t); + // Error valve will pick this execption up and display it to user + attributes.put( Globals.EXCEPTION_ATTR, t ); + } + } + } + + + /** + * Overrides the name of the character encoding used in the body of + * this request. This method must be called prior to reading request + * parameters or reading input using getReader(). + * + * @param enc The character encoding to be used + * + * @exception UnsupportedEncodingException if the specified encoding + * is not supported + * + * @since Servlet 2.3 + */ + public void setCharacterEncoding(String enc) + throws UnsupportedEncodingException { + + if (usingReader) + return; + + // Ensure that the specified encoding is valid + byte buffer[] = new byte[1]; + buffer[0] = (byte) 'a'; + String dummy = new String(buffer, enc); + + // Save the validated encoding + coyoteRequest.setCharacterEncoding(enc); + + } + + + // ---------------------------------------------------- HttpRequest Methods + + + /** + * Add a Cookie to the set of Cookies associated with this Request. + * + * @param cookie The new cookie + */ + public void addCookie(Cookie cookie) { + + if (!cookiesParsed) + parseCookies(); + + int size = 0; + if (cookies != null) { + size = cookies.length; + } + + Cookie[] newCookies = new Cookie[size + 1]; + for (int i = 0; i < size; i++) { + newCookies[i] = cookies[i]; + } + newCookies[size] = cookie; + + cookies = newCookies; + + } + + + /** + * Add a Header to the set of Headers associated with this Request. + * + * @param name The new header name + * @param value The new header value + */ + public void addHeader(String name, String value) { + // Not used + } + + + /** + * Add a Locale to the set of preferred Locales for this Request. The + * first added Locale will be the first one returned by getLocales(). + * + * @param locale The new preferred Locale + */ + public void addLocale(Locale locale) { + locales.add(locale); + } + + + /** + * Add a parameter name and corresponding set of values to this Request. + * (This is used when restoring the original request on a form based + * login). + * + * @param name Name of this request parameter + * @param values Corresponding values for this request parameter + */ + public void addParameter(String name, String values[]) { + coyoteRequest.getParameters().addParameterValues(name, values); + } + + + /** + * Clear the collection of Cookies associated with this Request. + */ + public void clearCookies() { + cookiesParsed = true; + cookies = null; + } + + + /** + * Clear the collection of Headers associated with this Request. + */ + public void clearHeaders() { + // Not used + } + + + /** + * Clear the collection of Locales associated with this Request. + */ + public void clearLocales() { + locales.clear(); + } + + + /** + * Clear the collection of parameters associated with this Request. + */ + public void clearParameters() { + // Not used + } + + + /** + * Set the authentication type used for this request, if any; otherwise + * set the type to null. Typical values are "BASIC", + * "DIGEST", or "SSL". + * + * @param type The authentication type used + */ + public void setAuthType(String type) { + this.authType = type; + } + + + /** + * Set the context path for this Request. This will normally be called + * when the associated Context is mapping the Request to a particular + * Wrapper. + * + * @param path The context path + */ + public void setContextPath(String path) { + + if (path == null) { + mappingData.contextPath.setString(""); + } else { + mappingData.contextPath.setString(path); + } + + } + + + /** + * Set the HTTP request method used for this Request. + * + * @param method The request method + */ + public void setMethod(String method) { + // Not used + } + + + /** + * Set the query string for this Request. This will normally be called + * by the HTTP Connector, when it parses the request headers. + * + * @param query The query string + */ + public void setQueryString(String query) { + // Not used + } + + + /** + * Set the path information for this Request. This will normally be called + * when the associated Context is mapping the Request to a particular + * Wrapper. + * + * @param path The path information + */ + public void setPathInfo(String path) { + mappingData.pathInfo.setString(path); + } + + + /** + * Set a flag indicating whether or not the requested session ID for this + * request came in through a cookie. This is normally called by the + * HTTP Connector, when it parses the request headers. + * + * @param flag The new flag + */ + public void setRequestedSessionCookie(boolean flag) { + + this.requestedSessionCookie = flag; + + } + + + /** + * Set the requested session ID for this request. This is normally called + * by the HTTP Connector, when it parses the request headers. + * + * @param id The new session id + */ + public void setRequestedSessionId(String id) { + + this.requestedSessionId = id; + + } + + + /** + * Set a flag indicating whether or not the requested session ID for this + * request came in through a URL. This is normally called by the + * HTTP Connector, when it parses the request headers. + * + * @param flag The new flag + */ + public void setRequestedSessionURL(boolean flag) { + + this.requestedSessionURL = flag; + + } + + + /** + * Set the unparsed request URI for this Request. This will normally be + * called by the HTTP Connector, when it parses the request headers. + * + * @param uri The request URI + */ + public void setRequestURI(String uri) { + // Not used + } + + + /** + * Set the decoded request URI. + * + * @param uri The decoded request URI + */ + public void setDecodedRequestURI(String uri) { + // Not used + } + + + /** + * Get the decoded request URI. + * + * @return the URL decoded request URI + */ + public String getDecodedRequestURI() { + return (coyoteRequest.decodedURI().toString()); + } + + + /** + * Get the decoded request URI. + * + * @return the URL decoded request URI + */ + public MessageBytes getDecodedRequestURIMB() { + return (coyoteRequest.decodedURI()); + } + + + /** + * Set the servlet path for this Request. This will normally be called + * when the associated Context is mapping the Request to a particular + * Wrapper. + * + * @param path The servlet path + */ + public void setServletPath(String path) { + if (path != null) + mappingData.wrapperPath.setString(path); + } + + + /** + * Set the Principal who has been authenticated for this Request. This + * value is also used to calculate the value to be returned by the + * getRemoteUser() method. + * + * @param principal The user Principal + */ + public void setUserPrincipal(Principal principal) { + + if (System.getSecurityManager() != null){ + HttpSession session = getSession(false); + if ( (subject != null) && + (!subject.getPrincipals().contains(principal)) ){ + subject.getPrincipals().add(principal); + } else if (session != null && + session.getAttribute(Globals.SUBJECT_ATTR) == null) { + subject = new Subject(); + subject.getPrincipals().add(principal); + } + if (session != null){ + session.setAttribute(Globals.SUBJECT_ATTR, subject); + } + } + + this.userPrincipal = principal; + } + + + // --------------------------------------------- HttpServletRequest Methods + + + /** + * Return the authentication type used for this Request. + */ + public String getAuthType() { + return (authType); + } + + + /** + * Return the portion of the request URI used to select the Context + * of the Request. + */ + public String getContextPath() { + return (mappingData.contextPath.toString()); + } + + + /** + * Get the context path. + * + * @return the context path + */ + public MessageBytes getContextPathMB() { + return (mappingData.contextPath); + } + + + /** + * Return the set of Cookies received with this Request. + */ + public Cookie[] getCookies() { + + if (!cookiesParsed) + parseCookies(); + + return cookies; + + } + + + /** + * Set the set of cookies recieved with this Request. + */ + public void setCookies(Cookie[] cookies) { + + this.cookies = cookies; + + } + + + /** + * Return the value of the specified date header, if any; otherwise + * return -1. + * + * @param name Name of the requested date header + * + * @exception IllegalArgumentException if the specified header value + * cannot be converted to a date + */ + public long getDateHeader(String name) { + + String value = getHeader(name); + if (value == null) + return (-1L); + + // Attempt to convert the date header in a variety of formats + long result = FastHttpDateFormat.parseDate(value, formats); + if (result != (-1L)) { + return result; + } + throw new IllegalArgumentException(value); + + } + + + /** + * Return the first value of the specified header, if any; otherwise, + * return null + * + * @param name Name of the requested header + */ + public String getHeader(String name) { + return coyoteRequest.getHeader(name); + } + + + /** + * Return all of the values of the specified header, if any; otherwise, + * return an empty enumeration. + * + * @param name Name of the requested header + */ + public Enumeration getHeaders(String name) { + return coyoteRequest.getMimeHeaders().values(name); + } + + + /** + * Return the names of all headers received with this request. + */ + public Enumeration getHeaderNames() { + return coyoteRequest.getMimeHeaders().names(); + } + + + /** + * Return the value of the specified header as an integer, or -1 if there + * is no such header for this request. + * + * @param name Name of the requested header + * + * @exception IllegalArgumentException if the specified header value + * cannot be converted to an integer + */ + public int getIntHeader(String name) { + + String value = getHeader(name); + if (value == null) { + return (-1); + } else { + return (Integer.parseInt(value)); + } + + } + + + /** + * Return the HTTP request method used in this Request. + */ + public String getMethod() { + return coyoteRequest.method().toString(); + } + + + /** + * Return the path information associated with this Request. + */ + public String getPathInfo() { + return (mappingData.pathInfo.toString()); + } + + + /** + * Get the path info. + * + * @return the path info + */ + public MessageBytes getPathInfoMB() { + return (mappingData.pathInfo); + } + + + /** + * Return the extra path information for this request, translated + * to a real path. + */ + public String getPathTranslated() { + + if (context == null) + return (null); + + if (getPathInfo() == null) { + return (null); + } else { + return (context.getServletContext().getRealPath(getPathInfo())); + } + + } + + + /** + * Return the query string associated with this request. + */ + public String getQueryString() { + String queryString = coyoteRequest.queryString().toString(); + if (queryString == null || queryString.equals("")) { + return (null); + } else { + return queryString; + } + } + + + /** + * Return the name of the remote user that has been authenticated + * for this Request. + */ + public String getRemoteUser() { + + if (userPrincipal != null) { + return (userPrincipal.getName()); + } else { + return (null); + } + + } + + + /** + * Get the request path. + * + * @return the request path + */ + public MessageBytes getRequestPathMB() { + return (mappingData.requestPath); + } + + + /** + * Return the session identifier included in this request, if any. + */ + public String getRequestedSessionId() { + return (requestedSessionId); + } + + + /** + * Return the request URI for this request. + */ + public String getRequestURI() { + return coyoteRequest.requestURI().toString(); + } + + + /** + * Reconstructs the URL the client used to make the request. + * The returned URL contains a protocol, server name, port + * number, and server path, but it does not include query + * string parameters. + *

    + * Because this method returns a StringBuffer, + * not a String, you can modify the URL easily, + * for example, to append query parameters. + *

    + * This method is useful for creating redirect messages and + * for reporting errors. + * + * @return A StringBuffer object containing the + * reconstructed URL + */ + public StringBuffer getRequestURL() { + + StringBuffer url = new StringBuffer(); + String scheme = getScheme(); + int port = getServerPort(); + if (port < 0) + port = 80; // Work around java.net.URL bug + + url.append(scheme); + url.append("://"); + url.append(getServerName()); + if ((scheme.equals("http") && (port != 80)) + || (scheme.equals("https") && (port != 443))) { + url.append(':'); + url.append(port); + } + url.append(getRequestURI()); + + return (url); + + } + + + /** + * Return the portion of the request URI used to select the servlet + * that will process this request. + */ + public String getServletPath() { + return (mappingData.wrapperPath.toString()); + } + + + /** + * Get the servlet path. + * + * @return the servlet path + */ + public MessageBytes getServletPathMB() { + return (mappingData.wrapperPath); + } + + + /** + * Return the session associated with this Request, creating one + * if necessary. + */ + public HttpSession getSession() { + Session session = doGetSession(true); + if (session != null) { + return session.getSession(); + } else { + return null; + } + } + + + /** + * Return the session associated with this Request, creating one + * if necessary and requested. + * + * @param create Create a new session if one does not exist + */ + public HttpSession getSession(boolean create) { + Session session = doGetSession(create); + if (session != null) { + return session.getSession(); + } else { + return null; + } + } + + + /** + * Return true if the session identifier included in this + * request came from a cookie. + */ + public boolean isRequestedSessionIdFromCookie() { + + if (requestedSessionId != null) + return (requestedSessionCookie); + else + return (false); + + } + + + /** + * Return true if the session identifier included in this + * request came from the request URI. + */ + public boolean isRequestedSessionIdFromURL() { + + if (requestedSessionId != null) + return (requestedSessionURL); + else + return (false); + + } + + + /** + * Return true if the session identifier included in this + * request came from the request URI. + * + * @deprecated As of Version 2.1 of the Java Servlet API, use + * isRequestedSessionIdFromURL() instead. + */ + public boolean isRequestedSessionIdFromUrl() { + return (isRequestedSessionIdFromURL()); + } + + + /** + * Return true if the session identifier included in this + * request identifies a valid session. + */ + public boolean isRequestedSessionIdValid() { + + if (requestedSessionId == null) + return (false); + if (context == null) + return (false); + Manager manager = context.getManager(); + if (manager == null) + return (false); + Session session = null; + try { + session = manager.findSession(requestedSessionId); + } catch (IOException e) { + session = null; + } + if ((session != null) && session.isValid()) + return (true); + else + return (false); + + } + + + /** + * Return true if the authenticated user principal + * possesses the specified role name. + * + * @param role Role name to be validated + */ + public boolean isUserInRole(String role) { + + // Have we got an authenticated principal at all? + if (userPrincipal == null) + return (false); + + // Identify the Realm we will use for checking role assignmenets + if (context == null) + return (false); + Realm realm = context.getRealm(); + if (realm == null) + return (false); + + // Check for a role alias defined in a element + if (wrapper != null) { + String realRole = wrapper.findSecurityReference(role); + if ((realRole != null) && + realm.hasRole(userPrincipal, realRole)) + return (true); + } + + // Check for a role defined directly as a + return (realm.hasRole(userPrincipal, role)); + + } + + + /** + * Return the principal that has been authenticated for this Request. + */ + public Principal getPrincipal() { + return (userPrincipal); + } + + + /** + * Return the principal that has been authenticated for this Request. + */ + public Principal getUserPrincipal() { + if (userPrincipal instanceof GenericPrincipal) { + return ((GenericPrincipal) userPrincipal).getUserPrincipal(); + } else { + return (userPrincipal); + } + } + + + /** + * Return the session associated with this Request, creating one + * if necessary. + */ + public Session getSessionInternal() { + return doGetSession(true); + } + + + /** + * Return the session associated with this Request, creating one + * if necessary and requested. + * + * @param create Create a new session if one does not exist + */ + public Session getSessionInternal(boolean create) { + return doGetSession(create); + } + + + // ------------------------------------------------------ Protected Methods + + + protected Session doGetSession(boolean create) { + + // There cannot be a session if no context has been assigned yet + if (context == null) + return (null); + + // Return the current session if it exists and is valid + if ((session != null) && !session.isValid()) + session = null; + if (session != null) + return (session); + + // Return the requested session if it exists and is valid + Manager manager = null; + if (context != null) + manager = context.getManager(); + if (manager == null) + return (null); // Sessions are not supported + if (requestedSessionId != null) { + try { + session = manager.findSession(requestedSessionId); + } catch (IOException e) { + session = null; + } + if ((session != null) && !session.isValid()) + session = null; + if (session != null) { + session.access(); + return (session); + } + } + + // Create a new session if requested and the response is not committed + if (!create) + return (null); + if ((context != null) && (response != null) && + context.getCookies() && + response.getResponse().isCommitted()) { + throw new IllegalStateException + (sm.getString("coyoteRequest.sessionCreateCommitted")); + } + + // Attempt to reuse session id if one was submitted in a cookie + // Do not reuse the session id if it is from a URL, to prevent possible + // phishing attacks + if (connector.getEmptySessionPath() + && isRequestedSessionIdFromCookie()) { + session = manager.createSession(getRequestedSessionId()); + } else { + session = manager.createSession(null); + } + + // Creating a new session cookie based on that session + if ((session != null) && (getContext() != null) + && getContext().getCookies()) { + Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME, + session.getIdInternal()); + configureSessionCookie(cookie); + response.addCookieInternal(cookie); + } + + if (session != null) { + session.access(); + return (session); + } else { + return (null); + } + + } + + /** + * Configures the given JSESSIONID cookie. + * + * @param cookie The JSESSIONID cookie to be configured + */ + protected void configureSessionCookie(Cookie cookie) { + cookie.setMaxAge(-1); + String contextPath = null; + if (!connector.getEmptySessionPath() && (getContext() != null)) { + contextPath = getContext().getEncodedPath(); + } + if ((contextPath != null) && (contextPath.length() > 0)) { + cookie.setPath(contextPath); + } else { + cookie.setPath("/"); + } + if (isSecure()) { + cookie.setSecure(true); + } + } + + /** + * Parse cookies. + */ + protected void parseCookies() { + + cookiesParsed = true; + + Cookies serverCookies = coyoteRequest.getCookies(); + int count = serverCookies.getCookieCount(); + if (count <= 0) + return; + + cookies = new Cookie[count]; + + int idx=0; + for (int i = 0; i < count; i++) { + ServerCookie scookie = serverCookies.getCookie(i); + try { + Cookie cookie = new Cookie(scookie.getName().toString(), + scookie.getValue().toString()); + cookie.setPath(scookie.getPath().toString()); + cookie.setVersion(scookie.getVersion()); + String domain = scookie.getDomain().toString(); + if (domain != null) { + cookie.setDomain(scookie.getDomain().toString()); + } + cookies[idx++] = cookie; + } catch(IllegalArgumentException e) { + // Ignore bad cookie + } + } + if( idx < count ) { + Cookie [] ncookies = new Cookie[idx]; + System.arraycopy(cookies, 0, ncookies, 0, idx); + cookies = ncookies; + } + + } + + /** + * Parse request parameters. + */ + protected void parseParameters() { + + parametersParsed = true; + + Parameters parameters = coyoteRequest.getParameters(); + + // getCharacterEncoding() may have been overridden to search for + // hidden form field containing request encoding + String enc = getCharacterEncoding(); + + boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI(); + if (enc != null) { + parameters.setEncoding(enc); + if (useBodyEncodingForURI) { + parameters.setQueryStringEncoding(enc); + } + } else { + parameters.setEncoding + (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); + if (useBodyEncodingForURI) { + parameters.setQueryStringEncoding + (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); + } + } + + parameters.handleQueryParameters(); + + if (usingInputStream || usingReader) + return; + + if (!getMethod().equalsIgnoreCase("POST")) + return; + + String contentType = getContentType(); + if (contentType == null) + contentType = ""; + int semicolon = contentType.indexOf(';'); + if (semicolon >= 0) { + contentType = contentType.substring(0, semicolon).trim(); + } else { + contentType = contentType.trim(); + } + if (!("application/x-www-form-urlencoded".equals(contentType))) + return; + + int len = getContentLength(); + + if (len > 0) { + int maxPostSize = connector.getMaxPostSize(); + if ((maxPostSize > 0) && (len > maxPostSize)) { + context.getLogger().info + (sm.getString("coyoteRequest.postTooLarge")); + throw new IllegalStateException("Post too large"); + } + try { + byte[] formData = null; + if (len < CACHED_POST_LEN) { + if (postData == null) + postData = new byte[CACHED_POST_LEN]; + formData = postData; + } else { + formData = new byte[len]; + } + int actualLen = readPostBody(formData, len); + if (actualLen == len) { + parameters.processParameters(formData, 0, len); + } + } catch (Throwable t) { + ; // Ignore + } + } + + } + + + /** + * Read post body in an array. + */ + protected int readPostBody(byte body[], int len) + throws IOException { + + int offset = 0; + do { + int inputLen = getStream().read(body, offset, len - offset); + if (inputLen <= 0) { + return offset; + } + offset += inputLen; + } while ((len - offset) > 0); + return len; + + } + + + /** + * Parse request locales. + */ + protected void parseLocales() { + + localesParsed = true; + + Enumeration values = getHeaders("accept-language"); + + while (values.hasMoreElements()) { + String value = values.nextElement().toString(); + parseLocalesHeader(value); + } + + } + + + /** + * Parse accept-language header value. + */ + protected void parseLocalesHeader(String value) { + + // Store the accumulated languages that have been requested in + // a local collection, sorted by the quality value (so we can + // add Locales in descending order). The values will be ArrayLists + // containing the corresponding Locales to be added + TreeMap locales = new TreeMap(); + + // Preprocess the value to remove all whitespace + int white = value.indexOf(' '); + if (white < 0) + white = value.indexOf('\t'); + if (white >= 0) { + StringBuffer sb = new StringBuffer(); + int len = value.length(); + for (int i = 0; i < len; i++) { + char ch = value.charAt(i); + if ((ch != ' ') && (ch != '\t')) + sb.append(ch); + } + value = sb.toString(); + } + + // Process each comma-delimited language specification + parser.setString(value); // ASSERT: parser is available to us + int length = parser.getLength(); + while (true) { + + // Extract the next comma-delimited entry + int start = parser.getIndex(); + if (start >= length) + break; + int end = parser.findChar(','); + String entry = parser.extract(start, end).trim(); + parser.advance(); // For the following entry + + // Extract the quality factor for this entry + double quality = 1.0; + int semi = entry.indexOf(";q="); + if (semi >= 0) { + try { + quality = Double.parseDouble(entry.substring(semi + 3)); + } catch (NumberFormatException e) { + quality = 0.0; + } + entry = entry.substring(0, semi); + } + + // Skip entries we are not going to keep track of + if (quality < 0.00005) + continue; // Zero (or effectively zero) quality factors + if ("*".equals(entry)) + continue; // FIXME - "*" entries are not handled + + // Extract the language and country for this entry + String language = null; + String country = null; + String variant = null; + int dash = entry.indexOf('-'); + if (dash < 0) { + language = entry; + country = ""; + variant = ""; + } else { + language = entry.substring(0, dash); + country = entry.substring(dash + 1); + int vDash = country.indexOf('-'); + if (vDash > 0) { + String cTemp = country.substring(0, vDash); + variant = country.substring(vDash + 1); + country = cTemp; + } else { + variant = ""; + } + } + + // Add a new Locale to the list of Locales for this quality level + Locale locale = new Locale(language, country, variant); + Double key = new Double(-quality); // Reverse the order + ArrayList values = (ArrayList) locales.get(key); + if (values == null) { + values = new ArrayList(); + locales.put(key, values); + } + values.add(locale); + + } + + // Process the quality values in highest->lowest order (due to + // negating the Double value when creating the key) + Iterator keys = locales.keySet().iterator(); + while (keys.hasNext()) { + Double key = (Double) keys.next(); + ArrayList list = (ArrayList) locales.get(key); + Iterator values = list.iterator(); + while (values.hasNext()) { + Locale locale = (Locale) values.next(); + addLocale(locale); + } + } + + } + + +} diff --git a/java/org/apache/catalina/connector/RequestFacade.java b/java/org/apache/catalina/connector/RequestFacade.java index 458cc9b04..db5b0f374 100644 --- a/java/org/apache/catalina/connector/RequestFacade.java +++ b/java/org/apache/catalina/connector/RequestFacade.java @@ -1,933 +1,933 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.BufferedReader; -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletInputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.util.StringManager; - - -import org.apache.catalina.security.SecurityUtil; - -/** - * Facade class that wraps a Coyote request object. - * All methods are delegated to the wrapped request. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @author Jean-Francois Arcand - * @version $Revision: 303900 $ $Date: 2005-04-30 00:22:29 +0200 (sam., 30 avr. 2005) $ - */ - -@SuppressWarnings("deprecation") -public class RequestFacade implements HttpServletRequest { - - - // ----------------------------------------------------------- DoPrivileged - - private final class GetAttributePrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getAttributeNames(); - } - } - - - private final class GetParameterMapPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getParameterMap(); - } - } - - - private final class GetRequestDispatcherPrivilegedAction - implements PrivilegedAction { - - private String path; - - public GetRequestDispatcherPrivilegedAction(String path){ - this.path = path; - } - - public Object run() { - return request.getRequestDispatcher(path); - } - } - - - private final class GetParameterPrivilegedAction - implements PrivilegedAction { - - public String name; - - public GetParameterPrivilegedAction(String name){ - this.name = name; - } - - public Object run() { - return request.getParameter(name); - } - } - - - private final class GetParameterNamesPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getParameterNames(); - } - } - - - private final class GetParameterValuePrivilegedAction - implements PrivilegedAction { - - public String name; - - public GetParameterValuePrivilegedAction(String name){ - this.name = name; - } - - public Object run() { - return request.getParameterValues(name); - } - } - - - private final class GetCookiesPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getCookies(); - } - } - - - private final class GetCharacterEncodingPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getCharacterEncoding(); - } - } - - - private final class GetHeadersPrivilegedAction - implements PrivilegedAction { - - private String name; - - public GetHeadersPrivilegedAction(String name){ - this.name = name; - } - - public Object run() { - return request.getHeaders(name); - } - } - - - private final class GetHeaderNamesPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getHeaderNames(); - } - } - - - private final class GetLocalePrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getLocale(); - } - } - - - private final class GetLocalesPrivilegedAction - implements PrivilegedAction { - - public Object run() { - return request.getLocales(); - } - } - - private final class GetSessionPrivilegedAction - implements PrivilegedAction { - - private boolean create; - - public GetSessionPrivilegedAction(boolean create){ - this.create = create; - } - - public Object run() { - return request.getSession(create); - } - } - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a wrapper for the specified request. - * - * @param request The request to be wrapped - */ - public RequestFacade(Request request) { - - this.request = request; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The wrapped request. - */ - protected Request request = null; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // --------------------------------------------------------- Public Methods - - - /** - * Clear facade. - */ - public void clear() { - request = null; - } - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - // ------------------------------------------------- ServletRequest Methods - - - public Object getAttribute(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getAttribute(name); - } - - - public Enumeration getAttributeNames() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Enumeration)AccessController.doPrivileged( - new GetAttributePrivilegedAction()); - } else { - return request.getAttributeNames(); - } - } - - - public String getCharacterEncoding() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (String)AccessController.doPrivileged( - new GetCharacterEncodingPrivilegedAction()); - } else { - return request.getCharacterEncoding(); - } - } - - - public void setCharacterEncoding(String env) - throws java.io.UnsupportedEncodingException { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - request.setCharacterEncoding(env); - } - - - public int getContentLength() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getContentLength(); - } - - - public String getContentType() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getContentType(); - } - - - public ServletInputStream getInputStream() throws IOException { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getInputStream(); - } - - - public String getParameter(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (String)AccessController.doPrivileged( - new GetParameterPrivilegedAction(name)); - } else { - return request.getParameter(name); - } - } - - - public Enumeration getParameterNames() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Enumeration)AccessController.doPrivileged( - new GetParameterNamesPrivilegedAction()); - } else { - return request.getParameterNames(); - } - } - - - public String[] getParameterValues(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - String[] ret = null; - - /* - * Clone the returned array only if there is a security manager - * in place, so that performance won't suffer in the nonsecure case - */ - if (SecurityUtil.isPackageProtectionEnabled()){ - ret = (String[]) AccessController.doPrivileged( - new GetParameterValuePrivilegedAction(name)); - if (ret != null) { - ret = (String[]) ret.clone(); - } - } else { - ret = request.getParameterValues(name); - } - - return ret; - } - - - public Map getParameterMap() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Map)AccessController.doPrivileged( - new GetParameterMapPrivilegedAction()); - } else { - return request.getParameterMap(); - } - } - - - public String getProtocol() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getProtocol(); - } - - - public String getScheme() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getScheme(); - } - - - public String getServerName() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getServerName(); - } - - - public int getServerPort() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getServerPort(); - } - - - public BufferedReader getReader() throws IOException { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getReader(); - } - - - public String getRemoteAddr() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRemoteAddr(); - } - - - public String getRemoteHost() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRemoteHost(); - } - - - public void setAttribute(String name, Object o) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - request.setAttribute(name, o); - } - - - public void removeAttribute(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - request.removeAttribute(name); - } - - - public Locale getLocale() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Locale)AccessController.doPrivileged( - new GetLocalePrivilegedAction()); - } else { - return request.getLocale(); - } - } - - - public Enumeration getLocales() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Enumeration)AccessController.doPrivileged( - new GetLocalesPrivilegedAction()); - } else { - return request.getLocales(); - } - } - - - public boolean isSecure() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isSecure(); - } - - - public RequestDispatcher getRequestDispatcher(String path) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (RequestDispatcher)AccessController.doPrivileged( - new GetRequestDispatcherPrivilegedAction(path)); - } else { - return request.getRequestDispatcher(path); - } - } - - public String getRealPath(String path) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRealPath(path); - } - - - public String getAuthType() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getAuthType(); - } - - - public Cookie[] getCookies() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - Cookie[] ret = null; - - /* - * Clone the returned array only if there is a security manager - * in place, so that performance won't suffer in the nonsecure case - */ - if (SecurityUtil.isPackageProtectionEnabled()){ - ret = (Cookie[])AccessController.doPrivileged( - new GetCookiesPrivilegedAction()); - if (ret != null) { - ret = (Cookie[]) ret.clone(); - } - } else { - ret = request.getCookies(); - } - - return ret; - } - - - public long getDateHeader(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getDateHeader(name); - } - - - public String getHeader(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getHeader(name); - } - - - public Enumeration getHeaders(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Enumeration)AccessController.doPrivileged( - new GetHeadersPrivilegedAction(name)); - } else { - return request.getHeaders(name); - } - } - - - public Enumeration getHeaderNames() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (System.getSecurityManager() != null){ - return (Enumeration)AccessController.doPrivileged( - new GetHeaderNamesPrivilegedAction()); - } else { - return request.getHeaderNames(); - } - } - - - public int getIntHeader(String name) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getIntHeader(name); - } - - - public String getMethod() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getMethod(); - } - - - public String getPathInfo() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getPathInfo(); - } - - - public String getPathTranslated() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getPathTranslated(); - } - - - public String getContextPath() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getContextPath(); - } - - - public String getQueryString() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getQueryString(); - } - - - public String getRemoteUser() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRemoteUser(); - } - - - public boolean isUserInRole(String role) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isUserInRole(role); - } - - - public java.security.Principal getUserPrincipal() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getUserPrincipal(); - } - - - public String getRequestedSessionId() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRequestedSessionId(); - } - - - public String getRequestURI() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRequestURI(); - } - - - public StringBuffer getRequestURL() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRequestURL(); - } - - - public String getServletPath() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getServletPath(); - } - - - public HttpSession getSession(boolean create) { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - if (SecurityUtil.isPackageProtectionEnabled()){ - return (HttpSession)AccessController. - doPrivileged(new GetSessionPrivilegedAction(create)); - } else { - return request.getSession(create); - } - } - - public HttpSession getSession() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return getSession(true); - } - - - public boolean isRequestedSessionIdValid() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isRequestedSessionIdValid(); - } - - - public boolean isRequestedSessionIdFromCookie() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isRequestedSessionIdFromCookie(); - } - - - public boolean isRequestedSessionIdFromURL() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isRequestedSessionIdFromURL(); - } - - - public boolean isRequestedSessionIdFromUrl() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.isRequestedSessionIdFromURL(); - } - - - public String getLocalAddr() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getLocalAddr(); - } - - - public String getLocalName() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getLocalName(); - } - - - public int getLocalPort() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getLocalPort(); - } - - - public int getRemotePort() { - - if (request == null) { - throw new IllegalStateException( - sm.getString("requestFacade.nullRequest")); - } - - return request.getRemotePort(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.BufferedReader; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Enumeration; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletInputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.util.StringManager; + + +import org.apache.catalina.security.SecurityUtil; + +/** + * Facade class that wraps a Coyote request object. + * All methods are delegated to the wrapped request. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @author Jean-Francois Arcand + * @version $Revision: 303900 $ $Date: 2005-04-30 00:22:29 +0200 (sam., 30 avr. 2005) $ + */ + +@SuppressWarnings("deprecation") +public class RequestFacade implements HttpServletRequest { + + + // ----------------------------------------------------------- DoPrivileged + + private final class GetAttributePrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getAttributeNames(); + } + } + + + private final class GetParameterMapPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getParameterMap(); + } + } + + + private final class GetRequestDispatcherPrivilegedAction + implements PrivilegedAction { + + private String path; + + public GetRequestDispatcherPrivilegedAction(String path){ + this.path = path; + } + + public Object run() { + return request.getRequestDispatcher(path); + } + } + + + private final class GetParameterPrivilegedAction + implements PrivilegedAction { + + public String name; + + public GetParameterPrivilegedAction(String name){ + this.name = name; + } + + public Object run() { + return request.getParameter(name); + } + } + + + private final class GetParameterNamesPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getParameterNames(); + } + } + + + private final class GetParameterValuePrivilegedAction + implements PrivilegedAction { + + public String name; + + public GetParameterValuePrivilegedAction(String name){ + this.name = name; + } + + public Object run() { + return request.getParameterValues(name); + } + } + + + private final class GetCookiesPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getCookies(); + } + } + + + private final class GetCharacterEncodingPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getCharacterEncoding(); + } + } + + + private final class GetHeadersPrivilegedAction + implements PrivilegedAction { + + private String name; + + public GetHeadersPrivilegedAction(String name){ + this.name = name; + } + + public Object run() { + return request.getHeaders(name); + } + } + + + private final class GetHeaderNamesPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getHeaderNames(); + } + } + + + private final class GetLocalePrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getLocale(); + } + } + + + private final class GetLocalesPrivilegedAction + implements PrivilegedAction { + + public Object run() { + return request.getLocales(); + } + } + + private final class GetSessionPrivilegedAction + implements PrivilegedAction { + + private boolean create; + + public GetSessionPrivilegedAction(boolean create){ + this.create = create; + } + + public Object run() { + return request.getSession(create); + } + } + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a wrapper for the specified request. + * + * @param request The request to be wrapped + */ + public RequestFacade(Request request) { + + this.request = request; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The wrapped request. + */ + protected Request request = null; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // --------------------------------------------------------- Public Methods + + + /** + * Clear facade. + */ + public void clear() { + request = null; + } + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + // ------------------------------------------------- ServletRequest Methods + + + public Object getAttribute(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getAttribute(name); + } + + + public Enumeration getAttributeNames() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Enumeration)AccessController.doPrivileged( + new GetAttributePrivilegedAction()); + } else { + return request.getAttributeNames(); + } + } + + + public String getCharacterEncoding() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (String)AccessController.doPrivileged( + new GetCharacterEncodingPrivilegedAction()); + } else { + return request.getCharacterEncoding(); + } + } + + + public void setCharacterEncoding(String env) + throws java.io.UnsupportedEncodingException { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + request.setCharacterEncoding(env); + } + + + public int getContentLength() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getContentLength(); + } + + + public String getContentType() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getContentType(); + } + + + public ServletInputStream getInputStream() throws IOException { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getInputStream(); + } + + + public String getParameter(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (String)AccessController.doPrivileged( + new GetParameterPrivilegedAction(name)); + } else { + return request.getParameter(name); + } + } + + + public Enumeration getParameterNames() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Enumeration)AccessController.doPrivileged( + new GetParameterNamesPrivilegedAction()); + } else { + return request.getParameterNames(); + } + } + + + public String[] getParameterValues(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + String[] ret = null; + + /* + * Clone the returned array only if there is a security manager + * in place, so that performance won't suffer in the nonsecure case + */ + if (SecurityUtil.isPackageProtectionEnabled()){ + ret = (String[]) AccessController.doPrivileged( + new GetParameterValuePrivilegedAction(name)); + if (ret != null) { + ret = (String[]) ret.clone(); + } + } else { + ret = request.getParameterValues(name); + } + + return ret; + } + + + public Map getParameterMap() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Map)AccessController.doPrivileged( + new GetParameterMapPrivilegedAction()); + } else { + return request.getParameterMap(); + } + } + + + public String getProtocol() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getProtocol(); + } + + + public String getScheme() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getScheme(); + } + + + public String getServerName() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getServerName(); + } + + + public int getServerPort() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getServerPort(); + } + + + public BufferedReader getReader() throws IOException { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getReader(); + } + + + public String getRemoteAddr() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRemoteAddr(); + } + + + public String getRemoteHost() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRemoteHost(); + } + + + public void setAttribute(String name, Object o) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + request.setAttribute(name, o); + } + + + public void removeAttribute(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + request.removeAttribute(name); + } + + + public Locale getLocale() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Locale)AccessController.doPrivileged( + new GetLocalePrivilegedAction()); + } else { + return request.getLocale(); + } + } + + + public Enumeration getLocales() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Enumeration)AccessController.doPrivileged( + new GetLocalesPrivilegedAction()); + } else { + return request.getLocales(); + } + } + + + public boolean isSecure() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isSecure(); + } + + + public RequestDispatcher getRequestDispatcher(String path) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (RequestDispatcher)AccessController.doPrivileged( + new GetRequestDispatcherPrivilegedAction(path)); + } else { + return request.getRequestDispatcher(path); + } + } + + public String getRealPath(String path) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRealPath(path); + } + + + public String getAuthType() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getAuthType(); + } + + + public Cookie[] getCookies() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + Cookie[] ret = null; + + /* + * Clone the returned array only if there is a security manager + * in place, so that performance won't suffer in the nonsecure case + */ + if (SecurityUtil.isPackageProtectionEnabled()){ + ret = (Cookie[])AccessController.doPrivileged( + new GetCookiesPrivilegedAction()); + if (ret != null) { + ret = (Cookie[]) ret.clone(); + } + } else { + ret = request.getCookies(); + } + + return ret; + } + + + public long getDateHeader(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getDateHeader(name); + } + + + public String getHeader(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getHeader(name); + } + + + public Enumeration getHeaders(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Enumeration)AccessController.doPrivileged( + new GetHeadersPrivilegedAction(name)); + } else { + return request.getHeaders(name); + } + } + + + public Enumeration getHeaderNames() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (System.getSecurityManager() != null){ + return (Enumeration)AccessController.doPrivileged( + new GetHeaderNamesPrivilegedAction()); + } else { + return request.getHeaderNames(); + } + } + + + public int getIntHeader(String name) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getIntHeader(name); + } + + + public String getMethod() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getMethod(); + } + + + public String getPathInfo() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getPathInfo(); + } + + + public String getPathTranslated() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getPathTranslated(); + } + + + public String getContextPath() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getContextPath(); + } + + + public String getQueryString() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getQueryString(); + } + + + public String getRemoteUser() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRemoteUser(); + } + + + public boolean isUserInRole(String role) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isUserInRole(role); + } + + + public java.security.Principal getUserPrincipal() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getUserPrincipal(); + } + + + public String getRequestedSessionId() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRequestedSessionId(); + } + + + public String getRequestURI() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRequestURI(); + } + + + public StringBuffer getRequestURL() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRequestURL(); + } + + + public String getServletPath() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getServletPath(); + } + + + public HttpSession getSession(boolean create) { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + if (SecurityUtil.isPackageProtectionEnabled()){ + return (HttpSession)AccessController. + doPrivileged(new GetSessionPrivilegedAction(create)); + } else { + return request.getSession(create); + } + } + + public HttpSession getSession() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return getSession(true); + } + + + public boolean isRequestedSessionIdValid() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isRequestedSessionIdValid(); + } + + + public boolean isRequestedSessionIdFromCookie() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isRequestedSessionIdFromCookie(); + } + + + public boolean isRequestedSessionIdFromURL() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isRequestedSessionIdFromURL(); + } + + + public boolean isRequestedSessionIdFromUrl() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.isRequestedSessionIdFromURL(); + } + + + public String getLocalAddr() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getLocalAddr(); + } + + + public String getLocalName() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getLocalName(); + } + + + public int getLocalPort() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getLocalPort(); + } + + + public int getRemotePort() { + + if (request == null) { + throw new IllegalStateException( + sm.getString("requestFacade.nullRequest")); + } + + return request.getRemotePort(); + } + +} diff --git a/java/org/apache/catalina/connector/Response.java b/java/org/apache/catalina/connector/Response.java index 89c9fc1eb..a13249693 100644 --- a/java/org/apache/catalina/connector/Response.java +++ b/java/org/apache/catalina/connector/Response.java @@ -1,1563 +1,1563 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Locale; -import java.util.TimeZone; -import java.util.Vector; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.Session; -import org.apache.catalina.Wrapper; -import org.apache.catalina.security.SecurityUtil; -import org.apache.catalina.util.CharsetMapper; -import org.apache.catalina.util.DateTool; -import org.apache.catalina.util.StringManager; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.UEncoder; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.http.ServerCookie; -import org.apache.tomcat.util.net.URL; - -/** - * Wrapper object for the Coyote response. - * - * @author Remy Maucherat - * @author Craig R. McClanahan - * @version $Revision: 371866 $ $Date: 2006-01-24 09:52:54 +0100 (mar., 24 janv. 2006) $ - */ - -public class Response - implements HttpServletResponse { - - - // ----------------------------------------------------------- Constructors - - static { - // Ensure that URL is loaded for SM - URL.isSchemeChar('c'); - } - - public Response() { - urlEncoder.addSafeCharacter('/'); - } - - - // ----------------------------------------------------- Class Variables - - - /** - * Descriptive information about this Response implementation. - */ - protected static final String info = - "org.apache.coyote.tomcat5.CoyoteResponse/1.0"; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - /** - * The date format we will use for creating date headers. - */ - protected SimpleDateFormat format = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Associated Catalina connector. - */ - protected Connector connector; - - /** - * Return the Connector through which this Request was received. - */ - public Connector getConnector() { - return (this.connector); - } - - /** - * Set the Connector through which this Request was received. - * - * @param connector The new connector - */ - public void setConnector(Connector connector) { - this.connector = connector; - if("AJP/1.3".equals(connector.getProtocol())) { - // default size to size of one ajp-packet - outputBuffer = new OutputBuffer(8184); - } else { - outputBuffer = new OutputBuffer(); - } - outputStream = new CoyoteOutputStream(outputBuffer); - writer = new CoyoteWriter(outputBuffer); - } - - - /** - * Coyote response. - */ - protected org.apache.coyote.Response coyoteResponse; - - /** - * Set the Coyote response. - * - * @param coyoteResponse The Coyote response - */ - public void setCoyoteResponse(org.apache.coyote.Response coyoteResponse) { - this.coyoteResponse = coyoteResponse; - outputBuffer.setResponse(coyoteResponse); - } - - /** - * Get the Coyote response. - */ - public org.apache.coyote.Response getCoyoteResponse() { - return (coyoteResponse); - } - - - /** - * Return the Context within which this Request is being processed. - */ - public Context getContext() { - return (request.getContext()); - } - - /** - * Set the Context within which this Request is being processed. This - * must be called as soon as the appropriate Context is identified, because - * it identifies the value to be returned by getContextPath(), - * and thus enables parsing of the request URI. - * - * @param context The newly associated Context - */ - public void setContext(Context context) { - request.setContext(context); - } - - - /** - * The associated output buffer. - */ - protected OutputBuffer outputBuffer; - - - /** - * The associated output stream. - */ - protected CoyoteOutputStream outputStream; - - - /** - * The associated writer. - */ - protected CoyoteWriter writer; - - - /** - * The application commit flag. - */ - protected boolean appCommitted = false; - - - /** - * The included flag. - */ - protected boolean included = false; - - - /** - * The characterEncoding flag - */ - private boolean isCharacterEncodingSet = false; - - /** - * The error flag. - */ - protected boolean error = false; - - - /** - * The set of Cookies associated with this Response. - */ - protected ArrayList cookies = new ArrayList(); - - - /** - * Using output stream flag. - */ - protected boolean usingOutputStream = false; - - - /** - * Using writer flag. - */ - protected boolean usingWriter = false; - - - /** - * URL encoder. - */ - protected UEncoder urlEncoder = new UEncoder(); - - - /** - * Recyclable buffer to hold the redirect URL. - */ - protected CharChunk redirectURLCC = new CharChunk(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Release all object references, and initialize instance variables, in - * preparation for reuse of this object. - */ - public void recycle() { - - outputBuffer.recycle(); - usingOutputStream = false; - usingWriter = false; - appCommitted = false; - included = false; - error = false; - isCharacterEncodingSet = false; - - cookies.clear(); - - if (Constants.SECURITY) { - if (facade != null) { - facade.clear(); - facade = null; - } - if (outputStream != null) { - outputStream.clear(); - outputStream = null; - } - if (writer != null) { - writer.clear(); - writer = null; - } - } else { - writer.recycle(); - } - - } - - - /** - * Clear cached encoders (to save memory for Comet requests). - */ - public void clearEncoders() { - outputBuffer.clearEncoders(); - } - - - // ------------------------------------------------------- Response Methods - - - /** - * Return the number of bytes actually written to the output stream. - */ - public int getContentCount() { - return outputBuffer.getContentWritten(); - } - - - /** - * Set the application commit flag. - * - * @param appCommitted The new application committed flag value - */ - public void setAppCommitted(boolean appCommitted) { - this.appCommitted = appCommitted; - } - - - /** - * Application commit flag accessor. - */ - public boolean isAppCommitted() { - return (this.appCommitted || isCommitted() || isSuspended() - || ((getContentLength() > 0) - && (getContentCount() >= getContentLength()))); - } - - - /** - * Return the "processing inside an include" flag. - */ - public boolean getIncluded() { - return included; - } - - - /** - * Set the "processing inside an include" flag. - * - * @param included true if we are currently inside a - * RequestDispatcher.include(), else false - */ - public void setIncluded(boolean included) { - this.included = included; - } - - - /** - * Return descriptive information about this Response implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - return (info); - } - - - /** - * The request with which this response is associated. - */ - protected Request request = null; - - /** - * Return the Request with which this Response is associated. - */ - public org.apache.catalina.connector.Request getRequest() { - return (this.request); - } - - /** - * Set the Request with which this Response is associated. - * - * @param request The new associated request - */ - public void setRequest(org.apache.catalina.connector.Request request) { - this.request = (Request) request; - } - - - /** - * The facade associated with this response. - */ - protected ResponseFacade facade = null; - - /** - * Return the ServletResponse for which this object - * is the facade. - */ - public HttpServletResponse getResponse() { - if (facade == null) { - facade = new ResponseFacade(this); - } - return (facade); - } - - - /** - * Return the output stream associated with this Response. - */ - public OutputStream getStream() { - if (outputStream == null) { - outputStream = new CoyoteOutputStream(outputBuffer); - } - return outputStream; - } - - - /** - * Set the output stream associated with this Response. - * - * @param stream The new output stream - */ - public void setStream(OutputStream stream) { - // This method is evil - } - - - /** - * Set the suspended flag. - * - * @param suspended The new suspended flag value - */ - public void setSuspended(boolean suspended) { - outputBuffer.setSuspended(suspended); - } - - - /** - * Suspended flag accessor. - */ - public boolean isSuspended() { - return outputBuffer.isSuspended(); - } - - - /** - * Set the error flag. - */ - public void setError() { - error = true; - } - - - /** - * Error flag accessor. - */ - public boolean isError() { - return error; - } - - - /** - * Create and return a ServletOutputStream to write the content - * associated with this Response. - * - * @exception IOException if an input/output error occurs - */ - public ServletOutputStream createOutputStream() - throws IOException { - // Probably useless - if (outputStream == null) { - outputStream = new CoyoteOutputStream(outputBuffer); - } - return outputStream; - } - - - /** - * Perform whatever actions are required to flush and close the output - * stream or writer, in a single operation. - * - * @exception IOException if an input/output error occurs - */ - public void finishResponse() - throws IOException { - // Writing leftover bytes - try { - outputBuffer.close(); - } catch(IOException e) { - ; - } catch(Throwable t) { - t.printStackTrace(); - } - } - - - /** - * Return the content length that was set or calculated for this Response. - */ - public int getContentLength() { - return (coyoteResponse.getContentLength()); - } - - - /** - * Return the content type that was set or calculated for this response, - * or null if no content type was set. - */ - public String getContentType() { - return (coyoteResponse.getContentType()); - } - - - /** - * Return a PrintWriter that can be used to render error messages, - * regardless of whether a stream or writer has already been acquired. - * - * @return Writer which can be used for error reports. If the response is - * not an error report returned using sendError or triggered by an - * unexpected exception thrown during the servlet processing - * (and only in that case), null will be returned if the response stream - * has already been used. - * - * @exception IOException if an input/output error occurs - */ - public PrintWriter getReporter() throws IOException { - if (outputBuffer.isNew()) { - outputBuffer.checkConverter(); - if (writer == null) { - writer = new CoyoteWriter(outputBuffer); - } - return writer; - } else { - return null; - } - } - - - // ------------------------------------------------ ServletResponse Methods - - - /** - * Flush the buffer and commit this response. - * - * @exception IOException if an input/output error occurs - */ - public void flushBuffer() - throws IOException { - outputBuffer.flush(); - } - - - /** - * Return the actual buffer size used for this Response. - */ - public int getBufferSize() { - return outputBuffer.getBufferSize(); - } - - - /** - * Return the character encoding used for this Response. - */ - public String getCharacterEncoding() { - return (coyoteResponse.getCharacterEncoding()); - } - - - /** - * Return the servlet output stream associated with this Response. - * - * @exception IllegalStateException if getWriter has - * already been called for this response - * @exception IOException if an input/output error occurs - */ - public ServletOutputStream getOutputStream() - throws IOException { - - if (usingWriter) - throw new IllegalStateException - (sm.getString("coyoteResponse.getOutputStream.ise")); - - usingOutputStream = true; - if (outputStream == null) { - outputStream = new CoyoteOutputStream(outputBuffer); - } - return outputStream; - - } - - - /** - * Return the Locale assigned to this response. - */ - public Locale getLocale() { - return (coyoteResponse.getLocale()); - } - - - /** - * Return the writer associated with this Response. - * - * @exception IllegalStateException if getOutputStream has - * already been called for this response - * @exception IOException if an input/output error occurs - */ - public PrintWriter getWriter() - throws IOException { - - if (usingOutputStream) - throw new IllegalStateException - (sm.getString("coyoteResponse.getWriter.ise")); - - usingWriter = true; - outputBuffer.checkConverter(); - if (writer == null) { - writer = new CoyoteWriter(outputBuffer); - } - return writer; - - } - - - /** - * Has the output of this response already been committed? - */ - public boolean isCommitted() { - return (coyoteResponse.isCommitted()); - } - - - /** - * Clear any content written to the buffer. - * - * @exception IllegalStateException if this response has already - * been committed - */ - public void reset() { - - if (included) - return; // Ignore any call from an included servlet - - coyoteResponse.reset(); - outputBuffer.reset(); - } - - - /** - * Reset the data buffer but not any status or header information. - * - * @exception IllegalStateException if the response has already - * been committed - */ - public void resetBuffer() { - - if (isCommitted()) - throw new IllegalStateException - (sm.getString("coyoteResponse.resetBuffer.ise")); - - outputBuffer.reset(); - - } - - - /** - * Set the buffer size to be used for this Response. - * - * @param size The new buffer size - * - * @exception IllegalStateException if this method is called after - * output has been committed for this response - */ - public void setBufferSize(int size) { - - if (isCommitted() || !outputBuffer.isNew()) - throw new IllegalStateException - (sm.getString("coyoteResponse.setBufferSize.ise")); - - outputBuffer.setBufferSize(size); - - } - - - /** - * Set the content length (in bytes) for this Response. - * - * @param length The new content length - */ - public void setContentLength(int length) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - if (usingWriter) - return; - - coyoteResponse.setContentLength(length); - - } - - - /** - * Set the content type for this Response. - * - * @param type The new content type - */ - public void setContentType(String type) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - // Ignore charset if getWriter() has already been called - if (usingWriter) { - if (type != null) { - int index = type.indexOf(";"); - if (index != -1) { - type = type.substring(0, index); - } - } - } - - coyoteResponse.setContentType(type); - - // Check to see if content type contains charset - if (type != null) { - int index = type.indexOf(";"); - if (index != -1) { - int len = type.length(); - index++; - while (index < len && Character.isSpace(type.charAt(index))) { - index++; - } - if (index+7 < len - && type.charAt(index) == 'c' - && type.charAt(index+1) == 'h' - && type.charAt(index+2) == 'a' - && type.charAt(index+3) == 'r' - && type.charAt(index+4) == 's' - && type.charAt(index+5) == 'e' - && type.charAt(index+6) == 't' - && type.charAt(index+7) == '=') { - isCharacterEncodingSet = true; - } - } - } - } - - - /* - * Overrides the name of the character encoding used in the body - * of the request. This method must be called prior to reading - * request parameters or reading input using getReader(). - * - * @param charset String containing the name of the chararacter encoding. - */ - public void setCharacterEncoding(String charset) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - // Ignore any call made after the getWriter has been invoked - // The default should be used - if (usingWriter) - return; - - coyoteResponse.setCharacterEncoding(charset); - isCharacterEncodingSet = true; - } - - - - /** - * Set the Locale that is appropriate for this response, including - * setting the appropriate character encoding. - * - * @param locale The new locale - */ - public void setLocale(Locale locale) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - coyoteResponse.setLocale(locale); - - // Ignore any call made after the getWriter has been invoked. - // The default should be used - if (usingWriter) - return; - - if (isCharacterEncodingSet) { - return; - } - - CharsetMapper cm = getContext().getCharsetMapper(); - String charset = cm.getCharset( locale ); - if ( charset != null ){ - coyoteResponse.setCharacterEncoding(charset); - } - - } - - - // --------------------------------------------------- HttpResponse Methods - - - /** - * Return an array of all cookies set for this response, or - * a zero-length array if no cookies have been set. - */ - public Cookie[] getCookies() { - return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); - } - - - /** - * Return the value for the specified header, or null if this - * header has not been set. If more than one value was added for this - * name, only the first is returned; use getHeaderValues() to retrieve all - * of them. - * - * @param name Header name to look up - */ - public String getHeader(String name) { - return coyoteResponse.getMimeHeaders().getHeader(name); - } - - - /** - * Return an array of all the header names set for this response, or - * a zero-length array if no headers have been set. - */ - public String[] getHeaderNames() { - - MimeHeaders headers = coyoteResponse.getMimeHeaders(); - int n = headers.size(); - String[] result = new String[n]; - for (int i = 0; i < n; i++) { - result[i] = headers.getName(i).toString(); - } - return result; - - } - - - /** - * Return an array of all the header values associated with the - * specified header name, or an zero-length array if there are no such - * header values. - * - * @param name Header name to look up - */ - public String[] getHeaderValues(String name) { - - Enumeration enumeration = coyoteResponse.getMimeHeaders().values(name); - Vector result = new Vector(); - while (enumeration.hasMoreElements()) { - result.addElement(enumeration.nextElement()); - } - String[] resultArray = new String[result.size()]; - result.copyInto(resultArray); - return resultArray; - - } - - - /** - * Return the error message that was set with sendError() - * for this Response. - */ - public String getMessage() { - return coyoteResponse.getMessage(); - } - - - /** - * Return the HTTP status code associated with this Response. - */ - public int getStatus() { - return coyoteResponse.getStatus(); - } - - - /** - * Reset this response, and specify the values for the HTTP status code - * and corresponding message. - * - * @exception IllegalStateException if this response has already been - * committed - */ - public void reset(int status, String message) { - reset(); - setStatus(status, message); - } - - - // -------------------------------------------- HttpServletResponse Methods - - - /** - * Add the specified Cookie to those that will be included with - * this Response. - * - * @param cookie Cookie to be added - */ - public void addCookie(final Cookie cookie) { - - // Ignore any call from an included servlet - if (included) - return; - - addCookieInternal(cookie); - - } - - - /** - * Add the specified Cookie to those that will be included with - * this Response. - * - * @param cookie Cookie to be added - */ - public void addCookieInternal(final Cookie cookie) { - - if (isCommitted()) - return; - - cookies.add(cookie); - - final StringBuffer sb = new StringBuffer(); - if (SecurityUtil.isPackageProtectionEnabled()) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run(){ - ServerCookie.appendCookieValue - (sb, cookie.getVersion(), cookie.getName(), - cookie.getValue(), cookie.getPath(), - cookie.getDomain(), cookie.getComment(), - cookie.getMaxAge(), cookie.getSecure()); - return null; - } - }); - } else { - ServerCookie.appendCookieValue - (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), - cookie.getPath(), cookie.getDomain(), cookie.getComment(), - cookie.getMaxAge(), cookie.getSecure()); - } - - // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 ) - // RFC2965 is not supported by browsers and the Servlet spec - // asks for 2109. - addHeader("Set-Cookie", sb.toString()); - - } - - - /** - * Add the specified date header to the specified value. - * - * @param name Name of the header to set - * @param value Date value to be set - */ - public void addDateHeader(String name, long value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) { - return; - } - - if (format == null) { - format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, - Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - addHeader(name, FastHttpDateFormat.formatDate(value, format)); - - } - - - /** - * Add the specified header to the specified value. - * - * @param name Name of the header to set - * @param value Value to be set - */ - public void addHeader(String name, String value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - coyoteResponse.addHeader(name, value); - - } - - - /** - * Add the specified integer header to the specified value. - * - * @param name Name of the header to set - * @param value Integer value to be set - */ - public void addIntHeader(String name, int value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - addHeader(name, "" + value); - - } - - - /** - * Has the specified header been set already in this response? - * - * @param name Name of the header to check - */ - public boolean containsHeader(String name) { - // Need special handling for Content-Type and Content-Length due to - // special handling of these in coyoteResponse - char cc=name.charAt(0); - if(cc=='C' || cc=='c') { - if(name.equalsIgnoreCase("Content-Type")) { - // Will return null if this has not been set - return (coyoteResponse.getContentType() != null); - } - if(name.equalsIgnoreCase("Content-Length")) { - // -1 means not known and is not sent to client - return (coyoteResponse.getContentLengthLong() != -1); - } - } - - return coyoteResponse.containsHeader(name); - } - - - /** - * Encode the session identifier associated with this response - * into the specified redirect URL, if necessary. - * - * @param url URL to be encoded - */ - public String encodeRedirectURL(String url) { - - if (isEncodeable(toAbsolute(url))) { - return (toEncoded(url, request.getSessionInternal().getIdInternal())); - } else { - return (url); - } - - } - - - /** - * Encode the session identifier associated with this response - * into the specified redirect URL, if necessary. - * - * @param url URL to be encoded - * - * @deprecated As of Version 2.1 of the Java Servlet API, use - * encodeRedirectURL() instead. - */ - public String encodeRedirectUrl(String url) { - return (encodeRedirectURL(url)); - } - - - /** - * Encode the session identifier associated with this response - * into the specified URL, if necessary. - * - * @param url URL to be encoded - */ - public String encodeURL(String url) { - - String absolute = toAbsolute(url); - if (isEncodeable(absolute)) { - // W3c spec clearly said - if (url.equalsIgnoreCase("")){ - url = absolute; - } - return (toEncoded(url, request.getSessionInternal().getIdInternal())); - } else { - return (url); - } - - } - - - /** - * Encode the session identifier associated with this response - * into the specified URL, if necessary. - * - * @param url URL to be encoded - * - * @deprecated As of Version 2.1 of the Java Servlet API, use - * encodeURL() instead. - */ - public String encodeUrl(String url) { - return (encodeURL(url)); - } - - - /** - * Send an acknowledgment of a request. - * - * @exception IOException if an input/output error occurs - */ - public void sendAcknowledgement() - throws IOException { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - coyoteResponse.acknowledge(); - - } - - - /** - * Send an error response with the specified status and a - * default message. - * - * @param status HTTP status code to send - * - * @exception IllegalStateException if this response has - * already been committed - * @exception IOException if an input/output error occurs - */ - public void sendError(int status) - throws IOException { - sendError(status, null); - } - - - /** - * Send an error response with the specified status and message. - * - * @param status HTTP status code to send - * @param message Corresponding message to send - * - * @exception IllegalStateException if this response has - * already been committed - * @exception IOException if an input/output error occurs - */ - public void sendError(int status, String message) - throws IOException { - - if (isCommitted()) - throw new IllegalStateException - (sm.getString("coyoteResponse.sendError.ise")); - - // Ignore any call from an included servlet - if (included) - return; - - Wrapper wrapper = getRequest().getWrapper(); - if (wrapper != null) { - wrapper.incrementErrorCount(); - } - - setError(); - - coyoteResponse.setStatus(status); - coyoteResponse.setMessage(message); - - // Clear any data content that has been buffered - resetBuffer(); - - // Cause the response to be finished (from the application perspective) - setSuspended(true); - - } - - - /** - * Send a temporary redirect to the specified redirect location URL. - * - * @param location Location URL to redirect to - * - * @exception IllegalStateException if this response has - * already been committed - * @exception IOException if an input/output error occurs - */ - public void sendRedirect(String location) - throws IOException { - - if (isCommitted()) - throw new IllegalStateException - (sm.getString("coyoteResponse.sendRedirect.ise")); - - // Ignore any call from an included servlet - if (included) - return; - - // Clear any data content that has been buffered - resetBuffer(); - - // Generate a temporary redirect to the specified location - try { - String absolute = toAbsolute(location); - setStatus(SC_FOUND); - setHeader("Location", absolute); - } catch (IllegalArgumentException e) { - setStatus(SC_NOT_FOUND); - } - - // Cause the response to be finished (from the application perspective) - setSuspended(true); - - } - - - /** - * Set the specified date header to the specified value. - * - * @param name Name of the header to set - * @param value Date value to be set - */ - public void setDateHeader(String name, long value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) { - return; - } - - if (format == null) { - format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, - Locale.US); - format.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - setHeader(name, FastHttpDateFormat.formatDate(value, format)); - - } - - - /** - * Set the specified header to the specified value. - * - * @param name Name of the header to set - * @param value Value to be set - */ - public void setHeader(String name, String value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - coyoteResponse.setHeader(name, value); - - } - - - /** - * Set the specified integer header to the specified value. - * - * @param name Name of the header to set - * @param value Integer value to be set - */ - public void setIntHeader(String name, int value) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - setHeader(name, "" + value); - - } - - - /** - * Set the HTTP status to be returned with this response. - * - * @param status The new HTTP status - */ - public void setStatus(int status) { - setStatus(status, null); - } - - - /** - * Set the HTTP status and message to be returned with this response. - * - * @param status The new HTTP status - * @param message The associated text message - * - * @deprecated As of Version 2.1 of the Java Servlet API, this method - * has been deprecated due to the ambiguous meaning of the message - * parameter. - */ - public void setStatus(int status, String message) { - - if (isCommitted()) - return; - - // Ignore any call from an included servlet - if (included) - return; - - coyoteResponse.setStatus(status); - coyoteResponse.setMessage(message); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return true if the specified URL should be encoded with - * a session identifier. This will be true if all of the following - * conditions are met: - *

      - *
    • The request we are responding to asked for a valid session - *
    • The requested session ID was not received via a cookie - *
    • The specified URL points back to somewhere within the web - * application that is responding to this request - *
    - * - * @param location Absolute URL to be validated - */ - protected boolean isEncodeable(final String location) { - - if (location == null) - return (false); - - // Is this an intra-document reference? - if (location.startsWith("#")) - return (false); - - // Are we in a valid session that is not using cookies? - final Request hreq = request; - final Session session = hreq.getSessionInternal(false); - if (session == null) - return (false); - if (hreq.isRequestedSessionIdFromCookie()) - return (false); - - if (SecurityUtil.isPackageProtectionEnabled()) { - return ((Boolean) - AccessController.doPrivileged(new PrivilegedAction() { - - public Object run(){ - return new Boolean(doIsEncodeable(hreq, session, location)); - } - })).booleanValue(); - } else { - return doIsEncodeable(hreq, session, location); - } - } - - private boolean doIsEncodeable(Request hreq, Session session, - String location) { - // Is this a valid absolute URL? - URL url = null; - try { - url = new URL(location); - } catch (MalformedURLException e) { - return (false); - } - - // Does this URL match down to (and including) the context path? - if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) - return (false); - if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) - return (false); - int serverPort = hreq.getServerPort(); - if (serverPort == -1) { - if ("https".equals(hreq.getScheme())) - serverPort = 443; - else - serverPort = 80; - } - int urlPort = url.getPort(); - if (urlPort == -1) { - if ("https".equals(url.getProtocol())) - urlPort = 443; - else - urlPort = 80; - } - if (serverPort != urlPort) - return (false); - - String contextPath = getContext().getPath(); - if (contextPath != null) { - String file = url.getFile(); - if ((file == null) || !file.startsWith(contextPath)) - return (false); - if( file.indexOf(";jsessionid=" + session.getIdInternal()) >= 0 ) - return (false); - } - - // This URL belongs to our web application, so it is encodeable - return (true); - - } - - - /** - * Convert (if necessary) and return the absolute URL that represents the - * resource referenced by this possibly relative URL. If this URL is - * already absolute, return it unchanged. - * - * @param location URL to be (possibly) converted and then returned - * - * @exception IllegalArgumentException if a MalformedURLException is - * thrown when converting the relative URL to an absolute one - */ - private String toAbsolute(String location) { - - if (location == null) - return (location); - - boolean leadingSlash = location.startsWith("/"); - - if (leadingSlash || !hasScheme(location)) { - - redirectURLCC.recycle(); - - String scheme = request.getScheme(); - String name = request.getServerName(); - int port = request.getServerPort(); - - try { - redirectURLCC.append(scheme, 0, scheme.length()); - redirectURLCC.append("://", 0, 3); - redirectURLCC.append(name, 0, name.length()); - if ((scheme.equals("http") && port != 80) - || (scheme.equals("https") && port != 443)) { - redirectURLCC.append(':'); - String portS = port + ""; - redirectURLCC.append(portS, 0, portS.length()); - } - if (!leadingSlash) { - String relativePath = request.getDecodedRequestURI(); - int pos = relativePath.lastIndexOf('/'); - relativePath = relativePath.substring(0, pos); - - String encodedURI = null; - final String frelativePath = relativePath; - if (SecurityUtil.isPackageProtectionEnabled() ){ - try{ - encodedURI = (String)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - public Object run() throws IOException{ - return urlEncoder.encodeURL(frelativePath); - } - }); - } catch (PrivilegedActionException pae){ - IllegalArgumentException iae = - new IllegalArgumentException(location); - iae.initCause(pae.getException()); - throw iae; - } - } else { - encodedURI = urlEncoder.encodeURL(relativePath); - } - redirectURLCC.append(encodedURI, 0, encodedURI.length()); - redirectURLCC.append('/'); - } - redirectURLCC.append(location, 0, location.length()); - } catch (IOException e) { - IllegalArgumentException iae = - new IllegalArgumentException(location); - iae.initCause(e); - throw iae; - } - - return redirectURLCC.toString(); - - } else { - - return (location); - - } - - } - - - /** - * Determine if a URI string has a scheme component. - */ - private boolean hasScheme(String uri) { - int len = uri.length(); - for(int i=0; i < len ; i++) { - char c = uri.charAt(i); - if(c == ':') { - return i > 0; - } else if(!URL.isSchemeChar(c)) { - return false; - } - } - return false; - } - - /** - * Return the specified URL with the specified session identifier - * suitably encoded. - * - * @param url URL to be encoded with the session id - * @param sessionId Session id to be included in the encoded URL - */ - protected String toEncoded(String url, String sessionId) { - - if ((url == null) || (sessionId == null)) - return (url); - - String path = url; - String query = ""; - String anchor = ""; - int question = url.indexOf('?'); - if (question >= 0) { - path = url.substring(0, question); - query = url.substring(question); - } - int pound = path.indexOf('#'); - if (pound >= 0) { - anchor = path.substring(pound); - path = path.substring(0, pound); - } - StringBuffer sb = new StringBuffer(path); - if( sb.length() > 0 ) { // jsessionid can't be first. - sb.append(";jsessionid="); - sb.append(sessionId); - } - sb.append(anchor); - sb.append(query); - return (sb.toString()); - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Locale; +import java.util.TimeZone; +import java.util.Vector; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Session; +import org.apache.catalina.Wrapper; +import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.util.CharsetMapper; +import org.apache.catalina.util.DateTool; +import org.apache.catalina.util.StringManager; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.UEncoder; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.http.ServerCookie; +import org.apache.tomcat.util.net.URL; + +/** + * Wrapper object for the Coyote response. + * + * @author Remy Maucherat + * @author Craig R. McClanahan + * @version $Revision: 371866 $ $Date: 2006-01-24 09:52:54 +0100 (mar., 24 janv. 2006) $ + */ + +public class Response + implements HttpServletResponse { + + + // ----------------------------------------------------------- Constructors + + static { + // Ensure that URL is loaded for SM + URL.isSchemeChar('c'); + } + + public Response() { + urlEncoder.addSafeCharacter('/'); + } + + + // ----------------------------------------------------- Class Variables + + + /** + * Descriptive information about this Response implementation. + */ + protected static final String info = + "org.apache.coyote.tomcat5.CoyoteResponse/1.0"; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + /** + * The date format we will use for creating date headers. + */ + protected SimpleDateFormat format = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Associated Catalina connector. + */ + protected Connector connector; + + /** + * Return the Connector through which this Request was received. + */ + public Connector getConnector() { + return (this.connector); + } + + /** + * Set the Connector through which this Request was received. + * + * @param connector The new connector + */ + public void setConnector(Connector connector) { + this.connector = connector; + if("AJP/1.3".equals(connector.getProtocol())) { + // default size to size of one ajp-packet + outputBuffer = new OutputBuffer(8184); + } else { + outputBuffer = new OutputBuffer(); + } + outputStream = new CoyoteOutputStream(outputBuffer); + writer = new CoyoteWriter(outputBuffer); + } + + + /** + * Coyote response. + */ + protected org.apache.coyote.Response coyoteResponse; + + /** + * Set the Coyote response. + * + * @param coyoteResponse The Coyote response + */ + public void setCoyoteResponse(org.apache.coyote.Response coyoteResponse) { + this.coyoteResponse = coyoteResponse; + outputBuffer.setResponse(coyoteResponse); + } + + /** + * Get the Coyote response. + */ + public org.apache.coyote.Response getCoyoteResponse() { + return (coyoteResponse); + } + + + /** + * Return the Context within which this Request is being processed. + */ + public Context getContext() { + return (request.getContext()); + } + + /** + * Set the Context within which this Request is being processed. This + * must be called as soon as the appropriate Context is identified, because + * it identifies the value to be returned by getContextPath(), + * and thus enables parsing of the request URI. + * + * @param context The newly associated Context + */ + public void setContext(Context context) { + request.setContext(context); + } + + + /** + * The associated output buffer. + */ + protected OutputBuffer outputBuffer; + + + /** + * The associated output stream. + */ + protected CoyoteOutputStream outputStream; + + + /** + * The associated writer. + */ + protected CoyoteWriter writer; + + + /** + * The application commit flag. + */ + protected boolean appCommitted = false; + + + /** + * The included flag. + */ + protected boolean included = false; + + + /** + * The characterEncoding flag + */ + private boolean isCharacterEncodingSet = false; + + /** + * The error flag. + */ + protected boolean error = false; + + + /** + * The set of Cookies associated with this Response. + */ + protected ArrayList cookies = new ArrayList(); + + + /** + * Using output stream flag. + */ + protected boolean usingOutputStream = false; + + + /** + * Using writer flag. + */ + protected boolean usingWriter = false; + + + /** + * URL encoder. + */ + protected UEncoder urlEncoder = new UEncoder(); + + + /** + * Recyclable buffer to hold the redirect URL. + */ + protected CharChunk redirectURLCC = new CharChunk(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Release all object references, and initialize instance variables, in + * preparation for reuse of this object. + */ + public void recycle() { + + outputBuffer.recycle(); + usingOutputStream = false; + usingWriter = false; + appCommitted = false; + included = false; + error = false; + isCharacterEncodingSet = false; + + cookies.clear(); + + if (Constants.SECURITY) { + if (facade != null) { + facade.clear(); + facade = null; + } + if (outputStream != null) { + outputStream.clear(); + outputStream = null; + } + if (writer != null) { + writer.clear(); + writer = null; + } + } else { + writer.recycle(); + } + + } + + + /** + * Clear cached encoders (to save memory for Comet requests). + */ + public void clearEncoders() { + outputBuffer.clearEncoders(); + } + + + // ------------------------------------------------------- Response Methods + + + /** + * Return the number of bytes actually written to the output stream. + */ + public int getContentCount() { + return outputBuffer.getContentWritten(); + } + + + /** + * Set the application commit flag. + * + * @param appCommitted The new application committed flag value + */ + public void setAppCommitted(boolean appCommitted) { + this.appCommitted = appCommitted; + } + + + /** + * Application commit flag accessor. + */ + public boolean isAppCommitted() { + return (this.appCommitted || isCommitted() || isSuspended() + || ((getContentLength() > 0) + && (getContentCount() >= getContentLength()))); + } + + + /** + * Return the "processing inside an include" flag. + */ + public boolean getIncluded() { + return included; + } + + + /** + * Set the "processing inside an include" flag. + * + * @param included true if we are currently inside a + * RequestDispatcher.include(), else false + */ + public void setIncluded(boolean included) { + this.included = included; + } + + + /** + * Return descriptive information about this Response implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + return (info); + } + + + /** + * The request with which this response is associated. + */ + protected Request request = null; + + /** + * Return the Request with which this Response is associated. + */ + public org.apache.catalina.connector.Request getRequest() { + return (this.request); + } + + /** + * Set the Request with which this Response is associated. + * + * @param request The new associated request + */ + public void setRequest(org.apache.catalina.connector.Request request) { + this.request = (Request) request; + } + + + /** + * The facade associated with this response. + */ + protected ResponseFacade facade = null; + + /** + * Return the ServletResponse for which this object + * is the facade. + */ + public HttpServletResponse getResponse() { + if (facade == null) { + facade = new ResponseFacade(this); + } + return (facade); + } + + + /** + * Return the output stream associated with this Response. + */ + public OutputStream getStream() { + if (outputStream == null) { + outputStream = new CoyoteOutputStream(outputBuffer); + } + return outputStream; + } + + + /** + * Set the output stream associated with this Response. + * + * @param stream The new output stream + */ + public void setStream(OutputStream stream) { + // This method is evil + } + + + /** + * Set the suspended flag. + * + * @param suspended The new suspended flag value + */ + public void setSuspended(boolean suspended) { + outputBuffer.setSuspended(suspended); + } + + + /** + * Suspended flag accessor. + */ + public boolean isSuspended() { + return outputBuffer.isSuspended(); + } + + + /** + * Set the error flag. + */ + public void setError() { + error = true; + } + + + /** + * Error flag accessor. + */ + public boolean isError() { + return error; + } + + + /** + * Create and return a ServletOutputStream to write the content + * associated with this Response. + * + * @exception IOException if an input/output error occurs + */ + public ServletOutputStream createOutputStream() + throws IOException { + // Probably useless + if (outputStream == null) { + outputStream = new CoyoteOutputStream(outputBuffer); + } + return outputStream; + } + + + /** + * Perform whatever actions are required to flush and close the output + * stream or writer, in a single operation. + * + * @exception IOException if an input/output error occurs + */ + public void finishResponse() + throws IOException { + // Writing leftover bytes + try { + outputBuffer.close(); + } catch(IOException e) { + ; + } catch(Throwable t) { + t.printStackTrace(); + } + } + + + /** + * Return the content length that was set or calculated for this Response. + */ + public int getContentLength() { + return (coyoteResponse.getContentLength()); + } + + + /** + * Return the content type that was set or calculated for this response, + * or null if no content type was set. + */ + public String getContentType() { + return (coyoteResponse.getContentType()); + } + + + /** + * Return a PrintWriter that can be used to render error messages, + * regardless of whether a stream or writer has already been acquired. + * + * @return Writer which can be used for error reports. If the response is + * not an error report returned using sendError or triggered by an + * unexpected exception thrown during the servlet processing + * (and only in that case), null will be returned if the response stream + * has already been used. + * + * @exception IOException if an input/output error occurs + */ + public PrintWriter getReporter() throws IOException { + if (outputBuffer.isNew()) { + outputBuffer.checkConverter(); + if (writer == null) { + writer = new CoyoteWriter(outputBuffer); + } + return writer; + } else { + return null; + } + } + + + // ------------------------------------------------ ServletResponse Methods + + + /** + * Flush the buffer and commit this response. + * + * @exception IOException if an input/output error occurs + */ + public void flushBuffer() + throws IOException { + outputBuffer.flush(); + } + + + /** + * Return the actual buffer size used for this Response. + */ + public int getBufferSize() { + return outputBuffer.getBufferSize(); + } + + + /** + * Return the character encoding used for this Response. + */ + public String getCharacterEncoding() { + return (coyoteResponse.getCharacterEncoding()); + } + + + /** + * Return the servlet output stream associated with this Response. + * + * @exception IllegalStateException if getWriter has + * already been called for this response + * @exception IOException if an input/output error occurs + */ + public ServletOutputStream getOutputStream() + throws IOException { + + if (usingWriter) + throw new IllegalStateException + (sm.getString("coyoteResponse.getOutputStream.ise")); + + usingOutputStream = true; + if (outputStream == null) { + outputStream = new CoyoteOutputStream(outputBuffer); + } + return outputStream; + + } + + + /** + * Return the Locale assigned to this response. + */ + public Locale getLocale() { + return (coyoteResponse.getLocale()); + } + + + /** + * Return the writer associated with this Response. + * + * @exception IllegalStateException if getOutputStream has + * already been called for this response + * @exception IOException if an input/output error occurs + */ + public PrintWriter getWriter() + throws IOException { + + if (usingOutputStream) + throw new IllegalStateException + (sm.getString("coyoteResponse.getWriter.ise")); + + usingWriter = true; + outputBuffer.checkConverter(); + if (writer == null) { + writer = new CoyoteWriter(outputBuffer); + } + return writer; + + } + + + /** + * Has the output of this response already been committed? + */ + public boolean isCommitted() { + return (coyoteResponse.isCommitted()); + } + + + /** + * Clear any content written to the buffer. + * + * @exception IllegalStateException if this response has already + * been committed + */ + public void reset() { + + if (included) + return; // Ignore any call from an included servlet + + coyoteResponse.reset(); + outputBuffer.reset(); + } + + + /** + * Reset the data buffer but not any status or header information. + * + * @exception IllegalStateException if the response has already + * been committed + */ + public void resetBuffer() { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.resetBuffer.ise")); + + outputBuffer.reset(); + + } + + + /** + * Set the buffer size to be used for this Response. + * + * @param size The new buffer size + * + * @exception IllegalStateException if this method is called after + * output has been committed for this response + */ + public void setBufferSize(int size) { + + if (isCommitted() || !outputBuffer.isNew()) + throw new IllegalStateException + (sm.getString("coyoteResponse.setBufferSize.ise")); + + outputBuffer.setBufferSize(size); + + } + + + /** + * Set the content length (in bytes) for this Response. + * + * @param length The new content length + */ + public void setContentLength(int length) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + if (usingWriter) + return; + + coyoteResponse.setContentLength(length); + + } + + + /** + * Set the content type for this Response. + * + * @param type The new content type + */ + public void setContentType(String type) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + // Ignore charset if getWriter() has already been called + if (usingWriter) { + if (type != null) { + int index = type.indexOf(";"); + if (index != -1) { + type = type.substring(0, index); + } + } + } + + coyoteResponse.setContentType(type); + + // Check to see if content type contains charset + if (type != null) { + int index = type.indexOf(";"); + if (index != -1) { + int len = type.length(); + index++; + while (index < len && Character.isSpace(type.charAt(index))) { + index++; + } + if (index+7 < len + && type.charAt(index) == 'c' + && type.charAt(index+1) == 'h' + && type.charAt(index+2) == 'a' + && type.charAt(index+3) == 'r' + && type.charAt(index+4) == 's' + && type.charAt(index+5) == 'e' + && type.charAt(index+6) == 't' + && type.charAt(index+7) == '=') { + isCharacterEncodingSet = true; + } + } + } + } + + + /* + * Overrides the name of the character encoding used in the body + * of the request. This method must be called prior to reading + * request parameters or reading input using getReader(). + * + * @param charset String containing the name of the chararacter encoding. + */ + public void setCharacterEncoding(String charset) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + // Ignore any call made after the getWriter has been invoked + // The default should be used + if (usingWriter) + return; + + coyoteResponse.setCharacterEncoding(charset); + isCharacterEncodingSet = true; + } + + + + /** + * Set the Locale that is appropriate for this response, including + * setting the appropriate character encoding. + * + * @param locale The new locale + */ + public void setLocale(Locale locale) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setLocale(locale); + + // Ignore any call made after the getWriter has been invoked. + // The default should be used + if (usingWriter) + return; + + if (isCharacterEncodingSet) { + return; + } + + CharsetMapper cm = getContext().getCharsetMapper(); + String charset = cm.getCharset( locale ); + if ( charset != null ){ + coyoteResponse.setCharacterEncoding(charset); + } + + } + + + // --------------------------------------------------- HttpResponse Methods + + + /** + * Return an array of all cookies set for this response, or + * a zero-length array if no cookies have been set. + */ + public Cookie[] getCookies() { + return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); + } + + + /** + * Return the value for the specified header, or null if this + * header has not been set. If more than one value was added for this + * name, only the first is returned; use getHeaderValues() to retrieve all + * of them. + * + * @param name Header name to look up + */ + public String getHeader(String name) { + return coyoteResponse.getMimeHeaders().getHeader(name); + } + + + /** + * Return an array of all the header names set for this response, or + * a zero-length array if no headers have been set. + */ + public String[] getHeaderNames() { + + MimeHeaders headers = coyoteResponse.getMimeHeaders(); + int n = headers.size(); + String[] result = new String[n]; + for (int i = 0; i < n; i++) { + result[i] = headers.getName(i).toString(); + } + return result; + + } + + + /** + * Return an array of all the header values associated with the + * specified header name, or an zero-length array if there are no such + * header values. + * + * @param name Header name to look up + */ + public String[] getHeaderValues(String name) { + + Enumeration enumeration = coyoteResponse.getMimeHeaders().values(name); + Vector result = new Vector(); + while (enumeration.hasMoreElements()) { + result.addElement(enumeration.nextElement()); + } + String[] resultArray = new String[result.size()]; + result.copyInto(resultArray); + return resultArray; + + } + + + /** + * Return the error message that was set with sendError() + * for this Response. + */ + public String getMessage() { + return coyoteResponse.getMessage(); + } + + + /** + * Return the HTTP status code associated with this Response. + */ + public int getStatus() { + return coyoteResponse.getStatus(); + } + + + /** + * Reset this response, and specify the values for the HTTP status code + * and corresponding message. + * + * @exception IllegalStateException if this response has already been + * committed + */ + public void reset(int status, String message) { + reset(); + setStatus(status, message); + } + + + // -------------------------------------------- HttpServletResponse Methods + + + /** + * Add the specified Cookie to those that will be included with + * this Response. + * + * @param cookie Cookie to be added + */ + public void addCookie(final Cookie cookie) { + + // Ignore any call from an included servlet + if (included) + return; + + addCookieInternal(cookie); + + } + + + /** + * Add the specified Cookie to those that will be included with + * this Response. + * + * @param cookie Cookie to be added + */ + public void addCookieInternal(final Cookie cookie) { + + if (isCommitted()) + return; + + cookies.add(cookie); + + final StringBuffer sb = new StringBuffer(); + if (SecurityUtil.isPackageProtectionEnabled()) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run(){ + ServerCookie.appendCookieValue + (sb, cookie.getVersion(), cookie.getName(), + cookie.getValue(), cookie.getPath(), + cookie.getDomain(), cookie.getComment(), + cookie.getMaxAge(), cookie.getSecure()); + return null; + } + }); + } else { + ServerCookie.appendCookieValue + (sb, cookie.getVersion(), cookie.getName(), cookie.getValue(), + cookie.getPath(), cookie.getDomain(), cookie.getComment(), + cookie.getMaxAge(), cookie.getSecure()); + } + + // the header name is Set-Cookie for both "old" and v.1 ( RFC2109 ) + // RFC2965 is not supported by browsers and the Servlet spec + // asks for 2109. + addHeader("Set-Cookie", sb.toString()); + + } + + + /** + * Add the specified date header to the specified value. + * + * @param name Name of the header to set + * @param value Date value to be set + */ + public void addDateHeader(String name, long value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) { + return; + } + + if (format == null) { + format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, + Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + addHeader(name, FastHttpDateFormat.formatDate(value, format)); + + } + + + /** + * Add the specified header to the specified value. + * + * @param name Name of the header to set + * @param value Value to be set + */ + public void addHeader(String name, String value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.addHeader(name, value); + + } + + + /** + * Add the specified integer header to the specified value. + * + * @param name Name of the header to set + * @param value Integer value to be set + */ + public void addIntHeader(String name, int value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + addHeader(name, "" + value); + + } + + + /** + * Has the specified header been set already in this response? + * + * @param name Name of the header to check + */ + public boolean containsHeader(String name) { + // Need special handling for Content-Type and Content-Length due to + // special handling of these in coyoteResponse + char cc=name.charAt(0); + if(cc=='C' || cc=='c') { + if(name.equalsIgnoreCase("Content-Type")) { + // Will return null if this has not been set + return (coyoteResponse.getContentType() != null); + } + if(name.equalsIgnoreCase("Content-Length")) { + // -1 means not known and is not sent to client + return (coyoteResponse.getContentLengthLong() != -1); + } + } + + return coyoteResponse.containsHeader(name); + } + + + /** + * Encode the session identifier associated with this response + * into the specified redirect URL, if necessary. + * + * @param url URL to be encoded + */ + public String encodeRedirectURL(String url) { + + if (isEncodeable(toAbsolute(url))) { + return (toEncoded(url, request.getSessionInternal().getIdInternal())); + } else { + return (url); + } + + } + + + /** + * Encode the session identifier associated with this response + * into the specified redirect URL, if necessary. + * + * @param url URL to be encoded + * + * @deprecated As of Version 2.1 of the Java Servlet API, use + * encodeRedirectURL() instead. + */ + public String encodeRedirectUrl(String url) { + return (encodeRedirectURL(url)); + } + + + /** + * Encode the session identifier associated with this response + * into the specified URL, if necessary. + * + * @param url URL to be encoded + */ + public String encodeURL(String url) { + + String absolute = toAbsolute(url); + if (isEncodeable(absolute)) { + // W3c spec clearly said + if (url.equalsIgnoreCase("")){ + url = absolute; + } + return (toEncoded(url, request.getSessionInternal().getIdInternal())); + } else { + return (url); + } + + } + + + /** + * Encode the session identifier associated with this response + * into the specified URL, if necessary. + * + * @param url URL to be encoded + * + * @deprecated As of Version 2.1 of the Java Servlet API, use + * encodeURL() instead. + */ + public String encodeUrl(String url) { + return (encodeURL(url)); + } + + + /** + * Send an acknowledgment of a request. + * + * @exception IOException if an input/output error occurs + */ + public void sendAcknowledgement() + throws IOException { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.acknowledge(); + + } + + + /** + * Send an error response with the specified status and a + * default message. + * + * @param status HTTP status code to send + * + * @exception IllegalStateException if this response has + * already been committed + * @exception IOException if an input/output error occurs + */ + public void sendError(int status) + throws IOException { + sendError(status, null); + } + + + /** + * Send an error response with the specified status and message. + * + * @param status HTTP status code to send + * @param message Corresponding message to send + * + * @exception IllegalStateException if this response has + * already been committed + * @exception IOException if an input/output error occurs + */ + public void sendError(int status, String message) + throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.sendError.ise")); + + // Ignore any call from an included servlet + if (included) + return; + + Wrapper wrapper = getRequest().getWrapper(); + if (wrapper != null) { + wrapper.incrementErrorCount(); + } + + setError(); + + coyoteResponse.setStatus(status); + coyoteResponse.setMessage(message); + + // Clear any data content that has been buffered + resetBuffer(); + + // Cause the response to be finished (from the application perspective) + setSuspended(true); + + } + + + /** + * Send a temporary redirect to the specified redirect location URL. + * + * @param location Location URL to redirect to + * + * @exception IllegalStateException if this response has + * already been committed + * @exception IOException if an input/output error occurs + */ + public void sendRedirect(String location) + throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (sm.getString("coyoteResponse.sendRedirect.ise")); + + // Ignore any call from an included servlet + if (included) + return; + + // Clear any data content that has been buffered + resetBuffer(); + + // Generate a temporary redirect to the specified location + try { + String absolute = toAbsolute(location); + setStatus(SC_FOUND); + setHeader("Location", absolute); + } catch (IllegalArgumentException e) { + setStatus(SC_NOT_FOUND); + } + + // Cause the response to be finished (from the application perspective) + setSuspended(true); + + } + + + /** + * Set the specified date header to the specified value. + * + * @param name Name of the header to set + * @param value Date value to be set + */ + public void setDateHeader(String name, long value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) { + return; + } + + if (format == null) { + format = new SimpleDateFormat(DateTool.HTTP_RESPONSE_DATE_HEADER, + Locale.US); + format.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + setHeader(name, FastHttpDateFormat.formatDate(value, format)); + + } + + + /** + * Set the specified header to the specified value. + * + * @param name Name of the header to set + * @param value Value to be set + */ + public void setHeader(String name, String value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setHeader(name, value); + + } + + + /** + * Set the specified integer header to the specified value. + * + * @param name Name of the header to set + * @param value Integer value to be set + */ + public void setIntHeader(String name, int value) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + setHeader(name, "" + value); + + } + + + /** + * Set the HTTP status to be returned with this response. + * + * @param status The new HTTP status + */ + public void setStatus(int status) { + setStatus(status, null); + } + + + /** + * Set the HTTP status and message to be returned with this response. + * + * @param status The new HTTP status + * @param message The associated text message + * + * @deprecated As of Version 2.1 of the Java Servlet API, this method + * has been deprecated due to the ambiguous meaning of the message + * parameter. + */ + public void setStatus(int status, String message) { + + if (isCommitted()) + return; + + // Ignore any call from an included servlet + if (included) + return; + + coyoteResponse.setStatus(status); + coyoteResponse.setMessage(message); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return true if the specified URL should be encoded with + * a session identifier. This will be true if all of the following + * conditions are met: + *
      + *
    • The request we are responding to asked for a valid session + *
    • The requested session ID was not received via a cookie + *
    • The specified URL points back to somewhere within the web + * application that is responding to this request + *
    + * + * @param location Absolute URL to be validated + */ + protected boolean isEncodeable(final String location) { + + if (location == null) + return (false); + + // Is this an intra-document reference? + if (location.startsWith("#")) + return (false); + + // Are we in a valid session that is not using cookies? + final Request hreq = request; + final Session session = hreq.getSessionInternal(false); + if (session == null) + return (false); + if (hreq.isRequestedSessionIdFromCookie()) + return (false); + + if (SecurityUtil.isPackageProtectionEnabled()) { + return ((Boolean) + AccessController.doPrivileged(new PrivilegedAction() { + + public Object run(){ + return new Boolean(doIsEncodeable(hreq, session, location)); + } + })).booleanValue(); + } else { + return doIsEncodeable(hreq, session, location); + } + } + + private boolean doIsEncodeable(Request hreq, Session session, + String location) { + // Is this a valid absolute URL? + URL url = null; + try { + url = new URL(location); + } catch (MalformedURLException e) { + return (false); + } + + // Does this URL match down to (and including) the context path? + if (!hreq.getScheme().equalsIgnoreCase(url.getProtocol())) + return (false); + if (!hreq.getServerName().equalsIgnoreCase(url.getHost())) + return (false); + int serverPort = hreq.getServerPort(); + if (serverPort == -1) { + if ("https".equals(hreq.getScheme())) + serverPort = 443; + else + serverPort = 80; + } + int urlPort = url.getPort(); + if (urlPort == -1) { + if ("https".equals(url.getProtocol())) + urlPort = 443; + else + urlPort = 80; + } + if (serverPort != urlPort) + return (false); + + String contextPath = getContext().getPath(); + if (contextPath != null) { + String file = url.getFile(); + if ((file == null) || !file.startsWith(contextPath)) + return (false); + if( file.indexOf(";jsessionid=" + session.getIdInternal()) >= 0 ) + return (false); + } + + // This URL belongs to our web application, so it is encodeable + return (true); + + } + + + /** + * Convert (if necessary) and return the absolute URL that represents the + * resource referenced by this possibly relative URL. If this URL is + * already absolute, return it unchanged. + * + * @param location URL to be (possibly) converted and then returned + * + * @exception IllegalArgumentException if a MalformedURLException is + * thrown when converting the relative URL to an absolute one + */ + private String toAbsolute(String location) { + + if (location == null) + return (location); + + boolean leadingSlash = location.startsWith("/"); + + if (leadingSlash || !hasScheme(location)) { + + redirectURLCC.recycle(); + + String scheme = request.getScheme(); + String name = request.getServerName(); + int port = request.getServerPort(); + + try { + redirectURLCC.append(scheme, 0, scheme.length()); + redirectURLCC.append("://", 0, 3); + redirectURLCC.append(name, 0, name.length()); + if ((scheme.equals("http") && port != 80) + || (scheme.equals("https") && port != 443)) { + redirectURLCC.append(':'); + String portS = port + ""; + redirectURLCC.append(portS, 0, portS.length()); + } + if (!leadingSlash) { + String relativePath = request.getDecodedRequestURI(); + int pos = relativePath.lastIndexOf('/'); + relativePath = relativePath.substring(0, pos); + + String encodedURI = null; + final String frelativePath = relativePath; + if (SecurityUtil.isPackageProtectionEnabled() ){ + try{ + encodedURI = (String)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + public Object run() throws IOException{ + return urlEncoder.encodeURL(frelativePath); + } + }); + } catch (PrivilegedActionException pae){ + IllegalArgumentException iae = + new IllegalArgumentException(location); + iae.initCause(pae.getException()); + throw iae; + } + } else { + encodedURI = urlEncoder.encodeURL(relativePath); + } + redirectURLCC.append(encodedURI, 0, encodedURI.length()); + redirectURLCC.append('/'); + } + redirectURLCC.append(location, 0, location.length()); + } catch (IOException e) { + IllegalArgumentException iae = + new IllegalArgumentException(location); + iae.initCause(e); + throw iae; + } + + return redirectURLCC.toString(); + + } else { + + return (location); + + } + + } + + + /** + * Determine if a URI string has a scheme component. + */ + private boolean hasScheme(String uri) { + int len = uri.length(); + for(int i=0; i < len ; i++) { + char c = uri.charAt(i); + if(c == ':') { + return i > 0; + } else if(!URL.isSchemeChar(c)) { + return false; + } + } + return false; + } + + /** + * Return the specified URL with the specified session identifier + * suitably encoded. + * + * @param url URL to be encoded with the session id + * @param sessionId Session id to be included in the encoded URL + */ + protected String toEncoded(String url, String sessionId) { + + if ((url == null) || (sessionId == null)) + return (url); + + String path = url; + String query = ""; + String anchor = ""; + int question = url.indexOf('?'); + if (question >= 0) { + path = url.substring(0, question); + query = url.substring(question); + } + int pound = path.indexOf('#'); + if (pound >= 0) { + anchor = path.substring(pound); + path = path.substring(0, pound); + } + StringBuffer sb = new StringBuffer(path); + if( sb.length() > 0 ) { // jsessionid can't be first. + sb.append(";jsessionid="); + sb.append(sessionId); + } + sb.append(anchor); + sb.append(query); + return (sb.toString()); + + } + + +} + diff --git a/java/org/apache/catalina/connector/ResponseFacade.java b/java/org/apache/catalina/connector/ResponseFacade.java index 5a8fc48a1..71bf2fc1e 100644 --- a/java/org/apache/catalina/connector/ResponseFacade.java +++ b/java/org/apache/catalina/connector/ResponseFacade.java @@ -1,553 +1,553 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.connector; - -import java.io.IOException; -import java.io.PrintWriter; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.util.StringManager; -import org.apache.catalina.security.SecurityUtil; - -/** - * Facade class that wraps a Coyote response object. - * All methods are delegated to the wrapped response. - * - * @author Remy Maucherat - * @author Jean-Francois Arcand - * @version $Revision: 303900 $ $Date: 2005-04-30 00:22:29 +0200 (sam., 30 avr. 2005) $ - */ -@SuppressWarnings("deprecation") -public class ResponseFacade - implements HttpServletResponse { - - - // ----------------------------------------------------------- DoPrivileged - - private final class SetContentTypePrivilegedAction - implements PrivilegedAction { - - private String contentType; - - public SetContentTypePrivilegedAction(String contentType){ - this.contentType = contentType; - } - - public Object run() { - response.setContentType(contentType); - return null; - } - } - - private final class DateHeaderPrivilegedAction - implements PrivilegedAction { - - private String name; - private long value; - private boolean add; - - DateHeaderPrivilegedAction(String name, long value, boolean add) { - this.name = name; - this.value = value; - this.add = add; - } - - public Object run() { - if(add) { - response.addDateHeader(name, value); - } else { - response.setDateHeader(name, value); - } - return null; - } - } - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a wrapper for the specified response. - * - * @param response The response to be wrapped - */ - public ResponseFacade(Response response) { - - this.response = response; - } - - - // ----------------------------------------------- Class/Instance Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The wrapped response. - */ - protected Response response = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Clear facade. - */ - public void clear() { - response = null; - } - - - /** - * Prevent cloning the facade. - */ - protected Object clone() - throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - - public void finish() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - response.setSuspended(true); - } - - - public boolean isFinished() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.isSuspended(); - } - - - // ------------------------------------------------ ServletResponse Methods - - - public String getCharacterEncoding() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.getCharacterEncoding(); - } - - - public ServletOutputStream getOutputStream() - throws IOException { - - // if (isFinished()) - // throw new IllegalStateException - // (/*sm.getString("responseFacade.finished")*/); - - ServletOutputStream sos = response.getOutputStream(); - if (isFinished()) - response.setSuspended(true); - return (sos); - - } - - - public PrintWriter getWriter() - throws IOException { - - // if (isFinished()) - // throw new IllegalStateException - // (/*sm.getString("responseFacade.finished")*/); - - PrintWriter writer = response.getWriter(); - if (isFinished()) - response.setSuspended(true); - return (writer); - - } - - - public void setContentLength(int len) { - - if (isCommitted()) - return; - - response.setContentLength(len); - - } - - - public void setContentType(String type) { - - if (isCommitted()) - return; - - if (SecurityUtil.isPackageProtectionEnabled()){ - AccessController.doPrivileged(new SetContentTypePrivilegedAction(type)); - } else { - response.setContentType(type); - } - } - - - public void setBufferSize(int size) { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.setBufferSize(size); - - } - - - public int getBufferSize() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.getBufferSize(); - } - - - public void flushBuffer() - throws IOException { - - if (isFinished()) - // throw new IllegalStateException - // (/*sm.getString("responseFacade.finished")*/); - return; - - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged(new PrivilegedExceptionAction(){ - - public Object run() throws IOException{ - response.setAppCommitted(true); - - response.flushBuffer(); - return null; - } - }); - } catch(PrivilegedActionException e){ - Exception ex = e.getException(); - if (ex instanceof IOException){ - throw (IOException)ex; - } - } - } else { - response.setAppCommitted(true); - - response.flushBuffer(); - } - - } - - - public void resetBuffer() { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.resetBuffer(); - - } - - - public boolean isCommitted() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return (response.isAppCommitted()); - } - - - public void reset() { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.reset(); - - } - - - public void setLocale(Locale loc) { - - if (isCommitted()) - return; - - response.setLocale(loc); - } - - - public Locale getLocale() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.getLocale(); - } - - - public void addCookie(Cookie cookie) { - - if (isCommitted()) - return; - - response.addCookie(cookie); - - } - - - public boolean containsHeader(String name) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.containsHeader(name); - } - - - public String encodeURL(String url) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.encodeURL(url); - } - - - public String encodeRedirectURL(String url) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.encodeRedirectURL(url); - } - - - public String encodeUrl(String url) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.encodeURL(url); - } - - - public String encodeRedirectUrl(String url) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.encodeRedirectURL(url); - } - - - public void sendError(int sc, String msg) - throws IOException { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.setAppCommitted(true); - - response.sendError(sc, msg); - - } - - - public void sendError(int sc) - throws IOException { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.setAppCommitted(true); - - response.sendError(sc); - - } - - - public void sendRedirect(String location) - throws IOException { - - if (isCommitted()) - throw new IllegalStateException - (/*sm.getString("responseBase.reset.ise")*/); - - response.setAppCommitted(true); - - response.sendRedirect(location); - - } - - - public void setDateHeader(String name, long date) { - - if (isCommitted()) - return; - - if(System.getSecurityManager() != null) { - AccessController.doPrivileged(new DateHeaderPrivilegedAction - (name, date, false)); - } else { - response.setDateHeader(name, date); - } - - } - - - public void addDateHeader(String name, long date) { - - if (isCommitted()) - return; - - if(System.getSecurityManager() != null) { - AccessController.doPrivileged(new DateHeaderPrivilegedAction - (name, date, true)); - } else { - response.addDateHeader(name, date); - } - - } - - - public void setHeader(String name, String value) { - - if (isCommitted()) - return; - - response.setHeader(name, value); - - } - - - public void addHeader(String name, String value) { - - if (isCommitted()) - return; - - response.addHeader(name, value); - - } - - - public void setIntHeader(String name, int value) { - - if (isCommitted()) - return; - - response.setIntHeader(name, value); - - } - - - public void addIntHeader(String name, int value) { - - if (isCommitted()) - return; - - response.addIntHeader(name, value); - - } - - - public void setStatus(int sc) { - - if (isCommitted()) - return; - - response.setStatus(sc); - - } - - - public void setStatus(int sc, String sm) { - - if (isCommitted()) - return; - - response.setStatus(sc, sm); - } - - - public String getContentType() { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - return response.getContentType(); - } - - - public void setCharacterEncoding(String arg0) { - - if (response == null) { - throw new IllegalStateException( - sm.getString("responseFacade.nullResponse")); - } - - response.setCharacterEncoding(arg0); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.connector; + +import java.io.IOException; +import java.io.PrintWriter; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Locale; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.util.StringManager; +import org.apache.catalina.security.SecurityUtil; + +/** + * Facade class that wraps a Coyote response object. + * All methods are delegated to the wrapped response. + * + * @author Remy Maucherat + * @author Jean-Francois Arcand + * @version $Revision: 303900 $ $Date: 2005-04-30 00:22:29 +0200 (sam., 30 avr. 2005) $ + */ +@SuppressWarnings("deprecation") +public class ResponseFacade + implements HttpServletResponse { + + + // ----------------------------------------------------------- DoPrivileged + + private final class SetContentTypePrivilegedAction + implements PrivilegedAction { + + private String contentType; + + public SetContentTypePrivilegedAction(String contentType){ + this.contentType = contentType; + } + + public Object run() { + response.setContentType(contentType); + return null; + } + } + + private final class DateHeaderPrivilegedAction + implements PrivilegedAction { + + private String name; + private long value; + private boolean add; + + DateHeaderPrivilegedAction(String name, long value, boolean add) { + this.name = name; + this.value = value; + this.add = add; + } + + public Object run() { + if(add) { + response.addDateHeader(name, value); + } else { + response.setDateHeader(name, value); + } + return null; + } + } + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a wrapper for the specified response. + * + * @param response The response to be wrapped + */ + public ResponseFacade(Response response) { + + this.response = response; + } + + + // ----------------------------------------------- Class/Instance Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The wrapped response. + */ + protected Response response = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Clear facade. + */ + public void clear() { + response = null; + } + + + /** + * Prevent cloning the facade. + */ + protected Object clone() + throws CloneNotSupportedException { + throw new CloneNotSupportedException(); + } + + + public void finish() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + response.setSuspended(true); + } + + + public boolean isFinished() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.isSuspended(); + } + + + // ------------------------------------------------ ServletResponse Methods + + + public String getCharacterEncoding() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.getCharacterEncoding(); + } + + + public ServletOutputStream getOutputStream() + throws IOException { + + // if (isFinished()) + // throw new IllegalStateException + // (/*sm.getString("responseFacade.finished")*/); + + ServletOutputStream sos = response.getOutputStream(); + if (isFinished()) + response.setSuspended(true); + return (sos); + + } + + + public PrintWriter getWriter() + throws IOException { + + // if (isFinished()) + // throw new IllegalStateException + // (/*sm.getString("responseFacade.finished")*/); + + PrintWriter writer = response.getWriter(); + if (isFinished()) + response.setSuspended(true); + return (writer); + + } + + + public void setContentLength(int len) { + + if (isCommitted()) + return; + + response.setContentLength(len); + + } + + + public void setContentType(String type) { + + if (isCommitted()) + return; + + if (SecurityUtil.isPackageProtectionEnabled()){ + AccessController.doPrivileged(new SetContentTypePrivilegedAction(type)); + } else { + response.setContentType(type); + } + } + + + public void setBufferSize(int size) { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.setBufferSize(size); + + } + + + public int getBufferSize() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.getBufferSize(); + } + + + public void flushBuffer() + throws IOException { + + if (isFinished()) + // throw new IllegalStateException + // (/*sm.getString("responseFacade.finished")*/); + return; + + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged(new PrivilegedExceptionAction(){ + + public Object run() throws IOException{ + response.setAppCommitted(true); + + response.flushBuffer(); + return null; + } + }); + } catch(PrivilegedActionException e){ + Exception ex = e.getException(); + if (ex instanceof IOException){ + throw (IOException)ex; + } + } + } else { + response.setAppCommitted(true); + + response.flushBuffer(); + } + + } + + + public void resetBuffer() { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.resetBuffer(); + + } + + + public boolean isCommitted() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return (response.isAppCommitted()); + } + + + public void reset() { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.reset(); + + } + + + public void setLocale(Locale loc) { + + if (isCommitted()) + return; + + response.setLocale(loc); + } + + + public Locale getLocale() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.getLocale(); + } + + + public void addCookie(Cookie cookie) { + + if (isCommitted()) + return; + + response.addCookie(cookie); + + } + + + public boolean containsHeader(String name) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.containsHeader(name); + } + + + public String encodeURL(String url) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.encodeURL(url); + } + + + public String encodeRedirectURL(String url) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.encodeRedirectURL(url); + } + + + public String encodeUrl(String url) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.encodeURL(url); + } + + + public String encodeRedirectUrl(String url) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.encodeRedirectURL(url); + } + + + public void sendError(int sc, String msg) + throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.setAppCommitted(true); + + response.sendError(sc, msg); + + } + + + public void sendError(int sc) + throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.setAppCommitted(true); + + response.sendError(sc); + + } + + + public void sendRedirect(String location) + throws IOException { + + if (isCommitted()) + throw new IllegalStateException + (/*sm.getString("responseBase.reset.ise")*/); + + response.setAppCommitted(true); + + response.sendRedirect(location); + + } + + + public void setDateHeader(String name, long date) { + + if (isCommitted()) + return; + + if(System.getSecurityManager() != null) { + AccessController.doPrivileged(new DateHeaderPrivilegedAction + (name, date, false)); + } else { + response.setDateHeader(name, date); + } + + } + + + public void addDateHeader(String name, long date) { + + if (isCommitted()) + return; + + if(System.getSecurityManager() != null) { + AccessController.doPrivileged(new DateHeaderPrivilegedAction + (name, date, true)); + } else { + response.addDateHeader(name, date); + } + + } + + + public void setHeader(String name, String value) { + + if (isCommitted()) + return; + + response.setHeader(name, value); + + } + + + public void addHeader(String name, String value) { + + if (isCommitted()) + return; + + response.addHeader(name, value); + + } + + + public void setIntHeader(String name, int value) { + + if (isCommitted()) + return; + + response.setIntHeader(name, value); + + } + + + public void addIntHeader(String name, int value) { + + if (isCommitted()) + return; + + response.addIntHeader(name, value); + + } + + + public void setStatus(int sc) { + + if (isCommitted()) + return; + + response.setStatus(sc); + + } + + + public void setStatus(int sc, String sm) { + + if (isCommitted()) + return; + + response.setStatus(sc, sm); + } + + + public String getContentType() { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + return response.getContentType(); + } + + + public void setCharacterEncoding(String arg0) { + + if (response == null) { + throw new IllegalStateException( + sm.getString("responseFacade.nullResponse")); + } + + response.setCharacterEncoding(arg0); + } + +} diff --git a/java/org/apache/catalina/connector/mbeans-descriptors.xml b/java/org/apache/catalina/connector/mbeans-descriptors.xml index 527b4235f..5651d53c2 100644 --- a/java/org/apache/catalina/connector/mbeans-descriptors.xml +++ b/java/org/apache/catalina/connector/mbeans-descriptors.xml @@ -1,198 +1,198 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/core/ApplicationContext.java b/java/org/apache/catalina/core/ApplicationContext.java index fd3a2a384..8d2d7fdb4 100644 --- a/java/org/apache/catalina/core/ApplicationContext.java +++ b/java/org/apache/catalina/core/ApplicationContext.java @@ -1,974 +1,974 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.File; -import java.io.InputStream; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Set; - -import javax.naming.Binding; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextAttributeEvent; -import javax.servlet.ServletContextAttributeListener; - -import org.apache.catalina.Context; -import org.apache.catalina.Host; -import org.apache.catalina.Wrapper; -import org.apache.catalina.deploy.ApplicationParameter; -import org.apache.catalina.util.Enumerator; -import org.apache.catalina.util.ResourceSet; -import org.apache.catalina.util.ServerInfo; -import org.apache.catalina.util.StringManager; -import org.apache.naming.resources.DirContextURLStreamHandler; -import org.apache.naming.resources.Resource; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.mapper.MappingData; - - -/** - * Standard implementation of ServletContext that represents - * a web application's execution environment. An instance of this class is - * associated with each instance of StandardContext. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 377994 $ $Date: 2006-02-15 13:37:28 +0100 (mer., 15 févr. 2006) $ - */ - -public class ApplicationContext - implements ServletContext { - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class, associated with the specified - * Context instance. - * - * @param context The associated Context instance - */ - public ApplicationContext(String basePath, StandardContext context) { - super(); - this.context = context; - this.basePath = basePath; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The context attributes for this context. - */ - private HashMap attributes = new HashMap(); - - - /** - * List of read only attributes for this context. - */ - private HashMap readOnlyAttributes = new HashMap(); - - - /** - * The Context instance with which we are associated. - */ - private StandardContext context = null; - - - /** - * Empty collection to serve as the basis for empty enumerations. - * DO NOT ADD ANY ELEMENTS TO THIS COLLECTION! - */ - private static final ArrayList empty = new ArrayList(); - - - /** - * The facade around this object. - */ - private ServletContext facade = new ApplicationContextFacade(this); - - - /** - * The merged context initialization parameters for this Context. - */ - private HashMap parameters = null; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Base path. - */ - private String basePath = null; - - - /** - * Thread local mapping data. - */ - private ThreadLocal localMappingData = new ThreadLocal(); - - - /** - * Thread local URI message bytes. - */ - private ThreadLocal localUriMB = new ThreadLocal(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the resources object that is mapped to a specified path. - * The path must begin with a "/" and is interpreted as relative to the - * current context root. - */ - public DirContext getResources() { - - return context.getResources(); - - } - - - // ------------------------------------------------- ServletContext Methods - - - /** - * Return the value of the specified context attribute, if any; - * otherwise return null. - * - * @param name Name of the context attribute to return - */ - public Object getAttribute(String name) { - - synchronized (attributes) { - return (attributes.get(name)); - } - - } - - - /** - * Return an enumeration of the names of the context attributes - * associated with this context. - */ - public Enumeration getAttributeNames() { - - synchronized (attributes) { - return new Enumerator(attributes.keySet(), true); - } - - } - - - /** - * Return a ServletContext object that corresponds to a - * specified URI on the server. This method allows servlets to gain - * access to the context for various parts of the server, and as needed - * obtain RequestDispatcher objects or resources from the - * context. The given path must be absolute (beginning with a "/"), - * and is interpreted based on our virtual host's document root. - * - * @param uri Absolute URI of a resource on the server - */ - public ServletContext getContext(String uri) { - - // Validate the format of the specified argument - if ((uri == null) || (!uri.startsWith("/"))) - return (null); - - Context child = null; - try { - Host host = (Host) context.getParent(); - String mapuri = uri; - while (true) { - child = (Context) host.findChild(mapuri); - if (child != null) - break; - int slash = mapuri.lastIndexOf('/'); - if (slash < 0) - break; - mapuri = mapuri.substring(0, slash); - } - } catch (Throwable t) { - return (null); - } - - if (child == null) - return (null); - - if (context.getCrossContext()) { - // If crossContext is enabled, can always return the context - return child.getServletContext(); - } else if (child == context) { - // Can still return the current context - return context.getServletContext(); - } else { - // Nothing to return - return (null); - } - } - - - /** - * Return the main path associated with this context. - */ - public String getContextPath() { - return context.getPath(); - } - - - /** - * Return the value of the specified initialization parameter, or - * null if this parameter does not exist. - * - * @param name Name of the initialization parameter to retrieve - */ - public String getInitParameter(final String name) { - - mergeParameters(); - synchronized (parameters) { - return ((String) parameters.get(name)); - } - } - - - /** - * Return the names of the context's initialization parameters, or an - * empty enumeration if the context has no initialization parameters. - */ - public Enumeration getInitParameterNames() { - - mergeParameters(); - synchronized (parameters) { - return (new Enumerator(parameters.keySet())); - } - - } - - - /** - * Return the major version of the Java Servlet API that we implement. - */ - public int getMajorVersion() { - - return (Constants.MAJOR_VERSION); - - } - - - /** - * Return the minor version of the Java Servlet API that we implement. - */ - public int getMinorVersion() { - - return (Constants.MINOR_VERSION); - - } - - - /** - * Return the MIME type of the specified file, or null if - * the MIME type cannot be determined. - * - * @param file Filename for which to identify a MIME type - */ - public String getMimeType(String file) { - - if (file == null) - return (null); - int period = file.lastIndexOf("."); - if (period < 0) - return (null); - String extension = file.substring(period + 1); - if (extension.length() < 1) - return (null); - return (context.findMimeMapping(extension)); - - } - - - /** - * Return a RequestDispatcher object that acts as a - * wrapper for the named servlet. - * - * @param name Name of the servlet for which a dispatcher is requested - */ - public RequestDispatcher getNamedDispatcher(String name) { - - // Validate the name argument - if (name == null) - return (null); - - // Create and return a corresponding request dispatcher - Wrapper wrapper = (Wrapper) context.findChild(name); - if (wrapper == null) - return (null); - - return new ApplicationDispatcher(wrapper, null, null, null, null, name); - - } - - - /** - * Return the real path for a given virtual path, if possible; otherwise - * return null. - * - * @param path The path to the desired resource - */ - public String getRealPath(String path) { - - if (!context.isFilesystemBased()) - return null; - - if (path == null) { - return null; - } - - File file = new File(basePath, path); - return (file.getAbsolutePath()); - - } - - - /** - * Return a RequestDispatcher instance that acts as a - * wrapper for the resource at the given path. The path must begin - * with a "/" and is interpreted as relative to the current context root. - * - * @param path The path to the desired resource. - */ - public RequestDispatcher getRequestDispatcher(String path) { - - // Validate the path argument - if (path == null) - return (null); - if (!path.startsWith("/")) - throw new IllegalArgumentException - (sm.getString - ("applicationContext.requestDispatcher.iae", path)); - path = normalize(path); - if (path == null) - return (null); - - // Retrieve the thread local URI - MessageBytes uriMB = (MessageBytes) localUriMB.get(); - if (uriMB == null) { - uriMB = MessageBytes.newInstance(); - CharChunk uriCC = uriMB.getCharChunk(); - uriCC.setLimit(-1); - localUriMB.set(uriMB); - } else { - uriMB.recycle(); - } - - // Get query string - String queryString = null; - int pos = path.indexOf('?'); - if (pos >= 0) { - queryString = path.substring(pos + 1); - } else { - pos = path.length(); - } - - // Retrieve the thread local mapping data - MappingData mappingData = (MappingData) localMappingData.get(); - if (mappingData == null) { - mappingData = new MappingData(); - localMappingData.set(mappingData); - } - - // Map the URI - CharChunk uriCC = uriMB.getCharChunk(); - try { - uriCC.append(context.getPath(), 0, context.getPath().length()); - /* - * Ignore any trailing path params (separated by ';') for mapping - * purposes - */ - int semicolon = path.indexOf(';'); - if (pos >= 0 && semicolon > pos) { - semicolon = -1; - } - uriCC.append(path, 0, semicolon > 0 ? semicolon : pos); - context.getMapper().map(uriMB, mappingData); - if (mappingData.wrapper == null) { - return (null); - } - /* - * Append any trailing path params (separated by ';') that were - * ignored for mapping purposes, so that they're reflected in the - * RequestDispatcher's requestURI - */ - if (semicolon > 0) { - uriCC.append(path, semicolon, pos - semicolon); - } - } catch (Exception e) { - // Should never happen - log(sm.getString("applicationContext.mapping.error"), e); - return (null); - } - - Wrapper wrapper = (Wrapper) mappingData.wrapper; - String wrapperPath = mappingData.wrapperPath.toString(); - String pathInfo = mappingData.pathInfo.toString(); - - mappingData.recycle(); - - // Construct a RequestDispatcher to process this request - return new ApplicationDispatcher - (wrapper, uriCC.toString(), wrapperPath, pathInfo, - queryString, null); - - } - - - - /** - * Return the URL to the resource that is mapped to a specified path. - * The path must begin with a "/" and is interpreted as relative to the - * current context root. - * - * @param path The path to the desired resource - * - * @exception MalformedURLException if the path is not given - * in the correct form - */ - public URL getResource(String path) - throws MalformedURLException { - - if (path == null || !path.startsWith("/")) { - throw new MalformedURLException(sm.getString("applicationContext.requestDispatcher.iae", path)); - } - - path = normalize(path); - if (path == null) - return (null); - - String libPath = "/WEB-INF/lib/"; - if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) { - File jarFile = null; - if (context.isFilesystemBased()) { - jarFile = new File(basePath, path); - } else { - jarFile = new File(context.getWorkPath(), path); - } - if (jarFile.exists()) { - return jarFile.toURL(); - } else { - return null; - } - } else { - - DirContext resources = context.getResources(); - if (resources != null) { - String fullPath = context.getName() + path; - String hostName = context.getParent().getName(); - try { - resources.lookup(path); - return new URL - ("jndi", "", 0, getJNDIUri(hostName, fullPath), - new DirContextURLStreamHandler(resources)); - } catch (Exception e) { - // Ignore - } - } - } - - return (null); - - } - - - /** - * Return the requested resource as an InputStream. The - * path must be specified according to the rules described under - * getResource. If no such resource can be identified, - * return null. - * - * @param path The path to the desired resource. - */ - public InputStream getResourceAsStream(String path) { - - path = normalize(path); - if (path == null) - return (null); - - DirContext resources = context.getResources(); - if (resources != null) { - try { - Object resource = resources.lookup(path); - if (resource instanceof Resource) - return (((Resource) resource).streamContent()); - } catch (Exception e) { - } - } - return (null); - - } - - - /** - * Return a Set containing the resource paths of resources member of the - * specified collection. Each path will be a String starting with - * a "/" character. The returned set is immutable. - * - * @param path Collection path - */ - public Set getResourcePaths(String path) { - - // Validate the path argument - if (path == null) { - return null; - } - if (!path.startsWith("/")) { - throw new IllegalArgumentException - (sm.getString("applicationContext.resourcePaths.iae", path)); - } - - path = normalize(path); - if (path == null) - return (null); - - DirContext resources = context.getResources(); - if (resources != null) { - return (getResourcePathsInternal(resources, path)); - } - return (null); - - } - - - /** - * Internal implementation of getResourcesPath() logic. - * - * @param resources Directory context to search - * @param path Collection path - */ - private Set getResourcePathsInternal(DirContext resources, String path) { - - ResourceSet set = new ResourceSet(); - try { - listCollectionPaths(set, resources, path); - } catch (NamingException e) { - return (null); - } - set.setLocked(true); - return (set); - - } - - - /** - * Return the name and version of the servlet container. - */ - public String getServerInfo() { - - return (ServerInfo.getServerInfo()); - - } - - - /** - * @deprecated As of Java Servlet API 2.1, with no direct replacement. - */ - public Servlet getServlet(String name) { - - return (null); - - } - - - /** - * Return the display name of this web application. - */ - public String getServletContextName() { - - return (context.getDisplayName()); - - } - - - /** - * @deprecated As of Java Servlet API 2.1, with no direct replacement. - */ - public Enumeration getServletNames() { - return (new Enumerator(empty)); - } - - - /** - * @deprecated As of Java Servlet API 2.1, with no direct replacement. - */ - public Enumeration getServlets() { - return (new Enumerator(empty)); - } - - - /** - * Writes the specified message to a servlet log file. - * - * @param message Message to be written - */ - public void log(String message) { - - context.getLogger().info(message); - - } - - - /** - * Writes the specified exception and message to a servlet log file. - * - * @param exception Exception to be reported - * @param message Message to be written - * - * @deprecated As of Java Servlet API 2.1, use - * log(String, Throwable) instead - */ - public void log(Exception exception, String message) { - - context.getLogger().error(message, exception); - - } - - - /** - * Writes the specified message and exception to a servlet log file. - * - * @param message Message to be written - * @param throwable Exception to be reported - */ - public void log(String message, Throwable throwable) { - - context.getLogger().error(message, throwable); - - } - - - /** - * Remove the context attribute with the specified name, if any. - * - * @param name Name of the context attribute to be removed - */ - public void removeAttribute(String name) { - - Object value = null; - boolean found = false; - - // Remove the specified attribute - synchronized (attributes) { - // Check for read only attribute - if (readOnlyAttributes.containsKey(name)) - return; - found = attributes.containsKey(name); - if (found) { - value = attributes.get(name); - attributes.remove(name); - } else { - return; - } - } - - // Notify interested application event listeners - Object listeners[] = context.getApplicationEventListeners(); - if ((listeners == null) || (listeners.length == 0)) - return; - ServletContextAttributeEvent event = - new ServletContextAttributeEvent(context.getServletContext(), - name, value); - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof ServletContextAttributeListener)) - continue; - ServletContextAttributeListener listener = - (ServletContextAttributeListener) listeners[i]; - try { - context.fireContainerEvent("beforeContextAttributeRemoved", - listener); - listener.attributeRemoved(event); - context.fireContainerEvent("afterContextAttributeRemoved", - listener); - } catch (Throwable t) { - context.fireContainerEvent("afterContextAttributeRemoved", - listener); - // FIXME - should we do anything besides log these? - log(sm.getString("applicationContext.attributeEvent"), t); - } - } - - } - - - /** - * Bind the specified value with the specified context attribute name, - * replacing any existing value for that name. - * - * @param name Attribute name to be bound - * @param value New attribute value to be bound - */ - public void setAttribute(String name, Object value) { - - // Name cannot be null - if (name == null) - throw new IllegalArgumentException - (sm.getString("applicationContext.setAttribute.namenull")); - - // Null value is the same as removeAttribute() - if (value == null) { - removeAttribute(name); - return; - } - - Object oldValue = null; - boolean replaced = false; - - // Add or replace the specified attribute - synchronized (attributes) { - // Check for read only attribute - if (readOnlyAttributes.containsKey(name)) - return; - oldValue = attributes.get(name); - if (oldValue != null) - replaced = true; - attributes.put(name, value); - } - - // Notify interested application event listeners - Object listeners[] = context.getApplicationEventListeners(); - if ((listeners == null) || (listeners.length == 0)) - return; - ServletContextAttributeEvent event = null; - if (replaced) - event = - new ServletContextAttributeEvent(context.getServletContext(), - name, oldValue); - else - event = - new ServletContextAttributeEvent(context.getServletContext(), - name, value); - - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof ServletContextAttributeListener)) - continue; - ServletContextAttributeListener listener = - (ServletContextAttributeListener) listeners[i]; - try { - if (replaced) { - context.fireContainerEvent - ("beforeContextAttributeReplaced", listener); - listener.attributeReplaced(event); - context.fireContainerEvent("afterContextAttributeReplaced", - listener); - } else { - context.fireContainerEvent("beforeContextAttributeAdded", - listener); - listener.attributeAdded(event); - context.fireContainerEvent("afterContextAttributeAdded", - listener); - } - } catch (Throwable t) { - if (replaced) - context.fireContainerEvent("afterContextAttributeReplaced", - listener); - else - context.fireContainerEvent("afterContextAttributeAdded", - listener); - // FIXME - should we do anything besides log these? - log(sm.getString("applicationContext.attributeEvent"), t); - } - } - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Clear all application-created attributes. - */ - void clearAttributes() { - - // Create list of attributes to be removed - ArrayList list = new ArrayList(); - synchronized (attributes) { - Iterator iter = attributes.keySet().iterator(); - while (iter.hasNext()) { - list.add(iter.next()); - } - } - - // Remove application originated attributes - // (read only attributes will be left in place) - Iterator keys = list.iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - removeAttribute(key); - } - - } - - - /** - * Return the facade associated with this ApplicationContext. - */ - protected ServletContext getFacade() { - - return (this.facade); - - } - - - /** - * Set an attribute as read only. - */ - void setAttributeReadOnly(String name) { - - synchronized (attributes) { - if (attributes.containsKey(name)) - readOnlyAttributes.put(name, name); - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Return a context-relative path, beginning with a "/", that represents - * the canonical version of the specified path after ".." and "." elements - * are resolved out. If the specified path attempts to go outside the - * boundaries of the current context (i.e. too many ".." path elements - * are present), return null instead. - * - * @param path Path to be normalized - */ - private String normalize(String path) { - - if (path == null) { - return null; - } - - String normalized = path; - - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - return (null); // Trying to go outside our context - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Return the normalized path that we have completed - return (normalized); - - } - - - /** - * Merge the context initialization parameters specified in the application - * deployment descriptor with the application parameters described in the - * server configuration, respecting the override property of - * the application parameters appropriately. - */ - private void mergeParameters() { - - if (parameters != null) - return; - HashMap results = new HashMap(); - String names[] = context.findParameters(); - for (int i = 0; i < names.length; i++) - results.put(names[i], context.findParameter(names[i])); - ApplicationParameter params[] = - context.findApplicationParameters(); - for (int i = 0; i < params.length; i++) { - if (params[i].getOverride()) { - if (results.get(params[i].getName()) == null) - results.put(params[i].getName(), params[i].getValue()); - } else { - results.put(params[i].getName(), params[i].getValue()); - } - } - parameters = results; - - } - - - /** - * List resource paths (recursively), and store all of them in the given - * Set. - */ - private static void listCollectionPaths - (Set set, DirContext resources, String path) - throws NamingException { - - Enumeration childPaths = resources.listBindings(path); - while (childPaths.hasMoreElements()) { - Binding binding = (Binding) childPaths.nextElement(); - String name = binding.getName(); - StringBuffer childPath = new StringBuffer(path); - if (!"/".equals(path) && !path.endsWith("/")) - childPath.append("/"); - childPath.append(name); - Object object = binding.getObject(); - if (object instanceof DirContext) { - childPath.append("/"); - } - set.add(childPath.toString()); - } - - } - - - /** - * Get full path, based on the host name and the context path. - */ - private static String getJNDIUri(String hostName, String path) { - if (!path.startsWith("/")) - return "/" + hostName + "/" + path; - else - return "/" + hostName + path; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.File; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Set; + +import javax.naming.Binding; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextAttributeEvent; +import javax.servlet.ServletContextAttributeListener; + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.Wrapper; +import org.apache.catalina.deploy.ApplicationParameter; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.ResourceSet; +import org.apache.catalina.util.ServerInfo; +import org.apache.catalina.util.StringManager; +import org.apache.naming.resources.DirContextURLStreamHandler; +import org.apache.naming.resources.Resource; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.mapper.MappingData; + + +/** + * Standard implementation of ServletContext that represents + * a web application's execution environment. An instance of this class is + * associated with each instance of StandardContext. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 377994 $ $Date: 2006-02-15 13:37:28 +0100 (mer., 15 févr. 2006) $ + */ + +public class ApplicationContext + implements ServletContext { + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class, associated with the specified + * Context instance. + * + * @param context The associated Context instance + */ + public ApplicationContext(String basePath, StandardContext context) { + super(); + this.context = context; + this.basePath = basePath; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The context attributes for this context. + */ + private HashMap attributes = new HashMap(); + + + /** + * List of read only attributes for this context. + */ + private HashMap readOnlyAttributes = new HashMap(); + + + /** + * The Context instance with which we are associated. + */ + private StandardContext context = null; + + + /** + * Empty collection to serve as the basis for empty enumerations. + * DO NOT ADD ANY ELEMENTS TO THIS COLLECTION! + */ + private static final ArrayList empty = new ArrayList(); + + + /** + * The facade around this object. + */ + private ServletContext facade = new ApplicationContextFacade(this); + + + /** + * The merged context initialization parameters for this Context. + */ + private HashMap parameters = null; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Base path. + */ + private String basePath = null; + + + /** + * Thread local mapping data. + */ + private ThreadLocal localMappingData = new ThreadLocal(); + + + /** + * Thread local URI message bytes. + */ + private ThreadLocal localUriMB = new ThreadLocal(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the resources object that is mapped to a specified path. + * The path must begin with a "/" and is interpreted as relative to the + * current context root. + */ + public DirContext getResources() { + + return context.getResources(); + + } + + + // ------------------------------------------------- ServletContext Methods + + + /** + * Return the value of the specified context attribute, if any; + * otherwise return null. + * + * @param name Name of the context attribute to return + */ + public Object getAttribute(String name) { + + synchronized (attributes) { + return (attributes.get(name)); + } + + } + + + /** + * Return an enumeration of the names of the context attributes + * associated with this context. + */ + public Enumeration getAttributeNames() { + + synchronized (attributes) { + return new Enumerator(attributes.keySet(), true); + } + + } + + + /** + * Return a ServletContext object that corresponds to a + * specified URI on the server. This method allows servlets to gain + * access to the context for various parts of the server, and as needed + * obtain RequestDispatcher objects or resources from the + * context. The given path must be absolute (beginning with a "/"), + * and is interpreted based on our virtual host's document root. + * + * @param uri Absolute URI of a resource on the server + */ + public ServletContext getContext(String uri) { + + // Validate the format of the specified argument + if ((uri == null) || (!uri.startsWith("/"))) + return (null); + + Context child = null; + try { + Host host = (Host) context.getParent(); + String mapuri = uri; + while (true) { + child = (Context) host.findChild(mapuri); + if (child != null) + break; + int slash = mapuri.lastIndexOf('/'); + if (slash < 0) + break; + mapuri = mapuri.substring(0, slash); + } + } catch (Throwable t) { + return (null); + } + + if (child == null) + return (null); + + if (context.getCrossContext()) { + // If crossContext is enabled, can always return the context + return child.getServletContext(); + } else if (child == context) { + // Can still return the current context + return context.getServletContext(); + } else { + // Nothing to return + return (null); + } + } + + + /** + * Return the main path associated with this context. + */ + public String getContextPath() { + return context.getPath(); + } + + + /** + * Return the value of the specified initialization parameter, or + * null if this parameter does not exist. + * + * @param name Name of the initialization parameter to retrieve + */ + public String getInitParameter(final String name) { + + mergeParameters(); + synchronized (parameters) { + return ((String) parameters.get(name)); + } + } + + + /** + * Return the names of the context's initialization parameters, or an + * empty enumeration if the context has no initialization parameters. + */ + public Enumeration getInitParameterNames() { + + mergeParameters(); + synchronized (parameters) { + return (new Enumerator(parameters.keySet())); + } + + } + + + /** + * Return the major version of the Java Servlet API that we implement. + */ + public int getMajorVersion() { + + return (Constants.MAJOR_VERSION); + + } + + + /** + * Return the minor version of the Java Servlet API that we implement. + */ + public int getMinorVersion() { + + return (Constants.MINOR_VERSION); + + } + + + /** + * Return the MIME type of the specified file, or null if + * the MIME type cannot be determined. + * + * @param file Filename for which to identify a MIME type + */ + public String getMimeType(String file) { + + if (file == null) + return (null); + int period = file.lastIndexOf("."); + if (period < 0) + return (null); + String extension = file.substring(period + 1); + if (extension.length() < 1) + return (null); + return (context.findMimeMapping(extension)); + + } + + + /** + * Return a RequestDispatcher object that acts as a + * wrapper for the named servlet. + * + * @param name Name of the servlet for which a dispatcher is requested + */ + public RequestDispatcher getNamedDispatcher(String name) { + + // Validate the name argument + if (name == null) + return (null); + + // Create and return a corresponding request dispatcher + Wrapper wrapper = (Wrapper) context.findChild(name); + if (wrapper == null) + return (null); + + return new ApplicationDispatcher(wrapper, null, null, null, null, name); + + } + + + /** + * Return the real path for a given virtual path, if possible; otherwise + * return null. + * + * @param path The path to the desired resource + */ + public String getRealPath(String path) { + + if (!context.isFilesystemBased()) + return null; + + if (path == null) { + return null; + } + + File file = new File(basePath, path); + return (file.getAbsolutePath()); + + } + + + /** + * Return a RequestDispatcher instance that acts as a + * wrapper for the resource at the given path. The path must begin + * with a "/" and is interpreted as relative to the current context root. + * + * @param path The path to the desired resource. + */ + public RequestDispatcher getRequestDispatcher(String path) { + + // Validate the path argument + if (path == null) + return (null); + if (!path.startsWith("/")) + throw new IllegalArgumentException + (sm.getString + ("applicationContext.requestDispatcher.iae", path)); + path = normalize(path); + if (path == null) + return (null); + + // Retrieve the thread local URI + MessageBytes uriMB = (MessageBytes) localUriMB.get(); + if (uriMB == null) { + uriMB = MessageBytes.newInstance(); + CharChunk uriCC = uriMB.getCharChunk(); + uriCC.setLimit(-1); + localUriMB.set(uriMB); + } else { + uriMB.recycle(); + } + + // Get query string + String queryString = null; + int pos = path.indexOf('?'); + if (pos >= 0) { + queryString = path.substring(pos + 1); + } else { + pos = path.length(); + } + + // Retrieve the thread local mapping data + MappingData mappingData = (MappingData) localMappingData.get(); + if (mappingData == null) { + mappingData = new MappingData(); + localMappingData.set(mappingData); + } + + // Map the URI + CharChunk uriCC = uriMB.getCharChunk(); + try { + uriCC.append(context.getPath(), 0, context.getPath().length()); + /* + * Ignore any trailing path params (separated by ';') for mapping + * purposes + */ + int semicolon = path.indexOf(';'); + if (pos >= 0 && semicolon > pos) { + semicolon = -1; + } + uriCC.append(path, 0, semicolon > 0 ? semicolon : pos); + context.getMapper().map(uriMB, mappingData); + if (mappingData.wrapper == null) { + return (null); + } + /* + * Append any trailing path params (separated by ';') that were + * ignored for mapping purposes, so that they're reflected in the + * RequestDispatcher's requestURI + */ + if (semicolon > 0) { + uriCC.append(path, semicolon, pos - semicolon); + } + } catch (Exception e) { + // Should never happen + log(sm.getString("applicationContext.mapping.error"), e); + return (null); + } + + Wrapper wrapper = (Wrapper) mappingData.wrapper; + String wrapperPath = mappingData.wrapperPath.toString(); + String pathInfo = mappingData.pathInfo.toString(); + + mappingData.recycle(); + + // Construct a RequestDispatcher to process this request + return new ApplicationDispatcher + (wrapper, uriCC.toString(), wrapperPath, pathInfo, + queryString, null); + + } + + + + /** + * Return the URL to the resource that is mapped to a specified path. + * The path must begin with a "/" and is interpreted as relative to the + * current context root. + * + * @param path The path to the desired resource + * + * @exception MalformedURLException if the path is not given + * in the correct form + */ + public URL getResource(String path) + throws MalformedURLException { + + if (path == null || !path.startsWith("/")) { + throw new MalformedURLException(sm.getString("applicationContext.requestDispatcher.iae", path)); + } + + path = normalize(path); + if (path == null) + return (null); + + String libPath = "/WEB-INF/lib/"; + if ((path.startsWith(libPath)) && (path.endsWith(".jar"))) { + File jarFile = null; + if (context.isFilesystemBased()) { + jarFile = new File(basePath, path); + } else { + jarFile = new File(context.getWorkPath(), path); + } + if (jarFile.exists()) { + return jarFile.toURL(); + } else { + return null; + } + } else { + + DirContext resources = context.getResources(); + if (resources != null) { + String fullPath = context.getName() + path; + String hostName = context.getParent().getName(); + try { + resources.lookup(path); + return new URL + ("jndi", "", 0, getJNDIUri(hostName, fullPath), + new DirContextURLStreamHandler(resources)); + } catch (Exception e) { + // Ignore + } + } + } + + return (null); + + } + + + /** + * Return the requested resource as an InputStream. The + * path must be specified according to the rules described under + * getResource. If no such resource can be identified, + * return null. + * + * @param path The path to the desired resource. + */ + public InputStream getResourceAsStream(String path) { + + path = normalize(path); + if (path == null) + return (null); + + DirContext resources = context.getResources(); + if (resources != null) { + try { + Object resource = resources.lookup(path); + if (resource instanceof Resource) + return (((Resource) resource).streamContent()); + } catch (Exception e) { + } + } + return (null); + + } + + + /** + * Return a Set containing the resource paths of resources member of the + * specified collection. Each path will be a String starting with + * a "/" character. The returned set is immutable. + * + * @param path Collection path + */ + public Set getResourcePaths(String path) { + + // Validate the path argument + if (path == null) { + return null; + } + if (!path.startsWith("/")) { + throw new IllegalArgumentException + (sm.getString("applicationContext.resourcePaths.iae", path)); + } + + path = normalize(path); + if (path == null) + return (null); + + DirContext resources = context.getResources(); + if (resources != null) { + return (getResourcePathsInternal(resources, path)); + } + return (null); + + } + + + /** + * Internal implementation of getResourcesPath() logic. + * + * @param resources Directory context to search + * @param path Collection path + */ + private Set getResourcePathsInternal(DirContext resources, String path) { + + ResourceSet set = new ResourceSet(); + try { + listCollectionPaths(set, resources, path); + } catch (NamingException e) { + return (null); + } + set.setLocked(true); + return (set); + + } + + + /** + * Return the name and version of the servlet container. + */ + public String getServerInfo() { + + return (ServerInfo.getServerInfo()); + + } + + + /** + * @deprecated As of Java Servlet API 2.1, with no direct replacement. + */ + public Servlet getServlet(String name) { + + return (null); + + } + + + /** + * Return the display name of this web application. + */ + public String getServletContextName() { + + return (context.getDisplayName()); + + } + + + /** + * @deprecated As of Java Servlet API 2.1, with no direct replacement. + */ + public Enumeration getServletNames() { + return (new Enumerator(empty)); + } + + + /** + * @deprecated As of Java Servlet API 2.1, with no direct replacement. + */ + public Enumeration getServlets() { + return (new Enumerator(empty)); + } + + + /** + * Writes the specified message to a servlet log file. + * + * @param message Message to be written + */ + public void log(String message) { + + context.getLogger().info(message); + + } + + + /** + * Writes the specified exception and message to a servlet log file. + * + * @param exception Exception to be reported + * @param message Message to be written + * + * @deprecated As of Java Servlet API 2.1, use + * log(String, Throwable) instead + */ + public void log(Exception exception, String message) { + + context.getLogger().error(message, exception); + + } + + + /** + * Writes the specified message and exception to a servlet log file. + * + * @param message Message to be written + * @param throwable Exception to be reported + */ + public void log(String message, Throwable throwable) { + + context.getLogger().error(message, throwable); + + } + + + /** + * Remove the context attribute with the specified name, if any. + * + * @param name Name of the context attribute to be removed + */ + public void removeAttribute(String name) { + + Object value = null; + boolean found = false; + + // Remove the specified attribute + synchronized (attributes) { + // Check for read only attribute + if (readOnlyAttributes.containsKey(name)) + return; + found = attributes.containsKey(name); + if (found) { + value = attributes.get(name); + attributes.remove(name); + } else { + return; + } + } + + // Notify interested application event listeners + Object listeners[] = context.getApplicationEventListeners(); + if ((listeners == null) || (listeners.length == 0)) + return; + ServletContextAttributeEvent event = + new ServletContextAttributeEvent(context.getServletContext(), + name, value); + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof ServletContextAttributeListener)) + continue; + ServletContextAttributeListener listener = + (ServletContextAttributeListener) listeners[i]; + try { + context.fireContainerEvent("beforeContextAttributeRemoved", + listener); + listener.attributeRemoved(event); + context.fireContainerEvent("afterContextAttributeRemoved", + listener); + } catch (Throwable t) { + context.fireContainerEvent("afterContextAttributeRemoved", + listener); + // FIXME - should we do anything besides log these? + log(sm.getString("applicationContext.attributeEvent"), t); + } + } + + } + + + /** + * Bind the specified value with the specified context attribute name, + * replacing any existing value for that name. + * + * @param name Attribute name to be bound + * @param value New attribute value to be bound + */ + public void setAttribute(String name, Object value) { + + // Name cannot be null + if (name == null) + throw new IllegalArgumentException + (sm.getString("applicationContext.setAttribute.namenull")); + + // Null value is the same as removeAttribute() + if (value == null) { + removeAttribute(name); + return; + } + + Object oldValue = null; + boolean replaced = false; + + // Add or replace the specified attribute + synchronized (attributes) { + // Check for read only attribute + if (readOnlyAttributes.containsKey(name)) + return; + oldValue = attributes.get(name); + if (oldValue != null) + replaced = true; + attributes.put(name, value); + } + + // Notify interested application event listeners + Object listeners[] = context.getApplicationEventListeners(); + if ((listeners == null) || (listeners.length == 0)) + return; + ServletContextAttributeEvent event = null; + if (replaced) + event = + new ServletContextAttributeEvent(context.getServletContext(), + name, oldValue); + else + event = + new ServletContextAttributeEvent(context.getServletContext(), + name, value); + + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof ServletContextAttributeListener)) + continue; + ServletContextAttributeListener listener = + (ServletContextAttributeListener) listeners[i]; + try { + if (replaced) { + context.fireContainerEvent + ("beforeContextAttributeReplaced", listener); + listener.attributeReplaced(event); + context.fireContainerEvent("afterContextAttributeReplaced", + listener); + } else { + context.fireContainerEvent("beforeContextAttributeAdded", + listener); + listener.attributeAdded(event); + context.fireContainerEvent("afterContextAttributeAdded", + listener); + } + } catch (Throwable t) { + if (replaced) + context.fireContainerEvent("afterContextAttributeReplaced", + listener); + else + context.fireContainerEvent("afterContextAttributeAdded", + listener); + // FIXME - should we do anything besides log these? + log(sm.getString("applicationContext.attributeEvent"), t); + } + } + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Clear all application-created attributes. + */ + void clearAttributes() { + + // Create list of attributes to be removed + ArrayList list = new ArrayList(); + synchronized (attributes) { + Iterator iter = attributes.keySet().iterator(); + while (iter.hasNext()) { + list.add(iter.next()); + } + } + + // Remove application originated attributes + // (read only attributes will be left in place) + Iterator keys = list.iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + removeAttribute(key); + } + + } + + + /** + * Return the facade associated with this ApplicationContext. + */ + protected ServletContext getFacade() { + + return (this.facade); + + } + + + /** + * Set an attribute as read only. + */ + void setAttributeReadOnly(String name) { + + synchronized (attributes) { + if (attributes.containsKey(name)) + readOnlyAttributes.put(name, name); + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements + * are present), return null instead. + * + * @param path Path to be normalized + */ + private String normalize(String path) { + + if (path == null) { + return null; + } + + String normalized = path; + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + return (null); // Trying to go outside our context + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Return the normalized path that we have completed + return (normalized); + + } + + + /** + * Merge the context initialization parameters specified in the application + * deployment descriptor with the application parameters described in the + * server configuration, respecting the override property of + * the application parameters appropriately. + */ + private void mergeParameters() { + + if (parameters != null) + return; + HashMap results = new HashMap(); + String names[] = context.findParameters(); + for (int i = 0; i < names.length; i++) + results.put(names[i], context.findParameter(names[i])); + ApplicationParameter params[] = + context.findApplicationParameters(); + for (int i = 0; i < params.length; i++) { + if (params[i].getOverride()) { + if (results.get(params[i].getName()) == null) + results.put(params[i].getName(), params[i].getValue()); + } else { + results.put(params[i].getName(), params[i].getValue()); + } + } + parameters = results; + + } + + + /** + * List resource paths (recursively), and store all of them in the given + * Set. + */ + private static void listCollectionPaths + (Set set, DirContext resources, String path) + throws NamingException { + + Enumeration childPaths = resources.listBindings(path); + while (childPaths.hasMoreElements()) { + Binding binding = (Binding) childPaths.nextElement(); + String name = binding.getName(); + StringBuffer childPath = new StringBuffer(path); + if (!"/".equals(path) && !path.endsWith("/")) + childPath.append("/"); + childPath.append(name); + Object object = binding.getObject(); + if (object instanceof DirContext) { + childPath.append("/"); + } + set.add(childPath.toString()); + } + + } + + + /** + * Get full path, based on the host name and the context path. + */ + private static String getJNDIUri(String hostName, String path) { + if (!path.startsWith("/")) + return "/" + hostName + "/" + path; + else + return "/" + hostName + path; + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationContextFacade.java b/java/org/apache/catalina/core/ApplicationContextFacade.java index 78d4aca22..5e5599582 100644 --- a/java/org/apache/catalina/core/ApplicationContextFacade.java +++ b/java/org/apache/catalina/core/ApplicationContextFacade.java @@ -1,508 +1,508 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.InputStream; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Set; - -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.apache.catalina.security.SecurityUtil; - - -/** - * Facade object which masks the internal ApplicationContext - * object from the web application. - * - * @author Remy Maucherat - * @author Jean-Francois Arcand - * @version $Revision: 377994 $ $Date: 2006-02-15 13:37:28 +0100 (mer., 15 févr. 2006) $ - */ - -public final class ApplicationContextFacade - implements ServletContext { - - // ---------------------------------------------------------- Attributes - /** - * Cache Class object used for reflection. - */ - private HashMap classCache; - - - /** - * Cache method object. - */ - private HashMap objectCache; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class, associated with the specified - * Context instance. - * - * @param context The associated Context instance - */ - public ApplicationContextFacade(ApplicationContext context) { - super(); - this.context = context; - - classCache = new HashMap(); - objectCache = new HashMap(); - initClassCache(); - } - - - private void initClassCache(){ - Class[] clazz = new Class[]{String.class}; - classCache.put("getContext", clazz); - classCache.put("getMimeType", clazz); - classCache.put("getResourcePaths", clazz); - classCache.put("getResource", clazz); - classCache.put("getResourceAsStream", clazz); - classCache.put("getRequestDispatcher", clazz); - classCache.put("getNamedDispatcher", clazz); - classCache.put("getServlet", clazz); - classCache.put("getInitParameter", clazz); - classCache.put("setAttribute", new Class[]{String.class, Object.class}); - classCache.put("removeAttribute", clazz); - classCache.put("getRealPath", clazz); - classCache.put("getAttribute", clazz); - classCache.put("log", clazz); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped application context. - */ - private ApplicationContext context = null; - - - - // ------------------------------------------------- ServletContext Methods - - - public ServletContext getContext(String uripath) { - ServletContext theContext = null; - if (SecurityUtil.isPackageProtectionEnabled()) { - theContext = (ServletContext) - doPrivileged("getContext", new Object[]{uripath}); - } else { - theContext = context.getContext(uripath); - } - if ((theContext != null) && - (theContext instanceof ApplicationContext)){ - theContext = ((ApplicationContext)theContext).getFacade(); - } - return (theContext); - } - - - public int getMajorVersion() { - return context.getMajorVersion(); - } - - - public int getMinorVersion() { - return context.getMinorVersion(); - } - - - public String getMimeType(String file) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String)doPrivileged("getMimeType", new Object[]{file}); - } else { - return context.getMimeType(file); - } - } - - - public Set getResourcePaths(String path) { - if (SecurityUtil.isPackageProtectionEnabled()){ - return (Set)doPrivileged("getResourcePaths", new Object[]{path}); - } else { - return context.getResourcePaths(path); - } - } - - - public URL getResource(String path) - throws MalformedURLException { - if (System.getSecurityManager() != null) { - try { - return (URL) invokeMethod(context, "getResource", - new Object[]{path}); - } catch(Throwable t) { - if (t instanceof MalformedURLException){ - throw (MalformedURLException)t; - } - return null; - } - } else { - return context.getResource(path); - } - } - - - public InputStream getResourceAsStream(String path) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (InputStream) doPrivileged("getResourceAsStream", - new Object[]{path}); - } else { - return context.getResourceAsStream(path); - } - } - - - public RequestDispatcher getRequestDispatcher(final String path) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (RequestDispatcher) doPrivileged("getRequestDispatcher", - new Object[]{path}); - } else { - return context.getRequestDispatcher(path); - } - } - - - public RequestDispatcher getNamedDispatcher(String name) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (RequestDispatcher) doPrivileged("getNamedDispatcher", - new Object[]{name}); - } else { - return context.getNamedDispatcher(name); - } - } - - - public Servlet getServlet(String name) - throws ServletException { - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - return (Servlet) invokeMethod(context, "getServlet", - new Object[]{name}); - } catch (Throwable t) { - if (t instanceof ServletException) { - throw (ServletException) t; - } - return null; - } - } else { - return context.getServlet(name); - } - } - - - public Enumeration getServlets() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (Enumeration) doPrivileged("getServlets", null); - } else { - return context.getServlets(); - } - } - - - public Enumeration getServletNames() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (Enumeration) doPrivileged("getServletNames", null); - } else { - return context.getServletNames(); - } - } - - - public void log(String msg) { - if (SecurityUtil.isPackageProtectionEnabled()) { - doPrivileged("log", new Object[]{msg} ); - } else { - context.log(msg); - } - } - - - public void log(Exception exception, String msg) { - if (SecurityUtil.isPackageProtectionEnabled()) { - doPrivileged("log", new Class[]{Exception.class, String.class}, - new Object[]{exception,msg}); - } else { - context.log(exception, msg); - } - } - - - public void log(String message, Throwable throwable) { - if (SecurityUtil.isPackageProtectionEnabled()) { - doPrivileged("log", new Class[]{String.class, Throwable.class}, - new Object[]{message, throwable}); - } else { - context.log(message, throwable); - } - } - - - public String getRealPath(String path) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String) doPrivileged("getRealPath", new Object[]{path}); - } else { - return context.getRealPath(path); - } - } - - - public String getServerInfo() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String) doPrivileged("getServerInfo", null); - } else { - return context.getServerInfo(); - } - } - - - public String getInitParameter(String name) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String) doPrivileged("getInitParameter", - new Object[]{name}); - } else { - return context.getInitParameter(name); - } - } - - - public Enumeration getInitParameterNames() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (Enumeration) doPrivileged("getInitParameterNames", null); - } else { - return context.getInitParameterNames(); - } - } - - - public Object getAttribute(String name) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return doPrivileged("getAttribute", new Object[]{name}); - } else { - return context.getAttribute(name); - } - } - - - public Enumeration getAttributeNames() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (Enumeration) doPrivileged("getAttributeNames", null); - } else { - return context.getAttributeNames(); - } - } - - - public void setAttribute(String name, Object object) { - if (SecurityUtil.isPackageProtectionEnabled()) { - doPrivileged("setAttribute", new Object[]{name,object}); - } else { - context.setAttribute(name, object); - } - } - - - public void removeAttribute(String name) { - if (SecurityUtil.isPackageProtectionEnabled()) { - doPrivileged("removeAttribute", new Object[]{name}); - } else { - context.removeAttribute(name); - } - } - - - public String getServletContextName() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String) doPrivileged("getServletContextName", null); - } else { - return context.getServletContextName(); - } - } - - - public String getContextPath() { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (String) doPrivileged("getContextPath", null); - } else { - return context.getContextPath(); - } - } - - - /** - * Use reflection to invoke the requested method. Cache the method object - * to speed up the process - * @param appContext The AppliationContext object on which the method - * will be invoked - * @param methodName The method to call. - * @param params The arguments passed to the called method. - */ - private Object doPrivileged(ApplicationContext appContext, - final String methodName, - final Object[] params) { - try{ - return invokeMethod(appContext, methodName, params ); - } catch (Throwable t){ - throw new RuntimeException(t.getMessage()); - } - - } - - - /** - * Use reflection to invoke the requested method. Cache the method object - * to speed up the process - * will be invoked - * @param methodName The method to call. - * @param params The arguments passed to the called method. - */ - private Object doPrivileged(final String methodName, final Object[] params){ - try{ - return invokeMethod(context, methodName, params); - }catch(Throwable t){ - throw new RuntimeException(t.getMessage()); - } - } - - - /** - * Use reflection to invoke the requested method. Cache the method object - * to speed up the process - * @param appContext The AppliationContext object on which the method - * will be invoked - * @param methodName The method to call. - * @param params The arguments passed to the called method. - */ - private Object invokeMethod(ApplicationContext appContext, - final String methodName, - Object[] params) - throws Throwable{ - - try{ - Method method = (Method)objectCache.get(methodName); - if (method == null){ - method = appContext.getClass() - .getMethod(methodName, (Class[])classCache.get(methodName)); - objectCache.put(methodName, method); - } - - return executeMethod(method,appContext,params); - } catch (Exception ex){ - handleException(ex, methodName); - return null; - } finally { - params = null; - } - } - - /** - * Use reflection to invoke the requested method. Cache the method object - * to speed up the process - * @param methodName The method to invoke. - * @param clazz The class where the method is. - * @param params The arguments passed to the called method. - */ - private Object doPrivileged(final String methodName, - final Class[] clazz, - Object[] params){ - - try{ - Method method = context.getClass() - .getMethod(methodName, (Class[])clazz); - return executeMethod(method,context,params); - } catch (Exception ex){ - try{ - handleException(ex, methodName); - }catch (Throwable t){ - throw new RuntimeException(t.getMessage()); - } - return null; - } finally { - params = null; - } - } - - - /** - * Executes the method of the specified ApplicationContext - * @param method The method object to be invoked. - * @param context The AppliationContext object on which the method - * will be invoked - * @param params The arguments passed to the called method. - */ - private Object executeMethod(final Method method, - final ApplicationContext context, - final Object[] params) - throws PrivilegedActionException, - IllegalAccessException, - InvocationTargetException { - - if (SecurityUtil.isPackageProtectionEnabled()){ - return AccessController.doPrivileged(new PrivilegedExceptionAction(){ - public Object run() throws IllegalAccessException, InvocationTargetException{ - return method.invoke(context, params); - } - }); - } else { - return method.invoke(context, params); - } - } - - - /** - * - * Throw the real exception. - * @param ex The current exception - */ - private void handleException(Exception ex, String methodName) - throws Throwable { - - Throwable realException; - - if (ex instanceof PrivilegedActionException) { - ex = ((PrivilegedActionException) ex).getException(); - } - - if (ex instanceof InvocationTargetException) { - realException = - ((InvocationTargetException) ex).getTargetException(); - } else { - realException = ex; - } - - throw realException; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Set; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.apache.catalina.security.SecurityUtil; + + +/** + * Facade object which masks the internal ApplicationContext + * object from the web application. + * + * @author Remy Maucherat + * @author Jean-Francois Arcand + * @version $Revision: 377994 $ $Date: 2006-02-15 13:37:28 +0100 (mer., 15 févr. 2006) $ + */ + +public final class ApplicationContextFacade + implements ServletContext { + + // ---------------------------------------------------------- Attributes + /** + * Cache Class object used for reflection. + */ + private HashMap classCache; + + + /** + * Cache method object. + */ + private HashMap objectCache; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class, associated with the specified + * Context instance. + * + * @param context The associated Context instance + */ + public ApplicationContextFacade(ApplicationContext context) { + super(); + this.context = context; + + classCache = new HashMap(); + objectCache = new HashMap(); + initClassCache(); + } + + + private void initClassCache(){ + Class[] clazz = new Class[]{String.class}; + classCache.put("getContext", clazz); + classCache.put("getMimeType", clazz); + classCache.put("getResourcePaths", clazz); + classCache.put("getResource", clazz); + classCache.put("getResourceAsStream", clazz); + classCache.put("getRequestDispatcher", clazz); + classCache.put("getNamedDispatcher", clazz); + classCache.put("getServlet", clazz); + classCache.put("getInitParameter", clazz); + classCache.put("setAttribute", new Class[]{String.class, Object.class}); + classCache.put("removeAttribute", clazz); + classCache.put("getRealPath", clazz); + classCache.put("getAttribute", clazz); + classCache.put("log", clazz); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Wrapped application context. + */ + private ApplicationContext context = null; + + + + // ------------------------------------------------- ServletContext Methods + + + public ServletContext getContext(String uripath) { + ServletContext theContext = null; + if (SecurityUtil.isPackageProtectionEnabled()) { + theContext = (ServletContext) + doPrivileged("getContext", new Object[]{uripath}); + } else { + theContext = context.getContext(uripath); + } + if ((theContext != null) && + (theContext instanceof ApplicationContext)){ + theContext = ((ApplicationContext)theContext).getFacade(); + } + return (theContext); + } + + + public int getMajorVersion() { + return context.getMajorVersion(); + } + + + public int getMinorVersion() { + return context.getMinorVersion(); + } + + + public String getMimeType(String file) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String)doPrivileged("getMimeType", new Object[]{file}); + } else { + return context.getMimeType(file); + } + } + + + public Set getResourcePaths(String path) { + if (SecurityUtil.isPackageProtectionEnabled()){ + return (Set)doPrivileged("getResourcePaths", new Object[]{path}); + } else { + return context.getResourcePaths(path); + } + } + + + public URL getResource(String path) + throws MalformedURLException { + if (System.getSecurityManager() != null) { + try { + return (URL) invokeMethod(context, "getResource", + new Object[]{path}); + } catch(Throwable t) { + if (t instanceof MalformedURLException){ + throw (MalformedURLException)t; + } + return null; + } + } else { + return context.getResource(path); + } + } + + + public InputStream getResourceAsStream(String path) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (InputStream) doPrivileged("getResourceAsStream", + new Object[]{path}); + } else { + return context.getResourceAsStream(path); + } + } + + + public RequestDispatcher getRequestDispatcher(final String path) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (RequestDispatcher) doPrivileged("getRequestDispatcher", + new Object[]{path}); + } else { + return context.getRequestDispatcher(path); + } + } + + + public RequestDispatcher getNamedDispatcher(String name) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (RequestDispatcher) doPrivileged("getNamedDispatcher", + new Object[]{name}); + } else { + return context.getNamedDispatcher(name); + } + } + + + public Servlet getServlet(String name) + throws ServletException { + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + return (Servlet) invokeMethod(context, "getServlet", + new Object[]{name}); + } catch (Throwable t) { + if (t instanceof ServletException) { + throw (ServletException) t; + } + return null; + } + } else { + return context.getServlet(name); + } + } + + + public Enumeration getServlets() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (Enumeration) doPrivileged("getServlets", null); + } else { + return context.getServlets(); + } + } + + + public Enumeration getServletNames() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (Enumeration) doPrivileged("getServletNames", null); + } else { + return context.getServletNames(); + } + } + + + public void log(String msg) { + if (SecurityUtil.isPackageProtectionEnabled()) { + doPrivileged("log", new Object[]{msg} ); + } else { + context.log(msg); + } + } + + + public void log(Exception exception, String msg) { + if (SecurityUtil.isPackageProtectionEnabled()) { + doPrivileged("log", new Class[]{Exception.class, String.class}, + new Object[]{exception,msg}); + } else { + context.log(exception, msg); + } + } + + + public void log(String message, Throwable throwable) { + if (SecurityUtil.isPackageProtectionEnabled()) { + doPrivileged("log", new Class[]{String.class, Throwable.class}, + new Object[]{message, throwable}); + } else { + context.log(message, throwable); + } + } + + + public String getRealPath(String path) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String) doPrivileged("getRealPath", new Object[]{path}); + } else { + return context.getRealPath(path); + } + } + + + public String getServerInfo() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String) doPrivileged("getServerInfo", null); + } else { + return context.getServerInfo(); + } + } + + + public String getInitParameter(String name) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String) doPrivileged("getInitParameter", + new Object[]{name}); + } else { + return context.getInitParameter(name); + } + } + + + public Enumeration getInitParameterNames() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (Enumeration) doPrivileged("getInitParameterNames", null); + } else { + return context.getInitParameterNames(); + } + } + + + public Object getAttribute(String name) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return doPrivileged("getAttribute", new Object[]{name}); + } else { + return context.getAttribute(name); + } + } + + + public Enumeration getAttributeNames() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (Enumeration) doPrivileged("getAttributeNames", null); + } else { + return context.getAttributeNames(); + } + } + + + public void setAttribute(String name, Object object) { + if (SecurityUtil.isPackageProtectionEnabled()) { + doPrivileged("setAttribute", new Object[]{name,object}); + } else { + context.setAttribute(name, object); + } + } + + + public void removeAttribute(String name) { + if (SecurityUtil.isPackageProtectionEnabled()) { + doPrivileged("removeAttribute", new Object[]{name}); + } else { + context.removeAttribute(name); + } + } + + + public String getServletContextName() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String) doPrivileged("getServletContextName", null); + } else { + return context.getServletContextName(); + } + } + + + public String getContextPath() { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (String) doPrivileged("getContextPath", null); + } else { + return context.getContextPath(); + } + } + + + /** + * Use reflection to invoke the requested method. Cache the method object + * to speed up the process + * @param appContext The AppliationContext object on which the method + * will be invoked + * @param methodName The method to call. + * @param params The arguments passed to the called method. + */ + private Object doPrivileged(ApplicationContext appContext, + final String methodName, + final Object[] params) { + try{ + return invokeMethod(appContext, methodName, params ); + } catch (Throwable t){ + throw new RuntimeException(t.getMessage()); + } + + } + + + /** + * Use reflection to invoke the requested method. Cache the method object + * to speed up the process + * will be invoked + * @param methodName The method to call. + * @param params The arguments passed to the called method. + */ + private Object doPrivileged(final String methodName, final Object[] params){ + try{ + return invokeMethod(context, methodName, params); + }catch(Throwable t){ + throw new RuntimeException(t.getMessage()); + } + } + + + /** + * Use reflection to invoke the requested method. Cache the method object + * to speed up the process + * @param appContext The AppliationContext object on which the method + * will be invoked + * @param methodName The method to call. + * @param params The arguments passed to the called method. + */ + private Object invokeMethod(ApplicationContext appContext, + final String methodName, + Object[] params) + throws Throwable{ + + try{ + Method method = (Method)objectCache.get(methodName); + if (method == null){ + method = appContext.getClass() + .getMethod(methodName, (Class[])classCache.get(methodName)); + objectCache.put(methodName, method); + } + + return executeMethod(method,appContext,params); + } catch (Exception ex){ + handleException(ex, methodName); + return null; + } finally { + params = null; + } + } + + /** + * Use reflection to invoke the requested method. Cache the method object + * to speed up the process + * @param methodName The method to invoke. + * @param clazz The class where the method is. + * @param params The arguments passed to the called method. + */ + private Object doPrivileged(final String methodName, + final Class[] clazz, + Object[] params){ + + try{ + Method method = context.getClass() + .getMethod(methodName, (Class[])clazz); + return executeMethod(method,context,params); + } catch (Exception ex){ + try{ + handleException(ex, methodName); + }catch (Throwable t){ + throw new RuntimeException(t.getMessage()); + } + return null; + } finally { + params = null; + } + } + + + /** + * Executes the method of the specified ApplicationContext + * @param method The method object to be invoked. + * @param context The AppliationContext object on which the method + * will be invoked + * @param params The arguments passed to the called method. + */ + private Object executeMethod(final Method method, + final ApplicationContext context, + final Object[] params) + throws PrivilegedActionException, + IllegalAccessException, + InvocationTargetException { + + if (SecurityUtil.isPackageProtectionEnabled()){ + return AccessController.doPrivileged(new PrivilegedExceptionAction(){ + public Object run() throws IllegalAccessException, InvocationTargetException{ + return method.invoke(context, params); + } + }); + } else { + return method.invoke(context, params); + } + } + + + /** + * + * Throw the real exception. + * @param ex The current exception + */ + private void handleException(Exception ex, String methodName) + throws Throwable { + + Throwable realException; + + if (ex instanceof PrivilegedActionException) { + ex = ((PrivilegedActionException) ex).getException(); + } + + if (ex instanceof InvocationTargetException) { + realException = + ((InvocationTargetException) ex).getTargetException(); + } else { + realException = ex; + } + + throw realException; + } +} diff --git a/java/org/apache/catalina/core/ApplicationDispatcher.java b/java/org/apache/catalina/core/ApplicationDispatcher.java index f3f739cca..eaffefb86 100644 --- a/java/org/apache/catalina/core/ApplicationDispatcher.java +++ b/java/org/apache/catalina/core/ApplicationDispatcher.java @@ -1,961 +1,961 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - -import java.io.IOException; -import java.io.PrintWriter; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; - -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestWrapper; -import javax.servlet.ServletResponse; -import javax.servlet.ServletResponseWrapper; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.InstanceEvent; -import org.apache.catalina.Wrapper; -import org.apache.catalina.connector.ClientAbortException; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.RequestFacade; -import org.apache.catalina.connector.Response; -import org.apache.catalina.connector.ResponseFacade; -import org.apache.catalina.util.InstanceSupport; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Standard implementation of RequestDispatcher that allows a - * request to be forwarded to a different resource to create the ultimate - * response, or to include the output of another resource in the response - * from this resource. This implementation allows application level servlets - * to wrap the request and/or response objects that are passed on to the - * called resource, as long as the wrapping classes extend - * javax.servlet.ServletRequestWrapper and - * javax.servlet.ServletResponseWrapper. - * - * @author Craig R. McClanahan - * @version $Revision: 303947 $ $Date: 2005-06-09 07:50:26 +0200 (jeu., 09 juin 2005) $ - */ - -final class ApplicationDispatcher - implements RequestDispatcher { - - - protected class PrivilegedForward implements PrivilegedExceptionAction { - private ServletRequest request; - private ServletResponse response; - - PrivilegedForward(ServletRequest request, ServletResponse response) - { - this.request = request; - this.response = response; - } - - public Object run() throws java.lang.Exception { - doForward(request,response); - return null; - } - } - - protected class PrivilegedInclude implements PrivilegedExceptionAction { - private ServletRequest request; - private ServletResponse response; - - PrivilegedInclude(ServletRequest request, ServletResponse response) - { - this.request = request; - this.response = response; - } - - public Object run() throws ServletException, IOException { - doInclude(request,response); - return null; - } - } - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class, configured according to the - * specified parameters. If both servletPath and pathInfo are - * null, it will be assumed that this RequestDispatcher - * was acquired by name, rather than by path. - * - * @param wrapper The Wrapper associated with the resource that will - * be forwarded to or included (required) - * @param requestURI The request URI to this resource (if any) - * @param servletPath The revised servlet path to this resource (if any) - * @param pathInfo The revised extra path information to this resource - * (if any) - * @param queryString Query string parameters included with this request - * (if any) - * @param name Servlet name (if a named dispatcher was created) - * else null - */ - public ApplicationDispatcher - (Wrapper wrapper, String requestURI, String servletPath, - String pathInfo, String queryString, String name) { - - super(); - - // Save all of our configuration parameters - this.wrapper = wrapper; - this.context = (Context) wrapper.getParent(); - this.requestURI = requestURI; - this.servletPath = servletPath; - this.origServletPath = servletPath; - this.pathInfo = pathInfo; - this.queryString = queryString; - this.name = name; - if (wrapper instanceof StandardWrapper) - this.support = ((StandardWrapper) wrapper).getInstanceSupport(); - else - this.support = new InstanceSupport(wrapper); - - if ( log.isDebugEnabled() ) - log.debug("servletPath=" + this.servletPath + ", pathInfo=" + - this.pathInfo + ", queryString=" + queryString + - ", name=" + this.name); - - } - - - // ----------------------------------------------------- Instance Variables - - private static Log log = LogFactory.getLog(ApplicationDispatcher.class); - - /** - * The request specified by the dispatching application. - */ - private ServletRequest appRequest = null; - - - /** - * The response specified by the dispatching application. - */ - private ServletResponse appResponse = null; - - - /** - * The Context this RequestDispatcher is associated with. - */ - private Context context = null; - - - /** - * Are we performing an include() instead of a forward()? - */ - private boolean including = false; - - - /** - * Descriptive information about this implementation. - */ - private static final String info = - "org.apache.catalina.core.ApplicationDispatcher/1.0"; - - - /** - * The servlet name for a named dispatcher. - */ - private String name = null; - - - /** - * The outermost request that will be passed on to the invoked servlet. - */ - private ServletRequest outerRequest = null; - - - /** - * The outermost response that will be passed on to the invoked servlet. - */ - private ServletResponse outerResponse = null; - - - /** - * The extra path information for this RequestDispatcher. - */ - private String pathInfo = null; - - - /** - * The query string parameters for this RequestDispatcher. - */ - private String queryString = null; - - - /** - * The request URI for this RequestDispatcher. - */ - private String requestURI = null; - - /** - * The servlet path for this RequestDispatcher. - */ - private String servletPath = null; - - private String origServletPath = null; - - /** - * The StringManager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The InstanceSupport instance associated with our Wrapper (used to - * send "before dispatch" and "after dispatch" events. - */ - private InstanceSupport support = null; - - - /** - * The Wrapper associated with the resource that will be forwarded to - * or included. - */ - private Wrapper wrapper = null; - - - /** - * The request wrapper we have created and installed (if any). - */ - private ServletRequest wrapRequest = null; - - - /** - * The response wrapper we have created and installed (if any). - */ - private ServletResponse wrapResponse = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Forward this request and response to another resource for processing. - * Any runtime exception, IOException, or ServletException thrown by the - * called servlet will be propogated to the caller. - * - * @param request The servlet request to be forwarded - * @param response The servlet response to be forwarded - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs - */ - public void forward(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - if (System.getSecurityManager() != null) { - try { - PrivilegedForward dp = new PrivilegedForward(request,response); - AccessController.doPrivileged(dp); - } catch (PrivilegedActionException pe) { - Exception e = pe.getException(); - if (e instanceof ServletException) - throw (ServletException) e; - throw (IOException) e; - } - } else { - doForward(request,response); - } - } - - private void doForward(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - - // Reset any output that has been buffered, but keep headers/cookies - if (response.isCommitted()) { - if ( log.isDebugEnabled() ) - log.debug(" Forward on committed response --> ISE"); - throw new IllegalStateException - (sm.getString("applicationDispatcher.forward.ise")); - } - try { - response.resetBuffer(); - } catch (IllegalStateException e) { - if ( log.isDebugEnabled() ) - log.debug(" Forward resetBuffer() returned ISE: " + e); - throw e; - } - - // Set up to handle the specified request and response - setup(request, response, false); - - // Identify the HTTP-specific request and response objects (if any) - HttpServletRequest hrequest = null; - if (request instanceof HttpServletRequest) - hrequest = (HttpServletRequest) request; - HttpServletResponse hresponse = null; - if (response instanceof HttpServletResponse) - hresponse = (HttpServletResponse) response; - - // Handle a non-HTTP forward by passing the existing request/response - if ((hrequest == null) || (hresponse == null)) { - - if ( log.isDebugEnabled() ) - log.debug(" Non-HTTP Forward"); - - processRequest(hrequest,hresponse); - - } - - // Handle an HTTP named dispatcher forward - else if ((servletPath == null) && (pathInfo == null)) { - - if ( log.isDebugEnabled() ) - log.debug(" Named Dispatcher Forward"); - - ApplicationHttpRequest wrequest = - (ApplicationHttpRequest) wrapRequest(); - wrequest.setRequestURI(hrequest.getRequestURI()); - wrequest.setContextPath(hrequest.getContextPath()); - wrequest.setServletPath(hrequest.getServletPath()); - wrequest.setPathInfo(hrequest.getPathInfo()); - wrequest.setQueryString(hrequest.getQueryString()); - - processRequest(request,response); - - wrequest.recycle(); - unwrapRequest(); - - } - - // Handle an HTTP path-based forward - else { - - if ( log.isDebugEnabled() ) - log.debug(" Path Based Forward"); - - ApplicationHttpRequest wrequest = - (ApplicationHttpRequest) wrapRequest(); - String contextPath = context.getPath(); - - if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) { - wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR, - hrequest.getRequestURI()); - wrequest.setAttribute(Globals.FORWARD_CONTEXT_PATH_ATTR, - hrequest.getContextPath()); - wrequest.setAttribute(Globals.FORWARD_SERVLET_PATH_ATTR, - hrequest.getServletPath()); - wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR, - hrequest.getPathInfo()); - wrequest.setAttribute(Globals.FORWARD_QUERY_STRING_ATTR, - hrequest.getQueryString()); - } - - wrequest.setContextPath(contextPath); - wrequest.setRequestURI(requestURI); - wrequest.setServletPath(servletPath); - wrequest.setPathInfo(pathInfo); - if (queryString != null) { - wrequest.setQueryString(queryString); - wrequest.setQueryParams(queryString); - } - - processRequest(request,response); - - wrequest.recycle(); - unwrapRequest(); - - } - - // This is not a real close in order to support error processing - if ( log.isDebugEnabled() ) - log.debug(" Disabling the response for futher output"); - - if (response instanceof ResponseFacade) { - ((ResponseFacade) response).finish(); - } else { - // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped - // and may no longer be instance of RequestFacade - if (log.isDebugEnabled()){ - log.debug( " The Response is vehiculed using a wrapper: " - + response.getClass().getName() ); - } - - // Close anyway - try { - PrintWriter writer = response.getWriter(); - writer.close(); - } catch (IllegalStateException e) { - try { - ServletOutputStream stream = response.getOutputStream(); - stream.close(); - } catch (IllegalStateException f) { - ; - } catch (IOException f) { - ; - } - } catch (IOException e) { - ; - } - } - - } - - - - /** - * Prepare the request based on the filter configuration. - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - private void processRequest(ServletRequest request, - ServletResponse response) - throws IOException, ServletException { - - Integer disInt = (Integer) request.getAttribute - (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR); - if (disInt != null) { - if (disInt.intValue() != ApplicationFilterFactory.ERROR) { - outerRequest.setAttribute - (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, - origServletPath); - outerRequest.setAttribute - (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - Integer.valueOf(ApplicationFilterFactory.FORWARD)); - invoke(outerRequest, response); - } else { - invoke(outerRequest, response); - } - } - - } - - - - /** - * Include the response from another resource in the current response. - * Any runtime exception, IOException, or ServletException thrown by the - * called servlet will be propogated to the caller. - * - * @param request The servlet request that is including this one - * @param response The servlet response to be appended to - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs - */ - public void include(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - if (System.getSecurityManager() != null) { - try { - PrivilegedInclude dp = new PrivilegedInclude(request,response); - AccessController.doPrivileged(dp); - } catch (PrivilegedActionException pe) { - Exception e = pe.getException(); - - if (e instanceof ServletException) - throw (ServletException) e; - throw (IOException) e; - } - } else { - doInclude(request,response); - } - } - - private void doInclude(ServletRequest request, ServletResponse response) - throws ServletException, IOException - { - // Set up to handle the specified request and response - setup(request, response, true); - - // Create a wrapped response to use for this request - // ServletResponse wresponse = null; - ServletResponse wresponse = wrapResponse(); - - // Handle a non-HTTP include - if (!(request instanceof HttpServletRequest) || - !(response instanceof HttpServletResponse)) { - - if ( log.isDebugEnabled() ) - log.debug(" Non-HTTP Include"); - request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - Integer.valueOf(ApplicationFilterFactory.INCLUDE)); - request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(request, outerResponse); - } - - // Handle an HTTP named dispatcher include - else if (name != null) { - - if ( log.isDebugEnabled() ) - log.debug(" Named Dispatcher Include"); - - ApplicationHttpRequest wrequest = - (ApplicationHttpRequest) wrapRequest(); - wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name); - if (servletPath != null) - wrequest.setServletPath(servletPath); - wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - Integer.valueOf(ApplicationFilterFactory.INCLUDE)); - wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(outerRequest, outerResponse); - - wrequest.recycle(); - } - - // Handle an HTTP path based include - else { - - if ( log.isDebugEnabled() ) - log.debug(" Path Based Include"); - - ApplicationHttpRequest wrequest = - (ApplicationHttpRequest) wrapRequest(); - String contextPath = context.getPath(); - if (requestURI != null) - wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR, - requestURI); - if (contextPath != null) - wrequest.setAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR, - contextPath); - if (servletPath != null) - wrequest.setAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR, - servletPath); - if (pathInfo != null) - wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR, - pathInfo); - if (queryString != null) { - wrequest.setAttribute(Globals.INCLUDE_QUERY_STRING_ATTR, - queryString); - wrequest.setQueryParams(queryString); - } - - wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - Integer.valueOf(ApplicationFilterFactory.INCLUDE)); - wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); - invoke(outerRequest, outerResponse); - - wrequest.recycle(); - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Ask the resource represented by this RequestDispatcher to process - * the associated request, and create (or append to) the associated - * response. - *

    - * IMPLEMENTATION NOTE: This implementation assumes - * that no filters are applied to a forwarded or included resource, - * because they were already done for the original request. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - private void invoke(ServletRequest request, ServletResponse response) - throws IOException, ServletException { - - // Checking to see if the context classloader is the current context - // classloader. If it's not, we're saving it, and setting the context - // classloader to the Context classloader - ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); - ClassLoader contextClassLoader = context.getLoader().getClassLoader(); - - if (oldCCL != contextClassLoader) { - Thread.currentThread().setContextClassLoader(contextClassLoader); - } else { - oldCCL = null; - } - - // Initialize local variables we may need - HttpServletRequest hrequest = (HttpServletRequest) request; - HttpServletResponse hresponse = (HttpServletResponse) response; - Servlet servlet = null; - IOException ioException = null; - ServletException servletException = null; - RuntimeException runtimeException = null; - boolean unavailable = false; - - // Check for the servlet being marked unavailable - if (wrapper.isUnavailable()) { - wrapper.getLogger().warn( - sm.getString("applicationDispatcher.isUnavailable", - wrapper.getName())); - long available = wrapper.getAvailable(); - if ((available > 0L) && (available < Long.MAX_VALUE)) - hresponse.setDateHeader("Retry-After", available); - hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm - .getString("applicationDispatcher.isUnavailable", wrapper - .getName())); - unavailable = true; - } - - // Allocate a servlet instance to process this request - try { - if (!unavailable) { - servlet = wrapper.allocate(); - } - } catch (ServletException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", - wrapper.getName()), StandardWrapper.getRootCause(e)); - servletException = e; - servlet = null; - } catch (Throwable e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", - wrapper.getName()), e); - servletException = new ServletException - (sm.getString("applicationDispatcher.allocateException", - wrapper.getName()), e); - servlet = null; - } - - // Get the FilterChain Here - ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); - ApplicationFilterChain filterChain = factory.createFilterChain(request, - wrapper,servlet); - // Call the service() method for the allocated servlet instance - try { - String jspFile = wrapper.getJspFile(); - if (jspFile != null) - request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); - else - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, - servlet, request, response); - // for includes/forwards - if ((servlet != null) && (filterChain != null)) { - filterChain.doFilter(request, response); - } - // Servlet Service Method is called by the FilterChain - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - } catch (ClientAbortException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - ioException = e; - } catch (IOException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", - wrapper.getName()), e); - ioException = e; - } catch (UnavailableException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", - wrapper.getName()), e); - servletException = e; - wrapper.unavailable(e); - } catch (ServletException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - Throwable rootCause = StandardWrapper.getRootCause(e); - if (!(rootCause instanceof ClientAbortException)) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", - wrapper.getName()), rootCause); - } - servletException = e; - } catch (RuntimeException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, - servlet, request, response); - wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", - wrapper.getName()), e); - runtimeException = e; - } - - // Release the filter chain (if any) for this request - try { - if (filterChain != null) - filterChain.release(); - } catch (Throwable e) { - log.error(sm.getString("standardWrapper.releaseFilters", - wrapper.getName()), e); - //FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue - } - - // Deallocate the allocated servlet instance - try { - if (servlet != null) { - wrapper.deallocate(servlet); - } - } catch (ServletException e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", - wrapper.getName()), e); - servletException = e; - } catch (Throwable e) { - wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", - wrapper.getName()), e); - servletException = new ServletException - (sm.getString("applicationDispatcher.deallocateException", - wrapper.getName()), e); - } - - // Reset the old context class loader - if (oldCCL != null) - Thread.currentThread().setContextClassLoader(oldCCL); - - // Unwrap request/response if needed - // See Bugzilla 30949 - unwrapRequest(); - unwrapResponse(); - - // Rethrow an exception if one was thrown by the invoked servlet - if (ioException != null) - throw ioException; - if (servletException != null) - throw servletException; - if (runtimeException != null) - throw runtimeException; - - } - - - /** - * Set up to handle the specified request and response - * - * @param request The servlet request specified by the caller - * @param response The servlet response specified by the caller - * @param including Are we performing an include() as opposed to - * a forward()? - */ - private void setup(ServletRequest request, ServletResponse response, - boolean including) { - - this.appRequest = request; - this.appResponse = response; - this.outerRequest = request; - this.outerResponse = response; - this.including = including; - - } - - - /** - * Unwrap the request if we have wrapped it. - */ - private void unwrapRequest() { - - if (wrapRequest == null) - return; - - ServletRequest previous = null; - ServletRequest current = outerRequest; - while (current != null) { - - // If we run into the container request we are done - if ((current instanceof Request) - || (current instanceof RequestFacade)) - break; - - // Remove the current request if it is our wrapper - if (current == wrapRequest) { - ServletRequest next = - ((ServletRequestWrapper) current).getRequest(); - if (previous == null) - outerRequest = next; - else - ((ServletRequestWrapper) previous).setRequest(next); - break; - } - - // Advance to the next request in the chain - previous = current; - current = ((ServletRequestWrapper) current).getRequest(); - - } - - } - - - /** - * Unwrap the response if we have wrapped it. - */ - private void unwrapResponse() { - - if (wrapResponse == null) - return; - - ServletResponse previous = null; - ServletResponse current = outerResponse; - while (current != null) { - - // If we run into the container response we are done - if ((current instanceof Response) - || (current instanceof ResponseFacade)) - break; - - // Remove the current response if it is our wrapper - if (current == wrapResponse) { - ServletResponse next = - ((ServletResponseWrapper) current).getResponse(); - if (previous == null) - outerResponse = next; - else - ((ServletResponseWrapper) previous).setResponse(next); - break; - } - - // Advance to the next response in the chain - previous = current; - current = ((ServletResponseWrapper) current).getResponse(); - - } - - } - - - /** - * Create and return a request wrapper that has been inserted in the - * appropriate spot in the request chain. - */ - private ServletRequest wrapRequest() { - - // Locate the request we should insert in front of - ServletRequest previous = null; - ServletRequest current = outerRequest; - while (current != null) { - if ("org.apache.catalina.servlets.InvokerHttpRequest". - equals(current.getClass().getName())) - break; // KLUDGE - Make nested RD.forward() using invoker work - if (!(current instanceof ServletRequestWrapper)) - break; - if (current instanceof ApplicationHttpRequest) - break; - if (current instanceof ApplicationRequest) - break; - if (current instanceof Request) - break; - previous = current; - current = ((ServletRequestWrapper) current).getRequest(); - } - - // Instantiate a new wrapper at this point and insert it in the chain - ServletRequest wrapper = null; - if ((current instanceof ApplicationHttpRequest) || - (current instanceof Request) || - (current instanceof HttpServletRequest)) { - // Compute a crossContext flag - HttpServletRequest hcurrent = (HttpServletRequest) current; - boolean crossContext = false; - if ((outerRequest instanceof ApplicationHttpRequest) || - (outerRequest instanceof Request) || - (outerRequest instanceof HttpServletRequest)) { - HttpServletRequest houterRequest = - (HttpServletRequest) outerRequest; - Object contextPath = houterRequest.getAttribute - (Globals.INCLUDE_CONTEXT_PATH_ATTR); - if (contextPath == null) { - // Forward - contextPath = houterRequest.getContextPath(); - } - crossContext = !(context.getPath().equals(contextPath)); - } - wrapper = new ApplicationHttpRequest - (hcurrent, context, crossContext); - } else { - wrapper = new ApplicationRequest(current); - } - if (previous == null) - outerRequest = wrapper; - else - ((ServletRequestWrapper) previous).setRequest(wrapper); - wrapRequest = wrapper; - return (wrapper); - - } - - - /** - * Create and return a response wrapper that has been inserted in the - * appropriate spot in the response chain. - */ - private ServletResponse wrapResponse() { - - // Locate the response we should insert in front of - ServletResponse previous = null; - ServletResponse current = outerResponse; - while (current != null) { - if (!(current instanceof ServletResponseWrapper)) - break; - if (current instanceof ApplicationHttpResponse) - break; - if (current instanceof ApplicationResponse) - break; - if (current instanceof Response) - break; - previous = current; - current = ((ServletResponseWrapper) current).getResponse(); - } - - // Instantiate a new wrapper at this point and insert it in the chain - ServletResponse wrapper = null; - if ((current instanceof ApplicationHttpResponse) || - (current instanceof Response) || - (current instanceof HttpServletResponse)) - wrapper = - new ApplicationHttpResponse((HttpServletResponse) current, - including); - else - wrapper = new ApplicationResponse(current, including); - if (previous == null) - outerResponse = wrapper; - else - ((ServletResponseWrapper) previous).setResponse(wrapper); - wrapResponse = wrapper; - return (wrapper); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + +import java.io.IOException; +import java.io.PrintWriter; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestWrapper; +import javax.servlet.ServletResponse; +import javax.servlet.ServletResponseWrapper; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.InstanceEvent; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.ClientAbortException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.RequestFacade; +import org.apache.catalina.connector.Response; +import org.apache.catalina.connector.ResponseFacade; +import org.apache.catalina.util.InstanceSupport; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Standard implementation of RequestDispatcher that allows a + * request to be forwarded to a different resource to create the ultimate + * response, or to include the output of another resource in the response + * from this resource. This implementation allows application level servlets + * to wrap the request and/or response objects that are passed on to the + * called resource, as long as the wrapping classes extend + * javax.servlet.ServletRequestWrapper and + * javax.servlet.ServletResponseWrapper. + * + * @author Craig R. McClanahan + * @version $Revision: 303947 $ $Date: 2005-06-09 07:50:26 +0200 (jeu., 09 juin 2005) $ + */ + +final class ApplicationDispatcher + implements RequestDispatcher { + + + protected class PrivilegedForward implements PrivilegedExceptionAction { + private ServletRequest request; + private ServletResponse response; + + PrivilegedForward(ServletRequest request, ServletResponse response) + { + this.request = request; + this.response = response; + } + + public Object run() throws java.lang.Exception { + doForward(request,response); + return null; + } + } + + protected class PrivilegedInclude implements PrivilegedExceptionAction { + private ServletRequest request; + private ServletResponse response; + + PrivilegedInclude(ServletRequest request, ServletResponse response) + { + this.request = request; + this.response = response; + } + + public Object run() throws ServletException, IOException { + doInclude(request,response); + return null; + } + } + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class, configured according to the + * specified parameters. If both servletPath and pathInfo are + * null, it will be assumed that this RequestDispatcher + * was acquired by name, rather than by path. + * + * @param wrapper The Wrapper associated with the resource that will + * be forwarded to or included (required) + * @param requestURI The request URI to this resource (if any) + * @param servletPath The revised servlet path to this resource (if any) + * @param pathInfo The revised extra path information to this resource + * (if any) + * @param queryString Query string parameters included with this request + * (if any) + * @param name Servlet name (if a named dispatcher was created) + * else null + */ + public ApplicationDispatcher + (Wrapper wrapper, String requestURI, String servletPath, + String pathInfo, String queryString, String name) { + + super(); + + // Save all of our configuration parameters + this.wrapper = wrapper; + this.context = (Context) wrapper.getParent(); + this.requestURI = requestURI; + this.servletPath = servletPath; + this.origServletPath = servletPath; + this.pathInfo = pathInfo; + this.queryString = queryString; + this.name = name; + if (wrapper instanceof StandardWrapper) + this.support = ((StandardWrapper) wrapper).getInstanceSupport(); + else + this.support = new InstanceSupport(wrapper); + + if ( log.isDebugEnabled() ) + log.debug("servletPath=" + this.servletPath + ", pathInfo=" + + this.pathInfo + ", queryString=" + queryString + + ", name=" + this.name); + + } + + + // ----------------------------------------------------- Instance Variables + + private static Log log = LogFactory.getLog(ApplicationDispatcher.class); + + /** + * The request specified by the dispatching application. + */ + private ServletRequest appRequest = null; + + + /** + * The response specified by the dispatching application. + */ + private ServletResponse appResponse = null; + + + /** + * The Context this RequestDispatcher is associated with. + */ + private Context context = null; + + + /** + * Are we performing an include() instead of a forward()? + */ + private boolean including = false; + + + /** + * Descriptive information about this implementation. + */ + private static final String info = + "org.apache.catalina.core.ApplicationDispatcher/1.0"; + + + /** + * The servlet name for a named dispatcher. + */ + private String name = null; + + + /** + * The outermost request that will be passed on to the invoked servlet. + */ + private ServletRequest outerRequest = null; + + + /** + * The outermost response that will be passed on to the invoked servlet. + */ + private ServletResponse outerResponse = null; + + + /** + * The extra path information for this RequestDispatcher. + */ + private String pathInfo = null; + + + /** + * The query string parameters for this RequestDispatcher. + */ + private String queryString = null; + + + /** + * The request URI for this RequestDispatcher. + */ + private String requestURI = null; + + /** + * The servlet path for this RequestDispatcher. + */ + private String servletPath = null; + + private String origServletPath = null; + + /** + * The StringManager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The InstanceSupport instance associated with our Wrapper (used to + * send "before dispatch" and "after dispatch" events. + */ + private InstanceSupport support = null; + + + /** + * The Wrapper associated with the resource that will be forwarded to + * or included. + */ + private Wrapper wrapper = null; + + + /** + * The request wrapper we have created and installed (if any). + */ + private ServletRequest wrapRequest = null; + + + /** + * The response wrapper we have created and installed (if any). + */ + private ServletResponse wrapResponse = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Forward this request and response to another resource for processing. + * Any runtime exception, IOException, or ServletException thrown by the + * called servlet will be propogated to the caller. + * + * @param request The servlet request to be forwarded + * @param response The servlet response to be forwarded + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet exception occurs + */ + public void forward(ServletRequest request, ServletResponse response) + throws ServletException, IOException + { + if (System.getSecurityManager() != null) { + try { + PrivilegedForward dp = new PrivilegedForward(request,response); + AccessController.doPrivileged(dp); + } catch (PrivilegedActionException pe) { + Exception e = pe.getException(); + if (e instanceof ServletException) + throw (ServletException) e; + throw (IOException) e; + } + } else { + doForward(request,response); + } + } + + private void doForward(ServletRequest request, ServletResponse response) + throws ServletException, IOException + { + + // Reset any output that has been buffered, but keep headers/cookies + if (response.isCommitted()) { + if ( log.isDebugEnabled() ) + log.debug(" Forward on committed response --> ISE"); + throw new IllegalStateException + (sm.getString("applicationDispatcher.forward.ise")); + } + try { + response.resetBuffer(); + } catch (IllegalStateException e) { + if ( log.isDebugEnabled() ) + log.debug(" Forward resetBuffer() returned ISE: " + e); + throw e; + } + + // Set up to handle the specified request and response + setup(request, response, false); + + // Identify the HTTP-specific request and response objects (if any) + HttpServletRequest hrequest = null; + if (request instanceof HttpServletRequest) + hrequest = (HttpServletRequest) request; + HttpServletResponse hresponse = null; + if (response instanceof HttpServletResponse) + hresponse = (HttpServletResponse) response; + + // Handle a non-HTTP forward by passing the existing request/response + if ((hrequest == null) || (hresponse == null)) { + + if ( log.isDebugEnabled() ) + log.debug(" Non-HTTP Forward"); + + processRequest(hrequest,hresponse); + + } + + // Handle an HTTP named dispatcher forward + else if ((servletPath == null) && (pathInfo == null)) { + + if ( log.isDebugEnabled() ) + log.debug(" Named Dispatcher Forward"); + + ApplicationHttpRequest wrequest = + (ApplicationHttpRequest) wrapRequest(); + wrequest.setRequestURI(hrequest.getRequestURI()); + wrequest.setContextPath(hrequest.getContextPath()); + wrequest.setServletPath(hrequest.getServletPath()); + wrequest.setPathInfo(hrequest.getPathInfo()); + wrequest.setQueryString(hrequest.getQueryString()); + + processRequest(request,response); + + wrequest.recycle(); + unwrapRequest(); + + } + + // Handle an HTTP path-based forward + else { + + if ( log.isDebugEnabled() ) + log.debug(" Path Based Forward"); + + ApplicationHttpRequest wrequest = + (ApplicationHttpRequest) wrapRequest(); + String contextPath = context.getPath(); + + if (hrequest.getAttribute(Globals.FORWARD_REQUEST_URI_ATTR) == null) { + wrequest.setAttribute(Globals.FORWARD_REQUEST_URI_ATTR, + hrequest.getRequestURI()); + wrequest.setAttribute(Globals.FORWARD_CONTEXT_PATH_ATTR, + hrequest.getContextPath()); + wrequest.setAttribute(Globals.FORWARD_SERVLET_PATH_ATTR, + hrequest.getServletPath()); + wrequest.setAttribute(Globals.FORWARD_PATH_INFO_ATTR, + hrequest.getPathInfo()); + wrequest.setAttribute(Globals.FORWARD_QUERY_STRING_ATTR, + hrequest.getQueryString()); + } + + wrequest.setContextPath(contextPath); + wrequest.setRequestURI(requestURI); + wrequest.setServletPath(servletPath); + wrequest.setPathInfo(pathInfo); + if (queryString != null) { + wrequest.setQueryString(queryString); + wrequest.setQueryParams(queryString); + } + + processRequest(request,response); + + wrequest.recycle(); + unwrapRequest(); + + } + + // This is not a real close in order to support error processing + if ( log.isDebugEnabled() ) + log.debug(" Disabling the response for futher output"); + + if (response instanceof ResponseFacade) { + ((ResponseFacade) response).finish(); + } else { + // Servlet SRV.6.2.2. The Resquest/Response may have been wrapped + // and may no longer be instance of RequestFacade + if (log.isDebugEnabled()){ + log.debug( " The Response is vehiculed using a wrapper: " + + response.getClass().getName() ); + } + + // Close anyway + try { + PrintWriter writer = response.getWriter(); + writer.close(); + } catch (IllegalStateException e) { + try { + ServletOutputStream stream = response.getOutputStream(); + stream.close(); + } catch (IllegalStateException f) { + ; + } catch (IOException f) { + ; + } + } catch (IOException e) { + ; + } + } + + } + + + + /** + * Prepare the request based on the filter configuration. + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + private void processRequest(ServletRequest request, + ServletResponse response) + throws IOException, ServletException { + + Integer disInt = (Integer) request.getAttribute + (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR); + if (disInt != null) { + if (disInt.intValue() != ApplicationFilterFactory.ERROR) { + outerRequest.setAttribute + (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, + origServletPath); + outerRequest.setAttribute + (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + Integer.valueOf(ApplicationFilterFactory.FORWARD)); + invoke(outerRequest, response); + } else { + invoke(outerRequest, response); + } + } + + } + + + + /** + * Include the response from another resource in the current response. + * Any runtime exception, IOException, or ServletException thrown by the + * called servlet will be propogated to the caller. + * + * @param request The servlet request that is including this one + * @param response The servlet response to be appended to + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet exception occurs + */ + public void include(ServletRequest request, ServletResponse response) + throws ServletException, IOException + { + if (System.getSecurityManager() != null) { + try { + PrivilegedInclude dp = new PrivilegedInclude(request,response); + AccessController.doPrivileged(dp); + } catch (PrivilegedActionException pe) { + Exception e = pe.getException(); + + if (e instanceof ServletException) + throw (ServletException) e; + throw (IOException) e; + } + } else { + doInclude(request,response); + } + } + + private void doInclude(ServletRequest request, ServletResponse response) + throws ServletException, IOException + { + // Set up to handle the specified request and response + setup(request, response, true); + + // Create a wrapped response to use for this request + // ServletResponse wresponse = null; + ServletResponse wresponse = wrapResponse(); + + // Handle a non-HTTP include + if (!(request instanceof HttpServletRequest) || + !(response instanceof HttpServletResponse)) { + + if ( log.isDebugEnabled() ) + log.debug(" Non-HTTP Include"); + request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + Integer.valueOf(ApplicationFilterFactory.INCLUDE)); + request.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); + invoke(request, outerResponse); + } + + // Handle an HTTP named dispatcher include + else if (name != null) { + + if ( log.isDebugEnabled() ) + log.debug(" Named Dispatcher Include"); + + ApplicationHttpRequest wrequest = + (ApplicationHttpRequest) wrapRequest(); + wrequest.setAttribute(Globals.NAMED_DISPATCHER_ATTR, name); + if (servletPath != null) + wrequest.setServletPath(servletPath); + wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + Integer.valueOf(ApplicationFilterFactory.INCLUDE)); + wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); + invoke(outerRequest, outerResponse); + + wrequest.recycle(); + } + + // Handle an HTTP path based include + else { + + if ( log.isDebugEnabled() ) + log.debug(" Path Based Include"); + + ApplicationHttpRequest wrequest = + (ApplicationHttpRequest) wrapRequest(); + String contextPath = context.getPath(); + if (requestURI != null) + wrequest.setAttribute(Globals.INCLUDE_REQUEST_URI_ATTR, + requestURI); + if (contextPath != null) + wrequest.setAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR, + contextPath); + if (servletPath != null) + wrequest.setAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR, + servletPath); + if (pathInfo != null) + wrequest.setAttribute(Globals.INCLUDE_PATH_INFO_ATTR, + pathInfo); + if (queryString != null) { + wrequest.setAttribute(Globals.INCLUDE_QUERY_STRING_ATTR, + queryString); + wrequest.setQueryParams(queryString); + } + + wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + Integer.valueOf(ApplicationFilterFactory.INCLUDE)); + wrequest.setAttribute(ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, origServletPath); + invoke(outerRequest, outerResponse); + + wrequest.recycle(); + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Ask the resource represented by this RequestDispatcher to process + * the associated request, and create (or append to) the associated + * response. + *

    + * IMPLEMENTATION NOTE: This implementation assumes + * that no filters are applied to a forwarded or included resource, + * because they were already done for the original request. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + private void invoke(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + + // Checking to see if the context classloader is the current context + // classloader. If it's not, we're saving it, and setting the context + // classloader to the Context classloader + ClassLoader oldCCL = Thread.currentThread().getContextClassLoader(); + ClassLoader contextClassLoader = context.getLoader().getClassLoader(); + + if (oldCCL != contextClassLoader) { + Thread.currentThread().setContextClassLoader(contextClassLoader); + } else { + oldCCL = null; + } + + // Initialize local variables we may need + HttpServletRequest hrequest = (HttpServletRequest) request; + HttpServletResponse hresponse = (HttpServletResponse) response; + Servlet servlet = null; + IOException ioException = null; + ServletException servletException = null; + RuntimeException runtimeException = null; + boolean unavailable = false; + + // Check for the servlet being marked unavailable + if (wrapper.isUnavailable()) { + wrapper.getLogger().warn( + sm.getString("applicationDispatcher.isUnavailable", + wrapper.getName())); + long available = wrapper.getAvailable(); + if ((available > 0L) && (available < Long.MAX_VALUE)) + hresponse.setDateHeader("Retry-After", available); + hresponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm + .getString("applicationDispatcher.isUnavailable", wrapper + .getName())); + unavailable = true; + } + + // Allocate a servlet instance to process this request + try { + if (!unavailable) { + servlet = wrapper.allocate(); + } + } catch (ServletException e) { + wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", + wrapper.getName()), StandardWrapper.getRootCause(e)); + servletException = e; + servlet = null; + } catch (Throwable e) { + wrapper.getLogger().error(sm.getString("applicationDispatcher.allocateException", + wrapper.getName()), e); + servletException = new ServletException + (sm.getString("applicationDispatcher.allocateException", + wrapper.getName()), e); + servlet = null; + } + + // Get the FilterChain Here + ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance(); + ApplicationFilterChain filterChain = factory.createFilterChain(request, + wrapper,servlet); + // Call the service() method for the allocated servlet instance + try { + String jspFile = wrapper.getJspFile(); + if (jspFile != null) + request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); + else + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.BEFORE_DISPATCH_EVENT, + servlet, request, response); + // for includes/forwards + if ((servlet != null) && (filterChain != null)) { + filterChain.doFilter(request, response); + } + // Servlet Service Method is called by the FilterChain + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + } catch (ClientAbortException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + ioException = e; + } catch (IOException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + wrapper.getName()), e); + ioException = e; + } catch (UnavailableException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + wrapper.getName()), e); + servletException = e; + wrapper.unavailable(e); + } catch (ServletException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + Throwable rootCause = StandardWrapper.getRootCause(e); + if (!(rootCause instanceof ClientAbortException)) { + wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + wrapper.getName()), rootCause); + } + servletException = e; + } catch (RuntimeException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + support.fireInstanceEvent(InstanceEvent.AFTER_DISPATCH_EVENT, + servlet, request, response); + wrapper.getLogger().error(sm.getString("applicationDispatcher.serviceException", + wrapper.getName()), e); + runtimeException = e; + } + + // Release the filter chain (if any) for this request + try { + if (filterChain != null) + filterChain.release(); + } catch (Throwable e) { + log.error(sm.getString("standardWrapper.releaseFilters", + wrapper.getName()), e); + //FIXME Exception handling needs to be simpiler to what is in the StandardWrapperValue + } + + // Deallocate the allocated servlet instance + try { + if (servlet != null) { + wrapper.deallocate(servlet); + } + } catch (ServletException e) { + wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", + wrapper.getName()), e); + servletException = e; + } catch (Throwable e) { + wrapper.getLogger().error(sm.getString("applicationDispatcher.deallocateException", + wrapper.getName()), e); + servletException = new ServletException + (sm.getString("applicationDispatcher.deallocateException", + wrapper.getName()), e); + } + + // Reset the old context class loader + if (oldCCL != null) + Thread.currentThread().setContextClassLoader(oldCCL); + + // Unwrap request/response if needed + // See Bugzilla 30949 + unwrapRequest(); + unwrapResponse(); + + // Rethrow an exception if one was thrown by the invoked servlet + if (ioException != null) + throw ioException; + if (servletException != null) + throw servletException; + if (runtimeException != null) + throw runtimeException; + + } + + + /** + * Set up to handle the specified request and response + * + * @param request The servlet request specified by the caller + * @param response The servlet response specified by the caller + * @param including Are we performing an include() as opposed to + * a forward()? + */ + private void setup(ServletRequest request, ServletResponse response, + boolean including) { + + this.appRequest = request; + this.appResponse = response; + this.outerRequest = request; + this.outerResponse = response; + this.including = including; + + } + + + /** + * Unwrap the request if we have wrapped it. + */ + private void unwrapRequest() { + + if (wrapRequest == null) + return; + + ServletRequest previous = null; + ServletRequest current = outerRequest; + while (current != null) { + + // If we run into the container request we are done + if ((current instanceof Request) + || (current instanceof RequestFacade)) + break; + + // Remove the current request if it is our wrapper + if (current == wrapRequest) { + ServletRequest next = + ((ServletRequestWrapper) current).getRequest(); + if (previous == null) + outerRequest = next; + else + ((ServletRequestWrapper) previous).setRequest(next); + break; + } + + // Advance to the next request in the chain + previous = current; + current = ((ServletRequestWrapper) current).getRequest(); + + } + + } + + + /** + * Unwrap the response if we have wrapped it. + */ + private void unwrapResponse() { + + if (wrapResponse == null) + return; + + ServletResponse previous = null; + ServletResponse current = outerResponse; + while (current != null) { + + // If we run into the container response we are done + if ((current instanceof Response) + || (current instanceof ResponseFacade)) + break; + + // Remove the current response if it is our wrapper + if (current == wrapResponse) { + ServletResponse next = + ((ServletResponseWrapper) current).getResponse(); + if (previous == null) + outerResponse = next; + else + ((ServletResponseWrapper) previous).setResponse(next); + break; + } + + // Advance to the next response in the chain + previous = current; + current = ((ServletResponseWrapper) current).getResponse(); + + } + + } + + + /** + * Create and return a request wrapper that has been inserted in the + * appropriate spot in the request chain. + */ + private ServletRequest wrapRequest() { + + // Locate the request we should insert in front of + ServletRequest previous = null; + ServletRequest current = outerRequest; + while (current != null) { + if ("org.apache.catalina.servlets.InvokerHttpRequest". + equals(current.getClass().getName())) + break; // KLUDGE - Make nested RD.forward() using invoker work + if (!(current instanceof ServletRequestWrapper)) + break; + if (current instanceof ApplicationHttpRequest) + break; + if (current instanceof ApplicationRequest) + break; + if (current instanceof Request) + break; + previous = current; + current = ((ServletRequestWrapper) current).getRequest(); + } + + // Instantiate a new wrapper at this point and insert it in the chain + ServletRequest wrapper = null; + if ((current instanceof ApplicationHttpRequest) || + (current instanceof Request) || + (current instanceof HttpServletRequest)) { + // Compute a crossContext flag + HttpServletRequest hcurrent = (HttpServletRequest) current; + boolean crossContext = false; + if ((outerRequest instanceof ApplicationHttpRequest) || + (outerRequest instanceof Request) || + (outerRequest instanceof HttpServletRequest)) { + HttpServletRequest houterRequest = + (HttpServletRequest) outerRequest; + Object contextPath = houterRequest.getAttribute + (Globals.INCLUDE_CONTEXT_PATH_ATTR); + if (contextPath == null) { + // Forward + contextPath = houterRequest.getContextPath(); + } + crossContext = !(context.getPath().equals(contextPath)); + } + wrapper = new ApplicationHttpRequest + (hcurrent, context, crossContext); + } else { + wrapper = new ApplicationRequest(current); + } + if (previous == null) + outerRequest = wrapper; + else + ((ServletRequestWrapper) previous).setRequest(wrapper); + wrapRequest = wrapper; + return (wrapper); + + } + + + /** + * Create and return a response wrapper that has been inserted in the + * appropriate spot in the response chain. + */ + private ServletResponse wrapResponse() { + + // Locate the response we should insert in front of + ServletResponse previous = null; + ServletResponse current = outerResponse; + while (current != null) { + if (!(current instanceof ServletResponseWrapper)) + break; + if (current instanceof ApplicationHttpResponse) + break; + if (current instanceof ApplicationResponse) + break; + if (current instanceof Response) + break; + previous = current; + current = ((ServletResponseWrapper) current).getResponse(); + } + + // Instantiate a new wrapper at this point and insert it in the chain + ServletResponse wrapper = null; + if ((current instanceof ApplicationHttpResponse) || + (current instanceof Response) || + (current instanceof HttpServletResponse)) + wrapper = + new ApplicationHttpResponse((HttpServletResponse) current, + including); + else + wrapper = new ApplicationResponse(current, including); + if (previous == null) + outerResponse = wrapper; + else + ((ServletResponseWrapper) previous).setResponse(wrapper); + wrapResponse = wrapper; + return (wrapper); + + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationFilterChain.java b/java/org/apache/catalina/core/ApplicationFilterChain.java index ca36d4721..6297dfb4c 100644 --- a/java/org/apache/catalina/core/ApplicationFilterChain.java +++ b/java/org/apache/catalina/core/ApplicationFilterChain.java @@ -1,342 +1,342 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; -import java.security.Principal; -import java.security.PrivilegedActionException; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.InstanceEvent; -import org.apache.catalina.security.SecurityUtil; -import org.apache.catalina.util.InstanceSupport; -import org.apache.catalina.util.StringManager; - -/** - * Implementation of javax.servlet.FilterChain used to manage - * the execution of a set of filters for a particular request. When the - * set of defined filters has all been executed, the next call to - * doFilter() will execute the servlet's service() - * method itself. - * - * @author Craig R. McClanahan - * @version $Revision: 303523 $ $Date: 2004-11-22 17:35:18 +0100 (lun., 22 nov. 2004) $ - */ - -final class ApplicationFilterChain implements FilterChain { - - - // -------------------------------------------------------------- Constants - - - public static final int INCREMENT = 10; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new chain instance with no defined filters. - */ - public ApplicationFilterChain() { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Filters. - */ - private ApplicationFilterConfig[] filters = - new ApplicationFilterConfig[0]; - - - /** - * The int which is used to maintain the current position - * in the filter chain. - */ - private int pos = 0; - - - /** - * The int which gives the current number of filters in the chain. - */ - private int n = 0; - - - /** - * The servlet instance to be executed by this chain. - */ - private Servlet servlet = null; - - - /** - * The string manager for our package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The InstanceSupport instance associated with our Wrapper (used to - * send "before filter" and "after filter" events. - */ - private InstanceSupport support = null; - - - /** - * Static class array used when the SecurityManager is turned on and - * doFilterserviceservice() method of the servlet itself. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet exception occurs - */ - public void doFilter(ServletRequest request, ServletResponse response) - throws IOException, ServletException { - - if( System.getSecurityManager() != null ) { - final ServletRequest req = request; - final ServletResponse res = response; - try { - java.security.AccessController.doPrivileged( - new java.security.PrivilegedExceptionAction() { - public Object run() - throws ServletException, IOException { - internalDoFilter(req,res); - return null; - } - } - ); - } catch( PrivilegedActionException pe) { - Exception e = pe.getException(); - if (e instanceof ServletException) - throw (ServletException) e; - else if (e instanceof IOException) - throw (IOException) e; - else if (e instanceof RuntimeException) - throw (RuntimeException) e; - else - throw new ServletException(e.getMessage(), e); - } - } else { - internalDoFilter(request,response); - } - } - - private void internalDoFilter(ServletRequest request, - ServletResponse response) - throws IOException, ServletException { - - // Call the next filter if there is one - if (pos < n) { - ApplicationFilterConfig filterConfig = filters[pos++]; - Filter filter = null; - try { - filter = filterConfig.getFilter(); - support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, - filter, request, response); - - if( System.getSecurityManager() != null ) { - final ServletRequest req = request; - final ServletResponse res = response; - Principal principal = - ((HttpServletRequest) req).getUserPrincipal(); - - Object[] args = new Object[]{req, res, this}; - SecurityUtil.doAsPrivilege - ("doFilter", filter, classType, args); - - args = null; - } else { - filter.doFilter(request, response, this); - } - - support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, - filter, request, response); - } catch (IOException e) { - if (filter != null) - support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, - filter, request, response, e); - throw e; - } catch (ServletException e) { - if (filter != null) - support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, - filter, request, response, e); - throw e; - } catch (RuntimeException e) { - if (filter != null) - support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, - filter, request, response, e); - throw e; - } catch (Throwable e) { - if (filter != null) - support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, - filter, request, response, e); - throw new ServletException - (sm.getString("filterChain.filter"), e); - } - return; - } - - // We fell off the end of the chain -- call the servlet instance - try { - support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, - servlet, request, response); - if ((request instanceof HttpServletRequest) && - (response instanceof HttpServletResponse)) { - - if( System.getSecurityManager() != null ) { - final ServletRequest req = request; - final ServletResponse res = response; - Principal principal = - ((HttpServletRequest) req).getUserPrincipal(); - Object[] args = new Object[]{req, res}; - SecurityUtil.doAsPrivilege("service", - servlet, - classTypeUsedInService, - args, - principal); - args = null; - } else { - servlet.service((HttpServletRequest) request, - (HttpServletResponse) response); - } - } else { - servlet.service(request, response); - } - support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, - servlet, request, response); - } catch (IOException e) { - support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, - servlet, request, response, e); - throw e; - } catch (ServletException e) { - support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, - servlet, request, response, e); - throw e; - } catch (RuntimeException e) { - support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, - servlet, request, response, e); - throw e; - } catch (Throwable e) { - support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, - servlet, request, response, e); - throw new ServletException - (sm.getString("filterChain.servlet"), e); - } - - } - - - // -------------------------------------------------------- Package Methods - - - - /** - * Add a filter to the set of filters that will be executed in this chain. - * - * @param filterConfig The FilterConfig for the servlet to be executed - */ - void addFilter(ApplicationFilterConfig filterConfig) { - - if (n == filters.length) { - ApplicationFilterConfig[] newFilters = - new ApplicationFilterConfig[n + INCREMENT]; - System.arraycopy(filters, 0, newFilters, 0, n); - filters = newFilters; - } - filters[n++] = filterConfig; - - } - - - /** - * Release references to the filters and wrapper executed by this chain. - */ - void release() { - - n = 0; - pos = 0; - servlet = null; - support = null; - - } - - - /** - * Set the servlet that will be executed at the end of this chain. - * - * @param servlet The Wrapper for the servlet to be executed - */ - void setServlet(Servlet servlet) { - - this.servlet = servlet; - - } - - - /** - * Set the InstanceSupport object used for event notifications - * for this filter chain. - * - * @param support The InstanceSupport object for our Wrapper - */ - void setSupport(InstanceSupport support) { - - this.support = support; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; +import java.security.Principal; +import java.security.PrivilegedActionException; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.InstanceEvent; +import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.util.InstanceSupport; +import org.apache.catalina.util.StringManager; + +/** + * Implementation of javax.servlet.FilterChain used to manage + * the execution of a set of filters for a particular request. When the + * set of defined filters has all been executed, the next call to + * doFilter() will execute the servlet's service() + * method itself. + * + * @author Craig R. McClanahan + * @version $Revision: 303523 $ $Date: 2004-11-22 17:35:18 +0100 (lun., 22 nov. 2004) $ + */ + +final class ApplicationFilterChain implements FilterChain { + + + // -------------------------------------------------------------- Constants + + + public static final int INCREMENT = 10; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new chain instance with no defined filters. + */ + public ApplicationFilterChain() { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Filters. + */ + private ApplicationFilterConfig[] filters = + new ApplicationFilterConfig[0]; + + + /** + * The int which is used to maintain the current position + * in the filter chain. + */ + private int pos = 0; + + + /** + * The int which gives the current number of filters in the chain. + */ + private int n = 0; + + + /** + * The servlet instance to be executed by this chain. + */ + private Servlet servlet = null; + + + /** + * The string manager for our package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The InstanceSupport instance associated with our Wrapper (used to + * send "before filter" and "after filter" events. + */ + private InstanceSupport support = null; + + + /** + * Static class array used when the SecurityManager is turned on and + * doFilterserviceservice() method of the servlet itself. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet exception occurs + */ + public void doFilter(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + + if( System.getSecurityManager() != null ) { + final ServletRequest req = request; + final ServletResponse res = response; + try { + java.security.AccessController.doPrivileged( + new java.security.PrivilegedExceptionAction() { + public Object run() + throws ServletException, IOException { + internalDoFilter(req,res); + return null; + } + } + ); + } catch( PrivilegedActionException pe) { + Exception e = pe.getException(); + if (e instanceof ServletException) + throw (ServletException) e; + else if (e instanceof IOException) + throw (IOException) e; + else if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new ServletException(e.getMessage(), e); + } + } else { + internalDoFilter(request,response); + } + } + + private void internalDoFilter(ServletRequest request, + ServletResponse response) + throws IOException, ServletException { + + // Call the next filter if there is one + if (pos < n) { + ApplicationFilterConfig filterConfig = filters[pos++]; + Filter filter = null; + try { + filter = filterConfig.getFilter(); + support.fireInstanceEvent(InstanceEvent.BEFORE_FILTER_EVENT, + filter, request, response); + + if( System.getSecurityManager() != null ) { + final ServletRequest req = request; + final ServletResponse res = response; + Principal principal = + ((HttpServletRequest) req).getUserPrincipal(); + + Object[] args = new Object[]{req, res, this}; + SecurityUtil.doAsPrivilege + ("doFilter", filter, classType, args); + + args = null; + } else { + filter.doFilter(request, response, this); + } + + support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, + filter, request, response); + } catch (IOException e) { + if (filter != null) + support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, + filter, request, response, e); + throw e; + } catch (ServletException e) { + if (filter != null) + support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, + filter, request, response, e); + throw e; + } catch (RuntimeException e) { + if (filter != null) + support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, + filter, request, response, e); + throw e; + } catch (Throwable e) { + if (filter != null) + support.fireInstanceEvent(InstanceEvent.AFTER_FILTER_EVENT, + filter, request, response, e); + throw new ServletException + (sm.getString("filterChain.filter"), e); + } + return; + } + + // We fell off the end of the chain -- call the servlet instance + try { + support.fireInstanceEvent(InstanceEvent.BEFORE_SERVICE_EVENT, + servlet, request, response); + if ((request instanceof HttpServletRequest) && + (response instanceof HttpServletResponse)) { + + if( System.getSecurityManager() != null ) { + final ServletRequest req = request; + final ServletResponse res = response; + Principal principal = + ((HttpServletRequest) req).getUserPrincipal(); + Object[] args = new Object[]{req, res}; + SecurityUtil.doAsPrivilege("service", + servlet, + classTypeUsedInService, + args, + principal); + args = null; + } else { + servlet.service((HttpServletRequest) request, + (HttpServletResponse) response); + } + } else { + servlet.service(request, response); + } + support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, + servlet, request, response); + } catch (IOException e) { + support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, + servlet, request, response, e); + throw e; + } catch (ServletException e) { + support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, + servlet, request, response, e); + throw e; + } catch (RuntimeException e) { + support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, + servlet, request, response, e); + throw e; + } catch (Throwable e) { + support.fireInstanceEvent(InstanceEvent.AFTER_SERVICE_EVENT, + servlet, request, response, e); + throw new ServletException + (sm.getString("filterChain.servlet"), e); + } + + } + + + // -------------------------------------------------------- Package Methods + + + + /** + * Add a filter to the set of filters that will be executed in this chain. + * + * @param filterConfig The FilterConfig for the servlet to be executed + */ + void addFilter(ApplicationFilterConfig filterConfig) { + + if (n == filters.length) { + ApplicationFilterConfig[] newFilters = + new ApplicationFilterConfig[n + INCREMENT]; + System.arraycopy(filters, 0, newFilters, 0, n); + filters = newFilters; + } + filters[n++] = filterConfig; + + } + + + /** + * Release references to the filters and wrapper executed by this chain. + */ + void release() { + + n = 0; + pos = 0; + servlet = null; + support = null; + + } + + + /** + * Set the servlet that will be executed at the end of this chain. + * + * @param servlet The Wrapper for the servlet to be executed + */ + void setServlet(Servlet servlet) { + + this.servlet = servlet; + + } + + + /** + * Set the InstanceSupport object used for event notifications + * for this filter chain. + * + * @param support The InstanceSupport object for our Wrapper + */ + void setSupport(InstanceSupport support) { + + this.support = support; + + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationFilterConfig.java b/java/org/apache/catalina/core/ApplicationFilterConfig.java index 9c431b12f..56d3161a0 100644 --- a/java/org/apache/catalina/core/ApplicationFilterConfig.java +++ b/java/org/apache/catalina/core/ApplicationFilterConfig.java @@ -1,346 +1,346 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Map; - -import javax.naming.NamingException; -import javax.servlet.Filter; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - -import org.apache.catalina.Context; -import org.apache.catalina.deploy.FilterDef; -import org.apache.catalina.security.SecurityUtil; -import org.apache.catalina.util.AnnotationProcessor; -import org.apache.catalina.util.Enumerator; -import org.apache.tomcat.util.log.SystemLogHandler; - - -/** - * Implementation of a javax.servlet.FilterConfig useful in - * managing the filter instances instantiated when a web application - * is first started. - * - * @author Craig R. McClanahan - * @version $Revision: 355530 $ $Date: 2005-12-09 17:42:23 +0100 (ven., 09 déc. 2005) $ - */ - -final class ApplicationFilterConfig implements FilterConfig, Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new ApplicationFilterConfig for the specified filter - * definition. - * - * @param context The context with which we are associated - * @param filterDef Filter definition for which a FilterConfig is to be - * constructed - * - * @exception ClassCastException if the specified class does not implement - * the javax.servlet.Filter interface - * @exception ClassNotFoundException if the filter class cannot be found - * @exception IllegalAccessException if the filter class cannot be - * publicly instantiated - * @exception InstantiationException if an exception occurs while - * instantiating the filter object - * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException - */ - public ApplicationFilterConfig(Context context, FilterDef filterDef) - throws ClassCastException, ClassNotFoundException, - IllegalAccessException, InstantiationException, - ServletException, InvocationTargetException, NamingException { - - super(); - this.context = context; - setFilterDef(filterDef); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The Context with which we are associated. - */ - private Context context = null; - - - /** - * The application Filter we are configured for. - */ - private transient Filter filter = null; - - - /** - * The FilterDef that defines our associated Filter. - */ - private FilterDef filterDef = null; - - - // --------------------------------------------------- FilterConfig Methods - - - /** - * Return the name of the filter we are configuring. - */ - public String getFilterName() { - - return (filterDef.getFilterName()); - - } - - - /** - * Return a String containing the value of the named - * initialization parameter, or null if the parameter - * does not exist. - * - * @param name Name of the requested initialization parameter - */ - public String getInitParameter(String name) { - - Map map = filterDef.getParameterMap(); - if (map == null) - return (null); - else - return ((String) map.get(name)); - - } - - - /** - * Return an Enumeration of the names of the initialization - * parameters for this Filter. - */ - public Enumeration getInitParameterNames() { - - Map map = filterDef.getParameterMap(); - if (map == null) - return (new Enumerator(new ArrayList())); - else - return (new Enumerator(map.keySet())); - - } - - - /** - * Return the ServletContext of our associated web application. - */ - public ServletContext getServletContext() { - - return (this.context.getServletContext()); - - } - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ApplicationFilterConfig["); - sb.append("name="); - sb.append(filterDef.getFilterName()); - sb.append(", filterClass="); - sb.append(filterDef.getFilterClass()); - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Return the application Filter we are configured for. - * - * @exception ClassCastException if the specified class does not implement - * the javax.servlet.Filter interface - * @exception ClassNotFoundException if the filter class cannot be found - * @exception IllegalAccessException if the filter class cannot be - * publicly instantiated - * @exception InstantiationException if an exception occurs while - * instantiating the filter object - * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException - */ - Filter getFilter() throws ClassCastException, ClassNotFoundException, - IllegalAccessException, InstantiationException, ServletException, - InvocationTargetException, NamingException { - - // Return the existing filter instance, if any - if (this.filter != null) - return (this.filter); - - // Identify the class loader we will be using - String filterClass = filterDef.getFilterClass(); - ClassLoader classLoader = null; - if (filterClass.startsWith("org.apache.catalina.")) - classLoader = this.getClass().getClassLoader(); - else - classLoader = context.getLoader().getClassLoader(); - - ClassLoader oldCtxClassLoader = - Thread.currentThread().getContextClassLoader(); - - // Instantiate a new instance of this filter and return it - Class clazz = classLoader.loadClass(filterClass); - this.filter = (Filter) clazz.newInstance(); - if (!context.getIgnoreAnnotations()) { - if (context instanceof StandardContext - && ((StandardContext) context).getNamingContextListener() != null) { - AnnotationProcessor.injectNamingResources - (((StandardContext) context).getNamingContextListener().getEnvContext(), this.filter); - } - AnnotationProcessor.postConstruct(this.filter); - } - if (context instanceof StandardContext && - ((StandardContext) context).getSwallowOutput()) { - try { - SystemLogHandler.startCapture(); - filter.init(this); - } finally { - String log = SystemLogHandler.stopCapture(); - if (log != null && log.length() > 0) { - getServletContext().log(log); - } - } - } else { - filter.init(this); - } - return (this.filter); - - } - - - /** - * Return the filter definition we are configured for. - */ - FilterDef getFilterDef() { - - return (this.filterDef); - - } - - - /** - * Release the Filter instance associated with this FilterConfig, - * if there is one. - */ - void release() { - - if (this.filter != null){ - if (System.getSecurityManager() != null) { - try { - SecurityUtil.doAsPrivilege("destroy", filter); - } catch(java.lang.Exception ex){ - context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); - } - SecurityUtil.remove(filter); - } else { - filter.destroy(); - } - if (!context.getIgnoreAnnotations()) { - try { - AnnotationProcessor.preDestroy(this.filter); - } catch (Exception e) { - context.getLogger().error("ApplicationFilterConfig.preDestroy", e); - } - } - } - this.filter = null; - - } - - - /** - * Set the filter definition we are configured for. This has the side - * effect of instantiating an instance of the corresponding filter class. - * - * @param filterDef The new filter definition - * - * @exception ClassCastException if the specified class does not implement - * the javax.servlet.Filter interface - * @exception ClassNotFoundException if the filter class cannot be found - * @exception IllegalAccessException if the filter class cannot be - * publicly instantiated - * @exception InstantiationException if an exception occurs while - * instantiating the filter object - * @exception ServletException if thrown by the filter's init() method - * @throws NamingException - * @throws InvocationTargetException - */ - void setFilterDef(FilterDef filterDef) - throws ClassCastException, ClassNotFoundException, - IllegalAccessException, InstantiationException, - ServletException, InvocationTargetException, NamingException { - - this.filterDef = filterDef; - if (filterDef == null) { - - // Release any previously allocated filter instance - if (this.filter != null){ - if( System.getSecurityManager() != null) { - try{ - SecurityUtil.doAsPrivilege("destroy", filter); - } catch(java.lang.Exception ex){ - context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); - } - SecurityUtil.remove(filter); - } else { - filter.destroy(); - } - if (!context.getIgnoreAnnotations()) { - try { - AnnotationProcessor.preDestroy(this.filter); - } catch (Exception e) { - context.getLogger().error("ApplicationFilterConfig.preDestroy", e); - } - } - } - this.filter = null; - - } else { - - // Allocate a new filter instance - Filter filter = getFilter(); - - } - - } - - - // -------------------------------------------------------- Private Methods - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.Serializable; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Map; + +import javax.naming.NamingException; +import javax.servlet.Filter; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + +import org.apache.catalina.Context; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.util.AnnotationProcessor; +import org.apache.catalina.util.Enumerator; +import org.apache.tomcat.util.log.SystemLogHandler; + + +/** + * Implementation of a javax.servlet.FilterConfig useful in + * managing the filter instances instantiated when a web application + * is first started. + * + * @author Craig R. McClanahan + * @version $Revision: 355530 $ $Date: 2005-12-09 17:42:23 +0100 (ven., 09 déc. 2005) $ + */ + +final class ApplicationFilterConfig implements FilterConfig, Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new ApplicationFilterConfig for the specified filter + * definition. + * + * @param context The context with which we are associated + * @param filterDef Filter definition for which a FilterConfig is to be + * constructed + * + * @exception ClassCastException if the specified class does not implement + * the javax.servlet.Filter interface + * @exception ClassNotFoundException if the filter class cannot be found + * @exception IllegalAccessException if the filter class cannot be + * publicly instantiated + * @exception InstantiationException if an exception occurs while + * instantiating the filter object + * @exception ServletException if thrown by the filter's init() method + * @throws NamingException + * @throws InvocationTargetException + */ + public ApplicationFilterConfig(Context context, FilterDef filterDef) + throws ClassCastException, ClassNotFoundException, + IllegalAccessException, InstantiationException, + ServletException, InvocationTargetException, NamingException { + + super(); + this.context = context; + setFilterDef(filterDef); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Context with which we are associated. + */ + private Context context = null; + + + /** + * The application Filter we are configured for. + */ + private transient Filter filter = null; + + + /** + * The FilterDef that defines our associated Filter. + */ + private FilterDef filterDef = null; + + + // --------------------------------------------------- FilterConfig Methods + + + /** + * Return the name of the filter we are configuring. + */ + public String getFilterName() { + + return (filterDef.getFilterName()); + + } + + + /** + * Return a String containing the value of the named + * initialization parameter, or null if the parameter + * does not exist. + * + * @param name Name of the requested initialization parameter + */ + public String getInitParameter(String name) { + + Map map = filterDef.getParameterMap(); + if (map == null) + return (null); + else + return ((String) map.get(name)); + + } + + + /** + * Return an Enumeration of the names of the initialization + * parameters for this Filter. + */ + public Enumeration getInitParameterNames() { + + Map map = filterDef.getParameterMap(); + if (map == null) + return (new Enumerator(new ArrayList())); + else + return (new Enumerator(map.keySet())); + + } + + + /** + * Return the ServletContext of our associated web application. + */ + public ServletContext getServletContext() { + + return (this.context.getServletContext()); + + } + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ApplicationFilterConfig["); + sb.append("name="); + sb.append(filterDef.getFilterName()); + sb.append(", filterClass="); + sb.append(filterDef.getFilterClass()); + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Return the application Filter we are configured for. + * + * @exception ClassCastException if the specified class does not implement + * the javax.servlet.Filter interface + * @exception ClassNotFoundException if the filter class cannot be found + * @exception IllegalAccessException if the filter class cannot be + * publicly instantiated + * @exception InstantiationException if an exception occurs while + * instantiating the filter object + * @exception ServletException if thrown by the filter's init() method + * @throws NamingException + * @throws InvocationTargetException + */ + Filter getFilter() throws ClassCastException, ClassNotFoundException, + IllegalAccessException, InstantiationException, ServletException, + InvocationTargetException, NamingException { + + // Return the existing filter instance, if any + if (this.filter != null) + return (this.filter); + + // Identify the class loader we will be using + String filterClass = filterDef.getFilterClass(); + ClassLoader classLoader = null; + if (filterClass.startsWith("org.apache.catalina.")) + classLoader = this.getClass().getClassLoader(); + else + classLoader = context.getLoader().getClassLoader(); + + ClassLoader oldCtxClassLoader = + Thread.currentThread().getContextClassLoader(); + + // Instantiate a new instance of this filter and return it + Class clazz = classLoader.loadClass(filterClass); + this.filter = (Filter) clazz.newInstance(); + if (!context.getIgnoreAnnotations()) { + if (context instanceof StandardContext + && ((StandardContext) context).getNamingContextListener() != null) { + AnnotationProcessor.injectNamingResources + (((StandardContext) context).getNamingContextListener().getEnvContext(), this.filter); + } + AnnotationProcessor.postConstruct(this.filter); + } + if (context instanceof StandardContext && + ((StandardContext) context).getSwallowOutput()) { + try { + SystemLogHandler.startCapture(); + filter.init(this); + } finally { + String log = SystemLogHandler.stopCapture(); + if (log != null && log.length() > 0) { + getServletContext().log(log); + } + } + } else { + filter.init(this); + } + return (this.filter); + + } + + + /** + * Return the filter definition we are configured for. + */ + FilterDef getFilterDef() { + + return (this.filterDef); + + } + + + /** + * Release the Filter instance associated with this FilterConfig, + * if there is one. + */ + void release() { + + if (this.filter != null){ + if (System.getSecurityManager() != null) { + try { + SecurityUtil.doAsPrivilege("destroy", filter); + } catch(java.lang.Exception ex){ + context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); + } + SecurityUtil.remove(filter); + } else { + filter.destroy(); + } + if (!context.getIgnoreAnnotations()) { + try { + AnnotationProcessor.preDestroy(this.filter); + } catch (Exception e) { + context.getLogger().error("ApplicationFilterConfig.preDestroy", e); + } + } + } + this.filter = null; + + } + + + /** + * Set the filter definition we are configured for. This has the side + * effect of instantiating an instance of the corresponding filter class. + * + * @param filterDef The new filter definition + * + * @exception ClassCastException if the specified class does not implement + * the javax.servlet.Filter interface + * @exception ClassNotFoundException if the filter class cannot be found + * @exception IllegalAccessException if the filter class cannot be + * publicly instantiated + * @exception InstantiationException if an exception occurs while + * instantiating the filter object + * @exception ServletException if thrown by the filter's init() method + * @throws NamingException + * @throws InvocationTargetException + */ + void setFilterDef(FilterDef filterDef) + throws ClassCastException, ClassNotFoundException, + IllegalAccessException, InstantiationException, + ServletException, InvocationTargetException, NamingException { + + this.filterDef = filterDef; + if (filterDef == null) { + + // Release any previously allocated filter instance + if (this.filter != null){ + if( System.getSecurityManager() != null) { + try{ + SecurityUtil.doAsPrivilege("destroy", filter); + } catch(java.lang.Exception ex){ + context.getLogger().error("ApplicationFilterConfig.doAsPrivilege", ex); + } + SecurityUtil.remove(filter); + } else { + filter.destroy(); + } + if (!context.getIgnoreAnnotations()) { + try { + AnnotationProcessor.preDestroy(this.filter); + } catch (Exception e) { + context.getLogger().error("ApplicationFilterConfig.preDestroy", e); + } + } + } + this.filter = null; + + } else { + + // Allocate a new filter instance + Filter filter = getFilter(); + + } + + } + + + // -------------------------------------------------------- Private Methods + + +} diff --git a/java/org/apache/catalina/core/ApplicationFilterFactory.java b/java/org/apache/catalina/core/ApplicationFilterFactory.java index bbe23f035..630f0e136 100644 --- a/java/org/apache/catalina/core/ApplicationFilterFactory.java +++ b/java/org/apache/catalina/core/ApplicationFilterFactory.java @@ -1,369 +1,369 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import javax.servlet.Servlet; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; - -import org.apache.catalina.Globals; -import org.apache.catalina.Wrapper; -import org.apache.catalina.connector.Request; -import org.apache.catalina.deploy.FilterMap; - -/** - * Factory for the creation and caching of Filters and creationg - * of Filter Chains. - * - * @author Greg Murray - * @author Remy Maucherat - * @version $Revision: 1.0 - */ - -public final class ApplicationFilterFactory { - - - // -------------------------------------------------------------- Constants - - - public static final int ERROR = 1; - public static final Integer ERROR_INTEGER = new Integer(ERROR); - public static final int FORWARD = 2; - public static final Integer FORWARD_INTEGER = new Integer(FORWARD); - public static final int INCLUDE = 4; - public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE); - public static final int REQUEST = 8; - public static final Integer REQUEST_INTEGER = new Integer(REQUEST); - - public static final String DISPATCHER_TYPE_ATTR = - Globals.DISPATCHER_TYPE_ATTR; - public static final String DISPATCHER_REQUEST_PATH_ATTR = - Globals.DISPATCHER_REQUEST_PATH_ATTR; - - private static final SecurityManager securityManager = - System.getSecurityManager(); - - private static ApplicationFilterFactory factory = null;; - - - // ----------------------------------------------------------- Constructors - - - /* - * Prevent instanciation outside of the getInstanceMethod(). - */ - private ApplicationFilterFactory() { - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the fqctory instance. - */ - public static ApplicationFilterFactory getInstance() { - if (factory == null) { - factory = new ApplicationFilterFactory(); - } - return factory; - } - - - /** - * Construct and return a FilterChain implementation that will wrap the - * execution of the specified servlet instance. If we should not execute - * a filter chain at all, return null. - * - * @param request The servlet request we are processing - * @param servlet The servlet instance to be wrapped - */ - public ApplicationFilterChain createFilterChain - (ServletRequest request, Wrapper wrapper, Servlet servlet) { - - // get the dispatcher type - int dispatcher = -1; - if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) { - Integer dispatcherInt = - (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR); - dispatcher = dispatcherInt.intValue(); - } - String requestPath = null; - Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR); - - if (attribute != null){ - requestPath = attribute.toString(); - } - - HttpServletRequest hreq = null; - if (request instanceof HttpServletRequest) - hreq = (HttpServletRequest)request; - // If there is no servlet to execute, return null - if (servlet == null) - return (null); - - // Create and initialize a filter chain object - ApplicationFilterChain filterChain = null; - if ((securityManager == null) && (request instanceof Request)) { - Request req = (Request) request; - filterChain = (ApplicationFilterChain) req.getFilterChain(); - if (filterChain == null) { - filterChain = new ApplicationFilterChain(); - req.setFilterChain(filterChain); - } - } else { - // Security: Do not recycle - filterChain = new ApplicationFilterChain(); - } - - filterChain.setServlet(servlet); - - filterChain.setSupport - (((StandardWrapper)wrapper).getInstanceSupport()); - - // Acquire the filter mappings for this Context - StandardContext context = (StandardContext) wrapper.getParent(); - FilterMap filterMaps[] = context.findFilterMaps(); - - // If there are no filter mappings, we are done - if ((filterMaps == null) || (filterMaps.length == 0)) - return (filterChain); - - // Acquire the information we will need to match filter mappings - String servletName = wrapper.getName(); - - int n = 0; - - // Add the relevant path-mapped filters to this filter chain - for (int i = 0; i < filterMaps.length; i++) { - if (!matchDispatcher(filterMaps[i] ,dispatcher)) { - continue; - } - if (!matchFiltersURL(filterMaps[i], requestPath)) - continue; - ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) - context.findFilterConfig(filterMaps[i].getFilterName()); - if (filterConfig == null) { - ; // FIXME - log configuration problem - continue; - } - filterChain.addFilter(filterConfig); - n++; - } - - // Add filters that match on servlet name second - for (int i = 0; i < filterMaps.length; i++) { - if (!matchDispatcher(filterMaps[i] ,dispatcher)) { - continue; - } - if (!matchFiltersServlet(filterMaps[i], servletName)) - continue; - ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) - context.findFilterConfig(filterMaps[i].getFilterName()); - if (filterConfig == null) { - ; // FIXME - log configuration problem - continue; - } - filterChain.addFilter(filterConfig); - n++; - } - - // Return the completed filter chain - return (filterChain); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Return true if the context-relative request path - * matches the requirements of the specified filter mapping; - * otherwise, return false. - * - * @param filterMap Filter mapping being checked - * @param requestPath Context-relative request path of this request - */ - private boolean matchFiltersURL(FilterMap filterMap, String requestPath) { - - // Check the specific "*" special URL pattern, which also matches - // named dispatches - if (filterMap.getAllMatch()) - return (true); - - if (requestPath == null) - return (false); - - // Match on context relative request path - String[] testPaths = filterMap.getURLPatterns(); - - for (int i = 0; i < testPaths.length; i++) { - if (matchFiltersURL(testPaths[i], requestPath)) { - return (true); - } - } - - // No match - return (false); - - } - - - /** - * Return true if the context-relative request path - * matches the requirements of the specified filter mapping; - * otherwise, return false. - * - * @param testPath URL mapping being checked - * @param requestPath Context-relative request path of this request - */ - private boolean matchFiltersURL(String testPath, String requestPath) { - - if (testPath == null) - return (false); - - // Case 1 - Exact Match - if (testPath.equals(requestPath)) - return (true); - - // Case 2 - Path Match ("/.../*") - if (testPath.equals("/*")) - return (true); - if (testPath.endsWith("/*")) { - if (testPath.regionMatches(0, requestPath, 0, - testPath.length() - 2)) { - if (requestPath.length() == (testPath.length() - 2)) { - return (true); - } else if ('/' == requestPath.charAt(testPath.length() - 2)) { - return (true); - } - } - return (false); - } - - // Case 3 - Extension Match - if (testPath.startsWith("*.")) { - int slash = requestPath.lastIndexOf('/'); - int period = requestPath.lastIndexOf('.'); - if ((slash >= 0) && (period > slash) - && (period != requestPath.length() - 1) - && ((requestPath.length() - period) - == (testPath.length() - 1))) { - return (testPath.regionMatches(2, requestPath, period + 1, - testPath.length() - 2)); - } - } - - // Case 4 - "Default" Match - return (false); // NOTE - Not relevant for selecting filters - - } - - - /** - * Return true if the specified servlet name matches - * the requirements of the specified filter mapping; otherwise - * return false. - * - * @param filterMap Filter mapping being checked - * @param servletName Servlet name being checked - */ - private boolean matchFiltersServlet(FilterMap filterMap, - String servletName) { - - if (servletName == null) { - return (false); - } else { - String[] servletNames = filterMap.getServletNames(); - for (int i = 0; i < servletNames.length; i++) { - if (servletName.equals(servletNames[i])) { - return (true); - } - } - return false; - } - - } - - - /** - * Convienience method which returns true if the dispatcher type - * matches the dispatcher types specified in the FilterMap - */ - private boolean matchDispatcher(FilterMap filterMap, int dispatcher) { - switch (dispatcher) { - case FORWARD : { - if (filterMap.getDispatcherMapping() == FilterMap.FORWARD || - filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { - return true; - } - break; - } - case INCLUDE : { - if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { - return true; - } - break; - } - case REQUEST : { - if (filterMap.getDispatcherMapping() == FilterMap.REQUEST || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) { - return true; - } - break; - } - case ERROR : { - if (filterMap.getDispatcherMapping() == FilterMap.ERROR || - filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || - filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || - filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) { - return true; - } - break; - } - } - return false; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import javax.servlet.Servlet; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import org.apache.catalina.Globals; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Request; +import org.apache.catalina.deploy.FilterMap; + +/** + * Factory for the creation and caching of Filters and creationg + * of Filter Chains. + * + * @author Greg Murray + * @author Remy Maucherat + * @version $Revision: 1.0 + */ + +public final class ApplicationFilterFactory { + + + // -------------------------------------------------------------- Constants + + + public static final int ERROR = 1; + public static final Integer ERROR_INTEGER = new Integer(ERROR); + public static final int FORWARD = 2; + public static final Integer FORWARD_INTEGER = new Integer(FORWARD); + public static final int INCLUDE = 4; + public static final Integer INCLUDE_INTEGER = new Integer(INCLUDE); + public static final int REQUEST = 8; + public static final Integer REQUEST_INTEGER = new Integer(REQUEST); + + public static final String DISPATCHER_TYPE_ATTR = + Globals.DISPATCHER_TYPE_ATTR; + public static final String DISPATCHER_REQUEST_PATH_ATTR = + Globals.DISPATCHER_REQUEST_PATH_ATTR; + + private static final SecurityManager securityManager = + System.getSecurityManager(); + + private static ApplicationFilterFactory factory = null;; + + + // ----------------------------------------------------------- Constructors + + + /* + * Prevent instanciation outside of the getInstanceMethod(). + */ + private ApplicationFilterFactory() { + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the fqctory instance. + */ + public static ApplicationFilterFactory getInstance() { + if (factory == null) { + factory = new ApplicationFilterFactory(); + } + return factory; + } + + + /** + * Construct and return a FilterChain implementation that will wrap the + * execution of the specified servlet instance. If we should not execute + * a filter chain at all, return null. + * + * @param request The servlet request we are processing + * @param servlet The servlet instance to be wrapped + */ + public ApplicationFilterChain createFilterChain + (ServletRequest request, Wrapper wrapper, Servlet servlet) { + + // get the dispatcher type + int dispatcher = -1; + if (request.getAttribute(DISPATCHER_TYPE_ATTR) != null) { + Integer dispatcherInt = + (Integer) request.getAttribute(DISPATCHER_TYPE_ATTR); + dispatcher = dispatcherInt.intValue(); + } + String requestPath = null; + Object attribute = request.getAttribute(DISPATCHER_REQUEST_PATH_ATTR); + + if (attribute != null){ + requestPath = attribute.toString(); + } + + HttpServletRequest hreq = null; + if (request instanceof HttpServletRequest) + hreq = (HttpServletRequest)request; + // If there is no servlet to execute, return null + if (servlet == null) + return (null); + + // Create and initialize a filter chain object + ApplicationFilterChain filterChain = null; + if ((securityManager == null) && (request instanceof Request)) { + Request req = (Request) request; + filterChain = (ApplicationFilterChain) req.getFilterChain(); + if (filterChain == null) { + filterChain = new ApplicationFilterChain(); + req.setFilterChain(filterChain); + } + } else { + // Security: Do not recycle + filterChain = new ApplicationFilterChain(); + } + + filterChain.setServlet(servlet); + + filterChain.setSupport + (((StandardWrapper)wrapper).getInstanceSupport()); + + // Acquire the filter mappings for this Context + StandardContext context = (StandardContext) wrapper.getParent(); + FilterMap filterMaps[] = context.findFilterMaps(); + + // If there are no filter mappings, we are done + if ((filterMaps == null) || (filterMaps.length == 0)) + return (filterChain); + + // Acquire the information we will need to match filter mappings + String servletName = wrapper.getName(); + + int n = 0; + + // Add the relevant path-mapped filters to this filter chain + for (int i = 0; i < filterMaps.length; i++) { + if (!matchDispatcher(filterMaps[i] ,dispatcher)) { + continue; + } + if (!matchFiltersURL(filterMaps[i], requestPath)) + continue; + ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) + context.findFilterConfig(filterMaps[i].getFilterName()); + if (filterConfig == null) { + ; // FIXME - log configuration problem + continue; + } + filterChain.addFilter(filterConfig); + n++; + } + + // Add filters that match on servlet name second + for (int i = 0; i < filterMaps.length; i++) { + if (!matchDispatcher(filterMaps[i] ,dispatcher)) { + continue; + } + if (!matchFiltersServlet(filterMaps[i], servletName)) + continue; + ApplicationFilterConfig filterConfig = (ApplicationFilterConfig) + context.findFilterConfig(filterMaps[i].getFilterName()); + if (filterConfig == null) { + ; // FIXME - log configuration problem + continue; + } + filterChain.addFilter(filterConfig); + n++; + } + + // Return the completed filter chain + return (filterChain); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Return true if the context-relative request path + * matches the requirements of the specified filter mapping; + * otherwise, return false. + * + * @param filterMap Filter mapping being checked + * @param requestPath Context-relative request path of this request + */ + private boolean matchFiltersURL(FilterMap filterMap, String requestPath) { + + // Check the specific "*" special URL pattern, which also matches + // named dispatches + if (filterMap.getAllMatch()) + return (true); + + if (requestPath == null) + return (false); + + // Match on context relative request path + String[] testPaths = filterMap.getURLPatterns(); + + for (int i = 0; i < testPaths.length; i++) { + if (matchFiltersURL(testPaths[i], requestPath)) { + return (true); + } + } + + // No match + return (false); + + } + + + /** + * Return true if the context-relative request path + * matches the requirements of the specified filter mapping; + * otherwise, return false. + * + * @param testPath URL mapping being checked + * @param requestPath Context-relative request path of this request + */ + private boolean matchFiltersURL(String testPath, String requestPath) { + + if (testPath == null) + return (false); + + // Case 1 - Exact Match + if (testPath.equals(requestPath)) + return (true); + + // Case 2 - Path Match ("/.../*") + if (testPath.equals("/*")) + return (true); + if (testPath.endsWith("/*")) { + if (testPath.regionMatches(0, requestPath, 0, + testPath.length() - 2)) { + if (requestPath.length() == (testPath.length() - 2)) { + return (true); + } else if ('/' == requestPath.charAt(testPath.length() - 2)) { + return (true); + } + } + return (false); + } + + // Case 3 - Extension Match + if (testPath.startsWith("*.")) { + int slash = requestPath.lastIndexOf('/'); + int period = requestPath.lastIndexOf('.'); + if ((slash >= 0) && (period > slash) + && (period != requestPath.length() - 1) + && ((requestPath.length() - period) + == (testPath.length() - 1))) { + return (testPath.regionMatches(2, requestPath, period + 1, + testPath.length() - 2)); + } + } + + // Case 4 - "Default" Match + return (false); // NOTE - Not relevant for selecting filters + + } + + + /** + * Return true if the specified servlet name matches + * the requirements of the specified filter mapping; otherwise + * return false. + * + * @param filterMap Filter mapping being checked + * @param servletName Servlet name being checked + */ + private boolean matchFiltersServlet(FilterMap filterMap, + String servletName) { + + if (servletName == null) { + return (false); + } else { + String[] servletNames = filterMap.getServletNames(); + for (int i = 0; i < servletNames.length; i++) { + if (servletName.equals(servletNames[i])) { + return (true); + } + } + return false; + } + + } + + + /** + * Convienience method which returns true if the dispatcher type + * matches the dispatcher types specified in the FilterMap + */ + private boolean matchDispatcher(FilterMap filterMap, int dispatcher) { + switch (dispatcher) { + case FORWARD : { + if (filterMap.getDispatcherMapping() == FilterMap.FORWARD || + filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { + return true; + } + break; + } + case INCLUDE : { + if (filterMap.getDispatcherMapping() == FilterMap.INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE) { + return true; + } + break; + } + case REQUEST : { + if (filterMap.getDispatcherMapping() == FilterMap.REQUEST || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE) { + return true; + } + break; + } + case ERROR : { + if (filterMap.getDispatcherMapping() == FilterMap.ERROR || + filterMap.getDispatcherMapping() == FilterMap.FORWARD_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR || + filterMap.getDispatcherMapping() == FilterMap.INCLUDE_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_FORWARD_INCLUDE || + filterMap.getDispatcherMapping() == FilterMap.REQUEST_ERROR_INCLUDE) { + return true; + } + break; + } + } + return false; + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationHttpRequest.java b/java/org/apache/catalina/core/ApplicationHttpRequest.java index 58c6a4284..3ef5e5953 100644 --- a/java/org/apache/catalina/core/ApplicationHttpRequest.java +++ b/java/org/apache/catalina/core/ApplicationHttpRequest.java @@ -1,950 +1,950 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; - -import javax.servlet.RequestDispatcher; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Session; -import org.apache.catalina.Manager; -import org.apache.catalina.util.Enumerator; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.StringManager; - - -/** - * Wrapper around a javax.servlet.http.HttpServletRequest - * that transforms an application request object (which might be the original - * one passed to a servlet, or might be based on the 2.3 - * javax.servlet.http.HttpServletRequestWrapper class) - * back into an internal org.apache.catalina.HttpRequest. - *

    - * WARNING: Due to Java's lack of support for multiple - * inheritance, all of the logic in ApplicationRequest is - * duplicated in ApplicationHttpRequest. Make sure that you - * keep these two classes in synchronization when making changes! - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303799 $ $Date: 2005-03-25 09:41:23 +0100 (ven., 25 mars 2005) $ - */ - -class ApplicationHttpRequest extends HttpServletRequestWrapper { - - - // ------------------------------------------------------- Static Variables - - - /** - * The set of attribute names that are special for request dispatchers. - */ - protected static final String specials[] = - { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR, - Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR, - Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, - Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, - Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR }; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new wrapped request around the specified servlet request. - * - * @param request The servlet request being wrapped - */ - public ApplicationHttpRequest(HttpServletRequest request, Context context, - boolean crossContext) { - - super(request); - this.context = context; - this.crossContext = crossContext; - setRequest(request); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The context for this request. - */ - protected Context context = null; - - - /** - * The context path for this request. - */ - protected String contextPath = null; - - - /** - * If this request is cross context, since this changes session accesss - * behavior. - */ - protected boolean crossContext = false; - - - /** - * The current dispatcher type. - */ - protected Object dispatcherType = null; - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.core.ApplicationHttpRequest/1.0"; - - - /** - * The request parameters for this request. This is initialized from the - * wrapped request, but updates are allowed. - */ - protected Map parameters = null; - - - /** - * Have the parameters for this request already been parsed? - */ - private boolean parsedParams = false; - - - /** - * The path information for this request. - */ - protected String pathInfo = null; - - - /** - * The query parameters for the current request. - */ - private String queryParamString = null; - - - /** - * The query string for this request. - */ - protected String queryString = null; - - - /** - * The current request dispatcher path. - */ - protected Object requestDispatcherPath = null; - - - /** - * The request URI for this request. - */ - protected String requestURI = null; - - - /** - * The servlet path for this request. - */ - protected String servletPath = null; - - - /** - * The currently active session for this request. - */ - protected Session session = null; - - - /** - * Special attributes. - */ - protected Object[] specialAttributes = new Object[specials.length]; - - - // ------------------------------------------------- ServletRequest Methods - - - /** - * Override the getAttribute() method of the wrapped request. - * - * @param name Name of the attribute to retrieve - */ - public Object getAttribute(String name) { - - if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { - return dispatcherType; - } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { - if ( requestDispatcherPath != null ){ - return requestDispatcherPath.toString(); - } else { - return null; - } - } - - int pos = getSpecial(name); - if (pos == -1) { - return getRequest().getAttribute(name); - } else { - if ((specialAttributes[pos] == null) - && (specialAttributes[5] == null) && (pos >= 5)) { - // If it's a forward special attribute, and null, it means this - // is an include, so we check the wrapped request since - // the request could have been forwarded before the include - return getRequest().getAttribute(name); - } else { - return specialAttributes[pos]; - } - } - - } - - - /** - * Override the getAttributeNames() method of the wrapped - * request. - */ - public Enumeration getAttributeNames() { - return (new AttributeNamesEnumerator()); - } - - - /** - * Override the removeAttribute() method of the - * wrapped request. - * - * @param name Name of the attribute to remove - */ - public void removeAttribute(String name) { - - if (!removeSpecial(name)) - getRequest().removeAttribute(name); - - } - - - /** - * Override the setAttribute() method of the - * wrapped request. - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set - */ - public void setAttribute(String name, Object value) { - - if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { - dispatcherType = value; - return; - } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { - requestDispatcherPath = value; - return; - } - - if (!setSpecial(name, value)) { - getRequest().setAttribute(name, value); - } - - } - - - /** - * Return a RequestDispatcher that wraps the resource at the specified - * path, which may be interpreted as relative to the current request path. - * - * @param path Path of the resource to be wrapped - */ - public RequestDispatcher getRequestDispatcher(String path) { - - if (context == null) - return (null); - - // If the path is already context-relative, just pass it through - if (path == null) - return (null); - else if (path.startsWith("/")) - return (context.getServletContext().getRequestDispatcher(path)); - - // Convert a request-relative path to a context-relative one - String servletPath = - (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); - if (servletPath == null) - servletPath = getServletPath(); - - // Add the path info, if there is any - String pathInfo = getPathInfo(); - String requestPath = null; - - if (pathInfo == null) { - requestPath = servletPath; - } else { - requestPath = servletPath + pathInfo; - } - - int pos = requestPath.lastIndexOf('/'); - String relative = null; - if (pos >= 0) { - relative = RequestUtil.normalize - (requestPath.substring(0, pos + 1) + path); - } else { - relative = RequestUtil.normalize(requestPath + path); - } - - return (context.getServletContext().getRequestDispatcher(relative)); - - } - - - // --------------------------------------------- HttpServletRequest Methods - - - /** - * Override the getContextPath() method of the wrapped - * request. - */ - public String getContextPath() { - - return (this.contextPath); - - } - - - /** - * Override the getParameter() method of the wrapped request. - * - * @param name Name of the requested parameter - */ - public String getParameter(String name) { - - parseParameters(); - - Object value = parameters.get(name); - if (value == null) - return (null); - else if (value instanceof String[]) - return (((String[]) value)[0]); - else if (value instanceof String) - return ((String) value); - else - return (value.toString()); - - } - - - /** - * Override the getParameterMap() method of the - * wrapped request. - */ - public Map getParameterMap() { - - parseParameters(); - return (parameters); - - } - - - /** - * Override the getParameterNames() method of the - * wrapped request. - */ - public Enumeration getParameterNames() { - - parseParameters(); - return (new Enumerator(parameters.keySet())); - - } - - - /** - * Override the getParameterValues() method of the - * wrapped request. - * - * @param name Name of the requested parameter - */ - public String[] getParameterValues(String name) { - - parseParameters(); - Object value = parameters.get(name); - if (value == null) - return ((String[]) null); - else if (value instanceof String[]) - return ((String[]) value); - else if (value instanceof String) { - String values[] = new String[1]; - values[0] = (String) value; - return (values); - } else { - String values[] = new String[1]; - values[0] = value.toString(); - return (values); - } - - } - - - /** - * Override the getPathInfo() method of the wrapped request. - */ - public String getPathInfo() { - - return (this.pathInfo); - - } - - - /** - * Override the getQueryString() method of the wrapped - * request. - */ - public String getQueryString() { - - return (this.queryString); - - } - - - /** - * Override the getRequestURI() method of the wrapped - * request. - */ - public String getRequestURI() { - - return (this.requestURI); - - } - - - /** - * Override the getRequestURL() method of the wrapped - * request. - */ - public StringBuffer getRequestURL() { - - StringBuffer url = new StringBuffer(); - String scheme = getScheme(); - int port = getServerPort(); - if (port < 0) - port = 80; // Work around java.net.URL bug - - url.append(scheme); - url.append("://"); - url.append(getServerName()); - if ((scheme.equals("http") && (port != 80)) - || (scheme.equals("https") && (port != 443))) { - url.append(':'); - url.append(port); - } - url.append(getRequestURI()); - - return (url); - - } - - - /** - * Override the getServletPath() method of the wrapped - * request. - */ - public String getServletPath() { - - return (this.servletPath); - - } - - - /** - * Return the session associated with this Request, creating one - * if necessary. - */ - public HttpSession getSession() { - return (getSession(true)); - } - - - /** - * Return the session associated with this Request, creating one - * if necessary and requested. - * - * @param create Create a new session if one does not exist - */ - public HttpSession getSession(boolean create) { - - if (crossContext) { - - // There cannot be a session if no context has been assigned yet - if (context == null) - return (null); - - // Return the current session if it exists and is valid - if (session != null && session.isValid()) { - return (session.getSession()); - } - - HttpSession other = super.getSession(false); - if (create && (other == null)) { - // First create a session in the first context: the problem is - // that the top level request is the only one which can - // create the cookie safely - other = super.getSession(true); - } - if (other != null) { - Session localSession = null; - try { - localSession = - context.getManager().findSession(other.getId()); - } catch (IOException e) { - // Ignore - } - if (localSession == null && create) { - localSession = - context.getManager().createSession(other.getId()); - } - if (localSession != null) { - localSession.access(); - session = localSession; - return session.getSession(); - } - } - return null; - - } else { - return super.getSession(create); - } - - } - - - /** - * Returns true if the request specifies a JSESSIONID that is valid within - * the context of this ApplicationHttpRequest, false otherwise. - * - * @return true if the request specifies a JSESSIONID that is valid within - * the context of this ApplicationHttpRequest, false otherwise. - */ - public boolean isRequestedSessionIdValid() { - - if (crossContext) { - - String requestedSessionId = getRequestedSessionId(); - if (requestedSessionId == null) - return (false); - if (context == null) - return (false); - Manager manager = context.getManager(); - if (manager == null) - return (false); - Session session = null; - try { - session = manager.findSession(requestedSessionId); - } catch (IOException e) { - session = null; - } - if ((session != null) && session.isValid()) { - return (true); - } else { - return (false); - } - - } else { - return super.isRequestedSessionIdValid(); - } - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Recycle this request - */ - public void recycle() { - if (session != null) { - session.endAccess(); - } - } - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Perform a shallow copy of the specified Map, and return the result. - * - * @param orig Origin Map to be copied - */ - Map copyMap(Map orig) { - - if (orig == null) - return (new HashMap()); - HashMap dest = new HashMap(); - Iterator keys = orig.keySet().iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - dest.put(key, orig.get(key)); - } - return (dest); - - } - - - /** - * Set the context path for this request. - * - * @param contextPath The new context path - */ - void setContextPath(String contextPath) { - - this.contextPath = contextPath; - - } - - - /** - * Set the path information for this request. - * - * @param pathInfo The new path info - */ - void setPathInfo(String pathInfo) { - - this.pathInfo = pathInfo; - - } - - - /** - * Set the query string for this request. - * - * @param queryString The new query string - */ - void setQueryString(String queryString) { - - this.queryString = queryString; - - } - - - /** - * Set the request that we are wrapping. - * - * @param request The new wrapped request - */ - void setRequest(HttpServletRequest request) { - - super.setRequest(request); - - // Initialize the attributes for this request - dispatcherType = request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); - requestDispatcherPath = - request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); - - // Initialize the path elements for this request - contextPath = request.getContextPath(); - pathInfo = request.getPathInfo(); - queryString = request.getQueryString(); - requestURI = request.getRequestURI(); - servletPath = request.getServletPath(); - - } - - - /** - * Set the request URI for this request. - * - * @param requestURI The new request URI - */ - void setRequestURI(String requestURI) { - - this.requestURI = requestURI; - - } - - - /** - * Set the servlet path for this request. - * - * @param servletPath The new servlet path - */ - void setServletPath(String servletPath) { - - this.servletPath = servletPath; - - } - - - /** - * Parses the parameters of this request. - * - * If parameters are present in both the query string and the request - * content, they are merged. - */ - void parseParameters() { - - if (parsedParams) { - return; - } - - parameters = new HashMap(); - parameters = copyMap(getRequest().getParameterMap()); - mergeParameters(); - parsedParams = true; - } - - - /** - * Save query parameters for this request. - * - * @param queryString The query string containing parameters for this - * request - */ - void setQueryParams(String queryString) { - this.queryParamString = queryString; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Is this attribute name one of the special ones that is added only for - * included servlets? - * - * @param name Attribute name to be tested - */ - protected boolean isSpecial(String name) { - - for (int i = 0; i < specials.length; i++) { - if (specials[i].equals(name)) - return (true); - } - return (false); - - } - - - /** - * Get a special attribute. - * - * @return the special attribute pos, or -1 if it is not a special - * attribute - */ - protected int getSpecial(String name) { - for (int i = 0; i < specials.length; i++) { - if (specials[i].equals(name)) { - return (i); - } - } - return (-1); - } - - - /** - * Set a special attribute. - * - * @return true if the attribute was a special attribute, false otherwise - */ - protected boolean setSpecial(String name, Object value) { - for (int i = 0; i < specials.length; i++) { - if (specials[i].equals(name)) { - specialAttributes[i] = value; - return (true); - } - } - return (false); - } - - - /** - * Remove a special attribute. - * - * @return true if the attribute was a special attribute, false otherwise - */ - protected boolean removeSpecial(String name) { - for (int i = 0; i < specials.length; i++) { - if (specials[i].equals(name)) { - specialAttributes[i] = null; - return (true); - } - } - return (false); - } - - - /** - * Merge the two sets of parameter values into a single String array. - * - * @param values1 First set of values - * @param values2 Second set of values - */ - protected String[] mergeValues(Object values1, Object values2) { - - ArrayList results = new ArrayList(); - - if (values1 == null) - ; - else if (values1 instanceof String) - results.add(values1); - else if (values1 instanceof String[]) { - String values[] = (String[]) values1; - for (int i = 0; i < values.length; i++) - results.add(values[i]); - } else - results.add(values1.toString()); - - if (values2 == null) - ; - else if (values2 instanceof String) - results.add(values2); - else if (values2 instanceof String[]) { - String values[] = (String[]) values2; - for (int i = 0; i < values.length; i++) - results.add(values[i]); - } else - results.add(values2.toString()); - - String values[] = new String[results.size()]; - return ((String[]) results.toArray(values)); - - } - - - // ------------------------------------------------------ Private Methods - - - /** - * Merge the parameters from the saved query parameter string (if any), and - * the parameters already present on this request (if any), such that the - * parameter values from the query string show up first if there are - * duplicate parameter names. - */ - private void mergeParameters() { - - if ((queryParamString == null) || (queryParamString.length() < 1)) - return; - - HashMap queryParameters = new HashMap(); - String encoding = getCharacterEncoding(); - if (encoding == null) - encoding = "ISO-8859-1"; - try { - RequestUtil.parseParameters - (queryParameters, queryParamString, encoding); - } catch (Exception e) { - ; - } - Iterator keys = parameters.keySet().iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - Object value = queryParameters.get(key); - if (value == null) { - queryParameters.put(key, parameters.get(key)); - continue; - } - queryParameters.put - (key, mergeValues(value, parameters.get(key))); - } - parameters = queryParameters; - - } - - - // ----------------------------------- AttributeNamesEnumerator Inner Class - - - /** - * Utility class used to expose the special attributes as being available - * as request attributes. - */ - protected class AttributeNamesEnumerator implements Enumeration { - - protected int pos = -1; - protected int last = -1; - protected Enumeration parentEnumeration = null; - protected String next = null; - - public AttributeNamesEnumerator() { - parentEnumeration = getRequest().getAttributeNames(); - for (int i = 0; i < specialAttributes.length; i++) { - if (getAttribute(specials[i]) != null) { - last = i; - } - } - } - - public boolean hasMoreElements() { - return ((pos != last) || (next != null) - || ((next = findNext()) != null)); - } - - public Object nextElement() { - if (pos != last) { - for (int i = pos + 1; i <= last; i++) { - if (getAttribute(specials[i]) != null) { - pos = i; - return (specials[i]); - } - } - } - String result = next; - if (next != null) { - next = findNext(); - } else { - throw new NoSuchElementException(); - } - return result; - } - - protected String findNext() { - String result = null; - while ((result == null) && (parentEnumeration.hasMoreElements())) { - String current = (String) parentEnumeration.nextElement(); - if (!isSpecial(current)) { - result = current; - } - } - return result; - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Session; +import org.apache.catalina.Manager; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.StringManager; + + +/** + * Wrapper around a javax.servlet.http.HttpServletRequest + * that transforms an application request object (which might be the original + * one passed to a servlet, or might be based on the 2.3 + * javax.servlet.http.HttpServletRequestWrapper class) + * back into an internal org.apache.catalina.HttpRequest. + *

    + * WARNING: Due to Java's lack of support for multiple + * inheritance, all of the logic in ApplicationRequest is + * duplicated in ApplicationHttpRequest. Make sure that you + * keep these two classes in synchronization when making changes! + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303799 $ $Date: 2005-03-25 09:41:23 +0100 (ven., 25 mars 2005) $ + */ + +class ApplicationHttpRequest extends HttpServletRequestWrapper { + + + // ------------------------------------------------------- Static Variables + + + /** + * The set of attribute names that are special for request dispatchers. + */ + protected static final String specials[] = + { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR, + Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR, + Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, + Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, + Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR }; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new wrapped request around the specified servlet request. + * + * @param request The servlet request being wrapped + */ + public ApplicationHttpRequest(HttpServletRequest request, Context context, + boolean crossContext) { + + super(request); + this.context = context; + this.crossContext = crossContext; + setRequest(request); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The context for this request. + */ + protected Context context = null; + + + /** + * The context path for this request. + */ + protected String contextPath = null; + + + /** + * If this request is cross context, since this changes session accesss + * behavior. + */ + protected boolean crossContext = false; + + + /** + * The current dispatcher type. + */ + protected Object dispatcherType = null; + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.core.ApplicationHttpRequest/1.0"; + + + /** + * The request parameters for this request. This is initialized from the + * wrapped request, but updates are allowed. + */ + protected Map parameters = null; + + + /** + * Have the parameters for this request already been parsed? + */ + private boolean parsedParams = false; + + + /** + * The path information for this request. + */ + protected String pathInfo = null; + + + /** + * The query parameters for the current request. + */ + private String queryParamString = null; + + + /** + * The query string for this request. + */ + protected String queryString = null; + + + /** + * The current request dispatcher path. + */ + protected Object requestDispatcherPath = null; + + + /** + * The request URI for this request. + */ + protected String requestURI = null; + + + /** + * The servlet path for this request. + */ + protected String servletPath = null; + + + /** + * The currently active session for this request. + */ + protected Session session = null; + + + /** + * Special attributes. + */ + protected Object[] specialAttributes = new Object[specials.length]; + + + // ------------------------------------------------- ServletRequest Methods + + + /** + * Override the getAttribute() method of the wrapped request. + * + * @param name Name of the attribute to retrieve + */ + public Object getAttribute(String name) { + + if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { + return dispatcherType; + } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { + if ( requestDispatcherPath != null ){ + return requestDispatcherPath.toString(); + } else { + return null; + } + } + + int pos = getSpecial(name); + if (pos == -1) { + return getRequest().getAttribute(name); + } else { + if ((specialAttributes[pos] == null) + && (specialAttributes[5] == null) && (pos >= 5)) { + // If it's a forward special attribute, and null, it means this + // is an include, so we check the wrapped request since + // the request could have been forwarded before the include + return getRequest().getAttribute(name); + } else { + return specialAttributes[pos]; + } + } + + } + + + /** + * Override the getAttributeNames() method of the wrapped + * request. + */ + public Enumeration getAttributeNames() { + return (new AttributeNamesEnumerator()); + } + + + /** + * Override the removeAttribute() method of the + * wrapped request. + * + * @param name Name of the attribute to remove + */ + public void removeAttribute(String name) { + + if (!removeSpecial(name)) + getRequest().removeAttribute(name); + + } + + + /** + * Override the setAttribute() method of the + * wrapped request. + * + * @param name Name of the attribute to set + * @param value Value of the attribute to set + */ + public void setAttribute(String name, Object value) { + + if (name.equals(Globals.DISPATCHER_TYPE_ATTR)) { + dispatcherType = value; + return; + } else if (name.equals(Globals.DISPATCHER_REQUEST_PATH_ATTR)) { + requestDispatcherPath = value; + return; + } + + if (!setSpecial(name, value)) { + getRequest().setAttribute(name, value); + } + + } + + + /** + * Return a RequestDispatcher that wraps the resource at the specified + * path, which may be interpreted as relative to the current request path. + * + * @param path Path of the resource to be wrapped + */ + public RequestDispatcher getRequestDispatcher(String path) { + + if (context == null) + return (null); + + // If the path is already context-relative, just pass it through + if (path == null) + return (null); + else if (path.startsWith("/")) + return (context.getServletContext().getRequestDispatcher(path)); + + // Convert a request-relative path to a context-relative one + String servletPath = + (String) getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); + if (servletPath == null) + servletPath = getServletPath(); + + // Add the path info, if there is any + String pathInfo = getPathInfo(); + String requestPath = null; + + if (pathInfo == null) { + requestPath = servletPath; + } else { + requestPath = servletPath + pathInfo; + } + + int pos = requestPath.lastIndexOf('/'); + String relative = null; + if (pos >= 0) { + relative = RequestUtil.normalize + (requestPath.substring(0, pos + 1) + path); + } else { + relative = RequestUtil.normalize(requestPath + path); + } + + return (context.getServletContext().getRequestDispatcher(relative)); + + } + + + // --------------------------------------------- HttpServletRequest Methods + + + /** + * Override the getContextPath() method of the wrapped + * request. + */ + public String getContextPath() { + + return (this.contextPath); + + } + + + /** + * Override the getParameter() method of the wrapped request. + * + * @param name Name of the requested parameter + */ + public String getParameter(String name) { + + parseParameters(); + + Object value = parameters.get(name); + if (value == null) + return (null); + else if (value instanceof String[]) + return (((String[]) value)[0]); + else if (value instanceof String) + return ((String) value); + else + return (value.toString()); + + } + + + /** + * Override the getParameterMap() method of the + * wrapped request. + */ + public Map getParameterMap() { + + parseParameters(); + return (parameters); + + } + + + /** + * Override the getParameterNames() method of the + * wrapped request. + */ + public Enumeration getParameterNames() { + + parseParameters(); + return (new Enumerator(parameters.keySet())); + + } + + + /** + * Override the getParameterValues() method of the + * wrapped request. + * + * @param name Name of the requested parameter + */ + public String[] getParameterValues(String name) { + + parseParameters(); + Object value = parameters.get(name); + if (value == null) + return ((String[]) null); + else if (value instanceof String[]) + return ((String[]) value); + else if (value instanceof String) { + String values[] = new String[1]; + values[0] = (String) value; + return (values); + } else { + String values[] = new String[1]; + values[0] = value.toString(); + return (values); + } + + } + + + /** + * Override the getPathInfo() method of the wrapped request. + */ + public String getPathInfo() { + + return (this.pathInfo); + + } + + + /** + * Override the getQueryString() method of the wrapped + * request. + */ + public String getQueryString() { + + return (this.queryString); + + } + + + /** + * Override the getRequestURI() method of the wrapped + * request. + */ + public String getRequestURI() { + + return (this.requestURI); + + } + + + /** + * Override the getRequestURL() method of the wrapped + * request. + */ + public StringBuffer getRequestURL() { + + StringBuffer url = new StringBuffer(); + String scheme = getScheme(); + int port = getServerPort(); + if (port < 0) + port = 80; // Work around java.net.URL bug + + url.append(scheme); + url.append("://"); + url.append(getServerName()); + if ((scheme.equals("http") && (port != 80)) + || (scheme.equals("https") && (port != 443))) { + url.append(':'); + url.append(port); + } + url.append(getRequestURI()); + + return (url); + + } + + + /** + * Override the getServletPath() method of the wrapped + * request. + */ + public String getServletPath() { + + return (this.servletPath); + + } + + + /** + * Return the session associated with this Request, creating one + * if necessary. + */ + public HttpSession getSession() { + return (getSession(true)); + } + + + /** + * Return the session associated with this Request, creating one + * if necessary and requested. + * + * @param create Create a new session if one does not exist + */ + public HttpSession getSession(boolean create) { + + if (crossContext) { + + // There cannot be a session if no context has been assigned yet + if (context == null) + return (null); + + // Return the current session if it exists and is valid + if (session != null && session.isValid()) { + return (session.getSession()); + } + + HttpSession other = super.getSession(false); + if (create && (other == null)) { + // First create a session in the first context: the problem is + // that the top level request is the only one which can + // create the cookie safely + other = super.getSession(true); + } + if (other != null) { + Session localSession = null; + try { + localSession = + context.getManager().findSession(other.getId()); + } catch (IOException e) { + // Ignore + } + if (localSession == null && create) { + localSession = + context.getManager().createSession(other.getId()); + } + if (localSession != null) { + localSession.access(); + session = localSession; + return session.getSession(); + } + } + return null; + + } else { + return super.getSession(create); + } + + } + + + /** + * Returns true if the request specifies a JSESSIONID that is valid within + * the context of this ApplicationHttpRequest, false otherwise. + * + * @return true if the request specifies a JSESSIONID that is valid within + * the context of this ApplicationHttpRequest, false otherwise. + */ + public boolean isRequestedSessionIdValid() { + + if (crossContext) { + + String requestedSessionId = getRequestedSessionId(); + if (requestedSessionId == null) + return (false); + if (context == null) + return (false); + Manager manager = context.getManager(); + if (manager == null) + return (false); + Session session = null; + try { + session = manager.findSession(requestedSessionId); + } catch (IOException e) { + session = null; + } + if ((session != null) && session.isValid()) { + return (true); + } else { + return (false); + } + + } else { + return super.isRequestedSessionIdValid(); + } + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Recycle this request + */ + public void recycle() { + if (session != null) { + session.endAccess(); + } + } + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Perform a shallow copy of the specified Map, and return the result. + * + * @param orig Origin Map to be copied + */ + Map copyMap(Map orig) { + + if (orig == null) + return (new HashMap()); + HashMap dest = new HashMap(); + Iterator keys = orig.keySet().iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + dest.put(key, orig.get(key)); + } + return (dest); + + } + + + /** + * Set the context path for this request. + * + * @param contextPath The new context path + */ + void setContextPath(String contextPath) { + + this.contextPath = contextPath; + + } + + + /** + * Set the path information for this request. + * + * @param pathInfo The new path info + */ + void setPathInfo(String pathInfo) { + + this.pathInfo = pathInfo; + + } + + + /** + * Set the query string for this request. + * + * @param queryString The new query string + */ + void setQueryString(String queryString) { + + this.queryString = queryString; + + } + + + /** + * Set the request that we are wrapping. + * + * @param request The new wrapped request + */ + void setRequest(HttpServletRequest request) { + + super.setRequest(request); + + // Initialize the attributes for this request + dispatcherType = request.getAttribute(Globals.DISPATCHER_TYPE_ATTR); + requestDispatcherPath = + request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR); + + // Initialize the path elements for this request + contextPath = request.getContextPath(); + pathInfo = request.getPathInfo(); + queryString = request.getQueryString(); + requestURI = request.getRequestURI(); + servletPath = request.getServletPath(); + + } + + + /** + * Set the request URI for this request. + * + * @param requestURI The new request URI + */ + void setRequestURI(String requestURI) { + + this.requestURI = requestURI; + + } + + + /** + * Set the servlet path for this request. + * + * @param servletPath The new servlet path + */ + void setServletPath(String servletPath) { + + this.servletPath = servletPath; + + } + + + /** + * Parses the parameters of this request. + * + * If parameters are present in both the query string and the request + * content, they are merged. + */ + void parseParameters() { + + if (parsedParams) { + return; + } + + parameters = new HashMap(); + parameters = copyMap(getRequest().getParameterMap()); + mergeParameters(); + parsedParams = true; + } + + + /** + * Save query parameters for this request. + * + * @param queryString The query string containing parameters for this + * request + */ + void setQueryParams(String queryString) { + this.queryParamString = queryString; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Is this attribute name one of the special ones that is added only for + * included servlets? + * + * @param name Attribute name to be tested + */ + protected boolean isSpecial(String name) { + + for (int i = 0; i < specials.length; i++) { + if (specials[i].equals(name)) + return (true); + } + return (false); + + } + + + /** + * Get a special attribute. + * + * @return the special attribute pos, or -1 if it is not a special + * attribute + */ + protected int getSpecial(String name) { + for (int i = 0; i < specials.length; i++) { + if (specials[i].equals(name)) { + return (i); + } + } + return (-1); + } + + + /** + * Set a special attribute. + * + * @return true if the attribute was a special attribute, false otherwise + */ + protected boolean setSpecial(String name, Object value) { + for (int i = 0; i < specials.length; i++) { + if (specials[i].equals(name)) { + specialAttributes[i] = value; + return (true); + } + } + return (false); + } + + + /** + * Remove a special attribute. + * + * @return true if the attribute was a special attribute, false otherwise + */ + protected boolean removeSpecial(String name) { + for (int i = 0; i < specials.length; i++) { + if (specials[i].equals(name)) { + specialAttributes[i] = null; + return (true); + } + } + return (false); + } + + + /** + * Merge the two sets of parameter values into a single String array. + * + * @param values1 First set of values + * @param values2 Second set of values + */ + protected String[] mergeValues(Object values1, Object values2) { + + ArrayList results = new ArrayList(); + + if (values1 == null) + ; + else if (values1 instanceof String) + results.add(values1); + else if (values1 instanceof String[]) { + String values[] = (String[]) values1; + for (int i = 0; i < values.length; i++) + results.add(values[i]); + } else + results.add(values1.toString()); + + if (values2 == null) + ; + else if (values2 instanceof String) + results.add(values2); + else if (values2 instanceof String[]) { + String values[] = (String[]) values2; + for (int i = 0; i < values.length; i++) + results.add(values[i]); + } else + results.add(values2.toString()); + + String values[] = new String[results.size()]; + return ((String[]) results.toArray(values)); + + } + + + // ------------------------------------------------------ Private Methods + + + /** + * Merge the parameters from the saved query parameter string (if any), and + * the parameters already present on this request (if any), such that the + * parameter values from the query string show up first if there are + * duplicate parameter names. + */ + private void mergeParameters() { + + if ((queryParamString == null) || (queryParamString.length() < 1)) + return; + + HashMap queryParameters = new HashMap(); + String encoding = getCharacterEncoding(); + if (encoding == null) + encoding = "ISO-8859-1"; + try { + RequestUtil.parseParameters + (queryParameters, queryParamString, encoding); + } catch (Exception e) { + ; + } + Iterator keys = parameters.keySet().iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + Object value = queryParameters.get(key); + if (value == null) { + queryParameters.put(key, parameters.get(key)); + continue; + } + queryParameters.put + (key, mergeValues(value, parameters.get(key))); + } + parameters = queryParameters; + + } + + + // ----------------------------------- AttributeNamesEnumerator Inner Class + + + /** + * Utility class used to expose the special attributes as being available + * as request attributes. + */ + protected class AttributeNamesEnumerator implements Enumeration { + + protected int pos = -1; + protected int last = -1; + protected Enumeration parentEnumeration = null; + protected String next = null; + + public AttributeNamesEnumerator() { + parentEnumeration = getRequest().getAttributeNames(); + for (int i = 0; i < specialAttributes.length; i++) { + if (getAttribute(specials[i]) != null) { + last = i; + } + } + } + + public boolean hasMoreElements() { + return ((pos != last) || (next != null) + || ((next = findNext()) != null)); + } + + public Object nextElement() { + if (pos != last) { + for (int i = pos + 1; i <= last; i++) { + if (getAttribute(specials[i]) != null) { + pos = i; + return (specials[i]); + } + } + } + String result = next; + if (next != null) { + next = findNext(); + } else { + throw new NoSuchElementException(); + } + return result; + } + + protected String findNext() { + String result = null; + while ((result == null) && (parentEnumeration.hasMoreElements())) { + String current = (String) parentEnumeration.nextElement(); + if (!isSpecial(current)) { + result = current; + } + } + return result; + } + + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationHttpResponse.java b/java/org/apache/catalina/core/ApplicationHttpResponse.java index 9fd422b5c..28c6934d8 100644 --- a/java/org/apache/catalina/core/ApplicationHttpResponse.java +++ b/java/org/apache/catalina/core/ApplicationHttpResponse.java @@ -1,393 +1,393 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; -import java.util.Locale; - -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.catalina.util.StringManager; - - -/** - * Wrapper around a javax.servlet.http.HttpServletResponse - * that transforms an application response object (which might be the original - * one passed to a servlet, or might be based on the 2.3 - * javax.servlet.http.HttpServletResponseWrapper class) - * back into an internal org.apache.catalina.HttpResponse. - *

    - * WARNING: Due to Java's lack of support for multiple - * inheritance, all of the logic in ApplicationResponse is - * duplicated in ApplicationHttpResponse. Make sure that you - * keep these two classes in synchronization when making changes! - * - * @author Craig R. McClanahan - * @version $Revision: 303387 $ $Date: 2004-10-15 18:09:27 +0200 (ven., 15 oct. 2004) $ - */ - -class ApplicationHttpResponse extends HttpServletResponseWrapper { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new wrapped response around the specified servlet response. - * - * @param response The servlet response being wrapped - */ - public ApplicationHttpResponse(HttpServletResponse response) { - - this(response, false); - - } - - - /** - * Construct a new wrapped response around the specified servlet response. - * - * @param response The servlet response being wrapped - * @param included true if this response is being processed - * by a RequestDispatcher.include() call - */ - public ApplicationHttpResponse(HttpServletResponse response, - boolean included) { - - super(response); - setIncluded(included); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Is this wrapped response the subject of an include() - * call? - */ - protected boolean included = false; - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.core.ApplicationHttpResponse/1.0"; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------ ServletResponse Methods - - - /** - * Disallow reset() calls on a included response. - * - * @exception IllegalStateException if the response has already - * been committed - */ - public void reset() { - - // If already committed, the wrapped response will throw ISE - if (!included || getResponse().isCommitted()) - getResponse().reset(); - - } - - - /** - * Disallow setContentLength() calls on an included response. - * - * @param len The new content length - */ - public void setContentLength(int len) { - - if (!included) - getResponse().setContentLength(len); - - } - - - /** - * Disallow setContentType() calls on an included response. - * - * @param type The new content type - */ - public void setContentType(String type) { - - if (!included) - getResponse().setContentType(type); - - } - - - /** - * Disallow setLocale() calls on an included response. - * - * @param loc The new locale - */ - public void setLocale(Locale loc) { - - if (!included) - getResponse().setLocale(loc); - - } - - - /** - * Ignore setBufferSize() calls on an included response. - * - * @param size The buffer size - */ - public void setBufferSize(int size) { - if (!included) - getResponse().setBufferSize(size); - } - - - // -------------------------------------------- HttpServletResponse Methods - - - /** - * Disallow addCookie() calls on an included response. - * - * @param cookie The new cookie - */ - public void addCookie(Cookie cookie) { - - if (!included) - ((HttpServletResponse) getResponse()).addCookie(cookie); - - } - - - /** - * Disallow addDateHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void addDateHeader(String name, long value) { - - if (!included) - ((HttpServletResponse) getResponse()).addDateHeader(name, value); - - } - - - /** - * Disallow addHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void addHeader(String name, String value) { - - if (!included) - ((HttpServletResponse) getResponse()).addHeader(name, value); - - } - - - /** - * Disallow addIntHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void addIntHeader(String name, int value) { - - if (!included) - ((HttpServletResponse) getResponse()).addIntHeader(name, value); - - } - - - /** - * Disallow sendError() calls on an included response. - * - * @param sc The new status code - * - * @exception IOException if an input/output error occurs - */ - public void sendError(int sc) throws IOException { - - if (!included) - ((HttpServletResponse) getResponse()).sendError(sc); - - } - - - /** - * Disallow sendError() calls on an included response. - * - * @param sc The new status code - * @param msg The new message - * - * @exception IOException if an input/output error occurs - */ - public void sendError(int sc, String msg) throws IOException { - - if (!included) - ((HttpServletResponse) getResponse()).sendError(sc, msg); - - } - - - /** - * Disallow sendRedirect() calls on an included response. - * - * @param location The new location - * - * @exception IOException if an input/output error occurs - */ - public void sendRedirect(String location) throws IOException { - - if (!included) - ((HttpServletResponse) getResponse()).sendRedirect(location); - - } - - - /** - * Disallow setDateHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void setDateHeader(String name, long value) { - - if (!included) - ((HttpServletResponse) getResponse()).setDateHeader(name, value); - - } - - - /** - * Disallow setHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void setHeader(String name, String value) { - - if (!included) - ((HttpServletResponse) getResponse()).setHeader(name, value); - - } - - - /** - * Disallow setIntHeader() calls on an included response. - * - * @param name The new header name - * @param value The new header value - */ - public void setIntHeader(String name, int value) { - - if (!included) - ((HttpServletResponse) getResponse()).setIntHeader(name, value); - - } - - - /** - * Disallow setStatus() calls on an included response. - * - * @param sc The new status code - */ - public void setStatus(int sc) { - - if (!included) - ((HttpServletResponse) getResponse()).setStatus(sc); - - } - - - /** - * Disallow setStatus() calls on an included response. - * - * @param sc The new status code - * @param msg The new message - */ - public void setStatus(int sc, String msg) { - - if (!included) - ((HttpServletResponse) getResponse()).setStatus(sc, msg); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the included flag for this response. - */ - boolean isIncluded() { - - return (this.included); - - } - - - /** - * Set the included flag for this response. - * - * @param included The new included flag - */ - void setIncluded(boolean included) { - - this.included = included; - - } - - - /** - * Set the response that we are wrapping. - * - * @param response The new wrapped response - */ - void setResponse(HttpServletResponse response) { - - super.setResponse(response); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; +import java.util.Locale; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.catalina.util.StringManager; + + +/** + * Wrapper around a javax.servlet.http.HttpServletResponse + * that transforms an application response object (which might be the original + * one passed to a servlet, or might be based on the 2.3 + * javax.servlet.http.HttpServletResponseWrapper class) + * back into an internal org.apache.catalina.HttpResponse. + *

    + * WARNING: Due to Java's lack of support for multiple + * inheritance, all of the logic in ApplicationResponse is + * duplicated in ApplicationHttpResponse. Make sure that you + * keep these two classes in synchronization when making changes! + * + * @author Craig R. McClanahan + * @version $Revision: 303387 $ $Date: 2004-10-15 18:09:27 +0200 (ven., 15 oct. 2004) $ + */ + +class ApplicationHttpResponse extends HttpServletResponseWrapper { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new wrapped response around the specified servlet response. + * + * @param response The servlet response being wrapped + */ + public ApplicationHttpResponse(HttpServletResponse response) { + + this(response, false); + + } + + + /** + * Construct a new wrapped response around the specified servlet response. + * + * @param response The servlet response being wrapped + * @param included true if this response is being processed + * by a RequestDispatcher.include() call + */ + public ApplicationHttpResponse(HttpServletResponse response, + boolean included) { + + super(response); + setIncluded(included); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Is this wrapped response the subject of an include() + * call? + */ + protected boolean included = false; + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.core.ApplicationHttpResponse/1.0"; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------ ServletResponse Methods + + + /** + * Disallow reset() calls on a included response. + * + * @exception IllegalStateException if the response has already + * been committed + */ + public void reset() { + + // If already committed, the wrapped response will throw ISE + if (!included || getResponse().isCommitted()) + getResponse().reset(); + + } + + + /** + * Disallow setContentLength() calls on an included response. + * + * @param len The new content length + */ + public void setContentLength(int len) { + + if (!included) + getResponse().setContentLength(len); + + } + + + /** + * Disallow setContentType() calls on an included response. + * + * @param type The new content type + */ + public void setContentType(String type) { + + if (!included) + getResponse().setContentType(type); + + } + + + /** + * Disallow setLocale() calls on an included response. + * + * @param loc The new locale + */ + public void setLocale(Locale loc) { + + if (!included) + getResponse().setLocale(loc); + + } + + + /** + * Ignore setBufferSize() calls on an included response. + * + * @param size The buffer size + */ + public void setBufferSize(int size) { + if (!included) + getResponse().setBufferSize(size); + } + + + // -------------------------------------------- HttpServletResponse Methods + + + /** + * Disallow addCookie() calls on an included response. + * + * @param cookie The new cookie + */ + public void addCookie(Cookie cookie) { + + if (!included) + ((HttpServletResponse) getResponse()).addCookie(cookie); + + } + + + /** + * Disallow addDateHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void addDateHeader(String name, long value) { + + if (!included) + ((HttpServletResponse) getResponse()).addDateHeader(name, value); + + } + + + /** + * Disallow addHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void addHeader(String name, String value) { + + if (!included) + ((HttpServletResponse) getResponse()).addHeader(name, value); + + } + + + /** + * Disallow addIntHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void addIntHeader(String name, int value) { + + if (!included) + ((HttpServletResponse) getResponse()).addIntHeader(name, value); + + } + + + /** + * Disallow sendError() calls on an included response. + * + * @param sc The new status code + * + * @exception IOException if an input/output error occurs + */ + public void sendError(int sc) throws IOException { + + if (!included) + ((HttpServletResponse) getResponse()).sendError(sc); + + } + + + /** + * Disallow sendError() calls on an included response. + * + * @param sc The new status code + * @param msg The new message + * + * @exception IOException if an input/output error occurs + */ + public void sendError(int sc, String msg) throws IOException { + + if (!included) + ((HttpServletResponse) getResponse()).sendError(sc, msg); + + } + + + /** + * Disallow sendRedirect() calls on an included response. + * + * @param location The new location + * + * @exception IOException if an input/output error occurs + */ + public void sendRedirect(String location) throws IOException { + + if (!included) + ((HttpServletResponse) getResponse()).sendRedirect(location); + + } + + + /** + * Disallow setDateHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void setDateHeader(String name, long value) { + + if (!included) + ((HttpServletResponse) getResponse()).setDateHeader(name, value); + + } + + + /** + * Disallow setHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void setHeader(String name, String value) { + + if (!included) + ((HttpServletResponse) getResponse()).setHeader(name, value); + + } + + + /** + * Disallow setIntHeader() calls on an included response. + * + * @param name The new header name + * @param value The new header value + */ + public void setIntHeader(String name, int value) { + + if (!included) + ((HttpServletResponse) getResponse()).setIntHeader(name, value); + + } + + + /** + * Disallow setStatus() calls on an included response. + * + * @param sc The new status code + */ + public void setStatus(int sc) { + + if (!included) + ((HttpServletResponse) getResponse()).setStatus(sc); + + } + + + /** + * Disallow setStatus() calls on an included response. + * + * @param sc The new status code + * @param msg The new message + */ + public void setStatus(int sc, String msg) { + + if (!included) + ((HttpServletResponse) getResponse()).setStatus(sc, msg); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the included flag for this response. + */ + boolean isIncluded() { + + return (this.included); + + } + + + /** + * Set the included flag for this response. + * + * @param included The new included flag + */ + void setIncluded(boolean included) { + + this.included = included; + + } + + + /** + * Set the response that we are wrapping. + * + * @param response The new wrapped response + */ + void setResponse(HttpServletResponse response) { + + super.setResponse(response); + + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationRequest.java b/java/org/apache/catalina/core/ApplicationRequest.java index 6eb1c734b..bed95a3aa 100644 --- a/java/org/apache/catalina/core/ApplicationRequest.java +++ b/java/org/apache/catalina/core/ApplicationRequest.java @@ -1,209 +1,209 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.util.Enumeration; -import java.util.HashMap; - -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestWrapper; - -import org.apache.catalina.Globals; -import org.apache.catalina.util.Enumerator; -import org.apache.catalina.util.StringManager; - - -/** - * Wrapper around a javax.servlet.ServletRequest - * that transforms an application request object (which might be the original - * one passed to a servlet, or might be based on the 2.3 - * javax.servlet.ServletRequestWrapper class) - * back into an internal org.apache.catalina.Request. - *

    - * WARNING: Due to Java's lack of support for multiple - * inheritance, all of the logic in ApplicationRequest is - * duplicated in ApplicationHttpRequest. Make sure that you - * keep these two classes in synchronization when making changes! - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -class ApplicationRequest extends ServletRequestWrapper { - - - // ------------------------------------------------------- Static Variables - - - /** - * The set of attribute names that are special for request dispatchers. - */ - protected static final String specials[] = - { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR, - Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR, - Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, - Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, - Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR }; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new wrapped request around the specified servlet request. - * - * @param request The servlet request being wrapped - */ - public ApplicationRequest(ServletRequest request) { - - super(request); - setRequest(request); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The request attributes for this request. This is initialized from the - * wrapped request, but updates are allowed. - */ - protected HashMap attributes = new HashMap(); - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------- ServletRequest Methods - - - /** - * Override the getAttribute() method of the wrapped request. - * - * @param name Name of the attribute to retrieve - */ - public Object getAttribute(String name) { - - synchronized (attributes) { - return (attributes.get(name)); - } - - } - - - /** - * Override the getAttributeNames() method of the wrapped - * request. - */ - public Enumeration getAttributeNames() { - - synchronized (attributes) { - return (new Enumerator(attributes.keySet())); - } - - } - - - /** - * Override the removeAttribute() method of the - * wrapped request. - * - * @param name Name of the attribute to remove - */ - public void removeAttribute(String name) { - - synchronized (attributes) { - attributes.remove(name); - if (!isSpecial(name)) - getRequest().removeAttribute(name); - } - - } - - - /** - * Override the setAttribute() method of the - * wrapped request. - * - * @param name Name of the attribute to set - * @param value Value of the attribute to set - */ - public void setAttribute(String name, Object value) { - - synchronized (attributes) { - attributes.put(name, value); - if (!isSpecial(name)) - getRequest().setAttribute(name, value); - } - - } - - - // ------------------------------------------ ServletRequestWrapper Methods - - - /** - * Set the request that we are wrapping. - * - * @param request The new wrapped request - */ - public void setRequest(ServletRequest request) { - - super.setRequest(request); - - // Initialize the attributes for this request - synchronized (attributes) { - attributes.clear(); - Enumeration names = request.getAttributeNames(); - while (names.hasMoreElements()) { - String name = (String) names.nextElement(); - Object value = request.getAttribute(name); - attributes.put(name, value); - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Is this attribute name one of the special ones that is added only for - * included servlets? - * - * @param name Attribute name to be tested - */ - protected boolean isSpecial(String name) { - - for (int i = 0; i < specials.length; i++) { - if (specials[i].equals(name)) - return (true); - } - return (false); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.util.Enumeration; +import java.util.HashMap; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestWrapper; + +import org.apache.catalina.Globals; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.StringManager; + + +/** + * Wrapper around a javax.servlet.ServletRequest + * that transforms an application request object (which might be the original + * one passed to a servlet, or might be based on the 2.3 + * javax.servlet.ServletRequestWrapper class) + * back into an internal org.apache.catalina.Request. + *

    + * WARNING: Due to Java's lack of support for multiple + * inheritance, all of the logic in ApplicationRequest is + * duplicated in ApplicationHttpRequest. Make sure that you + * keep these two classes in synchronization when making changes! + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +class ApplicationRequest extends ServletRequestWrapper { + + + // ------------------------------------------------------- Static Variables + + + /** + * The set of attribute names that are special for request dispatchers. + */ + protected static final String specials[] = + { Globals.INCLUDE_REQUEST_URI_ATTR, Globals.INCLUDE_CONTEXT_PATH_ATTR, + Globals.INCLUDE_SERVLET_PATH_ATTR, Globals.INCLUDE_PATH_INFO_ATTR, + Globals.INCLUDE_QUERY_STRING_ATTR, Globals.FORWARD_REQUEST_URI_ATTR, + Globals.FORWARD_CONTEXT_PATH_ATTR, Globals.FORWARD_SERVLET_PATH_ATTR, + Globals.FORWARD_PATH_INFO_ATTR, Globals.FORWARD_QUERY_STRING_ATTR }; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new wrapped request around the specified servlet request. + * + * @param request The servlet request being wrapped + */ + public ApplicationRequest(ServletRequest request) { + + super(request); + setRequest(request); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The request attributes for this request. This is initialized from the + * wrapped request, but updates are allowed. + */ + protected HashMap attributes = new HashMap(); + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------- ServletRequest Methods + + + /** + * Override the getAttribute() method of the wrapped request. + * + * @param name Name of the attribute to retrieve + */ + public Object getAttribute(String name) { + + synchronized (attributes) { + return (attributes.get(name)); + } + + } + + + /** + * Override the getAttributeNames() method of the wrapped + * request. + */ + public Enumeration getAttributeNames() { + + synchronized (attributes) { + return (new Enumerator(attributes.keySet())); + } + + } + + + /** + * Override the removeAttribute() method of the + * wrapped request. + * + * @param name Name of the attribute to remove + */ + public void removeAttribute(String name) { + + synchronized (attributes) { + attributes.remove(name); + if (!isSpecial(name)) + getRequest().removeAttribute(name); + } + + } + + + /** + * Override the setAttribute() method of the + * wrapped request. + * + * @param name Name of the attribute to set + * @param value Value of the attribute to set + */ + public void setAttribute(String name, Object value) { + + synchronized (attributes) { + attributes.put(name, value); + if (!isSpecial(name)) + getRequest().setAttribute(name, value); + } + + } + + + // ------------------------------------------ ServletRequestWrapper Methods + + + /** + * Set the request that we are wrapping. + * + * @param request The new wrapped request + */ + public void setRequest(ServletRequest request) { + + super.setRequest(request); + + // Initialize the attributes for this request + synchronized (attributes) { + attributes.clear(); + Enumeration names = request.getAttributeNames(); + while (names.hasMoreElements()) { + String name = (String) names.nextElement(); + Object value = request.getAttribute(name); + attributes.put(name, value); + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Is this attribute name one of the special ones that is added only for + * included servlets? + * + * @param name Attribute name to be tested + */ + protected boolean isSpecial(String name) { + + for (int i = 0; i < specials.length; i++) { + if (specials[i].equals(name)) + return (true); + } + return (false); + + } + + +} diff --git a/java/org/apache/catalina/core/ApplicationResponse.java b/java/org/apache/catalina/core/ApplicationResponse.java index d4b1870eb..becb25d2d 100644 --- a/java/org/apache/catalina/core/ApplicationResponse.java +++ b/java/org/apache/catalina/core/ApplicationResponse.java @@ -1,201 +1,201 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.util.Locale; - -import javax.servlet.ServletResponse; -import javax.servlet.ServletResponseWrapper; - -import org.apache.catalina.util.StringManager; - - -/** - * Wrapper around a javax.servlet.ServletResponse - * that transforms an application response object (which might be the original - * one passed to a servlet, or might be based on the 2.3 - * javax.servlet.ServletResponseWrapper class) - * back into an internal org.apache.catalina.Response. - *

    - * WARNING: Due to Java's lack of support for multiple - * inheritance, all of the logic in ApplicationResponse is - * duplicated in ApplicationHttpResponse. Make sure that you - * keep these two classes in synchronization when making changes! - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -class ApplicationResponse extends ServletResponseWrapper { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new wrapped response around the specified servlet response. - * - * @param response The servlet response being wrapped - */ - public ApplicationResponse(ServletResponse response) { - - this(response, false); - - } - - - /** - * Construct a new wrapped response around the specified servlet response. - * - * @param response The servlet response being wrapped - * @param included true if this response is being processed - * by a RequestDispatcher.include() call - */ - public ApplicationResponse(ServletResponse response, boolean included) { - - super(response); - setIncluded(included); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Is this wrapped response the subject of an include() - * call? - */ - protected boolean included = false; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------ ServletResponse Methods - - - /** - * Disallow reset() calls on a included response. - * - * @exception IllegalStateException if the response has already - * been committed - */ - public void reset() { - - // If already committed, the wrapped response will throw ISE - if (!included || getResponse().isCommitted()) - getResponse().reset(); - - } - - - /** - * Disallow setContentLength() calls on an included response. - * - * @param len The new content length - */ - public void setContentLength(int len) { - - if (!included) - getResponse().setContentLength(len); - - } - - - /** - * Disallow setContentType() calls on an included response. - * - * @param type The new content type - */ - public void setContentType(String type) { - - if (!included) - getResponse().setContentType(type); - - } - - - /** - * Ignore setLocale() calls on an included response. - * - * @param loc The new locale - */ - public void setLocale(Locale loc) { - if (!included) - getResponse().setLocale(loc); - } - - - /** - * Ignore setBufferSize() calls on an included response. - * - * @param size The buffer size - */ - public void setBufferSize(int size) { - if (!included) - getResponse().setBufferSize(size); - } - - - // ----------------------------------------- ServletResponseWrapper Methods - - - /** - * Set the response that we are wrapping. - * - * @param response The new wrapped response - */ - public void setResponse(ServletResponse response) { - - super.setResponse(response); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Return the included flag for this response. - */ - boolean isIncluded() { - - return (this.included); - - } - - - /** - * Set the included flag for this response. - * - * @param included The new included flag - */ - void setIncluded(boolean included) { - - this.included = included; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.util.Locale; + +import javax.servlet.ServletResponse; +import javax.servlet.ServletResponseWrapper; + +import org.apache.catalina.util.StringManager; + + +/** + * Wrapper around a javax.servlet.ServletResponse + * that transforms an application response object (which might be the original + * one passed to a servlet, or might be based on the 2.3 + * javax.servlet.ServletResponseWrapper class) + * back into an internal org.apache.catalina.Response. + *

    + * WARNING: Due to Java's lack of support for multiple + * inheritance, all of the logic in ApplicationResponse is + * duplicated in ApplicationHttpResponse. Make sure that you + * keep these two classes in synchronization when making changes! + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +class ApplicationResponse extends ServletResponseWrapper { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new wrapped response around the specified servlet response. + * + * @param response The servlet response being wrapped + */ + public ApplicationResponse(ServletResponse response) { + + this(response, false); + + } + + + /** + * Construct a new wrapped response around the specified servlet response. + * + * @param response The servlet response being wrapped + * @param included true if this response is being processed + * by a RequestDispatcher.include() call + */ + public ApplicationResponse(ServletResponse response, boolean included) { + + super(response); + setIncluded(included); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Is this wrapped response the subject of an include() + * call? + */ + protected boolean included = false; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------ ServletResponse Methods + + + /** + * Disallow reset() calls on a included response. + * + * @exception IllegalStateException if the response has already + * been committed + */ + public void reset() { + + // If already committed, the wrapped response will throw ISE + if (!included || getResponse().isCommitted()) + getResponse().reset(); + + } + + + /** + * Disallow setContentLength() calls on an included response. + * + * @param len The new content length + */ + public void setContentLength(int len) { + + if (!included) + getResponse().setContentLength(len); + + } + + + /** + * Disallow setContentType() calls on an included response. + * + * @param type The new content type + */ + public void setContentType(String type) { + + if (!included) + getResponse().setContentType(type); + + } + + + /** + * Ignore setLocale() calls on an included response. + * + * @param loc The new locale + */ + public void setLocale(Locale loc) { + if (!included) + getResponse().setLocale(loc); + } + + + /** + * Ignore setBufferSize() calls on an included response. + * + * @param size The buffer size + */ + public void setBufferSize(int size) { + if (!included) + getResponse().setBufferSize(size); + } + + + // ----------------------------------------- ServletResponseWrapper Methods + + + /** + * Set the response that we are wrapping. + * + * @param response The new wrapped response + */ + public void setResponse(ServletResponse response) { + + super.setResponse(response); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Return the included flag for this response. + */ + boolean isIncluded() { + + return (this.included); + + } + + + /** + * Set the included flag for this response. + * + * @param included The new included flag + */ + void setIncluded(boolean included) { + + this.included = included; + + } + + +} diff --git a/java/org/apache/catalina/core/AprLifecycleListener.java b/java/org/apache/catalina/core/AprLifecycleListener.java index 72d77dbb5..ab81fb2e8 100644 --- a/java/org/apache/catalina/core/AprLifecycleListener.java +++ b/java/org/apache/catalina/core/AprLifecycleListener.java @@ -1,118 +1,118 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.core; - - -import java.lang.reflect.Method; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Implementation of LifecycleListener that will init and - * and destroy APR. - * - * @author Remy Maucherat - * @version $Revision: 374878 $ $Date: 2006-02-04 16:02:39 +0100 (sam., 04 févr. 2006) $ - * @since 4.1 - */ - -public class AprLifecycleListener - implements LifecycleListener { - - private static Log log = LogFactory.getLog(AprLifecycleListener.class); - - /** - * The string manager for this package. - */ - protected StringManager sm = - StringManager.getManager(Constants.Package); - - - // -------------------------------------------------------------- Constants - - - protected static final int REQUIRED_MAJOR = 1; - protected static final int REQUIRED_MINOR = 1; - protected static final int REQUIRED_PATCH = 2; - - - // ---------------------------------------------- LifecycleListener Methods - - - /** - * Primary entry point for startup and shutdown events. - * - * @param event The event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - if (Lifecycle.INIT_EVENT.equals(event.getType())) { - int major = 0; - int minor = 0; - int patch = 0; - try { - String methodName = "initialize"; - Class paramTypes[] = new Class[1]; - paramTypes[0] = String.class; - Object paramValues[] = new Object[1]; - paramValues[0] = null; - Class clazz = Class.forName("org.apache.tomcat.jni.Library"); - Method method = clazz.getMethod(methodName, paramTypes); - method.invoke(null, paramValues); - major = clazz.getField("TCN_MAJOR_VERSION").getInt(null); - minor = clazz.getField("TCN_MINOR_VERSION").getInt(null); - patch = clazz.getField("TCN_PATCH_VERSION").getInt(null); - } catch (Throwable t) { - if (!log.isDebugEnabled()) { - log.info(sm.getString("aprListener.aprInit", - System.getProperty("java.library.path"))); - } else { - log.debug(sm.getString("aprListener.aprInit", - System.getProperty("java.library.path")), t); - } - return; - } - if ((major != REQUIRED_MAJOR) || (minor != REQUIRED_MINOR) - || (patch < REQUIRED_PATCH)) { - log.error(sm.getString("aprListener.tcnInvalid", major + "." - + minor + "." + patch, REQUIRED_MAJOR + "." - + REQUIRED_MINOR + "." + REQUIRED_PATCH)); - } - } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) { - try { - String methodName = "terminate"; - Method method = Class.forName("org.apache.tomcat.jni.Library") - .getMethod(methodName, (Class [])null); - method.invoke(null, (Object []) null); - } catch (Throwable t) { - if (!log.isDebugEnabled()) { - log.info(sm.getString("aprListener.aprDestroy")); - } else { - log.debug(sm.getString("aprListener.aprDestroy"), t); - } - } - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.core; + + +import java.lang.reflect.Method; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Implementation of LifecycleListener that will init and + * and destroy APR. + * + * @author Remy Maucherat + * @version $Revision: 374878 $ $Date: 2006-02-04 16:02:39 +0100 (sam., 04 févr. 2006) $ + * @since 4.1 + */ + +public class AprLifecycleListener + implements LifecycleListener { + + private static Log log = LogFactory.getLog(AprLifecycleListener.class); + + /** + * The string manager for this package. + */ + protected StringManager sm = + StringManager.getManager(Constants.Package); + + + // -------------------------------------------------------------- Constants + + + protected static final int REQUIRED_MAJOR = 1; + protected static final int REQUIRED_MINOR = 1; + protected static final int REQUIRED_PATCH = 2; + + + // ---------------------------------------------- LifecycleListener Methods + + + /** + * Primary entry point for startup and shutdown events. + * + * @param event The event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + if (Lifecycle.INIT_EVENT.equals(event.getType())) { + int major = 0; + int minor = 0; + int patch = 0; + try { + String methodName = "initialize"; + Class paramTypes[] = new Class[1]; + paramTypes[0] = String.class; + Object paramValues[] = new Object[1]; + paramValues[0] = null; + Class clazz = Class.forName("org.apache.tomcat.jni.Library"); + Method method = clazz.getMethod(methodName, paramTypes); + method.invoke(null, paramValues); + major = clazz.getField("TCN_MAJOR_VERSION").getInt(null); + minor = clazz.getField("TCN_MINOR_VERSION").getInt(null); + patch = clazz.getField("TCN_PATCH_VERSION").getInt(null); + } catch (Throwable t) { + if (!log.isDebugEnabled()) { + log.info(sm.getString("aprListener.aprInit", + System.getProperty("java.library.path"))); + } else { + log.debug(sm.getString("aprListener.aprInit", + System.getProperty("java.library.path")), t); + } + return; + } + if ((major != REQUIRED_MAJOR) || (minor != REQUIRED_MINOR) + || (patch < REQUIRED_PATCH)) { + log.error(sm.getString("aprListener.tcnInvalid", major + "." + + minor + "." + patch, REQUIRED_MAJOR + "." + + REQUIRED_MINOR + "." + REQUIRED_PATCH)); + } + } else if (Lifecycle.AFTER_STOP_EVENT.equals(event.getType())) { + try { + String methodName = "terminate"; + Method method = Class.forName("org.apache.tomcat.jni.Library") + .getMethod(methodName, (Class [])null); + method.invoke(null, (Object []) null); + } catch (Throwable t) { + if (!log.isDebugEnabled()) { + log.info(sm.getString("aprListener.aprDestroy")); + } else { + log.debug(sm.getString("aprListener.aprDestroy"), t); + } + } + } + + } + + +} diff --git a/java/org/apache/catalina/core/Constants.java b/java/org/apache/catalina/core/Constants.java index 0c6d9084d..c75986ab5 100644 --- a/java/org/apache/catalina/core/Constants.java +++ b/java/org/apache/catalina/core/Constants.java @@ -1,31 +1,31 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -public class Constants { - - public static final String Package = "org.apache.catalina.core"; - public static final int MAJOR_VERSION = 2; - public static final int MINOR_VERSION = 4; - - public static final String JSP_SERVLET_CLASS = - "org.apache.jasper.servlet.JspServlet"; - public static final String JSP_SERVLET_NAME = "jsp"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +public class Constants { + + public static final String Package = "org.apache.catalina.core"; + public static final int MAJOR_VERSION = 2; + public static final int MINOR_VERSION = 4; + + public static final String JSP_SERVLET_CLASS = + "org.apache.jasper.servlet.JspServlet"; + public static final String JSP_SERVLET_NAME = "jsp"; + +} diff --git a/java/org/apache/catalina/core/ContainerBase.java b/java/org/apache/catalina/core/ContainerBase.java index bf34aec54..74ce013eb 100644 --- a/java/org/apache/catalina/core/ContainerBase.java +++ b/java/org/apache/catalina/core/ContainerBase.java @@ -1,1586 +1,1586 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.IOException; -import java.io.Serializable; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.naming.directory.DirContext; -import javax.servlet.ServletException; - -import org.apache.catalina.Cluster; -import org.apache.catalina.Container; -import org.apache.catalina.ContainerEvent; -import org.apache.catalina.ContainerListener; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.Manager; -import org.apache.catalina.Pipeline; -import org.apache.catalina.Realm; -import org.apache.catalina.Valve; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.naming.resources.ProxyDirContext; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Abstract implementation of the Container interface, providing common - * functionality required by nearly every implementation. Classes extending - * this base class must implement getInfo(), and may implement - * a replacement for invoke(). - *

    - * All subclasses of this abstract base class will include support for a - * Pipeline object that defines the processing to be performed for each request - * received by the invoke() method of this class, utilizing the - * "Chain of Responsibility" design pattern. A subclass should encapsulate its - * own processing functionality as a Valve, and configure this - * Valve into the pipeline by calling setBasic(). - *

    - * This implementation fires property change events, per the JavaBeans design - * pattern, for changes in singleton properties. In addition, it fires the - * following ContainerEvent events to listeners who register - * themselves with addContainerListener(): - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
    TypeDataDescription
    addChildContainerChild container added to this Container.
    addValveValveValve added to this Container.
    removeChildContainerChild container removed from this Container.
    removeValveValveValve removed from this Container.
    startnullContainer was started.
    stopnullContainer was stopped.
    - * Subclasses that fire additional events should document them in the - * class comments of the implementation class. - * - * @author Craig R. McClanahan - */ - -public abstract class ContainerBase - implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( ContainerBase.class ); - - /** - * Perform addChild with the permissions of this class. - * addChild can be called with the XML parser on the stack, - * this allows the XML parser to have fewer privileges than - * Tomcat. - */ - protected class PrivilegedAddChild - implements PrivilegedAction { - - private Container child; - - PrivilegedAddChild(Container child) { - this.child = child; - } - - public Object run() { - addChildInternal(child); - return null; - } - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The child Containers belonging to this Container, keyed by name. - */ - protected HashMap children = new HashMap(); - - - /** - * The processor delay for this component. - */ - protected int backgroundProcessorDelay = -1; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The container event listeners for this Container. - */ - protected ArrayList listeners = new ArrayList(); - - - /** - * The Loader implementation with which this Container is associated. - */ - protected Loader loader = null; - - - /** - * The Logger implementation with which this Container is associated. - */ - protected Log logger = null; - - - /** - * Associated logger name. - */ - protected String logName = null; - - - /** - * The Manager implementation with which this Container is associated. - */ - protected Manager manager = null; - - - /** - * The cluster with which this Container is associated. - */ - protected Cluster cluster = null; - - - /** - * The human-readable name of this Container. - */ - protected String name = null; - - - /** - * The parent Container to which this Container is a child. - */ - protected Container parent = null; - - - /** - * The parent class loader to be configured when we install a Loader. - */ - protected ClassLoader parentClassLoader = null; - - - /** - * The Pipeline object with which this Container is associated. - */ - protected Pipeline pipeline = new StandardPipeline(this); - - - /** - * The Realm with which this Container is associated. - */ - protected Realm realm = null; - - - /** - * The resources DirContext object with which this Container is associated. - */ - protected DirContext resources = null; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started? - */ - protected boolean started = false; - - protected boolean initialized=false; - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - /** - * The background thread. - */ - private Thread thread = null; - - - /** - * The background thread completion semaphore. - */ - private boolean threadDone = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Get the delay between the invocation of the backgroundProcess method on - * this container and its children. Child containers will not be invoked - * if their delay value is not negative (which would mean they are using - * their own thread). Setting this to a positive value will cause - * a thread to be spawn. After waiting the specified amount of time, - * the thread will invoke the executePeriodic method on this container - * and all its children. - */ - public int getBackgroundProcessorDelay() { - return backgroundProcessorDelay; - } - - - /** - * Set the delay between the invocation of the execute method on this - * container and its children. - * - * @param delay The delay in seconds between the invocation of - * backgroundProcess methods - */ - public void setBackgroundProcessorDelay(int delay) { - backgroundProcessorDelay = delay; - } - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - return this.getClass().getName(); - } - - - /** - * Return the Loader with which this Container is associated. If there is - * no associated Loader, return the Loader associated with our parent - * Container (if any); otherwise, return null. - */ - public Loader getLoader() { - - if (loader != null) - return (loader); - if (parent != null) - return (parent.getLoader()); - return (null); - - } - - - /** - * Set the Loader with which this Container is associated. - * - * @param loader The newly associated loader - */ - public synchronized void setLoader(Loader loader) { - - // Change components if necessary - Loader oldLoader = this.loader; - if (oldLoader == loader) - return; - this.loader = loader; - - // Stop the old component if necessary - if (started && (oldLoader != null) && - (oldLoader instanceof Lifecycle)) { - try { - ((Lifecycle) oldLoader).stop(); - } catch (LifecycleException e) { - log.error("ContainerBase.setLoader: stop: ", e); - } - } - - // Start the new component if necessary - if (loader != null) - loader.setContainer(this); - if (started && (loader != null) && - (loader instanceof Lifecycle)) { - try { - ((Lifecycle) loader).start(); - } catch (LifecycleException e) { - log.error("ContainerBase.setLoader: start: ", e); - } - } - - // Report this property change to interested listeners - support.firePropertyChange("loader", oldLoader, this.loader); - - } - - - /** - * Return the Logger with which this Container is associated. If there is - * no associated Logger, return the Logger associated with our parent - * Container (if any); otherwise return null. - */ - public Log getLogger() { - - if (logger != null) - return (logger); - logger = LogFactory.getLog(logName()); - return (logger); - - } - - - /** - * Return the Manager with which this Container is associated. If there is - * no associated Manager, return the Manager associated with our parent - * Container (if any); otherwise return null. - */ - public Manager getManager() { - - if (manager != null) - return (manager); - if (parent != null) - return (parent.getManager()); - return (null); - - } - - - /** - * Set the Manager with which this Container is associated. - * - * @param manager The newly associated Manager - */ - public synchronized void setManager(Manager manager) { - - // Change components if necessary - Manager oldManager = this.manager; - if (oldManager == manager) - return; - this.manager = manager; - - // Stop the old component if necessary - if (started && (oldManager != null) && - (oldManager instanceof Lifecycle)) { - try { - ((Lifecycle) oldManager).stop(); - } catch (LifecycleException e) { - log.error("ContainerBase.setManager: stop: ", e); - } - } - - // Start the new component if necessary - if (manager != null) - manager.setContainer(this); - if (started && (manager != null) && - (manager instanceof Lifecycle)) { - try { - ((Lifecycle) manager).start(); - } catch (LifecycleException e) { - log.error("ContainerBase.setManager: start: ", e); - } - } - - // Report this property change to interested listeners - support.firePropertyChange("manager", oldManager, this.manager); - - } - - - /** - * Return an object which may be utilized for mapping to this component. - */ - public Object getMappingObject() { - return this; - } - - - /** - * Return the Cluster with which this Container is associated. If there is - * no associated Cluster, return the Cluster associated with our parent - * Container (if any); otherwise return null. - */ - public Cluster getCluster() { - if (cluster != null) - return (cluster); - - if (parent != null) - return (parent.getCluster()); - - return (null); - } - - - /** - * Set the Cluster with which this Container is associated. - * - * @param cluster The newly associated Cluster - */ - public synchronized void setCluster(Cluster cluster) { - // Change components if necessary - Cluster oldCluster = this.cluster; - if (oldCluster == cluster) - return; - this.cluster = cluster; - - // Stop the old component if necessary - if (started && (oldCluster != null) && - (oldCluster instanceof Lifecycle)) { - try { - ((Lifecycle) oldCluster).stop(); - } catch (LifecycleException e) { - log.error("ContainerBase.setCluster: stop: ", e); - } - } - - // Start the new component if necessary - if (cluster != null) - cluster.setContainer(this); - - if (started && (cluster != null) && - (cluster instanceof Lifecycle)) { - try { - ((Lifecycle) cluster).start(); - } catch (LifecycleException e) { - log.error("ContainerBase.setCluster: start: ", e); - } - } - - // Report this property change to interested listeners - support.firePropertyChange("cluster", oldCluster, this.cluster); - } - - - /** - * Return a name string (suitable for use by humans) that describes this - * Container. Within the set of child containers belonging to a particular - * parent, Container names must be unique. - */ - public String getName() { - - return (name); - - } - - - /** - * Set a name string (suitable for use by humans) that describes this - * Container. Within the set of child containers belonging to a particular - * parent, Container names must be unique. - * - * @param name New name of this container - * - * @exception IllegalStateException if this Container has already been - * added to the children of a parent Container (after which the name - * may not be changed) - */ - public void setName(String name) { - - String oldName = this.name; - this.name = name; - support.firePropertyChange("name", oldName, this.name); - } - - - /** - * Return the Container for which this Container is a child, if there is - * one. If there is no defined parent, return null. - */ - public Container getParent() { - - return (parent); - - } - - - /** - * Set the parent Container to which this Container is being added as a - * child. This Container may refuse to become attached to the specified - * Container by throwing an exception. - * - * @param container Container to which this Container is being added - * as a child - * - * @exception IllegalArgumentException if this Container refuses to become - * attached to the specified Container - */ - public void setParent(Container container) { - - Container oldParent = this.parent; - this.parent = container; - support.firePropertyChange("parent", oldParent, this.parent); - - } - - - /** - * Return the parent class loader (if any) for this web application. - * This call is meaningful only after a Loader has - * been configured. - */ - public ClassLoader getParentClassLoader() { - if (parentClassLoader != null) - return (parentClassLoader); - if (parent != null) { - return (parent.getParentClassLoader()); - } - return (ClassLoader.getSystemClassLoader()); - - } - - - /** - * Set the parent class loader (if any) for this web application. - * This call is meaningful only before a Loader has - * been configured, and the specified value (if non-null) should be - * passed as an argument to the class loader constructor. - * - * - * @param parent The new parent class loader - */ - public void setParentClassLoader(ClassLoader parent) { - ClassLoader oldParentClassLoader = this.parentClassLoader; - this.parentClassLoader = parent; - support.firePropertyChange("parentClassLoader", oldParentClassLoader, - this.parentClassLoader); - - } - - - /** - * Return the Pipeline object that manages the Valves associated with - * this Container. - */ - public Pipeline getPipeline() { - - return (this.pipeline); - - } - - - /** - * Return the Realm with which this Container is associated. If there is - * no associated Realm, return the Realm associated with our parent - * Container (if any); otherwise return null. - */ - public Realm getRealm() { - - if (realm != null) - return (realm); - if (parent != null) - return (parent.getRealm()); - return (null); - - } - - - /** - * Set the Realm with which this Container is associated. - * - * @param realm The newly associated Realm - */ - public synchronized void setRealm(Realm realm) { - - // Change components if necessary - Realm oldRealm = this.realm; - if (oldRealm == realm) - return; - this.realm = realm; - - // Stop the old component if necessary - if (started && (oldRealm != null) && - (oldRealm instanceof Lifecycle)) { - try { - ((Lifecycle) oldRealm).stop(); - } catch (LifecycleException e) { - log.error("ContainerBase.setRealm: stop: ", e); - } - } - - // Start the new component if necessary - if (realm != null) - realm.setContainer(this); - if (started && (realm != null) && - (realm instanceof Lifecycle)) { - try { - ((Lifecycle) realm).start(); - } catch (LifecycleException e) { - log.error("ContainerBase.setRealm: start: ", e); - } - } - - // Report this property change to interested listeners - support.firePropertyChange("realm", oldRealm, this.realm); - - } - - - /** - * Return the resources DirContext object with which this Container is - * associated. If there is no associated resources object, return the - * resources associated with our parent Container (if any); otherwise - * return null. - */ - public DirContext getResources() { - if (resources != null) - return (resources); - if (parent != null) - return (parent.getResources()); - return (null); - - } - - - /** - * Set the resources DirContext object with which this Container is - * associated. - * - * @param resources The newly associated DirContext - */ - public synchronized void setResources(DirContext resources) { - // Called from StandardContext.setResources() - // <- StandardContext.start() - // <- ContainerBase.addChildInternal() - - // Change components if necessary - DirContext oldResources = this.resources; - if (oldResources == resources) - return; - Hashtable env = new Hashtable(); - if (getParent() != null) - env.put(ProxyDirContext.HOST, getParent().getName()); - env.put(ProxyDirContext.CONTEXT, getName()); - this.resources = new ProxyDirContext(env, resources); - // Report this property change to interested listeners - support.firePropertyChange("resources", oldResources, this.resources); - - } - - - // ------------------------------------------------------ Container Methods - - - /** - * Add a new child Container to those associated with this Container, - * if supported. Prior to adding this Container to the set of children, - * the child's setParent() method must be called, with this - * Container as an argument. This method may thrown an - * IllegalArgumentException if this Container chooses not - * to be attached to the specified Container, in which case it is not added - * - * @param child New child Container to be added - * - * @exception IllegalArgumentException if this exception is thrown by - * the setParent() method of the child Container - * @exception IllegalArgumentException if the new child does not have - * a name unique from that of existing children of this Container - * @exception IllegalStateException if this Container does not support - * child Containers - */ - public void addChild(Container child) { - if (System.getSecurityManager() != null) { - PrivilegedAction dp = - new PrivilegedAddChild(child); - AccessController.doPrivileged(dp); - } else { - addChildInternal(child); - } - } - - private void addChildInternal(Container child) { - - if( log.isDebugEnabled() ) - log.debug("Add child " + child + " " + this); - synchronized(children) { - if (children.get(child.getName()) != null) - throw new IllegalArgumentException("addChild: Child name '" + - child.getName() + - "' is not unique"); - child.setParent(this); // May throw IAE - children.put(child.getName(), child); - - // Start child - if (started && (child instanceof Lifecycle)) { - boolean success = false; - try { - ((Lifecycle) child).start(); - success = true; - } catch (LifecycleException e) { - log.error("ContainerBase.addChild: start: ", e); - throw new IllegalStateException - ("ContainerBase.addChild: start: " + e); - } finally { - if (!success) { - children.remove(child.getName()); - } - } - } - - fireContainerEvent(ADD_CHILD_EVENT, child); - } - - } - - - /** - * Add a container event listener to this component. - * - * @param listener The listener to add - */ - public void addContainerListener(ContainerListener listener) { - - synchronized (listeners) { - listeners.add(listener); - } - - } - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - - support.addPropertyChangeListener(listener); - - } - - - /** - * Return the child Container, associated with this Container, with - * the specified name (if any); otherwise, return null - * - * @param name Name of the child Container to be retrieved - */ - public Container findChild(String name) { - - if (name == null) - return (null); - synchronized (children) { // Required by post-start changes - return ((Container) children.get(name)); - } - - } - - - /** - * Return the set of children Containers associated with this Container. - * If this Container has no children, a zero-length array is returned. - */ - public Container[] findChildren() { - - synchronized (children) { - Container results[] = new Container[children.size()]; - return ((Container[]) children.values().toArray(results)); - } - - } - - - /** - * Return the set of container listeners associated with this Container. - * If this Container has no registered container listeners, a zero-length - * array is returned. - */ - public ContainerListener[] findContainerListeners() { - - synchronized (listeners) { - ContainerListener[] results = - new ContainerListener[listeners.size()]; - return ((ContainerListener[]) listeners.toArray(results)); - } - - } - - - /** - * Process the specified Request, to produce the corresponding Response, - * by invoking the first Valve in our pipeline (if any), or the basic - * Valve otherwise. - * - * @param request Request to be processed - * @param response Response to be produced - * - * @exception IllegalStateException if neither a pipeline or a basic - * Valve have been configured for this Container - * @exception IOException if an input/output error occurred while - * processing - * @exception ServletException if a ServletException was thrown - * while processing this request - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - pipeline.getFirst().invoke(request, response); - - } - - - /** - * Remove an existing child Container from association with this parent - * Container. - * - * @param child Existing child Container to be removed - */ - public void removeChild(Container child) { - - synchronized(children) { - if (children.get(child.getName()) == null) - return; - children.remove(child.getName()); - } - - if (started && (child instanceof Lifecycle)) { - try { - if( child instanceof ContainerBase ) { - if( ((ContainerBase)child).started ) { - ((Lifecycle) child).stop(); - } - } else { - ((Lifecycle) child).stop(); - } - } catch (LifecycleException e) { - log.error("ContainerBase.removeChild: stop: ", e); - } - } - - fireContainerEvent(REMOVE_CHILD_EVENT, child); - - // child.setParent(null); - - } - - - /** - * Remove a container event listener from this component. - * - * @param listener The listener to remove - */ - public void removeContainerListener(ContainerListener listener) { - - synchronized (listeners) { - listeners.remove(listener); - } - - } - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - - support.removePropertyChangeListener(listener); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public synchronized void start() throws LifecycleException { - - // Validate and update our current component state - if (started) { - if(log.isInfoEnabled()) - log.info(sm.getString("containerBase.alreadyStarted", logName())); - return; - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); - - started = true; - - // Start our subordinate components, if any - if ((loader != null) && (loader instanceof Lifecycle)) - ((Lifecycle) loader).start(); - logger = null; - getLogger(); - if ((logger != null) && (logger instanceof Lifecycle)) - ((Lifecycle) logger).start(); - if ((manager != null) && (manager instanceof Lifecycle)) - ((Lifecycle) manager).start(); - if ((cluster != null) && (cluster instanceof Lifecycle)) - ((Lifecycle) cluster).start(); - if ((realm != null) && (realm instanceof Lifecycle)) - ((Lifecycle) realm).start(); - if ((resources != null) && (resources instanceof Lifecycle)) - ((Lifecycle) resources).start(); - - // Start our child containers, if any - Container children[] = findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i] instanceof Lifecycle) - ((Lifecycle) children[i]).start(); - } - - // Start the Valves in our pipeline (including the basic), if any - if (pipeline instanceof Lifecycle) - ((Lifecycle) pipeline).start(); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(START_EVENT, null); - - // Start our thread - threadStart(); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public synchronized void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) { - if(log.isInfoEnabled()) - log.info(sm.getString("containerBase.notStarted", logName())); - return; - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); - - // Stop our thread - threadStop(); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Stop the Valves in our pipeline (including the basic), if any - if (pipeline instanceof Lifecycle) { - ((Lifecycle) pipeline).stop(); - } - - // Stop our child containers, if any - Container children[] = findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i] instanceof Lifecycle) - ((Lifecycle) children[i]).stop(); - } - // Remove children - so next start can work - children = findChildren(); - for (int i = 0; i < children.length; i++) { - removeChild(children[i]); - } - - // Stop our subordinate components, if any - if ((resources != null) && (resources instanceof Lifecycle)) { - ((Lifecycle) resources).stop(); - } - if ((realm != null) && (realm instanceof Lifecycle)) { - ((Lifecycle) realm).stop(); - } - if ((cluster != null) && (cluster instanceof Lifecycle)) { - ((Lifecycle) cluster).stop(); - } - if ((manager != null) && (manager instanceof Lifecycle)) { - ((Lifecycle) manager).stop(); - } - if ((logger != null) && (logger instanceof Lifecycle)) { - ((Lifecycle) logger).stop(); - } - if ((loader != null) && (loader instanceof Lifecycle)) { - ((Lifecycle) loader).stop(); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - - } - - /** Init method, part of the MBean lifecycle. - * If the container was added via JMX, it'll register itself with the - * parent, using the ObjectName conventions to locate the parent. - * - * If the container was added directly and it doesn't have an ObjectName, - * it'll create a name and register itself with the JMX console. On destroy(), - * the object will unregister. - * - * @throws Exception - */ - public void init() throws Exception { - - if( this.getParent() == null ) { - // "Life" update - ObjectName parentName=getParentName(); - - //log.info("Register " + parentName ); - if( parentName != null && - mserver.isRegistered(parentName)) - { - mserver.invoke(parentName, "addChild", new Object[] { this }, - new String[] {"org.apache.catalina.Container"}); - } - } - initialized=true; - } - - public ObjectName getParentName() throws MalformedObjectNameException { - return null; - } - - public void destroy() throws Exception { - if( started ) { - stop(); - } - initialized=false; - - // unregister this component - if ( oname != null ) { - try { - if( controller == oname ) { - Registry.getRegistry(null, null) - .unregisterComponent(oname); - if(log.isDebugEnabled()) - log.debug("unregistering " + oname); - } - } catch( Throwable t ) { - log.error("Error unregistering ", t ); - } - } - - if (parent != null) { - parent.removeChild(this); - } - - // Stop our child containers, if any - Container children[] = findChildren(); - for (int i = 0; i < children.length; i++) { - removeChild(children[i]); - } - - } - - // ------------------------------------------------------- Pipeline Methods - - - /** - * Add a new Valve to the end of the pipeline associated with this - * Container. Prior to adding the Valve, the Valve's - * setContainer method must be called, with this Container - * as an argument. The method may throw an - * IllegalArgumentException if this Valve chooses not to - * be associated with this Container, or IllegalStateException - * if it is already associated with a different Container. - * - * @param valve Valve to be added - * - * @exception IllegalArgumentException if this Container refused to - * accept the specified Valve - * @exception IllegalArgumentException if the specifie Valve refuses to be - * associated with this Container - * @exception IllegalStateException if the specified Valve is already - * associated with a different Container - */ - public synchronized void addValve(Valve valve) { - - pipeline.addValve(valve); - fireContainerEvent(ADD_VALVE_EVENT, valve); - } - - public ObjectName[] getValveObjectNames() { - return ((StandardPipeline)pipeline).getValveObjectNames(); - } - - /** - *

    Return the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). - */ - public Valve getBasic() { - - return (pipeline.getBasic()); - - } - - - /** - * Return the first valve in the pipeline. - */ - public Valve getFirst() { - - return (pipeline.getFirst()); - - } - - - /** - * Return the set of Valves in the pipeline associated with this - * Container, including the basic Valve (if any). If there are no - * such Valves, a zero-length array is returned. - */ - public Valve[] getValves() { - - return (pipeline.getValves()); - - } - - - /** - * Remove the specified Valve from the pipeline associated with this - * Container, if it is found; otherwise, do nothing. - * - * @param valve Valve to be removed - */ - public synchronized void removeValve(Valve valve) { - - pipeline.removeValve(valve); - fireContainerEvent(REMOVE_VALVE_EVENT, valve); - } - - - /** - *

    Set the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). Prioer to setting the basic Valve, - * the Valve's setContainer() will be called, if it - * implements Contained, with the owning Container as an - * argument. The method may throw an IllegalArgumentException - * if this Valve chooses not to be associated with this Container, or - * IllegalStateException if it is already associated with - * a different Container.

    - * - * @param valve Valve to be distinguished as the basic Valve - */ - public void setBasic(Valve valve) { - - pipeline.setBasic(valve); - - } - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - - if (!started) - return; - - if (cluster != null) { - try { - cluster.backgroundProcess(); - } catch (Exception e) { - log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e); - } - } - if (loader != null) { - try { - loader.backgroundProcess(); - } catch (Exception e) { - log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e); - } - } - if (manager != null) { - try { - manager.backgroundProcess(); - } catch (Exception e) { - log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e); - } - } - if (realm != null) { - try { - realm.backgroundProcess(); - } catch (Exception e) { - log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e); - } - } - Valve current = pipeline.getFirst(); - while (current != null) { - try { - current.backgroundProcess(); - } catch (Exception e) { - log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e); - } - current = current.getNext(); - } - lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Notify all container event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param data Event data - */ - public void fireContainerEvent(String type, Object data) { - - if (listeners.size() < 1) - return; - ContainerEvent event = new ContainerEvent(this, type, data); - ContainerListener list[] = new ContainerListener[0]; - synchronized (listeners) { - list = (ContainerListener[]) listeners.toArray(list); - } - for (int i = 0; i < list.length; i++) - ((ContainerListener) list[i]).containerEvent(event); - - } - - - /** - * Return the abbreviated name of this container for logging messsages - */ - protected String logName() { - - if (logName != null) { - return logName; - } - String loggerName = null; - Container current = this; - while (current != null) { - String name = current.getName(); - if ((name == null) || (name.equals(""))) { - name = "/"; - } - loggerName = "[" + name + "]" - + ((loggerName != null) ? ("." + loggerName) : ""); - current = current.getParent(); - } - logName = ContainerBase.class.getName() + "." + loggerName; - return logName; - - } - - - // -------------------- JMX and Registration -------------------- - protected String type; - protected String domain; - protected String suffix; - protected ObjectName oname; - protected ObjectName controller; - protected transient MBeanServer mserver; - - public ObjectName getJmxName() { - return oname; - } - - public String getObjectName() { - if (oname != null) { - return oname.toString(); - } else return null; - } - - public String getDomain() { - if( domain==null ) { - Container parent=this; - while( parent != null && - !( parent instanceof StandardEngine) ) { - parent=parent.getParent(); - } - if( parent instanceof StandardEngine ) { - domain=((StandardEngine)parent).getDomain(); - } - } - return domain; - } - - public void setDomain(String domain) { - this.domain=domain; - } - - public String getType() { - return type; - } - - protected String getJSR77Suffix() { - return suffix; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - if (name == null ){ - return null; - } - - domain=name.getDomain(); - - type=name.getKeyProperty("type"); - if( type==null ) { - type=name.getKeyProperty("j2eeType"); - } - - String j2eeApp=name.getKeyProperty("J2EEApplication"); - String j2eeServer=name.getKeyProperty("J2EEServer"); - if( j2eeApp==null ) { - j2eeApp="none"; - } - if( j2eeServer==null ) { - j2eeServer="none"; - } - suffix=",J2EEApplication=" + j2eeApp + ",J2EEServer=" + j2eeServer; - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - public ObjectName[] getChildren() { - ObjectName result[]=new ObjectName[children.size()]; - Iterator it=children.values().iterator(); - int i=0; - while( it.hasNext() ) { - Object next=it.next(); - if( next instanceof ContainerBase ) { - result[i++]=((ContainerBase)next).getJmxName(); - } - } - return result; - } - - public ObjectName createObjectName(String domain, ObjectName parent) - throws Exception - { - if( log.isDebugEnabled()) - log.debug("Create ObjectName " + domain + " " + parent ); - return null; - } - - public String getContainerSuffix() { - Container container=this; - Container context=null; - Container host=null; - Container servlet=null; - - StringBuffer suffix=new StringBuffer(); - - if( container instanceof StandardHost ) { - host=container; - } else if( container instanceof StandardContext ) { - host=container.getParent(); - context=container; - } else if( container instanceof StandardWrapper ) { - context=container.getParent(); - host=context.getParent(); - servlet=container; - } - if( context!=null ) { - String path=((StandardContext)context).getPath(); - suffix.append(",path=").append((path.equals("")) ? "/" : path); - } - if( host!=null ) suffix.append(",host=").append( host.getName() ); - if( servlet != null ) { - String name=container.getName(); - suffix.append(",servlet="); - suffix.append((name=="") ? "/" : name); - } - return suffix.toString(); - } - - - /** - * Start the background thread that will periodically check for - * session timeouts. - */ - protected void threadStart() { - - if (thread != null) - return; - if (backgroundProcessorDelay <= 0) - return; - - threadDone = false; - String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; - thread = new Thread(new ContainerBackgroundProcessor(), threadName); - thread.setDaemon(true); - thread.start(); - - } - - - /** - * Stop the background thread that is periodically checking for - * session timeouts. - */ - protected void threadStop() { - - if (thread == null) - return; - - threadDone = true; - thread.interrupt(); - try { - thread.join(); - } catch (InterruptedException e) { - ; - } - - thread = null; - - } - - - // -------------------------------------- ContainerExecuteDelay Inner Class - - - /** - * Private thread class to invoke the backgroundProcess method - * of this container and its children after a fixed delay. - */ - protected class ContainerBackgroundProcessor implements Runnable { - - public void run() { - while (!threadDone) { - try { - Thread.sleep(backgroundProcessorDelay * 1000L); - } catch (InterruptedException e) { - ; - } - if (!threadDone) { - Container parent = (Container) getMappingObject(); - ClassLoader cl = - Thread.currentThread().getContextClassLoader(); - if (parent.getLoader() != null) { - cl = parent.getLoader().getClassLoader(); - } - processChildren(parent, cl); - } - } - } - - protected void processChildren(Container container, ClassLoader cl) { - try { - if (container.getLoader() != null) { - Thread.currentThread().setContextClassLoader - (container.getLoader().getClassLoader()); - } - container.backgroundProcess(); - } catch (Throwable t) { - log.error("Exception invoking periodic operation: ", t); - } finally { - Thread.currentThread().setContextClassLoader(cl); - } - Container[] children = container.findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i].getBackgroundProcessorDelay() <= 0) { - processChildren(children[i], cl); - } - } - } - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.Serializable; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.naming.directory.DirContext; +import javax.servlet.ServletException; + +import org.apache.catalina.Cluster; +import org.apache.catalina.Container; +import org.apache.catalina.ContainerEvent; +import org.apache.catalina.ContainerListener; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.Manager; +import org.apache.catalina.Pipeline; +import org.apache.catalina.Realm; +import org.apache.catalina.Valve; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.naming.resources.ProxyDirContext; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Abstract implementation of the Container interface, providing common + * functionality required by nearly every implementation. Classes extending + * this base class must implement getInfo(), and may implement + * a replacement for invoke(). + *

    + * All subclasses of this abstract base class will include support for a + * Pipeline object that defines the processing to be performed for each request + * received by the invoke() method of this class, utilizing the + * "Chain of Responsibility" design pattern. A subclass should encapsulate its + * own processing functionality as a Valve, and configure this + * Valve into the pipeline by calling setBasic(). + *

    + * This implementation fires property change events, per the JavaBeans design + * pattern, for changes in singleton properties. In addition, it fires the + * following ContainerEvent events to listeners who register + * themselves with addContainerListener(): + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
    TypeDataDescription
    addChildContainerChild container added to this Container.
    addValveValveValve added to this Container.
    removeChildContainerChild container removed from this Container.
    removeValveValveValve removed from this Container.
    startnullContainer was started.
    stopnullContainer was stopped.
    + * Subclasses that fire additional events should document them in the + * class comments of the implementation class. + * + * @author Craig R. McClanahan + */ + +public abstract class ContainerBase + implements Container, Lifecycle, Pipeline, MBeanRegistration, Serializable { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( ContainerBase.class ); + + /** + * Perform addChild with the permissions of this class. + * addChild can be called with the XML parser on the stack, + * this allows the XML parser to have fewer privileges than + * Tomcat. + */ + protected class PrivilegedAddChild + implements PrivilegedAction { + + private Container child; + + PrivilegedAddChild(Container child) { + this.child = child; + } + + public Object run() { + addChildInternal(child); + return null; + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The child Containers belonging to this Container, keyed by name. + */ + protected HashMap children = new HashMap(); + + + /** + * The processor delay for this component. + */ + protected int backgroundProcessorDelay = -1; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The container event listeners for this Container. + */ + protected ArrayList listeners = new ArrayList(); + + + /** + * The Loader implementation with which this Container is associated. + */ + protected Loader loader = null; + + + /** + * The Logger implementation with which this Container is associated. + */ + protected Log logger = null; + + + /** + * Associated logger name. + */ + protected String logName = null; + + + /** + * The Manager implementation with which this Container is associated. + */ + protected Manager manager = null; + + + /** + * The cluster with which this Container is associated. + */ + protected Cluster cluster = null; + + + /** + * The human-readable name of this Container. + */ + protected String name = null; + + + /** + * The parent Container to which this Container is a child. + */ + protected Container parent = null; + + + /** + * The parent class loader to be configured when we install a Loader. + */ + protected ClassLoader parentClassLoader = null; + + + /** + * The Pipeline object with which this Container is associated. + */ + protected Pipeline pipeline = new StandardPipeline(this); + + + /** + * The Realm with which this Container is associated. + */ + protected Realm realm = null; + + + /** + * The resources DirContext object with which this Container is associated. + */ + protected DirContext resources = null; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started? + */ + protected boolean started = false; + + protected boolean initialized=false; + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + /** + * The background thread. + */ + private Thread thread = null; + + + /** + * The background thread completion semaphore. + */ + private boolean threadDone = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Get the delay between the invocation of the backgroundProcess method on + * this container and its children. Child containers will not be invoked + * if their delay value is not negative (which would mean they are using + * their own thread). Setting this to a positive value will cause + * a thread to be spawn. After waiting the specified amount of time, + * the thread will invoke the executePeriodic method on this container + * and all its children. + */ + public int getBackgroundProcessorDelay() { + return backgroundProcessorDelay; + } + + + /** + * Set the delay between the invocation of the execute method on this + * container and its children. + * + * @param delay The delay in seconds between the invocation of + * backgroundProcess methods + */ + public void setBackgroundProcessorDelay(int delay) { + backgroundProcessorDelay = delay; + } + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + return this.getClass().getName(); + } + + + /** + * Return the Loader with which this Container is associated. If there is + * no associated Loader, return the Loader associated with our parent + * Container (if any); otherwise, return null. + */ + public Loader getLoader() { + + if (loader != null) + return (loader); + if (parent != null) + return (parent.getLoader()); + return (null); + + } + + + /** + * Set the Loader with which this Container is associated. + * + * @param loader The newly associated loader + */ + public synchronized void setLoader(Loader loader) { + + // Change components if necessary + Loader oldLoader = this.loader; + if (oldLoader == loader) + return; + this.loader = loader; + + // Stop the old component if necessary + if (started && (oldLoader != null) && + (oldLoader instanceof Lifecycle)) { + try { + ((Lifecycle) oldLoader).stop(); + } catch (LifecycleException e) { + log.error("ContainerBase.setLoader: stop: ", e); + } + } + + // Start the new component if necessary + if (loader != null) + loader.setContainer(this); + if (started && (loader != null) && + (loader instanceof Lifecycle)) { + try { + ((Lifecycle) loader).start(); + } catch (LifecycleException e) { + log.error("ContainerBase.setLoader: start: ", e); + } + } + + // Report this property change to interested listeners + support.firePropertyChange("loader", oldLoader, this.loader); + + } + + + /** + * Return the Logger with which this Container is associated. If there is + * no associated Logger, return the Logger associated with our parent + * Container (if any); otherwise return null. + */ + public Log getLogger() { + + if (logger != null) + return (logger); + logger = LogFactory.getLog(logName()); + return (logger); + + } + + + /** + * Return the Manager with which this Container is associated. If there is + * no associated Manager, return the Manager associated with our parent + * Container (if any); otherwise return null. + */ + public Manager getManager() { + + if (manager != null) + return (manager); + if (parent != null) + return (parent.getManager()); + return (null); + + } + + + /** + * Set the Manager with which this Container is associated. + * + * @param manager The newly associated Manager + */ + public synchronized void setManager(Manager manager) { + + // Change components if necessary + Manager oldManager = this.manager; + if (oldManager == manager) + return; + this.manager = manager; + + // Stop the old component if necessary + if (started && (oldManager != null) && + (oldManager instanceof Lifecycle)) { + try { + ((Lifecycle) oldManager).stop(); + } catch (LifecycleException e) { + log.error("ContainerBase.setManager: stop: ", e); + } + } + + // Start the new component if necessary + if (manager != null) + manager.setContainer(this); + if (started && (manager != null) && + (manager instanceof Lifecycle)) { + try { + ((Lifecycle) manager).start(); + } catch (LifecycleException e) { + log.error("ContainerBase.setManager: start: ", e); + } + } + + // Report this property change to interested listeners + support.firePropertyChange("manager", oldManager, this.manager); + + } + + + /** + * Return an object which may be utilized for mapping to this component. + */ + public Object getMappingObject() { + return this; + } + + + /** + * Return the Cluster with which this Container is associated. If there is + * no associated Cluster, return the Cluster associated with our parent + * Container (if any); otherwise return null. + */ + public Cluster getCluster() { + if (cluster != null) + return (cluster); + + if (parent != null) + return (parent.getCluster()); + + return (null); + } + + + /** + * Set the Cluster with which this Container is associated. + * + * @param cluster The newly associated Cluster + */ + public synchronized void setCluster(Cluster cluster) { + // Change components if necessary + Cluster oldCluster = this.cluster; + if (oldCluster == cluster) + return; + this.cluster = cluster; + + // Stop the old component if necessary + if (started && (oldCluster != null) && + (oldCluster instanceof Lifecycle)) { + try { + ((Lifecycle) oldCluster).stop(); + } catch (LifecycleException e) { + log.error("ContainerBase.setCluster: stop: ", e); + } + } + + // Start the new component if necessary + if (cluster != null) + cluster.setContainer(this); + + if (started && (cluster != null) && + (cluster instanceof Lifecycle)) { + try { + ((Lifecycle) cluster).start(); + } catch (LifecycleException e) { + log.error("ContainerBase.setCluster: start: ", e); + } + } + + // Report this property change to interested listeners + support.firePropertyChange("cluster", oldCluster, this.cluster); + } + + + /** + * Return a name string (suitable for use by humans) that describes this + * Container. Within the set of child containers belonging to a particular + * parent, Container names must be unique. + */ + public String getName() { + + return (name); + + } + + + /** + * Set a name string (suitable for use by humans) that describes this + * Container. Within the set of child containers belonging to a particular + * parent, Container names must be unique. + * + * @param name New name of this container + * + * @exception IllegalStateException if this Container has already been + * added to the children of a parent Container (after which the name + * may not be changed) + */ + public void setName(String name) { + + String oldName = this.name; + this.name = name; + support.firePropertyChange("name", oldName, this.name); + } + + + /** + * Return the Container for which this Container is a child, if there is + * one. If there is no defined parent, return null. + */ + public Container getParent() { + + return (parent); + + } + + + /** + * Set the parent Container to which this Container is being added as a + * child. This Container may refuse to become attached to the specified + * Container by throwing an exception. + * + * @param container Container to which this Container is being added + * as a child + * + * @exception IllegalArgumentException if this Container refuses to become + * attached to the specified Container + */ + public void setParent(Container container) { + + Container oldParent = this.parent; + this.parent = container; + support.firePropertyChange("parent", oldParent, this.parent); + + } + + + /** + * Return the parent class loader (if any) for this web application. + * This call is meaningful only after a Loader has + * been configured. + */ + public ClassLoader getParentClassLoader() { + if (parentClassLoader != null) + return (parentClassLoader); + if (parent != null) { + return (parent.getParentClassLoader()); + } + return (ClassLoader.getSystemClassLoader()); + + } + + + /** + * Set the parent class loader (if any) for this web application. + * This call is meaningful only before a Loader has + * been configured, and the specified value (if non-null) should be + * passed as an argument to the class loader constructor. + * + * + * @param parent The new parent class loader + */ + public void setParentClassLoader(ClassLoader parent) { + ClassLoader oldParentClassLoader = this.parentClassLoader; + this.parentClassLoader = parent; + support.firePropertyChange("parentClassLoader", oldParentClassLoader, + this.parentClassLoader); + + } + + + /** + * Return the Pipeline object that manages the Valves associated with + * this Container. + */ + public Pipeline getPipeline() { + + return (this.pipeline); + + } + + + /** + * Return the Realm with which this Container is associated. If there is + * no associated Realm, return the Realm associated with our parent + * Container (if any); otherwise return null. + */ + public Realm getRealm() { + + if (realm != null) + return (realm); + if (parent != null) + return (parent.getRealm()); + return (null); + + } + + + /** + * Set the Realm with which this Container is associated. + * + * @param realm The newly associated Realm + */ + public synchronized void setRealm(Realm realm) { + + // Change components if necessary + Realm oldRealm = this.realm; + if (oldRealm == realm) + return; + this.realm = realm; + + // Stop the old component if necessary + if (started && (oldRealm != null) && + (oldRealm instanceof Lifecycle)) { + try { + ((Lifecycle) oldRealm).stop(); + } catch (LifecycleException e) { + log.error("ContainerBase.setRealm: stop: ", e); + } + } + + // Start the new component if necessary + if (realm != null) + realm.setContainer(this); + if (started && (realm != null) && + (realm instanceof Lifecycle)) { + try { + ((Lifecycle) realm).start(); + } catch (LifecycleException e) { + log.error("ContainerBase.setRealm: start: ", e); + } + } + + // Report this property change to interested listeners + support.firePropertyChange("realm", oldRealm, this.realm); + + } + + + /** + * Return the resources DirContext object with which this Container is + * associated. If there is no associated resources object, return the + * resources associated with our parent Container (if any); otherwise + * return null. + */ + public DirContext getResources() { + if (resources != null) + return (resources); + if (parent != null) + return (parent.getResources()); + return (null); + + } + + + /** + * Set the resources DirContext object with which this Container is + * associated. + * + * @param resources The newly associated DirContext + */ + public synchronized void setResources(DirContext resources) { + // Called from StandardContext.setResources() + // <- StandardContext.start() + // <- ContainerBase.addChildInternal() + + // Change components if necessary + DirContext oldResources = this.resources; + if (oldResources == resources) + return; + Hashtable env = new Hashtable(); + if (getParent() != null) + env.put(ProxyDirContext.HOST, getParent().getName()); + env.put(ProxyDirContext.CONTEXT, getName()); + this.resources = new ProxyDirContext(env, resources); + // Report this property change to interested listeners + support.firePropertyChange("resources", oldResources, this.resources); + + } + + + // ------------------------------------------------------ Container Methods + + + /** + * Add a new child Container to those associated with this Container, + * if supported. Prior to adding this Container to the set of children, + * the child's setParent() method must be called, with this + * Container as an argument. This method may thrown an + * IllegalArgumentException if this Container chooses not + * to be attached to the specified Container, in which case it is not added + * + * @param child New child Container to be added + * + * @exception IllegalArgumentException if this exception is thrown by + * the setParent() method of the child Container + * @exception IllegalArgumentException if the new child does not have + * a name unique from that of existing children of this Container + * @exception IllegalStateException if this Container does not support + * child Containers + */ + public void addChild(Container child) { + if (System.getSecurityManager() != null) { + PrivilegedAction dp = + new PrivilegedAddChild(child); + AccessController.doPrivileged(dp); + } else { + addChildInternal(child); + } + } + + private void addChildInternal(Container child) { + + if( log.isDebugEnabled() ) + log.debug("Add child " + child + " " + this); + synchronized(children) { + if (children.get(child.getName()) != null) + throw new IllegalArgumentException("addChild: Child name '" + + child.getName() + + "' is not unique"); + child.setParent(this); // May throw IAE + children.put(child.getName(), child); + + // Start child + if (started && (child instanceof Lifecycle)) { + boolean success = false; + try { + ((Lifecycle) child).start(); + success = true; + } catch (LifecycleException e) { + log.error("ContainerBase.addChild: start: ", e); + throw new IllegalStateException + ("ContainerBase.addChild: start: " + e); + } finally { + if (!success) { + children.remove(child.getName()); + } + } + } + + fireContainerEvent(ADD_CHILD_EVENT, child); + } + + } + + + /** + * Add a container event listener to this component. + * + * @param listener The listener to add + */ + public void addContainerListener(ContainerListener listener) { + + synchronized (listeners) { + listeners.add(listener); + } + + } + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + + support.addPropertyChangeListener(listener); + + } + + + /** + * Return the child Container, associated with this Container, with + * the specified name (if any); otherwise, return null + * + * @param name Name of the child Container to be retrieved + */ + public Container findChild(String name) { + + if (name == null) + return (null); + synchronized (children) { // Required by post-start changes + return ((Container) children.get(name)); + } + + } + + + /** + * Return the set of children Containers associated with this Container. + * If this Container has no children, a zero-length array is returned. + */ + public Container[] findChildren() { + + synchronized (children) { + Container results[] = new Container[children.size()]; + return ((Container[]) children.values().toArray(results)); + } + + } + + + /** + * Return the set of container listeners associated with this Container. + * If this Container has no registered container listeners, a zero-length + * array is returned. + */ + public ContainerListener[] findContainerListeners() { + + synchronized (listeners) { + ContainerListener[] results = + new ContainerListener[listeners.size()]; + return ((ContainerListener[]) listeners.toArray(results)); + } + + } + + + /** + * Process the specified Request, to produce the corresponding Response, + * by invoking the first Valve in our pipeline (if any), or the basic + * Valve otherwise. + * + * @param request Request to be processed + * @param response Response to be produced + * + * @exception IllegalStateException if neither a pipeline or a basic + * Valve have been configured for this Container + * @exception IOException if an input/output error occurred while + * processing + * @exception ServletException if a ServletException was thrown + * while processing this request + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + pipeline.getFirst().invoke(request, response); + + } + + + /** + * Remove an existing child Container from association with this parent + * Container. + * + * @param child Existing child Container to be removed + */ + public void removeChild(Container child) { + + synchronized(children) { + if (children.get(child.getName()) == null) + return; + children.remove(child.getName()); + } + + if (started && (child instanceof Lifecycle)) { + try { + if( child instanceof ContainerBase ) { + if( ((ContainerBase)child).started ) { + ((Lifecycle) child).stop(); + } + } else { + ((Lifecycle) child).stop(); + } + } catch (LifecycleException e) { + log.error("ContainerBase.removeChild: stop: ", e); + } + } + + fireContainerEvent(REMOVE_CHILD_EVENT, child); + + // child.setParent(null); + + } + + + /** + * Remove a container event listener from this component. + * + * @param listener The listener to remove + */ + public void removeContainerListener(ContainerListener listener) { + + synchronized (listeners) { + listeners.remove(listener); + } + + } + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + + support.removePropertyChangeListener(listener); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public synchronized void start() throws LifecycleException { + + // Validate and update our current component state + if (started) { + if(log.isInfoEnabled()) + log.info(sm.getString("containerBase.alreadyStarted", logName())); + return; + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); + + started = true; + + // Start our subordinate components, if any + if ((loader != null) && (loader instanceof Lifecycle)) + ((Lifecycle) loader).start(); + logger = null; + getLogger(); + if ((logger != null) && (logger instanceof Lifecycle)) + ((Lifecycle) logger).start(); + if ((manager != null) && (manager instanceof Lifecycle)) + ((Lifecycle) manager).start(); + if ((cluster != null) && (cluster instanceof Lifecycle)) + ((Lifecycle) cluster).start(); + if ((realm != null) && (realm instanceof Lifecycle)) + ((Lifecycle) realm).start(); + if ((resources != null) && (resources instanceof Lifecycle)) + ((Lifecycle) resources).start(); + + // Start our child containers, if any + Container children[] = findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof Lifecycle) + ((Lifecycle) children[i]).start(); + } + + // Start the Valves in our pipeline (including the basic), if any + if (pipeline instanceof Lifecycle) + ((Lifecycle) pipeline).start(); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(START_EVENT, null); + + // Start our thread + threadStart(); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public synchronized void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) { + if(log.isInfoEnabled()) + log.info(sm.getString("containerBase.notStarted", logName())); + return; + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); + + // Stop our thread + threadStop(); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Stop the Valves in our pipeline (including the basic), if any + if (pipeline instanceof Lifecycle) { + ((Lifecycle) pipeline).stop(); + } + + // Stop our child containers, if any + Container children[] = findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof Lifecycle) + ((Lifecycle) children[i]).stop(); + } + // Remove children - so next start can work + children = findChildren(); + for (int i = 0; i < children.length; i++) { + removeChild(children[i]); + } + + // Stop our subordinate components, if any + if ((resources != null) && (resources instanceof Lifecycle)) { + ((Lifecycle) resources).stop(); + } + if ((realm != null) && (realm instanceof Lifecycle)) { + ((Lifecycle) realm).stop(); + } + if ((cluster != null) && (cluster instanceof Lifecycle)) { + ((Lifecycle) cluster).stop(); + } + if ((manager != null) && (manager instanceof Lifecycle)) { + ((Lifecycle) manager).stop(); + } + if ((logger != null) && (logger instanceof Lifecycle)) { + ((Lifecycle) logger).stop(); + } + if ((loader != null) && (loader instanceof Lifecycle)) { + ((Lifecycle) loader).stop(); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); + + } + + /** Init method, part of the MBean lifecycle. + * If the container was added via JMX, it'll register itself with the + * parent, using the ObjectName conventions to locate the parent. + * + * If the container was added directly and it doesn't have an ObjectName, + * it'll create a name and register itself with the JMX console. On destroy(), + * the object will unregister. + * + * @throws Exception + */ + public void init() throws Exception { + + if( this.getParent() == null ) { + // "Life" update + ObjectName parentName=getParentName(); + + //log.info("Register " + parentName ); + if( parentName != null && + mserver.isRegistered(parentName)) + { + mserver.invoke(parentName, "addChild", new Object[] { this }, + new String[] {"org.apache.catalina.Container"}); + } + } + initialized=true; + } + + public ObjectName getParentName() throws MalformedObjectNameException { + return null; + } + + public void destroy() throws Exception { + if( started ) { + stop(); + } + initialized=false; + + // unregister this component + if ( oname != null ) { + try { + if( controller == oname ) { + Registry.getRegistry(null, null) + .unregisterComponent(oname); + if(log.isDebugEnabled()) + log.debug("unregistering " + oname); + } + } catch( Throwable t ) { + log.error("Error unregistering ", t ); + } + } + + if (parent != null) { + parent.removeChild(this); + } + + // Stop our child containers, if any + Container children[] = findChildren(); + for (int i = 0; i < children.length; i++) { + removeChild(children[i]); + } + + } + + // ------------------------------------------------------- Pipeline Methods + + + /** + * Add a new Valve to the end of the pipeline associated with this + * Container. Prior to adding the Valve, the Valve's + * setContainer method must be called, with this Container + * as an argument. The method may throw an + * IllegalArgumentException if this Valve chooses not to + * be associated with this Container, or IllegalStateException + * if it is already associated with a different Container. + * + * @param valve Valve to be added + * + * @exception IllegalArgumentException if this Container refused to + * accept the specified Valve + * @exception IllegalArgumentException if the specifie Valve refuses to be + * associated with this Container + * @exception IllegalStateException if the specified Valve is already + * associated with a different Container + */ + public synchronized void addValve(Valve valve) { + + pipeline.addValve(valve); + fireContainerEvent(ADD_VALVE_EVENT, valve); + } + + public ObjectName[] getValveObjectNames() { + return ((StandardPipeline)pipeline).getValveObjectNames(); + } + + /** + *

    Return the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). + */ + public Valve getBasic() { + + return (pipeline.getBasic()); + + } + + + /** + * Return the first valve in the pipeline. + */ + public Valve getFirst() { + + return (pipeline.getFirst()); + + } + + + /** + * Return the set of Valves in the pipeline associated with this + * Container, including the basic Valve (if any). If there are no + * such Valves, a zero-length array is returned. + */ + public Valve[] getValves() { + + return (pipeline.getValves()); + + } + + + /** + * Remove the specified Valve from the pipeline associated with this + * Container, if it is found; otherwise, do nothing. + * + * @param valve Valve to be removed + */ + public synchronized void removeValve(Valve valve) { + + pipeline.removeValve(valve); + fireContainerEvent(REMOVE_VALVE_EVENT, valve); + } + + + /** + *

    Set the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). Prioer to setting the basic Valve, + * the Valve's setContainer() will be called, if it + * implements Contained, with the owning Container as an + * argument. The method may throw an IllegalArgumentException + * if this Valve chooses not to be associated with this Container, or + * IllegalStateException if it is already associated with + * a different Container.

    + * + * @param valve Valve to be distinguished as the basic Valve + */ + public void setBasic(Valve valve) { + + pipeline.setBasic(valve); + + } + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + + if (!started) + return; + + if (cluster != null) { + try { + cluster.backgroundProcess(); + } catch (Exception e) { + log.warn(sm.getString("containerBase.backgroundProcess.cluster", cluster), e); + } + } + if (loader != null) { + try { + loader.backgroundProcess(); + } catch (Exception e) { + log.warn(sm.getString("containerBase.backgroundProcess.loader", loader), e); + } + } + if (manager != null) { + try { + manager.backgroundProcess(); + } catch (Exception e) { + log.warn(sm.getString("containerBase.backgroundProcess.manager", manager), e); + } + } + if (realm != null) { + try { + realm.backgroundProcess(); + } catch (Exception e) { + log.warn(sm.getString("containerBase.backgroundProcess.realm", realm), e); + } + } + Valve current = pipeline.getFirst(); + while (current != null) { + try { + current.backgroundProcess(); + } catch (Exception e) { + log.warn(sm.getString("containerBase.backgroundProcess.valve", current), e); + } + current = current.getNext(); + } + lifecycle.fireLifecycleEvent(Lifecycle.PERIODIC_EVENT, null); + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Notify all container event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param data Event data + */ + public void fireContainerEvent(String type, Object data) { + + if (listeners.size() < 1) + return; + ContainerEvent event = new ContainerEvent(this, type, data); + ContainerListener list[] = new ContainerListener[0]; + synchronized (listeners) { + list = (ContainerListener[]) listeners.toArray(list); + } + for (int i = 0; i < list.length; i++) + ((ContainerListener) list[i]).containerEvent(event); + + } + + + /** + * Return the abbreviated name of this container for logging messsages + */ + protected String logName() { + + if (logName != null) { + return logName; + } + String loggerName = null; + Container current = this; + while (current != null) { + String name = current.getName(); + if ((name == null) || (name.equals(""))) { + name = "/"; + } + loggerName = "[" + name + "]" + + ((loggerName != null) ? ("." + loggerName) : ""); + current = current.getParent(); + } + logName = ContainerBase.class.getName() + "." + loggerName; + return logName; + + } + + + // -------------------- JMX and Registration -------------------- + protected String type; + protected String domain; + protected String suffix; + protected ObjectName oname; + protected ObjectName controller; + protected transient MBeanServer mserver; + + public ObjectName getJmxName() { + return oname; + } + + public String getObjectName() { + if (oname != null) { + return oname.toString(); + } else return null; + } + + public String getDomain() { + if( domain==null ) { + Container parent=this; + while( parent != null && + !( parent instanceof StandardEngine) ) { + parent=parent.getParent(); + } + if( parent instanceof StandardEngine ) { + domain=((StandardEngine)parent).getDomain(); + } + } + return domain; + } + + public void setDomain(String domain) { + this.domain=domain; + } + + public String getType() { + return type; + } + + protected String getJSR77Suffix() { + return suffix; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + if (name == null ){ + return null; + } + + domain=name.getDomain(); + + type=name.getKeyProperty("type"); + if( type==null ) { + type=name.getKeyProperty("j2eeType"); + } + + String j2eeApp=name.getKeyProperty("J2EEApplication"); + String j2eeServer=name.getKeyProperty("J2EEServer"); + if( j2eeApp==null ) { + j2eeApp="none"; + } + if( j2eeServer==null ) { + j2eeServer="none"; + } + suffix=",J2EEApplication=" + j2eeApp + ",J2EEServer=" + j2eeServer; + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + public ObjectName[] getChildren() { + ObjectName result[]=new ObjectName[children.size()]; + Iterator it=children.values().iterator(); + int i=0; + while( it.hasNext() ) { + Object next=it.next(); + if( next instanceof ContainerBase ) { + result[i++]=((ContainerBase)next).getJmxName(); + } + } + return result; + } + + public ObjectName createObjectName(String domain, ObjectName parent) + throws Exception + { + if( log.isDebugEnabled()) + log.debug("Create ObjectName " + domain + " " + parent ); + return null; + } + + public String getContainerSuffix() { + Container container=this; + Container context=null; + Container host=null; + Container servlet=null; + + StringBuffer suffix=new StringBuffer(); + + if( container instanceof StandardHost ) { + host=container; + } else if( container instanceof StandardContext ) { + host=container.getParent(); + context=container; + } else if( container instanceof StandardWrapper ) { + context=container.getParent(); + host=context.getParent(); + servlet=container; + } + if( context!=null ) { + String path=((StandardContext)context).getPath(); + suffix.append(",path=").append((path.equals("")) ? "/" : path); + } + if( host!=null ) suffix.append(",host=").append( host.getName() ); + if( servlet != null ) { + String name=container.getName(); + suffix.append(",servlet="); + suffix.append((name=="") ? "/" : name); + } + return suffix.toString(); + } + + + /** + * Start the background thread that will periodically check for + * session timeouts. + */ + protected void threadStart() { + + if (thread != null) + return; + if (backgroundProcessorDelay <= 0) + return; + + threadDone = false; + String threadName = "ContainerBackgroundProcessor[" + toString() + "]"; + thread = new Thread(new ContainerBackgroundProcessor(), threadName); + thread.setDaemon(true); + thread.start(); + + } + + + /** + * Stop the background thread that is periodically checking for + * session timeouts. + */ + protected void threadStop() { + + if (thread == null) + return; + + threadDone = true; + thread.interrupt(); + try { + thread.join(); + } catch (InterruptedException e) { + ; + } + + thread = null; + + } + + + // -------------------------------------- ContainerExecuteDelay Inner Class + + + /** + * Private thread class to invoke the backgroundProcess method + * of this container and its children after a fixed delay. + */ + protected class ContainerBackgroundProcessor implements Runnable { + + public void run() { + while (!threadDone) { + try { + Thread.sleep(backgroundProcessorDelay * 1000L); + } catch (InterruptedException e) { + ; + } + if (!threadDone) { + Container parent = (Container) getMappingObject(); + ClassLoader cl = + Thread.currentThread().getContextClassLoader(); + if (parent.getLoader() != null) { + cl = parent.getLoader().getClassLoader(); + } + processChildren(parent, cl); + } + } + } + + protected void processChildren(Container container, ClassLoader cl) { + try { + if (container.getLoader() != null) { + Thread.currentThread().setContextClassLoader + (container.getLoader().getClassLoader()); + } + container.backgroundProcess(); + } catch (Throwable t) { + log.error("Exception invoking periodic operation: ", t); + } finally { + Thread.currentThread().setContextClassLoader(cl); + } + Container[] children = container.findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i].getBackgroundProcessorDelay() <= 0) { + processChildren(children[i], cl); + } + } + } + + } + + +} diff --git a/java/org/apache/catalina/core/DummyRequest.java b/java/org/apache/catalina/core/DummyRequest.java index 140f7819a..68e87e3ed 100644 --- a/java/org/apache/catalina/core/DummyRequest.java +++ b/java/org/apache/catalina/core/DummyRequest.java @@ -1,267 +1,267 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.UnsupportedEncodingException; -import java.net.Socket; -import java.security.Principal; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.Locale; -import java.util.Map; - -import javax.servlet.FilterChain; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletInputStream; -import javax.servlet.ServletRequest; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Context; -import org.apache.catalina.Host; -import org.apache.catalina.Wrapper; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.connector.Response; -import org.apache.tomcat.util.buf.MessageBytes; - - -/** - * Dummy request object, used for request dispatcher mapping, as well as - * JSP precompilation. - * - * @author Remy Maucherat - * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ - */ - -public class DummyRequest - implements HttpServletRequest { - - public DummyRequest() { - } - - public DummyRequest(String contextPath, String decodedURI, - String queryString) { - this.contextPath = contextPath; - this.decodedURI = decodedURI; - this.queryString = queryString; - } - - protected String contextPath = null; - protected String decodedURI = null; - protected String queryString = null; - - protected String pathInfo = null; - protected String servletPath = null; - protected Wrapper wrapper = null; - - protected FilterChain filterChain = null; - - private static Enumeration dummyEnum = new Enumeration(){ - public boolean hasMoreElements(){ - return false; - } - public Object nextElement(){ - return null; - } - }; - - public String getContextPath() { - return (contextPath); - } - - public MessageBytes getContextPathMB() { - return null; - } - - public ServletRequest getRequest() { - return (this); - } - - public String getDecodedRequestURI() { - return decodedURI; - } - - public MessageBytes getDecodedRequestURIMB() { - return null; - } - - public FilterChain getFilterChain() { - return (this.filterChain); - } - - public void setFilterChain(FilterChain filterChain) { - this.filterChain = filterChain; - } - - public String getQueryString() { - return queryString; - } - - public void setQueryString(String query) { - queryString = query; - } - - public String getPathInfo() { - return pathInfo; - } - - public void setPathInfo(String path) { - pathInfo = path; - } - - public MessageBytes getPathInfoMB() { - return null; - } - - public MessageBytes getRequestPathMB() { - return null; - } - - public String getServletPath() { - return servletPath; - } - - public void setServletPath(String path) { - servletPath = path; - } - - public MessageBytes getServletPathMB() { - return null; - } - - public Wrapper getWrapper() { - return (this.wrapper); - } - - public void setWrapper(Wrapper wrapper) { - this.wrapper = wrapper; - } - - public String getAuthorization() { return null; } - public void setAuthorization(String authorization) {} - public Connector getConnector() { return null; } - public void setConnector(Connector connector) {} - public Context getContext() { return null; } - public void setContext(Context context) {} - public Host getHost() { return null; } - public void setHost(Host host) {} - public String getInfo() { return null; } - public Response getResponse() { return null; } - public void setResponse(Response response) {} - public Socket getSocket() { return null; } - public void setSocket(Socket socket) {} - public InputStream getStream() { return null; } - public void setStream(InputStream input) {} - public void addLocale(Locale locale) {} - public ServletInputStream createInputStream() throws IOException { - return null; - } - public void finishRequest() throws IOException {} - public Object getNote(String name) { return null; } - public Iterator getNoteNames() { return null; } - public void removeNote(String name) {} - public void setContentType(String type) {} - public void setNote(String name, Object value) {} - public void setProtocol(String protocol) {} - public void setRemoteAddr(String remoteAddr) {} - public void setRemoteHost(String remoteHost) {} - public void setScheme(String scheme) {} - public void setServerName(String name) {} - public void setServerPort(int port) {} - public Object getAttribute(String name) { return null; } - public Enumeration getAttributeNames() { return null; } - public String getCharacterEncoding() { return null; } - public int getContentLength() { return -1; } - public void setContentLength(int length) {} - public String getContentType() { return null; } - public ServletInputStream getInputStream() throws IOException { - return null; - } - public Locale getLocale() { return null; } - public Enumeration getLocales() { return null; } - public String getProtocol() { return null; } - public BufferedReader getReader() throws IOException { return null; } - public String getRealPath(String path) { return null; } - public String getRemoteAddr() { return null; } - public String getRemoteHost() { return null; } - public String getScheme() { return null; } - public String getServerName() { return null; } - public int getServerPort() { return -1; } - public boolean isSecure() { return false; } - public void removeAttribute(String name) {} - public void setAttribute(String name, Object value) {} - public void setCharacterEncoding(String enc) - throws UnsupportedEncodingException {} - public void addCookie(Cookie cookie) {} - public void addHeader(String name, String value) {} - public void addParameter(String name, String values[]) {} - public void clearCookies() {} - public void clearHeaders() {} - public void clearLocales() {} - public void clearParameters() {} - public void recycle() {} - public void setAuthType(String authType) {} - public void setContextPath(String path) {} - public void setMethod(String method) {} - public void setRequestedSessionCookie(boolean flag) {} - public void setRequestedSessionId(String id) {} - public void setRequestedSessionURL(boolean flag) {} - public void setRequestURI(String uri) {} - public void setSecure(boolean secure) {} - public void setUserPrincipal(Principal principal) {} - public String getParameter(String name) { return null; } - public Map getParameterMap() { return null; } - public Enumeration getParameterNames() { return dummyEnum; } - public String[] getParameterValues(String name) { return null; } - public RequestDispatcher getRequestDispatcher(String path) { - return null; - } - public String getAuthType() { return null; } - public Cookie[] getCookies() { return null; } - public long getDateHeader(String name) { return -1; } - public String getHeader(String name) { return null; } - public Enumeration getHeaders(String name) { return null; } - public Enumeration getHeaderNames() { return null; } - public int getIntHeader(String name) { return -1; } - public String getMethod() { return null; } - public String getPathTranslated() { return null; } - public String getRemoteUser() { return null; } - public String getRequestedSessionId() { return null; } - public String getRequestURI() { return null; } - public void setDecodedRequestURI(String uri) {} - public StringBuffer getRequestURL() { return null; } - public HttpSession getSession() { return null; } - public HttpSession getSession(boolean create) { return null; } - public boolean isRequestedSessionIdFromCookie() { return false; } - public boolean isRequestedSessionIdFromURL() { return false; } - public boolean isRequestedSessionIdFromUrl() { return false; } - public boolean isRequestedSessionIdValid() { return false; } - public boolean isUserInRole(String role) { return false; } - public Principal getUserPrincipal() { return null; } - public String getLocalAddr() { return null; } - public String getLocalName() { return null; } - public int getLocalPort() { return -1; } - public int getRemotePort() { return -1; } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.Socket; +import java.security.Principal; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.FilterChain; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.connector.Response; +import org.apache.tomcat.util.buf.MessageBytes; + + +/** + * Dummy request object, used for request dispatcher mapping, as well as + * JSP precompilation. + * + * @author Remy Maucherat + * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ + */ + +public class DummyRequest + implements HttpServletRequest { + + public DummyRequest() { + } + + public DummyRequest(String contextPath, String decodedURI, + String queryString) { + this.contextPath = contextPath; + this.decodedURI = decodedURI; + this.queryString = queryString; + } + + protected String contextPath = null; + protected String decodedURI = null; + protected String queryString = null; + + protected String pathInfo = null; + protected String servletPath = null; + protected Wrapper wrapper = null; + + protected FilterChain filterChain = null; + + private static Enumeration dummyEnum = new Enumeration(){ + public boolean hasMoreElements(){ + return false; + } + public Object nextElement(){ + return null; + } + }; + + public String getContextPath() { + return (contextPath); + } + + public MessageBytes getContextPathMB() { + return null; + } + + public ServletRequest getRequest() { + return (this); + } + + public String getDecodedRequestURI() { + return decodedURI; + } + + public MessageBytes getDecodedRequestURIMB() { + return null; + } + + public FilterChain getFilterChain() { + return (this.filterChain); + } + + public void setFilterChain(FilterChain filterChain) { + this.filterChain = filterChain; + } + + public String getQueryString() { + return queryString; + } + + public void setQueryString(String query) { + queryString = query; + } + + public String getPathInfo() { + return pathInfo; + } + + public void setPathInfo(String path) { + pathInfo = path; + } + + public MessageBytes getPathInfoMB() { + return null; + } + + public MessageBytes getRequestPathMB() { + return null; + } + + public String getServletPath() { + return servletPath; + } + + public void setServletPath(String path) { + servletPath = path; + } + + public MessageBytes getServletPathMB() { + return null; + } + + public Wrapper getWrapper() { + return (this.wrapper); + } + + public void setWrapper(Wrapper wrapper) { + this.wrapper = wrapper; + } + + public String getAuthorization() { return null; } + public void setAuthorization(String authorization) {} + public Connector getConnector() { return null; } + public void setConnector(Connector connector) {} + public Context getContext() { return null; } + public void setContext(Context context) {} + public Host getHost() { return null; } + public void setHost(Host host) {} + public String getInfo() { return null; } + public Response getResponse() { return null; } + public void setResponse(Response response) {} + public Socket getSocket() { return null; } + public void setSocket(Socket socket) {} + public InputStream getStream() { return null; } + public void setStream(InputStream input) {} + public void addLocale(Locale locale) {} + public ServletInputStream createInputStream() throws IOException { + return null; + } + public void finishRequest() throws IOException {} + public Object getNote(String name) { return null; } + public Iterator getNoteNames() { return null; } + public void removeNote(String name) {} + public void setContentType(String type) {} + public void setNote(String name, Object value) {} + public void setProtocol(String protocol) {} + public void setRemoteAddr(String remoteAddr) {} + public void setRemoteHost(String remoteHost) {} + public void setScheme(String scheme) {} + public void setServerName(String name) {} + public void setServerPort(int port) {} + public Object getAttribute(String name) { return null; } + public Enumeration getAttributeNames() { return null; } + public String getCharacterEncoding() { return null; } + public int getContentLength() { return -1; } + public void setContentLength(int length) {} + public String getContentType() { return null; } + public ServletInputStream getInputStream() throws IOException { + return null; + } + public Locale getLocale() { return null; } + public Enumeration getLocales() { return null; } + public String getProtocol() { return null; } + public BufferedReader getReader() throws IOException { return null; } + public String getRealPath(String path) { return null; } + public String getRemoteAddr() { return null; } + public String getRemoteHost() { return null; } + public String getScheme() { return null; } + public String getServerName() { return null; } + public int getServerPort() { return -1; } + public boolean isSecure() { return false; } + public void removeAttribute(String name) {} + public void setAttribute(String name, Object value) {} + public void setCharacterEncoding(String enc) + throws UnsupportedEncodingException {} + public void addCookie(Cookie cookie) {} + public void addHeader(String name, String value) {} + public void addParameter(String name, String values[]) {} + public void clearCookies() {} + public void clearHeaders() {} + public void clearLocales() {} + public void clearParameters() {} + public void recycle() {} + public void setAuthType(String authType) {} + public void setContextPath(String path) {} + public void setMethod(String method) {} + public void setRequestedSessionCookie(boolean flag) {} + public void setRequestedSessionId(String id) {} + public void setRequestedSessionURL(boolean flag) {} + public void setRequestURI(String uri) {} + public void setSecure(boolean secure) {} + public void setUserPrincipal(Principal principal) {} + public String getParameter(String name) { return null; } + public Map getParameterMap() { return null; } + public Enumeration getParameterNames() { return dummyEnum; } + public String[] getParameterValues(String name) { return null; } + public RequestDispatcher getRequestDispatcher(String path) { + return null; + } + public String getAuthType() { return null; } + public Cookie[] getCookies() { return null; } + public long getDateHeader(String name) { return -1; } + public String getHeader(String name) { return null; } + public Enumeration getHeaders(String name) { return null; } + public Enumeration getHeaderNames() { return null; } + public int getIntHeader(String name) { return -1; } + public String getMethod() { return null; } + public String getPathTranslated() { return null; } + public String getRemoteUser() { return null; } + public String getRequestedSessionId() { return null; } + public String getRequestURI() { return null; } + public void setDecodedRequestURI(String uri) {} + public StringBuffer getRequestURL() { return null; } + public HttpSession getSession() { return null; } + public HttpSession getSession(boolean create) { return null; } + public boolean isRequestedSessionIdFromCookie() { return false; } + public boolean isRequestedSessionIdFromURL() { return false; } + public boolean isRequestedSessionIdFromUrl() { return false; } + public boolean isRequestedSessionIdValid() { return false; } + public boolean isUserInRole(String role) { return false; } + public Principal getUserPrincipal() { return null; } + public String getLocalAddr() { return null; } + public String getLocalName() { return null; } + public int getLocalPort() { return -1; } + public int getRemotePort() { return -1; } + +} + diff --git a/java/org/apache/catalina/core/DummyResponse.java b/java/org/apache/catalina/core/DummyResponse.java index 574c4ee87..f3b27e0e8 100644 --- a/java/org/apache/catalina/core/DummyResponse.java +++ b/java/org/apache/catalina/core/DummyResponse.java @@ -1,124 +1,124 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; -import java.io.OutputStream; -import java.io.PrintWriter; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.connector.Request; - - -/** - * Dummy response object, used for JSP precompilation. - * - * @author Remy Maucherat - * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ - */ - -public class DummyResponse - implements HttpServletResponse { - - public DummyResponse() { - } - - - public void setAppCommitted(boolean appCommitted) {} - public boolean isAppCommitted() { return false; } - public Connector getConnector() { return null; } - public void setConnector(Connector connector) {} - public int getContentCount() { return -1; } - public Context getContext() { return null; } - public void setContext(Context context) {} - public boolean getIncluded() { return false; } - public void setIncluded(boolean included) {} - public String getInfo() { return null; } - public Request getRequest() { return null; } - public void setRequest(Request request) {} - public ServletResponse getResponse() { return null; } - public OutputStream getStream() { return null; } - public void setStream(OutputStream stream) {} - public void setSuspended(boolean suspended) {} - public boolean isSuspended() { return false; } - public void setError() {} - public boolean isError() { return false; } - public ServletOutputStream createOutputStream() throws IOException { - return null; - } - public void finishResponse() throws IOException {} - public int getContentLength() { return -1; } - public String getContentType() { return null; } - public PrintWriter getReporter() { return null; } - public void recycle() {} - public void write(int b) throws IOException {} - public void write(byte b[]) throws IOException {} - public void write(byte b[], int off, int len) throws IOException {} - public void flushBuffer() throws IOException {} - public int getBufferSize() { return -1; } - public String getCharacterEncoding() { return null; } - public void setCharacterEncoding(String charEncoding) {} - public ServletOutputStream getOutputStream() throws IOException { - return null; - } - public Locale getLocale() { return null; } - public PrintWriter getWriter() throws IOException { return null; } - public boolean isCommitted() { return false; } - public void reset() {} - public void resetBuffer() {} - public void setBufferSize(int size) {} - public void setContentLength(int length) {} - public void setContentType(String type) {} - public void setLocale(Locale locale) {} - - public Cookie[] getCookies() { return null; } - public String getHeader(String name) { return null; } - public String[] getHeaderNames() { return null; } - public String[] getHeaderValues(String name) { return null; } - public String getMessage() { return null; } - public int getStatus() { return -1; } - public void reset(int status, String message) {} - public void addCookie(Cookie cookie) {} - public void addDateHeader(String name, long value) {} - public void addHeader(String name, String value) {} - public void addIntHeader(String name, int value) {} - public boolean containsHeader(String name) { return false; } - public String encodeRedirectURL(String url) { return null; } - public String encodeRedirectUrl(String url) { return null; } - public String encodeURL(String url) { return null; } - public String encodeUrl(String url) { return null; } - public void sendAcknowledgement() throws IOException {} - public void sendError(int status) throws IOException {} - public void sendError(int status, String message) throws IOException {} - public void sendRedirect(String location) throws IOException {} - public void setDateHeader(String name, long value) {} - public void setHeader(String name, String value) {} - public void setIntHeader(String name, int value) {} - public void setStatus(int status) {} - public void setStatus(int status, String message) {} - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.Locale; + +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.connector.Request; + + +/** + * Dummy response object, used for JSP precompilation. + * + * @author Remy Maucherat + * @version $Revision: 302975 $ $Date: 2004-06-23 10:25:04 +0200 (mer., 23 juin 2004) $ + */ + +public class DummyResponse + implements HttpServletResponse { + + public DummyResponse() { + } + + + public void setAppCommitted(boolean appCommitted) {} + public boolean isAppCommitted() { return false; } + public Connector getConnector() { return null; } + public void setConnector(Connector connector) {} + public int getContentCount() { return -1; } + public Context getContext() { return null; } + public void setContext(Context context) {} + public boolean getIncluded() { return false; } + public void setIncluded(boolean included) {} + public String getInfo() { return null; } + public Request getRequest() { return null; } + public void setRequest(Request request) {} + public ServletResponse getResponse() { return null; } + public OutputStream getStream() { return null; } + public void setStream(OutputStream stream) {} + public void setSuspended(boolean suspended) {} + public boolean isSuspended() { return false; } + public void setError() {} + public boolean isError() { return false; } + public ServletOutputStream createOutputStream() throws IOException { + return null; + } + public void finishResponse() throws IOException {} + public int getContentLength() { return -1; } + public String getContentType() { return null; } + public PrintWriter getReporter() { return null; } + public void recycle() {} + public void write(int b) throws IOException {} + public void write(byte b[]) throws IOException {} + public void write(byte b[], int off, int len) throws IOException {} + public void flushBuffer() throws IOException {} + public int getBufferSize() { return -1; } + public String getCharacterEncoding() { return null; } + public void setCharacterEncoding(String charEncoding) {} + public ServletOutputStream getOutputStream() throws IOException { + return null; + } + public Locale getLocale() { return null; } + public PrintWriter getWriter() throws IOException { return null; } + public boolean isCommitted() { return false; } + public void reset() {} + public void resetBuffer() {} + public void setBufferSize(int size) {} + public void setContentLength(int length) {} + public void setContentType(String type) {} + public void setLocale(Locale locale) {} + + public Cookie[] getCookies() { return null; } + public String getHeader(String name) { return null; } + public String[] getHeaderNames() { return null; } + public String[] getHeaderValues(String name) { return null; } + public String getMessage() { return null; } + public int getStatus() { return -1; } + public void reset(int status, String message) {} + public void addCookie(Cookie cookie) {} + public void addDateHeader(String name, long value) {} + public void addHeader(String name, String value) {} + public void addIntHeader(String name, int value) {} + public boolean containsHeader(String name) { return false; } + public String encodeRedirectURL(String url) { return null; } + public String encodeRedirectUrl(String url) { return null; } + public String encodeURL(String url) { return null; } + public String encodeUrl(String url) { return null; } + public void sendAcknowledgement() throws IOException {} + public void sendError(int status) throws IOException {} + public void sendError(int status, String message) throws IOException {} + public void sendRedirect(String location) throws IOException {} + public void setDateHeader(String name, long value) {} + public void setHeader(String name, String value) {} + public void setIntHeader(String name, int value) {} + public void setStatus(int status) {} + public void setStatus(int status, String message) {} + + +} diff --git a/java/org/apache/catalina/core/LocalStrings.properties b/java/org/apache/catalina/core/LocalStrings.properties index 8065a6798..86bb70295 100644 --- a/java/org/apache/catalina/core/LocalStrings.properties +++ b/java/org/apache/catalina/core/LocalStrings.properties @@ -1,187 +1,187 @@ -applicationContext.attributeEvent=Exception thrown by attributes event listener -applicationContext.mapping.error=Error during mapping -applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character -applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character -applicationContext.setAttribute.namenull=Name cannot be null -applicationDispatcher.allocateException=Allocate exception for servlet {0} -applicationDispatcher.deallocateException=Deallocate exception for servlet {0} -applicationDispatcher.forward.ise=Cannot forward after response has been committed -applicationDispatcher.forward.throw=Forwarded resource threw an exception -applicationDispatcher.include.throw=Included resource threw an exception -applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable -applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception -applicationRequest.badParent=Cannot locate parent Request implementation -applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper -applicationResponse.badParent=Cannot locate parent Response implementation -applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper -aprListener.aprInit=The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0} -aprListener.tcnInvalid=An incompatible version {0} of the Apache Tomcat Native library is installed, while Tomcat requires version {1} -aprListener.aprDestroy=Failed shutdown of Apache Portable Runtime -containerBase.addDefaultMapper=Exception configuring default mapper of class {0} -containerBase.alreadyStarted=Container {0} has already been started -containerBase.notConfigured=No basic Valve has been configured -containerBase.notStarted=Container {0} has not been started -containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process -containerBase.backgroundProcess.loader=Exception processing loader {0} background process -containerBase.backgroundProcess.manager=Exception processing manager {0} background process -containerBase.backgroundProcess.realm=Exception processing realm {0} background process -containerBase.backgroundProcess.valve=Exception processing valve {0} background process -fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started -fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started -filterChain.filter=Filter execution threw an exception -filterChain.servlet=Servlet execution threw an exception -httpContextMapper.container=This container is not a StandardContext -httpEngineMapper.container=This container is not a StandardEngine -httpHostMapper.container=This container is not a StandardHost -interceptorValve.alreadyStarted=InterceptorValve has already been started -interceptorValve.notStarted=InterceptorValve has not yet been started -naming.bindFailed=Failed to bind object: {0} -naming.jmxRegistrationFailed=Failed to register in JMX: {0} -naming.unbindFailed=Failed to unbind object: {0} -naming.invalidEnvEntryType=Environment entry {0} has an invalid type -naming.invalidEnvEntryValue=Environment entry {0} has an invalid value -naming.namingContextCreationFailed=Creation of the naming context failed: {0} -standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper -standardContext.alreadyStarted=Context has already been started -standardContext.applicationListener=Error configuring application listener of class {0} -standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s) -standardContext.badRequest=Invalid request path ({0}). -standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched. -standardContext.errorPage.error=Error page location {0} must start with a ''/'' -standardContext.errorPage.required=ErrorPage cannot be null -standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4 -standardContext.filterMap.either=Filter mapping must specify either a or a -standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0} -standardContext.filterMap.pattern=Invalid {0} in filter mapping -standardContext.filterStart=Exception starting filter {0} -standardContext.filterStartFailed=Failed to start application Filters successfully -standardContext.requestListenerStartFailed=Failed to start request listener valve successfully -standardContext.requestListenerConfig.added=Added request listener Valve -standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0} -standardContext.isUnavailable=This application is not currently available -standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0} -standardContext.listenerStartFailed=Failed to start application Listeners successfully -standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0} -standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/' -standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4 -standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/' -standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 -standardContext.loginConfig.required=LoginConfig cannot be null -standardContext.mappingError=MAPPING configuration error for relative URI {0} -standardContext.notFound=The requested resource ({0}) is not available. -standardContext.notReloadable=Reloading is disabled on this Context -standardContext.notStarted=Context has not yet been started -standardContext.notWrapper=Child of a Context must be a Wrapper -standardContext.parameter.duplicate=Duplicate context initialization parameter {0} -standardContext.parameter.required=Both parameter name and parameter value are required -standardContext.reloadingCompleted=Reloading this Context is completed -standardContext.reloadingFailed=Reloading this Context failed due to previous errors -standardContext.reloadingStarted=Reloading this Context has started -standardContext.resourcesStart=Error starting static Resources -standardContext.securityConstraint.pattern=Invalid {0} in security constraint -standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0} -standardContext.servletMap.pattern=Invalid {0} in servlet mapping -standardContext.startCleanup=Exception during cleanup after start failed -standardContext.startFailed=Context [{0}] startup failed due to previous errors -standardContext.startingLoader=Exception starting Loader -standardContext.startingManager=Exception starting Manager -standardContext.startingWrapper=Exception starting Wrapper for servlet {0} -standardContext.stoppingContext=Exception stopping Context -standardContext.stoppingLoader=Exception stopping Loader -standardContext.stoppingManager=Exception stopping Manager -standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0} -standardContext.urlDecode=Cannot URL decode request path {0} -standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4 -standardContext.urlValidate=Cannot validate URL decoded request path {0} -standardContext.wrapper.error=JSP file {0} must start with a ''/' -standardContext.wrapper.warning=WARNING: JSP file {0} must start with a ''/'' in Servlet 2.4 -standardEngine.alreadyStarted=Engine has already been started -standardEngine.mappingError=MAPPING configuration error for server name {0} -standardEngine.noHost=No Host matches server name {0} -standardEngine.noHostHeader=HTTP/1.1 request with no Host: header -standardEngine.notHost=Child of an Engine must be a Host -standardEngine.notParent=Engine cannot have a parent Container -standardEngine.notStarted=Engine has not yet been started -standardEngine.unfoundHost=Virtual host {0} not found -standardEngine.unknownHost=No server host specified in this request -standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0} -standardHost.accessBase=Cannot access document base directory {0} -standardHost.alreadyStarted=Host has already been started -standardHost.appBase=Application base directory {0} does not exist -standardHost.clientAbort=Remote Client Aborted Request, IOException: {0} -standardHost.configRequired=URL to configuration file is required -standardHost.configNotAllowed=Use of configuration file is not allowed -standardHost.installBase=Only web applications in the Host web application directory can be installed -standardHost.installing=Installing web application at context path {0} from URL {1} -standardHost.installingWAR=Installing web application from URL {0} -standardHost.installingXML=Processing Context configuration file URL {0} -standardHost.installError=Error deploying application at context path {0} -standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0} -standardHost.docBase=Document base directory {0} already exists -standardHost.mappingError=MAPPING configuration error for request URI {0} -standardHost.noContext=No Context configured to process this request -standardHost.noHost=No Host configured to process this request -standardHost.notContext=Child of a Host must be a Context -standardHost.notStarted=Host has not yet been started -standardHost.nullName=Host name is required -standardHost.pathFormat=Invalid context path: {0} -standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1} -standardHost.pathMissing=Context path {0} is not currently in use -standardHost.pathRequired=Context path is required -standardHost.pathUsed=Context path {0} is already in use -standardHost.removing=Removing web application at context path {0} -standardHost.removeError=Error removing application at context path {0} -standardHost.start=Starting web application at context path {0} -standardHost.stop=Stopping web application at context path {0} -standardHost.unfoundContext=Cannot find context for request URI {0} -standardHost.warRequired=URL to web application archive is required -standardHost.warURL=Invalid URL for web application archive: {0} -standardHost.validationEnabled=XML validation enabled -standardHost.validationDisabled=XML validation disabled -standardPipeline.alreadyStarted=Pipeline has already been started -standardPipeline.notStarted=Pipeline has not been started -standardPipeline.noValve=No more Valves in the Pipeline processing this request -standardServer.addContainer.ise=No connectors available to associate this container with -standardServer.initialize.initialized=This server has already been initialized -standardServer.start.connectors=At least one connector is not associated with any container -standardServer.start.started=This server has already been started -standardServer.stop.notStarted=This server has not yet been started -standardService.initialize.initialized=This service has already been initialized -standardService.initialize.failed=Service initializing at {0} failed -standardService.register.failed=Error registering Service at domain {0} -standardService.start.name=Starting service {0} -standardService.start.started=This service has already been started -standardService.stop.name=Stopping service {0} -standardService.stop.notStarted=This service has not yet been started -standardWrapper.allocate=Error allocating a servlet instance -standardWrapper.allocateException=Allocate exception for servlet {0} -standardWrapper.containerServlet=Loading container servlet {0} -standardWrapper.createFilters=Create filters exception for servlet {0} -standardWrapper.deallocateException=Deallocate exception for servlet {0} -standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception -standardWrapper.exception0=Tomcat Exception Report -standardWrapper.exception1=A Servlet Exception Has Occurred -standardWrapper.exception2=Exception Report: -standardWrapper.exception3=Root Cause: -standardWrapper.initException=Servlet.init() for servlet {0} threw exception -standardWrapper.instantiate=Error instantiating servlet class {0} -standardWrapper.isUnavailable=Servlet {0} is currently unavailable -standardWrapper.jasperLoader=Using Jasper classloader for servlet {0} -standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character -standardWrapper.loadException=Servlet {0} threw load() exception -standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on -standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0} -standardWrapper.notChild=Wrapper container may not have child containers -standardWrapper.notClass=No servlet class has been specified for servlet {0} -standardWrapper.notContext=Parent container of a Wrapper must be a Context -standardWrapper.notFound=Servlet {0} is not available -standardWrapper.notServlet=Class {0} is not a Servlet -standardWrapper.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application -standardWrapper.releaseFilters=Release filters exception for servlet {0} -standardWrapper.serviceException=Servlet.service() for servlet {0} threw exception -standardWrapper.statusHeader=HTTP Status {0} - {1} -standardWrapper.statusTitle=Tomcat Error Report -standardWrapper.unavailable=Marking servlet {0} as unavailable -standardWrapper.unloadException=Servlet {0} threw unload() exception -standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded -standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated +applicationContext.attributeEvent=Exception thrown by attributes event listener +applicationContext.mapping.error=Error during mapping +applicationContext.requestDispatcher.iae=Path {0} does not start with a "/" character +applicationContext.resourcePaths.iae=Path {0} does not start with a "/" character +applicationContext.setAttribute.namenull=Name cannot be null +applicationDispatcher.allocateException=Allocate exception for servlet {0} +applicationDispatcher.deallocateException=Deallocate exception for servlet {0} +applicationDispatcher.forward.ise=Cannot forward after response has been committed +applicationDispatcher.forward.throw=Forwarded resource threw an exception +applicationDispatcher.include.throw=Included resource threw an exception +applicationDispatcher.isUnavailable=Servlet {0} is currently unavailable +applicationDispatcher.serviceException=Servlet.service() for servlet {0} threw exception +applicationRequest.badParent=Cannot locate parent Request implementation +applicationRequest.badRequest=Request is not a javax.servlet.ServletRequestWrapper +applicationResponse.badParent=Cannot locate parent Response implementation +applicationResponse.badResponse=Response is not a javax.servlet.ServletResponseWrapper +aprListener.aprInit=The Apache Tomcat Native library which allows optimal performance in production environments was not found on the java.library.path: {0} +aprListener.tcnInvalid=An incompatible version {0} of the Apache Tomcat Native library is installed, while Tomcat requires version {1} +aprListener.aprDestroy=Failed shutdown of Apache Portable Runtime +containerBase.addDefaultMapper=Exception configuring default mapper of class {0} +containerBase.alreadyStarted=Container {0} has already been started +containerBase.notConfigured=No basic Valve has been configured +containerBase.notStarted=Container {0} has not been started +containerBase.backgroundProcess.cluster=Exception processing cluster {0} background process +containerBase.backgroundProcess.loader=Exception processing loader {0} background process +containerBase.backgroundProcess.manager=Exception processing manager {0} background process +containerBase.backgroundProcess.realm=Exception processing realm {0} background process +containerBase.backgroundProcess.valve=Exception processing valve {0} background process +fastEngineMapper.alreadyStarted=FastEngineMapper {0} has already been started +fastEngineMapper.notStarted=FastEngineMapper {0} has not yet been started +filterChain.filter=Filter execution threw an exception +filterChain.servlet=Servlet execution threw an exception +httpContextMapper.container=This container is not a StandardContext +httpEngineMapper.container=This container is not a StandardEngine +httpHostMapper.container=This container is not a StandardHost +interceptorValve.alreadyStarted=InterceptorValve has already been started +interceptorValve.notStarted=InterceptorValve has not yet been started +naming.bindFailed=Failed to bind object: {0} +naming.jmxRegistrationFailed=Failed to register in JMX: {0} +naming.unbindFailed=Failed to unbind object: {0} +naming.invalidEnvEntryType=Environment entry {0} has an invalid type +naming.invalidEnvEntryValue=Environment entry {0} has an invalid value +naming.namingContextCreationFailed=Creation of the naming context failed: {0} +standardContext.invalidWrapperClass={0} is not a subclass of StandardWrapper +standardContext.alreadyStarted=Context has already been started +standardContext.applicationListener=Error configuring application listener of class {0} +standardContext.applicationSkipped=Skipped installing application listeners due to previous error(s) +standardContext.badRequest=Invalid request path ({0}). +standardContext.crlfinurl=The URL pattern "{0}" contains a CR or LF and so can never be matched. +standardContext.errorPage.error=Error page location {0} must start with a ''/'' +standardContext.errorPage.required=ErrorPage cannot be null +standardContext.errorPage.warning=WARNING: Error page location {0} must start with a ''/'' in Servlet 2.4 +standardContext.filterMap.either=Filter mapping must specify either a or a +standardContext.filterMap.name=Filter mapping specifies an unknown filter name {0} +standardContext.filterMap.pattern=Invalid {0} in filter mapping +standardContext.filterStart=Exception starting filter {0} +standardContext.filterStartFailed=Failed to start application Filters successfully +standardContext.requestListenerStartFailed=Failed to start request listener valve successfully +standardContext.requestListenerConfig.added=Added request listener Valve +standardContext.requestListenerConfig.error=Exception adding request listener Valve: {0} +standardContext.isUnavailable=This application is not currently available +standardContext.listenerStart=Exception sending context initialized event to listener instance of class {0} +standardContext.listenerStartFailed=Failed to start application Listeners successfully +standardContext.listenerStop=Exception sending context destroyed event to listener instance of class {0} +standardContext.loginConfig.errorPage=Form error page {0} must start with a ''/' +standardContext.loginConfig.errorWarning=WARNING: Form error page {0} must start with a ''/'' in Servlet 2.4 +standardContext.loginConfig.loginPage=Form login page {0} must start with a ''/' +standardContext.loginConfig.loginWarning=WARNING: Form login page {0} must start with a ''/'' in Servlet 2.4 +standardContext.loginConfig.required=LoginConfig cannot be null +standardContext.mappingError=MAPPING configuration error for relative URI {0} +standardContext.notFound=The requested resource ({0}) is not available. +standardContext.notReloadable=Reloading is disabled on this Context +standardContext.notStarted=Context has not yet been started +standardContext.notWrapper=Child of a Context must be a Wrapper +standardContext.parameter.duplicate=Duplicate context initialization parameter {0} +standardContext.parameter.required=Both parameter name and parameter value are required +standardContext.reloadingCompleted=Reloading this Context is completed +standardContext.reloadingFailed=Reloading this Context failed due to previous errors +standardContext.reloadingStarted=Reloading this Context has started +standardContext.resourcesStart=Error starting static Resources +standardContext.securityConstraint.pattern=Invalid {0} in security constraint +standardContext.servletMap.name=Servlet mapping specifies an unknown servlet name {0} +standardContext.servletMap.pattern=Invalid {0} in servlet mapping +standardContext.startCleanup=Exception during cleanup after start failed +standardContext.startFailed=Context [{0}] startup failed due to previous errors +standardContext.startingLoader=Exception starting Loader +standardContext.startingManager=Exception starting Manager +standardContext.startingWrapper=Exception starting Wrapper for servlet {0} +standardContext.stoppingContext=Exception stopping Context +standardContext.stoppingLoader=Exception stopping Loader +standardContext.stoppingManager=Exception stopping Manager +standardContext.stoppingWrapper=Exception stopping Wrapper for servlet {0} +standardContext.urlDecode=Cannot URL decode request path {0} +standardContext.urlPattern.patternWarning=WARNING: URL pattern {0} must start with a ''/'' in Servlet 2.4 +standardContext.urlValidate=Cannot validate URL decoded request path {0} +standardContext.wrapper.error=JSP file {0} must start with a ''/' +standardContext.wrapper.warning=WARNING: JSP file {0} must start with a ''/'' in Servlet 2.4 +standardEngine.alreadyStarted=Engine has already been started +standardEngine.mappingError=MAPPING configuration error for server name {0} +standardEngine.noHost=No Host matches server name {0} +standardEngine.noHostHeader=HTTP/1.1 request with no Host: header +standardEngine.notHost=Child of an Engine must be a Host +standardEngine.notParent=Engine cannot have a parent Container +standardEngine.notStarted=Engine has not yet been started +standardEngine.unfoundHost=Virtual host {0} not found +standardEngine.unknownHost=No server host specified in this request +standardEngine.unregister.mbeans.failed=Error in destroy() for mbean file {0} +standardHost.accessBase=Cannot access document base directory {0} +standardHost.alreadyStarted=Host has already been started +standardHost.appBase=Application base directory {0} does not exist +standardHost.clientAbort=Remote Client Aborted Request, IOException: {0} +standardHost.configRequired=URL to configuration file is required +standardHost.configNotAllowed=Use of configuration file is not allowed +standardHost.installBase=Only web applications in the Host web application directory can be installed +standardHost.installing=Installing web application at context path {0} from URL {1} +standardHost.installingWAR=Installing web application from URL {0} +standardHost.installingXML=Processing Context configuration file URL {0} +standardHost.installError=Error deploying application at context path {0} +standardHost.invalidErrorReportValveClass=Couldn''t load specified error report valve class: {0} +standardHost.docBase=Document base directory {0} already exists +standardHost.mappingError=MAPPING configuration error for request URI {0} +standardHost.noContext=No Context configured to process this request +standardHost.noHost=No Host configured to process this request +standardHost.notContext=Child of a Host must be a Context +standardHost.notStarted=Host has not yet been started +standardHost.nullName=Host name is required +standardHost.pathFormat=Invalid context path: {0} +standardHost.pathMatch=Context path {0} must match the directory or WAR file name: {1} +standardHost.pathMissing=Context path {0} is not currently in use +standardHost.pathRequired=Context path is required +standardHost.pathUsed=Context path {0} is already in use +standardHost.removing=Removing web application at context path {0} +standardHost.removeError=Error removing application at context path {0} +standardHost.start=Starting web application at context path {0} +standardHost.stop=Stopping web application at context path {0} +standardHost.unfoundContext=Cannot find context for request URI {0} +standardHost.warRequired=URL to web application archive is required +standardHost.warURL=Invalid URL for web application archive: {0} +standardHost.validationEnabled=XML validation enabled +standardHost.validationDisabled=XML validation disabled +standardPipeline.alreadyStarted=Pipeline has already been started +standardPipeline.notStarted=Pipeline has not been started +standardPipeline.noValve=No more Valves in the Pipeline processing this request +standardServer.addContainer.ise=No connectors available to associate this container with +standardServer.initialize.initialized=This server has already been initialized +standardServer.start.connectors=At least one connector is not associated with any container +standardServer.start.started=This server has already been started +standardServer.stop.notStarted=This server has not yet been started +standardService.initialize.initialized=This service has already been initialized +standardService.initialize.failed=Service initializing at {0} failed +standardService.register.failed=Error registering Service at domain {0} +standardService.start.name=Starting service {0} +standardService.start.started=This service has already been started +standardService.stop.name=Stopping service {0} +standardService.stop.notStarted=This service has not yet been started +standardWrapper.allocate=Error allocating a servlet instance +standardWrapper.allocateException=Allocate exception for servlet {0} +standardWrapper.containerServlet=Loading container servlet {0} +standardWrapper.createFilters=Create filters exception for servlet {0} +standardWrapper.deallocateException=Deallocate exception for servlet {0} +standardWrapper.destroyException=Servlet.destroy() for servlet {0} threw exception +standardWrapper.exception0=Tomcat Exception Report +standardWrapper.exception1=A Servlet Exception Has Occurred +standardWrapper.exception2=Exception Report: +standardWrapper.exception3=Root Cause: +standardWrapper.initException=Servlet.init() for servlet {0} threw exception +standardWrapper.instantiate=Error instantiating servlet class {0} +standardWrapper.isUnavailable=Servlet {0} is currently unavailable +standardWrapper.jasperLoader=Using Jasper classloader for servlet {0} +standardWrapper.jspFile.format=JSP file {0} does not start with a ''/'' character +standardWrapper.loadException=Servlet {0} threw load() exception +standardWrapper.missingClass=Wrapper cannot find servlet class {0} or a class it depends on +standardWrapper.missingLoader=Wrapper cannot find Loader for servlet {0} +standardWrapper.notChild=Wrapper container may not have child containers +standardWrapper.notClass=No servlet class has been specified for servlet {0} +standardWrapper.notContext=Parent container of a Wrapper must be a Context +standardWrapper.notFound=Servlet {0} is not available +standardWrapper.notServlet=Class {0} is not a Servlet +standardWrapper.privilegedServlet=Servlet of class {0} is privileged and cannot be loaded by this web application +standardWrapper.releaseFilters=Release filters exception for servlet {0} +standardWrapper.serviceException=Servlet.service() for servlet {0} threw exception +standardWrapper.statusHeader=HTTP Status {0} - {1} +standardWrapper.statusTitle=Tomcat Error Report +standardWrapper.unavailable=Marking servlet {0} as unavailable +standardWrapper.unloadException=Servlet {0} threw unload() exception +standardWrapper.unloading=Cannot allocate servlet {0} because it is being unloaded +standardWrapper.waiting=Waiting for {0} instance(s) to be deallocated diff --git a/java/org/apache/catalina/core/LocalStrings_es.properties b/java/org/apache/catalina/core/LocalStrings_es.properties index c8e983d01..2281b6c9c 100644 --- a/java/org/apache/catalina/core/LocalStrings_es.properties +++ b/java/org/apache/catalina/core/LocalStrings_es.properties @@ -1,172 +1,172 @@ -applicationContext.attributeEvent=Excepción lanzada por escuchador de eventos de atributos -applicationContext.mapping.error=Error durante mapeo -applicationContext.requestDispatcher.iae=La Trayectoria {0} no comienza con carácter "/" -applicationContext.setAttribute.namenull=El nombre no puede ser nulo -applicationDispatcher.allocateException=Excepción de reserva de espacio para servlet {0} -applicationDispatcher.deallocateException=Excepción de recuperación de espacio para servlet {0} -applicationDispatcher.forward.ise=No puedo reenviar después de que la respuesta se haya llevado a cabo. -applicationDispatcher.forward.throw=El recurso reenviado lanzó un excepción -applicationDispatcher.include.throw=El recurso incluído lanzó una excepción -applicationDispatcher.isUnavailable=El Servlet {0} no está disponible en este momento -applicationDispatcher.serviceException=El Servlet.service() para servlet {0} lanzó una excepción -applicationRequest.badParent=No puedo localizar la implementación de Requerimiento padre -applicationRequest.badRequest=El requerimiento no es un javax.servlet.ServletRequestWrapper -applicationResponse.badParent=No puedo localizar implementación de Respuesta padre -applicationResponse.badResponse=La Respuesta no es un javax.servlet.ServletResponseWrapper -containerBase.addDefaultMapper=Excepción configurando mapeador por defecto de clase {0} -containerBase.alreadyStarted=Ya ha sido arrancado el Contenedor {0} -containerBase.notConfigured=No se ha configurado Válvula básica -containerBase.notStarted=No se ha arrancado el Contenedor {0} -fastEngineMapper.alreadyStarted=Ya se ha arrancado el FastEngineMapper {0} -fastEngineMapper.notStarted=No se ha arrancado aún el FastEngineMapper {0} -filterChain.filter=La ejecución del Filtro lanzó una excepción -filterChain.servlet=La ejecución del Servlet lanzó una excepción -httpContextMapper.container=Este Contenedor no es un StandardContext -httpEngineMapper.container=Este Contenedor no es un StandardEngine -httpHostMapper.container=Esta Contenedor no es una StandardHost -interceptorValve.alreadyStarted=Ya ha sido arrancada la InterceptorValve -interceptorValve.notStarted=Aún no ha sido arrancada la InterceptorValve -naming.bindFailed=No pude cambiar (bind) objeto: {0} -naming.unbindFailed=No pude descambiar (unbind) objecto: {0} -naming.invalidEnvEntryType=La entrada de Entorno {0} tiene un tipo inválido -naming.invalidEnvEntryValue=La entrada de Entorno {0} tiene un valor inválido -naming.namingContextCreationFailed=Falló la creación del contexto de nombres (naming): {0} -standardContext.alreadyStarted=Ya se ha arrancado el Contexto -standardContext.applicationListener=Error configurando escuchador de aplicación de clase {0} -standardContext.applicationSkipped=Se ha saltado la instalación de escuchadores de aplicación debido a error(es) previo(s) -standardContext.badRequest=Trayectoria de requerimiento inválida ({0}). -standardContext.errorPage.error=La localización de la página de error 0} debe de comenzar con ''/'' -standardContext.errorPage.required=ErrorPage no puede ser nulo -standardContext.errorPage.warning=AVISO: La localización de la página de error {0} debe de comenzar con ''/'' en Servlet 2.4 -standardContext.filterMap.either=El mapeo de filtro debe de especificar o un o un -standardContext.filterMap.name=El mapeo de filtro especifica un nombre desconocido de filtro {0} -standardContext.filterMap.pattern= {0} inválido en mapeo de filtro -standardContext.filterStart=Excepción arrancando filtro {0} -standardContext.filterStartFailed=No pude arrancar Filtros de aplicación con éxito -standardContext.requestListenerStartFailed=No pude arrancar válvula de escuchador de requerimiento con exito -standardContext.requestListenerConfig.added=Añadida Válvula de escuchador de requerimiento -standardContext.requestListenerConfig.error=Excepción añadiendo Válvula de escuchador de requerimiento: {0} -standardContext.isUnavailable=Esta aplicación no está disponible en este momento -standardContext.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0} -standardContext.listenerStartFailed=No pude arrancar Escuchadores de aplicación con éxito -standardContext.listenerStop=Excepción enviando evento de contexto destruído a instancia de escuchador de clase {0} -standardContext.loginConfig.errorPage=La Página de error de Formulario {0} debe de comenzar con ''/' -standardContext.loginConfig.errorWarning=AVISO: La página de error de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 -standardContext.loginConfig.loginPage=La página de login de Formulario {0} debe de comenzar con ''/' -standardContext.loginConfig.loginWarning=AVISO: La página de login de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 -standardContext.loginConfig.required=LoginConfig no puede ser nula -standardContext.mappingError=Error de configuración de MAPEO para URI relativa {0} -standardContext.notFound=El recurso requerido ({0}) no se encuentra disponible -standardContext.notReloadable=Está desactivada la recarga en este Contexto -standardContext.notStarted=Aún no se ha arrancado el Contexto -standardContext.notWrapper=El Hijo de un Contexto debe de ser un Arropador (Wrapper) -standardContext.parameter.duplicate=Duplicado parámetro de inicialización de contexto {0} -standardContext.parameter.required=Es necesario poner nombre de parámetro y valor de parámetro -standardContext.reloadingCompleted=Se ha completado la Regarga de este Contexto -standardContext.reloadingFailed=Falló la recarga de este Contexto debido a errores previos -standardContext.reloadingStarted=Ha comenzado la recarga de este Contexto -standardContext.resourcesStart=Error arrancando Recursos estáticos -standardContext.securityConstraint.pattern= {0} inválida en restricción de seguridad -standardContext.servletMap.name=El mapeo de Servlet especifica un nombre de servlet desconocido {0} -standardContext.servletMap.pattern= {0} inválida en mapeo de servlet -standardContext.startCleanup=Excepción durante la limpieza tras no poder arrancar -standardContext.startFailed=Falló en arranque del Contexto [{0}] debido a errores previos -standardContext.startingLoader=Excepción arrancando Cargador -standardContext.startingManager=Excepción arrancando Gestor -standardContext.startingWrapper=Excepción arrancando Arropador (Wrapper) para servlet {0} -standardContext.stoppingContext=Excepci?n parando Context -standardContext.stoppingLoader=Excepción parando Cargador -standardContext.stoppingManager=Excepción parando Gestor -standardContext.stoppingWrapper=Excepción parando Arropador (Wrapper) para servlet {0} -standardContext.urlDecode=No puedo decodificar URL de trayectoria de requerimiento {0} -standardContext.urlPattern.patternWarning=AVISO: el patrón URL {0} debe de comenzar con ''/'' en Servlet 2.4 -standardContext.urlValidate=No puedo validar trayectoria de requerimiento de URL decodificada {0} -standardContext.wrapper.error=El archivo JSP {0} debe de comenzar con ''/' -standardContext.wrapper.warning=AVISO: El archivo JSP {0} debe de comenzar con ''/'' en Servlet 2.4 -standardEngine.alreadyStarted=Ya ha sido arrancado el Motor -standardEngine.mappingError=Error de configuración de MAPEO para nombre de servidor {0} -standardEngine.noHost=No hay Máquina que coincida con nombre de servidor {0} -standardEngine.noHostHeader=Requerimiento HTTP/1.1 sin Máquina: cabecera -standardEngine.notHost=El Hijo de un Motor debe de ser un Máquina -standardEngine.notParent=El Motor no puede tener un Contenedor padre -standardEngine.notStarted=Aún no se ha arrancado el Motor -standardEngine.unfoundHost=Máquina virtual {0} no hallada -standardEngine.unknownHost=No se ha especificado máquina servidora en este requerimiento -standardHost.accessBase=No puedo acceder a directorio base de documento {0} -standardHost.alreadyStarted=Ya ha sido arrancada la Máquina -standardHost.appBase=No existe el directorio base de aplicación {0} -standardHost.clientAbort=El Cliente Remoto Abortó el Requerimiento, IOException: {0} -standardHost.configRequired=Es necesario poner la URL a archivo de configuración -standardHost.configNotAllowed=No se permite el uso del archivo de configuración -standardHost.installBase=Sólo se pueden instalar aplicaciones web en el directorio de aplicaciones web de Máquina -standardHost.installing=Instalando aplicaciones web en trayectoria de contexto {0} desde URL {1} -standardHost.installingWAR=Instalando aplicación web desde URL {0} -standardHost.installingXML=Procesando URL de archivo de configuración de Contexto {0} -standardHost.installError=Error desplegando aplicación en trayectoria de contexto {0} -standardHost.invalidErrorReportValveClass=No pude cargar clase especifiada de válvula de informe de error: {0} -standardHost.docBase=Ya existe el directorio base de documento {0} -standardHost.mappingError=Error de configuración de MAPEO para URI de requerimiento {0} -standardHost.noContext=No se ha configurado Contexto para procesar este requerimiento -standardHost.noHost=No se ha configurado Máquina para procesar este requerimiento -standardHost.notContext=El Hijo de una Máquina debe de ser un Contexto -standardHost.notStarted=Aún no se ha arrancado la Máquina -standardHost.nullName=Es necesario poner el nombre de Máquina -standardHost.pathFormat=Trayectoria de contexto inválida: {0} -standardHost.pathMatch=La trayectoria de Contexto {0} debe de coincidir con el nombre de directorio o de archivo WAR: {1} -standardHost.pathMissing=La trayectoria de Contexto {0} no está en uso en este momento -standardHost.pathRequired=Es necesario poner la trayectoria de Contexto -standardHost.pathUsed=Ya está en uso la trayectoria de Contexto {0} -standardHost.removing=Quitando aplicación web en trayectoria de contexto {0} -standardHost.removeError=Error quitando aplicación en trayectoria de contexto {0} -standardHost.start=Arrancando aplicación web en trayectoria de contexto {0} -standardHost.stop=Parando aplicación web en trayectoria de contexto {0} -standardHost.unfoundContext=No puedo hallar contexto para URI de requerimiento {0} -standardHost.warRequired=Es necesario poner la URL a archivo de aplicación web -standardHost.warURL=URL inválida para archivo de aplicación web: {0} -standardHost.validationEnabled=Activada la validación XML -standardHost.validationDisabled=Desactivada la validación XML -standardPipeline.alreadyStarted=Ya se ha arrancado la Tubería (Pipeline) -standardPipeline.notStarted=No se ha arrancado la Tubería (Pipeline) -standardPipeline.noValve=No hay más Válvulas en la Tubería (Pipeline) procesando este requerimiento -standardServer.addContainer.ise=No hay conectores disponibles para ser asociados con este contenedor -standardServer.initialize.initialized=Ya se ha inicializado este servidor -standardServer.start.connectors=Al menos un conector no está asociado con cualquier contenedor -standardServer.start.started=Ya ha sido arrancado este servidor -standardServer.stop.notStarted=Aún no ha sido arrancado este servidor -standardService.initialize.initialized=Ya ha sido inicializado este servicio -standardService.start.name=Arrancando servicio {0} -standardService.start.started=Ya ha sido arrancado este sercicio -standardService.stop.name=Parando servicio {0} -standardService.stop.notStarted=Aún no se ha arrancado este servicio -standardWrapper.allocate=Error reservando espacio para una instancia de servlet -standardWrapper.allocateException=Excepción de reserva de espacio para servlet {0} -standardWrapper.containerServlet=Cargando servlet de contenedor {0} -standardWrapper.createFilters=Excepción de creación de filtros para servlet {0} -standardWrapper.deallocateException=Excepción de recuperación de espacio para servlet {0} -standardWrapper.destroyException=Servlet.destroy() para servlet {0} lanzó excepción -standardWrapper.exception0=Informe de Excepción de Tomcat -standardWrapper.exception1=Ha tenido lugar una Excepción de Servlet -standardWrapper.exception2=Informe de Excepción: -standardWrapper.exception3=Causa Raíz: -standardWrapper.initException=Servlet.init() para servlet {0} lanzó excepción -standardWrapper.instantiate=Error instanciando clase de servlet {0} -standardWrapper.isUnavailable=El Servlet {0} no está disponible en este momento -standardWrapper.jasperLoader=Usando cargador de clases (classloader) de Jasper para servlet {0} -standardWrapper.jspFile.format=El archivo JSP {0} no comienza con carácter ''/'' -standardWrapper.loadException=El Servlet {0} lanzó excepción de load() -standardWrapper.missingClass=El Arropador (Wrapper) no puede hallar clase de servlet {0} o una clase de la que depende -standardWrapper.missingLoader=El Arropador (Wrapper) no puede hallar Cargador para servlet {0} -standardWrapper.notChild=El contenedor de Arropador (Wrapper) no puede tener contenedores hijo -standardWrapper.notClass=No se ha especificado clase de servlet para servlet {0} -standardWrapper.notContext=El contenedor padre para un Arropador (Wrapper) debe de ser un Contexto -standardWrapper.notFound=No está disponible el Servlet {0} -standardWrapper.notServlet=La Clase {0} no es un Servlet -standardWrapper.privilegedServlet=El Servlet de clase {0} es privilegiado y no puede ser cargado mediante esta aplicación web -standardWrapper.releaseFilters=Excepción de Liberación de filtros para servlet {0} -standardWrapper.serviceException=Servlet.service() para servlet {0} lanzó excepción -standardWrapper.statusHeader=HTTP Estado {0} - {1} -standardWrapper.statusTitle=Informe de Error de Tomcat -standardWrapper.unavailable=Marcando el servlet {0} como no disponible -standardWrapper.unloadException=El Servlet {0} lanzó excepción unload() -standardWrapper.unloading=No puedo reservar espacio para servlet {0} porque está siendo descargado -standardWrapper.waiting=Esperando por {0} instancia(s) para recuperar su espacio reservado +applicationContext.attributeEvent=Excepción lanzada por escuchador de eventos de atributos +applicationContext.mapping.error=Error durante mapeo +applicationContext.requestDispatcher.iae=La Trayectoria {0} no comienza con carácter "/" +applicationContext.setAttribute.namenull=El nombre no puede ser nulo +applicationDispatcher.allocateException=Excepción de reserva de espacio para servlet {0} +applicationDispatcher.deallocateException=Excepción de recuperación de espacio para servlet {0} +applicationDispatcher.forward.ise=No puedo reenviar después de que la respuesta se haya llevado a cabo. +applicationDispatcher.forward.throw=El recurso reenviado lanzó un excepción +applicationDispatcher.include.throw=El recurso incluído lanzó una excepción +applicationDispatcher.isUnavailable=El Servlet {0} no está disponible en este momento +applicationDispatcher.serviceException=El Servlet.service() para servlet {0} lanzó una excepción +applicationRequest.badParent=No puedo localizar la implementación de Requerimiento padre +applicationRequest.badRequest=El requerimiento no es un javax.servlet.ServletRequestWrapper +applicationResponse.badParent=No puedo localizar implementación de Respuesta padre +applicationResponse.badResponse=La Respuesta no es un javax.servlet.ServletResponseWrapper +containerBase.addDefaultMapper=Excepción configurando mapeador por defecto de clase {0} +containerBase.alreadyStarted=Ya ha sido arrancado el Contenedor {0} +containerBase.notConfigured=No se ha configurado Válvula básica +containerBase.notStarted=No se ha arrancado el Contenedor {0} +fastEngineMapper.alreadyStarted=Ya se ha arrancado el FastEngineMapper {0} +fastEngineMapper.notStarted=No se ha arrancado aún el FastEngineMapper {0} +filterChain.filter=La ejecución del Filtro lanzó una excepción +filterChain.servlet=La ejecución del Servlet lanzó una excepción +httpContextMapper.container=Este Contenedor no es un StandardContext +httpEngineMapper.container=Este Contenedor no es un StandardEngine +httpHostMapper.container=Esta Contenedor no es una StandardHost +interceptorValve.alreadyStarted=Ya ha sido arrancada la InterceptorValve +interceptorValve.notStarted=Aún no ha sido arrancada la InterceptorValve +naming.bindFailed=No pude cambiar (bind) objeto: {0} +naming.unbindFailed=No pude descambiar (unbind) objecto: {0} +naming.invalidEnvEntryType=La entrada de Entorno {0} tiene un tipo inválido +naming.invalidEnvEntryValue=La entrada de Entorno {0} tiene un valor inválido +naming.namingContextCreationFailed=Falló la creación del contexto de nombres (naming): {0} +standardContext.alreadyStarted=Ya se ha arrancado el Contexto +standardContext.applicationListener=Error configurando escuchador de aplicación de clase {0} +standardContext.applicationSkipped=Se ha saltado la instalación de escuchadores de aplicación debido a error(es) previo(s) +standardContext.badRequest=Trayectoria de requerimiento inválida ({0}). +standardContext.errorPage.error=La localización de la página de error 0} debe de comenzar con ''/'' +standardContext.errorPage.required=ErrorPage no puede ser nulo +standardContext.errorPage.warning=AVISO: La localización de la página de error {0} debe de comenzar con ''/'' en Servlet 2.4 +standardContext.filterMap.either=El mapeo de filtro debe de especificar o un o un +standardContext.filterMap.name=El mapeo de filtro especifica un nombre desconocido de filtro {0} +standardContext.filterMap.pattern= {0} inválido en mapeo de filtro +standardContext.filterStart=Excepción arrancando filtro {0} +standardContext.filterStartFailed=No pude arrancar Filtros de aplicación con éxito +standardContext.requestListenerStartFailed=No pude arrancar válvula de escuchador de requerimiento con exito +standardContext.requestListenerConfig.added=Añadida Válvula de escuchador de requerimiento +standardContext.requestListenerConfig.error=Excepción añadiendo Válvula de escuchador de requerimiento: {0} +standardContext.isUnavailable=Esta aplicación no está disponible en este momento +standardContext.listenerStart=Excepción enviando evento inicializado de contexto a instancia de escuchador de clase {0} +standardContext.listenerStartFailed=No pude arrancar Escuchadores de aplicación con éxito +standardContext.listenerStop=Excepción enviando evento de contexto destruído a instancia de escuchador de clase {0} +standardContext.loginConfig.errorPage=La Página de error de Formulario {0} debe de comenzar con ''/' +standardContext.loginConfig.errorWarning=AVISO: La página de error de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 +standardContext.loginConfig.loginPage=La página de login de Formulario {0} debe de comenzar con ''/' +standardContext.loginConfig.loginWarning=AVISO: La página de login de Formulario {0} debe de comenzar con ''/'' en Servlet 2.4 +standardContext.loginConfig.required=LoginConfig no puede ser nula +standardContext.mappingError=Error de configuración de MAPEO para URI relativa {0} +standardContext.notFound=El recurso requerido ({0}) no se encuentra disponible +standardContext.notReloadable=Está desactivada la recarga en este Contexto +standardContext.notStarted=Aún no se ha arrancado el Contexto +standardContext.notWrapper=El Hijo de un Contexto debe de ser un Arropador (Wrapper) +standardContext.parameter.duplicate=Duplicado parámetro de inicialización de contexto {0} +standardContext.parameter.required=Es necesario poner nombre de parámetro y valor de parámetro +standardContext.reloadingCompleted=Se ha completado la Regarga de este Contexto +standardContext.reloadingFailed=Falló la recarga de este Contexto debido a errores previos +standardContext.reloadingStarted=Ha comenzado la recarga de este Contexto +standardContext.resourcesStart=Error arrancando Recursos estáticos +standardContext.securityConstraint.pattern= {0} inválida en restricción de seguridad +standardContext.servletMap.name=El mapeo de Servlet especifica un nombre de servlet desconocido {0} +standardContext.servletMap.pattern= {0} inválida en mapeo de servlet +standardContext.startCleanup=Excepción durante la limpieza tras no poder arrancar +standardContext.startFailed=Falló en arranque del Contexto [{0}] debido a errores previos +standardContext.startingLoader=Excepción arrancando Cargador +standardContext.startingManager=Excepción arrancando Gestor +standardContext.startingWrapper=Excepción arrancando Arropador (Wrapper) para servlet {0} +standardContext.stoppingContext=Excepci?n parando Context +standardContext.stoppingLoader=Excepción parando Cargador +standardContext.stoppingManager=Excepción parando Gestor +standardContext.stoppingWrapper=Excepción parando Arropador (Wrapper) para servlet {0} +standardContext.urlDecode=No puedo decodificar URL de trayectoria de requerimiento {0} +standardContext.urlPattern.patternWarning=AVISO: el patrón URL {0} debe de comenzar con ''/'' en Servlet 2.4 +standardContext.urlValidate=No puedo validar trayectoria de requerimiento de URL decodificada {0} +standardContext.wrapper.error=El archivo JSP {0} debe de comenzar con ''/' +standardContext.wrapper.warning=AVISO: El archivo JSP {0} debe de comenzar con ''/'' en Servlet 2.4 +standardEngine.alreadyStarted=Ya ha sido arrancado el Motor +standardEngine.mappingError=Error de configuración de MAPEO para nombre de servidor {0} +standardEngine.noHost=No hay Máquina que coincida con nombre de servidor {0} +standardEngine.noHostHeader=Requerimiento HTTP/1.1 sin Máquina: cabecera +standardEngine.notHost=El Hijo de un Motor debe de ser un Máquina +standardEngine.notParent=El Motor no puede tener un Contenedor padre +standardEngine.notStarted=Aún no se ha arrancado el Motor +standardEngine.unfoundHost=Máquina virtual {0} no hallada +standardEngine.unknownHost=No se ha especificado máquina servidora en este requerimiento +standardHost.accessBase=No puedo acceder a directorio base de documento {0} +standardHost.alreadyStarted=Ya ha sido arrancada la Máquina +standardHost.appBase=No existe el directorio base de aplicación {0} +standardHost.clientAbort=El Cliente Remoto Abortó el Requerimiento, IOException: {0} +standardHost.configRequired=Es necesario poner la URL a archivo de configuración +standardHost.configNotAllowed=No se permite el uso del archivo de configuración +standardHost.installBase=Sólo se pueden instalar aplicaciones web en el directorio de aplicaciones web de Máquina +standardHost.installing=Instalando aplicaciones web en trayectoria de contexto {0} desde URL {1} +standardHost.installingWAR=Instalando aplicación web desde URL {0} +standardHost.installingXML=Procesando URL de archivo de configuración de Contexto {0} +standardHost.installError=Error desplegando aplicación en trayectoria de contexto {0} +standardHost.invalidErrorReportValveClass=No pude cargar clase especifiada de válvula de informe de error: {0} +standardHost.docBase=Ya existe el directorio base de documento {0} +standardHost.mappingError=Error de configuración de MAPEO para URI de requerimiento {0} +standardHost.noContext=No se ha configurado Contexto para procesar este requerimiento +standardHost.noHost=No se ha configurado Máquina para procesar este requerimiento +standardHost.notContext=El Hijo de una Máquina debe de ser un Contexto +standardHost.notStarted=Aún no se ha arrancado la Máquina +standardHost.nullName=Es necesario poner el nombre de Máquina +standardHost.pathFormat=Trayectoria de contexto inválida: {0} +standardHost.pathMatch=La trayectoria de Contexto {0} debe de coincidir con el nombre de directorio o de archivo WAR: {1} +standardHost.pathMissing=La trayectoria de Contexto {0} no está en uso en este momento +standardHost.pathRequired=Es necesario poner la trayectoria de Contexto +standardHost.pathUsed=Ya está en uso la trayectoria de Contexto {0} +standardHost.removing=Quitando aplicación web en trayectoria de contexto {0} +standardHost.removeError=Error quitando aplicación en trayectoria de contexto {0} +standardHost.start=Arrancando aplicación web en trayectoria de contexto {0} +standardHost.stop=Parando aplicación web en trayectoria de contexto {0} +standardHost.unfoundContext=No puedo hallar contexto para URI de requerimiento {0} +standardHost.warRequired=Es necesario poner la URL a archivo de aplicación web +standardHost.warURL=URL inválida para archivo de aplicación web: {0} +standardHost.validationEnabled=Activada la validación XML +standardHost.validationDisabled=Desactivada la validación XML +standardPipeline.alreadyStarted=Ya se ha arrancado la Tubería (Pipeline) +standardPipeline.notStarted=No se ha arrancado la Tubería (Pipeline) +standardPipeline.noValve=No hay más Válvulas en la Tubería (Pipeline) procesando este requerimiento +standardServer.addContainer.ise=No hay conectores disponibles para ser asociados con este contenedor +standardServer.initialize.initialized=Ya se ha inicializado este servidor +standardServer.start.connectors=Al menos un conector no está asociado con cualquier contenedor +standardServer.start.started=Ya ha sido arrancado este servidor +standardServer.stop.notStarted=Aún no ha sido arrancado este servidor +standardService.initialize.initialized=Ya ha sido inicializado este servicio +standardService.start.name=Arrancando servicio {0} +standardService.start.started=Ya ha sido arrancado este sercicio +standardService.stop.name=Parando servicio {0} +standardService.stop.notStarted=Aún no se ha arrancado este servicio +standardWrapper.allocate=Error reservando espacio para una instancia de servlet +standardWrapper.allocateException=Excepción de reserva de espacio para servlet {0} +standardWrapper.containerServlet=Cargando servlet de contenedor {0} +standardWrapper.createFilters=Excepción de creación de filtros para servlet {0} +standardWrapper.deallocateException=Excepción de recuperación de espacio para servlet {0} +standardWrapper.destroyException=Servlet.destroy() para servlet {0} lanzó excepción +standardWrapper.exception0=Informe de Excepción de Tomcat +standardWrapper.exception1=Ha tenido lugar una Excepción de Servlet +standardWrapper.exception2=Informe de Excepción: +standardWrapper.exception3=Causa Raíz: +standardWrapper.initException=Servlet.init() para servlet {0} lanzó excepción +standardWrapper.instantiate=Error instanciando clase de servlet {0} +standardWrapper.isUnavailable=El Servlet {0} no está disponible en este momento +standardWrapper.jasperLoader=Usando cargador de clases (classloader) de Jasper para servlet {0} +standardWrapper.jspFile.format=El archivo JSP {0} no comienza con carácter ''/'' +standardWrapper.loadException=El Servlet {0} lanzó excepción de load() +standardWrapper.missingClass=El Arropador (Wrapper) no puede hallar clase de servlet {0} o una clase de la que depende +standardWrapper.missingLoader=El Arropador (Wrapper) no puede hallar Cargador para servlet {0} +standardWrapper.notChild=El contenedor de Arropador (Wrapper) no puede tener contenedores hijo +standardWrapper.notClass=No se ha especificado clase de servlet para servlet {0} +standardWrapper.notContext=El contenedor padre para un Arropador (Wrapper) debe de ser un Contexto +standardWrapper.notFound=No está disponible el Servlet {0} +standardWrapper.notServlet=La Clase {0} no es un Servlet +standardWrapper.privilegedServlet=El Servlet de clase {0} es privilegiado y no puede ser cargado mediante esta aplicación web +standardWrapper.releaseFilters=Excepción de Liberación de filtros para servlet {0} +standardWrapper.serviceException=Servlet.service() para servlet {0} lanzó excepción +standardWrapper.statusHeader=HTTP Estado {0} - {1} +standardWrapper.statusTitle=Informe de Error de Tomcat +standardWrapper.unavailable=Marcando el servlet {0} como no disponible +standardWrapper.unloadException=El Servlet {0} lanzó excepción unload() +standardWrapper.unloading=No puedo reservar espacio para servlet {0} porque está siendo descargado +standardWrapper.waiting=Esperando por {0} instancia(s) para recuperar su espacio reservado diff --git a/java/org/apache/catalina/core/LocalStrings_fr.properties b/java/org/apache/catalina/core/LocalStrings_fr.properties index eb28a396d..633f2c385 100644 --- a/java/org/apache/catalina/core/LocalStrings_fr.properties +++ b/java/org/apache/catalina/core/LocalStrings_fr.properties @@ -1,164 +1,164 @@ -applicationContext.attributeEvent=Exception lancée par l''écouteur (listener) d''évènement attributs -applicationContext.requestDispatcher.iae=Le chemin {0} ne commence pas par le caractère "/" -applicationContext.setAttribute.namenull=le nom ne peut être nul -applicationDispatcher.allocateException=Exception d''allocation pour la servlet {0} -applicationDispatcher.deallocateException=Exception de désallocation pour la servlet {0} -applicationDispatcher.forward.ise=Impossible d''utiliser faire-suivre (forward) après que la réponse ait été envoyée -applicationDispatcher.forward.throw=La ressource faire-suivre (forwarded) a lancé une exception -applicationDispatcher.include.throw=La ressource incluse (included) a lancé une exception -applicationDispatcher.isUnavailable=La servlet {0} est actuellement indisponible -applicationDispatcher.serviceException="Servlet.service()" pour la servlet {0} a lancé une exception -applicationRequest.badParent=Impossible de trouver l''implementation requête apparentée (parent request) -applicationRequest.badRequest=La requête n''est pas une "javax.servlet.ServletRequestWrapper" -applicationResponse.badParent=Impossible de trouver une implémentation réponse apparentée (parent response) -applicationResponse.badResponse=La réponse n''est pas une "javax.servlet.ServletResponseWrapper" -containerBase.addDefaultMapper=Exception lors de la configuration du routeur par défaut (default mapper) pour la classe {0} -containerBase.alreadyStarted=Le conteneur {0} a déjà été démarré -containerBase.notConfigured=Aucune Valve basique (basic valve) n''a été configurée -containerBase.notStarted=Le conteneur {0} n''a pas été démarré -fastEngineMapper.alreadyStarted=le "FastEngineMapper" {0} a déjà été démarré -fastEngineMapper.notStarted=Le "FastEngineMapper" {0} n''a pas encore été démarré -filterChain.filter=L''exécution du filtre (Filter) a lancé une exception -filterChain.servlet=L''exécution de la servlet a lancé une exception -httpContextMapper.container=Ce conteneur n''est pas un "StandardContext" -httpEngineMapper.container=Ce conteneur n''est pas un "StandardEngine" -httpHostMapper.container=Ce conteneur n''est pas un "StandardHost" -interceptorValve.alreadyStarted=La valve d''interception (InterceptorValve) a déjà été démarrée -interceptorValve.notStarted=La valve d''interception (InterceptorValve) n''a pas encore été démarrée -naming.bindFailed=Echec lors du liage à l''objet: {0} -naming.unbindFailed=Echec lors du déliage à l''objet : {0} -naming.invalidEnvEntryType=L''entrée environnement {0} a un type invalide -naming.invalidEnvEntryValue=L''entrée environnement {0} a une valeur invalide -naming.namingContextCreationFailed=La création du context de nommage (naming context) a échoué : {0} -standardContext.alreadyStarted=Le contexte a déjà été démarré -standardContext.applicationListener=Erreur lors de la configuration de la classe d''écoute de l''application (application listener) {0} -standardContext.applicationSkipped=L''installation des écouteurs (listeners) de l''application a été sautée suite aux erreurs précédentes -standardContext.badRequest=Chemin de requête invalide ({0}). -standardContext.errorPage.error=La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/' -standardContext.errorPage.required=La page d''erreur (ErrorPage) ne peut être nulle -standardContext.errorPage.warning=ATTENTION: La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 -standardContext.filterMap.either=L''association de filtre (filter mapping) doit indiqué soit une ou une -standardContext.filterMap.name=L''association de filtre (filter mapping) indique un nom de filtre inconnu {0} -standardContext.filterMap.pattern= {0} invalide dans l''association de filtre (filter mapping) -standardContext.filterStart=Exception au démarrage du filtre {0} -standardContext.filterStartFailed=Echec du démarrage des filtres d''application -standardContext.requestListenerStartFailed=Echec démarrage des Valves d''écoute -standardContext.requestListenerConfig.added=Ajout de la valve d''écoute -standardContext.requestListenerConfig.error=Exception lors de l''ajout de la valve d''écoute de requête: {0} -standardContext.isUnavailable=Cette application n''est pas disponible actuellement -standardContext.listenerStart=Exception lors de l''envoi de l''évènement contexte initialisé (context initialized) à l''instance de classe d''écoute (listener) {0} -standardContext.listenerStartFailed=Echec du démarrage des écouteurs (listeners) d''application -standardContext.listenerStop=Exception lors de l''envoi de l''évènement contexte détruit (context destroyed) à l''instance de classe d''écoute {0} -standardContext.loginConfig.errorPage=La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' -standardContext.loginConfig.errorWarning=ATTENTION: La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 -standardContext.loginConfig.loginPage=La forme de page de connexion (form login page) {0} doit commencer par un ''/'' -standardContext.loginConfig.loginWarning=ATTENTION: La forme de page de connexion (form login page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 -standardContext.loginConfig.required="LoginConfig" ne peut être nul -standardContext.mappingError=Erreur dans la configuration d''association (mapping configuration) pour l''URI relative {0} -standardContext.notFound=La ressource demandée ({0}) n''est pas disponible. -standardContext.notReloadable=Le rechargement est désactivé pour ce contexte -standardContext.notStarted=Le contexte n''a pas encore été démarré -standardContext.notWrapper=Le fils du contexte (child of context) doit être un enrobeur (wrapper) -standardContext.parameter.duplicate=Paramètre d''initialisation de contexte dupliqué {0} -standardContext.parameter.required=Le nom de paramètre ainsi que la valeur du paramètre sont requis -standardContext.reloadingCompleted=Le rechargement de ce contexte est terminé -standardContext.reloadingFailed=Le rechargement de ce contexte a échoué suite à une erreur précédente -standardContext.reloadingStarted=Le rechargement de ce contexte a démarré -standardContext.securityConstraint.pattern= {0} invalide d''après les contraintes de sécurité (security constraint) -standardContext.servletMap.name=L''association de servlet (servlet mapping) indique un nom de servlet inconnu {0} -standardContext.servletMap.pattern= {0} invalide dans l''association de servlet (servlet mapping) -standardContext.startCleanup=Exception lors du nettoyage après que le démarrage ait échoué -standardContext.startFailed=Erreur de démarrage du contexte [{0}] suite aux erreurs précédentes -standardContext.startingLoader=Exception an démarrage du "Loader" -standardContext.startingManager=Exception an démarrage du "Manager" -standardContext.startingWrapper=Exception an démarrage de l''enrobeur (wrapper) de la servlet {0} -standardContext.stoppingContext=Exception ? l''arr?t du "Context" -standardContext.stoppingLoader=Exception à l''arrêt du "Loader" -standardContext.stoppingManager=Exception à l''arrêt du "Manager" -standardContext.stoppingWrapper=Exception à l''arrêt de l''enrobeur (wrapper) de la servlet {0} -standardContext.resourcesStart=Erreur lors du démarrage des Resources statiques -standardContext.urlDecode=Impossible de décoder le chemin de requête encodé dans l''URL {0} -standardContext.urlPattern.patternWarning=ATTENTION: Le modèle (pattern) URL {0} doit commencer par un ''/'' dans l''API Servlet 2.4 -standardContext.urlValidate=Impossible de valider le chemin de requête encodé dans l''URL {0} -standardContext.wrapper.error=Le fichier JSP {0} doit commencer par un ''/'' -standardContext.wrapper.warning=ATTENTION: Le fichier JSP {0} doit commencer par un ''/'' dans l''API Servlet 2.4 -standardEngine.alreadyStarted=Le moteur a déjà été démarré -standardEngine.mappingError=Erreur de configuration d''association (mapping configuration) pour le serveur {0} -standardEngine.noHost=Aucune hôte (host) ne correspond au nom de serveur {0} -standardEngine.noHostHeader=requête HTTP/1.1 sans entête Host: -standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit être un hôte -standardEngine.notParent=Les moteurs (engine) ne peuvent avoir de parent conteneur (container) -standardEngine.notStarted=Le moteur n''a pas encore été démarré -standardEngine.unfoundHost=L''hôte virtuel (virtual host) {0} est introuvable -standardEngine.unknownHost=Aucun serveur hôte n''est indiqué pour cette requête -standardHost.accessBase=Impossible d''accéder le répertoire "document base" {0} -standardHost.alreadyStarted=L''hôte a déjà été démarré -standardHost.appBase=Le répertoire de base de l''application {0} n''existe pas -standardHost.configRequired=Une URL vers le fichier de configuration est obligatoire -standardHost.configNotAllowed=L''utilisation d''un fichier de configuration file n''est pas autorisé -standardHost.installing=Installation d''une application pour le chemin de contexte {0} depuis l''URL {1} -standardHost.installingWAR=Installation d''une application depuis l''URL {0} -standardHost.installError=Erreur lors du déploiement de l''application pour le chemin de contexte {0} -standardHost.invalidErrorReportValveClass=Impossible de charger la classe valve de rapport d''erreur: {0} -standardHost.docBase=Le répertoire "document base" {0} existe déjà -standardHost.mappingError=Erreur d''association de configuration (mapping configuration) pour l''URI demandée {0} -standardHost.noContext=Aucune contexte n''est configuré pour traiter cette requête -standardHost.noHost=Aucun hôte n''est configuré pour traiter cette requête -standardHost.notContext=Le fils d''un hôte (child of a Host) doit être un contexte -standardHost.notStarted=l''hôte n''a pas encore été démarré -standardHost.nullName=Le nom d''hôte est requis -standardHost.pathFormat=Chemin de contexte invalide: {0} -standardHost.pathMissing=Le chemin de contexte {0} n''est pas utilisé actuellement -standardHost.pathRequired=Le chemin de contexte est requis -standardHost.pathUsed=Le chemin de contexte {0} est déjà utilisé -standardHost.removing=Retrait de l''application web pour le chemin de contexte {0} -standardHost.removeError=Erreur lors du retrait de l''application web pour le chemin de contexte {0} -standardHost.start=Démarrage de l''application web application pour le chemin de contexte {0} -standardHost.stop=Arrét de l''application web application pour le chemin de contexte {0} -standardHost.unfoundContext=Impossible de trouver un contexte pour l''URI {0} demandée -standardHost.warRequired=Une URL vers l''archive d''application web (war) est nécessaire -standardHost.warURL=URL vers l''archive d''application web (war) invalide: {0} -standardPipeline.alreadyStarted=Le "Pipeline" a déjà été démarré -standardPipeline.notStarted=le "Pipeline" n''a pas été démarré -standardPipeline.noValve=Plus aucune Valves dans le "Pipeline" traitant cette requête -standardServer.addContainer.ise=Aucun connecteur disponible à associer avec ce conteneur (container) -standardServer.initialize.initialized=Ce serveur a déjà été initialisé -standardServer.start.connectors=Au moins un connecteur n''est pas associé à aucun conteneur (container) -standardServer.start.started=Ce serveur a déjà été démarré -standardServer.stop.notStarted=Ce serveur n''a pas encore été démarré -standardService.initialize.initialized=Ce service a déjà été initialisé -standardService.start.name=Démarrage du service {0} -standardService.start.started=Ce service a déjà été démarré -standardService.stop.name=Arrêt du service {0} -standardService.stop.notStarted=Ce service n''a pas encore été démarré -standardWrapper.allocate=Erreur d''allocation à une instance de servlet -standardWrapper.allocateException=Exception lors de l''allocation pour la servlet {0} -standardWrapper.containerServlet=Chargement du conteneur (container) de servlet {0} -standardWrapper.createFilters=Exception à la création de filtres pour la servlet {0} -standardWrapper.deallocateException=Exception à la désallocation pour la servlet {0} -standardWrapper.destroyException="Servlet.destroy()" de la servlet {0} a généré une exception -standardWrapper.exception0=Rapport d''exception Tomcat -standardWrapper.exception1=Une exception Servlet s''est produite -standardWrapper.exception2=Rapport d''exception: -standardWrapper.exception3=Cause mère: -standardWrapper.initException="Servlet.init()" pour la servlet {0} a généré une exception -standardWrapper.instantiate=Erreur à l''instantiation de la classe servlet {0} -standardWrapper.isUnavailable=La servlet {0} est actuellement indisponible -standardWrapper.jasperLoader=Utilisation du chargeur de classe Jasper (classloader) pour la servlet {0} -standardWrapper.jspFile.format=Le fichier JSP {0} ne commence par par un caractère ''/'' -standardWrapper.loadException=La servlet {0} a généré une exception "load()" -standardWrapper.missingClass=L''enrobeur (wrapper) ne peut trouver la classe servlet {0} ou une classe dont elle dépend -standardWrapper.missingLoader=L''enrobeur (wrapper) ne peut trouver de chargeur (loader) pour la servlet {0} -standardWrapper.notChild=L''enrobeur de conteneur (wrapper container) peut ne pas avoir de conteneurs fils -standardWrapper.notClass=Aucune classe servlet n''a été spécifiée pour la servlet {0} -standardWrapper.notContext=Le conteneur parent d''un enrobeur (wrapper) doit être un contexte -standardWrapper.notFound=Servlet {0} n''est pas disponible. -standardWrapper.notServlet=La classe {0} n''est pas une servlet -standardWrapper.privilegedServlet=La servlet de classe {0} est privilégiée (privileged) et ne peut être chargé par cette application web -standardWrapper.releaseFilters=Exception des filtres de sortie (release filters) pour la servlet {0} -standardWrapper.serviceException="Servlet.service()" pour la servlet {0} a généré une exception -standardWrapper.statusHeader=Etat HTTP {0} - {1} -standardWrapper.statusTitle=Rapport d''erreur Tomcat -standardWrapper.unavailable=La servlet {0} est marqué comme indisponible -standardWrapper.unloadException=La servlet {0} a généré une exception "unload()" -standardWrapper.unloading=Impossible d''allouer la servlet {0} car elle a été déchargée +applicationContext.attributeEvent=Exception lancée par l''écouteur (listener) d''évènement attributs +applicationContext.requestDispatcher.iae=Le chemin {0} ne commence pas par le caractère "/" +applicationContext.setAttribute.namenull=le nom ne peut être nul +applicationDispatcher.allocateException=Exception d''allocation pour la servlet {0} +applicationDispatcher.deallocateException=Exception de désallocation pour la servlet {0} +applicationDispatcher.forward.ise=Impossible d''utiliser faire-suivre (forward) après que la réponse ait été envoyée +applicationDispatcher.forward.throw=La ressource faire-suivre (forwarded) a lancé une exception +applicationDispatcher.include.throw=La ressource incluse (included) a lancé une exception +applicationDispatcher.isUnavailable=La servlet {0} est actuellement indisponible +applicationDispatcher.serviceException="Servlet.service()" pour la servlet {0} a lancé une exception +applicationRequest.badParent=Impossible de trouver l''implementation requête apparentée (parent request) +applicationRequest.badRequest=La requête n''est pas une "javax.servlet.ServletRequestWrapper" +applicationResponse.badParent=Impossible de trouver une implémentation réponse apparentée (parent response) +applicationResponse.badResponse=La réponse n''est pas une "javax.servlet.ServletResponseWrapper" +containerBase.addDefaultMapper=Exception lors de la configuration du routeur par défaut (default mapper) pour la classe {0} +containerBase.alreadyStarted=Le conteneur {0} a déjà été démarré +containerBase.notConfigured=Aucune Valve basique (basic valve) n''a été configurée +containerBase.notStarted=Le conteneur {0} n''a pas été démarré +fastEngineMapper.alreadyStarted=le "FastEngineMapper" {0} a déjà été démarré +fastEngineMapper.notStarted=Le "FastEngineMapper" {0} n''a pas encore été démarré +filterChain.filter=L''exécution du filtre (Filter) a lancé une exception +filterChain.servlet=L''exécution de la servlet a lancé une exception +httpContextMapper.container=Ce conteneur n''est pas un "StandardContext" +httpEngineMapper.container=Ce conteneur n''est pas un "StandardEngine" +httpHostMapper.container=Ce conteneur n''est pas un "StandardHost" +interceptorValve.alreadyStarted=La valve d''interception (InterceptorValve) a déjà été démarrée +interceptorValve.notStarted=La valve d''interception (InterceptorValve) n''a pas encore été démarrée +naming.bindFailed=Echec lors du liage à l''objet: {0} +naming.unbindFailed=Echec lors du déliage à l''objet : {0} +naming.invalidEnvEntryType=L''entrée environnement {0} a un type invalide +naming.invalidEnvEntryValue=L''entrée environnement {0} a une valeur invalide +naming.namingContextCreationFailed=La création du context de nommage (naming context) a échoué : {0} +standardContext.alreadyStarted=Le contexte a déjà été démarré +standardContext.applicationListener=Erreur lors de la configuration de la classe d''écoute de l''application (application listener) {0} +standardContext.applicationSkipped=L''installation des écouteurs (listeners) de l''application a été sautée suite aux erreurs précédentes +standardContext.badRequest=Chemin de requête invalide ({0}). +standardContext.errorPage.error=La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/' +standardContext.errorPage.required=La page d''erreur (ErrorPage) ne peut être nulle +standardContext.errorPage.warning=ATTENTION: La position de la page d''erreur (ErrorPage) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 +standardContext.filterMap.either=L''association de filtre (filter mapping) doit indiqué soit une ou une +standardContext.filterMap.name=L''association de filtre (filter mapping) indique un nom de filtre inconnu {0} +standardContext.filterMap.pattern= {0} invalide dans l''association de filtre (filter mapping) +standardContext.filterStart=Exception au démarrage du filtre {0} +standardContext.filterStartFailed=Echec du démarrage des filtres d''application +standardContext.requestListenerStartFailed=Echec démarrage des Valves d''écoute +standardContext.requestListenerConfig.added=Ajout de la valve d''écoute +standardContext.requestListenerConfig.error=Exception lors de l''ajout de la valve d''écoute de requête: {0} +standardContext.isUnavailable=Cette application n''est pas disponible actuellement +standardContext.listenerStart=Exception lors de l''envoi de l''évènement contexte initialisé (context initialized) à l''instance de classe d''écoute (listener) {0} +standardContext.listenerStartFailed=Echec du démarrage des écouteurs (listeners) d''application +standardContext.listenerStop=Exception lors de l''envoi de l''évènement contexte détruit (context destroyed) à l''instance de classe d''écoute {0} +standardContext.loginConfig.errorPage=La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' +standardContext.loginConfig.errorWarning=ATTENTION: La forme de page d''erreur (form error page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 +standardContext.loginConfig.loginPage=La forme de page de connexion (form login page) {0} doit commencer par un ''/'' +standardContext.loginConfig.loginWarning=ATTENTION: La forme de page de connexion (form login page) {0} doit commencer par un ''/'' dans l''API Servlet 2.4 +standardContext.loginConfig.required="LoginConfig" ne peut être nul +standardContext.mappingError=Erreur dans la configuration d''association (mapping configuration) pour l''URI relative {0} +standardContext.notFound=La ressource demandée ({0}) n''est pas disponible. +standardContext.notReloadable=Le rechargement est désactivé pour ce contexte +standardContext.notStarted=Le contexte n''a pas encore été démarré +standardContext.notWrapper=Le fils du contexte (child of context) doit être un enrobeur (wrapper) +standardContext.parameter.duplicate=Paramètre d''initialisation de contexte dupliqué {0} +standardContext.parameter.required=Le nom de paramètre ainsi que la valeur du paramètre sont requis +standardContext.reloadingCompleted=Le rechargement de ce contexte est terminé +standardContext.reloadingFailed=Le rechargement de ce contexte a échoué suite à une erreur précédente +standardContext.reloadingStarted=Le rechargement de ce contexte a démarré +standardContext.securityConstraint.pattern= {0} invalide d''après les contraintes de sécurité (security constraint) +standardContext.servletMap.name=L''association de servlet (servlet mapping) indique un nom de servlet inconnu {0} +standardContext.servletMap.pattern= {0} invalide dans l''association de servlet (servlet mapping) +standardContext.startCleanup=Exception lors du nettoyage après que le démarrage ait échoué +standardContext.startFailed=Erreur de démarrage du contexte [{0}] suite aux erreurs précédentes +standardContext.startingLoader=Exception an démarrage du "Loader" +standardContext.startingManager=Exception an démarrage du "Manager" +standardContext.startingWrapper=Exception an démarrage de l''enrobeur (wrapper) de la servlet {0} +standardContext.stoppingContext=Exception ? l''arr?t du "Context" +standardContext.stoppingLoader=Exception à l''arrêt du "Loader" +standardContext.stoppingManager=Exception à l''arrêt du "Manager" +standardContext.stoppingWrapper=Exception à l''arrêt de l''enrobeur (wrapper) de la servlet {0} +standardContext.resourcesStart=Erreur lors du démarrage des Resources statiques +standardContext.urlDecode=Impossible de décoder le chemin de requête encodé dans l''URL {0} +standardContext.urlPattern.patternWarning=ATTENTION: Le modèle (pattern) URL {0} doit commencer par un ''/'' dans l''API Servlet 2.4 +standardContext.urlValidate=Impossible de valider le chemin de requête encodé dans l''URL {0} +standardContext.wrapper.error=Le fichier JSP {0} doit commencer par un ''/'' +standardContext.wrapper.warning=ATTENTION: Le fichier JSP {0} doit commencer par un ''/'' dans l''API Servlet 2.4 +standardEngine.alreadyStarted=Le moteur a déjà été démarré +standardEngine.mappingError=Erreur de configuration d''association (mapping configuration) pour le serveur {0} +standardEngine.noHost=Aucune hôte (host) ne correspond au nom de serveur {0} +standardEngine.noHostHeader=requête HTTP/1.1 sans entête Host: +standardEngine.notHost=Le fils d''un moteur (child of an Engine) doit être un hôte +standardEngine.notParent=Les moteurs (engine) ne peuvent avoir de parent conteneur (container) +standardEngine.notStarted=Le moteur n''a pas encore été démarré +standardEngine.unfoundHost=L''hôte virtuel (virtual host) {0} est introuvable +standardEngine.unknownHost=Aucun serveur hôte n''est indiqué pour cette requête +standardHost.accessBase=Impossible d''accéder le répertoire "document base" {0} +standardHost.alreadyStarted=L''hôte a déjà été démarré +standardHost.appBase=Le répertoire de base de l''application {0} n''existe pas +standardHost.configRequired=Une URL vers le fichier de configuration est obligatoire +standardHost.configNotAllowed=L''utilisation d''un fichier de configuration file n''est pas autorisé +standardHost.installing=Installation d''une application pour le chemin de contexte {0} depuis l''URL {1} +standardHost.installingWAR=Installation d''une application depuis l''URL {0} +standardHost.installError=Erreur lors du déploiement de l''application pour le chemin de contexte {0} +standardHost.invalidErrorReportValveClass=Impossible de charger la classe valve de rapport d''erreur: {0} +standardHost.docBase=Le répertoire "document base" {0} existe déjà +standardHost.mappingError=Erreur d''association de configuration (mapping configuration) pour l''URI demandée {0} +standardHost.noContext=Aucune contexte n''est configuré pour traiter cette requête +standardHost.noHost=Aucun hôte n''est configuré pour traiter cette requête +standardHost.notContext=Le fils d''un hôte (child of a Host) doit être un contexte +standardHost.notStarted=l''hôte n''a pas encore été démarré +standardHost.nullName=Le nom d''hôte est requis +standardHost.pathFormat=Chemin de contexte invalide: {0} +standardHost.pathMissing=Le chemin de contexte {0} n''est pas utilisé actuellement +standardHost.pathRequired=Le chemin de contexte est requis +standardHost.pathUsed=Le chemin de contexte {0} est déjà utilisé +standardHost.removing=Retrait de l''application web pour le chemin de contexte {0} +standardHost.removeError=Erreur lors du retrait de l''application web pour le chemin de contexte {0} +standardHost.start=Démarrage de l''application web application pour le chemin de contexte {0} +standardHost.stop=Arrét de l''application web application pour le chemin de contexte {0} +standardHost.unfoundContext=Impossible de trouver un contexte pour l''URI {0} demandée +standardHost.warRequired=Une URL vers l''archive d''application web (war) est nécessaire +standardHost.warURL=URL vers l''archive d''application web (war) invalide: {0} +standardPipeline.alreadyStarted=Le "Pipeline" a déjà été démarré +standardPipeline.notStarted=le "Pipeline" n''a pas été démarré +standardPipeline.noValve=Plus aucune Valves dans le "Pipeline" traitant cette requête +standardServer.addContainer.ise=Aucun connecteur disponible à associer avec ce conteneur (container) +standardServer.initialize.initialized=Ce serveur a déjà été initialisé +standardServer.start.connectors=Au moins un connecteur n''est pas associé à aucun conteneur (container) +standardServer.start.started=Ce serveur a déjà été démarré +standardServer.stop.notStarted=Ce serveur n''a pas encore été démarré +standardService.initialize.initialized=Ce service a déjà été initialisé +standardService.start.name=Démarrage du service {0} +standardService.start.started=Ce service a déjà été démarré +standardService.stop.name=Arrêt du service {0} +standardService.stop.notStarted=Ce service n''a pas encore été démarré +standardWrapper.allocate=Erreur d''allocation à une instance de servlet +standardWrapper.allocateException=Exception lors de l''allocation pour la servlet {0} +standardWrapper.containerServlet=Chargement du conteneur (container) de servlet {0} +standardWrapper.createFilters=Exception à la création de filtres pour la servlet {0} +standardWrapper.deallocateException=Exception à la désallocation pour la servlet {0} +standardWrapper.destroyException="Servlet.destroy()" de la servlet {0} a généré une exception +standardWrapper.exception0=Rapport d''exception Tomcat +standardWrapper.exception1=Une exception Servlet s''est produite +standardWrapper.exception2=Rapport d''exception: +standardWrapper.exception3=Cause mère: +standardWrapper.initException="Servlet.init()" pour la servlet {0} a généré une exception +standardWrapper.instantiate=Erreur à l''instantiation de la classe servlet {0} +standardWrapper.isUnavailable=La servlet {0} est actuellement indisponible +standardWrapper.jasperLoader=Utilisation du chargeur de classe Jasper (classloader) pour la servlet {0} +standardWrapper.jspFile.format=Le fichier JSP {0} ne commence par par un caractère ''/'' +standardWrapper.loadException=La servlet {0} a généré une exception "load()" +standardWrapper.missingClass=L''enrobeur (wrapper) ne peut trouver la classe servlet {0} ou une classe dont elle dépend +standardWrapper.missingLoader=L''enrobeur (wrapper) ne peut trouver de chargeur (loader) pour la servlet {0} +standardWrapper.notChild=L''enrobeur de conteneur (wrapper container) peut ne pas avoir de conteneurs fils +standardWrapper.notClass=Aucune classe servlet n''a été spécifiée pour la servlet {0} +standardWrapper.notContext=Le conteneur parent d''un enrobeur (wrapper) doit être un contexte +standardWrapper.notFound=Servlet {0} n''est pas disponible. +standardWrapper.notServlet=La classe {0} n''est pas une servlet +standardWrapper.privilegedServlet=La servlet de classe {0} est privilégiée (privileged) et ne peut être chargé par cette application web +standardWrapper.releaseFilters=Exception des filtres de sortie (release filters) pour la servlet {0} +standardWrapper.serviceException="Servlet.service()" pour la servlet {0} a généré une exception +standardWrapper.statusHeader=Etat HTTP {0} - {1} +standardWrapper.statusTitle=Rapport d''erreur Tomcat +standardWrapper.unavailable=La servlet {0} est marqué comme indisponible +standardWrapper.unloadException=La servlet {0} a généré une exception "unload()" +standardWrapper.unloading=Impossible d''allouer la servlet {0} car elle a été déchargée diff --git a/java/org/apache/catalina/core/LocalStrings_ja.properties b/java/org/apache/catalina/core/LocalStrings_ja.properties index f591dfdf3..c7a0bf08f 100644 --- a/java/org/apache/catalina/core/LocalStrings_ja.properties +++ b/java/org/apache/catalina/core/LocalStrings_ja.properties @@ -1,172 +1,172 @@ -applicationContext.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f -applicationContext.mapping.error=\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -applicationContext.requestDispatcher.iae=\u30d1\u30b9 {0} \u304c"/"\u6587\u5b57\u3067\u59cb\u307e\u308a\u307e\u305b\u3093 -applicationContext.setAttribute.namenull=name\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -applicationDispatcher.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 -applicationDispatcher.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 -applicationDispatcher.forward.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30d5\u30a9\u30ef\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -applicationDispatcher.forward.throw=\u30d5\u30a9\u30ef\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -applicationDispatcher.include.throw=\u30a4\u30f3\u30af\u30eb\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -applicationDispatcher.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 -applicationDispatcher.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -applicationRequest.badParent=\u89aa\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 -applicationRequest.badRequest=\u30ea\u30af\u30a8\u30b9\u30c8\u304cjavax.servlet.ServletRequestWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -applicationResponse.badParent=\u89aa\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 -applicationResponse.badResponse=\u30ec\u30b9\u30dd\u30f3\u30b9\u304cjavax.servlet.ServletResponseWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -containerBase.addDefaultMapper=\u30af\u30e9\u30b9 {0} \u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30de\u30c3\u30d1\u3092\u8a2d\u5b9a\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -containerBase.alreadyStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -containerBase.notConfigured=\u57fa\u672c\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -containerBase.notStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -fastEngineMapper.alreadyStarted=FastEngineMapper {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -fastEngineMapper.notStarted=FastEngineMapper {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -filterChain.filter=\u30d5\u30a3\u30eb\u30bf\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -filterChain.servlet=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -httpContextMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardContext\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -httpEngineMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardEngine\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -httpHostMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardHost\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -interceptorValve.alreadyStarted=InterceptorValve\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -interceptorValve.notStarted=InterceptorValve\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -naming.bindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -naming.unbindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -naming.invalidEnvEntryType=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u578b\u3092\u6301\u3063\u3066\u3044\u307e\u3059 -naming.invalidEnvEntryValue=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u5024\u3092\u6301\u3063\u3066\u3044\u307e\u3059 -naming.namingContextCreationFailed=\u540d\u524d\u4ed8\u304d\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -standardContext.alreadyStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardContext.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -standardContext.applicationSkipped=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059 -standardContext.badRequest=\u7121\u52b9\u306a\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9\u3067\u3059 ({0})\u3002 -standardContext.errorPage.error=\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.errorPage.required=ErrorPage\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -standardContext.errorPage.warning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.filterMap.either=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u53c8\u306f\u306e\u3069\u3061\u3089\u304b\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.filterMap.name=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30d5\u30a3\u30eb\u30bf\u540d {0} \u3092\u6307\u5b9a\u3057\u307e\u3057\u305f -standardContext.filterMap.pattern=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 -standardContext.filterStart=\u30d5\u30a3\u30eb\u30bf {0} \u306e\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.filterStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d5\u30a3\u30eb\u30bf\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f -standardContext.requestListenerStartFailed=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f -standardContext.requestListenerConfig.added=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f -standardContext.requestListenerConfig.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u8ffd\u52a0\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0} -standardContext.isUnavailable=\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 -standardContext.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.listenerStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f -standardContext.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u7834\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.loginConfig.errorPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.loginConfig.errorWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.loginConfig.loginPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.loginConfig.loginWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.loginConfig.required=LoginConfig\u306fnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -standardContext.mappingError=\u76f8\u5bfeURI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 -standardContext.notFound=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9 ({0}) \u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 -standardContext.notReloadable=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u518d\u30ed\u30fc\u30c9\u306f\u7121\u52b9\u3067\u3059 -standardContext.notStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardContext.notWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30e9\u30c3\u30d1\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.parameter.duplicate=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30d1\u30e9\u30e1\u30bf {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059 -standardContext.parameter.required=\u30d1\u30e9\u30e1\u30bf\u540d\u3068\u30d1\u30e9\u30e1\u30bf\u5024\u306e\u4e21\u65b9\u304c\u5fc5\u8981\u3067\u3059 -standardContext.reloadingCompleted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f -standardContext.reloadingFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f -standardContext.reloadingStarted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u3092\u958b\u59cb\u3057\u307e\u3057\u305f -standardContext.resourcesStart=\u9759\u7684\u30ea\u30bd\u30fc\u30b9\u306e\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -standardContext.securityConstraint.pattern=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u5236\u7d04\u306e\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 -standardContext.servletMap.name=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d {0} \u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059 -standardContext.servletMap.pattern=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 -standardContext.startCleanup=\u8d77\u52d5\u304c\u5931\u6557\u3057\u305f\u5f8c\u306e\u30af\u30ea\u30fc\u30f3\u30ca\u30c3\u30d7\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -standardContext.startFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u8d77\u52d5\u304c\u5931\u6557\u3057\u307e\u3057\u305f [{0}] -standardContext.startingLoader=\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.startingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.startingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.stoppingContext=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.stoppingLoader=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.stoppingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.stoppingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardContext.urlDecode=\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u306eURL\u30c7\u30b3\u30fc\u30c9\u304c\u3067\u304d\u307e\u305b\u3093 -standardContext.urlPattern.patternWarning=\u8b66\u544a: Servlet 2.4\u3067\u306fURL\u30d1\u30bf\u30fc\u30f3 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.urlValidate=URL\u30c7\u30b3\u30fc\u30c9\u3055\u308c\u305f\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u3092\u691c\u8a3c\u3067\u304d\u307e\u305b\u3093 -standardContext.wrapper.error=JSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardContext.wrapper.warning=\u8b66\u544a: Servlet 2.4\u3067\u306fJSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardEngine.alreadyStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardEngine.mappingError=\u30b5\u30fc\u30d0\u540d {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 -standardEngine.noHost=\u30b5\u30fc\u30d0\u540d {0} \u306b\u4e00\u81f4\u3059\u308b\u30db\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093 -standardEngine.noHostHeader=Host:\u30d8\u30c3\u30c0\u3092\u6301\u305f\u306a\u3044 HTTP/1.1 \u30ea\u30af\u30a8\u30b9\u30c8\u3067\u3059 -standardEngine.notHost=\u30a8\u30f3\u30b8\u30f3\u306e\u5b50\u4f9b\u306f\u30db\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -standardEngine.notStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardEngine.unfoundHost=\u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -standardEngine.unknownHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u4e2d\u306b\u30b5\u30fc\u30d0\u30db\u30b9\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardHost.accessBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093 -standardHost.alreadyStarted=\u30db\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardHost.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 -standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: {0} -standardHost.configRequired=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3078\u306eURL\u304c\u5fc5\u8981\u3067\u3059 -standardHost.configNotAllowed=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -standardHost.installBase=\u30db\u30b9\u30c8Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4e2d\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3060\u3051\u304c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059 -standardHost.installing=URL {1} \u304b\u3089\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306bWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 -standardHost.installingWAR=URL {0} \u304b\u3089Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 -standardHost.installingXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL {0} \u3092\u51e6\u7406\u3057\u3066\u3044\u307e\u3059 -standardHost.installError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: {0} -standardHost.docBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059 -standardHost.mappingError=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 -standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 -standardHost.noHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30db\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 -standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardHost.notStarted=\u30db\u30b9\u30c8\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059 -standardHost.pathFormat=\u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u3067\u3059: {0} -standardHost.pathMatch=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u53c8\u306fWAR\u30d5\u30a1\u30a4\u30eb\u540d\u306b\u4e00\u81f4\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093: {1} -standardHost.pathMissing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u73fe\u5728\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardHost.pathRequired=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u304c\u5fc5\u8981\u3067\u3059 -standardHost.pathUsed=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 -standardHost.removing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u3057\u307e\u3059 -standardHost.removeError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -standardHost.start=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3059 -standardHost.stop=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3059 -standardHost.unfoundContext=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 -standardHost.warRequired=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306eURL\u304c\u5fc5\u8981\u3067\u3059 -standardHost.warURL=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306aURL\u3067\u3059: {0} -standardHost.validationEnabled=XML\u691c\u8a3c\u306f\u6709\u52b9\u3067\u3059 -standardHost.validationDisabled=XML\u691c\u8a3c\u306f\u7121\u52b9\u3067\u3059 -standardPipeline.alreadyStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardPipeline.notStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardPipeline.noValve=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u4e2d\u306b\u3053\u308c\u4ee5\u4e0a\u306e\u30d0\u30eb\u30d6\u306f\u3042\u308a\u307e\u305b\u3093 -standardServer.addContainer.ise=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u95a2\u9023\u3065\u3051\u308b\u305f\u3081\u306e\u30b3\u30cd\u30af\u30bf\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 -standardServer.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardServer.start.connectors=\u30b3\u30f3\u30c6\u30ca\u306b\u4e00\u3064\u3082\u30b3\u30cd\u30af\u30bf\u304c\u95a2\u9023\u3065\u3051\u3089\u308c\u3066\u3044\u307e\u305b\u3093 -standardServer.start.started=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardServer.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardService.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardService.start.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u8d77\u52d5\u3057\u307e\u3059 -standardService.start.started=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardService.stop.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u505c\u6b62\u3057\u307e\u3059 -standardService.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardWrapper.allocate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -standardWrapper.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 -standardWrapper.containerServlet=\u30b3\u30f3\u30c6\u30ca\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 -standardWrapper.createFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0}\u306b\u5bfe\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u4f5c\u6210\u3057\u307e\u3059 -standardWrapper.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u5bfe\u3059\u308b\u4f8b\u5916\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3057\u307e\u3059 -standardWrapper.destroyException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.destroy()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardWrapper.exception0=Tomcat\u306e\u4f8b\u5916\u306e\u5831\u544a -standardWrapper.exception1=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -standardWrapper.exception2=\u4f8b\u5916\u306e\u5831\u544a: -standardWrapper.exception3=\u6839\u672c\u306e\u539f\u56e0: -standardWrapper.initException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.init()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardWrapper.instantiate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u3092\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -standardWrapper.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 -standardWrapper.jasperLoader=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306bJasper\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u3092\u4f7f\u7528\u3057\u307e\u3059 -standardWrapper.jspFile.format=JSP\u30d5\u30a1\u30a4\u30eb {0} \u304c''/''\u6587\u5b57\u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u305b\u3093 -standardWrapper.loadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardWrapper.missingClass=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u53c8\u306f\u305d\u308c\u304c\u4f9d\u5b58\u3059\u308b\u30af\u30e9\u30b9\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 -standardWrapper.missingLoader=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30ed\u30fc\u30c0\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 -standardWrapper.notChild=\u30e9\u30c3\u30d1\u30b3\u30f3\u30c6\u30ca\u306f\u5b50\u4f9b\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -standardWrapper.notClass=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u6307\u5b9a\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9\u304c\u3042\u308a\u307e\u305b\u3093 -standardWrapper.notContext=\u30e9\u30c3\u30d1\u306e\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -standardWrapper.notFound=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 -standardWrapper.notServlet=\u30af\u30e9\u30b9 {0} \u306f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -standardWrapper.privilegedServlet=\u30af\u30e9\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306f\u7279\u6a29\u3092\u4e0e\u3048\u3089\u308c\u3066\u3044\u308b\u306e\u3067\u3001\u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -standardWrapper.releaseFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 -standardWrapper.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardWrapper.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} -standardWrapper.statusTitle=Tomcat\u306e\u30a8\u30e9\u30fc\u306e\u5831\u544a -standardWrapper.unavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u5229\u7528\u4e0d\u53ef\u80fd\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 -standardWrapper.unloadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cunload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardWrapper.unloading=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u30ed\u30fc\u30c9\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 -standardWrapper.waiting={0} \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u5272\u308a\u5f53\u3066\u89e3\u9664\u3055\u308c\u308b\u306e\u3092\u5f85\u3063\u3066\u3044\u307e\u3059 +applicationContext.attributeEvent=\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u306b\u3088\u3063\u3066\u4f8b\u5916\u304c\u6295\u3052\u3089\u308c\u307e\u3057\u305f +applicationContext.mapping.error=\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +applicationContext.requestDispatcher.iae=\u30d1\u30b9 {0} \u304c"/"\u6587\u5b57\u3067\u59cb\u307e\u308a\u307e\u305b\u3093 +applicationContext.setAttribute.namenull=name\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +applicationDispatcher.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 +applicationDispatcher.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 +applicationDispatcher.forward.ise=\u30ec\u30b9\u30dd\u30f3\u30b9\u3092\u30b3\u30df\u30c3\u30c8\u3057\u305f\u5f8c\u3067\u30d5\u30a9\u30ef\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +applicationDispatcher.forward.throw=\u30d5\u30a9\u30ef\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +applicationDispatcher.include.throw=\u30a4\u30f3\u30af\u30eb\u30fc\u30c9\u3057\u305f\u30ea\u30bd\u30fc\u30b9\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +applicationDispatcher.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 +applicationDispatcher.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +applicationRequest.badParent=\u89aa\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 +applicationRequest.badRequest=\u30ea\u30af\u30a8\u30b9\u30c8\u304cjavax.servlet.ServletRequestWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +applicationResponse.badParent=\u89aa\u306e\u30ec\u30b9\u30dd\u30f3\u30b9\u5b9f\u88c5\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 +applicationResponse.badResponse=\u30ec\u30b9\u30dd\u30f3\u30b9\u304cjavax.servlet.ServletResponseWrapper\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +containerBase.addDefaultMapper=\u30af\u30e9\u30b9 {0} \u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u30de\u30c3\u30d1\u3092\u8a2d\u5b9a\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +containerBase.alreadyStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +containerBase.notConfigured=\u57fa\u672c\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +containerBase.notStarted=\u30b3\u30f3\u30c6\u30ca {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +fastEngineMapper.alreadyStarted=FastEngineMapper {0} \u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +fastEngineMapper.notStarted=FastEngineMapper {0} \u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +filterChain.filter=\u30d5\u30a3\u30eb\u30bf\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +filterChain.servlet=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u5b9f\u884c\u306b\u3088\u308a\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +httpContextMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardContext\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +httpEngineMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardEngine\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +httpHostMapper.container=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u306fStandardHost\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +interceptorValve.alreadyStarted=InterceptorValve\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +interceptorValve.notStarted=InterceptorValve\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +naming.bindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +naming.unbindFailed=\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306e\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +naming.invalidEnvEntryType=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u578b\u3092\u6301\u3063\u3066\u3044\u307e\u3059 +naming.invalidEnvEntryValue=\u74b0\u5883\u30a8\u30f3\u30c8\u30ea {0} \u306f\u7121\u52b9\u306a\u5024\u3092\u6301\u3063\u3066\u3044\u307e\u3059 +naming.namingContextCreationFailed=\u540d\u524d\u4ed8\u304d\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u751f\u6210\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +standardContext.alreadyStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardContext.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8a2d\u5b9a\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +standardContext.applicationSkipped=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3092\u30b9\u30ad\u30c3\u30d7\u3057\u307e\u3059 +standardContext.badRequest=\u7121\u52b9\u306a\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9\u3067\u3059 ({0})\u3002 +standardContext.errorPage.error=\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.errorPage.required=ErrorPage\u304cnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +standardContext.errorPage.warning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u306e\u4f4d\u7f6e {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.filterMap.either=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u53c8\u306f\u306e\u3069\u3061\u3089\u304b\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.filterMap.name=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30d5\u30a3\u30eb\u30bf\u540d {0} \u3092\u6307\u5b9a\u3057\u307e\u3057\u305f +standardContext.filterMap.pattern=\u30d5\u30a3\u30eb\u30bf\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 +standardContext.filterStart=\u30d5\u30a3\u30eb\u30bf {0} \u306e\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.filterStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d5\u30a3\u30eb\u30bf\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f +standardContext.requestListenerStartFailed=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f +standardContext.requestListenerConfig.added=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u3092\u8ffd\u52a0\u3057\u307e\u3057\u305f +standardContext.requestListenerConfig.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30ea\u30b9\u30ca\u30d0\u30eb\u30d6\u8ffd\u52a0\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0} +standardContext.isUnavailable=\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 +standardContext.listenerStart=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.listenerStartFailed=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30ea\u30b9\u30ca\u306e\u8d77\u52d5\u306b\u5931\u6557\u3057\u307e\u3057\u305f +standardContext.listenerStop=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u7834\u68c4\u30a4\u30d9\u30f3\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.loginConfig.errorPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.loginConfig.errorWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30a8\u30e9\u30fc\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.loginConfig.loginPage=\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.loginConfig.loginWarning=\u8b66\u544a: Servlet 2.4\u3067\u306f\u30d5\u30a9\u30fc\u30e0\u306e\u30ed\u30b0\u30a4\u30f3\u30da\u30fc\u30b8 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.loginConfig.required=LoginConfig\u306fnull\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +standardContext.mappingError=\u76f8\u5bfeURI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 +standardContext.notFound=\u30ea\u30af\u30a8\u30b9\u30c8\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9 ({0}) \u306f\u5229\u7528\u3067\u304d\u307e\u305b\u3093\u3002 +standardContext.notReloadable=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u518d\u30ed\u30fc\u30c9\u306f\u7121\u52b9\u3067\u3059 +standardContext.notStarted=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardContext.notWrapper=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30e9\u30c3\u30d1\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.parameter.duplicate=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u521d\u671f\u5316\u30d1\u30e9\u30e1\u30bf {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059 +standardContext.parameter.required=\u30d1\u30e9\u30e1\u30bf\u540d\u3068\u30d1\u30e9\u30e1\u30bf\u5024\u306e\u4e21\u65b9\u304c\u5fc5\u8981\u3067\u3059 +standardContext.reloadingCompleted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f +standardContext.reloadingFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f +standardContext.reloadingStarted=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u3092\u958b\u59cb\u3057\u307e\u3057\u305f +standardContext.resourcesStart=\u9759\u7684\u30ea\u30bd\u30fc\u30b9\u306e\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +standardContext.securityConstraint.pattern=\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u306e\u5236\u7d04\u306e\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 +standardContext.servletMap.name=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u306f\u672a\u77e5\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d {0} \u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059 +standardContext.servletMap.pattern=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u4e2d\u306b\u7121\u52b9\u306a {0} \u304c\u3042\u308a\u307e\u3059 +standardContext.startCleanup=\u8d77\u52d5\u304c\u5931\u6557\u3057\u305f\u5f8c\u306e\u30af\u30ea\u30fc\u30f3\u30ca\u30c3\u30d7\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +standardContext.startFailed=\u4ee5\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u8d77\u52d5\u304c\u5931\u6557\u3057\u307e\u3057\u305f [{0}] +standardContext.startingLoader=\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.startingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.startingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u8d77\u52d5\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.stoppingContext=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.stoppingLoader=\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.stoppingManager=\u30de\u30cd\u30fc\u30b8\u30e3\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.stoppingWrapper=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30e9\u30c3\u30d1\u3092\u505c\u6b62\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardContext.urlDecode=\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u306eURL\u30c7\u30b3\u30fc\u30c9\u304c\u3067\u304d\u307e\u305b\u3093 +standardContext.urlPattern.patternWarning=\u8b66\u544a: Servlet 2.4\u3067\u306fURL\u30d1\u30bf\u30fc\u30f3 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.urlValidate=URL\u30c7\u30b3\u30fc\u30c9\u3055\u308c\u305f\u30ea\u30af\u30a8\u30b9\u30c8\u30d1\u30b9 {0} \u3092\u691c\u8a3c\u3067\u304d\u307e\u305b\u3093 +standardContext.wrapper.error=JSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardContext.wrapper.warning=\u8b66\u544a: Servlet 2.4\u3067\u306fJSP\u30d5\u30a1\u30a4\u30eb {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardEngine.alreadyStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardEngine.mappingError=\u30b5\u30fc\u30d0\u540d {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 +standardEngine.noHost=\u30b5\u30fc\u30d0\u540d {0} \u306b\u4e00\u81f4\u3059\u308b\u30db\u30b9\u30c8\u304c\u5b58\u5728\u3057\u307e\u305b\u3093 +standardEngine.noHostHeader=Host:\u30d8\u30c3\u30c0\u3092\u6301\u305f\u306a\u3044 HTTP/1.1 \u30ea\u30af\u30a8\u30b9\u30c8\u3067\u3059 +standardEngine.notHost=\u30a8\u30f3\u30b8\u30f3\u306e\u5b50\u4f9b\u306f\u30db\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardEngine.notParent=\u30a8\u30f3\u30b8\u30f3\u306f\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +standardEngine.notStarted=\u30a8\u30f3\u30b8\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardEngine.unfoundHost=\u30d0\u30fc\u30c1\u30e3\u30eb\u30db\u30b9\u30c8 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +standardEngine.unknownHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u4e2d\u306b\u30b5\u30fc\u30d0\u30db\u30b9\u30c8\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardHost.accessBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093 +standardHost.alreadyStarted=\u30db\u30b9\u30c8\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardHost.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 +standardHost.clientAbort=\u30ea\u30e2\u30fc\u30c8\u30af\u30e9\u30a4\u30a2\u30f3\u30c8\u304c\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u4e2d\u6b62\u3057\u307e\u3057\u305f, IOException: {0} +standardHost.configRequired=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u3078\u306eURL\u304c\u5fc5\u8981\u3067\u3059 +standardHost.configNotAllowed=\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u304c\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +standardHost.installBase=\u30db\u30b9\u30c8Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u4e2d\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3060\u3051\u304c\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3067\u304d\u307e\u3059 +standardHost.installing=URL {1} \u304b\u3089\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306bWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 +standardHost.installingWAR=URL {0} \u304b\u3089Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u30a4\u30f3\u30b9\u30c8\u30fc\u30eb\u3057\u307e\u3059 +standardHost.installingXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u8a2d\u5b9a\u30d5\u30a1\u30a4\u30eb\u306eURL {0} \u3092\u51e6\u7406\u3057\u3066\u3044\u307e\u3059 +standardHost.installError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306b\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +standardHost.invalidErrorReportValveClass=\u6307\u5b9a\u3055\u308c\u305f\u30a8\u30e9\u30fc\u30ea\u30dd\u30fc\u30c8\u30d0\u30eb\u30d6\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093: {0} +standardHost.docBase=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\u65e2\u306b\u5b58\u5728\u3057\u307e\u3059 +standardHost.mappingError=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30de\u30c3\u30d4\u30f3\u30b0\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 +standardHost.noContext=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 +standardHost.noHost=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u305f\u3081\u306b\u8a2d\u5b9a\u3055\u308c\u305f\u30db\u30b9\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 +standardHost.notContext=\u30db\u30b9\u30c8\u306e\u5b50\u4f9b\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardHost.notStarted=\u30db\u30b9\u30c8\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardHost.nullName=\u30db\u30b9\u30c8\u540d\u304c\u5fc5\u8981\u3067\u3059 +standardHost.pathFormat=\u7121\u52b9\u306a\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u3067\u3059: {0} +standardHost.pathMatch=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u53c8\u306fWAR\u30d5\u30a1\u30a4\u30eb\u540d\u306b\u4e00\u81f4\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093: {1} +standardHost.pathMissing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u73fe\u5728\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardHost.pathRequired=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9\u304c\u5fc5\u8981\u3067\u3059 +standardHost.pathUsed=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306f\u65e2\u306b\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 +standardHost.removing=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u3057\u307e\u3059 +standardHost.removeError=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u524a\u9664\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +standardHost.start=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u8d77\u52d5\u3057\u307e\u3059 +standardHost.stop=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u505c\u6b62\u3057\u307e\u3059 +standardHost.unfoundContext=\u30ea\u30af\u30a8\u30b9\u30c8URI {0} \u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 +standardHost.warRequired=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306eURL\u304c\u5fc5\u8981\u3067\u3059 +standardHost.warURL=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306aURL\u3067\u3059: {0} +standardHost.validationEnabled=XML\u691c\u8a3c\u306f\u6709\u52b9\u3067\u3059 +standardHost.validationDisabled=XML\u691c\u8a3c\u306f\u7121\u52b9\u3067\u3059 +standardPipeline.alreadyStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardPipeline.notStarted=\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardPipeline.noValve=\u3053\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u51e6\u7406\u3059\u308b\u30d1\u30a4\u30d7\u30e9\u30a4\u30f3\u4e2d\u306b\u3053\u308c\u4ee5\u4e0a\u306e\u30d0\u30eb\u30d6\u306f\u3042\u308a\u307e\u305b\u3093 +standardServer.addContainer.ise=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u95a2\u9023\u3065\u3051\u308b\u305f\u3081\u306e\u30b3\u30cd\u30af\u30bf\u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 +standardServer.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardServer.start.connectors=\u30b3\u30f3\u30c6\u30ca\u306b\u4e00\u3064\u3082\u30b3\u30cd\u30af\u30bf\u304c\u95a2\u9023\u3065\u3051\u3089\u308c\u3066\u3044\u307e\u305b\u3093 +standardServer.start.started=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardServer.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardService.initialize.initialized=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u521d\u671f\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardService.start.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u8d77\u52d5\u3057\u307e\u3059 +standardService.start.started=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardService.stop.name=\u30b5\u30fc\u30d3\u30b9 {0} \u3092\u505c\u6b62\u3057\u307e\u3059 +standardService.stop.notStarted=\u3053\u306e\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardWrapper.allocate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +standardWrapper.allocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u4f8b\u5916\u3092\u5272\u308a\u5f53\u3066\u307e\u3059 +standardWrapper.containerServlet=\u30b3\u30f3\u30c6\u30ca\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 +standardWrapper.createFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0}\u306b\u5bfe\u3059\u308b\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u4f5c\u6210\u3057\u307e\u3059 +standardWrapper.deallocateException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u5bfe\u3059\u308b\u4f8b\u5916\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3057\u307e\u3059 +standardWrapper.destroyException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.destroy()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardWrapper.exception0=Tomcat\u306e\u4f8b\u5916\u306e\u5831\u544a +standardWrapper.exception1=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +standardWrapper.exception2=\u4f8b\u5916\u306e\u5831\u544a: +standardWrapper.exception3=\u6839\u672c\u306e\u539f\u56e0: +standardWrapper.initException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.init()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardWrapper.instantiate=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u3092\u521d\u671f\u5316\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +standardWrapper.isUnavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306f\u73fe\u5728\u5229\u7528\u3067\u304d\u307e\u305b\u3093 +standardWrapper.jasperLoader=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306bJasper\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u3092\u4f7f\u7528\u3057\u307e\u3059 +standardWrapper.jspFile.format=JSP\u30d5\u30a1\u30a4\u30eb {0} \u304c''/''\u6587\u5b57\u3067\u59cb\u307e\u3063\u3066\u3044\u307e\u305b\u3093 +standardWrapper.loadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardWrapper.missingClass=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9 {0} \u53c8\u306f\u305d\u308c\u304c\u4f9d\u5b58\u3059\u308b\u30af\u30e9\u30b9\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 +standardWrapper.missingLoader=\u30e9\u30c3\u30d1\u304c\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30ed\u30fc\u30c0\u3092\u898b\u3064\u3051\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 +standardWrapper.notChild=\u30e9\u30c3\u30d1\u30b3\u30f3\u30c6\u30ca\u306f\u5b50\u4f9b\u306e\u30b3\u30f3\u30c6\u30ca\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +standardWrapper.notClass=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306b\u6307\u5b9a\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30af\u30e9\u30b9\u304c\u3042\u308a\u307e\u305b\u3093 +standardWrapper.notContext=\u30e9\u30c3\u30d1\u306e\u89aa\u306e\u30b3\u30f3\u30c6\u30ca\u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +standardWrapper.notFound=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u5229\u7528\u3067\u304d\u307e\u305b\u3093 +standardWrapper.notServlet=\u30af\u30e9\u30b9 {0} \u306f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +standardWrapper.privilegedServlet=\u30af\u30e9\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306f\u7279\u6a29\u3092\u4e0e\u3048\u3089\u308c\u3066\u3044\u308b\u306e\u3067\u3001\u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306b\u3088\u3063\u3066\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +standardWrapper.releaseFilters=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306e\u30d5\u30a3\u30eb\u30bf\u4f8b\u5916\u3092\u89e3\u9664\u3057\u307e\u3059 +standardWrapper.serviceException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u306eServlet.service()\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardWrapper.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} +standardWrapper.statusTitle=Tomcat\u306e\u30a8\u30e9\u30fc\u306e\u5831\u544a +standardWrapper.unavailable=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u3092\u5229\u7528\u4e0d\u53ef\u80fd\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 +standardWrapper.unloadException=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304cunload()\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardWrapper.unloading=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8 {0} \u304c\u30ed\u30fc\u30c9\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u5272\u308a\u5f53\u3066\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 +standardWrapper.waiting={0} \u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u304c\u5272\u308a\u5f53\u3066\u89e3\u9664\u3055\u308c\u308b\u306e\u3092\u5f85\u3063\u3066\u3044\u307e\u3059 diff --git a/java/org/apache/catalina/core/NamingContextListener.java b/java/org/apache/catalina/core/NamingContextListener.java index 838d8fdd2..fe9249748 100644 --- a/java/org/apache/catalina/core/NamingContextListener.java +++ b/java/org/apache/catalina/core/NamingContextListener.java @@ -1,1025 +1,1025 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.StringTokenizer; - -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.naming.NameAlreadyBoundException; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.StringRefAddr; - -import org.apache.catalina.Container; -import org.apache.catalina.ContainerEvent; -import org.apache.catalina.ContainerListener; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Server; -import org.apache.catalina.Service; -import org.apache.catalina.deploy.ContextEjb; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextLocalEjb; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceEnvRef; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.ContextTransaction; -import org.apache.catalina.deploy.NamingResources; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.naming.ContextAccessController; -import org.apache.naming.ContextBindings; -import org.apache.naming.EjbRef; -import org.apache.naming.NamingContext; -import org.apache.naming.ResourceEnvRef; -import org.apache.naming.ResourceLinkRef; -import org.apache.naming.ResourceRef; -import org.apache.naming.TransactionRef; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Helper class used to initialize and populate the JNDI context associated - * with each context and server. - * - * @author Remy Maucherat - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - */ - -public class NamingContextListener - implements LifecycleListener, ContainerListener, PropertyChangeListener { - - private static Log log = LogFactory.getLog(NamingContextListener.class); - - - // ----------------------------------------------------- Instance Variables - - - protected Log logger = log; - - - /** - * Name of the associated naming context. - */ - protected String name = "/"; - - - /** - * Associated container. - */ - protected Object container = null; - - - /** - * Initialized flag. - */ - protected boolean initialized = false; - - - /** - * Associated naming resources. - */ - protected NamingResources namingResources = null; - - - /** - * Associated JNDI context. - */ - protected NamingContext namingContext = null; - - - /** - * Comp context. - */ - protected javax.naming.Context compCtx = null; - - - /** - * Env context. - */ - protected javax.naming.Context envCtx = null; - - - /** - * Objectnames hashtable. - */ - protected HashMap objectNames = new HashMap(); - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the "name" property. - */ - public String getName() { - return (this.name); - } - - - /** - * Set the "name" property. - * - * @param name The new name - */ - public void setName(String name) { - this.name = name; - } - - - /** - * Return the comp context. - */ - public javax.naming.Context getCompContext() { - return this.compCtx; - } - - - /** - * Return the env context. - */ - public javax.naming.Context getEnvContext() { - return this.envCtx; - } - - - /** - * Return the associated naming context. - */ - public NamingContext getNamingContext() { - return (this.namingContext); - } - - - // ---------------------------------------------- LifecycleListener Methods - - - /** - * Acknowledge the occurrence of the specified event. - * - * @param event LifecycleEvent that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - container = event.getLifecycle(); - - if (container instanceof Context) { - namingResources = ((Context) container).getNamingResources(); - logger = log; - } else if (container instanceof Server) { - namingResources = ((Server) container).getGlobalNamingResources(); - } else { - return; - } - - if (event.getType() == Lifecycle.START_EVENT) { - - if (initialized) - return; - - Hashtable contextEnv = new Hashtable(); - try { - namingContext = new NamingContext(contextEnv, getName()); - } catch (NamingException e) { - // Never happens - } - ContextAccessController.setSecurityToken(getName(), container); - ContextBindings.bindContext(container, namingContext, container); - if( log.isDebugEnabled() ) { - log.debug("Bound " + container ); - } - - // Setting the context in read/write mode - ContextAccessController.setWritable(getName(), container); - - try { - createNamingContext(); - } catch (NamingException e) { - logger.error - (sm.getString("naming.namingContextCreationFailed", e)); - } - - // Binding the naming context to the class loader - if (container instanceof Context) { - // Setting the context in read only mode - ContextAccessController.setReadOnly(getName()); - try { - ContextBindings.bindClassLoader - (container, container, - ((Container) container).getLoader().getClassLoader()); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - } - - if (container instanceof Server) { - namingResources.addPropertyChangeListener(this); - org.apache.naming.factory.ResourceLinkFactory.setGlobalContext - (namingContext); - try { - ContextBindings.bindClassLoader - (container, container, - this.getClass().getClassLoader()); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - if (container instanceof StandardServer) { - ((StandardServer) container).setGlobalNamingContext - (namingContext); - } - } - - initialized = true; - - } else if (event.getType() == Lifecycle.STOP_EVENT) { - - if (!initialized) - return; - - // Setting the context in read/write mode - ContextAccessController.setWritable(getName(), container); - ContextBindings.unbindContext(container, container); - - if (container instanceof Context) { - ContextBindings.unbindClassLoader - (container, container, - ((Container) container).getLoader().getClassLoader()); - } - - if (container instanceof Server) { - namingResources.removePropertyChangeListener(this); - ContextBindings.unbindClassLoader - (container, container, - this.getClass().getClassLoader()); - } - - ContextAccessController.unsetSecurityToken(getName(), container); - - namingContext = null; - envCtx = null; - compCtx = null; - initialized = false; - - } - - } - - - // ---------------------------------------------- ContainerListener Methods - - - /** - * Acknowledge the occurrence of the specified event. - * Note: Will never be called when the listener is associated to a Server, - * since it is not a Container. - * - * @param event ContainerEvent that has occurred - */ - public void containerEvent(ContainerEvent event) { - - if (!initialized) - return; - - // Setting the context in read/write mode - ContextAccessController.setWritable(getName(), container); - - String type = event.getType(); - - if (type.equals("addEjb")) { - - String ejbName = (String) event.getData(); - if (ejbName != null) { - ContextEjb ejb = namingResources.findEjb(ejbName); - addEjb(ejb); - } - - } else if (type.equals("addEnvironment")) { - - String environmentName = (String) event.getData(); - if (environmentName != null) { - ContextEnvironment env = - namingResources.findEnvironment(environmentName); - addEnvironment(env); - } - - } else if (type.equals("addLocalEjb")) { - - String localEjbName = (String) event.getData(); - if (localEjbName != null) { - ContextLocalEjb localEjb = - namingResources.findLocalEjb(localEjbName); - addLocalEjb(localEjb); - } - - } else if (type.equals("addResource")) { - - String resourceName = (String) event.getData(); - if (resourceName != null) { - ContextResource resource = - namingResources.findResource(resourceName); - addResource(resource); - } - - } else if (type.equals("addResourceLink")) { - - String resourceLinkName = (String) event.getData(); - if (resourceLinkName != null) { - ContextResourceLink resourceLink = - namingResources.findResourceLink(resourceLinkName); - addResourceLink(resourceLink); - } - - } else if (type.equals("addResourceEnvRef")) { - - String resourceEnvRefName = (String) event.getData(); - if (resourceEnvRefName != null) { - ContextResourceEnvRef resourceEnvRef = - namingResources.findResourceEnvRef(resourceEnvRefName); - addResourceEnvRef(resourceEnvRef); - } - - } else if (type.equals("removeEjb")) { - - String ejbName = (String) event.getData(); - if (ejbName != null) { - removeEjb(ejbName); - } - - } else if (type.equals("removeEnvironment")) { - - String environmentName = (String) event.getData(); - if (environmentName != null) { - removeEnvironment(environmentName); - } - - } else if (type.equals("removeLocalEjb")) { - - String localEjbName = (String) event.getData(); - if (localEjbName != null) { - removeLocalEjb(localEjbName); - } - - } else if (type.equals("removeResource")) { - - String resourceName = (String) event.getData(); - if (resourceName != null) { - removeResource(resourceName); - } - - } else if (type.equals("removeResourceLink")) { - - String resourceLinkName = (String) event.getData(); - if (resourceLinkName != null) { - removeResourceLink(resourceLinkName); - } - - } else if (type.equals("removeResourceEnvRef")) { - - String resourceEnvRefName = (String) event.getData(); - if (resourceEnvRefName != null) { - removeResourceEnvRef(resourceEnvRefName); - } - - } - - // Setting the context in read only mode - ContextAccessController.setReadOnly(getName()); - - } - - - // ----------------------------------------- PropertyChangeListener Methods - - - /** - * Process property change events. Currently, only listens to such events - * on the NamingResources instance for the global naming - * resources. - * - * @param event The property change event that has occurred - */ - public void propertyChange(PropertyChangeEvent event) { - - if (!initialized) - return; - - Object source = event.getSource(); - if (source == namingResources) { - - // Setting the context in read/write mode - ContextAccessController.setWritable(getName(), container); - - processGlobalResourcesChange(event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - - // Setting the context in read only mode - ContextAccessController.setReadOnly(getName()); - - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Process a property change on the global naming resources, by making the - * corresponding addition or removal to the associated JNDI context. - * - * @param name Property name of the change to be processed - * @param oldValue The old value (or null if adding) - * @param newValue The new value (or null if removing) - */ - private void processGlobalResourcesChange(String name, - Object oldValue, - Object newValue) { - - // NOTE - It seems that the Context for global JNDI resources - // is left in read-write mode, so we do not have to change it here - - if (name.equals("ejb")) { - if (oldValue != null) { - ContextEjb ejb = (ContextEjb) oldValue; - if (ejb.getName() != null) { - removeEjb(ejb.getName()); - } - } - if (newValue != null) { - ContextEjb ejb = (ContextEjb) newValue; - if (ejb.getName() != null) { - addEjb(ejb); - } - } - } else if (name.equals("environment")) { - if (oldValue != null) { - ContextEnvironment env = (ContextEnvironment) oldValue; - if (env.getName() != null) { - removeEnvironment(env.getName()); - } - } - if (newValue != null) { - ContextEnvironment env = (ContextEnvironment) newValue; - if (env.getName() != null) { - addEnvironment(env); - } - } - } else if (name.equals("localEjb")) { - if (oldValue != null) { - ContextLocalEjb ejb = (ContextLocalEjb) oldValue; - if (ejb.getName() != null) { - removeLocalEjb(ejb.getName()); - } - } - if (newValue != null) { - ContextLocalEjb ejb = (ContextLocalEjb) newValue; - if (ejb.getName() != null) { - addLocalEjb(ejb); - } - } - } else if (name.equals("resource")) { - if (oldValue != null) { - ContextResource resource = (ContextResource) oldValue; - if (resource.getName() != null) { - removeResource(resource.getName()); - } - } - if (newValue != null) { - ContextResource resource = (ContextResource) newValue; - if (resource.getName() != null) { - addResource(resource); - } - } - } else if (name.equals("resourceEnvRef")) { - if (oldValue != null) { - ContextResourceEnvRef resourceEnvRef = - (ContextResourceEnvRef) oldValue; - if (resourceEnvRef.getName() != null) { - removeResourceEnvRef(resourceEnvRef.getName()); - } - } - if (newValue != null) { - ContextResourceEnvRef resourceEnvRef = - (ContextResourceEnvRef) newValue; - if (resourceEnvRef.getName() != null) { - addResourceEnvRef(resourceEnvRef); - } - } - } else if (name.equals("resourceLink")) { - if (oldValue != null) { - ContextResourceLink rl = (ContextResourceLink) oldValue; - if (rl.getName() != null) { - removeResourceLink(rl.getName()); - } - } - if (newValue != null) { - ContextResourceLink rl = (ContextResourceLink) newValue; - if (rl.getName() != null) { - addResourceLink(rl); - } - } - } - - - } - - - /** - * Create and initialize the JNDI naming context. - */ - private void createNamingContext() - throws NamingException { - - // Creating the comp subcontext - if (container instanceof Server) { - compCtx = namingContext; - envCtx = namingContext; - } else { - compCtx = namingContext.createSubcontext("comp"); - envCtx = compCtx.createSubcontext("env"); - } - - int i; - - if (log.isDebugEnabled()) - log.debug("Creating JNDI naming context"); - - if (namingResources == null) { - namingResources = new NamingResources(); - namingResources.setContainer(container); - } - - // Resource links - ContextResourceLink[] resourceLinks = - namingResources.findResourceLinks(); - for (i = 0; i < resourceLinks.length; i++) { - addResourceLink(resourceLinks[i]); - } - - // Resources - ContextResource[] resources = namingResources.findResources(); - for (i = 0; i < resources.length; i++) { - addResource(resources[i]); - } - - // Resources Env - ContextResourceEnvRef[] resourceEnvRefs = namingResources.findResourceEnvRefs(); - for (i = 0; i < resourceEnvRefs.length; i++) { - addResourceEnvRef(resourceEnvRefs[i]); - } - - // Environment entries - ContextEnvironment[] contextEnvironments = - namingResources.findEnvironments(); - for (i = 0; i < contextEnvironments.length; i++) { - addEnvironment(contextEnvironments[i]); - } - - // EJB references - ContextEjb[] ejbs = namingResources.findEjbs(); - for (i = 0; i < ejbs.length; i++) { - addEjb(ejbs[i]); - } - - // Binding a User Transaction reference - if (container instanceof Context) { - try { - Reference ref = new TransactionRef(); - compCtx.bind("UserTransaction", ref); - ContextTransaction transaction = namingResources.getTransaction(); - if (transaction != null) { - Iterator params = transaction.listProperties(); - while (params.hasNext()) { - String paramName = (String) params.next(); - String paramValue = (String) transaction.getProperty(paramName); - StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); - ref.add(refAddr); - } - } - } catch (NameAlreadyBoundException e) { - // Ignore because UserTransaction was obviously - // added via ResourceLink - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - } - - // Binding the resources directory context - if (container instanceof Context) { - try { - compCtx.bind("Resources", - ((Container) container).getResources()); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - } - - } - - - /** - * Create an ObjectName for this - * ContextResource object. - * - * @param resource The resource - * @return ObjectName The object name - * @exception MalformedObjectNameException if a name cannot be created - */ - protected ObjectName createObjectName(ContextResource resource) - throws MalformedObjectNameException { - - String domain = null; - if (container instanceof StandardServer) { - domain = ((StandardServer) container).getDomain(); - } else if (container instanceof ContainerBase) { - domain = ((ContainerBase) container).getDomain(); - } - if (domain == null) { - domain = "Catalina"; - } - - ObjectName name = null; - String quotedResourceName = ObjectName.quote(resource.getName()); - if (container instanceof Server) { - name = new ObjectName(domain + ":type=DataSource" + - ",class=" + resource.getType() + - ",name=" + quotedResourceName); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) - path = "/"; - Host host = (Host) ((Context)container).getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=DataSource" + - ",path=" + path + - ",host=" + host.getName() + - ",class=" + resource.getType() + - ",name=" + quotedResourceName); - } - - return (name); - - } - - - /** - * Set the specified EJBs in the naming context. - */ - public void addEjb(ContextEjb ejb) { - - // Create a reference to the EJB. - Reference ref = new EjbRef - (ejb.getType(), ejb.getHome(), ejb.getRemote(), ejb.getLink()); - // Adding the additional parameters, if any - Iterator params = ejb.listProperties(); - while (params.hasNext()) { - String paramName = (String) params.next(); - String paramValue = (String) ejb.getProperty(paramName); - StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); - ref.add(refAddr); - } - try { - createSubcontexts(envCtx, ejb.getName()); - envCtx.bind(ejb.getName(), ref); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - - } - - - /** - * Set the specified environment entries in the naming context. - */ - public void addEnvironment(ContextEnvironment env) { - - Object value = null; - // Instantiating a new instance of the correct object type, and - // initializing it. - String type = env.getType(); - try { - if (type.equals("java.lang.String")) { - value = env.getValue(); - } else if (type.equals("java.lang.Byte")) { - if (env.getValue() == null) { - value = new Byte((byte) 0); - } else { - value = Byte.decode(env.getValue()); - } - } else if (type.equals("java.lang.Short")) { - if (env.getValue() == null) { - value = new Short((short) 0); - } else { - value = Short.decode(env.getValue()); - } - } else if (type.equals("java.lang.Integer")) { - if (env.getValue() == null) { - value = new Integer(0); - } else { - value = Integer.decode(env.getValue()); - } - } else if (type.equals("java.lang.Long")) { - if (env.getValue() == null) { - value = new Long(0); - } else { - value = Long.decode(env.getValue()); - } - } else if (type.equals("java.lang.Boolean")) { - value = Boolean.valueOf(env.getValue()); - } else if (type.equals("java.lang.Double")) { - if (env.getValue() == null) { - value = new Double(0); - } else { - value = Double.valueOf(env.getValue()); - } - } else if (type.equals("java.lang.Float")) { - if (env.getValue() == null) { - value = new Float(0); - } else { - value = Float.valueOf(env.getValue()); - } - } else if (type.equals("java.lang.Character")) { - if (env.getValue() == null) { - value = new Character((char) 0); - } else { - if (env.getValue().length() == 1) { - value = new Character(env.getValue().charAt(0)); - } else { - throw new IllegalArgumentException(); - } - } - } else { - logger.error(sm.getString("naming.invalidEnvEntryType", env.getName())); - } - } catch (NumberFormatException e) { - logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); - } catch (IllegalArgumentException e) { - logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); - } - - // Binding the object to the appropriate name - if (value != null) { - try { - if (logger.isDebugEnabled()) - logger.debug(" Adding environment entry " + env.getName()); - createSubcontexts(envCtx, env.getName()); - envCtx.bind(env.getName(), value); - } catch (NamingException e) { - logger.error(sm.getString("naming.invalidEnvEntryValue", e)); - } - } - - } - - - /** - * Set the specified local EJBs in the naming context. - */ - public void addLocalEjb(ContextLocalEjb localEjb) { - - - - } - - - /** - * Set the specified resources in the naming context. - */ - public void addResource(ContextResource resource) { - - // Create a reference to the resource. - Reference ref = new ResourceRef - (resource.getType(), resource.getDescription(), - resource.getScope(), resource.getAuth()); - // Adding the additional parameters, if any - Iterator params = resource.listProperties(); - while (params.hasNext()) { - String paramName = (String) params.next(); - String paramValue = (String) resource.getProperty(paramName); - StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); - ref.add(refAddr); - } - try { - if (logger.isDebugEnabled()) { - logger.debug(" Adding resource ref " - + resource.getName() + " " + ref); - } - createSubcontexts(envCtx, resource.getName()); - envCtx.bind(resource.getName(), ref); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - - if ("javax.sql.DataSource".equals(ref.getClassName())) { - try { - ObjectName on = createObjectName(resource); - Object actualResource = envCtx.lookup(resource.getName()); - Registry.getRegistry(null, null).registerComponent(actualResource, on, null); - objectNames.put(resource.getName(), on); - } catch (Exception e) { - logger.warn(sm.getString("naming.jmxRegistrationFailed", e)); - } - } - - } - - - /** - * Set the specified resources in the naming context. - */ - public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) { - - // Create a reference to the resource env. - Reference ref = new ResourceEnvRef(resourceEnvRef.getType()); - // Adding the additional parameters, if any - Iterator params = resourceEnvRef.listProperties(); - while (params.hasNext()) { - String paramName = (String) params.next(); - String paramValue = (String) resourceEnvRef.getProperty(paramName); - StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); - ref.add(refAddr); - } - try { - if (logger.isDebugEnabled()) - log.debug(" Adding resource env ref " + resourceEnvRef.getName()); - createSubcontexts(envCtx, resourceEnvRef.getName()); - envCtx.bind(resourceEnvRef.getName(), ref); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - - } - - - /** - * Set the specified resource link in the naming context. - */ - public void addResourceLink(ContextResourceLink resourceLink) { - - // Create a reference to the resource. - Reference ref = new ResourceLinkRef - (resourceLink.getType(), resourceLink.getGlobal()); - javax.naming.Context ctx = - "UserTransaction".equals(resourceLink.getName()) - ? compCtx : envCtx; - try { - if (logger.isDebugEnabled()) - log.debug(" Adding resource link " + resourceLink.getName()); - createSubcontexts(envCtx, resourceLink.getName()); - ctx.bind(resourceLink.getName(), ref); - } catch (NamingException e) { - logger.error(sm.getString("naming.bindFailed", e)); - } - - } - - - /** - * Set the specified EJBs in the naming context. - */ - public void removeEjb(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - } - - - /** - * Set the specified environment entries in the naming context. - */ - public void removeEnvironment(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - } - - - /** - * Set the specified local EJBs in the naming context. - */ - public void removeLocalEjb(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - } - - - /** - * Set the specified resources in the naming context. - */ - public void removeResource(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - ObjectName on = (ObjectName) objectNames.get(name); - if (on != null) { - Registry.getRegistry(null, null).unregisterComponent(on); - } - - } - - - /** - * Set the specified resources in the naming context. - */ - public void removeResourceEnvRef(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - } - - - /** - * Set the specified resources in the naming context. - */ - public void removeResourceLink(String name) { - - try { - envCtx.unbind(name); - } catch (NamingException e) { - logger.error(sm.getString("naming.unbindFailed", e)); - } - - } - - - /** - * Create all intermediate subcontexts. - */ - private void createSubcontexts(javax.naming.Context ctx, String name) - throws NamingException { - javax.naming.Context currentContext = ctx; - StringTokenizer tokenizer = new StringTokenizer(name, "/"); - while (tokenizer.hasMoreTokens()) { - String token = tokenizer.nextToken(); - if ((!token.equals("")) && (tokenizer.hasMoreTokens())) { - try { - currentContext = currentContext.createSubcontext(token); - } catch (NamingException e) { - // Silent catch. Probably an object is already bound in - // the context. - currentContext = - (javax.naming.Context) currentContext.lookup(token); - } - } - } - } - - -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.StringRefAddr; + +import org.apache.catalina.Container; +import org.apache.catalina.ContainerEvent; +import org.apache.catalina.ContainerListener; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Server; +import org.apache.catalina.Service; +import org.apache.catalina.deploy.ContextEjb; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextLocalEjb; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceEnvRef; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.ContextTransaction; +import org.apache.catalina.deploy.NamingResources; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.naming.ContextAccessController; +import org.apache.naming.ContextBindings; +import org.apache.naming.EjbRef; +import org.apache.naming.NamingContext; +import org.apache.naming.ResourceEnvRef; +import org.apache.naming.ResourceLinkRef; +import org.apache.naming.ResourceRef; +import org.apache.naming.TransactionRef; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Helper class used to initialize and populate the JNDI context associated + * with each context and server. + * + * @author Remy Maucherat + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + */ + +public class NamingContextListener + implements LifecycleListener, ContainerListener, PropertyChangeListener { + + private static Log log = LogFactory.getLog(NamingContextListener.class); + + + // ----------------------------------------------------- Instance Variables + + + protected Log logger = log; + + + /** + * Name of the associated naming context. + */ + protected String name = "/"; + + + /** + * Associated container. + */ + protected Object container = null; + + + /** + * Initialized flag. + */ + protected boolean initialized = false; + + + /** + * Associated naming resources. + */ + protected NamingResources namingResources = null; + + + /** + * Associated JNDI context. + */ + protected NamingContext namingContext = null; + + + /** + * Comp context. + */ + protected javax.naming.Context compCtx = null; + + + /** + * Env context. + */ + protected javax.naming.Context envCtx = null; + + + /** + * Objectnames hashtable. + */ + protected HashMap objectNames = new HashMap(); + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the "name" property. + */ + public String getName() { + return (this.name); + } + + + /** + * Set the "name" property. + * + * @param name The new name + */ + public void setName(String name) { + this.name = name; + } + + + /** + * Return the comp context. + */ + public javax.naming.Context getCompContext() { + return this.compCtx; + } + + + /** + * Return the env context. + */ + public javax.naming.Context getEnvContext() { + return this.envCtx; + } + + + /** + * Return the associated naming context. + */ + public NamingContext getNamingContext() { + return (this.namingContext); + } + + + // ---------------------------------------------- LifecycleListener Methods + + + /** + * Acknowledge the occurrence of the specified event. + * + * @param event LifecycleEvent that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + container = event.getLifecycle(); + + if (container instanceof Context) { + namingResources = ((Context) container).getNamingResources(); + logger = log; + } else if (container instanceof Server) { + namingResources = ((Server) container).getGlobalNamingResources(); + } else { + return; + } + + if (event.getType() == Lifecycle.START_EVENT) { + + if (initialized) + return; + + Hashtable contextEnv = new Hashtable(); + try { + namingContext = new NamingContext(contextEnv, getName()); + } catch (NamingException e) { + // Never happens + } + ContextAccessController.setSecurityToken(getName(), container); + ContextBindings.bindContext(container, namingContext, container); + if( log.isDebugEnabled() ) { + log.debug("Bound " + container ); + } + + // Setting the context in read/write mode + ContextAccessController.setWritable(getName(), container); + + try { + createNamingContext(); + } catch (NamingException e) { + logger.error + (sm.getString("naming.namingContextCreationFailed", e)); + } + + // Binding the naming context to the class loader + if (container instanceof Context) { + // Setting the context in read only mode + ContextAccessController.setReadOnly(getName()); + try { + ContextBindings.bindClassLoader + (container, container, + ((Container) container).getLoader().getClassLoader()); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + } + + if (container instanceof Server) { + namingResources.addPropertyChangeListener(this); + org.apache.naming.factory.ResourceLinkFactory.setGlobalContext + (namingContext); + try { + ContextBindings.bindClassLoader + (container, container, + this.getClass().getClassLoader()); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + if (container instanceof StandardServer) { + ((StandardServer) container).setGlobalNamingContext + (namingContext); + } + } + + initialized = true; + + } else if (event.getType() == Lifecycle.STOP_EVENT) { + + if (!initialized) + return; + + // Setting the context in read/write mode + ContextAccessController.setWritable(getName(), container); + ContextBindings.unbindContext(container, container); + + if (container instanceof Context) { + ContextBindings.unbindClassLoader + (container, container, + ((Container) container).getLoader().getClassLoader()); + } + + if (container instanceof Server) { + namingResources.removePropertyChangeListener(this); + ContextBindings.unbindClassLoader + (container, container, + this.getClass().getClassLoader()); + } + + ContextAccessController.unsetSecurityToken(getName(), container); + + namingContext = null; + envCtx = null; + compCtx = null; + initialized = false; + + } + + } + + + // ---------------------------------------------- ContainerListener Methods + + + /** + * Acknowledge the occurrence of the specified event. + * Note: Will never be called when the listener is associated to a Server, + * since it is not a Container. + * + * @param event ContainerEvent that has occurred + */ + public void containerEvent(ContainerEvent event) { + + if (!initialized) + return; + + // Setting the context in read/write mode + ContextAccessController.setWritable(getName(), container); + + String type = event.getType(); + + if (type.equals("addEjb")) { + + String ejbName = (String) event.getData(); + if (ejbName != null) { + ContextEjb ejb = namingResources.findEjb(ejbName); + addEjb(ejb); + } + + } else if (type.equals("addEnvironment")) { + + String environmentName = (String) event.getData(); + if (environmentName != null) { + ContextEnvironment env = + namingResources.findEnvironment(environmentName); + addEnvironment(env); + } + + } else if (type.equals("addLocalEjb")) { + + String localEjbName = (String) event.getData(); + if (localEjbName != null) { + ContextLocalEjb localEjb = + namingResources.findLocalEjb(localEjbName); + addLocalEjb(localEjb); + } + + } else if (type.equals("addResource")) { + + String resourceName = (String) event.getData(); + if (resourceName != null) { + ContextResource resource = + namingResources.findResource(resourceName); + addResource(resource); + } + + } else if (type.equals("addResourceLink")) { + + String resourceLinkName = (String) event.getData(); + if (resourceLinkName != null) { + ContextResourceLink resourceLink = + namingResources.findResourceLink(resourceLinkName); + addResourceLink(resourceLink); + } + + } else if (type.equals("addResourceEnvRef")) { + + String resourceEnvRefName = (String) event.getData(); + if (resourceEnvRefName != null) { + ContextResourceEnvRef resourceEnvRef = + namingResources.findResourceEnvRef(resourceEnvRefName); + addResourceEnvRef(resourceEnvRef); + } + + } else if (type.equals("removeEjb")) { + + String ejbName = (String) event.getData(); + if (ejbName != null) { + removeEjb(ejbName); + } + + } else if (type.equals("removeEnvironment")) { + + String environmentName = (String) event.getData(); + if (environmentName != null) { + removeEnvironment(environmentName); + } + + } else if (type.equals("removeLocalEjb")) { + + String localEjbName = (String) event.getData(); + if (localEjbName != null) { + removeLocalEjb(localEjbName); + } + + } else if (type.equals("removeResource")) { + + String resourceName = (String) event.getData(); + if (resourceName != null) { + removeResource(resourceName); + } + + } else if (type.equals("removeResourceLink")) { + + String resourceLinkName = (String) event.getData(); + if (resourceLinkName != null) { + removeResourceLink(resourceLinkName); + } + + } else if (type.equals("removeResourceEnvRef")) { + + String resourceEnvRefName = (String) event.getData(); + if (resourceEnvRefName != null) { + removeResourceEnvRef(resourceEnvRefName); + } + + } + + // Setting the context in read only mode + ContextAccessController.setReadOnly(getName()); + + } + + + // ----------------------------------------- PropertyChangeListener Methods + + + /** + * Process property change events. Currently, only listens to such events + * on the NamingResources instance for the global naming + * resources. + * + * @param event The property change event that has occurred + */ + public void propertyChange(PropertyChangeEvent event) { + + if (!initialized) + return; + + Object source = event.getSource(); + if (source == namingResources) { + + // Setting the context in read/write mode + ContextAccessController.setWritable(getName(), container); + + processGlobalResourcesChange(event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + + // Setting the context in read only mode + ContextAccessController.setReadOnly(getName()); + + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Process a property change on the global naming resources, by making the + * corresponding addition or removal to the associated JNDI context. + * + * @param name Property name of the change to be processed + * @param oldValue The old value (or null if adding) + * @param newValue The new value (or null if removing) + */ + private void processGlobalResourcesChange(String name, + Object oldValue, + Object newValue) { + + // NOTE - It seems that the Context for global JNDI resources + // is left in read-write mode, so we do not have to change it here + + if (name.equals("ejb")) { + if (oldValue != null) { + ContextEjb ejb = (ContextEjb) oldValue; + if (ejb.getName() != null) { + removeEjb(ejb.getName()); + } + } + if (newValue != null) { + ContextEjb ejb = (ContextEjb) newValue; + if (ejb.getName() != null) { + addEjb(ejb); + } + } + } else if (name.equals("environment")) { + if (oldValue != null) { + ContextEnvironment env = (ContextEnvironment) oldValue; + if (env.getName() != null) { + removeEnvironment(env.getName()); + } + } + if (newValue != null) { + ContextEnvironment env = (ContextEnvironment) newValue; + if (env.getName() != null) { + addEnvironment(env); + } + } + } else if (name.equals("localEjb")) { + if (oldValue != null) { + ContextLocalEjb ejb = (ContextLocalEjb) oldValue; + if (ejb.getName() != null) { + removeLocalEjb(ejb.getName()); + } + } + if (newValue != null) { + ContextLocalEjb ejb = (ContextLocalEjb) newValue; + if (ejb.getName() != null) { + addLocalEjb(ejb); + } + } + } else if (name.equals("resource")) { + if (oldValue != null) { + ContextResource resource = (ContextResource) oldValue; + if (resource.getName() != null) { + removeResource(resource.getName()); + } + } + if (newValue != null) { + ContextResource resource = (ContextResource) newValue; + if (resource.getName() != null) { + addResource(resource); + } + } + } else if (name.equals("resourceEnvRef")) { + if (oldValue != null) { + ContextResourceEnvRef resourceEnvRef = + (ContextResourceEnvRef) oldValue; + if (resourceEnvRef.getName() != null) { + removeResourceEnvRef(resourceEnvRef.getName()); + } + } + if (newValue != null) { + ContextResourceEnvRef resourceEnvRef = + (ContextResourceEnvRef) newValue; + if (resourceEnvRef.getName() != null) { + addResourceEnvRef(resourceEnvRef); + } + } + } else if (name.equals("resourceLink")) { + if (oldValue != null) { + ContextResourceLink rl = (ContextResourceLink) oldValue; + if (rl.getName() != null) { + removeResourceLink(rl.getName()); + } + } + if (newValue != null) { + ContextResourceLink rl = (ContextResourceLink) newValue; + if (rl.getName() != null) { + addResourceLink(rl); + } + } + } + + + } + + + /** + * Create and initialize the JNDI naming context. + */ + private void createNamingContext() + throws NamingException { + + // Creating the comp subcontext + if (container instanceof Server) { + compCtx = namingContext; + envCtx = namingContext; + } else { + compCtx = namingContext.createSubcontext("comp"); + envCtx = compCtx.createSubcontext("env"); + } + + int i; + + if (log.isDebugEnabled()) + log.debug("Creating JNDI naming context"); + + if (namingResources == null) { + namingResources = new NamingResources(); + namingResources.setContainer(container); + } + + // Resource links + ContextResourceLink[] resourceLinks = + namingResources.findResourceLinks(); + for (i = 0; i < resourceLinks.length; i++) { + addResourceLink(resourceLinks[i]); + } + + // Resources + ContextResource[] resources = namingResources.findResources(); + for (i = 0; i < resources.length; i++) { + addResource(resources[i]); + } + + // Resources Env + ContextResourceEnvRef[] resourceEnvRefs = namingResources.findResourceEnvRefs(); + for (i = 0; i < resourceEnvRefs.length; i++) { + addResourceEnvRef(resourceEnvRefs[i]); + } + + // Environment entries + ContextEnvironment[] contextEnvironments = + namingResources.findEnvironments(); + for (i = 0; i < contextEnvironments.length; i++) { + addEnvironment(contextEnvironments[i]); + } + + // EJB references + ContextEjb[] ejbs = namingResources.findEjbs(); + for (i = 0; i < ejbs.length; i++) { + addEjb(ejbs[i]); + } + + // Binding a User Transaction reference + if (container instanceof Context) { + try { + Reference ref = new TransactionRef(); + compCtx.bind("UserTransaction", ref); + ContextTransaction transaction = namingResources.getTransaction(); + if (transaction != null) { + Iterator params = transaction.listProperties(); + while (params.hasNext()) { + String paramName = (String) params.next(); + String paramValue = (String) transaction.getProperty(paramName); + StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); + ref.add(refAddr); + } + } + } catch (NameAlreadyBoundException e) { + // Ignore because UserTransaction was obviously + // added via ResourceLink + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + } + + // Binding the resources directory context + if (container instanceof Context) { + try { + compCtx.bind("Resources", + ((Container) container).getResources()); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + } + + } + + + /** + * Create an ObjectName for this + * ContextResource object. + * + * @param resource The resource + * @return ObjectName The object name + * @exception MalformedObjectNameException if a name cannot be created + */ + protected ObjectName createObjectName(ContextResource resource) + throws MalformedObjectNameException { + + String domain = null; + if (container instanceof StandardServer) { + domain = ((StandardServer) container).getDomain(); + } else if (container instanceof ContainerBase) { + domain = ((ContainerBase) container).getDomain(); + } + if (domain == null) { + domain = "Catalina"; + } + + ObjectName name = null; + String quotedResourceName = ObjectName.quote(resource.getName()); + if (container instanceof Server) { + name = new ObjectName(domain + ":type=DataSource" + + ",class=" + resource.getType() + + ",name=" + quotedResourceName); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) + path = "/"; + Host host = (Host) ((Context)container).getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=DataSource" + + ",path=" + path + + ",host=" + host.getName() + + ",class=" + resource.getType() + + ",name=" + quotedResourceName); + } + + return (name); + + } + + + /** + * Set the specified EJBs in the naming context. + */ + public void addEjb(ContextEjb ejb) { + + // Create a reference to the EJB. + Reference ref = new EjbRef + (ejb.getType(), ejb.getHome(), ejb.getRemote(), ejb.getLink()); + // Adding the additional parameters, if any + Iterator params = ejb.listProperties(); + while (params.hasNext()) { + String paramName = (String) params.next(); + String paramValue = (String) ejb.getProperty(paramName); + StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); + ref.add(refAddr); + } + try { + createSubcontexts(envCtx, ejb.getName()); + envCtx.bind(ejb.getName(), ref); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + + } + + + /** + * Set the specified environment entries in the naming context. + */ + public void addEnvironment(ContextEnvironment env) { + + Object value = null; + // Instantiating a new instance of the correct object type, and + // initializing it. + String type = env.getType(); + try { + if (type.equals("java.lang.String")) { + value = env.getValue(); + } else if (type.equals("java.lang.Byte")) { + if (env.getValue() == null) { + value = new Byte((byte) 0); + } else { + value = Byte.decode(env.getValue()); + } + } else if (type.equals("java.lang.Short")) { + if (env.getValue() == null) { + value = new Short((short) 0); + } else { + value = Short.decode(env.getValue()); + } + } else if (type.equals("java.lang.Integer")) { + if (env.getValue() == null) { + value = new Integer(0); + } else { + value = Integer.decode(env.getValue()); + } + } else if (type.equals("java.lang.Long")) { + if (env.getValue() == null) { + value = new Long(0); + } else { + value = Long.decode(env.getValue()); + } + } else if (type.equals("java.lang.Boolean")) { + value = Boolean.valueOf(env.getValue()); + } else if (type.equals("java.lang.Double")) { + if (env.getValue() == null) { + value = new Double(0); + } else { + value = Double.valueOf(env.getValue()); + } + } else if (type.equals("java.lang.Float")) { + if (env.getValue() == null) { + value = new Float(0); + } else { + value = Float.valueOf(env.getValue()); + } + } else if (type.equals("java.lang.Character")) { + if (env.getValue() == null) { + value = new Character((char) 0); + } else { + if (env.getValue().length() == 1) { + value = new Character(env.getValue().charAt(0)); + } else { + throw new IllegalArgumentException(); + } + } + } else { + logger.error(sm.getString("naming.invalidEnvEntryType", env.getName())); + } + } catch (NumberFormatException e) { + logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); + } catch (IllegalArgumentException e) { + logger.error(sm.getString("naming.invalidEnvEntryValue", env.getName())); + } + + // Binding the object to the appropriate name + if (value != null) { + try { + if (logger.isDebugEnabled()) + logger.debug(" Adding environment entry " + env.getName()); + createSubcontexts(envCtx, env.getName()); + envCtx.bind(env.getName(), value); + } catch (NamingException e) { + logger.error(sm.getString("naming.invalidEnvEntryValue", e)); + } + } + + } + + + /** + * Set the specified local EJBs in the naming context. + */ + public void addLocalEjb(ContextLocalEjb localEjb) { + + + + } + + + /** + * Set the specified resources in the naming context. + */ + public void addResource(ContextResource resource) { + + // Create a reference to the resource. + Reference ref = new ResourceRef + (resource.getType(), resource.getDescription(), + resource.getScope(), resource.getAuth()); + // Adding the additional parameters, if any + Iterator params = resource.listProperties(); + while (params.hasNext()) { + String paramName = (String) params.next(); + String paramValue = (String) resource.getProperty(paramName); + StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); + ref.add(refAddr); + } + try { + if (logger.isDebugEnabled()) { + logger.debug(" Adding resource ref " + + resource.getName() + " " + ref); + } + createSubcontexts(envCtx, resource.getName()); + envCtx.bind(resource.getName(), ref); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + + if ("javax.sql.DataSource".equals(ref.getClassName())) { + try { + ObjectName on = createObjectName(resource); + Object actualResource = envCtx.lookup(resource.getName()); + Registry.getRegistry(null, null).registerComponent(actualResource, on, null); + objectNames.put(resource.getName(), on); + } catch (Exception e) { + logger.warn(sm.getString("naming.jmxRegistrationFailed", e)); + } + } + + } + + + /** + * Set the specified resources in the naming context. + */ + public void addResourceEnvRef(ContextResourceEnvRef resourceEnvRef) { + + // Create a reference to the resource env. + Reference ref = new ResourceEnvRef(resourceEnvRef.getType()); + // Adding the additional parameters, if any + Iterator params = resourceEnvRef.listProperties(); + while (params.hasNext()) { + String paramName = (String) params.next(); + String paramValue = (String) resourceEnvRef.getProperty(paramName); + StringRefAddr refAddr = new StringRefAddr(paramName, paramValue); + ref.add(refAddr); + } + try { + if (logger.isDebugEnabled()) + log.debug(" Adding resource env ref " + resourceEnvRef.getName()); + createSubcontexts(envCtx, resourceEnvRef.getName()); + envCtx.bind(resourceEnvRef.getName(), ref); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + + } + + + /** + * Set the specified resource link in the naming context. + */ + public void addResourceLink(ContextResourceLink resourceLink) { + + // Create a reference to the resource. + Reference ref = new ResourceLinkRef + (resourceLink.getType(), resourceLink.getGlobal()); + javax.naming.Context ctx = + "UserTransaction".equals(resourceLink.getName()) + ? compCtx : envCtx; + try { + if (logger.isDebugEnabled()) + log.debug(" Adding resource link " + resourceLink.getName()); + createSubcontexts(envCtx, resourceLink.getName()); + ctx.bind(resourceLink.getName(), ref); + } catch (NamingException e) { + logger.error(sm.getString("naming.bindFailed", e)); + } + + } + + + /** + * Set the specified EJBs in the naming context. + */ + public void removeEjb(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + } + + + /** + * Set the specified environment entries in the naming context. + */ + public void removeEnvironment(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + } + + + /** + * Set the specified local EJBs in the naming context. + */ + public void removeLocalEjb(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + } + + + /** + * Set the specified resources in the naming context. + */ + public void removeResource(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + ObjectName on = (ObjectName) objectNames.get(name); + if (on != null) { + Registry.getRegistry(null, null).unregisterComponent(on); + } + + } + + + /** + * Set the specified resources in the naming context. + */ + public void removeResourceEnvRef(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + } + + + /** + * Set the specified resources in the naming context. + */ + public void removeResourceLink(String name) { + + try { + envCtx.unbind(name); + } catch (NamingException e) { + logger.error(sm.getString("naming.unbindFailed", e)); + } + + } + + + /** + * Create all intermediate subcontexts. + */ + private void createSubcontexts(javax.naming.Context ctx, String name) + throws NamingException { + javax.naming.Context currentContext = ctx; + StringTokenizer tokenizer = new StringTokenizer(name, "/"); + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + if ((!token.equals("")) && (tokenizer.hasMoreTokens())) { + try { + currentContext = currentContext.createSubcontext(token); + } catch (NamingException e) { + // Silent catch. Probably an object is already bound in + // the context. + currentContext = + (javax.naming.Context) currentContext.lookup(token); + } + } + } + } + + +} diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java index 151ca9e4b..e99ccbffb 100644 --- a/java/org/apache/catalina/core/StandardContext.java +++ b/java/org/apache/catalina/core/StandardContext.java @@ -1,5581 +1,5581 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Stack; -import java.util.TreeMap; - -import javax.management.AttributeNotFoundException; -import javax.management.ListenerNotFoundException; -import javax.management.MBeanNotificationInfo; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.Notification; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationEmitter; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.FilterConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletContextAttributeListener; -import javax.servlet.ServletContextEvent; -import javax.servlet.ServletContextListener; -import javax.servlet.ServletException; -import javax.servlet.ServletRequestAttributeListener; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionListener; - -import org.apache.catalina.Container; -import org.apache.catalina.ContainerListener; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Globals; -import org.apache.catalina.Host; -import org.apache.catalina.InstanceListener; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.Manager; -import org.apache.catalina.Wrapper; -import org.apache.catalina.deploy.ApplicationParameter; -import org.apache.catalina.deploy.ErrorPage; -import org.apache.catalina.deploy.FilterDef; -import org.apache.catalina.deploy.FilterMap; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.deploy.MessageDestination; -import org.apache.catalina.deploy.MessageDestinationRef; -import org.apache.catalina.deploy.NamingResources; -import org.apache.catalina.deploy.SecurityCollection; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.loader.WebappLoader; -import org.apache.catalina.session.StandardManager; -import org.apache.catalina.startup.ContextConfig; -import org.apache.catalina.startup.TldConfig; -import org.apache.catalina.util.AnnotationProcessor; -import org.apache.catalina.util.CharsetMapper; -import org.apache.catalina.util.ExtensionValidator; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.URLEncoder; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.naming.ContextBindings; -import org.apache.naming.resources.BaseDirContext; -import org.apache.naming.resources.DirContextURLStreamHandler; -import org.apache.naming.resources.FileDirContext; -import org.apache.naming.resources.ProxyDirContext; -import org.apache.naming.resources.WARDirContext; -import org.apache.tomcat.util.modeler.Registry; - -/** - * Standard implementation of the Context interface. Each - * child container must be a Wrapper implementation to process the - * requests directed to a particular servlet. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 386331 $ $Date: 2006-03-16 15:03:12 +0100 (jeu., 16 mars 2006) $ - */ - -public class StandardContext - extends ContainerBase - implements Context, Serializable, NotificationEmitter -{ - private static transient Log log = LogFactory.getLog(StandardContext.class); - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new StandardContext component with the default basic Valve. - */ - public StandardContext() { - - super(); - pipeline.setBasic(new StandardContextValve()); - broadcaster = new NotificationBroadcasterSupport(); - - } - - - // ----------------------------------------------------- Class Variables - - - /** - * The descriptive information string for this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardContext/1.0"; - - - /** - * Array containing the safe characters set. - */ - protected static URLEncoder urlEncoder; - - - /** - * GMT timezone - all HTTP dates are on GMT - */ - static { - urlEncoder = new URLEncoder(); - urlEncoder.addSafeCharacter('~'); - urlEncoder.addSafeCharacter('-'); - urlEncoder.addSafeCharacter('_'); - urlEncoder.addSafeCharacter('.'); - urlEncoder.addSafeCharacter('*'); - urlEncoder.addSafeCharacter('/'); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The alternate deployment descriptor name. - */ - private String altDDName = null; - - - /** - * Associated host name. - */ - private String hostName; - - - /** - * The antiJARLocking flag for this Context. - */ - private boolean antiJARLocking = false; - - - /** - * The antiResourceLocking flag for this Context. - */ - private boolean antiResourceLocking = false; - - - /** - * The set of application listener class names configured for this - * application, in the order they were encountered in the web.xml file. - */ - private String applicationListeners[] = new String[0]; - - - /** - * The set of instantiated application event listener objects. - */ - private transient Object applicationEventListenersObjects[] = - new Object[0]; - - - /** - * The set of instantiated application lifecycle listener objects. - */ - private transient Object applicationLifecycleListenersObjects[] = - new Object[0]; - - - /** - * The set of application parameters defined for this application. - */ - private ApplicationParameter applicationParameters[] = - new ApplicationParameter[0]; - - - /** - * The application available flag for this Context. - */ - private boolean available = false; - - /** - * The broadcaster that sends j2ee notifications. - */ - private NotificationBroadcasterSupport broadcaster = null; - - /** - * The Locale to character set mapper for this application. - */ - private transient CharsetMapper charsetMapper = null; - - - /** - * The Java class name of the CharsetMapper class to be created. - */ - private String charsetMapperClass = - "org.apache.catalina.util.CharsetMapper"; - - - /** - * The path to a file to save this Context information. - */ - private String configFile = null; - - - /** - * The "correctly configured" flag for this Context. - */ - private boolean configured = false; - - - /** - * The security constraints for this web application. - */ - private SecurityConstraint constraints[] = new SecurityConstraint[0]; - - - /** - * The ServletContext implementation associated with this Context. - */ - protected transient ApplicationContext context = null; - - - /** - * Compiler classpath to use. - */ - private String compilerClasspath = null; - - - /** - * Should we attempt to use cookies for session id communication? - */ - private boolean cookies = true; - - - /** - * Should we allow the ServletContext.getContext() method - * to access the context of other web applications in this server? - */ - private boolean crossContext = false; - - - /** - * Encoded path. - */ - private String encodedPath = null; - - - /** - * The "follow standard delegation model" flag that will be used to - * configure our ClassLoader. - */ - private boolean delegate = false; - - - /** - * The display name of this web application. - */ - private String displayName = null; - - - /** - * Override the default context xml location. - */ - private String defaultContextXml; - - - /** - * Override the default web xml location. - */ - private String defaultWebXml; - - - /** - * The distributable flag for this web application. - */ - private boolean distributable = false; - - - /** - * The document root for this web application. - */ - private String docBase = null; - - - /** - * The exception pages for this web application, keyed by fully qualified - * class name of the Java exception. - */ - private HashMap exceptionPages = new HashMap(); - - - /** - * The set of filter configurations (and associated filter instances) we - * have initialized, keyed by filter name. - */ - private HashMap filterConfigs = new HashMap(); - - - /** - * The set of filter definitions for this application, keyed by - * filter name. - */ - private HashMap filterDefs = new HashMap(); - - - /** - * The set of filter mappings for this application, in the order - * they were defined in the deployment descriptor. - */ - private FilterMap filterMaps[] = new FilterMap[0]; - - - /** - * Ignore annotations. - */ - private boolean ignoreAnnotations = false; - - - /** - * The set of classnames of InstanceListeners that will be added - * to each newly created Wrapper by createWrapper(). - */ - private String instanceListeners[] = new String[0]; - - - /** - * The login configuration descriptor for this web application. - */ - private LoginConfig loginConfig = null; - - - /** - * The mapper associated with this context. - */ - private org.apache.tomcat.util.http.mapper.Mapper mapper = - new org.apache.tomcat.util.http.mapper.Mapper(); - - - /** - * The naming context listener for this web application. - */ - private transient NamingContextListener namingContextListener = null; - - - /** - * The naming resources for this web application. - */ - private NamingResources namingResources = null; - - - /** - * The message destinations for this web application. - */ - private HashMap messageDestinations = new HashMap(); - - - /** - * The MIME mappings for this web application, keyed by extension. - */ - private HashMap mimeMappings = new HashMap(); - - - /** - * Special case: error page for status 200. - */ - private ErrorPage okErrorPage = null; - - - /** - * The context initialization parameters for this web application, - * keyed by name. - */ - private HashMap parameters = new HashMap(); - - - /** - * The request processing pause flag (while reloading occurs) - */ - private boolean paused = false; - - - /** - * The public identifier of the DTD for the web application deployment - * descriptor version we are currently parsing. This is used to support - * relaxed validation rules when processing version 2.2 web.xml files. - */ - private String publicId = null; - - - /** - * The reloadable flag for this web application. - */ - private boolean reloadable = false; - - - /** - * Unpack WAR property. - */ - private boolean unpackWAR = true; - - - /** - * The DefaultContext override flag for this web application. - */ - private boolean override = false; - - - /** - * The original document root for this web application. - */ - private String originalDocBase = null; - - - /** - * The privileged flag for this web application. - */ - private boolean privileged = false; - - - /** - * Should the next call to addWelcomeFile() cause replacement - * of any existing welcome files? This will be set before processing the - * web application's deployment descriptor, so that application specified - * choices replace, rather than append to, those defined - * in the global descriptor. - */ - private boolean replaceWelcomeFiles = false; - - - /** - * The security role mappings for this application, keyed by role - * name (as used within the application). - */ - private HashMap roleMappings = new HashMap(); - - - /** - * The security roles for this application, keyed by role name. - */ - private String securityRoles[] = new String[0]; - - - /** - * The servlet mappings for this web application, keyed by - * matching pattern. - */ - private HashMap servletMappings = new HashMap(); - - - /** - * The session timeout (in minutes) for this web application. - */ - private int sessionTimeout = 30; - - /** - * The notification sequence number. - */ - private long sequenceNumber = 0; - - /** - * The status code error pages for this web application, keyed by - * HTTP status code (as an Integer). - */ - private HashMap statusPages = new HashMap(); - - - /** - * Set flag to true to cause the system.out and system.err to be redirected - * to the logger when executing a servlet. - */ - private boolean swallowOutput = false; - - - /** - * The JSP tag libraries for this web application, keyed by URI - */ - private HashMap taglibs = new HashMap(); - - - /** - * Amount of ms that the container will wait for servlets to unload. - */ - private long unloadDelay = 2000; - - - /** - * The watched resources for this application. - */ - private String watchedResources[] = new String[0]; - - - /** - * The welcome files for this application. - */ - private String welcomeFiles[] = new String[0]; - - - /** - * The set of classnames of LifecycleListeners that will be added - * to each newly created Wrapper by createWrapper(). - */ - private String wrapperLifecycles[] = new String[0]; - - - /** - * The set of classnames of ContainerListeners that will be added - * to each newly created Wrapper by createWrapper(). - */ - private String wrapperListeners[] = new String[0]; - - - /** - * The pathname to the work directory for this context (relative to - * the server's home if not absolute). - */ - private String workDir = null; - - - /** - * Java class name of the Wrapper class implementation we use. - */ - private String wrapperClassName = StandardWrapper.class.getName(); - private Class wrapperClass = null; - - - /** - * JNDI use flag. - */ - private boolean useNaming = true; - - - /** - * Filesystem based flag. - */ - private boolean filesystemBased = false; - - - /** - * Name of the associated naming context. - */ - private String namingContextName = null; - - - /** - * Caching allowed flag. - */ - private boolean cachingAllowed = true; - - - /** - * Case sensitivity. - */ - protected boolean caseSensitive = true; - - - /** - * Allow linking. - */ - protected boolean allowLinking = false; - - - /** - * Cache max size in KB. - */ - protected int cacheMaxSize = 10240; // 10 MB - - - /** - * Cache TTL in ms. - */ - protected int cacheTTL = 5000; - - - private boolean lazy=true; - - /** - * Non proxied resources. - */ - private transient DirContext webappResources = null; - - private long startupTime; - private long startTime; - private long tldScanTime; - - /** - * Name of the engine. If null, the domain is used. - */ - private String engineName = null; - private String j2EEApplication="none"; - private String j2EEServer="none"; - - - /** - * Attribute value used to turn on/off XML validation - */ - private boolean webXmlValidation = false; - - - /** - * Attribute value used to turn on/off XML namespace validation - */ - private boolean webXmlNamespaceAware = false; - - /** - * Attribute value used to turn on/off TLD processing - */ - private boolean processTlds = true; - - /** - * Attribute value used to turn on/off XML validation - */ - private boolean tldValidation = false; - - - /** - * Attribute value used to turn on/off TLD XML namespace validation - */ - private boolean tldNamespaceAware = false; - - - /** - * Should we save the configuration. - */ - private boolean saveConfig = true; - - - // ----------------------------------------------------- Context Properties - - - public String getEncodedPath() { - return encodedPath; - } - - - public void setName( String name ) { - super.setName( name ); - encodedPath = urlEncoder.encode(name); - } - - - /** - * Is caching allowed ? - */ - public boolean isCachingAllowed() { - return cachingAllowed; - } - - - /** - * Set caching allowed flag. - */ - public void setCachingAllowed(boolean cachingAllowed) { - this.cachingAllowed = cachingAllowed; - } - - - /** - * Set case sensitivity. - */ - public void setCaseSensitive(boolean caseSensitive) { - this.caseSensitive = caseSensitive; - } - - - /** - * Is case sensitive ? - */ - public boolean isCaseSensitive() { - return caseSensitive; - } - - - /** - * Set allow linking. - */ - public void setAllowLinking(boolean allowLinking) { - this.allowLinking = allowLinking; - } - - - /** - * Is linking allowed. - */ - public boolean isAllowLinking() { - return allowLinking; - } - - - /** - * Set cache TTL. - */ - public void setCacheTTL(int cacheTTL) { - this.cacheTTL = cacheTTL; - } - - - /** - * Get cache TTL. - */ - public int getCacheTTL() { - return cacheTTL; - } - - - /** - * Return the maximum size of the cache in KB. - */ - public int getCacheMaxSize() { - return cacheMaxSize; - } - - - /** - * Set the maximum size of the cache in KB. - */ - public void setCacheMaxSize(int cacheMaxSize) { - this.cacheMaxSize = cacheMaxSize; - } - - - /** - * Return the "follow standard delegation model" flag used to configure - * our ClassLoader. - */ - public boolean getDelegate() { - - return (this.delegate); - - } - - - /** - * Set the "follow standard delegation model" flag used to configure - * our ClassLoader. - * - * @param delegate The new flag - */ - public void setDelegate(boolean delegate) { - - boolean oldDelegate = this.delegate; - this.delegate = delegate; - support.firePropertyChange("delegate", new Boolean(oldDelegate), - new Boolean(this.delegate)); - - } - - - /** - * Returns true if the internal naming support is used. - */ - public boolean isUseNaming() { - - return (useNaming); - - } - - - /** - * Enables or disables naming. - */ - public void setUseNaming(boolean useNaming) { - this.useNaming = useNaming; - } - - - /** - * Returns true if the resources associated with this context are - * filesystem based. - */ - public boolean isFilesystemBased() { - - return (filesystemBased); - - } - - - /** - * Return the set of initialized application event listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @exception IllegalStateException if this method is called before - * this application has started, or after it has been stopped - */ - public Object[] getApplicationEventListeners() { - return (applicationEventListenersObjects); - } - - - /** - * Store the set of initialized application event listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @param listeners The set of instantiated listener objects. - */ - public void setApplicationEventListeners(Object listeners[]) { - applicationEventListenersObjects = listeners; - } - - - /** - * Return the set of initialized application lifecycle listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @exception IllegalStateException if this method is called before - * this application has started, or after it has been stopped - */ - public Object[] getApplicationLifecycleListeners() { - return (applicationLifecycleListenersObjects); - } - - - /** - * Store the set of initialized application lifecycle listener objects, - * in the order they were specified in the web application deployment - * descriptor, for this application. - * - * @param listeners The set of instantiated listener objects. - */ - public void setApplicationLifecycleListeners(Object listeners[]) { - applicationLifecycleListenersObjects = listeners; - } - - - /** - * Return the antiJARLocking flag for this Context. - */ - public boolean getAntiJARLocking() { - - return (this.antiJARLocking); - - } - - - /** - * Return the antiResourceLocking flag for this Context. - */ - public boolean getAntiResourceLocking() { - - return (this.antiResourceLocking); - - } - - - /** - * Set the antiJARLocking feature for this Context. - * - * @param antiJARLocking The new flag value - */ - public void setAntiJARLocking(boolean antiJARLocking) { - - boolean oldAntiJARLocking = this.antiJARLocking; - this.antiJARLocking = antiJARLocking; - support.firePropertyChange("antiJARLocking", - new Boolean(oldAntiJARLocking), - new Boolean(this.antiJARLocking)); - - } - - - /** - * Set the antiResourceLocking feature for this Context. - * - * @param antiResourceLocking The new flag value - */ - public void setAntiResourceLocking(boolean antiResourceLocking) { - - boolean oldAntiResourceLocking = this.antiResourceLocking; - this.antiResourceLocking = antiResourceLocking; - support.firePropertyChange("antiResourceLocking", - new Boolean(oldAntiResourceLocking), - new Boolean(this.antiResourceLocking)); - - } - - - /** - * Return the application available flag for this Context. - */ - public boolean getAvailable() { - - return (this.available); - - } - - - /** - * Set the application available flag for this Context. - * - * @param available The new application available flag - */ - public void setAvailable(boolean available) { - - boolean oldAvailable = this.available; - this.available = available; - support.firePropertyChange("available", - new Boolean(oldAvailable), - new Boolean(this.available)); - - } - - - /** - * Return the Locale to character set mapper for this Context. - */ - public CharsetMapper getCharsetMapper() { - - // Create a mapper the first time it is requested - if (this.charsetMapper == null) { - try { - Class clazz = Class.forName(charsetMapperClass); - this.charsetMapper = - (CharsetMapper) clazz.newInstance(); - } catch (Throwable t) { - this.charsetMapper = new CharsetMapper(); - } - } - - return (this.charsetMapper); - - } - - - /** - * Set the Locale to character set mapper for this Context. - * - * @param mapper The new mapper - */ - public void setCharsetMapper(CharsetMapper mapper) { - - CharsetMapper oldCharsetMapper = this.charsetMapper; - this.charsetMapper = mapper; - if( mapper != null ) - this.charsetMapperClass= mapper.getClass().getName(); - support.firePropertyChange("charsetMapper", oldCharsetMapper, - this.charsetMapper); - - } - - /** - * Return the path to a file to save this Context information. - */ - public String getConfigFile() { - - return (this.configFile); - - } - - - /** - * Set the path to a file to save this Context information. - * - * @param configFile The path to a file to save this Context information. - */ - public void setConfigFile(String configFile) { - - this.configFile = configFile; - } - - - /** - * Return the "correctly configured" flag for this Context. - */ - public boolean getConfigured() { - - return (this.configured); - - } - - - /** - * Set the "correctly configured" flag for this Context. This can be - * set to false by startup listeners that detect a fatal configuration - * error to avoid the application from being made available. - * - * @param configured The new correctly configured flag - */ - public void setConfigured(boolean configured) { - - boolean oldConfigured = this.configured; - this.configured = configured; - support.firePropertyChange("configured", - new Boolean(oldConfigured), - new Boolean(this.configured)); - - } - - - /** - * Return the "use cookies for session ids" flag. - */ - public boolean getCookies() { - - return (this.cookies); - - } - - - /** - * Set the "use cookies for session ids" flag. - * - * @param cookies The new flag - */ - public void setCookies(boolean cookies) { - - boolean oldCookies = this.cookies; - this.cookies = cookies; - support.firePropertyChange("cookies", - new Boolean(oldCookies), - new Boolean(this.cookies)); - - } - - - /** - * Return the "allow crossing servlet contexts" flag. - */ - public boolean getCrossContext() { - - return (this.crossContext); - - } - - - /** - * Set the "allow crossing servlet contexts" flag. - * - * @param crossContext The new cross contexts flag - */ - public void setCrossContext(boolean crossContext) { - - boolean oldCrossContext = this.crossContext; - this.crossContext = crossContext; - support.firePropertyChange("crossContext", - new Boolean(oldCrossContext), - new Boolean(this.crossContext)); - - } - - public String getDefaultContextXml() { - return defaultContextXml; - } - - /** - * Set the location of the default context xml that will be used. - * If not absolute, it'll be made relative to the engine's base dir - * ( which defaults to catalina.base system property ). - * - * @param defaultContextXml The default web xml - */ - public void setDefaultContextXml(String defaultContextXml) { - this.defaultContextXml = defaultContextXml; - } - - public String getDefaultWebXml() { - return defaultWebXml; - } - - /** - * Set the location of the default web xml that will be used. - * If not absolute, it'll be made relative to the engine's base dir - * ( which defaults to catalina.base system property ). - * - * @param defaultWebXml The default web xml - */ - public void setDefaultWebXml(String defaultWebXml) { - this.defaultWebXml = defaultWebXml; - } - - /** - * Gets the time (in milliseconds) it took to start this context. - * - * @return Time (in milliseconds) it took to start this context. - */ - public long getStartupTime() { - return startupTime; - } - - public void setStartupTime(long startupTime) { - this.startupTime = startupTime; - } - - public long getTldScanTime() { - return tldScanTime; - } - - public void setTldScanTime(long tldScanTime) { - this.tldScanTime = tldScanTime; - } - - /** - * Return the display name of this web application. - */ - public String getDisplayName() { - - return (this.displayName); - - } - - - /** - * Return the alternate Deployment Descriptor name. - */ - public String getAltDDName(){ - return altDDName; - } - - - /** - * Set an alternate Deployment Descriptor name. - */ - public void setAltDDName(String altDDName) { - this.altDDName = altDDName; - if (context != null) { - context.setAttribute(Globals.ALT_DD_ATTR,altDDName); - } - } - - - /** - * Return the compiler classpath. - */ - public String getCompilerClasspath(){ - return compilerClasspath; - } - - - /** - * Set the compiler classpath. - */ - public void setCompilerClasspath(String compilerClasspath) { - this.compilerClasspath = compilerClasspath; - } - - - /** - * Set the display name of this web application. - * - * @param displayName The new display name - */ - public void setDisplayName(String displayName) { - - String oldDisplayName = this.displayName; - this.displayName = displayName; - support.firePropertyChange("displayName", oldDisplayName, - this.displayName); - } - - - /** - * Return the distributable flag for this web application. - */ - public boolean getDistributable() { - - return (this.distributable); - - } - - /** - * Set the distributable flag for this web application. - * - * @param distributable The new distributable flag - */ - public void setDistributable(boolean distributable) { - boolean oldDistributable = this.distributable; - this.distributable = distributable; - support.firePropertyChange("distributable", - new Boolean(oldDistributable), - new Boolean(this.distributable)); - - // Bugzilla 32866 - if(getManager() != null) { - if(log.isDebugEnabled()) { - log.debug("Propagating distributable=" + distributable - + " to manager"); - } - getManager().setDistributable(distributable); - } - } - - - /** - * Return the document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - */ - public String getDocBase() { - - return (this.docBase); - - } - - - /** - * Set the document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - * - * @param docBase The new document root - */ - public void setDocBase(String docBase) { - - this.docBase = docBase; - - } - - // experimental - public boolean isLazy() { - return lazy; - } - - public void setLazy(boolean lazy) { - this.lazy = lazy; - } - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - public String getEngineName() { - if( engineName != null ) return engineName; - return domain; - } - - public void setEngineName(String engineName) { - this.engineName = engineName; - } - - public String getJ2EEApplication() { - return j2EEApplication; - } - - public void setJ2EEApplication(String j2EEApplication) { - this.j2EEApplication = j2EEApplication; - } - - public String getJ2EEServer() { - return j2EEServer; - } - - public void setJ2EEServer(String j2EEServer) { - this.j2EEServer = j2EEServer; - } - - - /** - * Set the Loader with which this Context is associated. - * - * @param loader The newly associated loader - */ - public synchronized void setLoader(Loader loader) { - - super.setLoader(loader); - - } - - - /** - * Return the boolean on the annotations parsing. - */ - public boolean getIgnoreAnnotations() { - return this.ignoreAnnotations; - } - - - /** - * Set the boolean on the annotations parsing for this web - * application. - * - * @param ignoreAnnotations The boolean on the annotations parsing - */ - public void setIgnoreAnnotations(boolean ignoreAnnotations) { - boolean oldIgnoreAnnotations = this.ignoreAnnotations; - this.ignoreAnnotations = ignoreAnnotations; - support.firePropertyChange("ignoreAnnotations", Boolean.valueOf(oldIgnoreAnnotations), - Boolean.valueOf(this.ignoreAnnotations)); - } - - - /** - * Return the login configuration descriptor for this web application. - */ - public LoginConfig getLoginConfig() { - - return (this.loginConfig); - - } - - - /** - * Set the login configuration descriptor for this web application. - * - * @param config The new login configuration - */ - public void setLoginConfig(LoginConfig config) { - - // Validate the incoming property value - if (config == null) - throw new IllegalArgumentException - (sm.getString("standardContext.loginConfig.required")); - String loginPage = config.getLoginPage(); - if ((loginPage != null) && !loginPage.startsWith("/")) { - if (isServlet22()) { - if(log.isDebugEnabled()) - log.debug(sm.getString("standardContext.loginConfig.loginWarning", - loginPage)); - config.setLoginPage("/" + loginPage); - } else { - throw new IllegalArgumentException - (sm.getString("standardContext.loginConfig.loginPage", - loginPage)); - } - } - String errorPage = config.getErrorPage(); - if ((errorPage != null) && !errorPage.startsWith("/")) { - if (isServlet22()) { - if(log.isDebugEnabled()) - log.debug(sm.getString("standardContext.loginConfig.errorWarning", - errorPage)); - config.setErrorPage("/" + errorPage); - } else { - throw new IllegalArgumentException - (sm.getString("standardContext.loginConfig.errorPage", - errorPage)); - } - } - - // Process the property setting change - LoginConfig oldLoginConfig = this.loginConfig; - this.loginConfig = config; - support.firePropertyChange("loginConfig", - oldLoginConfig, this.loginConfig); - - } - - - /** - * Get the mapper associated with the context. - */ - public org.apache.tomcat.util.http.mapper.Mapper getMapper() { - return (mapper); - } - - - /** - * Return the naming resources associated with this web application. - */ - public NamingResources getNamingResources() { - - if (namingResources == null) { - setNamingResources(new NamingResources()); - } - return (namingResources); - - } - - - /** - * Set the naming resources for this web application. - * - * @param namingResources The new naming resources - */ - public void setNamingResources(NamingResources namingResources) { - - // Process the property setting change - NamingResources oldNamingResources = this.namingResources; - this.namingResources = namingResources; - namingResources.setContainer(this); - support.firePropertyChange("namingResources", - oldNamingResources, this.namingResources); - - } - - - /** - * Return the context path for this Context. - */ - public String getPath() { - - return (getName()); - - } - - - /** - * Set the context path for this Context. - *

    - * IMPLEMENTATION NOTE: The context path is used as the "name" of - * a Context, because it must be unique. - * - * @param path The new context path - */ - public void setPath(String path) { - // XXX Use host in name - setName(RequestUtil.URLDecode(path)); - - } - - - /** - * Return the public identifier of the deployment descriptor DTD that is - * currently being parsed. - */ - public String getPublicId() { - - return (this.publicId); - - } - - - /** - * Set the public identifier of the deployment descriptor DTD that is - * currently being parsed. - * - * @param publicId The public identifier - */ - public void setPublicId(String publicId) { - - if (log.isDebugEnabled()) - log.debug("Setting deployment descriptor public ID to '" + - publicId + "'"); - - String oldPublicId = this.publicId; - this.publicId = publicId; - support.firePropertyChange("publicId", oldPublicId, publicId); - - } - - - /** - * Return the reloadable flag for this web application. - */ - public boolean getReloadable() { - - return (this.reloadable); - - } - - - /** - * Return the DefaultContext override flag for this web application. - */ - public boolean getOverride() { - - return (this.override); - - } - - - /** - * Return the original document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - * Is only set as deployment has change docRoot! - */ - public String getOriginalDocBase() { - - return (this.originalDocBase); - - } - - /** - * Set the original document root for this Context. This can be an absolute - * pathname, a relative pathname, or a URL. - * - * @param docBase The orginal document root - */ - public void setOriginalDocBase(String docBase) { - - this.originalDocBase = docBase; - } - - /** - * Return the privileged flag for this web application. - */ - public boolean getPrivileged() { - - return (this.privileged); - - } - - - /** - * Set the privileged flag for this web application. - * - * @param privileged The new privileged flag - */ - public void setPrivileged(boolean privileged) { - - boolean oldPrivileged = this.privileged; - this.privileged = privileged; - support.firePropertyChange("privileged", - new Boolean(oldPrivileged), - new Boolean(this.privileged)); - - } - - - /** - * Set the reloadable flag for this web application. - * - * @param reloadable The new reloadable flag - */ - public void setReloadable(boolean reloadable) { - - boolean oldReloadable = this.reloadable; - this.reloadable = reloadable; - support.firePropertyChange("reloadable", - new Boolean(oldReloadable), - new Boolean(this.reloadable)); - - } - - - /** - * Set the DefaultContext override flag for this web application. - * - * @param override The new override flag - */ - public void setOverride(boolean override) { - - boolean oldOverride = this.override; - this.override = override; - support.firePropertyChange("override", - new Boolean(oldOverride), - new Boolean(this.override)); - - } - - - /** - * Return the "replace welcome files" property. - */ - public boolean isReplaceWelcomeFiles() { - - return (this.replaceWelcomeFiles); - - } - - - /** - * Set the "replace welcome files" property. - * - * @param replaceWelcomeFiles The new property value - */ - public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) { - - boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles; - this.replaceWelcomeFiles = replaceWelcomeFiles; - support.firePropertyChange("replaceWelcomeFiles", - new Boolean(oldReplaceWelcomeFiles), - new Boolean(this.replaceWelcomeFiles)); - - } - - - /** - * Return the servlet context for which this Context is a facade. - */ - public ServletContext getServletContext() { - - if (context == null) { - context = new ApplicationContext(getBasePath(), this); - if (altDDName != null) - context.setAttribute(Globals.ALT_DD_ATTR,altDDName); - } - return (context.getFacade()); - - } - - - /** - * Return the default session timeout (in minutes) for this - * web application. - */ - public int getSessionTimeout() { - - return (this.sessionTimeout); - - } - - - /** - * Set the default session timeout (in minutes) for this - * web application. - * - * @param timeout The new default session timeout - */ - public void setSessionTimeout(int timeout) { - - int oldSessionTimeout = this.sessionTimeout; - /* - * SRV.13.4 ("Deployment Descriptor"): - * If the timeout is 0 or less, the container ensures the default - * behaviour of sessions is never to time out. - */ - this.sessionTimeout = (timeout == 0) ? -1 : timeout; - support.firePropertyChange("sessionTimeout", - new Integer(oldSessionTimeout), - new Integer(this.sessionTimeout)); - - } - - - /** - * Return the value of the swallowOutput flag. - */ - public boolean getSwallowOutput() { - - return (this.swallowOutput); - - } - - - /** - * Set the value of the swallowOutput flag. If set to true, the system.out - * and system.err will be redirected to the logger during a servlet - * execution. - * - * @param swallowOutput The new value - */ - public void setSwallowOutput(boolean swallowOutput) { - - boolean oldSwallowOutput = this.swallowOutput; - this.swallowOutput = swallowOutput; - support.firePropertyChange("swallowOutput", - new Boolean(oldSwallowOutput), - new Boolean(this.swallowOutput)); - - } - - - /** - * Return the value of the unloadDelay flag. - */ - public long getUnloadDelay() { - - return (this.unloadDelay); - - } - - - /** - * Set the value of the unloadDelay flag, which represents the amount - * of ms that the container will wait when unloading servlets. - * Setting this to a small value may cause more requests to fail - * to complete when stopping a web application. - * - * @param unloadDelay The new value - */ - public void setUnloadDelay(long unloadDelay) { - - long oldUnloadDelay = this.unloadDelay; - this.unloadDelay = unloadDelay; - support.firePropertyChange("unloadDelay", - new Long(oldUnloadDelay), - new Long(this.unloadDelay)); - - } - - - /** - * Unpack WAR flag accessor. - */ - public boolean getUnpackWAR() { - - return (unpackWAR); - - } - - - /** - * Unpack WAR flag mutator. - */ - public void setUnpackWAR(boolean unpackWAR) { - - this.unpackWAR = unpackWAR; - - } - - /** - * Return the Java class name of the Wrapper implementation used - * for servlets registered in this Context. - */ - public String getWrapperClass() { - - return (this.wrapperClassName); - - } - - - /** - * Set the Java class name of the Wrapper implementation used - * for servlets registered in this Context. - * - * @param wrapperClassName The new wrapper class name - * - * @throws IllegalArgumentException if the specified wrapper class - * cannot be found or is not a subclass of StandardWrapper - */ - public void setWrapperClass(String wrapperClassName) { - - this.wrapperClassName = wrapperClassName; - - try { - wrapperClass = Class.forName(wrapperClassName); - if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) { - throw new IllegalArgumentException( - sm.getString("standardContext.invalidWrapperClass", - wrapperClassName)); - } - } catch (ClassNotFoundException cnfe) { - throw new IllegalArgumentException(cnfe.getMessage()); - } - } - - - /** - * Set the resources DirContext object with which this Container is - * associated. - * - * @param resources The newly associated DirContext - */ - public synchronized void setResources(DirContext resources) { - - if (started) { - throw new IllegalStateException - (sm.getString("standardContext.resources.started")); - } - - DirContext oldResources = this.webappResources; - if (oldResources == resources) - return; - - if (resources instanceof BaseDirContext) { - ((BaseDirContext) resources).setCached(isCachingAllowed()); - ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); - ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); - } - if (resources instanceof FileDirContext) { - filesystemBased = true; - ((FileDirContext) resources).setCaseSensitive(isCaseSensitive()); - ((FileDirContext) resources).setAllowLinking(isAllowLinking()); - } - this.webappResources = resources; - - // The proxied resources will be refreshed on start - this.resources = null; - - support.firePropertyChange("resources", oldResources, - this.webappResources); - - } - - - // ------------------------------------------------------ Public Properties - - - /** - * Return the Locale to character set mapper class for this Context. - */ - public String getCharsetMapperClass() { - - return (this.charsetMapperClass); - - } - - - /** - * Set the Locale to character set mapper class for this Context. - * - * @param mapper The new mapper class - */ - public void setCharsetMapperClass(String mapper) { - - String oldCharsetMapperClass = this.charsetMapperClass; - this.charsetMapperClass = mapper; - support.firePropertyChange("charsetMapperClass", - oldCharsetMapperClass, - this.charsetMapperClass); - - } - - - /** Get the absolute path to the work dir. - * To avoid duplication. - * - * @return The work path - */ - public String getWorkPath() { - File workDir = new File(getWorkDir()); - if (!workDir.isAbsolute()) { - File catalinaHome = engineBase(); - String catalinaHomePath = null; - try { - catalinaHomePath = catalinaHome.getCanonicalPath(); - workDir = new File(catalinaHomePath, - getWorkDir()); - } catch (IOException e) { - log.warn("Exception obtaining work path for " + getPath()); - } - } - return workDir.getAbsolutePath(); - } - - /** - * Return the work directory for this Context. - */ - public String getWorkDir() { - - return (this.workDir); - - } - - - /** - * Set the work directory for this Context. - * - * @param workDir The new work directory - */ - public void setWorkDir(String workDir) { - - this.workDir = workDir; - - if (started) { - postWorkDirectory(); - } - } - - - /** - * Save config ? - */ - public boolean isSaveConfig() { - return saveConfig; - } - - - /** - * Set save config flag. - */ - public void setSaveConfig(boolean saveConfig) { - this.saveConfig = saveConfig; - } - - - // -------------------------------------------------------- Context Methods - - - /** - * Add a new Listener class name to the set of Listeners - * configured for this application. - * - * @param listener Java class name of a listener class - */ - public void addApplicationListener(String listener) { - - synchronized (applicationListeners) { - String results[] =new String[applicationListeners.length + 1]; - for (int i = 0; i < applicationListeners.length; i++) { - if (listener.equals(applicationListeners[i])) - return; - results[i] = applicationListeners[i]; - } - results[applicationListeners.length] = listener; - applicationListeners = results; - } - fireContainerEvent("addApplicationListener", listener); - - // FIXME - add instance if already started? - - } - - - /** - * Add a new application parameter for this application. - * - * @param parameter The new application parameter - */ - public void addApplicationParameter(ApplicationParameter parameter) { - - synchronized (applicationParameters) { - String newName = parameter.getName(); - for (int i = 0; i < applicationParameters.length; i++) { - if (newName.equals(applicationParameters[i].getName()) && - !applicationParameters[i].getOverride()) - return; - } - ApplicationParameter results[] = - new ApplicationParameter[applicationParameters.length + 1]; - System.arraycopy(applicationParameters, 0, results, 0, - applicationParameters.length); - results[applicationParameters.length] = parameter; - applicationParameters = results; - } - fireContainerEvent("addApplicationParameter", parameter); - - } - - - /** - * Add a child Container, only if the proposed child is an implementation - * of Wrapper. - * - * @param child Child container to be added - * - * @exception IllegalArgumentException if the proposed container is - * not an implementation of Wrapper - */ - public void addChild(Container child) { - - // Global JspServlet - Wrapper oldJspServlet = null; - - if (!(child instanceof Wrapper)) { - throw new IllegalArgumentException - (sm.getString("standardContext.notWrapper")); - } - - Wrapper wrapper = (Wrapper) child; - boolean isJspServlet = "jsp".equals(child.getName()); - - // Allow webapp to override JspServlet inherited from global web.xml. - if (isJspServlet) { - oldJspServlet = (Wrapper) findChild("jsp"); - if (oldJspServlet != null) { - removeChild(oldJspServlet); - } - } - - String jspFile = wrapper.getJspFile(); - if ((jspFile != null) && !jspFile.startsWith("/")) { - if (isServlet22()) { - if(log.isDebugEnabled()) - log.debug(sm.getString("standardContext.wrapper.warning", - jspFile)); - wrapper.setJspFile("/" + jspFile); - } else { - throw new IllegalArgumentException - (sm.getString("standardContext.wrapper.error", jspFile)); - } - } - - super.addChild(child); - - if (isJspServlet && oldJspServlet != null) { - /* - * The webapp-specific JspServlet inherits all the mappings - * specified in the global web.xml, and may add additional ones. - */ - String[] jspMappings = oldJspServlet.findMappings(); - for (int i=0; jspMappings!=null && inull. - * - * @param errorCode Error code to look up - */ - public ErrorPage findErrorPage(int errorCode) { - if (errorCode == 200) { - return (okErrorPage); - } else { - return ((ErrorPage) statusPages.get(new Integer(errorCode))); - } - - } - - - /** - * Return the error page entry for the specified Java exception type, - * if any; otherwise return null. - * - * @param exceptionType Exception type to look up - */ - public ErrorPage findErrorPage(String exceptionType) { - - synchronized (exceptionPages) { - return ((ErrorPage) exceptionPages.get(exceptionType)); - } - - } - - - /** - * Return the set of defined error pages for all specified error codes - * and exception types. - */ - public ErrorPage[] findErrorPages() { - - synchronized(exceptionPages) { - synchronized(statusPages) { - ErrorPage results1[] = new ErrorPage[exceptionPages.size()]; - results1 = - (ErrorPage[]) exceptionPages.values().toArray(results1); - ErrorPage results2[] = new ErrorPage[statusPages.size()]; - results2 = - (ErrorPage[]) statusPages.values().toArray(results2); - ErrorPage results[] = - new ErrorPage[results1.length + results2.length]; - for (int i = 0; i < results1.length; i++) - results[i] = results1[i]; - for (int i = results1.length; i < results.length; i++) - results[i] = results2[i - results1.length]; - return (results); - } - } - - } - - - /** - * Return the filter definition for the specified filter name, if any; - * otherwise return null. - * - * @param filterName Filter name to look up - */ - public FilterDef findFilterDef(String filterName) { - - synchronized (filterDefs) { - return ((FilterDef) filterDefs.get(filterName)); - } - - } - - - /** - * Return the set of defined filters for this Context. - */ - public FilterDef[] findFilterDefs() { - - synchronized (filterDefs) { - FilterDef results[] = new FilterDef[filterDefs.size()]; - return ((FilterDef[]) filterDefs.values().toArray(results)); - } - - } - - - /** - * Return the set of filter mappings for this Context. - */ - public FilterMap[] findFilterMaps() { - - return (filterMaps); - - } - - - /** - * Return the set of InstanceListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findInstanceListeners() { - - return (instanceListeners); - - } - - - /** - * FIXME: Fooling introspection ... - */ - public Context findMappingObject() { - return (Context) getMappingObject(); - } - - - /** - * Return the message destination with the specified name, if any; - * otherwise, return null. - * - * @param name Name of the desired message destination - */ - public MessageDestination findMessageDestination(String name) { - - synchronized (messageDestinations) { - return ((MessageDestination) messageDestinations.get(name)); - } - - } - - - /** - * Return the set of defined message destinations for this web - * application. If none have been defined, a zero-length array - * is returned. - */ - public MessageDestination[] findMessageDestinations() { - - synchronized (messageDestinations) { - MessageDestination results[] = - new MessageDestination[messageDestinations.size()]; - return ((MessageDestination[]) - messageDestinations.values().toArray(results)); - } - - } - - - /** - * Return the message destination ref with the specified name, if any; - * otherwise, return null. - * - * @param name Name of the desired message destination ref - */ - public MessageDestinationRef - findMessageDestinationRef(String name) { - - return namingResources.findMessageDestinationRef(name); - - } - - - /** - * Return the set of defined message destination refs for this web - * application. If none have been defined, a zero-length array - * is returned. - */ - public MessageDestinationRef[] - findMessageDestinationRefs() { - - return namingResources.findMessageDestinationRefs(); - - } - - - /** - * Return the MIME type to which the specified extension is mapped, - * if any; otherwise return null. - * - * @param extension Extension to map to a MIME type - */ - public String findMimeMapping(String extension) { - - return ((String) mimeMappings.get(extension)); - - } - - - /** - * Return the extensions for which MIME mappings are defined. If there - * are none, a zero-length array is returned. - */ - public String[] findMimeMappings() { - - synchronized (mimeMappings) { - String results[] = new String[mimeMappings.size()]; - return - ((String[]) mimeMappings.keySet().toArray(results)); - } - - } - - - /** - * Return the value for the specified context initialization - * parameter name, if any; otherwise return null. - * - * @param name Name of the parameter to return - */ - public String findParameter(String name) { - - synchronized (parameters) { - return ((String) parameters.get(name)); - } - - } - - - /** - * Return the names of all defined context initialization parameters - * for this Context. If no parameters are defined, a zero-length - * array is returned. - */ - public String[] findParameters() { - - synchronized (parameters) { - String results[] = new String[parameters.size()]; - return ((String[]) parameters.keySet().toArray(results)); - } - - } - - - /** - * For the given security role (as used by an application), return the - * corresponding role name (as defined by the underlying Realm) if there - * is one. Otherwise, return the specified role unchanged. - * - * @param role Security role to map - */ - public String findRoleMapping(String role) { - - String realRole = null; - synchronized (roleMappings) { - realRole = (String) roleMappings.get(role); - } - if (realRole != null) - return (realRole); - else - return (role); - - } - - - /** - * Return true if the specified security role is defined - * for this application; otherwise return false. - * - * @param role Security role to verify - */ - public boolean findSecurityRole(String role) { - - synchronized (securityRoles) { - for (int i = 0; i < securityRoles.length; i++) { - if (role.equals(securityRoles[i])) - return (true); - } - } - return (false); - - } - - - /** - * Return the security roles defined for this application. If none - * have been defined, a zero-length array is returned. - */ - public String[] findSecurityRoles() { - - return (securityRoles); - - } - - - /** - * Return the servlet name mapped by the specified pattern (if any); - * otherwise return null. - * - * @param pattern Pattern for which a mapping is requested - */ - public String findServletMapping(String pattern) { - - synchronized (servletMappings) { - return ((String) servletMappings.get(pattern)); - } - - } - - - /** - * Return the patterns of all defined servlet mappings for this - * Context. If no mappings are defined, a zero-length array is returned. - */ - public String[] findServletMappings() { - - synchronized (servletMappings) { - String results[] = new String[servletMappings.size()]; - return - ((String[]) servletMappings.keySet().toArray(results)); - } - - } - - - /** - * Return the context-relative URI of the error page for the specified - * HTTP status code, if any; otherwise return null. - * - * @param status HTTP status code to look up - */ - public String findStatusPage(int status) { - - return ((String) statusPages.get(new Integer(status))); - - } - - - /** - * Return the set of HTTP status codes for which error pages have - * been specified. If none are specified, a zero-length array - * is returned. - */ - public int[] findStatusPages() { - - synchronized (statusPages) { - int results[] = new int[statusPages.size()]; - Iterator elements = statusPages.keySet().iterator(); - int i = 0; - while (elements.hasNext()) - results[i++] = ((Integer) elements.next()).intValue(); - return (results); - } - - } - - - /** - * Return the tag library descriptor location for the specified taglib - * URI, if any; otherwise, return null. - * - * @param uri URI, relative to the web.xml file - */ - public String findTaglib(String uri) { - - synchronized (taglibs) { - return ((String) taglibs.get(uri)); - } - - } - - - /** - * Return the URIs of all tag libraries for which a tag library - * descriptor location has been specified. If none are specified, - * a zero-length array is returned. - */ - public String[] findTaglibs() { - - synchronized (taglibs) { - String results[] = new String[taglibs.size()]; - return ((String[]) taglibs.keySet().toArray(results)); - } - - } - - - /** - * Return true if the specified welcome file is defined - * for this Context; otherwise return false. - * - * @param name Welcome file to verify - */ - public boolean findWelcomeFile(String name) { - - synchronized (welcomeFiles) { - for (int i = 0; i < welcomeFiles.length; i++) { - if (name.equals(welcomeFiles[i])) - return (true); - } - } - return (false); - - } - - - /** - * Return the set of watched resources for this Context. If none are - * defined, a zero length array will be returned. - */ - public String[] findWatchedResources() { - return watchedResources; - } - - - /** - * Return the set of welcome files defined for this Context. If none are - * defined, a zero-length array is returned. - */ - public String[] findWelcomeFiles() { - - return (welcomeFiles); - - } - - - /** - * Return the set of LifecycleListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findWrapperLifecycles() { - - return (wrapperLifecycles); - - } - - - /** - * Return the set of ContainerListener classes that will be added to - * newly created Wrappers automatically. - */ - public String[] findWrapperListeners() { - - return (wrapperListeners); - - } - - - /** - * Reload this web application, if reloading is supported. - *

    - * IMPLEMENTATION NOTE: This method is designed to deal with - * reloads required by changes to classes in the underlying repositories - * of our class loader. It does not handle changes to the web application - * deployment descriptor. If that has occurred, you should stop this - * Context and create (and start) a new Context instance instead. - * - * @exception IllegalStateException if the reloadable - * property is set to false. - */ - public synchronized void reload() { - - // Validate our current component state - if (!started) - throw new IllegalStateException - (sm.getString("containerBase.notStarted", logName())); - - // Make sure reloading is enabled - // if (!reloadable) - // throw new IllegalStateException - // (sm.getString("standardContext.notReloadable")); - if(log.isInfoEnabled()) - log.info(sm.getString("standardContext.reloadingStarted")); - - // Stop accepting requests temporarily - setPaused(true); - - try { - stop(); - } catch (LifecycleException e) { - log.error(sm.getString("standardContext.stoppingContext"), e); - } - - try { - start(); - } catch (LifecycleException e) { - log.error(sm.getString("standardContext.startingContext"), e); - } - - setPaused(false); - - } - - - /** - * Remove the specified application listener class from the set of - * listeners for this application. - * - * @param listener Java class name of the listener to be removed - */ - public void removeApplicationListener(String listener) { - - synchronized (applicationListeners) { - - // Make sure this welcome file is currently present - int n = -1; - for (int i = 0; i < applicationListeners.length; i++) { - if (applicationListeners[i].equals(listener)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - String results[] = new String[applicationListeners.length - 1]; - for (int i = 0; i < applicationListeners.length; i++) { - if (i != n) - results[j++] = applicationListeners[i]; - } - applicationListeners = results; - - } - - // Inform interested listeners - fireContainerEvent("removeApplicationListener", listener); - - // FIXME - behavior if already started? - - } - - - /** - * Remove the application parameter with the specified name from - * the set for this application. - * - * @param name Name of the application parameter to remove - */ - public void removeApplicationParameter(String name) { - - synchronized (applicationParameters) { - - // Make sure this parameter is currently present - int n = -1; - for (int i = 0; i < applicationParameters.length; i++) { - if (name.equals(applicationParameters[i].getName())) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified parameter - int j = 0; - ApplicationParameter results[] = - new ApplicationParameter[applicationParameters.length - 1]; - for (int i = 0; i < applicationParameters.length; i++) { - if (i != n) - results[j++] = applicationParameters[i]; - } - applicationParameters = results; - - } - - // Inform interested listeners - fireContainerEvent("removeApplicationParameter", name); - - } - - - /** - * Add a child Container, only if the proposed child is an implementation - * of Wrapper. - * - * @param child Child container to be added - * - * @exception IllegalArgumentException if the proposed container is - * not an implementation of Wrapper - */ - public void removeChild(Container child) { - - if (!(child instanceof Wrapper)) { - throw new IllegalArgumentException - (sm.getString("standardContext.notWrapper")); - } - - super.removeChild(child); - - } - - - /** - * Remove the specified security constraint from this web application. - * - * @param constraint Constraint to be removed - */ - public void removeConstraint(SecurityConstraint constraint) { - - synchronized (constraints) { - - // Make sure this constraint is currently present - int n = -1; - for (int i = 0; i < constraints.length; i++) { - if (constraints[i].equals(constraint)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - SecurityConstraint results[] = - new SecurityConstraint[constraints.length - 1]; - for (int i = 0; i < constraints.length; i++) { - if (i != n) - results[j++] = constraints[i]; - } - constraints = results; - - } - - // Inform interested listeners - fireContainerEvent("removeConstraint", constraint); - - } - - - /** - * Remove the error page for the specified error code or - * Java language exception, if it exists; otherwise, no action is taken. - * - * @param errorPage The error page definition to be removed - */ - public void removeErrorPage(ErrorPage errorPage) { - - String exceptionType = errorPage.getExceptionType(); - if (exceptionType != null) { - synchronized (exceptionPages) { - exceptionPages.remove(exceptionType); - } - } else { - synchronized (statusPages) { - if (errorPage.getErrorCode() == 200) { - this.okErrorPage = null; - } - statusPages.remove(new Integer(errorPage.getErrorCode())); - } - } - fireContainerEvent("removeErrorPage", errorPage); - - } - - - /** - * Remove the specified filter definition from this Context, if it exists; - * otherwise, no action is taken. - * - * @param filterDef Filter definition to be removed - */ - public void removeFilterDef(FilterDef filterDef) { - - synchronized (filterDefs) { - filterDefs.remove(filterDef.getFilterName()); - } - fireContainerEvent("removeFilterDef", filterDef); - - } - - - /** - * Remove a filter mapping from this Context. - * - * @param filterMap The filter mapping to be removed - */ - public void removeFilterMap(FilterMap filterMap) { - - synchronized (filterMaps) { - - // Make sure this filter mapping is currently present - int n = -1; - for (int i = 0; i < filterMaps.length; i++) { - if (filterMaps[i] == filterMap) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified filter mapping - FilterMap results[] = new FilterMap[filterMaps.length - 1]; - System.arraycopy(filterMaps, 0, results, 0, n); - System.arraycopy(filterMaps, n + 1, results, n, - (filterMaps.length - 1) - n); - filterMaps = results; - - } - - // Inform interested listeners - fireContainerEvent("removeFilterMap", filterMap); - - } - - - /** - * Remove a class name from the set of InstanceListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of an InstanceListener class to be removed - */ - public void removeInstanceListener(String listener) { - - synchronized (instanceListeners) { - - // Make sure this welcome file is currently present - int n = -1; - for (int i = 0; i < instanceListeners.length; i++) { - if (instanceListeners[i].equals(listener)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - String results[] = new String[instanceListeners.length - 1]; - for (int i = 0; i < instanceListeners.length; i++) { - if (i != n) - results[j++] = instanceListeners[i]; - } - instanceListeners = results; - - } - - // Inform interested listeners - fireContainerEvent("removeInstanceListener", listener); - - } - - - /** - * Remove any message destination with the specified name. - * - * @param name Name of the message destination to remove - */ - public void removeMessageDestination(String name) { - - synchronized (messageDestinations) { - messageDestinations.remove(name); - } - fireContainerEvent("removeMessageDestination", name); - - } - - - /** - * Remove any message destination ref with the specified name. - * - * @param name Name of the message destination ref to remove - */ - public void removeMessageDestinationRef(String name) { - - namingResources.removeMessageDestinationRef(name); - fireContainerEvent("removeMessageDestinationRef", name); - - } - - - /** - * Remove the MIME mapping for the specified extension, if it exists; - * otherwise, no action is taken. - * - * @param extension Extension to remove the mapping for - */ - public void removeMimeMapping(String extension) { - - synchronized (mimeMappings) { - mimeMappings.remove(extension); - } - fireContainerEvent("removeMimeMapping", extension); - - } - - - /** - * Remove the context initialization parameter with the specified - * name, if it exists; otherwise, no action is taken. - * - * @param name Name of the parameter to remove - */ - public void removeParameter(String name) { - - synchronized (parameters) { - parameters.remove(name); - } - fireContainerEvent("removeParameter", name); - - } - - - /** - * Remove any security role reference for the specified name - * - * @param role Security role (as used in the application) to remove - */ - public void removeRoleMapping(String role) { - - synchronized (roleMappings) { - roleMappings.remove(role); - } - fireContainerEvent("removeRoleMapping", role); - - } - - - /** - * Remove any security role with the specified name. - * - * @param role Security role to remove - */ - public void removeSecurityRole(String role) { - - synchronized (securityRoles) { - - // Make sure this security role is currently present - int n = -1; - for (int i = 0; i < securityRoles.length; i++) { - if (role.equals(securityRoles[i])) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified security role - int j = 0; - String results[] = new String[securityRoles.length - 1]; - for (int i = 0; i < securityRoles.length; i++) { - if (i != n) - results[j++] = securityRoles[i]; - } - securityRoles = results; - - } - - // Inform interested listeners - fireContainerEvent("removeSecurityRole", role); - - } - - - /** - * Remove any servlet mapping for the specified pattern, if it exists; - * otherwise, no action is taken. - * - * @param pattern URL pattern of the mapping to remove - */ - public void removeServletMapping(String pattern) { - - String name = null; - synchronized (servletMappings) { - name = (String) servletMappings.remove(pattern); - } - Wrapper wrapper = (Wrapper) findChild(name); - if( wrapper != null ) { - wrapper.removeMapping(pattern); - } - mapper.removeWrapper(pattern); - fireContainerEvent("removeServletMapping", pattern); - - } - - - /** - * Remove the tag library location forthe specified tag library URI. - * - * @param uri URI, relative to the web.xml file - */ - public void removeTaglib(String uri) { - - synchronized (taglibs) { - taglibs.remove(uri); - } - fireContainerEvent("removeTaglib", uri); - } - - - /** - * Remove the specified watched resource name from the list associated - * with this Context. - * - * @param name Name of the watched resource to be removed - */ - public void removeWatchedResource(String name) { - - synchronized (watchedResources) { - - // Make sure this watched resource is currently present - int n = -1; - for (int i = 0; i < watchedResources.length; i++) { - if (watchedResources[i].equals(name)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified watched resource - int j = 0; - String results[] = new String[watchedResources.length - 1]; - for (int i = 0; i < watchedResources.length; i++) { - if (i != n) - results[j++] = watchedResources[i]; - } - watchedResources = results; - - } - - fireContainerEvent("removeWatchedResource", name); - - } - - - /** - * Remove the specified welcome file name from the list recognized - * by this Context. - * - * @param name Name of the welcome file to be removed - */ - public void removeWelcomeFile(String name) { - - synchronized (welcomeFiles) { - - // Make sure this welcome file is currently present - int n = -1; - for (int i = 0; i < welcomeFiles.length; i++) { - if (welcomeFiles[i].equals(name)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - String results[] = new String[welcomeFiles.length - 1]; - for (int i = 0; i < welcomeFiles.length; i++) { - if (i != n) - results[j++] = welcomeFiles[i]; - } - welcomeFiles = results; - - } - - // Inform interested listeners - postWelcomeFiles(); - fireContainerEvent("removeWelcomeFile", name); - - } - - - /** - * Remove a class name from the set of LifecycleListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of a LifecycleListener class to be removed - */ - public void removeWrapperLifecycle(String listener) { - - - synchronized (wrapperLifecycles) { - - // Make sure this welcome file is currently present - int n = -1; - for (int i = 0; i < wrapperLifecycles.length; i++) { - if (wrapperLifecycles[i].equals(listener)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - String results[] = new String[wrapperLifecycles.length - 1]; - for (int i = 0; i < wrapperLifecycles.length; i++) { - if (i != n) - results[j++] = wrapperLifecycles[i]; - } - wrapperLifecycles = results; - - } - - // Inform interested listeners - fireContainerEvent("removeWrapperLifecycle", listener); - - } - - - /** - * Remove a class name from the set of ContainerListener classes that - * will be added to newly created Wrappers. - * - * @param listener Class name of a ContainerListener class to be removed - */ - public void removeWrapperListener(String listener) { - - - synchronized (wrapperListeners) { - - // Make sure this welcome file is currently present - int n = -1; - for (int i = 0; i < wrapperListeners.length; i++) { - if (wrapperListeners[i].equals(listener)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified constraint - int j = 0; - String results[] = new String[wrapperListeners.length - 1]; - for (int i = 0; i < wrapperListeners.length; i++) { - if (i != n) - results[j++] = wrapperListeners[i]; - } - wrapperListeners = results; - - } - - // Inform interested listeners - fireContainerEvent("removeWrapperListener", listener); - - } - - - /** - * Gets the cumulative processing times of all servlets in this - * StandardContext. - * - * @return Cumulative processing times of all servlets in this - * StandardContext - */ - public long getProcessingTime() { - - long result = 0; - - Container[] children = findChildren(); - if (children != null) { - for( int i=0; i< children.length; i++ ) { - result += ((StandardWrapper)children[i]).getProcessingTime(); - } - } - - return result; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Configure and initialize the set of filters for this Context. - * Return true if all filter initialization completed - * successfully, or false otherwise. - */ - public boolean filterStart() { - - if (getLogger().isDebugEnabled()) - getLogger().debug("Starting filters"); - // Instantiate and record a FilterConfig for each defined filter - boolean ok = true; - synchronized (filterConfigs) { - filterConfigs.clear(); - Iterator names = filterDefs.keySet().iterator(); - while (names.hasNext()) { - String name = (String) names.next(); - if (getLogger().isDebugEnabled()) - getLogger().debug(" Starting filter '" + name + "'"); - ApplicationFilterConfig filterConfig = null; - try { - filterConfig = new ApplicationFilterConfig - (this, (FilterDef) filterDefs.get(name)); - filterConfigs.put(name, filterConfig); - } catch (Throwable t) { - getLogger().error - (sm.getString("standardContext.filterStart", name), t); - ok = false; - } - } - } - - return (ok); - - } - - - /** - * Finalize and release the set of filters for this Context. - * Return true if all filter finalization completed - * successfully, or false otherwise. - */ - public boolean filterStop() { - - if (getLogger().isDebugEnabled()) - getLogger().debug("Stopping filters"); - - // Release all Filter and FilterConfig instances - synchronized (filterConfigs) { - Iterator names = filterConfigs.keySet().iterator(); - while (names.hasNext()) { - String name = (String) names.next(); - if (getLogger().isDebugEnabled()) - getLogger().debug(" Stopping filter '" + name + "'"); - ApplicationFilterConfig filterConfig = - (ApplicationFilterConfig) filterConfigs.get(name); - filterConfig.release(); - } - filterConfigs.clear(); - } - return (true); - - } - - - /** - * Find and return the initialized FilterConfig for the - * specified filter name, if any; otherwise return null. - * - * @param name Name of the desired filter - */ - public FilterConfig findFilterConfig(String name) { - - return ((FilterConfig) filterConfigs.get(name)); - - } - - - /** - * Configure the set of instantiated application event listeners - * for this Context. Return true if all listeners wre - * initialized successfully, or false otherwise. - */ - public boolean listenerStart() { - - if (log.isDebugEnabled()) - log.debug("Configuring application event listeners"); - - // Instantiate the required listeners - ClassLoader loader = getLoader().getClassLoader(); - String listeners[] = findApplicationListeners(); - Object results[] = new Object[listeners.length]; - boolean ok = true; - for (int i = 0; i < results.length; i++) { - if (getLogger().isDebugEnabled()) - getLogger().debug(" Configuring event listener class '" + - listeners[i] + "'"); - try { - Class clazz = loader.loadClass(listeners[i]); - results[i] = clazz.newInstance(); - // Annotation processing - if (!getIgnoreAnnotations()) { - if (getNamingContextListener() != null) { - AnnotationProcessor.injectNamingResources - (getNamingContextListener().getEnvContext(), results[i]); - } - AnnotationProcessor.postConstruct(results[i]); - } - } catch (Throwable t) { - getLogger().error - (sm.getString("standardContext.applicationListener", - listeners[i]), t); - ok = false; - } - } - if (!ok) { - getLogger().error(sm.getString("standardContext.applicationSkipped")); - return (false); - } - - // Sort listeners in two arrays - ArrayList eventListeners = new ArrayList(); - ArrayList lifecycleListeners = new ArrayList(); - for (int i = 0; i < results.length; i++) { - if ((results[i] instanceof ServletContextAttributeListener) - || (results[i] instanceof ServletRequestAttributeListener) - || (results[i] instanceof ServletRequestListener) - || (results[i] instanceof HttpSessionAttributeListener)) { - eventListeners.add(results[i]); - } - if ((results[i] instanceof ServletContextListener) - || (results[i] instanceof HttpSessionListener)) { - lifecycleListeners.add(results[i]); - } - } - - setApplicationEventListeners(eventListeners.toArray()); - setApplicationLifecycleListeners(lifecycleListeners.toArray()); - - // Send application start events - - if (getLogger().isDebugEnabled()) - getLogger().debug("Sending application start events"); - - Object instances[] = getApplicationLifecycleListeners(); - if (instances == null) - return (ok); - ServletContextEvent event = - new ServletContextEvent(getServletContext()); - for (int i = 0; i < instances.length; i++) { - if (instances[i] == null) - continue; - if (!(instances[i] instanceof ServletContextListener)) - continue; - ServletContextListener listener = - (ServletContextListener) instances[i]; - try { - fireContainerEvent("beforeContextInitialized", listener); - listener.contextInitialized(event); - fireContainerEvent("afterContextInitialized", listener); - } catch (Throwable t) { - fireContainerEvent("afterContextInitialized", listener); - getLogger().error - (sm.getString("standardContext.listenerStart", - instances[i].getClass().getName()), t); - ok = false; - } - } - return (ok); - - } - - - /** - * Send an application stop event to all interested listeners. - * Return true if all events were sent successfully, - * or false otherwise. - */ - public boolean listenerStop() { - - if (log.isDebugEnabled()) - log.debug("Sending application stop events"); - - boolean ok = true; - Object listeners[] = getApplicationLifecycleListeners(); - if (listeners != null) { - ServletContextEvent event = - new ServletContextEvent(getServletContext()); - for (int i = 0; i < listeners.length; i++) { - int j = (listeners.length - 1) - i; - if (listeners[j] == null) - continue; - if (listeners[j] instanceof ServletContextListener) { - ServletContextListener listener = - (ServletContextListener) listeners[j]; - try { - fireContainerEvent("beforeContextDestroyed", listener); - listener.contextDestroyed(event); - fireContainerEvent("afterContextDestroyed", listener); - } catch (Throwable t) { - fireContainerEvent("afterContextDestroyed", listener); - getLogger().error - (sm.getString("standardContext.listenerStop", - listeners[j].getClass().getName()), t); - ok = false; - } - } - // Annotation processing - if (!getIgnoreAnnotations()) { - try { - AnnotationProcessor.preDestroy(listeners[j]); - } catch (Throwable t) { - getLogger().error - (sm.getString("standardContext.listenerStop", - listeners[j].getClass().getName()), t); - ok = false; - } - } - } - } - - // Annotation processing - listeners = getApplicationEventListeners(); - if (!getIgnoreAnnotations() && listeners != null) { - for (int i = 0; i < listeners.length; i++) { - int j = (listeners.length - 1) - i; - if (listeners[j] == null) - continue; - try { - AnnotationProcessor.preDestroy(listeners[j]); - } catch (Throwable t) { - getLogger().error - (sm.getString("standardContext.listenerStop", - listeners[j].getClass().getName()), t); - ok = false; - } - } - } - - setApplicationEventListeners(null); - setApplicationLifecycleListeners(null); - - return (ok); - - } - - - /** - * Allocate resources, including proxy. - * Return true if initialization was successfull, - * or false otherwise. - */ - public boolean resourcesStart() { - - boolean ok = true; - - Hashtable env = new Hashtable(); - if (getParent() != null) - env.put(ProxyDirContext.HOST, getParent().getName()); - env.put(ProxyDirContext.CONTEXT, getName()); - - try { - ProxyDirContext proxyDirContext = - new ProxyDirContext(env, webappResources); - if (webappResources instanceof FileDirContext) { - filesystemBased = true; - ((FileDirContext) webappResources).setCaseSensitive - (isCaseSensitive()); - ((FileDirContext) webappResources).setAllowLinking - (isAllowLinking()); - } - if (webappResources instanceof BaseDirContext) { - ((BaseDirContext) webappResources).setDocBase(getBasePath()); - ((BaseDirContext) webappResources).setCached - (isCachingAllowed()); - ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL()); - ((BaseDirContext) webappResources).setCacheMaxSize - (getCacheMaxSize()); - ((BaseDirContext) webappResources).allocate(); - } - // Register the cache in JMX - if (isCachingAllowed()) { - ObjectName resourcesName = - new ObjectName(this.getDomain() + ":type=Cache,host=" - + getHostname() + ",path=" - + (("".equals(getPath()))?"/":getPath())); - Registry.getRegistry(null, null).registerComponent - (proxyDirContext.getCache(), resourcesName, null); - } - this.resources = proxyDirContext; - } catch (Throwable t) { - log.error(sm.getString("standardContext.resourcesStart"), t); - ok = false; - } - - return (ok); - - } - - - /** - * Deallocate resources and destroy proxy. - */ - public boolean resourcesStop() { - - boolean ok = true; - - try { - if (resources != null) { - if (resources instanceof Lifecycle) { - ((Lifecycle) resources).stop(); - } - if (webappResources instanceof BaseDirContext) { - ((BaseDirContext) webappResources).release(); - } - // Unregister the cache in JMX - if (isCachingAllowed()) { - ObjectName resourcesName = - new ObjectName(this.getDomain() - + ":type=Cache,host=" - + getHostname() + ",path=" - + (("".equals(getPath()))?"/" - :getPath())); - Registry.getRegistry(null, null) - .unregisterComponent(resourcesName); - } - } - } catch (Throwable t) { - log.error(sm.getString("standardContext.resourcesStop"), t); - ok = false; - } - - this.resources = null; - - return (ok); - - } - - - /** - * Load and initialize all servlets marked "load on startup" in the - * web application deployment descriptor. - * - * @param children Array of wrappers for all currently defined - * servlets (including those not declared load on startup) - */ - public void loadOnStartup(Container children[]) { - - // Collect "load on startup" servlets that need to be initialized - TreeMap map = new TreeMap(); - for (int i = 0; i < children.length; i++) { - Wrapper wrapper = (Wrapper) children[i]; - int loadOnStartup = wrapper.getLoadOnStartup(); - if (loadOnStartup < 0) - continue; - if (loadOnStartup == 0) // Arbitrarily put them last - loadOnStartup = Integer.MAX_VALUE; - Integer key = new Integer(loadOnStartup); - ArrayList list = (ArrayList) map.get(key); - if (list == null) { - list = new ArrayList(); - map.put(key, list); - } - list.add(wrapper); - } - - // Load the collected "load on startup" servlets - Iterator keys = map.keySet().iterator(); - while (keys.hasNext()) { - Integer key = (Integer) keys.next(); - ArrayList list = (ArrayList) map.get(key); - Iterator wrappers = list.iterator(); - while (wrappers.hasNext()) { - Wrapper wrapper = (Wrapper) wrappers.next(); - try { - wrapper.load(); - } catch (ServletException e) { - getLogger().error(sm.getString("standardWrapper.loadException", - getName()), StandardWrapper.getRootCause(e)); - // NOTE: load errors (including a servlet that throws - // UnavailableException from tht init() method) are NOT - // fatal to application startup - } - } - } - - } - - - /** - * Start this Context component. - * - * @exception LifecycleException if a startup error occurs - */ - public synchronized void start() throws LifecycleException { - //if (lazy ) return; - if (started) { - if(log.isInfoEnabled()) - log.info(sm.getString("containerBase.alreadyStarted", logName())); - return; - } - if( !initialized ) { - try { - init(); - } catch( Exception ex ) { - throw new LifecycleException("Error initializaing ", ex); - } - } - if(log.isDebugEnabled()) - log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName())); - - // Set JMX object name for proper pipeline registration - preRegisterJMX(); - - if ((oname != null) && - (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) { - // As things depend on the JMX registration, the context - // must be reregistered again once properly initialized - Registry.getRegistry(null, null).unregisterComponent(oname); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); - - setAvailable(false); - setConfigured(false); - boolean ok = true; - - // Add missing components as necessary - if (webappResources == null) { // (1) Required by Loader - if (log.isDebugEnabled()) - log.debug("Configuring default Resources"); - try { - if ((docBase != null) && (docBase.endsWith(".war")) && (!(new File(getBasePath())).isDirectory())) - setResources(new WARDirContext()); - else - setResources(new FileDirContext()); - } catch (IllegalArgumentException e) { - log.error("Error initializing resources: " + e.getMessage()); - ok = false; - } - } - if (ok) { - if (!resourcesStart()) { - log.error( "Error in resourceStart()"); - ok = false; - } - } - - // Look for a realm - that may have been configured earlier. - // If the realm is added after context - it'll set itself. - // TODO: what is the use case for this ? - if( realm == null && mserver != null ) { - ObjectName realmName=null; - try { - realmName=new ObjectName( getEngineName() + ":type=Realm,host=" + - getHostname() + ",path=" + getPath()); - if( mserver.isRegistered(realmName ) ) { - mserver.invoke(realmName, "init", - new Object[] {}, - new String[] {} - ); - } - } catch( Throwable t ) { - if(log.isDebugEnabled()) - log.debug("No realm for this host " + realmName); - } - } - - if (getLoader() == null) { - ClassLoader parent = null; - if (getPrivileged()) { - if (log.isDebugEnabled()) - log.debug("Configuring privileged default Loader"); - parent = this.getClass().getClassLoader(); - } else { - if (log.isDebugEnabled()) - log.debug("Configuring non-privileged default Loader"); - parent = getParentClassLoader(); - } - WebappLoader webappLoader = new WebappLoader(parent); - webappLoader.setDelegate(getDelegate()); - setLoader(webappLoader); - } - - // Initialize character set mapper - getCharsetMapper(); - - // Post work directory - postWorkDirectory(); - - // Validate required extensions - boolean dependencyCheck = true; - try { - dependencyCheck = ExtensionValidator.validateApplication - (getResources(), this); - } catch (IOException ioe) { - log.error("Error in dependencyCheck", ioe); - dependencyCheck = false; - } - - if (!dependencyCheck) { - // do not make application available if depency check fails - ok = false; - } - - // Reading the "catalina.useNaming" environment variable - String useNamingProperty = System.getProperty("catalina.useNaming"); - if ((useNamingProperty != null) - && (useNamingProperty.equals("false"))) { - useNaming = false; - } - - if (ok && isUseNaming()) { - if (namingContextListener == null) { - namingContextListener = new NamingContextListener(); - namingContextListener.setName(getNamingContextName()); - addLifecycleListener(namingContextListener); - } - } - - // Standard container startup - if (log.isDebugEnabled()) - log.debug("Processing standard container startup"); - - // Acquire clustered manager - Manager contextManager = null; - if (manager == null) { - if ((getCluster() != null) && distributable) { - try { - contextManager = getCluster().createManager(getName()); - } catch (Exception ex) { - log.error("standardContext.clusterFail", ex); - ok = false; - } - } else { - contextManager = new StandardManager(); - } - } - - - // Binding thread - ClassLoader oldCCL = bindThread(); - - boolean mainOk = false; - - try { - - if (ok) { - - started = true; - - // Start our subordinate components, if any - if ((loader != null) && (loader instanceof Lifecycle)) - ((Lifecycle) loader).start(); - - // Unbinding thread - unbindThread(oldCCL); - - // Binding thread - oldCCL = bindThread(); - - // Initialize logger again. Other components might have used it too early, - // so it should be reset. - logger = null; - getLogger(); - if ((logger != null) && (logger instanceof Lifecycle)) - ((Lifecycle) logger).start(); - - if ((cluster != null) && (cluster instanceof Lifecycle)) - ((Lifecycle) cluster).start(); - if ((realm != null) && (realm instanceof Lifecycle)) - ((Lifecycle) realm).start(); - if ((resources != null) && (resources instanceof Lifecycle)) - ((Lifecycle) resources).start(); - - // Start our child containers, if any - Container children[] = findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i] instanceof Lifecycle) - ((Lifecycle) children[i]).start(); - } - - // Start the Valves in our pipeline (including the basic), - // if any - if (pipeline instanceof Lifecycle) { - ((Lifecycle) pipeline).start(); - } - - if(getProcessTlds()) { - processTlds(); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(START_EVENT, null); - - // Configure default manager if none was specified - if (contextManager != null) { - setManager(contextManager); - } - - // Start manager - if ((manager != null) && (manager instanceof Lifecycle)) { - ((Lifecycle) getManager()).start(); - } - - // Start ContainerBackgroundProcessor thread - super.threadStart(); - - mainOk = true; - - } - - } finally { - // Unbinding thread - unbindThread(oldCCL); - if (!mainOk) { - // An exception occurred - // Register with JMX anyway, to allow management - registerJMX(); - } - } - - if (!getConfigured()) { - log.error( "Error getConfigured"); - ok = false; - } - - // We put the resources into the servlet context - if (ok) - getServletContext().setAttribute - (Globals.RESOURCES_ATTR, getResources()); - - // Initialize associated mapper - mapper.setContext(getPath(), welcomeFiles, resources); - - // Binding thread - oldCCL = bindThread(); - - // Set annotation processing parameter for Jasper (unfortunately, since - // this can be configured in many places and not just in /WEB-INF/web.xml, - // there are not many solutions) - if (ignoreAnnotations) { - Wrapper jspServlet = (Wrapper) findChild(Constants.JSP_SERVLET_NAME); - jspServlet.addInitParameter("org.apache.jasper.IGNORE_ANNOTATIONS", "true"); - } - - try { - - // Create context attributes that will be required - if (ok) { - postWelcomeFiles(); - } - - if (ok) { - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); - } - - // Configure and call application event listeners and filters - if (ok) { - if (!listenerStart()) { - log.error( "Error listenerStart"); - ok = false; - } - } - if (ok) { - if (!filterStart()) { - log.error( "Error filterStart"); - ok = false; - } - } - - // Load and initialize all "load on startup" servlets - if (ok) { - loadOnStartup(findChildren()); - } - - } finally { - // Unbinding thread - unbindThread(oldCCL); - } - - // Set available status depending upon startup success - if (ok) { - if (log.isDebugEnabled()) - log.debug("Starting completed"); - setAvailable(true); - } else { - log.error(sm.getString("standardContext.startFailed", getName())); - try { - stop(); - } catch (Throwable t) { - log.error(sm.getString("standardContext.startCleanup"), t); - } - setAvailable(false); - } - - // JMX registration - registerJMX(); - - startTime=System.currentTimeMillis(); - - // Send j2ee.state.running notification - if (ok && (this.getObjectName() != null)) { - Notification notification = - new Notification("j2ee.state.running", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - // Close all JARs right away to avoid always opening a peak number - // of files on startup - if (getLoader() instanceof WebappLoader) { - ((WebappLoader) getLoader()).closeJARs(true); - } - - // Reinitializing if something went wrong - if (!ok && started) { - stop(); - } - - //cacheContext(); - } - - /** - * Processes TLDs. - * - * @throws LifecycleException If an error occurs - */ - protected void processTlds() throws LifecycleException { - TldConfig tldConfig = new TldConfig(); - tldConfig.setContext(this); - - // (1) check if the attribute has been defined - // on the context element. - tldConfig.setTldValidation(tldValidation); - tldConfig.setTldNamespaceAware(tldNamespaceAware); - - // (2) if the attribute wasn't defined on the context - // try the host. - if (!tldValidation) { - tldConfig.setTldValidation - (((StandardHost) getParent()).getXmlValidation()); - } - - if (!tldNamespaceAware) { - tldConfig.setTldNamespaceAware - (((StandardHost) getParent()).getXmlNamespaceAware()); - } - - try { - tldConfig.execute(); - } catch (Exception ex) { - log.error("Error reading tld listeners " - + ex.toString(), ex); - } - } - - private void cacheContext() { - try { - File workDir=new File( getWorkPath() ); - - File ctxSer=new File( workDir, "_tomcat_context.ser"); - FileOutputStream fos=new FileOutputStream( ctxSer ); - ObjectOutputStream oos=new ObjectOutputStream( fos ); - oos.writeObject(this); - oos.close(); - fos.close(); - } catch( Throwable t ) { - if(log.isInfoEnabled()) - log.info("Error saving context.ser ", t); - } - } - - - /** - * Stop this Context component. - * - * @exception LifecycleException if a shutdown error occurs - */ - public synchronized void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) { - if(log.isInfoEnabled()) - log.info(sm.getString("containerBase.notStarted", logName())); - return; - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); - - // Send j2ee.state.stopping notification - if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopping", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - // Mark this application as unavailable while we shut down - setAvailable(false); - - // Binding thread - ClassLoader oldCCL = bindThread(); - - try { - - // Stop our filters - filterStop(); - - // Stop our application listeners - listenerStop(); - - // Stop ContainerBackgroundProcessor thread - super.threadStop(); - - if ((manager != null) && (manager instanceof Lifecycle)) { - ((Lifecycle) manager).stop(); - } - - // Finalize our character set mapper - setCharsetMapper(null); - - // Normal container shutdown processing - if (log.isDebugEnabled()) - log.debug("Processing standard container shutdown"); - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Stop the Valves in our pipeline (including the basic), if any - if (pipeline instanceof Lifecycle) { - ((Lifecycle) pipeline).stop(); - } - - // Stop our child containers, if any - Container[] children = findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i] instanceof Lifecycle) - ((Lifecycle) children[i]).stop(); - } - - // Clear all application-originated servlet context attributes - if (context != null) - context.clearAttributes(); - - // Stop resources - resourcesStop(); - - if ((realm != null) && (realm instanceof Lifecycle)) { - ((Lifecycle) realm).stop(); - } - if ((cluster != null) && (cluster instanceof Lifecycle)) { - ((Lifecycle) cluster).stop(); - } - if ((logger != null) && (logger instanceof Lifecycle)) { - ((Lifecycle) logger).stop(); - } - if ((loader != null) && (loader instanceof Lifecycle)) { - ((Lifecycle) loader).stop(); - } - - } finally { - - // Unbinding thread - unbindThread(oldCCL); - - } - - // Send j2ee.state.stopped notification - if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopped", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - // Reset application context - context = null; - - // This object will no longer be visible or used. - try { - resetContext(); - } catch( Exception ex ) { - log.error( "Error reseting context " + this + " " + ex, ex ); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - - if (log.isDebugEnabled()) - log.debug("Stopping complete"); - - } - - /** Destroy needs to clean up the context completely. - * - * The problem is that undoing all the config in start() and restoring - * a 'fresh' state is impossible. After stop()/destroy()/init()/start() - * we should have the same state as if a fresh start was done - i.e - * read modified web.xml, etc. This can only be done by completely - * removing the context object and remapping a new one, or by cleaning - * up everything. - * - * XXX Should this be done in stop() ? - * - */ - public void destroy() throws Exception { - if( oname != null ) { - // Send j2ee.object.deleted notification - Notification notification = - new Notification("j2ee.object.deleted", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - super.destroy(); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(DESTROY_EVENT, null); - - instanceListeners = new String[0]; - - } - - private void resetContext() throws Exception, MBeanRegistrationException { - // Restore the original state ( pre reading web.xml in start ) - // If you extend this - override this method and make sure to clean up - children=new HashMap(); - startupTime = 0; - startTime = 0; - tldScanTime = 0; - - // Bugzilla 32867 - distributable = false; - - applicationListeners = new String[0]; - applicationEventListenersObjects = new Object[0]; - applicationLifecycleListenersObjects = new Object[0]; - - if(log.isDebugEnabled()) - log.debug("resetContext " + oname); - } - - /** - * Return a String representation of this component. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - if (getParent() != null) { - sb.append(getParent().toString()); - sb.append("."); - } - sb.append("StandardContext["); - sb.append(getName()); - sb.append("]"); - return (sb.toString()); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Adjust the URL pattern to begin with a leading slash, if appropriate - * (i.e. we are running a servlet 2.2 application). Otherwise, return - * the specified URL pattern unchanged. - * - * @param urlPattern The URL pattern to be adjusted (if needed) - * and returned - */ - protected String adjustURLPattern(String urlPattern) { - - if (urlPattern == null) - return (urlPattern); - if (urlPattern.startsWith("/") || urlPattern.startsWith("*.")) - return (urlPattern); - if (!isServlet22()) - return (urlPattern); - if(log.isDebugEnabled()) - log.debug(sm.getString("standardContext.urlPattern.patternWarning", - urlPattern)); - return ("/" + urlPattern); - - } - - - /** - * Are we processing a version 2.2 deployment descriptor? - */ - protected boolean isServlet22() { - - if (this.publicId == null) - return (false); - if (this.publicId.equals - (org.apache.catalina.startup.Constants.WebDtdPublicId_22)) - return (true); - else - return (false); - - } - - - /** - * Return a File object representing the base directory for the - * entire servlet container (i.e. the Engine container if present). - */ - protected File engineBase() { - String base=System.getProperty("catalina.base"); - if( base == null ) { - StandardEngine eng=(StandardEngine)this.getParent().getParent(); - base=eng.getBaseDir(); - } - return (new File(base)); - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Bind current thread, both for CL purposes and for JNDI ENC support - * during : startup, shutdown and realoading of the context. - * - * @return the previous context class loader - */ - private ClassLoader bindThread() { - - ClassLoader oldContextClassLoader = - Thread.currentThread().getContextClassLoader(); - - if (getResources() == null) - return oldContextClassLoader; - - if (getLoader().getClassLoader() != null) { - Thread.currentThread().setContextClassLoader - (getLoader().getClassLoader()); - } - - DirContextURLStreamHandler.bind(getResources()); - - if (isUseNaming()) { - try { - ContextBindings.bindThread(this, this); - } catch (NamingException e) { - // Silent catch, as this is a normal case during the early - // startup stages - } - } - - return oldContextClassLoader; - - } - - - /** - * Unbind thread. - */ - private void unbindThread(ClassLoader oldContextClassLoader) { - - Thread.currentThread().setContextClassLoader(oldContextClassLoader); - - oldContextClassLoader = null; - - if (isUseNaming()) { - ContextBindings.unbindThread(this, this); - } - - DirContextURLStreamHandler.unbind(); - - } - - - - /** - * Get base path. - */ - protected String getBasePath() { - String docBase = null; - Container container = this; - while (container != null) { - if (container instanceof Host) - break; - container = container.getParent(); - } - File file = new File(getDocBase()); - if (!file.isAbsolute()) { - if (container == null) { - docBase = (new File(engineBase(), getDocBase())).getPath(); - } else { - // Use the "appBase" property of this container - String appBase = ((Host) container).getAppBase(); - file = new File(appBase); - if (!file.isAbsolute()) - file = new File(engineBase(), appBase); - docBase = (new File(file, getDocBase())).getPath(); - } - } else { - docBase = file.getPath(); - } - return docBase; - } - - - /** - * Get app base. - */ - protected String getAppBase() { - String appBase = null; - Container container = this; - while (container != null) { - if (container instanceof Host) - break; - container = container.getParent(); - } - if (container != null) { - appBase = ((Host) container).getAppBase(); - } - return appBase; - } - - - /** - * Get config base. - */ - public File getConfigBase() { - File configBase = - new File(System.getProperty("catalina.base"), "conf"); - if (!configBase.exists()) { - return null; - } - Container container = this; - Container host = null; - Container engine = null; - while (container != null) { - if (container instanceof Host) - host = container; - if (container instanceof Engine) - engine = container; - container = container.getParent(); - } - if (engine != null) { - configBase = new File(configBase, engine.getName()); - } - if (host != null) { - configBase = new File(configBase, host.getName()); - } - if (saveConfig) { - configBase.mkdirs(); - } - return configBase; - } - - - /** - * Given a context path, get the config file name. - */ - protected String getDefaultConfigFile() { - String basename = null; - String path = getPath(); - if (path.equals("")) { - basename = "ROOT"; - } else { - basename = path.substring(1).replace('/', '#'); - } - return (basename + ".xml"); - } - - - /** - * Copy a file. - */ - private boolean copy(File src, File dest) { - FileInputStream is = null; - FileOutputStream os = null; - try { - is = new FileInputStream(src); - os = new FileOutputStream(dest); - byte[] buf = new byte[4096]; - while (true) { - int len = is.read(buf); - if (len < 0) - break; - os.write(buf, 0, len); - } - is.close(); - os.close(); - } catch (IOException e) { - return false; - } finally { - try { - if (is != null) { - is.close(); - } - } catch (Exception e) { - // Ignore - } - try { - if (os != null) { - os.close(); - } - } catch (Exception e) { - // Ignore - } - } - return true; - } - - - /** - * Get naming context full name. - */ - private String getNamingContextName() { - if (namingContextName == null) { - Container parent = getParent(); - if (parent == null) { - namingContextName = getName(); - } else { - Stack stk = new Stack(); - StringBuffer buff = new StringBuffer(); - while (parent != null) { - stk.push(parent.getName()); - parent = parent.getParent(); - } - while (!stk.empty()) { - buff.append("/" + stk.pop()); - } - buff.append(getName()); - namingContextName = buff.toString(); - } - } - return namingContextName; - } - - - /** - * Naming context listener accessor. - */ - public NamingContextListener getNamingContextListener() { - return namingContextListener; - } - - - /** - * Naming context listener setter. - */ - public void setNamingContextListener(NamingContextListener namingContextListener) { - this.namingContextListener = namingContextListener; - } - - - /** - * Return the request processing paused flag for this Context. - */ - public boolean getPaused() { - - return (this.paused); - - } - - - /** - * Post a copy of our web application resources as a servlet context - * attribute. - */ - private void postResources() { - - getServletContext().setAttribute - (Globals.RESOURCES_ATTR, getResources()); - - } - - - /** - * Post a copy of our current list of welcome files as a servlet context - * attribute, so that the default servlet can find them. - */ - private void postWelcomeFiles() { - - getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES", - welcomeFiles); - - } - - public String getHostname() { - Container parentHost = getParent(); - if (parentHost != null) { - hostName = parentHost.getName(); - } - if ((hostName == null) || (hostName.length() < 1)) - hostName = "_"; - return hostName; - } - - /** - * Set the appropriate context attribute for our work directory. - */ - private void postWorkDirectory() { - - // Acquire (or calculate) the work directory path - String workDir = getWorkDir(); - if (workDir == null) { - - // Retrieve our parent (normally a host) name - String hostName = null; - String engineName = null; - String hostWorkDir = null; - Container parentHost = getParent(); - if (parentHost != null) { - hostName = parentHost.getName(); - if (parentHost instanceof StandardHost) { - hostWorkDir = ((StandardHost)parentHost).getWorkDir(); - } - Container parentEngine = parentHost.getParent(); - if (parentEngine != null) { - engineName = parentEngine.getName(); - } - } - if ((hostName == null) || (hostName.length() < 1)) - hostName = "_"; - if ((engineName == null) || (engineName.length() < 1)) - engineName = "_"; - - String temp = getPath(); - if (temp.startsWith("/")) - temp = temp.substring(1); - temp = temp.replace('/', '_'); - temp = temp.replace('\\', '_'); - if (temp.length() < 1) - temp = "_"; - if (hostWorkDir != null ) { - workDir = hostWorkDir + File.separator + temp; - } else { - workDir = "work" + File.separator + engineName + - File.separator + hostName + File.separator + temp; - } - setWorkDir(workDir); - } - - // Create this directory if necessary - File dir = new File(workDir); - if (!dir.isAbsolute()) { - File catalinaHome = engineBase(); - String catalinaHomePath = null; - try { - catalinaHomePath = catalinaHome.getCanonicalPath(); - dir = new File(catalinaHomePath, workDir); - } catch (IOException e) { - } - } - dir.mkdirs(); - - // Set the appropriate servlet context attribute - getServletContext().setAttribute(Globals.WORK_DIR_ATTR, dir); - if (getServletContext() instanceof ApplicationContext) - ((ApplicationContext) getServletContext()).setAttributeReadOnly - (Globals.WORK_DIR_ATTR); - - } - - - /** - * Set the request processing paused flag for this Context. - * - * @param paused The new request processing paused flag - */ - private void setPaused(boolean paused) { - - this.paused = paused; - - } - - - /** - * Validate the syntax of a proposed <url-pattern> - * for conformance with specification requirements. - * - * @param urlPattern URL pattern to be validated - */ - private boolean validateURLPattern(String urlPattern) { - - if (urlPattern == null) - return (false); - if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { - getLogger().warn(sm.getString("standardContext.crlfinurl",urlPattern)); - } - if (urlPattern.startsWith("*.")) { - if (urlPattern.indexOf('/') < 0) - return (true); - else - return (false); - } - if ( (urlPattern.startsWith("/")) && - (urlPattern.indexOf("*.") < 0)) - return (true); - else - return (false); - - } - - - // ------------------------------------------------------------- Operations - - - /** - * JSR77 deploymentDescriptor attribute - * - * @return string deployment descriptor - */ - public String getDeploymentDescriptor() { - - InputStream stream = null; - ServletContext servletContext = getServletContext(); - if (servletContext != null) { - stream = servletContext.getResourceAsStream( - org.apache.catalina.startup.Constants.ApplicationWebXml); - } - if (stream == null) { - return ""; - } - BufferedReader br = new BufferedReader( - new InputStreamReader(stream)); - StringBuffer sb = new StringBuffer(); - String strRead = ""; - try { - while (strRead != null) { - sb.append(strRead); - strRead = br.readLine(); - } - } catch (IOException e) { - return ""; - } - - return sb.toString(); - - } - - - /** - * JSR77 servlets attribute - * - * @return list of all servlets ( we know about ) - */ - public String[] getServlets() { - - String[] result = null; - - Container[] children = findChildren(); - if (children != null) { - result = new String[children.length]; - for( int i=0; i< children.length; i++ ) { - result[i] = ((StandardWrapper)children[i]).getObjectName(); - } - } - - return result; - } - - - public ObjectName createObjectName(String hostDomain, ObjectName parentName) - throws MalformedObjectNameException - { - String onameStr; - StandardHost hst=(StandardHost)getParent(); - - String pathName=getName(); - String hostName=getParent().getName(); - String name= "//" + ((hostName==null)? "DEFAULT" : hostName) + - (("".equals(pathName))?"/":pathName ); - - String suffix=",J2EEApplication=" + - getJ2EEApplication() + ",J2EEServer=" + - getJ2EEServer(); - - onameStr="j2eeType=WebModule,name=" + name + suffix; - if( log.isDebugEnabled()) - log.debug("Registering " + onameStr + " for " + oname); - - // default case - no domain explictely set. - if( getDomain() == null ) domain=hst.getDomain(); - - ObjectName oname=new ObjectName(getDomain() + ":" + onameStr); - return oname; - } - - private void preRegisterJMX() { - try { - StandardHost host = (StandardHost) getParent(); - if ((oname == null) - || (oname.getKeyProperty("j2eeType") == null)) { - oname = createObjectName(host.getDomain(), host.getJmxName()); - controller = oname; - } - } catch(Exception ex) { - if(log.isInfoEnabled()) - log.info("Error registering ctx with jmx " + this + " " + - oname + " " + ex.toString(), ex ); - } - } - - private void registerJMX() { - try { - if (log.isDebugEnabled()) { - log.debug("Checking for " + oname ); - } - if(! Registry.getRegistry(null, null) - .getMBeanServer().isRegistered(oname)) { - controller = oname; - Registry.getRegistry(null, null) - .registerComponent(this, oname, null); - - // Send j2ee.object.created notification - if (this.getObjectName() != null) { - Notification notification = new Notification( - "j2ee.object.created", - this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - } - Container children[] = findChildren(); - for (int i=0; children!=null && i 0 ) { - hostName=path.substring(0, delim); - path = path.substring(delim); - if (path.equals("/")) { - this.setName(""); - } else { - this.setName(path); - } - } else { - if(log.isDebugEnabled()) - log.debug("Setting path " + path ); - this.setName( path ); - } - // XXX The service and domain should be the same. - String parentDomain=getEngineName(); - if( parentDomain == null ) parentDomain=domain; - ObjectName parentName=new ObjectName( parentDomain + ":" + - "type=Host,host=" + hostName); - return parentName; - } - - public void create() throws Exception{ - init(); - } - - /* Remove a JMX notficationListener - * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) - */ - public void removeNotificationListener(NotificationListener listener, - NotificationFilter filter, Object object) throws ListenerNotFoundException { - broadcaster.removeNotificationListener(listener,filter,object); - - } - - private MBeanNotificationInfo[] notificationInfo; - - /* Get JMX Broadcaster Info - * @TODO use StringManager for international support! - * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! - * @see javax.management.NotificationBroadcaster#getNotificationInfo() - */ - public MBeanNotificationInfo[] getNotificationInfo() { - // FIXME: i18n - if(notificationInfo == null) { - notificationInfo = new MBeanNotificationInfo[]{ - new MBeanNotificationInfo(new String[] { - "j2ee.object.created"}, - Notification.class.getName(), - "web application is created" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.starting"}, - Notification.class.getName(), - "change web application is starting" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.running"}, - Notification.class.getName(), - "web application is running" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.stopped"}, - Notification.class.getName(), - "web application start to stopped" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.object.stopped"}, - Notification.class.getName(), - "web application is stopped" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.object.deleted"}, - Notification.class.getName(), - "web application is deleted" - ) - }; - - } - - return notificationInfo; - } - - - /* Add a JMX-NotificationListener - * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) - */ - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, Object object) throws IllegalArgumentException { - broadcaster.addNotificationListener(listener,filter,object); - - } - - - /** - * Remove a JMX-NotificationListener - * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) - */ - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException { - broadcaster.removeNotificationListener(listener); - - } - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the naming resources associated with this web application. - */ - public javax.naming.directory.DirContext getStaticResources() { - - return getResources(); - - } - - - /** - * Return the naming resources associated with this web application. - * FIXME: Fooling introspection ... - */ - public javax.naming.directory.DirContext findStaticResources() { - - return getResources(); - - } - - - /** - * Return the naming resources associated with this web application. - */ - public String[] getWelcomeFiles() { - - return findWelcomeFiles(); - - } - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param webXmlValidation true to enable xml instance validation - */ - public void setXmlValidation(boolean webXmlValidation){ - - this.webXmlValidation = webXmlValidation; - - } - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getXmlValidation(){ - return webXmlValidation; - } - - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - */ - public boolean getXmlNamespaceAware(){ - return webXmlNamespaceAware; - } - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param webXmlNamespaceAware true to enable namespace awareness - */ - public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ - this.webXmlNamespaceAware= webXmlNamespaceAware; - } - - - /** - * Set the validation feature of the XML parser used when - * parsing tlds files. - * @param tldValidation true to enable xml instance validation - */ - public void setTldValidation(boolean tldValidation){ - - this.tldValidation = tldValidation; - - } - - /** - * Get the server.xml attribute's webXmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getTldValidation(){ - return tldValidation; - } - - /** - * Sets the process TLDs attribute. - * - * @param newProcessTlds The new value - */ - public void setProcessTlds(boolean newProcessTlds) { - processTlds = newProcessTlds; - } - - /** - * Returns the processTlds attribute value. - */ - public boolean getProcessTlds() { - return processTlds; - } - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - */ - public boolean getTldNamespaceAware(){ - return tldNamespaceAware; - } - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param tldNamespaceAware true to enable namespace awareness - */ - public void setTldNamespaceAware(boolean tldNamespaceAware){ - this.tldNamespaceAware= tldNamespaceAware; - } - - - /** - * Support for "stateManageable" JSR77 - */ - public boolean isStateManageable() { - return true; - } - - public void startRecursive() throws LifecycleException { - // nothing to start recursive, the servlets will be started by load-on-startup - start(); - } - - public int getState() { - if( started ) { - return 1; // RUNNING - } - if( initialized ) { - return 0; // starting ? - } - if( ! available ) { - return 4; //FAILED - } - // 2 - STOPPING - return 3; // STOPPED - } - - /** - * The J2EE Server ObjectName this module is deployed on. - */ - private String server = null; - - /** - * The Java virtual machines on which this module is running. - */ - private String[] javaVMs = null; - - public String getServer() { - return server; - } - - public String setServer(String server) { - return this.server=server; - } - - public String[] getJavaVMs() { - return javaVMs; - } - - public String[] setJavaVMs(String[] javaVMs) { - return this.javaVMs = javaVMs; - } - - /** - * Gets the time this context was started. - * - * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this - * context was started - */ - public long getStartTime() { - return startTime; - } - - public boolean isEventProvider() { - return false; - } - - public boolean isStatisticsProvider() { - return false; - } - -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Stack; +import java.util.TreeMap; + +import javax.management.AttributeNotFoundException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.servlet.FilterConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletContextAttributeListener; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.ServletException; +import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionListener; + +import org.apache.catalina.Container; +import org.apache.catalina.ContainerListener; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Globals; +import org.apache.catalina.Host; +import org.apache.catalina.InstanceListener; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.Manager; +import org.apache.catalina.Wrapper; +import org.apache.catalina.deploy.ApplicationParameter; +import org.apache.catalina.deploy.ErrorPage; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.deploy.MessageDestination; +import org.apache.catalina.deploy.MessageDestinationRef; +import org.apache.catalina.deploy.NamingResources; +import org.apache.catalina.deploy.SecurityCollection; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.session.StandardManager; +import org.apache.catalina.startup.ContextConfig; +import org.apache.catalina.startup.TldConfig; +import org.apache.catalina.util.AnnotationProcessor; +import org.apache.catalina.util.CharsetMapper; +import org.apache.catalina.util.ExtensionValidator; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.URLEncoder; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.naming.ContextBindings; +import org.apache.naming.resources.BaseDirContext; +import org.apache.naming.resources.DirContextURLStreamHandler; +import org.apache.naming.resources.FileDirContext; +import org.apache.naming.resources.ProxyDirContext; +import org.apache.naming.resources.WARDirContext; +import org.apache.tomcat.util.modeler.Registry; + +/** + * Standard implementation of the Context interface. Each + * child container must be a Wrapper implementation to process the + * requests directed to a particular servlet. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 386331 $ $Date: 2006-03-16 15:03:12 +0100 (jeu., 16 mars 2006) $ + */ + +public class StandardContext + extends ContainerBase + implements Context, Serializable, NotificationEmitter +{ + private static transient Log log = LogFactory.getLog(StandardContext.class); + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new StandardContext component with the default basic Valve. + */ + public StandardContext() { + + super(); + pipeline.setBasic(new StandardContextValve()); + broadcaster = new NotificationBroadcasterSupport(); + + } + + + // ----------------------------------------------------- Class Variables + + + /** + * The descriptive information string for this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardContext/1.0"; + + + /** + * Array containing the safe characters set. + */ + protected static URLEncoder urlEncoder; + + + /** + * GMT timezone - all HTTP dates are on GMT + */ + static { + urlEncoder = new URLEncoder(); + urlEncoder.addSafeCharacter('~'); + urlEncoder.addSafeCharacter('-'); + urlEncoder.addSafeCharacter('_'); + urlEncoder.addSafeCharacter('.'); + urlEncoder.addSafeCharacter('*'); + urlEncoder.addSafeCharacter('/'); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The alternate deployment descriptor name. + */ + private String altDDName = null; + + + /** + * Associated host name. + */ + private String hostName; + + + /** + * The antiJARLocking flag for this Context. + */ + private boolean antiJARLocking = false; + + + /** + * The antiResourceLocking flag for this Context. + */ + private boolean antiResourceLocking = false; + + + /** + * The set of application listener class names configured for this + * application, in the order they were encountered in the web.xml file. + */ + private String applicationListeners[] = new String[0]; + + + /** + * The set of instantiated application event listener objects. + */ + private transient Object applicationEventListenersObjects[] = + new Object[0]; + + + /** + * The set of instantiated application lifecycle listener objects. + */ + private transient Object applicationLifecycleListenersObjects[] = + new Object[0]; + + + /** + * The set of application parameters defined for this application. + */ + private ApplicationParameter applicationParameters[] = + new ApplicationParameter[0]; + + + /** + * The application available flag for this Context. + */ + private boolean available = false; + + /** + * The broadcaster that sends j2ee notifications. + */ + private NotificationBroadcasterSupport broadcaster = null; + + /** + * The Locale to character set mapper for this application. + */ + private transient CharsetMapper charsetMapper = null; + + + /** + * The Java class name of the CharsetMapper class to be created. + */ + private String charsetMapperClass = + "org.apache.catalina.util.CharsetMapper"; + + + /** + * The path to a file to save this Context information. + */ + private String configFile = null; + + + /** + * The "correctly configured" flag for this Context. + */ + private boolean configured = false; + + + /** + * The security constraints for this web application. + */ + private SecurityConstraint constraints[] = new SecurityConstraint[0]; + + + /** + * The ServletContext implementation associated with this Context. + */ + protected transient ApplicationContext context = null; + + + /** + * Compiler classpath to use. + */ + private String compilerClasspath = null; + + + /** + * Should we attempt to use cookies for session id communication? + */ + private boolean cookies = true; + + + /** + * Should we allow the ServletContext.getContext() method + * to access the context of other web applications in this server? + */ + private boolean crossContext = false; + + + /** + * Encoded path. + */ + private String encodedPath = null; + + + /** + * The "follow standard delegation model" flag that will be used to + * configure our ClassLoader. + */ + private boolean delegate = false; + + + /** + * The display name of this web application. + */ + private String displayName = null; + + + /** + * Override the default context xml location. + */ + private String defaultContextXml; + + + /** + * Override the default web xml location. + */ + private String defaultWebXml; + + + /** + * The distributable flag for this web application. + */ + private boolean distributable = false; + + + /** + * The document root for this web application. + */ + private String docBase = null; + + + /** + * The exception pages for this web application, keyed by fully qualified + * class name of the Java exception. + */ + private HashMap exceptionPages = new HashMap(); + + + /** + * The set of filter configurations (and associated filter instances) we + * have initialized, keyed by filter name. + */ + private HashMap filterConfigs = new HashMap(); + + + /** + * The set of filter definitions for this application, keyed by + * filter name. + */ + private HashMap filterDefs = new HashMap(); + + + /** + * The set of filter mappings for this application, in the order + * they were defined in the deployment descriptor. + */ + private FilterMap filterMaps[] = new FilterMap[0]; + + + /** + * Ignore annotations. + */ + private boolean ignoreAnnotations = false; + + + /** + * The set of classnames of InstanceListeners that will be added + * to each newly created Wrapper by createWrapper(). + */ + private String instanceListeners[] = new String[0]; + + + /** + * The login configuration descriptor for this web application. + */ + private LoginConfig loginConfig = null; + + + /** + * The mapper associated with this context. + */ + private org.apache.tomcat.util.http.mapper.Mapper mapper = + new org.apache.tomcat.util.http.mapper.Mapper(); + + + /** + * The naming context listener for this web application. + */ + private transient NamingContextListener namingContextListener = null; + + + /** + * The naming resources for this web application. + */ + private NamingResources namingResources = null; + + + /** + * The message destinations for this web application. + */ + private HashMap messageDestinations = new HashMap(); + + + /** + * The MIME mappings for this web application, keyed by extension. + */ + private HashMap mimeMappings = new HashMap(); + + + /** + * Special case: error page for status 200. + */ + private ErrorPage okErrorPage = null; + + + /** + * The context initialization parameters for this web application, + * keyed by name. + */ + private HashMap parameters = new HashMap(); + + + /** + * The request processing pause flag (while reloading occurs) + */ + private boolean paused = false; + + + /** + * The public identifier of the DTD for the web application deployment + * descriptor version we are currently parsing. This is used to support + * relaxed validation rules when processing version 2.2 web.xml files. + */ + private String publicId = null; + + + /** + * The reloadable flag for this web application. + */ + private boolean reloadable = false; + + + /** + * Unpack WAR property. + */ + private boolean unpackWAR = true; + + + /** + * The DefaultContext override flag for this web application. + */ + private boolean override = false; + + + /** + * The original document root for this web application. + */ + private String originalDocBase = null; + + + /** + * The privileged flag for this web application. + */ + private boolean privileged = false; + + + /** + * Should the next call to addWelcomeFile() cause replacement + * of any existing welcome files? This will be set before processing the + * web application's deployment descriptor, so that application specified + * choices replace, rather than append to, those defined + * in the global descriptor. + */ + private boolean replaceWelcomeFiles = false; + + + /** + * The security role mappings for this application, keyed by role + * name (as used within the application). + */ + private HashMap roleMappings = new HashMap(); + + + /** + * The security roles for this application, keyed by role name. + */ + private String securityRoles[] = new String[0]; + + + /** + * The servlet mappings for this web application, keyed by + * matching pattern. + */ + private HashMap servletMappings = new HashMap(); + + + /** + * The session timeout (in minutes) for this web application. + */ + private int sessionTimeout = 30; + + /** + * The notification sequence number. + */ + private long sequenceNumber = 0; + + /** + * The status code error pages for this web application, keyed by + * HTTP status code (as an Integer). + */ + private HashMap statusPages = new HashMap(); + + + /** + * Set flag to true to cause the system.out and system.err to be redirected + * to the logger when executing a servlet. + */ + private boolean swallowOutput = false; + + + /** + * The JSP tag libraries for this web application, keyed by URI + */ + private HashMap taglibs = new HashMap(); + + + /** + * Amount of ms that the container will wait for servlets to unload. + */ + private long unloadDelay = 2000; + + + /** + * The watched resources for this application. + */ + private String watchedResources[] = new String[0]; + + + /** + * The welcome files for this application. + */ + private String welcomeFiles[] = new String[0]; + + + /** + * The set of classnames of LifecycleListeners that will be added + * to each newly created Wrapper by createWrapper(). + */ + private String wrapperLifecycles[] = new String[0]; + + + /** + * The set of classnames of ContainerListeners that will be added + * to each newly created Wrapper by createWrapper(). + */ + private String wrapperListeners[] = new String[0]; + + + /** + * The pathname to the work directory for this context (relative to + * the server's home if not absolute). + */ + private String workDir = null; + + + /** + * Java class name of the Wrapper class implementation we use. + */ + private String wrapperClassName = StandardWrapper.class.getName(); + private Class wrapperClass = null; + + + /** + * JNDI use flag. + */ + private boolean useNaming = true; + + + /** + * Filesystem based flag. + */ + private boolean filesystemBased = false; + + + /** + * Name of the associated naming context. + */ + private String namingContextName = null; + + + /** + * Caching allowed flag. + */ + private boolean cachingAllowed = true; + + + /** + * Case sensitivity. + */ + protected boolean caseSensitive = true; + + + /** + * Allow linking. + */ + protected boolean allowLinking = false; + + + /** + * Cache max size in KB. + */ + protected int cacheMaxSize = 10240; // 10 MB + + + /** + * Cache TTL in ms. + */ + protected int cacheTTL = 5000; + + + private boolean lazy=true; + + /** + * Non proxied resources. + */ + private transient DirContext webappResources = null; + + private long startupTime; + private long startTime; + private long tldScanTime; + + /** + * Name of the engine. If null, the domain is used. + */ + private String engineName = null; + private String j2EEApplication="none"; + private String j2EEServer="none"; + + + /** + * Attribute value used to turn on/off XML validation + */ + private boolean webXmlValidation = false; + + + /** + * Attribute value used to turn on/off XML namespace validation + */ + private boolean webXmlNamespaceAware = false; + + /** + * Attribute value used to turn on/off TLD processing + */ + private boolean processTlds = true; + + /** + * Attribute value used to turn on/off XML validation + */ + private boolean tldValidation = false; + + + /** + * Attribute value used to turn on/off TLD XML namespace validation + */ + private boolean tldNamespaceAware = false; + + + /** + * Should we save the configuration. + */ + private boolean saveConfig = true; + + + // ----------------------------------------------------- Context Properties + + + public String getEncodedPath() { + return encodedPath; + } + + + public void setName( String name ) { + super.setName( name ); + encodedPath = urlEncoder.encode(name); + } + + + /** + * Is caching allowed ? + */ + public boolean isCachingAllowed() { + return cachingAllowed; + } + + + /** + * Set caching allowed flag. + */ + public void setCachingAllowed(boolean cachingAllowed) { + this.cachingAllowed = cachingAllowed; + } + + + /** + * Set case sensitivity. + */ + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + + /** + * Is case sensitive ? + */ + public boolean isCaseSensitive() { + return caseSensitive; + } + + + /** + * Set allow linking. + */ + public void setAllowLinking(boolean allowLinking) { + this.allowLinking = allowLinking; + } + + + /** + * Is linking allowed. + */ + public boolean isAllowLinking() { + return allowLinking; + } + + + /** + * Set cache TTL. + */ + public void setCacheTTL(int cacheTTL) { + this.cacheTTL = cacheTTL; + } + + + /** + * Get cache TTL. + */ + public int getCacheTTL() { + return cacheTTL; + } + + + /** + * Return the maximum size of the cache in KB. + */ + public int getCacheMaxSize() { + return cacheMaxSize; + } + + + /** + * Set the maximum size of the cache in KB. + */ + public void setCacheMaxSize(int cacheMaxSize) { + this.cacheMaxSize = cacheMaxSize; + } + + + /** + * Return the "follow standard delegation model" flag used to configure + * our ClassLoader. + */ + public boolean getDelegate() { + + return (this.delegate); + + } + + + /** + * Set the "follow standard delegation model" flag used to configure + * our ClassLoader. + * + * @param delegate The new flag + */ + public void setDelegate(boolean delegate) { + + boolean oldDelegate = this.delegate; + this.delegate = delegate; + support.firePropertyChange("delegate", new Boolean(oldDelegate), + new Boolean(this.delegate)); + + } + + + /** + * Returns true if the internal naming support is used. + */ + public boolean isUseNaming() { + + return (useNaming); + + } + + + /** + * Enables or disables naming. + */ + public void setUseNaming(boolean useNaming) { + this.useNaming = useNaming; + } + + + /** + * Returns true if the resources associated with this context are + * filesystem based. + */ + public boolean isFilesystemBased() { + + return (filesystemBased); + + } + + + /** + * Return the set of initialized application event listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @exception IllegalStateException if this method is called before + * this application has started, or after it has been stopped + */ + public Object[] getApplicationEventListeners() { + return (applicationEventListenersObjects); + } + + + /** + * Store the set of initialized application event listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @param listeners The set of instantiated listener objects. + */ + public void setApplicationEventListeners(Object listeners[]) { + applicationEventListenersObjects = listeners; + } + + + /** + * Return the set of initialized application lifecycle listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @exception IllegalStateException if this method is called before + * this application has started, or after it has been stopped + */ + public Object[] getApplicationLifecycleListeners() { + return (applicationLifecycleListenersObjects); + } + + + /** + * Store the set of initialized application lifecycle listener objects, + * in the order they were specified in the web application deployment + * descriptor, for this application. + * + * @param listeners The set of instantiated listener objects. + */ + public void setApplicationLifecycleListeners(Object listeners[]) { + applicationLifecycleListenersObjects = listeners; + } + + + /** + * Return the antiJARLocking flag for this Context. + */ + public boolean getAntiJARLocking() { + + return (this.antiJARLocking); + + } + + + /** + * Return the antiResourceLocking flag for this Context. + */ + public boolean getAntiResourceLocking() { + + return (this.antiResourceLocking); + + } + + + /** + * Set the antiJARLocking feature for this Context. + * + * @param antiJARLocking The new flag value + */ + public void setAntiJARLocking(boolean antiJARLocking) { + + boolean oldAntiJARLocking = this.antiJARLocking; + this.antiJARLocking = antiJARLocking; + support.firePropertyChange("antiJARLocking", + new Boolean(oldAntiJARLocking), + new Boolean(this.antiJARLocking)); + + } + + + /** + * Set the antiResourceLocking feature for this Context. + * + * @param antiResourceLocking The new flag value + */ + public void setAntiResourceLocking(boolean antiResourceLocking) { + + boolean oldAntiResourceLocking = this.antiResourceLocking; + this.antiResourceLocking = antiResourceLocking; + support.firePropertyChange("antiResourceLocking", + new Boolean(oldAntiResourceLocking), + new Boolean(this.antiResourceLocking)); + + } + + + /** + * Return the application available flag for this Context. + */ + public boolean getAvailable() { + + return (this.available); + + } + + + /** + * Set the application available flag for this Context. + * + * @param available The new application available flag + */ + public void setAvailable(boolean available) { + + boolean oldAvailable = this.available; + this.available = available; + support.firePropertyChange("available", + new Boolean(oldAvailable), + new Boolean(this.available)); + + } + + + /** + * Return the Locale to character set mapper for this Context. + */ + public CharsetMapper getCharsetMapper() { + + // Create a mapper the first time it is requested + if (this.charsetMapper == null) { + try { + Class clazz = Class.forName(charsetMapperClass); + this.charsetMapper = + (CharsetMapper) clazz.newInstance(); + } catch (Throwable t) { + this.charsetMapper = new CharsetMapper(); + } + } + + return (this.charsetMapper); + + } + + + /** + * Set the Locale to character set mapper for this Context. + * + * @param mapper The new mapper + */ + public void setCharsetMapper(CharsetMapper mapper) { + + CharsetMapper oldCharsetMapper = this.charsetMapper; + this.charsetMapper = mapper; + if( mapper != null ) + this.charsetMapperClass= mapper.getClass().getName(); + support.firePropertyChange("charsetMapper", oldCharsetMapper, + this.charsetMapper); + + } + + /** + * Return the path to a file to save this Context information. + */ + public String getConfigFile() { + + return (this.configFile); + + } + + + /** + * Set the path to a file to save this Context information. + * + * @param configFile The path to a file to save this Context information. + */ + public void setConfigFile(String configFile) { + + this.configFile = configFile; + } + + + /** + * Return the "correctly configured" flag for this Context. + */ + public boolean getConfigured() { + + return (this.configured); + + } + + + /** + * Set the "correctly configured" flag for this Context. This can be + * set to false by startup listeners that detect a fatal configuration + * error to avoid the application from being made available. + * + * @param configured The new correctly configured flag + */ + public void setConfigured(boolean configured) { + + boolean oldConfigured = this.configured; + this.configured = configured; + support.firePropertyChange("configured", + new Boolean(oldConfigured), + new Boolean(this.configured)); + + } + + + /** + * Return the "use cookies for session ids" flag. + */ + public boolean getCookies() { + + return (this.cookies); + + } + + + /** + * Set the "use cookies for session ids" flag. + * + * @param cookies The new flag + */ + public void setCookies(boolean cookies) { + + boolean oldCookies = this.cookies; + this.cookies = cookies; + support.firePropertyChange("cookies", + new Boolean(oldCookies), + new Boolean(this.cookies)); + + } + + + /** + * Return the "allow crossing servlet contexts" flag. + */ + public boolean getCrossContext() { + + return (this.crossContext); + + } + + + /** + * Set the "allow crossing servlet contexts" flag. + * + * @param crossContext The new cross contexts flag + */ + public void setCrossContext(boolean crossContext) { + + boolean oldCrossContext = this.crossContext; + this.crossContext = crossContext; + support.firePropertyChange("crossContext", + new Boolean(oldCrossContext), + new Boolean(this.crossContext)); + + } + + public String getDefaultContextXml() { + return defaultContextXml; + } + + /** + * Set the location of the default context xml that will be used. + * If not absolute, it'll be made relative to the engine's base dir + * ( which defaults to catalina.base system property ). + * + * @param defaultContextXml The default web xml + */ + public void setDefaultContextXml(String defaultContextXml) { + this.defaultContextXml = defaultContextXml; + } + + public String getDefaultWebXml() { + return defaultWebXml; + } + + /** + * Set the location of the default web xml that will be used. + * If not absolute, it'll be made relative to the engine's base dir + * ( which defaults to catalina.base system property ). + * + * @param defaultWebXml The default web xml + */ + public void setDefaultWebXml(String defaultWebXml) { + this.defaultWebXml = defaultWebXml; + } + + /** + * Gets the time (in milliseconds) it took to start this context. + * + * @return Time (in milliseconds) it took to start this context. + */ + public long getStartupTime() { + return startupTime; + } + + public void setStartupTime(long startupTime) { + this.startupTime = startupTime; + } + + public long getTldScanTime() { + return tldScanTime; + } + + public void setTldScanTime(long tldScanTime) { + this.tldScanTime = tldScanTime; + } + + /** + * Return the display name of this web application. + */ + public String getDisplayName() { + + return (this.displayName); + + } + + + /** + * Return the alternate Deployment Descriptor name. + */ + public String getAltDDName(){ + return altDDName; + } + + + /** + * Set an alternate Deployment Descriptor name. + */ + public void setAltDDName(String altDDName) { + this.altDDName = altDDName; + if (context != null) { + context.setAttribute(Globals.ALT_DD_ATTR,altDDName); + } + } + + + /** + * Return the compiler classpath. + */ + public String getCompilerClasspath(){ + return compilerClasspath; + } + + + /** + * Set the compiler classpath. + */ + public void setCompilerClasspath(String compilerClasspath) { + this.compilerClasspath = compilerClasspath; + } + + + /** + * Set the display name of this web application. + * + * @param displayName The new display name + */ + public void setDisplayName(String displayName) { + + String oldDisplayName = this.displayName; + this.displayName = displayName; + support.firePropertyChange("displayName", oldDisplayName, + this.displayName); + } + + + /** + * Return the distributable flag for this web application. + */ + public boolean getDistributable() { + + return (this.distributable); + + } + + /** + * Set the distributable flag for this web application. + * + * @param distributable The new distributable flag + */ + public void setDistributable(boolean distributable) { + boolean oldDistributable = this.distributable; + this.distributable = distributable; + support.firePropertyChange("distributable", + new Boolean(oldDistributable), + new Boolean(this.distributable)); + + // Bugzilla 32866 + if(getManager() != null) { + if(log.isDebugEnabled()) { + log.debug("Propagating distributable=" + distributable + + " to manager"); + } + getManager().setDistributable(distributable); + } + } + + + /** + * Return the document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + */ + public String getDocBase() { + + return (this.docBase); + + } + + + /** + * Set the document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + * + * @param docBase The new document root + */ + public void setDocBase(String docBase) { + + this.docBase = docBase; + + } + + // experimental + public boolean isLazy() { + return lazy; + } + + public void setLazy(boolean lazy) { + this.lazy = lazy; + } + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + public String getEngineName() { + if( engineName != null ) return engineName; + return domain; + } + + public void setEngineName(String engineName) { + this.engineName = engineName; + } + + public String getJ2EEApplication() { + return j2EEApplication; + } + + public void setJ2EEApplication(String j2EEApplication) { + this.j2EEApplication = j2EEApplication; + } + + public String getJ2EEServer() { + return j2EEServer; + } + + public void setJ2EEServer(String j2EEServer) { + this.j2EEServer = j2EEServer; + } + + + /** + * Set the Loader with which this Context is associated. + * + * @param loader The newly associated loader + */ + public synchronized void setLoader(Loader loader) { + + super.setLoader(loader); + + } + + + /** + * Return the boolean on the annotations parsing. + */ + public boolean getIgnoreAnnotations() { + return this.ignoreAnnotations; + } + + + /** + * Set the boolean on the annotations parsing for this web + * application. + * + * @param ignoreAnnotations The boolean on the annotations parsing + */ + public void setIgnoreAnnotations(boolean ignoreAnnotations) { + boolean oldIgnoreAnnotations = this.ignoreAnnotations; + this.ignoreAnnotations = ignoreAnnotations; + support.firePropertyChange("ignoreAnnotations", Boolean.valueOf(oldIgnoreAnnotations), + Boolean.valueOf(this.ignoreAnnotations)); + } + + + /** + * Return the login configuration descriptor for this web application. + */ + public LoginConfig getLoginConfig() { + + return (this.loginConfig); + + } + + + /** + * Set the login configuration descriptor for this web application. + * + * @param config The new login configuration + */ + public void setLoginConfig(LoginConfig config) { + + // Validate the incoming property value + if (config == null) + throw new IllegalArgumentException + (sm.getString("standardContext.loginConfig.required")); + String loginPage = config.getLoginPage(); + if ((loginPage != null) && !loginPage.startsWith("/")) { + if (isServlet22()) { + if(log.isDebugEnabled()) + log.debug(sm.getString("standardContext.loginConfig.loginWarning", + loginPage)); + config.setLoginPage("/" + loginPage); + } else { + throw new IllegalArgumentException + (sm.getString("standardContext.loginConfig.loginPage", + loginPage)); + } + } + String errorPage = config.getErrorPage(); + if ((errorPage != null) && !errorPage.startsWith("/")) { + if (isServlet22()) { + if(log.isDebugEnabled()) + log.debug(sm.getString("standardContext.loginConfig.errorWarning", + errorPage)); + config.setErrorPage("/" + errorPage); + } else { + throw new IllegalArgumentException + (sm.getString("standardContext.loginConfig.errorPage", + errorPage)); + } + } + + // Process the property setting change + LoginConfig oldLoginConfig = this.loginConfig; + this.loginConfig = config; + support.firePropertyChange("loginConfig", + oldLoginConfig, this.loginConfig); + + } + + + /** + * Get the mapper associated with the context. + */ + public org.apache.tomcat.util.http.mapper.Mapper getMapper() { + return (mapper); + } + + + /** + * Return the naming resources associated with this web application. + */ + public NamingResources getNamingResources() { + + if (namingResources == null) { + setNamingResources(new NamingResources()); + } + return (namingResources); + + } + + + /** + * Set the naming resources for this web application. + * + * @param namingResources The new naming resources + */ + public void setNamingResources(NamingResources namingResources) { + + // Process the property setting change + NamingResources oldNamingResources = this.namingResources; + this.namingResources = namingResources; + namingResources.setContainer(this); + support.firePropertyChange("namingResources", + oldNamingResources, this.namingResources); + + } + + + /** + * Return the context path for this Context. + */ + public String getPath() { + + return (getName()); + + } + + + /** + * Set the context path for this Context. + *

    + * IMPLEMENTATION NOTE: The context path is used as the "name" of + * a Context, because it must be unique. + * + * @param path The new context path + */ + public void setPath(String path) { + // XXX Use host in name + setName(RequestUtil.URLDecode(path)); + + } + + + /** + * Return the public identifier of the deployment descriptor DTD that is + * currently being parsed. + */ + public String getPublicId() { + + return (this.publicId); + + } + + + /** + * Set the public identifier of the deployment descriptor DTD that is + * currently being parsed. + * + * @param publicId The public identifier + */ + public void setPublicId(String publicId) { + + if (log.isDebugEnabled()) + log.debug("Setting deployment descriptor public ID to '" + + publicId + "'"); + + String oldPublicId = this.publicId; + this.publicId = publicId; + support.firePropertyChange("publicId", oldPublicId, publicId); + + } + + + /** + * Return the reloadable flag for this web application. + */ + public boolean getReloadable() { + + return (this.reloadable); + + } + + + /** + * Return the DefaultContext override flag for this web application. + */ + public boolean getOverride() { + + return (this.override); + + } + + + /** + * Return the original document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + * Is only set as deployment has change docRoot! + */ + public String getOriginalDocBase() { + + return (this.originalDocBase); + + } + + /** + * Set the original document root for this Context. This can be an absolute + * pathname, a relative pathname, or a URL. + * + * @param docBase The orginal document root + */ + public void setOriginalDocBase(String docBase) { + + this.originalDocBase = docBase; + } + + /** + * Return the privileged flag for this web application. + */ + public boolean getPrivileged() { + + return (this.privileged); + + } + + + /** + * Set the privileged flag for this web application. + * + * @param privileged The new privileged flag + */ + public void setPrivileged(boolean privileged) { + + boolean oldPrivileged = this.privileged; + this.privileged = privileged; + support.firePropertyChange("privileged", + new Boolean(oldPrivileged), + new Boolean(this.privileged)); + + } + + + /** + * Set the reloadable flag for this web application. + * + * @param reloadable The new reloadable flag + */ + public void setReloadable(boolean reloadable) { + + boolean oldReloadable = this.reloadable; + this.reloadable = reloadable; + support.firePropertyChange("reloadable", + new Boolean(oldReloadable), + new Boolean(this.reloadable)); + + } + + + /** + * Set the DefaultContext override flag for this web application. + * + * @param override The new override flag + */ + public void setOverride(boolean override) { + + boolean oldOverride = this.override; + this.override = override; + support.firePropertyChange("override", + new Boolean(oldOverride), + new Boolean(this.override)); + + } + + + /** + * Return the "replace welcome files" property. + */ + public boolean isReplaceWelcomeFiles() { + + return (this.replaceWelcomeFiles); + + } + + + /** + * Set the "replace welcome files" property. + * + * @param replaceWelcomeFiles The new property value + */ + public void setReplaceWelcomeFiles(boolean replaceWelcomeFiles) { + + boolean oldReplaceWelcomeFiles = this.replaceWelcomeFiles; + this.replaceWelcomeFiles = replaceWelcomeFiles; + support.firePropertyChange("replaceWelcomeFiles", + new Boolean(oldReplaceWelcomeFiles), + new Boolean(this.replaceWelcomeFiles)); + + } + + + /** + * Return the servlet context for which this Context is a facade. + */ + public ServletContext getServletContext() { + + if (context == null) { + context = new ApplicationContext(getBasePath(), this); + if (altDDName != null) + context.setAttribute(Globals.ALT_DD_ATTR,altDDName); + } + return (context.getFacade()); + + } + + + /** + * Return the default session timeout (in minutes) for this + * web application. + */ + public int getSessionTimeout() { + + return (this.sessionTimeout); + + } + + + /** + * Set the default session timeout (in minutes) for this + * web application. + * + * @param timeout The new default session timeout + */ + public void setSessionTimeout(int timeout) { + + int oldSessionTimeout = this.sessionTimeout; + /* + * SRV.13.4 ("Deployment Descriptor"): + * If the timeout is 0 or less, the container ensures the default + * behaviour of sessions is never to time out. + */ + this.sessionTimeout = (timeout == 0) ? -1 : timeout; + support.firePropertyChange("sessionTimeout", + new Integer(oldSessionTimeout), + new Integer(this.sessionTimeout)); + + } + + + /** + * Return the value of the swallowOutput flag. + */ + public boolean getSwallowOutput() { + + return (this.swallowOutput); + + } + + + /** + * Set the value of the swallowOutput flag. If set to true, the system.out + * and system.err will be redirected to the logger during a servlet + * execution. + * + * @param swallowOutput The new value + */ + public void setSwallowOutput(boolean swallowOutput) { + + boolean oldSwallowOutput = this.swallowOutput; + this.swallowOutput = swallowOutput; + support.firePropertyChange("swallowOutput", + new Boolean(oldSwallowOutput), + new Boolean(this.swallowOutput)); + + } + + + /** + * Return the value of the unloadDelay flag. + */ + public long getUnloadDelay() { + + return (this.unloadDelay); + + } + + + /** + * Set the value of the unloadDelay flag, which represents the amount + * of ms that the container will wait when unloading servlets. + * Setting this to a small value may cause more requests to fail + * to complete when stopping a web application. + * + * @param unloadDelay The new value + */ + public void setUnloadDelay(long unloadDelay) { + + long oldUnloadDelay = this.unloadDelay; + this.unloadDelay = unloadDelay; + support.firePropertyChange("unloadDelay", + new Long(oldUnloadDelay), + new Long(this.unloadDelay)); + + } + + + /** + * Unpack WAR flag accessor. + */ + public boolean getUnpackWAR() { + + return (unpackWAR); + + } + + + /** + * Unpack WAR flag mutator. + */ + public void setUnpackWAR(boolean unpackWAR) { + + this.unpackWAR = unpackWAR; + + } + + /** + * Return the Java class name of the Wrapper implementation used + * for servlets registered in this Context. + */ + public String getWrapperClass() { + + return (this.wrapperClassName); + + } + + + /** + * Set the Java class name of the Wrapper implementation used + * for servlets registered in this Context. + * + * @param wrapperClassName The new wrapper class name + * + * @throws IllegalArgumentException if the specified wrapper class + * cannot be found or is not a subclass of StandardWrapper + */ + public void setWrapperClass(String wrapperClassName) { + + this.wrapperClassName = wrapperClassName; + + try { + wrapperClass = Class.forName(wrapperClassName); + if (!StandardWrapper.class.isAssignableFrom(wrapperClass)) { + throw new IllegalArgumentException( + sm.getString("standardContext.invalidWrapperClass", + wrapperClassName)); + } + } catch (ClassNotFoundException cnfe) { + throw new IllegalArgumentException(cnfe.getMessage()); + } + } + + + /** + * Set the resources DirContext object with which this Container is + * associated. + * + * @param resources The newly associated DirContext + */ + public synchronized void setResources(DirContext resources) { + + if (started) { + throw new IllegalStateException + (sm.getString("standardContext.resources.started")); + } + + DirContext oldResources = this.webappResources; + if (oldResources == resources) + return; + + if (resources instanceof BaseDirContext) { + ((BaseDirContext) resources).setCached(isCachingAllowed()); + ((BaseDirContext) resources).setCacheTTL(getCacheTTL()); + ((BaseDirContext) resources).setCacheMaxSize(getCacheMaxSize()); + } + if (resources instanceof FileDirContext) { + filesystemBased = true; + ((FileDirContext) resources).setCaseSensitive(isCaseSensitive()); + ((FileDirContext) resources).setAllowLinking(isAllowLinking()); + } + this.webappResources = resources; + + // The proxied resources will be refreshed on start + this.resources = null; + + support.firePropertyChange("resources", oldResources, + this.webappResources); + + } + + + // ------------------------------------------------------ Public Properties + + + /** + * Return the Locale to character set mapper class for this Context. + */ + public String getCharsetMapperClass() { + + return (this.charsetMapperClass); + + } + + + /** + * Set the Locale to character set mapper class for this Context. + * + * @param mapper The new mapper class + */ + public void setCharsetMapperClass(String mapper) { + + String oldCharsetMapperClass = this.charsetMapperClass; + this.charsetMapperClass = mapper; + support.firePropertyChange("charsetMapperClass", + oldCharsetMapperClass, + this.charsetMapperClass); + + } + + + /** Get the absolute path to the work dir. + * To avoid duplication. + * + * @return The work path + */ + public String getWorkPath() { + File workDir = new File(getWorkDir()); + if (!workDir.isAbsolute()) { + File catalinaHome = engineBase(); + String catalinaHomePath = null; + try { + catalinaHomePath = catalinaHome.getCanonicalPath(); + workDir = new File(catalinaHomePath, + getWorkDir()); + } catch (IOException e) { + log.warn("Exception obtaining work path for " + getPath()); + } + } + return workDir.getAbsolutePath(); + } + + /** + * Return the work directory for this Context. + */ + public String getWorkDir() { + + return (this.workDir); + + } + + + /** + * Set the work directory for this Context. + * + * @param workDir The new work directory + */ + public void setWorkDir(String workDir) { + + this.workDir = workDir; + + if (started) { + postWorkDirectory(); + } + } + + + /** + * Save config ? + */ + public boolean isSaveConfig() { + return saveConfig; + } + + + /** + * Set save config flag. + */ + public void setSaveConfig(boolean saveConfig) { + this.saveConfig = saveConfig; + } + + + // -------------------------------------------------------- Context Methods + + + /** + * Add a new Listener class name to the set of Listeners + * configured for this application. + * + * @param listener Java class name of a listener class + */ + public void addApplicationListener(String listener) { + + synchronized (applicationListeners) { + String results[] =new String[applicationListeners.length + 1]; + for (int i = 0; i < applicationListeners.length; i++) { + if (listener.equals(applicationListeners[i])) + return; + results[i] = applicationListeners[i]; + } + results[applicationListeners.length] = listener; + applicationListeners = results; + } + fireContainerEvent("addApplicationListener", listener); + + // FIXME - add instance if already started? + + } + + + /** + * Add a new application parameter for this application. + * + * @param parameter The new application parameter + */ + public void addApplicationParameter(ApplicationParameter parameter) { + + synchronized (applicationParameters) { + String newName = parameter.getName(); + for (int i = 0; i < applicationParameters.length; i++) { + if (newName.equals(applicationParameters[i].getName()) && + !applicationParameters[i].getOverride()) + return; + } + ApplicationParameter results[] = + new ApplicationParameter[applicationParameters.length + 1]; + System.arraycopy(applicationParameters, 0, results, 0, + applicationParameters.length); + results[applicationParameters.length] = parameter; + applicationParameters = results; + } + fireContainerEvent("addApplicationParameter", parameter); + + } + + + /** + * Add a child Container, only if the proposed child is an implementation + * of Wrapper. + * + * @param child Child container to be added + * + * @exception IllegalArgumentException if the proposed container is + * not an implementation of Wrapper + */ + public void addChild(Container child) { + + // Global JspServlet + Wrapper oldJspServlet = null; + + if (!(child instanceof Wrapper)) { + throw new IllegalArgumentException + (sm.getString("standardContext.notWrapper")); + } + + Wrapper wrapper = (Wrapper) child; + boolean isJspServlet = "jsp".equals(child.getName()); + + // Allow webapp to override JspServlet inherited from global web.xml. + if (isJspServlet) { + oldJspServlet = (Wrapper) findChild("jsp"); + if (oldJspServlet != null) { + removeChild(oldJspServlet); + } + } + + String jspFile = wrapper.getJspFile(); + if ((jspFile != null) && !jspFile.startsWith("/")) { + if (isServlet22()) { + if(log.isDebugEnabled()) + log.debug(sm.getString("standardContext.wrapper.warning", + jspFile)); + wrapper.setJspFile("/" + jspFile); + } else { + throw new IllegalArgumentException + (sm.getString("standardContext.wrapper.error", jspFile)); + } + } + + super.addChild(child); + + if (isJspServlet && oldJspServlet != null) { + /* + * The webapp-specific JspServlet inherits all the mappings + * specified in the global web.xml, and may add additional ones. + */ + String[] jspMappings = oldJspServlet.findMappings(); + for (int i=0; jspMappings!=null && inull. + * + * @param errorCode Error code to look up + */ + public ErrorPage findErrorPage(int errorCode) { + if (errorCode == 200) { + return (okErrorPage); + } else { + return ((ErrorPage) statusPages.get(new Integer(errorCode))); + } + + } + + + /** + * Return the error page entry for the specified Java exception type, + * if any; otherwise return null. + * + * @param exceptionType Exception type to look up + */ + public ErrorPage findErrorPage(String exceptionType) { + + synchronized (exceptionPages) { + return ((ErrorPage) exceptionPages.get(exceptionType)); + } + + } + + + /** + * Return the set of defined error pages for all specified error codes + * and exception types. + */ + public ErrorPage[] findErrorPages() { + + synchronized(exceptionPages) { + synchronized(statusPages) { + ErrorPage results1[] = new ErrorPage[exceptionPages.size()]; + results1 = + (ErrorPage[]) exceptionPages.values().toArray(results1); + ErrorPage results2[] = new ErrorPage[statusPages.size()]; + results2 = + (ErrorPage[]) statusPages.values().toArray(results2); + ErrorPage results[] = + new ErrorPage[results1.length + results2.length]; + for (int i = 0; i < results1.length; i++) + results[i] = results1[i]; + for (int i = results1.length; i < results.length; i++) + results[i] = results2[i - results1.length]; + return (results); + } + } + + } + + + /** + * Return the filter definition for the specified filter name, if any; + * otherwise return null. + * + * @param filterName Filter name to look up + */ + public FilterDef findFilterDef(String filterName) { + + synchronized (filterDefs) { + return ((FilterDef) filterDefs.get(filterName)); + } + + } + + + /** + * Return the set of defined filters for this Context. + */ + public FilterDef[] findFilterDefs() { + + synchronized (filterDefs) { + FilterDef results[] = new FilterDef[filterDefs.size()]; + return ((FilterDef[]) filterDefs.values().toArray(results)); + } + + } + + + /** + * Return the set of filter mappings for this Context. + */ + public FilterMap[] findFilterMaps() { + + return (filterMaps); + + } + + + /** + * Return the set of InstanceListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findInstanceListeners() { + + return (instanceListeners); + + } + + + /** + * FIXME: Fooling introspection ... + */ + public Context findMappingObject() { + return (Context) getMappingObject(); + } + + + /** + * Return the message destination with the specified name, if any; + * otherwise, return null. + * + * @param name Name of the desired message destination + */ + public MessageDestination findMessageDestination(String name) { + + synchronized (messageDestinations) { + return ((MessageDestination) messageDestinations.get(name)); + } + + } + + + /** + * Return the set of defined message destinations for this web + * application. If none have been defined, a zero-length array + * is returned. + */ + public MessageDestination[] findMessageDestinations() { + + synchronized (messageDestinations) { + MessageDestination results[] = + new MessageDestination[messageDestinations.size()]; + return ((MessageDestination[]) + messageDestinations.values().toArray(results)); + } + + } + + + /** + * Return the message destination ref with the specified name, if any; + * otherwise, return null. + * + * @param name Name of the desired message destination ref + */ + public MessageDestinationRef + findMessageDestinationRef(String name) { + + return namingResources.findMessageDestinationRef(name); + + } + + + /** + * Return the set of defined message destination refs for this web + * application. If none have been defined, a zero-length array + * is returned. + */ + public MessageDestinationRef[] + findMessageDestinationRefs() { + + return namingResources.findMessageDestinationRefs(); + + } + + + /** + * Return the MIME type to which the specified extension is mapped, + * if any; otherwise return null. + * + * @param extension Extension to map to a MIME type + */ + public String findMimeMapping(String extension) { + + return ((String) mimeMappings.get(extension)); + + } + + + /** + * Return the extensions for which MIME mappings are defined. If there + * are none, a zero-length array is returned. + */ + public String[] findMimeMappings() { + + synchronized (mimeMappings) { + String results[] = new String[mimeMappings.size()]; + return + ((String[]) mimeMappings.keySet().toArray(results)); + } + + } + + + /** + * Return the value for the specified context initialization + * parameter name, if any; otherwise return null. + * + * @param name Name of the parameter to return + */ + public String findParameter(String name) { + + synchronized (parameters) { + return ((String) parameters.get(name)); + } + + } + + + /** + * Return the names of all defined context initialization parameters + * for this Context. If no parameters are defined, a zero-length + * array is returned. + */ + public String[] findParameters() { + + synchronized (parameters) { + String results[] = new String[parameters.size()]; + return ((String[]) parameters.keySet().toArray(results)); + } + + } + + + /** + * For the given security role (as used by an application), return the + * corresponding role name (as defined by the underlying Realm) if there + * is one. Otherwise, return the specified role unchanged. + * + * @param role Security role to map + */ + public String findRoleMapping(String role) { + + String realRole = null; + synchronized (roleMappings) { + realRole = (String) roleMappings.get(role); + } + if (realRole != null) + return (realRole); + else + return (role); + + } + + + /** + * Return true if the specified security role is defined + * for this application; otherwise return false. + * + * @param role Security role to verify + */ + public boolean findSecurityRole(String role) { + + synchronized (securityRoles) { + for (int i = 0; i < securityRoles.length; i++) { + if (role.equals(securityRoles[i])) + return (true); + } + } + return (false); + + } + + + /** + * Return the security roles defined for this application. If none + * have been defined, a zero-length array is returned. + */ + public String[] findSecurityRoles() { + + return (securityRoles); + + } + + + /** + * Return the servlet name mapped by the specified pattern (if any); + * otherwise return null. + * + * @param pattern Pattern for which a mapping is requested + */ + public String findServletMapping(String pattern) { + + synchronized (servletMappings) { + return ((String) servletMappings.get(pattern)); + } + + } + + + /** + * Return the patterns of all defined servlet mappings for this + * Context. If no mappings are defined, a zero-length array is returned. + */ + public String[] findServletMappings() { + + synchronized (servletMappings) { + String results[] = new String[servletMappings.size()]; + return + ((String[]) servletMappings.keySet().toArray(results)); + } + + } + + + /** + * Return the context-relative URI of the error page for the specified + * HTTP status code, if any; otherwise return null. + * + * @param status HTTP status code to look up + */ + public String findStatusPage(int status) { + + return ((String) statusPages.get(new Integer(status))); + + } + + + /** + * Return the set of HTTP status codes for which error pages have + * been specified. If none are specified, a zero-length array + * is returned. + */ + public int[] findStatusPages() { + + synchronized (statusPages) { + int results[] = new int[statusPages.size()]; + Iterator elements = statusPages.keySet().iterator(); + int i = 0; + while (elements.hasNext()) + results[i++] = ((Integer) elements.next()).intValue(); + return (results); + } + + } + + + /** + * Return the tag library descriptor location for the specified taglib + * URI, if any; otherwise, return null. + * + * @param uri URI, relative to the web.xml file + */ + public String findTaglib(String uri) { + + synchronized (taglibs) { + return ((String) taglibs.get(uri)); + } + + } + + + /** + * Return the URIs of all tag libraries for which a tag library + * descriptor location has been specified. If none are specified, + * a zero-length array is returned. + */ + public String[] findTaglibs() { + + synchronized (taglibs) { + String results[] = new String[taglibs.size()]; + return ((String[]) taglibs.keySet().toArray(results)); + } + + } + + + /** + * Return true if the specified welcome file is defined + * for this Context; otherwise return false. + * + * @param name Welcome file to verify + */ + public boolean findWelcomeFile(String name) { + + synchronized (welcomeFiles) { + for (int i = 0; i < welcomeFiles.length; i++) { + if (name.equals(welcomeFiles[i])) + return (true); + } + } + return (false); + + } + + + /** + * Return the set of watched resources for this Context. If none are + * defined, a zero length array will be returned. + */ + public String[] findWatchedResources() { + return watchedResources; + } + + + /** + * Return the set of welcome files defined for this Context. If none are + * defined, a zero-length array is returned. + */ + public String[] findWelcomeFiles() { + + return (welcomeFiles); + + } + + + /** + * Return the set of LifecycleListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findWrapperLifecycles() { + + return (wrapperLifecycles); + + } + + + /** + * Return the set of ContainerListener classes that will be added to + * newly created Wrappers automatically. + */ + public String[] findWrapperListeners() { + + return (wrapperListeners); + + } + + + /** + * Reload this web application, if reloading is supported. + *

    + * IMPLEMENTATION NOTE: This method is designed to deal with + * reloads required by changes to classes in the underlying repositories + * of our class loader. It does not handle changes to the web application + * deployment descriptor. If that has occurred, you should stop this + * Context and create (and start) a new Context instance instead. + * + * @exception IllegalStateException if the reloadable + * property is set to false. + */ + public synchronized void reload() { + + // Validate our current component state + if (!started) + throw new IllegalStateException + (sm.getString("containerBase.notStarted", logName())); + + // Make sure reloading is enabled + // if (!reloadable) + // throw new IllegalStateException + // (sm.getString("standardContext.notReloadable")); + if(log.isInfoEnabled()) + log.info(sm.getString("standardContext.reloadingStarted")); + + // Stop accepting requests temporarily + setPaused(true); + + try { + stop(); + } catch (LifecycleException e) { + log.error(sm.getString("standardContext.stoppingContext"), e); + } + + try { + start(); + } catch (LifecycleException e) { + log.error(sm.getString("standardContext.startingContext"), e); + } + + setPaused(false); + + } + + + /** + * Remove the specified application listener class from the set of + * listeners for this application. + * + * @param listener Java class name of the listener to be removed + */ + public void removeApplicationListener(String listener) { + + synchronized (applicationListeners) { + + // Make sure this welcome file is currently present + int n = -1; + for (int i = 0; i < applicationListeners.length; i++) { + if (applicationListeners[i].equals(listener)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + String results[] = new String[applicationListeners.length - 1]; + for (int i = 0; i < applicationListeners.length; i++) { + if (i != n) + results[j++] = applicationListeners[i]; + } + applicationListeners = results; + + } + + // Inform interested listeners + fireContainerEvent("removeApplicationListener", listener); + + // FIXME - behavior if already started? + + } + + + /** + * Remove the application parameter with the specified name from + * the set for this application. + * + * @param name Name of the application parameter to remove + */ + public void removeApplicationParameter(String name) { + + synchronized (applicationParameters) { + + // Make sure this parameter is currently present + int n = -1; + for (int i = 0; i < applicationParameters.length; i++) { + if (name.equals(applicationParameters[i].getName())) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified parameter + int j = 0; + ApplicationParameter results[] = + new ApplicationParameter[applicationParameters.length - 1]; + for (int i = 0; i < applicationParameters.length; i++) { + if (i != n) + results[j++] = applicationParameters[i]; + } + applicationParameters = results; + + } + + // Inform interested listeners + fireContainerEvent("removeApplicationParameter", name); + + } + + + /** + * Add a child Container, only if the proposed child is an implementation + * of Wrapper. + * + * @param child Child container to be added + * + * @exception IllegalArgumentException if the proposed container is + * not an implementation of Wrapper + */ + public void removeChild(Container child) { + + if (!(child instanceof Wrapper)) { + throw new IllegalArgumentException + (sm.getString("standardContext.notWrapper")); + } + + super.removeChild(child); + + } + + + /** + * Remove the specified security constraint from this web application. + * + * @param constraint Constraint to be removed + */ + public void removeConstraint(SecurityConstraint constraint) { + + synchronized (constraints) { + + // Make sure this constraint is currently present + int n = -1; + for (int i = 0; i < constraints.length; i++) { + if (constraints[i].equals(constraint)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + SecurityConstraint results[] = + new SecurityConstraint[constraints.length - 1]; + for (int i = 0; i < constraints.length; i++) { + if (i != n) + results[j++] = constraints[i]; + } + constraints = results; + + } + + // Inform interested listeners + fireContainerEvent("removeConstraint", constraint); + + } + + + /** + * Remove the error page for the specified error code or + * Java language exception, if it exists; otherwise, no action is taken. + * + * @param errorPage The error page definition to be removed + */ + public void removeErrorPage(ErrorPage errorPage) { + + String exceptionType = errorPage.getExceptionType(); + if (exceptionType != null) { + synchronized (exceptionPages) { + exceptionPages.remove(exceptionType); + } + } else { + synchronized (statusPages) { + if (errorPage.getErrorCode() == 200) { + this.okErrorPage = null; + } + statusPages.remove(new Integer(errorPage.getErrorCode())); + } + } + fireContainerEvent("removeErrorPage", errorPage); + + } + + + /** + * Remove the specified filter definition from this Context, if it exists; + * otherwise, no action is taken. + * + * @param filterDef Filter definition to be removed + */ + public void removeFilterDef(FilterDef filterDef) { + + synchronized (filterDefs) { + filterDefs.remove(filterDef.getFilterName()); + } + fireContainerEvent("removeFilterDef", filterDef); + + } + + + /** + * Remove a filter mapping from this Context. + * + * @param filterMap The filter mapping to be removed + */ + public void removeFilterMap(FilterMap filterMap) { + + synchronized (filterMaps) { + + // Make sure this filter mapping is currently present + int n = -1; + for (int i = 0; i < filterMaps.length; i++) { + if (filterMaps[i] == filterMap) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified filter mapping + FilterMap results[] = new FilterMap[filterMaps.length - 1]; + System.arraycopy(filterMaps, 0, results, 0, n); + System.arraycopy(filterMaps, n + 1, results, n, + (filterMaps.length - 1) - n); + filterMaps = results; + + } + + // Inform interested listeners + fireContainerEvent("removeFilterMap", filterMap); + + } + + + /** + * Remove a class name from the set of InstanceListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of an InstanceListener class to be removed + */ + public void removeInstanceListener(String listener) { + + synchronized (instanceListeners) { + + // Make sure this welcome file is currently present + int n = -1; + for (int i = 0; i < instanceListeners.length; i++) { + if (instanceListeners[i].equals(listener)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + String results[] = new String[instanceListeners.length - 1]; + for (int i = 0; i < instanceListeners.length; i++) { + if (i != n) + results[j++] = instanceListeners[i]; + } + instanceListeners = results; + + } + + // Inform interested listeners + fireContainerEvent("removeInstanceListener", listener); + + } + + + /** + * Remove any message destination with the specified name. + * + * @param name Name of the message destination to remove + */ + public void removeMessageDestination(String name) { + + synchronized (messageDestinations) { + messageDestinations.remove(name); + } + fireContainerEvent("removeMessageDestination", name); + + } + + + /** + * Remove any message destination ref with the specified name. + * + * @param name Name of the message destination ref to remove + */ + public void removeMessageDestinationRef(String name) { + + namingResources.removeMessageDestinationRef(name); + fireContainerEvent("removeMessageDestinationRef", name); + + } + + + /** + * Remove the MIME mapping for the specified extension, if it exists; + * otherwise, no action is taken. + * + * @param extension Extension to remove the mapping for + */ + public void removeMimeMapping(String extension) { + + synchronized (mimeMappings) { + mimeMappings.remove(extension); + } + fireContainerEvent("removeMimeMapping", extension); + + } + + + /** + * Remove the context initialization parameter with the specified + * name, if it exists; otherwise, no action is taken. + * + * @param name Name of the parameter to remove + */ + public void removeParameter(String name) { + + synchronized (parameters) { + parameters.remove(name); + } + fireContainerEvent("removeParameter", name); + + } + + + /** + * Remove any security role reference for the specified name + * + * @param role Security role (as used in the application) to remove + */ + public void removeRoleMapping(String role) { + + synchronized (roleMappings) { + roleMappings.remove(role); + } + fireContainerEvent("removeRoleMapping", role); + + } + + + /** + * Remove any security role with the specified name. + * + * @param role Security role to remove + */ + public void removeSecurityRole(String role) { + + synchronized (securityRoles) { + + // Make sure this security role is currently present + int n = -1; + for (int i = 0; i < securityRoles.length; i++) { + if (role.equals(securityRoles[i])) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified security role + int j = 0; + String results[] = new String[securityRoles.length - 1]; + for (int i = 0; i < securityRoles.length; i++) { + if (i != n) + results[j++] = securityRoles[i]; + } + securityRoles = results; + + } + + // Inform interested listeners + fireContainerEvent("removeSecurityRole", role); + + } + + + /** + * Remove any servlet mapping for the specified pattern, if it exists; + * otherwise, no action is taken. + * + * @param pattern URL pattern of the mapping to remove + */ + public void removeServletMapping(String pattern) { + + String name = null; + synchronized (servletMappings) { + name = (String) servletMappings.remove(pattern); + } + Wrapper wrapper = (Wrapper) findChild(name); + if( wrapper != null ) { + wrapper.removeMapping(pattern); + } + mapper.removeWrapper(pattern); + fireContainerEvent("removeServletMapping", pattern); + + } + + + /** + * Remove the tag library location forthe specified tag library URI. + * + * @param uri URI, relative to the web.xml file + */ + public void removeTaglib(String uri) { + + synchronized (taglibs) { + taglibs.remove(uri); + } + fireContainerEvent("removeTaglib", uri); + } + + + /** + * Remove the specified watched resource name from the list associated + * with this Context. + * + * @param name Name of the watched resource to be removed + */ + public void removeWatchedResource(String name) { + + synchronized (watchedResources) { + + // Make sure this watched resource is currently present + int n = -1; + for (int i = 0; i < watchedResources.length; i++) { + if (watchedResources[i].equals(name)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified watched resource + int j = 0; + String results[] = new String[watchedResources.length - 1]; + for (int i = 0; i < watchedResources.length; i++) { + if (i != n) + results[j++] = watchedResources[i]; + } + watchedResources = results; + + } + + fireContainerEvent("removeWatchedResource", name); + + } + + + /** + * Remove the specified welcome file name from the list recognized + * by this Context. + * + * @param name Name of the welcome file to be removed + */ + public void removeWelcomeFile(String name) { + + synchronized (welcomeFiles) { + + // Make sure this welcome file is currently present + int n = -1; + for (int i = 0; i < welcomeFiles.length; i++) { + if (welcomeFiles[i].equals(name)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + String results[] = new String[welcomeFiles.length - 1]; + for (int i = 0; i < welcomeFiles.length; i++) { + if (i != n) + results[j++] = welcomeFiles[i]; + } + welcomeFiles = results; + + } + + // Inform interested listeners + postWelcomeFiles(); + fireContainerEvent("removeWelcomeFile", name); + + } + + + /** + * Remove a class name from the set of LifecycleListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of a LifecycleListener class to be removed + */ + public void removeWrapperLifecycle(String listener) { + + + synchronized (wrapperLifecycles) { + + // Make sure this welcome file is currently present + int n = -1; + for (int i = 0; i < wrapperLifecycles.length; i++) { + if (wrapperLifecycles[i].equals(listener)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + String results[] = new String[wrapperLifecycles.length - 1]; + for (int i = 0; i < wrapperLifecycles.length; i++) { + if (i != n) + results[j++] = wrapperLifecycles[i]; + } + wrapperLifecycles = results; + + } + + // Inform interested listeners + fireContainerEvent("removeWrapperLifecycle", listener); + + } + + + /** + * Remove a class name from the set of ContainerListener classes that + * will be added to newly created Wrappers. + * + * @param listener Class name of a ContainerListener class to be removed + */ + public void removeWrapperListener(String listener) { + + + synchronized (wrapperListeners) { + + // Make sure this welcome file is currently present + int n = -1; + for (int i = 0; i < wrapperListeners.length; i++) { + if (wrapperListeners[i].equals(listener)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified constraint + int j = 0; + String results[] = new String[wrapperListeners.length - 1]; + for (int i = 0; i < wrapperListeners.length; i++) { + if (i != n) + results[j++] = wrapperListeners[i]; + } + wrapperListeners = results; + + } + + // Inform interested listeners + fireContainerEvent("removeWrapperListener", listener); + + } + + + /** + * Gets the cumulative processing times of all servlets in this + * StandardContext. + * + * @return Cumulative processing times of all servlets in this + * StandardContext + */ + public long getProcessingTime() { + + long result = 0; + + Container[] children = findChildren(); + if (children != null) { + for( int i=0; i< children.length; i++ ) { + result += ((StandardWrapper)children[i]).getProcessingTime(); + } + } + + return result; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Configure and initialize the set of filters for this Context. + * Return true if all filter initialization completed + * successfully, or false otherwise. + */ + public boolean filterStart() { + + if (getLogger().isDebugEnabled()) + getLogger().debug("Starting filters"); + // Instantiate and record a FilterConfig for each defined filter + boolean ok = true; + synchronized (filterConfigs) { + filterConfigs.clear(); + Iterator names = filterDefs.keySet().iterator(); + while (names.hasNext()) { + String name = (String) names.next(); + if (getLogger().isDebugEnabled()) + getLogger().debug(" Starting filter '" + name + "'"); + ApplicationFilterConfig filterConfig = null; + try { + filterConfig = new ApplicationFilterConfig + (this, (FilterDef) filterDefs.get(name)); + filterConfigs.put(name, filterConfig); + } catch (Throwable t) { + getLogger().error + (sm.getString("standardContext.filterStart", name), t); + ok = false; + } + } + } + + return (ok); + + } + + + /** + * Finalize and release the set of filters for this Context. + * Return true if all filter finalization completed + * successfully, or false otherwise. + */ + public boolean filterStop() { + + if (getLogger().isDebugEnabled()) + getLogger().debug("Stopping filters"); + + // Release all Filter and FilterConfig instances + synchronized (filterConfigs) { + Iterator names = filterConfigs.keySet().iterator(); + while (names.hasNext()) { + String name = (String) names.next(); + if (getLogger().isDebugEnabled()) + getLogger().debug(" Stopping filter '" + name + "'"); + ApplicationFilterConfig filterConfig = + (ApplicationFilterConfig) filterConfigs.get(name); + filterConfig.release(); + } + filterConfigs.clear(); + } + return (true); + + } + + + /** + * Find and return the initialized FilterConfig for the + * specified filter name, if any; otherwise return null. + * + * @param name Name of the desired filter + */ + public FilterConfig findFilterConfig(String name) { + + return ((FilterConfig) filterConfigs.get(name)); + + } + + + /** + * Configure the set of instantiated application event listeners + * for this Context. Return true if all listeners wre + * initialized successfully, or false otherwise. + */ + public boolean listenerStart() { + + if (log.isDebugEnabled()) + log.debug("Configuring application event listeners"); + + // Instantiate the required listeners + ClassLoader loader = getLoader().getClassLoader(); + String listeners[] = findApplicationListeners(); + Object results[] = new Object[listeners.length]; + boolean ok = true; + for (int i = 0; i < results.length; i++) { + if (getLogger().isDebugEnabled()) + getLogger().debug(" Configuring event listener class '" + + listeners[i] + "'"); + try { + Class clazz = loader.loadClass(listeners[i]); + results[i] = clazz.newInstance(); + // Annotation processing + if (!getIgnoreAnnotations()) { + if (getNamingContextListener() != null) { + AnnotationProcessor.injectNamingResources + (getNamingContextListener().getEnvContext(), results[i]); + } + AnnotationProcessor.postConstruct(results[i]); + } + } catch (Throwable t) { + getLogger().error + (sm.getString("standardContext.applicationListener", + listeners[i]), t); + ok = false; + } + } + if (!ok) { + getLogger().error(sm.getString("standardContext.applicationSkipped")); + return (false); + } + + // Sort listeners in two arrays + ArrayList eventListeners = new ArrayList(); + ArrayList lifecycleListeners = new ArrayList(); + for (int i = 0; i < results.length; i++) { + if ((results[i] instanceof ServletContextAttributeListener) + || (results[i] instanceof ServletRequestAttributeListener) + || (results[i] instanceof ServletRequestListener) + || (results[i] instanceof HttpSessionAttributeListener)) { + eventListeners.add(results[i]); + } + if ((results[i] instanceof ServletContextListener) + || (results[i] instanceof HttpSessionListener)) { + lifecycleListeners.add(results[i]); + } + } + + setApplicationEventListeners(eventListeners.toArray()); + setApplicationLifecycleListeners(lifecycleListeners.toArray()); + + // Send application start events + + if (getLogger().isDebugEnabled()) + getLogger().debug("Sending application start events"); + + Object instances[] = getApplicationLifecycleListeners(); + if (instances == null) + return (ok); + ServletContextEvent event = + new ServletContextEvent(getServletContext()); + for (int i = 0; i < instances.length; i++) { + if (instances[i] == null) + continue; + if (!(instances[i] instanceof ServletContextListener)) + continue; + ServletContextListener listener = + (ServletContextListener) instances[i]; + try { + fireContainerEvent("beforeContextInitialized", listener); + listener.contextInitialized(event); + fireContainerEvent("afterContextInitialized", listener); + } catch (Throwable t) { + fireContainerEvent("afterContextInitialized", listener); + getLogger().error + (sm.getString("standardContext.listenerStart", + instances[i].getClass().getName()), t); + ok = false; + } + } + return (ok); + + } + + + /** + * Send an application stop event to all interested listeners. + * Return true if all events were sent successfully, + * or false otherwise. + */ + public boolean listenerStop() { + + if (log.isDebugEnabled()) + log.debug("Sending application stop events"); + + boolean ok = true; + Object listeners[] = getApplicationLifecycleListeners(); + if (listeners != null) { + ServletContextEvent event = + new ServletContextEvent(getServletContext()); + for (int i = 0; i < listeners.length; i++) { + int j = (listeners.length - 1) - i; + if (listeners[j] == null) + continue; + if (listeners[j] instanceof ServletContextListener) { + ServletContextListener listener = + (ServletContextListener) listeners[j]; + try { + fireContainerEvent("beforeContextDestroyed", listener); + listener.contextDestroyed(event); + fireContainerEvent("afterContextDestroyed", listener); + } catch (Throwable t) { + fireContainerEvent("afterContextDestroyed", listener); + getLogger().error + (sm.getString("standardContext.listenerStop", + listeners[j].getClass().getName()), t); + ok = false; + } + } + // Annotation processing + if (!getIgnoreAnnotations()) { + try { + AnnotationProcessor.preDestroy(listeners[j]); + } catch (Throwable t) { + getLogger().error + (sm.getString("standardContext.listenerStop", + listeners[j].getClass().getName()), t); + ok = false; + } + } + } + } + + // Annotation processing + listeners = getApplicationEventListeners(); + if (!getIgnoreAnnotations() && listeners != null) { + for (int i = 0; i < listeners.length; i++) { + int j = (listeners.length - 1) - i; + if (listeners[j] == null) + continue; + try { + AnnotationProcessor.preDestroy(listeners[j]); + } catch (Throwable t) { + getLogger().error + (sm.getString("standardContext.listenerStop", + listeners[j].getClass().getName()), t); + ok = false; + } + } + } + + setApplicationEventListeners(null); + setApplicationLifecycleListeners(null); + + return (ok); + + } + + + /** + * Allocate resources, including proxy. + * Return true if initialization was successfull, + * or false otherwise. + */ + public boolean resourcesStart() { + + boolean ok = true; + + Hashtable env = new Hashtable(); + if (getParent() != null) + env.put(ProxyDirContext.HOST, getParent().getName()); + env.put(ProxyDirContext.CONTEXT, getName()); + + try { + ProxyDirContext proxyDirContext = + new ProxyDirContext(env, webappResources); + if (webappResources instanceof FileDirContext) { + filesystemBased = true; + ((FileDirContext) webappResources).setCaseSensitive + (isCaseSensitive()); + ((FileDirContext) webappResources).setAllowLinking + (isAllowLinking()); + } + if (webappResources instanceof BaseDirContext) { + ((BaseDirContext) webappResources).setDocBase(getBasePath()); + ((BaseDirContext) webappResources).setCached + (isCachingAllowed()); + ((BaseDirContext) webappResources).setCacheTTL(getCacheTTL()); + ((BaseDirContext) webappResources).setCacheMaxSize + (getCacheMaxSize()); + ((BaseDirContext) webappResources).allocate(); + } + // Register the cache in JMX + if (isCachingAllowed()) { + ObjectName resourcesName = + new ObjectName(this.getDomain() + ":type=Cache,host=" + + getHostname() + ",path=" + + (("".equals(getPath()))?"/":getPath())); + Registry.getRegistry(null, null).registerComponent + (proxyDirContext.getCache(), resourcesName, null); + } + this.resources = proxyDirContext; + } catch (Throwable t) { + log.error(sm.getString("standardContext.resourcesStart"), t); + ok = false; + } + + return (ok); + + } + + + /** + * Deallocate resources and destroy proxy. + */ + public boolean resourcesStop() { + + boolean ok = true; + + try { + if (resources != null) { + if (resources instanceof Lifecycle) { + ((Lifecycle) resources).stop(); + } + if (webappResources instanceof BaseDirContext) { + ((BaseDirContext) webappResources).release(); + } + // Unregister the cache in JMX + if (isCachingAllowed()) { + ObjectName resourcesName = + new ObjectName(this.getDomain() + + ":type=Cache,host=" + + getHostname() + ",path=" + + (("".equals(getPath()))?"/" + :getPath())); + Registry.getRegistry(null, null) + .unregisterComponent(resourcesName); + } + } + } catch (Throwable t) { + log.error(sm.getString("standardContext.resourcesStop"), t); + ok = false; + } + + this.resources = null; + + return (ok); + + } + + + /** + * Load and initialize all servlets marked "load on startup" in the + * web application deployment descriptor. + * + * @param children Array of wrappers for all currently defined + * servlets (including those not declared load on startup) + */ + public void loadOnStartup(Container children[]) { + + // Collect "load on startup" servlets that need to be initialized + TreeMap map = new TreeMap(); + for (int i = 0; i < children.length; i++) { + Wrapper wrapper = (Wrapper) children[i]; + int loadOnStartup = wrapper.getLoadOnStartup(); + if (loadOnStartup < 0) + continue; + if (loadOnStartup == 0) // Arbitrarily put them last + loadOnStartup = Integer.MAX_VALUE; + Integer key = new Integer(loadOnStartup); + ArrayList list = (ArrayList) map.get(key); + if (list == null) { + list = new ArrayList(); + map.put(key, list); + } + list.add(wrapper); + } + + // Load the collected "load on startup" servlets + Iterator keys = map.keySet().iterator(); + while (keys.hasNext()) { + Integer key = (Integer) keys.next(); + ArrayList list = (ArrayList) map.get(key); + Iterator wrappers = list.iterator(); + while (wrappers.hasNext()) { + Wrapper wrapper = (Wrapper) wrappers.next(); + try { + wrapper.load(); + } catch (ServletException e) { + getLogger().error(sm.getString("standardWrapper.loadException", + getName()), StandardWrapper.getRootCause(e)); + // NOTE: load errors (including a servlet that throws + // UnavailableException from tht init() method) are NOT + // fatal to application startup + } + } + } + + } + + + /** + * Start this Context component. + * + * @exception LifecycleException if a startup error occurs + */ + public synchronized void start() throws LifecycleException { + //if (lazy ) return; + if (started) { + if(log.isInfoEnabled()) + log.info(sm.getString("containerBase.alreadyStarted", logName())); + return; + } + if( !initialized ) { + try { + init(); + } catch( Exception ex ) { + throw new LifecycleException("Error initializaing ", ex); + } + } + if(log.isDebugEnabled()) + log.debug("Starting " + ("".equals(getName()) ? "ROOT" : getName())); + + // Set JMX object name for proper pipeline registration + preRegisterJMX(); + + if ((oname != null) && + (Registry.getRegistry(null, null).getMBeanServer().isRegistered(oname))) { + // As things depend on the JMX registration, the context + // must be reregistered again once properly initialized + Registry.getRegistry(null, null).unregisterComponent(oname); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); + + setAvailable(false); + setConfigured(false); + boolean ok = true; + + // Add missing components as necessary + if (webappResources == null) { // (1) Required by Loader + if (log.isDebugEnabled()) + log.debug("Configuring default Resources"); + try { + if ((docBase != null) && (docBase.endsWith(".war")) && (!(new File(getBasePath())).isDirectory())) + setResources(new WARDirContext()); + else + setResources(new FileDirContext()); + } catch (IllegalArgumentException e) { + log.error("Error initializing resources: " + e.getMessage()); + ok = false; + } + } + if (ok) { + if (!resourcesStart()) { + log.error( "Error in resourceStart()"); + ok = false; + } + } + + // Look for a realm - that may have been configured earlier. + // If the realm is added after context - it'll set itself. + // TODO: what is the use case for this ? + if( realm == null && mserver != null ) { + ObjectName realmName=null; + try { + realmName=new ObjectName( getEngineName() + ":type=Realm,host=" + + getHostname() + ",path=" + getPath()); + if( mserver.isRegistered(realmName ) ) { + mserver.invoke(realmName, "init", + new Object[] {}, + new String[] {} + ); + } + } catch( Throwable t ) { + if(log.isDebugEnabled()) + log.debug("No realm for this host " + realmName); + } + } + + if (getLoader() == null) { + ClassLoader parent = null; + if (getPrivileged()) { + if (log.isDebugEnabled()) + log.debug("Configuring privileged default Loader"); + parent = this.getClass().getClassLoader(); + } else { + if (log.isDebugEnabled()) + log.debug("Configuring non-privileged default Loader"); + parent = getParentClassLoader(); + } + WebappLoader webappLoader = new WebappLoader(parent); + webappLoader.setDelegate(getDelegate()); + setLoader(webappLoader); + } + + // Initialize character set mapper + getCharsetMapper(); + + // Post work directory + postWorkDirectory(); + + // Validate required extensions + boolean dependencyCheck = true; + try { + dependencyCheck = ExtensionValidator.validateApplication + (getResources(), this); + } catch (IOException ioe) { + log.error("Error in dependencyCheck", ioe); + dependencyCheck = false; + } + + if (!dependencyCheck) { + // do not make application available if depency check fails + ok = false; + } + + // Reading the "catalina.useNaming" environment variable + String useNamingProperty = System.getProperty("catalina.useNaming"); + if ((useNamingProperty != null) + && (useNamingProperty.equals("false"))) { + useNaming = false; + } + + if (ok && isUseNaming()) { + if (namingContextListener == null) { + namingContextListener = new NamingContextListener(); + namingContextListener.setName(getNamingContextName()); + addLifecycleListener(namingContextListener); + } + } + + // Standard container startup + if (log.isDebugEnabled()) + log.debug("Processing standard container startup"); + + // Acquire clustered manager + Manager contextManager = null; + if (manager == null) { + if ((getCluster() != null) && distributable) { + try { + contextManager = getCluster().createManager(getName()); + } catch (Exception ex) { + log.error("standardContext.clusterFail", ex); + ok = false; + } + } else { + contextManager = new StandardManager(); + } + } + + + // Binding thread + ClassLoader oldCCL = bindThread(); + + boolean mainOk = false; + + try { + + if (ok) { + + started = true; + + // Start our subordinate components, if any + if ((loader != null) && (loader instanceof Lifecycle)) + ((Lifecycle) loader).start(); + + // Unbinding thread + unbindThread(oldCCL); + + // Binding thread + oldCCL = bindThread(); + + // Initialize logger again. Other components might have used it too early, + // so it should be reset. + logger = null; + getLogger(); + if ((logger != null) && (logger instanceof Lifecycle)) + ((Lifecycle) logger).start(); + + if ((cluster != null) && (cluster instanceof Lifecycle)) + ((Lifecycle) cluster).start(); + if ((realm != null) && (realm instanceof Lifecycle)) + ((Lifecycle) realm).start(); + if ((resources != null) && (resources instanceof Lifecycle)) + ((Lifecycle) resources).start(); + + // Start our child containers, if any + Container children[] = findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof Lifecycle) + ((Lifecycle) children[i]).start(); + } + + // Start the Valves in our pipeline (including the basic), + // if any + if (pipeline instanceof Lifecycle) { + ((Lifecycle) pipeline).start(); + } + + if(getProcessTlds()) { + processTlds(); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(START_EVENT, null); + + // Configure default manager if none was specified + if (contextManager != null) { + setManager(contextManager); + } + + // Start manager + if ((manager != null) && (manager instanceof Lifecycle)) { + ((Lifecycle) getManager()).start(); + } + + // Start ContainerBackgroundProcessor thread + super.threadStart(); + + mainOk = true; + + } + + } finally { + // Unbinding thread + unbindThread(oldCCL); + if (!mainOk) { + // An exception occurred + // Register with JMX anyway, to allow management + registerJMX(); + } + } + + if (!getConfigured()) { + log.error( "Error getConfigured"); + ok = false; + } + + // We put the resources into the servlet context + if (ok) + getServletContext().setAttribute + (Globals.RESOURCES_ATTR, getResources()); + + // Initialize associated mapper + mapper.setContext(getPath(), welcomeFiles, resources); + + // Binding thread + oldCCL = bindThread(); + + // Set annotation processing parameter for Jasper (unfortunately, since + // this can be configured in many places and not just in /WEB-INF/web.xml, + // there are not many solutions) + if (ignoreAnnotations) { + Wrapper jspServlet = (Wrapper) findChild(Constants.JSP_SERVLET_NAME); + jspServlet.addInitParameter("org.apache.jasper.IGNORE_ANNOTATIONS", "true"); + } + + try { + + // Create context attributes that will be required + if (ok) { + postWelcomeFiles(); + } + + if (ok) { + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); + } + + // Configure and call application event listeners and filters + if (ok) { + if (!listenerStart()) { + log.error( "Error listenerStart"); + ok = false; + } + } + if (ok) { + if (!filterStart()) { + log.error( "Error filterStart"); + ok = false; + } + } + + // Load and initialize all "load on startup" servlets + if (ok) { + loadOnStartup(findChildren()); + } + + } finally { + // Unbinding thread + unbindThread(oldCCL); + } + + // Set available status depending upon startup success + if (ok) { + if (log.isDebugEnabled()) + log.debug("Starting completed"); + setAvailable(true); + } else { + log.error(sm.getString("standardContext.startFailed", getName())); + try { + stop(); + } catch (Throwable t) { + log.error(sm.getString("standardContext.startCleanup"), t); + } + setAvailable(false); + } + + // JMX registration + registerJMX(); + + startTime=System.currentTimeMillis(); + + // Send j2ee.state.running notification + if (ok && (this.getObjectName() != null)) { + Notification notification = + new Notification("j2ee.state.running", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + // Close all JARs right away to avoid always opening a peak number + // of files on startup + if (getLoader() instanceof WebappLoader) { + ((WebappLoader) getLoader()).closeJARs(true); + } + + // Reinitializing if something went wrong + if (!ok && started) { + stop(); + } + + //cacheContext(); + } + + /** + * Processes TLDs. + * + * @throws LifecycleException If an error occurs + */ + protected void processTlds() throws LifecycleException { + TldConfig tldConfig = new TldConfig(); + tldConfig.setContext(this); + + // (1) check if the attribute has been defined + // on the context element. + tldConfig.setTldValidation(tldValidation); + tldConfig.setTldNamespaceAware(tldNamespaceAware); + + // (2) if the attribute wasn't defined on the context + // try the host. + if (!tldValidation) { + tldConfig.setTldValidation + (((StandardHost) getParent()).getXmlValidation()); + } + + if (!tldNamespaceAware) { + tldConfig.setTldNamespaceAware + (((StandardHost) getParent()).getXmlNamespaceAware()); + } + + try { + tldConfig.execute(); + } catch (Exception ex) { + log.error("Error reading tld listeners " + + ex.toString(), ex); + } + } + + private void cacheContext() { + try { + File workDir=new File( getWorkPath() ); + + File ctxSer=new File( workDir, "_tomcat_context.ser"); + FileOutputStream fos=new FileOutputStream( ctxSer ); + ObjectOutputStream oos=new ObjectOutputStream( fos ); + oos.writeObject(this); + oos.close(); + fos.close(); + } catch( Throwable t ) { + if(log.isInfoEnabled()) + log.info("Error saving context.ser ", t); + } + } + + + /** + * Stop this Context component. + * + * @exception LifecycleException if a shutdown error occurs + */ + public synchronized void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) { + if(log.isInfoEnabled()) + log.info(sm.getString("containerBase.notStarted", logName())); + return; + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); + + // Send j2ee.state.stopping notification + if (this.getObjectName() != null) { + Notification notification = + new Notification("j2ee.state.stopping", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + // Mark this application as unavailable while we shut down + setAvailable(false); + + // Binding thread + ClassLoader oldCCL = bindThread(); + + try { + + // Stop our filters + filterStop(); + + // Stop our application listeners + listenerStop(); + + // Stop ContainerBackgroundProcessor thread + super.threadStop(); + + if ((manager != null) && (manager instanceof Lifecycle)) { + ((Lifecycle) manager).stop(); + } + + // Finalize our character set mapper + setCharsetMapper(null); + + // Normal container shutdown processing + if (log.isDebugEnabled()) + log.debug("Processing standard container shutdown"); + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Stop the Valves in our pipeline (including the basic), if any + if (pipeline instanceof Lifecycle) { + ((Lifecycle) pipeline).stop(); + } + + // Stop our child containers, if any + Container[] children = findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof Lifecycle) + ((Lifecycle) children[i]).stop(); + } + + // Clear all application-originated servlet context attributes + if (context != null) + context.clearAttributes(); + + // Stop resources + resourcesStop(); + + if ((realm != null) && (realm instanceof Lifecycle)) { + ((Lifecycle) realm).stop(); + } + if ((cluster != null) && (cluster instanceof Lifecycle)) { + ((Lifecycle) cluster).stop(); + } + if ((logger != null) && (logger instanceof Lifecycle)) { + ((Lifecycle) logger).stop(); + } + if ((loader != null) && (loader instanceof Lifecycle)) { + ((Lifecycle) loader).stop(); + } + + } finally { + + // Unbinding thread + unbindThread(oldCCL); + + } + + // Send j2ee.state.stopped notification + if (this.getObjectName() != null) { + Notification notification = + new Notification("j2ee.state.stopped", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + // Reset application context + context = null; + + // This object will no longer be visible or used. + try { + resetContext(); + } catch( Exception ex ) { + log.error( "Error reseting context " + this + " " + ex, ex ); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); + + if (log.isDebugEnabled()) + log.debug("Stopping complete"); + + } + + /** Destroy needs to clean up the context completely. + * + * The problem is that undoing all the config in start() and restoring + * a 'fresh' state is impossible. After stop()/destroy()/init()/start() + * we should have the same state as if a fresh start was done - i.e + * read modified web.xml, etc. This can only be done by completely + * removing the context object and remapping a new one, or by cleaning + * up everything. + * + * XXX Should this be done in stop() ? + * + */ + public void destroy() throws Exception { + if( oname != null ) { + // Send j2ee.object.deleted notification + Notification notification = + new Notification("j2ee.object.deleted", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + super.destroy(); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(DESTROY_EVENT, null); + + instanceListeners = new String[0]; + + } + + private void resetContext() throws Exception, MBeanRegistrationException { + // Restore the original state ( pre reading web.xml in start ) + // If you extend this - override this method and make sure to clean up + children=new HashMap(); + startupTime = 0; + startTime = 0; + tldScanTime = 0; + + // Bugzilla 32867 + distributable = false; + + applicationListeners = new String[0]; + applicationEventListenersObjects = new Object[0]; + applicationLifecycleListenersObjects = new Object[0]; + + if(log.isDebugEnabled()) + log.debug("resetContext " + oname); + } + + /** + * Return a String representation of this component. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + if (getParent() != null) { + sb.append(getParent().toString()); + sb.append("."); + } + sb.append("StandardContext["); + sb.append(getName()); + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Adjust the URL pattern to begin with a leading slash, if appropriate + * (i.e. we are running a servlet 2.2 application). Otherwise, return + * the specified URL pattern unchanged. + * + * @param urlPattern The URL pattern to be adjusted (if needed) + * and returned + */ + protected String adjustURLPattern(String urlPattern) { + + if (urlPattern == null) + return (urlPattern); + if (urlPattern.startsWith("/") || urlPattern.startsWith("*.")) + return (urlPattern); + if (!isServlet22()) + return (urlPattern); + if(log.isDebugEnabled()) + log.debug(sm.getString("standardContext.urlPattern.patternWarning", + urlPattern)); + return ("/" + urlPattern); + + } + + + /** + * Are we processing a version 2.2 deployment descriptor? + */ + protected boolean isServlet22() { + + if (this.publicId == null) + return (false); + if (this.publicId.equals + (org.apache.catalina.startup.Constants.WebDtdPublicId_22)) + return (true); + else + return (false); + + } + + + /** + * Return a File object representing the base directory for the + * entire servlet container (i.e. the Engine container if present). + */ + protected File engineBase() { + String base=System.getProperty("catalina.base"); + if( base == null ) { + StandardEngine eng=(StandardEngine)this.getParent().getParent(); + base=eng.getBaseDir(); + } + return (new File(base)); + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Bind current thread, both for CL purposes and for JNDI ENC support + * during : startup, shutdown and realoading of the context. + * + * @return the previous context class loader + */ + private ClassLoader bindThread() { + + ClassLoader oldContextClassLoader = + Thread.currentThread().getContextClassLoader(); + + if (getResources() == null) + return oldContextClassLoader; + + if (getLoader().getClassLoader() != null) { + Thread.currentThread().setContextClassLoader + (getLoader().getClassLoader()); + } + + DirContextURLStreamHandler.bind(getResources()); + + if (isUseNaming()) { + try { + ContextBindings.bindThread(this, this); + } catch (NamingException e) { + // Silent catch, as this is a normal case during the early + // startup stages + } + } + + return oldContextClassLoader; + + } + + + /** + * Unbind thread. + */ + private void unbindThread(ClassLoader oldContextClassLoader) { + + Thread.currentThread().setContextClassLoader(oldContextClassLoader); + + oldContextClassLoader = null; + + if (isUseNaming()) { + ContextBindings.unbindThread(this, this); + } + + DirContextURLStreamHandler.unbind(); + + } + + + + /** + * Get base path. + */ + protected String getBasePath() { + String docBase = null; + Container container = this; + while (container != null) { + if (container instanceof Host) + break; + container = container.getParent(); + } + File file = new File(getDocBase()); + if (!file.isAbsolute()) { + if (container == null) { + docBase = (new File(engineBase(), getDocBase())).getPath(); + } else { + // Use the "appBase" property of this container + String appBase = ((Host) container).getAppBase(); + file = new File(appBase); + if (!file.isAbsolute()) + file = new File(engineBase(), appBase); + docBase = (new File(file, getDocBase())).getPath(); + } + } else { + docBase = file.getPath(); + } + return docBase; + } + + + /** + * Get app base. + */ + protected String getAppBase() { + String appBase = null; + Container container = this; + while (container != null) { + if (container instanceof Host) + break; + container = container.getParent(); + } + if (container != null) { + appBase = ((Host) container).getAppBase(); + } + return appBase; + } + + + /** + * Get config base. + */ + public File getConfigBase() { + File configBase = + new File(System.getProperty("catalina.base"), "conf"); + if (!configBase.exists()) { + return null; + } + Container container = this; + Container host = null; + Container engine = null; + while (container != null) { + if (container instanceof Host) + host = container; + if (container instanceof Engine) + engine = container; + container = container.getParent(); + } + if (engine != null) { + configBase = new File(configBase, engine.getName()); + } + if (host != null) { + configBase = new File(configBase, host.getName()); + } + if (saveConfig) { + configBase.mkdirs(); + } + return configBase; + } + + + /** + * Given a context path, get the config file name. + */ + protected String getDefaultConfigFile() { + String basename = null; + String path = getPath(); + if (path.equals("")) { + basename = "ROOT"; + } else { + basename = path.substring(1).replace('/', '#'); + } + return (basename + ".xml"); + } + + + /** + * Copy a file. + */ + private boolean copy(File src, File dest) { + FileInputStream is = null; + FileOutputStream os = null; + try { + is = new FileInputStream(src); + os = new FileOutputStream(dest); + byte[] buf = new byte[4096]; + while (true) { + int len = is.read(buf); + if (len < 0) + break; + os.write(buf, 0, len); + } + is.close(); + os.close(); + } catch (IOException e) { + return false; + } finally { + try { + if (is != null) { + is.close(); + } + } catch (Exception e) { + // Ignore + } + try { + if (os != null) { + os.close(); + } + } catch (Exception e) { + // Ignore + } + } + return true; + } + + + /** + * Get naming context full name. + */ + private String getNamingContextName() { + if (namingContextName == null) { + Container parent = getParent(); + if (parent == null) { + namingContextName = getName(); + } else { + Stack stk = new Stack(); + StringBuffer buff = new StringBuffer(); + while (parent != null) { + stk.push(parent.getName()); + parent = parent.getParent(); + } + while (!stk.empty()) { + buff.append("/" + stk.pop()); + } + buff.append(getName()); + namingContextName = buff.toString(); + } + } + return namingContextName; + } + + + /** + * Naming context listener accessor. + */ + public NamingContextListener getNamingContextListener() { + return namingContextListener; + } + + + /** + * Naming context listener setter. + */ + public void setNamingContextListener(NamingContextListener namingContextListener) { + this.namingContextListener = namingContextListener; + } + + + /** + * Return the request processing paused flag for this Context. + */ + public boolean getPaused() { + + return (this.paused); + + } + + + /** + * Post a copy of our web application resources as a servlet context + * attribute. + */ + private void postResources() { + + getServletContext().setAttribute + (Globals.RESOURCES_ATTR, getResources()); + + } + + + /** + * Post a copy of our current list of welcome files as a servlet context + * attribute, so that the default servlet can find them. + */ + private void postWelcomeFiles() { + + getServletContext().setAttribute("org.apache.catalina.WELCOME_FILES", + welcomeFiles); + + } + + public String getHostname() { + Container parentHost = getParent(); + if (parentHost != null) { + hostName = parentHost.getName(); + } + if ((hostName == null) || (hostName.length() < 1)) + hostName = "_"; + return hostName; + } + + /** + * Set the appropriate context attribute for our work directory. + */ + private void postWorkDirectory() { + + // Acquire (or calculate) the work directory path + String workDir = getWorkDir(); + if (workDir == null) { + + // Retrieve our parent (normally a host) name + String hostName = null; + String engineName = null; + String hostWorkDir = null; + Container parentHost = getParent(); + if (parentHost != null) { + hostName = parentHost.getName(); + if (parentHost instanceof StandardHost) { + hostWorkDir = ((StandardHost)parentHost).getWorkDir(); + } + Container parentEngine = parentHost.getParent(); + if (parentEngine != null) { + engineName = parentEngine.getName(); + } + } + if ((hostName == null) || (hostName.length() < 1)) + hostName = "_"; + if ((engineName == null) || (engineName.length() < 1)) + engineName = "_"; + + String temp = getPath(); + if (temp.startsWith("/")) + temp = temp.substring(1); + temp = temp.replace('/', '_'); + temp = temp.replace('\\', '_'); + if (temp.length() < 1) + temp = "_"; + if (hostWorkDir != null ) { + workDir = hostWorkDir + File.separator + temp; + } else { + workDir = "work" + File.separator + engineName + + File.separator + hostName + File.separator + temp; + } + setWorkDir(workDir); + } + + // Create this directory if necessary + File dir = new File(workDir); + if (!dir.isAbsolute()) { + File catalinaHome = engineBase(); + String catalinaHomePath = null; + try { + catalinaHomePath = catalinaHome.getCanonicalPath(); + dir = new File(catalinaHomePath, workDir); + } catch (IOException e) { + } + } + dir.mkdirs(); + + // Set the appropriate servlet context attribute + getServletContext().setAttribute(Globals.WORK_DIR_ATTR, dir); + if (getServletContext() instanceof ApplicationContext) + ((ApplicationContext) getServletContext()).setAttributeReadOnly + (Globals.WORK_DIR_ATTR); + + } + + + /** + * Set the request processing paused flag for this Context. + * + * @param paused The new request processing paused flag + */ + private void setPaused(boolean paused) { + + this.paused = paused; + + } + + + /** + * Validate the syntax of a proposed <url-pattern> + * for conformance with specification requirements. + * + * @param urlPattern URL pattern to be validated + */ + private boolean validateURLPattern(String urlPattern) { + + if (urlPattern == null) + return (false); + if (urlPattern.indexOf('\n') >= 0 || urlPattern.indexOf('\r') >= 0) { + getLogger().warn(sm.getString("standardContext.crlfinurl",urlPattern)); + } + if (urlPattern.startsWith("*.")) { + if (urlPattern.indexOf('/') < 0) + return (true); + else + return (false); + } + if ( (urlPattern.startsWith("/")) && + (urlPattern.indexOf("*.") < 0)) + return (true); + else + return (false); + + } + + + // ------------------------------------------------------------- Operations + + + /** + * JSR77 deploymentDescriptor attribute + * + * @return string deployment descriptor + */ + public String getDeploymentDescriptor() { + + InputStream stream = null; + ServletContext servletContext = getServletContext(); + if (servletContext != null) { + stream = servletContext.getResourceAsStream( + org.apache.catalina.startup.Constants.ApplicationWebXml); + } + if (stream == null) { + return ""; + } + BufferedReader br = new BufferedReader( + new InputStreamReader(stream)); + StringBuffer sb = new StringBuffer(); + String strRead = ""; + try { + while (strRead != null) { + sb.append(strRead); + strRead = br.readLine(); + } + } catch (IOException e) { + return ""; + } + + return sb.toString(); + + } + + + /** + * JSR77 servlets attribute + * + * @return list of all servlets ( we know about ) + */ + public String[] getServlets() { + + String[] result = null; + + Container[] children = findChildren(); + if (children != null) { + result = new String[children.length]; + for( int i=0; i< children.length; i++ ) { + result[i] = ((StandardWrapper)children[i]).getObjectName(); + } + } + + return result; + } + + + public ObjectName createObjectName(String hostDomain, ObjectName parentName) + throws MalformedObjectNameException + { + String onameStr; + StandardHost hst=(StandardHost)getParent(); + + String pathName=getName(); + String hostName=getParent().getName(); + String name= "//" + ((hostName==null)? "DEFAULT" : hostName) + + (("".equals(pathName))?"/":pathName ); + + String suffix=",J2EEApplication=" + + getJ2EEApplication() + ",J2EEServer=" + + getJ2EEServer(); + + onameStr="j2eeType=WebModule,name=" + name + suffix; + if( log.isDebugEnabled()) + log.debug("Registering " + onameStr + " for " + oname); + + // default case - no domain explictely set. + if( getDomain() == null ) domain=hst.getDomain(); + + ObjectName oname=new ObjectName(getDomain() + ":" + onameStr); + return oname; + } + + private void preRegisterJMX() { + try { + StandardHost host = (StandardHost) getParent(); + if ((oname == null) + || (oname.getKeyProperty("j2eeType") == null)) { + oname = createObjectName(host.getDomain(), host.getJmxName()); + controller = oname; + } + } catch(Exception ex) { + if(log.isInfoEnabled()) + log.info("Error registering ctx with jmx " + this + " " + + oname + " " + ex.toString(), ex ); + } + } + + private void registerJMX() { + try { + if (log.isDebugEnabled()) { + log.debug("Checking for " + oname ); + } + if(! Registry.getRegistry(null, null) + .getMBeanServer().isRegistered(oname)) { + controller = oname; + Registry.getRegistry(null, null) + .registerComponent(this, oname, null); + + // Send j2ee.object.created notification + if (this.getObjectName() != null) { + Notification notification = new Notification( + "j2ee.object.created", + this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + } + Container children[] = findChildren(); + for (int i=0; children!=null && i 0 ) { + hostName=path.substring(0, delim); + path = path.substring(delim); + if (path.equals("/")) { + this.setName(""); + } else { + this.setName(path); + } + } else { + if(log.isDebugEnabled()) + log.debug("Setting path " + path ); + this.setName( path ); + } + // XXX The service and domain should be the same. + String parentDomain=getEngineName(); + if( parentDomain == null ) parentDomain=domain; + ObjectName parentName=new ObjectName( parentDomain + ":" + + "type=Host,host=" + hostName); + return parentName; + } + + public void create() throws Exception{ + init(); + } + + /* Remove a JMX notficationListener + * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) + */ + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object object) throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener,filter,object); + + } + + private MBeanNotificationInfo[] notificationInfo; + + /* Get JMX Broadcaster Info + * @TODO use StringManager for international support! + * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! + * @see javax.management.NotificationBroadcaster#getNotificationInfo() + */ + public MBeanNotificationInfo[] getNotificationInfo() { + // FIXME: i18n + if(notificationInfo == null) { + notificationInfo = new MBeanNotificationInfo[]{ + new MBeanNotificationInfo(new String[] { + "j2ee.object.created"}, + Notification.class.getName(), + "web application is created" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.starting"}, + Notification.class.getName(), + "change web application is starting" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.running"}, + Notification.class.getName(), + "web application is running" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.stopped"}, + Notification.class.getName(), + "web application start to stopped" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.object.stopped"}, + Notification.class.getName(), + "web application is stopped" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.object.deleted"}, + Notification.class.getName(), + "web application is deleted" + ) + }; + + } + + return notificationInfo; + } + + + /* Add a JMX-NotificationListener + * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) + */ + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object object) throws IllegalArgumentException { + broadcaster.addNotificationListener(listener,filter,object); + + } + + + /** + * Remove a JMX-NotificationListener + * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) + */ + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + + } + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the naming resources associated with this web application. + */ + public javax.naming.directory.DirContext getStaticResources() { + + return getResources(); + + } + + + /** + * Return the naming resources associated with this web application. + * FIXME: Fooling introspection ... + */ + public javax.naming.directory.DirContext findStaticResources() { + + return getResources(); + + } + + + /** + * Return the naming resources associated with this web application. + */ + public String[] getWelcomeFiles() { + + return findWelcomeFiles(); + + } + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param webXmlValidation true to enable xml instance validation + */ + public void setXmlValidation(boolean webXmlValidation){ + + this.webXmlValidation = webXmlValidation; + + } + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getXmlValidation(){ + return webXmlValidation; + } + + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + */ + public boolean getXmlNamespaceAware(){ + return webXmlNamespaceAware; + } + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param webXmlNamespaceAware true to enable namespace awareness + */ + public void setXmlNamespaceAware(boolean webXmlNamespaceAware){ + this.webXmlNamespaceAware= webXmlNamespaceAware; + } + + + /** + * Set the validation feature of the XML parser used when + * parsing tlds files. + * @param tldValidation true to enable xml instance validation + */ + public void setTldValidation(boolean tldValidation){ + + this.tldValidation = tldValidation; + + } + + /** + * Get the server.xml attribute's webXmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getTldValidation(){ + return tldValidation; + } + + /** + * Sets the process TLDs attribute. + * + * @param newProcessTlds The new value + */ + public void setProcessTlds(boolean newProcessTlds) { + processTlds = newProcessTlds; + } + + /** + * Returns the processTlds attribute value. + */ + public boolean getProcessTlds() { + return processTlds; + } + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + */ + public boolean getTldNamespaceAware(){ + return tldNamespaceAware; + } + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param tldNamespaceAware true to enable namespace awareness + */ + public void setTldNamespaceAware(boolean tldNamespaceAware){ + this.tldNamespaceAware= tldNamespaceAware; + } + + + /** + * Support for "stateManageable" JSR77 + */ + public boolean isStateManageable() { + return true; + } + + public void startRecursive() throws LifecycleException { + // nothing to start recursive, the servlets will be started by load-on-startup + start(); + } + + public int getState() { + if( started ) { + return 1; // RUNNING + } + if( initialized ) { + return 0; // starting ? + } + if( ! available ) { + return 4; //FAILED + } + // 2 - STOPPING + return 3; // STOPPED + } + + /** + * The J2EE Server ObjectName this module is deployed on. + */ + private String server = null; + + /** + * The Java virtual machines on which this module is running. + */ + private String[] javaVMs = null; + + public String getServer() { + return server; + } + + public String setServer(String server) { + return this.server=server; + } + + public String[] getJavaVMs() { + return javaVMs; + } + + public String[] setJavaVMs(String[] javaVMs) { + return this.javaVMs = javaVMs; + } + + /** + * Gets the time this context was started. + * + * @return Time (in milliseconds since January 1, 1970, 00:00:00) when this + * context was started + */ + public long getStartTime() { + return startTime; + } + + public boolean isEventProvider() { + return false; + } + + public boolean isStatisticsProvider() { + return false; + } + +} diff --git a/java/org/apache/catalina/core/StandardContextValve.java b/java/org/apache/catalina/core/StandardContextValve.java index 2466d6aa5..a86ef492e 100644 --- a/java/org/apache/catalina/core/StandardContextValve.java +++ b/java/org/apache/catalina/core/StandardContextValve.java @@ -1,270 +1,270 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestEvent; -import javax.servlet.ServletRequestListener; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Container; -import org.apache.catalina.Globals; -import org.apache.catalina.Wrapper; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.buf.MessageBytes; - -/** - * Valve that implements the default basic behavior for the - * StandardContext container implementation. - *

    - * USAGE CONSTRAINT: This implementation is likely to be useful only - * when processing HTTP requests. - * - * @author Craig R. McClanahan - * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ - */ - -final class StandardContextValve - extends ValveBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardContextValve/1.0"; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - private static Log log = LogFactory.getLog(StandardContextValve.class); - - - private StandardContext context = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Cast to a StandardContext right away, as it will be needed later. - * - * @see org.apache.catalina.Contained#setContainer(org.apache.catalina.Container) - */ - public void setContainer(Container container) { - super.setContainer(container); - context = (StandardContext) container; - } - - - /** - * Select the appropriate child Wrapper to process this request, - * based on the specified request URI. If no matching Wrapper can - * be found, return an appropriate HTTP error. - * - * @param request Request to be processed - * @param response Response to be produced - * @param valveContext Valve context used to forward to the next Valve - * - * @exception IOException if an input/output error occurred - * @exception ServletException if a servlet error occurred - */ - public final void invoke(Request request, Response response) - throws IOException, ServletException { - - // Disallow any direct access to resources under WEB-INF or META-INF - MessageBytes requestPathMB = request.getRequestPathMB(); - if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) - || (requestPathMB.equalsIgnoreCase("/META-INF")) - || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) - || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { - String requestURI = request.getDecodedRequestURI(); - notFound(requestURI, response); - return; - } - - // Wait if we are reloading - while (context.getPaused()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - ; - } - } - - // Select the Wrapper to be used for this Request - Wrapper wrapper = request.getWrapper(); - if (wrapper == null) { - String requestURI = request.getDecodedRequestURI(); - notFound(requestURI, response); - return; - } - - // Normal request processing - Object instances[] = context.getApplicationEventListeners(); - - ServletRequestEvent event = null; - - if ((instances != null) - && (instances.length > 0)) { - event = new ServletRequestEvent - (((StandardContext) container).getServletContext(), - request.getRequest()); - // create pre-service event - for (int i = 0; i < instances.length; i++) { - if (instances[i] == null) - continue; - if (!(instances[i] instanceof ServletRequestListener)) - continue; - ServletRequestListener listener = - (ServletRequestListener) instances[i]; - try { - listener.requestInitialized(event); - } catch (Throwable t) { - container.getLogger().error(sm.getString("requestListenerValve.requestInit", - instances[i].getClass().getName()), t); - ServletRequest sreq = request.getRequest(); - sreq.setAttribute(Globals.EXCEPTION_ATTR,t); - return; - } - } - } - - wrapper.getPipeline().getFirst().invoke(request, response); - - if ((instances !=null ) && - (instances.length > 0)) { - // create post-service event - for (int i = 0; i < instances.length; i++) { - if (instances[i] == null) - continue; - if (!(instances[i] instanceof ServletRequestListener)) - continue; - ServletRequestListener listener = - (ServletRequestListener) instances[i]; - try { - listener.requestDestroyed(event); - } catch (Throwable t) { - container.getLogger().error(sm.getString("requestListenerValve.requestDestroy", - instances[i].getClass().getName()), t); - ServletRequest sreq = request.getRequest(); - sreq.setAttribute(Globals.EXCEPTION_ATTR,t); - } - } - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Report a "bad request" error for the specified resource. FIXME: We - * should really be using the error reporting settings for this web - * application, but currently that code runs at the wrapper level rather - * than the context level. - * - * @param requestURI The request URI for the requested resource - * @param response The response we are creating - */ - private void badRequest(String requestURI, HttpServletResponse response) { - - try { - response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI); - } catch (IllegalStateException e) { - ; - } catch (IOException e) { - ; - } - - } - - - /** - * Report a "forbidden" error for the specified resource. - * - * @param requestURI The request URI for the requested resource - * @param response The response we are creating - */ - private void forbidden(String requestURI, HttpServletResponse response) { - - try { - response.sendError(HttpServletResponse.SC_FORBIDDEN, requestURI); - } catch (IllegalStateException e) { - ; - } catch (IOException e) { - ; - } - - } - - - /** - * Report a "not found" error for the specified resource. FIXME: We - * should really be using the error reporting settings for this web - * application, but currently that code runs at the wrapper level rather - * than the context level. - * - * @param requestURI The request URI for the requested resource - * @param response The response we are creating - */ - private void notFound(String requestURI, HttpServletResponse response) { - - try { - response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI); - } catch (IllegalStateException e) { - ; - } catch (IOException e) { - ; - } - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletRequestEvent; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Container; +import org.apache.catalina.Globals; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * Valve that implements the default basic behavior for the + * StandardContext container implementation. + *

    + * USAGE CONSTRAINT: This implementation is likely to be useful only + * when processing HTTP requests. + * + * @author Craig R. McClanahan + * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ + */ + +final class StandardContextValve + extends ValveBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardContextValve/1.0"; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + private static Log log = LogFactory.getLog(StandardContextValve.class); + + + private StandardContext context = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Cast to a StandardContext right away, as it will be needed later. + * + * @see org.apache.catalina.Contained#setContainer(org.apache.catalina.Container) + */ + public void setContainer(Container container) { + super.setContainer(container); + context = (StandardContext) container; + } + + + /** + * Select the appropriate child Wrapper to process this request, + * based on the specified request URI. If no matching Wrapper can + * be found, return an appropriate HTTP error. + * + * @param request Request to be processed + * @param response Response to be produced + * @param valveContext Valve context used to forward to the next Valve + * + * @exception IOException if an input/output error occurred + * @exception ServletException if a servlet error occurred + */ + public final void invoke(Request request, Response response) + throws IOException, ServletException { + + // Disallow any direct access to resources under WEB-INF or META-INF + MessageBytes requestPathMB = request.getRequestPathMB(); + if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) + || (requestPathMB.equalsIgnoreCase("/META-INF")) + || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) + || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { + String requestURI = request.getDecodedRequestURI(); + notFound(requestURI, response); + return; + } + + // Wait if we are reloading + while (context.getPaused()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + ; + } + } + + // Select the Wrapper to be used for this Request + Wrapper wrapper = request.getWrapper(); + if (wrapper == null) { + String requestURI = request.getDecodedRequestURI(); + notFound(requestURI, response); + return; + } + + // Normal request processing + Object instances[] = context.getApplicationEventListeners(); + + ServletRequestEvent event = null; + + if ((instances != null) + && (instances.length > 0)) { + event = new ServletRequestEvent + (((StandardContext) container).getServletContext(), + request.getRequest()); + // create pre-service event + for (int i = 0; i < instances.length; i++) { + if (instances[i] == null) + continue; + if (!(instances[i] instanceof ServletRequestListener)) + continue; + ServletRequestListener listener = + (ServletRequestListener) instances[i]; + try { + listener.requestInitialized(event); + } catch (Throwable t) { + container.getLogger().error(sm.getString("requestListenerValve.requestInit", + instances[i].getClass().getName()), t); + ServletRequest sreq = request.getRequest(); + sreq.setAttribute(Globals.EXCEPTION_ATTR,t); + return; + } + } + } + + wrapper.getPipeline().getFirst().invoke(request, response); + + if ((instances !=null ) && + (instances.length > 0)) { + // create post-service event + for (int i = 0; i < instances.length; i++) { + if (instances[i] == null) + continue; + if (!(instances[i] instanceof ServletRequestListener)) + continue; + ServletRequestListener listener = + (ServletRequestListener) instances[i]; + try { + listener.requestDestroyed(event); + } catch (Throwable t) { + container.getLogger().error(sm.getString("requestListenerValve.requestDestroy", + instances[i].getClass().getName()), t); + ServletRequest sreq = request.getRequest(); + sreq.setAttribute(Globals.EXCEPTION_ATTR,t); + } + } + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Report a "bad request" error for the specified resource. FIXME: We + * should really be using the error reporting settings for this web + * application, but currently that code runs at the wrapper level rather + * than the context level. + * + * @param requestURI The request URI for the requested resource + * @param response The response we are creating + */ + private void badRequest(String requestURI, HttpServletResponse response) { + + try { + response.sendError(HttpServletResponse.SC_BAD_REQUEST, requestURI); + } catch (IllegalStateException e) { + ; + } catch (IOException e) { + ; + } + + } + + + /** + * Report a "forbidden" error for the specified resource. + * + * @param requestURI The request URI for the requested resource + * @param response The response we are creating + */ + private void forbidden(String requestURI, HttpServletResponse response) { + + try { + response.sendError(HttpServletResponse.SC_FORBIDDEN, requestURI); + } catch (IllegalStateException e) { + ; + } catch (IOException e) { + ; + } + + } + + + /** + * Report a "not found" error for the specified resource. FIXME: We + * should really be using the error reporting settings for this web + * application, but currently that code runs at the wrapper level rather + * than the context level. + * + * @param requestURI The request URI for the requested resource + * @param response The response we are creating + */ + private void notFound(String requestURI, HttpServletResponse response) { + + try { + response.sendError(HttpServletResponse.SC_NOT_FOUND, requestURI); + } catch (IllegalStateException e) { + ; + } catch (IOException e) { + ; + } + + } + + +} diff --git a/java/org/apache/catalina/core/StandardEngine.java b/java/org/apache/catalina/core/StandardEngine.java index 98cace689..a85a6e9be 100644 --- a/java/org/apache/catalina/core/StandardEngine.java +++ b/java/org/apache/catalina/core/StandardEngine.java @@ -1,537 +1,537 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.File; -import java.util.List; - -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.apache.catalina.Container; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Realm; -import org.apache.catalina.Service; -import org.apache.catalina.realm.JAASRealm; -import org.apache.catalina.util.ServerInfo; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.modeler.modules.MbeansSource; - -/** - * Standard implementation of the Engine interface. Each - * child container must be a Host implementation to process the specific - * fully qualified host name of that virtual host.
    - * You can set the jvmRoute direct or with the System.property jvmRoute. - * - * @author Craig R. McClanahan - * @version $Revision: 303667 $ $Date: 2005-01-29 20:41:16 +0100 (sam., 29 janv. 2005) $ - */ - -public class StandardEngine - extends ContainerBase - implements Engine { - - private static Log log = LogFactory.getLog(StandardEngine.class); - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new StandardEngine component with the default basic Valve. - */ - public StandardEngine() { - - super(); - pipeline.setBasic(new StandardEngineValve()); - /* Set the jmvRoute using the system property jvmRoute */ - try { - setJvmRoute(System.getProperty("jvmRoute")); - } catch(Exception ex) { - } - // By default, the engine will hold the reloading thread - backgroundProcessorDelay = 10; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Host name to use when no server host, or an unknown host, - * is specified in the request. - */ - private String defaultHost = null; - - - /** - * The descriptive information string for this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardEngine/1.0"; - - - /** - * The Service that owns this Engine, if any. - */ - private Service service = null; - - /** Allow the base dir to be specified explicitely for - * each engine. In time we should stop using catalina.base property - - * otherwise we loose some flexibility. - */ - private String baseDir = null; - - /** Optional mbeans config file. This will replace the "hacks" in - * jk and ServerListener. The mbeans file will support (transparent) - * persistence - soon. It'll probably replace jk2.properties and could - * replace server.xml. Of course - the same beans could be loaded and - * managed by an external entity - like the embedding app - which - * can use a different persistence mechanism. - */ - private String mbeansFile = null; - - /** Mbeans loaded by the engine. - */ - private List mbeans; - - - /** - * The JVM Route ID for this Tomcat instance. All Route ID's must be unique - * across the cluster. - */ - private String jvmRouteId; - - - // ------------------------------------------------------------- Properties - - /** Provide a default in case no explicit configuration is set - * - * @return configured realm, or a JAAS realm by default - */ - public Realm getRealm() { - Realm configured=super.getRealm(); - // If no set realm has been called - default to JAAS - // This can be overriden at engine, context and host level - if( configured==null ) { - configured=new JAASRealm(); - this.setRealm( configured ); - } - return configured; - } - - - /** - * Return the default host. - */ - public String getDefaultHost() { - - return (defaultHost); - - } - - - /** - * Set the default host. - * - * @param host The new default host - */ - public void setDefaultHost(String host) { - - String oldDefaultHost = this.defaultHost; - if (host == null) { - this.defaultHost = null; - } else { - this.defaultHost = host.toLowerCase(); - } - support.firePropertyChange("defaultHost", oldDefaultHost, - this.defaultHost); - - } - - public void setName(String name ) { - if( domain != null ) { - // keep name==domain, ignore override - // we are already registered - super.setName( domain ); - return; - } - // The engine name is used as domain - domain=name; // XXX should we set it in init() ? It shouldn't matter - super.setName( name ); - } - - - /** - * Set the cluster-wide unique identifier for this Engine. - * This value is only useful in a load-balancing scenario. - *

    - * This property should not be changed once it is set. - */ - public void setJvmRoute(String routeId) { - jvmRouteId = routeId; - } - - - /** - * Retrieve the cluster-wide unique identifier for this Engine. - * This value is only useful in a load-balancing scenario. - */ - public String getJvmRoute() { - return jvmRouteId; - } - - - /** - * Return the Service with which we are associated (if any). - */ - public Service getService() { - - return (this.service); - - } - - - /** - * Set the Service with which we are associated (if any). - * - * @param service The service that owns this Engine - */ - public void setService(Service service) { - this.service = service; - } - - public String getMbeansFile() { - return mbeansFile; - } - - public void setMbeansFile(String mbeansFile) { - this.mbeansFile = mbeansFile; - } - - public String getBaseDir() { - if( baseDir==null ) { - baseDir=System.getProperty("catalina.base"); - } - if( baseDir==null ) { - baseDir=System.getProperty("catalina.home"); - } - return baseDir; - } - - public void setBaseDir(String baseDir) { - this.baseDir = baseDir; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Add a child Container, only if the proposed child is an implementation - * of Host. - * - * @param child Child container to be added - */ - public void addChild(Container child) { - - if (!(child instanceof Host)) - throw new IllegalArgumentException - (sm.getString("standardEngine.notHost")); - super.addChild(child); - - } - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - /** - * Disallow any attempt to set a parent for this Container, since an - * Engine is supposed to be at the top of the Container hierarchy. - * - * @param container Proposed parent Container - */ - public void setParent(Container container) { - - throw new IllegalArgumentException - (sm.getString("standardEngine.notParent")); - - } - - - private boolean initialized=false; - - public void init() { - if( initialized ) return; - initialized=true; - - if( oname==null ) { - // not registered in JMX yet - standalone mode - try { - if (domain==null) { - domain=getName(); - } - if(log.isDebugEnabled()) - log.debug( "Register " + domain ); - oname=new ObjectName(domain + ":type=Engine"); - controller=oname; - Registry.getRegistry(null, null) - .registerComponent(this, oname, null); - } catch( Throwable t ) { - log.info("Error registering ", t ); - } - } - - if( mbeansFile == null ) { - String defaultMBeansFile=getBaseDir() + "/conf/tomcat5-mbeans.xml"; - File f=new File( defaultMBeansFile ); - if( f.exists() ) mbeansFile=f.getAbsolutePath(); - } - if( mbeansFile != null ) { - readEngineMbeans(); - } - if( mbeans != null ) { - try { - Registry.getRegistry(null, null).invoke(mbeans, "init", false); - } catch (Exception e) { - log.error("Error in init() for " + mbeansFile, e); - } - } - - // not needed since the following if statement does the same thing the right way - // remove later after checking - //if( service==null ) { - // try { - // ObjectName serviceName=getParentName(); - // if( mserver.isRegistered( serviceName )) { - // log.info("Registering with the service "); - // try { - // mserver.invoke( serviceName, "setContainer", - // new Object[] { this }, - // new String[] { "org.apache.catalina.Container" } ); - // } catch( Exception ex ) { - // ex.printStackTrace(); - // } - // } - // } catch( Exception ex ) { - // log.error("Error registering with service "); - // } - //} - - if( service==null ) { - // for consistency...: we are probably in embeded mode - try { - service=new StandardService(); - service.setContainer( this ); - service.initialize(); - } catch( Throwable t ) { - log.error(t); - } - } - - } - - public void destroy() throws LifecycleException { - if( ! initialized ) return; - initialized=false; - - // if we created it, make sure it's also destroyed - // this call implizit this.stop() - ((StandardService)service).destroy(); - - if( mbeans != null ) { - try { - Registry.getRegistry(null, null) - .invoke(mbeans, "destroy", false); - } catch (Exception e) { - log.error(sm.getString("standardEngine.unregister.mbeans.failed" ,mbeansFile), e); - } - } - // - if( mbeans != null ) { - try { - for( int i=0; iEngine interface. Each + * child container must be a Host implementation to process the specific + * fully qualified host name of that virtual host.
    + * You can set the jvmRoute direct or with the System.property jvmRoute. + * + * @author Craig R. McClanahan + * @version $Revision: 303667 $ $Date: 2005-01-29 20:41:16 +0100 (sam., 29 janv. 2005) $ + */ + +public class StandardEngine + extends ContainerBase + implements Engine { + + private static Log log = LogFactory.getLog(StandardEngine.class); + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new StandardEngine component with the default basic Valve. + */ + public StandardEngine() { + + super(); + pipeline.setBasic(new StandardEngineValve()); + /* Set the jmvRoute using the system property jvmRoute */ + try { + setJvmRoute(System.getProperty("jvmRoute")); + } catch(Exception ex) { + } + // By default, the engine will hold the reloading thread + backgroundProcessorDelay = 10; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Host name to use when no server host, or an unknown host, + * is specified in the request. + */ + private String defaultHost = null; + + + /** + * The descriptive information string for this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardEngine/1.0"; + + + /** + * The Service that owns this Engine, if any. + */ + private Service service = null; + + /** Allow the base dir to be specified explicitely for + * each engine. In time we should stop using catalina.base property - + * otherwise we loose some flexibility. + */ + private String baseDir = null; + + /** Optional mbeans config file. This will replace the "hacks" in + * jk and ServerListener. The mbeans file will support (transparent) + * persistence - soon. It'll probably replace jk2.properties and could + * replace server.xml. Of course - the same beans could be loaded and + * managed by an external entity - like the embedding app - which + * can use a different persistence mechanism. + */ + private String mbeansFile = null; + + /** Mbeans loaded by the engine. + */ + private List mbeans; + + + /** + * The JVM Route ID for this Tomcat instance. All Route ID's must be unique + * across the cluster. + */ + private String jvmRouteId; + + + // ------------------------------------------------------------- Properties + + /** Provide a default in case no explicit configuration is set + * + * @return configured realm, or a JAAS realm by default + */ + public Realm getRealm() { + Realm configured=super.getRealm(); + // If no set realm has been called - default to JAAS + // This can be overriden at engine, context and host level + if( configured==null ) { + configured=new JAASRealm(); + this.setRealm( configured ); + } + return configured; + } + + + /** + * Return the default host. + */ + public String getDefaultHost() { + + return (defaultHost); + + } + + + /** + * Set the default host. + * + * @param host The new default host + */ + public void setDefaultHost(String host) { + + String oldDefaultHost = this.defaultHost; + if (host == null) { + this.defaultHost = null; + } else { + this.defaultHost = host.toLowerCase(); + } + support.firePropertyChange("defaultHost", oldDefaultHost, + this.defaultHost); + + } + + public void setName(String name ) { + if( domain != null ) { + // keep name==domain, ignore override + // we are already registered + super.setName( domain ); + return; + } + // The engine name is used as domain + domain=name; // XXX should we set it in init() ? It shouldn't matter + super.setName( name ); + } + + + /** + * Set the cluster-wide unique identifier for this Engine. + * This value is only useful in a load-balancing scenario. + *

    + * This property should not be changed once it is set. + */ + public void setJvmRoute(String routeId) { + jvmRouteId = routeId; + } + + + /** + * Retrieve the cluster-wide unique identifier for this Engine. + * This value is only useful in a load-balancing scenario. + */ + public String getJvmRoute() { + return jvmRouteId; + } + + + /** + * Return the Service with which we are associated (if any). + */ + public Service getService() { + + return (this.service); + + } + + + /** + * Set the Service with which we are associated (if any). + * + * @param service The service that owns this Engine + */ + public void setService(Service service) { + this.service = service; + } + + public String getMbeansFile() { + return mbeansFile; + } + + public void setMbeansFile(String mbeansFile) { + this.mbeansFile = mbeansFile; + } + + public String getBaseDir() { + if( baseDir==null ) { + baseDir=System.getProperty("catalina.base"); + } + if( baseDir==null ) { + baseDir=System.getProperty("catalina.home"); + } + return baseDir; + } + + public void setBaseDir(String baseDir) { + this.baseDir = baseDir; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Add a child Container, only if the proposed child is an implementation + * of Host. + * + * @param child Child container to be added + */ + public void addChild(Container child) { + + if (!(child instanceof Host)) + throw new IllegalArgumentException + (sm.getString("standardEngine.notHost")); + super.addChild(child); + + } + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + /** + * Disallow any attempt to set a parent for this Container, since an + * Engine is supposed to be at the top of the Container hierarchy. + * + * @param container Proposed parent Container + */ + public void setParent(Container container) { + + throw new IllegalArgumentException + (sm.getString("standardEngine.notParent")); + + } + + + private boolean initialized=false; + + public void init() { + if( initialized ) return; + initialized=true; + + if( oname==null ) { + // not registered in JMX yet - standalone mode + try { + if (domain==null) { + domain=getName(); + } + if(log.isDebugEnabled()) + log.debug( "Register " + domain ); + oname=new ObjectName(domain + ":type=Engine"); + controller=oname; + Registry.getRegistry(null, null) + .registerComponent(this, oname, null); + } catch( Throwable t ) { + log.info("Error registering ", t ); + } + } + + if( mbeansFile == null ) { + String defaultMBeansFile=getBaseDir() + "/conf/tomcat5-mbeans.xml"; + File f=new File( defaultMBeansFile ); + if( f.exists() ) mbeansFile=f.getAbsolutePath(); + } + if( mbeansFile != null ) { + readEngineMbeans(); + } + if( mbeans != null ) { + try { + Registry.getRegistry(null, null).invoke(mbeans, "init", false); + } catch (Exception e) { + log.error("Error in init() for " + mbeansFile, e); + } + } + + // not needed since the following if statement does the same thing the right way + // remove later after checking + //if( service==null ) { + // try { + // ObjectName serviceName=getParentName(); + // if( mserver.isRegistered( serviceName )) { + // log.info("Registering with the service "); + // try { + // mserver.invoke( serviceName, "setContainer", + // new Object[] { this }, + // new String[] { "org.apache.catalina.Container" } ); + // } catch( Exception ex ) { + // ex.printStackTrace(); + // } + // } + // } catch( Exception ex ) { + // log.error("Error registering with service "); + // } + //} + + if( service==null ) { + // for consistency...: we are probably in embeded mode + try { + service=new StandardService(); + service.setContainer( this ); + service.initialize(); + } catch( Throwable t ) { + log.error(t); + } + } + + } + + public void destroy() throws LifecycleException { + if( ! initialized ) return; + initialized=false; + + // if we created it, make sure it's also destroyed + // this call implizit this.stop() + ((StandardService)service).destroy(); + + if( mbeans != null ) { + try { + Registry.getRegistry(null, null) + .invoke(mbeans, "destroy", false); + } catch (Exception e) { + log.error(sm.getString("standardEngine.unregister.mbeans.failed" ,mbeansFile), e); + } + } + // + if( mbeans != null ) { + try { + for( int i=0; iStandardEngine container implementation. - *

    - * USAGE CONSTRAINT: This implementation is likely to be useful only - * when processing HTTP requests. - * - * @author Craig R. McClanahan - * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ - */ - -final class StandardEngineValve - extends ValveBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardEngineValve/1.0"; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Select the appropriate child Host to process this request, - * based on the requested server name. If no matching Host can - * be found, return an appropriate HTTP error. - * - * @param request Request to be processed - * @param response Response to be produced - * @param valveContext Valve context used to forward to the next Valve - * - * @exception IOException if an input/output error occurred - * @exception ServletException if a servlet error occurred - */ - public final void invoke(Request request, Response response) - throws IOException, ServletException { - - // Select the Host to be used for this Request - Host host = request.getHost(); - if (host == null) { - response.sendError - (HttpServletResponse.SC_BAD_REQUEST, - sm.getString("standardEngine.noHost", - request.getServerName())); - return; - } - - // Ask this Host to process this request - host.getPipeline().getFirst().invoke(request, response); - - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Host; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; + + +/** + * Valve that implements the default basic behavior for the + * StandardEngine container implementation. + *

    + * USAGE CONSTRAINT: This implementation is likely to be useful only + * when processing HTTP requests. + * + * @author Craig R. McClanahan + * @version $Revision: 302978 $ $Date: 2004-06-23 18:59:42 +0200 (mer., 23 juin 2004) $ + */ + +final class StandardEngineValve + extends ValveBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardEngineValve/1.0"; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Select the appropriate child Host to process this request, + * based on the requested server name. If no matching Host can + * be found, return an appropriate HTTP error. + * + * @param request Request to be processed + * @param response Response to be produced + * @param valveContext Valve context used to forward to the next Valve + * + * @exception IOException if an input/output error occurred + * @exception ServletException if a servlet error occurred + */ + public final void invoke(Request request, Response response) + throws IOException, ServletException { + + // Select the Host to be used for this Request + Host host = request.getHost(); + if (host == null) { + response.sendError + (HttpServletResponse.SC_BAD_REQUEST, + sm.getString("standardEngine.noHost", + request.getServerName())); + return; + } + + // Ask this Host to process this request + host.getPipeline().getFirst().invoke(request, response); + + } + +} diff --git a/java/org/apache/catalina/core/StandardHost.java b/java/org/apache/catalina/core/StandardHost.java index 5b9d8e359..c7f4daf2c 100644 --- a/java/org/apache/catalina/core/StandardHost.java +++ b/java/org/apache/catalina/core/StandardHost.java @@ -1,822 +1,822 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Host; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Valve; -import org.apache.catalina.startup.HostConfig; -import org.apache.catalina.valves.ValveBase; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Standard implementation of the Host interface. Each - * child container must be a Context implementation to process the - * requests directed to a particular web application. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303666 $ $Date: 2005-01-29 20:38:37 +0100 (sam., 29 janv. 2005) $ - */ - -public class StandardHost - extends ContainerBase - implements Host - { - /* Why do we implement deployer and delegate to deployer ??? */ - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( StandardHost.class ); - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new StandardHost component with the default basic Valve. - */ - public StandardHost() { - - super(); - pipeline.setBasic(new StandardHostValve()); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of aliases for this Host. - */ - private String[] aliases = new String[0]; - - - /** - * The application root for this Host. - */ - private String appBase = "."; - - - /** - * The auto deploy flag for this Host. - */ - private boolean autoDeploy = true; - - - /** - * The Java class name of the default context configuration class - * for deployed web applications. - */ - private String configClass = - "org.apache.catalina.startup.ContextConfig"; - - - /** - * The Java class name of the default Context implementation class for - * deployed web applications. - */ - private String contextClass = - "org.apache.catalina.core.StandardContext"; - - - /** - * The deploy on startup flag for this Host. - */ - private boolean deployOnStartup = true; - - - /** - * deploy Context XML config files property. - */ - private boolean deployXML = true; - - - /** - * The Java class name of the default error reporter implementation class - * for deployed web applications. - */ - private String errorReportValveClass = - "org.apache.catalina.valves.ErrorReportValve"; - - /** - * The object name for the errorReportValve. - */ - private ObjectName errorReportValveObjectName = null; - - /** - * The descriptive information string for this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardHost/1.0"; - - - /** - * The live deploy flag for this Host. - */ - private boolean liveDeploy = true; - - - /** - * Unpack WARs property. - */ - private boolean unpackWARs = true; - - - /** - * Work Directory base for applications. - */ - private String workDir = null; - - - /** - * Attribute value used to turn on/off XML validation - */ - private boolean xmlValidation = false; - - - /** - * Attribute value used to turn on/off XML namespace awarenes. - */ - private boolean xmlNamespaceAware = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the application root for this Host. This can be an absolute - * pathname, a relative pathname, or a URL. - */ - public String getAppBase() { - - return (this.appBase); - - } - - - /** - * Set the application root for this Host. This can be an absolute - * pathname, a relative pathname, or a URL. - * - * @param appBase The new application root - */ - public void setAppBase(String appBase) { - - String oldAppBase = this.appBase; - this.appBase = appBase; - support.firePropertyChange("appBase", oldAppBase, this.appBase); - - } - - - /** - * Return the value of the auto deploy flag. If true, it indicates that - * this host's child webapps will be dynamically deployed. - */ - public boolean getAutoDeploy() { - - return (this.autoDeploy); - - } - - - /** - * Set the auto deploy flag value for this host. - * - * @param autoDeploy The new auto deploy flag - */ - public void setAutoDeploy(boolean autoDeploy) { - - boolean oldAutoDeploy = this.autoDeploy; - this.autoDeploy = autoDeploy; - support.firePropertyChange("autoDeploy", oldAutoDeploy, - this.autoDeploy); - - } - - - /** - * Return the Java class name of the context configuration class - * for new web applications. - */ - public String getConfigClass() { - - return (this.configClass); - - } - - - /** - * Set the Java class name of the context configuration class - * for new web applications. - * - * @param configClass The new context configuration class - */ - public void setConfigClass(String configClass) { - - String oldConfigClass = this.configClass; - this.configClass = configClass; - support.firePropertyChange("configClass", - oldConfigClass, this.configClass); - - } - - - /** - * Return the Java class name of the Context implementation class - * for new web applications. - */ - public String getContextClass() { - - return (this.contextClass); - - } - - - /** - * Set the Java class name of the Context implementation class - * for new web applications. - * - * @param contextClass The new context implementation class - */ - public void setContextClass(String contextClass) { - - String oldContextClass = this.contextClass; - this.contextClass = contextClass; - support.firePropertyChange("contextClass", - oldContextClass, this.contextClass); - - } - - - /** - * Return the value of the deploy on startup flag. If true, it indicates - * that this host's child webapps should be discovred and automatically - * deployed at startup time. - */ - public boolean getDeployOnStartup() { - - return (this.deployOnStartup); - - } - - - /** - * Set the deploy on startup flag value for this host. - * - * @param deployOnStartup The new deploy on startup flag - */ - public void setDeployOnStartup(boolean deployOnStartup) { - - boolean oldDeployOnStartup = this.deployOnStartup; - this.deployOnStartup = deployOnStartup; - support.firePropertyChange("deployOnStartup", oldDeployOnStartup, - this.deployOnStartup); - - } - - - /** - * Deploy XML Context config files flag accessor. - */ - public boolean isDeployXML() { - - return (deployXML); - - } - - - /** - * Deploy XML Context config files flag mutator. - */ - public void setDeployXML(boolean deployXML) { - - this.deployXML = deployXML; - - } - - - /** - * Return the value of the live deploy flag. If true, it indicates that - * a background thread should be started that looks for web application - * context files, WAR files, or unpacked directories being dropped in to - * the appBase directory, and deploys new ones as they are - * encountered. - */ - public boolean getLiveDeploy() { - return (this.autoDeploy); - } - - - /** - * Set the live deploy flag value for this host. - * - * @param liveDeploy The new live deploy flag - */ - public void setLiveDeploy(boolean liveDeploy) { - setAutoDeploy(liveDeploy); - } - - - /** - * Return the Java class name of the error report valve class - * for new web applications. - */ - public String getErrorReportValveClass() { - - return (this.errorReportValveClass); - - } - - - /** - * Set the Java class name of the error report valve class - * for new web applications. - * - * @param errorReportValveClass The new error report valve class - */ - public void setErrorReportValveClass(String errorReportValveClass) { - - String oldErrorReportValveClassClass = this.errorReportValveClass; - this.errorReportValveClass = errorReportValveClass; - support.firePropertyChange("errorReportValveClass", - oldErrorReportValveClassClass, - this.errorReportValveClass); - - } - - - /** - * Return the canonical, fully qualified, name of the virtual host - * this Container represents. - */ - public String getName() { - - return (name); - - } - - - /** - * Set the canonical, fully qualified, name of the virtual host - * this Container represents. - * - * @param name Virtual host name - * - * @exception IllegalArgumentException if name is null - */ - public void setName(String name) { - - if (name == null) - throw new IllegalArgumentException - (sm.getString("standardHost.nullName")); - - name = name.toLowerCase(); // Internally all names are lower case - - String oldName = this.name; - this.name = name; - support.firePropertyChange("name", oldName, this.name); - - } - - - /** - * Unpack WARs flag accessor. - */ - public boolean isUnpackWARs() { - - return (unpackWARs); - - } - - - /** - * Unpack WARs flag mutator. - */ - public void setUnpackWARs(boolean unpackWARs) { - - this.unpackWARs = unpackWARs; - - } - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param xmlValidation true to enable xml instance validation - */ - public void setXmlValidation(boolean xmlValidation){ - - this.xmlValidation = xmlValidation; - - } - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getXmlValidation(){ - return xmlValidation; - } - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - * - */ - public boolean getXmlNamespaceAware(){ - return xmlNamespaceAware; - } - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param xmlNamespaceAware true to enable namespace awareness - */ - public void setXmlNamespaceAware(boolean xmlNamespaceAware){ - this.xmlNamespaceAware=xmlNamespaceAware; - } - - /** - * Host work directory base. - */ - public String getWorkDir() { - - return (workDir); - } - - - /** - * Host work directory base. - */ - public void setWorkDir(String workDir) { - - this.workDir = workDir; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an alias name that should be mapped to this same Host. - * - * @param alias The alias to be added - */ - public void addAlias(String alias) { - - alias = alias.toLowerCase(); - - // Skip duplicate aliases - for (int i = 0; i < aliases.length; i++) { - if (aliases[i].equals(alias)) - return; - } - - // Add this alias to the list - String newAliases[] = new String[aliases.length + 1]; - for (int i = 0; i < aliases.length; i++) - newAliases[i] = aliases[i]; - newAliases[aliases.length] = alias; - - aliases = newAliases; - - // Inform interested listeners - fireContainerEvent(ADD_ALIAS_EVENT, alias); - - } - - - /** - * Add a child Container, only if the proposed child is an implementation - * of Context. - * - * @param child Child container to be added - */ - public void addChild(Container child) { - - if (!(child instanceof Context)) - throw new IllegalArgumentException - (sm.getString("standardHost.notContext")); - super.addChild(child); - - } - - - /** - * Return the set of alias names for this Host. If none are defined, - * a zero length array is returned. - */ - public String[] findAliases() { - - return (this.aliases); - - } - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the Context that would be used to process the specified - * host-relative request URI, if any; otherwise return null. - * - * @param uri Request URI to be mapped - */ - public Context map(String uri) { - - if (log.isDebugEnabled()) - log.debug("Mapping request URI '" + uri + "'"); - if (uri == null) - return (null); - - // Match on the longest possible context path prefix - if (log.isTraceEnabled()) - log.trace(" Trying the longest context path prefix"); - Context context = null; - String mapuri = uri; - while (true) { - context = (Context) findChild(mapuri); - if (context != null) - break; - int slash = mapuri.lastIndexOf('/'); - if (slash < 0) - break; - mapuri = mapuri.substring(0, slash); - } - - // If no Context matches, select the default Context - if (context == null) { - if (log.isTraceEnabled()) - log.trace(" Trying the default context"); - context = (Context) findChild(""); - } - - // Complain if no Context has been selected - if (context == null) { - log.error(sm.getString("standardHost.mappingError", uri)); - return (null); - } - - // Return the mapped Context (if any) - if (log.isDebugEnabled()) - log.debug(" Mapped to context '" + context.getPath() + "'"); - return (context); - - } - - - /** - * Remove the specified alias name from the aliases for this Host. - * - * @param alias Alias name to be removed - */ - public void removeAlias(String alias) { - - alias = alias.toLowerCase(); - - synchronized (aliases) { - - // Make sure this alias is currently present - int n = -1; - for (int i = 0; i < aliases.length; i++) { - if (aliases[i].equals(alias)) { - n = i; - break; - } - } - if (n < 0) - return; - - // Remove the specified alias - int j = 0; - String results[] = new String[aliases.length - 1]; - for (int i = 0; i < aliases.length; i++) { - if (i != n) - results[j++] = aliases[i]; - } - aliases = results; - - } - - // Inform interested listeners - fireContainerEvent(REMOVE_ALIAS_EVENT, alias); - - } - - - /** - * Return a String representation of this component. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - if (getParent() != null) { - sb.append(getParent().toString()); - sb.append("."); - } - sb.append("StandardHost["); - sb.append(getName()); - sb.append("]"); - return (sb.toString()); - - } - - - /** - * Start this host. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public synchronized void start() throws LifecycleException { - if( started ) { - return; - } - if( ! initialized ) - init(); - - // Look for a realm - that may have been configured earlier. - // If the realm is added after context - it'll set itself. - if( realm == null ) { - ObjectName realmName=null; - try { - realmName=new ObjectName( domain + ":type=Realm,host=" + getName()); - if( mserver.isRegistered(realmName ) ) { - mserver.invoke(realmName, "init", - new Object[] {}, - new String[] {} - ); - } - } catch( Throwable t ) { - log.debug("No realm for this host " + realmName); - } - } - - // Set error report valve - if ((errorReportValveClass != null) - && (!errorReportValveClass.equals(""))) { - try { - boolean found = false; - if(errorReportValveObjectName != null) { - ObjectName[] names = - ((StandardPipeline)pipeline).getValveObjectNames(); - for (int i=0; !found && iHost interface. Each + * child container must be a Context implementation to process the + * requests directed to a particular web application. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303666 $ $Date: 2005-01-29 20:38:37 +0100 (sam., 29 janv. 2005) $ + */ + +public class StandardHost + extends ContainerBase + implements Host + { + /* Why do we implement deployer and delegate to deployer ??? */ + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( StandardHost.class ); + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new StandardHost component with the default basic Valve. + */ + public StandardHost() { + + super(); + pipeline.setBasic(new StandardHostValve()); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of aliases for this Host. + */ + private String[] aliases = new String[0]; + + + /** + * The application root for this Host. + */ + private String appBase = "."; + + + /** + * The auto deploy flag for this Host. + */ + private boolean autoDeploy = true; + + + /** + * The Java class name of the default context configuration class + * for deployed web applications. + */ + private String configClass = + "org.apache.catalina.startup.ContextConfig"; + + + /** + * The Java class name of the default Context implementation class for + * deployed web applications. + */ + private String contextClass = + "org.apache.catalina.core.StandardContext"; + + + /** + * The deploy on startup flag for this Host. + */ + private boolean deployOnStartup = true; + + + /** + * deploy Context XML config files property. + */ + private boolean deployXML = true; + + + /** + * The Java class name of the default error reporter implementation class + * for deployed web applications. + */ + private String errorReportValveClass = + "org.apache.catalina.valves.ErrorReportValve"; + + /** + * The object name for the errorReportValve. + */ + private ObjectName errorReportValveObjectName = null; + + /** + * The descriptive information string for this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardHost/1.0"; + + + /** + * The live deploy flag for this Host. + */ + private boolean liveDeploy = true; + + + /** + * Unpack WARs property. + */ + private boolean unpackWARs = true; + + + /** + * Work Directory base for applications. + */ + private String workDir = null; + + + /** + * Attribute value used to turn on/off XML validation + */ + private boolean xmlValidation = false; + + + /** + * Attribute value used to turn on/off XML namespace awarenes. + */ + private boolean xmlNamespaceAware = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the application root for this Host. This can be an absolute + * pathname, a relative pathname, or a URL. + */ + public String getAppBase() { + + return (this.appBase); + + } + + + /** + * Set the application root for this Host. This can be an absolute + * pathname, a relative pathname, or a URL. + * + * @param appBase The new application root + */ + public void setAppBase(String appBase) { + + String oldAppBase = this.appBase; + this.appBase = appBase; + support.firePropertyChange("appBase", oldAppBase, this.appBase); + + } + + + /** + * Return the value of the auto deploy flag. If true, it indicates that + * this host's child webapps will be dynamically deployed. + */ + public boolean getAutoDeploy() { + + return (this.autoDeploy); + + } + + + /** + * Set the auto deploy flag value for this host. + * + * @param autoDeploy The new auto deploy flag + */ + public void setAutoDeploy(boolean autoDeploy) { + + boolean oldAutoDeploy = this.autoDeploy; + this.autoDeploy = autoDeploy; + support.firePropertyChange("autoDeploy", oldAutoDeploy, + this.autoDeploy); + + } + + + /** + * Return the Java class name of the context configuration class + * for new web applications. + */ + public String getConfigClass() { + + return (this.configClass); + + } + + + /** + * Set the Java class name of the context configuration class + * for new web applications. + * + * @param configClass The new context configuration class + */ + public void setConfigClass(String configClass) { + + String oldConfigClass = this.configClass; + this.configClass = configClass; + support.firePropertyChange("configClass", + oldConfigClass, this.configClass); + + } + + + /** + * Return the Java class name of the Context implementation class + * for new web applications. + */ + public String getContextClass() { + + return (this.contextClass); + + } + + + /** + * Set the Java class name of the Context implementation class + * for new web applications. + * + * @param contextClass The new context implementation class + */ + public void setContextClass(String contextClass) { + + String oldContextClass = this.contextClass; + this.contextClass = contextClass; + support.firePropertyChange("contextClass", + oldContextClass, this.contextClass); + + } + + + /** + * Return the value of the deploy on startup flag. If true, it indicates + * that this host's child webapps should be discovred and automatically + * deployed at startup time. + */ + public boolean getDeployOnStartup() { + + return (this.deployOnStartup); + + } + + + /** + * Set the deploy on startup flag value for this host. + * + * @param deployOnStartup The new deploy on startup flag + */ + public void setDeployOnStartup(boolean deployOnStartup) { + + boolean oldDeployOnStartup = this.deployOnStartup; + this.deployOnStartup = deployOnStartup; + support.firePropertyChange("deployOnStartup", oldDeployOnStartup, + this.deployOnStartup); + + } + + + /** + * Deploy XML Context config files flag accessor. + */ + public boolean isDeployXML() { + + return (deployXML); + + } + + + /** + * Deploy XML Context config files flag mutator. + */ + public void setDeployXML(boolean deployXML) { + + this.deployXML = deployXML; + + } + + + /** + * Return the value of the live deploy flag. If true, it indicates that + * a background thread should be started that looks for web application + * context files, WAR files, or unpacked directories being dropped in to + * the appBase directory, and deploys new ones as they are + * encountered. + */ + public boolean getLiveDeploy() { + return (this.autoDeploy); + } + + + /** + * Set the live deploy flag value for this host. + * + * @param liveDeploy The new live deploy flag + */ + public void setLiveDeploy(boolean liveDeploy) { + setAutoDeploy(liveDeploy); + } + + + /** + * Return the Java class name of the error report valve class + * for new web applications. + */ + public String getErrorReportValveClass() { + + return (this.errorReportValveClass); + + } + + + /** + * Set the Java class name of the error report valve class + * for new web applications. + * + * @param errorReportValveClass The new error report valve class + */ + public void setErrorReportValveClass(String errorReportValveClass) { + + String oldErrorReportValveClassClass = this.errorReportValveClass; + this.errorReportValveClass = errorReportValveClass; + support.firePropertyChange("errorReportValveClass", + oldErrorReportValveClassClass, + this.errorReportValveClass); + + } + + + /** + * Return the canonical, fully qualified, name of the virtual host + * this Container represents. + */ + public String getName() { + + return (name); + + } + + + /** + * Set the canonical, fully qualified, name of the virtual host + * this Container represents. + * + * @param name Virtual host name + * + * @exception IllegalArgumentException if name is null + */ + public void setName(String name) { + + if (name == null) + throw new IllegalArgumentException + (sm.getString("standardHost.nullName")); + + name = name.toLowerCase(); // Internally all names are lower case + + String oldName = this.name; + this.name = name; + support.firePropertyChange("name", oldName, this.name); + + } + + + /** + * Unpack WARs flag accessor. + */ + public boolean isUnpackWARs() { + + return (unpackWARs); + + } + + + /** + * Unpack WARs flag mutator. + */ + public void setUnpackWARs(boolean unpackWARs) { + + this.unpackWARs = unpackWARs; + + } + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param xmlValidation true to enable xml instance validation + */ + public void setXmlValidation(boolean xmlValidation){ + + this.xmlValidation = xmlValidation; + + } + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getXmlValidation(){ + return xmlValidation; + } + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + * + */ + public boolean getXmlNamespaceAware(){ + return xmlNamespaceAware; + } + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param xmlNamespaceAware true to enable namespace awareness + */ + public void setXmlNamespaceAware(boolean xmlNamespaceAware){ + this.xmlNamespaceAware=xmlNamespaceAware; + } + + /** + * Host work directory base. + */ + public String getWorkDir() { + + return (workDir); + } + + + /** + * Host work directory base. + */ + public void setWorkDir(String workDir) { + + this.workDir = workDir; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an alias name that should be mapped to this same Host. + * + * @param alias The alias to be added + */ + public void addAlias(String alias) { + + alias = alias.toLowerCase(); + + // Skip duplicate aliases + for (int i = 0; i < aliases.length; i++) { + if (aliases[i].equals(alias)) + return; + } + + // Add this alias to the list + String newAliases[] = new String[aliases.length + 1]; + for (int i = 0; i < aliases.length; i++) + newAliases[i] = aliases[i]; + newAliases[aliases.length] = alias; + + aliases = newAliases; + + // Inform interested listeners + fireContainerEvent(ADD_ALIAS_EVENT, alias); + + } + + + /** + * Add a child Container, only if the proposed child is an implementation + * of Context. + * + * @param child Child container to be added + */ + public void addChild(Container child) { + + if (!(child instanceof Context)) + throw new IllegalArgumentException + (sm.getString("standardHost.notContext")); + super.addChild(child); + + } + + + /** + * Return the set of alias names for this Host. If none are defined, + * a zero length array is returned. + */ + public String[] findAliases() { + + return (this.aliases); + + } + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the Context that would be used to process the specified + * host-relative request URI, if any; otherwise return null. + * + * @param uri Request URI to be mapped + */ + public Context map(String uri) { + + if (log.isDebugEnabled()) + log.debug("Mapping request URI '" + uri + "'"); + if (uri == null) + return (null); + + // Match on the longest possible context path prefix + if (log.isTraceEnabled()) + log.trace(" Trying the longest context path prefix"); + Context context = null; + String mapuri = uri; + while (true) { + context = (Context) findChild(mapuri); + if (context != null) + break; + int slash = mapuri.lastIndexOf('/'); + if (slash < 0) + break; + mapuri = mapuri.substring(0, slash); + } + + // If no Context matches, select the default Context + if (context == null) { + if (log.isTraceEnabled()) + log.trace(" Trying the default context"); + context = (Context) findChild(""); + } + + // Complain if no Context has been selected + if (context == null) { + log.error(sm.getString("standardHost.mappingError", uri)); + return (null); + } + + // Return the mapped Context (if any) + if (log.isDebugEnabled()) + log.debug(" Mapped to context '" + context.getPath() + "'"); + return (context); + + } + + + /** + * Remove the specified alias name from the aliases for this Host. + * + * @param alias Alias name to be removed + */ + public void removeAlias(String alias) { + + alias = alias.toLowerCase(); + + synchronized (aliases) { + + // Make sure this alias is currently present + int n = -1; + for (int i = 0; i < aliases.length; i++) { + if (aliases[i].equals(alias)) { + n = i; + break; + } + } + if (n < 0) + return; + + // Remove the specified alias + int j = 0; + String results[] = new String[aliases.length - 1]; + for (int i = 0; i < aliases.length; i++) { + if (i != n) + results[j++] = aliases[i]; + } + aliases = results; + + } + + // Inform interested listeners + fireContainerEvent(REMOVE_ALIAS_EVENT, alias); + + } + + + /** + * Return a String representation of this component. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + if (getParent() != null) { + sb.append(getParent().toString()); + sb.append("."); + } + sb.append("StandardHost["); + sb.append(getName()); + sb.append("]"); + return (sb.toString()); + + } + + + /** + * Start this host. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public synchronized void start() throws LifecycleException { + if( started ) { + return; + } + if( ! initialized ) + init(); + + // Look for a realm - that may have been configured earlier. + // If the realm is added after context - it'll set itself. + if( realm == null ) { + ObjectName realmName=null; + try { + realmName=new ObjectName( domain + ":type=Realm,host=" + getName()); + if( mserver.isRegistered(realmName ) ) { + mserver.invoke(realmName, "init", + new Object[] {}, + new String[] {} + ); + } + } catch( Throwable t ) { + log.debug("No realm for this host " + realmName); + } + } + + // Set error report valve + if ((errorReportValveClass != null) + && (!errorReportValveClass.equals(""))) { + try { + boolean found = false; + if(errorReportValveObjectName != null) { + ObjectName[] names = + ((StandardPipeline)pipeline).getValveObjectNames(); + for (int i=0; !found && iStandardHost container implementation. - *

    - * USAGE CONSTRAINT: This implementation is likely to be useful only - * when processing HTTP requests. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 304105 $ $Date: 2005-09-27 21:20:54 +0200 (mar., 27 sept. 2005) $ - */ - -final class StandardHostValve - extends ValveBase { - - - private static Log log = LogFactory.getLog(StandardHostValve.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardHostValve/1.0"; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Select the appropriate child Context to process this request, - * based on the specified request URI. If no matching Context can - * be found, return an appropriate HTTP error. - * - * @param request Request to be processed - * @param response Response to be produced - * @param valveContext Valve context used to forward to the next Valve - * - * @exception IOException if an input/output error occurred - * @exception ServletException if a servlet error occurred - */ - public final void invoke(Request request, Response response) - throws IOException, ServletException { - - // Select the Context to be used for this Request - Context context = request.getContext(); - if (context == null) { - response.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - sm.getString("standardHost.noContext")); - return; - } - - // Bind the context CL to the current thread - if( context.getLoader() != null ) { - // Not started - it should check for availability first - // This should eventually move to Engine, it's generic. - Thread.currentThread().setContextClassLoader - (context.getLoader().getClassLoader()); - } - - // Ask this Context to process this request - context.getPipeline().getFirst().invoke(request, response); - - // Error page processing - response.setSuspended(false); - - Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR); - - if (t != null) { - throwable(request, response, t); - } else { - status(request, response); - } - - // Restore the context classloader - Thread.currentThread().setContextClassLoader - (StandardHostValve.class.getClassLoader()); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Handle the specified Throwable encountered while processing - * the specified Request to produce the specified Response. Any - * exceptions that occur during generation of the exception report are - * logged and swallowed. - * - * @param request The request being processed - * @param response The response being generated - * @param throwable The exception that occurred (which possibly wraps - * a root cause exception - */ - protected void throwable(Request request, Response response, - Throwable throwable) { - Context context = request.getContext(); - if (context == null) - return; - - Throwable realError = throwable; - - if (realError instanceof ServletException) { - realError = ((ServletException) realError).getRootCause(); - if (realError == null) { - realError = throwable; - } - } - - // If this is an aborted request from a client just log it and return - if (realError instanceof ClientAbortException ) { - if (log.isDebugEnabled()) { - log.debug - (sm.getString("standardHost.clientAbort", - realError.getCause().getMessage())); - } - return; - } - - ErrorPage errorPage = findErrorPage(context, throwable); - if ((errorPage == null) && (realError != throwable)) { - errorPage = findErrorPage(context, realError); - } - - if (errorPage != null) { - response.setAppCommitted(false); - request.setAttribute - (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, - errorPage.getLocation()); - request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - new Integer(ApplicationFilterFactory.ERROR)); - request.setAttribute - (Globals.STATUS_CODE_ATTR, - new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); - request.setAttribute(Globals.ERROR_MESSAGE_ATTR, - throwable.getMessage()); - request.setAttribute(Globals.EXCEPTION_ATTR, - realError); - Wrapper wrapper = request.getWrapper(); - if (wrapper != null) - request.setAttribute(Globals.SERVLET_NAME_ATTR, - wrapper.getName()); - request.setAttribute(Globals.EXCEPTION_PAGE_ATTR, - request.getRequestURI()); - request.setAttribute(Globals.EXCEPTION_TYPE_ATTR, - realError.getClass()); - if (custom(request, response, errorPage)) { - try { - response.flushBuffer(); - } catch (IOException e) { - container.getLogger().warn("Exception Processing " + errorPage, e); - } - } - } else { - // A custom error-page has not been defined for the exception - // that was thrown during request processing. Check if an - // error-page for error code 500 was specified and if so, - // send that page back as the response. - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - // The response is an error - response.setError(); - - status(request, response); - } - - - } - - - /** - * Handle the HTTP status code (and corresponding message) generated - * while processing the specified Request to produce the specified - * Response. Any exceptions that occur during generation of the error - * report are logged and swallowed. - * - * @param request The request being processed - * @param response The response being generated - */ - protected void status(Request request, Response response) { - - int statusCode = response.getStatus(); - - // Handle a custom error page for this status code - Context context = request.getContext(); - if (context == null) - return; - - /* Only look for error pages when isError() is set. - * isError() is set when response.sendError() is invoked. This - * allows custom error pages without relying on default from - * web.xml. - */ - if (!response.isError()) - return; - - ErrorPage errorPage = context.findErrorPage(statusCode); - if (errorPage != null) { - response.setAppCommitted(false); - request.setAttribute(Globals.STATUS_CODE_ATTR, - new Integer(statusCode)); - - String message = RequestUtil.filter(response.getMessage()); - if (message == null) - message = ""; - request.setAttribute(Globals.ERROR_MESSAGE_ATTR, message); - request.setAttribute - (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, - errorPage.getLocation()); - request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - new Integer(ApplicationFilterFactory.ERROR)); - - - Wrapper wrapper = request.getWrapper(); - if (wrapper != null) - request.setAttribute(Globals.SERVLET_NAME_ATTR, - wrapper.getName()); - request.setAttribute(Globals.EXCEPTION_PAGE_ATTR, - request.getRequestURI()); - if (custom(request, response, errorPage)) { - try { - response.flushBuffer(); - } catch (IOException e) { - container.getLogger().warn("Exception Processing " + errorPage, e); - } - } - } - - } - - - /** - * Find and return the ErrorPage instance for the specified exception's - * class, or an ErrorPage instance for the closest superclass for which - * there is such a definition. If no associated ErrorPage instance is - * found, return null. - * - * @param context The Context in which to search - * @param exception The exception for which to find an ErrorPage - */ - protected static ErrorPage findErrorPage - (Context context, Throwable exception) { - - if (exception == null) - return (null); - Class clazz = exception.getClass(); - String name = clazz.getName(); - while (!Object.class.equals(clazz)) { - ErrorPage errorPage = context.findErrorPage(name); - if (errorPage != null) - return (errorPage); - clazz = clazz.getSuperclass(); - if (clazz == null) - break; - name = clazz.getName(); - } - return (null); - - } - - - /** - * Handle an HTTP status code or Java exception by forwarding control - * to the location included in the specified errorPage object. It is - * assumed that the caller has already recorded any request attributes - * that are to be forwarded to this page. Return true if - * we successfully utilized the specified error page location, or - * false if the default error report should be rendered. - * - * @param request The request being processed - * @param response The response being generated - * @param errorPage The errorPage directive we are obeying - */ - protected boolean custom(Request request, Response response, - ErrorPage errorPage) { - - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("Processing " + errorPage); - - request.setPathInfo(errorPage.getLocation()); - - try { - - // Reset the response if possible (else IllegalStateException) - //hres.reset(); - // Reset the response (keeping the real error code and message) - Integer statusCodeObj = - (Integer) request.getAttribute(Globals.STATUS_CODE_ATTR); - int statusCode = statusCodeObj.intValue(); - String message = - (String) request.getAttribute(Globals.ERROR_MESSAGE_ATTR); - response.reset(statusCode, message); - - // Forward control to the specified location - ServletContext servletContext = - request.getContext().getServletContext(); - RequestDispatcher rd = - servletContext.getRequestDispatcher(errorPage.getLocation()); - rd.forward(request.getRequest(), response.getResponse()); - - // If we forward, the response is suspended again - response.setSuspended(false); - - // Indicate that we have successfully processed this custom page - return (true); - - } catch (Throwable t) { - - // Report our failure to process this custom page - container.getLogger().error("Exception Processing " + errorPage, t); - return (false); - - } - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.ClientAbortException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.deploy.ErrorPage; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Valve that implements the default basic behavior for the + * StandardHost container implementation. + *

    + * USAGE CONSTRAINT: This implementation is likely to be useful only + * when processing HTTP requests. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 304105 $ $Date: 2005-09-27 21:20:54 +0200 (mar., 27 sept. 2005) $ + */ + +final class StandardHostValve + extends ValveBase { + + + private static Log log = LogFactory.getLog(StandardHostValve.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardHostValve/1.0"; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Select the appropriate child Context to process this request, + * based on the specified request URI. If no matching Context can + * be found, return an appropriate HTTP error. + * + * @param request Request to be processed + * @param response Response to be produced + * @param valveContext Valve context used to forward to the next Valve + * + * @exception IOException if an input/output error occurred + * @exception ServletException if a servlet error occurred + */ + public final void invoke(Request request, Response response) + throws IOException, ServletException { + + // Select the Context to be used for this Request + Context context = request.getContext(); + if (context == null) { + response.sendError + (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + sm.getString("standardHost.noContext")); + return; + } + + // Bind the context CL to the current thread + if( context.getLoader() != null ) { + // Not started - it should check for availability first + // This should eventually move to Engine, it's generic. + Thread.currentThread().setContextClassLoader + (context.getLoader().getClassLoader()); + } + + // Ask this Context to process this request + context.getPipeline().getFirst().invoke(request, response); + + // Error page processing + response.setSuspended(false); + + Throwable t = (Throwable) request.getAttribute(Globals.EXCEPTION_ATTR); + + if (t != null) { + throwable(request, response, t); + } else { + status(request, response); + } + + // Restore the context classloader + Thread.currentThread().setContextClassLoader + (StandardHostValve.class.getClassLoader()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Handle the specified Throwable encountered while processing + * the specified Request to produce the specified Response. Any + * exceptions that occur during generation of the exception report are + * logged and swallowed. + * + * @param request The request being processed + * @param response The response being generated + * @param throwable The exception that occurred (which possibly wraps + * a root cause exception + */ + protected void throwable(Request request, Response response, + Throwable throwable) { + Context context = request.getContext(); + if (context == null) + return; + + Throwable realError = throwable; + + if (realError instanceof ServletException) { + realError = ((ServletException) realError).getRootCause(); + if (realError == null) { + realError = throwable; + } + } + + // If this is an aborted request from a client just log it and return + if (realError instanceof ClientAbortException ) { + if (log.isDebugEnabled()) { + log.debug + (sm.getString("standardHost.clientAbort", + realError.getCause().getMessage())); + } + return; + } + + ErrorPage errorPage = findErrorPage(context, throwable); + if ((errorPage == null) && (realError != throwable)) { + errorPage = findErrorPage(context, realError); + } + + if (errorPage != null) { + response.setAppCommitted(false); + request.setAttribute + (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, + errorPage.getLocation()); + request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + new Integer(ApplicationFilterFactory.ERROR)); + request.setAttribute + (Globals.STATUS_CODE_ATTR, + new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + request.setAttribute(Globals.ERROR_MESSAGE_ATTR, + throwable.getMessage()); + request.setAttribute(Globals.EXCEPTION_ATTR, + realError); + Wrapper wrapper = request.getWrapper(); + if (wrapper != null) + request.setAttribute(Globals.SERVLET_NAME_ATTR, + wrapper.getName()); + request.setAttribute(Globals.EXCEPTION_PAGE_ATTR, + request.getRequestURI()); + request.setAttribute(Globals.EXCEPTION_TYPE_ATTR, + realError.getClass()); + if (custom(request, response, errorPage)) { + try { + response.flushBuffer(); + } catch (IOException e) { + container.getLogger().warn("Exception Processing " + errorPage, e); + } + } + } else { + // A custom error-page has not been defined for the exception + // that was thrown during request processing. Check if an + // error-page for error code 500 was specified and if so, + // send that page back as the response. + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + // The response is an error + response.setError(); + + status(request, response); + } + + + } + + + /** + * Handle the HTTP status code (and corresponding message) generated + * while processing the specified Request to produce the specified + * Response. Any exceptions that occur during generation of the error + * report are logged and swallowed. + * + * @param request The request being processed + * @param response The response being generated + */ + protected void status(Request request, Response response) { + + int statusCode = response.getStatus(); + + // Handle a custom error page for this status code + Context context = request.getContext(); + if (context == null) + return; + + /* Only look for error pages when isError() is set. + * isError() is set when response.sendError() is invoked. This + * allows custom error pages without relying on default from + * web.xml. + */ + if (!response.isError()) + return; + + ErrorPage errorPage = context.findErrorPage(statusCode); + if (errorPage != null) { + response.setAppCommitted(false); + request.setAttribute(Globals.STATUS_CODE_ATTR, + new Integer(statusCode)); + + String message = RequestUtil.filter(response.getMessage()); + if (message == null) + message = ""; + request.setAttribute(Globals.ERROR_MESSAGE_ATTR, message); + request.setAttribute + (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, + errorPage.getLocation()); + request.setAttribute(ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + new Integer(ApplicationFilterFactory.ERROR)); + + + Wrapper wrapper = request.getWrapper(); + if (wrapper != null) + request.setAttribute(Globals.SERVLET_NAME_ATTR, + wrapper.getName()); + request.setAttribute(Globals.EXCEPTION_PAGE_ATTR, + request.getRequestURI()); + if (custom(request, response, errorPage)) { + try { + response.flushBuffer(); + } catch (IOException e) { + container.getLogger().warn("Exception Processing " + errorPage, e); + } + } + } + + } + + + /** + * Find and return the ErrorPage instance for the specified exception's + * class, or an ErrorPage instance for the closest superclass for which + * there is such a definition. If no associated ErrorPage instance is + * found, return null. + * + * @param context The Context in which to search + * @param exception The exception for which to find an ErrorPage + */ + protected static ErrorPage findErrorPage + (Context context, Throwable exception) { + + if (exception == null) + return (null); + Class clazz = exception.getClass(); + String name = clazz.getName(); + while (!Object.class.equals(clazz)) { + ErrorPage errorPage = context.findErrorPage(name); + if (errorPage != null) + return (errorPage); + clazz = clazz.getSuperclass(); + if (clazz == null) + break; + name = clazz.getName(); + } + return (null); + + } + + + /** + * Handle an HTTP status code or Java exception by forwarding control + * to the location included in the specified errorPage object. It is + * assumed that the caller has already recorded any request attributes + * that are to be forwarded to this page. Return true if + * we successfully utilized the specified error page location, or + * false if the default error report should be rendered. + * + * @param request The request being processed + * @param response The response being generated + * @param errorPage The errorPage directive we are obeying + */ + protected boolean custom(Request request, Response response, + ErrorPage errorPage) { + + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("Processing " + errorPage); + + request.setPathInfo(errorPage.getLocation()); + + try { + + // Reset the response if possible (else IllegalStateException) + //hres.reset(); + // Reset the response (keeping the real error code and message) + Integer statusCodeObj = + (Integer) request.getAttribute(Globals.STATUS_CODE_ATTR); + int statusCode = statusCodeObj.intValue(); + String message = + (String) request.getAttribute(Globals.ERROR_MESSAGE_ATTR); + response.reset(statusCode, message); + + // Forward control to the specified location + ServletContext servletContext = + request.getContext().getServletContext(); + RequestDispatcher rd = + servletContext.getRequestDispatcher(errorPage.getLocation()); + rd.forward(request.getRequest(), response.getResponse()); + + // If we forward, the response is suspended again + response.setSuspended(false); + + // Indicate that we have successfully processed this custom page + return (true); + + } catch (Throwable t) { + + // Report our failure to process this custom page + container.getLogger().error("Exception Processing " + errorPage, t); + return (false); + + } + + } + + +} diff --git a/java/org/apache/catalina/core/StandardPipeline.java b/java/org/apache/catalina/core/StandardPipeline.java index d0499f02c..3d79ecb78 100644 --- a/java/org/apache/catalina/core/StandardPipeline.java +++ b/java/org/apache/catalina/core/StandardPipeline.java @@ -1,561 +1,561 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.util.ArrayList; - -import javax.management.ObjectName; - -import org.apache.catalina.Contained; -import org.apache.catalina.Container; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Pipeline; -import org.apache.catalina.Valve; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Standard implementation of a processing Pipeline that will invoke - * a series of Valves that have been configured to be called in order. This - * implementation can be used for any type of Container. - * - * IMPLEMENTATION WARNING - This implementation assumes that no - * calls to addValve() or removeValve are allowed - * while a request is currently being processed. Otherwise, the mechanism - * by which per-thread state is maintained will need to be modified. - * - * @author Craig R. McClanahan - */ - -public class StandardPipeline - implements Pipeline, Contained, Lifecycle - { - - private static Log log = LogFactory.getLog(StandardPipeline.class); - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new StandardPipeline instance with no associated Container. - */ - public StandardPipeline() { - - this(null); - - } - - - /** - * Construct a new StandardPipeline instance that is associated with the - * specified Container. - * - * @param container The container we should be associated with - */ - public StandardPipeline(Container container) { - - super(); - setContainer(container); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The basic Valve (if any) associated with this Pipeline. - */ - protected Valve basic = null; - - - /** - * The Container with which this Pipeline is associated. - */ - protected Container container = null; - - - /** - * Descriptive information about this implementation. - */ - protected String info = "org.apache.catalina.core.StandardPipeline/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - protected boolean started = false; - - - /** - * The first valve associated with this Pipeline. - */ - protected Valve first = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Return descriptive information about this implementation class. - */ - public String getInfo() { - - return (this.info); - - } - - - // ------------------------------------------------------ Contained Methods - - - /** - * Return the Container with which this Pipeline is associated. - */ - public Container getContainer() { - - return (this.container); - - } - - - /** - * Set the Container with which this Pipeline is associated. - * - * @param container The new associated container - */ - public void setContainer(Container container) { - - this.container = container; - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - /** - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public synchronized void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("standardPipeline.alreadyStarted")); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); - - started = true; - - // Start the Valves in our pipeline (including the basic), if any - Valve current = first; - if (current == null) { - current = basic; - } - while (current != null) { - if (current instanceof Lifecycle) - ((Lifecycle) current).start(); - registerValve(current); - current = current.getNext(); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(START_EVENT, null); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public synchronized void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("standardPipeline.notStarted")); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Stop the Valves in our pipeline (including the basic), if any - Valve current = first; - if (current == null) { - current = basic; - } - while (current != null) { - if (current instanceof Lifecycle) - ((Lifecycle) current).stop(); - unregisterValve(current); - current = current.getNext(); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - } - - private void registerValve(Valve valve) { - - if( valve instanceof ValveBase && - ((ValveBase)valve).getObjectName()==null ) { - try { - - String domain=((ContainerBase)container).getDomain(); - if( container instanceof StandardContext ) { - domain=((StandardContext)container).getEngineName(); - } - if( container instanceof StandardWrapper) { - Container ctx=((StandardWrapper)container).getParent(); - domain=((StandardContext)ctx).getEngineName(); - } - ObjectName vname=((ValveBase)valve).createObjectName( - domain, - ((ContainerBase)container).getJmxName()); - if( vname != null ) { - ((ValveBase)valve).setObjectName(vname); - Registry.getRegistry(null, null).registerComponent - (valve, vname, valve.getClass().getName()); - ((ValveBase)valve).setController - (((ContainerBase)container).getJmxName()); - } - } catch( Throwable t ) { - log.info( "Can't register valve " + valve , t ); - } - } - } - - private void unregisterValve(Valve valve) { - if( valve instanceof ValveBase ) { - try { - ValveBase vb=(ValveBase)valve; - if( vb.getController()!=null && - vb.getController() == - ((ContainerBase)container).getJmxName() ) { - - ObjectName vname=vb.getObjectName(); - Registry.getRegistry(null, null).getMBeanServer() - .unregisterMBean(vname); - ((ValveBase)valve).setObjectName(null); - } - } catch( Throwable t ) { - log.info( "Can't unregister valve " + valve , t ); - } - } - } - - // ------------------------------------------------------- Pipeline Methods - - - /** - *

    Return the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). - */ - public Valve getBasic() { - - return (this.basic); - - } - - - /** - *

    Set the Valve instance that has been distinguished as the basic - * Valve for this Pipeline (if any). Prioer to setting the basic Valve, - * the Valve's setContainer() will be called, if it - * implements Contained, with the owning Container as an - * argument. The method may throw an IllegalArgumentException - * if this Valve chooses not to be associated with this Container, or - * IllegalStateException if it is already associated with - * a different Container.

    - * - * @param valve Valve to be distinguished as the basic Valve - */ - public void setBasic(Valve valve) { - - // Change components if necessary - Valve oldBasic = this.basic; - if (oldBasic == valve) - return; - - // Stop the old component if necessary - if (oldBasic != null) { - if (started && (oldBasic instanceof Lifecycle)) { - try { - ((Lifecycle) oldBasic).stop(); - } catch (LifecycleException e) { - log.error("StandardPipeline.setBasic: stop", e); - } - } - if (oldBasic instanceof Contained) { - try { - ((Contained) oldBasic).setContainer(null); - } catch (Throwable t) { - ; - } - } - } - - // Start the new component if necessary - if (valve == null) - return; - if (valve instanceof Contained) { - ((Contained) valve).setContainer(this.container); - } - if (valve instanceof Lifecycle) { - try { - ((Lifecycle) valve).start(); - } catch (LifecycleException e) { - log.error("StandardPipeline.setBasic: start", e); - return; - } - } - - // Update the pipeline - Valve current = first; - while (current != null) { - if (current.getNext() == oldBasic) { - current.setNext(valve); - break; - } - current = current.getNext(); - } - - this.basic = valve; - - } - - - /** - *

    Add a new Valve to the end of the pipeline associated with this - * Container. Prior to adding the Valve, the Valve's - * setContainer() method will be called, if it implements - * Contained, with the owning Container as an argument. - * The method may throw an - * IllegalArgumentException if this Valve chooses not to - * be associated with this Container, or IllegalStateException - * if it is already associated with a different Container.

    - * - * @param valve Valve to be added - * - * @exception IllegalArgumentException if this Container refused to - * accept the specified Valve - * @exception IllegalArgumentException if the specifie Valve refuses to be - * associated with this Container - * @exception IllegalStateException if the specified Valve is already - * associated with a different Container - */ - public void addValve(Valve valve) { - - // Validate that we can add this Valve - if (valve instanceof Contained) - ((Contained) valve).setContainer(this.container); - - // Start the new component if necessary - if (started) { - if (valve instanceof Lifecycle) { - try { - ((Lifecycle) valve).start(); - } catch (LifecycleException e) { - log.error("StandardPipeline.addValve: start: ", e); - } - } - // Register the newly added valve - registerValve(valve); - } - - // Add this Valve to the set associated with this Pipeline - if (first == null) { - first = valve; - valve.setNext(basic); - } else { - Valve current = first; - while (current != null) { - if (current.getNext() == basic) { - current.setNext(valve); - valve.setNext(basic); - break; - } - current = current.getNext(); - } - } - - } - - - /** - * Return the set of Valves in the pipeline associated with this - * Container, including the basic Valve (if any). If there are no - * such Valves, a zero-length array is returned. - */ - public Valve[] getValves() { - - ArrayList valveList = new ArrayList(); - Valve current = first; - if (current == null) { - current = basic; - } - while (current != null) { - valveList.add(current); - current = current.getNext(); - } - - return ((Valve[]) valveList.toArray(new Valve[0])); - - } - - public ObjectName[] getValveObjectNames() { - - ArrayList valveList = new ArrayList(); - Valve current = first; - if (current == null) { - current = basic; - } - while (current != null) { - if (current instanceof ValveBase) { - valveList.add(((ValveBase) current).getObjectName()); - } - current = current.getNext(); - } - - return ((ObjectName[]) valveList.toArray(new ObjectName[0])); - - } - - /** - * Remove the specified Valve from the pipeline associated with this - * Container, if it is found; otherwise, do nothing. If the Valve is - * found and removed, the Valve's setContainer(null) method - * will be called if it implements Contained. - * - * @param valve Valve to be removed - */ - public void removeValve(Valve valve) { - - Valve current; - if(first == valve) { - first = first.getNext(); - current = null; - } else { - current = first; - } - while (current != null) { - if (current.getNext() == valve) { - current.setNext(valve.getNext()); - break; - } - current = current.getNext(); - } - - if (valve instanceof Contained) - ((Contained) valve).setContainer(null); - - // Stop this valve if necessary - if (started) { - if (valve instanceof Lifecycle) { - try { - ((Lifecycle) valve).stop(); - } catch (LifecycleException e) { - log.error("StandardPipeline.removeValve: stop: ", e); - } - } - // Unregister the removed valave - unregisterValve(valve); - } - - } - - - public Valve getFirst() { - if (first != null) { - return first; - } else { - return basic; - } - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.util.ArrayList; + +import javax.management.ObjectName; + +import org.apache.catalina.Contained; +import org.apache.catalina.Container; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Pipeline; +import org.apache.catalina.Valve; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Standard implementation of a processing Pipeline that will invoke + * a series of Valves that have been configured to be called in order. This + * implementation can be used for any type of Container. + * + * IMPLEMENTATION WARNING - This implementation assumes that no + * calls to addValve() or removeValve are allowed + * while a request is currently being processed. Otherwise, the mechanism + * by which per-thread state is maintained will need to be modified. + * + * @author Craig R. McClanahan + */ + +public class StandardPipeline + implements Pipeline, Contained, Lifecycle + { + + private static Log log = LogFactory.getLog(StandardPipeline.class); + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new StandardPipeline instance with no associated Container. + */ + public StandardPipeline() { + + this(null); + + } + + + /** + * Construct a new StandardPipeline instance that is associated with the + * specified Container. + * + * @param container The container we should be associated with + */ + public StandardPipeline(Container container) { + + super(); + setContainer(container); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The basic Valve (if any) associated with this Pipeline. + */ + protected Valve basic = null; + + + /** + * The Container with which this Pipeline is associated. + */ + protected Container container = null; + + + /** + * Descriptive information about this implementation. + */ + protected String info = "org.apache.catalina.core.StandardPipeline/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + protected boolean started = false; + + + /** + * The first valve associated with this Pipeline. + */ + protected Valve first = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Return descriptive information about this implementation class. + */ + public String getInfo() { + + return (this.info); + + } + + + // ------------------------------------------------------ Contained Methods + + + /** + * Return the Container with which this Pipeline is associated. + */ + public Container getContainer() { + + return (this.container); + + } + + + /** + * Set the Container with which this Pipeline is associated. + * + * @param container The new associated container + */ + public void setContainer(Container container) { + + this.container = container; + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + /** + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public synchronized void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("standardPipeline.alreadyStarted")); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); + + started = true; + + // Start the Valves in our pipeline (including the basic), if any + Valve current = first; + if (current == null) { + current = basic; + } + while (current != null) { + if (current instanceof Lifecycle) + ((Lifecycle) current).start(); + registerValve(current); + current = current.getNext(); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(START_EVENT, null); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public synchronized void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("standardPipeline.notStarted")); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Stop the Valves in our pipeline (including the basic), if any + Valve current = first; + if (current == null) { + current = basic; + } + while (current != null) { + if (current instanceof Lifecycle) + ((Lifecycle) current).stop(); + unregisterValve(current); + current = current.getNext(); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); + } + + private void registerValve(Valve valve) { + + if( valve instanceof ValveBase && + ((ValveBase)valve).getObjectName()==null ) { + try { + + String domain=((ContainerBase)container).getDomain(); + if( container instanceof StandardContext ) { + domain=((StandardContext)container).getEngineName(); + } + if( container instanceof StandardWrapper) { + Container ctx=((StandardWrapper)container).getParent(); + domain=((StandardContext)ctx).getEngineName(); + } + ObjectName vname=((ValveBase)valve).createObjectName( + domain, + ((ContainerBase)container).getJmxName()); + if( vname != null ) { + ((ValveBase)valve).setObjectName(vname); + Registry.getRegistry(null, null).registerComponent + (valve, vname, valve.getClass().getName()); + ((ValveBase)valve).setController + (((ContainerBase)container).getJmxName()); + } + } catch( Throwable t ) { + log.info( "Can't register valve " + valve , t ); + } + } + } + + private void unregisterValve(Valve valve) { + if( valve instanceof ValveBase ) { + try { + ValveBase vb=(ValveBase)valve; + if( vb.getController()!=null && + vb.getController() == + ((ContainerBase)container).getJmxName() ) { + + ObjectName vname=vb.getObjectName(); + Registry.getRegistry(null, null).getMBeanServer() + .unregisterMBean(vname); + ((ValveBase)valve).setObjectName(null); + } + } catch( Throwable t ) { + log.info( "Can't unregister valve " + valve , t ); + } + } + } + + // ------------------------------------------------------- Pipeline Methods + + + /** + *

    Return the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). + */ + public Valve getBasic() { + + return (this.basic); + + } + + + /** + *

    Set the Valve instance that has been distinguished as the basic + * Valve for this Pipeline (if any). Prioer to setting the basic Valve, + * the Valve's setContainer() will be called, if it + * implements Contained, with the owning Container as an + * argument. The method may throw an IllegalArgumentException + * if this Valve chooses not to be associated with this Container, or + * IllegalStateException if it is already associated with + * a different Container.

    + * + * @param valve Valve to be distinguished as the basic Valve + */ + public void setBasic(Valve valve) { + + // Change components if necessary + Valve oldBasic = this.basic; + if (oldBasic == valve) + return; + + // Stop the old component if necessary + if (oldBasic != null) { + if (started && (oldBasic instanceof Lifecycle)) { + try { + ((Lifecycle) oldBasic).stop(); + } catch (LifecycleException e) { + log.error("StandardPipeline.setBasic: stop", e); + } + } + if (oldBasic instanceof Contained) { + try { + ((Contained) oldBasic).setContainer(null); + } catch (Throwable t) { + ; + } + } + } + + // Start the new component if necessary + if (valve == null) + return; + if (valve instanceof Contained) { + ((Contained) valve).setContainer(this.container); + } + if (valve instanceof Lifecycle) { + try { + ((Lifecycle) valve).start(); + } catch (LifecycleException e) { + log.error("StandardPipeline.setBasic: start", e); + return; + } + } + + // Update the pipeline + Valve current = first; + while (current != null) { + if (current.getNext() == oldBasic) { + current.setNext(valve); + break; + } + current = current.getNext(); + } + + this.basic = valve; + + } + + + /** + *

    Add a new Valve to the end of the pipeline associated with this + * Container. Prior to adding the Valve, the Valve's + * setContainer() method will be called, if it implements + * Contained, with the owning Container as an argument. + * The method may throw an + * IllegalArgumentException if this Valve chooses not to + * be associated with this Container, or IllegalStateException + * if it is already associated with a different Container.

    + * + * @param valve Valve to be added + * + * @exception IllegalArgumentException if this Container refused to + * accept the specified Valve + * @exception IllegalArgumentException if the specifie Valve refuses to be + * associated with this Container + * @exception IllegalStateException if the specified Valve is already + * associated with a different Container + */ + public void addValve(Valve valve) { + + // Validate that we can add this Valve + if (valve instanceof Contained) + ((Contained) valve).setContainer(this.container); + + // Start the new component if necessary + if (started) { + if (valve instanceof Lifecycle) { + try { + ((Lifecycle) valve).start(); + } catch (LifecycleException e) { + log.error("StandardPipeline.addValve: start: ", e); + } + } + // Register the newly added valve + registerValve(valve); + } + + // Add this Valve to the set associated with this Pipeline + if (first == null) { + first = valve; + valve.setNext(basic); + } else { + Valve current = first; + while (current != null) { + if (current.getNext() == basic) { + current.setNext(valve); + valve.setNext(basic); + break; + } + current = current.getNext(); + } + } + + } + + + /** + * Return the set of Valves in the pipeline associated with this + * Container, including the basic Valve (if any). If there are no + * such Valves, a zero-length array is returned. + */ + public Valve[] getValves() { + + ArrayList valveList = new ArrayList(); + Valve current = first; + if (current == null) { + current = basic; + } + while (current != null) { + valveList.add(current); + current = current.getNext(); + } + + return ((Valve[]) valveList.toArray(new Valve[0])); + + } + + public ObjectName[] getValveObjectNames() { + + ArrayList valveList = new ArrayList(); + Valve current = first; + if (current == null) { + current = basic; + } + while (current != null) { + if (current instanceof ValveBase) { + valveList.add(((ValveBase) current).getObjectName()); + } + current = current.getNext(); + } + + return ((ObjectName[]) valveList.toArray(new ObjectName[0])); + + } + + /** + * Remove the specified Valve from the pipeline associated with this + * Container, if it is found; otherwise, do nothing. If the Valve is + * found and removed, the Valve's setContainer(null) method + * will be called if it implements Contained. + * + * @param valve Valve to be removed + */ + public void removeValve(Valve valve) { + + Valve current; + if(first == valve) { + first = first.getNext(); + current = null; + } else { + current = first; + } + while (current != null) { + if (current.getNext() == valve) { + current.setNext(valve.getNext()); + break; + } + current = current.getNext(); + } + + if (valve instanceof Contained) + ((Contained) valve).setContainer(null); + + // Stop this valve if necessary + if (started) { + if (valve instanceof Lifecycle) { + try { + ((Lifecycle) valve).stop(); + } catch (LifecycleException e) { + log.error("StandardPipeline.removeValve: stop: ", e); + } + } + // Unregister the removed valave + unregisterValve(valve); + } + + } + + + public Valve getFirst() { + if (first != null) { + return first; + } else { + return basic; + } + } + + +} diff --git a/java/org/apache/catalina/core/StandardServer.java b/java/org/apache/catalina/core/StandardServer.java index 908b3791f..09a1d10aa 100644 --- a/java/org/apache/catalina/core/StandardServer.java +++ b/java/org/apache/catalina/core/StandardServer.java @@ -1,826 +1,826 @@ -/* - * Copyright 1999-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.security.AccessControlException; -import java.util.Random; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.catalina.Context; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Server; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.Service; -import org.apache.catalina.deploy.NamingResources; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.util.ServerInfo; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.buf.StringCache; -import org.apache.tomcat.util.modeler.Registry; - - - -/** - * Standard implementation of the Server interface, available for use - * (but not required) when deploying and starting Catalina. - * - * @author Craig R. McClanahan - * @version $Revision: 370082 $ $Date: 2006-01-18 10:17:33 +0100 (mer., 18 janv. 2006) $ - */ -public final class StandardServer - implements Lifecycle, Server, MBeanRegistration - { - private static Log log = LogFactory.getLog(StandardServer.class); - - - // -------------------------------------------------------------- Constants - - - /** - * ServerLifecycleListener classname. - */ - private static String SERVER_LISTENER_CLASS_NAME = - "org.apache.catalina.mbeans.ServerLifecycleListener"; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct a default instance of this class. - */ - public StandardServer() { - - super(); - ServerFactory.setServer(this); - - globalNamingResources = new NamingResources(); - globalNamingResources.setContainer(this); - - if (isUseNaming()) { - if (namingContextListener == null) { - namingContextListener = new NamingContextListener(); - addLifecycleListener(namingContextListener); - } - } - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Global naming resources context. - */ - private javax.naming.Context globalNamingContext = null; - - - /** - * Global naming resources. - */ - private NamingResources globalNamingResources = null; - - - /** - * Descriptive information about this Server implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardServer/1.0"; - - - /** - * The lifecycle event support for this component. - */ - private LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The naming context listener for this web application. - */ - private NamingContextListener namingContextListener = null; - - - /** - * The port number on which we wait for shutdown commands. - */ - private int port = 8005; - - - /** - * A random number generator that is only used if - * the shutdown command string is longer than 1024 characters. - */ - private Random random = null; - - - /** - * The set of Services associated with this Server. - */ - private Service services[] = new Service[0]; - - - /** - * The shutdown command string we are looking for. - */ - private String shutdown = "SHUTDOWN"; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started? - */ - private boolean started = false; - - - /** - * Has this component been initialized? - */ - private boolean initialized = false; - - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - private boolean stopAwait = false; - - // ------------------------------------------------------------- Properties - - - /** - * Return the global naming resources context. - */ - public javax.naming.Context getGlobalNamingContext() { - - return (this.globalNamingContext); - - } - - - /** - * Set the global naming resources context. - * - * @param globalNamingContext The new global naming resource context - */ - public void setGlobalNamingContext - (javax.naming.Context globalNamingContext) { - - this.globalNamingContext = globalNamingContext; - - } - - - /** - * Return the global naming resources. - */ - public NamingResources getGlobalNamingResources() { - - return (this.globalNamingResources); - - } - - - /** - * Set the global naming resources. - * - * @param globalNamingResources The new global naming resources - */ - public void setGlobalNamingResources - (NamingResources globalNamingResources) { - - NamingResources oldGlobalNamingResources = - this.globalNamingResources; - this.globalNamingResources = globalNamingResources; - this.globalNamingResources.setContainer(this); - support.firePropertyChange("globalNamingResources", - oldGlobalNamingResources, - this.globalNamingResources); - - } - - - /** - * Return descriptive information about this Server implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - /** - * Report the current Tomcat Server Release number - * @return Tomcat release identifier - */ - public String getServerInfo() { - - return ServerInfo.getServerInfo(); - } - - /** - * Return the port number we listen to for shutdown commands. - */ - public int getPort() { - - return (this.port); - - } - - - /** - * Set the port number we listen to for shutdown commands. - * - * @param port The new port number - */ - public void setPort(int port) { - - this.port = port; - - } - - - /** - * Return the shutdown command string we are waiting for. - */ - public String getShutdown() { - - return (this.shutdown); - - } - - - /** - * Set the shutdown command we are waiting for. - * - * @param shutdown The new shutdown command - */ - public void setShutdown(String shutdown) { - - this.shutdown = shutdown; - - } - - - // --------------------------------------------------------- Server Methods - - - /** - * Add a new Service to the set of defined Services. - * - * @param service The Service to be added - */ - public void addService(Service service) { - - service.setServer(this); - - synchronized (services) { - Service results[] = new Service[services.length + 1]; - System.arraycopy(services, 0, results, 0, services.length); - results[services.length] = service; - services = results; - - if (initialized) { - try { - service.initialize(); - } catch (LifecycleException e) { - log.error(e); - } - } - - if (started && (service instanceof Lifecycle)) { - try { - ((Lifecycle) service).start(); - } catch (LifecycleException e) { - ; - } - } - - // Report this property change to interested listeners - support.firePropertyChange("service", null, service); - } - - } - - public void stopAwait() { - stopAwait=true; - } - - /** - * Wait until a proper shutdown command is received, then return. - * This keeps the main thread alive - the thread pool listening for http - * connections is daemon threads. - */ - public void await() { - // Negative values - don't wait on port - tomcat is embedded or we just don't like ports - if( port == -2 ) { - // undocumented yet - for embedding apps that are around, alive. - return; - } - if( port==-1 ) { - while( true ) { - try { - Thread.sleep( 100000 ); - } catch( InterruptedException ex ) { - } - if( stopAwait ) return; - } - } - - // Set up a server socket to wait on - ServerSocket serverSocket = null; - try { - serverSocket = - new ServerSocket(port, 1, - InetAddress.getByName("127.0.0.1")); - } catch (IOException e) { - log.error("StandardServer.await: create[" + port - + "]: ", e); - System.exit(1); - } - - // Loop waiting for a connection and a valid command - while (true) { - - // Wait for the next connection - Socket socket = null; - InputStream stream = null; - try { - socket = serverSocket.accept(); - socket.setSoTimeout(10 * 1000); // Ten seconds - stream = socket.getInputStream(); - } catch (AccessControlException ace) { - log.warn("StandardServer.accept security exception: " - + ace.getMessage(), ace); - continue; - } catch (IOException e) { - log.error("StandardServer.await: accept: ", e); - System.exit(1); - } - - // Read a set of characters from the socket - StringBuffer command = new StringBuffer(); - int expected = 1024; // Cut off to avoid DoS attack - while (expected < shutdown.length()) { - if (random == null) - random = new Random(System.currentTimeMillis()); - expected += (random.nextInt() % 1024); - } - while (expected > 0) { - int ch = -1; - try { - ch = stream.read(); - } catch (IOException e) { - log.warn("StandardServer.await: read: ", e); - ch = -1; - } - if (ch < 32) // Control character or EOF terminates loop - break; - command.append((char) ch); - expected--; - } - - // Close the socket now that we are done with it - try { - socket.close(); - } catch (IOException e) { - ; - } - - // Match against our command string - boolean match = command.toString().equals(shutdown); - if (match) { - break; - } else - log.warn("StandardServer.await: Invalid command '" + - command.toString() + "' received"); - - } - - // Close the server socket and return - try { - serverSocket.close(); - } catch (IOException e) { - ; - } - - } - - - /** - * Return the specified Service (if it exists); otherwise return - * null. - * - * @param name Name of the Service to be returned - */ - public Service findService(String name) { - - if (name == null) { - return (null); - } - synchronized (services) { - for (int i = 0; i < services.length; i++) { - if (name.equals(services[i].getName())) { - return (services[i]); - } - } - } - return (null); - - } - - - /** - * Return the set of Services defined within this Server. - */ - public Service[] findServices() { - - return (services); - - } - - /** - * Return the JMX service names. - */ - public ObjectName[] getServiceNames() { - ObjectName onames[]=new ObjectName[ services.length ]; - for( int i=0; iServer - * out to the server.xml configuration file. - * - * @exception javax.management.InstanceNotFoundException if the managed resource object - * cannot be found - * @exception javax.management.MBeanException if the initializer of the object throws - * an exception, or persistence is not supported - * @exception javax.management.RuntimeOperationsException if an exception is reported - * by the persistence mechanism - */ - public synchronized void storeConfig() throws Exception { - - ObjectName sname = null; - try { - sname = new ObjectName("Catalina:type=StoreConfig"); - if(mserver.isRegistered(sname)) { - mserver.invoke(sname, "storeConfig", null, null); - } else - log.error("StoreConfig mbean not registered" + sname); - } catch (Throwable t) { - log.error(t); - } - - } - - - /** - * Write the configuration information for Context - * out to the specified configuration file. - * - * @exception javax.management.InstanceNotFoundException if the managed resource object - * cannot be found - * @exception javax.management.MBeanException if the initializer of the object throws - * an exception, or persistence is not supported - * @exception javax.management.RuntimeOperationsException if an exception is reported - * by the persistence mechanism - */ - public synchronized void storeContext(Context context) throws Exception { - - ObjectName sname = null; - try { - sname = new ObjectName("Catalina:type=StoreConfig"); - if(mserver.isRegistered(sname)) { - mserver.invoke(sname, "store", - new Object[] {context}, - new String [] { "java.lang.String"}); - } else - log.error("StoreConfig mbean not registered" + sname); - } catch (Throwable t) { - log.error(t); - } - - } - - - /** - * Return true if naming should be used. - */ - private boolean isUseNaming() { - boolean useNaming = true; - // Reading the "catalina.useNaming" environment variable - String useNamingProperty = System.getProperty("catalina.useNaming"); - if ((useNamingProperty != null) - && (useNamingProperty.equals("false"))) { - useNaming = false; - } - return useNaming; - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a LifecycleEvent listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a LifecycleEvent listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called before any of the public - * methods of this component are utilized. It should also send a - * LifecycleEvent of type START_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) { - log.debug(sm.getString("standardServer.start.started")); - return; - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); - - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Start our defined Services - synchronized (services) { - for (int i = 0; i < services.length; i++) { - if (services[i] instanceof Lifecycle) - ((Lifecycle) services[i]).start(); - } - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. It should also send a LifecycleEvent - * of type STOP_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - return; - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); - - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Stop our defined Services - for (int i = 0; i < services.length; i++) { - if (services[i] instanceof Lifecycle) - ((Lifecycle) services[i]).stop(); - } - - // Notify our interested LifecycleListeners - lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); - - } - - public void init() throws Exception { - initialize(); - } - - /** - * Invoke a pre-startup initialization. This is used to allow connectors - * to bind to restricted ports under Unix operating environments. - */ - public void initialize() - throws LifecycleException - { - if (initialized) { - log.info(sm.getString("standardServer.initialize.initialized")); - return; - } - lifecycle.fireLifecycleEvent(INIT_EVENT, null); - initialized = true; - - if( oname==null ) { - try { - oname=new ObjectName( "Catalina:type=Server"); - Registry.getRegistry(null, null) - .registerComponent(this, oname, null ); - } catch (Exception e) { - log.error("Error registering ",e); - } - } - - // Register global String cache - try { - ObjectName oname2 = - new ObjectName(oname.getDomain() + ":type=StringCache"); - Registry.getRegistry(null, null) - .registerComponent(new StringCache(), oname2, null ); - } catch (Exception e) { - log.error("Error registering ",e); - } - - // Initialize our defined Services - for (int i = 0; i < services.length; i++) { - services[i].initialize(); - } - } - - protected String type; - protected String domain; - protected String suffix; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - -} +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.InputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.AccessControlException; +import java.util.Random; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Server; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.Service; +import org.apache.catalina.deploy.NamingResources; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.util.ServerInfo; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.buf.StringCache; +import org.apache.tomcat.util.modeler.Registry; + + + +/** + * Standard implementation of the Server interface, available for use + * (but not required) when deploying and starting Catalina. + * + * @author Craig R. McClanahan + * @version $Revision: 370082 $ $Date: 2006-01-18 10:17:33 +0100 (mer., 18 janv. 2006) $ + */ +public final class StandardServer + implements Lifecycle, Server, MBeanRegistration + { + private static Log log = LogFactory.getLog(StandardServer.class); + + + // -------------------------------------------------------------- Constants + + + /** + * ServerLifecycleListener classname. + */ + private static String SERVER_LISTENER_CLASS_NAME = + "org.apache.catalina.mbeans.ServerLifecycleListener"; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct a default instance of this class. + */ + public StandardServer() { + + super(); + ServerFactory.setServer(this); + + globalNamingResources = new NamingResources(); + globalNamingResources.setContainer(this); + + if (isUseNaming()) { + if (namingContextListener == null) { + namingContextListener = new NamingContextListener(); + addLifecycleListener(namingContextListener); + } + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Global naming resources context. + */ + private javax.naming.Context globalNamingContext = null; + + + /** + * Global naming resources. + */ + private NamingResources globalNamingResources = null; + + + /** + * Descriptive information about this Server implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardServer/1.0"; + + + /** + * The lifecycle event support for this component. + */ + private LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The naming context listener for this web application. + */ + private NamingContextListener namingContextListener = null; + + + /** + * The port number on which we wait for shutdown commands. + */ + private int port = 8005; + + + /** + * A random number generator that is only used if + * the shutdown command string is longer than 1024 characters. + */ + private Random random = null; + + + /** + * The set of Services associated with this Server. + */ + private Service services[] = new Service[0]; + + + /** + * The shutdown command string we are looking for. + */ + private String shutdown = "SHUTDOWN"; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started? + */ + private boolean started = false; + + + /** + * Has this component been initialized? + */ + private boolean initialized = false; + + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + private boolean stopAwait = false; + + // ------------------------------------------------------------- Properties + + + /** + * Return the global naming resources context. + */ + public javax.naming.Context getGlobalNamingContext() { + + return (this.globalNamingContext); + + } + + + /** + * Set the global naming resources context. + * + * @param globalNamingContext The new global naming resource context + */ + public void setGlobalNamingContext + (javax.naming.Context globalNamingContext) { + + this.globalNamingContext = globalNamingContext; + + } + + + /** + * Return the global naming resources. + */ + public NamingResources getGlobalNamingResources() { + + return (this.globalNamingResources); + + } + + + /** + * Set the global naming resources. + * + * @param globalNamingResources The new global naming resources + */ + public void setGlobalNamingResources + (NamingResources globalNamingResources) { + + NamingResources oldGlobalNamingResources = + this.globalNamingResources; + this.globalNamingResources = globalNamingResources; + this.globalNamingResources.setContainer(this); + support.firePropertyChange("globalNamingResources", + oldGlobalNamingResources, + this.globalNamingResources); + + } + + + /** + * Return descriptive information about this Server implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + /** + * Report the current Tomcat Server Release number + * @return Tomcat release identifier + */ + public String getServerInfo() { + + return ServerInfo.getServerInfo(); + } + + /** + * Return the port number we listen to for shutdown commands. + */ + public int getPort() { + + return (this.port); + + } + + + /** + * Set the port number we listen to for shutdown commands. + * + * @param port The new port number + */ + public void setPort(int port) { + + this.port = port; + + } + + + /** + * Return the shutdown command string we are waiting for. + */ + public String getShutdown() { + + return (this.shutdown); + + } + + + /** + * Set the shutdown command we are waiting for. + * + * @param shutdown The new shutdown command + */ + public void setShutdown(String shutdown) { + + this.shutdown = shutdown; + + } + + + // --------------------------------------------------------- Server Methods + + + /** + * Add a new Service to the set of defined Services. + * + * @param service The Service to be added + */ + public void addService(Service service) { + + service.setServer(this); + + synchronized (services) { + Service results[] = new Service[services.length + 1]; + System.arraycopy(services, 0, results, 0, services.length); + results[services.length] = service; + services = results; + + if (initialized) { + try { + service.initialize(); + } catch (LifecycleException e) { + log.error(e); + } + } + + if (started && (service instanceof Lifecycle)) { + try { + ((Lifecycle) service).start(); + } catch (LifecycleException e) { + ; + } + } + + // Report this property change to interested listeners + support.firePropertyChange("service", null, service); + } + + } + + public void stopAwait() { + stopAwait=true; + } + + /** + * Wait until a proper shutdown command is received, then return. + * This keeps the main thread alive - the thread pool listening for http + * connections is daemon threads. + */ + public void await() { + // Negative values - don't wait on port - tomcat is embedded or we just don't like ports + if( port == -2 ) { + // undocumented yet - for embedding apps that are around, alive. + return; + } + if( port==-1 ) { + while( true ) { + try { + Thread.sleep( 100000 ); + } catch( InterruptedException ex ) { + } + if( stopAwait ) return; + } + } + + // Set up a server socket to wait on + ServerSocket serverSocket = null; + try { + serverSocket = + new ServerSocket(port, 1, + InetAddress.getByName("127.0.0.1")); + } catch (IOException e) { + log.error("StandardServer.await: create[" + port + + "]: ", e); + System.exit(1); + } + + // Loop waiting for a connection and a valid command + while (true) { + + // Wait for the next connection + Socket socket = null; + InputStream stream = null; + try { + socket = serverSocket.accept(); + socket.setSoTimeout(10 * 1000); // Ten seconds + stream = socket.getInputStream(); + } catch (AccessControlException ace) { + log.warn("StandardServer.accept security exception: " + + ace.getMessage(), ace); + continue; + } catch (IOException e) { + log.error("StandardServer.await: accept: ", e); + System.exit(1); + } + + // Read a set of characters from the socket + StringBuffer command = new StringBuffer(); + int expected = 1024; // Cut off to avoid DoS attack + while (expected < shutdown.length()) { + if (random == null) + random = new Random(System.currentTimeMillis()); + expected += (random.nextInt() % 1024); + } + while (expected > 0) { + int ch = -1; + try { + ch = stream.read(); + } catch (IOException e) { + log.warn("StandardServer.await: read: ", e); + ch = -1; + } + if (ch < 32) // Control character or EOF terminates loop + break; + command.append((char) ch); + expected--; + } + + // Close the socket now that we are done with it + try { + socket.close(); + } catch (IOException e) { + ; + } + + // Match against our command string + boolean match = command.toString().equals(shutdown); + if (match) { + break; + } else + log.warn("StandardServer.await: Invalid command '" + + command.toString() + "' received"); + + } + + // Close the server socket and return + try { + serverSocket.close(); + } catch (IOException e) { + ; + } + + } + + + /** + * Return the specified Service (if it exists); otherwise return + * null. + * + * @param name Name of the Service to be returned + */ + public Service findService(String name) { + + if (name == null) { + return (null); + } + synchronized (services) { + for (int i = 0; i < services.length; i++) { + if (name.equals(services[i].getName())) { + return (services[i]); + } + } + } + return (null); + + } + + + /** + * Return the set of Services defined within this Server. + */ + public Service[] findServices() { + + return (services); + + } + + /** + * Return the JMX service names. + */ + public ObjectName[] getServiceNames() { + ObjectName onames[]=new ObjectName[ services.length ]; + for( int i=0; iServer + * out to the server.xml configuration file. + * + * @exception javax.management.InstanceNotFoundException if the managed resource object + * cannot be found + * @exception javax.management.MBeanException if the initializer of the object throws + * an exception, or persistence is not supported + * @exception javax.management.RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ + public synchronized void storeConfig() throws Exception { + + ObjectName sname = null; + try { + sname = new ObjectName("Catalina:type=StoreConfig"); + if(mserver.isRegistered(sname)) { + mserver.invoke(sname, "storeConfig", null, null); + } else + log.error("StoreConfig mbean not registered" + sname); + } catch (Throwable t) { + log.error(t); + } + + } + + + /** + * Write the configuration information for Context + * out to the specified configuration file. + * + * @exception javax.management.InstanceNotFoundException if the managed resource object + * cannot be found + * @exception javax.management.MBeanException if the initializer of the object throws + * an exception, or persistence is not supported + * @exception javax.management.RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ + public synchronized void storeContext(Context context) throws Exception { + + ObjectName sname = null; + try { + sname = new ObjectName("Catalina:type=StoreConfig"); + if(mserver.isRegistered(sname)) { + mserver.invoke(sname, "store", + new Object[] {context}, + new String [] { "java.lang.String"}); + } else + log.error("StoreConfig mbean not registered" + sname); + } catch (Throwable t) { + log.error(t); + } + + } + + + /** + * Return true if naming should be used. + */ + private boolean isUseNaming() { + boolean useNaming = true; + // Reading the "catalina.useNaming" environment variable + String useNamingProperty = System.getProperty("catalina.useNaming"); + if ((useNamingProperty != null) + && (useNamingProperty.equals("false"))) { + useNaming = false; + } + return useNaming; + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a LifecycleEvent listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a LifecycleEvent listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called before any of the public + * methods of this component are utilized. It should also send a + * LifecycleEvent of type START_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) { + log.debug(sm.getString("standardServer.start.started")); + return; + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null); + + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Start our defined Services + synchronized (services) { + for (int i = 0; i < services.length; i++) { + if (services[i] instanceof Lifecycle) + ((Lifecycle) services[i]).start(); + } + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. It should also send a LifecycleEvent + * of type STOP_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + return; + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null); + + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Stop our defined Services + for (int i = 0; i < services.length; i++) { + if (services[i] instanceof Lifecycle) + ((Lifecycle) services[i]).stop(); + } + + // Notify our interested LifecycleListeners + lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null); + + } + + public void init() throws Exception { + initialize(); + } + + /** + * Invoke a pre-startup initialization. This is used to allow connectors + * to bind to restricted ports under Unix operating environments. + */ + public void initialize() + throws LifecycleException + { + if (initialized) { + log.info(sm.getString("standardServer.initialize.initialized")); + return; + } + lifecycle.fireLifecycleEvent(INIT_EVENT, null); + initialized = true; + + if( oname==null ) { + try { + oname=new ObjectName( "Catalina:type=Server"); + Registry.getRegistry(null, null) + .registerComponent(this, oname, null ); + } catch (Exception e) { + log.error("Error registering ",e); + } + } + + // Register global String cache + try { + ObjectName oname2 = + new ObjectName(oname.getDomain() + ":type=StringCache"); + Registry.getRegistry(null, null) + .registerComponent(new StringCache(), oname2, null ); + } catch (Exception e) { + log.error("Error registering ",e); + } + + // Initialize our defined Services + for (int i = 0; i < services.length; i++) { + services[i].initialize(); + } + } + + protected String type; + protected String domain; + protected String suffix; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + +} diff --git a/java/org/apache/catalina/core/StandardService.java b/java/org/apache/catalina/core/StandardService.java index 707c823cc..7b17adb43 100644 --- a/java/org/apache/catalina/core/StandardService.java +++ b/java/org/apache/catalina/core/StandardService.java @@ -1,630 +1,630 @@ -/* - * Copyright 1999-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import org.apache.catalina.Container; -import org.apache.catalina.Engine; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Server; -import org.apache.catalina.Service; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Standard implementation of the Service interface. The - * associated Container is generally an instance of Engine, but this is - * not required. - * - * @author Craig R. McClanahan - */ - -public class StandardService - implements Lifecycle, Service, MBeanRegistration - { - private static Log log = LogFactory.getLog(StandardService.class); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Descriptive information about this component implementation. - */ - private static final String info = - "org.apache.catalina.core.StandardService/1.0"; - - - /** - * The name of this service. - */ - private String name = null; - - - /** - * The lifecycle event support for this component. - */ - private LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - /** - * The Server that owns this Service, if any. - */ - private Server server = null; - - /** - * Has this component been started? - */ - private boolean started = false; - - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - /** - * The set of Connectors associated with this Service. - */ - protected Connector connectors[] = new Connector[0]; - - - /** - * The Container associated with this Service. (In the case of the - * org.apache.catalina.startup.Embedded subclass, this holds the most - * recently added Engine.) - */ - protected Container container = null; - - - /** - * Has this component been initialized? - */ - protected boolean initialized = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Container that handles requests for all - * Connectors associated with this Service. - */ - public Container getContainer() { - - return (this.container); - - } - - - /** - * Set the Container that handles requests for all - * Connectors associated with this Service. - * - * @param container The new Container - */ - public void setContainer(Container container) { - - Container oldContainer = this.container; - if ((oldContainer != null) && (oldContainer instanceof Engine)) - ((Engine) oldContainer).setService(null); - this.container = container; - if ((this.container != null) && (this.container instanceof Engine)) - ((Engine) this.container).setService(this); - if (started && (this.container != null) && - (this.container instanceof Lifecycle)) { - try { - ((Lifecycle) this.container).start(); - } catch (LifecycleException e) { - ; - } - } - synchronized (connectors) { - for (int i = 0; i < connectors.length; i++) - connectors[i].setContainer(this.container); - } - if (started && (oldContainer != null) && - (oldContainer instanceof Lifecycle)) { - try { - ((Lifecycle) oldContainer).stop(); - } catch (LifecycleException e) { - ; - } - } - - // Report this property change to interested listeners - support.firePropertyChange("container", oldContainer, this.container); - - } - - public ObjectName getContainerName() { - if( container instanceof ContainerBase ) { - return ((ContainerBase)container).getJmxName(); - } - return null; - } - - - /** - * Return descriptive information about this Service implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the name of this Service. - */ - public String getName() { - - return (this.name); - - } - - - /** - * Set the name of this Service. - * - * @param name The new service name - */ - public void setName(String name) { - - this.name = name; - - } - - - /** - * Return the Server with which we are associated (if any). - */ - public Server getServer() { - - return (this.server); - - } - - - /** - * Set the Server with which we are associated (if any). - * - * @param server The server that owns this Service - */ - public void setServer(Server server) { - - this.server = server; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new Connector to the set of defined Connectors, and associate it - * with this Service's Container. - * - * @param connector The Connector to be added - */ - public void addConnector(Connector connector) { - - synchronized (connectors) { - connector.setContainer(this.container); - connector.setService(this); - Connector results[] = new Connector[connectors.length + 1]; - System.arraycopy(connectors, 0, results, 0, connectors.length); - results[connectors.length] = connector; - connectors = results; - - if (initialized) { - try { - connector.initialize(); - } catch (LifecycleException e) { - log.error("Connector.initialize", e); - } - } - - if (started && (connector instanceof Lifecycle)) { - try { - ((Lifecycle) connector).start(); - } catch (LifecycleException e) { - log.error("Connector.start", e); - } - } - - // Report this property change to interested listeners - support.firePropertyChange("connector", null, connector); - } - - } - - public ObjectName[] getConnectorNames() { - ObjectName results[] = new ObjectName[connectors.length]; - for( int i=0; iService interface. The + * associated Container is generally an instance of Engine, but this is + * not required. + * + * @author Craig R. McClanahan + */ + +public class StandardService + implements Lifecycle, Service, MBeanRegistration + { + private static Log log = LogFactory.getLog(StandardService.class); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Descriptive information about this component implementation. + */ + private static final String info = + "org.apache.catalina.core.StandardService/1.0"; + + + /** + * The name of this service. + */ + private String name = null; + + + /** + * The lifecycle event support for this component. + */ + private LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + /** + * The Server that owns this Service, if any. + */ + private Server server = null; + + /** + * Has this component been started? + */ + private boolean started = false; + + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + /** + * The set of Connectors associated with this Service. + */ + protected Connector connectors[] = new Connector[0]; + + + /** + * The Container associated with this Service. (In the case of the + * org.apache.catalina.startup.Embedded subclass, this holds the most + * recently added Engine.) + */ + protected Container container = null; + + + /** + * Has this component been initialized? + */ + protected boolean initialized = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Container that handles requests for all + * Connectors associated with this Service. + */ + public Container getContainer() { + + return (this.container); + + } + + + /** + * Set the Container that handles requests for all + * Connectors associated with this Service. + * + * @param container The new Container + */ + public void setContainer(Container container) { + + Container oldContainer = this.container; + if ((oldContainer != null) && (oldContainer instanceof Engine)) + ((Engine) oldContainer).setService(null); + this.container = container; + if ((this.container != null) && (this.container instanceof Engine)) + ((Engine) this.container).setService(this); + if (started && (this.container != null) && + (this.container instanceof Lifecycle)) { + try { + ((Lifecycle) this.container).start(); + } catch (LifecycleException e) { + ; + } + } + synchronized (connectors) { + for (int i = 0; i < connectors.length; i++) + connectors[i].setContainer(this.container); + } + if (started && (oldContainer != null) && + (oldContainer instanceof Lifecycle)) { + try { + ((Lifecycle) oldContainer).stop(); + } catch (LifecycleException e) { + ; + } + } + + // Report this property change to interested listeners + support.firePropertyChange("container", oldContainer, this.container); + + } + + public ObjectName getContainerName() { + if( container instanceof ContainerBase ) { + return ((ContainerBase)container).getJmxName(); + } + return null; + } + + + /** + * Return descriptive information about this Service implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the name of this Service. + */ + public String getName() { + + return (this.name); + + } + + + /** + * Set the name of this Service. + * + * @param name The new service name + */ + public void setName(String name) { + + this.name = name; + + } + + + /** + * Return the Server with which we are associated (if any). + */ + public Server getServer() { + + return (this.server); + + } + + + /** + * Set the Server with which we are associated (if any). + * + * @param server The server that owns this Service + */ + public void setServer(Server server) { + + this.server = server; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new Connector to the set of defined Connectors, and associate it + * with this Service's Container. + * + * @param connector The Connector to be added + */ + public void addConnector(Connector connector) { + + synchronized (connectors) { + connector.setContainer(this.container); + connector.setService(this); + Connector results[] = new Connector[connectors.length + 1]; + System.arraycopy(connectors, 0, results, 0, connectors.length); + results[connectors.length] = connector; + connectors = results; + + if (initialized) { + try { + connector.initialize(); + } catch (LifecycleException e) { + log.error("Connector.initialize", e); + } + } + + if (started && (connector instanceof Lifecycle)) { + try { + ((Lifecycle) connector).start(); + } catch (LifecycleException e) { + log.error("Connector.start", e); + } + } + + // Report this property change to interested listeners + support.firePropertyChange("connector", null, connector); + } + + } + + public ObjectName[] getConnectorNames() { + ObjectName results[] = new ObjectName[connectors.length]; + for( int i=0; iWrapper interface that represents - * an individual servlet definition. No child Containers are allowed, and - * the parent Container must be a Context. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 345286 $ $Date: 2005-11-17 18:00:24 +0100 (jeu., 17 nov. 2005) $ - */ -public class StandardWrapper - extends ContainerBase - implements ServletConfig, Wrapper, NotificationEmitter { - - protected static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( StandardWrapper.class ); - - protected static final String[] DEFAULT_SERVLET_METHODS = new String[] { - "GET", "HEAD", "POST" }; - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new StandardWrapper component with the default basic Valve. - */ - public StandardWrapper() { - - super(); - swValve=new StandardWrapperValve(); - pipeline.setBasic(swValve); - broadcaster = new NotificationBroadcasterSupport(); - - if (restrictedServlets == null) { - restrictedServlets = new Properties(); - try { - InputStream is = - this.getClass().getClassLoader().getResourceAsStream - ("org/apache/catalina/core/RestrictedServlets.properties"); - if (is != null) { - restrictedServlets.load(is); - } else { - log.error(sm.getString("standardWrapper.restrictedServletsResources")); - } - } catch (IOException e) { - log.error(sm.getString("standardWrapper.restrictedServletsResources"), e); - } - } - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The date and time at which this servlet will become available (in - * milliseconds since the epoch), or zero if the servlet is available. - * If this value equals Long.MAX_VALUE, the unavailability of this - * servlet is considered permanent. - */ - protected long available = 0L; - - /** - * The broadcaster that sends j2ee notifications. - */ - protected NotificationBroadcasterSupport broadcaster = null; - - /** - * The count of allocations that are currently active (even if they - * are for the same instance, as will be true on a non-STM servlet). - */ - protected int countAllocated = 0; - - - /** - * The facade associated with this wrapper. - */ - protected StandardWrapperFacade facade = - new StandardWrapperFacade(this); - - - /** - * The descriptive information string for this implementation. - */ - protected static final String info = - "org.apache.catalina.core.StandardWrapper/1.0"; - - - /** - * The (single) initialized instance of this servlet. - */ - protected Servlet instance = null; - - - /** - * The support object for our instance listeners. - */ - protected InstanceSupport instanceSupport = new InstanceSupport(this); - - - /** - * The context-relative URI of the JSP file for this servlet. - */ - protected String jspFile = null; - - - /** - * The load-on-startup order value (negative value means load on - * first call) for this servlet. - */ - protected int loadOnStartup = -1; - - - /** - * Mappings associated with the wrapper. - */ - protected ArrayList mappings = new ArrayList(); - - - /** - * The initialization parameters for this servlet, keyed by - * parameter name. - */ - protected HashMap parameters = new HashMap(); - - - /** - * The security role references for this servlet, keyed by role name - * used in the servlet. The corresponding value is the role name of - * the web application itself. - */ - protected HashMap references = new HashMap(); - - - /** - * The run-as identity for this servlet. - */ - protected String runAs = null; - - /** - * The notification sequence number. - */ - protected long sequenceNumber = 0; - - /** - * The fully qualified servlet class name for this servlet. - */ - protected String servletClass = null; - - - /** - * Does this servlet implement the SingleThreadModel interface? - */ - protected boolean singleThreadModel = false; - - - /** - * Are we unloading our servlet instance at the moment? - */ - protected boolean unloading = false; - - - /** - * Maximum number of STM instances. - */ - protected int maxInstances = 20; - - - /** - * Number of instances currently loaded for a STM servlet. - */ - protected int nInstances = 0; - - - /** - * Stack containing the STM instances. - */ - protected Stack instancePool = null; - - - /** - * Wait time for servlet unload in ms. - */ - protected long unloadDelay = 2000; - - - /** - * True if this StandardWrapper is for the JspServlet - */ - protected boolean isJspServlet; - - - /** - * The ObjectName of the JSP monitoring mbean - */ - protected ObjectName jspMonitorON; - - - /** - * Should we swallow System.out - */ - protected boolean swallowOutput = false; - - // To support jmx attributes - protected StandardWrapperValve swValve; - protected long loadTime=0; - protected int classLoadTime=0; - - /** - * Static class array used when the SecurityManager is turned on and - * Servlet.init is invoked. - */ - protected static Class[] classType = new Class[]{ServletConfig.class}; - - - /** - * Static class array used when the SecurityManager is turned on and - * Servlet.service is invoked. - */ - protected static Class[] classTypeUsedInService = new Class[]{ - ServletRequest.class, - ServletResponse.class}; - - /** - * Restricted servlets (which can only be loaded by a privileged webapp). - */ - protected static Properties restrictedServlets = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the available date/time for this servlet, in milliseconds since - * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean - * that unavailability is permanent and any request for this servlet will return - * an SC_NOT_FOUND error. If this date/time is in the future, any request for - * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, - * the servlet is currently available. - */ - public long getAvailable() { - - return (this.available); - - } - - - /** - * Set the available date/time for this servlet, in milliseconds since the - * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean - * that unavailability is permanent and any request for this servlet will return - * an SC_NOT_FOUND error. If this date/time is in the future, any request for - * this servlet will return an SC_SERVICE_UNAVAILABLE error. - * - * @param available The new available date/time - */ - public void setAvailable(long available) { - - long oldAvailable = this.available; - if (available > System.currentTimeMillis()) - this.available = available; - else - this.available = 0L; - support.firePropertyChange("available", new Long(oldAvailable), - new Long(this.available)); - - } - - - /** - * Return the number of active allocations of this servlet, even if they - * are all for the same instance (as will be true for servlets that do - * not implement SingleThreadModel. - */ - public int getCountAllocated() { - - return (this.countAllocated); - - } - - - public String getEngineName() { - return ((StandardContext)getParent()).getEngineName(); - } - - - /** - * Return descriptive information about this Container implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the InstanceSupport object for this Wrapper instance. - */ - public InstanceSupport getInstanceSupport() { - - return (this.instanceSupport); - - } - - - /** - * Return the context-relative URI of the JSP file for this servlet. - */ - public String getJspFile() { - - return (this.jspFile); - - } - - - /** - * Set the context-relative URI of the JSP file for this servlet. - * - * @param jspFile JSP file URI - */ - public void setJspFile(String jspFile) { - - String oldJspFile = this.jspFile; - this.jspFile = jspFile; - support.firePropertyChange("jspFile", oldJspFile, this.jspFile); - - // Each jsp-file needs to be represented by its own JspServlet and - // corresponding JspMonitoring mbean, because it may be initialized - // with its own init params - isJspServlet = true; - - } - - - /** - * Return the load-on-startup order value (negative value means - * load on first call). - */ - public int getLoadOnStartup() { - - if (isJspServlet && loadOnStartup < 0) { - /* - * JspServlet must always be preloaded, because its instance is - * used during registerJMX (when registering the JSP - * monitoring mbean) - */ - return Integer.MAX_VALUE; - } else { - return (this.loadOnStartup); - } - } - - - /** - * Set the load-on-startup order value (negative value means - * load on first call). - * - * @param value New load-on-startup value - */ - public void setLoadOnStartup(int value) { - - int oldLoadOnStartup = this.loadOnStartup; - this.loadOnStartup = value; - support.firePropertyChange("loadOnStartup", - new Integer(oldLoadOnStartup), - new Integer(this.loadOnStartup)); - - } - - - - /** - * Set the load-on-startup order value from a (possibly null) string. - * Per the specification, any missing or non-numeric value is converted - * to a zero, so that this servlet will still be loaded at startup - * time, but in an arbitrary order. - * - * @param value New load-on-startup value - */ - public void setLoadOnStartupString(String value) { - - try { - setLoadOnStartup(Integer.parseInt(value)); - } catch (NumberFormatException e) { - setLoadOnStartup(0); - } - } - - public String getLoadOnStartupString() { - return Integer.toString( getLoadOnStartup()); - } - - - /** - * Return maximum number of instances that will be allocated when a single - * thread model servlet is used. - */ - public int getMaxInstances() { - - return (this.maxInstances); - - } - - - /** - * Set the maximum number of instances that will be allocated when a single - * thread model servlet is used. - * - * @param maxInstances New value of maxInstances - */ - public void setMaxInstances(int maxInstances) { - - int oldMaxInstances = this.maxInstances; - this.maxInstances = maxInstances; - support.firePropertyChange("maxInstances", oldMaxInstances, - this.maxInstances); - - } - - - /** - * Set the parent Container of this Wrapper, but only if it is a Context. - * - * @param container Proposed parent Container - */ - public void setParent(Container container) { - - if ((container != null) && - !(container instanceof Context)) - throw new IllegalArgumentException - (sm.getString("standardWrapper.notContext")); - if (container instanceof StandardContext) { - swallowOutput = ((StandardContext)container).getSwallowOutput(); - unloadDelay = ((StandardContext)container).getUnloadDelay(); - } - super.setParent(container); - - } - - - /** - * Return the run-as identity for this servlet. - */ - public String getRunAs() { - - return (this.runAs); - - } - - - /** - * Set the run-as identity for this servlet. - * - * @param runAs New run-as identity value - */ - public void setRunAs(String runAs) { - - String oldRunAs = this.runAs; - this.runAs = runAs; - support.firePropertyChange("runAs", oldRunAs, this.runAs); - - } - - - /** - * Return the fully qualified servlet class name for this servlet. - */ - public String getServletClass() { - - return (this.servletClass); - - } - - - /** - * Set the fully qualified servlet class name for this servlet. - * - * @param servletClass Servlet class name - */ - public void setServletClass(String servletClass) { - - String oldServletClass = this.servletClass; - this.servletClass = servletClass; - support.firePropertyChange("servletClass", oldServletClass, - this.servletClass); - if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) { - isJspServlet = true; - } - } - - - - /** - * Set the name of this servlet. This is an alias for the normal - * Container.setName() method, and complements the - * getServletName() method required by the - * ServletConfig interface. - * - * @param name The new name of this servlet - */ - public void setServletName(String name) { - - setName(name); - - } - - - /** - * Return true if the servlet class represented by this - * component implements the SingleThreadModel interface. - */ - public boolean isSingleThreadModel() { - - try { - loadServlet(); - } catch (Throwable t) { - ; - } - return (singleThreadModel); - - } - - - /** - * Is this servlet currently unavailable? - */ - public boolean isUnavailable() { - - if (available == 0L) - return (false); - else if (available <= System.currentTimeMillis()) { - available = 0L; - return (false); - } else - return (true); - - } - - - /** - * Gets the names of the methods supported by the underlying servlet. - * - * This is the same set of methods included in the Allow response header - * in response to an OPTIONS request method processed by the underlying - * servlet. - * - * @return Array of names of the methods supported by the underlying - * servlet - */ - public String[] getServletMethods() throws ServletException { - - Class servletClazz = loadServlet().getClass(); - if (!javax.servlet.http.HttpServlet.class.isAssignableFrom( - servletClazz)) { - return DEFAULT_SERVLET_METHODS; - } - - HashSet allow = new HashSet(); - allow.add("TRACE"); - allow.add("OPTIONS"); - - Method[] methods = getAllDeclaredMethods(servletClazz); - for (int i=0; methods != null && iservice() method called. If the servlet class does - * not implement SingleThreadModel, the (only) initialized - * instance may be returned immediately. If the servlet class implements - * SingleThreadModel, the Wrapper implementation must ensure - * that this instance is not allocated again until it is deallocated by a - * call to deallocate(). - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if a loading error occurs - */ - public Servlet allocate() throws ServletException { - - // If we are currently unloading this servlet, throw an exception - if (unloading) - throw new ServletException - (sm.getString("standardWrapper.unloading", getName())); - - // If not SingleThreadedModel, return the same instance every time - if (!singleThreadModel) { - - // Load and initialize our instance if necessary - if (instance == null) { - synchronized (this) { - if (instance == null) { - try { - if (log.isDebugEnabled()) - log.debug("Allocating non-STM instance"); - - instance = loadServlet(); - } catch (ServletException e) { - throw e; - } catch (Throwable e) { - throw new ServletException - (sm.getString("standardWrapper.allocate"), e); - } - } - } - } - - if (!singleThreadModel) { - if (log.isTraceEnabled()) - log.trace(" Returning non-STM instance"); - countAllocated++; - return (instance); - } - - } - - synchronized (instancePool) { - - while (countAllocated >= nInstances) { - // Allocate a new instance if possible, or else wait - if (nInstances < maxInstances) { - try { - instancePool.push(loadServlet()); - nInstances++; - } catch (ServletException e) { - throw e; - } catch (Throwable e) { - throw new ServletException - (sm.getString("standardWrapper.allocate"), e); - } - } else { - try { - instancePool.wait(); - } catch (InterruptedException e) { - ; - } - } - } - if (log.isTraceEnabled()) - log.trace(" Returning allocated STM instance"); - countAllocated++; - return (Servlet) instancePool.pop(); - - } - - } - - - /** - * Return this previously allocated servlet to the pool of available - * instances. If this servlet class does not implement SingleThreadModel, - * no action is actually required. - * - * @param servlet The servlet to be returned - * - * @exception ServletException if a deallocation error occurs - */ - public void deallocate(Servlet servlet) throws ServletException { - - // If not SingleThreadModel, no action is required - if (!singleThreadModel) { - countAllocated--; - return; - } - - // Unlock and free this instance - synchronized (instancePool) { - countAllocated--; - instancePool.push(servlet); - instancePool.notify(); - } - - } - - - /** - * Return the value for the specified initialization parameter name, - * if any; otherwise return null. - * - * @param name Name of the requested initialization parameter - */ - public String findInitParameter(String name) { - - synchronized (parameters) { - return ((String) parameters.get(name)); - } - - } - - - /** - * Return the names of all defined initialization parameters for this - * servlet. - */ - public String[] findInitParameters() { - - synchronized (parameters) { - String results[] = new String[parameters.size()]; - return ((String[]) parameters.keySet().toArray(results)); - } - - } - - - /** - * Return the mappings associated with this wrapper. - */ - public String[] findMappings() { - - synchronized (mappings) { - return (String[]) mappings.toArray(new String[mappings.size()]); - } - - } - - - /** - * Return the security role link for the specified security role - * reference name, if any; otherwise return null. - * - * @param name Security role reference used within this servlet - */ - public String findSecurityReference(String name) { - - synchronized (references) { - return ((String) references.get(name)); - } - - } - - - /** - * Return the set of security role reference names associated with - * this servlet, if any; otherwise return a zero-length array. - */ - public String[] findSecurityReferences() { - - synchronized (references) { - String results[] = new String[references.size()]; - return ((String[]) references.keySet().toArray(results)); - } - - } - - - /** - * FIXME: Fooling introspection ... - */ - public Wrapper findMappingObject() { - return (Wrapper) getMappingObject(); - } - - - /** - * Load and initialize an instance of this servlet, if there is not already - * at least one initialized instance. This can be used, for example, to - * load servlets that are marked in the deployment descriptor to be loaded - * at server startup time. - *

    - * IMPLEMENTATION NOTE: Servlets whose classnames begin with - * org.apache.catalina. (so-called "container" servlets) - * are loaded by the same classloader that loaded this class, rather than - * the classloader for the current web application. - * This gives such classes access to Catalina internals, which are - * prevented for classes loaded for web applications. - * - * @exception ServletException if the servlet init() method threw - * an exception - * @exception ServletException if some other loading problem occurs - */ - public synchronized void load() throws ServletException { - instance = loadServlet(); - } - - - /** - * Load and initialize an instance of this servlet, if there is not already - * at least one initialized instance. This can be used, for example, to - * load servlets that are marked in the deployment descriptor to be loaded - * at server startup time. - */ - public synchronized Servlet loadServlet() throws ServletException { - - // Nothing to do if we already have an instance or an instance pool - if (!singleThreadModel && (instance != null)) - return instance; - - PrintStream out = System.out; - if (swallowOutput) { - SystemLogHandler.startCapture(); - } - - Servlet servlet; - try { - long t1=System.currentTimeMillis(); - // If this "servlet" is really a JSP file, get the right class. - // HOLD YOUR NOSE - this is a kludge that avoids having to do special - // case Catalina-specific code in Jasper - it also requires that the - // servlet path be replaced by the element content in - // order to be completely effective - String actualClass = servletClass; - if ((actualClass == null) && (jspFile != null)) { - Wrapper jspWrapper = (Wrapper) - ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME); - if (jspWrapper != null) { - actualClass = jspWrapper.getServletClass(); - // Merge init parameters - String paramNames[] = jspWrapper.findInitParameters(); - for (int i = 0; i < paramNames.length; i++) { - if (parameters.get(paramNames[i]) == null) { - parameters.put - (paramNames[i], - jspWrapper.findInitParameter(paramNames[i])); - } - } - } - } - - // Complain if no servlet class has been specified - if (actualClass == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.notClass", getName())); - } - - // Acquire an instance of the class loader to be used - Loader loader = getLoader(); - if (loader == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.missingLoader", getName())); - } - - ClassLoader classLoader = loader.getClassLoader(); - - // Special case class loader for a container provided servlet - // - if (isContainerProvidedServlet(actualClass) && - ! ((Context)getParent()).getPrivileged() ) { - // If it is a priviledged context - using its own - // class loader will work, since it's a child of the container - // loader - classLoader = this.getClass().getClassLoader(); - } - - // Load the specified servlet class from the appropriate class loader - Class classClass = null; - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - final ClassLoader fclassLoader = classLoader; - final String factualClass = actualClass; - try{ - classClass = (Class)AccessController.doPrivileged( - new PrivilegedExceptionAction(){ - public Object run() throws Exception{ - if (fclassLoader != null) { - return fclassLoader.loadClass(factualClass); - } else { - return Class.forName(factualClass); - } - } - }); - } catch(PrivilegedActionException pax){ - Exception ex = pax.getException(); - if (ex instanceof ClassNotFoundException){ - throw (ClassNotFoundException)ex; - } else { - getServletContext().log( "Error loading " - + fclassLoader + " " + factualClass, ex ); - } - } - } else { - if (classLoader != null) { - classClass = classLoader.loadClass(actualClass); - } else { - classClass = Class.forName(actualClass); - } - } - } catch (ClassNotFoundException e) { - unavailable(null); - getServletContext().log( "Error loading " + classLoader + " " + actualClass, e ); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass), - e); - } - - if (classClass == null) { - unavailable(null); - throw new ServletException - (sm.getString("standardWrapper.missingClass", actualClass)); - } - - // Instantiate and initialize an instance of the servlet class itself - try { - servlet = (Servlet) classClass.newInstance(); - // Annotation processing - if (!((Context) getParent()).getIgnoreAnnotations()) { - if (getParent() instanceof StandardContext - && ((StandardContext) getParent()).getNamingContextListener() != null) { - AnnotationProcessor.injectNamingResources - (((StandardContext) getParent()).getNamingContextListener().getEnvContext(), servlet); - } - AnnotationProcessor.postConstruct(servlet); - } - } catch (ClassCastException e) { - unavailable(null); - // Restore the context ClassLoader - throw new ServletException - (sm.getString("standardWrapper.notServlet", actualClass), e); - } catch (Throwable e) { - unavailable(null); - - // Added extra log statement for Bugzilla 36630: - // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 - if(log.isDebugEnabled()) { - log.debug(sm.getString("standardWrapper.instantiate", actualClass), e); - } - - // Restore the context ClassLoader - throw new ServletException - (sm.getString("standardWrapper.instantiate", actualClass), e); - } - - // Check if loading the servlet in this web application should be - // allowed - if (!isServletAllowed(servlet)) { - throw new SecurityException - (sm.getString("standardWrapper.privilegedServlet", - actualClass)); - } - - // Special handling for ContainerServlet instances - if ((servlet instanceof ContainerServlet) && - (isContainerProvidedServlet(actualClass) || - ((Context)getParent()).getPrivileged() )) { - ((ContainerServlet) servlet).setWrapper(this); - } - - classLoadTime=(int) (System.currentTimeMillis() -t1); - // Call the initialization method of this servlet - try { - instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, - servlet); - - if( System.getSecurityManager() != null) { - - Object[] args = new Object[]{((ServletConfig)facade)}; - SecurityUtil.doAsPrivilege("init", - servlet, - classType, - args); - args = null; - } else { - servlet.init(facade); - } - - // Invoke jspInit on JSP pages - if ((loadOnStartup >= 0) && (jspFile != null)) { - // Invoking jspInit - DummyRequest req = new DummyRequest(); - req.setServletPath(jspFile); - req.setQueryString("jsp_precompile=true"); - DummyResponse res = new DummyResponse(); - - if( System.getSecurityManager() != null) { - Object[] args = new Object[]{req, res}; - SecurityUtil.doAsPrivilege("service", - servlet, - classTypeUsedInService, - args); - args = null; - } else { - servlet.service(req, res); - } - } - instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, - servlet); - } catch (UnavailableException f) { - instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, - servlet, f); - unavailable(f); - throw f; - } catch (ServletException f) { - instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, - servlet, f); - // If the servlet wanted to be unavailable it would have - // said so, so do not call unavailable(null). - throw f; - } catch (Throwable f) { - getServletContext().log("StandardWrapper.Throwable", f ); - instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, - servlet, f); - // If the servlet wanted to be unavailable it would have - // said so, so do not call unavailable(null). - throw new ServletException - (sm.getString("standardWrapper.initException", getName()), f); - } - - // Register our newly initialized instance - singleThreadModel = servlet instanceof SingleThreadModel; - if (singleThreadModel) { - if (instancePool == null) - instancePool = new Stack(); - } - fireContainerEvent("load", this); - - loadTime=System.currentTimeMillis() -t1; - } finally { - if (swallowOutput) { - String log = SystemLogHandler.stopCapture(); - if (log != null && log.length() > 0) { - if (getServletContext() != null) { - getServletContext().log(log); - } else { - out.println(log); - } - } - } - } - return servlet; - - } - - - /** - * Remove the specified initialization parameter from this servlet. - * - * @param name Name of the initialization parameter to remove - */ - public void removeInitParameter(String name) { - - synchronized (parameters) { - parameters.remove(name); - } - fireContainerEvent("removeInitParameter", name); - - } - - - /** - * Remove a listener no longer interested in InstanceEvents. - * - * @param listener The listener to remove - */ - public void removeInstanceListener(InstanceListener listener) { - - instanceSupport.removeInstanceListener(listener); - - } - - - /** - * Remove a mapping associated with the wrapper. - * - * @param mapping The pattern to remove - */ - public void removeMapping(String mapping) { - - synchronized (mappings) { - mappings.remove(mapping); - } - fireContainerEvent("removeMapping", mapping); - - } - - - /** - * Remove any security role reference for the specified role name. - * - * @param name Security role used within this servlet to be removed - */ - public void removeSecurityReference(String name) { - - synchronized (references) { - references.remove(name); - } - fireContainerEvent("removeSecurityReference", name); - - } - - - /** - * Return a String representation of this component. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - if (getParent() != null) { - sb.append(getParent().toString()); - sb.append("."); - } - sb.append("StandardWrapper["); - sb.append(getName()); - sb.append("]"); - return (sb.toString()); - - } - - - /** - * Process an UnavailableException, marking this servlet as unavailable - * for the specified amount of time. - * - * @param unavailable The exception that occurred, or null - * to mark this servlet as permanently unavailable - */ - public void unavailable(UnavailableException unavailable) { - getServletContext().log(sm.getString("standardWrapper.unavailable", getName())); - if (unavailable == null) - setAvailable(Long.MAX_VALUE); - else if (unavailable.isPermanent()) - setAvailable(Long.MAX_VALUE); - else { - int unavailableSeconds = unavailable.getUnavailableSeconds(); - if (unavailableSeconds <= 0) - unavailableSeconds = 60; // Arbitrary default - setAvailable(System.currentTimeMillis() + - (unavailableSeconds * 1000L)); - } - - } - - - /** - * Unload all initialized instances of this servlet, after calling the - * destroy() method for each instance. This can be used, - * for example, prior to shutting down the entire servlet engine, or - * prior to reloading all of the classes from the Loader associated with - * our Loader's repository. - * - * @exception ServletException if an exception is thrown by the - * destroy() method - */ - public synchronized void unload() throws ServletException { - - // Nothing to do if we have never loaded the instance - if (!singleThreadModel && (instance == null)) - return; - unloading = true; - - // Loaf a while if the current instance is allocated - // (possibly more than once if non-STM) - if (countAllocated > 0) { - int nRetries = 0; - long delay = unloadDelay / 20; - while ((nRetries < 21) && (countAllocated > 0)) { - if ((nRetries % 10) == 0) { - log.info(sm.getString("standardWrapper.waiting", - new Integer(countAllocated))); - } - try { - Thread.sleep(delay); - } catch (InterruptedException e) { - ; - } - nRetries++; - } - } - - PrintStream out = System.out; - if (swallowOutput) { - SystemLogHandler.startCapture(); - } - - // Call the servlet destroy() method - try { - instanceSupport.fireInstanceEvent - (InstanceEvent.BEFORE_DESTROY_EVENT, instance); - - if( System.getSecurityManager() != null) { - SecurityUtil.doAsPrivilege("destroy", - instance); - SecurityUtil.remove(instance); - } else { - instance.destroy(); - } - - instanceSupport.fireInstanceEvent - (InstanceEvent.AFTER_DESTROY_EVENT, instance); - - // Annotation processing - if (!((Context) getParent()).getIgnoreAnnotations()) { - AnnotationProcessor.preDestroy(instance); - } - - } catch (Throwable t) { - instanceSupport.fireInstanceEvent - (InstanceEvent.AFTER_DESTROY_EVENT, instance, t); - instance = null; - instancePool = null; - nInstances = 0; - fireContainerEvent("unload", this); - unloading = false; - throw new ServletException - (sm.getString("standardWrapper.destroyException", getName()), - t); - } finally { - // Write captured output - if (swallowOutput) { - String log = SystemLogHandler.stopCapture(); - if (log != null && log.length() > 0) { - if (getServletContext() != null) { - getServletContext().log(log); - } else { - out.println(log); - } - } - } - } - - // Deregister the destroyed instance - instance = null; - - if (singleThreadModel && (instancePool != null)) { - try { - while (!instancePool.isEmpty()) { - Servlet s = (Servlet) instancePool.pop(); - if (System.getSecurityManager() != null) { - SecurityUtil.doAsPrivilege("destroy", s); - SecurityUtil.remove(instance); - } else { - s.destroy(); - } - // Annotation processing - if (!((Context) getParent()).getIgnoreAnnotations()) { - AnnotationProcessor.preDestroy(s); - } - } - } catch (Throwable t) { - instancePool = null; - nInstances = 0; - unloading = false; - fireContainerEvent("unload", this); - throw new ServletException - (sm.getString("standardWrapper.destroyException", - getName()), t); - } - instancePool = null; - nInstances = 0; - } - - singleThreadModel = false; - - unloading = false; - fireContainerEvent("unload", this); - - } - - - // -------------------------------------------------- ServletConfig Methods - - - /** - * Return the initialization parameter value for the specified name, - * if any; otherwise return null. - * - * @param name Name of the initialization parameter to retrieve - */ - public String getInitParameter(String name) { - - return (findInitParameter(name)); - - } - - - /** - * Return the set of initialization parameter names defined for this - * servlet. If none are defined, an empty Enumeration is returned. - */ - public Enumeration getInitParameterNames() { - - synchronized (parameters) { - return (new Enumerator(parameters.keySet())); - } - - } - - - /** - * Return the servlet context with which this servlet is associated. - */ - public ServletContext getServletContext() { - - if (parent == null) - return (null); - else if (!(parent instanceof Context)) - return (null); - else - return (((Context) parent).getServletContext()); - - } - - - /** - * Return the name of this servlet. - */ - public String getServletName() { - - return (getName()); - - } - - public long getProcessingTime() { - return swValve.getProcessingTime(); - } - - public void setProcessingTime(long processingTime) { - swValve.setProcessingTime(processingTime); - } - - public long getMaxTime() { - return swValve.getMaxTime(); - } - - public void setMaxTime(long maxTime) { - swValve.setMaxTime(maxTime); - } - - public long getMinTime() { - return swValve.getMinTime(); - } - - public void setMinTime(long minTime) { - swValve.setMinTime(minTime); - } - - public int getRequestCount() { - return swValve.getRequestCount(); - } - - public void setRequestCount(int requestCount) { - swValve.setRequestCount(requestCount); - } - - public int getErrorCount() { - return swValve.getErrorCount(); - } - - public void setErrorCount(int errorCount) { - swValve.setErrorCount(errorCount); - } - - /** - * Increment the error count used for monitoring. - */ - public void incrementErrorCount(){ - swValve.setErrorCount(swValve.getErrorCount() + 1); - } - - public long getLoadTime() { - return loadTime; - } - - public void setLoadTime(long loadTime) { - this.loadTime = loadTime; - } - - public int getClassLoadTime() { - return classLoadTime; - } - - // -------------------------------------------------------- Package Methods - - - // -------------------------------------------------------- protected Methods - - - /** - * Add a default Mapper implementation if none have been configured - * explicitly. - * - * @param mapperClass Java class name of the default Mapper - */ - protected void addDefaultMapper(String mapperClass) { - - ; // No need for a default Mapper on a Wrapper - - } - - - /** - * Return true if the specified class name represents a - * container provided servlet class that should be loaded by the - * server class loader. - * - * @param classname Name of the class to be checked - */ - protected boolean isContainerProvidedServlet(String classname) { - - if (classname.startsWith("org.apache.catalina.")) { - return (true); - } - try { - Class clazz = - this.getClass().getClassLoader().loadClass(classname); - return (ContainerServlet.class.isAssignableFrom(clazz)); - } catch (Throwable t) { - return (false); - } - - } - - - /** - * Return true if loading this servlet is allowed. - */ - protected boolean isServletAllowed(Object servlet) { - - // Privileged webapps may load all servlets without restriction - if (((Context) getParent()).getPrivileged()) { - return true; - } - - if (servlet instanceof ContainerServlet) { - return (false); - } - - Class clazz = servlet.getClass(); - while (clazz != null && !clazz.getName().equals("javax.servlet.http.HttpServlet")) { - if ("restricted".equals(restrictedServlets.getProperty(clazz.getName()))) { - return (false); - } - clazz = clazz.getSuperclass(); - } - - return (true); - - } - - - protected Method[] getAllDeclaredMethods(Class c) { - - if (c.equals(javax.servlet.http.HttpServlet.class)) { - return null; - } - - Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); - - Method[] thisMethods = c.getDeclaredMethods(); - if (thisMethods == null) { - return parentMethods; - } - - if ((parentMethods != null) && (parentMethods.length > 0)) { - Method[] allMethods = - new Method[parentMethods.length + thisMethods.length]; - System.arraycopy(parentMethods, 0, allMethods, 0, - parentMethods.length); - System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, - thisMethods.length); - - thisMethods = allMethods; - } - - return thisMethods; - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Start this component, pre-loading the servlet if the load-on-startup - * value is set appropriately. - * - * @exception LifecycleException if a fatal error occurs during startup - */ - public void start() throws LifecycleException { - - // Send j2ee.state.starting notification - if (this.getObjectName() != null) { - Notification notification = new Notification("j2ee.state.starting", - this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - // Start up this component - super.start(); - - if( oname != null ) - registerJMX((StandardContext)getParent()); - - // Load and initialize an instance of this servlet if requested - // MOVED TO StandardContext START() METHOD - - setAvailable(0L); - - // Send j2ee.state.running notification - if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.running", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - } - - - /** - * Stop this component, gracefully shutting down the servlet if it has - * been initialized. - * - * @exception LifecycleException if a fatal error occurs during shutdown - */ - public void stop() throws LifecycleException { - - setAvailable(Long.MAX_VALUE); - - // Send j2ee.state.stopping notification - if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopping", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - // Shut down our servlet instance (if it has been initialized) - try { - unload(); - } catch (ServletException e) { - getServletContext().log(sm.getString - ("standardWrapper.unloadException", getName()), e); - } - - // Shut down this component - super.stop(); - - // Send j2ee.state.stoppped notification - if (this.getObjectName() != null) { - Notification notification = - new Notification("j2ee.state.stopped", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - if( oname != null ) { - Registry.getRegistry(null, null).unregisterComponent(oname); - - // Send j2ee.object.deleted notification - Notification notification = - new Notification("j2ee.object.deleted", this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - - if (isJspServlet && jspMonitorON != null ) { - Registry.getRegistry(null, null).unregisterComponent(jspMonitorON); - } - - } - - protected void registerJMX(StandardContext ctx) { - - String parentName = ctx.getName(); - parentName = ("".equals(parentName)) ? "/" : parentName; - - String hostName = ctx.getParent().getName(); - hostName = (hostName==null) ? "DEFAULT" : hostName; - - String domain = ctx.getDomain(); - - String webMod= "//" + hostName + parentName; - String onameStr = domain + ":j2eeType=Servlet,name=" + getName() + - ",WebModule=" + webMod + ",J2EEApplication=" + - ctx.getJ2EEApplication() + ",J2EEServer=" + - ctx.getJ2EEServer(); - try { - oname=new ObjectName(onameStr); - controller=oname; - Registry.getRegistry(null, null) - .registerComponent(this, oname, null ); - - // Send j2ee.object.created notification - if (this.getObjectName() != null) { - Notification notification = new Notification( - "j2ee.object.created", - this.getObjectName(), - sequenceNumber++); - broadcaster.sendNotification(notification); - } - } catch( Exception ex ) { - log.info("Error registering servlet with jmx " + this); - } - - if (isJspServlet) { - // Register JSP monitoring mbean - onameStr = domain + ":type=JspMonitor,name=" + getName() - + ",WebModule=" + webMod - + ",J2EEApplication=" + ctx.getJ2EEApplication() - + ",J2EEServer=" + ctx.getJ2EEServer(); - try { - jspMonitorON = new ObjectName(onameStr); - Registry.getRegistry(null, null) - .registerComponent(instance, jspMonitorON, null); - } catch( Exception ex ) { - log.info("Error registering JSP monitoring with jmx " + - instance); - } - } - } - - - /* Remove a JMX notficationListener - * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) - */ - public void removeNotificationListener(NotificationListener listener, - NotificationFilter filter, Object object) throws ListenerNotFoundException { - broadcaster.removeNotificationListener(listener,filter,object); - - } - - protected MBeanNotificationInfo[] notificationInfo; - - /* Get JMX Broadcaster Info - * @TODO use StringManager for international support! - * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! - * @see javax.management.NotificationBroadcaster#getNotificationInfo() - */ - public MBeanNotificationInfo[] getNotificationInfo() { - - if(notificationInfo == null) { - notificationInfo = new MBeanNotificationInfo[]{ - new MBeanNotificationInfo(new String[] { - "j2ee.object.created"}, - Notification.class.getName(), - "servlet is created" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.starting"}, - Notification.class.getName(), - "servlet is starting" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.running"}, - Notification.class.getName(), - "servlet is running" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.state.stopped"}, - Notification.class.getName(), - "servlet start to stopped" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.object.stopped"}, - Notification.class.getName(), - "servlet is stopped" - ), - new MBeanNotificationInfo(new String[] { - "j2ee.object.deleted"}, - Notification.class.getName(), - "servlet is deleted" - ) - }; - - } - - return notificationInfo; - } - - - /* Add a JMX-NotificationListener - * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) - */ - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, Object object) throws IllegalArgumentException { - broadcaster.addNotificationListener(listener,filter,object); - } - - - /** - * Remove a JMX-NotificationListener - * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) - */ - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException { - broadcaster.removeNotificationListener(listener); - } - - - // ------------------------------------------------------------- Attributes - - - public boolean isEventProvider() { - return false; - } - - public boolean isStateManageable() { - return false; - } - - public boolean isStatisticsProvider() { - return false; - } - - -} +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + +import java.lang.reflect.Method; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintStream; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Properties; +import java.util.Stack; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.SingleThreadModel; +import javax.servlet.UnavailableException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +import org.apache.catalina.Container; +import org.apache.catalina.ContainerServlet; +import org.apache.catalina.Context; +import org.apache.catalina.InstanceEvent; +import org.apache.catalina.InstanceListener; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Loader; +import org.apache.catalina.Wrapper; +import org.apache.catalina.security.SecurityUtil; +import org.apache.catalina.util.AnnotationProcessor; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.InstanceSupport; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.log.SystemLogHandler; +import org.apache.tomcat.util.modeler.Registry; + +/** + * Standard implementation of the Wrapper interface that represents + * an individual servlet definition. No child Containers are allowed, and + * the parent Container must be a Context. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 345286 $ $Date: 2005-11-17 18:00:24 +0100 (jeu., 17 nov. 2005) $ + */ +public class StandardWrapper + extends ContainerBase + implements ServletConfig, Wrapper, NotificationEmitter { + + protected static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( StandardWrapper.class ); + + protected static final String[] DEFAULT_SERVLET_METHODS = new String[] { + "GET", "HEAD", "POST" }; + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new StandardWrapper component with the default basic Valve. + */ + public StandardWrapper() { + + super(); + swValve=new StandardWrapperValve(); + pipeline.setBasic(swValve); + broadcaster = new NotificationBroadcasterSupport(); + + if (restrictedServlets == null) { + restrictedServlets = new Properties(); + try { + InputStream is = + this.getClass().getClassLoader().getResourceAsStream + ("org/apache/catalina/core/RestrictedServlets.properties"); + if (is != null) { + restrictedServlets.load(is); + } else { + log.error(sm.getString("standardWrapper.restrictedServletsResources")); + } + } catch (IOException e) { + log.error(sm.getString("standardWrapper.restrictedServletsResources"), e); + } + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The date and time at which this servlet will become available (in + * milliseconds since the epoch), or zero if the servlet is available. + * If this value equals Long.MAX_VALUE, the unavailability of this + * servlet is considered permanent. + */ + protected long available = 0L; + + /** + * The broadcaster that sends j2ee notifications. + */ + protected NotificationBroadcasterSupport broadcaster = null; + + /** + * The count of allocations that are currently active (even if they + * are for the same instance, as will be true on a non-STM servlet). + */ + protected int countAllocated = 0; + + + /** + * The facade associated with this wrapper. + */ + protected StandardWrapperFacade facade = + new StandardWrapperFacade(this); + + + /** + * The descriptive information string for this implementation. + */ + protected static final String info = + "org.apache.catalina.core.StandardWrapper/1.0"; + + + /** + * The (single) initialized instance of this servlet. + */ + protected Servlet instance = null; + + + /** + * The support object for our instance listeners. + */ + protected InstanceSupport instanceSupport = new InstanceSupport(this); + + + /** + * The context-relative URI of the JSP file for this servlet. + */ + protected String jspFile = null; + + + /** + * The load-on-startup order value (negative value means load on + * first call) for this servlet. + */ + protected int loadOnStartup = -1; + + + /** + * Mappings associated with the wrapper. + */ + protected ArrayList mappings = new ArrayList(); + + + /** + * The initialization parameters for this servlet, keyed by + * parameter name. + */ + protected HashMap parameters = new HashMap(); + + + /** + * The security role references for this servlet, keyed by role name + * used in the servlet. The corresponding value is the role name of + * the web application itself. + */ + protected HashMap references = new HashMap(); + + + /** + * The run-as identity for this servlet. + */ + protected String runAs = null; + + /** + * The notification sequence number. + */ + protected long sequenceNumber = 0; + + /** + * The fully qualified servlet class name for this servlet. + */ + protected String servletClass = null; + + + /** + * Does this servlet implement the SingleThreadModel interface? + */ + protected boolean singleThreadModel = false; + + + /** + * Are we unloading our servlet instance at the moment? + */ + protected boolean unloading = false; + + + /** + * Maximum number of STM instances. + */ + protected int maxInstances = 20; + + + /** + * Number of instances currently loaded for a STM servlet. + */ + protected int nInstances = 0; + + + /** + * Stack containing the STM instances. + */ + protected Stack instancePool = null; + + + /** + * Wait time for servlet unload in ms. + */ + protected long unloadDelay = 2000; + + + /** + * True if this StandardWrapper is for the JspServlet + */ + protected boolean isJspServlet; + + + /** + * The ObjectName of the JSP monitoring mbean + */ + protected ObjectName jspMonitorON; + + + /** + * Should we swallow System.out + */ + protected boolean swallowOutput = false; + + // To support jmx attributes + protected StandardWrapperValve swValve; + protected long loadTime=0; + protected int classLoadTime=0; + + /** + * Static class array used when the SecurityManager is turned on and + * Servlet.init is invoked. + */ + protected static Class[] classType = new Class[]{ServletConfig.class}; + + + /** + * Static class array used when the SecurityManager is turned on and + * Servlet.service is invoked. + */ + protected static Class[] classTypeUsedInService = new Class[]{ + ServletRequest.class, + ServletResponse.class}; + + /** + * Restricted servlets (which can only be loaded by a privileged webapp). + */ + protected static Properties restrictedServlets = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the available date/time for this servlet, in milliseconds since + * the epoch. If this date/time is Long.MAX_VALUE, it is considered to mean + * that unavailability is permanent and any request for this servlet will return + * an SC_NOT_FOUND error. If this date/time is in the future, any request for + * this servlet will return an SC_SERVICE_UNAVAILABLE error. If it is zero, + * the servlet is currently available. + */ + public long getAvailable() { + + return (this.available); + + } + + + /** + * Set the available date/time for this servlet, in milliseconds since the + * epoch. If this date/time is Long.MAX_VALUE, it is considered to mean + * that unavailability is permanent and any request for this servlet will return + * an SC_NOT_FOUND error. If this date/time is in the future, any request for + * this servlet will return an SC_SERVICE_UNAVAILABLE error. + * + * @param available The new available date/time + */ + public void setAvailable(long available) { + + long oldAvailable = this.available; + if (available > System.currentTimeMillis()) + this.available = available; + else + this.available = 0L; + support.firePropertyChange("available", new Long(oldAvailable), + new Long(this.available)); + + } + + + /** + * Return the number of active allocations of this servlet, even if they + * are all for the same instance (as will be true for servlets that do + * not implement SingleThreadModel. + */ + public int getCountAllocated() { + + return (this.countAllocated); + + } + + + public String getEngineName() { + return ((StandardContext)getParent()).getEngineName(); + } + + + /** + * Return descriptive information about this Container implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the InstanceSupport object for this Wrapper instance. + */ + public InstanceSupport getInstanceSupport() { + + return (this.instanceSupport); + + } + + + /** + * Return the context-relative URI of the JSP file for this servlet. + */ + public String getJspFile() { + + return (this.jspFile); + + } + + + /** + * Set the context-relative URI of the JSP file for this servlet. + * + * @param jspFile JSP file URI + */ + public void setJspFile(String jspFile) { + + String oldJspFile = this.jspFile; + this.jspFile = jspFile; + support.firePropertyChange("jspFile", oldJspFile, this.jspFile); + + // Each jsp-file needs to be represented by its own JspServlet and + // corresponding JspMonitoring mbean, because it may be initialized + // with its own init params + isJspServlet = true; + + } + + + /** + * Return the load-on-startup order value (negative value means + * load on first call). + */ + public int getLoadOnStartup() { + + if (isJspServlet && loadOnStartup < 0) { + /* + * JspServlet must always be preloaded, because its instance is + * used during registerJMX (when registering the JSP + * monitoring mbean) + */ + return Integer.MAX_VALUE; + } else { + return (this.loadOnStartup); + } + } + + + /** + * Set the load-on-startup order value (negative value means + * load on first call). + * + * @param value New load-on-startup value + */ + public void setLoadOnStartup(int value) { + + int oldLoadOnStartup = this.loadOnStartup; + this.loadOnStartup = value; + support.firePropertyChange("loadOnStartup", + new Integer(oldLoadOnStartup), + new Integer(this.loadOnStartup)); + + } + + + + /** + * Set the load-on-startup order value from a (possibly null) string. + * Per the specification, any missing or non-numeric value is converted + * to a zero, so that this servlet will still be loaded at startup + * time, but in an arbitrary order. + * + * @param value New load-on-startup value + */ + public void setLoadOnStartupString(String value) { + + try { + setLoadOnStartup(Integer.parseInt(value)); + } catch (NumberFormatException e) { + setLoadOnStartup(0); + } + } + + public String getLoadOnStartupString() { + return Integer.toString( getLoadOnStartup()); + } + + + /** + * Return maximum number of instances that will be allocated when a single + * thread model servlet is used. + */ + public int getMaxInstances() { + + return (this.maxInstances); + + } + + + /** + * Set the maximum number of instances that will be allocated when a single + * thread model servlet is used. + * + * @param maxInstances New value of maxInstances + */ + public void setMaxInstances(int maxInstances) { + + int oldMaxInstances = this.maxInstances; + this.maxInstances = maxInstances; + support.firePropertyChange("maxInstances", oldMaxInstances, + this.maxInstances); + + } + + + /** + * Set the parent Container of this Wrapper, but only if it is a Context. + * + * @param container Proposed parent Container + */ + public void setParent(Container container) { + + if ((container != null) && + !(container instanceof Context)) + throw new IllegalArgumentException + (sm.getString("standardWrapper.notContext")); + if (container instanceof StandardContext) { + swallowOutput = ((StandardContext)container).getSwallowOutput(); + unloadDelay = ((StandardContext)container).getUnloadDelay(); + } + super.setParent(container); + + } + + + /** + * Return the run-as identity for this servlet. + */ + public String getRunAs() { + + return (this.runAs); + + } + + + /** + * Set the run-as identity for this servlet. + * + * @param runAs New run-as identity value + */ + public void setRunAs(String runAs) { + + String oldRunAs = this.runAs; + this.runAs = runAs; + support.firePropertyChange("runAs", oldRunAs, this.runAs); + + } + + + /** + * Return the fully qualified servlet class name for this servlet. + */ + public String getServletClass() { + + return (this.servletClass); + + } + + + /** + * Set the fully qualified servlet class name for this servlet. + * + * @param servletClass Servlet class name + */ + public void setServletClass(String servletClass) { + + String oldServletClass = this.servletClass; + this.servletClass = servletClass; + support.firePropertyChange("servletClass", oldServletClass, + this.servletClass); + if (Constants.JSP_SERVLET_CLASS.equals(servletClass)) { + isJspServlet = true; + } + } + + + + /** + * Set the name of this servlet. This is an alias for the normal + * Container.setName() method, and complements the + * getServletName() method required by the + * ServletConfig interface. + * + * @param name The new name of this servlet + */ + public void setServletName(String name) { + + setName(name); + + } + + + /** + * Return true if the servlet class represented by this + * component implements the SingleThreadModel interface. + */ + public boolean isSingleThreadModel() { + + try { + loadServlet(); + } catch (Throwable t) { + ; + } + return (singleThreadModel); + + } + + + /** + * Is this servlet currently unavailable? + */ + public boolean isUnavailable() { + + if (available == 0L) + return (false); + else if (available <= System.currentTimeMillis()) { + available = 0L; + return (false); + } else + return (true); + + } + + + /** + * Gets the names of the methods supported by the underlying servlet. + * + * This is the same set of methods included in the Allow response header + * in response to an OPTIONS request method processed by the underlying + * servlet. + * + * @return Array of names of the methods supported by the underlying + * servlet + */ + public String[] getServletMethods() throws ServletException { + + Class servletClazz = loadServlet().getClass(); + if (!javax.servlet.http.HttpServlet.class.isAssignableFrom( + servletClazz)) { + return DEFAULT_SERVLET_METHODS; + } + + HashSet allow = new HashSet(); + allow.add("TRACE"); + allow.add("OPTIONS"); + + Method[] methods = getAllDeclaredMethods(servletClazz); + for (int i=0; methods != null && iservice() method called. If the servlet class does + * not implement SingleThreadModel, the (only) initialized + * instance may be returned immediately. If the servlet class implements + * SingleThreadModel, the Wrapper implementation must ensure + * that this instance is not allocated again until it is deallocated by a + * call to deallocate(). + * + * @exception ServletException if the servlet init() method threw + * an exception + * @exception ServletException if a loading error occurs + */ + public Servlet allocate() throws ServletException { + + // If we are currently unloading this servlet, throw an exception + if (unloading) + throw new ServletException + (sm.getString("standardWrapper.unloading", getName())); + + // If not SingleThreadedModel, return the same instance every time + if (!singleThreadModel) { + + // Load and initialize our instance if necessary + if (instance == null) { + synchronized (this) { + if (instance == null) { + try { + if (log.isDebugEnabled()) + log.debug("Allocating non-STM instance"); + + instance = loadServlet(); + } catch (ServletException e) { + throw e; + } catch (Throwable e) { + throw new ServletException + (sm.getString("standardWrapper.allocate"), e); + } + } + } + } + + if (!singleThreadModel) { + if (log.isTraceEnabled()) + log.trace(" Returning non-STM instance"); + countAllocated++; + return (instance); + } + + } + + synchronized (instancePool) { + + while (countAllocated >= nInstances) { + // Allocate a new instance if possible, or else wait + if (nInstances < maxInstances) { + try { + instancePool.push(loadServlet()); + nInstances++; + } catch (ServletException e) { + throw e; + } catch (Throwable e) { + throw new ServletException + (sm.getString("standardWrapper.allocate"), e); + } + } else { + try { + instancePool.wait(); + } catch (InterruptedException e) { + ; + } + } + } + if (log.isTraceEnabled()) + log.trace(" Returning allocated STM instance"); + countAllocated++; + return (Servlet) instancePool.pop(); + + } + + } + + + /** + * Return this previously allocated servlet to the pool of available + * instances. If this servlet class does not implement SingleThreadModel, + * no action is actually required. + * + * @param servlet The servlet to be returned + * + * @exception ServletException if a deallocation error occurs + */ + public void deallocate(Servlet servlet) throws ServletException { + + // If not SingleThreadModel, no action is required + if (!singleThreadModel) { + countAllocated--; + return; + } + + // Unlock and free this instance + synchronized (instancePool) { + countAllocated--; + instancePool.push(servlet); + instancePool.notify(); + } + + } + + + /** + * Return the value for the specified initialization parameter name, + * if any; otherwise return null. + * + * @param name Name of the requested initialization parameter + */ + public String findInitParameter(String name) { + + synchronized (parameters) { + return ((String) parameters.get(name)); + } + + } + + + /** + * Return the names of all defined initialization parameters for this + * servlet. + */ + public String[] findInitParameters() { + + synchronized (parameters) { + String results[] = new String[parameters.size()]; + return ((String[]) parameters.keySet().toArray(results)); + } + + } + + + /** + * Return the mappings associated with this wrapper. + */ + public String[] findMappings() { + + synchronized (mappings) { + return (String[]) mappings.toArray(new String[mappings.size()]); + } + + } + + + /** + * Return the security role link for the specified security role + * reference name, if any; otherwise return null. + * + * @param name Security role reference used within this servlet + */ + public String findSecurityReference(String name) { + + synchronized (references) { + return ((String) references.get(name)); + } + + } + + + /** + * Return the set of security role reference names associated with + * this servlet, if any; otherwise return a zero-length array. + */ + public String[] findSecurityReferences() { + + synchronized (references) { + String results[] = new String[references.size()]; + return ((String[]) references.keySet().toArray(results)); + } + + } + + + /** + * FIXME: Fooling introspection ... + */ + public Wrapper findMappingObject() { + return (Wrapper) getMappingObject(); + } + + + /** + * Load and initialize an instance of this servlet, if there is not already + * at least one initialized instance. This can be used, for example, to + * load servlets that are marked in the deployment descriptor to be loaded + * at server startup time. + *

    + * IMPLEMENTATION NOTE: Servlets whose classnames begin with + * org.apache.catalina. (so-called "container" servlets) + * are loaded by the same classloader that loaded this class, rather than + * the classloader for the current web application. + * This gives such classes access to Catalina internals, which are + * prevented for classes loaded for web applications. + * + * @exception ServletException if the servlet init() method threw + * an exception + * @exception ServletException if some other loading problem occurs + */ + public synchronized void load() throws ServletException { + instance = loadServlet(); + } + + + /** + * Load and initialize an instance of this servlet, if there is not already + * at least one initialized instance. This can be used, for example, to + * load servlets that are marked in the deployment descriptor to be loaded + * at server startup time. + */ + public synchronized Servlet loadServlet() throws ServletException { + + // Nothing to do if we already have an instance or an instance pool + if (!singleThreadModel && (instance != null)) + return instance; + + PrintStream out = System.out; + if (swallowOutput) { + SystemLogHandler.startCapture(); + } + + Servlet servlet; + try { + long t1=System.currentTimeMillis(); + // If this "servlet" is really a JSP file, get the right class. + // HOLD YOUR NOSE - this is a kludge that avoids having to do special + // case Catalina-specific code in Jasper - it also requires that the + // servlet path be replaced by the element content in + // order to be completely effective + String actualClass = servletClass; + if ((actualClass == null) && (jspFile != null)) { + Wrapper jspWrapper = (Wrapper) + ((Context) getParent()).findChild(Constants.JSP_SERVLET_NAME); + if (jspWrapper != null) { + actualClass = jspWrapper.getServletClass(); + // Merge init parameters + String paramNames[] = jspWrapper.findInitParameters(); + for (int i = 0; i < paramNames.length; i++) { + if (parameters.get(paramNames[i]) == null) { + parameters.put + (paramNames[i], + jspWrapper.findInitParameter(paramNames[i])); + } + } + } + } + + // Complain if no servlet class has been specified + if (actualClass == null) { + unavailable(null); + throw new ServletException + (sm.getString("standardWrapper.notClass", getName())); + } + + // Acquire an instance of the class loader to be used + Loader loader = getLoader(); + if (loader == null) { + unavailable(null); + throw new ServletException + (sm.getString("standardWrapper.missingLoader", getName())); + } + + ClassLoader classLoader = loader.getClassLoader(); + + // Special case class loader for a container provided servlet + // + if (isContainerProvidedServlet(actualClass) && + ! ((Context)getParent()).getPrivileged() ) { + // If it is a priviledged context - using its own + // class loader will work, since it's a child of the container + // loader + classLoader = this.getClass().getClassLoader(); + } + + // Load the specified servlet class from the appropriate class loader + Class classClass = null; + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + final ClassLoader fclassLoader = classLoader; + final String factualClass = actualClass; + try{ + classClass = (Class)AccessController.doPrivileged( + new PrivilegedExceptionAction(){ + public Object run() throws Exception{ + if (fclassLoader != null) { + return fclassLoader.loadClass(factualClass); + } else { + return Class.forName(factualClass); + } + } + }); + } catch(PrivilegedActionException pax){ + Exception ex = pax.getException(); + if (ex instanceof ClassNotFoundException){ + throw (ClassNotFoundException)ex; + } else { + getServletContext().log( "Error loading " + + fclassLoader + " " + factualClass, ex ); + } + } + } else { + if (classLoader != null) { + classClass = classLoader.loadClass(actualClass); + } else { + classClass = Class.forName(actualClass); + } + } + } catch (ClassNotFoundException e) { + unavailable(null); + getServletContext().log( "Error loading " + classLoader + " " + actualClass, e ); + throw new ServletException + (sm.getString("standardWrapper.missingClass", actualClass), + e); + } + + if (classClass == null) { + unavailable(null); + throw new ServletException + (sm.getString("standardWrapper.missingClass", actualClass)); + } + + // Instantiate and initialize an instance of the servlet class itself + try { + servlet = (Servlet) classClass.newInstance(); + // Annotation processing + if (!((Context) getParent()).getIgnoreAnnotations()) { + if (getParent() instanceof StandardContext + && ((StandardContext) getParent()).getNamingContextListener() != null) { + AnnotationProcessor.injectNamingResources + (((StandardContext) getParent()).getNamingContextListener().getEnvContext(), servlet); + } + AnnotationProcessor.postConstruct(servlet); + } + } catch (ClassCastException e) { + unavailable(null); + // Restore the context ClassLoader + throw new ServletException + (sm.getString("standardWrapper.notServlet", actualClass), e); + } catch (Throwable e) { + unavailable(null); + + // Added extra log statement for Bugzilla 36630: + // http://issues.apache.org/bugzilla/show_bug.cgi?id=36630 + if(log.isDebugEnabled()) { + log.debug(sm.getString("standardWrapper.instantiate", actualClass), e); + } + + // Restore the context ClassLoader + throw new ServletException + (sm.getString("standardWrapper.instantiate", actualClass), e); + } + + // Check if loading the servlet in this web application should be + // allowed + if (!isServletAllowed(servlet)) { + throw new SecurityException + (sm.getString("standardWrapper.privilegedServlet", + actualClass)); + } + + // Special handling for ContainerServlet instances + if ((servlet instanceof ContainerServlet) && + (isContainerProvidedServlet(actualClass) || + ((Context)getParent()).getPrivileged() )) { + ((ContainerServlet) servlet).setWrapper(this); + } + + classLoadTime=(int) (System.currentTimeMillis() -t1); + // Call the initialization method of this servlet + try { + instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT, + servlet); + + if( System.getSecurityManager() != null) { + + Object[] args = new Object[]{((ServletConfig)facade)}; + SecurityUtil.doAsPrivilege("init", + servlet, + classType, + args); + args = null; + } else { + servlet.init(facade); + } + + // Invoke jspInit on JSP pages + if ((loadOnStartup >= 0) && (jspFile != null)) { + // Invoking jspInit + DummyRequest req = new DummyRequest(); + req.setServletPath(jspFile); + req.setQueryString("jsp_precompile=true"); + DummyResponse res = new DummyResponse(); + + if( System.getSecurityManager() != null) { + Object[] args = new Object[]{req, res}; + SecurityUtil.doAsPrivilege("service", + servlet, + classTypeUsedInService, + args); + args = null; + } else { + servlet.service(req, res); + } + } + instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, + servlet); + } catch (UnavailableException f) { + instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, + servlet, f); + unavailable(f); + throw f; + } catch (ServletException f) { + instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, + servlet, f); + // If the servlet wanted to be unavailable it would have + // said so, so do not call unavailable(null). + throw f; + } catch (Throwable f) { + getServletContext().log("StandardWrapper.Throwable", f ); + instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT, + servlet, f); + // If the servlet wanted to be unavailable it would have + // said so, so do not call unavailable(null). + throw new ServletException + (sm.getString("standardWrapper.initException", getName()), f); + } + + // Register our newly initialized instance + singleThreadModel = servlet instanceof SingleThreadModel; + if (singleThreadModel) { + if (instancePool == null) + instancePool = new Stack(); + } + fireContainerEvent("load", this); + + loadTime=System.currentTimeMillis() -t1; + } finally { + if (swallowOutput) { + String log = SystemLogHandler.stopCapture(); + if (log != null && log.length() > 0) { + if (getServletContext() != null) { + getServletContext().log(log); + } else { + out.println(log); + } + } + } + } + return servlet; + + } + + + /** + * Remove the specified initialization parameter from this servlet. + * + * @param name Name of the initialization parameter to remove + */ + public void removeInitParameter(String name) { + + synchronized (parameters) { + parameters.remove(name); + } + fireContainerEvent("removeInitParameter", name); + + } + + + /** + * Remove a listener no longer interested in InstanceEvents. + * + * @param listener The listener to remove + */ + public void removeInstanceListener(InstanceListener listener) { + + instanceSupport.removeInstanceListener(listener); + + } + + + /** + * Remove a mapping associated with the wrapper. + * + * @param mapping The pattern to remove + */ + public void removeMapping(String mapping) { + + synchronized (mappings) { + mappings.remove(mapping); + } + fireContainerEvent("removeMapping", mapping); + + } + + + /** + * Remove any security role reference for the specified role name. + * + * @param name Security role used within this servlet to be removed + */ + public void removeSecurityReference(String name) { + + synchronized (references) { + references.remove(name); + } + fireContainerEvent("removeSecurityReference", name); + + } + + + /** + * Return a String representation of this component. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + if (getParent() != null) { + sb.append(getParent().toString()); + sb.append("."); + } + sb.append("StandardWrapper["); + sb.append(getName()); + sb.append("]"); + return (sb.toString()); + + } + + + /** + * Process an UnavailableException, marking this servlet as unavailable + * for the specified amount of time. + * + * @param unavailable The exception that occurred, or null + * to mark this servlet as permanently unavailable + */ + public void unavailable(UnavailableException unavailable) { + getServletContext().log(sm.getString("standardWrapper.unavailable", getName())); + if (unavailable == null) + setAvailable(Long.MAX_VALUE); + else if (unavailable.isPermanent()) + setAvailable(Long.MAX_VALUE); + else { + int unavailableSeconds = unavailable.getUnavailableSeconds(); + if (unavailableSeconds <= 0) + unavailableSeconds = 60; // Arbitrary default + setAvailable(System.currentTimeMillis() + + (unavailableSeconds * 1000L)); + } + + } + + + /** + * Unload all initialized instances of this servlet, after calling the + * destroy() method for each instance. This can be used, + * for example, prior to shutting down the entire servlet engine, or + * prior to reloading all of the classes from the Loader associated with + * our Loader's repository. + * + * @exception ServletException if an exception is thrown by the + * destroy() method + */ + public synchronized void unload() throws ServletException { + + // Nothing to do if we have never loaded the instance + if (!singleThreadModel && (instance == null)) + return; + unloading = true; + + // Loaf a while if the current instance is allocated + // (possibly more than once if non-STM) + if (countAllocated > 0) { + int nRetries = 0; + long delay = unloadDelay / 20; + while ((nRetries < 21) && (countAllocated > 0)) { + if ((nRetries % 10) == 0) { + log.info(sm.getString("standardWrapper.waiting", + new Integer(countAllocated))); + } + try { + Thread.sleep(delay); + } catch (InterruptedException e) { + ; + } + nRetries++; + } + } + + PrintStream out = System.out; + if (swallowOutput) { + SystemLogHandler.startCapture(); + } + + // Call the servlet destroy() method + try { + instanceSupport.fireInstanceEvent + (InstanceEvent.BEFORE_DESTROY_EVENT, instance); + + if( System.getSecurityManager() != null) { + SecurityUtil.doAsPrivilege("destroy", + instance); + SecurityUtil.remove(instance); + } else { + instance.destroy(); + } + + instanceSupport.fireInstanceEvent + (InstanceEvent.AFTER_DESTROY_EVENT, instance); + + // Annotation processing + if (!((Context) getParent()).getIgnoreAnnotations()) { + AnnotationProcessor.preDestroy(instance); + } + + } catch (Throwable t) { + instanceSupport.fireInstanceEvent + (InstanceEvent.AFTER_DESTROY_EVENT, instance, t); + instance = null; + instancePool = null; + nInstances = 0; + fireContainerEvent("unload", this); + unloading = false; + throw new ServletException + (sm.getString("standardWrapper.destroyException", getName()), + t); + } finally { + // Write captured output + if (swallowOutput) { + String log = SystemLogHandler.stopCapture(); + if (log != null && log.length() > 0) { + if (getServletContext() != null) { + getServletContext().log(log); + } else { + out.println(log); + } + } + } + } + + // Deregister the destroyed instance + instance = null; + + if (singleThreadModel && (instancePool != null)) { + try { + while (!instancePool.isEmpty()) { + Servlet s = (Servlet) instancePool.pop(); + if (System.getSecurityManager() != null) { + SecurityUtil.doAsPrivilege("destroy", s); + SecurityUtil.remove(instance); + } else { + s.destroy(); + } + // Annotation processing + if (!((Context) getParent()).getIgnoreAnnotations()) { + AnnotationProcessor.preDestroy(s); + } + } + } catch (Throwable t) { + instancePool = null; + nInstances = 0; + unloading = false; + fireContainerEvent("unload", this); + throw new ServletException + (sm.getString("standardWrapper.destroyException", + getName()), t); + } + instancePool = null; + nInstances = 0; + } + + singleThreadModel = false; + + unloading = false; + fireContainerEvent("unload", this); + + } + + + // -------------------------------------------------- ServletConfig Methods + + + /** + * Return the initialization parameter value for the specified name, + * if any; otherwise return null. + * + * @param name Name of the initialization parameter to retrieve + */ + public String getInitParameter(String name) { + + return (findInitParameter(name)); + + } + + + /** + * Return the set of initialization parameter names defined for this + * servlet. If none are defined, an empty Enumeration is returned. + */ + public Enumeration getInitParameterNames() { + + synchronized (parameters) { + return (new Enumerator(parameters.keySet())); + } + + } + + + /** + * Return the servlet context with which this servlet is associated. + */ + public ServletContext getServletContext() { + + if (parent == null) + return (null); + else if (!(parent instanceof Context)) + return (null); + else + return (((Context) parent).getServletContext()); + + } + + + /** + * Return the name of this servlet. + */ + public String getServletName() { + + return (getName()); + + } + + public long getProcessingTime() { + return swValve.getProcessingTime(); + } + + public void setProcessingTime(long processingTime) { + swValve.setProcessingTime(processingTime); + } + + public long getMaxTime() { + return swValve.getMaxTime(); + } + + public void setMaxTime(long maxTime) { + swValve.setMaxTime(maxTime); + } + + public long getMinTime() { + return swValve.getMinTime(); + } + + public void setMinTime(long minTime) { + swValve.setMinTime(minTime); + } + + public int getRequestCount() { + return swValve.getRequestCount(); + } + + public void setRequestCount(int requestCount) { + swValve.setRequestCount(requestCount); + } + + public int getErrorCount() { + return swValve.getErrorCount(); + } + + public void setErrorCount(int errorCount) { + swValve.setErrorCount(errorCount); + } + + /** + * Increment the error count used for monitoring. + */ + public void incrementErrorCount(){ + swValve.setErrorCount(swValve.getErrorCount() + 1); + } + + public long getLoadTime() { + return loadTime; + } + + public void setLoadTime(long loadTime) { + this.loadTime = loadTime; + } + + public int getClassLoadTime() { + return classLoadTime; + } + + // -------------------------------------------------------- Package Methods + + + // -------------------------------------------------------- protected Methods + + + /** + * Add a default Mapper implementation if none have been configured + * explicitly. + * + * @param mapperClass Java class name of the default Mapper + */ + protected void addDefaultMapper(String mapperClass) { + + ; // No need for a default Mapper on a Wrapper + + } + + + /** + * Return true if the specified class name represents a + * container provided servlet class that should be loaded by the + * server class loader. + * + * @param classname Name of the class to be checked + */ + protected boolean isContainerProvidedServlet(String classname) { + + if (classname.startsWith("org.apache.catalina.")) { + return (true); + } + try { + Class clazz = + this.getClass().getClassLoader().loadClass(classname); + return (ContainerServlet.class.isAssignableFrom(clazz)); + } catch (Throwable t) { + return (false); + } + + } + + + /** + * Return true if loading this servlet is allowed. + */ + protected boolean isServletAllowed(Object servlet) { + + // Privileged webapps may load all servlets without restriction + if (((Context) getParent()).getPrivileged()) { + return true; + } + + if (servlet instanceof ContainerServlet) { + return (false); + } + + Class clazz = servlet.getClass(); + while (clazz != null && !clazz.getName().equals("javax.servlet.http.HttpServlet")) { + if ("restricted".equals(restrictedServlets.getProperty(clazz.getName()))) { + return (false); + } + clazz = clazz.getSuperclass(); + } + + return (true); + + } + + + protected Method[] getAllDeclaredMethods(Class c) { + + if (c.equals(javax.servlet.http.HttpServlet.class)) { + return null; + } + + Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass()); + + Method[] thisMethods = c.getDeclaredMethods(); + if (thisMethods == null) { + return parentMethods; + } + + if ((parentMethods != null) && (parentMethods.length > 0)) { + Method[] allMethods = + new Method[parentMethods.length + thisMethods.length]; + System.arraycopy(parentMethods, 0, allMethods, 0, + parentMethods.length); + System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, + thisMethods.length); + + thisMethods = allMethods; + } + + return thisMethods; + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Start this component, pre-loading the servlet if the load-on-startup + * value is set appropriately. + * + * @exception LifecycleException if a fatal error occurs during startup + */ + public void start() throws LifecycleException { + + // Send j2ee.state.starting notification + if (this.getObjectName() != null) { + Notification notification = new Notification("j2ee.state.starting", + this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + // Start up this component + super.start(); + + if( oname != null ) + registerJMX((StandardContext)getParent()); + + // Load and initialize an instance of this servlet if requested + // MOVED TO StandardContext START() METHOD + + setAvailable(0L); + + // Send j2ee.state.running notification + if (this.getObjectName() != null) { + Notification notification = + new Notification("j2ee.state.running", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + } + + + /** + * Stop this component, gracefully shutting down the servlet if it has + * been initialized. + * + * @exception LifecycleException if a fatal error occurs during shutdown + */ + public void stop() throws LifecycleException { + + setAvailable(Long.MAX_VALUE); + + // Send j2ee.state.stopping notification + if (this.getObjectName() != null) { + Notification notification = + new Notification("j2ee.state.stopping", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + // Shut down our servlet instance (if it has been initialized) + try { + unload(); + } catch (ServletException e) { + getServletContext().log(sm.getString + ("standardWrapper.unloadException", getName()), e); + } + + // Shut down this component + super.stop(); + + // Send j2ee.state.stoppped notification + if (this.getObjectName() != null) { + Notification notification = + new Notification("j2ee.state.stopped", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + if( oname != null ) { + Registry.getRegistry(null, null).unregisterComponent(oname); + + // Send j2ee.object.deleted notification + Notification notification = + new Notification("j2ee.object.deleted", this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + + if (isJspServlet && jspMonitorON != null ) { + Registry.getRegistry(null, null).unregisterComponent(jspMonitorON); + } + + } + + protected void registerJMX(StandardContext ctx) { + + String parentName = ctx.getName(); + parentName = ("".equals(parentName)) ? "/" : parentName; + + String hostName = ctx.getParent().getName(); + hostName = (hostName==null) ? "DEFAULT" : hostName; + + String domain = ctx.getDomain(); + + String webMod= "//" + hostName + parentName; + String onameStr = domain + ":j2eeType=Servlet,name=" + getName() + + ",WebModule=" + webMod + ",J2EEApplication=" + + ctx.getJ2EEApplication() + ",J2EEServer=" + + ctx.getJ2EEServer(); + try { + oname=new ObjectName(onameStr); + controller=oname; + Registry.getRegistry(null, null) + .registerComponent(this, oname, null ); + + // Send j2ee.object.created notification + if (this.getObjectName() != null) { + Notification notification = new Notification( + "j2ee.object.created", + this.getObjectName(), + sequenceNumber++); + broadcaster.sendNotification(notification); + } + } catch( Exception ex ) { + log.info("Error registering servlet with jmx " + this); + } + + if (isJspServlet) { + // Register JSP monitoring mbean + onameStr = domain + ":type=JspMonitor,name=" + getName() + + ",WebModule=" + webMod + + ",J2EEApplication=" + ctx.getJ2EEApplication() + + ",J2EEServer=" + ctx.getJ2EEServer(); + try { + jspMonitorON = new ObjectName(onameStr); + Registry.getRegistry(null, null) + .registerComponent(instance, jspMonitorON, null); + } catch( Exception ex ) { + log.info("Error registering JSP monitoring with jmx " + + instance); + } + } + } + + + /* Remove a JMX notficationListener + * @see javax.management.NotificationEmitter#removeNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) + */ + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, Object object) throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener,filter,object); + + } + + protected MBeanNotificationInfo[] notificationInfo; + + /* Get JMX Broadcaster Info + * @TODO use StringManager for international support! + * @TODO This two events we not send j2ee.state.failed and j2ee.attribute.changed! + * @see javax.management.NotificationBroadcaster#getNotificationInfo() + */ + public MBeanNotificationInfo[] getNotificationInfo() { + + if(notificationInfo == null) { + notificationInfo = new MBeanNotificationInfo[]{ + new MBeanNotificationInfo(new String[] { + "j2ee.object.created"}, + Notification.class.getName(), + "servlet is created" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.starting"}, + Notification.class.getName(), + "servlet is starting" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.running"}, + Notification.class.getName(), + "servlet is running" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.state.stopped"}, + Notification.class.getName(), + "servlet start to stopped" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.object.stopped"}, + Notification.class.getName(), + "servlet is stopped" + ), + new MBeanNotificationInfo(new String[] { + "j2ee.object.deleted"}, + Notification.class.getName(), + "servlet is deleted" + ) + }; + + } + + return notificationInfo; + } + + + /* Add a JMX-NotificationListener + * @see javax.management.NotificationBroadcaster#addNotificationListener(javax.management.NotificationListener, javax.management.NotificationFilter, java.lang.Object) + */ + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, Object object) throws IllegalArgumentException { + broadcaster.addNotificationListener(listener,filter,object); + } + + + /** + * Remove a JMX-NotificationListener + * @see javax.management.NotificationBroadcaster#removeNotificationListener(javax.management.NotificationListener) + */ + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + broadcaster.removeNotificationListener(listener); + } + + + // ------------------------------------------------------------- Attributes + + + public boolean isEventProvider() { + return false; + } + + public boolean isStateManageable() { + return false; + } + + public boolean isStatisticsProvider() { + return false; + } + + +} diff --git a/java/org/apache/catalina/core/StandardWrapperFacade.java b/java/org/apache/catalina/core/StandardWrapperFacade.java index c80e2d301..9711353b2 100644 --- a/java/org/apache/catalina/core/StandardWrapperFacade.java +++ b/java/org/apache/catalina/core/StandardWrapperFacade.java @@ -1,88 +1,88 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.util.Enumeration; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; - - -/** - * Facade for the StandardWrapper object. - * - * @author Remy Maucharat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class StandardWrapperFacade - implements ServletConfig { - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new facede around a StandardWrapper. - */ - public StandardWrapperFacade(StandardWrapper config) { - - super(); - this.config = (ServletConfig) config; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped config. - */ - private ServletConfig config = null; - - - // -------------------------------------------------- ServletConfig Methods - - - public String getServletName() { - return config.getServletName(); - } - - - public ServletContext getServletContext() { - ServletContext theContext = config.getServletContext(); - if ((theContext != null) && - (theContext instanceof ApplicationContext)) - theContext = ((ApplicationContext) theContext).getFacade(); - return (theContext); - } - - - public String getInitParameter(String name) { - return config.getInitParameter(name); - } - - - public Enumeration getInitParameterNames() { - return config.getInitParameterNames(); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + + +/** + * Facade for the StandardWrapper object. + * + * @author Remy Maucharat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class StandardWrapperFacade + implements ServletConfig { + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new facede around a StandardWrapper. + */ + public StandardWrapperFacade(StandardWrapper config) { + + super(); + this.config = (ServletConfig) config; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Wrapped config. + */ + private ServletConfig config = null; + + + // -------------------------------------------------- ServletConfig Methods + + + public String getServletName() { + return config.getServletName(); + } + + + public ServletContext getServletContext() { + ServletContext theContext = config.getServletContext(); + if ((theContext != null) && + (theContext instanceof ApplicationContext)) + theContext = ((ApplicationContext) theContext).getFacade(); + return (theContext); + } + + + public String getInitParameter(String name) { + return config.getInitParameter(name); + } + + + public Enumeration getInitParameterNames() { + return config.getInitParameterNames(); + } + + +} diff --git a/java/org/apache/catalina/core/StandardWrapperValve.java b/java/org/apache/catalina/core/StandardWrapperValve.java index 152ef28b6..464d60072 100644 --- a/java/org/apache/catalina/core/StandardWrapperValve.java +++ b/java/org/apache/catalina/core/StandardWrapperValve.java @@ -1,386 +1,386 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.core; - - -import java.io.IOException; - -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.connector.ClientAbortException; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.log.SystemLogHandler; - -/** - * Valve that implements the default basic behavior for the - * StandardWrapper container implementation. - * - * @author Craig R. McClanahan - * @version $Revision: 303681 $ $Date: 2005-02-06 11:39:32 +0100 (dim., 06 févr. 2005) $ - */ - -final class StandardWrapperValve - extends ValveBase { - - private static Log log = LogFactory.getLog(StandardWrapperValve.class); - - // ----------------------------------------------------- Instance Variables - - - // Some JMX statistics. This vavle is associated with a StandardWrapper. - // We exponse the StandardWrapper as JMX ( j2eeType=Servlet ). The fields - // are here for performance. - private volatile long processingTime; - private volatile long maxTime; - private volatile long minTime = Long.MAX_VALUE; - private volatile int requestCount; - private volatile int errorCount; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - // --------------------------------------------------------- Public Methods - - - /** - * Invoke the servlet we are managing, respecting the rules regarding - * servlet lifecycle and SingleThreadModel support. - * - * @param request Request to be processed - * @param response Response to be produced - * @param valveContext Valve context used to forward to the next Valve - * - * @exception IOException if an input/output error occurred - * @exception ServletException if a servlet error occurred - */ - public final void invoke(Request request, Response response) - throws IOException, ServletException { - - // Initialize local variables we may need - boolean unavailable = false; - Throwable throwable = null; - // This should be a Request attribute... - long t1=System.currentTimeMillis(); - requestCount++; - StandardWrapper wrapper = (StandardWrapper) getContainer(); - Servlet servlet = null; - Context context = (Context) wrapper.getParent(); - - // Check for the application being marked unavailable - if (!context.getAvailable()) { - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, - sm.getString("standardContext.isUnavailable")); - unavailable = true; - } - - // Check for the servlet being marked unavailable - if (!unavailable && wrapper.isUnavailable()) { - container.getLogger().info(sm.getString("standardWrapper.isUnavailable", - wrapper.getName())); - long available = wrapper.getAvailable(); - if ((available > 0L) && (available < Long.MAX_VALUE)) { - response.setDateHeader("Retry-After", available); - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, - sm.getString("standardWrapper.isUnavailable", - wrapper.getName())); - } else if (available == Long.MAX_VALUE) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - sm.getString("standardWrapper.notFound", - wrapper.getName())); - } - unavailable = true; - } - - // Allocate a servlet instance to process this request - try { - if (!unavailable) { - servlet = wrapper.allocate(); - } - } catch (UnavailableException e) { - long available = wrapper.getAvailable(); - if ((available > 0L) && (available < Long.MAX_VALUE)) { - response.setDateHeader("Retry-After", available); - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, - sm.getString("standardWrapper.isUnavailable", - wrapper.getName())); - } else if (available == Long.MAX_VALUE) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - sm.getString("standardWrapper.notFound", - wrapper.getName())); - } - } catch (ServletException e) { - container.getLogger().error(sm.getString("standardWrapper.allocateException", - wrapper.getName()), StandardWrapper.getRootCause(e)); - throwable = e; - exception(request, response, e); - servlet = null; - } catch (Throwable e) { - container.getLogger().error(sm.getString("standardWrapper.allocateException", - wrapper.getName()), e); - throwable = e; - exception(request, response, e); - servlet = null; - } - - // Acknowlege the request - try { - response.sendAcknowledgement(); - } catch (IOException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - container.getLogger().warn(sm.getString("standardWrapper.acknowledgeException", - wrapper.getName()), e); - throwable = e; - exception(request, response, e); - } catch (Throwable e) { - container.getLogger().error(sm.getString("standardWrapper.acknowledgeException", - wrapper.getName()), e); - throwable = e; - exception(request, response, e); - servlet = null; - } - MessageBytes requestPathMB = null; - if (request != null) { - requestPathMB = request.getRequestPathMB(); - } - request.setAttribute - (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, - ApplicationFilterFactory.REQUEST_INTEGER); - request.setAttribute - (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, - requestPathMB); - // Create the filter chain for this request - ApplicationFilterFactory factory = - ApplicationFilterFactory.getInstance(); - ApplicationFilterChain filterChain = - factory.createFilterChain(request, wrapper, servlet); - - // Call the filter chain for this request - // NOTE: This also calls the servlet's service() method - try { - String jspFile = wrapper.getJspFile(); - if (jspFile != null) - request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); - else - request.removeAttribute(Globals.JSP_FILE_ATTR); - if ((servlet != null) && (filterChain != null)) { - - // Swallow output if needed - if (context.getSwallowOutput()) { - try { - SystemLogHandler.startCapture(); - filterChain.doFilter(request.getRequest(), - response.getResponse()); - } finally { - String log = SystemLogHandler.stopCapture(); - if (log != null && log.length() > 0) { - context.getLogger().info(log); - } - } - } else { - filterChain.doFilter - (request.getRequest(), response.getResponse()); - } - - } - request.removeAttribute(Globals.JSP_FILE_ATTR); - } catch (ClientAbortException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - throwable = e; - exception(request, response, e); - } catch (IOException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - container.getLogger().warn(sm.getString("standardWrapper.serviceException", - wrapper.getName()), e); - throwable = e; - exception(request, response, e); - } catch (UnavailableException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - container.getLogger().warn(sm.getString("standardWrapper.serviceException", - wrapper.getName()), e); - // throwable = e; - // exception(request, response, e); - wrapper.unavailable(e); - long available = wrapper.getAvailable(); - if ((available > 0L) && (available < Long.MAX_VALUE)) { - response.setDateHeader("Retry-After", available); - response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, - sm.getString("standardWrapper.isUnavailable", - wrapper.getName())); - } else if (available == Long.MAX_VALUE) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - sm.getString("standardWrapper.notFound", - wrapper.getName())); - } - // Do not save exception in 'throwable', because we - // do not want to do exception(request, response, e) processing - } catch (ServletException e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - Throwable rootCause = StandardWrapper.getRootCause(e); - if (!(rootCause instanceof ClientAbortException)) { - container.getLogger().error(sm.getString("standardWrapper.serviceException", - wrapper.getName()), rootCause); - } - throwable = e; - exception(request, response, e); - } catch (Throwable e) { - request.removeAttribute(Globals.JSP_FILE_ATTR); - container.getLogger().error(sm.getString("standardWrapper.serviceException", - wrapper.getName()), e); - throwable = e; - exception(request, response, e); - } - - // Release the filter chain (if any) for this request - try { - if (filterChain != null) - filterChain.release(); - } catch (Throwable e) { - container.getLogger().error(sm.getString("standardWrapper.releaseFilters", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); - } - } - - // Deallocate the allocated servlet instance - try { - if (servlet != null) { - wrapper.deallocate(servlet); - } - } catch (Throwable e) { - container.getLogger().error(sm.getString("standardWrapper.deallocateException", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); - } - } - - // If this servlet has been marked permanently unavailable, - // unload it and release this instance - try { - if ((servlet != null) && - (wrapper.getAvailable() == Long.MAX_VALUE)) { - wrapper.unload(); - } - } catch (Throwable e) { - container.getLogger().error(sm.getString("standardWrapper.unloadException", - wrapper.getName()), e); - if (throwable == null) { - throwable = e; - exception(request, response, e); - } - } - long t2=System.currentTimeMillis(); - - long time=t2-t1; - processingTime += time; - if( time > maxTime) maxTime=time; - if( time < minTime) minTime=time; - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Handle the specified ServletException encountered while processing - * the specified Request to produce the specified Response. Any - * exceptions that occur during generation of the exception report are - * logged and swallowed. - * - * @param request The request being processed - * @param response The response being generated - * @param exception The exception that occurred (which possibly wraps - * a root cause exception - */ - private void exception(Request request, Response response, - Throwable exception) { - request.setAttribute(Globals.EXCEPTION_ATTR, exception); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - - } - - public long getProcessingTime() { - return processingTime; - } - - public void setProcessingTime(long processingTime) { - this.processingTime = processingTime; - } - - public long getMaxTime() { - return maxTime; - } - - public void setMaxTime(long maxTime) { - this.maxTime = maxTime; - } - - public long getMinTime() { - return minTime; - } - - public void setMinTime(long minTime) { - this.minTime = minTime; - } - - public int getRequestCount() { - return requestCount; - } - - public void setRequestCount(int requestCount) { - this.requestCount = requestCount; - } - - public int getErrorCount() { - return errorCount; - } - - public void setErrorCount(int errorCount) { - this.errorCount = errorCount; - } - - // Don't register in JMX - - public ObjectName createObjectName(String domain, ObjectName parent) - throws MalformedObjectNameException - { - return null; - } -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.core; + + +import java.io.IOException; + +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.connector.ClientAbortException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.log.SystemLogHandler; + +/** + * Valve that implements the default basic behavior for the + * StandardWrapper container implementation. + * + * @author Craig R. McClanahan + * @version $Revision: 303681 $ $Date: 2005-02-06 11:39:32 +0100 (dim., 06 févr. 2005) $ + */ + +final class StandardWrapperValve + extends ValveBase { + + private static Log log = LogFactory.getLog(StandardWrapperValve.class); + + // ----------------------------------------------------- Instance Variables + + + // Some JMX statistics. This vavle is associated with a StandardWrapper. + // We exponse the StandardWrapper as JMX ( j2eeType=Servlet ). The fields + // are here for performance. + private volatile long processingTime; + private volatile long maxTime; + private volatile long minTime = Long.MAX_VALUE; + private volatile int requestCount; + private volatile int errorCount; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + // --------------------------------------------------------- Public Methods + + + /** + * Invoke the servlet we are managing, respecting the rules regarding + * servlet lifecycle and SingleThreadModel support. + * + * @param request Request to be processed + * @param response Response to be produced + * @param valveContext Valve context used to forward to the next Valve + * + * @exception IOException if an input/output error occurred + * @exception ServletException if a servlet error occurred + */ + public final void invoke(Request request, Response response) + throws IOException, ServletException { + + // Initialize local variables we may need + boolean unavailable = false; + Throwable throwable = null; + // This should be a Request attribute... + long t1=System.currentTimeMillis(); + requestCount++; + StandardWrapper wrapper = (StandardWrapper) getContainer(); + Servlet servlet = null; + Context context = (Context) wrapper.getParent(); + + // Check for the application being marked unavailable + if (!context.getAvailable()) { + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, + sm.getString("standardContext.isUnavailable")); + unavailable = true; + } + + // Check for the servlet being marked unavailable + if (!unavailable && wrapper.isUnavailable()) { + container.getLogger().info(sm.getString("standardWrapper.isUnavailable", + wrapper.getName())); + long available = wrapper.getAvailable(); + if ((available > 0L) && (available < Long.MAX_VALUE)) { + response.setDateHeader("Retry-After", available); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, + sm.getString("standardWrapper.isUnavailable", + wrapper.getName())); + } else if (available == Long.MAX_VALUE) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + sm.getString("standardWrapper.notFound", + wrapper.getName())); + } + unavailable = true; + } + + // Allocate a servlet instance to process this request + try { + if (!unavailable) { + servlet = wrapper.allocate(); + } + } catch (UnavailableException e) { + long available = wrapper.getAvailable(); + if ((available > 0L) && (available < Long.MAX_VALUE)) { + response.setDateHeader("Retry-After", available); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, + sm.getString("standardWrapper.isUnavailable", + wrapper.getName())); + } else if (available == Long.MAX_VALUE) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + sm.getString("standardWrapper.notFound", + wrapper.getName())); + } + } catch (ServletException e) { + container.getLogger().error(sm.getString("standardWrapper.allocateException", + wrapper.getName()), StandardWrapper.getRootCause(e)); + throwable = e; + exception(request, response, e); + servlet = null; + } catch (Throwable e) { + container.getLogger().error(sm.getString("standardWrapper.allocateException", + wrapper.getName()), e); + throwable = e; + exception(request, response, e); + servlet = null; + } + + // Acknowlege the request + try { + response.sendAcknowledgement(); + } catch (IOException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + container.getLogger().warn(sm.getString("standardWrapper.acknowledgeException", + wrapper.getName()), e); + throwable = e; + exception(request, response, e); + } catch (Throwable e) { + container.getLogger().error(sm.getString("standardWrapper.acknowledgeException", + wrapper.getName()), e); + throwable = e; + exception(request, response, e); + servlet = null; + } + MessageBytes requestPathMB = null; + if (request != null) { + requestPathMB = request.getRequestPathMB(); + } + request.setAttribute + (ApplicationFilterFactory.DISPATCHER_TYPE_ATTR, + ApplicationFilterFactory.REQUEST_INTEGER); + request.setAttribute + (ApplicationFilterFactory.DISPATCHER_REQUEST_PATH_ATTR, + requestPathMB); + // Create the filter chain for this request + ApplicationFilterFactory factory = + ApplicationFilterFactory.getInstance(); + ApplicationFilterChain filterChain = + factory.createFilterChain(request, wrapper, servlet); + + // Call the filter chain for this request + // NOTE: This also calls the servlet's service() method + try { + String jspFile = wrapper.getJspFile(); + if (jspFile != null) + request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); + else + request.removeAttribute(Globals.JSP_FILE_ATTR); + if ((servlet != null) && (filterChain != null)) { + + // Swallow output if needed + if (context.getSwallowOutput()) { + try { + SystemLogHandler.startCapture(); + filterChain.doFilter(request.getRequest(), + response.getResponse()); + } finally { + String log = SystemLogHandler.stopCapture(); + if (log != null && log.length() > 0) { + context.getLogger().info(log); + } + } + } else { + filterChain.doFilter + (request.getRequest(), response.getResponse()); + } + + } + request.removeAttribute(Globals.JSP_FILE_ATTR); + } catch (ClientAbortException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + throwable = e; + exception(request, response, e); + } catch (IOException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + container.getLogger().warn(sm.getString("standardWrapper.serviceException", + wrapper.getName()), e); + throwable = e; + exception(request, response, e); + } catch (UnavailableException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + container.getLogger().warn(sm.getString("standardWrapper.serviceException", + wrapper.getName()), e); + // throwable = e; + // exception(request, response, e); + wrapper.unavailable(e); + long available = wrapper.getAvailable(); + if ((available > 0L) && (available < Long.MAX_VALUE)) { + response.setDateHeader("Retry-After", available); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, + sm.getString("standardWrapper.isUnavailable", + wrapper.getName())); + } else if (available == Long.MAX_VALUE) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + sm.getString("standardWrapper.notFound", + wrapper.getName())); + } + // Do not save exception in 'throwable', because we + // do not want to do exception(request, response, e) processing + } catch (ServletException e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + Throwable rootCause = StandardWrapper.getRootCause(e); + if (!(rootCause instanceof ClientAbortException)) { + container.getLogger().error(sm.getString("standardWrapper.serviceException", + wrapper.getName()), rootCause); + } + throwable = e; + exception(request, response, e); + } catch (Throwable e) { + request.removeAttribute(Globals.JSP_FILE_ATTR); + container.getLogger().error(sm.getString("standardWrapper.serviceException", + wrapper.getName()), e); + throwable = e; + exception(request, response, e); + } + + // Release the filter chain (if any) for this request + try { + if (filterChain != null) + filterChain.release(); + } catch (Throwable e) { + container.getLogger().error(sm.getString("standardWrapper.releaseFilters", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } + } + + // Deallocate the allocated servlet instance + try { + if (servlet != null) { + wrapper.deallocate(servlet); + } + } catch (Throwable e) { + container.getLogger().error(sm.getString("standardWrapper.deallocateException", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } + } + + // If this servlet has been marked permanently unavailable, + // unload it and release this instance + try { + if ((servlet != null) && + (wrapper.getAvailable() == Long.MAX_VALUE)) { + wrapper.unload(); + } + } catch (Throwable e) { + container.getLogger().error(sm.getString("standardWrapper.unloadException", + wrapper.getName()), e); + if (throwable == null) { + throwable = e; + exception(request, response, e); + } + } + long t2=System.currentTimeMillis(); + + long time=t2-t1; + processingTime += time; + if( time > maxTime) maxTime=time; + if( time < minTime) minTime=time; + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Handle the specified ServletException encountered while processing + * the specified Request to produce the specified Response. Any + * exceptions that occur during generation of the exception report are + * logged and swallowed. + * + * @param request The request being processed + * @param response The response being generated + * @param exception The exception that occurred (which possibly wraps + * a root cause exception + */ + private void exception(Request request, Response response, + Throwable exception) { + request.setAttribute(Globals.EXCEPTION_ATTR, exception); + response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + + } + + public long getProcessingTime() { + return processingTime; + } + + public void setProcessingTime(long processingTime) { + this.processingTime = processingTime; + } + + public long getMaxTime() { + return maxTime; + } + + public void setMaxTime(long maxTime) { + this.maxTime = maxTime; + } + + public long getMinTime() { + return minTime; + } + + public void setMinTime(long minTime) { + this.minTime = minTime; + } + + public int getRequestCount() { + return requestCount; + } + + public void setRequestCount(int requestCount) { + this.requestCount = requestCount; + } + + public int getErrorCount() { + return errorCount; + } + + public void setErrorCount(int errorCount) { + this.errorCount = errorCount; + } + + // Don't register in JMX + + public ObjectName createObjectName(String domain, ObjectName parent) + throws MalformedObjectNameException + { + return null; + } +} diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml index 0bbfee94e..d052c7a9b 100644 --- a/java/org/apache/catalina/core/mbeans-descriptors.xml +++ b/java/org/apache/catalina/core/mbeans-descriptors.xml @@ -1,694 +1,694 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/deploy/ApplicationParameter.java b/java/org/apache/catalina/deploy/ApplicationParameter.java index 959c2a678..768e4332b 100644 --- a/java/org/apache/catalina/deploy/ApplicationParameter.java +++ b/java/org/apache/catalina/deploy/ApplicationParameter.java @@ -1,121 +1,121 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of a context initialization parameter that is configured - * in the server configuration file, rather than the application deployment - * descriptor. This is convenient for establishing default values (which - * may be configured to allow application overrides or not) without having - * to modify the application deployment descriptor itself. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class ApplicationParameter implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this environment entry. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The name of this application parameter. - */ - private String name = null; - - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - - /** - * Does this application parameter allow overrides by the application - * deployment descriptor? - */ - private boolean override = true; - - public boolean getOverride() { - return (this.override); - } - - public void setOverride(boolean override) { - this.override = override; - } - - - /** - * The value of this application parameter. - */ - private String value = null; - - public String getValue() { - return (this.value); - } - - public void setValue(String value) { - this.value = value; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ApplicationParameter["); - sb.append("name="); - sb.append(name); - if (description != null) { - sb.append(", description="); - sb.append(description); - } - sb.append(", value="); - sb.append(value); - sb.append(", override="); - sb.append(override); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of a context initialization parameter that is configured + * in the server configuration file, rather than the application deployment + * descriptor. This is convenient for establishing default values (which + * may be configured to allow application overrides or not) without having + * to modify the application deployment descriptor itself. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class ApplicationParameter implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this environment entry. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The name of this application parameter. + */ + private String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + * Does this application parameter allow overrides by the application + * deployment descriptor? + */ + private boolean override = true; + + public boolean getOverride() { + return (this.override); + } + + public void setOverride(boolean override) { + this.override = override; + } + + + /** + * The value of this application parameter. + */ + private String value = null; + + public String getValue() { + return (this.value); + } + + public void setValue(String value) { + this.value = value; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ApplicationParameter["); + sb.append("name="); + sb.append(name); + if (description != null) { + sb.append(", description="); + sb.append(description); + } + sb.append(", value="); + sb.append(value); + sb.append(", override="); + sb.append(override); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/ContextEjb.java b/java/org/apache/catalina/deploy/ContextEjb.java index b15c45159..7cbea6fac 100644 --- a/java/org/apache/catalina/deploy/ContextEjb.java +++ b/java/org/apache/catalina/deploy/ContextEjb.java @@ -1,118 +1,118 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of an EJB resource reference for a web application, as - * represented in a <ejb-ref> element in the - * deployment descriptor. - * - * @author Craig R. McClanahan - * @author Peter Rossbach (pero@apache.org) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ContextEjb extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - - - /** - * The name of the EJB home implementation class. - */ - private String home = null; - - public String getHome() { - return (this.home); - } - - public void setHome(String home) { - this.home = home; - } - - - /** - * The link to a J2EE EJB definition. - */ - private String link = null; - - public String getLink() { - return (this.link); - } - - public void setLink(String link) { - this.link = link; - } - - /** - * The name of the EJB remote implementation class. - */ - private String remote = null; - - public String getRemote() { - return (this.remote); - } - - public void setRemote(String remote) { - this.remote = remote; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextEjb["); - sb.append("name="); - sb.append(getName()); - if (getDescription() != null) { - sb.append(", description="); - sb.append(getDescription()); - } - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - if (home != null) { - sb.append(", home="); - sb.append(home); - } - if (remote != null) { - sb.append(", remote="); - sb.append(remote); - } - if (link != null) { - sb.append(", link="); - sb.append(link); - } - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of an EJB resource reference for a web application, as + * represented in a <ejb-ref> element in the + * deployment descriptor. + * + * @author Craig R. McClanahan + * @author Peter Rossbach (pero@apache.org) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ContextEjb extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + + + /** + * The name of the EJB home implementation class. + */ + private String home = null; + + public String getHome() { + return (this.home); + } + + public void setHome(String home) { + this.home = home; + } + + + /** + * The link to a J2EE EJB definition. + */ + private String link = null; + + public String getLink() { + return (this.link); + } + + public void setLink(String link) { + this.link = link; + } + + /** + * The name of the EJB remote implementation class. + */ + private String remote = null; + + public String getRemote() { + return (this.remote); + } + + public void setRemote(String remote) { + this.remote = remote; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextEjb["); + sb.append("name="); + sb.append(getName()); + if (getDescription() != null) { + sb.append(", description="); + sb.append(getDescription()); + } + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + if (home != null) { + sb.append(", home="); + sb.append(home); + } + if (remote != null) { + sb.append(", remote="); + sb.append(remote); + } + if (link != null) { + sb.append(", link="); + sb.append(link); + } + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/ContextEnvironment.java b/java/org/apache/catalina/deploy/ContextEnvironment.java index d07c003f3..3dcdc7f4a 100644 --- a/java/org/apache/catalina/deploy/ContextEnvironment.java +++ b/java/org/apache/catalina/deploy/ContextEnvironment.java @@ -1,155 +1,155 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of an application environment entry, as represented in - * an <env-entry> element in the deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class ContextEnvironment implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this environment entry. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The name of this environment entry. - */ - private String name = null; - - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - - /** - * Does this environment entry allow overrides by the application - * deployment descriptor? - */ - private boolean override = true; - - public boolean getOverride() { - return (this.override); - } - - public void setOverride(boolean override) { - this.override = override; - } - - - /** - * The type of this environment entry. - */ - private String type = null; - - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - } - - - /** - * The value of this environment entry. - */ - private String value = null; - - public String getValue() { - return (this.value); - } - - public void setValue(String value) { - this.value = value; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextEnvironment["); - sb.append("name="); - sb.append(name); - if (description != null) { - sb.append(", description="); - sb.append(description); - } - if (type != null) { - sb.append(", type="); - sb.append(type); - } - if (value != null) { - sb.append(", value="); - sb.append(value); - } - sb.append(", override="); - sb.append(override); - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * The NamingResources with which we are associated (if any). - */ - protected NamingResources resources = null; - - public NamingResources getNamingResources() { - return (this.resources); - } - - void setNamingResources(NamingResources resources) { - this.resources = resources; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of an application environment entry, as represented in + * an <env-entry> element in the deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class ContextEnvironment implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this environment entry. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The name of this environment entry. + */ + private String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + * Does this environment entry allow overrides by the application + * deployment descriptor? + */ + private boolean override = true; + + public boolean getOverride() { + return (this.override); + } + + public void setOverride(boolean override) { + this.override = override; + } + + + /** + * The type of this environment entry. + */ + private String type = null; + + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + } + + + /** + * The value of this environment entry. + */ + private String value = null; + + public String getValue() { + return (this.value); + } + + public void setValue(String value) { + this.value = value; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextEnvironment["); + sb.append("name="); + sb.append(name); + if (description != null) { + sb.append(", description="); + sb.append(description); + } + if (type != null) { + sb.append(", type="); + sb.append(type); + } + if (value != null) { + sb.append(", value="); + sb.append(value); + } + sb.append(", override="); + sb.append(override); + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * The NamingResources with which we are associated (if any). + */ + protected NamingResources resources = null; + + public NamingResources getNamingResources() { + return (this.resources); + } + + void setNamingResources(NamingResources resources) { + this.resources = resources; + } + + +} diff --git a/java/org/apache/catalina/deploy/ContextLocalEjb.java b/java/org/apache/catalina/deploy/ContextLocalEjb.java index 8d2a52fa0..afc4190f9 100644 --- a/java/org/apache/catalina/deploy/ContextLocalEjb.java +++ b/java/org/apache/catalina/deploy/ContextLocalEjb.java @@ -1,115 +1,115 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of a local EJB resource reference for a web application, as - * represented in a <ejb-local-ref> element in the - * deployment descriptor. - * - * @author Craig R. McClanahan - * @author Peter Rossbach (pero@apache.org) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ContextLocalEjb extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - /** - * The name of the EJB home implementation class. - */ - private String home = null; - - public String getHome() { - return (this.home); - } - - public void setHome(String home) { - this.home = home; - } - - - /** - * The link to a J2EE EJB definition. - */ - private String link = null; - - public String getLink() { - return (this.link); - } - - public void setLink(String link) { - this.link = link; - } - - - /** - * The name of the EJB local implementation class. - */ - private String local = null; - - public String getLocal() { - return (this.local); - } - - public void setLocal(String local) { - this.local = local; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextLocalEjb["); - sb.append("name="); - sb.append(getName()); - if (getDescription() != null) { - sb.append(", description="); - sb.append(getDescription()); - } - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - if (home != null) { - sb.append(", home="); - sb.append(home); - } - if (link != null) { - sb.append(", link="); - sb.append(link); - } - if (local != null) { - sb.append(", local="); - sb.append(local); - } - sb.append("]"); - return (sb.toString()); - - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of a local EJB resource reference for a web application, as + * represented in a <ejb-local-ref> element in the + * deployment descriptor. + * + * @author Craig R. McClanahan + * @author Peter Rossbach (pero@apache.org) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ContextLocalEjb extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + /** + * The name of the EJB home implementation class. + */ + private String home = null; + + public String getHome() { + return (this.home); + } + + public void setHome(String home) { + this.home = home; + } + + + /** + * The link to a J2EE EJB definition. + */ + private String link = null; + + public String getLink() { + return (this.link); + } + + public void setLink(String link) { + this.link = link; + } + + + /** + * The name of the EJB local implementation class. + */ + private String local = null; + + public String getLocal() { + return (this.local); + } + + public void setLocal(String local) { + this.local = local; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextLocalEjb["); + sb.append("name="); + sb.append(getName()); + if (getDescription() != null) { + sb.append(", description="); + sb.append(getDescription()); + } + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + if (home != null) { + sb.append(", home="); + sb.append(home); + } + if (link != null) { + sb.append(", link="); + sb.append(link); + } + if (local != null) { + sb.append(", local="); + sb.append(local); + } + sb.append("]"); + return (sb.toString()); + + } +} diff --git a/java/org/apache/catalina/deploy/ContextResource.java b/java/org/apache/catalina/deploy/ContextResource.java index 57e30c219..8bb52d310 100644 --- a/java/org/apache/catalina/deploy/ContextResource.java +++ b/java/org/apache/catalina/deploy/ContextResource.java @@ -1,99 +1,99 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - -/** - * Representation of a resource reference for a web application, as - * represented in a <resource-ref> element in the - * deployment descriptor. - * - * @author Craig R. McClanahan - * @author Peter Rossbach (pero@apache.org) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ContextResource extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The authorization requirement for this resource - * (Application or Container). - */ - private String auth = null; - - public String getAuth() { - return (this.auth); - } - - public void setAuth(String auth) { - this.auth = auth; - } - - /** - * The sharing scope of this resource factory (Shareable - * or Unshareable). - */ - private String scope = "Shareable"; - - public String getScope() { - return (this.scope); - } - - public void setScope(String scope) { - this.scope = scope; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextResource["); - sb.append("name="); - sb.append(getName()); - if (getDescription() != null) { - sb.append(", description="); - sb.append(getDescription()); - } - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - if (auth != null) { - sb.append(", auth="); - sb.append(auth); - } - if (scope != null) { - sb.append(", scope="); - sb.append(scope); - } - sb.append("]"); - return (sb.toString()); - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + +/** + * Representation of a resource reference for a web application, as + * represented in a <resource-ref> element in the + * deployment descriptor. + * + * @author Craig R. McClanahan + * @author Peter Rossbach (pero@apache.org) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ContextResource extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The authorization requirement for this resource + * (Application or Container). + */ + private String auth = null; + + public String getAuth() { + return (this.auth); + } + + public void setAuth(String auth) { + this.auth = auth; + } + + /** + * The sharing scope of this resource factory (Shareable + * or Unshareable). + */ + private String scope = "Shareable"; + + public String getScope() { + return (this.scope); + } + + public void setScope(String scope) { + this.scope = scope; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextResource["); + sb.append("name="); + sb.append(getName()); + if (getDescription() != null) { + sb.append(", description="); + sb.append(getDescription()); + } + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + if (auth != null) { + sb.append(", auth="); + sb.append(auth); + } + if (scope != null) { + sb.append(", scope="); + sb.append(scope); + } + sb.append("]"); + return (sb.toString()); + + } + +} diff --git a/java/org/apache/catalina/deploy/ContextResourceEnvRef.java b/java/org/apache/catalina/deploy/ContextResourceEnvRef.java index fda2a8bd0..a554e9949 100644 --- a/java/org/apache/catalina/deploy/ContextResourceEnvRef.java +++ b/java/org/apache/catalina/deploy/ContextResourceEnvRef.java @@ -1,75 +1,75 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of an application resource reference, as represented in - * an <res-env-refy> element in the deployment descriptor. - * - * @author Craig R. McClanahan - * @author Peter Rossbach (pero@apache.org) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ContextResourceEnvRef extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - /** - * Does this environment entry allow overrides by the application - * deployment descriptor? - */ - private boolean override = true; - - public boolean getOverride() { - return (this.override); - } - - public void setOverride(boolean override) { - this.override = override; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextResourceEnvRef["); - sb.append("name="); - sb.append(getName()); - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - sb.append(", override="); - sb.append(override); - sb.append("]"); - return (sb.toString()); - - } - - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of an application resource reference, as represented in + * an <res-env-refy> element in the deployment descriptor. + * + * @author Craig R. McClanahan + * @author Peter Rossbach (pero@apache.org) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ContextResourceEnvRef extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + /** + * Does this environment entry allow overrides by the application + * deployment descriptor? + */ + private boolean override = true; + + public boolean getOverride() { + return (this.override); + } + + public void setOverride(boolean override) { + this.override = override; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextResourceEnvRef["); + sb.append("name="); + sb.append(getName()); + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + sb.append(", override="); + sb.append(override); + sb.append("]"); + return (sb.toString()); + + } + + + +} diff --git a/java/org/apache/catalina/deploy/ContextResourceLink.java b/java/org/apache/catalina/deploy/ContextResourceLink.java index 7b566bba7..0a4f9762f 100644 --- a/java/org/apache/catalina/deploy/ContextResourceLink.java +++ b/java/org/apache/catalina/deploy/ContextResourceLink.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of a resource link for a web application, as - * represented in a <ResourceLink> element in the - * server configuration file. - * - * @author Remy Maucherat - * @author Peter Rossbach (Peter Rossbach (pero@apache.org)) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ContextResourceLink extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - /** - * The global name of this resource. - */ - private String global = null; - - public String getGlobal() { - return (this.global); - } - - public void setGlobal(String global) { - this.global = global; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextResourceLink["); - sb.append("name="); - sb.append(getName()); - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - if (getGlobal() != null) { - sb.append(", global="); - sb.append(getGlobal()); - } - sb.append("]"); - return (sb.toString()); - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of a resource link for a web application, as + * represented in a <ResourceLink> element in the + * server configuration file. + * + * @author Remy Maucherat + * @author Peter Rossbach (Peter Rossbach (pero@apache.org)) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ContextResourceLink extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + /** + * The global name of this resource. + */ + private String global = null; + + public String getGlobal() { + return (this.global); + } + + public void setGlobal(String global) { + this.global = global; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextResourceLink["); + sb.append("name="); + sb.append(getName()); + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + if (getGlobal() != null) { + sb.append(", global="); + sb.append(getGlobal()); + } + sb.append("]"); + return (sb.toString()); + + } + +} diff --git a/java/org/apache/catalina/deploy/ContextService.java b/java/org/apache/catalina/deploy/ContextService.java index 1930502b8..3e2c7160d 100644 --- a/java/org/apache/catalina/deploy/ContextService.java +++ b/java/org/apache/catalina/deploy/ContextService.java @@ -1,235 +1,235 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - -/** - * Representation of a web service reference for a web application, as - * represented in a <service-ref> element in the - * deployment descriptor. - * - * @author Fabien Carrion - * @version $Revision: 303342 $ $Date: 2005-03-15 23:29:49 -0700 (Web, 15 Mar 2006) $ - */ - -public class ContextService extends ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The WebService reference name. - */ - private String displayname = null; - - public String getDisplayname() { - return (this.displayname); - } - - public void setDisplayname(String displayname) { - this.displayname = displayname; - } - - /** - * An icon for this WebService. - */ - private String icon = null; - - public String getIcon() { - return (this.icon); - } - - public void setIcon(String icon) { - this.icon = icon; - } - - /** - * An icon for this WebService. - */ - private String serviceinterface = null; - - public String getServiceinterface() { - return (this.serviceinterface); - } - - public void setServiceinterface(String serviceinterface) { - this.serviceinterface = serviceinterface; - } - - /** - * Contains the location (relative to the root of - * the module) of the web service WSDL description. - */ - private String wsdlfile = null; - - public String getWsdlfile() { - return (this.wsdlfile); - } - - public void setWsdlfile(String wsdlfile) { - this.wsdlfile = wsdlfile; - } - - /** - * A file specifying the correlation of the WSDL definition - * to the interfaces (Service Endpoint Interface, Service Interface). - */ - private String jaxrpcmappingfile = null; - - public String getJaxrpcmappingfile() { - return (this.jaxrpcmappingfile); - } - - public void setJaxrpcmappingfile(String jaxrpcmappingfile) { - this.jaxrpcmappingfile = jaxrpcmappingfile; - } - - /** - * Declares the specific WSDL service element that is being referred to. - * It is not specified if no wsdl-file is declared or if WSDL contains only - * 1 service element. - * - * A service-qname is composed by a namespaceURI and a localpart. - * It must be defined if more than 1 service is declared in the WSDL. - * - * serviceqname[0] : namespaceURI - * serviceqname[1] : localpart - */ - private String[] serviceqname = new String[2]; - - public String[] getServiceqname() { - return (this.serviceqname); - } - - public void setServiceqname(String[] serviceqname) { - this.serviceqname = serviceqname; - } - - public void setServiceqname(String serviceqname, int i) { - this.serviceqname[i] = serviceqname; - } - - public void setNamespaceURI(String namespaceuri) { - this.serviceqname[0] = namespaceuri; - } - - public void setLocalpart(String localpart) { - this.serviceqname[1] = localpart; - } - - /** - * Declares a client dependency on the container to resolving a Service Endpoint Interface - * to a WSDL port. It optionally associates the Service Endpoint Interface with a - * particular port-component. - * - * portcomponent[0] : service-endpoint-interface - * portcomponent[1] : port-component-link - */ - private String[] portcomponent = new String[2]; - - public String[] getPortcomponent() { - return (this.portcomponent); - } - - public void setPortcomponent(String[] portcomponent) { - this.portcomponent = portcomponent; - } - - public void setPortcomponent(String portcomponent, int i) { - this.portcomponent[i] = portcomponent; - } - - public void setServiceendpoint(String serviceendpoint) { - this.portcomponent[0] = serviceendpoint; - } - - public void setPortlink(String portlink) { - this.portcomponent[1] = portlink; - } - - /** - * A list of Handler to use for this service-ref. - * - * The instanciation of the handler have to be done. - */ - private String handler = null; - - public String getHandler() { - return (this.handler); - } - - public void setHandler(String handler) { - this.handler = handler; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ContextService["); - sb.append("name="); - sb.append(getName()); - if (getDescription() != null) { - sb.append(", description="); - sb.append(getDescription()); - } - if (getType() != null) { - sb.append(", type="); - sb.append(getType()); - } - if (displayname != null) { - sb.append(", displayname="); - sb.append(displayname); - } - if (icon != null) { - sb.append(", icon="); - sb.append(icon); - } - if (wsdlfile != null) { - sb.append(", wsdl-file="); - sb.append(wsdlfile); - } - if (jaxrpcmappingfile != null) { - sb.append(", jaxrpc-mapping-file="); - sb.append(jaxrpcmappingfile); - } - if (serviceqname != null) { - sb.append(", service-qname="); - sb.append(serviceqname); - } - if (portcomponent != null) { - sb.append(", port-component="); - sb.append(portcomponent); - } - if (handler != null) { - sb.append(", handler="); - sb.append(handler); - } - sb.append("]"); - return (sb.toString()); - - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + +/** + * Representation of a web service reference for a web application, as + * represented in a <service-ref> element in the + * deployment descriptor. + * + * @author Fabien Carrion + * @version $Revision: 303342 $ $Date: 2005-03-15 23:29:49 -0700 (Web, 15 Mar 2006) $ + */ + +public class ContextService extends ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The WebService reference name. + */ + private String displayname = null; + + public String getDisplayname() { + return (this.displayname); + } + + public void setDisplayname(String displayname) { + this.displayname = displayname; + } + + /** + * An icon for this WebService. + */ + private String icon = null; + + public String getIcon() { + return (this.icon); + } + + public void setIcon(String icon) { + this.icon = icon; + } + + /** + * An icon for this WebService. + */ + private String serviceinterface = null; + + public String getServiceinterface() { + return (this.serviceinterface); + } + + public void setServiceinterface(String serviceinterface) { + this.serviceinterface = serviceinterface; + } + + /** + * Contains the location (relative to the root of + * the module) of the web service WSDL description. + */ + private String wsdlfile = null; + + public String getWsdlfile() { + return (this.wsdlfile); + } + + public void setWsdlfile(String wsdlfile) { + this.wsdlfile = wsdlfile; + } + + /** + * A file specifying the correlation of the WSDL definition + * to the interfaces (Service Endpoint Interface, Service Interface). + */ + private String jaxrpcmappingfile = null; + + public String getJaxrpcmappingfile() { + return (this.jaxrpcmappingfile); + } + + public void setJaxrpcmappingfile(String jaxrpcmappingfile) { + this.jaxrpcmappingfile = jaxrpcmappingfile; + } + + /** + * Declares the specific WSDL service element that is being referred to. + * It is not specified if no wsdl-file is declared or if WSDL contains only + * 1 service element. + * + * A service-qname is composed by a namespaceURI and a localpart. + * It must be defined if more than 1 service is declared in the WSDL. + * + * serviceqname[0] : namespaceURI + * serviceqname[1] : localpart + */ + private String[] serviceqname = new String[2]; + + public String[] getServiceqname() { + return (this.serviceqname); + } + + public void setServiceqname(String[] serviceqname) { + this.serviceqname = serviceqname; + } + + public void setServiceqname(String serviceqname, int i) { + this.serviceqname[i] = serviceqname; + } + + public void setNamespaceURI(String namespaceuri) { + this.serviceqname[0] = namespaceuri; + } + + public void setLocalpart(String localpart) { + this.serviceqname[1] = localpart; + } + + /** + * Declares a client dependency on the container to resolving a Service Endpoint Interface + * to a WSDL port. It optionally associates the Service Endpoint Interface with a + * particular port-component. + * + * portcomponent[0] : service-endpoint-interface + * portcomponent[1] : port-component-link + */ + private String[] portcomponent = new String[2]; + + public String[] getPortcomponent() { + return (this.portcomponent); + } + + public void setPortcomponent(String[] portcomponent) { + this.portcomponent = portcomponent; + } + + public void setPortcomponent(String portcomponent, int i) { + this.portcomponent[i] = portcomponent; + } + + public void setServiceendpoint(String serviceendpoint) { + this.portcomponent[0] = serviceendpoint; + } + + public void setPortlink(String portlink) { + this.portcomponent[1] = portlink; + } + + /** + * A list of Handler to use for this service-ref. + * + * The instanciation of the handler have to be done. + */ + private String handler = null; + + public String getHandler() { + return (this.handler); + } + + public void setHandler(String handler) { + this.handler = handler; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ContextService["); + sb.append("name="); + sb.append(getName()); + if (getDescription() != null) { + sb.append(", description="); + sb.append(getDescription()); + } + if (getType() != null) { + sb.append(", type="); + sb.append(getType()); + } + if (displayname != null) { + sb.append(", displayname="); + sb.append(displayname); + } + if (icon != null) { + sb.append(", icon="); + sb.append(icon); + } + if (wsdlfile != null) { + sb.append(", wsdl-file="); + sb.append(wsdlfile); + } + if (jaxrpcmappingfile != null) { + sb.append(", jaxrpc-mapping-file="); + sb.append(jaxrpcmappingfile); + } + if (serviceqname != null) { + sb.append(", service-qname="); + sb.append(serviceqname); + } + if (portcomponent != null) { + sb.append(", port-component="); + sb.append(portcomponent); + } + if (handler != null) { + sb.append(", handler="); + sb.append(handler); + } + sb.append("]"); + return (sb.toString()); + + } + +} diff --git a/java/org/apache/catalina/deploy/ContextTransaction.java b/java/org/apache/catalina/deploy/ContextTransaction.java index 092aaf6f6..a198667d1 100644 --- a/java/org/apache/catalina/deploy/ContextTransaction.java +++ b/java/org/apache/catalina/deploy/ContextTransaction.java @@ -1,105 +1,105 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; -import java.util.HashMap; -import java.util.Iterator; - - -/** - * Representation of an application resource reference, as represented in - * an <res-env-refy> element in the deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 303032 $ $Date: 2004-07-26 18:04:02 +0200 (lun., 26 juil. 2004) $ - */ - -public class ContextTransaction implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * Holder for our configured properties. - */ - private HashMap properties = new HashMap(); - - /** - * Return a configured property. - */ - public Object getProperty(String name) { - return properties.get(name); - } - - /** - * Set a configured property. - */ - public void setProperty(String name, Object value) { - properties.put(name, value); - } - - /** - * remove a configured property. - */ - public void removeProperty(String name) { - properties.remove(name); - } - - /** - * List properties. - */ - public Iterator listProperties() { - return properties.keySet().iterator(); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("Transaction["); - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * The NamingResources with which we are associated (if any). - */ - protected NamingResources resources = null; - - public NamingResources getNamingResources() { - return (this.resources); - } - - void setNamingResources(NamingResources resources) { - this.resources = resources; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Iterator; + + +/** + * Representation of an application resource reference, as represented in + * an <res-env-refy> element in the deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 303032 $ $Date: 2004-07-26 18:04:02 +0200 (lun., 26 juil. 2004) $ + */ + +public class ContextTransaction implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * Holder for our configured properties. + */ + private HashMap properties = new HashMap(); + + /** + * Return a configured property. + */ + public Object getProperty(String name) { + return properties.get(name); + } + + /** + * Set a configured property. + */ + public void setProperty(String name, Object value) { + properties.put(name, value); + } + + /** + * remove a configured property. + */ + public void removeProperty(String name) { + properties.remove(name); + } + + /** + * List properties. + */ + public Iterator listProperties() { + return properties.keySet().iterator(); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("Transaction["); + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * The NamingResources with which we are associated (if any). + */ + protected NamingResources resources = null; + + public NamingResources getNamingResources() { + return (this.resources); + } + + void setNamingResources(NamingResources resources) { + this.resources = resources; + } + + +} diff --git a/java/org/apache/catalina/deploy/ErrorPage.java b/java/org/apache/catalina/deploy/ErrorPage.java index 4bcbf55cf..6fb5d5dc7 100644 --- a/java/org/apache/catalina/deploy/ErrorPage.java +++ b/java/org/apache/catalina/deploy/ErrorPage.java @@ -1,170 +1,170 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import org.apache.catalina.util.RequestUtil; -import java.io.Serializable; - - -/** - * Representation of an error page element for a web application, - * as represented in a <error-page> element in the - * deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class ErrorPage implements Serializable { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The error (status) code for which this error page is active. - */ - private int errorCode = 0; - - - /** - * The exception type for which this error page is active. - */ - private String exceptionType = null; - - - /** - * The context-relative location to handle this error or exception. - */ - private String location = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the error code. - */ - public int getErrorCode() { - - return (this.errorCode); - - } - - - /** - * Set the error code. - * - * @param errorCode The new error code - */ - public void setErrorCode(int errorCode) { - - this.errorCode = errorCode; - - } - - - /** - * Set the error code (hack for default XmlMapper data type). - * - * @param errorCode The new error code - */ - public void setErrorCode(String errorCode) { - - try { - this.errorCode = Integer.parseInt(errorCode); - } catch (Throwable t) { - this.errorCode = 0; - } - - } - - - /** - * Return the exception type. - */ - public String getExceptionType() { - - return (this.exceptionType); - - } - - - /** - * Set the exception type. - * - * @param exceptionType The new exception type - */ - public void setExceptionType(String exceptionType) { - - this.exceptionType = exceptionType; - - } - - - /** - * Return the location. - */ - public String getLocation() { - - return (this.location); - - } - - - /** - * Set the location. - * - * @param location The new location - */ - public void setLocation(String location) { - - // if ((location == null) || !location.startsWith("/")) - // throw new IllegalArgumentException - // ("Error Page Location must start with a '/'"); - this.location = RequestUtil.URLDecode(location); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Render a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ErrorPage["); - if (exceptionType == null) { - sb.append("errorCode="); - sb.append(errorCode); - } else { - sb.append("exceptionType="); - sb.append(exceptionType); - } - sb.append(", location="); - sb.append(location); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import org.apache.catalina.util.RequestUtil; +import java.io.Serializable; + + +/** + * Representation of an error page element for a web application, + * as represented in a <error-page> element in the + * deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class ErrorPage implements Serializable { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The error (status) code for which this error page is active. + */ + private int errorCode = 0; + + + /** + * The exception type for which this error page is active. + */ + private String exceptionType = null; + + + /** + * The context-relative location to handle this error or exception. + */ + private String location = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the error code. + */ + public int getErrorCode() { + + return (this.errorCode); + + } + + + /** + * Set the error code. + * + * @param errorCode The new error code + */ + public void setErrorCode(int errorCode) { + + this.errorCode = errorCode; + + } + + + /** + * Set the error code (hack for default XmlMapper data type). + * + * @param errorCode The new error code + */ + public void setErrorCode(String errorCode) { + + try { + this.errorCode = Integer.parseInt(errorCode); + } catch (Throwable t) { + this.errorCode = 0; + } + + } + + + /** + * Return the exception type. + */ + public String getExceptionType() { + + return (this.exceptionType); + + } + + + /** + * Set the exception type. + * + * @param exceptionType The new exception type + */ + public void setExceptionType(String exceptionType) { + + this.exceptionType = exceptionType; + + } + + + /** + * Return the location. + */ + public String getLocation() { + + return (this.location); + + } + + + /** + * Set the location. + * + * @param location The new location + */ + public void setLocation(String location) { + + // if ((location == null) || !location.startsWith("/")) + // throw new IllegalArgumentException + // ("Error Page Location must start with a '/'"); + this.location = RequestUtil.URLDecode(location); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Render a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ErrorPage["); + if (exceptionType == null) { + sb.append("errorCode="); + sb.append(errorCode); + } else { + sb.append("exceptionType="); + sb.append(exceptionType); + } + sb.append(", location="); + sb.append(location); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/FilterDef.java b/java/org/apache/catalina/deploy/FilterDef.java index d81b08390..7b9888853 100644 --- a/java/org/apache/catalina/deploy/FilterDef.java +++ b/java/org/apache/catalina/deploy/FilterDef.java @@ -1,171 +1,171 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import java.util.HashMap; -import java.util.Map; -import java.io.Serializable; - - -/** - * Representation of a filter definition for a web application, as represented - * in a <filter> element in the deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class FilterDef implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this filter. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The display name of this filter. - */ - private String displayName = null; - - public String getDisplayName() { - return (this.displayName); - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - - /** - * The fully qualified name of the Java class that implements this filter. - */ - private String filterClass = null; - - public String getFilterClass() { - return (this.filterClass); - } - - public void setFilterClass(String filterClass) { - this.filterClass = filterClass; - } - - - /** - * The name of this filter, which must be unique among the filters - * defined for a particular web application. - */ - private String filterName = null; - - public String getFilterName() { - return (this.filterName); - } - - public void setFilterName(String filterName) { - this.filterName = filterName; - } - - - /** - * The large icon associated with this filter. - */ - private String largeIcon = null; - - public String getLargeIcon() { - return (this.largeIcon); - } - - public void setLargeIcon(String largeIcon) { - this.largeIcon = largeIcon; - } - - - /** - * The set of initialization parameters for this filter, keyed by - * parameter name. - */ - private Map parameters = new HashMap(); - - public Map getParameterMap() { - - return (this.parameters); - - } - - - /** - * The small icon associated with this filter. - */ - private String smallIcon = null; - - public String getSmallIcon() { - return (this.smallIcon); - } - - public void setSmallIcon(String smallIcon) { - this.smallIcon = smallIcon; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an initialization parameter to the set of parameters associated - * with this filter. - * - * @param name The initialization parameter name - * @param value The initialization parameter value - */ - public void addInitParameter(String name, String value) { - - parameters.put(name, value); - - } - - - /** - * Render a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("FilterDef["); - sb.append("filterName="); - sb.append(this.filterName); - sb.append(", filterClass="); - sb.append(this.filterClass); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import java.util.HashMap; +import java.util.Map; +import java.io.Serializable; + + +/** + * Representation of a filter definition for a web application, as represented + * in a <filter> element in the deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class FilterDef implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this filter. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The display name of this filter. + */ + private String displayName = null; + + public String getDisplayName() { + return (this.displayName); + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + + /** + * The fully qualified name of the Java class that implements this filter. + */ + private String filterClass = null; + + public String getFilterClass() { + return (this.filterClass); + } + + public void setFilterClass(String filterClass) { + this.filterClass = filterClass; + } + + + /** + * The name of this filter, which must be unique among the filters + * defined for a particular web application. + */ + private String filterName = null; + + public String getFilterName() { + return (this.filterName); + } + + public void setFilterName(String filterName) { + this.filterName = filterName; + } + + + /** + * The large icon associated with this filter. + */ + private String largeIcon = null; + + public String getLargeIcon() { + return (this.largeIcon); + } + + public void setLargeIcon(String largeIcon) { + this.largeIcon = largeIcon; + } + + + /** + * The set of initialization parameters for this filter, keyed by + * parameter name. + */ + private Map parameters = new HashMap(); + + public Map getParameterMap() { + + return (this.parameters); + + } + + + /** + * The small icon associated with this filter. + */ + private String smallIcon = null; + + public String getSmallIcon() { + return (this.smallIcon); + } + + public void setSmallIcon(String smallIcon) { + this.smallIcon = smallIcon; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an initialization parameter to the set of parameters associated + * with this filter. + * + * @param name The initialization parameter name + * @param value The initialization parameter value + */ + public void addInitParameter(String name, String value) { + + parameters.put(name, value); + + } + + + /** + * Render a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("FilterDef["); + sb.append("filterName="); + sb.append(this.filterName); + sb.append(", filterClass="); + sb.append(this.filterClass); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/FilterMap.java b/java/org/apache/catalina/deploy/FilterMap.java index 2b285e385..c05df9ed6 100644 --- a/java/org/apache/catalina/deploy/FilterMap.java +++ b/java/org/apache/catalina/deploy/FilterMap.java @@ -1,234 +1,234 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import org.apache.catalina.util.RequestUtil; -import java.io.Serializable; - - -/** - * Representation of a filter mapping for a web application, as represented - * in a <filter-mapping> element in the deployment - * descriptor. Each filter mapping must contain a filter name plus either - * a URL pattern or a servlet name. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class FilterMap implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The name of this filter to be executed when this mapping matches - * a particular request. - */ - - public static final int ERROR = 1; - public static final int FORWARD = 2; - public static final int FORWARD_ERROR =3; - public static final int INCLUDE = 4; - public static final int INCLUDE_ERROR = 5; - public static final int INCLUDE_ERROR_FORWARD =6; - public static final int INCLUDE_FORWARD = 7; - public static final int REQUEST = 8; - public static final int REQUEST_ERROR = 9; - public static final int REQUEST_ERROR_FORWARD = 10; - public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11; - public static final int REQUEST_ERROR_INCLUDE = 12; - public static final int REQUEST_FORWARD = 13; - public static final int REQUEST_INCLUDE = 14; - public static final int REQUEST_FORWARD_INCLUDE= 15; - - // represents nothing having been set. This will be seen - // as equal to a REQUEST - private static final int NOT_SET = -1; - - private int dispatcherMapping=NOT_SET; - - private String filterName = null; - - public String getFilterName() { - return (this.filterName); - } - - public void setFilterName(String filterName) { - this.filterName = filterName; - } - - - /** - * The servlet name this mapping matches. - */ - private String[] servletNames = new String[0]; - - public String[] getServletNames() { - return (this.servletNames); - } - - public void addServletName(String servletName) { - String[] results = new String[servletNames.length + 1]; - System.arraycopy(servletNames, 0, results, 0, servletNames.length); - results[servletNames.length] = servletName; - servletNames = results; - } - - - /** - * The flag that indicates this mapping will match all. - */ - private boolean allMatch = false; - - public boolean getAllMatch() { - return allMatch; - } - - - /** - * The URL pattern this mapping matches. - */ - private String[] urlPatterns = new String[0]; - - public String[] getURLPatterns() { - return (this.urlPatterns); - } - - public void addURLPattern(String urlPattern) { - if ("*".equals(urlPattern)) { - this.allMatch = true; - } else { - String[] results = new String[urlPatterns.length + 1]; - System.arraycopy(urlPatterns, 0, results, 0, urlPatterns.length); - results[urlPatterns.length] = RequestUtil.URLDecode(urlPattern); - urlPatterns = results; - } - } - - /** - * - * This method will be used to set the current state of the FilterMap - * representing the state of when filters should be applied: - * - * ERROR - * FORWARD - * FORWARD_ERROR - * INCLUDE - * INCLUDE_ERROR - * INCLUDE_ERROR_FORWARD - * REQUEST - * REQUEST_ERROR - * REQUEST_ERROR_INCLUDE - * REQUEST_ERROR_FORWARD_INCLUDE - * REQUEST_INCLUDE - * REQUEST_FORWARD, - * REQUEST_FORWARD_INCLUDE - * - */ - public void setDispatcher(String dispatcherString) { - String dispatcher = dispatcherString.toUpperCase(); - - if (dispatcher.equals("FORWARD")) { - - // apply FORWARD to the global dispatcherMapping. - switch (dispatcherMapping) { - case NOT_SET : dispatcherMapping = FORWARD; break; - case ERROR : dispatcherMapping = FORWARD_ERROR; break; - case INCLUDE : dispatcherMapping = INCLUDE_FORWARD; break; - case INCLUDE_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; - case REQUEST : dispatcherMapping = REQUEST_FORWARD; break; - case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; - case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; - case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; - } - } else if (dispatcher.equals("INCLUDE")) { - // apply INCLUDE to the global dispatcherMapping. - switch (dispatcherMapping) { - case NOT_SET : dispatcherMapping = INCLUDE; break; - case ERROR : dispatcherMapping = INCLUDE_ERROR; break; - case FORWARD : dispatcherMapping = INCLUDE_FORWARD; break; - case FORWARD_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; - case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break; - case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; - case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; - case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; - } - } else if (dispatcher.equals("REQUEST")) { - // apply REQUEST to the global dispatcherMapping. - switch (dispatcherMapping) { - case NOT_SET : dispatcherMapping = REQUEST; break; - case ERROR : dispatcherMapping = REQUEST_ERROR; break; - case FORWARD : dispatcherMapping = REQUEST_FORWARD; break; - case FORWARD_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; - case INCLUDE : dispatcherMapping = REQUEST_INCLUDE; break; - case INCLUDE_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; - case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; - case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; - } - } else if (dispatcher.equals("ERROR")) { - // apply ERROR to the global dispatcherMapping. - switch (dispatcherMapping) { - case NOT_SET : dispatcherMapping = ERROR; break; - case FORWARD : dispatcherMapping = FORWARD_ERROR; break; - case INCLUDE : dispatcherMapping = INCLUDE_ERROR; break; - case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; - case REQUEST : dispatcherMapping = REQUEST_ERROR; break; - case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; - case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break; - case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; - } - } - } - - public int getDispatcherMapping() { - // per the SRV.6.2.5 absence of any dispatcher elements is - // equivelant to a REQUEST value - if (dispatcherMapping == NOT_SET) return REQUEST; - else return dispatcherMapping; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Render a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("FilterMap["); - sb.append("filterName="); - sb.append(this.filterName); - for (int i = 0; i < servletNames.length; i++) { - sb.append(", servletName="); - sb.append(servletNames[i]); - } - for (int i = 0; i < urlPatterns.length; i++) { - sb.append(", urlPattern="); - sb.append(urlPatterns[i]); - } - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import org.apache.catalina.util.RequestUtil; +import java.io.Serializable; + + +/** + * Representation of a filter mapping for a web application, as represented + * in a <filter-mapping> element in the deployment + * descriptor. Each filter mapping must contain a filter name plus either + * a URL pattern or a servlet name. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class FilterMap implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The name of this filter to be executed when this mapping matches + * a particular request. + */ + + public static final int ERROR = 1; + public static final int FORWARD = 2; + public static final int FORWARD_ERROR =3; + public static final int INCLUDE = 4; + public static final int INCLUDE_ERROR = 5; + public static final int INCLUDE_ERROR_FORWARD =6; + public static final int INCLUDE_FORWARD = 7; + public static final int REQUEST = 8; + public static final int REQUEST_ERROR = 9; + public static final int REQUEST_ERROR_FORWARD = 10; + public static final int REQUEST_ERROR_FORWARD_INCLUDE = 11; + public static final int REQUEST_ERROR_INCLUDE = 12; + public static final int REQUEST_FORWARD = 13; + public static final int REQUEST_INCLUDE = 14; + public static final int REQUEST_FORWARD_INCLUDE= 15; + + // represents nothing having been set. This will be seen + // as equal to a REQUEST + private static final int NOT_SET = -1; + + private int dispatcherMapping=NOT_SET; + + private String filterName = null; + + public String getFilterName() { + return (this.filterName); + } + + public void setFilterName(String filterName) { + this.filterName = filterName; + } + + + /** + * The servlet name this mapping matches. + */ + private String[] servletNames = new String[0]; + + public String[] getServletNames() { + return (this.servletNames); + } + + public void addServletName(String servletName) { + String[] results = new String[servletNames.length + 1]; + System.arraycopy(servletNames, 0, results, 0, servletNames.length); + results[servletNames.length] = servletName; + servletNames = results; + } + + + /** + * The flag that indicates this mapping will match all. + */ + private boolean allMatch = false; + + public boolean getAllMatch() { + return allMatch; + } + + + /** + * The URL pattern this mapping matches. + */ + private String[] urlPatterns = new String[0]; + + public String[] getURLPatterns() { + return (this.urlPatterns); + } + + public void addURLPattern(String urlPattern) { + if ("*".equals(urlPattern)) { + this.allMatch = true; + } else { + String[] results = new String[urlPatterns.length + 1]; + System.arraycopy(urlPatterns, 0, results, 0, urlPatterns.length); + results[urlPatterns.length] = RequestUtil.URLDecode(urlPattern); + urlPatterns = results; + } + } + + /** + * + * This method will be used to set the current state of the FilterMap + * representing the state of when filters should be applied: + * + * ERROR + * FORWARD + * FORWARD_ERROR + * INCLUDE + * INCLUDE_ERROR + * INCLUDE_ERROR_FORWARD + * REQUEST + * REQUEST_ERROR + * REQUEST_ERROR_INCLUDE + * REQUEST_ERROR_FORWARD_INCLUDE + * REQUEST_INCLUDE + * REQUEST_FORWARD, + * REQUEST_FORWARD_INCLUDE + * + */ + public void setDispatcher(String dispatcherString) { + String dispatcher = dispatcherString.toUpperCase(); + + if (dispatcher.equals("FORWARD")) { + + // apply FORWARD to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = FORWARD; break; + case ERROR : dispatcherMapping = FORWARD_ERROR; break; + case INCLUDE : dispatcherMapping = INCLUDE_FORWARD; break; + case INCLUDE_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_FORWARD; break; + case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case REQUEST_ERROR_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + case REQUEST_INCLUDE : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("INCLUDE")) { + // apply INCLUDE to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = INCLUDE; break; + case ERROR : dispatcherMapping = INCLUDE_ERROR; break; + case FORWARD : dispatcherMapping = INCLUDE_FORWARD; break; + case FORWARD_ERROR : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_INCLUDE; break; + case REQUEST_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case REQUEST_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + case REQUEST_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("REQUEST")) { + // apply REQUEST to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = REQUEST; break; + case ERROR : dispatcherMapping = REQUEST_ERROR; break; + case FORWARD : dispatcherMapping = REQUEST_FORWARD; break; + case FORWARD_ERROR : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case INCLUDE : dispatcherMapping = REQUEST_INCLUDE; break; + case INCLUDE_ERROR : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case INCLUDE_FORWARD : dispatcherMapping = REQUEST_FORWARD_INCLUDE; break; + case INCLUDE_ERROR_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + } + } else if (dispatcher.equals("ERROR")) { + // apply ERROR to the global dispatcherMapping. + switch (dispatcherMapping) { + case NOT_SET : dispatcherMapping = ERROR; break; + case FORWARD : dispatcherMapping = FORWARD_ERROR; break; + case INCLUDE : dispatcherMapping = INCLUDE_ERROR; break; + case INCLUDE_FORWARD : dispatcherMapping = INCLUDE_ERROR_FORWARD; break; + case REQUEST : dispatcherMapping = REQUEST_ERROR; break; + case REQUEST_INCLUDE : dispatcherMapping = REQUEST_ERROR_INCLUDE; break; + case REQUEST_FORWARD : dispatcherMapping = REQUEST_ERROR_FORWARD; break; + case REQUEST_FORWARD_INCLUDE : dispatcherMapping = REQUEST_ERROR_FORWARD_INCLUDE; break; + } + } + } + + public int getDispatcherMapping() { + // per the SRV.6.2.5 absence of any dispatcher elements is + // equivelant to a REQUEST value + if (dispatcherMapping == NOT_SET) return REQUEST; + else return dispatcherMapping; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Render a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("FilterMap["); + sb.append("filterName="); + sb.append(this.filterName); + for (int i = 0; i < servletNames.length; i++) { + sb.append(", servletName="); + sb.append(servletNames[i]); + } + for (int i = 0; i < urlPatterns.length; i++) { + sb.append(", urlPattern="); + sb.append(urlPatterns[i]); + } + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/LoginConfig.java b/java/org/apache/catalina/deploy/LoginConfig.java index 38ba89647..cc8aa47af 100644 --- a/java/org/apache/catalina/deploy/LoginConfig.java +++ b/java/org/apache/catalina/deploy/LoginConfig.java @@ -1,166 +1,166 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import org.apache.catalina.util.RequestUtil; -import java.io.Serializable; - - -/** - * Representation of a login configuration element for a web application, - * as represented in a <login-config> element in the - * deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class LoginConfig implements Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new LoginConfig with default properties. - */ - public LoginConfig() { - - super(); - - } - - - /** - * Construct a new LoginConfig with the specified properties. - * - * @param authMethod The authentication method - * @param realmName The realm name - * @param loginPage The login page URI - * @param errorPage The error page URI - */ - public LoginConfig(String authMethod, String realmName, - String loginPage, String errorPage) { - - super(); - setAuthMethod(authMethod); - setRealmName(realmName); - setLoginPage(loginPage); - setErrorPage(errorPage); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * The authentication method to use for application login. Must be - * BASIC, DIGEST, FORM, or CLIENT-CERT. - */ - private String authMethod = null; - - public String getAuthMethod() { - return (this.authMethod); - } - - public void setAuthMethod(String authMethod) { - this.authMethod = authMethod; - } - - - /** - * The context-relative URI of the error page for form login. - */ - private String errorPage = null; - - public String getErrorPage() { - return (this.errorPage); - } - - public void setErrorPage(String errorPage) { - // if ((errorPage == null) || !errorPage.startsWith("/")) - // throw new IllegalArgumentException - // ("Error Page resource path must start with a '/'"); - this.errorPage = RequestUtil.URLDecode(errorPage); - } - - - /** - * The context-relative URI of the login page for form login. - */ - private String loginPage = null; - - public String getLoginPage() { - return (this.loginPage); - } - - public void setLoginPage(String loginPage) { - // if ((loginPage == null) || !loginPage.startsWith("/")) - // throw new IllegalArgumentException - // ("Login Page resource path must start with a '/'"); - this.loginPage = RequestUtil.URLDecode(loginPage); - } - - - /** - * The realm name used when challenging the user for authentication - * credentials. - */ - private String realmName = null; - - public String getRealmName() { - return (this.realmName); - } - - public void setRealmName(String realmName) { - this.realmName = realmName; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("LoginConfig["); - sb.append("authMethod="); - sb.append(authMethod); - if (realmName != null) { - sb.append(", realmName="); - sb.append(realmName); - } - if (loginPage != null) { - sb.append(", loginPage="); - sb.append(loginPage); - } - if (errorPage != null) { - sb.append(", errorPage="); - sb.append(errorPage); - } - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import org.apache.catalina.util.RequestUtil; +import java.io.Serializable; + + +/** + * Representation of a login configuration element for a web application, + * as represented in a <login-config> element in the + * deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class LoginConfig implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new LoginConfig with default properties. + */ + public LoginConfig() { + + super(); + + } + + + /** + * Construct a new LoginConfig with the specified properties. + * + * @param authMethod The authentication method + * @param realmName The realm name + * @param loginPage The login page URI + * @param errorPage The error page URI + */ + public LoginConfig(String authMethod, String realmName, + String loginPage, String errorPage) { + + super(); + setAuthMethod(authMethod); + setRealmName(realmName); + setLoginPage(loginPage); + setErrorPage(errorPage); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * The authentication method to use for application login. Must be + * BASIC, DIGEST, FORM, or CLIENT-CERT. + */ + private String authMethod = null; + + public String getAuthMethod() { + return (this.authMethod); + } + + public void setAuthMethod(String authMethod) { + this.authMethod = authMethod; + } + + + /** + * The context-relative URI of the error page for form login. + */ + private String errorPage = null; + + public String getErrorPage() { + return (this.errorPage); + } + + public void setErrorPage(String errorPage) { + // if ((errorPage == null) || !errorPage.startsWith("/")) + // throw new IllegalArgumentException + // ("Error Page resource path must start with a '/'"); + this.errorPage = RequestUtil.URLDecode(errorPage); + } + + + /** + * The context-relative URI of the login page for form login. + */ + private String loginPage = null; + + public String getLoginPage() { + return (this.loginPage); + } + + public void setLoginPage(String loginPage) { + // if ((loginPage == null) || !loginPage.startsWith("/")) + // throw new IllegalArgumentException + // ("Login Page resource path must start with a '/'"); + this.loginPage = RequestUtil.URLDecode(loginPage); + } + + + /** + * The realm name used when challenging the user for authentication + * credentials. + */ + private String realmName = null; + + public String getRealmName() { + return (this.realmName); + } + + public void setRealmName(String realmName) { + this.realmName = realmName; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("LoginConfig["); + sb.append("authMethod="); + sb.append(authMethod); + if (realmName != null) { + sb.append(", realmName="); + sb.append(realmName); + } + if (loginPage != null) { + sb.append(", loginPage="); + sb.append(loginPage); + } + if (errorPage != null) { + sb.append(", errorPage="); + sb.append(errorPage); + } + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/MessageDestination.java b/java/org/apache/catalina/deploy/MessageDestination.java index 3e8276b2d..d7078d453 100644 --- a/java/org/apache/catalina/deploy/MessageDestination.java +++ b/java/org/apache/catalina/deploy/MessageDestination.java @@ -1,140 +1,140 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -/** - *

    Representation of a message destination for a web application, as - * represented in a <message-destination> element - * in the deployment descriptor.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - * @since Tomcat 5.0 - */ - -public class MessageDestination { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this destination. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The display name of this destination. - */ - private String displayName = null; - - public String getDisplayName() { - return (this.displayName); - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - - /** - * The large icon of this destination. - */ - private String largeIcon = null; - - public String getLargeIcon() { - return (this.largeIcon); - } - - public void setLargeIcon(String largeIcon) { - this.largeIcon = largeIcon; - } - - - /** - * The name of this destination. - */ - private String name = null; - - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - - /** - * The small icon of this destination. - */ - private String smallIcon = null; - - public String getSmallIcon() { - return (this.smallIcon); - } - - public void setSmallIcon(String smallIcon) { - this.smallIcon = smallIcon; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("MessageDestination["); - sb.append("name="); - sb.append(name); - if (displayName != null) { - sb.append(", displayName="); - sb.append(displayName); - } - if (largeIcon != null) { - sb.append(", largeIcon="); - sb.append(largeIcon); - } - if (smallIcon != null) { - sb.append(", smallIcon="); - sb.append(smallIcon); - } - if (description != null) { - sb.append(", description="); - sb.append(description); - } - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +/** + *

    Representation of a message destination for a web application, as + * represented in a <message-destination> element + * in the deployment descriptor.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + * @since Tomcat 5.0 + */ + +public class MessageDestination { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this destination. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The display name of this destination. + */ + private String displayName = null; + + public String getDisplayName() { + return (this.displayName); + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + + /** + * The large icon of this destination. + */ + private String largeIcon = null; + + public String getLargeIcon() { + return (this.largeIcon); + } + + public void setLargeIcon(String largeIcon) { + this.largeIcon = largeIcon; + } + + + /** + * The name of this destination. + */ + private String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + * The small icon of this destination. + */ + private String smallIcon = null; + + public String getSmallIcon() { + return (this.smallIcon); + } + + public void setSmallIcon(String smallIcon) { + this.smallIcon = smallIcon; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("MessageDestination["); + sb.append("name="); + sb.append(name); + if (displayName != null) { + sb.append(", displayName="); + sb.append(displayName); + } + if (largeIcon != null) { + sb.append(", largeIcon="); + sb.append(largeIcon); + } + if (smallIcon != null) { + sb.append(", smallIcon="); + sb.append(smallIcon); + } + if (description != null) { + sb.append(", description="); + sb.append(description); + } + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/MessageDestinationRef.java b/java/org/apache/catalina/deploy/MessageDestinationRef.java index 542b7493a..9668fca53 100644 --- a/java/org/apache/catalina/deploy/MessageDestinationRef.java +++ b/java/org/apache/catalina/deploy/MessageDestinationRef.java @@ -1,159 +1,159 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - *

    Representation of a message destination reference for a web application, - * as represented in a <message-destination-ref> element - * in the deployment descriptor.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - * @since Tomcat 5.0 - */ - -public class MessageDestinationRef implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this destination ref. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The link of this destination ref. - */ - private String link = null; - - public String getLink() { - return (this.link); - } - - public void setLink(String link) { - this.link = link; - } - - - /** - * The name of this destination ref. - */ - private String name = null; - - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - - /** - * The type of this destination ref. - */ - private String type = null; - - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - } - - - /** - * The usage of this destination ref. - */ - private String usage = null; - - public String getUsage() { - return (this.usage); - } - - public void setUsage(String usage) { - this.usage = usage; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("MessageDestination["); - sb.append("name="); - sb.append(name); - if (link != null) { - sb.append(", link="); - sb.append(link); - } - if (type != null) { - sb.append(", type="); - sb.append(type); - } - if (usage != null) { - sb.append(", usage="); - sb.append(usage); - } - if (description != null) { - sb.append(", description="); - sb.append(description); - } - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * The NamingResources with which we are associated (if any). - */ - protected NamingResources resources = null; - - public NamingResources getNamingResources() { - return (this.resources); - } - - void setNamingResources(NamingResources resources) { - this.resources = resources; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + *

    Representation of a message destination reference for a web application, + * as represented in a <message-destination-ref> element + * in the deployment descriptor.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + * @since Tomcat 5.0 + */ + +public class MessageDestinationRef implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this destination ref. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The link of this destination ref. + */ + private String link = null; + + public String getLink() { + return (this.link); + } + + public void setLink(String link) { + this.link = link; + } + + + /** + * The name of this destination ref. + */ + private String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + * The type of this destination ref. + */ + private String type = null; + + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + } + + + /** + * The usage of this destination ref. + */ + private String usage = null; + + public String getUsage() { + return (this.usage); + } + + public void setUsage(String usage) { + this.usage = usage; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("MessageDestination["); + sb.append("name="); + sb.append(name); + if (link != null) { + sb.append(", link="); + sb.append(link); + } + if (type != null) { + sb.append(", type="); + sb.append(type); + } + if (usage != null) { + sb.append(", usage="); + sb.append(usage); + } + if (description != null) { + sb.append(", description="); + sb.append(description); + } + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * The NamingResources with which we are associated (if any). + */ + protected NamingResources resources = null; + + public NamingResources getNamingResources() { + return (this.resources); + } + + void setNamingResources(NamingResources resources) { + this.resources = resources; + } + + +} diff --git a/java/org/apache/catalina/deploy/NamingResources.java b/java/org/apache/catalina/deploy/NamingResources.java index fdb06356c..583a4002c 100644 --- a/java/org/apache/catalina/deploy/NamingResources.java +++ b/java/org/apache/catalina/deploy/NamingResources.java @@ -1,783 +1,783 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.util.HashMap; -import java.util.Hashtable; -import java.io.Serializable; - - -/** - * Holds and manages the naming resources defined in the J2EE Enterprise - * Naming Context and their associated JNDI context. - * - * @author Remy Maucherat - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class NamingResources implements Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new NamingResources instance. - */ - public NamingResources() { - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated container object. - */ - private Object container = null; - - - /** - * List of naming entries, keyed by name. The value is the entry type, as - * declared by the user. - */ - private Hashtable entries = new Hashtable(); - - - /** - * The EJB resource references for this web application, keyed by name. - */ - private HashMap ejbs = new HashMap(); - - - /** - * The environment entries for this web application, keyed by name. - */ - private HashMap envs = new HashMap(); - - - /** - * The local EJB resource references for this web application, keyed by - * name. - */ - private HashMap localEjbs = new HashMap(); - - - /** - * The message destination referencess for this web application, - * keyed by name. - */ - private HashMap mdrs = new HashMap(); - - - /** - * The resource environment references for this web application, - * keyed by name. - */ - private HashMap resourceEnvRefs = new HashMap(); - - - /** - * The resource references for this web application, keyed by name. - */ - private HashMap resources = new HashMap(); - - - /** - * The resource links for this web application, keyed by name. - */ - private HashMap resourceLinks = new HashMap(); - - - /** - * The web service references for this web application, keyed by name. - */ - private HashMap services = new HashMap(); - - - /** - * The transaction for this webapp. - */ - private ContextTransaction transaction = null; - - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - // ------------------------------------------------------------- Properties - - - /** - * Get the container with which the naming resources are associated. - */ - public Object getContainer() { - return container; - } - - - /** - * Set the container with which the naming resources are associated. - */ - public void setContainer(Object container) { - this.container = container; - } - - - /** - * Set the transaction object. - */ - public void setTransaction(ContextTransaction transaction) { - this.transaction = transaction; - } - - - /** - * Get the transaction object. - */ - public ContextTransaction getTransaction() { - return transaction; - } - - - /** - * Add an EJB resource reference for this web application. - * - * @param ejb New EJB resource reference - */ - public void addEjb(ContextEjb ejb) { - - if (entries.containsKey(ejb.getName())) { - return; - } else { - entries.put(ejb.getName(), ejb.getType()); - } - - synchronized (ejbs) { - ejb.setNamingResources(this); - ejbs.put(ejb.getName(), ejb); - } - support.firePropertyChange("ejb", null, ejb); - - } - - - /** - * Add an environment entry for this web application. - * - * @param environment New environment entry - */ - public void addEnvironment(ContextEnvironment environment) { - - if (entries.containsKey(environment.getName())) { - return; - } else { - entries.put(environment.getName(), environment.getType()); - } - - synchronized (envs) { - environment.setNamingResources(this); - envs.put(environment.getName(), environment); - } - support.firePropertyChange("environment", null, environment); - - } - - - /** - * Add a local EJB resource reference for this web application. - * - * @param ejb New EJB resource reference - */ - public void addLocalEjb(ContextLocalEjb ejb) { - - if (entries.containsKey(ejb.getName())) { - return; - } else { - entries.put(ejb.getName(), ejb.getType()); - } - - synchronized (localEjbs) { - ejb.setNamingResources(this); - localEjbs.put(ejb.getName(), ejb); - } - support.firePropertyChange("localEjb", null, ejb); - - } - - - /** - * Add a message destination reference for this web application. - * - * @param mdr New message destination reference - */ - public void addMessageDestinationRef(MessageDestinationRef mdr) { - - if (entries.containsKey(mdr.getName())) { - return; - } else { - entries.put(mdr.getName(), mdr.getType()); - } - - synchronized (mdrs) { - mdr.setNamingResources(this); - mdrs.put(mdr.getName(), mdr); - } - support.firePropertyChange("messageDestinationRef", null, mdr); - - } - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - - support.addPropertyChangeListener(listener); - - } - - - /** - * Add a resource reference for this web application. - * - * @param resource New resource reference - */ - public void addResource(ContextResource resource) { - - if (entries.containsKey(resource.getName())) { - return; - } else { - entries.put(resource.getName(), resource.getType()); - } - - synchronized (resources) { - resource.setNamingResources(this); - resources.put(resource.getName(), resource); - } - support.firePropertyChange("resource", null, resource); - - } - - - /** - * Add a resource environment reference for this web application. - * - * @param resource The resource - */ - public void addResourceEnvRef(ContextResourceEnvRef resource) { - - if (entries.containsKey(resource.getName())) { - return; - } else { - entries.put(resource.getName(), resource.getType()); - } - - synchronized (localEjbs) { - resource.setNamingResources(this); - resourceEnvRefs.put(resource.getName(), resource); - } - support.firePropertyChange("resourceEnvRef", null, resource); - - } - - - /** - * Add a resource link for this web application. - * - * @param resourceLink New resource link - */ - public void addResourceLink(ContextResourceLink resourceLink) { - - if (entries.containsKey(resourceLink.getName())) { - return; - } else { - Object value = resourceLink.getType(); - if (value == null) { - value = ""; - } - entries.put(resourceLink.getName(), value); - } - - synchronized (resourceLinks) { - resourceLink.setNamingResources(this); - resourceLinks.put(resourceLink.getName(), resourceLink); - } - support.firePropertyChange("resourceLink", null, resourceLink); - - } - - - /** - * Add a web service reference for this web application. - * - * @param service New web service reference - */ - public void addService(ContextService service) { - - if (entries.containsKey(service.getName())) { - return; - } else { - entries.put(service.getName(), service.getType()); - } - - synchronized (services) { - service.setNamingResources(this); - services.put(service.getName(), service); - } - support.firePropertyChange("service", null, service); - - } - - - /** - * Return the EJB resource reference with the specified name, if any; - * otherwise, return null. - * - * @param name Name of the desired EJB resource reference - */ - public ContextEjb findEjb(String name) { - - synchronized (ejbs) { - return ((ContextEjb) ejbs.get(name)); - } - - } - - - /** - * Return the defined EJB resource references for this application. - * If there are none, a zero-length array is returned. - */ - public ContextEjb[] findEjbs() { - - synchronized (ejbs) { - ContextEjb results[] = new ContextEjb[ejbs.size()]; - return ((ContextEjb[]) ejbs.values().toArray(results)); - } - - } - - - /** - * Return the environment entry with the specified name, if any; - * otherwise, return null. - * - * @param name Name of the desired environment entry - */ - public ContextEnvironment findEnvironment(String name) { - - synchronized (envs) { - return ((ContextEnvironment) envs.get(name)); - } - - } - - - /** - * Return the set of defined environment entries for this web - * application. If none have been defined, a zero-length array - * is returned. - */ - public ContextEnvironment[] findEnvironments() { - - synchronized (envs) { - ContextEnvironment results[] = new ContextEnvironment[envs.size()]; - return ((ContextEnvironment[]) envs.values().toArray(results)); - } - - } - - - /** - * Return the local EJB resource reference with the specified name, if any; - * otherwise, return null. - * - * @param name Name of the desired EJB resource reference - */ - public ContextLocalEjb findLocalEjb(String name) { - - synchronized (localEjbs) { - return ((ContextLocalEjb) localEjbs.get(name)); - } - - } - - - /** - * Return the defined local EJB resource references for this application. - * If there are none, a zero-length array is returned. - */ - public ContextLocalEjb[] findLocalEjbs() { - - synchronized (localEjbs) { - ContextLocalEjb results[] = new ContextLocalEjb[localEjbs.size()]; - return ((ContextLocalEjb[]) localEjbs.values().toArray(results)); - } - - } - - - /** - * Return the message destination reference with the specified name, - * if any; otherwise, return null. - * - * @param name Name of the desired message destination reference - */ - public MessageDestinationRef findMessageDestinationRef(String name) { - - synchronized (mdrs) { - return ((MessageDestinationRef) mdrs.get(name)); - } - - } - - - /** - * Return the defined message destination references for this application. - * If there are none, a zero-length array is returned. - */ - public MessageDestinationRef[] findMessageDestinationRefs() { - - synchronized (mdrs) { - MessageDestinationRef results[] = - new MessageDestinationRef[mdrs.size()]; - return ((MessageDestinationRef[]) mdrs.values().toArray(results)); - } - - } - - - /** - * Return the resource reference with the specified name, if any; - * otherwise return null. - * - * @param name Name of the desired resource reference - */ - public ContextResource findResource(String name) { - - synchronized (resources) { - return ((ContextResource) resources.get(name)); - } - - } - - - /** - * Return the resource link with the specified name, if any; - * otherwise return null. - * - * @param name Name of the desired resource link - */ - public ContextResourceLink findResourceLink(String name) { - - synchronized (resourceLinks) { - return ((ContextResourceLink) resourceLinks.get(name)); - } - - } - - - /** - * Return the defined resource links for this application. If - * none have been defined, a zero-length array is returned. - */ - public ContextResourceLink[] findResourceLinks() { - - synchronized (resourceLinks) { - ContextResourceLink results[] = - new ContextResourceLink[resourceLinks.size()]; - return ((ContextResourceLink[]) resourceLinks.values() - .toArray(results)); - } - - } - - - /** - * Return the defined resource references for this application. If - * none have been defined, a zero-length array is returned. - */ - public ContextResource[] findResources() { - - synchronized (resources) { - ContextResource results[] = new ContextResource[resources.size()]; - return ((ContextResource[]) resources.values().toArray(results)); - } - - } - - - /** - * Return the resource environment reference type for the specified - * name, if any; otherwise return null. - * - * @param name Name of the desired resource environment reference - */ - public ContextResourceEnvRef findResourceEnvRef(String name) { - - synchronized (resourceEnvRefs) { - return ((ContextResourceEnvRef) resourceEnvRefs.get(name)); - } - - } - - - /** - * Return the set of resource environment reference names for this - * web application. If none have been specified, a zero-length - * array is returned. - */ - public ContextResourceEnvRef[] findResourceEnvRefs() { - - synchronized (resourceEnvRefs) { - ContextResourceEnvRef results[] = new ContextResourceEnvRef[resourceEnvRefs.size()]; - return ((ContextResourceEnvRef[]) resourceEnvRefs.values().toArray(results)); - } - - } - - - /** - * Return the web service reference for the specified - * name, if any; otherwise return null. - * - * @param name Name of the desired web service - */ - public ContextService findService(String name) { - - synchronized (services) { - return ((ContextService) services.get(name)); - } - - } - - - /** - * Return the defined web service references for this application. If - * none have been defined, a zero-length array is returned. - */ - public ContextService[] findServices() { - - synchronized (services) { - ContextService results[] = new ContextService[services.size()]; - return ((ContextService[]) services.values().toArray(results)); - } - - } - - - /** - * Return true if the name specified already exists. - */ - public boolean exists(String name) { - - return (entries.containsKey(name)); - - } - - - /** - * Remove any EJB resource reference with the specified name. - * - * @param name Name of the EJB resource reference to remove - */ - public void removeEjb(String name) { - - entries.remove(name); - - ContextEjb ejb = null; - synchronized (ejbs) { - ejb = (ContextEjb) ejbs.remove(name); - } - if (ejb != null) { - support.firePropertyChange("ejb", ejb, null); - ejb.setNamingResources(null); - } - - } - - - /** - * Remove any environment entry with the specified name. - * - * @param name Name of the environment entry to remove - */ - public void removeEnvironment(String name) { - - entries.remove(name); - - ContextEnvironment environment = null; - synchronized (envs) { - environment = (ContextEnvironment) envs.remove(name); - } - if (environment != null) { - support.firePropertyChange("environment", environment, null); - environment.setNamingResources(null); - } - - } - - - /** - * Remove any local EJB resource reference with the specified name. - * - * @param name Name of the EJB resource reference to remove - */ - public void removeLocalEjb(String name) { - - entries.remove(name); - - ContextLocalEjb localEjb = null; - synchronized (localEjbs) { - localEjb = (ContextLocalEjb) ejbs.remove(name); - } - if (localEjb != null) { - support.firePropertyChange("localEjb", localEjb, null); - localEjb.setNamingResources(null); - } - - } - - - /** - * Remove any message destination reference with the specified name. - * - * @param name Name of the message destination resource reference to remove - */ - public void removeMessageDestinationRef(String name) { - - entries.remove(name); - - MessageDestinationRef mdr = null; - synchronized (mdrs) { - mdr = (MessageDestinationRef) mdrs.remove(name); - } - if (mdr != null) { - support.firePropertyChange("messageDestinationRef", - mdr, null); - mdr.setNamingResources(null); - } - - } - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - - support.removePropertyChangeListener(listener); - - } - - - /** - * Remove any resource reference with the specified name. - * - * @param name Name of the resource reference to remove - */ - public void removeResource(String name) { - - entries.remove(name); - - ContextResource resource = null; - synchronized (resources) { - resource = (ContextResource) resources.remove(name); - } - if (resource != null) { - support.firePropertyChange("resource", resource, null); - resource.setNamingResources(null); - } - - } - - - /** - * Remove any resource environment reference with the specified name. - * - * @param name Name of the resource environment reference to remove - */ - public void removeResourceEnvRef(String name) { - - entries.remove(name); - - String type = null; - synchronized (resourceEnvRefs) { - type = (String) resourceEnvRefs.remove(name); - } - if (type != null) { - support.firePropertyChange("resourceEnvRef", - name + ":" + type, null); - } - - } - - - /** - * Remove any resource link with the specified name. - * - * @param name Name of the resource link to remove - */ - public void removeResourceLink(String name) { - - entries.remove(name); - - ContextResourceLink resourceLink = null; - synchronized (resourceLinks) { - resourceLink = (ContextResourceLink) resourceLinks.remove(name); - } - if (resourceLink != null) { - support.firePropertyChange("resourceLink", resourceLink, null); - resourceLink.setNamingResources(null); - } - - } - - - /** - * Remove any web service reference with the specified name. - * - * @param name Name of the web service reference to remove - */ - public void removeService(String name) { - - entries.remove(name); - - ContextService service = null; - synchronized (services) { - service = (ContextService) services.remove(name); - } - if (service != null) { - support.firePropertyChange("service", service, null); - service.setNamingResources(null); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.util.HashMap; +import java.util.Hashtable; +import java.io.Serializable; + + +/** + * Holds and manages the naming resources defined in the J2EE Enterprise + * Naming Context and their associated JNDI context. + * + * @author Remy Maucherat + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class NamingResources implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new NamingResources instance. + */ + public NamingResources() { + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated container object. + */ + private Object container = null; + + + /** + * List of naming entries, keyed by name. The value is the entry type, as + * declared by the user. + */ + private Hashtable entries = new Hashtable(); + + + /** + * The EJB resource references for this web application, keyed by name. + */ + private HashMap ejbs = new HashMap(); + + + /** + * The environment entries for this web application, keyed by name. + */ + private HashMap envs = new HashMap(); + + + /** + * The local EJB resource references for this web application, keyed by + * name. + */ + private HashMap localEjbs = new HashMap(); + + + /** + * The message destination referencess for this web application, + * keyed by name. + */ + private HashMap mdrs = new HashMap(); + + + /** + * The resource environment references for this web application, + * keyed by name. + */ + private HashMap resourceEnvRefs = new HashMap(); + + + /** + * The resource references for this web application, keyed by name. + */ + private HashMap resources = new HashMap(); + + + /** + * The resource links for this web application, keyed by name. + */ + private HashMap resourceLinks = new HashMap(); + + + /** + * The web service references for this web application, keyed by name. + */ + private HashMap services = new HashMap(); + + + /** + * The transaction for this webapp. + */ + private ContextTransaction transaction = null; + + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + // ------------------------------------------------------------- Properties + + + /** + * Get the container with which the naming resources are associated. + */ + public Object getContainer() { + return container; + } + + + /** + * Set the container with which the naming resources are associated. + */ + public void setContainer(Object container) { + this.container = container; + } + + + /** + * Set the transaction object. + */ + public void setTransaction(ContextTransaction transaction) { + this.transaction = transaction; + } + + + /** + * Get the transaction object. + */ + public ContextTransaction getTransaction() { + return transaction; + } + + + /** + * Add an EJB resource reference for this web application. + * + * @param ejb New EJB resource reference + */ + public void addEjb(ContextEjb ejb) { + + if (entries.containsKey(ejb.getName())) { + return; + } else { + entries.put(ejb.getName(), ejb.getType()); + } + + synchronized (ejbs) { + ejb.setNamingResources(this); + ejbs.put(ejb.getName(), ejb); + } + support.firePropertyChange("ejb", null, ejb); + + } + + + /** + * Add an environment entry for this web application. + * + * @param environment New environment entry + */ + public void addEnvironment(ContextEnvironment environment) { + + if (entries.containsKey(environment.getName())) { + return; + } else { + entries.put(environment.getName(), environment.getType()); + } + + synchronized (envs) { + environment.setNamingResources(this); + envs.put(environment.getName(), environment); + } + support.firePropertyChange("environment", null, environment); + + } + + + /** + * Add a local EJB resource reference for this web application. + * + * @param ejb New EJB resource reference + */ + public void addLocalEjb(ContextLocalEjb ejb) { + + if (entries.containsKey(ejb.getName())) { + return; + } else { + entries.put(ejb.getName(), ejb.getType()); + } + + synchronized (localEjbs) { + ejb.setNamingResources(this); + localEjbs.put(ejb.getName(), ejb); + } + support.firePropertyChange("localEjb", null, ejb); + + } + + + /** + * Add a message destination reference for this web application. + * + * @param mdr New message destination reference + */ + public void addMessageDestinationRef(MessageDestinationRef mdr) { + + if (entries.containsKey(mdr.getName())) { + return; + } else { + entries.put(mdr.getName(), mdr.getType()); + } + + synchronized (mdrs) { + mdr.setNamingResources(this); + mdrs.put(mdr.getName(), mdr); + } + support.firePropertyChange("messageDestinationRef", null, mdr); + + } + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + + support.addPropertyChangeListener(listener); + + } + + + /** + * Add a resource reference for this web application. + * + * @param resource New resource reference + */ + public void addResource(ContextResource resource) { + + if (entries.containsKey(resource.getName())) { + return; + } else { + entries.put(resource.getName(), resource.getType()); + } + + synchronized (resources) { + resource.setNamingResources(this); + resources.put(resource.getName(), resource); + } + support.firePropertyChange("resource", null, resource); + + } + + + /** + * Add a resource environment reference for this web application. + * + * @param resource The resource + */ + public void addResourceEnvRef(ContextResourceEnvRef resource) { + + if (entries.containsKey(resource.getName())) { + return; + } else { + entries.put(resource.getName(), resource.getType()); + } + + synchronized (localEjbs) { + resource.setNamingResources(this); + resourceEnvRefs.put(resource.getName(), resource); + } + support.firePropertyChange("resourceEnvRef", null, resource); + + } + + + /** + * Add a resource link for this web application. + * + * @param resourceLink New resource link + */ + public void addResourceLink(ContextResourceLink resourceLink) { + + if (entries.containsKey(resourceLink.getName())) { + return; + } else { + Object value = resourceLink.getType(); + if (value == null) { + value = ""; + } + entries.put(resourceLink.getName(), value); + } + + synchronized (resourceLinks) { + resourceLink.setNamingResources(this); + resourceLinks.put(resourceLink.getName(), resourceLink); + } + support.firePropertyChange("resourceLink", null, resourceLink); + + } + + + /** + * Add a web service reference for this web application. + * + * @param service New web service reference + */ + public void addService(ContextService service) { + + if (entries.containsKey(service.getName())) { + return; + } else { + entries.put(service.getName(), service.getType()); + } + + synchronized (services) { + service.setNamingResources(this); + services.put(service.getName(), service); + } + support.firePropertyChange("service", null, service); + + } + + + /** + * Return the EJB resource reference with the specified name, if any; + * otherwise, return null. + * + * @param name Name of the desired EJB resource reference + */ + public ContextEjb findEjb(String name) { + + synchronized (ejbs) { + return ((ContextEjb) ejbs.get(name)); + } + + } + + + /** + * Return the defined EJB resource references for this application. + * If there are none, a zero-length array is returned. + */ + public ContextEjb[] findEjbs() { + + synchronized (ejbs) { + ContextEjb results[] = new ContextEjb[ejbs.size()]; + return ((ContextEjb[]) ejbs.values().toArray(results)); + } + + } + + + /** + * Return the environment entry with the specified name, if any; + * otherwise, return null. + * + * @param name Name of the desired environment entry + */ + public ContextEnvironment findEnvironment(String name) { + + synchronized (envs) { + return ((ContextEnvironment) envs.get(name)); + } + + } + + + /** + * Return the set of defined environment entries for this web + * application. If none have been defined, a zero-length array + * is returned. + */ + public ContextEnvironment[] findEnvironments() { + + synchronized (envs) { + ContextEnvironment results[] = new ContextEnvironment[envs.size()]; + return ((ContextEnvironment[]) envs.values().toArray(results)); + } + + } + + + /** + * Return the local EJB resource reference with the specified name, if any; + * otherwise, return null. + * + * @param name Name of the desired EJB resource reference + */ + public ContextLocalEjb findLocalEjb(String name) { + + synchronized (localEjbs) { + return ((ContextLocalEjb) localEjbs.get(name)); + } + + } + + + /** + * Return the defined local EJB resource references for this application. + * If there are none, a zero-length array is returned. + */ + public ContextLocalEjb[] findLocalEjbs() { + + synchronized (localEjbs) { + ContextLocalEjb results[] = new ContextLocalEjb[localEjbs.size()]; + return ((ContextLocalEjb[]) localEjbs.values().toArray(results)); + } + + } + + + /** + * Return the message destination reference with the specified name, + * if any; otherwise, return null. + * + * @param name Name of the desired message destination reference + */ + public MessageDestinationRef findMessageDestinationRef(String name) { + + synchronized (mdrs) { + return ((MessageDestinationRef) mdrs.get(name)); + } + + } + + + /** + * Return the defined message destination references for this application. + * If there are none, a zero-length array is returned. + */ + public MessageDestinationRef[] findMessageDestinationRefs() { + + synchronized (mdrs) { + MessageDestinationRef results[] = + new MessageDestinationRef[mdrs.size()]; + return ((MessageDestinationRef[]) mdrs.values().toArray(results)); + } + + } + + + /** + * Return the resource reference with the specified name, if any; + * otherwise return null. + * + * @param name Name of the desired resource reference + */ + public ContextResource findResource(String name) { + + synchronized (resources) { + return ((ContextResource) resources.get(name)); + } + + } + + + /** + * Return the resource link with the specified name, if any; + * otherwise return null. + * + * @param name Name of the desired resource link + */ + public ContextResourceLink findResourceLink(String name) { + + synchronized (resourceLinks) { + return ((ContextResourceLink) resourceLinks.get(name)); + } + + } + + + /** + * Return the defined resource links for this application. If + * none have been defined, a zero-length array is returned. + */ + public ContextResourceLink[] findResourceLinks() { + + synchronized (resourceLinks) { + ContextResourceLink results[] = + new ContextResourceLink[resourceLinks.size()]; + return ((ContextResourceLink[]) resourceLinks.values() + .toArray(results)); + } + + } + + + /** + * Return the defined resource references for this application. If + * none have been defined, a zero-length array is returned. + */ + public ContextResource[] findResources() { + + synchronized (resources) { + ContextResource results[] = new ContextResource[resources.size()]; + return ((ContextResource[]) resources.values().toArray(results)); + } + + } + + + /** + * Return the resource environment reference type for the specified + * name, if any; otherwise return null. + * + * @param name Name of the desired resource environment reference + */ + public ContextResourceEnvRef findResourceEnvRef(String name) { + + synchronized (resourceEnvRefs) { + return ((ContextResourceEnvRef) resourceEnvRefs.get(name)); + } + + } + + + /** + * Return the set of resource environment reference names for this + * web application. If none have been specified, a zero-length + * array is returned. + */ + public ContextResourceEnvRef[] findResourceEnvRefs() { + + synchronized (resourceEnvRefs) { + ContextResourceEnvRef results[] = new ContextResourceEnvRef[resourceEnvRefs.size()]; + return ((ContextResourceEnvRef[]) resourceEnvRefs.values().toArray(results)); + } + + } + + + /** + * Return the web service reference for the specified + * name, if any; otherwise return null. + * + * @param name Name of the desired web service + */ + public ContextService findService(String name) { + + synchronized (services) { + return ((ContextService) services.get(name)); + } + + } + + + /** + * Return the defined web service references for this application. If + * none have been defined, a zero-length array is returned. + */ + public ContextService[] findServices() { + + synchronized (services) { + ContextService results[] = new ContextService[services.size()]; + return ((ContextService[]) services.values().toArray(results)); + } + + } + + + /** + * Return true if the name specified already exists. + */ + public boolean exists(String name) { + + return (entries.containsKey(name)); + + } + + + /** + * Remove any EJB resource reference with the specified name. + * + * @param name Name of the EJB resource reference to remove + */ + public void removeEjb(String name) { + + entries.remove(name); + + ContextEjb ejb = null; + synchronized (ejbs) { + ejb = (ContextEjb) ejbs.remove(name); + } + if (ejb != null) { + support.firePropertyChange("ejb", ejb, null); + ejb.setNamingResources(null); + } + + } + + + /** + * Remove any environment entry with the specified name. + * + * @param name Name of the environment entry to remove + */ + public void removeEnvironment(String name) { + + entries.remove(name); + + ContextEnvironment environment = null; + synchronized (envs) { + environment = (ContextEnvironment) envs.remove(name); + } + if (environment != null) { + support.firePropertyChange("environment", environment, null); + environment.setNamingResources(null); + } + + } + + + /** + * Remove any local EJB resource reference with the specified name. + * + * @param name Name of the EJB resource reference to remove + */ + public void removeLocalEjb(String name) { + + entries.remove(name); + + ContextLocalEjb localEjb = null; + synchronized (localEjbs) { + localEjb = (ContextLocalEjb) ejbs.remove(name); + } + if (localEjb != null) { + support.firePropertyChange("localEjb", localEjb, null); + localEjb.setNamingResources(null); + } + + } + + + /** + * Remove any message destination reference with the specified name. + * + * @param name Name of the message destination resource reference to remove + */ + public void removeMessageDestinationRef(String name) { + + entries.remove(name); + + MessageDestinationRef mdr = null; + synchronized (mdrs) { + mdr = (MessageDestinationRef) mdrs.remove(name); + } + if (mdr != null) { + support.firePropertyChange("messageDestinationRef", + mdr, null); + mdr.setNamingResources(null); + } + + } + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + + support.removePropertyChangeListener(listener); + + } + + + /** + * Remove any resource reference with the specified name. + * + * @param name Name of the resource reference to remove + */ + public void removeResource(String name) { + + entries.remove(name); + + ContextResource resource = null; + synchronized (resources) { + resource = (ContextResource) resources.remove(name); + } + if (resource != null) { + support.firePropertyChange("resource", resource, null); + resource.setNamingResources(null); + } + + } + + + /** + * Remove any resource environment reference with the specified name. + * + * @param name Name of the resource environment reference to remove + */ + public void removeResourceEnvRef(String name) { + + entries.remove(name); + + String type = null; + synchronized (resourceEnvRefs) { + type = (String) resourceEnvRefs.remove(name); + } + if (type != null) { + support.firePropertyChange("resourceEnvRef", + name + ":" + type, null); + } + + } + + + /** + * Remove any resource link with the specified name. + * + * @param name Name of the resource link to remove + */ + public void removeResourceLink(String name) { + + entries.remove(name); + + ContextResourceLink resourceLink = null; + synchronized (resourceLinks) { + resourceLink = (ContextResourceLink) resourceLinks.remove(name); + } + if (resourceLink != null) { + support.firePropertyChange("resourceLink", resourceLink, null); + resourceLink.setNamingResources(null); + } + + } + + + /** + * Remove any web service reference with the specified name. + * + * @param name Name of the web service reference to remove + */ + public void removeService(String name) { + + entries.remove(name); + + ContextService service = null; + synchronized (services) { + service = (ContextService) services.remove(name); + } + if (service != null) { + support.firePropertyChange("service", service, null); + service.setNamingResources(null); + } + + } + + +} diff --git a/java/org/apache/catalina/deploy/ResourceBase.java b/java/org/apache/catalina/deploy/ResourceBase.java index 38820967a..5356421fe 100644 --- a/java/org/apache/catalina/deploy/ResourceBase.java +++ b/java/org/apache/catalina/deploy/ResourceBase.java @@ -1,132 +1,132 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; -import java.util.Iterator; -import java.util.HashMap; - - -/** - * Representation of an Context element - * - * @author Peter Rossbach (pero@apache.org) - * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ - */ - -public class ResourceBase implements Serializable { - - - // ------------------------------------------------------------- Properties - - - /** - * The description of this Context Element. - */ - private String description = null; - - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - - /** - * The name of this context Element. - */ - private String name = null; - - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - - /** - * The name of the EJB bean implementation class. - */ - private String type = null; - - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - } - - - /** - * Holder for our configured properties. - */ - private HashMap properties = new HashMap(); - - /** - * Return a configured property. - */ - public Object getProperty(String name) { - return properties.get(name); - } - - /** - * Set a configured property. - */ - public void setProperty(String name, Object value) { - properties.put(name, value); - } - - /** - * remove a configured property. - */ - public void removeProperty(String name) { - properties.remove(name); - } - - /** - * List properties. - */ - public Iterator listProperties() { - return properties.keySet().iterator(); - } - - - // -------------------------------------------------------- Package Methods - - - /** - * The NamingResources with which we are associated (if any). - */ - protected NamingResources resources = null; - - public NamingResources getNamingResources() { - return (this.resources); - } - - void setNamingResources(NamingResources resources) { - this.resources = resources; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.HashMap; + + +/** + * Representation of an Context element + * + * @author Peter Rossbach (pero@apache.org) + * @version $Revision: 303342 $ $Date: 2004-10-05 09:56:49 +0200 (mar., 05 oct. 2004) $ + */ + +public class ResourceBase implements Serializable { + + + // ------------------------------------------------------------- Properties + + + /** + * The description of this Context Element. + */ + private String description = null; + + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + + /** + * The name of this context Element. + */ + private String name = null; + + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + + /** + * The name of the EJB bean implementation class. + */ + private String type = null; + + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + } + + + /** + * Holder for our configured properties. + */ + private HashMap properties = new HashMap(); + + /** + * Return a configured property. + */ + public Object getProperty(String name) { + return properties.get(name); + } + + /** + * Set a configured property. + */ + public void setProperty(String name, Object value) { + properties.put(name, value); + } + + /** + * remove a configured property. + */ + public void removeProperty(String name) { + properties.remove(name); + } + + /** + * List properties. + */ + public Iterator listProperties() { + return properties.keySet().iterator(); + } + + + // -------------------------------------------------------- Package Methods + + + /** + * The NamingResources with which we are associated (if any). + */ + protected NamingResources resources = null; + + public NamingResources getNamingResources() { + return (this.resources); + } + + void setNamingResources(NamingResources resources) { + this.resources = resources; + } + + +} diff --git a/java/org/apache/catalina/deploy/SecurityCollection.java b/java/org/apache/catalina/deploy/SecurityCollection.java index d8c0a827f..b3d9874c9 100644 --- a/java/org/apache/catalina/deploy/SecurityCollection.java +++ b/java/org/apache/catalina/deploy/SecurityCollection.java @@ -1,348 +1,348 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - - -import org.apache.catalina.util.RequestUtil; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.Serializable; - - -/** - * Representation of a web resource collection for a web application's security - * constraint, as represented in a <web-resource-collection> - * element in the deployment descriptor. - *

    - * WARNING: It is assumed that instances of this class will be created - * and modified only within the context of a single thread, before the instance - * is made visible to the remainder of the application. After that, only read - * access is expected. Therefore, none of the read and write access within - * this class is synchronized. - * - * @author Craig R. McClanahan - * @version $Revision: 304007 $ $Date: 2005-07-21 22:14:57 +0200 (jeu., 21 juil. 2005) $ - */ - -public class SecurityCollection implements Serializable { - - private static Log log = LogFactory.getLog(SecurityCollection.class); - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new security collection instance with default values. - */ - public SecurityCollection() { - - this(null, null); - - } - - - /** - * Construct a new security collection instance with specified values. - * - * @param name Name of this security collection - */ - public SecurityCollection(String name) { - - this(name, null); - - } - - - /** - * Construct a new security collection instance with specified values. - * - * @param name Name of this security collection - * @param description Description of this security collection - */ - public SecurityCollection(String name, String description) { - - super(); - setName(name); - setDescription(description); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Description of this web resource collection. - */ - private String description = null; - - - /** - * The HTTP methods covered by this web resource collection. - */ - private String methods[] = new String[0]; - - - /** - * The name of this web resource collection. - */ - private String name = null; - - - /** - * The URL patterns protected by this security collection. - */ - private String patterns[] = new String[0]; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the description of this web resource collection. - */ - public String getDescription() { - - return (this.description); - - } - - - /** - * Set the description of this web resource collection. - * - * @param description The new description - */ - public void setDescription(String description) { - - this.description = description; - - } - - - /** - * Return the name of this web resource collection. - */ - public String getName() { - - return (this.name); - - } - - - /** - * Set the name of this web resource collection - * - * @param name The new name - */ - public void setName(String name) { - - this.name = name; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an HTTP request method to be part of this web resource collection. - */ - public void addMethod(String method) { - - if (method == null) - return; - String results[] = new String[methods.length + 1]; - for (int i = 0; i < methods.length; i++) - results[i] = methods[i]; - results[methods.length] = method; - methods = results; - - } - - - /** - * Add a URL pattern to be part of this web resource collection. - */ - public void addPattern(String pattern) { - - if (pattern == null) - return; - - // Bugzilla 34805: add friendly warning. - if(pattern.endsWith("*")) { - if (pattern.charAt(pattern.length()-1) != '/') { - if (log.isDebugEnabled()) { - log.warn("Suspicious url pattern: \"" + pattern + "\"" + - " - see http://java.sun.com/aboutJava/communityprocess/first/jsr053/servlet23_PFD.pdf" + - " section 11.2" ); - } - } - } - - pattern = RequestUtil.URLDecode(pattern); - String results[] = new String[patterns.length + 1]; - for (int i = 0; i < patterns.length; i++) { - results[i] = patterns[i]; - } - results[patterns.length] = pattern; - patterns = results; - - } - - - /** - * Return true if the specified HTTP request method is - * part of this web resource collection. - * - * @param method Request method to check - */ - public boolean findMethod(String method) { - - if (methods.length == 0) - return (true); - for (int i = 0; i < methods.length; i++) { - if (methods[i].equals(method)) - return (true); - } - return (false); - - } - - - /** - * Return the set of HTTP request methods that are part of this web - * resource collection, or a zero-length array if all request methods - * are included. - */ - public String[] findMethods() { - - return (methods); - - } - - - /** - * Is the specified pattern part of this web resource collection? - * - * @param pattern Pattern to be compared - */ - public boolean findPattern(String pattern) { - - for (int i = 0; i < patterns.length; i++) { - if (patterns[i].equals(pattern)) - return (true); - } - return (false); - - } - - - /** - * Return the set of URL patterns that are part of this web resource - * collection. If none have been specified, a zero-length array is - * returned. - */ - public String[] findPatterns() { - - return (patterns); - - } - - - /** - * Remove the specified HTTP request method from those that are part - * of this web resource collection. - * - * @param method Request method to be removed - */ - public void removeMethod(String method) { - - if (method == null) - return; - int n = -1; - for (int i = 0; i < methods.length; i++) { - if (methods[i].equals(method)) { - n = i; - break; - } - } - if (n >= 0) { - int j = 0; - String results[] = new String[methods.length - 1]; - for (int i = 0; i < methods.length; i++) { - if (i != n) - results[j++] = methods[i]; - } - methods = results; - } - - } - - - /** - * Remove the specified URL pattern from those that are part of this - * web resource collection. - * - * @param pattern Pattern to be removed - */ - public void removePattern(String pattern) { - - if (pattern == null) - return; - int n = -1; - for (int i = 0; i < patterns.length; i++) { - if (patterns[i].equals(pattern)) { - n = i; - break; - } - } - if (n >= 0) { - int j = 0; - String results[] = new String[patterns.length - 1]; - for (int i = 0; i < patterns.length; i++) { - if (i != n) - results[j++] = patterns[i]; - } - patterns = results; - } - - } - - - /** - * Return a String representation of this security collection. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SecurityCollection["); - sb.append(name); - if (description != null) { - sb.append(", "); - sb.append(description); - } - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + + +import org.apache.catalina.util.RequestUtil; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import java.io.Serializable; + + +/** + * Representation of a web resource collection for a web application's security + * constraint, as represented in a <web-resource-collection> + * element in the deployment descriptor. + *

    + * WARNING: It is assumed that instances of this class will be created + * and modified only within the context of a single thread, before the instance + * is made visible to the remainder of the application. After that, only read + * access is expected. Therefore, none of the read and write access within + * this class is synchronized. + * + * @author Craig R. McClanahan + * @version $Revision: 304007 $ $Date: 2005-07-21 22:14:57 +0200 (jeu., 21 juil. 2005) $ + */ + +public class SecurityCollection implements Serializable { + + private static Log log = LogFactory.getLog(SecurityCollection.class); + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new security collection instance with default values. + */ + public SecurityCollection() { + + this(null, null); + + } + + + /** + * Construct a new security collection instance with specified values. + * + * @param name Name of this security collection + */ + public SecurityCollection(String name) { + + this(name, null); + + } + + + /** + * Construct a new security collection instance with specified values. + * + * @param name Name of this security collection + * @param description Description of this security collection + */ + public SecurityCollection(String name, String description) { + + super(); + setName(name); + setDescription(description); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Description of this web resource collection. + */ + private String description = null; + + + /** + * The HTTP methods covered by this web resource collection. + */ + private String methods[] = new String[0]; + + + /** + * The name of this web resource collection. + */ + private String name = null; + + + /** + * The URL patterns protected by this security collection. + */ + private String patterns[] = new String[0]; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the description of this web resource collection. + */ + public String getDescription() { + + return (this.description); + + } + + + /** + * Set the description of this web resource collection. + * + * @param description The new description + */ + public void setDescription(String description) { + + this.description = description; + + } + + + /** + * Return the name of this web resource collection. + */ + public String getName() { + + return (this.name); + + } + + + /** + * Set the name of this web resource collection + * + * @param name The new name + */ + public void setName(String name) { + + this.name = name; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an HTTP request method to be part of this web resource collection. + */ + public void addMethod(String method) { + + if (method == null) + return; + String results[] = new String[methods.length + 1]; + for (int i = 0; i < methods.length; i++) + results[i] = methods[i]; + results[methods.length] = method; + methods = results; + + } + + + /** + * Add a URL pattern to be part of this web resource collection. + */ + public void addPattern(String pattern) { + + if (pattern == null) + return; + + // Bugzilla 34805: add friendly warning. + if(pattern.endsWith("*")) { + if (pattern.charAt(pattern.length()-1) != '/') { + if (log.isDebugEnabled()) { + log.warn("Suspicious url pattern: \"" + pattern + "\"" + + " - see http://java.sun.com/aboutJava/communityprocess/first/jsr053/servlet23_PFD.pdf" + + " section 11.2" ); + } + } + } + + pattern = RequestUtil.URLDecode(pattern); + String results[] = new String[patterns.length + 1]; + for (int i = 0; i < patterns.length; i++) { + results[i] = patterns[i]; + } + results[patterns.length] = pattern; + patterns = results; + + } + + + /** + * Return true if the specified HTTP request method is + * part of this web resource collection. + * + * @param method Request method to check + */ + public boolean findMethod(String method) { + + if (methods.length == 0) + return (true); + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(method)) + return (true); + } + return (false); + + } + + + /** + * Return the set of HTTP request methods that are part of this web + * resource collection, or a zero-length array if all request methods + * are included. + */ + public String[] findMethods() { + + return (methods); + + } + + + /** + * Is the specified pattern part of this web resource collection? + * + * @param pattern Pattern to be compared + */ + public boolean findPattern(String pattern) { + + for (int i = 0; i < patterns.length; i++) { + if (patterns[i].equals(pattern)) + return (true); + } + return (false); + + } + + + /** + * Return the set of URL patterns that are part of this web resource + * collection. If none have been specified, a zero-length array is + * returned. + */ + public String[] findPatterns() { + + return (patterns); + + } + + + /** + * Remove the specified HTTP request method from those that are part + * of this web resource collection. + * + * @param method Request method to be removed + */ + public void removeMethod(String method) { + + if (method == null) + return; + int n = -1; + for (int i = 0; i < methods.length; i++) { + if (methods[i].equals(method)) { + n = i; + break; + } + } + if (n >= 0) { + int j = 0; + String results[] = new String[methods.length - 1]; + for (int i = 0; i < methods.length; i++) { + if (i != n) + results[j++] = methods[i]; + } + methods = results; + } + + } + + + /** + * Remove the specified URL pattern from those that are part of this + * web resource collection. + * + * @param pattern Pattern to be removed + */ + public void removePattern(String pattern) { + + if (pattern == null) + return; + int n = -1; + for (int i = 0; i < patterns.length; i++) { + if (patterns[i].equals(pattern)) { + n = i; + break; + } + } + if (n >= 0) { + int j = 0; + String results[] = new String[patterns.length - 1]; + for (int i = 0; i < patterns.length; i++) { + if (i != n) + results[j++] = patterns[i]; + } + patterns = results; + } + + } + + + /** + * Return a String representation of this security collection. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SecurityCollection["); + sb.append(name); + if (description != null) { + sb.append(", "); + sb.append(description); + } + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/deploy/SecurityConstraint.java b/java/org/apache/catalina/deploy/SecurityConstraint.java index 4d80a8b37..e9cff33e5 100644 --- a/java/org/apache/catalina/deploy/SecurityConstraint.java +++ b/java/org/apache/catalina/deploy/SecurityConstraint.java @@ -1,459 +1,459 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.deploy; - -import java.io.Serializable; - - -/** - * Representation of a security constraint element for a web application, - * as represented in a <security-constraint> element in the - * deployment descriptor. - *

    - * WARNING: It is assumed that instances of this class will be created - * and modified only within the context of a single thread, before the instance - * is made visible to the remainder of the application. After that, only read - * access is expected. Therefore, none of the read and write access within - * this class is synchronized. - * - * @author Craig R. McClanahan - * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ - */ - -public class SecurityConstraint implements Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new security constraint instance with default values. - */ - public SecurityConstraint() { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Was the "all roles" wildcard included in the authorization constraints - * for this security constraint? - */ - private boolean allRoles = false; - - - /** - * Was an authorization constraint included in this security constraint? - * This is necessary to distinguish the case where an auth-constraint with - * no roles (signifying no direct access at all) was requested, versus - * a lack of auth-constraint which implies no access control checking. - */ - private boolean authConstraint = false; - - - /** - * The set of roles permitted to access resources protected by this - * security constraint. - */ - private String authRoles[] = new String[0]; - - - /** - * The set of web resource collections protected by this security - * constraint. - */ - private SecurityCollection collections[] = new SecurityCollection[0]; - - - /** - * The display name of this security constraint. - */ - private String displayName = null; - - - /** - * The user data constraint for this security constraint. Must be NONE, - * INTEGRAL, or CONFIDENTIAL. - */ - private String userConstraint = "NONE"; - - - // ------------------------------------------------------------- Properties - - - /** - * Was the "all roles" wildcard included in this authentication - * constraint? - */ - public boolean getAllRoles() { - - return (this.allRoles); - - } - - - /** - * Return the authorization constraint present flag for this security - * constraint. - */ - public boolean getAuthConstraint() { - - return (this.authConstraint); - - } - - - /** - * Set the authorization constraint present flag for this security - * constraint. - */ - public void setAuthConstraint(boolean authConstraint) { - - this.authConstraint = authConstraint; - - } - - - /** - * Return the display name of this security constraint. - */ - public String getDisplayName() { - - return (this.displayName); - - } - - - /** - * Set the display name of this security constraint. - */ - public void setDisplayName(String displayName) { - - this.displayName = displayName; - - } - - - /** - * Return the user data constraint for this security constraint. - */ - public String getUserConstraint() { - - return (userConstraint); - - } - - - /** - * Set the user data constraint for this security constraint. - * - * @param userConstraint The new user data constraint - */ - public void setUserConstraint(String userConstraint) { - - if (userConstraint != null) - this.userConstraint = userConstraint; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an authorization role, which is a role name that will be - * permitted access to the resources protected by this security constraint. - * - * @param authRole Role name to be added - */ - public void addAuthRole(String authRole) { - - if (authRole == null) - return; - if ("*".equals(authRole)) { - allRoles = true; - return; - } - String results[] = new String[authRoles.length + 1]; - for (int i = 0; i < authRoles.length; i++) - results[i] = authRoles[i]; - results[authRoles.length] = authRole; - authRoles = results; - authConstraint = true; - - } - - - /** - * Add a new web resource collection to those protected by this - * security constraint. - * - * @param collection The new web resource collection - */ - public void addCollection(SecurityCollection collection) { - - if (collection == null) - return; - SecurityCollection results[] = - new SecurityCollection[collections.length + 1]; - for (int i = 0; i < collections.length; i++) - results[i] = collections[i]; - results[collections.length] = collection; - collections = results; - - } - - - /** - * Return true if the specified role is permitted access to - * the resources protected by this security constraint. - * - * @param role Role name to be checked - */ - public boolean findAuthRole(String role) { - - if (role == null) - return (false); - for (int i = 0; i < authRoles.length; i++) { - if (role.equals(authRoles[i])) - return (true); - } - return (false); - - } - - - /** - * Return the set of roles that are permitted access to the resources - * protected by this security constraint. If none have been defined, - * a zero-length array is returned (which implies that all authenticated - * users are permitted access). - */ - public String[] findAuthRoles() { - - return (authRoles); - - } - - - /** - * Return the web resource collection for the specified name, if any; - * otherwise, return null. - * - * @param name Web resource collection name to return - */ - public SecurityCollection findCollection(String name) { - - if (name == null) - return (null); - for (int i = 0; i < collections.length; i++) { - if (name.equals(collections[i].getName())) - return (collections[i]); - } - return (null); - - } - - - /** - * Return all of the web resource collections protected by this - * security constraint. If there are none, a zero-length array is - * returned. - */ - public SecurityCollection[] findCollections() { - - return (collections); - - } - - - /** - * Return true if the specified context-relative URI (and - * associated HTTP method) are protected by this security constraint. - * - * @param uri Context-relative URI to check - * @param method Request method being used - */ - public boolean included(String uri, String method) { - - // We cannot match without a valid request method - if (method == null) - return (false); - - // Check all of the collections included in this constraint - for (int i = 0; i < collections.length; i++) { - if (!collections[i].findMethod(method)) - continue; - String patterns[] = collections[i].findPatterns(); - for (int j = 0; j < patterns.length; j++) { - if (matchPattern(uri, patterns[j])) - return (true); - } - } - - // No collection included in this constraint matches this request - return (false); - - } - - - /** - * Remove the specified role from the set of roles permitted to access - * the resources protected by this security constraint. - * - * @param authRole Role name to be removed - */ - public void removeAuthRole(String authRole) { - - if (authRole == null) - return; - int n = -1; - for (int i = 0; i < authRoles.length; i++) { - if (authRoles[i].equals(authRole)) { - n = i; - break; - } - } - if (n >= 0) { - int j = 0; - String results[] = new String[authRoles.length - 1]; - for (int i = 0; i < authRoles.length; i++) { - if (i != n) - results[j++] = authRoles[i]; - } - authRoles = results; - } - - } - - - /** - * Remove the specified web resource collection from those protected by - * this security constraint. - * - * @param collection Web resource collection to be removed - */ - public void removeCollection(SecurityCollection collection) { - - if (collection == null) - return; - int n = -1; - for (int i = 0; i < collections.length; i++) { - if (collections[i].equals(collection)) { - n = i; - break; - } - } - if (n >= 0) { - int j = 0; - SecurityCollection results[] = - new SecurityCollection[collections.length - 1]; - for (int i = 0; i < collections.length; i++) { - if (i != n) - results[j++] = collections[i]; - } - collections = results; - } - - } - - - /** - * Return a String representation of this security constraint. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SecurityConstraint["); - for (int i = 0; i < collections.length; i++) { - if (i > 0) - sb.append(", "); - sb.append(collections[i].getName()); - } - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Does the specified request path match the specified URL pattern? - * This method follows the same rules (in the same order) as those used - * for mapping requests to servlets. - * - * @param path Context-relative request path to be checked - * (must start with '/') - * @param pattern URL pattern to be compared against - */ - private boolean matchPattern(String path, String pattern) { - - // Normalize the argument strings - if ((path == null) || (path.length() == 0)) - path = "/"; - if ((pattern == null) || (pattern.length() == 0)) - pattern = "/"; - - // Check for exact match - if (path.equals(pattern)) - return (true); - - // Check for path prefix matching - if (pattern.startsWith("/") && pattern.endsWith("/*")) { - pattern = pattern.substring(0, pattern.length() - 2); - if (pattern.length() == 0) - return (true); // "/*" is the same as "/" - if (path.endsWith("/")) - path = path.substring(0, path.length() - 1); - while (true) { - if (pattern.equals(path)) - return (true); - int slash = path.lastIndexOf('/'); - if (slash <= 0) - break; - path = path.substring(0, slash); - } - return (false); - } - - // Check for suffix matching - if (pattern.startsWith("*.")) { - int slash = path.lastIndexOf('/'); - int period = path.lastIndexOf('.'); - if ((slash >= 0) && (period > slash) && - path.endsWith(pattern.substring(1))) { - return (true); - } - return (false); - } - - // Check for universal mapping - if (pattern.equals("/")) - return (true); - - return (false); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.deploy; + +import java.io.Serializable; + + +/** + * Representation of a security constraint element for a web application, + * as represented in a <security-constraint> element in the + * deployment descriptor. + *

    + * WARNING: It is assumed that instances of this class will be created + * and modified only within the context of a single thread, before the instance + * is made visible to the remainder of the application. After that, only read + * access is expected. Therefore, none of the read and write access within + * this class is synchronized. + * + * @author Craig R. McClanahan + * @version $Revision: 302879 $ $Date: 2004-05-13 22:40:49 +0200 (jeu., 13 mai 2004) $ + */ + +public class SecurityConstraint implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new security constraint instance with default values. + */ + public SecurityConstraint() { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Was the "all roles" wildcard included in the authorization constraints + * for this security constraint? + */ + private boolean allRoles = false; + + + /** + * Was an authorization constraint included in this security constraint? + * This is necessary to distinguish the case where an auth-constraint with + * no roles (signifying no direct access at all) was requested, versus + * a lack of auth-constraint which implies no access control checking. + */ + private boolean authConstraint = false; + + + /** + * The set of roles permitted to access resources protected by this + * security constraint. + */ + private String authRoles[] = new String[0]; + + + /** + * The set of web resource collections protected by this security + * constraint. + */ + private SecurityCollection collections[] = new SecurityCollection[0]; + + + /** + * The display name of this security constraint. + */ + private String displayName = null; + + + /** + * The user data constraint for this security constraint. Must be NONE, + * INTEGRAL, or CONFIDENTIAL. + */ + private String userConstraint = "NONE"; + + + // ------------------------------------------------------------- Properties + + + /** + * Was the "all roles" wildcard included in this authentication + * constraint? + */ + public boolean getAllRoles() { + + return (this.allRoles); + + } + + + /** + * Return the authorization constraint present flag for this security + * constraint. + */ + public boolean getAuthConstraint() { + + return (this.authConstraint); + + } + + + /** + * Set the authorization constraint present flag for this security + * constraint. + */ + public void setAuthConstraint(boolean authConstraint) { + + this.authConstraint = authConstraint; + + } + + + /** + * Return the display name of this security constraint. + */ + public String getDisplayName() { + + return (this.displayName); + + } + + + /** + * Set the display name of this security constraint. + */ + public void setDisplayName(String displayName) { + + this.displayName = displayName; + + } + + + /** + * Return the user data constraint for this security constraint. + */ + public String getUserConstraint() { + + return (userConstraint); + + } + + + /** + * Set the user data constraint for this security constraint. + * + * @param userConstraint The new user data constraint + */ + public void setUserConstraint(String userConstraint) { + + if (userConstraint != null) + this.userConstraint = userConstraint; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an authorization role, which is a role name that will be + * permitted access to the resources protected by this security constraint. + * + * @param authRole Role name to be added + */ + public void addAuthRole(String authRole) { + + if (authRole == null) + return; + if ("*".equals(authRole)) { + allRoles = true; + return; + } + String results[] = new String[authRoles.length + 1]; + for (int i = 0; i < authRoles.length; i++) + results[i] = authRoles[i]; + results[authRoles.length] = authRole; + authRoles = results; + authConstraint = true; + + } + + + /** + * Add a new web resource collection to those protected by this + * security constraint. + * + * @param collection The new web resource collection + */ + public void addCollection(SecurityCollection collection) { + + if (collection == null) + return; + SecurityCollection results[] = + new SecurityCollection[collections.length + 1]; + for (int i = 0; i < collections.length; i++) + results[i] = collections[i]; + results[collections.length] = collection; + collections = results; + + } + + + /** + * Return true if the specified role is permitted access to + * the resources protected by this security constraint. + * + * @param role Role name to be checked + */ + public boolean findAuthRole(String role) { + + if (role == null) + return (false); + for (int i = 0; i < authRoles.length; i++) { + if (role.equals(authRoles[i])) + return (true); + } + return (false); + + } + + + /** + * Return the set of roles that are permitted access to the resources + * protected by this security constraint. If none have been defined, + * a zero-length array is returned (which implies that all authenticated + * users are permitted access). + */ + public String[] findAuthRoles() { + + return (authRoles); + + } + + + /** + * Return the web resource collection for the specified name, if any; + * otherwise, return null. + * + * @param name Web resource collection name to return + */ + public SecurityCollection findCollection(String name) { + + if (name == null) + return (null); + for (int i = 0; i < collections.length; i++) { + if (name.equals(collections[i].getName())) + return (collections[i]); + } + return (null); + + } + + + /** + * Return all of the web resource collections protected by this + * security constraint. If there are none, a zero-length array is + * returned. + */ + public SecurityCollection[] findCollections() { + + return (collections); + + } + + + /** + * Return true if the specified context-relative URI (and + * associated HTTP method) are protected by this security constraint. + * + * @param uri Context-relative URI to check + * @param method Request method being used + */ + public boolean included(String uri, String method) { + + // We cannot match without a valid request method + if (method == null) + return (false); + + // Check all of the collections included in this constraint + for (int i = 0; i < collections.length; i++) { + if (!collections[i].findMethod(method)) + continue; + String patterns[] = collections[i].findPatterns(); + for (int j = 0; j < patterns.length; j++) { + if (matchPattern(uri, patterns[j])) + return (true); + } + } + + // No collection included in this constraint matches this request + return (false); + + } + + + /** + * Remove the specified role from the set of roles permitted to access + * the resources protected by this security constraint. + * + * @param authRole Role name to be removed + */ + public void removeAuthRole(String authRole) { + + if (authRole == null) + return; + int n = -1; + for (int i = 0; i < authRoles.length; i++) { + if (authRoles[i].equals(authRole)) { + n = i; + break; + } + } + if (n >= 0) { + int j = 0; + String results[] = new String[authRoles.length - 1]; + for (int i = 0; i < authRoles.length; i++) { + if (i != n) + results[j++] = authRoles[i]; + } + authRoles = results; + } + + } + + + /** + * Remove the specified web resource collection from those protected by + * this security constraint. + * + * @param collection Web resource collection to be removed + */ + public void removeCollection(SecurityCollection collection) { + + if (collection == null) + return; + int n = -1; + for (int i = 0; i < collections.length; i++) { + if (collections[i].equals(collection)) { + n = i; + break; + } + } + if (n >= 0) { + int j = 0; + SecurityCollection results[] = + new SecurityCollection[collections.length - 1]; + for (int i = 0; i < collections.length; i++) { + if (i != n) + results[j++] = collections[i]; + } + collections = results; + } + + } + + + /** + * Return a String representation of this security constraint. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SecurityConstraint["); + for (int i = 0; i < collections.length; i++) { + if (i > 0) + sb.append(", "); + sb.append(collections[i].getName()); + } + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Does the specified request path match the specified URL pattern? + * This method follows the same rules (in the same order) as those used + * for mapping requests to servlets. + * + * @param path Context-relative request path to be checked + * (must start with '/') + * @param pattern URL pattern to be compared against + */ + private boolean matchPattern(String path, String pattern) { + + // Normalize the argument strings + if ((path == null) || (path.length() == 0)) + path = "/"; + if ((pattern == null) || (pattern.length() == 0)) + pattern = "/"; + + // Check for exact match + if (path.equals(pattern)) + return (true); + + // Check for path prefix matching + if (pattern.startsWith("/") && pattern.endsWith("/*")) { + pattern = pattern.substring(0, pattern.length() - 2); + if (pattern.length() == 0) + return (true); // "/*" is the same as "/" + if (path.endsWith("/")) + path = path.substring(0, path.length() - 1); + while (true) { + if (pattern.equals(path)) + return (true); + int slash = path.lastIndexOf('/'); + if (slash <= 0) + break; + path = path.substring(0, slash); + } + return (false); + } + + // Check for suffix matching + if (pattern.startsWith("*.")) { + int slash = path.lastIndexOf('/'); + int period = path.lastIndexOf('.'); + if ((slash >= 0) && (period > slash) && + path.endsWith(pattern.substring(1))) { + return (true); + } + return (false); + } + + // Check for universal mapping + if (pattern.equals("/")) + return (true); + + return (false); + + } + + +} diff --git a/java/org/apache/catalina/deploy/mbeans-descriptors.xml b/java/org/apache/catalina/deploy/mbeans-descriptors.xml index 1d982eb0b..3dc13b229 100644 --- a/java/org/apache/catalina/deploy/mbeans-descriptors.xml +++ b/java/org/apache/catalina/deploy/mbeans-descriptors.xml @@ -1,185 +1,185 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/deploy/package.html b/java/org/apache/catalina/deploy/package.html index 81b742d08..2612fa023 100644 --- a/java/org/apache/catalina/deploy/package.html +++ b/java/org/apache/catalina/deploy/package.html @@ -1,10 +1,10 @@ - - -

    This package contains Java objects that represent complex data structures -from the web application deployment descriptor file (web.xml). -It is assumed that these objects will be initialized within the context of -a single thread, and then referenced in a read-only manner subsequent to that -time. Therefore, no multi-thread synchronization is utilized within the -implementation classes.

    - - + + +

    This package contains Java objects that represent complex data structures +from the web application deployment descriptor file (web.xml). +It is assumed that these objects will be initialized within the context of +a single thread, and then referenced in a read-only manner subsequent to that +time. Therefore, no multi-thread synchronization is utilized within the +implementation classes.

    + + diff --git a/java/org/apache/catalina/loader/Constants.java b/java/org/apache/catalina/loader/Constants.java index 7d5aeb057..23cb78b16 100644 --- a/java/org/apache/catalina/loader/Constants.java +++ b/java/org/apache/catalina/loader/Constants.java @@ -1,25 +1,25 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - - -public class Constants { - - public static final String Package = "org.apache.catalina.loader"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + + +public class Constants { + + public static final String Package = "org.apache.catalina.loader"; + +} diff --git a/java/org/apache/catalina/loader/LocaStrings_fr.properties b/java/org/apache/catalina/loader/LocaStrings_fr.properties index 08d13e19e..6c19abff6 100644 --- a/java/org/apache/catalina/loader/LocaStrings_fr.properties +++ b/java/org/apache/catalina/loader/LocaStrings_fr.properties @@ -1,30 +1,30 @@ -fileClassLoader.canRead=Le réceptacle (repository) {0} ne peut être lu -fileClassLoader.exists=Le réceptacle (repository) {0} n''existe pas -fileClassLoader.jarFile=Impossible de lire le fichier JAR {0} -fileClassLoader.restricted=Impossible de charger la classe restreinte (restricted class) {0} -standardLoader.addRepository=Ajout du réceptacle (repository) {0} -standardLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré -standardLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes -standardLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte -standardLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux -standardLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré -standardLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0} -standardLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte -standardLoader.removeRepository=Retrait du réceptacle (repository) {0} -standardLoader.starting=Démarrage de ce chargeur (loader) -standardLoader.stopping=Arrêt de ce chargeur (loader) -webappLoader.addRepository=Ajout du réceptacle (repository) {0} -webappLoader.deploy=Déploiement des classes des réceptacles (class repositories) vers le dossier de travail (work directory) {0} -webappLoader.jarDeploy=Déploiement du JAR {0} vers {1} -webappLoader.classDeploy=Déploiement des fichiers classes {0} vers {1} -webappLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré -webappLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes -webappLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte -webappLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux -webappLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré -webappLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0} -webappLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte -webappLoader.removeRepository=Retrait du réceptacle (repository) {0} -webappLoader.starting=Démarrage de ce chargeur (loader) -webappLoader.stopping=Arrêt de ce chargeur (loader) -webappLoader.failModifiedCheck=Erreur dans le suivi des modifications +fileClassLoader.canRead=Le réceptacle (repository) {0} ne peut être lu +fileClassLoader.exists=Le réceptacle (repository) {0} n''existe pas +fileClassLoader.jarFile=Impossible de lire le fichier JAR {0} +fileClassLoader.restricted=Impossible de charger la classe restreinte (restricted class) {0} +standardLoader.addRepository=Ajout du réceptacle (repository) {0} +standardLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré +standardLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes +standardLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte +standardLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux +standardLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré +standardLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0} +standardLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte +standardLoader.removeRepository=Retrait du réceptacle (repository) {0} +standardLoader.starting=Démarrage de ce chargeur (loader) +standardLoader.stopping=Arrêt de ce chargeur (loader) +webappLoader.addRepository=Ajout du réceptacle (repository) {0} +webappLoader.deploy=Déploiement des classes des réceptacles (class repositories) vers le dossier de travail (work directory) {0} +webappLoader.jarDeploy=Déploiement du JAR {0} vers {1} +webappLoader.classDeploy=Déploiement des fichiers classes {0} vers {1} +webappLoader.alreadyStarted=Le chargeur (loader) a déjà été démarré +webappLoader.checkInterval=Impossible de régler l''interval de vérification de rechargement à {0} secondes +webappLoader.notContext=Impossible d''auto-recharger sans que le conteneur ne soit un contexte +webappLoader.notReloadabe=Propriété de rechargement (reloadable property) mise à faux +webappLoader.notStarted=Le chargeur (loader) n''a pas encore été démarré +webappLoader.reloadable=Impossible de mettre la propriété de rechargement (reloadable property) à {0} +webappLoader.reloading=Les vérifications de rechargement sont activées pour ce contexte +webappLoader.removeRepository=Retrait du réceptacle (repository) {0} +webappLoader.starting=Démarrage de ce chargeur (loader) +webappLoader.stopping=Arrêt de ce chargeur (loader) +webappLoader.failModifiedCheck=Erreur dans le suivi des modifications diff --git a/java/org/apache/catalina/loader/LocalStrings.properties b/java/org/apache/catalina/loader/LocalStrings.properties index 9db238f44..45e50f079 100644 --- a/java/org/apache/catalina/loader/LocalStrings.properties +++ b/java/org/apache/catalina/loader/LocalStrings.properties @@ -1,31 +1,31 @@ -fileClassLoader.canRead=Repository {0} cannot be read -fileClassLoader.exists=Repository {0} does not exist -fileClassLoader.jarFile=Cannot read JAR file {0} -fileClassLoader.restricted=Cannot load restricted class {0} -standardLoader.addRepository=Adding repository {0} -standardLoader.alreadyStarted=Loader has already been started -standardLoader.checkInterval=Cannot set reload check interval to {0} seconds -standardLoader.notContext=Cannot auto-reload unless our Container is a Context -standardLoader.notReloadabe=Reloadable property is set to false -standardLoader.notStarted=Loader has not yet been started -standardLoader.reloadable=Cannot set reloadable property to {0} -standardLoader.reloading=Reloading checks are enabled for this Context -standardLoader.removeRepository=Removing repository {0} -standardLoader.starting=Starting this Loader -standardLoader.stopping=Stopping this Loader -webappClassLoader.stopped=Illegal access: this web application instance has been stopped already. Could not load {0}. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. -webappLoader.addRepository=Adding repository {0} -webappLoader.deploy=Deploying class repositories to work directory {0} -webappLoader.jarDeploy=Deploy JAR {0} to {1} -webappLoader.classDeploy=Deploy class files {0} to {1} -webappLoader.alreadyStarted=Loader has already been started -webappLoader.checkInterval=Cannot set reload check interval to {0} seconds -webappLoader.notContext=Cannot auto-reload unless our Container is a Context -webappLoader.notReloadabe=Reloadable property is set to false -webappLoader.notStarted=Loader has not yet been started -webappLoader.reloadable=Cannot set reloadable property to {0} -webappLoader.reloading=Reloading checks are enabled for this Context -webappLoader.removeRepository=Removing repository {0} -webappLoader.starting=Starting this Loader -webappLoader.stopping=Stopping this Loader -webappLoader.failModifiedCheck=Error tracking modifications +fileClassLoader.canRead=Repository {0} cannot be read +fileClassLoader.exists=Repository {0} does not exist +fileClassLoader.jarFile=Cannot read JAR file {0} +fileClassLoader.restricted=Cannot load restricted class {0} +standardLoader.addRepository=Adding repository {0} +standardLoader.alreadyStarted=Loader has already been started +standardLoader.checkInterval=Cannot set reload check interval to {0} seconds +standardLoader.notContext=Cannot auto-reload unless our Container is a Context +standardLoader.notReloadabe=Reloadable property is set to false +standardLoader.notStarted=Loader has not yet been started +standardLoader.reloadable=Cannot set reloadable property to {0} +standardLoader.reloading=Reloading checks are enabled for this Context +standardLoader.removeRepository=Removing repository {0} +standardLoader.starting=Starting this Loader +standardLoader.stopping=Stopping this Loader +webappClassLoader.stopped=Illegal access: this web application instance has been stopped already. Could not load {0}. The eventual following stack trace is caused by an error thrown for debugging purposes as well as to attempt to terminate the thread which caused the illegal access, and has no functional impact. +webappLoader.addRepository=Adding repository {0} +webappLoader.deploy=Deploying class repositories to work directory {0} +webappLoader.jarDeploy=Deploy JAR {0} to {1} +webappLoader.classDeploy=Deploy class files {0} to {1} +webappLoader.alreadyStarted=Loader has already been started +webappLoader.checkInterval=Cannot set reload check interval to {0} seconds +webappLoader.notContext=Cannot auto-reload unless our Container is a Context +webappLoader.notReloadabe=Reloadable property is set to false +webappLoader.notStarted=Loader has not yet been started +webappLoader.reloadable=Cannot set reloadable property to {0} +webappLoader.reloading=Reloading checks are enabled for this Context +webappLoader.removeRepository=Removing repository {0} +webappLoader.starting=Starting this Loader +webappLoader.stopping=Stopping this Loader +webappLoader.failModifiedCheck=Error tracking modifications diff --git a/java/org/apache/catalina/loader/LocalStrings_es.properties b/java/org/apache/catalina/loader/LocalStrings_es.properties index ec0c31c14..2e7c95b76 100644 --- a/java/org/apache/catalina/loader/LocalStrings_es.properties +++ b/java/org/apache/catalina/loader/LocalStrings_es.properties @@ -1,31 +1,31 @@ -fileClassLoader.canRead=No se puede leer el Repositorio {0} -fileClassLoader.exists=No existe el Repositorio {0} -fileClassLoader.jarFile=No puedo leer archivo JAR {0} -fileClassLoader.restricted=No puedo cargar clase restringida {0} -standardLoader.addRepository=Añadiendo repositorio {0} -standardLoader.alreadyStarted=Ya ha sido arrancado el Cargador -standardLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos -standardLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto -standardLoader.notReloadabe=La propiedad Recargable está puesta a falsa -standardLoader.notStarted=Aún no se ha arrancado el Cargador -standardLoader.reloadable=No puedo poner la propiedad recargable a {0} -standardLoader.reloading=Se han activado las revisiones de Recarga para este Contexto -standardLoader.removeRepository=Quitando repositorio {0} -standardLoader.starting=Arrancando este Cargador -standardLoader.stopping=Parando este Cargador -webappClassLoader.stopped=Acceso ilegal: esta instancia de aplicación web ya ha sido parada. Could not load {0}. La eventual traza de pila que sigue ha sido motivada por un error lanzado con motivos de depuración así como para intentar terminar el hilo que motivó el acceso ilegal y no tiene impacto funcional. -webappLoader.addRepository=Añadiendo repositorio {0} -webappLoader.deploy=Desplegando repositorios de clase en directorio de trabajo {0} -webappLoader.jarDeploy=Despliegue del JAR {0} en {1} -webappLoader.classDeploy=Despliegue de archivos de clase {0} en {1} -webappLoader.alreadyStarted=Ya se ha arrancado el Cargador -webappLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos -webappLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto -webappLoader.notReloadabe=Se ha puesto la propiedad Recargable a falsa -webappLoader.notStarted=Aún no se ha arrancado el Cargador -webappLoader.reloadable=No puedo poner la propiedad recargable a {0} -webappLoader.reloading=Se han activado los chequeos de Recarga para este Contexto -webappLoader.removeRepository=Quitando repositorio {0} -webappLoader.starting=Arrancando este Cargador -webappLoader.stopping=Parando este Cargador -webappLoader.failModifiedCheck=Modificaciones de pista de error +fileClassLoader.canRead=No se puede leer el Repositorio {0} +fileClassLoader.exists=No existe el Repositorio {0} +fileClassLoader.jarFile=No puedo leer archivo JAR {0} +fileClassLoader.restricted=No puedo cargar clase restringida {0} +standardLoader.addRepository=Añadiendo repositorio {0} +standardLoader.alreadyStarted=Ya ha sido arrancado el Cargador +standardLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos +standardLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto +standardLoader.notReloadabe=La propiedad Recargable está puesta a falsa +standardLoader.notStarted=Aún no se ha arrancado el Cargador +standardLoader.reloadable=No puedo poner la propiedad recargable a {0} +standardLoader.reloading=Se han activado las revisiones de Recarga para este Contexto +standardLoader.removeRepository=Quitando repositorio {0} +standardLoader.starting=Arrancando este Cargador +standardLoader.stopping=Parando este Cargador +webappClassLoader.stopped=Acceso ilegal: esta instancia de aplicación web ya ha sido parada. Could not load {0}. La eventual traza de pila que sigue ha sido motivada por un error lanzado con motivos de depuración así como para intentar terminar el hilo que motivó el acceso ilegal y no tiene impacto funcional. +webappLoader.addRepository=Añadiendo repositorio {0} +webappLoader.deploy=Desplegando repositorios de clase en directorio de trabajo {0} +webappLoader.jarDeploy=Despliegue del JAR {0} en {1} +webappLoader.classDeploy=Despliegue de archivos de clase {0} en {1} +webappLoader.alreadyStarted=Ya se ha arrancado el Cargador +webappLoader.checkInterval=No puedo poner el intervalo de revisión de recarga a {0} segundos +webappLoader.notContext=No puedo auto-recargar a menos que nuestro Contenedor sea un Contexto +webappLoader.notReloadabe=Se ha puesto la propiedad Recargable a falsa +webappLoader.notStarted=Aún no se ha arrancado el Cargador +webappLoader.reloadable=No puedo poner la propiedad recargable a {0} +webappLoader.reloading=Se han activado los chequeos de Recarga para este Contexto +webappLoader.removeRepository=Quitando repositorio {0} +webappLoader.starting=Arrancando este Cargador +webappLoader.stopping=Parando este Cargador +webappLoader.failModifiedCheck=Modificaciones de pista de error diff --git a/java/org/apache/catalina/loader/LocalStrings_ja.properties b/java/org/apache/catalina/loader/LocalStrings_ja.properties index 3f44753a1..4b1e56bd0 100644 --- a/java/org/apache/catalina/loader/LocalStrings_ja.properties +++ b/java/org/apache/catalina/loader/LocalStrings_ja.properties @@ -1,31 +1,31 @@ -fileClassLoader.canRead=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u8aad\u3081\u307e\u305b\u3093 -fileClassLoader.exists=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 -fileClassLoader.jarFile=JAR\u30d5\u30a1\u30a4\u30eb {0} \u304c\u8aad\u3081\u307e\u305b\u3093 -fileClassLoader.restricted=\u5236\u9650\u3055\u308c\u305f\u30af\u30e9\u30b9 {0} \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -standardLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059 -standardLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 -standardLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093 -standardLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -standardLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 -standardLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059 -standardLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059 -standardLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059 -standardLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059 -webappClassLoader.stopped=\u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9: \u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u65e2\u306b\u505c\u6b62\u3055\u308c\u3066\u3044\u307e\u3059 Could not load {0}. \u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9\u3092\u5f15\u304d\u8d77\u3053\u3057\u305f\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3055\u305b\u3001\u6295\u3052\u3089\u308c\u305f\u30a8\u30e9\u30fc\u306b\u3088\u308a\u30c7\u30d0\u30c3\u30b0\u7528\u306b\u6b21\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u304c\u751f\u6210\u3055\u308c\u307e\u3057\u305f\u304c\uff0c\u6a5f\u80fd\u306b\u5f71\u97ff\u306f\u3042\u308a\u307e\u305b\u3093 -webappLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059 -webappLoader.deploy=\u30af\u30e9\u30b9\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u914d\u5099\u3057\u307e\u3059 -webappLoader.jarDeploy=JAR {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059 -webappLoader.classDeploy=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059 -webappLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -webappLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 -webappLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093 -webappLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -webappLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -webappLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 -webappLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059 -webappLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059 -webappLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059 -webappLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059 -webappLoader.failModifiedCheck=\u5909\u66f4\u8ffd\u8de1\u30a8\u30e9\u30fc\u3067\u3059 +fileClassLoader.canRead=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u8aad\u3081\u307e\u305b\u3093 +fileClassLoader.exists=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 +fileClassLoader.jarFile=JAR\u30d5\u30a1\u30a4\u30eb {0} \u304c\u8aad\u3081\u307e\u305b\u3093 +fileClassLoader.restricted=\u5236\u9650\u3055\u308c\u305f\u30af\u30e9\u30b9 {0} \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +standardLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059 +standardLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 +standardLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093 +standardLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +standardLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 +standardLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059 +standardLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059 +standardLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059 +standardLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059 +webappClassLoader.stopped=\u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9: \u3053\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306f\u65e2\u306b\u505c\u6b62\u3055\u308c\u3066\u3044\u307e\u3059 Could not load {0}. \u4e0d\u6b63\u306a\u30a2\u30af\u30bb\u30b9\u3092\u5f15\u304d\u8d77\u3053\u3057\u305f\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3055\u305b\u3001\u6295\u3052\u3089\u308c\u305f\u30a8\u30e9\u30fc\u306b\u3088\u308a\u30c7\u30d0\u30c3\u30b0\u7528\u306b\u6b21\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u304c\u751f\u6210\u3055\u308c\u307e\u3057\u305f\u304c\uff0c\u6a5f\u80fd\u306b\u5f71\u97ff\u306f\u3042\u308a\u307e\u305b\u3093 +webappLoader.addRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u8ffd\u52a0\u3057\u307e\u3059 +webappLoader.deploy=\u30af\u30e9\u30b9\u30ea\u30dd\u30b8\u30c8\u30ea\u3092\u4f5c\u696d\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306b\u914d\u5099\u3057\u307e\u3059 +webappLoader.jarDeploy=JAR {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059 +webappLoader.classDeploy=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u914d\u5099\u3057\u307e\u3059 +webappLoader.alreadyStarted=\u30ed\u30fc\u30c0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +webappLoader.checkInterval=\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u9593\u9694\u3092{0}\u79d2\u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 +webappLoader.notContext=\u3053\u306e\u30b3\u30f3\u30c6\u30ca\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306a\u3051\u308c\u3070\u3001\u81ea\u52d5\u518d\u30ed\u30fc\u30c9\u306f\u3067\u304d\u307e\u305b\u3093 +webappLoader.notReloadabe=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u304cfalse\u306b\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +webappLoader.notStarted=\u30ed\u30fc\u30c0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +webappLoader.reloadable=reloadable\u30d7\u30ed\u30d1\u30c6\u30a3\u3092 {0} \u306b\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 +webappLoader.reloading=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e\u518d\u30ed\u30fc\u30c9\u30c1\u30a7\u30c3\u30af\u306f\u6709\u52b9\u3067\u3059 +webappLoader.removeRepository=\u30ea\u30dd\u30b8\u30c8\u30ea {0} \u3092\u524a\u9664\u3057\u307e\u3059 +webappLoader.starting=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u8d77\u52d5\u3057\u307e\u3059 +webappLoader.stopping=\u3053\u306e\u30ed\u30fc\u30c0\u3092\u505c\u6b62\u3057\u307e\u3059 +webappLoader.failModifiedCheck=\u5909\u66f4\u8ffd\u8de1\u30a8\u30e9\u30fc\u3067\u3059 diff --git a/java/org/apache/catalina/loader/Reloader.java b/java/org/apache/catalina/loader/Reloader.java index f221f9a74..7670a7f82 100644 --- a/java/org/apache/catalina/loader/Reloader.java +++ b/java/org/apache/catalina/loader/Reloader.java @@ -1,61 +1,61 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - - -/** - * Internal interface that ClassLoader implementations may - * optionally implement to support the auto-reload functionality of - * the classloader associated with the context. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface Reloader { - - - /** - * Add a new repository to the set of places this ClassLoader can look for - * classes to be loaded. - * - * @param repository Name of a source of classes to be loaded, such as a - * directory pathname, a JAR file pathname, or a ZIP file pathname - * - * @exception IllegalArgumentException if the specified repository is - * invalid or does not exist - */ - public void addRepository(String repository); - - - /** - * Return a String array of the current repositories for this class - * loader. If there are no repositories, a zero-length array is - * returned. - */ - public String[] findRepositories(); - - - /** - * Have one or more classes or resources been modified so that a reload - * is appropriate? - */ - public boolean modified(); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + + +/** + * Internal interface that ClassLoader implementations may + * optionally implement to support the auto-reload functionality of + * the classloader associated with the context. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface Reloader { + + + /** + * Add a new repository to the set of places this ClassLoader can look for + * classes to be loaded. + * + * @param repository Name of a source of classes to be loaded, such as a + * directory pathname, a JAR file pathname, or a ZIP file pathname + * + * @exception IllegalArgumentException if the specified repository is + * invalid or does not exist + */ + public void addRepository(String repository); + + + /** + * Return a String array of the current repositories for this class + * loader. If there are no repositories, a zero-length array is + * returned. + */ + public String[] findRepositories(); + + + /** + * Have one or more classes or resources been modified so that a reload + * is appropriate? + */ + public boolean modified(); + + +} diff --git a/java/org/apache/catalina/loader/ResourceEntry.java b/java/org/apache/catalina/loader/ResourceEntry.java index a3e01b968..70928ec18 100644 --- a/java/org/apache/catalina/loader/ResourceEntry.java +++ b/java/org/apache/catalina/loader/ResourceEntry.java @@ -1,77 +1,77 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - -import java.net.URL; -import java.security.cert.Certificate; -import java.util.jar.Manifest; - -/** - * Resource entry. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ -public class ResourceEntry { - - - /** - * The "last modified" time of the origin file at the time this class - * was loaded, in milliseconds since the epoch. - */ - public long lastModified = -1; - - - /** - * Binary content of the resource. - */ - public byte[] binaryContent = null; - - - /** - * Loaded class. - */ - public Class loadedClass = null; - - - /** - * URL source from where the object was loaded. - */ - public URL source = null; - - - /** - * URL of the codebase from where the object was loaded. - */ - public URL codeBase = null; - - - /** - * Manifest (if the resource was loaded from a JAR). - */ - public Manifest manifest = null; - - - /** - * Certificates (if the resource was loaded from a JAR). - */ - public Certificate[] certificates = null; - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + +import java.net.URL; +import java.security.cert.Certificate; +import java.util.jar.Manifest; + +/** + * Resource entry. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ +public class ResourceEntry { + + + /** + * The "last modified" time of the origin file at the time this class + * was loaded, in milliseconds since the epoch. + */ + public long lastModified = -1; + + + /** + * Binary content of the resource. + */ + public byte[] binaryContent = null; + + + /** + * Loaded class. + */ + public Class loadedClass = null; + + + /** + * URL source from where the object was loaded. + */ + public URL source = null; + + + /** + * URL of the codebase from where the object was loaded. + */ + public URL codeBase = null; + + + /** + * Manifest (if the resource was loaded from a JAR). + */ + public Manifest manifest = null; + + + /** + * Certificates (if the resource was loaded from a JAR). + */ + public Certificate[] certificates = null; + + +} + diff --git a/java/org/apache/catalina/loader/StandardClassLoader.java b/java/org/apache/catalina/loader/StandardClassLoader.java index 29c246b0e..cfe1d7cde 100644 --- a/java/org/apache/catalina/loader/StandardClassLoader.java +++ b/java/org/apache/catalina/loader/StandardClassLoader.java @@ -1,60 +1,60 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - -import java.net.URL; -import java.net.URLClassLoader; - -/** - * Subclass implementation of java.net.URLClassLoader that knows how - * to load classes from disk directories, as well as local and remote JAR - * files. It also implements the Reloader interface, to provide - * automatic reloading support to the associated loader. - *

    - * In all cases, URLs must conform to the contract specified by - * URLClassLoader - any URL that ends with a "/" character is - * assumed to represent a directory; all other URLs are assumed to be the - * address of a JAR file. - *

    - * IMPLEMENTATION NOTE - Local repositories are searched in - * the order they are added via the initial constructor and/or any subsequent - * calls to addRepository(). - *

    - * IMPLEMENTATION NOTE - At present, there are no dependencies - * from this class to any other Catalina class, so that it could be used - * independently. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303071 $ $Date: 2004-08-05 12:54:43 +0200 (jeu., 05 août 2004) $ - */ - -public class StandardClassLoader - extends URLClassLoader - implements StandardClassLoaderMBean { - - public StandardClassLoader(URL repositories[]) { - super(repositories); - } - - public StandardClassLoader(URL repositories[], ClassLoader parent) { - super(repositories, parent); - } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + +import java.net.URL; +import java.net.URLClassLoader; + +/** + * Subclass implementation of java.net.URLClassLoader that knows how + * to load classes from disk directories, as well as local and remote JAR + * files. It also implements the Reloader interface, to provide + * automatic reloading support to the associated loader. + *

    + * In all cases, URLs must conform to the contract specified by + * URLClassLoader - any URL that ends with a "/" character is + * assumed to represent a directory; all other URLs are assumed to be the + * address of a JAR file. + *

    + * IMPLEMENTATION NOTE - Local repositories are searched in + * the order they are added via the initial constructor and/or any subsequent + * calls to addRepository(). + *

    + * IMPLEMENTATION NOTE - At present, there are no dependencies + * from this class to any other Catalina class, so that it could be used + * independently. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303071 $ $Date: 2004-08-05 12:54:43 +0200 (jeu., 05 août 2004) $ + */ + +public class StandardClassLoader + extends URLClassLoader + implements StandardClassLoaderMBean { + + public StandardClassLoader(URL repositories[]) { + super(repositories); + } + + public StandardClassLoader(URL repositories[], ClassLoader parent) { + super(repositories, parent); + } + +} + diff --git a/java/org/apache/catalina/loader/StandardClassLoaderMBean.java b/java/org/apache/catalina/loader/StandardClassLoaderMBean.java index 7f19d6941..237601582 100644 --- a/java/org/apache/catalina/loader/StandardClassLoaderMBean.java +++ b/java/org/apache/catalina/loader/StandardClassLoaderMBean.java @@ -1,28 +1,28 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - -/** - * MBean interface for StandardClassLoader, to allow JMX remote management. - * - * @author Remy Maucherat - * @version $Revision: 302740 $ $Date: 2004-03-02 13:32:19 +0100 (mar., 02 mars 2004) $ - */ -public interface StandardClassLoaderMBean { -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + +/** + * MBean interface for StandardClassLoader, to allow JMX remote management. + * + * @author Remy Maucherat + * @version $Revision: 302740 $ $Date: 2004-03-02 13:32:19 +0100 (mar., 02 mars 2004) $ + */ +public interface StandardClassLoaderMBean { +} + diff --git a/java/org/apache/catalina/loader/WebappClassLoader.java b/java/org/apache/catalina/loader/WebappClassLoader.java index 71716397e..fb839a7d3 100644 --- a/java/org/apache/catalina/loader/WebappClassLoader.java +++ b/java/org/apache/catalina/loader/WebappClassLoader.java @@ -1,2347 +1,2347 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - -import java.io.ByteArrayInputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilePermission; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.AccessControlException; -import java.security.AccessController; -import java.security.CodeSource; -import java.security.Permission; -import java.security.PermissionCollection; -import java.security.Policy; -import java.security.PrivilegedAction; -import java.sql.Driver; -import java.sql.DriverManager; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Vector; -import java.util.jar.Attributes; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import java.util.jar.Manifest; -import java.util.jar.Attributes.Name; - -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.util.StringManager; -import org.apache.naming.JndiPermission; -import org.apache.naming.resources.Resource; -import org.apache.naming.resources.ResourceAttributes; -import org.apache.tomcat.util.IntrospectionUtils; - -/** - * Specialized web application class loader. - *

    - * This class loader is a full reimplementation of the - * URLClassLoader from the JDK. It is desinged to be fully - * compatible with a normal URLClassLoader, although its internal - * behavior may be completely different. - *

    - * IMPLEMENTATION NOTE - This class loader faithfully follows - * the delegation model recommended in the specification. The system class - * loader will be queried first, then the local repositories, and only then - * delegation to the parent class loader will occur. This allows the web - * application to override any shared class except the classes from J2SE. - * Special handling is provided from the JAXP XML parser interfaces, the JNDI - * interfaces, and the classes from the servlet API, which are never loaded - * from the webapp repository. - *

    - * IMPLEMENTATION NOTE - Due to limitations in Jasper - * compilation technology, any repository which contains classes from - * the servlet API will be ignored by the class loader. - *

    - * IMPLEMENTATION NOTE - The class loader generates source - * URLs which include the full JAR URL when a class is loaded from a JAR file, - * which allows setting security permission at the class level, even when a - * class is contained inside a JAR. - *

    - * IMPLEMENTATION NOTE - Local repositories are searched in - * the order they are added via the initial constructor and/or any subsequent - * calls to addRepository() or addJar(). - *

    - * IMPLEMENTATION NOTE - No check for sealing violations or - * security is made unless a security manager is present. - * - * @author Remy Maucherat - * @author Craig R. McClanahan - * @version $Revision$ $Date: 2006-05-19 19:52:46 -0700 (Fri, 19 May 2006) $ - */ -public class WebappClassLoader - extends URLClassLoader - implements Reloader, Lifecycle - { - - protected static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( WebappClassLoader.class ); - - protected class PrivilegedFindResource - implements PrivilegedAction { - - protected File file; - protected String path; - - PrivilegedFindResource(File file, String path) { - this.file = file; - this.path = path; - } - - public Object run() { - return findResourceInternal(file, path); - } - - } - - - // ------------------------------------------------------- Static Variables - - - /** - * The set of trigger classes that will cause a proposed repository not - * to be added if this class is visible to the class loader that loaded - * this factory class. Typically, trigger classes will be listed for - * components that have been integrated into the JDK for later versions, - * but where the corresponding JAR files are required to run on - * earlier versions. - */ - protected static final String[] triggers = { - "javax.servlet.Servlet" // Servlet API - }; - - - /** - * Set of package names which are not allowed to be loaded from a webapp - * class loader without delegating first. - */ - protected static final String[] packageTriggers = { - }; - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Use anti JAR locking code, which does URL rerouting when accessing - * resources. - */ - boolean antiJARLocking = false; - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new ClassLoader with no defined repositories and no - * parent ClassLoader. - */ - public WebappClassLoader() { - - super(new URL[0]); - this.parent = getParent(); - system = getSystemClassLoader(); - securityManager = System.getSecurityManager(); - - if (securityManager != null) { - refreshPolicy(); - } - - } - - - /** - * Construct a new ClassLoader with no defined repositories and no - * parent ClassLoader. - */ - public WebappClassLoader(ClassLoader parent) { - - super(new URL[0], parent); - - this.parent = getParent(); - - system = getSystemClassLoader(); - securityManager = System.getSecurityManager(); - - if (securityManager != null) { - refreshPolicy(); - } - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated directory context giving access to the resources in this - * webapp. - */ - protected DirContext resources = null; - - - /** - * The cache of ResourceEntry for classes and resources we have loaded, - * keyed by resource name. - */ - protected HashMap resourceEntries = new HashMap(); - - - /** - * The list of not found resources. - */ - protected HashMap notFoundResources = new HashMap(); - - - /** - * Should this class loader delegate to the parent class loader - * before searching its own repositories (i.e. the - * usual Java2 delegation model)? If set to false, - * this class loader will search its own repositories first, and - * delegate to the parent only if the class or resource is not - * found locally. - */ - protected boolean delegate = false; - - - /** - * Last time a JAR was accessed. - */ - protected long lastJarAccessed = 0L; - - - /** - * The list of local repositories, in the order they should be searched - * for locally loaded classes or resources. - */ - protected String[] repositories = new String[0]; - - - /** - * Repositories URLs, used to cache the result of getURLs. - */ - protected URL[] repositoryURLs = null; - - - /** - * Repositories translated as path in the work directory (for Jasper - * originally), but which is used to generate fake URLs should getURLs be - * called. - */ - protected File[] files = new File[0]; - - - /** - * The list of JARs, in the order they should be searched - * for locally loaded classes or resources. - */ - protected JarFile[] jarFiles = new JarFile[0]; - - - /** - * The list of JARs, in the order they should be searched - * for locally loaded classes or resources. - */ - protected File[] jarRealFiles = new File[0]; - - - /** - * The path which will be monitored for added Jar files. - */ - protected String jarPath = null; - - - /** - * The list of JARs, in the order they should be searched - * for locally loaded classes or resources. - */ - protected String[] jarNames = new String[0]; - - - /** - * The list of JARs last modified dates, in the order they should be - * searched for locally loaded classes or resources. - */ - protected long[] lastModifiedDates = new long[0]; - - - /** - * The list of resources which should be checked when checking for - * modifications. - */ - protected String[] paths = new String[0]; - - - /** - * A list of read File and Jndi Permission's required if this loader - * is for a web application context. - */ - protected ArrayList permissionList = new ArrayList(); - - - /** - * Path where resources loaded from JARs will be extracted. - */ - protected File loaderDir = null; - - - /** - * The PermissionCollection for each CodeSource for a web - * application context. - */ - protected HashMap loaderPC = new HashMap(); - - - /** - * Instance of the SecurityManager installed. - */ - protected SecurityManager securityManager = null; - - - /** - * The parent class loader. - */ - protected ClassLoader parent = null; - - - /** - * The system class loader. - */ - protected ClassLoader system = null; - - - /** - * Has this component been started? - */ - protected boolean started = false; - - - /** - * Has external repositories. - */ - protected boolean hasExternalRepositories = false; - - /** - * need conversion for properties files - */ - protected boolean needConvert = false; - - - /** - * All permission. - */ - protected Permission allPermission = new java.security.AllPermission(); - - - // ------------------------------------------------------------- Properties - - - /** - * Get associated resources. - */ - public DirContext getResources() { - - return this.resources; - - } - - - /** - * Set associated resources. - */ - public void setResources(DirContext resources) { - - this.resources = resources; - - } - - - /** - * Return the "delegate first" flag for this class loader. - */ - public boolean getDelegate() { - - return (this.delegate); - - } - - - /** - * Set the "delegate first" flag for this class loader. - * - * @param delegate The new "delegate first" flag - */ - public void setDelegate(boolean delegate) { - - this.delegate = delegate; - - } - - - /** - * @return Returns the antiJARLocking. - */ - public boolean getAntiJARLocking() { - return antiJARLocking; - } - - - /** - * @param antiJARLocking The antiJARLocking to set. - */ - public void setAntiJARLocking(boolean antiJARLocking) { - this.antiJARLocking = antiJARLocking; - } - - - /** - * If there is a Java SecurityManager create a read FilePermission - * or JndiPermission for the file directory path. - * - * @param path file directory path - */ - public void addPermission(String path) { - if (path == null) { - return; - } - - if (securityManager != null) { - Permission permission = null; - if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) { - if (!path.endsWith("/")) { - path = path + "/"; - } - permission = new JndiPermission(path + "*"); - addPermission(permission); - } else { - if (!path.endsWith(File.separator)) { - permission = new FilePermission(path, "read"); - addPermission(permission); - path = path + File.separator; - } - permission = new FilePermission(path + "-", "read"); - addPermission(permission); - } - } - } - - - /** - * If there is a Java SecurityManager create a read FilePermission - * or JndiPermission for URL. - * - * @param url URL for a file or directory on local system - */ - public void addPermission(URL url) { - if (url != null) { - addPermission(url.toString()); - } - } - - - /** - * If there is a Java SecurityManager create a Permission. - * - * @param permission The permission - */ - public void addPermission(Permission permission) { - if ((securityManager != null) && (permission != null)) { - permissionList.add(permission); - } - } - - - /** - * Return the JAR path. - */ - public String getJarPath() { - - return this.jarPath; - - } - - - /** - * Change the Jar path. - */ - public void setJarPath(String jarPath) { - - this.jarPath = jarPath; - - } - - - /** - * Change the work directory. - */ - public void setWorkDir(File workDir) { - this.loaderDir = new File(workDir, "loader"); - } - - /** - * Utility method for use in subclasses. - * Must be called before Lifecycle methods to have any effect. - */ - protected void setParentClassLoader(ClassLoader pcl) { - parent = pcl; - } - - // ------------------------------------------------------- Reloader Methods - - - /** - * Add a new repository to the set of places this ClassLoader can look for - * classes to be loaded. - * - * @param repository Name of a source of classes to be loaded, such as a - * directory pathname, a JAR file pathname, or a ZIP file pathname - * - * @exception IllegalArgumentException if the specified repository is - * invalid or does not exist - */ - public void addRepository(String repository) { - - // Ignore any of the standard repositories, as they are set up using - // either addJar or addRepository - if (repository.startsWith("/WEB-INF/lib") - || repository.startsWith("/WEB-INF/classes")) - return; - - // Add this repository to our underlying class loader - try { - URL url = new URL(repository); - super.addURL(url); - hasExternalRepositories = true; - repositoryURLs = null; - } catch (MalformedURLException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Invalid repository: " + repository); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Add a new repository to the set of places this ClassLoader can look for - * classes to be loaded. - * - * @param repository Name of a source of classes to be loaded, such as a - * directory pathname, a JAR file pathname, or a ZIP file pathname - * - * @exception IllegalArgumentException if the specified repository is - * invalid or does not exist - */ - synchronized void addRepository(String repository, File file) { - - // Note : There should be only one (of course), but I think we should - // keep this a bit generic - - if (repository == null) - return; - - if (log.isDebugEnabled()) - log.debug("addRepository(" + repository + ")"); - - int i; - - // Add this repository to our internal list - String[] result = new String[repositories.length + 1]; - for (i = 0; i < repositories.length; i++) { - result[i] = repositories[i]; - } - result[repositories.length] = repository; - repositories = result; - - // Add the file to the list - File[] result2 = new File[files.length + 1]; - for (i = 0; i < files.length; i++) { - result2[i] = files[i]; - } - result2[files.length] = file; - files = result2; - - } - - - synchronized void addJar(String jar, JarFile jarFile, File file) - throws IOException { - - if (jar == null) - return; - if (jarFile == null) - return; - if (file == null) - return; - - if (log.isDebugEnabled()) - log.debug("addJar(" + jar + ")"); - - int i; - - if ((jarPath != null) && (jar.startsWith(jarPath))) { - - String jarName = jar.substring(jarPath.length()); - while (jarName.startsWith("/")) - jarName = jarName.substring(1); - - String[] result = new String[jarNames.length + 1]; - for (i = 0; i < jarNames.length; i++) { - result[i] = jarNames[i]; - } - result[jarNames.length] = jarName; - jarNames = result; - - } - - try { - - // Register the JAR for tracking - - long lastModified = - ((ResourceAttributes) resources.getAttributes(jar)) - .getLastModified(); - - String[] result = new String[paths.length + 1]; - for (i = 0; i < paths.length; i++) { - result[i] = paths[i]; - } - result[paths.length] = jar; - paths = result; - - long[] result3 = new long[lastModifiedDates.length + 1]; - for (i = 0; i < lastModifiedDates.length; i++) { - result3[i] = lastModifiedDates[i]; - } - result3[lastModifiedDates.length] = lastModified; - lastModifiedDates = result3; - - } catch (NamingException e) { - // Ignore - } - - // If the JAR currently contains invalid classes, don't actually use it - // for classloading - if (!validateJarFile(file)) - return; - - JarFile[] result2 = new JarFile[jarFiles.length + 1]; - for (i = 0; i < jarFiles.length; i++) { - result2[i] = jarFiles[i]; - } - result2[jarFiles.length] = jarFile; - jarFiles = result2; - - // Add the file to the list - File[] result4 = new File[jarRealFiles.length + 1]; - for (i = 0; i < jarRealFiles.length; i++) { - result4[i] = jarRealFiles[i]; - } - result4[jarRealFiles.length] = file; - jarRealFiles = result4; - } - - - /** - * Return a String array of the current repositories for this class - * loader. If there are no repositories, a zero-length array is - * returned.For security reason, returns a clone of the Array (since - * String are immutable). - */ - public String[] findRepositories() { - - return ((String[])repositories.clone()); - - } - - - /** - * Have one or more classes or resources been modified so that a reload - * is appropriate? - */ - public boolean modified() { - - if (log.isDebugEnabled()) - log.debug("modified()"); - - // Checking for modified loaded resources - int length = paths.length; - - // A rare race condition can occur in the updates of the two arrays - // It's totally ok if the latest class added is not checked (it will - // be checked the next time - int length2 = lastModifiedDates.length; - if (length > length2) - length = length2; - - for (int i = 0; i < length; i++) { - try { - long lastModified = - ((ResourceAttributes) resources.getAttributes(paths[i])) - .getLastModified(); - if (lastModified != lastModifiedDates[i]) { - if( log.isDebugEnabled() ) - log.debug(" Resource '" + paths[i] - + "' was modified; Date is now: " - + new java.util.Date(lastModified) + " Was: " - + new java.util.Date(lastModifiedDates[i])); - return (true); - } - } catch (NamingException e) { - log.error(" Resource '" + paths[i] + "' is missing"); - return (true); - } - } - - length = jarNames.length; - - // Check if JARs have been added or removed - if (getJarPath() != null) { - - try { - NamingEnumeration enumeration = resources.listBindings(getJarPath()); - int i = 0; - while (enumeration.hasMoreElements() && (i < length)) { - NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); - String name = ncPair.getName(); - // Ignore non JARs present in the lib folder - if (!name.endsWith(".jar")) - continue; - if (!name.equals(jarNames[i])) { - // Missing JAR - log.info(" Additional JARs have been added : '" - + name + "'"); - return (true); - } - i++; - } - if (enumeration.hasMoreElements()) { - while (enumeration.hasMoreElements()) { - NameClassPair ncPair = - (NameClassPair) enumeration.nextElement(); - String name = ncPair.getName(); - // Additional non-JAR files are allowed - if (name.endsWith(".jar")) { - // There was more JARs - log.info(" Additional JARs have been added"); - return (true); - } - } - } else if (i < jarNames.length) { - // There was less JARs - log.info(" Additional JARs have been added"); - return (true); - } - } catch (NamingException e) { - if (log.isDebugEnabled()) - log.debug(" Failed tracking modifications of '" - + getJarPath() + "'"); - } catch (ClassCastException e) { - log.error(" Failed tracking modifications of '" - + getJarPath() + "' : " + e.getMessage()); - } - - } - - // No classes have been modified - return (false); - - } - - - /** - * Render a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("WebappClassLoader\r\n"); - sb.append(" delegate: "); - sb.append(delegate); - sb.append("\r\n"); - sb.append(" repositories:\r\n"); - if (repositories != null) { - for (int i = 0; i < repositories.length; i++) { - sb.append(" "); - sb.append(repositories[i]); - sb.append("\r\n"); - } - } - if (this.parent != null) { - sb.append("----------> Parent Classloader:\r\n"); - sb.append(this.parent.toString()); - sb.append("\r\n"); - } - return (sb.toString()); - - } - - - // ---------------------------------------------------- ClassLoader Methods - - - /** - * Add the specified URL to the classloader. - */ - protected void addURL(URL url) { - super.addURL(url); - hasExternalRepositories = true; - repositoryURLs = null; - } - - - /** - * Find the specified class in our local repositories, if possible. If - * not found, throw ClassNotFoundException. - * - * @param name Name of the class to be loaded - * - * @exception ClassNotFoundException if the class was not found - */ - public Class findClass(String name) throws ClassNotFoundException { - - if (log.isDebugEnabled()) - log.debug(" findClass(" + name + ")"); - - // Cannot load anything from local repositories if class loader is stopped - if (!started) { - throw new ClassNotFoundException(name); - } - - // (1) Permission to define this class when using a SecurityManager - if (securityManager != null) { - int i = name.lastIndexOf('.'); - if (i >= 0) { - try { - if (log.isTraceEnabled()) - log.trace(" securityManager.checkPackageDefinition"); - securityManager.checkPackageDefinition(name.substring(0,i)); - } catch (Exception se) { - if (log.isTraceEnabled()) - log.trace(" -->Exception-->ClassNotFoundException", se); - throw new ClassNotFoundException(name, se); - } - } - } - - // Ask our superclass to locate this class, if possible - // (throws ClassNotFoundException if it is not found) - Class clazz = null; - try { - if (log.isTraceEnabled()) - log.trace(" findClassInternal(" + name + ")"); - try { - clazz = findClassInternal(name); - } catch(ClassNotFoundException cnfe) { - if (!hasExternalRepositories) { - throw cnfe; - } - } catch(AccessControlException ace) { - throw new ClassNotFoundException(name, ace); - } catch (RuntimeException e) { - if (log.isTraceEnabled()) - log.trace(" -->RuntimeException Rethrown", e); - throw e; - } - if ((clazz == null) && hasExternalRepositories) { - try { - clazz = super.findClass(name); - } catch(AccessControlException ace) { - throw new ClassNotFoundException(name, ace); - } catch (RuntimeException e) { - if (log.isTraceEnabled()) - log.trace(" -->RuntimeException Rethrown", e); - throw e; - } - } - if (clazz == null) { - if (log.isDebugEnabled()) - log.debug(" --> Returning ClassNotFoundException"); - throw new ClassNotFoundException(name); - } - } catch (ClassNotFoundException e) { - if (log.isTraceEnabled()) - log.trace(" --> Passing on ClassNotFoundException"); - throw e; - } - - // Return the class we have located - if (log.isTraceEnabled()) - log.debug(" Returning class " + clazz); - if ((log.isTraceEnabled()) && (clazz != null)) - log.debug(" Loaded by " + clazz.getClassLoader()); - return (clazz); - - } - - - /** - * Find the specified resource in our local repository, and return a - * URL refering to it, or null if this resource - * cannot be found. - * - * @param name Name of the resource to be found - */ - public URL findResource(final String name) { - - if (log.isDebugEnabled()) - log.debug(" findResource(" + name + ")"); - - URL url = null; - - ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); - if (entry == null) { - entry = findResourceInternal(name, name); - } - if (entry != null) { - url = entry.source; - } - - if ((url == null) && hasExternalRepositories) - url = super.findResource(name); - - if (log.isDebugEnabled()) { - if (url != null) - log.debug(" --> Returning '" + url.toString() + "'"); - else - log.debug(" --> Resource not found, returning null"); - } - return (url); - - } - - - /** - * Return an enumeration of URLs representing all of the - * resources with the given name. If no resources with this name are - * found, return an empty enumeration. - * - * @param name Name of the resources to be found - * - * @exception IOException if an input/output error occurs - */ - public Enumeration findResources(String name) throws IOException { - - if (log.isDebugEnabled()) - log.debug(" findResources(" + name + ")"); - - Vector result = new Vector(); - - int jarFilesLength = jarFiles.length; - int repositoriesLength = repositories.length; - - int i; - - // Looking at the repositories - for (i = 0; i < repositoriesLength; i++) { - try { - String fullPath = repositories[i] + name; - resources.lookup(fullPath); - // Note : Not getting an exception here means the resource was - // found - try { - result.addElement(getURI(new File(files[i], name))); - } catch (MalformedURLException e) { - // Ignore - } - } catch (NamingException e) { - } - } - - // Looking at the JAR files - synchronized (jarFiles) { - if (openJARs()) { - for (i = 0; i < jarFilesLength; i++) { - JarEntry jarEntry = jarFiles[i].getJarEntry(name); - if (jarEntry != null) { - try { - String jarFakeUrl = getURI(jarRealFiles[i]).toString(); - jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name; - result.addElement(new URL(jarFakeUrl)); - } catch (MalformedURLException e) { - // Ignore - } - } - } - } - } - - // Adding the results of a call to the superclass - if (hasExternalRepositories) { - - Enumeration otherResourcePaths = super.findResources(name); - - while (otherResourcePaths.hasMoreElements()) { - result.addElement(otherResourcePaths.nextElement()); - } - - } - - return result.elements(); - - } - - - /** - * Find the resource with the given name. A resource is some data - * (images, audio, text, etc.) that can be accessed by class code in a - * way that is independent of the location of the code. The name of a - * resource is a "/"-separated path name that identifies the resource. - * If the resource cannot be found, return null. - *

    - * This method searches according to the following algorithm, returning - * as soon as it finds the appropriate URL. If the resource cannot be - * found, returns null. - *

      - *
    • If the delegate property is set to true, - * call the getResource() method of the parent class - * loader, if any.
    • - *
    • Call findResource() to find this resource in our - * locally defined repositories.
    • - *
    • Call the getResource() method of the parent class - * loader, if any.
    • - *
    - * - * @param name Name of the resource to return a URL for - */ - public URL getResource(String name) { - - if (log.isDebugEnabled()) - log.debug("getResource(" + name + ")"); - URL url = null; - - // (1) Delegate to parent if requested - if (delegate) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - url = loader.getResource(name); - if (url != null) { - if (log.isDebugEnabled()) - log.debug(" --> Returning '" + url.toString() + "'"); - return (url); - } - } - - // (2) Search local repositories - url = findResource(name); - if (url != null) { - // Locating the repository for special handling in the case - // of a JAR - if (antiJARLocking) { - ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); - try { - String repository = entry.codeBase.toString(); - if ((repository.endsWith(".jar")) - && (!(name.endsWith(".class")))) { - // Copy binary content to the work directory if not present - File resourceFile = new File(loaderDir, name); - url = getURI(resourceFile); - } - } catch (Exception e) { - // Ignore - } - } - if (log.isDebugEnabled()) - log.debug(" --> Returning '" + url.toString() + "'"); - return (url); - } - - // (3) Delegate to parent unconditionally if not already attempted - if( !delegate ) { - ClassLoader loader = parent; - if (loader == null) - loader = system; - url = loader.getResource(name); - if (url != null) { - if (log.isDebugEnabled()) - log.debug(" --> Returning '" + url.toString() + "'"); - return (url); - } - } - - // (4) Resource was not found - if (log.isDebugEnabled()) - log.debug(" --> Resource not found, returning null"); - return (null); - - } - - - /** - * Find the resource with the given name, and return an input stream - * that can be used for reading it. The search order is as described - * for getResource(), after checking to see if the resource - * data has been previously cached. If the resource cannot be found, - * return null. - * - * @param name Name of the resource to return an input stream for - */ - public InputStream getResourceAsStream(String name) { - - if (log.isDebugEnabled()) - log.debug("getResourceAsStream(" + name + ")"); - InputStream stream = null; - - // (0) Check for a cached copy of this resource - stream = findLoadedResource(name); - if (stream != null) { - if (log.isDebugEnabled()) - log.debug(" --> Returning stream from cache"); - return (stream); - } - - // (1) Delegate to parent if requested - if (delegate) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - stream = loader.getResourceAsStream(name); - if (stream != null) { - // FIXME - cache??? - if (log.isDebugEnabled()) - log.debug(" --> Returning stream from parent"); - return (stream); - } - } - - // (2) Search local repositories - if (log.isDebugEnabled()) - log.debug(" Searching local repositories"); - URL url = findResource(name); - if (url != null) { - // FIXME - cache??? - if (log.isDebugEnabled()) - log.debug(" --> Returning stream from local"); - stream = findLoadedResource(name); - try { - if (hasExternalRepositories && (stream == null)) - stream = url.openStream(); - } catch (IOException e) { - ; // Ignore - } - if (stream != null) - return (stream); - } - - // (3) Delegate to parent unconditionally - if (!delegate) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader unconditionally " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - stream = loader.getResourceAsStream(name); - if (stream != null) { - // FIXME - cache??? - if (log.isDebugEnabled()) - log.debug(" --> Returning stream from parent"); - return (stream); - } - } - - // (4) Resource was not found - if (log.isDebugEnabled()) - log.debug(" --> Resource not found, returning null"); - return (null); - - } - - - /** - * Load the class with the specified name. This method searches for - * classes in the same manner as loadClass(String, boolean) - * with false as the second argument. - * - * @param name Name of the class to be loaded - * - * @exception ClassNotFoundException if the class was not found - */ - public Class loadClass(String name) throws ClassNotFoundException { - - return (loadClass(name, false)); - - } - - - /** - * Load the class with the specified name, searching using the following - * algorithm until it finds and returns the class. If the class cannot - * be found, returns ClassNotFoundException. - *
      - *
    • Call findLoadedClass(String) to check if the - * class has already been loaded. If it has, the same - * Class object is returned.
    • - *
    • If the delegate property is set to true, - * call the loadClass() method of the parent class - * loader, if any.
    • - *
    • Call findClass() to find this class in our locally - * defined repositories.
    • - *
    • Call the loadClass() method of our parent - * class loader, if any.
    • - *
    - * If the class was found using the above steps, and the - * resolve flag is true, this method will then - * call resolveClass(Class) on the resulting Class object. - * - * @param name Name of the class to be loaded - * @param resolve If true then resolve the class - * - * @exception ClassNotFoundException if the class was not found - */ - public Class loadClass(String name, boolean resolve) - throws ClassNotFoundException { - - if (log.isDebugEnabled()) - log.debug("loadClass(" + name + ", " + resolve + ")"); - Class clazz = null; - - // Log access to stopped classloader - if (!started) { - try { - throw new IllegalStateException(); - } catch (IllegalStateException e) { - log.info(sm.getString("webappClassLoader.stopped", name), e); - } - } - - // (0) Check our previously loaded local class cache - clazz = findLoadedClass0(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Returning class from cache"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - - // (0.1) Check our previously loaded class cache - clazz = findLoadedClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Returning class from cache"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - - // (0.2) Try loading the class with the system class loader, to prevent - // the webapp from overriding J2SE classes - try { - clazz = system.loadClass(name); - if (clazz != null) { - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - // Ignore - } - - // (0.5) Permission to access this class when using a SecurityManager - if (securityManager != null) { - int i = name.lastIndexOf('.'); - if (i >= 0) { - try { - securityManager.checkPackageAccess(name.substring(0,i)); - } catch (SecurityException se) { - String error = "Security Violation, attempt to use " + - "Restricted Class: " + name; - log.info(error, se); - throw new ClassNotFoundException(error, se); - } - } - } - - boolean delegateLoad = delegate || filter(name); - - // (1) Delegate to our parent if requested - if (delegateLoad) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader1 " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - try { - clazz = loader.loadClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Loading class from parent"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - ; - } - } - - // (2) Search local repositories - if (log.isDebugEnabled()) - log.debug(" Searching local repositories"); - try { - clazz = findClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Loading class from local repository"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - ; - } - - // (3) Delegate to parent unconditionally - if (!delegateLoad) { - if (log.isDebugEnabled()) - log.debug(" Delegating to parent classloader at end: " + parent); - ClassLoader loader = parent; - if (loader == null) - loader = system; - try { - clazz = loader.loadClass(name); - if (clazz != null) { - if (log.isDebugEnabled()) - log.debug(" Loading class from parent"); - if (resolve) - resolveClass(clazz); - return (clazz); - } - } catch (ClassNotFoundException e) { - ; - } - } - - throw new ClassNotFoundException(name); - } - - - /** - * Get the Permissions for a CodeSource. If this instance - * of WebappClassLoader is for a web application context, - * add read FilePermission or JndiPermissions for the base - * directory (if unpacked), - * the context URL, and jar file resources. - * - * @param codeSource where the code was loaded from - * @return PermissionCollection for CodeSource - */ - protected PermissionCollection getPermissions(CodeSource codeSource) { - - String codeUrl = codeSource.getLocation().toString(); - PermissionCollection pc; - if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) { - pc = super.getPermissions(codeSource); - if (pc != null) { - Iterator perms = permissionList.iterator(); - while (perms.hasNext()) { - Permission p = (Permission)perms.next(); - pc.add(p); - } - loaderPC.put(codeUrl,pc); - } - } - return (pc); - - } - - - /** - * Returns the search path of URLs for loading classes and resources. - * This includes the original list of URLs specified to the constructor, - * along with any URLs subsequently appended by the addURL() method. - * @return the search path of URLs for loading classes and resources. - */ - public URL[] getURLs() { - - if (repositoryURLs != null) { - return repositoryURLs; - } - - URL[] external = super.getURLs(); - - int filesLength = files.length; - int jarFilesLength = jarRealFiles.length; - int length = filesLength + jarFilesLength + external.length; - int i; - - try { - - URL[] urls = new URL[length]; - for (i = 0; i < length; i++) { - if (i < filesLength) { - urls[i] = getURL(files[i], true); - } else if (i < filesLength + jarFilesLength) { - urls[i] = getURL(jarRealFiles[i - filesLength], true); - } else { - urls[i] = external[i - filesLength - jarFilesLength]; - } - } - - repositoryURLs = urls; - - } catch (MalformedURLException e) { - repositoryURLs = new URL[0]; - } - - return repositoryURLs; - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - return new LifecycleListener[0]; - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - } - - - /** - * Start the class loader. - * - * @exception LifecycleException if a lifecycle error occurs - */ - public void start() throws LifecycleException { - - started = true; - String encoding = null; - try { - encoding = System.getProperty("file.encoding"); - } catch (Exception e) { - return; - } - if (encoding.indexOf("EBCDIC")!=-1) { - needConvert = true; - } - - } - - - /** - * Stop the class loader. - * - * @exception LifecycleException if a lifecycle error occurs - */ - public void stop() throws LifecycleException { - - // Clearing references should be done before setting started to - // false, due to possible side effects - clearReferences(); - - started = false; - - int length = files.length; - for (int i = 0; i < length; i++) { - files[i] = null; - } - - length = jarFiles.length; - for (int i = 0; i < length; i++) { - try { - if (jarFiles[i] != null) { - jarFiles[i].close(); - } - } catch (IOException e) { - // Ignore - } - jarFiles[i] = null; - } - - notFoundResources.clear(); - resourceEntries.clear(); - resources = null; - repositories = null; - repositoryURLs = null; - files = null; - jarFiles = null; - jarRealFiles = null; - jarPath = null; - jarNames = null; - lastModifiedDates = null; - paths = null; - hasExternalRepositories = false; - parent = null; - - permissionList.clear(); - loaderPC.clear(); - - if (loaderDir != null) { - deleteDir(loaderDir); - } - - } - - - /** - * Used to periodically signal to the classloader to release - * JAR resources. - */ - public void closeJARs(boolean force) { - if (jarFiles.length > 0) { - synchronized (jarFiles) { - if (force || (System.currentTimeMillis() - > (lastJarAccessed + 90000))) { - for (int i = 0; i < jarFiles.length; i++) { - try { - if (jarFiles[i] != null) { - jarFiles[i].close(); - jarFiles[i] = null; - } - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Failed to close JAR", e); - } - } - } - } - } - } - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Clear references. - */ - protected void clearReferences() { - - // Unregister any JDBC drivers loaded by this classloader - Enumeration drivers = DriverManager.getDrivers(); - while (drivers.hasMoreElements()) { - Driver driver = (Driver) drivers.nextElement(); - if (driver.getClass().getClassLoader() == this) { - try { - DriverManager.deregisterDriver(driver); - } catch (SQLException e) { - log.warn("SQL driver deregistration failed", e); - } - } - } - - // Null out any static or final fields from loaded classes, - // as a workaround for apparent garbage collection bugs - Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator(); - while (loadedClasses.hasNext()) { - ResourceEntry entry = (ResourceEntry) loadedClasses.next(); - if (entry.loadedClass != null) { - Class clazz = entry.loadedClass; - try { - Field[] fields = clazz.getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - int mods = field.getModifiers(); - if (field.getType().isPrimitive() - || (field.getName().indexOf("$") != -1)) { - continue; - } - if (Modifier.isStatic(mods)) { - try { - field.setAccessible(true); - if (Modifier.isFinal(mods)) { - if (!((field.getType().getName().startsWith("java.")) - || (field.getType().getName().startsWith("javax.")))) { - nullInstance(field.get(null)); - } - } else { - field.set(null, null); - if (log.isDebugEnabled()) { - log.debug("Set field " + field.getName() - + " to null in class " + clazz.getName()); - } - } - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug("Could not set field " + field.getName() - + " to null in class " + clazz.getName(), t); - } - } - } - } - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug("Could not clean fields for class " + clazz.getName(), t); - } - } - } - } - - // Clear the IntrospectionUtils cache. - IntrospectionUtils.clear(); - - // Clear the classloader reference in common-logging - org.apache.commons.logging.LogFactory.release(this); - - // Clear the classloader reference in the VM's bean introspector - java.beans.Introspector.flushCaches(); - - } - - - protected void nullInstance(Object instance) { - if (instance == null) { - return; - } - Field[] fields = instance.getClass().getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - Field field = fields[i]; - int mods = field.getModifiers(); - if (field.getType().isPrimitive() - || (field.getName().indexOf("$") != -1)) { - continue; - } - try { - field.setAccessible(true); - if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) { - // Doing something recursively is too risky - continue; - } else { - Object value = field.get(instance); - if (null != value) { - Class valueClass = value.getClass(); - if (!loadedByThisOrChild(valueClass)) { - if (log.isDebugEnabled()) { - log.debug("Not setting field " + field.getName() + - " to null in object of class " + - instance.getClass().getName() + - " because the referenced object was of type " + - valueClass.getName() + - " which was not loaded by this WebappClassLoader."); - } - } else { - field.set(instance, null); - if (log.isDebugEnabled()) { - log.debug("Set field " + field.getName() - + " to null in class " + instance.getClass().getName()); - } - } - } - } - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug("Could not set field " + field.getName() - + " to null in object instance of class " - + instance.getClass().getName(), t); - } - } - } - } - - - /** - * Determine whether a class was loaded by this class loader or one of - * its child class loaders. - */ - protected boolean loadedByThisOrChild(Class clazz) - { - boolean result = false; - for (ClassLoader classLoader = clazz.getClassLoader(); - null != classLoader; classLoader = classLoader.getParent()) { - if (classLoader.equals(this)) { - result = true; - break; - } - } - return result; - } - - - /** - * Used to periodically signal to the classloader to release JAR resources. - */ - protected boolean openJARs() { - if (started && (jarFiles.length > 0)) { - lastJarAccessed = System.currentTimeMillis(); - if (jarFiles[0] == null) { - for (int i = 0; i < jarFiles.length; i++) { - try { - jarFiles[i] = new JarFile(jarRealFiles[i]); - } catch (IOException e) { - if (log.isDebugEnabled()) { - log.debug("Failed to open JAR", e); - } - return false; - } - } - } - } - return true; - } - - - /** - * Find specified class in local repositories. - * - * @return the loaded class, or null if the class isn't found - */ - protected Class findClassInternal(String name) - throws ClassNotFoundException { - - if (!validate(name)) - throw new ClassNotFoundException(name); - - String tempPath = name.replace('.', '/'); - String classPath = tempPath + ".class"; - - ResourceEntry entry = null; - - entry = findResourceInternal(name, classPath); - - if (entry == null) - throw new ClassNotFoundException(name); - - Class clazz = entry.loadedClass; - if (clazz != null) - return clazz; - - synchronized (this) { - if (entry.binaryContent == null && entry.loadedClass == null) - throw new ClassNotFoundException(name); - } - - // Looking up the package - String packageName = null; - int pos = name.lastIndexOf('.'); - if (pos != -1) - packageName = name.substring(0, pos); - - Package pkg = null; - - if (packageName != null) { - - pkg = getPackage(packageName); - - // Define the package (if null) - if (pkg == null) { - if (entry.manifest == null) { - definePackage(packageName, null, null, null, null, null, - null, null); - } else { - definePackage(packageName, entry.manifest, entry.codeBase); - } - } - - } - - // Create the code source object - CodeSource codeSource = - new CodeSource(entry.codeBase, entry.certificates); - - if (securityManager != null) { - - // Checking sealing - if (pkg != null) { - boolean sealCheck = true; - if (pkg.isSealed()) { - sealCheck = pkg.isSealed(entry.codeBase); - } else { - sealCheck = (entry.manifest == null) - || !isPackageSealed(packageName, entry.manifest); - } - if (!sealCheck) - throw new SecurityException - ("Sealing violation loading " + name + " : Package " - + packageName + " is sealed."); - } - - } - - synchronized (this) { - if (entry.loadedClass == null) { - clazz = defineClass(name, entry.binaryContent, 0, - entry.binaryContent.length, - codeSource); - entry.loadedClass = clazz; - entry.binaryContent = null; - entry.source = null; - entry.codeBase = null; - entry.manifest = null; - entry.certificates = null; - } else { - clazz = entry.loadedClass; - } - } - - return clazz; - - } - - /** - * Find specified resource in local repositories. This block - * will execute under an AccessControl.doPrivilege block. - * - * @return the loaded resource, or null if the resource isn't found - */ - protected ResourceEntry findResourceInternal(File file, String path){ - ResourceEntry entry = new ResourceEntry(); - try { - entry.source = getURI(new File(file, path)); - entry.codeBase = getURL(new File(file, path), false); - } catch (MalformedURLException e) { - return null; - } - return entry; - } - - - /** - * Find specified resource in local repositories. - * - * @return the loaded resource, or null if the resource isn't found - */ - protected ResourceEntry findResourceInternal(String name, String path) { - - if (!started) { - log.info(sm.getString("webappClassLoader.stopped", name)); - return null; - } - - if ((name == null) || (path == null)) - return null; - - ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); - if (entry != null) - return entry; - - int contentLength = -1; - InputStream binaryStream = null; - - int jarFilesLength = jarFiles.length; - int repositoriesLength = repositories.length; - - int i; - - Resource resource = null; - - boolean fileNeedConvert = false; - - for (i = 0; (entry == null) && (i < repositoriesLength); i++) { - try { - - String fullPath = repositories[i] + path; - - Object lookupResult = resources.lookup(fullPath); - if (lookupResult instanceof Resource) { - resource = (Resource) lookupResult; - } - - // Note : Not getting an exception here means the resource was - // found - if (securityManager != null) { - PrivilegedAction dp = - new PrivilegedFindResource(files[i], path); - entry = (ResourceEntry)AccessController.doPrivileged(dp); - } else { - entry = findResourceInternal(files[i], path); - } - - ResourceAttributes attributes = - (ResourceAttributes) resources.getAttributes(fullPath); - contentLength = (int) attributes.getContentLength(); - entry.lastModified = attributes.getLastModified(); - - if (resource != null) { - - - try { - binaryStream = resource.streamContent(); - } catch (IOException e) { - return null; - } - - if (needConvert) { - if (path.endsWith(".properties")) { - fileNeedConvert = true; - } - } - - // Register the full path for modification checking - // Note: Only syncing on a 'constant' object is needed - synchronized (allPermission) { - - int j; - - long[] result2 = - new long[lastModifiedDates.length + 1]; - for (j = 0; j < lastModifiedDates.length; j++) { - result2[j] = lastModifiedDates[j]; - } - result2[lastModifiedDates.length] = entry.lastModified; - lastModifiedDates = result2; - - String[] result = new String[paths.length + 1]; - for (j = 0; j < paths.length; j++) { - result[j] = paths[j]; - } - result[paths.length] = fullPath; - paths = result; - - } - - } - - } catch (NamingException e) { - } - } - - if ((entry == null) && (notFoundResources.containsKey(name))) - return null; - - JarEntry jarEntry = null; - - synchronized (jarFiles) { - - if (!openJARs()) { - return null; - } - for (i = 0; (entry == null) && (i < jarFilesLength); i++) { - - jarEntry = jarFiles[i].getJarEntry(path); - - if (jarEntry != null) { - - entry = new ResourceEntry(); - try { - entry.codeBase = getURL(jarRealFiles[i], false); - String jarFakeUrl = getURI(jarRealFiles[i]).toString(); - jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path; - entry.source = new URL(jarFakeUrl); - entry.lastModified = jarRealFiles[i].lastModified(); - } catch (MalformedURLException e) { - return null; - } - contentLength = (int) jarEntry.getSize(); - try { - entry.manifest = jarFiles[i].getManifest(); - binaryStream = jarFiles[i].getInputStream(jarEntry); - } catch (IOException e) { - return null; - } - - // Extract resources contained in JAR to the workdir - if (antiJARLocking && !(path.endsWith(".class"))) { - byte[] buf = new byte[1024]; - File resourceFile = new File - (loaderDir, jarEntry.getName()); - if (!resourceFile.exists()) { - Enumeration entries = jarFiles[i].entries(); - while (entries.hasMoreElements()) { - JarEntry jarEntry2 = - (JarEntry) entries.nextElement(); - if (!(jarEntry2.isDirectory()) - && (!jarEntry2.getName().endsWith - (".class"))) { - resourceFile = new File - (loaderDir, jarEntry2.getName()); - resourceFile.getParentFile().mkdirs(); - FileOutputStream os = null; - InputStream is = null; - try { - is = jarFiles[i].getInputStream - (jarEntry2); - os = new FileOutputStream - (resourceFile); - while (true) { - int n = is.read(buf); - if (n <= 0) { - break; - } - os.write(buf, 0, n); - } - } catch (IOException e) { - // Ignore - } finally { - try { - if (is != null) { - is.close(); - } - } catch (IOException e) { - } - try { - if (os != null) { - os.close(); - } - } catch (IOException e) { - } - } - } - } - } - } - - } - - } - - if (entry == null) { - synchronized (notFoundResources) { - notFoundResources.put(name, name); - } - return null; - } - - if (binaryStream != null) { - - byte[] binaryContent = new byte[contentLength]; - - int pos = 0; - try { - - while (true) { - int n = binaryStream.read(binaryContent, pos, - binaryContent.length - pos); - if (n <= 0) - break; - pos += n; - } - binaryStream.close(); - } catch (IOException e) { - e.printStackTrace(); - return null; - } catch (Exception e) { - e.printStackTrace(); - return null; - } - - if (fileNeedConvert) { - String str = new String(binaryContent,0,pos); - try { - binaryContent = str.getBytes("UTF-8"); - } catch (Exception e) { - return null; - } - } - entry.binaryContent = binaryContent; - - // The certificates are only available after the JarEntry - // associated input stream has been fully read - if (jarEntry != null) { - entry.certificates = jarEntry.getCertificates(); - } - - } - - } - - // Add the entry in the local resource repository - synchronized (resourceEntries) { - // Ensures that all the threads which may be in a race to load - // a particular class all end up with the same ResourceEntry - // instance - ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name); - if (entry2 == null) { - resourceEntries.put(name, entry); - } else { - entry = entry2; - } - } - - return entry; - - } - - - /** - * Returns true if the specified package name is sealed according to the - * given manifest. - */ - protected boolean isPackageSealed(String name, Manifest man) { - - String path = name.replace('.', '/') + '/'; - Attributes attr = man.getAttributes(path); - String sealed = null; - if (attr != null) { - sealed = attr.getValue(Name.SEALED); - } - if (sealed == null) { - if ((attr = man.getMainAttributes()) != null) { - sealed = attr.getValue(Name.SEALED); - } - } - return "true".equalsIgnoreCase(sealed); - - } - - - /** - * Finds the resource with the given name if it has previously been - * loaded and cached by this class loader, and return an input stream - * to the resource data. If this resource has not been cached, return - * null. - * - * @param name Name of the resource to return - */ - protected InputStream findLoadedResource(String name) { - - ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); - if (entry != null) { - if (entry.binaryContent != null) - return new ByteArrayInputStream(entry.binaryContent); - } - return (null); - - } - - - /** - * Finds the class with the given name if it has previously been - * loaded and cached by this class loader, and return the Class object. - * If this class has not been cached, return null. - * - * @param name Name of the resource to return - */ - protected Class findLoadedClass0(String name) { - - ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); - if (entry != null) { - return entry.loadedClass; - } - return (null); // FIXME - findLoadedResource() - - } - - - /** - * Refresh the system policy file, to pick up eventual changes. - */ - protected void refreshPolicy() { - - try { - // The policy file may have been modified to adjust - // permissions, so we're reloading it when loading or - // reloading a Context - Policy policy = Policy.getPolicy(); - policy.refresh(); - } catch (AccessControlException e) { - // Some policy files may restrict this, even for the core, - // so this exception is ignored - } - - } - - - /** - * Filter classes. - * - * @param name class name - * @return true if the class should be filtered - */ - protected boolean filter(String name) { - - if (name == null) - return false; - - // Looking up the package - String packageName = null; - int pos = name.lastIndexOf('.'); - if (pos != -1) - packageName = name.substring(0, pos); - else - return false; - - for (int i = 0; i < packageTriggers.length; i++) { - if (packageName.startsWith(packageTriggers[i])) - return true; - } - - return false; - - } - - - /** - * Validate a classname. As per SRV.9.7.2, we must restict loading of - * classes from J2SE (java.*) and classes of the servlet API - * (javax.servlet.*). That should enhance robustness and prevent a number - * of user error (where an older version of servlet.jar would be present - * in /WEB-INF/lib). - * - * @param name class name - * @return true if the name is valid - */ - protected boolean validate(String name) { - - if (name == null) - return false; - if (name.startsWith("java.")) - return false; - - return true; - - } - - - /** - * Check the specified JAR file, and return true if it does - * not contain any of the trigger classes. - * - * @param jarfile The JAR file to be checked - * - * @exception IOException if an input/output error occurs - */ - protected boolean validateJarFile(File jarfile) - throws IOException { - - if (triggers == null) - return (true); - JarFile jarFile = new JarFile(jarfile); - for (int i = 0; i < triggers.length; i++) { - Class clazz = null; - try { - if (parent != null) { - clazz = parent.loadClass(triggers[i]); - } else { - clazz = Class.forName(triggers[i]); - } - } catch (Throwable t) { - clazz = null; - } - if (clazz == null) - continue; - String name = triggers[i].replace('.', '/') + ".class"; - if (log.isDebugEnabled()) - log.debug(" Checking for " + name); - JarEntry jarEntry = jarFile.getJarEntry(name); - if (jarEntry != null) { - log.info("validateJarFile(" + jarfile + - ") - jar not loaded. See Servlet Spec 2.3, " - + "section 9.7.2. Offending class: " + name); - jarFile.close(); - return (false); - } - } - jarFile.close(); - return (true); - - } - - - /** - * Get URL. - */ - protected URL getURL(File file, boolean encoded) - throws MalformedURLException { - - File realFile = file; - try { - realFile = realFile.getCanonicalFile(); - } catch (IOException e) { - // Ignore - } - if(encoded) { - return getURI(realFile); - } else { - return realFile.toURL(); - } - - } - - - /** - * Get URL. - */ - protected URL getURI(File file) - throws MalformedURLException { - - - File realFile = file; - try { - realFile = realFile.getCanonicalFile(); - } catch (IOException e) { - // Ignore - } - return realFile.toURI().toURL(); - - } - - - /** - * Delete the specified directory, including all of its contents and - * subdirectories recursively. - * - * @param dir File object representing the directory to be deleted - */ - protected static void deleteDir(File dir) { - - String files[] = dir.list(); - if (files == null) { - files = new String[0]; - } - for (int i = 0; i < files.length; i++) { - File file = new File(dir, files[i]); - if (file.isDirectory()) { - deleteDir(file); - } else { - file.delete(); - } - } - dir.delete(); - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.AccessControlException; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.PrivilegedAction; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Vector; +import java.util.jar.Attributes; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.Manifest; +import java.util.jar.Attributes.Name; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.util.StringManager; +import org.apache.naming.JndiPermission; +import org.apache.naming.resources.Resource; +import org.apache.naming.resources.ResourceAttributes; +import org.apache.tomcat.util.IntrospectionUtils; + +/** + * Specialized web application class loader. + *

    + * This class loader is a full reimplementation of the + * URLClassLoader from the JDK. It is desinged to be fully + * compatible with a normal URLClassLoader, although its internal + * behavior may be completely different. + *

    + * IMPLEMENTATION NOTE - This class loader faithfully follows + * the delegation model recommended in the specification. The system class + * loader will be queried first, then the local repositories, and only then + * delegation to the parent class loader will occur. This allows the web + * application to override any shared class except the classes from J2SE. + * Special handling is provided from the JAXP XML parser interfaces, the JNDI + * interfaces, and the classes from the servlet API, which are never loaded + * from the webapp repository. + *

    + * IMPLEMENTATION NOTE - Due to limitations in Jasper + * compilation technology, any repository which contains classes from + * the servlet API will be ignored by the class loader. + *

    + * IMPLEMENTATION NOTE - The class loader generates source + * URLs which include the full JAR URL when a class is loaded from a JAR file, + * which allows setting security permission at the class level, even when a + * class is contained inside a JAR. + *

    + * IMPLEMENTATION NOTE - Local repositories are searched in + * the order they are added via the initial constructor and/or any subsequent + * calls to addRepository() or addJar(). + *

    + * IMPLEMENTATION NOTE - No check for sealing violations or + * security is made unless a security manager is present. + * + * @author Remy Maucherat + * @author Craig R. McClanahan + * @version $Revision$ $Date: 2006-05-19 19:52:46 -0700 (Fri, 19 May 2006) $ + */ +public class WebappClassLoader + extends URLClassLoader + implements Reloader, Lifecycle + { + + protected static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( WebappClassLoader.class ); + + protected class PrivilegedFindResource + implements PrivilegedAction { + + protected File file; + protected String path; + + PrivilegedFindResource(File file, String path) { + this.file = file; + this.path = path; + } + + public Object run() { + return findResourceInternal(file, path); + } + + } + + + // ------------------------------------------------------- Static Variables + + + /** + * The set of trigger classes that will cause a proposed repository not + * to be added if this class is visible to the class loader that loaded + * this factory class. Typically, trigger classes will be listed for + * components that have been integrated into the JDK for later versions, + * but where the corresponding JAR files are required to run on + * earlier versions. + */ + protected static final String[] triggers = { + "javax.servlet.Servlet" // Servlet API + }; + + + /** + * Set of package names which are not allowed to be loaded from a webapp + * class loader without delegating first. + */ + protected static final String[] packageTriggers = { + }; + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Use anti JAR locking code, which does URL rerouting when accessing + * resources. + */ + boolean antiJARLocking = false; + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new ClassLoader with no defined repositories and no + * parent ClassLoader. + */ + public WebappClassLoader() { + + super(new URL[0]); + this.parent = getParent(); + system = getSystemClassLoader(); + securityManager = System.getSecurityManager(); + + if (securityManager != null) { + refreshPolicy(); + } + + } + + + /** + * Construct a new ClassLoader with no defined repositories and no + * parent ClassLoader. + */ + public WebappClassLoader(ClassLoader parent) { + + super(new URL[0], parent); + + this.parent = getParent(); + + system = getSystemClassLoader(); + securityManager = System.getSecurityManager(); + + if (securityManager != null) { + refreshPolicy(); + } + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated directory context giving access to the resources in this + * webapp. + */ + protected DirContext resources = null; + + + /** + * The cache of ResourceEntry for classes and resources we have loaded, + * keyed by resource name. + */ + protected HashMap resourceEntries = new HashMap(); + + + /** + * The list of not found resources. + */ + protected HashMap notFoundResources = new HashMap(); + + + /** + * Should this class loader delegate to the parent class loader + * before searching its own repositories (i.e. the + * usual Java2 delegation model)? If set to false, + * this class loader will search its own repositories first, and + * delegate to the parent only if the class or resource is not + * found locally. + */ + protected boolean delegate = false; + + + /** + * Last time a JAR was accessed. + */ + protected long lastJarAccessed = 0L; + + + /** + * The list of local repositories, in the order they should be searched + * for locally loaded classes or resources. + */ + protected String[] repositories = new String[0]; + + + /** + * Repositories URLs, used to cache the result of getURLs. + */ + protected URL[] repositoryURLs = null; + + + /** + * Repositories translated as path in the work directory (for Jasper + * originally), but which is used to generate fake URLs should getURLs be + * called. + */ + protected File[] files = new File[0]; + + + /** + * The list of JARs, in the order they should be searched + * for locally loaded classes or resources. + */ + protected JarFile[] jarFiles = new JarFile[0]; + + + /** + * The list of JARs, in the order they should be searched + * for locally loaded classes or resources. + */ + protected File[] jarRealFiles = new File[0]; + + + /** + * The path which will be monitored for added Jar files. + */ + protected String jarPath = null; + + + /** + * The list of JARs, in the order they should be searched + * for locally loaded classes or resources. + */ + protected String[] jarNames = new String[0]; + + + /** + * The list of JARs last modified dates, in the order they should be + * searched for locally loaded classes or resources. + */ + protected long[] lastModifiedDates = new long[0]; + + + /** + * The list of resources which should be checked when checking for + * modifications. + */ + protected String[] paths = new String[0]; + + + /** + * A list of read File and Jndi Permission's required if this loader + * is for a web application context. + */ + protected ArrayList permissionList = new ArrayList(); + + + /** + * Path where resources loaded from JARs will be extracted. + */ + protected File loaderDir = null; + + + /** + * The PermissionCollection for each CodeSource for a web + * application context. + */ + protected HashMap loaderPC = new HashMap(); + + + /** + * Instance of the SecurityManager installed. + */ + protected SecurityManager securityManager = null; + + + /** + * The parent class loader. + */ + protected ClassLoader parent = null; + + + /** + * The system class loader. + */ + protected ClassLoader system = null; + + + /** + * Has this component been started? + */ + protected boolean started = false; + + + /** + * Has external repositories. + */ + protected boolean hasExternalRepositories = false; + + /** + * need conversion for properties files + */ + protected boolean needConvert = false; + + + /** + * All permission. + */ + protected Permission allPermission = new java.security.AllPermission(); + + + // ------------------------------------------------------------- Properties + + + /** + * Get associated resources. + */ + public DirContext getResources() { + + return this.resources; + + } + + + /** + * Set associated resources. + */ + public void setResources(DirContext resources) { + + this.resources = resources; + + } + + + /** + * Return the "delegate first" flag for this class loader. + */ + public boolean getDelegate() { + + return (this.delegate); + + } + + + /** + * Set the "delegate first" flag for this class loader. + * + * @param delegate The new "delegate first" flag + */ + public void setDelegate(boolean delegate) { + + this.delegate = delegate; + + } + + + /** + * @return Returns the antiJARLocking. + */ + public boolean getAntiJARLocking() { + return antiJARLocking; + } + + + /** + * @param antiJARLocking The antiJARLocking to set. + */ + public void setAntiJARLocking(boolean antiJARLocking) { + this.antiJARLocking = antiJARLocking; + } + + + /** + * If there is a Java SecurityManager create a read FilePermission + * or JndiPermission for the file directory path. + * + * @param path file directory path + */ + public void addPermission(String path) { + if (path == null) { + return; + } + + if (securityManager != null) { + Permission permission = null; + if( path.startsWith("jndi:") || path.startsWith("jar:jndi:") ) { + if (!path.endsWith("/")) { + path = path + "/"; + } + permission = new JndiPermission(path + "*"); + addPermission(permission); + } else { + if (!path.endsWith(File.separator)) { + permission = new FilePermission(path, "read"); + addPermission(permission); + path = path + File.separator; + } + permission = new FilePermission(path + "-", "read"); + addPermission(permission); + } + } + } + + + /** + * If there is a Java SecurityManager create a read FilePermission + * or JndiPermission for URL. + * + * @param url URL for a file or directory on local system + */ + public void addPermission(URL url) { + if (url != null) { + addPermission(url.toString()); + } + } + + + /** + * If there is a Java SecurityManager create a Permission. + * + * @param permission The permission + */ + public void addPermission(Permission permission) { + if ((securityManager != null) && (permission != null)) { + permissionList.add(permission); + } + } + + + /** + * Return the JAR path. + */ + public String getJarPath() { + + return this.jarPath; + + } + + + /** + * Change the Jar path. + */ + public void setJarPath(String jarPath) { + + this.jarPath = jarPath; + + } + + + /** + * Change the work directory. + */ + public void setWorkDir(File workDir) { + this.loaderDir = new File(workDir, "loader"); + } + + /** + * Utility method for use in subclasses. + * Must be called before Lifecycle methods to have any effect. + */ + protected void setParentClassLoader(ClassLoader pcl) { + parent = pcl; + } + + // ------------------------------------------------------- Reloader Methods + + + /** + * Add a new repository to the set of places this ClassLoader can look for + * classes to be loaded. + * + * @param repository Name of a source of classes to be loaded, such as a + * directory pathname, a JAR file pathname, or a ZIP file pathname + * + * @exception IllegalArgumentException if the specified repository is + * invalid or does not exist + */ + public void addRepository(String repository) { + + // Ignore any of the standard repositories, as they are set up using + // either addJar or addRepository + if (repository.startsWith("/WEB-INF/lib") + || repository.startsWith("/WEB-INF/classes")) + return; + + // Add this repository to our underlying class loader + try { + URL url = new URL(repository); + super.addURL(url); + hasExternalRepositories = true; + repositoryURLs = null; + } catch (MalformedURLException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Invalid repository: " + repository); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Add a new repository to the set of places this ClassLoader can look for + * classes to be loaded. + * + * @param repository Name of a source of classes to be loaded, such as a + * directory pathname, a JAR file pathname, or a ZIP file pathname + * + * @exception IllegalArgumentException if the specified repository is + * invalid or does not exist + */ + synchronized void addRepository(String repository, File file) { + + // Note : There should be only one (of course), but I think we should + // keep this a bit generic + + if (repository == null) + return; + + if (log.isDebugEnabled()) + log.debug("addRepository(" + repository + ")"); + + int i; + + // Add this repository to our internal list + String[] result = new String[repositories.length + 1]; + for (i = 0; i < repositories.length; i++) { + result[i] = repositories[i]; + } + result[repositories.length] = repository; + repositories = result; + + // Add the file to the list + File[] result2 = new File[files.length + 1]; + for (i = 0; i < files.length; i++) { + result2[i] = files[i]; + } + result2[files.length] = file; + files = result2; + + } + + + synchronized void addJar(String jar, JarFile jarFile, File file) + throws IOException { + + if (jar == null) + return; + if (jarFile == null) + return; + if (file == null) + return; + + if (log.isDebugEnabled()) + log.debug("addJar(" + jar + ")"); + + int i; + + if ((jarPath != null) && (jar.startsWith(jarPath))) { + + String jarName = jar.substring(jarPath.length()); + while (jarName.startsWith("/")) + jarName = jarName.substring(1); + + String[] result = new String[jarNames.length + 1]; + for (i = 0; i < jarNames.length; i++) { + result[i] = jarNames[i]; + } + result[jarNames.length] = jarName; + jarNames = result; + + } + + try { + + // Register the JAR for tracking + + long lastModified = + ((ResourceAttributes) resources.getAttributes(jar)) + .getLastModified(); + + String[] result = new String[paths.length + 1]; + for (i = 0; i < paths.length; i++) { + result[i] = paths[i]; + } + result[paths.length] = jar; + paths = result; + + long[] result3 = new long[lastModifiedDates.length + 1]; + for (i = 0; i < lastModifiedDates.length; i++) { + result3[i] = lastModifiedDates[i]; + } + result3[lastModifiedDates.length] = lastModified; + lastModifiedDates = result3; + + } catch (NamingException e) { + // Ignore + } + + // If the JAR currently contains invalid classes, don't actually use it + // for classloading + if (!validateJarFile(file)) + return; + + JarFile[] result2 = new JarFile[jarFiles.length + 1]; + for (i = 0; i < jarFiles.length; i++) { + result2[i] = jarFiles[i]; + } + result2[jarFiles.length] = jarFile; + jarFiles = result2; + + // Add the file to the list + File[] result4 = new File[jarRealFiles.length + 1]; + for (i = 0; i < jarRealFiles.length; i++) { + result4[i] = jarRealFiles[i]; + } + result4[jarRealFiles.length] = file; + jarRealFiles = result4; + } + + + /** + * Return a String array of the current repositories for this class + * loader. If there are no repositories, a zero-length array is + * returned.For security reason, returns a clone of the Array (since + * String are immutable). + */ + public String[] findRepositories() { + + return ((String[])repositories.clone()); + + } + + + /** + * Have one or more classes or resources been modified so that a reload + * is appropriate? + */ + public boolean modified() { + + if (log.isDebugEnabled()) + log.debug("modified()"); + + // Checking for modified loaded resources + int length = paths.length; + + // A rare race condition can occur in the updates of the two arrays + // It's totally ok if the latest class added is not checked (it will + // be checked the next time + int length2 = lastModifiedDates.length; + if (length > length2) + length = length2; + + for (int i = 0; i < length; i++) { + try { + long lastModified = + ((ResourceAttributes) resources.getAttributes(paths[i])) + .getLastModified(); + if (lastModified != lastModifiedDates[i]) { + if( log.isDebugEnabled() ) + log.debug(" Resource '" + paths[i] + + "' was modified; Date is now: " + + new java.util.Date(lastModified) + " Was: " + + new java.util.Date(lastModifiedDates[i])); + return (true); + } + } catch (NamingException e) { + log.error(" Resource '" + paths[i] + "' is missing"); + return (true); + } + } + + length = jarNames.length; + + // Check if JARs have been added or removed + if (getJarPath() != null) { + + try { + NamingEnumeration enumeration = resources.listBindings(getJarPath()); + int i = 0; + while (enumeration.hasMoreElements() && (i < length)) { + NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); + String name = ncPair.getName(); + // Ignore non JARs present in the lib folder + if (!name.endsWith(".jar")) + continue; + if (!name.equals(jarNames[i])) { + // Missing JAR + log.info(" Additional JARs have been added : '" + + name + "'"); + return (true); + } + i++; + } + if (enumeration.hasMoreElements()) { + while (enumeration.hasMoreElements()) { + NameClassPair ncPair = + (NameClassPair) enumeration.nextElement(); + String name = ncPair.getName(); + // Additional non-JAR files are allowed + if (name.endsWith(".jar")) { + // There was more JARs + log.info(" Additional JARs have been added"); + return (true); + } + } + } else if (i < jarNames.length) { + // There was less JARs + log.info(" Additional JARs have been added"); + return (true); + } + } catch (NamingException e) { + if (log.isDebugEnabled()) + log.debug(" Failed tracking modifications of '" + + getJarPath() + "'"); + } catch (ClassCastException e) { + log.error(" Failed tracking modifications of '" + + getJarPath() + "' : " + e.getMessage()); + } + + } + + // No classes have been modified + return (false); + + } + + + /** + * Render a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("WebappClassLoader\r\n"); + sb.append(" delegate: "); + sb.append(delegate); + sb.append("\r\n"); + sb.append(" repositories:\r\n"); + if (repositories != null) { + for (int i = 0; i < repositories.length; i++) { + sb.append(" "); + sb.append(repositories[i]); + sb.append("\r\n"); + } + } + if (this.parent != null) { + sb.append("----------> Parent Classloader:\r\n"); + sb.append(this.parent.toString()); + sb.append("\r\n"); + } + return (sb.toString()); + + } + + + // ---------------------------------------------------- ClassLoader Methods + + + /** + * Add the specified URL to the classloader. + */ + protected void addURL(URL url) { + super.addURL(url); + hasExternalRepositories = true; + repositoryURLs = null; + } + + + /** + * Find the specified class in our local repositories, if possible. If + * not found, throw ClassNotFoundException. + * + * @param name Name of the class to be loaded + * + * @exception ClassNotFoundException if the class was not found + */ + public Class findClass(String name) throws ClassNotFoundException { + + if (log.isDebugEnabled()) + log.debug(" findClass(" + name + ")"); + + // Cannot load anything from local repositories if class loader is stopped + if (!started) { + throw new ClassNotFoundException(name); + } + + // (1) Permission to define this class when using a SecurityManager + if (securityManager != null) { + int i = name.lastIndexOf('.'); + if (i >= 0) { + try { + if (log.isTraceEnabled()) + log.trace(" securityManager.checkPackageDefinition"); + securityManager.checkPackageDefinition(name.substring(0,i)); + } catch (Exception se) { + if (log.isTraceEnabled()) + log.trace(" -->Exception-->ClassNotFoundException", se); + throw new ClassNotFoundException(name, se); + } + } + } + + // Ask our superclass to locate this class, if possible + // (throws ClassNotFoundException if it is not found) + Class clazz = null; + try { + if (log.isTraceEnabled()) + log.trace(" findClassInternal(" + name + ")"); + try { + clazz = findClassInternal(name); + } catch(ClassNotFoundException cnfe) { + if (!hasExternalRepositories) { + throw cnfe; + } + } catch(AccessControlException ace) { + throw new ClassNotFoundException(name, ace); + } catch (RuntimeException e) { + if (log.isTraceEnabled()) + log.trace(" -->RuntimeException Rethrown", e); + throw e; + } + if ((clazz == null) && hasExternalRepositories) { + try { + clazz = super.findClass(name); + } catch(AccessControlException ace) { + throw new ClassNotFoundException(name, ace); + } catch (RuntimeException e) { + if (log.isTraceEnabled()) + log.trace(" -->RuntimeException Rethrown", e); + throw e; + } + } + if (clazz == null) { + if (log.isDebugEnabled()) + log.debug(" --> Returning ClassNotFoundException"); + throw new ClassNotFoundException(name); + } + } catch (ClassNotFoundException e) { + if (log.isTraceEnabled()) + log.trace(" --> Passing on ClassNotFoundException"); + throw e; + } + + // Return the class we have located + if (log.isTraceEnabled()) + log.debug(" Returning class " + clazz); + if ((log.isTraceEnabled()) && (clazz != null)) + log.debug(" Loaded by " + clazz.getClassLoader()); + return (clazz); + + } + + + /** + * Find the specified resource in our local repository, and return a + * URL refering to it, or null if this resource + * cannot be found. + * + * @param name Name of the resource to be found + */ + public URL findResource(final String name) { + + if (log.isDebugEnabled()) + log.debug(" findResource(" + name + ")"); + + URL url = null; + + ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); + if (entry == null) { + entry = findResourceInternal(name, name); + } + if (entry != null) { + url = entry.source; + } + + if ((url == null) && hasExternalRepositories) + url = super.findResource(name); + + if (log.isDebugEnabled()) { + if (url != null) + log.debug(" --> Returning '" + url.toString() + "'"); + else + log.debug(" --> Resource not found, returning null"); + } + return (url); + + } + + + /** + * Return an enumeration of URLs representing all of the + * resources with the given name. If no resources with this name are + * found, return an empty enumeration. + * + * @param name Name of the resources to be found + * + * @exception IOException if an input/output error occurs + */ + public Enumeration findResources(String name) throws IOException { + + if (log.isDebugEnabled()) + log.debug(" findResources(" + name + ")"); + + Vector result = new Vector(); + + int jarFilesLength = jarFiles.length; + int repositoriesLength = repositories.length; + + int i; + + // Looking at the repositories + for (i = 0; i < repositoriesLength; i++) { + try { + String fullPath = repositories[i] + name; + resources.lookup(fullPath); + // Note : Not getting an exception here means the resource was + // found + try { + result.addElement(getURI(new File(files[i], name))); + } catch (MalformedURLException e) { + // Ignore + } + } catch (NamingException e) { + } + } + + // Looking at the JAR files + synchronized (jarFiles) { + if (openJARs()) { + for (i = 0; i < jarFilesLength; i++) { + JarEntry jarEntry = jarFiles[i].getJarEntry(name); + if (jarEntry != null) { + try { + String jarFakeUrl = getURI(jarRealFiles[i]).toString(); + jarFakeUrl = "jar:" + jarFakeUrl + "!/" + name; + result.addElement(new URL(jarFakeUrl)); + } catch (MalformedURLException e) { + // Ignore + } + } + } + } + } + + // Adding the results of a call to the superclass + if (hasExternalRepositories) { + + Enumeration otherResourcePaths = super.findResources(name); + + while (otherResourcePaths.hasMoreElements()) { + result.addElement(otherResourcePaths.nextElement()); + } + + } + + return result.elements(); + + } + + + /** + * Find the resource with the given name. A resource is some data + * (images, audio, text, etc.) that can be accessed by class code in a + * way that is independent of the location of the code. The name of a + * resource is a "/"-separated path name that identifies the resource. + * If the resource cannot be found, return null. + *

    + * This method searches according to the following algorithm, returning + * as soon as it finds the appropriate URL. If the resource cannot be + * found, returns null. + *

      + *
    • If the delegate property is set to true, + * call the getResource() method of the parent class + * loader, if any.
    • + *
    • Call findResource() to find this resource in our + * locally defined repositories.
    • + *
    • Call the getResource() method of the parent class + * loader, if any.
    • + *
    + * + * @param name Name of the resource to return a URL for + */ + public URL getResource(String name) { + + if (log.isDebugEnabled()) + log.debug("getResource(" + name + ")"); + URL url = null; + + // (1) Delegate to parent if requested + if (delegate) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; + url = loader.getResource(name); + if (url != null) { + if (log.isDebugEnabled()) + log.debug(" --> Returning '" + url.toString() + "'"); + return (url); + } + } + + // (2) Search local repositories + url = findResource(name); + if (url != null) { + // Locating the repository for special handling in the case + // of a JAR + if (antiJARLocking) { + ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); + try { + String repository = entry.codeBase.toString(); + if ((repository.endsWith(".jar")) + && (!(name.endsWith(".class")))) { + // Copy binary content to the work directory if not present + File resourceFile = new File(loaderDir, name); + url = getURI(resourceFile); + } + } catch (Exception e) { + // Ignore + } + } + if (log.isDebugEnabled()) + log.debug(" --> Returning '" + url.toString() + "'"); + return (url); + } + + // (3) Delegate to parent unconditionally if not already attempted + if( !delegate ) { + ClassLoader loader = parent; + if (loader == null) + loader = system; + url = loader.getResource(name); + if (url != null) { + if (log.isDebugEnabled()) + log.debug(" --> Returning '" + url.toString() + "'"); + return (url); + } + } + + // (4) Resource was not found + if (log.isDebugEnabled()) + log.debug(" --> Resource not found, returning null"); + return (null); + + } + + + /** + * Find the resource with the given name, and return an input stream + * that can be used for reading it. The search order is as described + * for getResource(), after checking to see if the resource + * data has been previously cached. If the resource cannot be found, + * return null. + * + * @param name Name of the resource to return an input stream for + */ + public InputStream getResourceAsStream(String name) { + + if (log.isDebugEnabled()) + log.debug("getResourceAsStream(" + name + ")"); + InputStream stream = null; + + // (0) Check for a cached copy of this resource + stream = findLoadedResource(name); + if (stream != null) { + if (log.isDebugEnabled()) + log.debug(" --> Returning stream from cache"); + return (stream); + } + + // (1) Delegate to parent if requested + if (delegate) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; + stream = loader.getResourceAsStream(name); + if (stream != null) { + // FIXME - cache??? + if (log.isDebugEnabled()) + log.debug(" --> Returning stream from parent"); + return (stream); + } + } + + // (2) Search local repositories + if (log.isDebugEnabled()) + log.debug(" Searching local repositories"); + URL url = findResource(name); + if (url != null) { + // FIXME - cache??? + if (log.isDebugEnabled()) + log.debug(" --> Returning stream from local"); + stream = findLoadedResource(name); + try { + if (hasExternalRepositories && (stream == null)) + stream = url.openStream(); + } catch (IOException e) { + ; // Ignore + } + if (stream != null) + return (stream); + } + + // (3) Delegate to parent unconditionally + if (!delegate) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader unconditionally " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; + stream = loader.getResourceAsStream(name); + if (stream != null) { + // FIXME - cache??? + if (log.isDebugEnabled()) + log.debug(" --> Returning stream from parent"); + return (stream); + } + } + + // (4) Resource was not found + if (log.isDebugEnabled()) + log.debug(" --> Resource not found, returning null"); + return (null); + + } + + + /** + * Load the class with the specified name. This method searches for + * classes in the same manner as loadClass(String, boolean) + * with false as the second argument. + * + * @param name Name of the class to be loaded + * + * @exception ClassNotFoundException if the class was not found + */ + public Class loadClass(String name) throws ClassNotFoundException { + + return (loadClass(name, false)); + + } + + + /** + * Load the class with the specified name, searching using the following + * algorithm until it finds and returns the class. If the class cannot + * be found, returns ClassNotFoundException. + *
      + *
    • Call findLoadedClass(String) to check if the + * class has already been loaded. If it has, the same + * Class object is returned.
    • + *
    • If the delegate property is set to true, + * call the loadClass() method of the parent class + * loader, if any.
    • + *
    • Call findClass() to find this class in our locally + * defined repositories.
    • + *
    • Call the loadClass() method of our parent + * class loader, if any.
    • + *
    + * If the class was found using the above steps, and the + * resolve flag is true, this method will then + * call resolveClass(Class) on the resulting Class object. + * + * @param name Name of the class to be loaded + * @param resolve If true then resolve the class + * + * @exception ClassNotFoundException if the class was not found + */ + public Class loadClass(String name, boolean resolve) + throws ClassNotFoundException { + + if (log.isDebugEnabled()) + log.debug("loadClass(" + name + ", " + resolve + ")"); + Class clazz = null; + + // Log access to stopped classloader + if (!started) { + try { + throw new IllegalStateException(); + } catch (IllegalStateException e) { + log.info(sm.getString("webappClassLoader.stopped", name), e); + } + } + + // (0) Check our previously loaded local class cache + clazz = findLoadedClass0(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Returning class from cache"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + + // (0.1) Check our previously loaded class cache + clazz = findLoadedClass(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Returning class from cache"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + + // (0.2) Try loading the class with the system class loader, to prevent + // the webapp from overriding J2SE classes + try { + clazz = system.loadClass(name); + if (clazz != null) { + if (resolve) + resolveClass(clazz); + return (clazz); + } + } catch (ClassNotFoundException e) { + // Ignore + } + + // (0.5) Permission to access this class when using a SecurityManager + if (securityManager != null) { + int i = name.lastIndexOf('.'); + if (i >= 0) { + try { + securityManager.checkPackageAccess(name.substring(0,i)); + } catch (SecurityException se) { + String error = "Security Violation, attempt to use " + + "Restricted Class: " + name; + log.info(error, se); + throw new ClassNotFoundException(error, se); + } + } + } + + boolean delegateLoad = delegate || filter(name); + + // (1) Delegate to our parent if requested + if (delegateLoad) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader1 " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; + try { + clazz = loader.loadClass(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Loading class from parent"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + } catch (ClassNotFoundException e) { + ; + } + } + + // (2) Search local repositories + if (log.isDebugEnabled()) + log.debug(" Searching local repositories"); + try { + clazz = findClass(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Loading class from local repository"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + } catch (ClassNotFoundException e) { + ; + } + + // (3) Delegate to parent unconditionally + if (!delegateLoad) { + if (log.isDebugEnabled()) + log.debug(" Delegating to parent classloader at end: " + parent); + ClassLoader loader = parent; + if (loader == null) + loader = system; + try { + clazz = loader.loadClass(name); + if (clazz != null) { + if (log.isDebugEnabled()) + log.debug(" Loading class from parent"); + if (resolve) + resolveClass(clazz); + return (clazz); + } + } catch (ClassNotFoundException e) { + ; + } + } + + throw new ClassNotFoundException(name); + } + + + /** + * Get the Permissions for a CodeSource. If this instance + * of WebappClassLoader is for a web application context, + * add read FilePermission or JndiPermissions for the base + * directory (if unpacked), + * the context URL, and jar file resources. + * + * @param codeSource where the code was loaded from + * @return PermissionCollection for CodeSource + */ + protected PermissionCollection getPermissions(CodeSource codeSource) { + + String codeUrl = codeSource.getLocation().toString(); + PermissionCollection pc; + if ((pc = (PermissionCollection)loaderPC.get(codeUrl)) == null) { + pc = super.getPermissions(codeSource); + if (pc != null) { + Iterator perms = permissionList.iterator(); + while (perms.hasNext()) { + Permission p = (Permission)perms.next(); + pc.add(p); + } + loaderPC.put(codeUrl,pc); + } + } + return (pc); + + } + + + /** + * Returns the search path of URLs for loading classes and resources. + * This includes the original list of URLs specified to the constructor, + * along with any URLs subsequently appended by the addURL() method. + * @return the search path of URLs for loading classes and resources. + */ + public URL[] getURLs() { + + if (repositoryURLs != null) { + return repositoryURLs; + } + + URL[] external = super.getURLs(); + + int filesLength = files.length; + int jarFilesLength = jarRealFiles.length; + int length = filesLength + jarFilesLength + external.length; + int i; + + try { + + URL[] urls = new URL[length]; + for (i = 0; i < length; i++) { + if (i < filesLength) { + urls[i] = getURL(files[i], true); + } else if (i < filesLength + jarFilesLength) { + urls[i] = getURL(jarRealFiles[i - filesLength], true); + } else { + urls[i] = external[i - filesLength - jarFilesLength]; + } + } + + repositoryURLs = urls; + + } catch (MalformedURLException e) { + repositoryURLs = new URL[0]; + } + + return repositoryURLs; + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + return new LifecycleListener[0]; + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + } + + + /** + * Start the class loader. + * + * @exception LifecycleException if a lifecycle error occurs + */ + public void start() throws LifecycleException { + + started = true; + String encoding = null; + try { + encoding = System.getProperty("file.encoding"); + } catch (Exception e) { + return; + } + if (encoding.indexOf("EBCDIC")!=-1) { + needConvert = true; + } + + } + + + /** + * Stop the class loader. + * + * @exception LifecycleException if a lifecycle error occurs + */ + public void stop() throws LifecycleException { + + // Clearing references should be done before setting started to + // false, due to possible side effects + clearReferences(); + + started = false; + + int length = files.length; + for (int i = 0; i < length; i++) { + files[i] = null; + } + + length = jarFiles.length; + for (int i = 0; i < length; i++) { + try { + if (jarFiles[i] != null) { + jarFiles[i].close(); + } + } catch (IOException e) { + // Ignore + } + jarFiles[i] = null; + } + + notFoundResources.clear(); + resourceEntries.clear(); + resources = null; + repositories = null; + repositoryURLs = null; + files = null; + jarFiles = null; + jarRealFiles = null; + jarPath = null; + jarNames = null; + lastModifiedDates = null; + paths = null; + hasExternalRepositories = false; + parent = null; + + permissionList.clear(); + loaderPC.clear(); + + if (loaderDir != null) { + deleteDir(loaderDir); + } + + } + + + /** + * Used to periodically signal to the classloader to release + * JAR resources. + */ + public void closeJARs(boolean force) { + if (jarFiles.length > 0) { + synchronized (jarFiles) { + if (force || (System.currentTimeMillis() + > (lastJarAccessed + 90000))) { + for (int i = 0; i < jarFiles.length; i++) { + try { + if (jarFiles[i] != null) { + jarFiles[i].close(); + jarFiles[i] = null; + } + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed to close JAR", e); + } + } + } + } + } + } + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Clear references. + */ + protected void clearReferences() { + + // Unregister any JDBC drivers loaded by this classloader + Enumeration drivers = DriverManager.getDrivers(); + while (drivers.hasMoreElements()) { + Driver driver = (Driver) drivers.nextElement(); + if (driver.getClass().getClassLoader() == this) { + try { + DriverManager.deregisterDriver(driver); + } catch (SQLException e) { + log.warn("SQL driver deregistration failed", e); + } + } + } + + // Null out any static or final fields from loaded classes, + // as a workaround for apparent garbage collection bugs + Iterator loadedClasses = ((HashMap) resourceEntries.clone()).values().iterator(); + while (loadedClasses.hasNext()) { + ResourceEntry entry = (ResourceEntry) loadedClasses.next(); + if (entry.loadedClass != null) { + Class clazz = entry.loadedClass; + try { + Field[] fields = clazz.getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + int mods = field.getModifiers(); + if (field.getType().isPrimitive() + || (field.getName().indexOf("$") != -1)) { + continue; + } + if (Modifier.isStatic(mods)) { + try { + field.setAccessible(true); + if (Modifier.isFinal(mods)) { + if (!((field.getType().getName().startsWith("java.")) + || (field.getType().getName().startsWith("javax.")))) { + nullInstance(field.get(null)); + } + } else { + field.set(null, null); + if (log.isDebugEnabled()) { + log.debug("Set field " + field.getName() + + " to null in class " + clazz.getName()); + } + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Could not set field " + field.getName() + + " to null in class " + clazz.getName(), t); + } + } + } + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Could not clean fields for class " + clazz.getName(), t); + } + } + } + } + + // Clear the IntrospectionUtils cache. + IntrospectionUtils.clear(); + + // Clear the classloader reference in common-logging + org.apache.commons.logging.LogFactory.release(this); + + // Clear the classloader reference in the VM's bean introspector + java.beans.Introspector.flushCaches(); + + } + + + protected void nullInstance(Object instance) { + if (instance == null) { + return; + } + Field[] fields = instance.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + Field field = fields[i]; + int mods = field.getModifiers(); + if (field.getType().isPrimitive() + || (field.getName().indexOf("$") != -1)) { + continue; + } + try { + field.setAccessible(true); + if (Modifier.isStatic(mods) && Modifier.isFinal(mods)) { + // Doing something recursively is too risky + continue; + } else { + Object value = field.get(instance); + if (null != value) { + Class valueClass = value.getClass(); + if (!loadedByThisOrChild(valueClass)) { + if (log.isDebugEnabled()) { + log.debug("Not setting field " + field.getName() + + " to null in object of class " + + instance.getClass().getName() + + " because the referenced object was of type " + + valueClass.getName() + + " which was not loaded by this WebappClassLoader."); + } + } else { + field.set(instance, null); + if (log.isDebugEnabled()) { + log.debug("Set field " + field.getName() + + " to null in class " + instance.getClass().getName()); + } + } + } + } + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug("Could not set field " + field.getName() + + " to null in object instance of class " + + instance.getClass().getName(), t); + } + } + } + } + + + /** + * Determine whether a class was loaded by this class loader or one of + * its child class loaders. + */ + protected boolean loadedByThisOrChild(Class clazz) + { + boolean result = false; + for (ClassLoader classLoader = clazz.getClassLoader(); + null != classLoader; classLoader = classLoader.getParent()) { + if (classLoader.equals(this)) { + result = true; + break; + } + } + return result; + } + + + /** + * Used to periodically signal to the classloader to release JAR resources. + */ + protected boolean openJARs() { + if (started && (jarFiles.length > 0)) { + lastJarAccessed = System.currentTimeMillis(); + if (jarFiles[0] == null) { + for (int i = 0; i < jarFiles.length; i++) { + try { + jarFiles[i] = new JarFile(jarRealFiles[i]); + } catch (IOException e) { + if (log.isDebugEnabled()) { + log.debug("Failed to open JAR", e); + } + return false; + } + } + } + } + return true; + } + + + /** + * Find specified class in local repositories. + * + * @return the loaded class, or null if the class isn't found + */ + protected Class findClassInternal(String name) + throws ClassNotFoundException { + + if (!validate(name)) + throw new ClassNotFoundException(name); + + String tempPath = name.replace('.', '/'); + String classPath = tempPath + ".class"; + + ResourceEntry entry = null; + + entry = findResourceInternal(name, classPath); + + if (entry == null) + throw new ClassNotFoundException(name); + + Class clazz = entry.loadedClass; + if (clazz != null) + return clazz; + + synchronized (this) { + if (entry.binaryContent == null && entry.loadedClass == null) + throw new ClassNotFoundException(name); + } + + // Looking up the package + String packageName = null; + int pos = name.lastIndexOf('.'); + if (pos != -1) + packageName = name.substring(0, pos); + + Package pkg = null; + + if (packageName != null) { + + pkg = getPackage(packageName); + + // Define the package (if null) + if (pkg == null) { + if (entry.manifest == null) { + definePackage(packageName, null, null, null, null, null, + null, null); + } else { + definePackage(packageName, entry.manifest, entry.codeBase); + } + } + + } + + // Create the code source object + CodeSource codeSource = + new CodeSource(entry.codeBase, entry.certificates); + + if (securityManager != null) { + + // Checking sealing + if (pkg != null) { + boolean sealCheck = true; + if (pkg.isSealed()) { + sealCheck = pkg.isSealed(entry.codeBase); + } else { + sealCheck = (entry.manifest == null) + || !isPackageSealed(packageName, entry.manifest); + } + if (!sealCheck) + throw new SecurityException + ("Sealing violation loading " + name + " : Package " + + packageName + " is sealed."); + } + + } + + synchronized (this) { + if (entry.loadedClass == null) { + clazz = defineClass(name, entry.binaryContent, 0, + entry.binaryContent.length, + codeSource); + entry.loadedClass = clazz; + entry.binaryContent = null; + entry.source = null; + entry.codeBase = null; + entry.manifest = null; + entry.certificates = null; + } else { + clazz = entry.loadedClass; + } + } + + return clazz; + + } + + /** + * Find specified resource in local repositories. This block + * will execute under an AccessControl.doPrivilege block. + * + * @return the loaded resource, or null if the resource isn't found + */ + protected ResourceEntry findResourceInternal(File file, String path){ + ResourceEntry entry = new ResourceEntry(); + try { + entry.source = getURI(new File(file, path)); + entry.codeBase = getURL(new File(file, path), false); + } catch (MalformedURLException e) { + return null; + } + return entry; + } + + + /** + * Find specified resource in local repositories. + * + * @return the loaded resource, or null if the resource isn't found + */ + protected ResourceEntry findResourceInternal(String name, String path) { + + if (!started) { + log.info(sm.getString("webappClassLoader.stopped", name)); + return null; + } + + if ((name == null) || (path == null)) + return null; + + ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); + if (entry != null) + return entry; + + int contentLength = -1; + InputStream binaryStream = null; + + int jarFilesLength = jarFiles.length; + int repositoriesLength = repositories.length; + + int i; + + Resource resource = null; + + boolean fileNeedConvert = false; + + for (i = 0; (entry == null) && (i < repositoriesLength); i++) { + try { + + String fullPath = repositories[i] + path; + + Object lookupResult = resources.lookup(fullPath); + if (lookupResult instanceof Resource) { + resource = (Resource) lookupResult; + } + + // Note : Not getting an exception here means the resource was + // found + if (securityManager != null) { + PrivilegedAction dp = + new PrivilegedFindResource(files[i], path); + entry = (ResourceEntry)AccessController.doPrivileged(dp); + } else { + entry = findResourceInternal(files[i], path); + } + + ResourceAttributes attributes = + (ResourceAttributes) resources.getAttributes(fullPath); + contentLength = (int) attributes.getContentLength(); + entry.lastModified = attributes.getLastModified(); + + if (resource != null) { + + + try { + binaryStream = resource.streamContent(); + } catch (IOException e) { + return null; + } + + if (needConvert) { + if (path.endsWith(".properties")) { + fileNeedConvert = true; + } + } + + // Register the full path for modification checking + // Note: Only syncing on a 'constant' object is needed + synchronized (allPermission) { + + int j; + + long[] result2 = + new long[lastModifiedDates.length + 1]; + for (j = 0; j < lastModifiedDates.length; j++) { + result2[j] = lastModifiedDates[j]; + } + result2[lastModifiedDates.length] = entry.lastModified; + lastModifiedDates = result2; + + String[] result = new String[paths.length + 1]; + for (j = 0; j < paths.length; j++) { + result[j] = paths[j]; + } + result[paths.length] = fullPath; + paths = result; + + } + + } + + } catch (NamingException e) { + } + } + + if ((entry == null) && (notFoundResources.containsKey(name))) + return null; + + JarEntry jarEntry = null; + + synchronized (jarFiles) { + + if (!openJARs()) { + return null; + } + for (i = 0; (entry == null) && (i < jarFilesLength); i++) { + + jarEntry = jarFiles[i].getJarEntry(path); + + if (jarEntry != null) { + + entry = new ResourceEntry(); + try { + entry.codeBase = getURL(jarRealFiles[i], false); + String jarFakeUrl = getURI(jarRealFiles[i]).toString(); + jarFakeUrl = "jar:" + jarFakeUrl + "!/" + path; + entry.source = new URL(jarFakeUrl); + entry.lastModified = jarRealFiles[i].lastModified(); + } catch (MalformedURLException e) { + return null; + } + contentLength = (int) jarEntry.getSize(); + try { + entry.manifest = jarFiles[i].getManifest(); + binaryStream = jarFiles[i].getInputStream(jarEntry); + } catch (IOException e) { + return null; + } + + // Extract resources contained in JAR to the workdir + if (antiJARLocking && !(path.endsWith(".class"))) { + byte[] buf = new byte[1024]; + File resourceFile = new File + (loaderDir, jarEntry.getName()); + if (!resourceFile.exists()) { + Enumeration entries = jarFiles[i].entries(); + while (entries.hasMoreElements()) { + JarEntry jarEntry2 = + (JarEntry) entries.nextElement(); + if (!(jarEntry2.isDirectory()) + && (!jarEntry2.getName().endsWith + (".class"))) { + resourceFile = new File + (loaderDir, jarEntry2.getName()); + resourceFile.getParentFile().mkdirs(); + FileOutputStream os = null; + InputStream is = null; + try { + is = jarFiles[i].getInputStream + (jarEntry2); + os = new FileOutputStream + (resourceFile); + while (true) { + int n = is.read(buf); + if (n <= 0) { + break; + } + os.write(buf, 0, n); + } + } catch (IOException e) { + // Ignore + } finally { + try { + if (is != null) { + is.close(); + } + } catch (IOException e) { + } + try { + if (os != null) { + os.close(); + } + } catch (IOException e) { + } + } + } + } + } + } + + } + + } + + if (entry == null) { + synchronized (notFoundResources) { + notFoundResources.put(name, name); + } + return null; + } + + if (binaryStream != null) { + + byte[] binaryContent = new byte[contentLength]; + + int pos = 0; + try { + + while (true) { + int n = binaryStream.read(binaryContent, pos, + binaryContent.length - pos); + if (n <= 0) + break; + pos += n; + } + binaryStream.close(); + } catch (IOException e) { + e.printStackTrace(); + return null; + } catch (Exception e) { + e.printStackTrace(); + return null; + } + + if (fileNeedConvert) { + String str = new String(binaryContent,0,pos); + try { + binaryContent = str.getBytes("UTF-8"); + } catch (Exception e) { + return null; + } + } + entry.binaryContent = binaryContent; + + // The certificates are only available after the JarEntry + // associated input stream has been fully read + if (jarEntry != null) { + entry.certificates = jarEntry.getCertificates(); + } + + } + + } + + // Add the entry in the local resource repository + synchronized (resourceEntries) { + // Ensures that all the threads which may be in a race to load + // a particular class all end up with the same ResourceEntry + // instance + ResourceEntry entry2 = (ResourceEntry) resourceEntries.get(name); + if (entry2 == null) { + resourceEntries.put(name, entry); + } else { + entry = entry2; + } + } + + return entry; + + } + + + /** + * Returns true if the specified package name is sealed according to the + * given manifest. + */ + protected boolean isPackageSealed(String name, Manifest man) { + + String path = name.replace('.', '/') + '/'; + Attributes attr = man.getAttributes(path); + String sealed = null; + if (attr != null) { + sealed = attr.getValue(Name.SEALED); + } + if (sealed == null) { + if ((attr = man.getMainAttributes()) != null) { + sealed = attr.getValue(Name.SEALED); + } + } + return "true".equalsIgnoreCase(sealed); + + } + + + /** + * Finds the resource with the given name if it has previously been + * loaded and cached by this class loader, and return an input stream + * to the resource data. If this resource has not been cached, return + * null. + * + * @param name Name of the resource to return + */ + protected InputStream findLoadedResource(String name) { + + ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); + if (entry != null) { + if (entry.binaryContent != null) + return new ByteArrayInputStream(entry.binaryContent); + } + return (null); + + } + + + /** + * Finds the class with the given name if it has previously been + * loaded and cached by this class loader, and return the Class object. + * If this class has not been cached, return null. + * + * @param name Name of the resource to return + */ + protected Class findLoadedClass0(String name) { + + ResourceEntry entry = (ResourceEntry) resourceEntries.get(name); + if (entry != null) { + return entry.loadedClass; + } + return (null); // FIXME - findLoadedResource() + + } + + + /** + * Refresh the system policy file, to pick up eventual changes. + */ + protected void refreshPolicy() { + + try { + // The policy file may have been modified to adjust + // permissions, so we're reloading it when loading or + // reloading a Context + Policy policy = Policy.getPolicy(); + policy.refresh(); + } catch (AccessControlException e) { + // Some policy files may restrict this, even for the core, + // so this exception is ignored + } + + } + + + /** + * Filter classes. + * + * @param name class name + * @return true if the class should be filtered + */ + protected boolean filter(String name) { + + if (name == null) + return false; + + // Looking up the package + String packageName = null; + int pos = name.lastIndexOf('.'); + if (pos != -1) + packageName = name.substring(0, pos); + else + return false; + + for (int i = 0; i < packageTriggers.length; i++) { + if (packageName.startsWith(packageTriggers[i])) + return true; + } + + return false; + + } + + + /** + * Validate a classname. As per SRV.9.7.2, we must restict loading of + * classes from J2SE (java.*) and classes of the servlet API + * (javax.servlet.*). That should enhance robustness and prevent a number + * of user error (where an older version of servlet.jar would be present + * in /WEB-INF/lib). + * + * @param name class name + * @return true if the name is valid + */ + protected boolean validate(String name) { + + if (name == null) + return false; + if (name.startsWith("java.")) + return false; + + return true; + + } + + + /** + * Check the specified JAR file, and return true if it does + * not contain any of the trigger classes. + * + * @param jarfile The JAR file to be checked + * + * @exception IOException if an input/output error occurs + */ + protected boolean validateJarFile(File jarfile) + throws IOException { + + if (triggers == null) + return (true); + JarFile jarFile = new JarFile(jarfile); + for (int i = 0; i < triggers.length; i++) { + Class clazz = null; + try { + if (parent != null) { + clazz = parent.loadClass(triggers[i]); + } else { + clazz = Class.forName(triggers[i]); + } + } catch (Throwable t) { + clazz = null; + } + if (clazz == null) + continue; + String name = triggers[i].replace('.', '/') + ".class"; + if (log.isDebugEnabled()) + log.debug(" Checking for " + name); + JarEntry jarEntry = jarFile.getJarEntry(name); + if (jarEntry != null) { + log.info("validateJarFile(" + jarfile + + ") - jar not loaded. See Servlet Spec 2.3, " + + "section 9.7.2. Offending class: " + name); + jarFile.close(); + return (false); + } + } + jarFile.close(); + return (true); + + } + + + /** + * Get URL. + */ + protected URL getURL(File file, boolean encoded) + throws MalformedURLException { + + File realFile = file; + try { + realFile = realFile.getCanonicalFile(); + } catch (IOException e) { + // Ignore + } + if(encoded) { + return getURI(realFile); + } else { + return realFile.toURL(); + } + + } + + + /** + * Get URL. + */ + protected URL getURI(File file) + throws MalformedURLException { + + + File realFile = file; + try { + realFile = realFile.getCanonicalFile(); + } catch (IOException e) { + // Ignore + } + return realFile.toURI().toURL(); + + } + + + /** + * Delete the specified directory, including all of its contents and + * subdirectories recursively. + * + * @param dir File object representing the directory to be deleted + */ + protected static void deleteDir(File dir) { + + String files[] = dir.list(); + if (files == null) { + files = new String[0]; + } + for (int i = 0; i < files.length; i++) { + File file = new File(dir, files[i]); + if (file.isDirectory()) { + deleteDir(file); + } else { + file.delete(); + } + } + dir.delete(); + + } + + +} + diff --git a/java/org/apache/catalina/loader/WebappLoader.java b/java/org/apache/catalina/loader/WebappLoader.java index 7d9bf3b4b..10f4f69e0 100644 --- a/java/org/apache/catalina/loader/WebappLoader.java +++ b/java/org/apache/catalina/loader/WebappLoader.java @@ -1,1227 +1,1227 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.loader; - - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.File; -import java.io.FileOutputStream; -import java.io.FilePermission; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLStreamHandlerFactory; -import java.util.ArrayList; -import java.util.jar.JarFile; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.naming.Binding; -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.ServletContext; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Globals; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.naming.resources.DirContextURLStreamHandler; -import org.apache.naming.resources.DirContextURLStreamHandlerFactory; -import org.apache.naming.resources.Resource; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Classloader implementation which is specialized for handling web - * applications in the most efficient way, while being Catalina aware (all - * accesses to resources are made through the DirContext interface). - * This class loader supports detection of modified - * Java classes, which can be used to implement auto-reload support. - *

    - * This class loader is configured by adding the pathnames of directories, - * JAR files, and ZIP files with the addRepository() method, - * prior to calling start(). When a new class is required, - * these repositories will be consulted first to locate the class. If it - * is not present, the system class loader will be used instead. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ - */ - -public class WebappLoader - implements Lifecycle, Loader, PropertyChangeListener, MBeanRegistration { - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new WebappLoader with no defined parent class loader - * (so that the actual parent will be the system class loader). - */ - public WebappLoader() { - - this(null); - - } - - - /** - * Construct a new WebappLoader with the specified class loader - * to be defined as the parent of the ClassLoader we ultimately create. - * - * @param parent The parent class loader - */ - public WebappLoader(ClassLoader parent) { - super(); - this.parentClassLoader = parent; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * First load of the class. - */ - private static boolean first = true; - - - /** - * The class loader being managed by this Loader component. - */ - private WebappClassLoader classLoader = null; - - - /** - * The Container with which this Loader has been associated. - */ - private Container container = null; - - - /** - * The "follow standard delegation model" flag that will be used to - * configure our ClassLoader. - */ - private boolean delegate = false; - - - /** - * The descriptive information about this Loader implementation. - */ - private static final String info = - "org.apache.catalina.loader.WebappLoader/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The Java class name of the ClassLoader implementation to be used. - * This class should extend WebappClassLoader, otherwise, a different - * loader implementation must be used. - */ - private String loaderClass = - "org.apache.catalina.loader.WebappClassLoader"; - - - /** - * The parent class loader of the class loader we will create. - */ - private ClassLoader parentClassLoader = null; - - - /** - * The reloadable flag for this Loader. - */ - private boolean reloadable = false; - - - /** - * The set of repositories associated with this class loader. - */ - private String repositories[] = new String[0]; - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started? - */ - private boolean started = false; - - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - /** - * Classpath set in the loader. - */ - private String classpath = null; - - - /** - * Repositories that are set in the loader, for JMX. - */ - private ArrayList loaderRepositories = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Java class loader to be used by this Container. - */ - public ClassLoader getClassLoader() { - - return ((ClassLoader) classLoader); - - } - - - /** - * Return the Container with which this Logger has been associated. - */ - public Container getContainer() { - - return (container); - - } - - - /** - * Set the Container with which this Logger has been associated. - * - * @param container The associated Container - */ - public void setContainer(Container container) { - - // Deregister from the old Container (if any) - if ((this.container != null) && (this.container instanceof Context)) - ((Context) this.container).removePropertyChangeListener(this); - - // Process this property change - Container oldContainer = this.container; - this.container = container; - support.firePropertyChange("container", oldContainer, this.container); - - // Register with the new Container (if any) - if ((this.container != null) && (this.container instanceof Context)) { - setReloadable( ((Context) this.container).getReloadable() ); - ((Context) this.container).addPropertyChangeListener(this); - } - - } - - - /** - * Return the "follow standard delegation model" flag used to configure - * our ClassLoader. - */ - public boolean getDelegate() { - - return (this.delegate); - - } - - - /** - * Set the "follow standard delegation model" flag used to configure - * our ClassLoader. - * - * @param delegate The new flag - */ - public void setDelegate(boolean delegate) { - - boolean oldDelegate = this.delegate; - this.delegate = delegate; - support.firePropertyChange("delegate", new Boolean(oldDelegate), - new Boolean(this.delegate)); - - } - - - /** - * Return descriptive information about this Loader implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the ClassLoader class name. - */ - public String getLoaderClass() { - - return (this.loaderClass); - - } - - - /** - * Set the ClassLoader class name. - * - * @param loaderClass The new ClassLoader class name - */ - public void setLoaderClass(String loaderClass) { - - this.loaderClass = loaderClass; - - } - - - /** - * Return the reloadable flag for this Loader. - */ - public boolean getReloadable() { - - return (this.reloadable); - - } - - - /** - * Set the reloadable flag for this Loader. - * - * @param reloadable The new reloadable flag - */ - public void setReloadable(boolean reloadable) { - - // Process this property change - boolean oldReloadable = this.reloadable; - this.reloadable = reloadable; - support.firePropertyChange("reloadable", - new Boolean(oldReloadable), - new Boolean(this.reloadable)); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - - support.addPropertyChangeListener(listener); - - } - - - /** - * Add a new repository to the set of repositories for this class loader. - * - * @param repository Repository to be added - */ - public void addRepository(String repository) { - - if (log.isDebugEnabled()) - log.debug(sm.getString("webappLoader.addRepository", repository)); - - for (int i = 0; i < repositories.length; i++) { - if (repository.equals(repositories[i])) - return; - } - String results[] = new String[repositories.length + 1]; - for (int i = 0; i < repositories.length; i++) - results[i] = repositories[i]; - results[repositories.length] = repository; - repositories = results; - - if (started && (classLoader != null)) { - classLoader.addRepository(repository); - if( loaderRepositories != null ) loaderRepositories.add(repository); - setClassPath(); - } - - } - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - if (reloadable && modified()) { - try { - Thread.currentThread().setContextClassLoader - (WebappLoader.class.getClassLoader()); - if (container instanceof StandardContext) { - ((StandardContext) container).reload(); - } - } finally { - if (container.getLoader() != null) { - Thread.currentThread().setContextClassLoader - (container.getLoader().getClassLoader()); - } - } - } else { - closeJARs(false); - } - } - - - /** - * Return the set of repositories defined for this class loader. - * If none are defined, a zero-length array is returned. - * For security reason, returns a clone of the Array (since - * String are immutable). - */ - public String[] findRepositories() { - - return ((String[])repositories.clone()); - - } - - public String[] getRepositories() { - return ((String[])repositories.clone()); - } - - /** Extra repositories for this loader - */ - public String getRepositoriesString() { - StringBuffer sb=new StringBuffer(); - for( int i=0; i 0) - classpath.append(File.pathSeparator); - classpath.append(cp); - n++; - } - break; - //continue; - } - URL repositories[] = - ((URLClassLoader) loader).getURLs(); - for (int i = 0; i < repositories.length; i++) { - String repository = repositories[i].toString(); - if (repository.startsWith("file://")) - repository = repository.substring(7); - else if (repository.startsWith("file:")) - repository = repository.substring(5); - else if (repository.startsWith("jndi:")) - repository = - servletContext.getRealPath(repository.substring(5)); - else - continue; - if (repository == null) - continue; - if (n > 0) - classpath.append(File.pathSeparator); - classpath.append(repository); - n++; - } - loader = loader.getParent(); - layers++; - } - - this.classpath=classpath.toString(); - - // Store the assembled class path as a servlet context attribute - servletContext.setAttribute(Globals.CLASS_PATH_ATTR, - classpath.toString()); - - } - - // try to extract the classpath from a loader that is not URLClassLoader - private String getClasspath( ClassLoader loader ) { - try { - Method m=loader.getClass().getMethod("getClasspath", new Class[] {}); - if( log.isTraceEnabled()) - log.trace("getClasspath " + m ); - if( m==null ) return null; - Object o=m.invoke( loader, new Object[] {} ); - if( log.isDebugEnabled() ) - log.debug("gotClasspath " + o); - if( o instanceof String ) - return (String)o; - return null; - } catch( Exception ex ) { - if (log.isDebugEnabled()) - log.debug("getClasspath ", ex); - } - return null; - } - - /** - * Copy directory. - */ - private boolean copyDir(DirContext srcDir, File destDir) { - - try { - - NamingEnumeration enumeration = srcDir.list(""); - while (enumeration.hasMoreElements()) { - NameClassPair ncPair = - (NameClassPair) enumeration.nextElement(); - String name = ncPair.getName(); - Object object = srcDir.lookup(name); - File currentFile = new File(destDir, name); - if (object instanceof Resource) { - InputStream is = ((Resource) object).streamContent(); - OutputStream os = new FileOutputStream(currentFile); - if (!copy(is, os)) - return false; - } else if (object instanceof InputStream) { - OutputStream os = new FileOutputStream(currentFile); - if (!copy((InputStream) object, os)) - return false; - } else if (object instanceof DirContext) { - currentFile.mkdir(); - copyDir((DirContext) object, currentFile); - } - } - - } catch (NamingException e) { - return false; - } catch (IOException e) { - return false; - } - - return true; - - } - - - /** - * Copy a file to the specified temp directory. This is required only - * because Jasper depends on it. - */ - private boolean copy(InputStream is, OutputStream os) { - - try { - byte[] buf = new byte[4096]; - while (true) { - int len = is.read(buf); - if (len < 0) - break; - os.write(buf, 0, len); - } - is.close(); - os.close(); - } catch (IOException e) { - return false; - } - - return true; - - } - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( WebappLoader.class ); - - private ObjectName oname; - private MBeanServer mserver; - private String domain; - private ObjectName controller; - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - public ObjectName getController() { - return controller; - } - - public void setController(ObjectName controller) { - this.controller = controller; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.loader; + + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.File; +import java.io.FileOutputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLStreamHandlerFactory; +import java.util.ArrayList; +import java.util.jar.JarFile; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.naming.Binding; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.servlet.ServletContext; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Globals; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.naming.resources.DirContextURLStreamHandler; +import org.apache.naming.resources.DirContextURLStreamHandlerFactory; +import org.apache.naming.resources.Resource; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Classloader implementation which is specialized for handling web + * applications in the most efficient way, while being Catalina aware (all + * accesses to resources are made through the DirContext interface). + * This class loader supports detection of modified + * Java classes, which can be used to implement auto-reload support. + *

    + * This class loader is configured by adding the pathnames of directories, + * JAR files, and ZIP files with the addRepository() method, + * prior to calling start(). When a new class is required, + * these repositories will be consulted first to locate the class. If it + * is not present, the system class loader will be used instead. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303352 $ $Date: 2004-10-05 19:12:52 +0200 (mar., 05 oct. 2004) $ + */ + +public class WebappLoader + implements Lifecycle, Loader, PropertyChangeListener, MBeanRegistration { + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new WebappLoader with no defined parent class loader + * (so that the actual parent will be the system class loader). + */ + public WebappLoader() { + + this(null); + + } + + + /** + * Construct a new WebappLoader with the specified class loader + * to be defined as the parent of the ClassLoader we ultimately create. + * + * @param parent The parent class loader + */ + public WebappLoader(ClassLoader parent) { + super(); + this.parentClassLoader = parent; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * First load of the class. + */ + private static boolean first = true; + + + /** + * The class loader being managed by this Loader component. + */ + private WebappClassLoader classLoader = null; + + + /** + * The Container with which this Loader has been associated. + */ + private Container container = null; + + + /** + * The "follow standard delegation model" flag that will be used to + * configure our ClassLoader. + */ + private boolean delegate = false; + + + /** + * The descriptive information about this Loader implementation. + */ + private static final String info = + "org.apache.catalina.loader.WebappLoader/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The Java class name of the ClassLoader implementation to be used. + * This class should extend WebappClassLoader, otherwise, a different + * loader implementation must be used. + */ + private String loaderClass = + "org.apache.catalina.loader.WebappClassLoader"; + + + /** + * The parent class loader of the class loader we will create. + */ + private ClassLoader parentClassLoader = null; + + + /** + * The reloadable flag for this Loader. + */ + private boolean reloadable = false; + + + /** + * The set of repositories associated with this class loader. + */ + private String repositories[] = new String[0]; + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started? + */ + private boolean started = false; + + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + /** + * Classpath set in the loader. + */ + private String classpath = null; + + + /** + * Repositories that are set in the loader, for JMX. + */ + private ArrayList loaderRepositories = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Java class loader to be used by this Container. + */ + public ClassLoader getClassLoader() { + + return ((ClassLoader) classLoader); + + } + + + /** + * Return the Container with which this Logger has been associated. + */ + public Container getContainer() { + + return (container); + + } + + + /** + * Set the Container with which this Logger has been associated. + * + * @param container The associated Container + */ + public void setContainer(Container container) { + + // Deregister from the old Container (if any) + if ((this.container != null) && (this.container instanceof Context)) + ((Context) this.container).removePropertyChangeListener(this); + + // Process this property change + Container oldContainer = this.container; + this.container = container; + support.firePropertyChange("container", oldContainer, this.container); + + // Register with the new Container (if any) + if ((this.container != null) && (this.container instanceof Context)) { + setReloadable( ((Context) this.container).getReloadable() ); + ((Context) this.container).addPropertyChangeListener(this); + } + + } + + + /** + * Return the "follow standard delegation model" flag used to configure + * our ClassLoader. + */ + public boolean getDelegate() { + + return (this.delegate); + + } + + + /** + * Set the "follow standard delegation model" flag used to configure + * our ClassLoader. + * + * @param delegate The new flag + */ + public void setDelegate(boolean delegate) { + + boolean oldDelegate = this.delegate; + this.delegate = delegate; + support.firePropertyChange("delegate", new Boolean(oldDelegate), + new Boolean(this.delegate)); + + } + + + /** + * Return descriptive information about this Loader implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the ClassLoader class name. + */ + public String getLoaderClass() { + + return (this.loaderClass); + + } + + + /** + * Set the ClassLoader class name. + * + * @param loaderClass The new ClassLoader class name + */ + public void setLoaderClass(String loaderClass) { + + this.loaderClass = loaderClass; + + } + + + /** + * Return the reloadable flag for this Loader. + */ + public boolean getReloadable() { + + return (this.reloadable); + + } + + + /** + * Set the reloadable flag for this Loader. + * + * @param reloadable The new reloadable flag + */ + public void setReloadable(boolean reloadable) { + + // Process this property change + boolean oldReloadable = this.reloadable; + this.reloadable = reloadable; + support.firePropertyChange("reloadable", + new Boolean(oldReloadable), + new Boolean(this.reloadable)); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + + support.addPropertyChangeListener(listener); + + } + + + /** + * Add a new repository to the set of repositories for this class loader. + * + * @param repository Repository to be added + */ + public void addRepository(String repository) { + + if (log.isDebugEnabled()) + log.debug(sm.getString("webappLoader.addRepository", repository)); + + for (int i = 0; i < repositories.length; i++) { + if (repository.equals(repositories[i])) + return; + } + String results[] = new String[repositories.length + 1]; + for (int i = 0; i < repositories.length; i++) + results[i] = repositories[i]; + results[repositories.length] = repository; + repositories = results; + + if (started && (classLoader != null)) { + classLoader.addRepository(repository); + if( loaderRepositories != null ) loaderRepositories.add(repository); + setClassPath(); + } + + } + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + if (reloadable && modified()) { + try { + Thread.currentThread().setContextClassLoader + (WebappLoader.class.getClassLoader()); + if (container instanceof StandardContext) { + ((StandardContext) container).reload(); + } + } finally { + if (container.getLoader() != null) { + Thread.currentThread().setContextClassLoader + (container.getLoader().getClassLoader()); + } + } + } else { + closeJARs(false); + } + } + + + /** + * Return the set of repositories defined for this class loader. + * If none are defined, a zero-length array is returned. + * For security reason, returns a clone of the Array (since + * String are immutable). + */ + public String[] findRepositories() { + + return ((String[])repositories.clone()); + + } + + public String[] getRepositories() { + return ((String[])repositories.clone()); + } + + /** Extra repositories for this loader + */ + public String getRepositoriesString() { + StringBuffer sb=new StringBuffer(); + for( int i=0; i 0) + classpath.append(File.pathSeparator); + classpath.append(cp); + n++; + } + break; + //continue; + } + URL repositories[] = + ((URLClassLoader) loader).getURLs(); + for (int i = 0; i < repositories.length; i++) { + String repository = repositories[i].toString(); + if (repository.startsWith("file://")) + repository = repository.substring(7); + else if (repository.startsWith("file:")) + repository = repository.substring(5); + else if (repository.startsWith("jndi:")) + repository = + servletContext.getRealPath(repository.substring(5)); + else + continue; + if (repository == null) + continue; + if (n > 0) + classpath.append(File.pathSeparator); + classpath.append(repository); + n++; + } + loader = loader.getParent(); + layers++; + } + + this.classpath=classpath.toString(); + + // Store the assembled class path as a servlet context attribute + servletContext.setAttribute(Globals.CLASS_PATH_ATTR, + classpath.toString()); + + } + + // try to extract the classpath from a loader that is not URLClassLoader + private String getClasspath( ClassLoader loader ) { + try { + Method m=loader.getClass().getMethod("getClasspath", new Class[] {}); + if( log.isTraceEnabled()) + log.trace("getClasspath " + m ); + if( m==null ) return null; + Object o=m.invoke( loader, new Object[] {} ); + if( log.isDebugEnabled() ) + log.debug("gotClasspath " + o); + if( o instanceof String ) + return (String)o; + return null; + } catch( Exception ex ) { + if (log.isDebugEnabled()) + log.debug("getClasspath ", ex); + } + return null; + } + + /** + * Copy directory. + */ + private boolean copyDir(DirContext srcDir, File destDir) { + + try { + + NamingEnumeration enumeration = srcDir.list(""); + while (enumeration.hasMoreElements()) { + NameClassPair ncPair = + (NameClassPair) enumeration.nextElement(); + String name = ncPair.getName(); + Object object = srcDir.lookup(name); + File currentFile = new File(destDir, name); + if (object instanceof Resource) { + InputStream is = ((Resource) object).streamContent(); + OutputStream os = new FileOutputStream(currentFile); + if (!copy(is, os)) + return false; + } else if (object instanceof InputStream) { + OutputStream os = new FileOutputStream(currentFile); + if (!copy((InputStream) object, os)) + return false; + } else if (object instanceof DirContext) { + currentFile.mkdir(); + copyDir((DirContext) object, currentFile); + } + } + + } catch (NamingException e) { + return false; + } catch (IOException e) { + return false; + } + + return true; + + } + + + /** + * Copy a file to the specified temp directory. This is required only + * because Jasper depends on it. + */ + private boolean copy(InputStream is, OutputStream os) { + + try { + byte[] buf = new byte[4096]; + while (true) { + int len = is.read(buf); + if (len < 0) + break; + os.write(buf, 0, len); + } + is.close(); + os.close(); + } catch (IOException e) { + return false; + } + + return true; + + } + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( WebappLoader.class ); + + private ObjectName oname; + private MBeanServer mserver; + private String domain; + private ObjectName controller; + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + public ObjectName getController() { + return controller; + } + + public void setController(ObjectName controller) { + this.controller = controller; + } + +} diff --git a/java/org/apache/catalina/loader/mbeans-descriptors.xml b/java/org/apache/catalina/loader/mbeans-descriptors.xml index 2f286e783..33bc62c7d 100644 --- a/java/org/apache/catalina/loader/mbeans-descriptors.xml +++ b/java/org/apache/catalina/loader/mbeans-descriptors.xml @@ -1,59 +1,59 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/mbeans-descriptors.xml b/java/org/apache/catalina/mbeans-descriptors.xml index 568afd1ab..54daf1c97 100644 --- a/java/org/apache/catalina/mbeans-descriptors.xml +++ b/java/org/apache/catalina/mbeans-descriptors.xml @@ -1,150 +1,150 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/mbeans/ClassNameMBean.java b/java/org/apache/catalina/mbeans/ClassNameMBean.java index 9e132d6d9..e03f89aff 100644 --- a/java/org/apache/catalina/mbeans/ClassNameMBean.java +++ b/java/org/apache/catalina/mbeans/ClassNameMBean.java @@ -1,76 +1,76 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.MBeanException; -import javax.management.RuntimeOperationsException; - -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A convenience base class for ModelMBean implementations - * where the underlying base class (and therefore the set of supported - * properties) is different for varying implementations of a standard - * interface. For Catalina, that includes at least the following: - * Connector, Logger, Realm, and Valve. This class creates an artificial - * MBean attribute named className, which reports the fully - * qualified class name of the managed object as its value.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ClassNameMBean extends BaseModelMBean { - - - // ---------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initialize of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public ClassNameMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------ Properties - - - /** - * Return the fully qualified Java class name of the managed object - * for this MBean. - */ - public String getClassName() { - - return (this.resource.getClass().getName()); - - } - - - } +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.MBeanException; +import javax.management.RuntimeOperationsException; + +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A convenience base class for ModelMBean implementations + * where the underlying base class (and therefore the set of supported + * properties) is different for varying implementations of a standard + * interface. For Catalina, that includes at least the following: + * Connector, Logger, Realm, and Valve. This class creates an artificial + * MBean attribute named className, which reports the fully + * qualified class name of the managed object as its value.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ClassNameMBean extends BaseModelMBean { + + + // ---------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initialize of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public ClassNameMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------ Properties + + + /** + * Return the fully qualified Java class name of the managed object + * for this MBean. + */ + public String getClassName() { + + return (this.resource.getClass().getName()); + + } + + + } diff --git a/java/org/apache/catalina/mbeans/ConnectorMBean.java b/java/org/apache/catalina/mbeans/ConnectorMBean.java index 174e3d97f..a27f77810 100644 --- a/java/org/apache/catalina/mbeans/ConnectorMBean.java +++ b/java/org/apache/catalina/mbeans/ConnectorMBean.java @@ -1,140 +1,140 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - -import javax.management.Attribute; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.modelmbean.InvalidTargetObjectTypeException; - -import org.apache.catalina.connector.Connector; -import org.apache.tomcat.util.IntrospectionUtils; - - -/** - *

    A ModelMBean implementation for the - * org.apache.coyote.tomcat5.CoyoteConnector component.

    - * - * @author Amy Roh - * @version $Revision: 303320 $ $Date: 2004-10-04 11:25:55 +0200 (lun., 04 oct. 2004) $ - */ - -public class ConnectorMBean extends ClassNameMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public ConnectorMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - /** - * Obtain and return the value of a specific attribute of this MBean. - * - * @param name Name of the requested attribute - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public Object getAttribute(String name) throws AttributeNotFoundException, - MBeanException, ReflectionException { - - Object attribute = null; - // Validate the input parameters - if (name == null) - throw new RuntimeOperationsException(new IllegalArgumentException( - "Attribute name is null"), "Attribute name is null"); - - Object result = null; - try { - Connector connector = (Connector) getManagedResource(); - result = IntrospectionUtils.getProperty(connector, name); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - return result; - - } - - - /** - * Set the value of a specific attribute of this MBean. - * - * @param attribute The identification of the attribute to be set - * and the new value - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - - // Validate the input parameters - if (attribute == null) - throw new RuntimeOperationsException(new IllegalArgumentException( - "Attribute is null"), "Attribute is null"); - String name = attribute.getName(); - Object value = attribute.getValue(); - if (name == null) - throw new RuntimeOperationsException(new IllegalArgumentException( - "Attribute name is null"), "Attribute name is null"); - - try { - Connector connector = (Connector) getManagedResource(); - IntrospectionUtils.setProperty(connector, name, String.valueOf(value)); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; + +import org.apache.catalina.connector.Connector; +import org.apache.tomcat.util.IntrospectionUtils; + + +/** + *

    A ModelMBean implementation for the + * org.apache.coyote.tomcat5.CoyoteConnector component.

    + * + * @author Amy Roh + * @version $Revision: 303320 $ $Date: 2004-10-04 11:25:55 +0200 (lun., 04 oct. 2004) $ + */ + +public class ConnectorMBean extends ClassNameMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public ConnectorMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + /** + * Obtain and return the value of a specific attribute of this MBean. + * + * @param name Name of the requested attribute + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public Object getAttribute(String name) throws AttributeNotFoundException, + MBeanException, ReflectionException { + + Object attribute = null; + // Validate the input parameters + if (name == null) + throw new RuntimeOperationsException(new IllegalArgumentException( + "Attribute name is null"), "Attribute name is null"); + + Object result = null; + try { + Connector connector = (Connector) getManagedResource(); + result = IntrospectionUtils.getProperty(connector, name); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + return result; + + } + + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + + // Validate the input parameters + if (attribute == null) + throw new RuntimeOperationsException(new IllegalArgumentException( + "Attribute is null"), "Attribute is null"); + String name = attribute.getName(); + Object value = attribute.getValue(); + if (name == null) + throw new RuntimeOperationsException(new IllegalArgumentException( + "Attribute name is null"), "Attribute name is null"); + + try { + Connector connector = (Connector) getManagedResource(); + IntrospectionUtils.setProperty(connector, name, String.valueOf(value)); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + } + + +} diff --git a/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java b/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java index 6b59ddf5a..2f79235af 100644 --- a/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java +++ b/java/org/apache/catalina/mbeans/ContextEnvironmentMBean.java @@ -1,105 +1,105 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.Attribute; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.modelmbean.InvalidTargetObjectTypeException; - -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.deploy.ContextEnvironment component.

    - * - * @author Amy Roh - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ContextEnvironmentMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public ContextEnvironmentMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------------- Attributes - - - /** - * Set the value of a specific attribute of this MBean. - * - * @param attribute The identification of the attribute to be set - * and the new value - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - - super.setAttribute(attribute); - - ContextEnvironment ce = null; - try { - ce = (ContextEnvironment) getManagedResource(); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - // cannot use side-efects. It's removed and added back each time - // there is a modification in a resource. - NamingResources nr = ce.getNamingResources(); - nr.removeEnvironment(ce.getName()); - nr.addEnvironment(ce); - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; + +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.deploy.ContextEnvironment component.

    + * + * @author Amy Roh + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ContextEnvironmentMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public ContextEnvironmentMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------------- Attributes + + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + + super.setAttribute(attribute); + + ContextEnvironment ce = null; + try { + ce = (ContextEnvironment) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + // cannot use side-efects. It's removed and added back each time + // there is a modification in a resource. + NamingResources nr = ce.getNamingResources(); + nr.removeEnvironment(ce.getName()); + nr.addEnvironment(ce); + } + +} diff --git a/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java b/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java index 322fc80ed..a72e9ae59 100644 --- a/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java +++ b/java/org/apache/catalina/mbeans/ContextResourceLinkMBean.java @@ -1,105 +1,105 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.Attribute; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.modelmbean.InvalidTargetObjectTypeException; - -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.deploy.ContextResourceLink component.

    - * - * @author Amy Roh - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ContextResourceLinkMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public ContextResourceLinkMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------------- Attributes - - - /** - * Set the value of a specific attribute of this MBean. - * - * @param attribute The identification of the attribute to be set - * and the new value - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - - super.setAttribute(attribute); - - ContextResourceLink crl = null; - try { - crl = (ContextResourceLink) getManagedResource(); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - // cannot use side-efects. It's removed and added back each time - // there is a modification in a resource. - NamingResources nr = crl.getNamingResources(); - nr.removeResourceLink(crl.getName()); - nr.addResourceLink(crl); - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; + +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.deploy.ContextResourceLink component.

    + * + * @author Amy Roh + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ContextResourceLinkMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public ContextResourceLinkMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------------- Attributes + + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + + super.setAttribute(attribute); + + ContextResourceLink crl = null; + try { + crl = (ContextResourceLink) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + // cannot use side-efects. It's removed and added back each time + // there is a modification in a resource. + NamingResources nr = crl.getNamingResources(); + nr.removeResourceLink(crl.getName()); + nr.addResourceLink(crl); + } + +} diff --git a/java/org/apache/catalina/mbeans/ContextResourceMBean.java b/java/org/apache/catalina/mbeans/ContextResourceMBean.java index ed15b9c51..4f362053d 100644 --- a/java/org/apache/catalina/mbeans/ContextResourceMBean.java +++ b/java/org/apache/catalina/mbeans/ContextResourceMBean.java @@ -1,184 +1,184 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.Attribute; -import javax.management.AttributeNotFoundException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.modelmbean.InvalidTargetObjectTypeException; - -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.deploy.ContextResource component.

    - * - * @author Amy Roh - * @version $Revision: 303032 $ $Date: 2004-07-26 18:04:02 +0200 (lun., 26 juil. 2004) $ - */ - -public class ContextResourceMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public ContextResourceMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------------- Attributes - - - /** - * Obtain and return the value of a specific attribute of this MBean. - * - * @param name Name of the requested attribute - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public Object getAttribute(String name) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - - // Validate the input parameters - if (name == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute name is null"), - "Attribute name is null"); - - ContextResource cr = null; - try { - cr = (ContextResource) getManagedResource(); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - String value = null; - if ("auth".equals(name)) { - return (cr.getAuth()); - } else if ("description".equals(name)) { - return (cr.getDescription()); - } else if ("name".equals(name)) { - return (cr.getName()); - } else if ("scope".equals(name)) { - return (cr.getScope()); - } else if ("type".equals(name)) { - return (cr.getType()); - } else { - value = (String) cr.getProperty(name); - if (value == null) { - throw new AttributeNotFoundException - ("Cannot find attribute "+name); - } - } - - return value; - - } - - - /** - * Set the value of a specific attribute of this MBean. - * - * @param attribute The identification of the attribute to be set - * and the new value - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - - // Validate the input parameters - if (attribute == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute is null"), - "Attribute is null"); - String name = attribute.getName(); - Object value = attribute.getValue(); - if (name == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute name is null"), - "Attribute name is null"); - - ContextResource cr = null; - try { - cr = (ContextResource) getManagedResource(); - } catch (InstanceNotFoundException e) { - throw new MBeanException(e); - } catch (InvalidTargetObjectTypeException e) { - throw new MBeanException(e); - } - - if ("auth".equals(name)) { - cr.setAuth((String)value); - } else if ("description".equals(name)) { - cr.setDescription((String)value); - } else if ("name".equals(name)) { - cr.setName((String)value); - } else if ("scope".equals(name)) { - cr.setScope((String)value); - } else if ("type".equals(name)) { - cr.setType((String)value); - } else { - cr.setProperty(name, ""+value); - } - - // cannot use side-efects. It's removed and added back each time - // there is a modification in a resource. - NamingResources nr = cr.getNamingResources(); - nr.removeResource(cr.getName()); - nr.addResource(cr); - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.Attribute; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; + +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.deploy.ContextResource component.

    + * + * @author Amy Roh + * @version $Revision: 303032 $ $Date: 2004-07-26 18:04:02 +0200 (lun., 26 juil. 2004) $ + */ + +public class ContextResourceMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public ContextResourceMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------------- Attributes + + + /** + * Obtain and return the value of a specific attribute of this MBean. + * + * @param name Name of the requested attribute + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public Object getAttribute(String name) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + + // Validate the input parameters + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute name is null"), + "Attribute name is null"); + + ContextResource cr = null; + try { + cr = (ContextResource) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + String value = null; + if ("auth".equals(name)) { + return (cr.getAuth()); + } else if ("description".equals(name)) { + return (cr.getDescription()); + } else if ("name".equals(name)) { + return (cr.getName()); + } else if ("scope".equals(name)) { + return (cr.getScope()); + } else if ("type".equals(name)) { + return (cr.getType()); + } else { + value = (String) cr.getProperty(name); + if (value == null) { + throw new AttributeNotFoundException + ("Cannot find attribute "+name); + } + } + + return value; + + } + + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + + // Validate the input parameters + if (attribute == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute is null"), + "Attribute is null"); + String name = attribute.getName(); + Object value = attribute.getValue(); + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute name is null"), + "Attribute name is null"); + + ContextResource cr = null; + try { + cr = (ContextResource) getManagedResource(); + } catch (InstanceNotFoundException e) { + throw new MBeanException(e); + } catch (InvalidTargetObjectTypeException e) { + throw new MBeanException(e); + } + + if ("auth".equals(name)) { + cr.setAuth((String)value); + } else if ("description".equals(name)) { + cr.setDescription((String)value); + } else if ("name".equals(name)) { + cr.setName((String)value); + } else if ("scope".equals(name)) { + cr.setScope((String)value); + } else if ("type".equals(name)) { + cr.setType((String)value); + } else { + cr.setProperty(name, ""+value); + } + + // cannot use side-efects. It's removed and added back each time + // there is a modification in a resource. + NamingResources nr = cr.getNamingResources(); + nr.removeResource(cr.getName()); + nr.addResource(cr); + } + +} diff --git a/java/org/apache/catalina/mbeans/DefaultContextMBean.java b/java/org/apache/catalina/mbeans/DefaultContextMBean.java index 8743b4bed..302198581 100644 --- a/java/org/apache/catalina/mbeans/DefaultContextMBean.java +++ b/java/org/apache/catalina/mbeans/DefaultContextMBean.java @@ -1,328 +1,328 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - -import java.util.ArrayList; - -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Context; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardDefaultContext component.

    - * - * @author Amy Roh - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class DefaultContextMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public DefaultContextMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("DefaultContext"); - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the naming resources associated with this web application. - */ - private NamingResources getNamingResources() { - - return ((Context)this.resource).getNamingResources(); - - } - - - /** - * Return the MBean Names of the set of defined environment entries for - * this web application - */ - public String[] getEnvironments() { - ContextEnvironment[] envs = getNamingResources().findEnvironments(); - ArrayList results = new ArrayList(); - for (int i = 0; i < envs.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), envs[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for environment " + envs[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource references for this - * application. - */ - public String[] getResources() { - - ContextResource[] resources = getNamingResources().findResources(); - ArrayList results = new ArrayList(); - for (int i = 0; i < resources.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resources[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + resources[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource links for this - * application - */ - public String[] getResourceLinks() { - - ContextResourceLink[] links = getNamingResources().findResourceLinks(); - ArrayList results = new ArrayList(); - for (int i = 0; i < links.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), links[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + links[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - // ------------------------------------------------------------- Operations - - - /** - * Add an environment entry for this web application. - * - * @param envName New environment entry name - */ - public String addEnvironment(String envName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env != null) { - throw new IllegalArgumentException - ("Invalid environment name - already exists '" + envName + "'"); - } - env = new ContextEnvironment(); - env.setName(envName); - env.setType(type); - nresources.addEnvironment(env); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextEnvironment"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), env); - return (oname.toString()); - - } - - - /** - * Add a resource reference for this web application. - * - * @param resourceName New resource reference name - */ - public String addResource(String resourceName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource != null) { - throw new IllegalArgumentException - ("Invalid resource name - already exists'" + resourceName + "'"); - } - resource = new ContextResource(); - resource.setName(resourceName); - resource.setType(type); - nresources.addResource(resource); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResource"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resource); - - return (oname.toString()); - } - - - /** - * Add a resource link for this web application. - * - * @param resourceLinkName New resource link name - */ - public String addResourceLink(String resourceLinkName, String global, - String name, String type) throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextResourceLink resourceLink = - nresources.findResourceLink(resourceLinkName); - if (resourceLink != null) { - throw new IllegalArgumentException - ("Invalid resource link name - already exists'" + - resourceLinkName + "'"); - } - resourceLink = new ContextResourceLink(); - resourceLink.setGlobal(global); - resourceLink.setName(resourceLinkName); - resourceLink.setType(type); - nresources.addResourceLink(resourceLink); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResourceLink"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resourceLink); - return (oname.toString()); - } - - - /** - * Remove any environment entry with the specified name. - * - * @param envName Name of the environment entry to remove - */ - public void removeEnvironment(String envName) { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env == null) { - throw new IllegalArgumentException - ("Invalid environment name '" + envName + "'"); - } - nresources.removeEnvironment(envName); - - } - - - /** - * Remove any resource reference with the specified name. - * - * @param resourceName Name of the resource reference to remove - */ - public void removeResource(String resourceName) { - - resourceName = ObjectName.unquote(resourceName); - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource == null) { - throw new IllegalArgumentException - ("Invalid resource name '" + resourceName + "'"); - } - nresources.removeResource(resourceName); - } - - - /** - * Remove any resource link with the specified name. - * - * @param resourceLinkName Name of the resource reference to remove - */ - public void removeResourceLink(String resourceLinkName) { - - resourceLinkName = ObjectName.unquote(resourceLinkName); - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextResourceLink resource = nresources.findResourceLink(resourceLinkName); - if (resource == null) { - throw new IllegalArgumentException - ("Invalid resource name '" + resourceLinkName + "'"); - } - nresources.removeResourceLink(resourceLinkName); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + +import java.util.ArrayList; + +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Context; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardDefaultContext component.

    + * + * @author Amy Roh + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class DefaultContextMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public DefaultContextMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("DefaultContext"); + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the naming resources associated with this web application. + */ + private NamingResources getNamingResources() { + + return ((Context)this.resource).getNamingResources(); + + } + + + /** + * Return the MBean Names of the set of defined environment entries for + * this web application + */ + public String[] getEnvironments() { + ContextEnvironment[] envs = getNamingResources().findEnvironments(); + ArrayList results = new ArrayList(); + for (int i = 0; i < envs.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), envs[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for environment " + envs[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource references for this + * application. + */ + public String[] getResources() { + + ContextResource[] resources = getNamingResources().findResources(); + ArrayList results = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resources[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + resources[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource links for this + * application + */ + public String[] getResourceLinks() { + + ContextResourceLink[] links = getNamingResources().findResourceLinks(); + ArrayList results = new ArrayList(); + for (int i = 0; i < links.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), links[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + links[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + // ------------------------------------------------------------- Operations + + + /** + * Add an environment entry for this web application. + * + * @param envName New environment entry name + */ + public String addEnvironment(String envName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env != null) { + throw new IllegalArgumentException + ("Invalid environment name - already exists '" + envName + "'"); + } + env = new ContextEnvironment(); + env.setName(envName); + env.setType(type); + nresources.addEnvironment(env); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextEnvironment"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), env); + return (oname.toString()); + + } + + + /** + * Add a resource reference for this web application. + * + * @param resourceName New resource reference name + */ + public String addResource(String resourceName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource != null) { + throw new IllegalArgumentException + ("Invalid resource name - already exists'" + resourceName + "'"); + } + resource = new ContextResource(); + resource.setName(resourceName); + resource.setType(type); + nresources.addResource(resource); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResource"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resource); + + return (oname.toString()); + } + + + /** + * Add a resource link for this web application. + * + * @param resourceLinkName New resource link name + */ + public String addResourceLink(String resourceLinkName, String global, + String name, String type) throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextResourceLink resourceLink = + nresources.findResourceLink(resourceLinkName); + if (resourceLink != null) { + throw new IllegalArgumentException + ("Invalid resource link name - already exists'" + + resourceLinkName + "'"); + } + resourceLink = new ContextResourceLink(); + resourceLink.setGlobal(global); + resourceLink.setName(resourceLinkName); + resourceLink.setType(type); + nresources.addResourceLink(resourceLink); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResourceLink"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resourceLink); + return (oname.toString()); + } + + + /** + * Remove any environment entry with the specified name. + * + * @param envName Name of the environment entry to remove + */ + public void removeEnvironment(String envName) { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env == null) { + throw new IllegalArgumentException + ("Invalid environment name '" + envName + "'"); + } + nresources.removeEnvironment(envName); + + } + + + /** + * Remove any resource reference with the specified name. + * + * @param resourceName Name of the resource reference to remove + */ + public void removeResource(String resourceName) { + + resourceName = ObjectName.unquote(resourceName); + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource == null) { + throw new IllegalArgumentException + ("Invalid resource name '" + resourceName + "'"); + } + nresources.removeResource(resourceName); + } + + + /** + * Remove any resource link with the specified name. + * + * @param resourceLinkName Name of the resource reference to remove + */ + public void removeResourceLink(String resourceLinkName) { + + resourceLinkName = ObjectName.unquote(resourceLinkName); + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextResourceLink resource = nresources.findResourceLink(resourceLinkName); + if (resource == null) { + throw new IllegalArgumentException + ("Invalid resource name '" + resourceLinkName + "'"); + } + nresources.removeResourceLink(resourceLinkName); + } + + +} diff --git a/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java b/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java index 07476652d..d98fd1e24 100644 --- a/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java +++ b/java/org/apache/catalina/mbeans/GlobalResourcesLifecycleListener.java @@ -1,236 +1,236 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.util.Iterator; -import javax.naming.Binding; -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.OperationNotSupportedException; -import org.apache.catalina.Group; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Role; -import org.apache.catalina.User; -import org.apache.catalina.UserDatabase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Implementation of LifecycleListener that instantiates the - * set of MBeans associated with global JNDI resources that are subject to - * management. - * - * @author Craig R. McClanahan - * @version $Revision: 302983 $ $Date: 2004-06-26 01:56:25 +0200 (sam., 26 juin 2004) $ - * @since 4.1 - */ - -public class GlobalResourcesLifecycleListener - implements LifecycleListener { - private static Log log = LogFactory.getLog(GlobalResourcesLifecycleListener.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The owning Catalina component that we are attached to. - */ - protected Lifecycle component = null; - - - /** - * The configuration information registry for our managed beans. - */ - protected static Registry registry = MBeanUtils.createRegistry(); - - - // ---------------------------------------------- LifecycleListener Methods - - - /** - * Primary entry point for startup and shutdown events. - * - * @param event The event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - if (Lifecycle.START_EVENT.equals(event.getType())) { - component = event.getLifecycle(); - createMBeans(); - } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { - destroyMBeans(); - component = null; - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Create the MBeans for the interesting global JNDI resources. - */ - protected void createMBeans() { - - // Look up our global naming context - Context context = null; - try { - context = (Context) (new InitialContext()).lookup("java:/"); - } catch (NamingException e) { - log.error("No global naming context defined for server"); - return; - } - - // Recurse through the defined global JNDI resources context - try { - createMBeans("", context); - } catch (NamingException e) { - log.error("Exception processing Global JNDI Resources", e); - } - - } - - - /** - * Create the MBeans for the interesting global JNDI resources in - * the specified naming context. - * - * @param prefix Prefix for complete object name paths - * @param context Context to be scanned - * - * @exception NamingException if a JNDI exception occurs - */ - protected void createMBeans(String prefix, Context context) - throws NamingException { - - if (log.isDebugEnabled()) { - log.debug("Creating MBeans for Global JNDI Resources in Context '" + - prefix + "'"); - } - - try { - NamingEnumeration bindings = context.listBindings(""); - while (bindings.hasMore()) { - Binding binding = (Binding) bindings.next(); - String name = prefix + binding.getName(); - Object value = context.lookup(binding.getName()); - if (log.isDebugEnabled()) { - log.debug("Checking resource " + name); - } - if (value instanceof Context) { - createMBeans(name + "/", (Context) value); - } else if (value instanceof UserDatabase) { - try { - createMBeans(name, (UserDatabase) value); - } catch (Exception e) { - log.error("Exception creating UserDatabase MBeans for " + name, - e); - } - } - } - } catch( RuntimeException ex) { - log.error("RuntimeException " + ex); - } catch( OperationNotSupportedException ex) { - log.error("Operation not supported " + ex); - } - - } - - - /** - * Create the MBeans for the specified UserDatabase and its contents. - * - * @param name Complete resource name of this UserDatabase - * @param database The UserDatabase to be processed - * - * @exception Exception if an exception occurs while creating MBeans - */ - protected void createMBeans(String name, UserDatabase database) - throws Exception { - - // Create the MBean for the UserDatabase itself - if (log.isDebugEnabled()) { - log.debug("Creating UserDatabase MBeans for resource " + name); - log.debug("Database=" + database); - } - if (MBeanUtils.createMBean(database) == null) { - throw new IllegalArgumentException - ("Cannot create UserDatabase MBean for resource " + name); - } - - // Create the MBeans for each defined Role - Iterator roles = database.getRoles(); - while (roles.hasNext()) { - Role role = (Role) roles.next(); - if (log.isDebugEnabled()) { - log.debug(" Creating Role MBean for role " + role); - } - if (MBeanUtils.createMBean(role) == null) { - throw new IllegalArgumentException - ("Cannot create Role MBean for role " + role); - } - } - - // Create the MBeans for each defined Group - Iterator groups = database.getGroups(); - while (groups.hasNext()) { - Group group = (Group) groups.next(); - if (log.isDebugEnabled()) { - log.debug(" Creating Group MBean for group " + group); - } - if (MBeanUtils.createMBean(group) == null) { - throw new IllegalArgumentException - ("Cannot create Group MBean for group " + group); - } - } - - // Create the MBeans for each defined User - Iterator users = database.getUsers(); - while (users.hasNext()) { - User user = (User) users.next(); - if (log.isDebugEnabled()) { - log.debug(" Creating User MBean for user " + user); - } - if (MBeanUtils.createMBean(user) == null) { - throw new IllegalArgumentException - ("Cannot create User MBean for user " + user); - } - } - - } - - - /** - * Destroy the MBeans for the interesting global JNDI resources. - */ - protected void destroyMBeans() { - - if (log.isDebugEnabled()) { - log.debug("Destroying MBeans for Global JNDI Resources"); - } - - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.util.Iterator; +import javax.naming.Binding; +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import org.apache.catalina.Group; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.catalina.UserDatabase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Implementation of LifecycleListener that instantiates the + * set of MBeans associated with global JNDI resources that are subject to + * management. + * + * @author Craig R. McClanahan + * @version $Revision: 302983 $ $Date: 2004-06-26 01:56:25 +0200 (sam., 26 juin 2004) $ + * @since 4.1 + */ + +public class GlobalResourcesLifecycleListener + implements LifecycleListener { + private static Log log = LogFactory.getLog(GlobalResourcesLifecycleListener.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The owning Catalina component that we are attached to. + */ + protected Lifecycle component = null; + + + /** + * The configuration information registry for our managed beans. + */ + protected static Registry registry = MBeanUtils.createRegistry(); + + + // ---------------------------------------------- LifecycleListener Methods + + + /** + * Primary entry point for startup and shutdown events. + * + * @param event The event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + if (Lifecycle.START_EVENT.equals(event.getType())) { + component = event.getLifecycle(); + createMBeans(); + } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { + destroyMBeans(); + component = null; + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Create the MBeans for the interesting global JNDI resources. + */ + protected void createMBeans() { + + // Look up our global naming context + Context context = null; + try { + context = (Context) (new InitialContext()).lookup("java:/"); + } catch (NamingException e) { + log.error("No global naming context defined for server"); + return; + } + + // Recurse through the defined global JNDI resources context + try { + createMBeans("", context); + } catch (NamingException e) { + log.error("Exception processing Global JNDI Resources", e); + } + + } + + + /** + * Create the MBeans for the interesting global JNDI resources in + * the specified naming context. + * + * @param prefix Prefix for complete object name paths + * @param context Context to be scanned + * + * @exception NamingException if a JNDI exception occurs + */ + protected void createMBeans(String prefix, Context context) + throws NamingException { + + if (log.isDebugEnabled()) { + log.debug("Creating MBeans for Global JNDI Resources in Context '" + + prefix + "'"); + } + + try { + NamingEnumeration bindings = context.listBindings(""); + while (bindings.hasMore()) { + Binding binding = (Binding) bindings.next(); + String name = prefix + binding.getName(); + Object value = context.lookup(binding.getName()); + if (log.isDebugEnabled()) { + log.debug("Checking resource " + name); + } + if (value instanceof Context) { + createMBeans(name + "/", (Context) value); + } else if (value instanceof UserDatabase) { + try { + createMBeans(name, (UserDatabase) value); + } catch (Exception e) { + log.error("Exception creating UserDatabase MBeans for " + name, + e); + } + } + } + } catch( RuntimeException ex) { + log.error("RuntimeException " + ex); + } catch( OperationNotSupportedException ex) { + log.error("Operation not supported " + ex); + } + + } + + + /** + * Create the MBeans for the specified UserDatabase and its contents. + * + * @param name Complete resource name of this UserDatabase + * @param database The UserDatabase to be processed + * + * @exception Exception if an exception occurs while creating MBeans + */ + protected void createMBeans(String name, UserDatabase database) + throws Exception { + + // Create the MBean for the UserDatabase itself + if (log.isDebugEnabled()) { + log.debug("Creating UserDatabase MBeans for resource " + name); + log.debug("Database=" + database); + } + if (MBeanUtils.createMBean(database) == null) { + throw new IllegalArgumentException + ("Cannot create UserDatabase MBean for resource " + name); + } + + // Create the MBeans for each defined Role + Iterator roles = database.getRoles(); + while (roles.hasNext()) { + Role role = (Role) roles.next(); + if (log.isDebugEnabled()) { + log.debug(" Creating Role MBean for role " + role); + } + if (MBeanUtils.createMBean(role) == null) { + throw new IllegalArgumentException + ("Cannot create Role MBean for role " + role); + } + } + + // Create the MBeans for each defined Group + Iterator groups = database.getGroups(); + while (groups.hasNext()) { + Group group = (Group) groups.next(); + if (log.isDebugEnabled()) { + log.debug(" Creating Group MBean for group " + group); + } + if (MBeanUtils.createMBean(group) == null) { + throw new IllegalArgumentException + ("Cannot create Group MBean for group " + group); + } + } + + // Create the MBeans for each defined User + Iterator users = database.getUsers(); + while (users.hasNext()) { + User user = (User) users.next(); + if (log.isDebugEnabled()) { + log.debug(" Creating User MBean for user " + user); + } + if (MBeanUtils.createMBean(user) == null) { + throw new IllegalArgumentException + ("Cannot create User MBean for user " + user); + } + } + + } + + + /** + * Destroy the MBeans for the interesting global JNDI resources. + */ + protected void destroyMBeans() { + + if (log.isDebugEnabled()) { + log.debug("Destroying MBeans for Global JNDI Resources"); + } + + } + +} diff --git a/java/org/apache/catalina/mbeans/GroupMBean.java b/java/org/apache/catalina/mbeans/GroupMBean.java index 1697171f7..7975fb692 100644 --- a/java/org/apache/catalina/mbeans/GroupMBean.java +++ b/java/org/apache/catalina/mbeans/GroupMBean.java @@ -1,191 +1,191 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.util.ArrayList; -import java.util.Iterator; - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.User; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.Group component.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ - */ - -public class GroupMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public GroupMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - - /** - * The MBeanServer in which we are registered. - */ - protected MBeanServer mserver = MBeanUtils.createServer(); - - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("Group"); - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the MBean Names of all authorized roles for this group. - */ - public String[] getRoles() { - - Group group = (Group) this.resource; - ArrayList results = new ArrayList(); - Iterator roles = group.getRoles(); - while (roles.hasNext()) { - Role role = null; - try { - role = (Role) roles.next(); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), role); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for role " + role); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all users that are members of this group. - */ - public String[] getUsers() { - - Group group = (Group) this.resource; - ArrayList results = new ArrayList(); - Iterator users = group.getUsers(); - while (users.hasNext()) { - User user = null; - try { - user = (User) users.next(); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), user); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for user " + user); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - // ------------------------------------------------------------- Operations - - - /** - * Add a new {@link Role} to those this group belongs to. - * - * @param rolename Role name of the new role - */ - public void addRole(String rolename) { - - Group group = (Group) this.resource; - if (group == null) { - return; - } - Role role = group.getUserDatabase().findRole(rolename); - if (role == null) { - throw new IllegalArgumentException - ("Invalid role name '" + rolename + "'"); - } - group.addRole(role); - - } - - - /** - * Remove a {@link Role} from those this group belongs to. - * - * @param rolename Role name of the old role - */ - public void removeRole(String rolename) { - - Group group = (Group) this.resource; - if (group == null) { - return; - } - Role role = group.getUserDatabase().findRole(rolename); - if (role == null) { - throw new IllegalArgumentException - ("Invalid role name '" + rolename + "'"); - } - group.removeRole(role); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.Group component.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ + */ + +public class GroupMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public GroupMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + + /** + * The MBeanServer in which we are registered. + */ + protected MBeanServer mserver = MBeanUtils.createServer(); + + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("Group"); + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the MBean Names of all authorized roles for this group. + */ + public String[] getRoles() { + + Group group = (Group) this.resource; + ArrayList results = new ArrayList(); + Iterator roles = group.getRoles(); + while (roles.hasNext()) { + Role role = null; + try { + role = (Role) roles.next(); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), role); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for role " + role); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all users that are members of this group. + */ + public String[] getUsers() { + + Group group = (Group) this.resource; + ArrayList results = new ArrayList(); + Iterator users = group.getUsers(); + while (users.hasNext()) { + User user = null; + try { + user = (User) users.next(); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), user); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for user " + user); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + // ------------------------------------------------------------- Operations + + + /** + * Add a new {@link Role} to those this group belongs to. + * + * @param rolename Role name of the new role + */ + public void addRole(String rolename) { + + Group group = (Group) this.resource; + if (group == null) { + return; + } + Role role = group.getUserDatabase().findRole(rolename); + if (role == null) { + throw new IllegalArgumentException + ("Invalid role name '" + rolename + "'"); + } + group.addRole(role); + + } + + + /** + * Remove a {@link Role} from those this group belongs to. + * + * @param rolename Role name of the old role + */ + public void removeRole(String rolename) { + + Group group = (Group) this.resource; + if (group == null) { + return; + } + Role role = group.getUserDatabase().findRole(rolename); + if (role == null) { + throw new IllegalArgumentException + ("Invalid role name '" + rolename + "'"); + } + group.removeRole(role); + + } + + +} diff --git a/java/org/apache/catalina/mbeans/MBeanFactory.java b/java/org/apache/catalina/mbeans/MBeanFactory.java index 5c6592b95..9e6855af6 100644 --- a/java/org/apache/catalina/mbeans/MBeanFactory.java +++ b/java/org/apache/catalina/mbeans/MBeanFactory.java @@ -1,1076 +1,1076 @@ -/* - * Copyright 1999-2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - -import java.io.File; -import java.util.Vector; - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Server; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.Service; -import org.apache.catalina.Valve; -import org.apache.catalina.authenticator.SingleSignOn; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.core.ContainerBase; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.core.StandardEngine; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.core.StandardService; -import org.apache.catalina.loader.WebappLoader; -import org.apache.catalina.realm.DataSourceRealm; -import org.apache.catalina.realm.JDBCRealm; -import org.apache.catalina.realm.JNDIRealm; -import org.apache.catalina.realm.MemoryRealm; -import org.apache.catalina.realm.UserDatabaseRealm; -import org.apache.catalina.session.StandardManager; -import org.apache.catalina.startup.ContextConfig; -import org.apache.catalina.startup.HostConfig; -import org.apache.catalina.valves.AccessLogValve; -import org.apache.catalina.valves.RemoteAddrValve; -import org.apache.catalina.valves.RemoteHostValve; -import org.apache.catalina.valves.RequestDumperValve; -import org.apache.catalina.valves.ValveBase; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.Registry; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardServer component.

    - * - * @author Amy Roh - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - */ - -public class MBeanFactory extends BaseModelMBean { - - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(MBeanFactory.class); - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = MBeanUtils.createServer(); - - /** - * The configuration information registry for our managed beans. - */ - private static Registry registry = MBeanUtils.createRegistry(); - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public MBeanFactory() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - - - // ------------------------------------------------------------- Operations - - - /** - * Return the managed bean definition for the specified bean type - * - * @param type MBean type - */ - public String findObjectName(String type) { - - if (type.equals("org.apache.catalina.core.StandardContext")) { - return "StandardContext"; - } else if (type.equals("org.apache.catalina.core.StandardEngine")) { - return "Engine"; - } else if (type.equals("org.apache.catalina.core.StandardHost")) { - return "Host"; - } else { - return null; - } - - } - - - /** - * Little convenience method to remove redundant code - * when retrieving the path string - * - * @param t path string - * @return empty string if t==null || t.equals("/") - */ - private final String getPathStr(String t) { - if (t == null || t.equals("/")) { - return ""; - } - return t; - } - - /** - * Get Parent ContainerBase to add its child component - * from parent's ObjectName - */ - private ContainerBase getParentContainerFromParent(ObjectName pname) - throws Exception { - - String type = pname.getKeyProperty("type"); - String j2eeType = pname.getKeyProperty("j2eeType"); - Service service = getService(pname); - StandardEngine engine = (StandardEngine) service.getContainer(); - if ((j2eeType!=null) && (j2eeType.equals("WebModule"))) { - String name = pname.getKeyProperty("name"); - name = name.substring(2); - int i = name.indexOf("/"); - String hostName = name.substring(0,i); - String path = name.substring(i); - Host host = (Host) engine.findChild(hostName); - String pathStr = getPathStr(path); - StandardContext context = (StandardContext)host.findChild(pathStr); - return context; - } else if (type != null) { - if (type.equals("Engine")) { - return engine; - } else if (type.equals("Host")) { - String hostName = pname.getKeyProperty("host"); - StandardHost host = (StandardHost) engine.findChild(hostName); - return host; - } - } - return null; - - } - - - /** - * Get Parent ContainerBase to add its child component - * from child component's ObjectName as a String - */ - private ContainerBase getParentContainerFromChild(ObjectName oname) - throws Exception { - - String hostName = oname.getKeyProperty("host"); - String path = oname.getKeyProperty("path"); - Service service = getService(oname); - StandardEngine engine = (StandardEngine) service.getContainer(); - if (hostName == null) { - // child's container is Engine - return engine; - } else if (path == null) { - // child's container is Host - StandardHost host = (StandardHost) engine.findChild(hostName); - return host; - } else { - // child's container is Context - StandardHost host = (StandardHost) engine.findChild(hostName); - path = getPathStr(path); - StandardContext context = (StandardContext) host.findChild(path); - return context; - } - } - - - private Service getService(ObjectName oname) throws Exception { - - String domain = oname.getDomain(); - Server server = ServerFactory.getServer(); - Service[] services = server.findServices(); - StandardService service = null; - for (int i = 0; i < services.length; i++) { - service = (StandardService) services[i]; - if (domain.equals(service.getObjectName().getDomain())) { - break; - } - } - if (!service.getObjectName().getDomain().equals(domain)) { - throw new Exception("Service with the domain is not found"); - } - return service; - - } - - - /** - * Create a new AccessLoggerValve. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createAccessLoggerValve(String parent) - throws Exception { - - ObjectName pname = new ObjectName(parent); - // Create a new AccessLogValve instance - AccessLogValve accessLogger = new AccessLogValve(); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.addValve(accessLogger); - ObjectName oname = accessLogger.getObjectName(); - return (oname.toString()); - - } - - - /** - * Create a new AjpConnector - * - * @param parent MBean Name of the associated parent component - * @param address The IP address on which to bind - * @param port TCP port number to listen on - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createAjpConnector(String parent, String address, int port) - throws Exception { - - return createConnector(parent, address, port, true, false); - } - - /** - * Create a new DataSource Realm. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createDataSourceRealm(String parent, String dataSourceName, - String roleNameCol, String userCredCol, String userNameCol, - String userRoleTable, String userTable) throws Exception { - - // Create a new DataSourceRealm instance - DataSourceRealm realm = new DataSourceRealm(); - realm.setDataSourceName(dataSourceName); - realm.setRoleNameCol(roleNameCol); - realm.setUserCredCol(userCredCol); - realm.setUserNameCol(userNameCol); - realm.setUserRoleTable(userRoleTable); - realm.setUserTable(userTable); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.setRealm(realm); - // Return the corresponding MBean name - ObjectName oname = realm.getObjectName(); - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - } - - /** - * Create a new HttpConnector - * - * @param parent MBean Name of the associated parent component - * @param address The IP address on which to bind - * @param port TCP port number to listen on - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createHttpConnector(String parent, String address, int port) - throws Exception { - return createConnector(parent, address, port, false, false); - } - - /** - * Create a new Connector - * - * @param parent MBean Name of the associated parent component - * @param address The IP address on which to bind - * @param port TCP port number to listen on - * @param isAjp Create a AJP/1.3 Connector - * @param isSSL Create a secure Connector - * - * @exception Exception if an MBean cannot be created or registered - */ - private String createConnector(String parent, String address, int port, boolean isAjp, boolean isSSL) - throws Exception { - Connector retobj = new Connector(); - if ((address!=null) && (address.length()>0)) { - retobj.setProperty("address", address); - } - // Set port number - retobj.setPort(port); - // Set the protocol - retobj.setProtocol(isAjp ? "AJP/1.3" : "HTTP/1.1"); - // Set SSL - retobj.setSecure(isSSL); - retobj.setScheme(isSSL ? "https" : "http"); - // Add the new instance to its parent component - // FIX ME - addConnector will fail - ObjectName pname = new ObjectName(parent); - Service service = getService(pname); - service.addConnector(retobj); - - // Return the corresponding MBean name - ObjectName coname = retobj.getObjectName(); - - return (coname.toString()); - } - - - /** - * Create a new HttpsConnector - * - * @param parent MBean Name of the associated parent component - * @param address The IP address on which to bind - * @param port TCP port number to listen on - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createHttpsConnector(String parent, String address, int port) - throws Exception { - return createConnector(parent, address, port, false, true); - } - - /** - * Create a new JDBC Realm. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createJDBCRealm(String parent, String driverName, - String connectionName, String connectionPassword, String connectionURL) - throws Exception { - - // Create a new JDBCRealm instance - JDBCRealm realm = new JDBCRealm(); - realm.setDriverName(driverName); - realm.setConnectionName(connectionName); - realm.setConnectionPassword(connectionPassword); - realm.setConnectionURL(connectionURL); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.setRealm(realm); - // Return the corresponding MBean name - ObjectName oname = realm.getObjectName(); - - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - } - - - /** - * Create a new JNDI Realm. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createJNDIRealm(String parent) - throws Exception { - - // Create a new JNDIRealm instance - JNDIRealm realm = new JNDIRealm(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.setRealm(realm); - // Return the corresponding MBean name - ObjectName oname = realm.getObjectName(); - - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - - } - - - /** - * Create a new Memory Realm. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createMemoryRealm(String parent) - throws Exception { - - // Create a new MemoryRealm instance - MemoryRealm realm = new MemoryRealm(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.setRealm(realm); - // Return the corresponding MBean name - ObjectName oname = realm.getObjectName(); - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - } - - - /** - * Create a new Remote Address Filter Valve. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createRemoteAddrValve(String parent) - throws Exception { - - // Create a new RemoteAddrValve instance - RemoteAddrValve valve = new RemoteAddrValve(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - containerBase.addValve(valve); - ObjectName oname = valve.getObjectName(); - return (oname.toString()); - - } - - - /** - * Create a new Remote Host Filter Valve. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createRemoteHostValve(String parent) - throws Exception { - - // Create a new RemoteHostValve instance - RemoteHostValve valve = new RemoteHostValve(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - containerBase.addValve(valve); - ObjectName oname = valve.getObjectName(); - return (oname.toString()); - - } - - - /** - * Create a new Request Dumper Valve. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createRequestDumperValve(String parent) - throws Exception { - - // Create a new RequestDumperValve instance - RequestDumperValve valve = new RequestDumperValve(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - containerBase.addValve(valve); - ObjectName oname = valve.getObjectName(); - return (oname.toString()); - - } - - - /** - * Create a new Single Sign On Valve. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createSingleSignOn(String parent) - throws Exception { - - // Create a new SingleSignOn instance - SingleSignOn valve = new SingleSignOn(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - containerBase.addValve(valve); - ObjectName oname = valve.getObjectName(); - return (oname.toString()); - - } - - - /** - * Create a new StandardContext. - * - * @param parent MBean Name of the associated parent component - * @param path The context path for this Context - * @param docBase Document base directory (or WAR) for this Context - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createStandardContext(String parent, - String path, - String docBase) - throws Exception { - - // XXX for backward compatibility. Remove it once supported by the admin - return - createStandardContext(parent,path,docBase,false,false,false,false); - } - - /** - * Given a context path, get the config file name. - */ - private String getConfigFile(String path) { - String basename = null; - if (path.equals("")) { - basename = "ROOT"; - } else { - basename = path.substring(1).replace('/', '#'); - } - return (basename); - } - - /** - * Create a new StandardContext. - * - * @param parent MBean Name of the associated parent component - * @param path The context path for this Context - * @param docBase Document base directory (or WAR) for this Context - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createStandardContext(String parent, - String path, - String docBase, - boolean xmlValidation, - boolean xmlNamespaceAware, - boolean tldValidation, - boolean tldNamespaceAware) - throws Exception { - - // Create a new StandardContext instance - StandardContext context = new StandardContext(); - path = getPathStr(path); - context.setPath(path); - context.setDocBase(docBase); - context.setXmlValidation(xmlValidation); - context.setXmlNamespaceAware(xmlNamespaceAware); - context.setTldValidation(tldValidation); - context.setTldNamespaceAware(tldNamespaceAware); - - ContextConfig contextConfig = new ContextConfig(); - context.addLifecycleListener(contextConfig); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ObjectName deployer = new ObjectName(pname.getDomain()+ - ":type=Deployer,host="+ - pname.getKeyProperty("host")); - if(mserver.isRegistered(deployer)) { - String contextPath = context.getPath(); - mserver.invoke(deployer, "addServiced", - new Object [] {contextPath}, - new String [] {"java.lang.String"}); - String configPath = (String)mserver.getAttribute(deployer, - "configBaseName"); - String baseName = getConfigFile(contextPath); - File configFile = new File(new File(configPath), baseName+".xml"); - context.setConfigFile(configFile.getAbsolutePath()); - mserver.invoke(deployer, "manageApp", - new Object[] {context}, - new String[] {"org.apache.catalina.Context"}); - mserver.invoke(deployer, "removeServiced", - new Object [] {contextPath}, - new String [] {"java.lang.String"}); - } else { - log.warn("Deployer not found for "+pname.getKeyProperty("host")); - Service service = getService(pname); - Engine engine = (Engine) service.getContainer(); - Host host = (Host) engine.findChild(pname.getKeyProperty("host")); - host.addChild(context); - } - - // Return the corresponding MBean name - ObjectName oname = context.getJmxName(); - - return (oname.toString()); - - } - - - /** - * Create a new StandardEngine. - * - * @param parent MBean Name of the associated parent component - * @param engineName Unique name of this Engine - * @param defaultHost Default hostname of this Engine - * @param serviceName Unique name of this Service - * - * @exception Exception if an MBean cannot be created or registered - */ - - public Vector createStandardEngineService(String parent, - String engineName, String defaultHost, String serviceName) - throws Exception { - - // Create a new StandardService instance - StandardService service = new StandardService(); - service.setName(serviceName); - // Create a new StandardEngine instance - StandardEngine engine = new StandardEngine(); - engine.setName(engineName); - engine.setDefaultHost(defaultHost); - // Need to set engine before adding it to server in order to set domain - service.setContainer(engine); - // Add the new instance to its parent component - Server server = ServerFactory.getServer(); - server.addService(service); - Vector onames = new Vector(); - // FIXME service & engine.getObjectName - //ObjectName oname = engine.getObjectName(); - ObjectName oname = - MBeanUtils.createObjectName(engineName, engine); - onames.add(0, oname); - //oname = service.getObjectName(); - oname = - MBeanUtils.createObjectName(engineName, service); - onames.add(1, oname); - return (onames); - - } - - - /** - * Create a new StandardHost. - * - * @param parent MBean Name of the associated parent component - * @param name Unique name of this Host - * @param appBase Application base directory name - * @param autoDeploy Should we auto deploy? - * @param deployOnStartup Deploy on server startup? - * @param deployXML Should we deploy Context XML config files property? - * @param unpackWARs Should we unpack WARs when auto deploying? - * @param xmlNamespaceAware Should we turn on/off XML namespace awareness? - * @param xmlValidation Should we turn on/off XML validation? - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createStandardHost(String parent, String name, - String appBase, - boolean autoDeploy, - boolean deployOnStartup, - boolean deployXML, - boolean unpackWARs, - boolean xmlNamespaceAware, - boolean xmlValidation) - throws Exception { - - // Create a new StandardHost instance - StandardHost host = new StandardHost(); - host.setName(name); - host.setAppBase(appBase); - host.setAutoDeploy(autoDeploy); - host.setDeployOnStartup(deployOnStartup); - host.setDeployXML(deployXML); - host.setUnpackWARs(unpackWARs); - host.setXmlNamespaceAware(xmlNamespaceAware); - host.setXmlValidation(xmlValidation); - - // add HostConfig for active reloading - HostConfig hostConfig = new HostConfig(); - host.addLifecycleListener(hostConfig); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - Service service = getService(pname); - Engine engine = (Engine) service.getContainer(); - engine.addChild(host); - - // Return the corresponding MBean name - return (host.getObjectName().toString()); - - } - - - /** - * Create a new StandardManager. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createStandardManager(String parent) - throws Exception { - - // Create a new StandardManager instance - StandardManager manager = new StandardManager(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - if (containerBase != null) { - containerBase.setManager(manager); - } - ObjectName oname = manager.getObjectName(); - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - } - - - /** - * Create a new StandardService. - * - * @param parent MBean Name of the associated parent component - * @param name Unique name of this StandardService - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createStandardService(String parent, String name, String domain) - throws Exception { - - // Create a new StandardService instance - StandardService service = new StandardService(); - service.setName(name); - - // Add the new instance to its parent component - Server server = ServerFactory.getServer(); - server.addService(service); - - // Return the corresponding MBean name - return (service.getObjectName().toString()); - - } - - - - /** - * Create a new UserDatabaseRealm. - * - * @param parent MBean Name of the associated parent component - * @param resourceName Global JNDI resource name of the associated - * UserDatabase - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createUserDatabaseRealm(String parent, String resourceName) - throws Exception { - - // Create a new UserDatabaseRealm instance - UserDatabaseRealm realm = new UserDatabaseRealm(); - realm.setResourceName(resourceName); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - // Add the new instance to its parent component - containerBase.setRealm(realm); - // Return the corresponding MBean name - ObjectName oname = realm.getObjectName(); - // FIXME getObjectName() returns null - //ObjectName oname = - // MBeanUtils.createObjectName(pname.getDomain(), realm); - if (oname != null) { - return (oname.toString()); - } else { - return null; - } - - } - - - /** - * Create a new Web Application Loader. - * - * @param parent MBean Name of the associated parent component - * - * @exception Exception if an MBean cannot be created or registered - */ - public String createWebappLoader(String parent) - throws Exception { - - // Create a new WebappLoader instance - WebappLoader loader = new WebappLoader(); - - // Add the new instance to its parent component - ObjectName pname = new ObjectName(parent); - ContainerBase containerBase = getParentContainerFromParent(pname); - if (containerBase != null) { - containerBase.setLoader(loader); - } - // FIXME add Loader.getObjectName - //ObjectName oname = loader.getObjectName(); - ObjectName oname = - MBeanUtils.createObjectName(pname.getDomain(), loader); - return (oname.toString()); - - } - - - /** - * Remove an existing Connector. - * - * @param name MBean Name of the component to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeConnector(String name) throws Exception { - - // Acquire a reference to the component to be removed - ObjectName oname = new ObjectName(name); - Server server = ServerFactory.getServer(); - Service service = getService(oname); - String port = oname.getKeyProperty("port"); - //String address = oname.getKeyProperty("address"); - - Connector conns[] = (Connector[]) service.findConnectors(); - - for (int i = 0; i < conns.length; i++) { - String connAddress = String.valueOf(conns[i].getProperty("address")); - String connPort = ""+conns[i].getPort(); - - // if (((address.equals("null")) && - if ((connAddress==null) && port.equals(connPort)) { - service.removeConnector(conns[i]); - conns[i].destroy(); - break; - } - // } else if (address.equals(connAddress)) - if (port.equals(connPort)) { - // Remove this component from its parent component - service.removeConnector(conns[i]); - conns[i].destroy(); - break; - } - } - - } - - - /** - * Remove an existing Context. - * - * @param contextName MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeContext(String contextName) throws Exception { - - // Acquire a reference to the component to be removed - ObjectName oname = new ObjectName(contextName); - String domain = oname.getDomain(); - StandardService service = (StandardService) getService(oname); - - Engine engine = (Engine) service.getContainer(); - String name = oname.getKeyProperty("name"); - name = name.substring(2); - int i = name.indexOf("/"); - String hostName = name.substring(0,i); - String path = name.substring(i); - ObjectName deployer = new ObjectName(domain+":type=Deployer,host="+ - hostName); - String pathStr = getPathStr(path); - if(mserver.isRegistered(deployer)) { - mserver.invoke(deployer,"addServiced", - new Object[]{pathStr}, - new String[] {"java.lang.String"}); - mserver.invoke(deployer,"unmanageApp", - new Object[] {pathStr}, - new String[] {"java.lang.String"}); - mserver.invoke(deployer,"removeServiced", - new Object[] {pathStr}, - new String[] {"java.lang.String"}); - } else { - log.warn("Deployer not found for "+hostName); - Host host = (Host) engine.findChild(hostName); - Context context = (Context) host.findChild(pathStr); - // Remove this component from its parent component - host.removeChild(context); - if(context instanceof StandardContext) - try { - ((StandardContext)context).destroy(); - } catch (Exception e) { - log.warn("Error during context [" + context.getName() + "] destroy ", e); - } - - } - - } - - - /** - * Remove an existing Host. - * - * @param name MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeHost(String name) throws Exception { - - // Acquire a reference to the component to be removed - ObjectName oname = new ObjectName(name); - String hostName = oname.getKeyProperty("host"); - Service service = getService(oname); - Engine engine = (Engine) service.getContainer(); - Host host = (Host) engine.findChild(hostName); - - // Remove this component from its parent component - if(host!=null) { - if(host instanceof StandardHost) - ((StandardHost)host).destroy(); - else - engine.removeChild(host); - } - - } - - - /** - * Remove an existing Loader. - * - * @param name MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeLoader(String name) throws Exception { - - ObjectName oname = new ObjectName(name); - // Acquire a reference to the component to be removed - ContainerBase container = getParentContainerFromChild(oname); - container.setLoader(null); - - } - - - /** - * Remove an existing Manager. - * - * @param name MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeManager(String name) throws Exception { - - ObjectName oname = new ObjectName(name); - // Acquire a reference to the component to be removed - ContainerBase container = getParentContainerFromChild(oname); - container.setManager(null); - - } - - - /** - * Remove an existing Realm. - * - * @param name MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeRealm(String name) throws Exception { - - ObjectName oname = new ObjectName(name); - // Acquire a reference to the component to be removed - ContainerBase container = getParentContainerFromChild(oname); - container.setRealm(null); - } - - - /** - * Remove an existing Service. - * - * @param name MBean Name of the component to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeService(String name) throws Exception { - - // Acquire a reference to the component to be removed - ObjectName oname = new ObjectName(name); - String serviceName = oname.getKeyProperty("serviceName"); - Server server = ServerFactory.getServer(); - Service service = server.findService(serviceName); - - // Remove this component from its parent component - server.removeService(service); - - } - - - /** - * Remove an existing Valve. - * - * @param name MBean Name of the comonent to remove - * - * @exception Exception if a component cannot be removed - */ - public void removeValve(String name) throws Exception { - - // Acquire a reference to the component to be removed - ObjectName oname = new ObjectName(name); - ContainerBase container = getParentContainerFromChild(oname); - String sequence = oname.getKeyProperty("seq"); - Valve[] valves = (Valve[])container.getValves(); - for (int i = 0; i < valves.length; i++) { - ObjectName voname = ((ValveBase) valves[i]).getObjectName(); - if (voname.equals(oname)) { - container.removeValve(valves[i]); - } - } - } - -} - +/* + * Copyright 1999-2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + +import java.io.File; +import java.util.Vector; + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Server; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.Service; +import org.apache.catalina.Valve; +import org.apache.catalina.authenticator.SingleSignOn; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.ContainerBase; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.core.StandardEngine; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.core.StandardService; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.realm.DataSourceRealm; +import org.apache.catalina.realm.JDBCRealm; +import org.apache.catalina.realm.JNDIRealm; +import org.apache.catalina.realm.MemoryRealm; +import org.apache.catalina.realm.UserDatabaseRealm; +import org.apache.catalina.session.StandardManager; +import org.apache.catalina.startup.ContextConfig; +import org.apache.catalina.startup.HostConfig; +import org.apache.catalina.valves.AccessLogValve; +import org.apache.catalina.valves.RemoteAddrValve; +import org.apache.catalina.valves.RemoteHostValve; +import org.apache.catalina.valves.RequestDumperValve; +import org.apache.catalina.valves.ValveBase; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.Registry; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardServer component.

    + * + * @author Amy Roh + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + */ + +public class MBeanFactory extends BaseModelMBean { + + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(MBeanFactory.class); + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = MBeanUtils.createServer(); + + /** + * The configuration information registry for our managed beans. + */ + private static Registry registry = MBeanUtils.createRegistry(); + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public MBeanFactory() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + + + // ------------------------------------------------------------- Operations + + + /** + * Return the managed bean definition for the specified bean type + * + * @param type MBean type + */ + public String findObjectName(String type) { + + if (type.equals("org.apache.catalina.core.StandardContext")) { + return "StandardContext"; + } else if (type.equals("org.apache.catalina.core.StandardEngine")) { + return "Engine"; + } else if (type.equals("org.apache.catalina.core.StandardHost")) { + return "Host"; + } else { + return null; + } + + } + + + /** + * Little convenience method to remove redundant code + * when retrieving the path string + * + * @param t path string + * @return empty string if t==null || t.equals("/") + */ + private final String getPathStr(String t) { + if (t == null || t.equals("/")) { + return ""; + } + return t; + } + + /** + * Get Parent ContainerBase to add its child component + * from parent's ObjectName + */ + private ContainerBase getParentContainerFromParent(ObjectName pname) + throws Exception { + + String type = pname.getKeyProperty("type"); + String j2eeType = pname.getKeyProperty("j2eeType"); + Service service = getService(pname); + StandardEngine engine = (StandardEngine) service.getContainer(); + if ((j2eeType!=null) && (j2eeType.equals("WebModule"))) { + String name = pname.getKeyProperty("name"); + name = name.substring(2); + int i = name.indexOf("/"); + String hostName = name.substring(0,i); + String path = name.substring(i); + Host host = (Host) engine.findChild(hostName); + String pathStr = getPathStr(path); + StandardContext context = (StandardContext)host.findChild(pathStr); + return context; + } else if (type != null) { + if (type.equals("Engine")) { + return engine; + } else if (type.equals("Host")) { + String hostName = pname.getKeyProperty("host"); + StandardHost host = (StandardHost) engine.findChild(hostName); + return host; + } + } + return null; + + } + + + /** + * Get Parent ContainerBase to add its child component + * from child component's ObjectName as a String + */ + private ContainerBase getParentContainerFromChild(ObjectName oname) + throws Exception { + + String hostName = oname.getKeyProperty("host"); + String path = oname.getKeyProperty("path"); + Service service = getService(oname); + StandardEngine engine = (StandardEngine) service.getContainer(); + if (hostName == null) { + // child's container is Engine + return engine; + } else if (path == null) { + // child's container is Host + StandardHost host = (StandardHost) engine.findChild(hostName); + return host; + } else { + // child's container is Context + StandardHost host = (StandardHost) engine.findChild(hostName); + path = getPathStr(path); + StandardContext context = (StandardContext) host.findChild(path); + return context; + } + } + + + private Service getService(ObjectName oname) throws Exception { + + String domain = oname.getDomain(); + Server server = ServerFactory.getServer(); + Service[] services = server.findServices(); + StandardService service = null; + for (int i = 0; i < services.length; i++) { + service = (StandardService) services[i]; + if (domain.equals(service.getObjectName().getDomain())) { + break; + } + } + if (!service.getObjectName().getDomain().equals(domain)) { + throw new Exception("Service with the domain is not found"); + } + return service; + + } + + + /** + * Create a new AccessLoggerValve. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createAccessLoggerValve(String parent) + throws Exception { + + ObjectName pname = new ObjectName(parent); + // Create a new AccessLogValve instance + AccessLogValve accessLogger = new AccessLogValve(); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.addValve(accessLogger); + ObjectName oname = accessLogger.getObjectName(); + return (oname.toString()); + + } + + + /** + * Create a new AjpConnector + * + * @param parent MBean Name of the associated parent component + * @param address The IP address on which to bind + * @param port TCP port number to listen on + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createAjpConnector(String parent, String address, int port) + throws Exception { + + return createConnector(parent, address, port, true, false); + } + + /** + * Create a new DataSource Realm. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createDataSourceRealm(String parent, String dataSourceName, + String roleNameCol, String userCredCol, String userNameCol, + String userRoleTable, String userTable) throws Exception { + + // Create a new DataSourceRealm instance + DataSourceRealm realm = new DataSourceRealm(); + realm.setDataSourceName(dataSourceName); + realm.setRoleNameCol(roleNameCol); + realm.setUserCredCol(userCredCol); + realm.setUserNameCol(userNameCol); + realm.setUserRoleTable(userRoleTable); + realm.setUserTable(userTable); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.setRealm(realm); + // Return the corresponding MBean name + ObjectName oname = realm.getObjectName(); + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + } + + /** + * Create a new HttpConnector + * + * @param parent MBean Name of the associated parent component + * @param address The IP address on which to bind + * @param port TCP port number to listen on + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createHttpConnector(String parent, String address, int port) + throws Exception { + return createConnector(parent, address, port, false, false); + } + + /** + * Create a new Connector + * + * @param parent MBean Name of the associated parent component + * @param address The IP address on which to bind + * @param port TCP port number to listen on + * @param isAjp Create a AJP/1.3 Connector + * @param isSSL Create a secure Connector + * + * @exception Exception if an MBean cannot be created or registered + */ + private String createConnector(String parent, String address, int port, boolean isAjp, boolean isSSL) + throws Exception { + Connector retobj = new Connector(); + if ((address!=null) && (address.length()>0)) { + retobj.setProperty("address", address); + } + // Set port number + retobj.setPort(port); + // Set the protocol + retobj.setProtocol(isAjp ? "AJP/1.3" : "HTTP/1.1"); + // Set SSL + retobj.setSecure(isSSL); + retobj.setScheme(isSSL ? "https" : "http"); + // Add the new instance to its parent component + // FIX ME - addConnector will fail + ObjectName pname = new ObjectName(parent); + Service service = getService(pname); + service.addConnector(retobj); + + // Return the corresponding MBean name + ObjectName coname = retobj.getObjectName(); + + return (coname.toString()); + } + + + /** + * Create a new HttpsConnector + * + * @param parent MBean Name of the associated parent component + * @param address The IP address on which to bind + * @param port TCP port number to listen on + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createHttpsConnector(String parent, String address, int port) + throws Exception { + return createConnector(parent, address, port, false, true); + } + + /** + * Create a new JDBC Realm. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createJDBCRealm(String parent, String driverName, + String connectionName, String connectionPassword, String connectionURL) + throws Exception { + + // Create a new JDBCRealm instance + JDBCRealm realm = new JDBCRealm(); + realm.setDriverName(driverName); + realm.setConnectionName(connectionName); + realm.setConnectionPassword(connectionPassword); + realm.setConnectionURL(connectionURL); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.setRealm(realm); + // Return the corresponding MBean name + ObjectName oname = realm.getObjectName(); + + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + } + + + /** + * Create a new JNDI Realm. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createJNDIRealm(String parent) + throws Exception { + + // Create a new JNDIRealm instance + JNDIRealm realm = new JNDIRealm(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.setRealm(realm); + // Return the corresponding MBean name + ObjectName oname = realm.getObjectName(); + + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + + } + + + /** + * Create a new Memory Realm. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createMemoryRealm(String parent) + throws Exception { + + // Create a new MemoryRealm instance + MemoryRealm realm = new MemoryRealm(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.setRealm(realm); + // Return the corresponding MBean name + ObjectName oname = realm.getObjectName(); + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + } + + + /** + * Create a new Remote Address Filter Valve. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createRemoteAddrValve(String parent) + throws Exception { + + // Create a new RemoteAddrValve instance + RemoteAddrValve valve = new RemoteAddrValve(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + containerBase.addValve(valve); + ObjectName oname = valve.getObjectName(); + return (oname.toString()); + + } + + + /** + * Create a new Remote Host Filter Valve. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createRemoteHostValve(String parent) + throws Exception { + + // Create a new RemoteHostValve instance + RemoteHostValve valve = new RemoteHostValve(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + containerBase.addValve(valve); + ObjectName oname = valve.getObjectName(); + return (oname.toString()); + + } + + + /** + * Create a new Request Dumper Valve. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createRequestDumperValve(String parent) + throws Exception { + + // Create a new RequestDumperValve instance + RequestDumperValve valve = new RequestDumperValve(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + containerBase.addValve(valve); + ObjectName oname = valve.getObjectName(); + return (oname.toString()); + + } + + + /** + * Create a new Single Sign On Valve. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createSingleSignOn(String parent) + throws Exception { + + // Create a new SingleSignOn instance + SingleSignOn valve = new SingleSignOn(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + containerBase.addValve(valve); + ObjectName oname = valve.getObjectName(); + return (oname.toString()); + + } + + + /** + * Create a new StandardContext. + * + * @param parent MBean Name of the associated parent component + * @param path The context path for this Context + * @param docBase Document base directory (or WAR) for this Context + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createStandardContext(String parent, + String path, + String docBase) + throws Exception { + + // XXX for backward compatibility. Remove it once supported by the admin + return + createStandardContext(parent,path,docBase,false,false,false,false); + } + + /** + * Given a context path, get the config file name. + */ + private String getConfigFile(String path) { + String basename = null; + if (path.equals("")) { + basename = "ROOT"; + } else { + basename = path.substring(1).replace('/', '#'); + } + return (basename); + } + + /** + * Create a new StandardContext. + * + * @param parent MBean Name of the associated parent component + * @param path The context path for this Context + * @param docBase Document base directory (or WAR) for this Context + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createStandardContext(String parent, + String path, + String docBase, + boolean xmlValidation, + boolean xmlNamespaceAware, + boolean tldValidation, + boolean tldNamespaceAware) + throws Exception { + + // Create a new StandardContext instance + StandardContext context = new StandardContext(); + path = getPathStr(path); + context.setPath(path); + context.setDocBase(docBase); + context.setXmlValidation(xmlValidation); + context.setXmlNamespaceAware(xmlNamespaceAware); + context.setTldValidation(tldValidation); + context.setTldNamespaceAware(tldNamespaceAware); + + ContextConfig contextConfig = new ContextConfig(); + context.addLifecycleListener(contextConfig); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ObjectName deployer = new ObjectName(pname.getDomain()+ + ":type=Deployer,host="+ + pname.getKeyProperty("host")); + if(mserver.isRegistered(deployer)) { + String contextPath = context.getPath(); + mserver.invoke(deployer, "addServiced", + new Object [] {contextPath}, + new String [] {"java.lang.String"}); + String configPath = (String)mserver.getAttribute(deployer, + "configBaseName"); + String baseName = getConfigFile(contextPath); + File configFile = new File(new File(configPath), baseName+".xml"); + context.setConfigFile(configFile.getAbsolutePath()); + mserver.invoke(deployer, "manageApp", + new Object[] {context}, + new String[] {"org.apache.catalina.Context"}); + mserver.invoke(deployer, "removeServiced", + new Object [] {contextPath}, + new String [] {"java.lang.String"}); + } else { + log.warn("Deployer not found for "+pname.getKeyProperty("host")); + Service service = getService(pname); + Engine engine = (Engine) service.getContainer(); + Host host = (Host) engine.findChild(pname.getKeyProperty("host")); + host.addChild(context); + } + + // Return the corresponding MBean name + ObjectName oname = context.getJmxName(); + + return (oname.toString()); + + } + + + /** + * Create a new StandardEngine. + * + * @param parent MBean Name of the associated parent component + * @param engineName Unique name of this Engine + * @param defaultHost Default hostname of this Engine + * @param serviceName Unique name of this Service + * + * @exception Exception if an MBean cannot be created or registered + */ + + public Vector createStandardEngineService(String parent, + String engineName, String defaultHost, String serviceName) + throws Exception { + + // Create a new StandardService instance + StandardService service = new StandardService(); + service.setName(serviceName); + // Create a new StandardEngine instance + StandardEngine engine = new StandardEngine(); + engine.setName(engineName); + engine.setDefaultHost(defaultHost); + // Need to set engine before adding it to server in order to set domain + service.setContainer(engine); + // Add the new instance to its parent component + Server server = ServerFactory.getServer(); + server.addService(service); + Vector onames = new Vector(); + // FIXME service & engine.getObjectName + //ObjectName oname = engine.getObjectName(); + ObjectName oname = + MBeanUtils.createObjectName(engineName, engine); + onames.add(0, oname); + //oname = service.getObjectName(); + oname = + MBeanUtils.createObjectName(engineName, service); + onames.add(1, oname); + return (onames); + + } + + + /** + * Create a new StandardHost. + * + * @param parent MBean Name of the associated parent component + * @param name Unique name of this Host + * @param appBase Application base directory name + * @param autoDeploy Should we auto deploy? + * @param deployOnStartup Deploy on server startup? + * @param deployXML Should we deploy Context XML config files property? + * @param unpackWARs Should we unpack WARs when auto deploying? + * @param xmlNamespaceAware Should we turn on/off XML namespace awareness? + * @param xmlValidation Should we turn on/off XML validation? + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createStandardHost(String parent, String name, + String appBase, + boolean autoDeploy, + boolean deployOnStartup, + boolean deployXML, + boolean unpackWARs, + boolean xmlNamespaceAware, + boolean xmlValidation) + throws Exception { + + // Create a new StandardHost instance + StandardHost host = new StandardHost(); + host.setName(name); + host.setAppBase(appBase); + host.setAutoDeploy(autoDeploy); + host.setDeployOnStartup(deployOnStartup); + host.setDeployXML(deployXML); + host.setUnpackWARs(unpackWARs); + host.setXmlNamespaceAware(xmlNamespaceAware); + host.setXmlValidation(xmlValidation); + + // add HostConfig for active reloading + HostConfig hostConfig = new HostConfig(); + host.addLifecycleListener(hostConfig); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + Service service = getService(pname); + Engine engine = (Engine) service.getContainer(); + engine.addChild(host); + + // Return the corresponding MBean name + return (host.getObjectName().toString()); + + } + + + /** + * Create a new StandardManager. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createStandardManager(String parent) + throws Exception { + + // Create a new StandardManager instance + StandardManager manager = new StandardManager(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + if (containerBase != null) { + containerBase.setManager(manager); + } + ObjectName oname = manager.getObjectName(); + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + } + + + /** + * Create a new StandardService. + * + * @param parent MBean Name of the associated parent component + * @param name Unique name of this StandardService + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createStandardService(String parent, String name, String domain) + throws Exception { + + // Create a new StandardService instance + StandardService service = new StandardService(); + service.setName(name); + + // Add the new instance to its parent component + Server server = ServerFactory.getServer(); + server.addService(service); + + // Return the corresponding MBean name + return (service.getObjectName().toString()); + + } + + + + /** + * Create a new UserDatabaseRealm. + * + * @param parent MBean Name of the associated parent component + * @param resourceName Global JNDI resource name of the associated + * UserDatabase + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createUserDatabaseRealm(String parent, String resourceName) + throws Exception { + + // Create a new UserDatabaseRealm instance + UserDatabaseRealm realm = new UserDatabaseRealm(); + realm.setResourceName(resourceName); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + // Add the new instance to its parent component + containerBase.setRealm(realm); + // Return the corresponding MBean name + ObjectName oname = realm.getObjectName(); + // FIXME getObjectName() returns null + //ObjectName oname = + // MBeanUtils.createObjectName(pname.getDomain(), realm); + if (oname != null) { + return (oname.toString()); + } else { + return null; + } + + } + + + /** + * Create a new Web Application Loader. + * + * @param parent MBean Name of the associated parent component + * + * @exception Exception if an MBean cannot be created or registered + */ + public String createWebappLoader(String parent) + throws Exception { + + // Create a new WebappLoader instance + WebappLoader loader = new WebappLoader(); + + // Add the new instance to its parent component + ObjectName pname = new ObjectName(parent); + ContainerBase containerBase = getParentContainerFromParent(pname); + if (containerBase != null) { + containerBase.setLoader(loader); + } + // FIXME add Loader.getObjectName + //ObjectName oname = loader.getObjectName(); + ObjectName oname = + MBeanUtils.createObjectName(pname.getDomain(), loader); + return (oname.toString()); + + } + + + /** + * Remove an existing Connector. + * + * @param name MBean Name of the component to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeConnector(String name) throws Exception { + + // Acquire a reference to the component to be removed + ObjectName oname = new ObjectName(name); + Server server = ServerFactory.getServer(); + Service service = getService(oname); + String port = oname.getKeyProperty("port"); + //String address = oname.getKeyProperty("address"); + + Connector conns[] = (Connector[]) service.findConnectors(); + + for (int i = 0; i < conns.length; i++) { + String connAddress = String.valueOf(conns[i].getProperty("address")); + String connPort = ""+conns[i].getPort(); + + // if (((address.equals("null")) && + if ((connAddress==null) && port.equals(connPort)) { + service.removeConnector(conns[i]); + conns[i].destroy(); + break; + } + // } else if (address.equals(connAddress)) + if (port.equals(connPort)) { + // Remove this component from its parent component + service.removeConnector(conns[i]); + conns[i].destroy(); + break; + } + } + + } + + + /** + * Remove an existing Context. + * + * @param contextName MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeContext(String contextName) throws Exception { + + // Acquire a reference to the component to be removed + ObjectName oname = new ObjectName(contextName); + String domain = oname.getDomain(); + StandardService service = (StandardService) getService(oname); + + Engine engine = (Engine) service.getContainer(); + String name = oname.getKeyProperty("name"); + name = name.substring(2); + int i = name.indexOf("/"); + String hostName = name.substring(0,i); + String path = name.substring(i); + ObjectName deployer = new ObjectName(domain+":type=Deployer,host="+ + hostName); + String pathStr = getPathStr(path); + if(mserver.isRegistered(deployer)) { + mserver.invoke(deployer,"addServiced", + new Object[]{pathStr}, + new String[] {"java.lang.String"}); + mserver.invoke(deployer,"unmanageApp", + new Object[] {pathStr}, + new String[] {"java.lang.String"}); + mserver.invoke(deployer,"removeServiced", + new Object[] {pathStr}, + new String[] {"java.lang.String"}); + } else { + log.warn("Deployer not found for "+hostName); + Host host = (Host) engine.findChild(hostName); + Context context = (Context) host.findChild(pathStr); + // Remove this component from its parent component + host.removeChild(context); + if(context instanceof StandardContext) + try { + ((StandardContext)context).destroy(); + } catch (Exception e) { + log.warn("Error during context [" + context.getName() + "] destroy ", e); + } + + } + + } + + + /** + * Remove an existing Host. + * + * @param name MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeHost(String name) throws Exception { + + // Acquire a reference to the component to be removed + ObjectName oname = new ObjectName(name); + String hostName = oname.getKeyProperty("host"); + Service service = getService(oname); + Engine engine = (Engine) service.getContainer(); + Host host = (Host) engine.findChild(hostName); + + // Remove this component from its parent component + if(host!=null) { + if(host instanceof StandardHost) + ((StandardHost)host).destroy(); + else + engine.removeChild(host); + } + + } + + + /** + * Remove an existing Loader. + * + * @param name MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeLoader(String name) throws Exception { + + ObjectName oname = new ObjectName(name); + // Acquire a reference to the component to be removed + ContainerBase container = getParentContainerFromChild(oname); + container.setLoader(null); + + } + + + /** + * Remove an existing Manager. + * + * @param name MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeManager(String name) throws Exception { + + ObjectName oname = new ObjectName(name); + // Acquire a reference to the component to be removed + ContainerBase container = getParentContainerFromChild(oname); + container.setManager(null); + + } + + + /** + * Remove an existing Realm. + * + * @param name MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeRealm(String name) throws Exception { + + ObjectName oname = new ObjectName(name); + // Acquire a reference to the component to be removed + ContainerBase container = getParentContainerFromChild(oname); + container.setRealm(null); + } + + + /** + * Remove an existing Service. + * + * @param name MBean Name of the component to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeService(String name) throws Exception { + + // Acquire a reference to the component to be removed + ObjectName oname = new ObjectName(name); + String serviceName = oname.getKeyProperty("serviceName"); + Server server = ServerFactory.getServer(); + Service service = server.findService(serviceName); + + // Remove this component from its parent component + server.removeService(service); + + } + + + /** + * Remove an existing Valve. + * + * @param name MBean Name of the comonent to remove + * + * @exception Exception if a component cannot be removed + */ + public void removeValve(String name) throws Exception { + + // Acquire a reference to the component to be removed + ObjectName oname = new ObjectName(name); + ContainerBase container = getParentContainerFromChild(oname); + String sequence = oname.getKeyProperty("seq"); + Valve[] valves = (Valve[])container.getValves(); + for (int i = 0; i < valves.length; i++) { + ObjectName voname = ((ValveBase) valves[i]).getObjectName(); + if (voname.equals(oname)) { + container.removeValve(valves[i]); + } + } + } + +} + diff --git a/java/org/apache/catalina/mbeans/MBeanUtils.java b/java/org/apache/catalina/mbeans/MBeanUtils.java index 62db99727..6acbe0b2d 100644 --- a/java/org/apache/catalina/mbeans/MBeanUtils.java +++ b/java/org/apache/catalina/mbeans/MBeanUtils.java @@ -1,1873 +1,1873 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.util.Hashtable; - -import javax.management.DynamicMBean; -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.modelmbean.ModelMBean; - -import org.apache.catalina.Contained; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Group; -import org.apache.catalina.Host; -import org.apache.catalina.Loader; -import org.apache.catalina.Manager; -import org.apache.catalina.Realm; -import org.apache.catalina.Role; -import org.apache.catalina.Server; -import org.apache.catalina.Service; -import org.apache.catalina.User; -import org.apache.catalina.UserDatabase; -import org.apache.catalina.Valve; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.catalina.valves.ValveBase; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Public utility methods in support of the server side MBeans implementation. - * - * @author Craig R. McClanahan - * @author Amy Roh - * @version $Revision: 303558 $ $Date: 2004-12-01 12:17:34 +0100 (mer., 01 déc. 2004) $ - */ - -public class MBeanUtils { - private static Log log = LogFactory.getLog(MBeanUtils.class); - - // ------------------------------------------------------- Static Variables - - - /** - * The set of exceptions to the normal rules used by - * createManagedBean(). The first element of each pair - * is a class name, and the second element is the managed bean name. - */ - private static String exceptions[][] = { - { "org.apache.ajp.tomcat4.Ajp13Connector", - "Ajp13Connector" }, - { "org.apache.coyote.tomcat4.Ajp13Connector", - "CoyoteConnector" }, - { "org.apache.catalina.users.JDBCGroup", - "Group" }, - { "org.apache.catalina.users.JDBCRole", - "Role" }, - { "org.apache.catalina.users.JDBCUser", - "User" }, - { "org.apache.catalina.users.MemoryGroup", - "Group" }, - { "org.apache.catalina.users.MemoryRole", - "Role" }, - { "org.apache.catalina.users.MemoryUser", - "User" }, - }; - - - /** - * The configuration information registry for our managed beans. - */ - private static Registry registry = createRegistry(); - - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = createServer(); - - - // --------------------------------------------------------- Static Methods - - /** - * Create and return the name of the ManagedBean that - * corresponds to this Catalina component. - * - * @param component The component for which to create a name - */ - static String createManagedName(Object component) { - - // Deal with exceptions to the standard rule - String className = component.getClass().getName(); - for (int i = 0; i < exceptions.length; i++) { - if (className.equals(exceptions[i][0])) { - return (exceptions[i][1]); - } - } - - // Perform the standard transformation - int period = className.lastIndexOf('.'); - if (period >= 0) - className = className.substring(period + 1); - return (className); - - } - - - /** - * Create, register, and return an MBean for this - * Connector object. - * - * @param connector The Connector to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Connector connector) - throws Exception { - - String mname = createManagedName(connector); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(connector); - ObjectName oname = createObjectName(domain, connector); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Context object. - * - * @param context The Context to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Context context) - throws Exception { - - String mname = createManagedName(context); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(context); - ObjectName oname = createObjectName(domain, context); - if( mserver.isRegistered(oname)) { - log.debug("Already registered " + oname); - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * ContextEnvironment object. - * - * @param environment The ContextEnvironment to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(ContextEnvironment environment) - throws Exception { - - String mname = createManagedName(environment); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(environment); - ObjectName oname = createObjectName(domain, environment); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * ContextResource object. - * - * @param resource The ContextResource to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(ContextResource resource) - throws Exception { - - String mname = createManagedName(resource); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(resource); - ObjectName oname = createObjectName(domain, resource); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * ContextResourceLink object. - * - * @param resourceLink The ContextResourceLink to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(ContextResourceLink resourceLink) - throws Exception { - - String mname = createManagedName(resourceLink); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(resourceLink); - ObjectName oname = createObjectName(domain, resourceLink); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - /** - * Create, register, and return an MBean for this - * Engine object. - * - * @param engine The Engine to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Engine engine) - throws Exception { - - String mname = createManagedName(engine); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(engine); - ObjectName oname = createObjectName(domain, engine); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Group object. - * - * @param group The Group to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Group group) - throws Exception { - - String mname = createManagedName(group); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(group); - ObjectName oname = createObjectName(domain, group); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Host object. - * - * @param host The Host to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Host host) - throws Exception { - - String mname = createManagedName(host); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(host); - ObjectName oname = createObjectName(domain, host); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Loader object. - * - * @param loader The Loader to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Loader loader) - throws Exception { - - String mname = createManagedName(loader); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(loader); - ObjectName oname = createObjectName(domain, loader); - if( mserver.isRegistered( oname )) { - // side effect: stop it - mserver.unregisterMBean( oname ); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - /** - * Create, register, and return an MBean for this - * Manager object. - * - * @param manager The Manager to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Manager manager) - throws Exception { - - String mname = createManagedName(manager); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(manager); - ObjectName oname = createObjectName(domain, manager); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * MBeanFactory object. - * - * @param factory The MBeanFactory to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(MBeanFactory factory) - throws Exception { - - String mname = createManagedName(factory); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(factory); - ObjectName oname = createObjectName(domain, factory); - if( mserver.isRegistered(oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * NamingResources object. - * - * @param resource The NamingResources to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(NamingResources resource) - throws Exception { - - String mname = createManagedName(resource); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(resource); - ObjectName oname = createObjectName(domain, resource); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Realm object. - * - * @param realm The Realm to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Realm realm) - throws Exception { - - String mname = createManagedName(realm); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(realm); - ObjectName oname = createObjectName(domain, realm); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Role object. - * - * @param role The Role to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Role role) - throws Exception { - - String mname = createManagedName(role); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(role); - ObjectName oname = createObjectName(domain, role); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Server object. - * - * @param server The Server to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Server server) - throws Exception { - - String mname = createManagedName(server); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(server); - ObjectName oname = createObjectName(domain, server); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Service object. - * - * @param service The Service to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Service service) - throws Exception { - - String mname = createManagedName(service); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(service); - ObjectName oname = createObjectName(domain, service); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * User object. - * - * @param user The User to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(User user) - throws Exception { - - String mname = createManagedName(user); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(user); - ObjectName oname = createObjectName(domain, user); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * UserDatabase object. - * - * @param userDatabase The UserDatabase to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(UserDatabase userDatabase) - throws Exception { - - String mname = createManagedName(userDatabase); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(userDatabase); - ObjectName oname = createObjectName(domain, userDatabase); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - - /** - * Create, register, and return an MBean for this - * Valve object. - * - * @param valve The Valve to be managed - * - * @exception Exception if an MBean cannot be created or registered - */ - static DynamicMBean createMBean(Valve valve) - throws Exception { - - String mname = createManagedName(valve); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - Exception e = new Exception("ManagedBean is not found with "+mname); - throw new MBeanException(e); - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - DynamicMBean mbean = managed.createMBean(valve); - ObjectName oname = createObjectName(domain, valve); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - mserver.registerMBean(mbean, oname); - return (mbean); - - } - - /** - * Create an ObjectName for this - * Connector object. - * - * @param domain Domain in which this name is to be created - * @param connector The Connector to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Connector connector) - throws MalformedObjectNameException { - - ObjectName name = null; - if (connector.getClass().getName().indexOf("CoyoteConnector") >= 0 ) { - try { - String address = (String) - IntrospectionUtils.getProperty(connector, "address"); - Integer port = (Integer) - IntrospectionUtils.getProperty(connector, "port"); - Service service = connector.getService(); - String serviceName = null; - if (service != null) - serviceName = service.getName(); - StringBuffer sb = new StringBuffer(domain); - sb.append(":type=Connector"); - sb.append(",port=" + port); - if ((address != null) && (address.length()>0)) { - sb.append(",address=" + address); - } - name = new ObjectName(sb.toString()); - return (name); - } catch (Exception e) { - throw new MalformedObjectNameException - ("Cannot create object name for " + connector+e); - } - } else { - throw new MalformedObjectNameException - ("Cannot create object name for " + connector); - } - - } - - - /** - * Create an ObjectName for this - * Context object. - * - * @param domain Domain in which this name is to be created - * @param context The Context to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Context context) - throws MalformedObjectNameException { - - ObjectName name = null; - Host host = (Host)context.getParent(); - Service service = ((Engine)host.getParent()).getService(); - String path = context.getPath(); - if (path.length() < 1) - path = "/"; - // FIXME - name = new ObjectName(domain + ":j2eeType=WebModule,name=//" + - host.getName()+ path + - ",J2EEApplication=none,J2EEServer=none"); - - return (name); - - } - - - /** - * Create an ObjectName for this - * Service object. - * - * @param domain Domain in which this name is to be created - * @param environment The ContextEnvironment to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - public static ObjectName createObjectName(String domain, - ContextEnvironment environment) - throws MalformedObjectNameException { - - ObjectName name = null; - Object container = - environment.getNamingResources().getContainer(); - if (container instanceof Server) { - name = new ObjectName(domain + ":type=Environment" + - ",resourcetype=Global,name=" + environment.getName()); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) - path = "/"; - Host host = (Host) ((Context)container).getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Environment" + - ",resourcetype=Context,path=" + path + - ",host=" + host.getName() + - ",name=" + environment.getName()); - } - return (name); - - } - - - /** - * Create an ObjectName for this - * ContextResource object. - * - * @param domain Domain in which this name is to be created - * @param resource The ContextResource to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - public static ObjectName createObjectName(String domain, - ContextResource resource) - throws MalformedObjectNameException { - - ObjectName name = null; - String quotedResourceName = ObjectName.quote(resource.getName()); - Object container = - resource.getNamingResources().getContainer(); - if (container instanceof Server) { - name = new ObjectName(domain + ":type=Resource" + - ",resourcetype=Global,class=" + resource.getType() + - ",name=" + quotedResourceName); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) - path = "/"; - Host host = (Host) ((Context)container).getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Resource" + - ",resourcetype=Context,path=" + path + - ",host=" + host.getName() + - ",class=" + resource.getType() + - ",name=" + quotedResourceName); - } - - return (name); - - } - - - /** - * Create an ObjectName for this - * ContextResourceLink object. - * - * @param domain Domain in which this name is to be created - * @param resourceLink The ContextResourceLink to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - public static ObjectName createObjectName(String domain, - ContextResourceLink resourceLink) - throws MalformedObjectNameException { - - ObjectName name = null; - String quotedResourceLinkName - = ObjectName.quote(resourceLink.getName()); - Object container = - resourceLink.getNamingResources().getContainer(); - if (container instanceof Server) { - name = new ObjectName(domain + ":type=ResourceLink" + - ",resourcetype=Global" + - ",name=" + quotedResourceLinkName); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) - path = "/"; - Host host = (Host) ((Context)container).getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=ResourceLink" + - ",resourcetype=Context,path=" + path + - ",host=" + host.getName() + - ",name=" + quotedResourceLinkName); - } - - return (name); - - } - - - - /** - * Create an ObjectName for this - * Engine object. - * - * @param domain Domain in which this name is to be created - * @param engine The Engine to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Engine engine) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=Engine"); - return (name); - - } - - - /** - * Create an ObjectName for this - * Group object. - * - * @param domain Domain in which this name is to be created - * @param group The Group to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Group group) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=Group,groupname=" + - ObjectName.quote(group.getGroupname()) + - ",database=" + group.getUserDatabase().getId()); - return (name); - - } - - - /** - * Create an ObjectName for this - * Host object. - * - * @param domain Domain in which this name is to be created - * @param host The Host to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Host host) - throws MalformedObjectNameException { - - ObjectName name = null; - Engine engine = (Engine)host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Host,host=" + - host.getName()); - return (name); - - } - - - /** - * Create an ObjectName for this - * Loader object. - * - * @param domain Domain in which this name is to be created - * @param loader The Loader to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Loader loader) - throws MalformedObjectNameException { - - ObjectName name = null; - Container container = loader.getContainer(); - - if (container instanceof Engine) { - Service service = ((Engine)container).getService(); - name = new ObjectName(domain + ":type=Loader"); - } else if (container instanceof Host) { - Engine engine = (Engine) container.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Loader,host=" + - container.getName()); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) container.getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Loader,path=" + path + - ",host=" + host.getName()); - } - - return (name); - - } - - - /** - * Create an ObjectName for this - * Manager object. - * - * @param domain Domain in which this name is to be created - * @param manager The Manager to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Manager manager) - throws MalformedObjectNameException { - - ObjectName name = null; - Container container = manager.getContainer(); - - if (container instanceof Engine) { - Service service = ((Engine)container).getService(); - name = new ObjectName(domain + ":type=Manager"); - } else if (container instanceof Host) { - Engine engine = (Engine) container.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Manager,host=" + - container.getName()); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) container.getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Manager,path=" + path + - ",host=" + host.getName()); - } - - return (name); - - } - - - /** - * Create an ObjectName for this - * Server object. - * - * @param domain Domain in which this name is to be created - * @param resources The NamingResources to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - NamingResources resources) - throws MalformedObjectNameException { - - ObjectName name = null; - Object container = resources.getContainer(); - if (container instanceof Server) { - name = new ObjectName(domain + ":type=NamingResources" + - ",resourcetype=Global"); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) - path = "/"; - Host host = (Host) ((Context)container).getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=NamingResources" + - ",resourcetype=Context,path=" + path + - ",host=" + host.getName()); - } - - return (name); - - } - - - /** - * Create an ObjectName for this - * MBeanFactory object. - * - * @param domain Domain in which this name is to be created - * @param factory The MBeanFactory to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - MBeanFactory factory) - throws MalformedObjectNameException { - - ObjectName name = new ObjectName(domain + ":type=MBeanFactory"); - - return (name); - - } - - - /** - * Create an ObjectName for this - * Realm object. - * - * @param domain Domain in which this name is to be created - * @param realm The Realm to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Realm realm) - throws MalformedObjectNameException { - - ObjectName name = null; - Container container = realm.getContainer(); - - if (container instanceof Engine) { - Service service = ((Engine)container).getService(); - name = new ObjectName(domain + ":type=Realm"); - } else if (container instanceof Host) { - Engine engine = (Engine) container.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Realm,host=" + - container.getName()); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) container.getParent(); - Engine engine = (Engine) host.getParent(); - Service service = engine.getService(); - name = new ObjectName(domain + ":type=Realm,path=" + path + - ",host=" + host.getName()); - } - - return (name); - - } - - - /** - * Create an ObjectName for this - * Role object. - * - * @param domain Domain in which this name is to be created - * @param role The Role to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Role role) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=Role,rolename=" + - role.getRolename() + ",database=" + - role.getUserDatabase().getId()); - return (name); - - } - - - /** - * Create an ObjectName for this - * Server object. - * - * @param domain Domain in which this name is to be created - * @param server The Server to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Server server) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=Server"); - return (name); - - } - - - /** - * Create an ObjectName for this - * Service object. - * - * @param domain Domain in which this name is to be created - * @param service The Service to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Service service) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=Service,serviceName=" + - service.getName()); - return (name); - - } - - - /** - * Create an ObjectName for this - * User object. - * - * @param domain Domain in which this name is to be created - * @param user The User to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - User user) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=User,username=" + - ObjectName.quote(user.getUsername()) - + ",database=" + user.getUserDatabase().getId()); - return (name); - - } - - - /** - * Create an ObjectName for this - * UserDatabase object. - * - * @param domain Domain in which this name is to be created - * @param userDatabase The UserDatabase to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - UserDatabase userDatabase) - throws MalformedObjectNameException { - - ObjectName name = null; - name = new ObjectName(domain + ":type=UserDatabase,database=" + - userDatabase.getId()); - return (name); - - } - - - /** - * Create an ObjectName for this - * Valve object. - * - * @param domain Domain in which this name is to be created - * @param valve The Valve to be named - * - * @exception MalformedObjectNameException if a name cannot be created - */ - static ObjectName createObjectName(String domain, - Valve valve) - throws MalformedObjectNameException { - if( valve instanceof ValveBase ) { - ObjectName name=((ValveBase)valve).getObjectName(); - if( name != null ) - return name; - } - - ObjectName name = null; - Container container = null; - String className=valve.getClass().getName(); - int period = className.lastIndexOf('.'); - if (period >= 0) - className = className.substring(period + 1); - if( valve instanceof Contained ) { - container = ((Contained)valve).getContainer(); - } - if( container == null ) { - throw new MalformedObjectNameException( - "Cannot create mbean for non-contained valve " + - valve); - } - if (container instanceof Engine) { - Service service = ((Engine)container).getService(); - String local=""; - int seq = getSeq(local); - String ext=""; - if( seq > 0 ) { - ext=",seq=" + seq; - } - name = new ObjectName(domain + ":type=Valve,name=" + className + - ext + local ); - } else if (container instanceof Host) { - Service service = ((Engine)container.getParent()).getService(); - String local=",host=" +container.getName(); - int seq = getSeq(local); - String ext=""; - if( seq > 0 ) { - ext=",seq=" + seq; - } - name = new ObjectName(domain + ":type=Valve,name=" + className + - ext + local ); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) container.getParent(); - Service service = ((Engine) host.getParent()).getService(); - String local=",path=" + path + ",host=" + - host.getName(); - int seq = getSeq(local); - String ext=""; - if( seq > 0 ) { - ext=",seq=" + seq; - } - name = new ObjectName(domain + ":type=Valve,name=" + className + - ext + local ); - } - - return (name); - - } - - static Hashtable seq=new Hashtable(); - static int getSeq( String key ) { - int i[]=(int [])seq.get( key ); - if (i == null ) { - i=new int[1]; - i[0]=0; - seq.put( key, i); - } else { - i[0]++; - } - return i[0]; - } - - /** - * Create and configure (if necessary) and return the registry of - * managed object descriptions. - */ - public synchronized static Registry createRegistry() { - - if (registry == null) { - registry = Registry.getRegistry(null, null); - ClassLoader cl=ServerLifecycleListener.class.getClassLoader(); - - registry.loadDescriptors("org.apache.catalina.mbeans", cl); - registry.loadDescriptors("org.apache.catalina.authenticator", cl); - registry.loadDescriptors("org.apache.catalina.core", cl); - registry.loadDescriptors("org.apache.catalina", cl); - registry.loadDescriptors("org.apache.catalina.deploy", cl); - registry.loadDescriptors("org.apache.catalina.loader", cl); - registry.loadDescriptors("org.apache.catalina.realm", cl); - registry.loadDescriptors("org.apache.catalina.session", cl); - registry.loadDescriptors("org.apache.catalina.startup", cl); - registry.loadDescriptors("org.apache.catalina.users", cl); - registry.loadDescriptors("org.apache.catalina.cluster", cl); - registry.loadDescriptors("org.apache.catalina.connector", cl); - registry.loadDescriptors("org.apache.catalina.valves", cl); - } - return (registry); - - } - - - /** - * Create and configure (if necessary) and return the - * MBeanServer with which we will be - * registering our DynamicMBean implementations. - */ - public synchronized static MBeanServer createServer() { - - if (mserver == null) { - try { - mserver = Registry.getRegistry(null, null).getMBeanServer(); - } catch (Throwable t) { - t.printStackTrace(System.out); - System.exit(1); - } - } - return (mserver); - - } - - - /** - * Deregister the MBean for this - * Connector object. - * - * @param connector The Connector to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Connector connector, Service service) - throws Exception { - - connector.setService(service); - String mname = createManagedName(connector); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, connector); - connector.setService(null); - if( mserver.isRegistered( oname )) { - mserver.unregisterMBean(oname); - } - } - - - /** - * Deregister the MBean for this - * Context object. - * - * @param context The Context to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Context context) - throws Exception { - - String mname = createManagedName(context); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, context); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * ContextEnvironment object. - * - * @param environment The ContextEnvironment to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(ContextEnvironment environment) - throws Exception { - - String mname = createManagedName(environment); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, environment); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * ContextResource object. - * - * @param resource The ContextResource to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(ContextResource resource) - throws Exception { - - String mname = createManagedName(resource); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, resource); - if( mserver.isRegistered(oname )) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * ContextResourceLink object. - * - * @param resourceLink The ContextResourceLink to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(ContextResourceLink resourceLink) - throws Exception { - - String mname = createManagedName(resourceLink); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, resourceLink); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - /** - * Deregister the MBean for this - * Engine object. - * - * @param engine The Engine to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Engine engine) - throws Exception { - - String mname = createManagedName(engine); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, engine); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Group object. - * - * @param group The Group to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Group group) - throws Exception { - - String mname = createManagedName(group); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, group); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Host object. - * - * @param host The Host to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Host host) - throws Exception { - - String mname = createManagedName(host); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, host); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Loader object. - * - * @param loader The Loader to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Loader loader) - throws Exception { - - String mname = createManagedName(loader); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, loader); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Manager object. - * - * @param manager The Manager to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Manager manager) - throws Exception { - - String mname = createManagedName(manager); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, manager); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * NamingResources object. - * - * @param resources The NamingResources to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(NamingResources resources) - throws Exception { - - String mname = createManagedName(resources); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, resources); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Realm object. - * - * @param realm The Realm to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Realm realm) - throws Exception { - - String mname = createManagedName(realm); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, realm); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Role object. - * - * @param role The Role to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Role role) - throws Exception { - - String mname = createManagedName(role); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, role); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Server object. - * - * @param server The Server to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Server server) - throws Exception { - - String mname = createManagedName(server); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, server); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Service object. - * - * @param service The Service to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Service service) - throws Exception { - - String mname = createManagedName(service); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, service); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * User object. - * - * @param user The User to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(User user) - throws Exception { - - String mname = createManagedName(user); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, user); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * UserDatabase object. - * - * @param userDatabase The UserDatabase to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(UserDatabase userDatabase) - throws Exception { - - String mname = createManagedName(userDatabase); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, userDatabase); - if( mserver.isRegistered(oname) ) - mserver.unregisterMBean(oname); - - } - - - /** - * Deregister the MBean for this - * Valve object. - * - * @param valve The Valve to be managed - * - * @exception Exception if an MBean cannot be deregistered - */ - static void destroyMBean(Valve valve, Container container) - throws Exception { - - ((Contained)valve).setContainer(container); - String mname = createManagedName(valve); - ManagedBean managed = registry.findManagedBean(mname); - if (managed == null) { - return; - } - String domain = managed.getDomain(); - if (domain == null) - domain = mserver.getDefaultDomain(); - ObjectName oname = createObjectName(domain, valve); - try { - ((Contained)valve).setContainer(null); - } catch (Throwable t) { - ; - } - if( mserver.isRegistered(oname) ) { - mserver.unregisterMBean(oname); - } - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.util.Hashtable; + +import javax.management.DynamicMBean; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.modelmbean.ModelMBean; + +import org.apache.catalina.Contained; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Group; +import org.apache.catalina.Host; +import org.apache.catalina.Loader; +import org.apache.catalina.Manager; +import org.apache.catalina.Realm; +import org.apache.catalina.Role; +import org.apache.catalina.Server; +import org.apache.catalina.Service; +import org.apache.catalina.User; +import org.apache.catalina.UserDatabase; +import org.apache.catalina.Valve; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.catalina.valves.ValveBase; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Public utility methods in support of the server side MBeans implementation. + * + * @author Craig R. McClanahan + * @author Amy Roh + * @version $Revision: 303558 $ $Date: 2004-12-01 12:17:34 +0100 (mer., 01 déc. 2004) $ + */ + +public class MBeanUtils { + private static Log log = LogFactory.getLog(MBeanUtils.class); + + // ------------------------------------------------------- Static Variables + + + /** + * The set of exceptions to the normal rules used by + * createManagedBean(). The first element of each pair + * is a class name, and the second element is the managed bean name. + */ + private static String exceptions[][] = { + { "org.apache.ajp.tomcat4.Ajp13Connector", + "Ajp13Connector" }, + { "org.apache.coyote.tomcat4.Ajp13Connector", + "CoyoteConnector" }, + { "org.apache.catalina.users.JDBCGroup", + "Group" }, + { "org.apache.catalina.users.JDBCRole", + "Role" }, + { "org.apache.catalina.users.JDBCUser", + "User" }, + { "org.apache.catalina.users.MemoryGroup", + "Group" }, + { "org.apache.catalina.users.MemoryRole", + "Role" }, + { "org.apache.catalina.users.MemoryUser", + "User" }, + }; + + + /** + * The configuration information registry for our managed beans. + */ + private static Registry registry = createRegistry(); + + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = createServer(); + + + // --------------------------------------------------------- Static Methods + + /** + * Create and return the name of the ManagedBean that + * corresponds to this Catalina component. + * + * @param component The component for which to create a name + */ + static String createManagedName(Object component) { + + // Deal with exceptions to the standard rule + String className = component.getClass().getName(); + for (int i = 0; i < exceptions.length; i++) { + if (className.equals(exceptions[i][0])) { + return (exceptions[i][1]); + } + } + + // Perform the standard transformation + int period = className.lastIndexOf('.'); + if (period >= 0) + className = className.substring(period + 1); + return (className); + + } + + + /** + * Create, register, and return an MBean for this + * Connector object. + * + * @param connector The Connector to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Connector connector) + throws Exception { + + String mname = createManagedName(connector); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(connector); + ObjectName oname = createObjectName(domain, connector); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Context object. + * + * @param context The Context to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Context context) + throws Exception { + + String mname = createManagedName(context); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(context); + ObjectName oname = createObjectName(domain, context); + if( mserver.isRegistered(oname)) { + log.debug("Already registered " + oname); + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * ContextEnvironment object. + * + * @param environment The ContextEnvironment to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(ContextEnvironment environment) + throws Exception { + + String mname = createManagedName(environment); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(environment); + ObjectName oname = createObjectName(domain, environment); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * ContextResource object. + * + * @param resource The ContextResource to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(ContextResource resource) + throws Exception { + + String mname = createManagedName(resource); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(resource); + ObjectName oname = createObjectName(domain, resource); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * ContextResourceLink object. + * + * @param resourceLink The ContextResourceLink to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(ContextResourceLink resourceLink) + throws Exception { + + String mname = createManagedName(resourceLink); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(resourceLink); + ObjectName oname = createObjectName(domain, resourceLink); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + /** + * Create, register, and return an MBean for this + * Engine object. + * + * @param engine The Engine to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Engine engine) + throws Exception { + + String mname = createManagedName(engine); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(engine); + ObjectName oname = createObjectName(domain, engine); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Group object. + * + * @param group The Group to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Group group) + throws Exception { + + String mname = createManagedName(group); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(group); + ObjectName oname = createObjectName(domain, group); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Host object. + * + * @param host The Host to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Host host) + throws Exception { + + String mname = createManagedName(host); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(host); + ObjectName oname = createObjectName(domain, host); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Loader object. + * + * @param loader The Loader to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Loader loader) + throws Exception { + + String mname = createManagedName(loader); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(loader); + ObjectName oname = createObjectName(domain, loader); + if( mserver.isRegistered( oname )) { + // side effect: stop it + mserver.unregisterMBean( oname ); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + /** + * Create, register, and return an MBean for this + * Manager object. + * + * @param manager The Manager to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Manager manager) + throws Exception { + + String mname = createManagedName(manager); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(manager); + ObjectName oname = createObjectName(domain, manager); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * MBeanFactory object. + * + * @param factory The MBeanFactory to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(MBeanFactory factory) + throws Exception { + + String mname = createManagedName(factory); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(factory); + ObjectName oname = createObjectName(domain, factory); + if( mserver.isRegistered(oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * NamingResources object. + * + * @param resource The NamingResources to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(NamingResources resource) + throws Exception { + + String mname = createManagedName(resource); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(resource); + ObjectName oname = createObjectName(domain, resource); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Realm object. + * + * @param realm The Realm to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Realm realm) + throws Exception { + + String mname = createManagedName(realm); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(realm); + ObjectName oname = createObjectName(domain, realm); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Role object. + * + * @param role The Role to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Role role) + throws Exception { + + String mname = createManagedName(role); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(role); + ObjectName oname = createObjectName(domain, role); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Server object. + * + * @param server The Server to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Server server) + throws Exception { + + String mname = createManagedName(server); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(server); + ObjectName oname = createObjectName(domain, server); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Service object. + * + * @param service The Service to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Service service) + throws Exception { + + String mname = createManagedName(service); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(service); + ObjectName oname = createObjectName(domain, service); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * User object. + * + * @param user The User to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(User user) + throws Exception { + + String mname = createManagedName(user); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(user); + ObjectName oname = createObjectName(domain, user); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * UserDatabase object. + * + * @param userDatabase The UserDatabase to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(UserDatabase userDatabase) + throws Exception { + + String mname = createManagedName(userDatabase); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(userDatabase); + ObjectName oname = createObjectName(domain, userDatabase); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + + /** + * Create, register, and return an MBean for this + * Valve object. + * + * @param valve The Valve to be managed + * + * @exception Exception if an MBean cannot be created or registered + */ + static DynamicMBean createMBean(Valve valve) + throws Exception { + + String mname = createManagedName(valve); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + Exception e = new Exception("ManagedBean is not found with "+mname); + throw new MBeanException(e); + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + DynamicMBean mbean = managed.createMBean(valve); + ObjectName oname = createObjectName(domain, valve); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + mserver.registerMBean(mbean, oname); + return (mbean); + + } + + /** + * Create an ObjectName for this + * Connector object. + * + * @param domain Domain in which this name is to be created + * @param connector The Connector to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Connector connector) + throws MalformedObjectNameException { + + ObjectName name = null; + if (connector.getClass().getName().indexOf("CoyoteConnector") >= 0 ) { + try { + String address = (String) + IntrospectionUtils.getProperty(connector, "address"); + Integer port = (Integer) + IntrospectionUtils.getProperty(connector, "port"); + Service service = connector.getService(); + String serviceName = null; + if (service != null) + serviceName = service.getName(); + StringBuffer sb = new StringBuffer(domain); + sb.append(":type=Connector"); + sb.append(",port=" + port); + if ((address != null) && (address.length()>0)) { + sb.append(",address=" + address); + } + name = new ObjectName(sb.toString()); + return (name); + } catch (Exception e) { + throw new MalformedObjectNameException + ("Cannot create object name for " + connector+e); + } + } else { + throw new MalformedObjectNameException + ("Cannot create object name for " + connector); + } + + } + + + /** + * Create an ObjectName for this + * Context object. + * + * @param domain Domain in which this name is to be created + * @param context The Context to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Context context) + throws MalformedObjectNameException { + + ObjectName name = null; + Host host = (Host)context.getParent(); + Service service = ((Engine)host.getParent()).getService(); + String path = context.getPath(); + if (path.length() < 1) + path = "/"; + // FIXME + name = new ObjectName(domain + ":j2eeType=WebModule,name=//" + + host.getName()+ path + + ",J2EEApplication=none,J2EEServer=none"); + + return (name); + + } + + + /** + * Create an ObjectName for this + * Service object. + * + * @param domain Domain in which this name is to be created + * @param environment The ContextEnvironment to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + public static ObjectName createObjectName(String domain, + ContextEnvironment environment) + throws MalformedObjectNameException { + + ObjectName name = null; + Object container = + environment.getNamingResources().getContainer(); + if (container instanceof Server) { + name = new ObjectName(domain + ":type=Environment" + + ",resourcetype=Global,name=" + environment.getName()); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) + path = "/"; + Host host = (Host) ((Context)container).getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Environment" + + ",resourcetype=Context,path=" + path + + ",host=" + host.getName() + + ",name=" + environment.getName()); + } + return (name); + + } + + + /** + * Create an ObjectName for this + * ContextResource object. + * + * @param domain Domain in which this name is to be created + * @param resource The ContextResource to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + public static ObjectName createObjectName(String domain, + ContextResource resource) + throws MalformedObjectNameException { + + ObjectName name = null; + String quotedResourceName = ObjectName.quote(resource.getName()); + Object container = + resource.getNamingResources().getContainer(); + if (container instanceof Server) { + name = new ObjectName(domain + ":type=Resource" + + ",resourcetype=Global,class=" + resource.getType() + + ",name=" + quotedResourceName); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) + path = "/"; + Host host = (Host) ((Context)container).getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Resource" + + ",resourcetype=Context,path=" + path + + ",host=" + host.getName() + + ",class=" + resource.getType() + + ",name=" + quotedResourceName); + } + + return (name); + + } + + + /** + * Create an ObjectName for this + * ContextResourceLink object. + * + * @param domain Domain in which this name is to be created + * @param resourceLink The ContextResourceLink to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + public static ObjectName createObjectName(String domain, + ContextResourceLink resourceLink) + throws MalformedObjectNameException { + + ObjectName name = null; + String quotedResourceLinkName + = ObjectName.quote(resourceLink.getName()); + Object container = + resourceLink.getNamingResources().getContainer(); + if (container instanceof Server) { + name = new ObjectName(domain + ":type=ResourceLink" + + ",resourcetype=Global" + + ",name=" + quotedResourceLinkName); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) + path = "/"; + Host host = (Host) ((Context)container).getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=ResourceLink" + + ",resourcetype=Context,path=" + path + + ",host=" + host.getName() + + ",name=" + quotedResourceLinkName); + } + + return (name); + + } + + + + /** + * Create an ObjectName for this + * Engine object. + * + * @param domain Domain in which this name is to be created + * @param engine The Engine to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Engine engine) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=Engine"); + return (name); + + } + + + /** + * Create an ObjectName for this + * Group object. + * + * @param domain Domain in which this name is to be created + * @param group The Group to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Group group) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=Group,groupname=" + + ObjectName.quote(group.getGroupname()) + + ",database=" + group.getUserDatabase().getId()); + return (name); + + } + + + /** + * Create an ObjectName for this + * Host object. + * + * @param domain Domain in which this name is to be created + * @param host The Host to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Host host) + throws MalformedObjectNameException { + + ObjectName name = null; + Engine engine = (Engine)host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Host,host=" + + host.getName()); + return (name); + + } + + + /** + * Create an ObjectName for this + * Loader object. + * + * @param domain Domain in which this name is to be created + * @param loader The Loader to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Loader loader) + throws MalformedObjectNameException { + + ObjectName name = null; + Container container = loader.getContainer(); + + if (container instanceof Engine) { + Service service = ((Engine)container).getService(); + name = new ObjectName(domain + ":type=Loader"); + } else if (container instanceof Host) { + Engine engine = (Engine) container.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Loader,host=" + + container.getName()); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) container.getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Loader,path=" + path + + ",host=" + host.getName()); + } + + return (name); + + } + + + /** + * Create an ObjectName for this + * Manager object. + * + * @param domain Domain in which this name is to be created + * @param manager The Manager to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Manager manager) + throws MalformedObjectNameException { + + ObjectName name = null; + Container container = manager.getContainer(); + + if (container instanceof Engine) { + Service service = ((Engine)container).getService(); + name = new ObjectName(domain + ":type=Manager"); + } else if (container instanceof Host) { + Engine engine = (Engine) container.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Manager,host=" + + container.getName()); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) container.getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Manager,path=" + path + + ",host=" + host.getName()); + } + + return (name); + + } + + + /** + * Create an ObjectName for this + * Server object. + * + * @param domain Domain in which this name is to be created + * @param resources The NamingResources to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + NamingResources resources) + throws MalformedObjectNameException { + + ObjectName name = null; + Object container = resources.getContainer(); + if (container instanceof Server) { + name = new ObjectName(domain + ":type=NamingResources" + + ",resourcetype=Global"); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) + path = "/"; + Host host = (Host) ((Context)container).getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=NamingResources" + + ",resourcetype=Context,path=" + path + + ",host=" + host.getName()); + } + + return (name); + + } + + + /** + * Create an ObjectName for this + * MBeanFactory object. + * + * @param domain Domain in which this name is to be created + * @param factory The MBeanFactory to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + MBeanFactory factory) + throws MalformedObjectNameException { + + ObjectName name = new ObjectName(domain + ":type=MBeanFactory"); + + return (name); + + } + + + /** + * Create an ObjectName for this + * Realm object. + * + * @param domain Domain in which this name is to be created + * @param realm The Realm to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Realm realm) + throws MalformedObjectNameException { + + ObjectName name = null; + Container container = realm.getContainer(); + + if (container instanceof Engine) { + Service service = ((Engine)container).getService(); + name = new ObjectName(domain + ":type=Realm"); + } else if (container instanceof Host) { + Engine engine = (Engine) container.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Realm,host=" + + container.getName()); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) container.getParent(); + Engine engine = (Engine) host.getParent(); + Service service = engine.getService(); + name = new ObjectName(domain + ":type=Realm,path=" + path + + ",host=" + host.getName()); + } + + return (name); + + } + + + /** + * Create an ObjectName for this + * Role object. + * + * @param domain Domain in which this name is to be created + * @param role The Role to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Role role) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=Role,rolename=" + + role.getRolename() + ",database=" + + role.getUserDatabase().getId()); + return (name); + + } + + + /** + * Create an ObjectName for this + * Server object. + * + * @param domain Domain in which this name is to be created + * @param server The Server to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Server server) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=Server"); + return (name); + + } + + + /** + * Create an ObjectName for this + * Service object. + * + * @param domain Domain in which this name is to be created + * @param service The Service to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Service service) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=Service,serviceName=" + + service.getName()); + return (name); + + } + + + /** + * Create an ObjectName for this + * User object. + * + * @param domain Domain in which this name is to be created + * @param user The User to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + User user) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=User,username=" + + ObjectName.quote(user.getUsername()) + + ",database=" + user.getUserDatabase().getId()); + return (name); + + } + + + /** + * Create an ObjectName for this + * UserDatabase object. + * + * @param domain Domain in which this name is to be created + * @param userDatabase The UserDatabase to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + UserDatabase userDatabase) + throws MalformedObjectNameException { + + ObjectName name = null; + name = new ObjectName(domain + ":type=UserDatabase,database=" + + userDatabase.getId()); + return (name); + + } + + + /** + * Create an ObjectName for this + * Valve object. + * + * @param domain Domain in which this name is to be created + * @param valve The Valve to be named + * + * @exception MalformedObjectNameException if a name cannot be created + */ + static ObjectName createObjectName(String domain, + Valve valve) + throws MalformedObjectNameException { + if( valve instanceof ValveBase ) { + ObjectName name=((ValveBase)valve).getObjectName(); + if( name != null ) + return name; + } + + ObjectName name = null; + Container container = null; + String className=valve.getClass().getName(); + int period = className.lastIndexOf('.'); + if (period >= 0) + className = className.substring(period + 1); + if( valve instanceof Contained ) { + container = ((Contained)valve).getContainer(); + } + if( container == null ) { + throw new MalformedObjectNameException( + "Cannot create mbean for non-contained valve " + + valve); + } + if (container instanceof Engine) { + Service service = ((Engine)container).getService(); + String local=""; + int seq = getSeq(local); + String ext=""; + if( seq > 0 ) { + ext=",seq=" + seq; + } + name = new ObjectName(domain + ":type=Valve,name=" + className + + ext + local ); + } else if (container instanceof Host) { + Service service = ((Engine)container.getParent()).getService(); + String local=",host=" +container.getName(); + int seq = getSeq(local); + String ext=""; + if( seq > 0 ) { + ext=",seq=" + seq; + } + name = new ObjectName(domain + ":type=Valve,name=" + className + + ext + local ); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) container.getParent(); + Service service = ((Engine) host.getParent()).getService(); + String local=",path=" + path + ",host=" + + host.getName(); + int seq = getSeq(local); + String ext=""; + if( seq > 0 ) { + ext=",seq=" + seq; + } + name = new ObjectName(domain + ":type=Valve,name=" + className + + ext + local ); + } + + return (name); + + } + + static Hashtable seq=new Hashtable(); + static int getSeq( String key ) { + int i[]=(int [])seq.get( key ); + if (i == null ) { + i=new int[1]; + i[0]=0; + seq.put( key, i); + } else { + i[0]++; + } + return i[0]; + } + + /** + * Create and configure (if necessary) and return the registry of + * managed object descriptions. + */ + public synchronized static Registry createRegistry() { + + if (registry == null) { + registry = Registry.getRegistry(null, null); + ClassLoader cl=ServerLifecycleListener.class.getClassLoader(); + + registry.loadDescriptors("org.apache.catalina.mbeans", cl); + registry.loadDescriptors("org.apache.catalina.authenticator", cl); + registry.loadDescriptors("org.apache.catalina.core", cl); + registry.loadDescriptors("org.apache.catalina", cl); + registry.loadDescriptors("org.apache.catalina.deploy", cl); + registry.loadDescriptors("org.apache.catalina.loader", cl); + registry.loadDescriptors("org.apache.catalina.realm", cl); + registry.loadDescriptors("org.apache.catalina.session", cl); + registry.loadDescriptors("org.apache.catalina.startup", cl); + registry.loadDescriptors("org.apache.catalina.users", cl); + registry.loadDescriptors("org.apache.catalina.cluster", cl); + registry.loadDescriptors("org.apache.catalina.connector", cl); + registry.loadDescriptors("org.apache.catalina.valves", cl); + } + return (registry); + + } + + + /** + * Create and configure (if necessary) and return the + * MBeanServer with which we will be + * registering our DynamicMBean implementations. + */ + public synchronized static MBeanServer createServer() { + + if (mserver == null) { + try { + mserver = Registry.getRegistry(null, null).getMBeanServer(); + } catch (Throwable t) { + t.printStackTrace(System.out); + System.exit(1); + } + } + return (mserver); + + } + + + /** + * Deregister the MBean for this + * Connector object. + * + * @param connector The Connector to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Connector connector, Service service) + throws Exception { + + connector.setService(service); + String mname = createManagedName(connector); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, connector); + connector.setService(null); + if( mserver.isRegistered( oname )) { + mserver.unregisterMBean(oname); + } + } + + + /** + * Deregister the MBean for this + * Context object. + * + * @param context The Context to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Context context) + throws Exception { + + String mname = createManagedName(context); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, context); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * ContextEnvironment object. + * + * @param environment The ContextEnvironment to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(ContextEnvironment environment) + throws Exception { + + String mname = createManagedName(environment); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, environment); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * ContextResource object. + * + * @param resource The ContextResource to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(ContextResource resource) + throws Exception { + + String mname = createManagedName(resource); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, resource); + if( mserver.isRegistered(oname )) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * ContextResourceLink object. + * + * @param resourceLink The ContextResourceLink to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(ContextResourceLink resourceLink) + throws Exception { + + String mname = createManagedName(resourceLink); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, resourceLink); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + /** + * Deregister the MBean for this + * Engine object. + * + * @param engine The Engine to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Engine engine) + throws Exception { + + String mname = createManagedName(engine); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, engine); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Group object. + * + * @param group The Group to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Group group) + throws Exception { + + String mname = createManagedName(group); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, group); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Host object. + * + * @param host The Host to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Host host) + throws Exception { + + String mname = createManagedName(host); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, host); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Loader object. + * + * @param loader The Loader to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Loader loader) + throws Exception { + + String mname = createManagedName(loader); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, loader); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Manager object. + * + * @param manager The Manager to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Manager manager) + throws Exception { + + String mname = createManagedName(manager); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, manager); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * NamingResources object. + * + * @param resources The NamingResources to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(NamingResources resources) + throws Exception { + + String mname = createManagedName(resources); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, resources); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Realm object. + * + * @param realm The Realm to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Realm realm) + throws Exception { + + String mname = createManagedName(realm); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, realm); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Role object. + * + * @param role The Role to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Role role) + throws Exception { + + String mname = createManagedName(role); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, role); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Server object. + * + * @param server The Server to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Server server) + throws Exception { + + String mname = createManagedName(server); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, server); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Service object. + * + * @param service The Service to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Service service) + throws Exception { + + String mname = createManagedName(service); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, service); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * User object. + * + * @param user The User to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(User user) + throws Exception { + + String mname = createManagedName(user); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, user); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * UserDatabase object. + * + * @param userDatabase The UserDatabase to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(UserDatabase userDatabase) + throws Exception { + + String mname = createManagedName(userDatabase); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, userDatabase); + if( mserver.isRegistered(oname) ) + mserver.unregisterMBean(oname); + + } + + + /** + * Deregister the MBean for this + * Valve object. + * + * @param valve The Valve to be managed + * + * @exception Exception if an MBean cannot be deregistered + */ + static void destroyMBean(Valve valve, Container container) + throws Exception { + + ((Contained)valve).setContainer(container); + String mname = createManagedName(valve); + ManagedBean managed = registry.findManagedBean(mname); + if (managed == null) { + return; + } + String domain = managed.getDomain(); + if (domain == null) + domain = mserver.getDefaultDomain(); + ObjectName oname = createObjectName(domain, valve); + try { + ((Contained)valve).setContainer(null); + } catch (Throwable t) { + ; + } + if( mserver.isRegistered(oname) ) { + mserver.unregisterMBean(oname); + } + + } + +} diff --git a/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java b/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java index c4a2e1a67..4bd3f155d 100644 --- a/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java +++ b/java/org/apache/catalina/mbeans/MemoryUserDatabaseMBean.java @@ -1,395 +1,395 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.util.ArrayList; -import java.util.Iterator; - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.User; -import org.apache.catalina.UserDatabase; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.users.MemoryUserDatabase component.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ - */ - -public class MemoryUserDatabaseMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public MemoryUserDatabaseMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - - /** - * The MBeanServer in which we are registered. - */ - protected MBeanServer mserver = MBeanUtils.createServer(); - - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("MemoryUserDatabase"); - - - /** - * The ManagedBean information describing Group MBeans. - */ - protected ManagedBean managedGroup = - registry.findManagedBean("Group"); - - - /** - * The ManagedBean information describing Group MBeans. - */ - protected ManagedBean managedRole = - registry.findManagedBean("Role"); - - - /** - * The ManagedBean information describing User MBeans. - */ - protected ManagedBean managedUser = - registry.findManagedBean("User"); - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the MBean Names of all groups defined in this database. - */ - public String[] getGroups() { - - UserDatabase database = (UserDatabase) this.resource; - ArrayList results = new ArrayList(); - Iterator groups = database.getGroups(); - while (groups.hasNext()) { - Group group = (Group) groups.next(); - results.add(findGroup(group.getGroupname())); - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all roles defined in this database. - */ - public String[] getRoles() { - - UserDatabase database = (UserDatabase) this.resource; - ArrayList results = new ArrayList(); - Iterator roles = database.getRoles(); - while (roles.hasNext()) { - Role role = (Role) roles.next(); - results.add(findRole(role.getRolename())); - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all users defined in this database. - */ - public String[] getUsers() { - - UserDatabase database = (UserDatabase) this.resource; - ArrayList results = new ArrayList(); - Iterator users = database.getUsers(); - while (users.hasNext()) { - User user = (User) users.next(); - results.add(findUser(user.getUsername())); - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - // ------------------------------------------------------------- Operations - - - /** - * Create a new Group and return the corresponding MBean Name. - * - * @param groupname Group name of the new group - * @param description Description of the new group - */ - public String createGroup(String groupname, String description) { - - UserDatabase database = (UserDatabase) this.resource; - Group group = database.createGroup(groupname, description); - try { - MBeanUtils.createMBean(group); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception creating group " + group + " MBean"); - iae.initCause(e); - throw iae; - } - return (findGroup(groupname)); - - } - - - /** - * Create a new Role and return the corresponding MBean Name. - * - * @param rolename Group name of the new group - * @param description Description of the new group - */ - public String createRole(String rolename, String description) { - - UserDatabase database = (UserDatabase) this.resource; - Role role = database.createRole(rolename, description); - try { - MBeanUtils.createMBean(role); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception creating role " + role + " MBean"); - iae.initCause(e); - throw iae; - } - return (findRole(rolename)); - - } - - - /** - * Create a new User and return the corresponding MBean Name. - * - * @param username User name of the new user - * @param password Password for the new user - * @param fullName Full name for the new user - */ - public String createUser(String username, String password, - String fullName) { - - UserDatabase database = (UserDatabase) this.resource; - User user = database.createUser(username, password, fullName); - try { - MBeanUtils.createMBean(user); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception creating user " + user + " MBean"); - iae.initCause(e); - throw iae; - } - return (findUser(username)); - - } - - - /** - * Return the MBean Name for the specified group name (if any); - * otherwise return null. - * - * @param groupname Group name to look up - */ - public String findGroup(String groupname) { - - UserDatabase database = (UserDatabase) this.resource; - Group group = database.findGroup(groupname); - if (group == null) { - return (null); - } - try { - ObjectName oname = - MBeanUtils.createObjectName(managedGroup.getDomain(), group); - return (oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for group " + group); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Return the MBean Name for the specified role name (if any); - * otherwise return null. - * - * @param rolename Role name to look up - */ - public String findRole(String rolename) { - - UserDatabase database = (UserDatabase) this.resource; - Role role = database.findRole(rolename); - if (role == null) { - return (null); - } - try { - ObjectName oname = - MBeanUtils.createObjectName(managedRole.getDomain(), role); - return (oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for role " + role); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Return the MBean Name for the specified user name (if any); - * otherwise return null. - * - * @param username User name to look up - */ - public String findUser(String username) { - - UserDatabase database = (UserDatabase) this.resource; - User user = database.findUser(username); - if (user == null) { - return (null); - } - try { - ObjectName oname = - MBeanUtils.createObjectName(managedUser.getDomain(), user); - return (oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for user " + user); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Remove an existing group and destroy the corresponding MBean. - * - * @param groupname Group name to remove - */ - public void removeGroup(String groupname) { - - UserDatabase database = (UserDatabase) this.resource; - Group group = database.findGroup(groupname); - if (group == null) { - return; - } - try { - MBeanUtils.destroyMBean(group); - database.removeGroup(group); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception destroying group " + group + " MBean"); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Remove an existing role and destroy the corresponding MBean. - * - * @param rolename Role name to remove - */ - public void removeRole(String rolename) { - - UserDatabase database = (UserDatabase) this.resource; - Role role = database.findRole(rolename); - if (role == null) { - return; - } - try { - MBeanUtils.destroyMBean(role); - database.removeRole(role); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception destroying role " + role + " MBean"); - iae.initCause(e); - throw iae; - } - - } - - - /** - * Remove an existing user and destroy the corresponding MBean. - * - * @param username User name to remove - */ - public void removeUser(String username) { - - UserDatabase database = (UserDatabase) this.resource; - User user = database.findUser(username); - if (user == null) { - return; - } - try { - MBeanUtils.destroyMBean(user); - database.removeUser(user); - } catch (Exception e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Exception destroying user " + user + " MBean"); - iae.initCause(e); - throw iae; - } - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.catalina.UserDatabase; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.users.MemoryUserDatabase component.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ + */ + +public class MemoryUserDatabaseMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public MemoryUserDatabaseMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + + /** + * The MBeanServer in which we are registered. + */ + protected MBeanServer mserver = MBeanUtils.createServer(); + + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("MemoryUserDatabase"); + + + /** + * The ManagedBean information describing Group MBeans. + */ + protected ManagedBean managedGroup = + registry.findManagedBean("Group"); + + + /** + * The ManagedBean information describing Group MBeans. + */ + protected ManagedBean managedRole = + registry.findManagedBean("Role"); + + + /** + * The ManagedBean information describing User MBeans. + */ + protected ManagedBean managedUser = + registry.findManagedBean("User"); + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the MBean Names of all groups defined in this database. + */ + public String[] getGroups() { + + UserDatabase database = (UserDatabase) this.resource; + ArrayList results = new ArrayList(); + Iterator groups = database.getGroups(); + while (groups.hasNext()) { + Group group = (Group) groups.next(); + results.add(findGroup(group.getGroupname())); + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all roles defined in this database. + */ + public String[] getRoles() { + + UserDatabase database = (UserDatabase) this.resource; + ArrayList results = new ArrayList(); + Iterator roles = database.getRoles(); + while (roles.hasNext()) { + Role role = (Role) roles.next(); + results.add(findRole(role.getRolename())); + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all users defined in this database. + */ + public String[] getUsers() { + + UserDatabase database = (UserDatabase) this.resource; + ArrayList results = new ArrayList(); + Iterator users = database.getUsers(); + while (users.hasNext()) { + User user = (User) users.next(); + results.add(findUser(user.getUsername())); + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + // ------------------------------------------------------------- Operations + + + /** + * Create a new Group and return the corresponding MBean Name. + * + * @param groupname Group name of the new group + * @param description Description of the new group + */ + public String createGroup(String groupname, String description) { + + UserDatabase database = (UserDatabase) this.resource; + Group group = database.createGroup(groupname, description); + try { + MBeanUtils.createMBean(group); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception creating group " + group + " MBean"); + iae.initCause(e); + throw iae; + } + return (findGroup(groupname)); + + } + + + /** + * Create a new Role and return the corresponding MBean Name. + * + * @param rolename Group name of the new group + * @param description Description of the new group + */ + public String createRole(String rolename, String description) { + + UserDatabase database = (UserDatabase) this.resource; + Role role = database.createRole(rolename, description); + try { + MBeanUtils.createMBean(role); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception creating role " + role + " MBean"); + iae.initCause(e); + throw iae; + } + return (findRole(rolename)); + + } + + + /** + * Create a new User and return the corresponding MBean Name. + * + * @param username User name of the new user + * @param password Password for the new user + * @param fullName Full name for the new user + */ + public String createUser(String username, String password, + String fullName) { + + UserDatabase database = (UserDatabase) this.resource; + User user = database.createUser(username, password, fullName); + try { + MBeanUtils.createMBean(user); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception creating user " + user + " MBean"); + iae.initCause(e); + throw iae; + } + return (findUser(username)); + + } + + + /** + * Return the MBean Name for the specified group name (if any); + * otherwise return null. + * + * @param groupname Group name to look up + */ + public String findGroup(String groupname) { + + UserDatabase database = (UserDatabase) this.resource; + Group group = database.findGroup(groupname); + if (group == null) { + return (null); + } + try { + ObjectName oname = + MBeanUtils.createObjectName(managedGroup.getDomain(), group); + return (oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for group " + group); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Return the MBean Name for the specified role name (if any); + * otherwise return null. + * + * @param rolename Role name to look up + */ + public String findRole(String rolename) { + + UserDatabase database = (UserDatabase) this.resource; + Role role = database.findRole(rolename); + if (role == null) { + return (null); + } + try { + ObjectName oname = + MBeanUtils.createObjectName(managedRole.getDomain(), role); + return (oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for role " + role); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Return the MBean Name for the specified user name (if any); + * otherwise return null. + * + * @param username User name to look up + */ + public String findUser(String username) { + + UserDatabase database = (UserDatabase) this.resource; + User user = database.findUser(username); + if (user == null) { + return (null); + } + try { + ObjectName oname = + MBeanUtils.createObjectName(managedUser.getDomain(), user); + return (oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for user " + user); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Remove an existing group and destroy the corresponding MBean. + * + * @param groupname Group name to remove + */ + public void removeGroup(String groupname) { + + UserDatabase database = (UserDatabase) this.resource; + Group group = database.findGroup(groupname); + if (group == null) { + return; + } + try { + MBeanUtils.destroyMBean(group); + database.removeGroup(group); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception destroying group " + group + " MBean"); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Remove an existing role and destroy the corresponding MBean. + * + * @param rolename Role name to remove + */ + public void removeRole(String rolename) { + + UserDatabase database = (UserDatabase) this.resource; + Role role = database.findRole(rolename); + if (role == null) { + return; + } + try { + MBeanUtils.destroyMBean(role); + database.removeRole(role); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception destroying role " + role + " MBean"); + iae.initCause(e); + throw iae; + } + + } + + + /** + * Remove an existing user and destroy the corresponding MBean. + * + * @param username User name to remove + */ + public void removeUser(String username) { + + UserDatabase database = (UserDatabase) this.resource; + User user = database.findUser(username); + if (user == null) { + return; + } + try { + MBeanUtils.destroyMBean(user); + database.removeUser(user); + } catch (Exception e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Exception destroying user " + user + " MBean"); + iae.initCause(e); + throw iae; + } + + } + + +} diff --git a/java/org/apache/catalina/mbeans/NamingResourcesMBean.java b/java/org/apache/catalina/mbeans/NamingResourcesMBean.java index 7a3bb10c8..a9b402a81 100644 --- a/java/org/apache/catalina/mbeans/NamingResourcesMBean.java +++ b/java/org/apache/catalina/mbeans/NamingResourcesMBean.java @@ -1,323 +1,323 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - -import java.util.ArrayList; - -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.deploy.NamingResources component.

    - * - * @author Amy Roh - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class NamingResourcesMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public NamingResourcesMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("NamingResources"); - - // ------------------------------------------------------------- Attributes - - - /** - * Return the MBean Names of the set of defined environment entries for - * this web application - */ - public String[] getEnvironments() { - ContextEnvironment[] envs = - ((NamingResources)this.resource).findEnvironments(); - ArrayList results = new ArrayList(); - for (int i = 0; i < envs.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), envs[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for environment " + envs[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource references for this - * application. - */ - public String[] getResources() { - - ContextResource[] resources = - ((NamingResources)this.resource).findResources(); - ArrayList results = new ArrayList(); - for (int i = 0; i < resources.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resources[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + resources[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource link references for - * this application. - */ - public String[] getResourceLinks() { - - ContextResourceLink[] resourceLinks = - ((NamingResources)this.resource).findResourceLinks(); - ArrayList results = new ArrayList(); - for (int i = 0; i < resourceLinks.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resourceLinks[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + resourceLinks[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - // ------------------------------------------------------------- Operations - - - /** - * Add an environment entry for this web application. - * - * @param envName New environment entry name - * @param type The type of the new environment entry - * @param value The value of the new environment entry - */ - public String addEnvironment(String envName, String type, String value) - throws MalformedObjectNameException { - - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return null; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env != null) { - throw new IllegalArgumentException - ("Invalid environment name - already exists '" + envName + "'"); - } - env = new ContextEnvironment(); - env.setName(envName); - env.setType(type); - env.setValue(value); - nresources.addEnvironment(env); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextEnvironment"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), env); - return (oname.toString()); - - } - - - /** - * Add a resource reference for this web application. - * - * @param resourceName New resource reference name - * @param type New resource reference type - */ - public String addResource(String resourceName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return null; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource != null) { - throw new IllegalArgumentException - ("Invalid resource name - already exists'" + resourceName + "'"); - } - resource = new ContextResource(); - resource.setName(resourceName); - resource.setType(type); - nresources.addResource(resource); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResource"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resource); - return (oname.toString()); - } - - - /** - * Add a resource link reference for this web application. - * - * @param resourceLinkName New resource link reference name - * @param type New resource link reference type - */ - public String addResourceLink(String resourceLinkName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return null; - } - ContextResourceLink resourceLink = - nresources.findResourceLink(resourceLinkName); - if (resourceLink != null) { - throw new IllegalArgumentException - ("Invalid resource link name - already exists'" + - resourceLinkName + "'"); - } - resourceLink = new ContextResourceLink(); - resourceLink.setName(resourceLinkName); - resourceLink.setType(type); - nresources.addResourceLink(resourceLink); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResourceLink"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resourceLink); - return (oname.toString()); - } - - - /** - * Remove any environment entry with the specified name. - * - * @param envName Name of the environment entry to remove - */ - public void removeEnvironment(String envName) { - - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env == null) { - throw new IllegalArgumentException - ("Invalid environment name '" + envName + "'"); - } - nresources.removeEnvironment(envName); - - } - - - /** - * Remove any resource reference with the specified name. - * - * @param resourceName Name of the resource reference to remove - */ - public void removeResource(String resourceName) { - - resourceName = ObjectName.unquote(resourceName); - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource == null) { - throw new IllegalArgumentException - ("Invalid resource name '" + resourceName + "'"); - } - nresources.removeResource(resourceName); - - } - - - /** - * Remove any resource link reference with the specified name. - * - * @param resourceLinkName Name of the resource link reference to remove - */ - public void removeResourceLink(String resourceLinkName) { - - resourceLinkName = ObjectName.unquote(resourceLinkName); - NamingResources nresources = (NamingResources) this.resource; - if (nresources == null) { - return; - } - ContextResourceLink resourceLink = - nresources.findResourceLink(resourceLinkName); - if (resourceLink == null) { - throw new IllegalArgumentException - ("Invalid resource Link name '" + resourceLinkName + "'"); - } - nresources.removeResourceLink(resourceLinkName); - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + +import java.util.ArrayList; + +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.deploy.NamingResources component.

    + * + * @author Amy Roh + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class NamingResourcesMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public NamingResourcesMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("NamingResources"); + + // ------------------------------------------------------------- Attributes + + + /** + * Return the MBean Names of the set of defined environment entries for + * this web application + */ + public String[] getEnvironments() { + ContextEnvironment[] envs = + ((NamingResources)this.resource).findEnvironments(); + ArrayList results = new ArrayList(); + for (int i = 0; i < envs.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), envs[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for environment " + envs[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource references for this + * application. + */ + public String[] getResources() { + + ContextResource[] resources = + ((NamingResources)this.resource).findResources(); + ArrayList results = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resources[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + resources[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource link references for + * this application. + */ + public String[] getResourceLinks() { + + ContextResourceLink[] resourceLinks = + ((NamingResources)this.resource).findResourceLinks(); + ArrayList results = new ArrayList(); + for (int i = 0; i < resourceLinks.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resourceLinks[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + resourceLinks[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + // ------------------------------------------------------------- Operations + + + /** + * Add an environment entry for this web application. + * + * @param envName New environment entry name + * @param type The type of the new environment entry + * @param value The value of the new environment entry + */ + public String addEnvironment(String envName, String type, String value) + throws MalformedObjectNameException { + + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return null; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env != null) { + throw new IllegalArgumentException + ("Invalid environment name - already exists '" + envName + "'"); + } + env = new ContextEnvironment(); + env.setName(envName); + env.setType(type); + env.setValue(value); + nresources.addEnvironment(env); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextEnvironment"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), env); + return (oname.toString()); + + } + + + /** + * Add a resource reference for this web application. + * + * @param resourceName New resource reference name + * @param type New resource reference type + */ + public String addResource(String resourceName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return null; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource != null) { + throw new IllegalArgumentException + ("Invalid resource name - already exists'" + resourceName + "'"); + } + resource = new ContextResource(); + resource.setName(resourceName); + resource.setType(type); + nresources.addResource(resource); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResource"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resource); + return (oname.toString()); + } + + + /** + * Add a resource link reference for this web application. + * + * @param resourceLinkName New resource link reference name + * @param type New resource link reference type + */ + public String addResourceLink(String resourceLinkName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return null; + } + ContextResourceLink resourceLink = + nresources.findResourceLink(resourceLinkName); + if (resourceLink != null) { + throw new IllegalArgumentException + ("Invalid resource link name - already exists'" + + resourceLinkName + "'"); + } + resourceLink = new ContextResourceLink(); + resourceLink.setName(resourceLinkName); + resourceLink.setType(type); + nresources.addResourceLink(resourceLink); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResourceLink"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resourceLink); + return (oname.toString()); + } + + + /** + * Remove any environment entry with the specified name. + * + * @param envName Name of the environment entry to remove + */ + public void removeEnvironment(String envName) { + + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env == null) { + throw new IllegalArgumentException + ("Invalid environment name '" + envName + "'"); + } + nresources.removeEnvironment(envName); + + } + + + /** + * Remove any resource reference with the specified name. + * + * @param resourceName Name of the resource reference to remove + */ + public void removeResource(String resourceName) { + + resourceName = ObjectName.unquote(resourceName); + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource == null) { + throw new IllegalArgumentException + ("Invalid resource name '" + resourceName + "'"); + } + nresources.removeResource(resourceName); + + } + + + /** + * Remove any resource link reference with the specified name. + * + * @param resourceLinkName Name of the resource link reference to remove + */ + public void removeResourceLink(String resourceLinkName) { + + resourceLinkName = ObjectName.unquote(resourceLinkName); + NamingResources nresources = (NamingResources) this.resource; + if (nresources == null) { + return; + } + ContextResourceLink resourceLink = + nresources.findResourceLink(resourceLinkName); + if (resourceLink == null) { + throw new IllegalArgumentException + ("Invalid resource Link name '" + resourceLinkName + "'"); + } + nresources.removeResourceLink(resourceLinkName); + } + +} diff --git a/java/org/apache/catalina/mbeans/RoleMBean.java b/java/org/apache/catalina/mbeans/RoleMBean.java index 541c57af9..bba28ebe3 100644 --- a/java/org/apache/catalina/mbeans/RoleMBean.java +++ b/java/org/apache/catalina/mbeans/RoleMBean.java @@ -1,88 +1,88 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.RuntimeOperationsException; - -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.Role component.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class RoleMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public RoleMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - - /** - * The MBeanServer in which we are registered. - */ - protected MBeanServer mserver = MBeanUtils.createServer(); - - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("Role"); - - - // ------------------------------------------------------------- Attributes - - - // ------------------------------------------------------------- Operations - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.RuntimeOperationsException; + +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.Role component.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class RoleMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public RoleMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + + /** + * The MBeanServer in which we are registered. + */ + protected MBeanServer mserver = MBeanUtils.createServer(); + + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("Role"); + + + // ------------------------------------------------------------- Attributes + + + // ------------------------------------------------------------- Operations + + +} diff --git a/java/org/apache/catalina/mbeans/ServerLifecycleListener.java b/java/org/apache/catalina/mbeans/ServerLifecycleListener.java index ce1ef5dc3..c8bdcaec1 100644 --- a/java/org/apache/catalina/mbeans/ServerLifecycleListener.java +++ b/java/org/apache/catalina/mbeans/ServerLifecycleListener.java @@ -1,1411 +1,1411 @@ -/* - * Copyright 1999-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import javax.management.MBeanException; - -import org.apache.catalina.Container; -import org.apache.catalina.ContainerEvent; -import org.apache.catalina.ContainerListener; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Globals; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.Manager; -import org.apache.catalina.Realm; -import org.apache.catalina.Server; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.Service; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.core.StandardEngine; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.core.StandardServer; -import org.apache.catalina.core.StandardService; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Implementation of LifecycleListener that - * instantiates the set of MBeans associated with the components of a - * running instance of Catalina. - * - * @author Craig R. McClanahan - * @author Amy Roh - * @version $Revision: 303365 $ $Date: 2004-10-06 18:10:57 +0200 (mer., 06 oct. 2004) $ - */ - -public class ServerLifecycleListener - implements ContainerListener, LifecycleListener, PropertyChangeListener { - - private static Log log = LogFactory.getLog(ServerLifecycleListener.class); - - - // ------------------------------------------------------------- Properties - - - /** - * Semicolon separated list of paths containing MBean desciptor resources. - */ - protected String descriptors = null; - - public String getDescriptors() { - return (this.descriptors); - } - - public void setDescriptors(String descriptors) { - this.descriptors = descriptors; - } - - - // ---------------------------------------------- ContainerListener Methods - - - /** - * Handle a ContainerEvent from one of the Containers we are - * interested in. - * - * @param event The event that has occurred - */ - public void containerEvent(ContainerEvent event) { - - try { - String type = event.getType(); - if (Container.ADD_CHILD_EVENT.equals(type)) { - processContainerAddChild(event.getContainer(), - (Container) event.getData()); - } else if (Container.REMOVE_CHILD_EVENT.equals(type)) { - processContainerRemoveChild(event.getContainer(), - (Container) event.getData()); - } - } catch (Exception e) { - log.error("Exception processing event " + event, e); - } - - } - - - // ---------------------------------------------- LifecycleListener Methods - - - /** - * Primary entry point for startup and shutdown events. - * - * @param event The event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - Lifecycle lifecycle = event.getLifecycle(); - if (Lifecycle.START_EVENT.equals(event.getType())) { - - if (lifecycle instanceof Server) { - createMBeans(); - } - - // We are embedded. - if( lifecycle instanceof Service ) { - try { - MBeanFactory factory = new MBeanFactory(); - createMBeans(factory); - createMBeans((Service)lifecycle); - } catch( Exception ex ) { - log.error("Create mbean factory"); - } - } - - /* - // Ignore events from StandardContext objects to avoid - // reregistering the context - if (lifecycle instanceof StandardContext) - return; - createMBeans(); - */ - - } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { - try { - if (lifecycle instanceof Server) { - destroyMBeans((Server)lifecycle); - } - if (lifecycle instanceof Service) { - destroyMBeans((Service)lifecycle); - } - } catch (MBeanException t) { - - Exception e = t.getTargetException(); - if (e == null) { - e = t; - } - log.error("destroyMBeans: MBeanException", e); - - } catch (Throwable t) { - - log.error("destroyMBeans: Throwable", t); - - } - // FIXME: RMI adaptor should be stopped; however, this is - // undocumented in MX4J, and reports exist in the MX4J bug DB that - // this doesn't work - - } - - if ((Context.RELOAD_EVENT.equals(event.getType())) - || (Lifecycle.START_EVENT.equals(event.getType()))) { - - // Give context a new handle to the MBean server if the - // context has been reloaded since reloading causes the - // context to lose its previous handle to the server - if (lifecycle instanceof StandardContext) { - // If the context is privileged, give a reference to it - // in a servlet context attribute - StandardContext context = (StandardContext)lifecycle; - if (context.getPrivileged()) { - context.getServletContext().setAttribute - (Globals.MBEAN_REGISTRY_ATTR, - MBeanUtils.createRegistry()); - context.getServletContext().setAttribute - (Globals.MBEAN_SERVER_ATTR, - MBeanUtils.createServer()); - } - } - - } - - } - - - // ----------------------------------------- PropertyChangeListener Methods - - - /** - * Handle a PropertyChangeEvent from one of the Containers - * we are interested in. - * - * @param event The event that has occurred - */ - public void propertyChange(PropertyChangeEvent event) { - - if (event.getSource() instanceof Container) { - try { - processContainerPropertyChange((Container) event.getSource(), - event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - } catch (Exception e) { - log.error("Exception handling Container property change", e); - } - }/* else if (event.getSource() instanceof DefaultContext) { - try { - processDefaultContextPropertyChange - ((DefaultContext) event.getSource(), - event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - } catch (Exception e) { - log.error("Exception handling DefaultContext property change", e); - } - }*/ else if (event.getSource() instanceof NamingResources) { - try { - processNamingResourcesPropertyChange - ((NamingResources) event.getSource(), - event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - } catch (Exception e) { - log.error("Exception handling NamingResources property change", e); - } - } else if (event.getSource() instanceof Server) { - try { - processServerPropertyChange((Server) event.getSource(), - event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - } catch (Exception e) { - log.error("Exception handing Server property change", e); - } - } else if (event.getSource() instanceof Service) { - try { - processServicePropertyChange((Service) event.getSource(), - event.getPropertyName(), - event.getOldValue(), - event.getNewValue()); - } catch (Exception e) { - log.error("Exception handing Service property change", e); - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Create the MBeans that correspond to every existing node of our tree. - */ - protected void createMBeans() { - - try { - - MBeanFactory factory = new MBeanFactory(); - createMBeans(factory); - createMBeans(ServerFactory.getServer()); - - } catch (MBeanException t) { - - Exception e = t.getTargetException(); - if (e == null) - e = t; - log.error("createMBeans: MBeanException", e); - - } catch (Throwable t) { - - log.error("createMBeans: Throwable", t); - - } - - } - - - /** - * Create the MBeans for the specified Connector and its nested components. - * - * @param connector Connector for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Connector connector) throws Exception { - - // Create the MBean for the Connnector itself -// if (log.isDebugEnabled()) -// log.debug("Creating MBean for Connector " + connector); -// MBeanUtils.createMBean(connector); - - } - - - /** - * Create the MBeans for the specified Context and its nested components. - * - * @param context Context for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Context context) throws Exception { - - // Create the MBean for the Context itself -// if (log.isDebugEnabled()) -// log.debug("Creating MBean for Context " + context); -// MBeanUtils.createMBean(context); - context.addContainerListener(this); - if (context instanceof StandardContext) { - ((StandardContext) context).addPropertyChangeListener(this); - ((StandardContext) context).addLifecycleListener(this); - } - - // If the context is privileged, give a reference to it - // in a servlet context attribute - if (context.getPrivileged()) { - context.getServletContext().setAttribute - (Globals.MBEAN_REGISTRY_ATTR, - MBeanUtils.createRegistry()); - context.getServletContext().setAttribute - (Globals.MBEAN_SERVER_ATTR, - MBeanUtils.createServer()); - } - - // Create the MBeans for the associated nested components - Loader cLoader = context.getLoader(); - if (cLoader != null) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Loader " + cLoader); - //MBeanUtils.createMBean(cLoader); - } - Manager cManager = context.getManager(); - if (cManager != null) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Manager " + cManager); - //MBeanUtils.createMBean(cManager); - } - Realm hRealm = context.getParent().getRealm(); - Realm cRealm = context.getRealm(); - if ((cRealm != null) && (cRealm != hRealm)) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Realm " + cRealm); - //MBeanUtils.createMBean(cRealm); - } - - // Create the MBeans for the NamingResources (if any) - NamingResources resources = context.getNamingResources(); - createMBeans(resources); - - } - - - /** - * Create the MBeans for the specified ContextEnvironment entry. - * - * @param environment ContextEnvironment for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(ContextEnvironment environment) - throws Exception { - - // Create the MBean for the ContextEnvironment itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for ContextEnvironment " + environment); - } - MBeanUtils.createMBean(environment); - - } - - - /** - * Create the MBeans for the specified ContextResource entry. - * - * @param resource ContextResource for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(ContextResource resource) - throws Exception { - - // Create the MBean for the ContextResource itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for ContextResource " + resource); - } - MBeanUtils.createMBean(resource); - - } - - - /** - * Create the MBeans for the specified ContextResourceLink entry. - * - * @param resourceLink ContextResourceLink for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(ContextResourceLink resourceLink) - throws Exception { - - // Create the MBean for the ContextResourceLink itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for ContextResourceLink " + resourceLink); - } - MBeanUtils.createMBean(resourceLink); - - } - - - /** - * Create the MBeans for the specified DefaultContext and its nested components. - * - * @param dcontext DefaultContext for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - /* - protected void createMBeans(DefaultContext dcontext) throws Exception { - - // Create the MBean for the DefaultContext itself - if (log.isDebugEnabled()) - log.debug("Creating MBean for DefaultContext " + dcontext); - MBeanUtils.createMBean(dcontext); - - dcontext.addPropertyChangeListener(this); - - // Create the MBeans for the associated nested components - Loader dLoader = dcontext.getLoader(); - if (dLoader != null) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Loader " + dLoader); - //MBeanUtils.createMBean(dLoader); - } - - Manager dManager = dcontext.getManager(); - if (dManager != null) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Manager " + dManager); - //MBeanUtils.createMBean(dManager); - } - - // Create the MBeans for the NamingResources (if any) - NamingResources resources = dcontext.getNamingResources(); - createMBeans(resources); - - } - */ - - - /** - * Create the MBeans for the specified Engine and its nested components. - * - * @param engine Engine for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Engine engine) throws Exception { - - // Create the MBean for the Engine itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Engine " + engine); - } - //MBeanUtils.createMBean(engine); - engine.addContainerListener(this); - if (engine instanceof StandardEngine) { - ((StandardEngine) engine).addPropertyChangeListener(this); - } - - // Create the MBeans for the associated nested components - Realm eRealm = engine.getRealm(); - if (eRealm != null) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Realm " + eRealm); - //MBeanUtils.createMBean(eRealm); - } - - // Create the MBeans for each child Host - Container hosts[] = engine.findChildren(); - for (int j = 0; j < hosts.length; j++) { - createMBeans((Host) hosts[j]); - } - - } - - - /** - * Create the MBeans for the specified Host and its nested components. - * - * @param host Host for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Host host) throws Exception { - - // Create the MBean for the Host itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Host " + host); - } - //MBeanUtils.createMBean(host); - host.addContainerListener(this); - if (host instanceof StandardHost) { - ((StandardHost) host).addPropertyChangeListener(this); - } - - // Create the MBeans for the associated nested components - Realm eRealm = host.getParent().getRealm(); - Realm hRealm = host.getRealm(); - if ((hRealm != null) && (hRealm != eRealm)) { - if (log.isDebugEnabled()) - log.debug("Creating MBean for Realm " + hRealm); - //MBeanUtils.createMBean(hRealm); - } - - // Create the MBeans for each child Context - Container contexts[] = host.findChildren(); - for (int k = 0; k < contexts.length; k++) { - createMBeans((Context) contexts[k]); - } - - } - - - /** - * Create the MBeans for MBeanFactory. - * - * @param factory MBeanFactory for which to create MBean - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(MBeanFactory factory) throws Exception { - - // Create the MBean for the MBeanFactory - if (log.isDebugEnabled()) - log.debug("Creating MBean for MBeanFactory " + factory); - MBeanUtils.createMBean(factory); - - } - - - /** - * Create the MBeans for the specified NamingResources and its - * nested components. - * - * @param resources NamingResources for which to create MBeans - */ - protected void createMBeans(NamingResources resources) throws Exception { - - // Create the MBean for the NamingResources itself - if (log.isDebugEnabled()) { - log.debug("Creating MBean for NamingResources " + resources); - } - MBeanUtils.createMBean(resources); - resources.addPropertyChangeListener(this); - - // Create the MBeans for each child environment entry - ContextEnvironment environments[] = resources.findEnvironments(); - for (int i = 0; i < environments.length; i++) { - createMBeans(environments[i]); - } - - // Create the MBeans for each child resource entry - ContextResource cresources[] = resources.findResources(); - for (int i = 0; i < cresources.length; i++) { - createMBeans(cresources[i]); - } - - // Create the MBeans for each child resource link entry - ContextResourceLink cresourcelinks[] = resources.findResourceLinks(); - for (int i = 0; i < cresourcelinks.length; i++) { - createMBeans(cresourcelinks[i]); - } - - } - - - /** - * Create the MBeans for the specified Server and its nested components. - * - * @param server Server for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Server server) throws Exception { - - // Create the MBean for the Server itself - if (log.isDebugEnabled()) - log.debug("Creating MBean for Server " + server); - //MBeanUtils.createMBean(server); - if (server instanceof StandardServer) { - ((StandardServer) server).addPropertyChangeListener(this); - } - - // Create the MBeans for the global NamingResources (if any) - NamingResources resources = server.getGlobalNamingResources(); - if (resources != null) { - createMBeans(resources); - } - - // Create the MBeans for each child Service - Service services[] = server.findServices(); - for (int i = 0; i < services.length; i++) { - // FIXME - Warp object hierarchy not currently supported - if (services[i].getContainer().getClass().getName().equals - ("org.apache.catalina.connector.warp.WarpEngine")) { - if (log.isDebugEnabled()) { - log.debug("Skipping MBean for Service " + services[i]); - } - continue; - } - createMBeans(services[i]); - } - - } - - - /** - * Create the MBeans for the specified Service and its nested components. - * - * @param service Service for which to create MBeans - * - * @exception Exception if an exception is thrown during MBean creation - */ - protected void createMBeans(Service service) throws Exception { - - // Create the MBean for the Service itself - if (log.isDebugEnabled()) - log.debug("Creating MBean for Service " + service); - //MBeanUtils.createMBean(service); - if (service instanceof StandardService) { - ((StandardService) service).addPropertyChangeListener(this); - } - - // Create the MBeans for the corresponding Connectors - Connector connectors[] = service.findConnectors(); - for (int j = 0; j < connectors.length; j++) { - createMBeans(connectors[j]); - } - - // Create the MBean for the associated Engine and friends - Engine engine = (Engine) service.getContainer(); - if (engine != null) { - createMBeans(engine); - } - - } - - - - - /** - * Deregister the MBeans for the specified Connector and its nested - * components. - * - * @param connector Connector for which to deregister MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Connector connector, Service service) - throws Exception { - -// // deregister the MBean for the Connector itself -// if (log.isDebugEnabled()) -// log.debug("Destroying MBean for Connector " + connector); -// MBeanUtils.destroyMBean(connector, service); - - } - - - /** - * Deregister the MBeans for the specified Context and its nested - * components. - * - * @param context Context for which to deregister MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Context context) throws Exception { - - // Deregister ourselves as a ContainerListener - context.removeContainerListener(this); - - // Destroy the MBeans for the associated nested components - Realm hRealm = context.getParent().getRealm(); - Realm cRealm = context.getRealm(); - if ((cRealm != null) && (cRealm != hRealm)) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Realm " + cRealm); - //MBeanUtils.destroyMBean(cRealm); - } - Manager cManager = context.getManager(); - if (cManager != null) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Manager " + cManager); - //MBeanUtils.destroyMBean(cManager); - } - Loader cLoader = context.getLoader(); - if (cLoader != null) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Loader " + cLoader); - //MBeanUtils.destroyMBean(cLoader); - } - - // Destroy the MBeans for the NamingResources (if any) - NamingResources resources = context.getNamingResources(); - if (resources != null) { - destroyMBeans(resources); - } - - // deregister the MBean for the Context itself - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Context " + context); - //MBeanUtils.destroyMBean(context); - if (context instanceof StandardContext) { - ((StandardContext) context). - removePropertyChangeListener(this); - } - - } - - - /** - * Deregister the MBeans for the specified ContextEnvironment entry. - * - * @param environment ContextEnvironment for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(ContextEnvironment environment) - throws Exception { - - // Destroy the MBean for the ContextEnvironment itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for ContextEnvironment " + environment); - } - MBeanUtils.destroyMBean(environment); - - } - - - /** - * Deregister the MBeans for the specified ContextResource entry. - * - * @param resource ContextResource for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(ContextResource resource) - throws Exception { - - // Destroy the MBean for the ContextResource itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for ContextResource " + resource); - } - MBeanUtils.destroyMBean(resource); - - } - - - /** - * Deregister the MBeans for the specified ContextResourceLink entry. - * - * @param resourceLink ContextResourceLink for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(ContextResourceLink resourceLink) - throws Exception { - - // Destroy the MBean for the ContextResourceLink itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for ContextResourceLink " + resourceLink); - } - MBeanUtils.destroyMBean(resourceLink); - - } - - - /** - * Deregister the MBeans for the specified DefaultContext and its nested - * components. - * - * @param dcontext DefaultContext for which to deregister MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - /* - protected void destroyMBeans(DefaultContext dcontext) throws Exception { - - Manager dManager = dcontext.getManager(); - if (dManager != null) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Manager " + dManager); - //MBeanUtils.destroyMBean(dManager); - } - - Loader dLoader = dcontext.getLoader(); - if (dLoader != null) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Loader " + dLoader); - //MBeanUtils.destroyMBean(dLoader); - } - - // Destroy the MBeans for the NamingResources (if any) - NamingResources resources = dcontext.getNamingResources(); - if (resources != null) { - destroyMBeans(resources); - } - - // deregister the MBean for the DefaultContext itself - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Context " + dcontext); - MBeanUtils.destroyMBean(dcontext); - dcontext.removePropertyChangeListener(this); - - } - */ - - - /** - * Deregister the MBeans for the specified Engine and its nested - * components. - * - * @param engine Engine for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Engine engine) throws Exception { - - // Deregister ourselves as a ContainerListener - engine.removeContainerListener(this); - - // Deregister the MBeans for each child Host - Container hosts[] = engine.findChildren(); - for (int k = 0; k < hosts.length; k++) { - destroyMBeans((Host) hosts[k]); - } - - // Deregister the MBeans for the associated nested components - Realm eRealm = engine.getRealm(); - if (eRealm != null) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Realm " + eRealm); - //MBeanUtils.destroyMBean(eRealm); - } - - // Deregister the MBean for the Engine itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for Engine " + engine); - } - //MBeanUtils.destroyMBean(engine); - - } - - - /** - * Deregister the MBeans for the specified Host and its nested components. - * - * @param host Host for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Host host) throws Exception { - - // Deregister ourselves as a ContainerListener - host.removeContainerListener(this); - - // Deregister the MBeans for each child Context - Container contexts[] = host.findChildren(); - for (int k = 0; k < contexts.length; k++) { - destroyMBeans((Context) contexts[k]); - } - - - // Deregister the MBeans for the associated nested components - Realm eRealm = host.getParent().getRealm(); - Realm hRealm = host.getRealm(); - if ((hRealm != null) && (hRealm != eRealm)) { - if (log.isDebugEnabled()) - log.debug("Destroying MBean for Realm " + hRealm); - //MBeanUtils.destroyMBean(hRealm); - } - - // Deregister the MBean for the Host itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for Host " + host); - } - //MBeanUtils.destroyMBean(host); - - } - - - /** - * Deregister the MBeans for the specified NamingResources and its - * nested components. - * - * @param resources NamingResources for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(NamingResources resources) throws Exception { - - // Destroy the MBeans for each child resource entry - ContextResource cresources[] = resources.findResources(); - for (int i = 0; i < cresources.length; i++) { - destroyMBeans(cresources[i]); - } - - // Destroy the MBeans for each child resource link entry - ContextResourceLink cresourcelinks[] = resources.findResourceLinks(); - for (int i = 0; i < cresourcelinks.length; i++) { - destroyMBeans(cresourcelinks[i]); - } - - // Destroy the MBeans for each child environment entry - ContextEnvironment environments[] = resources.findEnvironments(); - for (int i = 0; i < environments.length; i++) { - destroyMBeans(environments[i]); - } - - // Destroy the MBean for the NamingResources itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for NamingResources " + resources); - } - MBeanUtils.destroyMBean(resources); - resources.removePropertyChangeListener(this); - - } - - - /** - * Deregister the MBeans for the specified Server and its related - * components. - * - * @param server Server for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Server server) throws Exception { - - // Destroy the MBeans for the global NamingResources (if any) - NamingResources resources = server.getGlobalNamingResources(); - if (resources != null) { - destroyMBeans(resources); - } - - // Destroy the MBeans for each child Service - Service services[] = server.findServices(); - for (int i = 0; i < services.length; i++) { - // FIXME - Warp object hierarchy not currently supported - if (services[i].getContainer().getClass().getName().equals - ("org.apache.catalina.connector.warp.WarpEngine")) { - if (log.isDebugEnabled()) { - log.debug("Skipping MBean for Service " + services[i]); - } - continue; - } - destroyMBeans(services[i]); - } - - // Destroy the MBean for the Server itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for Server " + server); - } - //MBeanUtils.destroyMBean(server); - if (server instanceof StandardServer) { - ((StandardServer) server).removePropertyChangeListener(this); - } - - } - - - /** - * Deregister the MBeans for the specified Service and its nested - * components. - * - * @param service Service for which to destroy MBeans - * - * @exception Exception if an exception is thrown during MBean destruction - */ - protected void destroyMBeans(Service service) throws Exception { - - // Deregister the MBeans for the associated Engine - Engine engine = (Engine) service.getContainer(); - if (engine != null) { - //destroyMBeans(engine); - } - -// // Deregister the MBeans for the corresponding Connectors -// Connector connectors[] = service.findConnectors(); -// for (int j = 0; j < connectors.length; j++) { -// destroyMBeans(connectors[j], service); -// } - - // Deregister the MBean for the Service itself - if (log.isDebugEnabled()) { - log.debug("Destroying MBean for Service " + service); - } - //MBeanUtils.destroyMBean(service); - if (service instanceof StandardService) { - ((StandardService) service).removePropertyChangeListener(this); - } - - } - - - /** - * Process the addition of a new child Container to a parent Container. - * - * @param parent Parent container - * @param child Child container - */ - protected void processContainerAddChild(Container parent, - Container child) { - - if (log.isDebugEnabled()) - log.debug("Process addChild[parent=" + parent + ",child=" + child + "]"); - - try { - if (child instanceof Context) { - createMBeans((Context) child); - } else if (child instanceof Engine) { - createMBeans((Engine) child); - } else if (child instanceof Host) { - createMBeans((Host) child); - } - } catch (MBeanException t) { - Exception e = t.getTargetException(); - if (e == null) - e = t; - log.error("processContainerAddChild: MBeanException", e); - } catch (Throwable t) { - log.error("processContainerAddChild: Throwable", t); - } - - } - - - - - /** - * Process a property change event on a Container. - * - * @param container The container on which this event occurred - * @param propertyName The name of the property that changed - * @param oldValue The previous value (may be null) - * @param newValue The new value (may be null) - * - * @exception Exception if an exception is thrown - */ - protected void processContainerPropertyChange(Container container, - String propertyName, - Object oldValue, - Object newValue) - throws Exception { - - if (log.isTraceEnabled()) { - log.trace("propertyChange[container=" + container + - ",propertyName=" + propertyName + - ",oldValue=" + oldValue + - ",newValue=" + newValue + "]"); - } - if ("loader".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Loader " + oldValue); - } - MBeanUtils.destroyMBean((Loader) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Loader " + newValue); - } - MBeanUtils.createMBean((Loader) newValue); - } - } else if ("logger".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Logger " + oldValue); - } - // MBeanUtils.destroyMBean((Logger) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Logger " + newValue); - } - //MBeanUtils.createMBean((Logger) newValue); - } - } else if ("manager".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Manager " + oldValue); - } - //MBeanUtils.destroyMBean((Manager) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Manager " + newValue); - } - //MBeanUtils.createMBean((Manager) newValue); - } - } else if ("realm".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Realm " + oldValue); - } - MBeanUtils.destroyMBean((Realm) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Realm " + newValue); - } - //MBeanUtils.createMBean((Realm) newValue); - } - } else if ("service".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((Service) oldValue); - } - if (newValue != null) { - createMBeans((Service) newValue); - } - } - - } - - - /** - * Process a property change event on a DefaultContext. - * - * @param defaultContext The DefaultContext on which this event occurred - * @param propertyName The name of the property that changed - * @param oldValue The previous value (may be null) - * @param newValue The new value (may be null) - * - * @exception Exception if an exception is thrown - */ - /* - protected void processDefaultContextPropertyChange(DefaultContext defaultContext, - String propertyName, - Object oldValue, - Object newValue) - throws Exception { - - if (log.isTraceEnabled()) { - log.trace("propertyChange[defaultContext=" + defaultContext + - ",propertyName=" + propertyName + - ",oldValue=" + oldValue + - ",newValue=" + newValue + "]"); - } - if ("loader".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Loader " + oldValue); - } - MBeanUtils.destroyMBean((Loader) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Loader " + newValue); - } - MBeanUtils.createMBean((Loader) newValue); - } - } else if ("logger".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Logger " + oldValue); - } - //MBeanUtils.destroyMBean((Logger) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Logger " + newValue); - } - //MBeanUtils.createMBean((Logger) newValue); - } - } else if ("manager".equals(propertyName)) { - if (oldValue != null) { - if (log.isDebugEnabled()) { - log.debug("Removing MBean for Manager " + oldValue); - } - MBeanUtils.destroyMBean((Manager) oldValue); - } - if (newValue != null) { - if (log.isDebugEnabled()) { - log.debug("Creating MBean for Manager " + newValue); - } - MBeanUtils.createMBean((Manager) newValue); - } - } else if ("realm".equals(propertyName)) { - if (oldValue != null) { -// if (log.isDebugEnabled()) { -// log.debug("Removing MBean for Realm " + oldValue); -// } -// //MBeanUtils.destroyMBean((Realm) oldValue); - } - if (newValue != null) { -// if (log.isDebugEnabled()) { -// log.debug("Creating MBean for Realm " + newValue); -// } -// //MBeanUtils.createMBean((Realm) newValue); - } - } else if ("service".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((Service) oldValue); - } - if (newValue != null) { - createMBeans((Service) newValue); - } - } - - }*/ - - - /** - * Process the removal of a child Container from a parent Container. - * - * @param parent Parent container - * @param child Child container - */ - protected void processContainerRemoveChild(Container parent, - Container child) { - - if (log.isDebugEnabled()) - log.debug("Process removeChild[parent=" + parent + ",child=" + - child + "]"); - - try { - if (child instanceof Context) { - Context context = (Context) child; - if (context.getPrivileged()) { - context.getServletContext().removeAttribute - (Globals.MBEAN_REGISTRY_ATTR); - context.getServletContext().removeAttribute - (Globals.MBEAN_SERVER_ATTR); - } - if (log.isDebugEnabled()) - log.debug(" Removing MBean for Context " + context); - destroyMBeans(context); - if (context instanceof StandardContext) { - ((StandardContext) context). - removePropertyChangeListener(this); - } - } else if (child instanceof Host) { - Host host = (Host) child; - destroyMBeans(host); - if (host instanceof StandardHost) { - ((StandardHost) host). - removePropertyChangeListener(this); - } - } - } catch (MBeanException t) { - Exception e = t.getTargetException(); - if (e == null) - e = t; - log.error("processContainerRemoveChild: MBeanException", e); - } catch (Throwable t) { - log.error("processContainerRemoveChild: Throwable", t); - } - - } - - - /** - * Process a property change event on a NamingResources. - * - * @param resources The global naming resources on which this - * event occurred - * @param propertyName The name of the property that changed - * @param oldValue The previous value (may be null) - * @param newValue The new value (may be null) - * - * @exception Exception if an exception is thrown - */ - protected void processNamingResourcesPropertyChange - (NamingResources resources, String propertyName, - Object oldValue, Object newValue) - throws Exception { - - if (log.isTraceEnabled()) { - log.trace("propertyChange[namingResources=" + resources + - ",propertyName=" + propertyName + - ",oldValue=" + oldValue + - ",newValue=" + newValue + "]"); - } - - // FIXME - Add other resource types when supported by admin tool - if ("environment".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((ContextEnvironment) oldValue); - } - if (newValue != null) { - createMBeans((ContextEnvironment) newValue); - } - } else if ("resource".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((ContextResource) oldValue); - } - if (newValue != null) { - createMBeans((ContextResource) newValue); - } - } else if ("resourceLink".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((ContextResourceLink) oldValue); - } - if (newValue != null) { - createMBeans((ContextResourceLink) newValue); - } - } - - } - - - /** - * Process a property change event on a Server. - * - * @param server The server on which this event occurred - * @param propertyName The name of the property that changed - * @param oldValue The previous value (may be null) - * @param newValue The new value (may be null) - * - * @exception Exception if an exception is thrown - */ - protected void processServerPropertyChange(Server server, - String propertyName, - Object oldValue, - Object newValue) - throws Exception { - - if (log.isTraceEnabled()) { - log.trace("propertyChange[server=" + server + - ",propertyName=" + propertyName + - ",oldValue=" + oldValue + - ",newValue=" + newValue + "]"); - } - if ("globalNamingResources".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((NamingResources) oldValue); - } - if (newValue != null) { - createMBeans((NamingResources) newValue); - } - } else if ("service".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((Service) oldValue); - } - if (newValue != null) { - createMBeans((Service) newValue); - } - } - - } - - - /** - * Process a property change event on a Service. - * - * @param service The service on which this event occurred - * @param propertyName The name of the property that changed - * @param oldValue The previous value (may be null) - * @param newValue The new value (may be null) - * - * @exception Exception if an exception is thrown - */ - protected void processServicePropertyChange(Service service, - String propertyName, - Object oldValue, - Object newValue) - throws Exception { - - if (log.isTraceEnabled()) { - log.trace("propertyChange[service=" + service + - ",propertyName=" + propertyName + - ",oldValue=" + oldValue + - ",newValue=" + newValue + "]"); - } - if ("connector".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((Connector) oldValue, service); - } - if (newValue != null) { - createMBeans((Connector) newValue); - } - } else if ("container".equals(propertyName)) { - if (oldValue != null) { - destroyMBeans((Engine) oldValue); - } - if (newValue != null) { - createMBeans((Engine) newValue); - } - } - - } - - -} +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import javax.management.MBeanException; + +import org.apache.catalina.Container; +import org.apache.catalina.ContainerEvent; +import org.apache.catalina.ContainerListener; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Globals; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.Manager; +import org.apache.catalina.Realm; +import org.apache.catalina.Server; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.Service; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.core.StandardEngine; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.core.StandardServer; +import org.apache.catalina.core.StandardService; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Implementation of LifecycleListener that + * instantiates the set of MBeans associated with the components of a + * running instance of Catalina. + * + * @author Craig R. McClanahan + * @author Amy Roh + * @version $Revision: 303365 $ $Date: 2004-10-06 18:10:57 +0200 (mer., 06 oct. 2004) $ + */ + +public class ServerLifecycleListener + implements ContainerListener, LifecycleListener, PropertyChangeListener { + + private static Log log = LogFactory.getLog(ServerLifecycleListener.class); + + + // ------------------------------------------------------------- Properties + + + /** + * Semicolon separated list of paths containing MBean desciptor resources. + */ + protected String descriptors = null; + + public String getDescriptors() { + return (this.descriptors); + } + + public void setDescriptors(String descriptors) { + this.descriptors = descriptors; + } + + + // ---------------------------------------------- ContainerListener Methods + + + /** + * Handle a ContainerEvent from one of the Containers we are + * interested in. + * + * @param event The event that has occurred + */ + public void containerEvent(ContainerEvent event) { + + try { + String type = event.getType(); + if (Container.ADD_CHILD_EVENT.equals(type)) { + processContainerAddChild(event.getContainer(), + (Container) event.getData()); + } else if (Container.REMOVE_CHILD_EVENT.equals(type)) { + processContainerRemoveChild(event.getContainer(), + (Container) event.getData()); + } + } catch (Exception e) { + log.error("Exception processing event " + event, e); + } + + } + + + // ---------------------------------------------- LifecycleListener Methods + + + /** + * Primary entry point for startup and shutdown events. + * + * @param event The event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + Lifecycle lifecycle = event.getLifecycle(); + if (Lifecycle.START_EVENT.equals(event.getType())) { + + if (lifecycle instanceof Server) { + createMBeans(); + } + + // We are embedded. + if( lifecycle instanceof Service ) { + try { + MBeanFactory factory = new MBeanFactory(); + createMBeans(factory); + createMBeans((Service)lifecycle); + } catch( Exception ex ) { + log.error("Create mbean factory"); + } + } + + /* + // Ignore events from StandardContext objects to avoid + // reregistering the context + if (lifecycle instanceof StandardContext) + return; + createMBeans(); + */ + + } else if (Lifecycle.STOP_EVENT.equals(event.getType())) { + try { + if (lifecycle instanceof Server) { + destroyMBeans((Server)lifecycle); + } + if (lifecycle instanceof Service) { + destroyMBeans((Service)lifecycle); + } + } catch (MBeanException t) { + + Exception e = t.getTargetException(); + if (e == null) { + e = t; + } + log.error("destroyMBeans: MBeanException", e); + + } catch (Throwable t) { + + log.error("destroyMBeans: Throwable", t); + + } + // FIXME: RMI adaptor should be stopped; however, this is + // undocumented in MX4J, and reports exist in the MX4J bug DB that + // this doesn't work + + } + + if ((Context.RELOAD_EVENT.equals(event.getType())) + || (Lifecycle.START_EVENT.equals(event.getType()))) { + + // Give context a new handle to the MBean server if the + // context has been reloaded since reloading causes the + // context to lose its previous handle to the server + if (lifecycle instanceof StandardContext) { + // If the context is privileged, give a reference to it + // in a servlet context attribute + StandardContext context = (StandardContext)lifecycle; + if (context.getPrivileged()) { + context.getServletContext().setAttribute + (Globals.MBEAN_REGISTRY_ATTR, + MBeanUtils.createRegistry()); + context.getServletContext().setAttribute + (Globals.MBEAN_SERVER_ATTR, + MBeanUtils.createServer()); + } + } + + } + + } + + + // ----------------------------------------- PropertyChangeListener Methods + + + /** + * Handle a PropertyChangeEvent from one of the Containers + * we are interested in. + * + * @param event The event that has occurred + */ + public void propertyChange(PropertyChangeEvent event) { + + if (event.getSource() instanceof Container) { + try { + processContainerPropertyChange((Container) event.getSource(), + event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + } catch (Exception e) { + log.error("Exception handling Container property change", e); + } + }/* else if (event.getSource() instanceof DefaultContext) { + try { + processDefaultContextPropertyChange + ((DefaultContext) event.getSource(), + event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + } catch (Exception e) { + log.error("Exception handling DefaultContext property change", e); + } + }*/ else if (event.getSource() instanceof NamingResources) { + try { + processNamingResourcesPropertyChange + ((NamingResources) event.getSource(), + event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + } catch (Exception e) { + log.error("Exception handling NamingResources property change", e); + } + } else if (event.getSource() instanceof Server) { + try { + processServerPropertyChange((Server) event.getSource(), + event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + } catch (Exception e) { + log.error("Exception handing Server property change", e); + } + } else if (event.getSource() instanceof Service) { + try { + processServicePropertyChange((Service) event.getSource(), + event.getPropertyName(), + event.getOldValue(), + event.getNewValue()); + } catch (Exception e) { + log.error("Exception handing Service property change", e); + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Create the MBeans that correspond to every existing node of our tree. + */ + protected void createMBeans() { + + try { + + MBeanFactory factory = new MBeanFactory(); + createMBeans(factory); + createMBeans(ServerFactory.getServer()); + + } catch (MBeanException t) { + + Exception e = t.getTargetException(); + if (e == null) + e = t; + log.error("createMBeans: MBeanException", e); + + } catch (Throwable t) { + + log.error("createMBeans: Throwable", t); + + } + + } + + + /** + * Create the MBeans for the specified Connector and its nested components. + * + * @param connector Connector for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Connector connector) throws Exception { + + // Create the MBean for the Connnector itself +// if (log.isDebugEnabled()) +// log.debug("Creating MBean for Connector " + connector); +// MBeanUtils.createMBean(connector); + + } + + + /** + * Create the MBeans for the specified Context and its nested components. + * + * @param context Context for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Context context) throws Exception { + + // Create the MBean for the Context itself +// if (log.isDebugEnabled()) +// log.debug("Creating MBean for Context " + context); +// MBeanUtils.createMBean(context); + context.addContainerListener(this); + if (context instanceof StandardContext) { + ((StandardContext) context).addPropertyChangeListener(this); + ((StandardContext) context).addLifecycleListener(this); + } + + // If the context is privileged, give a reference to it + // in a servlet context attribute + if (context.getPrivileged()) { + context.getServletContext().setAttribute + (Globals.MBEAN_REGISTRY_ATTR, + MBeanUtils.createRegistry()); + context.getServletContext().setAttribute + (Globals.MBEAN_SERVER_ATTR, + MBeanUtils.createServer()); + } + + // Create the MBeans for the associated nested components + Loader cLoader = context.getLoader(); + if (cLoader != null) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Loader " + cLoader); + //MBeanUtils.createMBean(cLoader); + } + Manager cManager = context.getManager(); + if (cManager != null) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Manager " + cManager); + //MBeanUtils.createMBean(cManager); + } + Realm hRealm = context.getParent().getRealm(); + Realm cRealm = context.getRealm(); + if ((cRealm != null) && (cRealm != hRealm)) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Realm " + cRealm); + //MBeanUtils.createMBean(cRealm); + } + + // Create the MBeans for the NamingResources (if any) + NamingResources resources = context.getNamingResources(); + createMBeans(resources); + + } + + + /** + * Create the MBeans for the specified ContextEnvironment entry. + * + * @param environment ContextEnvironment for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(ContextEnvironment environment) + throws Exception { + + // Create the MBean for the ContextEnvironment itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for ContextEnvironment " + environment); + } + MBeanUtils.createMBean(environment); + + } + + + /** + * Create the MBeans for the specified ContextResource entry. + * + * @param resource ContextResource for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(ContextResource resource) + throws Exception { + + // Create the MBean for the ContextResource itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for ContextResource " + resource); + } + MBeanUtils.createMBean(resource); + + } + + + /** + * Create the MBeans for the specified ContextResourceLink entry. + * + * @param resourceLink ContextResourceLink for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(ContextResourceLink resourceLink) + throws Exception { + + // Create the MBean for the ContextResourceLink itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for ContextResourceLink " + resourceLink); + } + MBeanUtils.createMBean(resourceLink); + + } + + + /** + * Create the MBeans for the specified DefaultContext and its nested components. + * + * @param dcontext DefaultContext for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + /* + protected void createMBeans(DefaultContext dcontext) throws Exception { + + // Create the MBean for the DefaultContext itself + if (log.isDebugEnabled()) + log.debug("Creating MBean for DefaultContext " + dcontext); + MBeanUtils.createMBean(dcontext); + + dcontext.addPropertyChangeListener(this); + + // Create the MBeans for the associated nested components + Loader dLoader = dcontext.getLoader(); + if (dLoader != null) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Loader " + dLoader); + //MBeanUtils.createMBean(dLoader); + } + + Manager dManager = dcontext.getManager(); + if (dManager != null) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Manager " + dManager); + //MBeanUtils.createMBean(dManager); + } + + // Create the MBeans for the NamingResources (if any) + NamingResources resources = dcontext.getNamingResources(); + createMBeans(resources); + + } + */ + + + /** + * Create the MBeans for the specified Engine and its nested components. + * + * @param engine Engine for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Engine engine) throws Exception { + + // Create the MBean for the Engine itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Engine " + engine); + } + //MBeanUtils.createMBean(engine); + engine.addContainerListener(this); + if (engine instanceof StandardEngine) { + ((StandardEngine) engine).addPropertyChangeListener(this); + } + + // Create the MBeans for the associated nested components + Realm eRealm = engine.getRealm(); + if (eRealm != null) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Realm " + eRealm); + //MBeanUtils.createMBean(eRealm); + } + + // Create the MBeans for each child Host + Container hosts[] = engine.findChildren(); + for (int j = 0; j < hosts.length; j++) { + createMBeans((Host) hosts[j]); + } + + } + + + /** + * Create the MBeans for the specified Host and its nested components. + * + * @param host Host for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Host host) throws Exception { + + // Create the MBean for the Host itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Host " + host); + } + //MBeanUtils.createMBean(host); + host.addContainerListener(this); + if (host instanceof StandardHost) { + ((StandardHost) host).addPropertyChangeListener(this); + } + + // Create the MBeans for the associated nested components + Realm eRealm = host.getParent().getRealm(); + Realm hRealm = host.getRealm(); + if ((hRealm != null) && (hRealm != eRealm)) { + if (log.isDebugEnabled()) + log.debug("Creating MBean for Realm " + hRealm); + //MBeanUtils.createMBean(hRealm); + } + + // Create the MBeans for each child Context + Container contexts[] = host.findChildren(); + for (int k = 0; k < contexts.length; k++) { + createMBeans((Context) contexts[k]); + } + + } + + + /** + * Create the MBeans for MBeanFactory. + * + * @param factory MBeanFactory for which to create MBean + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(MBeanFactory factory) throws Exception { + + // Create the MBean for the MBeanFactory + if (log.isDebugEnabled()) + log.debug("Creating MBean for MBeanFactory " + factory); + MBeanUtils.createMBean(factory); + + } + + + /** + * Create the MBeans for the specified NamingResources and its + * nested components. + * + * @param resources NamingResources for which to create MBeans + */ + protected void createMBeans(NamingResources resources) throws Exception { + + // Create the MBean for the NamingResources itself + if (log.isDebugEnabled()) { + log.debug("Creating MBean for NamingResources " + resources); + } + MBeanUtils.createMBean(resources); + resources.addPropertyChangeListener(this); + + // Create the MBeans for each child environment entry + ContextEnvironment environments[] = resources.findEnvironments(); + for (int i = 0; i < environments.length; i++) { + createMBeans(environments[i]); + } + + // Create the MBeans for each child resource entry + ContextResource cresources[] = resources.findResources(); + for (int i = 0; i < cresources.length; i++) { + createMBeans(cresources[i]); + } + + // Create the MBeans for each child resource link entry + ContextResourceLink cresourcelinks[] = resources.findResourceLinks(); + for (int i = 0; i < cresourcelinks.length; i++) { + createMBeans(cresourcelinks[i]); + } + + } + + + /** + * Create the MBeans for the specified Server and its nested components. + * + * @param server Server for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Server server) throws Exception { + + // Create the MBean for the Server itself + if (log.isDebugEnabled()) + log.debug("Creating MBean for Server " + server); + //MBeanUtils.createMBean(server); + if (server instanceof StandardServer) { + ((StandardServer) server).addPropertyChangeListener(this); + } + + // Create the MBeans for the global NamingResources (if any) + NamingResources resources = server.getGlobalNamingResources(); + if (resources != null) { + createMBeans(resources); + } + + // Create the MBeans for each child Service + Service services[] = server.findServices(); + for (int i = 0; i < services.length; i++) { + // FIXME - Warp object hierarchy not currently supported + if (services[i].getContainer().getClass().getName().equals + ("org.apache.catalina.connector.warp.WarpEngine")) { + if (log.isDebugEnabled()) { + log.debug("Skipping MBean for Service " + services[i]); + } + continue; + } + createMBeans(services[i]); + } + + } + + + /** + * Create the MBeans for the specified Service and its nested components. + * + * @param service Service for which to create MBeans + * + * @exception Exception if an exception is thrown during MBean creation + */ + protected void createMBeans(Service service) throws Exception { + + // Create the MBean for the Service itself + if (log.isDebugEnabled()) + log.debug("Creating MBean for Service " + service); + //MBeanUtils.createMBean(service); + if (service instanceof StandardService) { + ((StandardService) service).addPropertyChangeListener(this); + } + + // Create the MBeans for the corresponding Connectors + Connector connectors[] = service.findConnectors(); + for (int j = 0; j < connectors.length; j++) { + createMBeans(connectors[j]); + } + + // Create the MBean for the associated Engine and friends + Engine engine = (Engine) service.getContainer(); + if (engine != null) { + createMBeans(engine); + } + + } + + + + + /** + * Deregister the MBeans for the specified Connector and its nested + * components. + * + * @param connector Connector for which to deregister MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Connector connector, Service service) + throws Exception { + +// // deregister the MBean for the Connector itself +// if (log.isDebugEnabled()) +// log.debug("Destroying MBean for Connector " + connector); +// MBeanUtils.destroyMBean(connector, service); + + } + + + /** + * Deregister the MBeans for the specified Context and its nested + * components. + * + * @param context Context for which to deregister MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Context context) throws Exception { + + // Deregister ourselves as a ContainerListener + context.removeContainerListener(this); + + // Destroy the MBeans for the associated nested components + Realm hRealm = context.getParent().getRealm(); + Realm cRealm = context.getRealm(); + if ((cRealm != null) && (cRealm != hRealm)) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Realm " + cRealm); + //MBeanUtils.destroyMBean(cRealm); + } + Manager cManager = context.getManager(); + if (cManager != null) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Manager " + cManager); + //MBeanUtils.destroyMBean(cManager); + } + Loader cLoader = context.getLoader(); + if (cLoader != null) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Loader " + cLoader); + //MBeanUtils.destroyMBean(cLoader); + } + + // Destroy the MBeans for the NamingResources (if any) + NamingResources resources = context.getNamingResources(); + if (resources != null) { + destroyMBeans(resources); + } + + // deregister the MBean for the Context itself + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Context " + context); + //MBeanUtils.destroyMBean(context); + if (context instanceof StandardContext) { + ((StandardContext) context). + removePropertyChangeListener(this); + } + + } + + + /** + * Deregister the MBeans for the specified ContextEnvironment entry. + * + * @param environment ContextEnvironment for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(ContextEnvironment environment) + throws Exception { + + // Destroy the MBean for the ContextEnvironment itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for ContextEnvironment " + environment); + } + MBeanUtils.destroyMBean(environment); + + } + + + /** + * Deregister the MBeans for the specified ContextResource entry. + * + * @param resource ContextResource for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(ContextResource resource) + throws Exception { + + // Destroy the MBean for the ContextResource itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for ContextResource " + resource); + } + MBeanUtils.destroyMBean(resource); + + } + + + /** + * Deregister the MBeans for the specified ContextResourceLink entry. + * + * @param resourceLink ContextResourceLink for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(ContextResourceLink resourceLink) + throws Exception { + + // Destroy the MBean for the ContextResourceLink itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for ContextResourceLink " + resourceLink); + } + MBeanUtils.destroyMBean(resourceLink); + + } + + + /** + * Deregister the MBeans for the specified DefaultContext and its nested + * components. + * + * @param dcontext DefaultContext for which to deregister MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + /* + protected void destroyMBeans(DefaultContext dcontext) throws Exception { + + Manager dManager = dcontext.getManager(); + if (dManager != null) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Manager " + dManager); + //MBeanUtils.destroyMBean(dManager); + } + + Loader dLoader = dcontext.getLoader(); + if (dLoader != null) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Loader " + dLoader); + //MBeanUtils.destroyMBean(dLoader); + } + + // Destroy the MBeans for the NamingResources (if any) + NamingResources resources = dcontext.getNamingResources(); + if (resources != null) { + destroyMBeans(resources); + } + + // deregister the MBean for the DefaultContext itself + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Context " + dcontext); + MBeanUtils.destroyMBean(dcontext); + dcontext.removePropertyChangeListener(this); + + } + */ + + + /** + * Deregister the MBeans for the specified Engine and its nested + * components. + * + * @param engine Engine for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Engine engine) throws Exception { + + // Deregister ourselves as a ContainerListener + engine.removeContainerListener(this); + + // Deregister the MBeans for each child Host + Container hosts[] = engine.findChildren(); + for (int k = 0; k < hosts.length; k++) { + destroyMBeans((Host) hosts[k]); + } + + // Deregister the MBeans for the associated nested components + Realm eRealm = engine.getRealm(); + if (eRealm != null) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Realm " + eRealm); + //MBeanUtils.destroyMBean(eRealm); + } + + // Deregister the MBean for the Engine itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for Engine " + engine); + } + //MBeanUtils.destroyMBean(engine); + + } + + + /** + * Deregister the MBeans for the specified Host and its nested components. + * + * @param host Host for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Host host) throws Exception { + + // Deregister ourselves as a ContainerListener + host.removeContainerListener(this); + + // Deregister the MBeans for each child Context + Container contexts[] = host.findChildren(); + for (int k = 0; k < contexts.length; k++) { + destroyMBeans((Context) contexts[k]); + } + + + // Deregister the MBeans for the associated nested components + Realm eRealm = host.getParent().getRealm(); + Realm hRealm = host.getRealm(); + if ((hRealm != null) && (hRealm != eRealm)) { + if (log.isDebugEnabled()) + log.debug("Destroying MBean for Realm " + hRealm); + //MBeanUtils.destroyMBean(hRealm); + } + + // Deregister the MBean for the Host itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for Host " + host); + } + //MBeanUtils.destroyMBean(host); + + } + + + /** + * Deregister the MBeans for the specified NamingResources and its + * nested components. + * + * @param resources NamingResources for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(NamingResources resources) throws Exception { + + // Destroy the MBeans for each child resource entry + ContextResource cresources[] = resources.findResources(); + for (int i = 0; i < cresources.length; i++) { + destroyMBeans(cresources[i]); + } + + // Destroy the MBeans for each child resource link entry + ContextResourceLink cresourcelinks[] = resources.findResourceLinks(); + for (int i = 0; i < cresourcelinks.length; i++) { + destroyMBeans(cresourcelinks[i]); + } + + // Destroy the MBeans for each child environment entry + ContextEnvironment environments[] = resources.findEnvironments(); + for (int i = 0; i < environments.length; i++) { + destroyMBeans(environments[i]); + } + + // Destroy the MBean for the NamingResources itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for NamingResources " + resources); + } + MBeanUtils.destroyMBean(resources); + resources.removePropertyChangeListener(this); + + } + + + /** + * Deregister the MBeans for the specified Server and its related + * components. + * + * @param server Server for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Server server) throws Exception { + + // Destroy the MBeans for the global NamingResources (if any) + NamingResources resources = server.getGlobalNamingResources(); + if (resources != null) { + destroyMBeans(resources); + } + + // Destroy the MBeans for each child Service + Service services[] = server.findServices(); + for (int i = 0; i < services.length; i++) { + // FIXME - Warp object hierarchy not currently supported + if (services[i].getContainer().getClass().getName().equals + ("org.apache.catalina.connector.warp.WarpEngine")) { + if (log.isDebugEnabled()) { + log.debug("Skipping MBean for Service " + services[i]); + } + continue; + } + destroyMBeans(services[i]); + } + + // Destroy the MBean for the Server itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for Server " + server); + } + //MBeanUtils.destroyMBean(server); + if (server instanceof StandardServer) { + ((StandardServer) server).removePropertyChangeListener(this); + } + + } + + + /** + * Deregister the MBeans for the specified Service and its nested + * components. + * + * @param service Service for which to destroy MBeans + * + * @exception Exception if an exception is thrown during MBean destruction + */ + protected void destroyMBeans(Service service) throws Exception { + + // Deregister the MBeans for the associated Engine + Engine engine = (Engine) service.getContainer(); + if (engine != null) { + //destroyMBeans(engine); + } + +// // Deregister the MBeans for the corresponding Connectors +// Connector connectors[] = service.findConnectors(); +// for (int j = 0; j < connectors.length; j++) { +// destroyMBeans(connectors[j], service); +// } + + // Deregister the MBean for the Service itself + if (log.isDebugEnabled()) { + log.debug("Destroying MBean for Service " + service); + } + //MBeanUtils.destroyMBean(service); + if (service instanceof StandardService) { + ((StandardService) service).removePropertyChangeListener(this); + } + + } + + + /** + * Process the addition of a new child Container to a parent Container. + * + * @param parent Parent container + * @param child Child container + */ + protected void processContainerAddChild(Container parent, + Container child) { + + if (log.isDebugEnabled()) + log.debug("Process addChild[parent=" + parent + ",child=" + child + "]"); + + try { + if (child instanceof Context) { + createMBeans((Context) child); + } else if (child instanceof Engine) { + createMBeans((Engine) child); + } else if (child instanceof Host) { + createMBeans((Host) child); + } + } catch (MBeanException t) { + Exception e = t.getTargetException(); + if (e == null) + e = t; + log.error("processContainerAddChild: MBeanException", e); + } catch (Throwable t) { + log.error("processContainerAddChild: Throwable", t); + } + + } + + + + + /** + * Process a property change event on a Container. + * + * @param container The container on which this event occurred + * @param propertyName The name of the property that changed + * @param oldValue The previous value (may be null) + * @param newValue The new value (may be null) + * + * @exception Exception if an exception is thrown + */ + protected void processContainerPropertyChange(Container container, + String propertyName, + Object oldValue, + Object newValue) + throws Exception { + + if (log.isTraceEnabled()) { + log.trace("propertyChange[container=" + container + + ",propertyName=" + propertyName + + ",oldValue=" + oldValue + + ",newValue=" + newValue + "]"); + } + if ("loader".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Loader " + oldValue); + } + MBeanUtils.destroyMBean((Loader) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Loader " + newValue); + } + MBeanUtils.createMBean((Loader) newValue); + } + } else if ("logger".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Logger " + oldValue); + } + // MBeanUtils.destroyMBean((Logger) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Logger " + newValue); + } + //MBeanUtils.createMBean((Logger) newValue); + } + } else if ("manager".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Manager " + oldValue); + } + //MBeanUtils.destroyMBean((Manager) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Manager " + newValue); + } + //MBeanUtils.createMBean((Manager) newValue); + } + } else if ("realm".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Realm " + oldValue); + } + MBeanUtils.destroyMBean((Realm) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Realm " + newValue); + } + //MBeanUtils.createMBean((Realm) newValue); + } + } else if ("service".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((Service) oldValue); + } + if (newValue != null) { + createMBeans((Service) newValue); + } + } + + } + + + /** + * Process a property change event on a DefaultContext. + * + * @param defaultContext The DefaultContext on which this event occurred + * @param propertyName The name of the property that changed + * @param oldValue The previous value (may be null) + * @param newValue The new value (may be null) + * + * @exception Exception if an exception is thrown + */ + /* + protected void processDefaultContextPropertyChange(DefaultContext defaultContext, + String propertyName, + Object oldValue, + Object newValue) + throws Exception { + + if (log.isTraceEnabled()) { + log.trace("propertyChange[defaultContext=" + defaultContext + + ",propertyName=" + propertyName + + ",oldValue=" + oldValue + + ",newValue=" + newValue + "]"); + } + if ("loader".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Loader " + oldValue); + } + MBeanUtils.destroyMBean((Loader) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Loader " + newValue); + } + MBeanUtils.createMBean((Loader) newValue); + } + } else if ("logger".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Logger " + oldValue); + } + //MBeanUtils.destroyMBean((Logger) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Logger " + newValue); + } + //MBeanUtils.createMBean((Logger) newValue); + } + } else if ("manager".equals(propertyName)) { + if (oldValue != null) { + if (log.isDebugEnabled()) { + log.debug("Removing MBean for Manager " + oldValue); + } + MBeanUtils.destroyMBean((Manager) oldValue); + } + if (newValue != null) { + if (log.isDebugEnabled()) { + log.debug("Creating MBean for Manager " + newValue); + } + MBeanUtils.createMBean((Manager) newValue); + } + } else if ("realm".equals(propertyName)) { + if (oldValue != null) { +// if (log.isDebugEnabled()) { +// log.debug("Removing MBean for Realm " + oldValue); +// } +// //MBeanUtils.destroyMBean((Realm) oldValue); + } + if (newValue != null) { +// if (log.isDebugEnabled()) { +// log.debug("Creating MBean for Realm " + newValue); +// } +// //MBeanUtils.createMBean((Realm) newValue); + } + } else if ("service".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((Service) oldValue); + } + if (newValue != null) { + createMBeans((Service) newValue); + } + } + + }*/ + + + /** + * Process the removal of a child Container from a parent Container. + * + * @param parent Parent container + * @param child Child container + */ + protected void processContainerRemoveChild(Container parent, + Container child) { + + if (log.isDebugEnabled()) + log.debug("Process removeChild[parent=" + parent + ",child=" + + child + "]"); + + try { + if (child instanceof Context) { + Context context = (Context) child; + if (context.getPrivileged()) { + context.getServletContext().removeAttribute + (Globals.MBEAN_REGISTRY_ATTR); + context.getServletContext().removeAttribute + (Globals.MBEAN_SERVER_ATTR); + } + if (log.isDebugEnabled()) + log.debug(" Removing MBean for Context " + context); + destroyMBeans(context); + if (context instanceof StandardContext) { + ((StandardContext) context). + removePropertyChangeListener(this); + } + } else if (child instanceof Host) { + Host host = (Host) child; + destroyMBeans(host); + if (host instanceof StandardHost) { + ((StandardHost) host). + removePropertyChangeListener(this); + } + } + } catch (MBeanException t) { + Exception e = t.getTargetException(); + if (e == null) + e = t; + log.error("processContainerRemoveChild: MBeanException", e); + } catch (Throwable t) { + log.error("processContainerRemoveChild: Throwable", t); + } + + } + + + /** + * Process a property change event on a NamingResources. + * + * @param resources The global naming resources on which this + * event occurred + * @param propertyName The name of the property that changed + * @param oldValue The previous value (may be null) + * @param newValue The new value (may be null) + * + * @exception Exception if an exception is thrown + */ + protected void processNamingResourcesPropertyChange + (NamingResources resources, String propertyName, + Object oldValue, Object newValue) + throws Exception { + + if (log.isTraceEnabled()) { + log.trace("propertyChange[namingResources=" + resources + + ",propertyName=" + propertyName + + ",oldValue=" + oldValue + + ",newValue=" + newValue + "]"); + } + + // FIXME - Add other resource types when supported by admin tool + if ("environment".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((ContextEnvironment) oldValue); + } + if (newValue != null) { + createMBeans((ContextEnvironment) newValue); + } + } else if ("resource".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((ContextResource) oldValue); + } + if (newValue != null) { + createMBeans((ContextResource) newValue); + } + } else if ("resourceLink".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((ContextResourceLink) oldValue); + } + if (newValue != null) { + createMBeans((ContextResourceLink) newValue); + } + } + + } + + + /** + * Process a property change event on a Server. + * + * @param server The server on which this event occurred + * @param propertyName The name of the property that changed + * @param oldValue The previous value (may be null) + * @param newValue The new value (may be null) + * + * @exception Exception if an exception is thrown + */ + protected void processServerPropertyChange(Server server, + String propertyName, + Object oldValue, + Object newValue) + throws Exception { + + if (log.isTraceEnabled()) { + log.trace("propertyChange[server=" + server + + ",propertyName=" + propertyName + + ",oldValue=" + oldValue + + ",newValue=" + newValue + "]"); + } + if ("globalNamingResources".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((NamingResources) oldValue); + } + if (newValue != null) { + createMBeans((NamingResources) newValue); + } + } else if ("service".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((Service) oldValue); + } + if (newValue != null) { + createMBeans((Service) newValue); + } + } + + } + + + /** + * Process a property change event on a Service. + * + * @param service The service on which this event occurred + * @param propertyName The name of the property that changed + * @param oldValue The previous value (may be null) + * @param newValue The new value (may be null) + * + * @exception Exception if an exception is thrown + */ + protected void processServicePropertyChange(Service service, + String propertyName, + Object oldValue, + Object newValue) + throws Exception { + + if (log.isTraceEnabled()) { + log.trace("propertyChange[service=" + service + + ",propertyName=" + propertyName + + ",oldValue=" + oldValue + + ",newValue=" + newValue + "]"); + } + if ("connector".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((Connector) oldValue, service); + } + if (newValue != null) { + createMBeans((Connector) newValue); + } + } else if ("container".equals(propertyName)) { + if (oldValue != null) { + destroyMBeans((Engine) oldValue); + } + if (newValue != null) { + createMBeans((Engine) newValue); + } + } + + } + + +} diff --git a/java/org/apache/catalina/mbeans/StandardContextMBean.java b/java/org/apache/catalina/mbeans/StandardContextMBean.java index adbedc114..760676ebd 100644 --- a/java/org/apache/catalina/mbeans/StandardContextMBean.java +++ b/java/org/apache/catalina/mbeans/StandardContextMBean.java @@ -1,357 +1,357 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - -import java.util.ArrayList; - -import javax.management.MBeanException; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceLink; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardContext component.

    - * - * @author Amy Roh - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class StandardContextMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public StandardContextMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("StandardContext"); - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the naming resources associated with this web application. - */ - private NamingResources getNamingResources() { - - return ((StandardContext)this.resource).getNamingResources(); - - } - - /** - * Return the naming resources associated with this web application. - */ - public void reload() { - - ((StandardContext)this.resource).reload(); - - } - - - /** - * Return the MBean Names of the set of defined environment entries for - * this web application - */ - public String[] getEnvironments() { - ContextEnvironment[] envs = getNamingResources().findEnvironments(); - ArrayList results = new ArrayList(); - for (int i = 0; i < envs.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), envs[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for environment " + envs[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource references for this - * application. - */ - public String[] getResources() { - - ContextResource[] resources = getNamingResources().findResources(); - ArrayList results = new ArrayList(); - for (int i = 0; i < resources.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resources[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + resources[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all the defined resource links for this - * application - */ - public String[] getResourceLinks() { - - ContextResourceLink[] links = getNamingResources().findResourceLinks(); - ArrayList results = new ArrayList(); - for (int i = 0; i < links.length; i++) { - try { - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), links[i]); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for resource " + links[i]); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the naming resources associated with this web application. - */ - public javax.naming.directory.DirContext getStaticResources() { - - return ((StandardContext)this.resource).getResources(); - - } - - - /** - * Return the naming resources associated with this web application. - */ - public String[] getWelcomeFiles() { - - return ((StandardContext)this.resource).findWelcomeFiles(); - - } - - - // ------------------------------------------------------------- Operations - - - /** - * Add an environment entry for this web application. - * - * @param envName New environment entry name - */ - public String addEnvironment(String envName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env != null) { - throw new IllegalArgumentException - ("Invalid environment name - already exists '" + envName + "'"); - } - env = new ContextEnvironment(); - env.setName(envName); - env.setType(type); - nresources.addEnvironment(env); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextEnvironment"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), env); - return (oname.toString()); - - } - - - /** - * Add a resource reference for this web application. - * - * @param resourceName New resource reference name - */ - public String addResource(String resourceName, String type) - throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource != null) { - throw new IllegalArgumentException - ("Invalid resource name - already exists'" + resourceName + "'"); - } - resource = new ContextResource(); - resource.setName(resourceName); - resource.setType(type); - nresources.addResource(resource); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResource"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resource); - return (oname.toString()); - } - - - /** - * Add a resource link for this web application. - * - * @param resourceLinkName New resource link name - */ - public String addResourceLink(String resourceLinkName, String global, - String name, String type) throws MalformedObjectNameException { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return null; - } - ContextResourceLink resourceLink = - nresources.findResourceLink(resourceLinkName); - if (resourceLink != null) { - throw new IllegalArgumentException - ("Invalid resource link name - already exists'" + - resourceLinkName + "'"); - } - resourceLink = new ContextResourceLink(); - resourceLink.setGlobal(global); - resourceLink.setName(resourceLinkName); - resourceLink.setType(type); - nresources.addResourceLink(resourceLink); - - // Return the corresponding MBean name - ManagedBean managed = registry.findManagedBean("ContextResourceLink"); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), resourceLink); - return (oname.toString()); - } - - - /** - * Remove any environment entry with the specified name. - * - * @param envName Name of the environment entry to remove - */ - public void removeEnvironment(String envName) { - - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextEnvironment env = nresources.findEnvironment(envName); - if (env == null) { - throw new IllegalArgumentException - ("Invalid environment name '" + envName + "'"); - } - nresources.removeEnvironment(envName); - - } - - - /** - * Remove any resource reference with the specified name. - * - * @param resourceName Name of the resource reference to remove - */ - public void removeResource(String resourceName) { - - resourceName = ObjectName.unquote(resourceName); - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextResource resource = nresources.findResource(resourceName); - if (resource == null) { - throw new IllegalArgumentException - ("Invalid resource name '" + resourceName + "'"); - } - nresources.removeResource(resourceName); - } - - - /** - * Remove any resource link with the specified name. - * - * @param resourceLinkName Name of the resource reference to remove - */ - public void removeResourceLink(String resourceLinkName) { - - resourceLinkName = ObjectName.unquote(resourceLinkName); - NamingResources nresources = getNamingResources(); - if (nresources == null) { - return; - } - ContextResourceLink resource = nresources.findResourceLink(resourceLinkName); - if (resource == null) { - throw new IllegalArgumentException - ("Invalid resource name '" + resourceLinkName + "'"); - } - nresources.removeResourceLink(resourceLinkName); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + +import java.util.ArrayList; + +import javax.management.MBeanException; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceLink; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardContext component.

    + * + * @author Amy Roh + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class StandardContextMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public StandardContextMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("StandardContext"); + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the naming resources associated with this web application. + */ + private NamingResources getNamingResources() { + + return ((StandardContext)this.resource).getNamingResources(); + + } + + /** + * Return the naming resources associated with this web application. + */ + public void reload() { + + ((StandardContext)this.resource).reload(); + + } + + + /** + * Return the MBean Names of the set of defined environment entries for + * this web application + */ + public String[] getEnvironments() { + ContextEnvironment[] envs = getNamingResources().findEnvironments(); + ArrayList results = new ArrayList(); + for (int i = 0; i < envs.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), envs[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for environment " + envs[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource references for this + * application. + */ + public String[] getResources() { + + ContextResource[] resources = getNamingResources().findResources(); + ArrayList results = new ArrayList(); + for (int i = 0; i < resources.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resources[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + resources[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all the defined resource links for this + * application + */ + public String[] getResourceLinks() { + + ContextResourceLink[] links = getNamingResources().findResourceLinks(); + ArrayList results = new ArrayList(); + for (int i = 0; i < links.length; i++) { + try { + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), links[i]); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for resource " + links[i]); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the naming resources associated with this web application. + */ + public javax.naming.directory.DirContext getStaticResources() { + + return ((StandardContext)this.resource).getResources(); + + } + + + /** + * Return the naming resources associated with this web application. + */ + public String[] getWelcomeFiles() { + + return ((StandardContext)this.resource).findWelcomeFiles(); + + } + + + // ------------------------------------------------------------- Operations + + + /** + * Add an environment entry for this web application. + * + * @param envName New environment entry name + */ + public String addEnvironment(String envName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env != null) { + throw new IllegalArgumentException + ("Invalid environment name - already exists '" + envName + "'"); + } + env = new ContextEnvironment(); + env.setName(envName); + env.setType(type); + nresources.addEnvironment(env); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextEnvironment"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), env); + return (oname.toString()); + + } + + + /** + * Add a resource reference for this web application. + * + * @param resourceName New resource reference name + */ + public String addResource(String resourceName, String type) + throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource != null) { + throw new IllegalArgumentException + ("Invalid resource name - already exists'" + resourceName + "'"); + } + resource = new ContextResource(); + resource.setName(resourceName); + resource.setType(type); + nresources.addResource(resource); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResource"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resource); + return (oname.toString()); + } + + + /** + * Add a resource link for this web application. + * + * @param resourceLinkName New resource link name + */ + public String addResourceLink(String resourceLinkName, String global, + String name, String type) throws MalformedObjectNameException { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return null; + } + ContextResourceLink resourceLink = + nresources.findResourceLink(resourceLinkName); + if (resourceLink != null) { + throw new IllegalArgumentException + ("Invalid resource link name - already exists'" + + resourceLinkName + "'"); + } + resourceLink = new ContextResourceLink(); + resourceLink.setGlobal(global); + resourceLink.setName(resourceLinkName); + resourceLink.setType(type); + nresources.addResourceLink(resourceLink); + + // Return the corresponding MBean name + ManagedBean managed = registry.findManagedBean("ContextResourceLink"); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), resourceLink); + return (oname.toString()); + } + + + /** + * Remove any environment entry with the specified name. + * + * @param envName Name of the environment entry to remove + */ + public void removeEnvironment(String envName) { + + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextEnvironment env = nresources.findEnvironment(envName); + if (env == null) { + throw new IllegalArgumentException + ("Invalid environment name '" + envName + "'"); + } + nresources.removeEnvironment(envName); + + } + + + /** + * Remove any resource reference with the specified name. + * + * @param resourceName Name of the resource reference to remove + */ + public void removeResource(String resourceName) { + + resourceName = ObjectName.unquote(resourceName); + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextResource resource = nresources.findResource(resourceName); + if (resource == null) { + throw new IllegalArgumentException + ("Invalid resource name '" + resourceName + "'"); + } + nresources.removeResource(resourceName); + } + + + /** + * Remove any resource link with the specified name. + * + * @param resourceLinkName Name of the resource reference to remove + */ + public void removeResourceLink(String resourceLinkName) { + + resourceLinkName = ObjectName.unquote(resourceLinkName); + NamingResources nresources = getNamingResources(); + if (nresources == null) { + return; + } + ContextResourceLink resource = nresources.findResourceLink(resourceLinkName); + if (resource == null) { + throw new IllegalArgumentException + ("Invalid resource name '" + resourceLinkName + "'"); + } + nresources.removeResourceLink(resourceLinkName); + } + + +} diff --git a/java/org/apache/catalina/mbeans/StandardEngineMBean.java b/java/org/apache/catalina/mbeans/StandardEngineMBean.java index 6e4e6a87e..910361ae0 100644 --- a/java/org/apache/catalina/mbeans/StandardEngineMBean.java +++ b/java/org/apache/catalina/mbeans/StandardEngineMBean.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.RuntimeOperationsException; - -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardEngine component.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class StandardEngineMBean extends BaseModelMBean { - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = MBeanUtils.createServer(); - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public StandardEngineMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - - // ------------------------------------------------------------- Operations - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.RuntimeOperationsException; + +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardEngine component.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class StandardEngineMBean extends BaseModelMBean { + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = MBeanUtils.createServer(); + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public StandardEngineMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + + // ------------------------------------------------------------- Operations + + +} diff --git a/java/org/apache/catalina/mbeans/StandardHostMBean.java b/java/org/apache/catalina/mbeans/StandardHostMBean.java index 4555710e5..6dbe64e71 100644 --- a/java/org/apache/catalina/mbeans/StandardHostMBean.java +++ b/java/org/apache/catalina/mbeans/StandardHostMBean.java @@ -1,149 +1,149 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Valve; -import org.apache.catalina.core.StandardHost; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardHost component.

    - * - * @author Amy Roh - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class StandardHostMBean extends BaseModelMBean { - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = MBeanUtils.createServer(); - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public StandardHostMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - - // ------------------------------------------------------------- Operations - - - /** - * Add an alias name that should be mapped to this Host - * - * @param alias The alias to be added - * - * @exception Exception if an MBean cannot be created or registered - */ - public void addAlias(String alias) - throws Exception { - - StandardHost host = (StandardHost) this.resource; - host.addAlias(alias); - - } - - - /** - * Return the set of alias names for this Host - * - * @exception Exception if an MBean cannot be created or registered - */ - public String [] findAliases() - throws Exception { - - StandardHost host = (StandardHost) this.resource; - return host.findAliases(); - - } - - - /** - * Return the MBean Names of the Valves assoicated with this Host - * - * @exception Exception if an MBean cannot be created or registered - */ - public String [] getValves() - throws Exception { - - Registry registry = MBeanUtils.createRegistry(); - StandardHost host = (StandardHost) this.resource; - String mname = MBeanUtils.createManagedName(host); - ManagedBean managed = registry.findManagedBean(mname); - String domain = null; - if (managed != null) { - domain = managed.getDomain(); - } - if (domain == null) - domain = mserver.getDefaultDomain(); - Valve [] valves = host.getValves(); - String [] mbeanNames = new String[valves.length]; - for (int i = 0; i < valves.length; i++) { - mbeanNames[i] = - MBeanUtils.createObjectName(domain, valves[i]).toString(); - } - - return mbeanNames; - - } - - - /** - * Return the specified alias name from the aliases for this Host - * - * @param alias Alias name to be removed - * - * @exception Exception if an MBean cannot be created or registered - */ - public void removeAlias(String alias) - throws Exception { - - StandardHost host = (StandardHost) this.resource; - host.removeAlias(alias); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Valve; +import org.apache.catalina.core.StandardHost; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardHost component.

    + * + * @author Amy Roh + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class StandardHostMBean extends BaseModelMBean { + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = MBeanUtils.createServer(); + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public StandardHostMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + + // ------------------------------------------------------------- Operations + + + /** + * Add an alias name that should be mapped to this Host + * + * @param alias The alias to be added + * + * @exception Exception if an MBean cannot be created or registered + */ + public void addAlias(String alias) + throws Exception { + + StandardHost host = (StandardHost) this.resource; + host.addAlias(alias); + + } + + + /** + * Return the set of alias names for this Host + * + * @exception Exception if an MBean cannot be created or registered + */ + public String [] findAliases() + throws Exception { + + StandardHost host = (StandardHost) this.resource; + return host.findAliases(); + + } + + + /** + * Return the MBean Names of the Valves assoicated with this Host + * + * @exception Exception if an MBean cannot be created or registered + */ + public String [] getValves() + throws Exception { + + Registry registry = MBeanUtils.createRegistry(); + StandardHost host = (StandardHost) this.resource; + String mname = MBeanUtils.createManagedName(host); + ManagedBean managed = registry.findManagedBean(mname); + String domain = null; + if (managed != null) { + domain = managed.getDomain(); + } + if (domain == null) + domain = mserver.getDefaultDomain(); + Valve [] valves = host.getValves(); + String [] mbeanNames = new String[valves.length]; + for (int i = 0; i < valves.length; i++) { + mbeanNames[i] = + MBeanUtils.createObjectName(domain, valves[i]).toString(); + } + + return mbeanNames; + + } + + + /** + * Return the specified alias name from the aliases for this Host + * + * @param alias Alias name to be removed + * + * @exception Exception if an MBean cannot be created or registered + */ + public void removeAlias(String alias) + throws Exception { + + StandardHost host = (StandardHost) this.resource; + host.removeAlias(alias); + + } + + +} diff --git a/java/org/apache/catalina/mbeans/StandardServerMBean.java b/java/org/apache/catalina/mbeans/StandardServerMBean.java index 94b8547bc..204b2d56b 100644 --- a/java/org/apache/catalina/mbeans/StandardServerMBean.java +++ b/java/org/apache/catalina/mbeans/StandardServerMBean.java @@ -1,102 +1,102 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.InstanceNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.RuntimeOperationsException; -import org.apache.catalina.Server; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.core.StandardServer; -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardServer component.

    - * - * @author Amy Roh - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class StandardServerMBean extends BaseModelMBean { - - - // ------------------------------------------------------- Static Variables - - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = MBeanUtils.createServer(); - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public StandardServerMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - // ------------------------------------------------------------- Operations - - - /** - * Write the configuration information for this entire Server - * out to the server.xml configuration file. - * - * @exception InstanceNotFoundException if the managed resource object - * cannot be found - * @exception MBeanException if the initializer of the object throws - * an exception, or persistence is not supported - * @exception RuntimeOperationsException if an exception is reported - * by the persistence mechanism - */ - public synchronized void store() throws InstanceNotFoundException, - MBeanException, RuntimeOperationsException { - - Server server = ServerFactory.getServer(); - if (server instanceof StandardServer) { - try { - ((StandardServer) server).storeConfig(); - } catch (Exception e) { - throw new MBeanException(e, "Error updating conf/server.xml"); - } - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.InstanceNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.RuntimeOperationsException; +import org.apache.catalina.Server; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.core.StandardServer; +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardServer component.

    + * + * @author Amy Roh + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class StandardServerMBean extends BaseModelMBean { + + + // ------------------------------------------------------- Static Variables + + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = MBeanUtils.createServer(); + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public StandardServerMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + // ------------------------------------------------------------- Operations + + + /** + * Write the configuration information for this entire Server + * out to the server.xml configuration file. + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception, or persistence is not supported + * @exception RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ + public synchronized void store() throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException { + + Server server = ServerFactory.getServer(); + if (server instanceof StandardServer) { + try { + ((StandardServer) server).storeConfig(); + } catch (Exception e) { + throw new MBeanException(e, "Error updating conf/server.xml"); + } + } + + } + + +} diff --git a/java/org/apache/catalina/mbeans/StandardServiceMBean.java b/java/org/apache/catalina/mbeans/StandardServiceMBean.java index 503996d9d..a38793271 100644 --- a/java/org/apache/catalina/mbeans/StandardServiceMBean.java +++ b/java/org/apache/catalina/mbeans/StandardServiceMBean.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.RuntimeOperationsException; - -import org.apache.tomcat.util.modeler.BaseModelMBean; - - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.core.StandardService component.

    - * - * @author Amy Roh - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class StandardServiceMBean extends BaseModelMBean { - - /** - * The MBeanServer for this application. - */ - private static MBeanServer mserver = MBeanUtils.createServer(); - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public StandardServiceMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ------------------------------------------------------------- Attributes - - - - // ------------------------------------------------------------- Operations - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.RuntimeOperationsException; + +import org.apache.tomcat.util.modeler.BaseModelMBean; + + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.core.StandardService component.

    + * + * @author Amy Roh + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class StandardServiceMBean extends BaseModelMBean { + + /** + * The MBeanServer for this application. + */ + private static MBeanServer mserver = MBeanUtils.createServer(); + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public StandardServiceMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ------------------------------------------------------------- Attributes + + + + // ------------------------------------------------------------- Operations + + +} diff --git a/java/org/apache/catalina/mbeans/UserMBean.java b/java/org/apache/catalina/mbeans/UserMBean.java index 05dc48409..c5d7b1d40 100644 --- a/java/org/apache/catalina/mbeans/UserMBean.java +++ b/java/org/apache/catalina/mbeans/UserMBean.java @@ -1,233 +1,233 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.mbeans; - - -import java.util.ArrayList; -import java.util.Iterator; - -import javax.management.MBeanException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.management.RuntimeOperationsException; - -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.User; -import org.apache.tomcat.util.modeler.BaseModelMBean; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.Registry; - -/** - *

    A ModelMBean implementation for the - * org.apache.catalina.User component.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ - */ - -public class UserMBean extends BaseModelMBean { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - public UserMBean() - throws MBeanException, RuntimeOperationsException { - - super(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The configuration information registry for our managed beans. - */ - protected Registry registry = MBeanUtils.createRegistry(); - - - /** - * The MBeanServer in which we are registered. - */ - protected MBeanServer mserver = MBeanUtils.createServer(); - - - /** - * The ManagedBean information describing this MBean. - */ - protected ManagedBean managed = - registry.findManagedBean("User"); - - - // ------------------------------------------------------------- Attributes - - - /** - * Return the MBean Names of all groups this user is a member of. - */ - public String[] getGroups() { - - User user = (User) this.resource; - ArrayList results = new ArrayList(); - Iterator groups = user.getGroups(); - while (groups.hasNext()) { - Group group = null; - try { - group = (Group) groups.next(); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), group); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for group " + group); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - /** - * Return the MBean Names of all roles assigned to this user. - */ - public String[] getRoles() { - - User user = (User) this.resource; - ArrayList results = new ArrayList(); - Iterator roles = user.getRoles(); - while (roles.hasNext()) { - Role role = null; - try { - role = (Role) roles.next(); - ObjectName oname = - MBeanUtils.createObjectName(managed.getDomain(), role); - results.add(oname.toString()); - } catch (MalformedObjectNameException e) { - IllegalArgumentException iae = new IllegalArgumentException - ("Cannot create object name for role " + role); - iae.initCause(e); - throw iae; - } - } - return ((String[]) results.toArray(new String[results.size()])); - - } - - - // ------------------------------------------------------------- Operations - - - /** - * Add a new {@link Group} to those this user belongs to. - * - * @param groupname Group name of the new group - */ - public void addGroup(String groupname) { - - User user = (User) this.resource; - if (user == null) { - return; - } - Group group = user.getUserDatabase().findGroup(groupname); - if (group == null) { - throw new IllegalArgumentException - ("Invalid group name '" + groupname + "'"); - } - user.addGroup(group); - - } - - - /** - * Add a new {@link Role} to those this user belongs to. - * - * @param rolename Role name of the new role - */ - public void addRole(String rolename) { - - User user = (User) this.resource; - if (user == null) { - return; - } - Role role = user.getUserDatabase().findRole(rolename); - if (role == null) { - throw new IllegalArgumentException - ("Invalid role name '" + rolename + "'"); - } - user.addRole(role); - - } - - - /** - * Remove a {@link Group} from those this user belongs to. - * - * @param groupname Group name of the old group - */ - public void removeGroup(String groupname) { - - User user = (User) this.resource; - if (user == null) { - return; - } - Group group = user.getUserDatabase().findGroup(groupname); - if (group == null) { - throw new IllegalArgumentException - ("Invalid group name '" + groupname + "'"); - } - user.removeGroup(group); - - } - - - /** - * Remove a {@link Role} from those this user belongs to. - * - * @param rolename Role name of the old role - */ - public void removeRole(String rolename) { - - User user = (User) this.resource; - if (user == null) { - return; - } - Role role = user.getUserDatabase().findRole(rolename); - if (role == null) { - throw new IllegalArgumentException - ("Invalid role name '" + rolename + "'"); - } - user.removeRole(role); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.mbeans; + + +import java.util.ArrayList; +import java.util.Iterator; + +import javax.management.MBeanException; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.management.RuntimeOperationsException; + +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; + +/** + *

    A ModelMBean implementation for the + * org.apache.catalina.User component.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302833 $ $Date: 2004-04-15 03:44:09 +0200 (jeu., 15 avr. 2004) $ + */ + +public class UserMBean extends BaseModelMBean { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + public UserMBean() + throws MBeanException, RuntimeOperationsException { + + super(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The configuration information registry for our managed beans. + */ + protected Registry registry = MBeanUtils.createRegistry(); + + + /** + * The MBeanServer in which we are registered. + */ + protected MBeanServer mserver = MBeanUtils.createServer(); + + + /** + * The ManagedBean information describing this MBean. + */ + protected ManagedBean managed = + registry.findManagedBean("User"); + + + // ------------------------------------------------------------- Attributes + + + /** + * Return the MBean Names of all groups this user is a member of. + */ + public String[] getGroups() { + + User user = (User) this.resource; + ArrayList results = new ArrayList(); + Iterator groups = user.getGroups(); + while (groups.hasNext()) { + Group group = null; + try { + group = (Group) groups.next(); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), group); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for group " + group); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + /** + * Return the MBean Names of all roles assigned to this user. + */ + public String[] getRoles() { + + User user = (User) this.resource; + ArrayList results = new ArrayList(); + Iterator roles = user.getRoles(); + while (roles.hasNext()) { + Role role = null; + try { + role = (Role) roles.next(); + ObjectName oname = + MBeanUtils.createObjectName(managed.getDomain(), role); + results.add(oname.toString()); + } catch (MalformedObjectNameException e) { + IllegalArgumentException iae = new IllegalArgumentException + ("Cannot create object name for role " + role); + iae.initCause(e); + throw iae; + } + } + return ((String[]) results.toArray(new String[results.size()])); + + } + + + // ------------------------------------------------------------- Operations + + + /** + * Add a new {@link Group} to those this user belongs to. + * + * @param groupname Group name of the new group + */ + public void addGroup(String groupname) { + + User user = (User) this.resource; + if (user == null) { + return; + } + Group group = user.getUserDatabase().findGroup(groupname); + if (group == null) { + throw new IllegalArgumentException + ("Invalid group name '" + groupname + "'"); + } + user.addGroup(group); + + } + + + /** + * Add a new {@link Role} to those this user belongs to. + * + * @param rolename Role name of the new role + */ + public void addRole(String rolename) { + + User user = (User) this.resource; + if (user == null) { + return; + } + Role role = user.getUserDatabase().findRole(rolename); + if (role == null) { + throw new IllegalArgumentException + ("Invalid role name '" + rolename + "'"); + } + user.addRole(role); + + } + + + /** + * Remove a {@link Group} from those this user belongs to. + * + * @param groupname Group name of the old group + */ + public void removeGroup(String groupname) { + + User user = (User) this.resource; + if (user == null) { + return; + } + Group group = user.getUserDatabase().findGroup(groupname); + if (group == null) { + throw new IllegalArgumentException + ("Invalid group name '" + groupname + "'"); + } + user.removeGroup(group); + + } + + + /** + * Remove a {@link Role} from those this user belongs to. + * + * @param rolename Role name of the old role + */ + public void removeRole(String rolename) { + + User user = (User) this.resource; + if (user == null) { + return; + } + Role role = user.getUserDatabase().findRole(rolename); + if (role == null) { + throw new IllegalArgumentException + ("Invalid role name '" + rolename + "'"); + } + user.removeRole(role); + + } + + +} diff --git a/java/org/apache/catalina/mbeans/mbeans-descriptors.xml b/java/org/apache/catalina/mbeans/mbeans-descriptors.xml index 6b5939f6a..e6a67d15e 100644 --- a/java/org/apache/catalina/mbeans/mbeans-descriptors.xml +++ b/java/org/apache/catalina/mbeans/mbeans-descriptors.xml @@ -1,405 +1,405 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/realm/Constants.java b/java/org/apache/catalina/realm/Constants.java index 372f4c4f3..d81f92bc1 100644 --- a/java/org/apache/catalina/realm/Constants.java +++ b/java/org/apache/catalina/realm/Constants.java @@ -1,44 +1,44 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -/** - * Manifest constants for this Java package. - * - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class Constants { - - public static final String Package = "org.apache.catalina.realm"; - - // Authentication methods for login configuration - public static final String FORM_METHOD = "FORM"; - - // Form based authentication constants - public static final String FORM_ACTION = "/j_security_check"; - - // User data constraints for transport guarantee - public static final String NONE_TRANSPORT = "NONE"; - public static final String INTEGRAL_TRANSPORT = "INTEGRAL"; - public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +/** + * Manifest constants for this Java package. + * + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class Constants { + + public static final String Package = "org.apache.catalina.realm"; + + // Authentication methods for login configuration + public static final String FORM_METHOD = "FORM"; + + // Form based authentication constants + public static final String FORM_ACTION = "/j_security_check"; + + // User data constraints for transport guarantee + public static final String NONE_TRANSPORT = "NONE"; + public static final String INTEGRAL_TRANSPORT = "INTEGRAL"; + public static final String CONFIDENTIAL_TRANSPORT = "CONFIDENTIAL"; + +} diff --git a/java/org/apache/catalina/realm/DataSourceRealm.java b/java/org/apache/catalina/realm/DataSourceRealm.java index 7cfcf17aa..8b7f32d0d 100644 --- a/java/org/apache/catalina/realm/DataSourceRealm.java +++ b/java/org/apache/catalina/realm/DataSourceRealm.java @@ -1,662 +1,662 @@ -/* - * Copyright 1999,2004-2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; - -import javax.naming.Context; -import javax.sql.DataSource; - -import org.apache.naming.ContextBindings; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.core.StandardServer; -import org.apache.catalina.util.StringManager; - -/** -* -* Implmentation of Realm that works with any JDBC JNDI DataSource. -* See the JDBCRealm.howto for more details on how to set up the database and -* for configuration options. -* -* @author Glenn L. Nielsen -* @author Craig R. McClanahan -* @author Carson McDonald -* @author Ignacio Ortega -* @version $Revision: 394121 $ -*/ - -public class DataSourceRealm - extends RealmBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The generated string for the roles PreparedStatement - */ - private String preparedRoles = null; - - - /** - * The generated string for the credentials PreparedStatement - */ - private String preparedCredentials = null; - - - /** - * The name of the JNDI JDBC DataSource - */ - protected String dataSourceName = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String info = - "org.apache.catalina.realm.DataSourceRealm/1.0"; - - - /** - * Context local datasource. - */ - protected boolean localDataSource = false; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String name = "DataSourceRealm"; - - - /** - * The column in the user role table that names a role - */ - protected String roleNameCol = null; - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The column in the user table that holds the user's credintials - */ - protected String userCredCol = null; - - - /** - * The column in the user table that holds the user's name - */ - protected String userNameCol = null; - - - /** - * The table that holds the relation between user's and roles - */ - protected String userRoleTable = null; - - - /** - * The table that holds user data. - */ - protected String userTable = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the name of the JNDI JDBC DataSource. - * - */ - public String getDataSourceName() { - return dataSourceName; - } - - /** - * Set the name of the JNDI JDBC DataSource. - * - * @param dataSourceName the name of the JNDI JDBC DataSource - */ - public void setDataSourceName( String dataSourceName) { - this.dataSourceName = dataSourceName; - } - - /** - * Return if the datasource will be looked up in the webapp JNDI Context. - */ - public boolean getLocalDataSource() { - return localDataSource; - } - - /** - * Set to true to cause the datasource to be looked up in the webapp JNDI - * Context. - * - * @param localDataSource the new flag value - */ - public void setLocalDataSource(boolean localDataSource) { - this.localDataSource = localDataSource; - } - - /** - * Return the column in the user role table that names a role. - * - */ - public String getRoleNameCol() { - return roleNameCol; - } - - /** - * Set the column in the user role table that names a role. - * - * @param roleNameCol The column name - */ - public void setRoleNameCol( String roleNameCol ) { - this.roleNameCol = roleNameCol; - } - - /** - * Return the column in the user table that holds the user's credentials. - * - */ - public String getUserCredCol() { - return userCredCol; - } - - /** - * Set the column in the user table that holds the user's credentials. - * - * @param userCredCol The column name - */ - public void setUserCredCol( String userCredCol ) { - this.userCredCol = userCredCol; - } - - /** - * Return the column in the user table that holds the user's name. - * - */ - public String getUserNameCol() { - return userNameCol; - } - - /** - * Set the column in the user table that holds the user's name. - * - * @param userNameCol The column name - */ - public void setUserNameCol( String userNameCol ) { - this.userNameCol = userNameCol; - } - - /** - * Return the table that holds the relation between user's and roles. - * - */ - public String getUserRoleTable() { - return userRoleTable; - } - - /** - * Set the table that holds the relation between user's and roles. - * - * @param userRoleTable The table name - */ - public void setUserRoleTable( String userRoleTable ) { - this.userRoleTable = userRoleTable; - } - - /** - * Return the table that holds user data.. - * - */ - public String getUserTable() { - return userTable; - } - - /** - * Set the table that holds user data. - * - * @param userTable The table name - */ - public void setUserTable( String userTable ) { - this.userTable = userTable; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * If there are any errors with the JDBC connection, executing - * the query or anything we return null (don't authenticate). This - * event is also logged, and the connection will be closed so that - * a subsequent request will automatically re-open it. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials) { - - // No user - can't possibly authenticate, don't bother the database then - if (username == null) { - return null; - } - - Connection dbConnection = null; - - try { - - // Ensure that we have an open database connection - dbConnection = open(); - if (dbConnection == null) { - // If the db connection open fails, return "not authenticated" - return null; - } - - // Acquire a Principal object for this user - return authenticate(dbConnection, username, credentials); - - } catch (SQLException e) { - // Log the problem for posterity - containerLog.error(sm.getString("dataSourceRealm.exception"), e); - - // Return "not authenticated" for this request - return (null); - - } finally { - close(dbConnection); - } - - } - - - // -------------------------------------------------------- Package Methods - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param dbConnection The database connection to be used - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - protected Principal authenticate(Connection dbConnection, - String username, - String credentials) throws SQLException{ - - String dbCredentials = getPassword(dbConnection, username); - - // Validate the user's credentials - boolean validated = false; - if (hasMessageDigest()) { - // Hex hashes should be compared case-insensitive - validated = (digest(credentials).equalsIgnoreCase(dbCredentials)); - } else - validated = (digest(credentials).equals(dbCredentials)); - - if (validated) { - if (containerLog.isTraceEnabled()) - containerLog.trace( - sm.getString("dataSourceRealm.authenticateSuccess", - username)); - } else { - if (containerLog.isTraceEnabled()) - containerLog.trace( - sm.getString("dataSourceRealm.authenticateFailure", - username)); - return (null); - } - - ArrayList list = getRoles(dbConnection, username); - - // Create and return a suitable Principal for this user - return (new GenericPrincipal(this, username, credentials, list)); - - } - - - /** - * Close the specified database connection. - * - * @param dbConnection The connection to be closed - */ - protected void close(Connection dbConnection) { - - // Do nothing if the database connection is already closed - if (dbConnection == null) - return; - - // Commit if not auto committed - try { - if (!dbConnection.getAutoCommit()) { - dbConnection.commit(); - } - } catch (SQLException e) { - containerLog.error("Exception committing connection before closing:", e); - } - - // Close this database connection, and log any errors - try { - dbConnection.close(); - } catch (SQLException e) { - containerLog.error(sm.getString("dataSourceRealm.close"), e); // Just log it here - } - - } - - /** - * Open the specified database connection. - * - * @return Connection to the database - */ - protected Connection open() { - - try { - Context context = null; - if (localDataSource) { - context = ContextBindings.getClassLoader(); - context = (Context) context.lookup("comp/env"); - } else { - StandardServer server = - (StandardServer) ServerFactory.getServer(); - context = server.getGlobalNamingContext(); - } - DataSource dataSource = (DataSource)context.lookup(dataSourceName); - return dataSource.getConnection(); - } catch (Exception e) { - // Log the problem for posterity - containerLog.error(sm.getString("dataSourceRealm.exception"), e); - } - return null; - } - - /** - * Return a short name for this Realm implementation. - */ - protected String getName() { - - return (name); - - } - - /** - * Return the password associated with the given principal's user name. - */ - protected String getPassword(String username) { - - Connection dbConnection = null; - - // Ensure that we have an open database connection - dbConnection = open(); - if (dbConnection == null) { - return null; - } - - try { - return getPassword(dbConnection, username); - } finally { - close(dbConnection); - } - } - - /** - * Return the password associated with the given principal's user name. - * @param dbConnection The database connection to be used - * @param username Username for which password should be retrieved - */ - protected String getPassword(Connection dbConnection, - String username) { - - ResultSet rs = null; - PreparedStatement stmt = null; - String dbCredentials = null; - - try { - stmt = credentials(dbConnection, username); - rs = stmt.executeQuery(); - if (rs.next()) { - dbCredentials = rs.getString(1); - } - - return (dbCredentials != null) ? dbCredentials.trim() : null; - - } catch(SQLException e) { - containerLog.error( - sm.getString("dataSourceRealm.getPassword.exception", - username)); - } finally { - try { - if (rs != null) { - rs.close(); - } - if (stmt != null) { - stmt.close(); - } - } catch (SQLException e) { - containerLog.error( - sm.getString("dataSourceRealm.getPassword.exception", - username)); - - } - } - - return null; - } - - - /** - * Return the Principal associated with the given user name. - */ - protected Principal getPrincipal(String username) { - Connection dbConnection = open(); - if (dbConnection == null) { - return new GenericPrincipal(this,username, null, null); - } - try { - return (new GenericPrincipal(this, - username, - getPassword(dbConnection, username), - getRoles(dbConnection, username))); - } finally { - close(dbConnection); - } - - } - - /** - * Return the roles associated with the given user name. - * @param username Username for which roles should be retrieved - */ - protected ArrayList getRoles(String username) { - - Connection dbConnection = null; - - // Ensure that we have an open database connection - dbConnection = open(); - if (dbConnection == null) { - return null; - } - - try { - return getRoles(dbConnection, username); - } finally { - close(dbConnection); - } - } - - /** - * Return the roles associated with the given user name - * @param dbConnection The database connection to be used - * @param username Username for which roles should be retrieved - */ - protected ArrayList getRoles(Connection dbConnection, - String username) { - - ResultSet rs = null; - PreparedStatement stmt = null; - ArrayList list = null; - - try { - stmt = roles(dbConnection, username); - rs = stmt.executeQuery(); - list = new ArrayList(); - - while (rs.next()) { - String role = rs.getString(1); - if (role != null) { - list.add(role.trim()); - } - } - return list; - } catch(SQLException e) { - containerLog.error( - sm.getString("dataSourceRealm.getRoles.exception", username)); - } - finally { - try { - if (rs != null) { - rs.close(); - } - if (stmt != null) { - stmt.close(); - } - } catch (SQLException e) { - containerLog.error( - sm.getString("dataSourceRealm.getRoles.exception", - username)); - } - } - - return null; - } - - /** - * Return a PreparedStatement configured to perform the SELECT required - * to retrieve user credentials for the specified username. - * - * @param dbConnection The database connection to be used - * @param username Username for which credentials should be retrieved - * - * @exception SQLException if a database error occurs - */ - private PreparedStatement credentials(Connection dbConnection, - String username) - throws SQLException { - - PreparedStatement credentials = - dbConnection.prepareStatement(preparedCredentials); - - credentials.setString(1, username); - return (credentials); - - } - - /** - * Return a PreparedStatement configured to perform the SELECT required - * to retrieve user roles for the specified username. - * - * @param dbConnection The database connection to be used - * @param username Username for which roles should be retrieved - * - * @exception SQLException if a database error occurs - */ - private PreparedStatement roles(Connection dbConnection, String username) - throws SQLException { - - PreparedStatement roles = - dbConnection.prepareStatement(preparedRoles); - - roles.setString(1, username); - return (roles); - - } - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - // Create the roles PreparedStatement string - StringBuffer temp = new StringBuffer("SELECT "); - temp.append(roleNameCol); - temp.append(" FROM "); - temp.append(userRoleTable); - temp.append(" WHERE "); - temp.append(userNameCol); - temp.append(" = ?"); - preparedRoles = temp.toString(); - - // Create the credentials PreparedStatement string - temp = new StringBuffer("SELECT "); - temp.append(userCredCol); - temp.append(" FROM "); - temp.append(userTable); - temp.append(" WHERE "); - temp.append(userNameCol); - temp.append(" = ?"); - preparedCredentials = temp.toString(); - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - } - - -} +/* + * Copyright 1999,2004-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.security.Principal; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; + +import javax.naming.Context; +import javax.sql.DataSource; + +import org.apache.naming.ContextBindings; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.core.StandardServer; +import org.apache.catalina.util.StringManager; + +/** +* +* Implmentation of Realm that works with any JDBC JNDI DataSource. +* See the JDBCRealm.howto for more details on how to set up the database and +* for configuration options. +* +* @author Glenn L. Nielsen +* @author Craig R. McClanahan +* @author Carson McDonald +* @author Ignacio Ortega +* @version $Revision: 394121 $ +*/ + +public class DataSourceRealm + extends RealmBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The generated string for the roles PreparedStatement + */ + private String preparedRoles = null; + + + /** + * The generated string for the credentials PreparedStatement + */ + private String preparedCredentials = null; + + + /** + * The name of the JNDI JDBC DataSource + */ + protected String dataSourceName = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String info = + "org.apache.catalina.realm.DataSourceRealm/1.0"; + + + /** + * Context local datasource. + */ + protected boolean localDataSource = false; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String name = "DataSourceRealm"; + + + /** + * The column in the user role table that names a role + */ + protected String roleNameCol = null; + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The column in the user table that holds the user's credintials + */ + protected String userCredCol = null; + + + /** + * The column in the user table that holds the user's name + */ + protected String userNameCol = null; + + + /** + * The table that holds the relation between user's and roles + */ + protected String userRoleTable = null; + + + /** + * The table that holds user data. + */ + protected String userTable = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the name of the JNDI JDBC DataSource. + * + */ + public String getDataSourceName() { + return dataSourceName; + } + + /** + * Set the name of the JNDI JDBC DataSource. + * + * @param dataSourceName the name of the JNDI JDBC DataSource + */ + public void setDataSourceName( String dataSourceName) { + this.dataSourceName = dataSourceName; + } + + /** + * Return if the datasource will be looked up in the webapp JNDI Context. + */ + public boolean getLocalDataSource() { + return localDataSource; + } + + /** + * Set to true to cause the datasource to be looked up in the webapp JNDI + * Context. + * + * @param localDataSource the new flag value + */ + public void setLocalDataSource(boolean localDataSource) { + this.localDataSource = localDataSource; + } + + /** + * Return the column in the user role table that names a role. + * + */ + public String getRoleNameCol() { + return roleNameCol; + } + + /** + * Set the column in the user role table that names a role. + * + * @param roleNameCol The column name + */ + public void setRoleNameCol( String roleNameCol ) { + this.roleNameCol = roleNameCol; + } + + /** + * Return the column in the user table that holds the user's credentials. + * + */ + public String getUserCredCol() { + return userCredCol; + } + + /** + * Set the column in the user table that holds the user's credentials. + * + * @param userCredCol The column name + */ + public void setUserCredCol( String userCredCol ) { + this.userCredCol = userCredCol; + } + + /** + * Return the column in the user table that holds the user's name. + * + */ + public String getUserNameCol() { + return userNameCol; + } + + /** + * Set the column in the user table that holds the user's name. + * + * @param userNameCol The column name + */ + public void setUserNameCol( String userNameCol ) { + this.userNameCol = userNameCol; + } + + /** + * Return the table that holds the relation between user's and roles. + * + */ + public String getUserRoleTable() { + return userRoleTable; + } + + /** + * Set the table that holds the relation between user's and roles. + * + * @param userRoleTable The table name + */ + public void setUserRoleTable( String userRoleTable ) { + this.userRoleTable = userRoleTable; + } + + /** + * Return the table that holds user data.. + * + */ + public String getUserTable() { + return userTable; + } + + /** + * Set the table that holds user data. + * + * @param userTable The table name + */ + public void setUserTable( String userTable ) { + this.userTable = userTable; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * If there are any errors with the JDBC connection, executing + * the query or anything we return null (don't authenticate). This + * event is also logged, and the connection will be closed so that + * a subsequent request will automatically re-open it. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials) { + + // No user - can't possibly authenticate, don't bother the database then + if (username == null) { + return null; + } + + Connection dbConnection = null; + + try { + + // Ensure that we have an open database connection + dbConnection = open(); + if (dbConnection == null) { + // If the db connection open fails, return "not authenticated" + return null; + } + + // Acquire a Principal object for this user + return authenticate(dbConnection, username, credentials); + + } catch (SQLException e) { + // Log the problem for posterity + containerLog.error(sm.getString("dataSourceRealm.exception"), e); + + // Return "not authenticated" for this request + return (null); + + } finally { + close(dbConnection); + } + + } + + + // -------------------------------------------------------- Package Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param dbConnection The database connection to be used + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + protected Principal authenticate(Connection dbConnection, + String username, + String credentials) throws SQLException{ + + String dbCredentials = getPassword(dbConnection, username); + + // Validate the user's credentials + boolean validated = false; + if (hasMessageDigest()) { + // Hex hashes should be compared case-insensitive + validated = (digest(credentials).equalsIgnoreCase(dbCredentials)); + } else + validated = (digest(credentials).equals(dbCredentials)); + + if (validated) { + if (containerLog.isTraceEnabled()) + containerLog.trace( + sm.getString("dataSourceRealm.authenticateSuccess", + username)); + } else { + if (containerLog.isTraceEnabled()) + containerLog.trace( + sm.getString("dataSourceRealm.authenticateFailure", + username)); + return (null); + } + + ArrayList list = getRoles(dbConnection, username); + + // Create and return a suitable Principal for this user + return (new GenericPrincipal(this, username, credentials, list)); + + } + + + /** + * Close the specified database connection. + * + * @param dbConnection The connection to be closed + */ + protected void close(Connection dbConnection) { + + // Do nothing if the database connection is already closed + if (dbConnection == null) + return; + + // Commit if not auto committed + try { + if (!dbConnection.getAutoCommit()) { + dbConnection.commit(); + } + } catch (SQLException e) { + containerLog.error("Exception committing connection before closing:", e); + } + + // Close this database connection, and log any errors + try { + dbConnection.close(); + } catch (SQLException e) { + containerLog.error(sm.getString("dataSourceRealm.close"), e); // Just log it here + } + + } + + /** + * Open the specified database connection. + * + * @return Connection to the database + */ + protected Connection open() { + + try { + Context context = null; + if (localDataSource) { + context = ContextBindings.getClassLoader(); + context = (Context) context.lookup("comp/env"); + } else { + StandardServer server = + (StandardServer) ServerFactory.getServer(); + context = server.getGlobalNamingContext(); + } + DataSource dataSource = (DataSource)context.lookup(dataSourceName); + return dataSource.getConnection(); + } catch (Exception e) { + // Log the problem for posterity + containerLog.error(sm.getString("dataSourceRealm.exception"), e); + } + return null; + } + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + + return (name); + + } + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String username) { + + Connection dbConnection = null; + + // Ensure that we have an open database connection + dbConnection = open(); + if (dbConnection == null) { + return null; + } + + try { + return getPassword(dbConnection, username); + } finally { + close(dbConnection); + } + } + + /** + * Return the password associated with the given principal's user name. + * @param dbConnection The database connection to be used + * @param username Username for which password should be retrieved + */ + protected String getPassword(Connection dbConnection, + String username) { + + ResultSet rs = null; + PreparedStatement stmt = null; + String dbCredentials = null; + + try { + stmt = credentials(dbConnection, username); + rs = stmt.executeQuery(); + if (rs.next()) { + dbCredentials = rs.getString(1); + } + + return (dbCredentials != null) ? dbCredentials.trim() : null; + + } catch(SQLException e) { + containerLog.error( + sm.getString("dataSourceRealm.getPassword.exception", + username)); + } finally { + try { + if (rs != null) { + rs.close(); + } + if (stmt != null) { + stmt.close(); + } + } catch (SQLException e) { + containerLog.error( + sm.getString("dataSourceRealm.getPassword.exception", + username)); + + } + } + + return null; + } + + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String username) { + Connection dbConnection = open(); + if (dbConnection == null) { + return new GenericPrincipal(this,username, null, null); + } + try { + return (new GenericPrincipal(this, + username, + getPassword(dbConnection, username), + getRoles(dbConnection, username))); + } finally { + close(dbConnection); + } + + } + + /** + * Return the roles associated with the given user name. + * @param username Username for which roles should be retrieved + */ + protected ArrayList getRoles(String username) { + + Connection dbConnection = null; + + // Ensure that we have an open database connection + dbConnection = open(); + if (dbConnection == null) { + return null; + } + + try { + return getRoles(dbConnection, username); + } finally { + close(dbConnection); + } + } + + /** + * Return the roles associated with the given user name + * @param dbConnection The database connection to be used + * @param username Username for which roles should be retrieved + */ + protected ArrayList getRoles(Connection dbConnection, + String username) { + + ResultSet rs = null; + PreparedStatement stmt = null; + ArrayList list = null; + + try { + stmt = roles(dbConnection, username); + rs = stmt.executeQuery(); + list = new ArrayList(); + + while (rs.next()) { + String role = rs.getString(1); + if (role != null) { + list.add(role.trim()); + } + } + return list; + } catch(SQLException e) { + containerLog.error( + sm.getString("dataSourceRealm.getRoles.exception", username)); + } + finally { + try { + if (rs != null) { + rs.close(); + } + if (stmt != null) { + stmt.close(); + } + } catch (SQLException e) { + containerLog.error( + sm.getString("dataSourceRealm.getRoles.exception", + username)); + } + } + + return null; + } + + /** + * Return a PreparedStatement configured to perform the SELECT required + * to retrieve user credentials for the specified username. + * + * @param dbConnection The database connection to be used + * @param username Username for which credentials should be retrieved + * + * @exception SQLException if a database error occurs + */ + private PreparedStatement credentials(Connection dbConnection, + String username) + throws SQLException { + + PreparedStatement credentials = + dbConnection.prepareStatement(preparedCredentials); + + credentials.setString(1, username); + return (credentials); + + } + + /** + * Return a PreparedStatement configured to perform the SELECT required + * to retrieve user roles for the specified username. + * + * @param dbConnection The database connection to be used + * @param username Username for which roles should be retrieved + * + * @exception SQLException if a database error occurs + */ + private PreparedStatement roles(Connection dbConnection, String username) + throws SQLException { + + PreparedStatement roles = + dbConnection.prepareStatement(preparedRoles); + + roles.setString(1, username); + return (roles); + + } + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + // Create the roles PreparedStatement string + StringBuffer temp = new StringBuffer("SELECT "); + temp.append(roleNameCol); + temp.append(" FROM "); + temp.append(userRoleTable); + temp.append(" WHERE "); + temp.append(userNameCol); + temp.append(" = ?"); + preparedRoles = temp.toString(); + + // Create the credentials PreparedStatement string + temp = new StringBuffer("SELECT "); + temp.append(userCredCol); + temp.append(" FROM "); + temp.append(userTable); + temp.append(" WHERE "); + temp.append(userNameCol); + temp.append(" = ?"); + preparedCredentials = temp.toString(); + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + } + + +} diff --git a/java/org/apache/catalina/realm/GenericPrincipal.java b/java/org/apache/catalina/realm/GenericPrincipal.java index 95f680456..fff728d86 100644 --- a/java/org/apache/catalina/realm/GenericPrincipal.java +++ b/java/org/apache/catalina/realm/GenericPrincipal.java @@ -1,199 +1,199 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.util.Arrays; -import java.util.List; -import org.apache.catalina.Realm; - - -/** - * Generic implementation of java.security.Principal that - * is available for use by Realm implementations. - * - * @author Craig R. McClanahan - * @version $Revision: 303827 $ $Date: 2005-04-01 13:36:52 +0200 (ven., 01 avr. 2005) $ - */ - -public class GenericPrincipal implements Principal { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new Principal, associated with the specified Realm, for the - * specified username and password. - * - * @param realm The Realm that owns this Principal - * @param name The username of the user represented by this Principal - * @param password Credentials used to authenticate this user - */ - public GenericPrincipal(Realm realm, String name, String password) { - - this(realm, name, password, null); - - } - - - /** - * Construct a new Principal, associated with the specified Realm, for the - * specified username and password, with the specified role names - * (as Strings). - * - * @param realm The Realm that owns this principal - * @param name The username of the user represented by this Principal - * @param password Credentials used to authenticate this user - * @param roles List of roles (must be Strings) possessed by this user - */ - public GenericPrincipal(Realm realm, String name, String password, - List roles) { - this(realm, name, password, roles, null); - } - - /** - * Construct a new Principal, associated with the specified Realm, for the - * specified username and password, with the specified role names - * (as Strings). - * - * @param realm The Realm that owns this principal - * @param name The username of the user represented by this Principal - * @param password Credentials used to authenticate this user - * @param roles List of roles (must be Strings) possessed by this user - * @param userPrincipal - the principal to be returned from the request - * getUserPrincipal call if not null; if null, this will be returned - */ - public GenericPrincipal(Realm realm, String name, String password, - List roles, Principal userPrincipal) { - - super(); - this.realm = realm; - this.name = name; - this.password = password; - this.userPrincipal = userPrincipal; - if (roles != null) { - this.roles = new String[roles.size()]; - this.roles = (String[]) roles.toArray(this.roles); - if (this.roles.length > 0) - Arrays.sort(this.roles); - } - } - - - // ------------------------------------------------------------- Properties - - - /** - * The username of the user represented by this Principal. - */ - protected String name = null; - - public String getName() { - return (this.name); - } - - - /** - * The authentication credentials for the user represented by - * this Principal. - */ - protected String password = null; - - public String getPassword() { - return (this.password); - } - - - /** - * The Realm with which this Principal is associated. - */ - protected Realm realm = null; - - public Realm getRealm() { - return (this.realm); - } - - void setRealm( Realm realm ) { - this.realm=realm; - } - - - /** - * The set of roles associated with this user. - */ - protected String roles[] = new String[0]; - - public String[] getRoles() { - return (this.roles); - } - - - /** - * The authenticated Principal to be exposed to applications. - */ - protected Principal userPrincipal = null; - - public Principal getUserPrincipal() { - if (userPrincipal != null) { - return userPrincipal; - } else { - return this; - } - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Does the user represented by this Principal possess the specified role? - * - * @param role Role to be tested - */ - public boolean hasRole(String role) { - - if("*".equals(role)) // Special 2.4 role meaning everyone - return true; - if (role == null) - return (false); - return (Arrays.binarySearch(roles, role) >= 0); - - } - - - /** - * Return a String representation of this object, which exposes only - * information that should be public. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("GenericPrincipal["); - sb.append(this.name); - sb.append("("); - for( int i=0;ijava.security.Principal that + * is available for use by Realm implementations. + * + * @author Craig R. McClanahan + * @version $Revision: 303827 $ $Date: 2005-04-01 13:36:52 +0200 (ven., 01 avr. 2005) $ + */ + +public class GenericPrincipal implements Principal { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new Principal, associated with the specified Realm, for the + * specified username and password. + * + * @param realm The Realm that owns this Principal + * @param name The username of the user represented by this Principal + * @param password Credentials used to authenticate this user + */ + public GenericPrincipal(Realm realm, String name, String password) { + + this(realm, name, password, null); + + } + + + /** + * Construct a new Principal, associated with the specified Realm, for the + * specified username and password, with the specified role names + * (as Strings). + * + * @param realm The Realm that owns this principal + * @param name The username of the user represented by this Principal + * @param password Credentials used to authenticate this user + * @param roles List of roles (must be Strings) possessed by this user + */ + public GenericPrincipal(Realm realm, String name, String password, + List roles) { + this(realm, name, password, roles, null); + } + + /** + * Construct a new Principal, associated with the specified Realm, for the + * specified username and password, with the specified role names + * (as Strings). + * + * @param realm The Realm that owns this principal + * @param name The username of the user represented by this Principal + * @param password Credentials used to authenticate this user + * @param roles List of roles (must be Strings) possessed by this user + * @param userPrincipal - the principal to be returned from the request + * getUserPrincipal call if not null; if null, this will be returned + */ + public GenericPrincipal(Realm realm, String name, String password, + List roles, Principal userPrincipal) { + + super(); + this.realm = realm; + this.name = name; + this.password = password; + this.userPrincipal = userPrincipal; + if (roles != null) { + this.roles = new String[roles.size()]; + this.roles = (String[]) roles.toArray(this.roles); + if (this.roles.length > 0) + Arrays.sort(this.roles); + } + } + + + // ------------------------------------------------------------- Properties + + + /** + * The username of the user represented by this Principal. + */ + protected String name = null; + + public String getName() { + return (this.name); + } + + + /** + * The authentication credentials for the user represented by + * this Principal. + */ + protected String password = null; + + public String getPassword() { + return (this.password); + } + + + /** + * The Realm with which this Principal is associated. + */ + protected Realm realm = null; + + public Realm getRealm() { + return (this.realm); + } + + void setRealm( Realm realm ) { + this.realm=realm; + } + + + /** + * The set of roles associated with this user. + */ + protected String roles[] = new String[0]; + + public String[] getRoles() { + return (this.roles); + } + + + /** + * The authenticated Principal to be exposed to applications. + */ + protected Principal userPrincipal = null; + + public Principal getUserPrincipal() { + if (userPrincipal != null) { + return userPrincipal; + } else { + return this; + } + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Does the user represented by this Principal possess the specified role? + * + * @param role Role to be tested + */ + public boolean hasRole(String role) { + + if("*".equals(role)) // Special 2.4 role meaning everyone + return true; + if (role == null) + return (false); + return (Arrays.binarySearch(roles, role) >= 0); + + } + + + /** + * Return a String representation of this object, which exposes only + * information that should be public. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("GenericPrincipal["); + sb.append(this.name); + sb.append("("); + for( int i=0;iImplementation of the JAAS CallbackHandler interface, - * used to negotiate delivery of the username and credentials that were - * specified to our constructor. No interaction with the user is required - * (or possible).

    - * - *

    This CallbackHandler will pre-digest the supplied - * password, if required by the <Realm> element in - * server.xml.

    - *

    At present, JAASCallbackHandler knows how to handle callbacks of - * type javax.security.auth.callback.NameCallback and - * javax.security.auth.callback.PasswordCallback.

    - * - * @author Craig R. McClanahan - * @author Andrew R. Jaquith - * @version $Revision: 303719 $ $Date: 2005-02-19 00:43:20 +0100 (sam., 19 févr. 2005) $ - */ - -public class JAASCallbackHandler implements CallbackHandler { - private static Log log = LogFactory.getLog(JAASCallbackHandler.class); - - // ------------------------------------------------------------ Constructor - - - /** - * Construct a callback handler configured with the specified values. - * Note that if the JAASRealm instance specifies digested passwords, - * the password parameter will be pre-digested here. - * - * @param realm Our associated JAASRealm instance - * @param username Username to be authenticated with - * @param password Password to be authenticated with - */ - public JAASCallbackHandler(JAASRealm realm, String username, - String password) { - - super(); - this.realm = realm; - this.username = username; - - if (realm.hasMessageDigest()) { - this.password = realm.digest(password); - } - else { - this.password = password; - } - } - - - // ----------------------------------------------------- Instance Variables - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - /** - * The password to be authenticated with. - */ - protected String password = null; - - - /** - * The associated JAASRealm instance. - */ - protected JAASRealm realm = null; - - - /** - * The username to be authenticated with. - */ - protected String username = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieve the information requested in the provided Callbacks. - * This implementation only recognizes NameCallback and - * PasswordCallback instances. - * - * @param callbacks The set of Callbacks to be processed - * - * @exception IOException if an input/output error occurs - * @exception UnsupportedCallbackException if the login method requests - * an unsupported callback type - */ - public void handle(Callback callbacks[]) - throws IOException, UnsupportedCallbackException { - - for (int i = 0; i < callbacks.length; i++) { - - if (callbacks[i] instanceof NameCallback) { - if (realm.getContainer().getLogger().isTraceEnabled()) - realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", username)); - ((NameCallback) callbacks[i]).setName(username); - } else if (callbacks[i] instanceof PasswordCallback) { - final char[] passwordcontents; - if (password != null) { - passwordcontents = password.toCharArray(); - } else { - passwordcontents = new char[0]; - } - ((PasswordCallback) callbacks[i]).setPassword - (passwordcontents); - } else { - throw new UnsupportedCallbackException(callbacks[i]); - } - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.io.IOException; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; + +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + *

    Implementation of the JAAS CallbackHandler interface, + * used to negotiate delivery of the username and credentials that were + * specified to our constructor. No interaction with the user is required + * (or possible).

    + * + *

    This CallbackHandler will pre-digest the supplied + * password, if required by the <Realm> element in + * server.xml.

    + *

    At present, JAASCallbackHandler knows how to handle callbacks of + * type javax.security.auth.callback.NameCallback and + * javax.security.auth.callback.PasswordCallback.

    + * + * @author Craig R. McClanahan + * @author Andrew R. Jaquith + * @version $Revision: 303719 $ $Date: 2005-02-19 00:43:20 +0100 (sam., 19 févr. 2005) $ + */ + +public class JAASCallbackHandler implements CallbackHandler { + private static Log log = LogFactory.getLog(JAASCallbackHandler.class); + + // ------------------------------------------------------------ Constructor + + + /** + * Construct a callback handler configured with the specified values. + * Note that if the JAASRealm instance specifies digested passwords, + * the password parameter will be pre-digested here. + * + * @param realm Our associated JAASRealm instance + * @param username Username to be authenticated with + * @param password Password to be authenticated with + */ + public JAASCallbackHandler(JAASRealm realm, String username, + String password) { + + super(); + this.realm = realm; + this.username = username; + + if (realm.hasMessageDigest()) { + this.password = realm.digest(password); + } + else { + this.password = password; + } + } + + + // ----------------------------------------------------- Instance Variables + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + /** + * The password to be authenticated with. + */ + protected String password = null; + + + /** + * The associated JAASRealm instance. + */ + protected JAASRealm realm = null; + + + /** + * The username to be authenticated with. + */ + protected String username = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieve the information requested in the provided Callbacks. + * This implementation only recognizes NameCallback and + * PasswordCallback instances. + * + * @param callbacks The set of Callbacks to be processed + * + * @exception IOException if an input/output error occurs + * @exception UnsupportedCallbackException if the login method requests + * an unsupported callback type + */ + public void handle(Callback callbacks[]) + throws IOException, UnsupportedCallbackException { + + for (int i = 0; i < callbacks.length; i++) { + + if (callbacks[i] instanceof NameCallback) { + if (realm.getContainer().getLogger().isTraceEnabled()) + realm.getContainer().getLogger().trace(sm.getString("jaasCallback.username", username)); + ((NameCallback) callbacks[i]).setName(username); + } else if (callbacks[i] instanceof PasswordCallback) { + final char[] passwordcontents; + if (password != null) { + passwordcontents = password.toCharArray(); + } else { + passwordcontents = new char[0]; + } + ((PasswordCallback) callbacks[i]).setPassword + (passwordcontents); + } else { + throw new UnsupportedCallbackException(callbacks[i]); + } + } + } +} diff --git a/java/org/apache/catalina/realm/JAASMemoryLoginModule.java b/java/org/apache/catalina/realm/JAASMemoryLoginModule.java index f9f38dc37..2794fb2f6 100644 --- a/java/org/apache/catalina/realm/JAASMemoryLoginModule.java +++ b/java/org/apache/catalina/realm/JAASMemoryLoginModule.java @@ -1,386 +1,386 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.io.File; -import java.io.IOException; -import java.security.Principal; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.NameCallback; -import javax.security.auth.callback.PasswordCallback; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.FailedLoginException; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -import org.apache.catalina.Context; -import org.apache.catalina.Realm; -import org.apache.catalina.connector.Request; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.digester.Digester; - - -/** - *

    Implementation of the JAAS LoginModule interface, - * primarily for use in testing JAASRealm. It utilizes an - * XML-format data file of username/password/role information identical to - * that supported by org.apache.catalina.realm.MemoryRealm - * (except that digested passwords are not supported).

    - * - *

    This class recognizes the following string-valued options, which are - * specified in the configuration file (and passed to our constructor in - * the options argument:

    - *
      - *
    • debug - Set to "true" to get debugging messages - * generated to System.out. The default value is false.
    • - *
    • pathname - Relative (to the pathname specified by the - * "catalina.base" system property) or absolute pahtname to the - * XML file containing our user information, in the format supported by - * {@link MemoryRealm}. The default value matches the MemoryRealm - * default.
    • - *
    - * - *

    IMPLEMENTATION NOTE - This class implements - * Realm only to satisfy the calling requirements of the - * GenericPrincipal constructor. It does not actually perform - * the functionality required of a Realm implementation.

    - * - * @author Craig R. McClanahan - * @version $Revision: 303719 $ $Date: 2005-02-19 00:43:20 +0100 (sam., 19 févr. 2005) $ - */ - -public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule, Realm { - // We need to extend MemoryRealm to avoid class cast - - private static Log log = LogFactory.getLog(JAASMemoryLoginModule.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The callback handler responsible for answering our requests. - */ - protected CallbackHandler callbackHandler = null; - - - /** - * Has our own commit() returned successfully? - */ - protected boolean committed = false; - - - /** - * The configuration information for this LoginModule. - */ - protected Map options = null; - - - /** - * The absolute or relative pathname to the XML configuration file. - */ - protected String pathname = "conf/tomcat-users.xml"; - - - /** - * The Principal identified by our validation, or - * null if validation falied. - */ - protected Principal principal = null; - - - /** - * The set of Principals loaded from our configuration file. - */ - protected HashMap principals = new HashMap(); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - /** - * The state information that is shared with other configured - * LoginModule instances. - */ - protected Map sharedState = null; - - - /** - * The subject for which we are performing authentication. - */ - protected Subject subject = null; - - - // --------------------------------------------------------- Public Methods - - public JAASMemoryLoginModule() { - log.debug("MEMORY LOGIN MODULE"); - } - - /** - * Phase 2 of authenticating a Subject when Phase 1 - * fails. This method is called if the LoginContext - * failed somewhere in the overall authentication chain. - * - * @return true if this method succeeded, or - * false if this LoginModule should be - * ignored - * - * @exception LoginException if the abort fails - */ - public boolean abort() throws LoginException { - - // If our authentication was not successful, just return false - if (principal == null) - return (false); - - // Clean up if overall authentication failed - if (committed) - logout(); - else { - committed = false; - principal = null; - } - log.debug("Abort"); - return (true); - - } - - - /** - * Phase 2 of authenticating a Subject when Phase 1 - * was successful. This method is called if the LoginContext - * succeeded in the overall authentication chain. - * - * @return true if the authentication succeeded, or - * false if this LoginModule should be - * ignored - * - * @exception LoginException if the commit fails - */ - public boolean commit() throws LoginException { - log.debug("commit " + principal); - - // If authentication was not successful, just return false - if (principal == null) - return (false); - - // Add our Principal to the Subject if needed - if (!subject.getPrincipals().contains(principal)) - subject.getPrincipals().add(principal); - - committed = true; - return (true); - - } - - - /** - * Return the SecurityConstraints configured to guard the request URI for - * this request, or null if there is no such constraint. - * - * @param request Request we are processing - * @param context Context the Request is mapped to - */ - public SecurityConstraint [] findSecurityConstraints(Request request, - Context context) { - ArrayList results = null; - // Are there any defined security constraints? - SecurityConstraint constraints[] = context.findConstraints(); - if ((constraints == null) || (constraints.length == 0)) { - if (context.getLogger().isDebugEnabled()) - context.getLogger().debug(" No applicable constraints defined"); - return (null); - } - - // Check each defined security constraint - String uri = request.getDecodedRequestURI(); - String contextPath = request.getContextPath(); - if (contextPath.length() > 0) - uri = uri.substring(contextPath.length()); - uri = RequestUtil.URLDecode(uri); // Before checking constraints - String method = request.getMethod(); - for (int i = 0; i < constraints.length; i++) { - if (context.getLogger().isDebugEnabled()) - context.getLogger().debug(" Checking constraint '" + constraints[i] + - "' against " + method + " " + uri + " --> " + - constraints[i].included(uri, method)); - if (constraints[i].included(uri, method)) { - if(results == null) { - results = new ArrayList(); - } - results.add(constraints[i]); - } - } - - // No applicable security constraint was found - if (context.getLogger().isDebugEnabled()) - context.getLogger().debug(" No applicable constraint located"); - if(results == null) - return null; - SecurityConstraint [] array = new SecurityConstraint[results.size()]; - System.arraycopy(results.toArray(), 0, array, 0, array.length); - return array; - } - - - /** - * Initialize this LoginModule with the specified - * configuration information. - * - * @param subject The Subject to be authenticated - * @param callbackHandler A CallbackHandler for communicating - * with the end user as necessary - * @param sharedState State information shared with other - * LoginModule instances - * @param options Configuration information for this specific - * LoginModule instance - */ - public void initialize(Subject subject, CallbackHandler callbackHandler, - Map sharedState, Map options) { - log.debug("Init"); - - // Save configuration values - this.subject = subject; - this.callbackHandler = callbackHandler; - this.sharedState = sharedState; - this.options = options; - - // Perform instance-specific initialization - if (options.get("pathname") != null) - this.pathname = (String) options.get("pathname"); - - // Load our defined Principals - load(); - - } - - - /** - * Phase 1 of authenticating a Subject. - * - * @return true if the authentication succeeded, or - * false if this LoginModule should be - * ignored - * - * @exception LoginException if the authentication fails - */ - public boolean login() throws LoginException { - - // Set up our CallbackHandler requests - if (callbackHandler == null) - throw new LoginException("No CallbackHandler specified"); - Callback callbacks[] = new Callback[2]; - callbacks[0] = new NameCallback("Username: "); - callbacks[1] = new PasswordCallback("Password: ", false); - - // Interact with the user to retrieve the username and password - String username = null; - String password = null; - try { - callbackHandler.handle(callbacks); - username = ((NameCallback) callbacks[0]).getName(); - password = - new String(((PasswordCallback) callbacks[1]).getPassword()); - } catch (IOException e) { - throw new LoginException(e.toString()); - } catch (UnsupportedCallbackException e) { - throw new LoginException(e.toString()); - } - - // Validate the username and password we have received - principal = super.authenticate(username, password); - - log.debug("login " + username + " " + principal); - - // Report results based on success or failure - if (principal != null) { - return (true); - } else { - throw new - FailedLoginException("Username or password is incorrect"); - } - - } - - - /** - * Log out this user. - * - * @return true in all cases because thie - * LoginModule should not be ignored - * - * @exception LoginException if logging out failed - */ - public boolean logout() throws LoginException { - - subject.getPrincipals().remove(principal); - committed = false; - principal = null; - return (true); - - } - - - // ---------------------------------------------------------- Realm Methods - // ------------------------------------------------------ Protected Methods - - - /** - * Load the contents of our configuration file. - */ - protected void load() { - - // Validate the existence of our configuration file - File file = new File(pathname); - if (!file.isAbsolute()) - file = new File(System.getProperty("catalina.base"), pathname); - if (!file.exists() || !file.canRead()) { - log.warn("Cannot load configuration file " + file.getAbsolutePath()); - return; - } - - // Load the contents of our configuration file - Digester digester = new Digester(); - digester.setValidating(false); - digester.addRuleSet(new MemoryRuleSet()); - try { - digester.push(this); - digester.parse(file); - } catch (Exception e) { - log.warn("Error processing configuration file " + - file.getAbsolutePath(), e); - return; - } finally { - digester.reset(); - } - - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.io.File; +import java.io.IOException; +import java.security.Principal; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import javax.security.auth.Subject; +import javax.security.auth.callback.Callback; +import javax.security.auth.callback.CallbackHandler; +import javax.security.auth.callback.NameCallback; +import javax.security.auth.callback.PasswordCallback; +import javax.security.auth.callback.UnsupportedCallbackException; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginException; +import javax.security.auth.spi.LoginModule; + +import org.apache.catalina.Context; +import org.apache.catalina.Realm; +import org.apache.catalina.connector.Request; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.digester.Digester; + + +/** + *

    Implementation of the JAAS LoginModule interface, + * primarily for use in testing JAASRealm. It utilizes an + * XML-format data file of username/password/role information identical to + * that supported by org.apache.catalina.realm.MemoryRealm + * (except that digested passwords are not supported).

    + * + *

    This class recognizes the following string-valued options, which are + * specified in the configuration file (and passed to our constructor in + * the options argument:

    + *
      + *
    • debug - Set to "true" to get debugging messages + * generated to System.out. The default value is false.
    • + *
    • pathname - Relative (to the pathname specified by the + * "catalina.base" system property) or absolute pahtname to the + * XML file containing our user information, in the format supported by + * {@link MemoryRealm}. The default value matches the MemoryRealm + * default.
    • + *
    + * + *

    IMPLEMENTATION NOTE - This class implements + * Realm only to satisfy the calling requirements of the + * GenericPrincipal constructor. It does not actually perform + * the functionality required of a Realm implementation.

    + * + * @author Craig R. McClanahan + * @version $Revision: 303719 $ $Date: 2005-02-19 00:43:20 +0100 (sam., 19 févr. 2005) $ + */ + +public class JAASMemoryLoginModule extends MemoryRealm implements LoginModule, Realm { + // We need to extend MemoryRealm to avoid class cast + + private static Log log = LogFactory.getLog(JAASMemoryLoginModule.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The callback handler responsible for answering our requests. + */ + protected CallbackHandler callbackHandler = null; + + + /** + * Has our own commit() returned successfully? + */ + protected boolean committed = false; + + + /** + * The configuration information for this LoginModule. + */ + protected Map options = null; + + + /** + * The absolute or relative pathname to the XML configuration file. + */ + protected String pathname = "conf/tomcat-users.xml"; + + + /** + * The Principal identified by our validation, or + * null if validation falied. + */ + protected Principal principal = null; + + + /** + * The set of Principals loaded from our configuration file. + */ + protected HashMap principals = new HashMap(); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + /** + * The state information that is shared with other configured + * LoginModule instances. + */ + protected Map sharedState = null; + + + /** + * The subject for which we are performing authentication. + */ + protected Subject subject = null; + + + // --------------------------------------------------------- Public Methods + + public JAASMemoryLoginModule() { + log.debug("MEMORY LOGIN MODULE"); + } + + /** + * Phase 2 of authenticating a Subject when Phase 1 + * fails. This method is called if the LoginContext + * failed somewhere in the overall authentication chain. + * + * @return true if this method succeeded, or + * false if this LoginModule should be + * ignored + * + * @exception LoginException if the abort fails + */ + public boolean abort() throws LoginException { + + // If our authentication was not successful, just return false + if (principal == null) + return (false); + + // Clean up if overall authentication failed + if (committed) + logout(); + else { + committed = false; + principal = null; + } + log.debug("Abort"); + return (true); + + } + + + /** + * Phase 2 of authenticating a Subject when Phase 1 + * was successful. This method is called if the LoginContext + * succeeded in the overall authentication chain. + * + * @return true if the authentication succeeded, or + * false if this LoginModule should be + * ignored + * + * @exception LoginException if the commit fails + */ + public boolean commit() throws LoginException { + log.debug("commit " + principal); + + // If authentication was not successful, just return false + if (principal == null) + return (false); + + // Add our Principal to the Subject if needed + if (!subject.getPrincipals().contains(principal)) + subject.getPrincipals().add(principal); + + committed = true; + return (true); + + } + + + /** + * Return the SecurityConstraints configured to guard the request URI for + * this request, or null if there is no such constraint. + * + * @param request Request we are processing + * @param context Context the Request is mapped to + */ + public SecurityConstraint [] findSecurityConstraints(Request request, + Context context) { + ArrayList results = null; + // Are there any defined security constraints? + SecurityConstraint constraints[] = context.findConstraints(); + if ((constraints == null) || (constraints.length == 0)) { + if (context.getLogger().isDebugEnabled()) + context.getLogger().debug(" No applicable constraints defined"); + return (null); + } + + // Check each defined security constraint + String uri = request.getDecodedRequestURI(); + String contextPath = request.getContextPath(); + if (contextPath.length() > 0) + uri = uri.substring(contextPath.length()); + uri = RequestUtil.URLDecode(uri); // Before checking constraints + String method = request.getMethod(); + for (int i = 0; i < constraints.length; i++) { + if (context.getLogger().isDebugEnabled()) + context.getLogger().debug(" Checking constraint '" + constraints[i] + + "' against " + method + " " + uri + " --> " + + constraints[i].included(uri, method)); + if (constraints[i].included(uri, method)) { + if(results == null) { + results = new ArrayList(); + } + results.add(constraints[i]); + } + } + + // No applicable security constraint was found + if (context.getLogger().isDebugEnabled()) + context.getLogger().debug(" No applicable constraint located"); + if(results == null) + return null; + SecurityConstraint [] array = new SecurityConstraint[results.size()]; + System.arraycopy(results.toArray(), 0, array, 0, array.length); + return array; + } + + + /** + * Initialize this LoginModule with the specified + * configuration information. + * + * @param subject The Subject to be authenticated + * @param callbackHandler A CallbackHandler for communicating + * with the end user as necessary + * @param sharedState State information shared with other + * LoginModule instances + * @param options Configuration information for this specific + * LoginModule instance + */ + public void initialize(Subject subject, CallbackHandler callbackHandler, + Map sharedState, Map options) { + log.debug("Init"); + + // Save configuration values + this.subject = subject; + this.callbackHandler = callbackHandler; + this.sharedState = sharedState; + this.options = options; + + // Perform instance-specific initialization + if (options.get("pathname") != null) + this.pathname = (String) options.get("pathname"); + + // Load our defined Principals + load(); + + } + + + /** + * Phase 1 of authenticating a Subject. + * + * @return true if the authentication succeeded, or + * false if this LoginModule should be + * ignored + * + * @exception LoginException if the authentication fails + */ + public boolean login() throws LoginException { + + // Set up our CallbackHandler requests + if (callbackHandler == null) + throw new LoginException("No CallbackHandler specified"); + Callback callbacks[] = new Callback[2]; + callbacks[0] = new NameCallback("Username: "); + callbacks[1] = new PasswordCallback("Password: ", false); + + // Interact with the user to retrieve the username and password + String username = null; + String password = null; + try { + callbackHandler.handle(callbacks); + username = ((NameCallback) callbacks[0]).getName(); + password = + new String(((PasswordCallback) callbacks[1]).getPassword()); + } catch (IOException e) { + throw new LoginException(e.toString()); + } catch (UnsupportedCallbackException e) { + throw new LoginException(e.toString()); + } + + // Validate the username and password we have received + principal = super.authenticate(username, password); + + log.debug("login " + username + " " + principal); + + // Report results based on success or failure + if (principal != null) { + return (true); + } else { + throw new + FailedLoginException("Username or password is incorrect"); + } + + } + + + /** + * Log out this user. + * + * @return true in all cases because thie + * LoginModule should not be ignored + * + * @exception LoginException if logging out failed + */ + public boolean logout() throws LoginException { + + subject.getPrincipals().remove(principal); + committed = false; + principal = null; + return (true); + + } + + + // ---------------------------------------------------------- Realm Methods + // ------------------------------------------------------ Protected Methods + + + /** + * Load the contents of our configuration file. + */ + protected void load() { + + // Validate the existence of our configuration file + File file = new File(pathname); + if (!file.isAbsolute()) + file = new File(System.getProperty("catalina.base"), pathname); + if (!file.exists() || !file.canRead()) { + log.warn("Cannot load configuration file " + file.getAbsolutePath()); + return; + } + + // Load the contents of our configuration file + Digester digester = new Digester(); + digester.setValidating(false); + digester.addRuleSet(new MemoryRuleSet()); + try { + digester.push(this); + digester.parse(file); + } catch (Exception e) { + log.warn("Error processing configuration file " + + file.getAbsolutePath(), e); + return; + } finally { + digester.reset(); + } + + } +} diff --git a/java/org/apache/catalina/realm/JAASRealm.java b/java/org/apache/catalina/realm/JAASRealm.java index 77573c6a1..5b57a903a 100644 --- a/java/org/apache/catalina/realm/JAASRealm.java +++ b/java/org/apache/catalina/realm/JAASRealm.java @@ -1,571 +1,571 @@ -/* - * Copyright 2001-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.security.auth.Subject; -import javax.security.auth.login.AccountExpiredException; -import javax.security.auth.login.CredentialExpiredException; -import javax.security.auth.login.FailedLoginException; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -import org.apache.catalina.Container; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - *

    Implmentation of Realm that authenticates users via the Java - * Authentication and Authorization Service (JAAS). JAAS support requires - * either JDK 1.4 (which includes it as part of the standard platform) or - * JDK 1.3 (with the plug-in jaas.jar file).

    - * - *

    The value configured for the appName property is passed to - * the javax.security.auth.login.LoginContext constructor, to - * specify the application name used to select the set of relevant - * LoginModules required.

    - * - *

    The JAAS Specification describes the result of a successful login as a - * javax.security.auth.Subject instance, which can contain zero - * or more java.security.Principal objects in the return value - * of the Subject.getPrincipals() method. However, it provides - * no guidance on how to distinguish Principals that describe the individual - * user (and are thus appropriate to return as the value of - * request.getUserPrincipal() in a web application) from the Principal(s) - * that describe the authorized roles for this user. To maintain as much - * independence as possible from the underlying LoginMethod - * implementation executed by JAAS, the following policy is implemented by - * this Realm:

    - *
      - *
    • The JAAS LoginModule is assumed to return a - * Subject with at least one Principal instance - * representing the user himself or herself, and zero or more separate - * Principals representing the security roles authorized - * for this user.
    • - *
    • On the Principal representing the user, the Principal - * name is an appropriate value to return via the Servlet API method - * HttpServletRequest.getRemoteUser().
    • - *
    • On the Principals representing the security roles, the - * name is the name of the authorized security role.
    • - *
    • This Realm will be configured with two lists of fully qualified Java - * class names of classes that implement - * java.security.Principal - one that identifies class(es) - * representing a user, and one that identifies class(es) representing - * a security role.
    • - *
    • As this Realm iterates over the Principals returned by - * Subject.getPrincipals(), it will identify the first - * Principal that matches the "user classes" list as the - * Principal for this user.
    • - *
    • As this Realm iterates over the Princpals returned by - * Subject.getPrincipals(), it will accumulate the set of - * all Principals matching the "role classes" list as - * identifying the security roles for this user.
    • - *
    • It is a configuration error for the JAAS login method to return a - * validated Subject without a Principal that - * matches the "user classes" list.
    • - *
    • By default, the enclosing Container's name serves as the - * application name used to obtain the JAAS LoginContext ("Catalina" in - * a default installation). Tomcat must be able to find an application - * with this name in the JAAS configuration file. Here is a hypothetical - * JAAS configuration file entry for a database-oriented login module that uses - * a Tomcat-managed JNDI database resource: - *
      Catalina {
      -org.foobar.auth.DatabaseLoginModule REQUIRED
      -    JNDI_RESOURCE=jdbc/AuthDB
      -  USER_TABLE=users
      -  USER_ID_COLUMN=id
      -  USER_NAME_COLUMN=name
      -  USER_CREDENTIAL_COLUMN=password
      -  ROLE_TABLE=roles
      -  ROLE_NAME_COLUMN=name
      -  PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
      -};
    • - *
    • To set the JAAS configuration file - * location, set the CATALINA_OPTS environment variable - * similar to the following: -
      CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"
      - *
    • - *
    • As part of the login process, JAASRealm registers its own CallbackHandler, - * called (unsurprisingly) JAASCallbackHandler. This handler supplies the - * HTTP requests's username and credentials to the user-supplied LoginModule
    • - *
    • As with other Realm implementations, digested passwords are supported if - * the <Realm> element in server.xml contains a - * digest attribute; JAASCallbackHandler will digest the password - * prior to passing it back to the LoginModule
    • -*
    -* -* @author Craig R. McClanahan -* @author Yoav Shapira - * @version $Revision: 303827 $ $Date: 2005-04-01 13:36:52 +0200 (ven., 01 avr. 2005) $ - */ - -public class JAASRealm - extends RealmBase - { - private static Log log = LogFactory.getLog(JAASRealm.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The application name passed to the JAAS LoginContext, - * which uses it to select the set of relevant LoginModules. - */ - protected String appName = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String info = - "org.apache.catalina.realm.JAASRealm/1.0"; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String name = "JAASRealm"; - - - /** - * The list of role class names, split out for easy processing. - */ - protected List roleClasses = new ArrayList(); - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The set of user class names, split out for easy processing. - */ - protected List userClasses = new ArrayList(); - - - /** - * Whether to use context ClassLoader or default ClassLoader. - * True means use context ClassLoader, and True is the default - * value. - */ - protected boolean useContextClassLoader = true; - - - // ------------------------------------------------------------- Properties - - - /** - * setter for the appName member variable - * @deprecated JAAS should use the Engine (domain) name and webpp/host overrides - */ - public void setAppName(String name) { - appName = name; - } - - /** - * getter for the appName member variable - */ - public String getAppName() { - return appName; - } - - /** - * Sets whether to use the context or default ClassLoader. - * True means use context ClassLoader. - * - * @param useContext True means use context ClassLoader - */ - public void setUseContextClassLoader(boolean useContext) { - useContextClassLoader = useContext; - log.info("Setting useContextClassLoader = " + useContext); - } - - /** - * Returns whether to use the context or default ClassLoader. - * True means to use the context ClassLoader. - * - * @return The value of useContextClassLoader - */ - public boolean isUseContextClassLoader() { - return useContextClassLoader; - } - - public void setContainer(Container container) { - super.setContainer(container); - - if( appName==null ) { - String name=container.getName(); - name = makeLegalForJAAS(name); - - appName=name; - - log.info("Set JAAS app name " + appName); - } - } - - /** - * Comma-delimited list of java.security.Principal classes - * that represent security roles. - */ - protected String roleClassNames = null; - - public String getRoleClassNames() { - return (this.roleClassNames); - } - - /** - * Sets the list of comma-delimited classes that represent - * roles. The classes in the list must implement java.security.Principal. - * When this accessor is called (for example, by a Digester - * instance parsing the - * configuration file), it will parse the class names and store the resulting - * string(s) into the ArrayList field roleClasses. - */ - public void setRoleClassNames(String roleClassNames) { - this.roleClassNames = roleClassNames; - roleClasses.clear(); - String temp = this.roleClassNames; - if (temp == null) { - return; - } - while (true) { - int comma = temp.indexOf(','); - if (comma < 0) { - break; - } - roleClasses.add(temp.substring(0, comma).trim()); - temp = temp.substring(comma + 1); - } - temp = temp.trim(); - if (temp.length() > 0) { - roleClasses.add(temp); - } - } - - - /** - * Comma-delimited list of java.security.Principal classes - * that represent individual users. - */ - protected String userClassNames = null; - - public String getUserClassNames() { - return (this.userClassNames); - } - - /** - * Sets the list of comma-delimited classes that represent individual - * users. The classes in the list must implement java.security.Principal. - * When this accessor is called (for example, by a Digester - * instance parsing the - * configuration file), it will parse the class names and store the resulting - * string(s) into the ArrayList field userClasses. - */ - public void setUserClassNames(String userClassNames) { - this.userClassNames = userClassNames; - userClasses.clear(); - String temp = this.userClassNames; - if (temp == null) { - return; - } - while (true) { - int comma = temp.indexOf(','); - if (comma < 0) { - break; - } - userClasses.add(temp.substring(0, comma).trim()); - temp = temp.substring(comma + 1); - } - temp = temp.trim(); - if (temp.length() > 0) { - userClasses.add(temp); - } - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * If there are any errors with the JDBC connection, executing - * the query or anything we return null (don't authenticate). This - * event is also logged, and the connection will be closed so that - * a subsequent request will automatically re-open it. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials) { - - // Establish a LoginContext to use for authentication - try { - LoginContext loginContext = null; - if( appName==null ) appName="Tomcat"; - - if( log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.beginLogin", username, appName)); - - // What if the LoginModule is in the container class loader ? - ClassLoader ocl = null; - - if (isUseContextClassLoader()) { - ocl=Thread.currentThread().getContextClassLoader(); - Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - } - - try { - loginContext = new LoginContext - (appName, new JAASCallbackHandler(this, username, - credentials)); - } catch (Throwable e) { - log.error(sm.getString("jaasRealm.unexpectedError"), e); - return (null); - } finally { - if( isUseContextClassLoader()) { - Thread.currentThread().setContextClassLoader(ocl); - } - } - - if( log.isDebugEnabled()) - log.debug("Login context created " + username); - - // Negotiate a login via this LoginContext - Subject subject = null; - try { - loginContext.login(); - subject = loginContext.getSubject(); - if (subject == null) { - if( log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.failedLogin", username)); - return (null); - } - } catch (AccountExpiredException e) { - if (log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.accountExpired", username)); - return (null); - } catch (CredentialExpiredException e) { - if (log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.credentialExpired", username)); - return (null); - } catch (FailedLoginException e) { - if (log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.failedLogin", username)); - return (null); - } catch (LoginException e) { - log.warn(sm.getString("jaasRealm.loginException", username), e); - return (null); - } catch (Throwable e) { - log.error(sm.getString("jaasRealm.unexpectedError"), e); - return (null); - } - - if( log.isDebugEnabled()) - log.debug(sm.getString("jaasRealm.loginContextCreated", username)); - - // Return the appropriate Principal for this authenticated Subject - Principal principal = createPrincipal(username, subject); - if (principal == null) { - log.debug(sm.getString("jaasRealm.authenticateFailure", username)); - return (null); - } - if (log.isDebugEnabled()) { - log.debug(sm.getString("jaasRealm.authenticateSuccess", username)); - } - - return (principal); - } catch( Throwable t) { - log.error( "error ", t); - return null; - } - } - - - // -------------------------------------------------------- Package Methods - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a short name for this Realm implementation. - */ - protected String getName() { - - return (name); - - } - - - /** - * Return the password associated with the given principal's user name. - */ - protected String getPassword(String username) { - - return (null); - - } - - - /** - * Return the Principal associated with the given user name. - */ - protected Principal getPrincipal(String username) { - - return (null); - - } - - - /** - * Identify and return a java.security.Principal instance - * representing the authenticated user for the specified Subject. - * The Principal is constructed by scanning the list of Principals returned - * by the JAASLoginModule. The first Principal object that matches - * one of the class names supplied as a "user class" is the user Principal. - * This object is returned to tha caller. - * Any remaining principal objects returned by the LoginModules are mapped to - * roles, but only if their respective classes match one of the "role class" classes. - * If a user Principal cannot be constructed, return null. - * @param subject The Subject representing the logged-in user - */ - protected Principal createPrincipal(String username, Subject subject) { - // Prepare to scan the Principals for this Subject - String password = null; // Will not be carried forward - - List roles = new ArrayList(); - Principal userPrincipal = null; - - // Scan the Principals for this Subject - Iterator principals = subject.getPrincipals().iterator(); - while (principals.hasNext()) { - Principal principal = (Principal) principals.next(); - - String principalClass = principal.getClass().getName(); - - if( log.isDebugEnabled() ) { - log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass)); - } - - if (userPrincipal == null && userClasses.contains(principalClass)) { - userPrincipal = principal; - if( log.isDebugEnabled() ) { - log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName())); - } - } - - if (roleClasses.contains(principalClass)) { - roles.add(principal.getName()); - if( log.isDebugEnabled() ) { - log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName())); - } - } - } - - // Print failure message if needed - if (userPrincipal == null) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("jaasRealm.userPrincipalFailure")); - log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); - } - } else { - if (roles.size() == 0) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); - } - } - } - - // Return the resulting Principal for our authenticated user - return new GenericPrincipal(this, username, null, roles, userPrincipal); - } - - /** - * Ensure the given name is legal for JAAS configuration. - * Added for Bugzilla 30869, made protected for easy customization - * in case my implementation is insufficient, which I think is - * very likely. - * - * @param src The name to validate - * @return A string that's a valid JAAS realm name - */ - protected String makeLegalForJAAS(final String src) { - String result = src; - - // Default name is "other" per JAAS spec - if(result == null) { - result = "other"; - } - - // Strip leading slash if present, as Sun JAAS impl - // barfs on it (see Bugzilla 30869 bug report). - if(result.startsWith("/")) { - result = result.substring(1); - } - - return result; - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - } - - -} +/* + * Copyright 2001-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.security.auth.Subject; +import javax.security.auth.login.AccountExpiredException; +import javax.security.auth.login.CredentialExpiredException; +import javax.security.auth.login.FailedLoginException; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; + +import org.apache.catalina.Container; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + *

    Implmentation of Realm that authenticates users via the Java + * Authentication and Authorization Service (JAAS). JAAS support requires + * either JDK 1.4 (which includes it as part of the standard platform) or + * JDK 1.3 (with the plug-in jaas.jar file).

    + * + *

    The value configured for the appName property is passed to + * the javax.security.auth.login.LoginContext constructor, to + * specify the application name used to select the set of relevant + * LoginModules required.

    + * + *

    The JAAS Specification describes the result of a successful login as a + * javax.security.auth.Subject instance, which can contain zero + * or more java.security.Principal objects in the return value + * of the Subject.getPrincipals() method. However, it provides + * no guidance on how to distinguish Principals that describe the individual + * user (and are thus appropriate to return as the value of + * request.getUserPrincipal() in a web application) from the Principal(s) + * that describe the authorized roles for this user. To maintain as much + * independence as possible from the underlying LoginMethod + * implementation executed by JAAS, the following policy is implemented by + * this Realm:

    + *
      + *
    • The JAAS LoginModule is assumed to return a + * Subject with at least one Principal instance + * representing the user himself or herself, and zero or more separate + * Principals representing the security roles authorized + * for this user.
    • + *
    • On the Principal representing the user, the Principal + * name is an appropriate value to return via the Servlet API method + * HttpServletRequest.getRemoteUser().
    • + *
    • On the Principals representing the security roles, the + * name is the name of the authorized security role.
    • + *
    • This Realm will be configured with two lists of fully qualified Java + * class names of classes that implement + * java.security.Principal - one that identifies class(es) + * representing a user, and one that identifies class(es) representing + * a security role.
    • + *
    • As this Realm iterates over the Principals returned by + * Subject.getPrincipals(), it will identify the first + * Principal that matches the "user classes" list as the + * Principal for this user.
    • + *
    • As this Realm iterates over the Princpals returned by + * Subject.getPrincipals(), it will accumulate the set of + * all Principals matching the "role classes" list as + * identifying the security roles for this user.
    • + *
    • It is a configuration error for the JAAS login method to return a + * validated Subject without a Principal that + * matches the "user classes" list.
    • + *
    • By default, the enclosing Container's name serves as the + * application name used to obtain the JAAS LoginContext ("Catalina" in + * a default installation). Tomcat must be able to find an application + * with this name in the JAAS configuration file. Here is a hypothetical + * JAAS configuration file entry for a database-oriented login module that uses + * a Tomcat-managed JNDI database resource: + *
      Catalina {
      +org.foobar.auth.DatabaseLoginModule REQUIRED
      +    JNDI_RESOURCE=jdbc/AuthDB
      +  USER_TABLE=users
      +  USER_ID_COLUMN=id
      +  USER_NAME_COLUMN=name
      +  USER_CREDENTIAL_COLUMN=password
      +  ROLE_TABLE=roles
      +  ROLE_NAME_COLUMN=name
      +  PRINCIPAL_FACTORY=org.foobar.auth.impl.SimplePrincipalFactory;
      +};
    • + *
    • To set the JAAS configuration file + * location, set the CATALINA_OPTS environment variable + * similar to the following: +
      CATALINA_OPTS="-Djava.security.auth.login.config=$CATALINA_HOME/conf/jaas.config"
      + *
    • + *
    • As part of the login process, JAASRealm registers its own CallbackHandler, + * called (unsurprisingly) JAASCallbackHandler. This handler supplies the + * HTTP requests's username and credentials to the user-supplied LoginModule
    • + *
    • As with other Realm implementations, digested passwords are supported if + * the <Realm> element in server.xml contains a + * digest attribute; JAASCallbackHandler will digest the password + * prior to passing it back to the LoginModule
    • +*
    +* +* @author Craig R. McClanahan +* @author Yoav Shapira + * @version $Revision: 303827 $ $Date: 2005-04-01 13:36:52 +0200 (ven., 01 avr. 2005) $ + */ + +public class JAASRealm + extends RealmBase + { + private static Log log = LogFactory.getLog(JAASRealm.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The application name passed to the JAAS LoginContext, + * which uses it to select the set of relevant LoginModules. + */ + protected String appName = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String info = + "org.apache.catalina.realm.JAASRealm/1.0"; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String name = "JAASRealm"; + + + /** + * The list of role class names, split out for easy processing. + */ + protected List roleClasses = new ArrayList(); + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The set of user class names, split out for easy processing. + */ + protected List userClasses = new ArrayList(); + + + /** + * Whether to use context ClassLoader or default ClassLoader. + * True means use context ClassLoader, and True is the default + * value. + */ + protected boolean useContextClassLoader = true; + + + // ------------------------------------------------------------- Properties + + + /** + * setter for the appName member variable + * @deprecated JAAS should use the Engine (domain) name and webpp/host overrides + */ + public void setAppName(String name) { + appName = name; + } + + /** + * getter for the appName member variable + */ + public String getAppName() { + return appName; + } + + /** + * Sets whether to use the context or default ClassLoader. + * True means use context ClassLoader. + * + * @param useContext True means use context ClassLoader + */ + public void setUseContextClassLoader(boolean useContext) { + useContextClassLoader = useContext; + log.info("Setting useContextClassLoader = " + useContext); + } + + /** + * Returns whether to use the context or default ClassLoader. + * True means to use the context ClassLoader. + * + * @return The value of useContextClassLoader + */ + public boolean isUseContextClassLoader() { + return useContextClassLoader; + } + + public void setContainer(Container container) { + super.setContainer(container); + + if( appName==null ) { + String name=container.getName(); + name = makeLegalForJAAS(name); + + appName=name; + + log.info("Set JAAS app name " + appName); + } + } + + /** + * Comma-delimited list of java.security.Principal classes + * that represent security roles. + */ + protected String roleClassNames = null; + + public String getRoleClassNames() { + return (this.roleClassNames); + } + + /** + * Sets the list of comma-delimited classes that represent + * roles. The classes in the list must implement java.security.Principal. + * When this accessor is called (for example, by a Digester + * instance parsing the + * configuration file), it will parse the class names and store the resulting + * string(s) into the ArrayList field roleClasses. + */ + public void setRoleClassNames(String roleClassNames) { + this.roleClassNames = roleClassNames; + roleClasses.clear(); + String temp = this.roleClassNames; + if (temp == null) { + return; + } + while (true) { + int comma = temp.indexOf(','); + if (comma < 0) { + break; + } + roleClasses.add(temp.substring(0, comma).trim()); + temp = temp.substring(comma + 1); + } + temp = temp.trim(); + if (temp.length() > 0) { + roleClasses.add(temp); + } + } + + + /** + * Comma-delimited list of java.security.Principal classes + * that represent individual users. + */ + protected String userClassNames = null; + + public String getUserClassNames() { + return (this.userClassNames); + } + + /** + * Sets the list of comma-delimited classes that represent individual + * users. The classes in the list must implement java.security.Principal. + * When this accessor is called (for example, by a Digester + * instance parsing the + * configuration file), it will parse the class names and store the resulting + * string(s) into the ArrayList field userClasses. + */ + public void setUserClassNames(String userClassNames) { + this.userClassNames = userClassNames; + userClasses.clear(); + String temp = this.userClassNames; + if (temp == null) { + return; + } + while (true) { + int comma = temp.indexOf(','); + if (comma < 0) { + break; + } + userClasses.add(temp.substring(0, comma).trim()); + temp = temp.substring(comma + 1); + } + temp = temp.trim(); + if (temp.length() > 0) { + userClasses.add(temp); + } + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * If there are any errors with the JDBC connection, executing + * the query or anything we return null (don't authenticate). This + * event is also logged, and the connection will be closed so that + * a subsequent request will automatically re-open it. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials) { + + // Establish a LoginContext to use for authentication + try { + LoginContext loginContext = null; + if( appName==null ) appName="Tomcat"; + + if( log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.beginLogin", username, appName)); + + // What if the LoginModule is in the container class loader ? + ClassLoader ocl = null; + + if (isUseContextClassLoader()) { + ocl=Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); + } + + try { + loginContext = new LoginContext + (appName, new JAASCallbackHandler(this, username, + credentials)); + } catch (Throwable e) { + log.error(sm.getString("jaasRealm.unexpectedError"), e); + return (null); + } finally { + if( isUseContextClassLoader()) { + Thread.currentThread().setContextClassLoader(ocl); + } + } + + if( log.isDebugEnabled()) + log.debug("Login context created " + username); + + // Negotiate a login via this LoginContext + Subject subject = null; + try { + loginContext.login(); + subject = loginContext.getSubject(); + if (subject == null) { + if( log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.failedLogin", username)); + return (null); + } + } catch (AccountExpiredException e) { + if (log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.accountExpired", username)); + return (null); + } catch (CredentialExpiredException e) { + if (log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.credentialExpired", username)); + return (null); + } catch (FailedLoginException e) { + if (log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.failedLogin", username)); + return (null); + } catch (LoginException e) { + log.warn(sm.getString("jaasRealm.loginException", username), e); + return (null); + } catch (Throwable e) { + log.error(sm.getString("jaasRealm.unexpectedError"), e); + return (null); + } + + if( log.isDebugEnabled()) + log.debug(sm.getString("jaasRealm.loginContextCreated", username)); + + // Return the appropriate Principal for this authenticated Subject + Principal principal = createPrincipal(username, subject); + if (principal == null) { + log.debug(sm.getString("jaasRealm.authenticateFailure", username)); + return (null); + } + if (log.isDebugEnabled()) { + log.debug(sm.getString("jaasRealm.authenticateSuccess", username)); + } + + return (principal); + } catch( Throwable t) { + log.error( "error ", t); + return null; + } + } + + + // -------------------------------------------------------- Package Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + + return (name); + + } + + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String username) { + + return (null); + + } + + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String username) { + + return (null); + + } + + + /** + * Identify and return a java.security.Principal instance + * representing the authenticated user for the specified Subject. + * The Principal is constructed by scanning the list of Principals returned + * by the JAASLoginModule. The first Principal object that matches + * one of the class names supplied as a "user class" is the user Principal. + * This object is returned to tha caller. + * Any remaining principal objects returned by the LoginModules are mapped to + * roles, but only if their respective classes match one of the "role class" classes. + * If a user Principal cannot be constructed, return null. + * @param subject The Subject representing the logged-in user + */ + protected Principal createPrincipal(String username, Subject subject) { + // Prepare to scan the Principals for this Subject + String password = null; // Will not be carried forward + + List roles = new ArrayList(); + Principal userPrincipal = null; + + // Scan the Principals for this Subject + Iterator principals = subject.getPrincipals().iterator(); + while (principals.hasNext()) { + Principal principal = (Principal) principals.next(); + + String principalClass = principal.getClass().getName(); + + if( log.isDebugEnabled() ) { + log.debug(sm.getString("jaasRealm.checkPrincipal", principal, principalClass)); + } + + if (userPrincipal == null && userClasses.contains(principalClass)) { + userPrincipal = principal; + if( log.isDebugEnabled() ) { + log.debug(sm.getString("jaasRealm.userPrincipalSuccess", principal.getName())); + } + } + + if (roleClasses.contains(principalClass)) { + roles.add(principal.getName()); + if( log.isDebugEnabled() ) { + log.debug(sm.getString("jaasRealm.rolePrincipalAdd", principal.getName())); + } + } + } + + // Print failure message if needed + if (userPrincipal == null) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("jaasRealm.userPrincipalFailure")); + log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); + } + } else { + if (roles.size() == 0) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("jaasRealm.rolePrincipalFailure")); + } + } + } + + // Return the resulting Principal for our authenticated user + return new GenericPrincipal(this, username, null, roles, userPrincipal); + } + + /** + * Ensure the given name is legal for JAAS configuration. + * Added for Bugzilla 30869, made protected for easy customization + * in case my implementation is insufficient, which I think is + * very likely. + * + * @param src The name to validate + * @return A string that's a valid JAAS realm name + */ + protected String makeLegalForJAAS(final String src) { + String result = src; + + // Default name is "other" per JAAS spec + if(result == null) { + result = "other"; + } + + // Strip leading slash if present, as Sun JAAS impl + // barfs on it (see Bugzilla 30869 bug report). + if(result.startsWith("/")) { + result = result.substring(1); + } + + return result; + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + } + + +} diff --git a/java/org/apache/catalina/realm/JDBCRealm.java b/java/org/apache/catalina/realm/JDBCRealm.java index e4c3b27eb..ffff0e9fd 100644 --- a/java/org/apache/catalina/realm/JDBCRealm.java +++ b/java/org/apache/catalina/realm/JDBCRealm.java @@ -1,791 +1,791 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Properties; - -import org.apache.catalina.LifecycleException; -import org.apache.catalina.util.StringManager; - - -/** -* -* Implmentation of Realm that works with any JDBC supported database. -* See the JDBCRealm.howto for more details on how to set up the database and -* for configuration options. -* -*

    TODO - Support connection pooling (including message -* format objects) so that authenticate() does not have to be -* synchronized and would fix the ugly connection logic.

    -* -* @author Craig R. McClanahan -* @author Carson McDonald -* @author Ignacio Ortega -* @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ -*/ - -public class JDBCRealm - extends RealmBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The connection username to use when trying to connect to the database. - */ - protected String connectionName = null; - - - /** - * The connection URL to use when trying to connect to the database. - */ - protected String connectionPassword = null; - - - /** - * The connection URL to use when trying to connect to the database. - */ - protected String connectionURL = null; - - - /** - * The connection to the database. - */ - protected Connection dbConnection = null; - - - /** - * Instance of the JDBC Driver class we use as a connection factory. - */ - protected Driver driver = null; - - - /** - * The JDBC driver to use. - */ - protected String driverName = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String info = - "org.apache.catalina.realm.JDBCRealm/1.0"; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String name = "JDBCRealm"; - - - /** - * The PreparedStatement to use for authenticating users. - */ - protected PreparedStatement preparedCredentials = null; - - - /** - * The PreparedStatement to use for identifying the roles for - * a specified user. - */ - protected PreparedStatement preparedRoles = null; - - - /** - * The column in the user role table that names a role - */ - protected String roleNameCol = null; - - - /** - * The string manager for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The column in the user table that holds the user's credintials - */ - protected String userCredCol = null; - - - /** - * The column in the user table that holds the user's name - */ - protected String userNameCol = null; - - - /** - * The table that holds the relation between user's and roles - */ - protected String userRoleTable = null; - - - /** - * The table that holds user data. - */ - protected String userTable = null; - - - // ------------------------------------------------------------- Properties - - /** - * Return the username to use to connect to the database. - * - */ - public String getConnectionName() { - return connectionName; - } - - /** - * Set the username to use to connect to the database. - * - * @param connectionName Username - */ - public void setConnectionName(String connectionName) { - this.connectionName = connectionName; - } - - /** - * Return the password to use to connect to the database. - * - */ - public String getConnectionPassword() { - return connectionPassword; - } - - /** - * Set the password to use to connect to the database. - * - * @param connectionPassword User password - */ - public void setConnectionPassword(String connectionPassword) { - this.connectionPassword = connectionPassword; - } - - /** - * Return the URL to use to connect to the database. - * - */ - public String getConnectionURL() { - return connectionURL; - } - - /** - * Set the URL to use to connect to the database. - * - * @param connectionURL The new connection URL - */ - public void setConnectionURL( String connectionURL ) { - this.connectionURL = connectionURL; - } - - /** - * Return the JDBC driver that will be used. - * - */ - public String getDriverName() { - return driverName; - } - - /** - * Set the JDBC driver that will be used. - * - * @param driverName The driver name - */ - public void setDriverName( String driverName ) { - this.driverName = driverName; - } - - /** - * Return the column in the user role table that names a role. - * - */ - public String getRoleNameCol() { - return roleNameCol; - } - - /** - * Set the column in the user role table that names a role. - * - * @param roleNameCol The column name - */ - public void setRoleNameCol( String roleNameCol ) { - this.roleNameCol = roleNameCol; - } - - /** - * Return the column in the user table that holds the user's credentials. - * - */ - public String getUserCredCol() { - return userCredCol; - } - - /** - * Set the column in the user table that holds the user's credentials. - * - * @param userCredCol The column name - */ - public void setUserCredCol( String userCredCol ) { - this.userCredCol = userCredCol; - } - - /** - * Return the column in the user table that holds the user's name. - * - */ - public String getUserNameCol() { - return userNameCol; - } - - /** - * Set the column in the user table that holds the user's name. - * - * @param userNameCol The column name - */ - public void setUserNameCol( String userNameCol ) { - this.userNameCol = userNameCol; - } - - /** - * Return the table that holds the relation between user's and roles. - * - */ - public String getUserRoleTable() { - return userRoleTable; - } - - /** - * Set the table that holds the relation between user's and roles. - * - * @param userRoleTable The table name - */ - public void setUserRoleTable( String userRoleTable ) { - this.userRoleTable = userRoleTable; - } - - /** - * Return the table that holds user data.. - * - */ - public String getUserTable() { - return userTable; - } - - /** - * Set the table that holds user data. - * - * @param userTable The table name - */ - public void setUserTable( String userTable ) { - this.userTable = userTable; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * If there are any errors with the JDBC connection, executing - * the query or anything we return null (don't authenticate). This - * event is also logged, and the connection will be closed so that - * a subsequent request will automatically re-open it. - * - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public synchronized Principal authenticate(String username, String credentials) { - - // Number of tries is the numebr of attempts to connect to the database - // during this login attempt (if we need to open the database) - // This needs rewritten wuth better pooling support, the existing code - // needs signature changes since the Prepared statements needs cached - // with the connections. - // The code below will try twice if there is a SQLException so the - // connection may try to be opened again. On normal conditions (including - // invalid login - the above is only used once. - int numberOfTries = 2; - while (numberOfTries>0) { - try { - - // Ensure that we have an open database connection - open(); - - // Acquire a Principal object for this user - Principal principal = authenticate(dbConnection, - username, credentials); - - - // Return the Principal (if any) - return (principal); - - } catch (SQLException e) { - - // Log the problem for posterity - containerLog.error(sm.getString("jdbcRealm.exception"), e); - - // Close the connection so that it gets reopened next time - if (dbConnection != null) - close(dbConnection); - - } - - numberOfTries--; - } - - // Worst case scenario - return null; - - } - - - // -------------------------------------------------------- Package Methods - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param dbConnection The database connection to be used - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public synchronized Principal authenticate(Connection dbConnection, - String username, - String credentials) { - - // No user - can't possibly authenticate - if (username == null) { - return (null); - } - - // Look up the user's credentials - String dbCredentials = getPassword(username); - - // Validate the user's credentials - boolean validated = false; - if (hasMessageDigest()) { - // Hex hashes should be compared case-insensitive - validated = (digest(credentials).equalsIgnoreCase(dbCredentials)); - } else { - validated = (digest(credentials).equals(dbCredentials)); - } - - if (validated) { - if (containerLog.isTraceEnabled()) - containerLog.trace(sm.getString("jdbcRealm.authenticateSuccess", - username)); - } else { - if (containerLog.isTraceEnabled()) - containerLog.trace(sm.getString("jdbcRealm.authenticateFailure", - username)); - return (null); - } - - ArrayList roles = getRoles(username); - - // Create and return a suitable Principal for this user - return (new GenericPrincipal(this, username, credentials, roles)); - - } - - - /** - * Close the specified database connection. - * - * @param dbConnection The connection to be closed - */ - protected void close(Connection dbConnection) { - - // Do nothing if the database connection is already closed - if (dbConnection == null) - return; - - // Close our prepared statements (if any) - try { - preparedCredentials.close(); - } catch (Throwable f) { - ; - } - this.preparedCredentials = null; - - - try { - preparedRoles.close(); - } catch (Throwable f) { - ; - } - this.preparedRoles = null; - - - // Close this database connection, and log any errors - try { - dbConnection.close(); - } catch (SQLException e) { - containerLog.warn(sm.getString("jdbcRealm.close"), e); // Just log it here - } finally { - this.dbConnection = null; - } - - } - - - /** - * Return a PreparedStatement configured to perform the SELECT required - * to retrieve user credentials for the specified username. - * - * @param dbConnection The database connection to be used - * @param username Username for which credentials should be retrieved - * - * @exception SQLException if a database error occurs - */ - protected PreparedStatement credentials(Connection dbConnection, - String username) - throws SQLException { - - if (preparedCredentials == null) { - StringBuffer sb = new StringBuffer("SELECT "); - sb.append(userCredCol); - sb.append(" FROM "); - sb.append(userTable); - sb.append(" WHERE "); - sb.append(userNameCol); - sb.append(" = ?"); - - if(containerLog.isDebugEnabled()) { - containerLog.debug("credentials query: " + sb.toString()); - } - - preparedCredentials = - dbConnection.prepareStatement(sb.toString()); - } - - if (username == null) { - preparedCredentials.setNull(1,java.sql.Types.VARCHAR); - } else { - preparedCredentials.setString(1, username); - } - - return (preparedCredentials); - } - - - /** - * Return a short name for this Realm implementation. - */ - protected String getName() { - - return (name); - - } - - - /** - * Return the password associated with the given principal's user name. - */ - protected String getPassword(String username) { - - // Look up the user's credentials - String dbCredentials = null; - PreparedStatement stmt = null; - ResultSet rs = null; - - // Number of tries is the numebr of attempts to connect to the database - // during this login attempt (if we need to open the database) - // This needs rewritten wuth better pooling support, the existing code - // needs signature changes since the Prepared statements needs cached - // with the connections. - // The code below will try twice if there is a SQLException so the - // connection may try to be opened again. On normal conditions (including - // invalid login - the above is only used once. - int numberOfTries = 2; - while (numberOfTries>0) { - try { - - // Ensure that we have an open database connection - open(); - - try { - stmt = credentials(dbConnection, username); - rs = stmt.executeQuery(); - - if (rs.next()) { - dbCredentials = rs.getString(1); - } - rs.close(); - rs = null; - if (dbCredentials == null) { - return (null); - } - - dbCredentials = dbCredentials.trim(); - return dbCredentials; - - } finally { - if (rs!=null) { - try { - rs.close(); - } catch(SQLException e) { - containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet")); - } - } - dbConnection.commit(); - } - - } catch (SQLException e) { - - // Log the problem for posterity - containerLog.error(sm.getString("jdbcRealm.exception"), e); - - // Close the connection so that it gets reopened next time - if (dbConnection != null) - close(dbConnection); - - } - - numberOfTries--; - } - - return (null); - } - - - /** - * Return the Principal associated with the given user name. - */ - protected Principal getPrincipal(String username) { - - return (new GenericPrincipal(this, - username, - getPassword(username), - getRoles(username))); - - } - - - /** - * Return the roles associated with the gven user name. - */ - protected ArrayList getRoles(String username) { - - PreparedStatement stmt = null; - ResultSet rs = null; - - // Number of tries is the numebr of attempts to connect to the database - // during this login attempt (if we need to open the database) - // This needs rewritten wuth better pooling support, the existing code - // needs signature changes since the Prepared statements needs cached - // with the connections. - // The code below will try twice if there is a SQLException so the - // connection may try to be opened again. On normal conditions (including - // invalid login - the above is only used once. - int numberOfTries = 2; - while (numberOfTries>0) { - try { - - // Ensure that we have an open database connection - open(); - - try { - // Accumulate the user's roles - ArrayList roleList = new ArrayList(); - stmt = roles(dbConnection, username); - rs = stmt.executeQuery(); - while (rs.next()) { - String role = rs.getString(1); - if (null!=role) { - roleList.add(role.trim()); - } - } - rs.close(); - rs = null; - - return (roleList); - - } finally { - if (rs!=null) { - try { - rs.close(); - } catch(SQLException e) { - containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet")); - } - } - dbConnection.commit(); - } - - } catch (SQLException e) { - - // Log the problem for posterity - containerLog.error(sm.getString("jdbcRealm.exception"), e); - - // Close the connection so that it gets reopened next time - if (dbConnection != null) - close(dbConnection); - - } - - numberOfTries--; - } - - return (null); - - } - - - /** - * Open (if necessary) and return a database connection for use by - * this Realm. - * - * @exception SQLException if a database error occurs - */ - protected Connection open() throws SQLException { - - // Do nothing if there is a database connection already open - if (dbConnection != null) - return (dbConnection); - - // Instantiate our database driver if necessary - if (driver == null) { - try { - Class clazz = Class.forName(driverName); - driver = (Driver) clazz.newInstance(); - } catch (Throwable e) { - throw new SQLException(e.getMessage()); - } - } - - // Open a new connection - Properties props = new Properties(); - if (connectionName != null) - props.put("user", connectionName); - if (connectionPassword != null) - props.put("password", connectionPassword); - dbConnection = driver.connect(connectionURL, props); - dbConnection.setAutoCommit(false); - return (dbConnection); - - } - - - /** - * Release our use of this connection so that it can be recycled. - * - * @param dbConnection The connection to be released - */ - protected void release(Connection dbConnection) { - - ; // NO-OP since we are not pooling anything - - } - - - /** - * Return a PreparedStatement configured to perform the SELECT required - * to retrieve user roles for the specified username. - * - * @param dbConnection The database connection to be used - * @param username Username for which roles should be retrieved - * - * @exception SQLException if a database error occurs - */ - protected PreparedStatement roles(Connection dbConnection, String username) - throws SQLException { - - if (preparedRoles == null) { - StringBuffer sb = new StringBuffer("SELECT "); - sb.append(roleNameCol); - sb.append(" FROM "); - sb.append(userRoleTable); - sb.append(" WHERE "); - sb.append(userNameCol); - sb.append(" = ?"); - preparedRoles = - dbConnection.prepareStatement(sb.toString()); - } - - preparedRoles.setString(1, username); - return (preparedRoles); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - // Validate that we can open our connection - but let tomcat - // startup in case the database is temporarily unavailable - try { - open(); - } catch (SQLException e) { - containerLog.error(sm.getString("jdbcRealm.open"), e); - } - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - // Close any open DB connection - close(this.dbConnection); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.security.Principal; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Properties; + +import org.apache.catalina.LifecycleException; +import org.apache.catalina.util.StringManager; + + +/** +* +* Implmentation of Realm that works with any JDBC supported database. +* See the JDBCRealm.howto for more details on how to set up the database and +* for configuration options. +* +*

    TODO - Support connection pooling (including message +* format objects) so that authenticate() does not have to be +* synchronized and would fix the ugly connection logic.

    +* +* @author Craig R. McClanahan +* @author Carson McDonald +* @author Ignacio Ortega +* @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ +*/ + +public class JDBCRealm + extends RealmBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The connection username to use when trying to connect to the database. + */ + protected String connectionName = null; + + + /** + * The connection URL to use when trying to connect to the database. + */ + protected String connectionPassword = null; + + + /** + * The connection URL to use when trying to connect to the database. + */ + protected String connectionURL = null; + + + /** + * The connection to the database. + */ + protected Connection dbConnection = null; + + + /** + * Instance of the JDBC Driver class we use as a connection factory. + */ + protected Driver driver = null; + + + /** + * The JDBC driver to use. + */ + protected String driverName = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String info = + "org.apache.catalina.realm.JDBCRealm/1.0"; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String name = "JDBCRealm"; + + + /** + * The PreparedStatement to use for authenticating users. + */ + protected PreparedStatement preparedCredentials = null; + + + /** + * The PreparedStatement to use for identifying the roles for + * a specified user. + */ + protected PreparedStatement preparedRoles = null; + + + /** + * The column in the user role table that names a role + */ + protected String roleNameCol = null; + + + /** + * The string manager for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The column in the user table that holds the user's credintials + */ + protected String userCredCol = null; + + + /** + * The column in the user table that holds the user's name + */ + protected String userNameCol = null; + + + /** + * The table that holds the relation between user's and roles + */ + protected String userRoleTable = null; + + + /** + * The table that holds user data. + */ + protected String userTable = null; + + + // ------------------------------------------------------------- Properties + + /** + * Return the username to use to connect to the database. + * + */ + public String getConnectionName() { + return connectionName; + } + + /** + * Set the username to use to connect to the database. + * + * @param connectionName Username + */ + public void setConnectionName(String connectionName) { + this.connectionName = connectionName; + } + + /** + * Return the password to use to connect to the database. + * + */ + public String getConnectionPassword() { + return connectionPassword; + } + + /** + * Set the password to use to connect to the database. + * + * @param connectionPassword User password + */ + public void setConnectionPassword(String connectionPassword) { + this.connectionPassword = connectionPassword; + } + + /** + * Return the URL to use to connect to the database. + * + */ + public String getConnectionURL() { + return connectionURL; + } + + /** + * Set the URL to use to connect to the database. + * + * @param connectionURL The new connection URL + */ + public void setConnectionURL( String connectionURL ) { + this.connectionURL = connectionURL; + } + + /** + * Return the JDBC driver that will be used. + * + */ + public String getDriverName() { + return driverName; + } + + /** + * Set the JDBC driver that will be used. + * + * @param driverName The driver name + */ + public void setDriverName( String driverName ) { + this.driverName = driverName; + } + + /** + * Return the column in the user role table that names a role. + * + */ + public String getRoleNameCol() { + return roleNameCol; + } + + /** + * Set the column in the user role table that names a role. + * + * @param roleNameCol The column name + */ + public void setRoleNameCol( String roleNameCol ) { + this.roleNameCol = roleNameCol; + } + + /** + * Return the column in the user table that holds the user's credentials. + * + */ + public String getUserCredCol() { + return userCredCol; + } + + /** + * Set the column in the user table that holds the user's credentials. + * + * @param userCredCol The column name + */ + public void setUserCredCol( String userCredCol ) { + this.userCredCol = userCredCol; + } + + /** + * Return the column in the user table that holds the user's name. + * + */ + public String getUserNameCol() { + return userNameCol; + } + + /** + * Set the column in the user table that holds the user's name. + * + * @param userNameCol The column name + */ + public void setUserNameCol( String userNameCol ) { + this.userNameCol = userNameCol; + } + + /** + * Return the table that holds the relation between user's and roles. + * + */ + public String getUserRoleTable() { + return userRoleTable; + } + + /** + * Set the table that holds the relation between user's and roles. + * + * @param userRoleTable The table name + */ + public void setUserRoleTable( String userRoleTable ) { + this.userRoleTable = userRoleTable; + } + + /** + * Return the table that holds user data.. + * + */ + public String getUserTable() { + return userTable; + } + + /** + * Set the table that holds user data. + * + * @param userTable The table name + */ + public void setUserTable( String userTable ) { + this.userTable = userTable; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * If there are any errors with the JDBC connection, executing + * the query or anything we return null (don't authenticate). This + * event is also logged, and the connection will be closed so that + * a subsequent request will automatically re-open it. + * + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public synchronized Principal authenticate(String username, String credentials) { + + // Number of tries is the numebr of attempts to connect to the database + // during this login attempt (if we need to open the database) + // This needs rewritten wuth better pooling support, the existing code + // needs signature changes since the Prepared statements needs cached + // with the connections. + // The code below will try twice if there is a SQLException so the + // connection may try to be opened again. On normal conditions (including + // invalid login - the above is only used once. + int numberOfTries = 2; + while (numberOfTries>0) { + try { + + // Ensure that we have an open database connection + open(); + + // Acquire a Principal object for this user + Principal principal = authenticate(dbConnection, + username, credentials); + + + // Return the Principal (if any) + return (principal); + + } catch (SQLException e) { + + // Log the problem for posterity + containerLog.error(sm.getString("jdbcRealm.exception"), e); + + // Close the connection so that it gets reopened next time + if (dbConnection != null) + close(dbConnection); + + } + + numberOfTries--; + } + + // Worst case scenario + return null; + + } + + + // -------------------------------------------------------- Package Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param dbConnection The database connection to be used + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public synchronized Principal authenticate(Connection dbConnection, + String username, + String credentials) { + + // No user - can't possibly authenticate + if (username == null) { + return (null); + } + + // Look up the user's credentials + String dbCredentials = getPassword(username); + + // Validate the user's credentials + boolean validated = false; + if (hasMessageDigest()) { + // Hex hashes should be compared case-insensitive + validated = (digest(credentials).equalsIgnoreCase(dbCredentials)); + } else { + validated = (digest(credentials).equals(dbCredentials)); + } + + if (validated) { + if (containerLog.isTraceEnabled()) + containerLog.trace(sm.getString("jdbcRealm.authenticateSuccess", + username)); + } else { + if (containerLog.isTraceEnabled()) + containerLog.trace(sm.getString("jdbcRealm.authenticateFailure", + username)); + return (null); + } + + ArrayList roles = getRoles(username); + + // Create and return a suitable Principal for this user + return (new GenericPrincipal(this, username, credentials, roles)); + + } + + + /** + * Close the specified database connection. + * + * @param dbConnection The connection to be closed + */ + protected void close(Connection dbConnection) { + + // Do nothing if the database connection is already closed + if (dbConnection == null) + return; + + // Close our prepared statements (if any) + try { + preparedCredentials.close(); + } catch (Throwable f) { + ; + } + this.preparedCredentials = null; + + + try { + preparedRoles.close(); + } catch (Throwable f) { + ; + } + this.preparedRoles = null; + + + // Close this database connection, and log any errors + try { + dbConnection.close(); + } catch (SQLException e) { + containerLog.warn(sm.getString("jdbcRealm.close"), e); // Just log it here + } finally { + this.dbConnection = null; + } + + } + + + /** + * Return a PreparedStatement configured to perform the SELECT required + * to retrieve user credentials for the specified username. + * + * @param dbConnection The database connection to be used + * @param username Username for which credentials should be retrieved + * + * @exception SQLException if a database error occurs + */ + protected PreparedStatement credentials(Connection dbConnection, + String username) + throws SQLException { + + if (preparedCredentials == null) { + StringBuffer sb = new StringBuffer("SELECT "); + sb.append(userCredCol); + sb.append(" FROM "); + sb.append(userTable); + sb.append(" WHERE "); + sb.append(userNameCol); + sb.append(" = ?"); + + if(containerLog.isDebugEnabled()) { + containerLog.debug("credentials query: " + sb.toString()); + } + + preparedCredentials = + dbConnection.prepareStatement(sb.toString()); + } + + if (username == null) { + preparedCredentials.setNull(1,java.sql.Types.VARCHAR); + } else { + preparedCredentials.setString(1, username); + } + + return (preparedCredentials); + } + + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + + return (name); + + } + + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String username) { + + // Look up the user's credentials + String dbCredentials = null; + PreparedStatement stmt = null; + ResultSet rs = null; + + // Number of tries is the numebr of attempts to connect to the database + // during this login attempt (if we need to open the database) + // This needs rewritten wuth better pooling support, the existing code + // needs signature changes since the Prepared statements needs cached + // with the connections. + // The code below will try twice if there is a SQLException so the + // connection may try to be opened again. On normal conditions (including + // invalid login - the above is only used once. + int numberOfTries = 2; + while (numberOfTries>0) { + try { + + // Ensure that we have an open database connection + open(); + + try { + stmt = credentials(dbConnection, username); + rs = stmt.executeQuery(); + + if (rs.next()) { + dbCredentials = rs.getString(1); + } + rs.close(); + rs = null; + if (dbCredentials == null) { + return (null); + } + + dbCredentials = dbCredentials.trim(); + return dbCredentials; + + } finally { + if (rs!=null) { + try { + rs.close(); + } catch(SQLException e) { + containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet")); + } + } + dbConnection.commit(); + } + + } catch (SQLException e) { + + // Log the problem for posterity + containerLog.error(sm.getString("jdbcRealm.exception"), e); + + // Close the connection so that it gets reopened next time + if (dbConnection != null) + close(dbConnection); + + } + + numberOfTries--; + } + + return (null); + } + + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String username) { + + return (new GenericPrincipal(this, + username, + getPassword(username), + getRoles(username))); + + } + + + /** + * Return the roles associated with the gven user name. + */ + protected ArrayList getRoles(String username) { + + PreparedStatement stmt = null; + ResultSet rs = null; + + // Number of tries is the numebr of attempts to connect to the database + // during this login attempt (if we need to open the database) + // This needs rewritten wuth better pooling support, the existing code + // needs signature changes since the Prepared statements needs cached + // with the connections. + // The code below will try twice if there is a SQLException so the + // connection may try to be opened again. On normal conditions (including + // invalid login - the above is only used once. + int numberOfTries = 2; + while (numberOfTries>0) { + try { + + // Ensure that we have an open database connection + open(); + + try { + // Accumulate the user's roles + ArrayList roleList = new ArrayList(); + stmt = roles(dbConnection, username); + rs = stmt.executeQuery(); + while (rs.next()) { + String role = rs.getString(1); + if (null!=role) { + roleList.add(role.trim()); + } + } + rs.close(); + rs = null; + + return (roleList); + + } finally { + if (rs!=null) { + try { + rs.close(); + } catch(SQLException e) { + containerLog.warn(sm.getString("jdbcRealm.abnormalCloseResultSet")); + } + } + dbConnection.commit(); + } + + } catch (SQLException e) { + + // Log the problem for posterity + containerLog.error(sm.getString("jdbcRealm.exception"), e); + + // Close the connection so that it gets reopened next time + if (dbConnection != null) + close(dbConnection); + + } + + numberOfTries--; + } + + return (null); + + } + + + /** + * Open (if necessary) and return a database connection for use by + * this Realm. + * + * @exception SQLException if a database error occurs + */ + protected Connection open() throws SQLException { + + // Do nothing if there is a database connection already open + if (dbConnection != null) + return (dbConnection); + + // Instantiate our database driver if necessary + if (driver == null) { + try { + Class clazz = Class.forName(driverName); + driver = (Driver) clazz.newInstance(); + } catch (Throwable e) { + throw new SQLException(e.getMessage()); + } + } + + // Open a new connection + Properties props = new Properties(); + if (connectionName != null) + props.put("user", connectionName); + if (connectionPassword != null) + props.put("password", connectionPassword); + dbConnection = driver.connect(connectionURL, props); + dbConnection.setAutoCommit(false); + return (dbConnection); + + } + + + /** + * Release our use of this connection so that it can be recycled. + * + * @param dbConnection The connection to be released + */ + protected void release(Connection dbConnection) { + + ; // NO-OP since we are not pooling anything + + } + + + /** + * Return a PreparedStatement configured to perform the SELECT required + * to retrieve user roles for the specified username. + * + * @param dbConnection The database connection to be used + * @param username Username for which roles should be retrieved + * + * @exception SQLException if a database error occurs + */ + protected PreparedStatement roles(Connection dbConnection, String username) + throws SQLException { + + if (preparedRoles == null) { + StringBuffer sb = new StringBuffer("SELECT "); + sb.append(roleNameCol); + sb.append(" FROM "); + sb.append(userRoleTable); + sb.append(" WHERE "); + sb.append(userNameCol); + sb.append(" = ?"); + preparedRoles = + dbConnection.prepareStatement(sb.toString()); + } + + preparedRoles.setString(1, username); + return (preparedRoles); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + // Validate that we can open our connection - but let tomcat + // startup in case the database is temporarily unavailable + try { + open(); + } catch (SQLException e) { + containerLog.error(sm.getString("jdbcRealm.open"), e); + } + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + // Close any open DB connection + close(this.dbConnection); + + } + + +} diff --git a/java/org/apache/catalina/realm/JNDIRealm.java b/java/org/apache/catalina/realm/JNDIRealm.java index ce6cb8f5d..ab1dcd937 100644 --- a/java/org/apache/catalina/realm/JNDIRealm.java +++ b/java/org/apache/catalina/realm/JNDIRealm.java @@ -1,1797 +1,1797 @@ -/* - * Copyright 1999-2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.realm; - -import java.io.IOException; -import java.security.Principal; -import java.text.MessageFormat; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Hashtable; -import java.util.List; - -import javax.naming.Context; -import javax.naming.CommunicationException; -import javax.naming.CompositeName; -import javax.naming.InvalidNameException; -import javax.naming.NameNotFoundException; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.NameParser; -import javax.naming.Name; -import javax.naming.AuthenticationException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.InitialDirContext; -import javax.naming.directory.SearchControls; -import javax.naming.directory.SearchResult; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.util.Base64; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; - -/** - *

    Implementation of Realm that works with a directory - * server accessed via the Java Naming and Directory Interface (JNDI) APIs. - * The following constraints are imposed on the data structure in the - * underlying directory server:

    - *
      - * - *
    • Each user that can be authenticated is represented by an individual - * element in the top level DirContext that is accessed - * via the connectionURL property.
    • - * - *
    • If a socket connection can not be made to the connectURL - * an attempt will be made to use the alternateURL if it - * exists.
    • - * - *
    • Each user element has a distinguished name that can be formed by - * substituting the presented username into a pattern configured by the - * userPattern property.
    • - * - *
    • Alternatively, if the userPattern property is not - * specified, a unique element can be located by searching the directory - * context. In this case: - *
        - *
      • The userSearch pattern specifies the search filter - * after substitution of the username.
      • - *
      • The userBase property can be set to the element that - * is the base of the subtree containing users. If not specified, - * the search base is the top-level context.
      • - *
      • The userSubtree property can be set to - * true if you wish to search the entire subtree of the - * directory context. The default value of false - * requests a search of only the current level.
      • - *
      - *
    • - * - *
    • The user may be authenticated by binding to the directory with the - * username and password presented. This method is used when the - * userPassword property is not specified.
    • - * - *
    • The user may be authenticated by retrieving the value of an attribute - * from the directory and comparing it explicitly with the value presented - * by the user. This method is used when the userPassword - * property is specified, in which case: - *
        - *
      • The element for this user must contain an attribute named by the - * userPassword property. - *
      • The value of the user password attribute is either a cleartext - * String, or the result of passing a cleartext String through the - * RealmBase.digest() method (using the standard digest - * support included in RealmBase). - *
      • The user is considered to be authenticated if the presented - * credentials (after being passed through - * RealmBase.digest()) are equal to the retrieved value - * for the user password attribute.
      • - *
    • - * - *
    • Each group of users that has been assigned a particular role may be - * represented by an individual element in the top level - * DirContext that is accessed via the - * connectionURL property. This element has the following - * characteristics: - *
        - *
      • The set of all possible groups of interest can be selected by a - * search pattern configured by the roleSearch - * property.
      • - *
      • The roleSearch pattern optionally includes pattern - * replacements "{0}" for the distinguished name, and/or "{1}" for - * the username, of the authenticated user for which roles will be - * retrieved.
      • - *
      • The roleBase property can be set to the element that - * is the base of the search for matching roles. If not specified, - * the entire context will be searched.
      • - *
      • The roleSubtree property can be set to - * true if you wish to search the entire subtree of the - * directory context. The default value of false - * requests a search of only the current level.
      • - *
      • The element includes an attribute (whose name is configured by - * the roleName property) containing the name of the - * role represented by this element.
      • - *
    • - * - *
    • In addition, roles may be represented by the values of an attribute - * in the user's element whose name is configured by the - * userRoleName property.
    • - * - *
    • Note that the standard <security-role-ref> element in - * the web application deployment descriptor allows applications to refer - * to roles programmatically by names other than those used in the - * directory server itself.
    • - *
    - * - *

    TODO - Support connection pooling (including message - * format objects) so that authenticate() does not have to be - * synchronized.

    - * - *

    WARNING - There is a reported bug against the Netscape - * provider code (com.netscape.jndi.ldap.LdapContextFactory) with respect to - * successfully authenticated a non-existing user. The - * report is here: http://issues.apache.org/bugzilla/show_bug.cgi?id=11210 . - * With luck, Netscape has updated their provider code and this is not an - * issue.

    - * - * @author John Holman - * @author Craig R. McClanahan - * @version $Revision: 373029 $ $Date: 2006-01-28 00:27:16 +0100 (sam., 28 janv. 2006) $ - */ - -public class JNDIRealm extends RealmBase { - - - // ----------------------------------------------------- Instance Variables - - /** - * The type of authentication to use - */ - protected String authentication = null; - - /** - * The connection username for the server we will contact. - */ - protected String connectionName = null; - - - /** - * The connection password for the server we will contact. - */ - protected String connectionPassword = null; - - - /** - * The connection URL for the server we will contact. - */ - protected String connectionURL = null; - - - /** - * The directory context linking us to our directory server. - */ - protected DirContext context = null; - - - /** - * The JNDI context factory used to acquire our InitialContext. By - * default, assumes use of an LDAP server using the standard JNDI LDAP - * provider. - */ - protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; - - - /** - * How aliases should be dereferenced during search operations. - */ - protected String derefAliases = null; - - /** - * Constant that holds the name of the environment property for specifying - * the manner in which aliases should be dereferenced. - */ - public final static String DEREF_ALIASES = "java.naming.ldap.derefAliases"; - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String info = - "org.apache.catalina.realm.JNDIRealm/1.0"; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String name = "JNDIRealm"; - - - /** - * The protocol that will be used in the communication with the - * directory server. - */ - protected String protocol = null; - - - /** - * How should we handle referrals? Microsoft Active Directory can't handle - * the default case, so an application authenticating against AD must - * set referrals to "follow". - */ - protected String referrals = null; - - - /** - * The base element for user searches. - */ - protected String userBase = ""; - - - /** - * The message format used to search for a user, with "{0}" marking - * the spot where the username goes. - */ - protected String userSearch = null; - - - /** - * The MessageFormat object associated with the current - * userSearch. - */ - protected MessageFormat userSearchFormat = null; - - - /** - * Should we search the entire subtree for matching users? - */ - protected boolean userSubtree = false; - - - /** - * The attribute name used to retrieve the user password. - */ - protected String userPassword = null; - - - /** - * A string of LDAP user patterns or paths, ":"-separated - * These will be used to form the distinguished name of a - * user, with "{0}" marking the spot where the specified username - * goes. - * This is similar to userPattern, but allows for multiple searches - * for a user. - */ - protected String[] userPatternArray = null; - - - /** - * The message format used to form the distinguished name of a - * user, with "{0}" marking the spot where the specified username - * goes. - */ - protected String userPattern = null; - - - /** - * An array of MessageFormat objects associated with the current - * userPatternArray. - */ - protected MessageFormat[] userPatternFormatArray = null; - - - /** - * The base element for role searches. - */ - protected String roleBase = ""; - - - /** - * The MessageFormat object associated with the current - * roleSearch. - */ - protected MessageFormat roleFormat = null; - - - /** - * The name of an attribute in the user's entry containing - * roles for that user - */ - protected String userRoleName = null; - - - /** - * The name of the attribute containing roles held elsewhere - */ - protected String roleName = null; - - - /** - * The message format used to select roles for a user, with "{0}" marking - * the spot where the distinguished name of the user goes. - */ - protected String roleSearch = null; - - - /** - * Should we search the entire subtree for matching memberships? - */ - protected boolean roleSubtree = false; - - /** - * An alternate URL, to which, we should connect if connectionURL fails. - */ - protected String alternateURL; - - /** - * The number of connection attempts. If greater than zero we use the - * alternate url. - */ - protected int connectionAttempt = 0; - - /** - * The current user pattern to be used for lookup and binding of a user. - */ - protected int curUserPattern = 0; - - // ------------------------------------------------------------- Properties - - /** - * Return the type of authentication to use. - */ - public String getAuthentication() { - - return authentication; - - } - - /** - * Set the type of authentication to use. - * - * @param authentication The authentication - */ - public void setAuthentication(String authentication) { - - this.authentication = authentication; - - } - - /** - * Return the connection username for this Realm. - */ - public String getConnectionName() { - - return (this.connectionName); - - } - - - /** - * Set the connection username for this Realm. - * - * @param connectionName The new connection username - */ - public void setConnectionName(String connectionName) { - - this.connectionName = connectionName; - - } - - - /** - * Return the connection password for this Realm. - */ - public String getConnectionPassword() { - - return (this.connectionPassword); - - } - - - /** - * Set the connection password for this Realm. - * - * @param connectionPassword The new connection password - */ - public void setConnectionPassword(String connectionPassword) { - - this.connectionPassword = connectionPassword; - - } - - - /** - * Return the connection URL for this Realm. - */ - public String getConnectionURL() { - - return (this.connectionURL); - - } - - - /** - * Set the connection URL for this Realm. - * - * @param connectionURL The new connection URL - */ - public void setConnectionURL(String connectionURL) { - - this.connectionURL = connectionURL; - - } - - - /** - * Return the JNDI context factory for this Realm. - */ - public String getContextFactory() { - - return (this.contextFactory); - - } - - - /** - * Set the JNDI context factory for this Realm. - * - * @param contextFactory The new context factory - */ - public void setContextFactory(String contextFactory) { - - this.contextFactory = contextFactory; - - } - - /** - * Return the derefAliases setting to be used. - */ - public java.lang.String getDerefAliases() { - return derefAliases; - } - - /** - * Set the value for derefAliases to be used when searching the directory. - * - * @param derefAliases New value of property derefAliases. - */ - public void setDerefAliases(java.lang.String derefAliases) { - this.derefAliases = derefAliases; - } - - /** - * Return the protocol to be used. - */ - public String getProtocol() { - - return protocol; - - } - - /** - * Set the protocol for this Realm. - * - * @param protocol The new protocol. - */ - public void setProtocol(String protocol) { - - this.protocol = protocol; - - } - - - /** - * Returns the current settings for handling JNDI referrals. - */ - public String getReferrals () { - return referrals; - } - - - /** - * How do we handle JNDI referrals? ignore, follow, or throw - * (see javax.naming.Context.REFERRAL for more information). - */ - public void setReferrals (String referrals) { - this.referrals = referrals; - } - - - /** - * Return the base element for user searches. - */ - public String getUserBase() { - - return (this.userBase); - - } - - - /** - * Set the base element for user searches. - * - * @param userBase The new base element - */ - public void setUserBase(String userBase) { - - this.userBase = userBase; - - } - - - /** - * Return the message format pattern for selecting users in this Realm. - */ - public String getUserSearch() { - - return (this.userSearch); - - } - - - /** - * Set the message format pattern for selecting users in this Realm. - * - * @param userSearch The new user search pattern - */ - public void setUserSearch(String userSearch) { - - this.userSearch = userSearch; - if (userSearch == null) - userSearchFormat = null; - else - userSearchFormat = new MessageFormat(userSearch); - - } - - - /** - * Return the "search subtree for users" flag. - */ - public boolean getUserSubtree() { - - return (this.userSubtree); - - } - - - /** - * Set the "search subtree for users" flag. - * - * @param userSubtree The new search flag - */ - public void setUserSubtree(boolean userSubtree) { - - this.userSubtree = userSubtree; - - } - - - /** - * Return the user role name attribute name for this Realm. - */ - public String getUserRoleName() { - - return userRoleName; - } - - - /** - * Set the user role name attribute name for this Realm. - * - * @param userRoleName The new userRole name attribute name - */ - public void setUserRoleName(String userRoleName) { - - this.userRoleName = userRoleName; - - } - - - /** - * Return the base element for role searches. - */ - public String getRoleBase() { - - return (this.roleBase); - - } - - - /** - * Set the base element for role searches. - * - * @param roleBase The new base element - */ - public void setRoleBase(String roleBase) { - - this.roleBase = roleBase; - - } - - - /** - * Return the role name attribute name for this Realm. - */ - public String getRoleName() { - - return (this.roleName); - - } - - - /** - * Set the role name attribute name for this Realm. - * - * @param roleName The new role name attribute name - */ - public void setRoleName(String roleName) { - - this.roleName = roleName; - - } - - - /** - * Return the message format pattern for selecting roles in this Realm. - */ - public String getRoleSearch() { - - return (this.roleSearch); - - } - - - /** - * Set the message format pattern for selecting roles in this Realm. - * - * @param roleSearch The new role search pattern - */ - public void setRoleSearch(String roleSearch) { - - this.roleSearch = roleSearch; - if (roleSearch == null) - roleFormat = null; - else - roleFormat = new MessageFormat(roleSearch); - - } - - - /** - * Return the "search subtree for roles" flag. - */ - public boolean getRoleSubtree() { - - return (this.roleSubtree); - - } - - - /** - * Set the "search subtree for roles" flag. - * - * @param roleSubtree The new search flag - */ - public void setRoleSubtree(boolean roleSubtree) { - - this.roleSubtree = roleSubtree; - - } - - - /** - * Return the password attribute used to retrieve the user password. - */ - public String getUserPassword() { - - return (this.userPassword); - - } - - - /** - * Set the password attribute used to retrieve the user password. - * - * @param userPassword The new password attribute - */ - public void setUserPassword(String userPassword) { - - this.userPassword = userPassword; - - } - - - /** - * Return the message format pattern for selecting users in this Realm. - */ - public String getUserPattern() { - - return (this.userPattern); - - } - - - /** - * Set the message format pattern for selecting users in this Realm. - * This may be one simple pattern, or multiple patterns to be tried, - * separated by parentheses. (for example, either "cn={0}", or - * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported, - * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is - * also valid. Complex search strings with &, etc are NOT supported. - * - * @param userPattern The new user pattern - */ - public void setUserPattern(String userPattern) { - - this.userPattern = userPattern; - if (userPattern == null) - userPatternArray = null; - else { - userPatternArray = parseUserPatternString(userPattern); - int len = this.userPatternArray.length; - userPatternFormatArray = new MessageFormat[len]; - for (int i=0; i < len; i++) { - userPatternFormatArray[i] = - new MessageFormat(userPatternArray[i]); - } - } - } - - - /** - * Getter for property alternateURL. - * - * @return Value of property alternateURL. - */ - public String getAlternateURL() { - - return this.alternateURL; - - } - - - /** - * Setter for property alternateURL. - * - * @param alternateURL New value of property alternateURL. - */ - public void setAlternateURL(String alternateURL) { - - this.alternateURL = alternateURL; - - } - - - // ---------------------------------------------------------- Realm Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * If there are any errors with the JDBC connection, executing - * the query or anything we return null (don't authenticate). This - * event is also logged, and the connection will be closed so that - * a subsequent request will automatically re-open it. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials) { - - DirContext context = null; - Principal principal = null; - - try { - - // Ensure that we have a directory context available - context = open(); - - // Occassionally the directory context will timeout. Try one more - // time before giving up. - try { - - // Authenticate the specified username if possible - principal = authenticate(context, username, credentials); - - } catch (CommunicationException e) { - - // log the exception so we know it's there. - containerLog.warn(sm.getString("jndiRealm.exception"), e); - - // close the connection so we know it will be reopened. - if (context != null) - close(context); - - // open a new directory context. - context = open(); - - // Try the authentication again. - principal = authenticate(context, username, credentials); - - } - - - // Release this context - release(context); - - // Return the authenticated Principal (if any) - return (principal); - - } catch (NamingException e) { - - // Log the problem for posterity - containerLog.error(sm.getString("jndiRealm.exception"), e); - - // Close the connection so that it gets reopened next time - if (context != null) - close(context); - - // Return "not authenticated" for this request - return (null); - - } - - } - - - // -------------------------------------------------------- Package Methods - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param context The directory context - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - * - * @exception NamingException if a directory server error occurs - */ - public synchronized Principal authenticate(DirContext context, - String username, - String credentials) - throws NamingException { - - if (username == null || username.equals("") - || credentials == null || credentials.equals("")) - return (null); - - if (userPatternArray != null) { - for (curUserPattern = 0; - curUserPattern < userPatternFormatArray.length; - curUserPattern++) { - // Retrieve user information - User user = getUser(context, username); - if (user != null) { - try { - // Check the user's credentials - if (checkCredentials(context, user, credentials)) { - // Search for additional roles - List roles = getRoles(context, user); - return (new GenericPrincipal(this, - username, - credentials, - roles)); - } - } catch (InvalidNameException ine) { - // Log the problem for posterity - containerLog.warn(sm.getString("jndiRealm.exception"), ine); - // ignore; this is probably due to a name not fitting - // the search path format exactly, as in a fully- - // qualified name being munged into a search path - // that already contains cn= or vice-versa - } - } - } - return null; - } else { - // Retrieve user information - User user = getUser(context, username); - if (user == null) - return (null); - - // Check the user's credentials - if (!checkCredentials(context, user, credentials)) - return (null); - - // Search for additional roles - List roles = getRoles(context, user); - - // Create and return a suitable Principal for this user - return (new GenericPrincipal(this, username, credentials, roles)); - } - } - - - /** - * Return a User object containing information about the user - * with the specified username, if found in the directory; - * otherwise return null. - * - * If the userPassword configuration attribute is - * specified, the value of that attribute is retrieved from the - * user's directory entry. If the userRoleName - * configuration attribute is specified, all values of that - * attribute are retrieved from the directory entry. - * - * @param context The directory context - * @param username Username to be looked up - * - * @exception NamingException if a directory server error occurs - */ - protected User getUser(DirContext context, String username) - throws NamingException { - - User user = null; - - // Get attributes to retrieve from user entry - ArrayList list = new ArrayList(); - if (userPassword != null) - list.add(userPassword); - if (userRoleName != null) - list.add(userRoleName); - String[] attrIds = new String[list.size()]; - list.toArray(attrIds); - - // Use pattern or search for user entry - if (userPatternFormatArray != null) { - user = getUserByPattern(context, username, attrIds); - } else { - user = getUserBySearch(context, username, attrIds); - } - - return user; - } - - - /** - * Use the UserPattern configuration attribute to - * locate the directory entry for the user with the specified - * username and return a User object; otherwise return - * null. - * - * @param context The directory context - * @param username The username - * @param attrIds String[]containing names of attributes to - * retrieve. - * - * @exception NamingException if a directory server error occurs - */ - protected User getUserByPattern(DirContext context, - String username, - String[] attrIds) - throws NamingException { - - if (username == null || userPatternFormatArray[curUserPattern] == null) - return (null); - - // Form the dn from the user pattern - String dn = userPatternFormatArray[curUserPattern].format(new String[] { username }); - - // Get required attributes from user entry - Attributes attrs = null; - try { - attrs = context.getAttributes(dn, attrIds); - } catch (NameNotFoundException e) { - return (null); - } - if (attrs == null) - return (null); - - // Retrieve value of userPassword - String password = null; - if (userPassword != null) - password = getAttributeValue(userPassword, attrs); - - // Retrieve values of userRoleName attribute - ArrayList roles = null; - if (userRoleName != null) - roles = addAttributeValues(userRoleName, attrs, roles); - - return new User(username, dn, password, roles); - } - - - /** - * Search the directory to return a User object containing - * information about the user with the specified username, if - * found in the directory; otherwise return null. - * - * @param context The directory context - * @param username The username - * @param attrIds String[]containing names of attributes to retrieve. - * - * @exception NamingException if a directory server error occurs - */ - protected User getUserBySearch(DirContext context, - String username, - String[] attrIds) - throws NamingException { - - if (username == null || userSearchFormat == null) - return (null); - - // Form the search filter - String filter = userSearchFormat.format(new String[] { username }); - - // Set up the search controls - SearchControls constraints = new SearchControls(); - - if (userSubtree) { - constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); - } - else { - constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE); - } - - // Specify the attributes to be retrieved - if (attrIds == null) - attrIds = new String[0]; - constraints.setReturningAttributes(attrIds); - - NamingEnumeration results = - context.search(userBase, filter, constraints); - - - // Fail if no entries found - if (results == null || !results.hasMore()) { - return (null); - } - - // Get result for the first entry found - SearchResult result = (SearchResult)results.next(); - - // Check no further entries were found - if (results.hasMore()) { - if(containerLog.isInfoEnabled()) - containerLog.info("username " + username + " has multiple entries"); - return (null); - } - - // Get the entry's distinguished name - NameParser parser = context.getNameParser(""); - Name contextName = parser.parse(context.getNameInNamespace()); - Name baseName = parser.parse(userBase); - - // Bugzilla 32269 - Name entryName = parser.parse(new CompositeName(result.getName()).get(0)); - - Name name = contextName.addAll(baseName); - name = name.addAll(entryName); - String dn = name.toString(); - - if (containerLog.isTraceEnabled()) - containerLog.trace(" entry found for " + username + " with dn " + dn); - - // Get the entry's attributes - Attributes attrs = result.getAttributes(); - if (attrs == null) - return null; - - // Retrieve value of userPassword - String password = null; - if (userPassword != null) - password = getAttributeValue(userPassword, attrs); - - // Retrieve values of userRoleName attribute - ArrayList roles = null; - if (userRoleName != null) - roles = addAttributeValues(userRoleName, attrs, roles); - - return new User(username, dn, password, roles); - } - - - /** - * Check whether the given User can be authenticated with the - * given credentials. If the userPassword - * configuration attribute is specified, the credentials - * previously retrieved from the directory are compared explicitly - * with those presented by the user. Otherwise the presented - * credentials are checked by binding to the directory as the - * user. - * - * @param context The directory context - * @param user The User to be authenticated - * @param credentials The credentials presented by the user - * - * @exception NamingException if a directory server error occurs - */ - protected boolean checkCredentials(DirContext context, - User user, - String credentials) - throws NamingException { - - boolean validated = false; - - if (userPassword == null) { - validated = bindAsUser(context, user, credentials); - } else { - validated = compareCredentials(context, user, credentials); - } - - if (containerLog.isTraceEnabled()) { - if (validated) { - containerLog.trace(sm.getString("jndiRealm.authenticateSuccess", - user.username)); - } else { - containerLog.trace(sm.getString("jndiRealm.authenticateFailure", - user.username)); - } - } - return (validated); - } - - - - /** - * Check whether the credentials presented by the user match those - * retrieved from the directory. - * - * @param context The directory context - * @param info The User to be authenticated - * @param credentials Authentication credentials - * - * @exception NamingException if a directory server error occurs - */ - protected boolean compareCredentials(DirContext context, - User info, - String credentials) - throws NamingException { - - if (info == null || credentials == null) - return (false); - - String password = info.password; - if (password == null) - return (false); - - // Validate the credentials specified by the user - if (containerLog.isTraceEnabled()) - containerLog.trace(" validating credentials"); - - boolean validated = false; - if (hasMessageDigest()) { - // iPlanet support if the values starts with {SHA1} - // The string is in a format compatible with Base64.encode not - // the Hex encoding of the parent class. - if (password.startsWith("{SHA}")) { - /* sync since super.digest() does this same thing */ - synchronized (this) { - password = password.substring(5); - md.reset(); - md.update(credentials.getBytes()); - String digestedPassword = - new String(Base64.encode(md.digest())); - validated = password.equals(digestedPassword); - } - } else if (password.startsWith("{SSHA}")) { - // Bugzilla 32938 - /* sync since super.digest() does this same thing */ - synchronized (this) { - password = password.substring(6); - - md.reset(); - md.update(credentials.getBytes()); - - // Decode stored password. - ByteChunk pwbc = new ByteChunk(password.length()); - try { - pwbc.append(password.getBytes(), 0, password.length()); - } catch (IOException e) { - // Should never happen - containerLog.error("Could not append password bytes to chunk: ", e); - } - - CharChunk decoded = new CharChunk(); - Base64.decode(pwbc, decoded); - char[] pwarray = decoded.getBuffer(); - - // Split decoded password into hash and salt. - final int saltpos = 20; - byte[] hash = new byte[saltpos]; - for (int i=0; i< hash.length; i++) { - hash[i] = (byte) pwarray[i]; - } - - byte[] salt = new byte[pwarray.length - saltpos]; - for (int i=0; i< salt.length; i++) - salt[i] = (byte)pwarray[i+saltpos]; - - md.update(salt); - byte[] dp = md.digest(); - - validated = Arrays.equals(dp, hash); - } // End synchronized(this) block - } else { - // Hex hashes should be compared case-insensitive - validated = (digest(credentials).equalsIgnoreCase(password)); - } - } else - validated = (digest(credentials).equals(password)); - return (validated); - - } - - - - /** - * Check credentials by binding to the directory as the user - * - * @param context The directory context - * @param user The User to be authenticated - * @param credentials Authentication credentials - * - * @exception NamingException if a directory server error occurs - */ - protected boolean bindAsUser(DirContext context, - User user, - String credentials) - throws NamingException { - Attributes attr; - - if (credentials == null || user == null) - return (false); - - String dn = user.dn; - if (dn == null) - return (false); - - // Validate the credentials specified by the user - if (containerLog.isTraceEnabled()) { - containerLog.trace(" validating credentials by binding as the user"); - } - - // Set up security environment to bind as the user - context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn); - context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials); - - // Elicit an LDAP bind operation - boolean validated = false; - try { - if (containerLog.isTraceEnabled()) { - containerLog.trace(" binding as " + dn); - } - attr = context.getAttributes("", null); - validated = true; - } - catch (AuthenticationException e) { - if (containerLog.isTraceEnabled()) { - containerLog.trace(" bind attempt failed"); - } - } - - // Restore the original security environment - if (connectionName != null) { - context.addToEnvironment(Context.SECURITY_PRINCIPAL, - connectionName); - } else { - context.removeFromEnvironment(Context.SECURITY_PRINCIPAL); - } - - if (connectionPassword != null) { - context.addToEnvironment(Context.SECURITY_CREDENTIALS, - connectionPassword); - } - else { - context.removeFromEnvironment(Context.SECURITY_CREDENTIALS); - } - - return (validated); - } - - - /** - * Return a List of roles associated with the given User. Any - * roles present in the user's directory entry are supplemented by - * a directory search. If no roles are associated with this user, - * a zero-length List is returned. - * - * @param context The directory context we are searching - * @param user The User to be checked - * - * @exception NamingException if a directory server error occurs - */ - protected List getRoles(DirContext context, User user) - throws NamingException { - - if (user == null) - return (null); - - String dn = user.dn; - String username = user.username; - - if (dn == null || username == null) - return (null); - - if (containerLog.isTraceEnabled()) - containerLog.trace(" getRoles(" + dn + ")"); - - // Start with roles retrieved from the user entry - ArrayList list = user.roles; - if (list == null) { - list = new ArrayList(); - } - - // Are we configured to do role searches? - if ((roleFormat == null) || (roleName == null)) - return (list); - - // Set up parameters for an appropriate search - String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username }); - SearchControls controls = new SearchControls(); - if (roleSubtree) - controls.setSearchScope(SearchControls.SUBTREE_SCOPE); - else - controls.setSearchScope(SearchControls.ONELEVEL_SCOPE); - controls.setReturningAttributes(new String[] {roleName}); - - // Perform the configured search and process the results - NamingEnumeration results = - context.search(roleBase, filter, controls); - if (results == null) - return (list); // Should never happen, but just in case ... - while (results.hasMore()) { - SearchResult result = (SearchResult) results.next(); - Attributes attrs = result.getAttributes(); - if (attrs == null) - continue; - list = addAttributeValues(roleName, attrs, list); - } - - - if (containerLog.isTraceEnabled()) { - if (list != null) { - containerLog.trace(" Returning " + list.size() + " roles"); - for (int i=0; i 0) - containerLog.debug("Connecting to URL " + alternateURL); - env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); - if (connectionName != null) - env.put(Context.SECURITY_PRINCIPAL, connectionName); - if (connectionPassword != null) - env.put(Context.SECURITY_CREDENTIALS, connectionPassword); - if (connectionURL != null && connectionAttempt == 0) - env.put(Context.PROVIDER_URL, connectionURL); - else if (alternateURL != null && connectionAttempt > 0) - env.put(Context.PROVIDER_URL, alternateURL); - if (authentication != null) - env.put(Context.SECURITY_AUTHENTICATION, authentication); - if (protocol != null) - env.put(Context.SECURITY_PROTOCOL, protocol); - if (referrals != null) - env.put(Context.REFERRAL, referrals); - if (derefAliases != null) - env.put(JNDIRealm.DEREF_ALIASES, derefAliases); - - return env; - - } - - - /** - * Release our use of this connection so that it can be recycled. - * - * @param context The directory context to release - */ - protected void release(DirContext context) { - - ; // NO-OP since we are not pooling anything - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - // Validate that we can open our connection - try { - open(); - } catch (NamingException e) { - throw new LifecycleException(sm.getString("jndiRealm.open"), e); - } - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - // Close any open directory server connection - close(this.context); - - } - - /** - * Given a string containing LDAP patterns for user locations (separated by - * parentheses in a pseudo-LDAP search string format - - * "(location1)(location2)", returns an array of those paths. Real LDAP - * search strings are supported as well (though only the "|" "OR" type). - * - * @param userPatternString - a string LDAP search paths surrounded by - * parentheses - */ - protected String[] parseUserPatternString(String userPatternString) { - - if (userPatternString != null) { - ArrayList pathList = new ArrayList(); - int startParenLoc = userPatternString.indexOf('('); - if (startParenLoc == -1) { - // no parens here; return whole thing - return new String[] {userPatternString}; - } - int startingPoint = 0; - while (startParenLoc > -1) { - int endParenLoc = 0; - // weed out escaped open parens and parens enclosing the - // whole statement (in the case of valid LDAP search - // strings: (|(something)(somethingelse)) - while ( (userPatternString.charAt(startParenLoc + 1) == '|') || - (startParenLoc != 0 && userPatternString.charAt(startParenLoc - 1) == '\\') ) { - startParenLoc = userPatternString.indexOf("(", startParenLoc+1); - } - endParenLoc = userPatternString.indexOf(")", startParenLoc+1); - // weed out escaped end-parens - while (userPatternString.charAt(endParenLoc - 1) == '\\') { - endParenLoc = userPatternString.indexOf(")", endParenLoc+1); - } - String nextPathPart = userPatternString.substring - (startParenLoc+1, endParenLoc); - pathList.add(nextPathPart); - startingPoint = endParenLoc+1; - startParenLoc = userPatternString.indexOf('(', startingPoint); - } - return (String[])pathList.toArray(new String[] {}); - } - return null; - - } - - - /** - * Given an LDAP search string, returns the string with certain characters - * escaped according to RFC 2254 guidelines. - * The character mapping is as follows: - * char -> Replacement - * --------------------------- - * * -> \2a - * ( -> \28 - * ) -> \29 - * \ -> \5c - * \0 -> \00 - * @param inString string to escape according to RFC 2254 guidelines - * @return String the escaped/encoded result - */ - protected String doRFC2254Encoding(String inString) { - StringBuffer buf = new StringBuffer(inString.length()); - for (int i = 0; i < inString.length(); i++) { - char c = inString.charAt(i); - switch (c) { - case '\\': - buf.append("\\5c"); - break; - case '*': - buf.append("\\2a"); - break; - case '(': - buf.append("\\28"); - break; - case ')': - buf.append("\\29"); - break; - case '\0': - buf.append("\\00"); - break; - default: - buf.append(c); - break; - } - } - return buf.toString(); - } - - -} - -// ------------------------------------------------------ Private Classes - -/** - * A private class representing a User - */ -class User { - String username = null; - String dn = null; - String password = null; - ArrayList roles = null; - - - User(String username, String dn, String password, ArrayList roles) { - this.username = username; - this.dn = dn; - this.password = password; - this.roles = roles; - } - -} +/* + * Copyright 1999-2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.realm; + +import java.io.IOException; +import java.security.Principal; +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Hashtable; +import java.util.List; + +import javax.naming.Context; +import javax.naming.CommunicationException; +import javax.naming.CompositeName; +import javax.naming.InvalidNameException; +import javax.naming.NameNotFoundException; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.NameParser; +import javax.naming.Name; +import javax.naming.AuthenticationException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.InitialDirContext; +import javax.naming.directory.SearchControls; +import javax.naming.directory.SearchResult; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.util.Base64; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; + +/** + *

    Implementation of Realm that works with a directory + * server accessed via the Java Naming and Directory Interface (JNDI) APIs. + * The following constraints are imposed on the data structure in the + * underlying directory server:

    + *
      + * + *
    • Each user that can be authenticated is represented by an individual + * element in the top level DirContext that is accessed + * via the connectionURL property.
    • + * + *
    • If a socket connection can not be made to the connectURL + * an attempt will be made to use the alternateURL if it + * exists.
    • + * + *
    • Each user element has a distinguished name that can be formed by + * substituting the presented username into a pattern configured by the + * userPattern property.
    • + * + *
    • Alternatively, if the userPattern property is not + * specified, a unique element can be located by searching the directory + * context. In this case: + *
        + *
      • The userSearch pattern specifies the search filter + * after substitution of the username.
      • + *
      • The userBase property can be set to the element that + * is the base of the subtree containing users. If not specified, + * the search base is the top-level context.
      • + *
      • The userSubtree property can be set to + * true if you wish to search the entire subtree of the + * directory context. The default value of false + * requests a search of only the current level.
      • + *
      + *
    • + * + *
    • The user may be authenticated by binding to the directory with the + * username and password presented. This method is used when the + * userPassword property is not specified.
    • + * + *
    • The user may be authenticated by retrieving the value of an attribute + * from the directory and comparing it explicitly with the value presented + * by the user. This method is used when the userPassword + * property is specified, in which case: + *
        + *
      • The element for this user must contain an attribute named by the + * userPassword property. + *
      • The value of the user password attribute is either a cleartext + * String, or the result of passing a cleartext String through the + * RealmBase.digest() method (using the standard digest + * support included in RealmBase). + *
      • The user is considered to be authenticated if the presented + * credentials (after being passed through + * RealmBase.digest()) are equal to the retrieved value + * for the user password attribute.
      • + *
    • + * + *
    • Each group of users that has been assigned a particular role may be + * represented by an individual element in the top level + * DirContext that is accessed via the + * connectionURL property. This element has the following + * characteristics: + *
        + *
      • The set of all possible groups of interest can be selected by a + * search pattern configured by the roleSearch + * property.
      • + *
      • The roleSearch pattern optionally includes pattern + * replacements "{0}" for the distinguished name, and/or "{1}" for + * the username, of the authenticated user for which roles will be + * retrieved.
      • + *
      • The roleBase property can be set to the element that + * is the base of the search for matching roles. If not specified, + * the entire context will be searched.
      • + *
      • The roleSubtree property can be set to + * true if you wish to search the entire subtree of the + * directory context. The default value of false + * requests a search of only the current level.
      • + *
      • The element includes an attribute (whose name is configured by + * the roleName property) containing the name of the + * role represented by this element.
      • + *
    • + * + *
    • In addition, roles may be represented by the values of an attribute + * in the user's element whose name is configured by the + * userRoleName property.
    • + * + *
    • Note that the standard <security-role-ref> element in + * the web application deployment descriptor allows applications to refer + * to roles programmatically by names other than those used in the + * directory server itself.
    • + *
    + * + *

    TODO - Support connection pooling (including message + * format objects) so that authenticate() does not have to be + * synchronized.

    + * + *

    WARNING - There is a reported bug against the Netscape + * provider code (com.netscape.jndi.ldap.LdapContextFactory) with respect to + * successfully authenticated a non-existing user. The + * report is here: http://issues.apache.org/bugzilla/show_bug.cgi?id=11210 . + * With luck, Netscape has updated their provider code and this is not an + * issue.

    + * + * @author John Holman + * @author Craig R. McClanahan + * @version $Revision: 373029 $ $Date: 2006-01-28 00:27:16 +0100 (sam., 28 janv. 2006) $ + */ + +public class JNDIRealm extends RealmBase { + + + // ----------------------------------------------------- Instance Variables + + /** + * The type of authentication to use + */ + protected String authentication = null; + + /** + * The connection username for the server we will contact. + */ + protected String connectionName = null; + + + /** + * The connection password for the server we will contact. + */ + protected String connectionPassword = null; + + + /** + * The connection URL for the server we will contact. + */ + protected String connectionURL = null; + + + /** + * The directory context linking us to our directory server. + */ + protected DirContext context = null; + + + /** + * The JNDI context factory used to acquire our InitialContext. By + * default, assumes use of an LDAP server using the standard JNDI LDAP + * provider. + */ + protected String contextFactory = "com.sun.jndi.ldap.LdapCtxFactory"; + + + /** + * How aliases should be dereferenced during search operations. + */ + protected String derefAliases = null; + + /** + * Constant that holds the name of the environment property for specifying + * the manner in which aliases should be dereferenced. + */ + public final static String DEREF_ALIASES = "java.naming.ldap.derefAliases"; + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String info = + "org.apache.catalina.realm.JNDIRealm/1.0"; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String name = "JNDIRealm"; + + + /** + * The protocol that will be used in the communication with the + * directory server. + */ + protected String protocol = null; + + + /** + * How should we handle referrals? Microsoft Active Directory can't handle + * the default case, so an application authenticating against AD must + * set referrals to "follow". + */ + protected String referrals = null; + + + /** + * The base element for user searches. + */ + protected String userBase = ""; + + + /** + * The message format used to search for a user, with "{0}" marking + * the spot where the username goes. + */ + protected String userSearch = null; + + + /** + * The MessageFormat object associated with the current + * userSearch. + */ + protected MessageFormat userSearchFormat = null; + + + /** + * Should we search the entire subtree for matching users? + */ + protected boolean userSubtree = false; + + + /** + * The attribute name used to retrieve the user password. + */ + protected String userPassword = null; + + + /** + * A string of LDAP user patterns or paths, ":"-separated + * These will be used to form the distinguished name of a + * user, with "{0}" marking the spot where the specified username + * goes. + * This is similar to userPattern, but allows for multiple searches + * for a user. + */ + protected String[] userPatternArray = null; + + + /** + * The message format used to form the distinguished name of a + * user, with "{0}" marking the spot where the specified username + * goes. + */ + protected String userPattern = null; + + + /** + * An array of MessageFormat objects associated with the current + * userPatternArray. + */ + protected MessageFormat[] userPatternFormatArray = null; + + + /** + * The base element for role searches. + */ + protected String roleBase = ""; + + + /** + * The MessageFormat object associated with the current + * roleSearch. + */ + protected MessageFormat roleFormat = null; + + + /** + * The name of an attribute in the user's entry containing + * roles for that user + */ + protected String userRoleName = null; + + + /** + * The name of the attribute containing roles held elsewhere + */ + protected String roleName = null; + + + /** + * The message format used to select roles for a user, with "{0}" marking + * the spot where the distinguished name of the user goes. + */ + protected String roleSearch = null; + + + /** + * Should we search the entire subtree for matching memberships? + */ + protected boolean roleSubtree = false; + + /** + * An alternate URL, to which, we should connect if connectionURL fails. + */ + protected String alternateURL; + + /** + * The number of connection attempts. If greater than zero we use the + * alternate url. + */ + protected int connectionAttempt = 0; + + /** + * The current user pattern to be used for lookup and binding of a user. + */ + protected int curUserPattern = 0; + + // ------------------------------------------------------------- Properties + + /** + * Return the type of authentication to use. + */ + public String getAuthentication() { + + return authentication; + + } + + /** + * Set the type of authentication to use. + * + * @param authentication The authentication + */ + public void setAuthentication(String authentication) { + + this.authentication = authentication; + + } + + /** + * Return the connection username for this Realm. + */ + public String getConnectionName() { + + return (this.connectionName); + + } + + + /** + * Set the connection username for this Realm. + * + * @param connectionName The new connection username + */ + public void setConnectionName(String connectionName) { + + this.connectionName = connectionName; + + } + + + /** + * Return the connection password for this Realm. + */ + public String getConnectionPassword() { + + return (this.connectionPassword); + + } + + + /** + * Set the connection password for this Realm. + * + * @param connectionPassword The new connection password + */ + public void setConnectionPassword(String connectionPassword) { + + this.connectionPassword = connectionPassword; + + } + + + /** + * Return the connection URL for this Realm. + */ + public String getConnectionURL() { + + return (this.connectionURL); + + } + + + /** + * Set the connection URL for this Realm. + * + * @param connectionURL The new connection URL + */ + public void setConnectionURL(String connectionURL) { + + this.connectionURL = connectionURL; + + } + + + /** + * Return the JNDI context factory for this Realm. + */ + public String getContextFactory() { + + return (this.contextFactory); + + } + + + /** + * Set the JNDI context factory for this Realm. + * + * @param contextFactory The new context factory + */ + public void setContextFactory(String contextFactory) { + + this.contextFactory = contextFactory; + + } + + /** + * Return the derefAliases setting to be used. + */ + public java.lang.String getDerefAliases() { + return derefAliases; + } + + /** + * Set the value for derefAliases to be used when searching the directory. + * + * @param derefAliases New value of property derefAliases. + */ + public void setDerefAliases(java.lang.String derefAliases) { + this.derefAliases = derefAliases; + } + + /** + * Return the protocol to be used. + */ + public String getProtocol() { + + return protocol; + + } + + /** + * Set the protocol for this Realm. + * + * @param protocol The new protocol. + */ + public void setProtocol(String protocol) { + + this.protocol = protocol; + + } + + + /** + * Returns the current settings for handling JNDI referrals. + */ + public String getReferrals () { + return referrals; + } + + + /** + * How do we handle JNDI referrals? ignore, follow, or throw + * (see javax.naming.Context.REFERRAL for more information). + */ + public void setReferrals (String referrals) { + this.referrals = referrals; + } + + + /** + * Return the base element for user searches. + */ + public String getUserBase() { + + return (this.userBase); + + } + + + /** + * Set the base element for user searches. + * + * @param userBase The new base element + */ + public void setUserBase(String userBase) { + + this.userBase = userBase; + + } + + + /** + * Return the message format pattern for selecting users in this Realm. + */ + public String getUserSearch() { + + return (this.userSearch); + + } + + + /** + * Set the message format pattern for selecting users in this Realm. + * + * @param userSearch The new user search pattern + */ + public void setUserSearch(String userSearch) { + + this.userSearch = userSearch; + if (userSearch == null) + userSearchFormat = null; + else + userSearchFormat = new MessageFormat(userSearch); + + } + + + /** + * Return the "search subtree for users" flag. + */ + public boolean getUserSubtree() { + + return (this.userSubtree); + + } + + + /** + * Set the "search subtree for users" flag. + * + * @param userSubtree The new search flag + */ + public void setUserSubtree(boolean userSubtree) { + + this.userSubtree = userSubtree; + + } + + + /** + * Return the user role name attribute name for this Realm. + */ + public String getUserRoleName() { + + return userRoleName; + } + + + /** + * Set the user role name attribute name for this Realm. + * + * @param userRoleName The new userRole name attribute name + */ + public void setUserRoleName(String userRoleName) { + + this.userRoleName = userRoleName; + + } + + + /** + * Return the base element for role searches. + */ + public String getRoleBase() { + + return (this.roleBase); + + } + + + /** + * Set the base element for role searches. + * + * @param roleBase The new base element + */ + public void setRoleBase(String roleBase) { + + this.roleBase = roleBase; + + } + + + /** + * Return the role name attribute name for this Realm. + */ + public String getRoleName() { + + return (this.roleName); + + } + + + /** + * Set the role name attribute name for this Realm. + * + * @param roleName The new role name attribute name + */ + public void setRoleName(String roleName) { + + this.roleName = roleName; + + } + + + /** + * Return the message format pattern for selecting roles in this Realm. + */ + public String getRoleSearch() { + + return (this.roleSearch); + + } + + + /** + * Set the message format pattern for selecting roles in this Realm. + * + * @param roleSearch The new role search pattern + */ + public void setRoleSearch(String roleSearch) { + + this.roleSearch = roleSearch; + if (roleSearch == null) + roleFormat = null; + else + roleFormat = new MessageFormat(roleSearch); + + } + + + /** + * Return the "search subtree for roles" flag. + */ + public boolean getRoleSubtree() { + + return (this.roleSubtree); + + } + + + /** + * Set the "search subtree for roles" flag. + * + * @param roleSubtree The new search flag + */ + public void setRoleSubtree(boolean roleSubtree) { + + this.roleSubtree = roleSubtree; + + } + + + /** + * Return the password attribute used to retrieve the user password. + */ + public String getUserPassword() { + + return (this.userPassword); + + } + + + /** + * Set the password attribute used to retrieve the user password. + * + * @param userPassword The new password attribute + */ + public void setUserPassword(String userPassword) { + + this.userPassword = userPassword; + + } + + + /** + * Return the message format pattern for selecting users in this Realm. + */ + public String getUserPattern() { + + return (this.userPattern); + + } + + + /** + * Set the message format pattern for selecting users in this Realm. + * This may be one simple pattern, or multiple patterns to be tried, + * separated by parentheses. (for example, either "cn={0}", or + * "(cn={0})(cn={0},o=myorg)" Full LDAP search strings are also supported, + * but only the "OR", "|" syntax, so "(|(cn={0})(cn={0},o=myorg))" is + * also valid. Complex search strings with &, etc are NOT supported. + * + * @param userPattern The new user pattern + */ + public void setUserPattern(String userPattern) { + + this.userPattern = userPattern; + if (userPattern == null) + userPatternArray = null; + else { + userPatternArray = parseUserPatternString(userPattern); + int len = this.userPatternArray.length; + userPatternFormatArray = new MessageFormat[len]; + for (int i=0; i < len; i++) { + userPatternFormatArray[i] = + new MessageFormat(userPatternArray[i]); + } + } + } + + + /** + * Getter for property alternateURL. + * + * @return Value of property alternateURL. + */ + public String getAlternateURL() { + + return this.alternateURL; + + } + + + /** + * Setter for property alternateURL. + * + * @param alternateURL New value of property alternateURL. + */ + public void setAlternateURL(String alternateURL) { + + this.alternateURL = alternateURL; + + } + + + // ---------------------------------------------------------- Realm Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * If there are any errors with the JDBC connection, executing + * the query or anything we return null (don't authenticate). This + * event is also logged, and the connection will be closed so that + * a subsequent request will automatically re-open it. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials) { + + DirContext context = null; + Principal principal = null; + + try { + + // Ensure that we have a directory context available + context = open(); + + // Occassionally the directory context will timeout. Try one more + // time before giving up. + try { + + // Authenticate the specified username if possible + principal = authenticate(context, username, credentials); + + } catch (CommunicationException e) { + + // log the exception so we know it's there. + containerLog.warn(sm.getString("jndiRealm.exception"), e); + + // close the connection so we know it will be reopened. + if (context != null) + close(context); + + // open a new directory context. + context = open(); + + // Try the authentication again. + principal = authenticate(context, username, credentials); + + } + + + // Release this context + release(context); + + // Return the authenticated Principal (if any) + return (principal); + + } catch (NamingException e) { + + // Log the problem for posterity + containerLog.error(sm.getString("jndiRealm.exception"), e); + + // Close the connection so that it gets reopened next time + if (context != null) + close(context); + + // Return "not authenticated" for this request + return (null); + + } + + } + + + // -------------------------------------------------------- Package Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param context The directory context + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + * + * @exception NamingException if a directory server error occurs + */ + public synchronized Principal authenticate(DirContext context, + String username, + String credentials) + throws NamingException { + + if (username == null || username.equals("") + || credentials == null || credentials.equals("")) + return (null); + + if (userPatternArray != null) { + for (curUserPattern = 0; + curUserPattern < userPatternFormatArray.length; + curUserPattern++) { + // Retrieve user information + User user = getUser(context, username); + if (user != null) { + try { + // Check the user's credentials + if (checkCredentials(context, user, credentials)) { + // Search for additional roles + List roles = getRoles(context, user); + return (new GenericPrincipal(this, + username, + credentials, + roles)); + } + } catch (InvalidNameException ine) { + // Log the problem for posterity + containerLog.warn(sm.getString("jndiRealm.exception"), ine); + // ignore; this is probably due to a name not fitting + // the search path format exactly, as in a fully- + // qualified name being munged into a search path + // that already contains cn= or vice-versa + } + } + } + return null; + } else { + // Retrieve user information + User user = getUser(context, username); + if (user == null) + return (null); + + // Check the user's credentials + if (!checkCredentials(context, user, credentials)) + return (null); + + // Search for additional roles + List roles = getRoles(context, user); + + // Create and return a suitable Principal for this user + return (new GenericPrincipal(this, username, credentials, roles)); + } + } + + + /** + * Return a User object containing information about the user + * with the specified username, if found in the directory; + * otherwise return null. + * + * If the userPassword configuration attribute is + * specified, the value of that attribute is retrieved from the + * user's directory entry. If the userRoleName + * configuration attribute is specified, all values of that + * attribute are retrieved from the directory entry. + * + * @param context The directory context + * @param username Username to be looked up + * + * @exception NamingException if a directory server error occurs + */ + protected User getUser(DirContext context, String username) + throws NamingException { + + User user = null; + + // Get attributes to retrieve from user entry + ArrayList list = new ArrayList(); + if (userPassword != null) + list.add(userPassword); + if (userRoleName != null) + list.add(userRoleName); + String[] attrIds = new String[list.size()]; + list.toArray(attrIds); + + // Use pattern or search for user entry + if (userPatternFormatArray != null) { + user = getUserByPattern(context, username, attrIds); + } else { + user = getUserBySearch(context, username, attrIds); + } + + return user; + } + + + /** + * Use the UserPattern configuration attribute to + * locate the directory entry for the user with the specified + * username and return a User object; otherwise return + * null. + * + * @param context The directory context + * @param username The username + * @param attrIds String[]containing names of attributes to + * retrieve. + * + * @exception NamingException if a directory server error occurs + */ + protected User getUserByPattern(DirContext context, + String username, + String[] attrIds) + throws NamingException { + + if (username == null || userPatternFormatArray[curUserPattern] == null) + return (null); + + // Form the dn from the user pattern + String dn = userPatternFormatArray[curUserPattern].format(new String[] { username }); + + // Get required attributes from user entry + Attributes attrs = null; + try { + attrs = context.getAttributes(dn, attrIds); + } catch (NameNotFoundException e) { + return (null); + } + if (attrs == null) + return (null); + + // Retrieve value of userPassword + String password = null; + if (userPassword != null) + password = getAttributeValue(userPassword, attrs); + + // Retrieve values of userRoleName attribute + ArrayList roles = null; + if (userRoleName != null) + roles = addAttributeValues(userRoleName, attrs, roles); + + return new User(username, dn, password, roles); + } + + + /** + * Search the directory to return a User object containing + * information about the user with the specified username, if + * found in the directory; otherwise return null. + * + * @param context The directory context + * @param username The username + * @param attrIds String[]containing names of attributes to retrieve. + * + * @exception NamingException if a directory server error occurs + */ + protected User getUserBySearch(DirContext context, + String username, + String[] attrIds) + throws NamingException { + + if (username == null || userSearchFormat == null) + return (null); + + // Form the search filter + String filter = userSearchFormat.format(new String[] { username }); + + // Set up the search controls + SearchControls constraints = new SearchControls(); + + if (userSubtree) { + constraints.setSearchScope(SearchControls.SUBTREE_SCOPE); + } + else { + constraints.setSearchScope(SearchControls.ONELEVEL_SCOPE); + } + + // Specify the attributes to be retrieved + if (attrIds == null) + attrIds = new String[0]; + constraints.setReturningAttributes(attrIds); + + NamingEnumeration results = + context.search(userBase, filter, constraints); + + + // Fail if no entries found + if (results == null || !results.hasMore()) { + return (null); + } + + // Get result for the first entry found + SearchResult result = (SearchResult)results.next(); + + // Check no further entries were found + if (results.hasMore()) { + if(containerLog.isInfoEnabled()) + containerLog.info("username " + username + " has multiple entries"); + return (null); + } + + // Get the entry's distinguished name + NameParser parser = context.getNameParser(""); + Name contextName = parser.parse(context.getNameInNamespace()); + Name baseName = parser.parse(userBase); + + // Bugzilla 32269 + Name entryName = parser.parse(new CompositeName(result.getName()).get(0)); + + Name name = contextName.addAll(baseName); + name = name.addAll(entryName); + String dn = name.toString(); + + if (containerLog.isTraceEnabled()) + containerLog.trace(" entry found for " + username + " with dn " + dn); + + // Get the entry's attributes + Attributes attrs = result.getAttributes(); + if (attrs == null) + return null; + + // Retrieve value of userPassword + String password = null; + if (userPassword != null) + password = getAttributeValue(userPassword, attrs); + + // Retrieve values of userRoleName attribute + ArrayList roles = null; + if (userRoleName != null) + roles = addAttributeValues(userRoleName, attrs, roles); + + return new User(username, dn, password, roles); + } + + + /** + * Check whether the given User can be authenticated with the + * given credentials. If the userPassword + * configuration attribute is specified, the credentials + * previously retrieved from the directory are compared explicitly + * with those presented by the user. Otherwise the presented + * credentials are checked by binding to the directory as the + * user. + * + * @param context The directory context + * @param user The User to be authenticated + * @param credentials The credentials presented by the user + * + * @exception NamingException if a directory server error occurs + */ + protected boolean checkCredentials(DirContext context, + User user, + String credentials) + throws NamingException { + + boolean validated = false; + + if (userPassword == null) { + validated = bindAsUser(context, user, credentials); + } else { + validated = compareCredentials(context, user, credentials); + } + + if (containerLog.isTraceEnabled()) { + if (validated) { + containerLog.trace(sm.getString("jndiRealm.authenticateSuccess", + user.username)); + } else { + containerLog.trace(sm.getString("jndiRealm.authenticateFailure", + user.username)); + } + } + return (validated); + } + + + + /** + * Check whether the credentials presented by the user match those + * retrieved from the directory. + * + * @param context The directory context + * @param info The User to be authenticated + * @param credentials Authentication credentials + * + * @exception NamingException if a directory server error occurs + */ + protected boolean compareCredentials(DirContext context, + User info, + String credentials) + throws NamingException { + + if (info == null || credentials == null) + return (false); + + String password = info.password; + if (password == null) + return (false); + + // Validate the credentials specified by the user + if (containerLog.isTraceEnabled()) + containerLog.trace(" validating credentials"); + + boolean validated = false; + if (hasMessageDigest()) { + // iPlanet support if the values starts with {SHA1} + // The string is in a format compatible with Base64.encode not + // the Hex encoding of the parent class. + if (password.startsWith("{SHA}")) { + /* sync since super.digest() does this same thing */ + synchronized (this) { + password = password.substring(5); + md.reset(); + md.update(credentials.getBytes()); + String digestedPassword = + new String(Base64.encode(md.digest())); + validated = password.equals(digestedPassword); + } + } else if (password.startsWith("{SSHA}")) { + // Bugzilla 32938 + /* sync since super.digest() does this same thing */ + synchronized (this) { + password = password.substring(6); + + md.reset(); + md.update(credentials.getBytes()); + + // Decode stored password. + ByteChunk pwbc = new ByteChunk(password.length()); + try { + pwbc.append(password.getBytes(), 0, password.length()); + } catch (IOException e) { + // Should never happen + containerLog.error("Could not append password bytes to chunk: ", e); + } + + CharChunk decoded = new CharChunk(); + Base64.decode(pwbc, decoded); + char[] pwarray = decoded.getBuffer(); + + // Split decoded password into hash and salt. + final int saltpos = 20; + byte[] hash = new byte[saltpos]; + for (int i=0; i< hash.length; i++) { + hash[i] = (byte) pwarray[i]; + } + + byte[] salt = new byte[pwarray.length - saltpos]; + for (int i=0; i< salt.length; i++) + salt[i] = (byte)pwarray[i+saltpos]; + + md.update(salt); + byte[] dp = md.digest(); + + validated = Arrays.equals(dp, hash); + } // End synchronized(this) block + } else { + // Hex hashes should be compared case-insensitive + validated = (digest(credentials).equalsIgnoreCase(password)); + } + } else + validated = (digest(credentials).equals(password)); + return (validated); + + } + + + + /** + * Check credentials by binding to the directory as the user + * + * @param context The directory context + * @param user The User to be authenticated + * @param credentials Authentication credentials + * + * @exception NamingException if a directory server error occurs + */ + protected boolean bindAsUser(DirContext context, + User user, + String credentials) + throws NamingException { + Attributes attr; + + if (credentials == null || user == null) + return (false); + + String dn = user.dn; + if (dn == null) + return (false); + + // Validate the credentials specified by the user + if (containerLog.isTraceEnabled()) { + containerLog.trace(" validating credentials by binding as the user"); + } + + // Set up security environment to bind as the user + context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn); + context.addToEnvironment(Context.SECURITY_CREDENTIALS, credentials); + + // Elicit an LDAP bind operation + boolean validated = false; + try { + if (containerLog.isTraceEnabled()) { + containerLog.trace(" binding as " + dn); + } + attr = context.getAttributes("", null); + validated = true; + } + catch (AuthenticationException e) { + if (containerLog.isTraceEnabled()) { + containerLog.trace(" bind attempt failed"); + } + } + + // Restore the original security environment + if (connectionName != null) { + context.addToEnvironment(Context.SECURITY_PRINCIPAL, + connectionName); + } else { + context.removeFromEnvironment(Context.SECURITY_PRINCIPAL); + } + + if (connectionPassword != null) { + context.addToEnvironment(Context.SECURITY_CREDENTIALS, + connectionPassword); + } + else { + context.removeFromEnvironment(Context.SECURITY_CREDENTIALS); + } + + return (validated); + } + + + /** + * Return a List of roles associated with the given User. Any + * roles present in the user's directory entry are supplemented by + * a directory search. If no roles are associated with this user, + * a zero-length List is returned. + * + * @param context The directory context we are searching + * @param user The User to be checked + * + * @exception NamingException if a directory server error occurs + */ + protected List getRoles(DirContext context, User user) + throws NamingException { + + if (user == null) + return (null); + + String dn = user.dn; + String username = user.username; + + if (dn == null || username == null) + return (null); + + if (containerLog.isTraceEnabled()) + containerLog.trace(" getRoles(" + dn + ")"); + + // Start with roles retrieved from the user entry + ArrayList list = user.roles; + if (list == null) { + list = new ArrayList(); + } + + // Are we configured to do role searches? + if ((roleFormat == null) || (roleName == null)) + return (list); + + // Set up parameters for an appropriate search + String filter = roleFormat.format(new String[] { doRFC2254Encoding(dn), username }); + SearchControls controls = new SearchControls(); + if (roleSubtree) + controls.setSearchScope(SearchControls.SUBTREE_SCOPE); + else + controls.setSearchScope(SearchControls.ONELEVEL_SCOPE); + controls.setReturningAttributes(new String[] {roleName}); + + // Perform the configured search and process the results + NamingEnumeration results = + context.search(roleBase, filter, controls); + if (results == null) + return (list); // Should never happen, but just in case ... + while (results.hasMore()) { + SearchResult result = (SearchResult) results.next(); + Attributes attrs = result.getAttributes(); + if (attrs == null) + continue; + list = addAttributeValues(roleName, attrs, list); + } + + + if (containerLog.isTraceEnabled()) { + if (list != null) { + containerLog.trace(" Returning " + list.size() + " roles"); + for (int i=0; i 0) + containerLog.debug("Connecting to URL " + alternateURL); + env.put(Context.INITIAL_CONTEXT_FACTORY, contextFactory); + if (connectionName != null) + env.put(Context.SECURITY_PRINCIPAL, connectionName); + if (connectionPassword != null) + env.put(Context.SECURITY_CREDENTIALS, connectionPassword); + if (connectionURL != null && connectionAttempt == 0) + env.put(Context.PROVIDER_URL, connectionURL); + else if (alternateURL != null && connectionAttempt > 0) + env.put(Context.PROVIDER_URL, alternateURL); + if (authentication != null) + env.put(Context.SECURITY_AUTHENTICATION, authentication); + if (protocol != null) + env.put(Context.SECURITY_PROTOCOL, protocol); + if (referrals != null) + env.put(Context.REFERRAL, referrals); + if (derefAliases != null) + env.put(JNDIRealm.DEREF_ALIASES, derefAliases); + + return env; + + } + + + /** + * Release our use of this connection so that it can be recycled. + * + * @param context The directory context to release + */ + protected void release(DirContext context) { + + ; // NO-OP since we are not pooling anything + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + // Validate that we can open our connection + try { + open(); + } catch (NamingException e) { + throw new LifecycleException(sm.getString("jndiRealm.open"), e); + } + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + // Close any open directory server connection + close(this.context); + + } + + /** + * Given a string containing LDAP patterns for user locations (separated by + * parentheses in a pseudo-LDAP search string format - + * "(location1)(location2)", returns an array of those paths. Real LDAP + * search strings are supported as well (though only the "|" "OR" type). + * + * @param userPatternString - a string LDAP search paths surrounded by + * parentheses + */ + protected String[] parseUserPatternString(String userPatternString) { + + if (userPatternString != null) { + ArrayList pathList = new ArrayList(); + int startParenLoc = userPatternString.indexOf('('); + if (startParenLoc == -1) { + // no parens here; return whole thing + return new String[] {userPatternString}; + } + int startingPoint = 0; + while (startParenLoc > -1) { + int endParenLoc = 0; + // weed out escaped open parens and parens enclosing the + // whole statement (in the case of valid LDAP search + // strings: (|(something)(somethingelse)) + while ( (userPatternString.charAt(startParenLoc + 1) == '|') || + (startParenLoc != 0 && userPatternString.charAt(startParenLoc - 1) == '\\') ) { + startParenLoc = userPatternString.indexOf("(", startParenLoc+1); + } + endParenLoc = userPatternString.indexOf(")", startParenLoc+1); + // weed out escaped end-parens + while (userPatternString.charAt(endParenLoc - 1) == '\\') { + endParenLoc = userPatternString.indexOf(")", endParenLoc+1); + } + String nextPathPart = userPatternString.substring + (startParenLoc+1, endParenLoc); + pathList.add(nextPathPart); + startingPoint = endParenLoc+1; + startParenLoc = userPatternString.indexOf('(', startingPoint); + } + return (String[])pathList.toArray(new String[] {}); + } + return null; + + } + + + /** + * Given an LDAP search string, returns the string with certain characters + * escaped according to RFC 2254 guidelines. + * The character mapping is as follows: + * char -> Replacement + * --------------------------- + * * -> \2a + * ( -> \28 + * ) -> \29 + * \ -> \5c + * \0 -> \00 + * @param inString string to escape according to RFC 2254 guidelines + * @return String the escaped/encoded result + */ + protected String doRFC2254Encoding(String inString) { + StringBuffer buf = new StringBuffer(inString.length()); + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + switch (c) { + case '\\': + buf.append("\\5c"); + break; + case '*': + buf.append("\\2a"); + break; + case '(': + buf.append("\\28"); + break; + case ')': + buf.append("\\29"); + break; + case '\0': + buf.append("\\00"); + break; + default: + buf.append(c); + break; + } + } + return buf.toString(); + } + + +} + +// ------------------------------------------------------ Private Classes + +/** + * A private class representing a User + */ +class User { + String username = null; + String dn = null; + String password = null; + ArrayList roles = null; + + + User(String username, String dn, String password, ArrayList roles) { + this.username = username; + this.dn = dn; + this.password = password; + this.roles = roles; + } + +} diff --git a/java/org/apache/catalina/realm/LocalStrings.properties b/java/org/apache/catalina/realm/LocalStrings.properties index 9d8cd8b9d..a41418279 100644 --- a/java/org/apache/catalina/realm/LocalStrings.properties +++ b/java/org/apache/catalina/realm/LocalStrings.properties @@ -1,72 +1,72 @@ -# $Id: LocalStrings.properties 303678 2005-02-03 15:14:34Z remm $ - -# language - -# package org.apache.catalina.realm - -jaasRealm.beginLogin=JAASRealm login requested for username "{0}" using LoginContext for application "{1}" -jaasRealm.accountExpired=Username "{0}" NOT authenticated due to expired account -jaasRealm.authenticateFailure=Username "{0}" NOT successfully authenticated -jaasRealm.authenticateSuccess=Username "{0}" successfully authenticated as Principal "{1}" -- Subject was created too -jaasRealm.credentialExpired=Username "{0}" NOT authenticated due to expired credential -jaasRealm.failedLogin=Username "{0}" NOT authenticated due to failed login -jaasRealm.loginException=Login exception authenticating username "{0}" -jaasRealm.unexpectedError=Unexpected error -jaasRealm.loginContextCreated=JAAS LoginContext created for username "{0}" -jaasRealm.userPrincipalSuccess=Subject for username "{0}" returned user Principal "{1}" -jaasRealm.userPrincipalFailure=Subject for username "{0}" did not return a valid user Principal -jaasRealm.cachePrincipal=User Principal "{0}" cached; has {1} role Principal(s) -jaasRealm.checkPrincipal=Checking Principal "{0}" [{1}] -jaasRealm.userPrincipalSuccess=Principal "{0}" is a valid user class. We will use this as the user Principal. -jaasRealm.userPrincipalFailure=No valid user Principal found -jaasRealm.rolePrincipalAdd=Adding role Principal "{0}" to this user Principal''s roles -jaasRealm.rolePrincipalSuccess={0} role Principal(s) found -jaasRealm.rolePrincipalFailure=No valid role Principals found. -jaasRealm.isInRole.start=Checking if user Principal "{0}" possesses role "{1}" -jaasRealm.isInRole.noPrincipalOrRole=No roles Principals found. User Principal or Subject is null, or user Principal not in cache -jaasRealm.isInRole.principalCached=User Principal has {0} role Principal(s) -jaasRealm.isInRole.possessesRole=User Principal has a role Principal called "{0}" -jaasRealm.isInRole.match=Matching role Principal found. -jaasRealm.isInRole.noMatch=Matching role Principal NOT found. -jaasCallback.digestpassword=Digested password "{0}" as "{1}" -jaasCallback.username=Returned username "{0}" -jaasCallback.password=Returned password "{0}" -jdbcRealm.authenticateFailure=Username {0} NOT successfully authenticated -jdbcRealm.authenticateSuccess=Username {0} successfully authenticated -jdbcRealm.close=Exception closing database connection -jdbcRealm.exception=Exception performing authentication -jdbcRealm.getPassword.exception=Exception retrieving password for "{0}" -jdbcRealm.getRoles.exception=Exception retrieving roles for "{0}" -jdbcRealm.open=Exception opening database connection -jndiRealm.authenticateFailure=Username {0} NOT successfully authenticated -jndiRealm.authenticateSuccess=Username {0} successfully authenticated -jndiRealm.close=Exception closing directory server connection -jndiRealm.exception=Exception performing authentication -jndiRealm.open=Exception opening directory server connection -memoryRealm.authenticateFailure=Username {0} NOT successfully authenticated -memoryRealm.authenticateSuccess=Username {0} successfully authenticated -memoryRealm.loadExist=Memory database file {0} cannot be read -memoryRealm.loadPath=Loading users from memory database file {0} -memoryRealm.readXml=Exception while reading memory database file -realmBase.algorithm=Invalid message digest algorithm {0} specified -realmBase.alreadyStarted=This Realm has already been started -realmBase.digest=Error digesting user credentials -realmBase.forbidden=Access to the requested resource has been denied -realmBase.hasRoleFailure=Username {0} does NOT have role {1} -realmBase.hasRoleSuccess=Username {0} has role {1} -realmBase.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal -realmBase.notStarted=This Realm has not yet been started -realmBase.authenticateFailure=Username {0} NOT successfully authenticated -realmBase.authenticateSuccess=Username {0} successfully authenticated -userDatabaseRealm.authenticateError=Login configuration error authenticating username {0} -userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0} -userDatabaseRealm.noDatabase=No UserDatabase component found under key {0} -userDatabaseRealm.noEngine=No Engine component found in container hierarchy -userDatabaseRealm.noGlobal=No global JNDI resources context found -dataSourceRealm.authenticateFailure=Username {0} NOT successfully authenticated -dataSourceRealm.authenticateSuccess=Username {0} successfully authenticated -dataSourceRealm.close=Exception closing database connection -dataSourceRealm.exception=Exception performing authentication -dataSourceRealm.getPassword.exception=Exception retrieving password for "{0}" -dataSourceRealm.getRoles.exception=Exception retrieving roles for "{0}" -dataSourceRealm.open=Exception opening database connection +# $Id: LocalStrings.properties 303678 2005-02-03 15:14:34Z remm $ + +# language + +# package org.apache.catalina.realm + +jaasRealm.beginLogin=JAASRealm login requested for username "{0}" using LoginContext for application "{1}" +jaasRealm.accountExpired=Username "{0}" NOT authenticated due to expired account +jaasRealm.authenticateFailure=Username "{0}" NOT successfully authenticated +jaasRealm.authenticateSuccess=Username "{0}" successfully authenticated as Principal "{1}" -- Subject was created too +jaasRealm.credentialExpired=Username "{0}" NOT authenticated due to expired credential +jaasRealm.failedLogin=Username "{0}" NOT authenticated due to failed login +jaasRealm.loginException=Login exception authenticating username "{0}" +jaasRealm.unexpectedError=Unexpected error +jaasRealm.loginContextCreated=JAAS LoginContext created for username "{0}" +jaasRealm.userPrincipalSuccess=Subject for username "{0}" returned user Principal "{1}" +jaasRealm.userPrincipalFailure=Subject for username "{0}" did not return a valid user Principal +jaasRealm.cachePrincipal=User Principal "{0}" cached; has {1} role Principal(s) +jaasRealm.checkPrincipal=Checking Principal "{0}" [{1}] +jaasRealm.userPrincipalSuccess=Principal "{0}" is a valid user class. We will use this as the user Principal. +jaasRealm.userPrincipalFailure=No valid user Principal found +jaasRealm.rolePrincipalAdd=Adding role Principal "{0}" to this user Principal''s roles +jaasRealm.rolePrincipalSuccess={0} role Principal(s) found +jaasRealm.rolePrincipalFailure=No valid role Principals found. +jaasRealm.isInRole.start=Checking if user Principal "{0}" possesses role "{1}" +jaasRealm.isInRole.noPrincipalOrRole=No roles Principals found. User Principal or Subject is null, or user Principal not in cache +jaasRealm.isInRole.principalCached=User Principal has {0} role Principal(s) +jaasRealm.isInRole.possessesRole=User Principal has a role Principal called "{0}" +jaasRealm.isInRole.match=Matching role Principal found. +jaasRealm.isInRole.noMatch=Matching role Principal NOT found. +jaasCallback.digestpassword=Digested password "{0}" as "{1}" +jaasCallback.username=Returned username "{0}" +jaasCallback.password=Returned password "{0}" +jdbcRealm.authenticateFailure=Username {0} NOT successfully authenticated +jdbcRealm.authenticateSuccess=Username {0} successfully authenticated +jdbcRealm.close=Exception closing database connection +jdbcRealm.exception=Exception performing authentication +jdbcRealm.getPassword.exception=Exception retrieving password for "{0}" +jdbcRealm.getRoles.exception=Exception retrieving roles for "{0}" +jdbcRealm.open=Exception opening database connection +jndiRealm.authenticateFailure=Username {0} NOT successfully authenticated +jndiRealm.authenticateSuccess=Username {0} successfully authenticated +jndiRealm.close=Exception closing directory server connection +jndiRealm.exception=Exception performing authentication +jndiRealm.open=Exception opening directory server connection +memoryRealm.authenticateFailure=Username {0} NOT successfully authenticated +memoryRealm.authenticateSuccess=Username {0} successfully authenticated +memoryRealm.loadExist=Memory database file {0} cannot be read +memoryRealm.loadPath=Loading users from memory database file {0} +memoryRealm.readXml=Exception while reading memory database file +realmBase.algorithm=Invalid message digest algorithm {0} specified +realmBase.alreadyStarted=This Realm has already been started +realmBase.digest=Error digesting user credentials +realmBase.forbidden=Access to the requested resource has been denied +realmBase.hasRoleFailure=Username {0} does NOT have role {1} +realmBase.hasRoleSuccess=Username {0} has role {1} +realmBase.notAuthenticated=Configuration error: Cannot perform access control without an authenticated principal +realmBase.notStarted=This Realm has not yet been started +realmBase.authenticateFailure=Username {0} NOT successfully authenticated +realmBase.authenticateSuccess=Username {0} successfully authenticated +userDatabaseRealm.authenticateError=Login configuration error authenticating username {0} +userDatabaseRealm.lookup=Exception looking up UserDatabase under key {0} +userDatabaseRealm.noDatabase=No UserDatabase component found under key {0} +userDatabaseRealm.noEngine=No Engine component found in container hierarchy +userDatabaseRealm.noGlobal=No global JNDI resources context found +dataSourceRealm.authenticateFailure=Username {0} NOT successfully authenticated +dataSourceRealm.authenticateSuccess=Username {0} successfully authenticated +dataSourceRealm.close=Exception closing database connection +dataSourceRealm.exception=Exception performing authentication +dataSourceRealm.getPassword.exception=Exception retrieving password for "{0}" +dataSourceRealm.getRoles.exception=Exception retrieving roles for "{0}" +dataSourceRealm.open=Exception opening database connection diff --git a/java/org/apache/catalina/realm/LocalStrings_es.properties b/java/org/apache/catalina/realm/LocalStrings_es.properties index 3ce2fd755..94696f733 100644 --- a/java/org/apache/catalina/realm/LocalStrings_es.properties +++ b/java/org/apache/catalina/realm/LocalStrings_es.properties @@ -1,47 +1,47 @@ -# $Id: LocalStrings_es.properties 302991 2004-07-03 04:16:41Z billbarker $ - -# language es - -# package org.apache.catalina.realm - -jaasRealm.accountExpired=El usuario {0} NO ha sido autentificado porque ha expirado su cuenta -jaasRealm.authenticatedSuccess=El usuario {0} ha sido autentificado con éxito -jaasRealm.credentialExpired=El usuario {0} NO ha sido autentificado porque ha expirado su credencial -jaasRealm.failedLogin=El usuario {0} NO ha sido autentificado porque ha fallado el login -jaasRealm.loginException=Excepción de Login autenticando nombre de usuario {0} -jaasRealm.unexpectedError=Error inesperado -jdbcRealm.authenticateFailure=El usuario {0} NO ha sido autentificado correctamente -jdbcRealm.authenticateSuccess=El usuario {0} ha sido autentificado correctamente -jdbcRealm.close=Excepción al cerrar la conexión a la base de datos -jdbcRealm.exception=Excepción al realizar la autentificación -jdbcRealm.open=Excepción abriendo la conexión a la base de datos -jndiRealm.authenticateFailure=Autentificación fallida para el usuario {0} -jndiRealm.authenticateSuccess=Autentificación correcta para el usuario {0} -jndiRealm.close=Excepción al cerrar la conexión al servidor de directorio -jndiRealm.exception=Excepción al realizar la autentificación -jndiRealm.open=Excepción al abrir la conexión al servidor de directorio -memoryRealm.authenticateFailure=Autentificación fallida para el usuario {0} -memoryRealm.authenticateSuccess=Autentificación correcta para el usuario {0} -memoryRealm.loadExist=El fichero de usuarios {0} no ha podido ser leído -memoryRealm.loadPath=Cargando los usuarios desde el fichero {0} -memoryRealm.readXml=Excepción mientras se leía el fichero de usuarios -realmBase.algorithm=El algoritmo resumen (digest) {0} es inválido -realmBase.alreadyStarted=Este dominio ya ha sido inicializado -realmBase.digest=Error procesando las credenciales del usuario -realmBase.forbidden=El acceso al recurso pedido ha sido denegado -realmBase.hasRoleFailure=El usuario {0} NO desempeña el papel de {1} -realmBase.hasRoleSuccess=El usuario {0} desempeña el papel de {1} -realmBase.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autentificado -realmBase.notStarted=Este dominio aún no ha sido inicializado -realmBase.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito -realmBase.authenticateSuccess=Nombre de usuario {0} autenticado con éxito -userDatabaseRealm.authenticateError=Error de configuración de Login autenticando nombre de usuario {0} -userDatabaseRealm.lookup=Excepción buscando en Base de datos de Usuario mediante la clave {0} -userDatabaseRealm.noDatabase=No se ha hallado componente de Base de datos de Usuario mediante la clave {0} -userDatabaseRealm.noEngine=No se ha hallado componente de Motor en jerarquía de contenedor -userDatabaseRealm.noGlobal=No se ha hallado contexto de recursos globales JNDI -dataSourceRealm.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito -dataSourceRealm.authenticateSuccess=Nombre de usuario {0} autenticado con éxito -dataSourceRealm.close=Excepción cerrando conexión a base de datos -dataSourceRealm.exception=Excepción realizando autenticación -dataSourceRealm.open=Excepción abriendo conexión a base de datos +# $Id: LocalStrings_es.properties 302991 2004-07-03 04:16:41Z billbarker $ + +# language es + +# package org.apache.catalina.realm + +jaasRealm.accountExpired=El usuario {0} NO ha sido autentificado porque ha expirado su cuenta +jaasRealm.authenticatedSuccess=El usuario {0} ha sido autentificado con éxito +jaasRealm.credentialExpired=El usuario {0} NO ha sido autentificado porque ha expirado su credencial +jaasRealm.failedLogin=El usuario {0} NO ha sido autentificado porque ha fallado el login +jaasRealm.loginException=Excepción de Login autenticando nombre de usuario {0} +jaasRealm.unexpectedError=Error inesperado +jdbcRealm.authenticateFailure=El usuario {0} NO ha sido autentificado correctamente +jdbcRealm.authenticateSuccess=El usuario {0} ha sido autentificado correctamente +jdbcRealm.close=Excepción al cerrar la conexión a la base de datos +jdbcRealm.exception=Excepción al realizar la autentificación +jdbcRealm.open=Excepción abriendo la conexión a la base de datos +jndiRealm.authenticateFailure=Autentificación fallida para el usuario {0} +jndiRealm.authenticateSuccess=Autentificación correcta para el usuario {0} +jndiRealm.close=Excepción al cerrar la conexión al servidor de directorio +jndiRealm.exception=Excepción al realizar la autentificación +jndiRealm.open=Excepción al abrir la conexión al servidor de directorio +memoryRealm.authenticateFailure=Autentificación fallida para el usuario {0} +memoryRealm.authenticateSuccess=Autentificación correcta para el usuario {0} +memoryRealm.loadExist=El fichero de usuarios {0} no ha podido ser leído +memoryRealm.loadPath=Cargando los usuarios desde el fichero {0} +memoryRealm.readXml=Excepción mientras se leía el fichero de usuarios +realmBase.algorithm=El algoritmo resumen (digest) {0} es inválido +realmBase.alreadyStarted=Este dominio ya ha sido inicializado +realmBase.digest=Error procesando las credenciales del usuario +realmBase.forbidden=El acceso al recurso pedido ha sido denegado +realmBase.hasRoleFailure=El usuario {0} NO desempeña el papel de {1} +realmBase.hasRoleSuccess=El usuario {0} desempeña el papel de {1} +realmBase.notAuthenticated=Error de Configuración: No se pueden realizar funciones de control de acceso sin un principal autentificado +realmBase.notStarted=Este dominio aún no ha sido inicializado +realmBase.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito +realmBase.authenticateSuccess=Nombre de usuario {0} autenticado con éxito +userDatabaseRealm.authenticateError=Error de configuración de Login autenticando nombre de usuario {0} +userDatabaseRealm.lookup=Excepción buscando en Base de datos de Usuario mediante la clave {0} +userDatabaseRealm.noDatabase=No se ha hallado componente de Base de datos de Usuario mediante la clave {0} +userDatabaseRealm.noEngine=No se ha hallado componente de Motor en jerarquía de contenedor +userDatabaseRealm.noGlobal=No se ha hallado contexto de recursos globales JNDI +dataSourceRealm.authenticateFailure=Nombre de usuario {0} NO autenticado con éxito +dataSourceRealm.authenticateSuccess=Nombre de usuario {0} autenticado con éxito +dataSourceRealm.close=Excepción cerrando conexión a base de datos +dataSourceRealm.exception=Excepción realizando autenticación +dataSourceRealm.open=Excepción abriendo conexión a base de datos diff --git a/java/org/apache/catalina/realm/LocalStrings_fr.properties b/java/org/apache/catalina/realm/LocalStrings_fr.properties index 607790919..5750597f1 100644 --- a/java/org/apache/catalina/realm/LocalStrings_fr.properties +++ b/java/org/apache/catalina/realm/LocalStrings_fr.properties @@ -1,41 +1,41 @@ -# $Id: LocalStrings_fr.properties 302991 2004-07-03 04:16:41Z billbarker $ - -# language - -# package org.apache.catalina.realm - -jaasRealm.accountExpired=le nom d''utilisateur {0} N''A PAS été authentifié car le compte a expiré -jaasRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès -jaasRealm.credentialExpired=le nom d''utilisateur {0} N''A PAS été authentifié car son crédit a expiré (expired credential) -jaasRealm.failedLogin=le nom d''utilisateur {0} N''A PAS été authentifié car son contrôle d''accès (login) a échoué -jaasRealm.loginException=Exception lors de l''authentification par login du nom d''utilisateur {0} -jdbcRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié -jdbcRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès -jdbcRealm.close=Exception lors de la fermeture de la connexion à la base de données -jdbcRealm.exception=Exception pendant le traitement de l''authentification -jdbcRealm.open=Exception lors de l''ouverture de la base de données -jndiRealm.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié -jndiRealm.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès -jndiRealm.close=Exception lors de la fermeture de la connexion au serveur d''accès (directory server) -jndiRealm.exception=Exception pendant le traitement de l''authentification -jndiRealm.open=Exception lors de l''ouverture de la connexion au serveur d''accès (directory server) -memoryRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié -memoryRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès -memoryRealm.loadExist=Le fichier base de données mémoire (memory database) {0} ne peut être lu -memoryRealm.loadPath=Chargement des utilisateurs depuis le fichier base de données mémoire (memory database) {0} -memoryRealm.readXml=Exception lors de la lecture du fichier base de données mémoire (memory database) -realmBase.algorithm=L''algorithme d''empreinte de message (message digest) {0} indiqué est invalide -realmBase.alreadyStarted=Ce royaume (Realm) a déjà été démarré -realmBase.digest=Erreur lors du traitement des empreintes (digest) des crédits utilisateur (user credentials) -realmBase.forbidden=L''accès à la ressource demandée a été interdit -realmBase.hasRoleFailure=Le nom d''utilisateur {0} N''A PAS de rôle {1} -realmBase.hasRoleSuccess=Le nom d''utilisateur {0} a pour rôle {1} -realmBase.notAuthenticated=Erreur de configuration: Impossible de conduire un contrôle d''accès sans un authentifié principal (authenticated principal) -realmBase.notStarted=Ce royaume (Realm) n''a pas encore été démarré -realmBase.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié -realmBase.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès -userDatabaseRealm.authenticateError=Erreur de configuration du contrôle d''accès (login) lors de l''authentification du nom d''utilisateur {0} -userDatabaseRealm.lookup=Exception lors de la recherche dans la base de données utilisateurs avec la clef {0} -userDatabaseRealm.noDatabase=Aucun composant base de données utilisateurs trouvé pour la clef {0} -userDatabaseRealm.noEngine=Aucun composant moteur (engine component) trouvé dans la hiérarchie des conteneurs -userDatabaseRealm.noGlobal=Aucune ressource globale JNDI trouvée +# $Id: LocalStrings_fr.properties 302991 2004-07-03 04:16:41Z billbarker $ + +# language + +# package org.apache.catalina.realm + +jaasRealm.accountExpired=le nom d''utilisateur {0} N''A PAS été authentifié car le compte a expiré +jaasRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès +jaasRealm.credentialExpired=le nom d''utilisateur {0} N''A PAS été authentifié car son crédit a expiré (expired credential) +jaasRealm.failedLogin=le nom d''utilisateur {0} N''A PAS été authentifié car son contrôle d''accès (login) a échoué +jaasRealm.loginException=Exception lors de l''authentification par login du nom d''utilisateur {0} +jdbcRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié +jdbcRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès +jdbcRealm.close=Exception lors de la fermeture de la connexion à la base de données +jdbcRealm.exception=Exception pendant le traitement de l''authentification +jdbcRealm.open=Exception lors de l''ouverture de la base de données +jndiRealm.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié +jndiRealm.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès +jndiRealm.close=Exception lors de la fermeture de la connexion au serveur d''accès (directory server) +jndiRealm.exception=Exception pendant le traitement de l''authentification +jndiRealm.open=Exception lors de l''ouverture de la connexion au serveur d''accès (directory server) +memoryRealm.authenticateFailure=le nom d''utilisateur {0} N''A PAS été authentifié +memoryRealm.authenticateSuccess=le nom d''utilisateur {0} a été authentifié avec succès +memoryRealm.loadExist=Le fichier base de données mémoire (memory database) {0} ne peut être lu +memoryRealm.loadPath=Chargement des utilisateurs depuis le fichier base de données mémoire (memory database) {0} +memoryRealm.readXml=Exception lors de la lecture du fichier base de données mémoire (memory database) +realmBase.algorithm=L''algorithme d''empreinte de message (message digest) {0} indiqué est invalide +realmBase.alreadyStarted=Ce royaume (Realm) a déjà été démarré +realmBase.digest=Erreur lors du traitement des empreintes (digest) des crédits utilisateur (user credentials) +realmBase.forbidden=L''accès à la ressource demandée a été interdit +realmBase.hasRoleFailure=Le nom d''utilisateur {0} N''A PAS de rôle {1} +realmBase.hasRoleSuccess=Le nom d''utilisateur {0} a pour rôle {1} +realmBase.notAuthenticated=Erreur de configuration: Impossible de conduire un contrôle d''accès sans un authentifié principal (authenticated principal) +realmBase.notStarted=Ce royaume (Realm) n''a pas encore été démarré +realmBase.authenticateFailure=Le nom d''utilisateur {0} N''A PAS été authentifié +realmBase.authenticateSuccess=Le nom d''utilisateur {0} a été authentifié avec succès +userDatabaseRealm.authenticateError=Erreur de configuration du contrôle d''accès (login) lors de l''authentification du nom d''utilisateur {0} +userDatabaseRealm.lookup=Exception lors de la recherche dans la base de données utilisateurs avec la clef {0} +userDatabaseRealm.noDatabase=Aucun composant base de données utilisateurs trouvé pour la clef {0} +userDatabaseRealm.noEngine=Aucun composant moteur (engine component) trouvé dans la hiérarchie des conteneurs +userDatabaseRealm.noGlobal=Aucune ressource globale JNDI trouvée diff --git a/java/org/apache/catalina/realm/LocalStrings_ja.properties b/java/org/apache/catalina/realm/LocalStrings_ja.properties index 11e432fe4..b4868f11f 100644 --- a/java/org/apache/catalina/realm/LocalStrings_ja.properties +++ b/java/org/apache/catalina/realm/LocalStrings_ja.properties @@ -1,47 +1,47 @@ -# $Id: LocalStrings_ja.properties 302991 2004-07-03 04:16:41Z billbarker $ - -# language ja - -# package org.apache.catalina.realm - -jaasRealm.accountExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u671f\u9650\u304c\u5207\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 -jaasRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -jaasRealm.credentialExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a3c\u660e\u66f8\u306e\u671f\u9650\u304c\u5207\u308c\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 -jaasRealm.failedLogin=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30b0\u30a4\u30f3\u306b\u5931\u6557\u3057\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f -jaasRealm.loginException=\u30e6\u30fc\u30b6\u540d {0} \u306e\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -jaasRealm.unexpectedError=\u4e88\u6e2c\u3057\u306a\u3044\u30a8\u30e9\u30fc\u3067\u3059 -jdbcRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f -jdbcRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -jdbcRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jdbcRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jdbcRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -jndiRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f -jndiRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -jndiRealm.close=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jndiRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jndiRealm.open=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -memoryRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f -memoryRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -memoryRealm.loadExist=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092\u8aad\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 -memoryRealm.loadPath=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30e6\u30fc\u30b6\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 -memoryRealm.readXml=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -realmBase.algorithm=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -realmBase.alreadyStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -realmBase.digest=\u30e6\u30fc\u30b6\u306e\u8a3c\u660e\u66f8\u306e\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a8\u30e9\u30fc -realmBase.forbidden=\u8981\u6c42\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f -realmBase.hasRoleFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 -realmBase.hasRoleSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u3059 -realmBase.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u3067\u306f\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u304c\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 -realmBase.notStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -realmBase.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f -realmBase.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -userDatabaseRealm.authenticateError=\u30e6\u30fc\u30b6\u540d {0} \u3092\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u8a2d\u5b9a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -userDatabaseRealm.lookup=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u691c\u7d22\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -userDatabaseRealm.noDatabase=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -userDatabaseRealm.noEngine=\u30b3\u30f3\u30c6\u30ca\u968e\u5c64\u4e2d\u306b\u30a8\u30f3\u30b8\u30f3\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -userDatabaseRealm.noGlobal=\u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -dataSourceRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f -dataSourceRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f -dataSourceRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -dataSourceRealm.exception=\u8a8d\u8a3c\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -dataSourceRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +# $Id: LocalStrings_ja.properties 302991 2004-07-03 04:16:41Z billbarker $ + +# language ja + +# package org.apache.catalina.realm + +jaasRealm.accountExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30a2\u30ab\u30a6\u30f3\u30c8\u306e\u671f\u9650\u304c\u5207\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 +jaasRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +jaasRealm.credentialExpired=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a3c\u660e\u66f8\u306e\u671f\u9650\u304c\u5207\u308c\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093 +jaasRealm.failedLogin=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30b0\u30a4\u30f3\u306b\u5931\u6557\u3057\u305f\u305f\u3081\u306b\u8a8d\u8a3c\u3055\u308c\u307e\u305b\u3093\u3067\u3057\u305f +jaasRealm.loginException=\u30e6\u30fc\u30b6\u540d {0} \u306e\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +jaasRealm.unexpectedError=\u4e88\u6e2c\u3057\u306a\u3044\u30a8\u30e9\u30fc\u3067\u3059 +jdbcRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f +jdbcRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +jdbcRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jdbcRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jdbcRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +jndiRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f +jndiRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +jndiRealm.close=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jndiRealm.exception=\u8a8d\u8a3c\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jndiRealm.open=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u30b5\u30fc\u30d0\u63a5\u7d9a\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +memoryRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f +memoryRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +memoryRealm.loadExist=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092\u8aad\u3080\u3053\u3068\u304c\u3067\u304d\u307e\u305b\u3093 +memoryRealm.loadPath=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u304b\u3089\u30e6\u30fc\u30b6\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 +memoryRealm.readXml=\u30e1\u30e2\u30ea\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d5\u30a1\u30a4\u30eb\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +realmBase.algorithm=\u7121\u52b9\u306a\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +realmBase.alreadyStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +realmBase.digest=\u30e6\u30fc\u30b6\u306e\u8a3c\u660e\u66f8\u306e\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30a8\u30e9\u30fc +realmBase.forbidden=\u8981\u6c42\u3055\u308c\u305f\u30ea\u30bd\u30fc\u30b9\u3078\u306e\u30a2\u30af\u30bb\u30b9\u304c\u62d2\u5426\u3055\u308c\u307e\u3057\u305f +realmBase.hasRoleFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 +realmBase.hasRoleSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u30ed\u30fc\u30eb {1} \u3092\u6301\u3063\u3066\u3044\u307e\u3059 +realmBase.notAuthenticated=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u8a8d\u8a3c\u3055\u308c\u305f\u4e3b\u4f53\u306a\u3057\u3067\u306f\u30a2\u30af\u30bb\u30b9\u5236\u5fa1\u304c\u5b9f\u884c\u3067\u304d\u307e\u305b\u3093 +realmBase.notStarted=\u3053\u306e\u30ec\u30eb\u30e0\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +realmBase.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f +realmBase.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +userDatabaseRealm.authenticateError=\u30e6\u30fc\u30b6\u540d {0} \u3092\u8a8d\u8a3c\u4e2d\u306b\u30ed\u30b0\u30a4\u30f3\u8a2d\u5b9a\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +userDatabaseRealm.lookup=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u691c\u7d22\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +userDatabaseRealm.noDatabase=\u30ad\u30fc {0} \u3067\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +userDatabaseRealm.noEngine=\u30b3\u30f3\u30c6\u30ca\u968e\u5c64\u4e2d\u306b\u30a8\u30f3\u30b8\u30f3\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +userDatabaseRealm.noGlobal=\u30b0\u30ed\u30fc\u30d0\u30eb\u306aJNDI\u30ea\u30bd\u30fc\u30b9\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +dataSourceRealm.authenticateFailure=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u5931\u6557\u3057\u307e\u3057\u305f +dataSourceRealm.authenticateSuccess=\u30e6\u30fc\u30b6\u540d {0} \u306f\u8a8d\u8a3c\u306b\u6210\u529f\u3057\u307e\u3057\u305f +dataSourceRealm.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +dataSourceRealm.exception=\u8a8d\u8a3c\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +dataSourceRealm.open=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30aa\u30fc\u30d7\u30f3\u4e2d\u306e\u4f8b\u5916\u3067\u3059 diff --git a/java/org/apache/catalina/realm/MemoryRealm.java b/java/org/apache/catalina/realm/MemoryRealm.java index 0e2de5537..5a924af32 100644 --- a/java/org/apache/catalina/realm/MemoryRealm.java +++ b/java/org/apache/catalina/realm/MemoryRealm.java @@ -1,340 +1,340 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.io.File; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import org.apache.catalina.Container; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.digester.Digester; - - -/** - * Simple implementation of Realm that reads an XML file to configure - * the valid users, passwords, and roles. The file format (and default file - * location) are identical to those currently supported by Tomcat 3.X. - *

    - * IMPLEMENTATION NOTE: It is assumed that the in-memory - * collection representing our defined users (and their roles) is initialized - * at application startup and never modified again. Therefore, no thread - * synchronization is performed around accesses to the principals collection. - * - * @author Craig R. McClanahan - * @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ - */ - -public class MemoryRealm extends RealmBase { - - private static Log log = LogFactory.getLog(MemoryRealm.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The Container with which this Realm is associated. - */ - private Container container = null; - - - /** - * The Digester we will use to process in-memory database files. - */ - private static Digester digester = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected final String info = - "org.apache.catalina.realm.MemoryRealm/1.0"; - - - /** - * Descriptive information about this Realm implementation. - */ - - protected static final String name = "MemoryRealm"; - - - /** - * The pathname (absolute or relative to Catalina's current working - * directory) of the XML file containing our database information. - */ - private String pathname = "conf/tomcat-users.xml"; - - - /** - * The set of valid Principals for this Realm, keyed by user name. - */ - private Map principals = new HashMap(); - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started? - */ - private boolean started = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Realm implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return info; - - } - - - /** - * Return the pathname of our XML file containing user definitions. - */ - public String getPathname() { - - return pathname; - - } - - - /** - * Set the pathname of our XML file containing user definitions. If a - * relative pathname is specified, it is resolved against "catalina.base". - * - * @param pathname The new pathname - */ - public void setPathname(String pathname) { - - this.pathname = pathname; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials) { - - GenericPrincipal principal = - (GenericPrincipal) principals.get(username); - - boolean validated = false; - if (principal != null) { - if (hasMessageDigest()) { - // Hex hashes should be compared case-insensitive - validated = (digest(credentials) - .equalsIgnoreCase(principal.getPassword())); - } else { - validated = - (digest(credentials).equals(principal.getPassword())); - } - } - - if (validated) { - if (log.isDebugEnabled()) - log.debug(sm.getString("memoryRealm.authenticateSuccess", username)); - return (principal); - } else { - if (log.isDebugEnabled()) - log.debug(sm.getString("memoryRealm.authenticateFailure", username)); - return (null); - } - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Add a new user to the in-memory database. - * - * @param username User's username - * @param password User's password (clear text) - * @param roles Comma-delimited set of roles associated with this user - */ - void addUser(String username, String password, String roles) { - - // Accumulate the list of roles for this user - ArrayList list = new ArrayList(); - roles += ","; - while (true) { - int comma = roles.indexOf(','); - if (comma < 0) - break; - String role = roles.substring(0, comma).trim(); - list.add(role); - roles = roles.substring(comma + 1); - } - - // Construct and cache the Principal for this user - GenericPrincipal principal = - new GenericPrincipal(this, username, password, list); - principals.put(username, principal); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a configured Digester to use for processing - * the XML input file, creating a new one if necessary. - */ - protected synchronized Digester getDigester() { - - if (digester == null) { - digester = new Digester(); - digester.setValidating(false); - digester.addRuleSet(new MemoryRuleSet()); - } - return (digester); - - } - - - /** - * Return a short name for this Realm implementation. - */ - protected String getName() { - - return (name); - - } - - - /** - * Return the password associated with the given principal's user name. - */ - protected String getPassword(String username) { - - GenericPrincipal principal = - (GenericPrincipal) principals.get(username); - if (principal != null) { - return (principal.getPassword()); - } else { - return (null); - } - - } - - - /** - * Return the Principal associated with the given user name. - */ - protected Principal getPrincipal(String username) { - - return (Principal) principals.get(username); - - } - - /** - * Returns the principals for this realm. - * - * @return The principals, keyed by user name (a String) - */ - protected Map getPrincipals() { - return principals; - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public synchronized void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - // Validate the existence of our database file - File file = new File(pathname); - if (!file.isAbsolute()) - file = new File(System.getProperty("catalina.base"), pathname); - if (!file.exists() || !file.canRead()) - throw new LifecycleException - (sm.getString("memoryRealm.loadExist", - file.getAbsolutePath())); - - // Load the contents of the database file - if (log.isDebugEnabled()) - log.debug(sm.getString("memoryRealm.loadPath", - file.getAbsolutePath())); - Digester digester = getDigester(); - try { - synchronized (digester) { - digester.push(this); - digester.parse(file); - } - } catch (Exception e) { - throw new LifecycleException("memoryRealm.readXml", e); - } finally { - digester.reset(); - } - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public synchronized void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - // No shutdown activities required - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.security.Principal; +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import org.apache.catalina.Container; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.digester.Digester; + + +/** + * Simple implementation of Realm that reads an XML file to configure + * the valid users, passwords, and roles. The file format (and default file + * location) are identical to those currently supported by Tomcat 3.X. + *

    + * IMPLEMENTATION NOTE: It is assumed that the in-memory + * collection representing our defined users (and their roles) is initialized + * at application startup and never modified again. Therefore, no thread + * synchronization is performed around accesses to the principals collection. + * + * @author Craig R. McClanahan + * @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ + */ + +public class MemoryRealm extends RealmBase { + + private static Log log = LogFactory.getLog(MemoryRealm.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The Container with which this Realm is associated. + */ + private Container container = null; + + + /** + * The Digester we will use to process in-memory database files. + */ + private static Digester digester = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected final String info = + "org.apache.catalina.realm.MemoryRealm/1.0"; + + + /** + * Descriptive information about this Realm implementation. + */ + + protected static final String name = "MemoryRealm"; + + + /** + * The pathname (absolute or relative to Catalina's current working + * directory) of the XML file containing our database information. + */ + private String pathname = "conf/tomcat-users.xml"; + + + /** + * The set of valid Principals for this Realm, keyed by user name. + */ + private Map principals = new HashMap(); + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started? + */ + private boolean started = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Realm implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return info; + + } + + + /** + * Return the pathname of our XML file containing user definitions. + */ + public String getPathname() { + + return pathname; + + } + + + /** + * Set the pathname of our XML file containing user definitions. If a + * relative pathname is specified, it is resolved against "catalina.base". + * + * @param pathname The new pathname + */ + public void setPathname(String pathname) { + + this.pathname = pathname; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials) { + + GenericPrincipal principal = + (GenericPrincipal) principals.get(username); + + boolean validated = false; + if (principal != null) { + if (hasMessageDigest()) { + // Hex hashes should be compared case-insensitive + validated = (digest(credentials) + .equalsIgnoreCase(principal.getPassword())); + } else { + validated = + (digest(credentials).equals(principal.getPassword())); + } + } + + if (validated) { + if (log.isDebugEnabled()) + log.debug(sm.getString("memoryRealm.authenticateSuccess", username)); + return (principal); + } else { + if (log.isDebugEnabled()) + log.debug(sm.getString("memoryRealm.authenticateFailure", username)); + return (null); + } + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Add a new user to the in-memory database. + * + * @param username User's username + * @param password User's password (clear text) + * @param roles Comma-delimited set of roles associated with this user + */ + void addUser(String username, String password, String roles) { + + // Accumulate the list of roles for this user + ArrayList list = new ArrayList(); + roles += ","; + while (true) { + int comma = roles.indexOf(','); + if (comma < 0) + break; + String role = roles.substring(0, comma).trim(); + list.add(role); + roles = roles.substring(comma + 1); + } + + // Construct and cache the Principal for this user + GenericPrincipal principal = + new GenericPrincipal(this, username, password, list); + principals.put(username, principal); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a configured Digester to use for processing + * the XML input file, creating a new one if necessary. + */ + protected synchronized Digester getDigester() { + + if (digester == null) { + digester = new Digester(); + digester.setValidating(false); + digester.addRuleSet(new MemoryRuleSet()); + } + return (digester); + + } + + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + + return (name); + + } + + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String username) { + + GenericPrincipal principal = + (GenericPrincipal) principals.get(username); + if (principal != null) { + return (principal.getPassword()); + } else { + return (null); + } + + } + + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String username) { + + return (Principal) principals.get(username); + + } + + /** + * Returns the principals for this realm. + * + * @return The principals, keyed by user name (a String) + */ + protected Map getPrincipals() { + return principals; + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public synchronized void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + // Validate the existence of our database file + File file = new File(pathname); + if (!file.isAbsolute()) + file = new File(System.getProperty("catalina.base"), pathname); + if (!file.exists() || !file.canRead()) + throw new LifecycleException + (sm.getString("memoryRealm.loadExist", + file.getAbsolutePath())); + + // Load the contents of the database file + if (log.isDebugEnabled()) + log.debug(sm.getString("memoryRealm.loadPath", + file.getAbsolutePath())); + Digester digester = getDigester(); + try { + synchronized (digester) { + digester.push(this); + digester.parse(file); + } + } catch (Exception e) { + throw new LifecycleException("memoryRealm.readXml", e); + } finally { + digester.reset(); + } + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public synchronized void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + // No shutdown activities required + + } + + +} diff --git a/java/org/apache/catalina/realm/MemoryRuleSet.java b/java/org/apache/catalina/realm/MemoryRuleSet.java index de6458a6b..9d74d31d6 100644 --- a/java/org/apache/catalina/realm/MemoryRuleSet.java +++ b/java/org/apache/catalina/realm/MemoryRuleSet.java @@ -1,134 +1,134 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.Rule; -import org.apache.tomcat.util.digester.RuleSetBase; -import org.xml.sax.Attributes; - - -/** - *

    RuleSet for recognizing the users defined in the - * XML file processed by MemoryRealm.

    - * - * @author Craig R. McClanahan - * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ - */ - -public class MemoryRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public MemoryRuleSet() { - - this("tomcat-users/"); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public MemoryRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

    Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

    - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - digester.addRule(prefix + "user", new MemoryUserRule()); - - } - - -} - - -/** - * Private class used when parsing the XML database file. - */ -final class MemoryUserRule extends Rule { - - - /** - * Construct a new instance of this Rule. - */ - public MemoryUserRule() { - } - - - /** - * Process a <user> element from the XML database file. - * - * @param attributes The attribute list for this element - */ - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - String username = attributes.getValue("name"); - if (username == null) { - username = attributes.getValue("username"); - } - String password = attributes.getValue("password"); - String roles = attributes.getValue("roles"); - - MemoryRealm realm = - (MemoryRealm) digester.peek(digester.getCount() - 1); - realm.addUser(username, password, roles); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.Rule; +import org.apache.tomcat.util.digester.RuleSetBase; +import org.xml.sax.Attributes; + + +/** + *

    RuleSet for recognizing the users defined in the + * XML file processed by MemoryRealm.

    + * + * @author Craig R. McClanahan + * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ + */ + +public class MemoryRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public MemoryRuleSet() { + + this("tomcat-users/"); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public MemoryRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

    Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

    + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + digester.addRule(prefix + "user", new MemoryUserRule()); + + } + + +} + + +/** + * Private class used when parsing the XML database file. + */ +final class MemoryUserRule extends Rule { + + + /** + * Construct a new instance of this Rule. + */ + public MemoryUserRule() { + } + + + /** + * Process a <user> element from the XML database file. + * + * @param attributes The attribute list for this element + */ + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + String username = attributes.getValue("name"); + if (username == null) { + username = attributes.getValue("username"); + } + String password = attributes.getValue("password"); + String roles = attributes.getValue("roles"); + + MemoryRealm realm = + (MemoryRealm) digester.peek(digester.getCount() - 1); + realm.addUser(username, password, roles); + + } + + +} diff --git a/java/org/apache/catalina/realm/RealmBase.java b/java/org/apache/catalina/realm/RealmBase.java index 4a0e3b707..f70d94a2e 100644 --- a/java/org/apache/catalina/realm/RealmBase.java +++ b/java/org/apache/catalina/realm/RealmBase.java @@ -1,1426 +1,1426 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.Principal; -import java.security.cert.X509Certificate; -import java.util.ArrayList; - -import javax.management.Attribute; -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Realm; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.core.ContainerBase; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.deploy.SecurityCollection; -import org.apache.catalina.util.HexUtils; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.MD5Encoder; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; - -/** - * Simple implementation of Realm that reads an XML file to configure - * the valid users, passwords, and roles. The file format (and default file - * location) are identical to those currently supported by Tomcat 3.X. - * - * @author Craig R. McClanahan - * @version $Revision: 388949 $ $Date: 2006-03-26 21:55:03 +0200 (dim., 26 mars 2006) $ - */ - -public abstract class RealmBase - implements Lifecycle, Realm, MBeanRegistration { - - private static Log log = LogFactory.getLog(RealmBase.class); - - // ----------------------------------------------------- Instance Variables - - - /** - * The Container with which this Realm is associated. - */ - protected Container container = null; - - - /** - * Container log - */ - protected Log containerLog = null; - - - /** - * Digest algorithm used in storing passwords in a non-plaintext format. - * Valid values are those accepted for the algorithm name by the - * MessageDigest class, or null if no digesting should - * be performed. - */ - protected String digest = null; - - /** - * The encoding charset for the digest. - */ - protected String digestEncoding = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String info = - "org.apache.catalina.realm.RealmBase/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The MessageDigest object for digesting user credentials (passwords). - */ - protected MessageDigest md = null; - - - /** - * The MD5 helper object for this class. - */ - protected static final MD5Encoder md5Encoder = new MD5Encoder(); - - - /** - * MD5 message digest provider. - */ - protected static MessageDigest md5Helper; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started? - */ - protected boolean started = false; - - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - /** - * Should we validate client certificate chains when they are presented? - */ - protected boolean validate = true; - - - /** - * The all role mode. - */ - protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Container with which this Realm has been associated. - */ - public Container getContainer() { - - return (container); - - } - - - /** - * Set the Container with which this Realm has been associated. - * - * @param container The associated Container - */ - public void setContainer(Container container) { - - Container oldContainer = this.container; - this.container = container; - support.firePropertyChange("container", oldContainer, this.container); - - } - - /** - * Return the all roles mode. - */ - public String getAllRolesMode() { - - return allRolesMode.toString(); - - } - - - /** - * Set the all roles mode. - */ - public void setAllRolesMode(String allRolesMode) { - - this.allRolesMode = AllRolesMode.toMode(allRolesMode); - - } - - /** - * Return the digest algorithm used for storing credentials. - */ - public String getDigest() { - - return digest; - - } - - - /** - * Set the digest algorithm used for storing credentials. - * - * @param digest The new digest algorithm - */ - public void setDigest(String digest) { - - this.digest = digest; - - } - - /** - * Returns the digest encoding charset. - * - * @return The charset (may be null) for platform default - */ - public String getDigestEncoding() { - return digestEncoding; - } - - /** - * Sets the digest encoding charset. - * - * @param charset The charset (null for platform default) - */ - public void setDigestEncoding(String charset) { - digestEncoding = charset; - } - - /** - * Return descriptive information about this Realm implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return info; - - } - - - /** - * Return the "validate certificate chains" flag. - */ - public boolean getValidate() { - - return (this.validate); - - } - - - /** - * Set the "validate certificate chains" flag. - * - * @param validate The new validate certificate chains flag - */ - public void setValidate(boolean validate) { - - this.validate = validate; - - } - - - // --------------------------------------------------------- Public Methods - - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - - support.addPropertyChangeListener(listener); - - } - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, String credentials) { - - String serverCredentials = getPassword(username); - - boolean validated ; - if ( serverCredentials == null ) { - validated = false; - } else if(hasMessageDigest()) { - validated = serverCredentials.equalsIgnoreCase(digest(credentials)); - } else { - validated = serverCredentials.equals(credentials); - } - if(! validated ) { - if (containerLog.isTraceEnabled()) { - containerLog.trace(sm.getString("realmBase.authenticateFailure", - username)); - } - return null; - } - if (containerLog.isTraceEnabled()) { - containerLog.trace(sm.getString("realmBase.authenticateSuccess", - username)); - } - - return getPrincipal(username); - } - - - /** - * Return the Principal associated with the specified username and - * credentials, if there is one; otherwise return null. - * - * @param username Username of the Principal to look up - * @param credentials Password or other credentials to use in - * authenticating this username - */ - public Principal authenticate(String username, byte[] credentials) { - - return (authenticate(username, credentials.toString())); - - } - - - /** - * Return the Principal associated with the specified username, which - * matches the digest calculated using the given parameters using the - * method described in RFC 2069; otherwise return null. - * - * @param username Username of the Principal to look up - * @param clientDigest Digest which has been submitted by the client - * @param nOnce Unique (or supposedly unique) token which has been used - * for this request - * @param realm Realm name - * @param md5a2 Second MD5 digest used to calculate the digest : - * MD5(Method + ":" + uri) - */ - public Principal authenticate(String username, String clientDigest, - String nOnce, String nc, String cnonce, - String qop, String realm, - String md5a2) { - - String md5a1 = getDigest(username, realm); - if (md5a1 == null) - return null; - String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":" - + cnonce + ":" + qop + ":" + md5a2; - - byte[] valueBytes = null; - if(getDigestEncoding() == null) { - valueBytes = serverDigestValue.getBytes(); - } else { - try { - valueBytes = serverDigestValue.getBytes(getDigestEncoding()); - } catch (UnsupportedEncodingException uee) { - log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); - throw new IllegalArgumentException(uee.getMessage()); - } - } - - String serverDigest = null; - // Bugzilla 32137 - synchronized(md5Helper) { - serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes)); - } - - if (log.isDebugEnabled()) { - log.debug("Digest : " + clientDigest + " Username:" + username - + " ClientSigest:" + clientDigest + " nOnce:" + nOnce - + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop - + " realm:" + realm + "md5a2:" + md5a2 - + " Server digest:" + serverDigest); - } - - if (serverDigest.equals(clientDigest)) - return getPrincipal(username); - else - return null; - } - - - - /** - * Return the Principal associated with the specified chain of X509 - * client certificates. If there is none, return null. - * - * @param certs Array of client certificates, with the first one in - * the array being the certificate of the client itself. - */ - public Principal authenticate(X509Certificate certs[]) { - - if ((certs == null) || (certs.length < 1)) - return (null); - - // Check the validity of each certificate in the chain - if (log.isDebugEnabled()) - log.debug("Authenticating client certificate chain"); - if (validate) { - for (int i = 0; i < certs.length; i++) { - if (log.isDebugEnabled()) - log.debug(" Checking validity for '" + - certs[i].getSubjectDN().getName() + "'"); - try { - certs[i].checkValidity(); - } catch (Exception e) { - if (log.isDebugEnabled()) - log.debug(" Validity exception", e); - return (null); - } - } - } - - // Check the existence of the client Principal in our database - return (getPrincipal(certs[0])); - - } - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - } - - - /** - * Return the SecurityConstraints configured to guard the request URI for - * this request, or null if there is no such constraint. - * - * @param request Request we are processing - * @param context Context the Request is mapped to - */ - public SecurityConstraint [] findSecurityConstraints(Request request, - Context context) { - - ArrayList results = null; - // Are there any defined security constraints? - SecurityConstraint constraints[] = context.findConstraints(); - if ((constraints == null) || (constraints.length == 0)) { - if (log.isDebugEnabled()) - log.debug(" No applicable constraints defined"); - return (null); - } - - // Check each defined security constraint - String uri = request.getRequestPathMB().toString(); - - String method = request.getMethod(); - int i; - boolean found = false; - for (i = 0; i < constraints.length; i++) { - SecurityCollection [] collection = constraints[i].findCollections(); - - // If collection is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( collection == null) { - continue; - } - - if (log.isDebugEnabled()) { - log.debug(" Checking constraint '" + constraints[i] + - "' against " + method + " " + uri + " --> " + - constraints[i].included(uri, method)); - } - - for(int j=0; j < collection.length; j++){ - String [] patterns = collection[j].findPatterns(); - - // If patterns is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( patterns == null) { - continue; - } - - for(int k=0; k < patterns.length; k++) { - if(uri.equals(patterns[k])) { - found = true; - if(collection[j].findMethod(method)) { - if(results == null) { - results = new ArrayList(); - } - results.add(constraints[i]); - } - } - } - } - } - - if(found) { - return resultsToArray(results); - } - - int longest = -1; - - for (i = 0; i < constraints.length; i++) { - SecurityCollection [] collection = constraints[i].findCollections(); - - // If collection is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( collection == null) { - continue; - } - - if (log.isDebugEnabled()) { - log.debug(" Checking constraint '" + constraints[i] + - "' against " + method + " " + uri + " --> " + - constraints[i].included(uri, method)); - } - - for(int j=0; j < collection.length; j++){ - String [] patterns = collection[j].findPatterns(); - - // If patterns is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( patterns == null) { - continue; - } - - boolean matched = false; - int length = -1; - for(int k=0; k < patterns.length; k++) { - String pattern = patterns[k]; - if(pattern.startsWith("/") && pattern.endsWith("/*") && - pattern.length() >= longest) { - - if(pattern.length() == 2) { - matched = true; - length = pattern.length(); - } else if(pattern.regionMatches(0,uri,0, - pattern.length()-1) || - (pattern.length()-2 == uri.length() && - pattern.regionMatches(0,uri,0, - pattern.length()-2))) { - matched = true; - length = pattern.length(); - } - } - } - if(matched) { - found = true; - if(length > longest) { - if(results != null) { - results.clear(); - } - longest = length; - } - if(collection[j].findMethod(method)) { - if(results == null) { - results = new ArrayList(); - } - results.add(constraints[i]); - } - } - } - } - - if(found) { - return resultsToArray(results); - } - - for (i = 0; i < constraints.length; i++) { - SecurityCollection [] collection = constraints[i].findCollections(); - - // If collection is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( collection == null) { - continue; - } - - if (log.isDebugEnabled()) { - log.debug(" Checking constraint '" + constraints[i] + - "' against " + method + " " + uri + " --> " + - constraints[i].included(uri, method)); - } - - boolean matched = false; - int pos = -1; - for(int j=0; j < collection.length; j++){ - String [] patterns = collection[j].findPatterns(); - - // If patterns is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( patterns == null) { - continue; - } - - for(int k=0; k < patterns.length && !matched; k++) { - String pattern = patterns[k]; - if(pattern.startsWith("*.")){ - int slash = uri.lastIndexOf("/"); - int dot = uri.lastIndexOf("."); - if(slash >= 0 && dot > slash && - dot != uri.length()-1 && - uri.length()-dot == pattern.length()-1) { - if(pattern.regionMatches(1,uri,dot,uri.length()-dot)) { - matched = true; - pos = j; - } - } - } - } - } - if(matched) { - found = true; - if(collection[pos].findMethod(method)) { - if(results == null) { - results = new ArrayList(); - } - results.add(constraints[i]); - } - } - } - - if(found) { - return resultsToArray(results); - } - - for (i = 0; i < constraints.length; i++) { - SecurityCollection [] collection = constraints[i].findCollections(); - - // If collection is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( collection == null) { - continue; - } - - if (log.isDebugEnabled()) { - log.debug(" Checking constraint '" + constraints[i] + - "' against " + method + " " + uri + " --> " + - constraints[i].included(uri, method)); - } - - for(int j=0; j < collection.length; j++){ - String [] patterns = collection[j].findPatterns(); - - // If patterns is null, continue to avoid an NPE - // See Bugzilla 30624 - if ( patterns == null) { - continue; - } - - boolean matched = false; - for(int k=0; k < patterns.length && !matched; k++) { - String pattern = patterns[k]; - if(pattern.equals("/")){ - matched = true; - } - } - if(matched) { - if(results == null) { - results = new ArrayList(); - } - results.add(constraints[i]); - } - } - } - - if(results == null) { - // No applicable security constraint was found - if (log.isDebugEnabled()) - log.debug(" No applicable constraint located"); - } - return resultsToArray(results); - } - - /** - * Convert an ArrayList to a SecurityContraint []. - */ - private SecurityConstraint [] resultsToArray(ArrayList results) { - if(results == null) { - return null; - } - SecurityConstraint [] array = new SecurityConstraint[results.size()]; - results.toArray(array); - return array; - } - - - /** - * Perform access control based on the specified authorization constraint. - * Return true if this constraint is satisfied and processing - * should continue, or false otherwise. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraints Security constraint we are enforcing - * @param context The Context to which client of this class is attached. - * - * @exception IOException if an input/output error occurs - */ - public boolean hasResourcePermission(Request request, - Response response, - SecurityConstraint []constraints, - Context context) - throws IOException { - - if (constraints == null || constraints.length == 0) - return (true); - - // Specifically allow access to the form login and form error pages - // and the "j_security_check" action - LoginConfig config = context.getLoginConfig(); - if ((config != null) && - (Constants.FORM_METHOD.equals(config.getAuthMethod()))) { - String requestURI = request.getRequestPathMB().toString(); - String loginPage = config.getLoginPage(); - if (loginPage.equals(requestURI)) { - if (log.isDebugEnabled()) - log.debug(" Allow access to login page " + loginPage); - return (true); - } - String errorPage = config.getErrorPage(); - if (errorPage.equals(requestURI)) { - if (log.isDebugEnabled()) - log.debug(" Allow access to error page " + errorPage); - return (true); - } - if (requestURI.endsWith(Constants.FORM_ACTION)) { - if (log.isDebugEnabled()) - log.debug(" Allow access to username/password submission"); - return (true); - } - } - - // Which user principal have we already authenticated? - Principal principal = request.getPrincipal(); - boolean status = false; - boolean denyfromall = false; - for(int i=0; i < constraints.length; i++) { - SecurityConstraint constraint = constraints[i]; - - String roles[]; - if (constraint.getAllRoles()) { - // * means all roles defined in web.xml - roles = request.getContext().findSecurityRoles(); - } else { - roles = constraint.findAuthRoles(); - } - - if (roles == null) - roles = new String[0]; - - if (log.isDebugEnabled()) - log.debug(" Checking roles " + principal); - - if (roles.length == 0 && !constraint.getAllRoles()) { - if(constraint.getAuthConstraint()) { - if( log.isDebugEnabled() ) - log.debug("No roles "); - status = false; // No listed roles means no access at all - denyfromall = true; - } else { - if(log.isDebugEnabled()) - log.debug("Passing all access"); - return (true); - } - } else if (principal == null) { - if (log.isDebugEnabled()) - log.debug(" No user authenticated, cannot grant access"); - status = false; - } else if(!denyfromall) { - - for (int j = 0; j < roles.length; j++) { - if (hasRole(principal, roles[j])) - status = true; - if( log.isDebugEnabled() ) - log.debug( "No role found: " + roles[j]); - } - } - } - - if (allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) { - if (log.isDebugEnabled()) { - log.debug("Checking for all roles mode: " + allRolesMode); - } - // Check for an all roles(role-name="*") - for (int i = 0; i < constraints.length; i++) { - SecurityConstraint constraint = constraints[i]; - String roles[]; - // If the all roles mode exists, sets - if (constraint.getAllRoles()) { - if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) { - if (log.isDebugEnabled()) { - log.debug("Granting access for role-name=*, auth-only"); - } - status = true; - break; - } - - // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles - roles = request.getContext().findSecurityRoles(); - if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) { - if (log.isDebugEnabled()) { - log.debug("Granting access for role-name=*, strict auth-only"); - } - status = true; - break; - } - } - } - } - - // Return a "Forbidden" message denying access to this resource - if(!status) { - response.sendError - (HttpServletResponse.SC_FORBIDDEN, - sm.getString("realmBase.forbidden")); - } - return status; - - } - - - /** - * Return true if the specified Principal has the specified - * security role, within the context of this Realm; otherwise return - * false. This method can be overridden by Realm - * implementations, but the default is adequate when an instance of - * GenericPrincipal is used to represent authenticated - * Principals from this Realm. - * - * @param principal Principal for whom the role is to be checked - * @param role Security role to be checked - */ - public boolean hasRole(Principal principal, String role) { - - // Should be overriten in JAASRealm - to avoid pretty inefficient conversions - if ((principal == null) || (role == null) || - !(principal instanceof GenericPrincipal)) - return (false); - - GenericPrincipal gp = (GenericPrincipal) principal; - if (!(gp.getRealm() == this)) { - if(log.isDebugEnabled()) - log.debug("Different realm " + this + " " + gp.getRealm());// return (false); - } - boolean result = gp.hasRole(role); - if (log.isDebugEnabled()) { - String name = principal.getName(); - if (result) - log.debug(sm.getString("realmBase.hasRoleSuccess", name, role)); - else - log.debug(sm.getString("realmBase.hasRoleFailure", name, role)); - } - return (result); - - } - - - /** - * Enforce any user data constraint required by the security constraint - * guarding this request URI. Return true if this constraint - * was not violated and processing should continue, or false - * if we have created a response already. - * - * @param request Request we are processing - * @param response Response we are creating - * @param constraints Security constraint being checked - * - * @exception IOException if an input/output error occurs - */ - public boolean hasUserDataPermission(Request request, - Response response, - SecurityConstraint []constraints) - throws IOException { - - // Is there a relevant user data constraint? - if (constraints == null || constraints.length == 0) { - if (log.isDebugEnabled()) - log.debug(" No applicable security constraint defined"); - return (true); - } - for(int i=0; i < constraints.length; i++) { - SecurityConstraint constraint = constraints[i]; - String userConstraint = constraint.getUserConstraint(); - if (userConstraint == null) { - if (log.isDebugEnabled()) - log.debug(" No applicable user data constraint defined"); - return (true); - } - if (userConstraint.equals(Constants.NONE_TRANSPORT)) { - if (log.isDebugEnabled()) - log.debug(" User data constraint has no restrictions"); - return (true); - } - - } - // Validate the request against the user data constraint - if (request.getRequest().isSecure()) { - if (log.isDebugEnabled()) - log.debug(" User data constraint already satisfied"); - return (true); - } - // Initialize variables we need to determine the appropriate action - int redirectPort = request.getConnector().getRedirectPort(); - - // Is redirecting disabled? - if (redirectPort <= 0) { - if (log.isDebugEnabled()) - log.debug(" SSL redirect is disabled"); - response.sendError - (HttpServletResponse.SC_FORBIDDEN, - request.getRequestURI()); - return (false); - } - - // Redirect to the corresponding SSL port - StringBuffer file = new StringBuffer(); - String protocol = "https"; - String host = request.getServerName(); - // Protocol - file.append(protocol).append("://").append(host); - // Host with port - if(redirectPort != 443) { - file.append(":").append(redirectPort); - } - // URI - file.append(request.getRequestURI()); - String requestedSessionId = request.getRequestedSessionId(); - if ((requestedSessionId != null) && - request.isRequestedSessionIdFromURL()) { - file.append(";jsessionid="); - file.append(requestedSessionId); - } - String queryString = request.getQueryString(); - if (queryString != null) { - file.append('?'); - file.append(queryString); - } - if (log.isDebugEnabled()) - log.debug(" Redirecting to " + file.toString()); - response.sendRedirect(file.toString()); - return (false); - - } - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - - support.removePropertyChangeListener(listener); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called before any of the public - * methods of this component are utilized. It should also send a - * LifecycleEvent of type START_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) { - if(log.isInfoEnabled()) - log.info(sm.getString("realmBase.alreadyStarted")); - return; - } - if( !initialized ) { - init(); - } - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Create a MessageDigest instance for credentials, if desired - if (digest != null) { - try { - md = MessageDigest.getInstance(digest); - } catch (NoSuchAlgorithmException e) { - throw new LifecycleException - (sm.getString("realmBase.algorithm", digest), e); - } - } - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. It should also send a LifecycleEvent - * of type STOP_EVENT to any registered listeners. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() - throws LifecycleException { - - // Validate and update our current component state - if (!started) { - if(log.isInfoEnabled()) - log.info(sm.getString("realmBase.notStarted")); - return; - } - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Clean up allocated resources - md = null; - - destroy(); - - } - - public void destroy() { - - // unregister this realm - if ( oname!=null ) { - try { - Registry.getRegistry(null, null).unregisterComponent(oname); - if(log.isDebugEnabled()) - log.debug( "unregistering realm " + oname ); - } catch( Exception ex ) { - log.error( "Can't unregister realm " + oname, ex); - } - } - - } - - // ------------------------------------------------------ Protected Methods - - - /** - * Digest the password using the specified algorithm and - * convert the result to a corresponding hexadecimal string. - * If exception, the plain credentials string is returned. - * - * @param credentials Password or other credentials to use in - * authenticating this username - */ - protected String digest(String credentials) { - - // If no MessageDigest instance is specified, return unchanged - if (hasMessageDigest() == false) - return (credentials); - - // Digest the user credentials and return as hexadecimal - synchronized (this) { - try { - md.reset(); - - byte[] bytes = null; - if(getDigestEncoding() == null) { - bytes = credentials.getBytes(); - } else { - try { - bytes = credentials.getBytes(getDigestEncoding()); - } catch (UnsupportedEncodingException uee) { - log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); - throw new IllegalArgumentException(uee.getMessage()); - } - } - md.update(bytes); - - return (HexUtils.convert(md.digest())); - } catch (Exception e) { - log.error(sm.getString("realmBase.digest"), e); - return (credentials); - } - } - - } - - protected boolean hasMessageDigest() { - return !(md == null); - } - - /** - * Return the digest associated with given principal's user name. - */ - protected String getDigest(String username, String realmName) { - if (md5Helper == null) { - try { - md5Helper = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - log.error("Couldn't get MD5 digest: ", e); - throw new IllegalStateException(e.getMessage()); - } - } - - if (hasMessageDigest()) { - // Use pre-generated digest - return getPassword(username); - } - - String digestValue = username + ":" + realmName + ":" - + getPassword(username); - - byte[] valueBytes = null; - if(getDigestEncoding() == null) { - valueBytes = digestValue.getBytes(); - } else { - try { - valueBytes = digestValue.getBytes(getDigestEncoding()); - } catch (UnsupportedEncodingException uee) { - log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); - throw new IllegalArgumentException(uee.getMessage()); - } - } - - byte[] digest = null; - // Bugzilla 32137 - synchronized(md5Helper) { - digest = md5Helper.digest(valueBytes); - } - - return md5Encoder.encode(digest); - } - - - /** - * Return a short name for this Realm implementation, for use in - * log messages. - */ - protected abstract String getName(); - - - /** - * Return the password associated with the given principal's user name. - */ - protected abstract String getPassword(String username); - - - /** - * Return the Principal associated with the given certificate. - */ - protected Principal getPrincipal(X509Certificate usercert) { - return(getPrincipal(usercert.getSubjectDN().getName())); - } - - - /** - * Return the Principal associated with the given user name. - */ - protected abstract Principal getPrincipal(String username); - - - // --------------------------------------------------------- Static Methods - - - /** - * Digest password using the algorithm especificied and - * convert the result to a corresponding hex string. - * If exception, the plain credentials string is returned - * - * @param credentials Password or other credentials to use in - * authenticating this username - * @param algorithm Algorithm used to do the digest - * @param encoding Character encoding of the string to digest - */ - public final static String Digest(String credentials, String algorithm, - String encoding) { - - try { - // Obtain a new message digest with "digest" encryption - MessageDigest md = - (MessageDigest) MessageDigest.getInstance(algorithm).clone(); - - // encode the credentials - // Should use the digestEncoding, but that's not a static field - if (encoding == null) { - md.update(credentials.getBytes()); - } else { - md.update(credentials.getBytes(encoding)); - } - - // Digest the credentials and return as hexadecimal - return (HexUtils.convert(md.digest())); - } catch(Exception ex) { - log.error(ex); - return credentials; - } - - } - - - /** - * Digest password using the algorithm especificied and - * convert the result to a corresponding hex string. - * If exception, the plain credentials string is returned - */ - public static void main(String args[]) { - - String encoding = null; - int firstCredentialArg = 2; - - if (args.length > 4 && args[2].equalsIgnoreCase("-e")) { - encoding = args[3]; - firstCredentialArg = 4; - } - - if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) { - for(int i=firstCredentialArg; i < args.length ; i++){ - System.out.print(args[i]+":"); - System.out.println(Digest(args[i], args[1], encoding)); - } - } else { - System.out.println - ("Usage: RealmBase -a [-e ] "); - } - - } - - - // -------------------- JMX and Registration -------------------- - protected String type; - protected String domain; - protected String host; - protected String path; - protected ObjectName oname; - protected ObjectName controller; - protected MBeanServer mserver; - - public ObjectName getController() { - return controller; - } - - public void setController(ObjectName controller) { - this.controller = controller; - } - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public String getType() { - return type; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - - type=name.getKeyProperty("type"); - host=name.getKeyProperty("host"); - path=name.getKeyProperty("path"); - - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - protected boolean initialized=false; - - public void init() { - this.containerLog = container.getLogger(); - if( initialized && container != null ) return; - - initialized=true; - if( container== null ) { - ObjectName parent=null; - // Register with the parent - try { - if( host == null ) { - // global - parent=new ObjectName(domain +":type=Engine"); - } else if( path==null ) { - parent=new ObjectName(domain + - ":type=Host,host=" + host); - } else { - parent=new ObjectName(domain +":j2eeType=WebModule,name=//" + - host + path); - } - if( mserver.isRegistered(parent )) { - if(log.isDebugEnabled()) - log.debug("Register with " + parent); - mserver.setAttribute(parent, new Attribute("realm", this)); - } - } catch (Exception e) { - log.error("Parent not available yet: " + parent); - } - } - - if( oname==null ) { - // register - try { - ContainerBase cb=(ContainerBase)container; - oname=new ObjectName(cb.getDomain()+":type=Realm" + cb.getContainerSuffix()); - Registry.getRegistry(null, null).registerComponent(this, oname, null ); - if(log.isDebugEnabled()) - log.debug("Register Realm "+oname); - } catch (Throwable e) { - log.error( "Can't register " + oname, e); - } - } - - } - - - protected static class AllRolesMode { - - private String name; - /** Use the strict servlet spec interpretation which requires that the user - * have one of the web-app/security-role/role-name - */ - public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict"); - /** Allow any authenticated user - */ - public static final AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly"); - /** Allow any authenticated user only if there are no web-app/security-roles - */ - public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly"); - - static AllRolesMode toMode(String name) - { - AllRolesMode mode; - if( name.equalsIgnoreCase(STRICT_MODE.name) ) - mode = STRICT_MODE; - else if( name.equalsIgnoreCase(AUTH_ONLY_MODE.name) ) - mode = AUTH_ONLY_MODE; - else if( name.equalsIgnoreCase(STRICT_AUTH_ONLY_MODE.name) ) - mode = STRICT_AUTH_ONLY_MODE; - else - throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly"); - return mode; - } - - private AllRolesMode(String name) - { - this.name = name; - } - - public boolean equals(Object o) - { - boolean equals = false; - if( o instanceof AllRolesMode ) - { - AllRolesMode mode = (AllRolesMode) o; - equals = name.equals(mode.name); - } - return equals; - } - public int hashCode() - { - return name.hashCode(); - } - public String toString() - { - return name; - } - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.cert.X509Certificate; +import java.util.ArrayList; + +import javax.management.Attribute; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Realm; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.core.ContainerBase; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.deploy.SecurityCollection; +import org.apache.catalina.util.HexUtils; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.MD5Encoder; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.Registry; + +/** + * Simple implementation of Realm that reads an XML file to configure + * the valid users, passwords, and roles. The file format (and default file + * location) are identical to those currently supported by Tomcat 3.X. + * + * @author Craig R. McClanahan + * @version $Revision: 388949 $ $Date: 2006-03-26 21:55:03 +0200 (dim., 26 mars 2006) $ + */ + +public abstract class RealmBase + implements Lifecycle, Realm, MBeanRegistration { + + private static Log log = LogFactory.getLog(RealmBase.class); + + // ----------------------------------------------------- Instance Variables + + + /** + * The Container with which this Realm is associated. + */ + protected Container container = null; + + + /** + * Container log + */ + protected Log containerLog = null; + + + /** + * Digest algorithm used in storing passwords in a non-plaintext format. + * Valid values are those accepted for the algorithm name by the + * MessageDigest class, or null if no digesting should + * be performed. + */ + protected String digest = null; + + /** + * The encoding charset for the digest. + */ + protected String digestEncoding = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String info = + "org.apache.catalina.realm.RealmBase/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The MessageDigest object for digesting user credentials (passwords). + */ + protected MessageDigest md = null; + + + /** + * The MD5 helper object for this class. + */ + protected static final MD5Encoder md5Encoder = new MD5Encoder(); + + + /** + * MD5 message digest provider. + */ + protected static MessageDigest md5Helper; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started? + */ + protected boolean started = false; + + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + /** + * Should we validate client certificate chains when they are presented? + */ + protected boolean validate = true; + + + /** + * The all role mode. + */ + protected AllRolesMode allRolesMode = AllRolesMode.STRICT_MODE; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Container with which this Realm has been associated. + */ + public Container getContainer() { + + return (container); + + } + + + /** + * Set the Container with which this Realm has been associated. + * + * @param container The associated Container + */ + public void setContainer(Container container) { + + Container oldContainer = this.container; + this.container = container; + support.firePropertyChange("container", oldContainer, this.container); + + } + + /** + * Return the all roles mode. + */ + public String getAllRolesMode() { + + return allRolesMode.toString(); + + } + + + /** + * Set the all roles mode. + */ + public void setAllRolesMode(String allRolesMode) { + + this.allRolesMode = AllRolesMode.toMode(allRolesMode); + + } + + /** + * Return the digest algorithm used for storing credentials. + */ + public String getDigest() { + + return digest; + + } + + + /** + * Set the digest algorithm used for storing credentials. + * + * @param digest The new digest algorithm + */ + public void setDigest(String digest) { + + this.digest = digest; + + } + + /** + * Returns the digest encoding charset. + * + * @return The charset (may be null) for platform default + */ + public String getDigestEncoding() { + return digestEncoding; + } + + /** + * Sets the digest encoding charset. + * + * @param charset The charset (null for platform default) + */ + public void setDigestEncoding(String charset) { + digestEncoding = charset; + } + + /** + * Return descriptive information about this Realm implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return info; + + } + + + /** + * Return the "validate certificate chains" flag. + */ + public boolean getValidate() { + + return (this.validate); + + } + + + /** + * Set the "validate certificate chains" flag. + * + * @param validate The new validate certificate chains flag + */ + public void setValidate(boolean validate) { + + this.validate = validate; + + } + + + // --------------------------------------------------------- Public Methods + + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + + support.addPropertyChangeListener(listener); + + } + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, String credentials) { + + String serverCredentials = getPassword(username); + + boolean validated ; + if ( serverCredentials == null ) { + validated = false; + } else if(hasMessageDigest()) { + validated = serverCredentials.equalsIgnoreCase(digest(credentials)); + } else { + validated = serverCredentials.equals(credentials); + } + if(! validated ) { + if (containerLog.isTraceEnabled()) { + containerLog.trace(sm.getString("realmBase.authenticateFailure", + username)); + } + return null; + } + if (containerLog.isTraceEnabled()) { + containerLog.trace(sm.getString("realmBase.authenticateSuccess", + username)); + } + + return getPrincipal(username); + } + + + /** + * Return the Principal associated with the specified username and + * credentials, if there is one; otherwise return null. + * + * @param username Username of the Principal to look up + * @param credentials Password or other credentials to use in + * authenticating this username + */ + public Principal authenticate(String username, byte[] credentials) { + + return (authenticate(username, credentials.toString())); + + } + + + /** + * Return the Principal associated with the specified username, which + * matches the digest calculated using the given parameters using the + * method described in RFC 2069; otherwise return null. + * + * @param username Username of the Principal to look up + * @param clientDigest Digest which has been submitted by the client + * @param nOnce Unique (or supposedly unique) token which has been used + * for this request + * @param realm Realm name + * @param md5a2 Second MD5 digest used to calculate the digest : + * MD5(Method + ":" + uri) + */ + public Principal authenticate(String username, String clientDigest, + String nOnce, String nc, String cnonce, + String qop, String realm, + String md5a2) { + + String md5a1 = getDigest(username, realm); + if (md5a1 == null) + return null; + String serverDigestValue = md5a1 + ":" + nOnce + ":" + nc + ":" + + cnonce + ":" + qop + ":" + md5a2; + + byte[] valueBytes = null; + if(getDigestEncoding() == null) { + valueBytes = serverDigestValue.getBytes(); + } else { + try { + valueBytes = serverDigestValue.getBytes(getDigestEncoding()); + } catch (UnsupportedEncodingException uee) { + log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); + throw new IllegalArgumentException(uee.getMessage()); + } + } + + String serverDigest = null; + // Bugzilla 32137 + synchronized(md5Helper) { + serverDigest = md5Encoder.encode(md5Helper.digest(valueBytes)); + } + + if (log.isDebugEnabled()) { + log.debug("Digest : " + clientDigest + " Username:" + username + + " ClientSigest:" + clientDigest + " nOnce:" + nOnce + + " nc:" + nc + " cnonce:" + cnonce + " qop:" + qop + + " realm:" + realm + "md5a2:" + md5a2 + + " Server digest:" + serverDigest); + } + + if (serverDigest.equals(clientDigest)) + return getPrincipal(username); + else + return null; + } + + + + /** + * Return the Principal associated with the specified chain of X509 + * client certificates. If there is none, return null. + * + * @param certs Array of client certificates, with the first one in + * the array being the certificate of the client itself. + */ + public Principal authenticate(X509Certificate certs[]) { + + if ((certs == null) || (certs.length < 1)) + return (null); + + // Check the validity of each certificate in the chain + if (log.isDebugEnabled()) + log.debug("Authenticating client certificate chain"); + if (validate) { + for (int i = 0; i < certs.length; i++) { + if (log.isDebugEnabled()) + log.debug(" Checking validity for '" + + certs[i].getSubjectDN().getName() + "'"); + try { + certs[i].checkValidity(); + } catch (Exception e) { + if (log.isDebugEnabled()) + log.debug(" Validity exception", e); + return (null); + } + } + } + + // Check the existence of the client Principal in our database + return (getPrincipal(certs[0])); + + } + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + } + + + /** + * Return the SecurityConstraints configured to guard the request URI for + * this request, or null if there is no such constraint. + * + * @param request Request we are processing + * @param context Context the Request is mapped to + */ + public SecurityConstraint [] findSecurityConstraints(Request request, + Context context) { + + ArrayList results = null; + // Are there any defined security constraints? + SecurityConstraint constraints[] = context.findConstraints(); + if ((constraints == null) || (constraints.length == 0)) { + if (log.isDebugEnabled()) + log.debug(" No applicable constraints defined"); + return (null); + } + + // Check each defined security constraint + String uri = request.getRequestPathMB().toString(); + + String method = request.getMethod(); + int i; + boolean found = false; + for (i = 0; i < constraints.length; i++) { + SecurityCollection [] collection = constraints[i].findCollections(); + + // If collection is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( collection == null) { + continue; + } + + if (log.isDebugEnabled()) { + log.debug(" Checking constraint '" + constraints[i] + + "' against " + method + " " + uri + " --> " + + constraints[i].included(uri, method)); + } + + for(int j=0; j < collection.length; j++){ + String [] patterns = collection[j].findPatterns(); + + // If patterns is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( patterns == null) { + continue; + } + + for(int k=0; k < patterns.length; k++) { + if(uri.equals(patterns[k])) { + found = true; + if(collection[j].findMethod(method)) { + if(results == null) { + results = new ArrayList(); + } + results.add(constraints[i]); + } + } + } + } + } + + if(found) { + return resultsToArray(results); + } + + int longest = -1; + + for (i = 0; i < constraints.length; i++) { + SecurityCollection [] collection = constraints[i].findCollections(); + + // If collection is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( collection == null) { + continue; + } + + if (log.isDebugEnabled()) { + log.debug(" Checking constraint '" + constraints[i] + + "' against " + method + " " + uri + " --> " + + constraints[i].included(uri, method)); + } + + for(int j=0; j < collection.length; j++){ + String [] patterns = collection[j].findPatterns(); + + // If patterns is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( patterns == null) { + continue; + } + + boolean matched = false; + int length = -1; + for(int k=0; k < patterns.length; k++) { + String pattern = patterns[k]; + if(pattern.startsWith("/") && pattern.endsWith("/*") && + pattern.length() >= longest) { + + if(pattern.length() == 2) { + matched = true; + length = pattern.length(); + } else if(pattern.regionMatches(0,uri,0, + pattern.length()-1) || + (pattern.length()-2 == uri.length() && + pattern.regionMatches(0,uri,0, + pattern.length()-2))) { + matched = true; + length = pattern.length(); + } + } + } + if(matched) { + found = true; + if(length > longest) { + if(results != null) { + results.clear(); + } + longest = length; + } + if(collection[j].findMethod(method)) { + if(results == null) { + results = new ArrayList(); + } + results.add(constraints[i]); + } + } + } + } + + if(found) { + return resultsToArray(results); + } + + for (i = 0; i < constraints.length; i++) { + SecurityCollection [] collection = constraints[i].findCollections(); + + // If collection is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( collection == null) { + continue; + } + + if (log.isDebugEnabled()) { + log.debug(" Checking constraint '" + constraints[i] + + "' against " + method + " " + uri + " --> " + + constraints[i].included(uri, method)); + } + + boolean matched = false; + int pos = -1; + for(int j=0; j < collection.length; j++){ + String [] patterns = collection[j].findPatterns(); + + // If patterns is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( patterns == null) { + continue; + } + + for(int k=0; k < patterns.length && !matched; k++) { + String pattern = patterns[k]; + if(pattern.startsWith("*.")){ + int slash = uri.lastIndexOf("/"); + int dot = uri.lastIndexOf("."); + if(slash >= 0 && dot > slash && + dot != uri.length()-1 && + uri.length()-dot == pattern.length()-1) { + if(pattern.regionMatches(1,uri,dot,uri.length()-dot)) { + matched = true; + pos = j; + } + } + } + } + } + if(matched) { + found = true; + if(collection[pos].findMethod(method)) { + if(results == null) { + results = new ArrayList(); + } + results.add(constraints[i]); + } + } + } + + if(found) { + return resultsToArray(results); + } + + for (i = 0; i < constraints.length; i++) { + SecurityCollection [] collection = constraints[i].findCollections(); + + // If collection is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( collection == null) { + continue; + } + + if (log.isDebugEnabled()) { + log.debug(" Checking constraint '" + constraints[i] + + "' against " + method + " " + uri + " --> " + + constraints[i].included(uri, method)); + } + + for(int j=0; j < collection.length; j++){ + String [] patterns = collection[j].findPatterns(); + + // If patterns is null, continue to avoid an NPE + // See Bugzilla 30624 + if ( patterns == null) { + continue; + } + + boolean matched = false; + for(int k=0; k < patterns.length && !matched; k++) { + String pattern = patterns[k]; + if(pattern.equals("/")){ + matched = true; + } + } + if(matched) { + if(results == null) { + results = new ArrayList(); + } + results.add(constraints[i]); + } + } + } + + if(results == null) { + // No applicable security constraint was found + if (log.isDebugEnabled()) + log.debug(" No applicable constraint located"); + } + return resultsToArray(results); + } + + /** + * Convert an ArrayList to a SecurityContraint []. + */ + private SecurityConstraint [] resultsToArray(ArrayList results) { + if(results == null) { + return null; + } + SecurityConstraint [] array = new SecurityConstraint[results.size()]; + results.toArray(array); + return array; + } + + + /** + * Perform access control based on the specified authorization constraint. + * Return true if this constraint is satisfied and processing + * should continue, or false otherwise. + * + * @param request Request we are processing + * @param response Response we are creating + * @param constraints Security constraint we are enforcing + * @param context The Context to which client of this class is attached. + * + * @exception IOException if an input/output error occurs + */ + public boolean hasResourcePermission(Request request, + Response response, + SecurityConstraint []constraints, + Context context) + throws IOException { + + if (constraints == null || constraints.length == 0) + return (true); + + // Specifically allow access to the form login and form error pages + // and the "j_security_check" action + LoginConfig config = context.getLoginConfig(); + if ((config != null) && + (Constants.FORM_METHOD.equals(config.getAuthMethod()))) { + String requestURI = request.getRequestPathMB().toString(); + String loginPage = config.getLoginPage(); + if (loginPage.equals(requestURI)) { + if (log.isDebugEnabled()) + log.debug(" Allow access to login page " + loginPage); + return (true); + } + String errorPage = config.getErrorPage(); + if (errorPage.equals(requestURI)) { + if (log.isDebugEnabled()) + log.debug(" Allow access to error page " + errorPage); + return (true); + } + if (requestURI.endsWith(Constants.FORM_ACTION)) { + if (log.isDebugEnabled()) + log.debug(" Allow access to username/password submission"); + return (true); + } + } + + // Which user principal have we already authenticated? + Principal principal = request.getPrincipal(); + boolean status = false; + boolean denyfromall = false; + for(int i=0; i < constraints.length; i++) { + SecurityConstraint constraint = constraints[i]; + + String roles[]; + if (constraint.getAllRoles()) { + // * means all roles defined in web.xml + roles = request.getContext().findSecurityRoles(); + } else { + roles = constraint.findAuthRoles(); + } + + if (roles == null) + roles = new String[0]; + + if (log.isDebugEnabled()) + log.debug(" Checking roles " + principal); + + if (roles.length == 0 && !constraint.getAllRoles()) { + if(constraint.getAuthConstraint()) { + if( log.isDebugEnabled() ) + log.debug("No roles "); + status = false; // No listed roles means no access at all + denyfromall = true; + } else { + if(log.isDebugEnabled()) + log.debug("Passing all access"); + return (true); + } + } else if (principal == null) { + if (log.isDebugEnabled()) + log.debug(" No user authenticated, cannot grant access"); + status = false; + } else if(!denyfromall) { + + for (int j = 0; j < roles.length; j++) { + if (hasRole(principal, roles[j])) + status = true; + if( log.isDebugEnabled() ) + log.debug( "No role found: " + roles[j]); + } + } + } + + if (allRolesMode != AllRolesMode.STRICT_MODE && !status && principal != null) { + if (log.isDebugEnabled()) { + log.debug("Checking for all roles mode: " + allRolesMode); + } + // Check for an all roles(role-name="*") + for (int i = 0; i < constraints.length; i++) { + SecurityConstraint constraint = constraints[i]; + String roles[]; + // If the all roles mode exists, sets + if (constraint.getAllRoles()) { + if (allRolesMode == AllRolesMode.AUTH_ONLY_MODE) { + if (log.isDebugEnabled()) { + log.debug("Granting access for role-name=*, auth-only"); + } + status = true; + break; + } + + // For AllRolesMode.STRICT_AUTH_ONLY_MODE there must be zero roles + roles = request.getContext().findSecurityRoles(); + if (roles.length == 0 && allRolesMode == AllRolesMode.STRICT_AUTH_ONLY_MODE) { + if (log.isDebugEnabled()) { + log.debug("Granting access for role-name=*, strict auth-only"); + } + status = true; + break; + } + } + } + } + + // Return a "Forbidden" message denying access to this resource + if(!status) { + response.sendError + (HttpServletResponse.SC_FORBIDDEN, + sm.getString("realmBase.forbidden")); + } + return status; + + } + + + /** + * Return true if the specified Principal has the specified + * security role, within the context of this Realm; otherwise return + * false. This method can be overridden by Realm + * implementations, but the default is adequate when an instance of + * GenericPrincipal is used to represent authenticated + * Principals from this Realm. + * + * @param principal Principal for whom the role is to be checked + * @param role Security role to be checked + */ + public boolean hasRole(Principal principal, String role) { + + // Should be overriten in JAASRealm - to avoid pretty inefficient conversions + if ((principal == null) || (role == null) || + !(principal instanceof GenericPrincipal)) + return (false); + + GenericPrincipal gp = (GenericPrincipal) principal; + if (!(gp.getRealm() == this)) { + if(log.isDebugEnabled()) + log.debug("Different realm " + this + " " + gp.getRealm());// return (false); + } + boolean result = gp.hasRole(role); + if (log.isDebugEnabled()) { + String name = principal.getName(); + if (result) + log.debug(sm.getString("realmBase.hasRoleSuccess", name, role)); + else + log.debug(sm.getString("realmBase.hasRoleFailure", name, role)); + } + return (result); + + } + + + /** + * Enforce any user data constraint required by the security constraint + * guarding this request URI. Return true if this constraint + * was not violated and processing should continue, or false + * if we have created a response already. + * + * @param request Request we are processing + * @param response Response we are creating + * @param constraints Security constraint being checked + * + * @exception IOException if an input/output error occurs + */ + public boolean hasUserDataPermission(Request request, + Response response, + SecurityConstraint []constraints) + throws IOException { + + // Is there a relevant user data constraint? + if (constraints == null || constraints.length == 0) { + if (log.isDebugEnabled()) + log.debug(" No applicable security constraint defined"); + return (true); + } + for(int i=0; i < constraints.length; i++) { + SecurityConstraint constraint = constraints[i]; + String userConstraint = constraint.getUserConstraint(); + if (userConstraint == null) { + if (log.isDebugEnabled()) + log.debug(" No applicable user data constraint defined"); + return (true); + } + if (userConstraint.equals(Constants.NONE_TRANSPORT)) { + if (log.isDebugEnabled()) + log.debug(" User data constraint has no restrictions"); + return (true); + } + + } + // Validate the request against the user data constraint + if (request.getRequest().isSecure()) { + if (log.isDebugEnabled()) + log.debug(" User data constraint already satisfied"); + return (true); + } + // Initialize variables we need to determine the appropriate action + int redirectPort = request.getConnector().getRedirectPort(); + + // Is redirecting disabled? + if (redirectPort <= 0) { + if (log.isDebugEnabled()) + log.debug(" SSL redirect is disabled"); + response.sendError + (HttpServletResponse.SC_FORBIDDEN, + request.getRequestURI()); + return (false); + } + + // Redirect to the corresponding SSL port + StringBuffer file = new StringBuffer(); + String protocol = "https"; + String host = request.getServerName(); + // Protocol + file.append(protocol).append("://").append(host); + // Host with port + if(redirectPort != 443) { + file.append(":").append(redirectPort); + } + // URI + file.append(request.getRequestURI()); + String requestedSessionId = request.getRequestedSessionId(); + if ((requestedSessionId != null) && + request.isRequestedSessionIdFromURL()) { + file.append(";jsessionid="); + file.append(requestedSessionId); + } + String queryString = request.getQueryString(); + if (queryString != null) { + file.append('?'); + file.append(queryString); + } + if (log.isDebugEnabled()) + log.debug(" Redirecting to " + file.toString()); + response.sendRedirect(file.toString()); + return (false); + + } + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + + support.removePropertyChangeListener(listener); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called before any of the public + * methods of this component are utilized. It should also send a + * LifecycleEvent of type START_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) { + if(log.isInfoEnabled()) + log.info(sm.getString("realmBase.alreadyStarted")); + return; + } + if( !initialized ) { + init(); + } + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Create a MessageDigest instance for credentials, if desired + if (digest != null) { + try { + md = MessageDigest.getInstance(digest); + } catch (NoSuchAlgorithmException e) { + throw new LifecycleException + (sm.getString("realmBase.algorithm", digest), e); + } + } + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. It should also send a LifecycleEvent + * of type STOP_EVENT to any registered listeners. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() + throws LifecycleException { + + // Validate and update our current component state + if (!started) { + if(log.isInfoEnabled()) + log.info(sm.getString("realmBase.notStarted")); + return; + } + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Clean up allocated resources + md = null; + + destroy(); + + } + + public void destroy() { + + // unregister this realm + if ( oname!=null ) { + try { + Registry.getRegistry(null, null).unregisterComponent(oname); + if(log.isDebugEnabled()) + log.debug( "unregistering realm " + oname ); + } catch( Exception ex ) { + log.error( "Can't unregister realm " + oname, ex); + } + } + + } + + // ------------------------------------------------------ Protected Methods + + + /** + * Digest the password using the specified algorithm and + * convert the result to a corresponding hexadecimal string. + * If exception, the plain credentials string is returned. + * + * @param credentials Password or other credentials to use in + * authenticating this username + */ + protected String digest(String credentials) { + + // If no MessageDigest instance is specified, return unchanged + if (hasMessageDigest() == false) + return (credentials); + + // Digest the user credentials and return as hexadecimal + synchronized (this) { + try { + md.reset(); + + byte[] bytes = null; + if(getDigestEncoding() == null) { + bytes = credentials.getBytes(); + } else { + try { + bytes = credentials.getBytes(getDigestEncoding()); + } catch (UnsupportedEncodingException uee) { + log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); + throw new IllegalArgumentException(uee.getMessage()); + } + } + md.update(bytes); + + return (HexUtils.convert(md.digest())); + } catch (Exception e) { + log.error(sm.getString("realmBase.digest"), e); + return (credentials); + } + } + + } + + protected boolean hasMessageDigest() { + return !(md == null); + } + + /** + * Return the digest associated with given principal's user name. + */ + protected String getDigest(String username, String realmName) { + if (md5Helper == null) { + try { + md5Helper = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + log.error("Couldn't get MD5 digest: ", e); + throw new IllegalStateException(e.getMessage()); + } + } + + if (hasMessageDigest()) { + // Use pre-generated digest + return getPassword(username); + } + + String digestValue = username + ":" + realmName + ":" + + getPassword(username); + + byte[] valueBytes = null; + if(getDigestEncoding() == null) { + valueBytes = digestValue.getBytes(); + } else { + try { + valueBytes = digestValue.getBytes(getDigestEncoding()); + } catch (UnsupportedEncodingException uee) { + log.error("Illegal digestEncoding: " + getDigestEncoding(), uee); + throw new IllegalArgumentException(uee.getMessage()); + } + } + + byte[] digest = null; + // Bugzilla 32137 + synchronized(md5Helper) { + digest = md5Helper.digest(valueBytes); + } + + return md5Encoder.encode(digest); + } + + + /** + * Return a short name for this Realm implementation, for use in + * log messages. + */ + protected abstract String getName(); + + + /** + * Return the password associated with the given principal's user name. + */ + protected abstract String getPassword(String username); + + + /** + * Return the Principal associated with the given certificate. + */ + protected Principal getPrincipal(X509Certificate usercert) { + return(getPrincipal(usercert.getSubjectDN().getName())); + } + + + /** + * Return the Principal associated with the given user name. + */ + protected abstract Principal getPrincipal(String username); + + + // --------------------------------------------------------- Static Methods + + + /** + * Digest password using the algorithm especificied and + * convert the result to a corresponding hex string. + * If exception, the plain credentials string is returned + * + * @param credentials Password or other credentials to use in + * authenticating this username + * @param algorithm Algorithm used to do the digest + * @param encoding Character encoding of the string to digest + */ + public final static String Digest(String credentials, String algorithm, + String encoding) { + + try { + // Obtain a new message digest with "digest" encryption + MessageDigest md = + (MessageDigest) MessageDigest.getInstance(algorithm).clone(); + + // encode the credentials + // Should use the digestEncoding, but that's not a static field + if (encoding == null) { + md.update(credentials.getBytes()); + } else { + md.update(credentials.getBytes(encoding)); + } + + // Digest the credentials and return as hexadecimal + return (HexUtils.convert(md.digest())); + } catch(Exception ex) { + log.error(ex); + return credentials; + } + + } + + + /** + * Digest password using the algorithm especificied and + * convert the result to a corresponding hex string. + * If exception, the plain credentials string is returned + */ + public static void main(String args[]) { + + String encoding = null; + int firstCredentialArg = 2; + + if (args.length > 4 && args[2].equalsIgnoreCase("-e")) { + encoding = args[3]; + firstCredentialArg = 4; + } + + if(args.length > firstCredentialArg && args[0].equalsIgnoreCase("-a")) { + for(int i=firstCredentialArg; i < args.length ; i++){ + System.out.print(args[i]+":"); + System.out.println(Digest(args[i], args[1], encoding)); + } + } else { + System.out.println + ("Usage: RealmBase -a [-e ] "); + } + + } + + + // -------------------- JMX and Registration -------------------- + protected String type; + protected String domain; + protected String host; + protected String path; + protected ObjectName oname; + protected ObjectName controller; + protected MBeanServer mserver; + + public ObjectName getController() { + return controller; + } + + public void setController(ObjectName controller) { + this.controller = controller; + } + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public String getType() { + return type; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + + type=name.getKeyProperty("type"); + host=name.getKeyProperty("host"); + path=name.getKeyProperty("path"); + + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + protected boolean initialized=false; + + public void init() { + this.containerLog = container.getLogger(); + if( initialized && container != null ) return; + + initialized=true; + if( container== null ) { + ObjectName parent=null; + // Register with the parent + try { + if( host == null ) { + // global + parent=new ObjectName(domain +":type=Engine"); + } else if( path==null ) { + parent=new ObjectName(domain + + ":type=Host,host=" + host); + } else { + parent=new ObjectName(domain +":j2eeType=WebModule,name=//" + + host + path); + } + if( mserver.isRegistered(parent )) { + if(log.isDebugEnabled()) + log.debug("Register with " + parent); + mserver.setAttribute(parent, new Attribute("realm", this)); + } + } catch (Exception e) { + log.error("Parent not available yet: " + parent); + } + } + + if( oname==null ) { + // register + try { + ContainerBase cb=(ContainerBase)container; + oname=new ObjectName(cb.getDomain()+":type=Realm" + cb.getContainerSuffix()); + Registry.getRegistry(null, null).registerComponent(this, oname, null ); + if(log.isDebugEnabled()) + log.debug("Register Realm "+oname); + } catch (Throwable e) { + log.error( "Can't register " + oname, e); + } + } + + } + + + protected static class AllRolesMode { + + private String name; + /** Use the strict servlet spec interpretation which requires that the user + * have one of the web-app/security-role/role-name + */ + public static final AllRolesMode STRICT_MODE = new AllRolesMode("strict"); + /** Allow any authenticated user + */ + public static final AllRolesMode AUTH_ONLY_MODE = new AllRolesMode("authOnly"); + /** Allow any authenticated user only if there are no web-app/security-roles + */ + public static final AllRolesMode STRICT_AUTH_ONLY_MODE = new AllRolesMode("strictAuthOnly"); + + static AllRolesMode toMode(String name) + { + AllRolesMode mode; + if( name.equalsIgnoreCase(STRICT_MODE.name) ) + mode = STRICT_MODE; + else if( name.equalsIgnoreCase(AUTH_ONLY_MODE.name) ) + mode = AUTH_ONLY_MODE; + else if( name.equalsIgnoreCase(STRICT_AUTH_ONLY_MODE.name) ) + mode = STRICT_AUTH_ONLY_MODE; + else + throw new IllegalStateException("Unknown mode, must be one of: strict, authOnly, strictAuthOnly"); + return mode; + } + + private AllRolesMode(String name) + { + this.name = name; + } + + public boolean equals(Object o) + { + boolean equals = false; + if( o instanceof AllRolesMode ) + { + AllRolesMode mode = (AllRolesMode) o; + equals = name.equals(mode.name); + } + return equals; + } + public int hashCode() + { + return name.hashCode(); + } + public String toString() + { + return name; + } + } + +} diff --git a/java/org/apache/catalina/realm/UserDatabaseRealm.java b/java/org/apache/catalina/realm/UserDatabaseRealm.java index 2dfb83e79..af32b5177 100644 --- a/java/org/apache/catalina/realm/UserDatabaseRealm.java +++ b/java/org/apache/catalina/realm/UserDatabaseRealm.java @@ -1,285 +1,285 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.realm; - - -import java.security.Principal; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.naming.Context; - -import org.apache.catalina.Group; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Role; -import org.apache.catalina.ServerFactory; -import org.apache.catalina.User; -import org.apache.catalina.UserDatabase; -import org.apache.catalina.core.StandardServer; -import org.apache.catalina.users.MemoryUser; -import org.apache.catalina.util.StringManager; - - -/** - *

    Implementation of {@link org.apache.catalina.Realm} that is based on an implementation of - * {@link UserDatabase} made available through the global JNDI resources - * configured for this instance of Catalina. Set the resourceName - * parameter to the global JNDI resources name for the configured instance - * of UserDatabase that we should consult.

    - * - * @author Craig R. McClanahan - * @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ - * @since 4.1 - */ - -public class UserDatabaseRealm - extends RealmBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The UserDatabase we will use to authenticate users - * and identify associated roles. - */ - protected UserDatabase database = null; - - - /** - * Descriptive information about this Realm implementation. - */ - protected final String info = - "org.apache.catalina.realm.UserDatabaseRealm/1.0"; - - - /** - * Descriptive information about this Realm implementation. - */ - protected static final String name = "UserDatabaseRealm"; - - - /** - * The global JNDI name of the UserDatabase resource - * we will be utilizing. - */ - protected String resourceName = "UserDatabase"; - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Realm implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return info; - - } - - - /** - * Return the global JNDI name of the UserDatabase resource - * we will be using. - */ - public String getResourceName() { - - return resourceName; - - } - - - /** - * Set the global JNDI name of the UserDatabase resource - * we will be using. - * - * @param resourceName The new global JNDI name - */ - public void setResourceName(String resourceName) { - - this.resourceName = resourceName; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return true if the specified Principal has the specified - * security role, within the context of this Realm; otherwise return - * false. This implementation returns true - * if the User has the role, or if any Group - * that the User is a member of has the role. - * - * @param principal Principal for whom the role is to be checked - * @param role Security role to be checked - */ - public boolean hasRole(Principal principal, String role) { - if( principal instanceof GenericPrincipal) { - GenericPrincipal gp = (GenericPrincipal)principal; - if(gp.getUserPrincipal() instanceof User) { - principal = gp.getUserPrincipal(); - } - } - if(! (principal instanceof User) ) { - //Play nice with SSO and mixed Realms - return super.hasRole(principal, role); - } - if("*".equals(role)) { - return true; - } else if(role == null) { - return false; - } - User user = (User)principal; - Role dbrole = database.findRole(role); - if(dbrole == null) { - return false; - } - if(user.isInRole(dbrole)) { - return true; - } - Iterator groups = user.getGroups(); - while(groups.hasNext()) { - Group group = (Group)groups.next(); - if(group.isInRole(dbrole)) { - return true; - } - } - return false; - } - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a short name for this Realm implementation. - */ - protected String getName() { - - return (name); - - } - - - /** - * Return the password associated with the given principal's user name. - */ - protected String getPassword(String username) { - - User user = database.findUser(username); - - if (user == null) { - return null; - } - - return (user.getPassword()); - - } - - - /** - * Return the Principal associated with the given user name. - */ - protected Principal getPrincipal(String username) { - - User user = database.findUser(username); - if(user == null) { - return null; - } - - List roles = new ArrayList(); - Iterator uroles = user.getRoles(); - while(uroles.hasNext()) { - Role role = (Role)uroles.next(); - roles.add(role.getName()); - } - Iterator groups = user.getGroups(); - while(groups.hasNext()) { - Group group = (Group)groups.next(); - uroles = user.getRoles(); - while(uroles.hasNext()) { - Role role = (Role)uroles.next(); - roles.add(role.getName()); - } - } - return new GenericPrincipal(this, username, user.getPassword(), roles, user); - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Prepare for active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents it from being started - */ - public synchronized void start() throws LifecycleException { - - // Perform normal superclass initialization - super.start(); - - try { - StandardServer server = (StandardServer) ServerFactory.getServer(); - Context context = server.getGlobalNamingContext(); - database = (UserDatabase) context.lookup(resourceName); - } catch (Throwable e) { - containerLog.error(sm.getString("userDatabaseRealm.lookup", - resourceName), - e); - database = null; - } - if (database == null) { - throw new LifecycleException - (sm.getString("userDatabaseRealm.noDatabase", resourceName)); - } - - } - - - /** - * Gracefully shut down active use of the public methods of this Component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public synchronized void stop() throws LifecycleException { - - // Perform normal superclass finalization - super.stop(); - - // Release reference to our user database - database = null; - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.realm; + + +import java.security.Principal; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.naming.Context; + +import org.apache.catalina.Group; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Role; +import org.apache.catalina.ServerFactory; +import org.apache.catalina.User; +import org.apache.catalina.UserDatabase; +import org.apache.catalina.core.StandardServer; +import org.apache.catalina.users.MemoryUser; +import org.apache.catalina.util.StringManager; + + +/** + *

    Implementation of {@link org.apache.catalina.Realm} that is based on an implementation of + * {@link UserDatabase} made available through the global JNDI resources + * configured for this instance of Catalina. Set the resourceName + * parameter to the global JNDI resources name for the configured instance + * of UserDatabase that we should consult.

    + * + * @author Craig R. McClanahan + * @version $Revision: 373023 $ $Date: 2006-01-28 00:17:43 +0100 (sam., 28 janv. 2006) $ + * @since 4.1 + */ + +public class UserDatabaseRealm + extends RealmBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The UserDatabase we will use to authenticate users + * and identify associated roles. + */ + protected UserDatabase database = null; + + + /** + * Descriptive information about this Realm implementation. + */ + protected final String info = + "org.apache.catalina.realm.UserDatabaseRealm/1.0"; + + + /** + * Descriptive information about this Realm implementation. + */ + protected static final String name = "UserDatabaseRealm"; + + + /** + * The global JNDI name of the UserDatabase resource + * we will be utilizing. + */ + protected String resourceName = "UserDatabase"; + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Realm implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return info; + + } + + + /** + * Return the global JNDI name of the UserDatabase resource + * we will be using. + */ + public String getResourceName() { + + return resourceName; + + } + + + /** + * Set the global JNDI name of the UserDatabase resource + * we will be using. + * + * @param resourceName The new global JNDI name + */ + public void setResourceName(String resourceName) { + + this.resourceName = resourceName; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return true if the specified Principal has the specified + * security role, within the context of this Realm; otherwise return + * false. This implementation returns true + * if the User has the role, or if any Group + * that the User is a member of has the role. + * + * @param principal Principal for whom the role is to be checked + * @param role Security role to be checked + */ + public boolean hasRole(Principal principal, String role) { + if( principal instanceof GenericPrincipal) { + GenericPrincipal gp = (GenericPrincipal)principal; + if(gp.getUserPrincipal() instanceof User) { + principal = gp.getUserPrincipal(); + } + } + if(! (principal instanceof User) ) { + //Play nice with SSO and mixed Realms + return super.hasRole(principal, role); + } + if("*".equals(role)) { + return true; + } else if(role == null) { + return false; + } + User user = (User)principal; + Role dbrole = database.findRole(role); + if(dbrole == null) { + return false; + } + if(user.isInRole(dbrole)) { + return true; + } + Iterator groups = user.getGroups(); + while(groups.hasNext()) { + Group group = (Group)groups.next(); + if(group.isInRole(dbrole)) { + return true; + } + } + return false; + } + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a short name for this Realm implementation. + */ + protected String getName() { + + return (name); + + } + + + /** + * Return the password associated with the given principal's user name. + */ + protected String getPassword(String username) { + + User user = database.findUser(username); + + if (user == null) { + return null; + } + + return (user.getPassword()); + + } + + + /** + * Return the Principal associated with the given user name. + */ + protected Principal getPrincipal(String username) { + + User user = database.findUser(username); + if(user == null) { + return null; + } + + List roles = new ArrayList(); + Iterator uroles = user.getRoles(); + while(uroles.hasNext()) { + Role role = (Role)uroles.next(); + roles.add(role.getName()); + } + Iterator groups = user.getGroups(); + while(groups.hasNext()) { + Group group = (Group)groups.next(); + uroles = user.getRoles(); + while(uroles.hasNext()) { + Role role = (Role)uroles.next(); + roles.add(role.getName()); + } + } + return new GenericPrincipal(this, username, user.getPassword(), roles, user); + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Prepare for active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents it from being started + */ + public synchronized void start() throws LifecycleException { + + // Perform normal superclass initialization + super.start(); + + try { + StandardServer server = (StandardServer) ServerFactory.getServer(); + Context context = server.getGlobalNamingContext(); + database = (UserDatabase) context.lookup(resourceName); + } catch (Throwable e) { + containerLog.error(sm.getString("userDatabaseRealm.lookup", + resourceName), + e); + database = null; + } + if (database == null) { + throw new LifecycleException + (sm.getString("userDatabaseRealm.noDatabase", resourceName)); + } + + } + + + /** + * Gracefully shut down active use of the public methods of this Component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public synchronized void stop() throws LifecycleException { + + // Perform normal superclass finalization + super.stop(); + + // Release reference to our user database + database = null; + + } + + +} diff --git a/java/org/apache/catalina/realm/mbeans-descriptors.xml b/java/org/apache/catalina/realm/mbeans-descriptors.xml index f733a6b5a..21eb3b726 100644 --- a/java/org/apache/catalina/realm/mbeans-descriptors.xml +++ b/java/org/apache/catalina/realm/mbeans-descriptors.xml @@ -1,298 +1,298 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/realm/package.html b/java/org/apache/catalina/realm/package.html index e66a44cef..f6efcfe73 100644 --- a/java/org/apache/catalina/realm/package.html +++ b/java/org/apache/catalina/realm/package.html @@ -1,64 +1,64 @@ - - -

    This package contains Realm implementations for the -various supported realm technologies for authenticating users and -identifying their associated roles. The Realm that is -associated with a web application's Context (or a hierarchically -superior Container) is used to resolve authentication and role presence -questions when a web application uses container managed security as described -in the Servlet API Specification, version 2.2.

    - -

    The implementations share a common base class that supports basic -functionality for all of the standard Realm implementations, -and can be configured by setting the following properties (default values -are in square brackets):

    -
      -
    • debug - Debugging detail level for this component. [0]
    • -
    - -

    The standard Realm implementations that are currently -available include the following (with additional configuration properties -as specified):

    -
      -
    • JDBCRealm - Implementation of Realm that operates - from data stored in a relational database that is accessed via a JDBC - driver. The name of the driver, database connection information, and - the names of the relevant tables and columns are configured with the - following additional properties: -
        -
      • connectionURL - The URL to use when connecting to this database. - [REQUIRED - NO DEFAULT]
      • -
      • driverName - Fully qualified Java class name of the JDBC driver - to be used. [REQUIRED - NO DEFAULT]
      • -
      • roleNameCol - Name of the database column that contains role - names. [REQUIRED - NO DEFAULT]
      • -
      • userCredCol - Name of the database column that contains the - user's credentials (i.e. password) in cleartext. [REQUIRED - - NO DEFAULT]
      • -
      • userNameCol - Name of the database column that contains the - user's logon username. [REQUIRED - NO DEFAULT]
      • -
      • userRoleTable - Name of the database table containing user - role information. This table must include the columns specified by - the userNameCol and roleNameCol properties. - [REQUIRED - NO DEFAULT]
      • -
      • userTable - Name of the database table containing user - information. This table must include the columns specified by the - userNameCol and userCredCol properties. - [REQUIRED - NO DEFAULT]
      • -
      -
    • -
    • MemoryRealm - Implementation of Realm that uses the - contents of a simple XML file (conf/tomcat-users.xml) as the - list of valid users and their roles. This implementation is primarily to - demonstrate that the authentication technology functions correctly, and is - not anticipated as adequate for general purpose use. This component - supports the following additional properties: -
        -
      • pathname - Pathname of the XML file containing our user and - role information. If a relative pathname is specified, it is resolved - against the pathname specified by the "catalina.home" system property. - [conf/tomcat-users.xml]
      • -
      -
    - - + + +

    This package contains Realm implementations for the +various supported realm technologies for authenticating users and +identifying their associated roles. The Realm that is +associated with a web application's Context (or a hierarchically +superior Container) is used to resolve authentication and role presence +questions when a web application uses container managed security as described +in the Servlet API Specification, version 2.2.

    + +

    The implementations share a common base class that supports basic +functionality for all of the standard Realm implementations, +and can be configured by setting the following properties (default values +are in square brackets):

    +
      +
    • debug - Debugging detail level for this component. [0]
    • +
    + +

    The standard Realm implementations that are currently +available include the following (with additional configuration properties +as specified):

    +
      +
    • JDBCRealm - Implementation of Realm that operates + from data stored in a relational database that is accessed via a JDBC + driver. The name of the driver, database connection information, and + the names of the relevant tables and columns are configured with the + following additional properties: +
        +
      • connectionURL - The URL to use when connecting to this database. + [REQUIRED - NO DEFAULT]
      • +
      • driverName - Fully qualified Java class name of the JDBC driver + to be used. [REQUIRED - NO DEFAULT]
      • +
      • roleNameCol - Name of the database column that contains role + names. [REQUIRED - NO DEFAULT]
      • +
      • userCredCol - Name of the database column that contains the + user's credentials (i.e. password) in cleartext. [REQUIRED - + NO DEFAULT]
      • +
      • userNameCol - Name of the database column that contains the + user's logon username. [REQUIRED - NO DEFAULT]
      • +
      • userRoleTable - Name of the database table containing user + role information. This table must include the columns specified by + the userNameCol and roleNameCol properties. + [REQUIRED - NO DEFAULT]
      • +
      • userTable - Name of the database table containing user + information. This table must include the columns specified by the + userNameCol and userCredCol properties. + [REQUIRED - NO DEFAULT]
      • +
      +
    • +
    • MemoryRealm - Implementation of Realm that uses the + contents of a simple XML file (conf/tomcat-users.xml) as the + list of valid users and their roles. This implementation is primarily to + demonstrate that the authentication technology functions correctly, and is + not anticipated as adequate for general purpose use. This component + supports the following additional properties: +
        +
      • pathname - Pathname of the XML file containing our user and + role information. If a relative pathname is specified, it is resolved + against the pathname specified by the "catalina.home" system property. + [conf/tomcat-users.xml]
      • +
      +
    + + diff --git a/java/org/apache/catalina/security/LocalStrings.properties b/java/org/apache/catalina/security/LocalStrings.properties index 0d6026075..443fd394e 100644 --- a/java/org/apache/catalina/security/LocalStrings.properties +++ b/java/org/apache/catalina/security/LocalStrings.properties @@ -1,2 +1,2 @@ -SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block. - +SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block. + diff --git a/java/org/apache/catalina/security/LocalStrings_es.properties b/java/org/apache/catalina/security/LocalStrings_es.properties index 08f9abd9c..a05aaf1db 100644 --- a/java/org/apache/catalina/security/LocalStrings_es.properties +++ b/java/org/apache/catalina/security/LocalStrings_es.properties @@ -1,2 +1,2 @@ -SecurityUtil.doAsPrivilege=Ha tenido lugar una excepción al ejecutar el bloque PrivilegedExceptionAction. - +SecurityUtil.doAsPrivilege=Ha tenido lugar una excepción al ejecutar el bloque PrivilegedExceptionAction. + diff --git a/java/org/apache/catalina/security/LocalStrings_fr.properties b/java/org/apache/catalina/security/LocalStrings_fr.properties index 664c81ab0..d1990353b 100644 --- a/java/org/apache/catalina/security/LocalStrings_fr.properties +++ b/java/org/apache/catalina/security/LocalStrings_fr.properties @@ -1,2 +1,2 @@ -SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''exécution du bloc "PrivilegedExceptionAction". - +SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''exécution du bloc "PrivilegedExceptionAction". + diff --git a/java/org/apache/catalina/security/LocalStrings_ja.properties b/java/org/apache/catalina/security/LocalStrings_ja.properties index 03b24be68..4e4af3055 100644 --- a/java/org/apache/catalina/security/LocalStrings_ja.properties +++ b/java/org/apache/catalina/security/LocalStrings_ja.properties @@ -1,2 +1,2 @@ -SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 - +SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 + diff --git a/java/org/apache/catalina/security/SecurityClassLoad.java b/java/org/apache/catalina/security/SecurityClassLoad.java index bc07af66b..8912a770c 100644 --- a/java/org/apache/catalina/security/SecurityClassLoad.java +++ b/java/org/apache/catalina/security/SecurityClassLoad.java @@ -1,201 +1,201 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.security; - -/** - * Static class used to preload java classes when using the - * Java SecurityManager so that the defineClassInPackage - * RuntimePermission does not trigger an AccessControlException. - * - * @author Glenn L. Nielsen - * @author Jean-Francois Arcand - * @version $Revision: 304042 $ $Date: 2005-08-04 08:07:46 +0200 (jeu., 04 août 2005) $ - */ - -public final class SecurityClassLoad { - - public static void securityClassLoad(ClassLoader loader) - throws Exception { - - if( System.getSecurityManager() == null ){ - return; - } - - loadCorePackage(loader); - loadLoaderPackage(loader); - loadSessionPackage(loader); - loadUtilPackage(loader); - loadJavaxPackage(loader); - loadCoyotePackage(loader); - loadHttp11Package(loader); - } - - - private final static void loadCorePackage(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.catalina."; - loader.loadClass - (basePackage + - "core.ApplicationContextFacade$1"); - loader.loadClass - (basePackage + - "core.ApplicationDispatcher$PrivilegedForward"); - loader.loadClass - (basePackage + - "core.ApplicationDispatcher$PrivilegedInclude"); - loader.loadClass - (basePackage + - "core.ContainerBase$PrivilegedAddChild"); - loader.loadClass - (basePackage + - "core.StandardWrapper$1"); - } - - - private final static void loadLoaderPackage(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.catalina."; - loader.loadClass - (basePackage + - "loader.WebappClassLoader$PrivilegedFindResource"); - } - - - private final static void loadSessionPackage(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.catalina."; - loader.loadClass - (basePackage + "session.StandardSession"); - loader.loadClass - (basePackage + - "session.StandardSession$1"); - loader.loadClass - (basePackage + - "session.StandardManager$PrivilegedDoUnload"); - } - - - private final static void loadUtilPackage(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.catalina."; - loader.loadClass - (basePackage + "util.URL"); - loader.loadClass(basePackage + "util.Enumerator"); - } - - - private final static void loadJavaxPackage(ClassLoader loader) - throws Exception { - loader.loadClass("javax.servlet.http.Cookie"); - } - - - private final static void loadHttp11Package(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.coyote.http11."; - loader.loadClass(basePackage + "Http11Processor$1"); - loader.loadClass(basePackage + "InternalOutputBuffer$1"); - loader.loadClass(basePackage + "InternalOutputBuffer$2"); - } - - - private final static void loadCoyotePackage(ClassLoader loader) - throws Exception { - String basePackage = "org.apache.catalina.connector."; - loader.loadClass - (basePackage + - "RequestFacade$GetAttributePrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetParameterMapPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetRequestDispatcherPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetParameterPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetParameterNamesPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetParameterValuePrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetCharacterEncodingPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetHeadersPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetHeaderNamesPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetCookiesPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetLocalePrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetLocalesPrivilegedAction"); - loader.loadClass - (basePackage + - "ResponseFacade$SetContentTypePrivilegedAction"); - loader.loadClass - (basePackage + - "ResponseFacade$DateHeaderPrivilegedAction"); - loader.loadClass - (basePackage + - "RequestFacade$GetSessionPrivilegedAction"); - loader.loadClass - (basePackage + - "ResponseFacade$1"); - loader.loadClass - (basePackage + - "OutputBuffer$1"); - loader.loadClass - (basePackage + - "CoyoteInputStream$1"); - loader.loadClass - (basePackage + - "CoyoteInputStream$2"); - loader.loadClass - (basePackage + - "CoyoteInputStream$3"); - loader.loadClass - (basePackage + - "CoyoteInputStream$4"); - loader.loadClass - (basePackage + - "CoyoteInputStream$5"); - loader.loadClass - (basePackage + - "InputBuffer$1"); - loader.loadClass - (basePackage + - "Response$1"); - loader.loadClass - (basePackage + - "Response$2"); - loader.loadClass - (basePackage + - "Response$3"); - } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.security; + +/** + * Static class used to preload java classes when using the + * Java SecurityManager so that the defineClassInPackage + * RuntimePermission does not trigger an AccessControlException. + * + * @author Glenn L. Nielsen + * @author Jean-Francois Arcand + * @version $Revision: 304042 $ $Date: 2005-08-04 08:07:46 +0200 (jeu., 04 août 2005) $ + */ + +public final class SecurityClassLoad { + + public static void securityClassLoad(ClassLoader loader) + throws Exception { + + if( System.getSecurityManager() == null ){ + return; + } + + loadCorePackage(loader); + loadLoaderPackage(loader); + loadSessionPackage(loader); + loadUtilPackage(loader); + loadJavaxPackage(loader); + loadCoyotePackage(loader); + loadHttp11Package(loader); + } + + + private final static void loadCorePackage(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.catalina."; + loader.loadClass + (basePackage + + "core.ApplicationContextFacade$1"); + loader.loadClass + (basePackage + + "core.ApplicationDispatcher$PrivilegedForward"); + loader.loadClass + (basePackage + + "core.ApplicationDispatcher$PrivilegedInclude"); + loader.loadClass + (basePackage + + "core.ContainerBase$PrivilegedAddChild"); + loader.loadClass + (basePackage + + "core.StandardWrapper$1"); + } + + + private final static void loadLoaderPackage(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.catalina."; + loader.loadClass + (basePackage + + "loader.WebappClassLoader$PrivilegedFindResource"); + } + + + private final static void loadSessionPackage(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.catalina."; + loader.loadClass + (basePackage + "session.StandardSession"); + loader.loadClass + (basePackage + + "session.StandardSession$1"); + loader.loadClass + (basePackage + + "session.StandardManager$PrivilegedDoUnload"); + } + + + private final static void loadUtilPackage(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.catalina."; + loader.loadClass + (basePackage + "util.URL"); + loader.loadClass(basePackage + "util.Enumerator"); + } + + + private final static void loadJavaxPackage(ClassLoader loader) + throws Exception { + loader.loadClass("javax.servlet.http.Cookie"); + } + + + private final static void loadHttp11Package(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.coyote.http11."; + loader.loadClass(basePackage + "Http11Processor$1"); + loader.loadClass(basePackage + "InternalOutputBuffer$1"); + loader.loadClass(basePackage + "InternalOutputBuffer$2"); + } + + + private final static void loadCoyotePackage(ClassLoader loader) + throws Exception { + String basePackage = "org.apache.catalina.connector."; + loader.loadClass + (basePackage + + "RequestFacade$GetAttributePrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetParameterMapPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetRequestDispatcherPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetParameterPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetParameterNamesPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetParameterValuePrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetCharacterEncodingPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetHeadersPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetHeaderNamesPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetCookiesPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetLocalePrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetLocalesPrivilegedAction"); + loader.loadClass + (basePackage + + "ResponseFacade$SetContentTypePrivilegedAction"); + loader.loadClass + (basePackage + + "ResponseFacade$DateHeaderPrivilegedAction"); + loader.loadClass + (basePackage + + "RequestFacade$GetSessionPrivilegedAction"); + loader.loadClass + (basePackage + + "ResponseFacade$1"); + loader.loadClass + (basePackage + + "OutputBuffer$1"); + loader.loadClass + (basePackage + + "CoyoteInputStream$1"); + loader.loadClass + (basePackage + + "CoyoteInputStream$2"); + loader.loadClass + (basePackage + + "CoyoteInputStream$3"); + loader.loadClass + (basePackage + + "CoyoteInputStream$4"); + loader.loadClass + (basePackage + + "CoyoteInputStream$5"); + loader.loadClass + (basePackage + + "InputBuffer$1"); + loader.loadClass + (basePackage + + "Response$1"); + loader.loadClass + (basePackage + + "Response$2"); + loader.loadClass + (basePackage + + "Response$3"); + } + +} + diff --git a/java/org/apache/catalina/security/SecurityConfig.java b/java/org/apache/catalina/security/SecurityConfig.java index af19946a9..b066acd23 100644 --- a/java/org/apache/catalina/security/SecurityConfig.java +++ b/java/org/apache/catalina/security/SecurityConfig.java @@ -1,133 +1,133 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.security; - -import java.security.Security; -import org.apache.catalina.startup.CatalinaProperties; - -/** - * Util class to protect Catalina against package access and insertion. - * The code are been moved from Catalina.java - * @author the Catalina.java authors - * @author Jean-Francois Arcand - */ -public final class SecurityConfig{ - private static SecurityConfig singleton = null; - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SecurityConfig.class ); - - - private final static String PACKAGE_ACCESS = "sun.," - + "org.apache.catalina." - + ",org.apache.jasper." - + ",org.apache.coyote." - + ",org.apache.tomcat."; - - private final static String PACKAGE_DEFINITION= "java.,sun." - + ",org.apache.catalina." - + ",org.apache.coyote." - + ",org.apache.tomcat." - + ",org.apache.jasper."; - /** - * List of protected package from conf/catalina.properties - */ - private String packageDefinition; - - - /** - * List of protected package from conf/catalina.properties - */ - private String packageAccess; - - - /** - * Create a single instance of this class. - */ - private SecurityConfig(){ - try{ - packageDefinition = CatalinaProperties.getProperty("package.definition"); - packageAccess = CatalinaProperties.getProperty("package.access"); - } catch (java.lang.Exception ex){ - if (log.isDebugEnabled()){ - log.debug("Unable to load properties using CatalinaProperties", ex); - } - } - } - - - /** - * Returns the singleton instance of that class. - * @return an instance of that class. - */ - public static SecurityConfig newInstance(){ - if (singleton == null){ - singleton = new SecurityConfig(); - } - return singleton; - } - - - /** - * Set the security package.access value. - */ - public void setPackageAccess(){ - // If catalina.properties is missing, protect all by default. - if (packageAccess == null){ - setSecurityProperty("package.access", PACKAGE_ACCESS); - } else { - setSecurityProperty("package.access", packageAccess); - } - } - - - /** - * Set the security package.definition value. - */ - public void setPackageDefinition(){ - // If catalina.properties is missing, protect all by default. - if (packageDefinition == null){ - setSecurityProperty("package.definition", PACKAGE_DEFINITION); - } else { - setSecurityProperty("package.definition", packageDefinition); - } - } - - - /** - * Set the proper security property - * @param properties the package.* property. - */ - private final void setSecurityProperty(String properties, String packageList){ - if (System.getSecurityManager() != null){ - String definition = Security.getProperty(properties); - if( definition != null && definition.length() > 0 ){ - definition += ","; - } - - Security.setProperty(properties, - // FIX ME package "javax." was removed to prevent HotSpot - // fatal internal errors - definition + packageList); - } - } - - -} - - - - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.security; + +import java.security.Security; +import org.apache.catalina.startup.CatalinaProperties; + +/** + * Util class to protect Catalina against package access and insertion. + * The code are been moved from Catalina.java + * @author the Catalina.java authors + * @author Jean-Francois Arcand + */ +public final class SecurityConfig{ + private static SecurityConfig singleton = null; + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SecurityConfig.class ); + + + private final static String PACKAGE_ACCESS = "sun.," + + "org.apache.catalina." + + ",org.apache.jasper." + + ",org.apache.coyote." + + ",org.apache.tomcat."; + + private final static String PACKAGE_DEFINITION= "java.,sun." + + ",org.apache.catalina." + + ",org.apache.coyote." + + ",org.apache.tomcat." + + ",org.apache.jasper."; + /** + * List of protected package from conf/catalina.properties + */ + private String packageDefinition; + + + /** + * List of protected package from conf/catalina.properties + */ + private String packageAccess; + + + /** + * Create a single instance of this class. + */ + private SecurityConfig(){ + try{ + packageDefinition = CatalinaProperties.getProperty("package.definition"); + packageAccess = CatalinaProperties.getProperty("package.access"); + } catch (java.lang.Exception ex){ + if (log.isDebugEnabled()){ + log.debug("Unable to load properties using CatalinaProperties", ex); + } + } + } + + + /** + * Returns the singleton instance of that class. + * @return an instance of that class. + */ + public static SecurityConfig newInstance(){ + if (singleton == null){ + singleton = new SecurityConfig(); + } + return singleton; + } + + + /** + * Set the security package.access value. + */ + public void setPackageAccess(){ + // If catalina.properties is missing, protect all by default. + if (packageAccess == null){ + setSecurityProperty("package.access", PACKAGE_ACCESS); + } else { + setSecurityProperty("package.access", packageAccess); + } + } + + + /** + * Set the security package.definition value. + */ + public void setPackageDefinition(){ + // If catalina.properties is missing, protect all by default. + if (packageDefinition == null){ + setSecurityProperty("package.definition", PACKAGE_DEFINITION); + } else { + setSecurityProperty("package.definition", packageDefinition); + } + } + + + /** + * Set the proper security property + * @param properties the package.* property. + */ + private final void setSecurityProperty(String properties, String packageList){ + if (System.getSecurityManager() != null){ + String definition = Security.getProperty(properties); + if( definition != null && definition.length() > 0 ){ + definition += ","; + } + + Security.setProperty(properties, + // FIX ME package "javax." was removed to prevent HotSpot + // fatal internal errors + definition + packageList); + } + } + + +} + + + + diff --git a/java/org/apache/catalina/security/SecurityUtil.java b/java/org/apache/catalina/security/SecurityUtil.java index 3af22d2d1..a2870514c 100644 --- a/java/org/apache/catalina/security/SecurityUtil.java +++ b/java/org/apache/catalina/security/SecurityUtil.java @@ -1,384 +1,384 @@ -/* - * Copyright 1999-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.security; - - -import java.io.IOException; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Principal; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.HashMap; - -import javax.security.auth.Subject; -import javax.servlet.Filter; -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Globals; -import org.apache.catalina.util.StringManager; -/** - * This utility class associates a Subject to the current - * AccessControlContext. When a SecurityManager is - * used, * the container will always associate the called thread with an - * AccessControlContext * containing only the principal of the requested - * Servlet/Filter. - * - * This class uses reflection to invoke the invoke methods. - * - * @author Jean-Francois Arcand - */ - -public final class SecurityUtil{ - - private final static int INIT= 0; - private final static int SERVICE = 1; - private final static int DOFILTER = 1; - private final static int DESTROY = 2; - - private final static String INIT_METHOD = "init"; - private final static String DOFILTER_METHOD = "doFilter"; - private final static String SERVICE_METHOD = "service"; - private final static String DESTROY_METHOD = "destroy"; - - /** - * Cache every object for which we are creating method on it. - */ - private static HashMap objectCache = new HashMap(); - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SecurityUtil.class ); - - private static String PACKAGE = "org.apache.catalina.security"; - - private static boolean packageDefinitionEnabled = - (System.getProperty("package.definition") == null && - System.getProperty("package.access") == null) ? false : true; - - /** - * The string resources for this package. - */ - private static final StringManager sm = - StringManager.getManager(PACKAGE); - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Servlet on which the method will - * be called. - */ - public static void doAsPrivilege(final String methodName, - final Servlet targetObject) throws java.lang.Exception{ - doAsPrivilege(methodName, targetObject, null, null, null); - } - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Servlet on which the method will - * be called. - * @param targetType Class array used to instanciate a i - * Method object. - * @param targetArguments Object array contains the runtime - * parameters instance. - */ - public static void doAsPrivilege(final String methodName, - final Servlet targetObject, - final Class[] targetType, - final Object[] targetArguments) - throws java.lang.Exception{ - - doAsPrivilege(methodName, - targetObject, - targetType, - targetArguments, - null); - } - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Servlet on which the method will - * be called. - * @param targetType Class array used to instanciate a - * Method object. - * @param targetArguments Object array contains the - * runtime parameters instance. - * @param principal the Principal to which the security - * privilege apply.. - */ - public static void doAsPrivilege(final String methodName, - final Servlet targetObject, - final Class[] targetType, - final Object[] targetArguments, - Principal principal) - throws java.lang.Exception{ - - Method method = null; - Method[] methodsCache = null; - if(objectCache.containsKey(targetObject)){ - methodsCache = (Method[])objectCache.get(targetObject); - method = findMethod(methodsCache, methodName); - if (method == null){ - method = createMethodAndCacheIt(methodsCache, - methodName, - targetObject, - targetType); - } - } else { - method = createMethodAndCacheIt(methodsCache, - methodName, - targetObject, - targetType); - } - - execute(method, targetObject, targetArguments, principal); - } - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Filter on which the method will - * be called. - */ - public static void doAsPrivilege(final String methodName, - final Filter targetObject) - throws java.lang.Exception{ - - doAsPrivilege(methodName, targetObject, null, null); - } - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Filter on which the method will - * be called. - * @param targetType Class array used to instanciate a - * Method object. - * @param targetArguments Object array contains the - * runtime parameters instance. - */ - public static void doAsPrivilege(final String methodName, - final Filter targetObject, - final Class[] targetType, - final Object[] targetArguments) - throws java.lang.Exception{ - Method method = null; - - Method[] methodsCache = null; - if(objectCache.containsKey(targetObject)){ - methodsCache = (Method[])objectCache.get(targetObject); - method = findMethod(methodsCache, methodName); - if (method == null){ - method = createMethodAndCacheIt(methodsCache, - methodName, - targetObject, - targetType); - } - } else { - method = createMethodAndCacheIt(methodsCache, - methodName, - targetObject, - targetType); - } - - execute(method, targetObject, targetArguments, null); - } - - - /** - * Perform work as a particular Subject. Here the work - * will be granted to a null subject. - * - * @param methodName the method to apply the security restriction - * @param targetObject the Servlet on which the method will - * be called. - * @param targetArguments Object array contains the - * runtime parameters instance. - * @param principal the Principal to which the security - * privilege applies - */ - private static void execute(final Method method, - final Object targetObject, - final Object[] targetArguments, - Principal principal) - throws java.lang.Exception{ - - try{ - Subject subject = null; - PrivilegedExceptionAction pea = new PrivilegedExceptionAction(){ - public Object run() throws Exception{ - method.invoke(targetObject, targetArguments); - return null; - } - }; - - // The first argument is always the request object - if (targetArguments != null - && targetArguments[0] instanceof HttpServletRequest){ - HttpServletRequest request = - (HttpServletRequest)targetArguments[0]; - - boolean hasSubject = false; - HttpSession session = request.getSession(false); - if (session != null){ - subject = - (Subject)session.getAttribute(Globals.SUBJECT_ATTR); - hasSubject = (subject != null); - } - - if (subject == null){ - subject = new Subject(); - - if (principal != null){ - subject.getPrincipals().add(principal); - } - } - - if (session != null && !hasSubject) { - session.setAttribute(Globals.SUBJECT_ATTR, subject); - } - } - - Subject.doAsPrivileged(subject, pea, null); - } catch( PrivilegedActionException pe) { - Throwable e = ((InvocationTargetException)pe.getException()) - .getTargetException(); - - if (log.isDebugEnabled()){ - log.debug(sm.getString("SecurityUtil.doAsPrivilege"), e); - } - - if (e instanceof UnavailableException) - throw (UnavailableException) e; - else if (e instanceof ServletException) - throw (ServletException) e; - else if (e instanceof IOException) - throw (IOException) e; - else if (e instanceof RuntimeException) - throw (RuntimeException) e; - else - throw new ServletException(e.getMessage(), e); - } - } - - - /** - * Find a method stored within the cache. - * @param methodsCache the cache used to store method instance - * @param methodName the method to apply the security restriction - * @return the method instance, null if not yet created. - */ - private static Method findMethod(Method[] methodsCache, - String methodName){ - if (methodName.equalsIgnoreCase(INIT_METHOD) - && methodsCache[INIT] != null){ - return methodsCache[INIT]; - } else if (methodName.equalsIgnoreCase(DESTROY_METHOD) - && methodsCache[DESTROY] != null){ - return methodsCache[DESTROY]; - } else if (methodName.equalsIgnoreCase(SERVICE_METHOD) - && methodsCache[SERVICE] != null){ - return methodsCache[SERVICE]; - } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD) - && methodsCache[DOFILTER] != null){ - return methodsCache[DOFILTER]; - } - return null; - } - - - /** - * Create the method and cache it for further re-use. - * @param methodsCache the cache used to store method instance - * @param methodName the method to apply the security restriction - * @param targetObject the Servlet on which the method will - * be called. - * @param targetType Class array used to instanciate a - * Method object. - * @return the method instance. - */ - private static Method createMethodAndCacheIt(Method[] methodsCache, - String methodName, - Object targetObject, - Class[] targetType) - throws Exception{ - - if ( methodsCache == null){ - methodsCache = new Method[3]; - } - - Method method = - targetObject.getClass().getMethod(methodName, targetType); - - if (methodName.equalsIgnoreCase(INIT_METHOD)){ - methodsCache[INIT] = method; - } else if (methodName.equalsIgnoreCase(DESTROY_METHOD)){ - methodsCache[DESTROY] = method; - } else if (methodName.equalsIgnoreCase(SERVICE_METHOD)){ - methodsCache[SERVICE] = method; - } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD)){ - methodsCache[DOFILTER] = method; - } - - objectCache.put(targetObject, methodsCache ); - - return method; - } - - - /** - * Remove the object from the cache. - * - * @param cachedObject The object to remove - */ - public static void remove(Object cachedObject){ - objectCache.remove(cachedObject); - } - - - /** - * Return the SecurityManager only if Security is enabled AND - * package protection mechanism is enabled. - */ - public static boolean isPackageProtectionEnabled(){ - if (packageDefinitionEnabled && System.getSecurityManager() != null){ - return true; - } - return false; - } - - -} +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.security; + + +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.HashMap; + +import javax.security.auth.Subject; +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Globals; +import org.apache.catalina.util.StringManager; +/** + * This utility class associates a Subject to the current + * AccessControlContext. When a SecurityManager is + * used, * the container will always associate the called thread with an + * AccessControlContext * containing only the principal of the requested + * Servlet/Filter. + * + * This class uses reflection to invoke the invoke methods. + * + * @author Jean-Francois Arcand + */ + +public final class SecurityUtil{ + + private final static int INIT= 0; + private final static int SERVICE = 1; + private final static int DOFILTER = 1; + private final static int DESTROY = 2; + + private final static String INIT_METHOD = "init"; + private final static String DOFILTER_METHOD = "doFilter"; + private final static String SERVICE_METHOD = "service"; + private final static String DESTROY_METHOD = "destroy"; + + /** + * Cache every object for which we are creating method on it. + */ + private static HashMap objectCache = new HashMap(); + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SecurityUtil.class ); + + private static String PACKAGE = "org.apache.catalina.security"; + + private static boolean packageDefinitionEnabled = + (System.getProperty("package.definition") == null && + System.getProperty("package.access") == null) ? false : true; + + /** + * The string resources for this package. + */ + private static final StringManager sm = + StringManager.getManager(PACKAGE); + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Servlet on which the method will + * be called. + */ + public static void doAsPrivilege(final String methodName, + final Servlet targetObject) throws java.lang.Exception{ + doAsPrivilege(methodName, targetObject, null, null, null); + } + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Servlet on which the method will + * be called. + * @param targetType Class array used to instanciate a i + * Method object. + * @param targetArguments Object array contains the runtime + * parameters instance. + */ + public static void doAsPrivilege(final String methodName, + final Servlet targetObject, + final Class[] targetType, + final Object[] targetArguments) + throws java.lang.Exception{ + + doAsPrivilege(methodName, + targetObject, + targetType, + targetArguments, + null); + } + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Servlet on which the method will + * be called. + * @param targetType Class array used to instanciate a + * Method object. + * @param targetArguments Object array contains the + * runtime parameters instance. + * @param principal the Principal to which the security + * privilege apply.. + */ + public static void doAsPrivilege(final String methodName, + final Servlet targetObject, + final Class[] targetType, + final Object[] targetArguments, + Principal principal) + throws java.lang.Exception{ + + Method method = null; + Method[] methodsCache = null; + if(objectCache.containsKey(targetObject)){ + methodsCache = (Method[])objectCache.get(targetObject); + method = findMethod(methodsCache, methodName); + if (method == null){ + method = createMethodAndCacheIt(methodsCache, + methodName, + targetObject, + targetType); + } + } else { + method = createMethodAndCacheIt(methodsCache, + methodName, + targetObject, + targetType); + } + + execute(method, targetObject, targetArguments, principal); + } + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Filter on which the method will + * be called. + */ + public static void doAsPrivilege(final String methodName, + final Filter targetObject) + throws java.lang.Exception{ + + doAsPrivilege(methodName, targetObject, null, null); + } + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Filter on which the method will + * be called. + * @param targetType Class array used to instanciate a + * Method object. + * @param targetArguments Object array contains the + * runtime parameters instance. + */ + public static void doAsPrivilege(final String methodName, + final Filter targetObject, + final Class[] targetType, + final Object[] targetArguments) + throws java.lang.Exception{ + Method method = null; + + Method[] methodsCache = null; + if(objectCache.containsKey(targetObject)){ + methodsCache = (Method[])objectCache.get(targetObject); + method = findMethod(methodsCache, methodName); + if (method == null){ + method = createMethodAndCacheIt(methodsCache, + methodName, + targetObject, + targetType); + } + } else { + method = createMethodAndCacheIt(methodsCache, + methodName, + targetObject, + targetType); + } + + execute(method, targetObject, targetArguments, null); + } + + + /** + * Perform work as a particular Subject. Here the work + * will be granted to a null subject. + * + * @param methodName the method to apply the security restriction + * @param targetObject the Servlet on which the method will + * be called. + * @param targetArguments Object array contains the + * runtime parameters instance. + * @param principal the Principal to which the security + * privilege applies + */ + private static void execute(final Method method, + final Object targetObject, + final Object[] targetArguments, + Principal principal) + throws java.lang.Exception{ + + try{ + Subject subject = null; + PrivilegedExceptionAction pea = new PrivilegedExceptionAction(){ + public Object run() throws Exception{ + method.invoke(targetObject, targetArguments); + return null; + } + }; + + // The first argument is always the request object + if (targetArguments != null + && targetArguments[0] instanceof HttpServletRequest){ + HttpServletRequest request = + (HttpServletRequest)targetArguments[0]; + + boolean hasSubject = false; + HttpSession session = request.getSession(false); + if (session != null){ + subject = + (Subject)session.getAttribute(Globals.SUBJECT_ATTR); + hasSubject = (subject != null); + } + + if (subject == null){ + subject = new Subject(); + + if (principal != null){ + subject.getPrincipals().add(principal); + } + } + + if (session != null && !hasSubject) { + session.setAttribute(Globals.SUBJECT_ATTR, subject); + } + } + + Subject.doAsPrivileged(subject, pea, null); + } catch( PrivilegedActionException pe) { + Throwable e = ((InvocationTargetException)pe.getException()) + .getTargetException(); + + if (log.isDebugEnabled()){ + log.debug(sm.getString("SecurityUtil.doAsPrivilege"), e); + } + + if (e instanceof UnavailableException) + throw (UnavailableException) e; + else if (e instanceof ServletException) + throw (ServletException) e; + else if (e instanceof IOException) + throw (IOException) e; + else if (e instanceof RuntimeException) + throw (RuntimeException) e; + else + throw new ServletException(e.getMessage(), e); + } + } + + + /** + * Find a method stored within the cache. + * @param methodsCache the cache used to store method instance + * @param methodName the method to apply the security restriction + * @return the method instance, null if not yet created. + */ + private static Method findMethod(Method[] methodsCache, + String methodName){ + if (methodName.equalsIgnoreCase(INIT_METHOD) + && methodsCache[INIT] != null){ + return methodsCache[INIT]; + } else if (methodName.equalsIgnoreCase(DESTROY_METHOD) + && methodsCache[DESTROY] != null){ + return methodsCache[DESTROY]; + } else if (methodName.equalsIgnoreCase(SERVICE_METHOD) + && methodsCache[SERVICE] != null){ + return methodsCache[SERVICE]; + } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD) + && methodsCache[DOFILTER] != null){ + return methodsCache[DOFILTER]; + } + return null; + } + + + /** + * Create the method and cache it for further re-use. + * @param methodsCache the cache used to store method instance + * @param methodName the method to apply the security restriction + * @param targetObject the Servlet on which the method will + * be called. + * @param targetType Class array used to instanciate a + * Method object. + * @return the method instance. + */ + private static Method createMethodAndCacheIt(Method[] methodsCache, + String methodName, + Object targetObject, + Class[] targetType) + throws Exception{ + + if ( methodsCache == null){ + methodsCache = new Method[3]; + } + + Method method = + targetObject.getClass().getMethod(methodName, targetType); + + if (methodName.equalsIgnoreCase(INIT_METHOD)){ + methodsCache[INIT] = method; + } else if (methodName.equalsIgnoreCase(DESTROY_METHOD)){ + methodsCache[DESTROY] = method; + } else if (methodName.equalsIgnoreCase(SERVICE_METHOD)){ + methodsCache[SERVICE] = method; + } else if (methodName.equalsIgnoreCase(DOFILTER_METHOD)){ + methodsCache[DOFILTER] = method; + } + + objectCache.put(targetObject, methodsCache ); + + return method; + } + + + /** + * Remove the object from the cache. + * + * @param cachedObject The object to remove + */ + public static void remove(Object cachedObject){ + objectCache.remove(cachedObject); + } + + + /** + * Return the SecurityManager only if Security is enabled AND + * package protection mechanism is enabled. + */ + public static boolean isPackageProtectionEnabled(){ + if (packageDefinitionEnabled && System.getSecurityManager() != null){ + return true; + } + return false; + } + + +} diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java index 7cccd9908..2b4e1d34e 100644 --- a/java/org/apache/catalina/servlets/CGIServlet.java +++ b/java/org/apache/catalina/servlets/CGIServlet.java @@ -1,1952 +1,1952 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.ArrayList; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Locale; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.UnavailableException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Globals; -import org.apache.catalina.util.IOTools; - - -/** - * CGI-invoking servlet for web applications, used to execute scripts which - * comply to the Common Gateway Interface (CGI) specification and are named - * in the path-info used to invoke this servlet. - * - *

    - * Note: This code compiles and even works for simple CGI cases. - * Exhaustive testing has not been done. Please consider it beta - * quality. Feedback is appreciated to the author (see below). - *

    - *

    - * - * Example:
    - * If an instance of this servlet was mapped (using - * <web-app>/WEB-INF/web.xml) to: - *

    - *

    - * - * <web-app>/cgi-bin/* - * - *

    - *

    - * then the following request: - *

    - *

    - * - * http://localhost:8080/<web-app>/cgi-bin/dir1/script/pathinfo1 - * - *

    - *

    - * would result in the execution of the script - *

    - *

    - * - * <web-app-root>/WEB-INF/cgi/dir1/script - * - *

    - *

    - * with the script's PATH_INFO set to /pathinfo1. - *

    - *

    - * Recommendation: House all your CGI scripts under - * <webapp>/WEB-INF/cgi. This will ensure that you do not - * accidentally expose your cgi scripts' code to the outside world and that - * your cgis will be cleanly ensconced underneath the WEB-INF (i.e., - * non-content) area. - *

    - *

    - * The default CGI location is mentioned above. You have the flexibility to - * put CGIs wherever you want, however: - *

    - *

    - * The CGI search path will start at - * webAppRootDir + File.separator + cgiPathPrefix - * (or webAppRootDir alone if cgiPathPrefix is - * null). - *

    - *

    - * cgiPathPrefix is defined by setting - * this servlet's cgiPathPrefix init parameter - *

    - * - *

    - * - * CGI Specification:
    derived from - * http://cgi-spec.golux.com. - * A work-in-progress & expired Internet Draft. Note no actual RFC describing - * the CGI specification exists. Where the behavior of this servlet differs - * from the specification cited above, it is either documented here, a bug, - * or an instance where the specification cited differs from Best - * Community Practice (BCP). - * Such instances should be well-documented here. Please email the - * Jakarta Tomcat group [tomcat-dev@jakarta.apache.org] - * with amendments. - * - *

    - *

    - * - * Canonical metavariables:
    - * The CGI specification defines the following canonical metavariables: - *
    - * [excerpt from CGI specification] - *

    - *  AUTH_TYPE
    - *  CONTENT_LENGTH
    - *  CONTENT_TYPE
    - *  GATEWAY_INTERFACE
    - *  PATH_INFO
    - *  PATH_TRANSLATED
    - *  QUERY_STRING
    - *  REMOTE_ADDR
    - *  REMOTE_HOST
    - *  REMOTE_IDENT
    - *  REMOTE_USER
    - *  REQUEST_METHOD
    - *  SCRIPT_NAME
    - *  SERVER_NAME
    - *  SERVER_PORT
    - *  SERVER_PROTOCOL
    - *  SERVER_SOFTWARE
    - * 
    - *

    - * Metavariables with names beginning with the protocol name (e.g., - * "HTTP_ACCEPT") are also canonical in their description of request header - * fields. The number and meaning of these fields may change independently - * of this specification. (See also section 6.1.5 [of the CGI specification].) - *

    - * [end excerpt] - * - *

    - *

    Implementation notes

    - *

    - * - * standard input handling: If your script accepts standard input, - * then the client must start sending input within a certain timeout period, - * otherwise the servlet will assume no input is coming and carry on running - * the script. The script's the standard input will be closed and handling of - * any further input from the client is undefined. Most likely it will be - * ignored. If this behavior becomes undesirable, then this servlet needs - * to be enhanced to handle threading of the spawned process' stdin, stdout, - * and stderr (which should not be too hard). - *
    - * If you find your cgi scripts are timing out receiving input, you can set - * the init parameter of your webapps' cgi-handling servlet - * to be - *

    - *

    - * - * Metavariable Values: According to the CGI specificion, - * implementations may choose to represent both null or missing values in an - * implementation-specific manner, but must define that manner. This - * implementation chooses to always define all required metavariables, but - * set the value to "" for all metavariables whose value is either null or - * undefined. PATH_TRANSLATED is the sole exception to this rule, as per the - * CGI Specification. - * - *

    - *

    - * - * NPH -- Non-parsed-header implementation: This implementation does - * not support the CGI NPH concept, whereby server ensures that the data - * supplied to the script are preceisely as supplied by the client and - * unaltered by the server. - *

    - *

    - * The function of a servlet container (including Tomcat) is specifically - * designed to parse and possible alter CGI-specific variables, and as - * such makes NPH functionality difficult to support. - *

    - *

    - * The CGI specification states that compliant servers MAY support NPH output. - * It does not state servers MUST support NPH output to be unconditionally - * compliant. Thus, this implementation maintains unconditional compliance - * with the specification though NPH support is not present. - *

    - *

    - * - * The CGI specification is located at - * http://cgi-spec.golux.com. - * - *

    - *

    - *

    TODO:

    - *
      - *
    • Support for setting headers (for example, Location headers don't work) - *
    • Support for collapsing multiple header lines (per RFC 2616) - *
    • Ensure handling of POST method does not interfere with 2.3 Filters - *
    • Refactor some debug code out of core - *
    • Ensure header handling preserves encoding - *
    • Possibly rewrite CGIRunner.run()? - *
    • Possibly refactor CGIRunner and CGIEnvironment as non-inner classes? - *
    • Document handling of cgi stdin when there is no stdin - *
    • Revisit IOException handling in CGIRunner.run() - *
    • Better documentation - *
    • Confirm use of ServletInputStream.available() in CGIRunner.run() is - * not needed - *
    • Make checking for "." and ".." in servlet & cgi PATH_INFO less - * draconian - *
    • [add more to this TODO list] - *
    - *

    - * - * @author Martin T Dengler [root@martindengler.com] - * @author Amy Roh - * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ - * @since Tomcat 4.0 - * - */ - - -public final class CGIServlet extends HttpServlet { - - /* some vars below copied from Craig R. McClanahan's InvokerServlet */ - - /** the debugging detail level for this servlet. */ - private int debug = 0; - - /** - * The CGI search path will start at - * webAppRootDir + File.separator + cgiPathPrefix - * (or webAppRootDir alone if cgiPathPrefix is - * null) - */ - private String cgiPathPrefix = null; - - /** the executable to use with the script */ - private String cgiExecutable = "perl"; - - /** the encoding to use for parameters */ - private String parameterEncoding = System.getProperty("file.encoding", - "UTF-8"); - - /** object used to ensure multiple threads don't try to expand same file */ - static Object expandFileLock = new Object(); - - /** the shell environment variables to be passed to the CGI script */ - static Hashtable shellEnv = new Hashtable(); - - /** - * Sets instance variables. - *

    - * Modified from Craig R. McClanahan's InvokerServlet - *

    - * - * @param config a ServletConfig object - * containing the servlet's - * configuration and initialization - * parameters - * - * @exception ServletException if an exception has occurred that - * interferes with the servlet's normal - * operation - */ - public void init(ServletConfig config) throws ServletException { - - super.init(config); - - // Verify that we were not accessed using the invoker servlet - String servletName = getServletConfig().getServletName(); - if (servletName == null) - servletName = ""; - if (servletName.startsWith("org.apache.catalina.INVOKER.")) - throw new UnavailableException - ("Cannot invoke CGIServlet through the invoker"); - - boolean passShellEnvironment = false; - - // Set our properties from the initialization parameters - String value = null; - try { - value = getServletConfig().getInitParameter("debug"); - debug = Integer.parseInt(value); - cgiPathPrefix = - getServletConfig().getInitParameter("cgiPathPrefix"); - value = getServletConfig().getInitParameter("passShellEnvironment"); - passShellEnvironment = Boolean.valueOf(value).booleanValue(); - } catch (Throwable t) { - //NOOP - } - log("init: loglevel set to " + debug); - - if (passShellEnvironment) { - try { - shellEnv.putAll(getShellEnvironment()); - } catch (IOException ioe) { - ServletException e = new ServletException( - "Unable to read shell environment variables", ioe); - throw e; - } - } - - value = getServletConfig().getInitParameter("executable"); - if (value != null) { - cgiExecutable = value; - } - - value = getServletConfig().getInitParameter("parameterEncoding"); - if (value != null) { - parameterEncoding = value; - } - - } - - - - /** - * Prints out important Servlet API and container information - * - *

    - * Copied from SnoopAllServlet by Craig R. McClanahan - *

    - * - * @param out ServletOutputStream as target of the information - * @param req HttpServletRequest object used as source of information - * @param res HttpServletResponse object currently not used but could - * provide future information - * - * @exception IOException if a write operation exception occurs - * - */ - protected void printServletEnvironment(ServletOutputStream out, - HttpServletRequest req, HttpServletResponse res) throws IOException { - - // Document the properties from ServletRequest - out.println("

    ServletRequest Properties

    "); - out.println("
      "); - Enumeration attrs = req.getAttributeNames(); - while (attrs.hasMoreElements()) { - String attr = (String) attrs.nextElement(); - out.println("
    • attribute " + attr + " = " + - req.getAttribute(attr)); - } - out.println("
    • characterEncoding = " + - req.getCharacterEncoding()); - out.println("
    • contentLength = " + - req.getContentLength()); - out.println("
    • contentType = " + - req.getContentType()); - Enumeration locales = req.getLocales(); - while (locales.hasMoreElements()) { - Locale locale = (Locale) locales.nextElement(); - out.println("
    • locale = " + locale); - } - Enumeration params = req.getParameterNames(); - while (params.hasMoreElements()) { - String param = (String) params.nextElement(); - String values[] = req.getParameterValues(param); - for (int i = 0; i < values.length; i++) - out.println("
    • parameter " + param + " = " + - values[i]); - } - out.println("
    • protocol = " + req.getProtocol()); - out.println("
    • remoteAddr = " + req.getRemoteAddr()); - out.println("
    • remoteHost = " + req.getRemoteHost()); - out.println("
    • scheme = " + req.getScheme()); - out.println("
    • secure = " + req.isSecure()); - out.println("
    • serverName = " + req.getServerName()); - out.println("
    • serverPort = " + req.getServerPort()); - out.println("
    "); - out.println("
    "); - - // Document the properties from HttpServletRequest - out.println("

    HttpServletRequest Properties

    "); - out.println("
      "); - out.println("
    • authType = " + req.getAuthType()); - out.println("
    • contextPath = " + - req.getContextPath()); - Cookie cookies[] = req.getCookies(); - if (cookies!=null) { - for (int i = 0; i < cookies.length; i++) - out.println("
    • cookie " + cookies[i].getName() +" = " +cookies[i].getValue()); - } - Enumeration headers = req.getHeaderNames(); - while (headers.hasMoreElements()) { - String header = (String) headers.nextElement(); - out.println("
    • header " + header + " = " + - req.getHeader(header)); - } - out.println("
    • method = " + req.getMethod()); - out.println("
    • pathInfo = " - + req.getPathInfo()); - out.println("
    • pathTranslated = " + - req.getPathTranslated()); - out.println("
    • queryString = " + - req.getQueryString()); - out.println("
    • remoteUser = " + - req.getRemoteUser()); - out.println("
    • requestedSessionId = " + - req.getRequestedSessionId()); - out.println("
    • requestedSessionIdFromCookie = " + - req.isRequestedSessionIdFromCookie()); - out.println("
    • requestedSessionIdFromURL = " + - req.isRequestedSessionIdFromURL()); - out.println("
    • requestedSessionIdValid = " + - req.isRequestedSessionIdValid()); - out.println("
    • requestURI = " + - req.getRequestURI()); - out.println("
    • servletPath = " + - req.getServletPath()); - out.println("
    • userPrincipal = " + - req.getUserPrincipal()); - out.println("
    "); - out.println("
    "); - - // Document the servlet request attributes - out.println("

    ServletRequest Attributes

    "); - out.println("
      "); - attrs = req.getAttributeNames(); - while (attrs.hasMoreElements()) { - String attr = (String) attrs.nextElement(); - out.println("
    • " + attr + " = " + - req.getAttribute(attr)); - } - out.println("
    "); - out.println("
    "); - - // Process the current session (if there is one) - HttpSession session = req.getSession(false); - if (session != null) { - - // Document the session properties - out.println("

    HttpSession Properties

    "); - out.println("
      "); - out.println("
    • id = " + - session.getId()); - out.println("
    • creationTime = " + - new Date(session.getCreationTime())); - out.println("
    • lastAccessedTime = " + - new Date(session.getLastAccessedTime())); - out.println("
    • maxInactiveInterval = " + - session.getMaxInactiveInterval()); - out.println("
    "); - out.println("
    "); - - // Document the session attributes - out.println("

    HttpSession Attributes

    "); - out.println("
      "); - attrs = session.getAttributeNames(); - while (attrs.hasMoreElements()) { - String attr = (String) attrs.nextElement(); - out.println("
    • " + attr + " = " + - session.getAttribute(attr)); - } - out.println("
    "); - out.println("
    "); - - } - - // Document the servlet configuration properties - out.println("

    ServletConfig Properties

    "); - out.println("
      "); - out.println("
    • servletName = " + - getServletConfig().getServletName()); - out.println("
    "); - out.println("
    "); - - // Document the servlet configuration initialization parameters - out.println("

    ServletConfig Initialization Parameters

    "); - out.println("
      "); - params = getServletConfig().getInitParameterNames(); - while (params.hasMoreElements()) { - String param = (String) params.nextElement(); - String value = getServletConfig().getInitParameter(param); - out.println("
    • " + param + " = " + value); - } - out.println("
    "); - out.println("
    "); - - // Document the servlet context properties - out.println("

    ServletContext Properties

    "); - out.println("
      "); - out.println("
    • majorVersion = " + - getServletContext().getMajorVersion()); - out.println("
    • minorVersion = " + - getServletContext().getMinorVersion()); - out.println("
    • realPath('/') = " + - getServletContext().getRealPath("/")); - out.println("
    • serverInfo = " + - getServletContext().getServerInfo()); - out.println("
    "); - out.println("
    "); - - // Document the servlet context initialization parameters - out.println("

    ServletContext Initialization Parameters

    "); - out.println("
      "); - params = getServletContext().getInitParameterNames(); - while (params.hasMoreElements()) { - String param = (String) params.nextElement(); - String value = getServletContext().getInitParameter(param); - out.println("
    • " + param + " = " + value); - } - out.println("
    "); - out.println("
    "); - - // Document the servlet context attributes - out.println("

    ServletContext Attributes

    "); - out.println("
      "); - attrs = getServletContext().getAttributeNames(); - while (attrs.hasMoreElements()) { - String attr = (String) attrs.nextElement(); - out.println("
    • " + attr + " = " + - getServletContext().getAttribute(attr)); - } - out.println("
    "); - out.println("
    "); - - - - } - - - - /** - * Provides CGI Gateway service -- delegates to doGet - * - * @param req HttpServletRequest passed in by servlet container - * @param res HttpServletResponse passed in by servlet container - * - * @exception ServletException if a servlet-specific exception occurs - * @exception IOException if a read/write exception occurs - * - * @see javax.servlet.http.HttpServlet - * - */ - protected void doPost(HttpServletRequest req, HttpServletResponse res) - throws IOException, ServletException { - doGet(req, res); - } - - - - /** - * Provides CGI Gateway service - * - * @param req HttpServletRequest passed in by servlet container - * @param res HttpServletResponse passed in by servlet container - * - * @exception ServletException if a servlet-specific exception occurs - * @exception IOException if a read/write exception occurs - * - * @see javax.servlet.http.HttpServlet - * - */ - protected void doGet(HttpServletRequest req, HttpServletResponse res) - throws ServletException, IOException { - - // Verify that we were not accessed using the invoker servlet - if (req.getAttribute(Globals.INVOKED_ATTR) != null) - throw new UnavailableException - ("Cannot invoke CGIServlet through the invoker"); - - CGIEnvironment cgiEnv = new CGIEnvironment(req, getServletContext()); - - if (cgiEnv.isValid()) { - CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(), - cgiEnv.getEnvironment(), - cgiEnv.getWorkingDirectory(), - cgiEnv.getParameters()); - //if POST, we need to cgi.setInput - //REMIND: how does this interact with Servlet API 2.3's Filters?! - if ("POST".equals(req.getMethod())) { - cgi.setInput(req.getInputStream()); - } - cgi.setResponse(res); - cgi.run(); - } - - if (!cgiEnv.isValid()) { - res.setStatus(404); - } - - if (debug >= 10) { - try { - ServletOutputStream out = res.getOutputStream(); - out.println("$Name$"); - out.println("$Header$

    "); - - if (cgiEnv.isValid()) { - out.println(cgiEnv.toString()); - } else { - out.println("

    "); - out.println("CGI script not found or not specified."); - out.println("

    "); - out.println("

    "); - out.println("Check the HttpServletRequest "); - out.println("pathInfo "); - out.println("property to see if it is what you meant "); - out.println("it to be. You must specify an existant "); - out.println("and executable file as part of the "); - out.println("path-info."); - out.println("

    "); - out.println("

    "); - out.println("For a good discussion of how CGI scripts "); - out.println("work and what their environment variables "); - out.println("mean, please visit the CGI "); - out.println("Specification page."); - out.println("

    "); - - } - - printServletEnvironment(out, req, res); - - out.println(""); - - } catch (IOException ignored) { - } - - } //debugging - - - } //doGet - - - - /** For future testing use only; does nothing right now */ - public static void main(String[] args) { - System.out.println("$Header$"); - } - - /** - * Get all shell environment variables. Have to do it this rather ugly way - * as the API to obtain is not available in 1.4 and earlier APIs. - * - * See Read environment - * variables from an application for original source and article. - */ - private Hashtable getShellEnvironment() throws IOException { - Hashtable envVars = new Hashtable(); - Process p = null; - Runtime r = Runtime.getRuntime(); - String OS = System.getProperty("os.name").toLowerCase(); - boolean ignoreCase; - - if (OS.indexOf("windows 9") > -1) { - p = r.exec( "command.com /c set" ); - ignoreCase = true; - } else if ( (OS.indexOf("nt") > -1) - || (OS.indexOf("windows 20") > -1) - || (OS.indexOf("windows xp") > -1) ) { - // thanks to JuanFran for the xp fix! - p = r.exec( "cmd.exe /c set" ); - ignoreCase = true; - } else { - // our last hope, we assume Unix (thanks to H. Ware for the fix) - p = r.exec( "env" ); - ignoreCase = false; - } - - BufferedReader br = new BufferedReader - ( new InputStreamReader( p.getInputStream() ) ); - String line; - while( (line = br.readLine()) != null ) { - int idx = line.indexOf( '=' ); - String key = line.substring( 0, idx ); - String value = line.substring( idx+1 ); - if (ignoreCase) { - key = key.toUpperCase(); - } - envVars.put(key, value); - } - return envVars; - } - - - - - - - - /** - * Encapsulates the CGI environment and rules to derive - * that environment from the servlet container and request information. - * - *

    - *

    - * - * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ - * @since Tomcat 4.0 - * - */ - protected class CGIEnvironment { - - - /** context of the enclosing servlet */ - private ServletContext context = null; - - /** context path of enclosing servlet */ - private String contextPath = null; - - /** servlet URI of the enclosing servlet */ - private String servletPath = null; - - /** pathInfo for the current request */ - private String pathInfo = null; - - /** real file system directory of the enclosing servlet's web app */ - private String webAppRootDir = null; - - /** tempdir for context - used to expand scripts in unexpanded wars */ - private File tmpDir = null; - - /** derived cgi environment */ - private Hashtable env = null; - - /** cgi command to be invoked */ - private String command = null; - - /** cgi command's desired working directory */ - private File workingDirectory = null; - - /** cgi command's command line parameters */ - private ArrayList cmdLineParameters = new ArrayList(); - - /** whether or not this object is valid or not */ - private boolean valid = false; - - - /** - * Creates a CGIEnvironment and derives the necessary environment, - * query parameters, working directory, cgi command, etc. - * - * @param req HttpServletRequest for information provided by - * the Servlet API - * @param context ServletContext for information provided by the - * Servlet API - * - */ - protected CGIEnvironment(HttpServletRequest req, - ServletContext context) throws IOException { - setupFromContext(context); - setupFromRequest(req); - - this.valid = setCGIEnvironment(req); - - if (this.valid) { - workingDirectory = new File(command.substring(0, - command.lastIndexOf(File.separator))); - } - - } - - - - /** - * Uses the ServletContext to set some CGI variables - * - * @param context ServletContext for information provided by the - * Servlet API - */ - protected void setupFromContext(ServletContext context) { - this.context = context; - this.webAppRootDir = context.getRealPath("/"); - this.tmpDir = (File) context.getAttribute(Globals.WORK_DIR_ATTR); - } - - - - /** - * Uses the HttpServletRequest to set most CGI variables - * - * @param req HttpServletRequest for information provided by - * the Servlet API - * @throws UnsupportedEncodingException - */ - protected void setupFromRequest(HttpServletRequest req) - throws UnsupportedEncodingException { - - this.contextPath = req.getContextPath(); - this.servletPath = req.getServletPath(); - this.pathInfo = req.getPathInfo(); - // If getPathInfo() returns null, must be using extension mapping - // In this case, pathInfo should be same as servletPath - if (this.pathInfo == null) { - this.pathInfo = this.servletPath; - } - - // If request is HEAD or GET and Query String does not contain - // an unencoded "=" this is an indexed query. Parsed Query String - // forms command line parameters for cgi command. - if (!"GET".equals(req.getMethod()) && - !"HEAD".equals(req.getMethod())) - return; - - String qs = req.getQueryString(); - - if (qs == null || qs.indexOf("=")>0) - return; - - int delimIndex = 0; - int lastDelimIndex = 0; - delimIndex = qs.indexOf("+"); - - while (delimIndex >0) { - cmdLineParameters.add(URLDecoder.decode(qs.substring( - lastDelimIndex,delimIndex),parameterEncoding)); - lastDelimIndex = delimIndex + 1; - delimIndex = qs.indexOf("+",lastDelimIndex); - } - cmdLineParameters.add(URLDecoder.decode(qs.substring( - lastDelimIndex),parameterEncoding)); - } - - - /** - * Resolves core information about the cgi script. - * - *

    - * Example URI: - *

     /servlet/cgigateway/dir1/realCGIscript/pathinfo1 
    - *
      - *
    • path = $CATALINA_HOME/mywebapp/dir1/realCGIscript - *
    • scriptName = /servlet/cgigateway/dir1/realCGIscript - *
    • cgiName = /dir1/realCGIscript - *
    • name = realCGIscript - *
    - *

    - *

    - * CGI search algorithm: search the real path below - * <my-webapp-root> and find the first non-directory in - * the getPathTranslated("/"), reading/searching from left-to-right. - *

    - *

    - * The CGI search path will start at - * webAppRootDir + File.separator + cgiPathPrefix - * (or webAppRootDir alone if cgiPathPrefix is - * null). - *

    - *

    - * cgiPathPrefix is defined by setting - * this servlet's cgiPathPrefix init parameter - * - *

    - * - * @param pathInfo String from HttpServletRequest.getPathInfo() - * @param webAppRootDir String from context.getRealPath("/") - * @param contextPath String as from - * HttpServletRequest.getContextPath() - * @param servletPath String as from - * HttpServletRequest.getServletPath() - * @param cgiPathPrefix subdirectory of webAppRootDir below which - * the web app's CGIs may be stored; can be null. - * The CGI search path will start at - * webAppRootDir + File.separator + cgiPathPrefix - * (or webAppRootDir alone if cgiPathPrefix is - * null). cgiPathPrefix is defined by setting - * the servlet's cgiPathPrefix init parameter. - * - * - * @return - *
      - *
    • - * path - full file-system path to valid cgi script, - * or null if no cgi was found - *
    • - * scriptName - - * CGI variable SCRIPT_NAME; the full URL path - * to valid cgi script or null if no cgi was - * found - *
    • - * cgiName - servlet pathInfo fragment corresponding to - * the cgi script itself, or null if not found - *
    • - * name - simple name (no directories) of the - * cgi script, or null if no cgi was found - *
    - * - * @since Tomcat 4.0 - */ - protected String[] findCGI(String pathInfo, String webAppRootDir, - String contextPath, String servletPath, - String cgiPathPrefix) { - String path = null; - String name = null; - String scriptname = null; - String cginame = null; - - if ((webAppRootDir != null) - && (webAppRootDir.lastIndexOf(File.separator) == - (webAppRootDir.length() - 1))) { - //strip the trailing "/" from the webAppRootDir - webAppRootDir = - webAppRootDir.substring(0, (webAppRootDir.length() - 1)); - } - - if (cgiPathPrefix != null) { - webAppRootDir = webAppRootDir + File.separator - + cgiPathPrefix; - } - - if (debug >= 2) { - log("findCGI: path=" + pathInfo + ", " + webAppRootDir); - } - - File currentLocation = new File(webAppRootDir); - StringTokenizer dirWalker = - new StringTokenizer(pathInfo, "/"); - if (debug >= 3) { - log("findCGI: currentLoc=" + currentLocation); - } - while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { - if (debug >= 3) { - log("findCGI: currentLoc=" + currentLocation); - } - currentLocation = new File(currentLocation, - (String) dirWalker.nextElement()); - } - if (!currentLocation.isFile()) { - return new String[] { null, null, null, null }; - } else { - if (debug >= 2) { - log("findCGI: FOUND cgi at " + currentLocation); - } - path = currentLocation.getAbsolutePath(); - name = currentLocation.getName(); - cginame = - currentLocation.getParent().substring(webAppRootDir.length()) - + File.separator - + name; - - if (".".equals(contextPath)) { - scriptname = servletPath + cginame; - } else { - scriptname = contextPath + servletPath + cginame; - } - } - - if (debug >= 1) { - log("findCGI calc: name=" + name + ", path=" + path - + ", scriptname=" + scriptname + ", cginame=" + cginame); - } - return new String[] { path, scriptname, cginame, name }; - } - - /** - * Constructs the CGI environment to be supplied to the invoked CGI - * script; relies heavliy on Servlet API methods and findCGI - * - * @param req request associated with the CGI - * invokation - * - * @return true if environment was set OK, false if there - * was a problem and no environment was set - */ - protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { - - /* - * This method is slightly ugly; c'est la vie. - * "You cannot stop [ugliness], you can only hope to contain [it]" - * (apologies to Marv Albert regarding MJ) - */ - - Hashtable envp = new Hashtable(); - - // Add the shell environment variables (if any) - envp.putAll(shellEnv); - - // Add the CGI environment variables - String sPathInfoOrig = null; - String sPathTranslatedOrig = null; - String sPathInfoCGI = null; - String sPathTranslatedCGI = null; - String sCGIFullPath = null; - String sCGIScriptName = null; - String sCGIFullName = null; - String sCGIName = null; - String[] sCGINames; - - - sPathInfoOrig = this.pathInfo; - sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; - - sPathTranslatedOrig = req.getPathTranslated(); - sPathTranslatedOrig = - sPathTranslatedOrig == null ? "" : sPathTranslatedOrig; - - if (webAppRootDir == null ) { - // The app has not been deployed in exploded form - webAppRootDir = tmpDir.toString(); - expandCGIScript(); - } - - sCGINames = findCGI(sPathInfoOrig, - webAppRootDir, - contextPath, - servletPath, - cgiPathPrefix); - - sCGIFullPath = sCGINames[0]; - sCGIScriptName = sCGINames[1]; - sCGIFullName = sCGINames[2]; - sCGIName = sCGINames[3]; - - if (sCGIFullPath == null - || sCGIScriptName == null - || sCGIFullName == null - || sCGIName == null) { - return false; - } - - envp.put("SERVER_SOFTWARE", "TOMCAT"); - - envp.put("SERVER_NAME", nullsToBlanks(req.getServerName())); - - envp.put("GATEWAY_INTERFACE", "CGI/1.1"); - - envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol())); - - int port = req.getServerPort(); - Integer iPort = (port == 0 ? new Integer(-1) : new Integer(port)); - envp.put("SERVER_PORT", iPort.toString()); - - envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod())); - - envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI())); - - - /*- - * PATH_INFO should be determined by using sCGIFullName: - * 1) Let sCGIFullName not end in a "/" (see method findCGI) - * 2) Let sCGIFullName equal the pathInfo fragment which - * corresponds to the actual cgi script. - * 3) Thus, PATH_INFO = request.getPathInfo().substring( - * sCGIFullName.length()) - * - * (see method findCGI, where the real work is done) - * - */ - if (pathInfo == null - || (pathInfo.substring(sCGIFullName.length()).length() <= 0)) { - sPathInfoCGI = ""; - } else { - sPathInfoCGI = pathInfo.substring(sCGIFullName.length()); - } - envp.put("PATH_INFO", sPathInfoCGI); - - - /*- - * PATH_TRANSLATED must be determined after PATH_INFO (and the - * implied real cgi-script) has been taken into account. - * - * The following example demonstrates: - * - * servlet info = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2 - * cgifullpath = /servlet/cgigw/dir1/dir2/cgi1 - * path_info = /trans1/trans2 - * webAppRootDir = servletContext.getRealPath("/") - * - * path_translated = servletContext.getRealPath("/trans1/trans2") - * - * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI - * (unless sPathInfoCGI is null or blank, then the CGI - * specification dictates that the PATH_TRANSLATED metavariable - * SHOULD NOT be defined. - * - */ - if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) { - sPathTranslatedCGI = context.getRealPath(sPathInfoCGI); - } else { - sPathTranslatedCGI = null; - } - if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) { - //NOOP - } else { - envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI)); - } - - - envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName)); - - envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString())); - - envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost())); - - envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr())); - - envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType())); - - envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser())); - - envp.put("REMOTE_IDENT", ""); //not necessary for full compliance - - envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType())); - - - /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined - * if there is no content, so we cannot put 0 or -1 in as per the - * Servlet API spec. - */ - int contentLength = req.getContentLength(); - String sContentLength = (contentLength <= 0 ? "" : - (new Integer(contentLength)).toString()); - envp.put("CONTENT_LENGTH", sContentLength); - - - Enumeration headers = req.getHeaderNames(); - String header = null; - while (headers.hasMoreElements()) { - header = null; - header = ((String) headers.nextElement()).toUpperCase(); - //REMIND: rewrite multiple headers as if received as single - //REMIND: change character set - //REMIND: I forgot what the previous REMIND means - if ("AUTHORIZATION".equalsIgnoreCase(header) || - "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) { - //NOOP per CGI specification section 11.2 - } else { - envp.put("HTTP_" + header.replace('-', '_'), - req.getHeader(header)); - } - } - - File fCGIFullPath = new File(sCGIFullPath); - command = fCGIFullPath.getCanonicalPath(); - - envp.put("X_TOMCAT_SCRIPT_PATH", command); //for kicks - - this.env = envp; - - return true; - - } - - /** - * Extracts requested resource from web app archive to context work - * directory to enable CGI script to be executed. - */ - protected void expandCGIScript() { - StringBuffer srcPath = new StringBuffer(); - StringBuffer destPath = new StringBuffer(); - InputStream is = null; - - // paths depend on mapping - if (cgiPathPrefix == null ) { - srcPath.append(pathInfo); - is = context.getResourceAsStream(srcPath.toString()); - destPath.append(tmpDir); - destPath.append(pathInfo); - } else { - // essentially same search algorithm as findCGI() - srcPath.append(cgiPathPrefix); - StringTokenizer pathWalker = - new StringTokenizer (pathInfo, "/"); - // start with first element - while (pathWalker.hasMoreElements() && (is == null)) { - srcPath.append("/"); - srcPath.append(pathWalker.nextElement()); - is = context.getResourceAsStream(srcPath.toString()); - } - destPath.append(tmpDir); - destPath.append("/"); - destPath.append(srcPath); - } - - if (is == null) { - // didn't find anything, give up now - if (debug >= 2) { - log("expandCGIScript: source '" + srcPath + "' not found"); - } - return; - } - - File f = new File(destPath.toString()); - if (f.exists()) { - // Don't need to expand if it already exists - return; - } - - // create directories - String dirPath = new String (destPath.toString().substring( - 0,destPath.toString().lastIndexOf("/"))); - File dir = new File(dirPath); - dir.mkdirs(); - - try { - synchronized (expandFileLock) { - // make sure file doesn't exist - if (f.exists()) { - return; - } - - // create file - if (!f.createNewFile()) { - return; - } - FileOutputStream fos = new FileOutputStream(f); - - // copy data - IOTools.flow(is, fos); - is.close(); - fos.close(); - if (debug >= 2) { - log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'"); - } - } - } catch (IOException ioe) { - // delete in case file is corrupted - if (f.exists()) { - f.delete(); - } - } - } - - - /** - * Print important CGI environment information in a easy-to-read HTML - * table - * - * @return HTML string containing CGI environment info - * - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - - sb.append(""); - - sb.append(""); - - sb.append(""); - - sb.append(""); - - if (isValid()) { - Enumeration envk = env.keys(); - while (envk.hasMoreElements()) { - String s = (String) envk.nextElement(); - sb.append(""); - } - } - - sb.append(""); - - sb.append(""); - - sb.append(""); - - sb.append(""); - - sb.append("
    "); - sb.append("CGIEnvironment Info
    Debug Level"); - sb.append(debug); - sb.append("
    Validity:"); - sb.append(isValid()); - sb.append("
    "); - sb.append(s); - sb.append(""); - sb.append(blanksToString((String) env.get(s), - "[will be set to blank]")); - sb.append("

    Derived Command"); - sb.append(nullsToBlanks(command)); - sb.append("
    Working Directory"); - if (workingDirectory != null) { - sb.append(workingDirectory.toString()); - } - sb.append("
    Command Line Params"); - for (int i=0; i < cmdLineParameters.size(); i++) { - String param = (String) cmdLineParameters.get(i); - sb.append("

    "); - sb.append(param); - sb.append("

    "); - } - sb.append("

    end."); - - return sb.toString(); - } - - - - /** - * Gets derived command string - * - * @return command string - * - */ - protected String getCommand() { - return command; - } - - - - /** - * Gets derived CGI working directory - * - * @return working directory - * - */ - protected File getWorkingDirectory() { - return workingDirectory; - } - - - - /** - * Gets derived CGI environment - * - * @return CGI environment - * - */ - protected Hashtable getEnvironment() { - return env; - } - - - - /** - * Gets derived CGI query parameters - * - * @return CGI query parameters - * - */ - protected ArrayList getParameters() { - return cmdLineParameters; - } - - - - /** - * Gets validity status - * - * @return true if this environment is valid, false - * otherwise - * - */ - protected boolean isValid() { - return valid; - } - - - - /** - * Converts null strings to blank strings ("") - * - * @param s string to be converted if necessary - * @return a non-null string, either the original or the empty string - * ("") if the original was null - */ - protected String nullsToBlanks(String s) { - return nullsToString(s, ""); - } - - - - /** - * Converts null strings to another string - * - * @param couldBeNull string to be converted if necessary - * @param subForNulls string to return instead of a null string - * @return a non-null string, either the original or the substitute - * string if the original was null - */ - protected String nullsToString(String couldBeNull, - String subForNulls) { - return (couldBeNull == null ? subForNulls : couldBeNull); - } - - - - /** - * Converts blank strings to another string - * - * @param couldBeBlank string to be converted if necessary - * @param subForBlanks string to return instead of a blank string - * @return a non-null string, either the original or the substitute - * string if the original was null or empty ("") - */ - protected String blanksToString(String couldBeBlank, - String subForBlanks) { - return (("".equals(couldBeBlank) || couldBeBlank == null) - ? subForBlanks - : couldBeBlank); - } - - - - } //class CGIEnvironment - - - - - - - /** - * Encapsulates the knowledge of how to run a CGI script, given the - * script's desired environment and (optionally) input/output streams - * - *

    - * - * Exposes a run method used to actually invoke the - * CGI. - * - *

    - *

    - * - * The CGI environment and settings are derived from the information - * passed to the constuctor. - * - *

    - *

    - * - * The input and output streams can be set by the setInput - * and setResponse methods, respectively. - *

    - * - * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ - */ - - protected class CGIRunner { - - /** script/command to be executed */ - private String command = null; - - /** environment used when invoking the cgi script */ - private Hashtable env = null; - - /** working directory used when invoking the cgi script */ - private File wd = null; - - /** command line parameters to be passed to the invoked script */ - private ArrayList params = null; - - /** stdin to be passed to cgi script */ - private InputStream stdin = null; - - /** response object used to set headers & get output stream */ - private HttpServletResponse response = null; - - /** boolean tracking whether this object has enough info to run() */ - private boolean readyToRun = false; - - - - - /** - * Creates a CGIRunner and initializes its environment, working - * directory, and query parameters. - *
    - * Input/output streams (optional) are set using the - * setInput and setResponse methods, - * respectively. - * - * @param command string full path to command to be executed - * @param env Hashtable with the desired script environment - * @param wd File with the script's desired working directory - * @param params ArrayList with the script's query command line - * paramters as strings - */ - protected CGIRunner(String command, Hashtable env, File wd, - ArrayList params) { - this.command = command; - this.env = env; - this.wd = wd; - this.params = params; - updateReadyStatus(); - } - - - - /** - * Checks & sets ready status - */ - protected void updateReadyStatus() { - if (command != null - && env != null - && wd != null - && params != null - && response != null) { - readyToRun = true; - } else { - readyToRun = false; - } - } - - - - /** - * Gets ready status - * - * @return false if not ready (run will throw - * an exception), true if ready - */ - protected boolean isReady() { - return readyToRun; - } - - - - /** - * Sets HttpServletResponse object used to set headers and send - * output to - * - * @param response HttpServletResponse to be used - * - */ - protected void setResponse(HttpServletResponse response) { - this.response = response; - updateReadyStatus(); - } - - - - /** - * Sets standard input to be passed on to the invoked cgi script - * - * @param stdin InputStream to be used - * - */ - protected void setInput(InputStream stdin) { - this.stdin = stdin; - updateReadyStatus(); - } - - - - /** - * Converts a Hashtable to a String array by converting each - * key/value pair in the Hashtable to a String in the form - * "key=value" (hashkey + "=" + hash.get(hashkey).toString()) - * - * @param h Hashtable to convert - * - * @return converted string array - * - * @exception NullPointerException if a hash key has a null value - * - */ - protected String[] hashToStringArray(Hashtable h) - throws NullPointerException { - Vector v = new Vector(); - Enumeration e = h.keys(); - while (e.hasMoreElements()) { - String k = e.nextElement().toString(); - v.add(k + "=" + h.get(k)); - } - String[] strArr = new String[v.size()]; - v.copyInto(strArr); - return strArr; - } - - - - /** - * Executes a CGI script with the desired environment, current working - * directory, and input/output streams - * - *

    - * This implements the following CGI specification recommedations: - *

      - *
    • Servers SHOULD provide the "query" component of - * the script-URI as command-line arguments to scripts if it - * does not contain any unencoded "=" characters and the - * command-line arguments can be generated in an unambiguous - * manner. - *
    • Servers SHOULD set the AUTH_TYPE metavariable to the value - * of the "auth-scheme" token of the - * "Authorization" if it was supplied as part of the - * request header. See getCGIEnvironment method. - *
    • Where applicable, servers SHOULD set the current working - * directory to the directory in which the script is located - * before invoking it. - *
    • Server implementations SHOULD define their behavior for the - * following cases: - *
        - *
      • Allowed characters in pathInfo: This implementation - * does not allow ASCII NUL nor any character which cannot - * be URL-encoded according to internet standards; - *
      • Allowed characters in path segments: This - * implementation does not allow non-terminal NULL - * segments in the the path -- IOExceptions may be thrown; - *
      • "." and ".." path - * segments: - * This implementation does not allow "." and - * ".." in the the path, and such characters - * will result in an IOException being thrown; - *
      • Implementation limitations: This implementation - * does not impose any limitations except as documented - * above. This implementation may be limited by the - * servlet container used to house this implementation. - * In particular, all the primary CGI variable values - * are derived either directly or indirectly from the - * container's implementation of the Servlet API methods. - *
      - *
    - *

    - * - * @exception IOException if problems during reading/writing occur - * - * @see java.lang.Runtime#exec(String command, String[] envp, - * File dir) - */ - protected void run() throws IOException { - - /* - * REMIND: this method feels too big; should it be re-written? - */ - - if (!isReady()) { - throw new IOException(this.getClass().getName() - + ": not ready to run."); - } - - if (debug >= 1 ) { - log("runCGI(envp=[" + env + "], command=" + command + ")"); - } - - if ((command.indexOf(File.separator + "." + File.separator) >= 0) - || (command.indexOf(File.separator + "..") >= 0) - || (command.indexOf(".." + File.separator) >= 0)) { - throw new IOException(this.getClass().getName() - + "Illegal Character in CGI command " - + "path ('.' or '..') detected. Not " - + "running CGI [" + command + "]."); - } - - /* original content/structure of this section taken from - * http://developer.java.sun.com/developer/ - * bugParade/bugs/4216884.html - * with major modifications by Martin Dengler - */ - Runtime rt = null; - InputStream cgiOutput = null; - BufferedReader commandsStdErr = null; - BufferedOutputStream commandsStdIn = null; - Process proc = null; - int bufRead = -1; - - //create query arguments - StringBuffer cmdAndArgs = new StringBuffer(); - if (command.indexOf(" ") < 0) { - cmdAndArgs.append(command); - } else { - // Spaces used as delimiter, so need to use quotes - cmdAndArgs.append("\""); - cmdAndArgs.append(command); - cmdAndArgs.append("\""); - } - - for (int i=0; i < params.size(); i++) { - cmdAndArgs.append(" "); - String param = (String) params.get(i); - if (param.indexOf(" ") < 0) { - cmdAndArgs.append(param); - } else { - // Spaces used as delimiter, so need to use quotes - cmdAndArgs.append("\""); - cmdAndArgs.append(param); - cmdAndArgs.append("\""); - } - } - - StringBuffer command = new StringBuffer(cgiExecutable); - command.append(" "); - command.append(cmdAndArgs.toString()); - cmdAndArgs = command; - - rt = Runtime.getRuntime(); - proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd); - - String sContentLength = (String) env.get("CONTENT_LENGTH"); - - if(!"".equals(sContentLength)) { - commandsStdIn = new BufferedOutputStream(proc.getOutputStream()); - IOTools.flow(stdin, commandsStdIn); - commandsStdIn.flush(); - commandsStdIn.close(); - } - - /* we want to wait for the process to exit, Process.waitFor() - * is useless in our situation; see - * http://developer.java.sun.com/developer/ - * bugParade/bugs/4223650.html - */ - - boolean isRunning = true; - commandsStdErr = new BufferedReader - (new InputStreamReader(proc.getErrorStream())); - final BufferedReader stdErrRdr = commandsStdErr ; - - new Thread() { - public void run () { - sendToLog(stdErrRdr) ; - } ; - }.start() ; - - InputStream cgiHeaderStream = - new HTTPHeaderInputStream(proc.getInputStream()); - BufferedReader cgiHeaderReader = - new BufferedReader(new InputStreamReader(cgiHeaderStream)); - - while (isRunning) { - try { - //set headers - String line = null; - while (((line = cgiHeaderReader.readLine()) != null) - && !("".equals(line))) { - if (debug >= 2) { - log("runCGI: addHeader(\"" + line + "\")"); - } - if (line.startsWith("HTTP")) { - response.setStatus(getSCFromHttpStatusLine(line)); - } else if (line.indexOf(":") >= 0) { - String header = - line.substring(0, line.indexOf(":")).trim(); - String value = - line.substring(line.indexOf(":") + 1).trim(); - if (header.equalsIgnoreCase("status")) { - response.setStatus(getSCFromCGIStatusHeader(value)); - } else { - response.addHeader(header , value); - } - } else { - log("runCGI: bad header line \"" + line + "\""); - } - } - - //write output - byte[] bBuf = new byte[2048]; - - OutputStream out = response.getOutputStream(); - cgiOutput = proc.getInputStream(); - - try { - while ((bufRead = cgiOutput.read(bBuf)) != -1) { - if (debug >= 4) { - log("runCGI: output " + bufRead + - " bytes of data"); - } - out.write(bBuf, 0, bufRead); - } - } finally { - // Attempt to consume any leftover byte if something bad happens, - // such as a socket disconnect on the servlet side; otherwise, the - // external process could hang - if (bufRead != -1) { - while ((bufRead = cgiOutput.read(bBuf)) != -1) {} - } - } - - proc.exitValue(); // Throws exception if alive - - isRunning = false; - - } catch (IllegalThreadStateException e) { - try { - Thread.sleep(500); - } catch (InterruptedException ignored) { - } - } - } //replacement for Process.waitFor() - - // Close the output stream used - cgiOutput.close(); - } - - /** - * Parses the Status-Line and extracts the status code. - * - * @param line The HTTP Status-Line (RFC2616, section 6.1) - * @return The extracted status code or the code representing an - * internal error if a valid status code cannot be extracted. - */ - private int getSCFromHttpStatusLine(String line) { - int statusStart = line.indexOf(' ') + 1; - - if (statusStart < 1 || line.length() < statusStart + 3) { - // Not a valid HTTP Status-Line - log ("runCGI: invalid HTTP Status-Line:" + line); - return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - } - - String status = line.substring(statusStart, statusStart + 3); - - int statusCode; - try { - statusCode = Integer.parseInt(status); - } catch (NumberFormatException nfe) { - // Not a valid status code - log ("runCGI: invalid status code:" + status); - return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - } - - return statusCode; - } - - /** - * Parses the CGI Status Header value and extracts the status code. - * - * @param value The CGI Status value of the form - * digit digit digit SP reason-phrase - * @return The extracted status code or the code representing an - * internal error if a valid status code cannot be extracted. - */ - private int getSCFromCGIStatusHeader(String value) { - if (value.length() < 3) { - // Not a valid status value - log ("runCGI: invalid status value:" + value); - return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - } - - String status = value.substring(0, 3); - - int statusCode; - try { - statusCode = Integer.parseInt(status); - } catch (NumberFormatException nfe) { - // Not a valid status code - log ("runCGI: invalid status code:" + status); - return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - } - - return statusCode; - } - - private void sendToLog(BufferedReader rdr) { - String line = null; - int lineCount = 0 ; - try { - while ((line = rdr.readLine()) != null) { - log("runCGI (stderr):" + line) ; - lineCount++ ; - } - } catch (IOException e) { - log("sendToLog error", e) ; - } finally { - try { - rdr.close() ; - } catch (IOException ce) { - log("sendToLog error", ce) ; - } ; - } ; - if ( lineCount > 0 && debug > 2) { - log("runCGI: " + lineCount + " lines received on stderr") ; - } ; - } - } //class CGIRunner - - /** - * This is an input stream specifically for reading HTTP headers. It reads - * upto and including the two blank lines terminating the headers. It - * allows the content to be read using bytes or characters as appropriate. - */ - protected class HTTPHeaderInputStream extends InputStream { - private static final int STATE_CHARACTER = 0; - private static final int STATE_FIRST_CR = 1; - private static final int STATE_FIRST_LF = 2; - private static final int STATE_SECOND_CR = 3; - private static final int STATE_HEADER_END = 4; - - private InputStream input; - private int state; - - HTTPHeaderInputStream(InputStream theInput) { - input = theInput; - state = STATE_CHARACTER; - } - - /** - * @see java.io.InputStream#read() - */ - public int read() throws IOException { - if (state == STATE_HEADER_END) { - return -1; - } - - int i = input.read(); - - // Update the state - // State machine looks like this - // - // -------->-------- - // | (CR) | - // | | - // CR1--->--- | - // | | | - // ^(CR) |(LF) | - // | | | - // CHAR--->--LF1--->--EOH - // (LF) | (LF) | - // |(CR) ^(LF) - // | | - // (CR2)-->--- - - if (i == 10) { - // LF - switch(state) { - case STATE_CHARACTER: - state = STATE_FIRST_LF; - break; - case STATE_FIRST_CR: - state = STATE_FIRST_LF; - break; - case STATE_FIRST_LF: - case STATE_SECOND_CR: - state = STATE_HEADER_END; - break; - } - - } else if (i == 13) { - // CR - switch(state) { - case STATE_CHARACTER: - state = STATE_FIRST_CR; - break; - case STATE_FIRST_CR: - state = STATE_HEADER_END; - break; - case STATE_FIRST_LF: - state = STATE_SECOND_CR; - break; - } - - } else { - state = STATE_CHARACTER; - } - - return i; - } - } // class HTTPHeaderInputStream - -} //class CGIServlet +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.UnavailableException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Globals; +import org.apache.catalina.util.IOTools; + + +/** + * CGI-invoking servlet for web applications, used to execute scripts which + * comply to the Common Gateway Interface (CGI) specification and are named + * in the path-info used to invoke this servlet. + * + *

    + * Note: This code compiles and even works for simple CGI cases. + * Exhaustive testing has not been done. Please consider it beta + * quality. Feedback is appreciated to the author (see below). + *

    + *

    + * + * Example:
    + * If an instance of this servlet was mapped (using + * <web-app>/WEB-INF/web.xml) to: + *

    + *

    + * + * <web-app>/cgi-bin/* + * + *

    + *

    + * then the following request: + *

    + *

    + * + * http://localhost:8080/<web-app>/cgi-bin/dir1/script/pathinfo1 + * + *

    + *

    + * would result in the execution of the script + *

    + *

    + * + * <web-app-root>/WEB-INF/cgi/dir1/script + * + *

    + *

    + * with the script's PATH_INFO set to /pathinfo1. + *

    + *

    + * Recommendation: House all your CGI scripts under + * <webapp>/WEB-INF/cgi. This will ensure that you do not + * accidentally expose your cgi scripts' code to the outside world and that + * your cgis will be cleanly ensconced underneath the WEB-INF (i.e., + * non-content) area. + *

    + *

    + * The default CGI location is mentioned above. You have the flexibility to + * put CGIs wherever you want, however: + *

    + *

    + * The CGI search path will start at + * webAppRootDir + File.separator + cgiPathPrefix + * (or webAppRootDir alone if cgiPathPrefix is + * null). + *

    + *

    + * cgiPathPrefix is defined by setting + * this servlet's cgiPathPrefix init parameter + *

    + * + *

    + * + * CGI Specification:
    derived from + * http://cgi-spec.golux.com. + * A work-in-progress & expired Internet Draft. Note no actual RFC describing + * the CGI specification exists. Where the behavior of this servlet differs + * from the specification cited above, it is either documented here, a bug, + * or an instance where the specification cited differs from Best + * Community Practice (BCP). + * Such instances should be well-documented here. Please email the + * Jakarta Tomcat group [tomcat-dev@jakarta.apache.org] + * with amendments. + * + *

    + *

    + * + * Canonical metavariables:
    + * The CGI specification defines the following canonical metavariables: + *
    + * [excerpt from CGI specification] + *

    + *  AUTH_TYPE
    + *  CONTENT_LENGTH
    + *  CONTENT_TYPE
    + *  GATEWAY_INTERFACE
    + *  PATH_INFO
    + *  PATH_TRANSLATED
    + *  QUERY_STRING
    + *  REMOTE_ADDR
    + *  REMOTE_HOST
    + *  REMOTE_IDENT
    + *  REMOTE_USER
    + *  REQUEST_METHOD
    + *  SCRIPT_NAME
    + *  SERVER_NAME
    + *  SERVER_PORT
    + *  SERVER_PROTOCOL
    + *  SERVER_SOFTWARE
    + * 
    + *

    + * Metavariables with names beginning with the protocol name (e.g., + * "HTTP_ACCEPT") are also canonical in their description of request header + * fields. The number and meaning of these fields may change independently + * of this specification. (See also section 6.1.5 [of the CGI specification].) + *

    + * [end excerpt] + * + *

    + *

    Implementation notes

    + *

    + * + * standard input handling: If your script accepts standard input, + * then the client must start sending input within a certain timeout period, + * otherwise the servlet will assume no input is coming and carry on running + * the script. The script's the standard input will be closed and handling of + * any further input from the client is undefined. Most likely it will be + * ignored. If this behavior becomes undesirable, then this servlet needs + * to be enhanced to handle threading of the spawned process' stdin, stdout, + * and stderr (which should not be too hard). + *
    + * If you find your cgi scripts are timing out receiving input, you can set + * the init parameter of your webapps' cgi-handling servlet + * to be + *

    + *

    + * + * Metavariable Values: According to the CGI specificion, + * implementations may choose to represent both null or missing values in an + * implementation-specific manner, but must define that manner. This + * implementation chooses to always define all required metavariables, but + * set the value to "" for all metavariables whose value is either null or + * undefined. PATH_TRANSLATED is the sole exception to this rule, as per the + * CGI Specification. + * + *

    + *

    + * + * NPH -- Non-parsed-header implementation: This implementation does + * not support the CGI NPH concept, whereby server ensures that the data + * supplied to the script are preceisely as supplied by the client and + * unaltered by the server. + *

    + *

    + * The function of a servlet container (including Tomcat) is specifically + * designed to parse and possible alter CGI-specific variables, and as + * such makes NPH functionality difficult to support. + *

    + *

    + * The CGI specification states that compliant servers MAY support NPH output. + * It does not state servers MUST support NPH output to be unconditionally + * compliant. Thus, this implementation maintains unconditional compliance + * with the specification though NPH support is not present. + *

    + *

    + * + * The CGI specification is located at + * http://cgi-spec.golux.com. + * + *

    + *

    + *

    TODO:

    + *
      + *
    • Support for setting headers (for example, Location headers don't work) + *
    • Support for collapsing multiple header lines (per RFC 2616) + *
    • Ensure handling of POST method does not interfere with 2.3 Filters + *
    • Refactor some debug code out of core + *
    • Ensure header handling preserves encoding + *
    • Possibly rewrite CGIRunner.run()? + *
    • Possibly refactor CGIRunner and CGIEnvironment as non-inner classes? + *
    • Document handling of cgi stdin when there is no stdin + *
    • Revisit IOException handling in CGIRunner.run() + *
    • Better documentation + *
    • Confirm use of ServletInputStream.available() in CGIRunner.run() is + * not needed + *
    • Make checking for "." and ".." in servlet & cgi PATH_INFO less + * draconian + *
    • [add more to this TODO list] + *
    + *

    + * + * @author Martin T Dengler [root@martindengler.com] + * @author Amy Roh + * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ + * @since Tomcat 4.0 + * + */ + + +public final class CGIServlet extends HttpServlet { + + /* some vars below copied from Craig R. McClanahan's InvokerServlet */ + + /** the debugging detail level for this servlet. */ + private int debug = 0; + + /** + * The CGI search path will start at + * webAppRootDir + File.separator + cgiPathPrefix + * (or webAppRootDir alone if cgiPathPrefix is + * null) + */ + private String cgiPathPrefix = null; + + /** the executable to use with the script */ + private String cgiExecutable = "perl"; + + /** the encoding to use for parameters */ + private String parameterEncoding = System.getProperty("file.encoding", + "UTF-8"); + + /** object used to ensure multiple threads don't try to expand same file */ + static Object expandFileLock = new Object(); + + /** the shell environment variables to be passed to the CGI script */ + static Hashtable shellEnv = new Hashtable(); + + /** + * Sets instance variables. + *

    + * Modified from Craig R. McClanahan's InvokerServlet + *

    + * + * @param config a ServletConfig object + * containing the servlet's + * configuration and initialization + * parameters + * + * @exception ServletException if an exception has occurred that + * interferes with the servlet's normal + * operation + */ + public void init(ServletConfig config) throws ServletException { + + super.init(config); + + // Verify that we were not accessed using the invoker servlet + String servletName = getServletConfig().getServletName(); + if (servletName == null) + servletName = ""; + if (servletName.startsWith("org.apache.catalina.INVOKER.")) + throw new UnavailableException + ("Cannot invoke CGIServlet through the invoker"); + + boolean passShellEnvironment = false; + + // Set our properties from the initialization parameters + String value = null; + try { + value = getServletConfig().getInitParameter("debug"); + debug = Integer.parseInt(value); + cgiPathPrefix = + getServletConfig().getInitParameter("cgiPathPrefix"); + value = getServletConfig().getInitParameter("passShellEnvironment"); + passShellEnvironment = Boolean.valueOf(value).booleanValue(); + } catch (Throwable t) { + //NOOP + } + log("init: loglevel set to " + debug); + + if (passShellEnvironment) { + try { + shellEnv.putAll(getShellEnvironment()); + } catch (IOException ioe) { + ServletException e = new ServletException( + "Unable to read shell environment variables", ioe); + throw e; + } + } + + value = getServletConfig().getInitParameter("executable"); + if (value != null) { + cgiExecutable = value; + } + + value = getServletConfig().getInitParameter("parameterEncoding"); + if (value != null) { + parameterEncoding = value; + } + + } + + + + /** + * Prints out important Servlet API and container information + * + *

    + * Copied from SnoopAllServlet by Craig R. McClanahan + *

    + * + * @param out ServletOutputStream as target of the information + * @param req HttpServletRequest object used as source of information + * @param res HttpServletResponse object currently not used but could + * provide future information + * + * @exception IOException if a write operation exception occurs + * + */ + protected void printServletEnvironment(ServletOutputStream out, + HttpServletRequest req, HttpServletResponse res) throws IOException { + + // Document the properties from ServletRequest + out.println("

    ServletRequest Properties

    "); + out.println("
      "); + Enumeration attrs = req.getAttributeNames(); + while (attrs.hasMoreElements()) { + String attr = (String) attrs.nextElement(); + out.println("
    • attribute " + attr + " = " + + req.getAttribute(attr)); + } + out.println("
    • characterEncoding = " + + req.getCharacterEncoding()); + out.println("
    • contentLength = " + + req.getContentLength()); + out.println("
    • contentType = " + + req.getContentType()); + Enumeration locales = req.getLocales(); + while (locales.hasMoreElements()) { + Locale locale = (Locale) locales.nextElement(); + out.println("
    • locale = " + locale); + } + Enumeration params = req.getParameterNames(); + while (params.hasMoreElements()) { + String param = (String) params.nextElement(); + String values[] = req.getParameterValues(param); + for (int i = 0; i < values.length; i++) + out.println("
    • parameter " + param + " = " + + values[i]); + } + out.println("
    • protocol = " + req.getProtocol()); + out.println("
    • remoteAddr = " + req.getRemoteAddr()); + out.println("
    • remoteHost = " + req.getRemoteHost()); + out.println("
    • scheme = " + req.getScheme()); + out.println("
    • secure = " + req.isSecure()); + out.println("
    • serverName = " + req.getServerName()); + out.println("
    • serverPort = " + req.getServerPort()); + out.println("
    "); + out.println("
    "); + + // Document the properties from HttpServletRequest + out.println("

    HttpServletRequest Properties

    "); + out.println("
      "); + out.println("
    • authType = " + req.getAuthType()); + out.println("
    • contextPath = " + + req.getContextPath()); + Cookie cookies[] = req.getCookies(); + if (cookies!=null) { + for (int i = 0; i < cookies.length; i++) + out.println("
    • cookie " + cookies[i].getName() +" = " +cookies[i].getValue()); + } + Enumeration headers = req.getHeaderNames(); + while (headers.hasMoreElements()) { + String header = (String) headers.nextElement(); + out.println("
    • header " + header + " = " + + req.getHeader(header)); + } + out.println("
    • method = " + req.getMethod()); + out.println("
    • pathInfo = " + + req.getPathInfo()); + out.println("
    • pathTranslated = " + + req.getPathTranslated()); + out.println("
    • queryString = " + + req.getQueryString()); + out.println("
    • remoteUser = " + + req.getRemoteUser()); + out.println("
    • requestedSessionId = " + + req.getRequestedSessionId()); + out.println("
    • requestedSessionIdFromCookie = " + + req.isRequestedSessionIdFromCookie()); + out.println("
    • requestedSessionIdFromURL = " + + req.isRequestedSessionIdFromURL()); + out.println("
    • requestedSessionIdValid = " + + req.isRequestedSessionIdValid()); + out.println("
    • requestURI = " + + req.getRequestURI()); + out.println("
    • servletPath = " + + req.getServletPath()); + out.println("
    • userPrincipal = " + + req.getUserPrincipal()); + out.println("
    "); + out.println("
    "); + + // Document the servlet request attributes + out.println("

    ServletRequest Attributes

    "); + out.println("
      "); + attrs = req.getAttributeNames(); + while (attrs.hasMoreElements()) { + String attr = (String) attrs.nextElement(); + out.println("
    • " + attr + " = " + + req.getAttribute(attr)); + } + out.println("
    "); + out.println("
    "); + + // Process the current session (if there is one) + HttpSession session = req.getSession(false); + if (session != null) { + + // Document the session properties + out.println("

    HttpSession Properties

    "); + out.println("
      "); + out.println("
    • id = " + + session.getId()); + out.println("
    • creationTime = " + + new Date(session.getCreationTime())); + out.println("
    • lastAccessedTime = " + + new Date(session.getLastAccessedTime())); + out.println("
    • maxInactiveInterval = " + + session.getMaxInactiveInterval()); + out.println("
    "); + out.println("
    "); + + // Document the session attributes + out.println("

    HttpSession Attributes

    "); + out.println("
      "); + attrs = session.getAttributeNames(); + while (attrs.hasMoreElements()) { + String attr = (String) attrs.nextElement(); + out.println("
    • " + attr + " = " + + session.getAttribute(attr)); + } + out.println("
    "); + out.println("
    "); + + } + + // Document the servlet configuration properties + out.println("

    ServletConfig Properties

    "); + out.println("
      "); + out.println("
    • servletName = " + + getServletConfig().getServletName()); + out.println("
    "); + out.println("
    "); + + // Document the servlet configuration initialization parameters + out.println("

    ServletConfig Initialization Parameters

    "); + out.println("
      "); + params = getServletConfig().getInitParameterNames(); + while (params.hasMoreElements()) { + String param = (String) params.nextElement(); + String value = getServletConfig().getInitParameter(param); + out.println("
    • " + param + " = " + value); + } + out.println("
    "); + out.println("
    "); + + // Document the servlet context properties + out.println("

    ServletContext Properties

    "); + out.println("
      "); + out.println("
    • majorVersion = " + + getServletContext().getMajorVersion()); + out.println("
    • minorVersion = " + + getServletContext().getMinorVersion()); + out.println("
    • realPath('/') = " + + getServletContext().getRealPath("/")); + out.println("
    • serverInfo = " + + getServletContext().getServerInfo()); + out.println("
    "); + out.println("
    "); + + // Document the servlet context initialization parameters + out.println("

    ServletContext Initialization Parameters

    "); + out.println("
      "); + params = getServletContext().getInitParameterNames(); + while (params.hasMoreElements()) { + String param = (String) params.nextElement(); + String value = getServletContext().getInitParameter(param); + out.println("
    • " + param + " = " + value); + } + out.println("
    "); + out.println("
    "); + + // Document the servlet context attributes + out.println("

    ServletContext Attributes

    "); + out.println("
      "); + attrs = getServletContext().getAttributeNames(); + while (attrs.hasMoreElements()) { + String attr = (String) attrs.nextElement(); + out.println("
    • " + attr + " = " + + getServletContext().getAttribute(attr)); + } + out.println("
    "); + out.println("
    "); + + + + } + + + + /** + * Provides CGI Gateway service -- delegates to doGet + * + * @param req HttpServletRequest passed in by servlet container + * @param res HttpServletResponse passed in by servlet container + * + * @exception ServletException if a servlet-specific exception occurs + * @exception IOException if a read/write exception occurs + * + * @see javax.servlet.http.HttpServlet + * + */ + protected void doPost(HttpServletRequest req, HttpServletResponse res) + throws IOException, ServletException { + doGet(req, res); + } + + + + /** + * Provides CGI Gateway service + * + * @param req HttpServletRequest passed in by servlet container + * @param res HttpServletResponse passed in by servlet container + * + * @exception ServletException if a servlet-specific exception occurs + * @exception IOException if a read/write exception occurs + * + * @see javax.servlet.http.HttpServlet + * + */ + protected void doGet(HttpServletRequest req, HttpServletResponse res) + throws ServletException, IOException { + + // Verify that we were not accessed using the invoker servlet + if (req.getAttribute(Globals.INVOKED_ATTR) != null) + throw new UnavailableException + ("Cannot invoke CGIServlet through the invoker"); + + CGIEnvironment cgiEnv = new CGIEnvironment(req, getServletContext()); + + if (cgiEnv.isValid()) { + CGIRunner cgi = new CGIRunner(cgiEnv.getCommand(), + cgiEnv.getEnvironment(), + cgiEnv.getWorkingDirectory(), + cgiEnv.getParameters()); + //if POST, we need to cgi.setInput + //REMIND: how does this interact with Servlet API 2.3's Filters?! + if ("POST".equals(req.getMethod())) { + cgi.setInput(req.getInputStream()); + } + cgi.setResponse(res); + cgi.run(); + } + + if (!cgiEnv.isValid()) { + res.setStatus(404); + } + + if (debug >= 10) { + try { + ServletOutputStream out = res.getOutputStream(); + out.println("$Name$"); + out.println("$Header$

    "); + + if (cgiEnv.isValid()) { + out.println(cgiEnv.toString()); + } else { + out.println("

    "); + out.println("CGI script not found or not specified."); + out.println("

    "); + out.println("

    "); + out.println("Check the HttpServletRequest "); + out.println("pathInfo "); + out.println("property to see if it is what you meant "); + out.println("it to be. You must specify an existant "); + out.println("and executable file as part of the "); + out.println("path-info."); + out.println("

    "); + out.println("

    "); + out.println("For a good discussion of how CGI scripts "); + out.println("work and what their environment variables "); + out.println("mean, please visit the CGI "); + out.println("Specification page."); + out.println("

    "); + + } + + printServletEnvironment(out, req, res); + + out.println(""); + + } catch (IOException ignored) { + } + + } //debugging + + + } //doGet + + + + /** For future testing use only; does nothing right now */ + public static void main(String[] args) { + System.out.println("$Header$"); + } + + /** + * Get all shell environment variables. Have to do it this rather ugly way + * as the API to obtain is not available in 1.4 and earlier APIs. + * + * See Read environment + * variables from an application for original source and article. + */ + private Hashtable getShellEnvironment() throws IOException { + Hashtable envVars = new Hashtable(); + Process p = null; + Runtime r = Runtime.getRuntime(); + String OS = System.getProperty("os.name").toLowerCase(); + boolean ignoreCase; + + if (OS.indexOf("windows 9") > -1) { + p = r.exec( "command.com /c set" ); + ignoreCase = true; + } else if ( (OS.indexOf("nt") > -1) + || (OS.indexOf("windows 20") > -1) + || (OS.indexOf("windows xp") > -1) ) { + // thanks to JuanFran for the xp fix! + p = r.exec( "cmd.exe /c set" ); + ignoreCase = true; + } else { + // our last hope, we assume Unix (thanks to H. Ware for the fix) + p = r.exec( "env" ); + ignoreCase = false; + } + + BufferedReader br = new BufferedReader + ( new InputStreamReader( p.getInputStream() ) ); + String line; + while( (line = br.readLine()) != null ) { + int idx = line.indexOf( '=' ); + String key = line.substring( 0, idx ); + String value = line.substring( idx+1 ); + if (ignoreCase) { + key = key.toUpperCase(); + } + envVars.put(key, value); + } + return envVars; + } + + + + + + + + /** + * Encapsulates the CGI environment and rules to derive + * that environment from the servlet container and request information. + * + *

    + *

    + * + * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ + * @since Tomcat 4.0 + * + */ + protected class CGIEnvironment { + + + /** context of the enclosing servlet */ + private ServletContext context = null; + + /** context path of enclosing servlet */ + private String contextPath = null; + + /** servlet URI of the enclosing servlet */ + private String servletPath = null; + + /** pathInfo for the current request */ + private String pathInfo = null; + + /** real file system directory of the enclosing servlet's web app */ + private String webAppRootDir = null; + + /** tempdir for context - used to expand scripts in unexpanded wars */ + private File tmpDir = null; + + /** derived cgi environment */ + private Hashtable env = null; + + /** cgi command to be invoked */ + private String command = null; + + /** cgi command's desired working directory */ + private File workingDirectory = null; + + /** cgi command's command line parameters */ + private ArrayList cmdLineParameters = new ArrayList(); + + /** whether or not this object is valid or not */ + private boolean valid = false; + + + /** + * Creates a CGIEnvironment and derives the necessary environment, + * query parameters, working directory, cgi command, etc. + * + * @param req HttpServletRequest for information provided by + * the Servlet API + * @param context ServletContext for information provided by the + * Servlet API + * + */ + protected CGIEnvironment(HttpServletRequest req, + ServletContext context) throws IOException { + setupFromContext(context); + setupFromRequest(req); + + this.valid = setCGIEnvironment(req); + + if (this.valid) { + workingDirectory = new File(command.substring(0, + command.lastIndexOf(File.separator))); + } + + } + + + + /** + * Uses the ServletContext to set some CGI variables + * + * @param context ServletContext for information provided by the + * Servlet API + */ + protected void setupFromContext(ServletContext context) { + this.context = context; + this.webAppRootDir = context.getRealPath("/"); + this.tmpDir = (File) context.getAttribute(Globals.WORK_DIR_ATTR); + } + + + + /** + * Uses the HttpServletRequest to set most CGI variables + * + * @param req HttpServletRequest for information provided by + * the Servlet API + * @throws UnsupportedEncodingException + */ + protected void setupFromRequest(HttpServletRequest req) + throws UnsupportedEncodingException { + + this.contextPath = req.getContextPath(); + this.servletPath = req.getServletPath(); + this.pathInfo = req.getPathInfo(); + // If getPathInfo() returns null, must be using extension mapping + // In this case, pathInfo should be same as servletPath + if (this.pathInfo == null) { + this.pathInfo = this.servletPath; + } + + // If request is HEAD or GET and Query String does not contain + // an unencoded "=" this is an indexed query. Parsed Query String + // forms command line parameters for cgi command. + if (!"GET".equals(req.getMethod()) && + !"HEAD".equals(req.getMethod())) + return; + + String qs = req.getQueryString(); + + if (qs == null || qs.indexOf("=")>0) + return; + + int delimIndex = 0; + int lastDelimIndex = 0; + delimIndex = qs.indexOf("+"); + + while (delimIndex >0) { + cmdLineParameters.add(URLDecoder.decode(qs.substring( + lastDelimIndex,delimIndex),parameterEncoding)); + lastDelimIndex = delimIndex + 1; + delimIndex = qs.indexOf("+",lastDelimIndex); + } + cmdLineParameters.add(URLDecoder.decode(qs.substring( + lastDelimIndex),parameterEncoding)); + } + + + /** + * Resolves core information about the cgi script. + * + *

    + * Example URI: + *

     /servlet/cgigateway/dir1/realCGIscript/pathinfo1 
    + *
      + *
    • path = $CATALINA_HOME/mywebapp/dir1/realCGIscript + *
    • scriptName = /servlet/cgigateway/dir1/realCGIscript + *
    • cgiName = /dir1/realCGIscript + *
    • name = realCGIscript + *
    + *

    + *

    + * CGI search algorithm: search the real path below + * <my-webapp-root> and find the first non-directory in + * the getPathTranslated("/"), reading/searching from left-to-right. + *

    + *

    + * The CGI search path will start at + * webAppRootDir + File.separator + cgiPathPrefix + * (or webAppRootDir alone if cgiPathPrefix is + * null). + *

    + *

    + * cgiPathPrefix is defined by setting + * this servlet's cgiPathPrefix init parameter + * + *

    + * + * @param pathInfo String from HttpServletRequest.getPathInfo() + * @param webAppRootDir String from context.getRealPath("/") + * @param contextPath String as from + * HttpServletRequest.getContextPath() + * @param servletPath String as from + * HttpServletRequest.getServletPath() + * @param cgiPathPrefix subdirectory of webAppRootDir below which + * the web app's CGIs may be stored; can be null. + * The CGI search path will start at + * webAppRootDir + File.separator + cgiPathPrefix + * (or webAppRootDir alone if cgiPathPrefix is + * null). cgiPathPrefix is defined by setting + * the servlet's cgiPathPrefix init parameter. + * + * + * @return + *
      + *
    • + * path - full file-system path to valid cgi script, + * or null if no cgi was found + *
    • + * scriptName - + * CGI variable SCRIPT_NAME; the full URL path + * to valid cgi script or null if no cgi was + * found + *
    • + * cgiName - servlet pathInfo fragment corresponding to + * the cgi script itself, or null if not found + *
    • + * name - simple name (no directories) of the + * cgi script, or null if no cgi was found + *
    + * + * @since Tomcat 4.0 + */ + protected String[] findCGI(String pathInfo, String webAppRootDir, + String contextPath, String servletPath, + String cgiPathPrefix) { + String path = null; + String name = null; + String scriptname = null; + String cginame = null; + + if ((webAppRootDir != null) + && (webAppRootDir.lastIndexOf(File.separator) == + (webAppRootDir.length() - 1))) { + //strip the trailing "/" from the webAppRootDir + webAppRootDir = + webAppRootDir.substring(0, (webAppRootDir.length() - 1)); + } + + if (cgiPathPrefix != null) { + webAppRootDir = webAppRootDir + File.separator + + cgiPathPrefix; + } + + if (debug >= 2) { + log("findCGI: path=" + pathInfo + ", " + webAppRootDir); + } + + File currentLocation = new File(webAppRootDir); + StringTokenizer dirWalker = + new StringTokenizer(pathInfo, "/"); + if (debug >= 3) { + log("findCGI: currentLoc=" + currentLocation); + } + while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { + if (debug >= 3) { + log("findCGI: currentLoc=" + currentLocation); + } + currentLocation = new File(currentLocation, + (String) dirWalker.nextElement()); + } + if (!currentLocation.isFile()) { + return new String[] { null, null, null, null }; + } else { + if (debug >= 2) { + log("findCGI: FOUND cgi at " + currentLocation); + } + path = currentLocation.getAbsolutePath(); + name = currentLocation.getName(); + cginame = + currentLocation.getParent().substring(webAppRootDir.length()) + + File.separator + + name; + + if (".".equals(contextPath)) { + scriptname = servletPath + cginame; + } else { + scriptname = contextPath + servletPath + cginame; + } + } + + if (debug >= 1) { + log("findCGI calc: name=" + name + ", path=" + path + + ", scriptname=" + scriptname + ", cginame=" + cginame); + } + return new String[] { path, scriptname, cginame, name }; + } + + /** + * Constructs the CGI environment to be supplied to the invoked CGI + * script; relies heavliy on Servlet API methods and findCGI + * + * @param req request associated with the CGI + * invokation + * + * @return true if environment was set OK, false if there + * was a problem and no environment was set + */ + protected boolean setCGIEnvironment(HttpServletRequest req) throws IOException { + + /* + * This method is slightly ugly; c'est la vie. + * "You cannot stop [ugliness], you can only hope to contain [it]" + * (apologies to Marv Albert regarding MJ) + */ + + Hashtable envp = new Hashtable(); + + // Add the shell environment variables (if any) + envp.putAll(shellEnv); + + // Add the CGI environment variables + String sPathInfoOrig = null; + String sPathTranslatedOrig = null; + String sPathInfoCGI = null; + String sPathTranslatedCGI = null; + String sCGIFullPath = null; + String sCGIScriptName = null; + String sCGIFullName = null; + String sCGIName = null; + String[] sCGINames; + + + sPathInfoOrig = this.pathInfo; + sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; + + sPathTranslatedOrig = req.getPathTranslated(); + sPathTranslatedOrig = + sPathTranslatedOrig == null ? "" : sPathTranslatedOrig; + + if (webAppRootDir == null ) { + // The app has not been deployed in exploded form + webAppRootDir = tmpDir.toString(); + expandCGIScript(); + } + + sCGINames = findCGI(sPathInfoOrig, + webAppRootDir, + contextPath, + servletPath, + cgiPathPrefix); + + sCGIFullPath = sCGINames[0]; + sCGIScriptName = sCGINames[1]; + sCGIFullName = sCGINames[2]; + sCGIName = sCGINames[3]; + + if (sCGIFullPath == null + || sCGIScriptName == null + || sCGIFullName == null + || sCGIName == null) { + return false; + } + + envp.put("SERVER_SOFTWARE", "TOMCAT"); + + envp.put("SERVER_NAME", nullsToBlanks(req.getServerName())); + + envp.put("GATEWAY_INTERFACE", "CGI/1.1"); + + envp.put("SERVER_PROTOCOL", nullsToBlanks(req.getProtocol())); + + int port = req.getServerPort(); + Integer iPort = (port == 0 ? new Integer(-1) : new Integer(port)); + envp.put("SERVER_PORT", iPort.toString()); + + envp.put("REQUEST_METHOD", nullsToBlanks(req.getMethod())); + + envp.put("REQUEST_URI", nullsToBlanks(req.getRequestURI())); + + + /*- + * PATH_INFO should be determined by using sCGIFullName: + * 1) Let sCGIFullName not end in a "/" (see method findCGI) + * 2) Let sCGIFullName equal the pathInfo fragment which + * corresponds to the actual cgi script. + * 3) Thus, PATH_INFO = request.getPathInfo().substring( + * sCGIFullName.length()) + * + * (see method findCGI, where the real work is done) + * + */ + if (pathInfo == null + || (pathInfo.substring(sCGIFullName.length()).length() <= 0)) { + sPathInfoCGI = ""; + } else { + sPathInfoCGI = pathInfo.substring(sCGIFullName.length()); + } + envp.put("PATH_INFO", sPathInfoCGI); + + + /*- + * PATH_TRANSLATED must be determined after PATH_INFO (and the + * implied real cgi-script) has been taken into account. + * + * The following example demonstrates: + * + * servlet info = /servlet/cgigw/dir1/dir2/cgi1/trans1/trans2 + * cgifullpath = /servlet/cgigw/dir1/dir2/cgi1 + * path_info = /trans1/trans2 + * webAppRootDir = servletContext.getRealPath("/") + * + * path_translated = servletContext.getRealPath("/trans1/trans2") + * + * That is, PATH_TRANSLATED = webAppRootDir + sPathInfoCGI + * (unless sPathInfoCGI is null or blank, then the CGI + * specification dictates that the PATH_TRANSLATED metavariable + * SHOULD NOT be defined. + * + */ + if (sPathInfoCGI != null && !("".equals(sPathInfoCGI))) { + sPathTranslatedCGI = context.getRealPath(sPathInfoCGI); + } else { + sPathTranslatedCGI = null; + } + if (sPathTranslatedCGI == null || "".equals(sPathTranslatedCGI)) { + //NOOP + } else { + envp.put("PATH_TRANSLATED", nullsToBlanks(sPathTranslatedCGI)); + } + + + envp.put("SCRIPT_NAME", nullsToBlanks(sCGIScriptName)); + + envp.put("QUERY_STRING", nullsToBlanks(req.getQueryString())); + + envp.put("REMOTE_HOST", nullsToBlanks(req.getRemoteHost())); + + envp.put("REMOTE_ADDR", nullsToBlanks(req.getRemoteAddr())); + + envp.put("AUTH_TYPE", nullsToBlanks(req.getAuthType())); + + envp.put("REMOTE_USER", nullsToBlanks(req.getRemoteUser())); + + envp.put("REMOTE_IDENT", ""); //not necessary for full compliance + + envp.put("CONTENT_TYPE", nullsToBlanks(req.getContentType())); + + + /* Note CGI spec says CONTENT_LENGTH must be NULL ("") or undefined + * if there is no content, so we cannot put 0 or -1 in as per the + * Servlet API spec. + */ + int contentLength = req.getContentLength(); + String sContentLength = (contentLength <= 0 ? "" : + (new Integer(contentLength)).toString()); + envp.put("CONTENT_LENGTH", sContentLength); + + + Enumeration headers = req.getHeaderNames(); + String header = null; + while (headers.hasMoreElements()) { + header = null; + header = ((String) headers.nextElement()).toUpperCase(); + //REMIND: rewrite multiple headers as if received as single + //REMIND: change character set + //REMIND: I forgot what the previous REMIND means + if ("AUTHORIZATION".equalsIgnoreCase(header) || + "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) { + //NOOP per CGI specification section 11.2 + } else { + envp.put("HTTP_" + header.replace('-', '_'), + req.getHeader(header)); + } + } + + File fCGIFullPath = new File(sCGIFullPath); + command = fCGIFullPath.getCanonicalPath(); + + envp.put("X_TOMCAT_SCRIPT_PATH", command); //for kicks + + this.env = envp; + + return true; + + } + + /** + * Extracts requested resource from web app archive to context work + * directory to enable CGI script to be executed. + */ + protected void expandCGIScript() { + StringBuffer srcPath = new StringBuffer(); + StringBuffer destPath = new StringBuffer(); + InputStream is = null; + + // paths depend on mapping + if (cgiPathPrefix == null ) { + srcPath.append(pathInfo); + is = context.getResourceAsStream(srcPath.toString()); + destPath.append(tmpDir); + destPath.append(pathInfo); + } else { + // essentially same search algorithm as findCGI() + srcPath.append(cgiPathPrefix); + StringTokenizer pathWalker = + new StringTokenizer (pathInfo, "/"); + // start with first element + while (pathWalker.hasMoreElements() && (is == null)) { + srcPath.append("/"); + srcPath.append(pathWalker.nextElement()); + is = context.getResourceAsStream(srcPath.toString()); + } + destPath.append(tmpDir); + destPath.append("/"); + destPath.append(srcPath); + } + + if (is == null) { + // didn't find anything, give up now + if (debug >= 2) { + log("expandCGIScript: source '" + srcPath + "' not found"); + } + return; + } + + File f = new File(destPath.toString()); + if (f.exists()) { + // Don't need to expand if it already exists + return; + } + + // create directories + String dirPath = new String (destPath.toString().substring( + 0,destPath.toString().lastIndexOf("/"))); + File dir = new File(dirPath); + dir.mkdirs(); + + try { + synchronized (expandFileLock) { + // make sure file doesn't exist + if (f.exists()) { + return; + } + + // create file + if (!f.createNewFile()) { + return; + } + FileOutputStream fos = new FileOutputStream(f); + + // copy data + IOTools.flow(is, fos); + is.close(); + fos.close(); + if (debug >= 2) { + log("expandCGIScript: expanded '" + srcPath + "' to '" + destPath + "'"); + } + } + } catch (IOException ioe) { + // delete in case file is corrupted + if (f.exists()) { + f.delete(); + } + } + } + + + /** + * Print important CGI environment information in a easy-to-read HTML + * table + * + * @return HTML string containing CGI environment info + * + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + + sb.append(""); + + sb.append(""); + + sb.append(""); + + sb.append(""); + + if (isValid()) { + Enumeration envk = env.keys(); + while (envk.hasMoreElements()) { + String s = (String) envk.nextElement(); + sb.append(""); + } + } + + sb.append(""); + + sb.append(""); + + sb.append(""); + + sb.append(""); + + sb.append("
    "); + sb.append("CGIEnvironment Info
    Debug Level"); + sb.append(debug); + sb.append("
    Validity:"); + sb.append(isValid()); + sb.append("
    "); + sb.append(s); + sb.append(""); + sb.append(blanksToString((String) env.get(s), + "[will be set to blank]")); + sb.append("

    Derived Command"); + sb.append(nullsToBlanks(command)); + sb.append("
    Working Directory"); + if (workingDirectory != null) { + sb.append(workingDirectory.toString()); + } + sb.append("
    Command Line Params"); + for (int i=0; i < cmdLineParameters.size(); i++) { + String param = (String) cmdLineParameters.get(i); + sb.append("

    "); + sb.append(param); + sb.append("

    "); + } + sb.append("

    end."); + + return sb.toString(); + } + + + + /** + * Gets derived command string + * + * @return command string + * + */ + protected String getCommand() { + return command; + } + + + + /** + * Gets derived CGI working directory + * + * @return working directory + * + */ + protected File getWorkingDirectory() { + return workingDirectory; + } + + + + /** + * Gets derived CGI environment + * + * @return CGI environment + * + */ + protected Hashtable getEnvironment() { + return env; + } + + + + /** + * Gets derived CGI query parameters + * + * @return CGI query parameters + * + */ + protected ArrayList getParameters() { + return cmdLineParameters; + } + + + + /** + * Gets validity status + * + * @return true if this environment is valid, false + * otherwise + * + */ + protected boolean isValid() { + return valid; + } + + + + /** + * Converts null strings to blank strings ("") + * + * @param s string to be converted if necessary + * @return a non-null string, either the original or the empty string + * ("") if the original was null + */ + protected String nullsToBlanks(String s) { + return nullsToString(s, ""); + } + + + + /** + * Converts null strings to another string + * + * @param couldBeNull string to be converted if necessary + * @param subForNulls string to return instead of a null string + * @return a non-null string, either the original or the substitute + * string if the original was null + */ + protected String nullsToString(String couldBeNull, + String subForNulls) { + return (couldBeNull == null ? subForNulls : couldBeNull); + } + + + + /** + * Converts blank strings to another string + * + * @param couldBeBlank string to be converted if necessary + * @param subForBlanks string to return instead of a blank string + * @return a non-null string, either the original or the substitute + * string if the original was null or empty ("") + */ + protected String blanksToString(String couldBeBlank, + String subForBlanks) { + return (("".equals(couldBeBlank) || couldBeBlank == null) + ? subForBlanks + : couldBeBlank); + } + + + + } //class CGIEnvironment + + + + + + + /** + * Encapsulates the knowledge of how to run a CGI script, given the + * script's desired environment and (optionally) input/output streams + * + *

    + * + * Exposes a run method used to actually invoke the + * CGI. + * + *

    + *

    + * + * The CGI environment and settings are derived from the information + * passed to the constuctor. + * + *

    + *

    + * + * The input and output streams can be set by the setInput + * and setResponse methods, respectively. + *

    + * + * @version $Revision: 421476 $, $Date: 2006-07-12 22:08:28 -0400 (Wed, 12 Jul 2006) $ + */ + + protected class CGIRunner { + + /** script/command to be executed */ + private String command = null; + + /** environment used when invoking the cgi script */ + private Hashtable env = null; + + /** working directory used when invoking the cgi script */ + private File wd = null; + + /** command line parameters to be passed to the invoked script */ + private ArrayList params = null; + + /** stdin to be passed to cgi script */ + private InputStream stdin = null; + + /** response object used to set headers & get output stream */ + private HttpServletResponse response = null; + + /** boolean tracking whether this object has enough info to run() */ + private boolean readyToRun = false; + + + + + /** + * Creates a CGIRunner and initializes its environment, working + * directory, and query parameters. + *
    + * Input/output streams (optional) are set using the + * setInput and setResponse methods, + * respectively. + * + * @param command string full path to command to be executed + * @param env Hashtable with the desired script environment + * @param wd File with the script's desired working directory + * @param params ArrayList with the script's query command line + * paramters as strings + */ + protected CGIRunner(String command, Hashtable env, File wd, + ArrayList params) { + this.command = command; + this.env = env; + this.wd = wd; + this.params = params; + updateReadyStatus(); + } + + + + /** + * Checks & sets ready status + */ + protected void updateReadyStatus() { + if (command != null + && env != null + && wd != null + && params != null + && response != null) { + readyToRun = true; + } else { + readyToRun = false; + } + } + + + + /** + * Gets ready status + * + * @return false if not ready (run will throw + * an exception), true if ready + */ + protected boolean isReady() { + return readyToRun; + } + + + + /** + * Sets HttpServletResponse object used to set headers and send + * output to + * + * @param response HttpServletResponse to be used + * + */ + protected void setResponse(HttpServletResponse response) { + this.response = response; + updateReadyStatus(); + } + + + + /** + * Sets standard input to be passed on to the invoked cgi script + * + * @param stdin InputStream to be used + * + */ + protected void setInput(InputStream stdin) { + this.stdin = stdin; + updateReadyStatus(); + } + + + + /** + * Converts a Hashtable to a String array by converting each + * key/value pair in the Hashtable to a String in the form + * "key=value" (hashkey + "=" + hash.get(hashkey).toString()) + * + * @param h Hashtable to convert + * + * @return converted string array + * + * @exception NullPointerException if a hash key has a null value + * + */ + protected String[] hashToStringArray(Hashtable h) + throws NullPointerException { + Vector v = new Vector(); + Enumeration e = h.keys(); + while (e.hasMoreElements()) { + String k = e.nextElement().toString(); + v.add(k + "=" + h.get(k)); + } + String[] strArr = new String[v.size()]; + v.copyInto(strArr); + return strArr; + } + + + + /** + * Executes a CGI script with the desired environment, current working + * directory, and input/output streams + * + *

    + * This implements the following CGI specification recommedations: + *

      + *
    • Servers SHOULD provide the "query" component of + * the script-URI as command-line arguments to scripts if it + * does not contain any unencoded "=" characters and the + * command-line arguments can be generated in an unambiguous + * manner. + *
    • Servers SHOULD set the AUTH_TYPE metavariable to the value + * of the "auth-scheme" token of the + * "Authorization" if it was supplied as part of the + * request header. See getCGIEnvironment method. + *
    • Where applicable, servers SHOULD set the current working + * directory to the directory in which the script is located + * before invoking it. + *
    • Server implementations SHOULD define their behavior for the + * following cases: + *
        + *
      • Allowed characters in pathInfo: This implementation + * does not allow ASCII NUL nor any character which cannot + * be URL-encoded according to internet standards; + *
      • Allowed characters in path segments: This + * implementation does not allow non-terminal NULL + * segments in the the path -- IOExceptions may be thrown; + *
      • "." and ".." path + * segments: + * This implementation does not allow "." and + * ".." in the the path, and such characters + * will result in an IOException being thrown; + *
      • Implementation limitations: This implementation + * does not impose any limitations except as documented + * above. This implementation may be limited by the + * servlet container used to house this implementation. + * In particular, all the primary CGI variable values + * are derived either directly or indirectly from the + * container's implementation of the Servlet API methods. + *
      + *
    + *

    + * + * @exception IOException if problems during reading/writing occur + * + * @see java.lang.Runtime#exec(String command, String[] envp, + * File dir) + */ + protected void run() throws IOException { + + /* + * REMIND: this method feels too big; should it be re-written? + */ + + if (!isReady()) { + throw new IOException(this.getClass().getName() + + ": not ready to run."); + } + + if (debug >= 1 ) { + log("runCGI(envp=[" + env + "], command=" + command + ")"); + } + + if ((command.indexOf(File.separator + "." + File.separator) >= 0) + || (command.indexOf(File.separator + "..") >= 0) + || (command.indexOf(".." + File.separator) >= 0)) { + throw new IOException(this.getClass().getName() + + "Illegal Character in CGI command " + + "path ('.' or '..') detected. Not " + + "running CGI [" + command + "]."); + } + + /* original content/structure of this section taken from + * http://developer.java.sun.com/developer/ + * bugParade/bugs/4216884.html + * with major modifications by Martin Dengler + */ + Runtime rt = null; + InputStream cgiOutput = null; + BufferedReader commandsStdErr = null; + BufferedOutputStream commandsStdIn = null; + Process proc = null; + int bufRead = -1; + + //create query arguments + StringBuffer cmdAndArgs = new StringBuffer(); + if (command.indexOf(" ") < 0) { + cmdAndArgs.append(command); + } else { + // Spaces used as delimiter, so need to use quotes + cmdAndArgs.append("\""); + cmdAndArgs.append(command); + cmdAndArgs.append("\""); + } + + for (int i=0; i < params.size(); i++) { + cmdAndArgs.append(" "); + String param = (String) params.get(i); + if (param.indexOf(" ") < 0) { + cmdAndArgs.append(param); + } else { + // Spaces used as delimiter, so need to use quotes + cmdAndArgs.append("\""); + cmdAndArgs.append(param); + cmdAndArgs.append("\""); + } + } + + StringBuffer command = new StringBuffer(cgiExecutable); + command.append(" "); + command.append(cmdAndArgs.toString()); + cmdAndArgs = command; + + rt = Runtime.getRuntime(); + proc = rt.exec(cmdAndArgs.toString(), hashToStringArray(env), wd); + + String sContentLength = (String) env.get("CONTENT_LENGTH"); + + if(!"".equals(sContentLength)) { + commandsStdIn = new BufferedOutputStream(proc.getOutputStream()); + IOTools.flow(stdin, commandsStdIn); + commandsStdIn.flush(); + commandsStdIn.close(); + } + + /* we want to wait for the process to exit, Process.waitFor() + * is useless in our situation; see + * http://developer.java.sun.com/developer/ + * bugParade/bugs/4223650.html + */ + + boolean isRunning = true; + commandsStdErr = new BufferedReader + (new InputStreamReader(proc.getErrorStream())); + final BufferedReader stdErrRdr = commandsStdErr ; + + new Thread() { + public void run () { + sendToLog(stdErrRdr) ; + } ; + }.start() ; + + InputStream cgiHeaderStream = + new HTTPHeaderInputStream(proc.getInputStream()); + BufferedReader cgiHeaderReader = + new BufferedReader(new InputStreamReader(cgiHeaderStream)); + + while (isRunning) { + try { + //set headers + String line = null; + while (((line = cgiHeaderReader.readLine()) != null) + && !("".equals(line))) { + if (debug >= 2) { + log("runCGI: addHeader(\"" + line + "\")"); + } + if (line.startsWith("HTTP")) { + response.setStatus(getSCFromHttpStatusLine(line)); + } else if (line.indexOf(":") >= 0) { + String header = + line.substring(0, line.indexOf(":")).trim(); + String value = + line.substring(line.indexOf(":") + 1).trim(); + if (header.equalsIgnoreCase("status")) { + response.setStatus(getSCFromCGIStatusHeader(value)); + } else { + response.addHeader(header , value); + } + } else { + log("runCGI: bad header line \"" + line + "\""); + } + } + + //write output + byte[] bBuf = new byte[2048]; + + OutputStream out = response.getOutputStream(); + cgiOutput = proc.getInputStream(); + + try { + while ((bufRead = cgiOutput.read(bBuf)) != -1) { + if (debug >= 4) { + log("runCGI: output " + bufRead + + " bytes of data"); + } + out.write(bBuf, 0, bufRead); + } + } finally { + // Attempt to consume any leftover byte if something bad happens, + // such as a socket disconnect on the servlet side; otherwise, the + // external process could hang + if (bufRead != -1) { + while ((bufRead = cgiOutput.read(bBuf)) != -1) {} + } + } + + proc.exitValue(); // Throws exception if alive + + isRunning = false; + + } catch (IllegalThreadStateException e) { + try { + Thread.sleep(500); + } catch (InterruptedException ignored) { + } + } + } //replacement for Process.waitFor() + + // Close the output stream used + cgiOutput.close(); + } + + /** + * Parses the Status-Line and extracts the status code. + * + * @param line The HTTP Status-Line (RFC2616, section 6.1) + * @return The extracted status code or the code representing an + * internal error if a valid status code cannot be extracted. + */ + private int getSCFromHttpStatusLine(String line) { + int statusStart = line.indexOf(' ') + 1; + + if (statusStart < 1 || line.length() < statusStart + 3) { + // Not a valid HTTP Status-Line + log ("runCGI: invalid HTTP Status-Line:" + line); + return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + } + + String status = line.substring(statusStart, statusStart + 3); + + int statusCode; + try { + statusCode = Integer.parseInt(status); + } catch (NumberFormatException nfe) { + // Not a valid status code + log ("runCGI: invalid status code:" + status); + return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + } + + return statusCode; + } + + /** + * Parses the CGI Status Header value and extracts the status code. + * + * @param value The CGI Status value of the form + * digit digit digit SP reason-phrase + * @return The extracted status code or the code representing an + * internal error if a valid status code cannot be extracted. + */ + private int getSCFromCGIStatusHeader(String value) { + if (value.length() < 3) { + // Not a valid status value + log ("runCGI: invalid status value:" + value); + return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + } + + String status = value.substring(0, 3); + + int statusCode; + try { + statusCode = Integer.parseInt(status); + } catch (NumberFormatException nfe) { + // Not a valid status code + log ("runCGI: invalid status code:" + status); + return HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + } + + return statusCode; + } + + private void sendToLog(BufferedReader rdr) { + String line = null; + int lineCount = 0 ; + try { + while ((line = rdr.readLine()) != null) { + log("runCGI (stderr):" + line) ; + lineCount++ ; + } + } catch (IOException e) { + log("sendToLog error", e) ; + } finally { + try { + rdr.close() ; + } catch (IOException ce) { + log("sendToLog error", ce) ; + } ; + } ; + if ( lineCount > 0 && debug > 2) { + log("runCGI: " + lineCount + " lines received on stderr") ; + } ; + } + } //class CGIRunner + + /** + * This is an input stream specifically for reading HTTP headers. It reads + * upto and including the two blank lines terminating the headers. It + * allows the content to be read using bytes or characters as appropriate. + */ + protected class HTTPHeaderInputStream extends InputStream { + private static final int STATE_CHARACTER = 0; + private static final int STATE_FIRST_CR = 1; + private static final int STATE_FIRST_LF = 2; + private static final int STATE_SECOND_CR = 3; + private static final int STATE_HEADER_END = 4; + + private InputStream input; + private int state; + + HTTPHeaderInputStream(InputStream theInput) { + input = theInput; + state = STATE_CHARACTER; + } + + /** + * @see java.io.InputStream#read() + */ + public int read() throws IOException { + if (state == STATE_HEADER_END) { + return -1; + } + + int i = input.read(); + + // Update the state + // State machine looks like this + // + // -------->-------- + // | (CR) | + // | | + // CR1--->--- | + // | | | + // ^(CR) |(LF) | + // | | | + // CHAR--->--LF1--->--EOH + // (LF) | (LF) | + // |(CR) ^(LF) + // | | + // (CR2)-->--- + + if (i == 10) { + // LF + switch(state) { + case STATE_CHARACTER: + state = STATE_FIRST_LF; + break; + case STATE_FIRST_CR: + state = STATE_FIRST_LF; + break; + case STATE_FIRST_LF: + case STATE_SECOND_CR: + state = STATE_HEADER_END; + break; + } + + } else if (i == 13) { + // CR + switch(state) { + case STATE_CHARACTER: + state = STATE_FIRST_CR; + break; + case STATE_FIRST_CR: + state = STATE_HEADER_END; + break; + case STATE_FIRST_LF: + state = STATE_SECOND_CR; + break; + } + + } else { + state = STATE_CHARACTER; + } + + return i; + } + } // class HTTPHeaderInputStream + +} //class CGIServlet diff --git a/java/org/apache/catalina/servlets/Constants.java b/java/org/apache/catalina/servlets/Constants.java index c465ae172..7909f9fcc 100644 --- a/java/org/apache/catalina/servlets/Constants.java +++ b/java/org/apache/catalina/servlets/Constants.java @@ -1,26 +1,26 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - - -public class Constants { - - public static final String Package = "org.apache.catalina.servlets"; - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + + +public class Constants { + + public static final String Package = "org.apache.catalina.servlets"; + +} + diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java index 8e0b971d2..dbe047233 100644 --- a/java/org/apache/catalina/servlets/DefaultServlet.java +++ b/java/org/apache/catalina/servlets/DefaultServlet.java @@ -1,2205 +1,2205 @@ -/* - * Copyright 1999,2004-2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - - -import java.io.BufferedInputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.RandomAccessFile; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.StringTokenizer; - -import javax.naming.InitialContext; -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.transform.Source; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.stream.StreamResult; -import javax.xml.transform.stream.StreamSource; - -import org.apache.catalina.Globals; -import org.apache.catalina.util.ServerInfo; -import org.apache.catalina.util.StringManager; -import org.apache.catalina.util.URLEncoder; -import org.apache.naming.resources.CacheEntry; -import org.apache.naming.resources.ProxyDirContext; -import org.apache.naming.resources.Resource; -import org.apache.naming.resources.ResourceAttributes; - - -/** - * The default resource-serving servlet for most web applications, - * used to serve static resources such as HTML pages and images. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 332127 $ $Date: 2005-11-09 20:50:47 +0100 (mer., 09 nov. 2005) $ - */ - -public class DefaultServlet - extends HttpServlet { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The debugging detail level for this servlet. - */ - protected int debug = 0; - - - /** - * The input buffer size to use when serving resources. - */ - protected int input = 2048; - - - /** - * Should we generate directory listings? - */ - protected boolean listings = false; - - - /** - * Read only flag. By default, it's set to true. - */ - protected boolean readOnly = true; - - - /** - * The output buffer size to use when serving resources. - */ - protected int output = 2048; - - - /** - * Array containing the safe characters set. - */ - protected static URLEncoder urlEncoder; - - - /** - * Allow customized directory listing per directory. - */ - protected String localXsltFile = null; - - - /** - * Allow customized directory listing per instance. - */ - protected String globalXsltFile = null; - - - /** - * Allow a readme file to be included. - */ - protected String readmeFile = null; - - - /** - * Proxy directory context. - */ - protected ProxyDirContext resources = null; - - - /** - * File encoding to be used when reading static files. If none is specified - * the platform default is used. - */ - protected String fileEncoding = null; - - - /** - * Minimum size for sendfile usage in bytes. - */ - protected int sendfileSize = 48 * 1024; - - - /** - * Full range marker. - */ - protected static ArrayList FULL = new ArrayList(); - - - // ----------------------------------------------------- Static Initializer - - - /** - * GMT timezone - all HTTP dates are on GMT - */ - static { - urlEncoder = new URLEncoder(); - urlEncoder.addSafeCharacter('-'); - urlEncoder.addSafeCharacter('_'); - urlEncoder.addSafeCharacter('.'); - urlEncoder.addSafeCharacter('*'); - urlEncoder.addSafeCharacter('/'); - } - - - /** - * MIME multipart separation string - */ - protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY"; - - - /** - * JNDI resources name. - */ - protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources"; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Size of file transfer buffer in bytes. - */ - protected static final int BUFFER_SIZE = 4096; - - - // --------------------------------------------------------- Public Methods - - - /** - * Finalize this servlet. - */ - public void destroy() { - } - - - /** - * Initialize this servlet. - */ - public void init() throws ServletException { - - // Set our properties from the initialization parameters - String value = null; - try { - value = getServletConfig().getInitParameter("debug"); - debug = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("input"); - input = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("listings"); - listings = (new Boolean(value)).booleanValue(); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("readonly"); - if (value != null) - readOnly = (new Boolean(value)).booleanValue(); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("output"); - output = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("sendfileSize"); - sendfileSize = Integer.parseInt(value) * 1024; - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("fileEncoding"); - fileEncoding = value; - } catch (Throwable t) { - ; - } - - globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); - localXsltFile = getServletConfig().getInitParameter("localXsltFile"); - readmeFile = getServletConfig().getInitParameter("readmeFile"); - - // Sanity check on the specified buffer sizes - if (input < 256) - input = 256; - if (output < 256) - output = 256; - - if (debug > 0) { - log("DefaultServlet.init: input buffer size=" + input + - ", output buffer size=" + output); - } - - // Load the proxy dir context. - try { - resources = (ProxyDirContext) getServletContext() - .getAttribute(Globals.RESOURCES_ATTR); - } catch(ClassCastException e) { - // Failed : Not the right type - } - if (resources == null) { - try { - resources = - (ProxyDirContext) new InitialContext() - .lookup(RESOURCES_JNDI_NAME); - } catch (NamingException e) { - // Failed - } catch (ClassCastException e) { - // Failed : Not the right type - } - } - - if (resources == null) { - throw new UnavailableException("No resources"); - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return the relative path associated with this servlet. - * - * @param request The servlet request we are processing - */ - protected String getRelativePath(HttpServletRequest request) { - - // Are we being processed by a RequestDispatcher.include()? - if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) { - String result = (String) request.getAttribute( - Globals.INCLUDE_PATH_INFO_ATTR); - if (result == null) - result = (String) request.getAttribute( - Globals.INCLUDE_SERVLET_PATH_ATTR); - if ((result == null) || (result.equals(""))) - result = "/"; - return (result); - } - - // No, extract the desired path directly from the request - String result = request.getPathInfo(); - if (result == null) { - result = request.getServletPath(); - } - if ((result == null) || (result.equals(""))) { - result = "/"; - } - return (result); - - } - - - /** - * Process a GET request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doGet(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - // Serve the requested resource, including the data content - serveResource(request, response, true); - - } - - - /** - * Process a HEAD request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doHead(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - // Serve the requested resource, without the data content - serveResource(request, response, false); - - } - - - /** - * Process a POST request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doPost(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - doGet(request, response); - } - - - /** - * Process a POST request for the specified resource. - * - * @param req The servlet request we are processing - * @param resp The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doPut(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - String path = getRelativePath(req); - - boolean exists = true; - try { - resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - boolean result = true; - - // Temp. content file used to support partial PUT - File contentFile = null; - - Range range = parseContentRange(req, resp); - - InputStream resourceInputStream = null; - - // Append data specified in ranges to existing content for this - // resource - create a temp. file on the local filesystem to - // perform this operation - // Assume just one range is specified for now - if (range != null) { - contentFile = executePartialPut(req, range, path); - resourceInputStream = new FileInputStream(contentFile); - } else { - resourceInputStream = req.getInputStream(); - } - - try { - Resource newResource = new Resource(resourceInputStream); - // FIXME: Add attributes - if (exists) { - resources.rebind(path, newResource); - } else { - resources.bind(path, newResource); - } - } catch(NamingException e) { - result = false; - } - - if (result) { - if (exists) { - resp.setStatus(HttpServletResponse.SC_NO_CONTENT); - } else { - resp.setStatus(HttpServletResponse.SC_CREATED); - } - } else { - resp.sendError(HttpServletResponse.SC_CONFLICT); - } - - } - - - /** - * Handle a partial PUT. New content specified in request is appended to - * existing content in oldRevisionContent (if present). This code does - * not support simultaneous partial updates to the same resource. - */ - protected File executePartialPut(HttpServletRequest req, Range range, - String path) - throws IOException { - - // Append data specified in ranges to existing content for this - // resource - create a temp. file on the local filesystem to - // perform this operation - File tempDir = (File) getServletContext().getAttribute - ("javax.servlet.context.tempdir"); - // Convert all '/' characters to '.' in resourcePath - String convertedResourcePath = path.replace('/', '.'); - File contentFile = new File(tempDir, convertedResourcePath); - if (contentFile.createNewFile()) { - // Clean up contentFile when Tomcat is terminated - contentFile.deleteOnExit(); - } - - RandomAccessFile randAccessContentFile = - new RandomAccessFile(contentFile, "rw"); - - Resource oldResource = null; - try { - Object obj = resources.lookup(path); - if (obj instanceof Resource) - oldResource = (Resource) obj; - } catch (NamingException e) { - } - - // Copy data in oldRevisionContent to contentFile - if (oldResource != null) { - BufferedInputStream bufOldRevStream = - new BufferedInputStream(oldResource.streamContent(), - BUFFER_SIZE); - - int numBytesRead; - byte[] copyBuffer = new byte[BUFFER_SIZE]; - while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) { - randAccessContentFile.write(copyBuffer, 0, numBytesRead); - } - - bufOldRevStream.close(); - } - - randAccessContentFile.setLength(range.length); - - // Append data in request input stream to contentFile - randAccessContentFile.seek(range.start); - int numBytesRead; - byte[] transferBuffer = new byte[BUFFER_SIZE]; - BufferedInputStream requestBufInStream = - new BufferedInputStream(req.getInputStream(), BUFFER_SIZE); - while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) { - randAccessContentFile.write(transferBuffer, 0, numBytesRead); - } - randAccessContentFile.close(); - requestBufInStream.close(); - - return contentFile; - - } - - - /** - * Process a POST request for the specified resource. - * - * @param req The servlet request we are processing - * @param resp The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - - String path = getRelativePath(req); - - boolean exists = true; - try { - resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - if (exists) { - boolean result = true; - try { - resources.unbind(path); - } catch (NamingException e) { - result = false; - } - if (result) { - resp.setStatus(HttpServletResponse.SC_NO_CONTENT); - } else { - resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); - } - } else { - resp.sendError(HttpServletResponse.SC_NOT_FOUND); - } - - } - - - /** - * Check if the conditions specified in the optional If headers are - * satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceAttributes The resource information - * @return boolean true if the resource meets all the specified conditions, - * and false if any of the conditions is not satisfied, in which case - * request processing is stopped - */ - protected boolean checkIfHeaders(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - - return checkIfMatch(request, response, resourceAttributes) - && checkIfModifiedSince(request, response, resourceAttributes) - && checkIfNoneMatch(request, response, resourceAttributes) - && checkIfUnmodifiedSince(request, response, resourceAttributes); - - } - - - /** - * Get the ETag associated with a file. - * - * @param resourceAttributes The resource information - */ - protected String getETag(ResourceAttributes resourceAttributes) { - String result = null; - if ((result = resourceAttributes.getETag(true)) != null) { - return result; - } else if ((result = resourceAttributes.getETag()) != null) { - return result; - } else { - return "W/\"" + resourceAttributes.getContentLength() + "-" - + resourceAttributes.getLastModified() + "\""; - } - } - - - /** - * URL rewriter. - * - * @param path Path which has to be rewiten - */ - protected String rewriteUrl(String path) { - return urlEncoder.encode( path ); - } - - - /** - * Display the size of a file. - */ - protected void displaySize(StringBuffer buf, int filesize) { - - int leftside = filesize / 1024; - int rightside = (filesize % 1024) / 103; // makes 1 digit - // To avoid 0.0 for non-zero file, we bump to 0.1 - if (leftside == 0 && rightside == 0 && filesize != 0) - rightside = 1; - buf.append(leftside).append(".").append(rightside); - buf.append(" KB"); - - } - - - /** - * Serve the specified resource, optionally including the data content. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param content Should the content be included? - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void serveResource(HttpServletRequest request, - HttpServletResponse response, - boolean content) - throws IOException, ServletException { - - // Identify the requested resource path - String path = getRelativePath(request); - if (debug > 0) { - if (content) - log("DefaultServlet.serveResource: Serving resource '" + - path + "' headers and data"); - else - log("DefaultServlet.serveResource: Serving resource '" + - path + "' headers only"); - } - - CacheEntry cacheEntry = resources.lookupCache(path); - - if (!cacheEntry.exists) { - // Check if we're included so we can return the appropriate - // missing resource name in the error - String requestUri = (String) request.getAttribute( - Globals.INCLUDE_REQUEST_URI_ATTR); - if (requestUri == null) { - requestUri = request.getRequestURI(); - } else { - // We're included, and the response.sendError() below is going - // to be ignored by the resource that is including us. - // Therefore, the only way we can let the including resource - // know is by including warning message in response - response.getWriter().write( - sm.getString("defaultServlet.missingResource", - requestUri)); - } - - response.sendError(HttpServletResponse.SC_NOT_FOUND, - requestUri); - return; - } - - // If the resource is not a collection, and the resource path - // ends with "/" or "\", return NOT FOUND - if (cacheEntry.context == null) { - if (path.endsWith("/") || (path.endsWith("\\"))) { - // Check if we're included so we can return the appropriate - // missing resource name in the error - String requestUri = (String) request.getAttribute( - Globals.INCLUDE_REQUEST_URI_ATTR); - if (requestUri == null) { - requestUri = request.getRequestURI(); - } - response.sendError(HttpServletResponse.SC_NOT_FOUND, - requestUri); - return; - } - } - - // Check if the conditions specified in the optional If headers are - // satisfied. - if (cacheEntry.context == null) { - - // Checking If headers - boolean included = - (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null); - if (!included - && !checkIfHeaders(request, response, cacheEntry.attributes)) { - return; - } - - } - - // Find content type. - String contentType = cacheEntry.attributes.getMimeType(); - if (contentType == null) { - contentType = getServletContext().getMimeType(cacheEntry.name); - cacheEntry.attributes.setMimeType(contentType); - } - - ArrayList ranges = null; - long contentLength = -1L; - - if (cacheEntry.context != null) { - - // Skip directory listings if we have been configured to - // suppress them - if (!listings) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - request.getRequestURI()); - return; - } - contentType = "text/html;charset=UTF-8"; - - } else { - - // Parse range specifier - - ranges = parseRange(request, response, cacheEntry.attributes); - - // ETag header - response.setHeader("ETag", getETag(cacheEntry.attributes)); - - // Last-Modified header - response.setHeader("Last-Modified", - cacheEntry.attributes.getLastModifiedHttp()); - - // Get content length - contentLength = cacheEntry.attributes.getContentLength(); - // Special case for zero length files, which would cause a - // (silent) ISE when setting the output buffer size - if (contentLength == 0L) { - content = false; - } - - } - - ServletOutputStream ostream = null; - PrintWriter writer = null; - - if (content) { - - // Trying to retrieve the servlet output stream - - try { - ostream = response.getOutputStream(); - } catch (IllegalStateException e) { - // If it fails, we try to get a Writer instead if we're - // trying to serve a text file - if ( (contentType == null) - || (contentType.startsWith("text")) ) { - writer = response.getWriter(); - } else { - throw e; - } - } - - } - - if ( (cacheEntry.context != null) - || ( ((ranges == null) || (ranges.isEmpty())) - && (request.getHeader("Range") == null) ) - || (ranges == FULL) ) { - - // Set the appropriate output headers - if (contentType != null) { - if (debug > 0) - log("DefaultServlet.serveFile: contentType='" + - contentType + "'"); - response.setContentType(contentType); - } - if ((cacheEntry.resource != null) && (contentLength >= 0)) { - if (debug > 0) - log("DefaultServlet.serveFile: contentLength=" + - contentLength); - if (contentLength < Integer.MAX_VALUE) { - response.setContentLength((int) contentLength); - } else { - // Set the content-length as String to be able to use a long - response.setHeader("content-length", "" + contentLength); - } - } - - InputStream renderResult = null; - if (cacheEntry.context != null) { - - if (content) { - // Serve the directory browser - renderResult = - render(request.getContextPath(), cacheEntry); - } - - } - - // Copy the input stream to our output stream (if requested) - if (content) { - try { - response.setBufferSize(output); - } catch (IllegalStateException e) { - // Silent catch - } - if (ostream != null) { - if (!checkSendfile(request, response, cacheEntry, contentLength, null)) - copy(cacheEntry, renderResult, ostream); - } else { - copy(cacheEntry, renderResult, writer); - } - } - - } else { - - if ((ranges == null) || (ranges.isEmpty())) - return; - - // Partial content response. - - response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); - - if (ranges.size() == 1) { - - Range range = (Range) ranges.get(0); - response.addHeader("Content-Range", "bytes " - + range.start - + "-" + range.end + "/" - + range.length); - long length = range.end - range.start + 1; - if (length < Integer.MAX_VALUE) { - response.setContentLength((int) length); - } else { - // Set the content-length as String to be able to use a long - response.setHeader("content-length", "" + length); - } - - if (contentType != null) { - if (debug > 0) - log("DefaultServlet.serveFile: contentType='" + - contentType + "'"); - response.setContentType(contentType); - } - - if (content) { - try { - response.setBufferSize(output); - } catch (IllegalStateException e) { - // Silent catch - } - if (ostream != null) { - if (!checkSendfile(request, response, cacheEntry, range.end - range.start + 1, range)) - copy(cacheEntry, ostream, range); - } else { - copy(cacheEntry, writer, range); - } - } - - } else { - - response.setContentType("multipart/byteranges; boundary=" - + mimeSeparation); - - if (content) { - try { - response.setBufferSize(output); - } catch (IllegalStateException e) { - // Silent catch - } - if (ostream != null) { - copy(cacheEntry, ostream, ranges.iterator(), - contentType); - } else { - copy(cacheEntry, writer, ranges.iterator(), - contentType); - } - } - - } - - } - - } - - - /** - * Parse the content-range header. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @return Range - */ - protected Range parseContentRange(HttpServletRequest request, - HttpServletResponse response) - throws IOException { - - // Retrieving the content-range header (if any is specified - String rangeHeader = request.getHeader("Content-Range"); - - if (rangeHeader == null) - return null; - - // bytes is the only range unit supported - if (!rangeHeader.startsWith("bytes")) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - - rangeHeader = rangeHeader.substring(6).trim(); - - int dashPos = rangeHeader.indexOf('-'); - int slashPos = rangeHeader.indexOf('/'); - - if (dashPos == -1) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - - if (slashPos == -1) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - - Range range = new Range(); - - try { - range.start = Long.parseLong(rangeHeader.substring(0, dashPos)); - range.end = - Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos)); - range.length = Long.parseLong - (rangeHeader.substring(slashPos + 1, rangeHeader.length())); - } catch (NumberFormatException e) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - - if (!range.validate()) { - response.sendError(HttpServletResponse.SC_BAD_REQUEST); - return null; - } - - return range; - - } - - - /** - * Parse the range header. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @return Vector of ranges - */ - protected ArrayList parseRange(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - - // Checking If-Range - String headerValue = request.getHeader("If-Range"); - - if (headerValue != null) { - - long headerValueTime = (-1L); - try { - headerValueTime = request.getDateHeader("If-Range"); - } catch (Exception e) { - ; - } - - String eTag = getETag(resourceAttributes); - long lastModified = resourceAttributes.getLastModified(); - - if (headerValueTime == (-1L)) { - - // If the ETag the client gave does not match the entity - // etag, then the entire entity is returned. - if (!eTag.equals(headerValue.trim())) - return FULL; - - } else { - - // If the timestamp of the entity the client got is older than - // the last modification date of the entity, the entire entity - // is returned. - if (lastModified > (headerValueTime + 1000)) - return FULL; - - } - - } - - long fileLength = resourceAttributes.getContentLength(); - - if (fileLength == 0) - return null; - - // Retrieving the range header (if any is specified - String rangeHeader = request.getHeader("Range"); - - if (rangeHeader == null) - return null; - // bytes is the only range unit supported (and I don't see the point - // of adding new ones). - if (!rangeHeader.startsWith("bytes")) { - response.addHeader("Content-Range", "bytes */" + fileLength); - response.sendError - (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - return null; - } - - rangeHeader = rangeHeader.substring(6); - - // Vector which will contain all the ranges which are successfully - // parsed. - ArrayList result = new ArrayList(); - StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ","); - - // Parsing the range list - while (commaTokenizer.hasMoreTokens()) { - String rangeDefinition = commaTokenizer.nextToken().trim(); - - Range currentRange = new Range(); - currentRange.length = fileLength; - - int dashPos = rangeDefinition.indexOf('-'); - - if (dashPos == -1) { - response.addHeader("Content-Range", "bytes */" + fileLength); - response.sendError - (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - return null; - } - - if (dashPos == 0) { - - try { - long offset = Long.parseLong(rangeDefinition); - currentRange.start = fileLength + offset; - currentRange.end = fileLength - 1; - } catch (NumberFormatException e) { - response.addHeader("Content-Range", - "bytes */" + fileLength); - response.sendError - (HttpServletResponse - .SC_REQUESTED_RANGE_NOT_SATISFIABLE); - return null; - } - - } else { - - try { - currentRange.start = Long.parseLong - (rangeDefinition.substring(0, dashPos)); - if (dashPos < rangeDefinition.length() - 1) - currentRange.end = Long.parseLong - (rangeDefinition.substring - (dashPos + 1, rangeDefinition.length())); - else - currentRange.end = fileLength - 1; - } catch (NumberFormatException e) { - response.addHeader("Content-Range", - "bytes */" + fileLength); - response.sendError - (HttpServletResponse - .SC_REQUESTED_RANGE_NOT_SATISFIABLE); - return null; - } - - } - - if (!currentRange.validate()) { - response.addHeader("Content-Range", "bytes */" + fileLength); - response.sendError - (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); - return null; - } - - result.add(currentRange); - } - - return result; - } - - - - /** - * Decide which way to render. HTML or XML. - */ - protected InputStream render - (String contextPath, CacheEntry cacheEntry) { - InputStream xsltInputStream = - findXsltInputStream(cacheEntry.context); - - if (xsltInputStream==null) { - return renderHtml(contextPath, cacheEntry); - } else { - return renderXml(contextPath, cacheEntry, xsltInputStream); - } - - } - - /** - * Return an InputStream to an HTML representation of the contents - * of this directory. - * - * @param contextPath Context path to which our internal paths are - * relative - */ - protected InputStream renderXml(String contextPath, - CacheEntry cacheEntry, - InputStream xsltInputStream) { - - StringBuffer sb = new StringBuffer(); - - sb.append(""); - sb.append(""); - - sb.append(""); - - try { - - // Render the directory entries within this directory - NamingEnumeration enumeration = resources.list(cacheEntry.name); - - // rewriteUrl(contextPath) is expensive. cache result for later reuse - String rewrittenContextPath = rewriteUrl(contextPath); - - while (enumeration.hasMoreElements()) { - - NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); - String resourceName = ncPair.getName(); - String trimmed = resourceName/*.substring(trim)*/; - if (trimmed.equalsIgnoreCase("WEB-INF") || - trimmed.equalsIgnoreCase("META-INF") || - trimmed.equalsIgnoreCase(localXsltFile)) - continue; - - CacheEntry childCacheEntry = - resources.lookupCache(cacheEntry.name + resourceName); - if (!childCacheEntry.exists) { - continue; - } - - sb.append(""); - sb.append(trimmed); - if (childCacheEntry.context != null) - sb.append("/"); - sb.append(""); - - } - - } catch (NamingException e) { - // Something went wrong - e.printStackTrace(); - } - - sb.append(""); - - String readme = getReadme(cacheEntry.context); - - if (readme!=null) { - sb.append(""); - } - - - sb.append(""); - - - try { - TransformerFactory tFactory = TransformerFactory.newInstance(); - Source xmlSource = new StreamSource(new StringReader(sb.toString())); - Source xslSource = new StreamSource(xsltInputStream); - Transformer transformer = tFactory.newTransformer(xslSource); - - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); - StreamResult out = new StreamResult(osWriter); - transformer.transform(xmlSource, out); - osWriter.flush(); - return (new ByteArrayInputStream(stream.toByteArray())); - } catch (Exception e) { - log("directory transform failure: " + e.getMessage()); - return renderHtml(contextPath, cacheEntry); - } - } - - /** - * Return an InputStream to an HTML representation of the contents - * of this directory. - * - * @param contextPath Context path to which our internal paths are - * relative - */ - protected InputStream renderHtml - (String contextPath, CacheEntry cacheEntry) { - - String name = cacheEntry.name; - - // Number of characters to trim from the beginnings of filenames - int trim = name.length(); - if (!name.endsWith("/")) - trim += 1; - if (name.equals("/")) - trim = 1; - - // Prepare a writer to a buffered area - ByteArrayOutputStream stream = new ByteArrayOutputStream(); - OutputStreamWriter osWriter = null; - try { - osWriter = new OutputStreamWriter(stream, "UTF8"); - } catch (Exception e) { - // Should never happen - osWriter = new OutputStreamWriter(stream); - } - PrintWriter writer = new PrintWriter(osWriter); - - StringBuffer sb = new StringBuffer(); - - // rewriteUrl(contextPath) is expensive. cache result for later reuse - String rewrittenContextPath = rewriteUrl(contextPath); - - // Render the page header - sb.append("\r\n"); - sb.append("\r\n"); - sb.append(""); - sb.append(sm.getString("directory.title", name)); - sb.append("\r\n"); - sb.append(" "); - sb.append("\r\n"); - sb.append(""); - sb.append("

    "); - sb.append(sm.getString("directory.title", name)); - - // Render the link to our parent (if required) - String parentDirectory = name; - if (parentDirectory.endsWith("/")) { - parentDirectory = - parentDirectory.substring(0, parentDirectory.length() - 1); - } - int slash = parentDirectory.lastIndexOf('/'); - if (slash >= 0) { - String parent = name.substring(0, slash); - sb.append(" - "); - sb.append(""); - sb.append(sm.getString("directory.parent", parent)); - sb.append(""); - sb.append(""); - } - - sb.append("

    "); - sb.append("
    "); - - sb.append("\r\n"); - - // Render the column headings - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append("\r\n"); - sb.append(""); - - try { - - // Render the directory entries within this directory - NamingEnumeration enumeration = resources.list(cacheEntry.name); - boolean shade = false; - while (enumeration.hasMoreElements()) { - - NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); - String resourceName = ncPair.getName(); - String trimmed = resourceName/*.substring(trim)*/; - if (trimmed.equalsIgnoreCase("WEB-INF") || - trimmed.equalsIgnoreCase("META-INF")) - continue; - - CacheEntry childCacheEntry = - resources.lookupCache(cacheEntry.name + resourceName); - if (!childCacheEntry.exists) { - continue; - } - - sb.append("\r\n"); - shade = !shade; - - sb.append("\r\n"); - - sb.append("\r\n"); - - sb.append("\r\n"); - - sb.append("\r\n"); - } - - } catch (NamingException e) { - // Something went wrong - e.printStackTrace(); - } - - // Render the page footer - sb.append("
    "); - sb.append(sm.getString("directory.filename")); - sb.append(""); - sb.append(sm.getString("directory.size")); - sb.append(""); - sb.append(sm.getString("directory.lastModified")); - sb.append("
      \r\n"); - sb.append(""); - sb.append(trimmed); - if (childCacheEntry.context != null) - sb.append("/"); - sb.append(""); - if (childCacheEntry.context != null) - sb.append(" "); - else - sb.append(renderSize(childCacheEntry.attributes.getContentLength())); - sb.append(""); - sb.append(childCacheEntry.attributes.getLastModifiedHttp()); - sb.append("
    \r\n"); - - sb.append("
    "); - - String readme = getReadme(cacheEntry.context); - if (readme!=null) { - sb.append(readme); - sb.append("
    "); - } - - sb.append("

    ").append(ServerInfo.getServerInfo()).append("

    "); - sb.append("\r\n"); - sb.append("\r\n"); - - // Return an input stream to the underlying bytes - writer.write(sb.toString()); - writer.flush(); - return (new ByteArrayInputStream(stream.toByteArray())); - - } - - - /** - * Render the specified file size (in bytes). - * - * @param size File size (in bytes) - */ - protected String renderSize(long size) { - - long leftSide = size / 1024; - long rightSide = (size % 1024) / 103; // Makes 1 digit - if ((leftSide == 0) && (rightSide == 0) && (size > 0)) - rightSide = 1; - - return ("" + leftSide + "." + rightSide + " kb"); - - } - - - /** - * Get the readme file as a string. - */ - protected String getReadme(DirContext directory) { - if (readmeFile!=null) { - try { - Object obj = directory.lookup(readmeFile); - - if (obj!=null && obj instanceof Resource) { - StringWriter buffer = new StringWriter(); - InputStream is = ((Resource)obj).streamContent(); - copyRange(new InputStreamReader(is), - new PrintWriter(buffer)); - - return buffer.toString(); - } - } catch(Throwable e) { - ; /* Should only be IOException or NamingException - * can be ignored - */ - } - } - - return null; - } - - - /** - * Return the xsl template inputstream (if possible) - */ - protected InputStream findXsltInputStream(DirContext directory) { - - if (localXsltFile!=null) { - try { - Object obj = directory.lookup(localXsltFile); - if (obj!=null && obj instanceof Resource) { - InputStream is = ((Resource)obj).streamContent(); - if (is!=null) - return is; - } - } catch(Throwable e) { - ; /* Should only be IOException or NamingException - * can be ignored - */ - } - } - - /* Open and read in file in one fell swoop to reduce chance - * chance of leaving handle open. - */ - if (globalXsltFile!=null) { - FileInputStream fis = null; - - try { - File f = new File(globalXsltFile); - if (f.exists()){ - fis =new FileInputStream(f); - byte b[] = new byte[(int)f.length()]; /* danger! */ - fis.read(b); - return new ByteArrayInputStream(b); - } - } catch(Throwable e) { - log("This shouldn't happen (?)...", e); - return null; - } finally { - try { - if (fis!=null) - fis.close(); - } catch(Throwable e){ - ; - } - } - } - - return null; - - } - - - // -------------------------------------------------------- protected Methods - - - /** - * Check if sendfile can be used. - */ - protected boolean checkSendfile(HttpServletRequest request, - HttpServletResponse response, - CacheEntry entry, - long length, Range range) { - if ((sendfileSize > 0) - && (entry.resource != null) - && ((length > sendfileSize) || (entry.resource.getContent() == null)) - && (entry.attributes.getCanonicalPath() != null) - && (Boolean.TRUE == request.getAttribute("org.apache.tomcat.sendfile.support")) - && (request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade")) - && (response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))) { - request.setAttribute("org.apache.tomcat.sendfile.filename", entry.attributes.getCanonicalPath()); - if (range == null) { - request.setAttribute("org.apache.tomcat.sendfile.start", new Long(0L)); - request.setAttribute("org.apache.tomcat.sendfile.end", new Long(length)); - } else { - request.setAttribute("org.apache.tomcat.sendfile.start", new Long(range.start)); - request.setAttribute("org.apache.tomcat.sendfile.end", new Long(range.end + 1)); - } - request.setAttribute("org.apache.tomcat.sendfile.token", this); - return true; - } else { - return false; - } - } - - - /** - * Check if the if-match condition is satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceInfo File object - * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request - * processing is stopped - */ - protected boolean checkIfMatch(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - - String eTag = getETag(resourceAttributes); - String headerValue = request.getHeader("If-Match"); - if (headerValue != null) { - if (headerValue.indexOf('*') == -1) { - - StringTokenizer commaTokenizer = new StringTokenizer - (headerValue, ","); - boolean conditionSatisfied = false; - - while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { - String currentToken = commaTokenizer.nextToken(); - if (currentToken.trim().equals(eTag)) - conditionSatisfied = true; - } - - // If none of the given ETags match, 412 Precodition failed is - // sent back - if (!conditionSatisfied) { - response.sendError - (HttpServletResponse.SC_PRECONDITION_FAILED); - return false; - } - - } - } - return true; - - } - - - /** - * Check if the if-modified-since condition is satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceInfo File object - * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request - * processing is stopped - */ - protected boolean checkIfModifiedSince(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - try { - long headerValue = request.getDateHeader("If-Modified-Since"); - long lastModified = resourceAttributes.getLastModified(); - if (headerValue != -1) { - - // If an If-None-Match header has been specified, if modified since - // is ignored. - if ((request.getHeader("If-None-Match") == null) - && (lastModified <= headerValue + 1000)) { - // The entity has not been modified since the date - // specified by the client. This is not an error case. - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - return false; - } - } - } catch(IllegalArgumentException illegalArgument) { - return true; - } - return true; - - } - - - /** - * Check if the if-none-match condition is satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceInfo File object - * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request - * processing is stopped - */ - protected boolean checkIfNoneMatch(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - - String eTag = getETag(resourceAttributes); - String headerValue = request.getHeader("If-None-Match"); - if (headerValue != null) { - - boolean conditionSatisfied = false; - - if (!headerValue.equals("*")) { - - StringTokenizer commaTokenizer = - new StringTokenizer(headerValue, ","); - - while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { - String currentToken = commaTokenizer.nextToken(); - if (currentToken.trim().equals(eTag)) - conditionSatisfied = true; - } - - } else { - conditionSatisfied = true; - } - - if (conditionSatisfied) { - - // For GET and HEAD, we should respond with - // 304 Not Modified. - // For every other method, 412 Precondition Failed is sent - // back. - if ( ("GET".equals(request.getMethod())) - || ("HEAD".equals(request.getMethod())) ) { - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - return false; - } else { - response.sendError - (HttpServletResponse.SC_PRECONDITION_FAILED); - return false; - } - } - } - return true; - - } - - - /** - * Check if the if-unmodified-since condition is satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceInfo File object - * @return boolean true if the resource meets the specified condition, - * and false if the condition is not satisfied, in which case request - * processing is stopped - */ - protected boolean checkIfUnmodifiedSince(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - try { - long lastModified = resourceAttributes.getLastModified(); - long headerValue = request.getDateHeader("If-Unmodified-Since"); - if (headerValue != -1) { - if ( lastModified > (headerValue + 1000)) { - // The entity has not been modified since the date - // specified by the client. This is not an error case. - response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); - return false; - } - } - } catch(IllegalArgumentException illegalArgument) { - return true; - } - return true; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The resource information - * @param ostream The output stream to write to - * - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, InputStream is, - ServletOutputStream ostream) - throws IOException { - - IOException exception = null; - InputStream resourceInputStream = null; - - // Optimization: If the binary content has already been loaded, send - // it directly - if (cacheEntry.resource != null) { - byte buffer[] = cacheEntry.resource.getContent(); - if (buffer != null) { - ostream.write(buffer, 0, buffer.length); - return; - } - resourceInputStream = cacheEntry.resource.streamContent(); - } else { - resourceInputStream = is; - } - - InputStream istream = new BufferedInputStream - (resourceInputStream, input); - - // Copy the input stream to the output stream - exception = copyRange(istream, ostream); - - // Clean up the input stream - try { - istream.close(); - } catch (Throwable t) { - ; - } - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The resource info - * @param writer The writer to write to - * - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, InputStream is, PrintWriter writer) - throws IOException { - - IOException exception = null; - - InputStream resourceInputStream = null; - if (cacheEntry.resource != null) { - resourceInputStream = cacheEntry.resource.streamContent(); - } else { - resourceInputStream = is; - } - - Reader reader; - if (fileEncoding == null) { - reader = new InputStreamReader(resourceInputStream); - } else { - reader = new InputStreamReader(resourceInputStream, - fileEncoding); - } - - // Copy the input stream to the output stream - exception = copyRange(reader, writer); - - // Clean up the reader - try { - reader.close(); - } catch (Throwable t) { - ; - } - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The ResourceInfo object - * @param ostream The output stream to write to - * @param range Range the client wanted to retrieve - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, - Range range) - throws IOException { - - IOException exception = null; - - InputStream resourceInputStream = cacheEntry.resource.streamContent(); - InputStream istream = - new BufferedInputStream(resourceInputStream, input); - exception = copyRange(istream, ostream, range.start, range.end); - - // Clean up the input stream - try { - istream.close(); - } catch (Throwable t) { - ; - } - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The ResourceInfo object - * @param writer The writer to write to - * @param range Range the client wanted to retrieve - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, PrintWriter writer, - Range range) - throws IOException { - - IOException exception = null; - - InputStream resourceInputStream = cacheEntry.resource.streamContent(); - - Reader reader; - if (fileEncoding == null) { - reader = new InputStreamReader(resourceInputStream); - } else { - reader = new InputStreamReader(resourceInputStream, - fileEncoding); - } - - exception = copyRange(reader, writer, range.start, range.end); - - // Clean up the input stream - try { - reader.close(); - } catch (Throwable t) { - ; - } - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The ResourceInfo object - * @param ostream The output stream to write to - * @param ranges Enumeration of the ranges the client wanted to retrieve - * @param contentType Content type of the resource - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, - Iterator ranges, String contentType) - throws IOException { - - IOException exception = null; - - while ( (exception == null) && (ranges.hasNext()) ) { - - InputStream resourceInputStream = cacheEntry.resource.streamContent(); - InputStream istream = - new BufferedInputStream(resourceInputStream, input); - - Range currentRange = (Range) ranges.next(); - - // Writing MIME header. - ostream.println(); - ostream.println("--" + mimeSeparation); - if (contentType != null) - ostream.println("Content-Type: " + contentType); - ostream.println("Content-Range: bytes " + currentRange.start - + "-" + currentRange.end + "/" - + currentRange.length); - ostream.println(); - - // Printing content - exception = copyRange(istream, ostream, currentRange.start, - currentRange.end); - - try { - istream.close(); - } catch (Throwable t) { - ; - } - - } - - ostream.println(); - ostream.print("--" + mimeSeparation + "--"); - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param resourceInfo The ResourceInfo object - * @param writer The writer to write to - * @param ranges Enumeration of the ranges the client wanted to retrieve - * @param contentType Content type of the resource - * @exception IOException if an input/output error occurs - */ - protected void copy(CacheEntry cacheEntry, PrintWriter writer, - Iterator ranges, String contentType) - throws IOException { - - IOException exception = null; - - while ( (exception == null) && (ranges.hasNext()) ) { - - InputStream resourceInputStream = cacheEntry.resource.streamContent(); - - Reader reader; - if (fileEncoding == null) { - reader = new InputStreamReader(resourceInputStream); - } else { - reader = new InputStreamReader(resourceInputStream, - fileEncoding); - } - - Range currentRange = (Range) ranges.next(); - - // Writing MIME header. - writer.println(); - writer.println("--" + mimeSeparation); - if (contentType != null) - writer.println("Content-Type: " + contentType); - writer.println("Content-Range: bytes " + currentRange.start - + "-" + currentRange.end + "/" - + currentRange.length); - writer.println(); - - // Printing content - exception = copyRange(reader, writer, currentRange.start, - currentRange.end); - - try { - reader.close(); - } catch (Throwable t) { - ; - } - - } - - writer.println(); - writer.print("--" + mimeSeparation + "--"); - - // Rethrow any exception that has occurred - if (exception != null) - throw exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param istream The input stream to read from - * @param ostream The output stream to write to - * @return Exception which occurred during processing - */ - protected IOException copyRange(InputStream istream, - ServletOutputStream ostream) { - - // Copy the input stream to the output stream - IOException exception = null; - byte buffer[] = new byte[input]; - int len = buffer.length; - while (true) { - try { - len = istream.read(buffer); - if (len == -1) - break; - ostream.write(buffer, 0, len); - } catch (IOException e) { - exception = e; - len = -1; - break; - } - } - return exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param reader The reader to read from - * @param writer The writer to write to - * @return Exception which occurred during processing - */ - protected IOException copyRange(Reader reader, PrintWriter writer) { - - // Copy the input stream to the output stream - IOException exception = null; - char buffer[] = new char[input]; - int len = buffer.length; - while (true) { - try { - len = reader.read(buffer); - if (len == -1) - break; - writer.write(buffer, 0, len); - } catch (IOException e) { - exception = e; - len = -1; - break; - } - } - return exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param istream The input stream to read from - * @param ostream The output stream to write to - * @param start Start of the range which will be copied - * @param end End of the range which will be copied - * @return Exception which occurred during processing - */ - protected IOException copyRange(InputStream istream, - ServletOutputStream ostream, - long start, long end) { - - if (debug > 10) - log("Serving bytes:" + start + "-" + end); - - try { - istream.skip(start); - } catch (IOException e) { - return e; - } - - IOException exception = null; - long bytesToRead = end - start + 1; - - byte buffer[] = new byte[input]; - int len = buffer.length; - while ( (bytesToRead > 0) && (len >= buffer.length)) { - try { - len = istream.read(buffer); - if (bytesToRead >= len) { - ostream.write(buffer, 0, len); - bytesToRead -= len; - } else { - ostream.write(buffer, 0, (int) bytesToRead); - bytesToRead = 0; - } - } catch (IOException e) { - exception = e; - len = -1; - } - if (len < buffer.length) - break; - } - - return exception; - - } - - - /** - * Copy the contents of the specified input stream to the specified - * output stream, and ensure that both streams are closed before returning - * (even in the face of an exception). - * - * @param reader The reader to read from - * @param writer The writer to write to - * @param start Start of the range which will be copied - * @param end End of the range which will be copied - * @return Exception which occurred during processing - */ - protected IOException copyRange(Reader reader, PrintWriter writer, - long start, long end) { - - try { - reader.skip(start); - } catch (IOException e) { - return e; - } - - IOException exception = null; - long bytesToRead = end - start + 1; - - char buffer[] = new char[input]; - int len = buffer.length; - while ( (bytesToRead > 0) && (len >= buffer.length)) { - try { - len = reader.read(buffer); - if (bytesToRead >= len) { - writer.write(buffer, 0, len); - bytesToRead -= len; - } else { - writer.write(buffer, 0, (int) bytesToRead); - bytesToRead = 0; - } - } catch (IOException e) { - exception = e; - len = -1; - } - if (len < buffer.length) - break; - } - - return exception; - - } - - - - // ------------------------------------------------------ Range Inner Class - - - protected class Range { - - public long start; - public long end; - public long length; - - /** - * Validate range. - */ - public boolean validate() { - if (end >= length) - end = length - 1; - return ( (start >= 0) && (end >= 0) && (start <= end) - && (length > 0) ); - } - - public void recycle() { - start = 0; - end = 0; - length = 0; - } - - } - - -} +/* + * Copyright 1999,2004-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.RandomAccessFile; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.naming.InitialContext; +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.catalina.Globals; +import org.apache.catalina.util.ServerInfo; +import org.apache.catalina.util.StringManager; +import org.apache.catalina.util.URLEncoder; +import org.apache.naming.resources.CacheEntry; +import org.apache.naming.resources.ProxyDirContext; +import org.apache.naming.resources.Resource; +import org.apache.naming.resources.ResourceAttributes; + + +/** + * The default resource-serving servlet for most web applications, + * used to serve static resources such as HTML pages and images. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 332127 $ $Date: 2005-11-09 20:50:47 +0100 (mer., 09 nov. 2005) $ + */ + +public class DefaultServlet + extends HttpServlet { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The debugging detail level for this servlet. + */ + protected int debug = 0; + + + /** + * The input buffer size to use when serving resources. + */ + protected int input = 2048; + + + /** + * Should we generate directory listings? + */ + protected boolean listings = false; + + + /** + * Read only flag. By default, it's set to true. + */ + protected boolean readOnly = true; + + + /** + * The output buffer size to use when serving resources. + */ + protected int output = 2048; + + + /** + * Array containing the safe characters set. + */ + protected static URLEncoder urlEncoder; + + + /** + * Allow customized directory listing per directory. + */ + protected String localXsltFile = null; + + + /** + * Allow customized directory listing per instance. + */ + protected String globalXsltFile = null; + + + /** + * Allow a readme file to be included. + */ + protected String readmeFile = null; + + + /** + * Proxy directory context. + */ + protected ProxyDirContext resources = null; + + + /** + * File encoding to be used when reading static files. If none is specified + * the platform default is used. + */ + protected String fileEncoding = null; + + + /** + * Minimum size for sendfile usage in bytes. + */ + protected int sendfileSize = 48 * 1024; + + + /** + * Full range marker. + */ + protected static ArrayList FULL = new ArrayList(); + + + // ----------------------------------------------------- Static Initializer + + + /** + * GMT timezone - all HTTP dates are on GMT + */ + static { + urlEncoder = new URLEncoder(); + urlEncoder.addSafeCharacter('-'); + urlEncoder.addSafeCharacter('_'); + urlEncoder.addSafeCharacter('.'); + urlEncoder.addSafeCharacter('*'); + urlEncoder.addSafeCharacter('/'); + } + + + /** + * MIME multipart separation string + */ + protected static final String mimeSeparation = "CATALINA_MIME_BOUNDARY"; + + + /** + * JNDI resources name. + */ + protected static final String RESOURCES_JNDI_NAME = "java:/comp/Resources"; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Size of file transfer buffer in bytes. + */ + protected static final int BUFFER_SIZE = 4096; + + + // --------------------------------------------------------- Public Methods + + + /** + * Finalize this servlet. + */ + public void destroy() { + } + + + /** + * Initialize this servlet. + */ + public void init() throws ServletException { + + // Set our properties from the initialization parameters + String value = null; + try { + value = getServletConfig().getInitParameter("debug"); + debug = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("input"); + input = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("listings"); + listings = (new Boolean(value)).booleanValue(); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("readonly"); + if (value != null) + readOnly = (new Boolean(value)).booleanValue(); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("output"); + output = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("sendfileSize"); + sendfileSize = Integer.parseInt(value) * 1024; + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("fileEncoding"); + fileEncoding = value; + } catch (Throwable t) { + ; + } + + globalXsltFile = getServletConfig().getInitParameter("globalXsltFile"); + localXsltFile = getServletConfig().getInitParameter("localXsltFile"); + readmeFile = getServletConfig().getInitParameter("readmeFile"); + + // Sanity check on the specified buffer sizes + if (input < 256) + input = 256; + if (output < 256) + output = 256; + + if (debug > 0) { + log("DefaultServlet.init: input buffer size=" + input + + ", output buffer size=" + output); + } + + // Load the proxy dir context. + try { + resources = (ProxyDirContext) getServletContext() + .getAttribute(Globals.RESOURCES_ATTR); + } catch(ClassCastException e) { + // Failed : Not the right type + } + if (resources == null) { + try { + resources = + (ProxyDirContext) new InitialContext() + .lookup(RESOURCES_JNDI_NAME); + } catch (NamingException e) { + // Failed + } catch (ClassCastException e) { + // Failed : Not the right type + } + } + + if (resources == null) { + throw new UnavailableException("No resources"); + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return the relative path associated with this servlet. + * + * @param request The servlet request we are processing + */ + protected String getRelativePath(HttpServletRequest request) { + + // Are we being processed by a RequestDispatcher.include()? + if (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null) { + String result = (String) request.getAttribute( + Globals.INCLUDE_PATH_INFO_ATTR); + if (result == null) + result = (String) request.getAttribute( + Globals.INCLUDE_SERVLET_PATH_ATTR); + if ((result == null) || (result.equals(""))) + result = "/"; + return (result); + } + + // No, extract the desired path directly from the request + String result = request.getPathInfo(); + if (result == null) { + result = request.getServletPath(); + } + if ((result == null) || (result.equals(""))) { + result = "/"; + } + return (result); + + } + + + /** + * Process a GET request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + // Serve the requested resource, including the data content + serveResource(request, response, true); + + } + + + /** + * Process a HEAD request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doHead(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + // Serve the requested resource, without the data content + serveResource(request, response, false); + + } + + + /** + * Process a POST request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doPost(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + doGet(request, response); + } + + + /** + * Process a POST request for the specified resource. + * + * @param req The servlet request we are processing + * @param resp The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + String path = getRelativePath(req); + + boolean exists = true; + try { + resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + boolean result = true; + + // Temp. content file used to support partial PUT + File contentFile = null; + + Range range = parseContentRange(req, resp); + + InputStream resourceInputStream = null; + + // Append data specified in ranges to existing content for this + // resource - create a temp. file on the local filesystem to + // perform this operation + // Assume just one range is specified for now + if (range != null) { + contentFile = executePartialPut(req, range, path); + resourceInputStream = new FileInputStream(contentFile); + } else { + resourceInputStream = req.getInputStream(); + } + + try { + Resource newResource = new Resource(resourceInputStream); + // FIXME: Add attributes + if (exists) { + resources.rebind(path, newResource); + } else { + resources.bind(path, newResource); + } + } catch(NamingException e) { + result = false; + } + + if (result) { + if (exists) { + resp.setStatus(HttpServletResponse.SC_NO_CONTENT); + } else { + resp.setStatus(HttpServletResponse.SC_CREATED); + } + } else { + resp.sendError(HttpServletResponse.SC_CONFLICT); + } + + } + + + /** + * Handle a partial PUT. New content specified in request is appended to + * existing content in oldRevisionContent (if present). This code does + * not support simultaneous partial updates to the same resource. + */ + protected File executePartialPut(HttpServletRequest req, Range range, + String path) + throws IOException { + + // Append data specified in ranges to existing content for this + // resource - create a temp. file on the local filesystem to + // perform this operation + File tempDir = (File) getServletContext().getAttribute + ("javax.servlet.context.tempdir"); + // Convert all '/' characters to '.' in resourcePath + String convertedResourcePath = path.replace('/', '.'); + File contentFile = new File(tempDir, convertedResourcePath); + if (contentFile.createNewFile()) { + // Clean up contentFile when Tomcat is terminated + contentFile.deleteOnExit(); + } + + RandomAccessFile randAccessContentFile = + new RandomAccessFile(contentFile, "rw"); + + Resource oldResource = null; + try { + Object obj = resources.lookup(path); + if (obj instanceof Resource) + oldResource = (Resource) obj; + } catch (NamingException e) { + } + + // Copy data in oldRevisionContent to contentFile + if (oldResource != null) { + BufferedInputStream bufOldRevStream = + new BufferedInputStream(oldResource.streamContent(), + BUFFER_SIZE); + + int numBytesRead; + byte[] copyBuffer = new byte[BUFFER_SIZE]; + while ((numBytesRead = bufOldRevStream.read(copyBuffer)) != -1) { + randAccessContentFile.write(copyBuffer, 0, numBytesRead); + } + + bufOldRevStream.close(); + } + + randAccessContentFile.setLength(range.length); + + // Append data in request input stream to contentFile + randAccessContentFile.seek(range.start); + int numBytesRead; + byte[] transferBuffer = new byte[BUFFER_SIZE]; + BufferedInputStream requestBufInStream = + new BufferedInputStream(req.getInputStream(), BUFFER_SIZE); + while ((numBytesRead = requestBufInStream.read(transferBuffer)) != -1) { + randAccessContentFile.write(transferBuffer, 0, numBytesRead); + } + randAccessContentFile.close(); + requestBufInStream.close(); + + return contentFile; + + } + + + /** + * Process a POST request for the specified resource. + * + * @param req The servlet request we are processing + * @param resp The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + + String path = getRelativePath(req); + + boolean exists = true; + try { + resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + if (exists) { + boolean result = true; + try { + resources.unbind(path); + } catch (NamingException e) { + result = false; + } + if (result) { + resp.setStatus(HttpServletResponse.SC_NO_CONTENT); + } else { + resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); + } + } else { + resp.sendError(HttpServletResponse.SC_NOT_FOUND); + } + + } + + + /** + * Check if the conditions specified in the optional If headers are + * satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceAttributes The resource information + * @return boolean true if the resource meets all the specified conditions, + * and false if any of the conditions is not satisfied, in which case + * request processing is stopped + */ + protected boolean checkIfHeaders(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + + return checkIfMatch(request, response, resourceAttributes) + && checkIfModifiedSince(request, response, resourceAttributes) + && checkIfNoneMatch(request, response, resourceAttributes) + && checkIfUnmodifiedSince(request, response, resourceAttributes); + + } + + + /** + * Get the ETag associated with a file. + * + * @param resourceAttributes The resource information + */ + protected String getETag(ResourceAttributes resourceAttributes) { + String result = null; + if ((result = resourceAttributes.getETag(true)) != null) { + return result; + } else if ((result = resourceAttributes.getETag()) != null) { + return result; + } else { + return "W/\"" + resourceAttributes.getContentLength() + "-" + + resourceAttributes.getLastModified() + "\""; + } + } + + + /** + * URL rewriter. + * + * @param path Path which has to be rewiten + */ + protected String rewriteUrl(String path) { + return urlEncoder.encode( path ); + } + + + /** + * Display the size of a file. + */ + protected void displaySize(StringBuffer buf, int filesize) { + + int leftside = filesize / 1024; + int rightside = (filesize % 1024) / 103; // makes 1 digit + // To avoid 0.0 for non-zero file, we bump to 0.1 + if (leftside == 0 && rightside == 0 && filesize != 0) + rightside = 1; + buf.append(leftside).append(".").append(rightside); + buf.append(" KB"); + + } + + + /** + * Serve the specified resource, optionally including the data content. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param content Should the content be included? + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void serveResource(HttpServletRequest request, + HttpServletResponse response, + boolean content) + throws IOException, ServletException { + + // Identify the requested resource path + String path = getRelativePath(request); + if (debug > 0) { + if (content) + log("DefaultServlet.serveResource: Serving resource '" + + path + "' headers and data"); + else + log("DefaultServlet.serveResource: Serving resource '" + + path + "' headers only"); + } + + CacheEntry cacheEntry = resources.lookupCache(path); + + if (!cacheEntry.exists) { + // Check if we're included so we can return the appropriate + // missing resource name in the error + String requestUri = (String) request.getAttribute( + Globals.INCLUDE_REQUEST_URI_ATTR); + if (requestUri == null) { + requestUri = request.getRequestURI(); + } else { + // We're included, and the response.sendError() below is going + // to be ignored by the resource that is including us. + // Therefore, the only way we can let the including resource + // know is by including warning message in response + response.getWriter().write( + sm.getString("defaultServlet.missingResource", + requestUri)); + } + + response.sendError(HttpServletResponse.SC_NOT_FOUND, + requestUri); + return; + } + + // If the resource is not a collection, and the resource path + // ends with "/" or "\", return NOT FOUND + if (cacheEntry.context == null) { + if (path.endsWith("/") || (path.endsWith("\\"))) { + // Check if we're included so we can return the appropriate + // missing resource name in the error + String requestUri = (String) request.getAttribute( + Globals.INCLUDE_REQUEST_URI_ATTR); + if (requestUri == null) { + requestUri = request.getRequestURI(); + } + response.sendError(HttpServletResponse.SC_NOT_FOUND, + requestUri); + return; + } + } + + // Check if the conditions specified in the optional If headers are + // satisfied. + if (cacheEntry.context == null) { + + // Checking If headers + boolean included = + (request.getAttribute(Globals.INCLUDE_CONTEXT_PATH_ATTR) != null); + if (!included + && !checkIfHeaders(request, response, cacheEntry.attributes)) { + return; + } + + } + + // Find content type. + String contentType = cacheEntry.attributes.getMimeType(); + if (contentType == null) { + contentType = getServletContext().getMimeType(cacheEntry.name); + cacheEntry.attributes.setMimeType(contentType); + } + + ArrayList ranges = null; + long contentLength = -1L; + + if (cacheEntry.context != null) { + + // Skip directory listings if we have been configured to + // suppress them + if (!listings) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + request.getRequestURI()); + return; + } + contentType = "text/html;charset=UTF-8"; + + } else { + + // Parse range specifier + + ranges = parseRange(request, response, cacheEntry.attributes); + + // ETag header + response.setHeader("ETag", getETag(cacheEntry.attributes)); + + // Last-Modified header + response.setHeader("Last-Modified", + cacheEntry.attributes.getLastModifiedHttp()); + + // Get content length + contentLength = cacheEntry.attributes.getContentLength(); + // Special case for zero length files, which would cause a + // (silent) ISE when setting the output buffer size + if (contentLength == 0L) { + content = false; + } + + } + + ServletOutputStream ostream = null; + PrintWriter writer = null; + + if (content) { + + // Trying to retrieve the servlet output stream + + try { + ostream = response.getOutputStream(); + } catch (IllegalStateException e) { + // If it fails, we try to get a Writer instead if we're + // trying to serve a text file + if ( (contentType == null) + || (contentType.startsWith("text")) ) { + writer = response.getWriter(); + } else { + throw e; + } + } + + } + + if ( (cacheEntry.context != null) + || ( ((ranges == null) || (ranges.isEmpty())) + && (request.getHeader("Range") == null) ) + || (ranges == FULL) ) { + + // Set the appropriate output headers + if (contentType != null) { + if (debug > 0) + log("DefaultServlet.serveFile: contentType='" + + contentType + "'"); + response.setContentType(contentType); + } + if ((cacheEntry.resource != null) && (contentLength >= 0)) { + if (debug > 0) + log("DefaultServlet.serveFile: contentLength=" + + contentLength); + if (contentLength < Integer.MAX_VALUE) { + response.setContentLength((int) contentLength); + } else { + // Set the content-length as String to be able to use a long + response.setHeader("content-length", "" + contentLength); + } + } + + InputStream renderResult = null; + if (cacheEntry.context != null) { + + if (content) { + // Serve the directory browser + renderResult = + render(request.getContextPath(), cacheEntry); + } + + } + + // Copy the input stream to our output stream (if requested) + if (content) { + try { + response.setBufferSize(output); + } catch (IllegalStateException e) { + // Silent catch + } + if (ostream != null) { + if (!checkSendfile(request, response, cacheEntry, contentLength, null)) + copy(cacheEntry, renderResult, ostream); + } else { + copy(cacheEntry, renderResult, writer); + } + } + + } else { + + if ((ranges == null) || (ranges.isEmpty())) + return; + + // Partial content response. + + response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); + + if (ranges.size() == 1) { + + Range range = (Range) ranges.get(0); + response.addHeader("Content-Range", "bytes " + + range.start + + "-" + range.end + "/" + + range.length); + long length = range.end - range.start + 1; + if (length < Integer.MAX_VALUE) { + response.setContentLength((int) length); + } else { + // Set the content-length as String to be able to use a long + response.setHeader("content-length", "" + length); + } + + if (contentType != null) { + if (debug > 0) + log("DefaultServlet.serveFile: contentType='" + + contentType + "'"); + response.setContentType(contentType); + } + + if (content) { + try { + response.setBufferSize(output); + } catch (IllegalStateException e) { + // Silent catch + } + if (ostream != null) { + if (!checkSendfile(request, response, cacheEntry, range.end - range.start + 1, range)) + copy(cacheEntry, ostream, range); + } else { + copy(cacheEntry, writer, range); + } + } + + } else { + + response.setContentType("multipart/byteranges; boundary=" + + mimeSeparation); + + if (content) { + try { + response.setBufferSize(output); + } catch (IllegalStateException e) { + // Silent catch + } + if (ostream != null) { + copy(cacheEntry, ostream, ranges.iterator(), + contentType); + } else { + copy(cacheEntry, writer, ranges.iterator(), + contentType); + } + } + + } + + } + + } + + + /** + * Parse the content-range header. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @return Range + */ + protected Range parseContentRange(HttpServletRequest request, + HttpServletResponse response) + throws IOException { + + // Retrieving the content-range header (if any is specified + String rangeHeader = request.getHeader("Content-Range"); + + if (rangeHeader == null) + return null; + + // bytes is the only range unit supported + if (!rangeHeader.startsWith("bytes")) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + + rangeHeader = rangeHeader.substring(6).trim(); + + int dashPos = rangeHeader.indexOf('-'); + int slashPos = rangeHeader.indexOf('/'); + + if (dashPos == -1) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + + if (slashPos == -1) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + + Range range = new Range(); + + try { + range.start = Long.parseLong(rangeHeader.substring(0, dashPos)); + range.end = + Long.parseLong(rangeHeader.substring(dashPos + 1, slashPos)); + range.length = Long.parseLong + (rangeHeader.substring(slashPos + 1, rangeHeader.length())); + } catch (NumberFormatException e) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + + if (!range.validate()) { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + return null; + } + + return range; + + } + + + /** + * Parse the range header. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @return Vector of ranges + */ + protected ArrayList parseRange(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + + // Checking If-Range + String headerValue = request.getHeader("If-Range"); + + if (headerValue != null) { + + long headerValueTime = (-1L); + try { + headerValueTime = request.getDateHeader("If-Range"); + } catch (Exception e) { + ; + } + + String eTag = getETag(resourceAttributes); + long lastModified = resourceAttributes.getLastModified(); + + if (headerValueTime == (-1L)) { + + // If the ETag the client gave does not match the entity + // etag, then the entire entity is returned. + if (!eTag.equals(headerValue.trim())) + return FULL; + + } else { + + // If the timestamp of the entity the client got is older than + // the last modification date of the entity, the entire entity + // is returned. + if (lastModified > (headerValueTime + 1000)) + return FULL; + + } + + } + + long fileLength = resourceAttributes.getContentLength(); + + if (fileLength == 0) + return null; + + // Retrieving the range header (if any is specified + String rangeHeader = request.getHeader("Range"); + + if (rangeHeader == null) + return null; + // bytes is the only range unit supported (and I don't see the point + // of adding new ones). + if (!rangeHeader.startsWith("bytes")) { + response.addHeader("Content-Range", "bytes */" + fileLength); + response.sendError + (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return null; + } + + rangeHeader = rangeHeader.substring(6); + + // Vector which will contain all the ranges which are successfully + // parsed. + ArrayList result = new ArrayList(); + StringTokenizer commaTokenizer = new StringTokenizer(rangeHeader, ","); + + // Parsing the range list + while (commaTokenizer.hasMoreTokens()) { + String rangeDefinition = commaTokenizer.nextToken().trim(); + + Range currentRange = new Range(); + currentRange.length = fileLength; + + int dashPos = rangeDefinition.indexOf('-'); + + if (dashPos == -1) { + response.addHeader("Content-Range", "bytes */" + fileLength); + response.sendError + (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return null; + } + + if (dashPos == 0) { + + try { + long offset = Long.parseLong(rangeDefinition); + currentRange.start = fileLength + offset; + currentRange.end = fileLength - 1; + } catch (NumberFormatException e) { + response.addHeader("Content-Range", + "bytes */" + fileLength); + response.sendError + (HttpServletResponse + .SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return null; + } + + } else { + + try { + currentRange.start = Long.parseLong + (rangeDefinition.substring(0, dashPos)); + if (dashPos < rangeDefinition.length() - 1) + currentRange.end = Long.parseLong + (rangeDefinition.substring + (dashPos + 1, rangeDefinition.length())); + else + currentRange.end = fileLength - 1; + } catch (NumberFormatException e) { + response.addHeader("Content-Range", + "bytes */" + fileLength); + response.sendError + (HttpServletResponse + .SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return null; + } + + } + + if (!currentRange.validate()) { + response.addHeader("Content-Range", "bytes */" + fileLength); + response.sendError + (HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE); + return null; + } + + result.add(currentRange); + } + + return result; + } + + + + /** + * Decide which way to render. HTML or XML. + */ + protected InputStream render + (String contextPath, CacheEntry cacheEntry) { + InputStream xsltInputStream = + findXsltInputStream(cacheEntry.context); + + if (xsltInputStream==null) { + return renderHtml(contextPath, cacheEntry); + } else { + return renderXml(contextPath, cacheEntry, xsltInputStream); + } + + } + + /** + * Return an InputStream to an HTML representation of the contents + * of this directory. + * + * @param contextPath Context path to which our internal paths are + * relative + */ + protected InputStream renderXml(String contextPath, + CacheEntry cacheEntry, + InputStream xsltInputStream) { + + StringBuffer sb = new StringBuffer(); + + sb.append(""); + sb.append(""); + + sb.append(""); + + try { + + // Render the directory entries within this directory + NamingEnumeration enumeration = resources.list(cacheEntry.name); + + // rewriteUrl(contextPath) is expensive. cache result for later reuse + String rewrittenContextPath = rewriteUrl(contextPath); + + while (enumeration.hasMoreElements()) { + + NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); + String resourceName = ncPair.getName(); + String trimmed = resourceName/*.substring(trim)*/; + if (trimmed.equalsIgnoreCase("WEB-INF") || + trimmed.equalsIgnoreCase("META-INF") || + trimmed.equalsIgnoreCase(localXsltFile)) + continue; + + CacheEntry childCacheEntry = + resources.lookupCache(cacheEntry.name + resourceName); + if (!childCacheEntry.exists) { + continue; + } + + sb.append(""); + sb.append(trimmed); + if (childCacheEntry.context != null) + sb.append("/"); + sb.append(""); + + } + + } catch (NamingException e) { + // Something went wrong + e.printStackTrace(); + } + + sb.append(""); + + String readme = getReadme(cacheEntry.context); + + if (readme!=null) { + sb.append(""); + } + + + sb.append(""); + + + try { + TransformerFactory tFactory = TransformerFactory.newInstance(); + Source xmlSource = new StreamSource(new StringReader(sb.toString())); + Source xslSource = new StreamSource(xsltInputStream); + Transformer transformer = tFactory.newTransformer(xslSource); + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + OutputStreamWriter osWriter = new OutputStreamWriter(stream, "UTF8"); + StreamResult out = new StreamResult(osWriter); + transformer.transform(xmlSource, out); + osWriter.flush(); + return (new ByteArrayInputStream(stream.toByteArray())); + } catch (Exception e) { + log("directory transform failure: " + e.getMessage()); + return renderHtml(contextPath, cacheEntry); + } + } + + /** + * Return an InputStream to an HTML representation of the contents + * of this directory. + * + * @param contextPath Context path to which our internal paths are + * relative + */ + protected InputStream renderHtml + (String contextPath, CacheEntry cacheEntry) { + + String name = cacheEntry.name; + + // Number of characters to trim from the beginnings of filenames + int trim = name.length(); + if (!name.endsWith("/")) + trim += 1; + if (name.equals("/")) + trim = 1; + + // Prepare a writer to a buffered area + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + OutputStreamWriter osWriter = null; + try { + osWriter = new OutputStreamWriter(stream, "UTF8"); + } catch (Exception e) { + // Should never happen + osWriter = new OutputStreamWriter(stream); + } + PrintWriter writer = new PrintWriter(osWriter); + + StringBuffer sb = new StringBuffer(); + + // rewriteUrl(contextPath) is expensive. cache result for later reuse + String rewrittenContextPath = rewriteUrl(contextPath); + + // Render the page header + sb.append("\r\n"); + sb.append("\r\n"); + sb.append(""); + sb.append(sm.getString("directory.title", name)); + sb.append("\r\n"); + sb.append(" "); + sb.append("\r\n"); + sb.append(""); + sb.append("

    "); + sb.append(sm.getString("directory.title", name)); + + // Render the link to our parent (if required) + String parentDirectory = name; + if (parentDirectory.endsWith("/")) { + parentDirectory = + parentDirectory.substring(0, parentDirectory.length() - 1); + } + int slash = parentDirectory.lastIndexOf('/'); + if (slash >= 0) { + String parent = name.substring(0, slash); + sb.append(" - "); + sb.append(""); + sb.append(sm.getString("directory.parent", parent)); + sb.append(""); + sb.append(""); + } + + sb.append("

    "); + sb.append("
    "); + + sb.append("\r\n"); + + // Render the column headings + sb.append("\r\n"); + sb.append("\r\n"); + sb.append("\r\n"); + sb.append("\r\n"); + sb.append(""); + + try { + + // Render the directory entries within this directory + NamingEnumeration enumeration = resources.list(cacheEntry.name); + boolean shade = false; + while (enumeration.hasMoreElements()) { + + NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); + String resourceName = ncPair.getName(); + String trimmed = resourceName/*.substring(trim)*/; + if (trimmed.equalsIgnoreCase("WEB-INF") || + trimmed.equalsIgnoreCase("META-INF")) + continue; + + CacheEntry childCacheEntry = + resources.lookupCache(cacheEntry.name + resourceName); + if (!childCacheEntry.exists) { + continue; + } + + sb.append("\r\n"); + shade = !shade; + + sb.append("\r\n"); + + sb.append("\r\n"); + + sb.append("\r\n"); + + sb.append("\r\n"); + } + + } catch (NamingException e) { + // Something went wrong + e.printStackTrace(); + } + + // Render the page footer + sb.append("
    "); + sb.append(sm.getString("directory.filename")); + sb.append(""); + sb.append(sm.getString("directory.size")); + sb.append(""); + sb.append(sm.getString("directory.lastModified")); + sb.append("
      \r\n"); + sb.append(""); + sb.append(trimmed); + if (childCacheEntry.context != null) + sb.append("/"); + sb.append(""); + if (childCacheEntry.context != null) + sb.append(" "); + else + sb.append(renderSize(childCacheEntry.attributes.getContentLength())); + sb.append(""); + sb.append(childCacheEntry.attributes.getLastModifiedHttp()); + sb.append("
    \r\n"); + + sb.append("
    "); + + String readme = getReadme(cacheEntry.context); + if (readme!=null) { + sb.append(readme); + sb.append("
    "); + } + + sb.append("

    ").append(ServerInfo.getServerInfo()).append("

    "); + sb.append("\r\n"); + sb.append("\r\n"); + + // Return an input stream to the underlying bytes + writer.write(sb.toString()); + writer.flush(); + return (new ByteArrayInputStream(stream.toByteArray())); + + } + + + /** + * Render the specified file size (in bytes). + * + * @param size File size (in bytes) + */ + protected String renderSize(long size) { + + long leftSide = size / 1024; + long rightSide = (size % 1024) / 103; // Makes 1 digit + if ((leftSide == 0) && (rightSide == 0) && (size > 0)) + rightSide = 1; + + return ("" + leftSide + "." + rightSide + " kb"); + + } + + + /** + * Get the readme file as a string. + */ + protected String getReadme(DirContext directory) { + if (readmeFile!=null) { + try { + Object obj = directory.lookup(readmeFile); + + if (obj!=null && obj instanceof Resource) { + StringWriter buffer = new StringWriter(); + InputStream is = ((Resource)obj).streamContent(); + copyRange(new InputStreamReader(is), + new PrintWriter(buffer)); + + return buffer.toString(); + } + } catch(Throwable e) { + ; /* Should only be IOException or NamingException + * can be ignored + */ + } + } + + return null; + } + + + /** + * Return the xsl template inputstream (if possible) + */ + protected InputStream findXsltInputStream(DirContext directory) { + + if (localXsltFile!=null) { + try { + Object obj = directory.lookup(localXsltFile); + if (obj!=null && obj instanceof Resource) { + InputStream is = ((Resource)obj).streamContent(); + if (is!=null) + return is; + } + } catch(Throwable e) { + ; /* Should only be IOException or NamingException + * can be ignored + */ + } + } + + /* Open and read in file in one fell swoop to reduce chance + * chance of leaving handle open. + */ + if (globalXsltFile!=null) { + FileInputStream fis = null; + + try { + File f = new File(globalXsltFile); + if (f.exists()){ + fis =new FileInputStream(f); + byte b[] = new byte[(int)f.length()]; /* danger! */ + fis.read(b); + return new ByteArrayInputStream(b); + } + } catch(Throwable e) { + log("This shouldn't happen (?)...", e); + return null; + } finally { + try { + if (fis!=null) + fis.close(); + } catch(Throwable e){ + ; + } + } + } + + return null; + + } + + + // -------------------------------------------------------- protected Methods + + + /** + * Check if sendfile can be used. + */ + protected boolean checkSendfile(HttpServletRequest request, + HttpServletResponse response, + CacheEntry entry, + long length, Range range) { + if ((sendfileSize > 0) + && (entry.resource != null) + && ((length > sendfileSize) || (entry.resource.getContent() == null)) + && (entry.attributes.getCanonicalPath() != null) + && (Boolean.TRUE == request.getAttribute("org.apache.tomcat.sendfile.support")) + && (request.getClass().getName().equals("org.apache.catalina.connector.RequestFacade")) + && (response.getClass().getName().equals("org.apache.catalina.connector.ResponseFacade"))) { + request.setAttribute("org.apache.tomcat.sendfile.filename", entry.attributes.getCanonicalPath()); + if (range == null) { + request.setAttribute("org.apache.tomcat.sendfile.start", new Long(0L)); + request.setAttribute("org.apache.tomcat.sendfile.end", new Long(length)); + } else { + request.setAttribute("org.apache.tomcat.sendfile.start", new Long(range.start)); + request.setAttribute("org.apache.tomcat.sendfile.end", new Long(range.end + 1)); + } + request.setAttribute("org.apache.tomcat.sendfile.token", this); + return true; + } else { + return false; + } + } + + + /** + * Check if the if-match condition is satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceInfo File object + * @return boolean true if the resource meets the specified condition, + * and false if the condition is not satisfied, in which case request + * processing is stopped + */ + protected boolean checkIfMatch(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + + String eTag = getETag(resourceAttributes); + String headerValue = request.getHeader("If-Match"); + if (headerValue != null) { + if (headerValue.indexOf('*') == -1) { + + StringTokenizer commaTokenizer = new StringTokenizer + (headerValue, ","); + boolean conditionSatisfied = false; + + while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { + String currentToken = commaTokenizer.nextToken(); + if (currentToken.trim().equals(eTag)) + conditionSatisfied = true; + } + + // If none of the given ETags match, 412 Precodition failed is + // sent back + if (!conditionSatisfied) { + response.sendError + (HttpServletResponse.SC_PRECONDITION_FAILED); + return false; + } + + } + } + return true; + + } + + + /** + * Check if the if-modified-since condition is satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceInfo File object + * @return boolean true if the resource meets the specified condition, + * and false if the condition is not satisfied, in which case request + * processing is stopped + */ + protected boolean checkIfModifiedSince(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + try { + long headerValue = request.getDateHeader("If-Modified-Since"); + long lastModified = resourceAttributes.getLastModified(); + if (headerValue != -1) { + + // If an If-None-Match header has been specified, if modified since + // is ignored. + if ((request.getHeader("If-None-Match") == null) + && (lastModified <= headerValue + 1000)) { + // The entity has not been modified since the date + // specified by the client. This is not an error case. + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return false; + } + } + } catch(IllegalArgumentException illegalArgument) { + return true; + } + return true; + + } + + + /** + * Check if the if-none-match condition is satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceInfo File object + * @return boolean true if the resource meets the specified condition, + * and false if the condition is not satisfied, in which case request + * processing is stopped + */ + protected boolean checkIfNoneMatch(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + + String eTag = getETag(resourceAttributes); + String headerValue = request.getHeader("If-None-Match"); + if (headerValue != null) { + + boolean conditionSatisfied = false; + + if (!headerValue.equals("*")) { + + StringTokenizer commaTokenizer = + new StringTokenizer(headerValue, ","); + + while (!conditionSatisfied && commaTokenizer.hasMoreTokens()) { + String currentToken = commaTokenizer.nextToken(); + if (currentToken.trim().equals(eTag)) + conditionSatisfied = true; + } + + } else { + conditionSatisfied = true; + } + + if (conditionSatisfied) { + + // For GET and HEAD, we should respond with + // 304 Not Modified. + // For every other method, 412 Precondition Failed is sent + // back. + if ( ("GET".equals(request.getMethod())) + || ("HEAD".equals(request.getMethod())) ) { + response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); + return false; + } else { + response.sendError + (HttpServletResponse.SC_PRECONDITION_FAILED); + return false; + } + } + } + return true; + + } + + + /** + * Check if the if-unmodified-since condition is satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceInfo File object + * @return boolean true if the resource meets the specified condition, + * and false if the condition is not satisfied, in which case request + * processing is stopped + */ + protected boolean checkIfUnmodifiedSince(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + try { + long lastModified = resourceAttributes.getLastModified(); + long headerValue = request.getDateHeader("If-Unmodified-Since"); + if (headerValue != -1) { + if ( lastModified > (headerValue + 1000)) { + // The entity has not been modified since the date + // specified by the client. This is not an error case. + response.sendError(HttpServletResponse.SC_PRECONDITION_FAILED); + return false; + } + } + } catch(IllegalArgumentException illegalArgument) { + return true; + } + return true; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The resource information + * @param ostream The output stream to write to + * + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, InputStream is, + ServletOutputStream ostream) + throws IOException { + + IOException exception = null; + InputStream resourceInputStream = null; + + // Optimization: If the binary content has already been loaded, send + // it directly + if (cacheEntry.resource != null) { + byte buffer[] = cacheEntry.resource.getContent(); + if (buffer != null) { + ostream.write(buffer, 0, buffer.length); + return; + } + resourceInputStream = cacheEntry.resource.streamContent(); + } else { + resourceInputStream = is; + } + + InputStream istream = new BufferedInputStream + (resourceInputStream, input); + + // Copy the input stream to the output stream + exception = copyRange(istream, ostream); + + // Clean up the input stream + try { + istream.close(); + } catch (Throwable t) { + ; + } + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The resource info + * @param writer The writer to write to + * + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, InputStream is, PrintWriter writer) + throws IOException { + + IOException exception = null; + + InputStream resourceInputStream = null; + if (cacheEntry.resource != null) { + resourceInputStream = cacheEntry.resource.streamContent(); + } else { + resourceInputStream = is; + } + + Reader reader; + if (fileEncoding == null) { + reader = new InputStreamReader(resourceInputStream); + } else { + reader = new InputStreamReader(resourceInputStream, + fileEncoding); + } + + // Copy the input stream to the output stream + exception = copyRange(reader, writer); + + // Clean up the reader + try { + reader.close(); + } catch (Throwable t) { + ; + } + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The ResourceInfo object + * @param ostream The output stream to write to + * @param range Range the client wanted to retrieve + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, + Range range) + throws IOException { + + IOException exception = null; + + InputStream resourceInputStream = cacheEntry.resource.streamContent(); + InputStream istream = + new BufferedInputStream(resourceInputStream, input); + exception = copyRange(istream, ostream, range.start, range.end); + + // Clean up the input stream + try { + istream.close(); + } catch (Throwable t) { + ; + } + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The ResourceInfo object + * @param writer The writer to write to + * @param range Range the client wanted to retrieve + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, PrintWriter writer, + Range range) + throws IOException { + + IOException exception = null; + + InputStream resourceInputStream = cacheEntry.resource.streamContent(); + + Reader reader; + if (fileEncoding == null) { + reader = new InputStreamReader(resourceInputStream); + } else { + reader = new InputStreamReader(resourceInputStream, + fileEncoding); + } + + exception = copyRange(reader, writer, range.start, range.end); + + // Clean up the input stream + try { + reader.close(); + } catch (Throwable t) { + ; + } + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The ResourceInfo object + * @param ostream The output stream to write to + * @param ranges Enumeration of the ranges the client wanted to retrieve + * @param contentType Content type of the resource + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, ServletOutputStream ostream, + Iterator ranges, String contentType) + throws IOException { + + IOException exception = null; + + while ( (exception == null) && (ranges.hasNext()) ) { + + InputStream resourceInputStream = cacheEntry.resource.streamContent(); + InputStream istream = + new BufferedInputStream(resourceInputStream, input); + + Range currentRange = (Range) ranges.next(); + + // Writing MIME header. + ostream.println(); + ostream.println("--" + mimeSeparation); + if (contentType != null) + ostream.println("Content-Type: " + contentType); + ostream.println("Content-Range: bytes " + currentRange.start + + "-" + currentRange.end + "/" + + currentRange.length); + ostream.println(); + + // Printing content + exception = copyRange(istream, ostream, currentRange.start, + currentRange.end); + + try { + istream.close(); + } catch (Throwable t) { + ; + } + + } + + ostream.println(); + ostream.print("--" + mimeSeparation + "--"); + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param resourceInfo The ResourceInfo object + * @param writer The writer to write to + * @param ranges Enumeration of the ranges the client wanted to retrieve + * @param contentType Content type of the resource + * @exception IOException if an input/output error occurs + */ + protected void copy(CacheEntry cacheEntry, PrintWriter writer, + Iterator ranges, String contentType) + throws IOException { + + IOException exception = null; + + while ( (exception == null) && (ranges.hasNext()) ) { + + InputStream resourceInputStream = cacheEntry.resource.streamContent(); + + Reader reader; + if (fileEncoding == null) { + reader = new InputStreamReader(resourceInputStream); + } else { + reader = new InputStreamReader(resourceInputStream, + fileEncoding); + } + + Range currentRange = (Range) ranges.next(); + + // Writing MIME header. + writer.println(); + writer.println("--" + mimeSeparation); + if (contentType != null) + writer.println("Content-Type: " + contentType); + writer.println("Content-Range: bytes " + currentRange.start + + "-" + currentRange.end + "/" + + currentRange.length); + writer.println(); + + // Printing content + exception = copyRange(reader, writer, currentRange.start, + currentRange.end); + + try { + reader.close(); + } catch (Throwable t) { + ; + } + + } + + writer.println(); + writer.print("--" + mimeSeparation + "--"); + + // Rethrow any exception that has occurred + if (exception != null) + throw exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param istream The input stream to read from + * @param ostream The output stream to write to + * @return Exception which occurred during processing + */ + protected IOException copyRange(InputStream istream, + ServletOutputStream ostream) { + + // Copy the input stream to the output stream + IOException exception = null; + byte buffer[] = new byte[input]; + int len = buffer.length; + while (true) { + try { + len = istream.read(buffer); + if (len == -1) + break; + ostream.write(buffer, 0, len); + } catch (IOException e) { + exception = e; + len = -1; + break; + } + } + return exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param reader The reader to read from + * @param writer The writer to write to + * @return Exception which occurred during processing + */ + protected IOException copyRange(Reader reader, PrintWriter writer) { + + // Copy the input stream to the output stream + IOException exception = null; + char buffer[] = new char[input]; + int len = buffer.length; + while (true) { + try { + len = reader.read(buffer); + if (len == -1) + break; + writer.write(buffer, 0, len); + } catch (IOException e) { + exception = e; + len = -1; + break; + } + } + return exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param istream The input stream to read from + * @param ostream The output stream to write to + * @param start Start of the range which will be copied + * @param end End of the range which will be copied + * @return Exception which occurred during processing + */ + protected IOException copyRange(InputStream istream, + ServletOutputStream ostream, + long start, long end) { + + if (debug > 10) + log("Serving bytes:" + start + "-" + end); + + try { + istream.skip(start); + } catch (IOException e) { + return e; + } + + IOException exception = null; + long bytesToRead = end - start + 1; + + byte buffer[] = new byte[input]; + int len = buffer.length; + while ( (bytesToRead > 0) && (len >= buffer.length)) { + try { + len = istream.read(buffer); + if (bytesToRead >= len) { + ostream.write(buffer, 0, len); + bytesToRead -= len; + } else { + ostream.write(buffer, 0, (int) bytesToRead); + bytesToRead = 0; + } + } catch (IOException e) { + exception = e; + len = -1; + } + if (len < buffer.length) + break; + } + + return exception; + + } + + + /** + * Copy the contents of the specified input stream to the specified + * output stream, and ensure that both streams are closed before returning + * (even in the face of an exception). + * + * @param reader The reader to read from + * @param writer The writer to write to + * @param start Start of the range which will be copied + * @param end End of the range which will be copied + * @return Exception which occurred during processing + */ + protected IOException copyRange(Reader reader, PrintWriter writer, + long start, long end) { + + try { + reader.skip(start); + } catch (IOException e) { + return e; + } + + IOException exception = null; + long bytesToRead = end - start + 1; + + char buffer[] = new char[input]; + int len = buffer.length; + while ( (bytesToRead > 0) && (len >= buffer.length)) { + try { + len = reader.read(buffer); + if (bytesToRead >= len) { + writer.write(buffer, 0, len); + bytesToRead -= len; + } else { + writer.write(buffer, 0, (int) bytesToRead); + bytesToRead = 0; + } + } catch (IOException e) { + exception = e; + len = -1; + } + if (len < buffer.length) + break; + } + + return exception; + + } + + + + // ------------------------------------------------------ Range Inner Class + + + protected class Range { + + public long start; + public long end; + public long length; + + /** + * Validate range. + */ + public boolean validate() { + if (end >= length) + end = length - 1; + return ( (start >= 0) && (end >= 0) && (start <= end) + && (length > 0) ); + } + + public void recycle() { + start = 0; + end = 0; + length = 0; + } + + } + + +} diff --git a/java/org/apache/catalina/servlets/InvokerHttpRequest.java b/java/org/apache/catalina/servlets/InvokerHttpRequest.java index c0772e423..fdc6fc4dc 100644 --- a/java/org/apache/catalina/servlets/InvokerHttpRequest.java +++ b/java/org/apache/catalina/servlets/InvokerHttpRequest.java @@ -1,198 +1,198 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - - -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; - - -/** - * Wrapper around a javax.servlet.http.HttpServletRequest - * utilized when InvokerServlet processes the initial request - * for an invoked servlet. Subsequent requests will be mapped directly - * to the servlet, because a new servlet mapping will have been created. - * - * @author Craig R. McClanahan - * @version $Revision: 303211 $ $Date: 2004-09-08 12:38:14 +0200 (mer., 08 sept. 2004) $ - */ - -class InvokerHttpRequest extends HttpServletRequestWrapper { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new wrapped request around the specified servlet request. - * - * @param request The servlet request being wrapped - */ - public InvokerHttpRequest(HttpServletRequest request) { - - super(request); - this.pathInfo = request.getPathInfo(); - this.pathTranslated = request.getPathTranslated(); - this.requestURI = request.getRequestURI(); - this.servletPath = request.getServletPath(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.servlets.InvokerHttpRequest/1.0"; - - - /** - * The path information for this request. - */ - protected String pathInfo = null; - - - /** - * The translated path information for this request. - */ - protected String pathTranslated = null; - - - /** - * The request URI for this request. - */ - protected String requestURI = null; - - - /** - * The servlet path for this request. - */ - protected String servletPath = null; - - - // --------------------------------------------- HttpServletRequest Methods - - - /** - * Override the getPathInfo() method of the wrapped request. - */ - public String getPathInfo() { - - return (this.pathInfo); - - } - - - /** - * Override the getPathTranslated() method of the - * wrapped request. - */ - public String getPathTranslated() { - - return (this.pathTranslated); - - } - - - /** - * Override the getRequestURI() method of the wrapped request. - */ - public String getRequestURI() { - - return (this.requestURI); - - } - - - /** - * Override the getServletPath() method of the wrapped - * request. - */ - public String getServletPath() { - - return (this.servletPath); - - } - - - // -------------------------------------------------------- Package Methods - - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Set the path information for this request. - * - * @param pathInfo The new path info - */ - void setPathInfo(String pathInfo) { - - this.pathInfo = pathInfo; - - } - - - /** - * Set the translated path info for this request. - * - * @param pathTranslated The new translated path info - */ - void setPathTranslated(String pathTranslated) { - - this.pathTranslated = pathTranslated; - - } - - - /** - * Set the request URI for this request. - * - * @param requestURI The new request URI - */ - void setRequestURI(String requestURI) { - - this.requestURI = requestURI; - - } - - - /** - * Set the servlet path for this request. - * - * @param servletPath The new servlet path - */ - void setServletPath(String servletPath) { - - this.servletPath = servletPath; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + + +/** + * Wrapper around a javax.servlet.http.HttpServletRequest + * utilized when InvokerServlet processes the initial request + * for an invoked servlet. Subsequent requests will be mapped directly + * to the servlet, because a new servlet mapping will have been created. + * + * @author Craig R. McClanahan + * @version $Revision: 303211 $ $Date: 2004-09-08 12:38:14 +0200 (mer., 08 sept. 2004) $ + */ + +class InvokerHttpRequest extends HttpServletRequestWrapper { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new wrapped request around the specified servlet request. + * + * @param request The servlet request being wrapped + */ + public InvokerHttpRequest(HttpServletRequest request) { + + super(request); + this.pathInfo = request.getPathInfo(); + this.pathTranslated = request.getPathTranslated(); + this.requestURI = request.getRequestURI(); + this.servletPath = request.getServletPath(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.servlets.InvokerHttpRequest/1.0"; + + + /** + * The path information for this request. + */ + protected String pathInfo = null; + + + /** + * The translated path information for this request. + */ + protected String pathTranslated = null; + + + /** + * The request URI for this request. + */ + protected String requestURI = null; + + + /** + * The servlet path for this request. + */ + protected String servletPath = null; + + + // --------------------------------------------- HttpServletRequest Methods + + + /** + * Override the getPathInfo() method of the wrapped request. + */ + public String getPathInfo() { + + return (this.pathInfo); + + } + + + /** + * Override the getPathTranslated() method of the + * wrapped request. + */ + public String getPathTranslated() { + + return (this.pathTranslated); + + } + + + /** + * Override the getRequestURI() method of the wrapped request. + */ + public String getRequestURI() { + + return (this.requestURI); + + } + + + /** + * Override the getServletPath() method of the wrapped + * request. + */ + public String getServletPath() { + + return (this.servletPath); + + } + + + // -------------------------------------------------------- Package Methods + + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Set the path information for this request. + * + * @param pathInfo The new path info + */ + void setPathInfo(String pathInfo) { + + this.pathInfo = pathInfo; + + } + + + /** + * Set the translated path info for this request. + * + * @param pathTranslated The new translated path info + */ + void setPathTranslated(String pathTranslated) { + + this.pathTranslated = pathTranslated; + + } + + + /** + * Set the request URI for this request. + * + * @param requestURI The new request URI + */ + void setRequestURI(String requestURI) { + + this.requestURI = requestURI; + + } + + + /** + * Set the servlet path for this request. + * + * @param servletPath The new servlet path + */ + void setServletPath(String servletPath) { + + this.servletPath = servletPath; + + } + + +} diff --git a/java/org/apache/catalina/servlets/InvokerServlet.java b/java/org/apache/catalina/servlets/InvokerServlet.java index 318c0bc1a..1a6e1c9d5 100644 --- a/java/org/apache/catalina/servlets/InvokerServlet.java +++ b/java/org/apache/catalina/servlets/InvokerServlet.java @@ -1,497 +1,497 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - - -import java.io.IOException; - -import javax.servlet.Servlet; -import javax.servlet.ServletException; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.ContainerServlet; -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Wrapper; -import org.apache.catalina.util.StringManager; - - -/** - * The default servlet-invoking servlet for most web applications, - * used to serve requests to servlets that have not been registered - * in the web application deployment descriptor. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class InvokerServlet - extends HttpServlet implements ContainerServlet { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The Context container associated with our web application. - */ - private Context context = null; - - - /** - * The debugging detail level for this servlet. - */ - private int debug = 0; - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The Wrapper container associated with this servlet. - */ - private Wrapper wrapper = null; - - - // ----------------------------------------------- ContainerServlet Methods - - - /** - * Return the Wrapper with which we are associated. - */ - public Wrapper getWrapper() { - - return (this.wrapper); - - } - - - /** - * Set the Wrapper with which we are associated. - * - * @param wrapper The new wrapper - */ - public void setWrapper(Wrapper wrapper) { - - this.wrapper = wrapper; - if (wrapper == null) - context = null; - else - context = (Context) wrapper.getParent(); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Finalize this servlet. - */ - public void destroy() { - - ; // No actions necessary - - } - - - /** - * Process a GET request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - public void doGet(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - serveRequest(request, response); - - } - - - /** - * Process a HEAD request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - public void doHead(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - serveRequest(request, response); - - } - - - /** - * Process a POST request for the specified resource. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - public void doPost(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - serveRequest(request, response); - - } - - - /** - * Initialize this servlet. - */ - public void init() throws ServletException { - - // Ensure that our ContainerServlet properties have been set - if ((wrapper == null) || (context == null)) - throw new UnavailableException - (sm.getString("invokerServlet.noWrapper")); - - // Set our properties from the initialization parameters - String value = null; - try { - value = getServletConfig().getInitParameter("debug"); - debug = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - if (debug >= 1) - log("init: Associated with Context '" + context.getPath() + "'"); - - } - - - - // -------------------------------------------------------- Private Methods - - - /** - * Serve the specified request, creating the corresponding response. - * After the first time a particular servlet class is requested, it will - * be served directly (like any registered servlet) because it will have - * been registered and mapped in our associated Context. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - public void serveRequest(HttpServletRequest request, - HttpServletResponse response) - throws IOException, ServletException { - - // Disallow calling this servlet via a named dispatcher - if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null) - throw new ServletException - (sm.getString("invokerServlet.notNamed")); - - // Identify the input parameters and our "included" state - String inRequestURI = null; - String inServletPath = null; - String inPathInfo = null; - boolean included = - (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null); - - if (included) { - inRequestURI = - (String) request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR); - inServletPath = - (String) request.getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); - inPathInfo = - (String) request.getAttribute(Globals.INCLUDE_PATH_INFO_ATTR); - } else { - inRequestURI = request.getRequestURI(); - inServletPath = request.getServletPath(); - inPathInfo = request.getPathInfo(); - } - if (debug >= 1) { - log("included='" + included + "', requestURI='" + - inRequestURI + "'"); - log(" servletPath='" + inServletPath + "', pathInfo='" + - inPathInfo + "'"); - } - - // Make sure a servlet name or class name was specified - if (inPathInfo == null) { - if (debug >= 1) - log("Invalid pathInfo '" + inPathInfo + "'"); - if (included) - throw new ServletException - (sm.getString("invokerServlet.invalidPath", inRequestURI)); - else { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - return; - } - } - - // Identify the outgoing servlet name or class, and outgoing path info - String pathInfo = inPathInfo; - String servletClass = pathInfo.substring(1); - int slash = servletClass.indexOf('/'); - // if (debug >= 2) - // log(" Calculating with servletClass='" + servletClass + - // "', pathInfo='" + pathInfo + "', slash=" + slash); - if (slash >= 0) { - pathInfo = servletClass.substring(slash); - servletClass = servletClass.substring(0, slash); - } else { - pathInfo = ""; - } - - if (servletClass.startsWith("org.apache.catalina")) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - return; - } - - if (debug >= 1) - log("Processing servlet '" + servletClass + - "' with path info '" + pathInfo + "'"); - String name = "org.apache.catalina.INVOKER." + servletClass; - String pattern = inServletPath + "/" + servletClass + "/*"; - Wrapper wrapper = null; - - // Synchronize to avoid race conditions when multiple requests - // try to initialize the same servlet at the same time - synchronized (this) { - - // Are we referencing an existing servlet class or name? - wrapper = (Wrapper) context.findChild(servletClass); - if (wrapper == null) - wrapper = (Wrapper) context.findChild(name); - if (wrapper != null) { - String actualServletClass = wrapper.getServletClass(); - if ((actualServletClass != null) - && (actualServletClass.startsWith - ("org.apache.catalina"))) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - return; - } - if (debug >= 1) - log("Using wrapper for servlet '" + - wrapper.getName() + "' with mapping '" + - pattern + "'"); - context.addServletMapping(pattern, wrapper.getName()); - } - - // No, create a new wrapper for the specified servlet class - else { - - if (debug >= 1) - log("Creating wrapper for '" + servletClass + - "' with mapping '" + pattern + "'"); - - try { - wrapper = context.createWrapper(); - wrapper.setName(name); - wrapper.setLoadOnStartup(1); - wrapper.setServletClass(servletClass); - context.addChild(wrapper); - context.addServletMapping(pattern, name); - } catch (Throwable t) { - log(sm.getString("invokerServlet.cannotCreate", - inRequestURI), t); - context.removeServletMapping(pattern); - context.removeChild(wrapper); - if (included) - throw new ServletException - (sm.getString("invokerServlet.cannotCreate", - inRequestURI), t); - else { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - return; - } - } - } - - } - - // Create a request wrapper to pass on to the invoked servlet - InvokerHttpRequest wrequest = - new InvokerHttpRequest(request); - wrequest.setRequestURI(inRequestURI); - StringBuffer sb = new StringBuffer(inServletPath); - sb.append("/"); - sb.append(servletClass); - wrequest.setServletPath(sb.toString()); - if ((pathInfo == null) || (pathInfo.length() < 1)) { - wrequest.setPathInfo(null); - wrequest.setPathTranslated(null); - } else { - wrequest.setPathInfo(pathInfo); - wrequest.setPathTranslated - (getServletContext().getRealPath(pathInfo)); - } - - // Allocate a servlet instance to perform this request - Servlet instance = null; - try { - // if (debug >= 2) - // log(" Allocating servlet instance"); - instance = wrapper.allocate(); - } catch (ServletException e) { - log(sm.getString("invokerServlet.allocate", inRequestURI), e); - context.removeServletMapping(pattern); - context.removeChild(wrapper); - Throwable rootCause = e.getRootCause(); - if (rootCause == null) - rootCause = e; - if (rootCause instanceof ClassNotFoundException) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - inRequestURI); - return; - } else if (rootCause instanceof IOException) { - throw (IOException) rootCause; - } else if (rootCause instanceof RuntimeException) { - throw (RuntimeException) rootCause; - } else if (rootCause instanceof ServletException) { - throw (ServletException) rootCause; - } else { - throw new ServletException - (sm.getString("invokerServlet.allocate", inRequestURI), - rootCause); - } - } catch (Throwable e) { - log(sm.getString("invokerServlet.allocate", inRequestURI), e); - context.removeServletMapping(pattern); - context.removeChild(wrapper); - throw new ServletException - (sm.getString("invokerServlet.allocate", inRequestURI), e); - } - - // After loading the wrapper, restore some of the fields when including - if (included) { - wrequest.setRequestURI(request.getRequestURI()); - wrequest.setPathInfo(request.getPathInfo()); - wrequest.setServletPath(request.getServletPath()); - } - - // Invoke the service() method of the allocated servlet - try { - String jspFile = wrapper.getJspFile(); - if (jspFile != null) - request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); - else - request.removeAttribute(Globals.JSP_FILE_ATTR); - request.setAttribute(Globals.INVOKED_ATTR, - request.getServletPath()); - // if (debug >= 2) - // log(" Calling service() method, jspFile=" + - // jspFile); - instance.service(wrequest, response); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - } catch (IOException e) { - // if (debug >= 2) - // log(" service() method IOException", e); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - try { - wrapper.deallocate(instance); - } catch (Throwable f) { - ; - } - throw e; - } catch (UnavailableException e) { - // if (debug >= 2) - // log(" service() method UnavailableException", e); - context.removeServletMapping(pattern); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - try { - wrapper.deallocate(instance); - } catch (Throwable f) { - ; - } - throw e; - } catch (ServletException e) { - // if (debug >= 2) - // log(" service() method ServletException", e); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - try { - wrapper.deallocate(instance); - } catch (Throwable f) { - ; - } - throw e; - } catch (RuntimeException e) { - // if (debug >= 2) - // log(" service() method RuntimeException", e); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - try { - wrapper.deallocate(instance); - } catch (Throwable f) { - ; - } - throw e; - } catch (Throwable e) { - // if (debug >= 2) - // log(" service() method Throwable", e); - request.removeAttribute(Globals.INVOKED_ATTR); - request.removeAttribute(Globals.JSP_FILE_ATTR); - try { - wrapper.deallocate(instance); - } catch (Throwable f) { - ; - } - throw new ServletException("Invoker service() exception", e); - } - - // Deallocate the allocated servlet instance - try { - // if (debug >= 2) - // log(" deallocate servlet instance"); - wrapper.deallocate(instance); - } catch (ServletException e) { - log(sm.getString("invokerServlet.deallocate", inRequestURI), e); - throw e; - } catch (Throwable e) { - log(sm.getString("invokerServlet.deallocate", inRequestURI), e); - throw new ServletException - (sm.getString("invokerServlet.deallocate", inRequestURI), e); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + + +import java.io.IOException; + +import javax.servlet.Servlet; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.ContainerServlet; +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Wrapper; +import org.apache.catalina.util.StringManager; + + +/** + * The default servlet-invoking servlet for most web applications, + * used to serve requests to servlets that have not been registered + * in the web application deployment descriptor. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class InvokerServlet + extends HttpServlet implements ContainerServlet { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Context container associated with our web application. + */ + private Context context = null; + + + /** + * The debugging detail level for this servlet. + */ + private int debug = 0; + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The Wrapper container associated with this servlet. + */ + private Wrapper wrapper = null; + + + // ----------------------------------------------- ContainerServlet Methods + + + /** + * Return the Wrapper with which we are associated. + */ + public Wrapper getWrapper() { + + return (this.wrapper); + + } + + + /** + * Set the Wrapper with which we are associated. + * + * @param wrapper The new wrapper + */ + public void setWrapper(Wrapper wrapper) { + + this.wrapper = wrapper; + if (wrapper == null) + context = null; + else + context = (Context) wrapper.getParent(); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Finalize this servlet. + */ + public void destroy() { + + ; // No actions necessary + + } + + + /** + * Process a GET request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + public void doGet(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + serveRequest(request, response); + + } + + + /** + * Process a HEAD request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + public void doHead(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + serveRequest(request, response); + + } + + + /** + * Process a POST request for the specified resource. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + public void doPost(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + serveRequest(request, response); + + } + + + /** + * Initialize this servlet. + */ + public void init() throws ServletException { + + // Ensure that our ContainerServlet properties have been set + if ((wrapper == null) || (context == null)) + throw new UnavailableException + (sm.getString("invokerServlet.noWrapper")); + + // Set our properties from the initialization parameters + String value = null; + try { + value = getServletConfig().getInitParameter("debug"); + debug = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + if (debug >= 1) + log("init: Associated with Context '" + context.getPath() + "'"); + + } + + + + // -------------------------------------------------------- Private Methods + + + /** + * Serve the specified request, creating the corresponding response. + * After the first time a particular servlet class is requested, it will + * be served directly (like any registered servlet) because it will have + * been registered and mapped in our associated Context. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + public void serveRequest(HttpServletRequest request, + HttpServletResponse response) + throws IOException, ServletException { + + // Disallow calling this servlet via a named dispatcher + if (request.getAttribute(Globals.NAMED_DISPATCHER_ATTR) != null) + throw new ServletException + (sm.getString("invokerServlet.notNamed")); + + // Identify the input parameters and our "included" state + String inRequestURI = null; + String inServletPath = null; + String inPathInfo = null; + boolean included = + (request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR) != null); + + if (included) { + inRequestURI = + (String) request.getAttribute(Globals.INCLUDE_REQUEST_URI_ATTR); + inServletPath = + (String) request.getAttribute(Globals.INCLUDE_SERVLET_PATH_ATTR); + inPathInfo = + (String) request.getAttribute(Globals.INCLUDE_PATH_INFO_ATTR); + } else { + inRequestURI = request.getRequestURI(); + inServletPath = request.getServletPath(); + inPathInfo = request.getPathInfo(); + } + if (debug >= 1) { + log("included='" + included + "', requestURI='" + + inRequestURI + "'"); + log(" servletPath='" + inServletPath + "', pathInfo='" + + inPathInfo + "'"); + } + + // Make sure a servlet name or class name was specified + if (inPathInfo == null) { + if (debug >= 1) + log("Invalid pathInfo '" + inPathInfo + "'"); + if (included) + throw new ServletException + (sm.getString("invokerServlet.invalidPath", inRequestURI)); + else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } + } + + // Identify the outgoing servlet name or class, and outgoing path info + String pathInfo = inPathInfo; + String servletClass = pathInfo.substring(1); + int slash = servletClass.indexOf('/'); + // if (debug >= 2) + // log(" Calculating with servletClass='" + servletClass + + // "', pathInfo='" + pathInfo + "', slash=" + slash); + if (slash >= 0) { + pathInfo = servletClass.substring(slash); + servletClass = servletClass.substring(0, slash); + } else { + pathInfo = ""; + } + + if (servletClass.startsWith("org.apache.catalina")) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } + + if (debug >= 1) + log("Processing servlet '" + servletClass + + "' with path info '" + pathInfo + "'"); + String name = "org.apache.catalina.INVOKER." + servletClass; + String pattern = inServletPath + "/" + servletClass + "/*"; + Wrapper wrapper = null; + + // Synchronize to avoid race conditions when multiple requests + // try to initialize the same servlet at the same time + synchronized (this) { + + // Are we referencing an existing servlet class or name? + wrapper = (Wrapper) context.findChild(servletClass); + if (wrapper == null) + wrapper = (Wrapper) context.findChild(name); + if (wrapper != null) { + String actualServletClass = wrapper.getServletClass(); + if ((actualServletClass != null) + && (actualServletClass.startsWith + ("org.apache.catalina"))) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } + if (debug >= 1) + log("Using wrapper for servlet '" + + wrapper.getName() + "' with mapping '" + + pattern + "'"); + context.addServletMapping(pattern, wrapper.getName()); + } + + // No, create a new wrapper for the specified servlet class + else { + + if (debug >= 1) + log("Creating wrapper for '" + servletClass + + "' with mapping '" + pattern + "'"); + + try { + wrapper = context.createWrapper(); + wrapper.setName(name); + wrapper.setLoadOnStartup(1); + wrapper.setServletClass(servletClass); + context.addChild(wrapper); + context.addServletMapping(pattern, name); + } catch (Throwable t) { + log(sm.getString("invokerServlet.cannotCreate", + inRequestURI), t); + context.removeServletMapping(pattern); + context.removeChild(wrapper); + if (included) + throw new ServletException + (sm.getString("invokerServlet.cannotCreate", + inRequestURI), t); + else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } + } + } + + } + + // Create a request wrapper to pass on to the invoked servlet + InvokerHttpRequest wrequest = + new InvokerHttpRequest(request); + wrequest.setRequestURI(inRequestURI); + StringBuffer sb = new StringBuffer(inServletPath); + sb.append("/"); + sb.append(servletClass); + wrequest.setServletPath(sb.toString()); + if ((pathInfo == null) || (pathInfo.length() < 1)) { + wrequest.setPathInfo(null); + wrequest.setPathTranslated(null); + } else { + wrequest.setPathInfo(pathInfo); + wrequest.setPathTranslated + (getServletContext().getRealPath(pathInfo)); + } + + // Allocate a servlet instance to perform this request + Servlet instance = null; + try { + // if (debug >= 2) + // log(" Allocating servlet instance"); + instance = wrapper.allocate(); + } catch (ServletException e) { + log(sm.getString("invokerServlet.allocate", inRequestURI), e); + context.removeServletMapping(pattern); + context.removeChild(wrapper); + Throwable rootCause = e.getRootCause(); + if (rootCause == null) + rootCause = e; + if (rootCause instanceof ClassNotFoundException) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + inRequestURI); + return; + } else if (rootCause instanceof IOException) { + throw (IOException) rootCause; + } else if (rootCause instanceof RuntimeException) { + throw (RuntimeException) rootCause; + } else if (rootCause instanceof ServletException) { + throw (ServletException) rootCause; + } else { + throw new ServletException + (sm.getString("invokerServlet.allocate", inRequestURI), + rootCause); + } + } catch (Throwable e) { + log(sm.getString("invokerServlet.allocate", inRequestURI), e); + context.removeServletMapping(pattern); + context.removeChild(wrapper); + throw new ServletException + (sm.getString("invokerServlet.allocate", inRequestURI), e); + } + + // After loading the wrapper, restore some of the fields when including + if (included) { + wrequest.setRequestURI(request.getRequestURI()); + wrequest.setPathInfo(request.getPathInfo()); + wrequest.setServletPath(request.getServletPath()); + } + + // Invoke the service() method of the allocated servlet + try { + String jspFile = wrapper.getJspFile(); + if (jspFile != null) + request.setAttribute(Globals.JSP_FILE_ATTR, jspFile); + else + request.removeAttribute(Globals.JSP_FILE_ATTR); + request.setAttribute(Globals.INVOKED_ATTR, + request.getServletPath()); + // if (debug >= 2) + // log(" Calling service() method, jspFile=" + + // jspFile); + instance.service(wrequest, response); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + } catch (IOException e) { + // if (debug >= 2) + // log(" service() method IOException", e); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (UnavailableException e) { + // if (debug >= 2) + // log(" service() method UnavailableException", e); + context.removeServletMapping(pattern); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (ServletException e) { + // if (debug >= 2) + // log(" service() method ServletException", e); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (RuntimeException e) { + // if (debug >= 2) + // log(" service() method RuntimeException", e); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw e; + } catch (Throwable e) { + // if (debug >= 2) + // log(" service() method Throwable", e); + request.removeAttribute(Globals.INVOKED_ATTR); + request.removeAttribute(Globals.JSP_FILE_ATTR); + try { + wrapper.deallocate(instance); + } catch (Throwable f) { + ; + } + throw new ServletException("Invoker service() exception", e); + } + + // Deallocate the allocated servlet instance + try { + // if (debug >= 2) + // log(" deallocate servlet instance"); + wrapper.deallocate(instance); + } catch (ServletException e) { + log(sm.getString("invokerServlet.deallocate", inRequestURI), e); + throw e; + } catch (Throwable e) { + log(sm.getString("invokerServlet.deallocate", inRequestURI), e); + throw new ServletException + (sm.getString("invokerServlet.deallocate", inRequestURI), e); + } + + } + + +} diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties index f8b40c753..d4c2971d5 100644 --- a/java/org/apache/catalina/servlets/LocalStrings.properties +++ b/java/org/apache/catalina/servlets/LocalStrings.properties @@ -1,19 +1,19 @@ -defaultServlet.missingResource=The requested resource ({0}) is not available -defaultservlet.directorylistingfor=Directory Listing for: -defaultservlet.upto=Up to: -defaultservlet.subdirectories=Subdirectories: -defaultservlet.files=Files: -invokerServlet.allocate=Cannot allocate servlet instance for path {0} -invokerServlet.cannotCreate=Cannot create servlet wrapper for path {0} -invokerServlet.deallocate=Cannot deallocate servlet instance for path {0} -invokerServlet.invalidPath=No servlet name or class was specified in path {0} -invokerServlet.notNamed=Cannot call invoker servlet with a named dispatcher -invokerServlet.noWrapper=Container has not called setWrapper() for this servlet -webdavservlet.jaxpfailed=JAXP initialization failed -directory.filename=Filename -directory.lastModified=Last Modified -directory.parent=Up To {0} -directory.size=Size -directory.title=Directory Listing For {0} -directory.version=Tomcat Catalina version 4.0 - +defaultServlet.missingResource=The requested resource ({0}) is not available +defaultservlet.directorylistingfor=Directory Listing for: +defaultservlet.upto=Up to: +defaultservlet.subdirectories=Subdirectories: +defaultservlet.files=Files: +invokerServlet.allocate=Cannot allocate servlet instance for path {0} +invokerServlet.cannotCreate=Cannot create servlet wrapper for path {0} +invokerServlet.deallocate=Cannot deallocate servlet instance for path {0} +invokerServlet.invalidPath=No servlet name or class was specified in path {0} +invokerServlet.notNamed=Cannot call invoker servlet with a named dispatcher +invokerServlet.noWrapper=Container has not called setWrapper() for this servlet +webdavservlet.jaxpfailed=JAXP initialization failed +directory.filename=Filename +directory.lastModified=Last Modified +directory.parent=Up To {0} +directory.size=Size +directory.title=Directory Listing For {0} +directory.version=Tomcat Catalina version 4.0 + diff --git a/java/org/apache/catalina/servlets/LocalStrings_es.properties b/java/org/apache/catalina/servlets/LocalStrings_es.properties index f2ddd570a..4f55f63e6 100644 --- a/java/org/apache/catalina/servlets/LocalStrings_es.properties +++ b/java/org/apache/catalina/servlets/LocalStrings_es.properties @@ -1,18 +1,18 @@ -defaultservlet.directorylistingfor=Listado de Directorio para: -defaultservlet.upto=Atrás a: -defaultservlet.subdirectories=Subdirectorios: -defaultservlet.files=Archivos: -invokerServlet.allocate=No puedo reservar espacio para instancia de servlet para trayectoria {0} -invokerServlet.cannotCreate=No puedo crear arropador (wrapper) de servlet para trayectoria {0} -invokerServlet.deallocate=No puedo recuperar instancia de servlet para trayectoria {0} -invokerServlet.invalidPath=No se ha especificado nombre de servlet o clase en trayectoria {0} -invokerServlet.notNamed=No puedo llamar a servlet invocador mediante un despachador nombrado (named) -invokerServlet.noWrapper=El Contenedor no ha llamado a setWrapper() para este servlet -webdavservlet.jaxpfailed=Falló la inicialización de JAXP -directory.filename=Nombre de Archivo -directory.lastModified=Última Modificación -directory.parent=Atrás A {0} -directory.size=Medida -directory.title=Listado de Directorio Para {0} -directory.version=Tomcat Catalina versión 4.0 - +defaultservlet.directorylistingfor=Listado de Directorio para: +defaultservlet.upto=Atrás a: +defaultservlet.subdirectories=Subdirectorios: +defaultservlet.files=Archivos: +invokerServlet.allocate=No puedo reservar espacio para instancia de servlet para trayectoria {0} +invokerServlet.cannotCreate=No puedo crear arropador (wrapper) de servlet para trayectoria {0} +invokerServlet.deallocate=No puedo recuperar instancia de servlet para trayectoria {0} +invokerServlet.invalidPath=No se ha especificado nombre de servlet o clase en trayectoria {0} +invokerServlet.notNamed=No puedo llamar a servlet invocador mediante un despachador nombrado (named) +invokerServlet.noWrapper=El Contenedor no ha llamado a setWrapper() para este servlet +webdavservlet.jaxpfailed=Falló la inicialización de JAXP +directory.filename=Nombre de Archivo +directory.lastModified=Última Modificación +directory.parent=Atrás A {0} +directory.size=Medida +directory.title=Listado de Directorio Para {0} +directory.version=Tomcat Catalina versión 4.0 + diff --git a/java/org/apache/catalina/servlets/LocalStrings_fr.properties b/java/org/apache/catalina/servlets/LocalStrings_fr.properties index 62c3ccab2..d694e06c9 100644 --- a/java/org/apache/catalina/servlets/LocalStrings_fr.properties +++ b/java/org/apache/catalina/servlets/LocalStrings_fr.properties @@ -1,18 +1,18 @@ -defaultservlet.directorylistingfor=Liste du répertoire pour : -defaultservlet.upto=Jusqu''à: -defaultservlet.subdirectories=Sous-répertoires: -defaultservlet.files=Fichiers: -invokerServlet.allocate=Impossible d''allouer une instance de servlet pour le chemin {0} -invokerServlet.cannotCreate=Impossible de créer un enrobeur (wrapper) de servlet pour le chemin {0} -invokerServlet.deallocate=Impossible de désallouer une instance de servlet pour le chemin {0} -invokerServlet.invalidPath=Aucun nom de servlet ou de classe n''a été spécifié pour le chemin {0} -invokerServlet.notNamed=Impossible d''appeler le délégué (invoker) de servlet avec un aiguilleur (dispatcher) nommé -invokerServlet.noWrapper=Le conteneur n''a pas appelé "setWrapper()" pour cette servlet -webdavservlet.jaxpfailed=Erreur d''initialisation de JAXP -directory.filename=Nom de fichier -directory.lastModified=Dernière modification -directory.parent=Jusqu''à {0} -directory.size=Taille -directory.title=Liste du répertoire pour {0} -directory.version=Tomcat Catalina version 4.0 - +defaultservlet.directorylistingfor=Liste du répertoire pour : +defaultservlet.upto=Jusqu''à: +defaultservlet.subdirectories=Sous-répertoires: +defaultservlet.files=Fichiers: +invokerServlet.allocate=Impossible d''allouer une instance de servlet pour le chemin {0} +invokerServlet.cannotCreate=Impossible de créer un enrobeur (wrapper) de servlet pour le chemin {0} +invokerServlet.deallocate=Impossible de désallouer une instance de servlet pour le chemin {0} +invokerServlet.invalidPath=Aucun nom de servlet ou de classe n''a été spécifié pour le chemin {0} +invokerServlet.notNamed=Impossible d''appeler le délégué (invoker) de servlet avec un aiguilleur (dispatcher) nommé +invokerServlet.noWrapper=Le conteneur n''a pas appelé "setWrapper()" pour cette servlet +webdavservlet.jaxpfailed=Erreur d''initialisation de JAXP +directory.filename=Nom de fichier +directory.lastModified=Dernière modification +directory.parent=Jusqu''à {0} +directory.size=Taille +directory.title=Liste du répertoire pour {0} +directory.version=Tomcat Catalina version 4.0 + diff --git a/java/org/apache/catalina/servlets/LocalStrings_ja.properties b/java/org/apache/catalina/servlets/LocalStrings_ja.properties index 80e231939..d4802c39b 100644 --- a/java/org/apache/catalina/servlets/LocalStrings_ja.properties +++ b/java/org/apache/catalina/servlets/LocalStrings_ja.properties @@ -1,18 +1,18 @@ -defaultservlet.directorylistingfor=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7: -defaultservlet.upto=\u89aa\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: -defaultservlet.subdirectories=\u30b5\u30d6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: -defaultservlet.files=\u30d5\u30a1\u30a4\u30eb: -invokerServlet.allocate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093 -invokerServlet.cannotCreate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30e9\u30c3\u30d1\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 -invokerServlet.deallocate=\u30d1\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3067\u304d\u307e\u305b\u3093 -invokerServlet.invalidPath=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d\u53c8\u306f\u30af\u30e9\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -invokerServlet.notNamed=\u305d\u306e\u540d\u524d\u306e\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u30e3\u3067\u30a4\u30f3\u30dc\u30fc\u30ab\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u547c\u3073\u51fa\u305b\u307e\u305b\u3093 -invokerServlet.noWrapper=\u30b3\u30f3\u30c6\u30ca\u306f\u3053\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306b\u5bfe\u3057\u3066\u547c\u3073\u51fa\u3055\u308c\u305fsetWrapper()\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 -webdavservlet.jaxpfailed=JAXP\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f -directory.filename=\u30d5\u30a1\u30a4\u30eb\u540d -directory.lastModified=\u6700\u7d42\u66f4\u65b0 -directory.parent={0} \u306b\u79fb\u52d5 -directory.size=\u30b5\u30a4\u30ba -directory.title={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7 -directory.version=Tomcat Catalina \u30d0\u30fc\u30b8\u30e7\u30f3 4.0 - +defaultservlet.directorylistingfor=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7: +defaultservlet.upto=\u89aa\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: +defaultservlet.subdirectories=\u30b5\u30d6\u30c7\u30a3\u30ec\u30af\u30c8\u30ea: +defaultservlet.files=\u30d5\u30a1\u30a4\u30eb: +invokerServlet.allocate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093 +invokerServlet.cannotCreate=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30e9\u30c3\u30d1\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 +invokerServlet.deallocate=\u30d1\u30b9 {0} \u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306e\u5272\u308a\u5f53\u3066\u3092\u89e3\u9664\u3067\u304d\u307e\u305b\u3093 +invokerServlet.invalidPath=\u30d1\u30b9 {0} \u306b\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u540d\u53c8\u306f\u30af\u30e9\u30b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +invokerServlet.notNamed=\u305d\u306e\u540d\u524d\u306e\u30c7\u30a3\u30b9\u30d1\u30c3\u30c1\u30e3\u3067\u30a4\u30f3\u30dc\u30fc\u30ab\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u547c\u3073\u51fa\u305b\u307e\u305b\u3093 +invokerServlet.noWrapper=\u30b3\u30f3\u30c6\u30ca\u306f\u3053\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306b\u5bfe\u3057\u3066\u547c\u3073\u51fa\u3055\u308c\u305fsetWrapper()\u3092\u6301\u3063\u3066\u3044\u307e\u305b\u3093 +webdavservlet.jaxpfailed=JAXP\u306e\u521d\u671f\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f +directory.filename=\u30d5\u30a1\u30a4\u30eb\u540d +directory.lastModified=\u6700\u7d42\u66f4\u65b0 +directory.parent={0} \u306b\u79fb\u52d5 +directory.size=\u30b5\u30a4\u30ba +directory.title={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u4e00\u89a7 +directory.version=Tomcat Catalina \u30d0\u30fc\u30b8\u30e7\u30f3 4.0 + diff --git a/java/org/apache/catalina/servlets/WebdavServlet.java b/java/org/apache/catalina/servlets/WebdavServlet.java index ebfc1b7b9..78b49e89c 100644 --- a/java/org/apache/catalina/servlets/WebdavServlet.java +++ b/java/org/apache/catalina/servlets/WebdavServlet.java @@ -1,3082 +1,3082 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.servlets; - - -import java.io.IOException; -import java.io.StringWriter; -import java.io.Writer; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Stack; -import java.util.TimeZone; -import java.util.Vector; - -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.ServletException; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.catalina.util.DOMWriter; -import org.apache.catalina.util.MD5Encoder; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.XMLWriter; -import org.apache.naming.resources.CacheEntry; -import org.apache.naming.resources.Resource; -import org.apache.naming.resources.ResourceAttributes; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - - - -/** - * Servlet which adds support for WebDAV level 2. All the basic HTTP requests - * are handled by the DefaultServlet. - * - * @author Remy Maucherat - * @version $Revision: 303599 $ $Date: 2004-12-20 19:54:14 +0100 (lun., 20 déc. 2004) $ - */ - -public class WebdavServlet - extends DefaultServlet { - - - // -------------------------------------------------------------- Constants - - - private static final String METHOD_HEAD = "HEAD"; - private static final String METHOD_PROPFIND = "PROPFIND"; - private static final String METHOD_PROPPATCH = "PROPPATCH"; - private static final String METHOD_MKCOL = "MKCOL"; - private static final String METHOD_COPY = "COPY"; - private static final String METHOD_MOVE = "MOVE"; - private static final String METHOD_LOCK = "LOCK"; - private static final String METHOD_UNLOCK = "UNLOCK"; - - - /** - * Default depth is infite. - */ - private static final int INFINITY = 3; // To limit tree browsing a bit - - - /** - * PROPFIND - Specify a property mask. - */ - private static final int FIND_BY_PROPERTY = 0; - - - /** - * PROPFIND - Display all properties. - */ - private static final int FIND_ALL_PROP = 1; - - - /** - * PROPFIND - Return property names. - */ - private static final int FIND_PROPERTY_NAMES = 2; - - - /** - * Create a new lock. - */ - private static final int LOCK_CREATION = 0; - - - /** - * Refresh lock. - */ - private static final int LOCK_REFRESH = 1; - - - /** - * Default lock timeout value. - */ - private static final int DEFAULT_TIMEOUT = 3600; - - - /** - * Maximum lock timeout. - */ - private static final int MAX_TIMEOUT = 604800; - - - /** - * Default namespace. - */ - protected static final String DEFAULT_NAMESPACE = "DAV:"; - - - /** - * Simple date format for the creation date ISO representation (partial). - */ - protected static final SimpleDateFormat creationDateFormat = - new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); - - - /** - * MD5 message digest provider. - */ - protected static MessageDigest md5Helper; - - - /** - * The MD5 helper object for this class. - */ - protected static final MD5Encoder md5Encoder = new MD5Encoder(); - - - - static { - creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Repository of the locks put on single resources. - *

    - * Key : path
    - * Value : LockInfo - */ - private Hashtable resourceLocks = new Hashtable(); - - - /** - * Repository of the lock-null resources. - *

    - * Key : path of the collection containing the lock-null resource
    - * Value : Vector of lock-null resource which are members of the - * collection. Each element of the Vector is the path associated with - * the lock-null resource. - */ - private Hashtable lockNullResources = new Hashtable(); - - - /** - * Vector of the heritable locks. - *

    - * Key : path
    - * Value : LockInfo - */ - private Vector collectionLocks = new Vector(); - - - /** - * Secret information used to generate reasonably secure lock ids. - */ - private String secret = "catalina"; - - - // --------------------------------------------------------- Public Methods - - - /** - * Initialize this servlet. - */ - public void init() - throws ServletException { - - super.init(); - - String value = null; - try { - value = getServletConfig().getInitParameter("secret"); - if (value != null) - secret = value; - } catch (Throwable t) { - ; - } - - - // Load the MD5 helper used to calculate signatures. - try { - md5Helper = MessageDigest.getInstance("MD5"); - } catch (NoSuchAlgorithmException e) { - throw new UnavailableException("No MD5"); - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return JAXP document builder instance. - */ - protected DocumentBuilder getDocumentBuilder() - throws ServletException { - DocumentBuilder documentBuilder = null; - DocumentBuilderFactory documentBuilderFactory = null; - try { - documentBuilderFactory = DocumentBuilderFactory.newInstance(); - documentBuilderFactory.setNamespaceAware(true); - documentBuilder = documentBuilderFactory.newDocumentBuilder(); - } catch(ParserConfigurationException e) { - throw new ServletException - (sm.getString("webdavservlet.jaxpfailed")); - } - return documentBuilder; - } - - - /** - * Handles the special WebDAV methods. - */ - protected void service(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - String method = req.getMethod(); - - if (debug > 0) { - String path = getRelativePath(req); - log("[" + method + "] " + path); - } - - if (method.equals(METHOD_PROPFIND)) { - doPropfind(req, resp); - } else if (method.equals(METHOD_PROPPATCH)) { - doProppatch(req, resp); - } else if (method.equals(METHOD_MKCOL)) { - doMkcol(req, resp); - } else if (method.equals(METHOD_COPY)) { - doCopy(req, resp); - } else if (method.equals(METHOD_MOVE)) { - doMove(req, resp); - } else if (method.equals(METHOD_LOCK)) { - doLock(req, resp); - } else if (method.equals(METHOD_UNLOCK)) { - doUnlock(req, resp); - } else { - // DefaultServlet processing - super.service(req, resp); - } - - } - - - /** - * Check if the conditions specified in the optional If headers are - * satisfied. - * - * @param request The servlet request we are processing - * @param response The servlet response we are creating - * @param resourceAttributes The resource information - * @return boolean true if the resource meets all the specified conditions, - * and false if any of the conditions is not satisfied, in which case - * request processing is stopped - */ - protected boolean checkIfHeaders(HttpServletRequest request, - HttpServletResponse response, - ResourceAttributes resourceAttributes) - throws IOException { - - if (!super.checkIfHeaders(request, response, resourceAttributes)) - return false; - - // TODO : Checking the WebDAV If header - return true; - - } - - - /** - * OPTIONS Method. - * - * @param req The request - * @param resp The response - * @throws ServletException If an error occurs - * @throws IOException If an IO error occurs - */ - protected void doOptions(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - resp.addHeader("DAV", "1,2"); - - StringBuffer methodsAllowed = determineMethodsAllowed(resources, - req); - - resp.addHeader("Allow", methodsAllowed.toString()); - resp.addHeader("MS-Author-Via", "DAV"); - - } - - - /** - * PROPFIND Method. - */ - protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (!listings) { - // Get allowed methods - StringBuffer methodsAllowed = determineMethodsAllowed(resources, - req); - - resp.addHeader("Allow", methodsAllowed.toString()); - resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); - return; - } - - String path = getRelativePath(req); - if (path.endsWith("/")) - path = path.substring(0, path.length() - 1); - - if ((path.toUpperCase().startsWith("/WEB-INF")) || - (path.toUpperCase().startsWith("/META-INF"))) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - // Properties which are to be displayed. - Vector properties = null; - // Propfind depth - int depth = INFINITY; - // Propfind type - int type = FIND_ALL_PROP; - - String depthStr = req.getHeader("Depth"); - - if (depthStr == null) { - depth = INFINITY; - } else { - if (depthStr.equals("0")) { - depth = 0; - } else if (depthStr.equals("1")) { - depth = 1; - } else if (depthStr.equals("infinity")) { - depth = INFINITY; - } - } - - Node propNode = null; - - DocumentBuilder documentBuilder = getDocumentBuilder(); - - try { - Document document = documentBuilder.parse - (new InputSource(req.getInputStream())); - - // Get the root element of the document - Element rootElement = document.getDocumentElement(); - NodeList childList = rootElement.getChildNodes(); - - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - break; - case Node.ELEMENT_NODE: - if (currentNode.getNodeName().endsWith("prop")) { - type = FIND_BY_PROPERTY; - propNode = currentNode; - } - if (currentNode.getNodeName().endsWith("propname")) { - type = FIND_PROPERTY_NAMES; - } - if (currentNode.getNodeName().endsWith("allprop")) { - type = FIND_ALL_PROP; - } - break; - } - } - } catch(Exception e) { - // Most likely there was no content : we use the defaults. - // TODO : Enhance that ! - } - - if (type == FIND_BY_PROPERTY) { - properties = new Vector(); - NodeList childList = propNode.getChildNodes(); - - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - break; - case Node.ELEMENT_NODE: - String nodeName = currentNode.getNodeName(); - String propertyName = null; - if (nodeName.indexOf(':') != -1) { - propertyName = nodeName.substring - (nodeName.indexOf(':') + 1); - } else { - propertyName = nodeName; - } - // href is a live property which is handled differently - properties.addElement(propertyName); - break; - } - } - - } - - boolean exists = true; - Object object = null; - try { - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - int slash = path.lastIndexOf('/'); - if (slash != -1) { - String parentPath = path.substring(0, slash); - Vector currentLockNullResources = - (Vector) lockNullResources.get(parentPath); - if (currentLockNullResources != null) { - Enumeration lockNullResourcesList = - currentLockNullResources.elements(); - while (lockNullResourcesList.hasMoreElements()) { - String lockNullPath = (String) - lockNullResourcesList.nextElement(); - if (lockNullPath.equals(path)) { - resp.setStatus(WebdavStatus.SC_MULTI_STATUS); - resp.setContentType("text/xml; charset=UTF-8"); - // Create multistatus object - XMLWriter generatedXML = - new XMLWriter(resp.getWriter()); - generatedXML.writeXMLHeader(); - generatedXML.writeElement - (null, "multistatus" - + generateNamespaceDeclarations(), - XMLWriter.OPENING); - parseLockNullProperties - (req, generatedXML, lockNullPath, type, - properties); - generatedXML.writeElement(null, "multistatus", - XMLWriter.CLOSING); - generatedXML.sendData(); - return; - } - } - } - } - } - - if (!exists) { - resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); - return; - } - - resp.setStatus(WebdavStatus.SC_MULTI_STATUS); - - resp.setContentType("text/xml; charset=UTF-8"); - - // Create multistatus object - XMLWriter generatedXML = new XMLWriter(resp.getWriter()); - generatedXML.writeXMLHeader(); - - generatedXML.writeElement(null, "multistatus" - + generateNamespaceDeclarations(), - XMLWriter.OPENING); - - if (depth == 0) { - parseProperties(req, generatedXML, path, type, - properties); - } else { - // The stack always contains the object of the current level - Stack stack = new Stack(); - stack.push(path); - - // Stack of the objects one level below - Stack stackBelow = new Stack(); - - while ((!stack.isEmpty()) && (depth >= 0)) { - - String currentPath = (String) stack.pop(); - parseProperties(req, generatedXML, currentPath, - type, properties); - - try { - object = resources.lookup(currentPath); - } catch (NamingException e) { - continue; - } - - if ((object instanceof DirContext) && (depth > 0)) { - - try { - NamingEnumeration enumeration = resources.list(currentPath); - while (enumeration.hasMoreElements()) { - NameClassPair ncPair = - (NameClassPair) enumeration.nextElement(); - String newPath = currentPath; - if (!(newPath.endsWith("/"))) - newPath += "/"; - newPath += ncPair.getName(); - stackBelow.push(newPath); - } - } catch (NamingException e) { - resp.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - path); - return; - } - - // Displaying the lock-null resources present in that - // collection - String lockPath = currentPath; - if (lockPath.endsWith("/")) - lockPath = - lockPath.substring(0, lockPath.length() - 1); - Vector currentLockNullResources = - (Vector) lockNullResources.get(lockPath); - if (currentLockNullResources != null) { - Enumeration lockNullResourcesList = - currentLockNullResources.elements(); - while (lockNullResourcesList.hasMoreElements()) { - String lockNullPath = (String) - lockNullResourcesList.nextElement(); - parseLockNullProperties - (req, generatedXML, lockNullPath, type, - properties); - } - } - - } - - if (stack.isEmpty()) { - depth--; - stack = stackBelow; - stackBelow = new Stack(); - } - - generatedXML.sendData(); - - } - } - - generatedXML.writeElement(null, "multistatus", - XMLWriter.CLOSING); - - generatedXML.sendData(); - - } - - - /** - * PROPPATCH Method. - */ - protected void doProppatch(HttpServletRequest req, - HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); - - } - - - /** - * MKCOL Method. - */ - protected void doMkcol(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - String path = getRelativePath(req); - - if ((path.toUpperCase().startsWith("/WEB-INF")) || - (path.toUpperCase().startsWith("/META-INF"))) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - boolean exists = true; - Object object = null; - try { - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - // Can't create a collection if a resource already exists at the given - // path - if (exists) { - // Get allowed methods - StringBuffer methodsAllowed = determineMethodsAllowed(resources, - req); - - resp.addHeader("Allow", methodsAllowed.toString()); - - resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); - return; - } - - if (req.getInputStream().available() > 0) { - DocumentBuilder documentBuilder = getDocumentBuilder(); - try { - Document document = documentBuilder.parse - (new InputSource(req.getInputStream())); - // TODO : Process this request body - resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED); - return; - - } catch(SAXException saxe) { - // Parse error - assume invalid content - resp.sendError(WebdavStatus.SC_BAD_REQUEST); - return; - } - } - - boolean result = true; - try { - resources.createSubcontext(path); - } catch (NamingException e) { - result = false; - } - - if (!result) { - resp.sendError(WebdavStatus.SC_CONFLICT, - WebdavStatus.getStatusText - (WebdavStatus.SC_CONFLICT)); - } else { - resp.setStatus(WebdavStatus.SC_CREATED); - // Removing any lock-null resource which would be present - lockNullResources.remove(path); - } - - } - - - /** - * DELETE Method. - */ - protected void doDelete(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - deleteResource(req, resp); - - } - - - /** - * Process a POST request for the specified resource. - * - * @param req The servlet request we are processing - * @param resp The servlet response we are creating - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet-specified error occurs - */ - protected void doPut(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - super.doPut(req, resp); - - String path = getRelativePath(req); - - // Removing any lock-null resource which would be present - lockNullResources.remove(path); - - } - - /** - * COPY Method. - */ - protected void doCopy(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - copyResource(req, resp); - - } - - - /** - * MOVE Method. - */ - protected void doMove(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - String path = getRelativePath(req); - - if (copyResource(req, resp)) { - deleteResource(path, req, resp, false); - } - - } - - - /** - * LOCK Method. - */ - protected void doLock(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - LockInfo lock = new LockInfo(); - - // Parsing lock request - - // Parsing depth header - - String depthStr = req.getHeader("Depth"); - - if (depthStr == null) { - lock.depth = INFINITY; - } else { - if (depthStr.equals("0")) { - lock.depth = 0; - } else { - lock.depth = INFINITY; - } - } - - // Parsing timeout header - - int lockDuration = DEFAULT_TIMEOUT; - String lockDurationStr = req.getHeader("Timeout"); - if (lockDurationStr == null) { - lockDuration = DEFAULT_TIMEOUT; - } else { - int commaPos = lockDurationStr.indexOf(","); - // If multiple timeouts, just use the first - if (commaPos != -1) { - lockDurationStr = lockDurationStr.substring(0,commaPos); - } - if (lockDurationStr.startsWith("Second-")) { - lockDuration = - (new Integer(lockDurationStr.substring(7))).intValue(); - } else { - if (lockDurationStr.equalsIgnoreCase("infinity")) { - lockDuration = MAX_TIMEOUT; - } else { - try { - lockDuration = - (new Integer(lockDurationStr)).intValue(); - } catch (NumberFormatException e) { - lockDuration = MAX_TIMEOUT; - } - } - } - if (lockDuration == 0) { - lockDuration = DEFAULT_TIMEOUT; - } - if (lockDuration > MAX_TIMEOUT) { - lockDuration = MAX_TIMEOUT; - } - } - lock.expiresAt = System.currentTimeMillis() + (lockDuration * 1000); - - int lockRequestType = LOCK_CREATION; - - Node lockInfoNode = null; - - DocumentBuilder documentBuilder = getDocumentBuilder(); - - try { - Document document = documentBuilder.parse(new InputSource - (req.getInputStream())); - - // Get the root element of the document - Element rootElement = document.getDocumentElement(); - lockInfoNode = rootElement; - } catch(Exception e) { - lockRequestType = LOCK_REFRESH; - } - - if (lockInfoNode != null) { - - // Reading lock information - - NodeList childList = lockInfoNode.getChildNodes(); - StringWriter strWriter = null; - DOMWriter domWriter = null; - - Node lockScopeNode = null; - Node lockTypeNode = null; - Node lockOwnerNode = null; - - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - break; - case Node.ELEMENT_NODE: - String nodeName = currentNode.getNodeName(); - if (nodeName.endsWith("lockscope")) { - lockScopeNode = currentNode; - } - if (nodeName.endsWith("locktype")) { - lockTypeNode = currentNode; - } - if (nodeName.endsWith("owner")) { - lockOwnerNode = currentNode; - } - break; - } - } - - if (lockScopeNode != null) { - - childList = lockScopeNode.getChildNodes(); - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - break; - case Node.ELEMENT_NODE: - String tempScope = currentNode.getNodeName(); - if (tempScope.indexOf(':') != -1) { - lock.scope = tempScope.substring - (tempScope.indexOf(':') + 1); - } else { - lock.scope = tempScope; - } - break; - } - } - - if (lock.scope == null) { - // Bad request - resp.setStatus(WebdavStatus.SC_BAD_REQUEST); - } - - } else { - // Bad request - resp.setStatus(WebdavStatus.SC_BAD_REQUEST); - } - - if (lockTypeNode != null) { - - childList = lockTypeNode.getChildNodes(); - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - break; - case Node.ELEMENT_NODE: - String tempType = currentNode.getNodeName(); - if (tempType.indexOf(':') != -1) { - lock.type = - tempType.substring(tempType.indexOf(':') + 1); - } else { - lock.type = tempType; - } - break; - } - } - - if (lock.type == null) { - // Bad request - resp.setStatus(WebdavStatus.SC_BAD_REQUEST); - } - - } else { - // Bad request - resp.setStatus(WebdavStatus.SC_BAD_REQUEST); - } - - if (lockOwnerNode != null) { - - childList = lockOwnerNode.getChildNodes(); - for (int i=0; i < childList.getLength(); i++) { - Node currentNode = childList.item(i); - switch (currentNode.getNodeType()) { - case Node.TEXT_NODE: - lock.owner += currentNode.getNodeValue(); - break; - case Node.ELEMENT_NODE: - strWriter = new StringWriter(); - domWriter = new DOMWriter(strWriter, true); - domWriter.setQualifiedNames(false); - domWriter.print(currentNode); - lock.owner += strWriter.toString(); - break; - } - } - - if (lock.owner == null) { - // Bad request - resp.setStatus(WebdavStatus.SC_BAD_REQUEST); - } - - } else { - lock.owner = new String(); - } - - } - - String path = getRelativePath(req); - - lock.path = path; - - boolean exists = true; - Object object = null; - try { - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - Enumeration locksList = null; - - if (lockRequestType == LOCK_CREATION) { - - // Generating lock id - String lockTokenStr = req.getServletPath() + "-" + lock.type + "-" - + lock.scope + "-" + req.getUserPrincipal() + "-" - + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-" - + lock.expiresAt + "-" + System.currentTimeMillis() + "-" - + secret; - String lockToken = - md5Encoder.encode(md5Helper.digest(lockTokenStr.getBytes())); - - if ( (exists) && (object instanceof DirContext) && - (lock.depth == INFINITY) ) { - - // Locking a collection (and all its member resources) - - // Checking if a child resource of this collection is - // already locked - Vector lockPaths = new Vector(); - locksList = collectionLocks.elements(); - while (locksList.hasMoreElements()) { - LockInfo currentLock = (LockInfo) locksList.nextElement(); - if (currentLock.hasExpired()) { - resourceLocks.remove(currentLock.path); - continue; - } - if ( (currentLock.path.startsWith(lock.path)) && - ((currentLock.isExclusive()) || - (lock.isExclusive())) ) { - // A child collection of this collection is locked - lockPaths.addElement(currentLock.path); - } - } - locksList = resourceLocks.elements(); - while (locksList.hasMoreElements()) { - LockInfo currentLock = (LockInfo) locksList.nextElement(); - if (currentLock.hasExpired()) { - resourceLocks.remove(currentLock.path); - continue; - } - if ( (currentLock.path.startsWith(lock.path)) && - ((currentLock.isExclusive()) || - (lock.isExclusive())) ) { - // A child resource of this collection is locked - lockPaths.addElement(currentLock.path); - } - } - - if (!lockPaths.isEmpty()) { - - // One of the child paths was locked - // We generate a multistatus error report - - Enumeration lockPathsList = lockPaths.elements(); - - resp.setStatus(WebdavStatus.SC_CONFLICT); - - XMLWriter generatedXML = new XMLWriter(); - generatedXML.writeXMLHeader(); - - generatedXML.writeElement - (null, "multistatus" + generateNamespaceDeclarations(), - XMLWriter.OPENING); - - while (lockPathsList.hasMoreElements()) { - generatedXML.writeElement(null, "response", - XMLWriter.OPENING); - generatedXML.writeElement(null, "href", - XMLWriter.OPENING); - generatedXML - .writeText((String) lockPathsList.nextElement()); - generatedXML.writeElement(null, "href", - XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", - XMLWriter.OPENING); - generatedXML - .writeText("HTTP/1.1 " + WebdavStatus.SC_LOCKED - + " " + WebdavStatus - .getStatusText(WebdavStatus.SC_LOCKED)); - generatedXML.writeElement(null, "status", - XMLWriter.CLOSING); - - generatedXML.writeElement(null, "response", - XMLWriter.CLOSING); - } - - generatedXML.writeElement(null, "multistatus", - XMLWriter.CLOSING); - - Writer writer = resp.getWriter(); - writer.write(generatedXML.toString()); - writer.close(); - - return; - - } - - boolean addLock = true; - - // Checking if there is already a shared lock on this path - locksList = collectionLocks.elements(); - while (locksList.hasMoreElements()) { - - LockInfo currentLock = (LockInfo) locksList.nextElement(); - if (currentLock.path.equals(lock.path)) { - - if (currentLock.isExclusive()) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } else { - if (lock.isExclusive()) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - } - - currentLock.tokens.addElement(lockToken); - lock = currentLock; - addLock = false; - - } - - } - - if (addLock) { - lock.tokens.addElement(lockToken); - collectionLocks.addElement(lock); - } - - } else { - - // Locking a single resource - - // Retrieving an already existing lock on that resource - LockInfo presentLock = (LockInfo) resourceLocks.get(lock.path); - if (presentLock != null) { - - if ((presentLock.isExclusive()) || (lock.isExclusive())) { - // If either lock is exclusive, the lock can't be - // granted - resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); - return; - } else { - presentLock.tokens.addElement(lockToken); - lock = presentLock; - } - - } else { - - lock.tokens.addElement(lockToken); - resourceLocks.put(lock.path, lock); - - // Checking if a resource exists at this path - exists = true; - try { - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - if (!exists) { - - // "Creating" a lock-null resource - int slash = lock.path.lastIndexOf('/'); - String parentPath = lock.path.substring(0, slash); - - Vector lockNulls = - (Vector) lockNullResources.get(parentPath); - if (lockNulls == null) { - lockNulls = new Vector(); - lockNullResources.put(parentPath, lockNulls); - } - - lockNulls.addElement(lock.path); - - } - // Add the Lock-Token header as by RFC 2518 8.10.1 - // - only do this for newly created locks - resp.addHeader("Lock-Token", ""); - } - - } - - } - - if (lockRequestType == LOCK_REFRESH) { - - String ifHeader = req.getHeader("If"); - if (ifHeader == null) - ifHeader = ""; - - // Checking resource locks - - LockInfo toRenew = (LockInfo) resourceLocks.get(path); - Enumeration tokenList = null; - if (lock != null) { - - // At least one of the tokens of the locks must have been given - - tokenList = toRenew.tokens.elements(); - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (ifHeader.indexOf(token) != -1) { - toRenew.expiresAt = lock.expiresAt; - lock = toRenew; - } - } - - } - - // Checking inheritable collection locks - - Enumeration collectionLocksList = collectionLocks.elements(); - while (collectionLocksList.hasMoreElements()) { - toRenew = (LockInfo) collectionLocksList.nextElement(); - if (path.equals(toRenew.path)) { - - tokenList = toRenew.tokens.elements(); - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (ifHeader.indexOf(token) != -1) { - toRenew.expiresAt = lock.expiresAt; - lock = toRenew; - } - } - - } - } - - } - - // Set the status, then generate the XML response containing - // the lock information - XMLWriter generatedXML = new XMLWriter(); - generatedXML.writeXMLHeader(); - generatedXML.writeElement(null, "prop" - + generateNamespaceDeclarations(), - XMLWriter.OPENING); - - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.OPENING); - - lock.toXML(generatedXML); - - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.CLOSING); - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - - resp.setStatus(WebdavStatus.SC_OK); - resp.setContentType("text/xml; charset=UTF-8"); - Writer writer = resp.getWriter(); - writer.write(generatedXML.toString()); - writer.close(); - - } - - - /** - * UNLOCK Method. - */ - protected void doUnlock(HttpServletRequest req, HttpServletResponse resp) - throws ServletException, IOException { - - if (readOnly) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return; - } - - if (isLocked(req)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return; - } - - String path = getRelativePath(req); - - String lockTokenHeader = req.getHeader("Lock-Token"); - if (lockTokenHeader == null) - lockTokenHeader = ""; - - // Checking resource locks - - LockInfo lock = (LockInfo) resourceLocks.get(path); - Enumeration tokenList = null; - if (lock != null) { - - // At least one of the tokens of the locks must have been given - - tokenList = lock.tokens.elements(); - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (lockTokenHeader.indexOf(token) != -1) { - lock.tokens.removeElement(token); - } - } - - if (lock.tokens.isEmpty()) { - resourceLocks.remove(path); - // Removing any lock-null resource which would be present - lockNullResources.remove(path); - } - - } - - // Checking inheritable collection locks - - Enumeration collectionLocksList = collectionLocks.elements(); - while (collectionLocksList.hasMoreElements()) { - lock = (LockInfo) collectionLocksList.nextElement(); - if (path.equals(lock.path)) { - - tokenList = lock.tokens.elements(); - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (lockTokenHeader.indexOf(token) != -1) { - lock.tokens.removeElement(token); - break; - } - } - - if (lock.tokens.isEmpty()) { - collectionLocks.removeElement(lock); - // Removing any lock-null resource which would be present - lockNullResources.remove(path); - } - - } - } - - resp.setStatus(WebdavStatus.SC_NO_CONTENT); - - } - - /** - * Return a context-relative path, beginning with a "/", that represents - * the canonical version of the specified path after ".." and "." elements - * are resolved out. If the specified path attempts to go outside the - * boundaries of the current context (i.e. too many ".." path elements - * are present), return null instead. - * - * @param path Path to be normalized - */ - protected String normalize(String path) { - - if (path == null) - return null; - - // Create a place for the normalized path - String normalized = path; - - if (normalized == null) - return (null); - - if (normalized.equals("/.")) - return "/"; - - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - if (!normalized.startsWith("/")) - normalized = "/" + normalized; - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - return (null); // Trying to go outside our context - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Return the normalized path that we have completed - return (normalized); - - } - - - // -------------------------------------------------------- Private Methods - - /** - * Generate the namespace declarations. - */ - private String generateNamespaceDeclarations() { - return " xmlns=\"" + DEFAULT_NAMESPACE + "\""; - } - - - /** - * Check to see if a resource is currently write locked. The method - * will look at the "If" header to make sure the client - * has give the appropriate lock tokens. - * - * @param req Servlet request - * @return boolean true if the resource is locked (and no appropriate - * lock token has been found for at least one of the non-shared locks which - * are present on the resource). - */ - private boolean isLocked(HttpServletRequest req) { - - String path = getRelativePath(req); - - String ifHeader = req.getHeader("If"); - if (ifHeader == null) - ifHeader = ""; - - String lockTokenHeader = req.getHeader("Lock-Token"); - if (lockTokenHeader == null) - lockTokenHeader = ""; - - return isLocked(path, ifHeader + lockTokenHeader); - - } - - - /** - * Check to see if a resource is currently write locked. - * - * @param path Path of the resource - * @param ifHeader "If" HTTP header which was included in the request - * @return boolean true if the resource is locked (and no appropriate - * lock token has been found for at least one of the non-shared locks which - * are present on the resource). - */ - private boolean isLocked(String path, String ifHeader) { - - // Checking resource locks - - LockInfo lock = (LockInfo) resourceLocks.get(path); - Enumeration tokenList = null; - if ((lock != null) && (lock.hasExpired())) { - resourceLocks.remove(path); - } else if (lock != null) { - - // At least one of the tokens of the locks must have been given - - tokenList = lock.tokens.elements(); - boolean tokenMatch = false; - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (ifHeader.indexOf(token) != -1) - tokenMatch = true; - } - if (!tokenMatch) - return true; - - } - - // Checking inheritable collection locks - - Enumeration collectionLocksList = collectionLocks.elements(); - while (collectionLocksList.hasMoreElements()) { - lock = (LockInfo) collectionLocksList.nextElement(); - if (lock.hasExpired()) { - collectionLocks.removeElement(lock); - } else if (path.startsWith(lock.path)) { - - tokenList = lock.tokens.elements(); - boolean tokenMatch = false; - while (tokenList.hasMoreElements()) { - String token = (String) tokenList.nextElement(); - if (ifHeader.indexOf(token) != -1) - tokenMatch = true; - } - if (!tokenMatch) - return true; - - } - } - - return false; - - } - - - /** - * Copy a resource. - * - * @param req Servlet request - * @param resp Servlet response - * @return boolean true if the copy is successful - */ - private boolean copyResource(HttpServletRequest req, - HttpServletResponse resp) - throws ServletException, IOException { - - // Parsing destination header - - String destinationPath = req.getHeader("Destination"); - - if (destinationPath == null) { - resp.sendError(WebdavStatus.SC_BAD_REQUEST); - return false; - } - - // Remove url encoding from destination - destinationPath = RequestUtil.URLDecode(destinationPath, "UTF8"); - - int protocolIndex = destinationPath.indexOf("://"); - if (protocolIndex >= 0) { - // if the Destination URL contains the protocol, we can safely - // trim everything upto the first "/" character after "://" - int firstSeparator = - destinationPath.indexOf("/", protocolIndex + 4); - if (firstSeparator < 0) { - destinationPath = "/"; - } else { - destinationPath = destinationPath.substring(firstSeparator); - } - } else { - String hostName = req.getServerName(); - if ((hostName != null) && (destinationPath.startsWith(hostName))) { - destinationPath = destinationPath.substring(hostName.length()); - } - - int portIndex = destinationPath.indexOf(":"); - if (portIndex >= 0) { - destinationPath = destinationPath.substring(portIndex); - } - - if (destinationPath.startsWith(":")) { - int firstSeparator = destinationPath.indexOf("/"); - if (firstSeparator < 0) { - destinationPath = "/"; - } else { - destinationPath = - destinationPath.substring(firstSeparator); - } - } - } - - // Normalise destination path (remove '.' and '..') - destinationPath = normalize(destinationPath); - - String contextPath = req.getContextPath(); - if ((contextPath != null) && - (destinationPath.startsWith(contextPath))) { - destinationPath = destinationPath.substring(contextPath.length()); - } - - String pathInfo = req.getPathInfo(); - if (pathInfo != null) { - String servletPath = req.getServletPath(); - if ((servletPath != null) && - (destinationPath.startsWith(servletPath))) { - destinationPath = destinationPath - .substring(servletPath.length()); - } - } - - if (debug > 0) - log("Dest path :" + destinationPath); - - if ((destinationPath.toUpperCase().startsWith("/WEB-INF")) || - (destinationPath.toUpperCase().startsWith("/META-INF"))) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return false; - } - - String path = getRelativePath(req); - - if ((path.toUpperCase().startsWith("/WEB-INF")) || - (path.toUpperCase().startsWith("/META-INF"))) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return false; - } - - if (destinationPath.equals(path)) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return false; - } - - // Parsing overwrite header - - boolean overwrite = true; - String overwriteHeader = req.getHeader("Overwrite"); - - if (overwriteHeader != null) { - if (overwriteHeader.equalsIgnoreCase("T")) { - overwrite = true; - } else { - overwrite = false; - } - } - - // Overwriting the destination - - boolean exists = true; - try { - resources.lookup(destinationPath); - } catch (NamingException e) { - exists = false; - } - - if (overwrite) { - - // Delete destination resource, if it exists - if (exists) { - if (!deleteResource(destinationPath, req, resp, true)) { - return false; - } - } else { - resp.setStatus(WebdavStatus.SC_CREATED); - } - - } else { - - // If the destination exists, then it's a conflict - if (exists) { - resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); - return false; - } - - } - - // Copying source to destination - - Hashtable errorList = new Hashtable(); - - boolean result = copyResource(resources, errorList, - path, destinationPath); - - if ((!result) || (!errorList.isEmpty())) { - - sendReport(req, resp, errorList); - return false; - - } - - // Removing any lock-null resource which would be present at - // the destination path - lockNullResources.remove(destinationPath); - - return true; - - } - - - /** - * Copy a collection. - * - * @param resources Resources implementation to be used - * @param errorList Hashtable containing the list of errors which occurred - * during the copy operation - * @param source Path of the resource to be copied - * @param dest Destination path - */ - private boolean copyResource(DirContext resources, Hashtable errorList, - String source, String dest) { - - if (debug > 1) - log("Copy: " + source + " To: " + dest); - - Object object = null; - try { - object = resources.lookup(source); - } catch (NamingException e) { - } - - if (object instanceof DirContext) { - - try { - resources.createSubcontext(dest); - } catch (NamingException e) { - errorList.put - (dest, new Integer(WebdavStatus.SC_CONFLICT)); - return false; - } - - try { - NamingEnumeration enumeration = resources.list(source); - while (enumeration.hasMoreElements()) { - NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); - String childDest = dest; - if (!childDest.equals("/")) - childDest += "/"; - childDest += ncPair.getName(); - String childSrc = source; - if (!childSrc.equals("/")) - childSrc += "/"; - childSrc += ncPair.getName(); - copyResource(resources, errorList, childSrc, childDest); - } - } catch (NamingException e) { - errorList.put - (dest, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - return false; - } - - } else { - - if (object instanceof Resource) { - try { - resources.bind(dest, object); - } catch (NamingException e) { - errorList.put - (source, - new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - return false; - } - } else { - errorList.put - (source, - new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - return false; - } - - } - - return true; - - } - - - /** - * Delete a resource. - * - * @param req Servlet request - * @param resp Servlet response - * @return boolean true if the copy is successful - */ - private boolean deleteResource(HttpServletRequest req, - HttpServletResponse resp) - throws ServletException, IOException { - - String path = getRelativePath(req); - - return deleteResource(path, req, resp, true); - - } - - - /** - * Delete a resource. - * - * @param path Path of the resource which is to be deleted - * @param req Servlet request - * @param resp Servlet response - * @param setStatus Should the response status be set on successful - * completion - */ - private boolean deleteResource(String path, HttpServletRequest req, - HttpServletResponse resp, boolean setStatus) - throws ServletException, IOException { - - if ((path.toUpperCase().startsWith("/WEB-INF")) || - (path.toUpperCase().startsWith("/META-INF"))) { - resp.sendError(WebdavStatus.SC_FORBIDDEN); - return false; - } - - String ifHeader = req.getHeader("If"); - if (ifHeader == null) - ifHeader = ""; - - String lockTokenHeader = req.getHeader("Lock-Token"); - if (lockTokenHeader == null) - lockTokenHeader = ""; - - if (isLocked(path, ifHeader + lockTokenHeader)) { - resp.sendError(WebdavStatus.SC_LOCKED); - return false; - } - - boolean exists = true; - Object object = null; - try { - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - if (!exists) { - resp.sendError(WebdavStatus.SC_NOT_FOUND); - return false; - } - - boolean collection = (object instanceof DirContext); - - if (!collection) { - try { - resources.unbind(path); - } catch (NamingException e) { - resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); - return false; - } - } else { - - Hashtable errorList = new Hashtable(); - - deleteCollection(req, resources, path, errorList); - try { - resources.unbind(path); - } catch (NamingException e) { - errorList.put(path, new Integer - (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - } - - if (!errorList.isEmpty()) { - - sendReport(req, resp, errorList); - return false; - - } - - } - if (setStatus) { - resp.setStatus(WebdavStatus.SC_NO_CONTENT); - } - return true; - - } - - - /** - * Deletes a collection. - * - * @param resources Resources implementation associated with the context - * @param path Path to the collection to be deleted - * @param errorList Contains the list of the errors which occurred - */ - private void deleteCollection(HttpServletRequest req, - DirContext resources, - String path, Hashtable errorList) { - - if (debug > 1) - log("Delete:" + path); - - if ((path.toUpperCase().startsWith("/WEB-INF")) || - (path.toUpperCase().startsWith("/META-INF"))) { - errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN)); - return; - } - - String ifHeader = req.getHeader("If"); - if (ifHeader == null) - ifHeader = ""; - - String lockTokenHeader = req.getHeader("Lock-Token"); - if (lockTokenHeader == null) - lockTokenHeader = ""; - - Enumeration enumeration = null; - try { - enumeration = resources.list(path); - } catch (NamingException e) { - errorList.put(path, new Integer - (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - return; - } - - while (enumeration.hasMoreElements()) { - NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); - String childName = path; - if (!childName.equals("/")) - childName += "/"; - childName += ncPair.getName(); - - if (isLocked(childName, ifHeader + lockTokenHeader)) { - - errorList.put(childName, new Integer(WebdavStatus.SC_LOCKED)); - - } else { - - try { - Object object = resources.lookup(childName); - if (object instanceof DirContext) { - deleteCollection(req, resources, childName, errorList); - } - - try { - resources.unbind(childName); - } catch (NamingException e) { - if (!(object instanceof DirContext)) { - // If it's not a collection, then it's an unknown - // error - errorList.put - (childName, new Integer - (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - } - } - } catch (NamingException e) { - errorList.put - (childName, new Integer - (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); - } - } - - } - - } - - - /** - * Send a multistatus element containing a complete error report to the - * client. - * - * @param req Servlet request - * @param resp Servlet response - * @param errorList List of error to be displayed - */ - private void sendReport(HttpServletRequest req, HttpServletResponse resp, - Hashtable errorList) - throws ServletException, IOException { - - resp.setStatus(WebdavStatus.SC_MULTI_STATUS); - - String absoluteUri = req.getRequestURI(); - String relativePath = getRelativePath(req); - - XMLWriter generatedXML = new XMLWriter(); - generatedXML.writeXMLHeader(); - - generatedXML.writeElement(null, "multistatus" - + generateNamespaceDeclarations(), - XMLWriter.OPENING); - - Enumeration pathList = errorList.keys(); - while (pathList.hasMoreElements()) { - - String errorPath = (String) pathList.nextElement(); - int errorCode = ((Integer) errorList.get(errorPath)).intValue(); - - generatedXML.writeElement(null, "response", XMLWriter.OPENING); - - generatedXML.writeElement(null, "href", XMLWriter.OPENING); - String toAppend = errorPath.substring(relativePath.length()); - if (!toAppend.startsWith("/")) - toAppend = "/" + toAppend; - generatedXML.writeText(absoluteUri + toAppend); - generatedXML.writeElement(null, "href", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML - .writeText("HTTP/1.1 " + errorCode + " " - + WebdavStatus.getStatusText(errorCode)); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "response", XMLWriter.CLOSING); - - } - - generatedXML.writeElement(null, "multistatus", XMLWriter.CLOSING); - - Writer writer = resp.getWriter(); - writer.write(generatedXML.toString()); - writer.close(); - - } - - - /** - * Propfind helper method. - * - * @param req The servlet request - * @param resources Resources object associated with this context - * @param generatedXML XML response to the Propfind request - * @param path Path of the current resource - * @param type Propfind type - * @param propertiesVector If the propfind type is find properties by - * name, then this Vector contains those properties - */ - private void parseProperties(HttpServletRequest req, - XMLWriter generatedXML, - String path, int type, - Vector propertiesVector) { - - // Exclude any resource in the /WEB-INF and /META-INF subdirectories - // (the "toUpperCase()" avoids problems on Windows systems) - if (path.toUpperCase().startsWith("/WEB-INF") || - path.toUpperCase().startsWith("/META-INF")) - return; - - CacheEntry cacheEntry = resources.lookupCache(path); - - generatedXML.writeElement(null, "response", XMLWriter.OPENING); - String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " " - + WebdavStatus.getStatusText - (WebdavStatus.SC_OK)); - - // Generating href element - generatedXML.writeElement(null, "href", XMLWriter.OPENING); - - String href = req.getContextPath() + req.getServletPath(); - if ((href.endsWith("/")) && (path.startsWith("/"))) - href += path.substring(1); - else - href += path; - if ((cacheEntry.context != null) && (!href.endsWith("/"))) - href += "/"; - - generatedXML.writeText(rewriteUrl(href)); - - generatedXML.writeElement(null, "href", XMLWriter.CLOSING); - - String resourceName = path; - int lastSlash = path.lastIndexOf('/'); - if (lastSlash != -1) - resourceName = resourceName.substring(lastSlash + 1); - - switch (type) { - - case FIND_ALL_PROP : - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - generatedXML.writeProperty - (null, "creationdate", - getISOCreationDate(cacheEntry.attributes.getCreation())); - generatedXML.writeElement(null, "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement(null, "displayname", XMLWriter.CLOSING); - if (cacheEntry.resource != null) { - generatedXML.writeProperty - (null, "getlastmodified", FastHttpDateFormat.formatDate - (cacheEntry.attributes.getLastModified(), null)); - generatedXML.writeProperty - (null, "getcontentlength", - String.valueOf(cacheEntry.attributes.getContentLength())); - String contentType = getServletContext().getMimeType - (cacheEntry.name); - if (contentType != null) { - generatedXML.writeProperty(null, "getcontenttype", - contentType); - } - generatedXML.writeProperty(null, "getetag", - getETag(cacheEntry.attributes)); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.NO_CONTENT); - } else { - generatedXML.writeElement(null, "resourcetype", - XMLWriter.OPENING); - generatedXML.writeElement(null, "collection", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.CLOSING); - } - - generatedXML.writeProperty(null, "source", ""); - - String supportedLocks = "" - + "" - + "" - + "" + "" - + "" - + "" - + ""; - generatedXML.writeElement(null, "supportedlock", - XMLWriter.OPENING); - generatedXML.writeText(supportedLocks); - generatedXML.writeElement(null, "supportedlock", - XMLWriter.CLOSING); - - generateLockDiscovery(path, generatedXML); - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - break; - - case FIND_PROPERTY_NAMES : - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - generatedXML.writeElement(null, "creationdate", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "displayname", - XMLWriter.NO_CONTENT); - if (cacheEntry.resource != null) { - generatedXML.writeElement(null, "getcontentlanguage", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getcontentlength", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getcontenttype", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getetag", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getlastmodified", - XMLWriter.NO_CONTENT); - } - generatedXML.writeElement(null, "resourcetype", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "source", XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.NO_CONTENT); - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - break; - - case FIND_BY_PROPERTY : - - Vector propertiesNotFound = new Vector(); - - // Parse the list of properties - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - Enumeration properties = propertiesVector.elements(); - - while (properties.hasMoreElements()) { - - String property = (String) properties.nextElement(); - - if (property.equals("creationdate")) { - generatedXML.writeProperty - (null, "creationdate", - getISOCreationDate(cacheEntry.attributes.getCreation())); - } else if (property.equals("displayname")) { - generatedXML.writeElement - (null, "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement - (null, "displayname", XMLWriter.CLOSING); - } else if (property.equals("getcontentlanguage")) { - if (cacheEntry.context != null) { - propertiesNotFound.addElement(property); - } else { - generatedXML.writeElement(null, "getcontentlanguage", - XMLWriter.NO_CONTENT); - } - } else if (property.equals("getcontentlength")) { - if (cacheEntry.context != null) { - propertiesNotFound.addElement(property); - } else { - generatedXML.writeProperty - (null, "getcontentlength", - (String.valueOf(cacheEntry.attributes.getContentLength()))); - } - } else if (property.equals("getcontenttype")) { - if (cacheEntry.context != null) { - propertiesNotFound.addElement(property); - } else { - generatedXML.writeProperty - (null, "getcontenttype", - getServletContext().getMimeType - (cacheEntry.name)); - } - } else if (property.equals("getetag")) { - if (cacheEntry.context != null) { - propertiesNotFound.addElement(property); - } else { - generatedXML.writeProperty - (null, "getetag", getETag(cacheEntry.attributes)); - } - } else if (property.equals("getlastmodified")) { - if (cacheEntry.context != null) { - propertiesNotFound.addElement(property); - } else { - generatedXML.writeProperty - (null, "getlastmodified", FastHttpDateFormat.formatDate - (cacheEntry.attributes.getLastModified(), null)); - } - } else if (property.equals("resourcetype")) { - if (cacheEntry.context != null) { - generatedXML.writeElement(null, "resourcetype", - XMLWriter.OPENING); - generatedXML.writeElement(null, "collection", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.CLOSING); - } else { - generatedXML.writeElement(null, "resourcetype", - XMLWriter.NO_CONTENT); - } - } else if (property.equals("source")) { - generatedXML.writeProperty(null, "source", ""); - } else if (property.equals("supportedlock")) { - supportedLocks = "" - + "" - + "" - + "" + "" - + "" - + "" - + ""; - generatedXML.writeElement(null, "supportedlock", - XMLWriter.OPENING); - generatedXML.writeText(supportedLocks); - generatedXML.writeElement(null, "supportedlock", - XMLWriter.CLOSING); - } else if (property.equals("lockdiscovery")) { - if (!generateLockDiscovery(path, generatedXML)) - propertiesNotFound.addElement(property); - } else { - propertiesNotFound.addElement(property); - } - - } - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - Enumeration propertiesNotFoundList = propertiesNotFound.elements(); - - if (propertiesNotFoundList.hasMoreElements()) { - - status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND - + " " + WebdavStatus.getStatusText - (WebdavStatus.SC_NOT_FOUND)); - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - while (propertiesNotFoundList.hasMoreElements()) { - generatedXML.writeElement - (null, (String) propertiesNotFoundList.nextElement(), - XMLWriter.NO_CONTENT); - } - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - } - - break; - - } - - generatedXML.writeElement(null, "response", XMLWriter.CLOSING); - - } - - - /** - * Propfind helper method. Dispays the properties of a lock-null resource. - * - * @param resources Resources object associated with this context - * @param generatedXML XML response to the Propfind request - * @param path Path of the current resource - * @param type Propfind type - * @param propertiesVector If the propfind type is find properties by - * name, then this Vector contains those properties - */ - private void parseLockNullProperties(HttpServletRequest req, - XMLWriter generatedXML, - String path, int type, - Vector propertiesVector) { - - // Exclude any resource in the /WEB-INF and /META-INF subdirectories - // (the "toUpperCase()" avoids problems on Windows systems) - if (path.toUpperCase().startsWith("/WEB-INF") || - path.toUpperCase().startsWith("/META-INF")) - return; - - // Retrieving the lock associated with the lock-null resource - LockInfo lock = (LockInfo) resourceLocks.get(path); - - if (lock == null) - return; - - generatedXML.writeElement(null, "response", XMLWriter.OPENING); - String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " " - + WebdavStatus.getStatusText - (WebdavStatus.SC_OK)); - - // Generating href element - generatedXML.writeElement(null, "href", XMLWriter.OPENING); - - String absoluteUri = req.getRequestURI(); - String relativePath = getRelativePath(req); - String toAppend = path.substring(relativePath.length()); - if (!toAppend.startsWith("/")) - toAppend = "/" + toAppend; - - generatedXML.writeText(rewriteUrl(normalize(absoluteUri + toAppend))); - - generatedXML.writeElement(null, "href", XMLWriter.CLOSING); - - String resourceName = path; - int lastSlash = path.lastIndexOf('/'); - if (lastSlash != -1) - resourceName = resourceName.substring(lastSlash + 1); - - switch (type) { - - case FIND_ALL_PROP : - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - generatedXML.writeProperty - (null, "creationdate", - getISOCreationDate(lock.creationDate.getTime())); - generatedXML.writeElement - (null, "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement - (null, "displayname", XMLWriter.CLOSING); - generatedXML.writeProperty(null, "getlastmodified", - FastHttpDateFormat.formatDate - (lock.creationDate.getTime(), null)); - generatedXML.writeProperty - (null, "getcontentlength", String.valueOf(0)); - generatedXML.writeProperty(null, "getcontenttype", ""); - generatedXML.writeProperty(null, "getetag", ""); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.OPENING); - generatedXML.writeElement(null, "lock-null", XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.CLOSING); - - generatedXML.writeProperty(null, "source", ""); - - String supportedLocks = "" - + "" - + "" - + "" + "" - + "" - + "" - + ""; - generatedXML.writeElement(null, "supportedlock", - XMLWriter.OPENING); - generatedXML.writeText(supportedLocks); - generatedXML.writeElement(null, "supportedlock", - XMLWriter.CLOSING); - - generateLockDiscovery(path, generatedXML); - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - break; - - case FIND_PROPERTY_NAMES : - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - generatedXML.writeElement(null, "creationdate", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "displayname", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getcontentlanguage", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getcontentlength", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getcontenttype", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getetag", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "getlastmodified", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "source", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.NO_CONTENT); - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - break; - - case FIND_BY_PROPERTY : - - Vector propertiesNotFound = new Vector(); - - // Parse the list of properties - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - Enumeration properties = propertiesVector.elements(); - - while (properties.hasMoreElements()) { - - String property = (String) properties.nextElement(); - - if (property.equals("creationdate")) { - generatedXML.writeProperty - (null, "creationdate", - getISOCreationDate(lock.creationDate.getTime())); - } else if (property.equals("displayname")) { - generatedXML.writeElement - (null, "displayname", XMLWriter.OPENING); - generatedXML.writeData(resourceName); - generatedXML.writeElement - (null, "displayname", XMLWriter.CLOSING); - } else if (property.equals("getcontentlanguage")) { - generatedXML.writeElement(null, "getcontentlanguage", - XMLWriter.NO_CONTENT); - } else if (property.equals("getcontentlength")) { - generatedXML.writeProperty - (null, "getcontentlength", (String.valueOf(0))); - } else if (property.equals("getcontenttype")) { - generatedXML.writeProperty - (null, "getcontenttype", ""); - } else if (property.equals("getetag")) { - generatedXML.writeProperty(null, "getetag", ""); - } else if (property.equals("getlastmodified")) { - generatedXML.writeProperty - (null, "getlastmodified", - FastHttpDateFormat.formatDate - (lock.creationDate.getTime(), null)); - } else if (property.equals("resourcetype")) { - generatedXML.writeElement(null, "resourcetype", - XMLWriter.OPENING); - generatedXML.writeElement(null, "lock-null", - XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "resourcetype", - XMLWriter.CLOSING); - } else if (property.equals("source")) { - generatedXML.writeProperty(null, "source", ""); - } else if (property.equals("supportedlock")) { - supportedLocks = "" - + "" - + "" - + "" + "" - + "" - + "" - + ""; - generatedXML.writeElement(null, "supportedlock", - XMLWriter.OPENING); - generatedXML.writeText(supportedLocks); - generatedXML.writeElement(null, "supportedlock", - XMLWriter.CLOSING); - } else if (property.equals("lockdiscovery")) { - if (!generateLockDiscovery(path, generatedXML)) - propertiesNotFound.addElement(property); - } else { - propertiesNotFound.addElement(property); - } - - } - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - Enumeration propertiesNotFoundList = propertiesNotFound.elements(); - - if (propertiesNotFoundList.hasMoreElements()) { - - status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND - + " " + WebdavStatus.getStatusText - (WebdavStatus.SC_NOT_FOUND)); - - generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); - generatedXML.writeElement(null, "prop", XMLWriter.OPENING); - - while (propertiesNotFoundList.hasMoreElements()) { - generatedXML.writeElement - (null, (String) propertiesNotFoundList.nextElement(), - XMLWriter.NO_CONTENT); - } - - generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); - generatedXML.writeElement(null, "status", XMLWriter.OPENING); - generatedXML.writeText(status); - generatedXML.writeElement(null, "status", XMLWriter.CLOSING); - generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); - - } - - break; - - } - - generatedXML.writeElement(null, "response", XMLWriter.CLOSING); - - } - - - /** - * Print the lock discovery information associated with a path. - * - * @param path Path - * @param generatedXML XML data to which the locks info will be appended - * @return true if at least one lock was displayed - */ - private boolean generateLockDiscovery - (String path, XMLWriter generatedXML) { - - LockInfo resourceLock = (LockInfo) resourceLocks.get(path); - Enumeration collectionLocksList = collectionLocks.elements(); - - boolean wroteStart = false; - - if (resourceLock != null) { - wroteStart = true; - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.OPENING); - resourceLock.toXML(generatedXML); - } - - while (collectionLocksList.hasMoreElements()) { - LockInfo currentLock = - (LockInfo) collectionLocksList.nextElement(); - if (path.startsWith(currentLock.path)) { - if (!wroteStart) { - wroteStart = true; - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.OPENING); - } - currentLock.toXML(generatedXML); - } - } - - if (wroteStart) { - generatedXML.writeElement(null, "lockdiscovery", - XMLWriter.CLOSING); - } else { - return false; - } - - return true; - - } - - - /** - * Get creation date in ISO format. - */ - private String getISOCreationDate(long creationDate) { - StringBuffer creationDateValue = new StringBuffer - (creationDateFormat.format - (new Date(creationDate))); - /* - int offset = Calendar.getInstance().getTimeZone().getRawOffset() - / 3600000; // FIXME ? - if (offset < 0) { - creationDateValue.append("-"); - offset = -offset; - } else if (offset > 0) { - creationDateValue.append("+"); - } - if (offset != 0) { - if (offset < 10) - creationDateValue.append("0"); - creationDateValue.append(offset + ":00"); - } else { - creationDateValue.append("Z"); - } - */ - return creationDateValue.toString(); - } - - /** - * Determines the methods normally allowed for the resource. - * - */ - private StringBuffer determineMethodsAllowed(DirContext resources, - HttpServletRequest req) { - - StringBuffer methodsAllowed = new StringBuffer(); - boolean exists = true; - Object object = null; - try { - String path = getRelativePath(req); - - object = resources.lookup(path); - } catch (NamingException e) { - exists = false; - } - - if (!exists) { - methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK"); - return methodsAllowed; - } - - methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE"); - methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK"); - - if (listings) { - methodsAllowed.append(", PROPFIND"); - } - - if (!(object instanceof DirContext)) { - methodsAllowed.append(", PUT"); - } - - return methodsAllowed; - } - - // -------------------------------------------------- LockInfo Inner Class - - - /** - * Holds a lock information. - */ - private class LockInfo { - - - // -------------------------------------------------------- Constructor - - - /** - * Constructor. - */ - public LockInfo() { - - } - - - // ------------------------------------------------- Instance Variables - - - String path = "/"; - String type = "write"; - String scope = "exclusive"; - int depth = 0; - String owner = ""; - Vector tokens = new Vector(); - long expiresAt = 0; - Date creationDate = new Date(); - - - // ----------------------------------------------------- Public Methods - - - /** - * Get a String representation of this lock token. - */ - public String toString() { - - String result = "Type:" + type + "\n"; - result += "Scope:" + scope + "\n"; - result += "Depth:" + depth + "\n"; - result += "Owner:" + owner + "\n"; - result += "Expiration:" - + FastHttpDateFormat.formatDate(expiresAt, null) + "\n"; - Enumeration tokensList = tokens.elements(); - while (tokensList.hasMoreElements()) { - result += "Token:" + tokensList.nextElement() + "\n"; - } - return result; - - } - - - /** - * Return true if the lock has expired. - */ - public boolean hasExpired() { - return (System.currentTimeMillis() > expiresAt); - } - - - /** - * Return true if the lock is exclusive. - */ - public boolean isExclusive() { - - return (scope.equals("exclusive")); - - } - - - /** - * Get an XML representation of this lock token. This method will - * append an XML fragment to the given XML writer. - */ - public void toXML(XMLWriter generatedXML) { - - generatedXML.writeElement(null, "activelock", XMLWriter.OPENING); - - generatedXML.writeElement(null, "locktype", XMLWriter.OPENING); - generatedXML.writeElement(null, type, XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "locktype", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "lockscope", XMLWriter.OPENING); - generatedXML.writeElement(null, scope, XMLWriter.NO_CONTENT); - generatedXML.writeElement(null, "lockscope", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "depth", XMLWriter.OPENING); - if (depth == INFINITY) { - generatedXML.writeText("Infinity"); - } else { - generatedXML.writeText("0"); - } - generatedXML.writeElement(null, "depth", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "owner", XMLWriter.OPENING); - generatedXML.writeText(owner); - generatedXML.writeElement(null, "owner", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "timeout", XMLWriter.OPENING); - long timeout = (expiresAt - System.currentTimeMillis()) / 1000; - generatedXML.writeText("Second-" + timeout); - generatedXML.writeElement(null, "timeout", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "locktoken", XMLWriter.OPENING); - Enumeration tokensList = tokens.elements(); - while (tokensList.hasMoreElements()) { - generatedXML.writeElement(null, "href", XMLWriter.OPENING); - generatedXML.writeText("opaquelocktoken:" - + tokensList.nextElement()); - generatedXML.writeElement(null, "href", XMLWriter.CLOSING); - } - generatedXML.writeElement(null, "locktoken", XMLWriter.CLOSING); - - generatedXML.writeElement(null, "activelock", XMLWriter.CLOSING); - - } - - - } - - - // --------------------------------------------------- Property Inner Class - - - private class Property { - - public String name; - public String value; - public String namespace; - public String namespaceAbbrev; - public int status = WebdavStatus.SC_OK; - - } - - -}; - - -// -------------------------------------------------------- WebdavStatus Class - - -/** - * Wraps the HttpServletResponse class to abstract the - * specific protocol used. To support other protocols - * we would only need to modify this class and the - * WebDavRetCode classes. - * - * @author Marc Eaddy - * @version 1.0, 16 Nov 1997 - */ -class WebdavStatus { - - - // ----------------------------------------------------- Instance Variables - - - /** - * This Hashtable contains the mapping of HTTP and WebDAV - * status codes to descriptive text. This is a static - * variable. - */ - private static Hashtable mapStatusCodes = new Hashtable(); - - - // ------------------------------------------------------ HTTP Status Codes - - - /** - * Status code (200) indicating the request succeeded normally. - */ - public static final int SC_OK = HttpServletResponse.SC_OK; - - - /** - * Status code (201) indicating the request succeeded and created - * a new resource on the server. - */ - public static final int SC_CREATED = HttpServletResponse.SC_CREATED; - - - /** - * Status code (202) indicating that a request was accepted for - * processing, but was not completed. - */ - public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED; - - - /** - * Status code (204) indicating that the request succeeded but that - * there was no new information to return. - */ - public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT; - - - /** - * Status code (301) indicating that the resource has permanently - * moved to a new location, and that future references should use a - * new URI with their requests. - */ - public static final int SC_MOVED_PERMANENTLY = - HttpServletResponse.SC_MOVED_PERMANENTLY; - - - /** - * Status code (302) indicating that the resource has temporarily - * moved to another location, but that future references should - * still use the original URI to access the resource. - */ - public static final int SC_MOVED_TEMPORARILY = - HttpServletResponse.SC_MOVED_TEMPORARILY; - - - /** - * Status code (304) indicating that a conditional GET operation - * found that the resource was available and not modified. - */ - public static final int SC_NOT_MODIFIED = - HttpServletResponse.SC_NOT_MODIFIED; - - - /** - * Status code (400) indicating the request sent by the client was - * syntactically incorrect. - */ - public static final int SC_BAD_REQUEST = - HttpServletResponse.SC_BAD_REQUEST; - - - /** - * Status code (401) indicating that the request requires HTTP - * authentication. - */ - public static final int SC_UNAUTHORIZED = - HttpServletResponse.SC_UNAUTHORIZED; - - - /** - * Status code (403) indicating the server understood the request - * but refused to fulfill it. - */ - public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN; - - - /** - * Status code (404) indicating that the requested resource is not - * available. - */ - public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND; - - - /** - * Status code (500) indicating an error inside the HTTP service - * which prevented it from fulfilling the request. - */ - public static final int SC_INTERNAL_SERVER_ERROR = - HttpServletResponse.SC_INTERNAL_SERVER_ERROR; - - - /** - * Status code (501) indicating the HTTP service does not support - * the functionality needed to fulfill the request. - */ - public static final int SC_NOT_IMPLEMENTED = - HttpServletResponse.SC_NOT_IMPLEMENTED; - - - /** - * Status code (502) indicating that the HTTP server received an - * invalid response from a server it consulted when acting as a - * proxy or gateway. - */ - public static final int SC_BAD_GATEWAY = - HttpServletResponse.SC_BAD_GATEWAY; - - - /** - * Status code (503) indicating that the HTTP service is - * temporarily overloaded, and unable to handle the request. - */ - public static final int SC_SERVICE_UNAVAILABLE = - HttpServletResponse.SC_SERVICE_UNAVAILABLE; - - - /** - * Status code (100) indicating the client may continue with - * its request. This interim response is used to inform the - * client that the initial part of the request has been - * received and has not yet been rejected by the server. - */ - public static final int SC_CONTINUE = 100; - - - /** - * Status code (405) indicating the method specified is not - * allowed for the resource. - */ - public static final int SC_METHOD_NOT_ALLOWED = 405; - - - /** - * Status code (409) indicating that the request could not be - * completed due to a conflict with the current state of the - * resource. - */ - public static final int SC_CONFLICT = 409; - - - /** - * Status code (412) indicating the precondition given in one - * or more of the request-header fields evaluated to false - * when it was tested on the server. - */ - public static final int SC_PRECONDITION_FAILED = 412; - - - /** - * Status code (413) indicating the server is refusing to - * process a request because the request entity is larger - * than the server is willing or able to process. - */ - public static final int SC_REQUEST_TOO_LONG = 413; - - - /** - * Status code (415) indicating the server is refusing to service - * the request because the entity of the request is in a format - * not supported by the requested resource for the requested - * method. - */ - public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; - - - // -------------------------------------------- Extended WebDav status code - - - /** - * Status code (207) indicating that the response requires - * providing status for multiple independent operations. - */ - public static final int SC_MULTI_STATUS = 207; - // This one colides with HTTP 1.1 - // "207 Parital Update OK" - - - /** - * Status code (418) indicating the entity body submitted with - * the PATCH method was not understood by the resource. - */ - public static final int SC_UNPROCESSABLE_ENTITY = 418; - // This one colides with HTTP 1.1 - // "418 Reauthentication Required" - - - /** - * Status code (419) indicating that the resource does not have - * sufficient space to record the state of the resource after the - * execution of this method. - */ - public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; - // This one colides with HTTP 1.1 - // "419 Proxy Reauthentication Required" - - - /** - * Status code (420) indicating the method was not executed on - * a particular resource within its scope because some part of - * the method's execution failed causing the entire method to be - * aborted. - */ - public static final int SC_METHOD_FAILURE = 420; - - - /** - * Status code (423) indicating the destination resource of a - * method is locked, and either the request did not contain a - * valid Lock-Info header, or the Lock-Info header identifies - * a lock held by another principal. - */ - public static final int SC_LOCKED = 423; - - - // ------------------------------------------------------------ Initializer - - - static { - // HTTP 1.0 tatus Code - addStatusCodeMap(SC_OK, "OK"); - addStatusCodeMap(SC_CREATED, "Created"); - addStatusCodeMap(SC_ACCEPTED, "Accepted"); - addStatusCodeMap(SC_NO_CONTENT, "No Content"); - addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently"); - addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily"); - addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified"); - addStatusCodeMap(SC_BAD_REQUEST, "Bad Request"); - addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized"); - addStatusCodeMap(SC_FORBIDDEN, "Forbidden"); - addStatusCodeMap(SC_NOT_FOUND, "Not Found"); - addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); - addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented"); - addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway"); - addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable"); - addStatusCodeMap(SC_CONTINUE, "Continue"); - addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed"); - addStatusCodeMap(SC_CONFLICT, "Conflict"); - addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed"); - addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long"); - addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"); - // WebDav Status Codes - addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status"); - addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity"); - addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE, - "Insufficient Space On Resource"); - addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure"); - addStatusCodeMap(SC_LOCKED, "Locked"); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Returns the HTTP status text for the HTTP or WebDav status code - * specified by looking it up in the static mapping. This is a - * static function. - * - * @param nHttpStatusCode [IN] HTTP or WebDAV status code - * @return A string with a short descriptive phrase for the - * HTTP status code (e.g., "OK"). - */ - public static String getStatusText(int nHttpStatusCode) { - Integer intKey = new Integer(nHttpStatusCode); - - if (!mapStatusCodes.containsKey(intKey)) { - return ""; - } else { - return (String) mapStatusCodes.get(intKey); - } - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Adds a new status code -> status text mapping. This is a static - * method because the mapping is a static variable. - * - * @param nKey [IN] HTTP or WebDAV status code - * @param strVal [IN] HTTP status text - */ - private static void addStatusCodeMap(int nKey, String strVal) { - mapStatusCodes.put(new Integer(nKey), strVal); - } - -}; - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.servlets; + + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Stack; +import java.util.TimeZone; +import java.util.Vector; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; +import javax.servlet.ServletException; +import javax.servlet.UnavailableException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.catalina.util.DOMWriter; +import org.apache.catalina.util.MD5Encoder; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.XMLWriter; +import org.apache.naming.resources.CacheEntry; +import org.apache.naming.resources.Resource; +import org.apache.naming.resources.ResourceAttributes; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + + +/** + * Servlet which adds support for WebDAV level 2. All the basic HTTP requests + * are handled by the DefaultServlet. + * + * @author Remy Maucherat + * @version $Revision: 303599 $ $Date: 2004-12-20 19:54:14 +0100 (lun., 20 déc. 2004) $ + */ + +public class WebdavServlet + extends DefaultServlet { + + + // -------------------------------------------------------------- Constants + + + private static final String METHOD_HEAD = "HEAD"; + private static final String METHOD_PROPFIND = "PROPFIND"; + private static final String METHOD_PROPPATCH = "PROPPATCH"; + private static final String METHOD_MKCOL = "MKCOL"; + private static final String METHOD_COPY = "COPY"; + private static final String METHOD_MOVE = "MOVE"; + private static final String METHOD_LOCK = "LOCK"; + private static final String METHOD_UNLOCK = "UNLOCK"; + + + /** + * Default depth is infite. + */ + private static final int INFINITY = 3; // To limit tree browsing a bit + + + /** + * PROPFIND - Specify a property mask. + */ + private static final int FIND_BY_PROPERTY = 0; + + + /** + * PROPFIND - Display all properties. + */ + private static final int FIND_ALL_PROP = 1; + + + /** + * PROPFIND - Return property names. + */ + private static final int FIND_PROPERTY_NAMES = 2; + + + /** + * Create a new lock. + */ + private static final int LOCK_CREATION = 0; + + + /** + * Refresh lock. + */ + private static final int LOCK_REFRESH = 1; + + + /** + * Default lock timeout value. + */ + private static final int DEFAULT_TIMEOUT = 3600; + + + /** + * Maximum lock timeout. + */ + private static final int MAX_TIMEOUT = 604800; + + + /** + * Default namespace. + */ + protected static final String DEFAULT_NAMESPACE = "DAV:"; + + + /** + * Simple date format for the creation date ISO representation (partial). + */ + protected static final SimpleDateFormat creationDateFormat = + new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); + + + /** + * MD5 message digest provider. + */ + protected static MessageDigest md5Helper; + + + /** + * The MD5 helper object for this class. + */ + protected static final MD5Encoder md5Encoder = new MD5Encoder(); + + + + static { + creationDateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Repository of the locks put on single resources. + *

    + * Key : path
    + * Value : LockInfo + */ + private Hashtable resourceLocks = new Hashtable(); + + + /** + * Repository of the lock-null resources. + *

    + * Key : path of the collection containing the lock-null resource
    + * Value : Vector of lock-null resource which are members of the + * collection. Each element of the Vector is the path associated with + * the lock-null resource. + */ + private Hashtable lockNullResources = new Hashtable(); + + + /** + * Vector of the heritable locks. + *

    + * Key : path
    + * Value : LockInfo + */ + private Vector collectionLocks = new Vector(); + + + /** + * Secret information used to generate reasonably secure lock ids. + */ + private String secret = "catalina"; + + + // --------------------------------------------------------- Public Methods + + + /** + * Initialize this servlet. + */ + public void init() + throws ServletException { + + super.init(); + + String value = null; + try { + value = getServletConfig().getInitParameter("secret"); + if (value != null) + secret = value; + } catch (Throwable t) { + ; + } + + + // Load the MD5 helper used to calculate signatures. + try { + md5Helper = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + throw new UnavailableException("No MD5"); + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return JAXP document builder instance. + */ + protected DocumentBuilder getDocumentBuilder() + throws ServletException { + DocumentBuilder documentBuilder = null; + DocumentBuilderFactory documentBuilderFactory = null; + try { + documentBuilderFactory = DocumentBuilderFactory.newInstance(); + documentBuilderFactory.setNamespaceAware(true); + documentBuilder = documentBuilderFactory.newDocumentBuilder(); + } catch(ParserConfigurationException e) { + throw new ServletException + (sm.getString("webdavservlet.jaxpfailed")); + } + return documentBuilder; + } + + + /** + * Handles the special WebDAV methods. + */ + protected void service(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + String method = req.getMethod(); + + if (debug > 0) { + String path = getRelativePath(req); + log("[" + method + "] " + path); + } + + if (method.equals(METHOD_PROPFIND)) { + doPropfind(req, resp); + } else if (method.equals(METHOD_PROPPATCH)) { + doProppatch(req, resp); + } else if (method.equals(METHOD_MKCOL)) { + doMkcol(req, resp); + } else if (method.equals(METHOD_COPY)) { + doCopy(req, resp); + } else if (method.equals(METHOD_MOVE)) { + doMove(req, resp); + } else if (method.equals(METHOD_LOCK)) { + doLock(req, resp); + } else if (method.equals(METHOD_UNLOCK)) { + doUnlock(req, resp); + } else { + // DefaultServlet processing + super.service(req, resp); + } + + } + + + /** + * Check if the conditions specified in the optional If headers are + * satisfied. + * + * @param request The servlet request we are processing + * @param response The servlet response we are creating + * @param resourceAttributes The resource information + * @return boolean true if the resource meets all the specified conditions, + * and false if any of the conditions is not satisfied, in which case + * request processing is stopped + */ + protected boolean checkIfHeaders(HttpServletRequest request, + HttpServletResponse response, + ResourceAttributes resourceAttributes) + throws IOException { + + if (!super.checkIfHeaders(request, response, resourceAttributes)) + return false; + + // TODO : Checking the WebDAV If header + return true; + + } + + + /** + * OPTIONS Method. + * + * @param req The request + * @param resp The response + * @throws ServletException If an error occurs + * @throws IOException If an IO error occurs + */ + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + resp.addHeader("DAV", "1,2"); + + StringBuffer methodsAllowed = determineMethodsAllowed(resources, + req); + + resp.addHeader("Allow", methodsAllowed.toString()); + resp.addHeader("MS-Author-Via", "DAV"); + + } + + + /** + * PROPFIND Method. + */ + protected void doPropfind(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (!listings) { + // Get allowed methods + StringBuffer methodsAllowed = determineMethodsAllowed(resources, + req); + + resp.addHeader("Allow", methodsAllowed.toString()); + resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); + return; + } + + String path = getRelativePath(req); + if (path.endsWith("/")) + path = path.substring(0, path.length() - 1); + + if ((path.toUpperCase().startsWith("/WEB-INF")) || + (path.toUpperCase().startsWith("/META-INF"))) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + // Properties which are to be displayed. + Vector properties = null; + // Propfind depth + int depth = INFINITY; + // Propfind type + int type = FIND_ALL_PROP; + + String depthStr = req.getHeader("Depth"); + + if (depthStr == null) { + depth = INFINITY; + } else { + if (depthStr.equals("0")) { + depth = 0; + } else if (depthStr.equals("1")) { + depth = 1; + } else if (depthStr.equals("infinity")) { + depth = INFINITY; + } + } + + Node propNode = null; + + DocumentBuilder documentBuilder = getDocumentBuilder(); + + try { + Document document = documentBuilder.parse + (new InputSource(req.getInputStream())); + + // Get the root element of the document + Element rootElement = document.getDocumentElement(); + NodeList childList = rootElement.getChildNodes(); + + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + if (currentNode.getNodeName().endsWith("prop")) { + type = FIND_BY_PROPERTY; + propNode = currentNode; + } + if (currentNode.getNodeName().endsWith("propname")) { + type = FIND_PROPERTY_NAMES; + } + if (currentNode.getNodeName().endsWith("allprop")) { + type = FIND_ALL_PROP; + } + break; + } + } + } catch(Exception e) { + // Most likely there was no content : we use the defaults. + // TODO : Enhance that ! + } + + if (type == FIND_BY_PROPERTY) { + properties = new Vector(); + NodeList childList = propNode.getChildNodes(); + + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + String nodeName = currentNode.getNodeName(); + String propertyName = null; + if (nodeName.indexOf(':') != -1) { + propertyName = nodeName.substring + (nodeName.indexOf(':') + 1); + } else { + propertyName = nodeName; + } + // href is a live property which is handled differently + properties.addElement(propertyName); + break; + } + } + + } + + boolean exists = true; + Object object = null; + try { + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + int slash = path.lastIndexOf('/'); + if (slash != -1) { + String parentPath = path.substring(0, slash); + Vector currentLockNullResources = + (Vector) lockNullResources.get(parentPath); + if (currentLockNullResources != null) { + Enumeration lockNullResourcesList = + currentLockNullResources.elements(); + while (lockNullResourcesList.hasMoreElements()) { + String lockNullPath = (String) + lockNullResourcesList.nextElement(); + if (lockNullPath.equals(path)) { + resp.setStatus(WebdavStatus.SC_MULTI_STATUS); + resp.setContentType("text/xml; charset=UTF-8"); + // Create multistatus object + XMLWriter generatedXML = + new XMLWriter(resp.getWriter()); + generatedXML.writeXMLHeader(); + generatedXML.writeElement + (null, "multistatus" + + generateNamespaceDeclarations(), + XMLWriter.OPENING); + parseLockNullProperties + (req, generatedXML, lockNullPath, type, + properties); + generatedXML.writeElement(null, "multistatus", + XMLWriter.CLOSING); + generatedXML.sendData(); + return; + } + } + } + } + } + + if (!exists) { + resp.sendError(HttpServletResponse.SC_NOT_FOUND, path); + return; + } + + resp.setStatus(WebdavStatus.SC_MULTI_STATUS); + + resp.setContentType("text/xml; charset=UTF-8"); + + // Create multistatus object + XMLWriter generatedXML = new XMLWriter(resp.getWriter()); + generatedXML.writeXMLHeader(); + + generatedXML.writeElement(null, "multistatus" + + generateNamespaceDeclarations(), + XMLWriter.OPENING); + + if (depth == 0) { + parseProperties(req, generatedXML, path, type, + properties); + } else { + // The stack always contains the object of the current level + Stack stack = new Stack(); + stack.push(path); + + // Stack of the objects one level below + Stack stackBelow = new Stack(); + + while ((!stack.isEmpty()) && (depth >= 0)) { + + String currentPath = (String) stack.pop(); + parseProperties(req, generatedXML, currentPath, + type, properties); + + try { + object = resources.lookup(currentPath); + } catch (NamingException e) { + continue; + } + + if ((object instanceof DirContext) && (depth > 0)) { + + try { + NamingEnumeration enumeration = resources.list(currentPath); + while (enumeration.hasMoreElements()) { + NameClassPair ncPair = + (NameClassPair) enumeration.nextElement(); + String newPath = currentPath; + if (!(newPath.endsWith("/"))) + newPath += "/"; + newPath += ncPair.getName(); + stackBelow.push(newPath); + } + } catch (NamingException e) { + resp.sendError + (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + path); + return; + } + + // Displaying the lock-null resources present in that + // collection + String lockPath = currentPath; + if (lockPath.endsWith("/")) + lockPath = + lockPath.substring(0, lockPath.length() - 1); + Vector currentLockNullResources = + (Vector) lockNullResources.get(lockPath); + if (currentLockNullResources != null) { + Enumeration lockNullResourcesList = + currentLockNullResources.elements(); + while (lockNullResourcesList.hasMoreElements()) { + String lockNullPath = (String) + lockNullResourcesList.nextElement(); + parseLockNullProperties + (req, generatedXML, lockNullPath, type, + properties); + } + } + + } + + if (stack.isEmpty()) { + depth--; + stack = stackBelow; + stackBelow = new Stack(); + } + + generatedXML.sendData(); + + } + } + + generatedXML.writeElement(null, "multistatus", + XMLWriter.CLOSING); + + generatedXML.sendData(); + + } + + + /** + * PROPPATCH Method. + */ + protected void doProppatch(HttpServletRequest req, + HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED); + + } + + + /** + * MKCOL Method. + */ + protected void doMkcol(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + String path = getRelativePath(req); + + if ((path.toUpperCase().startsWith("/WEB-INF")) || + (path.toUpperCase().startsWith("/META-INF"))) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + boolean exists = true; + Object object = null; + try { + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + // Can't create a collection if a resource already exists at the given + // path + if (exists) { + // Get allowed methods + StringBuffer methodsAllowed = determineMethodsAllowed(resources, + req); + + resp.addHeader("Allow", methodsAllowed.toString()); + + resp.sendError(WebdavStatus.SC_METHOD_NOT_ALLOWED); + return; + } + + if (req.getInputStream().available() > 0) { + DocumentBuilder documentBuilder = getDocumentBuilder(); + try { + Document document = documentBuilder.parse + (new InputSource(req.getInputStream())); + // TODO : Process this request body + resp.sendError(WebdavStatus.SC_NOT_IMPLEMENTED); + return; + + } catch(SAXException saxe) { + // Parse error - assume invalid content + resp.sendError(WebdavStatus.SC_BAD_REQUEST); + return; + } + } + + boolean result = true; + try { + resources.createSubcontext(path); + } catch (NamingException e) { + result = false; + } + + if (!result) { + resp.sendError(WebdavStatus.SC_CONFLICT, + WebdavStatus.getStatusText + (WebdavStatus.SC_CONFLICT)); + } else { + resp.setStatus(WebdavStatus.SC_CREATED); + // Removing any lock-null resource which would be present + lockNullResources.remove(path); + } + + } + + + /** + * DELETE Method. + */ + protected void doDelete(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + deleteResource(req, resp); + + } + + + /** + * Process a POST request for the specified resource. + * + * @param req The servlet request we are processing + * @param resp The servlet response we are creating + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet-specified error occurs + */ + protected void doPut(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + super.doPut(req, resp); + + String path = getRelativePath(req); + + // Removing any lock-null resource which would be present + lockNullResources.remove(path); + + } + + /** + * COPY Method. + */ + protected void doCopy(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + copyResource(req, resp); + + } + + + /** + * MOVE Method. + */ + protected void doMove(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + String path = getRelativePath(req); + + if (copyResource(req, resp)) { + deleteResource(path, req, resp, false); + } + + } + + + /** + * LOCK Method. + */ + protected void doLock(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + LockInfo lock = new LockInfo(); + + // Parsing lock request + + // Parsing depth header + + String depthStr = req.getHeader("Depth"); + + if (depthStr == null) { + lock.depth = INFINITY; + } else { + if (depthStr.equals("0")) { + lock.depth = 0; + } else { + lock.depth = INFINITY; + } + } + + // Parsing timeout header + + int lockDuration = DEFAULT_TIMEOUT; + String lockDurationStr = req.getHeader("Timeout"); + if (lockDurationStr == null) { + lockDuration = DEFAULT_TIMEOUT; + } else { + int commaPos = lockDurationStr.indexOf(","); + // If multiple timeouts, just use the first + if (commaPos != -1) { + lockDurationStr = lockDurationStr.substring(0,commaPos); + } + if (lockDurationStr.startsWith("Second-")) { + lockDuration = + (new Integer(lockDurationStr.substring(7))).intValue(); + } else { + if (lockDurationStr.equalsIgnoreCase("infinity")) { + lockDuration = MAX_TIMEOUT; + } else { + try { + lockDuration = + (new Integer(lockDurationStr)).intValue(); + } catch (NumberFormatException e) { + lockDuration = MAX_TIMEOUT; + } + } + } + if (lockDuration == 0) { + lockDuration = DEFAULT_TIMEOUT; + } + if (lockDuration > MAX_TIMEOUT) { + lockDuration = MAX_TIMEOUT; + } + } + lock.expiresAt = System.currentTimeMillis() + (lockDuration * 1000); + + int lockRequestType = LOCK_CREATION; + + Node lockInfoNode = null; + + DocumentBuilder documentBuilder = getDocumentBuilder(); + + try { + Document document = documentBuilder.parse(new InputSource + (req.getInputStream())); + + // Get the root element of the document + Element rootElement = document.getDocumentElement(); + lockInfoNode = rootElement; + } catch(Exception e) { + lockRequestType = LOCK_REFRESH; + } + + if (lockInfoNode != null) { + + // Reading lock information + + NodeList childList = lockInfoNode.getChildNodes(); + StringWriter strWriter = null; + DOMWriter domWriter = null; + + Node lockScopeNode = null; + Node lockTypeNode = null; + Node lockOwnerNode = null; + + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + String nodeName = currentNode.getNodeName(); + if (nodeName.endsWith("lockscope")) { + lockScopeNode = currentNode; + } + if (nodeName.endsWith("locktype")) { + lockTypeNode = currentNode; + } + if (nodeName.endsWith("owner")) { + lockOwnerNode = currentNode; + } + break; + } + } + + if (lockScopeNode != null) { + + childList = lockScopeNode.getChildNodes(); + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + String tempScope = currentNode.getNodeName(); + if (tempScope.indexOf(':') != -1) { + lock.scope = tempScope.substring + (tempScope.indexOf(':') + 1); + } else { + lock.scope = tempScope; + } + break; + } + } + + if (lock.scope == null) { + // Bad request + resp.setStatus(WebdavStatus.SC_BAD_REQUEST); + } + + } else { + // Bad request + resp.setStatus(WebdavStatus.SC_BAD_REQUEST); + } + + if (lockTypeNode != null) { + + childList = lockTypeNode.getChildNodes(); + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + break; + case Node.ELEMENT_NODE: + String tempType = currentNode.getNodeName(); + if (tempType.indexOf(':') != -1) { + lock.type = + tempType.substring(tempType.indexOf(':') + 1); + } else { + lock.type = tempType; + } + break; + } + } + + if (lock.type == null) { + // Bad request + resp.setStatus(WebdavStatus.SC_BAD_REQUEST); + } + + } else { + // Bad request + resp.setStatus(WebdavStatus.SC_BAD_REQUEST); + } + + if (lockOwnerNode != null) { + + childList = lockOwnerNode.getChildNodes(); + for (int i=0; i < childList.getLength(); i++) { + Node currentNode = childList.item(i); + switch (currentNode.getNodeType()) { + case Node.TEXT_NODE: + lock.owner += currentNode.getNodeValue(); + break; + case Node.ELEMENT_NODE: + strWriter = new StringWriter(); + domWriter = new DOMWriter(strWriter, true); + domWriter.setQualifiedNames(false); + domWriter.print(currentNode); + lock.owner += strWriter.toString(); + break; + } + } + + if (lock.owner == null) { + // Bad request + resp.setStatus(WebdavStatus.SC_BAD_REQUEST); + } + + } else { + lock.owner = new String(); + } + + } + + String path = getRelativePath(req); + + lock.path = path; + + boolean exists = true; + Object object = null; + try { + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + Enumeration locksList = null; + + if (lockRequestType == LOCK_CREATION) { + + // Generating lock id + String lockTokenStr = req.getServletPath() + "-" + lock.type + "-" + + lock.scope + "-" + req.getUserPrincipal() + "-" + + lock.depth + "-" + lock.owner + "-" + lock.tokens + "-" + + lock.expiresAt + "-" + System.currentTimeMillis() + "-" + + secret; + String lockToken = + md5Encoder.encode(md5Helper.digest(lockTokenStr.getBytes())); + + if ( (exists) && (object instanceof DirContext) && + (lock.depth == INFINITY) ) { + + // Locking a collection (and all its member resources) + + // Checking if a child resource of this collection is + // already locked + Vector lockPaths = new Vector(); + locksList = collectionLocks.elements(); + while (locksList.hasMoreElements()) { + LockInfo currentLock = (LockInfo) locksList.nextElement(); + if (currentLock.hasExpired()) { + resourceLocks.remove(currentLock.path); + continue; + } + if ( (currentLock.path.startsWith(lock.path)) && + ((currentLock.isExclusive()) || + (lock.isExclusive())) ) { + // A child collection of this collection is locked + lockPaths.addElement(currentLock.path); + } + } + locksList = resourceLocks.elements(); + while (locksList.hasMoreElements()) { + LockInfo currentLock = (LockInfo) locksList.nextElement(); + if (currentLock.hasExpired()) { + resourceLocks.remove(currentLock.path); + continue; + } + if ( (currentLock.path.startsWith(lock.path)) && + ((currentLock.isExclusive()) || + (lock.isExclusive())) ) { + // A child resource of this collection is locked + lockPaths.addElement(currentLock.path); + } + } + + if (!lockPaths.isEmpty()) { + + // One of the child paths was locked + // We generate a multistatus error report + + Enumeration lockPathsList = lockPaths.elements(); + + resp.setStatus(WebdavStatus.SC_CONFLICT); + + XMLWriter generatedXML = new XMLWriter(); + generatedXML.writeXMLHeader(); + + generatedXML.writeElement + (null, "multistatus" + generateNamespaceDeclarations(), + XMLWriter.OPENING); + + while (lockPathsList.hasMoreElements()) { + generatedXML.writeElement(null, "response", + XMLWriter.OPENING); + generatedXML.writeElement(null, "href", + XMLWriter.OPENING); + generatedXML + .writeText((String) lockPathsList.nextElement()); + generatedXML.writeElement(null, "href", + XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", + XMLWriter.OPENING); + generatedXML + .writeText("HTTP/1.1 " + WebdavStatus.SC_LOCKED + + " " + WebdavStatus + .getStatusText(WebdavStatus.SC_LOCKED)); + generatedXML.writeElement(null, "status", + XMLWriter.CLOSING); + + generatedXML.writeElement(null, "response", + XMLWriter.CLOSING); + } + + generatedXML.writeElement(null, "multistatus", + XMLWriter.CLOSING); + + Writer writer = resp.getWriter(); + writer.write(generatedXML.toString()); + writer.close(); + + return; + + } + + boolean addLock = true; + + // Checking if there is already a shared lock on this path + locksList = collectionLocks.elements(); + while (locksList.hasMoreElements()) { + + LockInfo currentLock = (LockInfo) locksList.nextElement(); + if (currentLock.path.equals(lock.path)) { + + if (currentLock.isExclusive()) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } else { + if (lock.isExclusive()) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + } + + currentLock.tokens.addElement(lockToken); + lock = currentLock; + addLock = false; + + } + + } + + if (addLock) { + lock.tokens.addElement(lockToken); + collectionLocks.addElement(lock); + } + + } else { + + // Locking a single resource + + // Retrieving an already existing lock on that resource + LockInfo presentLock = (LockInfo) resourceLocks.get(lock.path); + if (presentLock != null) { + + if ((presentLock.isExclusive()) || (lock.isExclusive())) { + // If either lock is exclusive, the lock can't be + // granted + resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); + return; + } else { + presentLock.tokens.addElement(lockToken); + lock = presentLock; + } + + } else { + + lock.tokens.addElement(lockToken); + resourceLocks.put(lock.path, lock); + + // Checking if a resource exists at this path + exists = true; + try { + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + if (!exists) { + + // "Creating" a lock-null resource + int slash = lock.path.lastIndexOf('/'); + String parentPath = lock.path.substring(0, slash); + + Vector lockNulls = + (Vector) lockNullResources.get(parentPath); + if (lockNulls == null) { + lockNulls = new Vector(); + lockNullResources.put(parentPath, lockNulls); + } + + lockNulls.addElement(lock.path); + + } + // Add the Lock-Token header as by RFC 2518 8.10.1 + // - only do this for newly created locks + resp.addHeader("Lock-Token", ""); + } + + } + + } + + if (lockRequestType == LOCK_REFRESH) { + + String ifHeader = req.getHeader("If"); + if (ifHeader == null) + ifHeader = ""; + + // Checking resource locks + + LockInfo toRenew = (LockInfo) resourceLocks.get(path); + Enumeration tokenList = null; + if (lock != null) { + + // At least one of the tokens of the locks must have been given + + tokenList = toRenew.tokens.elements(); + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (ifHeader.indexOf(token) != -1) { + toRenew.expiresAt = lock.expiresAt; + lock = toRenew; + } + } + + } + + // Checking inheritable collection locks + + Enumeration collectionLocksList = collectionLocks.elements(); + while (collectionLocksList.hasMoreElements()) { + toRenew = (LockInfo) collectionLocksList.nextElement(); + if (path.equals(toRenew.path)) { + + tokenList = toRenew.tokens.elements(); + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (ifHeader.indexOf(token) != -1) { + toRenew.expiresAt = lock.expiresAt; + lock = toRenew; + } + } + + } + } + + } + + // Set the status, then generate the XML response containing + // the lock information + XMLWriter generatedXML = new XMLWriter(); + generatedXML.writeXMLHeader(); + generatedXML.writeElement(null, "prop" + + generateNamespaceDeclarations(), + XMLWriter.OPENING); + + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.OPENING); + + lock.toXML(generatedXML); + + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.CLOSING); + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + + resp.setStatus(WebdavStatus.SC_OK); + resp.setContentType("text/xml; charset=UTF-8"); + Writer writer = resp.getWriter(); + writer.write(generatedXML.toString()); + writer.close(); + + } + + + /** + * UNLOCK Method. + */ + protected void doUnlock(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + + if (readOnly) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return; + } + + if (isLocked(req)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return; + } + + String path = getRelativePath(req); + + String lockTokenHeader = req.getHeader("Lock-Token"); + if (lockTokenHeader == null) + lockTokenHeader = ""; + + // Checking resource locks + + LockInfo lock = (LockInfo) resourceLocks.get(path); + Enumeration tokenList = null; + if (lock != null) { + + // At least one of the tokens of the locks must have been given + + tokenList = lock.tokens.elements(); + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (lockTokenHeader.indexOf(token) != -1) { + lock.tokens.removeElement(token); + } + } + + if (lock.tokens.isEmpty()) { + resourceLocks.remove(path); + // Removing any lock-null resource which would be present + lockNullResources.remove(path); + } + + } + + // Checking inheritable collection locks + + Enumeration collectionLocksList = collectionLocks.elements(); + while (collectionLocksList.hasMoreElements()) { + lock = (LockInfo) collectionLocksList.nextElement(); + if (path.equals(lock.path)) { + + tokenList = lock.tokens.elements(); + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (lockTokenHeader.indexOf(token) != -1) { + lock.tokens.removeElement(token); + break; + } + } + + if (lock.tokens.isEmpty()) { + collectionLocks.removeElement(lock); + // Removing any lock-null resource which would be present + lockNullResources.remove(path); + } + + } + } + + resp.setStatus(WebdavStatus.SC_NO_CONTENT); + + } + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements + * are present), return null instead. + * + * @param path Path to be normalized + */ + protected String normalize(String path) { + + if (path == null) + return null; + + // Create a place for the normalized path + String normalized = path; + + if (normalized == null) + return (null); + + if (normalized.equals("/.")) + return "/"; + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + return (null); // Trying to go outside our context + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Return the normalized path that we have completed + return (normalized); + + } + + + // -------------------------------------------------------- Private Methods + + /** + * Generate the namespace declarations. + */ + private String generateNamespaceDeclarations() { + return " xmlns=\"" + DEFAULT_NAMESPACE + "\""; + } + + + /** + * Check to see if a resource is currently write locked. The method + * will look at the "If" header to make sure the client + * has give the appropriate lock tokens. + * + * @param req Servlet request + * @return boolean true if the resource is locked (and no appropriate + * lock token has been found for at least one of the non-shared locks which + * are present on the resource). + */ + private boolean isLocked(HttpServletRequest req) { + + String path = getRelativePath(req); + + String ifHeader = req.getHeader("If"); + if (ifHeader == null) + ifHeader = ""; + + String lockTokenHeader = req.getHeader("Lock-Token"); + if (lockTokenHeader == null) + lockTokenHeader = ""; + + return isLocked(path, ifHeader + lockTokenHeader); + + } + + + /** + * Check to see if a resource is currently write locked. + * + * @param path Path of the resource + * @param ifHeader "If" HTTP header which was included in the request + * @return boolean true if the resource is locked (and no appropriate + * lock token has been found for at least one of the non-shared locks which + * are present on the resource). + */ + private boolean isLocked(String path, String ifHeader) { + + // Checking resource locks + + LockInfo lock = (LockInfo) resourceLocks.get(path); + Enumeration tokenList = null; + if ((lock != null) && (lock.hasExpired())) { + resourceLocks.remove(path); + } else if (lock != null) { + + // At least one of the tokens of the locks must have been given + + tokenList = lock.tokens.elements(); + boolean tokenMatch = false; + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (ifHeader.indexOf(token) != -1) + tokenMatch = true; + } + if (!tokenMatch) + return true; + + } + + // Checking inheritable collection locks + + Enumeration collectionLocksList = collectionLocks.elements(); + while (collectionLocksList.hasMoreElements()) { + lock = (LockInfo) collectionLocksList.nextElement(); + if (lock.hasExpired()) { + collectionLocks.removeElement(lock); + } else if (path.startsWith(lock.path)) { + + tokenList = lock.tokens.elements(); + boolean tokenMatch = false; + while (tokenList.hasMoreElements()) { + String token = (String) tokenList.nextElement(); + if (ifHeader.indexOf(token) != -1) + tokenMatch = true; + } + if (!tokenMatch) + return true; + + } + } + + return false; + + } + + + /** + * Copy a resource. + * + * @param req Servlet request + * @param resp Servlet response + * @return boolean true if the copy is successful + */ + private boolean copyResource(HttpServletRequest req, + HttpServletResponse resp) + throws ServletException, IOException { + + // Parsing destination header + + String destinationPath = req.getHeader("Destination"); + + if (destinationPath == null) { + resp.sendError(WebdavStatus.SC_BAD_REQUEST); + return false; + } + + // Remove url encoding from destination + destinationPath = RequestUtil.URLDecode(destinationPath, "UTF8"); + + int protocolIndex = destinationPath.indexOf("://"); + if (protocolIndex >= 0) { + // if the Destination URL contains the protocol, we can safely + // trim everything upto the first "/" character after "://" + int firstSeparator = + destinationPath.indexOf("/", protocolIndex + 4); + if (firstSeparator < 0) { + destinationPath = "/"; + } else { + destinationPath = destinationPath.substring(firstSeparator); + } + } else { + String hostName = req.getServerName(); + if ((hostName != null) && (destinationPath.startsWith(hostName))) { + destinationPath = destinationPath.substring(hostName.length()); + } + + int portIndex = destinationPath.indexOf(":"); + if (portIndex >= 0) { + destinationPath = destinationPath.substring(portIndex); + } + + if (destinationPath.startsWith(":")) { + int firstSeparator = destinationPath.indexOf("/"); + if (firstSeparator < 0) { + destinationPath = "/"; + } else { + destinationPath = + destinationPath.substring(firstSeparator); + } + } + } + + // Normalise destination path (remove '.' and '..') + destinationPath = normalize(destinationPath); + + String contextPath = req.getContextPath(); + if ((contextPath != null) && + (destinationPath.startsWith(contextPath))) { + destinationPath = destinationPath.substring(contextPath.length()); + } + + String pathInfo = req.getPathInfo(); + if (pathInfo != null) { + String servletPath = req.getServletPath(); + if ((servletPath != null) && + (destinationPath.startsWith(servletPath))) { + destinationPath = destinationPath + .substring(servletPath.length()); + } + } + + if (debug > 0) + log("Dest path :" + destinationPath); + + if ((destinationPath.toUpperCase().startsWith("/WEB-INF")) || + (destinationPath.toUpperCase().startsWith("/META-INF"))) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return false; + } + + String path = getRelativePath(req); + + if ((path.toUpperCase().startsWith("/WEB-INF")) || + (path.toUpperCase().startsWith("/META-INF"))) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return false; + } + + if (destinationPath.equals(path)) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return false; + } + + // Parsing overwrite header + + boolean overwrite = true; + String overwriteHeader = req.getHeader("Overwrite"); + + if (overwriteHeader != null) { + if (overwriteHeader.equalsIgnoreCase("T")) { + overwrite = true; + } else { + overwrite = false; + } + } + + // Overwriting the destination + + boolean exists = true; + try { + resources.lookup(destinationPath); + } catch (NamingException e) { + exists = false; + } + + if (overwrite) { + + // Delete destination resource, if it exists + if (exists) { + if (!deleteResource(destinationPath, req, resp, true)) { + return false; + } + } else { + resp.setStatus(WebdavStatus.SC_CREATED); + } + + } else { + + // If the destination exists, then it's a conflict + if (exists) { + resp.sendError(WebdavStatus.SC_PRECONDITION_FAILED); + return false; + } + + } + + // Copying source to destination + + Hashtable errorList = new Hashtable(); + + boolean result = copyResource(resources, errorList, + path, destinationPath); + + if ((!result) || (!errorList.isEmpty())) { + + sendReport(req, resp, errorList); + return false; + + } + + // Removing any lock-null resource which would be present at + // the destination path + lockNullResources.remove(destinationPath); + + return true; + + } + + + /** + * Copy a collection. + * + * @param resources Resources implementation to be used + * @param errorList Hashtable containing the list of errors which occurred + * during the copy operation + * @param source Path of the resource to be copied + * @param dest Destination path + */ + private boolean copyResource(DirContext resources, Hashtable errorList, + String source, String dest) { + + if (debug > 1) + log("Copy: " + source + " To: " + dest); + + Object object = null; + try { + object = resources.lookup(source); + } catch (NamingException e) { + } + + if (object instanceof DirContext) { + + try { + resources.createSubcontext(dest); + } catch (NamingException e) { + errorList.put + (dest, new Integer(WebdavStatus.SC_CONFLICT)); + return false; + } + + try { + NamingEnumeration enumeration = resources.list(source); + while (enumeration.hasMoreElements()) { + NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); + String childDest = dest; + if (!childDest.equals("/")) + childDest += "/"; + childDest += ncPair.getName(); + String childSrc = source; + if (!childSrc.equals("/")) + childSrc += "/"; + childSrc += ncPair.getName(); + copyResource(resources, errorList, childSrc, childDest); + } + } catch (NamingException e) { + errorList.put + (dest, new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + return false; + } + + } else { + + if (object instanceof Resource) { + try { + resources.bind(dest, object); + } catch (NamingException e) { + errorList.put + (source, + new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + return false; + } + } else { + errorList.put + (source, + new Integer(WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + return false; + } + + } + + return true; + + } + + + /** + * Delete a resource. + * + * @param req Servlet request + * @param resp Servlet response + * @return boolean true if the copy is successful + */ + private boolean deleteResource(HttpServletRequest req, + HttpServletResponse resp) + throws ServletException, IOException { + + String path = getRelativePath(req); + + return deleteResource(path, req, resp, true); + + } + + + /** + * Delete a resource. + * + * @param path Path of the resource which is to be deleted + * @param req Servlet request + * @param resp Servlet response + * @param setStatus Should the response status be set on successful + * completion + */ + private boolean deleteResource(String path, HttpServletRequest req, + HttpServletResponse resp, boolean setStatus) + throws ServletException, IOException { + + if ((path.toUpperCase().startsWith("/WEB-INF")) || + (path.toUpperCase().startsWith("/META-INF"))) { + resp.sendError(WebdavStatus.SC_FORBIDDEN); + return false; + } + + String ifHeader = req.getHeader("If"); + if (ifHeader == null) + ifHeader = ""; + + String lockTokenHeader = req.getHeader("Lock-Token"); + if (lockTokenHeader == null) + lockTokenHeader = ""; + + if (isLocked(path, ifHeader + lockTokenHeader)) { + resp.sendError(WebdavStatus.SC_LOCKED); + return false; + } + + boolean exists = true; + Object object = null; + try { + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + if (!exists) { + resp.sendError(WebdavStatus.SC_NOT_FOUND); + return false; + } + + boolean collection = (object instanceof DirContext); + + if (!collection) { + try { + resources.unbind(path); + } catch (NamingException e) { + resp.sendError(WebdavStatus.SC_INTERNAL_SERVER_ERROR); + return false; + } + } else { + + Hashtable errorList = new Hashtable(); + + deleteCollection(req, resources, path, errorList); + try { + resources.unbind(path); + } catch (NamingException e) { + errorList.put(path, new Integer + (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + } + + if (!errorList.isEmpty()) { + + sendReport(req, resp, errorList); + return false; + + } + + } + if (setStatus) { + resp.setStatus(WebdavStatus.SC_NO_CONTENT); + } + return true; + + } + + + /** + * Deletes a collection. + * + * @param resources Resources implementation associated with the context + * @param path Path to the collection to be deleted + * @param errorList Contains the list of the errors which occurred + */ + private void deleteCollection(HttpServletRequest req, + DirContext resources, + String path, Hashtable errorList) { + + if (debug > 1) + log("Delete:" + path); + + if ((path.toUpperCase().startsWith("/WEB-INF")) || + (path.toUpperCase().startsWith("/META-INF"))) { + errorList.put(path, new Integer(WebdavStatus.SC_FORBIDDEN)); + return; + } + + String ifHeader = req.getHeader("If"); + if (ifHeader == null) + ifHeader = ""; + + String lockTokenHeader = req.getHeader("Lock-Token"); + if (lockTokenHeader == null) + lockTokenHeader = ""; + + Enumeration enumeration = null; + try { + enumeration = resources.list(path); + } catch (NamingException e) { + errorList.put(path, new Integer + (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + return; + } + + while (enumeration.hasMoreElements()) { + NameClassPair ncPair = (NameClassPair) enumeration.nextElement(); + String childName = path; + if (!childName.equals("/")) + childName += "/"; + childName += ncPair.getName(); + + if (isLocked(childName, ifHeader + lockTokenHeader)) { + + errorList.put(childName, new Integer(WebdavStatus.SC_LOCKED)); + + } else { + + try { + Object object = resources.lookup(childName); + if (object instanceof DirContext) { + deleteCollection(req, resources, childName, errorList); + } + + try { + resources.unbind(childName); + } catch (NamingException e) { + if (!(object instanceof DirContext)) { + // If it's not a collection, then it's an unknown + // error + errorList.put + (childName, new Integer + (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + } + } + } catch (NamingException e) { + errorList.put + (childName, new Integer + (WebdavStatus.SC_INTERNAL_SERVER_ERROR)); + } + } + + } + + } + + + /** + * Send a multistatus element containing a complete error report to the + * client. + * + * @param req Servlet request + * @param resp Servlet response + * @param errorList List of error to be displayed + */ + private void sendReport(HttpServletRequest req, HttpServletResponse resp, + Hashtable errorList) + throws ServletException, IOException { + + resp.setStatus(WebdavStatus.SC_MULTI_STATUS); + + String absoluteUri = req.getRequestURI(); + String relativePath = getRelativePath(req); + + XMLWriter generatedXML = new XMLWriter(); + generatedXML.writeXMLHeader(); + + generatedXML.writeElement(null, "multistatus" + + generateNamespaceDeclarations(), + XMLWriter.OPENING); + + Enumeration pathList = errorList.keys(); + while (pathList.hasMoreElements()) { + + String errorPath = (String) pathList.nextElement(); + int errorCode = ((Integer) errorList.get(errorPath)).intValue(); + + generatedXML.writeElement(null, "response", XMLWriter.OPENING); + + generatedXML.writeElement(null, "href", XMLWriter.OPENING); + String toAppend = errorPath.substring(relativePath.length()); + if (!toAppend.startsWith("/")) + toAppend = "/" + toAppend; + generatedXML.writeText(absoluteUri + toAppend); + generatedXML.writeElement(null, "href", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML + .writeText("HTTP/1.1 " + errorCode + " " + + WebdavStatus.getStatusText(errorCode)); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "response", XMLWriter.CLOSING); + + } + + generatedXML.writeElement(null, "multistatus", XMLWriter.CLOSING); + + Writer writer = resp.getWriter(); + writer.write(generatedXML.toString()); + writer.close(); + + } + + + /** + * Propfind helper method. + * + * @param req The servlet request + * @param resources Resources object associated with this context + * @param generatedXML XML response to the Propfind request + * @param path Path of the current resource + * @param type Propfind type + * @param propertiesVector If the propfind type is find properties by + * name, then this Vector contains those properties + */ + private void parseProperties(HttpServletRequest req, + XMLWriter generatedXML, + String path, int type, + Vector propertiesVector) { + + // Exclude any resource in the /WEB-INF and /META-INF subdirectories + // (the "toUpperCase()" avoids problems on Windows systems) + if (path.toUpperCase().startsWith("/WEB-INF") || + path.toUpperCase().startsWith("/META-INF")) + return; + + CacheEntry cacheEntry = resources.lookupCache(path); + + generatedXML.writeElement(null, "response", XMLWriter.OPENING); + String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " " + + WebdavStatus.getStatusText + (WebdavStatus.SC_OK)); + + // Generating href element + generatedXML.writeElement(null, "href", XMLWriter.OPENING); + + String href = req.getContextPath() + req.getServletPath(); + if ((href.endsWith("/")) && (path.startsWith("/"))) + href += path.substring(1); + else + href += path; + if ((cacheEntry.context != null) && (!href.endsWith("/"))) + href += "/"; + + generatedXML.writeText(rewriteUrl(href)); + + generatedXML.writeElement(null, "href", XMLWriter.CLOSING); + + String resourceName = path; + int lastSlash = path.lastIndexOf('/'); + if (lastSlash != -1) + resourceName = resourceName.substring(lastSlash + 1); + + switch (type) { + + case FIND_ALL_PROP : + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + generatedXML.writeProperty + (null, "creationdate", + getISOCreationDate(cacheEntry.attributes.getCreation())); + generatedXML.writeElement(null, "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement(null, "displayname", XMLWriter.CLOSING); + if (cacheEntry.resource != null) { + generatedXML.writeProperty + (null, "getlastmodified", FastHttpDateFormat.formatDate + (cacheEntry.attributes.getLastModified(), null)); + generatedXML.writeProperty + (null, "getcontentlength", + String.valueOf(cacheEntry.attributes.getContentLength())); + String contentType = getServletContext().getMimeType + (cacheEntry.name); + if (contentType != null) { + generatedXML.writeProperty(null, "getcontenttype", + contentType); + } + generatedXML.writeProperty(null, "getetag", + getETag(cacheEntry.attributes)); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.NO_CONTENT); + } else { + generatedXML.writeElement(null, "resourcetype", + XMLWriter.OPENING); + generatedXML.writeElement(null, "collection", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.CLOSING); + } + + generatedXML.writeProperty(null, "source", ""); + + String supportedLocks = "" + + "" + + "" + + "" + "" + + "" + + "" + + ""; + generatedXML.writeElement(null, "supportedlock", + XMLWriter.OPENING); + generatedXML.writeText(supportedLocks); + generatedXML.writeElement(null, "supportedlock", + XMLWriter.CLOSING); + + generateLockDiscovery(path, generatedXML); + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + break; + + case FIND_PROPERTY_NAMES : + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + generatedXML.writeElement(null, "creationdate", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "displayname", + XMLWriter.NO_CONTENT); + if (cacheEntry.resource != null) { + generatedXML.writeElement(null, "getcontentlanguage", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getcontentlength", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getcontenttype", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getetag", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getlastmodified", + XMLWriter.NO_CONTENT); + } + generatedXML.writeElement(null, "resourcetype", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "source", XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.NO_CONTENT); + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + break; + + case FIND_BY_PROPERTY : + + Vector propertiesNotFound = new Vector(); + + // Parse the list of properties + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + Enumeration properties = propertiesVector.elements(); + + while (properties.hasMoreElements()) { + + String property = (String) properties.nextElement(); + + if (property.equals("creationdate")) { + generatedXML.writeProperty + (null, "creationdate", + getISOCreationDate(cacheEntry.attributes.getCreation())); + } else if (property.equals("displayname")) { + generatedXML.writeElement + (null, "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement + (null, "displayname", XMLWriter.CLOSING); + } else if (property.equals("getcontentlanguage")) { + if (cacheEntry.context != null) { + propertiesNotFound.addElement(property); + } else { + generatedXML.writeElement(null, "getcontentlanguage", + XMLWriter.NO_CONTENT); + } + } else if (property.equals("getcontentlength")) { + if (cacheEntry.context != null) { + propertiesNotFound.addElement(property); + } else { + generatedXML.writeProperty + (null, "getcontentlength", + (String.valueOf(cacheEntry.attributes.getContentLength()))); + } + } else if (property.equals("getcontenttype")) { + if (cacheEntry.context != null) { + propertiesNotFound.addElement(property); + } else { + generatedXML.writeProperty + (null, "getcontenttype", + getServletContext().getMimeType + (cacheEntry.name)); + } + } else if (property.equals("getetag")) { + if (cacheEntry.context != null) { + propertiesNotFound.addElement(property); + } else { + generatedXML.writeProperty + (null, "getetag", getETag(cacheEntry.attributes)); + } + } else if (property.equals("getlastmodified")) { + if (cacheEntry.context != null) { + propertiesNotFound.addElement(property); + } else { + generatedXML.writeProperty + (null, "getlastmodified", FastHttpDateFormat.formatDate + (cacheEntry.attributes.getLastModified(), null)); + } + } else if (property.equals("resourcetype")) { + if (cacheEntry.context != null) { + generatedXML.writeElement(null, "resourcetype", + XMLWriter.OPENING); + generatedXML.writeElement(null, "collection", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.CLOSING); + } else { + generatedXML.writeElement(null, "resourcetype", + XMLWriter.NO_CONTENT); + } + } else if (property.equals("source")) { + generatedXML.writeProperty(null, "source", ""); + } else if (property.equals("supportedlock")) { + supportedLocks = "" + + "" + + "" + + "" + "" + + "" + + "" + + ""; + generatedXML.writeElement(null, "supportedlock", + XMLWriter.OPENING); + generatedXML.writeText(supportedLocks); + generatedXML.writeElement(null, "supportedlock", + XMLWriter.CLOSING); + } else if (property.equals("lockdiscovery")) { + if (!generateLockDiscovery(path, generatedXML)) + propertiesNotFound.addElement(property); + } else { + propertiesNotFound.addElement(property); + } + + } + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + Enumeration propertiesNotFoundList = propertiesNotFound.elements(); + + if (propertiesNotFoundList.hasMoreElements()) { + + status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND + + " " + WebdavStatus.getStatusText + (WebdavStatus.SC_NOT_FOUND)); + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + while (propertiesNotFoundList.hasMoreElements()) { + generatedXML.writeElement + (null, (String) propertiesNotFoundList.nextElement(), + XMLWriter.NO_CONTENT); + } + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + } + + break; + + } + + generatedXML.writeElement(null, "response", XMLWriter.CLOSING); + + } + + + /** + * Propfind helper method. Dispays the properties of a lock-null resource. + * + * @param resources Resources object associated with this context + * @param generatedXML XML response to the Propfind request + * @param path Path of the current resource + * @param type Propfind type + * @param propertiesVector If the propfind type is find properties by + * name, then this Vector contains those properties + */ + private void parseLockNullProperties(HttpServletRequest req, + XMLWriter generatedXML, + String path, int type, + Vector propertiesVector) { + + // Exclude any resource in the /WEB-INF and /META-INF subdirectories + // (the "toUpperCase()" avoids problems on Windows systems) + if (path.toUpperCase().startsWith("/WEB-INF") || + path.toUpperCase().startsWith("/META-INF")) + return; + + // Retrieving the lock associated with the lock-null resource + LockInfo lock = (LockInfo) resourceLocks.get(path); + + if (lock == null) + return; + + generatedXML.writeElement(null, "response", XMLWriter.OPENING); + String status = new String("HTTP/1.1 " + WebdavStatus.SC_OK + " " + + WebdavStatus.getStatusText + (WebdavStatus.SC_OK)); + + // Generating href element + generatedXML.writeElement(null, "href", XMLWriter.OPENING); + + String absoluteUri = req.getRequestURI(); + String relativePath = getRelativePath(req); + String toAppend = path.substring(relativePath.length()); + if (!toAppend.startsWith("/")) + toAppend = "/" + toAppend; + + generatedXML.writeText(rewriteUrl(normalize(absoluteUri + toAppend))); + + generatedXML.writeElement(null, "href", XMLWriter.CLOSING); + + String resourceName = path; + int lastSlash = path.lastIndexOf('/'); + if (lastSlash != -1) + resourceName = resourceName.substring(lastSlash + 1); + + switch (type) { + + case FIND_ALL_PROP : + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + generatedXML.writeProperty + (null, "creationdate", + getISOCreationDate(lock.creationDate.getTime())); + generatedXML.writeElement + (null, "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement + (null, "displayname", XMLWriter.CLOSING); + generatedXML.writeProperty(null, "getlastmodified", + FastHttpDateFormat.formatDate + (lock.creationDate.getTime(), null)); + generatedXML.writeProperty + (null, "getcontentlength", String.valueOf(0)); + generatedXML.writeProperty(null, "getcontenttype", ""); + generatedXML.writeProperty(null, "getetag", ""); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.OPENING); + generatedXML.writeElement(null, "lock-null", XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.CLOSING); + + generatedXML.writeProperty(null, "source", ""); + + String supportedLocks = "" + + "" + + "" + + "" + "" + + "" + + "" + + ""; + generatedXML.writeElement(null, "supportedlock", + XMLWriter.OPENING); + generatedXML.writeText(supportedLocks); + generatedXML.writeElement(null, "supportedlock", + XMLWriter.CLOSING); + + generateLockDiscovery(path, generatedXML); + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + break; + + case FIND_PROPERTY_NAMES : + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + generatedXML.writeElement(null, "creationdate", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "displayname", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getcontentlanguage", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getcontentlength", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getcontenttype", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getetag", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "getlastmodified", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "source", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.NO_CONTENT); + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + break; + + case FIND_BY_PROPERTY : + + Vector propertiesNotFound = new Vector(); + + // Parse the list of properties + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + Enumeration properties = propertiesVector.elements(); + + while (properties.hasMoreElements()) { + + String property = (String) properties.nextElement(); + + if (property.equals("creationdate")) { + generatedXML.writeProperty + (null, "creationdate", + getISOCreationDate(lock.creationDate.getTime())); + } else if (property.equals("displayname")) { + generatedXML.writeElement + (null, "displayname", XMLWriter.OPENING); + generatedXML.writeData(resourceName); + generatedXML.writeElement + (null, "displayname", XMLWriter.CLOSING); + } else if (property.equals("getcontentlanguage")) { + generatedXML.writeElement(null, "getcontentlanguage", + XMLWriter.NO_CONTENT); + } else if (property.equals("getcontentlength")) { + generatedXML.writeProperty + (null, "getcontentlength", (String.valueOf(0))); + } else if (property.equals("getcontenttype")) { + generatedXML.writeProperty + (null, "getcontenttype", ""); + } else if (property.equals("getetag")) { + generatedXML.writeProperty(null, "getetag", ""); + } else if (property.equals("getlastmodified")) { + generatedXML.writeProperty + (null, "getlastmodified", + FastHttpDateFormat.formatDate + (lock.creationDate.getTime(), null)); + } else if (property.equals("resourcetype")) { + generatedXML.writeElement(null, "resourcetype", + XMLWriter.OPENING); + generatedXML.writeElement(null, "lock-null", + XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "resourcetype", + XMLWriter.CLOSING); + } else if (property.equals("source")) { + generatedXML.writeProperty(null, "source", ""); + } else if (property.equals("supportedlock")) { + supportedLocks = "" + + "" + + "" + + "" + "" + + "" + + "" + + ""; + generatedXML.writeElement(null, "supportedlock", + XMLWriter.OPENING); + generatedXML.writeText(supportedLocks); + generatedXML.writeElement(null, "supportedlock", + XMLWriter.CLOSING); + } else if (property.equals("lockdiscovery")) { + if (!generateLockDiscovery(path, generatedXML)) + propertiesNotFound.addElement(property); + } else { + propertiesNotFound.addElement(property); + } + + } + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + Enumeration propertiesNotFoundList = propertiesNotFound.elements(); + + if (propertiesNotFoundList.hasMoreElements()) { + + status = new String("HTTP/1.1 " + WebdavStatus.SC_NOT_FOUND + + " " + WebdavStatus.getStatusText + (WebdavStatus.SC_NOT_FOUND)); + + generatedXML.writeElement(null, "propstat", XMLWriter.OPENING); + generatedXML.writeElement(null, "prop", XMLWriter.OPENING); + + while (propertiesNotFoundList.hasMoreElements()) { + generatedXML.writeElement + (null, (String) propertiesNotFoundList.nextElement(), + XMLWriter.NO_CONTENT); + } + + generatedXML.writeElement(null, "prop", XMLWriter.CLOSING); + generatedXML.writeElement(null, "status", XMLWriter.OPENING); + generatedXML.writeText(status); + generatedXML.writeElement(null, "status", XMLWriter.CLOSING); + generatedXML.writeElement(null, "propstat", XMLWriter.CLOSING); + + } + + break; + + } + + generatedXML.writeElement(null, "response", XMLWriter.CLOSING); + + } + + + /** + * Print the lock discovery information associated with a path. + * + * @param path Path + * @param generatedXML XML data to which the locks info will be appended + * @return true if at least one lock was displayed + */ + private boolean generateLockDiscovery + (String path, XMLWriter generatedXML) { + + LockInfo resourceLock = (LockInfo) resourceLocks.get(path); + Enumeration collectionLocksList = collectionLocks.elements(); + + boolean wroteStart = false; + + if (resourceLock != null) { + wroteStart = true; + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.OPENING); + resourceLock.toXML(generatedXML); + } + + while (collectionLocksList.hasMoreElements()) { + LockInfo currentLock = + (LockInfo) collectionLocksList.nextElement(); + if (path.startsWith(currentLock.path)) { + if (!wroteStart) { + wroteStart = true; + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.OPENING); + } + currentLock.toXML(generatedXML); + } + } + + if (wroteStart) { + generatedXML.writeElement(null, "lockdiscovery", + XMLWriter.CLOSING); + } else { + return false; + } + + return true; + + } + + + /** + * Get creation date in ISO format. + */ + private String getISOCreationDate(long creationDate) { + StringBuffer creationDateValue = new StringBuffer + (creationDateFormat.format + (new Date(creationDate))); + /* + int offset = Calendar.getInstance().getTimeZone().getRawOffset() + / 3600000; // FIXME ? + if (offset < 0) { + creationDateValue.append("-"); + offset = -offset; + } else if (offset > 0) { + creationDateValue.append("+"); + } + if (offset != 0) { + if (offset < 10) + creationDateValue.append("0"); + creationDateValue.append(offset + ":00"); + } else { + creationDateValue.append("Z"); + } + */ + return creationDateValue.toString(); + } + + /** + * Determines the methods normally allowed for the resource. + * + */ + private StringBuffer determineMethodsAllowed(DirContext resources, + HttpServletRequest req) { + + StringBuffer methodsAllowed = new StringBuffer(); + boolean exists = true; + Object object = null; + try { + String path = getRelativePath(req); + + object = resources.lookup(path); + } catch (NamingException e) { + exists = false; + } + + if (!exists) { + methodsAllowed.append("OPTIONS, MKCOL, PUT, LOCK"); + return methodsAllowed; + } + + methodsAllowed.append("OPTIONS, GET, HEAD, POST, DELETE, TRACE"); + methodsAllowed.append(", PROPPATCH, COPY, MOVE, LOCK, UNLOCK"); + + if (listings) { + methodsAllowed.append(", PROPFIND"); + } + + if (!(object instanceof DirContext)) { + methodsAllowed.append(", PUT"); + } + + return methodsAllowed; + } + + // -------------------------------------------------- LockInfo Inner Class + + + /** + * Holds a lock information. + */ + private class LockInfo { + + + // -------------------------------------------------------- Constructor + + + /** + * Constructor. + */ + public LockInfo() { + + } + + + // ------------------------------------------------- Instance Variables + + + String path = "/"; + String type = "write"; + String scope = "exclusive"; + int depth = 0; + String owner = ""; + Vector tokens = new Vector(); + long expiresAt = 0; + Date creationDate = new Date(); + + + // ----------------------------------------------------- Public Methods + + + /** + * Get a String representation of this lock token. + */ + public String toString() { + + String result = "Type:" + type + "\n"; + result += "Scope:" + scope + "\n"; + result += "Depth:" + depth + "\n"; + result += "Owner:" + owner + "\n"; + result += "Expiration:" + + FastHttpDateFormat.formatDate(expiresAt, null) + "\n"; + Enumeration tokensList = tokens.elements(); + while (tokensList.hasMoreElements()) { + result += "Token:" + tokensList.nextElement() + "\n"; + } + return result; + + } + + + /** + * Return true if the lock has expired. + */ + public boolean hasExpired() { + return (System.currentTimeMillis() > expiresAt); + } + + + /** + * Return true if the lock is exclusive. + */ + public boolean isExclusive() { + + return (scope.equals("exclusive")); + + } + + + /** + * Get an XML representation of this lock token. This method will + * append an XML fragment to the given XML writer. + */ + public void toXML(XMLWriter generatedXML) { + + generatedXML.writeElement(null, "activelock", XMLWriter.OPENING); + + generatedXML.writeElement(null, "locktype", XMLWriter.OPENING); + generatedXML.writeElement(null, type, XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "locktype", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "lockscope", XMLWriter.OPENING); + generatedXML.writeElement(null, scope, XMLWriter.NO_CONTENT); + generatedXML.writeElement(null, "lockscope", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "depth", XMLWriter.OPENING); + if (depth == INFINITY) { + generatedXML.writeText("Infinity"); + } else { + generatedXML.writeText("0"); + } + generatedXML.writeElement(null, "depth", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "owner", XMLWriter.OPENING); + generatedXML.writeText(owner); + generatedXML.writeElement(null, "owner", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "timeout", XMLWriter.OPENING); + long timeout = (expiresAt - System.currentTimeMillis()) / 1000; + generatedXML.writeText("Second-" + timeout); + generatedXML.writeElement(null, "timeout", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "locktoken", XMLWriter.OPENING); + Enumeration tokensList = tokens.elements(); + while (tokensList.hasMoreElements()) { + generatedXML.writeElement(null, "href", XMLWriter.OPENING); + generatedXML.writeText("opaquelocktoken:" + + tokensList.nextElement()); + generatedXML.writeElement(null, "href", XMLWriter.CLOSING); + } + generatedXML.writeElement(null, "locktoken", XMLWriter.CLOSING); + + generatedXML.writeElement(null, "activelock", XMLWriter.CLOSING); + + } + + + } + + + // --------------------------------------------------- Property Inner Class + + + private class Property { + + public String name; + public String value; + public String namespace; + public String namespaceAbbrev; + public int status = WebdavStatus.SC_OK; + + } + + +}; + + +// -------------------------------------------------------- WebdavStatus Class + + +/** + * Wraps the HttpServletResponse class to abstract the + * specific protocol used. To support other protocols + * we would only need to modify this class and the + * WebDavRetCode classes. + * + * @author Marc Eaddy + * @version 1.0, 16 Nov 1997 + */ +class WebdavStatus { + + + // ----------------------------------------------------- Instance Variables + + + /** + * This Hashtable contains the mapping of HTTP and WebDAV + * status codes to descriptive text. This is a static + * variable. + */ + private static Hashtable mapStatusCodes = new Hashtable(); + + + // ------------------------------------------------------ HTTP Status Codes + + + /** + * Status code (200) indicating the request succeeded normally. + */ + public static final int SC_OK = HttpServletResponse.SC_OK; + + + /** + * Status code (201) indicating the request succeeded and created + * a new resource on the server. + */ + public static final int SC_CREATED = HttpServletResponse.SC_CREATED; + + + /** + * Status code (202) indicating that a request was accepted for + * processing, but was not completed. + */ + public static final int SC_ACCEPTED = HttpServletResponse.SC_ACCEPTED; + + + /** + * Status code (204) indicating that the request succeeded but that + * there was no new information to return. + */ + public static final int SC_NO_CONTENT = HttpServletResponse.SC_NO_CONTENT; + + + /** + * Status code (301) indicating that the resource has permanently + * moved to a new location, and that future references should use a + * new URI with their requests. + */ + public static final int SC_MOVED_PERMANENTLY = + HttpServletResponse.SC_MOVED_PERMANENTLY; + + + /** + * Status code (302) indicating that the resource has temporarily + * moved to another location, but that future references should + * still use the original URI to access the resource. + */ + public static final int SC_MOVED_TEMPORARILY = + HttpServletResponse.SC_MOVED_TEMPORARILY; + + + /** + * Status code (304) indicating that a conditional GET operation + * found that the resource was available and not modified. + */ + public static final int SC_NOT_MODIFIED = + HttpServletResponse.SC_NOT_MODIFIED; + + + /** + * Status code (400) indicating the request sent by the client was + * syntactically incorrect. + */ + public static final int SC_BAD_REQUEST = + HttpServletResponse.SC_BAD_REQUEST; + + + /** + * Status code (401) indicating that the request requires HTTP + * authentication. + */ + public static final int SC_UNAUTHORIZED = + HttpServletResponse.SC_UNAUTHORIZED; + + + /** + * Status code (403) indicating the server understood the request + * but refused to fulfill it. + */ + public static final int SC_FORBIDDEN = HttpServletResponse.SC_FORBIDDEN; + + + /** + * Status code (404) indicating that the requested resource is not + * available. + */ + public static final int SC_NOT_FOUND = HttpServletResponse.SC_NOT_FOUND; + + + /** + * Status code (500) indicating an error inside the HTTP service + * which prevented it from fulfilling the request. + */ + public static final int SC_INTERNAL_SERVER_ERROR = + HttpServletResponse.SC_INTERNAL_SERVER_ERROR; + + + /** + * Status code (501) indicating the HTTP service does not support + * the functionality needed to fulfill the request. + */ + public static final int SC_NOT_IMPLEMENTED = + HttpServletResponse.SC_NOT_IMPLEMENTED; + + + /** + * Status code (502) indicating that the HTTP server received an + * invalid response from a server it consulted when acting as a + * proxy or gateway. + */ + public static final int SC_BAD_GATEWAY = + HttpServletResponse.SC_BAD_GATEWAY; + + + /** + * Status code (503) indicating that the HTTP service is + * temporarily overloaded, and unable to handle the request. + */ + public static final int SC_SERVICE_UNAVAILABLE = + HttpServletResponse.SC_SERVICE_UNAVAILABLE; + + + /** + * Status code (100) indicating the client may continue with + * its request. This interim response is used to inform the + * client that the initial part of the request has been + * received and has not yet been rejected by the server. + */ + public static final int SC_CONTINUE = 100; + + + /** + * Status code (405) indicating the method specified is not + * allowed for the resource. + */ + public static final int SC_METHOD_NOT_ALLOWED = 405; + + + /** + * Status code (409) indicating that the request could not be + * completed due to a conflict with the current state of the + * resource. + */ + public static final int SC_CONFLICT = 409; + + + /** + * Status code (412) indicating the precondition given in one + * or more of the request-header fields evaluated to false + * when it was tested on the server. + */ + public static final int SC_PRECONDITION_FAILED = 412; + + + /** + * Status code (413) indicating the server is refusing to + * process a request because the request entity is larger + * than the server is willing or able to process. + */ + public static final int SC_REQUEST_TOO_LONG = 413; + + + /** + * Status code (415) indicating the server is refusing to service + * the request because the entity of the request is in a format + * not supported by the requested resource for the requested + * method. + */ + public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415; + + + // -------------------------------------------- Extended WebDav status code + + + /** + * Status code (207) indicating that the response requires + * providing status for multiple independent operations. + */ + public static final int SC_MULTI_STATUS = 207; + // This one colides with HTTP 1.1 + // "207 Parital Update OK" + + + /** + * Status code (418) indicating the entity body submitted with + * the PATCH method was not understood by the resource. + */ + public static final int SC_UNPROCESSABLE_ENTITY = 418; + // This one colides with HTTP 1.1 + // "418 Reauthentication Required" + + + /** + * Status code (419) indicating that the resource does not have + * sufficient space to record the state of the resource after the + * execution of this method. + */ + public static final int SC_INSUFFICIENT_SPACE_ON_RESOURCE = 419; + // This one colides with HTTP 1.1 + // "419 Proxy Reauthentication Required" + + + /** + * Status code (420) indicating the method was not executed on + * a particular resource within its scope because some part of + * the method's execution failed causing the entire method to be + * aborted. + */ + public static final int SC_METHOD_FAILURE = 420; + + + /** + * Status code (423) indicating the destination resource of a + * method is locked, and either the request did not contain a + * valid Lock-Info header, or the Lock-Info header identifies + * a lock held by another principal. + */ + public static final int SC_LOCKED = 423; + + + // ------------------------------------------------------------ Initializer + + + static { + // HTTP 1.0 tatus Code + addStatusCodeMap(SC_OK, "OK"); + addStatusCodeMap(SC_CREATED, "Created"); + addStatusCodeMap(SC_ACCEPTED, "Accepted"); + addStatusCodeMap(SC_NO_CONTENT, "No Content"); + addStatusCodeMap(SC_MOVED_PERMANENTLY, "Moved Permanently"); + addStatusCodeMap(SC_MOVED_TEMPORARILY, "Moved Temporarily"); + addStatusCodeMap(SC_NOT_MODIFIED, "Not Modified"); + addStatusCodeMap(SC_BAD_REQUEST, "Bad Request"); + addStatusCodeMap(SC_UNAUTHORIZED, "Unauthorized"); + addStatusCodeMap(SC_FORBIDDEN, "Forbidden"); + addStatusCodeMap(SC_NOT_FOUND, "Not Found"); + addStatusCodeMap(SC_INTERNAL_SERVER_ERROR, "Internal Server Error"); + addStatusCodeMap(SC_NOT_IMPLEMENTED, "Not Implemented"); + addStatusCodeMap(SC_BAD_GATEWAY, "Bad Gateway"); + addStatusCodeMap(SC_SERVICE_UNAVAILABLE, "Service Unavailable"); + addStatusCodeMap(SC_CONTINUE, "Continue"); + addStatusCodeMap(SC_METHOD_NOT_ALLOWED, "Method Not Allowed"); + addStatusCodeMap(SC_CONFLICT, "Conflict"); + addStatusCodeMap(SC_PRECONDITION_FAILED, "Precondition Failed"); + addStatusCodeMap(SC_REQUEST_TOO_LONG, "Request Too Long"); + addStatusCodeMap(SC_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type"); + // WebDav Status Codes + addStatusCodeMap(SC_MULTI_STATUS, "Multi-Status"); + addStatusCodeMap(SC_UNPROCESSABLE_ENTITY, "Unprocessable Entity"); + addStatusCodeMap(SC_INSUFFICIENT_SPACE_ON_RESOURCE, + "Insufficient Space On Resource"); + addStatusCodeMap(SC_METHOD_FAILURE, "Method Failure"); + addStatusCodeMap(SC_LOCKED, "Locked"); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Returns the HTTP status text for the HTTP or WebDav status code + * specified by looking it up in the static mapping. This is a + * static function. + * + * @param nHttpStatusCode [IN] HTTP or WebDAV status code + * @return A string with a short descriptive phrase for the + * HTTP status code (e.g., "OK"). + */ + public static String getStatusText(int nHttpStatusCode) { + Integer intKey = new Integer(nHttpStatusCode); + + if (!mapStatusCodes.containsKey(intKey)) { + return ""; + } else { + return (String) mapStatusCodes.get(intKey); + } + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Adds a new status code -> status text mapping. This is a static + * method because the mapping is a static variable. + * + * @param nKey [IN] HTTP or WebDAV status code + * @param strVal [IN] HTTP status text + */ + private static void addStatusCodeMap(int nKey, String strVal) { + mapStatusCodes.put(new Integer(nKey), strVal); + } + +}; + diff --git a/java/org/apache/catalina/servlets/package.html b/java/org/apache/catalina/servlets/package.html index a28472a4a..1c9284398 100644 --- a/java/org/apache/catalina/servlets/package.html +++ b/java/org/apache/catalina/servlets/package.html @@ -1,17 +1,17 @@ - - -

    This package contains Servlets that implement some of the -standard functionality provided by the Catalina servlet container. Because -these servlets are in the org.apache.catalina package hierarchy, -they are in the privileged position of being able to reference internal server -data structures, which application level servlets are prevented from -accessing (by the application class loader implementation).

    - -

    To the extent that these servlets depend upon internal Catalina data -structures, they are obviously not portable to other servlet container -environments. However, they can be used as models for creating application -level servlets that provide similar capabilities -- most obviously the -DefaultServlet implementation, which -serves static resources when Catalina runs stand-alone.

    - - + + +

    This package contains Servlets that implement some of the +standard functionality provided by the Catalina servlet container. Because +these servlets are in the org.apache.catalina package hierarchy, +they are in the privileged position of being able to reference internal server +data structures, which application level servlets are prevented from +accessing (by the application class loader implementation).

    + +

    To the extent that these servlets depend upon internal Catalina data +structures, they are obviously not portable to other servlet container +environments. However, they can be used as models for creating application +level servlets that provide similar capabilities -- most obviously the +DefaultServlet implementation, which +serves static resources when Catalina runs stand-alone.

    + + diff --git a/java/org/apache/catalina/session/Constants.java b/java/org/apache/catalina/session/Constants.java index adb283ea8..f71985232 100644 --- a/java/org/apache/catalina/session/Constants.java +++ b/java/org/apache/catalina/session/Constants.java @@ -1,31 +1,31 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - -/** - * Manifest constants for the org.apache.catalina.session - * package. - * - * @author Craig R. McClanahan - */ - -public class Constants { - - public static final String Package = "org.apache.catalina.session"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + +/** + * Manifest constants for the org.apache.catalina.session + * package. + * + * @author Craig R. McClanahan + */ + +public class Constants { + + public static final String Package = "org.apache.catalina.session"; + +} diff --git a/java/org/apache/catalina/session/FileStore.java b/java/org/apache/catalina/session/FileStore.java index 80745aa06..3f7eacdbe 100644 --- a/java/org/apache/catalina/session/FileStore.java +++ b/java/org/apache/catalina/session/FileStore.java @@ -1,439 +1,439 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; - -import javax.servlet.ServletContext; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Loader; -import org.apache.catalina.Session; -import org.apache.catalina.Store; -import org.apache.catalina.util.CustomObjectInputStream; - - -/** - * Concrete implementation of the Store interface that utilizes - * a file per saved Session in a configured directory. Sessions that are - * saved are still subject to being expired based on inactivity. - * - * @author Craig R. McClanahan - * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public final class FileStore - extends StoreBase implements Store { - - - // ----------------------------------------------------- Constants - - - /** - * The extension to use for serialized session filenames. - */ - private static final String FILE_EXT = ".session"; - - - // ----------------------------------------------------- Instance Variables - - - /** - * The pathname of the directory in which Sessions are stored. - * This may be an absolute pathname, or a relative path that is - * resolved against the temporary work directory for this application. - */ - private String directory = "."; - - - /** - * A File representing the directory in which Sessions are stored. - */ - private File directoryFile = null; - - - /** - * The descriptive information about this implementation. - */ - private static final String info = "FileStore/1.0"; - - /** - * Name to register for this Store, used for logging. - */ - private static final String storeName = "fileStore"; - - /** - * Name to register for the background thread. - */ - private static final String threadName = "FileStore"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the directory path for this Store. - */ - public String getDirectory() { - - return (directory); - - } - - - /** - * Set the directory path for this Store. - * - * @param path The new directory path - */ - public void setDirectory(String path) { - - String oldDirectory = this.directory; - this.directory = path; - this.directoryFile = null; - support.firePropertyChange("directory", oldDirectory, - this.directory); - - } - - - /** - * Return descriptive information about this Store implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - /** - * Return the thread name for this Store. - */ - public String getThreadName() { - return(threadName); - } - - /** - * Return the name for this Store, used for logging. - */ - public String getStoreName() { - return(storeName); - } - - - /** - * Return the number of Sessions present in this Store. - * - * @exception IOException if an input/output error occurs - */ - public int getSize() throws IOException { - - // Acquire the list of files in our storage directory - File file = directory(); - if (file == null) { - return (0); - } - String files[] = file.list(); - - // Figure out which files are sessions - int keycount = 0; - for (int i = 0; i < files.length; i++) { - if (files[i].endsWith(FILE_EXT)) { - keycount++; - } - } - return (keycount); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Remove all of the Sessions in this Store. - * - * @exception IOException if an input/output error occurs - */ - public void clear() - throws IOException { - - String[] keys = keys(); - for (int i = 0; i < keys.length; i++) { - remove(keys[i]); - } - - } - - - /** - * Return an array containing the session identifiers of all Sessions - * currently saved in this Store. If there are no such Sessions, a - * zero-length array is returned. - * - * @exception IOException if an input/output error occurred - */ - public String[] keys() throws IOException { - - // Acquire the list of files in our storage directory - File file = directory(); - if (file == null) { - return (new String[0]); - } - - String files[] = file.list(); - - // Bugzilla 32130 - if((files == null) || (files.length < 1)) { - return (new String[0]); - } - - // Build and return the list of session identifiers - ArrayList list = new ArrayList(); - int n = FILE_EXT.length(); - for (int i = 0; i < files.length; i++) { - if (files[i].endsWith(FILE_EXT)) { - list.add(files[i].substring(0, files[i].length() - n)); - } - } - return ((String[]) list.toArray(new String[list.size()])); - - } - - - /** - * Load and return the Session associated with the specified session - * identifier from this Store, without removing it. If there is no - * such stored Session, return null. - * - * @param id Session identifier of the session to load - * - * @exception ClassNotFoundException if a deserialization error occurs - * @exception IOException if an input/output error occurs - */ - public Session load(String id) - throws ClassNotFoundException, IOException { - - // Open an input stream to the specified pathname, if any - File file = file(id); - if (file == null) { - return (null); - } - - if (! file.exists()) { - return (null); - } - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".loading", - id, file.getAbsolutePath())); - } - - FileInputStream fis = null; - ObjectInputStream ois = null; - Loader loader = null; - ClassLoader classLoader = null; - try { - fis = new FileInputStream(file.getAbsolutePath()); - BufferedInputStream bis = new BufferedInputStream(fis); - Container container = manager.getContainer(); - if (container != null) - loader = container.getLoader(); - if (loader != null) - classLoader = loader.getClassLoader(); - if (classLoader != null) - ois = new CustomObjectInputStream(bis, classLoader); - else - ois = new ObjectInputStream(bis); - } catch (FileNotFoundException e) { - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug("No persisted data file found"); - return (null); - } catch (IOException e) { - if (ois != null) { - try { - ois.close(); - } catch (IOException f) { - ; - } - ois = null; - } - throw e; - } - - try { - StandardSession session = - (StandardSession) manager.createEmptySession(); - session.readObjectData(ois); - session.setManager(manager); - return (session); - } finally { - // Close the input stream - if (ois != null) { - try { - ois.close(); - } catch (IOException f) { - ; - } - } - } - } - - - /** - * Remove the Session with the specified session identifier from - * this Store, if present. If no such Session is present, this method - * takes no action. - * - * @param id Session identifier of the Session to be removed - * - * @exception IOException if an input/output error occurs - */ - public void remove(String id) throws IOException { - - File file = file(id); - if (file == null) { - return; - } - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".removing", - id, file.getAbsolutePath())); - } - file.delete(); - - } - - - /** - * Save the specified Session into this Store. Any previously saved - * information for the associated session identifier is replaced. - * - * @param session Session to be saved - * - * @exception IOException if an input/output error occurs - */ - public void save(Session session) throws IOException { - - // Open an output stream to the specified pathname, if any - File file = file(session.getIdInternal()); - if (file == null) { - return; - } - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".saving", - session.getIdInternal(), file.getAbsolutePath())); - } - FileOutputStream fos = null; - ObjectOutputStream oos = null; - try { - fos = new FileOutputStream(file.getAbsolutePath()); - oos = new ObjectOutputStream(new BufferedOutputStream(fos)); - } catch (IOException e) { - if (oos != null) { - try { - oos.close(); - } catch (IOException f) { - ; - } - } - throw e; - } - - try { - ((StandardSession)session).writeObjectData(oos); - } finally { - oos.close(); - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Return a File object representing the pathname to our - * session persistence directory, if any. The directory will be - * created if it does not already exist. - */ - private File directory() { - - if (this.directory == null) { - return (null); - } - if (this.directoryFile != null) { - // NOTE: Race condition is harmless, so do not synchronize - return (this.directoryFile); - } - File file = new File(this.directory); - if (!file.isAbsolute()) { - Container container = manager.getContainer(); - if (container instanceof Context) { - ServletContext servletContext = - ((Context) container).getServletContext(); - File work = (File) - servletContext.getAttribute(Globals.WORK_DIR_ATTR); - file = new File(work, this.directory); - } else { - throw new IllegalArgumentException - ("Parent Container is not a Context"); - } - } - if (!file.exists() || !file.isDirectory()) { - file.delete(); - file.mkdirs(); - } - this.directoryFile = file; - return (file); - - } - - - /** - * Return a File object representing the pathname to our - * session persistence file, if any. - * - * @param id The ID of the Session to be retrieved. This is - * used in the file naming. - */ - private File file(String id) { - - if (this.directory == null) { - return (null); - } - String filename = id + FILE_EXT; - File file = new File(directory(), filename); - return (file); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; + +import javax.servlet.ServletContext; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Loader; +import org.apache.catalina.Session; +import org.apache.catalina.Store; +import org.apache.catalina.util.CustomObjectInputStream; + + +/** + * Concrete implementation of the Store interface that utilizes + * a file per saved Session in a configured directory. Sessions that are + * saved are still subject to being expired based on inactivity. + * + * @author Craig R. McClanahan + * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public final class FileStore + extends StoreBase implements Store { + + + // ----------------------------------------------------- Constants + + + /** + * The extension to use for serialized session filenames. + */ + private static final String FILE_EXT = ".session"; + + + // ----------------------------------------------------- Instance Variables + + + /** + * The pathname of the directory in which Sessions are stored. + * This may be an absolute pathname, or a relative path that is + * resolved against the temporary work directory for this application. + */ + private String directory = "."; + + + /** + * A File representing the directory in which Sessions are stored. + */ + private File directoryFile = null; + + + /** + * The descriptive information about this implementation. + */ + private static final String info = "FileStore/1.0"; + + /** + * Name to register for this Store, used for logging. + */ + private static final String storeName = "fileStore"; + + /** + * Name to register for the background thread. + */ + private static final String threadName = "FileStore"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the directory path for this Store. + */ + public String getDirectory() { + + return (directory); + + } + + + /** + * Set the directory path for this Store. + * + * @param path The new directory path + */ + public void setDirectory(String path) { + + String oldDirectory = this.directory; + this.directory = path; + this.directoryFile = null; + support.firePropertyChange("directory", oldDirectory, + this.directory); + + } + + + /** + * Return descriptive information about this Store implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + /** + * Return the thread name for this Store. + */ + public String getThreadName() { + return(threadName); + } + + /** + * Return the name for this Store, used for logging. + */ + public String getStoreName() { + return(storeName); + } + + + /** + * Return the number of Sessions present in this Store. + * + * @exception IOException if an input/output error occurs + */ + public int getSize() throws IOException { + + // Acquire the list of files in our storage directory + File file = directory(); + if (file == null) { + return (0); + } + String files[] = file.list(); + + // Figure out which files are sessions + int keycount = 0; + for (int i = 0; i < files.length; i++) { + if (files[i].endsWith(FILE_EXT)) { + keycount++; + } + } + return (keycount); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Remove all of the Sessions in this Store. + * + * @exception IOException if an input/output error occurs + */ + public void clear() + throws IOException { + + String[] keys = keys(); + for (int i = 0; i < keys.length; i++) { + remove(keys[i]); + } + + } + + + /** + * Return an array containing the session identifiers of all Sessions + * currently saved in this Store. If there are no such Sessions, a + * zero-length array is returned. + * + * @exception IOException if an input/output error occurred + */ + public String[] keys() throws IOException { + + // Acquire the list of files in our storage directory + File file = directory(); + if (file == null) { + return (new String[0]); + } + + String files[] = file.list(); + + // Bugzilla 32130 + if((files == null) || (files.length < 1)) { + return (new String[0]); + } + + // Build and return the list of session identifiers + ArrayList list = new ArrayList(); + int n = FILE_EXT.length(); + for (int i = 0; i < files.length; i++) { + if (files[i].endsWith(FILE_EXT)) { + list.add(files[i].substring(0, files[i].length() - n)); + } + } + return ((String[]) list.toArray(new String[list.size()])); + + } + + + /** + * Load and return the Session associated with the specified session + * identifier from this Store, without removing it. If there is no + * such stored Session, return null. + * + * @param id Session identifier of the session to load + * + * @exception ClassNotFoundException if a deserialization error occurs + * @exception IOException if an input/output error occurs + */ + public Session load(String id) + throws ClassNotFoundException, IOException { + + // Open an input stream to the specified pathname, if any + File file = file(id); + if (file == null) { + return (null); + } + + if (! file.exists()) { + return (null); + } + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".loading", + id, file.getAbsolutePath())); + } + + FileInputStream fis = null; + ObjectInputStream ois = null; + Loader loader = null; + ClassLoader classLoader = null; + try { + fis = new FileInputStream(file.getAbsolutePath()); + BufferedInputStream bis = new BufferedInputStream(fis); + Container container = manager.getContainer(); + if (container != null) + loader = container.getLoader(); + if (loader != null) + classLoader = loader.getClassLoader(); + if (classLoader != null) + ois = new CustomObjectInputStream(bis, classLoader); + else + ois = new ObjectInputStream(bis); + } catch (FileNotFoundException e) { + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug("No persisted data file found"); + return (null); + } catch (IOException e) { + if (ois != null) { + try { + ois.close(); + } catch (IOException f) { + ; + } + ois = null; + } + throw e; + } + + try { + StandardSession session = + (StandardSession) manager.createEmptySession(); + session.readObjectData(ois); + session.setManager(manager); + return (session); + } finally { + // Close the input stream + if (ois != null) { + try { + ois.close(); + } catch (IOException f) { + ; + } + } + } + } + + + /** + * Remove the Session with the specified session identifier from + * this Store, if present. If no such Session is present, this method + * takes no action. + * + * @param id Session identifier of the Session to be removed + * + * @exception IOException if an input/output error occurs + */ + public void remove(String id) throws IOException { + + File file = file(id); + if (file == null) { + return; + } + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".removing", + id, file.getAbsolutePath())); + } + file.delete(); + + } + + + /** + * Save the specified Session into this Store. Any previously saved + * information for the associated session identifier is replaced. + * + * @param session Session to be saved + * + * @exception IOException if an input/output error occurs + */ + public void save(Session session) throws IOException { + + // Open an output stream to the specified pathname, if any + File file = file(session.getIdInternal()); + if (file == null) { + return; + } + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName()+".saving", + session.getIdInternal(), file.getAbsolutePath())); + } + FileOutputStream fos = null; + ObjectOutputStream oos = null; + try { + fos = new FileOutputStream(file.getAbsolutePath()); + oos = new ObjectOutputStream(new BufferedOutputStream(fos)); + } catch (IOException e) { + if (oos != null) { + try { + oos.close(); + } catch (IOException f) { + ; + } + } + throw e; + } + + try { + ((StandardSession)session).writeObjectData(oos); + } finally { + oos.close(); + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Return a File object representing the pathname to our + * session persistence directory, if any. The directory will be + * created if it does not already exist. + */ + private File directory() { + + if (this.directory == null) { + return (null); + } + if (this.directoryFile != null) { + // NOTE: Race condition is harmless, so do not synchronize + return (this.directoryFile); + } + File file = new File(this.directory); + if (!file.isAbsolute()) { + Container container = manager.getContainer(); + if (container instanceof Context) { + ServletContext servletContext = + ((Context) container).getServletContext(); + File work = (File) + servletContext.getAttribute(Globals.WORK_DIR_ATTR); + file = new File(work, this.directory); + } else { + throw new IllegalArgumentException + ("Parent Container is not a Context"); + } + } + if (!file.exists() || !file.isDirectory()) { + file.delete(); + file.mkdirs(); + } + this.directoryFile = file; + return (file); + + } + + + /** + * Return a File object representing the pathname to our + * session persistence file, if any. + * + * @param id The ID of the Session to be retrieved. This is + * used in the file naming. + */ + private File file(String id) { + + if (this.directory == null) { + return (null); + } + String filename = id + FILE_EXT; + File file = new File(directory(), filename); + return (file); + + } + + +} diff --git a/java/org/apache/catalina/session/JDBCStore.java b/java/org/apache/catalina/session/JDBCStore.java index 971fa18a4..2f06500a6 100644 --- a/java/org/apache/catalina/session/JDBCStore.java +++ b/java/org/apache/catalina/session/JDBCStore.java @@ -1,988 +1,988 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.session; - -import org.apache.catalina.Container; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Loader; -import org.apache.catalina.Session; -import org.apache.catalina.Store; -import org.apache.catalina.util.CustomObjectInputStream; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Properties; - -/** - * Implementation of the Store interface that stores - * serialized session objects in a database. Sessions that are - * saved are still subject to being expired based on inactivity. - * - * @author Bip Thelin - * @version $Revision: 303826 $, $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public class JDBCStore - extends StoreBase implements Store { - - /** - * The descriptive information about this implementation. - */ - protected static String info = "JDBCStore/1.0"; - - /** - * Context name associated with this Store - */ - private String name = null; - - /** - * Name to register for this Store, used for logging. - */ - protected static String storeName = "JDBCStore"; - - /** - * Name to register for the background thread. - */ - protected String threadName = "JDBCStore"; - - /** - * The connection username to use when trying to connect to the database. - */ - protected String connectionName = null; - - - /** - * The connection URL to use when trying to connect to the database. - */ - protected String connectionPassword = null; - - /** - * Connection string to use when connecting to the DB. - */ - protected String connectionURL = null; - - /** - * The database connection. - */ - private Connection dbConnection = null; - - /** - * Instance of the JDBC Driver class we use as a connection factory. - */ - protected Driver driver = null; - - /** - * Driver to use. - */ - protected String driverName = null; - - // ------------------------------------------------------------- Table & cols - - /** - * Table to use. - */ - protected String sessionTable = "tomcat$sessions"; - - /** - * Column to use for /Engine/Host/Context name - */ - protected String sessionAppCol = "app"; - - /** - * Id column to use. - */ - protected String sessionIdCol = "id"; - - /** - * Data column to use. - */ - protected String sessionDataCol = "data"; - - /** - * Is Valid column to use. - */ - protected String sessionValidCol = "valid"; - - /** - * Max Inactive column to use. - */ - protected String sessionMaxInactiveCol = "maxinactive"; - - /** - * Last Accessed column to use. - */ - protected String sessionLastAccessedCol = "lastaccess"; - - // ------------------------------------------------------------- SQL Variables - - /** - * Variable to hold the getSize() prepared statement. - */ - protected PreparedStatement preparedSizeSql = null; - - /** - * Variable to hold the keys() prepared statement. - */ - protected PreparedStatement preparedKeysSql = null; - - /** - * Variable to hold the save() prepared statement. - */ - protected PreparedStatement preparedSaveSql = null; - - /** - * Variable to hold the clear() prepared statement. - */ - protected PreparedStatement preparedClearSql = null; - - /** - * Variable to hold the remove() prepared statement. - */ - protected PreparedStatement preparedRemoveSql = null; - - /** - * Variable to hold the load() prepared statement. - */ - protected PreparedStatement preparedLoadSql = null; - - // ------------------------------------------------------------- Properties - - /** - * Return the info for this Store. - */ - public String getInfo() { - return (info); - } - - /** - * Return the name for this instance (built from container name) - */ - public String getName() { - if (name == null) { - Container container = manager.getContainer(); - String contextName = container.getName(); - String hostName = ""; - String engineName = ""; - - if (container.getParent() != null) { - Container host = container.getParent(); - hostName = host.getName(); - if (host.getParent() != null) { - engineName = host.getParent().getName(); - } - } - name = "/" + engineName + "/" + hostName + contextName; - } - return name; - } - - /** - * Return the thread name for this Store. - */ - public String getThreadName() { - return (threadName); - } - - /** - * Return the name for this Store, used for logging. - */ - public String getStoreName() { - return (storeName); - } - - /** - * Set the driver for this Store. - * - * @param driverName The new driver - */ - public void setDriverName(String driverName) { - String oldDriverName = this.driverName; - this.driverName = driverName; - support.firePropertyChange("driverName", - oldDriverName, - this.driverName); - this.driverName = driverName; - } - - /** - * Return the driver for this Store. - */ - public String getDriverName() { - return (this.driverName); - } - - /** - * Return the username to use to connect to the database. - * - */ - public String getConnectionName() { - return connectionName; - } - - /** - * Set the username to use to connect to the database. - * - * @param connectionName Username - */ - public void setConnectionName(String connectionName) { - this.connectionName = connectionName; - } - - /** - * Return the password to use to connect to the database. - * - */ - public String getConnectionPassword() { - return connectionPassword; - } - - /** - * Set the password to use to connect to the database. - * - * @param connectionPassword User password - */ - public void setConnectionPassword(String connectionPassword) { - this.connectionPassword = connectionPassword; - } - - /** - * Set the Connection URL for this Store. - * - * @param connectionURL The new Connection URL - */ - public void setConnectionURL(String connectionURL) { - String oldConnString = this.connectionURL; - this.connectionURL = connectionURL; - support.firePropertyChange("connectionURL", - oldConnString, - this.connectionURL); - } - - /** - * Return the Connection URL for this Store. - */ - public String getConnectionURL() { - return (this.connectionURL); - } - - /** - * Set the table for this Store. - * - * @param sessionTable The new table - */ - public void setSessionTable(String sessionTable) { - String oldSessionTable = this.sessionTable; - this.sessionTable = sessionTable; - support.firePropertyChange("sessionTable", - oldSessionTable, - this.sessionTable); - } - - /** - * Return the table for this Store. - */ - public String getSessionTable() { - return (this.sessionTable); - } - - /** - * Set the App column for the table. - * - * @param sessionAppCol the column name - */ - public void setSessionAppCol(String sessionAppCol) { - String oldSessionAppCol = this.sessionAppCol; - this.sessionAppCol = sessionAppCol; - support.firePropertyChange("sessionAppCol", - oldSessionAppCol, - this.sessionAppCol); - } - - /** - * Return the web application name column for the table. - */ - public String getSessionAppCol() { - return (this.sessionAppCol); - } - - /** - * Set the Id column for the table. - * - * @param sessionIdCol the column name - */ - public void setSessionIdCol(String sessionIdCol) { - String oldSessionIdCol = this.sessionIdCol; - this.sessionIdCol = sessionIdCol; - support.firePropertyChange("sessionIdCol", - oldSessionIdCol, - this.sessionIdCol); - } - - /** - * Return the Id column for the table. - */ - public String getSessionIdCol() { - return (this.sessionIdCol); - } - - /** - * Set the Data column for the table - * - * @param sessionDataCol the column name - */ - public void setSessionDataCol(String sessionDataCol) { - String oldSessionDataCol = this.sessionDataCol; - this.sessionDataCol = sessionDataCol; - support.firePropertyChange("sessionDataCol", - oldSessionDataCol, - this.sessionDataCol); - } - - /** - * Return the data column for the table - */ - public String getSessionDataCol() { - return (this.sessionDataCol); - } - - /** - * Set the Is Valid column for the table - * - * @param sessionValidCol The column name - */ - public void setSessionValidCol(String sessionValidCol) { - String oldSessionValidCol = this.sessionValidCol; - this.sessionValidCol = sessionValidCol; - support.firePropertyChange("sessionValidCol", - oldSessionValidCol, - this.sessionValidCol); - } - - /** - * Return the Is Valid column - */ - public String getSessionValidCol() { - return (this.sessionValidCol); - } - - /** - * Set the Max Inactive column for the table - * - * @param sessionMaxInactiveCol The column name - */ - public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) { - String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol; - this.sessionMaxInactiveCol = sessionMaxInactiveCol; - support.firePropertyChange("sessionMaxInactiveCol", - oldSessionMaxInactiveCol, - this.sessionMaxInactiveCol); - } - - /** - * Return the Max Inactive column - */ - public String getSessionMaxInactiveCol() { - return (this.sessionMaxInactiveCol); - } - - /** - * Set the Last Accessed column for the table - * - * @param sessionLastAccessedCol The column name - */ - public void setSessionLastAccessedCol(String sessionLastAccessedCol) { - String oldSessionLastAccessedCol = this.sessionLastAccessedCol; - this.sessionLastAccessedCol = sessionLastAccessedCol; - support.firePropertyChange("sessionLastAccessedCol", - oldSessionLastAccessedCol, - this.sessionLastAccessedCol); - } - - /** - * Return the Last Accessed column - */ - public String getSessionLastAccessedCol() { - return (this.sessionLastAccessedCol); - } - - // --------------------------------------------------------- Public Methods - - /** - * Return an array containing the session identifiers of all Sessions - * currently saved in this Store. If there are no such Sessions, a - * zero-length array is returned. - * - * @exception IOException if an input/output error occurred - */ - public String[] keys() throws IOException { - ResultSet rst = null; - String keys[] = null; - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - - Connection _conn = getConnection(); - if (_conn == null) { - return (new String[0]); - } - try { - if (preparedKeysSql == null) { - String keysSql = "SELECT " + sessionIdCol + " FROM " - + sessionTable + " WHERE " + sessionAppCol - + " = ?"; - preparedKeysSql = _conn.prepareStatement(keysSql); - } - - preparedKeysSql.setString(1, getName()); - rst = preparedKeysSql.executeQuery(); - ArrayList tmpkeys = new ArrayList(); - if (rst != null) { - while (rst.next()) { - tmpkeys.add(rst.getString(1)); - } - } - keys = (String[]) tmpkeys.toArray(new String[tmpkeys.size()]); - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - keys = new String[0]; - // Close the connection so that it gets reopened next time - if (dbConnection != null) - close(dbConnection); - } finally { - try { - if (rst != null) { - rst.close(); - } - } catch (SQLException e) { - ; - } - - release(_conn); - } - numberOfTries--; - } - } - - return (keys); - } - - /** - * Return an integer containing a count of all Sessions - * currently saved in this Store. If there are no Sessions, - * 0 is returned. - * - * @exception IOException if an input/output error occurred - */ - public int getSize() throws IOException { - int size = 0; - ResultSet rst = null; - - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - Connection _conn = getConnection(); - - if (_conn == null) { - return (size); - } - - try { - if (preparedSizeSql == null) { - String sizeSql = "SELECT COUNT(" + sessionIdCol - + ") FROM " + sessionTable + " WHERE " - + sessionAppCol + " = ?"; - preparedSizeSql = _conn.prepareStatement(sizeSql); - } - - preparedSizeSql.setString(1, getName()); - rst = preparedSizeSql.executeQuery(); - if (rst.next()) { - size = rst.getInt(1); - } - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - if (dbConnection != null) - close(dbConnection); - } finally { - try { - if (rst != null) - rst.close(); - } catch (SQLException e) { - ; - } - - release(_conn); - } - numberOfTries--; - } - } - return (size); - } - - /** - * Load the Session associated with the id id. - * If no such session is found null is returned. - * - * @param id a value of type String - * @return the stored Session - * @exception ClassNotFoundException if an error occurs - * @exception IOException if an input/output error occurred - */ - public Session load(String id) - throws ClassNotFoundException, IOException { - ResultSet rst = null; - StandardSession _session = null; - Loader loader = null; - ClassLoader classLoader = null; - ObjectInputStream ois = null; - BufferedInputStream bis = null; - Container container = manager.getContainer(); - - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - Connection _conn = getConnection(); - if (_conn == null) { - return (null); - } - - try { - if (preparedLoadSql == null) { - String loadSql = "SELECT " + sessionIdCol + ", " - + sessionDataCol + " FROM " + sessionTable - + " WHERE " + sessionIdCol + " = ? AND " - + sessionAppCol + " = ?"; - preparedLoadSql = _conn.prepareStatement(loadSql); - } - - preparedLoadSql.setString(1, id); - preparedLoadSql.setString(2, getName()); - rst = preparedLoadSql.executeQuery(); - if (rst.next()) { - bis = new BufferedInputStream(rst.getBinaryStream(2)); - - if (container != null) { - loader = container.getLoader(); - } - if (loader != null) { - classLoader = loader.getClassLoader(); - } - if (classLoader != null) { - ois = new CustomObjectInputStream(bis, - classLoader); - } else { - ois = new ObjectInputStream(bis); - } - - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".loading", - id, sessionTable)); - } - - _session = (StandardSession) manager.createEmptySession(); - _session.readObjectData(ois); - _session.setManager(manager); - } else if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(getStoreName() + ": No persisted data object found"); - } - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - if (dbConnection != null) - close(dbConnection); - } finally { - try { - if (rst != null) { - rst.close(); - } - } catch (SQLException e) { - ; - } - if (ois != null) { - try { - ois.close(); - } catch (IOException e) { - ; - } - } - release(_conn); - } - numberOfTries--; - } - } - - return (_session); - } - - /** - * Remove the Session with the specified session identifier from - * this Store, if present. If no such Session is present, this method - * takes no action. - * - * @param id Session identifier of the Session to be removed - * - * @exception IOException if an input/output error occurs - */ - public void remove(String id) throws IOException { - - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - Connection _conn = getConnection(); - - if (_conn == null) { - return; - } - - try { - if (preparedRemoveSql == null) { - String removeSql = "DELETE FROM " + sessionTable - + " WHERE " + sessionIdCol + " = ? AND " - + sessionAppCol + " = ?"; - preparedRemoveSql = _conn.prepareStatement(removeSql); - } - - preparedRemoveSql.setString(1, id); - preparedRemoveSql.setString(2, getName()); - preparedRemoveSql.execute(); - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - if (dbConnection != null) - close(dbConnection); - } finally { - release(_conn); - } - numberOfTries--; - } - } - - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".removing", id, sessionTable)); - } - } - - /** - * Remove all of the Sessions in this Store. - * - * @exception IOException if an input/output error occurs - */ - public void clear() throws IOException { - - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - Connection _conn = getConnection(); - if (_conn == null) { - return; - } - - try { - if (preparedClearSql == null) { - String clearSql = "DELETE FROM " + sessionTable - + " WHERE " + sessionAppCol + " = ?"; - preparedClearSql = _conn.prepareStatement(clearSql); - } - - preparedClearSql.setString(1, getName()); - preparedClearSql.execute(); - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - if (dbConnection != null) - close(dbConnection); - } finally { - release(_conn); - } - numberOfTries--; - } - } - } - - /** - * Save a session to the Store. - * - * @param session the session to be stored - * @exception IOException if an input/output error occurs - */ - public void save(Session session) throws IOException { - ObjectOutputStream oos = null; - ByteArrayOutputStream bos = null; - ByteArrayInputStream bis = null; - InputStream in = null; - - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries > 0) { - Connection _conn = getConnection(); - if (_conn == null) { - return; - } - - // If sessions already exist in DB, remove and insert again. - // TODO: - // * Check if ID exists in database and if so use UPDATE. - remove(session.getIdInternal()); - - try { - bos = new ByteArrayOutputStream(); - oos = new ObjectOutputStream(new BufferedOutputStream(bos)); - - ((StandardSession) session).writeObjectData(oos); - oos.close(); - oos = null; - byte[] obs = bos.toByteArray(); - int size = obs.length; - bis = new ByteArrayInputStream(obs, 0, size); - in = new BufferedInputStream(bis, size); - - if (preparedSaveSql == null) { - String saveSql = "INSERT INTO " + sessionTable + " (" - + sessionIdCol + ", " + sessionAppCol + ", " - + sessionDataCol + ", " + sessionValidCol - + ", " + sessionMaxInactiveCol + ", " - + sessionLastAccessedCol - + ") VALUES (?, ?, ?, ?, ?, ?)"; - preparedSaveSql = _conn.prepareStatement(saveSql); - } - - preparedSaveSql.setString(1, session.getIdInternal()); - preparedSaveSql.setString(2, getName()); - preparedSaveSql.setBinaryStream(3, in, size); - preparedSaveSql.setString(4, session.isValid() ? "1" : "0"); - preparedSaveSql.setInt(5, session.getMaxInactiveInterval()); - preparedSaveSql.setLong(6, session.getLastAccessedTime()); - preparedSaveSql.execute(); - // Break out after the finally block - numberOfTries = 0; - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); - if (dbConnection != null) - close(dbConnection); - } catch (IOException e) { - ; - } finally { - if (oos != null) { - oos.close(); - } - if (bis != null) { - bis.close(); - } - if (in != null) { - in.close(); - } - - release(_conn); - } - numberOfTries--; - } - } - - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".saving", - session.getIdInternal(), sessionTable)); - } - } - - // --------------------------------------------------------- Protected Methods - - /** - * Check the connection associated with this store, if it's - * null or closed try to reopen it. - * Returns null if the connection could not be established. - * - * @return Connection if the connection suceeded - */ - protected Connection getConnection() { - try { - if (dbConnection == null || dbConnection.isClosed()) { - manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBClosed")); - open(); - if (dbConnection == null || dbConnection.isClosed()) { - manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBReOpenFail")); - } - } - } catch (SQLException ex) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionSQLException", - ex.toString())); - } - - return dbConnection; - } - - /** - * Open (if necessary) and return a database connection for use by - * this Realm. - * - * @exception SQLException if a database error occurs - */ - protected Connection open() throws SQLException { - - // Do nothing if there is a database connection already open - if (dbConnection != null) - return (dbConnection); - - // Instantiate our database driver if necessary - if (driver == null) { - try { - Class clazz = Class.forName(driverName); - driver = (Driver) clazz.newInstance(); - } catch (ClassNotFoundException ex) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", - ex.toString())); - } catch (InstantiationException ex) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", - ex.toString())); - } catch (IllegalAccessException ex) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", - ex.toString())); - } - } - - // Open a new connection - Properties props = new Properties(); - if (connectionName != null) - props.put("user", connectionName); - if (connectionPassword != null) - props.put("password", connectionPassword); - dbConnection = driver.connect(connectionURL, props); - dbConnection.setAutoCommit(true); - return (dbConnection); - - } - - /** - * Close the specified database connection. - * - * @param dbConnection The connection to be closed - */ - protected void close(Connection dbConnection) { - - // Do nothing if the database connection is already closed - if (dbConnection == null) - return; - - // Close our prepared statements (if any) - try { - preparedSizeSql.close(); - } catch (Throwable f) { - ; - } - this.preparedSizeSql = null; - - try { - preparedKeysSql.close(); - } catch (Throwable f) { - ; - } - this.preparedKeysSql = null; - - try { - preparedSaveSql.close(); - } catch (Throwable f) { - ; - } - this.preparedSaveSql = null; - - try { - preparedClearSql.close(); - } catch (Throwable f) { - ; - } - - try { - preparedRemoveSql.close(); - } catch (Throwable f) { - ; - } - this.preparedRemoveSql = null; - - try { - preparedLoadSql.close(); - } catch (Throwable f) { - ; - } - this.preparedLoadSql = null; - - // Close this database connection, and log any errors - try { - dbConnection.close(); - } catch (SQLException e) { - manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here - } finally { - this.dbConnection = null; - } - - } - - /** - * Release the connection, not needed here since the - * connection is not associated with a connection pool. - * - * @param conn The connection to be released - */ - protected void release(Connection conn) { - ; - } - - /** - * Called once when this Store is first started. - */ - public void start() throws LifecycleException { - super.start(); - - // Open connection to the database - this.dbConnection = getConnection(); - } - - /** - * Gracefully terminate everything associated with our db. - * Called once when this Store is stoping. - * - */ - public void stop() throws LifecycleException { - super.stop(); - - // Close and release everything associated with our db. - if (dbConnection != null) { - try { - dbConnection.commit(); - } catch (SQLException e) { - ; - } - close(dbConnection); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.session; + +import org.apache.catalina.Container; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Loader; +import org.apache.catalina.Session; +import org.apache.catalina.Store; +import org.apache.catalina.util.CustomObjectInputStream; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Properties; + +/** + * Implementation of the Store interface that stores + * serialized session objects in a database. Sessions that are + * saved are still subject to being expired based on inactivity. + * + * @author Bip Thelin + * @version $Revision: 303826 $, $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public class JDBCStore + extends StoreBase implements Store { + + /** + * The descriptive information about this implementation. + */ + protected static String info = "JDBCStore/1.0"; + + /** + * Context name associated with this Store + */ + private String name = null; + + /** + * Name to register for this Store, used for logging. + */ + protected static String storeName = "JDBCStore"; + + /** + * Name to register for the background thread. + */ + protected String threadName = "JDBCStore"; + + /** + * The connection username to use when trying to connect to the database. + */ + protected String connectionName = null; + + + /** + * The connection URL to use when trying to connect to the database. + */ + protected String connectionPassword = null; + + /** + * Connection string to use when connecting to the DB. + */ + protected String connectionURL = null; + + /** + * The database connection. + */ + private Connection dbConnection = null; + + /** + * Instance of the JDBC Driver class we use as a connection factory. + */ + protected Driver driver = null; + + /** + * Driver to use. + */ + protected String driverName = null; + + // ------------------------------------------------------------- Table & cols + + /** + * Table to use. + */ + protected String sessionTable = "tomcat$sessions"; + + /** + * Column to use for /Engine/Host/Context name + */ + protected String sessionAppCol = "app"; + + /** + * Id column to use. + */ + protected String sessionIdCol = "id"; + + /** + * Data column to use. + */ + protected String sessionDataCol = "data"; + + /** + * Is Valid column to use. + */ + protected String sessionValidCol = "valid"; + + /** + * Max Inactive column to use. + */ + protected String sessionMaxInactiveCol = "maxinactive"; + + /** + * Last Accessed column to use. + */ + protected String sessionLastAccessedCol = "lastaccess"; + + // ------------------------------------------------------------- SQL Variables + + /** + * Variable to hold the getSize() prepared statement. + */ + protected PreparedStatement preparedSizeSql = null; + + /** + * Variable to hold the keys() prepared statement. + */ + protected PreparedStatement preparedKeysSql = null; + + /** + * Variable to hold the save() prepared statement. + */ + protected PreparedStatement preparedSaveSql = null; + + /** + * Variable to hold the clear() prepared statement. + */ + protected PreparedStatement preparedClearSql = null; + + /** + * Variable to hold the remove() prepared statement. + */ + protected PreparedStatement preparedRemoveSql = null; + + /** + * Variable to hold the load() prepared statement. + */ + protected PreparedStatement preparedLoadSql = null; + + // ------------------------------------------------------------- Properties + + /** + * Return the info for this Store. + */ + public String getInfo() { + return (info); + } + + /** + * Return the name for this instance (built from container name) + */ + public String getName() { + if (name == null) { + Container container = manager.getContainer(); + String contextName = container.getName(); + String hostName = ""; + String engineName = ""; + + if (container.getParent() != null) { + Container host = container.getParent(); + hostName = host.getName(); + if (host.getParent() != null) { + engineName = host.getParent().getName(); + } + } + name = "/" + engineName + "/" + hostName + contextName; + } + return name; + } + + /** + * Return the thread name for this Store. + */ + public String getThreadName() { + return (threadName); + } + + /** + * Return the name for this Store, used for logging. + */ + public String getStoreName() { + return (storeName); + } + + /** + * Set the driver for this Store. + * + * @param driverName The new driver + */ + public void setDriverName(String driverName) { + String oldDriverName = this.driverName; + this.driverName = driverName; + support.firePropertyChange("driverName", + oldDriverName, + this.driverName); + this.driverName = driverName; + } + + /** + * Return the driver for this Store. + */ + public String getDriverName() { + return (this.driverName); + } + + /** + * Return the username to use to connect to the database. + * + */ + public String getConnectionName() { + return connectionName; + } + + /** + * Set the username to use to connect to the database. + * + * @param connectionName Username + */ + public void setConnectionName(String connectionName) { + this.connectionName = connectionName; + } + + /** + * Return the password to use to connect to the database. + * + */ + public String getConnectionPassword() { + return connectionPassword; + } + + /** + * Set the password to use to connect to the database. + * + * @param connectionPassword User password + */ + public void setConnectionPassword(String connectionPassword) { + this.connectionPassword = connectionPassword; + } + + /** + * Set the Connection URL for this Store. + * + * @param connectionURL The new Connection URL + */ + public void setConnectionURL(String connectionURL) { + String oldConnString = this.connectionURL; + this.connectionURL = connectionURL; + support.firePropertyChange("connectionURL", + oldConnString, + this.connectionURL); + } + + /** + * Return the Connection URL for this Store. + */ + public String getConnectionURL() { + return (this.connectionURL); + } + + /** + * Set the table for this Store. + * + * @param sessionTable The new table + */ + public void setSessionTable(String sessionTable) { + String oldSessionTable = this.sessionTable; + this.sessionTable = sessionTable; + support.firePropertyChange("sessionTable", + oldSessionTable, + this.sessionTable); + } + + /** + * Return the table for this Store. + */ + public String getSessionTable() { + return (this.sessionTable); + } + + /** + * Set the App column for the table. + * + * @param sessionAppCol the column name + */ + public void setSessionAppCol(String sessionAppCol) { + String oldSessionAppCol = this.sessionAppCol; + this.sessionAppCol = sessionAppCol; + support.firePropertyChange("sessionAppCol", + oldSessionAppCol, + this.sessionAppCol); + } + + /** + * Return the web application name column for the table. + */ + public String getSessionAppCol() { + return (this.sessionAppCol); + } + + /** + * Set the Id column for the table. + * + * @param sessionIdCol the column name + */ + public void setSessionIdCol(String sessionIdCol) { + String oldSessionIdCol = this.sessionIdCol; + this.sessionIdCol = sessionIdCol; + support.firePropertyChange("sessionIdCol", + oldSessionIdCol, + this.sessionIdCol); + } + + /** + * Return the Id column for the table. + */ + public String getSessionIdCol() { + return (this.sessionIdCol); + } + + /** + * Set the Data column for the table + * + * @param sessionDataCol the column name + */ + public void setSessionDataCol(String sessionDataCol) { + String oldSessionDataCol = this.sessionDataCol; + this.sessionDataCol = sessionDataCol; + support.firePropertyChange("sessionDataCol", + oldSessionDataCol, + this.sessionDataCol); + } + + /** + * Return the data column for the table + */ + public String getSessionDataCol() { + return (this.sessionDataCol); + } + + /** + * Set the Is Valid column for the table + * + * @param sessionValidCol The column name + */ + public void setSessionValidCol(String sessionValidCol) { + String oldSessionValidCol = this.sessionValidCol; + this.sessionValidCol = sessionValidCol; + support.firePropertyChange("sessionValidCol", + oldSessionValidCol, + this.sessionValidCol); + } + + /** + * Return the Is Valid column + */ + public String getSessionValidCol() { + return (this.sessionValidCol); + } + + /** + * Set the Max Inactive column for the table + * + * @param sessionMaxInactiveCol The column name + */ + public void setSessionMaxInactiveCol(String sessionMaxInactiveCol) { + String oldSessionMaxInactiveCol = this.sessionMaxInactiveCol; + this.sessionMaxInactiveCol = sessionMaxInactiveCol; + support.firePropertyChange("sessionMaxInactiveCol", + oldSessionMaxInactiveCol, + this.sessionMaxInactiveCol); + } + + /** + * Return the Max Inactive column + */ + public String getSessionMaxInactiveCol() { + return (this.sessionMaxInactiveCol); + } + + /** + * Set the Last Accessed column for the table + * + * @param sessionLastAccessedCol The column name + */ + public void setSessionLastAccessedCol(String sessionLastAccessedCol) { + String oldSessionLastAccessedCol = this.sessionLastAccessedCol; + this.sessionLastAccessedCol = sessionLastAccessedCol; + support.firePropertyChange("sessionLastAccessedCol", + oldSessionLastAccessedCol, + this.sessionLastAccessedCol); + } + + /** + * Return the Last Accessed column + */ + public String getSessionLastAccessedCol() { + return (this.sessionLastAccessedCol); + } + + // --------------------------------------------------------- Public Methods + + /** + * Return an array containing the session identifiers of all Sessions + * currently saved in this Store. If there are no such Sessions, a + * zero-length array is returned. + * + * @exception IOException if an input/output error occurred + */ + public String[] keys() throws IOException { + ResultSet rst = null; + String keys[] = null; + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + + Connection _conn = getConnection(); + if (_conn == null) { + return (new String[0]); + } + try { + if (preparedKeysSql == null) { + String keysSql = "SELECT " + sessionIdCol + " FROM " + + sessionTable + " WHERE " + sessionAppCol + + " = ?"; + preparedKeysSql = _conn.prepareStatement(keysSql); + } + + preparedKeysSql.setString(1, getName()); + rst = preparedKeysSql.executeQuery(); + ArrayList tmpkeys = new ArrayList(); + if (rst != null) { + while (rst.next()) { + tmpkeys.add(rst.getString(1)); + } + } + keys = (String[]) tmpkeys.toArray(new String[tmpkeys.size()]); + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + keys = new String[0]; + // Close the connection so that it gets reopened next time + if (dbConnection != null) + close(dbConnection); + } finally { + try { + if (rst != null) { + rst.close(); + } + } catch (SQLException e) { + ; + } + + release(_conn); + } + numberOfTries--; + } + } + + return (keys); + } + + /** + * Return an integer containing a count of all Sessions + * currently saved in this Store. If there are no Sessions, + * 0 is returned. + * + * @exception IOException if an input/output error occurred + */ + public int getSize() throws IOException { + int size = 0; + ResultSet rst = null; + + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + Connection _conn = getConnection(); + + if (_conn == null) { + return (size); + } + + try { + if (preparedSizeSql == null) { + String sizeSql = "SELECT COUNT(" + sessionIdCol + + ") FROM " + sessionTable + " WHERE " + + sessionAppCol + " = ?"; + preparedSizeSql = _conn.prepareStatement(sizeSql); + } + + preparedSizeSql.setString(1, getName()); + rst = preparedSizeSql.executeQuery(); + if (rst.next()) { + size = rst.getInt(1); + } + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + if (dbConnection != null) + close(dbConnection); + } finally { + try { + if (rst != null) + rst.close(); + } catch (SQLException e) { + ; + } + + release(_conn); + } + numberOfTries--; + } + } + return (size); + } + + /** + * Load the Session associated with the id id. + * If no such session is found null is returned. + * + * @param id a value of type String + * @return the stored Session + * @exception ClassNotFoundException if an error occurs + * @exception IOException if an input/output error occurred + */ + public Session load(String id) + throws ClassNotFoundException, IOException { + ResultSet rst = null; + StandardSession _session = null; + Loader loader = null; + ClassLoader classLoader = null; + ObjectInputStream ois = null; + BufferedInputStream bis = null; + Container container = manager.getContainer(); + + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + Connection _conn = getConnection(); + if (_conn == null) { + return (null); + } + + try { + if (preparedLoadSql == null) { + String loadSql = "SELECT " + sessionIdCol + ", " + + sessionDataCol + " FROM " + sessionTable + + " WHERE " + sessionIdCol + " = ? AND " + + sessionAppCol + " = ?"; + preparedLoadSql = _conn.prepareStatement(loadSql); + } + + preparedLoadSql.setString(1, id); + preparedLoadSql.setString(2, getName()); + rst = preparedLoadSql.executeQuery(); + if (rst.next()) { + bis = new BufferedInputStream(rst.getBinaryStream(2)); + + if (container != null) { + loader = container.getLoader(); + } + if (loader != null) { + classLoader = loader.getClassLoader(); + } + if (classLoader != null) { + ois = new CustomObjectInputStream(bis, + classLoader); + } else { + ois = new ObjectInputStream(bis); + } + + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".loading", + id, sessionTable)); + } + + _session = (StandardSession) manager.createEmptySession(); + _session.readObjectData(ois); + _session.setManager(manager); + } else if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(getStoreName() + ": No persisted data object found"); + } + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + if (dbConnection != null) + close(dbConnection); + } finally { + try { + if (rst != null) { + rst.close(); + } + } catch (SQLException e) { + ; + } + if (ois != null) { + try { + ois.close(); + } catch (IOException e) { + ; + } + } + release(_conn); + } + numberOfTries--; + } + } + + return (_session); + } + + /** + * Remove the Session with the specified session identifier from + * this Store, if present. If no such Session is present, this method + * takes no action. + * + * @param id Session identifier of the Session to be removed + * + * @exception IOException if an input/output error occurs + */ + public void remove(String id) throws IOException { + + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + Connection _conn = getConnection(); + + if (_conn == null) { + return; + } + + try { + if (preparedRemoveSql == null) { + String removeSql = "DELETE FROM " + sessionTable + + " WHERE " + sessionIdCol + " = ? AND " + + sessionAppCol + " = ?"; + preparedRemoveSql = _conn.prepareStatement(removeSql); + } + + preparedRemoveSql.setString(1, id); + preparedRemoveSql.setString(2, getName()); + preparedRemoveSql.execute(); + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + if (dbConnection != null) + close(dbConnection); + } finally { + release(_conn); + } + numberOfTries--; + } + } + + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".removing", id, sessionTable)); + } + } + + /** + * Remove all of the Sessions in this Store. + * + * @exception IOException if an input/output error occurs + */ + public void clear() throws IOException { + + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + Connection _conn = getConnection(); + if (_conn == null) { + return; + } + + try { + if (preparedClearSql == null) { + String clearSql = "DELETE FROM " + sessionTable + + " WHERE " + sessionAppCol + " = ?"; + preparedClearSql = _conn.prepareStatement(clearSql); + } + + preparedClearSql.setString(1, getName()); + preparedClearSql.execute(); + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + if (dbConnection != null) + close(dbConnection); + } finally { + release(_conn); + } + numberOfTries--; + } + } + } + + /** + * Save a session to the Store. + * + * @param session the session to be stored + * @exception IOException if an input/output error occurs + */ + public void save(Session session) throws IOException { + ObjectOutputStream oos = null; + ByteArrayOutputStream bos = null; + ByteArrayInputStream bis = null; + InputStream in = null; + + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries > 0) { + Connection _conn = getConnection(); + if (_conn == null) { + return; + } + + // If sessions already exist in DB, remove and insert again. + // TODO: + // * Check if ID exists in database and if so use UPDATE. + remove(session.getIdInternal()); + + try { + bos = new ByteArrayOutputStream(); + oos = new ObjectOutputStream(new BufferedOutputStream(bos)); + + ((StandardSession) session).writeObjectData(oos); + oos.close(); + oos = null; + byte[] obs = bos.toByteArray(); + int size = obs.length; + bis = new ByteArrayInputStream(obs, 0, size); + in = new BufferedInputStream(bis, size); + + if (preparedSaveSql == null) { + String saveSql = "INSERT INTO " + sessionTable + " (" + + sessionIdCol + ", " + sessionAppCol + ", " + + sessionDataCol + ", " + sessionValidCol + + ", " + sessionMaxInactiveCol + ", " + + sessionLastAccessedCol + + ") VALUES (?, ?, ?, ?, ?, ?)"; + preparedSaveSql = _conn.prepareStatement(saveSql); + } + + preparedSaveSql.setString(1, session.getIdInternal()); + preparedSaveSql.setString(2, getName()); + preparedSaveSql.setBinaryStream(3, in, size); + preparedSaveSql.setString(4, session.isValid() ? "1" : "0"); + preparedSaveSql.setInt(5, session.getMaxInactiveInterval()); + preparedSaveSql.setLong(6, session.getLastAccessedTime()); + preparedSaveSql.execute(); + // Break out after the finally block + numberOfTries = 0; + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".SQLException", e)); + if (dbConnection != null) + close(dbConnection); + } catch (IOException e) { + ; + } finally { + if (oos != null) { + oos.close(); + } + if (bis != null) { + bis.close(); + } + if (in != null) { + in.close(); + } + + release(_conn); + } + numberOfTries--; + } + } + + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(sm.getString(getStoreName() + ".saving", + session.getIdInternal(), sessionTable)); + } + } + + // --------------------------------------------------------- Protected Methods + + /** + * Check the connection associated with this store, if it's + * null or closed try to reopen it. + * Returns null if the connection could not be established. + * + * @return Connection if the connection suceeded + */ + protected Connection getConnection() { + try { + if (dbConnection == null || dbConnection.isClosed()) { + manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBClosed")); + open(); + if (dbConnection == null || dbConnection.isClosed()) { + manager.getContainer().getLogger().info(sm.getString(getStoreName() + ".checkConnectionDBReOpenFail")); + } + } + } catch (SQLException ex) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionSQLException", + ex.toString())); + } + + return dbConnection; + } + + /** + * Open (if necessary) and return a database connection for use by + * this Realm. + * + * @exception SQLException if a database error occurs + */ + protected Connection open() throws SQLException { + + // Do nothing if there is a database connection already open + if (dbConnection != null) + return (dbConnection); + + // Instantiate our database driver if necessary + if (driver == null) { + try { + Class clazz = Class.forName(driverName); + driver = (Driver) clazz.newInstance(); + } catch (ClassNotFoundException ex) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", + ex.toString())); + } catch (InstantiationException ex) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", + ex.toString())); + } catch (IllegalAccessException ex) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".checkConnectionClassNotFoundException", + ex.toString())); + } + } + + // Open a new connection + Properties props = new Properties(); + if (connectionName != null) + props.put("user", connectionName); + if (connectionPassword != null) + props.put("password", connectionPassword); + dbConnection = driver.connect(connectionURL, props); + dbConnection.setAutoCommit(true); + return (dbConnection); + + } + + /** + * Close the specified database connection. + * + * @param dbConnection The connection to be closed + */ + protected void close(Connection dbConnection) { + + // Do nothing if the database connection is already closed + if (dbConnection == null) + return; + + // Close our prepared statements (if any) + try { + preparedSizeSql.close(); + } catch (Throwable f) { + ; + } + this.preparedSizeSql = null; + + try { + preparedKeysSql.close(); + } catch (Throwable f) { + ; + } + this.preparedKeysSql = null; + + try { + preparedSaveSql.close(); + } catch (Throwable f) { + ; + } + this.preparedSaveSql = null; + + try { + preparedClearSql.close(); + } catch (Throwable f) { + ; + } + + try { + preparedRemoveSql.close(); + } catch (Throwable f) { + ; + } + this.preparedRemoveSql = null; + + try { + preparedLoadSql.close(); + } catch (Throwable f) { + ; + } + this.preparedLoadSql = null; + + // Close this database connection, and log any errors + try { + dbConnection.close(); + } catch (SQLException e) { + manager.getContainer().getLogger().error(sm.getString(getStoreName() + ".close", e.toString())); // Just log it here + } finally { + this.dbConnection = null; + } + + } + + /** + * Release the connection, not needed here since the + * connection is not associated with a connection pool. + * + * @param conn The connection to be released + */ + protected void release(Connection conn) { + ; + } + + /** + * Called once when this Store is first started. + */ + public void start() throws LifecycleException { + super.start(); + + // Open connection to the database + this.dbConnection = getConnection(); + } + + /** + * Gracefully terminate everything associated with our db. + * Called once when this Store is stoping. + * + */ + public void stop() throws LifecycleException { + super.stop(); + + // Close and release everything associated with our db. + if (dbConnection != null) { + try { + dbConnection.commit(); + } catch (SQLException e) { + ; + } + close(dbConnection); + } + } +} diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties index 288fb0346..705a62a3a 100644 --- a/java/org/apache/catalina/session/LocalStrings.properties +++ b/java/org/apache/catalina/session/LocalStrings.properties @@ -1,67 +1,67 @@ -applicationSession.session.ise=invalid session state -applicationSession.value.iae=null value -fileStore.alreadyStarted=File Store has already been started -fileStore.notStarted=File Store has not yet been started -fileStore.saving=Saving Session {0} to file {1} -fileStore.loading=Loading Session {0} from file {1} -fileStore.removing=Removing Session {0} at file {1} -JDBCStore.alreadyStarted=JDBC Store has already been started -JDBCStore.close=Exception closing database connection {0} -JDBCStore.notStarted=JDBC Store has not yet been started -JDBCStore.saving=Saving Session {0} to database {1} -JDBCStore.loading=Loading Session {0} from database {1} -JDBCStore.removing=Removing Session {0} at database {1} -JDBCStore.SQLException=SQL Error {0} -JDBCStore.checkConnectionDBClosed=The database connection is null or was found to be closed. Trying to re-open it. -JDBCStore.checkConnectionDBReOpenFail=The re-open on the database failed. The database could be down. -JDBCStore.checkConnectionSQLException=A SQL exception occurred {0} -JDBCStore.checkConnectionClassNotFoundException=JDBC driver class not found {0} -managerBase.complete=Seeding of random number generator has been completed -managerBase.getting=Getting message digest component for algorithm {0} -managerBase.gotten=Completed getting message digest component -managerBase.random=Exception initializing random number generator of class {0} -managerBase.seeding=Seeding random number generator class {0} -serverSession.value.iae=null value -standardManager.alreadyStarted=Manager has already been started -standardManager.createSession.ise=createSession: Too many active sessions -standardManager.expireException=processsExpire: Exception during session expiration -standardManager.loading=Loading persisted sessions from {0} -standardManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0} -standardManager.loading.ioe=IOException while loading persisted sessions: {0} -standardManager.notStarted=Manager has not yet been started -standardManager.sessionTimeout=Invalid session timeout setting {0} -standardManager.unloading=Saving persisted sessions to {0} -standardManager.unloading.ioe=IOException while saving persisted sessions: {0} -standardManager.managerLoad=Exception loading sessions from persistent storage -standardManager.managerUnload=Exception unloading sessions to persistent storage -standardSession.attributeEvent=Session attribute event listener threw exception -standardSession.bindingEvent=Session binding event listener threw exception -standardSession.invalidate.ise=invalidate: Session already invalidated -standardSession.isNew.ise=isNew: Session already invalidated -standardSession.getAttribute.ise=getAttribute: Session already invalidated -standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated -standardSession.getCreationTime.ise=getCreationTime: Session already invalidated -standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated -standardSession.getId.ise=getId: Session already invalidated -standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated -standardSession.getValueNames.ise=getValueNames: Session already invalidated -standardSession.notSerializable=Cannot serialize session attribute {0} for session {1} -standardSession.removeAttribute.ise=removeAttribute: Session already invalidated -standardSession.sessionEvent=Session event listener threw exception -standardSession.setAttribute.iae=setAttribute: Non-serializable attribute -standardSession.setAttribute.ise=setAttribute: Session already invalidated -standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null -standardSession.sessionCreated=Created Session id = {0} -persistentManager.loading=Loading {0} persisted sessions -persistentManager.unloading=Saving {0} persisted sessions -persistentManager.expiring=Expiring {0} sessions before saving them -persistentManager.deserializeError=Error deserializing Session {0}: {1} -persistentManager.serializeError=Error serializing Session {0}: {1} -persistentManager.swapMaxIdle=Swapping session {0} to Store, idle for {1} seconds -persistentManager.backupMaxIdle=Backing up session {0} to Store, idle for {1} seconds -persistentManager.backupException=Exception occurred when backing up Session {0}: {1} -persistentManager.tooManyActive=Too many active sessions, {0}, looking for idle sessions to swap out -persistentManager.swapTooManyActive=Swapping out session {0}, idle for {1} seconds too many sessions active -persistentManager.processSwaps=Checking for sessions to swap out, {0} active sessions in memory -persistentManager.activeSession=Session {0} has been idle for {1} seconds -persistentManager.swapIn=Swapping session {0} in from Store +applicationSession.session.ise=invalid session state +applicationSession.value.iae=null value +fileStore.alreadyStarted=File Store has already been started +fileStore.notStarted=File Store has not yet been started +fileStore.saving=Saving Session {0} to file {1} +fileStore.loading=Loading Session {0} from file {1} +fileStore.removing=Removing Session {0} at file {1} +JDBCStore.alreadyStarted=JDBC Store has already been started +JDBCStore.close=Exception closing database connection {0} +JDBCStore.notStarted=JDBC Store has not yet been started +JDBCStore.saving=Saving Session {0} to database {1} +JDBCStore.loading=Loading Session {0} from database {1} +JDBCStore.removing=Removing Session {0} at database {1} +JDBCStore.SQLException=SQL Error {0} +JDBCStore.checkConnectionDBClosed=The database connection is null or was found to be closed. Trying to re-open it. +JDBCStore.checkConnectionDBReOpenFail=The re-open on the database failed. The database could be down. +JDBCStore.checkConnectionSQLException=A SQL exception occurred {0} +JDBCStore.checkConnectionClassNotFoundException=JDBC driver class not found {0} +managerBase.complete=Seeding of random number generator has been completed +managerBase.getting=Getting message digest component for algorithm {0} +managerBase.gotten=Completed getting message digest component +managerBase.random=Exception initializing random number generator of class {0} +managerBase.seeding=Seeding random number generator class {0} +serverSession.value.iae=null value +standardManager.alreadyStarted=Manager has already been started +standardManager.createSession.ise=createSession: Too many active sessions +standardManager.expireException=processsExpire: Exception during session expiration +standardManager.loading=Loading persisted sessions from {0} +standardManager.loading.cnfe=ClassNotFoundException while loading persisted sessions: {0} +standardManager.loading.ioe=IOException while loading persisted sessions: {0} +standardManager.notStarted=Manager has not yet been started +standardManager.sessionTimeout=Invalid session timeout setting {0} +standardManager.unloading=Saving persisted sessions to {0} +standardManager.unloading.ioe=IOException while saving persisted sessions: {0} +standardManager.managerLoad=Exception loading sessions from persistent storage +standardManager.managerUnload=Exception unloading sessions to persistent storage +standardSession.attributeEvent=Session attribute event listener threw exception +standardSession.bindingEvent=Session binding event listener threw exception +standardSession.invalidate.ise=invalidate: Session already invalidated +standardSession.isNew.ise=isNew: Session already invalidated +standardSession.getAttribute.ise=getAttribute: Session already invalidated +standardSession.getAttributeNames.ise=getAttributeNames: Session already invalidated +standardSession.getCreationTime.ise=getCreationTime: Session already invalidated +standardSession.getLastAccessedTime.ise=getLastAccessedTime: Session already invalidated +standardSession.getId.ise=getId: Session already invalidated +standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: Session already invalidated +standardSession.getValueNames.ise=getValueNames: Session already invalidated +standardSession.notSerializable=Cannot serialize session attribute {0} for session {1} +standardSession.removeAttribute.ise=removeAttribute: Session already invalidated +standardSession.sessionEvent=Session event listener threw exception +standardSession.setAttribute.iae=setAttribute: Non-serializable attribute +standardSession.setAttribute.ise=setAttribute: Session already invalidated +standardSession.setAttribute.namenull=setAttribute: name parameter cannot be null +standardSession.sessionCreated=Created Session id = {0} +persistentManager.loading=Loading {0} persisted sessions +persistentManager.unloading=Saving {0} persisted sessions +persistentManager.expiring=Expiring {0} sessions before saving them +persistentManager.deserializeError=Error deserializing Session {0}: {1} +persistentManager.serializeError=Error serializing Session {0}: {1} +persistentManager.swapMaxIdle=Swapping session {0} to Store, idle for {1} seconds +persistentManager.backupMaxIdle=Backing up session {0} to Store, idle for {1} seconds +persistentManager.backupException=Exception occurred when backing up Session {0}: {1} +persistentManager.tooManyActive=Too many active sessions, {0}, looking for idle sessions to swap out +persistentManager.swapTooManyActive=Swapping out session {0}, idle for {1} seconds too many sessions active +persistentManager.processSwaps=Checking for sessions to swap out, {0} active sessions in memory +persistentManager.activeSession=Session {0} has been idle for {1} seconds +persistentManager.swapIn=Swapping session {0} in from Store diff --git a/java/org/apache/catalina/session/LocalStrings_es.properties b/java/org/apache/catalina/session/LocalStrings_es.properties index a8d011b34..e9027986b 100644 --- a/java/org/apache/catalina/session/LocalStrings_es.properties +++ b/java/org/apache/catalina/session/LocalStrings_es.properties @@ -1,66 +1,66 @@ -applicationSession.session.ise=estado inválido de sesión -applicationSession.value.iae=valor nulo -fileStore.alreadyStarted=Ya ha sido arrancado el Almacén de Archivos -fileStore.notStarted=Aún no se ha arrancado el Almacén de Archivos -fileStore.saving=Salvando Sesión {0} en archivo {1} -fileStore.loading=Cargando Sesión {0} desde archivo {1} -fileStore.removing=Quitando Sesión {0} en archivo {1} -JDBCStore.alreadyStarted=Ya ha sido arrancado el Almacén JDBC -JDBCStore.close=Excepción cerrando conexión a base de datos {0} -JDBCStore.notStarted=Aún no se ha arrancado el Almacén JDBC -JDBCStore.saving=Salvando Sesión {0} en base de datos {1} -JDBCStore.loading=Cargando Sesión {0} desde base de datos {1} -JDBCStore.removing=Quitando Sesión {0} en base de datos {1} -JDBCStore.SQLException=Error SQL {0} -JDBCStore.checkConnectionDBClosed=La conexióna a base de datos es nula o está cerrada. Intentando reabrirla. -JDBCStore.checkConnectionDBReOpenFail=Falló la reapertura de la base de datos. Puede que la base de datos esté caída. -JDBCStore.checkConnectionSQLException=Ha tenido lugar una excepción SQL {0} -JDBCStore.checkConnectionClassNotFoundException=No se ha hallado la clase del manejador (driver) JDBC {0} -managerBase.complete=Se ha completado la siembra del generador de números aleatorios -managerBase.getting=Obteniendo mensaje de componente de resumen (digest) para algoritmo {0} -managerBase.gotten=Completada la obtención de mensaje de componente de resumen (digest) -managerBase.random=Excepción inicializando generador de números aleatorios de clase {0} -managerBase.seeding=Sembrando clase de generador de números aleatorios {0} -serverSession.value.iae=valor nulo -standardManager.alreadyStarted=Ya ha sido arrancado el Gestor -standardManager.createSession.ise=createSession: Demasiadas sesiones activas -standardManager.expireException=processsExpire: Excepción durante la expiración de sesión -standardManager.loading=Cargando sesiones persistidas desde {0} -standardManager.loading.cnfe=ClassNotFoundException al cargar sesiones persistidas: {0} -standardManager.loading.ioe=IOException al cargar sesiones persistidas: {0} -standardManager.notStarted=Aún no se ha arrancado el Gestor -standardManager.sessionTimeout=Valor inválido de Tiempo Agotado de sesión {0} -standardManager.unloading=Salvando sesiones persistidas a {0} -standardManager.unloading.ioe=IOException al salvar sesiones persistidas: {0} -standardManager.managerLoad=Excepción cargando sesiones desde almacenamiento persistente -standardManager.managerUnload=Excepción descargando sesiones a almacenamiento persistente -standardSession.attributeEvent=El escuchador de eventos de atributo de Sesión lanzó una excepción -standardSession.invalidate.ise=invalidate: La Sesión ya ha sido invalidada -standardSession.isNew.ise=isNew: La Sesión ya ha sido invalidada -standardSession.getAttribute.ise=getAttribute: La Sesión ya ha sido invalidada -standardSession.getAttributeNames.ise=getAttributeNames: La Sesión ya ha sido invalidada -standardSession.getCreationTime.ise=getCreationTime: La Sesión ya ha sido invalidada -standardSession.getLastAccessedTime.ise=getLastAccessedTime: La Sesión ya ha sido invalidada -standardSession.getId.ise=getId: La Sesión ya ha sido invalidada -standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: La Sesión ya ha sido invalidada -standardSession.getValueNames.ise=getValueNames: La Sesión ya ha sido invalidada -standardSession.notSerializable=No puedo serializar atributo de sesión {0} para sesión {1} -standardSession.removeAttribute.ise=removeAttribute: La Sesión ya ha sido invalidada -standardSession.sessionEvent=El escuchador de evento de Sesión lanzó una execpción -standardSession.setAttribute.iae=setAttribute: Atributo no serializable -standardSession.setAttribute.ise=setAttribute: La Sesión ya ha sido invalidada -standardSession.setAttribute.namenull=setAttribute: el nuevo parámetro no puede ser nulo -standardSession.sessionCreated=Creada Sesión id = {0} -persistentManager.loading=Cargando {0} sesiones persistidas -persistentManager.unloading=Salvando {0} sesiones persistidas -persistentManager.expiring=Expirando {0} sesiones antes de salvarlas -persistentManager.deserializeError=Error des-serializando Sesión {0}: {1} -persistentManager.serializeError=Error serializando Sesión {0}: {1} -persistentManager.swapMaxIdle=Intercambiando sesión {0} a fuera a Almacén, ociosa durante {1} segundos -persistentManager.backupMaxIdle=Respaldando sesión {0} a Almacén, ociosa durante {1} segundos -persistentManager.backupException=Ha tenido lugar una excepción al respaldar la Sesión {0}: {1} -persistentManager.tooManyActive=Demasiadas sesiones activas, {0}, buscando sesiones ociosas para intercambiar -persistentManager.swapTooManyActive=Intercambiando sesión {0} a fuera, ociosa durante {1} segundos: Demasiadas sesiones activas -persistentManager.processSwaps=Mirando qué sesiones intercambiar a fuera, {0} sesiones activas en memoria -persistentManager.activeSession=La sesión {0} ha estado ociosa durante {1} segundos -persistentManager.swapIn=Intercambiando sesión {0} a dentro desde Almacén +applicationSession.session.ise=estado inválido de sesión +applicationSession.value.iae=valor nulo +fileStore.alreadyStarted=Ya ha sido arrancado el Almacén de Archivos +fileStore.notStarted=Aún no se ha arrancado el Almacén de Archivos +fileStore.saving=Salvando Sesión {0} en archivo {1} +fileStore.loading=Cargando Sesión {0} desde archivo {1} +fileStore.removing=Quitando Sesión {0} en archivo {1} +JDBCStore.alreadyStarted=Ya ha sido arrancado el Almacén JDBC +JDBCStore.close=Excepción cerrando conexión a base de datos {0} +JDBCStore.notStarted=Aún no se ha arrancado el Almacén JDBC +JDBCStore.saving=Salvando Sesión {0} en base de datos {1} +JDBCStore.loading=Cargando Sesión {0} desde base de datos {1} +JDBCStore.removing=Quitando Sesión {0} en base de datos {1} +JDBCStore.SQLException=Error SQL {0} +JDBCStore.checkConnectionDBClosed=La conexióna a base de datos es nula o está cerrada. Intentando reabrirla. +JDBCStore.checkConnectionDBReOpenFail=Falló la reapertura de la base de datos. Puede que la base de datos esté caída. +JDBCStore.checkConnectionSQLException=Ha tenido lugar una excepción SQL {0} +JDBCStore.checkConnectionClassNotFoundException=No se ha hallado la clase del manejador (driver) JDBC {0} +managerBase.complete=Se ha completado la siembra del generador de números aleatorios +managerBase.getting=Obteniendo mensaje de componente de resumen (digest) para algoritmo {0} +managerBase.gotten=Completada la obtención de mensaje de componente de resumen (digest) +managerBase.random=Excepción inicializando generador de números aleatorios de clase {0} +managerBase.seeding=Sembrando clase de generador de números aleatorios {0} +serverSession.value.iae=valor nulo +standardManager.alreadyStarted=Ya ha sido arrancado el Gestor +standardManager.createSession.ise=createSession: Demasiadas sesiones activas +standardManager.expireException=processsExpire: Excepción durante la expiración de sesión +standardManager.loading=Cargando sesiones persistidas desde {0} +standardManager.loading.cnfe=ClassNotFoundException al cargar sesiones persistidas: {0} +standardManager.loading.ioe=IOException al cargar sesiones persistidas: {0} +standardManager.notStarted=Aún no se ha arrancado el Gestor +standardManager.sessionTimeout=Valor inválido de Tiempo Agotado de sesión {0} +standardManager.unloading=Salvando sesiones persistidas a {0} +standardManager.unloading.ioe=IOException al salvar sesiones persistidas: {0} +standardManager.managerLoad=Excepción cargando sesiones desde almacenamiento persistente +standardManager.managerUnload=Excepción descargando sesiones a almacenamiento persistente +standardSession.attributeEvent=El escuchador de eventos de atributo de Sesión lanzó una excepción +standardSession.invalidate.ise=invalidate: La Sesión ya ha sido invalidada +standardSession.isNew.ise=isNew: La Sesión ya ha sido invalidada +standardSession.getAttribute.ise=getAttribute: La Sesión ya ha sido invalidada +standardSession.getAttributeNames.ise=getAttributeNames: La Sesión ya ha sido invalidada +standardSession.getCreationTime.ise=getCreationTime: La Sesión ya ha sido invalidada +standardSession.getLastAccessedTime.ise=getLastAccessedTime: La Sesión ya ha sido invalidada +standardSession.getId.ise=getId: La Sesión ya ha sido invalidada +standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: La Sesión ya ha sido invalidada +standardSession.getValueNames.ise=getValueNames: La Sesión ya ha sido invalidada +standardSession.notSerializable=No puedo serializar atributo de sesión {0} para sesión {1} +standardSession.removeAttribute.ise=removeAttribute: La Sesión ya ha sido invalidada +standardSession.sessionEvent=El escuchador de evento de Sesión lanzó una execpción +standardSession.setAttribute.iae=setAttribute: Atributo no serializable +standardSession.setAttribute.ise=setAttribute: La Sesión ya ha sido invalidada +standardSession.setAttribute.namenull=setAttribute: el nuevo parámetro no puede ser nulo +standardSession.sessionCreated=Creada Sesión id = {0} +persistentManager.loading=Cargando {0} sesiones persistidas +persistentManager.unloading=Salvando {0} sesiones persistidas +persistentManager.expiring=Expirando {0} sesiones antes de salvarlas +persistentManager.deserializeError=Error des-serializando Sesión {0}: {1} +persistentManager.serializeError=Error serializando Sesión {0}: {1} +persistentManager.swapMaxIdle=Intercambiando sesión {0} a fuera a Almacén, ociosa durante {1} segundos +persistentManager.backupMaxIdle=Respaldando sesión {0} a Almacén, ociosa durante {1} segundos +persistentManager.backupException=Ha tenido lugar una excepción al respaldar la Sesión {0}: {1} +persistentManager.tooManyActive=Demasiadas sesiones activas, {0}, buscando sesiones ociosas para intercambiar +persistentManager.swapTooManyActive=Intercambiando sesión {0} a fuera, ociosa durante {1} segundos: Demasiadas sesiones activas +persistentManager.processSwaps=Mirando qué sesiones intercambiar a fuera, {0} sesiones activas en memoria +persistentManager.activeSession=La sesión {0} ha estado ociosa durante {1} segundos +persistentManager.swapIn=Intercambiando sesión {0} a dentro desde Almacén diff --git a/java/org/apache/catalina/session/LocalStrings_fr.properties b/java/org/apache/catalina/session/LocalStrings_fr.properties index 74e0e6b20..3c9b6906f 100644 --- a/java/org/apache/catalina/session/LocalStrings_fr.properties +++ b/java/org/apache/catalina/session/LocalStrings_fr.properties @@ -1,65 +1,65 @@ -applicationSession.session.ise=état de session invalide -applicationSession.value.iae=valeur nulle -fileStore.alreadyStarted=Le "File Store" a déjà été démarré -fileStore.notStarted=Le "File Store" n''a pas encore été démarré -fileStore.saving=Sauvegarde de la Session {0} vers le fichier {1} -fileStore.loading=Chargement de la Session {0} depuis le fichier {1} -fileStore.removing=Retrait de la Session {0} du fichier {1} -JDBCStore.alreadyStarted=Le "JDBC Store" a déjà été démarré -JDBCStore.notStarted=Le "JDBC Store" n''a pas encore été démarré -JDBCStore.saving=Sauvegarde de la Session {0} vers la base de données {1} -JDBCStore.loading=Chargement de la Session {0} depuis la base de données {1} -JDBCStore.removing=Retrait de la Session {0} de la base de données {1} -JDBCStore.SQLException=Erreur SQL {0} -JDBCStore.checkConnectionDBClosed=La connexion à la base de données est nulle ou a été trouvé fermé. Tentative de réouverture. -JDBCStore.checkConnectionDBReOpenFail=La tentative de réouverture re-open de la base de données a échoué. La base de données est peut être arrétée. -JDBCStore.checkConnectionSQLException=Une exception SQL s''est produite {0} -JDBCStore.checkConnectionClassNotFoundException=La classe du driver JDBC n''a pas été trouvée {0} -managerBase.complete=L''alimentation du générateur de nombre aléatoire est terminé -managerBase.getting=Prise du composant d''algorithme empreinte de message (message digest) pour l''algorithme {0} -managerBase.gotten=Prise du composant d''algorithme empreinte de message (message digest) terminée -managerBase.random=Exception durant l''initialisation de la classe du générateur de nombre aléatoire {0} -managerBase.seeding=Alimentation de la classe du générateur de nombre aléatoire {0} -serverSession.value.iae=valeur nulle -standardManager.alreadyStarted=Le "Manager" a été démarré -standardManager.createSession.ise="createSession": Trop de sessions actives -standardManager.expireException="processsExpire": Exception lors de l''expiration de la session -standardManager.loading=Chargement des sessions qui ont persistés depuis {0} -standardManager.loading.cnfe="ClassNotFoundException" lors du chargement de sessions persistantes: {0} -standardManager.loading.ioe="IOException" lors du chargement des sessions persistantes: {0} -standardManager.notStarted=Le "Manager" n''a pas encore été démarré -standardManager.sessionTimeout=Réglage du délai d''inactivité (timeout) de session invalide {0} -standardManager.unloading=Sauvegarde des sessions ayant persistées vers {0} -standardManager.unloading.ioe="IOException" lors de la sauvegarde de sessions persistantes: {0} -standardManager.managerLoad=Exception au chargement des sessions depuis le stockage persistant (persistent storage) -standardManager.managerUnload=Exception au déchargement des sessions vers le stockage persistant (persistent storage) -standardSession.attributeEvent=L''écouteur d''évènement Attribut de Session (attribute event listener) a généré une exception -standardSession.invalidate.ise="invalidate": Session déjà invalidée -standardSession.isNew.ise="isNew": Session déjà invalidée -standardSession.getAttribute.ise="getAttribute": Session déjà invalidée -standardSession.getAttributeNames.ise="getAttributeNames": Session déjà invalidée -standardSession.getCreationTime.ise="getCreationTime": Session déjà invalidée -standardSession.getLastAccessedTime.ise="getLastAccessedTime": Session d\u00E9j\u00E0 invalid\u00E9e -standardSession.getId.ise=getId: Session déjà invalidée -standardSession.getMaxInactiveInterval.ise="getMaxInactiveInterval": Session déjà invalidée -standardSession.getValueNames.ise="getValueNames": Session déjà invalidée -standardSession.notSerializable=Impossible de sérialiser l''attribut de session {0} pour la session {1} -standardSession.removeAttribute.ise="removeAttribute": Session déjà invalidée -standardSession.sessionEvent=L''écouteur d''évènement de session (session event listener) a généré une exception -standardSession.setAttribute.iae="setAttribute": attribut non sérialisable -standardSession.setAttribute.ise="setAttribute": Session déjà invalidée -standardSession.setAttribute.namenull="setAttribute": le nom de paramètre ne peut être nul -standardSession.sessionCreated=Création de l''Id de Session = {0} -persistentManager.loading=Chargement de {0} sessions persistantes -persistentManager.unloading=Sauvegarde de {0} sessions persistantes -persistentManager.expiring=Expiration de {0} sessions avant leur sauvegarde -persistentManager.deserializeError=Erreur lors de la désérialisation de la session {0}: {1} -persistentManager.serializeError=Erreur lors de la sérialisation de la session {0}: {1} -persistentManager.swapMaxIdle=Basculement de la session {0} vers le stockage (Store), en attente pour {1} secondes -persistentManager.backupMaxIdle=Sauvegarde de la session {0} vers le stockage (Store), en attente pour {1} secondes -persistentManager.backupException=Exception lors de la sauvegarde de la session {0}: {1} -persistentManager.tooManyActive=Trop de sessions actives, {0}, à la recherche de sessions en attente pour basculement vers stockage (swap out) -persistentManager.swapTooManyActive=Basculement vers stockage (swap out) de la session {0}, en attente pour {1} secondes trop de sessions actives -persistentManager.processSwaps=Recherche de sessions à basculer vers stockage (swap out), {0} sessions actives en mémoire -persistentManager.activeSession=La session {0} a été en attente durant {1} secondes -persistentManager.swapIn=Basculement depuis le stockage (swap in) de la session {0} +applicationSession.session.ise=état de session invalide +applicationSession.value.iae=valeur nulle +fileStore.alreadyStarted=Le "File Store" a déjà été démarré +fileStore.notStarted=Le "File Store" n''a pas encore été démarré +fileStore.saving=Sauvegarde de la Session {0} vers le fichier {1} +fileStore.loading=Chargement de la Session {0} depuis le fichier {1} +fileStore.removing=Retrait de la Session {0} du fichier {1} +JDBCStore.alreadyStarted=Le "JDBC Store" a déjà été démarré +JDBCStore.notStarted=Le "JDBC Store" n''a pas encore été démarré +JDBCStore.saving=Sauvegarde de la Session {0} vers la base de données {1} +JDBCStore.loading=Chargement de la Session {0} depuis la base de données {1} +JDBCStore.removing=Retrait de la Session {0} de la base de données {1} +JDBCStore.SQLException=Erreur SQL {0} +JDBCStore.checkConnectionDBClosed=La connexion à la base de données est nulle ou a été trouvé fermé. Tentative de réouverture. +JDBCStore.checkConnectionDBReOpenFail=La tentative de réouverture re-open de la base de données a échoué. La base de données est peut être arrétée. +JDBCStore.checkConnectionSQLException=Une exception SQL s''est produite {0} +JDBCStore.checkConnectionClassNotFoundException=La classe du driver JDBC n''a pas été trouvée {0} +managerBase.complete=L''alimentation du générateur de nombre aléatoire est terminé +managerBase.getting=Prise du composant d''algorithme empreinte de message (message digest) pour l''algorithme {0} +managerBase.gotten=Prise du composant d''algorithme empreinte de message (message digest) terminée +managerBase.random=Exception durant l''initialisation de la classe du générateur de nombre aléatoire {0} +managerBase.seeding=Alimentation de la classe du générateur de nombre aléatoire {0} +serverSession.value.iae=valeur nulle +standardManager.alreadyStarted=Le "Manager" a été démarré +standardManager.createSession.ise="createSession": Trop de sessions actives +standardManager.expireException="processsExpire": Exception lors de l''expiration de la session +standardManager.loading=Chargement des sessions qui ont persistés depuis {0} +standardManager.loading.cnfe="ClassNotFoundException" lors du chargement de sessions persistantes: {0} +standardManager.loading.ioe="IOException" lors du chargement des sessions persistantes: {0} +standardManager.notStarted=Le "Manager" n''a pas encore été démarré +standardManager.sessionTimeout=Réglage du délai d''inactivité (timeout) de session invalide {0} +standardManager.unloading=Sauvegarde des sessions ayant persistées vers {0} +standardManager.unloading.ioe="IOException" lors de la sauvegarde de sessions persistantes: {0} +standardManager.managerLoad=Exception au chargement des sessions depuis le stockage persistant (persistent storage) +standardManager.managerUnload=Exception au déchargement des sessions vers le stockage persistant (persistent storage) +standardSession.attributeEvent=L''écouteur d''évènement Attribut de Session (attribute event listener) a généré une exception +standardSession.invalidate.ise="invalidate": Session déjà invalidée +standardSession.isNew.ise="isNew": Session déjà invalidée +standardSession.getAttribute.ise="getAttribute": Session déjà invalidée +standardSession.getAttributeNames.ise="getAttributeNames": Session déjà invalidée +standardSession.getCreationTime.ise="getCreationTime": Session déjà invalidée +standardSession.getLastAccessedTime.ise="getLastAccessedTime": Session d\u00E9j\u00E0 invalid\u00E9e +standardSession.getId.ise=getId: Session déjà invalidée +standardSession.getMaxInactiveInterval.ise="getMaxInactiveInterval": Session déjà invalidée +standardSession.getValueNames.ise="getValueNames": Session déjà invalidée +standardSession.notSerializable=Impossible de sérialiser l''attribut de session {0} pour la session {1} +standardSession.removeAttribute.ise="removeAttribute": Session déjà invalidée +standardSession.sessionEvent=L''écouteur d''évènement de session (session event listener) a généré une exception +standardSession.setAttribute.iae="setAttribute": attribut non sérialisable +standardSession.setAttribute.ise="setAttribute": Session déjà invalidée +standardSession.setAttribute.namenull="setAttribute": le nom de paramètre ne peut être nul +standardSession.sessionCreated=Création de l''Id de Session = {0} +persistentManager.loading=Chargement de {0} sessions persistantes +persistentManager.unloading=Sauvegarde de {0} sessions persistantes +persistentManager.expiring=Expiration de {0} sessions avant leur sauvegarde +persistentManager.deserializeError=Erreur lors de la désérialisation de la session {0}: {1} +persistentManager.serializeError=Erreur lors de la sérialisation de la session {0}: {1} +persistentManager.swapMaxIdle=Basculement de la session {0} vers le stockage (Store), en attente pour {1} secondes +persistentManager.backupMaxIdle=Sauvegarde de la session {0} vers le stockage (Store), en attente pour {1} secondes +persistentManager.backupException=Exception lors de la sauvegarde de la session {0}: {1} +persistentManager.tooManyActive=Trop de sessions actives, {0}, à la recherche de sessions en attente pour basculement vers stockage (swap out) +persistentManager.swapTooManyActive=Basculement vers stockage (swap out) de la session {0}, en attente pour {1} secondes trop de sessions actives +persistentManager.processSwaps=Recherche de sessions à basculer vers stockage (swap out), {0} sessions actives en mémoire +persistentManager.activeSession=La session {0} a été en attente durant {1} secondes +persistentManager.swapIn=Basculement depuis le stockage (swap in) de la session {0} diff --git a/java/org/apache/catalina/session/LocalStrings_ja.properties b/java/org/apache/catalina/session/LocalStrings_ja.properties index 6e5456379..b5f762193 100644 --- a/java/org/apache/catalina/session/LocalStrings_ja.properties +++ b/java/org/apache/catalina/session/LocalStrings_ja.properties @@ -1,67 +1,67 @@ -applicationSession.session.ise=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u72b6\u614b\u3067\u3059 -applicationSession.value.iae=null\u5024\u3067\u3059 -fileStore.alreadyStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -fileStore.notStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -fileStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 -fileStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 -fileStore.removing=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 -JDBCStore.alreadyStarted=JDBC\u30b9\u30c8\u30a2\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -JDBCStore.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a {0} \u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -JDBCStore.notStarted=JDBC\u30b9\u30c8\u30a2\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u307e\u305b\u3093 -JDBCStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 -JDBCStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 -JDBCStore.removing= \u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 -JDBCStore.SQLException=SQL\u30a8\u30e9\u30fc {0} -JDBCStore.checkConnectionDBClosed=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u304cnull\u3067\u3042\u308b\u304b\u3001\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u308b\u306e\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u518d\u30aa\u30fc\u30d7\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -JDBCStore.checkConnectionDBReOpenFail=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u518d\u30aa\u30fc\u30d7\u30f3\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 -JDBCStore.checkConnectionSQLException=SQL\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0} -JDBCStore.checkConnectionClassNotFoundException=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 {0} -managerBase.complete=\u4e71\u6570\u767a\u751f\u5668\u306e\u30b7\u30fc\u30c9\u306e\u751f\u6210\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f -managerBase.getting=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u53d6\u5f97\u3057\u307e\u3059 -managerBase.gotten=\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u53d6\u5f97\u3092\u5b8c\u4e86\u3057\u307e\u3057\u305f -managerBase.random=\u30af\u30e9\u30b9 {0} \u306e\u4e71\u6570\u767a\u751f\u5668\u306e\u521d\u671f\u5316\u306e\u4f8b\u5916\u3067\u3059 -managerBase.seeding=\u4e71\u6570\u767a\u751f\u5668\u30af\u30e9\u30b9 {0} \u306e\u30b7\u30fc\u30c9\u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059 -serverSession.value.iae=null\u5024\u3067\u3059 -standardManager.alreadyStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardManager.createSession.ise=createSession: \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059 -standardManager.expireException=processsExpire: \u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u7d42\u4e86\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardManager.loading={0} \u304b\u3089\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059 -standardManager.loading.cnfe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306bClassNotFoundException\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} -standardManager.loading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306eIOException\u3067\u3059: {0} -standardManager.notStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardManager.sessionTimeout=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u8a2d\u5b9a\u3067\u3059 {0} -standardManager.unloading=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092 {0} \u306b\u4fdd\u5b58\u3057\u307e\u3059 -standardManager.unloading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u4fdd\u5b58\u4e2d\u306eIOException\u3067\u3059: {0} -standardManager.managerLoad=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u304b\u3089\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardManager.managerUnload=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30a2\u30f3\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -standardSession.attributeEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardSession.bindingEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardSession.invalidate.ise=invalidate: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.isNew.ise=isNew: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getAttribute.ise=getAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getAttributeNames.ise=getAttributeNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getCreationTime.ise=getCreationTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getLastAccessedTime.ise=getLastAccessedTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getId.ise=getId: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.getValueNames.ise=getValueNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.notSerializable=\u30bb\u30c3\u30b7\u30e7\u30f3 {1} \u306e\u305f\u3081\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u307e\u305b\u3093 -standardSession.removeAttribute.ise=removeAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.sessionEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f -standardSession.setAttribute.iae=setAttribute: \u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u306a\u3044\u5c5e\u6027\u3067\u3059 -standardSession.setAttribute.ise=setAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 -standardSession.setAttribute.namenull=setAttribute: name\u30d1\u30e9\u30e1\u30bf\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -standardSession.sessionCreated=\u30bb\u30c3\u30b7\u30e7\u30f3ID = {0} \u3092\u751f\u6210\u3057\u307e\u3057\u305f -persistentManager.loading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 -persistentManager.unloading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3057\u307e\u3059 -persistentManager.expiring= {0} \u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3059\u308b\u524d\u306b\u671f\u9650\u5207\u308c\u306b\u306a\u308a\u307e\u3057\u305f -persistentManager.deserializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} -persistentManager.serializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} -persistentManager.swapMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30b9\u30ef\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 -persistentManager.backupMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 -persistentManager.backupException=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3059\u308b\u6642\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {1} -persistentManager.tooManyActive=\u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059\u3001{0}\u3001\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3059\u308b\u305f\u3081\u306b\u30a2\u30a4\u30c9\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u63a2\u3057\u3066\u3044\u307e\u3059 -persistentManager.swapTooManyActive=\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u308b\u306e\u3067\u3001{1}\u79d2\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3057\u307e\u3059 -persistentManager.processSwaps=\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30b9\u30ef\u30c3\u30d7\u3059\u308b\u305f\u3081\u306b\u30c1\u30a7\u30c3\u30af\u3057\u3066\u3044\u307e\u3059, \u30e1\u30e2\u30ea\u4e2d\u306b {0} \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5b58\u5728\u3057\u307e\u3059 -persistentManager.activeSession=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u306f{1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u307e\u3059 -persistentManager.swapIn=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a4\u30f3\u3057\u3066\u3044\u307e\u3059 +applicationSession.session.ise=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u72b6\u614b\u3067\u3059 +applicationSession.value.iae=null\u5024\u3067\u3059 +fileStore.alreadyStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +fileStore.notStarted=\u30d5\u30a1\u30a4\u30eb\u30b9\u30c8\u30a2\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +fileStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 +fileStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 +fileStore.removing=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d5\u30a1\u30a4\u30eb {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 +JDBCStore.alreadyStarted=JDBC\u30b9\u30c8\u30a2\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +JDBCStore.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a {0} \u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +JDBCStore.notStarted=JDBC\u30b9\u30c8\u30a2\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u307e\u305b\u3093 +JDBCStore.saving=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u306b\u4fdd\u5b58\u3057\u307e\u3059 +JDBCStore.loading=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u30ed\u30fc\u30c9\u3057\u307e\u3059 +JDBCStore.removing= \u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9 {1} \u304b\u3089\u524a\u9664\u3057\u307e\u3059 +JDBCStore.SQLException=SQL\u30a8\u30e9\u30fc {0} +JDBCStore.checkConnectionDBClosed=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u304cnull\u3067\u3042\u308b\u304b\u3001\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u308b\u306e\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f\u3002\u518d\u30aa\u30fc\u30d7\u30f3\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +JDBCStore.checkConnectionDBReOpenFail=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u518d\u30aa\u30fc\u30d7\u30f3\u304c\u5931\u6557\u3057\u307e\u3057\u305f\u3002\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u304c\u30c0\u30a6\u30f3\u3057\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u307e\u305b\u3093\u3002 +JDBCStore.checkConnectionSQLException=SQL\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f {0} +JDBCStore.checkConnectionClassNotFoundException=JDBC\u30c9\u30e9\u30a4\u30d0\u30af\u30e9\u30b9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 {0} +managerBase.complete=\u4e71\u6570\u767a\u751f\u5668\u306e\u30b7\u30fc\u30c9\u306e\u751f\u6210\u304c\u5b8c\u4e86\u3057\u307e\u3057\u305f +managerBase.getting=\u30a2\u30eb\u30b4\u30ea\u30ba\u30e0 {0} \u306e\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u3092\u53d6\u5f97\u3057\u307e\u3059 +managerBase.gotten=\u30e1\u30c3\u30bb\u30fc\u30b8\u30c0\u30a4\u30b8\u30a7\u30b9\u30c8\u30b3\u30f3\u30dd\u30fc\u30cd\u30f3\u30c8\u306e\u53d6\u5f97\u3092\u5b8c\u4e86\u3057\u307e\u3057\u305f +managerBase.random=\u30af\u30e9\u30b9 {0} \u306e\u4e71\u6570\u767a\u751f\u5668\u306e\u521d\u671f\u5316\u306e\u4f8b\u5916\u3067\u3059 +managerBase.seeding=\u4e71\u6570\u767a\u751f\u5668\u30af\u30e9\u30b9 {0} \u306e\u30b7\u30fc\u30c9\u3092\u751f\u6210\u3057\u3066\u3044\u307e\u3059 +serverSession.value.iae=null\u5024\u3067\u3059 +standardManager.alreadyStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardManager.createSession.ise=createSession: \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059 +standardManager.expireException=processsExpire: \u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u7d42\u4e86\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardManager.loading={0} \u304b\u3089\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u3066\u3044\u307e\u3059 +standardManager.loading.cnfe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306bClassNotFoundException\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {0} +standardManager.loading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306eIOException\u3067\u3059: {0} +standardManager.notStarted=\u30de\u30cd\u30fc\u30b8\u30e3\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardManager.sessionTimeout=\u7121\u52b9\u306a\u30bb\u30c3\u30b7\u30e7\u30f3\u30bf\u30a4\u30e0\u30a2\u30a6\u30c8\u8a2d\u5b9a\u3067\u3059 {0} +standardManager.unloading=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092 {0} \u306b\u4fdd\u5b58\u3057\u307e\u3059 +standardManager.unloading.ioe=\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u306e\u4fdd\u5b58\u4e2d\u306eIOException\u3067\u3059: {0} +standardManager.managerLoad=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u304b\u3089\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardManager.managerUnload=\u6c38\u7d9a\u8a18\u61b6\u88c5\u7f6e\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30a2\u30f3\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +standardSession.attributeEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardSession.bindingEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30d0\u30a4\u30f3\u30c7\u30a3\u30f3\u30b0\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardSession.invalidate.ise=invalidate: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.isNew.ise=isNew: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getAttribute.ise=getAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getAttributeNames.ise=getAttributeNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getCreationTime.ise=getCreationTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getLastAccessedTime.ise=getLastAccessedTime: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getId.ise=getId: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getMaxInactiveInterval.ise=getMaxInactiveInterval: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.getValueNames.ise=getValueNames: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.notSerializable=\u30bb\u30c3\u30b7\u30e7\u30f3 {1} \u306e\u305f\u3081\u306b\u30bb\u30c3\u30b7\u30e7\u30f3\u5c5e\u6027 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u307e\u305b\u3093 +standardSession.removeAttribute.ise=removeAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.sessionEvent=\u30bb\u30c3\u30b7\u30e7\u30f3\u30a4\u30d9\u30f3\u30c8\u30ea\u30b9\u30ca\u304c\u4f8b\u5916\u3092\u6295\u3052\u307e\u3057\u305f +standardSession.setAttribute.iae=setAttribute: \u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u3067\u304d\u306a\u3044\u5c5e\u6027\u3067\u3059 +standardSession.setAttribute.ise=setAttribute: \u30bb\u30c3\u30b7\u30e7\u30f3\u306f\u65e2\u306b\u7121\u52b9\u5316\u3055\u308c\u3066\u3044\u307e\u3059 +standardSession.setAttribute.namenull=setAttribute: name\u30d1\u30e9\u30e1\u30bf\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +standardSession.sessionCreated=\u30bb\u30c3\u30b7\u30e7\u30f3ID = {0} \u3092\u751f\u6210\u3057\u307e\u3057\u305f +persistentManager.loading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30ed\u30fc\u30c9\u3057\u307e\u3059 +persistentManager.unloading={0} \u306e\u6301\u7d9a\u3055\u308c\u305f\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3057\u307e\u3059 +persistentManager.expiring= {0} \u306e\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u4fdd\u5b58\u3059\u308b\u524d\u306b\u671f\u9650\u5207\u308c\u306b\u306a\u308a\u307e\u3057\u305f +persistentManager.deserializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30c7\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} +persistentManager.serializeError=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b7\u30ea\u30a2\u30e9\u30a4\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} +persistentManager.swapMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30b9\u30ef\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 +persistentManager.backupMaxIdle={1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u4fdd\u5b58\u3059\u308b\u305f\u3081\u306b\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3057\u3066\u3044\u307e\u3059 +persistentManager.backupException=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30d0\u30c3\u30af\u30a2\u30c3\u30d7\u3059\u308b\u6642\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: {1} +persistentManager.tooManyActive=\u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u307e\u3059\u3001{0}\u3001\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3059\u308b\u305f\u3081\u306b\u30a2\u30a4\u30c9\u30eb\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u63a2\u3057\u3066\u3044\u307e\u3059 +persistentManager.swapTooManyActive=\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u591a\u3059\u304e\u308b\u306e\u3067\u3001{1}\u79d2\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u308b\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a2\u30a6\u30c8\u3057\u307e\u3059 +persistentManager.processSwaps=\u30bb\u30c3\u30b7\u30e7\u30f3\u3092\u30b9\u30ef\u30c3\u30d7\u3059\u308b\u305f\u3081\u306b\u30c1\u30a7\u30c3\u30af\u3057\u3066\u3044\u307e\u3059, \u30e1\u30e2\u30ea\u4e2d\u306b {0} \u30a2\u30af\u30c6\u30a3\u30d6\u30bb\u30c3\u30b7\u30e7\u30f3\u304c\u5b58\u5728\u3057\u307e\u3059 +persistentManager.activeSession=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u306f{1}\u79d2\u9593\u30a2\u30a4\u30c9\u30eb\u3057\u3066\u3044\u307e\u3059 +persistentManager.swapIn=\u30bb\u30c3\u30b7\u30e7\u30f3 {0} \u3092\u30b9\u30ef\u30c3\u30d7\u30a4\u30f3\u3057\u3066\u3044\u307e\u3059 diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java index 0dcdba73d..7100e8b0e 100644 --- a/java/org/apache/catalina/session/ManagerBase.java +++ b/java/org/apache/catalina/session/ManagerBase.java @@ -1,1252 +1,1252 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.DataInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.PrivilegedAction; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Random; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.catalina.Container; -import org.apache.catalina.Engine; -import org.apache.catalina.Manager; -import org.apache.catalina.Session; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Minimal implementation of the Manager interface that supports - * no session persistence or distributable capabilities. This class may - * be subclassed to create more sophisticated Manager implementations. - * - * @author Craig R. McClanahan - * @version $Revision: 388112 $ $Date: 2006-03-23 10:00:30 +0100 (jeu., 23 mars 2006) $ - */ - -public abstract class ManagerBase implements Manager, MBeanRegistration { - protected Log log = LogFactory.getLog(ManagerBase.class); - - // ----------------------------------------------------- Instance Variables - - protected DataInputStream randomIS=null; - protected String devRandomSource="/dev/urandom"; - - /** - * The default message digest algorithm to use if we cannot use - * the requested one. - */ - protected static final String DEFAULT_ALGORITHM = "MD5"; - - - /** - * The message digest algorithm to be used when generating session - * identifiers. This must be an algorithm supported by the - * java.security.MessageDigest class on your platform. - */ - protected String algorithm = DEFAULT_ALGORITHM; - - - /** - * The Container with which this Manager is associated. - */ - protected Container container; - - - /** - * Return the MessageDigest implementation to be used when - * creating session identifiers. - */ - protected MessageDigest digest = null; - - - /** - * The distributable flag for Sessions created by this Manager. If this - * flag is set to true, any user attributes added to a - * session controlled by this Manager must be Serializable. - */ - protected boolean distributable; - - - /** - * A String initialization parameter used to increase the entropy of - * the initialization of our random number generator. - */ - protected String entropy = null; - - - /** - * The descriptive information string for this implementation. - */ - private static final String info = "ManagerBase/1.0"; - - - /** - * The default maximum inactive interval for Sessions created by - * this Manager. - */ - protected int maxInactiveInterval = 60; - - - /** - * The session id length of Sessions created by this Manager. - */ - protected int sessionIdLength = 16; - - - /** - * The descriptive name of this Manager implementation (for logging). - */ - protected static String name = "ManagerBase"; - - - /** - * A random number generator to use when generating session identifiers. - */ - protected Random random = null; - - - /** - * The Java class name of the random number generator class to be used - * when generating session identifiers. - */ - protected String randomClass = "java.security.SecureRandom"; - - - /** - * The longest time (in seconds) that an expired session had been alive. - */ - protected int sessionMaxAliveTime; - - - /** - * Average time (in seconds) that expired sessions had been alive. - */ - protected int sessionAverageAliveTime; - - - /** - * Number of sessions that have expired. - */ - protected int expiredSessions = 0; - - - /** - * The set of currently active Sessions for this Manager, keyed by - * session identifier. - */ - protected HashMap sessions = new HashMap(); - - // Number of sessions created by this manager - protected int sessionCounter=0; - - protected int maxActive=0; - - // number of duplicated session ids - anything >0 means we have problems - protected int duplicates=0; - - protected boolean initialized=false; - - /** - * Processing time during session expiration. - */ - protected long processingTime = 0; - - /** - * Iteration count for background processing. - */ - private int count = 0; - - - /** - * Frequency of the session expiration, and related manager operations. - * Manager operations will be done once for the specified amount of - * backgrondProcess calls (ie, the lower the amount, the most often the - * checks will occur). - */ - protected int processExpiresFrequency = 6; - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - - // ------------------------------------------------------------- Security classes - - - private class PrivilegedSetRandomFile implements PrivilegedAction{ - - public Object run(){ - try { - File f=new File( devRandomSource ); - if( ! f.exists() ) return null; - randomIS= new DataInputStream( new FileInputStream(f)); - randomIS.readLong(); - if( log.isDebugEnabled() ) - log.debug( "Opening " + devRandomSource ); - return randomIS; - } catch (IOException ex){ - return null; - } - } - } - - - // ------------------------------------------------------------- Properties - - /** - * Return the message digest algorithm for this Manager. - */ - public String getAlgorithm() { - - return (this.algorithm); - - } - - - /** - * Set the message digest algorithm for this Manager. - * - * @param algorithm The new message digest algorithm - */ - public void setAlgorithm(String algorithm) { - - String oldAlgorithm = this.algorithm; - this.algorithm = algorithm; - support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm); - - } - - - /** - * Return the Container with which this Manager is associated. - */ - public Container getContainer() { - - return (this.container); - - } - - - /** - * Set the Container with which this Manager is associated. - * - * @param container The newly associated Container - */ - public void setContainer(Container container) { - - Container oldContainer = this.container; - this.container = container; - support.firePropertyChange("container", oldContainer, this.container); - } - - - /** Returns the name of the implementation class. - */ - public String getClassName() { - return this.getClass().getName(); - } - - - /** - * Return the MessageDigest object to be used for calculating - * session identifiers. If none has been created yet, initialize - * one the first time this method is called. - */ - public synchronized MessageDigest getDigest() { - - if (this.digest == null) { - long t1=System.currentTimeMillis(); - if (log.isDebugEnabled()) - log.debug(sm.getString("managerBase.getting", algorithm)); - try { - this.digest = MessageDigest.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - log.error(sm.getString("managerBase.digest", algorithm), e); - try { - this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); - } catch (NoSuchAlgorithmException f) { - log.error(sm.getString("managerBase.digest", - DEFAULT_ALGORITHM), e); - this.digest = null; - } - } - if (log.isDebugEnabled()) - log.debug(sm.getString("managerBase.gotten")); - long t2=System.currentTimeMillis(); - if( log.isDebugEnabled() ) - log.debug("getDigest() " + (t2-t1)); - } - - return (this.digest); - - } - - - /** - * Return the distributable flag for the sessions supported by - * this Manager. - */ - public boolean getDistributable() { - - return (this.distributable); - - } - - - /** - * Set the distributable flag for the sessions supported by this - * Manager. If this flag is set, all user data objects added to - * sessions associated with this manager must implement Serializable. - * - * @param distributable The new distributable flag - */ - public void setDistributable(boolean distributable) { - - boolean oldDistributable = this.distributable; - this.distributable = distributable; - support.firePropertyChange("distributable", - new Boolean(oldDistributable), - new Boolean(this.distributable)); - - } - - - /** - * Return the entropy increaser value, or compute a semi-useful value - * if this String has not yet been set. - */ - public String getEntropy() { - - // Calculate a semi-useful value if this has not been set - if (this.entropy == null) { - // Use APR to get a crypto secure entropy value - byte[] result = new byte[32]; - boolean apr = false; - try { - String methodName = "random"; - Class paramTypes[] = new Class[2]; - paramTypes[0] = result.getClass(); - paramTypes[1] = int.class; - Object paramValues[] = new Object[2]; - paramValues[0] = result; - paramValues[1] = new Integer(32); - Method method = Class.forName("org.apache.tomcat.jni.OS") - .getMethod(methodName, paramTypes); - method.invoke(null, paramValues); - apr = true; - } catch (Throwable t) { - // Ignore - } - if (apr) { - setEntropy(new String(result)); - } else { - setEntropy(this.toString()); - } - } - - return (this.entropy); - - } - - - /** - * Set the entropy increaser value. - * - * @param entropy The new entropy increaser value - */ - public void setEntropy(String entropy) { - - String oldEntropy = entropy; - this.entropy = entropy; - support.firePropertyChange("entropy", oldEntropy, this.entropy); - - } - - - /** - * Return descriptive information about this Manager implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the default maximum inactive interval (in seconds) - * for Sessions created by this Manager. - */ - public int getMaxInactiveInterval() { - - return (this.maxInactiveInterval); - - } - - - /** - * Set the default maximum inactive interval (in seconds) - * for Sessions created by this Manager. - * - * @param interval The new default value - */ - public void setMaxInactiveInterval(int interval) { - - int oldMaxInactiveInterval = this.maxInactiveInterval; - this.maxInactiveInterval = interval; - support.firePropertyChange("maxInactiveInterval", - new Integer(oldMaxInactiveInterval), - new Integer(this.maxInactiveInterval)); - - } - - - /** - * Gets the session id length (in bytes) of Sessions created by - * this Manager. - * - * @return The session id length - */ - public int getSessionIdLength() { - - return (this.sessionIdLength); - - } - - - /** - * Sets the session id length (in bytes) for Sessions created by this - * Manager. - * - * @param idLength The session id length - */ - public void setSessionIdLength(int idLength) { - - int oldSessionIdLength = this.sessionIdLength; - this.sessionIdLength = idLength; - support.firePropertyChange("sessionIdLength", - new Integer(oldSessionIdLength), - new Integer(this.sessionIdLength)); - - } - - - /** - * Return the descriptive short name of this Manager implementation. - */ - public String getName() { - - return (name); - - } - - /** - * Use /dev/random-type special device. This is new code, but may reduce - * the big delay in generating the random. - * - * You must specify a path to a random generator file. Use /dev/urandom - * for linux ( or similar ) systems. Use /dev/random for maximum security - * ( it may block if not enough "random" exist ). You can also use - * a pipe that generates random. - * - * The code will check if the file exists, and default to java Random - * if not found. There is a significant performance difference, very - * visible on the first call to getSession ( like in the first JSP ) - * - so use it if available. - */ - public void setRandomFile( String s ) { - // as a hack, you can use a static file - and genarate the same - // session ids ( good for strange debugging ) - if (System.getSecurityManager() != null){ - randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile()); - } else { - try{ - devRandomSource=s; - File f=new File( devRandomSource ); - if( ! f.exists() ) return; - randomIS= new DataInputStream( new FileInputStream(f)); - randomIS.readLong(); - if( log.isDebugEnabled() ) - log.debug( "Opening " + devRandomSource ); - } catch( IOException ex ) { - try { - randomIS.close(); - } catch (Exception e) { - log.warn("Failed to close randomIS."); - } - - randomIS=null; - } - } - } - - public String getRandomFile() { - return devRandomSource; - } - - - /** - * Return the random number generator instance we should use for - * generating session identifiers. If there is no such generator - * currently defined, construct and seed a new one. - */ - public Random getRandom() { - if (this.random == null) { - // Calculate the new random number generator seed - long seed = System.currentTimeMillis(); - long t1 = seed; - char entropy[] = getEntropy().toCharArray(); - for (int i = 0; i < entropy.length; i++) { - long update = ((byte) entropy[i]) << ((i % 8) * 8); - seed ^= update; - } - try { - // Construct and seed a new random number generator - Class clazz = Class.forName(randomClass); - this.random = (Random) clazz.newInstance(); - this.random.setSeed(seed); - } catch (Exception e) { - // Fall back to the simple case - log.error(sm.getString("managerBase.random", randomClass), - e); - this.random = new java.util.Random(); - this.random.setSeed(seed); - } - if(log.isDebugEnabled()) { - long t2=System.currentTimeMillis(); - if( (t2-t1) > 100 ) - log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1)); - } - } - - return (this.random); - - } - - - /** - * Return the random number generator class name. - */ - public String getRandomClass() { - - return (this.randomClass); - - } - - - /** - * Set the random number generator class name. - * - * @param randomClass The new random number generator class name - */ - public void setRandomClass(String randomClass) { - - String oldRandomClass = this.randomClass; - this.randomClass = randomClass; - support.firePropertyChange("randomClass", oldRandomClass, - this.randomClass); - - } - - - /** - * Gets the number of sessions that have expired. - * - * @return Number of sessions that have expired - */ - public int getExpiredSessions() { - return expiredSessions; - } - - - /** - * Sets the number of sessions that have expired. - * - * @param expiredSessions Number of sessions that have expired - */ - public void setExpiredSessions(int expiredSessions) { - this.expiredSessions = expiredSessions; - } - - public long getProcessingTime() { - return processingTime; - } - - - public void setProcessingTime(long processingTime) { - this.processingTime = processingTime; - } - - /** - * Return the frequency of manager checks. - */ - public int getProcessExpiresFrequency() { - - return (this.processExpiresFrequency); - - } - - /** - * Set the manager checks frequency. - * - * @param processExpiresFrequency the new manager checks frequency - */ - public void setProcessExpiresFrequency(int processExpiresFrequency) { - - if (processExpiresFrequency <= 0) { - return; - } - - int oldProcessExpiresFrequency = this.processExpiresFrequency; - this.processExpiresFrequency = processExpiresFrequency; - support.firePropertyChange("processExpiresFrequency", - new Integer(oldProcessExpiresFrequency), - new Integer(this.processExpiresFrequency)); - - } - - // --------------------------------------------------------- Public Methods - - - /** - * Implements the Manager interface, direct call to processExpires - */ - public void backgroundProcess() { - count = (count + 1) % processExpiresFrequency; - if (count == 0) - processExpires(); - } - - /** - * Invalidate all sessions that have expired. - */ - public void processExpires() { - - long timeNow = System.currentTimeMillis(); - Session sessions[] = findSessions(); - int expireHere = 0 ; - - if(log.isDebugEnabled()) - log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); - for (int i = 0; i < sessions.length; i++) { - if (!sessions[i].isValid()) { - expireHere++; - } - } - long timeEnd = System.currentTimeMillis(); - if(log.isDebugEnabled()) - log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); - processingTime += ( timeEnd - timeNow ); - - } - - public void destroy() { - if( oname != null ) - Registry.getRegistry(null, null).unregisterComponent(oname); - initialized=false; - oname = null; - } - - public void init() { - if( initialized ) return; - initialized=true; - - if( oname==null ) { - try { - StandardContext ctx=(StandardContext)this.getContainer(); - Engine eng=(Engine)ctx.getParent().getParent(); - domain=ctx.getEngineName(); - distributable = ctx.getDistributable(); - StandardHost hst=(StandardHost)ctx.getParent(); - String path = ctx.getPath(); - if (path.equals("")) { - path = "/"; - } - oname=new ObjectName(domain + ":type=Manager,path=" - + path + ",host=" + hst.getName()); - Registry.getRegistry(null, null).registerComponent(this, oname, null ); - } catch (Exception e) { - log.error("Error registering ",e); - } - } - - // Initialize random number generation - getRandomBytes(new byte[16]); - - if(log.isDebugEnabled()) - log.debug("Registering " + oname ); - - } - - /** - * Add this Session to the set of active Sessions for this Manager. - * - * @param session Session to be added - */ - public void add(Session session) { - - synchronized (sessions) { - sessions.put(session.getIdInternal(), session); - if( sessions.size() > maxActive ) { - maxActive=sessions.size(); - } - } - } - - - /** - * Add a property change listener to this component. - * - * @param listener The listener to add - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - - support.addPropertyChangeListener(listener); - - } - - - /** - * Construct and return a new session object, based on the default - * settings specified by this Manager's properties. The session - * id will be assigned by this method, and available via the getId() - * method of the returned session. If a new session cannot be created - * for any reason, return null. - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @deprecated - */ - public Session createSession() { - return createSession(null); - } - - - /** - * Construct and return a new session object, based on the default - * settings specified by this Manager's properties. The session - * id specified will be used as the session id. - * If a new session cannot be created for any reason, return - * null. - * - * @param sessionId The session id which should be used to create the - * new session; if null, a new session id will be - * generated - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - */ - public Session createSession(String sessionId) { - - // Recycle or create a Session instance - Session session = createEmptySession(); - - // Initialize the properties of the new session and return it - session.setNew(true); - session.setValid(true); - session.setCreationTime(System.currentTimeMillis()); - session.setMaxInactiveInterval(this.maxInactiveInterval); - if (sessionId == null) { - sessionId = generateSessionId(); - // FIXME WHy we need no duplication check? - /* - synchronized (sessions) { - while (sessions.get(sessionId) != null) { // Guarantee - // uniqueness - duplicates++; - sessionId = generateSessionId(); - } - } - */ - - // FIXME: Code to be used in case route replacement is needed - /* - } else { - String jvmRoute = getJvmRoute(); - if (getJvmRoute() != null) { - String requestJvmRoute = null; - int index = sessionId.indexOf("."); - if (index > 0) { - requestJvmRoute = sessionId - .substring(index + 1, sessionId.length()); - } - if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) { - sessionId = sessionId.substring(0, index) + "." + jvmRoute; - } - } - */ - } - session.setId(sessionId); - sessionCounter++; - - return (session); - - } - - - /** - * Get a session from the recycled ones or create a new empty one. - * The PersistentManager manager does not need to create session data - * because it reads it from the Store. - */ - public Session createEmptySession() { - return (getNewSession()); - } - - - /** - * Return the active Session, associated with this Manager, with the - * specified session id (if any); otherwise return null. - * - * @param id The session id for the session to be returned - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @exception IOException if an input/output error occurs while - * processing this request - */ - public Session findSession(String id) throws IOException { - - if (id == null) - return (null); - synchronized (sessions) { - Session session = (Session) sessions.get(id); - return (session); - } - - } - - - /** - * Return the set of active Sessions associated with this Manager. - * If this Manager has no active Sessions, a zero-length array is returned. - */ - public Session[] findSessions() { - - Session results[] = null; - synchronized (sessions) { - results = new Session[sessions.size()]; - results = (Session[]) sessions.values().toArray(results); - } - return (results); - - } - - - /** - * Remove this Session from the active Sessions for this Manager. - * - * @param session Session to be removed - */ - public void remove(Session session) { - - synchronized (sessions) { - sessions.remove(session.getIdInternal()); - } - - } - - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - - support.removePropertyChangeListener(listener); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Get new session class to be used in the doLoad() method. - */ - protected StandardSession getNewSession() { - return new StandardSession(this); - } - - - protected void getRandomBytes(byte bytes[]) { - // Generate a byte array containing a session identifier - if (devRandomSource != null && randomIS == null) { - setRandomFile(devRandomSource); - } - if (randomIS != null) { - try { - int len = randomIS.read(bytes); - if (len == bytes.length) { - return; - } - if(log.isDebugEnabled()) - log.debug("Got " + len + " " + bytes.length ); - } catch (Exception ex) { - // Ignore - } - devRandomSource = null; - - try { - randomIS.close(); - } catch (Exception e) { - log.warn("Failed to close randomIS."); - } - - randomIS = null; - } - getRandom().nextBytes(bytes); - } - - - /** - * Generate and return a new session identifier. - */ - protected synchronized String generateSessionId() { - - byte random[] = new byte[16]; - String jvmRoute = getJvmRoute(); - String result = null; - - // Render the result as a String of hexadecimal digits - StringBuffer buffer = new StringBuffer(); - do { - int resultLenBytes = 0; - if (result != null) { - buffer = new StringBuffer(); - duplicates++; - } - - while (resultLenBytes < this.sessionIdLength) { - getRandomBytes(random); - random = getDigest().digest(random); - for (int j = 0; - j < random.length && resultLenBytes < this.sessionIdLength; - j++) { - byte b1 = (byte) ((random[j] & 0xf0) >> 4); - byte b2 = (byte) (random[j] & 0x0f); - if (b1 < 10) - buffer.append((char) ('0' + b1)); - else - buffer.append((char) ('A' + (b1 - 10))); - if (b2 < 10) - buffer.append((char) ('0' + b2)); - else - buffer.append((char) ('A' + (b2 - 10))); - resultLenBytes++; - } - } - if (jvmRoute != null) { - buffer.append('.').append(jvmRoute); - } - result = buffer.toString(); - } while (sessions.containsKey(result)); - return (result); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Retrieve the enclosing Engine for this Manager. - * - * @return an Engine object (or null). - */ - public Engine getEngine() { - Engine e = null; - for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) { - if (c != null && c instanceof Engine) { - e = (Engine)c; - } - } - return e; - } - - - /** - * Retrieve the JvmRoute for the enclosing Engine. - * @return the JvmRoute or null. - */ - public String getJvmRoute() { - Engine e = getEngine(); - return e == null ? null : e.getJvmRoute(); - } - - - // -------------------------------------------------------- Package Methods - - - public void setSessionCounter(int sessionCounter) { - this.sessionCounter = sessionCounter; - } - - - /** - * Total sessions created by this manager. - * - * @return sessions created - */ - public int getSessionCounter() { - return sessionCounter; - } - - - /** - * Number of duplicated session IDs generated by the random source. - * Anything bigger than 0 means problems. - * - * @return The count of duplicates - */ - public int getDuplicates() { - return duplicates; - } - - - public void setDuplicates(int duplicates) { - this.duplicates = duplicates; - } - - - /** - * Returns the number of active sessions - * - * @return number of sessions active - */ - public int getActiveSessions() { - return sessions.size(); - } - - - /** - * Max number of concurrent active sessions - * - * @return The highest number of concurrent active sessions - */ - public int getMaxActive() { - return maxActive; - } - - - public void setMaxActive(int maxActive) { - this.maxActive = maxActive; - } - - - /** - * Gets the longest time (in seconds) that an expired session had been - * alive. - * - * @return Longest time (in seconds) that an expired session had been - * alive. - */ - public int getSessionMaxAliveTime() { - return sessionMaxAliveTime; - } - - - /** - * Sets the longest time (in seconds) that an expired session had been - * alive. - * - * @param sessionMaxAliveTime Longest time (in seconds) that an expired - * session had been alive. - */ - public void setSessionMaxAliveTime(int sessionMaxAliveTime) { - this.sessionMaxAliveTime = sessionMaxAliveTime; - } - - - /** - * Gets the average time (in seconds) that expired sessions had been - * alive. - * - * @return Average time (in seconds) that expired sessions had been - * alive. - */ - public int getSessionAverageAliveTime() { - return sessionAverageAliveTime; - } - - - /** - * Sets the average time (in seconds) that expired sessions had been - * alive. - * - * @param sessionAverageAliveTime Average time (in seconds) that expired - * sessions had been alive. - */ - public void setSessionAverageAliveTime(int sessionAverageAliveTime) { - this.sessionAverageAliveTime = sessionAverageAliveTime; - } - - - /** - * For debugging: return a list of all session ids currently active - * - */ - public String listSessionIds() { - StringBuffer sb=new StringBuffer(); - Iterator keys=sessions.keySet().iterator(); - while( keys.hasNext() ) { - sb.append(keys.next()).append(" "); - } - return sb.toString(); - } - - - /** - * For debugging: get a session attribute - * - * @param sessionId - * @param key - * @return The attribute value, if found, null otherwise - */ - public String getSessionAttribute( String sessionId, String key ) { - Session s=(Session)sessions.get(sessionId); - if( s==null ) { - if(log.isInfoEnabled()) - log.info("Session not found " + sessionId); - return null; - } - Object o=s.getSession().getAttribute(key); - if( o==null ) return null; - return o.toString(); - } - - - /** - * Returns information about the session with the given session id. - * - *

    The session information is organized as a HashMap, mapping - * session attribute names to the String representation of their values. - * - * @param sessionId Session id - * - * @return HashMap mapping session attribute names to the String - * representation of their values, or null if no session with the - * specified id exists, or if the session does not have any attributes - */ - public HashMap getSession(String sessionId) { - Session s = (Session) sessions.get(sessionId); - if (s == null) { - if (log.isInfoEnabled()) { - log.info("Session not found " + sessionId); - } - return null; - } - - Enumeration ee = s.getSession().getAttributeNames(); - if (ee == null || !ee.hasMoreElements()) { - return null; - } - - HashMap map = new HashMap(); - while (ee.hasMoreElements()) { - String attrName = (String) ee.nextElement(); - map.put(attrName, getSessionAttribute(sessionId, attrName)); - } - - return map; - } - - - public void expireSession( String sessionId ) { - Session s=(Session)sessions.get(sessionId); - if( s==null ) { - if(log.isInfoEnabled()) - log.info("Session not found " + sessionId); - return; - } - s.expire(); - } - - - public String getLastAccessedTime( String sessionId ) { - Session s=(Session)sessions.get(sessionId); - if( s==null ) { - log.info("Session not found " + sessionId); - return ""; - } - return new Date(s.getLastAccessedTime()).toString(); - } - - - // -------------------- JMX and Registration -------------------- - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.DataInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivilegedAction; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Random; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.catalina.Container; +import org.apache.catalina.Engine; +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Minimal implementation of the Manager interface that supports + * no session persistence or distributable capabilities. This class may + * be subclassed to create more sophisticated Manager implementations. + * + * @author Craig R. McClanahan + * @version $Revision: 388112 $ $Date: 2006-03-23 10:00:30 +0100 (jeu., 23 mars 2006) $ + */ + +public abstract class ManagerBase implements Manager, MBeanRegistration { + protected Log log = LogFactory.getLog(ManagerBase.class); + + // ----------------------------------------------------- Instance Variables + + protected DataInputStream randomIS=null; + protected String devRandomSource="/dev/urandom"; + + /** + * The default message digest algorithm to use if we cannot use + * the requested one. + */ + protected static final String DEFAULT_ALGORITHM = "MD5"; + + + /** + * The message digest algorithm to be used when generating session + * identifiers. This must be an algorithm supported by the + * java.security.MessageDigest class on your platform. + */ + protected String algorithm = DEFAULT_ALGORITHM; + + + /** + * The Container with which this Manager is associated. + */ + protected Container container; + + + /** + * Return the MessageDigest implementation to be used when + * creating session identifiers. + */ + protected MessageDigest digest = null; + + + /** + * The distributable flag for Sessions created by this Manager. If this + * flag is set to true, any user attributes added to a + * session controlled by this Manager must be Serializable. + */ + protected boolean distributable; + + + /** + * A String initialization parameter used to increase the entropy of + * the initialization of our random number generator. + */ + protected String entropy = null; + + + /** + * The descriptive information string for this implementation. + */ + private static final String info = "ManagerBase/1.0"; + + + /** + * The default maximum inactive interval for Sessions created by + * this Manager. + */ + protected int maxInactiveInterval = 60; + + + /** + * The session id length of Sessions created by this Manager. + */ + protected int sessionIdLength = 16; + + + /** + * The descriptive name of this Manager implementation (for logging). + */ + protected static String name = "ManagerBase"; + + + /** + * A random number generator to use when generating session identifiers. + */ + protected Random random = null; + + + /** + * The Java class name of the random number generator class to be used + * when generating session identifiers. + */ + protected String randomClass = "java.security.SecureRandom"; + + + /** + * The longest time (in seconds) that an expired session had been alive. + */ + protected int sessionMaxAliveTime; + + + /** + * Average time (in seconds) that expired sessions had been alive. + */ + protected int sessionAverageAliveTime; + + + /** + * Number of sessions that have expired. + */ + protected int expiredSessions = 0; + + + /** + * The set of currently active Sessions for this Manager, keyed by + * session identifier. + */ + protected HashMap sessions = new HashMap(); + + // Number of sessions created by this manager + protected int sessionCounter=0; + + protected int maxActive=0; + + // number of duplicated session ids - anything >0 means we have problems + protected int duplicates=0; + + protected boolean initialized=false; + + /** + * Processing time during session expiration. + */ + protected long processingTime = 0; + + /** + * Iteration count for background processing. + */ + private int count = 0; + + + /** + * Frequency of the session expiration, and related manager operations. + * Manager operations will be done once for the specified amount of + * backgrondProcess calls (ie, the lower the amount, the most often the + * checks will occur). + */ + protected int processExpiresFrequency = 6; + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + + // ------------------------------------------------------------- Security classes + + + private class PrivilegedSetRandomFile implements PrivilegedAction{ + + public Object run(){ + try { + File f=new File( devRandomSource ); + if( ! f.exists() ) return null; + randomIS= new DataInputStream( new FileInputStream(f)); + randomIS.readLong(); + if( log.isDebugEnabled() ) + log.debug( "Opening " + devRandomSource ); + return randomIS; + } catch (IOException ex){ + return null; + } + } + } + + + // ------------------------------------------------------------- Properties + + /** + * Return the message digest algorithm for this Manager. + */ + public String getAlgorithm() { + + return (this.algorithm); + + } + + + /** + * Set the message digest algorithm for this Manager. + * + * @param algorithm The new message digest algorithm + */ + public void setAlgorithm(String algorithm) { + + String oldAlgorithm = this.algorithm; + this.algorithm = algorithm; + support.firePropertyChange("algorithm", oldAlgorithm, this.algorithm); + + } + + + /** + * Return the Container with which this Manager is associated. + */ + public Container getContainer() { + + return (this.container); + + } + + + /** + * Set the Container with which this Manager is associated. + * + * @param container The newly associated Container + */ + public void setContainer(Container container) { + + Container oldContainer = this.container; + this.container = container; + support.firePropertyChange("container", oldContainer, this.container); + } + + + /** Returns the name of the implementation class. + */ + public String getClassName() { + return this.getClass().getName(); + } + + + /** + * Return the MessageDigest object to be used for calculating + * session identifiers. If none has been created yet, initialize + * one the first time this method is called. + */ + public synchronized MessageDigest getDigest() { + + if (this.digest == null) { + long t1=System.currentTimeMillis(); + if (log.isDebugEnabled()) + log.debug(sm.getString("managerBase.getting", algorithm)); + try { + this.digest = MessageDigest.getInstance(algorithm); + } catch (NoSuchAlgorithmException e) { + log.error(sm.getString("managerBase.digest", algorithm), e); + try { + this.digest = MessageDigest.getInstance(DEFAULT_ALGORITHM); + } catch (NoSuchAlgorithmException f) { + log.error(sm.getString("managerBase.digest", + DEFAULT_ALGORITHM), e); + this.digest = null; + } + } + if (log.isDebugEnabled()) + log.debug(sm.getString("managerBase.gotten")); + long t2=System.currentTimeMillis(); + if( log.isDebugEnabled() ) + log.debug("getDigest() " + (t2-t1)); + } + + return (this.digest); + + } + + + /** + * Return the distributable flag for the sessions supported by + * this Manager. + */ + public boolean getDistributable() { + + return (this.distributable); + + } + + + /** + * Set the distributable flag for the sessions supported by this + * Manager. If this flag is set, all user data objects added to + * sessions associated with this manager must implement Serializable. + * + * @param distributable The new distributable flag + */ + public void setDistributable(boolean distributable) { + + boolean oldDistributable = this.distributable; + this.distributable = distributable; + support.firePropertyChange("distributable", + new Boolean(oldDistributable), + new Boolean(this.distributable)); + + } + + + /** + * Return the entropy increaser value, or compute a semi-useful value + * if this String has not yet been set. + */ + public String getEntropy() { + + // Calculate a semi-useful value if this has not been set + if (this.entropy == null) { + // Use APR to get a crypto secure entropy value + byte[] result = new byte[32]; + boolean apr = false; + try { + String methodName = "random"; + Class paramTypes[] = new Class[2]; + paramTypes[0] = result.getClass(); + paramTypes[1] = int.class; + Object paramValues[] = new Object[2]; + paramValues[0] = result; + paramValues[1] = new Integer(32); + Method method = Class.forName("org.apache.tomcat.jni.OS") + .getMethod(methodName, paramTypes); + method.invoke(null, paramValues); + apr = true; + } catch (Throwable t) { + // Ignore + } + if (apr) { + setEntropy(new String(result)); + } else { + setEntropy(this.toString()); + } + } + + return (this.entropy); + + } + + + /** + * Set the entropy increaser value. + * + * @param entropy The new entropy increaser value + */ + public void setEntropy(String entropy) { + + String oldEntropy = entropy; + this.entropy = entropy; + support.firePropertyChange("entropy", oldEntropy, this.entropy); + + } + + + /** + * Return descriptive information about this Manager implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the default maximum inactive interval (in seconds) + * for Sessions created by this Manager. + */ + public int getMaxInactiveInterval() { + + return (this.maxInactiveInterval); + + } + + + /** + * Set the default maximum inactive interval (in seconds) + * for Sessions created by this Manager. + * + * @param interval The new default value + */ + public void setMaxInactiveInterval(int interval) { + + int oldMaxInactiveInterval = this.maxInactiveInterval; + this.maxInactiveInterval = interval; + support.firePropertyChange("maxInactiveInterval", + new Integer(oldMaxInactiveInterval), + new Integer(this.maxInactiveInterval)); + + } + + + /** + * Gets the session id length (in bytes) of Sessions created by + * this Manager. + * + * @return The session id length + */ + public int getSessionIdLength() { + + return (this.sessionIdLength); + + } + + + /** + * Sets the session id length (in bytes) for Sessions created by this + * Manager. + * + * @param idLength The session id length + */ + public void setSessionIdLength(int idLength) { + + int oldSessionIdLength = this.sessionIdLength; + this.sessionIdLength = idLength; + support.firePropertyChange("sessionIdLength", + new Integer(oldSessionIdLength), + new Integer(this.sessionIdLength)); + + } + + + /** + * Return the descriptive short name of this Manager implementation. + */ + public String getName() { + + return (name); + + } + + /** + * Use /dev/random-type special device. This is new code, but may reduce + * the big delay in generating the random. + * + * You must specify a path to a random generator file. Use /dev/urandom + * for linux ( or similar ) systems. Use /dev/random for maximum security + * ( it may block if not enough "random" exist ). You can also use + * a pipe that generates random. + * + * The code will check if the file exists, and default to java Random + * if not found. There is a significant performance difference, very + * visible on the first call to getSession ( like in the first JSP ) + * - so use it if available. + */ + public void setRandomFile( String s ) { + // as a hack, you can use a static file - and genarate the same + // session ids ( good for strange debugging ) + if (System.getSecurityManager() != null){ + randomIS = (DataInputStream)AccessController.doPrivileged(new PrivilegedSetRandomFile()); + } else { + try{ + devRandomSource=s; + File f=new File( devRandomSource ); + if( ! f.exists() ) return; + randomIS= new DataInputStream( new FileInputStream(f)); + randomIS.readLong(); + if( log.isDebugEnabled() ) + log.debug( "Opening " + devRandomSource ); + } catch( IOException ex ) { + try { + randomIS.close(); + } catch (Exception e) { + log.warn("Failed to close randomIS."); + } + + randomIS=null; + } + } + } + + public String getRandomFile() { + return devRandomSource; + } + + + /** + * Return the random number generator instance we should use for + * generating session identifiers. If there is no such generator + * currently defined, construct and seed a new one. + */ + public Random getRandom() { + if (this.random == null) { + // Calculate the new random number generator seed + long seed = System.currentTimeMillis(); + long t1 = seed; + char entropy[] = getEntropy().toCharArray(); + for (int i = 0; i < entropy.length; i++) { + long update = ((byte) entropy[i]) << ((i % 8) * 8); + seed ^= update; + } + try { + // Construct and seed a new random number generator + Class clazz = Class.forName(randomClass); + this.random = (Random) clazz.newInstance(); + this.random.setSeed(seed); + } catch (Exception e) { + // Fall back to the simple case + log.error(sm.getString("managerBase.random", randomClass), + e); + this.random = new java.util.Random(); + this.random.setSeed(seed); + } + if(log.isDebugEnabled()) { + long t2=System.currentTimeMillis(); + if( (t2-t1) > 100 ) + log.debug(sm.getString("managerBase.seeding", randomClass) + " " + (t2-t1)); + } + } + + return (this.random); + + } + + + /** + * Return the random number generator class name. + */ + public String getRandomClass() { + + return (this.randomClass); + + } + + + /** + * Set the random number generator class name. + * + * @param randomClass The new random number generator class name + */ + public void setRandomClass(String randomClass) { + + String oldRandomClass = this.randomClass; + this.randomClass = randomClass; + support.firePropertyChange("randomClass", oldRandomClass, + this.randomClass); + + } + + + /** + * Gets the number of sessions that have expired. + * + * @return Number of sessions that have expired + */ + public int getExpiredSessions() { + return expiredSessions; + } + + + /** + * Sets the number of sessions that have expired. + * + * @param expiredSessions Number of sessions that have expired + */ + public void setExpiredSessions(int expiredSessions) { + this.expiredSessions = expiredSessions; + } + + public long getProcessingTime() { + return processingTime; + } + + + public void setProcessingTime(long processingTime) { + this.processingTime = processingTime; + } + + /** + * Return the frequency of manager checks. + */ + public int getProcessExpiresFrequency() { + + return (this.processExpiresFrequency); + + } + + /** + * Set the manager checks frequency. + * + * @param processExpiresFrequency the new manager checks frequency + */ + public void setProcessExpiresFrequency(int processExpiresFrequency) { + + if (processExpiresFrequency <= 0) { + return; + } + + int oldProcessExpiresFrequency = this.processExpiresFrequency; + this.processExpiresFrequency = processExpiresFrequency; + support.firePropertyChange("processExpiresFrequency", + new Integer(oldProcessExpiresFrequency), + new Integer(this.processExpiresFrequency)); + + } + + // --------------------------------------------------------- Public Methods + + + /** + * Implements the Manager interface, direct call to processExpires + */ + public void backgroundProcess() { + count = (count + 1) % processExpiresFrequency; + if (count == 0) + processExpires(); + } + + /** + * Invalidate all sessions that have expired. + */ + public void processExpires() { + + long timeNow = System.currentTimeMillis(); + Session sessions[] = findSessions(); + int expireHere = 0 ; + + if(log.isDebugEnabled()) + log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); + for (int i = 0; i < sessions.length; i++) { + if (!sessions[i].isValid()) { + expireHere++; + } + } + long timeEnd = System.currentTimeMillis(); + if(log.isDebugEnabled()) + log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); + processingTime += ( timeEnd - timeNow ); + + } + + public void destroy() { + if( oname != null ) + Registry.getRegistry(null, null).unregisterComponent(oname); + initialized=false; + oname = null; + } + + public void init() { + if( initialized ) return; + initialized=true; + + if( oname==null ) { + try { + StandardContext ctx=(StandardContext)this.getContainer(); + Engine eng=(Engine)ctx.getParent().getParent(); + domain=ctx.getEngineName(); + distributable = ctx.getDistributable(); + StandardHost hst=(StandardHost)ctx.getParent(); + String path = ctx.getPath(); + if (path.equals("")) { + path = "/"; + } + oname=new ObjectName(domain + ":type=Manager,path=" + + path + ",host=" + hst.getName()); + Registry.getRegistry(null, null).registerComponent(this, oname, null ); + } catch (Exception e) { + log.error("Error registering ",e); + } + } + + // Initialize random number generation + getRandomBytes(new byte[16]); + + if(log.isDebugEnabled()) + log.debug("Registering " + oname ); + + } + + /** + * Add this Session to the set of active Sessions for this Manager. + * + * @param session Session to be added + */ + public void add(Session session) { + + synchronized (sessions) { + sessions.put(session.getIdInternal(), session); + if( sessions.size() > maxActive ) { + maxActive=sessions.size(); + } + } + } + + + /** + * Add a property change listener to this component. + * + * @param listener The listener to add + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + + support.addPropertyChangeListener(listener); + + } + + + /** + * Construct and return a new session object, based on the default + * settings specified by this Manager's properties. The session + * id will be assigned by this method, and available via the getId() + * method of the returned session. If a new session cannot be created + * for any reason, return null. + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + * @deprecated + */ + public Session createSession() { + return createSession(null); + } + + + /** + * Construct and return a new session object, based on the default + * settings specified by this Manager's properties. The session + * id specified will be used as the session id. + * If a new session cannot be created for any reason, return + * null. + * + * @param sessionId The session id which should be used to create the + * new session; if null, a new session id will be + * generated + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + */ + public Session createSession(String sessionId) { + + // Recycle or create a Session instance + Session session = createEmptySession(); + + // Initialize the properties of the new session and return it + session.setNew(true); + session.setValid(true); + session.setCreationTime(System.currentTimeMillis()); + session.setMaxInactiveInterval(this.maxInactiveInterval); + if (sessionId == null) { + sessionId = generateSessionId(); + // FIXME WHy we need no duplication check? + /* + synchronized (sessions) { + while (sessions.get(sessionId) != null) { // Guarantee + // uniqueness + duplicates++; + sessionId = generateSessionId(); + } + } + */ + + // FIXME: Code to be used in case route replacement is needed + /* + } else { + String jvmRoute = getJvmRoute(); + if (getJvmRoute() != null) { + String requestJvmRoute = null; + int index = sessionId.indexOf("."); + if (index > 0) { + requestJvmRoute = sessionId + .substring(index + 1, sessionId.length()); + } + if (requestJvmRoute != null && !requestJvmRoute.equals(jvmRoute)) { + sessionId = sessionId.substring(0, index) + "." + jvmRoute; + } + } + */ + } + session.setId(sessionId); + sessionCounter++; + + return (session); + + } + + + /** + * Get a session from the recycled ones or create a new empty one. + * The PersistentManager manager does not need to create session data + * because it reads it from the Store. + */ + public Session createEmptySession() { + return (getNewSession()); + } + + + /** + * Return the active Session, associated with this Manager, with the + * specified session id (if any); otherwise return null. + * + * @param id The session id for the session to be returned + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + * @exception IOException if an input/output error occurs while + * processing this request + */ + public Session findSession(String id) throws IOException { + + if (id == null) + return (null); + synchronized (sessions) { + Session session = (Session) sessions.get(id); + return (session); + } + + } + + + /** + * Return the set of active Sessions associated with this Manager. + * If this Manager has no active Sessions, a zero-length array is returned. + */ + public Session[] findSessions() { + + Session results[] = null; + synchronized (sessions) { + results = new Session[sessions.size()]; + results = (Session[]) sessions.values().toArray(results); + } + return (results); + + } + + + /** + * Remove this Session from the active Sessions for this Manager. + * + * @param session Session to be removed + */ + public void remove(Session session) { + + synchronized (sessions) { + sessions.remove(session.getIdInternal()); + } + + } + + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + + support.removePropertyChangeListener(listener); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Get new session class to be used in the doLoad() method. + */ + protected StandardSession getNewSession() { + return new StandardSession(this); + } + + + protected void getRandomBytes(byte bytes[]) { + // Generate a byte array containing a session identifier + if (devRandomSource != null && randomIS == null) { + setRandomFile(devRandomSource); + } + if (randomIS != null) { + try { + int len = randomIS.read(bytes); + if (len == bytes.length) { + return; + } + if(log.isDebugEnabled()) + log.debug("Got " + len + " " + bytes.length ); + } catch (Exception ex) { + // Ignore + } + devRandomSource = null; + + try { + randomIS.close(); + } catch (Exception e) { + log.warn("Failed to close randomIS."); + } + + randomIS = null; + } + getRandom().nextBytes(bytes); + } + + + /** + * Generate and return a new session identifier. + */ + protected synchronized String generateSessionId() { + + byte random[] = new byte[16]; + String jvmRoute = getJvmRoute(); + String result = null; + + // Render the result as a String of hexadecimal digits + StringBuffer buffer = new StringBuffer(); + do { + int resultLenBytes = 0; + if (result != null) { + buffer = new StringBuffer(); + duplicates++; + } + + while (resultLenBytes < this.sessionIdLength) { + getRandomBytes(random); + random = getDigest().digest(random); + for (int j = 0; + j < random.length && resultLenBytes < this.sessionIdLength; + j++) { + byte b1 = (byte) ((random[j] & 0xf0) >> 4); + byte b2 = (byte) (random[j] & 0x0f); + if (b1 < 10) + buffer.append((char) ('0' + b1)); + else + buffer.append((char) ('A' + (b1 - 10))); + if (b2 < 10) + buffer.append((char) ('0' + b2)); + else + buffer.append((char) ('A' + (b2 - 10))); + resultLenBytes++; + } + } + if (jvmRoute != null) { + buffer.append('.').append(jvmRoute); + } + result = buffer.toString(); + } while (sessions.containsKey(result)); + return (result); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Retrieve the enclosing Engine for this Manager. + * + * @return an Engine object (or null). + */ + public Engine getEngine() { + Engine e = null; + for (Container c = getContainer(); e == null && c != null ; c = c.getParent()) { + if (c != null && c instanceof Engine) { + e = (Engine)c; + } + } + return e; + } + + + /** + * Retrieve the JvmRoute for the enclosing Engine. + * @return the JvmRoute or null. + */ + public String getJvmRoute() { + Engine e = getEngine(); + return e == null ? null : e.getJvmRoute(); + } + + + // -------------------------------------------------------- Package Methods + + + public void setSessionCounter(int sessionCounter) { + this.sessionCounter = sessionCounter; + } + + + /** + * Total sessions created by this manager. + * + * @return sessions created + */ + public int getSessionCounter() { + return sessionCounter; + } + + + /** + * Number of duplicated session IDs generated by the random source. + * Anything bigger than 0 means problems. + * + * @return The count of duplicates + */ + public int getDuplicates() { + return duplicates; + } + + + public void setDuplicates(int duplicates) { + this.duplicates = duplicates; + } + + + /** + * Returns the number of active sessions + * + * @return number of sessions active + */ + public int getActiveSessions() { + return sessions.size(); + } + + + /** + * Max number of concurrent active sessions + * + * @return The highest number of concurrent active sessions + */ + public int getMaxActive() { + return maxActive; + } + + + public void setMaxActive(int maxActive) { + this.maxActive = maxActive; + } + + + /** + * Gets the longest time (in seconds) that an expired session had been + * alive. + * + * @return Longest time (in seconds) that an expired session had been + * alive. + */ + public int getSessionMaxAliveTime() { + return sessionMaxAliveTime; + } + + + /** + * Sets the longest time (in seconds) that an expired session had been + * alive. + * + * @param sessionMaxAliveTime Longest time (in seconds) that an expired + * session had been alive. + */ + public void setSessionMaxAliveTime(int sessionMaxAliveTime) { + this.sessionMaxAliveTime = sessionMaxAliveTime; + } + + + /** + * Gets the average time (in seconds) that expired sessions had been + * alive. + * + * @return Average time (in seconds) that expired sessions had been + * alive. + */ + public int getSessionAverageAliveTime() { + return sessionAverageAliveTime; + } + + + /** + * Sets the average time (in seconds) that expired sessions had been + * alive. + * + * @param sessionAverageAliveTime Average time (in seconds) that expired + * sessions had been alive. + */ + public void setSessionAverageAliveTime(int sessionAverageAliveTime) { + this.sessionAverageAliveTime = sessionAverageAliveTime; + } + + + /** + * For debugging: return a list of all session ids currently active + * + */ + public String listSessionIds() { + StringBuffer sb=new StringBuffer(); + Iterator keys=sessions.keySet().iterator(); + while( keys.hasNext() ) { + sb.append(keys.next()).append(" "); + } + return sb.toString(); + } + + + /** + * For debugging: get a session attribute + * + * @param sessionId + * @param key + * @return The attribute value, if found, null otherwise + */ + public String getSessionAttribute( String sessionId, String key ) { + Session s=(Session)sessions.get(sessionId); + if( s==null ) { + if(log.isInfoEnabled()) + log.info("Session not found " + sessionId); + return null; + } + Object o=s.getSession().getAttribute(key); + if( o==null ) return null; + return o.toString(); + } + + + /** + * Returns information about the session with the given session id. + * + *

    The session information is organized as a HashMap, mapping + * session attribute names to the String representation of their values. + * + * @param sessionId Session id + * + * @return HashMap mapping session attribute names to the String + * representation of their values, or null if no session with the + * specified id exists, or if the session does not have any attributes + */ + public HashMap getSession(String sessionId) { + Session s = (Session) sessions.get(sessionId); + if (s == null) { + if (log.isInfoEnabled()) { + log.info("Session not found " + sessionId); + } + return null; + } + + Enumeration ee = s.getSession().getAttributeNames(); + if (ee == null || !ee.hasMoreElements()) { + return null; + } + + HashMap map = new HashMap(); + while (ee.hasMoreElements()) { + String attrName = (String) ee.nextElement(); + map.put(attrName, getSessionAttribute(sessionId, attrName)); + } + + return map; + } + + + public void expireSession( String sessionId ) { + Session s=(Session)sessions.get(sessionId); + if( s==null ) { + if(log.isInfoEnabled()) + log.info("Session not found " + sessionId); + return; + } + s.expire(); + } + + + public String getLastAccessedTime( String sessionId ) { + Session s=(Session)sessions.get(sessionId); + if( s==null ) { + log.info("Session not found " + sessionId); + return ""; + } + return new Date(s.getLastAccessedTime()).toString(); + } + + + // -------------------- JMX and Registration -------------------- + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + +} diff --git a/java/org/apache/catalina/session/PersistentManager.java b/java/org/apache/catalina/session/PersistentManager.java index 412cf206a..e92b4e050 100644 --- a/java/org/apache/catalina/session/PersistentManager.java +++ b/java/org/apache/catalina/session/PersistentManager.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - -/** - * Implementation of the Manager interface that makes use of - * a Store to swap active Sessions to disk. It can be configured to - * achieve several different goals: - * - *

  • Persist sessions across restarts of the Container
  • - *
  • Fault tolerance, keep sessions backed up on disk to allow - * recovery in the event of unplanned restarts.
  • - *
  • Limit the number of active sessions kept in memory by - * swapping less active sessions out to disk.
  • - * - * @version $Revision: 302726 $ - * @author Kief Morris (kief@kief.com) - */ - -public final class PersistentManager extends PersistentManagerBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information about this implementation. - */ - private static final String info = "PersistentManager/1.0"; - - - /** - * The descriptive name of this Manager implementation (for logging). - */ - protected static String name = "PersistentManager"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Manager implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - /** - * Return the descriptive short name of this Manager implementation. - */ - public String getName() { - - return (name); - - } - } - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + +/** + * Implementation of the Manager interface that makes use of + * a Store to swap active Sessions to disk. It can be configured to + * achieve several different goals: + * + *
  • Persist sessions across restarts of the Container
  • + *
  • Fault tolerance, keep sessions backed up on disk to allow + * recovery in the event of unplanned restarts.
  • + *
  • Limit the number of active sessions kept in memory by + * swapping less active sessions out to disk.
  • + * + * @version $Revision: 302726 $ + * @author Kief Morris (kief@kief.com) + */ + +public final class PersistentManager extends PersistentManagerBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information about this implementation. + */ + private static final String info = "PersistentManager/1.0"; + + + /** + * The descriptive name of this Manager implementation (for logging). + */ + protected static String name = "PersistentManager"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Manager implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + /** + * Return the descriptive short name of this Manager implementation. + */ + public String getName() { + + return (name); + + } + } + diff --git a/java/org/apache/catalina/session/PersistentManagerBase.java b/java/org/apache/catalina/session/PersistentManagerBase.java index cb5441528..ae73a5d95 100644 --- a/java/org/apache/catalina/session/PersistentManagerBase.java +++ b/java/org/apache/catalina/session/PersistentManagerBase.java @@ -1,1130 +1,1130 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.IOException; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Session; -import org.apache.catalina.Store; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.catalina.security.SecurityUtil; -/** - * Extends the ManagerBase class to implement most of the - * functionality required by a Manager which supports any kind of - * persistence, even if onlyfor restarts. - *

    - * IMPLEMENTATION NOTE: Correct behavior of session storing and - * reloading depends upon external calls to the start() and - * stop() methods of this class at the correct times. - * - * @author Craig R. McClanahan - * @author Jean-Francois Arcand - * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public abstract class PersistentManagerBase - extends ManagerBase - implements Lifecycle, PropertyChangeListener { - - private static Log log = LogFactory.getLog(PersistentManagerBase.class); - - // ---------------------------------------------------- Security Classes - - private class PrivilegedStoreClear - implements PrivilegedExceptionAction { - - PrivilegedStoreClear() { - } - - public Object run() throws Exception{ - store.clear(); - return null; - } - } - - private class PrivilegedStoreRemove - implements PrivilegedExceptionAction { - - private String id; - - PrivilegedStoreRemove(String id) { - this.id = id; - } - - public Object run() throws Exception{ - store.remove(id); - return null; - } - } - - private class PrivilegedStoreLoad - implements PrivilegedExceptionAction { - - private String id; - - PrivilegedStoreLoad(String id) { - this.id = id; - } - - public Object run() throws Exception{ - return store.load(id); - } - } - - private class PrivilegedStoreSave - implements PrivilegedExceptionAction { - - private Session session; - - PrivilegedStoreSave(Session session) { - this.session = session; - } - - public Object run() throws Exception{ - store.save(session); - return null; - } - } - - private class PrivilegedStoreKeys - implements PrivilegedExceptionAction { - - PrivilegedStoreKeys() { - } - - public Object run() throws Exception{ - return store.keys(); - } - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information about this implementation. - */ - private static final String info = "PersistentManagerBase/1.1"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The maximum number of active Sessions allowed, or -1 for no limit. - */ - protected int maxActiveSessions = -1; - - - /** - * The descriptive name of this Manager implementation (for logging). - */ - private static String name = "PersistentManagerBase"; - - - /** - * Has this component been started yet? - */ - protected boolean started = false; - - - /** - * Store object which will manage the Session store. - */ - protected Store store = null; - - - /** - * Whether to save and reload sessions when the Manager unload - * and load methods are called. - */ - protected boolean saveOnRestart = true; - - - /** - * How long a session must be idle before it should be backed up. - * -1 means sessions won't be backed up. - */ - protected int maxIdleBackup = -1; - - - /** - * Minimum time a session must be idle before it is swapped to disk. - * This overrides maxActiveSessions, to prevent thrashing if there are lots - * of active sessions. Setting to -1 means it's ignored. - */ - protected int minIdleSwap = -1; - - /** - * The maximum time a session may be idle before it should be swapped - * to file just on general principle. Setting this to -1 means sessions - * should not be forced out. - */ - protected int maxIdleSwap = -1; - - - /** - * Number of session creations that failed due to maxActiveSessions. - */ - protected int rejectedSessions = 0; - - - /** - * Processing time during session expiration and passivation. - */ - protected long processingTime = 0; - - - // ------------------------------------------------------------- Properties - - - - - - /** - * Indicates how many seconds old a session can get, after its last use in a - * request, before it should be backed up to the store. -1 means sessions - * are not backed up. - */ - public int getMaxIdleBackup() { - - return maxIdleBackup; - - } - - - /** - * Sets the option to back sessions up to the Store after they - * are used in a request. Sessions remain available in memory - * after being backed up, so they are not passivated as they are - * when swapped out. The value set indicates how old a session - * may get (since its last use) before it must be backed up: -1 - * means sessions are not backed up. - *

    - * Note that this is not a hard limit: sessions are checked - * against this age limit periodically according to processExpiresFrequency. - * This value should be considered to indicate when a session is - * ripe for backing up. - *

    - * So it is possible that a session may be idle for maxIdleBackup + - * processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other - * session expiration, swapping, etc. tasks. - * - * @param backup The number of seconds after their last accessed - * time when they should be written to the Store. - */ - public void setMaxIdleBackup (int backup) { - - if (backup == this.maxIdleBackup) - return; - int oldBackup = this.maxIdleBackup; - this.maxIdleBackup = backup; - support.firePropertyChange("maxIdleBackup", - new Integer(oldBackup), - new Integer(this.maxIdleBackup)); - - } - - - /** - * The time in seconds after which a session should be swapped out of - * memory to disk. - */ - public int getMaxIdleSwap() { - - return maxIdleSwap; - - } - - - /** - * Sets the time in seconds after which a session should be swapped out of - * memory to disk. - */ - public void setMaxIdleSwap(int max) { - - if (max == this.maxIdleSwap) - return; - int oldMaxIdleSwap = this.maxIdleSwap; - this.maxIdleSwap = max; - support.firePropertyChange("maxIdleSwap", - new Integer(oldMaxIdleSwap), - new Integer(this.maxIdleSwap)); - - } - - - /** - * The minimum time in seconds that a session must be idle before - * it can be swapped out of memory, or -1 if it can be swapped out - * at any time. - */ - public int getMinIdleSwap() { - - return minIdleSwap; - - } - - - /** - * Sets the minimum time in seconds that a session must be idle before - * it can be swapped out of memory due to maxActiveSession. Set it to -1 - * if it can be swapped out at any time. - */ - public void setMinIdleSwap(int min) { - - if (this.minIdleSwap == min) - return; - int oldMinIdleSwap = this.minIdleSwap; - this.minIdleSwap = min; - support.firePropertyChange("minIdleSwap", - new Integer(oldMinIdleSwap), - new Integer(this.minIdleSwap)); - - } - - - /** - * Set the Container with which this Manager has been associated. If it is a - * Context (the usual case), listen for changes to the session timeout - * property. - * - * @param container - * The associated Container - */ - public void setContainer(Container container) { - - // De-register from the old Container (if any) - if ((this.container != null) && (this.container instanceof Context)) - ((Context) this.container).removePropertyChangeListener(this); - - // Default processing provided by our superclass - super.setContainer(container); - - // Register with the new Container (if any) - if ((this.container != null) && (this.container instanceof Context)) { - setMaxInactiveInterval - ( ((Context) this.container).getSessionTimeout()*60 ); - ((Context) this.container).addPropertyChangeListener(this); - } - - } - - - /** - * Return descriptive information about this Manager implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return true, if the session id is loaded in memory - * otherwise false is returned - * - * @param id The session id for the session to be searched for - */ - public boolean isLoaded( String id ){ - try { - if ( super.findSession(id) != null ) - return true; - } catch (IOException e) { - log.error("checking isLoaded for id, " + id + ", "+e.getMessage(), e); - } - return false; - } - - - /** - * Return the maximum number of active Sessions allowed, or -1 for - * no limit. - */ - public int getMaxActiveSessions() { - - return (this.maxActiveSessions); - - } - - - /** - * Set the maximum number of actives Sessions allowed, or -1 for - * no limit. - * - * @param max The new maximum number of sessions - */ - public void setMaxActiveSessions(int max) { - - int oldMaxActiveSessions = this.maxActiveSessions; - this.maxActiveSessions = max; - support.firePropertyChange("maxActiveSessions", - new Integer(oldMaxActiveSessions), - new Integer(this.maxActiveSessions)); - - } - - - /** - * Number of session creations that failed due to maxActiveSessions. - * - * @return The count - */ - public int getRejectedSessions() { - return rejectedSessions; - } - - - public void setRejectedSessions(int rejectedSessions) { - this.rejectedSessions = rejectedSessions; - } - - /** - * Return the descriptive short name of this Manager implementation. - */ - public String getName() { - - return (name); - - } - - - /** - * Get the started status. - */ - protected boolean isStarted() { - - return started; - - } - - - /** - * Set the started flag - */ - protected void setStarted(boolean started) { - - this.started = started; - - } - - - /** - * Set the Store object which will manage persistent Session - * storage for this Manager. - * - * @param store the associated Store - */ - public void setStore(Store store) { - this.store = store; - store.setManager(this); - - } - - - /** - * Return the Store object which manages persistent Session - * storage for this Manager. - */ - public Store getStore() { - - return (this.store); - - } - - - - /** - * Indicates whether sessions are saved when the Manager is shut down - * properly. This requires the unload() method to be called. - */ - public boolean getSaveOnRestart() { - - return saveOnRestart; - - } - - - /** - * Set the option to save sessions to the Store when the Manager is - * shut down, then loaded when the Manager starts again. If set to - * false, any sessions found in the Store may still be picked up when - * the Manager is started again. - * - * @param saveOnRestart true if sessions should be saved on restart, false if - * they should be ignored. - */ - public void setSaveOnRestart(boolean saveOnRestart) { - - if (saveOnRestart == this.saveOnRestart) - return; - - boolean oldSaveOnRestart = this.saveOnRestart; - this.saveOnRestart = saveOnRestart; - support.firePropertyChange("saveOnRestart", - new Boolean(oldSaveOnRestart), - new Boolean(this.saveOnRestart)); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Clear all sessions from the Store. - */ - public void clearStore() { - - if (store == null) - return; - - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged(new PrivilegedStoreClear()); - }catch(PrivilegedActionException ex){ - Exception exception = ex.getException(); - log.error("Exception clearing the Store: " + exception); - exception.printStackTrace(); - } - } else { - store.clear(); - } - } catch (IOException e) { - log.error("Exception clearing the Store: " + e); - e.printStackTrace(); - } - - } - - - /** - * Implements the Manager interface, direct call to processExpires and processPersistenceChecks - */ - public void processExpires() { - - long timeNow = System.currentTimeMillis(); - Session sessions[] = findSessions(); - int expireHere = 0 ; - if(log.isDebugEnabled()) - log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); - for (int i = 0; i < sessions.length; i++) { - if (!sessions[i].isValid()) { - expiredSessions++; - expireHere++; - } - } - processPersistenceChecks(); - if ((getStore() != null) && (getStore() instanceof StoreBase)) { - ((StoreBase) getStore()).processExpires(); - } - - long timeEnd = System.currentTimeMillis(); - if(log.isDebugEnabled()) - log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); - processingTime += (timeEnd - timeNow); - - } - - - /** - * Called by the background thread after active sessions have been checked - * for expiration, to allow sessions to be swapped out, backed up, etc. - */ - public void processPersistenceChecks() { - - processMaxIdleSwaps(); - processMaxActiveSwaps(); - processMaxIdleBackups(); - - } - - - /** - * Return the active Session, associated with this Manager, with the - * specified session id (if any); otherwise return null. - * This method checks the persistence store if persistence is enabled, - * otherwise just uses the functionality from ManagerBase. - * - * @param id The session id for the session to be returned - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - * @exception IOException if an input/output error occurs while - * processing this request - */ - public Session findSession(String id) throws IOException { - - Session session = super.findSession(id); - if (session != null) - return (session); - - // See if the Session is in the Store - session = swapIn(id); - return (session); - - } - - /** - * Remove this Session from the active Sessions for this Manager, - * but not from the Store. (Used by the PersistentValve) - * - * @param session Session to be removed - */ - public void removeSuper(Session session) { - super.remove (session); - } - - /** - * Load all sessions found in the persistence mechanism, assuming - * they are marked as valid and have not passed their expiration - * limit. If persistence is not supported, this method returns - * without doing anything. - *

    - * Note that by default, this method is not called by the MiddleManager - * class. In order to use it, a subclass must specifically call it, - * for example in the start() and/or processPersistenceChecks() methods. - */ - public void load() { - - // Initialize our internal data structures - sessions.clear(); - - if (store == null) - return; - - String[] ids = null; - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - ids = (String[]) - AccessController.doPrivileged(new PrivilegedStoreKeys()); - }catch(PrivilegedActionException ex){ - Exception exception = ex.getException(); - log.error("Exception in the Store during load: " - + exception); - exception.printStackTrace(); - } - } else { - ids = store.keys(); - } - } catch (IOException e) { - log.error("Can't load sessions from store, " + e.getMessage(), e); - return; - } - - int n = ids.length; - if (n == 0) - return; - - if (log.isDebugEnabled()) - log.debug(sm.getString("persistentManager.loading", String.valueOf(n))); - - for (int i = 0; i < n; i++) - try { - swapIn(ids[i]); - } catch (IOException e) { - log.error("Failed load session from store, " + e.getMessage(), e); - } - - } - - - /** - * Remove this Session from the active Sessions for this Manager, - * and from the Store. - * - * @param session Session to be removed - */ - public void remove(Session session) { - - super.remove (session); - - if (store != null){ - removeSession(session.getIdInternal()); - } - } - - - /** - * Remove this Session from the active Sessions for this Manager, - * and from the Store. - * - * @param id Session's id to be removed - */ - protected void removeSession(String id){ - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged(new PrivilegedStoreRemove(id)); - }catch(PrivilegedActionException ex){ - Exception exception = ex.getException(); - log.error("Exception in the Store during removeSession: " - + exception); - exception.printStackTrace(); - } - } else { - store.remove(id); - } - } catch (IOException e) { - log.error("Exception removing session " + e.getMessage()); - e.printStackTrace(); - } - } - - /** - * Save all currently active sessions in the appropriate persistence - * mechanism, if any. If persistence is not supported, this method - * returns without doing anything. - *

    - * Note that by default, this method is not called by the MiddleManager - * class. In order to use it, a subclass must specifically call it, - * for example in the stop() and/or processPersistenceChecks() methods. - */ - public void unload() { - - if (store == null) - return; - - Session sessions[] = findSessions(); - int n = sessions.length; - if (n == 0) - return; - - if (log.isDebugEnabled()) - log.debug(sm.getString("persistentManager.unloading", - String.valueOf(n))); - - for (int i = 0; i < n; i++) - try { - swapOut(sessions[i]); - } catch (IOException e) { - ; // This is logged in writeSession() - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Look for a session in the Store and, if found, restore - * it in the Manager's list of active sessions if appropriate. - * The session will be removed from the Store after swapping - * in, but will not be added to the active session list if it - * is invalid or past its expiration. - */ - protected Session swapIn(String id) throws IOException { - - if (store == null) - return null; - - Session session = null; - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - session = (Session) - AccessController.doPrivileged(new PrivilegedStoreLoad(id)); - }catch(PrivilegedActionException ex){ - Exception exception = ex.getException(); - log.error("Exception in the Store during swapIn: " - + exception); - if (exception instanceof IOException){ - throw (IOException)exception; - } else if (exception instanceof ClassNotFoundException) { - throw (ClassNotFoundException)exception; - } - } - } else { - session = store.load(id); - } - } catch (ClassNotFoundException e) { - log.error(sm.getString("persistentManager.deserializeError", id, e)); - throw new IllegalStateException - (sm.getString("persistentManager.deserializeError", id, e)); - } - - if (session == null) - return (null); - - if (!session.isValid()) { - log.error("session swapped in is invalid or expired"); - session.expire(); - removeSession(id); - return (null); - } - - if(log.isDebugEnabled()) - log.debug(sm.getString("persistentManager.swapIn", id)); - - session.setManager(this); - // make sure the listeners know about it. - ((StandardSession)session).tellNew(); - add(session); - ((StandardSession)session).activate(); - session.endAccess(); - - return (session); - - } - - - /** - * Remove the session from the Manager's list of active - * sessions and write it out to the Store. If the session - * is past its expiration or invalid, this method does - * nothing. - * - * @param session The Session to write out. - */ - protected void swapOut(Session session) throws IOException { - - if (store == null || !session.isValid()) { - return; - } - - ((StandardSession)session).passivate(); - writeSession(session); - super.remove(session); - session.recycle(); - - } - - - /** - * Write the provided session to the Store without modifying - * the copy in memory or triggering passivation events. Does - * nothing if the session is invalid or past its expiration. - */ - protected void writeSession(Session session) throws IOException { - - if (store == null || !session.isValid()) { - return; - } - - try { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged(new PrivilegedStoreSave(session)); - }catch(PrivilegedActionException ex){ - Exception exception = ex.getException(); - log.error("Exception in the Store during writeSession: " - + exception); - exception.printStackTrace(); - } - } else { - store.save(session); - } - } catch (IOException e) { - log.error(sm.getString - ("persistentManager.serializeError", session.getIdInternal(), e)); - throw e; - } - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) { - log.info(sm.getString("standardManager.alreadyStarted")); - return; - } - if( ! initialized ) - init(); - - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Force initialization of the random number generator - if (log.isDebugEnabled()) - log.debug("Force random number initialization starting"); - String dummy = generateSessionId(); - if (log.isDebugEnabled()) - log.debug("Force random number initialization completed"); - - if (store == null) - log.error("No Store configured, persistence disabled"); - else if (store instanceof Lifecycle) - ((Lifecycle)store).start(); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - if (log.isDebugEnabled()) - log.debug("Stopping"); - - // Validate and update our current component state - if (!isStarted()) { - log.info(sm.getString("standardManager.notStarted")); - return; - } - - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - setStarted(false); - - if (getStore() != null && saveOnRestart) { - unload(); - } else { - // Expire all active sessions - Session sessions[] = findSessions(); - for (int i = 0; i < sessions.length; i++) { - StandardSession session = (StandardSession) sessions[i]; - if (!session.isValid()) - continue; - session.expire(); - } - } - - if (getStore() != null && getStore() instanceof Lifecycle) - ((Lifecycle)getStore()).stop(); - - // Require a new random number generator if we are restarted - this.random = null; - - if( initialized ) - destroy(); - - } - - - // ----------------------------------------- PropertyChangeListener Methods - - - /** - * Process property change events from our associated Context. - * - * @param event The property change event that has occurred - */ - public void propertyChange(PropertyChangeEvent event) { - - // Validate the source of this event - if (!(event.getSource() instanceof Context)) - return; - Context context = (Context) event.getSource(); - - // Process a relevant property change - if (event.getPropertyName().equals("sessionTimeout")) { - try { - setMaxInactiveInterval - ( ((Integer) event.getNewValue()).intValue()*60 ); - } catch (NumberFormatException e) { - log.error(sm.getString("standardManager.sessionTimeout", - event.getNewValue().toString())); - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Swap idle sessions out to Store if they are idle too long. - */ - protected void processMaxIdleSwaps() { - - if (!isStarted() || maxIdleSwap < 0) - return; - - Session sessions[] = findSessions(); - long timeNow = System.currentTimeMillis(); - - // Swap out all sessions idle longer than maxIdleSwap - // FIXME: What's preventing us from mangling a session during - // a request? - if (maxIdleSwap >= 0) { - for (int i = 0; i < sessions.length; i++) { - StandardSession session = (StandardSession) sessions[i]; - if (!session.isValid()) - continue; - int timeIdle = // Truncate, do not round up - (int) ((timeNow - session.getLastAccessedTime()) / 1000L); - if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) { - if (log.isDebugEnabled()) - log.debug(sm.getString - ("persistentManager.swapMaxIdle", - session.getIdInternal(), new Integer(timeIdle))); - try { - swapOut(session); - } catch (IOException e) { - ; // This is logged in writeSession() - } - } - } - } - - } - - - /** - * Swap idle sessions out to Store if too many are active - */ - protected void processMaxActiveSwaps() { - - if (!isStarted() || getMaxActiveSessions() < 0) - return; - - Session sessions[] = findSessions(); - - // FIXME: Smarter algorithm (LRU) - if (getMaxActiveSessions() >= sessions.length) - return; - - if(log.isDebugEnabled()) - log.debug(sm.getString - ("persistentManager.tooManyActive", - new Integer(sessions.length))); - - int toswap = sessions.length - getMaxActiveSessions(); - long timeNow = System.currentTimeMillis(); - - for (int i = 0; i < sessions.length && toswap > 0; i++) { - int timeIdle = // Truncate, do not round up - (int) ((timeNow - sessions[i].getLastAccessedTime()) / 1000L); - if (timeIdle > minIdleSwap) { - if(log.isDebugEnabled()) - log.debug(sm.getString - ("persistentManager.swapTooManyActive", - sessions[i].getIdInternal(), new Integer(timeIdle))); - try { - swapOut(sessions[i]); - } catch (IOException e) { - ; // This is logged in writeSession() - } - toswap--; - } - } - - } - - - /** - * Back up idle sessions. - */ - protected void processMaxIdleBackups() { - - if (!isStarted() || maxIdleBackup < 0) - return; - - Session sessions[] = findSessions(); - long timeNow = System.currentTimeMillis(); - - // Back up all sessions idle longer than maxIdleBackup - if (maxIdleBackup >= 0) { - for (int i = 0; i < sessions.length; i++) { - StandardSession session = (StandardSession) sessions[i]; - if (!session.isValid()) - continue; - int timeIdle = // Truncate, do not round up - (int) ((timeNow - session.getLastAccessedTime()) / 1000L); - if (timeIdle > maxIdleBackup) { - if (log.isDebugEnabled()) - log.debug(sm.getString - ("persistentManager.backupMaxIdle", - session.getIdInternal(), new Integer(timeIdle))); - - try { - writeSession(session); - } catch (IOException e) { - ; // This is logged in writeSession() - } - } - } - } - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Session; +import org.apache.catalina.Store; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.catalina.security.SecurityUtil; +/** + * Extends the ManagerBase class to implement most of the + * functionality required by a Manager which supports any kind of + * persistence, even if onlyfor restarts. + *

    + * IMPLEMENTATION NOTE: Correct behavior of session storing and + * reloading depends upon external calls to the start() and + * stop() methods of this class at the correct times. + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand + * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public abstract class PersistentManagerBase + extends ManagerBase + implements Lifecycle, PropertyChangeListener { + + private static Log log = LogFactory.getLog(PersistentManagerBase.class); + + // ---------------------------------------------------- Security Classes + + private class PrivilegedStoreClear + implements PrivilegedExceptionAction { + + PrivilegedStoreClear() { + } + + public Object run() throws Exception{ + store.clear(); + return null; + } + } + + private class PrivilegedStoreRemove + implements PrivilegedExceptionAction { + + private String id; + + PrivilegedStoreRemove(String id) { + this.id = id; + } + + public Object run() throws Exception{ + store.remove(id); + return null; + } + } + + private class PrivilegedStoreLoad + implements PrivilegedExceptionAction { + + private String id; + + PrivilegedStoreLoad(String id) { + this.id = id; + } + + public Object run() throws Exception{ + return store.load(id); + } + } + + private class PrivilegedStoreSave + implements PrivilegedExceptionAction { + + private Session session; + + PrivilegedStoreSave(Session session) { + this.session = session; + } + + public Object run() throws Exception{ + store.save(session); + return null; + } + } + + private class PrivilegedStoreKeys + implements PrivilegedExceptionAction { + + PrivilegedStoreKeys() { + } + + public Object run() throws Exception{ + return store.keys(); + } + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information about this implementation. + */ + private static final String info = "PersistentManagerBase/1.1"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The maximum number of active Sessions allowed, or -1 for no limit. + */ + protected int maxActiveSessions = -1; + + + /** + * The descriptive name of this Manager implementation (for logging). + */ + private static String name = "PersistentManagerBase"; + + + /** + * Has this component been started yet? + */ + protected boolean started = false; + + + /** + * Store object which will manage the Session store. + */ + protected Store store = null; + + + /** + * Whether to save and reload sessions when the Manager unload + * and load methods are called. + */ + protected boolean saveOnRestart = true; + + + /** + * How long a session must be idle before it should be backed up. + * -1 means sessions won't be backed up. + */ + protected int maxIdleBackup = -1; + + + /** + * Minimum time a session must be idle before it is swapped to disk. + * This overrides maxActiveSessions, to prevent thrashing if there are lots + * of active sessions. Setting to -1 means it's ignored. + */ + protected int minIdleSwap = -1; + + /** + * The maximum time a session may be idle before it should be swapped + * to file just on general principle. Setting this to -1 means sessions + * should not be forced out. + */ + protected int maxIdleSwap = -1; + + + /** + * Number of session creations that failed due to maxActiveSessions. + */ + protected int rejectedSessions = 0; + + + /** + * Processing time during session expiration and passivation. + */ + protected long processingTime = 0; + + + // ------------------------------------------------------------- Properties + + + + + + /** + * Indicates how many seconds old a session can get, after its last use in a + * request, before it should be backed up to the store. -1 means sessions + * are not backed up. + */ + public int getMaxIdleBackup() { + + return maxIdleBackup; + + } + + + /** + * Sets the option to back sessions up to the Store after they + * are used in a request. Sessions remain available in memory + * after being backed up, so they are not passivated as they are + * when swapped out. The value set indicates how old a session + * may get (since its last use) before it must be backed up: -1 + * means sessions are not backed up. + *

    + * Note that this is not a hard limit: sessions are checked + * against this age limit periodically according to processExpiresFrequency. + * This value should be considered to indicate when a session is + * ripe for backing up. + *

    + * So it is possible that a session may be idle for maxIdleBackup + + * processExpiresFrequency * engine.backgroundProcessorDelay seconds, plus the time it takes to handle other + * session expiration, swapping, etc. tasks. + * + * @param backup The number of seconds after their last accessed + * time when they should be written to the Store. + */ + public void setMaxIdleBackup (int backup) { + + if (backup == this.maxIdleBackup) + return; + int oldBackup = this.maxIdleBackup; + this.maxIdleBackup = backup; + support.firePropertyChange("maxIdleBackup", + new Integer(oldBackup), + new Integer(this.maxIdleBackup)); + + } + + + /** + * The time in seconds after which a session should be swapped out of + * memory to disk. + */ + public int getMaxIdleSwap() { + + return maxIdleSwap; + + } + + + /** + * Sets the time in seconds after which a session should be swapped out of + * memory to disk. + */ + public void setMaxIdleSwap(int max) { + + if (max == this.maxIdleSwap) + return; + int oldMaxIdleSwap = this.maxIdleSwap; + this.maxIdleSwap = max; + support.firePropertyChange("maxIdleSwap", + new Integer(oldMaxIdleSwap), + new Integer(this.maxIdleSwap)); + + } + + + /** + * The minimum time in seconds that a session must be idle before + * it can be swapped out of memory, or -1 if it can be swapped out + * at any time. + */ + public int getMinIdleSwap() { + + return minIdleSwap; + + } + + + /** + * Sets the minimum time in seconds that a session must be idle before + * it can be swapped out of memory due to maxActiveSession. Set it to -1 + * if it can be swapped out at any time. + */ + public void setMinIdleSwap(int min) { + + if (this.minIdleSwap == min) + return; + int oldMinIdleSwap = this.minIdleSwap; + this.minIdleSwap = min; + support.firePropertyChange("minIdleSwap", + new Integer(oldMinIdleSwap), + new Integer(this.minIdleSwap)); + + } + + + /** + * Set the Container with which this Manager has been associated. If it is a + * Context (the usual case), listen for changes to the session timeout + * property. + * + * @param container + * The associated Container + */ + public void setContainer(Container container) { + + // De-register from the old Container (if any) + if ((this.container != null) && (this.container instanceof Context)) + ((Context) this.container).removePropertyChangeListener(this); + + // Default processing provided by our superclass + super.setContainer(container); + + // Register with the new Container (if any) + if ((this.container != null) && (this.container instanceof Context)) { + setMaxInactiveInterval + ( ((Context) this.container).getSessionTimeout()*60 ); + ((Context) this.container).addPropertyChangeListener(this); + } + + } + + + /** + * Return descriptive information about this Manager implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return true, if the session id is loaded in memory + * otherwise false is returned + * + * @param id The session id for the session to be searched for + */ + public boolean isLoaded( String id ){ + try { + if ( super.findSession(id) != null ) + return true; + } catch (IOException e) { + log.error("checking isLoaded for id, " + id + ", "+e.getMessage(), e); + } + return false; + } + + + /** + * Return the maximum number of active Sessions allowed, or -1 for + * no limit. + */ + public int getMaxActiveSessions() { + + return (this.maxActiveSessions); + + } + + + /** + * Set the maximum number of actives Sessions allowed, or -1 for + * no limit. + * + * @param max The new maximum number of sessions + */ + public void setMaxActiveSessions(int max) { + + int oldMaxActiveSessions = this.maxActiveSessions; + this.maxActiveSessions = max; + support.firePropertyChange("maxActiveSessions", + new Integer(oldMaxActiveSessions), + new Integer(this.maxActiveSessions)); + + } + + + /** + * Number of session creations that failed due to maxActiveSessions. + * + * @return The count + */ + public int getRejectedSessions() { + return rejectedSessions; + } + + + public void setRejectedSessions(int rejectedSessions) { + this.rejectedSessions = rejectedSessions; + } + + /** + * Return the descriptive short name of this Manager implementation. + */ + public String getName() { + + return (name); + + } + + + /** + * Get the started status. + */ + protected boolean isStarted() { + + return started; + + } + + + /** + * Set the started flag + */ + protected void setStarted(boolean started) { + + this.started = started; + + } + + + /** + * Set the Store object which will manage persistent Session + * storage for this Manager. + * + * @param store the associated Store + */ + public void setStore(Store store) { + this.store = store; + store.setManager(this); + + } + + + /** + * Return the Store object which manages persistent Session + * storage for this Manager. + */ + public Store getStore() { + + return (this.store); + + } + + + + /** + * Indicates whether sessions are saved when the Manager is shut down + * properly. This requires the unload() method to be called. + */ + public boolean getSaveOnRestart() { + + return saveOnRestart; + + } + + + /** + * Set the option to save sessions to the Store when the Manager is + * shut down, then loaded when the Manager starts again. If set to + * false, any sessions found in the Store may still be picked up when + * the Manager is started again. + * + * @param saveOnRestart true if sessions should be saved on restart, false if + * they should be ignored. + */ + public void setSaveOnRestart(boolean saveOnRestart) { + + if (saveOnRestart == this.saveOnRestart) + return; + + boolean oldSaveOnRestart = this.saveOnRestart; + this.saveOnRestart = saveOnRestart; + support.firePropertyChange("saveOnRestart", + new Boolean(oldSaveOnRestart), + new Boolean(this.saveOnRestart)); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Clear all sessions from the Store. + */ + public void clearStore() { + + if (store == null) + return; + + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged(new PrivilegedStoreClear()); + }catch(PrivilegedActionException ex){ + Exception exception = ex.getException(); + log.error("Exception clearing the Store: " + exception); + exception.printStackTrace(); + } + } else { + store.clear(); + } + } catch (IOException e) { + log.error("Exception clearing the Store: " + e); + e.printStackTrace(); + } + + } + + + /** + * Implements the Manager interface, direct call to processExpires and processPersistenceChecks + */ + public void processExpires() { + + long timeNow = System.currentTimeMillis(); + Session sessions[] = findSessions(); + int expireHere = 0 ; + if(log.isDebugEnabled()) + log.debug("Start expire sessions " + getName() + " at " + timeNow + " sessioncount " + sessions.length); + for (int i = 0; i < sessions.length; i++) { + if (!sessions[i].isValid()) { + expiredSessions++; + expireHere++; + } + } + processPersistenceChecks(); + if ((getStore() != null) && (getStore() instanceof StoreBase)) { + ((StoreBase) getStore()).processExpires(); + } + + long timeEnd = System.currentTimeMillis(); + if(log.isDebugEnabled()) + log.debug("End expire sessions " + getName() + " processingTime " + (timeEnd - timeNow) + " expired sessions: " + expireHere); + processingTime += (timeEnd - timeNow); + + } + + + /** + * Called by the background thread after active sessions have been checked + * for expiration, to allow sessions to be swapped out, backed up, etc. + */ + public void processPersistenceChecks() { + + processMaxIdleSwaps(); + processMaxActiveSwaps(); + processMaxIdleBackups(); + + } + + + /** + * Return the active Session, associated with this Manager, with the + * specified session id (if any); otherwise return null. + * This method checks the persistence store if persistence is enabled, + * otherwise just uses the functionality from ManagerBase. + * + * @param id The session id for the session to be returned + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + * @exception IOException if an input/output error occurs while + * processing this request + */ + public Session findSession(String id) throws IOException { + + Session session = super.findSession(id); + if (session != null) + return (session); + + // See if the Session is in the Store + session = swapIn(id); + return (session); + + } + + /** + * Remove this Session from the active Sessions for this Manager, + * but not from the Store. (Used by the PersistentValve) + * + * @param session Session to be removed + */ + public void removeSuper(Session session) { + super.remove (session); + } + + /** + * Load all sessions found in the persistence mechanism, assuming + * they are marked as valid and have not passed their expiration + * limit. If persistence is not supported, this method returns + * without doing anything. + *

    + * Note that by default, this method is not called by the MiddleManager + * class. In order to use it, a subclass must specifically call it, + * for example in the start() and/or processPersistenceChecks() methods. + */ + public void load() { + + // Initialize our internal data structures + sessions.clear(); + + if (store == null) + return; + + String[] ids = null; + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + ids = (String[]) + AccessController.doPrivileged(new PrivilegedStoreKeys()); + }catch(PrivilegedActionException ex){ + Exception exception = ex.getException(); + log.error("Exception in the Store during load: " + + exception); + exception.printStackTrace(); + } + } else { + ids = store.keys(); + } + } catch (IOException e) { + log.error("Can't load sessions from store, " + e.getMessage(), e); + return; + } + + int n = ids.length; + if (n == 0) + return; + + if (log.isDebugEnabled()) + log.debug(sm.getString("persistentManager.loading", String.valueOf(n))); + + for (int i = 0; i < n; i++) + try { + swapIn(ids[i]); + } catch (IOException e) { + log.error("Failed load session from store, " + e.getMessage(), e); + } + + } + + + /** + * Remove this Session from the active Sessions for this Manager, + * and from the Store. + * + * @param session Session to be removed + */ + public void remove(Session session) { + + super.remove (session); + + if (store != null){ + removeSession(session.getIdInternal()); + } + } + + + /** + * Remove this Session from the active Sessions for this Manager, + * and from the Store. + * + * @param id Session's id to be removed + */ + protected void removeSession(String id){ + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged(new PrivilegedStoreRemove(id)); + }catch(PrivilegedActionException ex){ + Exception exception = ex.getException(); + log.error("Exception in the Store during removeSession: " + + exception); + exception.printStackTrace(); + } + } else { + store.remove(id); + } + } catch (IOException e) { + log.error("Exception removing session " + e.getMessage()); + e.printStackTrace(); + } + } + + /** + * Save all currently active sessions in the appropriate persistence + * mechanism, if any. If persistence is not supported, this method + * returns without doing anything. + *

    + * Note that by default, this method is not called by the MiddleManager + * class. In order to use it, a subclass must specifically call it, + * for example in the stop() and/or processPersistenceChecks() methods. + */ + public void unload() { + + if (store == null) + return; + + Session sessions[] = findSessions(); + int n = sessions.length; + if (n == 0) + return; + + if (log.isDebugEnabled()) + log.debug(sm.getString("persistentManager.unloading", + String.valueOf(n))); + + for (int i = 0; i < n; i++) + try { + swapOut(sessions[i]); + } catch (IOException e) { + ; // This is logged in writeSession() + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Look for a session in the Store and, if found, restore + * it in the Manager's list of active sessions if appropriate. + * The session will be removed from the Store after swapping + * in, but will not be added to the active session list if it + * is invalid or past its expiration. + */ + protected Session swapIn(String id) throws IOException { + + if (store == null) + return null; + + Session session = null; + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + session = (Session) + AccessController.doPrivileged(new PrivilegedStoreLoad(id)); + }catch(PrivilegedActionException ex){ + Exception exception = ex.getException(); + log.error("Exception in the Store during swapIn: " + + exception); + if (exception instanceof IOException){ + throw (IOException)exception; + } else if (exception instanceof ClassNotFoundException) { + throw (ClassNotFoundException)exception; + } + } + } else { + session = store.load(id); + } + } catch (ClassNotFoundException e) { + log.error(sm.getString("persistentManager.deserializeError", id, e)); + throw new IllegalStateException + (sm.getString("persistentManager.deserializeError", id, e)); + } + + if (session == null) + return (null); + + if (!session.isValid()) { + log.error("session swapped in is invalid or expired"); + session.expire(); + removeSession(id); + return (null); + } + + if(log.isDebugEnabled()) + log.debug(sm.getString("persistentManager.swapIn", id)); + + session.setManager(this); + // make sure the listeners know about it. + ((StandardSession)session).tellNew(); + add(session); + ((StandardSession)session).activate(); + session.endAccess(); + + return (session); + + } + + + /** + * Remove the session from the Manager's list of active + * sessions and write it out to the Store. If the session + * is past its expiration or invalid, this method does + * nothing. + * + * @param session The Session to write out. + */ + protected void swapOut(Session session) throws IOException { + + if (store == null || !session.isValid()) { + return; + } + + ((StandardSession)session).passivate(); + writeSession(session); + super.remove(session); + session.recycle(); + + } + + + /** + * Write the provided session to the Store without modifying + * the copy in memory or triggering passivation events. Does + * nothing if the session is invalid or past its expiration. + */ + protected void writeSession(Session session) throws IOException { + + if (store == null || !session.isValid()) { + return; + } + + try { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged(new PrivilegedStoreSave(session)); + }catch(PrivilegedActionException ex){ + Exception exception = ex.getException(); + log.error("Exception in the Store during writeSession: " + + exception); + exception.printStackTrace(); + } + } else { + store.save(session); + } + } catch (IOException e) { + log.error(sm.getString + ("persistentManager.serializeError", session.getIdInternal(), e)); + throw e; + } + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) { + log.info(sm.getString("standardManager.alreadyStarted")); + return; + } + if( ! initialized ) + init(); + + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Force initialization of the random number generator + if (log.isDebugEnabled()) + log.debug("Force random number initialization starting"); + String dummy = generateSessionId(); + if (log.isDebugEnabled()) + log.debug("Force random number initialization completed"); + + if (store == null) + log.error("No Store configured, persistence disabled"); + else if (store instanceof Lifecycle) + ((Lifecycle)store).start(); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + if (log.isDebugEnabled()) + log.debug("Stopping"); + + // Validate and update our current component state + if (!isStarted()) { + log.info(sm.getString("standardManager.notStarted")); + return; + } + + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + setStarted(false); + + if (getStore() != null && saveOnRestart) { + unload(); + } else { + // Expire all active sessions + Session sessions[] = findSessions(); + for (int i = 0; i < sessions.length; i++) { + StandardSession session = (StandardSession) sessions[i]; + if (!session.isValid()) + continue; + session.expire(); + } + } + + if (getStore() != null && getStore() instanceof Lifecycle) + ((Lifecycle)getStore()).stop(); + + // Require a new random number generator if we are restarted + this.random = null; + + if( initialized ) + destroy(); + + } + + + // ----------------------------------------- PropertyChangeListener Methods + + + /** + * Process property change events from our associated Context. + * + * @param event The property change event that has occurred + */ + public void propertyChange(PropertyChangeEvent event) { + + // Validate the source of this event + if (!(event.getSource() instanceof Context)) + return; + Context context = (Context) event.getSource(); + + // Process a relevant property change + if (event.getPropertyName().equals("sessionTimeout")) { + try { + setMaxInactiveInterval + ( ((Integer) event.getNewValue()).intValue()*60 ); + } catch (NumberFormatException e) { + log.error(sm.getString("standardManager.sessionTimeout", + event.getNewValue().toString())); + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Swap idle sessions out to Store if they are idle too long. + */ + protected void processMaxIdleSwaps() { + + if (!isStarted() || maxIdleSwap < 0) + return; + + Session sessions[] = findSessions(); + long timeNow = System.currentTimeMillis(); + + // Swap out all sessions idle longer than maxIdleSwap + // FIXME: What's preventing us from mangling a session during + // a request? + if (maxIdleSwap >= 0) { + for (int i = 0; i < sessions.length; i++) { + StandardSession session = (StandardSession) sessions[i]; + if (!session.isValid()) + continue; + int timeIdle = // Truncate, do not round up + (int) ((timeNow - session.getLastAccessedTime()) / 1000L); + if (timeIdle > maxIdleSwap && timeIdle > minIdleSwap) { + if (log.isDebugEnabled()) + log.debug(sm.getString + ("persistentManager.swapMaxIdle", + session.getIdInternal(), new Integer(timeIdle))); + try { + swapOut(session); + } catch (IOException e) { + ; // This is logged in writeSession() + } + } + } + } + + } + + + /** + * Swap idle sessions out to Store if too many are active + */ + protected void processMaxActiveSwaps() { + + if (!isStarted() || getMaxActiveSessions() < 0) + return; + + Session sessions[] = findSessions(); + + // FIXME: Smarter algorithm (LRU) + if (getMaxActiveSessions() >= sessions.length) + return; + + if(log.isDebugEnabled()) + log.debug(sm.getString + ("persistentManager.tooManyActive", + new Integer(sessions.length))); + + int toswap = sessions.length - getMaxActiveSessions(); + long timeNow = System.currentTimeMillis(); + + for (int i = 0; i < sessions.length && toswap > 0; i++) { + int timeIdle = // Truncate, do not round up + (int) ((timeNow - sessions[i].getLastAccessedTime()) / 1000L); + if (timeIdle > minIdleSwap) { + if(log.isDebugEnabled()) + log.debug(sm.getString + ("persistentManager.swapTooManyActive", + sessions[i].getIdInternal(), new Integer(timeIdle))); + try { + swapOut(sessions[i]); + } catch (IOException e) { + ; // This is logged in writeSession() + } + toswap--; + } + } + + } + + + /** + * Back up idle sessions. + */ + protected void processMaxIdleBackups() { + + if (!isStarted() || maxIdleBackup < 0) + return; + + Session sessions[] = findSessions(); + long timeNow = System.currentTimeMillis(); + + // Back up all sessions idle longer than maxIdleBackup + if (maxIdleBackup >= 0) { + for (int i = 0; i < sessions.length; i++) { + StandardSession session = (StandardSession) sessions[i]; + if (!session.isValid()) + continue; + int timeIdle = // Truncate, do not round up + (int) ((timeNow - session.getLastAccessedTime()) / 1000L); + if (timeIdle > maxIdleBackup) { + if (log.isDebugEnabled()) + log.debug(sm.getString + ("persistentManager.backupMaxIdle", + session.getIdInternal(), new Integer(timeIdle))); + + try { + writeSession(session); + } catch (IOException e) { + ; // This is logged in writeSession() + } + } + } + } + + } + +} diff --git a/java/org/apache/catalina/session/StandardManager.java b/java/org/apache/catalina/session/StandardManager.java index fb3725307..7af7884e4 100644 --- a/java/org/apache/catalina/session/StandardManager.java +++ b/java/org/apache/catalina/session/StandardManager.java @@ -1,753 +1,753 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.ArrayList; -import java.util.Iterator; -import javax.servlet.ServletContext; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.Session; -import org.apache.catalina.util.CustomObjectInputStream; -import org.apache.catalina.util.LifecycleSupport; - -import org.apache.catalina.security.SecurityUtil; -/** - * Standard implementation of the Manager interface that provides - * simple session persistence across restarts of this component (such as - * when the entire server is shut down and restarted, or when a particular - * web application is reloaded. - *

    - * IMPLEMENTATION NOTE: Correct behavior of session storing and - * reloading depends upon external calls to the start() and - * stop() methods of this class at the correct times. - * - * @author Craig R. McClanahan - * @author Jean-Francois Arcand - * @version $Revision: 387590 $ $Date: 2006-03-21 18:55:07 +0100 (mar., 21 mars 2006) $ - */ - -public class StandardManager - extends ManagerBase - implements Lifecycle, PropertyChangeListener { - - // ---------------------------------------------------- Security Classes - private class PrivilegedDoLoad - implements PrivilegedExceptionAction { - - PrivilegedDoLoad() { - } - - public Object run() throws Exception{ - doLoad(); - return null; - } - } - - private class PrivilegedDoUnload - implements PrivilegedExceptionAction { - - PrivilegedDoUnload() { - } - - public Object run() throws Exception{ - doUnload(); - return null; - } - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = "StandardManager/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The maximum number of active Sessions allowed, or -1 for no limit. - */ - protected int maxActiveSessions = -1; - - - /** - * The descriptive name of this Manager implementation (for logging). - */ - protected static String name = "StandardManager"; - - - /** - * Path name of the disk file in which active sessions are saved - * when we stop, and from which these sessions are loaded when we start. - * A null value indicates that no persistence is desired. - * If this pathname is relative, it will be resolved against the - * temporary working directory provided by our context, available via - * the javax.servlet.context.tempdir context attribute. - */ - protected String pathname = "SESSIONS.ser"; - - - /** - * Has this component been started yet? - */ - protected boolean started = false; - - - /** - * Number of session creations that failed due to maxActiveSessions. - */ - protected int rejectedSessions = 0; - - - /** - * Processing time during session expiration. - */ - protected long processingTime = 0; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the Container with which this Manager has been associated. If - * it is a Context (the usual case), listen for changes to the session - * timeout property. - * - * @param container The associated Container - */ - public void setContainer(Container container) { - - // De-register from the old Container (if any) - if ((this.container != null) && (this.container instanceof Context)) - ((Context) this.container).removePropertyChangeListener(this); - - // Default processing provided by our superclass - super.setContainer(container); - - // Register with the new Container (if any) - if ((this.container != null) && (this.container instanceof Context)) { - setMaxInactiveInterval - ( ((Context) this.container).getSessionTimeout()*60 ); - ((Context) this.container).addPropertyChangeListener(this); - } - - } - - - /** - * Return descriptive information about this Manager implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the maximum number of active Sessions allowed, or -1 for - * no limit. - */ - public int getMaxActiveSessions() { - - return (this.maxActiveSessions); - - } - - - /** Number of session creations that failed due to maxActiveSessions - * - * @return The count - */ - public int getRejectedSessions() { - return rejectedSessions; - } - - - public void setRejectedSessions(int rejectedSessions) { - this.rejectedSessions = rejectedSessions; - } - - - /** - * Set the maximum number of actives Sessions allowed, or -1 for - * no limit. - * - * @param max The new maximum number of sessions - */ - public void setMaxActiveSessions(int max) { - - int oldMaxActiveSessions = this.maxActiveSessions; - this.maxActiveSessions = max; - support.firePropertyChange("maxActiveSessions", - new Integer(oldMaxActiveSessions), - new Integer(this.maxActiveSessions)); - - } - - - /** - * Return the descriptive short name of this Manager implementation. - */ - public String getName() { - - return (name); - - } - - - /** - * Return the session persistence pathname, if any. - */ - public String getPathname() { - - return (this.pathname); - - } - - - /** - * Set the session persistence pathname to the specified value. If no - * persistence support is desired, set the pathname to null. - * - * @param pathname New session persistence pathname - */ - public void setPathname(String pathname) { - - String oldPathname = this.pathname; - this.pathname = pathname; - support.firePropertyChange("pathname", oldPathname, this.pathname); - - } - - - // --------------------------------------------------------- Public Methods - - /** - * Construct and return a new session object, based on the default - * settings specified by this Manager's properties. The session - * id will be assigned by this method, and available via the getId() - * method of the returned session. If a new session cannot be created - * for any reason, return null. - * - * @exception IllegalStateException if a new session cannot be - * instantiated for any reason - */ - public Session createSession(String sessionId) { - - if ((maxActiveSessions >= 0) && - (sessions.size() >= maxActiveSessions)) { - rejectedSessions++; - throw new IllegalStateException - (sm.getString("standardManager.createSession.ise")); - } - - return (super.createSession(sessionId)); - - } - - - /** - * Load any currently active sessions that were previously unloaded - * to the appropriate persistence mechanism, if any. If persistence is not - * supported, this method returns without doing anything. - * - * @exception ClassNotFoundException if a serialized class cannot be - * found during the reload - * @exception IOException if an input/output error occurs - */ - public void load() throws ClassNotFoundException, IOException { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged( new PrivilegedDoLoad() ); - } catch (PrivilegedActionException ex){ - Exception exception = ex.getException(); - if (exception instanceof ClassNotFoundException){ - throw (ClassNotFoundException)exception; - } else if (exception instanceof IOException){ - throw (IOException)exception; - } - if (log.isDebugEnabled()) - log.debug("Unreported exception in load() " - + exception); - } - } else { - doLoad(); - } - } - - - /** - * Load any currently active sessions that were previously unloaded - * to the appropriate persistence mechanism, if any. If persistence is not - * supported, this method returns without doing anything. - * - * @exception ClassNotFoundException if a serialized class cannot be - * found during the reload - * @exception IOException if an input/output error occurs - */ - protected void doLoad() throws ClassNotFoundException, IOException { - if (log.isDebugEnabled()) - log.debug("Start: Loading persisted sessions"); - - // Initialize our internal data structures - sessions.clear(); - - // Open an input stream to the specified pathname, if any - File file = file(); - if (file == null) - return; - if (log.isDebugEnabled()) - log.debug(sm.getString("standardManager.loading", pathname)); - FileInputStream fis = null; - ObjectInputStream ois = null; - Loader loader = null; - ClassLoader classLoader = null; - try { - fis = new FileInputStream(file.getAbsolutePath()); - BufferedInputStream bis = new BufferedInputStream(fis); - if (container != null) - loader = container.getLoader(); - if (loader != null) - classLoader = loader.getClassLoader(); - if (classLoader != null) { - if (log.isDebugEnabled()) - log.debug("Creating custom object input stream for class loader "); - ois = new CustomObjectInputStream(bis, classLoader); - } else { - if (log.isDebugEnabled()) - log.debug("Creating standard object input stream"); - ois = new ObjectInputStream(bis); - } - } catch (FileNotFoundException e) { - if (log.isDebugEnabled()) - log.debug("No persisted data file found"); - return; - } catch (IOException e) { - log.error(sm.getString("standardManager.loading.ioe", e), e); - if (ois != null) { - try { - ois.close(); - } catch (IOException f) { - ; - } - ois = null; - } - throw e; - } - - // Load the previously unloaded active sessions - synchronized (sessions) { - try { - Integer count = (Integer) ois.readObject(); - int n = count.intValue(); - if (log.isDebugEnabled()) - log.debug("Loading " + n + " persisted sessions"); - for (int i = 0; i < n; i++) { - StandardSession session = getNewSession(); - session.readObjectData(ois); - session.setManager(this); - sessions.put(session.getIdInternal(), session); - session.activate(); - session.endAccess(); - } - } catch (ClassNotFoundException e) { - log.error(sm.getString("standardManager.loading.cnfe", e), e); - if (ois != null) { - try { - ois.close(); - } catch (IOException f) { - ; - } - ois = null; - } - throw e; - } catch (IOException e) { - log.error(sm.getString("standardManager.loading.ioe", e), e); - if (ois != null) { - try { - ois.close(); - } catch (IOException f) { - ; - } - ois = null; - } - throw e; - } finally { - // Close the input stream - try { - if (ois != null) - ois.close(); - } catch (IOException f) { - // ignored - } - - // Delete the persistent storage file - if (file != null && file.exists() ) - file.delete(); - } - } - - if (log.isDebugEnabled()) - log.debug("Finish: Loading persisted sessions"); - } - - - /** - * Save any currently active sessions in the appropriate persistence - * mechanism, if any. If persistence is not supported, this method - * returns without doing anything. - * - * @exception IOException if an input/output error occurs - */ - public void unload() throws IOException { - if (SecurityUtil.isPackageProtectionEnabled()){ - try{ - AccessController.doPrivileged( new PrivilegedDoUnload() ); - } catch (PrivilegedActionException ex){ - Exception exception = ex.getException(); - if (exception instanceof IOException){ - throw (IOException)exception; - } - if (log.isDebugEnabled()) - log.debug("Unreported exception in unLoad() " - + exception); - } - } else { - doUnload(); - } - } - - - /** - * Save any currently active sessions in the appropriate persistence - * mechanism, if any. If persistence is not supported, this method - * returns without doing anything. - * - * @exception IOException if an input/output error occurs - */ - protected void doUnload() throws IOException { - - if (log.isDebugEnabled()) - log.debug("Unloading persisted sessions"); - - // Open an output stream to the specified pathname, if any - File file = file(); - if (file == null) - return; - if (log.isDebugEnabled()) - log.debug(sm.getString("standardManager.unloading", pathname)); - FileOutputStream fos = null; - ObjectOutputStream oos = null; - try { - fos = new FileOutputStream(file.getAbsolutePath()); - oos = new ObjectOutputStream(new BufferedOutputStream(fos)); - } catch (IOException e) { - log.error(sm.getString("standardManager.unloading.ioe", e), e); - if (oos != null) { - try { - oos.close(); - } catch (IOException f) { - ; - } - oos = null; - } - throw e; - } - - // Write the number of active sessions, followed by the details - ArrayList list = new ArrayList(); - synchronized (sessions) { - if (log.isDebugEnabled()) - log.debug("Unloading " + sessions.size() + " sessions"); - try { - oos.writeObject(new Integer(sessions.size())); - Iterator elements = sessions.values().iterator(); - while (elements.hasNext()) { - StandardSession session = - (StandardSession) elements.next(); - list.add(session); - ((StandardSession) session).passivate(); - session.writeObjectData(oos); - } - } catch (IOException e) { - log.error(sm.getString("standardManager.unloading.ioe", e), e); - if (oos != null) { - try { - oos.close(); - } catch (IOException f) { - ; - } - oos = null; - } - throw e; - } - } - - // Flush and close the output stream - try { - oos.flush(); - oos.close(); - oos = null; - } catch (IOException e) { - if (oos != null) { - try { - oos.close(); - } catch (IOException f) { - ; - } - oos = null; - } - throw e; - } - - // Expire all the sessions we just wrote - if (log.isDebugEnabled()) - log.debug("Expiring " + list.size() + " persisted sessions"); - Iterator expires = list.iterator(); - while (expires.hasNext()) { - StandardSession session = (StandardSession) expires.next(); - try { - session.expire(false); - } catch (Throwable t) { - ; - } finally { - session.recycle(); - } - } - - if (log.isDebugEnabled()) - log.debug("Unloading complete"); - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - if( ! initialized ) - init(); - - // Validate and update our current component state - if (started) { - return; - } - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Force initialization of the random number generator - if (log.isDebugEnabled()) - log.debug("Force random number initialization starting"); - String dummy = generateSessionId(); - if (log.isDebugEnabled()) - log.debug("Force random number initialization completed"); - - // Load unloaded sessions, if any - try { - load(); - } catch (Throwable t) { - log.error(sm.getString("standardManager.managerLoad"), t); - } - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - if (log.isDebugEnabled()) - log.debug("Stopping"); - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("standardManager.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Write out sessions - try { - unload(); - } catch (Throwable t) { - log.error(sm.getString("standardManager.managerUnload"), t); - } - - // Expire all active sessions - Session sessions[] = findSessions(); - for (int i = 0; i < sessions.length; i++) { - Session session = sessions[i]; - try { - if (session.isValid()) { - session.expire(); - } - } catch (Throwable t) { - ; - } finally { - // Measure against memory leaking if references to the session - // object are kept in a shared field somewhere - session.recycle(); - } - } - - // Require a new random number generator if we are restarted - this.random = null; - - if( initialized ) { - destroy(); - } - } - - - // ----------------------------------------- PropertyChangeListener Methods - - - /** - * Process property change events from our associated Context. - * - * @param event The property change event that has occurred - */ - public void propertyChange(PropertyChangeEvent event) { - - // Validate the source of this event - if (!(event.getSource() instanceof Context)) - return; - Context context = (Context) event.getSource(); - - // Process a relevant property change - if (event.getPropertyName().equals("sessionTimeout")) { - try { - setMaxInactiveInterval - ( ((Integer) event.getNewValue()).intValue()*60 ); - } catch (NumberFormatException e) { - log.error(sm.getString("standardManager.sessionTimeout", - event.getNewValue().toString())); - } - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a File object representing the pathname to our - * persistence file, if any. - */ - protected File file() { - - if ((pathname == null) || (pathname.length() == 0)) - return (null); - File file = new File(pathname); - if (!file.isAbsolute()) { - if (container instanceof Context) { - ServletContext servletContext = - ((Context) container).getServletContext(); - File tempdir = (File) - servletContext.getAttribute(Globals.WORK_DIR_ATTR); - if (tempdir != null) - file = new File(tempdir, pathname); - } - } -// if (!file.isAbsolute()) -// return (null); - return (file); - - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Iterator; +import javax.servlet.ServletContext; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.Session; +import org.apache.catalina.util.CustomObjectInputStream; +import org.apache.catalina.util.LifecycleSupport; + +import org.apache.catalina.security.SecurityUtil; +/** + * Standard implementation of the Manager interface that provides + * simple session persistence across restarts of this component (such as + * when the entire server is shut down and restarted, or when a particular + * web application is reloaded. + *

    + * IMPLEMENTATION NOTE: Correct behavior of session storing and + * reloading depends upon external calls to the start() and + * stop() methods of this class at the correct times. + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand + * @version $Revision: 387590 $ $Date: 2006-03-21 18:55:07 +0100 (mar., 21 mars 2006) $ + */ + +public class StandardManager + extends ManagerBase + implements Lifecycle, PropertyChangeListener { + + // ---------------------------------------------------- Security Classes + private class PrivilegedDoLoad + implements PrivilegedExceptionAction { + + PrivilegedDoLoad() { + } + + public Object run() throws Exception{ + doLoad(); + return null; + } + } + + private class PrivilegedDoUnload + implements PrivilegedExceptionAction { + + PrivilegedDoUnload() { + } + + public Object run() throws Exception{ + doUnload(); + return null; + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information about this implementation. + */ + protected static final String info = "StandardManager/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The maximum number of active Sessions allowed, or -1 for no limit. + */ + protected int maxActiveSessions = -1; + + + /** + * The descriptive name of this Manager implementation (for logging). + */ + protected static String name = "StandardManager"; + + + /** + * Path name of the disk file in which active sessions are saved + * when we stop, and from which these sessions are loaded when we start. + * A null value indicates that no persistence is desired. + * If this pathname is relative, it will be resolved against the + * temporary working directory provided by our context, available via + * the javax.servlet.context.tempdir context attribute. + */ + protected String pathname = "SESSIONS.ser"; + + + /** + * Has this component been started yet? + */ + protected boolean started = false; + + + /** + * Number of session creations that failed due to maxActiveSessions. + */ + protected int rejectedSessions = 0; + + + /** + * Processing time during session expiration. + */ + protected long processingTime = 0; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the Container with which this Manager has been associated. If + * it is a Context (the usual case), listen for changes to the session + * timeout property. + * + * @param container The associated Container + */ + public void setContainer(Container container) { + + // De-register from the old Container (if any) + if ((this.container != null) && (this.container instanceof Context)) + ((Context) this.container).removePropertyChangeListener(this); + + // Default processing provided by our superclass + super.setContainer(container); + + // Register with the new Container (if any) + if ((this.container != null) && (this.container instanceof Context)) { + setMaxInactiveInterval + ( ((Context) this.container).getSessionTimeout()*60 ); + ((Context) this.container).addPropertyChangeListener(this); + } + + } + + + /** + * Return descriptive information about this Manager implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the maximum number of active Sessions allowed, or -1 for + * no limit. + */ + public int getMaxActiveSessions() { + + return (this.maxActiveSessions); + + } + + + /** Number of session creations that failed due to maxActiveSessions + * + * @return The count + */ + public int getRejectedSessions() { + return rejectedSessions; + } + + + public void setRejectedSessions(int rejectedSessions) { + this.rejectedSessions = rejectedSessions; + } + + + /** + * Set the maximum number of actives Sessions allowed, or -1 for + * no limit. + * + * @param max The new maximum number of sessions + */ + public void setMaxActiveSessions(int max) { + + int oldMaxActiveSessions = this.maxActiveSessions; + this.maxActiveSessions = max; + support.firePropertyChange("maxActiveSessions", + new Integer(oldMaxActiveSessions), + new Integer(this.maxActiveSessions)); + + } + + + /** + * Return the descriptive short name of this Manager implementation. + */ + public String getName() { + + return (name); + + } + + + /** + * Return the session persistence pathname, if any. + */ + public String getPathname() { + + return (this.pathname); + + } + + + /** + * Set the session persistence pathname to the specified value. If no + * persistence support is desired, set the pathname to null. + * + * @param pathname New session persistence pathname + */ + public void setPathname(String pathname) { + + String oldPathname = this.pathname; + this.pathname = pathname; + support.firePropertyChange("pathname", oldPathname, this.pathname); + + } + + + // --------------------------------------------------------- Public Methods + + /** + * Construct and return a new session object, based on the default + * settings specified by this Manager's properties. The session + * id will be assigned by this method, and available via the getId() + * method of the returned session. If a new session cannot be created + * for any reason, return null. + * + * @exception IllegalStateException if a new session cannot be + * instantiated for any reason + */ + public Session createSession(String sessionId) { + + if ((maxActiveSessions >= 0) && + (sessions.size() >= maxActiveSessions)) { + rejectedSessions++; + throw new IllegalStateException + (sm.getString("standardManager.createSession.ise")); + } + + return (super.createSession(sessionId)); + + } + + + /** + * Load any currently active sessions that were previously unloaded + * to the appropriate persistence mechanism, if any. If persistence is not + * supported, this method returns without doing anything. + * + * @exception ClassNotFoundException if a serialized class cannot be + * found during the reload + * @exception IOException if an input/output error occurs + */ + public void load() throws ClassNotFoundException, IOException { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged( new PrivilegedDoLoad() ); + } catch (PrivilegedActionException ex){ + Exception exception = ex.getException(); + if (exception instanceof ClassNotFoundException){ + throw (ClassNotFoundException)exception; + } else if (exception instanceof IOException){ + throw (IOException)exception; + } + if (log.isDebugEnabled()) + log.debug("Unreported exception in load() " + + exception); + } + } else { + doLoad(); + } + } + + + /** + * Load any currently active sessions that were previously unloaded + * to the appropriate persistence mechanism, if any. If persistence is not + * supported, this method returns without doing anything. + * + * @exception ClassNotFoundException if a serialized class cannot be + * found during the reload + * @exception IOException if an input/output error occurs + */ + protected void doLoad() throws ClassNotFoundException, IOException { + if (log.isDebugEnabled()) + log.debug("Start: Loading persisted sessions"); + + // Initialize our internal data structures + sessions.clear(); + + // Open an input stream to the specified pathname, if any + File file = file(); + if (file == null) + return; + if (log.isDebugEnabled()) + log.debug(sm.getString("standardManager.loading", pathname)); + FileInputStream fis = null; + ObjectInputStream ois = null; + Loader loader = null; + ClassLoader classLoader = null; + try { + fis = new FileInputStream(file.getAbsolutePath()); + BufferedInputStream bis = new BufferedInputStream(fis); + if (container != null) + loader = container.getLoader(); + if (loader != null) + classLoader = loader.getClassLoader(); + if (classLoader != null) { + if (log.isDebugEnabled()) + log.debug("Creating custom object input stream for class loader "); + ois = new CustomObjectInputStream(bis, classLoader); + } else { + if (log.isDebugEnabled()) + log.debug("Creating standard object input stream"); + ois = new ObjectInputStream(bis); + } + } catch (FileNotFoundException e) { + if (log.isDebugEnabled()) + log.debug("No persisted data file found"); + return; + } catch (IOException e) { + log.error(sm.getString("standardManager.loading.ioe", e), e); + if (ois != null) { + try { + ois.close(); + } catch (IOException f) { + ; + } + ois = null; + } + throw e; + } + + // Load the previously unloaded active sessions + synchronized (sessions) { + try { + Integer count = (Integer) ois.readObject(); + int n = count.intValue(); + if (log.isDebugEnabled()) + log.debug("Loading " + n + " persisted sessions"); + for (int i = 0; i < n; i++) { + StandardSession session = getNewSession(); + session.readObjectData(ois); + session.setManager(this); + sessions.put(session.getIdInternal(), session); + session.activate(); + session.endAccess(); + } + } catch (ClassNotFoundException e) { + log.error(sm.getString("standardManager.loading.cnfe", e), e); + if (ois != null) { + try { + ois.close(); + } catch (IOException f) { + ; + } + ois = null; + } + throw e; + } catch (IOException e) { + log.error(sm.getString("standardManager.loading.ioe", e), e); + if (ois != null) { + try { + ois.close(); + } catch (IOException f) { + ; + } + ois = null; + } + throw e; + } finally { + // Close the input stream + try { + if (ois != null) + ois.close(); + } catch (IOException f) { + // ignored + } + + // Delete the persistent storage file + if (file != null && file.exists() ) + file.delete(); + } + } + + if (log.isDebugEnabled()) + log.debug("Finish: Loading persisted sessions"); + } + + + /** + * Save any currently active sessions in the appropriate persistence + * mechanism, if any. If persistence is not supported, this method + * returns without doing anything. + * + * @exception IOException if an input/output error occurs + */ + public void unload() throws IOException { + if (SecurityUtil.isPackageProtectionEnabled()){ + try{ + AccessController.doPrivileged( new PrivilegedDoUnload() ); + } catch (PrivilegedActionException ex){ + Exception exception = ex.getException(); + if (exception instanceof IOException){ + throw (IOException)exception; + } + if (log.isDebugEnabled()) + log.debug("Unreported exception in unLoad() " + + exception); + } + } else { + doUnload(); + } + } + + + /** + * Save any currently active sessions in the appropriate persistence + * mechanism, if any. If persistence is not supported, this method + * returns without doing anything. + * + * @exception IOException if an input/output error occurs + */ + protected void doUnload() throws IOException { + + if (log.isDebugEnabled()) + log.debug("Unloading persisted sessions"); + + // Open an output stream to the specified pathname, if any + File file = file(); + if (file == null) + return; + if (log.isDebugEnabled()) + log.debug(sm.getString("standardManager.unloading", pathname)); + FileOutputStream fos = null; + ObjectOutputStream oos = null; + try { + fos = new FileOutputStream(file.getAbsolutePath()); + oos = new ObjectOutputStream(new BufferedOutputStream(fos)); + } catch (IOException e) { + log.error(sm.getString("standardManager.unloading.ioe", e), e); + if (oos != null) { + try { + oos.close(); + } catch (IOException f) { + ; + } + oos = null; + } + throw e; + } + + // Write the number of active sessions, followed by the details + ArrayList list = new ArrayList(); + synchronized (sessions) { + if (log.isDebugEnabled()) + log.debug("Unloading " + sessions.size() + " sessions"); + try { + oos.writeObject(new Integer(sessions.size())); + Iterator elements = sessions.values().iterator(); + while (elements.hasNext()) { + StandardSession session = + (StandardSession) elements.next(); + list.add(session); + ((StandardSession) session).passivate(); + session.writeObjectData(oos); + } + } catch (IOException e) { + log.error(sm.getString("standardManager.unloading.ioe", e), e); + if (oos != null) { + try { + oos.close(); + } catch (IOException f) { + ; + } + oos = null; + } + throw e; + } + } + + // Flush and close the output stream + try { + oos.flush(); + oos.close(); + oos = null; + } catch (IOException e) { + if (oos != null) { + try { + oos.close(); + } catch (IOException f) { + ; + } + oos = null; + } + throw e; + } + + // Expire all the sessions we just wrote + if (log.isDebugEnabled()) + log.debug("Expiring " + list.size() + " persisted sessions"); + Iterator expires = list.iterator(); + while (expires.hasNext()) { + StandardSession session = (StandardSession) expires.next(); + try { + session.expire(false); + } catch (Throwable t) { + ; + } finally { + session.recycle(); + } + } + + if (log.isDebugEnabled()) + log.debug("Unloading complete"); + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + if( ! initialized ) + init(); + + // Validate and update our current component state + if (started) { + return; + } + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Force initialization of the random number generator + if (log.isDebugEnabled()) + log.debug("Force random number initialization starting"); + String dummy = generateSessionId(); + if (log.isDebugEnabled()) + log.debug("Force random number initialization completed"); + + // Load unloaded sessions, if any + try { + load(); + } catch (Throwable t) { + log.error(sm.getString("standardManager.managerLoad"), t); + } + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + if (log.isDebugEnabled()) + log.debug("Stopping"); + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("standardManager.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Write out sessions + try { + unload(); + } catch (Throwable t) { + log.error(sm.getString("standardManager.managerUnload"), t); + } + + // Expire all active sessions + Session sessions[] = findSessions(); + for (int i = 0; i < sessions.length; i++) { + Session session = sessions[i]; + try { + if (session.isValid()) { + session.expire(); + } + } catch (Throwable t) { + ; + } finally { + // Measure against memory leaking if references to the session + // object are kept in a shared field somewhere + session.recycle(); + } + } + + // Require a new random number generator if we are restarted + this.random = null; + + if( initialized ) { + destroy(); + } + } + + + // ----------------------------------------- PropertyChangeListener Methods + + + /** + * Process property change events from our associated Context. + * + * @param event The property change event that has occurred + */ + public void propertyChange(PropertyChangeEvent event) { + + // Validate the source of this event + if (!(event.getSource() instanceof Context)) + return; + Context context = (Context) event.getSource(); + + // Process a relevant property change + if (event.getPropertyName().equals("sessionTimeout")) { + try { + setMaxInactiveInterval + ( ((Integer) event.getNewValue()).intValue()*60 ); + } catch (NumberFormatException e) { + log.error(sm.getString("standardManager.sessionTimeout", + event.getNewValue().toString())); + } + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a File object representing the pathname to our + * persistence file, if any. + */ + protected File file() { + + if ((pathname == null) || (pathname.length() == 0)) + return (null); + File file = new File(pathname); + if (!file.isAbsolute()) { + if (container instanceof Context) { + ServletContext servletContext = + ((Context) container).getServletContext(); + File tempdir = (File) + servletContext.getAttribute(Globals.WORK_DIR_ATTR); + if (tempdir != null) + file = new File(tempdir, pathname); + } + } +// if (!file.isAbsolute()) +// return (null); + return (file); + + } +} diff --git a/java/org/apache/catalina/session/StandardSession.java b/java/org/apache/catalina/session/StandardSession.java index 66de704f7..de403ac6f 100644 --- a/java/org/apache/catalina/session/StandardSession.java +++ b/java/org/apache/catalina/session/StandardSession.java @@ -1,1713 +1,1713 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - - -import java.beans.PropertyChangeSupport; -import java.io.IOException; -import java.io.NotSerializableException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.Principal; -import java.security.PrivilegedAction; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionActivationListener; -import javax.servlet.http.HttpSessionAttributeListener; -import javax.servlet.http.HttpSessionBindingEvent; -import javax.servlet.http.HttpSessionBindingListener; -import javax.servlet.http.HttpSessionContext; -import javax.servlet.http.HttpSessionEvent; -import javax.servlet.http.HttpSessionListener; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.Manager; -import org.apache.catalina.Session; -import org.apache.catalina.SessionEvent; -import org.apache.catalina.SessionListener; -import org.apache.catalina.util.Enumerator; -import org.apache.catalina.util.StringManager; - -import org.apache.catalina.security.SecurityUtil; - -/** - * Standard implementation of the Session interface. This object is - * serializable, so that it can be stored in persistent storage or transferred - * to a different JVM for distributable session support. - *

    - * IMPLEMENTATION NOTE: An instance of this class represents both the - * internal (Session) and application level (HttpSession) view of the session. - * However, because the class itself is not declared public, Java logic outside - * of the org.apache.catalina.session package cannot cast an - * HttpSession view of this instance back to a Session view. - *

    - * IMPLEMENTATION NOTE: If you add fields to this class, you must - * make sure that you carry them over in the read/writeObject methods so - * that this class is properly serialized. - * - * @author Craig R. McClanahan - * @author Sean Legassick - * @author Jon S. Stevens - * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ - */ - -public class StandardSession - implements HttpSession, Session, Serializable { - - - protected static final boolean ACTIVITY_CHECK = - Boolean.valueOf(System.getProperty("org.apache.catalina.session.StandardSession.ACTIVITY_CHECK", "false")).booleanValue(); - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new Session associated with the specified Manager. - * - * @param manager The manager with which this Session is associated - */ - public StandardSession(Manager manager) { - - super(); - this.manager = manager; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Type array. - */ - protected static final String EMPTY_ARRAY[] = new String[0]; - - - /** - * The dummy attribute value serialized when a NotSerializableException is - * encountered in writeObject(). - */ - protected static final String NOT_SERIALIZED = - "___NOT_SERIALIZABLE_EXCEPTION___"; - - - /** - * The collection of user data attributes associated with this Session. - */ - protected Map attributes = new Hashtable(); - - - /** - * The authentication type used to authenticate our cached Principal, - * if any. NOTE: This value is not included in the serialized - * version of this object. - */ - protected transient String authType = null; - - - /** - * The java.lang.Method for the - * fireContainerEvent() method of the - * org.apache.catalina.core.StandardContext method, - * if our Context implementation is of this class. This value is - * computed dynamically the first time it is needed, or after - * a session reload (since it is declared transient). - */ - protected transient Method containerEventMethod = null; - - - /** - * The method signature for the fireContainerEvent method. - */ - protected static final Class containerEventTypes[] = - { String.class, Object.class }; - - - /** - * The time this session was created, in milliseconds since midnight, - * January 1, 1970 GMT. - */ - protected long creationTime = 0L; - - - /** - * Set of attribute names which are not allowed to be persisted. - */ - protected static final String[] excludedAttributes = { - Globals.SUBJECT_ATTR - }; - - - /** - * We are currently processing a session expiration, so bypass - * certain IllegalStateException tests. NOTE: This value is not - * included in the serialized version of this object. - */ - protected transient boolean expiring = false; - - - /** - * The facade associated with this session. NOTE: This value is not - * included in the serialized version of this object. - */ - protected transient StandardSessionFacade facade = null; - - - /** - * The session identifier of this Session. - */ - protected String id = null; - - - /** - * Descriptive information describing this Session implementation. - */ - protected static final String info = "StandardSession/1.0"; - - - /** - * The last accessed time for this Session. - */ - protected long lastAccessedTime = creationTime; - - - /** - * The session event listeners for this Session. - */ - protected transient ArrayList listeners = new ArrayList(); - - - /** - * The Manager with which this Session is associated. - */ - protected transient Manager manager = null; - - - /** - * The maximum time interval, in seconds, between client requests before - * the servlet container may invalidate this session. A negative time - * indicates that the session should never time out. - */ - protected int maxInactiveInterval = -1; - - - /** - * Flag indicating whether this session is new or not. - */ - protected boolean isNew = false; - - - /** - * Flag indicating whether this session is valid or not. - */ - protected boolean isValid = false; - - - /** - * Internal notes associated with this session by Catalina components - * and event listeners. IMPLEMENTATION NOTE: This object is - * not saved and restored across session serializations! - */ - protected transient Map notes = new Hashtable(); - - - /** - * The authenticated Principal associated with this session, if any. - * IMPLEMENTATION NOTE: This object is not saved and - * restored across session serializations! - */ - protected transient Principal principal = null; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The HTTP session context associated with this session. - */ - protected static HttpSessionContext sessionContext = null; - - - /** - * The property change support for this component. NOTE: This value - * is not included in the serialized version of this object. - */ - protected transient PropertyChangeSupport support = - new PropertyChangeSupport(this); - - - /** - * The current accessed time for this session. - */ - protected long thisAccessedTime = creationTime; - - - /** - * The access count for this session. - */ - protected transient AtomicInteger accessCount = null; - - - // ----------------------------------------------------- Session Properties - - - /** - * Return the authentication type used to authenticate our cached - * Principal, if any. - */ - public String getAuthType() { - - return (this.authType); - - } - - - /** - * Set the authentication type used to authenticate our cached - * Principal, if any. - * - * @param authType The new cached authentication type - */ - public void setAuthType(String authType) { - - String oldAuthType = this.authType; - this.authType = authType; - support.firePropertyChange("authType", oldAuthType, this.authType); - - } - - - /** - * Set the creation time for this session. This method is called by the - * Manager when an existing Session instance is reused. - * - * @param time The new creation time - */ - public void setCreationTime(long time) { - - this.creationTime = time; - this.lastAccessedTime = time; - this.thisAccessedTime = time; - - } - - - /** - * Return the session identifier for this session. - */ - public String getId() { - - return (this.id); - - } - - - /** - * Return the session identifier for this session. - */ - public String getIdInternal() { - - return (this.id); - - } - - - /** - * Set the session identifier for this session. - * - * @param id The new session identifier - */ - public void setId(String id) { - - if ((this.id != null) && (manager != null)) - manager.remove(this); - - this.id = id; - - if (manager != null) - manager.add(this); - tellNew(); - } - - - /** - * Inform the listeners about the new session. - * - */ - public void tellNew() { - - // Notify interested session event listeners - fireSessionEvent(Session.SESSION_CREATED_EVENT, null); - - // Notify interested application event listeners - Context context = (Context) manager.getContainer(); - Object listeners[] = context.getApplicationLifecycleListeners(); - if (listeners != null) { - HttpSessionEvent event = - new HttpSessionEvent(getSession()); - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof HttpSessionListener)) - continue; - HttpSessionListener listener = - (HttpSessionListener) listeners[i]; - try { - fireContainerEvent(context, - "beforeSessionCreated", - listener); - listener.sessionCreated(event); - fireContainerEvent(context, - "afterSessionCreated", - listener); - } catch (Throwable t) { - try { - fireContainerEvent(context, - "afterSessionCreated", - listener); - } catch (Exception e) { - ; - } - manager.getContainer().getLogger().error - (sm.getString("standardSession.sessionEvent"), t); - } - } - } - - } - - - /** - * Return descriptive information about this Session implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the last time the client sent a request associated with this - * session, as the number of milliseconds since midnight, January 1, 1970 - * GMT. Actions that your application takes, such as getting or setting - * a value associated with the session, do not affect the access time. - */ - public long getLastAccessedTime() { - - if (!isValidInternal()) { - throw new IllegalStateException - (sm.getString("standardSession.getLastAccessedTime.ise")); - } - - return (this.lastAccessedTime); - } - - /** - * Return the last client access time without invalidation check - * @see #getLastAccessedTime(). - */ - public long getLastAccessedTimeInternal() { - return (this.lastAccessedTime); - } - - /** - * Return the Manager within which this Session is valid. - */ - public Manager getManager() { - - return (this.manager); - - } - - - /** - * Set the Manager within which this Session is valid. - * - * @param manager The new Manager - */ - public void setManager(Manager manager) { - - this.manager = manager; - - } - - - /** - * Return the maximum time interval, in seconds, between client requests - * before the servlet container will invalidate the session. A negative - * time indicates that the session should never time out. - */ - public int getMaxInactiveInterval() { - - return (this.maxInactiveInterval); - - } - - - /** - * Set the maximum time interval, in seconds, between client requests - * before the servlet container will invalidate the session. A negative - * time indicates that the session should never time out. - * - * @param interval The new maximum interval - */ - public void setMaxInactiveInterval(int interval) { - - this.maxInactiveInterval = interval; - if (isValid && interval == 0) { - expire(); - } - - } - - - /** - * Set the isNew flag for this session. - * - * @param isNew The new value for the isNew flag - */ - public void setNew(boolean isNew) { - - this.isNew = isNew; - - } - - - /** - * Return the authenticated Principal that is associated with this Session. - * This provides an Authenticator with a means to cache a - * previously authenticated Principal, and avoid potentially expensive - * Realm.authenticate() calls on every request. If there - * is no current associated Principal, return null. - */ - public Principal getPrincipal() { - - return (this.principal); - - } - - - /** - * Set the authenticated Principal that is associated with this Session. - * This provides an Authenticator with a means to cache a - * previously authenticated Principal, and avoid potentially expensive - * Realm.authenticate() calls on every request. - * - * @param principal The new Principal, or null if none - */ - public void setPrincipal(Principal principal) { - - Principal oldPrincipal = this.principal; - this.principal = principal; - support.firePropertyChange("principal", oldPrincipal, this.principal); - - } - - - /** - * Return the HttpSession for which this object - * is the facade. - */ - public HttpSession getSession() { - - if (facade == null){ - if (SecurityUtil.isPackageProtectionEnabled()){ - final StandardSession fsession = this; - facade = (StandardSessionFacade)AccessController.doPrivileged(new PrivilegedAction(){ - public Object run(){ - return new StandardSessionFacade(fsession); - } - }); - } else { - facade = new StandardSessionFacade(this); - } - } - return (facade); - - } - - - /** - * Return the isValid flag for this session. - */ - public boolean isValid() { - - if (this.expiring) { - return true; - } - - if (!this.isValid) { - return false; - } - - if (ACTIVITY_CHECK && accessCount.get() > 0) { - return true; - } - - if (maxInactiveInterval >= 0) { - long timeNow = System.currentTimeMillis(); - int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); - if (timeIdle >= maxInactiveInterval) { - expire(true); - } - } - - return (this.isValid); - } - - - /** - * Set the isValid flag for this session. - * - * @param isValid The new value for the isValid flag - */ - public void setValid(boolean isValid) { - this.isValid = isValid; - } - - - // ------------------------------------------------- Session Public Methods - - - /** - * Update the accessed time information for this session. This method - * should be called by the context when a request comes in for a particular - * session, even if the application does not reference it. - */ - public void access() { - - this.lastAccessedTime = this.thisAccessedTime; - this.thisAccessedTime = System.currentTimeMillis(); - - if (ACTIVITY_CHECK) { - accessCount.incrementAndGet(); - } - - } - - - /** - * End the access. - */ - public void endAccess() { - - isNew = false; - - if (ACTIVITY_CHECK) { - accessCount.decrementAndGet(); - } - - } - - - /** - * Add a session event listener to this component. - */ - public void addSessionListener(SessionListener listener) { - - listeners.add(listener); - - } - - - /** - * Perform the internal processing required to invalidate this session, - * without triggering an exception if the session has already expired. - */ - public void expire() { - - expire(true); - - } - - - /** - * Perform the internal processing required to invalidate this session, - * without triggering an exception if the session has already expired. - * - * @param notify Should we notify listeners about the demise of - * this session? - */ - public void expire(boolean notify) { - - // Mark this session as "being expired" if needed - if (expiring) - return; - - synchronized (this) { - - if (manager == null) - return; - - expiring = true; - - // Notify interested application event listeners - // FIXME - Assumes we call listeners in reverse order - Context context = (Context) manager.getContainer(); - Object listeners[] = context.getApplicationLifecycleListeners(); - if (notify && (listeners != null)) { - HttpSessionEvent event = - new HttpSessionEvent(getSession()); - for (int i = 0; i < listeners.length; i++) { - int j = (listeners.length - 1) - i; - if (!(listeners[j] instanceof HttpSessionListener)) - continue; - HttpSessionListener listener = - (HttpSessionListener) listeners[j]; - try { - fireContainerEvent(context, - "beforeSessionDestroyed", - listener); - listener.sessionDestroyed(event); - fireContainerEvent(context, - "afterSessionDestroyed", - listener); - } catch (Throwable t) { - try { - fireContainerEvent(context, - "afterSessionDestroyed", - listener); - } catch (Exception e) { - ; - } - manager.getContainer().getLogger().error - (sm.getString("standardSession.sessionEvent"), t); - } - } - } - accessCount = null; - setValid(false); - - /* - * Compute how long this session has been alive, and update - * session manager's related properties accordingly - */ - long timeNow = System.currentTimeMillis(); - int timeAlive = (int) ((timeNow - creationTime)/1000); - synchronized (manager) { - if (timeAlive > manager.getSessionMaxAliveTime()) { - manager.setSessionMaxAliveTime(timeAlive); - } - int numExpired = manager.getExpiredSessions(); - numExpired++; - manager.setExpiredSessions(numExpired); - int average = manager.getSessionAverageAliveTime(); - average = ((average * (numExpired-1)) + timeAlive)/numExpired; - manager.setSessionAverageAliveTime(average); - } - - // Remove this session from our manager's active sessions - manager.remove(this); - - // Notify interested session event listeners - if (notify) { - fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null); - } - - // We have completed expire of this session - expiring = false; - - // Unbind any objects associated with this session - String keys[] = keys(); - for (int i = 0; i < keys.length; i++) - removeAttributeInternal(keys[i], notify); - - } - - } - - - /** - * Perform the internal processing required to passivate - * this session. - */ - public void passivate() { - - // Notify interested session event listeners - fireSessionEvent(Session.SESSION_PASSIVATED_EVENT, null); - - // Notify ActivationListeners - HttpSessionEvent event = null; - String keys[] = keys(); - for (int i = 0; i < keys.length; i++) { - Object attribute = attributes.get(keys[i]); - if (attribute instanceof HttpSessionActivationListener) { - if (event == null) - event = new HttpSessionEvent(getSession()); - try { - ((HttpSessionActivationListener)attribute) - .sessionWillPassivate(event); - } catch (Throwable t) { - manager.getContainer().getLogger().error - (sm.getString("standardSession.attributeEvent"), t); - } - } - } - - } - - - /** - * Perform internal processing required to activate this - * session. - */ - public void activate() { - - // Initialize access count - if (ACTIVITY_CHECK) { - accessCount = new AtomicInteger(); - } - - // Notify interested session event listeners - fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null); - - // Notify ActivationListeners - HttpSessionEvent event = null; - String keys[] = keys(); - for (int i = 0; i < keys.length; i++) { - Object attribute = attributes.get(keys[i]); - if (attribute instanceof HttpSessionActivationListener) { - if (event == null) - event = new HttpSessionEvent(getSession()); - try { - ((HttpSessionActivationListener)attribute) - .sessionDidActivate(event); - } catch (Throwable t) { - manager.getContainer().getLogger().error - (sm.getString("standardSession.attributeEvent"), t); - } - } - } - - } - - - /** - * Return the object bound with the specified name to the internal notes - * for this session, or null if no such binding exists. - * - * @param name Name of the note to be returned - */ - public Object getNote(String name) { - - return (notes.get(name)); - - } - - - /** - * Return an Iterator containing the String names of all notes bindings - * that exist for this session. - */ - public Iterator getNoteNames() { - - return (notes.keySet().iterator()); - - } - - - /** - * Release all object references, and initialize instance variables, in - * preparation for reuse of this object. - */ - public void recycle() { - - // Reset the instance variables associated with this Session - attributes.clear(); - setAuthType(null); - creationTime = 0L; - expiring = false; - id = null; - lastAccessedTime = 0L; - maxInactiveInterval = -1; - accessCount = null; - notes.clear(); - setPrincipal(null); - isNew = false; - isValid = false; - manager = null; - - } - - - /** - * Remove any object bound to the specified name in the internal notes - * for this session. - * - * @param name Name of the note to be removed - */ - public void removeNote(String name) { - - notes.remove(name); - - } - - - /** - * Remove a session event listener from this component. - */ - public void removeSessionListener(SessionListener listener) { - - listeners.remove(listener); - - } - - - /** - * Bind an object to a specified name in the internal notes associated - * with this session, replacing any existing binding for this name. - * - * @param name Name to which the object should be bound - * @param value Object to be bound to the specified name - */ - public void setNote(String name, Object value) { - - notes.put(name, value); - - } - - - /** - * Return a string representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - sb.append("StandardSession["); - sb.append(id); - sb.append("]"); - return (sb.toString()); - - } - - - // ------------------------------------------------ Session Package Methods - - - /** - * Read a serialized version of the contents of this session object from - * the specified object input stream, without requiring that the - * StandardSession itself have been serialized. - * - * @param stream The object input stream to read from - * - * @exception ClassNotFoundException if an unknown class is specified - * @exception IOException if an input/output error occurs - */ - public void readObjectData(ObjectInputStream stream) - throws ClassNotFoundException, IOException { - - readObject(stream); - - } - - - /** - * Write a serialized version of the contents of this session object to - * the specified object output stream, without requiring that the - * StandardSession itself have been serialized. - * - * @param stream The object output stream to write to - * - * @exception IOException if an input/output error occurs - */ - public void writeObjectData(ObjectOutputStream stream) - throws IOException { - - writeObject(stream); - - } - - - // ------------------------------------------------- HttpSession Properties - - - /** - * Return the time when this session was created, in milliseconds since - * midnight, January 1, 1970 GMT. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public long getCreationTime() { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.getCreationTime.ise")); - - return (this.creationTime); - - } - - - /** - * Return the ServletContext to which this session belongs. - */ - public ServletContext getServletContext() { - - if (manager == null) - return (null); - Context context = (Context) manager.getContainer(); - if (context == null) - return (null); - else - return (context.getServletContext()); - - } - - - /** - * Return the session context with which this session is associated. - * - * @deprecated As of Version 2.1, this method is deprecated and has no - * replacement. It will be removed in a future version of the - * Java Servlet API. - */ - public HttpSessionContext getSessionContext() { - - if (sessionContext == null) - sessionContext = new StandardSessionContext(); - return (sessionContext); - - } - - - // ----------------------------------------------HttpSession Public Methods - - - /** - * Return the object bound with the specified name in this session, or - * null if no object is bound with that name. - * - * @param name Name of the attribute to be returned - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public Object getAttribute(String name) { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.getAttribute.ise")); - - return (attributes.get(name)); - - } - - - /** - * Return an Enumeration of String objects - * containing the names of the objects bound to this session. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public Enumeration getAttributeNames() { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.getAttributeNames.ise")); - - return (new Enumerator(attributes.keySet(), true)); - - } - - - /** - * Return the object bound with the specified name in this session, or - * null if no object is bound with that name. - * - * @param name Name of the value to be returned - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - * @deprecated As of Version 2.2, this method is replaced by - * getAttribute() - */ - public Object getValue(String name) { - - return (getAttribute(name)); - - } - - - /** - * Return the set of names of objects bound to this session. If there - * are no such objects, a zero-length array is returned. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - * @deprecated As of Version 2.2, this method is replaced by - * getAttributeNames() - */ - public String[] getValueNames() { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.getValueNames.ise")); - - return (keys()); - - } - - - /** - * Invalidates this session and unbinds any objects bound to it. - * - * @exception IllegalStateException if this method is called on - * an invalidated session - */ - public void invalidate() { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.invalidate.ise")); - - // Cause this session to expire - expire(); - - } - - - /** - * Return true if the client does not yet know about the - * session, or if the client chooses not to join the session. For - * example, if the server used only cookie-based sessions, and the client - * has disabled the use of cookies, then a session would be new on each - * request. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public boolean isNew() { - - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.isNew.ise")); - - return (this.isNew); - - } - - - - /** - * Bind an object to this session, using the specified name. If an object - * of the same name is already bound to this session, the object is - * replaced. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueBound() on the object. - * - * @param name Name to which the object is bound, cannot be null - * @param value Object to be bound, cannot be null - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - * @deprecated As of Version 2.2, this method is replaced by - * setAttribute() - */ - public void putValue(String name, Object value) { - - setAttribute(name, value); - - } - - - /** - * Remove the object bound with the specified name from this session. If - * the session does not have an object bound with this name, this method - * does nothing. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueUnbound() on the object. - * - * @param name Name of the object to remove from this session. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public void removeAttribute(String name) { - - removeAttribute(name, true); - - } - - - /** - * Remove the object bound with the specified name from this session. If - * the session does not have an object bound with this name, this method - * does nothing. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueUnbound() on the object. - * - * @param name Name of the object to remove from this session. - * @param notify Should we notify interested listeners that this - * attribute is being removed? - * - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public void removeAttribute(String name, boolean notify) { - - // Validate our current state - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.removeAttribute.ise")); - - removeAttributeInternal(name, notify); - - } - - - /** - * Remove the object bound with the specified name from this session. If - * the session does not have an object bound with this name, this method - * does nothing. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueUnbound() on the object. - * - * @param name Name of the object to remove from this session. - * - * @exception IllegalStateException if this method is called on an - * invalidated session - * - * @deprecated As of Version 2.2, this method is replaced by - * removeAttribute() - */ - public void removeValue(String name) { - - removeAttribute(name); - - } - - - /** - * Bind an object to this session, using the specified name. If an object - * of the same name is already bound to this session, the object is - * replaced. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueBound() on the object. - * - * @param name Name to which the object is bound, cannot be null - * @param value Object to be bound, cannot be null - * - * @exception IllegalArgumentException if an attempt is made to add a - * non-serializable object in an environment marked distributable. - * @exception IllegalStateException if this method is called on an - * invalidated session - */ - public void setAttribute(String name, Object value) { - - // Name cannot be null - if (name == null) - throw new IllegalArgumentException - (sm.getString("standardSession.setAttribute.namenull")); - - // Null value is the same as removeAttribute() - if (value == null) { - removeAttribute(name); - return; - } - - // Validate our current state - if (!isValidInternal()) - throw new IllegalStateException - (sm.getString("standardSession.setAttribute.ise")); - if ((manager != null) && manager.getDistributable() && - !(value instanceof Serializable)) - throw new IllegalArgumentException - (sm.getString("standardSession.setAttribute.iae")); - - // Construct an event with the new value - HttpSessionBindingEvent event = null; - - // Call the valueBound() method if necessary - if (value instanceof HttpSessionBindingListener) { - // Don't call any notification if replacing with the same value - Object oldValue = attributes.get(name); - if (value != oldValue) { - event = new HttpSessionBindingEvent(getSession(), name, value); - try { - ((HttpSessionBindingListener) value).valueBound(event); - } catch (Throwable t){ - manager.getContainer().getLogger().error - (sm.getString("standardSession.bindingEvent"), t); - } - } - } - - // Replace or add this attribute - Object unbound = attributes.put(name, value); - - // Call the valueUnbound() method if necessary - if ((unbound != null) && (unbound != value) && - (unbound instanceof HttpSessionBindingListener)) { - try { - ((HttpSessionBindingListener) unbound).valueUnbound - (new HttpSessionBindingEvent(getSession(), name)); - } catch (Throwable t) { - manager.getContainer().getLogger().error - (sm.getString("standardSession.bindingEvent"), t); - } - } - - // Notify interested application event listeners - Context context = (Context) manager.getContainer(); - Object listeners[] = context.getApplicationEventListeners(); - if (listeners == null) - return; - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof HttpSessionAttributeListener)) - continue; - HttpSessionAttributeListener listener = - (HttpSessionAttributeListener) listeners[i]; - try { - if (unbound != null) { - fireContainerEvent(context, - "beforeSessionAttributeReplaced", - listener); - if (event == null) { - event = new HttpSessionBindingEvent - (getSession(), name, unbound); - } - listener.attributeReplaced(event); - fireContainerEvent(context, - "afterSessionAttributeReplaced", - listener); - } else { - fireContainerEvent(context, - "beforeSessionAttributeAdded", - listener); - if (event == null) { - event = new HttpSessionBindingEvent - (getSession(), name, value); - } - listener.attributeAdded(event); - fireContainerEvent(context, - "afterSessionAttributeAdded", - listener); - } - } catch (Throwable t) { - try { - if (unbound != null) { - fireContainerEvent(context, - "afterSessionAttributeReplaced", - listener); - } else { - fireContainerEvent(context, - "afterSessionAttributeAdded", - listener); - } - } catch (Exception e) { - ; - } - manager.getContainer().getLogger().error - (sm.getString("standardSession.attributeEvent"), t); - } - } - - } - - - // ------------------------------------------ HttpSession Protected Methods - - - /** - * Return the isValid flag for this session without any expiration - * check. - */ - protected boolean isValidInternal() { - return (this.isValid || this.expiring); - } - - - /** - * Read a serialized version of this session object from the specified - * object input stream. - *

    - * IMPLEMENTATION NOTE: The reference to the owning Manager - * is not restored by this method, and must be set explicitly. - * - * @param stream The input stream to read from - * - * @exception ClassNotFoundException if an unknown class is specified - * @exception IOException if an input/output error occurs - */ - protected void readObject(ObjectInputStream stream) - throws ClassNotFoundException, IOException { - - // Deserialize the scalar instance variables (except Manager) - authType = null; // Transient only - creationTime = ((Long) stream.readObject()).longValue(); - lastAccessedTime = ((Long) stream.readObject()).longValue(); - maxInactiveInterval = ((Integer) stream.readObject()).intValue(); - isNew = ((Boolean) stream.readObject()).booleanValue(); - isValid = ((Boolean) stream.readObject()).booleanValue(); - thisAccessedTime = ((Long) stream.readObject()).longValue(); - principal = null; // Transient only - // setId((String) stream.readObject()); - id = (String) stream.readObject(); - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug - ("readObject() loading session " + id); - - // Deserialize the attribute count and attribute values - if (attributes == null) - attributes = new Hashtable(); - int n = ((Integer) stream.readObject()).intValue(); - boolean isValidSave = isValid; - isValid = true; - for (int i = 0; i < n; i++) { - String name = (String) stream.readObject(); - Object value = (Object) stream.readObject(); - if ((value instanceof String) && (value.equals(NOT_SERIALIZED))) - continue; - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug(" loading attribute '" + name + - "' with value '" + value + "'"); - attributes.put(name, value); - } - isValid = isValidSave; - - if (listeners == null) { - listeners = new ArrayList(); - } - - if (notes == null) { - notes = new Hashtable(); - } - } - - - /** - * Write a serialized version of this session object to the specified - * object output stream. - *

    - * IMPLEMENTATION NOTE: The owning Manager will not be stored - * in the serialized representation of this Session. After calling - * readObject(), you must set the associated Manager - * explicitly. - *

    - * IMPLEMENTATION NOTE: Any attribute that is not Serializable - * will be unbound from the session, with appropriate actions if it - * implements HttpSessionBindingListener. If you do not want any such - * attributes, be sure the distributable property of the - * associated Manager is set to true. - * - * @param stream The output stream to write to - * - * @exception IOException if an input/output error occurs - */ - protected void writeObject(ObjectOutputStream stream) throws IOException { - - // Write the scalar instance variables (except Manager) - stream.writeObject(new Long(creationTime)); - stream.writeObject(new Long(lastAccessedTime)); - stream.writeObject(new Integer(maxInactiveInterval)); - stream.writeObject(new Boolean(isNew)); - stream.writeObject(new Boolean(isValid)); - stream.writeObject(new Long(thisAccessedTime)); - stream.writeObject(id); - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug - ("writeObject() storing session " + id); - - // Accumulate the names of serializable and non-serializable attributes - String keys[] = keys(); - ArrayList saveNames = new ArrayList(); - ArrayList saveValues = new ArrayList(); - for (int i = 0; i < keys.length; i++) { - Object value = attributes.get(keys[i]); - if (value == null) - continue; - else if ( (value instanceof Serializable) - && (!exclude(keys[i]) )) { - saveNames.add(keys[i]); - saveValues.add(value); - } else { - removeAttributeInternal(keys[i], true); - } - } - - // Serialize the attribute count and the Serializable attributes - int n = saveNames.size(); - stream.writeObject(new Integer(n)); - for (int i = 0; i < n; i++) { - stream.writeObject((String) saveNames.get(i)); - try { - stream.writeObject(saveValues.get(i)); - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug - (" storing attribute '" + saveNames.get(i) + - "' with value '" + saveValues.get(i) + "'"); - } catch (NotSerializableException e) { - manager.getContainer().getLogger().warn - (sm.getString("standardSession.notSerializable", - saveNames.get(i), id), e); - stream.writeObject(NOT_SERIALIZED); - if (manager.getContainer().getLogger().isDebugEnabled()) - manager.getContainer().getLogger().debug - (" storing attribute '" + saveNames.get(i) + - "' with value NOT_SERIALIZED"); - } - } - - } - - - /** - * Exclude attribute that cannot be serialized. - * @param name the attribute's name - */ - protected boolean exclude(String name){ - - for (int i = 0; i < excludedAttributes.length; i++) { - if (name.equalsIgnoreCase(excludedAttributes[i])) - return true; - } - - return false; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Fire container events if the Context implementation is the - * org.apache.catalina.core.StandardContext. - * - * @param context Context for which to fire events - * @param type Event type - * @param data Event data - * - * @exception Exception occurred during event firing - */ - protected void fireContainerEvent(Context context, - String type, Object data) - throws Exception { - - if (!"org.apache.catalina.core.StandardContext".equals - (context.getClass().getName())) { - return; // Container events are not supported - } - // NOTE: Race condition is harmless, so do not synchronize - if (containerEventMethod == null) { - containerEventMethod = - context.getClass().getMethod("fireContainerEvent", - containerEventTypes); - } - Object containerEventParams[] = new Object[2]; - containerEventParams[0] = type; - containerEventParams[1] = data; - containerEventMethod.invoke(context, containerEventParams); - - } - - - - /** - * Notify all session event listeners that a particular event has - * occurred for this Session. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param data Event data - */ - public void fireSessionEvent(String type, Object data) { - if (listeners.size() < 1) - return; - SessionEvent event = new SessionEvent(this, type, data); - SessionListener list[] = new SessionListener[0]; - synchronized (listeners) { - list = (SessionListener[]) listeners.toArray(list); - } - - for (int i = 0; i < list.length; i++){ - ((SessionListener) list[i]).sessionEvent(event); - } - - } - - - /** - * Return the names of all currently defined session attributes - * as an array of Strings. If there are no defined attributes, a - * zero-length array is returned. - */ - protected String[] keys() { - - return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY)); - - } - - - /** - * Remove the object bound with the specified name from this session. If - * the session does not have an object bound with this name, this method - * does nothing. - *

    - * After this method executes, and if the object implements - * HttpSessionBindingListener, the container calls - * valueUnbound() on the object. - * - * @param name Name of the object to remove from this session. - * @param notify Should we notify interested listeners that this - * attribute is being removed? - */ - protected void removeAttributeInternal(String name, boolean notify) { - - // Remove this attribute from our collection - Object value = attributes.remove(name); - - // Do we need to do valueUnbound() and attributeRemoved() notification? - if (!notify || (value == null)) { - return; - } - - // Call the valueUnbound() method if necessary - HttpSessionBindingEvent event = null; - if (value instanceof HttpSessionBindingListener) { - event = new HttpSessionBindingEvent(getSession(), name, value); - ((HttpSessionBindingListener) value).valueUnbound(event); - } - - // Notify interested application event listeners - Context context = (Context) manager.getContainer(); - Object listeners[] = context.getApplicationEventListeners(); - if (listeners == null) - return; - for (int i = 0; i < listeners.length; i++) { - if (!(listeners[i] instanceof HttpSessionAttributeListener)) - continue; - HttpSessionAttributeListener listener = - (HttpSessionAttributeListener) listeners[i]; - try { - fireContainerEvent(context, - "beforeSessionAttributeRemoved", - listener); - if (event == null) { - event = new HttpSessionBindingEvent - (getSession(), name, value); - } - listener.attributeRemoved(event); - fireContainerEvent(context, - "afterSessionAttributeRemoved", - listener); - } catch (Throwable t) { - try { - fireContainerEvent(context, - "afterSessionAttributeRemoved", - listener); - } catch (Exception e) { - ; - } - manager.getContainer().getLogger().error - (sm.getString("standardSession.attributeEvent"), t); - } - } - - } - - -} - - -// ------------------------------------------------------------ Protected Class - - -/** - * This class is a dummy implementation of the HttpSessionContext - * interface, to conform to the requirement that such an object be returned - * when HttpSession.getSessionContext() is called. - * - * @author Craig R. McClanahan - * - * @deprecated As of Java Servlet API 2.1 with no replacement. The - * interface will be removed in a future version of this API. - */ - -final class StandardSessionContext implements HttpSessionContext { - - - protected HashMap dummy = new HashMap(); - - /** - * Return the session identifiers of all sessions defined - * within this context. - * - * @deprecated As of Java Servlet API 2.1 with no replacement. - * This method must return an empty Enumeration - * and will be removed in a future version of the API. - */ - public Enumeration getIds() { - - return (new Enumerator(dummy)); - - } - - - /** - * Return the HttpSession associated with the - * specified session identifier. - * - * @param id Session identifier for which to look up a session - * - * @deprecated As of Java Servlet API 2.1 with no replacement. - * This method must return null and will be removed in a - * future version of the API. - */ - public HttpSession getSession(String id) { - - return (null); - - } - - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + + +import java.beans.PropertyChangeSupport; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.Principal; +import java.security.PrivilegedAction; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionActivationListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionBindingEvent; +import javax.servlet.http.HttpSessionBindingListener; +import javax.servlet.http.HttpSessionContext; +import javax.servlet.http.HttpSessionEvent; +import javax.servlet.http.HttpSessionListener; + +import org.apache.catalina.Context; +import org.apache.catalina.Globals; +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.SessionEvent; +import org.apache.catalina.SessionListener; +import org.apache.catalina.util.Enumerator; +import org.apache.catalina.util.StringManager; + +import org.apache.catalina.security.SecurityUtil; + +/** + * Standard implementation of the Session interface. This object is + * serializable, so that it can be stored in persistent storage or transferred + * to a different JVM for distributable session support. + *

    + * IMPLEMENTATION NOTE: An instance of this class represents both the + * internal (Session) and application level (HttpSession) view of the session. + * However, because the class itself is not declared public, Java logic outside + * of the org.apache.catalina.session package cannot cast an + * HttpSession view of this instance back to a Session view. + *

    + * IMPLEMENTATION NOTE: If you add fields to this class, you must + * make sure that you carry them over in the read/writeObject methods so + * that this class is properly serialized. + * + * @author Craig R. McClanahan + * @author Sean Legassick + * @author Jon S. Stevens + * @version $Revision: 384817 $ $Date: 2006-03-10 16:27:43 +0100 (ven., 10 mars 2006) $ + */ + +public class StandardSession + implements HttpSession, Session, Serializable { + + + protected static final boolean ACTIVITY_CHECK = + Boolean.valueOf(System.getProperty("org.apache.catalina.session.StandardSession.ACTIVITY_CHECK", "false")).booleanValue(); + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new Session associated with the specified Manager. + * + * @param manager The manager with which this Session is associated + */ + public StandardSession(Manager manager) { + + super(); + this.manager = manager; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Type array. + */ + protected static final String EMPTY_ARRAY[] = new String[0]; + + + /** + * The dummy attribute value serialized when a NotSerializableException is + * encountered in writeObject(). + */ + protected static final String NOT_SERIALIZED = + "___NOT_SERIALIZABLE_EXCEPTION___"; + + + /** + * The collection of user data attributes associated with this Session. + */ + protected Map attributes = new Hashtable(); + + + /** + * The authentication type used to authenticate our cached Principal, + * if any. NOTE: This value is not included in the serialized + * version of this object. + */ + protected transient String authType = null; + + + /** + * The java.lang.Method for the + * fireContainerEvent() method of the + * org.apache.catalina.core.StandardContext method, + * if our Context implementation is of this class. This value is + * computed dynamically the first time it is needed, or after + * a session reload (since it is declared transient). + */ + protected transient Method containerEventMethod = null; + + + /** + * The method signature for the fireContainerEvent method. + */ + protected static final Class containerEventTypes[] = + { String.class, Object.class }; + + + /** + * The time this session was created, in milliseconds since midnight, + * January 1, 1970 GMT. + */ + protected long creationTime = 0L; + + + /** + * Set of attribute names which are not allowed to be persisted. + */ + protected static final String[] excludedAttributes = { + Globals.SUBJECT_ATTR + }; + + + /** + * We are currently processing a session expiration, so bypass + * certain IllegalStateException tests. NOTE: This value is not + * included in the serialized version of this object. + */ + protected transient boolean expiring = false; + + + /** + * The facade associated with this session. NOTE: This value is not + * included in the serialized version of this object. + */ + protected transient StandardSessionFacade facade = null; + + + /** + * The session identifier of this Session. + */ + protected String id = null; + + + /** + * Descriptive information describing this Session implementation. + */ + protected static final String info = "StandardSession/1.0"; + + + /** + * The last accessed time for this Session. + */ + protected long lastAccessedTime = creationTime; + + + /** + * The session event listeners for this Session. + */ + protected transient ArrayList listeners = new ArrayList(); + + + /** + * The Manager with which this Session is associated. + */ + protected transient Manager manager = null; + + + /** + * The maximum time interval, in seconds, between client requests before + * the servlet container may invalidate this session. A negative time + * indicates that the session should never time out. + */ + protected int maxInactiveInterval = -1; + + + /** + * Flag indicating whether this session is new or not. + */ + protected boolean isNew = false; + + + /** + * Flag indicating whether this session is valid or not. + */ + protected boolean isValid = false; + + + /** + * Internal notes associated with this session by Catalina components + * and event listeners. IMPLEMENTATION NOTE: This object is + * not saved and restored across session serializations! + */ + protected transient Map notes = new Hashtable(); + + + /** + * The authenticated Principal associated with this session, if any. + * IMPLEMENTATION NOTE: This object is not saved and + * restored across session serializations! + */ + protected transient Principal principal = null; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The HTTP session context associated with this session. + */ + protected static HttpSessionContext sessionContext = null; + + + /** + * The property change support for this component. NOTE: This value + * is not included in the serialized version of this object. + */ + protected transient PropertyChangeSupport support = + new PropertyChangeSupport(this); + + + /** + * The current accessed time for this session. + */ + protected long thisAccessedTime = creationTime; + + + /** + * The access count for this session. + */ + protected transient AtomicInteger accessCount = null; + + + // ----------------------------------------------------- Session Properties + + + /** + * Return the authentication type used to authenticate our cached + * Principal, if any. + */ + public String getAuthType() { + + return (this.authType); + + } + + + /** + * Set the authentication type used to authenticate our cached + * Principal, if any. + * + * @param authType The new cached authentication type + */ + public void setAuthType(String authType) { + + String oldAuthType = this.authType; + this.authType = authType; + support.firePropertyChange("authType", oldAuthType, this.authType); + + } + + + /** + * Set the creation time for this session. This method is called by the + * Manager when an existing Session instance is reused. + * + * @param time The new creation time + */ + public void setCreationTime(long time) { + + this.creationTime = time; + this.lastAccessedTime = time; + this.thisAccessedTime = time; + + } + + + /** + * Return the session identifier for this session. + */ + public String getId() { + + return (this.id); + + } + + + /** + * Return the session identifier for this session. + */ + public String getIdInternal() { + + return (this.id); + + } + + + /** + * Set the session identifier for this session. + * + * @param id The new session identifier + */ + public void setId(String id) { + + if ((this.id != null) && (manager != null)) + manager.remove(this); + + this.id = id; + + if (manager != null) + manager.add(this); + tellNew(); + } + + + /** + * Inform the listeners about the new session. + * + */ + public void tellNew() { + + // Notify interested session event listeners + fireSessionEvent(Session.SESSION_CREATED_EVENT, null); + + // Notify interested application event listeners + Context context = (Context) manager.getContainer(); + Object listeners[] = context.getApplicationLifecycleListeners(); + if (listeners != null) { + HttpSessionEvent event = + new HttpSessionEvent(getSession()); + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof HttpSessionListener)) + continue; + HttpSessionListener listener = + (HttpSessionListener) listeners[i]; + try { + fireContainerEvent(context, + "beforeSessionCreated", + listener); + listener.sessionCreated(event); + fireContainerEvent(context, + "afterSessionCreated", + listener); + } catch (Throwable t) { + try { + fireContainerEvent(context, + "afterSessionCreated", + listener); + } catch (Exception e) { + ; + } + manager.getContainer().getLogger().error + (sm.getString("standardSession.sessionEvent"), t); + } + } + } + + } + + + /** + * Return descriptive information about this Session implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the last time the client sent a request associated with this + * session, as the number of milliseconds since midnight, January 1, 1970 + * GMT. Actions that your application takes, such as getting or setting + * a value associated with the session, do not affect the access time. + */ + public long getLastAccessedTime() { + + if (!isValidInternal()) { + throw new IllegalStateException + (sm.getString("standardSession.getLastAccessedTime.ise")); + } + + return (this.lastAccessedTime); + } + + /** + * Return the last client access time without invalidation check + * @see #getLastAccessedTime(). + */ + public long getLastAccessedTimeInternal() { + return (this.lastAccessedTime); + } + + /** + * Return the Manager within which this Session is valid. + */ + public Manager getManager() { + + return (this.manager); + + } + + + /** + * Set the Manager within which this Session is valid. + * + * @param manager The new Manager + */ + public void setManager(Manager manager) { + + this.manager = manager; + + } + + + /** + * Return the maximum time interval, in seconds, between client requests + * before the servlet container will invalidate the session. A negative + * time indicates that the session should never time out. + */ + public int getMaxInactiveInterval() { + + return (this.maxInactiveInterval); + + } + + + /** + * Set the maximum time interval, in seconds, between client requests + * before the servlet container will invalidate the session. A negative + * time indicates that the session should never time out. + * + * @param interval The new maximum interval + */ + public void setMaxInactiveInterval(int interval) { + + this.maxInactiveInterval = interval; + if (isValid && interval == 0) { + expire(); + } + + } + + + /** + * Set the isNew flag for this session. + * + * @param isNew The new value for the isNew flag + */ + public void setNew(boolean isNew) { + + this.isNew = isNew; + + } + + + /** + * Return the authenticated Principal that is associated with this Session. + * This provides an Authenticator with a means to cache a + * previously authenticated Principal, and avoid potentially expensive + * Realm.authenticate() calls on every request. If there + * is no current associated Principal, return null. + */ + public Principal getPrincipal() { + + return (this.principal); + + } + + + /** + * Set the authenticated Principal that is associated with this Session. + * This provides an Authenticator with a means to cache a + * previously authenticated Principal, and avoid potentially expensive + * Realm.authenticate() calls on every request. + * + * @param principal The new Principal, or null if none + */ + public void setPrincipal(Principal principal) { + + Principal oldPrincipal = this.principal; + this.principal = principal; + support.firePropertyChange("principal", oldPrincipal, this.principal); + + } + + + /** + * Return the HttpSession for which this object + * is the facade. + */ + public HttpSession getSession() { + + if (facade == null){ + if (SecurityUtil.isPackageProtectionEnabled()){ + final StandardSession fsession = this; + facade = (StandardSessionFacade)AccessController.doPrivileged(new PrivilegedAction(){ + public Object run(){ + return new StandardSessionFacade(fsession); + } + }); + } else { + facade = new StandardSessionFacade(this); + } + } + return (facade); + + } + + + /** + * Return the isValid flag for this session. + */ + public boolean isValid() { + + if (this.expiring) { + return true; + } + + if (!this.isValid) { + return false; + } + + if (ACTIVITY_CHECK && accessCount.get() > 0) { + return true; + } + + if (maxInactiveInterval >= 0) { + long timeNow = System.currentTimeMillis(); + int timeIdle = (int) ((timeNow - thisAccessedTime) / 1000L); + if (timeIdle >= maxInactiveInterval) { + expire(true); + } + } + + return (this.isValid); + } + + + /** + * Set the isValid flag for this session. + * + * @param isValid The new value for the isValid flag + */ + public void setValid(boolean isValid) { + this.isValid = isValid; + } + + + // ------------------------------------------------- Session Public Methods + + + /** + * Update the accessed time information for this session. This method + * should be called by the context when a request comes in for a particular + * session, even if the application does not reference it. + */ + public void access() { + + this.lastAccessedTime = this.thisAccessedTime; + this.thisAccessedTime = System.currentTimeMillis(); + + if (ACTIVITY_CHECK) { + accessCount.incrementAndGet(); + } + + } + + + /** + * End the access. + */ + public void endAccess() { + + isNew = false; + + if (ACTIVITY_CHECK) { + accessCount.decrementAndGet(); + } + + } + + + /** + * Add a session event listener to this component. + */ + public void addSessionListener(SessionListener listener) { + + listeners.add(listener); + + } + + + /** + * Perform the internal processing required to invalidate this session, + * without triggering an exception if the session has already expired. + */ + public void expire() { + + expire(true); + + } + + + /** + * Perform the internal processing required to invalidate this session, + * without triggering an exception if the session has already expired. + * + * @param notify Should we notify listeners about the demise of + * this session? + */ + public void expire(boolean notify) { + + // Mark this session as "being expired" if needed + if (expiring) + return; + + synchronized (this) { + + if (manager == null) + return; + + expiring = true; + + // Notify interested application event listeners + // FIXME - Assumes we call listeners in reverse order + Context context = (Context) manager.getContainer(); + Object listeners[] = context.getApplicationLifecycleListeners(); + if (notify && (listeners != null)) { + HttpSessionEvent event = + new HttpSessionEvent(getSession()); + for (int i = 0; i < listeners.length; i++) { + int j = (listeners.length - 1) - i; + if (!(listeners[j] instanceof HttpSessionListener)) + continue; + HttpSessionListener listener = + (HttpSessionListener) listeners[j]; + try { + fireContainerEvent(context, + "beforeSessionDestroyed", + listener); + listener.sessionDestroyed(event); + fireContainerEvent(context, + "afterSessionDestroyed", + listener); + } catch (Throwable t) { + try { + fireContainerEvent(context, + "afterSessionDestroyed", + listener); + } catch (Exception e) { + ; + } + manager.getContainer().getLogger().error + (sm.getString("standardSession.sessionEvent"), t); + } + } + } + accessCount = null; + setValid(false); + + /* + * Compute how long this session has been alive, and update + * session manager's related properties accordingly + */ + long timeNow = System.currentTimeMillis(); + int timeAlive = (int) ((timeNow - creationTime)/1000); + synchronized (manager) { + if (timeAlive > manager.getSessionMaxAliveTime()) { + manager.setSessionMaxAliveTime(timeAlive); + } + int numExpired = manager.getExpiredSessions(); + numExpired++; + manager.setExpiredSessions(numExpired); + int average = manager.getSessionAverageAliveTime(); + average = ((average * (numExpired-1)) + timeAlive)/numExpired; + manager.setSessionAverageAliveTime(average); + } + + // Remove this session from our manager's active sessions + manager.remove(this); + + // Notify interested session event listeners + if (notify) { + fireSessionEvent(Session.SESSION_DESTROYED_EVENT, null); + } + + // We have completed expire of this session + expiring = false; + + // Unbind any objects associated with this session + String keys[] = keys(); + for (int i = 0; i < keys.length; i++) + removeAttributeInternal(keys[i], notify); + + } + + } + + + /** + * Perform the internal processing required to passivate + * this session. + */ + public void passivate() { + + // Notify interested session event listeners + fireSessionEvent(Session.SESSION_PASSIVATED_EVENT, null); + + // Notify ActivationListeners + HttpSessionEvent event = null; + String keys[] = keys(); + for (int i = 0; i < keys.length; i++) { + Object attribute = attributes.get(keys[i]); + if (attribute instanceof HttpSessionActivationListener) { + if (event == null) + event = new HttpSessionEvent(getSession()); + try { + ((HttpSessionActivationListener)attribute) + .sessionWillPassivate(event); + } catch (Throwable t) { + manager.getContainer().getLogger().error + (sm.getString("standardSession.attributeEvent"), t); + } + } + } + + } + + + /** + * Perform internal processing required to activate this + * session. + */ + public void activate() { + + // Initialize access count + if (ACTIVITY_CHECK) { + accessCount = new AtomicInteger(); + } + + // Notify interested session event listeners + fireSessionEvent(Session.SESSION_ACTIVATED_EVENT, null); + + // Notify ActivationListeners + HttpSessionEvent event = null; + String keys[] = keys(); + for (int i = 0; i < keys.length; i++) { + Object attribute = attributes.get(keys[i]); + if (attribute instanceof HttpSessionActivationListener) { + if (event == null) + event = new HttpSessionEvent(getSession()); + try { + ((HttpSessionActivationListener)attribute) + .sessionDidActivate(event); + } catch (Throwable t) { + manager.getContainer().getLogger().error + (sm.getString("standardSession.attributeEvent"), t); + } + } + } + + } + + + /** + * Return the object bound with the specified name to the internal notes + * for this session, or null if no such binding exists. + * + * @param name Name of the note to be returned + */ + public Object getNote(String name) { + + return (notes.get(name)); + + } + + + /** + * Return an Iterator containing the String names of all notes bindings + * that exist for this session. + */ + public Iterator getNoteNames() { + + return (notes.keySet().iterator()); + + } + + + /** + * Release all object references, and initialize instance variables, in + * preparation for reuse of this object. + */ + public void recycle() { + + // Reset the instance variables associated with this Session + attributes.clear(); + setAuthType(null); + creationTime = 0L; + expiring = false; + id = null; + lastAccessedTime = 0L; + maxInactiveInterval = -1; + accessCount = null; + notes.clear(); + setPrincipal(null); + isNew = false; + isValid = false; + manager = null; + + } + + + /** + * Remove any object bound to the specified name in the internal notes + * for this session. + * + * @param name Name of the note to be removed + */ + public void removeNote(String name) { + + notes.remove(name); + + } + + + /** + * Remove a session event listener from this component. + */ + public void removeSessionListener(SessionListener listener) { + + listeners.remove(listener); + + } + + + /** + * Bind an object to a specified name in the internal notes associated + * with this session, replacing any existing binding for this name. + * + * @param name Name to which the object should be bound + * @param value Object to be bound to the specified name + */ + public void setNote(String name, Object value) { + + notes.put(name, value); + + } + + + /** + * Return a string representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + sb.append("StandardSession["); + sb.append(id); + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------ Session Package Methods + + + /** + * Read a serialized version of the contents of this session object from + * the specified object input stream, without requiring that the + * StandardSession itself have been serialized. + * + * @param stream The object input stream to read from + * + * @exception ClassNotFoundException if an unknown class is specified + * @exception IOException if an input/output error occurs + */ + public void readObjectData(ObjectInputStream stream) + throws ClassNotFoundException, IOException { + + readObject(stream); + + } + + + /** + * Write a serialized version of the contents of this session object to + * the specified object output stream, without requiring that the + * StandardSession itself have been serialized. + * + * @param stream The object output stream to write to + * + * @exception IOException if an input/output error occurs + */ + public void writeObjectData(ObjectOutputStream stream) + throws IOException { + + writeObject(stream); + + } + + + // ------------------------------------------------- HttpSession Properties + + + /** + * Return the time when this session was created, in milliseconds since + * midnight, January 1, 1970 GMT. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public long getCreationTime() { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.getCreationTime.ise")); + + return (this.creationTime); + + } + + + /** + * Return the ServletContext to which this session belongs. + */ + public ServletContext getServletContext() { + + if (manager == null) + return (null); + Context context = (Context) manager.getContainer(); + if (context == null) + return (null); + else + return (context.getServletContext()); + + } + + + /** + * Return the session context with which this session is associated. + * + * @deprecated As of Version 2.1, this method is deprecated and has no + * replacement. It will be removed in a future version of the + * Java Servlet API. + */ + public HttpSessionContext getSessionContext() { + + if (sessionContext == null) + sessionContext = new StandardSessionContext(); + return (sessionContext); + + } + + + // ----------------------------------------------HttpSession Public Methods + + + /** + * Return the object bound with the specified name in this session, or + * null if no object is bound with that name. + * + * @param name Name of the attribute to be returned + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public Object getAttribute(String name) { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.getAttribute.ise")); + + return (attributes.get(name)); + + } + + + /** + * Return an Enumeration of String objects + * containing the names of the objects bound to this session. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public Enumeration getAttributeNames() { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.getAttributeNames.ise")); + + return (new Enumerator(attributes.keySet(), true)); + + } + + + /** + * Return the object bound with the specified name in this session, or + * null if no object is bound with that name. + * + * @param name Name of the value to be returned + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + * @deprecated As of Version 2.2, this method is replaced by + * getAttribute() + */ + public Object getValue(String name) { + + return (getAttribute(name)); + + } + + + /** + * Return the set of names of objects bound to this session. If there + * are no such objects, a zero-length array is returned. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + * @deprecated As of Version 2.2, this method is replaced by + * getAttributeNames() + */ + public String[] getValueNames() { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.getValueNames.ise")); + + return (keys()); + + } + + + /** + * Invalidates this session and unbinds any objects bound to it. + * + * @exception IllegalStateException if this method is called on + * an invalidated session + */ + public void invalidate() { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.invalidate.ise")); + + // Cause this session to expire + expire(); + + } + + + /** + * Return true if the client does not yet know about the + * session, or if the client chooses not to join the session. For + * example, if the server used only cookie-based sessions, and the client + * has disabled the use of cookies, then a session would be new on each + * request. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public boolean isNew() { + + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.isNew.ise")); + + return (this.isNew); + + } + + + + /** + * Bind an object to this session, using the specified name. If an object + * of the same name is already bound to this session, the object is + * replaced. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueBound() on the object. + * + * @param name Name to which the object is bound, cannot be null + * @param value Object to be bound, cannot be null + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + * @deprecated As of Version 2.2, this method is replaced by + * setAttribute() + */ + public void putValue(String name, Object value) { + + setAttribute(name, value); + + } + + + /** + * Remove the object bound with the specified name from this session. If + * the session does not have an object bound with this name, this method + * does nothing. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueUnbound() on the object. + * + * @param name Name of the object to remove from this session. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public void removeAttribute(String name) { + + removeAttribute(name, true); + + } + + + /** + * Remove the object bound with the specified name from this session. If + * the session does not have an object bound with this name, this method + * does nothing. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueUnbound() on the object. + * + * @param name Name of the object to remove from this session. + * @param notify Should we notify interested listeners that this + * attribute is being removed? + * + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public void removeAttribute(String name, boolean notify) { + + // Validate our current state + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.removeAttribute.ise")); + + removeAttributeInternal(name, notify); + + } + + + /** + * Remove the object bound with the specified name from this session. If + * the session does not have an object bound with this name, this method + * does nothing. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueUnbound() on the object. + * + * @param name Name of the object to remove from this session. + * + * @exception IllegalStateException if this method is called on an + * invalidated session + * + * @deprecated As of Version 2.2, this method is replaced by + * removeAttribute() + */ + public void removeValue(String name) { + + removeAttribute(name); + + } + + + /** + * Bind an object to this session, using the specified name. If an object + * of the same name is already bound to this session, the object is + * replaced. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueBound() on the object. + * + * @param name Name to which the object is bound, cannot be null + * @param value Object to be bound, cannot be null + * + * @exception IllegalArgumentException if an attempt is made to add a + * non-serializable object in an environment marked distributable. + * @exception IllegalStateException if this method is called on an + * invalidated session + */ + public void setAttribute(String name, Object value) { + + // Name cannot be null + if (name == null) + throw new IllegalArgumentException + (sm.getString("standardSession.setAttribute.namenull")); + + // Null value is the same as removeAttribute() + if (value == null) { + removeAttribute(name); + return; + } + + // Validate our current state + if (!isValidInternal()) + throw new IllegalStateException + (sm.getString("standardSession.setAttribute.ise")); + if ((manager != null) && manager.getDistributable() && + !(value instanceof Serializable)) + throw new IllegalArgumentException + (sm.getString("standardSession.setAttribute.iae")); + + // Construct an event with the new value + HttpSessionBindingEvent event = null; + + // Call the valueBound() method if necessary + if (value instanceof HttpSessionBindingListener) { + // Don't call any notification if replacing with the same value + Object oldValue = attributes.get(name); + if (value != oldValue) { + event = new HttpSessionBindingEvent(getSession(), name, value); + try { + ((HttpSessionBindingListener) value).valueBound(event); + } catch (Throwable t){ + manager.getContainer().getLogger().error + (sm.getString("standardSession.bindingEvent"), t); + } + } + } + + // Replace or add this attribute + Object unbound = attributes.put(name, value); + + // Call the valueUnbound() method if necessary + if ((unbound != null) && (unbound != value) && + (unbound instanceof HttpSessionBindingListener)) { + try { + ((HttpSessionBindingListener) unbound).valueUnbound + (new HttpSessionBindingEvent(getSession(), name)); + } catch (Throwable t) { + manager.getContainer().getLogger().error + (sm.getString("standardSession.bindingEvent"), t); + } + } + + // Notify interested application event listeners + Context context = (Context) manager.getContainer(); + Object listeners[] = context.getApplicationEventListeners(); + if (listeners == null) + return; + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof HttpSessionAttributeListener)) + continue; + HttpSessionAttributeListener listener = + (HttpSessionAttributeListener) listeners[i]; + try { + if (unbound != null) { + fireContainerEvent(context, + "beforeSessionAttributeReplaced", + listener); + if (event == null) { + event = new HttpSessionBindingEvent + (getSession(), name, unbound); + } + listener.attributeReplaced(event); + fireContainerEvent(context, + "afterSessionAttributeReplaced", + listener); + } else { + fireContainerEvent(context, + "beforeSessionAttributeAdded", + listener); + if (event == null) { + event = new HttpSessionBindingEvent + (getSession(), name, value); + } + listener.attributeAdded(event); + fireContainerEvent(context, + "afterSessionAttributeAdded", + listener); + } + } catch (Throwable t) { + try { + if (unbound != null) { + fireContainerEvent(context, + "afterSessionAttributeReplaced", + listener); + } else { + fireContainerEvent(context, + "afterSessionAttributeAdded", + listener); + } + } catch (Exception e) { + ; + } + manager.getContainer().getLogger().error + (sm.getString("standardSession.attributeEvent"), t); + } + } + + } + + + // ------------------------------------------ HttpSession Protected Methods + + + /** + * Return the isValid flag for this session without any expiration + * check. + */ + protected boolean isValidInternal() { + return (this.isValid || this.expiring); + } + + + /** + * Read a serialized version of this session object from the specified + * object input stream. + *

    + * IMPLEMENTATION NOTE: The reference to the owning Manager + * is not restored by this method, and must be set explicitly. + * + * @param stream The input stream to read from + * + * @exception ClassNotFoundException if an unknown class is specified + * @exception IOException if an input/output error occurs + */ + protected void readObject(ObjectInputStream stream) + throws ClassNotFoundException, IOException { + + // Deserialize the scalar instance variables (except Manager) + authType = null; // Transient only + creationTime = ((Long) stream.readObject()).longValue(); + lastAccessedTime = ((Long) stream.readObject()).longValue(); + maxInactiveInterval = ((Integer) stream.readObject()).intValue(); + isNew = ((Boolean) stream.readObject()).booleanValue(); + isValid = ((Boolean) stream.readObject()).booleanValue(); + thisAccessedTime = ((Long) stream.readObject()).longValue(); + principal = null; // Transient only + // setId((String) stream.readObject()); + id = (String) stream.readObject(); + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug + ("readObject() loading session " + id); + + // Deserialize the attribute count and attribute values + if (attributes == null) + attributes = new Hashtable(); + int n = ((Integer) stream.readObject()).intValue(); + boolean isValidSave = isValid; + isValid = true; + for (int i = 0; i < n; i++) { + String name = (String) stream.readObject(); + Object value = (Object) stream.readObject(); + if ((value instanceof String) && (value.equals(NOT_SERIALIZED))) + continue; + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug(" loading attribute '" + name + + "' with value '" + value + "'"); + attributes.put(name, value); + } + isValid = isValidSave; + + if (listeners == null) { + listeners = new ArrayList(); + } + + if (notes == null) { + notes = new Hashtable(); + } + } + + + /** + * Write a serialized version of this session object to the specified + * object output stream. + *

    + * IMPLEMENTATION NOTE: The owning Manager will not be stored + * in the serialized representation of this Session. After calling + * readObject(), you must set the associated Manager + * explicitly. + *

    + * IMPLEMENTATION NOTE: Any attribute that is not Serializable + * will be unbound from the session, with appropriate actions if it + * implements HttpSessionBindingListener. If you do not want any such + * attributes, be sure the distributable property of the + * associated Manager is set to true. + * + * @param stream The output stream to write to + * + * @exception IOException if an input/output error occurs + */ + protected void writeObject(ObjectOutputStream stream) throws IOException { + + // Write the scalar instance variables (except Manager) + stream.writeObject(new Long(creationTime)); + stream.writeObject(new Long(lastAccessedTime)); + stream.writeObject(new Integer(maxInactiveInterval)); + stream.writeObject(new Boolean(isNew)); + stream.writeObject(new Boolean(isValid)); + stream.writeObject(new Long(thisAccessedTime)); + stream.writeObject(id); + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug + ("writeObject() storing session " + id); + + // Accumulate the names of serializable and non-serializable attributes + String keys[] = keys(); + ArrayList saveNames = new ArrayList(); + ArrayList saveValues = new ArrayList(); + for (int i = 0; i < keys.length; i++) { + Object value = attributes.get(keys[i]); + if (value == null) + continue; + else if ( (value instanceof Serializable) + && (!exclude(keys[i]) )) { + saveNames.add(keys[i]); + saveValues.add(value); + } else { + removeAttributeInternal(keys[i], true); + } + } + + // Serialize the attribute count and the Serializable attributes + int n = saveNames.size(); + stream.writeObject(new Integer(n)); + for (int i = 0; i < n; i++) { + stream.writeObject((String) saveNames.get(i)); + try { + stream.writeObject(saveValues.get(i)); + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug + (" storing attribute '" + saveNames.get(i) + + "' with value '" + saveValues.get(i) + "'"); + } catch (NotSerializableException e) { + manager.getContainer().getLogger().warn + (sm.getString("standardSession.notSerializable", + saveNames.get(i), id), e); + stream.writeObject(NOT_SERIALIZED); + if (manager.getContainer().getLogger().isDebugEnabled()) + manager.getContainer().getLogger().debug + (" storing attribute '" + saveNames.get(i) + + "' with value NOT_SERIALIZED"); + } + } + + } + + + /** + * Exclude attribute that cannot be serialized. + * @param name the attribute's name + */ + protected boolean exclude(String name){ + + for (int i = 0; i < excludedAttributes.length; i++) { + if (name.equalsIgnoreCase(excludedAttributes[i])) + return true; + } + + return false; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Fire container events if the Context implementation is the + * org.apache.catalina.core.StandardContext. + * + * @param context Context for which to fire events + * @param type Event type + * @param data Event data + * + * @exception Exception occurred during event firing + */ + protected void fireContainerEvent(Context context, + String type, Object data) + throws Exception { + + if (!"org.apache.catalina.core.StandardContext".equals + (context.getClass().getName())) { + return; // Container events are not supported + } + // NOTE: Race condition is harmless, so do not synchronize + if (containerEventMethod == null) { + containerEventMethod = + context.getClass().getMethod("fireContainerEvent", + containerEventTypes); + } + Object containerEventParams[] = new Object[2]; + containerEventParams[0] = type; + containerEventParams[1] = data; + containerEventMethod.invoke(context, containerEventParams); + + } + + + + /** + * Notify all session event listeners that a particular event has + * occurred for this Session. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param data Event data + */ + public void fireSessionEvent(String type, Object data) { + if (listeners.size() < 1) + return; + SessionEvent event = new SessionEvent(this, type, data); + SessionListener list[] = new SessionListener[0]; + synchronized (listeners) { + list = (SessionListener[]) listeners.toArray(list); + } + + for (int i = 0; i < list.length; i++){ + ((SessionListener) list[i]).sessionEvent(event); + } + + } + + + /** + * Return the names of all currently defined session attributes + * as an array of Strings. If there are no defined attributes, a + * zero-length array is returned. + */ + protected String[] keys() { + + return ((String[]) attributes.keySet().toArray(EMPTY_ARRAY)); + + } + + + /** + * Remove the object bound with the specified name from this session. If + * the session does not have an object bound with this name, this method + * does nothing. + *

    + * After this method executes, and if the object implements + * HttpSessionBindingListener, the container calls + * valueUnbound() on the object. + * + * @param name Name of the object to remove from this session. + * @param notify Should we notify interested listeners that this + * attribute is being removed? + */ + protected void removeAttributeInternal(String name, boolean notify) { + + // Remove this attribute from our collection + Object value = attributes.remove(name); + + // Do we need to do valueUnbound() and attributeRemoved() notification? + if (!notify || (value == null)) { + return; + } + + // Call the valueUnbound() method if necessary + HttpSessionBindingEvent event = null; + if (value instanceof HttpSessionBindingListener) { + event = new HttpSessionBindingEvent(getSession(), name, value); + ((HttpSessionBindingListener) value).valueUnbound(event); + } + + // Notify interested application event listeners + Context context = (Context) manager.getContainer(); + Object listeners[] = context.getApplicationEventListeners(); + if (listeners == null) + return; + for (int i = 0; i < listeners.length; i++) { + if (!(listeners[i] instanceof HttpSessionAttributeListener)) + continue; + HttpSessionAttributeListener listener = + (HttpSessionAttributeListener) listeners[i]; + try { + fireContainerEvent(context, + "beforeSessionAttributeRemoved", + listener); + if (event == null) { + event = new HttpSessionBindingEvent + (getSession(), name, value); + } + listener.attributeRemoved(event); + fireContainerEvent(context, + "afterSessionAttributeRemoved", + listener); + } catch (Throwable t) { + try { + fireContainerEvent(context, + "afterSessionAttributeRemoved", + listener); + } catch (Exception e) { + ; + } + manager.getContainer().getLogger().error + (sm.getString("standardSession.attributeEvent"), t); + } + } + + } + + +} + + +// ------------------------------------------------------------ Protected Class + + +/** + * This class is a dummy implementation of the HttpSessionContext + * interface, to conform to the requirement that such an object be returned + * when HttpSession.getSessionContext() is called. + * + * @author Craig R. McClanahan + * + * @deprecated As of Java Servlet API 2.1 with no replacement. The + * interface will be removed in a future version of this API. + */ + +final class StandardSessionContext implements HttpSessionContext { + + + protected HashMap dummy = new HashMap(); + + /** + * Return the session identifiers of all sessions defined + * within this context. + * + * @deprecated As of Java Servlet API 2.1 with no replacement. + * This method must return an empty Enumeration + * and will be removed in a future version of the API. + */ + public Enumeration getIds() { + + return (new Enumerator(dummy)); + + } + + + /** + * Return the HttpSession associated with the + * specified session identifier. + * + * @param id Session identifier for which to look up a session + * + * @deprecated As of Java Servlet API 2.1 with no replacement. + * This method must return null and will be removed in a + * future version of the API. + */ + public HttpSession getSession(String id) { + + return (null); + + } + + + +} diff --git a/java/org/apache/catalina/session/StandardSessionFacade.java b/java/org/apache/catalina/session/StandardSessionFacade.java index 8767180d0..e9a734614 100644 --- a/java/org/apache/catalina/session/StandardSessionFacade.java +++ b/java/org/apache/catalina/session/StandardSessionFacade.java @@ -1,158 +1,158 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.session; - - -import java.util.Enumeration; - -import javax.servlet.ServletContext; -import javax.servlet.http.HttpSession; -import javax.servlet.http.HttpSessionContext; - - -/** - * Facade for the StandardSession object. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class StandardSessionFacade - implements HttpSession { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new session facade. - */ - public StandardSessionFacade(StandardSession session) { - super(); - this.session = (HttpSession) session; - } - - - /** - * Construct a new session facade. - */ - public StandardSessionFacade(HttpSession session) { - super(); - this.session = session; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped session object. - */ - private HttpSession session = null; - - - // ---------------------------------------------------- HttpSession Methods - - - public long getCreationTime() { - return session.getCreationTime(); - } - - - public String getId() { - return session.getId(); - } - - - public long getLastAccessedTime() { - return session.getLastAccessedTime(); - } - - - public ServletContext getServletContext() { - // FIXME : Facade this object ? - return session.getServletContext(); - } - - - public void setMaxInactiveInterval(int interval) { - session.setMaxInactiveInterval(interval); - } - - - public int getMaxInactiveInterval() { - return session.getMaxInactiveInterval(); - } - - - public HttpSessionContext getSessionContext() { - return session.getSessionContext(); - } - - - public Object getAttribute(String name) { - return session.getAttribute(name); - } - - - public Object getValue(String name) { - return session.getAttribute(name); - } - - - public Enumeration getAttributeNames() { - return session.getAttributeNames(); - } - - - public String[] getValueNames() { - return session.getValueNames(); - } - - - public void setAttribute(String name, Object value) { - session.setAttribute(name, value); - } - - - public void putValue(String name, Object value) { - session.setAttribute(name, value); - } - - - public void removeAttribute(String name) { - session.removeAttribute(name); - } - - - public void removeValue(String name) { - session.removeAttribute(name); - } - - - public void invalidate() { - session.invalidate(); - } - - - public boolean isNew() { - return session.isNew(); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.session; + + +import java.util.Enumeration; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpSession; +import javax.servlet.http.HttpSessionContext; + + +/** + * Facade for the StandardSession object. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class StandardSessionFacade + implements HttpSession { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new session facade. + */ + public StandardSessionFacade(StandardSession session) { + super(); + this.session = (HttpSession) session; + } + + + /** + * Construct a new session facade. + */ + public StandardSessionFacade(HttpSession session) { + super(); + this.session = session; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Wrapped session object. + */ + private HttpSession session = null; + + + // ---------------------------------------------------- HttpSession Methods + + + public long getCreationTime() { + return session.getCreationTime(); + } + + + public String getId() { + return session.getId(); + } + + + public long getLastAccessedTime() { + return session.getLastAccessedTime(); + } + + + public ServletContext getServletContext() { + // FIXME : Facade this object ? + return session.getServletContext(); + } + + + public void setMaxInactiveInterval(int interval) { + session.setMaxInactiveInterval(interval); + } + + + public int getMaxInactiveInterval() { + return session.getMaxInactiveInterval(); + } + + + public HttpSessionContext getSessionContext() { + return session.getSessionContext(); + } + + + public Object getAttribute(String name) { + return session.getAttribute(name); + } + + + public Object getValue(String name) { + return session.getAttribute(name); + } + + + public Enumeration getAttributeNames() { + return session.getAttributeNames(); + } + + + public String[] getValueNames() { + return session.getValueNames(); + } + + + public void setAttribute(String name, Object value) { + session.setAttribute(name, value); + } + + + public void putValue(String name, Object value) { + session.setAttribute(name, value); + } + + + public void removeAttribute(String name) { + session.removeAttribute(name); + } + + + public void removeValue(String name) { + session.removeAttribute(name); + } + + + public void invalidate() { + session.invalidate(); + } + + + public boolean isNew() { + return session.isNew(); + } + + +} diff --git a/java/org/apache/catalina/session/StoreBase.java b/java/org/apache/catalina/session/StoreBase.java index 4984176d9..7412cee41 100644 --- a/java/org/apache/catalina/session/StoreBase.java +++ b/java/org/apache/catalina/session/StoreBase.java @@ -1,265 +1,265 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.session; - -import java.beans.PropertyChangeListener; -import java.beans.PropertyChangeSupport; -import java.io.IOException; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Manager; -import org.apache.catalina.Store; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; - -/** - * Abstract implementation of the Store interface to - * support most of the functionality required by a Store. - * - * @author Bip Thelin - * @version $Revision: 303826 $, $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public abstract class StoreBase - implements Lifecycle, Store { - - // ----------------------------------------------------- Instance Variables - - /** - * The descriptive information about this implementation. - */ - protected static String info = "StoreBase/1.0"; - - /** - * Name to register for this Store, used for logging. - */ - protected static String storeName = "StoreBase"; - - /** - * Has this component been started yet? - */ - protected boolean started = false; - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - /** - * The property change support for this component. - */ - protected PropertyChangeSupport support = new PropertyChangeSupport(this); - - /** - * The string manager for this package. - */ - protected StringManager sm = StringManager.getManager(Constants.Package); - - /** - * The Manager with which this JDBCStore is associated. - */ - protected Manager manager; - - // ------------------------------------------------------------- Properties - - /** - * Return the info for this Store. - */ - public String getInfo() { - return(info); - } - - - /** - * Return the name for this Store, used for logging. - */ - public String getStoreName() { - return(storeName); - } - - - /** - * Set the Manager with which this Store is associated. - * - * @param manager The newly associated Manager - */ - public void setManager(Manager manager) { - Manager oldManager = this.manager; - this.manager = manager; - support.firePropertyChange("manager", oldManager, this.manager); - } - - /** - * Return the Manager with which the Store is associated. - */ - public Manager getManager() { - return(this.manager); - } - - - // --------------------------------------------------------- Public Methods - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - lifecycle.addLifecycleListener(listener); - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to add - */ - public void removeLifecycleListener(LifecycleListener listener) { - lifecycle.removeLifecycleListener(listener); - } - - /** - * Add a property change listener to this component. - * - * @param listener a value of type 'PropertyChangeListener' - */ - public void addPropertyChangeListener(PropertyChangeListener listener) { - support.addPropertyChangeListener(listener); - } - - /** - * Remove a property change listener from this component. - * - * @param listener The listener to remove - */ - public void removePropertyChangeListener(PropertyChangeListener listener) { - support.removePropertyChangeListener(listener); - } - - // --------------------------------------------------------- Protected Methods - - /** - * Called by our background reaper thread to check if Sessions - * saved in our store are subject of being expired. If so expire - * the Session and remove it from the Store. - * - */ - public void processExpires() { - long timeNow = System.currentTimeMillis(); - String[] keys = null; - - if(!started) { - return; - } - - try { - keys = keys(); - } catch (IOException e) { - manager.getContainer().getLogger().error("Error getting keys", e); - return; - } - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires check number of " + keys.length + " sessions" ); - } - - for (int i = 0; i < keys.length; i++) { - try { - StandardSession session = (StandardSession) load(keys[i]); - if (session == null) { - continue; - } - if (session.isValid()) { - continue; - } - if (manager.getContainer().getLogger().isDebugEnabled()) { - manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires expire store session " + keys[i] ); - } - if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) { - // recycle old backup session - session.recycle(); - } else { - // expire swapped out session - session.expire(); - } - remove(session.getIdInternal()); - } catch (Exception e) { - manager.getContainer().getLogger().error("Session: "+keys[i]+"; ", e); - try { - remove(keys[i]); - } catch (IOException e2) { - manager.getContainer().getLogger().error("Error removing key", e2); - } - } - } - } - - - // --------------------------------------------------------- Thread Methods - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString(getStoreName()+".alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString(getStoreName()+".notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.session; + +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.io.IOException; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Manager; +import org.apache.catalina.Store; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; + +/** + * Abstract implementation of the Store interface to + * support most of the functionality required by a Store. + * + * @author Bip Thelin + * @version $Revision: 303826 $, $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public abstract class StoreBase + implements Lifecycle, Store { + + // ----------------------------------------------------- Instance Variables + + /** + * The descriptive information about this implementation. + */ + protected static String info = "StoreBase/1.0"; + + /** + * Name to register for this Store, used for logging. + */ + protected static String storeName = "StoreBase"; + + /** + * Has this component been started yet? + */ + protected boolean started = false; + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + /** + * The property change support for this component. + */ + protected PropertyChangeSupport support = new PropertyChangeSupport(this); + + /** + * The string manager for this package. + */ + protected StringManager sm = StringManager.getManager(Constants.Package); + + /** + * The Manager with which this JDBCStore is associated. + */ + protected Manager manager; + + // ------------------------------------------------------------- Properties + + /** + * Return the info for this Store. + */ + public String getInfo() { + return(info); + } + + + /** + * Return the name for this Store, used for logging. + */ + public String getStoreName() { + return(storeName); + } + + + /** + * Set the Manager with which this Store is associated. + * + * @param manager The newly associated Manager + */ + public void setManager(Manager manager) { + Manager oldManager = this.manager; + this.manager = manager; + support.firePropertyChange("manager", oldManager, this.manager); + } + + /** + * Return the Manager with which the Store is associated. + */ + public Manager getManager() { + return(this.manager); + } + + + // --------------------------------------------------------- Public Methods + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + lifecycle.addLifecycleListener(listener); + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + lifecycle.removeLifecycleListener(listener); + } + + /** + * Add a property change listener to this component. + * + * @param listener a value of type 'PropertyChangeListener' + */ + public void addPropertyChangeListener(PropertyChangeListener listener) { + support.addPropertyChangeListener(listener); + } + + /** + * Remove a property change listener from this component. + * + * @param listener The listener to remove + */ + public void removePropertyChangeListener(PropertyChangeListener listener) { + support.removePropertyChangeListener(listener); + } + + // --------------------------------------------------------- Protected Methods + + /** + * Called by our background reaper thread to check if Sessions + * saved in our store are subject of being expired. If so expire + * the Session and remove it from the Store. + * + */ + public void processExpires() { + long timeNow = System.currentTimeMillis(); + String[] keys = null; + + if(!started) { + return; + } + + try { + keys = keys(); + } catch (IOException e) { + manager.getContainer().getLogger().error("Error getting keys", e); + return; + } + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires check number of " + keys.length + " sessions" ); + } + + for (int i = 0; i < keys.length; i++) { + try { + StandardSession session = (StandardSession) load(keys[i]); + if (session == null) { + continue; + } + if (session.isValid()) { + continue; + } + if (manager.getContainer().getLogger().isDebugEnabled()) { + manager.getContainer().getLogger().debug(getStoreName()+ ": processExpires expire store session " + keys[i] ); + } + if ( ( (PersistentManagerBase) manager).isLoaded( keys[i] )) { + // recycle old backup session + session.recycle(); + } else { + // expire swapped out session + session.expire(); + } + remove(session.getIdInternal()); + } catch (Exception e) { + manager.getContainer().getLogger().error("Session: "+keys[i]+"; ", e); + try { + remove(keys[i]); + } catch (IOException e2) { + manager.getContainer().getLogger().error("Error removing key", e2); + } + } + } + } + + + // --------------------------------------------------------- Thread Methods + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString(getStoreName()+".alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString(getStoreName()+".notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + } + + +} diff --git a/java/org/apache/catalina/session/mbeans-descriptors.xml b/java/org/apache/catalina/session/mbeans-descriptors.xml index df6f70c4a..aa3535234 100644 --- a/java/org/apache/catalina/session/mbeans-descriptors.xml +++ b/java/org/apache/catalina/session/mbeans-descriptors.xml @@ -1,292 +1,292 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/session/package.html b/java/org/apache/catalina/session/package.html index 2db029c74..3c3d9a898 100644 --- a/java/org/apache/catalina/session/package.html +++ b/java/org/apache/catalina/session/package.html @@ -1,52 +1,52 @@ - - -

    This package contains the standard Manager and -Session implementations that represent the collection of -active sessions and the individual sessions themselves, respectively, -that are associated with a Context. Additional implementations -of the Manager interface can be based upon the supplied -convenience base class (ManagerBase), if desired. Different -implementations of Session are possible, but a need for -functionality beyond what is provided by the standard implementation -(StandardSession) is not expected.

    - -

    The convenience ManagerBase base class is configured by -setting the following properties:

    -
      -
    • algorithm - Message digest algorithm to be used when - generating session identifiers. This must be the name of an - algorithm supported by the java.security.MessageDigest - class on your platform. [DEFAULT_ALGORITHM]
    • -
    • debug - Debugging detail level for this component. [0]
    • -
    • distributable - Has the web application we are associated with - been marked as "distributable"? If it has, attempts to add or replace - a session attribute object that does not implement the - java.io.Serializable interface will be rejected. - [false]
    • -
    • entropy - A string initialization parameter that is used to - increase the entropy of the seeding of the random number generator - used in creation of session identifiers. [NONE]
    • -
    • maxInactiveInterval - The default maximum inactive interval, - in minutes, for sessions created by this Manager. The standard - implementation automatically updates this value based on the configuration - settings in the web application deployment descriptor. [60]
    • -
    • randomClass - The Java class name of the random number generator - to be used when creating session identifiers for this Manager. - [java.security.SecureRandom]
    • -
    - -

    The standard implementation of the Manager interface -(StandardManager) supports the following additional configuration -properties:

    -
      -
    • checkInterval - The interval, in seconds, between checks for - sessions that have expired and should be invalidated. [60]
    • -
    • maxActiveSessions - The maximum number of active sessions that - will be allowed, or -1 for no limit. [-1]
    • -
    • pathname - Pathname to the file that is used to store session - data persistently across container restarts. If this pathname is relative, - it is resolved against the temporary working directory provided by our - associated Context, if any. ["sessions.ser"]
    • -
    - - + + +

    This package contains the standard Manager and +Session implementations that represent the collection of +active sessions and the individual sessions themselves, respectively, +that are associated with a Context. Additional implementations +of the Manager interface can be based upon the supplied +convenience base class (ManagerBase), if desired. Different +implementations of Session are possible, but a need for +functionality beyond what is provided by the standard implementation +(StandardSession) is not expected.

    + +

    The convenience ManagerBase base class is configured by +setting the following properties:

    +
      +
    • algorithm - Message digest algorithm to be used when + generating session identifiers. This must be the name of an + algorithm supported by the java.security.MessageDigest + class on your platform. [DEFAULT_ALGORITHM]
    • +
    • debug - Debugging detail level for this component. [0]
    • +
    • distributable - Has the web application we are associated with + been marked as "distributable"? If it has, attempts to add or replace + a session attribute object that does not implement the + java.io.Serializable interface will be rejected. + [false]
    • +
    • entropy - A string initialization parameter that is used to + increase the entropy of the seeding of the random number generator + used in creation of session identifiers. [NONE]
    • +
    • maxInactiveInterval - The default maximum inactive interval, + in minutes, for sessions created by this Manager. The standard + implementation automatically updates this value based on the configuration + settings in the web application deployment descriptor. [60]
    • +
    • randomClass - The Java class name of the random number generator + to be used when creating session identifiers for this Manager. + [java.security.SecureRandom]
    • +
    + +

    The standard implementation of the Manager interface +(StandardManager) supports the following additional configuration +properties:

    +
      +
    • checkInterval - The interval, in seconds, between checks for + sessions that have expired and should be invalidated. [60]
    • +
    • maxActiveSessions - The maximum number of active sessions that + will be allowed, or -1 for no limit. [-1]
    • +
    • pathname - Pathname to the file that is used to store session + data persistently across container restarts. If this pathname is relative, + it is resolved against the temporary working directory provided by our + associated Context, if any. ["sessions.ser"]
    • +
    + + diff --git a/java/org/apache/catalina/ssi/ByteArrayServletOutputStream.java b/java/org/apache/catalina/ssi/ByteArrayServletOutputStream.java index b0b136f10..c3d2271a4 100644 --- a/java/org/apache/catalina/ssi/ByteArrayServletOutputStream.java +++ b/java/org/apache/catalina/ssi/ByteArrayServletOutputStream.java @@ -1,62 +1,62 @@ -/* - * Copyright 1999-2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ssi; - -import java.io.ByteArrayOutputStream; -import javax.servlet.ServletOutputStream; - - -/** - * Class that extends ServletOuputStream, used as a wrapper from within - * SsiInclude - * - * @author Bip Thelin - * @version $Revision: 304045 $, $Date: 2005-08-04 14:18:30 +0200 (jeu., 04 août 2005) $ - * @see ServletOutputStream and ByteArrayOutputStream - */ -public class ByteArrayServletOutputStream extends ServletOutputStream { - /** - * Our buffer to hold the stream. - */ - protected ByteArrayOutputStream buf = null; - - - /** - * Construct a new ServletOutputStream. - */ - public ByteArrayServletOutputStream() { - buf = new ByteArrayOutputStream(); - } - - - /** - * @return the byte array. - */ - public byte[] toByteArray() { - return buf.toByteArray(); - } - - - /** - * Write to our buffer. - * - * @param b The parameter to write - */ - public void write(int b) { - buf.write(b); - } -} +/* + * Copyright 1999-2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ssi; + +import java.io.ByteArrayOutputStream; +import javax.servlet.ServletOutputStream; + + +/** + * Class that extends ServletOuputStream, used as a wrapper from within + * SsiInclude + * + * @author Bip Thelin + * @version $Revision: 304045 $, $Date: 2005-08-04 14:18:30 +0200 (jeu., 04 août 2005) $ + * @see ServletOutputStream and ByteArrayOutputStream + */ +public class ByteArrayServletOutputStream extends ServletOutputStream { + /** + * Our buffer to hold the stream. + */ + protected ByteArrayOutputStream buf = null; + + + /** + * Construct a new ServletOutputStream. + */ + public ByteArrayServletOutputStream() { + buf = new ByteArrayOutputStream(); + } + + + /** + * @return the byte array. + */ + public byte[] toByteArray() { + return buf.toByteArray(); + } + + + /** + * Write to our buffer. + * + * @param b The parameter to write + */ + public void write(int b) { + buf.write(b); + } +} diff --git a/java/org/apache/catalina/ssi/ExpressionParseTree.java b/java/org/apache/catalina/ssi/ExpressionParseTree.java index 09198ac85..903b07699 100644 --- a/java/org/apache/catalina/ssi/ExpressionParseTree.java +++ b/java/org/apache/catalina/ssi/ExpressionParseTree.java @@ -1,383 +1,383 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.text.ParseException; -import java.util.LinkedList; -import java.util.List; -/** - * Represents a parsed expression. - * - * @version $Revision: 303166 $ - * @author Paul Speed - */ -public class ExpressionParseTree { - /** - * Contains the current set of completed nodes. This is a workspace for the - * parser. - */ - private LinkedList nodeStack = new LinkedList(); - /** - * Contains operator nodes that don't yet have values. This is a workspace - * for the parser. - */ - private LinkedList oppStack = new LinkedList(); - /** - * The root node after the expression has been parsed. - */ - private Node root; - /** - * The SSIMediator to use when evaluating the expressions. - */ - private SSIMediator ssiMediator; - - - /** - * Creates a new parse tree for the specified expression. - */ - public ExpressionParseTree(String expr, SSIMediator ssiMediator) - throws ParseException { - this.ssiMediator = ssiMediator; - parseExpression(expr); - } - - - /** - * Evaluates the tree and returns true or false. The specified SSIMediator - * is used to resolve variable references. - */ - public boolean evaluateTree() { - return root.evaluate(); - } - - - /** - * Pushes a new operator onto the opp stack, resolving existing opps as - * needed. - */ - private void pushOpp(OppNode node) { - // If node is null then it's just a group marker - if (node == null) { - oppStack.add(0, node); - return; - } - while (true) { - if (oppStack.size() == 0) break; - OppNode top = (OppNode)oppStack.get(0); - // If the top is a spacer then don't pop - // anything - if (top == null) break; - // If the top node has a lower precedence then - // let it stay - if (top.getPrecedence() < node.getPrecedence()) break; - // Remove the top node - oppStack.remove(0); - // Let it fill its branches - top.popValues(nodeStack); - // Stick it on the resolved node stack - nodeStack.add(0, top); - } - // Add the new node to the opp stack - oppStack.add(0, node); - } - - - /** - * Resolves all pending opp nodes on the stack until the next group marker - * is reached. - */ - private void resolveGroup() { - OppNode top = null; - while ((top = (OppNode)oppStack.remove(0)) != null) { - // Let it fill its branches - top.popValues(nodeStack); - // Stick it on the resolved node stack - nodeStack.add(0, top); - } - } - - - /** - * Parses the specified expression into a tree of parse nodes. - */ - private void parseExpression(String expr) throws ParseException { - StringNode currStringNode = null; - // We cheat a little and start an artificial - // group right away. It makes finishing easier. - pushOpp(null); - ExpressionTokenizer et = new ExpressionTokenizer(expr); - while (et.hasMoreTokens()) { - int token = et.nextToken(); - if (token != ExpressionTokenizer.TOKEN_STRING) - currStringNode = null; - switch (token) { - case ExpressionTokenizer.TOKEN_STRING : - if (currStringNode == null) { - currStringNode = new StringNode(et.getTokenValue()); - nodeStack.add(0, currStringNode); - } else { - // Add to the existing - currStringNode.value.append(" "); - currStringNode.value.append(et.getTokenValue()); - } - break; - case ExpressionTokenizer.TOKEN_AND : - pushOpp(new AndNode()); - break; - case ExpressionTokenizer.TOKEN_OR : - pushOpp(new OrNode()); - break; - case ExpressionTokenizer.TOKEN_NOT : - pushOpp(new NotNode()); - break; - case ExpressionTokenizer.TOKEN_EQ : - pushOpp(new EqualNode()); - break; - case ExpressionTokenizer.TOKEN_NOT_EQ : - pushOpp(new NotNode()); - // Sneak the regular node in. The NOT will - // be resolved when the next opp comes along. - oppStack.add(0, new EqualNode()); - break; - case ExpressionTokenizer.TOKEN_RBRACE : - // Closeout the current group - resolveGroup(); - break; - case ExpressionTokenizer.TOKEN_LBRACE : - // Push a group marker - pushOpp(null); - break; - case ExpressionTokenizer.TOKEN_GE : - pushOpp(new NotNode()); - // Similar stategy to NOT_EQ above, except this - // is NOT less than - oppStack.add(0, new LessThanNode()); - break; - case ExpressionTokenizer.TOKEN_LE : - pushOpp(new NotNode()); - // Similar stategy to NOT_EQ above, except this - // is NOT greater than - oppStack.add(0, new GreaterThanNode()); - break; - case ExpressionTokenizer.TOKEN_GT : - pushOpp(new GreaterThanNode()); - break; - case ExpressionTokenizer.TOKEN_LT : - pushOpp(new LessThanNode()); - break; - case ExpressionTokenizer.TOKEN_END : - break; - } - } - // Finish off the rest of the opps - resolveGroup(); - if (nodeStack.size() == 0) { - throw new ParseException("No nodes created.", et.getIndex()); - } - if (nodeStack.size() > 1) { - throw new ParseException("Extra nodes created.", et.getIndex()); - } - if (oppStack.size() != 0) { - throw new ParseException("Unused opp nodes exist.", et.getIndex()); - } - root = (Node)nodeStack.get(0); - } - - /** - * A node in the expression parse tree. - */ - private abstract class Node { - /** - * Return true if the node evaluates to true. - */ - public abstract boolean evaluate(); - } - /** - * A node the represents a String value - */ - private class StringNode extends Node { - StringBuffer value; - String resolved = null; - - - public StringNode(String value) { - this.value = new StringBuffer(value); - } - - - /** - * Resolves any variable references and returns the value string. - */ - public String getValue() { - if (resolved == null) - resolved = ssiMediator.substituteVariables(value.toString()); - return resolved; - } - - - /** - * Returns true if the string is not empty. - */ - public boolean evaluate() { - return !(getValue().length() == 0); - } - - - public String toString() { - return value.toString(); - } - } - - private static final int PRECEDENCE_NOT = 5; - private static final int PRECEDENCE_COMPARE = 4; - private static final int PRECEDENCE_LOGICAL = 1; - - /** - * A node implementation that represents an operation. - */ - private abstract class OppNode extends Node { - /** - * The left branch. - */ - Node left; - /** - * The right branch. - */ - Node right; - - - /** - * Returns a preference level suitable for comparison to other OppNode - * preference levels. - */ - public abstract int getPrecedence(); - - - /** - * Lets the node pop its own branch nodes off the front of the - * specified list. The default pulls two. - */ - public void popValues(List values) { - right = (Node)values.remove(0); - left = (Node)values.remove(0); - } - } - private final class NotNode extends OppNode { - public boolean evaluate() { - return !left.evaluate(); - } - - - public int getPrecedence() { - return PRECEDENCE_NOT; - } - - - /** - * Overridden to pop only one value. - */ - public void popValues(List values) { - left = (Node)values.remove(0); - } - - - public String toString() { - return left + " NOT"; - } - } - private final class AndNode extends OppNode { - public boolean evaluate() { - if (!left.evaluate()) // Short circuit - return false; - return right.evaluate(); - } - - - public int getPrecedence() { - return PRECEDENCE_LOGICAL; - } - - - public String toString() { - return left + " " + right + " AND"; - } - } - private final class OrNode extends OppNode { - public boolean evaluate() { - if (left.evaluate()) // Short circuit - return true; - return right.evaluate(); - } - - - public int getPrecedence() { - return PRECEDENCE_LOGICAL; - } - - - public String toString() { - return left + " " + right + " OR"; - } - } - private abstract class CompareNode extends OppNode { - protected int compareBranches() { - String val1 = ((StringNode)left).getValue(); - String val2 = ((StringNode)right).getValue(); - return val1.compareTo(val2); - } - } - private final class EqualNode extends CompareNode { - public boolean evaluate() { - return (compareBranches() == 0); - } - - - public int getPrecedence() { - return PRECEDENCE_COMPARE; - } - - - public String toString() { - return left + " " + right + " EQ"; - } - } - private final class GreaterThanNode extends CompareNode { - public boolean evaluate() { - return (compareBranches() > 0); - } - - - public int getPrecedence() { - return PRECEDENCE_COMPARE; - } - - - public String toString() { - return left + " " + right + " GT"; - } - } - private final class LessThanNode extends CompareNode { - public boolean evaluate() { - return (compareBranches() < 0); - } - - - public int getPrecedence() { - return PRECEDENCE_COMPARE; - } - - - public String toString() { - return left + " " + right + " LT"; - } - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.text.ParseException; +import java.util.LinkedList; +import java.util.List; +/** + * Represents a parsed expression. + * + * @version $Revision: 303166 $ + * @author Paul Speed + */ +public class ExpressionParseTree { + /** + * Contains the current set of completed nodes. This is a workspace for the + * parser. + */ + private LinkedList nodeStack = new LinkedList(); + /** + * Contains operator nodes that don't yet have values. This is a workspace + * for the parser. + */ + private LinkedList oppStack = new LinkedList(); + /** + * The root node after the expression has been parsed. + */ + private Node root; + /** + * The SSIMediator to use when evaluating the expressions. + */ + private SSIMediator ssiMediator; + + + /** + * Creates a new parse tree for the specified expression. + */ + public ExpressionParseTree(String expr, SSIMediator ssiMediator) + throws ParseException { + this.ssiMediator = ssiMediator; + parseExpression(expr); + } + + + /** + * Evaluates the tree and returns true or false. The specified SSIMediator + * is used to resolve variable references. + */ + public boolean evaluateTree() { + return root.evaluate(); + } + + + /** + * Pushes a new operator onto the opp stack, resolving existing opps as + * needed. + */ + private void pushOpp(OppNode node) { + // If node is null then it's just a group marker + if (node == null) { + oppStack.add(0, node); + return; + } + while (true) { + if (oppStack.size() == 0) break; + OppNode top = (OppNode)oppStack.get(0); + // If the top is a spacer then don't pop + // anything + if (top == null) break; + // If the top node has a lower precedence then + // let it stay + if (top.getPrecedence() < node.getPrecedence()) break; + // Remove the top node + oppStack.remove(0); + // Let it fill its branches + top.popValues(nodeStack); + // Stick it on the resolved node stack + nodeStack.add(0, top); + } + // Add the new node to the opp stack + oppStack.add(0, node); + } + + + /** + * Resolves all pending opp nodes on the stack until the next group marker + * is reached. + */ + private void resolveGroup() { + OppNode top = null; + while ((top = (OppNode)oppStack.remove(0)) != null) { + // Let it fill its branches + top.popValues(nodeStack); + // Stick it on the resolved node stack + nodeStack.add(0, top); + } + } + + + /** + * Parses the specified expression into a tree of parse nodes. + */ + private void parseExpression(String expr) throws ParseException { + StringNode currStringNode = null; + // We cheat a little and start an artificial + // group right away. It makes finishing easier. + pushOpp(null); + ExpressionTokenizer et = new ExpressionTokenizer(expr); + while (et.hasMoreTokens()) { + int token = et.nextToken(); + if (token != ExpressionTokenizer.TOKEN_STRING) + currStringNode = null; + switch (token) { + case ExpressionTokenizer.TOKEN_STRING : + if (currStringNode == null) { + currStringNode = new StringNode(et.getTokenValue()); + nodeStack.add(0, currStringNode); + } else { + // Add to the existing + currStringNode.value.append(" "); + currStringNode.value.append(et.getTokenValue()); + } + break; + case ExpressionTokenizer.TOKEN_AND : + pushOpp(new AndNode()); + break; + case ExpressionTokenizer.TOKEN_OR : + pushOpp(new OrNode()); + break; + case ExpressionTokenizer.TOKEN_NOT : + pushOpp(new NotNode()); + break; + case ExpressionTokenizer.TOKEN_EQ : + pushOpp(new EqualNode()); + break; + case ExpressionTokenizer.TOKEN_NOT_EQ : + pushOpp(new NotNode()); + // Sneak the regular node in. The NOT will + // be resolved when the next opp comes along. + oppStack.add(0, new EqualNode()); + break; + case ExpressionTokenizer.TOKEN_RBRACE : + // Closeout the current group + resolveGroup(); + break; + case ExpressionTokenizer.TOKEN_LBRACE : + // Push a group marker + pushOpp(null); + break; + case ExpressionTokenizer.TOKEN_GE : + pushOpp(new NotNode()); + // Similar stategy to NOT_EQ above, except this + // is NOT less than + oppStack.add(0, new LessThanNode()); + break; + case ExpressionTokenizer.TOKEN_LE : + pushOpp(new NotNode()); + // Similar stategy to NOT_EQ above, except this + // is NOT greater than + oppStack.add(0, new GreaterThanNode()); + break; + case ExpressionTokenizer.TOKEN_GT : + pushOpp(new GreaterThanNode()); + break; + case ExpressionTokenizer.TOKEN_LT : + pushOpp(new LessThanNode()); + break; + case ExpressionTokenizer.TOKEN_END : + break; + } + } + // Finish off the rest of the opps + resolveGroup(); + if (nodeStack.size() == 0) { + throw new ParseException("No nodes created.", et.getIndex()); + } + if (nodeStack.size() > 1) { + throw new ParseException("Extra nodes created.", et.getIndex()); + } + if (oppStack.size() != 0) { + throw new ParseException("Unused opp nodes exist.", et.getIndex()); + } + root = (Node)nodeStack.get(0); + } + + /** + * A node in the expression parse tree. + */ + private abstract class Node { + /** + * Return true if the node evaluates to true. + */ + public abstract boolean evaluate(); + } + /** + * A node the represents a String value + */ + private class StringNode extends Node { + StringBuffer value; + String resolved = null; + + + public StringNode(String value) { + this.value = new StringBuffer(value); + } + + + /** + * Resolves any variable references and returns the value string. + */ + public String getValue() { + if (resolved == null) + resolved = ssiMediator.substituteVariables(value.toString()); + return resolved; + } + + + /** + * Returns true if the string is not empty. + */ + public boolean evaluate() { + return !(getValue().length() == 0); + } + + + public String toString() { + return value.toString(); + } + } + + private static final int PRECEDENCE_NOT = 5; + private static final int PRECEDENCE_COMPARE = 4; + private static final int PRECEDENCE_LOGICAL = 1; + + /** + * A node implementation that represents an operation. + */ + private abstract class OppNode extends Node { + /** + * The left branch. + */ + Node left; + /** + * The right branch. + */ + Node right; + + + /** + * Returns a preference level suitable for comparison to other OppNode + * preference levels. + */ + public abstract int getPrecedence(); + + + /** + * Lets the node pop its own branch nodes off the front of the + * specified list. The default pulls two. + */ + public void popValues(List values) { + right = (Node)values.remove(0); + left = (Node)values.remove(0); + } + } + private final class NotNode extends OppNode { + public boolean evaluate() { + return !left.evaluate(); + } + + + public int getPrecedence() { + return PRECEDENCE_NOT; + } + + + /** + * Overridden to pop only one value. + */ + public void popValues(List values) { + left = (Node)values.remove(0); + } + + + public String toString() { + return left + " NOT"; + } + } + private final class AndNode extends OppNode { + public boolean evaluate() { + if (!left.evaluate()) // Short circuit + return false; + return right.evaluate(); + } + + + public int getPrecedence() { + return PRECEDENCE_LOGICAL; + } + + + public String toString() { + return left + " " + right + " AND"; + } + } + private final class OrNode extends OppNode { + public boolean evaluate() { + if (left.evaluate()) // Short circuit + return true; + return right.evaluate(); + } + + + public int getPrecedence() { + return PRECEDENCE_LOGICAL; + } + + + public String toString() { + return left + " " + right + " OR"; + } + } + private abstract class CompareNode extends OppNode { + protected int compareBranches() { + String val1 = ((StringNode)left).getValue(); + String val2 = ((StringNode)right).getValue(); + return val1.compareTo(val2); + } + } + private final class EqualNode extends CompareNode { + public boolean evaluate() { + return (compareBranches() == 0); + } + + + public int getPrecedence() { + return PRECEDENCE_COMPARE; + } + + + public String toString() { + return left + " " + right + " EQ"; + } + } + private final class GreaterThanNode extends CompareNode { + public boolean evaluate() { + return (compareBranches() > 0); + } + + + public int getPrecedence() { + return PRECEDENCE_COMPARE; + } + + + public String toString() { + return left + " " + right + " GT"; + } + } + private final class LessThanNode extends CompareNode { + public boolean evaluate() { + return (compareBranches() < 0); + } + + + public int getPrecedence() { + return PRECEDENCE_COMPARE; + } + + + public String toString() { + return left + " " + right + " LT"; + } + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/ExpressionTokenizer.java b/java/org/apache/catalina/ssi/ExpressionTokenizer.java index d0314956d..9e006c3de 100644 --- a/java/org/apache/catalina/ssi/ExpressionTokenizer.java +++ b/java/org/apache/catalina/ssi/ExpressionTokenizer.java @@ -1,170 +1,170 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -/** - * Parses an expression string to return the individual tokens. This is - * patterned similar to the StreamTokenizer in the JDK but customized for SSI - * conditional expression parsing. - * - * @version $Revision: 304061 $ - * @author Paul Speed - */ -public class ExpressionTokenizer { - public static final int TOKEN_STRING = 0; - public static final int TOKEN_AND = 1; - public static final int TOKEN_OR = 2; - public static final int TOKEN_NOT = 3; - public static final int TOKEN_EQ = 4; - public static final int TOKEN_NOT_EQ = 5; - public static final int TOKEN_RBRACE = 6; - public static final int TOKEN_LBRACE = 7; - public static final int TOKEN_GE = 8; - public static final int TOKEN_LE = 9; - public static final int TOKEN_GT = 10; - public static final int TOKEN_LT = 11; - public static final int TOKEN_END = 12; - private char[] expr; - private String tokenVal = null; - private int index; - private int length; - - - /** - * Creates a new parser for the specified expression. - */ - public ExpressionTokenizer(String expr) { - this.expr = expr.trim().toCharArray(); - this.length = this.expr.length; - } - - - /** - * Returns true if there are more tokens. - */ - public boolean hasMoreTokens() { - return index < length; - } - - - /** - * Returns the current index for error reporting purposes. - */ - public int getIndex() { - return index; - } - - - protected boolean isMetaChar(char c) { - return Character.isWhitespace(c) || c == '(' || c == ')' || c == '!' - || c == '<' || c == '>' || c == '|' || c == '&' || c == '='; - } - - - /** - * Returns the next token type and initializes any state variables - * accordingly. - */ - public int nextToken() { - // Skip any leading white space - while (index < length && Character.isWhitespace(expr[index])) - index++; - // Clear the current token val - tokenVal = null; - if (index == length) return TOKEN_END; // End of string - int start = index; - char currentChar = expr[index]; - char nextChar = (char)0; - index++; - if (index < length) nextChar = expr[index]; - // Check for a known token start - switch (currentChar) { - case '(' : - return TOKEN_LBRACE; - case ')' : - return TOKEN_RBRACE; - case '=' : - return TOKEN_EQ; - case '!' : - if (nextChar == '=') { - index++; - return TOKEN_NOT_EQ; - } else { - return TOKEN_NOT; - } - case '|' : - if (nextChar == '|') { - index++; - return TOKEN_OR; - } - break; - case '&' : - if (nextChar == '&') { - index++; - return TOKEN_AND; - } - break; - case '>' : - if (nextChar == '=') { - index++; - return TOKEN_GE; // Greater than or equal - } else { - return TOKEN_GT; // Greater than - } - case '<' : - if (nextChar == '=') { - index++; - return TOKEN_LE; // Less than or equal - } else { - return TOKEN_LT; // Less than - } - default : - // Otherwise it's a string - break; - } - int end = index; - // If it's a quoted string then end is the next unescaped quote - if (currentChar == '"' || currentChar == '\'') { - char endChar = currentChar; - boolean escaped = false; - start++; - for (; index < length; index++) { - if (expr[index] == '\\' && !escaped) { - escaped = true; - continue; - } - if (expr[index] == endChar && !escaped) break; - escaped = false; - } - end = index; - index++; // Skip the end quote - } else { - // End is the next whitespace character - for (; index < length; index++) { - if (isMetaChar(expr[index])) break; - } - end = index; - } - // Extract the string from the array - this.tokenVal = new String(expr, start, end - start); - return TOKEN_STRING; - } - - - /** - * Returns the String value of the token if it was type TOKEN_STRING. - * Otherwise null is returned. - */ - public String getTokenValue() { - return tokenVal; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +/** + * Parses an expression string to return the individual tokens. This is + * patterned similar to the StreamTokenizer in the JDK but customized for SSI + * conditional expression parsing. + * + * @version $Revision: 304061 $ + * @author Paul Speed + */ +public class ExpressionTokenizer { + public static final int TOKEN_STRING = 0; + public static final int TOKEN_AND = 1; + public static final int TOKEN_OR = 2; + public static final int TOKEN_NOT = 3; + public static final int TOKEN_EQ = 4; + public static final int TOKEN_NOT_EQ = 5; + public static final int TOKEN_RBRACE = 6; + public static final int TOKEN_LBRACE = 7; + public static final int TOKEN_GE = 8; + public static final int TOKEN_LE = 9; + public static final int TOKEN_GT = 10; + public static final int TOKEN_LT = 11; + public static final int TOKEN_END = 12; + private char[] expr; + private String tokenVal = null; + private int index; + private int length; + + + /** + * Creates a new parser for the specified expression. + */ + public ExpressionTokenizer(String expr) { + this.expr = expr.trim().toCharArray(); + this.length = this.expr.length; + } + + + /** + * Returns true if there are more tokens. + */ + public boolean hasMoreTokens() { + return index < length; + } + + + /** + * Returns the current index for error reporting purposes. + */ + public int getIndex() { + return index; + } + + + protected boolean isMetaChar(char c) { + return Character.isWhitespace(c) || c == '(' || c == ')' || c == '!' + || c == '<' || c == '>' || c == '|' || c == '&' || c == '='; + } + + + /** + * Returns the next token type and initializes any state variables + * accordingly. + */ + public int nextToken() { + // Skip any leading white space + while (index < length && Character.isWhitespace(expr[index])) + index++; + // Clear the current token val + tokenVal = null; + if (index == length) return TOKEN_END; // End of string + int start = index; + char currentChar = expr[index]; + char nextChar = (char)0; + index++; + if (index < length) nextChar = expr[index]; + // Check for a known token start + switch (currentChar) { + case '(' : + return TOKEN_LBRACE; + case ')' : + return TOKEN_RBRACE; + case '=' : + return TOKEN_EQ; + case '!' : + if (nextChar == '=') { + index++; + return TOKEN_NOT_EQ; + } else { + return TOKEN_NOT; + } + case '|' : + if (nextChar == '|') { + index++; + return TOKEN_OR; + } + break; + case '&' : + if (nextChar == '&') { + index++; + return TOKEN_AND; + } + break; + case '>' : + if (nextChar == '=') { + index++; + return TOKEN_GE; // Greater than or equal + } else { + return TOKEN_GT; // Greater than + } + case '<' : + if (nextChar == '=') { + index++; + return TOKEN_LE; // Less than or equal + } else { + return TOKEN_LT; // Less than + } + default : + // Otherwise it's a string + break; + } + int end = index; + // If it's a quoted string then end is the next unescaped quote + if (currentChar == '"' || currentChar == '\'') { + char endChar = currentChar; + boolean escaped = false; + start++; + for (; index < length; index++) { + if (expr[index] == '\\' && !escaped) { + escaped = true; + continue; + } + if (expr[index] == endChar && !escaped) break; + escaped = false; + } + end = index; + index++; // Skip the end quote + } else { + // End is the next whitespace character + for (; index < length; index++) { + if (isMetaChar(expr[index])) break; + } + end = index; + } + // Extract the string from the array + this.tokenVal = new String(expr, start, end - start); + return TOKEN_STRING; + } + + + /** + * Returns the String value of the token if it was type TOKEN_STRING. + * Otherwise null is returned. + */ + public String getTokenValue() { + return tokenVal; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/ResponseIncludeWrapper.java b/java/org/apache/catalina/ssi/ResponseIncludeWrapper.java index 5e8d0b5ed..3c7b89faa 100644 --- a/java/org/apache/catalina/ssi/ResponseIncludeWrapper.java +++ b/java/org/apache/catalina/ssi/ResponseIncludeWrapper.java @@ -1,238 +1,238 @@ -/* - * Copyright 1999-2002,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.ssi; - -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; - -import javax.servlet.ServletContext; -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.apache.catalina.util.DateTool; -/** - * A HttpServletResponseWrapper, used from - * SSIServletExternalResolver - * - * @author Bip Thelin - * @author David Becker - * @version $Revision: 304032 $, $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - */ -public class ResponseIncludeWrapper extends HttpServletResponseWrapper { - /** - * The names of some headers we want to capture. - */ - private static final String CONTENT_TYPE = "content-type"; - private static final String LAST_MODIFIED = "last-modified"; - protected long lastModified = -1; - private String contentType = null; - - /** - * Our ServletOutputStream - */ - protected ServletOutputStream captureServletOutputStream; - protected ServletOutputStream servletOutputStream; - protected PrintWriter printWriter; - - private ServletContext context; - private HttpServletRequest request; - - - /** - * Initialize our wrapper with the current HttpServletResponse and - * ServletOutputStream. - * - * @param context The servlet context - * @param request The HttpServletResponse to use - * @param response The response to use - * @param captureServletOutputStream The ServletOutputStream to use - */ - public ResponseIncludeWrapper(ServletContext context, - HttpServletRequest request, HttpServletResponse response, - ServletOutputStream captureServletOutputStream) { - super(response); - this.context = context; - this.request = request; - this.captureServletOutputStream = captureServletOutputStream; - } - - - /** - * Flush the servletOutputStream or printWriter ( only one will be non-null ) - * This must be called after a requestDispatcher.include, since we can't - * assume that the included servlet flushed its stream. - */ - public void flushOutputStreamOrWriter() throws IOException { - if (servletOutputStream != null) { - servletOutputStream.flush(); - } - if (printWriter != null) { - printWriter.flush(); - } - } - - - /** - * Return a printwriter, throws and exception if a OutputStream already - * been returned. - * - * @return a PrintWriter object - * @exception java.io.IOException - * if the outputstream already been called - */ - public PrintWriter getWriter() throws java.io.IOException { - if (servletOutputStream == null) { - if (printWriter == null) { - setCharacterEncoding(getCharacterEncoding()); - printWriter = new PrintWriter( - new OutputStreamWriter(captureServletOutputStream, - getCharacterEncoding())); - } - return printWriter; - } - throw new IllegalStateException(); - } - - - /** - * Return a OutputStream, throws and exception if a printwriter already - * been returned. - * - * @return a OutputStream object - * @exception java.io.IOException - * if the printwriter already been called - */ - public ServletOutputStream getOutputStream() throws java.io.IOException { - if (printWriter == null) { - if (servletOutputStream == null) { - servletOutputStream = captureServletOutputStream; - } - return servletOutputStream; - } - throw new IllegalStateException(); - } - - - /** - * Returns the value of the last-modified header field. The - * result is the number of milliseconds since January 1, 1970 GMT. - * - * @return the date the resource referenced by this - * ResponseIncludeWrapper was last modified, or -1 if not - * known. - */ - public long getLastModified() { - if (lastModified == -1) { - // javadocs say to return -1 if date not known, if you want another - // default, put it here - return -1; - } - return lastModified; - } - - /** - * Sets the value of the last-modified header field. - * - * @param lastModified The number of milliseconds since January 1, 1970 GMT. - */ - public void setLastModified(long lastModified) { - this.lastModified = lastModified; - ((HttpServletResponse) getResponse()).setDateHeader(LAST_MODIFIED, - lastModified); - } - - /** - * Returns the value of the content-type header field. - * - * @return the content type of the resource referenced by this - * ResponseIncludeWrapper, or null if not known. - */ - public String getContentType() { - if (contentType == null) { - String url = request.getRequestURI(); - String mime = context.getMimeType(url); - if (mime != null) - { - setContentType(mime); - } - else - { - // return a safe value - setContentType("application/x-octet-stream"); - } - } - return contentType; - } - - /** - * Sets the value of the content-type header field. - * - * @param mime a mime type - */ - public void setContentType(String mime) { - contentType = mime; - if (contentType != null) { - getResponse().setContentType(contentType); - } - } - - - public void addDateHeader(String name, long value) { - super.addDateHeader(name, value); - String lname = name.toLowerCase(); - if (lname.equals(LAST_MODIFIED)) { - lastModified = value; - } - } - - public void addHeader(String name, String value) { - super.addHeader(name, value); - String lname = name.toLowerCase(); - if (lname.equals(LAST_MODIFIED)) { - try { - lastModified = DateTool.rfc1123Format.parse(value).getTime(); - } catch (Throwable ignore) { } - } else if (lname.equals(CONTENT_TYPE)) { - contentType = value; - } - } - - public void setDateHeader(String name, long value) { - super.setDateHeader(name, value); - String lname = name.toLowerCase(); - if (lname.equals(LAST_MODIFIED)) { - lastModified = value; - } - } - - public void setHeader(String name, String value) { - super.setHeader(name, value); - String lname = name.toLowerCase(); - if (lname.equals(LAST_MODIFIED)) { - try { - lastModified = DateTool.rfc1123Format.parse(value).getTime(); - } catch (Throwable ignore) { } - } - else if (lname.equals(CONTENT_TYPE)) - { - contentType = value; - } - } -} +/* + * Copyright 1999-2002,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.ssi; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; + +import javax.servlet.ServletContext; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; + +import org.apache.catalina.util.DateTool; +/** + * A HttpServletResponseWrapper, used from + * SSIServletExternalResolver + * + * @author Bip Thelin + * @author David Becker + * @version $Revision: 304032 $, $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + */ +public class ResponseIncludeWrapper extends HttpServletResponseWrapper { + /** + * The names of some headers we want to capture. + */ + private static final String CONTENT_TYPE = "content-type"; + private static final String LAST_MODIFIED = "last-modified"; + protected long lastModified = -1; + private String contentType = null; + + /** + * Our ServletOutputStream + */ + protected ServletOutputStream captureServletOutputStream; + protected ServletOutputStream servletOutputStream; + protected PrintWriter printWriter; + + private ServletContext context; + private HttpServletRequest request; + + + /** + * Initialize our wrapper with the current HttpServletResponse and + * ServletOutputStream. + * + * @param context The servlet context + * @param request The HttpServletResponse to use + * @param response The response to use + * @param captureServletOutputStream The ServletOutputStream to use + */ + public ResponseIncludeWrapper(ServletContext context, + HttpServletRequest request, HttpServletResponse response, + ServletOutputStream captureServletOutputStream) { + super(response); + this.context = context; + this.request = request; + this.captureServletOutputStream = captureServletOutputStream; + } + + + /** + * Flush the servletOutputStream or printWriter ( only one will be non-null ) + * This must be called after a requestDispatcher.include, since we can't + * assume that the included servlet flushed its stream. + */ + public void flushOutputStreamOrWriter() throws IOException { + if (servletOutputStream != null) { + servletOutputStream.flush(); + } + if (printWriter != null) { + printWriter.flush(); + } + } + + + /** + * Return a printwriter, throws and exception if a OutputStream already + * been returned. + * + * @return a PrintWriter object + * @exception java.io.IOException + * if the outputstream already been called + */ + public PrintWriter getWriter() throws java.io.IOException { + if (servletOutputStream == null) { + if (printWriter == null) { + setCharacterEncoding(getCharacterEncoding()); + printWriter = new PrintWriter( + new OutputStreamWriter(captureServletOutputStream, + getCharacterEncoding())); + } + return printWriter; + } + throw new IllegalStateException(); + } + + + /** + * Return a OutputStream, throws and exception if a printwriter already + * been returned. + * + * @return a OutputStream object + * @exception java.io.IOException + * if the printwriter already been called + */ + public ServletOutputStream getOutputStream() throws java.io.IOException { + if (printWriter == null) { + if (servletOutputStream == null) { + servletOutputStream = captureServletOutputStream; + } + return servletOutputStream; + } + throw new IllegalStateException(); + } + + + /** + * Returns the value of the last-modified header field. The + * result is the number of milliseconds since January 1, 1970 GMT. + * + * @return the date the resource referenced by this + * ResponseIncludeWrapper was last modified, or -1 if not + * known. + */ + public long getLastModified() { + if (lastModified == -1) { + // javadocs say to return -1 if date not known, if you want another + // default, put it here + return -1; + } + return lastModified; + } + + /** + * Sets the value of the last-modified header field. + * + * @param lastModified The number of milliseconds since January 1, 1970 GMT. + */ + public void setLastModified(long lastModified) { + this.lastModified = lastModified; + ((HttpServletResponse) getResponse()).setDateHeader(LAST_MODIFIED, + lastModified); + } + + /** + * Returns the value of the content-type header field. + * + * @return the content type of the resource referenced by this + * ResponseIncludeWrapper, or null if not known. + */ + public String getContentType() { + if (contentType == null) { + String url = request.getRequestURI(); + String mime = context.getMimeType(url); + if (mime != null) + { + setContentType(mime); + } + else + { + // return a safe value + setContentType("application/x-octet-stream"); + } + } + return contentType; + } + + /** + * Sets the value of the content-type header field. + * + * @param mime a mime type + */ + public void setContentType(String mime) { + contentType = mime; + if (contentType != null) { + getResponse().setContentType(contentType); + } + } + + + public void addDateHeader(String name, long value) { + super.addDateHeader(name, value); + String lname = name.toLowerCase(); + if (lname.equals(LAST_MODIFIED)) { + lastModified = value; + } + } + + public void addHeader(String name, String value) { + super.addHeader(name, value); + String lname = name.toLowerCase(); + if (lname.equals(LAST_MODIFIED)) { + try { + lastModified = DateTool.rfc1123Format.parse(value).getTime(); + } catch (Throwable ignore) { } + } else if (lname.equals(CONTENT_TYPE)) { + contentType = value; + } + } + + public void setDateHeader(String name, long value) { + super.setDateHeader(name, value); + String lname = name.toLowerCase(); + if (lname.equals(LAST_MODIFIED)) { + lastModified = value; + } + } + + public void setHeader(String name, String value) { + super.setHeader(name, value); + String lname = name.toLowerCase(); + if (lname.equals(LAST_MODIFIED)) { + try { + lastModified = DateTool.rfc1123Format.parse(value).getTime(); + } catch (Throwable ignore) { } + } + else if (lname.equals(CONTENT_TYPE)) + { + contentType = value; + } + } +} diff --git a/java/org/apache/catalina/ssi/SSICommand.java b/java/org/apache/catalina/ssi/SSICommand.java index d18ac968a..1b0557de6 100644 --- a/java/org/apache/catalina/ssi/SSICommand.java +++ b/java/org/apache/catalina/ssi/SSICommand.java @@ -1,45 +1,45 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -/** - * The interface that all SSI commands ( SSIEcho, SSIInclude, ...) must - * implement. - * - * @author Bip Thelin - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public interface SSICommand { - /** - * Write the output of the command to the writer. - * - * @param ssiMediator - * the ssi mediator - * @param commandName - * the name of the actual command ( ie. echo ) - * @param paramNames - * The parameter names - * @param paramValues - * The parameter values - * @param writer - * the writer to output to - * @return the most current modified date resulting from any SSI commands - * @throws SSIStopProcessingException - * if SSI processing should be aborted - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) - throws SSIStopProcessingException; +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +/** + * The interface that all SSI commands ( SSIEcho, SSIInclude, ...) must + * implement. + * + * @author Bip Thelin + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public interface SSICommand { + /** + * Write the output of the command to the writer. + * + * @param ssiMediator + * the ssi mediator + * @param commandName + * the name of the actual command ( ie. echo ) + * @param paramNames + * The parameter names + * @param paramValues + * The parameter values + * @param writer + * the writer to output to + * @return the most current modified date resulting from any SSI commands + * @throws SSIStopProcessingException + * if SSI processing should be aborted + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) + throws SSIStopProcessingException; } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIConditional.java b/java/org/apache/catalina/ssi/SSIConditional.java index 01fe77594..3febc7f71 100644 --- a/java/org/apache/catalina/ssi/SSIConditional.java +++ b/java/org/apache/catalina/ssi/SSIConditional.java @@ -1,133 +1,133 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -import java.text.ParseException; -/** - * SSI command that handles all conditional directives. - * - * @version $Revision: 303882 $ - * @author Paul Speed - * @author David Becker - */ -public class SSIConditional implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) - throws SSIStopProcessingException { - // Assume anything using conditionals was modified by it - long lastModified = System.currentTimeMillis(); - // Retrieve the current state information - SSIConditionalState state = ssiMediator.getConditionalState(); - if ("if".equalsIgnoreCase(commandName)) { - // Do nothing if we are nested in a false branch - // except count it - if (state.processConditionalCommandsOnly) { - state.nestingCount++; - return lastModified; - } - state.nestingCount = 0; - // Evaluate the expression - if (evaluateArguments(paramNames, paramValues, ssiMediator)) { - // No more branches can be taken for this if block - state.branchTaken = true; - } else { - // Do not process this branch - state.processConditionalCommandsOnly = true; - state.branchTaken = false; - } - } else if ("elif".equalsIgnoreCase(commandName)) { - // No need to even execute if we are nested in - // a false branch - if (state.nestingCount > 0) return lastModified; - // If a branch was already taken in this if block - // then disable output and return - if (state.branchTaken) { - state.processConditionalCommandsOnly = true; - return lastModified; - } - // Evaluate the expression - if (evaluateArguments(paramNames, paramValues, ssiMediator)) { - // Turn back on output and mark the branch - state.processConditionalCommandsOnly = false; - state.branchTaken = true; - } else { - // Do not process this branch - state.processConditionalCommandsOnly = true; - state.branchTaken = false; - } - } else if ("else".equalsIgnoreCase(commandName)) { - // No need to even execute if we are nested in - // a false branch - if (state.nestingCount > 0) return lastModified; - // If we've already taken another branch then - // disable output otherwise enable it. - state.processConditionalCommandsOnly = state.branchTaken; - // And in any case, it's safe to say a branch - // has been taken. - state.branchTaken = true; - } else if ("endif".equalsIgnoreCase(commandName)) { - // If we are nested inside a false branch then pop out - // one level on the nesting count - if (state.nestingCount > 0) { - state.nestingCount--; - return lastModified; - } - // Turn output back on - state.processConditionalCommandsOnly = false; - // Reset the branch status for any outer if blocks, - // since clearly we took a branch to have gotten here - // in the first place. - state.branchTaken = true; - } else { - throw new SSIStopProcessingException(); - //throw new SsiCommandException( "Not a conditional command:" + - // cmdName ); - } - return lastModified; - } - - - /** - * Retrieves the expression from the specified arguments and peforms the - * necessary evaluation steps. - */ - private boolean evaluateArguments(String[] names, String[] values, - SSIMediator ssiMediator) throws SSIStopProcessingException { - String expr = getExpression(names, values); - if (expr == null) { - throw new SSIStopProcessingException(); - //throw new SsiCommandException( "No expression specified." ); - } - try { - ExpressionParseTree tree = new ExpressionParseTree(expr, - ssiMediator); - return tree.evaluateTree(); - } catch (ParseException e) { - //throw new SsiCommandException( "Error parsing expression." ); - throw new SSIStopProcessingException(); - } - } - - - /** - * Returns the "expr" if the arg name is appropriate, otherwise returns - * null. - */ - private String getExpression(String[] paramNames, String[] paramValues) { - if ("expr".equalsIgnoreCase(paramNames[0])) return paramValues[0]; - return null; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +import java.text.ParseException; +/** + * SSI command that handles all conditional directives. + * + * @version $Revision: 303882 $ + * @author Paul Speed + * @author David Becker + */ +public class SSIConditional implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) + throws SSIStopProcessingException { + // Assume anything using conditionals was modified by it + long lastModified = System.currentTimeMillis(); + // Retrieve the current state information + SSIConditionalState state = ssiMediator.getConditionalState(); + if ("if".equalsIgnoreCase(commandName)) { + // Do nothing if we are nested in a false branch + // except count it + if (state.processConditionalCommandsOnly) { + state.nestingCount++; + return lastModified; + } + state.nestingCount = 0; + // Evaluate the expression + if (evaluateArguments(paramNames, paramValues, ssiMediator)) { + // No more branches can be taken for this if block + state.branchTaken = true; + } else { + // Do not process this branch + state.processConditionalCommandsOnly = true; + state.branchTaken = false; + } + } else if ("elif".equalsIgnoreCase(commandName)) { + // No need to even execute if we are nested in + // a false branch + if (state.nestingCount > 0) return lastModified; + // If a branch was already taken in this if block + // then disable output and return + if (state.branchTaken) { + state.processConditionalCommandsOnly = true; + return lastModified; + } + // Evaluate the expression + if (evaluateArguments(paramNames, paramValues, ssiMediator)) { + // Turn back on output and mark the branch + state.processConditionalCommandsOnly = false; + state.branchTaken = true; + } else { + // Do not process this branch + state.processConditionalCommandsOnly = true; + state.branchTaken = false; + } + } else if ("else".equalsIgnoreCase(commandName)) { + // No need to even execute if we are nested in + // a false branch + if (state.nestingCount > 0) return lastModified; + // If we've already taken another branch then + // disable output otherwise enable it. + state.processConditionalCommandsOnly = state.branchTaken; + // And in any case, it's safe to say a branch + // has been taken. + state.branchTaken = true; + } else if ("endif".equalsIgnoreCase(commandName)) { + // If we are nested inside a false branch then pop out + // one level on the nesting count + if (state.nestingCount > 0) { + state.nestingCount--; + return lastModified; + } + // Turn output back on + state.processConditionalCommandsOnly = false; + // Reset the branch status for any outer if blocks, + // since clearly we took a branch to have gotten here + // in the first place. + state.branchTaken = true; + } else { + throw new SSIStopProcessingException(); + //throw new SsiCommandException( "Not a conditional command:" + + // cmdName ); + } + return lastModified; + } + + + /** + * Retrieves the expression from the specified arguments and peforms the + * necessary evaluation steps. + */ + private boolean evaluateArguments(String[] names, String[] values, + SSIMediator ssiMediator) throws SSIStopProcessingException { + String expr = getExpression(names, values); + if (expr == null) { + throw new SSIStopProcessingException(); + //throw new SsiCommandException( "No expression specified." ); + } + try { + ExpressionParseTree tree = new ExpressionParseTree(expr, + ssiMediator); + return tree.evaluateTree(); + } catch (ParseException e) { + //throw new SsiCommandException( "Error parsing expression." ); + throw new SSIStopProcessingException(); + } + } + + + /** + * Returns the "expr" if the arg name is appropriate, otherwise returns + * null. + */ + private String getExpression(String[] paramNames, String[] paramValues) { + if ("expr".equalsIgnoreCase(paramNames[0])) return paramValues[0]; + return null; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIConditionalState.java b/java/org/apache/catalina/ssi/SSIConditionalState.java index 180ee809c..cb8df77ad 100644 --- a/java/org/apache/catalina/ssi/SSIConditionalState.java +++ b/java/org/apache/catalina/ssi/SSIConditionalState.java @@ -1,38 +1,38 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -/** - * This class is used by SSIMediator and SSIConditional to keep track of state - * information necessary to process the nested conditional commands ( if, elif, - * else, endif ). - * - * @version $Revision: 303166 $ - * @author Dan Sandberg - * @author Paul Speed - */ -class SSIConditionalState { - /** - * Set to true if the current conditional has already been completed, i.e.: - * a branch was taken. - */ - boolean branchTaken = false; - /** - * Counts the number of nested false branches. - */ - int nestingCount = 0; - /** - * Set to true if only conditional commands ( if, elif, else, endif ) - * should be processed. - */ - boolean processConditionalCommandsOnly = false; +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +/** + * This class is used by SSIMediator and SSIConditional to keep track of state + * information necessary to process the nested conditional commands ( if, elif, + * else, endif ). + * + * @version $Revision: 303166 $ + * @author Dan Sandberg + * @author Paul Speed + */ +class SSIConditionalState { + /** + * Set to true if the current conditional has already been completed, i.e.: + * a branch was taken. + */ + boolean branchTaken = false; + /** + * Counts the number of nested false branches. + */ + int nestingCount = 0; + /** + * Set to true if only conditional commands ( if, elif, else, endif ) + * should be processed. + */ + boolean processConditionalCommandsOnly = false; } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIConfig.java b/java/org/apache/catalina/ssi/SSIConfig.java index 19fb2801e..8205db092 100644 --- a/java/org/apache/catalina/ssi/SSIConfig.java +++ b/java/org/apache/catalina/ssi/SSIConfig.java @@ -1,53 +1,53 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -/** - * Implements the Server-side #exec command - * - * @author Bip Thelin - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public final class SSIConfig implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - String substitutedValue = ssiMediator - .substituteVariables(paramValue); - if (paramName.equalsIgnoreCase("errmsg")) { - ssiMediator.setConfigErrMsg(substitutedValue); - } else if (paramName.equalsIgnoreCase("sizefmt")) { - ssiMediator.setConfigSizeFmt(substitutedValue); - } else if (paramName.equalsIgnoreCase("timefmt")) { - ssiMediator.setConfigTimeFmt(substitutedValue); - } else { - ssiMediator.log("#config--Invalid attribute: " + paramName); - //We need to fetch this value each time, since it may change - // during the - // loop - String configErrMsg = ssiMediator.getConfigErrMsg(); - writer.write(configErrMsg); - } - } - // Setting config options doesn't really change the page - return 0; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +/** + * Implements the Server-side #exec command + * + * @author Bip Thelin + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public final class SSIConfig implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + String substitutedValue = ssiMediator + .substituteVariables(paramValue); + if (paramName.equalsIgnoreCase("errmsg")) { + ssiMediator.setConfigErrMsg(substitutedValue); + } else if (paramName.equalsIgnoreCase("sizefmt")) { + ssiMediator.setConfigSizeFmt(substitutedValue); + } else if (paramName.equalsIgnoreCase("timefmt")) { + ssiMediator.setConfigTimeFmt(substitutedValue); + } else { + ssiMediator.log("#config--Invalid attribute: " + paramName); + //We need to fetch this value each time, since it may change + // during the + // loop + String configErrMsg = ssiMediator.getConfigErrMsg(); + writer.write(configErrMsg); + } + } + // Setting config options doesn't really change the page + return 0; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIEcho.java b/java/org/apache/catalina/ssi/SSIEcho.java index bbf3c470f..605f98447 100644 --- a/java/org/apache/catalina/ssi/SSIEcho.java +++ b/java/org/apache/catalina/ssi/SSIEcho.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -/** - * Return the result associated with the supplied Server Variable. - * - * @author Bip Thelin - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIEcho implements SSICommand { - protected final static String DEFAULT_ENCODING = "entity"; - protected final static String MISSING_VARIABLE_VALUE = "(none)"; - - - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - String encoding = DEFAULT_ENCODING; - String errorMessage = ssiMediator.getConfigErrMsg(); - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - if (paramName.equalsIgnoreCase("var")) { - String variableValue = ssiMediator.getVariableValue( - paramValue, encoding); - if (variableValue == null) { - variableValue = MISSING_VARIABLE_VALUE; - } - writer.write(variableValue); - lastModified = System.currentTimeMillis(); - } else if (paramName.equalsIgnoreCase("encoding")) { - if (isValidEncoding(paramValue)) { - encoding = paramValue; - } else { - ssiMediator.log("#echo--Invalid encoding: " + paramValue); - writer.write(errorMessage); - } - } else { - ssiMediator.log("#echo--Invalid attribute: " + paramName); - writer.write(errorMessage); - } - } - return lastModified; - } - - - protected boolean isValidEncoding(String encoding) { - return encoding.equalsIgnoreCase("url") - || encoding.equalsIgnoreCase("entity") - || encoding.equalsIgnoreCase("none"); - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +/** + * Return the result associated with the supplied Server Variable. + * + * @author Bip Thelin + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIEcho implements SSICommand { + protected final static String DEFAULT_ENCODING = "entity"; + protected final static String MISSING_VARIABLE_VALUE = "(none)"; + + + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + String encoding = DEFAULT_ENCODING; + String errorMessage = ssiMediator.getConfigErrMsg(); + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + if (paramName.equalsIgnoreCase("var")) { + String variableValue = ssiMediator.getVariableValue( + paramValue, encoding); + if (variableValue == null) { + variableValue = MISSING_VARIABLE_VALUE; + } + writer.write(variableValue); + lastModified = System.currentTimeMillis(); + } else if (paramName.equalsIgnoreCase("encoding")) { + if (isValidEncoding(paramValue)) { + encoding = paramValue; + } else { + ssiMediator.log("#echo--Invalid encoding: " + paramValue); + writer.write(errorMessage); + } + } else { + ssiMediator.log("#echo--Invalid attribute: " + paramName); + writer.write(errorMessage); + } + } + return lastModified; + } + + + protected boolean isValidEncoding(String encoding) { + return encoding.equalsIgnoreCase("url") + || encoding.equalsIgnoreCase("entity") + || encoding.equalsIgnoreCase("none"); + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIExec.java b/java/org/apache/catalina/ssi/SSIExec.java index 7074659d1..c0c4f9cb4 100644 --- a/java/org/apache/catalina/ssi/SSIExec.java +++ b/java/org/apache/catalina/ssi/SSIExec.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import org.apache.catalina.util.IOTools; -/** - * Implements the Server-side #exec command - * - * @author Bip Thelin - * @author Amy Roh - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIExec implements SSICommand { - protected SSIInclude ssiInclude = new SSIInclude(); - protected final static int BUFFER_SIZE = 1024; - - - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - String configErrMsg = ssiMediator.getConfigErrMsg(); - String paramName = paramNames[0]; - String paramValue = paramValues[0]; - String substitutedValue = ssiMediator.substituteVariables(paramValue); - if (paramName.equalsIgnoreCase("cgi")) { - lastModified = ssiInclude.process(ssiMediator, "include", - new String[]{"virtual"}, new String[]{substitutedValue}, - writer); - } else if (paramName.equalsIgnoreCase("cmd")) { - boolean foundProgram = false; - try { - Runtime rt = Runtime.getRuntime(); - Process proc = rt.exec(substitutedValue); - foundProgram = true; - BufferedReader stdOutReader = new BufferedReader( - new InputStreamReader(proc.getInputStream())); - BufferedReader stdErrReader = new BufferedReader( - new InputStreamReader(proc.getErrorStream())); - char[] buf = new char[BUFFER_SIZE]; - IOTools.flow(stdErrReader, writer, buf); - IOTools.flow(stdOutReader, writer, buf); - proc.waitFor(); - lastModified = System.currentTimeMillis(); - } catch (InterruptedException e) { - ssiMediator.log("Couldn't exec file: " + substitutedValue, e); - writer.write(configErrMsg); - } catch (IOException e) { - if (!foundProgram) { - //apache doesn't output an error message if it can't find - // a program - } - ssiMediator.log("Couldn't exec file: " + substitutedValue, e); - } - } - return lastModified; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import org.apache.catalina.util.IOTools; +/** + * Implements the Server-side #exec command + * + * @author Bip Thelin + * @author Amy Roh + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIExec implements SSICommand { + protected SSIInclude ssiInclude = new SSIInclude(); + protected final static int BUFFER_SIZE = 1024; + + + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + String configErrMsg = ssiMediator.getConfigErrMsg(); + String paramName = paramNames[0]; + String paramValue = paramValues[0]; + String substitutedValue = ssiMediator.substituteVariables(paramValue); + if (paramName.equalsIgnoreCase("cgi")) { + lastModified = ssiInclude.process(ssiMediator, "include", + new String[]{"virtual"}, new String[]{substitutedValue}, + writer); + } else if (paramName.equalsIgnoreCase("cmd")) { + boolean foundProgram = false; + try { + Runtime rt = Runtime.getRuntime(); + Process proc = rt.exec(substitutedValue); + foundProgram = true; + BufferedReader stdOutReader = new BufferedReader( + new InputStreamReader(proc.getInputStream())); + BufferedReader stdErrReader = new BufferedReader( + new InputStreamReader(proc.getErrorStream())); + char[] buf = new char[BUFFER_SIZE]; + IOTools.flow(stdErrReader, writer, buf); + IOTools.flow(stdOutReader, writer, buf); + proc.waitFor(); + lastModified = System.currentTimeMillis(); + } catch (InterruptedException e) { + ssiMediator.log("Couldn't exec file: " + substitutedValue, e); + writer.write(configErrMsg); + } catch (IOException e) { + if (!foundProgram) { + //apache doesn't output an error message if it can't find + // a program + } + ssiMediator.log("Couldn't exec file: " + substitutedValue, e); + } + } + return lastModified; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIExternalResolver.java b/java/org/apache/catalina/ssi/SSIExternalResolver.java index 18ac13290..f944d39bc 100644 --- a/java/org/apache/catalina/ssi/SSIExternalResolver.java +++ b/java/org/apache/catalina/ssi/SSIExternalResolver.java @@ -1,71 +1,71 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.util.Collection; -import java.util.Date; -/** - * Interface used by SSIMediator to talk to the 'outside world' ( usually a - * servlet ) - * - * @author Dan Sandberg - * @version $Revision: 303166 $, $Date: 2004-09-01 20:33:33 +0200 (mer., 01 sept. 2004) $ - */ -public interface SSIExternalResolver { - /** - * Adds any external variables to the variableNames collection. - * - * @param variableNames - * the collection to add to - */ - public void addVariableNames(Collection variableNames); - - - public String getVariableValue(String name); - - - /** - * Set the named variable to the specified value. If value is null, then - * the variable will be removed ( ie. a call to getVariableValue will - * return null ) - * - * @param name - * of the variable - * @param value - * of the variable - */ - public void setVariableValue(String name, String value); - - - /** - * Returns the current date. This is useful for putting the SSI stuff in a - * regression test. Since you can make the current date a constant, it - * makes testing easier since the output won't change. - * - * @return the data - */ - public Date getCurrentDate(); - - - public long getFileSize(String path, boolean virtual) throws IOException; - - - public long getFileLastModified(String path, boolean virtual) - throws IOException; - - - public String getFileText(String path, boolean virtual) throws IOException; - - - public void log(String message, Throwable throwable); +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +/** + * Interface used by SSIMediator to talk to the 'outside world' ( usually a + * servlet ) + * + * @author Dan Sandberg + * @version $Revision: 303166 $, $Date: 2004-09-01 20:33:33 +0200 (mer., 01 sept. 2004) $ + */ +public interface SSIExternalResolver { + /** + * Adds any external variables to the variableNames collection. + * + * @param variableNames + * the collection to add to + */ + public void addVariableNames(Collection variableNames); + + + public String getVariableValue(String name); + + + /** + * Set the named variable to the specified value. If value is null, then + * the variable will be removed ( ie. a call to getVariableValue will + * return null ) + * + * @param name + * of the variable + * @param value + * of the variable + */ + public void setVariableValue(String name, String value); + + + /** + * Returns the current date. This is useful for putting the SSI stuff in a + * regression test. Since you can make the current date a constant, it + * makes testing easier since the output won't change. + * + * @return the data + */ + public Date getCurrentDate(); + + + public long getFileSize(String path, boolean virtual) throws IOException; + + + public long getFileLastModified(String path, boolean virtual) + throws IOException; + + + public String getFileText(String path, boolean virtual) throws IOException; + + + public void log(String message, Throwable throwable); } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIFilter.java b/java/org/apache/catalina/ssi/SSIFilter.java index dddad6c8e..c99ff5015 100644 --- a/java/org/apache/catalina/ssi/SSIFilter.java +++ b/java/org/apache/catalina/ssi/SSIFilter.java @@ -1,192 +1,192 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.Writer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Globals; -/** - * Filter to process SSI requests within a webpage. Mapped to a content types - * from within web.xml. - * - * @author David Becker - * @version $Revision: 303920 $, $Date: 2005-05-05 22:52:37 +0200 (jeu., 05 mai 2005) $ - * @see org.apache.catalina.ssi.SSIServlet - */ -public class SSIFilter implements Filter { - protected FilterConfig config = null; - /** Debug level for this servlet. */ - protected int debug = 0; - /** Expiration time in seconds for the doc. */ - protected Long expires = null; - /** virtual path can be webapp-relative */ - protected boolean isVirtualWebappRelative = false; - /** regex pattern to match when evaluating content types */ - protected Pattern contentTypeRegEx = null; - /** default pattern for ssi filter content type matching */ - protected Pattern shtmlRegEx = - Pattern.compile("text/x-server-parsed-html(;.*)?"); - - - //----------------- Public methods. - /** - * Initialize this servlet. - * - * @exception ServletException - * if an error occurs - */ - public void init(FilterConfig config) throws ServletException { - this.config = config; - - String value = null; - try { - value = config.getInitParameter("debug"); - debug = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - try { - value = config.getInitParameter("contentType"); - contentTypeRegEx = Pattern.compile(value); - } catch (Throwable t) { - contentTypeRegEx = shtmlRegEx; - StringBuffer msg = new StringBuffer(); - msg.append("Invalid format or no contentType initParam; "); - msg.append("expected regular expression; defaulting to "); - msg.append(shtmlRegEx.pattern()); - config.getServletContext().log(msg.toString()); - } - try { - value = config.getInitParameter( - "isVirtualWebappRelative"); - isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false; - } catch (Throwable t) { - ; - } - try { - value = config.getInitParameter("expires"); - expires = Long.valueOf(value); - } catch (NumberFormatException e) { - expires = null; - config.getServletContext().log( - "Invalid format for expires initParam; expected integer (seconds)" - ); - } catch (Throwable t) { - ; - } - if (debug > 0) - config.getServletContext().log( - "SSIFilter.init() SSI invoker started with 'debug'=" + debug); - } - - public void doFilter(ServletRequest request, ServletResponse response, - FilterChain chain) throws IOException, ServletException { - // cast once - HttpServletRequest req = (HttpServletRequest)request; - HttpServletResponse res = (HttpServletResponse)response; - - // indicate that we're in SSI processing - req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); - - // setup to capture output - ByteArrayServletOutputStream basos = new ByteArrayServletOutputStream(); - ResponseIncludeWrapper responseIncludeWrapper = - new ResponseIncludeWrapper(config.getServletContext(),req, res, basos); - - // process remainder of filter chain - chain.doFilter(req, responseIncludeWrapper); - - // we can't assume the chain flushed its output - responseIncludeWrapper.flushOutputStreamOrWriter(); - byte[] bytes = basos.toByteArray(); - - // get content type - String contentType = responseIncludeWrapper.getContentType(); - - // is this an allowed type for SSI processing? - if (contentTypeRegEx.matcher(contentType).matches()) { - String encoding = res.getCharacterEncoding(); - - // set up SSI processing - SSIExternalResolver ssiExternalResolver = - new SSIServletExternalResolver(config.getServletContext(), req, - res, isVirtualWebappRelative, debug, encoding); - SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, - debug); - - // prepare readers/writers - Reader reader = - new InputStreamReader(new ByteArrayInputStream(bytes), encoding); - ByteArrayOutputStream ssiout = new ByteArrayOutputStream(); - PrintWriter writer = - new PrintWriter(new OutputStreamWriter(ssiout, encoding)); - - // do SSI processing - long lastModified = ssiProcessor.process(reader, - responseIncludeWrapper.getLastModified(), writer); - - // set output bytes - writer.flush(); - bytes = ssiout.toByteArray(); - - // override headers - if (expires != null) { - res.setDateHeader("expires", (new java.util.Date()).getTime() - + expires.longValue() * 1000); - } - if (lastModified > 0) { - res.setDateHeader("last-modified", lastModified); - } - res.setContentLength(bytes.length); - - Matcher shtmlMatcher = - shtmlRegEx.matcher(responseIncludeWrapper.getContentType()); - if (shtmlMatcher.matches()) { - // Convert shtml mime type to ordinary html mime type but preserve - // encoding, if any. - String enc = shtmlMatcher.group(1); - res.setContentType("text/html" + ((enc != null) ? enc : "")); - } - } - - // write output - try { - OutputStream out = res.getOutputStream(); - out.write(bytes); - } catch (Throwable t) { - Writer out = res.getWriter(); - out.write(new String(bytes)); - } - } - - public void destroy() { - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Globals; +/** + * Filter to process SSI requests within a webpage. Mapped to a content types + * from within web.xml. + * + * @author David Becker + * @version $Revision: 303920 $, $Date: 2005-05-05 22:52:37 +0200 (jeu., 05 mai 2005) $ + * @see org.apache.catalina.ssi.SSIServlet + */ +public class SSIFilter implements Filter { + protected FilterConfig config = null; + /** Debug level for this servlet. */ + protected int debug = 0; + /** Expiration time in seconds for the doc. */ + protected Long expires = null; + /** virtual path can be webapp-relative */ + protected boolean isVirtualWebappRelative = false; + /** regex pattern to match when evaluating content types */ + protected Pattern contentTypeRegEx = null; + /** default pattern for ssi filter content type matching */ + protected Pattern shtmlRegEx = + Pattern.compile("text/x-server-parsed-html(;.*)?"); + + + //----------------- Public methods. + /** + * Initialize this servlet. + * + * @exception ServletException + * if an error occurs + */ + public void init(FilterConfig config) throws ServletException { + this.config = config; + + String value = null; + try { + value = config.getInitParameter("debug"); + debug = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + try { + value = config.getInitParameter("contentType"); + contentTypeRegEx = Pattern.compile(value); + } catch (Throwable t) { + contentTypeRegEx = shtmlRegEx; + StringBuffer msg = new StringBuffer(); + msg.append("Invalid format or no contentType initParam; "); + msg.append("expected regular expression; defaulting to "); + msg.append(shtmlRegEx.pattern()); + config.getServletContext().log(msg.toString()); + } + try { + value = config.getInitParameter( + "isVirtualWebappRelative"); + isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false; + } catch (Throwable t) { + ; + } + try { + value = config.getInitParameter("expires"); + expires = Long.valueOf(value); + } catch (NumberFormatException e) { + expires = null; + config.getServletContext().log( + "Invalid format for expires initParam; expected integer (seconds)" + ); + } catch (Throwable t) { + ; + } + if (debug > 0) + config.getServletContext().log( + "SSIFilter.init() SSI invoker started with 'debug'=" + debug); + } + + public void doFilter(ServletRequest request, ServletResponse response, + FilterChain chain) throws IOException, ServletException { + // cast once + HttpServletRequest req = (HttpServletRequest)request; + HttpServletResponse res = (HttpServletResponse)response; + + // indicate that we're in SSI processing + req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); + + // setup to capture output + ByteArrayServletOutputStream basos = new ByteArrayServletOutputStream(); + ResponseIncludeWrapper responseIncludeWrapper = + new ResponseIncludeWrapper(config.getServletContext(),req, res, basos); + + // process remainder of filter chain + chain.doFilter(req, responseIncludeWrapper); + + // we can't assume the chain flushed its output + responseIncludeWrapper.flushOutputStreamOrWriter(); + byte[] bytes = basos.toByteArray(); + + // get content type + String contentType = responseIncludeWrapper.getContentType(); + + // is this an allowed type for SSI processing? + if (contentTypeRegEx.matcher(contentType).matches()) { + String encoding = res.getCharacterEncoding(); + + // set up SSI processing + SSIExternalResolver ssiExternalResolver = + new SSIServletExternalResolver(config.getServletContext(), req, + res, isVirtualWebappRelative, debug, encoding); + SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, + debug); + + // prepare readers/writers + Reader reader = + new InputStreamReader(new ByteArrayInputStream(bytes), encoding); + ByteArrayOutputStream ssiout = new ByteArrayOutputStream(); + PrintWriter writer = + new PrintWriter(new OutputStreamWriter(ssiout, encoding)); + + // do SSI processing + long lastModified = ssiProcessor.process(reader, + responseIncludeWrapper.getLastModified(), writer); + + // set output bytes + writer.flush(); + bytes = ssiout.toByteArray(); + + // override headers + if (expires != null) { + res.setDateHeader("expires", (new java.util.Date()).getTime() + + expires.longValue() * 1000); + } + if (lastModified > 0) { + res.setDateHeader("last-modified", lastModified); + } + res.setContentLength(bytes.length); + + Matcher shtmlMatcher = + shtmlRegEx.matcher(responseIncludeWrapper.getContentType()); + if (shtmlMatcher.matches()) { + // Convert shtml mime type to ordinary html mime type but preserve + // encoding, if any. + String enc = shtmlMatcher.group(1); + res.setContentType("text/html" + ((enc != null) ? enc : "")); + } + } + + // write output + try { + OutputStream out = res.getOutputStream(); + out.write(bytes); + } catch (Throwable t) { + Writer out = res.getWriter(); + out.write(new String(bytes)); + } + } + + public void destroy() { + } +} diff --git a/java/org/apache/catalina/ssi/SSIFlastmod.java b/java/org/apache/catalina/ssi/SSIFlastmod.java index bd581db20..16ba362be 100644 --- a/java/org/apache/catalina/ssi/SSIFlastmod.java +++ b/java/org/apache/catalina/ssi/SSIFlastmod.java @@ -1,70 +1,70 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Date; -import org.apache.catalina.util.DateTool; -import org.apache.catalina.util.Strftime; -/** - * Implements the Server-side #flastmod command - * - * @author Bip Thelin - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 304061 $, $Date: 2005-08-17 23:21:37 +0200 (mer., 17 août 2005) $ - */ -public final class SSIFlastmod implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - String configErrMsg = ssiMediator.getConfigErrMsg(); - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - String substitutedValue = ssiMediator - .substituteVariables(paramValue); - try { - if (paramName.equalsIgnoreCase("file") - || paramName.equalsIgnoreCase("virtual")) { - boolean virtual = paramName.equalsIgnoreCase("virtual"); - lastModified = ssiMediator.getFileLastModified( - substitutedValue, virtual); - Date date = new Date(lastModified); - String configTimeFmt = ssiMediator.getConfigTimeFmt(); - writer.write(formatDate(date, configTimeFmt)); - } else { - ssiMediator.log("#flastmod--Invalid attribute: " - + paramName); - writer.write(configErrMsg); - } - } catch (IOException e) { - ssiMediator.log( - "#flastmod--Couldn't get last modified for file: " - + substitutedValue, e); - writer.write(configErrMsg); - } - } - return lastModified; - } - - - protected String formatDate(Date date, String configTimeFmt) { - Strftime strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US); - return strftime.format(date); - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import org.apache.catalina.util.DateTool; +import org.apache.catalina.util.Strftime; +/** + * Implements the Server-side #flastmod command + * + * @author Bip Thelin + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 304061 $, $Date: 2005-08-17 23:21:37 +0200 (mer., 17 août 2005) $ + */ +public final class SSIFlastmod implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + String configErrMsg = ssiMediator.getConfigErrMsg(); + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + String substitutedValue = ssiMediator + .substituteVariables(paramValue); + try { + if (paramName.equalsIgnoreCase("file") + || paramName.equalsIgnoreCase("virtual")) { + boolean virtual = paramName.equalsIgnoreCase("virtual"); + lastModified = ssiMediator.getFileLastModified( + substitutedValue, virtual); + Date date = new Date(lastModified); + String configTimeFmt = ssiMediator.getConfigTimeFmt(); + writer.write(formatDate(date, configTimeFmt)); + } else { + ssiMediator.log("#flastmod--Invalid attribute: " + + paramName); + writer.write(configErrMsg); + } + } catch (IOException e) { + ssiMediator.log( + "#flastmod--Couldn't get last modified for file: " + + substitutedValue, e); + writer.write(configErrMsg); + } + } + return lastModified; + } + + + protected String formatDate(Date date, String configTimeFmt) { + Strftime strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US); + return strftime.format(date); + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIFsize.java b/java/org/apache/catalina/ssi/SSIFsize.java index 388065501..157ed18a5 100644 --- a/java/org/apache/catalina/ssi/SSIFsize.java +++ b/java/org/apache/catalina/ssi/SSIFsize.java @@ -1,116 +1,116 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.io.PrintWriter; -import java.text.DecimalFormat; -/** - * Implements the Server-side #fsize command - * - * @author Bip Thelin - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public final class SSIFsize implements SSICommand { - protected final static int ONE_KILOBYTE = 1024; - protected final static int ONE_MEGABYTE = 1024 * 1024; - - - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - String configErrMsg = ssiMediator.getConfigErrMsg(); - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - String substitutedValue = ssiMediator - .substituteVariables(paramValue); - try { - if (paramName.equalsIgnoreCase("file") - || paramName.equalsIgnoreCase("virtual")) { - boolean virtual = paramName.equalsIgnoreCase("virtual"); - lastModified = ssiMediator.getFileLastModified( - substitutedValue, virtual); - long size = ssiMediator.getFileSize(substitutedValue, - virtual); - String configSizeFmt = ssiMediator.getConfigSizeFmt(); - writer.write(formatSize(size, configSizeFmt)); - } else { - ssiMediator.log("#fsize--Invalid attribute: " + paramName); - writer.write(configErrMsg); - } - } catch (IOException e) { - ssiMediator.log("#fsize--Couldn't get size for file: " - + substitutedValue, e); - writer.write(configErrMsg); - } - } - return lastModified; - } - - - public String repeat(char aChar, int numChars) { - if (numChars < 0) { - throw new IllegalArgumentException("Num chars can't be negative"); - } - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < numChars; i++) { - buf.append(aChar); - } - return buf.toString(); - } - - - public String padLeft(String str, int maxChars) { - String result = str; - int charsToAdd = maxChars - str.length(); - if (charsToAdd > 0) { - result = repeat(' ', charsToAdd) + str; - } - return result; - } - - - //We try to mimick Apache here, as we do everywhere - //All the 'magic' numbers are from the util_script.c Apache source file. - protected String formatSize(long size, String format) { - String retString = ""; - if (format.equalsIgnoreCase("bytes")) { - DecimalFormat decimalFormat = new DecimalFormat("#,##0"); - retString = decimalFormat.format(size); - } else { - if (size == 0) { - retString = "0k"; - } else if (size < ONE_KILOBYTE) { - retString = "1k"; - } else if (size < ONE_MEGABYTE) { - retString = Long.toString((size + 512) / ONE_KILOBYTE); - retString += "k"; - } else if (size < 99 * ONE_MEGABYTE) { - DecimalFormat decimalFormat = new DecimalFormat("0.0M"); - retString = decimalFormat.format(size / (double)ONE_MEGABYTE); - } else { - retString = Long.toString((size + (529 * ONE_KILOBYTE)) - / ONE_MEGABYTE); - retString += "M"; - } - retString = padLeft(retString, 5); - } - return retString; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.text.DecimalFormat; +/** + * Implements the Server-side #fsize command + * + * @author Bip Thelin + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public final class SSIFsize implements SSICommand { + protected final static int ONE_KILOBYTE = 1024; + protected final static int ONE_MEGABYTE = 1024 * 1024; + + + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + String configErrMsg = ssiMediator.getConfigErrMsg(); + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + String substitutedValue = ssiMediator + .substituteVariables(paramValue); + try { + if (paramName.equalsIgnoreCase("file") + || paramName.equalsIgnoreCase("virtual")) { + boolean virtual = paramName.equalsIgnoreCase("virtual"); + lastModified = ssiMediator.getFileLastModified( + substitutedValue, virtual); + long size = ssiMediator.getFileSize(substitutedValue, + virtual); + String configSizeFmt = ssiMediator.getConfigSizeFmt(); + writer.write(formatSize(size, configSizeFmt)); + } else { + ssiMediator.log("#fsize--Invalid attribute: " + paramName); + writer.write(configErrMsg); + } + } catch (IOException e) { + ssiMediator.log("#fsize--Couldn't get size for file: " + + substitutedValue, e); + writer.write(configErrMsg); + } + } + return lastModified; + } + + + public String repeat(char aChar, int numChars) { + if (numChars < 0) { + throw new IllegalArgumentException("Num chars can't be negative"); + } + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < numChars; i++) { + buf.append(aChar); + } + return buf.toString(); + } + + + public String padLeft(String str, int maxChars) { + String result = str; + int charsToAdd = maxChars - str.length(); + if (charsToAdd > 0) { + result = repeat(' ', charsToAdd) + str; + } + return result; + } + + + //We try to mimick Apache here, as we do everywhere + //All the 'magic' numbers are from the util_script.c Apache source file. + protected String formatSize(long size, String format) { + String retString = ""; + if (format.equalsIgnoreCase("bytes")) { + DecimalFormat decimalFormat = new DecimalFormat("#,##0"); + retString = decimalFormat.format(size); + } else { + if (size == 0) { + retString = "0k"; + } else if (size < ONE_KILOBYTE) { + retString = "1k"; + } else if (size < ONE_MEGABYTE) { + retString = Long.toString((size + 512) / ONE_KILOBYTE); + retString += "k"; + } else if (size < 99 * ONE_MEGABYTE) { + DecimalFormat decimalFormat = new DecimalFormat("0.0M"); + retString = decimalFormat.format(size / (double)ONE_MEGABYTE); + } else { + retString = Long.toString((size + (529 * ONE_KILOBYTE)) + / ONE_MEGABYTE); + retString += "M"; + } + retString = padLeft(retString, 5); + } + return retString; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIInclude.java b/java/org/apache/catalina/ssi/SSIInclude.java index 693fbc8c2..991be71a8 100644 --- a/java/org/apache/catalina/ssi/SSIInclude.java +++ b/java/org/apache/catalina/ssi/SSIInclude.java @@ -1,60 +1,60 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.io.PrintWriter; -/** - * Implements the Server-side #include command - * - * @author Bip Thelin - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public final class SSIInclude implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - String configErrMsg = ssiMediator.getConfigErrMsg(); - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - String substitutedValue = ssiMediator - .substituteVariables(paramValue); - try { - if (paramName.equalsIgnoreCase("file") - || paramName.equalsIgnoreCase("virtual")) { - boolean virtual = paramName.equalsIgnoreCase("virtual"); - lastModified = ssiMediator.getFileLastModified( - substitutedValue, virtual); - String text = ssiMediator.getFileText(substitutedValue, - virtual); - writer.write(text); - } else { - ssiMediator.log("#include--Invalid attribute: " - + paramName); - writer.write(configErrMsg); - } - } catch (IOException e) { - ssiMediator.log("#include--Couldn't include file: " - + substitutedValue, e); - writer.write(configErrMsg); - } - } - return lastModified; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.io.PrintWriter; +/** + * Implements the Server-side #include command + * + * @author Bip Thelin + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public final class SSIInclude implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + String configErrMsg = ssiMediator.getConfigErrMsg(); + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + String substitutedValue = ssiMediator + .substituteVariables(paramValue); + try { + if (paramName.equalsIgnoreCase("file") + || paramName.equalsIgnoreCase("virtual")) { + boolean virtual = paramName.equalsIgnoreCase("virtual"); + lastModified = ssiMediator.getFileLastModified( + substitutedValue, virtual); + String text = ssiMediator.getFileText(substitutedValue, + virtual); + writer.write(text); + } else { + ssiMediator.log("#include--Invalid attribute: " + + paramName); + writer.write(configErrMsg); + } + } catch (IOException e) { + ssiMediator.log("#include--Couldn't include file: " + + substitutedValue, e); + writer.write(configErrMsg); + } + } + return lastModified; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIMediator.java b/java/org/apache/catalina/ssi/SSIMediator.java index 679e43caa..e585e4f66 100644 --- a/java/org/apache/catalina/ssi/SSIMediator.java +++ b/java/org/apache/catalina/ssi/SSIMediator.java @@ -1,325 +1,325 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.util.Collection; -import java.util.Date; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.TimeZone; -import org.apache.catalina.util.DateTool; -import org.apache.catalina.util.Strftime; -import org.apache.catalina.util.URLEncoder; -/** - * Allows the different SSICommand implementations to share data/talk to each - * other - * - * @author Bip Thelin - * @author Amy Roh - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIMediator { - protected final static String DEFAULT_CONFIG_ERR_MSG = "[an error occurred while processing this directive]"; - protected final static String DEFAULT_CONFIG_TIME_FMT = "%A, %d-%b-%Y %T %Z"; - protected final static String DEFAULT_CONFIG_SIZE_FMT = "abbrev"; - protected static URLEncoder urlEncoder; - protected String configErrMsg = DEFAULT_CONFIG_ERR_MSG; - protected String configTimeFmt = DEFAULT_CONFIG_TIME_FMT; - protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT; - protected String className = getClass().getName(); - protected SSIExternalResolver ssiExternalResolver; - protected long lastModifiedDate; - protected int debug; - protected Strftime strftime; - protected SSIConditionalState conditionalState = new SSIConditionalState(); - static { - //We try to encode only the same characters that apache does - urlEncoder = new URLEncoder(); - urlEncoder.addSafeCharacter(','); - urlEncoder.addSafeCharacter(':'); - urlEncoder.addSafeCharacter('-'); - urlEncoder.addSafeCharacter('_'); - urlEncoder.addSafeCharacter('.'); - urlEncoder.addSafeCharacter('*'); - urlEncoder.addSafeCharacter('/'); - urlEncoder.addSafeCharacter('!'); - urlEncoder.addSafeCharacter('~'); - urlEncoder.addSafeCharacter('\''); - urlEncoder.addSafeCharacter('('); - urlEncoder.addSafeCharacter(')'); - } - - - public SSIMediator(SSIExternalResolver ssiExternalResolver, - long lastModifiedDate, int debug) { - this.ssiExternalResolver = ssiExternalResolver; - this.lastModifiedDate = lastModifiedDate; - this.debug = debug; - setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true); - } - - - public void setConfigErrMsg(String configErrMsg) { - this.configErrMsg = configErrMsg; - } - - - public void setConfigTimeFmt(String configTimeFmt) { - setConfigTimeFmt(configTimeFmt, false); - } - - - public void setConfigTimeFmt(String configTimeFmt, boolean fromConstructor) { - this.configTimeFmt = configTimeFmt; - //What's the story here with DateTool.LOCALE_US?? Why?? - this.strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US); - //Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be - // updated when - //the timefmt changes. This is what Apache SSI does. - setDateVariables(fromConstructor); - } - - - public void setConfigSizeFmt(String configSizeFmt) { - this.configSizeFmt = configSizeFmt; - } - - - public String getConfigErrMsg() { - return configErrMsg; - } - - - public String getConfigTimeFmt() { - return configTimeFmt; - } - - - public String getConfigSizeFmt() { - return configSizeFmt; - } - - - public SSIConditionalState getConditionalState() { - return conditionalState; - } - - - public Collection getVariableNames() { - Set variableNames = new HashSet(); - //These built-in variables are supplied by the mediator ( if not - // over-written by - // the user ) and always exist - variableNames.add("DATE_GMT"); - variableNames.add("DATE_LOCAL"); - variableNames.add("LAST_MODIFIED"); - ssiExternalResolver.addVariableNames(variableNames); - //Remove any variables that are reserved by this class - Iterator iter = variableNames.iterator(); - while (iter.hasNext()) { - String name = (String)iter.next(); - if (isNameReserved(name)) { - iter.remove(); - } - } - return variableNames; - } - - - public long getFileSize(String path, boolean virtual) throws IOException { - return ssiExternalResolver.getFileSize(path, virtual); - } - - - public long getFileLastModified(String path, boolean virtual) - throws IOException { - return ssiExternalResolver.getFileLastModified(path, virtual); - } - - - public String getFileText(String path, boolean virtual) throws IOException { - return ssiExternalResolver.getFileText(path, virtual); - } - - - protected boolean isNameReserved(String name) { - return name.startsWith(className + "."); - } - - - public String getVariableValue(String variableName) { - return getVariableValue(variableName, "none"); - } - - - public void setVariableValue(String variableName, String variableValue) { - if (!isNameReserved(variableName)) { - ssiExternalResolver.setVariableValue(variableName, variableValue); - } - } - - - public String getVariableValue(String variableName, String encoding) { - String lowerCaseVariableName = variableName.toLowerCase(); - String variableValue = null; - if (!isNameReserved(lowerCaseVariableName)) { - //Try getting it externally first, if it fails, try getting the - // 'built-in' - // value - variableValue = ssiExternalResolver.getVariableValue(variableName); - if (variableValue == null) { - variableName = variableName.toUpperCase(); - variableValue = (String)ssiExternalResolver - .getVariableValue(className + "." + variableName); - } - if (variableValue != null) { - variableValue = encode(variableValue, encoding); - } - } - return variableValue; - } - - - /** - * Applies variable substitution to the specified String and returns the - * new resolved string. - */ - public String substituteVariables(String val) { - // If it has no variable references then no work - // need to be done - if (val.indexOf('$') < 0) return val; - StringBuffer sb = new StringBuffer(val); - for (int i = 0; i < sb.length();) { - // Find the next $ - for (; i < sb.length(); i++) { - if (sb.charAt(i) == '$') { - i++; - break; - } - } - if (i == sb.length()) break; - // Check to see if the $ is escaped - if (i > 1 && sb.charAt(i - 2) == '\\') { - sb.deleteCharAt(i - 2); - i--; - continue; - } - int nameStart = i; - int start = i - 1; - int end = -1; - int nameEnd = -1; - char endChar = ' '; - // Check for {} wrapped var - if (sb.charAt(i) == '{') { - nameStart++; - endChar = '}'; - } - // Find the end of the var reference - for (; i < sb.length(); i++) { - if (sb.charAt(i) == endChar) break; - } - end = i; - nameEnd = end; - if (endChar == '}') end++; - // We should now have enough to extract the var name - String varName = sb.substring(nameStart, nameEnd); - String value = getVariableValue(varName); - if (value == null) value = ""; - // Replace the var name with its value - sb.replace(start, end, value); - // Start searching for the next $ after the value - // that was just substituted. - i = start + value.length(); - } - return sb.toString(); - } - - - protected String formatDate(Date date, TimeZone timeZone) { - String retVal; - if (timeZone != null) { - //we temporarily change strftime. Since SSIMediator is inherently - // single-threaded, this - //isn't a problem - TimeZone oldTimeZone = strftime.getTimeZone(); - strftime.setTimeZone(timeZone); - retVal = strftime.format(date); - strftime.setTimeZone(oldTimeZone); - } else { - retVal = strftime.format(date); - } - return retVal; - } - - - protected String encode(String value, String encoding) { - String retVal = null; - if (encoding.equalsIgnoreCase("url")) { - retVal = urlEncoder.encode(value); - } else if (encoding.equalsIgnoreCase("none")) { - retVal = value; - } else if (encoding.equalsIgnoreCase("entity")) { - //Not sure how this is really different than none - retVal = value; - } else { - //This shouldn't be possible - throw new IllegalArgumentException("Unknown encoding: " + encoding); - } - return retVal; - } - - - public void log(String message) { - ssiExternalResolver.log(message, null); - } - - - public void log(String message, Throwable throwable) { - ssiExternalResolver.log(message, throwable); - } - - - protected void setDateVariables(boolean fromConstructor) { - boolean alreadySet = ssiExternalResolver.getVariableValue(className - + ".alreadyset") != null; - //skip this if we are being called from the constructor, and this has - // already - // been set - if (!(fromConstructor && alreadySet)) { - ssiExternalResolver.setVariableValue(className + ".alreadyset", - "true"); - Date date = new Date(); - TimeZone timeZone = TimeZone.getTimeZone("GMT"); - String retVal = formatDate(date, timeZone); - //If we are setting on of the date variables, we want to remove - // them from the - // user - //defined list of variables, because this is what Apache does - setVariableValue("DATE_GMT", null); - ssiExternalResolver.setVariableValue(className + ".DATE_GMT", - retVal); - retVal = formatDate(date, null); - setVariableValue("DATE_LOCAL", null); - ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL", - retVal); - retVal = formatDate(new Date(lastModifiedDate), null); - setVariableValue("LAST_MODIFIED", null); - ssiExternalResolver.setVariableValue(className + ".LAST_MODIFIED", - retVal); - } - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.util.Collection; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.TimeZone; +import org.apache.catalina.util.DateTool; +import org.apache.catalina.util.Strftime; +import org.apache.catalina.util.URLEncoder; +/** + * Allows the different SSICommand implementations to share data/talk to each + * other + * + * @author Bip Thelin + * @author Amy Roh + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIMediator { + protected final static String DEFAULT_CONFIG_ERR_MSG = "[an error occurred while processing this directive]"; + protected final static String DEFAULT_CONFIG_TIME_FMT = "%A, %d-%b-%Y %T %Z"; + protected final static String DEFAULT_CONFIG_SIZE_FMT = "abbrev"; + protected static URLEncoder urlEncoder; + protected String configErrMsg = DEFAULT_CONFIG_ERR_MSG; + protected String configTimeFmt = DEFAULT_CONFIG_TIME_FMT; + protected String configSizeFmt = DEFAULT_CONFIG_SIZE_FMT; + protected String className = getClass().getName(); + protected SSIExternalResolver ssiExternalResolver; + protected long lastModifiedDate; + protected int debug; + protected Strftime strftime; + protected SSIConditionalState conditionalState = new SSIConditionalState(); + static { + //We try to encode only the same characters that apache does + urlEncoder = new URLEncoder(); + urlEncoder.addSafeCharacter(','); + urlEncoder.addSafeCharacter(':'); + urlEncoder.addSafeCharacter('-'); + urlEncoder.addSafeCharacter('_'); + urlEncoder.addSafeCharacter('.'); + urlEncoder.addSafeCharacter('*'); + urlEncoder.addSafeCharacter('/'); + urlEncoder.addSafeCharacter('!'); + urlEncoder.addSafeCharacter('~'); + urlEncoder.addSafeCharacter('\''); + urlEncoder.addSafeCharacter('('); + urlEncoder.addSafeCharacter(')'); + } + + + public SSIMediator(SSIExternalResolver ssiExternalResolver, + long lastModifiedDate, int debug) { + this.ssiExternalResolver = ssiExternalResolver; + this.lastModifiedDate = lastModifiedDate; + this.debug = debug; + setConfigTimeFmt(DEFAULT_CONFIG_TIME_FMT, true); + } + + + public void setConfigErrMsg(String configErrMsg) { + this.configErrMsg = configErrMsg; + } + + + public void setConfigTimeFmt(String configTimeFmt) { + setConfigTimeFmt(configTimeFmt, false); + } + + + public void setConfigTimeFmt(String configTimeFmt, boolean fromConstructor) { + this.configTimeFmt = configTimeFmt; + //What's the story here with DateTool.LOCALE_US?? Why?? + this.strftime = new Strftime(configTimeFmt, DateTool.LOCALE_US); + //Variables like DATE_LOCAL, DATE_GMT, and LAST_MODIFIED need to be + // updated when + //the timefmt changes. This is what Apache SSI does. + setDateVariables(fromConstructor); + } + + + public void setConfigSizeFmt(String configSizeFmt) { + this.configSizeFmt = configSizeFmt; + } + + + public String getConfigErrMsg() { + return configErrMsg; + } + + + public String getConfigTimeFmt() { + return configTimeFmt; + } + + + public String getConfigSizeFmt() { + return configSizeFmt; + } + + + public SSIConditionalState getConditionalState() { + return conditionalState; + } + + + public Collection getVariableNames() { + Set variableNames = new HashSet(); + //These built-in variables are supplied by the mediator ( if not + // over-written by + // the user ) and always exist + variableNames.add("DATE_GMT"); + variableNames.add("DATE_LOCAL"); + variableNames.add("LAST_MODIFIED"); + ssiExternalResolver.addVariableNames(variableNames); + //Remove any variables that are reserved by this class + Iterator iter = variableNames.iterator(); + while (iter.hasNext()) { + String name = (String)iter.next(); + if (isNameReserved(name)) { + iter.remove(); + } + } + return variableNames; + } + + + public long getFileSize(String path, boolean virtual) throws IOException { + return ssiExternalResolver.getFileSize(path, virtual); + } + + + public long getFileLastModified(String path, boolean virtual) + throws IOException { + return ssiExternalResolver.getFileLastModified(path, virtual); + } + + + public String getFileText(String path, boolean virtual) throws IOException { + return ssiExternalResolver.getFileText(path, virtual); + } + + + protected boolean isNameReserved(String name) { + return name.startsWith(className + "."); + } + + + public String getVariableValue(String variableName) { + return getVariableValue(variableName, "none"); + } + + + public void setVariableValue(String variableName, String variableValue) { + if (!isNameReserved(variableName)) { + ssiExternalResolver.setVariableValue(variableName, variableValue); + } + } + + + public String getVariableValue(String variableName, String encoding) { + String lowerCaseVariableName = variableName.toLowerCase(); + String variableValue = null; + if (!isNameReserved(lowerCaseVariableName)) { + //Try getting it externally first, if it fails, try getting the + // 'built-in' + // value + variableValue = ssiExternalResolver.getVariableValue(variableName); + if (variableValue == null) { + variableName = variableName.toUpperCase(); + variableValue = (String)ssiExternalResolver + .getVariableValue(className + "." + variableName); + } + if (variableValue != null) { + variableValue = encode(variableValue, encoding); + } + } + return variableValue; + } + + + /** + * Applies variable substitution to the specified String and returns the + * new resolved string. + */ + public String substituteVariables(String val) { + // If it has no variable references then no work + // need to be done + if (val.indexOf('$') < 0) return val; + StringBuffer sb = new StringBuffer(val); + for (int i = 0; i < sb.length();) { + // Find the next $ + for (; i < sb.length(); i++) { + if (sb.charAt(i) == '$') { + i++; + break; + } + } + if (i == sb.length()) break; + // Check to see if the $ is escaped + if (i > 1 && sb.charAt(i - 2) == '\\') { + sb.deleteCharAt(i - 2); + i--; + continue; + } + int nameStart = i; + int start = i - 1; + int end = -1; + int nameEnd = -1; + char endChar = ' '; + // Check for {} wrapped var + if (sb.charAt(i) == '{') { + nameStart++; + endChar = '}'; + } + // Find the end of the var reference + for (; i < sb.length(); i++) { + if (sb.charAt(i) == endChar) break; + } + end = i; + nameEnd = end; + if (endChar == '}') end++; + // We should now have enough to extract the var name + String varName = sb.substring(nameStart, nameEnd); + String value = getVariableValue(varName); + if (value == null) value = ""; + // Replace the var name with its value + sb.replace(start, end, value); + // Start searching for the next $ after the value + // that was just substituted. + i = start + value.length(); + } + return sb.toString(); + } + + + protected String formatDate(Date date, TimeZone timeZone) { + String retVal; + if (timeZone != null) { + //we temporarily change strftime. Since SSIMediator is inherently + // single-threaded, this + //isn't a problem + TimeZone oldTimeZone = strftime.getTimeZone(); + strftime.setTimeZone(timeZone); + retVal = strftime.format(date); + strftime.setTimeZone(oldTimeZone); + } else { + retVal = strftime.format(date); + } + return retVal; + } + + + protected String encode(String value, String encoding) { + String retVal = null; + if (encoding.equalsIgnoreCase("url")) { + retVal = urlEncoder.encode(value); + } else if (encoding.equalsIgnoreCase("none")) { + retVal = value; + } else if (encoding.equalsIgnoreCase("entity")) { + //Not sure how this is really different than none + retVal = value; + } else { + //This shouldn't be possible + throw new IllegalArgumentException("Unknown encoding: " + encoding); + } + return retVal; + } + + + public void log(String message) { + ssiExternalResolver.log(message, null); + } + + + public void log(String message, Throwable throwable) { + ssiExternalResolver.log(message, throwable); + } + + + protected void setDateVariables(boolean fromConstructor) { + boolean alreadySet = ssiExternalResolver.getVariableValue(className + + ".alreadyset") != null; + //skip this if we are being called from the constructor, and this has + // already + // been set + if (!(fromConstructor && alreadySet)) { + ssiExternalResolver.setVariableValue(className + ".alreadyset", + "true"); + Date date = new Date(); + TimeZone timeZone = TimeZone.getTimeZone("GMT"); + String retVal = formatDate(date, timeZone); + //If we are setting on of the date variables, we want to remove + // them from the + // user + //defined list of variables, because this is what Apache does + setVariableValue("DATE_GMT", null); + ssiExternalResolver.setVariableValue(className + ".DATE_GMT", + retVal); + retVal = formatDate(date, null); + setVariableValue("DATE_LOCAL", null); + ssiExternalResolver.setVariableValue(className + ".DATE_LOCAL", + retVal); + retVal = formatDate(new Date(lastModifiedDate), null); + setVariableValue("LAST_MODIFIED", null); + ssiExternalResolver.setVariableValue(className + ".LAST_MODIFIED", + retVal); + } + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIPrintenv.java b/java/org/apache/catalina/ssi/SSIPrintenv.java index eaf62cd47..68b7b5c87 100644 --- a/java/org/apache/catalina/ssi/SSIPrintenv.java +++ b/java/org/apache/catalina/ssi/SSIPrintenv.java @@ -1,56 +1,56 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -import java.util.Collection; -import java.util.Iterator; -/** - * Implements the Server-side #printenv command - * - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIPrintenv implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) { - long lastModified = 0; - //any arguments should produce an error - if (paramNames.length > 0) { - String errorMessage = ssiMediator.getConfigErrMsg(); - writer.write(errorMessage); - } else { - Collection variableNames = ssiMediator.getVariableNames(); - Iterator iter = variableNames.iterator(); - while (iter.hasNext()) { - String variableName = (String)iter.next(); - String variableValue = ssiMediator - .getVariableValue(variableName); - //This shouldn't happen, since all the variable names must - // have values - if (variableValue == null) { - variableValue = "(none)"; - } - writer.write(variableName); - writer.write('='); - writer.write(variableValue); - writer.write('\n'); - lastModified = System.currentTimeMillis(); - } - } - return lastModified; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +import java.util.Collection; +import java.util.Iterator; +/** + * Implements the Server-side #printenv command + * + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIPrintenv implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) { + long lastModified = 0; + //any arguments should produce an error + if (paramNames.length > 0) { + String errorMessage = ssiMediator.getConfigErrMsg(); + writer.write(errorMessage); + } else { + Collection variableNames = ssiMediator.getVariableNames(); + Iterator iter = variableNames.iterator(); + while (iter.hasNext()) { + String variableName = (String)iter.next(); + String variableValue = ssiMediator + .getVariableValue(variableName); + //This shouldn't happen, since all the variable names must + // have values + if (variableValue == null) { + variableValue = "(none)"; + } + writer.write(variableName); + writer.write('='); + writer.write(variableValue); + writer.write('\n'); + lastModified = System.currentTimeMillis(); + } + } + return lastModified; + } +} diff --git a/java/org/apache/catalina/ssi/SSIProcessor.java b/java/org/apache/catalina/ssi/SSIProcessor.java index 7fcfd4fee..9d7cd040d 100644 --- a/java/org/apache/catalina/ssi/SSIProcessor.java +++ b/java/org/apache/catalina/ssi/SSIProcessor.java @@ -1,313 +1,313 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Reader; -import java.io.StringWriter; -import java.util.HashMap; -import java.util.StringTokenizer; -import org.apache.catalina.util.IOTools; -/** - * The entry point to SSI processing. This class does the actual parsing, - * delegating to the SSIMediator, SSICommand, and SSIExternalResolver as - * necessary[ - * - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIProcessor { - /** The start pattern */ - protected final static String COMMAND_START = ""; - protected final static int BUFFER_SIZE = 4096; - protected SSIExternalResolver ssiExternalResolver; - protected HashMap commands = new HashMap(); - protected int debug; - - - public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug) { - this.ssiExternalResolver = ssiExternalResolver; - this.debug = debug; - addBuiltinCommands(); - } - - - protected void addBuiltinCommands() { - addCommand("config", new SSIConfig()); - addCommand("echo", new SSIEcho()); - addCommand("exec", new SSIExec()); - addCommand("include", new SSIInclude()); - addCommand("flastmod", new SSIFlastmod()); - addCommand("fsize", new SSIFsize()); - addCommand("printenv", new SSIPrintenv()); - addCommand("set", new SSISet()); - SSIConditional ssiConditional = new SSIConditional(); - addCommand("if", ssiConditional); - addCommand("elif", ssiConditional); - addCommand("endif", ssiConditional); - addCommand("else", ssiConditional); - } - - - public void addCommand(String name, SSICommand command) { - commands.put(name, command); - } - - - /** - * Process a file with server-side commands, reading from reader and - * writing the processed version to writer. NOTE: We really should be doing - * this in a streaming way rather than converting it to an array first. - * - * @param reader - * the reader to read the file containing SSIs from - * @param writer - * the writer to write the file with the SSIs processed. - * @return the most current modified date resulting from any SSI commands - * @throws IOException - * when things go horribly awry. Should be unlikely since the - * SSICommand usually catches 'normal' IOExceptions. - */ - public long process(Reader reader, long lastModifiedDate, - PrintWriter writer) throws IOException { - SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver, - lastModifiedDate, debug); - StringWriter stringWriter = new StringWriter(); - IOTools.flow(reader, stringWriter); - String fileContents = stringWriter.toString(); - stringWriter = null; - int index = 0; - boolean inside = false; - StringBuffer command = new StringBuffer(); - try { - while (index < fileContents.length()) { - char c = fileContents.charAt(index); - if (!inside) { - if (c == COMMAND_START.charAt(0) - && charCmp(fileContents, index, COMMAND_START)) { - inside = true; - index += COMMAND_START.length(); - command.setLength(0); //clear the command string - } else { - if (!ssiMediator.getConditionalState().processConditionalCommandsOnly) { - writer.write(c); - } - index++; - } - } else { - if (c == COMMAND_END.charAt(0) - && charCmp(fileContents, index, COMMAND_END)) { - inside = false; - index += COMMAND_END.length(); - String strCmd = parseCmd(command); - if (debug > 0) { - ssiExternalResolver.log( - "SSIProcessor.process -- processing command: " - + strCmd, null); - } - String[] paramNames = parseParamNames(command, strCmd - .length()); - String[] paramValues = parseParamValues(command, - strCmd.length(), paramNames.length); - //We need to fetch this value each time, since it may - // change - // during the loop - String configErrMsg = ssiMediator.getConfigErrMsg(); - SSICommand ssiCommand = (SSICommand)commands - .get(strCmd.toLowerCase()); - String errorMessage = null; - if (ssiCommand == null) { - errorMessage = "Unknown command: " + strCmd; - } else if (paramValues == null) { - errorMessage = "Error parsing directive parameters."; - } else if (paramNames.length != paramValues.length) { - errorMessage = "Parameter names count does not match parameter values count on command: " - + strCmd; - } else { - // don't process the command if we are processing - // conditional - // commands only and the - // command is not conditional - if (!ssiMediator.getConditionalState().processConditionalCommandsOnly - || ssiCommand instanceof SSIConditional) { - long lmd = ssiCommand.process(ssiMediator, strCmd, - paramNames, paramValues, writer); - if (lmd > lastModifiedDate) { - lastModifiedDate = lmd; - } - } - } - if (errorMessage != null) { - ssiExternalResolver.log(errorMessage, null); - writer.write(configErrMsg); - } - } else { - command.append(c); - index++; - } - } - } - } catch (SSIStopProcessingException e) { - //If we are here, then we have already stopped processing, so all - // is good - } - return lastModifiedDate; - } - - - /** - * Parse a StringBuffer and take out the param type token. Called from - * requestHandler - * - * @param cmd - * a value of type 'StringBuffer' - * @return a value of type 'String[]' - */ - protected String[] parseParamNames(StringBuffer cmd, int start) { - int bIdx = start; - int i = 0; - int quotes = 0; - boolean inside = false; - StringBuffer retBuf = new StringBuffer(); - while (bIdx < cmd.length()) { - if (!inside) { - while (bIdx < cmd.length() && isSpace(cmd.charAt(bIdx))) - bIdx++; - if (bIdx >= cmd.length()) break; - inside = !inside; - } else { - while (bIdx < cmd.length() && cmd.charAt(bIdx) != '=') { - retBuf.append(cmd.charAt(bIdx)); - bIdx++; - } - retBuf.append('='); - inside = !inside; - quotes = 0; - boolean escaped = false; - for (; bIdx < cmd.length() && quotes != 2; bIdx++) { - char c = cmd.charAt(bIdx); - // Need to skip escaped characters - if (c == '\\' && !escaped) { - escaped = true; - bIdx++; - continue; - } - escaped = false; - if (c == '"') quotes++; - } - } - } - StringTokenizer str = new StringTokenizer(retBuf.toString(), "="); - String[] retString = new String[str.countTokens()]; - while (str.hasMoreTokens()) { - retString[i++] = str.nextToken().trim(); - } - return retString; - } - - - /** - * Parse a StringBuffer and take out the param token. Called from - * requestHandler - * - * @param cmd - * a value of type 'StringBuffer' - * @return a value of type 'String[]' - */ - protected String[] parseParamValues(StringBuffer cmd, int start, int count) { - int valIndex = 0; - boolean inside = false; - String[] vals = new String[count]; - StringBuffer sb = new StringBuffer(); - for (int bIdx = start; bIdx < cmd.length(); bIdx++) { - if (!inside) { - while (bIdx < cmd.length() && cmd.charAt(bIdx) != '"') - bIdx++; - if (bIdx >= cmd.length()) break; - inside = !inside; - } else { - boolean escaped = false; - for (; bIdx < cmd.length(); bIdx++) { - char c = cmd.charAt(bIdx); - // Check for escapes - if (c == '\\' && !escaped) { - escaped = true; - continue; - } - // If we reach the other " then stop - if (c == '"' && !escaped) break; - // Since parsing of attributes and var - // substitution is done in separate places, - // we need to leave escape in the string - if (c == '$' && escaped) sb.append('\\'); - escaped = false; - sb.append(c); - } - // If we hit the end without seeing a quote - // the signal an error - if (bIdx == cmd.length()) return null; - vals[valIndex++] = sb.toString(); - sb.delete(0, sb.length()); // clear the buffer - inside = !inside; - } - } - return vals; - } - - - /** - * Parse a StringBuffer and take out the command token. Called from - * requestHandler - * - * @param cmd - * a value of type 'StringBuffer' - * @return a value of type 'String', or null if there is none - */ - private String parseCmd(StringBuffer cmd) { - int firstLetter = -1; - int lastLetter = -1; - for (int i = 0; i < cmd.length(); i++) { - char c = cmd.charAt(i); - if (Character.isLetter(c)) { - if (firstLetter == -1) { - firstLetter = i; - } - lastLetter = i; - } else if (isSpace(c)) { - if (lastLetter > -1) { - break; - } - } else { - break; - } - } - String command = null; - if (firstLetter != -1) { - command = cmd.substring(firstLetter, lastLetter + 1); - } - return command; - } - - - protected boolean charCmp(String buf, int index, String command) { - return buf.regionMatches(index, command, 0, command.length()); - } - - - protected boolean isSpace(char c) { - return c == ' ' || c == '\n' || c == '\t' || c == '\r'; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.StringTokenizer; +import org.apache.catalina.util.IOTools; +/** + * The entry point to SSI processing. This class does the actual parsing, + * delegating to the SSIMediator, SSICommand, and SSIExternalResolver as + * necessary[ + * + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIProcessor { + /** The start pattern */ + protected final static String COMMAND_START = ""; + protected final static int BUFFER_SIZE = 4096; + protected SSIExternalResolver ssiExternalResolver; + protected HashMap commands = new HashMap(); + protected int debug; + + + public SSIProcessor(SSIExternalResolver ssiExternalResolver, int debug) { + this.ssiExternalResolver = ssiExternalResolver; + this.debug = debug; + addBuiltinCommands(); + } + + + protected void addBuiltinCommands() { + addCommand("config", new SSIConfig()); + addCommand("echo", new SSIEcho()); + addCommand("exec", new SSIExec()); + addCommand("include", new SSIInclude()); + addCommand("flastmod", new SSIFlastmod()); + addCommand("fsize", new SSIFsize()); + addCommand("printenv", new SSIPrintenv()); + addCommand("set", new SSISet()); + SSIConditional ssiConditional = new SSIConditional(); + addCommand("if", ssiConditional); + addCommand("elif", ssiConditional); + addCommand("endif", ssiConditional); + addCommand("else", ssiConditional); + } + + + public void addCommand(String name, SSICommand command) { + commands.put(name, command); + } + + + /** + * Process a file with server-side commands, reading from reader and + * writing the processed version to writer. NOTE: We really should be doing + * this in a streaming way rather than converting it to an array first. + * + * @param reader + * the reader to read the file containing SSIs from + * @param writer + * the writer to write the file with the SSIs processed. + * @return the most current modified date resulting from any SSI commands + * @throws IOException + * when things go horribly awry. Should be unlikely since the + * SSICommand usually catches 'normal' IOExceptions. + */ + public long process(Reader reader, long lastModifiedDate, + PrintWriter writer) throws IOException { + SSIMediator ssiMediator = new SSIMediator(ssiExternalResolver, + lastModifiedDate, debug); + StringWriter stringWriter = new StringWriter(); + IOTools.flow(reader, stringWriter); + String fileContents = stringWriter.toString(); + stringWriter = null; + int index = 0; + boolean inside = false; + StringBuffer command = new StringBuffer(); + try { + while (index < fileContents.length()) { + char c = fileContents.charAt(index); + if (!inside) { + if (c == COMMAND_START.charAt(0) + && charCmp(fileContents, index, COMMAND_START)) { + inside = true; + index += COMMAND_START.length(); + command.setLength(0); //clear the command string + } else { + if (!ssiMediator.getConditionalState().processConditionalCommandsOnly) { + writer.write(c); + } + index++; + } + } else { + if (c == COMMAND_END.charAt(0) + && charCmp(fileContents, index, COMMAND_END)) { + inside = false; + index += COMMAND_END.length(); + String strCmd = parseCmd(command); + if (debug > 0) { + ssiExternalResolver.log( + "SSIProcessor.process -- processing command: " + + strCmd, null); + } + String[] paramNames = parseParamNames(command, strCmd + .length()); + String[] paramValues = parseParamValues(command, + strCmd.length(), paramNames.length); + //We need to fetch this value each time, since it may + // change + // during the loop + String configErrMsg = ssiMediator.getConfigErrMsg(); + SSICommand ssiCommand = (SSICommand)commands + .get(strCmd.toLowerCase()); + String errorMessage = null; + if (ssiCommand == null) { + errorMessage = "Unknown command: " + strCmd; + } else if (paramValues == null) { + errorMessage = "Error parsing directive parameters."; + } else if (paramNames.length != paramValues.length) { + errorMessage = "Parameter names count does not match parameter values count on command: " + + strCmd; + } else { + // don't process the command if we are processing + // conditional + // commands only and the + // command is not conditional + if (!ssiMediator.getConditionalState().processConditionalCommandsOnly + || ssiCommand instanceof SSIConditional) { + long lmd = ssiCommand.process(ssiMediator, strCmd, + paramNames, paramValues, writer); + if (lmd > lastModifiedDate) { + lastModifiedDate = lmd; + } + } + } + if (errorMessage != null) { + ssiExternalResolver.log(errorMessage, null); + writer.write(configErrMsg); + } + } else { + command.append(c); + index++; + } + } + } + } catch (SSIStopProcessingException e) { + //If we are here, then we have already stopped processing, so all + // is good + } + return lastModifiedDate; + } + + + /** + * Parse a StringBuffer and take out the param type token. Called from + * requestHandler + * + * @param cmd + * a value of type 'StringBuffer' + * @return a value of type 'String[]' + */ + protected String[] parseParamNames(StringBuffer cmd, int start) { + int bIdx = start; + int i = 0; + int quotes = 0; + boolean inside = false; + StringBuffer retBuf = new StringBuffer(); + while (bIdx < cmd.length()) { + if (!inside) { + while (bIdx < cmd.length() && isSpace(cmd.charAt(bIdx))) + bIdx++; + if (bIdx >= cmd.length()) break; + inside = !inside; + } else { + while (bIdx < cmd.length() && cmd.charAt(bIdx) != '=') { + retBuf.append(cmd.charAt(bIdx)); + bIdx++; + } + retBuf.append('='); + inside = !inside; + quotes = 0; + boolean escaped = false; + for (; bIdx < cmd.length() && quotes != 2; bIdx++) { + char c = cmd.charAt(bIdx); + // Need to skip escaped characters + if (c == '\\' && !escaped) { + escaped = true; + bIdx++; + continue; + } + escaped = false; + if (c == '"') quotes++; + } + } + } + StringTokenizer str = new StringTokenizer(retBuf.toString(), "="); + String[] retString = new String[str.countTokens()]; + while (str.hasMoreTokens()) { + retString[i++] = str.nextToken().trim(); + } + return retString; + } + + + /** + * Parse a StringBuffer and take out the param token. Called from + * requestHandler + * + * @param cmd + * a value of type 'StringBuffer' + * @return a value of type 'String[]' + */ + protected String[] parseParamValues(StringBuffer cmd, int start, int count) { + int valIndex = 0; + boolean inside = false; + String[] vals = new String[count]; + StringBuffer sb = new StringBuffer(); + for (int bIdx = start; bIdx < cmd.length(); bIdx++) { + if (!inside) { + while (bIdx < cmd.length() && cmd.charAt(bIdx) != '"') + bIdx++; + if (bIdx >= cmd.length()) break; + inside = !inside; + } else { + boolean escaped = false; + for (; bIdx < cmd.length(); bIdx++) { + char c = cmd.charAt(bIdx); + // Check for escapes + if (c == '\\' && !escaped) { + escaped = true; + continue; + } + // If we reach the other " then stop + if (c == '"' && !escaped) break; + // Since parsing of attributes and var + // substitution is done in separate places, + // we need to leave escape in the string + if (c == '$' && escaped) sb.append('\\'); + escaped = false; + sb.append(c); + } + // If we hit the end without seeing a quote + // the signal an error + if (bIdx == cmd.length()) return null; + vals[valIndex++] = sb.toString(); + sb.delete(0, sb.length()); // clear the buffer + inside = !inside; + } + } + return vals; + } + + + /** + * Parse a StringBuffer and take out the command token. Called from + * requestHandler + * + * @param cmd + * a value of type 'StringBuffer' + * @return a value of type 'String', or null if there is none + */ + private String parseCmd(StringBuffer cmd) { + int firstLetter = -1; + int lastLetter = -1; + for (int i = 0; i < cmd.length(); i++) { + char c = cmd.charAt(i); + if (Character.isLetter(c)) { + if (firstLetter == -1) { + firstLetter = i; + } + lastLetter = i; + } else if (isSpace(c)) { + if (lastLetter > -1) { + break; + } + } else { + break; + } + } + String command = null; + if (firstLetter != -1) { + command = cmd.substring(firstLetter, lastLetter + 1); + } + return command; + } + + + protected boolean charCmp(String buf, int index, String command) { + return buf.regionMatches(index, command, 0, command.length()); + } + + + protected boolean isSpace(char c) { + return c == ' ' || c == '\n' || c == '\t' || c == '\r'; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIServlet.java b/java/org/apache/catalina/ssi/SSIServlet.java index 44310eacc..f9f36906e 100644 --- a/java/org/apache/catalina/ssi/SSIServlet.java +++ b/java/org/apache/catalina/ssi/SSIServlet.java @@ -1,232 +1,232 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.URL; -import java.net.URLConnection; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.Globals; -/** - * Servlet to process SSI requests within a webpage. Mapped to a path from - * within web.xml. - * - * @author Bip Thelin - * @author Amy Roh - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSIServlet extends HttpServlet { - /** Debug level for this servlet. */ - protected int debug = 0; - /** Should the output be buffered. */ - protected boolean buffered = false; - /** Expiration time in seconds for the doc. */ - protected Long expires = null; - /** virtual path can be webapp-relative */ - protected boolean isVirtualWebappRelative = false; - /** Input encoding. If not specified, uses platform default */ - protected String inputEncoding = null; - /** Output encoding. If not specified, uses platform default */ - protected String outputEncoding = "UTF-8"; - - - //----------------- Public methods. - /** - * Initialize this servlet. - * - * @exception ServletException - * if an error occurs - */ - public void init() throws ServletException { - String value = null; - try { - value = getServletConfig().getInitParameter("debug"); - debug = Integer.parseInt(value); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter( - "isVirtualWebappRelative"); - isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false; - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("expires"); - expires = Long.valueOf(value); - } catch (NumberFormatException e) { - expires = null; - log("Invalid format for expires initParam; expected integer (seconds)"); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("buffered"); - buffered = Integer.parseInt(value) > 0?true:false; - } catch (Throwable t) { - ; - } - try { - inputEncoding = getServletConfig().getInitParameter("inputEncoding"); - } catch (Throwable t) { - ; - } - try { - value = getServletConfig().getInitParameter("outputEncoding"); - if (value != null) { - outputEncoding = value; - } - } catch (Throwable t) { - ; - } - if (debug > 0) - log("SSIServlet.init() SSI invoker started with 'debug'=" + debug); - } - - - /** - * Process and forward the GET request to our requestHandler()* - * - * @param req - * a value of type 'HttpServletRequest' - * @param res - * a value of type 'HttpServletResponse' - * @exception IOException - * if an error occurs - * @exception ServletException - * if an error occurs - */ - public void doGet(HttpServletRequest req, HttpServletResponse res) - throws IOException, ServletException { - if (debug > 0) log("SSIServlet.doGet()"); - requestHandler(req, res); - } - - - /** - * Process and forward the POST request to our - * requestHandler(). - * - * @param req - * a value of type 'HttpServletRequest' - * @param res - * a value of type 'HttpServletResponse' - * @exception IOException - * if an error occurs - * @exception ServletException - * if an error occurs - */ - public void doPost(HttpServletRequest req, HttpServletResponse res) - throws IOException, ServletException { - if (debug > 0) log("SSIServlet.doPost()"); - requestHandler(req, res); - } - - - /** - * Process our request and locate right SSI command. - * - * @param req - * a value of type 'HttpServletRequest' - * @param res - * a value of type 'HttpServletResponse' - */ - protected void requestHandler(HttpServletRequest req, - HttpServletResponse res) throws IOException, ServletException { - ServletContext servletContext = getServletContext(); - String path = SSIServletRequestUtil.getRelativePath(req); - if (debug > 0) - log("SSIServlet.requestHandler()\n" + "Serving " - + (buffered?"buffered ":"unbuffered ") + "resource '" - + path + "'"); - // Exclude any resource in the /WEB-INF and /META-INF subdirectories - // (the "toUpperCase()" avoids problems on Windows systems) - if (path == null || path.toUpperCase().startsWith("/WEB-INF") - || path.toUpperCase().startsWith("/META-INF")) { - res.sendError(HttpServletResponse.SC_NOT_FOUND, path); - log("Can't serve file: " + path); - return; - } - URL resource = servletContext.getResource(path); - if (resource == null) { - res.sendError(HttpServletResponse.SC_NOT_FOUND, path); - log("Can't find file: " + path); - return; - } - String resourceMimeType = servletContext.getMimeType(path); - if (resourceMimeType == null) { - resourceMimeType = "text/html"; - } - res.setContentType(resourceMimeType + ";charset=" + outputEncoding); - if (expires != null) { - res.setDateHeader("Expires", (new java.util.Date()).getTime() - + expires.longValue() * 1000); - } - req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); - processSSI(req, res, resource); - } - - - protected void processSSI(HttpServletRequest req, HttpServletResponse res, - URL resource) throws IOException { - SSIExternalResolver ssiExternalResolver = - new SSIServletExternalResolver(getServletContext(), req, res, - isVirtualWebappRelative, debug, inputEncoding); - SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, - debug); - PrintWriter printWriter = null; - StringWriter stringWriter = null; - if (buffered) { - stringWriter = new StringWriter(); - printWriter = new PrintWriter(stringWriter); - } else { - printWriter = res.getWriter(); - } - - URLConnection resourceInfo = resource.openConnection(); - InputStream resourceInputStream = resourceInfo.getInputStream(); - String encoding = resourceInfo.getContentEncoding(); - if (encoding == null) { - encoding = inputEncoding; - } - InputStreamReader isr; - if (encoding == null) { - isr = new InputStreamReader(resourceInputStream); - } else { - isr = new InputStreamReader(resourceInputStream, encoding); - } - BufferedReader bufferedReader = new BufferedReader(isr); - - long lastModified = ssiProcessor.process(bufferedReader, - resourceInfo.getLastModified(), printWriter); - if (lastModified > 0) { - res.setDateHeader("last-modified", lastModified); - } - if (buffered) { - printWriter.flush(); - String text = stringWriter.toString(); - res.getWriter().write(text); - } - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.URL; +import java.net.URLConnection; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.Globals; +/** + * Servlet to process SSI requests within a webpage. Mapped to a path from + * within web.xml. + * + * @author Bip Thelin + * @author Amy Roh + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSIServlet extends HttpServlet { + /** Debug level for this servlet. */ + protected int debug = 0; + /** Should the output be buffered. */ + protected boolean buffered = false; + /** Expiration time in seconds for the doc. */ + protected Long expires = null; + /** virtual path can be webapp-relative */ + protected boolean isVirtualWebappRelative = false; + /** Input encoding. If not specified, uses platform default */ + protected String inputEncoding = null; + /** Output encoding. If not specified, uses platform default */ + protected String outputEncoding = "UTF-8"; + + + //----------------- Public methods. + /** + * Initialize this servlet. + * + * @exception ServletException + * if an error occurs + */ + public void init() throws ServletException { + String value = null; + try { + value = getServletConfig().getInitParameter("debug"); + debug = Integer.parseInt(value); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter( + "isVirtualWebappRelative"); + isVirtualWebappRelative = Integer.parseInt(value) > 0?true:false; + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("expires"); + expires = Long.valueOf(value); + } catch (NumberFormatException e) { + expires = null; + log("Invalid format for expires initParam; expected integer (seconds)"); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("buffered"); + buffered = Integer.parseInt(value) > 0?true:false; + } catch (Throwable t) { + ; + } + try { + inputEncoding = getServletConfig().getInitParameter("inputEncoding"); + } catch (Throwable t) { + ; + } + try { + value = getServletConfig().getInitParameter("outputEncoding"); + if (value != null) { + outputEncoding = value; + } + } catch (Throwable t) { + ; + } + if (debug > 0) + log("SSIServlet.init() SSI invoker started with 'debug'=" + debug); + } + + + /** + * Process and forward the GET request to our requestHandler()* + * + * @param req + * a value of type 'HttpServletRequest' + * @param res + * a value of type 'HttpServletResponse' + * @exception IOException + * if an error occurs + * @exception ServletException + * if an error occurs + */ + public void doGet(HttpServletRequest req, HttpServletResponse res) + throws IOException, ServletException { + if (debug > 0) log("SSIServlet.doGet()"); + requestHandler(req, res); + } + + + /** + * Process and forward the POST request to our + * requestHandler(). + * + * @param req + * a value of type 'HttpServletRequest' + * @param res + * a value of type 'HttpServletResponse' + * @exception IOException + * if an error occurs + * @exception ServletException + * if an error occurs + */ + public void doPost(HttpServletRequest req, HttpServletResponse res) + throws IOException, ServletException { + if (debug > 0) log("SSIServlet.doPost()"); + requestHandler(req, res); + } + + + /** + * Process our request and locate right SSI command. + * + * @param req + * a value of type 'HttpServletRequest' + * @param res + * a value of type 'HttpServletResponse' + */ + protected void requestHandler(HttpServletRequest req, + HttpServletResponse res) throws IOException, ServletException { + ServletContext servletContext = getServletContext(); + String path = SSIServletRequestUtil.getRelativePath(req); + if (debug > 0) + log("SSIServlet.requestHandler()\n" + "Serving " + + (buffered?"buffered ":"unbuffered ") + "resource '" + + path + "'"); + // Exclude any resource in the /WEB-INF and /META-INF subdirectories + // (the "toUpperCase()" avoids problems on Windows systems) + if (path == null || path.toUpperCase().startsWith("/WEB-INF") + || path.toUpperCase().startsWith("/META-INF")) { + res.sendError(HttpServletResponse.SC_NOT_FOUND, path); + log("Can't serve file: " + path); + return; + } + URL resource = servletContext.getResource(path); + if (resource == null) { + res.sendError(HttpServletResponse.SC_NOT_FOUND, path); + log("Can't find file: " + path); + return; + } + String resourceMimeType = servletContext.getMimeType(path); + if (resourceMimeType == null) { + resourceMimeType = "text/html"; + } + res.setContentType(resourceMimeType + ";charset=" + outputEncoding); + if (expires != null) { + res.setDateHeader("Expires", (new java.util.Date()).getTime() + + expires.longValue() * 1000); + } + req.setAttribute(Globals.SSI_FLAG_ATTR, "true"); + processSSI(req, res, resource); + } + + + protected void processSSI(HttpServletRequest req, HttpServletResponse res, + URL resource) throws IOException { + SSIExternalResolver ssiExternalResolver = + new SSIServletExternalResolver(getServletContext(), req, res, + isVirtualWebappRelative, debug, inputEncoding); + SSIProcessor ssiProcessor = new SSIProcessor(ssiExternalResolver, + debug); + PrintWriter printWriter = null; + StringWriter stringWriter = null; + if (buffered) { + stringWriter = new StringWriter(); + printWriter = new PrintWriter(stringWriter); + } else { + printWriter = res.getWriter(); + } + + URLConnection resourceInfo = resource.openConnection(); + InputStream resourceInputStream = resourceInfo.getInputStream(); + String encoding = resourceInfo.getContentEncoding(); + if (encoding == null) { + encoding = inputEncoding; + } + InputStreamReader isr; + if (encoding == null) { + isr = new InputStreamReader(resourceInputStream); + } else { + isr = new InputStreamReader(resourceInputStream, encoding); + } + BufferedReader bufferedReader = new BufferedReader(isr); + + long lastModified = ssiProcessor.process(bufferedReader, + resourceInfo.getLastModified(), printWriter); + if (lastModified > 0) { + res.setDateHeader("last-modified", lastModified); + } + if (buffered) { + printWriter.flush(); + String text = stringWriter.toString(); + res.getWriter().write(text); + } + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIServletExternalResolver.java b/java/org/apache/catalina/ssi/SSIServletExternalResolver.java index 7ee7bad67..16e3519dc 100644 --- a/java/org/apache/catalina/ssi/SSIServletExternalResolver.java +++ b/java/org/apache/catalina/ssi/SSIServletExternalResolver.java @@ -1,567 +1,567 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLDecoder; -import java.util.Collection; -import java.util.Date; -import java.util.Enumeration; -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import org.apache.catalina.connector.Request; -import org.apache.coyote.Constants; - -/** - * An implementation of SSIExternalResolver that is used with servlets. - * - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 349308 $, $Date: 2005-11-27 21:52:55 +0100 (dim., 27 nov. 2005) $ - */ -public class SSIServletExternalResolver implements SSIExternalResolver { - protected final String VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH", - "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI", - "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", - "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", - "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED", - "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR", - "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD", - "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", - "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE", - "UNIQUE_ID"}; - protected ServletContext context; - protected HttpServletRequest req; - protected HttpServletResponse res; - protected boolean isVirtualWebappRelative; - protected int debug; - protected String inputEncoding; - - public SSIServletExternalResolver(ServletContext context, - HttpServletRequest req, HttpServletResponse res, - boolean isVirtualWebappRelative, int debug, String inputEncoding) { - this.context = context; - this.req = req; - this.res = res; - this.isVirtualWebappRelative = isVirtualWebappRelative; - this.debug = debug; - this.inputEncoding = inputEncoding; - } - - - public void log(String message, Throwable throwable) { - //We can't assume that Servlet.log( message, null ) - //is the same as Servlet.log( message ), since API - //doesn't seem to say so. - if (throwable != null) { - context.log(message, throwable); - } else { - context.log(message); - } - } - - - public void addVariableNames(Collection variableNames) { - for (int i = 0; i < VARIABLE_NAMES.length; i++) { - String variableName = VARIABLE_NAMES[i]; - String variableValue = getVariableValue(variableName); - if (variableValue != null) { - variableNames.add(variableName); - } - } - Enumeration e = req.getAttributeNames(); - while (e.hasMoreElements()) { - String name = (String)e.nextElement(); - if (!isNameReserved(name)) { - variableNames.add(name); - } - } - } - - - protected Object getReqAttributeIgnoreCase(String targetName) { - Object object = null; - if (!isNameReserved(targetName)) { - object = req.getAttribute(targetName); - if (object == null) { - Enumeration e = req.getAttributeNames(); - while (e.hasMoreElements()) { - String name = (String)e.nextElement(); - if (targetName.equalsIgnoreCase(name) - && !isNameReserved(name)) { - object = req.getAttribute(name); - if (object != null) { - break; - } - } - } - } - } - return object; - } - - - protected boolean isNameReserved(String name) { - return name.startsWith("java.") || name.startsWith("javax.") - || name.startsWith("sun."); - } - - - public void setVariableValue(String name, String value) { - if (!isNameReserved(name)) { - req.setAttribute(name, value); - } - } - - - public String getVariableValue(String name) { - String retVal = null; - Object object = getReqAttributeIgnoreCase(name); - if (object != null) { - retVal = object.toString(); - } else { - retVal = getCGIVariable(name); - } - return retVal; - } - - - protected String getCGIVariable(String name) { - String retVal = null; - String[] nameParts = name.toUpperCase().split("_"); - int requiredParts = 2; - if (nameParts.length == 1) { - if (nameParts[0].equals("PATH")) { - requiredParts = 1; - retVal = null; // Not implemented - } - } - else if (nameParts[0].equals("AUTH")) { - if (nameParts[1].equals("TYPE")) { - retVal = req.getAuthType(); - } - } else if(nameParts[0].equals("CONTENT")) { - if (nameParts[1].equals("LENGTH")) { - int contentLength = req.getContentLength(); - if (contentLength >= 0) { - retVal = Integer.toString(contentLength); - } - } else if (nameParts[1].equals("TYPE")) { - retVal = req.getContentType(); - } - } else if (nameParts[0].equals("DOCUMENT")) { - if (nameParts[1].equals("NAME")) { - String requestURI = req.getRequestURI(); - retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1); - } else if (nameParts[1].equals("URI")) { - retVal = req.getRequestURI(); - } - } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) { - retVal = "CGI/1.1"; - } else if (nameParts[0].equals("HTTP")) { - if (nameParts[1].equals("ACCEPT")) { - String accept = null; - if (nameParts.length == 2) { - accept = "Accept"; - } else if (nameParts[2].equals("ENCODING")) { - requiredParts = 3; - accept = "Accept-Encoding"; - } else if (nameParts[2].equals("LANGUAGE")) { - requiredParts = 3; - accept = "Accept-Language"; - } - if (accept != null) { - Enumeration acceptHeaders = req.getHeaders(accept); - if (acceptHeaders != null) - if (acceptHeaders.hasMoreElements()) { - StringBuffer rv = new StringBuffer( - (String) acceptHeaders.nextElement()); - while (acceptHeaders.hasMoreElements()) { - rv.append(", "); - rv.append((String) acceptHeaders.nextElement()); - } - retVal = rv.toString(); - } - } - } - else if (nameParts[1].equals("CONNECTION")) { - retVal = req.getHeader("Connection"); - } - else if (nameParts[1].equals("HOST")) { - retVal = req.getHeader("Host"); - } - else if (nameParts[1].equals("REFERER")) { - retVal = req.getHeader("Referer"); - } - else if (nameParts[1].equals("USER")) - if (nameParts.length == 3) - if (nameParts[2].equals("AGENT")) { - requiredParts = 3; - retVal = req.getHeader("User-Agent"); - } - - } else if (nameParts[0].equals("PATH")) { - if (nameParts[1].equals("INFO")) { - retVal = req.getPathInfo(); - } else if (nameParts[1].equals("TRANSLATED")) { - retVal = req.getPathTranslated(); - } - } else if (nameParts[0].equals("QUERY")) { - if (nameParts[1].equals("STRING")) { - String queryString = req.getQueryString(); - if (nameParts.length == 2) { - //apache displays this as an empty string rather than (none) - retVal = nullToEmptyString(queryString); - } else if (nameParts[2].equals("UNESCAPED")) { - requiredParts = 3; - if (queryString != null) { - // Use default as a last resort - String queryStringEncoding = - Constants.DEFAULT_CHARACTER_ENCODING; - - String uriEncoding = null; - boolean useBodyEncodingForURI = false; - - // Get encoding settings from request / connector if - // possible - String requestEncoding = req.getCharacterEncoding(); - if (req instanceof Request) { - uriEncoding = - ((Request)req).getConnector().getURIEncoding(); - useBodyEncodingForURI = ((Request)req) - .getConnector().getUseBodyEncodingForURI(); - } - - // If valid, apply settings from request / connector - if (uriEncoding != null) { - queryStringEncoding = uriEncoding; - } else if(useBodyEncodingForURI) { - if (requestEncoding != null) { - queryStringEncoding = requestEncoding; - } - } - - try { - retVal = URLDecoder.decode(queryString, - queryStringEncoding); - } catch (UnsupportedEncodingException e) { - retVal = queryString; - } - } - } - } - } else if(nameParts[0].equals("REMOTE")) { - if (nameParts[1].equals("ADDR")) { - retVal = req.getRemoteAddr(); - } else if (nameParts[1].equals("HOST")) { - retVal = req.getRemoteHost(); - } else if (nameParts[1].equals("IDENT")) { - retVal = null; // Not implemented - } else if (nameParts[1].equals("PORT")) { - retVal = Integer.toString( req.getRemotePort()); - } else if (nameParts[1].equals("USER")) { - retVal = req.getRemoteUser(); - } - } else if(nameParts[0].equals("REQUEST")) { - if (nameParts[1].equals("METHOD")) { - retVal = req.getMethod(); - } - else if (nameParts[1].equals("URI")) { - // If this is an error page, get the original URI - retVal = (String) req.getAttribute( - "javax.servlet.forward.request_uri"); - if (retVal == null) retVal=req.getRequestURI(); - } - } else if (nameParts[0].equals("SCRIPT")) { - String scriptName = req.getServletPath(); - if (nameParts[1].equals("FILENAME")) { - retVal = context.getRealPath(scriptName); - } - else if (nameParts[1].equals("NAME")) { - retVal = scriptName; - } - } else if (nameParts[0].equals("SERVER")) { - if (nameParts[1].equals("ADDR")) { - retVal = req.getLocalAddr(); - } - if (nameParts[1].equals("NAME")) { - retVal = req.getServerName(); - } else if (nameParts[1].equals("PORT")) { - retVal = Integer.toString(req.getServerPort()); - } else if (nameParts[1].equals("PROTOCOL")) { - retVal = req.getProtocol(); - } else if (nameParts[1].equals("SOFTWARE")) { - StringBuffer rv = new StringBuffer(context.getServerInfo()); - rv.append(" "); - rv.append(System.getProperty("java.vm.name")); - rv.append("/"); - rv.append(System.getProperty("java.vm.version")); - rv.append(" "); - rv.append(System.getProperty("os.name")); - retVal = rv.toString(); - } - } else if (name.equalsIgnoreCase("UNIQUE_ID")) { - retVal = req.getRequestedSessionId(); - } - if (requiredParts != nameParts.length) return null; - return retVal; - } - - public Date getCurrentDate() { - return new Date(); - } - - - protected String nullToEmptyString(String string) { - String retVal = string; - if (retVal == null) { - retVal = ""; - } - return retVal; - } - - - protected String getPathWithoutFileName(String servletPath) { - String retVal = null; - int lastSlash = servletPath.lastIndexOf('/'); - if (lastSlash >= 0) { - //cut off file namee - retVal = servletPath.substring(0, lastSlash + 1); - } - return retVal; - } - - - protected String getPathWithoutContext(String servletPath) { - String retVal = null; - int secondSlash = servletPath.indexOf('/', 1); - if (secondSlash >= 0) { - //cut off context - retVal = servletPath.substring(secondSlash); - } - return retVal; - } - - - protected String getAbsolutePath(String path) throws IOException { - String pathWithoutContext = SSIServletRequestUtil.getRelativePath(req); - String prefix = getPathWithoutFileName(pathWithoutContext); - if (prefix == null) { - throw new IOException("Couldn't remove filename from path: " - + pathWithoutContext); - } - String fullPath = prefix + path; - String retVal = SSIServletRequestUtil.normalize(fullPath); - if (retVal == null) { - throw new IOException("Normalization yielded null on path: " - + fullPath); - } - return retVal; - } - - - protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath( - String nonVirtualPath) throws IOException { - if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) { - throw new IOException("A non-virtual path can't be absolute: " - + nonVirtualPath); - } - if (nonVirtualPath.indexOf("../") >= 0) { - throw new IOException("A non-virtual path can't contain '../' : " - + nonVirtualPath); - } - String path = getAbsolutePath(nonVirtualPath); - ServletContextAndPath csAndP = new ServletContextAndPath( - context, path); - return csAndP; - } - - - protected ServletContextAndPath getServletContextAndPathFromVirtualPath( - String virtualPath) throws IOException { - - if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) { - return new ServletContextAndPath(context, - getAbsolutePath(virtualPath)); - } else { - String normalized = SSIServletRequestUtil.normalize(virtualPath); - if (isVirtualWebappRelative) { - return new ServletContextAndPath(context, normalized); - } else { - ServletContext normContext = context.getContext(normalized); - if (normContext == null) { - throw new IOException("Couldn't get context for path: " - + normalized); - } - //If it's the root context, then there is no context element - // to remove, - // ie: - // '/file1.shtml' vs '/appName1/file1.shtml' - if (!isRootContext(normContext)) { - String noContext = getPathWithoutContext(normalized); - if (noContext == null) { - throw new IOException( - "Couldn't remove context from path: " - + normalized); - } - return new ServletContextAndPath(normContext, noContext); - } else { - return new ServletContextAndPath(normContext, normalized); - } - } - } - } - - - //Assumes servletContext is not-null - //Assumes that identity comparison will be true for the same context - //Assuming the above, getContext("/") will be non-null as long as the root - // context is - // accessible. - //If it isn't, then servletContext can't be the root context anyway, hence - // they will - // not match. - protected boolean isRootContext(ServletContext servletContext) { - return servletContext == servletContext.getContext("/"); - } - - - protected ServletContextAndPath getServletContextAndPath( - String originalPath, boolean virtual) throws IOException { - ServletContextAndPath csAndP = null; - if (debug > 0) { - log("SSIServletExternalResolver.getServletContextAndPath( " - + originalPath + ", " + virtual + ")", null); - } - if (virtual) { - csAndP = getServletContextAndPathFromVirtualPath(originalPath); - } else { - csAndP = getServletContextAndPathFromNonVirtualPath(originalPath); - } - return csAndP; - } - - - protected URLConnection getURLConnection(String originalPath, - boolean virtual) throws IOException { - ServletContextAndPath csAndP = getServletContextAndPath(originalPath, - virtual); - ServletContext context = csAndP.getServletContext(); - String path = csAndP.getPath(); - URL url = context.getResource(path); - if (url == null) { - throw new IOException("Context did not contain resource: " + path); - } - URLConnection urlConnection = url.openConnection(); - return urlConnection; - } - - - public long getFileLastModified(String path, boolean virtual) - throws IOException { - long lastModified = 0; - try { - URLConnection urlConnection = getURLConnection(path, virtual); - lastModified = urlConnection.getLastModified(); - } catch (IOException e) { - // Ignore this. It will always fail for non-file based includes - } - return lastModified; - } - - - public long getFileSize(String path, boolean virtual) throws IOException { - long fileSize = -1; - try { - URLConnection urlConnection = getURLConnection(path, virtual); - fileSize = urlConnection.getContentLength(); - } catch (IOException e) { - // Ignore this. It will always fail for non-file based includes - } - return fileSize; - } - - - //We are making lots of unnecessary copies of the included data here. If - //someone ever complains that this is slow, we should connect the included - // stream to the print writer that SSICommand uses. - public String getFileText(String originalPath, boolean virtual) - throws IOException { - try { - ServletContextAndPath csAndP = getServletContextAndPath( - originalPath, virtual); - ServletContext context = csAndP.getServletContext(); - String path = csAndP.getPath(); - RequestDispatcher rd = context.getRequestDispatcher(path); - if (rd == null) { - throw new IOException( - "Couldn't get request dispatcher for path: " + path); - } - ByteArrayServletOutputStream basos = - new ByteArrayServletOutputStream(); - ResponseIncludeWrapper responseIncludeWrapper = - new ResponseIncludeWrapper(context, req, res, basos); - rd.include(req, responseIncludeWrapper); - //We can't assume the included servlet flushed its output - responseIncludeWrapper.flushOutputStreamOrWriter(); - byte[] bytes = basos.toByteArray(); - - //Assume platform default encoding unless otherwise specified - String retVal; - if (inputEncoding == null) { - retVal = new String( bytes ); - } else { - retVal = new String (bytes, inputEncoding); - } - - //make an assumption that an empty response is a failure. This is - // a problem - // if a truly empty file - //were included, but not sure how else to tell. - if (retVal.equals("")) { - throw new IOException("Couldn't find file: " + path); - } - return retVal; - } catch (ServletException e) { - throw new IOException("Couldn't include file: " + originalPath - + " because of ServletException: " + e.getMessage()); - } - } - - protected class ServletContextAndPath { - protected ServletContext servletContext; - protected String path; - - - public ServletContextAndPath(ServletContext servletContext, - String path) { - this.servletContext = servletContext; - this.path = path; - } - - - public ServletContext getServletContext() { - return servletContext; - } - - - public String getPath() { - return path; - } - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.IOException; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLDecoder; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import org.apache.catalina.connector.Request; +import org.apache.coyote.Constants; + +/** + * An implementation of SSIExternalResolver that is used with servlets. + * + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 349308 $, $Date: 2005-11-27 21:52:55 +0100 (dim., 27 nov. 2005) $ + */ +public class SSIServletExternalResolver implements SSIExternalResolver { + protected final String VARIABLE_NAMES[] = {"AUTH_TYPE", "CONTENT_LENGTH", + "CONTENT_TYPE", "DOCUMENT_NAME", "DOCUMENT_URI", + "GATEWAY_INTERFACE", "HTTP_ACCEPT", "HTTP_ACCEPT_ENCODING", + "HTTP_ACCEPT_LANGUAGE", "HTTP_CONNECTION", "HTTP_HOST", + "HTTP_REFERER", "HTTP_USER_AGENT", "PATH_INFO", "PATH_TRANSLATED", + "QUERY_STRING", "QUERY_STRING_UNESCAPED", "REMOTE_ADDR", + "REMOTE_HOST", "REMOTE_PORT", "REMOTE_USER", "REQUEST_METHOD", + "REQUEST_URI", "SCRIPT_FILENAME", "SCRIPT_NAME", "SERVER_ADDR", + "SERVER_NAME", "SERVER_PORT", "SERVER_PROTOCOL", "SERVER_SOFTWARE", + "UNIQUE_ID"}; + protected ServletContext context; + protected HttpServletRequest req; + protected HttpServletResponse res; + protected boolean isVirtualWebappRelative; + protected int debug; + protected String inputEncoding; + + public SSIServletExternalResolver(ServletContext context, + HttpServletRequest req, HttpServletResponse res, + boolean isVirtualWebappRelative, int debug, String inputEncoding) { + this.context = context; + this.req = req; + this.res = res; + this.isVirtualWebappRelative = isVirtualWebappRelative; + this.debug = debug; + this.inputEncoding = inputEncoding; + } + + + public void log(String message, Throwable throwable) { + //We can't assume that Servlet.log( message, null ) + //is the same as Servlet.log( message ), since API + //doesn't seem to say so. + if (throwable != null) { + context.log(message, throwable); + } else { + context.log(message); + } + } + + + public void addVariableNames(Collection variableNames) { + for (int i = 0; i < VARIABLE_NAMES.length; i++) { + String variableName = VARIABLE_NAMES[i]; + String variableValue = getVariableValue(variableName); + if (variableValue != null) { + variableNames.add(variableName); + } + } + Enumeration e = req.getAttributeNames(); + while (e.hasMoreElements()) { + String name = (String)e.nextElement(); + if (!isNameReserved(name)) { + variableNames.add(name); + } + } + } + + + protected Object getReqAttributeIgnoreCase(String targetName) { + Object object = null; + if (!isNameReserved(targetName)) { + object = req.getAttribute(targetName); + if (object == null) { + Enumeration e = req.getAttributeNames(); + while (e.hasMoreElements()) { + String name = (String)e.nextElement(); + if (targetName.equalsIgnoreCase(name) + && !isNameReserved(name)) { + object = req.getAttribute(name); + if (object != null) { + break; + } + } + } + } + } + return object; + } + + + protected boolean isNameReserved(String name) { + return name.startsWith("java.") || name.startsWith("javax.") + || name.startsWith("sun."); + } + + + public void setVariableValue(String name, String value) { + if (!isNameReserved(name)) { + req.setAttribute(name, value); + } + } + + + public String getVariableValue(String name) { + String retVal = null; + Object object = getReqAttributeIgnoreCase(name); + if (object != null) { + retVal = object.toString(); + } else { + retVal = getCGIVariable(name); + } + return retVal; + } + + + protected String getCGIVariable(String name) { + String retVal = null; + String[] nameParts = name.toUpperCase().split("_"); + int requiredParts = 2; + if (nameParts.length == 1) { + if (nameParts[0].equals("PATH")) { + requiredParts = 1; + retVal = null; // Not implemented + } + } + else if (nameParts[0].equals("AUTH")) { + if (nameParts[1].equals("TYPE")) { + retVal = req.getAuthType(); + } + } else if(nameParts[0].equals("CONTENT")) { + if (nameParts[1].equals("LENGTH")) { + int contentLength = req.getContentLength(); + if (contentLength >= 0) { + retVal = Integer.toString(contentLength); + } + } else if (nameParts[1].equals("TYPE")) { + retVal = req.getContentType(); + } + } else if (nameParts[0].equals("DOCUMENT")) { + if (nameParts[1].equals("NAME")) { + String requestURI = req.getRequestURI(); + retVal = requestURI.substring(requestURI.lastIndexOf('/') + 1); + } else if (nameParts[1].equals("URI")) { + retVal = req.getRequestURI(); + } + } else if (name.equalsIgnoreCase("GATEWAY_INTERFACE")) { + retVal = "CGI/1.1"; + } else if (nameParts[0].equals("HTTP")) { + if (nameParts[1].equals("ACCEPT")) { + String accept = null; + if (nameParts.length == 2) { + accept = "Accept"; + } else if (nameParts[2].equals("ENCODING")) { + requiredParts = 3; + accept = "Accept-Encoding"; + } else if (nameParts[2].equals("LANGUAGE")) { + requiredParts = 3; + accept = "Accept-Language"; + } + if (accept != null) { + Enumeration acceptHeaders = req.getHeaders(accept); + if (acceptHeaders != null) + if (acceptHeaders.hasMoreElements()) { + StringBuffer rv = new StringBuffer( + (String) acceptHeaders.nextElement()); + while (acceptHeaders.hasMoreElements()) { + rv.append(", "); + rv.append((String) acceptHeaders.nextElement()); + } + retVal = rv.toString(); + } + } + } + else if (nameParts[1].equals("CONNECTION")) { + retVal = req.getHeader("Connection"); + } + else if (nameParts[1].equals("HOST")) { + retVal = req.getHeader("Host"); + } + else if (nameParts[1].equals("REFERER")) { + retVal = req.getHeader("Referer"); + } + else if (nameParts[1].equals("USER")) + if (nameParts.length == 3) + if (nameParts[2].equals("AGENT")) { + requiredParts = 3; + retVal = req.getHeader("User-Agent"); + } + + } else if (nameParts[0].equals("PATH")) { + if (nameParts[1].equals("INFO")) { + retVal = req.getPathInfo(); + } else if (nameParts[1].equals("TRANSLATED")) { + retVal = req.getPathTranslated(); + } + } else if (nameParts[0].equals("QUERY")) { + if (nameParts[1].equals("STRING")) { + String queryString = req.getQueryString(); + if (nameParts.length == 2) { + //apache displays this as an empty string rather than (none) + retVal = nullToEmptyString(queryString); + } else if (nameParts[2].equals("UNESCAPED")) { + requiredParts = 3; + if (queryString != null) { + // Use default as a last resort + String queryStringEncoding = + Constants.DEFAULT_CHARACTER_ENCODING; + + String uriEncoding = null; + boolean useBodyEncodingForURI = false; + + // Get encoding settings from request / connector if + // possible + String requestEncoding = req.getCharacterEncoding(); + if (req instanceof Request) { + uriEncoding = + ((Request)req).getConnector().getURIEncoding(); + useBodyEncodingForURI = ((Request)req) + .getConnector().getUseBodyEncodingForURI(); + } + + // If valid, apply settings from request / connector + if (uriEncoding != null) { + queryStringEncoding = uriEncoding; + } else if(useBodyEncodingForURI) { + if (requestEncoding != null) { + queryStringEncoding = requestEncoding; + } + } + + try { + retVal = URLDecoder.decode(queryString, + queryStringEncoding); + } catch (UnsupportedEncodingException e) { + retVal = queryString; + } + } + } + } + } else if(nameParts[0].equals("REMOTE")) { + if (nameParts[1].equals("ADDR")) { + retVal = req.getRemoteAddr(); + } else if (nameParts[1].equals("HOST")) { + retVal = req.getRemoteHost(); + } else if (nameParts[1].equals("IDENT")) { + retVal = null; // Not implemented + } else if (nameParts[1].equals("PORT")) { + retVal = Integer.toString( req.getRemotePort()); + } else if (nameParts[1].equals("USER")) { + retVal = req.getRemoteUser(); + } + } else if(nameParts[0].equals("REQUEST")) { + if (nameParts[1].equals("METHOD")) { + retVal = req.getMethod(); + } + else if (nameParts[1].equals("URI")) { + // If this is an error page, get the original URI + retVal = (String) req.getAttribute( + "javax.servlet.forward.request_uri"); + if (retVal == null) retVal=req.getRequestURI(); + } + } else if (nameParts[0].equals("SCRIPT")) { + String scriptName = req.getServletPath(); + if (nameParts[1].equals("FILENAME")) { + retVal = context.getRealPath(scriptName); + } + else if (nameParts[1].equals("NAME")) { + retVal = scriptName; + } + } else if (nameParts[0].equals("SERVER")) { + if (nameParts[1].equals("ADDR")) { + retVal = req.getLocalAddr(); + } + if (nameParts[1].equals("NAME")) { + retVal = req.getServerName(); + } else if (nameParts[1].equals("PORT")) { + retVal = Integer.toString(req.getServerPort()); + } else if (nameParts[1].equals("PROTOCOL")) { + retVal = req.getProtocol(); + } else if (nameParts[1].equals("SOFTWARE")) { + StringBuffer rv = new StringBuffer(context.getServerInfo()); + rv.append(" "); + rv.append(System.getProperty("java.vm.name")); + rv.append("/"); + rv.append(System.getProperty("java.vm.version")); + rv.append(" "); + rv.append(System.getProperty("os.name")); + retVal = rv.toString(); + } + } else if (name.equalsIgnoreCase("UNIQUE_ID")) { + retVal = req.getRequestedSessionId(); + } + if (requiredParts != nameParts.length) return null; + return retVal; + } + + public Date getCurrentDate() { + return new Date(); + } + + + protected String nullToEmptyString(String string) { + String retVal = string; + if (retVal == null) { + retVal = ""; + } + return retVal; + } + + + protected String getPathWithoutFileName(String servletPath) { + String retVal = null; + int lastSlash = servletPath.lastIndexOf('/'); + if (lastSlash >= 0) { + //cut off file namee + retVal = servletPath.substring(0, lastSlash + 1); + } + return retVal; + } + + + protected String getPathWithoutContext(String servletPath) { + String retVal = null; + int secondSlash = servletPath.indexOf('/', 1); + if (secondSlash >= 0) { + //cut off context + retVal = servletPath.substring(secondSlash); + } + return retVal; + } + + + protected String getAbsolutePath(String path) throws IOException { + String pathWithoutContext = SSIServletRequestUtil.getRelativePath(req); + String prefix = getPathWithoutFileName(pathWithoutContext); + if (prefix == null) { + throw new IOException("Couldn't remove filename from path: " + + pathWithoutContext); + } + String fullPath = prefix + path; + String retVal = SSIServletRequestUtil.normalize(fullPath); + if (retVal == null) { + throw new IOException("Normalization yielded null on path: " + + fullPath); + } + return retVal; + } + + + protected ServletContextAndPath getServletContextAndPathFromNonVirtualPath( + String nonVirtualPath) throws IOException { + if (nonVirtualPath.startsWith("/") || nonVirtualPath.startsWith("\\")) { + throw new IOException("A non-virtual path can't be absolute: " + + nonVirtualPath); + } + if (nonVirtualPath.indexOf("../") >= 0) { + throw new IOException("A non-virtual path can't contain '../' : " + + nonVirtualPath); + } + String path = getAbsolutePath(nonVirtualPath); + ServletContextAndPath csAndP = new ServletContextAndPath( + context, path); + return csAndP; + } + + + protected ServletContextAndPath getServletContextAndPathFromVirtualPath( + String virtualPath) throws IOException { + + if (!virtualPath.startsWith("/") && !virtualPath.startsWith("\\")) { + return new ServletContextAndPath(context, + getAbsolutePath(virtualPath)); + } else { + String normalized = SSIServletRequestUtil.normalize(virtualPath); + if (isVirtualWebappRelative) { + return new ServletContextAndPath(context, normalized); + } else { + ServletContext normContext = context.getContext(normalized); + if (normContext == null) { + throw new IOException("Couldn't get context for path: " + + normalized); + } + //If it's the root context, then there is no context element + // to remove, + // ie: + // '/file1.shtml' vs '/appName1/file1.shtml' + if (!isRootContext(normContext)) { + String noContext = getPathWithoutContext(normalized); + if (noContext == null) { + throw new IOException( + "Couldn't remove context from path: " + + normalized); + } + return new ServletContextAndPath(normContext, noContext); + } else { + return new ServletContextAndPath(normContext, normalized); + } + } + } + } + + + //Assumes servletContext is not-null + //Assumes that identity comparison will be true for the same context + //Assuming the above, getContext("/") will be non-null as long as the root + // context is + // accessible. + //If it isn't, then servletContext can't be the root context anyway, hence + // they will + // not match. + protected boolean isRootContext(ServletContext servletContext) { + return servletContext == servletContext.getContext("/"); + } + + + protected ServletContextAndPath getServletContextAndPath( + String originalPath, boolean virtual) throws IOException { + ServletContextAndPath csAndP = null; + if (debug > 0) { + log("SSIServletExternalResolver.getServletContextAndPath( " + + originalPath + ", " + virtual + ")", null); + } + if (virtual) { + csAndP = getServletContextAndPathFromVirtualPath(originalPath); + } else { + csAndP = getServletContextAndPathFromNonVirtualPath(originalPath); + } + return csAndP; + } + + + protected URLConnection getURLConnection(String originalPath, + boolean virtual) throws IOException { + ServletContextAndPath csAndP = getServletContextAndPath(originalPath, + virtual); + ServletContext context = csAndP.getServletContext(); + String path = csAndP.getPath(); + URL url = context.getResource(path); + if (url == null) { + throw new IOException("Context did not contain resource: " + path); + } + URLConnection urlConnection = url.openConnection(); + return urlConnection; + } + + + public long getFileLastModified(String path, boolean virtual) + throws IOException { + long lastModified = 0; + try { + URLConnection urlConnection = getURLConnection(path, virtual); + lastModified = urlConnection.getLastModified(); + } catch (IOException e) { + // Ignore this. It will always fail for non-file based includes + } + return lastModified; + } + + + public long getFileSize(String path, boolean virtual) throws IOException { + long fileSize = -1; + try { + URLConnection urlConnection = getURLConnection(path, virtual); + fileSize = urlConnection.getContentLength(); + } catch (IOException e) { + // Ignore this. It will always fail for non-file based includes + } + return fileSize; + } + + + //We are making lots of unnecessary copies of the included data here. If + //someone ever complains that this is slow, we should connect the included + // stream to the print writer that SSICommand uses. + public String getFileText(String originalPath, boolean virtual) + throws IOException { + try { + ServletContextAndPath csAndP = getServletContextAndPath( + originalPath, virtual); + ServletContext context = csAndP.getServletContext(); + String path = csAndP.getPath(); + RequestDispatcher rd = context.getRequestDispatcher(path); + if (rd == null) { + throw new IOException( + "Couldn't get request dispatcher for path: " + path); + } + ByteArrayServletOutputStream basos = + new ByteArrayServletOutputStream(); + ResponseIncludeWrapper responseIncludeWrapper = + new ResponseIncludeWrapper(context, req, res, basos); + rd.include(req, responseIncludeWrapper); + //We can't assume the included servlet flushed its output + responseIncludeWrapper.flushOutputStreamOrWriter(); + byte[] bytes = basos.toByteArray(); + + //Assume platform default encoding unless otherwise specified + String retVal; + if (inputEncoding == null) { + retVal = new String( bytes ); + } else { + retVal = new String (bytes, inputEncoding); + } + + //make an assumption that an empty response is a failure. This is + // a problem + // if a truly empty file + //were included, but not sure how else to tell. + if (retVal.equals("")) { + throw new IOException("Couldn't find file: " + path); + } + return retVal; + } catch (ServletException e) { + throw new IOException("Couldn't include file: " + originalPath + + " because of ServletException: " + e.getMessage()); + } + } + + protected class ServletContextAndPath { + protected ServletContext servletContext; + protected String path; + + + public ServletContextAndPath(ServletContext servletContext, + String path) { + this.servletContext = servletContext; + this.path = path; + } + + + public ServletContext getServletContext() { + return servletContext; + } + + + public String getPath() { + return path; + } + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIServletRequestUtil.java b/java/org/apache/catalina/ssi/SSIServletRequestUtil.java index 01b5e6a45..2a227e83f 100644 --- a/java/org/apache/catalina/ssi/SSIServletRequestUtil.java +++ b/java/org/apache/catalina/ssi/SSIServletRequestUtil.java @@ -1,71 +1,71 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import javax.servlet.http.HttpServletRequest; -import org.apache.catalina.util.RequestUtil; -public class SSIServletRequestUtil { - /** - * Return the relative path associated with this servlet. Taken from - * DefaultServlet.java. Perhaps this should be put in - * org.apache.catalina.util somewhere? Seems like it would be widely used. - * - * @param request - * The servlet request we are processing - */ - public static String getRelativePath(HttpServletRequest request) { - // Are we being processed by a RequestDispatcher.include()? - if (request.getAttribute("javax.servlet.include.request_uri") != null) { - String result = (String)request - .getAttribute("javax.servlet.include.path_info"); - if (result == null) - result = (String)request - .getAttribute("javax.servlet.include.servlet_path"); - if ((result == null) || (result.equals(""))) result = "/"; - return (result); - } - // No, extract the desired path directly from the request - String result = request.getPathInfo(); - if (result == null) { - result = request.getServletPath(); - } - if ((result == null) || (result.equals(""))) { - result = "/"; - } - return normalize(result); - } - - - /** - * Return a context-relative path, beginning with a "/", that represents - * the canonical version of the specified path after ".." and "." elements - * are resolved out. If the specified path attempts to go outside the - * boundaries of the current context (i.e. too many ".." path elements are - * present), return null instead. This normalize should be - * the same as DefaultServlet.normalize, which is almost the same ( see - * source code below ) as RequestUtil.normalize. Do we need all this - * duplication? - * - * @param path - * Path to be normalized - */ - public static String normalize(String path) { - if (path == null) return null; - String normalized = path; - //Why doesn't RequestUtil do this?? - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - normalized = RequestUtil.normalize(path); - return normalized; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import javax.servlet.http.HttpServletRequest; +import org.apache.catalina.util.RequestUtil; +public class SSIServletRequestUtil { + /** + * Return the relative path associated with this servlet. Taken from + * DefaultServlet.java. Perhaps this should be put in + * org.apache.catalina.util somewhere? Seems like it would be widely used. + * + * @param request + * The servlet request we are processing + */ + public static String getRelativePath(HttpServletRequest request) { + // Are we being processed by a RequestDispatcher.include()? + if (request.getAttribute("javax.servlet.include.request_uri") != null) { + String result = (String)request + .getAttribute("javax.servlet.include.path_info"); + if (result == null) + result = (String)request + .getAttribute("javax.servlet.include.servlet_path"); + if ((result == null) || (result.equals(""))) result = "/"; + return (result); + } + // No, extract the desired path directly from the request + String result = request.getPathInfo(); + if (result == null) { + result = request.getServletPath(); + } + if ((result == null) || (result.equals(""))) { + result = "/"; + } + return normalize(result); + } + + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements are + * present), return null instead. This normalize should be + * the same as DefaultServlet.normalize, which is almost the same ( see + * source code below ) as RequestUtil.normalize. Do we need all this + * duplication? + * + * @param path + * Path to be normalized + */ + public static String normalize(String path) { + if (path == null) return null; + String normalized = path; + //Why doesn't RequestUtil do this?? + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + normalized = RequestUtil.normalize(path); + return normalized; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSISet.java b/java/org/apache/catalina/ssi/SSISet.java index 1094010c6..b1250176b 100644 --- a/java/org/apache/catalina/ssi/SSISet.java +++ b/java/org/apache/catalina/ssi/SSISet.java @@ -1,58 +1,58 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -import java.io.PrintWriter; -/** - * Implements the Server-side #set command - * - * @author Paul Speed - * @author Dan Sandberg - * @author David Becker - * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ - */ -public class SSISet implements SSICommand { - /** - * @see SSICommand - */ - public long process(SSIMediator ssiMediator, String commandName, - String[] paramNames, String[] paramValues, PrintWriter writer) - throws SSIStopProcessingException { - long lastModified = 0; - String errorMessage = ssiMediator.getConfigErrMsg(); - String variableName = null; - for (int i = 0; i < paramNames.length; i++) { - String paramName = paramNames[i]; - String paramValue = paramValues[i]; - if (paramName.equalsIgnoreCase("var")) { - variableName = paramValue; - } else if (paramName.equalsIgnoreCase("value")) { - if (variableName != null) { - String substitutedValue = ssiMediator - .substituteVariables(paramValue); - ssiMediator.setVariableValue(variableName, - substitutedValue); - lastModified = System.currentTimeMillis(); - } else { - ssiMediator.log("#set--no variable specified"); - writer.write(errorMessage); - throw new SSIStopProcessingException(); - } - } else { - ssiMediator.log("#set--Invalid attribute: " + paramName); - writer.write(errorMessage); - throw new SSIStopProcessingException(); - } - } - return lastModified; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +import java.io.PrintWriter; +/** + * Implements the Server-side #set command + * + * @author Paul Speed + * @author Dan Sandberg + * @author David Becker + * @version $Revision: 303882 $, $Date: 2005-04-23 12:22:37 +0200 (sam., 23 avr. 2005) $ + */ +public class SSISet implements SSICommand { + /** + * @see SSICommand + */ + public long process(SSIMediator ssiMediator, String commandName, + String[] paramNames, String[] paramValues, PrintWriter writer) + throws SSIStopProcessingException { + long lastModified = 0; + String errorMessage = ssiMediator.getConfigErrMsg(); + String variableName = null; + for (int i = 0; i < paramNames.length; i++) { + String paramName = paramNames[i]; + String paramValue = paramValues[i]; + if (paramName.equalsIgnoreCase("var")) { + variableName = paramValue; + } else if (paramName.equalsIgnoreCase("value")) { + if (variableName != null) { + String substitutedValue = ssiMediator + .substituteVariables(paramValue); + ssiMediator.setVariableValue(variableName, + substitutedValue); + lastModified = System.currentTimeMillis(); + } else { + ssiMediator.log("#set--no variable specified"); + writer.write(errorMessage); + throw new SSIStopProcessingException(); + } + } else { + ssiMediator.log("#set--Invalid attribute: " + paramName); + writer.write(errorMessage); + throw new SSIStopProcessingException(); + } + } + return lastModified; + } } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/SSIStopProcessingException.java b/java/org/apache/catalina/ssi/SSIStopProcessingException.java index 7c8705b7d..8a8a50ebe 100644 --- a/java/org/apache/catalina/ssi/SSIStopProcessingException.java +++ b/java/org/apache/catalina/ssi/SSIStopProcessingException.java @@ -1,24 +1,24 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. Licensed under the - * Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License - * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable - * law or agreed to in writing, software distributed under the License is - * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the specific language - * governing permissions and limitations under the License. - */ -package org.apache.catalina.ssi; - - -/** - * Exception used to tell SSIProcessor that it should stop processing SSI - * commands. This is used to mimick the Apache behavior in #set with invalid - * attributes. - * - * @author Paul Speed - * @author Dan Sandberg - * @version $Revision: 303166 $, $Date: 2004-09-01 20:33:33 +0200 (mer., 01 sept. 2004) $ - */ -public class SSIStopProcessingException extends Exception { +/* + * Copyright 1999,2004 The Apache Software Foundation. Licensed under the + * Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License + * at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable + * law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.apache.catalina.ssi; + + +/** + * Exception used to tell SSIProcessor that it should stop processing SSI + * commands. This is used to mimick the Apache behavior in #set with invalid + * attributes. + * + * @author Paul Speed + * @author Dan Sandberg + * @version $Revision: 303166 $, $Date: 2004-09-01 20:33:33 +0200 (mer., 01 sept. 2004) $ + */ +public class SSIStopProcessingException extends Exception { } \ No newline at end of file diff --git a/java/org/apache/catalina/ssi/package.html b/java/org/apache/catalina/ssi/package.html index 9d882ab83..9d6f01196 100644 --- a/java/org/apache/catalina/ssi/package.html +++ b/java/org/apache/catalina/ssi/package.html @@ -1,16 +1,16 @@ - -

    This package contains code that is used by the SsiInvoker.

    -

    This class consists of SsiMediator.java which works as a -mediator between the different SsiCommands. To add a command you have to -implement the SsiCommand interface and extend the -SsiMediator. Commands currently implemented are

    - -
      -
    • SsiConfig - Implementation of the NCSA command Config i.e. <!--#config errmsg="error?"-->
    • -
    • SsiEcho - Implementation of the NCSA command Echo i.e. <!--#echo var="SERVER_NAME"-->
    • -
    • SsiExec - Not implemented
    • -
    • SsiFlastMod - Implementation of the NCSA command flastmod i.e. <!--#flastmod virtual="file"-->
    • -
    • SsiFsize - Implementation of the NCSA command fsize i.e. <!--#fsize file="file"-->
    • -
    • SsiInclude - Implementation of the NCSA command Include i.e. <!--#config virtual="includefile"-->
    • -
    - + +

    This package contains code that is used by the SsiInvoker.

    +

    This class consists of SsiMediator.java which works as a +mediator between the different SsiCommands. To add a command you have to +implement the SsiCommand interface and extend the +SsiMediator. Commands currently implemented are

    + +
      +
    • SsiConfig - Implementation of the NCSA command Config i.e. <!--#config errmsg="error?"-->
    • +
    • SsiEcho - Implementation of the NCSA command Echo i.e. <!--#echo var="SERVER_NAME"-->
    • +
    • SsiExec - Not implemented
    • +
    • SsiFlastMod - Implementation of the NCSA command flastmod i.e. <!--#flastmod virtual="file"-->
    • +
    • SsiFsize - Implementation of the NCSA command fsize i.e. <!--#fsize file="file"-->
    • +
    • SsiInclude - Implementation of the NCSA command Include i.e. <!--#config virtual="includefile"-->
    • +
    + diff --git a/java/org/apache/catalina/startup/Authenticators.properties b/java/org/apache/catalina/startup/Authenticators.properties index 9e0aae7e0..e5e623adb 100644 --- a/java/org/apache/catalina/startup/Authenticators.properties +++ b/java/org/apache/catalina/startup/Authenticators.properties @@ -1,5 +1,5 @@ -BASIC=org.apache.catalina.authenticator.BasicAuthenticator -CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator -DIGEST=org.apache.catalina.authenticator.DigestAuthenticator -FORM=org.apache.catalina.authenticator.FormAuthenticator -NONE=org.apache.catalina.authenticator.NonLoginAuthenticator +BASIC=org.apache.catalina.authenticator.BasicAuthenticator +CLIENT-CERT=org.apache.catalina.authenticator.SSLAuthenticator +DIGEST=org.apache.catalina.authenticator.DigestAuthenticator +FORM=org.apache.catalina.authenticator.FormAuthenticator +NONE=org.apache.catalina.authenticator.NonLoginAuthenticator diff --git a/java/org/apache/catalina/startup/Catalina.java b/java/org/apache/catalina/startup/Catalina.java index a55b0e95a..8d5fa7439 100644 --- a/java/org/apache/catalina/startup/Catalina.java +++ b/java/org/apache/catalina/startup/Catalina.java @@ -1,688 +1,688 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.net.Socket; -import org.apache.catalina.Container; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.Server; -import org.apache.catalina.core.StandardServer; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.Rule; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; - - -/** - * Startup/Shutdown shell program for Catalina. The following command line - * options are recognized: - *
      - *
    • -config {pathname} - Set the pathname of the configuration file - * to be processed. If a relative path is specified, it will be - * interpreted as relative to the directory pathname specified by the - * "catalina.base" system property. [conf/server.xml] - *
    • -help - Display usage information. - *
    • -stop - Stop the currently running instance of Catalina. - * - * - * Should do the same thing as Embedded, but using a server.xml file. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 380229 $ $Date: 2006-02-23 22:28:29 +0100 (jeu., 23 févr. 2006) $ - */ - -public class Catalina extends Embedded { - - - // ----------------------------------------------------- Instance Variables - - - /** - * Pathname to the server configuration file. - */ - protected String configFile = "conf/server.xml"; - - // XXX Should be moved to embedded - /** - * The shared extensions class loader for this server. - */ - protected ClassLoader parentClassLoader = - Catalina.class.getClassLoader(); - - - /** - * The server component we are starting or stopping - */ - protected Server server = null; - - - /** - * Are we starting a new server? - */ - protected boolean starting = false; - - - /** - * Are we stopping an existing server? - */ - protected boolean stopping = false; - - - /** - * Use shutdown hook flag. - */ - protected boolean useShutdownHook = true; - - - /** - * Shutdown hook. - */ - protected Thread shutdownHook = null; - - - // ------------------------------------------------------------- Properties - - - public void setConfig(String file) { - configFile = file; - } - - - public void setConfigFile(String file) { - configFile = file; - } - - - public String getConfigFile() { - return configFile; - } - - - public void setUseShutdownHook(boolean useShutdownHook) { - this.useShutdownHook = useShutdownHook; - } - - - public boolean getUseShutdownHook() { - return useShutdownHook; - } - - - /** - * Set the shared extensions class loader. - * - * @param parentClassLoader The shared extensions class loader. - */ - public void setParentClassLoader(ClassLoader parentClassLoader) { - - this.parentClassLoader = parentClassLoader; - - } - - - /** - * Set the server instance we are configuring. - * - * @param server The new server - */ - public void setServer(Server server) { - - this.server = server; - - } - - // ----------------------------------------------------------- Main Program - - /** - * The application main program. - * - * @param args Command line arguments - */ - public static void main(String args[]) { - (new Catalina()).process(args); - } - - - /** - * The instance main program. - * - * @param args Command line arguments - */ - public void process(String args[]) { - - setAwait(true); - setCatalinaHome(); - setCatalinaBase(); - try { - if (arguments(args)) { - if (starting) { - load(args); - start(); - } else if (stopping) { - stopServer(); - } - } - } catch (Exception e) { - e.printStackTrace(System.out); - } - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Process the specified command line arguments, and return - * true if we should continue processing; otherwise - * return false. - * - * @param args Command line arguments to process - */ - protected boolean arguments(String args[]) { - - boolean isConfig = false; - - if (args.length < 1) { - usage(); - return (false); - } - - for (int i = 0; i < args.length; i++) { - if (isConfig) { - configFile = args[i]; - isConfig = false; - } else if (args[i].equals("-config")) { - isConfig = true; - } else if (args[i].equals("-nonaming")) { - setUseNaming( false ); - } else if (args[i].equals("-help")) { - usage(); - return (false); - } else if (args[i].equals("start")) { - starting = true; - stopping = false; - } else if (args[i].equals("stop")) { - starting = false; - stopping = true; - } else { - usage(); - return (false); - } - } - - return (true); - - } - - - /** - * Return a File object representing our configuration file. - */ - protected File configFile() { - - File file = new File(configFile); - if (!file.isAbsolute()) - file = new File(System.getProperty("catalina.base"), configFile); - return (file); - - } - - - /** - * Create and configure the Digester we will be using for startup. - */ - protected Digester createStartDigester() { - long t1=System.currentTimeMillis(); - // Initialize the digester - Digester digester = new Digester(); - digester.setValidating(false); - digester.setClassLoader(StandardServer.class.getClassLoader()); - - // Configure the actions we will be using - digester.addObjectCreate("Server", - "org.apache.catalina.core.StandardServer", - "className"); - digester.addSetProperties("Server"); - digester.addSetNext("Server", - "setServer", - "org.apache.catalina.Server"); - - digester.addObjectCreate("Server/GlobalNamingResources", - "org.apache.catalina.deploy.NamingResources"); - digester.addSetProperties("Server/GlobalNamingResources"); - digester.addSetNext("Server/GlobalNamingResources", - "setGlobalNamingResources", - "org.apache.catalina.deploy.NamingResources"); - - digester.addObjectCreate("Server/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties("Server/Listener"); - digester.addSetNext("Server/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - digester.addObjectCreate("Server/Service", - "org.apache.catalina.core.StandardService", - "className"); - digester.addSetProperties("Server/Service"); - digester.addSetNext("Server/Service", - "addService", - "org.apache.catalina.Service"); - - digester.addObjectCreate("Server/Service/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties("Server/Service/Listener"); - digester.addSetNext("Server/Service/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - digester.addRule("Server/Service/Connector", - new ConnectorCreateRule()); - digester.addRule("Server/Service/Connector", - new SetAllPropertiesRule()); - digester.addSetNext("Server/Service/Connector", - "addConnector", - "org.apache.catalina.connector.Connector"); - - digester.addObjectCreate("Server/Service/Connector/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties("Server/Service/Connector/Listener"); - digester.addSetNext("Server/Service/Connector/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - // Add RuleSets for nested elements - digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/")); - digester.addRuleSet(new EngineRuleSet("Server/Service/")); - digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); - digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/")); - digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/")); - digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/")); - - // When the 'engine' is found, set the parentClassLoader. - digester.addRule("Server/Service/Engine", - new SetParentClassLoaderRule(parentClassLoader)); - digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/")); - - long t2=System.currentTimeMillis(); - if (log.isDebugEnabled()) - log.debug("Digester for server.xml created " + ( t2-t1 )); - return (digester); - - } - - - /** - * Create and configure the Digester we will be using for shutdown. - */ - protected Digester createStopDigester() { - - // Initialize the digester - Digester digester = new Digester(); - - // Configure the rules we need for shutting down - digester.addObjectCreate("Server", - "org.apache.catalina.core.StandardServer", - "className"); - digester.addSetProperties("Server"); - digester.addSetNext("Server", - "setServer", - "org.apache.catalina.Server"); - - return (digester); - - } - - - public void stopServer() { - stopServer(null); - } - - public void stopServer(String[] arguments) { - - if (arguments != null) { - arguments(arguments); - } - - if( server == null ) { - // Create and execute our Digester - Digester digester = createStopDigester(); - digester.setClassLoader(Thread.currentThread().getContextClassLoader()); - File file = configFile(); - try { - InputSource is = - new InputSource("file://" + file.getAbsolutePath()); - FileInputStream fis = new FileInputStream(file); - is.setByteStream(fis); - digester.push(this); - digester.parse(is); - fis.close(); - } catch (Exception e) { - log.error("Catalina.stop: ", e); - System.exit(1); - } - } - - // Stop the existing server - try { - Socket socket = new Socket("127.0.0.1", server.getPort()); - OutputStream stream = socket.getOutputStream(); - String shutdown = server.getShutdown(); - for (int i = 0; i < shutdown.length(); i++) - stream.write(shutdown.charAt(i)); - stream.flush(); - stream.close(); - socket.close(); - } catch (IOException e) { - log.error("Catalina.stop: ", e); - System.exit(1); - } - - } - - - /** - * Set the catalina.base System property to the current - * working directory if it has not been set. - * @deprecated Use initDirs() - */ - public void setCatalinaBase() { - initDirs(); - } - - /** - * Set the catalina.home System property to the current - * working directory if it has not been set. - * @deprecated Use initDirs() - */ - public void setCatalinaHome() { - initDirs(); - } - - /** - * Start a new server instance. - */ - public void load() { - - initDirs(); - - // Before digester - it may be needed - - initNaming(); - - // Create and execute our Digester - Digester digester = createStartDigester(); - long t1 = System.currentTimeMillis(); - - Exception ex = null; - InputSource inputSource = null; - InputStream inputStream = null; - File file = null; - try { - file = configFile(); - inputStream = new FileInputStream(file); - inputSource = new InputSource("file://" + file.getAbsolutePath()); - } catch (Exception e) { - ; - } - if (inputStream == null) { - try { - inputStream = getClass().getClassLoader() - .getResourceAsStream(getConfigFile()); - inputSource = new InputSource - (getClass().getClassLoader() - .getResource(getConfigFile()).toString()); - } catch (Exception e) { - ; - } - } - - // This should be included in catalina.jar - // Alternative: don't bother with xml, just create it manually. - if( inputStream==null ) { - try { - inputStream = getClass().getClassLoader() - .getResourceAsStream("server-embed.xml"); - inputSource = new InputSource - (getClass().getClassLoader() - .getResource("server-embed.xml").toString()); - } catch (Exception e) { - ; - } - } - - - if ((inputStream == null) && (file != null)) { - log.warn("Can't load server.xml from " + file.getAbsolutePath()); - return; - } - - try { - inputSource.setByteStream(inputStream); - digester.push(this); - digester.parse(inputSource); - inputStream.close(); - } catch (Exception e) { - log.warn("Catalina.start using " - + getConfigFile() + ": " , e); - return; - } - - // Stream redirection - initStreams(); - - // Start the new server - if (server instanceof Lifecycle) { - try { - server.initialize(); - } catch (LifecycleException e) { - log.error("Catalina.start", e); - } - } - - long t2 = System.currentTimeMillis(); - if(log.isInfoEnabled()) - log.info("Initialization processed in " + (t2 - t1) + " ms"); - - } - - - /* - * Load using arguments - */ - public void load(String args[]) { - - try { - if (arguments(args)) - load(); - } catch (Exception e) { - e.printStackTrace(System.out); - } - } - - public void create() { - - } - - public void destroy() { - - } - - /** - * Start a new server instance. - */ - public void start() { - - if (server == null) { - load(); - } - - long t1 = System.currentTimeMillis(); - - // Start the new server - if (server instanceof Lifecycle) { - try { - ((Lifecycle) server).start(); - } catch (LifecycleException e) { - log.error("Catalina.start: ", e); - } - } - - long t2 = System.currentTimeMillis(); - if(log.isInfoEnabled()) - log.info("Server startup in " + (t2 - t1) + " ms"); - - try { - // Register shutdown hook - if (useShutdownHook) { - if (shutdownHook == null) { - shutdownHook = new CatalinaShutdownHook(); - } - Runtime.getRuntime().addShutdownHook(shutdownHook); - } - } catch (Throwable t) { - // This will fail on JDK 1.2. Ignoring, as Tomcat can run - // fine without the shutdown hook. - } - - if (await) { - await(); - stop(); - } - - } - - - /** - * Stop an existing server instance. - */ - public void stop() { - - try { - // Remove the ShutdownHook first so that server.stop() - // doesn't get invoked twice - if (useShutdownHook) { - Runtime.getRuntime().removeShutdownHook(shutdownHook); - } - } catch (Throwable t) { - // This will fail on JDK 1.2. Ignoring, as Tomcat can run - // fine without the shutdown hook. - } - - // Shut down the server - if (server instanceof Lifecycle) { - try { - ((Lifecycle) server).stop(); - } catch (LifecycleException e) { - log.error("Catalina.stop", e); - } - } - - } - - - /** - * Await and shutdown. - */ - public void await() { - - server.await(); - - } - - - /** - * Print usage information for this application. - */ - protected void usage() { - - System.out.println - ("usage: java org.apache.catalina.startup.Catalina" - + " [ -config {pathname} ]" - + " [ -nonaming ] { start | stop }"); - - } - - - // --------------------------------------- CatalinaShutdownHook Inner Class - - // XXX Should be moved to embedded ! - /** - * Shutdown hook which will perform a clean shutdown of Catalina if needed. - */ - protected class CatalinaShutdownHook extends Thread { - - public void run() { - - if (server != null) { - Catalina.this.stop(); - } - - } - - } - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( Catalina.class ); - -} - - -// ------------------------------------------------------------ Private Classes - - -/** - * Rule that sets the parent class loader for the top object on the stack, - * which must be a Container. - */ - -final class SetParentClassLoaderRule extends Rule { - - public SetParentClassLoaderRule(ClassLoader parentClassLoader) { - - this.parentClassLoader = parentClassLoader; - - } - - ClassLoader parentClassLoader = null; - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("Setting parent class loader"); - - Container top = (Container) digester.peek(); - top.setParentClassLoader(parentClassLoader); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import org.apache.catalina.Container; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.Server; +import org.apache.catalina.core.StandardServer; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.Rule; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; + + +/** + * Startup/Shutdown shell program for Catalina. The following command line + * options are recognized: + *
        + *
      • -config {pathname} - Set the pathname of the configuration file + * to be processed. If a relative path is specified, it will be + * interpreted as relative to the directory pathname specified by the + * "catalina.base" system property. [conf/server.xml] + *
      • -help - Display usage information. + *
      • -stop - Stop the currently running instance of Catalina. + * + * + * Should do the same thing as Embedded, but using a server.xml file. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 380229 $ $Date: 2006-02-23 22:28:29 +0100 (jeu., 23 févr. 2006) $ + */ + +public class Catalina extends Embedded { + + + // ----------------------------------------------------- Instance Variables + + + /** + * Pathname to the server configuration file. + */ + protected String configFile = "conf/server.xml"; + + // XXX Should be moved to embedded + /** + * The shared extensions class loader for this server. + */ + protected ClassLoader parentClassLoader = + Catalina.class.getClassLoader(); + + + /** + * The server component we are starting or stopping + */ + protected Server server = null; + + + /** + * Are we starting a new server? + */ + protected boolean starting = false; + + + /** + * Are we stopping an existing server? + */ + protected boolean stopping = false; + + + /** + * Use shutdown hook flag. + */ + protected boolean useShutdownHook = true; + + + /** + * Shutdown hook. + */ + protected Thread shutdownHook = null; + + + // ------------------------------------------------------------- Properties + + + public void setConfig(String file) { + configFile = file; + } + + + public void setConfigFile(String file) { + configFile = file; + } + + + public String getConfigFile() { + return configFile; + } + + + public void setUseShutdownHook(boolean useShutdownHook) { + this.useShutdownHook = useShutdownHook; + } + + + public boolean getUseShutdownHook() { + return useShutdownHook; + } + + + /** + * Set the shared extensions class loader. + * + * @param parentClassLoader The shared extensions class loader. + */ + public void setParentClassLoader(ClassLoader parentClassLoader) { + + this.parentClassLoader = parentClassLoader; + + } + + + /** + * Set the server instance we are configuring. + * + * @param server The new server + */ + public void setServer(Server server) { + + this.server = server; + + } + + // ----------------------------------------------------------- Main Program + + /** + * The application main program. + * + * @param args Command line arguments + */ + public static void main(String args[]) { + (new Catalina()).process(args); + } + + + /** + * The instance main program. + * + * @param args Command line arguments + */ + public void process(String args[]) { + + setAwait(true); + setCatalinaHome(); + setCatalinaBase(); + try { + if (arguments(args)) { + if (starting) { + load(args); + start(); + } else if (stopping) { + stopServer(); + } + } + } catch (Exception e) { + e.printStackTrace(System.out); + } + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Process the specified command line arguments, and return + * true if we should continue processing; otherwise + * return false. + * + * @param args Command line arguments to process + */ + protected boolean arguments(String args[]) { + + boolean isConfig = false; + + if (args.length < 1) { + usage(); + return (false); + } + + for (int i = 0; i < args.length; i++) { + if (isConfig) { + configFile = args[i]; + isConfig = false; + } else if (args[i].equals("-config")) { + isConfig = true; + } else if (args[i].equals("-nonaming")) { + setUseNaming( false ); + } else if (args[i].equals("-help")) { + usage(); + return (false); + } else if (args[i].equals("start")) { + starting = true; + stopping = false; + } else if (args[i].equals("stop")) { + starting = false; + stopping = true; + } else { + usage(); + return (false); + } + } + + return (true); + + } + + + /** + * Return a File object representing our configuration file. + */ + protected File configFile() { + + File file = new File(configFile); + if (!file.isAbsolute()) + file = new File(System.getProperty("catalina.base"), configFile); + return (file); + + } + + + /** + * Create and configure the Digester we will be using for startup. + */ + protected Digester createStartDigester() { + long t1=System.currentTimeMillis(); + // Initialize the digester + Digester digester = new Digester(); + digester.setValidating(false); + digester.setClassLoader(StandardServer.class.getClassLoader()); + + // Configure the actions we will be using + digester.addObjectCreate("Server", + "org.apache.catalina.core.StandardServer", + "className"); + digester.addSetProperties("Server"); + digester.addSetNext("Server", + "setServer", + "org.apache.catalina.Server"); + + digester.addObjectCreate("Server/GlobalNamingResources", + "org.apache.catalina.deploy.NamingResources"); + digester.addSetProperties("Server/GlobalNamingResources"); + digester.addSetNext("Server/GlobalNamingResources", + "setGlobalNamingResources", + "org.apache.catalina.deploy.NamingResources"); + + digester.addObjectCreate("Server/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties("Server/Listener"); + digester.addSetNext("Server/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + digester.addObjectCreate("Server/Service", + "org.apache.catalina.core.StandardService", + "className"); + digester.addSetProperties("Server/Service"); + digester.addSetNext("Server/Service", + "addService", + "org.apache.catalina.Service"); + + digester.addObjectCreate("Server/Service/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties("Server/Service/Listener"); + digester.addSetNext("Server/Service/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + digester.addRule("Server/Service/Connector", + new ConnectorCreateRule()); + digester.addRule("Server/Service/Connector", + new SetAllPropertiesRule()); + digester.addSetNext("Server/Service/Connector", + "addConnector", + "org.apache.catalina.connector.Connector"); + + digester.addObjectCreate("Server/Service/Connector/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties("Server/Service/Connector/Listener"); + digester.addSetNext("Server/Service/Connector/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + // Add RuleSets for nested elements + digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/")); + digester.addRuleSet(new EngineRuleSet("Server/Service/")); + digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); + digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/")); + digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/")); + digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/")); + + // When the 'engine' is found, set the parentClassLoader. + digester.addRule("Server/Service/Engine", + new SetParentClassLoaderRule(parentClassLoader)); + digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/")); + + long t2=System.currentTimeMillis(); + if (log.isDebugEnabled()) + log.debug("Digester for server.xml created " + ( t2-t1 )); + return (digester); + + } + + + /** + * Create and configure the Digester we will be using for shutdown. + */ + protected Digester createStopDigester() { + + // Initialize the digester + Digester digester = new Digester(); + + // Configure the rules we need for shutting down + digester.addObjectCreate("Server", + "org.apache.catalina.core.StandardServer", + "className"); + digester.addSetProperties("Server"); + digester.addSetNext("Server", + "setServer", + "org.apache.catalina.Server"); + + return (digester); + + } + + + public void stopServer() { + stopServer(null); + } + + public void stopServer(String[] arguments) { + + if (arguments != null) { + arguments(arguments); + } + + if( server == null ) { + // Create and execute our Digester + Digester digester = createStopDigester(); + digester.setClassLoader(Thread.currentThread().getContextClassLoader()); + File file = configFile(); + try { + InputSource is = + new InputSource("file://" + file.getAbsolutePath()); + FileInputStream fis = new FileInputStream(file); + is.setByteStream(fis); + digester.push(this); + digester.parse(is); + fis.close(); + } catch (Exception e) { + log.error("Catalina.stop: ", e); + System.exit(1); + } + } + + // Stop the existing server + try { + Socket socket = new Socket("127.0.0.1", server.getPort()); + OutputStream stream = socket.getOutputStream(); + String shutdown = server.getShutdown(); + for (int i = 0; i < shutdown.length(); i++) + stream.write(shutdown.charAt(i)); + stream.flush(); + stream.close(); + socket.close(); + } catch (IOException e) { + log.error("Catalina.stop: ", e); + System.exit(1); + } + + } + + + /** + * Set the catalina.base System property to the current + * working directory if it has not been set. + * @deprecated Use initDirs() + */ + public void setCatalinaBase() { + initDirs(); + } + + /** + * Set the catalina.home System property to the current + * working directory if it has not been set. + * @deprecated Use initDirs() + */ + public void setCatalinaHome() { + initDirs(); + } + + /** + * Start a new server instance. + */ + public void load() { + + initDirs(); + + // Before digester - it may be needed + + initNaming(); + + // Create and execute our Digester + Digester digester = createStartDigester(); + long t1 = System.currentTimeMillis(); + + Exception ex = null; + InputSource inputSource = null; + InputStream inputStream = null; + File file = null; + try { + file = configFile(); + inputStream = new FileInputStream(file); + inputSource = new InputSource("file://" + file.getAbsolutePath()); + } catch (Exception e) { + ; + } + if (inputStream == null) { + try { + inputStream = getClass().getClassLoader() + .getResourceAsStream(getConfigFile()); + inputSource = new InputSource + (getClass().getClassLoader() + .getResource(getConfigFile()).toString()); + } catch (Exception e) { + ; + } + } + + // This should be included in catalina.jar + // Alternative: don't bother with xml, just create it manually. + if( inputStream==null ) { + try { + inputStream = getClass().getClassLoader() + .getResourceAsStream("server-embed.xml"); + inputSource = new InputSource + (getClass().getClassLoader() + .getResource("server-embed.xml").toString()); + } catch (Exception e) { + ; + } + } + + + if ((inputStream == null) && (file != null)) { + log.warn("Can't load server.xml from " + file.getAbsolutePath()); + return; + } + + try { + inputSource.setByteStream(inputStream); + digester.push(this); + digester.parse(inputSource); + inputStream.close(); + } catch (Exception e) { + log.warn("Catalina.start using " + + getConfigFile() + ": " , e); + return; + } + + // Stream redirection + initStreams(); + + // Start the new server + if (server instanceof Lifecycle) { + try { + server.initialize(); + } catch (LifecycleException e) { + log.error("Catalina.start", e); + } + } + + long t2 = System.currentTimeMillis(); + if(log.isInfoEnabled()) + log.info("Initialization processed in " + (t2 - t1) + " ms"); + + } + + + /* + * Load using arguments + */ + public void load(String args[]) { + + try { + if (arguments(args)) + load(); + } catch (Exception e) { + e.printStackTrace(System.out); + } + } + + public void create() { + + } + + public void destroy() { + + } + + /** + * Start a new server instance. + */ + public void start() { + + if (server == null) { + load(); + } + + long t1 = System.currentTimeMillis(); + + // Start the new server + if (server instanceof Lifecycle) { + try { + ((Lifecycle) server).start(); + } catch (LifecycleException e) { + log.error("Catalina.start: ", e); + } + } + + long t2 = System.currentTimeMillis(); + if(log.isInfoEnabled()) + log.info("Server startup in " + (t2 - t1) + " ms"); + + try { + // Register shutdown hook + if (useShutdownHook) { + if (shutdownHook == null) { + shutdownHook = new CatalinaShutdownHook(); + } + Runtime.getRuntime().addShutdownHook(shutdownHook); + } + } catch (Throwable t) { + // This will fail on JDK 1.2. Ignoring, as Tomcat can run + // fine without the shutdown hook. + } + + if (await) { + await(); + stop(); + } + + } + + + /** + * Stop an existing server instance. + */ + public void stop() { + + try { + // Remove the ShutdownHook first so that server.stop() + // doesn't get invoked twice + if (useShutdownHook) { + Runtime.getRuntime().removeShutdownHook(shutdownHook); + } + } catch (Throwable t) { + // This will fail on JDK 1.2. Ignoring, as Tomcat can run + // fine without the shutdown hook. + } + + // Shut down the server + if (server instanceof Lifecycle) { + try { + ((Lifecycle) server).stop(); + } catch (LifecycleException e) { + log.error("Catalina.stop", e); + } + } + + } + + + /** + * Await and shutdown. + */ + public void await() { + + server.await(); + + } + + + /** + * Print usage information for this application. + */ + protected void usage() { + + System.out.println + ("usage: java org.apache.catalina.startup.Catalina" + + " [ -config {pathname} ]" + + " [ -nonaming ] { start | stop }"); + + } + + + // --------------------------------------- CatalinaShutdownHook Inner Class + + // XXX Should be moved to embedded ! + /** + * Shutdown hook which will perform a clean shutdown of Catalina if needed. + */ + protected class CatalinaShutdownHook extends Thread { + + public void run() { + + if (server != null) { + Catalina.this.stop(); + } + + } + + } + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( Catalina.class ); + +} + + +// ------------------------------------------------------------ Private Classes + + +/** + * Rule that sets the parent class loader for the top object on the stack, + * which must be a Container. + */ + +final class SetParentClassLoaderRule extends Rule { + + public SetParentClassLoaderRule(ClassLoader parentClassLoader) { + + this.parentClassLoader = parentClassLoader; + + } + + ClassLoader parentClassLoader = null; + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("Setting parent class loader"); + + Container top = (Container) digester.peek(); + top.setParentClassLoader(parentClassLoader); + + } + + +} diff --git a/java/org/apache/catalina/startup/CatalinaProperties.java b/java/org/apache/catalina/startup/CatalinaProperties.java index 0d76c5865..6720d6a12 100644 --- a/java/org/apache/catalina/startup/CatalinaProperties.java +++ b/java/org/apache/catalina/startup/CatalinaProperties.java @@ -1,171 +1,171 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.net.URL; -import java.util.Enumeration; -import java.util.Properties; - - -/** - * Utility class to read the bootstrap Catalina configuration. - * - * @author Remy Maucherat - * @version $Revision: 304109 $ $Date: 2005-09-29 16:36:25 +0200 (jeu., 29 sept. 2005) $ - */ - -public class CatalinaProperties { - - - // ------------------------------------------------------- Static Variables - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( CatalinaProperties.class ); - - private static Properties properties = null; - - - static { - - loadProperties(); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return specified property value. - */ - public static String getProperty(String name) { - - return properties.getProperty(name); - - } - - - /** - * Return specified property value. - */ - public static String getProperty(String name, String defaultValue) { - - return properties.getProperty(name, defaultValue); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Load properties. - */ - private static void loadProperties() { - - InputStream is = null; - Throwable error = null; - - try { - String configUrl = getConfigUrl(); - if (configUrl != null) { - is = (new URL(configUrl)).openStream(); - } - } catch (Throwable t) { - // Ignore - } - - if (is == null) { - try { - File home = new File(getCatalinaBase()); - File conf = new File(home, "conf"); - File properties = new File(conf, "catalina.properties"); - is = new FileInputStream(properties); - } catch (Throwable t) { - // Ignore - } - } - - if (is == null) { - try { - is = CatalinaProperties.class.getResourceAsStream - ("/org/apache/catalina/startup/catalina.properties"); - } catch (Throwable t) { - // Ignore - } - } - - if (is != null) { - try { - properties = new Properties(); - properties.load(is); - is.close(); - } catch (Throwable t) { - error = t; - } - } - - if ((is == null) || (error != null)) { - // Do something - log.warn("Failed to load catalina.properties", error); - // That's fine - we have reasonable defaults. - properties=new Properties(); - } - - // Register the properties as system properties - Enumeration enumeration = properties.propertyNames(); - while (enumeration.hasMoreElements()) { - String name = (String) enumeration.nextElement(); - String value = properties.getProperty(name); - if (value != null) { - System.setProperty(name, value); - } - } - - } - - - /** - * Get the value of the catalina.home environment variable. - */ - private static String getCatalinaHome() { - return System.getProperty("catalina.home", - System.getProperty("user.dir")); - } - - - /** - * Get the value of the catalina.base environment variable. - */ - private static String getCatalinaBase() { - return System.getProperty("catalina.base", getCatalinaHome()); - } - - - /** - * Get the value of the configuration URL. - */ - private static String getConfigUrl() { - return System.getProperty("catalina.config"); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; +import java.util.Enumeration; +import java.util.Properties; + + +/** + * Utility class to read the bootstrap Catalina configuration. + * + * @author Remy Maucherat + * @version $Revision: 304109 $ $Date: 2005-09-29 16:36:25 +0200 (jeu., 29 sept. 2005) $ + */ + +public class CatalinaProperties { + + + // ------------------------------------------------------- Static Variables + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( CatalinaProperties.class ); + + private static Properties properties = null; + + + static { + + loadProperties(); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return specified property value. + */ + public static String getProperty(String name) { + + return properties.getProperty(name); + + } + + + /** + * Return specified property value. + */ + public static String getProperty(String name, String defaultValue) { + + return properties.getProperty(name, defaultValue); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Load properties. + */ + private static void loadProperties() { + + InputStream is = null; + Throwable error = null; + + try { + String configUrl = getConfigUrl(); + if (configUrl != null) { + is = (new URL(configUrl)).openStream(); + } + } catch (Throwable t) { + // Ignore + } + + if (is == null) { + try { + File home = new File(getCatalinaBase()); + File conf = new File(home, "conf"); + File properties = new File(conf, "catalina.properties"); + is = new FileInputStream(properties); + } catch (Throwable t) { + // Ignore + } + } + + if (is == null) { + try { + is = CatalinaProperties.class.getResourceAsStream + ("/org/apache/catalina/startup/catalina.properties"); + } catch (Throwable t) { + // Ignore + } + } + + if (is != null) { + try { + properties = new Properties(); + properties.load(is); + is.close(); + } catch (Throwable t) { + error = t; + } + } + + if ((is == null) || (error != null)) { + // Do something + log.warn("Failed to load catalina.properties", error); + // That's fine - we have reasonable defaults. + properties=new Properties(); + } + + // Register the properties as system properties + Enumeration enumeration = properties.propertyNames(); + while (enumeration.hasMoreElements()) { + String name = (String) enumeration.nextElement(); + String value = properties.getProperty(name); + if (value != null) { + System.setProperty(name, value); + } + } + + } + + + /** + * Get the value of the catalina.home environment variable. + */ + private static String getCatalinaHome() { + return System.getProperty("catalina.home", + System.getProperty("user.dir")); + } + + + /** + * Get the value of the catalina.base environment variable. + */ + private static String getCatalinaBase() { + return System.getProperty("catalina.base", getCatalinaHome()); + } + + + /** + * Get the value of the configuration URL. + */ + private static String getConfigUrl() { + return System.getProperty("catalina.config"); + } + + +} diff --git a/java/org/apache/catalina/startup/ConnectorCreateRule.java b/java/org/apache/catalina/startup/ConnectorCreateRule.java index b19bb0cd6..96f030d74 100644 --- a/java/org/apache/catalina/startup/ConnectorCreateRule.java +++ b/java/org/apache/catalina/startup/ConnectorCreateRule.java @@ -1,55 +1,55 @@ -/* $Id: ConnectorCreateRule.java 303287 2004-09-29 09:55:39Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.catalina.connector.Connector; -import org.apache.tomcat.util.digester.Rule; -import org.xml.sax.Attributes; - - -/** - * Rule implementation that creates a connector. - */ - -public class ConnectorCreateRule extends Rule { - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the beginning of this element. - * - * @param attributes The attribute list of this element - */ - public void begin(Attributes attributes) throws Exception { - digester.push(new Connector(attributes.getValue("protocol"))); - } - - - /** - * Process the end of this element. - */ - public void end() throws Exception { - Object top = digester.pop(); - } - - -} +/* $Id: ConnectorCreateRule.java 303287 2004-09-29 09:55:39Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.catalina.connector.Connector; +import org.apache.tomcat.util.digester.Rule; +import org.xml.sax.Attributes; + + +/** + * Rule implementation that creates a connector. + */ + +public class ConnectorCreateRule extends Rule { + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + public void begin(Attributes attributes) throws Exception { + digester.push(new Connector(attributes.getValue("protocol"))); + } + + + /** + * Process the end of this element. + */ + public void end() throws Exception { + Object top = digester.pop(); + } + + +} diff --git a/java/org/apache/catalina/startup/Constants.java b/java/org/apache/catalina/startup/Constants.java index 71a497a56..289401af5 100644 --- a/java/org/apache/catalina/startup/Constants.java +++ b/java/org/apache/catalina/startup/Constants.java @@ -1,95 +1,95 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -/** - * String constants for the startup package. - * - * @author Craig R. McClanahan - * @author Jean-Francois Arcand - * @version $Revision: 303179 $ $Date: 2004-09-02 12:28:00 +0200 (jeu., 02 sept. 2004) $ - */ - -public final class Constants { - - public static final String Package = "org.apache.catalina.startup"; - - public static final String ApplicationContextXml = "META-INF/context.xml"; - public static final String ApplicationWebXml = "/WEB-INF/web.xml"; - public static final String DefaultContextXml = "conf/context.xml"; - public static final String DefaultWebXml = "conf/web.xml"; - public static final String HostContextXml = "context.xml.default"; - public static final String HostWebXml = "web.xml.default"; - - public static final String TldDtdPublicId_11 = - "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; - public static final String TldDtdResourcePath_11 = - "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd"; - - public static final String TldDtdPublicId_12 = - "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; - public static final String TldDtdResourcePath_12 = - "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd"; - - public static final String TldSchemaPublicId_20 = - "web-jsptaglibrary_2_0.xsd";; - public static final String TldSchemaResourcePath_20 = - "/javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd"; - - public static final String WebDtdPublicId_22 = - "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; - public static final String WebDtdResourcePath_22 = - "/javax/servlet/resources/web-app_2_2.dtd"; - - public static final String WebDtdPublicId_23 = - "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; - public static final String WebDtdResourcePath_23 = - "/javax/servlet/resources/web-app_2_3.dtd"; - - public static final String WebSchemaPublicId_24 = - "web-app_2_4.xsd";; - public static final String WebSchemaResourcePath_24 = - "/javax/servlet/resources/web-app_2_4.xsd"; - - public static final String J2eeSchemaPublicId_14 = - "j2ee_1_4.xsd";; - public static final String J2eeSchemaResourcePath_14 = - "/javax/servlet/resources/j2ee_1_4.xsd"; - - public static final String W3cSchemaPublicId_10 = - "xml.xsd";; - public static final String W3cSchemaResourcePath_10 = - "/javax/servlet/resources/xml.xsd"; - - public static final String JspSchemaPublicId_20 = - "jsp_2_0.xsd";; - public static final String JspSchemaResourcePath_20 = - "/javax/servlet/jsp/resources/jsp_2_0.xsd"; - - public static final String J2eeWebServiceSchemaPublicId_11 = - "j2ee_web_services_1_1.xsd"; - public static final String J2eeWebServiceSchemaResourcePath_11 = - "/javax/servlet/resources/j2ee_web_services_1_1.xsd"; - - public static final String J2eeWebServiceClientSchemaPublicId_11 = - "j2ee_web_services_client_1_1.xsd"; - public static final String J2eeWebServiceClientSchemaResourcePath_11 = - "/javax/servlet/resources/j2ee_web_services_client_1_1.xsd"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +/** + * String constants for the startup package. + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand + * @version $Revision: 303179 $ $Date: 2004-09-02 12:28:00 +0200 (jeu., 02 sept. 2004) $ + */ + +public final class Constants { + + public static final String Package = "org.apache.catalina.startup"; + + public static final String ApplicationContextXml = "META-INF/context.xml"; + public static final String ApplicationWebXml = "/WEB-INF/web.xml"; + public static final String DefaultContextXml = "conf/context.xml"; + public static final String DefaultWebXml = "conf/web.xml"; + public static final String HostContextXml = "context.xml.default"; + public static final String HostWebXml = "web.xml.default"; + + public static final String TldDtdPublicId_11 = + "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; + public static final String TldDtdResourcePath_11 = + "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd"; + + public static final String TldDtdPublicId_12 = + "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; + public static final String TldDtdResourcePath_12 = + "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd"; + + public static final String TldSchemaPublicId_20 = + "web-jsptaglibrary_2_0.xsd";; + public static final String TldSchemaResourcePath_20 = + "/javax/servlet/jsp/resources/web-jsptaglibrary_2_0.xsd"; + + public static final String WebDtdPublicId_22 = + "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; + public static final String WebDtdResourcePath_22 = + "/javax/servlet/resources/web-app_2_2.dtd"; + + public static final String WebDtdPublicId_23 = + "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; + public static final String WebDtdResourcePath_23 = + "/javax/servlet/resources/web-app_2_3.dtd"; + + public static final String WebSchemaPublicId_24 = + "web-app_2_4.xsd";; + public static final String WebSchemaResourcePath_24 = + "/javax/servlet/resources/web-app_2_4.xsd"; + + public static final String J2eeSchemaPublicId_14 = + "j2ee_1_4.xsd";; + public static final String J2eeSchemaResourcePath_14 = + "/javax/servlet/resources/j2ee_1_4.xsd"; + + public static final String W3cSchemaPublicId_10 = + "xml.xsd";; + public static final String W3cSchemaResourcePath_10 = + "/javax/servlet/resources/xml.xsd"; + + public static final String JspSchemaPublicId_20 = + "jsp_2_0.xsd";; + public static final String JspSchemaResourcePath_20 = + "/javax/servlet/jsp/resources/jsp_2_0.xsd"; + + public static final String J2eeWebServiceSchemaPublicId_11 = + "j2ee_web_services_1_1.xsd"; + public static final String J2eeWebServiceSchemaResourcePath_11 = + "/javax/servlet/resources/j2ee_web_services_1_1.xsd"; + + public static final String J2eeWebServiceClientSchemaPublicId_11 = + "j2ee_web_services_client_1_1.xsd"; + public static final String J2eeWebServiceClientSchemaResourcePath_11 = + "/javax/servlet/resources/j2ee_web_services_client_1_1.xsd"; + +} diff --git a/java/org/apache/catalina/startup/ContextConfig.java b/java/org/apache/catalina/startup/ContextConfig.java index 0c71c2251..f9ec1061f 100644 --- a/java/org/apache/catalina/startup/ContextConfig.java +++ b/java/org/apache/catalina/startup/ContextConfig.java @@ -1,1376 +1,1376 @@ -/* - * Copyright 1999-2001,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.Map; -import java.util.Properties; - -import javax.servlet.ServletContext; - -import org.apache.catalina.Authenticator; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Globals; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Pipeline; -import org.apache.catalina.Valve; -import org.apache.catalina.Wrapper; -import org.apache.catalina.core.ContainerBase; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.core.StandardEngine; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.deploy.ErrorPage; -import org.apache.catalina.deploy.FilterDef; -import org.apache.catalina.deploy.FilterMap; -import org.apache.catalina.deploy.LoginConfig; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.catalina.util.StringManager; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.RuleSet; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXParseException; - -/** - * Startup event listener for a Context that configures the properties - * of that Context, and the associated defined servlets. - * - * @author Craig R. McClanahan - * @author Jean-Francois Arcand - * @version $Revision: 379614 $ $Date: 2006-02-22 00:02:57 +0100 (mer., 22 févr. 2006) $ - */ - -public class ContextConfig - implements LifecycleListener { - - protected static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( ContextConfig.class ); - - // ----------------------------------------------------- Instance Variables - - - /** - * Custom mappings of login methods to authenticators - */ - protected Map customAuthenticators; - - - /** - * The set of Authenticators that we know how to configure. The key is - * the name of the implemented authentication method, and the value is - * the fully qualified Java class name of the corresponding Valve. - */ - protected static Properties authenticators = null; - - - /** - * The Context we are associated with. - */ - protected Context context = null; - - - /** - * The default web application's context file location. - */ - protected String defaultContextXml = null; - - - /** - * The default web application's deployment descriptor location. - */ - protected String defaultWebXml = null; - - - /** - * Track any fatal errors during startup configuration processing. - */ - protected boolean ok = false; - - - /** - * Any parse error which occurred while parsing XML descriptors. - */ - protected SAXParseException parseException = null; - - - /** - * Original docBase. - */ - protected String originalDocBase = null; - - - /** - * The string resources for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The Digester we will use to process web application - * context files. - */ - protected static Digester contextDigester = null; - - - /** - * The Digester we will use to process web application - * deployment descriptor files. - */ - protected static Digester webDigester = null; - - - /** - * The Rule used to parse the web.xml - */ - protected static WebRuleSet webRuleSet = new WebRuleSet(); - - /** - * Attribute value used to turn on/off XML validation - */ - protected static boolean xmlValidation = false; - - - /** - * Attribute value used to turn on/off XML namespace awarenes. - */ - protected static boolean xmlNamespaceAware = false; - - - /** - * Deployment count. - */ - protected static long deploymentCount = 0L; - - - protected static final LoginConfig DUMMY_LOGIN_CONFIG = - new LoginConfig("NONE", null, null, null); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the location of the default deployment descriptor - */ - public String getDefaultWebXml() { - if( defaultWebXml == null ) { - defaultWebXml=Constants.DefaultWebXml; - } - - return (this.defaultWebXml); - - } - - - /** - * Set the location of the default deployment descriptor - * - * @param path Absolute/relative path to the default web.xml - */ - public void setDefaultWebXml(String path) { - - this.defaultWebXml = path; - - } - - - /** - * Return the location of the default context file - */ - public String getDefaultContextXml() { - if( defaultContextXml == null ) { - defaultContextXml=Constants.DefaultContextXml; - } - - return (this.defaultContextXml); - - } - - - /** - * Set the location of the default context file - * - * @param path Absolute/relative path to the default context.xml - */ - public void setDefaultContextXml(String path) { - - this.defaultContextXml = path; - - } - - - /** - * Sets custom mappings of login methods to authenticators. - * - * @param customAuthenticators Custom mappings of login methods to - * authenticators - */ - public void setCustomAuthenticators(Map customAuthenticators) { - this.customAuthenticators = customAuthenticators; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Process events for an associated Context. - * - * @param event The lifecycle event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - // Identify the context we are associated with - try { - context = (Context) event.getLifecycle(); - } catch (ClassCastException e) { - log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e); - return; - } - - // Process the event that has occurred - if (event.getType().equals(Lifecycle.START_EVENT)) { - start(); - } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) { - beforeStart(); - } else if (event.getType().equals(StandardContext.AFTER_START_EVENT)) { - // Restore docBase for management tools - if (originalDocBase != null) { - String docBase = context.getDocBase(); - context.setDocBase(originalDocBase); - originalDocBase = docBase; - } - } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { - if (originalDocBase != null) { - String docBase = context.getDocBase(); - context.setDocBase(originalDocBase); - originalDocBase = docBase; - } - stop(); - } else if (event.getType().equals(Lifecycle.INIT_EVENT)) { - init(); - } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) { - destroy(); - } - - } - - - // -------------------------------------------------------- protected Methods - - - /** - * Process the application classes annotations, if it exists. - */ - protected void applicationAnnotationsConfig() { - - long t1=System.currentTimeMillis(); - - WebAnnotationSet.loadApplicationAnnotations(context); - - long t2=System.currentTimeMillis(); - if (context instanceof StandardContext) { - ((StandardContext) context).setStartupTime(t2-t1+ - ((StandardContext) context).getStartupTime()); - } - } - - - /** - * Process the application configuration file, if it exists. - */ - protected void applicationWebConfig() { - - String altDDName = null; - - // Open the application web.xml file, if it exists - InputStream stream = null; - ServletContext servletContext = context.getServletContext(); - if (servletContext != null) { - altDDName = (String)servletContext.getAttribute( - Globals.ALT_DD_ATTR); - if (altDDName != null) { - try { - stream = new FileInputStream(altDDName); - } catch (FileNotFoundException e) { - log.error(sm.getString("contextConfig.altDDNotFound", - altDDName)); - } - } - else { - stream = servletContext.getResourceAsStream - (Constants.ApplicationWebXml); - } - } - if (stream == null) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("contextConfig.applicationMissing") + " " + context); - } - return; - } - - long t1=System.currentTimeMillis(); - - if (webDigester == null){ - webDigester = createWebDigester(); - } - - URL url=null; - // Process the application web.xml file - synchronized (webDigester) { - try { - if (altDDName != null) { - url = new File(altDDName).toURL(); - } else { - url = servletContext.getResource( - Constants.ApplicationWebXml); - } - if( url!=null ) { - InputSource is = new InputSource(url.toExternalForm()); - is.setByteStream(stream); - if (context instanceof StandardContext) { - ((StandardContext) context).setReplaceWelcomeFiles(true); - } - webDigester.push(context); - webDigester.setErrorHandler(new ContextErrorHandler()); - - if(log.isDebugEnabled()) { - log.debug("Parsing application web.xml file at " + url.toExternalForm()); - } - - webDigester.parse(is); - - if (parseException != null) { - ok = false; - } - } else { - log.info("No web.xml, using defaults " + context ); - } - } catch (SAXParseException e) { - log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e); - log.error(sm.getString("contextConfig.applicationPosition", - "" + e.getLineNumber(), - "" + e.getColumnNumber())); - ok = false; - } catch (Exception e) { - log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e); - ok = false; - } finally { - webDigester.reset(); - parseException = null; - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - log.error(sm.getString("contextConfig.applicationClose"), e); - } - } - } - webRuleSet.recycle(); - - long t2=System.currentTimeMillis(); - if (context instanceof StandardContext) { - ((StandardContext) context).setStartupTime(t2-t1); - } - } - - - /** - * Set up an Authenticator automatically if required, and one has not - * already been configured. - */ - protected synchronized void authenticatorConfig() { - - // Does this Context require an Authenticator? - SecurityConstraint constraints[] = context.findConstraints(); - if ((constraints == null) || (constraints.length == 0)) - return; - LoginConfig loginConfig = context.getLoginConfig(); - if (loginConfig == null) { - loginConfig = DUMMY_LOGIN_CONFIG; - context.setLoginConfig(loginConfig); - } - - // Has an authenticator been configured already? - if (context instanceof Authenticator) - return; - if (context instanceof ContainerBase) { - Pipeline pipeline = ((ContainerBase) context).getPipeline(); - if (pipeline != null) { - Valve basic = pipeline.getBasic(); - if ((basic != null) && (basic instanceof Authenticator)) - return; - Valve valves[] = pipeline.getValves(); - for (int i = 0; i < valves.length; i++) { - if (valves[i] instanceof Authenticator) - return; - } - } - } else { - return; // Cannot install a Valve even if it would be needed - } - - // Has a Realm been configured for us to authenticate against? - if (context.getRealm() == null) { - log.error(sm.getString("contextConfig.missingRealm")); - ok = false; - return; - } - - /* - * First check to see if there is a custom mapping for the login - * method. If so, use it. Otherwise, check if there is a mapping in - * org/apache/catalina/startup/Authenticators.properties. - */ - Valve authenticator = null; - if (customAuthenticators != null) { - authenticator = (Valve) - customAuthenticators.get(loginConfig.getAuthMethod()); - } - if (authenticator == null) { - // Load our mapping properties if necessary - if (authenticators == null) { - try { - InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties"); - if( is!=null ) { - authenticators = new Properties(); - authenticators.load(is); - } else { - log.error(sm.getString( - "contextConfig.authenticatorResources")); - ok=false; - return; - } - } catch (IOException e) { - log.error(sm.getString( - "contextConfig.authenticatorResources"), e); - ok = false; - return; - } - } - - // Identify the class name of the Valve we should configure - String authenticatorName = null; - authenticatorName = - authenticators.getProperty(loginConfig.getAuthMethod()); - if (authenticatorName == null) { - log.error(sm.getString("contextConfig.authenticatorMissing", - loginConfig.getAuthMethod())); - ok = false; - return; - } - - // Instantiate and install an Authenticator of the requested class - try { - Class authenticatorClass = Class.forName(authenticatorName); - authenticator = (Valve) authenticatorClass.newInstance(); - } catch (Throwable t) { - log.error(sm.getString( - "contextConfig.authenticatorInstantiate", - authenticatorName), - t); - ok = false; - } - } - - if (authenticator != null && context instanceof ContainerBase) { - Pipeline pipeline = ((ContainerBase) context).getPipeline(); - if (pipeline != null) { - ((ContainerBase) context).addValve(authenticator); - if (log.isDebugEnabled()) { - log.debug(sm.getString( - "contextConfig.authenticatorConfigured", - loginConfig.getAuthMethod())); - } - } - } - - } - - - /** - * Create (if necessary) and return a Digester configured to process the - * web application deployment descriptor (web.xml). - */ - protected static Digester createWebDigester() { - Digester webDigester = - createWebXmlDigester(xmlNamespaceAware, xmlValidation); - return webDigester; - } - - - /** - * Create (if necessary) and return a Digester configured to process the - * web application deployment descriptor (web.xml). - */ - public static Digester createWebXmlDigester(boolean namespaceAware, - boolean validation) { - - Digester webDigester = DigesterFactory.newDigester(xmlValidation, - xmlNamespaceAware, - webRuleSet); - return webDigester; - } - - - /** - * Create (if necessary) and return a Digester configured to process the - * context configuration descriptor for an application. - */ - protected Digester createContextDigester() { - Digester digester = new Digester(); - digester.setValidating(false); - RuleSet contextRuleSet = new ContextRuleSet("", false); - digester.addRuleSet(contextRuleSet); - RuleSet namingRuleSet = new NamingRuleSet("Context/"); - digester.addRuleSet(namingRuleSet); - return digester; - } - - - protected String getBaseDir() { - Container engineC=context.getParent().getParent(); - if( engineC instanceof StandardEngine ) { - return ((StandardEngine)engineC).getBaseDir(); - } - return System.getProperty("catalina.base"); - } - - /** - * Process the default configuration file, if it exists. - * The default config must be read with the container loader - so - * container servlets can be loaded - */ - protected void defaultWebConfig() { - long t1=System.currentTimeMillis(); - - // Open the default web.xml file, if it exists - if( defaultWebXml==null && context instanceof StandardContext ) { - defaultWebXml=((StandardContext)context).getDefaultWebXml(); - } - // set the default if we don't have any overrides - if( defaultWebXml==null ) getDefaultWebXml(); - - File file = new File(this.defaultWebXml); - if (!file.isAbsolute()) { - file = new File(getBaseDir(), - this.defaultWebXml); - } - - InputStream stream = null; - InputSource source = null; - - try { - if ( ! file.exists() ) { - // Use getResource and getResourceAsStream - stream = getClass().getClassLoader() - .getResourceAsStream(defaultWebXml); - if( stream != null ) { - source = new InputSource - (getClass().getClassLoader() - .getResource(defaultWebXml).toString()); - } - if( stream== null ) { - // maybe embedded - stream = getClass().getClassLoader() - .getResourceAsStream("web-embed.xml"); - if( stream != null ) { - source = new InputSource - (getClass().getClassLoader() - .getResource("web-embed.xml").toString()); - } - } - - if( stream== null ) { - log.info("No default web.xml"); - } - } else { - source = - new InputSource("file://" + file.getAbsolutePath()); - stream = new FileInputStream(file); - } - } catch (Exception e) { - log.error(sm.getString("contextConfig.defaultMissing") - + " " + defaultWebXml + " " + file , e); - } - - if (webDigester == null){ - webDigester = createWebDigester(); - } - - if (stream != null) { - processDefaultWebConfig(webDigester, stream, source); - webRuleSet.recycle(); - } - - long t2=System.currentTimeMillis(); - if( (t2-t1) > 200 ) - log.debug("Processed default web.xml " + file + " " + ( t2-t1)); - - stream = null; - source = null; - - String resourceName = getHostConfigPath(Constants.HostWebXml); - file = new File(getConfigBase(), resourceName); - - try { - if ( ! file.exists() ) { - // Use getResource and getResourceAsStream - stream = getClass().getClassLoader() - .getResourceAsStream(resourceName); - if( stream != null ) { - source = new InputSource - (getClass().getClassLoader() - .getResource(resourceName).toString()); - } - } else { - source = - new InputSource("file://" + file.getAbsolutePath()); - stream = new FileInputStream(file); - } - } catch (Exception e) { - log.error(sm.getString("contextConfig.defaultMissing") - + " " + resourceName + " " + file , e); - } - - if (stream != null) { - processDefaultWebConfig(webDigester, stream, source); - webRuleSet.recycle(); - } - - } - - - /** - * Process a default web.xml. - */ - protected void processDefaultWebConfig(Digester digester, InputStream stream, - InputSource source) { - - if (log.isDebugEnabled()) - log.debug("Processing context [" + context.getName() - + "] web configuration resource " + source.getSystemId()); - - // Process the default web.xml file - synchronized (digester) { - try { - source.setByteStream(stream); - - if (context instanceof StandardContext) - ((StandardContext) context).setReplaceWelcomeFiles(true); - digester.setClassLoader(this.getClass().getClassLoader()); - digester.setUseContextClassLoader(false); - digester.push(context); - digester.setErrorHandler(new ContextErrorHandler()); - digester.parse(source); - if (parseException != null) { - ok = false; - } - } catch (SAXParseException e) { - log.error(sm.getString("contextConfig.defaultParse"), e); - log.error(sm.getString("contextConfig.defaultPosition", - "" + e.getLineNumber(), - "" + e.getColumnNumber())); - ok = false; - } catch (Exception e) { - log.error(sm.getString("contextConfig.defaultParse"), e); - ok = false; - } finally { - digester.reset(); - parseException = null; - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - log.error(sm.getString("contextConfig.defaultClose"), e); - } - } - } - } - - - /** - * Process the default configuration file, if it exists. - */ - protected void contextConfig() { - - // Open the default web.xml file, if it exists - if( defaultContextXml==null && context instanceof StandardContext ) { - defaultContextXml = ((StandardContext)context).getDefaultContextXml(); - } - // set the default if we don't have any overrides - if( defaultContextXml==null ) getDefaultContextXml(); - - if (!context.getOverride()) { - processContextConfig(new File(getBaseDir()), defaultContextXml); - processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml)); - } - if (context.getConfigFile() != null) - processContextConfig(new File(context.getConfigFile()), null); - - } - - - /** - * Process a context.xml. - */ - protected void processContextConfig(File baseDir, String resourceName) { - - if (log.isDebugEnabled()) - log.debug("Processing context [" + context.getName() - + "] configuration file " + baseDir + " " + resourceName); - - InputSource source = null; - InputStream stream = null; - - File file = baseDir; - if (resourceName != null) { - file = new File(baseDir, resourceName); - } - - try { - if ( !file.exists() ) { - if (resourceName != null) { - // Use getResource and getResourceAsStream - stream = getClass().getClassLoader() - .getResourceAsStream(resourceName); - if( stream != null ) { - source = new InputSource - (getClass().getClassLoader() - .getResource(resourceName).toString()); - } - } - } else { - source = - new InputSource("file://" + file.getAbsolutePath()); - stream = new FileInputStream(file); - // Add as watched resource so that cascade reload occurs if a default - // config file is modified/added/removed - context.addWatchedResource(file.getAbsolutePath()); - } - } catch (Exception e) { - log.error(sm.getString("contextConfig.defaultMissing") - + " " + resourceName + " " + file , e); - } - - if (source == null) - return; - if (contextDigester == null){ - contextDigester = createContextDigester(); - } - synchronized (contextDigester) { - try { - source.setByteStream(stream); - contextDigester.setClassLoader(this.getClass().getClassLoader()); - contextDigester.setUseContextClassLoader(false); - contextDigester.push(context.getParent()); - contextDigester.push(context); - contextDigester.setErrorHandler(new ContextErrorHandler()); - contextDigester.parse(source); - if (parseException != null) { - ok = false; - } - if (log.isDebugEnabled()) - log.debug("Successfully processed context [" + context.getName() - + "] configuration file " + baseDir + " " + resourceName); - } catch (SAXParseException e) { - log.error(sm.getString("contextConfig.defaultParse"), e); - log.error(sm.getString("contextConfig.defaultPosition", - "" + e.getLineNumber(), - "" + e.getColumnNumber())); - ok = false; - } catch (Exception e) { - log.error(sm.getString("contextConfig.defaultParse"), e); - ok = false; - } finally { - contextDigester.reset(); - parseException = null; - try { - if (stream != null) { - stream.close(); - } - } catch (IOException e) { - log.error(sm.getString("contextConfig.defaultClose"), e); - } - } - } - } - - - /** - * Adjust docBase. - */ - protected void fixDocBase() - throws IOException { - - Host host = (Host) context.getParent(); - String appBase = host.getAppBase(); - - boolean unpackWARs = true; - if (host instanceof StandardHost) { - unpackWARs = ((StandardHost) host).isUnpackWARs() - && ((StandardContext) context).getUnpackWAR(); - } - - File canonicalAppBase = new File(appBase); - if (canonicalAppBase.isAbsolute()) { - canonicalAppBase = canonicalAppBase.getCanonicalFile(); - } else { - canonicalAppBase = - new File(System.getProperty("catalina.base"), appBase) - .getCanonicalFile(); - } - - String docBase = context.getDocBase(); - if (docBase == null) { - // Trying to guess the docBase according to the path - String path = context.getPath(); - if (path == null) { - return; - } - if (path.equals("")) { - docBase = "ROOT"; - } else { - if (path.startsWith("/")) { - docBase = path.substring(1); - } else { - docBase = path; - } - } - } - - File file = new File(docBase); - if (!file.isAbsolute()) { - docBase = (new File(canonicalAppBase, docBase)).getPath(); - } else { - docBase = file.getCanonicalPath(); - } - file = new File(docBase); - String origDocBase = docBase; - - if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) { - URL war = new URL("jar:" + (new File(docBase)).toURL() + "!/"); - String contextPath = context.getPath(); - if (contextPath.equals("")) { - contextPath = "ROOT"; - } - docBase = ExpandWar.expand(host, war, contextPath); - file = new File(docBase); - docBase = file.getCanonicalPath(); - if (context instanceof StandardContext) { - ((StandardContext) context).setOriginalDocBase(origDocBase); - } - } else { - File docDir = new File(docBase); - if (!docDir.exists()) { - File warFile = new File(docBase + ".war"); - if (warFile.exists()) { - if (unpackWARs) { - URL war = new URL("jar:" + warFile.toURL() + "!/"); - docBase = ExpandWar.expand(host, war, context.getPath()); - file = new File(docBase); - docBase = file.getCanonicalPath(); - } else { - docBase = warFile.getCanonicalPath(); - } - } - if (context instanceof StandardContext) { - ((StandardContext) context).setOriginalDocBase(origDocBase); - } - } - } - - if (docBase.startsWith(canonicalAppBase.getPath())) { - docBase = docBase.substring(canonicalAppBase.getPath().length()); - docBase = docBase.replace(File.separatorChar, '/'); - if (docBase.startsWith("/")) { - docBase = docBase.substring(1); - } - } else { - docBase = docBase.replace(File.separatorChar, '/'); - } - - context.setDocBase(docBase); - - } - - - protected void antiLocking() - throws IOException { - - if ((context instanceof StandardContext) - && ((StandardContext) context).getAntiResourceLocking()) { - - Host host = (Host) context.getParent(); - String appBase = host.getAppBase(); - String docBase = context.getDocBase(); - if (docBase == null) - return; - if (originalDocBase == null) { - originalDocBase = docBase; - } else { - docBase = originalDocBase; - } - File docBaseFile = new File(docBase); - if (!docBaseFile.isAbsolute()) { - File file = new File(appBase); - if (!file.isAbsolute()) { - file = new File(System.getProperty("catalina.base"), appBase); - } - docBaseFile = new File(file, docBase); - } - - String path = context.getPath(); - if (path == null) { - return; - } - if (path.equals("")) { - docBase = "ROOT"; - } else { - if (path.startsWith("/")) { - docBase = path.substring(1); - } else { - docBase = path; - } - } - - File file = null; - if (docBase.toLowerCase().endsWith(".war")) { - file = new File(System.getProperty("java.io.tmpdir"), - deploymentCount++ + "-" + docBase + ".war"); - } else { - file = new File(System.getProperty("java.io.tmpdir"), - deploymentCount++ + "-" + docBase); - } - - if (log.isDebugEnabled()) - log.debug("Anti locking context[" + context.getPath() - + "] setting docBase to " + file); - - // Cleanup just in case an old deployment is lying around - ExpandWar.delete(file); - if (ExpandWar.copy(docBaseFile, file)) { - context.setDocBase(file.getAbsolutePath()); - } - - } - - } - - - /** - * Process a "init" event for this Context. - */ - protected void init() { - // Called from StandardContext.init() - - if (log.isDebugEnabled()) - log.debug(sm.getString("contextConfig.init")); - context.setConfigured(false); - ok = true; - - contextConfig(); - - try { - fixDocBase(); - } catch (IOException e) { - log.error(sm.getString("contextConfig.fixDocBase"), e); - } - - } - - - /** - * Process a "before start" event for this Context. - */ - protected synchronized void beforeStart() { - - try { - antiLocking(); - } catch (IOException e) { - log.error(sm.getString("contextConfig.antiLocking"), e); - } - - } - - - /** - * Process a "start" event for this Context. - */ - protected synchronized void start() { - // Called from StandardContext.start() - - if (log.isDebugEnabled()) - log.debug(sm.getString("contextConfig.start")); - - // Set properties based on DefaultContext - Container container = context.getParent(); - if( !context.getOverride() ) { - if( container instanceof Host ) { - // Reset the value only if the attribute wasn't - // set on the context. - xmlValidation = context.getXmlValidation(); - if (!xmlValidation) { - xmlValidation = ((Host)container).getXmlValidation(); - } - - xmlNamespaceAware = context.getXmlNamespaceAware(); - if (!xmlNamespaceAware){ - xmlNamespaceAware - = ((Host)container).getXmlNamespaceAware(); - } - - container = container.getParent(); - } - } - - // Process the default and application web.xml files - defaultWebConfig(); - applicationWebConfig(); - if (!context.getIgnoreAnnotations()) { - applicationAnnotationsConfig(); - } - if (ok) { - validateSecurityRoles(); - } - - // Configure an authenticator if we need one - if (ok) - authenticatorConfig(); - - // Dump the contents of this pipeline if requested - if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) { - log.debug("Pipeline Configuration:"); - Pipeline pipeline = ((ContainerBase) context).getPipeline(); - Valve valves[] = null; - if (pipeline != null) - valves = pipeline.getValves(); - if (valves != null) { - for (int i = 0; i < valves.length; i++) { - log.debug(" " + valves[i].getInfo()); - } - } - log.debug("======================"); - } - - // Make our application available if no problems were encountered - if (ok) - context.setConfigured(true); - else { - log.error(sm.getString("contextConfig.unavailable")); - context.setConfigured(false); - } - - } - - - /** - * Process a "stop" event for this Context. - */ - protected synchronized void stop() { - - if (log.isDebugEnabled()) - log.debug(sm.getString("contextConfig.stop")); - - int i; - - // Removing children - Container[] children = context.findChildren(); - for (i = 0; i < children.length; i++) { - context.removeChild(children[i]); - } - - // Removing application parameters - /* - ApplicationParameter[] applicationParameters = - context.findApplicationParameters(); - for (i = 0; i < applicationParameters.length; i++) { - context.removeApplicationParameter - (applicationParameters[i].getName()); - } - */ - - // Removing security constraints - SecurityConstraint[] securityConstraints = context.findConstraints(); - for (i = 0; i < securityConstraints.length; i++) { - context.removeConstraint(securityConstraints[i]); - } - - // Removing Ejbs - /* - ContextEjb[] contextEjbs = context.findEjbs(); - for (i = 0; i < contextEjbs.length; i++) { - context.removeEjb(contextEjbs[i].getName()); - } - */ - - // Removing environments - /* - ContextEnvironment[] contextEnvironments = context.findEnvironments(); - for (i = 0; i < contextEnvironments.length; i++) { - context.removeEnvironment(contextEnvironments[i].getName()); - } - */ - - // Removing errors pages - ErrorPage[] errorPages = context.findErrorPages(); - for (i = 0; i < errorPages.length; i++) { - context.removeErrorPage(errorPages[i]); - } - - // Removing filter defs - FilterDef[] filterDefs = context.findFilterDefs(); - for (i = 0; i < filterDefs.length; i++) { - context.removeFilterDef(filterDefs[i]); - } - - // Removing filter maps - FilterMap[] filterMaps = context.findFilterMaps(); - for (i = 0; i < filterMaps.length; i++) { - context.removeFilterMap(filterMaps[i]); - } - - // Removing local ejbs - /* - ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs(); - for (i = 0; i < contextLocalEjbs.length; i++) { - context.removeLocalEjb(contextLocalEjbs[i].getName()); - } - */ - - // Removing Mime mappings - String[] mimeMappings = context.findMimeMappings(); - for (i = 0; i < mimeMappings.length; i++) { - context.removeMimeMapping(mimeMappings[i]); - } - - // Removing parameters - String[] parameters = context.findParameters(); - for (i = 0; i < parameters.length; i++) { - context.removeParameter(parameters[i]); - } - - // Removing resource env refs - /* - String[] resourceEnvRefs = context.findResourceEnvRefs(); - for (i = 0; i < resourceEnvRefs.length; i++) { - context.removeResourceEnvRef(resourceEnvRefs[i]); - } - */ - - // Removing resource links - /* - ContextResourceLink[] contextResourceLinks = - context.findResourceLinks(); - for (i = 0; i < contextResourceLinks.length; i++) { - context.removeResourceLink(contextResourceLinks[i].getName()); - } - */ - - // Removing resources - /* - ContextResource[] contextResources = context.findResources(); - for (i = 0; i < contextResources.length; i++) { - context.removeResource(contextResources[i].getName()); - } - */ - - // Removing sercurity role - String[] securityRoles = context.findSecurityRoles(); - for (i = 0; i < securityRoles.length; i++) { - context.removeSecurityRole(securityRoles[i]); - } - - // Removing servlet mappings - String[] servletMappings = context.findServletMappings(); - for (i = 0; i < servletMappings.length; i++) { - context.removeServletMapping(servletMappings[i]); - } - - // FIXME : Removing status pages - - // Removing taglibs - String[] taglibs = context.findTaglibs(); - for (i = 0; i < taglibs.length; i++) { - context.removeTaglib(taglibs[i]); - } - - // Removing welcome files - String[] welcomeFiles = context.findWelcomeFiles(); - for (i = 0; i < welcomeFiles.length; i++) { - context.removeWelcomeFile(welcomeFiles[i]); - } - - // Removing wrapper lifecycles - String[] wrapperLifecycles = context.findWrapperLifecycles(); - for (i = 0; i < wrapperLifecycles.length; i++) { - context.removeWrapperLifecycle(wrapperLifecycles[i]); - } - - // Removing wrapper listeners - String[] wrapperListeners = context.findWrapperListeners(); - for (i = 0; i < wrapperListeners.length; i++) { - context.removeWrapperListener(wrapperListeners[i]); - } - - // Remove (partially) folders and files created by antiLocking - Host host = (Host) context.getParent(); - String appBase = host.getAppBase(); - String docBase = context.getDocBase(); - if ((docBase != null) && (originalDocBase != null)) { - File docBaseFile = new File(docBase); - if (!docBaseFile.isAbsolute()) { - docBaseFile = new File(appBase, docBase); - } - ExpandWar.delete(docBaseFile); - } - - ok = true; - - } - - - /** - * Process a "destroy" event for this Context. - */ - protected synchronized void destroy() { - // Called from StandardContext.destroy() - if (log.isDebugEnabled()) - log.debug(sm.getString("contextConfig.destroy")); - - // Changed to getWorkPath per Bugzilla 35819. - String workDir = ((StandardContext) context).getWorkPath(); - if (workDir != null) - ExpandWar.delete(new File(workDir)); - } - - - /** - * Validate the usage of security role names in the web application - * deployment descriptor. If any problems are found, issue warning - * messages (for backwards compatibility) and add the missing roles. - * (To make these problems fatal instead, simply set the ok - * instance variable to false as well). - */ - protected void validateSecurityRoles() { - - // Check role names used in elements - SecurityConstraint constraints[] = context.findConstraints(); - for (int i = 0; i < constraints.length; i++) { - String roles[] = constraints[i].findAuthRoles(); - for (int j = 0; j < roles.length; j++) { - if (!"*".equals(roles[j]) && - !context.findSecurityRole(roles[j])) { - log.info(sm.getString("contextConfig.role.auth", roles[j])); - context.addSecurityRole(roles[j]); - } - } - } - - // Check role names used in elements - Container wrappers[] = context.findChildren(); - for (int i = 0; i < wrappers.length; i++) { - Wrapper wrapper = (Wrapper) wrappers[i]; - String runAs = wrapper.getRunAs(); - if ((runAs != null) && !context.findSecurityRole(runAs)) { - log.info(sm.getString("contextConfig.role.runas", runAs)); - context.addSecurityRole(runAs); - } - String names[] = wrapper.findSecurityReferences(); - for (int j = 0; j < names.length; j++) { - String link = wrapper.findSecurityReference(names[j]); - if ((link != null) && !context.findSecurityRole(link)) { - log.info(sm.getString("contextConfig.role.link", link)); - context.addSecurityRole(link); - } - } - } - - } - - - /** - * Get config base. - */ - protected File getConfigBase() { - File configBase = - new File(System.getProperty("catalina.base"), "conf"); - if (!configBase.exists()) { - return null; - } else { - return configBase; - } - } - - - protected String getHostConfigPath(String resourceName) { - StringBuffer result = new StringBuffer(); - Container container = context; - Container host = null; - Container engine = null; - while (container != null) { - if (container instanceof Host) - host = container; - if (container instanceof Engine) - engine = container; - container = container.getParent(); - } - if (engine != null) { - result.append(engine.getName()).append('/'); - } - if (host != null) { - result.append(host.getName()).append('/'); - } - result.append(resourceName); - return result.toString(); - } - - - protected class ContextErrorHandler - implements ErrorHandler { - - public void error(SAXParseException exception) { - parseException = exception; - } - - public void fatalError(SAXParseException exception) { - parseException = exception; - } - - public void warning(SAXParseException exception) { - parseException = exception; - } - - } - - -} +/* + * Copyright 1999-2001,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +import javax.servlet.ServletContext; + +import org.apache.catalina.Authenticator; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Globals; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Pipeline; +import org.apache.catalina.Valve; +import org.apache.catalina.Wrapper; +import org.apache.catalina.core.ContainerBase; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.core.StandardEngine; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.deploy.ErrorPage; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.FilterMap; +import org.apache.catalina.deploy.LoginConfig; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.catalina.util.StringManager; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSet; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXParseException; + +/** + * Startup event listener for a Context that configures the properties + * of that Context, and the associated defined servlets. + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand + * @version $Revision: 379614 $ $Date: 2006-02-22 00:02:57 +0100 (mer., 22 févr. 2006) $ + */ + +public class ContextConfig + implements LifecycleListener { + + protected static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( ContextConfig.class ); + + // ----------------------------------------------------- Instance Variables + + + /** + * Custom mappings of login methods to authenticators + */ + protected Map customAuthenticators; + + + /** + * The set of Authenticators that we know how to configure. The key is + * the name of the implemented authentication method, and the value is + * the fully qualified Java class name of the corresponding Valve. + */ + protected static Properties authenticators = null; + + + /** + * The Context we are associated with. + */ + protected Context context = null; + + + /** + * The default web application's context file location. + */ + protected String defaultContextXml = null; + + + /** + * The default web application's deployment descriptor location. + */ + protected String defaultWebXml = null; + + + /** + * Track any fatal errors during startup configuration processing. + */ + protected boolean ok = false; + + + /** + * Any parse error which occurred while parsing XML descriptors. + */ + protected SAXParseException parseException = null; + + + /** + * Original docBase. + */ + protected String originalDocBase = null; + + + /** + * The string resources for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The Digester we will use to process web application + * context files. + */ + protected static Digester contextDigester = null; + + + /** + * The Digester we will use to process web application + * deployment descriptor files. + */ + protected static Digester webDigester = null; + + + /** + * The Rule used to parse the web.xml + */ + protected static WebRuleSet webRuleSet = new WebRuleSet(); + + /** + * Attribute value used to turn on/off XML validation + */ + protected static boolean xmlValidation = false; + + + /** + * Attribute value used to turn on/off XML namespace awarenes. + */ + protected static boolean xmlNamespaceAware = false; + + + /** + * Deployment count. + */ + protected static long deploymentCount = 0L; + + + protected static final LoginConfig DUMMY_LOGIN_CONFIG = + new LoginConfig("NONE", null, null, null); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the location of the default deployment descriptor + */ + public String getDefaultWebXml() { + if( defaultWebXml == null ) { + defaultWebXml=Constants.DefaultWebXml; + } + + return (this.defaultWebXml); + + } + + + /** + * Set the location of the default deployment descriptor + * + * @param path Absolute/relative path to the default web.xml + */ + public void setDefaultWebXml(String path) { + + this.defaultWebXml = path; + + } + + + /** + * Return the location of the default context file + */ + public String getDefaultContextXml() { + if( defaultContextXml == null ) { + defaultContextXml=Constants.DefaultContextXml; + } + + return (this.defaultContextXml); + + } + + + /** + * Set the location of the default context file + * + * @param path Absolute/relative path to the default context.xml + */ + public void setDefaultContextXml(String path) { + + this.defaultContextXml = path; + + } + + + /** + * Sets custom mappings of login methods to authenticators. + * + * @param customAuthenticators Custom mappings of login methods to + * authenticators + */ + public void setCustomAuthenticators(Map customAuthenticators) { + this.customAuthenticators = customAuthenticators; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Process events for an associated Context. + * + * @param event The lifecycle event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + // Identify the context we are associated with + try { + context = (Context) event.getLifecycle(); + } catch (ClassCastException e) { + log.error(sm.getString("contextConfig.cce", event.getLifecycle()), e); + return; + } + + // Process the event that has occurred + if (event.getType().equals(Lifecycle.START_EVENT)) { + start(); + } else if (event.getType().equals(StandardContext.BEFORE_START_EVENT)) { + beforeStart(); + } else if (event.getType().equals(StandardContext.AFTER_START_EVENT)) { + // Restore docBase for management tools + if (originalDocBase != null) { + String docBase = context.getDocBase(); + context.setDocBase(originalDocBase); + originalDocBase = docBase; + } + } else if (event.getType().equals(Lifecycle.STOP_EVENT)) { + if (originalDocBase != null) { + String docBase = context.getDocBase(); + context.setDocBase(originalDocBase); + originalDocBase = docBase; + } + stop(); + } else if (event.getType().equals(Lifecycle.INIT_EVENT)) { + init(); + } else if (event.getType().equals(Lifecycle.DESTROY_EVENT)) { + destroy(); + } + + } + + + // -------------------------------------------------------- protected Methods + + + /** + * Process the application classes annotations, if it exists. + */ + protected void applicationAnnotationsConfig() { + + long t1=System.currentTimeMillis(); + + WebAnnotationSet.loadApplicationAnnotations(context); + + long t2=System.currentTimeMillis(); + if (context instanceof StandardContext) { + ((StandardContext) context).setStartupTime(t2-t1+ + ((StandardContext) context).getStartupTime()); + } + } + + + /** + * Process the application configuration file, if it exists. + */ + protected void applicationWebConfig() { + + String altDDName = null; + + // Open the application web.xml file, if it exists + InputStream stream = null; + ServletContext servletContext = context.getServletContext(); + if (servletContext != null) { + altDDName = (String)servletContext.getAttribute( + Globals.ALT_DD_ATTR); + if (altDDName != null) { + try { + stream = new FileInputStream(altDDName); + } catch (FileNotFoundException e) { + log.error(sm.getString("contextConfig.altDDNotFound", + altDDName)); + } + } + else { + stream = servletContext.getResourceAsStream + (Constants.ApplicationWebXml); + } + } + if (stream == null) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("contextConfig.applicationMissing") + " " + context); + } + return; + } + + long t1=System.currentTimeMillis(); + + if (webDigester == null){ + webDigester = createWebDigester(); + } + + URL url=null; + // Process the application web.xml file + synchronized (webDigester) { + try { + if (altDDName != null) { + url = new File(altDDName).toURL(); + } else { + url = servletContext.getResource( + Constants.ApplicationWebXml); + } + if( url!=null ) { + InputSource is = new InputSource(url.toExternalForm()); + is.setByteStream(stream); + if (context instanceof StandardContext) { + ((StandardContext) context).setReplaceWelcomeFiles(true); + } + webDigester.push(context); + webDigester.setErrorHandler(new ContextErrorHandler()); + + if(log.isDebugEnabled()) { + log.debug("Parsing application web.xml file at " + url.toExternalForm()); + } + + webDigester.parse(is); + + if (parseException != null) { + ok = false; + } + } else { + log.info("No web.xml, using defaults " + context ); + } + } catch (SAXParseException e) { + log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e); + log.error(sm.getString("contextConfig.applicationPosition", + "" + e.getLineNumber(), + "" + e.getColumnNumber())); + ok = false; + } catch (Exception e) { + log.error(sm.getString("contextConfig.applicationParse", url.toExternalForm()), e); + ok = false; + } finally { + webDigester.reset(); + parseException = null; + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + log.error(sm.getString("contextConfig.applicationClose"), e); + } + } + } + webRuleSet.recycle(); + + long t2=System.currentTimeMillis(); + if (context instanceof StandardContext) { + ((StandardContext) context).setStartupTime(t2-t1); + } + } + + + /** + * Set up an Authenticator automatically if required, and one has not + * already been configured. + */ + protected synchronized void authenticatorConfig() { + + // Does this Context require an Authenticator? + SecurityConstraint constraints[] = context.findConstraints(); + if ((constraints == null) || (constraints.length == 0)) + return; + LoginConfig loginConfig = context.getLoginConfig(); + if (loginConfig == null) { + loginConfig = DUMMY_LOGIN_CONFIG; + context.setLoginConfig(loginConfig); + } + + // Has an authenticator been configured already? + if (context instanceof Authenticator) + return; + if (context instanceof ContainerBase) { + Pipeline pipeline = ((ContainerBase) context).getPipeline(); + if (pipeline != null) { + Valve basic = pipeline.getBasic(); + if ((basic != null) && (basic instanceof Authenticator)) + return; + Valve valves[] = pipeline.getValves(); + for (int i = 0; i < valves.length; i++) { + if (valves[i] instanceof Authenticator) + return; + } + } + } else { + return; // Cannot install a Valve even if it would be needed + } + + // Has a Realm been configured for us to authenticate against? + if (context.getRealm() == null) { + log.error(sm.getString("contextConfig.missingRealm")); + ok = false; + return; + } + + /* + * First check to see if there is a custom mapping for the login + * method. If so, use it. Otherwise, check if there is a mapping in + * org/apache/catalina/startup/Authenticators.properties. + */ + Valve authenticator = null; + if (customAuthenticators != null) { + authenticator = (Valve) + customAuthenticators.get(loginConfig.getAuthMethod()); + } + if (authenticator == null) { + // Load our mapping properties if necessary + if (authenticators == null) { + try { + InputStream is=this.getClass().getClassLoader().getResourceAsStream("org/apache/catalina/startup/Authenticators.properties"); + if( is!=null ) { + authenticators = new Properties(); + authenticators.load(is); + } else { + log.error(sm.getString( + "contextConfig.authenticatorResources")); + ok=false; + return; + } + } catch (IOException e) { + log.error(sm.getString( + "contextConfig.authenticatorResources"), e); + ok = false; + return; + } + } + + // Identify the class name of the Valve we should configure + String authenticatorName = null; + authenticatorName = + authenticators.getProperty(loginConfig.getAuthMethod()); + if (authenticatorName == null) { + log.error(sm.getString("contextConfig.authenticatorMissing", + loginConfig.getAuthMethod())); + ok = false; + return; + } + + // Instantiate and install an Authenticator of the requested class + try { + Class authenticatorClass = Class.forName(authenticatorName); + authenticator = (Valve) authenticatorClass.newInstance(); + } catch (Throwable t) { + log.error(sm.getString( + "contextConfig.authenticatorInstantiate", + authenticatorName), + t); + ok = false; + } + } + + if (authenticator != null && context instanceof ContainerBase) { + Pipeline pipeline = ((ContainerBase) context).getPipeline(); + if (pipeline != null) { + ((ContainerBase) context).addValve(authenticator); + if (log.isDebugEnabled()) { + log.debug(sm.getString( + "contextConfig.authenticatorConfigured", + loginConfig.getAuthMethod())); + } + } + } + + } + + + /** + * Create (if necessary) and return a Digester configured to process the + * web application deployment descriptor (web.xml). + */ + protected static Digester createWebDigester() { + Digester webDigester = + createWebXmlDigester(xmlNamespaceAware, xmlValidation); + return webDigester; + } + + + /** + * Create (if necessary) and return a Digester configured to process the + * web application deployment descriptor (web.xml). + */ + public static Digester createWebXmlDigester(boolean namespaceAware, + boolean validation) { + + Digester webDigester = DigesterFactory.newDigester(xmlValidation, + xmlNamespaceAware, + webRuleSet); + return webDigester; + } + + + /** + * Create (if necessary) and return a Digester configured to process the + * context configuration descriptor for an application. + */ + protected Digester createContextDigester() { + Digester digester = new Digester(); + digester.setValidating(false); + RuleSet contextRuleSet = new ContextRuleSet("", false); + digester.addRuleSet(contextRuleSet); + RuleSet namingRuleSet = new NamingRuleSet("Context/"); + digester.addRuleSet(namingRuleSet); + return digester; + } + + + protected String getBaseDir() { + Container engineC=context.getParent().getParent(); + if( engineC instanceof StandardEngine ) { + return ((StandardEngine)engineC).getBaseDir(); + } + return System.getProperty("catalina.base"); + } + + /** + * Process the default configuration file, if it exists. + * The default config must be read with the container loader - so + * container servlets can be loaded + */ + protected void defaultWebConfig() { + long t1=System.currentTimeMillis(); + + // Open the default web.xml file, if it exists + if( defaultWebXml==null && context instanceof StandardContext ) { + defaultWebXml=((StandardContext)context).getDefaultWebXml(); + } + // set the default if we don't have any overrides + if( defaultWebXml==null ) getDefaultWebXml(); + + File file = new File(this.defaultWebXml); + if (!file.isAbsolute()) { + file = new File(getBaseDir(), + this.defaultWebXml); + } + + InputStream stream = null; + InputSource source = null; + + try { + if ( ! file.exists() ) { + // Use getResource and getResourceAsStream + stream = getClass().getClassLoader() + .getResourceAsStream(defaultWebXml); + if( stream != null ) { + source = new InputSource + (getClass().getClassLoader() + .getResource(defaultWebXml).toString()); + } + if( stream== null ) { + // maybe embedded + stream = getClass().getClassLoader() + .getResourceAsStream("web-embed.xml"); + if( stream != null ) { + source = new InputSource + (getClass().getClassLoader() + .getResource("web-embed.xml").toString()); + } + } + + if( stream== null ) { + log.info("No default web.xml"); + } + } else { + source = + new InputSource("file://" + file.getAbsolutePath()); + stream = new FileInputStream(file); + } + } catch (Exception e) { + log.error(sm.getString("contextConfig.defaultMissing") + + " " + defaultWebXml + " " + file , e); + } + + if (webDigester == null){ + webDigester = createWebDigester(); + } + + if (stream != null) { + processDefaultWebConfig(webDigester, stream, source); + webRuleSet.recycle(); + } + + long t2=System.currentTimeMillis(); + if( (t2-t1) > 200 ) + log.debug("Processed default web.xml " + file + " " + ( t2-t1)); + + stream = null; + source = null; + + String resourceName = getHostConfigPath(Constants.HostWebXml); + file = new File(getConfigBase(), resourceName); + + try { + if ( ! file.exists() ) { + // Use getResource and getResourceAsStream + stream = getClass().getClassLoader() + .getResourceAsStream(resourceName); + if( stream != null ) { + source = new InputSource + (getClass().getClassLoader() + .getResource(resourceName).toString()); + } + } else { + source = + new InputSource("file://" + file.getAbsolutePath()); + stream = new FileInputStream(file); + } + } catch (Exception e) { + log.error(sm.getString("contextConfig.defaultMissing") + + " " + resourceName + " " + file , e); + } + + if (stream != null) { + processDefaultWebConfig(webDigester, stream, source); + webRuleSet.recycle(); + } + + } + + + /** + * Process a default web.xml. + */ + protected void processDefaultWebConfig(Digester digester, InputStream stream, + InputSource source) { + + if (log.isDebugEnabled()) + log.debug("Processing context [" + context.getName() + + "] web configuration resource " + source.getSystemId()); + + // Process the default web.xml file + synchronized (digester) { + try { + source.setByteStream(stream); + + if (context instanceof StandardContext) + ((StandardContext) context).setReplaceWelcomeFiles(true); + digester.setClassLoader(this.getClass().getClassLoader()); + digester.setUseContextClassLoader(false); + digester.push(context); + digester.setErrorHandler(new ContextErrorHandler()); + digester.parse(source); + if (parseException != null) { + ok = false; + } + } catch (SAXParseException e) { + log.error(sm.getString("contextConfig.defaultParse"), e); + log.error(sm.getString("contextConfig.defaultPosition", + "" + e.getLineNumber(), + "" + e.getColumnNumber())); + ok = false; + } catch (Exception e) { + log.error(sm.getString("contextConfig.defaultParse"), e); + ok = false; + } finally { + digester.reset(); + parseException = null; + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + log.error(sm.getString("contextConfig.defaultClose"), e); + } + } + } + } + + + /** + * Process the default configuration file, if it exists. + */ + protected void contextConfig() { + + // Open the default web.xml file, if it exists + if( defaultContextXml==null && context instanceof StandardContext ) { + defaultContextXml = ((StandardContext)context).getDefaultContextXml(); + } + // set the default if we don't have any overrides + if( defaultContextXml==null ) getDefaultContextXml(); + + if (!context.getOverride()) { + processContextConfig(new File(getBaseDir()), defaultContextXml); + processContextConfig(getConfigBase(), getHostConfigPath(Constants.HostContextXml)); + } + if (context.getConfigFile() != null) + processContextConfig(new File(context.getConfigFile()), null); + + } + + + /** + * Process a context.xml. + */ + protected void processContextConfig(File baseDir, String resourceName) { + + if (log.isDebugEnabled()) + log.debug("Processing context [" + context.getName() + + "] configuration file " + baseDir + " " + resourceName); + + InputSource source = null; + InputStream stream = null; + + File file = baseDir; + if (resourceName != null) { + file = new File(baseDir, resourceName); + } + + try { + if ( !file.exists() ) { + if (resourceName != null) { + // Use getResource and getResourceAsStream + stream = getClass().getClassLoader() + .getResourceAsStream(resourceName); + if( stream != null ) { + source = new InputSource + (getClass().getClassLoader() + .getResource(resourceName).toString()); + } + } + } else { + source = + new InputSource("file://" + file.getAbsolutePath()); + stream = new FileInputStream(file); + // Add as watched resource so that cascade reload occurs if a default + // config file is modified/added/removed + context.addWatchedResource(file.getAbsolutePath()); + } + } catch (Exception e) { + log.error(sm.getString("contextConfig.defaultMissing") + + " " + resourceName + " " + file , e); + } + + if (source == null) + return; + if (contextDigester == null){ + contextDigester = createContextDigester(); + } + synchronized (contextDigester) { + try { + source.setByteStream(stream); + contextDigester.setClassLoader(this.getClass().getClassLoader()); + contextDigester.setUseContextClassLoader(false); + contextDigester.push(context.getParent()); + contextDigester.push(context); + contextDigester.setErrorHandler(new ContextErrorHandler()); + contextDigester.parse(source); + if (parseException != null) { + ok = false; + } + if (log.isDebugEnabled()) + log.debug("Successfully processed context [" + context.getName() + + "] configuration file " + baseDir + " " + resourceName); + } catch (SAXParseException e) { + log.error(sm.getString("contextConfig.defaultParse"), e); + log.error(sm.getString("contextConfig.defaultPosition", + "" + e.getLineNumber(), + "" + e.getColumnNumber())); + ok = false; + } catch (Exception e) { + log.error(sm.getString("contextConfig.defaultParse"), e); + ok = false; + } finally { + contextDigester.reset(); + parseException = null; + try { + if (stream != null) { + stream.close(); + } + } catch (IOException e) { + log.error(sm.getString("contextConfig.defaultClose"), e); + } + } + } + } + + + /** + * Adjust docBase. + */ + protected void fixDocBase() + throws IOException { + + Host host = (Host) context.getParent(); + String appBase = host.getAppBase(); + + boolean unpackWARs = true; + if (host instanceof StandardHost) { + unpackWARs = ((StandardHost) host).isUnpackWARs() + && ((StandardContext) context).getUnpackWAR(); + } + + File canonicalAppBase = new File(appBase); + if (canonicalAppBase.isAbsolute()) { + canonicalAppBase = canonicalAppBase.getCanonicalFile(); + } else { + canonicalAppBase = + new File(System.getProperty("catalina.base"), appBase) + .getCanonicalFile(); + } + + String docBase = context.getDocBase(); + if (docBase == null) { + // Trying to guess the docBase according to the path + String path = context.getPath(); + if (path == null) { + return; + } + if (path.equals("")) { + docBase = "ROOT"; + } else { + if (path.startsWith("/")) { + docBase = path.substring(1); + } else { + docBase = path; + } + } + } + + File file = new File(docBase); + if (!file.isAbsolute()) { + docBase = (new File(canonicalAppBase, docBase)).getPath(); + } else { + docBase = file.getCanonicalPath(); + } + file = new File(docBase); + String origDocBase = docBase; + + if (docBase.toLowerCase().endsWith(".war") && !file.isDirectory() && unpackWARs) { + URL war = new URL("jar:" + (new File(docBase)).toURL() + "!/"); + String contextPath = context.getPath(); + if (contextPath.equals("")) { + contextPath = "ROOT"; + } + docBase = ExpandWar.expand(host, war, contextPath); + file = new File(docBase); + docBase = file.getCanonicalPath(); + if (context instanceof StandardContext) { + ((StandardContext) context).setOriginalDocBase(origDocBase); + } + } else { + File docDir = new File(docBase); + if (!docDir.exists()) { + File warFile = new File(docBase + ".war"); + if (warFile.exists()) { + if (unpackWARs) { + URL war = new URL("jar:" + warFile.toURL() + "!/"); + docBase = ExpandWar.expand(host, war, context.getPath()); + file = new File(docBase); + docBase = file.getCanonicalPath(); + } else { + docBase = warFile.getCanonicalPath(); + } + } + if (context instanceof StandardContext) { + ((StandardContext) context).setOriginalDocBase(origDocBase); + } + } + } + + if (docBase.startsWith(canonicalAppBase.getPath())) { + docBase = docBase.substring(canonicalAppBase.getPath().length()); + docBase = docBase.replace(File.separatorChar, '/'); + if (docBase.startsWith("/")) { + docBase = docBase.substring(1); + } + } else { + docBase = docBase.replace(File.separatorChar, '/'); + } + + context.setDocBase(docBase); + + } + + + protected void antiLocking() + throws IOException { + + if ((context instanceof StandardContext) + && ((StandardContext) context).getAntiResourceLocking()) { + + Host host = (Host) context.getParent(); + String appBase = host.getAppBase(); + String docBase = context.getDocBase(); + if (docBase == null) + return; + if (originalDocBase == null) { + originalDocBase = docBase; + } else { + docBase = originalDocBase; + } + File docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + File file = new File(appBase); + if (!file.isAbsolute()) { + file = new File(System.getProperty("catalina.base"), appBase); + } + docBaseFile = new File(file, docBase); + } + + String path = context.getPath(); + if (path == null) { + return; + } + if (path.equals("")) { + docBase = "ROOT"; + } else { + if (path.startsWith("/")) { + docBase = path.substring(1); + } else { + docBase = path; + } + } + + File file = null; + if (docBase.toLowerCase().endsWith(".war")) { + file = new File(System.getProperty("java.io.tmpdir"), + deploymentCount++ + "-" + docBase + ".war"); + } else { + file = new File(System.getProperty("java.io.tmpdir"), + deploymentCount++ + "-" + docBase); + } + + if (log.isDebugEnabled()) + log.debug("Anti locking context[" + context.getPath() + + "] setting docBase to " + file); + + // Cleanup just in case an old deployment is lying around + ExpandWar.delete(file); + if (ExpandWar.copy(docBaseFile, file)) { + context.setDocBase(file.getAbsolutePath()); + } + + } + + } + + + /** + * Process a "init" event for this Context. + */ + protected void init() { + // Called from StandardContext.init() + + if (log.isDebugEnabled()) + log.debug(sm.getString("contextConfig.init")); + context.setConfigured(false); + ok = true; + + contextConfig(); + + try { + fixDocBase(); + } catch (IOException e) { + log.error(sm.getString("contextConfig.fixDocBase"), e); + } + + } + + + /** + * Process a "before start" event for this Context. + */ + protected synchronized void beforeStart() { + + try { + antiLocking(); + } catch (IOException e) { + log.error(sm.getString("contextConfig.antiLocking"), e); + } + + } + + + /** + * Process a "start" event for this Context. + */ + protected synchronized void start() { + // Called from StandardContext.start() + + if (log.isDebugEnabled()) + log.debug(sm.getString("contextConfig.start")); + + // Set properties based on DefaultContext + Container container = context.getParent(); + if( !context.getOverride() ) { + if( container instanceof Host ) { + // Reset the value only if the attribute wasn't + // set on the context. + xmlValidation = context.getXmlValidation(); + if (!xmlValidation) { + xmlValidation = ((Host)container).getXmlValidation(); + } + + xmlNamespaceAware = context.getXmlNamespaceAware(); + if (!xmlNamespaceAware){ + xmlNamespaceAware + = ((Host)container).getXmlNamespaceAware(); + } + + container = container.getParent(); + } + } + + // Process the default and application web.xml files + defaultWebConfig(); + applicationWebConfig(); + if (!context.getIgnoreAnnotations()) { + applicationAnnotationsConfig(); + } + if (ok) { + validateSecurityRoles(); + } + + // Configure an authenticator if we need one + if (ok) + authenticatorConfig(); + + // Dump the contents of this pipeline if requested + if ((log.isDebugEnabled()) && (context instanceof ContainerBase)) { + log.debug("Pipeline Configuration:"); + Pipeline pipeline = ((ContainerBase) context).getPipeline(); + Valve valves[] = null; + if (pipeline != null) + valves = pipeline.getValves(); + if (valves != null) { + for (int i = 0; i < valves.length; i++) { + log.debug(" " + valves[i].getInfo()); + } + } + log.debug("======================"); + } + + // Make our application available if no problems were encountered + if (ok) + context.setConfigured(true); + else { + log.error(sm.getString("contextConfig.unavailable")); + context.setConfigured(false); + } + + } + + + /** + * Process a "stop" event for this Context. + */ + protected synchronized void stop() { + + if (log.isDebugEnabled()) + log.debug(sm.getString("contextConfig.stop")); + + int i; + + // Removing children + Container[] children = context.findChildren(); + for (i = 0; i < children.length; i++) { + context.removeChild(children[i]); + } + + // Removing application parameters + /* + ApplicationParameter[] applicationParameters = + context.findApplicationParameters(); + for (i = 0; i < applicationParameters.length; i++) { + context.removeApplicationParameter + (applicationParameters[i].getName()); + } + */ + + // Removing security constraints + SecurityConstraint[] securityConstraints = context.findConstraints(); + for (i = 0; i < securityConstraints.length; i++) { + context.removeConstraint(securityConstraints[i]); + } + + // Removing Ejbs + /* + ContextEjb[] contextEjbs = context.findEjbs(); + for (i = 0; i < contextEjbs.length; i++) { + context.removeEjb(contextEjbs[i].getName()); + } + */ + + // Removing environments + /* + ContextEnvironment[] contextEnvironments = context.findEnvironments(); + for (i = 0; i < contextEnvironments.length; i++) { + context.removeEnvironment(contextEnvironments[i].getName()); + } + */ + + // Removing errors pages + ErrorPage[] errorPages = context.findErrorPages(); + for (i = 0; i < errorPages.length; i++) { + context.removeErrorPage(errorPages[i]); + } + + // Removing filter defs + FilterDef[] filterDefs = context.findFilterDefs(); + for (i = 0; i < filterDefs.length; i++) { + context.removeFilterDef(filterDefs[i]); + } + + // Removing filter maps + FilterMap[] filterMaps = context.findFilterMaps(); + for (i = 0; i < filterMaps.length; i++) { + context.removeFilterMap(filterMaps[i]); + } + + // Removing local ejbs + /* + ContextLocalEjb[] contextLocalEjbs = context.findLocalEjbs(); + for (i = 0; i < contextLocalEjbs.length; i++) { + context.removeLocalEjb(contextLocalEjbs[i].getName()); + } + */ + + // Removing Mime mappings + String[] mimeMappings = context.findMimeMappings(); + for (i = 0; i < mimeMappings.length; i++) { + context.removeMimeMapping(mimeMappings[i]); + } + + // Removing parameters + String[] parameters = context.findParameters(); + for (i = 0; i < parameters.length; i++) { + context.removeParameter(parameters[i]); + } + + // Removing resource env refs + /* + String[] resourceEnvRefs = context.findResourceEnvRefs(); + for (i = 0; i < resourceEnvRefs.length; i++) { + context.removeResourceEnvRef(resourceEnvRefs[i]); + } + */ + + // Removing resource links + /* + ContextResourceLink[] contextResourceLinks = + context.findResourceLinks(); + for (i = 0; i < contextResourceLinks.length; i++) { + context.removeResourceLink(contextResourceLinks[i].getName()); + } + */ + + // Removing resources + /* + ContextResource[] contextResources = context.findResources(); + for (i = 0; i < contextResources.length; i++) { + context.removeResource(contextResources[i].getName()); + } + */ + + // Removing sercurity role + String[] securityRoles = context.findSecurityRoles(); + for (i = 0; i < securityRoles.length; i++) { + context.removeSecurityRole(securityRoles[i]); + } + + // Removing servlet mappings + String[] servletMappings = context.findServletMappings(); + for (i = 0; i < servletMappings.length; i++) { + context.removeServletMapping(servletMappings[i]); + } + + // FIXME : Removing status pages + + // Removing taglibs + String[] taglibs = context.findTaglibs(); + for (i = 0; i < taglibs.length; i++) { + context.removeTaglib(taglibs[i]); + } + + // Removing welcome files + String[] welcomeFiles = context.findWelcomeFiles(); + for (i = 0; i < welcomeFiles.length; i++) { + context.removeWelcomeFile(welcomeFiles[i]); + } + + // Removing wrapper lifecycles + String[] wrapperLifecycles = context.findWrapperLifecycles(); + for (i = 0; i < wrapperLifecycles.length; i++) { + context.removeWrapperLifecycle(wrapperLifecycles[i]); + } + + // Removing wrapper listeners + String[] wrapperListeners = context.findWrapperListeners(); + for (i = 0; i < wrapperListeners.length; i++) { + context.removeWrapperListener(wrapperListeners[i]); + } + + // Remove (partially) folders and files created by antiLocking + Host host = (Host) context.getParent(); + String appBase = host.getAppBase(); + String docBase = context.getDocBase(); + if ((docBase != null) && (originalDocBase != null)) { + File docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + docBaseFile = new File(appBase, docBase); + } + ExpandWar.delete(docBaseFile); + } + + ok = true; + + } + + + /** + * Process a "destroy" event for this Context. + */ + protected synchronized void destroy() { + // Called from StandardContext.destroy() + if (log.isDebugEnabled()) + log.debug(sm.getString("contextConfig.destroy")); + + // Changed to getWorkPath per Bugzilla 35819. + String workDir = ((StandardContext) context).getWorkPath(); + if (workDir != null) + ExpandWar.delete(new File(workDir)); + } + + + /** + * Validate the usage of security role names in the web application + * deployment descriptor. If any problems are found, issue warning + * messages (for backwards compatibility) and add the missing roles. + * (To make these problems fatal instead, simply set the ok + * instance variable to false as well). + */ + protected void validateSecurityRoles() { + + // Check role names used in elements + SecurityConstraint constraints[] = context.findConstraints(); + for (int i = 0; i < constraints.length; i++) { + String roles[] = constraints[i].findAuthRoles(); + for (int j = 0; j < roles.length; j++) { + if (!"*".equals(roles[j]) && + !context.findSecurityRole(roles[j])) { + log.info(sm.getString("contextConfig.role.auth", roles[j])); + context.addSecurityRole(roles[j]); + } + } + } + + // Check role names used in elements + Container wrappers[] = context.findChildren(); + for (int i = 0; i < wrappers.length; i++) { + Wrapper wrapper = (Wrapper) wrappers[i]; + String runAs = wrapper.getRunAs(); + if ((runAs != null) && !context.findSecurityRole(runAs)) { + log.info(sm.getString("contextConfig.role.runas", runAs)); + context.addSecurityRole(runAs); + } + String names[] = wrapper.findSecurityReferences(); + for (int j = 0; j < names.length; j++) { + String link = wrapper.findSecurityReference(names[j]); + if ((link != null) && !context.findSecurityRole(link)) { + log.info(sm.getString("contextConfig.role.link", link)); + context.addSecurityRole(link); + } + } + } + + } + + + /** + * Get config base. + */ + protected File getConfigBase() { + File configBase = + new File(System.getProperty("catalina.base"), "conf"); + if (!configBase.exists()) { + return null; + } else { + return configBase; + } + } + + + protected String getHostConfigPath(String resourceName) { + StringBuffer result = new StringBuffer(); + Container container = context; + Container host = null; + Container engine = null; + while (container != null) { + if (container instanceof Host) + host = container; + if (container instanceof Engine) + engine = container; + container = container.getParent(); + } + if (engine != null) { + result.append(engine.getName()).append('/'); + } + if (host != null) { + result.append(host.getName()).append('/'); + } + result.append(resourceName); + return result.toString(); + } + + + protected class ContextErrorHandler + implements ErrorHandler { + + public void error(SAXParseException exception) { + parseException = exception; + } + + public void fatalError(SAXParseException exception) { + parseException = exception; + } + + public void warning(SAXParseException exception) { + parseException = exception; + } + + } + + +} diff --git a/java/org/apache/catalina/startup/ContextRuleSet.java b/java/org/apache/catalina/startup/ContextRuleSet.java index cea29fe2d..252b31174 100644 --- a/java/org/apache/catalina/startup/ContextRuleSet.java +++ b/java/org/apache/catalina/startup/ContextRuleSet.java @@ -1,292 +1,292 @@ -/* - * Copyright 1999-2001,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.lang.reflect.Constructor; - -import org.apache.catalina.Container; -import org.apache.catalina.Loader; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.Rule; -import org.apache.tomcat.util.digester.RuleSetBase; -import org.xml.sax.Attributes; - - -/** - *

        RuleSet for processing the contents of a - * Context or DefaultContext definition element. To enable parsing of a - * DefaultContext, be sure to specify a prefix that ends with "/Default".

        - * - * @author Craig R. McClanahan - * @version $Revision: 345090 $ $Date: 2005-11-16 19:51:09 +0100 (mer., 16 nov. 2005) $ - */ - -public class ContextRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - /** - * Should the context be created. - */ - protected boolean create = true; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public ContextRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public ContextRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public ContextRuleSet(String prefix, boolean create) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - this.create = create; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - if (create) { - digester.addObjectCreate(prefix + "Context", - "org.apache.catalina.core.StandardContext", "className"); - digester.addSetProperties(prefix + "Context"); - } else { - digester.addRule(prefix + "Context", new SetContextPropertiesRule()); - } - - if (create) { - digester.addRule(prefix + "Context", - new LifecycleListenerRule - ("org.apache.catalina.startup.ContextConfig", - "configClass")); - digester.addSetNext(prefix + "Context", - "addChild", - "org.apache.catalina.Container"); - } - digester.addCallMethod(prefix + "Context/InstanceListener", - "addInstanceListener", 0); - - digester.addObjectCreate(prefix + "Context/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Context/Listener"); - digester.addSetNext(prefix + "Context/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - digester.addRule(prefix + "Context/Loader", - new CreateLoaderRule - ("org.apache.catalina.loader.WebappLoader", - "className")); - digester.addSetProperties(prefix + "Context/Loader"); - digester.addSetNext(prefix + "Context/Loader", - "setLoader", - "org.apache.catalina.Loader"); - - digester.addObjectCreate(prefix + "Context/Manager", - "org.apache.catalina.session.StandardManager", - "className"); - digester.addSetProperties(prefix + "Context/Manager"); - digester.addSetNext(prefix + "Context/Manager", - "setManager", - "org.apache.catalina.Manager"); - - digester.addObjectCreate(prefix + "Context/Manager/Store", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Context/Manager/Store"); - digester.addSetNext(prefix + "Context/Manager/Store", - "setStore", - "org.apache.catalina.Store"); - - digester.addObjectCreate(prefix + "Context/Parameter", - "org.apache.catalina.deploy.ApplicationParameter"); - digester.addSetProperties(prefix + "Context/Parameter"); - digester.addSetNext(prefix + "Context/Parameter", - "addApplicationParameter", - "org.apache.catalina.deploy.ApplicationParameter"); - - digester.addObjectCreate(prefix + "Context/Realm", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Context/Realm"); - digester.addSetNext(prefix + "Context/Realm", - "setRealm", - "org.apache.catalina.Realm"); - - digester.addObjectCreate(prefix + "Context/Resources", - "org.apache.naming.resources.FileDirContext", - "className"); - digester.addSetProperties(prefix + "Context/Resources"); - digester.addSetNext(prefix + "Context/Resources", - "setResources", - "javax.naming.directory.DirContext"); - - digester.addObjectCreate(prefix + "Context/ResourceLink", - "org.apache.catalina.deploy.ContextResourceLink"); - digester.addSetProperties(prefix + "Context/ResourceLink"); - digester.addRule(prefix + "Context/ResourceLink", - new SetNextNamingRule("addResourceLink", - "org.apache.catalina.deploy.ContextResourceLink")); - - digester.addObjectCreate(prefix + "Context/Valve", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Context/Valve"); - digester.addSetNext(prefix + "Context/Valve", - "addValve", - "org.apache.catalina.Valve"); - - digester.addCallMethod(prefix + "Context/WatchedResource", - "addWatchedResource", 0); - - digester.addCallMethod(prefix + "Context/WrapperLifecycle", - "addWrapperLifecycle", 0); - - digester.addCallMethod(prefix + "Context/WrapperListener", - "addWrapperListener", 0); - - } - -} - - -// ----------------------------------------------------------- Private Classes - - -/** - * Rule that creates a new Loader instance, with the parent - * class loader associated with the top object on the stack (which must be - * a Container), and pushes it on to the stack. - */ - -final class CreateLoaderRule extends Rule { - - public CreateLoaderRule(String loaderClass, String attributeName) { - - this.loaderClass = loaderClass; - this.attributeName = attributeName; - - } - - private String attributeName; - - private String loaderClass; - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - // Look up the required parent class loader - ClassLoader parentClassLoader = null; - Object ojb = digester.peek(); - if (ojb instanceof Container) { - parentClassLoader = ((Container)ojb).getParentClassLoader(); - } - - // Bugzilla 36852: http://issues.apache.org/bugzilla/show_bug.cgi?id=36852 - if((ojb instanceof org.apache.catalina.Context) && - (((org.apache.catalina.Context) ojb).getPrivileged())) { - parentClassLoader = ojb.getClass().getClassLoader(); - } - - // Instantiate a new Loader implementation object - String className = loaderClass; - if (attributeName != null) { - String value = attributes.getValue(attributeName); - if (value != null) - className = value; - } - Class clazz = Class.forName(className); - Class types[] = { ClassLoader.class }; - Object args[] = { parentClassLoader }; - Constructor constructor = clazz.getDeclaredConstructor(types); - Loader loader = (Loader) constructor.newInstance(args); - - // Push the new loader onto the stack - digester.push(loader); - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("new " + loader.getClass().getName()); - - } - - public void end(String namespace, String name) - throws Exception { - - Loader loader = (Loader) digester.pop(); - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("pop " + loader.getClass().getName()); - - } - - -} +/* + * Copyright 1999-2001,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.lang.reflect.Constructor; + +import org.apache.catalina.Container; +import org.apache.catalina.Loader; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.Rule; +import org.apache.tomcat.util.digester.RuleSetBase; +import org.xml.sax.Attributes; + + +/** + *

        RuleSet for processing the contents of a + * Context or DefaultContext definition element. To enable parsing of a + * DefaultContext, be sure to specify a prefix that ends with "/Default".

        + * + * @author Craig R. McClanahan + * @version $Revision: 345090 $ $Date: 2005-11-16 19:51:09 +0100 (mer., 16 nov. 2005) $ + */ + +public class ContextRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + /** + * Should the context be created. + */ + protected boolean create = true; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public ContextRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public ContextRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public ContextRuleSet(String prefix, boolean create) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + this.create = create; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + if (create) { + digester.addObjectCreate(prefix + "Context", + "org.apache.catalina.core.StandardContext", "className"); + digester.addSetProperties(prefix + "Context"); + } else { + digester.addRule(prefix + "Context", new SetContextPropertiesRule()); + } + + if (create) { + digester.addRule(prefix + "Context", + new LifecycleListenerRule + ("org.apache.catalina.startup.ContextConfig", + "configClass")); + digester.addSetNext(prefix + "Context", + "addChild", + "org.apache.catalina.Container"); + } + digester.addCallMethod(prefix + "Context/InstanceListener", + "addInstanceListener", 0); + + digester.addObjectCreate(prefix + "Context/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Context/Listener"); + digester.addSetNext(prefix + "Context/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + digester.addRule(prefix + "Context/Loader", + new CreateLoaderRule + ("org.apache.catalina.loader.WebappLoader", + "className")); + digester.addSetProperties(prefix + "Context/Loader"); + digester.addSetNext(prefix + "Context/Loader", + "setLoader", + "org.apache.catalina.Loader"); + + digester.addObjectCreate(prefix + "Context/Manager", + "org.apache.catalina.session.StandardManager", + "className"); + digester.addSetProperties(prefix + "Context/Manager"); + digester.addSetNext(prefix + "Context/Manager", + "setManager", + "org.apache.catalina.Manager"); + + digester.addObjectCreate(prefix + "Context/Manager/Store", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Context/Manager/Store"); + digester.addSetNext(prefix + "Context/Manager/Store", + "setStore", + "org.apache.catalina.Store"); + + digester.addObjectCreate(prefix + "Context/Parameter", + "org.apache.catalina.deploy.ApplicationParameter"); + digester.addSetProperties(prefix + "Context/Parameter"); + digester.addSetNext(prefix + "Context/Parameter", + "addApplicationParameter", + "org.apache.catalina.deploy.ApplicationParameter"); + + digester.addObjectCreate(prefix + "Context/Realm", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Context/Realm"); + digester.addSetNext(prefix + "Context/Realm", + "setRealm", + "org.apache.catalina.Realm"); + + digester.addObjectCreate(prefix + "Context/Resources", + "org.apache.naming.resources.FileDirContext", + "className"); + digester.addSetProperties(prefix + "Context/Resources"); + digester.addSetNext(prefix + "Context/Resources", + "setResources", + "javax.naming.directory.DirContext"); + + digester.addObjectCreate(prefix + "Context/ResourceLink", + "org.apache.catalina.deploy.ContextResourceLink"); + digester.addSetProperties(prefix + "Context/ResourceLink"); + digester.addRule(prefix + "Context/ResourceLink", + new SetNextNamingRule("addResourceLink", + "org.apache.catalina.deploy.ContextResourceLink")); + + digester.addObjectCreate(prefix + "Context/Valve", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Context/Valve"); + digester.addSetNext(prefix + "Context/Valve", + "addValve", + "org.apache.catalina.Valve"); + + digester.addCallMethod(prefix + "Context/WatchedResource", + "addWatchedResource", 0); + + digester.addCallMethod(prefix + "Context/WrapperLifecycle", + "addWrapperLifecycle", 0); + + digester.addCallMethod(prefix + "Context/WrapperListener", + "addWrapperListener", 0); + + } + +} + + +// ----------------------------------------------------------- Private Classes + + +/** + * Rule that creates a new Loader instance, with the parent + * class loader associated with the top object on the stack (which must be + * a Container), and pushes it on to the stack. + */ + +final class CreateLoaderRule extends Rule { + + public CreateLoaderRule(String loaderClass, String attributeName) { + + this.loaderClass = loaderClass; + this.attributeName = attributeName; + + } + + private String attributeName; + + private String loaderClass; + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + // Look up the required parent class loader + ClassLoader parentClassLoader = null; + Object ojb = digester.peek(); + if (ojb instanceof Container) { + parentClassLoader = ((Container)ojb).getParentClassLoader(); + } + + // Bugzilla 36852: http://issues.apache.org/bugzilla/show_bug.cgi?id=36852 + if((ojb instanceof org.apache.catalina.Context) && + (((org.apache.catalina.Context) ojb).getPrivileged())) { + parentClassLoader = ojb.getClass().getClassLoader(); + } + + // Instantiate a new Loader implementation object + String className = loaderClass; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) + className = value; + } + Class clazz = Class.forName(className); + Class types[] = { ClassLoader.class }; + Object args[] = { parentClassLoader }; + Constructor constructor = clazz.getDeclaredConstructor(types); + Loader loader = (Loader) constructor.newInstance(args); + + // Push the new loader onto the stack + digester.push(loader); + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("new " + loader.getClass().getName()); + + } + + public void end(String namespace, String name) + throws Exception { + + Loader loader = (Loader) digester.pop(); + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("pop " + loader.getClass().getName()); + + } + + +} diff --git a/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java b/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java index f284d9aa8..604aa3a84 100644 --- a/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java +++ b/java/org/apache/catalina/startup/CopyParentClassLoaderRule.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.lang.reflect.Method; -import org.apache.catalina.Container; -import org.apache.tomcat.util.digester.Rule; -import org.xml.sax.Attributes; - - -/** - *

        Rule that copies the parentClassLoader property from the - * next-to-top item on the stack (which must be a Container) - * to the top item on the stack (which must also be a - * Container).

        - * - * @author Craig R. McClanahan - * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ - */ - -public class CopyParentClassLoaderRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this Rule. - */ - public CopyParentClassLoaderRule() { - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Handle the beginning of an XML element. - * - * @param attributes The attributes of this element - * - * @exception Exception if a processing error occurs - */ - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("Copying parent class loader"); - Container child = (Container) digester.peek(0); - Object parent = digester.peek(1); - Method method = - parent.getClass().getMethod("getParentClassLoader", new Class[0]); - ClassLoader classLoader = - (ClassLoader) method.invoke(parent, new Object[0]); - child.setParentClassLoader(classLoader); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.lang.reflect.Method; +import org.apache.catalina.Container; +import org.apache.tomcat.util.digester.Rule; +import org.xml.sax.Attributes; + + +/** + *

        Rule that copies the parentClassLoader property from the + * next-to-top item on the stack (which must be a Container) + * to the top item on the stack (which must also be a + * Container).

        + * + * @author Craig R. McClanahan + * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ + */ + +public class CopyParentClassLoaderRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this Rule. + */ + public CopyParentClassLoaderRule() { + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Handle the beginning of an XML element. + * + * @param attributes The attributes of this element + * + * @exception Exception if a processing error occurs + */ + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("Copying parent class loader"); + Container child = (Container) digester.peek(0); + Object parent = digester.peek(1); + Method method = + parent.getClass().getMethod("getParentClassLoader", new Class[0]); + ClassLoader classLoader = + (ClassLoader) method.invoke(parent, new Object[0]); + child.setParentClassLoader(classLoader); + + } + + +} diff --git a/java/org/apache/catalina/startup/DigesterFactory.java b/java/org/apache/catalina/startup/DigesterFactory.java index 41bc62ac1..048d182d1 100644 --- a/java/org/apache/catalina/startup/DigesterFactory.java +++ b/java/org/apache/catalina/startup/DigesterFactory.java @@ -1,164 +1,164 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import java.net.URL; - -import org.apache.catalina.util.SchemaResolver; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.RuleSet; - -/** - * Wrapper class around the Digester that hide Digester's initialization details - * - * @author Jean-Francois Arcand - */ -public class DigesterFactory { - /** - * The log. - */ - protected static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(DigesterFactory.class); - - /** - * The XML entiry resolver used by the Digester. - */ - private static SchemaResolver schemaResolver; - - - /** - * Create a Digester parser with no Rule - * associated and XML validation turned off. - */ - public static Digester newDigester(){ - return newDigester(false, false, null); - } - - - /** - * Create a Digester parser with XML validation turned off. - * @param rule an instance of RuleSet used for parsing the xml. - */ - public static Digester newDigester(RuleSet rule){ - return newDigester(false,false,rule); - } - - - /** - * Create a Digester parser. - * @param xmlValidation turn on/off xml validation - * @param xmlNamespaceAware turn on/off namespace validation - * @param rule an instance of RuleSet used for parsing the xml. - */ - public static Digester newDigester(boolean xmlValidation, - boolean xmlNamespaceAware, - RuleSet rule) { - Digester digester = new Digester(); - digester.setNamespaceAware(xmlNamespaceAware); - digester.setValidating(xmlValidation); - digester.setUseContextClassLoader(true); - - if (xmlValidation || xmlNamespaceAware){ - configureSchema(digester); - } - - schemaResolver = new SchemaResolver(digester); - registerLocalSchema(); - - digester.setEntityResolver(schemaResolver); - if ( rule != null ) { - digester.addRuleSet(rule); - } - - return (digester); - } - - - /** - * Utilities used to force the parser to use local schema, when available, - * instead of the schemaLocation XML element. - */ - protected static void registerLocalSchema(){ - // J2EE - register(Constants.J2eeSchemaResourcePath_14, - Constants.J2eeSchemaPublicId_14); - // W3C - register(Constants.W3cSchemaResourcePath_10, - Constants.W3cSchemaPublicId_10); - // JSP - register(Constants.JspSchemaResourcePath_20, - Constants.JspSchemaPublicId_20); - // TLD - register(Constants.TldDtdResourcePath_11, - Constants.TldDtdPublicId_11); - - register(Constants.TldDtdResourcePath_12, - Constants.TldDtdPublicId_12); - - register(Constants.TldSchemaResourcePath_20, - Constants.TldSchemaPublicId_20); - - // web.xml - register(Constants.WebDtdResourcePath_22, - Constants.WebDtdPublicId_22); - - register(Constants.WebDtdResourcePath_23, - Constants.WebDtdPublicId_23); - - register(Constants.WebSchemaResourcePath_24, - Constants.WebSchemaPublicId_24); - - // Web Service - register(Constants.J2eeWebServiceSchemaResourcePath_11, - Constants.J2eeWebServiceSchemaPublicId_11); - - register(Constants.J2eeWebServiceClientSchemaResourcePath_11, - Constants.J2eeWebServiceClientSchemaPublicId_11); - - } - - - /** - * Load the resource and add it to the resolver. - */ - protected static void register(String resourceURL, String resourcePublicId){ - URL url = DigesterFactory.class.getResource(resourceURL); - - if(url == null) { - log.warn("Could not get url for " + resourceURL); - } else { - schemaResolver.register(resourcePublicId , url.toString() ); - } - } - - - /** - * Turn on DTD and/or validation (based on the parser implementation) - */ - protected static void configureSchema(Digester digester){ - URL url = DigesterFactory.class - .getResource(Constants.WebSchemaResourcePath_24); - - if(url == null) { - log.error("Could not get url for " - + Constants.WebSchemaResourcePath_24); - } else { - digester.setSchema(url.toString()); - } - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import java.net.URL; + +import org.apache.catalina.util.SchemaResolver; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSet; + +/** + * Wrapper class around the Digester that hide Digester's initialization details + * + * @author Jean-Francois Arcand + */ +public class DigesterFactory { + /** + * The log. + */ + protected static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(DigesterFactory.class); + + /** + * The XML entiry resolver used by the Digester. + */ + private static SchemaResolver schemaResolver; + + + /** + * Create a Digester parser with no Rule + * associated and XML validation turned off. + */ + public static Digester newDigester(){ + return newDigester(false, false, null); + } + + + /** + * Create a Digester parser with XML validation turned off. + * @param rule an instance of RuleSet used for parsing the xml. + */ + public static Digester newDigester(RuleSet rule){ + return newDigester(false,false,rule); + } + + + /** + * Create a Digester parser. + * @param xmlValidation turn on/off xml validation + * @param xmlNamespaceAware turn on/off namespace validation + * @param rule an instance of RuleSet used for parsing the xml. + */ + public static Digester newDigester(boolean xmlValidation, + boolean xmlNamespaceAware, + RuleSet rule) { + Digester digester = new Digester(); + digester.setNamespaceAware(xmlNamespaceAware); + digester.setValidating(xmlValidation); + digester.setUseContextClassLoader(true); + + if (xmlValidation || xmlNamespaceAware){ + configureSchema(digester); + } + + schemaResolver = new SchemaResolver(digester); + registerLocalSchema(); + + digester.setEntityResolver(schemaResolver); + if ( rule != null ) { + digester.addRuleSet(rule); + } + + return (digester); + } + + + /** + * Utilities used to force the parser to use local schema, when available, + * instead of the schemaLocation XML element. + */ + protected static void registerLocalSchema(){ + // J2EE + register(Constants.J2eeSchemaResourcePath_14, + Constants.J2eeSchemaPublicId_14); + // W3C + register(Constants.W3cSchemaResourcePath_10, + Constants.W3cSchemaPublicId_10); + // JSP + register(Constants.JspSchemaResourcePath_20, + Constants.JspSchemaPublicId_20); + // TLD + register(Constants.TldDtdResourcePath_11, + Constants.TldDtdPublicId_11); + + register(Constants.TldDtdResourcePath_12, + Constants.TldDtdPublicId_12); + + register(Constants.TldSchemaResourcePath_20, + Constants.TldSchemaPublicId_20); + + // web.xml + register(Constants.WebDtdResourcePath_22, + Constants.WebDtdPublicId_22); + + register(Constants.WebDtdResourcePath_23, + Constants.WebDtdPublicId_23); + + register(Constants.WebSchemaResourcePath_24, + Constants.WebSchemaPublicId_24); + + // Web Service + register(Constants.J2eeWebServiceSchemaResourcePath_11, + Constants.J2eeWebServiceSchemaPublicId_11); + + register(Constants.J2eeWebServiceClientSchemaResourcePath_11, + Constants.J2eeWebServiceClientSchemaPublicId_11); + + } + + + /** + * Load the resource and add it to the resolver. + */ + protected static void register(String resourceURL, String resourcePublicId){ + URL url = DigesterFactory.class.getResource(resourceURL); + + if(url == null) { + log.warn("Could not get url for " + resourceURL); + } else { + schemaResolver.register(resourcePublicId , url.toString() ); + } + } + + + /** + * Turn on DTD and/or validation (based on the parser implementation) + */ + protected static void configureSchema(Digester digester){ + URL url = DigesterFactory.class + .getResource(Constants.WebSchemaResourcePath_24); + + if(url == null) { + log.error("Could not get url for " + + Constants.WebSchemaResourcePath_24); + } else { + digester.setSchema(url.toString()); + } + } +} diff --git a/java/org/apache/catalina/startup/Embedded.java b/java/org/apache/catalina/startup/Embedded.java index 39d631be9..cd177031c 100644 --- a/java/org/apache/catalina/startup/Embedded.java +++ b/java/org/apache/catalina/startup/Embedded.java @@ -1,993 +1,993 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.io.IOException; -import java.net.InetAddress; -import java.util.HashMap; - -import org.apache.catalina.Authenticator; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Loader; -import org.apache.catalina.Realm; -import org.apache.catalina.Valve; -import org.apache.catalina.connector.Connector; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.core.StandardEngine; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.core.StandardService; -import org.apache.catalina.loader.WebappLoader; -import org.apache.catalina.security.SecurityConfig; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.log.SystemLogHandler; - - -/** - * Convenience class to embed a Catalina servlet container environment - * inside another application. You must call the methods of this class in the - * following order to ensure correct operation. - * - *
          - *
        • Instantiate a new instance of this class.
        • - *
        • Set the relevant properties of this object itself. In particular, - * you will want to establish the default Logger to be used, as well - * as the default Realm if you are using container-managed security.
        • - *
        • Call createEngine() to create an Engine object, and then - * call its property setters as desired.
        • - *
        • Call createHost() to create at least one virtual Host - * associated with the newly created Engine, and then call its property - * setters as desired. After you customize this Host, add it to the - * corresponding Engine with engine.addChild(host).
        • - *
        • Call createContext() to create at least one Context - * associated with each newly created Host, and then call its property - * setters as desired. You SHOULD create a Context with - * a pathname equal to a zero-length string, which will be used to process - * all requests not mapped to some other Context. After you customize - * this Context, add it to the corresponding Host with - * host.addChild(context).
        • - *
        • Call addEngine() to attach this Engine to the set of - * defined Engines for this object.
        • - *
        • Call createConnector() to create at least one TCP/IP - * connector, and then call its property setters as desired.
        • - *
        • Call addConnector() to attach this Connector to the set - * of defined Connectors for this object. The added Connector will use - * the most recently added Engine to process its received requests.
        • - *
        • Repeat the above series of steps as often as required (although there - * will typically be only one Engine instance created).
        • - *
        • Call start() to initiate normal operations of all the - * attached components.
        • - *
        - * - * After normal operations have begun, you can add and remove Connectors, - * Engines, Hosts, and Contexts on the fly. However, once you have removed - * a particular component, it must be thrown away -- you can create a new one - * with the same characteristics if you merely want to do a restart. - *

        - * To initiate a normal shutdown, call the stop() method of - * this object. - *

        - * @see org.apache.catalina.startup.Catalina#main For a complete example - * of how Tomcat is set up and launched as an Embedded application. - * - * @author Craig R. McClanahan - * @version $Revision: 304107 $ $Date: 2005-09-29 07:52:48 +0200 (jeu., 29 sept. 2005) $ - */ - -public class Embedded extends StandardService implements Lifecycle { - private static Log log = LogFactory.getLog(Embedded.class); - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default properties. - */ - public Embedded() { - - this(null); - - } - - - /** - * Construct a new instance of this class with specified properties. - * - * @param realm Realm implementation to be inherited by all components - * (unless overridden further down the container hierarchy) - */ - public Embedded(Realm realm) { - - super(); - setRealm(realm); - setSecurityProtection(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Is naming enabled ? - */ - protected boolean useNaming = true; - - - /** - * Is standard streams redirection enabled ? - */ - protected boolean redirectStreams = true; - - - /** - * The set of Engines that have been deployed in this server. Normally - * there will only be one. - */ - protected Engine engines[] = new Engine[0]; - - - /** - * Custom mappings of login methods to authenticators - */ - protected HashMap authenticators; - - - /** - * Descriptive information about this server implementation. - */ - protected static final String info = - "org.apache.catalina.startup.Embedded/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The default realm to be used by all containers associated with - * this compoennt. - */ - protected Realm realm = null; - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - protected boolean started = false; - - /** - * Use await. - */ - protected boolean await = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Return true if naming is enabled. - */ - public boolean isUseNaming() { - - return (this.useNaming); - - } - - - /** - * Enables or disables naming support. - * - * @param useNaming The new use naming value - */ - public void setUseNaming(boolean useNaming) { - - boolean oldUseNaming = this.useNaming; - this.useNaming = useNaming; - support.firePropertyChange("useNaming", new Boolean(oldUseNaming), - new Boolean(this.useNaming)); - - } - - - /** - * Return true if redirction of standard streams is enabled. - */ - public boolean isRedirectStreams() { - - return (this.redirectStreams); - - } - - - /** - * Enables or disables naming support. - * - * @param useNaming The new use naming value - */ - public void setRedirectStreams(boolean redirectStreams) { - - boolean oldRedirectStreams = this.redirectStreams; - this.redirectStreams = redirectStreams; - support.firePropertyChange("redirectStreams", new Boolean(oldRedirectStreams), - new Boolean(this.redirectStreams)); - - } - - - /** - * Return the default Realm for our Containers. - */ - public Realm getRealm() { - - return (this.realm); - - } - - - /** - * Set the default Realm for our Containers. - * - * @param realm The new default realm - */ - public void setRealm(Realm realm) { - - Realm oldRealm = this.realm; - this.realm = realm; - support.firePropertyChange("realm", oldRealm, this.realm); - - } - - public void setAwait(boolean b) { - await = b; - } - - public boolean isAwait() { - return await; - } - - public void setCatalinaHome( String s ) { - System.setProperty( "catalina.home", s); - } - - public void setCatalinaBase( String s ) { - System.setProperty( "catalina.base", s); - } - - public String getCatalinaHome() { - return System.getProperty("catalina.home"); - } - - public String getCatalinaBase() { - return System.getProperty("catalina.base"); - } - - - // --------------------------------------------------------- Public Methods - - /** - * Add a new Connector to the set of defined Connectors. The newly - * added Connector will be associated with the most recently added Engine. - * - * @param connector The connector to be added - * - * @exception IllegalStateException if no engines have been added yet - */ - public synchronized void addConnector(Connector connector) { - - if( log.isDebugEnabled() ) { - log.debug("Adding connector (" + connector.getInfo() + ")"); - } - - // Make sure we have a Container to send requests to - if (engines.length < 1) - throw new IllegalStateException - (sm.getString("embedded.noEngines")); - - /* - * Add the connector. This will set the connector's container to the - * most recently added Engine - */ - super.addConnector(connector); - } - - - /** - * Add a new Engine to the set of defined Engines. - * - * @param engine The engine to be added - */ - public synchronized void addEngine(Engine engine) { - - if( log.isDebugEnabled() ) - log.debug("Adding engine (" + engine.getInfo() + ")"); - - // Add this Engine to our set of defined Engines - Engine results[] = new Engine[engines.length + 1]; - for (int i = 0; i < engines.length; i++) - results[i] = engines[i]; - results[engines.length] = engine; - engines = results; - - // Start this Engine if necessary - if (started && (engine instanceof Lifecycle)) { - try { - ((Lifecycle) engine).start(); - } catch (LifecycleException e) { - log.error("Engine.start", e); - } - } - - this.container = engine; - } - - - /** - * Create, configure, and return a new TCP/IP socket connector - * based on the specified properties. - * - * @param address InetAddress to bind to, or null if the - * connector is supposed to bind to all addresses on this server - * @param port Port number to listen to - * @param secure true if the generated connector is supposed to be - * SSL-enabled, and false otherwise - */ - public Connector createConnector(InetAddress address, int port, - boolean secure) { - return createConnector(address != null? address.toString() : null, - port, secure); - } - - public Connector createConnector(String address, int port, - boolean secure) { - String protocol = "http"; - if (secure) { - protocol = "https"; - } - - return createConnector(address, port, protocol); - } - - - public Connector createConnector(InetAddress address, int port, - String protocol) { - return createConnector(address != null? address.toString() : null, - port, protocol); - } - - public Connector createConnector(String address, int port, - String protocol) { - - Connector connector = null; - - if (address != null) { - /* - * InetAddress.toString() returns a string of the form - * "/". Get the latter part, so that the - * address can be parsed (back) into an InetAddress using - * InetAddress.getByName(). - */ - int index = address.indexOf('/'); - if (index != -1) { - address = address.substring(index + 1); - } - } - - if (log.isDebugEnabled()) { - log.debug("Creating connector for address='" + - ((address == null) ? "ALL" : address) + - "' port='" + port + "' protocol='" + protocol + "'"); - } - - try { - - if (protocol.equals("ajp")) { - connector = new Connector("org.apache.jk.server.JkCoyoteHandler"); - } else if (protocol.equals("memory")) { - connector = new Connector("org.apache.coyote.memory.MemoryProtocolHandler"); - } else if (protocol.equals("http")) { - connector = new Connector(); - } else if (protocol.equals("https")) { - connector = new Connector(); - connector.setScheme("https"); - connector.setSecure(true); - // FIXME !!!! SET SSL PROPERTIES - } - - if (address != null) { - IntrospectionUtils.setProperty(connector, "address", - "" + address); - } - IntrospectionUtils.setProperty(connector, "port", "" + port); - - } catch (Exception e) { - log.error("Couldn't create connector."); - } - - return (connector); - - } - - /** - * Create, configure, and return a Context that will process all - * HTTP requests received from one of the associated Connectors, - * and directed to the specified context path on the virtual host - * to which this Context is connected. - *

        - * After you have customized the properties, listeners, and Valves - * for this Context, you must attach it to the corresponding Host - * by calling: - *

        -     *   host.addChild(context);
        -     * 
        - * which will also cause the Context to be started if the Host has - * already been started. - * - * @param path Context path of this application ("" for the default - * application for this host, must start with a slash otherwise) - * @param docBase Absolute pathname to the document base directory - * for this web application - * - * @exception IllegalArgumentException if an invalid parameter - * is specified - */ - public Context createContext(String path, String docBase) { - - if( log.isDebugEnabled() ) - log.debug("Creating context '" + path + "' with docBase '" + - docBase + "'"); - - StandardContext context = new StandardContext(); - - context.setDocBase(docBase); - context.setPath(path); - - ContextConfig config = new ContextConfig(); - config.setCustomAuthenticators(authenticators); - ((Lifecycle) context).addLifecycleListener(config); - - return (context); - - } - - - /** - * Create, configure, and return an Engine that will process all - * HTTP requests received from one of the associated Connectors, - * based on the specified properties. - */ - public Engine createEngine() { - - if( log.isDebugEnabled() ) - log.debug("Creating engine"); - - StandardEngine engine = new StandardEngine(); - - // Default host will be set to the first host added - engine.setRealm(realm); // Inherited by all children - - return (engine); - - } - - - /** - * Create, configure, and return a Host that will process all - * HTTP requests received from one of the associated Connectors, - * and directed to the specified virtual host. - *

        - * After you have customized the properties, listeners, and Valves - * for this Host, you must attach it to the corresponding Engine - * by calling: - *

        -     *   engine.addChild(host);
        -     * 
        - * which will also cause the Host to be started if the Engine has - * already been started. If this is the default (or only) Host you - * will be defining, you may also tell the Engine to pass all requests - * not assigned to another virtual host to this one: - *
        -     *   engine.setDefaultHost(host.getName());
        -     * 
        - * - * @param name Canonical name of this virtual host - * @param appBase Absolute pathname to the application base directory - * for this virtual host - * - * @exception IllegalArgumentException if an invalid parameter - * is specified - */ - public Host createHost(String name, String appBase) { - - if( log.isDebugEnabled() ) - log.debug("Creating host '" + name + "' with appBase '" + - appBase + "'"); - - StandardHost host = new StandardHost(); - - host.setAppBase(appBase); - host.setName(name); - - return (host); - - } - - - /** - * Create and return a class loader manager that can be customized, and - * then attached to a Context, before it is started. - * - * @param parent ClassLoader that will be the parent of the one - * created by this Loader - */ - public Loader createLoader(ClassLoader parent) { - - if( log.isDebugEnabled() ) - log.debug("Creating Loader with parent class loader '" + - parent + "'"); - - WebappLoader loader = new WebappLoader(parent); - return (loader); - - } - - - /** - * Return descriptive information about this Server implementation and - * the corresponding version number, in the format - * <description>/<version>. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Remove the specified Context from the set of defined Contexts for its - * associated Host. If this is the last Context for this Host, the Host - * will also be removed. - * - * @param context The Context to be removed - */ - public synchronized void removeContext(Context context) { - - if( log.isDebugEnabled() ) - log.debug("Removing context[" + context.getPath() + "]"); - - // Is this Context actually among those that are defined? - boolean found = false; - for (int i = 0; i < engines.length; i++) { - Container hosts[] = engines[i].findChildren(); - for (int j = 0; j < hosts.length; j++) { - Container contexts[] = hosts[j].findChildren(); - for (int k = 0; k < contexts.length; k++) { - if (context == (Context) contexts[k]) { - found = true; - break; - } - } - if (found) - break; - } - if (found) - break; - } - if (!found) - return; - - // Remove this Context from the associated Host - if( log.isDebugEnabled() ) - log.debug(" Removing this Context"); - context.getParent().removeChild(context); - - } - - - /** - * Remove the specified Engine from the set of defined Engines, along with - * all of its related Hosts and Contexts. All associated Connectors are - * also removed. - * - * @param engine The Engine to be removed - */ - public synchronized void removeEngine(Engine engine) { - - if( log.isDebugEnabled() ) - log.debug("Removing engine (" + engine.getInfo() + ")"); - - // Is the specified Engine actually defined? - int j = -1; - for (int i = 0; i < engines.length; i++) { - if (engine == engines[i]) { - j = i; - break; - } - } - if (j < 0) - return; - - // Remove any Connector that is using this Engine - if( log.isDebugEnabled() ) - log.debug(" Removing related Containers"); - while (true) { - int n = -1; - for (int i = 0; i < connectors.length; i++) { - if (connectors[i].getContainer() == (Container) engine) { - n = i; - break; - } - } - if (n < 0) - break; - removeConnector(connectors[n]); - } - - // Stop this Engine if necessary - if (engine instanceof Lifecycle) { - if( log.isDebugEnabled() ) - log.debug(" Stopping this Engine"); - try { - ((Lifecycle) engine).stop(); - } catch (LifecycleException e) { - log.error("Engine.stop", e); - } - } - - // Remove this Engine from our set of defined Engines - if( log.isDebugEnabled() ) - log.debug(" Removing this Engine"); - int k = 0; - Engine results[] = new Engine[engines.length - 1]; - for (int i = 0; i < engines.length; i++) { - if (i != j) - results[k++] = engines[i]; - } - engines = results; - - } - - - /** - * Remove the specified Host, along with all of its related Contexts, - * from the set of defined Hosts for its associated Engine. If this is - * the last Host for this Engine, the Engine will also be removed. - * - * @param host The Host to be removed - */ - public synchronized void removeHost(Host host) { - - if( log.isDebugEnabled() ) - log.debug("Removing host[" + host.getName() + "]"); - - // Is this Host actually among those that are defined? - boolean found = false; - for (int i = 0; i < engines.length; i++) { - Container hosts[] = engines[i].findChildren(); - for (int j = 0; j < hosts.length; j++) { - if (host == (Host) hosts[j]) { - found = true; - break; - - } - } - if (found) - break; - } - if (!found) - return; - - // Remove this Host from the associated Engine - if( log.isDebugEnabled() ) - log.debug(" Removing this Host"); - host.getParent().removeChild(host); - - } - - - /* - * Maps the specified login method to the specified authenticator, allowing - * the mappings in org/apache/catalina/startup/Authenticators.properties - * to be overridden. - * - * @param authenticator Authenticator to handle authentication for the - * specified login method - * @param loginMethod Login method that maps to the specified authenticator - * - * @throws IllegalArgumentException if the specified authenticator does not - * implement the org.apache.catalina.Valve interface - */ - public void addAuthenticator(Authenticator authenticator, - String loginMethod) { - if (!(authenticator instanceof Valve)) { - throw new IllegalArgumentException( - sm.getString("embedded.authenticatorNotInstanceOfValve")); - } - if (authenticators == null) { - synchronized (this) { - if (authenticators == null) { - authenticators = new HashMap(); - } - } - } - authenticators.put(loginMethod, authenticator); - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - if( log.isInfoEnabled() ) - log.info("Starting tomcat server"); - - // Validate the setup of our required system properties - initDirs(); - - // Initialize some naming specific properties - initNaming(); - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("embedded.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - initialized = true; - - // Start our defined Engines first - for (int i = 0; i < engines.length; i++) { - if (engines[i] instanceof Lifecycle) - ((Lifecycle) engines[i]).start(); - } - - // Start our defined Connectors second - for (int i = 0; i < connectors.length; i++) { - connectors[i].initialize(); - if (connectors[i] instanceof Lifecycle) - ((Lifecycle) connectors[i]).start(); - } - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - if( log.isDebugEnabled() ) - log.debug("Stopping embedded server"); - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("embedded.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - // Stop our defined Connectors first - for (int i = 0; i < connectors.length; i++) { - if (connectors[i] instanceof Lifecycle) - ((Lifecycle) connectors[i]).stop(); - } - - // Stop our defined Engines second - for (int i = 0; i < engines.length; i++) { - if (engines[i] instanceof Lifecycle) - ((Lifecycle) engines[i]).stop(); - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** Initialize naming - this should only enable java:env and root naming. - * If tomcat is embeded in an application that already defines those - - * it shouldn't do it. - * - * XXX The 2 should be separated, you may want to enable java: but not - * the initial context and the reverse - * XXX Can we "guess" - i.e. lookup java: and if something is returned assume - * false ? - * XXX We have a major problem with the current setting for java: url - */ - protected void initNaming() { - // Setting additional variables - if (!useNaming) { - log.info( "Catalina naming disabled"); - System.setProperty("catalina.useNaming", "false"); - } else { - System.setProperty("catalina.useNaming", "true"); - String value = "org.apache.naming"; - String oldValue = - System.getProperty(javax.naming.Context.URL_PKG_PREFIXES); - if (oldValue != null) { - value = value + ":" + oldValue; - } - System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value); - if( log.isDebugEnabled() ) - log.debug("Setting naming prefix=" + value); - value = System.getProperty - (javax.naming.Context.INITIAL_CONTEXT_FACTORY); - if (value == null) { - System.setProperty - (javax.naming.Context.INITIAL_CONTEXT_FACTORY, - "org.apache.naming.java.javaURLContextFactory"); - } else { - log.debug( "INITIAL_CONTEXT_FACTORY alread set " + value ); - } - } - } - - - protected void initDirs() { - - String catalinaHome = System.getProperty("catalina.home"); - if (catalinaHome == null) { - // Backwards compatibility patch for J2EE RI 1.3 - String j2eeHome = System.getProperty("com.sun.enterprise.home"); - if (j2eeHome != null) { - catalinaHome=System.getProperty("com.sun.enterprise.home"); - } else if (System.getProperty("catalina.base") != null) { - catalinaHome = System.getProperty("catalina.base"); - } else { - // Use IntrospectionUtils and guess the dir - catalinaHome = IntrospectionUtils.guessInstall - ("catalina.home", "catalina.base", "catalina.jar"); - if (catalinaHome == null) { - catalinaHome = IntrospectionUtils.guessInstall - ("tomcat.install", "catalina.home", "tomcat.jar"); - } - } - } - // last resort - for minimal/embedded cases. - if(catalinaHome==null) { - catalinaHome=System.getProperty("user.dir"); - } - if (catalinaHome != null) { - File home = new File(catalinaHome); - if (!home.isAbsolute()) { - try { - catalinaHome = home.getCanonicalPath(); - } catch (IOException e) { - catalinaHome = home.getAbsolutePath(); - } - } - System.setProperty("catalina.home", catalinaHome); - } - - if (System.getProperty("catalina.base") == null) { - System.setProperty("catalina.base", - catalinaHome); - } else { - String catalinaBase = System.getProperty("catalina.base"); - File base = new File(catalinaBase); - if (!base.isAbsolute()) { - try { - catalinaBase = base.getCanonicalPath(); - } catch (IOException e) { - catalinaBase = base.getAbsolutePath(); - } - } - System.setProperty("catalina.base", catalinaBase); - } - - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null || (!(new File(temp)).exists()) - || (!(new File(temp)).isDirectory())) { - log.error(sm.getString("embedded.notmp", temp)); - } - - } - - - protected void initStreams() { - if (redirectStreams) { - // Replace System.out and System.err with a custom PrintStream - SystemLogHandler systemlog = new SystemLogHandler(System.out); - System.setOut(systemlog); - System.setErr(systemlog); - } - } - - - // -------------------------------------------------------- Private Methods - - /** - * Set the security package access/protection. - */ - protected void setSecurityProtection(){ - SecurityConfig securityConfig = SecurityConfig.newInstance(); - securityConfig.setPackageDefinition(); - securityConfig.setPackageAccess(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.io.IOException; +import java.net.InetAddress; +import java.util.HashMap; + +import org.apache.catalina.Authenticator; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Loader; +import org.apache.catalina.Realm; +import org.apache.catalina.Valve; +import org.apache.catalina.connector.Connector; +import org.apache.catalina.core.StandardContext; +import org.apache.catalina.core.StandardEngine; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.core.StandardService; +import org.apache.catalina.loader.WebappLoader; +import org.apache.catalina.security.SecurityConfig; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.log.SystemLogHandler; + + +/** + * Convenience class to embed a Catalina servlet container environment + * inside another application. You must call the methods of this class in the + * following order to ensure correct operation. + * + *
          + *
        • Instantiate a new instance of this class.
        • + *
        • Set the relevant properties of this object itself. In particular, + * you will want to establish the default Logger to be used, as well + * as the default Realm if you are using container-managed security.
        • + *
        • Call createEngine() to create an Engine object, and then + * call its property setters as desired.
        • + *
        • Call createHost() to create at least one virtual Host + * associated with the newly created Engine, and then call its property + * setters as desired. After you customize this Host, add it to the + * corresponding Engine with engine.addChild(host).
        • + *
        • Call createContext() to create at least one Context + * associated with each newly created Host, and then call its property + * setters as desired. You SHOULD create a Context with + * a pathname equal to a zero-length string, which will be used to process + * all requests not mapped to some other Context. After you customize + * this Context, add it to the corresponding Host with + * host.addChild(context).
        • + *
        • Call addEngine() to attach this Engine to the set of + * defined Engines for this object.
        • + *
        • Call createConnector() to create at least one TCP/IP + * connector, and then call its property setters as desired.
        • + *
        • Call addConnector() to attach this Connector to the set + * of defined Connectors for this object. The added Connector will use + * the most recently added Engine to process its received requests.
        • + *
        • Repeat the above series of steps as often as required (although there + * will typically be only one Engine instance created).
        • + *
        • Call start() to initiate normal operations of all the + * attached components.
        • + *
        + * + * After normal operations have begun, you can add and remove Connectors, + * Engines, Hosts, and Contexts on the fly. However, once you have removed + * a particular component, it must be thrown away -- you can create a new one + * with the same characteristics if you merely want to do a restart. + *

        + * To initiate a normal shutdown, call the stop() method of + * this object. + *

        + * @see org.apache.catalina.startup.Catalina#main For a complete example + * of how Tomcat is set up and launched as an Embedded application. + * + * @author Craig R. McClanahan + * @version $Revision: 304107 $ $Date: 2005-09-29 07:52:48 +0200 (jeu., 29 sept. 2005) $ + */ + +public class Embedded extends StandardService implements Lifecycle { + private static Log log = LogFactory.getLog(Embedded.class); + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class with default properties. + */ + public Embedded() { + + this(null); + + } + + + /** + * Construct a new instance of this class with specified properties. + * + * @param realm Realm implementation to be inherited by all components + * (unless overridden further down the container hierarchy) + */ + public Embedded(Realm realm) { + + super(); + setRealm(realm); + setSecurityProtection(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Is naming enabled ? + */ + protected boolean useNaming = true; + + + /** + * Is standard streams redirection enabled ? + */ + protected boolean redirectStreams = true; + + + /** + * The set of Engines that have been deployed in this server. Normally + * there will only be one. + */ + protected Engine engines[] = new Engine[0]; + + + /** + * Custom mappings of login methods to authenticators + */ + protected HashMap authenticators; + + + /** + * Descriptive information about this server implementation. + */ + protected static final String info = + "org.apache.catalina.startup.Embedded/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The default realm to be used by all containers associated with + * this compoennt. + */ + protected Realm realm = null; + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + protected boolean started = false; + + /** + * Use await. + */ + protected boolean await = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Return true if naming is enabled. + */ + public boolean isUseNaming() { + + return (this.useNaming); + + } + + + /** + * Enables or disables naming support. + * + * @param useNaming The new use naming value + */ + public void setUseNaming(boolean useNaming) { + + boolean oldUseNaming = this.useNaming; + this.useNaming = useNaming; + support.firePropertyChange("useNaming", new Boolean(oldUseNaming), + new Boolean(this.useNaming)); + + } + + + /** + * Return true if redirction of standard streams is enabled. + */ + public boolean isRedirectStreams() { + + return (this.redirectStreams); + + } + + + /** + * Enables or disables naming support. + * + * @param useNaming The new use naming value + */ + public void setRedirectStreams(boolean redirectStreams) { + + boolean oldRedirectStreams = this.redirectStreams; + this.redirectStreams = redirectStreams; + support.firePropertyChange("redirectStreams", new Boolean(oldRedirectStreams), + new Boolean(this.redirectStreams)); + + } + + + /** + * Return the default Realm for our Containers. + */ + public Realm getRealm() { + + return (this.realm); + + } + + + /** + * Set the default Realm for our Containers. + * + * @param realm The new default realm + */ + public void setRealm(Realm realm) { + + Realm oldRealm = this.realm; + this.realm = realm; + support.firePropertyChange("realm", oldRealm, this.realm); + + } + + public void setAwait(boolean b) { + await = b; + } + + public boolean isAwait() { + return await; + } + + public void setCatalinaHome( String s ) { + System.setProperty( "catalina.home", s); + } + + public void setCatalinaBase( String s ) { + System.setProperty( "catalina.base", s); + } + + public String getCatalinaHome() { + return System.getProperty("catalina.home"); + } + + public String getCatalinaBase() { + return System.getProperty("catalina.base"); + } + + + // --------------------------------------------------------- Public Methods + + /** + * Add a new Connector to the set of defined Connectors. The newly + * added Connector will be associated with the most recently added Engine. + * + * @param connector The connector to be added + * + * @exception IllegalStateException if no engines have been added yet + */ + public synchronized void addConnector(Connector connector) { + + if( log.isDebugEnabled() ) { + log.debug("Adding connector (" + connector.getInfo() + ")"); + } + + // Make sure we have a Container to send requests to + if (engines.length < 1) + throw new IllegalStateException + (sm.getString("embedded.noEngines")); + + /* + * Add the connector. This will set the connector's container to the + * most recently added Engine + */ + super.addConnector(connector); + } + + + /** + * Add a new Engine to the set of defined Engines. + * + * @param engine The engine to be added + */ + public synchronized void addEngine(Engine engine) { + + if( log.isDebugEnabled() ) + log.debug("Adding engine (" + engine.getInfo() + ")"); + + // Add this Engine to our set of defined Engines + Engine results[] = new Engine[engines.length + 1]; + for (int i = 0; i < engines.length; i++) + results[i] = engines[i]; + results[engines.length] = engine; + engines = results; + + // Start this Engine if necessary + if (started && (engine instanceof Lifecycle)) { + try { + ((Lifecycle) engine).start(); + } catch (LifecycleException e) { + log.error("Engine.start", e); + } + } + + this.container = engine; + } + + + /** + * Create, configure, and return a new TCP/IP socket connector + * based on the specified properties. + * + * @param address InetAddress to bind to, or null if the + * connector is supposed to bind to all addresses on this server + * @param port Port number to listen to + * @param secure true if the generated connector is supposed to be + * SSL-enabled, and false otherwise + */ + public Connector createConnector(InetAddress address, int port, + boolean secure) { + return createConnector(address != null? address.toString() : null, + port, secure); + } + + public Connector createConnector(String address, int port, + boolean secure) { + String protocol = "http"; + if (secure) { + protocol = "https"; + } + + return createConnector(address, port, protocol); + } + + + public Connector createConnector(InetAddress address, int port, + String protocol) { + return createConnector(address != null? address.toString() : null, + port, protocol); + } + + public Connector createConnector(String address, int port, + String protocol) { + + Connector connector = null; + + if (address != null) { + /* + * InetAddress.toString() returns a string of the form + * "/". Get the latter part, so that the + * address can be parsed (back) into an InetAddress using + * InetAddress.getByName(). + */ + int index = address.indexOf('/'); + if (index != -1) { + address = address.substring(index + 1); + } + } + + if (log.isDebugEnabled()) { + log.debug("Creating connector for address='" + + ((address == null) ? "ALL" : address) + + "' port='" + port + "' protocol='" + protocol + "'"); + } + + try { + + if (protocol.equals("ajp")) { + connector = new Connector("org.apache.jk.server.JkCoyoteHandler"); + } else if (protocol.equals("memory")) { + connector = new Connector("org.apache.coyote.memory.MemoryProtocolHandler"); + } else if (protocol.equals("http")) { + connector = new Connector(); + } else if (protocol.equals("https")) { + connector = new Connector(); + connector.setScheme("https"); + connector.setSecure(true); + // FIXME !!!! SET SSL PROPERTIES + } + + if (address != null) { + IntrospectionUtils.setProperty(connector, "address", + "" + address); + } + IntrospectionUtils.setProperty(connector, "port", "" + port); + + } catch (Exception e) { + log.error("Couldn't create connector."); + } + + return (connector); + + } + + /** + * Create, configure, and return a Context that will process all + * HTTP requests received from one of the associated Connectors, + * and directed to the specified context path on the virtual host + * to which this Context is connected. + *

        + * After you have customized the properties, listeners, and Valves + * for this Context, you must attach it to the corresponding Host + * by calling: + *

        +     *   host.addChild(context);
        +     * 
        + * which will also cause the Context to be started if the Host has + * already been started. + * + * @param path Context path of this application ("" for the default + * application for this host, must start with a slash otherwise) + * @param docBase Absolute pathname to the document base directory + * for this web application + * + * @exception IllegalArgumentException if an invalid parameter + * is specified + */ + public Context createContext(String path, String docBase) { + + if( log.isDebugEnabled() ) + log.debug("Creating context '" + path + "' with docBase '" + + docBase + "'"); + + StandardContext context = new StandardContext(); + + context.setDocBase(docBase); + context.setPath(path); + + ContextConfig config = new ContextConfig(); + config.setCustomAuthenticators(authenticators); + ((Lifecycle) context).addLifecycleListener(config); + + return (context); + + } + + + /** + * Create, configure, and return an Engine that will process all + * HTTP requests received from one of the associated Connectors, + * based on the specified properties. + */ + public Engine createEngine() { + + if( log.isDebugEnabled() ) + log.debug("Creating engine"); + + StandardEngine engine = new StandardEngine(); + + // Default host will be set to the first host added + engine.setRealm(realm); // Inherited by all children + + return (engine); + + } + + + /** + * Create, configure, and return a Host that will process all + * HTTP requests received from one of the associated Connectors, + * and directed to the specified virtual host. + *

        + * After you have customized the properties, listeners, and Valves + * for this Host, you must attach it to the corresponding Engine + * by calling: + *

        +     *   engine.addChild(host);
        +     * 
        + * which will also cause the Host to be started if the Engine has + * already been started. If this is the default (or only) Host you + * will be defining, you may also tell the Engine to pass all requests + * not assigned to another virtual host to this one: + *
        +     *   engine.setDefaultHost(host.getName());
        +     * 
        + * + * @param name Canonical name of this virtual host + * @param appBase Absolute pathname to the application base directory + * for this virtual host + * + * @exception IllegalArgumentException if an invalid parameter + * is specified + */ + public Host createHost(String name, String appBase) { + + if( log.isDebugEnabled() ) + log.debug("Creating host '" + name + "' with appBase '" + + appBase + "'"); + + StandardHost host = new StandardHost(); + + host.setAppBase(appBase); + host.setName(name); + + return (host); + + } + + + /** + * Create and return a class loader manager that can be customized, and + * then attached to a Context, before it is started. + * + * @param parent ClassLoader that will be the parent of the one + * created by this Loader + */ + public Loader createLoader(ClassLoader parent) { + + if( log.isDebugEnabled() ) + log.debug("Creating Loader with parent class loader '" + + parent + "'"); + + WebappLoader loader = new WebappLoader(parent); + return (loader); + + } + + + /** + * Return descriptive information about this Server implementation and + * the corresponding version number, in the format + * <description>/<version>. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Remove the specified Context from the set of defined Contexts for its + * associated Host. If this is the last Context for this Host, the Host + * will also be removed. + * + * @param context The Context to be removed + */ + public synchronized void removeContext(Context context) { + + if( log.isDebugEnabled() ) + log.debug("Removing context[" + context.getPath() + "]"); + + // Is this Context actually among those that are defined? + boolean found = false; + for (int i = 0; i < engines.length; i++) { + Container hosts[] = engines[i].findChildren(); + for (int j = 0; j < hosts.length; j++) { + Container contexts[] = hosts[j].findChildren(); + for (int k = 0; k < contexts.length; k++) { + if (context == (Context) contexts[k]) { + found = true; + break; + } + } + if (found) + break; + } + if (found) + break; + } + if (!found) + return; + + // Remove this Context from the associated Host + if( log.isDebugEnabled() ) + log.debug(" Removing this Context"); + context.getParent().removeChild(context); + + } + + + /** + * Remove the specified Engine from the set of defined Engines, along with + * all of its related Hosts and Contexts. All associated Connectors are + * also removed. + * + * @param engine The Engine to be removed + */ + public synchronized void removeEngine(Engine engine) { + + if( log.isDebugEnabled() ) + log.debug("Removing engine (" + engine.getInfo() + ")"); + + // Is the specified Engine actually defined? + int j = -1; + for (int i = 0; i < engines.length; i++) { + if (engine == engines[i]) { + j = i; + break; + } + } + if (j < 0) + return; + + // Remove any Connector that is using this Engine + if( log.isDebugEnabled() ) + log.debug(" Removing related Containers"); + while (true) { + int n = -1; + for (int i = 0; i < connectors.length; i++) { + if (connectors[i].getContainer() == (Container) engine) { + n = i; + break; + } + } + if (n < 0) + break; + removeConnector(connectors[n]); + } + + // Stop this Engine if necessary + if (engine instanceof Lifecycle) { + if( log.isDebugEnabled() ) + log.debug(" Stopping this Engine"); + try { + ((Lifecycle) engine).stop(); + } catch (LifecycleException e) { + log.error("Engine.stop", e); + } + } + + // Remove this Engine from our set of defined Engines + if( log.isDebugEnabled() ) + log.debug(" Removing this Engine"); + int k = 0; + Engine results[] = new Engine[engines.length - 1]; + for (int i = 0; i < engines.length; i++) { + if (i != j) + results[k++] = engines[i]; + } + engines = results; + + } + + + /** + * Remove the specified Host, along with all of its related Contexts, + * from the set of defined Hosts for its associated Engine. If this is + * the last Host for this Engine, the Engine will also be removed. + * + * @param host The Host to be removed + */ + public synchronized void removeHost(Host host) { + + if( log.isDebugEnabled() ) + log.debug("Removing host[" + host.getName() + "]"); + + // Is this Host actually among those that are defined? + boolean found = false; + for (int i = 0; i < engines.length; i++) { + Container hosts[] = engines[i].findChildren(); + for (int j = 0; j < hosts.length; j++) { + if (host == (Host) hosts[j]) { + found = true; + break; + + } + } + if (found) + break; + } + if (!found) + return; + + // Remove this Host from the associated Engine + if( log.isDebugEnabled() ) + log.debug(" Removing this Host"); + host.getParent().removeChild(host); + + } + + + /* + * Maps the specified login method to the specified authenticator, allowing + * the mappings in org/apache/catalina/startup/Authenticators.properties + * to be overridden. + * + * @param authenticator Authenticator to handle authentication for the + * specified login method + * @param loginMethod Login method that maps to the specified authenticator + * + * @throws IllegalArgumentException if the specified authenticator does not + * implement the org.apache.catalina.Valve interface + */ + public void addAuthenticator(Authenticator authenticator, + String loginMethod) { + if (!(authenticator instanceof Valve)) { + throw new IllegalArgumentException( + sm.getString("embedded.authenticatorNotInstanceOfValve")); + } + if (authenticators == null) { + synchronized (this) { + if (authenticators == null) { + authenticators = new HashMap(); + } + } + } + authenticators.put(loginMethod, authenticator); + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + if( log.isInfoEnabled() ) + log.info("Starting tomcat server"); + + // Validate the setup of our required system properties + initDirs(); + + // Initialize some naming specific properties + initNaming(); + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("embedded.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + initialized = true; + + // Start our defined Engines first + for (int i = 0; i < engines.length; i++) { + if (engines[i] instanceof Lifecycle) + ((Lifecycle) engines[i]).start(); + } + + // Start our defined Connectors second + for (int i = 0; i < connectors.length; i++) { + connectors[i].initialize(); + if (connectors[i] instanceof Lifecycle) + ((Lifecycle) connectors[i]).start(); + } + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + if( log.isDebugEnabled() ) + log.debug("Stopping embedded server"); + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("embedded.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + // Stop our defined Connectors first + for (int i = 0; i < connectors.length; i++) { + if (connectors[i] instanceof Lifecycle) + ((Lifecycle) connectors[i]).stop(); + } + + // Stop our defined Engines second + for (int i = 0; i < engines.length; i++) { + if (engines[i] instanceof Lifecycle) + ((Lifecycle) engines[i]).stop(); + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** Initialize naming - this should only enable java:env and root naming. + * If tomcat is embeded in an application that already defines those - + * it shouldn't do it. + * + * XXX The 2 should be separated, you may want to enable java: but not + * the initial context and the reverse + * XXX Can we "guess" - i.e. lookup java: and if something is returned assume + * false ? + * XXX We have a major problem with the current setting for java: url + */ + protected void initNaming() { + // Setting additional variables + if (!useNaming) { + log.info( "Catalina naming disabled"); + System.setProperty("catalina.useNaming", "false"); + } else { + System.setProperty("catalina.useNaming", "true"); + String value = "org.apache.naming"; + String oldValue = + System.getProperty(javax.naming.Context.URL_PKG_PREFIXES); + if (oldValue != null) { + value = value + ":" + oldValue; + } + System.setProperty(javax.naming.Context.URL_PKG_PREFIXES, value); + if( log.isDebugEnabled() ) + log.debug("Setting naming prefix=" + value); + value = System.getProperty + (javax.naming.Context.INITIAL_CONTEXT_FACTORY); + if (value == null) { + System.setProperty + (javax.naming.Context.INITIAL_CONTEXT_FACTORY, + "org.apache.naming.java.javaURLContextFactory"); + } else { + log.debug( "INITIAL_CONTEXT_FACTORY alread set " + value ); + } + } + } + + + protected void initDirs() { + + String catalinaHome = System.getProperty("catalina.home"); + if (catalinaHome == null) { + // Backwards compatibility patch for J2EE RI 1.3 + String j2eeHome = System.getProperty("com.sun.enterprise.home"); + if (j2eeHome != null) { + catalinaHome=System.getProperty("com.sun.enterprise.home"); + } else if (System.getProperty("catalina.base") != null) { + catalinaHome = System.getProperty("catalina.base"); + } else { + // Use IntrospectionUtils and guess the dir + catalinaHome = IntrospectionUtils.guessInstall + ("catalina.home", "catalina.base", "catalina.jar"); + if (catalinaHome == null) { + catalinaHome = IntrospectionUtils.guessInstall + ("tomcat.install", "catalina.home", "tomcat.jar"); + } + } + } + // last resort - for minimal/embedded cases. + if(catalinaHome==null) { + catalinaHome=System.getProperty("user.dir"); + } + if (catalinaHome != null) { + File home = new File(catalinaHome); + if (!home.isAbsolute()) { + try { + catalinaHome = home.getCanonicalPath(); + } catch (IOException e) { + catalinaHome = home.getAbsolutePath(); + } + } + System.setProperty("catalina.home", catalinaHome); + } + + if (System.getProperty("catalina.base") == null) { + System.setProperty("catalina.base", + catalinaHome); + } else { + String catalinaBase = System.getProperty("catalina.base"); + File base = new File(catalinaBase); + if (!base.isAbsolute()) { + try { + catalinaBase = base.getCanonicalPath(); + } catch (IOException e) { + catalinaBase = base.getAbsolutePath(); + } + } + System.setProperty("catalina.base", catalinaBase); + } + + String temp = System.getProperty("java.io.tmpdir"); + if (temp == null || (!(new File(temp)).exists()) + || (!(new File(temp)).isDirectory())) { + log.error(sm.getString("embedded.notmp", temp)); + } + + } + + + protected void initStreams() { + if (redirectStreams) { + // Replace System.out and System.err with a custom PrintStream + SystemLogHandler systemlog = new SystemLogHandler(System.out); + System.setOut(systemlog); + System.setErr(systemlog); + } + } + + + // -------------------------------------------------------- Private Methods + + /** + * Set the security package access/protection. + */ + protected void setSecurityProtection(){ + SecurityConfig securityConfig = SecurityConfig.newInstance(); + securityConfig.setPackageDefinition(); + securityConfig.setPackageAccess(); + } + +} diff --git a/java/org/apache/catalina/startup/EngineConfig.java b/java/org/apache/catalina/startup/EngineConfig.java index a03a4cb3c..19e3375ba 100644 --- a/java/org/apache/catalina/startup/EngineConfig.java +++ b/java/org/apache/catalina/startup/EngineConfig.java @@ -1,111 +1,111 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.catalina.Engine; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.util.StringManager; - - -/** - * Startup event listener for a Engine that configures the properties - * of that Engine, and the associated defined contexts. - * - * @author Craig R. McClanahan - * @version $Revision: 349922 $ $Date: 2005-11-30 12:10:55 +0100 (mer., 30 nov. 2005) $ - */ - -public class EngineConfig - implements LifecycleListener { - - - protected static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( EngineConfig.class ); - - // ----------------------------------------------------- Instance Variables - - - /** - * The Engine we are associated with. - */ - protected Engine engine = null; - - - /** - * The string resources for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the START event for an associated Engine. - * - * @param event The lifecycle event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - // Identify the engine we are associated with - try { - engine = (Engine) event.getLifecycle(); - } catch (ClassCastException e) { - log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e); - return; - } - - // Process the event that has occurred - if (event.getType().equals(Lifecycle.START_EVENT)) - start(); - else if (event.getType().equals(Lifecycle.STOP_EVENT)) - stop(); - - } - - - // -------------------------------------------------------- Protected Methods - - - /** - * Process a "start" event for this Engine. - */ - protected void start() { - - if (engine.getLogger().isDebugEnabled()) - engine.getLogger().debug(sm.getString("engineConfig.start")); - - } - - - /** - * Process a "stop" event for this Engine. - */ - protected void stop() { - - if (engine.getLogger().isDebugEnabled()) - engine.getLogger().debug(sm.getString("engineConfig.stop")); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.catalina.Engine; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.util.StringManager; + + +/** + * Startup event listener for a Engine that configures the properties + * of that Engine, and the associated defined contexts. + * + * @author Craig R. McClanahan + * @version $Revision: 349922 $ $Date: 2005-11-30 12:10:55 +0100 (mer., 30 nov. 2005) $ + */ + +public class EngineConfig + implements LifecycleListener { + + + protected static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( EngineConfig.class ); + + // ----------------------------------------------------- Instance Variables + + + /** + * The Engine we are associated with. + */ + protected Engine engine = null; + + + /** + * The string resources for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the START event for an associated Engine. + * + * @param event The lifecycle event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + // Identify the engine we are associated with + try { + engine = (Engine) event.getLifecycle(); + } catch (ClassCastException e) { + log.error(sm.getString("engineConfig.cce", event.getLifecycle()), e); + return; + } + + // Process the event that has occurred + if (event.getType().equals(Lifecycle.START_EVENT)) + start(); + else if (event.getType().equals(Lifecycle.STOP_EVENT)) + stop(); + + } + + + // -------------------------------------------------------- Protected Methods + + + /** + * Process a "start" event for this Engine. + */ + protected void start() { + + if (engine.getLogger().isDebugEnabled()) + engine.getLogger().debug(sm.getString("engineConfig.start")); + + } + + + /** + * Process a "stop" event for this Engine. + */ + protected void stop() { + + if (engine.getLogger().isDebugEnabled()) + engine.getLogger().debug(sm.getString("engineConfig.stop")); + + } + + +} diff --git a/java/org/apache/catalina/startup/EngineRuleSet.java b/java/org/apache/catalina/startup/EngineRuleSet.java index a28903f12..bd9311855 100644 --- a/java/org/apache/catalina/startup/EngineRuleSet.java +++ b/java/org/apache/catalina/startup/EngineRuleSet.java @@ -1,149 +1,149 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.RuleSetBase; - - -/** - *

        RuleSet for processing the contents of a - * Engine definition element. This RuleSet does NOT include - * any rules for nested Host or DefaultContext elements, which should - * be added via instances of HostRuleSet or - * ContextRuleSet, respectively.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303970 $ $Date: 2005-06-30 15:08:14 +0200 (jeu., 30 juin 2005) $ - */ - -public class EngineRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public EngineRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public EngineRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - digester.addObjectCreate(prefix + "Engine", - "org.apache.catalina.core.StandardEngine", - "className"); - digester.addSetProperties(prefix + "Engine"); - digester.addRule(prefix + "Engine", - new LifecycleListenerRule - ("org.apache.catalina.startup.EngineConfig", - "engineConfigClass")); - digester.addSetNext(prefix + "Engine", - "setContainer", - "org.apache.catalina.Container"); - - //Cluster configuration start - digester.addObjectCreate(prefix + "Engine/Cluster", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Engine/Cluster"); - digester.addSetNext(prefix + "Engine/Cluster", - "setCluster", - "org.apache.catalina.Cluster"); - //Cluster configuration end - - digester.addObjectCreate(prefix + "Engine/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Engine/Listener"); - digester.addSetNext(prefix + "Engine/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - digester.addObjectCreate(prefix + "Engine/Logger", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Engine/Logger"); - digester.addSetNext(prefix + "Engine/Logger", - "setLogger", - "org.apache.catalina.Logger"); - - digester.addObjectCreate(prefix + "Engine/Realm", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Engine/Realm"); - digester.addSetNext(prefix + "Engine/Realm", - "setRealm", - "org.apache.catalina.Realm"); - - digester.addObjectCreate(prefix + "Engine/Valve", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Engine/Valve"); - digester.addSetNext(prefix + "Engine/Valve", - "addValve", - "org.apache.catalina.Valve"); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSetBase; + + +/** + *

        RuleSet for processing the contents of a + * Engine definition element. This RuleSet does NOT include + * any rules for nested Host or DefaultContext elements, which should + * be added via instances of HostRuleSet or + * ContextRuleSet, respectively.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303970 $ $Date: 2005-06-30 15:08:14 +0200 (jeu., 30 juin 2005) $ + */ + +public class EngineRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public EngineRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public EngineRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + digester.addObjectCreate(prefix + "Engine", + "org.apache.catalina.core.StandardEngine", + "className"); + digester.addSetProperties(prefix + "Engine"); + digester.addRule(prefix + "Engine", + new LifecycleListenerRule + ("org.apache.catalina.startup.EngineConfig", + "engineConfigClass")); + digester.addSetNext(prefix + "Engine", + "setContainer", + "org.apache.catalina.Container"); + + //Cluster configuration start + digester.addObjectCreate(prefix + "Engine/Cluster", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Engine/Cluster"); + digester.addSetNext(prefix + "Engine/Cluster", + "setCluster", + "org.apache.catalina.Cluster"); + //Cluster configuration end + + digester.addObjectCreate(prefix + "Engine/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Engine/Listener"); + digester.addSetNext(prefix + "Engine/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + digester.addObjectCreate(prefix + "Engine/Logger", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Engine/Logger"); + digester.addSetNext(prefix + "Engine/Logger", + "setLogger", + "org.apache.catalina.Logger"); + + digester.addObjectCreate(prefix + "Engine/Realm", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Engine/Realm"); + digester.addSetNext(prefix + "Engine/Realm", + "setRealm", + "org.apache.catalina.Realm"); + + digester.addObjectCreate(prefix + "Engine/Valve", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Engine/Valve"); + digester.addSetNext(prefix + "Engine/Valve", + "addValve", + "org.apache.catalina.Valve"); + + } + + +} diff --git a/java/org/apache/catalina/startup/ExpandWar.java b/java/org/apache/catalina/startup/ExpandWar.java index eba572e5c..fbf12a430 100644 --- a/java/org/apache/catalina/startup/ExpandWar.java +++ b/java/org/apache/catalina/startup/ExpandWar.java @@ -1,334 +1,334 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.InputStream; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.URL; -import java.nio.channels.FileChannel; -import java.util.Enumeration; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import org.apache.catalina.Host; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Expand out a WAR in a Host's appBase. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @author Glenn L. Nielsen - * @version $Revision: 303769 $ - */ - -public class ExpandWar { - - private static Log log = LogFactory.getLog(ExpandWar.class); - - /** - * The string resources for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Expand the WAR file found at the specified URL into an unpacked - * directory structure, and return the absolute pathname to the expanded - * directory. - * - * @param host Host war is being installed for - * @param war URL of the web application archive to be expanded - * (must start with "jar:") - * - * @exception IllegalArgumentException if this is not a "jar:" URL - * @exception IOException if an input/output error was encountered - * during expansion - */ - public static String expand(Host host, URL war) - throws IOException { - - // Calculate the directory name of the expanded directory - if (host.getLogger().isDebugEnabled()) { - host.getLogger().debug("expand(" + war.toString() + ")"); - } - String pathname = war.toString().replace('\\', '/'); - if (pathname.endsWith("!/")) { - pathname = pathname.substring(0, pathname.length() - 2); - } - int period = pathname.lastIndexOf('.'); - if (period >= pathname.length() - 4) - pathname = pathname.substring(0, period); - int slash = pathname.lastIndexOf('/'); - if (slash >= 0) { - pathname = pathname.substring(slash + 1); - } - if (host.getLogger().isDebugEnabled()) { - host.getLogger().debug(" Proposed directory name: " + pathname); - } - return expand(host, war, pathname); - - } - - - /** - * Expand the WAR file found at the specified URL into an unpacked - * directory structure, and return the absolute pathname to the expanded - * directory. - * - * @param host Host war is being installed for - * @param war URL of the web application archive to be expanded - * (must start with "jar:") - * @param pathname Context path name for web application - * - * @exception IllegalArgumentException if this is not a "jar:" URL - * @exception IOException if an input/output error was encountered - * during expansion - */ - public static String expand(Host host, URL war, String pathname) - throws IOException { - - // Make sure that there is no such directory already existing - File appBase = new File(host.getAppBase()); - if (!appBase.isAbsolute()) { - appBase = new File(System.getProperty("catalina.base"), - host.getAppBase()); - } - if (!appBase.exists() || !appBase.isDirectory()) { - throw new IOException - (sm.getString("hostConfig.appBase", - appBase.getAbsolutePath())); - } - File docBase = new File(appBase, pathname); - if (docBase.exists()) { - // War file is already installed - return (docBase.getAbsolutePath()); - } - - // Create the new document base directory - docBase.mkdir(); - - // Expand the WAR into the new document base directory - JarURLConnection juc = (JarURLConnection) war.openConnection(); - juc.setUseCaches(false); - JarFile jarFile = null; - InputStream input = null; - try { - jarFile = juc.getJarFile(); - Enumeration jarEntries = jarFile.entries(); - while (jarEntries.hasMoreElements()) { - JarEntry jarEntry = (JarEntry) jarEntries.nextElement(); - String name = jarEntry.getName(); - int last = name.lastIndexOf('/'); - if (last >= 0) { - File parent = new File(docBase, - name.substring(0, last)); - parent.mkdirs(); - } - if (name.endsWith("/")) { - continue; - } - input = jarFile.getInputStream(jarEntry); - - // Bugzilla 33636 - File expandedFile = expand(input, docBase, name); - long lastModified = jarEntry.getTime(); - if ((lastModified != -1) && (lastModified != 0) && (expandedFile != null)) { - expandedFile.setLastModified(lastModified); - } - - input.close(); - input = null; - } - } catch (IOException e) { - // If something went wrong, delete expanded dir to keep things - // clean - deleteDir(docBase); - throw e; - } finally { - if (input != null) { - try { - input.close(); - } catch (Throwable t) { - ; - } - input = null; - } - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - ; - } - jarFile = null; - } - } - - // Return the absolute path to our new document base directory - return (docBase.getAbsolutePath()); - - } - - - /** - * Copy the specified file or directory to the destination. - * - * @param src File object representing the source - * @param dest File object representing the destination - */ - public static boolean copy(File src, File dest) { - - boolean result = true; - - String files[] = null; - if (src.isDirectory()) { - files = src.list(); - result = dest.mkdir(); - } else { - files = new String[1]; - files[0] = ""; - } - if (files == null) { - files = new String[0]; - } - for (int i = 0; (i < files.length) && result; i++) { - File fileSrc = new File(src, files[i]); - File fileDest = new File(dest, files[i]); - if (fileSrc.isDirectory()) { - result = copy(fileSrc, fileDest); - } else { - FileChannel ic = null; - FileChannel oc = null; - try { - ic = (new FileInputStream(fileSrc)).getChannel(); - oc = (new FileOutputStream(fileDest)).getChannel(); - ic.transferTo(0, ic.size(), oc); - } catch (IOException e) { - log.error(sm.getString - ("expandWar.copy", fileSrc, fileDest), e); - result = false; - } finally { - if (ic != null) { - try { - ic.close(); - } catch (IOException e) { - } - } - if (oc != null) { - try { - oc.close(); - } catch (IOException e) { - } - } - } - } - } - return result; - - } - - - /** - * Delete the specified directory, including all of its contents and - * subdirectories recursively. - * - * @param dir File object representing the directory to be deleted - */ - public static boolean delete(File dir) { - if (dir.isDirectory()) { - return deleteDir(dir); - } else { - return dir.delete(); - } - } - - - /** - * Delete the specified directory, including all of its contents and - * subdirectories recursively. - * - * @param dir File object representing the directory to be deleted - */ - public static boolean deleteDir(File dir) { - - String files[] = dir.list(); - if (files == null) { - files = new String[0]; - } - for (int i = 0; i < files.length; i++) { - File file = new File(dir, files[i]); - if (file.isDirectory()) { - deleteDir(file); - } else { - file.delete(); - } - } - return dir.delete(); - - } - - - /** - * Expand the specified input stream into the specified directory, creating - * a file named from the specified relative path. - * - * @param input InputStream to be copied - * @param docBase Document base directory into which we are expanding - * @param name Relative pathname of the file to be created - * @return A handle to the expanded File - * - * @exception IOException if an input/output error occurs - */ - protected static File expand(InputStream input, File docBase, String name) - throws IOException { - - File file = new File(docBase, name); - BufferedOutputStream output = null; - try { - output = - new BufferedOutputStream(new FileOutputStream(file)); - byte buffer[] = new byte[2048]; - while (true) { - int n = input.read(buffer); - if (n <= 0) - break; - output.write(buffer, 0, n); - } - } finally { - if (output != null) { - try { - output.close(); - } catch (IOException e) { - // Ignore - } - } - } - - return file; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URL; +import java.nio.channels.FileChannel; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.apache.catalina.Host; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Expand out a WAR in a Host's appBase. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @author Glenn L. Nielsen + * @version $Revision: 303769 $ + */ + +public class ExpandWar { + + private static Log log = LogFactory.getLog(ExpandWar.class); + + /** + * The string resources for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Expand the WAR file found at the specified URL into an unpacked + * directory structure, and return the absolute pathname to the expanded + * directory. + * + * @param host Host war is being installed for + * @param war URL of the web application archive to be expanded + * (must start with "jar:") + * + * @exception IllegalArgumentException if this is not a "jar:" URL + * @exception IOException if an input/output error was encountered + * during expansion + */ + public static String expand(Host host, URL war) + throws IOException { + + // Calculate the directory name of the expanded directory + if (host.getLogger().isDebugEnabled()) { + host.getLogger().debug("expand(" + war.toString() + ")"); + } + String pathname = war.toString().replace('\\', '/'); + if (pathname.endsWith("!/")) { + pathname = pathname.substring(0, pathname.length() - 2); + } + int period = pathname.lastIndexOf('.'); + if (period >= pathname.length() - 4) + pathname = pathname.substring(0, period); + int slash = pathname.lastIndexOf('/'); + if (slash >= 0) { + pathname = pathname.substring(slash + 1); + } + if (host.getLogger().isDebugEnabled()) { + host.getLogger().debug(" Proposed directory name: " + pathname); + } + return expand(host, war, pathname); + + } + + + /** + * Expand the WAR file found at the specified URL into an unpacked + * directory structure, and return the absolute pathname to the expanded + * directory. + * + * @param host Host war is being installed for + * @param war URL of the web application archive to be expanded + * (must start with "jar:") + * @param pathname Context path name for web application + * + * @exception IllegalArgumentException if this is not a "jar:" URL + * @exception IOException if an input/output error was encountered + * during expansion + */ + public static String expand(Host host, URL war, String pathname) + throws IOException { + + // Make sure that there is no such directory already existing + File appBase = new File(host.getAppBase()); + if (!appBase.isAbsolute()) { + appBase = new File(System.getProperty("catalina.base"), + host.getAppBase()); + } + if (!appBase.exists() || !appBase.isDirectory()) { + throw new IOException + (sm.getString("hostConfig.appBase", + appBase.getAbsolutePath())); + } + File docBase = new File(appBase, pathname); + if (docBase.exists()) { + // War file is already installed + return (docBase.getAbsolutePath()); + } + + // Create the new document base directory + docBase.mkdir(); + + // Expand the WAR into the new document base directory + JarURLConnection juc = (JarURLConnection) war.openConnection(); + juc.setUseCaches(false); + JarFile jarFile = null; + InputStream input = null; + try { + jarFile = juc.getJarFile(); + Enumeration jarEntries = jarFile.entries(); + while (jarEntries.hasMoreElements()) { + JarEntry jarEntry = (JarEntry) jarEntries.nextElement(); + String name = jarEntry.getName(); + int last = name.lastIndexOf('/'); + if (last >= 0) { + File parent = new File(docBase, + name.substring(0, last)); + parent.mkdirs(); + } + if (name.endsWith("/")) { + continue; + } + input = jarFile.getInputStream(jarEntry); + + // Bugzilla 33636 + File expandedFile = expand(input, docBase, name); + long lastModified = jarEntry.getTime(); + if ((lastModified != -1) && (lastModified != 0) && (expandedFile != null)) { + expandedFile.setLastModified(lastModified); + } + + input.close(); + input = null; + } + } catch (IOException e) { + // If something went wrong, delete expanded dir to keep things + // clean + deleteDir(docBase); + throw e; + } finally { + if (input != null) { + try { + input.close(); + } catch (Throwable t) { + ; + } + input = null; + } + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + ; + } + jarFile = null; + } + } + + // Return the absolute path to our new document base directory + return (docBase.getAbsolutePath()); + + } + + + /** + * Copy the specified file or directory to the destination. + * + * @param src File object representing the source + * @param dest File object representing the destination + */ + public static boolean copy(File src, File dest) { + + boolean result = true; + + String files[] = null; + if (src.isDirectory()) { + files = src.list(); + result = dest.mkdir(); + } else { + files = new String[1]; + files[0] = ""; + } + if (files == null) { + files = new String[0]; + } + for (int i = 0; (i < files.length) && result; i++) { + File fileSrc = new File(src, files[i]); + File fileDest = new File(dest, files[i]); + if (fileSrc.isDirectory()) { + result = copy(fileSrc, fileDest); + } else { + FileChannel ic = null; + FileChannel oc = null; + try { + ic = (new FileInputStream(fileSrc)).getChannel(); + oc = (new FileOutputStream(fileDest)).getChannel(); + ic.transferTo(0, ic.size(), oc); + } catch (IOException e) { + log.error(sm.getString + ("expandWar.copy", fileSrc, fileDest), e); + result = false; + } finally { + if (ic != null) { + try { + ic.close(); + } catch (IOException e) { + } + } + if (oc != null) { + try { + oc.close(); + } catch (IOException e) { + } + } + } + } + } + return result; + + } + + + /** + * Delete the specified directory, including all of its contents and + * subdirectories recursively. + * + * @param dir File object representing the directory to be deleted + */ + public static boolean delete(File dir) { + if (dir.isDirectory()) { + return deleteDir(dir); + } else { + return dir.delete(); + } + } + + + /** + * Delete the specified directory, including all of its contents and + * subdirectories recursively. + * + * @param dir File object representing the directory to be deleted + */ + public static boolean deleteDir(File dir) { + + String files[] = dir.list(); + if (files == null) { + files = new String[0]; + } + for (int i = 0; i < files.length; i++) { + File file = new File(dir, files[i]); + if (file.isDirectory()) { + deleteDir(file); + } else { + file.delete(); + } + } + return dir.delete(); + + } + + + /** + * Expand the specified input stream into the specified directory, creating + * a file named from the specified relative path. + * + * @param input InputStream to be copied + * @param docBase Document base directory into which we are expanding + * @param name Relative pathname of the file to be created + * @return A handle to the expanded File + * + * @exception IOException if an input/output error occurs + */ + protected static File expand(InputStream input, File docBase, String name) + throws IOException { + + File file = new File(docBase, name); + BufferedOutputStream output = null; + try { + output = + new BufferedOutputStream(new FileOutputStream(file)); + byte buffer[] = new byte[2048]; + while (true) { + int n = input.read(buffer); + if (n <= 0) + break; + output.write(buffer, 0, n); + } + } finally { + if (output != null) { + try { + output.close(); + } catch (IOException e) { + // Ignore + } + } + } + + return file; + } + + +} diff --git a/java/org/apache/catalina/startup/HomesUserDatabase.java b/java/org/apache/catalina/startup/HomesUserDatabase.java index 2591a1445..ad7439449 100644 --- a/java/org/apache/catalina/startup/HomesUserDatabase.java +++ b/java/org/apache/catalina/startup/HomesUserDatabase.java @@ -1,143 +1,143 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.util.Hashtable; -import java.util.Enumeration; - - -/** - * Concrete implementation of the UserDatabase interface - * considers all directories in a directory whose pathname is specified - * to our constructor to be "home" directories for those users. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class HomesUserDatabase - implements UserDatabase { - - - // --------------------------------------------------------- Constructors - - - /** - * Initialize a new instance of this user database component. - */ - public HomesUserDatabase() { - - super(); - - } - - - // --------------------------------------------------- Instance Variables - - - /** - * The set of home directories for all defined users, keyed by username. - */ - private Hashtable homes = new Hashtable(); - - - /** - * The UserConfig listener with which we are associated. - */ - private UserConfig userConfig = null; - - - // ----------------------------------------------------------- Properties - - - /** - * Return the UserConfig listener with which we are associated. - */ - public UserConfig getUserConfig() { - - return (this.userConfig); - - } - - - /** - * Set the UserConfig listener with which we are associated. - * - * @param userConfig The new UserConfig listener - */ - public void setUserConfig(UserConfig userConfig) { - - this.userConfig = userConfig; - init(); - - } - - - // ------------------------------------------------------- Public Methods - - - /** - * Return an absolute pathname to the home directory for the specified user. - * - * @param user User for which a home directory should be retrieved - */ - public String getHome(String user) { - - return ((String) homes.get(user)); - - } - - - /** - * Return an enumeration of the usernames defined on this server. - */ - public Enumeration getUsers() { - - return (homes.keys()); - - } - - - // ------------------------------------------------------ Private Methods - - - /** - * Initialize our set of users and home directories. - */ - private void init() { - - String homeBase = userConfig.getHomeBase(); - File homeBaseDir = new File(homeBase); - if (!homeBaseDir.exists() || !homeBaseDir.isDirectory()) - return; - String homeBaseFiles[] = homeBaseDir.list(); - - for (int i = 0; i < homeBaseFiles.length; i++) { - File homeDir = new File(homeBaseDir, homeBaseFiles[i]); - if (!homeDir.isDirectory() || !homeDir.canRead()) - continue; - homes.put(homeBaseFiles[i], homeDir.toString()); - } - - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.util.Hashtable; +import java.util.Enumeration; + + +/** + * Concrete implementation of the UserDatabase interface + * considers all directories in a directory whose pathname is specified + * to our constructor to be "home" directories for those users. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class HomesUserDatabase + implements UserDatabase { + + + // --------------------------------------------------------- Constructors + + + /** + * Initialize a new instance of this user database component. + */ + public HomesUserDatabase() { + + super(); + + } + + + // --------------------------------------------------- Instance Variables + + + /** + * The set of home directories for all defined users, keyed by username. + */ + private Hashtable homes = new Hashtable(); + + + /** + * The UserConfig listener with which we are associated. + */ + private UserConfig userConfig = null; + + + // ----------------------------------------------------------- Properties + + + /** + * Return the UserConfig listener with which we are associated. + */ + public UserConfig getUserConfig() { + + return (this.userConfig); + + } + + + /** + * Set the UserConfig listener with which we are associated. + * + * @param userConfig The new UserConfig listener + */ + public void setUserConfig(UserConfig userConfig) { + + this.userConfig = userConfig; + init(); + + } + + + // ------------------------------------------------------- Public Methods + + + /** + * Return an absolute pathname to the home directory for the specified user. + * + * @param user User for which a home directory should be retrieved + */ + public String getHome(String user) { + + return ((String) homes.get(user)); + + } + + + /** + * Return an enumeration of the usernames defined on this server. + */ + public Enumeration getUsers() { + + return (homes.keys()); + + } + + + // ------------------------------------------------------ Private Methods + + + /** + * Initialize our set of users and home directories. + */ + private void init() { + + String homeBase = userConfig.getHomeBase(); + File homeBaseDir = new File(homeBase); + if (!homeBaseDir.exists() || !homeBaseDir.isDirectory()) + return; + String homeBaseFiles[] = homeBaseDir.list(); + + for (int i = 0; i < homeBaseFiles.length; i++) { + File homeDir = new File(homeBaseDir, homeBaseFiles[i]); + if (!homeDir.isDirectory() || !homeDir.canRead()) + continue; + homes.put(homeBaseFiles[i], homeDir.toString()); + } + + + } + + +} diff --git a/java/org/apache/catalina/startup/HostConfig.java b/java/org/apache/catalina/startup/HostConfig.java index fae222475..fd23158cf 100644 --- a/java/org/apache/catalina/startup/HostConfig.java +++ b/java/org/apache/catalina/startup/HostConfig.java @@ -1,1315 +1,1315 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.BufferedOutputStream; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import javax.management.ObjectName; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.core.ContainerBase; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.util.StringManager; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Startup event listener for a Host that configures the properties - * of that Host, and the associated defined contexts. - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 386336 $ $Date: 2006-03-16 15:13:00 +0100 (jeu., 16 mars 2006) $ - */ -public class HostConfig - implements LifecycleListener { - - protected static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( HostConfig.class ); - - // ----------------------------------------------------- Instance Variables - - - /** - * App base. - */ - protected File appBase = null; - - - /** - * Config base. - */ - protected File configBase = null; - - - /** - * The Java class name of the Context configuration class we should use. - */ - protected String configClass = "org.apache.catalina.startup.ContextConfig"; - - - /** - * The Java class name of the Context implementation we should use. - */ - protected String contextClass = "org.apache.catalina.core.StandardContext"; - - - /** - * The Host we are associated with. - */ - protected Host host = null; - - - /** - * The JMX ObjectName of this component. - */ - protected ObjectName oname = null; - - - /** - * The string resources for this package. - */ - protected static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Should we deploy XML Context config files? - */ - protected boolean deployXML = false; - - - /** - * Should we unpack WAR files when auto-deploying applications in the - * appBase directory? - */ - protected boolean unpackWARs = false; - - - /** - * Map of deployed applications. - */ - protected HashMap deployed = new HashMap(); - - - /** - * List of applications which are being serviced, and shouldn't be - * deployed/undeployed/redeployed at the moment. - */ - protected ArrayList serviced = new ArrayList(); - - - /** - * Attribute value used to turn on/off XML validation - */ - protected boolean xmlValidation = false; - - - /** - * Attribute value used to turn on/off XML namespace awarenes. - */ - protected boolean xmlNamespaceAware = false; - - - /** - * The Digester instance used to parse context descriptors. - */ - protected static Digester digester = createDigester(); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Context configuration class name. - */ - public String getConfigClass() { - - return (this.configClass); - - } - - - /** - * Set the Context configuration class name. - * - * @param configClass The new Context configuration class name. - */ - public void setConfigClass(String configClass) { - - this.configClass = configClass; - - } - - - /** - * Return the Context implementation class name. - */ - public String getContextClass() { - - return (this.contextClass); - - } - - - /** - * Set the Context implementation class name. - * - * @param contextClass The new Context implementation class name. - */ - public void setContextClass(String contextClass) { - - this.contextClass = contextClass; - - } - - - /** - * Return the deploy XML config file flag for this component. - */ - public boolean isDeployXML() { - - return (this.deployXML); - - } - - - /** - * Set the deploy XML config file flag for this component. - * - * @param deployXML The new deploy XML flag - */ - public void setDeployXML(boolean deployXML) { - - this.deployXML= deployXML; - - } - - - /** - * Return the unpack WARs flag. - */ - public boolean isUnpackWARs() { - - return (this.unpackWARs); - - } - - - /** - * Set the unpack WARs flag. - * - * @param unpackWARs The new unpack WARs flag - */ - public void setUnpackWARs(boolean unpackWARs) { - - this.unpackWARs = unpackWARs; - - } - - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param xmlValidation true to enable xml instance validation - */ - public void setXmlValidation(boolean xmlValidation){ - this.xmlValidation = xmlValidation; - } - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getXmlValidation(){ - return xmlValidation; - } - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - * - */ - public boolean getXmlNamespaceAware(){ - return xmlNamespaceAware; - } - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param xmlNamespaceAware true to enable namespace awareness - */ - public void setXmlNamespaceAware(boolean xmlNamespaceAware){ - this.xmlNamespaceAware=xmlNamespaceAware; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the START event for an associated Host. - * - * @param event The lifecycle event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) - check(); - - // Identify the host we are associated with - try { - host = (Host) event.getLifecycle(); - if (host instanceof StandardHost) { - setDeployXML(((StandardHost) host).isDeployXML()); - setUnpackWARs(((StandardHost) host).isUnpackWARs()); - setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware()); - setXmlValidation(((StandardHost) host).getXmlValidation()); - } - } catch (ClassCastException e) { - log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); - return; - } - - // Process the event that has occurred - if (event.getType().equals(Lifecycle.START_EVENT)) - start(); - else if (event.getType().equals(Lifecycle.STOP_EVENT)) - stop(); - - } - - - /** - * Add a serviced application to the list. - */ - public synchronized void addServiced(String name) { - serviced.add(name); - } - - - /** - * Is application serviced ? - * @return state of the application - */ - public synchronized boolean isServiced(String name) { - return (serviced.contains(name)); - } - - - /** - * Removed a serviced application from the list. - */ - public synchronized void removeServiced(String name) { - serviced.remove(name); - } - - - /** - * Get the instant where an application was deployed. - * @return 0L if no application with that name is deployed, or the instant - * on which the application was deployed - */ - public long getDeploymentTime(String name) { - DeployedApplication app = (DeployedApplication) deployed.get(name); - if (app == null) { - return 0L; - } else { - return app.timestamp; - } - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Create the digester which will be used to parse context config files. - */ - protected static Digester createDigester() { - Digester digester = new Digester(); - digester.setValidating(false); - // Add object creation rule - digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext", - "className"); - // Set the properties on that object (it doesn't matter if extra - // properties are set) - digester.addSetProperties("Context"); - return (digester); - } - - - /** - * Return a File object representing the "application root" directory - * for our associated Host. - */ - protected File appBase() { - - if (appBase != null) { - return appBase; - } - - File file = new File(host.getAppBase()); - if (!file.isAbsolute()) - file = new File(System.getProperty("catalina.base"), - host.getAppBase()); - try { - appBase = file.getCanonicalFile(); - } catch (IOException e) { - appBase = file; - } - return (appBase); - - } - - - /** - * Return a File object representing the "configuration root" directory - * for our associated Host. - */ - protected File configBase() { - - if (configBase != null) { - return configBase; - } - - File file = new File(System.getProperty("catalina.base"), "conf"); - Container parent = host.getParent(); - if ((parent != null) && (parent instanceof Engine)) { - file = new File(file, parent.getName()); - } - file = new File(file, host.getName()); - try { - configBase = file.getCanonicalFile(); - } catch (IOException e) { - configBase = file; - } - return (configBase); - - } - - /** - * Get the name of the configBase. - * For use with JMX management. - */ - public String getConfigBaseName() { - return configBase().getAbsolutePath(); - } - - /** - * Given a context path, get the config file name. - */ - protected String getConfigFile(String path) { - String basename = null; - if (path.equals("")) { - basename = "ROOT"; - } else { - basename = path.substring(1).replace('/', '#'); - } - return (basename); - } - - - /** - * Given a context path, get the config file name. - */ - protected String getDocBase(String path) { - String basename = null; - if (path.equals("")) { - basename = "ROOT"; - } else { - basename = path.substring(1); - } - return (basename); - } - - - /** - * Deploy applications for any directories or WAR files that are found - * in our "application root" directory. - */ - protected void deployApps() { - - File appBase = appBase(); - File configBase = configBase(); - // Deploy XML descriptors from configBase - deployDescriptors(configBase, configBase.list()); - // Deploy WARs, and loop if additional descriptors are found - deployWARs(appBase, appBase.list()); - // Deploy expanded folders - deployDirectories(appBase, appBase.list()); - - } - - - /** - * Deploy applications for any directories or WAR files that are found - * in our "application root" directory. - */ - protected void deployApps(String name) { - - File appBase = appBase(); - File configBase = configBase(); - String baseName = getConfigFile(name); - String docBase = getConfigFile(name); - - // Deploy XML descriptors from configBase - File xml = new File(configBase, baseName + ".xml"); - if (xml.exists()) - deployDescriptor(name, xml, baseName + ".xml"); - // Deploy WARs, and loop if additional descriptors are found - File war = new File(appBase, docBase + ".war"); - if (war.exists()) - deployWAR(name, war, docBase + ".war"); - // Deploy expanded folders - File dir = new File(appBase, docBase); - if (dir.exists()) - deployDirectory(name, dir, docBase); - - } - - - /** - * Deploy XML context descriptors. - */ - protected void deployDescriptors(File configBase, String[] files) { - - if (files == null) - return; - - for (int i = 0; i < files.length; i++) { - - if (files[i].equalsIgnoreCase("META-INF")) - continue; - if (files[i].equalsIgnoreCase("WEB-INF")) - continue; - File contextXml = new File(configBase, files[i]); - if (files[i].toLowerCase().endsWith(".xml")) { - - // Calculate the context path and make sure it is unique - String nameTmp = files[i].substring(0, files[i].length() - 4); - String contextPath = "/" + nameTmp.replace('#', '/'); - if (nameTmp.equals("ROOT")) { - contextPath = ""; - } - - if (isServiced(contextPath)) - continue; - - String file = files[i]; - - deployDescriptor(contextPath, contextXml, file); - - } - - } - - } - - - /** - * @param contextPath - * @param contextXml - * @param file - */ - protected void deployDescriptor(String contextPath, File contextXml, String file) { - if (deploymentExists(contextPath)) { - return; - } - - DeployedApplication deployedApp = new DeployedApplication(contextPath); - - // Assume this is a configuration descriptor and deploy it - if(log.isDebugEnabled()) { - log.debug(sm.getString("hostConfig.deployDescriptor", file)); - } - - Context context = null; - try { - synchronized (digester) { - try { - context = (Context) digester.parse(contextXml); - if (context == null) { - log.error(sm.getString("hostConfig.deployDescriptor.error", - file)); - return; - } - } finally { - digester.reset(); - } - } - if (context instanceof Lifecycle) { - Class clazz = Class.forName(host.getConfigClass()); - LifecycleListener listener = - (LifecycleListener) clazz.newInstance(); - ((Lifecycle) context).addLifecycleListener(listener); - } - context.setConfigFile(contextXml.getAbsolutePath()); - context.setPath(contextPath); - // Add the associated docBase to the redeployed list if it's a WAR - boolean isWar = false; - boolean isExternal = false; - if (context.getDocBase() != null) { - File docBase = new File(context.getDocBase()); - if (!docBase.isAbsolute()) { - docBase = new File(appBase(), context.getDocBase()); - } - // If external docBase, register .xml as redeploy first - if (!docBase.getCanonicalPath().startsWith(appBase().getAbsolutePath())) { - isExternal = true; - deployedApp.redeployResources.put - (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); - deployedApp.redeployResources.put(docBase.getAbsolutePath(), - new Long(docBase.lastModified())); - if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) { - isWar = true; - } - } else { - log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", - docBase)); - // Ignore specified docBase - context.setDocBase(null); - } - } - host.addChild(context); - // Get paths for WAR and expanded WAR in appBase - String name = null; - String path = context.getPath(); - if (path.equals("")) { - name = "ROOT"; - } else { - if (path.startsWith("/")) { - name = path.substring(1); - } else { - name = path; - } - } - File expandedDocBase = new File(name); - File warDocBase = new File(name + ".war"); - if (!expandedDocBase.isAbsolute()) { - expandedDocBase = new File(appBase(), name); - warDocBase = new File(appBase(), name + ".war"); - } - // Add the eventual unpacked WAR and all the resources which will be - // watched inside it - if (isWar && unpackWARs) { - deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), - new Long(expandedDocBase.lastModified())); - deployedApp.redeployResources.put - (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); - addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); - } else { - // Find an existing matching war and expanded folder - if (warDocBase.exists()) { - deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), - new Long(warDocBase.lastModified())); - } - if (expandedDocBase.exists()) { - deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), - new Long(expandedDocBase.lastModified())); - addWatchedResources(deployedApp, - expandedDocBase.getAbsolutePath(), context); - } else { - addWatchedResources(deployedApp, null, context); - } - // Add the context XML to the list of files which should trigger a redeployment - if (!isExternal) { - deployedApp.redeployResources.put - (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); - } - } - } catch (Throwable t) { - log.error(sm.getString("hostConfig.deployDescriptor.error", - file), t); - } - - if (context != null && host.findChild(context.getName()) != null) { - deployed.put(contextPath, deployedApp); - } - } - - - /** - * Deploy WAR files. - */ - protected void deployWARs(File appBase, String[] files) { - - if (files == null) - return; - - boolean checkAdditionalDeployments = false; - - for (int i = 0; i < files.length; i++) { - - if (files[i].equalsIgnoreCase("META-INF")) - continue; - if (files[i].equalsIgnoreCase("WEB-INF")) - continue; - File dir = new File(appBase, files[i]); - if (files[i].toLowerCase().endsWith(".war")) { - - // Calculate the context path and make sure it is unique - String contextPath = "/" + files[i]; - int period = contextPath.lastIndexOf("."); - if (period >= 0) - contextPath = contextPath.substring(0, period); - if (contextPath.equals("/ROOT")) - contextPath = ""; - - if (isServiced(contextPath)) - continue; - - String file = files[i]; - - deployWAR(contextPath, dir, file); - - } - - } - - } - - - /** - * @param contextPath - * @param dir - * @param file - */ - protected void deployWAR(String contextPath, File dir, String file) { - - if (deploymentExists(contextPath)) - return; - - // Checking for a nested /META-INF/context.xml - JarFile jar = null; - JarEntry entry = null; - InputStream istream = null; - BufferedOutputStream ostream = null; - File xml = new File - (configBase, file.substring(0, file.lastIndexOf(".")) + ".xml"); - if (deployXML && !xml.exists()) { - try { - jar = new JarFile(dir); - entry = jar.getJarEntry(Constants.ApplicationContextXml); - if (entry != null) { - istream = jar.getInputStream(entry); - - configBase.mkdirs(); - - ostream = - new BufferedOutputStream - (new FileOutputStream(xml), 1024); - byte buffer[] = new byte[1024]; - while (true) { - int n = istream.read(buffer); - if (n < 0) { - break; - } - ostream.write(buffer, 0, n); - } - ostream.flush(); - ostream.close(); - ostream = null; - istream.close(); - istream = null; - entry = null; - jar.close(); - jar = null; - } - } catch (Exception e) { - // Ignore and continue - if (ostream != null) { - try { - ostream.close(); - } catch (Throwable t) { - ; - } - ostream = null; - } - if (istream != null) { - try { - istream.close(); - } catch (Throwable t) { - ; - } - istream = null; - } - } finally { - entry = null; - if (jar != null) { - try { - jar.close(); - } catch (Throwable t) { - ; - } - jar = null; - } - } - } - - DeployedApplication deployedApp = new DeployedApplication(contextPath); - - // Deploy the application in this WAR file - if(log.isInfoEnabled()) - log.info(sm.getString("hostConfig.deployJar", file)); - - // Populate redeploy resources with the WAR file - deployedApp.redeployResources.put - (dir.getAbsolutePath(), new Long(dir.lastModified())); - - try { - Context context = (Context) Class.forName(contextClass).newInstance(); - if (context instanceof Lifecycle) { - Class clazz = Class.forName(host.getConfigClass()); - LifecycleListener listener = - (LifecycleListener) clazz.newInstance(); - ((Lifecycle) context).addLifecycleListener(listener); - } - context.setPath(contextPath); - context.setDocBase(file); - if (xml.exists()) { - context.setConfigFile(xml.getAbsolutePath()); - deployedApp.redeployResources.put - (xml.getAbsolutePath(), new Long(xml.lastModified())); - } - host.addChild(context); - // If we're unpacking WARs, the docBase will be mutated after - // starting the context - if (unpackWARs && (context.getDocBase() != null)) { - String name = null; - String path = context.getPath(); - if (path.equals("")) { - name = "ROOT"; - } else { - if (path.startsWith("/")) { - name = path.substring(1); - } else { - name = path; - } - } - File docBase = new File(name); - if (!docBase.isAbsolute()) { - docBase = new File(appBase(), name); - } - deployedApp.redeployResources.put(docBase.getAbsolutePath(), - new Long(docBase.lastModified())); - addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); - } else { - addWatchedResources(deployedApp, null, context); - } - } catch (Throwable t) { - log.error(sm.getString("hostConfig.deployJar.error", file), t); - } - - deployed.put(contextPath, deployedApp); - } - - - /** - * Deploy directories. - */ - protected void deployDirectories(File appBase, String[] files) { - - if (files == null) - return; - - for (int i = 0; i < files.length; i++) { - - if (files[i].equalsIgnoreCase("META-INF")) - continue; - if (files[i].equalsIgnoreCase("WEB-INF")) - continue; - File dir = new File(appBase, files[i]); - if (dir.isDirectory()) { - - // Calculate the context path and make sure it is unique - String contextPath = "/" + files[i]; - if (files[i].equals("ROOT")) - contextPath = ""; - - if (isServiced(contextPath)) - continue; - - deployDirectory(contextPath, dir, files[i]); - - } - - } - - } - - - /** - * @param contextPath - * @param dir - * @param file - */ - protected void deployDirectory(String contextPath, File dir, String file) { - DeployedApplication deployedApp = new DeployedApplication(contextPath); - - if (deploymentExists(contextPath)) - return; - - // Deploy the application in this directory - if( log.isDebugEnabled() ) - log.debug(sm.getString("hostConfig.deployDir", file)); - try { - Context context = (Context) Class.forName(contextClass).newInstance(); - if (context instanceof Lifecycle) { - Class clazz = Class.forName(host.getConfigClass()); - LifecycleListener listener = - (LifecycleListener) clazz.newInstance(); - ((Lifecycle) context).addLifecycleListener(listener); - } - context.setPath(contextPath); - context.setDocBase(file); - File configFile = new File(dir, Constants.ApplicationContextXml); - if (deployXML) { - context.setConfigFile(configFile.getAbsolutePath()); - } - host.addChild(context); - deployedApp.redeployResources.put(dir.getAbsolutePath(), - new Long(dir.lastModified())); - if (deployXML) { - deployedApp.redeployResources.put(configFile.getAbsolutePath(), - new Long(configFile.lastModified())); - } - addWatchedResources(deployedApp, dir.getAbsolutePath(), context); - } catch (Throwable t) { - log.error(sm.getString("hostConfig.deployDir.error", file), t); - } - - deployed.put(contextPath, deployedApp); - } - - - /** - * Check if a webapp is already deployed in this host. - * - * @param contextPath of the context which will be checked - */ - protected boolean deploymentExists(String contextPath) { - return (deployed.containsKey(contextPath) || (host.findChild(contextPath) != null)); - } - - - /** - * Add watched resources to the specified Context. - * @param app HostConfig deployed app - * @param docBase web app docBase - * @param context web application context - */ - protected void addWatchedResources(DeployedApplication app, String docBase, Context context) { - // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, WEB-INF/*.xml), where - // we would only check if at least one resource is newer than app.timestamp - File docBaseFile = null; - if (docBase != null) { - docBaseFile = new File(docBase); - if (!docBaseFile.isAbsolute()) { - docBaseFile = new File(appBase(), docBase); - } - } - String[] watchedResources = context.findWatchedResources(); - for (int i = 0; i < watchedResources.length; i++) { - File resource = new File(watchedResources[i]); - if (!resource.isAbsolute()) { - if (docBase != null) { - resource = new File(docBaseFile, watchedResources[i]); - } else { - continue; - } - } - app.reloadResources.put(resource.getAbsolutePath(), - new Long(resource.lastModified())); - } - } - - - /** - * Check resources for redeployment and reloading. - */ - protected synchronized void checkResources(DeployedApplication app) { - String[] resources = (String[]) app.redeployResources.keySet().toArray(new String[0]); - for (int i = 0; i < resources.length; i++) { - File resource = new File(resources[i]); - if (log.isDebugEnabled()) - log.debug("Checking context[" + app.name + "] redeploy resource " + resource); - if (resource.exists()) { - long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue(); - if ((!resource.isDirectory()) && resource.lastModified() > lastModified) { - // Undeploy application - if (log.isInfoEnabled()) - log.info(sm.getString("hostConfig.undeploy", app.name)); - ContainerBase context = (ContainerBase) host.findChild(app.name); - try { - host.removeChild(context); - } catch (Throwable t) { - log.warn(sm.getString - ("hostConfig.context.remove", app.name), t); - } - try { - context.destroy(); - } catch (Throwable t) { - log.warn(sm.getString - ("hostConfig.context.destroy", app.name), t); - } - // Delete other redeploy resources - for (int j = i + 1; j < resources.length; j++) { - try { - File current = new File(resources[j]); - current = current.getCanonicalFile(); - if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) - || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - deployed.remove(app.name); - return; - } - } else { - long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue(); - if (lastModified == 0L) { - continue; - } - // Undeploy application - if (log.isInfoEnabled()) - log.info(sm.getString("hostConfig.undeploy", app.name)); - ContainerBase context = (ContainerBase) host.findChild(app.name); - try { - host.removeChild(context); - } catch (Throwable t) { - log.warn(sm.getString - ("hostConfig.context.remove", app.name), t); - } - try { - context.destroy(); - } catch (Throwable t) { - log.warn(sm.getString - ("hostConfig.context.destroy", app.name), t); - } - // Delete all redeploy resources - for (int j = i + 1; j < resources.length; j++) { - try { - File current = new File(resources[j]); - current = current.getCanonicalFile(); - if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) - || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - // Delete reload resources as well (to remove any remaining .xml descriptor) - String[] resources2 = (String[]) app.reloadResources.keySet().toArray(new String[0]); - for (int j = 0; j < resources2.length; j++) { - try { - File current = new File(resources2[j]); - current = current.getCanonicalFile(); - if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) - || ((current.getAbsolutePath().startsWith(configBase().getAbsolutePath()) - && (current.getAbsolutePath().endsWith(".xml"))))) { - if (log.isDebugEnabled()) - log.debug("Delete " + current); - ExpandWar.delete(current); - } - } catch (IOException e) { - log.warn(sm.getString - ("hostConfig.canonicalizing", app.name), e); - } - } - deployed.remove(app.name); - return; - } - } - resources = (String[]) app.reloadResources.keySet().toArray(new String[0]); - for (int i = 0; i < resources.length; i++) { - File resource = new File(resources[i]); - if (log.isDebugEnabled()) - log.debug("Checking context[" + app.name + "] reload resource " + resource); - long lastModified = ((Long) app.reloadResources.get(resources[i])).longValue(); - if ((!resource.exists() && lastModified != 0L) - || (resource.lastModified() != lastModified)) { - // Reload application - if(log.isInfoEnabled()) - log.info(sm.getString("hostConfig.reload", app.name)); - Container context = host.findChild(app.name); - try { - ((Lifecycle) context).stop(); - } catch (Exception e) { - log.warn(sm.getString - ("hostConfig.context.restart", app.name), e); - } - // If the context was not started (for example an error - // in web.xml) we'll still get to try to start - try { - ((Lifecycle) context).start(); - } catch (Exception e) { - log.warn(sm.getString - ("hostConfig.context.restart", app.name), e); - } - // Update times - app.reloadResources.put(resources[i], new Long(resource.lastModified())); - app.timestamp = System.currentTimeMillis(); - return; - } - } - } - - - /** - * Process a "start" event for this Host. - */ - public void start() { - - if (log.isDebugEnabled()) - log.debug(sm.getString("hostConfig.start")); - - try { - ObjectName hostON = new ObjectName(host.getObjectName()); - oname = new ObjectName - (hostON.getDomain() + ":type=Deployer,host=" + host.getName()); - Registry.getRegistry(null, null).registerComponent - (this, oname, this.getClass().getName()); - } catch (Exception e) { - log.error(sm.getString("hostConfig.jmx.register", oname), e); - } - - if (host.getDeployOnStartup()) - deployApps(); - - } - - - /** - * Process a "stop" event for this Host. - */ - public void stop() { - - if (log.isDebugEnabled()) - log.debug(sm.getString("hostConfig.stop")); - - undeployApps(); - - if (oname != null) { - try { - Registry.getRegistry(null, null).unregisterComponent(oname); - } catch (Exception e) { - log.error(sm.getString("hostConfig.jmx.unregister", oname), e); - } - } - oname = null; - appBase = null; - configBase = null; - - } - - - /** - * Undeploy all deployed applications. - */ - protected void undeployApps() { - - if (log.isDebugEnabled()) - log.debug(sm.getString("hostConfig.undeploying")); - - // Soft undeploy all contexts we have deployed - DeployedApplication[] apps = - (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]); - for (int i = 0; i < apps.length; i++) { - try { - host.removeChild(host.findChild(apps[i].name)); - } catch (Throwable t) { - log.warn(sm.getString - ("hostConfig.context.remove", apps[i].name), t); - } - } - - deployed.clear(); - - } - - - /** - * Check status of all webapps. - */ - protected void check() { - - if (host.getAutoDeploy()) { - // Check for resources modification to trigger redeployment - DeployedApplication[] apps = - (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]); - for (int i = 0; i < apps.length; i++) { - if (!isServiced(apps[i].name)) - checkResources(apps[i]); - } - // Hotdeploy applications - deployApps(); - } - - } - - - /** - * Check status of a specific webapp, for use with stuff like management webapps. - */ - public void check(String name) { - DeployedApplication app = (DeployedApplication) deployed.get(name); - if (app != null) { - checkResources(app); - } else { - deployApps(name); - } - } - - /** - * Add a new Context to be managed by us. - * Entry point for the admin webapp, and other JMX Context controlers. - */ - public void manageApp(Context context) { - - String contextPath = context.getPath(); - - if (deployed.containsKey(contextPath)) - return; - - DeployedApplication deployedApp = new DeployedApplication(contextPath); - - // Add the associated docBase to the redeployed list if it's a WAR - boolean isWar = false; - if (context.getDocBase() != null) { - File docBase = new File(context.getDocBase()); - if (!docBase.isAbsolute()) { - docBase = new File(appBase(), context.getDocBase()); - } - deployedApp.redeployResources.put(docBase.getAbsolutePath(), - new Long(docBase.lastModified())); - if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) { - isWar = true; - } - } - host.addChild(context); - // Add the eventual unpacked WAR and all the resources which will be - // watched inside it - if (isWar && unpackWARs) { - String name = null; - String path = context.getPath(); - if (path.equals("")) { - name = "ROOT"; - } else { - if (path.startsWith("/")) { - name = path.substring(1); - } else { - name = path; - } - } - File docBase = new File(name); - if (!docBase.isAbsolute()) { - docBase = new File(appBase(), name); - } - deployedApp.redeployResources.put(docBase.getAbsolutePath(), - new Long(docBase.lastModified())); - addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); - } else { - addWatchedResources(deployedApp, null, context); - } - deployed.put(contextPath, deployedApp); - } - - /** - * Remove a webapp from our control. - * Entry point for the admin webapp, and other JMX Context controlers. - */ - public void unmanageApp(String contextPath) { - if(isServiced(contextPath)) { - deployed.remove(contextPath); - host.removeChild(host.findChild(contextPath)); - } - } - - // ----------------------------------------------------- Instance Variables - - - /** - * This class represents the state of a deployed application, as well as - * the monitored resources. - */ - protected class DeployedApplication { - public DeployedApplication(String name) { - this.name = name; - } - - /** - * Application context path. The assertion is that - * (host.getChild(name) != null). - */ - public String name; - - /** - * Any modification of the specified (static) resources will cause a - * redeployment of the application. If any of the specified resources is - * removed, the application will be undeployed. Typically, this will - * contain resources like the context.xml file, a compressed WAR path. - * The value is the last modification time. - */ - public LinkedHashMap redeployResources = new LinkedHashMap(); - - /** - * Any modification of the specified (static) resources will cause a - * reload of the application. This will typically contain resources - * such as the web.xml of a webapp, but can be configured to contain - * additional descriptors. - * The value is the last modification time. - */ - public HashMap reloadResources = new HashMap(); - - /** - * Instant where the application was last put in service. - */ - public long timestamp = System.currentTimeMillis(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import javax.management.ObjectName; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.core.ContainerBase; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.util.StringManager; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Startup event listener for a Host that configures the properties + * of that Host, and the associated defined contexts. + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 386336 $ $Date: 2006-03-16 15:13:00 +0100 (jeu., 16 mars 2006) $ + */ +public class HostConfig + implements LifecycleListener { + + protected static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( HostConfig.class ); + + // ----------------------------------------------------- Instance Variables + + + /** + * App base. + */ + protected File appBase = null; + + + /** + * Config base. + */ + protected File configBase = null; + + + /** + * The Java class name of the Context configuration class we should use. + */ + protected String configClass = "org.apache.catalina.startup.ContextConfig"; + + + /** + * The Java class name of the Context implementation we should use. + */ + protected String contextClass = "org.apache.catalina.core.StandardContext"; + + + /** + * The Host we are associated with. + */ + protected Host host = null; + + + /** + * The JMX ObjectName of this component. + */ + protected ObjectName oname = null; + + + /** + * The string resources for this package. + */ + protected static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Should we deploy XML Context config files? + */ + protected boolean deployXML = false; + + + /** + * Should we unpack WAR files when auto-deploying applications in the + * appBase directory? + */ + protected boolean unpackWARs = false; + + + /** + * Map of deployed applications. + */ + protected HashMap deployed = new HashMap(); + + + /** + * List of applications which are being serviced, and shouldn't be + * deployed/undeployed/redeployed at the moment. + */ + protected ArrayList serviced = new ArrayList(); + + + /** + * Attribute value used to turn on/off XML validation + */ + protected boolean xmlValidation = false; + + + /** + * Attribute value used to turn on/off XML namespace awarenes. + */ + protected boolean xmlNamespaceAware = false; + + + /** + * The Digester instance used to parse context descriptors. + */ + protected static Digester digester = createDigester(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Context configuration class name. + */ + public String getConfigClass() { + + return (this.configClass); + + } + + + /** + * Set the Context configuration class name. + * + * @param configClass The new Context configuration class name. + */ + public void setConfigClass(String configClass) { + + this.configClass = configClass; + + } + + + /** + * Return the Context implementation class name. + */ + public String getContextClass() { + + return (this.contextClass); + + } + + + /** + * Set the Context implementation class name. + * + * @param contextClass The new Context implementation class name. + */ + public void setContextClass(String contextClass) { + + this.contextClass = contextClass; + + } + + + /** + * Return the deploy XML config file flag for this component. + */ + public boolean isDeployXML() { + + return (this.deployXML); + + } + + + /** + * Set the deploy XML config file flag for this component. + * + * @param deployXML The new deploy XML flag + */ + public void setDeployXML(boolean deployXML) { + + this.deployXML= deployXML; + + } + + + /** + * Return the unpack WARs flag. + */ + public boolean isUnpackWARs() { + + return (this.unpackWARs); + + } + + + /** + * Set the unpack WARs flag. + * + * @param unpackWARs The new unpack WARs flag + */ + public void setUnpackWARs(boolean unpackWARs) { + + this.unpackWARs = unpackWARs; + + } + + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param xmlValidation true to enable xml instance validation + */ + public void setXmlValidation(boolean xmlValidation){ + this.xmlValidation = xmlValidation; + } + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getXmlValidation(){ + return xmlValidation; + } + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + * + */ + public boolean getXmlNamespaceAware(){ + return xmlNamespaceAware; + } + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param xmlNamespaceAware true to enable namespace awareness + */ + public void setXmlNamespaceAware(boolean xmlNamespaceAware){ + this.xmlNamespaceAware=xmlNamespaceAware; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the START event for an associated Host. + * + * @param event The lifecycle event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + if (event.getType().equals(Lifecycle.PERIODIC_EVENT)) + check(); + + // Identify the host we are associated with + try { + host = (Host) event.getLifecycle(); + if (host instanceof StandardHost) { + setDeployXML(((StandardHost) host).isDeployXML()); + setUnpackWARs(((StandardHost) host).isUnpackWARs()); + setXmlNamespaceAware(((StandardHost) host).getXmlNamespaceAware()); + setXmlValidation(((StandardHost) host).getXmlValidation()); + } + } catch (ClassCastException e) { + log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); + return; + } + + // Process the event that has occurred + if (event.getType().equals(Lifecycle.START_EVENT)) + start(); + else if (event.getType().equals(Lifecycle.STOP_EVENT)) + stop(); + + } + + + /** + * Add a serviced application to the list. + */ + public synchronized void addServiced(String name) { + serviced.add(name); + } + + + /** + * Is application serviced ? + * @return state of the application + */ + public synchronized boolean isServiced(String name) { + return (serviced.contains(name)); + } + + + /** + * Removed a serviced application from the list. + */ + public synchronized void removeServiced(String name) { + serviced.remove(name); + } + + + /** + * Get the instant where an application was deployed. + * @return 0L if no application with that name is deployed, or the instant + * on which the application was deployed + */ + public long getDeploymentTime(String name) { + DeployedApplication app = (DeployedApplication) deployed.get(name); + if (app == null) { + return 0L; + } else { + return app.timestamp; + } + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Create the digester which will be used to parse context config files. + */ + protected static Digester createDigester() { + Digester digester = new Digester(); + digester.setValidating(false); + // Add object creation rule + digester.addObjectCreate("Context", "org.apache.catalina.core.StandardContext", + "className"); + // Set the properties on that object (it doesn't matter if extra + // properties are set) + digester.addSetProperties("Context"); + return (digester); + } + + + /** + * Return a File object representing the "application root" directory + * for our associated Host. + */ + protected File appBase() { + + if (appBase != null) { + return appBase; + } + + File file = new File(host.getAppBase()); + if (!file.isAbsolute()) + file = new File(System.getProperty("catalina.base"), + host.getAppBase()); + try { + appBase = file.getCanonicalFile(); + } catch (IOException e) { + appBase = file; + } + return (appBase); + + } + + + /** + * Return a File object representing the "configuration root" directory + * for our associated Host. + */ + protected File configBase() { + + if (configBase != null) { + return configBase; + } + + File file = new File(System.getProperty("catalina.base"), "conf"); + Container parent = host.getParent(); + if ((parent != null) && (parent instanceof Engine)) { + file = new File(file, parent.getName()); + } + file = new File(file, host.getName()); + try { + configBase = file.getCanonicalFile(); + } catch (IOException e) { + configBase = file; + } + return (configBase); + + } + + /** + * Get the name of the configBase. + * For use with JMX management. + */ + public String getConfigBaseName() { + return configBase().getAbsolutePath(); + } + + /** + * Given a context path, get the config file name. + */ + protected String getConfigFile(String path) { + String basename = null; + if (path.equals("")) { + basename = "ROOT"; + } else { + basename = path.substring(1).replace('/', '#'); + } + return (basename); + } + + + /** + * Given a context path, get the config file name. + */ + protected String getDocBase(String path) { + String basename = null; + if (path.equals("")) { + basename = "ROOT"; + } else { + basename = path.substring(1); + } + return (basename); + } + + + /** + * Deploy applications for any directories or WAR files that are found + * in our "application root" directory. + */ + protected void deployApps() { + + File appBase = appBase(); + File configBase = configBase(); + // Deploy XML descriptors from configBase + deployDescriptors(configBase, configBase.list()); + // Deploy WARs, and loop if additional descriptors are found + deployWARs(appBase, appBase.list()); + // Deploy expanded folders + deployDirectories(appBase, appBase.list()); + + } + + + /** + * Deploy applications for any directories or WAR files that are found + * in our "application root" directory. + */ + protected void deployApps(String name) { + + File appBase = appBase(); + File configBase = configBase(); + String baseName = getConfigFile(name); + String docBase = getConfigFile(name); + + // Deploy XML descriptors from configBase + File xml = new File(configBase, baseName + ".xml"); + if (xml.exists()) + deployDescriptor(name, xml, baseName + ".xml"); + // Deploy WARs, and loop if additional descriptors are found + File war = new File(appBase, docBase + ".war"); + if (war.exists()) + deployWAR(name, war, docBase + ".war"); + // Deploy expanded folders + File dir = new File(appBase, docBase); + if (dir.exists()) + deployDirectory(name, dir, docBase); + + } + + + /** + * Deploy XML context descriptors. + */ + protected void deployDescriptors(File configBase, String[] files) { + + if (files == null) + return; + + for (int i = 0; i < files.length; i++) { + + if (files[i].equalsIgnoreCase("META-INF")) + continue; + if (files[i].equalsIgnoreCase("WEB-INF")) + continue; + File contextXml = new File(configBase, files[i]); + if (files[i].toLowerCase().endsWith(".xml")) { + + // Calculate the context path and make sure it is unique + String nameTmp = files[i].substring(0, files[i].length() - 4); + String contextPath = "/" + nameTmp.replace('#', '/'); + if (nameTmp.equals("ROOT")) { + contextPath = ""; + } + + if (isServiced(contextPath)) + continue; + + String file = files[i]; + + deployDescriptor(contextPath, contextXml, file); + + } + + } + + } + + + /** + * @param contextPath + * @param contextXml + * @param file + */ + protected void deployDescriptor(String contextPath, File contextXml, String file) { + if (deploymentExists(contextPath)) { + return; + } + + DeployedApplication deployedApp = new DeployedApplication(contextPath); + + // Assume this is a configuration descriptor and deploy it + if(log.isDebugEnabled()) { + log.debug(sm.getString("hostConfig.deployDescriptor", file)); + } + + Context context = null; + try { + synchronized (digester) { + try { + context = (Context) digester.parse(contextXml); + if (context == null) { + log.error(sm.getString("hostConfig.deployDescriptor.error", + file)); + return; + } + } finally { + digester.reset(); + } + } + if (context instanceof Lifecycle) { + Class clazz = Class.forName(host.getConfigClass()); + LifecycleListener listener = + (LifecycleListener) clazz.newInstance(); + ((Lifecycle) context).addLifecycleListener(listener); + } + context.setConfigFile(contextXml.getAbsolutePath()); + context.setPath(contextPath); + // Add the associated docBase to the redeployed list if it's a WAR + boolean isWar = false; + boolean isExternal = false; + if (context.getDocBase() != null) { + File docBase = new File(context.getDocBase()); + if (!docBase.isAbsolute()) { + docBase = new File(appBase(), context.getDocBase()); + } + // If external docBase, register .xml as redeploy first + if (!docBase.getCanonicalPath().startsWith(appBase().getAbsolutePath())) { + isExternal = true; + deployedApp.redeployResources.put + (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); + deployedApp.redeployResources.put(docBase.getAbsolutePath(), + new Long(docBase.lastModified())); + if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) { + isWar = true; + } + } else { + log.warn(sm.getString("hostConfig.deployDescriptor.localDocBaseSpecified", + docBase)); + // Ignore specified docBase + context.setDocBase(null); + } + } + host.addChild(context); + // Get paths for WAR and expanded WAR in appBase + String name = null; + String path = context.getPath(); + if (path.equals("")) { + name = "ROOT"; + } else { + if (path.startsWith("/")) { + name = path.substring(1); + } else { + name = path; + } + } + File expandedDocBase = new File(name); + File warDocBase = new File(name + ".war"); + if (!expandedDocBase.isAbsolute()) { + expandedDocBase = new File(appBase(), name); + warDocBase = new File(appBase(), name + ".war"); + } + // Add the eventual unpacked WAR and all the resources which will be + // watched inside it + if (isWar && unpackWARs) { + deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), + new Long(expandedDocBase.lastModified())); + deployedApp.redeployResources.put + (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); + addWatchedResources(deployedApp, expandedDocBase.getAbsolutePath(), context); + } else { + // Find an existing matching war and expanded folder + if (warDocBase.exists()) { + deployedApp.redeployResources.put(warDocBase.getAbsolutePath(), + new Long(warDocBase.lastModified())); + } + if (expandedDocBase.exists()) { + deployedApp.redeployResources.put(expandedDocBase.getAbsolutePath(), + new Long(expandedDocBase.lastModified())); + addWatchedResources(deployedApp, + expandedDocBase.getAbsolutePath(), context); + } else { + addWatchedResources(deployedApp, null, context); + } + // Add the context XML to the list of files which should trigger a redeployment + if (!isExternal) { + deployedApp.redeployResources.put + (contextXml.getAbsolutePath(), new Long(contextXml.lastModified())); + } + } + } catch (Throwable t) { + log.error(sm.getString("hostConfig.deployDescriptor.error", + file), t); + } + + if (context != null && host.findChild(context.getName()) != null) { + deployed.put(contextPath, deployedApp); + } + } + + + /** + * Deploy WAR files. + */ + protected void deployWARs(File appBase, String[] files) { + + if (files == null) + return; + + boolean checkAdditionalDeployments = false; + + for (int i = 0; i < files.length; i++) { + + if (files[i].equalsIgnoreCase("META-INF")) + continue; + if (files[i].equalsIgnoreCase("WEB-INF")) + continue; + File dir = new File(appBase, files[i]); + if (files[i].toLowerCase().endsWith(".war")) { + + // Calculate the context path and make sure it is unique + String contextPath = "/" + files[i]; + int period = contextPath.lastIndexOf("."); + if (period >= 0) + contextPath = contextPath.substring(0, period); + if (contextPath.equals("/ROOT")) + contextPath = ""; + + if (isServiced(contextPath)) + continue; + + String file = files[i]; + + deployWAR(contextPath, dir, file); + + } + + } + + } + + + /** + * @param contextPath + * @param dir + * @param file + */ + protected void deployWAR(String contextPath, File dir, String file) { + + if (deploymentExists(contextPath)) + return; + + // Checking for a nested /META-INF/context.xml + JarFile jar = null; + JarEntry entry = null; + InputStream istream = null; + BufferedOutputStream ostream = null; + File xml = new File + (configBase, file.substring(0, file.lastIndexOf(".")) + ".xml"); + if (deployXML && !xml.exists()) { + try { + jar = new JarFile(dir); + entry = jar.getJarEntry(Constants.ApplicationContextXml); + if (entry != null) { + istream = jar.getInputStream(entry); + + configBase.mkdirs(); + + ostream = + new BufferedOutputStream + (new FileOutputStream(xml), 1024); + byte buffer[] = new byte[1024]; + while (true) { + int n = istream.read(buffer); + if (n < 0) { + break; + } + ostream.write(buffer, 0, n); + } + ostream.flush(); + ostream.close(); + ostream = null; + istream.close(); + istream = null; + entry = null; + jar.close(); + jar = null; + } + } catch (Exception e) { + // Ignore and continue + if (ostream != null) { + try { + ostream.close(); + } catch (Throwable t) { + ; + } + ostream = null; + } + if (istream != null) { + try { + istream.close(); + } catch (Throwable t) { + ; + } + istream = null; + } + } finally { + entry = null; + if (jar != null) { + try { + jar.close(); + } catch (Throwable t) { + ; + } + jar = null; + } + } + } + + DeployedApplication deployedApp = new DeployedApplication(contextPath); + + // Deploy the application in this WAR file + if(log.isInfoEnabled()) + log.info(sm.getString("hostConfig.deployJar", file)); + + // Populate redeploy resources with the WAR file + deployedApp.redeployResources.put + (dir.getAbsolutePath(), new Long(dir.lastModified())); + + try { + Context context = (Context) Class.forName(contextClass).newInstance(); + if (context instanceof Lifecycle) { + Class clazz = Class.forName(host.getConfigClass()); + LifecycleListener listener = + (LifecycleListener) clazz.newInstance(); + ((Lifecycle) context).addLifecycleListener(listener); + } + context.setPath(contextPath); + context.setDocBase(file); + if (xml.exists()) { + context.setConfigFile(xml.getAbsolutePath()); + deployedApp.redeployResources.put + (xml.getAbsolutePath(), new Long(xml.lastModified())); + } + host.addChild(context); + // If we're unpacking WARs, the docBase will be mutated after + // starting the context + if (unpackWARs && (context.getDocBase() != null)) { + String name = null; + String path = context.getPath(); + if (path.equals("")) { + name = "ROOT"; + } else { + if (path.startsWith("/")) { + name = path.substring(1); + } else { + name = path; + } + } + File docBase = new File(name); + if (!docBase.isAbsolute()) { + docBase = new File(appBase(), name); + } + deployedApp.redeployResources.put(docBase.getAbsolutePath(), + new Long(docBase.lastModified())); + addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); + } else { + addWatchedResources(deployedApp, null, context); + } + } catch (Throwable t) { + log.error(sm.getString("hostConfig.deployJar.error", file), t); + } + + deployed.put(contextPath, deployedApp); + } + + + /** + * Deploy directories. + */ + protected void deployDirectories(File appBase, String[] files) { + + if (files == null) + return; + + for (int i = 0; i < files.length; i++) { + + if (files[i].equalsIgnoreCase("META-INF")) + continue; + if (files[i].equalsIgnoreCase("WEB-INF")) + continue; + File dir = new File(appBase, files[i]); + if (dir.isDirectory()) { + + // Calculate the context path and make sure it is unique + String contextPath = "/" + files[i]; + if (files[i].equals("ROOT")) + contextPath = ""; + + if (isServiced(contextPath)) + continue; + + deployDirectory(contextPath, dir, files[i]); + + } + + } + + } + + + /** + * @param contextPath + * @param dir + * @param file + */ + protected void deployDirectory(String contextPath, File dir, String file) { + DeployedApplication deployedApp = new DeployedApplication(contextPath); + + if (deploymentExists(contextPath)) + return; + + // Deploy the application in this directory + if( log.isDebugEnabled() ) + log.debug(sm.getString("hostConfig.deployDir", file)); + try { + Context context = (Context) Class.forName(contextClass).newInstance(); + if (context instanceof Lifecycle) { + Class clazz = Class.forName(host.getConfigClass()); + LifecycleListener listener = + (LifecycleListener) clazz.newInstance(); + ((Lifecycle) context).addLifecycleListener(listener); + } + context.setPath(contextPath); + context.setDocBase(file); + File configFile = new File(dir, Constants.ApplicationContextXml); + if (deployXML) { + context.setConfigFile(configFile.getAbsolutePath()); + } + host.addChild(context); + deployedApp.redeployResources.put(dir.getAbsolutePath(), + new Long(dir.lastModified())); + if (deployXML) { + deployedApp.redeployResources.put(configFile.getAbsolutePath(), + new Long(configFile.lastModified())); + } + addWatchedResources(deployedApp, dir.getAbsolutePath(), context); + } catch (Throwable t) { + log.error(sm.getString("hostConfig.deployDir.error", file), t); + } + + deployed.put(contextPath, deployedApp); + } + + + /** + * Check if a webapp is already deployed in this host. + * + * @param contextPath of the context which will be checked + */ + protected boolean deploymentExists(String contextPath) { + return (deployed.containsKey(contextPath) || (host.findChild(contextPath) != null)); + } + + + /** + * Add watched resources to the specified Context. + * @param app HostConfig deployed app + * @param docBase web app docBase + * @param context web application context + */ + protected void addWatchedResources(DeployedApplication app, String docBase, Context context) { + // FIXME: Feature idea. Add support for patterns (ex: WEB-INF/*, WEB-INF/*.xml), where + // we would only check if at least one resource is newer than app.timestamp + File docBaseFile = null; + if (docBase != null) { + docBaseFile = new File(docBase); + if (!docBaseFile.isAbsolute()) { + docBaseFile = new File(appBase(), docBase); + } + } + String[] watchedResources = context.findWatchedResources(); + for (int i = 0; i < watchedResources.length; i++) { + File resource = new File(watchedResources[i]); + if (!resource.isAbsolute()) { + if (docBase != null) { + resource = new File(docBaseFile, watchedResources[i]); + } else { + continue; + } + } + app.reloadResources.put(resource.getAbsolutePath(), + new Long(resource.lastModified())); + } + } + + + /** + * Check resources for redeployment and reloading. + */ + protected synchronized void checkResources(DeployedApplication app) { + String[] resources = (String[]) app.redeployResources.keySet().toArray(new String[0]); + for (int i = 0; i < resources.length; i++) { + File resource = new File(resources[i]); + if (log.isDebugEnabled()) + log.debug("Checking context[" + app.name + "] redeploy resource " + resource); + if (resource.exists()) { + long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue(); + if ((!resource.isDirectory()) && resource.lastModified() > lastModified) { + // Undeploy application + if (log.isInfoEnabled()) + log.info(sm.getString("hostConfig.undeploy", app.name)); + ContainerBase context = (ContainerBase) host.findChild(app.name); + try { + host.removeChild(context); + } catch (Throwable t) { + log.warn(sm.getString + ("hostConfig.context.remove", app.name), t); + } + try { + context.destroy(); + } catch (Throwable t) { + log.warn(sm.getString + ("hostConfig.context.destroy", app.name), t); + } + // Delete other redeploy resources + for (int j = i + 1; j < resources.length; j++) { + try { + File current = new File(resources[j]); + current = current.getCanonicalFile(); + if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) + || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) { + if (log.isDebugEnabled()) + log.debug("Delete " + current); + ExpandWar.delete(current); + } + } catch (IOException e) { + log.warn(sm.getString + ("hostConfig.canonicalizing", app.name), e); + } + } + deployed.remove(app.name); + return; + } + } else { + long lastModified = ((Long) app.redeployResources.get(resources[i])).longValue(); + if (lastModified == 0L) { + continue; + } + // Undeploy application + if (log.isInfoEnabled()) + log.info(sm.getString("hostConfig.undeploy", app.name)); + ContainerBase context = (ContainerBase) host.findChild(app.name); + try { + host.removeChild(context); + } catch (Throwable t) { + log.warn(sm.getString + ("hostConfig.context.remove", app.name), t); + } + try { + context.destroy(); + } catch (Throwable t) { + log.warn(sm.getString + ("hostConfig.context.destroy", app.name), t); + } + // Delete all redeploy resources + for (int j = i + 1; j < resources.length; j++) { + try { + File current = new File(resources[j]); + current = current.getCanonicalFile(); + if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) + || (current.getAbsolutePath().startsWith(configBase().getAbsolutePath()))) { + if (log.isDebugEnabled()) + log.debug("Delete " + current); + ExpandWar.delete(current); + } + } catch (IOException e) { + log.warn(sm.getString + ("hostConfig.canonicalizing", app.name), e); + } + } + // Delete reload resources as well (to remove any remaining .xml descriptor) + String[] resources2 = (String[]) app.reloadResources.keySet().toArray(new String[0]); + for (int j = 0; j < resources2.length; j++) { + try { + File current = new File(resources2[j]); + current = current.getCanonicalFile(); + if ((current.getAbsolutePath().startsWith(appBase().getAbsolutePath())) + || ((current.getAbsolutePath().startsWith(configBase().getAbsolutePath()) + && (current.getAbsolutePath().endsWith(".xml"))))) { + if (log.isDebugEnabled()) + log.debug("Delete " + current); + ExpandWar.delete(current); + } + } catch (IOException e) { + log.warn(sm.getString + ("hostConfig.canonicalizing", app.name), e); + } + } + deployed.remove(app.name); + return; + } + } + resources = (String[]) app.reloadResources.keySet().toArray(new String[0]); + for (int i = 0; i < resources.length; i++) { + File resource = new File(resources[i]); + if (log.isDebugEnabled()) + log.debug("Checking context[" + app.name + "] reload resource " + resource); + long lastModified = ((Long) app.reloadResources.get(resources[i])).longValue(); + if ((!resource.exists() && lastModified != 0L) + || (resource.lastModified() != lastModified)) { + // Reload application + if(log.isInfoEnabled()) + log.info(sm.getString("hostConfig.reload", app.name)); + Container context = host.findChild(app.name); + try { + ((Lifecycle) context).stop(); + } catch (Exception e) { + log.warn(sm.getString + ("hostConfig.context.restart", app.name), e); + } + // If the context was not started (for example an error + // in web.xml) we'll still get to try to start + try { + ((Lifecycle) context).start(); + } catch (Exception e) { + log.warn(sm.getString + ("hostConfig.context.restart", app.name), e); + } + // Update times + app.reloadResources.put(resources[i], new Long(resource.lastModified())); + app.timestamp = System.currentTimeMillis(); + return; + } + } + } + + + /** + * Process a "start" event for this Host. + */ + public void start() { + + if (log.isDebugEnabled()) + log.debug(sm.getString("hostConfig.start")); + + try { + ObjectName hostON = new ObjectName(host.getObjectName()); + oname = new ObjectName + (hostON.getDomain() + ":type=Deployer,host=" + host.getName()); + Registry.getRegistry(null, null).registerComponent + (this, oname, this.getClass().getName()); + } catch (Exception e) { + log.error(sm.getString("hostConfig.jmx.register", oname), e); + } + + if (host.getDeployOnStartup()) + deployApps(); + + } + + + /** + * Process a "stop" event for this Host. + */ + public void stop() { + + if (log.isDebugEnabled()) + log.debug(sm.getString("hostConfig.stop")); + + undeployApps(); + + if (oname != null) { + try { + Registry.getRegistry(null, null).unregisterComponent(oname); + } catch (Exception e) { + log.error(sm.getString("hostConfig.jmx.unregister", oname), e); + } + } + oname = null; + appBase = null; + configBase = null; + + } + + + /** + * Undeploy all deployed applications. + */ + protected void undeployApps() { + + if (log.isDebugEnabled()) + log.debug(sm.getString("hostConfig.undeploying")); + + // Soft undeploy all contexts we have deployed + DeployedApplication[] apps = + (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]); + for (int i = 0; i < apps.length; i++) { + try { + host.removeChild(host.findChild(apps[i].name)); + } catch (Throwable t) { + log.warn(sm.getString + ("hostConfig.context.remove", apps[i].name), t); + } + } + + deployed.clear(); + + } + + + /** + * Check status of all webapps. + */ + protected void check() { + + if (host.getAutoDeploy()) { + // Check for resources modification to trigger redeployment + DeployedApplication[] apps = + (DeployedApplication[]) deployed.values().toArray(new DeployedApplication[0]); + for (int i = 0; i < apps.length; i++) { + if (!isServiced(apps[i].name)) + checkResources(apps[i]); + } + // Hotdeploy applications + deployApps(); + } + + } + + + /** + * Check status of a specific webapp, for use with stuff like management webapps. + */ + public void check(String name) { + DeployedApplication app = (DeployedApplication) deployed.get(name); + if (app != null) { + checkResources(app); + } else { + deployApps(name); + } + } + + /** + * Add a new Context to be managed by us. + * Entry point for the admin webapp, and other JMX Context controlers. + */ + public void manageApp(Context context) { + + String contextPath = context.getPath(); + + if (deployed.containsKey(contextPath)) + return; + + DeployedApplication deployedApp = new DeployedApplication(contextPath); + + // Add the associated docBase to the redeployed list if it's a WAR + boolean isWar = false; + if (context.getDocBase() != null) { + File docBase = new File(context.getDocBase()); + if (!docBase.isAbsolute()) { + docBase = new File(appBase(), context.getDocBase()); + } + deployedApp.redeployResources.put(docBase.getAbsolutePath(), + new Long(docBase.lastModified())); + if (docBase.getAbsolutePath().toLowerCase().endsWith(".war")) { + isWar = true; + } + } + host.addChild(context); + // Add the eventual unpacked WAR and all the resources which will be + // watched inside it + if (isWar && unpackWARs) { + String name = null; + String path = context.getPath(); + if (path.equals("")) { + name = "ROOT"; + } else { + if (path.startsWith("/")) { + name = path.substring(1); + } else { + name = path; + } + } + File docBase = new File(name); + if (!docBase.isAbsolute()) { + docBase = new File(appBase(), name); + } + deployedApp.redeployResources.put(docBase.getAbsolutePath(), + new Long(docBase.lastModified())); + addWatchedResources(deployedApp, docBase.getAbsolutePath(), context); + } else { + addWatchedResources(deployedApp, null, context); + } + deployed.put(contextPath, deployedApp); + } + + /** + * Remove a webapp from our control. + * Entry point for the admin webapp, and other JMX Context controlers. + */ + public void unmanageApp(String contextPath) { + if(isServiced(contextPath)) { + deployed.remove(contextPath); + host.removeChild(host.findChild(contextPath)); + } + } + + // ----------------------------------------------------- Instance Variables + + + /** + * This class represents the state of a deployed application, as well as + * the monitored resources. + */ + protected class DeployedApplication { + public DeployedApplication(String name) { + this.name = name; + } + + /** + * Application context path. The assertion is that + * (host.getChild(name) != null). + */ + public String name; + + /** + * Any modification of the specified (static) resources will cause a + * redeployment of the application. If any of the specified resources is + * removed, the application will be undeployed. Typically, this will + * contain resources like the context.xml file, a compressed WAR path. + * The value is the last modification time. + */ + public LinkedHashMap redeployResources = new LinkedHashMap(); + + /** + * Any modification of the specified (static) resources will cause a + * reload of the application. This will typically contain resources + * such as the web.xml of a webapp, but can be configured to contain + * additional descriptors. + * The value is the last modification time. + */ + public HashMap reloadResources = new HashMap(); + + /** + * Instant where the application was last put in service. + */ + public long timestamp = System.currentTimeMillis(); + } + +} diff --git a/java/org/apache/catalina/startup/HostRuleSet.java b/java/org/apache/catalina/startup/HostRuleSet.java index 0af2ff949..0f9557fbd 100644 --- a/java/org/apache/catalina/startup/HostRuleSet.java +++ b/java/org/apache/catalina/startup/HostRuleSet.java @@ -1,145 +1,145 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.RuleSetBase; - - -/** - *

        RuleSet for processing the contents of a - * Host definition element. This RuleSet does NOT include - * any rules for nested Context or DefaultContext elements, which should - * be added via instances of ContextRuleSet.

        - * - * @author Craig R. McClanahan - * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ - */ - -public class HostRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public HostRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public HostRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - digester.addObjectCreate(prefix + "Host", - "org.apache.catalina.core.StandardHost", - "className"); - digester.addSetProperties(prefix + "Host"); - digester.addRule(prefix + "Host", - new CopyParentClassLoaderRule()); - digester.addRule(prefix + "Host", - new LifecycleListenerRule - ("org.apache.catalina.startup.HostConfig", - "hostConfigClass")); - digester.addSetNext(prefix + "Host", - "addChild", - "org.apache.catalina.Container"); - - digester.addCallMethod(prefix + "Host/Alias", - "addAlias", 0); - - //Cluster configuration start - digester.addObjectCreate(prefix + "Host/Cluster", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Host/Cluster"); - digester.addSetNext(prefix + "Host/Cluster", - "setCluster", - "org.apache.catalina.Cluster"); - //Cluster configuration end - - digester.addObjectCreate(prefix + "Host/Listener", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Host/Listener"); - digester.addSetNext(prefix + "Host/Listener", - "addLifecycleListener", - "org.apache.catalina.LifecycleListener"); - - digester.addObjectCreate(prefix + "Host/Realm", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Host/Realm"); - digester.addSetNext(prefix + "Host/Realm", - "setRealm", - "org.apache.catalina.Realm"); - - digester.addObjectCreate(prefix + "Host/Valve", - null, // MUST be specified in the element - "className"); - digester.addSetProperties(prefix + "Host/Valve"); - digester.addSetNext(prefix + "Host/Valve", - "addValve", - "org.apache.catalina.Valve"); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSetBase; + + +/** + *

        RuleSet for processing the contents of a + * Host definition element. This RuleSet does NOT include + * any rules for nested Context or DefaultContext elements, which should + * be added via instances of ContextRuleSet.

        + * + * @author Craig R. McClanahan + * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ + */ + +public class HostRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public HostRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public HostRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + digester.addObjectCreate(prefix + "Host", + "org.apache.catalina.core.StandardHost", + "className"); + digester.addSetProperties(prefix + "Host"); + digester.addRule(prefix + "Host", + new CopyParentClassLoaderRule()); + digester.addRule(prefix + "Host", + new LifecycleListenerRule + ("org.apache.catalina.startup.HostConfig", + "hostConfigClass")); + digester.addSetNext(prefix + "Host", + "addChild", + "org.apache.catalina.Container"); + + digester.addCallMethod(prefix + "Host/Alias", + "addAlias", 0); + + //Cluster configuration start + digester.addObjectCreate(prefix + "Host/Cluster", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Host/Cluster"); + digester.addSetNext(prefix + "Host/Cluster", + "setCluster", + "org.apache.catalina.Cluster"); + //Cluster configuration end + + digester.addObjectCreate(prefix + "Host/Listener", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Host/Listener"); + digester.addSetNext(prefix + "Host/Listener", + "addLifecycleListener", + "org.apache.catalina.LifecycleListener"); + + digester.addObjectCreate(prefix + "Host/Realm", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Host/Realm"); + digester.addSetNext(prefix + "Host/Realm", + "setRealm", + "org.apache.catalina.Realm"); + + digester.addObjectCreate(prefix + "Host/Valve", + null, // MUST be specified in the element + "className"); + digester.addSetProperties(prefix + "Host/Valve"); + digester.addSetNext(prefix + "Host/Valve", + "addValve", + "org.apache.catalina.Valve"); + + } + + +} diff --git a/java/org/apache/catalina/startup/LifecycleListenerRule.java b/java/org/apache/catalina/startup/LifecycleListenerRule.java index c22122e75..e8b2938c9 100644 --- a/java/org/apache/catalina/startup/LifecycleListenerRule.java +++ b/java/org/apache/catalina/startup/LifecycleListenerRule.java @@ -1,102 +1,102 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleListener; -import org.apache.tomcat.util.digester.Rule; -import org.xml.sax.Attributes; - - -/** - *

        Rule that creates a new LifecycleListener instance, - * and associates it with the top object on the stack (which must - * implement LifecycleListener).

        - */ - -public class LifecycleListenerRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this Rule. - * - * @param listenerClass Default name of the LifecycleListener - * implementation class to be created - * @param attributeName Name of the attribute that optionally - * includes an override name of the LifecycleListener class - */ - public LifecycleListenerRule(String listenerClass, String attributeName) { - - this.listenerClass = listenerClass; - this.attributeName = attributeName; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The attribute name of an attribute that can override the - * implementation class name. - */ - private String attributeName; - - - /** - * The name of the LifecycleListener implementation class. - */ - private String listenerClass; - - - // --------------------------------------------------------- Public Methods - - - /** - * Handle the beginning of an XML element. - * - * @param attributes The attributes of this element - * - * @exception Exception if a processing error occurs - */ - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - // Instantiate a new LifecyleListener implementation object - String className = listenerClass; - if (attributeName != null) { - String value = attributes.getValue(attributeName); - if (value != null) - className = value; - } - Class clazz = Class.forName(className); - LifecycleListener listener = - (LifecycleListener) clazz.newInstance(); - - // Add this LifecycleListener to our associated component - Lifecycle lifecycle = (Lifecycle) digester.peek(); - lifecycle.addLifecycleListener(listener); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleListener; +import org.apache.tomcat.util.digester.Rule; +import org.xml.sax.Attributes; + + +/** + *

        Rule that creates a new LifecycleListener instance, + * and associates it with the top object on the stack (which must + * implement LifecycleListener).

        + */ + +public class LifecycleListenerRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this Rule. + * + * @param listenerClass Default name of the LifecycleListener + * implementation class to be created + * @param attributeName Name of the attribute that optionally + * includes an override name of the LifecycleListener class + */ + public LifecycleListenerRule(String listenerClass, String attributeName) { + + this.listenerClass = listenerClass; + this.attributeName = attributeName; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute name of an attribute that can override the + * implementation class name. + */ + private String attributeName; + + + /** + * The name of the LifecycleListener implementation class. + */ + private String listenerClass; + + + // --------------------------------------------------------- Public Methods + + + /** + * Handle the beginning of an XML element. + * + * @param attributes The attributes of this element + * + * @exception Exception if a processing error occurs + */ + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + // Instantiate a new LifecyleListener implementation object + String className = listenerClass; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) + className = value; + } + Class clazz = Class.forName(className); + LifecycleListener listener = + (LifecycleListener) clazz.newInstance(); + + // Add this LifecycleListener to our associated component + Lifecycle lifecycle = (Lifecycle) digester.peek(); + lifecycle.addLifecycleListener(listener); + + } + + +} diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties index 5fdb3a3e5..b376dfe92 100644 --- a/java/org/apache/catalina/startup/LocalStrings.properties +++ b/java/org/apache/catalina/startup/LocalStrings.properties @@ -1,77 +1,77 @@ -contextConfig.applicationClose=Error closing application web.xml -contextConfig.applicationConfig=Configuration error in application web.xml -contextConfig.applicationListener=Exception creating listener of class {0} -contextConfig.applicationMissing=Missing application web.xml, using defaults only -contextConfig.applicationParse=Parse error in application web.xml file at {0} -contextConfig.applicationPosition=Occurred at line {0} column {1} -contextConfig.authenticatorConfigured=Configured an authenticator for method {0} -contextConfig.authenticatorInstantiate=Cannot instantiate an authenticator of class {0} -contextConfig.authenticatorMissing=Cannot configure an authenticator for method {0} -contextConfig.authenticatorResources=Cannot load authenticators mapping list -contextConfig.cce=Lifecycle event data object {0} is not a Context -contextConfig.certificatesConfig.added=Added certificates -> request attribute Valve -contextConfig.certificatesConfig.error=Exception adding CertificatesValve: -contextConfig.defaultClose=Error closing default web.xml -contextConfig.defaultConfig=Configuration error in default web.xml -contextConfig.defaultMissing=Missing default web.xml, using application web.xml only -contextConfig.defaultParse=Parse error in default web.xml -contextConfig.defaultPosition=Occurred at line {0} column {1} -contextConfig.fixDocBase=Exception fixing docBase: {0} -contextConfig.init=ContextConfig: Initializing -contextConfig.missingRealm=No Realm has been configured to authenticate against -contextConfig.role.auth=WARNING: Security role name {0} used in an without being defined in a -contextConfig.role.link=WARNING: Security role name {0} used in a without being defined in a -contextConfig.role.runas=WARNING: Security role name {0} used in a without being defined in a -contextConfig.start=ContextConfig: Processing START -contextConfig.stop=ContextConfig: Processing STOP -contextConfig.tldEntryException=Exception processing TLD {0} in JAR at resource path {1} in context {2} -contextConfig.tldFileException=Exception processing TLD at resource path {0} in context {1} -contextConfig.tldJarException=Exception processing JAR at resource path {0} in context {1} -contextConfig.tldResourcePath=Invalid TLD resource path {0} -contextConfig.unavailable=Marking this application unavailable due to previous error(s) -contextConfig.altDDNotFound=alt-dd file {0} not found -embedded.alreadyStarted=Embedded service has already been started -embedded.noEngines=No engines have been defined yet -embedded.notmp=Cannot find specified temporary folder at {0} -embedded.notStarted=Embedded service has not yet been started -embedded.authenticatorNotInstanceOfValve=Specified Authenticator is not a Valve -engineConfig.cce=Lifecycle event data object {0} is not an Engine -engineConfig.start=EngineConfig: Processing START -engineConfig.stop=EngineConfig: Processing STOP -expandWar.copy=Error copying {0} to {1} -hostConfig.appBase=Application base directory {0} does not exist -hostConfig.canonicalizing=Error delete redeploy resources from context [{0}] -hostConfig.cce=Lifecycle event data object {0} is not a Host -hostConfig.context.destroy=Error during context [{0}] destroy -hostConfig.context.remove=Error while removing context [{0}] -hostConfig.context.restart=Error during context [{0}] restart -hostConfig.deploy=Deploying web application directory {0} -hostConfig.deployDescriptor=Deploying configuration descriptor {0} -hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0} -hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored -hostConfig.deployDir=Deploying web application directory {0} -hostConfig.deployDir.error=Error deploying web application directory {0} -hostConfig.deployJar=Deploying web application archive {0} -hostConfig.deployJar.error=Error deploying web application archive {0} -hostConfig.deploy.error=Exception while deploying web application directory {0} -hostConfig.deploying=Deploying discovered web applications -hostConfig.expand=Expanding web application archive {0} -hostConfig.expand.error=Exception while expanding web application archive {0} -hostConfig.expanding=Expanding discovered web application archives -hostConfig.jmx.register=Register context [{0}] failed -hostConfig.jmx.unregister=Unregister context [{0}] failed -hostConfig.reload=Reloading context [{0}] -hostConfig.removeXML=Context [{0}] is undeployed -hostConfig.removeDIR=Directory {0} is undeployed -hostConfig.removeWAR=War {0} is undeployed -hostConfig.start=HostConfig: Processing START -hostConfig.stop=HostConfig: Processing STOP -hostConfig.undeploy=Undeploying context [{0}] -hostConfig.undeploy.error=Error undeploying web application at context path {0} -hostConfig.undeploying=Undeploying deployed web applications -userConfig.database=Exception loading user database -userConfig.deploy=Deploying web application for user {0} -userConfig.deploying=Deploying user web applications -userConfig.error=Error deploying web application for user {0} -userConfig.start=UserConfig: Processing START -userConfig.stop=UserConfig: Processing STOP +contextConfig.applicationClose=Error closing application web.xml +contextConfig.applicationConfig=Configuration error in application web.xml +contextConfig.applicationListener=Exception creating listener of class {0} +contextConfig.applicationMissing=Missing application web.xml, using defaults only +contextConfig.applicationParse=Parse error in application web.xml file at {0} +contextConfig.applicationPosition=Occurred at line {0} column {1} +contextConfig.authenticatorConfigured=Configured an authenticator for method {0} +contextConfig.authenticatorInstantiate=Cannot instantiate an authenticator of class {0} +contextConfig.authenticatorMissing=Cannot configure an authenticator for method {0} +contextConfig.authenticatorResources=Cannot load authenticators mapping list +contextConfig.cce=Lifecycle event data object {0} is not a Context +contextConfig.certificatesConfig.added=Added certificates -> request attribute Valve +contextConfig.certificatesConfig.error=Exception adding CertificatesValve: +contextConfig.defaultClose=Error closing default web.xml +contextConfig.defaultConfig=Configuration error in default web.xml +contextConfig.defaultMissing=Missing default web.xml, using application web.xml only +contextConfig.defaultParse=Parse error in default web.xml +contextConfig.defaultPosition=Occurred at line {0} column {1} +contextConfig.fixDocBase=Exception fixing docBase: {0} +contextConfig.init=ContextConfig: Initializing +contextConfig.missingRealm=No Realm has been configured to authenticate against +contextConfig.role.auth=WARNING: Security role name {0} used in an without being defined in a +contextConfig.role.link=WARNING: Security role name {0} used in a without being defined in a +contextConfig.role.runas=WARNING: Security role name {0} used in a without being defined in a +contextConfig.start=ContextConfig: Processing START +contextConfig.stop=ContextConfig: Processing STOP +contextConfig.tldEntryException=Exception processing TLD {0} in JAR at resource path {1} in context {2} +contextConfig.tldFileException=Exception processing TLD at resource path {0} in context {1} +contextConfig.tldJarException=Exception processing JAR at resource path {0} in context {1} +contextConfig.tldResourcePath=Invalid TLD resource path {0} +contextConfig.unavailable=Marking this application unavailable due to previous error(s) +contextConfig.altDDNotFound=alt-dd file {0} not found +embedded.alreadyStarted=Embedded service has already been started +embedded.noEngines=No engines have been defined yet +embedded.notmp=Cannot find specified temporary folder at {0} +embedded.notStarted=Embedded service has not yet been started +embedded.authenticatorNotInstanceOfValve=Specified Authenticator is not a Valve +engineConfig.cce=Lifecycle event data object {0} is not an Engine +engineConfig.start=EngineConfig: Processing START +engineConfig.stop=EngineConfig: Processing STOP +expandWar.copy=Error copying {0} to {1} +hostConfig.appBase=Application base directory {0} does not exist +hostConfig.canonicalizing=Error delete redeploy resources from context [{0}] +hostConfig.cce=Lifecycle event data object {0} is not a Host +hostConfig.context.destroy=Error during context [{0}] destroy +hostConfig.context.remove=Error while removing context [{0}] +hostConfig.context.restart=Error during context [{0}] restart +hostConfig.deploy=Deploying web application directory {0} +hostConfig.deployDescriptor=Deploying configuration descriptor {0} +hostConfig.deployDescriptor.error=Error deploying configuration descriptor {0} +hostConfig.deployDescriptor.localDocBaseSpecified=A docBase {0} inside the host appBase has been specified, and will be ignored +hostConfig.deployDir=Deploying web application directory {0} +hostConfig.deployDir.error=Error deploying web application directory {0} +hostConfig.deployJar=Deploying web application archive {0} +hostConfig.deployJar.error=Error deploying web application archive {0} +hostConfig.deploy.error=Exception while deploying web application directory {0} +hostConfig.deploying=Deploying discovered web applications +hostConfig.expand=Expanding web application archive {0} +hostConfig.expand.error=Exception while expanding web application archive {0} +hostConfig.expanding=Expanding discovered web application archives +hostConfig.jmx.register=Register context [{0}] failed +hostConfig.jmx.unregister=Unregister context [{0}] failed +hostConfig.reload=Reloading context [{0}] +hostConfig.removeXML=Context [{0}] is undeployed +hostConfig.removeDIR=Directory {0} is undeployed +hostConfig.removeWAR=War {0} is undeployed +hostConfig.start=HostConfig: Processing START +hostConfig.stop=HostConfig: Processing STOP +hostConfig.undeploy=Undeploying context [{0}] +hostConfig.undeploy.error=Error undeploying web application at context path {0} +hostConfig.undeploying=Undeploying deployed web applications +userConfig.database=Exception loading user database +userConfig.deploy=Deploying web application for user {0} +userConfig.deploying=Deploying user web applications +userConfig.error=Error deploying web application for user {0} +userConfig.start=UserConfig: Processing START +userConfig.stop=UserConfig: Processing STOP diff --git a/java/org/apache/catalina/startup/LocalStrings_es.properties b/java/org/apache/catalina/startup/LocalStrings_es.properties index 24d813049..0ecf8b16d 100644 --- a/java/org/apache/catalina/startup/LocalStrings_es.properties +++ b/java/org/apache/catalina/startup/LocalStrings_es.properties @@ -1,61 +1,61 @@ -contextConfig.applicationClose=Error durante el cierre del archivo web.xml de la aplicación -contextConfig.applicationConfig=Errror de configuración en el archivo web.xml de la aplicación -contextConfig.applicationListener=Excepción durante la creación de la clase de escucha (listener) {0} -contextConfig.applicationMissing=Falta el archivo web.xml de la aplicaciónb. Utilizando los parámetros por defecto -contextConfig.applicationParse=Error de evaluación (parse) en el archivo web.xml de la aplicación -contextConfig.applicationPosition=Se ha producido en la línea {0} columna {1} -contextConfig.authenticatorConfigured=Configuración de un autentificador (authenticator) para el método {0} -contextConfig.authenticatorInstantiate=Imposible de instanciar un autenticador (authenticator) para la clase {0} -contextConfig.authenticatorMissing=Imposible de configurar un autentificador (authenticator) para el método {0} -contextConfig.authenticatorResources=Imposible de cargar la lista de correspondencia de autenticadores (authenticators) -contextConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un Contexto -contextConfig.certificatesConfig.added=Adición de certificados -> requiere válvula de atributo (attribute Valve) -contextConfig.certificatesConfig.error=Excepción durante la adición de "CertificatesValve": -contextConfig.defaultClose=Error durante el cierre del archivo web.xml por defecto -contextConfig.defaultConfig=Error de configuración en el archivo web.xml por defecto -contextConfig.defaultMissing=Falta el archivo web.xml por defecto, utilizando sólo el archivo web.xml de la aplicación -contextConfig.defaultParse=Error de evaluación (parse) en el arcivo web.xml por defecto -contextConfig.defaultPosition=Se ha producido en la línea {0} columna {1} -contextConfig.missingRealm=Algún reino (realm) no ha sido configurado para realizar la autenticación -contextConfig.role.auth=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en -contextConfig.role.link=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en -contextConfig.role.runas=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en -contextConfig.start="ContextConfig": Tratamiento del "START" -contextConfig.stop="ContextConfig": Tratamiento del "STOP" -contextConfig.tldEntryException=Excepción durante el tratamiento de la TLD {0} en el JAR indicado por la trayectoria de recurso {1} -contextConfig.tldFileException=Excepción durante el tratamiento de la TLD indicada por la trayectoria de recurso {0} -contextConfig.tldJarException=Excepción durante el tratamiento del JAR indicado por la trayectoria de recurso {0} -contextConfig.tldResourcePath=Trayectoria de recurso TLD {0} inválida -contextConfig.unavailable=Esta aplicación está marcada como no disponible debido a los errores precedentes -embedded.alreadyStarted=El servicio embebido (embedded service) ya ha sido arrancado -embedded.noEngines=Algún motor (engine) no ha sido aún definido -embedded.notStarted=El servicio embebido (embedded service) aún no ha sido arrancado -engineConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un motor (engine) -engineConfig.start="EngineConfig": Tratamiento del "START" -engineConfig.stop="EngineConfig": Tratamiento del "STOP" -hostConfig.appBase=No existe el directorio base de la aplicación {0} -hostConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es una máquina (host) -hostConfig.deploy=Desplieque del directorio {0} de la aplicación web -hostConfig.deployDescriptor=Desplieque del descriptor de configuración {0} -hostConfig.deployDescriptor.error=Error durante el despliegue del descriptor de configuración {0} -hostConfig.deployDir=Despliegue del directorio {0} de la aplicación web -hostConfig.deployDir.error=Error durante el despliegue del directorio {0} de la aplicación web -hostConfig.deployJar=Despliegue del archivo {0} de la aplicación web -hostConfig.deployJar.error=Error durante el despliegue del archivo {0} de la aplicación web -hostConfig.deploy.error=Excepción en el directorio {0} de la aplicación web -hostConfig.deploying=Desplegando aplicaciones web descubiertas -hostConfig.expand=Descompresión del archivo {0} de la aplicación web -hostConfig.expand.error=Excepción durante la descompresión del archivo {0} de la aplicación web -hostConfig.expanding=Descubierta descompresión de archivos de aplicaciones web -hostConfig.context.restart=Error durante el arranque del contexto {0} -hostConfig.start="HostConfig": Tratamiento del "START" -hostConfig.stop="HostConfig": Tratamiento del "STOP" -hostConfig.undeploy=Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0} -hostConfig.undeploy.error=Error durante el repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0} -hostConfig.undeploying=Repliegue de las aplicaciones web desplegadas -userConfig.database=Excepción durante la carga de base de datos de usuario -userConfig.deploy=Despliegue de la aplicación web para el usuario {0} -userConfig.deploying=Desplegando aplicaciones web para el usuario -userConfig.error=Error durante el despliegue de la aplicación web para el usario {0} -userConfig.start="UserConfig": Tratamiento del "START" -userConfig.stop="UserConfig": Tratamiento del "STOP" +contextConfig.applicationClose=Error durante el cierre del archivo web.xml de la aplicación +contextConfig.applicationConfig=Errror de configuración en el archivo web.xml de la aplicación +contextConfig.applicationListener=Excepción durante la creación de la clase de escucha (listener) {0} +contextConfig.applicationMissing=Falta el archivo web.xml de la aplicaciónb. Utilizando los parámetros por defecto +contextConfig.applicationParse=Error de evaluación (parse) en el archivo web.xml de la aplicación +contextConfig.applicationPosition=Se ha producido en la línea {0} columna {1} +contextConfig.authenticatorConfigured=Configuración de un autentificador (authenticator) para el método {0} +contextConfig.authenticatorInstantiate=Imposible de instanciar un autenticador (authenticator) para la clase {0} +contextConfig.authenticatorMissing=Imposible de configurar un autentificador (authenticator) para el método {0} +contextConfig.authenticatorResources=Imposible de cargar la lista de correspondencia de autenticadores (authenticators) +contextConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un Contexto +contextConfig.certificatesConfig.added=Adición de certificados -> requiere válvula de atributo (attribute Valve) +contextConfig.certificatesConfig.error=Excepción durante la adición de "CertificatesValve": +contextConfig.defaultClose=Error durante el cierre del archivo web.xml por defecto +contextConfig.defaultConfig=Error de configuración en el archivo web.xml por defecto +contextConfig.defaultMissing=Falta el archivo web.xml por defecto, utilizando sólo el archivo web.xml de la aplicación +contextConfig.defaultParse=Error de evaluación (parse) en el arcivo web.xml por defecto +contextConfig.defaultPosition=Se ha producido en la línea {0} columna {1} +contextConfig.missingRealm=Algún reino (realm) no ha sido configurado para realizar la autenticación +contextConfig.role.auth=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en +contextConfig.role.link=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en +contextConfig.role.runas=ATENCIÓN: El nombre de papel de seguridad {0} es usado en un sin haber sido definido en +contextConfig.start="ContextConfig": Tratamiento del "START" +contextConfig.stop="ContextConfig": Tratamiento del "STOP" +contextConfig.tldEntryException=Excepción durante el tratamiento de la TLD {0} en el JAR indicado por la trayectoria de recurso {1} +contextConfig.tldFileException=Excepción durante el tratamiento de la TLD indicada por la trayectoria de recurso {0} +contextConfig.tldJarException=Excepción durante el tratamiento del JAR indicado por la trayectoria de recurso {0} +contextConfig.tldResourcePath=Trayectoria de recurso TLD {0} inválida +contextConfig.unavailable=Esta aplicación está marcada como no disponible debido a los errores precedentes +embedded.alreadyStarted=El servicio embebido (embedded service) ya ha sido arrancado +embedded.noEngines=Algún motor (engine) no ha sido aún definido +embedded.notStarted=El servicio embebido (embedded service) aún no ha sido arrancado +engineConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es un motor (engine) +engineConfig.start="EngineConfig": Tratamiento del "START" +engineConfig.stop="EngineConfig": Tratamiento del "STOP" +hostConfig.appBase=No existe el directorio base de la aplicación {0} +hostConfig.cce=El objeto de los datos de evento de ciclo de vida (Lifecycle event data object) {0} no es una máquina (host) +hostConfig.deploy=Desplieque del directorio {0} de la aplicación web +hostConfig.deployDescriptor=Desplieque del descriptor de configuración {0} +hostConfig.deployDescriptor.error=Error durante el despliegue del descriptor de configuración {0} +hostConfig.deployDir=Despliegue del directorio {0} de la aplicación web +hostConfig.deployDir.error=Error durante el despliegue del directorio {0} de la aplicación web +hostConfig.deployJar=Despliegue del archivo {0} de la aplicación web +hostConfig.deployJar.error=Error durante el despliegue del archivo {0} de la aplicación web +hostConfig.deploy.error=Excepción en el directorio {0} de la aplicación web +hostConfig.deploying=Desplegando aplicaciones web descubiertas +hostConfig.expand=Descompresión del archivo {0} de la aplicación web +hostConfig.expand.error=Excepción durante la descompresión del archivo {0} de la aplicación web +hostConfig.expanding=Descubierta descompresión de archivos de aplicaciones web +hostConfig.context.restart=Error durante el arranque del contexto {0} +hostConfig.start="HostConfig": Tratamiento del "START" +hostConfig.stop="HostConfig": Tratamiento del "STOP" +hostConfig.undeploy=Repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0} +hostConfig.undeploy.error=Error durante el repliegue (undeploy) de la aplicación web que tiene como trayectoria de contexto {0} +hostConfig.undeploying=Repliegue de las aplicaciones web desplegadas +userConfig.database=Excepción durante la carga de base de datos de usuario +userConfig.deploy=Despliegue de la aplicación web para el usuario {0} +userConfig.deploying=Desplegando aplicaciones web para el usuario +userConfig.error=Error durante el despliegue de la aplicación web para el usario {0} +userConfig.start="UserConfig": Tratamiento del "START" +userConfig.stop="UserConfig": Tratamiento del "STOP" diff --git a/java/org/apache/catalina/startup/LocalStrings_fr.properties b/java/org/apache/catalina/startup/LocalStrings_fr.properties index b7050b331..4f51967ff 100644 --- a/java/org/apache/catalina/startup/LocalStrings_fr.properties +++ b/java/org/apache/catalina/startup/LocalStrings_fr.properties @@ -1,59 +1,59 @@ -contextConfig.applicationClose=Erreur lors de la fermeture du fichier web.xml de l''application -contextConfig.applicationConfig=Erreur de configuration dans le fichier web.xml de l''application -contextConfig.applicationListener=Exception lors de la création de la classe d''écoute (listener) {0} -contextConfig.applicationMissing=Le fichier web.xml de l''application est absent, utilisation des paramêtres par défaut -contextConfig.applicationParse=Erreur d''évaluation (parse) dans le fichier web.xml de l''application -contextConfig.applicationPosition=S''est produite à la ligne {0} colonne {1} -contextConfig.authenticatorConfigured=Configuration d''un authentificateur (authenticator) pour la méthode {0} -contextConfig.authenticatorInstantiate=Impossible d''instancier un authentificateur (authenticator) pour la classe {0} -contextConfig.authenticatorMissing=Impossible de configurer un authentificateur (authenticator) pour la méthode {0} -contextConfig.authenticatorResources=Impossible de charger la liste de correspondance des authentificateur (authenticators) -contextConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un Contexte -contextConfig.certificatesConfig.added=Ajout de certificats -> requête Attribut de Valve (attribute Valve) -contextConfig.certificatesConfig.error=Exception lors de l''ajout des "CertificatesValve": -contextConfig.defaultClose=Erreur lors de la fermeture du fichier web.xml par défaut -contextConfig.defaultConfig=Erreur de configuration dans le fichier web.xml par défaut -contextConfig.defaultMissing=Le fichier web.xml par défaut est absent, utilisation du fichier web.xml de l''application web.xml seulement -contextConfig.defaultParse=Erreur d''évaluation (parse) dans le fichier web.xml par défaut -contextConfig.defaultPosition=S''est produite à la ligne {0} colonne {1} -contextConfig.missingRealm=Aucun royaume (realm) n''a été configuré pour réaliser l''authentification -contextConfig.role.auth=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans -contextConfig.role.link=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans -contextConfig.role.runas=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans -contextConfig.start="ContextConfig": Traitement du "START" -contextConfig.stop="ContextConfig": Traitement du "STOP" -contextConfig.tldEntryException=Exception lors du traitement de la TLD {0} dans le JAR indiqué par le chemin de ressource {1} -contextConfig.tldFileException=Exception lors du traitement de la TLD indiqué par le chemin de ressource {0} -contextConfig.tldJarException=Exception lors du traitement du JAR indiqué par le chemin de ressource {0} -contextConfig.tldResourcePath=Chemin de ressource TLD {0} invalide -contextConfig.unavailable=Cette application est marquée comme non disponible suite aux erreurs précédentes -embedded.alreadyStarted=Le service enfoui (embedded service) a déjà été démarré -embedded.noEngines=Aucun moteur (engine) n''a encore été défini -embedded.notStarted=Le service enfoui (embedded service) n''a pas encore été démarré -engineConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un moteur (engine) -engineConfig.start="EngineConfig": Traitement du "START" -engineConfig.stop="EngineConfig": Traitement du "STOP" -hostConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un hôte -hostConfig.deploy=Déploiement du répertoire {0} de l''application web -hostConfig.deployDescriptor=Déploiement du descripteur de configuration {0} -hostConfig.deployDescriptor.error=Erreur lors du déploiement du descripteur de configuration {0} -hostConfig.deployDir=Déploiement du répertoire {0} de l''application web -hostConfig.deployDir.error=Erreur lors du déploiement du répertoire {0} de l''application web -hostConfig.deployJar=Déploiement de l''archive {0} de l''application web -hostConfig.deployJar.error=Erreur lors du déploiement de l''archive {0} de l''application web -hostConfig.deploy.error=Exception lors du répertoire {0} de l''application web -hostConfig.deploying=Déploiement des applications web découvertes (discovered) -hostConfig.expand=Décompression de l''archive {0} de l''application web -hostConfig.expand.error=Exception lors de la décompression de l''archive {0} de l''application web -hostConfig.expanding=Décompression des archives des applications web découvertes (discovered) -hostConfig.start="HostConfig": Traitement du "START" -hostConfig.stop="HostConfig": Traitement du "STOP" -hostConfig.undeploy=Repli (undeploy) de l''application web ayant pour chemin de contexte {0} -hostConfig.undeploy.error=Erreur lors du repli (undeploy) de l''application web ayant pour chemin de contexte {0} -hostConfig.undeploying=Repli des applications web déployées -userConfig.database=Exception lors du chargement de la base de données utilisateur -userConfig.deploy=Déploiement de l''application web pour l''utilisateur {0} -userConfig.deploying=Déploiement des applications web utilisateur -userConfig.error=Erreur lors du déploiement de l''application web pour l''utilisateur {0} -userConfig.start="UserConfig": Traitement du "START" -userConfig.stop="UserConfig": Traitement du "STOP" +contextConfig.applicationClose=Erreur lors de la fermeture du fichier web.xml de l''application +contextConfig.applicationConfig=Erreur de configuration dans le fichier web.xml de l''application +contextConfig.applicationListener=Exception lors de la création de la classe d''écoute (listener) {0} +contextConfig.applicationMissing=Le fichier web.xml de l''application est absent, utilisation des paramêtres par défaut +contextConfig.applicationParse=Erreur d''évaluation (parse) dans le fichier web.xml de l''application +contextConfig.applicationPosition=S''est produite à la ligne {0} colonne {1} +contextConfig.authenticatorConfigured=Configuration d''un authentificateur (authenticator) pour la méthode {0} +contextConfig.authenticatorInstantiate=Impossible d''instancier un authentificateur (authenticator) pour la classe {0} +contextConfig.authenticatorMissing=Impossible de configurer un authentificateur (authenticator) pour la méthode {0} +contextConfig.authenticatorResources=Impossible de charger la liste de correspondance des authentificateur (authenticators) +contextConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un Contexte +contextConfig.certificatesConfig.added=Ajout de certificats -> requête Attribut de Valve (attribute Valve) +contextConfig.certificatesConfig.error=Exception lors de l''ajout des "CertificatesValve": +contextConfig.defaultClose=Erreur lors de la fermeture du fichier web.xml par défaut +contextConfig.defaultConfig=Erreur de configuration dans le fichier web.xml par défaut +contextConfig.defaultMissing=Le fichier web.xml par défaut est absent, utilisation du fichier web.xml de l''application web.xml seulement +contextConfig.defaultParse=Erreur d''évaluation (parse) dans le fichier web.xml par défaut +contextConfig.defaultPosition=S''est produite à la ligne {0} colonne {1} +contextConfig.missingRealm=Aucun royaume (realm) n''a été configuré pour réaliser l''authentification +contextConfig.role.auth=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans +contextConfig.role.link=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans +contextConfig.role.runas=ATTENTION: Le nom de rôle de sécurité {0} est utilisé dans un sans avoir été défini dans +contextConfig.start="ContextConfig": Traitement du "START" +contextConfig.stop="ContextConfig": Traitement du "STOP" +contextConfig.tldEntryException=Exception lors du traitement de la TLD {0} dans le JAR indiqué par le chemin de ressource {1} +contextConfig.tldFileException=Exception lors du traitement de la TLD indiqué par le chemin de ressource {0} +contextConfig.tldJarException=Exception lors du traitement du JAR indiqué par le chemin de ressource {0} +contextConfig.tldResourcePath=Chemin de ressource TLD {0} invalide +contextConfig.unavailable=Cette application est marquée comme non disponible suite aux erreurs précédentes +embedded.alreadyStarted=Le service enfoui (embedded service) a déjà été démarré +embedded.noEngines=Aucun moteur (engine) n''a encore été défini +embedded.notStarted=Le service enfoui (embedded service) n''a pas encore été démarré +engineConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un moteur (engine) +engineConfig.start="EngineConfig": Traitement du "START" +engineConfig.stop="EngineConfig": Traitement du "STOP" +hostConfig.cce=L''objet donnée évènement cycle de vie (Lifecycle event data object) {0} n''est pas un hôte +hostConfig.deploy=Déploiement du répertoire {0} de l''application web +hostConfig.deployDescriptor=Déploiement du descripteur de configuration {0} +hostConfig.deployDescriptor.error=Erreur lors du déploiement du descripteur de configuration {0} +hostConfig.deployDir=Déploiement du répertoire {0} de l''application web +hostConfig.deployDir.error=Erreur lors du déploiement du répertoire {0} de l''application web +hostConfig.deployJar=Déploiement de l''archive {0} de l''application web +hostConfig.deployJar.error=Erreur lors du déploiement de l''archive {0} de l''application web +hostConfig.deploy.error=Exception lors du répertoire {0} de l''application web +hostConfig.deploying=Déploiement des applications web découvertes (discovered) +hostConfig.expand=Décompression de l''archive {0} de l''application web +hostConfig.expand.error=Exception lors de la décompression de l''archive {0} de l''application web +hostConfig.expanding=Décompression des archives des applications web découvertes (discovered) +hostConfig.start="HostConfig": Traitement du "START" +hostConfig.stop="HostConfig": Traitement du "STOP" +hostConfig.undeploy=Repli (undeploy) de l''application web ayant pour chemin de contexte {0} +hostConfig.undeploy.error=Erreur lors du repli (undeploy) de l''application web ayant pour chemin de contexte {0} +hostConfig.undeploying=Repli des applications web déployées +userConfig.database=Exception lors du chargement de la base de données utilisateur +userConfig.deploy=Déploiement de l''application web pour l''utilisateur {0} +userConfig.deploying=Déploiement des applications web utilisateur +userConfig.error=Erreur lors du déploiement de l''application web pour l''utilisateur {0} +userConfig.start="UserConfig": Traitement du "START" +userConfig.stop="UserConfig": Traitement du "STOP" diff --git a/java/org/apache/catalina/startup/LocalStrings_ja.properties b/java/org/apache/catalina/startup/LocalStrings_ja.properties index 53d4ef71d..84951571a 100644 --- a/java/org/apache/catalina/startup/LocalStrings_ja.properties +++ b/java/org/apache/catalina/startup/LocalStrings_ja.properties @@ -1,64 +1,64 @@ -contextConfig.applicationClose=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -contextConfig.applicationConfig=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 -contextConfig.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u3092\u4f5c\u6210\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -contextConfig.applicationMissing=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059 -contextConfig.applicationParse=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 -contextConfig.applicationPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f -contextConfig.authenticatorConfigured=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3057\u307e\u3059 -contextConfig.authenticatorInstantiate=\u30af\u30e9\u30b9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u3067\u304d\u307e\u305b\u3093 -contextConfig.authenticatorMissing=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 -contextConfig.authenticatorResources=\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u306e\u30de\u30c3\u30d7\u30ea\u30b9\u30c8\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -contextConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -contextConfig.certificatesConfig.added=\u8a3c\u660e\u66f8\u3092\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u5c5e\u6027\u5024\u306b\u8ffd\u52a0\u3057\u307e\u3059 -contextConfig.certificatesConfig.error=CertificatesValve\u3092\u8ffd\u52a0\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: -contextConfig.defaultClose=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u30af\u30ed\u30fc\u30ba\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -contextConfig.defaultConfig=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u4e2d\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 -contextConfig.defaultMissing=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059 -contextConfig.defaultParse=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 -contextConfig.defaultPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f -contextConfig.missingRealm=\u8a8d\u8a3c\u3059\u308b\u305f\u3081\u306b\u30ec\u30eb\u30e0\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -contextConfig.role.auth=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f -contextConfig.role.link=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f -contextConfig.role.runas=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f -contextConfig.start=ContextConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 -contextConfig.stop=ContextConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 -contextConfig.tldEntryException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {1} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u306eTLD {0} \u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -contextConfig.tldFileException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eTLD\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -contextConfig.tldJarException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -contextConfig.tldResourcePath=\u7121\u52b9\u306aTLD\u306e\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} -contextConfig.unavailable=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u5229\u7528\u3067\u304d\u306a\u3044\u3088\u3046\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 -embedded.alreadyStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -embedded.noEngines=\u307e\u3060\u30a8\u30f3\u30b8\u30f3\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -embedded.notStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -engineConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30a8\u30f3\u30b8\u30f3\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -engineConfig.start=EngineConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 -engineConfig.stop=EngineConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 -hostConfig.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 -hostConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30db\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -hostConfig.deploy=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 -hostConfig.deployDescriptor=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u3057\u307e\u3059 -hostConfig.deployDescriptor.error=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -hostConfig.deployDir=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 -hostConfig.deployDir.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -hostConfig.deployJar=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u3057\u307e\u3059 -hostConfig.deployJar.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -hostConfig.deploy.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -hostConfig.deploying=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 -hostConfig.expand=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u3057\u307e\u3059 -hostConfig.expand.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -hostConfig.expanding=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u3092\u5c55\u958b\u3057\u307e\u3059 -hostConfig.context.restart=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u3092\u518d\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -hostConfig.removeXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f -hostConfig.removeDIR=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f -hostConfig.removeWAR=WAR\u30d5\u30a1\u30a4\u30eb {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f -hostConfig.start=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 -hostConfig.stop=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 -hostConfig.undeploy=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3059 -hostConfig.undeploy.error=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -hostConfig.undeploying=\u914d\u5099\u3055\u308c\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u3066\u3044\u307e\u3059 -userConfig.database=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -userConfig.deploy=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 -userConfig.deploying=\u30e6\u30fc\u30b6\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 -userConfig.error=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -userConfig.start=UserConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 -userConfig.stop=UserConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 +contextConfig.applicationClose=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +contextConfig.applicationConfig=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 +contextConfig.applicationListener=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u3092\u4f5c\u6210\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +contextConfig.applicationMissing=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30c7\u30d5\u30a9\u30eb\u30c8\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059 +contextConfig.applicationParse=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 +contextConfig.applicationPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f +contextConfig.authenticatorConfigured=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3057\u307e\u3059 +contextConfig.authenticatorInstantiate=\u30af\u30e9\u30b9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u3067\u304d\u307e\u305b\u3093 +contextConfig.authenticatorMissing=\u30e1\u30bd\u30c3\u30c9 {0} \u306e\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u3092\u8a2d\u5b9a\u3067\u304d\u307e\u305b\u3093 +contextConfig.authenticatorResources=\u30aa\u30fc\u30bb\u30f3\u30c6\u30a3\u30b1\u30fc\u30bf\u306e\u30de\u30c3\u30d7\u30ea\u30b9\u30c8\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +contextConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +contextConfig.certificatesConfig.added=\u8a3c\u660e\u66f8\u3092\u30ea\u30af\u30a8\u30b9\u30c8\u306e\u5c5e\u6027\u5024\u306b\u8ffd\u52a0\u3057\u307e\u3059 +contextConfig.certificatesConfig.error=CertificatesValve\u3092\u8ffd\u52a0\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f: +contextConfig.defaultClose=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u30af\u30ed\u30fc\u30ba\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +contextConfig.defaultConfig=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u306e\u4e2d\u306e\u8a2d\u5b9a\u30a8\u30e9\u30fc\u3067\u3059 +contextConfig.defaultMissing=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3001\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306eweb.xml\u3060\u3051\u3092\u4f7f\u7528\u3057\u307e\u3059 +contextConfig.defaultParse=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eweb.xml\u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 +contextConfig.defaultPosition={0}\u884c\u306e{1}\u5217\u76ee\u3067\u767a\u751f\u3057\u307e\u3057\u305f +contextConfig.missingRealm=\u8a8d\u8a3c\u3059\u308b\u305f\u3081\u306b\u30ec\u30eb\u30e0\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +contextConfig.role.auth=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f +contextConfig.role.link=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f +contextConfig.role.runas=\u8b66\u544a: \u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u306a\u3044\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u30ed\u30fc\u30eb\u540d {0} \u304c\u306e\u4e2d\u3067\u4f7f\u7528\u3055\u308c\u307e\u3057\u305f +contextConfig.start=ContextConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 +contextConfig.stop=ContextConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 +contextConfig.tldEntryException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {1} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u306eTLD {0} \u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +contextConfig.tldFileException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eTLD\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +contextConfig.tldJarException=\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} \u306eJAR\u30d5\u30a1\u30a4\u30eb\u3092\u51e6\u7406\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +contextConfig.tldResourcePath=\u7121\u52b9\u306aTLD\u306e\u30ea\u30bd\u30fc\u30b9\u30d1\u30b9 {0} +contextConfig.unavailable=\u524d\u306e\u30a8\u30e9\u30fc\u306e\u305f\u3081\u306b\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306f\u5229\u7528\u3067\u304d\u306a\u3044\u3088\u3046\u306b\u30de\u30fc\u30af\u3057\u307e\u3059 +embedded.alreadyStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +embedded.noEngines=\u307e\u3060\u30a8\u30f3\u30b8\u30f3\u304c\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +embedded.notStarted=\u7d44\u307f\u8fbc\u307f\u30b5\u30fc\u30d3\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +engineConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30a8\u30f3\u30b8\u30f3\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +engineConfig.start=EngineConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 +engineConfig.stop=EngineConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 +hostConfig.appBase=\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30d9\u30fc\u30b9\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 +hostConfig.cce=\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u30c7\u30fc\u30bf\u30aa\u30d6\u30b8\u30a7\u30af\u30c8 {0} \u306f\u30db\u30b9\u30c8\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +hostConfig.deploy=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 +hostConfig.deployDescriptor=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u3057\u307e\u3059 +hostConfig.deployDescriptor.error=\u8a2d\u5b9a\u8a18\u8ff0\u5b50 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +hostConfig.deployDir=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u3057\u307e\u3059 +hostConfig.deployDir.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +hostConfig.deployJar=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u3057\u307e\u3059 +hostConfig.deployJar.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +hostConfig.deploy.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u3092\u914d\u5099\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +hostConfig.deploying=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 +hostConfig.expand=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u3057\u307e\u3059 +hostConfig.expand.error=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6 {0} \u3092\u5c55\u958b\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +hostConfig.expanding=\u898b\u3064\u304b\u3063\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30a2\u30fc\u30ab\u30a4\u30d6\u3092\u5c55\u958b\u3057\u307e\u3059 +hostConfig.context.restart=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u3092\u518d\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +hostConfig.removeXML=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8 {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f +hostConfig.removeDIR=\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f +hostConfig.removeWAR=WAR\u30d5\u30a1\u30a4\u30eb {0} \u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3057\u305f +hostConfig.start=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 +hostConfig.stop=HostConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 +hostConfig.undeploy=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u307e\u3059 +hostConfig.undeploy.error=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u30d1\u30b9 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +hostConfig.undeploying=\u914d\u5099\u3055\u308c\u305fWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u306e\u914d\u5099\u3092\u89e3\u9664\u3057\u3066\u3044\u307e\u3059 +userConfig.database=\u30e6\u30fc\u30b6\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u306e\u30ed\u30fc\u30c9\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +userConfig.deploy=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 +userConfig.deploying=\u30e6\u30fc\u30b6\u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u307e\u3059 +userConfig.error=\u30e6\u30fc\u30b6 {0} \u306eWeb\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +userConfig.start=UserConfig: \u51e6\u7406\u3092\u958b\u59cb\u3057\u307e\u3059 +userConfig.stop=UserConfig: \u51e6\u7406\u3092\u505c\u6b62\u3057\u307e\u3059 diff --git a/java/org/apache/catalina/startup/NamingRuleSet.java b/java/org/apache/catalina/startup/NamingRuleSet.java index 67145e4c1..c0eb70a43 100644 --- a/java/org/apache/catalina/startup/NamingRuleSet.java +++ b/java/org/apache/catalina/startup/NamingRuleSet.java @@ -1,135 +1,135 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.RuleSetBase; - - -/** - *

        RuleSet for processing the JNDI Enterprise Naming - * Context resource declaration elements.

        - * - * @author Craig R. McClanahan - * @author Remy Maucherat - * @version $Revision: 303177 $ $Date: 2004-09-02 12:05:00 +0200 (jeu., 02 sept. 2004) $ - */ - -public class NamingRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public NamingRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public NamingRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - digester.addObjectCreate(prefix + "Ejb", - "org.apache.catalina.deploy.ContextEjb"); - digester.addRule(prefix + "Ejb", new SetAllPropertiesRule()); - digester.addRule(prefix + "Ejb", - new SetNextNamingRule("addEjb", - "org.apache.catalina.deploy.ContextEjb")); - - digester.addObjectCreate(prefix + "Environment", - "org.apache.catalina.deploy.ContextEnvironment"); - digester.addSetProperties(prefix + "Environment"); - digester.addRule(prefix + "Environment", - new SetNextNamingRule("addEnvironment", - "org.apache.catalina.deploy.ContextEnvironment")); - - digester.addObjectCreate(prefix + "LocalEjb", - "org.apache.catalina.deploy.ContextLocalEjb"); - digester.addRule(prefix + "LocalEjb", new SetAllPropertiesRule()); - digester.addRule(prefix + "LocalEjb", - new SetNextNamingRule("addLocalEjb", - "org.apache.catalina.deploy.ContextLocalEjb")); - - digester.addObjectCreate(prefix + "Resource", - "org.apache.catalina.deploy.ContextResource"); - digester.addRule(prefix + "Resource", new SetAllPropertiesRule()); - digester.addRule(prefix + "Resource", - new SetNextNamingRule("addResource", - "org.apache.catalina.deploy.ContextResource")); - - digester.addObjectCreate(prefix + "ResourceEnvRef", - "org.apache.catalina.deploy.ContextResourceEnvRef"); - digester.addRule(prefix + "ResourceEnvRef", new SetAllPropertiesRule()); - digester.addRule(prefix + "ResourceEnvRef", - new SetNextNamingRule("addResourceEnvRef", - "org.apache.catalina.deploy.ContextResourceEnvRef")); - - digester.addObjectCreate(prefix + "Transaction", - "org.apache.catalina.deploy.ContextTransaction"); - digester.addRule(prefix + "Transaction", new SetAllPropertiesRule()); - digester.addRule(prefix + "Transaction", - new SetNextNamingRule("setTransaction", - "org.apache.catalina.deploy.ContextTransaction")); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSetBase; + + +/** + *

        RuleSet for processing the JNDI Enterprise Naming + * Context resource declaration elements.

        + * + * @author Craig R. McClanahan + * @author Remy Maucherat + * @version $Revision: 303177 $ $Date: 2004-09-02 12:05:00 +0200 (jeu., 02 sept. 2004) $ + */ + +public class NamingRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public NamingRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public NamingRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + digester.addObjectCreate(prefix + "Ejb", + "org.apache.catalina.deploy.ContextEjb"); + digester.addRule(prefix + "Ejb", new SetAllPropertiesRule()); + digester.addRule(prefix + "Ejb", + new SetNextNamingRule("addEjb", + "org.apache.catalina.deploy.ContextEjb")); + + digester.addObjectCreate(prefix + "Environment", + "org.apache.catalina.deploy.ContextEnvironment"); + digester.addSetProperties(prefix + "Environment"); + digester.addRule(prefix + "Environment", + new SetNextNamingRule("addEnvironment", + "org.apache.catalina.deploy.ContextEnvironment")); + + digester.addObjectCreate(prefix + "LocalEjb", + "org.apache.catalina.deploy.ContextLocalEjb"); + digester.addRule(prefix + "LocalEjb", new SetAllPropertiesRule()); + digester.addRule(prefix + "LocalEjb", + new SetNextNamingRule("addLocalEjb", + "org.apache.catalina.deploy.ContextLocalEjb")); + + digester.addObjectCreate(prefix + "Resource", + "org.apache.catalina.deploy.ContextResource"); + digester.addRule(prefix + "Resource", new SetAllPropertiesRule()); + digester.addRule(prefix + "Resource", + new SetNextNamingRule("addResource", + "org.apache.catalina.deploy.ContextResource")); + + digester.addObjectCreate(prefix + "ResourceEnvRef", + "org.apache.catalina.deploy.ContextResourceEnvRef"); + digester.addRule(prefix + "ResourceEnvRef", new SetAllPropertiesRule()); + digester.addRule(prefix + "ResourceEnvRef", + new SetNextNamingRule("addResourceEnvRef", + "org.apache.catalina.deploy.ContextResourceEnvRef")); + + digester.addObjectCreate(prefix + "Transaction", + "org.apache.catalina.deploy.ContextTransaction"); + digester.addRule(prefix + "Transaction", new SetAllPropertiesRule()); + digester.addRule(prefix + "Transaction", + new SetNextNamingRule("setTransaction", + "org.apache.catalina.deploy.ContextTransaction")); + + } + + +} diff --git a/java/org/apache/catalina/startup/PasswdUserDatabase.java b/java/org/apache/catalina/startup/PasswdUserDatabase.java index 4d8b3b89a..4d96e8493 100644 --- a/java/org/apache/catalina/startup/PasswdUserDatabase.java +++ b/java/org/apache/catalina/startup/PasswdUserDatabase.java @@ -1,193 +1,193 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.BufferedReader; -import java.io.FileReader; -import java.io.IOException; -import java.util.Hashtable; -import java.util.Enumeration; - - -/** - * Concrete implementation of the UserDatabase interface - * that processes the /etc/passwd file on a Unix system. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class PasswdUserDatabase - implements UserDatabase { - - - // --------------------------------------------------------- Constructors - - - /** - * Initialize a new instance of this user database component. - */ - public PasswdUserDatabase() { - - super(); - - } - - - // --------------------------------------------------- Instance Variables - - - /** - * The pathname of the Unix password file. - */ - private static final String PASSWORD_FILE = "/etc/passwd"; - - - /** - * The set of home directories for all defined users, keyed by username. - */ - private Hashtable homes = new Hashtable(); - - - /** - * The UserConfig listener with which we are associated. - */ - private UserConfig userConfig = null; - - - // ----------------------------------------------------------- Properties - - - /** - * Return the UserConfig listener with which we are associated. - */ - public UserConfig getUserConfig() { - - return (this.userConfig); - - } - - - /** - * Set the UserConfig listener with which we are associated. - * - * @param userConfig The new UserConfig listener - */ - public void setUserConfig(UserConfig userConfig) { - - this.userConfig = userConfig; - init(); - - } - - - // ------------------------------------------------------- Public Methods - - - /** - * Return an absolute pathname to the home directory for the specified user. - * - * @param user User for which a home directory should be retrieved - */ - public String getHome(String user) { - - return ((String) homes.get(user)); - - } - - - /** - * Return an enumeration of the usernames defined on this server. - */ - public Enumeration getUsers() { - - return (homes.keys()); - - } - - - // ------------------------------------------------------ Private Methods - - - /** - * Initialize our set of users and home directories. - */ - private void init() { - - BufferedReader reader = null; - try { - - reader = new BufferedReader(new FileReader(PASSWORD_FILE)); - - while (true) { - - // Accumulate the next line - StringBuffer buffer = new StringBuffer(); - while (true) { - int ch = reader.read(); - if ((ch < 0) || (ch == '\n')) - break; - buffer.append((char) ch); - } - String line = buffer.toString(); - if (line.length() < 1) - break; - - // Parse the line into constituent elements - int n = 0; - String tokens[] = new String[7]; - for (int i = 0; i < tokens.length; i++) - tokens[i] = null; - while (n < tokens.length) { - String token = null; - int colon = line.indexOf(':'); - if (colon >= 0) { - token = line.substring(0, colon); - line = line.substring(colon + 1); - } else { - token = line; - line = ""; - } - tokens[n++] = token; - } - - // Add this user and corresponding directory - if ((tokens[0] != null) && (tokens[5] != null)) - homes.put(tokens[0], tokens[5]); - - } - - reader.close(); - reader = null; - - } catch (Exception e) { - if (reader != null) { - try { - reader.close(); - } catch (IOException f) { - ; - } - reader = null; - } - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Enumeration; + + +/** + * Concrete implementation of the UserDatabase interface + * that processes the /etc/passwd file on a Unix system. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class PasswdUserDatabase + implements UserDatabase { + + + // --------------------------------------------------------- Constructors + + + /** + * Initialize a new instance of this user database component. + */ + public PasswdUserDatabase() { + + super(); + + } + + + // --------------------------------------------------- Instance Variables + + + /** + * The pathname of the Unix password file. + */ + private static final String PASSWORD_FILE = "/etc/passwd"; + + + /** + * The set of home directories for all defined users, keyed by username. + */ + private Hashtable homes = new Hashtable(); + + + /** + * The UserConfig listener with which we are associated. + */ + private UserConfig userConfig = null; + + + // ----------------------------------------------------------- Properties + + + /** + * Return the UserConfig listener with which we are associated. + */ + public UserConfig getUserConfig() { + + return (this.userConfig); + + } + + + /** + * Set the UserConfig listener with which we are associated. + * + * @param userConfig The new UserConfig listener + */ + public void setUserConfig(UserConfig userConfig) { + + this.userConfig = userConfig; + init(); + + } + + + // ------------------------------------------------------- Public Methods + + + /** + * Return an absolute pathname to the home directory for the specified user. + * + * @param user User for which a home directory should be retrieved + */ + public String getHome(String user) { + + return ((String) homes.get(user)); + + } + + + /** + * Return an enumeration of the usernames defined on this server. + */ + public Enumeration getUsers() { + + return (homes.keys()); + + } + + + // ------------------------------------------------------ Private Methods + + + /** + * Initialize our set of users and home directories. + */ + private void init() { + + BufferedReader reader = null; + try { + + reader = new BufferedReader(new FileReader(PASSWORD_FILE)); + + while (true) { + + // Accumulate the next line + StringBuffer buffer = new StringBuffer(); + while (true) { + int ch = reader.read(); + if ((ch < 0) || (ch == '\n')) + break; + buffer.append((char) ch); + } + String line = buffer.toString(); + if (line.length() < 1) + break; + + // Parse the line into constituent elements + int n = 0; + String tokens[] = new String[7]; + for (int i = 0; i < tokens.length; i++) + tokens[i] = null; + while (n < tokens.length) { + String token = null; + int colon = line.indexOf(':'); + if (colon >= 0) { + token = line.substring(0, colon); + line = line.substring(colon + 1); + } else { + token = line; + line = ""; + } + tokens[n++] = token; + } + + // Add this user and corresponding directory + if ((tokens[0] != null) && (tokens[5] != null)) + homes.put(tokens[0], tokens[5]); + + } + + reader.close(); + reader = null; + + } catch (Exception e) { + if (reader != null) { + try { + reader.close(); + } catch (IOException f) { + ; + } + reader = null; + } + } + + } + + +} diff --git a/java/org/apache/catalina/startup/SetAllPropertiesRule.java b/java/org/apache/catalina/startup/SetAllPropertiesRule.java index 7b15278ea..a9a6492f7 100644 --- a/java/org/apache/catalina/startup/SetAllPropertiesRule.java +++ b/java/org/apache/catalina/startup/SetAllPropertiesRule.java @@ -1,64 +1,64 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import org.xml.sax.Attributes; - -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.digester.Rule; - -/** - * Rule that uses the introspection utils to set properties. - * - * @author Remy Maucherat - */ -public class SetAllPropertiesRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - /** - * Handle the beginning of an XML element. - * - * @param attributes The attributes of this element - * - * @exception Exception if a processing error occurs - */ - public void begin(String namespace, String nameX, Attributes attributes) - throws Exception { - - for (int i = 0; i < attributes.getLength(); i++) { - String name = attributes.getLocalName(i); - if ("".equals(name)) { - name = attributes.getQName(i); - } - String value = attributes.getValue(i); - IntrospectionUtils.setProperty(digester.peek(), name, value); - } - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import org.xml.sax.Attributes; + +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.digester.Rule; + +/** + * Rule that uses the introspection utils to set properties. + * + * @author Remy Maucherat + */ +public class SetAllPropertiesRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + /** + * Handle the beginning of an XML element. + * + * @param attributes The attributes of this element + * + * @exception Exception if a processing error occurs + */ + public void begin(String namespace, String nameX, Attributes attributes) + throws Exception { + + for (int i = 0; i < attributes.getLength(); i++) { + String name = attributes.getLocalName(i); + if ("".equals(name)) { + name = attributes.getQName(i); + } + String value = attributes.getValue(i); + IntrospectionUtils.setProperty(digester.peek(), name, value); + } + + } + + +} diff --git a/java/org/apache/catalina/startup/SetContextPropertiesRule.java b/java/org/apache/catalina/startup/SetContextPropertiesRule.java index 70f212266..2216565e8 100644 --- a/java/org/apache/catalina/startup/SetContextPropertiesRule.java +++ b/java/org/apache/catalina/startup/SetContextPropertiesRule.java @@ -1,68 +1,68 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import org.xml.sax.Attributes; - -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.digester.Rule; - -/** - * Rule that uses the introspection utils to set properties of a context - * (everything except "path"). - * - * @author Remy Maucherat - */ -public class SetContextPropertiesRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - /** - * Handle the beginning of an XML element. - * - * @param attributes The attributes of this element - * - * @exception Exception if a processing error occurs - */ - public void begin(String namespace, String nameX, Attributes attributes) - throws Exception { - - for (int i = 0; i < attributes.getLength(); i++) { - String name = attributes.getLocalName(i); - if ("".equals(name)) { - name = attributes.getQName(i); - } - if ("path".equals(name) || "docBase".equals(name)) { - continue; - } - String value = attributes.getValue(i); - IntrospectionUtils.setProperty(digester.peek(), name, value); - } - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import org.xml.sax.Attributes; + +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.digester.Rule; + +/** + * Rule that uses the introspection utils to set properties of a context + * (everything except "path"). + * + * @author Remy Maucherat + */ +public class SetContextPropertiesRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + /** + * Handle the beginning of an XML element. + * + * @param attributes The attributes of this element + * + * @exception Exception if a processing error occurs + */ + public void begin(String namespace, String nameX, Attributes attributes) + throws Exception { + + for (int i = 0; i < attributes.getLength(); i++) { + String name = attributes.getLocalName(i); + if ("".equals(name)) { + name = attributes.getQName(i); + } + if ("path".equals(name) || "docBase".equals(name)) { + continue; + } + String value = attributes.getValue(i); + IntrospectionUtils.setProperty(digester.peek(), name, value); + } + + } + + +} diff --git a/java/org/apache/catalina/startup/SetNextNamingRule.java b/java/org/apache/catalina/startup/SetNextNamingRule.java index 6f401132b..c73782ede 100644 --- a/java/org/apache/catalina/startup/SetNextNamingRule.java +++ b/java/org/apache/catalina/startup/SetNextNamingRule.java @@ -1,119 +1,119 @@ -/* $Id: SetNextNamingRule.java 303133 2004-08-29 16:46:15Z yoavs $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - -import org.apache.catalina.Context; -import org.apache.catalina.deploy.NamingResources; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.digester.Rule; - - -/** - *

        Rule implementation that calls a method on the (top-1) (parent) - * object, passing the top object (child) as an argument. It is - * commonly used to establish parent-child relationships.

        - * - *

        This rule now supports more flexible method matching by default. - * It is possible that this may break (some) code - * written against release 1.1.1 or earlier. - *

        - */ - -public class SetNextNamingRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "set next" rule with the specified method name. - * - * @param methodName Method name of the parent method to call - * @param paramType Java class of the parent method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public SetNextNamingRule(String methodName, - String paramType) { - - this.methodName = methodName; - this.paramType = paramType; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The method name to call on the parent object. - */ - protected String methodName = null; - - - /** - * The Java class name of the parameter type expected by the method. - */ - protected String paramType = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - // Identify the objects to be used - Object child = digester.peek(0); - Object parent = digester.peek(1); - - NamingResources namingResources = null; - if (parent instanceof Context) { - namingResources = ((Context) parent).getNamingResources(); - } else { - namingResources = (NamingResources) parent; - } - - // Call the specified method - IntrospectionUtils.callMethod1(namingResources, methodName, - child, paramType, digester.getClassLoader()); - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SetNextRule["); - sb.append("methodName="); - sb.append(methodName); - sb.append(", paramType="); - sb.append(paramType); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: SetNextNamingRule.java 303133 2004-08-29 16:46:15Z yoavs $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + +import org.apache.catalina.Context; +import org.apache.catalina.deploy.NamingResources; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.digester.Rule; + + +/** + *

        Rule implementation that calls a method on the (top-1) (parent) + * object, passing the top object (child) as an argument. It is + * commonly used to establish parent-child relationships.

        + * + *

        This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + *

        + */ + +public class SetNextNamingRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set next" rule with the specified method name. + * + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetNextNamingRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.peek(1); + + NamingResources namingResources = null; + if (parent instanceof Context) { + namingResources = ((Context) parent).getNamingResources(); + } else { + namingResources = (NamingResources) parent; + } + + // Call the specified method + IntrospectionUtils.callMethod1(namingResources, methodName, + child, paramType, digester.getClassLoader()); + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SetNextRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/startup/TldConfig.java b/java/org/apache/catalina/startup/TldConfig.java index 68e4f2c60..04dc2f450 100644 --- a/java/org/apache/catalina/startup/TldConfig.java +++ b/java/org/apache/catalina/startup/TldConfig.java @@ -1,722 +1,722 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; - -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; -import javax.servlet.ServletException; - -import org.apache.catalina.Context; -import org.apache.catalina.Globals; -import org.apache.catalina.core.StandardContext; -import org.apache.catalina.util.StringManager; -import org.apache.tomcat.util.digester.Digester; -import org.xml.sax.InputSource; - -/** - * Startup event listener for a Context that configures the properties - * of that Context, and the associated defined servlets. - * - * @author Craig R. McClanahan - * @author Jean-Francois Arcand - * @author Costin Manolache - */ -public final class TldConfig { - - // Names of JARs that are known not to contain any TLDs - private static HashSet noTldJars; - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( TldConfig.class ); - - private static final String FILE_URL_PREFIX = "file:"; - private static final int FILE_URL_PREFIX_LEN = FILE_URL_PREFIX.length(); - - - /* - * Initializes the set of JARs that are known not to contain any TLDs - */ - static { - noTldJars = new HashSet(); - noTldJars.add("catalina.jar"); - noTldJars.add("catalina-ant.jar"); - noTldJars.add("catalina-cluster.jar"); - noTldJars.add("catalina-optional.jar"); - noTldJars.add("commons-el.jar"); - noTldJars.add("commons-logging-api.jar"); - noTldJars.add("commons-modeler.jar"); - noTldJars.add("jasper-compiler.jar"); - noTldJars.add("jasper-compiler-jdt.jar"); - noTldJars.add("jasper-runtime.jar"); - noTldJars.add("jsp-api.jar"); - noTldJars.add("naming-resources.jar"); - noTldJars.add("naming-factory.jar"); - noTldJars.add("naming-factory-dbcp.jar"); - noTldJars.add("servlet-api.jar"); - noTldJars.add("servlets-cgi.jar"); - noTldJars.add("servlets-default.jar"); - noTldJars.add("servlets-invoker.jar"); - noTldJars.add("servlets-ssi.jar"); - noTldJars.add("servlets-webdav.jar"); - noTldJars.add("tomcat-ajp.jar"); - noTldJars.add("tomcat-coyote.jar"); - noTldJars.add("tomcat-http.jar"); - noTldJars.add("tomcat-util.jar"); - // i18n JARs - noTldJars.add("catalina-i18n-en.jar"); - noTldJars.add("catalina-i18n-es.jar"); - noTldJars.add("catalina-i18n-fr.jar"); - noTldJars.add("catalina-i18n-ja.jar"); - // Misc JARs not included with Tomcat - noTldJars.add("ant.jar"); - noTldJars.add("commons-dbcp.jar"); - noTldJars.add("commons-beanutils.jar"); - noTldJars.add("commons-fileupload-1.0.jar"); - noTldJars.add("commons-pool.jar"); - noTldJars.add("commons-digester.jar"); - noTldJars.add("commons-logging.jar"); - noTldJars.add("commons-collections.jar"); - noTldJars.add("jmx.jar"); - noTldJars.add("jmx-tools.jar"); - noTldJars.add("xercesImpl.jar"); - noTldJars.add("xmlParserAPIs.jar"); - noTldJars.add("xml-apis.jar"); - // JARs from J2SE runtime - noTldJars.add("sunjce_provider.jar"); - noTldJars.add("ldapsec.jar"); - noTldJars.add("localedata.jar"); - noTldJars.add("dnsns.jar"); - } - - - // ----------------------------------------------------- Instance Variables - - /** - * The Context we are associated with. - */ - private Context context = null; - - - /** - * The string resources for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - /** - * The Digester we will use to process tag library - * descriptor files. - */ - private static Digester tldDigester = null; - - - /** - * Attribute value used to turn on/off TLD validation - */ - private static boolean tldValidation = false; - - - /** - * Attribute value used to turn on/off TLD namespace awarenes. - */ - private static boolean tldNamespaceAware = false; - - private boolean rescan=true; - - private ArrayList listeners=new ArrayList(); - - // --------------------------------------------------------- Public Methods - - /** - * Sets the list of JARs that are known not to contain any TLDs. - * - * @param jarNames List of comma-separated names of JAR files that are - * known not to contain any TLDs - */ - public static void setNoTldJars(String jarNames) { - if (jarNames != null) { - noTldJars.clear(); - StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); - while (tokenizer.hasMoreElements()) { - noTldJars.add(tokenizer.nextToken()); - } - } - } - - /** - * Set the validation feature of the XML parser used when - * parsing xml instances. - * @param tldValidation true to enable xml instance validation - */ - public void setTldValidation(boolean tldValidation){ - TldConfig.tldValidation = tldValidation; - } - - /** - * Get the server.xml attribute's xmlValidation. - * @return true if validation is enabled. - * - */ - public boolean getTldValidation(){ - return tldValidation; - } - - /** - * Get the server.xml attribute's xmlNamespaceAware. - * @return true if namespace awarenes is enabled. - * - */ - public boolean getTldNamespaceAware(){ - return tldNamespaceAware; - } - - - /** - * Set the namespace aware feature of the XML parser used when - * parsing xml instances. - * @param tldNamespaceAware true to enable namespace awareness - */ - public void setTldNamespaceAware(boolean tldNamespaceAware){ - TldConfig.tldNamespaceAware = tldNamespaceAware; - } - - - public boolean isRescan() { - return rescan; - } - - public void setRescan(boolean rescan) { - this.rescan = rescan; - } - - public Context getContext() { - return context; - } - - public void setContext(Context context) { - this.context = context; - } - - public void addApplicationListener( String s ) { - //if(log.isDebugEnabled()) - log.debug( "Add tld listener " + s); - listeners.add(s); - } - - public String[] getTldListeners() { - String result[]=new String[listeners.size()]; - listeners.toArray(result); - return result; - } - - - /** - * Scan for and configure all tag library descriptors found in this - * web application. - * - * @exception Exception if a fatal input/output or parsing error occurs - */ - public void execute() throws Exception { - long t1=System.currentTimeMillis(); - - File tldCache=null; - - if (context instanceof StandardContext) { - File workDir= (File) - ((StandardContext)context).getServletContext().getAttribute(Globals.WORK_DIR_ATTR); - tldCache=new File( workDir, "tldCache.ser"); - } - - // Option to not rescan - if( ! rescan ) { - // find the cache - if( tldCache!= null && tldCache.exists()) { - // just read it... - processCache(tldCache); - return; - } - } - - /* - * Acquire the list of TLD resource paths, possibly embedded in JAR - * files, to be processed - */ - Set resourcePaths = tldScanResourcePaths(); - Map jarPaths = getJarPaths(); - - // Check to see if we can use cached listeners - if (tldCache != null && tldCache.exists()) { - long lastModified = getLastModified(resourcePaths, jarPaths); - if (lastModified < tldCache.lastModified()) { - processCache(tldCache); - return; - } - } - - // Scan each accumulated resource path for TLDs to be processed - Iterator paths = resourcePaths.iterator(); - while (paths.hasNext()) { - String path = (String) paths.next(); - if (path.endsWith(".jar")) { - tldScanJar(path); - } else { - tldScanTld(path); - } - } - if (jarPaths != null) { - paths = jarPaths.values().iterator(); - while (paths.hasNext()) { - tldScanJar((File) paths.next()); - } - } - - String list[] = getTldListeners(); - - if( tldCache!= null ) { - log.debug( "Saving tld cache: " + tldCache + " " + list.length); - try { - FileOutputStream out=new FileOutputStream(tldCache); - ObjectOutputStream oos=new ObjectOutputStream( out ); - oos.writeObject( list ); - oos.close(); - } catch( IOException ex ) { - ex.printStackTrace(); - } - } - - if( log.isDebugEnabled() ) - log.debug( "Adding tld listeners:" + list.length); - for( int i=0; list!=null && i lastModified) lastModified = lastM; - if (log.isDebugEnabled()) { - log.debug( "Last modified " + path + " " + lastM); - } - } - - if (jarPaths != null) { - paths = jarPaths.values().iterator(); - while (paths.hasNext()) { - File jarFile = (File) paths.next(); - long lastM = jarFile.lastModified(); - if (lastM > lastModified) lastModified = lastM; - if (log.isDebugEnabled()) { - log.debug("Last modified " + jarFile.getAbsolutePath() - + " " + lastM); - } - } - } - - return lastModified; - } - - private void processCache(File tldCache ) throws IOException { - // read the cache and return; - try { - FileInputStream in=new FileInputStream(tldCache); - ObjectInputStream ois=new ObjectInputStream( in ); - String list[]=(String [])ois.readObject(); - if( log.isDebugEnabled() ) - log.debug("Reusing tldCache " + tldCache + " " + list.length); - for( int i=0; list!=null && iMETA-INF subdirectory, and scan each TLD for application - * event listeners that need to be registered. - * - * @param resourcePath Resource path of the JAR file to scan - * - * @exception Exception if an exception occurs while scanning this JAR - */ - private void tldScanJar(String resourcePath) throws Exception { - - if (log.isDebugEnabled()) { - log.debug(" Scanning JAR at resource path '" + resourcePath + "'"); - } - - URL url = context.getServletContext().getResource(resourcePath); - if (url == null) { - throw new IllegalArgumentException - (sm.getString("contextConfig.tldResourcePath", - resourcePath)); - } - - File file = new File(url.getFile()); - file = file.getCanonicalFile(); - tldScanJar(file); - - } - - /** - * Scans all TLD entries in the given JAR for application listeners. - * - * @param file JAR file whose TLD entries are scanned for application - * listeners - */ - private void tldScanJar(File file) throws Exception { - - JarFile jarFile = null; - String name = null; - - String jarPath = file.getAbsolutePath(); - - try { - jarFile = new JarFile(file); - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry) entries.nextElement(); - name = entry.getName(); - if (!name.startsWith("META-INF/")) { - continue; - } - if (!name.endsWith(".tld")) { - continue; - } - if (log.isTraceEnabled()) { - log.trace(" Processing TLD at '" + name + "'"); - } - try { - tldScanStream(new InputSource(jarFile.getInputStream(entry))); - } catch (Exception e) { - log.error(sm.getString("contextConfig.tldEntryException", - name, jarPath, context.getPath()), - e); - } - } - } catch (Exception e) { - log.error(sm.getString("contextConfig.tldJarException", - jarPath, context.getPath()), - e); - } finally { - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - // Ignore - } - } - } - } - - /** - * Scan the TLD contents in the specified input stream, and register - * any application event listeners found there. NOTE - It is - * the responsibility of the caller to close the InputStream after this - * method returns. - * - * @param resourceStream InputStream containing a tag library descriptor - * - * @exception Exception if an exception occurs while scanning this TLD - */ - private void tldScanStream(InputSource resourceStream) - throws Exception { - - if (tldDigester == null){ - tldDigester = createTldDigester(); - } - - synchronized (tldDigester) { - try { - tldDigester.push(this); - tldDigester.parse(resourceStream); - } finally { - tldDigester.reset(); - } - } - - } - - /** - * Scan the TLD contents at the specified resource path, and register - * any application event listeners found there. - * - * @param resourcePath Resource path being scanned - * - * @exception Exception if an exception occurs while scanning this TLD - */ - private void tldScanTld(String resourcePath) throws Exception { - - if (log.isDebugEnabled()) { - log.debug(" Scanning TLD at resource path '" + resourcePath + "'"); - } - - InputSource inputSource = null; - try { - InputStream stream = - context.getServletContext().getResourceAsStream(resourcePath); - if (stream == null) { - throw new IllegalArgumentException - (sm.getString("contextConfig.tldResourcePath", - resourcePath)); - } - inputSource = new InputSource(stream); - if (inputSource == null) { - throw new IllegalArgumentException - (sm.getString("contextConfig.tldResourcePath", - resourcePath)); - } - tldScanStream(inputSource); - } catch (Exception e) { - throw new ServletException - (sm.getString("contextConfig.tldFileException", resourcePath, - context.getPath()), - e); - } - - } - - /** - * Accumulate and return a Set of resource paths to be analyzed for - * tag library descriptors. Each element of the returned set will be - * the context-relative path to either a tag library descriptor file, - * or to a JAR file that may contain tag library descriptors in its - * META-INF subdirectory. - * - * @exception IOException if an input/output error occurs while - * accumulating the list of resource paths - */ - private Set tldScanResourcePaths() throws IOException { - if (log.isDebugEnabled()) { - log.debug(" Accumulating TLD resource paths"); - } - Set resourcePaths = new HashSet(); - - // Accumulate resource paths explicitly listed in the web application - // deployment descriptor - if (log.isTraceEnabled()) { - log.trace(" Scanning elements in web.xml"); - } - String taglibs[] = context.findTaglibs(); - for (int i = 0; i < taglibs.length; i++) { - String resourcePath = context.findTaglib(taglibs[i]); - // FIXME - Servlet 2.4 DTD implies that the location MUST be - // a context-relative path starting with '/'? - if (!resourcePath.startsWith("/")) { - resourcePath = "/WEB-INF/" + resourcePath; - } - if (log.isTraceEnabled()) { - log.trace(" Adding path '" + resourcePath + - "' for URI '" + taglibs[i] + "'"); - } - resourcePaths.add(resourcePath); - } - - DirContext resources = context.getResources(); - if (resources != null) { - tldScanResourcePathsWebInf(resources, "/WEB-INF", resourcePaths); - } - - // Return the completed set - return (resourcePaths); - - } - - /* - * Scans the web application's subdirectory identified by rootPath, - * along with its subdirectories, for TLDs. - * - * Initially, rootPath equals /WEB-INF. The /WEB-INF/classes and - * /WEB-INF/lib subdirectories are excluded from the search, as per the - * JSP 2.0 spec. - * - * @param resources The web application's resources - * @param rootPath The path whose subdirectories are to be searched for - * TLDs - * @param tldPaths The set of TLD resource paths to add to - */ - private void tldScanResourcePathsWebInf(DirContext resources, - String rootPath, - Set tldPaths) - throws IOException { - - if (log.isTraceEnabled()) { - log.trace(" Scanning TLDs in " + rootPath + " subdirectory"); - } - - try { - NamingEnumeration items = resources.list(rootPath); - while (items.hasMoreElements()) { - NameClassPair item = (NameClassPair) items.nextElement(); - String resourcePath = rootPath + "/" + item.getName(); - if (!resourcePath.endsWith(".tld") - && (resourcePath.startsWith("/WEB-INF/classes") - || resourcePath.startsWith("/WEB-INF/lib"))) { - continue; - } - if (resourcePath.endsWith(".tld")) { - if (log.isTraceEnabled()) { - log.trace(" Adding path '" + resourcePath + "'"); - } - tldPaths.add(resourcePath); - } else { - tldScanResourcePathsWebInf(resources, resourcePath, - tldPaths); - } - } - } catch (NamingException e) { - ; // Silent catch: it's valid that no /WEB-INF directory exists - } - } - - /** - * Returns a map of the paths to all JAR files that are accessible to the - * webapp and will be scanned for TLDs. - * - * The map always includes all the JARs under WEB-INF/lib, as well as - * shared JARs in the classloader delegation chain of the webapp's - * classloader. - * - * The latter constitutes a Tomcat-specific extension to the TLD search - * order defined in the JSP spec. It allows tag libraries packaged as JAR - * files to be shared by web applications by simply dropping them in a - * location that all web applications have access to (e.g., - * /common/lib). - * - * The set of shared JARs to be scanned for TLDs is narrowed down by - * the noTldJars class variable, which contains the names of JARs - * that are known not to contain any TLDs. - * - * @return Map of JAR file paths - */ - private Map getJarPaths() { - - HashMap jarPathMap = null; - - ClassLoader webappLoader = Thread.currentThread().getContextClassLoader(); - ClassLoader loader = webappLoader; - while (loader != null) { - if (loader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) loader).getURLs(); - for (int i=0; iContext that configures the properties + * of that Context, and the associated defined servlets. + * + * @author Craig R. McClanahan + * @author Jean-Francois Arcand + * @author Costin Manolache + */ +public final class TldConfig { + + // Names of JARs that are known not to contain any TLDs + private static HashSet noTldJars; + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( TldConfig.class ); + + private static final String FILE_URL_PREFIX = "file:"; + private static final int FILE_URL_PREFIX_LEN = FILE_URL_PREFIX.length(); + + + /* + * Initializes the set of JARs that are known not to contain any TLDs + */ + static { + noTldJars = new HashSet(); + noTldJars.add("catalina.jar"); + noTldJars.add("catalina-ant.jar"); + noTldJars.add("catalina-cluster.jar"); + noTldJars.add("catalina-optional.jar"); + noTldJars.add("commons-el.jar"); + noTldJars.add("commons-logging-api.jar"); + noTldJars.add("commons-modeler.jar"); + noTldJars.add("jasper-compiler.jar"); + noTldJars.add("jasper-compiler-jdt.jar"); + noTldJars.add("jasper-runtime.jar"); + noTldJars.add("jsp-api.jar"); + noTldJars.add("naming-resources.jar"); + noTldJars.add("naming-factory.jar"); + noTldJars.add("naming-factory-dbcp.jar"); + noTldJars.add("servlet-api.jar"); + noTldJars.add("servlets-cgi.jar"); + noTldJars.add("servlets-default.jar"); + noTldJars.add("servlets-invoker.jar"); + noTldJars.add("servlets-ssi.jar"); + noTldJars.add("servlets-webdav.jar"); + noTldJars.add("tomcat-ajp.jar"); + noTldJars.add("tomcat-coyote.jar"); + noTldJars.add("tomcat-http.jar"); + noTldJars.add("tomcat-util.jar"); + // i18n JARs + noTldJars.add("catalina-i18n-en.jar"); + noTldJars.add("catalina-i18n-es.jar"); + noTldJars.add("catalina-i18n-fr.jar"); + noTldJars.add("catalina-i18n-ja.jar"); + // Misc JARs not included with Tomcat + noTldJars.add("ant.jar"); + noTldJars.add("commons-dbcp.jar"); + noTldJars.add("commons-beanutils.jar"); + noTldJars.add("commons-fileupload-1.0.jar"); + noTldJars.add("commons-pool.jar"); + noTldJars.add("commons-digester.jar"); + noTldJars.add("commons-logging.jar"); + noTldJars.add("commons-collections.jar"); + noTldJars.add("jmx.jar"); + noTldJars.add("jmx-tools.jar"); + noTldJars.add("xercesImpl.jar"); + noTldJars.add("xmlParserAPIs.jar"); + noTldJars.add("xml-apis.jar"); + // JARs from J2SE runtime + noTldJars.add("sunjce_provider.jar"); + noTldJars.add("ldapsec.jar"); + noTldJars.add("localedata.jar"); + noTldJars.add("dnsns.jar"); + } + + + // ----------------------------------------------------- Instance Variables + + /** + * The Context we are associated with. + */ + private Context context = null; + + + /** + * The string resources for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + /** + * The Digester we will use to process tag library + * descriptor files. + */ + private static Digester tldDigester = null; + + + /** + * Attribute value used to turn on/off TLD validation + */ + private static boolean tldValidation = false; + + + /** + * Attribute value used to turn on/off TLD namespace awarenes. + */ + private static boolean tldNamespaceAware = false; + + private boolean rescan=true; + + private ArrayList listeners=new ArrayList(); + + // --------------------------------------------------------- Public Methods + + /** + * Sets the list of JARs that are known not to contain any TLDs. + * + * @param jarNames List of comma-separated names of JAR files that are + * known not to contain any TLDs + */ + public static void setNoTldJars(String jarNames) { + if (jarNames != null) { + noTldJars.clear(); + StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); + while (tokenizer.hasMoreElements()) { + noTldJars.add(tokenizer.nextToken()); + } + } + } + + /** + * Set the validation feature of the XML parser used when + * parsing xml instances. + * @param tldValidation true to enable xml instance validation + */ + public void setTldValidation(boolean tldValidation){ + TldConfig.tldValidation = tldValidation; + } + + /** + * Get the server.xml attribute's xmlValidation. + * @return true if validation is enabled. + * + */ + public boolean getTldValidation(){ + return tldValidation; + } + + /** + * Get the server.xml attribute's xmlNamespaceAware. + * @return true if namespace awarenes is enabled. + * + */ + public boolean getTldNamespaceAware(){ + return tldNamespaceAware; + } + + + /** + * Set the namespace aware feature of the XML parser used when + * parsing xml instances. + * @param tldNamespaceAware true to enable namespace awareness + */ + public void setTldNamespaceAware(boolean tldNamespaceAware){ + TldConfig.tldNamespaceAware = tldNamespaceAware; + } + + + public boolean isRescan() { + return rescan; + } + + public void setRescan(boolean rescan) { + this.rescan = rescan; + } + + public Context getContext() { + return context; + } + + public void setContext(Context context) { + this.context = context; + } + + public void addApplicationListener( String s ) { + //if(log.isDebugEnabled()) + log.debug( "Add tld listener " + s); + listeners.add(s); + } + + public String[] getTldListeners() { + String result[]=new String[listeners.size()]; + listeners.toArray(result); + return result; + } + + + /** + * Scan for and configure all tag library descriptors found in this + * web application. + * + * @exception Exception if a fatal input/output or parsing error occurs + */ + public void execute() throws Exception { + long t1=System.currentTimeMillis(); + + File tldCache=null; + + if (context instanceof StandardContext) { + File workDir= (File) + ((StandardContext)context).getServletContext().getAttribute(Globals.WORK_DIR_ATTR); + tldCache=new File( workDir, "tldCache.ser"); + } + + // Option to not rescan + if( ! rescan ) { + // find the cache + if( tldCache!= null && tldCache.exists()) { + // just read it... + processCache(tldCache); + return; + } + } + + /* + * Acquire the list of TLD resource paths, possibly embedded in JAR + * files, to be processed + */ + Set resourcePaths = tldScanResourcePaths(); + Map jarPaths = getJarPaths(); + + // Check to see if we can use cached listeners + if (tldCache != null && tldCache.exists()) { + long lastModified = getLastModified(resourcePaths, jarPaths); + if (lastModified < tldCache.lastModified()) { + processCache(tldCache); + return; + } + } + + // Scan each accumulated resource path for TLDs to be processed + Iterator paths = resourcePaths.iterator(); + while (paths.hasNext()) { + String path = (String) paths.next(); + if (path.endsWith(".jar")) { + tldScanJar(path); + } else { + tldScanTld(path); + } + } + if (jarPaths != null) { + paths = jarPaths.values().iterator(); + while (paths.hasNext()) { + tldScanJar((File) paths.next()); + } + } + + String list[] = getTldListeners(); + + if( tldCache!= null ) { + log.debug( "Saving tld cache: " + tldCache + " " + list.length); + try { + FileOutputStream out=new FileOutputStream(tldCache); + ObjectOutputStream oos=new ObjectOutputStream( out ); + oos.writeObject( list ); + oos.close(); + } catch( IOException ex ) { + ex.printStackTrace(); + } + } + + if( log.isDebugEnabled() ) + log.debug( "Adding tld listeners:" + list.length); + for( int i=0; list!=null && i lastModified) lastModified = lastM; + if (log.isDebugEnabled()) { + log.debug( "Last modified " + path + " " + lastM); + } + } + + if (jarPaths != null) { + paths = jarPaths.values().iterator(); + while (paths.hasNext()) { + File jarFile = (File) paths.next(); + long lastM = jarFile.lastModified(); + if (lastM > lastModified) lastModified = lastM; + if (log.isDebugEnabled()) { + log.debug("Last modified " + jarFile.getAbsolutePath() + + " " + lastM); + } + } + } + + return lastModified; + } + + private void processCache(File tldCache ) throws IOException { + // read the cache and return; + try { + FileInputStream in=new FileInputStream(tldCache); + ObjectInputStream ois=new ObjectInputStream( in ); + String list[]=(String [])ois.readObject(); + if( log.isDebugEnabled() ) + log.debug("Reusing tldCache " + tldCache + " " + list.length); + for( int i=0; list!=null && iMETA-INF subdirectory, and scan each TLD for application + * event listeners that need to be registered. + * + * @param resourcePath Resource path of the JAR file to scan + * + * @exception Exception if an exception occurs while scanning this JAR + */ + private void tldScanJar(String resourcePath) throws Exception { + + if (log.isDebugEnabled()) { + log.debug(" Scanning JAR at resource path '" + resourcePath + "'"); + } + + URL url = context.getServletContext().getResource(resourcePath); + if (url == null) { + throw new IllegalArgumentException + (sm.getString("contextConfig.tldResourcePath", + resourcePath)); + } + + File file = new File(url.getFile()); + file = file.getCanonicalFile(); + tldScanJar(file); + + } + + /** + * Scans all TLD entries in the given JAR for application listeners. + * + * @param file JAR file whose TLD entries are scanned for application + * listeners + */ + private void tldScanJar(File file) throws Exception { + + JarFile jarFile = null; + String name = null; + + String jarPath = file.getAbsolutePath(); + + try { + jarFile = new JarFile(file); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = (JarEntry) entries.nextElement(); + name = entry.getName(); + if (!name.startsWith("META-INF/")) { + continue; + } + if (!name.endsWith(".tld")) { + continue; + } + if (log.isTraceEnabled()) { + log.trace(" Processing TLD at '" + name + "'"); + } + try { + tldScanStream(new InputSource(jarFile.getInputStream(entry))); + } catch (Exception e) { + log.error(sm.getString("contextConfig.tldEntryException", + name, jarPath, context.getPath()), + e); + } + } + } catch (Exception e) { + log.error(sm.getString("contextConfig.tldJarException", + jarPath, context.getPath()), + e); + } finally { + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + // Ignore + } + } + } + } + + /** + * Scan the TLD contents in the specified input stream, and register + * any application event listeners found there. NOTE - It is + * the responsibility of the caller to close the InputStream after this + * method returns. + * + * @param resourceStream InputStream containing a tag library descriptor + * + * @exception Exception if an exception occurs while scanning this TLD + */ + private void tldScanStream(InputSource resourceStream) + throws Exception { + + if (tldDigester == null){ + tldDigester = createTldDigester(); + } + + synchronized (tldDigester) { + try { + tldDigester.push(this); + tldDigester.parse(resourceStream); + } finally { + tldDigester.reset(); + } + } + + } + + /** + * Scan the TLD contents at the specified resource path, and register + * any application event listeners found there. + * + * @param resourcePath Resource path being scanned + * + * @exception Exception if an exception occurs while scanning this TLD + */ + private void tldScanTld(String resourcePath) throws Exception { + + if (log.isDebugEnabled()) { + log.debug(" Scanning TLD at resource path '" + resourcePath + "'"); + } + + InputSource inputSource = null; + try { + InputStream stream = + context.getServletContext().getResourceAsStream(resourcePath); + if (stream == null) { + throw new IllegalArgumentException + (sm.getString("contextConfig.tldResourcePath", + resourcePath)); + } + inputSource = new InputSource(stream); + if (inputSource == null) { + throw new IllegalArgumentException + (sm.getString("contextConfig.tldResourcePath", + resourcePath)); + } + tldScanStream(inputSource); + } catch (Exception e) { + throw new ServletException + (sm.getString("contextConfig.tldFileException", resourcePath, + context.getPath()), + e); + } + + } + + /** + * Accumulate and return a Set of resource paths to be analyzed for + * tag library descriptors. Each element of the returned set will be + * the context-relative path to either a tag library descriptor file, + * or to a JAR file that may contain tag library descriptors in its + * META-INF subdirectory. + * + * @exception IOException if an input/output error occurs while + * accumulating the list of resource paths + */ + private Set tldScanResourcePaths() throws IOException { + if (log.isDebugEnabled()) { + log.debug(" Accumulating TLD resource paths"); + } + Set resourcePaths = new HashSet(); + + // Accumulate resource paths explicitly listed in the web application + // deployment descriptor + if (log.isTraceEnabled()) { + log.trace(" Scanning elements in web.xml"); + } + String taglibs[] = context.findTaglibs(); + for (int i = 0; i < taglibs.length; i++) { + String resourcePath = context.findTaglib(taglibs[i]); + // FIXME - Servlet 2.4 DTD implies that the location MUST be + // a context-relative path starting with '/'? + if (!resourcePath.startsWith("/")) { + resourcePath = "/WEB-INF/" + resourcePath; + } + if (log.isTraceEnabled()) { + log.trace(" Adding path '" + resourcePath + + "' for URI '" + taglibs[i] + "'"); + } + resourcePaths.add(resourcePath); + } + + DirContext resources = context.getResources(); + if (resources != null) { + tldScanResourcePathsWebInf(resources, "/WEB-INF", resourcePaths); + } + + // Return the completed set + return (resourcePaths); + + } + + /* + * Scans the web application's subdirectory identified by rootPath, + * along with its subdirectories, for TLDs. + * + * Initially, rootPath equals /WEB-INF. The /WEB-INF/classes and + * /WEB-INF/lib subdirectories are excluded from the search, as per the + * JSP 2.0 spec. + * + * @param resources The web application's resources + * @param rootPath The path whose subdirectories are to be searched for + * TLDs + * @param tldPaths The set of TLD resource paths to add to + */ + private void tldScanResourcePathsWebInf(DirContext resources, + String rootPath, + Set tldPaths) + throws IOException { + + if (log.isTraceEnabled()) { + log.trace(" Scanning TLDs in " + rootPath + " subdirectory"); + } + + try { + NamingEnumeration items = resources.list(rootPath); + while (items.hasMoreElements()) { + NameClassPair item = (NameClassPair) items.nextElement(); + String resourcePath = rootPath + "/" + item.getName(); + if (!resourcePath.endsWith(".tld") + && (resourcePath.startsWith("/WEB-INF/classes") + || resourcePath.startsWith("/WEB-INF/lib"))) { + continue; + } + if (resourcePath.endsWith(".tld")) { + if (log.isTraceEnabled()) { + log.trace(" Adding path '" + resourcePath + "'"); + } + tldPaths.add(resourcePath); + } else { + tldScanResourcePathsWebInf(resources, resourcePath, + tldPaths); + } + } + } catch (NamingException e) { + ; // Silent catch: it's valid that no /WEB-INF directory exists + } + } + + /** + * Returns a map of the paths to all JAR files that are accessible to the + * webapp and will be scanned for TLDs. + * + * The map always includes all the JARs under WEB-INF/lib, as well as + * shared JARs in the classloader delegation chain of the webapp's + * classloader. + * + * The latter constitutes a Tomcat-specific extension to the TLD search + * order defined in the JSP spec. It allows tag libraries packaged as JAR + * files to be shared by web applications by simply dropping them in a + * location that all web applications have access to (e.g., + * /common/lib). + * + * The set of shared JARs to be scanned for TLDs is narrowed down by + * the noTldJars class variable, which contains the names of JARs + * that are known not to contain any TLDs. + * + * @return Map of JAR file paths + */ + private Map getJarPaths() { + + HashMap jarPathMap = null; + + ClassLoader webappLoader = Thread.currentThread().getContextClassLoader(); + ClassLoader loader = webappLoader; + while (loader != null) { + if (loader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) loader).getURLs(); + for (int i=0; iRuleSet for processing the contents of a tag library - * descriptor resource.

        - * - * @author Craig R. McClanahan - * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ - */ - -public class TldRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public TldRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public TldRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - - digester.addCallMethod(prefix + "taglib/listener/listener-class", - "addApplicationListener", 0); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.RuleSetBase; + + +/** + *

        RuleSet for processing the contents of a tag library + * descriptor resource.

        + * + * @author Craig R. McClanahan + * @version $Revision: 302984 $ $Date: 2004-06-26 19:41:33 +0200 (sam., 26 juin 2004) $ + */ + +public class TldRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public TldRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public TldRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + + digester.addCallMethod(prefix + "taglib/listener/listener-class", + "addApplicationListener", 0); + + } + + +} diff --git a/java/org/apache/catalina/startup/Tool.java b/java/org/apache/catalina/startup/Tool.java index f260a2adf..2fc50e6d6 100644 --- a/java/org/apache/catalina/startup/Tool.java +++ b/java/org/apache/catalina/startup/Tool.java @@ -1,243 +1,243 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.lang.reflect.Method; -import java.util.ArrayList; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - *

        General purpose wrapper for command line tools that should execute in an - * environment with the common class loader environment set up by Catalina. - * This should be executed from a command line script that conforms to - * the following requirements:

        - *
          - *
        • Passes the catalina.home system property configured with - * the pathname of the Tomcat installation directory.
        • - *
        • Sets the system classpath to include bootstrap.jar and - * $JAVA_HOME/lib/tools.jar.
        • - *
        - * - *

        The command line to execute the tool looks like:

        - *
        - *   java -classpath $CLASSPATH org.apache.catalina.startup.Tool \
        - *     ${options} ${classname} ${arguments}
        - * 
        - * - *

        with the following replacement contents: - *

          - *
        • ${options} - Command line options for this Tool wrapper. - * The following options are supported: - *
            - *
          • -ant : Set the ant.home system property - * to corresponding to the value of catalina.home - * (useful when your command line tool runs Ant).
          • - *
          • -common : Add common/classes and - * common/lib - *
          • -server : Add server/classes and - * server/lib to the class loader repositories.
          • - *
          • -shared : Add shared/classes and - * shared/lib to the class loader repositories.
          • - *
          - *
        • ${classname} - Fully qualified Java class name of the - * application's main class.
        • - *
        • ${arguments} - Command line arguments to be passed to - * the application's main() method.
        • - *
        - * - * @author Craig R. McClanahan - * @version $Revision: 302983 $ $Date: 2004-06-26 01:56:25 +0200 (sam., 26 juin 2004) $ - */ - -public final class Tool { - - - private static Log log = LogFactory.getLog(Tool.class); - - // ------------------------------------------------------- Static Variables - - - /** - * Set ant.home system property? - */ - private static boolean ant = false; - - - /** - * The pathname of our installation base directory. - */ - private static String catalinaHome = System.getProperty("catalina.home"); - - - /** - * Include common classes in the repositories? - */ - private static boolean common = false; - - - /** - * Include server classes in the repositories? - */ - private static boolean server = false; - - - /** - * Include shared classes in the repositories? - */ - private static boolean shared = false; - - - // ----------------------------------------------------------- Main Program - - - /** - * The main program for the bootstrap. - * - * @param args Command line arguments to be processed - */ - public static void main(String args[]) { - - // Verify that "catalina.home" was passed. - if (catalinaHome == null) { - log.error("Must set 'catalina.home' system property"); - System.exit(1); - } - - // Process command line options - int index = 0; - while (true) { - if (index == args.length) { - usage(); - System.exit(1); - } - if ("-ant".equals(args[index])) - ant = true; - else if ("-common".equals(args[index])) - common = true; - else if ("-server".equals(args[index])) - server = true; - else if ("-shared".equals(args[index])) - shared = true; - else - break; - index++; - } - if (index > args.length) { - usage(); - System.exit(1); - } - - // Set "ant.home" if requested - if (ant) - System.setProperty("ant.home", catalinaHome); - - // Construct the class loader we will be using - ClassLoader classLoader = null; - try { - ArrayList packed = new ArrayList(); - ArrayList unpacked = new ArrayList(); - unpacked.add(new File(catalinaHome, "classes")); - packed.add(new File(catalinaHome, "lib")); - if (common) { - unpacked.add(new File(catalinaHome, - "common" + File.separator + "classes")); - packed.add(new File(catalinaHome, - "common" + File.separator + "lib")); - } - if (server) { - unpacked.add(new File(catalinaHome, - "server" + File.separator + "classes")); - packed.add(new File(catalinaHome, - "server" + File.separator + "lib")); - } - if (shared) { - unpacked.add(new File(catalinaHome, - "shared" + File.separator + "classes")); - packed.add(new File(catalinaHome, - "shared" + File.separator + "lib")); - } - classLoader = - ClassLoaderFactory.createClassLoader - ((File[]) unpacked.toArray(new File[0]), - (File[]) packed.toArray(new File[0]), - null); - } catch (Throwable t) { - log.error("Class loader creation threw exception", t); - System.exit(1); - } - Thread.currentThread().setContextClassLoader(classLoader); - - // Load our application class - Class clazz = null; - String className = args[index++]; - try { - if (log.isDebugEnabled()) - log.debug("Loading application class " + className); - clazz = classLoader.loadClass(className); - } catch (Throwable t) { - log.error("Exception creating instance of " + className, t); - System.exit(1); - } - - // Locate the static main() method of the application class - Method method = null; - String params[] = new String[args.length - index]; - System.arraycopy(args, index, params, 0, params.length); - try { - if (log.isDebugEnabled()) - log.debug("Identifying main() method"); - String methodName = "main"; - Class paramTypes[] = new Class[1]; - paramTypes[0] = params.getClass(); - method = clazz.getMethod(methodName, paramTypes); - } catch (Throwable t) { - log.error("Exception locating main() method", t); - System.exit(1); - } - - // Invoke the main method of the application class - try { - if (log.isDebugEnabled()) - log.debug("Calling main() method"); - Object paramValues[] = new Object[1]; - paramValues[0] = params; - method.invoke(null, paramValues); - } catch (Throwable t) { - log.error("Exception calling main() method", t); - System.exit(1); - } - - } - - - /** - * Display usage information about this tool. - */ - private static void usage() { - - log.info("Usage: java org.apache.catalina.startup.Tool [] []"); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.lang.reflect.Method; +import java.util.ArrayList; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + *

        General purpose wrapper for command line tools that should execute in an + * environment with the common class loader environment set up by Catalina. + * This should be executed from a command line script that conforms to + * the following requirements:

        + *
          + *
        • Passes the catalina.home system property configured with + * the pathname of the Tomcat installation directory.
        • + *
        • Sets the system classpath to include bootstrap.jar and + * $JAVA_HOME/lib/tools.jar.
        • + *
        + * + *

        The command line to execute the tool looks like:

        + *
        + *   java -classpath $CLASSPATH org.apache.catalina.startup.Tool \
        + *     ${options} ${classname} ${arguments}
        + * 
        + * + *

        with the following replacement contents: + *

          + *
        • ${options} - Command line options for this Tool wrapper. + * The following options are supported: + *
            + *
          • -ant : Set the ant.home system property + * to corresponding to the value of catalina.home + * (useful when your command line tool runs Ant).
          • + *
          • -common : Add common/classes and + * common/lib + *
          • -server : Add server/classes and + * server/lib to the class loader repositories.
          • + *
          • -shared : Add shared/classes and + * shared/lib to the class loader repositories.
          • + *
          + *
        • ${classname} - Fully qualified Java class name of the + * application's main class.
        • + *
        • ${arguments} - Command line arguments to be passed to + * the application's main() method.
        • + *
        + * + * @author Craig R. McClanahan + * @version $Revision: 302983 $ $Date: 2004-06-26 01:56:25 +0200 (sam., 26 juin 2004) $ + */ + +public final class Tool { + + + private static Log log = LogFactory.getLog(Tool.class); + + // ------------------------------------------------------- Static Variables + + + /** + * Set ant.home system property? + */ + private static boolean ant = false; + + + /** + * The pathname of our installation base directory. + */ + private static String catalinaHome = System.getProperty("catalina.home"); + + + /** + * Include common classes in the repositories? + */ + private static boolean common = false; + + + /** + * Include server classes in the repositories? + */ + private static boolean server = false; + + + /** + * Include shared classes in the repositories? + */ + private static boolean shared = false; + + + // ----------------------------------------------------------- Main Program + + + /** + * The main program for the bootstrap. + * + * @param args Command line arguments to be processed + */ + public static void main(String args[]) { + + // Verify that "catalina.home" was passed. + if (catalinaHome == null) { + log.error("Must set 'catalina.home' system property"); + System.exit(1); + } + + // Process command line options + int index = 0; + while (true) { + if (index == args.length) { + usage(); + System.exit(1); + } + if ("-ant".equals(args[index])) + ant = true; + else if ("-common".equals(args[index])) + common = true; + else if ("-server".equals(args[index])) + server = true; + else if ("-shared".equals(args[index])) + shared = true; + else + break; + index++; + } + if (index > args.length) { + usage(); + System.exit(1); + } + + // Set "ant.home" if requested + if (ant) + System.setProperty("ant.home", catalinaHome); + + // Construct the class loader we will be using + ClassLoader classLoader = null; + try { + ArrayList packed = new ArrayList(); + ArrayList unpacked = new ArrayList(); + unpacked.add(new File(catalinaHome, "classes")); + packed.add(new File(catalinaHome, "lib")); + if (common) { + unpacked.add(new File(catalinaHome, + "common" + File.separator + "classes")); + packed.add(new File(catalinaHome, + "common" + File.separator + "lib")); + } + if (server) { + unpacked.add(new File(catalinaHome, + "server" + File.separator + "classes")); + packed.add(new File(catalinaHome, + "server" + File.separator + "lib")); + } + if (shared) { + unpacked.add(new File(catalinaHome, + "shared" + File.separator + "classes")); + packed.add(new File(catalinaHome, + "shared" + File.separator + "lib")); + } + classLoader = + ClassLoaderFactory.createClassLoader + ((File[]) unpacked.toArray(new File[0]), + (File[]) packed.toArray(new File[0]), + null); + } catch (Throwable t) { + log.error("Class loader creation threw exception", t); + System.exit(1); + } + Thread.currentThread().setContextClassLoader(classLoader); + + // Load our application class + Class clazz = null; + String className = args[index++]; + try { + if (log.isDebugEnabled()) + log.debug("Loading application class " + className); + clazz = classLoader.loadClass(className); + } catch (Throwable t) { + log.error("Exception creating instance of " + className, t); + System.exit(1); + } + + // Locate the static main() method of the application class + Method method = null; + String params[] = new String[args.length - index]; + System.arraycopy(args, index, params, 0, params.length); + try { + if (log.isDebugEnabled()) + log.debug("Identifying main() method"); + String methodName = "main"; + Class paramTypes[] = new Class[1]; + paramTypes[0] = params.getClass(); + method = clazz.getMethod(methodName, paramTypes); + } catch (Throwable t) { + log.error("Exception locating main() method", t); + System.exit(1); + } + + // Invoke the main method of the application class + try { + if (log.isDebugEnabled()) + log.debug("Calling main() method"); + Object paramValues[] = new Object[1]; + paramValues[0] = params; + method.invoke(null, paramValues); + } catch (Throwable t) { + log.error("Exception calling main() method", t); + System.exit(1); + } + + } + + + /** + * Display usage information about this tool. + */ + private static void usage() { + + log.info("Usage: java org.apache.catalina.startup.Tool [] []"); + + } + + +} diff --git a/java/org/apache/catalina/startup/UserConfig.java b/java/org/apache/catalina/startup/UserConfig.java index d5a7f8f23..4319cdce0 100644 --- a/java/org/apache/catalina/startup/UserConfig.java +++ b/java/org/apache/catalina/startup/UserConfig.java @@ -1,338 +1,338 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.io.File; -import java.util.Enumeration; - -import org.apache.catalina.Context; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.util.StringManager; - - -/** - * Startup event listener for a Host that configures Contexts (web - * applications) for all defined "users" who have a web application in a - * directory with the specified name in their home directories. The context - * path of each deployed application will be set to ~xxxxx, where - * xxxxx is the username of the owning user for that web application - * - * @author Craig R. McClanahan - * @version $Revision: 302976 $ $Date: 2004-06-23 15:51:38 +0200 (mer., 23 juin 2004) $ - */ - -public final class UserConfig - implements LifecycleListener { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( UserConfig.class ); - - - // ----------------------------------------------------- Instance Variables - - - /** - * The Java class name of the Context configuration class we should use. - */ - private String configClass = "org.apache.catalina.startup.ContextConfig"; - - - /** - * The Java class name of the Context implementation we should use. - */ - private String contextClass = "org.apache.catalina.core.StandardContext"; - - - /** - * The directory name to be searched for within each user home directory. - */ - private String directoryName = "public_html"; - - - /** - * The base directory containing user home directories. - */ - private String homeBase = null; - - - /** - * The Host we are associated with. - */ - private Host host = null; - - - /** - * The string resources for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The Java class name of the user database class we should use. - */ - private String userClass = - "org.apache.catalina.startup.PasswdUserDatabase"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Context configuration class name. - */ - public String getConfigClass() { - - return (this.configClass); - - } - - - /** - * Set the Context configuration class name. - * - * @param configClass The new Context configuration class name. - */ - public void setConfigClass(String configClass) { - - this.configClass = configClass; - - } - - - /** - * Return the Context implementation class name. - */ - public String getContextClass() { - - return (this.contextClass); - - } - - - /** - * Set the Context implementation class name. - * - * @param contextClass The new Context implementation class name. - */ - public void setContextClass(String contextClass) { - - this.contextClass = contextClass; - - } - - - /** - * Return the directory name for user web applications. - */ - public String getDirectoryName() { - - return (this.directoryName); - - } - - - /** - * Set the directory name for user web applications. - * - * @param directoryName The new directory name - */ - public void setDirectoryName(String directoryName) { - - this.directoryName = directoryName; - - } - - - /** - * Return the base directory containing user home directories. - */ - public String getHomeBase() { - - return (this.homeBase); - - } - - - /** - * Set the base directory containing user home directories. - * - * @param homeBase The new base directory - */ - public void setHomeBase(String homeBase) { - - this.homeBase = homeBase; - - } - - - /** - * Return the user database class name for this component. - */ - public String getUserClass() { - - return (this.userClass); - - } - - - /** - * Set the user database class name for this component. - */ - public void setUserClass(String userClass) { - - this.userClass = userClass; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the START event for an associated Host. - * - * @param event The lifecycle event that has occurred - */ - public void lifecycleEvent(LifecycleEvent event) { - - // Identify the host we are associated with - try { - host = (Host) event.getLifecycle(); - } catch (ClassCastException e) { - log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); - return; - } - - // Process the event that has occurred - if (event.getType().equals(Lifecycle.START_EVENT)) - start(); - else if (event.getType().equals(Lifecycle.STOP_EVENT)) - stop(); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Deploy a web application for any user who has a web application present - * in a directory with a specified name within their home directory. - */ - private void deploy() { - - if (host.getLogger().isDebugEnabled()) - host.getLogger().debug(sm.getString("userConfig.deploying")); - - // Load the user database object for this host - UserDatabase database = null; - try { - Class clazz = Class.forName(userClass); - database = (UserDatabase) clazz.newInstance(); - database.setUserConfig(this); - } catch (Exception e) { - host.getLogger().error(sm.getString("userConfig.database"), e); - return; - } - - // Deploy the web application (if any) for each defined user - Enumeration users = database.getUsers(); - while (users.hasMoreElements()) { - String user = (String) users.nextElement(); - String home = database.getHome(user); - deploy(user, home); - } - - } - - - /** - * Deploy a web application for the specified user if they have such an - * application in the defined directory within their home directory. - * - * @param user Username owning the application to be deployed - * @param home Home directory of this user - */ - private void deploy(String user, String home) { - - // Does this user have a web application to be deployed? - String contextPath = "/~" + user; - if (host.findChild(contextPath) != null) - return; - File app = new File(home, directoryName); - if (!app.exists() || !app.isDirectory()) - return; - /* - File dd = new File(app, "/WEB-INF/web.xml"); - if (!dd.exists() || !dd.isFile() || !dd.canRead()) - return; - */ - host.getLogger().info(sm.getString("userConfig.deploy", user)); - - // Deploy the web application for this user - try { - Class clazz = Class.forName(contextClass); - Context context = - (Context) clazz.newInstance(); - context.setPath(contextPath); - context.setDocBase(app.toString()); - if (context instanceof Lifecycle) { - clazz = Class.forName(configClass); - LifecycleListener listener = - (LifecycleListener) clazz.newInstance(); - ((Lifecycle) context).addLifecycleListener(listener); - } - host.addChild(context); - } catch (Exception e) { - host.getLogger().error(sm.getString("userConfig.error", user), e); - } - - } - - - /** - * Process a "start" event for this Host. - */ - private void start() { - - if (host.getLogger().isDebugEnabled()) - host.getLogger().debug(sm.getString("userConfig.start")); - - deploy(); - - } - - - /** - * Process a "stop" event for this Host. - */ - private void stop() { - - if (host.getLogger().isDebugEnabled()) - host.getLogger().debug(sm.getString("userConfig.stop")); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.io.File; +import java.util.Enumeration; + +import org.apache.catalina.Context; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.util.StringManager; + + +/** + * Startup event listener for a Host that configures Contexts (web + * applications) for all defined "users" who have a web application in a + * directory with the specified name in their home directories. The context + * path of each deployed application will be set to ~xxxxx, where + * xxxxx is the username of the owning user for that web application + * + * @author Craig R. McClanahan + * @version $Revision: 302976 $ $Date: 2004-06-23 15:51:38 +0200 (mer., 23 juin 2004) $ + */ + +public final class UserConfig + implements LifecycleListener { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( UserConfig.class ); + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Java class name of the Context configuration class we should use. + */ + private String configClass = "org.apache.catalina.startup.ContextConfig"; + + + /** + * The Java class name of the Context implementation we should use. + */ + private String contextClass = "org.apache.catalina.core.StandardContext"; + + + /** + * The directory name to be searched for within each user home directory. + */ + private String directoryName = "public_html"; + + + /** + * The base directory containing user home directories. + */ + private String homeBase = null; + + + /** + * The Host we are associated with. + */ + private Host host = null; + + + /** + * The string resources for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The Java class name of the user database class we should use. + */ + private String userClass = + "org.apache.catalina.startup.PasswdUserDatabase"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Context configuration class name. + */ + public String getConfigClass() { + + return (this.configClass); + + } + + + /** + * Set the Context configuration class name. + * + * @param configClass The new Context configuration class name. + */ + public void setConfigClass(String configClass) { + + this.configClass = configClass; + + } + + + /** + * Return the Context implementation class name. + */ + public String getContextClass() { + + return (this.contextClass); + + } + + + /** + * Set the Context implementation class name. + * + * @param contextClass The new Context implementation class name. + */ + public void setContextClass(String contextClass) { + + this.contextClass = contextClass; + + } + + + /** + * Return the directory name for user web applications. + */ + public String getDirectoryName() { + + return (this.directoryName); + + } + + + /** + * Set the directory name for user web applications. + * + * @param directoryName The new directory name + */ + public void setDirectoryName(String directoryName) { + + this.directoryName = directoryName; + + } + + + /** + * Return the base directory containing user home directories. + */ + public String getHomeBase() { + + return (this.homeBase); + + } + + + /** + * Set the base directory containing user home directories. + * + * @param homeBase The new base directory + */ + public void setHomeBase(String homeBase) { + + this.homeBase = homeBase; + + } + + + /** + * Return the user database class name for this component. + */ + public String getUserClass() { + + return (this.userClass); + + } + + + /** + * Set the user database class name for this component. + */ + public void setUserClass(String userClass) { + + this.userClass = userClass; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the START event for an associated Host. + * + * @param event The lifecycle event that has occurred + */ + public void lifecycleEvent(LifecycleEvent event) { + + // Identify the host we are associated with + try { + host = (Host) event.getLifecycle(); + } catch (ClassCastException e) { + log.error(sm.getString("hostConfig.cce", event.getLifecycle()), e); + return; + } + + // Process the event that has occurred + if (event.getType().equals(Lifecycle.START_EVENT)) + start(); + else if (event.getType().equals(Lifecycle.STOP_EVENT)) + stop(); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Deploy a web application for any user who has a web application present + * in a directory with a specified name within their home directory. + */ + private void deploy() { + + if (host.getLogger().isDebugEnabled()) + host.getLogger().debug(sm.getString("userConfig.deploying")); + + // Load the user database object for this host + UserDatabase database = null; + try { + Class clazz = Class.forName(userClass); + database = (UserDatabase) clazz.newInstance(); + database.setUserConfig(this); + } catch (Exception e) { + host.getLogger().error(sm.getString("userConfig.database"), e); + return; + } + + // Deploy the web application (if any) for each defined user + Enumeration users = database.getUsers(); + while (users.hasMoreElements()) { + String user = (String) users.nextElement(); + String home = database.getHome(user); + deploy(user, home); + } + + } + + + /** + * Deploy a web application for the specified user if they have such an + * application in the defined directory within their home directory. + * + * @param user Username owning the application to be deployed + * @param home Home directory of this user + */ + private void deploy(String user, String home) { + + // Does this user have a web application to be deployed? + String contextPath = "/~" + user; + if (host.findChild(contextPath) != null) + return; + File app = new File(home, directoryName); + if (!app.exists() || !app.isDirectory()) + return; + /* + File dd = new File(app, "/WEB-INF/web.xml"); + if (!dd.exists() || !dd.isFile() || !dd.canRead()) + return; + */ + host.getLogger().info(sm.getString("userConfig.deploy", user)); + + // Deploy the web application for this user + try { + Class clazz = Class.forName(contextClass); + Context context = + (Context) clazz.newInstance(); + context.setPath(contextPath); + context.setDocBase(app.toString()); + if (context instanceof Lifecycle) { + clazz = Class.forName(configClass); + LifecycleListener listener = + (LifecycleListener) clazz.newInstance(); + ((Lifecycle) context).addLifecycleListener(listener); + } + host.addChild(context); + } catch (Exception e) { + host.getLogger().error(sm.getString("userConfig.error", user), e); + } + + } + + + /** + * Process a "start" event for this Host. + */ + private void start() { + + if (host.getLogger().isDebugEnabled()) + host.getLogger().debug(sm.getString("userConfig.start")); + + deploy(); + + } + + + /** + * Process a "stop" event for this Host. + */ + private void stop() { + + if (host.getLogger().isDebugEnabled()) + host.getLogger().debug(sm.getString("userConfig.stop")); + + } + + +} diff --git a/java/org/apache/catalina/startup/UserDatabase.java b/java/org/apache/catalina/startup/UserDatabase.java index 39efa843e..fcac2704f 100644 --- a/java/org/apache/catalina/startup/UserDatabase.java +++ b/java/org/apache/catalina/startup/UserDatabase.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.util.Enumeration; - - -/** - * Abstraction of the set of users defined by the operating system on the - * current server platform. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public interface UserDatabase { - - - // ----------------------------------------------------------- Properties - - - /** - * Return the UserConfig listener with which we are associated. - */ - public UserConfig getUserConfig(); - - - /** - * Set the UserConfig listener with which we are associated. - * - * @param userConfig The new UserConfig listener - */ - public void setUserConfig(UserConfig userConfig); - - - // ------------------------------------------------------- Public Methods - - - /** - * Return an absolute pathname to the home directory for the specified user. - * - * @param user User for which a home directory should be retrieved - */ - public String getHome(String user); - - - /** - * Return an enumeration of the usernames defined on this server. - */ - public Enumeration getUsers(); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.util.Enumeration; + + +/** + * Abstraction of the set of users defined by the operating system on the + * current server platform. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public interface UserDatabase { + + + // ----------------------------------------------------------- Properties + + + /** + * Return the UserConfig listener with which we are associated. + */ + public UserConfig getUserConfig(); + + + /** + * Set the UserConfig listener with which we are associated. + * + * @param userConfig The new UserConfig listener + */ + public void setUserConfig(UserConfig userConfig); + + + // ------------------------------------------------------- Public Methods + + + /** + * Return an absolute pathname to the home directory for the specified user. + * + * @param user User for which a home directory should be retrieved + */ + public String getHome(String user); + + + /** + * Return an enumeration of the usernames defined on this server. + */ + public Enumeration getUsers(); + + +} diff --git a/java/org/apache/catalina/startup/WebAnnotationSet.java b/java/org/apache/catalina/startup/WebAnnotationSet.java index f2261d13a..f9022584c 100644 --- a/java/org/apache/catalina/startup/WebAnnotationSet.java +++ b/java/org/apache/catalina/startup/WebAnnotationSet.java @@ -1,369 +1,369 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import javax.annotation.Resource; -import javax.annotation.Resources; -import javax.annotation.security.DeclareRoles; -import javax.annotation.security.RunAs; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.core.StandardWrapper; -import org.apache.catalina.deploy.ContextEnvironment; -import org.apache.catalina.deploy.ContextResource; -import org.apache.catalina.deploy.ContextResourceEnvRef; -import org.apache.catalina.deploy.ContextService; -import org.apache.catalina.deploy.FilterDef; -import org.apache.catalina.deploy.MessageDestinationRef; - -/** - *

        AnnotationSet for processing the annotations of the web application - * classes (/WEB-INF/classes and /WEB-INF/lib).

        - * - * @author Fabien Carrion - * @version $Revision: 304108 $ $Date: 2006-03-01 10:39:15 -0700 (Wed, 03 Mar 2006) $ - */ - -public class WebAnnotationSet { - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the annotations on a context. - */ - public static void loadApplicationAnnotations(Context context) { - - loadApplicationListenerAnnotations(context); - loadApplicationFilterAnnotations(context); - loadApplicationServletAnnotations(context); - - - } - - - // -------------------------------------------------------- protected Methods - - - /** - * Process the annotations for the listeners. - */ - protected static void loadApplicationListenerAnnotations(Context context) { - String[] applicationListeners = context.findApplicationListeners(); - for (int i = 0; i < applicationListeners.length; i++) { - loadClassAnnotation(context, applicationListeners[i]); - } - } - - - /** - * Process the annotations for the filters. - */ - protected static void loadApplicationFilterAnnotations(Context context) { - FilterDef[] filterDefs = context.findFilterDefs(); - for (int i = 0; i < filterDefs.length; i++) { - loadClassAnnotation(context, (filterDefs[i]).getFilterClass()); - } - } - - - /** - * Process the annotations for the servlets. - */ - protected static void loadApplicationServletAnnotations(Context context) { - - ClassLoader classLoader = context.getLoader().getClassLoader(); - StandardWrapper wrapper = null; - Class classClass = null; - - Container[] children = context.findChildren(); - for (int i = 0; i < children.length; i++) { - if (children[i] instanceof StandardWrapper) { - - wrapper = (StandardWrapper) children[i]; - if (wrapper.getServletClass() == null) { - continue; - } - - try { - classClass = classLoader.loadClass(wrapper.getServletClass()); - } catch (ClassNotFoundException e) { - // We do nothing - } catch (NoClassDefFoundError e) { - // We do nothing - } - - if (classClass == null) { - continue; - } - - loadClassAnnotation(context, wrapper.getServletClass()); - /* Process RunAs annotation which can be only on servlets. - * Ref JSR 250, equivalent to the run-as element in - * the deployment descriptor - */ - if (classClass.isAnnotationPresent(RunAs.class)) { - RunAs annotation = (RunAs) - classClass.getAnnotation(RunAs.class); - wrapper.setRunAs(annotation.value()); - } - } - } - - - } - - - /** - * Process the annotations on a context for a given className. - */ - protected static void loadClassAnnotation(Context context, String fileString) { - - ClassLoader classLoader = context.getLoader().getClassLoader(); - Class classClass = null; - - try { - classClass = classLoader.loadClass(fileString); - } catch (ClassNotFoundException e) { - // We do nothing - } catch (NoClassDefFoundError e) { - // We do nothing - } - - if (classClass == null) { - return; - } - - // Initialize the annotations - - if (classClass.isAnnotationPresent(Resource.class)) { - Resource annotation = (Resource) - classClass.getAnnotation(Resource.class); - addResource(context, annotation); - } - /* Process Resources annotation. - * Ref JSR 250 - */ - if (classClass.isAnnotationPresent(Resources.class)) { - Resources annotation = (Resources) - classClass.getAnnotation(Resources.class); - for (int i = 0; annotation.value() != null && i < annotation.value().length; i++) { - addResource(context, annotation.value()[i]); - } - } - /* Process EJB annotation. - * Ref JSR 224, equivalent to the ejb-ref or ejb-local-ref - * element in the deployment descriptor. - if (classClass.isAnnotationPresent(EJB.class)) { - EJB annotation = (EJB) - classClass.getAnnotation(EJB.class); - - if ((annotation.mappedName().length() == 0) || - annotation.mappedName().equals("Local")) { - - ContextLocalEjb ejb = new ContextLocalEjb(); - - ejb.setName(annotation.name()); - ejb.setType(annotation.beanInterface().getCanonicalName()); - ejb.setDescription(annotation.description()); - - ejb.setHome(annotation.beanName()); - - context.getNamingResources().addLocalEjb(ejb); - - } else if (annotation.mappedName().equals("Remote")) { - - ContextEjb ejb = new ContextEjb(); - - ejb.setName(annotation.name()); - ejb.setType(annotation.beanInterface().getCanonicalName()); - ejb.setDescription(annotation.description()); - - ejb.setHome(annotation.beanName()); - - context.getNamingResources().addEjb(ejb); - - } - - } - */ - /* Process WebServiceRef annotation. - * Ref JSR 224, equivalent to the service-ref element in - * the deployment descriptor. - * The service-ref registration is not implemented - if (classClass.isAnnotationPresent(WebServiceRef.class)) { - WebServiceRef annotation = (WebServiceRef) - classClass.getAnnotation(WebServiceRef.class); - - ContextService service = new ContextService(); - - service.setName(annotation.name()); - service.setWsdlfile(annotation.wsdlLocation()); - - service.setType(annotation.type().getCanonicalName()); - - if (annotation.value() == null) - service.setServiceinterface(annotation.type().getCanonicalName()); - - if (annotation.type().getCanonicalName().equals("Service")) - service.setServiceinterface(annotation.type().getCanonicalName()); - - if (annotation.value().getCanonicalName().equals("Endpoint")) - service.setServiceendpoint(annotation.type().getCanonicalName()); - - service.setPortlink(annotation.type().getCanonicalName()); - - context.getNamingResources().addService(service); - - - } - */ - /* Process DeclareRoles annotation. - * Ref JSR 250, equivalent to the security-role element in - * the deployment descriptor - */ - if (classClass.isAnnotationPresent(DeclareRoles.class)) { - DeclareRoles annotation = (DeclareRoles) - classClass.getAnnotation(DeclareRoles.class); - for (int i = 0; annotation.value() != null && i < annotation.value().length; i++) { - context.addSecurityRole(annotation.value()[i]); - } - } - - - } - - - /** - * Process a Resource annotation to set up a Resource. - * Ref JSR 250, equivalent to the resource-ref, - * message-destination-ref, env-ref, resource-env-ref - * or service-ref element in the deployment descriptor. - */ - protected static void addResource(Context context, Resource annotation) { - - if (annotation.type().getCanonicalName().equals("java.lang.String") || - annotation.type().getCanonicalName().equals("java.lang.Character") || - annotation.type().getCanonicalName().equals("java.lang.Integer") || - annotation.type().getCanonicalName().equals("java.lang.Boolean") || - annotation.type().getCanonicalName().equals("java.lang.Double") || - annotation.type().getCanonicalName().equals("java.lang.Byte") || - annotation.type().getCanonicalName().equals("java.lang.Short") || - annotation.type().getCanonicalName().equals("java.lang.Long") || - annotation.type().getCanonicalName().equals("java.lang.Float")) { - - // env-ref element - ContextEnvironment resource = new ContextEnvironment(); - - resource.setName(annotation.name()); - resource.setType(annotation.type().getCanonicalName()); - - resource.setDescription(annotation.description()); - - resource.setValue(annotation.mappedName()); - - context.getNamingResources().addEnvironment(resource); - - } else if (annotation.type().getCanonicalName().equals("javax.xml.rpc.Service")) { - - // service-ref element - ContextService service = new ContextService(); - - service.setName(annotation.name()); - service.setWsdlfile(annotation.mappedName()); - - service.setType(annotation.type().getCanonicalName()); - service.setDescription(annotation.description()); - - context.getNamingResources().addService(service); - - } else if (annotation.type().getCanonicalName().equals("javax.sql.DataSource") || - annotation.type().getCanonicalName().equals("javax.jms.ConnectionFactory") || - annotation.type().getCanonicalName() - .equals("javax.jms.QueueConnectionFactory") || - annotation.type().getCanonicalName() - .equals("javax.jms.TopicConnectionFactory") || - annotation.type().getCanonicalName().equals("javax.mail.Session") || - annotation.type().getCanonicalName().equals("java.net.URL") || - annotation.type().getCanonicalName() - .equals("javax.resource.cci.ConnectionFactory") || - annotation.type().getCanonicalName().equals("org.omg.CORBA_2_3.ORB") || - annotation.type().getCanonicalName().endsWith("ConnectionFactory")) { - - // resource-ref element - ContextResource resource = new ContextResource(); - - resource.setName(annotation.name()); - resource.setType(annotation.type().getCanonicalName()); - - if (annotation.authenticationType() - == Resource.AuthenticationType.CONTAINER) { - resource.setAuth("Container"); - } - else if (annotation.authenticationType() - == Resource.AuthenticationType.APPLICATION) { - resource.setAuth("Application"); - } - - resource.setScope(annotation.shareable() ? "Shareable" : "Unshareable"); - resource.setProperty("mappedName", annotation.mappedName()); - resource.setDescription(annotation.description()); - - context.getNamingResources().addResource(resource); - - } else if (annotation.type().getCanonicalName().equals("javax.jms.Queue") || - annotation.type().getCanonicalName().equals("javax.jms.Topic")) { - - // message-destination-ref - MessageDestinationRef resource = new MessageDestinationRef(); - - resource.setName(annotation.name()); - resource.setType(annotation.type().getCanonicalName()); - - resource.setUsage(annotation.mappedName()); - resource.setDescription(annotation.description()); - - context.getNamingResources().addMessageDestinationRef(resource); - - } else if (annotation.type().getCanonicalName() - .equals("javax.resource.cci.InteractionSpec") || - annotation.type().getCanonicalName() - .equals("javax.transaction.UserTransaction") || - true) { - - // resource-env-ref - ContextResourceEnvRef resource = new ContextResourceEnvRef(); - - resource.setName(annotation.name()); - resource.setType(annotation.type().getCanonicalName()); - - resource.setProperty("mappedName", annotation.mappedName()); - resource.setDescription(annotation.description()); - - context.getNamingResources().addResourceEnvRef(resource); - - } - - - } - - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import javax.annotation.Resource; +import javax.annotation.Resources; +import javax.annotation.security.DeclareRoles; +import javax.annotation.security.RunAs; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.core.StandardWrapper; +import org.apache.catalina.deploy.ContextEnvironment; +import org.apache.catalina.deploy.ContextResource; +import org.apache.catalina.deploy.ContextResourceEnvRef; +import org.apache.catalina.deploy.ContextService; +import org.apache.catalina.deploy.FilterDef; +import org.apache.catalina.deploy.MessageDestinationRef; + +/** + *

        AnnotationSet for processing the annotations of the web application + * classes (/WEB-INF/classes and /WEB-INF/lib).

        + * + * @author Fabien Carrion + * @version $Revision: 304108 $ $Date: 2006-03-01 10:39:15 -0700 (Wed, 03 Mar 2006) $ + */ + +public class WebAnnotationSet { + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the annotations on a context. + */ + public static void loadApplicationAnnotations(Context context) { + + loadApplicationListenerAnnotations(context); + loadApplicationFilterAnnotations(context); + loadApplicationServletAnnotations(context); + + + } + + + // -------------------------------------------------------- protected Methods + + + /** + * Process the annotations for the listeners. + */ + protected static void loadApplicationListenerAnnotations(Context context) { + String[] applicationListeners = context.findApplicationListeners(); + for (int i = 0; i < applicationListeners.length; i++) { + loadClassAnnotation(context, applicationListeners[i]); + } + } + + + /** + * Process the annotations for the filters. + */ + protected static void loadApplicationFilterAnnotations(Context context) { + FilterDef[] filterDefs = context.findFilterDefs(); + for (int i = 0; i < filterDefs.length; i++) { + loadClassAnnotation(context, (filterDefs[i]).getFilterClass()); + } + } + + + /** + * Process the annotations for the servlets. + */ + protected static void loadApplicationServletAnnotations(Context context) { + + ClassLoader classLoader = context.getLoader().getClassLoader(); + StandardWrapper wrapper = null; + Class classClass = null; + + Container[] children = context.findChildren(); + for (int i = 0; i < children.length; i++) { + if (children[i] instanceof StandardWrapper) { + + wrapper = (StandardWrapper) children[i]; + if (wrapper.getServletClass() == null) { + continue; + } + + try { + classClass = classLoader.loadClass(wrapper.getServletClass()); + } catch (ClassNotFoundException e) { + // We do nothing + } catch (NoClassDefFoundError e) { + // We do nothing + } + + if (classClass == null) { + continue; + } + + loadClassAnnotation(context, wrapper.getServletClass()); + /* Process RunAs annotation which can be only on servlets. + * Ref JSR 250, equivalent to the run-as element in + * the deployment descriptor + */ + if (classClass.isAnnotationPresent(RunAs.class)) { + RunAs annotation = (RunAs) + classClass.getAnnotation(RunAs.class); + wrapper.setRunAs(annotation.value()); + } + } + } + + + } + + + /** + * Process the annotations on a context for a given className. + */ + protected static void loadClassAnnotation(Context context, String fileString) { + + ClassLoader classLoader = context.getLoader().getClassLoader(); + Class classClass = null; + + try { + classClass = classLoader.loadClass(fileString); + } catch (ClassNotFoundException e) { + // We do nothing + } catch (NoClassDefFoundError e) { + // We do nothing + } + + if (classClass == null) { + return; + } + + // Initialize the annotations + + if (classClass.isAnnotationPresent(Resource.class)) { + Resource annotation = (Resource) + classClass.getAnnotation(Resource.class); + addResource(context, annotation); + } + /* Process Resources annotation. + * Ref JSR 250 + */ + if (classClass.isAnnotationPresent(Resources.class)) { + Resources annotation = (Resources) + classClass.getAnnotation(Resources.class); + for (int i = 0; annotation.value() != null && i < annotation.value().length; i++) { + addResource(context, annotation.value()[i]); + } + } + /* Process EJB annotation. + * Ref JSR 224, equivalent to the ejb-ref or ejb-local-ref + * element in the deployment descriptor. + if (classClass.isAnnotationPresent(EJB.class)) { + EJB annotation = (EJB) + classClass.getAnnotation(EJB.class); + + if ((annotation.mappedName().length() == 0) || + annotation.mappedName().equals("Local")) { + + ContextLocalEjb ejb = new ContextLocalEjb(); + + ejb.setName(annotation.name()); + ejb.setType(annotation.beanInterface().getCanonicalName()); + ejb.setDescription(annotation.description()); + + ejb.setHome(annotation.beanName()); + + context.getNamingResources().addLocalEjb(ejb); + + } else if (annotation.mappedName().equals("Remote")) { + + ContextEjb ejb = new ContextEjb(); + + ejb.setName(annotation.name()); + ejb.setType(annotation.beanInterface().getCanonicalName()); + ejb.setDescription(annotation.description()); + + ejb.setHome(annotation.beanName()); + + context.getNamingResources().addEjb(ejb); + + } + + } + */ + /* Process WebServiceRef annotation. + * Ref JSR 224, equivalent to the service-ref element in + * the deployment descriptor. + * The service-ref registration is not implemented + if (classClass.isAnnotationPresent(WebServiceRef.class)) { + WebServiceRef annotation = (WebServiceRef) + classClass.getAnnotation(WebServiceRef.class); + + ContextService service = new ContextService(); + + service.setName(annotation.name()); + service.setWsdlfile(annotation.wsdlLocation()); + + service.setType(annotation.type().getCanonicalName()); + + if (annotation.value() == null) + service.setServiceinterface(annotation.type().getCanonicalName()); + + if (annotation.type().getCanonicalName().equals("Service")) + service.setServiceinterface(annotation.type().getCanonicalName()); + + if (annotation.value().getCanonicalName().equals("Endpoint")) + service.setServiceendpoint(annotation.type().getCanonicalName()); + + service.setPortlink(annotation.type().getCanonicalName()); + + context.getNamingResources().addService(service); + + + } + */ + /* Process DeclareRoles annotation. + * Ref JSR 250, equivalent to the security-role element in + * the deployment descriptor + */ + if (classClass.isAnnotationPresent(DeclareRoles.class)) { + DeclareRoles annotation = (DeclareRoles) + classClass.getAnnotation(DeclareRoles.class); + for (int i = 0; annotation.value() != null && i < annotation.value().length; i++) { + context.addSecurityRole(annotation.value()[i]); + } + } + + + } + + + /** + * Process a Resource annotation to set up a Resource. + * Ref JSR 250, equivalent to the resource-ref, + * message-destination-ref, env-ref, resource-env-ref + * or service-ref element in the deployment descriptor. + */ + protected static void addResource(Context context, Resource annotation) { + + if (annotation.type().getCanonicalName().equals("java.lang.String") || + annotation.type().getCanonicalName().equals("java.lang.Character") || + annotation.type().getCanonicalName().equals("java.lang.Integer") || + annotation.type().getCanonicalName().equals("java.lang.Boolean") || + annotation.type().getCanonicalName().equals("java.lang.Double") || + annotation.type().getCanonicalName().equals("java.lang.Byte") || + annotation.type().getCanonicalName().equals("java.lang.Short") || + annotation.type().getCanonicalName().equals("java.lang.Long") || + annotation.type().getCanonicalName().equals("java.lang.Float")) { + + // env-ref element + ContextEnvironment resource = new ContextEnvironment(); + + resource.setName(annotation.name()); + resource.setType(annotation.type().getCanonicalName()); + + resource.setDescription(annotation.description()); + + resource.setValue(annotation.mappedName()); + + context.getNamingResources().addEnvironment(resource); + + } else if (annotation.type().getCanonicalName().equals("javax.xml.rpc.Service")) { + + // service-ref element + ContextService service = new ContextService(); + + service.setName(annotation.name()); + service.setWsdlfile(annotation.mappedName()); + + service.setType(annotation.type().getCanonicalName()); + service.setDescription(annotation.description()); + + context.getNamingResources().addService(service); + + } else if (annotation.type().getCanonicalName().equals("javax.sql.DataSource") || + annotation.type().getCanonicalName().equals("javax.jms.ConnectionFactory") || + annotation.type().getCanonicalName() + .equals("javax.jms.QueueConnectionFactory") || + annotation.type().getCanonicalName() + .equals("javax.jms.TopicConnectionFactory") || + annotation.type().getCanonicalName().equals("javax.mail.Session") || + annotation.type().getCanonicalName().equals("java.net.URL") || + annotation.type().getCanonicalName() + .equals("javax.resource.cci.ConnectionFactory") || + annotation.type().getCanonicalName().equals("org.omg.CORBA_2_3.ORB") || + annotation.type().getCanonicalName().endsWith("ConnectionFactory")) { + + // resource-ref element + ContextResource resource = new ContextResource(); + + resource.setName(annotation.name()); + resource.setType(annotation.type().getCanonicalName()); + + if (annotation.authenticationType() + == Resource.AuthenticationType.CONTAINER) { + resource.setAuth("Container"); + } + else if (annotation.authenticationType() + == Resource.AuthenticationType.APPLICATION) { + resource.setAuth("Application"); + } + + resource.setScope(annotation.shareable() ? "Shareable" : "Unshareable"); + resource.setProperty("mappedName", annotation.mappedName()); + resource.setDescription(annotation.description()); + + context.getNamingResources().addResource(resource); + + } else if (annotation.type().getCanonicalName().equals("javax.jms.Queue") || + annotation.type().getCanonicalName().equals("javax.jms.Topic")) { + + // message-destination-ref + MessageDestinationRef resource = new MessageDestinationRef(); + + resource.setName(annotation.name()); + resource.setType(annotation.type().getCanonicalName()); + + resource.setUsage(annotation.mappedName()); + resource.setDescription(annotation.description()); + + context.getNamingResources().addMessageDestinationRef(resource); + + } else if (annotation.type().getCanonicalName() + .equals("javax.resource.cci.InteractionSpec") || + annotation.type().getCanonicalName() + .equals("javax.transaction.UserTransaction") || + true) { + + // resource-env-ref + ContextResourceEnvRef resource = new ContextResourceEnvRef(); + + resource.setName(annotation.name()); + resource.setType(annotation.type().getCanonicalName()); + + resource.setProperty("mappedName", annotation.mappedName()); + resource.setDescription(annotation.description()); + + context.getNamingResources().addResourceEnvRef(resource); + + } + + + } + + +} diff --git a/java/org/apache/catalina/startup/WebRuleSet.java b/java/org/apache/catalina/startup/WebRuleSet.java index e0db69418..4ba55412a 100644 --- a/java/org/apache/catalina/startup/WebRuleSet.java +++ b/java/org/apache/catalina/startup/WebRuleSet.java @@ -1,793 +1,793 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.startup; - - -import java.lang.reflect.Method; -import java.util.ArrayList; - -import org.apache.catalina.Context; -import org.apache.catalina.Wrapper; -import org.apache.catalina.deploy.SecurityConstraint; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.digester.CallMethodRule; -import org.apache.tomcat.util.digester.CallParamRule; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.Rule; -import org.apache.tomcat.util.digester.RuleSetBase; -import org.xml.sax.Attributes; - - -/** - *

        RuleSet for processing the contents of a web application - * deployment descriptor (/WEB-INF/web.xml) resource.

        - * - * @author Craig R. McClanahan - * @version $Revision: 304108 $ $Date: 2005-09-29 07:55:15 +0200 (jeu., 29 sept. 2005) $ - */ - -public class WebRuleSet extends RuleSetBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The matching pattern prefix to use for recognizing our elements. - */ - protected String prefix = null; - - - /** - * The SetSessionConfig rule used to parse the web.xml - */ - protected SetSessionConfig sessionConfig; - - - /** - * The SetLoginConfig rule used to parse the web.xml - */ - protected SetLoginConfig loginConfig; - - - /** - * The SetJspConfig rule used to parse the web.xml - */ - protected SetJspConfig jspConfig; - - - // ------------------------------------------------------------ Constructor - - - /** - * Construct an instance of this RuleSet with the default - * matching pattern prefix. - */ - public WebRuleSet() { - - this(""); - - } - - - /** - * Construct an instance of this RuleSet with the specified - * matching pattern prefix. - * - * @param prefix Prefix for matching pattern rules (including the - * trailing slash character) - */ - public WebRuleSet(String prefix) { - - super(); - this.namespaceURI = null; - this.prefix = prefix; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance.

        - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester) { - sessionConfig = new SetSessionConfig(); - jspConfig = new SetJspConfig(); - loginConfig = new SetLoginConfig(); - - digester.addRule(prefix + "web-app", - new SetPublicIdRule("setPublicId")); - digester.addRule(prefix + "web-app", - new IgnoreAnnotationsRule()); - - digester.addCallMethod(prefix + "web-app/context-param", - "addParameter", 2); - digester.addCallParam(prefix + "web-app/context-param/param-name", 0); - digester.addCallParam(prefix + "web-app/context-param/param-value", 1); - - digester.addCallMethod(prefix + "web-app/display-name", - "setDisplayName", 0); - - digester.addRule(prefix + "web-app/distributable", - new SetDistributableRule()); - - digester.addObjectCreate(prefix + "web-app/ejb-local-ref", - "org.apache.catalina.deploy.ContextLocalEjb"); - digester.addRule(prefix + "web-app/ejb-local-ref", - new SetNextNamingRule("addLocalEjb", - "org.apache.catalina.deploy.ContextLocalEjb")); - - digester.addCallMethod(prefix + "web-app/ejb-local-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link", - "setLink", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/local", - "setLocal", 0); - digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home", - "setHome", 0); - - digester.addObjectCreate(prefix + "web-app/ejb-ref", - "org.apache.catalina.deploy.ContextEjb"); - digester.addRule(prefix + "web-app/ejb-ref", - new SetNextNamingRule("addEjb", - "org.apache.catalina.deploy.ContextEjb")); - - digester.addCallMethod(prefix + "web-app/ejb-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link", - "setLink", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/home", - "setHome", 0); - digester.addCallMethod(prefix + "web-app/ejb-ref/remote", - "setRemote", 0); - - digester.addObjectCreate(prefix + "web-app/env-entry", - "org.apache.catalina.deploy.ContextEnvironment"); - digester.addRule(prefix + "web-app/env-entry", - new SetNextNamingRule("addEnvironment", - "org.apache.catalina.deploy.ContextEnvironment")); - - digester.addCallMethod(prefix + "web-app/env-entry/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value", - "setValue", 0); - - digester.addObjectCreate(prefix + "web-app/error-page", - "org.apache.catalina.deploy.ErrorPage"); - digester.addSetNext(prefix + "web-app/error-page", - "addErrorPage", - "org.apache.catalina.deploy.ErrorPage"); - - digester.addCallMethod(prefix + "web-app/error-page/error-code", - "setErrorCode", 0); - digester.addCallMethod(prefix + "web-app/error-page/exception-type", - "setExceptionType", 0); - digester.addCallMethod(prefix + "web-app/error-page/location", - "setLocation", 0); - - digester.addObjectCreate(prefix + "web-app/filter", - "org.apache.catalina.deploy.FilterDef"); - digester.addSetNext(prefix + "web-app/filter", - "addFilterDef", - "org.apache.catalina.deploy.FilterDef"); - - digester.addCallMethod(prefix + "web-app/filter/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/filter/display-name", - "setDisplayName", 0); - digester.addCallMethod(prefix + "web-app/filter/filter-class", - "setFilterClass", 0); - digester.addCallMethod(prefix + "web-app/filter/filter-name", - "setFilterName", 0); - digester.addCallMethod(prefix + "web-app/filter/large-icon", - "setLargeIcon", 0); - digester.addCallMethod(prefix + "web-app/filter/small-icon", - "setSmallIcon", 0); - - digester.addCallMethod(prefix + "web-app/filter/init-param", - "addInitParameter", 2); - digester.addCallParam(prefix + "web-app/filter/init-param/param-name", - 0); - digester.addCallParam(prefix + "web-app/filter/init-param/param-value", - 1); - - digester.addObjectCreate(prefix + "web-app/filter-mapping", - "org.apache.catalina.deploy.FilterMap"); - digester.addSetNext(prefix + "web-app/filter-mapping", - "addFilterMap", - "org.apache.catalina.deploy.FilterMap"); - - digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name", - "setFilterName", 0); - digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name", - "addServletName", 0); - digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern", - "addURLPattern", 0); - - digester.addCallMethod(prefix + "web-app/filter-mapping/dispatcher", - "setDispatcher", 0); - - digester.addCallMethod(prefix + "web-app/listener/listener-class", - "addApplicationListener", 0); - - digester.addRule(prefix + "web-app/jsp-config", - jspConfig); - - digester.addCallMethod(prefix + "web-app/jsp-config/jsp-property-group/url-pattern", - "addJspMapping", 0); - - digester.addCallMethod(prefix + "web-app/listener/listener-class", - "addApplicationListener", 0); - - digester.addRule(prefix + "web-app/login-config", - loginConfig); - - digester.addObjectCreate(prefix + "web-app/login-config", - "org.apache.catalina.deploy.LoginConfig"); - digester.addSetNext(prefix + "web-app/login-config", - "setLoginConfig", - "org.apache.catalina.deploy.LoginConfig"); - - digester.addCallMethod(prefix + "web-app/login-config/auth-method", - "setAuthMethod", 0); - digester.addCallMethod(prefix + "web-app/login-config/realm-name", - "setRealmName", 0); - digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-error-page", - "setErrorPage", 0); - digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-login-page", - "setLoginPage", 0); - - digester.addCallMethod(prefix + "web-app/mime-mapping", - "addMimeMapping", 2); - digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0); - digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1); - - digester.addObjectCreate(prefix + "web-app/resource-env-ref", - "org.apache.catalina.deploy.ContextResourceEnvRef"); - digester.addRule(prefix + "web-app/resource-env-ref", - new SetNextNamingRule("addResourceEnvRef", - "org.apache.catalina.deploy.ContextResourceEnvRef")); - - digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-type", - "setType", 0); - - digester.addObjectCreate(prefix + "web-app/message-destination", - "org.apache.catalina.deploy.MessageDestination"); - digester.addSetNext(prefix + "web-app/message-destination", - "addMessageDestination", - "org.apache.catalina.deploy.MessageDestination"); - - digester.addCallMethod(prefix + "web-app/message-destination/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/message-destination/display-name", - "setDisplayName", 0); - digester.addCallMethod(prefix + "web-app/message-destination/icon/large-icon", - "setLargeIcon", 0); - digester.addCallMethod(prefix + "web-app/message-destination/icon/small-icon", - "setSmallIcon", 0); - digester.addCallMethod(prefix + "web-app/message-destination/message-destination-name", - "setName", 0); - - digester.addObjectCreate(prefix + "web-app/message-destination-ref", - "org.apache.catalina.deploy.MessageDestinationRef"); - digester.addSetNext(prefix + "web-app/message-destination-ref", - "addMessageDestinationRef", - "org.apache.catalina.deploy.MessageDestinationRef"); - - digester.addCallMethod(prefix + "web-app/message-destination-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-link", - "setLink", 0); - digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-type", - "setType", 0); - digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-usage", - "setUsage", 0); - - digester.addObjectCreate(prefix + "web-app/resource-ref", - "org.apache.catalina.deploy.ContextResource"); - digester.addRule(prefix + "web-app/resource-ref", - new SetNextNamingRule("addResource", - "org.apache.catalina.deploy.ContextResource")); - - digester.addCallMethod(prefix + "web-app/resource-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/resource-ref/res-auth", - "setAuth", 0); - digester.addCallMethod(prefix + "web-app/resource-ref/res-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/resource-ref/res-sharing-scope", - "setScope", 0); - digester.addCallMethod(prefix + "web-app/resource-ref/res-type", - "setType", 0); - - digester.addObjectCreate(prefix + "web-app/security-constraint", - "org.apache.catalina.deploy.SecurityConstraint"); - digester.addSetNext(prefix + "web-app/security-constraint", - "addConstraint", - "org.apache.catalina.deploy.SecurityConstraint"); - - digester.addRule(prefix + "web-app/security-constraint/auth-constraint", - new SetAuthConstraintRule()); - digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name", - "addAuthRole", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/display-name", - "setDisplayName", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee", - "setUserConstraint", 0); - - digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection", - "org.apache.catalina.deploy.SecurityCollection"); - digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection", - "addCollection", - "org.apache.catalina.deploy.SecurityCollection"); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method", - "addMethod", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern", - "addPattern", 0); - digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name", - "setName", 0); - - digester.addCallMethod(prefix + "web-app/security-role/role-name", - "addSecurityRole", 0); - - digester.addObjectCreate(prefix + "web-app/service-ref", - "org.apache.catalina.deploy.ContextService"); - digester.addRule(prefix + "web-app/service-ref", - new SetNextNamingRule("addService", - "org.apache.catalina.deploy.ContextService")); - - digester.addCallMethod(prefix + "web-app/service-ref/description", - "setDescription", 0); - digester.addCallMethod(prefix + "web-app/service-ref/display-name", - "setDisplayname", 0); - digester.addCallMethod(prefix + "web-app/service-ref/icon", - "setIcon", 0); - digester.addCallMethod(prefix + "web-app/service-ref/service-ref-name", - "setName", 0); - digester.addCallMethod(prefix + "web-app/service-ref/service-interface", - "setServiceinterface", 0); - digester.addCallMethod(prefix + "web-app/service-ref/wsdl-file", - "setWsdlfile", 0); - digester.addCallMethod(prefix + "web-app/service-ref/jaxrpc-mapping-file", - "setJaxrpcmappingfile", 0); - digester.addCallMethod(prefix + "web-app/service-ref/service-qname/namespaceURI", - "setNamespaceURI", 0); - digester.addCallMethod(prefix + "web-app/service-ref/service-qname/localpart", - "setLocalpart", 0); - digester.addCallMethod(prefix + - "web-app/service-ref/port-component/service-endpoint-interface", - "setServiceendpoint", 0); - digester.addCallMethod(prefix + "web-app/service-ref/port-component/port-component-link", - "setPortlink", 0); - digester.addCallMethod(prefix + "web-app/service-ref/handler", - "setHandler", 0); - digester.addCallMethod(prefix + "web-app/service-ref/service-ref-type", - "setType", 0); - - digester.addRule(prefix + "web-app/servlet", - new WrapperCreateRule()); - digester.addSetNext(prefix + "web-app/servlet", - "addChild", - "org.apache.catalina.Container"); - - digester.addCallMethod(prefix + "web-app/servlet/init-param", - "addInitParameter", 2); - digester.addCallParam(prefix + "web-app/servlet/init-param/param-name", - 0); - digester.addCallParam(prefix + "web-app/servlet/init-param/param-value", - 1); - - digester.addCallMethod(prefix + "web-app/servlet/jsp-file", - "setJspFile", 0); - digester.addCallMethod(prefix + "web-app/servlet/load-on-startup", - "setLoadOnStartupString", 0); - digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name", - "setRunAs", 0); - - digester.addCallMethod(prefix + "web-app/servlet/security-role-ref", - "addSecurityReference", 2); - digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1); - digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0); - - digester.addCallMethod(prefix + "web-app/servlet/servlet-class", - "setServletClass", 0); - digester.addCallMethod(prefix + "web-app/servlet/servlet-name", - "setName", 0); - - digester.addRule(prefix + "web-app/servlet-mapping", - new CallMethodMultiRule("addServletMapping", 2, 0)); - digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1); - digester.addRule(prefix + "web-app/servlet-mapping/url-pattern", new CallParamMultiRule(0)); - - digester.addRule(prefix + "web-app/session-config", - sessionConfig); - - digester.addCallMethod(prefix + "web-app/session-config/session-timeout", - "setSessionTimeout", 1, - new Class[] { Integer.TYPE }); - digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0); - - digester.addCallMethod(prefix + "web-app/taglib", - "addTaglib", 2); - digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1); - digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0); - - digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file", - "addWelcomeFile", 0); - - digester.addCallMethod(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping", - "addLocaleEncodingMappingParameter", 2); - digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0); - digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1); - - } - - /** - * Reset counter used for validating the web.xml file. - */ - public void recycle(){ - jspConfig.isJspConfigSet = false; - sessionConfig.isSessionConfigSet = false; - loginConfig.isLoginConfigSet = false; - } -} - - -// ----------------------------------------------------------- Private Classes - - -/** - * Rule to check that the login-config is occuring - * only 1 time within the web.xml - */ -final class SetLoginConfig extends Rule { - protected boolean isLoginConfigSet = false; - public SetLoginConfig() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - if (isLoginConfigSet){ - throw new IllegalArgumentException( - " element is limited to 1 occurance"); - } - isLoginConfigSet = true; - } - -} - - -/** - * Rule to check that the jsp-config is occuring - * only 1 time within the web.xml - */ -final class SetJspConfig extends Rule { - protected boolean isJspConfigSet = false; - public SetJspConfig() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - if (isJspConfigSet){ - throw new IllegalArgumentException( - " element is limited to 1 occurance"); - } - isJspConfigSet = true; - } - -} - - -/** - * Rule to check that the session-config is occuring - * only 1 time within the web.xml - */ -final class SetSessionConfig extends Rule { - protected boolean isSessionConfigSet = false; - public SetSessionConfig() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - if (isSessionConfigSet){ - throw new IllegalArgumentException( - " element is limited to 1 occurance"); - } - isSessionConfigSet = true; - } - -} - -/** - * A Rule that calls the setAuthConstraint(true) method of - * the top item on the stack, which must be of type - * org.apache.catalina.deploy.SecurityConstraint. - */ - -final class SetAuthConstraintRule extends Rule { - - public SetAuthConstraintRule() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - SecurityConstraint securityConstraint = - (SecurityConstraint) digester.peek(); - securityConstraint.setAuthConstraint(true); - if (digester.getLogger().isDebugEnabled()) { - digester.getLogger() - .debug("Calling SecurityConstraint.setAuthConstraint(true)"); - } - } - -} - - -/** - * Class that calls setDistributable(true) for the top object - * on the stack, which must be a org.apache.catalina.Context. - */ - -final class SetDistributableRule extends Rule { - - public SetDistributableRule() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - Context context = (Context) digester.peek(); - context.setDistributable(true); - if (digester.getLogger().isDebugEnabled()) { - digester.getLogger().debug - (context.getClass().getName() + ".setDistributable( true)"); - } - } - -} - - -/** - * Class that calls a property setter for the top object on the stack, - * passing the public ID of the entity we are currently processing. - */ - -final class SetPublicIdRule extends Rule { - - public SetPublicIdRule(String method) { - this.method = method; - } - - private String method = null; - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - Context context = (Context) digester.peek(digester.getCount() - 1); - Object top = digester.peek(); - Class paramClasses[] = new Class[1]; - paramClasses[0] = "String".getClass(); - String paramValues[] = new String[1]; - paramValues[0] = digester.getPublicId(); - - Method m = null; - try { - m = top.getClass().getMethod(method, paramClasses); - } catch (NoSuchMethodException e) { - digester.getLogger().error("Can't find method " + method + " in " - + top + " CLASS " + top.getClass()); - return; - } - - m.invoke(top, (Object [])paramValues); - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("" + top.getClass().getName() + "." - + method + "(" + paramValues[0] + ")"); - - } - -} - - -/** - * A Rule that calls the factory method on the specified Context to - * create the object that is to be added to the stack. - */ - -final class WrapperCreateRule extends Rule { - - public WrapperCreateRule() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - Context context = - (Context) digester.peek(digester.getCount() - 1); - Wrapper wrapper = context.createWrapper(); - digester.push(wrapper); - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("new " + wrapper.getClass().getName()); - } - - public void end(String namespace, String name) - throws Exception { - Wrapper wrapper = (Wrapper) digester.pop(); - if (digester.getLogger().isDebugEnabled()) - digester.getLogger().debug("pop " + wrapper.getClass().getName()); - } - -} - - -/** - * A Rule that can be used to call multiple times a method as many times as needed - * (used for addServletMapping). - */ -final class CallParamMultiRule extends CallParamRule { - - public CallParamMultiRule(int paramIndex) { - super(paramIndex); - } - - public void end(String namespace, String name) { - if (bodyTextStack != null && !bodyTextStack.empty()) { - // what we do now is push one parameter onto the top set of parameters - Object parameters[] = (Object[]) digester.peekParams(); - ArrayList params = (ArrayList) parameters[paramIndex]; - if (params == null) { - params = new ArrayList(); - parameters[paramIndex] = params; - } - params.add(bodyTextStack.pop()); - } - } - -} - - -/** - * A Rule that can be used to call multiple times a method as many times as needed - * (used for addServletMapping). - */ -final class CallMethodMultiRule extends CallMethodRule { - - protected int multiParamIndex = 0; - - public CallMethodMultiRule(String methodName, int paramCount, int multiParamIndex) { - super(methodName, paramCount); - this.multiParamIndex = multiParamIndex; - } - - public void end() throws Exception { - - // Retrieve or construct the parameter values array - Object parameters[] = null; - if (paramCount > 0) { - parameters = (Object[]) digester.popParams(); - } else { - super.end(); - } - - ArrayList multiParams = (ArrayList) parameters[multiParamIndex]; - - // Construct the parameter values array we will need - // We only do the conversion if the param value is a String and - // the specified paramType is not String. - Object paramValues[] = new Object[paramTypes.length]; - for (int i = 0; i < paramTypes.length; i++) { - if (i != multiParamIndex) { - // convert nulls and convert stringy parameters - // for non-stringy param types - if(parameters[i] == null || (parameters[i] instanceof String - && !String.class.isAssignableFrom(paramTypes[i]))) { - paramValues[i] = - IntrospectionUtils.convert((String) parameters[i], paramTypes[i]); - } else { - paramValues[i] = parameters[i]; - } - } - } - - // Determine the target object for the method call - Object target; - if (targetOffset >= 0) { - target = digester.peek(targetOffset); - } else { - target = digester.peek(digester.getCount() + targetOffset); - } - - if (target == null) { - StringBuffer sb = new StringBuffer(); - sb.append("[CallMethodRule]{"); - sb.append(""); - sb.append("} Call target is null ("); - sb.append("targetOffset="); - sb.append(targetOffset); - sb.append(",stackdepth="); - sb.append(digester.getCount()); - sb.append(")"); - throw new org.xml.sax.SAXException(sb.toString()); - } - - for (int j = 0; j < multiParams.size(); j++) { - Object param = multiParams.get(j); - if(param == null || (param instanceof String - && !String.class.isAssignableFrom(paramTypes[multiParamIndex]))) { - paramValues[multiParamIndex] = - IntrospectionUtils.convert((String) param, paramTypes[multiParamIndex]); - } else { - paramValues[multiParamIndex] = param; - } - Object result = IntrospectionUtils.callMethodN(target, methodName, - paramValues, paramTypes); - } - - } - -} - - - -/** - * A Rule that check if the annotations have to be loaded. - * - */ - -final class IgnoreAnnotationsRule extends Rule { - - public IgnoreAnnotationsRule() { - } - - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - Context context = (Context) digester.peek(digester.getCount() - 1); - String value = attributes.getValue("metadata-complete"); - if ("true".equals(value)) { - context.setIgnoreAnnotations(true); - } - if (digester.getLogger().isDebugEnabled()) { - digester.getLogger().debug - (context.getClass().getName() + ".setIgnoreAnnotations( " + - context.getIgnoreAnnotations() + ")"); - } - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.startup; + + +import java.lang.reflect.Method; +import java.util.ArrayList; + +import org.apache.catalina.Context; +import org.apache.catalina.Wrapper; +import org.apache.catalina.deploy.SecurityConstraint; +import org.apache.tomcat.util.IntrospectionUtils; +import org.apache.tomcat.util.digester.CallMethodRule; +import org.apache.tomcat.util.digester.CallParamRule; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.Rule; +import org.apache.tomcat.util.digester.RuleSetBase; +import org.xml.sax.Attributes; + + +/** + *

        RuleSet for processing the contents of a web application + * deployment descriptor (/WEB-INF/web.xml) resource.

        + * + * @author Craig R. McClanahan + * @version $Revision: 304108 $ $Date: 2005-09-29 07:55:15 +0200 (jeu., 29 sept. 2005) $ + */ + +public class WebRuleSet extends RuleSetBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The matching pattern prefix to use for recognizing our elements. + */ + protected String prefix = null; + + + /** + * The SetSessionConfig rule used to parse the web.xml + */ + protected SetSessionConfig sessionConfig; + + + /** + * The SetLoginConfig rule used to parse the web.xml + */ + protected SetLoginConfig loginConfig; + + + /** + * The SetJspConfig rule used to parse the web.xml + */ + protected SetJspConfig jspConfig; + + + // ------------------------------------------------------------ Constructor + + + /** + * Construct an instance of this RuleSet with the default + * matching pattern prefix. + */ + public WebRuleSet() { + + this(""); + + } + + + /** + * Construct an instance of this RuleSet with the specified + * matching pattern prefix. + * + * @param prefix Prefix for matching pattern rules (including the + * trailing slash character) + */ + public WebRuleSet(String prefix) { + + super(); + this.namespaceURI = null; + this.prefix = prefix; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance.

        + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester) { + sessionConfig = new SetSessionConfig(); + jspConfig = new SetJspConfig(); + loginConfig = new SetLoginConfig(); + + digester.addRule(prefix + "web-app", + new SetPublicIdRule("setPublicId")); + digester.addRule(prefix + "web-app", + new IgnoreAnnotationsRule()); + + digester.addCallMethod(prefix + "web-app/context-param", + "addParameter", 2); + digester.addCallParam(prefix + "web-app/context-param/param-name", 0); + digester.addCallParam(prefix + "web-app/context-param/param-value", 1); + + digester.addCallMethod(prefix + "web-app/display-name", + "setDisplayName", 0); + + digester.addRule(prefix + "web-app/distributable", + new SetDistributableRule()); + + digester.addObjectCreate(prefix + "web-app/ejb-local-ref", + "org.apache.catalina.deploy.ContextLocalEjb"); + digester.addRule(prefix + "web-app/ejb-local-ref", + new SetNextNamingRule("addLocalEjb", + "org.apache.catalina.deploy.ContextLocalEjb")); + + digester.addCallMethod(prefix + "web-app/ejb-local-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-link", + "setLink", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/ejb-ref-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/local", + "setLocal", 0); + digester.addCallMethod(prefix + "web-app/ejb-local-ref/local-home", + "setHome", 0); + + digester.addObjectCreate(prefix + "web-app/ejb-ref", + "org.apache.catalina.deploy.ContextEjb"); + digester.addRule(prefix + "web-app/ejb-ref", + new SetNextNamingRule("addEjb", + "org.apache.catalina.deploy.ContextEjb")); + + digester.addCallMethod(prefix + "web-app/ejb-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-link", + "setLink", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/ejb-ref-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/home", + "setHome", 0); + digester.addCallMethod(prefix + "web-app/ejb-ref/remote", + "setRemote", 0); + + digester.addObjectCreate(prefix + "web-app/env-entry", + "org.apache.catalina.deploy.ContextEnvironment"); + digester.addRule(prefix + "web-app/env-entry", + new SetNextNamingRule("addEnvironment", + "org.apache.catalina.deploy.ContextEnvironment")); + + digester.addCallMethod(prefix + "web-app/env-entry/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/env-entry/env-entry-value", + "setValue", 0); + + digester.addObjectCreate(prefix + "web-app/error-page", + "org.apache.catalina.deploy.ErrorPage"); + digester.addSetNext(prefix + "web-app/error-page", + "addErrorPage", + "org.apache.catalina.deploy.ErrorPage"); + + digester.addCallMethod(prefix + "web-app/error-page/error-code", + "setErrorCode", 0); + digester.addCallMethod(prefix + "web-app/error-page/exception-type", + "setExceptionType", 0); + digester.addCallMethod(prefix + "web-app/error-page/location", + "setLocation", 0); + + digester.addObjectCreate(prefix + "web-app/filter", + "org.apache.catalina.deploy.FilterDef"); + digester.addSetNext(prefix + "web-app/filter", + "addFilterDef", + "org.apache.catalina.deploy.FilterDef"); + + digester.addCallMethod(prefix + "web-app/filter/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/filter/display-name", + "setDisplayName", 0); + digester.addCallMethod(prefix + "web-app/filter/filter-class", + "setFilterClass", 0); + digester.addCallMethod(prefix + "web-app/filter/filter-name", + "setFilterName", 0); + digester.addCallMethod(prefix + "web-app/filter/large-icon", + "setLargeIcon", 0); + digester.addCallMethod(prefix + "web-app/filter/small-icon", + "setSmallIcon", 0); + + digester.addCallMethod(prefix + "web-app/filter/init-param", + "addInitParameter", 2); + digester.addCallParam(prefix + "web-app/filter/init-param/param-name", + 0); + digester.addCallParam(prefix + "web-app/filter/init-param/param-value", + 1); + + digester.addObjectCreate(prefix + "web-app/filter-mapping", + "org.apache.catalina.deploy.FilterMap"); + digester.addSetNext(prefix + "web-app/filter-mapping", + "addFilterMap", + "org.apache.catalina.deploy.FilterMap"); + + digester.addCallMethod(prefix + "web-app/filter-mapping/filter-name", + "setFilterName", 0); + digester.addCallMethod(prefix + "web-app/filter-mapping/servlet-name", + "addServletName", 0); + digester.addCallMethod(prefix + "web-app/filter-mapping/url-pattern", + "addURLPattern", 0); + + digester.addCallMethod(prefix + "web-app/filter-mapping/dispatcher", + "setDispatcher", 0); + + digester.addCallMethod(prefix + "web-app/listener/listener-class", + "addApplicationListener", 0); + + digester.addRule(prefix + "web-app/jsp-config", + jspConfig); + + digester.addCallMethod(prefix + "web-app/jsp-config/jsp-property-group/url-pattern", + "addJspMapping", 0); + + digester.addCallMethod(prefix + "web-app/listener/listener-class", + "addApplicationListener", 0); + + digester.addRule(prefix + "web-app/login-config", + loginConfig); + + digester.addObjectCreate(prefix + "web-app/login-config", + "org.apache.catalina.deploy.LoginConfig"); + digester.addSetNext(prefix + "web-app/login-config", + "setLoginConfig", + "org.apache.catalina.deploy.LoginConfig"); + + digester.addCallMethod(prefix + "web-app/login-config/auth-method", + "setAuthMethod", 0); + digester.addCallMethod(prefix + "web-app/login-config/realm-name", + "setRealmName", 0); + digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-error-page", + "setErrorPage", 0); + digester.addCallMethod(prefix + "web-app/login-config/form-login-config/form-login-page", + "setLoginPage", 0); + + digester.addCallMethod(prefix + "web-app/mime-mapping", + "addMimeMapping", 2); + digester.addCallParam(prefix + "web-app/mime-mapping/extension", 0); + digester.addCallParam(prefix + "web-app/mime-mapping/mime-type", 1); + + digester.addObjectCreate(prefix + "web-app/resource-env-ref", + "org.apache.catalina.deploy.ContextResourceEnvRef"); + digester.addRule(prefix + "web-app/resource-env-ref", + new SetNextNamingRule("addResourceEnvRef", + "org.apache.catalina.deploy.ContextResourceEnvRef")); + + digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/resource-env-ref/resource-env-ref-type", + "setType", 0); + + digester.addObjectCreate(prefix + "web-app/message-destination", + "org.apache.catalina.deploy.MessageDestination"); + digester.addSetNext(prefix + "web-app/message-destination", + "addMessageDestination", + "org.apache.catalina.deploy.MessageDestination"); + + digester.addCallMethod(prefix + "web-app/message-destination/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/message-destination/display-name", + "setDisplayName", 0); + digester.addCallMethod(prefix + "web-app/message-destination/icon/large-icon", + "setLargeIcon", 0); + digester.addCallMethod(prefix + "web-app/message-destination/icon/small-icon", + "setSmallIcon", 0); + digester.addCallMethod(prefix + "web-app/message-destination/message-destination-name", + "setName", 0); + + digester.addObjectCreate(prefix + "web-app/message-destination-ref", + "org.apache.catalina.deploy.MessageDestinationRef"); + digester.addSetNext(prefix + "web-app/message-destination-ref", + "addMessageDestinationRef", + "org.apache.catalina.deploy.MessageDestinationRef"); + + digester.addCallMethod(prefix + "web-app/message-destination-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-link", + "setLink", 0); + digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-type", + "setType", 0); + digester.addCallMethod(prefix + "web-app/message-destination-ref/message-destination-usage", + "setUsage", 0); + + digester.addObjectCreate(prefix + "web-app/resource-ref", + "org.apache.catalina.deploy.ContextResource"); + digester.addRule(prefix + "web-app/resource-ref", + new SetNextNamingRule("addResource", + "org.apache.catalina.deploy.ContextResource")); + + digester.addCallMethod(prefix + "web-app/resource-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/resource-ref/res-auth", + "setAuth", 0); + digester.addCallMethod(prefix + "web-app/resource-ref/res-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/resource-ref/res-sharing-scope", + "setScope", 0); + digester.addCallMethod(prefix + "web-app/resource-ref/res-type", + "setType", 0); + + digester.addObjectCreate(prefix + "web-app/security-constraint", + "org.apache.catalina.deploy.SecurityConstraint"); + digester.addSetNext(prefix + "web-app/security-constraint", + "addConstraint", + "org.apache.catalina.deploy.SecurityConstraint"); + + digester.addRule(prefix + "web-app/security-constraint/auth-constraint", + new SetAuthConstraintRule()); + digester.addCallMethod(prefix + "web-app/security-constraint/auth-constraint/role-name", + "addAuthRole", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/display-name", + "setDisplayName", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/user-data-constraint/transport-guarantee", + "setUserConstraint", 0); + + digester.addObjectCreate(prefix + "web-app/security-constraint/web-resource-collection", + "org.apache.catalina.deploy.SecurityCollection"); + digester.addSetNext(prefix + "web-app/security-constraint/web-resource-collection", + "addCollection", + "org.apache.catalina.deploy.SecurityCollection"); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/http-method", + "addMethod", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/url-pattern", + "addPattern", 0); + digester.addCallMethod(prefix + "web-app/security-constraint/web-resource-collection/web-resource-name", + "setName", 0); + + digester.addCallMethod(prefix + "web-app/security-role/role-name", + "addSecurityRole", 0); + + digester.addObjectCreate(prefix + "web-app/service-ref", + "org.apache.catalina.deploy.ContextService"); + digester.addRule(prefix + "web-app/service-ref", + new SetNextNamingRule("addService", + "org.apache.catalina.deploy.ContextService")); + + digester.addCallMethod(prefix + "web-app/service-ref/description", + "setDescription", 0); + digester.addCallMethod(prefix + "web-app/service-ref/display-name", + "setDisplayname", 0); + digester.addCallMethod(prefix + "web-app/service-ref/icon", + "setIcon", 0); + digester.addCallMethod(prefix + "web-app/service-ref/service-ref-name", + "setName", 0); + digester.addCallMethod(prefix + "web-app/service-ref/service-interface", + "setServiceinterface", 0); + digester.addCallMethod(prefix + "web-app/service-ref/wsdl-file", + "setWsdlfile", 0); + digester.addCallMethod(prefix + "web-app/service-ref/jaxrpc-mapping-file", + "setJaxrpcmappingfile", 0); + digester.addCallMethod(prefix + "web-app/service-ref/service-qname/namespaceURI", + "setNamespaceURI", 0); + digester.addCallMethod(prefix + "web-app/service-ref/service-qname/localpart", + "setLocalpart", 0); + digester.addCallMethod(prefix + + "web-app/service-ref/port-component/service-endpoint-interface", + "setServiceendpoint", 0); + digester.addCallMethod(prefix + "web-app/service-ref/port-component/port-component-link", + "setPortlink", 0); + digester.addCallMethod(prefix + "web-app/service-ref/handler", + "setHandler", 0); + digester.addCallMethod(prefix + "web-app/service-ref/service-ref-type", + "setType", 0); + + digester.addRule(prefix + "web-app/servlet", + new WrapperCreateRule()); + digester.addSetNext(prefix + "web-app/servlet", + "addChild", + "org.apache.catalina.Container"); + + digester.addCallMethod(prefix + "web-app/servlet/init-param", + "addInitParameter", 2); + digester.addCallParam(prefix + "web-app/servlet/init-param/param-name", + 0); + digester.addCallParam(prefix + "web-app/servlet/init-param/param-value", + 1); + + digester.addCallMethod(prefix + "web-app/servlet/jsp-file", + "setJspFile", 0); + digester.addCallMethod(prefix + "web-app/servlet/load-on-startup", + "setLoadOnStartupString", 0); + digester.addCallMethod(prefix + "web-app/servlet/run-as/role-name", + "setRunAs", 0); + + digester.addCallMethod(prefix + "web-app/servlet/security-role-ref", + "addSecurityReference", 2); + digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-link", 1); + digester.addCallParam(prefix + "web-app/servlet/security-role-ref/role-name", 0); + + digester.addCallMethod(prefix + "web-app/servlet/servlet-class", + "setServletClass", 0); + digester.addCallMethod(prefix + "web-app/servlet/servlet-name", + "setName", 0); + + digester.addRule(prefix + "web-app/servlet-mapping", + new CallMethodMultiRule("addServletMapping", 2, 0)); + digester.addCallParam(prefix + "web-app/servlet-mapping/servlet-name", 1); + digester.addRule(prefix + "web-app/servlet-mapping/url-pattern", new CallParamMultiRule(0)); + + digester.addRule(prefix + "web-app/session-config", + sessionConfig); + + digester.addCallMethod(prefix + "web-app/session-config/session-timeout", + "setSessionTimeout", 1, + new Class[] { Integer.TYPE }); + digester.addCallParam(prefix + "web-app/session-config/session-timeout", 0); + + digester.addCallMethod(prefix + "web-app/taglib", + "addTaglib", 2); + digester.addCallParam(prefix + "web-app/taglib/taglib-location", 1); + digester.addCallParam(prefix + "web-app/taglib/taglib-uri", 0); + + digester.addCallMethod(prefix + "web-app/welcome-file-list/welcome-file", + "addWelcomeFile", 0); + + digester.addCallMethod(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping", + "addLocaleEncodingMappingParameter", 2); + digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/locale", 0); + digester.addCallParam(prefix + "web-app/locale-encoding-mapping-list/locale-encoding-mapping/encoding", 1); + + } + + /** + * Reset counter used for validating the web.xml file. + */ + public void recycle(){ + jspConfig.isJspConfigSet = false; + sessionConfig.isSessionConfigSet = false; + loginConfig.isLoginConfigSet = false; + } +} + + +// ----------------------------------------------------------- Private Classes + + +/** + * Rule to check that the login-config is occuring + * only 1 time within the web.xml + */ +final class SetLoginConfig extends Rule { + protected boolean isLoginConfigSet = false; + public SetLoginConfig() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + if (isLoginConfigSet){ + throw new IllegalArgumentException( + " element is limited to 1 occurance"); + } + isLoginConfigSet = true; + } + +} + + +/** + * Rule to check that the jsp-config is occuring + * only 1 time within the web.xml + */ +final class SetJspConfig extends Rule { + protected boolean isJspConfigSet = false; + public SetJspConfig() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + if (isJspConfigSet){ + throw new IllegalArgumentException( + " element is limited to 1 occurance"); + } + isJspConfigSet = true; + } + +} + + +/** + * Rule to check that the session-config is occuring + * only 1 time within the web.xml + */ +final class SetSessionConfig extends Rule { + protected boolean isSessionConfigSet = false; + public SetSessionConfig() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + if (isSessionConfigSet){ + throw new IllegalArgumentException( + " element is limited to 1 occurance"); + } + isSessionConfigSet = true; + } + +} + +/** + * A Rule that calls the setAuthConstraint(true) method of + * the top item on the stack, which must be of type + * org.apache.catalina.deploy.SecurityConstraint. + */ + +final class SetAuthConstraintRule extends Rule { + + public SetAuthConstraintRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + SecurityConstraint securityConstraint = + (SecurityConstraint) digester.peek(); + securityConstraint.setAuthConstraint(true); + if (digester.getLogger().isDebugEnabled()) { + digester.getLogger() + .debug("Calling SecurityConstraint.setAuthConstraint(true)"); + } + } + +} + + +/** + * Class that calls setDistributable(true) for the top object + * on the stack, which must be a org.apache.catalina.Context. + */ + +final class SetDistributableRule extends Rule { + + public SetDistributableRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + Context context = (Context) digester.peek(); + context.setDistributable(true); + if (digester.getLogger().isDebugEnabled()) { + digester.getLogger().debug + (context.getClass().getName() + ".setDistributable( true)"); + } + } + +} + + +/** + * Class that calls a property setter for the top object on the stack, + * passing the public ID of the entity we are currently processing. + */ + +final class SetPublicIdRule extends Rule { + + public SetPublicIdRule(String method) { + this.method = method; + } + + private String method = null; + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + Context context = (Context) digester.peek(digester.getCount() - 1); + Object top = digester.peek(); + Class paramClasses[] = new Class[1]; + paramClasses[0] = "String".getClass(); + String paramValues[] = new String[1]; + paramValues[0] = digester.getPublicId(); + + Method m = null; + try { + m = top.getClass().getMethod(method, paramClasses); + } catch (NoSuchMethodException e) { + digester.getLogger().error("Can't find method " + method + " in " + + top + " CLASS " + top.getClass()); + return; + } + + m.invoke(top, (Object [])paramValues); + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("" + top.getClass().getName() + "." + + method + "(" + paramValues[0] + ")"); + + } + +} + + +/** + * A Rule that calls the factory method on the specified Context to + * create the object that is to be added to the stack. + */ + +final class WrapperCreateRule extends Rule { + + public WrapperCreateRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + Context context = + (Context) digester.peek(digester.getCount() - 1); + Wrapper wrapper = context.createWrapper(); + digester.push(wrapper); + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("new " + wrapper.getClass().getName()); + } + + public void end(String namespace, String name) + throws Exception { + Wrapper wrapper = (Wrapper) digester.pop(); + if (digester.getLogger().isDebugEnabled()) + digester.getLogger().debug("pop " + wrapper.getClass().getName()); + } + +} + + +/** + * A Rule that can be used to call multiple times a method as many times as needed + * (used for addServletMapping). + */ +final class CallParamMultiRule extends CallParamRule { + + public CallParamMultiRule(int paramIndex) { + super(paramIndex); + } + + public void end(String namespace, String name) { + if (bodyTextStack != null && !bodyTextStack.empty()) { + // what we do now is push one parameter onto the top set of parameters + Object parameters[] = (Object[]) digester.peekParams(); + ArrayList params = (ArrayList) parameters[paramIndex]; + if (params == null) { + params = new ArrayList(); + parameters[paramIndex] = params; + } + params.add(bodyTextStack.pop()); + } + } + +} + + +/** + * A Rule that can be used to call multiple times a method as many times as needed + * (used for addServletMapping). + */ +final class CallMethodMultiRule extends CallMethodRule { + + protected int multiParamIndex = 0; + + public CallMethodMultiRule(String methodName, int paramCount, int multiParamIndex) { + super(methodName, paramCount); + this.multiParamIndex = multiParamIndex; + } + + public void end() throws Exception { + + // Retrieve or construct the parameter values array + Object parameters[] = null; + if (paramCount > 0) { + parameters = (Object[]) digester.popParams(); + } else { + super.end(); + } + + ArrayList multiParams = (ArrayList) parameters[multiParamIndex]; + + // Construct the parameter values array we will need + // We only do the conversion if the param value is a String and + // the specified paramType is not String. + Object paramValues[] = new Object[paramTypes.length]; + for (int i = 0; i < paramTypes.length; i++) { + if (i != multiParamIndex) { + // convert nulls and convert stringy parameters + // for non-stringy param types + if(parameters[i] == null || (parameters[i] instanceof String + && !String.class.isAssignableFrom(paramTypes[i]))) { + paramValues[i] = + IntrospectionUtils.convert((String) parameters[i], paramTypes[i]); + } else { + paramValues[i] = parameters[i]; + } + } + } + + // Determine the target object for the method call + Object target; + if (targetOffset >= 0) { + target = digester.peek(targetOffset); + } else { + target = digester.peek(digester.getCount() + targetOffset); + } + + if (target == null) { + StringBuffer sb = new StringBuffer(); + sb.append("[CallMethodRule]{"); + sb.append(""); + sb.append("} Call target is null ("); + sb.append("targetOffset="); + sb.append(targetOffset); + sb.append(",stackdepth="); + sb.append(digester.getCount()); + sb.append(")"); + throw new org.xml.sax.SAXException(sb.toString()); + } + + for (int j = 0; j < multiParams.size(); j++) { + Object param = multiParams.get(j); + if(param == null || (param instanceof String + && !String.class.isAssignableFrom(paramTypes[multiParamIndex]))) { + paramValues[multiParamIndex] = + IntrospectionUtils.convert((String) param, paramTypes[multiParamIndex]); + } else { + paramValues[multiParamIndex] = param; + } + Object result = IntrospectionUtils.callMethodN(target, methodName, + paramValues, paramTypes); + } + + } + +} + + + +/** + * A Rule that check if the annotations have to be loaded. + * + */ + +final class IgnoreAnnotationsRule extends Rule { + + public IgnoreAnnotationsRule() { + } + + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + Context context = (Context) digester.peek(digester.getCount() - 1); + String value = attributes.getValue("metadata-complete"); + if ("true".equals(value)) { + context.setIgnoreAnnotations(true); + } + if (digester.getLogger().isDebugEnabled()) { + digester.getLogger().debug + (context.getClass().getName() + ".setIgnoreAnnotations( " + + context.getIgnoreAnnotations() + ")"); + } + } + +} diff --git a/java/org/apache/catalina/startup/catalina.properties b/java/org/apache/catalina/startup/catalina.properties index 1d8ea08cb..a560e307b 100644 --- a/java/org/apache/catalina/startup/catalina.properties +++ b/java/org/apache/catalina/startup/catalina.properties @@ -1,66 +1,66 @@ -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageAccess unless the -# corresponding RuntimePermission ("accessClassInPackage."+package) has -# been granted. -package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans. -# -# List of comma-separated packages that start with or equal this string -# will cause a security exception to be thrown when -# passed to checkPackageDefinition unless the -# corresponding RuntimePermission ("defineClassInPackage."+package) has -# been granted. -# -# by default, no packages are restricted for definition, and none of -# the class loaders supplied with the JDK call checkPackageDefinition. -# -package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper. - -# -# -# List of comma-separated paths defining the contents of the "common" -# classloader. Prefixes should be used to define what is the repository type. -# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. -# If left as blank,the JVM system loader will be used as Catalina's "common" -# loader. -# Examples: -# "foo": Add this folder as a class repository -# "foo/*.jar": Add all the JARs of the specified folder as class -# repositories -# "foo/bar.jar": Add bar.jar as a class repository -common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar - -# -# List of comma-separated paths defining the contents of the "server" -# classloader. Prefixes should be used to define what is the repository type. -# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. -# If left as blank, the "common" loader will be used as Catalina's "server" -# loader. -# Examples: -# "foo": Add this folder as a class repository -# "foo/*.jar": Add all the JARs of the specified folder as class -# repositories -# "foo/bar.jar": Add bar.jar as a class repository -server.loader= - -# -# List of comma-separated paths defining the contents of the "shared" -# classloader. Prefixes should be used to define what is the repository type. -# Path may be relative to the CATALINA_BASE path or absolute. If left as blank, -# the "common" loader will be used as Catalina's "shared" loader. -# Examples: -# "foo": Add this folder as a class repository -# "foo/*.jar": Add all the JARs of the specified folder as class -# repositories -# "foo/bar.jar": Add bar.jar as a class repository -# Please note that for single jars, e.g. bar.jar, you need the URL form -# starting with file:. -shared.loader= - -# -# String cache configuration. -tomcat.util.buf.StringCache.byte.enabled=true -#tomcat.util.buf.StringCache.char.enabled=true -#tomcat.util.buf.StringCache.trainThreshold=500000 -#tomcat.util.buf.StringCache.cacheSize=5000 +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageAccess unless the +# corresponding RuntimePermission ("accessClassInPackage."+package) has +# been granted. +package.access=sun.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper.,sun.beans. +# +# List of comma-separated packages that start with or equal this string +# will cause a security exception to be thrown when +# passed to checkPackageDefinition unless the +# corresponding RuntimePermission ("defineClassInPackage."+package) has +# been granted. +# +# by default, no packages are restricted for definition, and none of +# the class loaders supplied with the JDK call checkPackageDefinition. +# +package.definition=sun.,java.,org.apache.catalina.,org.apache.coyote.,org.apache.tomcat.,org.apache.jasper. + +# +# +# List of comma-separated paths defining the contents of the "common" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. +# If left as blank,the JVM system loader will be used as Catalina's "common" +# loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +common.loader=${catalina.home}/lib,${catalina.home}/lib/*.jar + +# +# List of comma-separated paths defining the contents of the "server" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_HOME or CATALINA_BASE path or absolute. +# If left as blank, the "common" loader will be used as Catalina's "server" +# loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +server.loader= + +# +# List of comma-separated paths defining the contents of the "shared" +# classloader. Prefixes should be used to define what is the repository type. +# Path may be relative to the CATALINA_BASE path or absolute. If left as blank, +# the "common" loader will be used as Catalina's "shared" loader. +# Examples: +# "foo": Add this folder as a class repository +# "foo/*.jar": Add all the JARs of the specified folder as class +# repositories +# "foo/bar.jar": Add bar.jar as a class repository +# Please note that for single jars, e.g. bar.jar, you need the URL form +# starting with file:. +shared.loader= + +# +# String cache configuration. +tomcat.util.buf.StringCache.byte.enabled=true +#tomcat.util.buf.StringCache.char.enabled=true +#tomcat.util.buf.StringCache.trainThreshold=500000 +#tomcat.util.buf.StringCache.cacheSize=5000 diff --git a/java/org/apache/catalina/startup/mbeans-descriptors.xml b/java/org/apache/catalina/startup/mbeans-descriptors.xml index 7fdf92905..1d283c46a 100644 --- a/java/org/apache/catalina/startup/mbeans-descriptors.xml +++ b/java/org/apache/catalina/startup/mbeans-descriptors.xml @@ -1,111 +1,111 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/users/AbstractGroup.java b/java/org/apache/catalina/users/AbstractGroup.java index f7e1c4ff6..fbf6911bf 100644 --- a/java/org/apache/catalina/users/AbstractGroup.java +++ b/java/org/apache/catalina/users/AbstractGroup.java @@ -1,168 +1,168 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.util.Iterator; - -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.UserDatabase; - - -/** - *

        Convenience base class for {@link Group} implementations.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - * @since 4.1 - */ - -public abstract class AbstractGroup implements Group { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The description of this group. - */ - protected String description = null; - - - /** - * The group name of this group. - */ - protected String groupname = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the description of this group. - */ - public String getDescription() { - - return (this.description); - - } - - - /** - * Set the description of this group. - * - * @param description The new description - */ - public void setDescription(String description) { - - this.description = description; - - } - - - /** - * Return the group name of this group, which must be unique - * within the scope of a {@link UserDatabase}. - */ - public String getGroupname() { - - return (this.groupname); - - } - - - /** - * Set the group name of this group, which must be unique - * within the scope of a {@link UserDatabase}. - * - * @param groupname The new group name - */ - public void setGroupname(String groupname) { - - this.groupname = groupname; - - } - - - /** - * Return the set of {@link Role}s assigned specifically to this group. - */ - public abstract Iterator getRoles(); - - - /** - * Return the {@link UserDatabase} within which this Group is defined. - */ - public abstract UserDatabase getUserDatabase(); - - - /** - * Return an Iterator over the set of {@link org.apache.catalina.User}s that - * are members of this group. - */ - public abstract Iterator getUsers(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Role} to those assigned specifically to this group. - * - * @param role The new role - */ - public abstract void addRole(Role role); - - - /** - * Is this group specifically assigned the specified {@link Role}? - * - * @param role The role to check - */ - public abstract boolean isInRole(Role role); - - - /** - * Remove a {@link Role} from those assigned to this group. - * - * @param role The old role - */ - public abstract void removeRole(Role role); - - - /** - * Remove all {@link Role}s from those assigned to this group. - */ - public abstract void removeRoles(); - - - // ------------------------------------------------------ Principal Methods - - - /** - * Make the principal name the same as the group name. - */ - public String getName() { - - return (getGroupname()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.util.Iterator; + +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.UserDatabase; + + +/** + *

        Convenience base class for {@link Group} implementations.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + * @since 4.1 + */ + +public abstract class AbstractGroup implements Group { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The description of this group. + */ + protected String description = null; + + + /** + * The group name of this group. + */ + protected String groupname = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the description of this group. + */ + public String getDescription() { + + return (this.description); + + } + + + /** + * Set the description of this group. + * + * @param description The new description + */ + public void setDescription(String description) { + + this.description = description; + + } + + + /** + * Return the group name of this group, which must be unique + * within the scope of a {@link UserDatabase}. + */ + public String getGroupname() { + + return (this.groupname); + + } + + + /** + * Set the group name of this group, which must be unique + * within the scope of a {@link UserDatabase}. + * + * @param groupname The new group name + */ + public void setGroupname(String groupname) { + + this.groupname = groupname; + + } + + + /** + * Return the set of {@link Role}s assigned specifically to this group. + */ + public abstract Iterator getRoles(); + + + /** + * Return the {@link UserDatabase} within which this Group is defined. + */ + public abstract UserDatabase getUserDatabase(); + + + /** + * Return an Iterator over the set of {@link org.apache.catalina.User}s that + * are members of this group. + */ + public abstract Iterator getUsers(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Role} to those assigned specifically to this group. + * + * @param role The new role + */ + public abstract void addRole(Role role); + + + /** + * Is this group specifically assigned the specified {@link Role}? + * + * @param role The role to check + */ + public abstract boolean isInRole(Role role); + + + /** + * Remove a {@link Role} from those assigned to this group. + * + * @param role The old role + */ + public abstract void removeRole(Role role); + + + /** + * Remove all {@link Role}s from those assigned to this group. + */ + public abstract void removeRoles(); + + + // ------------------------------------------------------ Principal Methods + + + /** + * Make the principal name the same as the group name. + */ + public String getName() { + + return (getGroupname()); + + } + + +} diff --git a/java/org/apache/catalina/users/AbstractRole.java b/java/org/apache/catalina/users/AbstractRole.java index bb5db6b13..c0ef28a1a 100644 --- a/java/org/apache/catalina/users/AbstractRole.java +++ b/java/org/apache/catalina/users/AbstractRole.java @@ -1,122 +1,122 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import org.apache.catalina.Role; -import org.apache.catalina.UserDatabase; - - -/** - *

        Convenience base class for {@link Role} implementations.

        - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public abstract class AbstractRole implements Role { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The description of this Role. - */ - protected String description = null; - - - /** - * The role name of this Role. - */ - protected String rolename = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the description of this role. - */ - public String getDescription() { - - return (this.description); - - } - - - /** - * Set the description of this role. - * - * @param description The new description - */ - public void setDescription(String description) { - - this.description = description; - - } - - - /** - * Return the role name of this role, which must be unique - * within the scope of a {@link UserDatabase}. - */ - public String getRolename() { - - return (this.rolename); - - } - - - /** - * Set the role name of this role, which must be unique - * within the scope of a {@link UserDatabase}. - * - * @param rolename The new role name - */ - public void setRolename(String rolename) { - - this.rolename = rolename; - - } - - - /** - * Return the {@link UserDatabase} within which this Role is defined. - */ - public abstract UserDatabase getUserDatabase(); - - - // --------------------------------------------------------- Public Methods - - - // ------------------------------------------------------ Principal Methods - - - /** - * Make the principal name the same as the role name. - */ - public String getName() { - - return (getRolename()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import org.apache.catalina.Role; +import org.apache.catalina.UserDatabase; + + +/** + *

        Convenience base class for {@link Role} implementations.

        + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public abstract class AbstractRole implements Role { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The description of this Role. + */ + protected String description = null; + + + /** + * The role name of this Role. + */ + protected String rolename = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the description of this role. + */ + public String getDescription() { + + return (this.description); + + } + + + /** + * Set the description of this role. + * + * @param description The new description + */ + public void setDescription(String description) { + + this.description = description; + + } + + + /** + * Return the role name of this role, which must be unique + * within the scope of a {@link UserDatabase}. + */ + public String getRolename() { + + return (this.rolename); + + } + + + /** + * Set the role name of this role, which must be unique + * within the scope of a {@link UserDatabase}. + * + * @param rolename The new role name + */ + public void setRolename(String rolename) { + + this.rolename = rolename; + + } + + + /** + * Return the {@link UserDatabase} within which this Role is defined. + */ + public abstract UserDatabase getUserDatabase(); + + + // --------------------------------------------------------- Public Methods + + + // ------------------------------------------------------ Principal Methods + + + /** + * Make the principal name the same as the role name. + */ + public String getName() { + + return (getRolename()); + + } + + +} diff --git a/java/org/apache/catalina/users/AbstractUser.java b/java/org/apache/catalina/users/AbstractUser.java index c3ac28fae..9ca56a1e1 100644 --- a/java/org/apache/catalina/users/AbstractUser.java +++ b/java/org/apache/catalina/users/AbstractUser.java @@ -1,224 +1,224 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.util.Iterator; -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.User; - - -/** - *

        Convenience base class for {@link User} implementations.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - * @since 4.1 - */ - -public abstract class AbstractUser implements User { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The full name of this user. - */ - protected String fullName = null; - - - /** - * The logon password of this user. - */ - protected String password = null; - - - /** - * The logon username of this user. - */ - protected String username = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the full name of this user. - */ - public String getFullName() { - - return (this.fullName); - - } - - - /** - * Set the full name of this user. - * - * @param fullName The new full name - */ - public void setFullName(String fullName) { - - this.fullName = fullName; - - } - - - /** - * Return the set of {@link Group}s to which this user belongs. - */ - public abstract Iterator getGroups(); - - - /** - * Return the logon password of this user, optionally prefixed with the - * identifier of an encoding scheme surrounded by curly braces, such as - * {md5}xxxxx. - */ - public String getPassword() { - - return (this.password); - - } - - - /** - * Set the logon password of this user, optionally prefixed with the - * identifier of an encoding scheme surrounded by curly braces, such as - * {md5}xxxxx. - * - * @param password The new logon password - */ - public void setPassword(String password) { - - this.password = password; - - } - - - /** - * Return the set of {@link Role}s assigned specifically to this user. - */ - public abstract Iterator getRoles(); - - - /** - * Return the logon username of this user, which must be unique - * within the scope of a {@link org.apache.catalina.UserDatabase}. - */ - public String getUsername() { - - return (this.username); - - } - - - /** - * Set the logon username of this user, which must be unique within - * the scope of a {@link org.apache.catalina.UserDatabase}. - * - * @param username The new logon username - */ - public void setUsername(String username) { - - this.username = username; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Group} to those this user belongs to. - * - * @param group The new group - */ - public abstract void addGroup(Group group); - - - /** - * Add a new {@link Role} to those assigned specifically to this user. - * - * @param role The new role - */ - public abstract void addRole(Role role); - - - /** - * Is this user in the specified {@link Group}? - * - * @param group The group to check - */ - public abstract boolean isInGroup(Group group); - - - /** - * Is this user specifically assigned the specified {@link Role}? This - * method does NOT check for roles inherited based on - * {@link Group} membership. - * - * @param role The role to check - */ - public abstract boolean isInRole(Role role); - - - /** - * Remove a {@link Group} from those this user belongs to. - * - * @param group The old group - */ - public abstract void removeGroup(Group group); - - - /** - * Remove all {@link Group}s from those this user belongs to. - */ - public abstract void removeGroups(); - - - /** - * Remove a {@link Role} from those assigned to this user. - * - * @param role The old role - */ - public abstract void removeRole(Role role); - - - /** - * Remove all {@link Role}s from those assigned to this user. - */ - public abstract void removeRoles(); - - - // ------------------------------------------------------ Principal Methods - - - /** - * Make the principal name the same as the group name. - */ - public String getName() { - - return (getUsername()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.util.Iterator; +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.User; + + +/** + *

        Convenience base class for {@link User} implementations.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + * @since 4.1 + */ + +public abstract class AbstractUser implements User { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The full name of this user. + */ + protected String fullName = null; + + + /** + * The logon password of this user. + */ + protected String password = null; + + + /** + * The logon username of this user. + */ + protected String username = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the full name of this user. + */ + public String getFullName() { + + return (this.fullName); + + } + + + /** + * Set the full name of this user. + * + * @param fullName The new full name + */ + public void setFullName(String fullName) { + + this.fullName = fullName; + + } + + + /** + * Return the set of {@link Group}s to which this user belongs. + */ + public abstract Iterator getGroups(); + + + /** + * Return the logon password of this user, optionally prefixed with the + * identifier of an encoding scheme surrounded by curly braces, such as + * {md5}xxxxx. + */ + public String getPassword() { + + return (this.password); + + } + + + /** + * Set the logon password of this user, optionally prefixed with the + * identifier of an encoding scheme surrounded by curly braces, such as + * {md5}xxxxx. + * + * @param password The new logon password + */ + public void setPassword(String password) { + + this.password = password; + + } + + + /** + * Return the set of {@link Role}s assigned specifically to this user. + */ + public abstract Iterator getRoles(); + + + /** + * Return the logon username of this user, which must be unique + * within the scope of a {@link org.apache.catalina.UserDatabase}. + */ + public String getUsername() { + + return (this.username); + + } + + + /** + * Set the logon username of this user, which must be unique within + * the scope of a {@link org.apache.catalina.UserDatabase}. + * + * @param username The new logon username + */ + public void setUsername(String username) { + + this.username = username; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Group} to those this user belongs to. + * + * @param group The new group + */ + public abstract void addGroup(Group group); + + + /** + * Add a new {@link Role} to those assigned specifically to this user. + * + * @param role The new role + */ + public abstract void addRole(Role role); + + + /** + * Is this user in the specified {@link Group}? + * + * @param group The group to check + */ + public abstract boolean isInGroup(Group group); + + + /** + * Is this user specifically assigned the specified {@link Role}? This + * method does NOT check for roles inherited based on + * {@link Group} membership. + * + * @param role The role to check + */ + public abstract boolean isInRole(Role role); + + + /** + * Remove a {@link Group} from those this user belongs to. + * + * @param group The old group + */ + public abstract void removeGroup(Group group); + + + /** + * Remove all {@link Group}s from those this user belongs to. + */ + public abstract void removeGroups(); + + + /** + * Remove a {@link Role} from those assigned to this user. + * + * @param role The old role + */ + public abstract void removeRole(Role role); + + + /** + * Remove all {@link Role}s from those assigned to this user. + */ + public abstract void removeRoles(); + + + // ------------------------------------------------------ Principal Methods + + + /** + * Make the principal name the same as the group name. + */ + public String getName() { + + return (getUsername()); + + } + + +} diff --git a/java/org/apache/catalina/users/Constants.java b/java/org/apache/catalina/users/Constants.java index 320697733..157f1ea14 100644 --- a/java/org/apache/catalina/users/Constants.java +++ b/java/org/apache/catalina/users/Constants.java @@ -1,34 +1,34 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -/** - * Manifest constants for this Java package. - * - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @since 4.1 - */ - -public final class Constants { - - public static final String Package = "org.apache.catalina.users"; - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +/** + * Manifest constants for this Java package. + * + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @since 4.1 + */ + +public final class Constants { + + public static final String Package = "org.apache.catalina.users"; + +} diff --git a/java/org/apache/catalina/users/LocalStrings.properties b/java/org/apache/catalina/users/LocalStrings.properties index c38aa53e0..4c8c0c5c1 100644 --- a/java/org/apache/catalina/users/LocalStrings.properties +++ b/java/org/apache/catalina/users/LocalStrings.properties @@ -1,5 +1,5 @@ -memoryUserDatabase.invalidGroup=Invalid group name {0} -memoryUserDatabase.renameOld=Cannot rename original file to {0} -memoryUserDatabase.renameNew=Cannot rename new file to {0} -memoryUserDatabase.writeException=IOException writing to {0} -memoryUserDatabase.notPersistable=User database is not persistable - no write permissions on directory +memoryUserDatabase.invalidGroup=Invalid group name {0} +memoryUserDatabase.renameOld=Cannot rename original file to {0} +memoryUserDatabase.renameNew=Cannot rename new file to {0} +memoryUserDatabase.writeException=IOException writing to {0} +memoryUserDatabase.notPersistable=User database is not persistable - no write permissions on directory diff --git a/java/org/apache/catalina/users/LocalStrings_es.properties b/java/org/apache/catalina/users/LocalStrings_es.properties index e013434cc..121e6f98b 100644 --- a/java/org/apache/catalina/users/LocalStrings_es.properties +++ b/java/org/apache/catalina/users/LocalStrings_es.properties @@ -1,4 +1,4 @@ -memoryUserDatabase.invalidGroup=Nombre de grupo {0} inválido -memoryUserDatabase.renameOld=Imposible de renombrar el archivo original a {0} -memoryUserDatabase.renameNew=Imposible de renombrar el archivo nuevo a {0} -memoryUserDatabase.writeException=IOException durante la escritura hacia {0} +memoryUserDatabase.invalidGroup=Nombre de grupo {0} inválido +memoryUserDatabase.renameOld=Imposible de renombrar el archivo original a {0} +memoryUserDatabase.renameNew=Imposible de renombrar el archivo nuevo a {0} +memoryUserDatabase.writeException=IOException durante la escritura hacia {0} diff --git a/java/org/apache/catalina/users/LocalStrings_fr.properties b/java/org/apache/catalina/users/LocalStrings_fr.properties index 917de4021..bb28728eb 100644 --- a/java/org/apache/catalina/users/LocalStrings_fr.properties +++ b/java/org/apache/catalina/users/LocalStrings_fr.properties @@ -1,4 +1,4 @@ -memoryUserDatabase.invalidGroup=Nom de groupe invalide {0} -memoryUserDatabase.renameOld=Impossible de renommer le fichier original en {0} -memoryUserDatabase.renameNew=Impossible de renommer le nouveau fichier en {0} -memoryUserDatabase.writeException=IOException lors de l''écriture vers {0} +memoryUserDatabase.invalidGroup=Nom de groupe invalide {0} +memoryUserDatabase.renameOld=Impossible de renommer le fichier original en {0} +memoryUserDatabase.renameNew=Impossible de renommer le nouveau fichier en {0} +memoryUserDatabase.writeException=IOException lors de l''écriture vers {0} diff --git a/java/org/apache/catalina/users/LocalStrings_ja.properties b/java/org/apache/catalina/users/LocalStrings_ja.properties index 035424273..2ae96e8f9 100644 --- a/java/org/apache/catalina/users/LocalStrings_ja.properties +++ b/java/org/apache/catalina/users/LocalStrings_ja.properties @@ -1,4 +1,4 @@ -memoryUserDatabase.invalidGroup=\u7121\u52b9\u306a\u30b0\u30eb\u30fc\u30d7\u540d {0} -memoryUserDatabase.renameOld=\u5143\u306e\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 -memoryUserDatabase.renameNew=\u65b0\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 -memoryUserDatabase.writeException={0} \u306b\u66f8\u304d\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 +memoryUserDatabase.invalidGroup=\u7121\u52b9\u306a\u30b0\u30eb\u30fc\u30d7\u540d {0} +memoryUserDatabase.renameOld=\u5143\u306e\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 +memoryUserDatabase.renameNew=\u65b0\u3057\u3044\u30d5\u30a1\u30a4\u30eb\u540d\u3092 {0} \u306b\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 +memoryUserDatabase.writeException={0} \u306b\u66f8\u304d\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 diff --git a/java/org/apache/catalina/users/MemoryGroup.java b/java/org/apache/catalina/users/MemoryGroup.java index 186d33120..74eca4a6a 100644 --- a/java/org/apache/catalina/users/MemoryGroup.java +++ b/java/org/apache/catalina/users/MemoryGroup.java @@ -1,213 +1,213 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.util.ArrayList; -import java.util.Iterator; - -import org.apache.catalina.Role; -import org.apache.catalina.UserDatabase; - - -/** - *

        Concrete implementation of {@link org.apache.catalina.Group} for the - * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - * @since 4.1 - */ - -public class MemoryGroup extends AbstractGroup { - - - // ----------------------------------------------------------- Constructors - - - /** - * Package-private constructor used by the factory method in - * {@link MemoryUserDatabase}. - * - * @param database The {@link MemoryUserDatabase} that owns this group - * @param groupname Group name of this group - * @param description Description of this group - */ - MemoryGroup(MemoryUserDatabase database, - String groupname, String description) { - - super(); - this.database = database; - setGroupname(groupname); - setDescription(description); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The {@link MemoryUserDatabase} that owns this group. - */ - protected MemoryUserDatabase database = null; - - - /** - * The set of {@link Role}s associated with this group. - */ - protected ArrayList roles = new ArrayList(); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the set of {@link Role}s assigned specifically to this group. - */ - public Iterator getRoles() { - - synchronized (roles) { - return (roles.iterator()); - } - - } - - - /** - * Return the {@link UserDatabase} within which this Group is defined. - */ - public UserDatabase getUserDatabase() { - - return (this.database); - - } - - - /** - * Return the set of {@link org.apache.catalina.User}s that are members of this group. - */ - public Iterator getUsers() { - - ArrayList results = new ArrayList(); - Iterator users = database.getUsers(); - while (users.hasNext()) { - MemoryUser user = (MemoryUser) users.next(); - if (user.isInGroup(this)) { - results.add(user); - } - } - return (results.iterator()); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Role} to those assigned specifically to this group. - * - * @param role The new role - */ - public void addRole(Role role) { - - synchronized (roles) { - if (!roles.contains(role)) { - roles.add(role); - } - } - - } - - - /** - * Is this group specifically assigned the specified {@link Role}? - * - * @param role The role to check - */ - public boolean isInRole(Role role) { - - synchronized (roles) { - return (roles.contains(role)); - } - - } - - - /** - * Remove a {@link Role} from those assigned to this group. - * - * @param role The old role - */ - public void removeRole(Role role) { - - synchronized (roles) { - roles.remove(role); - } - - } - - - /** - * Remove all {@link Role}s from those assigned to this group. - */ - public void removeRoles() { - - synchronized (roles) { - roles.clear(); - } - - } - - - /** - *

        Return a String representation of this group in XML format.

        - */ - public String toString() { - - StringBuffer sb = new StringBuffer(" 0) { - sb.append(" roles=\""); - int n = 0; - Iterator values = roles.iterator(); - while (values.hasNext()) { - if (n > 0) { - sb.append(','); - } - n++; - sb.append((String) ((Role) values.next()).getRolename()); - } - sb.append("\""); - } - } - sb.append("/>"); - return (sb.toString()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.catalina.Role; +import org.apache.catalina.UserDatabase; + + +/** + *

        Concrete implementation of {@link org.apache.catalina.Group} for the + * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + * @since 4.1 + */ + +public class MemoryGroup extends AbstractGroup { + + + // ----------------------------------------------------------- Constructors + + + /** + * Package-private constructor used by the factory method in + * {@link MemoryUserDatabase}. + * + * @param database The {@link MemoryUserDatabase} that owns this group + * @param groupname Group name of this group + * @param description Description of this group + */ + MemoryGroup(MemoryUserDatabase database, + String groupname, String description) { + + super(); + this.database = database; + setGroupname(groupname); + setDescription(description); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The {@link MemoryUserDatabase} that owns this group. + */ + protected MemoryUserDatabase database = null; + + + /** + * The set of {@link Role}s associated with this group. + */ + protected ArrayList roles = new ArrayList(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the set of {@link Role}s assigned specifically to this group. + */ + public Iterator getRoles() { + + synchronized (roles) { + return (roles.iterator()); + } + + } + + + /** + * Return the {@link UserDatabase} within which this Group is defined. + */ + public UserDatabase getUserDatabase() { + + return (this.database); + + } + + + /** + * Return the set of {@link org.apache.catalina.User}s that are members of this group. + */ + public Iterator getUsers() { + + ArrayList results = new ArrayList(); + Iterator users = database.getUsers(); + while (users.hasNext()) { + MemoryUser user = (MemoryUser) users.next(); + if (user.isInGroup(this)) { + results.add(user); + } + } + return (results.iterator()); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Role} to those assigned specifically to this group. + * + * @param role The new role + */ + public void addRole(Role role) { + + synchronized (roles) { + if (!roles.contains(role)) { + roles.add(role); + } + } + + } + + + /** + * Is this group specifically assigned the specified {@link Role}? + * + * @param role The role to check + */ + public boolean isInRole(Role role) { + + synchronized (roles) { + return (roles.contains(role)); + } + + } + + + /** + * Remove a {@link Role} from those assigned to this group. + * + * @param role The old role + */ + public void removeRole(Role role) { + + synchronized (roles) { + roles.remove(role); + } + + } + + + /** + * Remove all {@link Role}s from those assigned to this group. + */ + public void removeRoles() { + + synchronized (roles) { + roles.clear(); + } + + } + + + /** + *

        Return a String representation of this group in XML format.

        + */ + public String toString() { + + StringBuffer sb = new StringBuffer(" 0) { + sb.append(" roles=\""); + int n = 0; + Iterator values = roles.iterator(); + while (values.hasNext()) { + if (n > 0) { + sb.append(','); + } + n++; + sb.append((String) ((Role) values.next()).getRolename()); + } + sb.append("\""); + } + } + sb.append("/>"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/users/MemoryRole.java b/java/org/apache/catalina/users/MemoryRole.java index c228214cc..a68670bdc 100644 --- a/java/org/apache/catalina/users/MemoryRole.java +++ b/java/org/apache/catalina/users/MemoryRole.java @@ -1,102 +1,102 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import org.apache.catalina.UserDatabase; - - -/** - *

        Concrete implementation of {@link org.apache.catalina.Role} for the - * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - * @since 4.1 - */ - -public class MemoryRole extends AbstractRole { - - - // ----------------------------------------------------------- Constructors - - - /** - * Package-private constructor used by the factory method in - * {@link MemoryUserDatabase}. - * - * @param database The {@link MemoryUserDatabase} that owns this role - * @param rolename Role name of this role - * @param description Description of this role - */ - MemoryRole(MemoryUserDatabase database, - String rolename, String description) { - - super(); - this.database = database; - setRolename(rolename); - setDescription(description); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The {@link MemoryUserDatabase} that owns this role. - */ - protected MemoryUserDatabase database = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the {@link UserDatabase} within which this role is defined. - */ - public UserDatabase getUserDatabase() { - - return (this.database); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Return a String representation of this role in XML format.

        - */ - public String toString() { - - StringBuffer sb = new StringBuffer(""); - return (sb.toString()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import org.apache.catalina.UserDatabase; + + +/** + *

        Concrete implementation of {@link org.apache.catalina.Role} for the + * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + * @since 4.1 + */ + +public class MemoryRole extends AbstractRole { + + + // ----------------------------------------------------------- Constructors + + + /** + * Package-private constructor used by the factory method in + * {@link MemoryUserDatabase}. + * + * @param database The {@link MemoryUserDatabase} that owns this role + * @param rolename Role name of this role + * @param description Description of this role + */ + MemoryRole(MemoryUserDatabase database, + String rolename, String description) { + + super(); + this.database = database; + setRolename(rolename); + setDescription(description); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The {@link MemoryUserDatabase} that owns this role. + */ + protected MemoryUserDatabase database = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the {@link UserDatabase} within which this role is defined. + */ + public UserDatabase getUserDatabase() { + + return (this.database); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Return a String representation of this role in XML format.

        + */ + public String toString() { + + StringBuffer sb = new StringBuffer(""); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/users/MemoryUser.java b/java/org/apache/catalina/users/MemoryUser.java index 92d224797..859bca2b3 100644 --- a/java/org/apache/catalina/users/MemoryUser.java +++ b/java/org/apache/catalina/users/MemoryUser.java @@ -1,296 +1,296 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.util.ArrayList; -import java.util.Iterator; - -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.UserDatabase; -import org.apache.catalina.util.RequestUtil; - -/** - *

        Concrete implementation of {@link org.apache.catalina.User} for the - * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - * @since 4.1 - */ - -public class MemoryUser extends AbstractUser { - - - // ----------------------------------------------------------- Constructors - - - /** - * Package-private constructor used by the factory method in - * {@link MemoryUserDatabase}. - * - * @param database The {@link MemoryUserDatabase} that owns this user - * @param username Logon username of the new user - * @param password Logon password of the new user - * @param fullName Full name of the new user - */ - MemoryUser(MemoryUserDatabase database, String username, - String password, String fullName) { - - super(); - this.database = database; - setUsername(username); - setPassword(password); - setFullName(fullName); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The {@link MemoryUserDatabase} that owns this user. - */ - protected MemoryUserDatabase database = null; - - - /** - * The set of {@link Group}s that this user is a member of. - */ - protected ArrayList groups = new ArrayList(); - - - /** - * The set of {@link Role}s associated with this user. - */ - protected ArrayList roles = new ArrayList(); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the set of {@link Group}s to which this user belongs. - */ - public Iterator getGroups() { - - synchronized (groups) { - return (groups.iterator()); - } - - } - - - /** - * Return the set of {@link Role}s assigned specifically to this user. - */ - public Iterator getRoles() { - - synchronized (roles) { - return (roles.iterator()); - } - - } - - - /** - * Return the {@link UserDatabase} within which this User is defined. - */ - public UserDatabase getUserDatabase() { - - return (this.database); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new {@link Group} to those this user belongs to. - * - * @param group The new group - */ - public void addGroup(Group group) { - - synchronized (groups) { - if (!groups.contains(group)) { - groups.add(group); - } - } - - } - - - /** - * Add a new {@link Role} to those assigned specifically to this user. - * - * @param role The new role - */ - public void addRole(Role role) { - - synchronized (roles) { - if (!roles.contains(role)) { - roles.add(role); - } - } - - } - - - /** - * Is this user in the specified group? - * - * @param group The group to check - */ - public boolean isInGroup(Group group) { - - synchronized (groups) { - return (groups.contains(group)); - } - - } - - - /** - * Is this user specifically assigned the specified {@link Role}? This - * method does NOT check for roles inherited based on - * {@link Group} membership. - * - * @param role The role to check - */ - public boolean isInRole(Role role) { - - synchronized (roles) { - return (roles.contains(role)); - } - - } - - - /** - * Remove a {@link Group} from those this user belongs to. - * - * @param group The old group - */ - public void removeGroup(Group group) { - - synchronized (groups) { - groups.remove(group); - } - - } - - - /** - * Remove all {@link Group}s from those this user belongs to. - */ - public void removeGroups() { - - synchronized (groups) { - groups.clear(); - } - - } - - - /** - * Remove a {@link Role} from those assigned to this user. - * - * @param role The old role - */ - public void removeRole(Role role) { - - synchronized (roles) { - roles.remove(role); - } - - } - - - /** - * Remove all {@link Role}s from those assigned to this user. - */ - public void removeRoles() { - - synchronized (roles) { - roles.clear(); - } - - } - - - /** - *

        Return a String representation of this user in XML format.

        - * - *

        IMPLEMENTATION NOTE - For backwards compatibility, - * the reader that processes this entry will accept either - * username or name for the username - * property.

        - */ - public String toString() { - - StringBuffer sb = new StringBuffer(" 0) { - sb.append(" groups=\""); - int n = 0; - Iterator values = groups.iterator(); - while (values.hasNext()) { - if (n > 0) { - sb.append(','); - } - n++; - sb.append(RequestUtil.filter(((Group) values.next()).getGroupname())); - } - sb.append("\""); - } - } - synchronized (roles) { - if (roles.size() > 0) { - sb.append(" roles=\""); - int n = 0; - Iterator values = roles.iterator(); - while (values.hasNext()) { - if (n > 0) { - sb.append(','); - } - n++; - sb.append(RequestUtil.filter(((Role) values.next()).getRolename())); - } - sb.append("\""); - } - } - sb.append("/>"); - return (sb.toString()); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.UserDatabase; +import org.apache.catalina.util.RequestUtil; + +/** + *

        Concrete implementation of {@link org.apache.catalina.User} for the + * {@link MemoryUserDatabase} implementation of {@link UserDatabase}.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + * @since 4.1 + */ + +public class MemoryUser extends AbstractUser { + + + // ----------------------------------------------------------- Constructors + + + /** + * Package-private constructor used by the factory method in + * {@link MemoryUserDatabase}. + * + * @param database The {@link MemoryUserDatabase} that owns this user + * @param username Logon username of the new user + * @param password Logon password of the new user + * @param fullName Full name of the new user + */ + MemoryUser(MemoryUserDatabase database, String username, + String password, String fullName) { + + super(); + this.database = database; + setUsername(username); + setPassword(password); + setFullName(fullName); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The {@link MemoryUserDatabase} that owns this user. + */ + protected MemoryUserDatabase database = null; + + + /** + * The set of {@link Group}s that this user is a member of. + */ + protected ArrayList groups = new ArrayList(); + + + /** + * The set of {@link Role}s associated with this user. + */ + protected ArrayList roles = new ArrayList(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the set of {@link Group}s to which this user belongs. + */ + public Iterator getGroups() { + + synchronized (groups) { + return (groups.iterator()); + } + + } + + + /** + * Return the set of {@link Role}s assigned specifically to this user. + */ + public Iterator getRoles() { + + synchronized (roles) { + return (roles.iterator()); + } + + } + + + /** + * Return the {@link UserDatabase} within which this User is defined. + */ + public UserDatabase getUserDatabase() { + + return (this.database); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new {@link Group} to those this user belongs to. + * + * @param group The new group + */ + public void addGroup(Group group) { + + synchronized (groups) { + if (!groups.contains(group)) { + groups.add(group); + } + } + + } + + + /** + * Add a new {@link Role} to those assigned specifically to this user. + * + * @param role The new role + */ + public void addRole(Role role) { + + synchronized (roles) { + if (!roles.contains(role)) { + roles.add(role); + } + } + + } + + + /** + * Is this user in the specified group? + * + * @param group The group to check + */ + public boolean isInGroup(Group group) { + + synchronized (groups) { + return (groups.contains(group)); + } + + } + + + /** + * Is this user specifically assigned the specified {@link Role}? This + * method does NOT check for roles inherited based on + * {@link Group} membership. + * + * @param role The role to check + */ + public boolean isInRole(Role role) { + + synchronized (roles) { + return (roles.contains(role)); + } + + } + + + /** + * Remove a {@link Group} from those this user belongs to. + * + * @param group The old group + */ + public void removeGroup(Group group) { + + synchronized (groups) { + groups.remove(group); + } + + } + + + /** + * Remove all {@link Group}s from those this user belongs to. + */ + public void removeGroups() { + + synchronized (groups) { + groups.clear(); + } + + } + + + /** + * Remove a {@link Role} from those assigned to this user. + * + * @param role The old role + */ + public void removeRole(Role role) { + + synchronized (roles) { + roles.remove(role); + } + + } + + + /** + * Remove all {@link Role}s from those assigned to this user. + */ + public void removeRoles() { + + synchronized (roles) { + roles.clear(); + } + + } + + + /** + *

        Return a String representation of this user in XML format.

        + * + *

        IMPLEMENTATION NOTE - For backwards compatibility, + * the reader that processes this entry will accept either + * username or name for the username + * property.

        + */ + public String toString() { + + StringBuffer sb = new StringBuffer(" 0) { + sb.append(" groups=\""); + int n = 0; + Iterator values = groups.iterator(); + while (values.hasNext()) { + if (n > 0) { + sb.append(','); + } + n++; + sb.append(RequestUtil.filter(((Group) values.next()).getGroupname())); + } + sb.append("\""); + } + } + synchronized (roles) { + if (roles.size() > 0) { + sb.append(" roles=\""); + int n = 0; + Iterator values = roles.iterator(); + while (values.hasNext()) { + if (n > 0) { + sb.append(','); + } + n++; + sb.append(RequestUtil.filter(((Role) values.next()).getRolename())); + } + sb.append("\""); + } + } + sb.append("/>"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/users/MemoryUserDatabase.java b/java/org/apache/catalina/users/MemoryUserDatabase.java index a0945cbfd..22256ce2c 100644 --- a/java/org/apache/catalina/users/MemoryUserDatabase.java +++ b/java/org/apache/catalina/users/MemoryUserDatabase.java @@ -1,803 +1,803 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.Iterator; -import org.apache.catalina.Group; -import org.apache.catalina.Role; -import org.apache.catalina.User; -import org.apache.catalina.UserDatabase; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.digester.ObjectCreationFactory; -import org.xml.sax.Attributes; - - -/** - *

        Concrete implementation of {@link UserDatabase} that loads all - * defined users, groups, and roles into an in-memory data structure, - * and uses a specified XML file for its persistent storage.

        - * - * @author Craig R. McClanahan - * @version $Revision: 304047 $ $Date: 2005-08-04 15:12:16 +0200 (jeu., 04 août 2005) $ - * @since 4.1 - */ - -public class MemoryUserDatabase implements UserDatabase { - - - private static Log log = LogFactory.getLog(MemoryUserDatabase.class); - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new instance with default values. - */ - public MemoryUserDatabase() { - - super(); - - } - - - /** - * Create a new instance with the specified values. - * - * @param id Unique global identifier of this user database - */ - public MemoryUserDatabase(String id) { - - super(); - this.id = id; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of {@link Group}s defined in this database, keyed by - * group name. - */ - protected HashMap groups = new HashMap(); - - - /** - * The unique global identifier of this user database. - */ - protected String id = null; - - - /** - * The relative (to catalina.base) or absolute pathname to - * the XML file in which we will save our persistent information. - */ - protected String pathname = "conf/tomcat-users.xml"; - - - /** - * The relative or absolute pathname to the file in which our old - * information is stored while renaming is in progress. - */ - protected String pathnameOld = pathname + ".old"; - - - /** - * The relative or absolute pathname ot the file in which we write - * our new information prior to renaming. - */ - protected String pathnameNew = pathname + ".new"; - - - /** - * A flag, indicating if the user database is read only. - */ - protected boolean readonly = false; - - /** - * The set of {@link Role}s defined in this database, keyed by - * role name. - */ - protected HashMap roles = new HashMap(); - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * The set of {@link User}s defined in this database, keyed by - * user name. - */ - protected HashMap users = new HashMap(); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the set of {@link Group}s defined in this user database. - */ - public Iterator getGroups() { - - synchronized (groups) { - return (groups.values().iterator()); - } - - } - - - /** - * Return the unique global identifier of this user database. - */ - public String getId() { - - return (this.id); - - } - - - /** - * Return the relative or absolute pathname to the persistent storage file. - */ - public String getPathname() { - - return (this.pathname); - - } - - - /** - * Set the relative or absolute pathname to the persistent storage file. - * - * @param pathname The new pathname - */ - public void setPathname(String pathname) { - - this.pathname = pathname; - this.pathnameOld = pathname + ".old"; - this.pathnameNew = pathname + ".new"; - - } - - - /** - * Returning the readonly status of the user database - */ - public boolean getReadonly() { - - return (this.readonly); - - } - - - /** - * Setting the readonly status of the user database - * - * @param pathname The new pathname - */ - public void setReadonly(boolean readonly) { - - this.readonly = readonly; - - } - - - /** - * Return the set of {@link Role}s defined in this user database. - */ - public Iterator getRoles() { - - synchronized (roles) { - return (roles.values().iterator()); - } - - } - - - /** - * Return the set of {@link User}s defined in this user database. - */ - public Iterator getUsers() { - - synchronized (users) { - return (users.values().iterator()); - } - - } - - - - // --------------------------------------------------------- Public Methods - - - /** - * Finalize access to this user database. - * - * @exception Exception if any exception is thrown during closing - */ - public void close() throws Exception { - - save(); - - synchronized (groups) { - synchronized (users) { - users.clear(); - groups.clear(); - } - } - - } - - - /** - * Create and return a new {@link Group} defined in this user database. - * - * @param groupname The group name of the new group (must be unique) - * @param description The description of this group - */ - public Group createGroup(String groupname, String description) { - - MemoryGroup group = new MemoryGroup(this, groupname, description); - synchronized (groups) { - groups.put(group.getGroupname(), group); - } - return (group); - - } - - - /** - * Create and return a new {@link Role} defined in this user database. - * - * @param rolename The role name of the new group (must be unique) - * @param description The description of this group - */ - public Role createRole(String rolename, String description) { - - MemoryRole role = new MemoryRole(this, rolename, description); - synchronized (roles) { - roles.put(role.getRolename(), role); - } - return (role); - - } - - - /** - * Create and return a new {@link User} defined in this user database. - * - * @param username The logon username of the new user (must be unique) - * @param password The logon password of the new user - * @param fullName The full name of the new user - */ - public User createUser(String username, String password, - String fullName) { - - MemoryUser user = new MemoryUser(this, username, password, fullName); - synchronized (users) { - users.put(user.getUsername(), user); - } - return (user); - - } - - - /** - * Return the {@link Group} with the specified group name, if any; - * otherwise return null. - * - * @param groupname Name of the group to return - */ - public Group findGroup(String groupname) { - - synchronized (groups) { - return ((Group) groups.get(groupname)); - } - - } - - - /** - * Return the {@link Role} with the specified role name, if any; - * otherwise return null. - * - * @param rolename Name of the role to return - */ - public Role findRole(String rolename) { - - synchronized (roles) { - return ((Role) roles.get(rolename)); - } - - } - - - /** - * Return the {@link User} with the specified user name, if any; - * otherwise return null. - * - * @param username Name of the user to return - */ - public User findUser(String username) { - - synchronized (users) { - return ((User) users.get(username)); - } - - } - - - /** - * Initialize access to this user database. - * - * @exception Exception if any exception is thrown during opening - */ - public void open() throws Exception { - - synchronized (groups) { - synchronized (users) { - - // Erase any previous groups and users - users.clear(); - groups.clear(); - roles.clear(); - - // Construct a reader for the XML input file (if it exists) - File file = new File(pathname); - if (!file.isAbsolute()) { - file = new File(System.getProperty("catalina.base"), - pathname); - } - if (!file.exists()) { - return; - } - FileInputStream fis = new FileInputStream(file); - - // Construct a digester to read the XML input file - Digester digester = new Digester(); - digester.addFactoryCreate - ("tomcat-users/group", - new MemoryGroupCreationFactory(this)); - digester.addFactoryCreate - ("tomcat-users/role", - new MemoryRoleCreationFactory(this)); - digester.addFactoryCreate - ("tomcat-users/user", - new MemoryUserCreationFactory(this)); - - // Parse the XML input file to load this database - try { - digester.parse(fis); - fis.close(); - } catch (Exception e) { - try { - fis.close(); - } catch (Throwable t) { - ; - } - throw e; - } - - } - } - - } - - - /** - * Remove the specified {@link Group} from this user database. - * - * @param group The group to be removed - */ - public void removeGroup(Group group) { - - synchronized (groups) { - Iterator users = getUsers(); - while (users.hasNext()) { - User user = (User) users.next(); - user.removeGroup(group); - } - groups.remove(group.getGroupname()); - } - - } - - - /** - * Remove the specified {@link Role} from this user database. - * - * @param role The role to be removed - */ - public void removeRole(Role role) { - - synchronized (roles) { - Iterator groups = getGroups(); - while (groups.hasNext()) { - Group group = (Group) groups.next(); - group.removeRole(role); - } - Iterator users = getUsers(); - while (users.hasNext()) { - User user = (User) users.next(); - user.removeRole(role); - } - roles.remove(role.getRolename()); - } - - } - - - /** - * Remove the specified {@link User} from this user database. - * - * @param user The user to be removed - */ - public void removeUser(User user) { - - synchronized (users) { - users.remove(user.getUsername()); - } - - } - - - /** - * Check for permissions to save this user database - * to persistent storage location - * - */ - public boolean isWriteable() { - - File file = new File(pathname); - if (!file.isAbsolute()) { - file = new File(System.getProperty("catalina.base"), - pathname); - } - File dir = file.getParentFile(); - return dir.exists() && dir.isDirectory() && dir.canWrite(); - - } - - - /** - * Save any updated information to the persistent storage location for - * this user database. - * - * @exception Exception if any exception is thrown during saving - */ - public void save() throws Exception { - - if (getReadonly()) { - return; - } - - if (!isWriteable()) { - log.warn(sm.getString("memoryUserDatabase.notPersistable")); - return; - } - - // Write out contents to a temporary file - File fileNew = new File(pathnameNew); - if (!fileNew.isAbsolute()) { - fileNew = - new File(System.getProperty("catalina.base"), pathnameNew); - } - PrintWriter writer = null; - try { - - // Configure our PrintWriter - FileOutputStream fos = new FileOutputStream(fileNew); - OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); - writer = new PrintWriter(osw); - - // Print the file prolog - writer.println(""); - writer.println(""); - - // Print entries for each defined role, group, and user - Iterator values = null; - values = getRoles(); - while (values.hasNext()) { - writer.print(" "); - writer.println(values.next()); - } - values = getGroups(); - while (values.hasNext()) { - writer.print(" "); - writer.println(values.next()); - } - values = getUsers(); - while (values.hasNext()) { - writer.print(" "); - writer.println(values.next()); - } - - // Print the file epilog - writer.println(""); - - // Check for errors that occurred while printing - if (writer.checkError()) { - writer.close(); - fileNew.delete(); - throw new IOException - (sm.getString("memoryUserDatabase.writeException", - fileNew.getAbsolutePath())); - } - writer.close(); - } catch (IOException e) { - if (writer != null) { - writer.close(); - } - fileNew.delete(); - throw e; - } - - // Perform the required renames to permanently save this file - File fileOld = new File(pathnameOld); - if (!fileOld.isAbsolute()) { - fileOld = - new File(System.getProperty("catalina.base"), pathnameOld); - } - fileOld.delete(); - File fileOrig = new File(pathname); - if (!fileOrig.isAbsolute()) { - fileOrig = - new File(System.getProperty("catalina.base"), pathname); - } - if (fileOrig.exists()) { - fileOld.delete(); - if (!fileOrig.renameTo(fileOld)) { - throw new IOException - (sm.getString("memoryUserDatabase.renameOld", - fileOld.getAbsolutePath())); - } - } - if (!fileNew.renameTo(fileOrig)) { - if (fileOld.exists()) { - fileOld.renameTo(fileOrig); - } - throw new IOException - (sm.getString("memoryUserDatabase.renameNew", - fileOrig.getAbsolutePath())); - } - fileOld.delete(); - - } - - - /** - * Return a String representation of this UserDatabase. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("MemoryUserDatabase[id="); - sb.append(this.id); - sb.append(",pathname="); - sb.append(pathname); - sb.append(",groupCount="); - sb.append(this.groups.size()); - sb.append(",roleCount="); - sb.append(this.roles.size()); - sb.append(",userCount="); - sb.append(this.users.size()); - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Return the StringManager for use in looking up messages. - */ - StringManager getStringManager() { - - return (sm); - - } - - -} - - - -/** - * Digester object creation factory for group instances. - */ -class MemoryGroupCreationFactory implements ObjectCreationFactory { - - public MemoryGroupCreationFactory(MemoryUserDatabase database) { - this.database = database; - } - - public Object createObject(Attributes attributes) { - String groupname = attributes.getValue("groupname"); - if (groupname == null) { - groupname = attributes.getValue("name"); - } - String description = attributes.getValue("description"); - String roles = attributes.getValue("roles"); - Group group = database.createGroup(groupname, description); - if (roles != null) { - while (roles.length() > 0) { - String rolename = null; - int comma = roles.indexOf(','); - if (comma >= 0) { - rolename = roles.substring(0, comma).trim(); - roles = roles.substring(comma + 1); - } else { - rolename = roles.trim(); - roles = ""; - } - if (rolename.length() > 0) { - Role role = database.findRole(rolename); - if (role == null) { - role = database.createRole(rolename, null); - } - group.addRole(role); - } - } - } - return (group); - } - - private MemoryUserDatabase database = null; - - private Digester digester = null; - - public Digester getDigester() { - return (this.digester); - } - - public void setDigester(Digester digester) { - this.digester = digester; - } - -} - - -/** - * Digester object creation factory for role instances. - */ -class MemoryRoleCreationFactory implements ObjectCreationFactory { - - public MemoryRoleCreationFactory(MemoryUserDatabase database) { - this.database = database; - } - - public Object createObject(Attributes attributes) { - String rolename = attributes.getValue("rolename"); - if (rolename == null) { - rolename = attributes.getValue("name"); - } - String description = attributes.getValue("description"); - Role role = database.createRole(rolename, description); - return (role); - } - - private MemoryUserDatabase database = null; - - private Digester digester = null; - - public Digester getDigester() { - return (this.digester); - } - - public void setDigester(Digester digester) { - this.digester = digester; - } - -} - - -/** - * Digester object creation factory for user instances. - */ -class MemoryUserCreationFactory implements ObjectCreationFactory { - - public MemoryUserCreationFactory(MemoryUserDatabase database) { - this.database = database; - } - - public Object createObject(Attributes attributes) { - String username = attributes.getValue("username"); - if (username == null) { - username = attributes.getValue("name"); - } - String password = attributes.getValue("password"); - String fullName = attributes.getValue("fullName"); - if (fullName == null) { - fullName = attributes.getValue("fullname"); - } - String groups = attributes.getValue("groups"); - String roles = attributes.getValue("roles"); - User user = database.createUser(username, password, fullName); - if (groups != null) { - while (groups.length() > 0) { - String groupname = null; - int comma = groups.indexOf(','); - if (comma >= 0) { - groupname = groups.substring(0, comma).trim(); - groups = groups.substring(comma + 1); - } else { - groupname = groups.trim(); - groups = ""; - } - if (groupname.length() > 0) { - Group group = database.findGroup(groupname); - if (group == null) { - group = database.createGroup(groupname, null); - } - user.addGroup(group); - } - } - } - if (roles != null) { - while (roles.length() > 0) { - String rolename = null; - int comma = roles.indexOf(','); - if (comma >= 0) { - rolename = roles.substring(0, comma).trim(); - roles = roles.substring(comma + 1); - } else { - rolename = roles.trim(); - roles = ""; - } - if (rolename.length() > 0) { - Role role = database.findRole(rolename); - if (role == null) { - role = database.createRole(rolename, null); - } - user.addRole(role); - } - } - } - return (user); - } - - private MemoryUserDatabase database = null; - - private Digester digester = null; - - public Digester getDigester() { - return (this.digester); - } - - public void setDigester(Digester digester) { - this.digester = digester; - } - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.Iterator; +import org.apache.catalina.Group; +import org.apache.catalina.Role; +import org.apache.catalina.User; +import org.apache.catalina.UserDatabase; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.digester.ObjectCreationFactory; +import org.xml.sax.Attributes; + + +/** + *

        Concrete implementation of {@link UserDatabase} that loads all + * defined users, groups, and roles into an in-memory data structure, + * and uses a specified XML file for its persistent storage.

        + * + * @author Craig R. McClanahan + * @version $Revision: 304047 $ $Date: 2005-08-04 15:12:16 +0200 (jeu., 04 août 2005) $ + * @since 4.1 + */ + +public class MemoryUserDatabase implements UserDatabase { + + + private static Log log = LogFactory.getLog(MemoryUserDatabase.class); + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new instance with default values. + */ + public MemoryUserDatabase() { + + super(); + + } + + + /** + * Create a new instance with the specified values. + * + * @param id Unique global identifier of this user database + */ + public MemoryUserDatabase(String id) { + + super(); + this.id = id; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of {@link Group}s defined in this database, keyed by + * group name. + */ + protected HashMap groups = new HashMap(); + + + /** + * The unique global identifier of this user database. + */ + protected String id = null; + + + /** + * The relative (to catalina.base) or absolute pathname to + * the XML file in which we will save our persistent information. + */ + protected String pathname = "conf/tomcat-users.xml"; + + + /** + * The relative or absolute pathname to the file in which our old + * information is stored while renaming is in progress. + */ + protected String pathnameOld = pathname + ".old"; + + + /** + * The relative or absolute pathname ot the file in which we write + * our new information prior to renaming. + */ + protected String pathnameNew = pathname + ".new"; + + + /** + * A flag, indicating if the user database is read only. + */ + protected boolean readonly = false; + + /** + * The set of {@link Role}s defined in this database, keyed by + * role name. + */ + protected HashMap roles = new HashMap(); + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * The set of {@link User}s defined in this database, keyed by + * user name. + */ + protected HashMap users = new HashMap(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the set of {@link Group}s defined in this user database. + */ + public Iterator getGroups() { + + synchronized (groups) { + return (groups.values().iterator()); + } + + } + + + /** + * Return the unique global identifier of this user database. + */ + public String getId() { + + return (this.id); + + } + + + /** + * Return the relative or absolute pathname to the persistent storage file. + */ + public String getPathname() { + + return (this.pathname); + + } + + + /** + * Set the relative or absolute pathname to the persistent storage file. + * + * @param pathname The new pathname + */ + public void setPathname(String pathname) { + + this.pathname = pathname; + this.pathnameOld = pathname + ".old"; + this.pathnameNew = pathname + ".new"; + + } + + + /** + * Returning the readonly status of the user database + */ + public boolean getReadonly() { + + return (this.readonly); + + } + + + /** + * Setting the readonly status of the user database + * + * @param pathname The new pathname + */ + public void setReadonly(boolean readonly) { + + this.readonly = readonly; + + } + + + /** + * Return the set of {@link Role}s defined in this user database. + */ + public Iterator getRoles() { + + synchronized (roles) { + return (roles.values().iterator()); + } + + } + + + /** + * Return the set of {@link User}s defined in this user database. + */ + public Iterator getUsers() { + + synchronized (users) { + return (users.values().iterator()); + } + + } + + + + // --------------------------------------------------------- Public Methods + + + /** + * Finalize access to this user database. + * + * @exception Exception if any exception is thrown during closing + */ + public void close() throws Exception { + + save(); + + synchronized (groups) { + synchronized (users) { + users.clear(); + groups.clear(); + } + } + + } + + + /** + * Create and return a new {@link Group} defined in this user database. + * + * @param groupname The group name of the new group (must be unique) + * @param description The description of this group + */ + public Group createGroup(String groupname, String description) { + + MemoryGroup group = new MemoryGroup(this, groupname, description); + synchronized (groups) { + groups.put(group.getGroupname(), group); + } + return (group); + + } + + + /** + * Create and return a new {@link Role} defined in this user database. + * + * @param rolename The role name of the new group (must be unique) + * @param description The description of this group + */ + public Role createRole(String rolename, String description) { + + MemoryRole role = new MemoryRole(this, rolename, description); + synchronized (roles) { + roles.put(role.getRolename(), role); + } + return (role); + + } + + + /** + * Create and return a new {@link User} defined in this user database. + * + * @param username The logon username of the new user (must be unique) + * @param password The logon password of the new user + * @param fullName The full name of the new user + */ + public User createUser(String username, String password, + String fullName) { + + MemoryUser user = new MemoryUser(this, username, password, fullName); + synchronized (users) { + users.put(user.getUsername(), user); + } + return (user); + + } + + + /** + * Return the {@link Group} with the specified group name, if any; + * otherwise return null. + * + * @param groupname Name of the group to return + */ + public Group findGroup(String groupname) { + + synchronized (groups) { + return ((Group) groups.get(groupname)); + } + + } + + + /** + * Return the {@link Role} with the specified role name, if any; + * otherwise return null. + * + * @param rolename Name of the role to return + */ + public Role findRole(String rolename) { + + synchronized (roles) { + return ((Role) roles.get(rolename)); + } + + } + + + /** + * Return the {@link User} with the specified user name, if any; + * otherwise return null. + * + * @param username Name of the user to return + */ + public User findUser(String username) { + + synchronized (users) { + return ((User) users.get(username)); + } + + } + + + /** + * Initialize access to this user database. + * + * @exception Exception if any exception is thrown during opening + */ + public void open() throws Exception { + + synchronized (groups) { + synchronized (users) { + + // Erase any previous groups and users + users.clear(); + groups.clear(); + roles.clear(); + + // Construct a reader for the XML input file (if it exists) + File file = new File(pathname); + if (!file.isAbsolute()) { + file = new File(System.getProperty("catalina.base"), + pathname); + } + if (!file.exists()) { + return; + } + FileInputStream fis = new FileInputStream(file); + + // Construct a digester to read the XML input file + Digester digester = new Digester(); + digester.addFactoryCreate + ("tomcat-users/group", + new MemoryGroupCreationFactory(this)); + digester.addFactoryCreate + ("tomcat-users/role", + new MemoryRoleCreationFactory(this)); + digester.addFactoryCreate + ("tomcat-users/user", + new MemoryUserCreationFactory(this)); + + // Parse the XML input file to load this database + try { + digester.parse(fis); + fis.close(); + } catch (Exception e) { + try { + fis.close(); + } catch (Throwable t) { + ; + } + throw e; + } + + } + } + + } + + + /** + * Remove the specified {@link Group} from this user database. + * + * @param group The group to be removed + */ + public void removeGroup(Group group) { + + synchronized (groups) { + Iterator users = getUsers(); + while (users.hasNext()) { + User user = (User) users.next(); + user.removeGroup(group); + } + groups.remove(group.getGroupname()); + } + + } + + + /** + * Remove the specified {@link Role} from this user database. + * + * @param role The role to be removed + */ + public void removeRole(Role role) { + + synchronized (roles) { + Iterator groups = getGroups(); + while (groups.hasNext()) { + Group group = (Group) groups.next(); + group.removeRole(role); + } + Iterator users = getUsers(); + while (users.hasNext()) { + User user = (User) users.next(); + user.removeRole(role); + } + roles.remove(role.getRolename()); + } + + } + + + /** + * Remove the specified {@link User} from this user database. + * + * @param user The user to be removed + */ + public void removeUser(User user) { + + synchronized (users) { + users.remove(user.getUsername()); + } + + } + + + /** + * Check for permissions to save this user database + * to persistent storage location + * + */ + public boolean isWriteable() { + + File file = new File(pathname); + if (!file.isAbsolute()) { + file = new File(System.getProperty("catalina.base"), + pathname); + } + File dir = file.getParentFile(); + return dir.exists() && dir.isDirectory() && dir.canWrite(); + + } + + + /** + * Save any updated information to the persistent storage location for + * this user database. + * + * @exception Exception if any exception is thrown during saving + */ + public void save() throws Exception { + + if (getReadonly()) { + return; + } + + if (!isWriteable()) { + log.warn(sm.getString("memoryUserDatabase.notPersistable")); + return; + } + + // Write out contents to a temporary file + File fileNew = new File(pathnameNew); + if (!fileNew.isAbsolute()) { + fileNew = + new File(System.getProperty("catalina.base"), pathnameNew); + } + PrintWriter writer = null; + try { + + // Configure our PrintWriter + FileOutputStream fos = new FileOutputStream(fileNew); + OutputStreamWriter osw = new OutputStreamWriter(fos, "UTF8"); + writer = new PrintWriter(osw); + + // Print the file prolog + writer.println(""); + writer.println(""); + + // Print entries for each defined role, group, and user + Iterator values = null; + values = getRoles(); + while (values.hasNext()) { + writer.print(" "); + writer.println(values.next()); + } + values = getGroups(); + while (values.hasNext()) { + writer.print(" "); + writer.println(values.next()); + } + values = getUsers(); + while (values.hasNext()) { + writer.print(" "); + writer.println(values.next()); + } + + // Print the file epilog + writer.println(""); + + // Check for errors that occurred while printing + if (writer.checkError()) { + writer.close(); + fileNew.delete(); + throw new IOException + (sm.getString("memoryUserDatabase.writeException", + fileNew.getAbsolutePath())); + } + writer.close(); + } catch (IOException e) { + if (writer != null) { + writer.close(); + } + fileNew.delete(); + throw e; + } + + // Perform the required renames to permanently save this file + File fileOld = new File(pathnameOld); + if (!fileOld.isAbsolute()) { + fileOld = + new File(System.getProperty("catalina.base"), pathnameOld); + } + fileOld.delete(); + File fileOrig = new File(pathname); + if (!fileOrig.isAbsolute()) { + fileOrig = + new File(System.getProperty("catalina.base"), pathname); + } + if (fileOrig.exists()) { + fileOld.delete(); + if (!fileOrig.renameTo(fileOld)) { + throw new IOException + (sm.getString("memoryUserDatabase.renameOld", + fileOld.getAbsolutePath())); + } + } + if (!fileNew.renameTo(fileOrig)) { + if (fileOld.exists()) { + fileOld.renameTo(fileOrig); + } + throw new IOException + (sm.getString("memoryUserDatabase.renameNew", + fileOrig.getAbsolutePath())); + } + fileOld.delete(); + + } + + + /** + * Return a String representation of this UserDatabase. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("MemoryUserDatabase[id="); + sb.append(this.id); + sb.append(",pathname="); + sb.append(pathname); + sb.append(",groupCount="); + sb.append(this.groups.size()); + sb.append(",roleCount="); + sb.append(this.roles.size()); + sb.append(",userCount="); + sb.append(this.users.size()); + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Return the StringManager for use in looking up messages. + */ + StringManager getStringManager() { + + return (sm); + + } + + +} + + + +/** + * Digester object creation factory for group instances. + */ +class MemoryGroupCreationFactory implements ObjectCreationFactory { + + public MemoryGroupCreationFactory(MemoryUserDatabase database) { + this.database = database; + } + + public Object createObject(Attributes attributes) { + String groupname = attributes.getValue("groupname"); + if (groupname == null) { + groupname = attributes.getValue("name"); + } + String description = attributes.getValue("description"); + String roles = attributes.getValue("roles"); + Group group = database.createGroup(groupname, description); + if (roles != null) { + while (roles.length() > 0) { + String rolename = null; + int comma = roles.indexOf(','); + if (comma >= 0) { + rolename = roles.substring(0, comma).trim(); + roles = roles.substring(comma + 1); + } else { + rolename = roles.trim(); + roles = ""; + } + if (rolename.length() > 0) { + Role role = database.findRole(rolename); + if (role == null) { + role = database.createRole(rolename, null); + } + group.addRole(role); + } + } + } + return (group); + } + + private MemoryUserDatabase database = null; + + private Digester digester = null; + + public Digester getDigester() { + return (this.digester); + } + + public void setDigester(Digester digester) { + this.digester = digester; + } + +} + + +/** + * Digester object creation factory for role instances. + */ +class MemoryRoleCreationFactory implements ObjectCreationFactory { + + public MemoryRoleCreationFactory(MemoryUserDatabase database) { + this.database = database; + } + + public Object createObject(Attributes attributes) { + String rolename = attributes.getValue("rolename"); + if (rolename == null) { + rolename = attributes.getValue("name"); + } + String description = attributes.getValue("description"); + Role role = database.createRole(rolename, description); + return (role); + } + + private MemoryUserDatabase database = null; + + private Digester digester = null; + + public Digester getDigester() { + return (this.digester); + } + + public void setDigester(Digester digester) { + this.digester = digester; + } + +} + + +/** + * Digester object creation factory for user instances. + */ +class MemoryUserCreationFactory implements ObjectCreationFactory { + + public MemoryUserCreationFactory(MemoryUserDatabase database) { + this.database = database; + } + + public Object createObject(Attributes attributes) { + String username = attributes.getValue("username"); + if (username == null) { + username = attributes.getValue("name"); + } + String password = attributes.getValue("password"); + String fullName = attributes.getValue("fullName"); + if (fullName == null) { + fullName = attributes.getValue("fullname"); + } + String groups = attributes.getValue("groups"); + String roles = attributes.getValue("roles"); + User user = database.createUser(username, password, fullName); + if (groups != null) { + while (groups.length() > 0) { + String groupname = null; + int comma = groups.indexOf(','); + if (comma >= 0) { + groupname = groups.substring(0, comma).trim(); + groups = groups.substring(comma + 1); + } else { + groupname = groups.trim(); + groups = ""; + } + if (groupname.length() > 0) { + Group group = database.findGroup(groupname); + if (group == null) { + group = database.createGroup(groupname, null); + } + user.addGroup(group); + } + } + } + if (roles != null) { + while (roles.length() > 0) { + String rolename = null; + int comma = roles.indexOf(','); + if (comma >= 0) { + rolename = roles.substring(0, comma).trim(); + roles = roles.substring(comma + 1); + } else { + rolename = roles.trim(); + roles = ""; + } + if (rolename.length() > 0) { + Role role = database.findRole(rolename); + if (role == null) { + role = database.createRole(rolename, null); + } + user.addRole(role); + } + } + } + return (user); + } + + private MemoryUserDatabase database = null; + + private Digester digester = null; + + public Digester getDigester() { + return (this.digester); + } + + public void setDigester(Digester digester) { + this.digester = digester; + } + +} diff --git a/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java b/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java index bb3c7c929..f23c1d447 100644 --- a/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java +++ b/java/org/apache/catalina/users/MemoryUserDatabaseFactory.java @@ -1,109 +1,109 @@ -/* - * Copyright 2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.users; - - -import java.util.Hashtable; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.RefAddr; -import javax.naming.Reference; -import javax.naming.spi.ObjectFactory; - - -/** - *

        JNDI object creation factory for MemoryUserDatabase - * instances. This makes it convenient to configure a user database - * in the global JNDI resources associated with this Catalina instance, - * and then link to that resource for web applications that administer - * the contents of the user database.

        - * - *

        The MemoryUserDatabase instance is configured based - * on the following parameter values:

        - *
          - *
        • pathname - Absolute or relative (to the directory - * path specified by the catalina.base system property) - * pathname to the XML file from which our user information is loaded, - * and to which it is stored. [conf/tomcat-users.xml]
        • - *
        - * - * @author Craig R. McClanahan - * @version $Revision: 304046 $ $Date: 2005-08-04 15:06:56 +0200 (jeu., 04 août 2005) $ - * @since 4.1 - */ - -public class MemoryUserDatabaseFactory implements ObjectFactory { - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Create and return a new MemoryUserDatabase instance - * that has been configured according to the properties of the - * specified Reference. If you instance can be created, - * return null instead.

        - * - * @param obj The possibly null object containing location or - * reference information that can be used in creating an object - * @param name The name of this object relative to nameCtx - * @param nameCtx The context relative to which the name - * parameter is specified, or null if name - * is relative to the default initial context - * @param environment The possibly null environment that is used in - * creating this object - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws Exception { - - // We only know how to deal with javax.naming.References - // that specify a class name of "org.apache.catalina.UserDatabase" - if ((obj == null) || !(obj instanceof Reference)) { - return (null); - } - Reference ref = (Reference) obj; - if (!"org.apache.catalina.UserDatabase".equals(ref.getClassName())) { - return (null); - } - - // Create and configure a MemoryUserDatabase instance based on the - // RefAddr values associated with this Reference - MemoryUserDatabase database = new MemoryUserDatabase(name.toString()); - RefAddr ra = null; - - ra = ref.get("pathname"); - if (ra != null) { - database.setPathname(ra.getContent().toString()); - } - - ra = ref.get("readonly"); - if (ra != null) { - database.setReadonly(Boolean.valueOf(ra.getContent().toString()).booleanValue()); - } - - // Return the configured database instance - database.open(); - database.save(); - return (database); - - } - - -} +/* + * Copyright 2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.users; + + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; + + +/** + *

        JNDI object creation factory for MemoryUserDatabase + * instances. This makes it convenient to configure a user database + * in the global JNDI resources associated with this Catalina instance, + * and then link to that resource for web applications that administer + * the contents of the user database.

        + * + *

        The MemoryUserDatabase instance is configured based + * on the following parameter values:

        + *
          + *
        • pathname - Absolute or relative (to the directory + * path specified by the catalina.base system property) + * pathname to the XML file from which our user information is loaded, + * and to which it is stored. [conf/tomcat-users.xml]
        • + *
        + * + * @author Craig R. McClanahan + * @version $Revision: 304046 $ $Date: 2005-08-04 15:06:56 +0200 (jeu., 04 août 2005) $ + * @since 4.1 + */ + +public class MemoryUserDatabaseFactory implements ObjectFactory { + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Create and return a new MemoryUserDatabase instance + * that has been configured according to the properties of the + * specified Reference. If you instance can be created, + * return null instead.

        + * + * @param obj The possibly null object containing location or + * reference information that can be used in creating an object + * @param name The name of this object relative to nameCtx + * @param nameCtx The context relative to which the name + * parameter is specified, or null if name + * is relative to the default initial context + * @param environment The possibly null environment that is used in + * creating this object + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws Exception { + + // We only know how to deal with javax.naming.References + // that specify a class name of "org.apache.catalina.UserDatabase" + if ((obj == null) || !(obj instanceof Reference)) { + return (null); + } + Reference ref = (Reference) obj; + if (!"org.apache.catalina.UserDatabase".equals(ref.getClassName())) { + return (null); + } + + // Create and configure a MemoryUserDatabase instance based on the + // RefAddr values associated with this Reference + MemoryUserDatabase database = new MemoryUserDatabase(name.toString()); + RefAddr ra = null; + + ra = ref.get("pathname"); + if (ra != null) { + database.setPathname(ra.getContent().toString()); + } + + ra = ref.get("readonly"); + if (ra != null) { + database.setReadonly(Boolean.valueOf(ra.getContent().toString()).booleanValue()); + } + + // Return the configured database instance + database.open(); + database.save(); + return (database); + + } + + +} diff --git a/java/org/apache/catalina/users/mbeans-descriptors.xml b/java/org/apache/catalina/users/mbeans-descriptors.xml index bc558b4ed..47b478cbb 100644 --- a/java/org/apache/catalina/users/mbeans-descriptors.xml +++ b/java/org/apache/catalina/users/mbeans-descriptors.xml @@ -1,280 +1,280 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/util/AnnotationProcessor.java b/java/org/apache/catalina/util/AnnotationProcessor.java index 6e11428f6..658798740 100644 --- a/java/org/apache/catalina/util/AnnotationProcessor.java +++ b/java/org/apache/catalina/util/AnnotationProcessor.java @@ -1,230 +1,230 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; -import javax.annotation.Resource; -import javax.ejb.EJB; -import javax.naming.NamingException; -import javax.persistence.PersistenceContext; -import javax.persistence.PersistenceUnit; -import javax.xml.ws.WebServiceRef; - - -/** - * Verify the annotation and Process it. - * - * @author Fabien Carrion - * @author Remy Maucherat - * @version $Revision: 303236 $, $Date: 2006-03-09 16:46:52 -0600 (Thu, 09 Mar 2006) $ - */ -public class AnnotationProcessor { - - - /** - * Call postConstruct method on the specified instance. - */ - public static void postConstruct(Object instance) - throws IllegalAccessException, InvocationTargetException { - - Method[] methods = instance.getClass().getDeclaredMethods(); - Method postConstruct = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(PostConstruct.class)) { - if ((postConstruct != null) - || (methods[i].getParameterTypes().length != 0) - || (Modifier.isStatic(methods[i].getModifiers())) - || (methods[i].getExceptionTypes().length > 0) - || (!methods[i].getReturnType().getName().equals("void"))) { - throw new IllegalArgumentException("Invalid PostConstruct annotation"); - } - postConstruct = methods[i]; - } - } - - // At the end the postconstruct annotated - // method is invoked - if (postConstruct != null) { - boolean accessibility = postConstruct.isAccessible(); - postConstruct.setAccessible(true); - postConstruct.invoke(instance); - postConstruct.setAccessible(accessibility); - } - - } - - - /** - * Call preDestroy method on the specified instance. - */ - public static void preDestroy(Object instance) - throws IllegalAccessException, InvocationTargetException { - - Method[] methods = instance.getClass().getDeclaredMethods(); - Method preDestroy = null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(PreDestroy.class)) { - if ((preDestroy != null) - || (methods[i].getParameterTypes().length != 0) - || (Modifier.isStatic(methods[i].getModifiers())) - || (methods[i].getExceptionTypes().length > 0) - || (!methods[i].getReturnType().getName().equals("void"))) { - throw new IllegalArgumentException("Invalid PreDestroy annotation"); - } - preDestroy = methods[i]; - } - } - - // At the end the postconstruct annotated - // method is invoked - if (preDestroy != null) { - boolean accessibility = preDestroy.isAccessible(); - preDestroy.setAccessible(true); - preDestroy.invoke(instance); - preDestroy.setAccessible(accessibility); - } - - } - - - /** - * Inject resources in specified instance. - */ - public static void injectNamingResources(javax.naming.Context context, Object instance) - throws IllegalAccessException, InvocationTargetException, NamingException { - - // Initialize fields annotations - Field[] fields = instance.getClass().getDeclaredFields(); - for (int i = 0; i < fields.length; i++) { - if (fields[i].isAnnotationPresent(Resource.class)) { - Resource annotation = (Resource) fields[i].getAnnotation(Resource.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(EJB.class)) { - EJB annotation = (EJB) fields[i].getAnnotation(EJB.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(WebServiceRef.class)) { - WebServiceRef annotation = - (WebServiceRef) fields[i].getAnnotation(WebServiceRef.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(PersistenceContext.class)) { - PersistenceContext annotation = - (PersistenceContext) fields[i].getAnnotation(PersistenceContext.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - if (fields[i].isAnnotationPresent(PersistenceUnit.class)) { - PersistenceUnit annotation = - (PersistenceUnit) fields[i].getAnnotation(PersistenceUnit.class); - lookupFieldResource(context, instance, fields[i], annotation.name()); - } - } - - // Initialize methods annotations - Method[] methods = instance.getClass().getDeclaredMethods(); - for (int i = 0; i < methods.length; i++) { - if (methods[i].isAnnotationPresent(Resource.class)) { - Resource annotation = (Resource) methods[i].getAnnotation(Resource.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(EJB.class)) { - EJB annotation = (EJB) methods[i].getAnnotation(EJB.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(WebServiceRef.class)) { - WebServiceRef annotation = - (WebServiceRef) methods[i].getAnnotation(WebServiceRef.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(PersistenceContext.class)) { - PersistenceContext annotation = - (PersistenceContext) methods[i].getAnnotation(PersistenceContext.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - if (methods[i].isAnnotationPresent(PersistenceUnit.class)) { - PersistenceUnit annotation = - (PersistenceUnit) methods[i].getAnnotation(PersistenceUnit.class); - lookupMethodResource(context, instance, methods[i], annotation.name()); - } - } - - } - - - /** - * Inject resources in specified field. - */ - protected static void lookupFieldResource(javax.naming.Context context, - Object instance, Field field, String name) - throws NamingException, IllegalAccessException { - - Object lookedupResource = null; - boolean accessibility = false; - - if ((name != null) && - (name.length() > 0)) { - lookedupResource = context.lookup(name); - } else { - lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName()); - } - - accessibility = field.isAccessible(); - field.setAccessible(true); - field.set(instance, lookedupResource); - field.setAccessible(accessibility); - } - - - /** - * Inject resources in specified method. - */ - protected static void lookupMethodResource(javax.naming.Context context, - Object instance, Method method, String name) - throws NamingException, IllegalAccessException, InvocationTargetException { - - if (!method.getName().startsWith("set") - || method.getParameterTypes().length != 1 - || !method.getReturnType().getName().equals("void")) { - throw new IllegalArgumentException("Invalid method resource injection annotation"); - } - - Object lookedupResource = null; - boolean accessibility = false; - - if ((name != null) && - (name.length() > 0)) { - lookedupResource = context.lookup(name); - } else { - lookedupResource = - context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3)); - } - - accessibility = method.isAccessible(); - method.setAccessible(true); - method.invoke(instance, lookedupResource); - method.setAccessible(accessibility); - } - - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import javax.annotation.Resource; +import javax.ejb.EJB; +import javax.naming.NamingException; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceUnit; +import javax.xml.ws.WebServiceRef; + + +/** + * Verify the annotation and Process it. + * + * @author Fabien Carrion + * @author Remy Maucherat + * @version $Revision: 303236 $, $Date: 2006-03-09 16:46:52 -0600 (Thu, 09 Mar 2006) $ + */ +public class AnnotationProcessor { + + + /** + * Call postConstruct method on the specified instance. + */ + public static void postConstruct(Object instance) + throws IllegalAccessException, InvocationTargetException { + + Method[] methods = instance.getClass().getDeclaredMethods(); + Method postConstruct = null; + for (int i = 0; i < methods.length; i++) { + if (methods[i].isAnnotationPresent(PostConstruct.class)) { + if ((postConstruct != null) + || (methods[i].getParameterTypes().length != 0) + || (Modifier.isStatic(methods[i].getModifiers())) + || (methods[i].getExceptionTypes().length > 0) + || (!methods[i].getReturnType().getName().equals("void"))) { + throw new IllegalArgumentException("Invalid PostConstruct annotation"); + } + postConstruct = methods[i]; + } + } + + // At the end the postconstruct annotated + // method is invoked + if (postConstruct != null) { + boolean accessibility = postConstruct.isAccessible(); + postConstruct.setAccessible(true); + postConstruct.invoke(instance); + postConstruct.setAccessible(accessibility); + } + + } + + + /** + * Call preDestroy method on the specified instance. + */ + public static void preDestroy(Object instance) + throws IllegalAccessException, InvocationTargetException { + + Method[] methods = instance.getClass().getDeclaredMethods(); + Method preDestroy = null; + for (int i = 0; i < methods.length; i++) { + if (methods[i].isAnnotationPresent(PreDestroy.class)) { + if ((preDestroy != null) + || (methods[i].getParameterTypes().length != 0) + || (Modifier.isStatic(methods[i].getModifiers())) + || (methods[i].getExceptionTypes().length > 0) + || (!methods[i].getReturnType().getName().equals("void"))) { + throw new IllegalArgumentException("Invalid PreDestroy annotation"); + } + preDestroy = methods[i]; + } + } + + // At the end the postconstruct annotated + // method is invoked + if (preDestroy != null) { + boolean accessibility = preDestroy.isAccessible(); + preDestroy.setAccessible(true); + preDestroy.invoke(instance); + preDestroy.setAccessible(accessibility); + } + + } + + + /** + * Inject resources in specified instance. + */ + public static void injectNamingResources(javax.naming.Context context, Object instance) + throws IllegalAccessException, InvocationTargetException, NamingException { + + // Initialize fields annotations + Field[] fields = instance.getClass().getDeclaredFields(); + for (int i = 0; i < fields.length; i++) { + if (fields[i].isAnnotationPresent(Resource.class)) { + Resource annotation = (Resource) fields[i].getAnnotation(Resource.class); + lookupFieldResource(context, instance, fields[i], annotation.name()); + } + if (fields[i].isAnnotationPresent(EJB.class)) { + EJB annotation = (EJB) fields[i].getAnnotation(EJB.class); + lookupFieldResource(context, instance, fields[i], annotation.name()); + } + if (fields[i].isAnnotationPresent(WebServiceRef.class)) { + WebServiceRef annotation = + (WebServiceRef) fields[i].getAnnotation(WebServiceRef.class); + lookupFieldResource(context, instance, fields[i], annotation.name()); + } + if (fields[i].isAnnotationPresent(PersistenceContext.class)) { + PersistenceContext annotation = + (PersistenceContext) fields[i].getAnnotation(PersistenceContext.class); + lookupFieldResource(context, instance, fields[i], annotation.name()); + } + if (fields[i].isAnnotationPresent(PersistenceUnit.class)) { + PersistenceUnit annotation = + (PersistenceUnit) fields[i].getAnnotation(PersistenceUnit.class); + lookupFieldResource(context, instance, fields[i], annotation.name()); + } + } + + // Initialize methods annotations + Method[] methods = instance.getClass().getDeclaredMethods(); + for (int i = 0; i < methods.length; i++) { + if (methods[i].isAnnotationPresent(Resource.class)) { + Resource annotation = (Resource) methods[i].getAnnotation(Resource.class); + lookupMethodResource(context, instance, methods[i], annotation.name()); + } + if (methods[i].isAnnotationPresent(EJB.class)) { + EJB annotation = (EJB) methods[i].getAnnotation(EJB.class); + lookupMethodResource(context, instance, methods[i], annotation.name()); + } + if (methods[i].isAnnotationPresent(WebServiceRef.class)) { + WebServiceRef annotation = + (WebServiceRef) methods[i].getAnnotation(WebServiceRef.class); + lookupMethodResource(context, instance, methods[i], annotation.name()); + } + if (methods[i].isAnnotationPresent(PersistenceContext.class)) { + PersistenceContext annotation = + (PersistenceContext) methods[i].getAnnotation(PersistenceContext.class); + lookupMethodResource(context, instance, methods[i], annotation.name()); + } + if (methods[i].isAnnotationPresent(PersistenceUnit.class)) { + PersistenceUnit annotation = + (PersistenceUnit) methods[i].getAnnotation(PersistenceUnit.class); + lookupMethodResource(context, instance, methods[i], annotation.name()); + } + } + + } + + + /** + * Inject resources in specified field. + */ + protected static void lookupFieldResource(javax.naming.Context context, + Object instance, Field field, String name) + throws NamingException, IllegalAccessException { + + Object lookedupResource = null; + boolean accessibility = false; + + if ((name != null) && + (name.length() > 0)) { + lookedupResource = context.lookup(name); + } else { + lookedupResource = context.lookup(instance.getClass().getName() + "/" + field.getName()); + } + + accessibility = field.isAccessible(); + field.setAccessible(true); + field.set(instance, lookedupResource); + field.setAccessible(accessibility); + } + + + /** + * Inject resources in specified method. + */ + protected static void lookupMethodResource(javax.naming.Context context, + Object instance, Method method, String name) + throws NamingException, IllegalAccessException, InvocationTargetException { + + if (!method.getName().startsWith("set") + || method.getParameterTypes().length != 1 + || !method.getReturnType().getName().equals("void")) { + throw new IllegalArgumentException("Invalid method resource injection annotation"); + } + + Object lookedupResource = null; + boolean accessibility = false; + + if ((name != null) && + (name.length() > 0)) { + lookedupResource = context.lookup(name); + } else { + lookedupResource = + context.lookup(instance.getClass().getName() + "/" + method.getName().substring(3)); + } + + accessibility = method.isAccessible(); + method.setAccessible(true); + method.invoke(instance, lookedupResource); + method.setAccessible(accessibility); + } + + +} diff --git a/java/org/apache/catalina/util/Base64.java b/java/org/apache/catalina/util/Base64.java index 87229ad5e..93c410e38 100644 --- a/java/org/apache/catalina/util/Base64.java +++ b/java/org/apache/catalina/util/Base64.java @@ -1,286 +1,286 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; - -/** - * This class provides encode/decode for RFC 2045 Base64 as defined by - * RFC 2045, N. Freed and N. Borenstein. RFC 2045: - * Multipurpose Internet Mail Extensions (MIME) Part One: Format of - * Internet Message Bodies. Reference 1996 - * - * @author Jeffrey Rodriguez - * @version $Id: Base64.java 303133 2004-08-29 16:46:15Z yoavs $ - */ -public final class Base64 -{ - static private final int BASELENGTH = 255; - static private final int LOOKUPLENGTH = 64; - static private final int TWENTYFOURBITGROUP = 24; - static private final int EIGHTBIT = 8; - static private final int SIXTEENBIT = 16; - static private final int SIXBIT = 6; - static private final int FOURBYTE = 4; - static private final int SIGN = -128; - static private final byte PAD = (byte) '='; - static private byte [] base64Alphabet = new byte[BASELENGTH]; - static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; - //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64"); - - static - { - for (int i = 0; i < BASELENGTH; i++ ) - { - base64Alphabet[i] = -1; - } - for (int i = 'Z'; i >= 'A'; i--) - { - base64Alphabet[i] = (byte) (i - 'A'); - } - for (int i = 'z'; i>= 'a'; i--) - { - base64Alphabet[i] = (byte) (i - 'a' + 26); - } - for (int i = '9'; i >= '0'; i--) - { - base64Alphabet[i] = (byte) (i - '0' + 52); - } - - base64Alphabet['+'] = 62; - base64Alphabet['/'] = 63; - - for (int i = 0; i <= 25; i++ ) - lookUpBase64Alphabet[i] = (byte) ('A' + i); - - for (int i = 26, j = 0; i <= 51; i++, j++ ) - lookUpBase64Alphabet[i] = (byte) ('a'+ j); - - for (int i = 52, j = 0; i <= 61; i++, j++ ) - lookUpBase64Alphabet[i] = (byte) ('0' + j); - - lookUpBase64Alphabet[62] = (byte) '+'; - lookUpBase64Alphabet[63] = (byte) '/'; - } - - public static boolean isBase64( String isValidString ) - { - return isArrayByteBase64(isValidString.getBytes()); - } - - public static boolean isBase64( byte octect ) - { - //shall we ignore white space? JEFF?? - return (octect == PAD || base64Alphabet[octect] != -1); - } - - public static boolean isArrayByteBase64( byte[] arrayOctect ) - { - int length = arrayOctect.length; - if (length == 0) - { - // shouldn't a 0 length array be valid base64 data? - // return false; - return true; - } - for (int i=0; i < length; i++) - { - if ( !Base64.isBase64(arrayOctect[i]) ) - return false; - } - return true; - } - - /** - * Encodes hex octects into Base64. - * - * @param binaryData Array containing binary data to encode. - * @return Base64-encoded data. - */ - public static byte[] encode( byte[] binaryData ) - { - int lengthDataBits = binaryData.length*EIGHTBIT; - int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; - int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; - byte encodedData[] = null; - - - if (fewerThan24bits != 0) - { - //data not divisible by 24 bit - encodedData = new byte[ (numberTriplets + 1 ) * 4 ]; - } - else - { - // 16 or 8 bit - encodedData = new byte[ numberTriplets * 4 ]; - } - - byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; - - int encodedIndex = 0; - int dataIndex = 0; - int i = 0; - //log.debug("number of triplets = " + numberTriplets); - for ( i = 0; iRFC 2045: + * Multipurpose Internet Mail Extensions (MIME) Part One: Format of + * Internet Message Bodies. Reference 1996 + * + * @author Jeffrey Rodriguez + * @version $Id: Base64.java 303133 2004-08-29 16:46:15Z yoavs $ + */ +public final class Base64 +{ + static private final int BASELENGTH = 255; + static private final int LOOKUPLENGTH = 64; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + static private final int SIGN = -128; + static private final byte PAD = (byte) '='; + static private byte [] base64Alphabet = new byte[BASELENGTH]; + static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; + //static private final Log log = LogSource.getInstance("org.apache.commons.util.Base64"); + + static + { + for (int i = 0; i < BASELENGTH; i++ ) + { + base64Alphabet[i] = -1; + } + for (int i = 'Z'; i >= 'A'; i--) + { + base64Alphabet[i] = (byte) (i - 'A'); + } + for (int i = 'z'; i>= 'a'; i--) + { + base64Alphabet[i] = (byte) (i - 'a' + 26); + } + for (int i = '9'; i >= '0'; i--) + { + base64Alphabet[i] = (byte) (i - '0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i <= 25; i++ ) + lookUpBase64Alphabet[i] = (byte) ('A' + i); + + for (int i = 26, j = 0; i <= 51; i++, j++ ) + lookUpBase64Alphabet[i] = (byte) ('a'+ j); + + for (int i = 52, j = 0; i <= 61; i++, j++ ) + lookUpBase64Alphabet[i] = (byte) ('0' + j); + + lookUpBase64Alphabet[62] = (byte) '+'; + lookUpBase64Alphabet[63] = (byte) '/'; + } + + public static boolean isBase64( String isValidString ) + { + return isArrayByteBase64(isValidString.getBytes()); + } + + public static boolean isBase64( byte octect ) + { + //shall we ignore white space? JEFF?? + return (octect == PAD || base64Alphabet[octect] != -1); + } + + public static boolean isArrayByteBase64( byte[] arrayOctect ) + { + int length = arrayOctect.length; + if (length == 0) + { + // shouldn't a 0 length array be valid base64 data? + // return false; + return true; + } + for (int i=0; i < length; i++) + { + if ( !Base64.isBase64(arrayOctect[i]) ) + return false; + } + return true; + } + + /** + * Encodes hex octects into Base64. + * + * @param binaryData Array containing binary data to encode. + * @return Base64-encoded data. + */ + public static byte[] encode( byte[] binaryData ) + { + int lengthDataBits = binaryData.length*EIGHTBIT; + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + byte encodedData[] = null; + + + if (fewerThan24bits != 0) + { + //data not divisible by 24 bit + encodedData = new byte[ (numberTriplets + 1 ) * 4 ]; + } + else + { + // 16 or 8 bit + encodedData = new byte[ numberTriplets * 4 ]; + } + + byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0; + + int encodedIndex = 0; + int dataIndex = 0; + int i = 0; + //log.debug("number of triplets = " + numberTriplets); + for ( i = 0; i= 0) { - if (version == 0) { - buf.append ("; Expires="); - if (cookie.getMaxAge() == 0) - DateTool.oldCookieFormat.format(new Date(10000), buf, - new FieldPosition(0)); - else - DateTool.oldCookieFormat.format - (new Date( System.currentTimeMillis() + - cookie.getMaxAge() *1000L), buf, - new FieldPosition(0)); - } else { - buf.append ("; Max-Age="); - buf.append (cookie.getMaxAge()); - } - } else if (version == 1) - buf.append ("; Discard"); - - // Path=path - if (cookie.getPath() != null) { - buf.append ("; Path="); - maybeQuote (version, buf, cookie.getPath()); - } - - // Secure - if (cookie.getSecure()) { - buf.append ("; Secure"); - } - } - - static void maybeQuote (int version, StringBuffer buf, - String value) - { - if (version == 0 || isToken (value)) - buf.append (value); - else { - buf.append ('"'); - buf.append (value); - buf.append ('"'); - } - } - - // - // from RFC 2068, token special case characters - // - private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; - - /* - * Return true iff the string counts as an HTTP/1.1 "token". - */ - private static boolean isToken (String value) { - int len = value.length (); - - for (int i = 0; i < len; i++) { - char c = value.charAt (i); - - if (c < 0x20 || c >= 0x7f || tspecials.indexOf (c) != -1) - return false; - } - return true; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + +import java.text.*; +import java.util.*; + +import javax.servlet.http.Cookie; + +// XXX use only one Date instance/request, reuse it. + +/** + * Cookie utils - generate cookie header, etc + * + * @author Original Author Unknown + * @author duncan@eng.sun.com + */ +public class CookieTools { + + /** Return the header name to set the cookie, based on cookie + * version + */ + public static String getCookieHeaderName(Cookie cookie) { + int version = cookie.getVersion(); + + if (version == 1) { + return "Set-Cookie2"; + } else { + return "Set-Cookie"; + } + } + + /** Return the header value used to set this cookie + * @deprecated Use StringBuffer version + */ + public static String getCookieHeaderValue(Cookie cookie) { + StringBuffer buf = new StringBuffer(); + getCookieHeaderValue( cookie, buf ); + return buf.toString(); + } + + /** Return the header value used to set this cookie + */ + public static void getCookieHeaderValue(Cookie cookie, StringBuffer buf) { + int version = cookie.getVersion(); + + // this part is the same for all cookies + + String name = cookie.getName(); // Avoid NPE on malformed cookies + if (name == null) + name = ""; + String value = cookie.getValue(); + if (value == null) + value = ""; + + buf.append(name); + buf.append("="); + maybeQuote(version, buf, value); + + // add version 1 specific information + if (version == 1) { + // Version=1 ... required + buf.append ("; Version=1"); + + // Comment=comment + if (cookie.getComment() != null) { + buf.append ("; Comment="); + maybeQuote (version, buf, cookie.getComment()); + } + } + + // add domain information, if present + + if (cookie.getDomain() != null) { + buf.append("; Domain="); + maybeQuote (version, buf, cookie.getDomain()); + } + + // Max-Age=secs/Discard ... or use old "Expires" format + if (cookie.getMaxAge() >= 0) { + if (version == 0) { + buf.append ("; Expires="); + if (cookie.getMaxAge() == 0) + DateTool.oldCookieFormat.format(new Date(10000), buf, + new FieldPosition(0)); + else + DateTool.oldCookieFormat.format + (new Date( System.currentTimeMillis() + + cookie.getMaxAge() *1000L), buf, + new FieldPosition(0)); + } else { + buf.append ("; Max-Age="); + buf.append (cookie.getMaxAge()); + } + } else if (version == 1) + buf.append ("; Discard"); + + // Path=path + if (cookie.getPath() != null) { + buf.append ("; Path="); + maybeQuote (version, buf, cookie.getPath()); + } + + // Secure + if (cookie.getSecure()) { + buf.append ("; Secure"); + } + } + + static void maybeQuote (int version, StringBuffer buf, + String value) + { + if (version == 0 || isToken (value)) + buf.append (value); + else { + buf.append ('"'); + buf.append (value); + buf.append ('"'); + } + } + + // + // from RFC 2068, token special case characters + // + private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; + + /* + * Return true iff the string counts as an HTTP/1.1 "token". + */ + private static boolean isToken (String value) { + int len = value.length (); + + for (int i = 0; i < len; i++) { + char c = value.charAt (i); + + if (c < 0x20 || c >= 0x7f || tspecials.indexOf (c) != -1) + return false; + } + return true; + } + + +} diff --git a/java/org/apache/catalina/util/CustomObjectInputStream.java b/java/org/apache/catalina/util/CustomObjectInputStream.java index 359733f5c..eec386d06 100644 --- a/java/org/apache/catalina/util/CustomObjectInputStream.java +++ b/java/org/apache/catalina/util/CustomObjectInputStream.java @@ -1,101 +1,101 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.io.InputStream; -import java.io.IOException; -import java.io.ObjectInputStream; -import java.io.ObjectStreamClass; -import java.lang.reflect.Proxy; - -/** - * Custom subclass of ObjectInputStream that loads from the - * class loader for this web application. This allows classes defined only - * with the web application to be found correctly. - * - * @author Craig R. McClanahan - * @author Bip Thelin - * @version $Revision: 304082 $, $Date: 2005-09-08 17:41:11 +0200 (jeu., 08 sept. 2005) $ - */ - -public final class CustomObjectInputStream - extends ObjectInputStream { - - - /** - * The class loader we will use to resolve classes. - */ - private ClassLoader classLoader = null; - - - /** - * Construct a new instance of CustomObjectInputStream - * - * @param stream The input stream we will read from - * @param classLoader The class loader used to instantiate objects - * - * @exception IOException if an input/output error occurs - */ - public CustomObjectInputStream(InputStream stream, - ClassLoader classLoader) - throws IOException { - - super(stream); - this.classLoader = classLoader; - } - - - /** - * Load the local class equivalent of the specified stream class - * description, by using the class loader assigned to this Context. - * - * @param classDesc Class description from the input stream - * - * @exception ClassNotFoundException if this class cannot be found - * @exception IOException if an input/output error occurs - */ - public Class resolveClass(ObjectStreamClass classDesc) - throws ClassNotFoundException, IOException { - try { - return Class.forName(classDesc.getName(), false, classLoader); - } catch (ClassNotFoundException e) { - // Try also the superclass because of primitive types - return super.resolveClass(classDesc); - } - } - - - /** - * Return a proxy class that implements the interfaces named in a proxy - * class descriptor. Do this using the class loader assigned to this - * Context. - */ - protected Class resolveProxyClass(String[] interfaces) - throws IOException, ClassNotFoundException { - - Class[] cinterfaces = new Class[interfaces.length]; - for (int i = 0; i < interfaces.length; i++) - cinterfaces[i] = classLoader.loadClass(interfaces[i]); - - try { - return Proxy.getProxyClass(classLoader, cinterfaces); - } catch (IllegalArgumentException e) { - throw new ClassNotFoundException(null, e); - } - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.lang.reflect.Proxy; + +/** + * Custom subclass of ObjectInputStream that loads from the + * class loader for this web application. This allows classes defined only + * with the web application to be found correctly. + * + * @author Craig R. McClanahan + * @author Bip Thelin + * @version $Revision: 304082 $, $Date: 2005-09-08 17:41:11 +0200 (jeu., 08 sept. 2005) $ + */ + +public final class CustomObjectInputStream + extends ObjectInputStream { + + + /** + * The class loader we will use to resolve classes. + */ + private ClassLoader classLoader = null; + + + /** + * Construct a new instance of CustomObjectInputStream + * + * @param stream The input stream we will read from + * @param classLoader The class loader used to instantiate objects + * + * @exception IOException if an input/output error occurs + */ + public CustomObjectInputStream(InputStream stream, + ClassLoader classLoader) + throws IOException { + + super(stream); + this.classLoader = classLoader; + } + + + /** + * Load the local class equivalent of the specified stream class + * description, by using the class loader assigned to this Context. + * + * @param classDesc Class description from the input stream + * + * @exception ClassNotFoundException if this class cannot be found + * @exception IOException if an input/output error occurs + */ + public Class resolveClass(ObjectStreamClass classDesc) + throws ClassNotFoundException, IOException { + try { + return Class.forName(classDesc.getName(), false, classLoader); + } catch (ClassNotFoundException e) { + // Try also the superclass because of primitive types + return super.resolveClass(classDesc); + } + } + + + /** + * Return a proxy class that implements the interfaces named in a proxy + * class descriptor. Do this using the class loader assigned to this + * Context. + */ + protected Class resolveProxyClass(String[] interfaces) + throws IOException, ClassNotFoundException { + + Class[] cinterfaces = new Class[interfaces.length]; + for (int i = 0; i < interfaces.length; i++) + cinterfaces[i] = classLoader.loadClass(interfaces[i]); + + try { + return Proxy.getProxyClass(classLoader, cinterfaces); + } catch (IllegalArgumentException e) { + throw new ClassNotFoundException(null, e); + } + } + +} diff --git a/java/org/apache/catalina/util/DOMWriter.java b/java/org/apache/catalina/util/DOMWriter.java index e87ef5c6a..d350356af 100644 --- a/java/org/apache/catalina/util/DOMWriter.java +++ b/java/org/apache/catalina/util/DOMWriter.java @@ -1,348 +1,348 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.io.Writer; - -import org.w3c.dom.Attr; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; - -/** - * A sample DOM writer. This sample program illustrates how to - * traverse a DOM tree in order to print a document that is parsed. - */ -public class DOMWriter { - - // - // Data - // - - /** Default Encoding */ - private static String - PRINTWRITER_ENCODING = "UTF8"; - - private static String MIME2JAVA_ENCODINGS[] = - { "Default", "UTF-8", "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", - "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP", - "SHIFT_JIS", "EUC-JP","GB2312", "BIG5", "EUC-KR", "ISO-2022-KR", "KOI8-R", "EBCDIC-CP-US", - "EBCDIC-CP-CA", "EBCDIC-CP-NL", "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI", "EBCDIC-CP-SE", - "EBCDIC-CP-IT", "EBCDIC-CP-ES", "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1", - "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE","EBCDIC-CP-YU", - "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16" - }; - - /** Output qualified names */ - private boolean qualifiedNames = true; - - /** Print writer. */ - protected PrintWriter out; - - /** Canonical output. */ - protected boolean canonical; - - - public DOMWriter(String encoding, boolean canonical) - throws UnsupportedEncodingException { - out = new PrintWriter(new OutputStreamWriter(System.out, encoding)); - this.canonical = canonical; - } // (String,boolean) - - // - // Constructors - // - - /** Default constructor. */ - public DOMWriter(boolean canonical) throws UnsupportedEncodingException { - this( getWriterEncoding(), canonical); - } - - public DOMWriter(Writer writer, boolean canonical) { - out = new PrintWriter(writer); - this.canonical = canonical; - } - - public boolean getQualifiedNames() { - return this.qualifiedNames; - } - - public void setQualifiedNames(boolean qualifiedNames) { - this.qualifiedNames = qualifiedNames; - } - - public static String getWriterEncoding( ) { - return (PRINTWRITER_ENCODING); - }// getWriterEncoding - - public static void setWriterEncoding( String encoding ) { - if( encoding.equalsIgnoreCase( "DEFAULT" ) ) - PRINTWRITER_ENCODING = "UTF8"; - else if( encoding.equalsIgnoreCase( "UTF-16" ) ) - PRINTWRITER_ENCODING = "Unicode"; - else - PRINTWRITER_ENCODING = MIME2Java.convert( encoding ); - }// setWriterEncoding - - - public static boolean isValidJavaEncoding( String encoding ) { - for ( int i = 0; i < MIME2JAVA_ENCODINGS.length; i++ ) - if ( encoding.equals( MIME2JAVA_ENCODINGS[i] ) ) - return (true); - - return (false); - }// isValidJavaEncoding - - - /** Prints the specified node, recursively. */ - public void print(Node node) { - - // is there anything to do? - if ( node == null ) { - return; - } - - int type = node.getNodeType(); - switch ( type ) { - // print document - case Node.DOCUMENT_NODE: { - if ( !canonical ) { - String Encoding = getWriterEncoding(); - if( Encoding.equalsIgnoreCase( "DEFAULT" ) ) - Encoding = "UTF-8"; - else if( Encoding.equalsIgnoreCase( "Unicode" ) ) - Encoding = "UTF-16"; - else - Encoding = MIME2Java.reverse( Encoding ); - - out.println(""); - } - print(((Document)node).getDocumentElement()); - out.flush(); - break; - } - - // print element with attributes - case Node.ELEMENT_NODE: { - out.print('<'); - if (this.qualifiedNames) { - out.print(node.getNodeName()); - } else { - out.print(node.getLocalName()); - } - Attr attrs[] = sortAttributes(node.getAttributes()); - for ( int i = 0; i < attrs.length; i++ ) { - Attr attr = attrs[i]; - out.print(' '); - if (this.qualifiedNames) { - out.print(attr.getNodeName()); - } else { - out.print(attr.getLocalName()); - } - - out.print("=\""); - out.print(normalize(attr.getNodeValue())); - out.print('"'); - } - out.print('>'); - NodeList children = node.getChildNodes(); - if ( children != null ) { - int len = children.getLength(); - for ( int i = 0; i < len; i++ ) { - print(children.item(i)); - } - } - break; - } - - // handle entity reference nodes - case Node.ENTITY_REFERENCE_NODE: { - if ( canonical ) { - NodeList children = node.getChildNodes(); - if ( children != null ) { - int len = children.getLength(); - for ( int i = 0; i < len; i++ ) { - print(children.item(i)); - } - } - } else { - out.print('&'); - if (this.qualifiedNames) { - out.print(node.getNodeName()); - } else { - out.print(node.getLocalName()); - } - out.print(';'); - } - break; - } - - // print cdata sections - case Node.CDATA_SECTION_NODE: { - if ( canonical ) { - out.print(normalize(node.getNodeValue())); - } else { - out.print(""); - } - break; - } - - // print text - case Node.TEXT_NODE: { - out.print(normalize(node.getNodeValue())); - break; - } - - // print processing instruction - case Node.PROCESSING_INSTRUCTION_NODE: { - out.print(" 0 ) { - out.print(' '); - out.print(data); - } - out.print("?>"); - break; - } - } - - if ( type == Node.ELEMENT_NODE ) { - out.print("'); - } - - out.flush(); - - } // print(Node) - - /** Returns a sorted list of attributes. */ - protected Attr[] sortAttributes(NamedNodeMap attrs) { - - int len = (attrs != null) ? attrs.getLength() : 0; - Attr array[] = new Attr[len]; - for ( int i = 0; i < len; i++ ) { - array[i] = (Attr)attrs.item(i); - } - for ( int i = 0; i < len - 1; i++ ) { - String name = null; - if (this.qualifiedNames) { - name = array[i].getNodeName(); - } else { - name = array[i].getLocalName(); - } - int index = i; - for ( int j = i + 1; j < len; j++ ) { - String curName = null; - if (this.qualifiedNames) { - curName = array[j].getNodeName(); - } else { - curName = array[j].getLocalName(); - } - if ( curName.compareTo(name) < 0 ) { - name = curName; - index = j; - } - } - if ( index != i ) { - Attr temp = array[i]; - array[i] = array[index]; - array[index] = temp; - } - } - - return (array); - - } // sortAttributes(NamedNodeMap):Attr[] - - - /** Normalizes the given string. */ - protected String normalize(String s) { - StringBuffer str = new StringBuffer(); - - int len = (s != null) ? s.length() : 0; - for ( int i = 0; i < len; i++ ) { - char ch = s.charAt(i); - switch ( ch ) { - case '<': { - str.append("<"); - break; - } - case '>': { - str.append(">"); - break; - } - case '&': { - str.append("&"); - break; - } - case '"': { - str.append("""); - break; - } - case '\r': - case '\n': { - if ( canonical ) { - str.append("&#"); - str.append(Integer.toString(ch)); - str.append(';'); - break; - } - // else, default append char - } - default: { - str.append(ch); - } - } - } - - return (str.toString()); - - } // normalize(String):String - - private static void printValidJavaEncoding() { - System.err.println( " ENCODINGS:" ); - System.err.print( " " ); - for( int i = 0; - i < MIME2JAVA_ENCODINGS.length; i++) { - System.err.print( MIME2JAVA_ENCODINGS[i] + " " ); - if( (i % 7 ) == 0 ){ - System.err.println(); - System.err.print( " " ); - } - } - - } // printJavaEncoding() - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +/** + * A sample DOM writer. This sample program illustrates how to + * traverse a DOM tree in order to print a document that is parsed. + */ +public class DOMWriter { + + // + // Data + // + + /** Default Encoding */ + private static String + PRINTWRITER_ENCODING = "UTF8"; + + private static String MIME2JAVA_ENCODINGS[] = + { "Default", "UTF-8", "US-ASCII", "ISO-8859-1", "ISO-8859-2", "ISO-8859-3", "ISO-8859-4", + "ISO-8859-5", "ISO-8859-6", "ISO-8859-7", "ISO-8859-8", "ISO-8859-9", "ISO-2022-JP", + "SHIFT_JIS", "EUC-JP","GB2312", "BIG5", "EUC-KR", "ISO-2022-KR", "KOI8-R", "EBCDIC-CP-US", + "EBCDIC-CP-CA", "EBCDIC-CP-NL", "EBCDIC-CP-DK", "EBCDIC-CP-NO", "EBCDIC-CP-FI", "EBCDIC-CP-SE", + "EBCDIC-CP-IT", "EBCDIC-CP-ES", "EBCDIC-CP-GB", "EBCDIC-CP-FR", "EBCDIC-CP-AR1", + "EBCDIC-CP-HE", "EBCDIC-CP-CH", "EBCDIC-CP-ROECE","EBCDIC-CP-YU", + "EBCDIC-CP-IS", "EBCDIC-CP-AR2", "UTF-16" + }; + + /** Output qualified names */ + private boolean qualifiedNames = true; + + /** Print writer. */ + protected PrintWriter out; + + /** Canonical output. */ + protected boolean canonical; + + + public DOMWriter(String encoding, boolean canonical) + throws UnsupportedEncodingException { + out = new PrintWriter(new OutputStreamWriter(System.out, encoding)); + this.canonical = canonical; + } // (String,boolean) + + // + // Constructors + // + + /** Default constructor. */ + public DOMWriter(boolean canonical) throws UnsupportedEncodingException { + this( getWriterEncoding(), canonical); + } + + public DOMWriter(Writer writer, boolean canonical) { + out = new PrintWriter(writer); + this.canonical = canonical; + } + + public boolean getQualifiedNames() { + return this.qualifiedNames; + } + + public void setQualifiedNames(boolean qualifiedNames) { + this.qualifiedNames = qualifiedNames; + } + + public static String getWriterEncoding( ) { + return (PRINTWRITER_ENCODING); + }// getWriterEncoding + + public static void setWriterEncoding( String encoding ) { + if( encoding.equalsIgnoreCase( "DEFAULT" ) ) + PRINTWRITER_ENCODING = "UTF8"; + else if( encoding.equalsIgnoreCase( "UTF-16" ) ) + PRINTWRITER_ENCODING = "Unicode"; + else + PRINTWRITER_ENCODING = MIME2Java.convert( encoding ); + }// setWriterEncoding + + + public static boolean isValidJavaEncoding( String encoding ) { + for ( int i = 0; i < MIME2JAVA_ENCODINGS.length; i++ ) + if ( encoding.equals( MIME2JAVA_ENCODINGS[i] ) ) + return (true); + + return (false); + }// isValidJavaEncoding + + + /** Prints the specified node, recursively. */ + public void print(Node node) { + + // is there anything to do? + if ( node == null ) { + return; + } + + int type = node.getNodeType(); + switch ( type ) { + // print document + case Node.DOCUMENT_NODE: { + if ( !canonical ) { + String Encoding = getWriterEncoding(); + if( Encoding.equalsIgnoreCase( "DEFAULT" ) ) + Encoding = "UTF-8"; + else if( Encoding.equalsIgnoreCase( "Unicode" ) ) + Encoding = "UTF-16"; + else + Encoding = MIME2Java.reverse( Encoding ); + + out.println(""); + } + print(((Document)node).getDocumentElement()); + out.flush(); + break; + } + + // print element with attributes + case Node.ELEMENT_NODE: { + out.print('<'); + if (this.qualifiedNames) { + out.print(node.getNodeName()); + } else { + out.print(node.getLocalName()); + } + Attr attrs[] = sortAttributes(node.getAttributes()); + for ( int i = 0; i < attrs.length; i++ ) { + Attr attr = attrs[i]; + out.print(' '); + if (this.qualifiedNames) { + out.print(attr.getNodeName()); + } else { + out.print(attr.getLocalName()); + } + + out.print("=\""); + out.print(normalize(attr.getNodeValue())); + out.print('"'); + } + out.print('>'); + NodeList children = node.getChildNodes(); + if ( children != null ) { + int len = children.getLength(); + for ( int i = 0; i < len; i++ ) { + print(children.item(i)); + } + } + break; + } + + // handle entity reference nodes + case Node.ENTITY_REFERENCE_NODE: { + if ( canonical ) { + NodeList children = node.getChildNodes(); + if ( children != null ) { + int len = children.getLength(); + for ( int i = 0; i < len; i++ ) { + print(children.item(i)); + } + } + } else { + out.print('&'); + if (this.qualifiedNames) { + out.print(node.getNodeName()); + } else { + out.print(node.getLocalName()); + } + out.print(';'); + } + break; + } + + // print cdata sections + case Node.CDATA_SECTION_NODE: { + if ( canonical ) { + out.print(normalize(node.getNodeValue())); + } else { + out.print(""); + } + break; + } + + // print text + case Node.TEXT_NODE: { + out.print(normalize(node.getNodeValue())); + break; + } + + // print processing instruction + case Node.PROCESSING_INSTRUCTION_NODE: { + out.print(" 0 ) { + out.print(' '); + out.print(data); + } + out.print("?>"); + break; + } + } + + if ( type == Node.ELEMENT_NODE ) { + out.print("'); + } + + out.flush(); + + } // print(Node) + + /** Returns a sorted list of attributes. */ + protected Attr[] sortAttributes(NamedNodeMap attrs) { + + int len = (attrs != null) ? attrs.getLength() : 0; + Attr array[] = new Attr[len]; + for ( int i = 0; i < len; i++ ) { + array[i] = (Attr)attrs.item(i); + } + for ( int i = 0; i < len - 1; i++ ) { + String name = null; + if (this.qualifiedNames) { + name = array[i].getNodeName(); + } else { + name = array[i].getLocalName(); + } + int index = i; + for ( int j = i + 1; j < len; j++ ) { + String curName = null; + if (this.qualifiedNames) { + curName = array[j].getNodeName(); + } else { + curName = array[j].getLocalName(); + } + if ( curName.compareTo(name) < 0 ) { + name = curName; + index = j; + } + } + if ( index != i ) { + Attr temp = array[i]; + array[i] = array[index]; + array[index] = temp; + } + } + + return (array); + + } // sortAttributes(NamedNodeMap):Attr[] + + + /** Normalizes the given string. */ + protected String normalize(String s) { + StringBuffer str = new StringBuffer(); + + int len = (s != null) ? s.length() : 0; + for ( int i = 0; i < len; i++ ) { + char ch = s.charAt(i); + switch ( ch ) { + case '<': { + str.append("<"); + break; + } + case '>': { + str.append(">"); + break; + } + case '&': { + str.append("&"); + break; + } + case '"': { + str.append("""); + break; + } + case '\r': + case '\n': { + if ( canonical ) { + str.append("&#"); + str.append(Integer.toString(ch)); + str.append(';'); + break; + } + // else, default append char + } + default: { + str.append(ch); + } + } + } + + return (str.toString()); + + } // normalize(String):String + + private static void printValidJavaEncoding() { + System.err.println( " ENCODINGS:" ); + System.err.print( " " ); + for( int i = 0; + i < MIME2JAVA_ENCODINGS.length; i++) { + System.err.print( MIME2JAVA_ENCODINGS[i] + " " ); + if( (i % 7 ) == 0 ){ + System.err.println(); + System.err.print( " " ); + } + } + + } // printJavaEncoding() + +} diff --git a/java/org/apache/catalina/util/DateTool.java b/java/org/apache/catalina/util/DateTool.java index 5404eac69..b5b8487fe 100644 --- a/java/org/apache/catalina/util/DateTool.java +++ b/java/org/apache/catalina/util/DateTool.java @@ -1,98 +1,98 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.Locale; -import java.util.TimeZone; - -/** - * Common place for date utils. - * - * @author dac@eng.sun.com - * @author Jason Hunter [jch@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Costin Manolache - */ -public class DateTool { - - private static StringManager sm = - StringManager.getManager("org.apache.catalina.util"); - - /** - * US locale - all HTTP dates are in english - */ - public final static Locale LOCALE_US = Locale.US; - - /** - * GMT timezone - all HTTP dates are on GMT - */ - public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); - - /** - * format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" - */ - public final static String RFC1123_PATTERN = - "EEE, dd MMM yyyyy HH:mm:ss z"; - - /** - * Format for http response header date field - */ - public static final String HTTP_RESPONSE_DATE_HEADER = - "EEE, dd MMM yyyy HH:mm:ss zzz"; - - // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT" - private final static String rfc1036Pattern = - "EEEEEEEEE, dd-MMM-yy HH:mm:ss z"; - - // format for C asctime() date string -- "Sun Nov 6 08:49:37 1994" - private final static String asctimePattern = - "EEE MMM d HH:mm:ss yyyyy"; - - /** - * Pattern used for old cookies - */ - public final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; - - /** - * DateFormat to be used to format dates - */ - public final static DateFormat rfc1123Format = - new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US); - - /** - * DateFormat to be used to format old netscape cookies - */ - public final static DateFormat oldCookieFormat = - new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US); - - public final static DateFormat rfc1036Format = - new SimpleDateFormat(rfc1036Pattern, LOCALE_US); - - public final static DateFormat asctimeFormat = - new SimpleDateFormat(asctimePattern, LOCALE_US); - - static { - rfc1123Format.setTimeZone(GMT_ZONE); - oldCookieFormat.setTimeZone(GMT_ZONE); - rfc1036Format.setTimeZone(GMT_ZONE); - asctimeFormat.setTimeZone(GMT_ZONE); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Locale; +import java.util.TimeZone; + +/** + * Common place for date utils. + * + * @author dac@eng.sun.com + * @author Jason Hunter [jch@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Costin Manolache + */ +public class DateTool { + + private static StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + /** + * US locale - all HTTP dates are in english + */ + public final static Locale LOCALE_US = Locale.US; + + /** + * GMT timezone - all HTTP dates are on GMT + */ + public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); + + /** + * format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" + */ + public final static String RFC1123_PATTERN = + "EEE, dd MMM yyyyy HH:mm:ss z"; + + /** + * Format for http response header date field + */ + public static final String HTTP_RESPONSE_DATE_HEADER = + "EEE, dd MMM yyyy HH:mm:ss zzz"; + + // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT" + private final static String rfc1036Pattern = + "EEEEEEEEE, dd-MMM-yy HH:mm:ss z"; + + // format for C asctime() date string -- "Sun Nov 6 08:49:37 1994" + private final static String asctimePattern = + "EEE MMM d HH:mm:ss yyyyy"; + + /** + * Pattern used for old cookies + */ + public final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; + + /** + * DateFormat to be used to format dates + */ + public final static DateFormat rfc1123Format = + new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US); + + /** + * DateFormat to be used to format old netscape cookies + */ + public final static DateFormat oldCookieFormat = + new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US); + + public final static DateFormat rfc1036Format = + new SimpleDateFormat(rfc1036Pattern, LOCALE_US); + + public final static DateFormat asctimeFormat = + new SimpleDateFormat(asctimePattern, LOCALE_US); + + static { + rfc1123Format.setTimeZone(GMT_ZONE); + oldCookieFormat.setTimeZone(GMT_ZONE); + rfc1036Format.setTimeZone(GMT_ZONE); + asctimeFormat.setTimeZone(GMT_ZONE); + } + +} diff --git a/java/org/apache/catalina/util/Enumerator.java b/java/org/apache/catalina/util/Enumerator.java index 851285f2e..96aa68010 100644 --- a/java/org/apache/catalina/util/Enumerator.java +++ b/java/org/apache/catalina/util/Enumerator.java @@ -1,175 +1,175 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.util.Collection; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.ArrayList; -import java.util.Map; -import java.util.NoSuchElementException; - - -/** - * Adapter class that wraps an Enumeration around a Java2 - * collection classes object Iterator so that existing APIs - * returning Enumerations can easily run on top of the new collections. - * Constructors are provided to easliy create such wrappers. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class Enumerator implements Enumeration { - - - // ----------------------------------------------------------- Constructors - - - /** - * Return an Enumeration over the values of the specified Collection. - * - * @param collection Collection whose values should be enumerated - */ - public Enumerator(Collection collection) { - - this(collection.iterator()); - - } - - - /** - * Return an Enumeration over the values of the specified Collection. - * - * @param collection Collection whose values should be enumerated - * @param clone true to clone iterator - */ - public Enumerator(Collection collection, boolean clone) { - - this(collection.iterator(), clone); - - } - - - /** - * Return an Enumeration over the values returned by the - * specified Iterator. - * - * @param iterator Iterator to be wrapped - */ - public Enumerator(Iterator iterator) { - - super(); - this.iterator = iterator; - - } - - - /** - * Return an Enumeration over the values returned by the - * specified Iterator. - * - * @param iterator Iterator to be wrapped - * @param clone true to clone iterator - */ - public Enumerator(Iterator iterator, boolean clone) { - - super(); - if (!clone) { - this.iterator = iterator; - } else { - List list = new ArrayList(); - while (iterator.hasNext()) { - list.add(iterator.next()); - } - this.iterator = list.iterator(); - } - - } - - - /** - * Return an Enumeration over the values of the specified Map. - * - * @param map Map whose values should be enumerated - */ - public Enumerator(Map map) { - - this(map.values().iterator()); - - } - - - /** - * Return an Enumeration over the values of the specified Map. - * - * @param map Map whose values should be enumerated - * @param clone true to clone iterator - */ - public Enumerator(Map map, boolean clone) { - - this(map.values().iterator(), clone); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The Iterator over which the Enumeration - * represented by this class actually operates. - */ - private Iterator iterator = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Tests if this enumeration contains more elements. - * - * @return true if and only if this enumeration object - * contains at least one more element to provide, false - * otherwise - */ - public boolean hasMoreElements() { - - return (iterator.hasNext()); - - } - - - /** - * Returns the next element of this enumeration if this enumeration - * has at least one more element to provide. - * - * @return the next element of this enumeration - * - * @exception NoSuchElementException if no more elements exist - */ - public Object nextElement() throws NoSuchElementException { - - return (iterator.next()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.ArrayList; +import java.util.Map; +import java.util.NoSuchElementException; + + +/** + * Adapter class that wraps an Enumeration around a Java2 + * collection classes object Iterator so that existing APIs + * returning Enumerations can easily run on top of the new collections. + * Constructors are provided to easliy create such wrappers. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class Enumerator implements Enumeration { + + + // ----------------------------------------------------------- Constructors + + + /** + * Return an Enumeration over the values of the specified Collection. + * + * @param collection Collection whose values should be enumerated + */ + public Enumerator(Collection collection) { + + this(collection.iterator()); + + } + + + /** + * Return an Enumeration over the values of the specified Collection. + * + * @param collection Collection whose values should be enumerated + * @param clone true to clone iterator + */ + public Enumerator(Collection collection, boolean clone) { + + this(collection.iterator(), clone); + + } + + + /** + * Return an Enumeration over the values returned by the + * specified Iterator. + * + * @param iterator Iterator to be wrapped + */ + public Enumerator(Iterator iterator) { + + super(); + this.iterator = iterator; + + } + + + /** + * Return an Enumeration over the values returned by the + * specified Iterator. + * + * @param iterator Iterator to be wrapped + * @param clone true to clone iterator + */ + public Enumerator(Iterator iterator, boolean clone) { + + super(); + if (!clone) { + this.iterator = iterator; + } else { + List list = new ArrayList(); + while (iterator.hasNext()) { + list.add(iterator.next()); + } + this.iterator = list.iterator(); + } + + } + + + /** + * Return an Enumeration over the values of the specified Map. + * + * @param map Map whose values should be enumerated + */ + public Enumerator(Map map) { + + this(map.values().iterator()); + + } + + + /** + * Return an Enumeration over the values of the specified Map. + * + * @param map Map whose values should be enumerated + * @param clone true to clone iterator + */ + public Enumerator(Map map, boolean clone) { + + this(map.values().iterator(), clone); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Iterator over which the Enumeration + * represented by this class actually operates. + */ + private Iterator iterator = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Tests if this enumeration contains more elements. + * + * @return true if and only if this enumeration object + * contains at least one more element to provide, false + * otherwise + */ + public boolean hasMoreElements() { + + return (iterator.hasNext()); + + } + + + /** + * Returns the next element of this enumeration if this enumeration + * has at least one more element to provide. + * + * @return the next element of this enumeration + * + * @exception NoSuchElementException if no more elements exist + */ + public Object nextElement() throws NoSuchElementException { + + return (iterator.next()); + + } + + +} diff --git a/java/org/apache/catalina/util/Extension.java b/java/org/apache/catalina/util/Extension.java index 11bd0d687..142bd5b1c 100644 --- a/java/org/apache/catalina/util/Extension.java +++ b/java/org/apache/catalina/util/Extension.java @@ -1,303 +1,303 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.util.StringTokenizer; - - -/** - * Utility class that represents either an available "Optional Package" - * (formerly known as "Standard Extension") as described in the manifest - * of a JAR file, or the requirement for such an optional package. It is - * used to support the requirements of the Servlet Specification, version - * 2.3, related to providing shared extensions to all webapps. - *

        - * In addition, static utility methods are available to scan a manifest - * and return an array of either available or required optional modules - * documented in that manifest. - *

        - * For more information about optional packages, see the document - * Optional Package Versioning in the documentation bundle for your - * Java2 Standard Edition package, in file - * guide/extensions/versioning.html. - * - * @author Craig McClanahan - * @author Justyna Horwat - * @author Greg Murray - * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ - */ - -public final class Extension { - - - // ------------------------------------------------------------- Properties - - - /** - * The name of the optional package being made available, or required. - */ - private String extensionName = null; - - - public String getExtensionName() { - return (this.extensionName); - } - - public void setExtensionName(String extensionName) { - this.extensionName = extensionName; - } - - /** - * The URL from which the most recent version of this optional package - * can be obtained if it is not already installed. - */ - private String implementationURL = null; - - public String getImplementationURL() { - return (this.implementationURL); - } - - public void setImplementationURL(String implementationURL) { - this.implementationURL = implementationURL; - } - - - /** - * The name of the company or organization that produced this - * implementation of this optional package. - */ - private String implementationVendor = null; - - public String getImplementationVendor() { - return (this.implementationVendor); - } - - public void setImplementationVendor(String implementationVendor) { - this.implementationVendor = implementationVendor; - } - - - /** - * The unique identifier of the company that produced the optional - * package contained in this JAR file. - */ - private String implementationVendorId = null; - - public String getImplementationVendorId() { - return (this.implementationVendorId); - } - - public void setImplementationVendorId(String implementationVendorId) { - this.implementationVendorId = implementationVendorId; - } - - - /** - * The version number (dotted decimal notation) for this implementation - * of the optional package. - */ - private String implementationVersion = null; - - public String getImplementationVersion() { - return (this.implementationVersion); - } - - public void setImplementationVersion(String implementationVersion) { - this.implementationVersion = implementationVersion; - } - - - /** - * The name of the company or organization that originated the - * specification to which this optional package conforms. - */ - private String specificationVendor = null; - - public String getSpecificationVendor() { - return (this.specificationVendor); - } - - public void setSpecificationVendor(String specificationVendor) { - this.specificationVendor = specificationVendor; - } - - - /** - * The version number (dotted decimal notation) of the specification - * to which this optional package conforms. - */ - private String specificationVersion = null; - - public String getSpecificationVersion() { - return (this.specificationVersion); - } - - public void setSpecificationVersion(String specificationVersion) { - this.specificationVersion = specificationVersion; - } - - - /** - * fulfilled is true if all the required extension dependencies have been - * satisfied - */ - private boolean fulfilled = false; - - public void setFulfilled(boolean fulfilled) { - this.fulfilled = fulfilled; - } - - public boolean isFulfilled() { - return fulfilled; - } - - // --------------------------------------------------------- Public Methods - - /** - * Return true if the specified Extension - * (which represents an optional package required by this application) - * is satisfied by this Extension (which represents an - * optional package that is already installed. Otherwise, return - * false. - * - * @param required Extension of the required optional package - */ - public boolean isCompatibleWith(Extension required) { - - // Extension Name must match - if (extensionName == null) - return (false); - if (!extensionName.equals(required.getExtensionName())) - return (false); - - // If specified, available specification version must be >= required - if (required.getSpecificationVersion() != null) { - if (!isNewer(specificationVersion, - required.getSpecificationVersion())) - return (false); - } - - // If specified, Implementation Vendor ID must match - if (required.getImplementationVendorId() != null) { - if (implementationVendorId == null) - return (false); - if (!implementationVendorId.equals(required - .getImplementationVendorId())) - return (false); - } - - // If specified, Implementation version must be >= required - if (required.getImplementationVersion() != null) { - if (!isNewer(implementationVersion, - required.getImplementationVersion())) - return (false); - } - - // This available optional package satisfies the requirements - return (true); - - } - - /** - * Return a String representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("Extension["); - sb.append(extensionName); - if (implementationURL != null) { - sb.append(", implementationURL="); - sb.append(implementationURL); - } - if (implementationVendor != null) { - sb.append(", implementationVendor="); - sb.append(implementationVendor); - } - if (implementationVendorId != null) { - sb.append(", implementationVendorId="); - sb.append(implementationVendorId); - } - if (implementationVersion != null) { - sb.append(", implementationVersion="); - sb.append(implementationVersion); - } - if (specificationVendor != null) { - sb.append(", specificationVendor="); - sb.append(specificationVendor); - } - if (specificationVersion != null) { - sb.append(", specificationVersion="); - sb.append(specificationVersion); - } - sb.append("]"); - return (sb.toString()); - - } - - - // -------------------------------------------------------- Private Methods - - - - /** - * Return true if the first version number is greater than - * or equal to the second; otherwise return false. - * - * @param first First version number (dotted decimal) - * @param second Second version number (dotted decimal) - * - * @exception NumberFormatException on a malformed version number - */ - private boolean isNewer(String first, String second) - throws NumberFormatException { - - if ((first == null) || (second == null)) - return (false); - if (first.equals(second)) - return (true); - - StringTokenizer fTok = new StringTokenizer(first, ".", true); - StringTokenizer sTok = new StringTokenizer(second, ".", true); - int fVersion = 0; - int sVersion = 0; - while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) { - if (fTok.hasMoreTokens()) - fVersion = Integer.parseInt(fTok.nextToken()); - else - fVersion = 0; - if (sTok.hasMoreTokens()) - sVersion = Integer.parseInt(sTok.nextToken()); - else - sVersion = 0; - if (fVersion < sVersion) - return (false); - else if (fVersion > sVersion) - return (true); - if (fTok.hasMoreTokens()) // Swallow the periods - fTok.nextToken(); - if (sTok.hasMoreTokens()) - sTok.nextToken(); - } - - return (true); // Exact match - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.util.StringTokenizer; + + +/** + * Utility class that represents either an available "Optional Package" + * (formerly known as "Standard Extension") as described in the manifest + * of a JAR file, or the requirement for such an optional package. It is + * used to support the requirements of the Servlet Specification, version + * 2.3, related to providing shared extensions to all webapps. + *

        + * In addition, static utility methods are available to scan a manifest + * and return an array of either available or required optional modules + * documented in that manifest. + *

        + * For more information about optional packages, see the document + * Optional Package Versioning in the documentation bundle for your + * Java2 Standard Edition package, in file + * guide/extensions/versioning.html. + * + * @author Craig McClanahan + * @author Justyna Horwat + * @author Greg Murray + * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ + */ + +public final class Extension { + + + // ------------------------------------------------------------- Properties + + + /** + * The name of the optional package being made available, or required. + */ + private String extensionName = null; + + + public String getExtensionName() { + return (this.extensionName); + } + + public void setExtensionName(String extensionName) { + this.extensionName = extensionName; + } + + /** + * The URL from which the most recent version of this optional package + * can be obtained if it is not already installed. + */ + private String implementationURL = null; + + public String getImplementationURL() { + return (this.implementationURL); + } + + public void setImplementationURL(String implementationURL) { + this.implementationURL = implementationURL; + } + + + /** + * The name of the company or organization that produced this + * implementation of this optional package. + */ + private String implementationVendor = null; + + public String getImplementationVendor() { + return (this.implementationVendor); + } + + public void setImplementationVendor(String implementationVendor) { + this.implementationVendor = implementationVendor; + } + + + /** + * The unique identifier of the company that produced the optional + * package contained in this JAR file. + */ + private String implementationVendorId = null; + + public String getImplementationVendorId() { + return (this.implementationVendorId); + } + + public void setImplementationVendorId(String implementationVendorId) { + this.implementationVendorId = implementationVendorId; + } + + + /** + * The version number (dotted decimal notation) for this implementation + * of the optional package. + */ + private String implementationVersion = null; + + public String getImplementationVersion() { + return (this.implementationVersion); + } + + public void setImplementationVersion(String implementationVersion) { + this.implementationVersion = implementationVersion; + } + + + /** + * The name of the company or organization that originated the + * specification to which this optional package conforms. + */ + private String specificationVendor = null; + + public String getSpecificationVendor() { + return (this.specificationVendor); + } + + public void setSpecificationVendor(String specificationVendor) { + this.specificationVendor = specificationVendor; + } + + + /** + * The version number (dotted decimal notation) of the specification + * to which this optional package conforms. + */ + private String specificationVersion = null; + + public String getSpecificationVersion() { + return (this.specificationVersion); + } + + public void setSpecificationVersion(String specificationVersion) { + this.specificationVersion = specificationVersion; + } + + + /** + * fulfilled is true if all the required extension dependencies have been + * satisfied + */ + private boolean fulfilled = false; + + public void setFulfilled(boolean fulfilled) { + this.fulfilled = fulfilled; + } + + public boolean isFulfilled() { + return fulfilled; + } + + // --------------------------------------------------------- Public Methods + + /** + * Return true if the specified Extension + * (which represents an optional package required by this application) + * is satisfied by this Extension (which represents an + * optional package that is already installed. Otherwise, return + * false. + * + * @param required Extension of the required optional package + */ + public boolean isCompatibleWith(Extension required) { + + // Extension Name must match + if (extensionName == null) + return (false); + if (!extensionName.equals(required.getExtensionName())) + return (false); + + // If specified, available specification version must be >= required + if (required.getSpecificationVersion() != null) { + if (!isNewer(specificationVersion, + required.getSpecificationVersion())) + return (false); + } + + // If specified, Implementation Vendor ID must match + if (required.getImplementationVendorId() != null) { + if (implementationVendorId == null) + return (false); + if (!implementationVendorId.equals(required + .getImplementationVendorId())) + return (false); + } + + // If specified, Implementation version must be >= required + if (required.getImplementationVersion() != null) { + if (!isNewer(implementationVersion, + required.getImplementationVersion())) + return (false); + } + + // This available optional package satisfies the requirements + return (true); + + } + + /** + * Return a String representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("Extension["); + sb.append(extensionName); + if (implementationURL != null) { + sb.append(", implementationURL="); + sb.append(implementationURL); + } + if (implementationVendor != null) { + sb.append(", implementationVendor="); + sb.append(implementationVendor); + } + if (implementationVendorId != null) { + sb.append(", implementationVendorId="); + sb.append(implementationVendorId); + } + if (implementationVersion != null) { + sb.append(", implementationVersion="); + sb.append(implementationVersion); + } + if (specificationVendor != null) { + sb.append(", specificationVendor="); + sb.append(specificationVendor); + } + if (specificationVersion != null) { + sb.append(", specificationVersion="); + sb.append(specificationVersion); + } + sb.append("]"); + return (sb.toString()); + + } + + + // -------------------------------------------------------- Private Methods + + + + /** + * Return true if the first version number is greater than + * or equal to the second; otherwise return false. + * + * @param first First version number (dotted decimal) + * @param second Second version number (dotted decimal) + * + * @exception NumberFormatException on a malformed version number + */ + private boolean isNewer(String first, String second) + throws NumberFormatException { + + if ((first == null) || (second == null)) + return (false); + if (first.equals(second)) + return (true); + + StringTokenizer fTok = new StringTokenizer(first, ".", true); + StringTokenizer sTok = new StringTokenizer(second, ".", true); + int fVersion = 0; + int sVersion = 0; + while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) { + if (fTok.hasMoreTokens()) + fVersion = Integer.parseInt(fTok.nextToken()); + else + fVersion = 0; + if (sTok.hasMoreTokens()) + sVersion = Integer.parseInt(sTok.nextToken()); + else + sVersion = 0; + if (fVersion < sVersion) + return (false); + else if (fVersion > sVersion) + return (true); + if (fTok.hasMoreTokens()) // Swallow the periods + fTok.nextToken(); + if (sTok.hasMoreTokens()) + sTok.nextToken(); + } + + return (true); // Exact match + + } + + +} diff --git a/java/org/apache/catalina/util/ExtensionValidator.java b/java/org/apache/catalina/util/ExtensionValidator.java index 54d74624a..04c886d20 100644 --- a/java/org/apache/catalina/util/ExtensionValidator.java +++ b/java/org/apache/catalina/util/ExtensionValidator.java @@ -1,423 +1,423 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.NoSuchElementException; -import java.util.StringTokenizer; -import java.util.jar.JarInputStream; -import java.util.jar.Manifest; - -import javax.naming.Binding; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -import org.apache.catalina.core.StandardContext; -import org.apache.naming.resources.Resource; - - -/** - * Ensures that all extension dependies are resolved for a WEB application - * are met. This class builds a master list of extensions available to an - * applicaiton and then validates those extensions. - * - * See http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html for - * a detailed explanation of the extension mechanism in Java. - * - * @author Greg Murray - * @author Justyna Horwat - * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ - * - */ -public final class ExtensionValidator { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(ExtensionValidator.class); - - /** - * The string resources for this package. - */ - private static StringManager sm = - StringManager.getManager("org.apache.catalina.util"); - - private static ArrayList containerAvailableExtensions = null; - private static ArrayList containerManifestResources = new ArrayList(); - - - // ----------------------------------------------------- Static Initializer - - - /** - * This static initializer loads the container level extensions that are - * available to all web applications. This method scans all extension - * directories available via the "java.ext.dirs" System property. - * - * The System Class-Path is also scanned for jar files that may contain - * available extensions. - */ - static { - - // check for container level optional packages - String systemClasspath = System.getProperty("java.class.path"); - - StringTokenizer strTok = new StringTokenizer(systemClasspath, - File.pathSeparator); - - // build a list of jar files in the classpath - while (strTok.hasMoreTokens()) { - String classpathItem = strTok.nextToken(); - if (classpathItem.toLowerCase().endsWith(".jar")) { - File item = new File(classpathItem); - if (item.exists()) { - try { - addSystemResource(item); - } catch (IOException e) { - log.error(sm.getString - ("extensionValidator.failload", item), e); - } - } - } - } - - // add specified folders to the list - addFolderList("java.ext.dirs"); - addFolderList("catalina.ext.dirs"); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Runtime validation of a Web Applicaiton. - * - * This method uses JNDI to look up the resources located under a - * DirContext. It locates Web Application MANIFEST.MF - * file in the /META-INF/ directory of the application and all - * MANIFEST.MF files in each JAR file located in the WEB-INF/lib - * directory and creates an ArrayList of - * ManifestResorce objects. These objects are then passed - * to the validateManifestResources method for validation. - * - * @param dirContext The JNDI root of the Web Application - * @param context The context from which the Logger and path to the - * application - * - * @return true if all required extensions satisfied - */ - public static synchronized boolean validateApplication( - DirContext dirContext, - StandardContext context) - throws IOException { - - String appName = context.getPath(); - ArrayList appManifestResources = new ArrayList(); - // If the application context is null it does not exist and - // therefore is not valid - if (dirContext == null) return false; - // Find the Manifest for the Web Applicaiton - InputStream inputStream = null; - try { - NamingEnumeration wne = dirContext.listBindings("/META-INF/"); - Binding binding = (Binding) wne.nextElement(); - if (binding.getName().toUpperCase().equals("MANIFEST.MF")) { - Resource resource = (Resource)dirContext.lookup - ("/META-INF/" + binding.getName()); - inputStream = resource.streamContent(); - Manifest manifest = new Manifest(inputStream); - inputStream.close(); - inputStream = null; - ManifestResource mre = new ManifestResource - (sm.getString("extensionValidator.web-application-manifest"), - manifest, ManifestResource.WAR); - appManifestResources.add(mre); - } - } catch (NamingException nex) { - // Application does not contain a MANIFEST.MF file - } catch (NoSuchElementException nse) { - // Application does not contain a MANIFEST.MF file - } finally { - if (inputStream != null) { - try { - inputStream.close(); - } catch (Throwable t) { - // Ignore - } - } - } - - // Locate the Manifests for all bundled JARs - NamingEnumeration ne = null; - try { - if (dirContext != null) { - ne = dirContext.listBindings("WEB-INF/lib/"); - } - while ((ne != null) && ne.hasMoreElements()) { - Binding binding = (Binding)ne.nextElement(); - if (!binding.getName().toLowerCase().endsWith(".jar")) { - continue; - } - Resource resource = (Resource)dirContext.lookup - ("/WEB-INF/lib/" + binding.getName()); - Manifest jmanifest = getManifest(resource.streamContent()); - if (jmanifest != null) { - ManifestResource mre = new ManifestResource( - binding.getName(), - jmanifest, - ManifestResource.APPLICATION); - appManifestResources.add(mre); - } - } - } catch (NamingException nex) { - // Jump out of the check for this application because it - // has no resources - } - - return validateManifestResources(appName, appManifestResources); - } - - - /** - * Checks to see if the given system JAR file contains a MANIFEST, and adds - * it to the container's manifest resources. - * - * @param jarFile The system JAR whose manifest to add - */ - public static void addSystemResource(File jarFile) throws IOException { - Manifest manifest = getManifest(new FileInputStream(jarFile)); - if (manifest != null) { - ManifestResource mre - = new ManifestResource(jarFile.getAbsolutePath(), - manifest, - ManifestResource.SYSTEM); - containerManifestResources.add(mre); - } - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Validates a ArrayList of ManifestResource - * objects. This method requires an application name (which is the - * context root of the application at runtime). - * - * false is returned if the extension dependencies - * represented by any given ManifestResource objects - * is not met. - * - * This method should also provide static validation of a Web Applicaiton - * if provided with the necessary parameters. - * - * @param appName The name of the Application that will appear in the - * error messages - * @param resources A list of ManifestResource objects - * to be validated. - * - * @return true if manifest resource file requirements are met - */ - private static boolean validateManifestResources(String appName, - ArrayList resources) { - boolean passes = true; - int failureCount = 0; - ArrayList availableExtensions = null; - - Iterator it = resources.iterator(); - while (it.hasNext()) { - ManifestResource mre = (ManifestResource)it.next(); - ArrayList requiredList = mre.getRequiredExtensions(); - if (requiredList == null) { - continue; - } - - // build the list of available extensions if necessary - if (availableExtensions == null) { - availableExtensions = buildAvailableExtensionsList(resources); - } - - // load the container level resource map if it has not been built - // yet - if (containerAvailableExtensions == null) { - containerAvailableExtensions - = buildAvailableExtensionsList(containerManifestResources); - } - - // iterate through the list of required extensions - Iterator rit = requiredList.iterator(); - while (rit.hasNext()) { - boolean found = false; - Extension requiredExt = (Extension)rit.next(); - // check the applicaion itself for the extension - if (availableExtensions != null) { - Iterator ait = availableExtensions.iterator(); - while (ait.hasNext()) { - Extension targetExt = (Extension) ait.next(); - if (targetExt.isCompatibleWith(requiredExt)) { - requiredExt.setFulfilled(true); - found = true; - break; - } - } - } - // check the container level list for the extension - if (!found && containerAvailableExtensions != null) { - Iterator cit = containerAvailableExtensions.iterator(); - while (cit.hasNext()) { - Extension targetExt = (Extension) cit.next(); - if (targetExt.isCompatibleWith(requiredExt)) { - requiredExt.setFulfilled(true); - found = true; - break; - } - } - } - if (!found) { - // Failure - log.info(sm.getString( - "extensionValidator.extension-not-found-error", - appName, mre.getResourceName(), - requiredExt.getExtensionName())); - passes = false; - failureCount++; - } - } - } - - if (!passes) { - log.info(sm.getString( - "extensionValidator.extension-validation-error", appName, - failureCount + "")); - } - - return passes; - } - - /* - * Build this list of available extensions so that we do not have to - * re-build this list every time we iterate through the list of required - * extensions. All available extensions in all of the - * MainfestResource objects will be added to a - * HashMap which is returned on the first dependency list - * processing pass. - * - * The key is the name + implementation version. - * - * NOTE: A list is built only if there is a dependency that needs - * to be checked (performance optimization). - * - * @param resources A list of ManifestResource objects - * - * @return HashMap Map of available extensions - */ - private static ArrayList buildAvailableExtensionsList(ArrayList resources) { - - ArrayList availableList = null; - - Iterator it = resources.iterator(); - while (it.hasNext()) { - ManifestResource mre = (ManifestResource)it.next(); - ArrayList list = mre.getAvailableExtensions(); - if (list != null) { - Iterator values = list.iterator(); - while (values.hasNext()) { - Extension ext = (Extension) values.next(); - if (availableList == null) { - availableList = new ArrayList(); - availableList.add(ext); - } else { - availableList.add(ext); - } - } - } - } - - return availableList; - } - - /** - * Return the Manifest from a jar file or war file - * - * @param inStream Input stream to a WAR or JAR file - * @return The WAR's or JAR's manifest - */ - private static Manifest getManifest(InputStream inStream) - throws IOException { - - Manifest manifest = null; - JarInputStream jin = null; - - try { - jin = new JarInputStream(inStream); - manifest = jin.getManifest(); - jin.close(); - jin = null; - } finally { - if (jin != null) { - try { - jin.close(); - } catch (Throwable t) { - // Ignore - } - } - } - - return manifest; - } - - - /** - * Add the JARs specified to the extension list. - */ - private static void addFolderList(String property) { - - // get the files in the extensions directory - String extensionsDir = System.getProperty(property); - if (extensionsDir != null) { - StringTokenizer extensionsTok - = new StringTokenizer(extensionsDir, File.pathSeparator); - while (extensionsTok.hasMoreTokens()) { - File targetDir = new File(extensionsTok.nextToken()); - if (!targetDir.exists() || !targetDir.isDirectory()) { - continue; - } - File[] files = targetDir.listFiles(); - for (int i = 0; i < files.length; i++) { - if (files[i].getName().toLowerCase().endsWith(".jar")) { - try { - addSystemResource(files[i]); - } catch (IOException e) { - log.error - (sm.getString - ("extensionValidator.failload", files[i]), e); - } - } - } - } - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.StringTokenizer; +import java.util.jar.JarInputStream; +import java.util.jar.Manifest; + +import javax.naming.Binding; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.apache.catalina.core.StandardContext; +import org.apache.naming.resources.Resource; + + +/** + * Ensures that all extension dependies are resolved for a WEB application + * are met. This class builds a master list of extensions available to an + * applicaiton and then validates those extensions. + * + * See http://java.sun.com/j2se/1.4/docs/guide/extensions/spec.html for + * a detailed explanation of the extension mechanism in Java. + * + * @author Greg Murray + * @author Justyna Horwat + * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ + * + */ +public final class ExtensionValidator { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(ExtensionValidator.class); + + /** + * The string resources for this package. + */ + private static StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + private static ArrayList containerAvailableExtensions = null; + private static ArrayList containerManifestResources = new ArrayList(); + + + // ----------------------------------------------------- Static Initializer + + + /** + * This static initializer loads the container level extensions that are + * available to all web applications. This method scans all extension + * directories available via the "java.ext.dirs" System property. + * + * The System Class-Path is also scanned for jar files that may contain + * available extensions. + */ + static { + + // check for container level optional packages + String systemClasspath = System.getProperty("java.class.path"); + + StringTokenizer strTok = new StringTokenizer(systemClasspath, + File.pathSeparator); + + // build a list of jar files in the classpath + while (strTok.hasMoreTokens()) { + String classpathItem = strTok.nextToken(); + if (classpathItem.toLowerCase().endsWith(".jar")) { + File item = new File(classpathItem); + if (item.exists()) { + try { + addSystemResource(item); + } catch (IOException e) { + log.error(sm.getString + ("extensionValidator.failload", item), e); + } + } + } + } + + // add specified folders to the list + addFolderList("java.ext.dirs"); + addFolderList("catalina.ext.dirs"); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Runtime validation of a Web Applicaiton. + * + * This method uses JNDI to look up the resources located under a + * DirContext. It locates Web Application MANIFEST.MF + * file in the /META-INF/ directory of the application and all + * MANIFEST.MF files in each JAR file located in the WEB-INF/lib + * directory and creates an ArrayList of + * ManifestResorce objects. These objects are then passed + * to the validateManifestResources method for validation. + * + * @param dirContext The JNDI root of the Web Application + * @param context The context from which the Logger and path to the + * application + * + * @return true if all required extensions satisfied + */ + public static synchronized boolean validateApplication( + DirContext dirContext, + StandardContext context) + throws IOException { + + String appName = context.getPath(); + ArrayList appManifestResources = new ArrayList(); + // If the application context is null it does not exist and + // therefore is not valid + if (dirContext == null) return false; + // Find the Manifest for the Web Applicaiton + InputStream inputStream = null; + try { + NamingEnumeration wne = dirContext.listBindings("/META-INF/"); + Binding binding = (Binding) wne.nextElement(); + if (binding.getName().toUpperCase().equals("MANIFEST.MF")) { + Resource resource = (Resource)dirContext.lookup + ("/META-INF/" + binding.getName()); + inputStream = resource.streamContent(); + Manifest manifest = new Manifest(inputStream); + inputStream.close(); + inputStream = null; + ManifestResource mre = new ManifestResource + (sm.getString("extensionValidator.web-application-manifest"), + manifest, ManifestResource.WAR); + appManifestResources.add(mre); + } + } catch (NamingException nex) { + // Application does not contain a MANIFEST.MF file + } catch (NoSuchElementException nse) { + // Application does not contain a MANIFEST.MF file + } finally { + if (inputStream != null) { + try { + inputStream.close(); + } catch (Throwable t) { + // Ignore + } + } + } + + // Locate the Manifests for all bundled JARs + NamingEnumeration ne = null; + try { + if (dirContext != null) { + ne = dirContext.listBindings("WEB-INF/lib/"); + } + while ((ne != null) && ne.hasMoreElements()) { + Binding binding = (Binding)ne.nextElement(); + if (!binding.getName().toLowerCase().endsWith(".jar")) { + continue; + } + Resource resource = (Resource)dirContext.lookup + ("/WEB-INF/lib/" + binding.getName()); + Manifest jmanifest = getManifest(resource.streamContent()); + if (jmanifest != null) { + ManifestResource mre = new ManifestResource( + binding.getName(), + jmanifest, + ManifestResource.APPLICATION); + appManifestResources.add(mre); + } + } + } catch (NamingException nex) { + // Jump out of the check for this application because it + // has no resources + } + + return validateManifestResources(appName, appManifestResources); + } + + + /** + * Checks to see if the given system JAR file contains a MANIFEST, and adds + * it to the container's manifest resources. + * + * @param jarFile The system JAR whose manifest to add + */ + public static void addSystemResource(File jarFile) throws IOException { + Manifest manifest = getManifest(new FileInputStream(jarFile)); + if (manifest != null) { + ManifestResource mre + = new ManifestResource(jarFile.getAbsolutePath(), + manifest, + ManifestResource.SYSTEM); + containerManifestResources.add(mre); + } + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Validates a ArrayList of ManifestResource + * objects. This method requires an application name (which is the + * context root of the application at runtime). + * + * false is returned if the extension dependencies + * represented by any given ManifestResource objects + * is not met. + * + * This method should also provide static validation of a Web Applicaiton + * if provided with the necessary parameters. + * + * @param appName The name of the Application that will appear in the + * error messages + * @param resources A list of ManifestResource objects + * to be validated. + * + * @return true if manifest resource file requirements are met + */ + private static boolean validateManifestResources(String appName, + ArrayList resources) { + boolean passes = true; + int failureCount = 0; + ArrayList availableExtensions = null; + + Iterator it = resources.iterator(); + while (it.hasNext()) { + ManifestResource mre = (ManifestResource)it.next(); + ArrayList requiredList = mre.getRequiredExtensions(); + if (requiredList == null) { + continue; + } + + // build the list of available extensions if necessary + if (availableExtensions == null) { + availableExtensions = buildAvailableExtensionsList(resources); + } + + // load the container level resource map if it has not been built + // yet + if (containerAvailableExtensions == null) { + containerAvailableExtensions + = buildAvailableExtensionsList(containerManifestResources); + } + + // iterate through the list of required extensions + Iterator rit = requiredList.iterator(); + while (rit.hasNext()) { + boolean found = false; + Extension requiredExt = (Extension)rit.next(); + // check the applicaion itself for the extension + if (availableExtensions != null) { + Iterator ait = availableExtensions.iterator(); + while (ait.hasNext()) { + Extension targetExt = (Extension) ait.next(); + if (targetExt.isCompatibleWith(requiredExt)) { + requiredExt.setFulfilled(true); + found = true; + break; + } + } + } + // check the container level list for the extension + if (!found && containerAvailableExtensions != null) { + Iterator cit = containerAvailableExtensions.iterator(); + while (cit.hasNext()) { + Extension targetExt = (Extension) cit.next(); + if (targetExt.isCompatibleWith(requiredExt)) { + requiredExt.setFulfilled(true); + found = true; + break; + } + } + } + if (!found) { + // Failure + log.info(sm.getString( + "extensionValidator.extension-not-found-error", + appName, mre.getResourceName(), + requiredExt.getExtensionName())); + passes = false; + failureCount++; + } + } + } + + if (!passes) { + log.info(sm.getString( + "extensionValidator.extension-validation-error", appName, + failureCount + "")); + } + + return passes; + } + + /* + * Build this list of available extensions so that we do not have to + * re-build this list every time we iterate through the list of required + * extensions. All available extensions in all of the + * MainfestResource objects will be added to a + * HashMap which is returned on the first dependency list + * processing pass. + * + * The key is the name + implementation version. + * + * NOTE: A list is built only if there is a dependency that needs + * to be checked (performance optimization). + * + * @param resources A list of ManifestResource objects + * + * @return HashMap Map of available extensions + */ + private static ArrayList buildAvailableExtensionsList(ArrayList resources) { + + ArrayList availableList = null; + + Iterator it = resources.iterator(); + while (it.hasNext()) { + ManifestResource mre = (ManifestResource)it.next(); + ArrayList list = mre.getAvailableExtensions(); + if (list != null) { + Iterator values = list.iterator(); + while (values.hasNext()) { + Extension ext = (Extension) values.next(); + if (availableList == null) { + availableList = new ArrayList(); + availableList.add(ext); + } else { + availableList.add(ext); + } + } + } + } + + return availableList; + } + + /** + * Return the Manifest from a jar file or war file + * + * @param inStream Input stream to a WAR or JAR file + * @return The WAR's or JAR's manifest + */ + private static Manifest getManifest(InputStream inStream) + throws IOException { + + Manifest manifest = null; + JarInputStream jin = null; + + try { + jin = new JarInputStream(inStream); + manifest = jin.getManifest(); + jin.close(); + jin = null; + } finally { + if (jin != null) { + try { + jin.close(); + } catch (Throwable t) { + // Ignore + } + } + } + + return manifest; + } + + + /** + * Add the JARs specified to the extension list. + */ + private static void addFolderList(String property) { + + // get the files in the extensions directory + String extensionsDir = System.getProperty(property); + if (extensionsDir != null) { + StringTokenizer extensionsTok + = new StringTokenizer(extensionsDir, File.pathSeparator); + while (extensionsTok.hasMoreTokens()) { + File targetDir = new File(extensionsTok.nextToken()); + if (!targetDir.exists() || !targetDir.isDirectory()) { + continue; + } + File[] files = targetDir.listFiles(); + for (int i = 0; i < files.length; i++) { + if (files[i].getName().toLowerCase().endsWith(".jar")) { + try { + addSystemResource(files[i]); + } catch (IOException e) { + log.error + (sm.getString + ("extensionValidator.failload", files[i]), e); + } + } + } + } + } + + } + + +} diff --git a/java/org/apache/catalina/util/FastDateFormat.java b/java/org/apache/catalina/util/FastDateFormat.java index 057eef71f..f2a2c5ce6 100644 --- a/java/org/apache/catalina/util/FastDateFormat.java +++ b/java/org/apache/catalina/util/FastDateFormat.java @@ -1,123 +1,123 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.util.Date; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; - -/** - * Fast date formatter that caches recently formatted date information - * and uses it to avoid too-frequent calls to the underlying - * formatter. Note: breaks fieldPosition param of format(Date, - * StringBuffer, FieldPosition). If you care about the field - * position, call the underlying DateFormat directly. - * - * @author Stan Bailes - * @author Alex Chaffee - **/ -public class FastDateFormat extends DateFormat { - DateFormat df; - long lastSec = -1; - StringBuffer sb = new StringBuffer(); - FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD); - - public FastDateFormat(DateFormat df) { - this.df = df; - } - - public Date parse(String text, ParsePosition pos) { - return df.parse(text, pos); - } - - /** - * Note: breaks functionality of fieldPosition param. Also: - * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS" - * instead if you want a msec field. - **/ - public StringBuffer format(Date date, StringBuffer toAppendTo, - FieldPosition fieldPosition) { - long dt = date.getTime(); - long ds = dt / 1000; - if (ds != lastSec) { - sb.setLength(0); - df.format(date, sb, fp); - lastSec = ds; - } else { - // munge current msec into existing string - int ms = (int)(dt % 1000); - int pos = fp.getEndIndex(); - int begin = fp.getBeginIndex(); - if (pos > 0) { - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - ms /= 10; - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - ms /= 10; - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - } - } - toAppendTo.append(sb.toString()); - return toAppendTo; - } - - public static void main(String[] args) { - String format = "yyyy-MM-dd HH:mm:ss.SSS"; - if (args.length > 0) - format = args[0]; - SimpleDateFormat sdf = new SimpleDateFormat(format); - FastDateFormat fdf = new FastDateFormat(sdf); - Date d = new Date(); - - d.setTime(1); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(20); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(500); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(999); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(1050); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(2543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(12345); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(12340); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - - final int reps = 100000; - { - long start = System.currentTimeMillis(); - for (int i = 0; i < reps; i++) { - d.setTime(System.currentTimeMillis()); - fdf.format(d); - } - long elap = System.currentTimeMillis() - start; - System.out.println("fast: " + elap + " elapsed"); - System.out.println(fdf.format(d)); - } - { - long start = System.currentTimeMillis(); - for (int i = 0; i < reps; i++) { - d.setTime(System.currentTimeMillis()); - sdf.format(d); - } - long elap = System.currentTimeMillis() - start; - System.out.println("slow: " + elap + " elapsed"); - System.out.println(sdf.format(d)); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.util.Date; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +/** + * Fast date formatter that caches recently formatted date information + * and uses it to avoid too-frequent calls to the underlying + * formatter. Note: breaks fieldPosition param of format(Date, + * StringBuffer, FieldPosition). If you care about the field + * position, call the underlying DateFormat directly. + * + * @author Stan Bailes + * @author Alex Chaffee + **/ +public class FastDateFormat extends DateFormat { + DateFormat df; + long lastSec = -1; + StringBuffer sb = new StringBuffer(); + FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD); + + public FastDateFormat(DateFormat df) { + this.df = df; + } + + public Date parse(String text, ParsePosition pos) { + return df.parse(text, pos); + } + + /** + * Note: breaks functionality of fieldPosition param. Also: + * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS" + * instead if you want a msec field. + **/ + public StringBuffer format(Date date, StringBuffer toAppendTo, + FieldPosition fieldPosition) { + long dt = date.getTime(); + long ds = dt / 1000; + if (ds != lastSec) { + sb.setLength(0); + df.format(date, sb, fp); + lastSec = ds; + } else { + // munge current msec into existing string + int ms = (int)(dt % 1000); + int pos = fp.getEndIndex(); + int begin = fp.getBeginIndex(); + if (pos > 0) { + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + ms /= 10; + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + ms /= 10; + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + } + } + toAppendTo.append(sb.toString()); + return toAppendTo; + } + + public static void main(String[] args) { + String format = "yyyy-MM-dd HH:mm:ss.SSS"; + if (args.length > 0) + format = args[0]; + SimpleDateFormat sdf = new SimpleDateFormat(format); + FastDateFormat fdf = new FastDateFormat(sdf); + Date d = new Date(); + + d.setTime(1); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(20); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(500); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(999); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(1050); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(2543); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(12345); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(12340); System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + + final int reps = 100000; + { + long start = System.currentTimeMillis(); + for (int i = 0; i < reps; i++) { + d.setTime(System.currentTimeMillis()); + fdf.format(d); + } + long elap = System.currentTimeMillis() - start; + System.out.println("fast: " + elap + " elapsed"); + System.out.println(fdf.format(d)); + } + { + long start = System.currentTimeMillis(); + for (int i = 0; i < reps; i++) { + d.setTime(System.currentTimeMillis()); + sdf.format(d); + } + long elap = System.currentTimeMillis() - start; + System.out.println("slow: " + elap + " elapsed"); + System.out.println(sdf.format(d)); + } + } +} diff --git a/java/org/apache/catalina/util/HexUtils.java b/java/org/apache/catalina/util/HexUtils.java index d93280d00..a3d920f5e 100644 --- a/java/org/apache/catalina/util/HexUtils.java +++ b/java/org/apache/catalina/util/HexUtils.java @@ -1,176 +1,176 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - -import java.io.ByteArrayOutputStream; - -/** - * Library of utility methods useful in dealing with converting byte arrays - * to and from strings of hexadecimal digits. - * - * @author Craig R. McClanahan - */ - -public final class HexUtils { - // Code from Ajp11, from Apache's JServ - - // Table for HEX to DEC byte translation - public static final int[] DEC = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager("org.apache.catalina.util"); - - - /** - * Convert a String of hexadecimal digits into the corresponding - * byte array by encoding each two hexadecimal digits as a byte. - * - * @param digits Hexadecimal digits representation - * - * @exception IllegalArgumentException if an invalid hexadecimal digit - * is found, or the input string contains an odd number of hexadecimal - * digits - */ - public static byte[] convert(String digits) { - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - for (int i = 0; i < digits.length(); i += 2) { - char c1 = digits.charAt(i); - if ((i+1) >= digits.length()) - throw new IllegalArgumentException - (sm.getString("hexUtil.odd")); - char c2 = digits.charAt(i + 1); - byte b = 0; - if ((c1 >= '0') && (c1 <= '9')) - b += ((c1 - '0') * 16); - else if ((c1 >= 'a') && (c1 <= 'f')) - b += ((c1 - 'a' + 10) * 16); - else if ((c1 >= 'A') && (c1 <= 'F')) - b += ((c1 - 'A' + 10) * 16); - else - throw new IllegalArgumentException - (sm.getString("hexUtil.bad")); - if ((c2 >= '0') && (c2 <= '9')) - b += (c2 - '0'); - else if ((c2 >= 'a') && (c2 <= 'f')) - b += (c2 - 'a' + 10); - else if ((c2 >= 'A') && (c2 <= 'F')) - b += (c2 - 'A' + 10); - else - throw new IllegalArgumentException - (sm.getString("hexUtil.bad")); - baos.write(b); - } - return (baos.toByteArray()); - - } - - - /** - * Convert a byte array into a printable format containing a - * String of hexadecimal digit characters (two per byte). - * - * @param bytes Byte array representation - */ - public static String convert(byte bytes[]) { - - StringBuffer sb = new StringBuffer(bytes.length * 2); - for (int i = 0; i < bytes.length; i++) { - sb.append(convertDigit((int) (bytes[i] >> 4))); - sb.append(convertDigit((int) (bytes[i] & 0x0f))); - } - return (sb.toString()); - - } - - /** - * Convert 4 hex digits to an int, and return the number of converted - * bytes. - * - * @param hex Byte array containing exactly four hexadecimal digits - * - * @exception IllegalArgumentException if an invalid hexadecimal digit - * is included - */ - public static int convert2Int( byte[] hex ) { - // Code from Ajp11, from Apache's JServ - - // assert b.length==4 - // assert valid data - int len; - if(hex.length < 4 ) return 0; - if( DEC[hex[0]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len = DEC[hex[0]]; - len = len << 4; - if( DEC[hex[1]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[1]]; - len = len << 4; - if( DEC[hex[2]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[2]]; - len = len << 4; - if( DEC[hex[3]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[3]]; - return len; - } - - - - /** - * [Private] Convert the specified value (0 .. 15) to the corresponding - * hexadecimal digit. - * - * @param value Value to be converted - */ - private static char convertDigit(int value) { - - value &= 0x0f; - if (value >= 10) - return ((char) (value - 10 + 'a')); - else - return ((char) (value + '0')); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + +import java.io.ByteArrayOutputStream; + +/** + * Library of utility methods useful in dealing with converting byte arrays + * to and from strings of hexadecimal digits. + * + * @author Craig R. McClanahan + */ + +public final class HexUtils { + // Code from Ajp11, from Apache's JServ + + // Table for HEX to DEC byte translation + public static final int[] DEC = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + + /** + * Convert a String of hexadecimal digits into the corresponding + * byte array by encoding each two hexadecimal digits as a byte. + * + * @param digits Hexadecimal digits representation + * + * @exception IllegalArgumentException if an invalid hexadecimal digit + * is found, or the input string contains an odd number of hexadecimal + * digits + */ + public static byte[] convert(String digits) { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < digits.length(); i += 2) { + char c1 = digits.charAt(i); + if ((i+1) >= digits.length()) + throw new IllegalArgumentException + (sm.getString("hexUtil.odd")); + char c2 = digits.charAt(i + 1); + byte b = 0; + if ((c1 >= '0') && (c1 <= '9')) + b += ((c1 - '0') * 16); + else if ((c1 >= 'a') && (c1 <= 'f')) + b += ((c1 - 'a' + 10) * 16); + else if ((c1 >= 'A') && (c1 <= 'F')) + b += ((c1 - 'A' + 10) * 16); + else + throw new IllegalArgumentException + (sm.getString("hexUtil.bad")); + if ((c2 >= '0') && (c2 <= '9')) + b += (c2 - '0'); + else if ((c2 >= 'a') && (c2 <= 'f')) + b += (c2 - 'a' + 10); + else if ((c2 >= 'A') && (c2 <= 'F')) + b += (c2 - 'A' + 10); + else + throw new IllegalArgumentException + (sm.getString("hexUtil.bad")); + baos.write(b); + } + return (baos.toByteArray()); + + } + + + /** + * Convert a byte array into a printable format containing a + * String of hexadecimal digit characters (two per byte). + * + * @param bytes Byte array representation + */ + public static String convert(byte bytes[]) { + + StringBuffer sb = new StringBuffer(bytes.length * 2); + for (int i = 0; i < bytes.length; i++) { + sb.append(convertDigit((int) (bytes[i] >> 4))); + sb.append(convertDigit((int) (bytes[i] & 0x0f))); + } + return (sb.toString()); + + } + + /** + * Convert 4 hex digits to an int, and return the number of converted + * bytes. + * + * @param hex Byte array containing exactly four hexadecimal digits + * + * @exception IllegalArgumentException if an invalid hexadecimal digit + * is included + */ + public static int convert2Int( byte[] hex ) { + // Code from Ajp11, from Apache's JServ + + // assert b.length==4 + // assert valid data + int len; + if(hex.length < 4 ) return 0; + if( DEC[hex[0]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len = DEC[hex[0]]; + len = len << 4; + if( DEC[hex[1]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[1]]; + len = len << 4; + if( DEC[hex[2]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[2]]; + len = len << 4; + if( DEC[hex[3]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[3]]; + return len; + } + + + + /** + * [Private] Convert the specified value (0 .. 15) to the corresponding + * hexadecimal digit. + * + * @param value Value to be converted + */ + private static char convertDigit(int value) { + + value &= 0x0f; + if (value >= 10) + return ((char) (value - 10 + 'a')); + else + return ((char) (value + '0')); + + } + + +} diff --git a/java/org/apache/catalina/util/IOTools.java b/java/org/apache/catalina/util/IOTools.java index d9e15f87e..5d303f691 100644 --- a/java/org/apache/catalina/util/IOTools.java +++ b/java/org/apache/catalina/util/IOTools.java @@ -1,86 +1,86 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.util; - -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.Reader; -import java.io.Writer; - - -/** - * Contains commonly needed I/O-related methods - * - * @author Dan Sandberg - */ -public class IOTools { - protected final static int DEFAULT_BUFFER_SIZE=4*1024; //4k - - //Ensure non-instantiability - private IOTools() { - } - - /** - * Read input from reader and write it to writer until there is no more - * input from reader. - * - * @param reader the reader to read from. - * @param writer the writer to write to. - * @param buf the char array to use as a bufferx - */ - public static void flow( Reader reader, Writer writer, char[] buf ) - throws IOException { - int numRead; - while ( (numRead = reader.read(buf) ) >= 0) { - writer.write(buf, 0, numRead); - } - } - - /** - * @see #flow( Reader, Writer, char[] ) - */ - public static void flow( Reader reader, Writer writer ) - throws IOException { - char[] buf = new char[DEFAULT_BUFFER_SIZE]; - flow( reader, writer, buf ); - } - - /** - * Read input from input stream and write it to output stream - * until there is no more input from input stream. - * - * @param is input stream the input stream to read from. - * @param os output stream the output stream to write to. - * @param buf the byte array to use as a buffer - */ - public static void flow( InputStream is, OutputStream os, byte[] buf ) - throws IOException { - int numRead; - while ( (numRead = is.read(buf) ) >= 0) { - os.write(buf, 0, numRead); - } - } - - /** - * @see #flow( java.io.InputStream, java.io.OutputStream, byte[] ) - */ - public static void flow( InputStream is, OutputStream os ) - throws IOException { - byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; - flow( is, os, buf ); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.util; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.Reader; +import java.io.Writer; + + +/** + * Contains commonly needed I/O-related methods + * + * @author Dan Sandberg + */ +public class IOTools { + protected final static int DEFAULT_BUFFER_SIZE=4*1024; //4k + + //Ensure non-instantiability + private IOTools() { + } + + /** + * Read input from reader and write it to writer until there is no more + * input from reader. + * + * @param reader the reader to read from. + * @param writer the writer to write to. + * @param buf the char array to use as a bufferx + */ + public static void flow( Reader reader, Writer writer, char[] buf ) + throws IOException { + int numRead; + while ( (numRead = reader.read(buf) ) >= 0) { + writer.write(buf, 0, numRead); + } + } + + /** + * @see #flow( Reader, Writer, char[] ) + */ + public static void flow( Reader reader, Writer writer ) + throws IOException { + char[] buf = new char[DEFAULT_BUFFER_SIZE]; + flow( reader, writer, buf ); + } + + /** + * Read input from input stream and write it to output stream + * until there is no more input from input stream. + * + * @param is input stream the input stream to read from. + * @param os output stream the output stream to write to. + * @param buf the byte array to use as a buffer + */ + public static void flow( InputStream is, OutputStream os, byte[] buf ) + throws IOException { + int numRead; + while ( (numRead = is.read(buf) ) >= 0) { + os.write(buf, 0, numRead); + } + } + + /** + * @see #flow( java.io.InputStream, java.io.OutputStream, byte[] ) + */ + public static void flow( InputStream is, OutputStream os ) + throws IOException { + byte[] buf = new byte[DEFAULT_BUFFER_SIZE]; + flow( is, os, buf ); + } +} diff --git a/java/org/apache/catalina/util/InstanceSupport.java b/java/org/apache/catalina/util/InstanceSupport.java index f1734af3b..b6a11ab0c 100644 --- a/java/org/apache/catalina/util/InstanceSupport.java +++ b/java/org/apache/catalina/util/InstanceSupport.java @@ -1,361 +1,361 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import javax.servlet.Filter; -import javax.servlet.Servlet; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import org.apache.catalina.InstanceEvent; -import org.apache.catalina.InstanceListener; -import org.apache.catalina.Wrapper; - - -/** - * Support class to assist in firing InstanceEvent notifications to - * registered InstanceListeners. - * - * @author Craig R. McClanahan - * @version $Id: InstanceSupport.java 303133 2004-08-29 16:46:15Z yoavs $ - */ - -public final class InstanceSupport { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new InstanceSupport object associated with the specified - * Instance component. - * - * @param wrapper The component that will be the source - * of events that we fire - */ - public InstanceSupport(Wrapper wrapper) { - - super(); - this.wrapper = wrapper; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of registered InstanceListeners for event notifications. - */ - private InstanceListener listeners[] = new InstanceListener[0]; - - - /** - * The source component for instance events that we will fire. - */ - private Wrapper wrapper = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Wrapper with which we are associated. - */ - public Wrapper getWrapper() { - - return (this.wrapper); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addInstanceListener(InstanceListener listener) { - - synchronized (listeners) { - InstanceListener results[] = - new InstanceListener[listeners.length + 1]; - for (int i = 0; i < listeners.length; i++) - results[i] = listeners[i]; - results[listeners.length] = listener; - listeners = results; - } - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param filter The relevant Filter for this event - */ - public void fireInstanceEvent(String type, Filter filter) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, filter, type); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param filter The relevant Filter for this event - * @param exception Exception that occurred - */ - public void fireInstanceEvent(String type, Filter filter, - Throwable exception) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, filter, type, - exception); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param filter The relevant Filter for this event - * @param request The servlet request we are processing - * @param response The servlet response we are processing - */ - public void fireInstanceEvent(String type, Filter filter, - ServletRequest request, - ServletResponse response) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, filter, type, - request, response); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param filter The relevant Filter for this event - * @param request The servlet request we are processing - * @param response The servlet response we are processing - * @param exception Exception that occurred - */ - public void fireInstanceEvent(String type, Filter filter, - ServletRequest request, - ServletResponse response, - Throwable exception) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, filter, type, - request, response, exception); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param servlet The relevant Servlet for this event - */ - public void fireInstanceEvent(String type, Servlet servlet) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, servlet, type); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param servlet The relevant Servlet for this event - * @param exception Exception that occurred - */ - public void fireInstanceEvent(String type, Servlet servlet, - Throwable exception) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, servlet, type, - exception); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param servlet The relevant Servlet for this event - * @param request The servlet request we are processing - * @param response The servlet response we are processing - */ - public void fireInstanceEvent(String type, Servlet servlet, - ServletRequest request, - ServletResponse response) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, servlet, type, - request, response); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param servlet The relevant Servlet for this event - * @param request The servlet request we are processing - * @param response The servlet response we are processing - * @param exception Exception that occurred - */ - public void fireInstanceEvent(String type, Servlet servlet, - ServletRequest request, - ServletResponse response, - Throwable exception) { - - if (listeners.length == 0) - return; - - InstanceEvent event = new InstanceEvent(wrapper, servlet, type, - request, response, exception); - InstanceListener interested[] = null; - synchronized (listeners) { - interested = (InstanceListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].instanceEvent(event); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeInstanceListener(InstanceListener listener) { - - synchronized (listeners) { - int n = -1; - for (int i = 0; i < listeners.length; i++) { - if (listeners[i] == listener) { - n = i; - break; - } - } - if (n < 0) - return; - InstanceListener results[] = - new InstanceListener[listeners.length - 1]; - int j = 0; - for (int i = 0; i < listeners.length; i++) { - if (i != n) - results[j++] = listeners[i]; - } - listeners = results; - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import javax.servlet.Filter; +import javax.servlet.Servlet; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import org.apache.catalina.InstanceEvent; +import org.apache.catalina.InstanceListener; +import org.apache.catalina.Wrapper; + + +/** + * Support class to assist in firing InstanceEvent notifications to + * registered InstanceListeners. + * + * @author Craig R. McClanahan + * @version $Id: InstanceSupport.java 303133 2004-08-29 16:46:15Z yoavs $ + */ + +public final class InstanceSupport { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new InstanceSupport object associated with the specified + * Instance component. + * + * @param wrapper The component that will be the source + * of events that we fire + */ + public InstanceSupport(Wrapper wrapper) { + + super(); + this.wrapper = wrapper; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of registered InstanceListeners for event notifications. + */ + private InstanceListener listeners[] = new InstanceListener[0]; + + + /** + * The source component for instance events that we will fire. + */ + private Wrapper wrapper = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Wrapper with which we are associated. + */ + public Wrapper getWrapper() { + + return (this.wrapper); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addInstanceListener(InstanceListener listener) { + + synchronized (listeners) { + InstanceListener results[] = + new InstanceListener[listeners.length + 1]; + for (int i = 0; i < listeners.length; i++) + results[i] = listeners[i]; + results[listeners.length] = listener; + listeners = results; + } + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param filter The relevant Filter for this event + */ + public void fireInstanceEvent(String type, Filter filter) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, filter, type); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param filter The relevant Filter for this event + * @param exception Exception that occurred + */ + public void fireInstanceEvent(String type, Filter filter, + Throwable exception) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, filter, type, + exception); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param filter The relevant Filter for this event + * @param request The servlet request we are processing + * @param response The servlet response we are processing + */ + public void fireInstanceEvent(String type, Filter filter, + ServletRequest request, + ServletResponse response) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, filter, type, + request, response); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param filter The relevant Filter for this event + * @param request The servlet request we are processing + * @param response The servlet response we are processing + * @param exception Exception that occurred + */ + public void fireInstanceEvent(String type, Filter filter, + ServletRequest request, + ServletResponse response, + Throwable exception) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, filter, type, + request, response, exception); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param servlet The relevant Servlet for this event + */ + public void fireInstanceEvent(String type, Servlet servlet) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, servlet, type); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param servlet The relevant Servlet for this event + * @param exception Exception that occurred + */ + public void fireInstanceEvent(String type, Servlet servlet, + Throwable exception) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, servlet, type, + exception); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param servlet The relevant Servlet for this event + * @param request The servlet request we are processing + * @param response The servlet response we are processing + */ + public void fireInstanceEvent(String type, Servlet servlet, + ServletRequest request, + ServletResponse response) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, servlet, type, + request, response); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param servlet The relevant Servlet for this event + * @param request The servlet request we are processing + * @param response The servlet response we are processing + * @param exception Exception that occurred + */ + public void fireInstanceEvent(String type, Servlet servlet, + ServletRequest request, + ServletResponse response, + Throwable exception) { + + if (listeners.length == 0) + return; + + InstanceEvent event = new InstanceEvent(wrapper, servlet, type, + request, response, exception); + InstanceListener interested[] = null; + synchronized (listeners) { + interested = (InstanceListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].instanceEvent(event); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeInstanceListener(InstanceListener listener) { + + synchronized (listeners) { + int n = -1; + for (int i = 0; i < listeners.length; i++) { + if (listeners[i] == listener) { + n = i; + break; + } + } + if (n < 0) + return; + InstanceListener results[] = + new InstanceListener[listeners.length - 1]; + int j = 0; + for (int i = 0; i < listeners.length; i++) { + if (i != n) + results[j++] = listeners[i]; + } + listeners = results; + } + + } + + +} diff --git a/java/org/apache/catalina/util/LifecycleSupport.java b/java/org/apache/catalina/util/LifecycleSupport.java index 1dc5a425f..f8a65f07a 100644 --- a/java/org/apache/catalina/util/LifecycleSupport.java +++ b/java/org/apache/catalina/util/LifecycleSupport.java @@ -1,154 +1,154 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; - - -/** - * Support class to assist in firing LifecycleEvent notifications to - * registered LifecycleListeners. - * - * @author Craig R. McClanahan - * @version $Id: LifecycleSupport.java 302726 2004-02-27 14:59:07Z yoavs $ - */ - -public final class LifecycleSupport { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new LifecycleSupport object associated with the specified - * Lifecycle component. - * - * @param lifecycle The Lifecycle component that will be the source - * of events that we fire - */ - public LifecycleSupport(Lifecycle lifecycle) { - - super(); - this.lifecycle = lifecycle; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The source component for lifecycle events that we will fire. - */ - private Lifecycle lifecycle = null; - - - /** - * The set of registered LifecycleListeners for event notifications. - */ - private LifecycleListener listeners[] = new LifecycleListener[0]; - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - synchronized (listeners) { - LifecycleListener results[] = - new LifecycleListener[listeners.length + 1]; - for (int i = 0; i < listeners.length; i++) - results[i] = listeners[i]; - results[listeners.length] = listener; - listeners = results; - } - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return listeners; - - } - - - /** - * Notify all lifecycle event listeners that a particular event has - * occurred for this Container. The default implementation performs - * this notification synchronously using the calling thread. - * - * @param type Event type - * @param data Event data - */ - public void fireLifecycleEvent(String type, Object data) { - - LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); - LifecycleListener interested[] = null; - synchronized (listeners) { - interested = (LifecycleListener[]) listeners.clone(); - } - for (int i = 0; i < interested.length; i++) - interested[i].lifecycleEvent(event); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to remove - */ - public void removeLifecycleListener(LifecycleListener listener) { - - synchronized (listeners) { - int n = -1; - for (int i = 0; i < listeners.length; i++) { - if (listeners[i] == listener) { - n = i; - break; - } - } - if (n < 0) - return; - LifecycleListener results[] = - new LifecycleListener[listeners.length - 1]; - int j = 0; - for (int i = 0; i < listeners.length; i++) { - if (i != n) - results[j++] = listeners[i]; - } - listeners = results; - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; + + +/** + * Support class to assist in firing LifecycleEvent notifications to + * registered LifecycleListeners. + * + * @author Craig R. McClanahan + * @version $Id: LifecycleSupport.java 302726 2004-02-27 14:59:07Z yoavs $ + */ + +public final class LifecycleSupport { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new LifecycleSupport object associated with the specified + * Lifecycle component. + * + * @param lifecycle The Lifecycle component that will be the source + * of events that we fire + */ + public LifecycleSupport(Lifecycle lifecycle) { + + super(); + this.lifecycle = lifecycle; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The source component for lifecycle events that we will fire. + */ + private Lifecycle lifecycle = null; + + + /** + * The set of registered LifecycleListeners for event notifications. + */ + private LifecycleListener listeners[] = new LifecycleListener[0]; + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + synchronized (listeners) { + LifecycleListener results[] = + new LifecycleListener[listeners.length + 1]; + for (int i = 0; i < listeners.length; i++) + results[i] = listeners[i]; + results[listeners.length] = listener; + listeners = results; + } + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return listeners; + + } + + + /** + * Notify all lifecycle event listeners that a particular event has + * occurred for this Container. The default implementation performs + * this notification synchronously using the calling thread. + * + * @param type Event type + * @param data Event data + */ + public void fireLifecycleEvent(String type, Object data) { + + LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); + LifecycleListener interested[] = null; + synchronized (listeners) { + interested = (LifecycleListener[]) listeners.clone(); + } + for (int i = 0; i < interested.length; i++) + interested[i].lifecycleEvent(event); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to remove + */ + public void removeLifecycleListener(LifecycleListener listener) { + + synchronized (listeners) { + int n = -1; + for (int i = 0; i < listeners.length; i++) { + if (listeners[i] == listener) { + n = i; + break; + } + } + if (n < 0) + return; + LifecycleListener results[] = + new LifecycleListener[listeners.length - 1]; + int j = 0; + for (int i = 0; i < listeners.length; i++) { + if (i != n) + results[j++] = listeners[i]; + } + listeners = results; + } + + } + + +} diff --git a/java/org/apache/catalina/util/LocalStrings.properties b/java/org/apache/catalina/util/LocalStrings.properties index 40806a90e..278cf714e 100644 --- a/java/org/apache/catalina/util/LocalStrings.properties +++ b/java/org/apache/catalina/util/LocalStrings.properties @@ -1,11 +1,11 @@ -parameterMap.locked=No modifications are allowed to a locked ParameterMap -resourceSet.locked=No modifications are allowed to a locked ResourceSet -hexUtil.bad=Bad hexadecimal digit -hexUtil.odd=Odd number of hexadecimal digits -#Default Messages Utilized by the ExtensionValidator -extensionValidator.web-application-manifest=Web Application Manifest -extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension "{2}" not found. -extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find {1} required extension(s). -extensionValidator.failload=Failure loading extension {0} -SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block. - +parameterMap.locked=No modifications are allowed to a locked ParameterMap +resourceSet.locked=No modifications are allowed to a locked ResourceSet +hexUtil.bad=Bad hexadecimal digit +hexUtil.odd=Odd number of hexadecimal digits +#Default Messages Utilized by the ExtensionValidator +extensionValidator.web-application-manifest=Web Application Manifest +extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension "{2}" not found. +extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failure to find {1} required extension(s). +extensionValidator.failload=Failure loading extension {0} +SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block. + diff --git a/java/org/apache/catalina/util/LocalStrings_es.properties b/java/org/apache/catalina/util/LocalStrings_es.properties index a16f07a9e..5b1643b5d 100644 --- a/java/org/apache/catalina/util/LocalStrings_es.properties +++ b/java/org/apache/catalina/util/LocalStrings_es.properties @@ -1,10 +1,10 @@ -parameterMap.locked=No se permiten modificaciones en un ParameterMap bloqueado -resourceSet.locked=No se permiten modificaciones en un ResourceSet bloqueado -hexUtil.bad=Dígito hexadecimal incorrecto -hexUtil.odd=Número de dígitos hexadecimales impar -#Default Messages Utilized by the ExtensionValidator -extensionValidator.web-application-manifest=Manifiesto de Aplicación Web -extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: La extensión no encuentra el "{2}" requerido. -extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Imposible de hallar la(s) extension(es) {1} requerida(s). -SecurityUtil.doAsPrivilege=Una excepción se ha producido durante la ejecución del bloque PrivilegedExceptionAction. - +parameterMap.locked=No se permiten modificaciones en un ParameterMap bloqueado +resourceSet.locked=No se permiten modificaciones en un ResourceSet bloqueado +hexUtil.bad=Dígito hexadecimal incorrecto +hexUtil.odd=Número de dígitos hexadecimales impar +#Default Messages Utilized by the ExtensionValidator +extensionValidator.web-application-manifest=Manifiesto de Aplicación Web +extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: La extensión no encuentra el "{2}" requerido. +extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Imposible de hallar la(s) extension(es) {1} requerida(s). +SecurityUtil.doAsPrivilege=Una excepción se ha producido durante la ejecución del bloque PrivilegedExceptionAction. + diff --git a/java/org/apache/catalina/util/LocalStrings_fr.properties b/java/org/apache/catalina/util/LocalStrings_fr.properties index 8cc3cff46..4c662486f 100644 --- a/java/org/apache/catalina/util/LocalStrings_fr.properties +++ b/java/org/apache/catalina/util/LocalStrings_fr.properties @@ -1,10 +1,10 @@ -parameterMap.locked=Aucune modification n''est authorisée sur un ParameterMap vérrouillé -resourceSet.locked=Aucune modification n''est authorisée sur un ResourceSet vérrouillé -hexUtil.bad=Mauvais digit hexadecimal -hexUtil.odd=Nombre impair de digits hexadecimaux -#Default Messages Utilized by the ExtensionValidator -extensionValidator.web-application-manifest=Web Application Manifest -extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise "{2}" est introuvable. -extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver {1} extension(s) requise(s). -SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''execution du bloc PrivilegedExceptionAction. - +parameterMap.locked=Aucune modification n''est authorisée sur un ParameterMap vérrouillé +resourceSet.locked=Aucune modification n''est authorisée sur un ResourceSet vérrouillé +hexUtil.bad=Mauvais digit hexadecimal +hexUtil.odd=Nombre impair de digits hexadecimaux +#Default Messages Utilized by the ExtensionValidator +extensionValidator.web-application-manifest=Web Application Manifest +extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise "{2}" est introuvable. +extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver {1} extension(s) requise(s). +SecurityUtil.doAsPrivilege=Une exception s''est produite lors de l''execution du bloc PrivilegedExceptionAction. + diff --git a/java/org/apache/catalina/util/LocalStrings_ja.properties b/java/org/apache/catalina/util/LocalStrings_ja.properties index 2e277106f..8aeeb008c 100644 --- a/java/org/apache/catalina/util/LocalStrings_ja.properties +++ b/java/org/apache/catalina/util/LocalStrings_ja.properties @@ -1,11 +1,11 @@ -parameterMap.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fParameterMap\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 -resourceSet.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fResourceSet\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 -hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059 -hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059 -#Default Messages Utilized by the ExtensionValidator -extensionValidator.web-application-manifest=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cb\u30d5\u30a7\u30b9\u30c8 -extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{2}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 -extensionValidator.extension-validation-error=ExtensionValidator[{0}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{1}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 -extensionValidator.failload=\u62e1\u5f35 {0} \u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f -SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 - +parameterMap.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fParameterMap\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 +resourceSet.locked=\u30ed\u30c3\u30af\u3055\u308c\u305fResourceSet\u306f\u5909\u66f4\u304c\u8a31\u3055\u308c\u307e\u305b\u3093 +hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059 +hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059 +#Default Messages Utilized by the ExtensionValidator +extensionValidator.web-application-manifest=Web\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u30de\u30cb\u30d5\u30a7\u30b9\u30c8 +extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{2}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 +extensionValidator.extension-validation-error=ExtensionValidator[{0}]: \u5fc5\u8981\u306a\u62e1\u5f35 "{1}" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 +extensionValidator.failload=\u62e1\u5f35 {0} \u306e\u30ed\u30fc\u30c9\u306b\u5931\u6557\u3057\u307e\u3057\u305f +SecurityUtil.doAsPrivilege=PrivilegedExceptionAction\u30d6\u30ed\u30c3\u30af\u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002 + diff --git a/java/org/apache/catalina/util/MD5Encoder.java b/java/org/apache/catalina/util/MD5Encoder.java index d5e4d93c8..f33b910dc 100644 --- a/java/org/apache/catalina/util/MD5Encoder.java +++ b/java/org/apache/catalina/util/MD5Encoder.java @@ -1,72 +1,72 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -/** - * Encode an MD5 digest into a String. - *

        - * The 128 bit MD5 hash is converted into a 32 character long String. - * Each character of the String is the hexadecimal representation of 4 bits - * of the digest. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class MD5Encoder { - - - // ----------------------------------------------------- Instance Variables - - - private static final char[] hexadecimal = - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'a', 'b', 'c', 'd', 'e', 'f'}; - - - // --------------------------------------------------------- Public Methods - - - /** - * Encodes the 128 bit (16 bytes) MD5 into a 32 character String. - * - * @param binaryData Array containing the digest - * @return Encoded MD5, or null if encoding failed - */ - public String encode( byte[] binaryData ) { - - if (binaryData.length != 16) - return null; - - char[] buffer = new char[32]; - - for (int i=0; i<16; i++) { - int low = (int) (binaryData[i] & 0x0f); - int high = (int) ((binaryData[i] & 0xf0) >> 4); - buffer[i*2] = hexadecimal[high]; - buffer[i*2 + 1] = hexadecimal[low]; - } - - return new String(buffer); - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +/** + * Encode an MD5 digest into a String. + *

        + * The 128 bit MD5 hash is converted into a 32 character long String. + * Each character of the String is the hexadecimal representation of 4 bits + * of the digest. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class MD5Encoder { + + + // ----------------------------------------------------- Instance Variables + + + private static final char[] hexadecimal = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + + + // --------------------------------------------------------- Public Methods + + + /** + * Encodes the 128 bit (16 bytes) MD5 into a 32 character String. + * + * @param binaryData Array containing the digest + * @return Encoded MD5, or null if encoding failed + */ + public String encode( byte[] binaryData ) { + + if (binaryData.length != 16) + return null; + + char[] buffer = new char[32]; + + for (int i=0; i<16; i++) { + int low = (int) (binaryData[i] & 0x0f); + int high = (int) ((binaryData[i] & 0xf0) >> 4); + buffer[i*2] = hexadecimal[high]; + buffer[i*2 + 1] = hexadecimal[low]; + } + + return new String(buffer); + + } + + +} + diff --git a/java/org/apache/catalina/util/MIME2Java.java b/java/org/apache/catalina/util/MIME2Java.java index da33443ff..e9bc12283 100644 --- a/java/org/apache/catalina/util/MIME2Java.java +++ b/java/org/apache/catalina/util/MIME2Java.java @@ -1,602 +1,602 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.util.*; - -/** - * MIME2Java is a convenience class which handles conversions between MIME charset names - * and Java encoding names. - *

        The supported XML encodings are the intersection of XML-supported code sets and those - * supported in JDK 1.1. - *

        MIME charset names are used on xmlEncoding parameters to methods such - * as TXDocument#setEncoding and DTD#setEncoding. - *

        Java encoding names are used on encoding parameters to - * methods such as TXDocument#printWithFormat and DTD#printExternal. - *

        - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
        - *

        Common Name - *

        - *

        Use this name in XML files - *

        - *

        Name Type - *

        - *

        Xerces converts to this Java Encoder Name - *

        8 bit Unicode - *

        UTF-8 - *

        - *

        IANA - *

        - *

        UTF8 - *

        ISO Latin 1 - *

        ISO-8859-1 - *

        - *

        MIME - *

        - *

        ISO-8859-1 - *

        ISO Latin 2 - *

        ISO-8859-2 - *

        - *

        MIME - *

        - *

        ISO-8859-2 - *

        ISO Latin 3 - *

        ISO-8859-3 - *

        - *

        MIME - *

        - *

        ISO-8859-3 - *

        ISO Latin 4 - *

        ISO-8859-4 - *

        - *

        MIME - *

        - *

        ISO-8859-4 - *

        ISO Latin Cyrillic - *

        ISO-8859-5 - *

        - *

        MIME - *

        - *

        ISO-8859-5 - *

        ISO Latin Arabic - *

        ISO-8859-6 - *

        - *

        MIME - *

        - *

        ISO-8859-6 - *

        ISO Latin Greek - *

        ISO-8859-7 - *

        - *

        MIME - *

        - *

        ISO-8859-7 - *

        ISO Latin Hebrew - *

        ISO-8859-8 - *

        - *

        MIME - *

        - *

        ISO-8859-8 - *

        ISO Latin 5 - *

        ISO-8859-9 - *

        - *

        MIME - *

        - *

        ISO-8859-9 - *

        EBCDIC: US - *

        ebcdic-cp-us - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Canada - *

        ebcdic-cp-ca - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Netherlands - *

        ebcdic-cp-nl - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Denmark - *

        ebcdic-cp-dk - *

        - *

        IANA - *

        - *

        cp277 - *

        EBCDIC: Norway - *

        ebcdic-cp-no - *

        - *

        IANA - *

        - *

        cp277 - *

        EBCDIC: Finland - *

        ebcdic-cp-fi - *

        - *

        IANA - *

        - *

        cp278 - *

        EBCDIC: Sweden - *

        ebcdic-cp-se - *

        - *

        IANA - *

        - *

        cp278 - *

        EBCDIC: Italy - *

        ebcdic-cp-it - *

        - *

        IANA - *

        - *

        cp280 - *

        EBCDIC: Spain, Latin America - *

        ebcdic-cp-es - *

        - *

        IANA - *

        - *

        cp284 - *

        EBCDIC: Great Britain - *

        ebcdic-cp-gb - *

        - *

        IANA - *

        - *

        cp285 - *

        EBCDIC: France - *

        ebcdic-cp-fr - *

        - *

        IANA - *

        - *

        cp297 - *

        EBCDIC: Arabic - *

        ebcdic-cp-ar1 - *

        - *

        IANA - *

        - *

        cp420 - *

        EBCDIC: Hebrew - *

        ebcdic-cp-he - *

        - *

        IANA - *

        - *

        cp424 - *

        EBCDIC: Switzerland - *

        ebcdic-cp-ch - *

        - *

        IANA - *

        - *

        cp500 - *

        EBCDIC: Roece - *

        ebcdic-cp-roece - *

        - *

        IANA - *

        - *

        cp870 - *

        EBCDIC: Yogoslavia - *

        ebcdic-cp-yu - *

        - *

        IANA - *

        - *

        cp870 - *

        EBCDIC: Iceland - *

        ebcdic-cp-is - *

        - *

        IANA - *

        - *

        cp871 - *

        EBCDIC: Urdu - *

        ebcdic-cp-ar2 - *

        - *

        IANA - *

        - *

        cp918 - *

        Chinese for PRC, mixed 1/2 byte - *

        gb2312 - *

        - *

        MIME - *

        - *

        GB2312 - *

        Extended Unix Code, packed for Japanese - *

        euc-jp - *

        - *

        MIME - *

        - *

        eucjis - *

        Japanese: iso-2022-jp - *

        iso-2020-jp - *

        - *

        MIME - *

        - *

        JIS - *

        Japanese: Shift JIS - *

        Shift_JIS - *

        - *

        MIME - *

        - *

        SJIS - *

        Chinese: Big5 - *

        Big5 - *

        - *

        MIME - *

        - *

        Big5 - *

        Extended Unix Code, packed for Korean - *

        euc-kr - *

        - *

        MIME - *

        - *

        iso2022kr - *

        Cyrillic - *

        koi8-r - *

        - *

        MIME - *

        - *

        koi8-r - *

        - * - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - * @author TAMURA Kent <kent@trl.ibm.co.jp> - */ -public class MIME2Java { - - static private Hashtable s_enchash; - static private Hashtable s_revhash; - - static { - s_enchash = new Hashtable(); - // , - s_enchash.put("UTF-8", "UTF8"); - s_enchash.put("US-ASCII", "8859_1"); // ? - s_enchash.put("ISO-8859-1", "8859_1"); - s_enchash.put("ISO-8859-2", "8859_2"); - s_enchash.put("ISO-8859-3", "8859_3"); - s_enchash.put("ISO-8859-4", "8859_4"); - s_enchash.put("ISO-8859-5", "8859_5"); - s_enchash.put("ISO-8859-6", "8859_6"); - s_enchash.put("ISO-8859-7", "8859_7"); - s_enchash.put("ISO-8859-8", "8859_8"); - s_enchash.put("ISO-8859-9", "8859_9"); - s_enchash.put("ISO-2022-JP", "JIS"); - s_enchash.put("SHIFT_JIS", "SJIS"); - s_enchash.put("EUC-JP", "EUCJIS"); - s_enchash.put("GB2312", "GB2312"); - s_enchash.put("BIG5", "Big5"); - s_enchash.put("EUC-KR", "KSC5601"); - s_enchash.put("ISO-2022-KR", "ISO2022KR"); - s_enchash.put("KOI8-R", "KOI8_R"); - - s_enchash.put("EBCDIC-CP-US", "CP037"); - s_enchash.put("EBCDIC-CP-CA", "CP037"); - s_enchash.put("EBCDIC-CP-NL", "CP037"); - s_enchash.put("EBCDIC-CP-DK", "CP277"); - s_enchash.put("EBCDIC-CP-NO", "CP277"); - s_enchash.put("EBCDIC-CP-FI", "CP278"); - s_enchash.put("EBCDIC-CP-SE", "CP278"); - s_enchash.put("EBCDIC-CP-IT", "CP280"); - s_enchash.put("EBCDIC-CP-ES", "CP284"); - s_enchash.put("EBCDIC-CP-GB", "CP285"); - s_enchash.put("EBCDIC-CP-FR", "CP297"); - s_enchash.put("EBCDIC-CP-AR1", "CP420"); - s_enchash.put("EBCDIC-CP-HE", "CP424"); - s_enchash.put("EBCDIC-CP-CH", "CP500"); - s_enchash.put("EBCDIC-CP-ROECE", "CP870"); - s_enchash.put("EBCDIC-CP-YU", "CP870"); - s_enchash.put("EBCDIC-CP-IS", "CP871"); - s_enchash.put("EBCDIC-CP-AR2", "CP918"); - - // j:CNS11643 -> EUC-TW? - // ISO-2022-CN? ISO-2022-CN-EXT? - - s_revhash = new Hashtable(); - // , - s_revhash.put("UTF8", "UTF-8"); - //s_revhash.put("8859_1", "US-ASCII"); // ? - s_revhash.put("8859_1", "ISO-8859-1"); - s_revhash.put("8859_2", "ISO-8859-2"); - s_revhash.put("8859_3", "ISO-8859-3"); - s_revhash.put("8859_4", "ISO-8859-4"); - s_revhash.put("8859_5", "ISO-8859-5"); - s_revhash.put("8859_6", "ISO-8859-6"); - s_revhash.put("8859_7", "ISO-8859-7"); - s_revhash.put("8859_8", "ISO-8859-8"); - s_revhash.put("8859_9", "ISO-8859-9"); - s_revhash.put("JIS", "ISO-2022-JP"); - s_revhash.put("SJIS", "Shift_JIS"); - s_revhash.put("EUCJIS", "EUC-JP"); - s_revhash.put("GB2312", "GB2312"); - s_revhash.put("BIG5", "Big5"); - s_revhash.put("KSC5601", "EUC-KR"); - s_revhash.put("ISO2022KR", "ISO-2022-KR"); - s_revhash.put("KOI8_R", "KOI8-R"); - - s_revhash.put("CP037", "EBCDIC-CP-US"); - s_revhash.put("CP037", "EBCDIC-CP-CA"); - s_revhash.put("CP037", "EBCDIC-CP-NL"); - s_revhash.put("CP277", "EBCDIC-CP-DK"); - s_revhash.put("CP277", "EBCDIC-CP-NO"); - s_revhash.put("CP278", "EBCDIC-CP-FI"); - s_revhash.put("CP278", "EBCDIC-CP-SE"); - s_revhash.put("CP280", "EBCDIC-CP-IT"); - s_revhash.put("CP284", "EBCDIC-CP-ES"); - s_revhash.put("CP285", "EBCDIC-CP-GB"); - s_revhash.put("CP297", "EBCDIC-CP-FR"); - s_revhash.put("CP420", "EBCDIC-CP-AR1"); - s_revhash.put("CP424", "EBCDIC-CP-HE"); - s_revhash.put("CP500", "EBCDIC-CP-CH"); - s_revhash.put("CP870", "EBCDIC-CP-ROECE"); - s_revhash.put("CP870", "EBCDIC-CP-YU"); - s_revhash.put("CP871", "EBCDIC-CP-IS"); - s_revhash.put("CP918", "EBCDIC-CP-AR2"); - } - - private MIME2Java() { - } - - /** - * Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name. - * @param mimeCharsetName Case insensitive MIME charset name: UTF-8, US-ASCII, ISO-8859-1, - * ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, - * ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS, - * EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R, - * EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK, - * EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT, - * EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1, - * EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU, - * EBCDIC-CP-IS and EBCDIC-CP-AR2. - * @return Java encoding name, or null if mimeCharsetName - * is unknown. - * @see #reverse - */ - public static String convert(String mimeCharsetName) { - return (String)s_enchash.get(mimeCharsetName.toUpperCase()); - } - - /** - * Convert a Java encoding name to MIME charset name. - * Available values of encoding are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4", - * "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS", - * "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278", - * "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918". - * @param encoding Case insensitive Java encoding name: UTF8, 8859_1, 8859_2, 8859_3, - * 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS, - * GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278, - * CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871 - * and CP918. - * @return MIME charset name, or null if encoding is unknown. - * @see #convert - */ - public static String reverse(String encoding) { - return (String)s_revhash.get(encoding.toUpperCase()); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.util.*; + +/** + * MIME2Java is a convenience class which handles conversions between MIME charset names + * and Java encoding names. + *

        The supported XML encodings are the intersection of XML-supported code sets and those + * supported in JDK 1.1. + *

        MIME charset names are used on xmlEncoding parameters to methods such + * as TXDocument#setEncoding and DTD#setEncoding. + *

        Java encoding names are used on encoding parameters to + * methods such as TXDocument#printWithFormat and DTD#printExternal. + *

        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        + *

        Common Name + *

        + *

        Use this name in XML files + *

        + *

        Name Type + *

        + *

        Xerces converts to this Java Encoder Name + *

        8 bit Unicode + *

        UTF-8 + *

        + *

        IANA + *

        + *

        UTF8 + *

        ISO Latin 1 + *

        ISO-8859-1 + *

        + *

        MIME + *

        + *

        ISO-8859-1 + *

        ISO Latin 2 + *

        ISO-8859-2 + *

        + *

        MIME + *

        + *

        ISO-8859-2 + *

        ISO Latin 3 + *

        ISO-8859-3 + *

        + *

        MIME + *

        + *

        ISO-8859-3 + *

        ISO Latin 4 + *

        ISO-8859-4 + *

        + *

        MIME + *

        + *

        ISO-8859-4 + *

        ISO Latin Cyrillic + *

        ISO-8859-5 + *

        + *

        MIME + *

        + *

        ISO-8859-5 + *

        ISO Latin Arabic + *

        ISO-8859-6 + *

        + *

        MIME + *

        + *

        ISO-8859-6 + *

        ISO Latin Greek + *

        ISO-8859-7 + *

        + *

        MIME + *

        + *

        ISO-8859-7 + *

        ISO Latin Hebrew + *

        ISO-8859-8 + *

        + *

        MIME + *

        + *

        ISO-8859-8 + *

        ISO Latin 5 + *

        ISO-8859-9 + *

        + *

        MIME + *

        + *

        ISO-8859-9 + *

        EBCDIC: US + *

        ebcdic-cp-us + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Canada + *

        ebcdic-cp-ca + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Netherlands + *

        ebcdic-cp-nl + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Denmark + *

        ebcdic-cp-dk + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Norway + *

        ebcdic-cp-no + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Finland + *

        ebcdic-cp-fi + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Sweden + *

        ebcdic-cp-se + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Italy + *

        ebcdic-cp-it + *

        + *

        IANA + *

        + *

        cp280 + *

        EBCDIC: Spain, Latin America + *

        ebcdic-cp-es + *

        + *

        IANA + *

        + *

        cp284 + *

        EBCDIC: Great Britain + *

        ebcdic-cp-gb + *

        + *

        IANA + *

        + *

        cp285 + *

        EBCDIC: France + *

        ebcdic-cp-fr + *

        + *

        IANA + *

        + *

        cp297 + *

        EBCDIC: Arabic + *

        ebcdic-cp-ar1 + *

        + *

        IANA + *

        + *

        cp420 + *

        EBCDIC: Hebrew + *

        ebcdic-cp-he + *

        + *

        IANA + *

        + *

        cp424 + *

        EBCDIC: Switzerland + *

        ebcdic-cp-ch + *

        + *

        IANA + *

        + *

        cp500 + *

        EBCDIC: Roece + *

        ebcdic-cp-roece + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Yogoslavia + *

        ebcdic-cp-yu + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Iceland + *

        ebcdic-cp-is + *

        + *

        IANA + *

        + *

        cp871 + *

        EBCDIC: Urdu + *

        ebcdic-cp-ar2 + *

        + *

        IANA + *

        + *

        cp918 + *

        Chinese for PRC, mixed 1/2 byte + *

        gb2312 + *

        + *

        MIME + *

        + *

        GB2312 + *

        Extended Unix Code, packed for Japanese + *

        euc-jp + *

        + *

        MIME + *

        + *

        eucjis + *

        Japanese: iso-2022-jp + *

        iso-2020-jp + *

        + *

        MIME + *

        + *

        JIS + *

        Japanese: Shift JIS + *

        Shift_JIS + *

        + *

        MIME + *

        + *

        SJIS + *

        Chinese: Big5 + *

        Big5 + *

        + *

        MIME + *

        + *

        Big5 + *

        Extended Unix Code, packed for Korean + *

        euc-kr + *

        + *

        MIME + *

        + *

        iso2022kr + *

        Cyrillic + *

        koi8-r + *

        + *

        MIME + *

        + *

        koi8-r + *

        + * + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + * @author TAMURA Kent <kent@trl.ibm.co.jp> + */ +public class MIME2Java { + + static private Hashtable s_enchash; + static private Hashtable s_revhash; + + static { + s_enchash = new Hashtable(); + // , + s_enchash.put("UTF-8", "UTF8"); + s_enchash.put("US-ASCII", "8859_1"); // ? + s_enchash.put("ISO-8859-1", "8859_1"); + s_enchash.put("ISO-8859-2", "8859_2"); + s_enchash.put("ISO-8859-3", "8859_3"); + s_enchash.put("ISO-8859-4", "8859_4"); + s_enchash.put("ISO-8859-5", "8859_5"); + s_enchash.put("ISO-8859-6", "8859_6"); + s_enchash.put("ISO-8859-7", "8859_7"); + s_enchash.put("ISO-8859-8", "8859_8"); + s_enchash.put("ISO-8859-9", "8859_9"); + s_enchash.put("ISO-2022-JP", "JIS"); + s_enchash.put("SHIFT_JIS", "SJIS"); + s_enchash.put("EUC-JP", "EUCJIS"); + s_enchash.put("GB2312", "GB2312"); + s_enchash.put("BIG5", "Big5"); + s_enchash.put("EUC-KR", "KSC5601"); + s_enchash.put("ISO-2022-KR", "ISO2022KR"); + s_enchash.put("KOI8-R", "KOI8_R"); + + s_enchash.put("EBCDIC-CP-US", "CP037"); + s_enchash.put("EBCDIC-CP-CA", "CP037"); + s_enchash.put("EBCDIC-CP-NL", "CP037"); + s_enchash.put("EBCDIC-CP-DK", "CP277"); + s_enchash.put("EBCDIC-CP-NO", "CP277"); + s_enchash.put("EBCDIC-CP-FI", "CP278"); + s_enchash.put("EBCDIC-CP-SE", "CP278"); + s_enchash.put("EBCDIC-CP-IT", "CP280"); + s_enchash.put("EBCDIC-CP-ES", "CP284"); + s_enchash.put("EBCDIC-CP-GB", "CP285"); + s_enchash.put("EBCDIC-CP-FR", "CP297"); + s_enchash.put("EBCDIC-CP-AR1", "CP420"); + s_enchash.put("EBCDIC-CP-HE", "CP424"); + s_enchash.put("EBCDIC-CP-CH", "CP500"); + s_enchash.put("EBCDIC-CP-ROECE", "CP870"); + s_enchash.put("EBCDIC-CP-YU", "CP870"); + s_enchash.put("EBCDIC-CP-IS", "CP871"); + s_enchash.put("EBCDIC-CP-AR2", "CP918"); + + // j:CNS11643 -> EUC-TW? + // ISO-2022-CN? ISO-2022-CN-EXT? + + s_revhash = new Hashtable(); + // , + s_revhash.put("UTF8", "UTF-8"); + //s_revhash.put("8859_1", "US-ASCII"); // ? + s_revhash.put("8859_1", "ISO-8859-1"); + s_revhash.put("8859_2", "ISO-8859-2"); + s_revhash.put("8859_3", "ISO-8859-3"); + s_revhash.put("8859_4", "ISO-8859-4"); + s_revhash.put("8859_5", "ISO-8859-5"); + s_revhash.put("8859_6", "ISO-8859-6"); + s_revhash.put("8859_7", "ISO-8859-7"); + s_revhash.put("8859_8", "ISO-8859-8"); + s_revhash.put("8859_9", "ISO-8859-9"); + s_revhash.put("JIS", "ISO-2022-JP"); + s_revhash.put("SJIS", "Shift_JIS"); + s_revhash.put("EUCJIS", "EUC-JP"); + s_revhash.put("GB2312", "GB2312"); + s_revhash.put("BIG5", "Big5"); + s_revhash.put("KSC5601", "EUC-KR"); + s_revhash.put("ISO2022KR", "ISO-2022-KR"); + s_revhash.put("KOI8_R", "KOI8-R"); + + s_revhash.put("CP037", "EBCDIC-CP-US"); + s_revhash.put("CP037", "EBCDIC-CP-CA"); + s_revhash.put("CP037", "EBCDIC-CP-NL"); + s_revhash.put("CP277", "EBCDIC-CP-DK"); + s_revhash.put("CP277", "EBCDIC-CP-NO"); + s_revhash.put("CP278", "EBCDIC-CP-FI"); + s_revhash.put("CP278", "EBCDIC-CP-SE"); + s_revhash.put("CP280", "EBCDIC-CP-IT"); + s_revhash.put("CP284", "EBCDIC-CP-ES"); + s_revhash.put("CP285", "EBCDIC-CP-GB"); + s_revhash.put("CP297", "EBCDIC-CP-FR"); + s_revhash.put("CP420", "EBCDIC-CP-AR1"); + s_revhash.put("CP424", "EBCDIC-CP-HE"); + s_revhash.put("CP500", "EBCDIC-CP-CH"); + s_revhash.put("CP870", "EBCDIC-CP-ROECE"); + s_revhash.put("CP870", "EBCDIC-CP-YU"); + s_revhash.put("CP871", "EBCDIC-CP-IS"); + s_revhash.put("CP918", "EBCDIC-CP-AR2"); + } + + private MIME2Java() { + } + + /** + * Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name. + * @param mimeCharsetName Case insensitive MIME charset name: UTF-8, US-ASCII, ISO-8859-1, + * ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6, + * ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS, + * EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R, + * EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK, + * EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT, + * EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1, + * EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU, + * EBCDIC-CP-IS and EBCDIC-CP-AR2. + * @return Java encoding name, or null if mimeCharsetName + * is unknown. + * @see #reverse + */ + public static String convert(String mimeCharsetName) { + return (String)s_enchash.get(mimeCharsetName.toUpperCase()); + } + + /** + * Convert a Java encoding name to MIME charset name. + * Available values of encoding are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4", + * "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS", + * "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278", + * "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918". + * @param encoding Case insensitive Java encoding name: UTF8, 8859_1, 8859_2, 8859_3, + * 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS, + * GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278, + * CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871 + * and CP918. + * @return MIME charset name, or null if encoding is unknown. + * @see #convert + */ + public static String reverse(String encoding) { + return (String)s_revhash.get(encoding.toUpperCase()); + } +} diff --git a/java/org/apache/catalina/util/ManifestResource.java b/java/org/apache/catalina/util/ManifestResource.java index 02eb7f585..6ae22d0e9 100644 --- a/java/org/apache/catalina/util/ManifestResource.java +++ b/java/org/apache/catalina/util/ManifestResource.java @@ -1,241 +1,241 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.util; - -import java.util.Iterator; -import java.util.jar.Manifest; -import java.util.jar.Attributes; -import java.util.ArrayList; - -/** - * Representation of a Manifest file and its available extensions and - * required extensions - * - * @author Greg Murray - * @author Justyna Horwat - * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ - * - */ -public class ManifestResource { - - // ------------------------------------------------------------- Properties - - // These are the resource types for determining effect error messages - public static final int SYSTEM = 1; - public static final int WAR = 2; - public static final int APPLICATION = 3; - - private ArrayList availableExtensions = null; - private ArrayList requiredExtensions = null; - - private String resourceName = null; - private int resourceType = -1; - - public ManifestResource(String resourceName, Manifest manifest, - int resourceType) { - this.resourceName = resourceName; - this.resourceType = resourceType; - processManifest(manifest); - } - - /** - * Gets the name of the resource - * - * @return The name of the resource - */ - public String getResourceName() { - return resourceName; - } - - /** - * Gets the list of available extensions - * - * @return List of available extensions - */ - public ArrayList getAvailableExtensions() { - return availableExtensions; - } - - /** - * Gets the list of required extensions - * - * @return List of required extensions - */ - public ArrayList getRequiredExtensions() { - return requiredExtensions; - } - - // --------------------------------------------------------- Public Methods - - /** - * Gets the number of available extensions - * - * @return The number of available extensions - */ - public int getAvailableExtensionCount() { - return (availableExtensions != null) ? availableExtensions.size() : 0; - } - - /** - * Gets the number of required extensions - * - * @return The number of required extensions - */ - public int getRequiredExtensionCount() { - return (requiredExtensions != null) ? requiredExtensions.size() : 0; - } - - /** - * Convienience method to check if this ManifestResource - * has an requires extensions. - * - * @return true if required extensions are present - */ - public boolean requiresExtensions() { - return (requiredExtensions != null) ? true : false; - } - - /** - * Returns true if all required extension dependencies - * have been meet for this ManifestResource object. - * - * @return boolean true if all extension dependencies have been satisfied - */ - public boolean isFulfilled() { - if (requiredExtensions == null) { - return false; - } - Iterator it = requiredExtensions.iterator(); - while (it.hasNext()) { - Extension ext = (Extension)it.next(); - if (!ext.isFulfilled()) return false; - } - return true; - } - - public String toString() { - - StringBuffer sb = new StringBuffer("ManifestResource["); - sb.append(resourceName); - - sb.append(", isFulfilled="); - sb.append(isFulfilled() +""); - sb.append(", requiredExtensionCount ="); - sb.append(getRequiredExtensionCount()); - sb.append(", availableExtensionCount="); - sb.append(getAvailableExtensionCount()); - switch (resourceType) { - case SYSTEM : sb.append(", resourceType=SYSTEM"); break; - case WAR : sb.append(", resourceType=WAR"); break; - case APPLICATION : sb.append(", resourceType=APPLICATION"); break; - } - sb.append("]"); - return (sb.toString()); - } - - - // -------------------------------------------------------- Private Methods - - private void processManifest(Manifest manifest) { - availableExtensions = getAvailableExtensions(manifest); - requiredExtensions = getRequiredExtensions(manifest); - } - - /** - * Return the set of Extension objects representing optional - * packages that are required by the application associated with the - * specified Manifest. - * - * @param manifest Manifest to be parsed - * - * @return List of required extensions, or null if the application - * does not require any extensions - */ - private ArrayList getRequiredExtensions(Manifest manifest) { - - Attributes attributes = manifest.getMainAttributes(); - String names = attributes.getValue("Extension-List"); - if (names == null) - return null; - - ArrayList extensionList = new ArrayList(); - names += " "; - - while (true) { - - int space = names.indexOf(' '); - if (space < 0) - break; - String name = names.substring(0, space).trim(); - names = names.substring(space + 1); - - String value = - attributes.getValue(name + "-Extension-Name"); - if (value == null) - continue; - Extension extension = new Extension(); - extension.setExtensionName(value); - extension.setImplementationURL - (attributes.getValue(name + "-Implementation-URL")); - extension.setImplementationVendorId - (attributes.getValue(name + "-Implementation-Vendor-Id")); - String version = attributes.getValue(name + "-Implementation-Version"); - extension.setImplementationVersion(version); - extension.setSpecificationVersion - (attributes.getValue(name + "-Specification-Version")); - extensionList.add(extension); - } - return extensionList; - } - - /** - * Return the set of Extension objects representing optional - * packages that are bundled with the application associated with the - * specified Manifest. - * - * @param manifest Manifest to be parsed - * - * @return List of available extensions, or null if the web application - * does not bundle any extensions - */ - private ArrayList getAvailableExtensions(Manifest manifest) { - - Attributes attributes = manifest.getMainAttributes(); - String name = attributes.getValue("Extension-Name"); - if (name == null) - return null; - - ArrayList extensionList = new ArrayList(); - - Extension extension = new Extension(); - extension.setExtensionName(name); - extension.setImplementationURL( - attributes.getValue("Implementation-URL")); - extension.setImplementationVendor( - attributes.getValue("Implementation-Vendor")); - extension.setImplementationVendorId( - attributes.getValue("Implementation-Vendor-Id")); - extension.setImplementationVersion( - attributes.getValue("Implementation-Version")); - extension.setSpecificationVersion( - attributes.getValue("Specification-Version")); - - extensionList.add(extension); - - return extensionList; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.util; + +import java.util.Iterator; +import java.util.jar.Manifest; +import java.util.jar.Attributes; +import java.util.ArrayList; + +/** + * Representation of a Manifest file and its available extensions and + * required extensions + * + * @author Greg Murray + * @author Justyna Horwat + * @version $Revision: 360278 $ $Date: 2005-12-31 14:26:41 +0100 (sam., 31 déc. 2005) $ + * + */ +public class ManifestResource { + + // ------------------------------------------------------------- Properties + + // These are the resource types for determining effect error messages + public static final int SYSTEM = 1; + public static final int WAR = 2; + public static final int APPLICATION = 3; + + private ArrayList availableExtensions = null; + private ArrayList requiredExtensions = null; + + private String resourceName = null; + private int resourceType = -1; + + public ManifestResource(String resourceName, Manifest manifest, + int resourceType) { + this.resourceName = resourceName; + this.resourceType = resourceType; + processManifest(manifest); + } + + /** + * Gets the name of the resource + * + * @return The name of the resource + */ + public String getResourceName() { + return resourceName; + } + + /** + * Gets the list of available extensions + * + * @return List of available extensions + */ + public ArrayList getAvailableExtensions() { + return availableExtensions; + } + + /** + * Gets the list of required extensions + * + * @return List of required extensions + */ + public ArrayList getRequiredExtensions() { + return requiredExtensions; + } + + // --------------------------------------------------------- Public Methods + + /** + * Gets the number of available extensions + * + * @return The number of available extensions + */ + public int getAvailableExtensionCount() { + return (availableExtensions != null) ? availableExtensions.size() : 0; + } + + /** + * Gets the number of required extensions + * + * @return The number of required extensions + */ + public int getRequiredExtensionCount() { + return (requiredExtensions != null) ? requiredExtensions.size() : 0; + } + + /** + * Convienience method to check if this ManifestResource + * has an requires extensions. + * + * @return true if required extensions are present + */ + public boolean requiresExtensions() { + return (requiredExtensions != null) ? true : false; + } + + /** + * Returns true if all required extension dependencies + * have been meet for this ManifestResource object. + * + * @return boolean true if all extension dependencies have been satisfied + */ + public boolean isFulfilled() { + if (requiredExtensions == null) { + return false; + } + Iterator it = requiredExtensions.iterator(); + while (it.hasNext()) { + Extension ext = (Extension)it.next(); + if (!ext.isFulfilled()) return false; + } + return true; + } + + public String toString() { + + StringBuffer sb = new StringBuffer("ManifestResource["); + sb.append(resourceName); + + sb.append(", isFulfilled="); + sb.append(isFulfilled() +""); + sb.append(", requiredExtensionCount ="); + sb.append(getRequiredExtensionCount()); + sb.append(", availableExtensionCount="); + sb.append(getAvailableExtensionCount()); + switch (resourceType) { + case SYSTEM : sb.append(", resourceType=SYSTEM"); break; + case WAR : sb.append(", resourceType=WAR"); break; + case APPLICATION : sb.append(", resourceType=APPLICATION"); break; + } + sb.append("]"); + return (sb.toString()); + } + + + // -------------------------------------------------------- Private Methods + + private void processManifest(Manifest manifest) { + availableExtensions = getAvailableExtensions(manifest); + requiredExtensions = getRequiredExtensions(manifest); + } + + /** + * Return the set of Extension objects representing optional + * packages that are required by the application associated with the + * specified Manifest. + * + * @param manifest Manifest to be parsed + * + * @return List of required extensions, or null if the application + * does not require any extensions + */ + private ArrayList getRequiredExtensions(Manifest manifest) { + + Attributes attributes = manifest.getMainAttributes(); + String names = attributes.getValue("Extension-List"); + if (names == null) + return null; + + ArrayList extensionList = new ArrayList(); + names += " "; + + while (true) { + + int space = names.indexOf(' '); + if (space < 0) + break; + String name = names.substring(0, space).trim(); + names = names.substring(space + 1); + + String value = + attributes.getValue(name + "-Extension-Name"); + if (value == null) + continue; + Extension extension = new Extension(); + extension.setExtensionName(value); + extension.setImplementationURL + (attributes.getValue(name + "-Implementation-URL")); + extension.setImplementationVendorId + (attributes.getValue(name + "-Implementation-Vendor-Id")); + String version = attributes.getValue(name + "-Implementation-Version"); + extension.setImplementationVersion(version); + extension.setSpecificationVersion + (attributes.getValue(name + "-Specification-Version")); + extensionList.add(extension); + } + return extensionList; + } + + /** + * Return the set of Extension objects representing optional + * packages that are bundled with the application associated with the + * specified Manifest. + * + * @param manifest Manifest to be parsed + * + * @return List of available extensions, or null if the web application + * does not bundle any extensions + */ + private ArrayList getAvailableExtensions(Manifest manifest) { + + Attributes attributes = manifest.getMainAttributes(); + String name = attributes.getValue("Extension-Name"); + if (name == null) + return null; + + ArrayList extensionList = new ArrayList(); + + Extension extension = new Extension(); + extension.setExtensionName(name); + extension.setImplementationURL( + attributes.getValue("Implementation-URL")); + extension.setImplementationVendor( + attributes.getValue("Implementation-Vendor")); + extension.setImplementationVendorId( + attributes.getValue("Implementation-Vendor-Id")); + extension.setImplementationVersion( + attributes.getValue("Implementation-Version")); + extension.setSpecificationVersion( + attributes.getValue("Specification-Version")); + + extensionList.add(extension); + + return extensionList; + } + +} diff --git a/java/org/apache/catalina/util/ParameterMap.java b/java/org/apache/catalina/util/ParameterMap.java index 35efd2069..4d855b86e 100644 --- a/java/org/apache/catalina/util/ParameterMap.java +++ b/java/org/apache/catalina/util/ParameterMap.java @@ -1,211 +1,211 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.util.HashMap; -import java.util.Map; - - -/** - * Extended implementation of HashMap that includes a - * locked property. This class can be used to safely expose - * Catalina internal parameter map objects to user classes without having - * to clone them in order to avoid modifications. When first created, a - * ParmaeterMap instance is not locked. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class ParameterMap extends HashMap { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new, empty map with the default initial capacity and - * load factor. - */ - public ParameterMap() { - - super(); - - } - - - /** - * Construct a new, empty map with the specified initial capacity and - * default load factor. - * - * @param initialCapacity The initial capacity of this map - */ - public ParameterMap(int initialCapacity) { - - super(initialCapacity); - - } - - - /** - * Construct a new, empty map with the specified initial capacity and - * load factor. - * - * @param initialCapacity The initial capacity of this map - * @param loadFactor The load factor of this map - */ - public ParameterMap(int initialCapacity, float loadFactor) { - - super(initialCapacity, loadFactor); - - } - - - /** - * Construct a new map with the same mappings as the given map. - * - * @param map Map whose contents are dupliated in the new map - */ - public ParameterMap(Map map) { - - super(map); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * The current lock state of this parameter map. - */ - private boolean locked = false; - - - /** - * Return the locked state of this parameter map. - */ - public boolean isLocked() { - - return (this.locked); - - } - - - /** - * Set the locked state of this parameter map. - * - * @param locked The new locked state - */ - public void setLocked(boolean locked) { - - this.locked = locked; - - } - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager("org.apache.catalina.util"); - - - // --------------------------------------------------------- Public Methods - - - - /** - * Remove all mappings from this map. - * - * @exception IllegalStateException if this map is currently locked - */ - public void clear() { - - if (locked) - throw new IllegalStateException - (sm.getString("parameterMap.locked")); - super.clear(); - - } - - - /** - * Associate the specified value with the specified key in this map. If - * the map previously contained a mapping for this key, the old value is - * replaced. - * - * @param key Key with which the specified value is to be associated - * @param value Value to be associated with the specified key - * - * @return The previous value associated with the specified key, or - * null if there was no mapping for key - * - * @exception IllegalStateException if this map is currently locked - */ - public Object put(Object key, Object value) { - - if (locked) - throw new IllegalStateException - (sm.getString("parameterMap.locked")); - return (super.put(key, value)); - - } - - - /** - * Copy all of the mappings from the specified map to this one. These - * mappings replace any mappings that this map had for any of the keys - * currently in the specified Map. - * - * @param map Mappings to be stored into this map - * - * @exception IllegalStateException if this map is currently locked - */ - public void putAll(Map map) { - - if (locked) - throw new IllegalStateException - (sm.getString("parameterMap.locked")); - super.putAll(map); - - } - - - /** - * Remove the mapping for this key from the map if present. - * - * @param key Key whose mapping is to be removed from the map - * - * @return The previous value associated with the specified key, or - * null if there was no mapping for that key - * - * @exception IllegalStateException if this map is currently locked - */ - public Object remove(Object key) { - - if (locked) - throw new IllegalStateException - (sm.getString("parameterMap.locked")); - return (super.remove(key)); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.util.HashMap; +import java.util.Map; + + +/** + * Extended implementation of HashMap that includes a + * locked property. This class can be used to safely expose + * Catalina internal parameter map objects to user classes without having + * to clone them in order to avoid modifications. When first created, a + * ParmaeterMap instance is not locked. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class ParameterMap extends HashMap { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new, empty map with the default initial capacity and + * load factor. + */ + public ParameterMap() { + + super(); + + } + + + /** + * Construct a new, empty map with the specified initial capacity and + * default load factor. + * + * @param initialCapacity The initial capacity of this map + */ + public ParameterMap(int initialCapacity) { + + super(initialCapacity); + + } + + + /** + * Construct a new, empty map with the specified initial capacity and + * load factor. + * + * @param initialCapacity The initial capacity of this map + * @param loadFactor The load factor of this map + */ + public ParameterMap(int initialCapacity, float loadFactor) { + + super(initialCapacity, loadFactor); + + } + + + /** + * Construct a new map with the same mappings as the given map. + * + * @param map Map whose contents are dupliated in the new map + */ + public ParameterMap(Map map) { + + super(map); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * The current lock state of this parameter map. + */ + private boolean locked = false; + + + /** + * Return the locked state of this parameter map. + */ + public boolean isLocked() { + + return (this.locked); + + } + + + /** + * Set the locked state of this parameter map. + * + * @param locked The new locked state + */ + public void setLocked(boolean locked) { + + this.locked = locked; + + } + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + + // --------------------------------------------------------- Public Methods + + + + /** + * Remove all mappings from this map. + * + * @exception IllegalStateException if this map is currently locked + */ + public void clear() { + + if (locked) + throw new IllegalStateException + (sm.getString("parameterMap.locked")); + super.clear(); + + } + + + /** + * Associate the specified value with the specified key in this map. If + * the map previously contained a mapping for this key, the old value is + * replaced. + * + * @param key Key with which the specified value is to be associated + * @param value Value to be associated with the specified key + * + * @return The previous value associated with the specified key, or + * null if there was no mapping for key + * + * @exception IllegalStateException if this map is currently locked + */ + public Object put(Object key, Object value) { + + if (locked) + throw new IllegalStateException + (sm.getString("parameterMap.locked")); + return (super.put(key, value)); + + } + + + /** + * Copy all of the mappings from the specified map to this one. These + * mappings replace any mappings that this map had for any of the keys + * currently in the specified Map. + * + * @param map Mappings to be stored into this map + * + * @exception IllegalStateException if this map is currently locked + */ + public void putAll(Map map) { + + if (locked) + throw new IllegalStateException + (sm.getString("parameterMap.locked")); + super.putAll(map); + + } + + + /** + * Remove the mapping for this key from the map if present. + * + * @param key Key whose mapping is to be removed from the map + * + * @return The previous value associated with the specified key, or + * null if there was no mapping for that key + * + * @exception IllegalStateException if this map is currently locked + */ + public Object remove(Object key) { + + if (locked) + throw new IllegalStateException + (sm.getString("parameterMap.locked")); + return (super.remove(key)); + + } + + +} diff --git a/java/org/apache/catalina/util/Queue.java b/java/org/apache/catalina/util/Queue.java index 2e1ca410b..fc4320acf 100644 --- a/java/org/apache/catalina/util/Queue.java +++ b/java/org/apache/catalina/util/Queue.java @@ -1,87 +1,87 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.util; - -import java.util.Vector; - -/** - * A simple FIFO queue class which causes the calling thread to wait - * if the queue is empty and notifies threads that are waiting when it - * is not empty. - * - * @author Anil V (akv@eng.sun.com) - */ -public class Queue { - private Vector vector = new Vector(); - - /** - * Put the object into the queue. - * - * @param object the object to be appended to the - * queue. - */ - public synchronized void put(Object object) { - vector.addElement(object); - notify(); - } - - /** - * Pull the first object out of the queue. Wait if the queue is - * empty. - */ - public synchronized Object pull() { - while (isEmpty()) - try { - wait(); - } catch (InterruptedException ex) { - } - return get(); - } - - /** - * Get the first object out of the queue. Return null if the queue - * is empty. - */ - public synchronized Object get() { - Object object = peek(); - if (object != null) - vector.removeElementAt(0); - return object; - } - - /** - * Peek to see if something is available. - */ - public Object peek() { - if (isEmpty()) - return null; - return vector.elementAt(0); - } - - /** - * Is the queue empty? - */ - public boolean isEmpty() { - return vector.isEmpty(); - } - - /** - * How many elements are there in this queue? - */ - public int size() { - return vector.size(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.util; + +import java.util.Vector; + +/** + * A simple FIFO queue class which causes the calling thread to wait + * if the queue is empty and notifies threads that are waiting when it + * is not empty. + * + * @author Anil V (akv@eng.sun.com) + */ +public class Queue { + private Vector vector = new Vector(); + + /** + * Put the object into the queue. + * + * @param object the object to be appended to the + * queue. + */ + public synchronized void put(Object object) { + vector.addElement(object); + notify(); + } + + /** + * Pull the first object out of the queue. Wait if the queue is + * empty. + */ + public synchronized Object pull() { + while (isEmpty()) + try { + wait(); + } catch (InterruptedException ex) { + } + return get(); + } + + /** + * Get the first object out of the queue. Return null if the queue + * is empty. + */ + public synchronized Object get() { + Object object = peek(); + if (object != null) + vector.removeElementAt(0); + return object; + } + + /** + * Peek to see if something is available. + */ + public Object peek() { + if (isEmpty()) + return null; + return vector.elementAt(0); + } + + /** + * Is the queue empty? + */ + public boolean isEmpty() { + return vector.isEmpty(); + } + + /** + * How many elements are there in this queue? + */ + public int size() { + return vector.size(); + } +} diff --git a/java/org/apache/catalina/util/RequestUtil.java b/java/org/apache/catalina/util/RequestUtil.java index b547d74c1..3a91c087e 100644 --- a/java/org/apache/catalina/util/RequestUtil.java +++ b/java/org/apache/catalina/util/RequestUtil.java @@ -1,509 +1,509 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - -import java.io.UnsupportedEncodingException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Map; -import java.util.TimeZone; - -import javax.servlet.http.Cookie; - - -/** - * General purpose request parsing and encoding utility methods. - * - * @author Craig R. McClanahan - * @author Tim Tye - * @version $Revision: 302905 $ $Date: 2004-05-26 18:41:54 +0200 (mer., 26 mai 2004) $ - */ - -public final class RequestUtil { - - - /** - * The DateFormat to use for generating readable dates in cookies. - */ - private static SimpleDateFormat format = - new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz"); - - static { - format.setTimeZone(TimeZone.getTimeZone("GMT")); - } - - - /** - * Encode a cookie as per RFC 2109. The resulting string can be used - * as the value for a Set-Cookie header. - * - * @param cookie The cookie to encode. - * @return A string following RFC 2109. - */ - public static String encodeCookie(Cookie cookie) { - - StringBuffer buf = new StringBuffer( cookie.getName() ); - buf.append("="); - buf.append(cookie.getValue()); - - if (cookie.getComment() != null) { - buf.append("; Comment=\""); - buf.append(cookie.getComment()); - buf.append("\""); - } - - if (cookie.getDomain() != null) { - buf.append("; Domain=\""); - buf.append(cookie.getDomain()); - buf.append("\""); - } - - long age = cookie.getMaxAge(); - if (cookie.getMaxAge() >= 0) { - buf.append("; Max-Age=\""); - buf.append(cookie.getMaxAge()); - buf.append("\""); - } - - if (cookie.getPath() != null) { - buf.append("; Path=\""); - buf.append(cookie.getPath()); - buf.append("\""); - } - - if (cookie.getSecure()) { - buf.append("; Secure"); - } - - if (cookie.getVersion() > 0) { - buf.append("; Version=\""); - buf.append(cookie.getVersion()); - buf.append("\""); - } - - return (buf.toString()); - } - - - /** - * Filter the specified message string for characters that are sensitive - * in HTML. This avoids potential attacks caused by including JavaScript - * codes in the request URL that is often reported in error messages. - * - * @param message The message string to be filtered - */ - public static String filter(String message) { - - if (message == null) - return (null); - - char content[] = new char[message.length()]; - message.getChars(0, message.length(), content, 0); - StringBuffer result = new StringBuffer(content.length + 50); - for (int i = 0; i < content.length; i++) { - switch (content[i]) { - case '<': - result.append("<"); - break; - case '>': - result.append(">"); - break; - case '&': - result.append("&"); - break; - case '"': - result.append("""); - break; - default: - result.append(content[i]); - } - } - return (result.toString()); - - } - - - /** - * Normalize a relative URI path that may have relative values ("/./", - * "/../", and so on ) it it. WARNING - This method is - * useful only for normalizing application-generated paths. It does not - * try to perform security checks for malicious input. - * - * @param path Relative path to be normalized - */ - public static String normalize(String path) { - - if (path == null) - return null; - - // Create a place for the normalized path - String normalized = path; - - if (normalized.equals("/.")) - return "/"; - - // Add a leading "/" if necessary - if (!normalized.startsWith("/")) - normalized = "/" + normalized; - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - return (null); // Trying to go outside our context - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Return the normalized path that we have completed - return (normalized); - - } - - - /** - * Parse the character encoding from the specified content type header. - * If the content type is null, or there is no explicit character encoding, - * null is returned. - * - * @param contentType a content type header - */ - public static String parseCharacterEncoding(String contentType) { - - if (contentType == null) - return (null); - int start = contentType.indexOf("charset="); - if (start < 0) - return (null); - String encoding = contentType.substring(start + 8); - int end = encoding.indexOf(';'); - if (end >= 0) - encoding = encoding.substring(0, end); - encoding = encoding.trim(); - if ((encoding.length() > 2) && (encoding.startsWith("\"")) - && (encoding.endsWith("\""))) - encoding = encoding.substring(1, encoding.length() - 1); - return (encoding.trim()); - - } - - - /** - * Parse a cookie header into an array of cookies according to RFC 2109. - * - * @param header Value of an HTTP "Cookie" header - */ - public static Cookie[] parseCookieHeader(String header) { - - if ((header == null) || (header.length() < 1)) - return (new Cookie[0]); - - ArrayList cookies = new ArrayList(); - while (header.length() > 0) { - int semicolon = header.indexOf(';'); - if (semicolon < 0) - semicolon = header.length(); - if (semicolon == 0) - break; - String token = header.substring(0, semicolon); - if (semicolon < header.length()) - header = header.substring(semicolon + 1); - else - header = ""; - try { - int equals = token.indexOf('='); - if (equals > 0) { - String name = token.substring(0, equals).trim(); - String value = token.substring(equals+1).trim(); - cookies.add(new Cookie(name, value)); - } - } catch (Throwable e) { - ; - } - } - - return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); - - } - - - /** - * Append request parameters from the specified String to the specified - * Map. It is presumed that the specified Map is not accessed from any - * other thread, so no synchronization is performed. - *

        - * IMPLEMENTATION NOTE: URL decoding is performed - * individually on the parsed name and value elements, rather than on - * the entire query string ahead of time, to properly deal with the case - * where the name or value includes an encoded "=" or "&" character - * that would otherwise be interpreted as a delimiter. - * - * @param map Map that accumulates the resulting parameters - * @param data Input string containing request parameters - * - * @exception IllegalArgumentException if the data is malformed - */ - public static void parseParameters(Map map, String data, String encoding) - throws UnsupportedEncodingException { - - if ((data != null) && (data.length() > 0)) { - - // use the specified encoding to extract bytes out of the - // given string so that the encoding is not lost. If an - // encoding is not specified, let it use platform default - byte[] bytes = null; - try { - if (encoding == null) { - bytes = data.getBytes(); - } else { - bytes = data.getBytes(encoding); - } - } catch (UnsupportedEncodingException uee) { - } - - parseParameters(map, bytes, encoding); - } - - } - - - /** - * Decode and return the specified URL-encoded String. - * When the byte array is converted to a string, the system default - * character encoding is used... This may be different than some other - * servers. - * - * @param str The url-encoded string - * - * @exception IllegalArgumentException if a '%' character is not followed - * by a valid 2-digit hexadecimal number - */ - public static String URLDecode(String str) { - - return URLDecode(str, null); - - } - - - /** - * Decode and return the specified URL-encoded String. - * - * @param str The url-encoded string - * @param enc The encoding to use; if null, the default encoding is used - * @exception IllegalArgumentException if a '%' character is not followed - * by a valid 2-digit hexadecimal number - */ - public static String URLDecode(String str, String enc) { - - if (str == null) - return (null); - - // use the specified encoding to extract bytes out of the - // given string so that the encoding is not lost. If an - // encoding is not specified, let it use platform default - byte[] bytes = null; - try { - if (enc == null) { - bytes = str.getBytes(); - } else { - bytes = str.getBytes(enc); - } - } catch (UnsupportedEncodingException uee) {} - - return URLDecode(bytes, enc); - - } - - - /** - * Decode and return the specified URL-encoded byte array. - * - * @param bytes The url-encoded byte array - * @exception IllegalArgumentException if a '%' character is not followed - * by a valid 2-digit hexadecimal number - */ - public static String URLDecode(byte[] bytes) { - return URLDecode(bytes, null); - } - - - /** - * Decode and return the specified URL-encoded byte array. - * - * @param bytes The url-encoded byte array - * @param enc The encoding to use; if null, the default encoding is used - * @exception IllegalArgumentException if a '%' character is not followed - * by a valid 2-digit hexadecimal number - */ - public static String URLDecode(byte[] bytes, String enc) { - - if (bytes == null) - return (null); - - int len = bytes.length; - int ix = 0; - int ox = 0; - while (ix < len) { - byte b = bytes[ix++]; // Get byte to test - if (b == '+') { - b = (byte)' '; - } else if (b == '%') { - b = (byte) ((convertHexDigit(bytes[ix++]) << 4) - + convertHexDigit(bytes[ix++])); - } - bytes[ox++] = b; - } - if (enc != null) { - try { - return new String(bytes, 0, ox, enc); - } catch (Exception e) { - e.printStackTrace(); - } - } - return new String(bytes, 0, ox); - - } - - - /** - * Convert a byte character value to hexidecimal digit value. - * - * @param b the character value byte - */ - private static byte convertHexDigit( byte b ) { - if ((b >= '0') && (b <= '9')) return (byte)(b - '0'); - if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10); - if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10); - return 0; - } - - - /** - * Put name and value pair in map. When name already exist, add value - * to array of values. - * - * @param map The map to populate - * @param name The parameter name - * @param value The parameter value - */ - private static void putMapEntry( Map map, String name, String value) { - String[] newValues = null; - String[] oldValues = (String[]) map.get(name); - if (oldValues == null) { - newValues = new String[1]; - newValues[0] = value; - } else { - newValues = new String[oldValues.length + 1]; - System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); - newValues[oldValues.length] = value; - } - map.put(name, newValues); - } - - - /** - * Append request parameters from the specified String to the specified - * Map. It is presumed that the specified Map is not accessed from any - * other thread, so no synchronization is performed. - *

        - * IMPLEMENTATION NOTE: URL decoding is performed - * individually on the parsed name and value elements, rather than on - * the entire query string ahead of time, to properly deal with the case - * where the name or value includes an encoded "=" or "&" character - * that would otherwise be interpreted as a delimiter. - * - * NOTE: byte array data is modified by this method. Caller beware. - * - * @param map Map that accumulates the resulting parameters - * @param data Input string containing request parameters - * @param encoding Encoding to use for converting hex - * - * @exception UnsupportedEncodingException if the data is malformed - */ - public static void parseParameters(Map map, byte[] data, String encoding) - throws UnsupportedEncodingException { - - if (data != null && data.length > 0) { - int pos = 0; - int ix = 0; - int ox = 0; - String key = null; - String value = null; - while (ix < data.length) { - byte c = data[ix++]; - switch ((char) c) { - case '&': - value = new String(data, 0, ox, encoding); - if (key != null) { - putMapEntry(map, key, value); - key = null; - } - ox = 0; - break; - case '=': - if (key == null) { - key = new String(data, 0, ox, encoding); - ox = 0; - } else { - data[ox++] = c; - } - break; - case '+': - data[ox++] = (byte)' '; - break; - case '%': - data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4) - + convertHexDigit(data[ix++])); - break; - default: - data[ox++] = c; - } - } - //The last value does not end in '&'. So save it now. - if (key != null) { - value = new String(data, 0, ox, encoding); - putMapEntry(map, key, value); - } - } - - } - - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + +import java.io.UnsupportedEncodingException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Map; +import java.util.TimeZone; + +import javax.servlet.http.Cookie; + + +/** + * General purpose request parsing and encoding utility methods. + * + * @author Craig R. McClanahan + * @author Tim Tye + * @version $Revision: 302905 $ $Date: 2004-05-26 18:41:54 +0200 (mer., 26 mai 2004) $ + */ + +public final class RequestUtil { + + + /** + * The DateFormat to use for generating readable dates in cookies. + */ + private static SimpleDateFormat format = + new SimpleDateFormat(" EEEE, dd-MMM-yy kk:mm:ss zz"); + + static { + format.setTimeZone(TimeZone.getTimeZone("GMT")); + } + + + /** + * Encode a cookie as per RFC 2109. The resulting string can be used + * as the value for a Set-Cookie header. + * + * @param cookie The cookie to encode. + * @return A string following RFC 2109. + */ + public static String encodeCookie(Cookie cookie) { + + StringBuffer buf = new StringBuffer( cookie.getName() ); + buf.append("="); + buf.append(cookie.getValue()); + + if (cookie.getComment() != null) { + buf.append("; Comment=\""); + buf.append(cookie.getComment()); + buf.append("\""); + } + + if (cookie.getDomain() != null) { + buf.append("; Domain=\""); + buf.append(cookie.getDomain()); + buf.append("\""); + } + + long age = cookie.getMaxAge(); + if (cookie.getMaxAge() >= 0) { + buf.append("; Max-Age=\""); + buf.append(cookie.getMaxAge()); + buf.append("\""); + } + + if (cookie.getPath() != null) { + buf.append("; Path=\""); + buf.append(cookie.getPath()); + buf.append("\""); + } + + if (cookie.getSecure()) { + buf.append("; Secure"); + } + + if (cookie.getVersion() > 0) { + buf.append("; Version=\""); + buf.append(cookie.getVersion()); + buf.append("\""); + } + + return (buf.toString()); + } + + + /** + * Filter the specified message string for characters that are sensitive + * in HTML. This avoids potential attacks caused by including JavaScript + * codes in the request URL that is often reported in error messages. + * + * @param message The message string to be filtered + */ + public static String filter(String message) { + + if (message == null) + return (null); + + char content[] = new char[message.length()]; + message.getChars(0, message.length(), content, 0); + StringBuffer result = new StringBuffer(content.length + 50); + for (int i = 0; i < content.length; i++) { + switch (content[i]) { + case '<': + result.append("<"); + break; + case '>': + result.append(">"); + break; + case '&': + result.append("&"); + break; + case '"': + result.append("""); + break; + default: + result.append(content[i]); + } + } + return (result.toString()); + + } + + + /** + * Normalize a relative URI path that may have relative values ("/./", + * "/../", and so on ) it it. WARNING - This method is + * useful only for normalizing application-generated paths. It does not + * try to perform security checks for malicious input. + * + * @param path Relative path to be normalized + */ + public static String normalize(String path) { + + if (path == null) + return null; + + // Create a place for the normalized path + String normalized = path; + + if (normalized.equals("/.")) + return "/"; + + // Add a leading "/" if necessary + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + return (null); // Trying to go outside our context + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Return the normalized path that we have completed + return (normalized); + + } + + + /** + * Parse the character encoding from the specified content type header. + * If the content type is null, or there is no explicit character encoding, + * null is returned. + * + * @param contentType a content type header + */ + public static String parseCharacterEncoding(String contentType) { + + if (contentType == null) + return (null); + int start = contentType.indexOf("charset="); + if (start < 0) + return (null); + String encoding = contentType.substring(start + 8); + int end = encoding.indexOf(';'); + if (end >= 0) + encoding = encoding.substring(0, end); + encoding = encoding.trim(); + if ((encoding.length() > 2) && (encoding.startsWith("\"")) + && (encoding.endsWith("\""))) + encoding = encoding.substring(1, encoding.length() - 1); + return (encoding.trim()); + + } + + + /** + * Parse a cookie header into an array of cookies according to RFC 2109. + * + * @param header Value of an HTTP "Cookie" header + */ + public static Cookie[] parseCookieHeader(String header) { + + if ((header == null) || (header.length() < 1)) + return (new Cookie[0]); + + ArrayList cookies = new ArrayList(); + while (header.length() > 0) { + int semicolon = header.indexOf(';'); + if (semicolon < 0) + semicolon = header.length(); + if (semicolon == 0) + break; + String token = header.substring(0, semicolon); + if (semicolon < header.length()) + header = header.substring(semicolon + 1); + else + header = ""; + try { + int equals = token.indexOf('='); + if (equals > 0) { + String name = token.substring(0, equals).trim(); + String value = token.substring(equals+1).trim(); + cookies.add(new Cookie(name, value)); + } + } catch (Throwable e) { + ; + } + } + + return ((Cookie[]) cookies.toArray(new Cookie[cookies.size()])); + + } + + + /** + * Append request parameters from the specified String to the specified + * Map. It is presumed that the specified Map is not accessed from any + * other thread, so no synchronization is performed. + *

        + * IMPLEMENTATION NOTE: URL decoding is performed + * individually on the parsed name and value elements, rather than on + * the entire query string ahead of time, to properly deal with the case + * where the name or value includes an encoded "=" or "&" character + * that would otherwise be interpreted as a delimiter. + * + * @param map Map that accumulates the resulting parameters + * @param data Input string containing request parameters + * + * @exception IllegalArgumentException if the data is malformed + */ + public static void parseParameters(Map map, String data, String encoding) + throws UnsupportedEncodingException { + + if ((data != null) && (data.length() > 0)) { + + // use the specified encoding to extract bytes out of the + // given string so that the encoding is not lost. If an + // encoding is not specified, let it use platform default + byte[] bytes = null; + try { + if (encoding == null) { + bytes = data.getBytes(); + } else { + bytes = data.getBytes(encoding); + } + } catch (UnsupportedEncodingException uee) { + } + + parseParameters(map, bytes, encoding); + } + + } + + + /** + * Decode and return the specified URL-encoded String. + * When the byte array is converted to a string, the system default + * character encoding is used... This may be different than some other + * servers. + * + * @param str The url-encoded string + * + * @exception IllegalArgumentException if a '%' character is not followed + * by a valid 2-digit hexadecimal number + */ + public static String URLDecode(String str) { + + return URLDecode(str, null); + + } + + + /** + * Decode and return the specified URL-encoded String. + * + * @param str The url-encoded string + * @param enc The encoding to use; if null, the default encoding is used + * @exception IllegalArgumentException if a '%' character is not followed + * by a valid 2-digit hexadecimal number + */ + public static String URLDecode(String str, String enc) { + + if (str == null) + return (null); + + // use the specified encoding to extract bytes out of the + // given string so that the encoding is not lost. If an + // encoding is not specified, let it use platform default + byte[] bytes = null; + try { + if (enc == null) { + bytes = str.getBytes(); + } else { + bytes = str.getBytes(enc); + } + } catch (UnsupportedEncodingException uee) {} + + return URLDecode(bytes, enc); + + } + + + /** + * Decode and return the specified URL-encoded byte array. + * + * @param bytes The url-encoded byte array + * @exception IllegalArgumentException if a '%' character is not followed + * by a valid 2-digit hexadecimal number + */ + public static String URLDecode(byte[] bytes) { + return URLDecode(bytes, null); + } + + + /** + * Decode and return the specified URL-encoded byte array. + * + * @param bytes The url-encoded byte array + * @param enc The encoding to use; if null, the default encoding is used + * @exception IllegalArgumentException if a '%' character is not followed + * by a valid 2-digit hexadecimal number + */ + public static String URLDecode(byte[] bytes, String enc) { + + if (bytes == null) + return (null); + + int len = bytes.length; + int ix = 0; + int ox = 0; + while (ix < len) { + byte b = bytes[ix++]; // Get byte to test + if (b == '+') { + b = (byte)' '; + } else if (b == '%') { + b = (byte) ((convertHexDigit(bytes[ix++]) << 4) + + convertHexDigit(bytes[ix++])); + } + bytes[ox++] = b; + } + if (enc != null) { + try { + return new String(bytes, 0, ox, enc); + } catch (Exception e) { + e.printStackTrace(); + } + } + return new String(bytes, 0, ox); + + } + + + /** + * Convert a byte character value to hexidecimal digit value. + * + * @param b the character value byte + */ + private static byte convertHexDigit( byte b ) { + if ((b >= '0') && (b <= '9')) return (byte)(b - '0'); + if ((b >= 'a') && (b <= 'f')) return (byte)(b - 'a' + 10); + if ((b >= 'A') && (b <= 'F')) return (byte)(b - 'A' + 10); + return 0; + } + + + /** + * Put name and value pair in map. When name already exist, add value + * to array of values. + * + * @param map The map to populate + * @param name The parameter name + * @param value The parameter value + */ + private static void putMapEntry( Map map, String name, String value) { + String[] newValues = null; + String[] oldValues = (String[]) map.get(name); + if (oldValues == null) { + newValues = new String[1]; + newValues[0] = value; + } else { + newValues = new String[oldValues.length + 1]; + System.arraycopy(oldValues, 0, newValues, 0, oldValues.length); + newValues[oldValues.length] = value; + } + map.put(name, newValues); + } + + + /** + * Append request parameters from the specified String to the specified + * Map. It is presumed that the specified Map is not accessed from any + * other thread, so no synchronization is performed. + *

        + * IMPLEMENTATION NOTE: URL decoding is performed + * individually on the parsed name and value elements, rather than on + * the entire query string ahead of time, to properly deal with the case + * where the name or value includes an encoded "=" or "&" character + * that would otherwise be interpreted as a delimiter. + * + * NOTE: byte array data is modified by this method. Caller beware. + * + * @param map Map that accumulates the resulting parameters + * @param data Input string containing request parameters + * @param encoding Encoding to use for converting hex + * + * @exception UnsupportedEncodingException if the data is malformed + */ + public static void parseParameters(Map map, byte[] data, String encoding) + throws UnsupportedEncodingException { + + if (data != null && data.length > 0) { + int pos = 0; + int ix = 0; + int ox = 0; + String key = null; + String value = null; + while (ix < data.length) { + byte c = data[ix++]; + switch ((char) c) { + case '&': + value = new String(data, 0, ox, encoding); + if (key != null) { + putMapEntry(map, key, value); + key = null; + } + ox = 0; + break; + case '=': + if (key == null) { + key = new String(data, 0, ox, encoding); + ox = 0; + } else { + data[ox++] = c; + } + break; + case '+': + data[ox++] = (byte)' '; + break; + case '%': + data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4) + + convertHexDigit(data[ix++])); + break; + default: + data[ox++] = c; + } + } + //The last value does not end in '&'. So save it now. + if (key != null) { + value = new String(data, 0, ox, encoding); + putMapEntry(map, key, value); + } + } + + } + + + +} diff --git a/java/org/apache/catalina/util/ResourceSet.java b/java/org/apache/catalina/util/ResourceSet.java index 5bb7903c7..1f1dcdcc6 100644 --- a/java/org/apache/catalina/util/ResourceSet.java +++ b/java/org/apache/catalina/util/ResourceSet.java @@ -1,184 +1,184 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.util.Collection; -import java.util.HashSet; - - -/** - * Extended implementation of HashSet that includes a - * locked property. This class can be used to safely expose - * resource path sets to user classes without having to clone them in order - * to avoid modifications. When first created, a ResourceMap - * is not locked. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class ResourceSet extends HashSet { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new, empty set with the default initial capacity and - * load factor. - */ - public ResourceSet() { - - super(); - - } - - - /** - * Construct a new, empty set with the specified initial capacity and - * default load factor. - * - * @param initialCapacity The initial capacity of this set - */ - public ResourceSet(int initialCapacity) { - - super(initialCapacity); - - } - - - /** - * Construct a new, empty set with the specified initial capacity and - * load factor. - * - * @param initialCapacity The initial capacity of this set - * @param loadFactor The load factor of this set - */ - public ResourceSet(int initialCapacity, float loadFactor) { - - super(initialCapacity, loadFactor); - - } - - - /** - * Construct a new set with the same contents as the existing collection. - * - * @param coll The collection whose contents we should copy - */ - public ResourceSet(Collection coll) { - - super(coll); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * The current lock state of this parameter map. - */ - private boolean locked = false; - - - /** - * Return the locked state of this parameter map. - */ - public boolean isLocked() { - - return (this.locked); - - } - - - /** - * Set the locked state of this parameter map. - * - * @param locked The new locked state - */ - public void setLocked(boolean locked) { - - this.locked = locked; - - } - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager("org.apache.catalina.util"); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add the specified element to this set if it is not already present. - * Return true if the element was added. - * - * @param o The object to be added - * - * @exception IllegalStateException if this ResourceSet is locked - */ - public boolean add(Object o) { - - if (locked) - throw new IllegalStateException - (sm.getString("resourceSet.locked")); - return (super.add(o)); - - } - - - /** - * Remove all of the elements from this set. - * - * @exception IllegalStateException if this ResourceSet is locked - */ - public void clear() { - - if (locked) - throw new IllegalStateException - (sm.getString("resourceSet.locked")); - super.clear(); - - } - - - /** - * Remove the given element from this set if it is present. - * Return true if the element was removed. - * - * @param o The object to be removed - * - * @exception IllegalStateException if this ResourceSet is locked - */ - public boolean remove(Object o) { - - if (locked) - throw new IllegalStateException - (sm.getString("resourceSet.locked")); - return (super.remove(o)); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.util.Collection; +import java.util.HashSet; + + +/** + * Extended implementation of HashSet that includes a + * locked property. This class can be used to safely expose + * resource path sets to user classes without having to clone them in order + * to avoid modifications. When first created, a ResourceMap + * is not locked. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class ResourceSet extends HashSet { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new, empty set with the default initial capacity and + * load factor. + */ + public ResourceSet() { + + super(); + + } + + + /** + * Construct a new, empty set with the specified initial capacity and + * default load factor. + * + * @param initialCapacity The initial capacity of this set + */ + public ResourceSet(int initialCapacity) { + + super(initialCapacity); + + } + + + /** + * Construct a new, empty set with the specified initial capacity and + * load factor. + * + * @param initialCapacity The initial capacity of this set + * @param loadFactor The load factor of this set + */ + public ResourceSet(int initialCapacity, float loadFactor) { + + super(initialCapacity, loadFactor); + + } + + + /** + * Construct a new set with the same contents as the existing collection. + * + * @param coll The collection whose contents we should copy + */ + public ResourceSet(Collection coll) { + + super(coll); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * The current lock state of this parameter map. + */ + private boolean locked = false; + + + /** + * Return the locked state of this parameter map. + */ + public boolean isLocked() { + + return (this.locked); + + } + + + /** + * Set the locked state of this parameter map. + * + * @param locked The new locked state + */ + public void setLocked(boolean locked) { + + this.locked = locked; + + } + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager("org.apache.catalina.util"); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the specified element to this set if it is not already present. + * Return true if the element was added. + * + * @param o The object to be added + * + * @exception IllegalStateException if this ResourceSet is locked + */ + public boolean add(Object o) { + + if (locked) + throw new IllegalStateException + (sm.getString("resourceSet.locked")); + return (super.add(o)); + + } + + + /** + * Remove all of the elements from this set. + * + * @exception IllegalStateException if this ResourceSet is locked + */ + public void clear() { + + if (locked) + throw new IllegalStateException + (sm.getString("resourceSet.locked")); + super.clear(); + + } + + + /** + * Remove the given element from this set if it is present. + * Return true if the element was removed. + * + * @param o The object to be removed + * + * @exception IllegalStateException if this ResourceSet is locked + */ + public boolean remove(Object o) { + + if (locked) + throw new IllegalStateException + (sm.getString("resourceSet.locked")); + return (super.remove(o)); + + } + + +} diff --git a/java/org/apache/catalina/util/SchemaResolver.java b/java/org/apache/catalina/util/SchemaResolver.java index ca2205c01..1a66de320 100644 --- a/java/org/apache/catalina/util/SchemaResolver.java +++ b/java/org/apache/catalina/util/SchemaResolver.java @@ -1,133 +1,133 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.util; - - -import java.util.HashMap; - -import org.apache.tomcat.util.digester.Digester; -import org.xml.sax.InputSource; -import org.xml.sax.EntityResolver; -import org.xml.sax.SAXException; - -/** - * This class implements a local SAX's EntityResolver. All - * DTDs and schemas used to validate the web.xml file will re-directed - * to a local file stored in the servlet-api.jar and jsp-api.jar. - * - * @author Jean-Francois Arcand - */ -public class SchemaResolver implements EntityResolver { - - /** - * The disgester instance for which this class is the entity resolver. - */ - protected Digester digester; - - - /** - * The URLs of dtds and schemas that have been registered, keyed by the - * public identifier that corresponds. - */ - protected HashMap entityValidator = new HashMap(); - - - /** - * The public identifier of the DTD we are currently parsing under - * (if any). - */ - protected String publicId = null; - - - /** - * Extension to make the difference between DTD and Schema. - */ - protected String schemaExtension = "xsd"; - - - /** - * Create a new EntityResolver that will redirect - * all remote dtds and schema to a locat destination. - * @param digester The digester instance. - */ - public SchemaResolver(Digester digester) { - this.digester = digester; - } - - - /** - * Register the specified DTD/Schema URL for the specified public - * identifier. This must be called before the first call to - * parse(). - * - * When adding a schema file (*.xsd), only the name of the file - * will get added. If two schemas with the same name are added, - * only the last one will be stored. - * - * @param publicId Public identifier of the DTD to be resolved - * @param entityURL The URL to use for reading this DTD - */ - public void register(String publicId, String entityURL) { - String key = publicId; - if (publicId.indexOf(schemaExtension) != -1) - key = publicId.substring(publicId.lastIndexOf('/')+1); - entityValidator.put(key, entityURL); - } - - - /** - * Resolve the requested external entity. - * - * @param publicId The public identifier of the entity being referenced - * @param systemId The system identifier of the entity being referenced - * - * @exception SAXException if a parsing exception occurs - * - */ - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException { - - if (publicId != null) { - this.publicId = publicId; - digester.setPublicId(publicId); - } - - // Has this system identifier been registered? - String entityURL = null; - if (publicId != null) { - entityURL = (String) entityValidator.get(publicId); - } - - // Redirect the schema location to a local destination - String key = null; - if (entityURL == null && systemId != null) { - key = systemId.substring(systemId.lastIndexOf('/')+1); - entityURL = (String)entityValidator.get(key); - } - - if (entityURL == null) { - return (null); - } - - try { - return (new InputSource(entityURL)); - } catch (Exception e) { - throw new SAXException(e); - } - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.util; + + +import java.util.HashMap; + +import org.apache.tomcat.util.digester.Digester; +import org.xml.sax.InputSource; +import org.xml.sax.EntityResolver; +import org.xml.sax.SAXException; + +/** + * This class implements a local SAX's EntityResolver. All + * DTDs and schemas used to validate the web.xml file will re-directed + * to a local file stored in the servlet-api.jar and jsp-api.jar. + * + * @author Jean-Francois Arcand + */ +public class SchemaResolver implements EntityResolver { + + /** + * The disgester instance for which this class is the entity resolver. + */ + protected Digester digester; + + + /** + * The URLs of dtds and schemas that have been registered, keyed by the + * public identifier that corresponds. + */ + protected HashMap entityValidator = new HashMap(); + + + /** + * The public identifier of the DTD we are currently parsing under + * (if any). + */ + protected String publicId = null; + + + /** + * Extension to make the difference between DTD and Schema. + */ + protected String schemaExtension = "xsd"; + + + /** + * Create a new EntityResolver that will redirect + * all remote dtds and schema to a locat destination. + * @param digester The digester instance. + */ + public SchemaResolver(Digester digester) { + this.digester = digester; + } + + + /** + * Register the specified DTD/Schema URL for the specified public + * identifier. This must be called before the first call to + * parse(). + * + * When adding a schema file (*.xsd), only the name of the file + * will get added. If two schemas with the same name are added, + * only the last one will be stored. + * + * @param publicId Public identifier of the DTD to be resolved + * @param entityURL The URL to use for reading this DTD + */ + public void register(String publicId, String entityURL) { + String key = publicId; + if (publicId.indexOf(schemaExtension) != -1) + key = publicId.substring(publicId.lastIndexOf('/')+1); + entityValidator.put(key, entityURL); + } + + + /** + * Resolve the requested external entity. + * + * @param publicId The public identifier of the entity being referenced + * @param systemId The system identifier of the entity being referenced + * + * @exception SAXException if a parsing exception occurs + * + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException { + + if (publicId != null) { + this.publicId = publicId; + digester.setPublicId(publicId); + } + + // Has this system identifier been registered? + String entityURL = null; + if (publicId != null) { + entityURL = (String) entityValidator.get(publicId); + } + + // Redirect the schema location to a local destination + String key = null; + if (entityURL == null && systemId != null) { + key = systemId.substring(systemId.lastIndexOf('/')+1); + entityURL = (String)entityValidator.get(key); + } + + if (entityURL == null) { + return (null); + } + + try { + return (new InputSource(entityURL)); + } catch (Exception e) { + throw new SAXException(e); + } + + } + +} diff --git a/java/org/apache/catalina/util/ServerInfo.java b/java/org/apache/catalina/util/ServerInfo.java index b42e5f052..71b4d7e1c 100644 --- a/java/org/apache/catalina/util/ServerInfo.java +++ b/java/org/apache/catalina/util/ServerInfo.java @@ -1,124 +1,124 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.io.InputStream; -import java.util.Properties; - - -/** - * Simple utility module to make it easy to plug in the server identifier - * when integrating Tomcat. - * - * @author Craig R. McClanahan - * @version $Revision: 303276 $ $Date: 2004-09-24 18:41:12 +0200 (ven., 24 sept. 2004) $ - */ - -public class ServerInfo { - - - // ------------------------------------------------------- Static Variables - - - /** - * The server information String with which we identify ourselves. - */ - private static String serverInfo = null; - - /** - * The server built String. - */ - private static String serverBuilt = null; - - /** - * The server's version number String. - */ - private static String serverNumber = null; - - static { - - try { - InputStream is = ServerInfo.class.getResourceAsStream - ("/org/apache/catalina/util/ServerInfo.properties"); - Properties props = new Properties(); - props.load(is); - is.close(); - serverInfo = props.getProperty("server.info"); - serverBuilt = props.getProperty("server.built"); - serverNumber = props.getProperty("server.number"); - } catch (Throwable t) { - ; - } - if (serverInfo == null) - serverInfo = "Apache Tomcat"; - if (serverBuilt == null) - serverBuilt = "unknown"; - if (serverNumber == null) - serverNumber = "5.5.0.0"; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the server identification for this version of Tomcat. - */ - public static String getServerInfo() { - - return (serverInfo); - - } - - /** - * Return the server built time for this version of Tomcat. - */ - public static String getServerBuilt() { - - return (serverBuilt); - - } - - /** - * Return the server's version number. - */ - public static String getServerNumber() { - - return (serverNumber); - - } - - public static void main(String args[]) { - System.out.println("Server version: " + getServerInfo()); - System.out.println("Server built: " + getServerBuilt()); - System.out.println("Server number: " + getServerNumber()); - System.out.println("OS Name: " + - System.getProperty("os.name")); - System.out.println("OS Version: " + - System.getProperty("os.version")); - System.out.println("Architecture: " + - System.getProperty("os.arch")); - System.out.println("JVM Version: " + - System.getProperty("java.runtime.version")); - System.out.println("JVM Vendor: " + - System.getProperty("java.vm.vendor")); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.io.InputStream; +import java.util.Properties; + + +/** + * Simple utility module to make it easy to plug in the server identifier + * when integrating Tomcat. + * + * @author Craig R. McClanahan + * @version $Revision: 303276 $ $Date: 2004-09-24 18:41:12 +0200 (ven., 24 sept. 2004) $ + */ + +public class ServerInfo { + + + // ------------------------------------------------------- Static Variables + + + /** + * The server information String with which we identify ourselves. + */ + private static String serverInfo = null; + + /** + * The server built String. + */ + private static String serverBuilt = null; + + /** + * The server's version number String. + */ + private static String serverNumber = null; + + static { + + try { + InputStream is = ServerInfo.class.getResourceAsStream + ("/org/apache/catalina/util/ServerInfo.properties"); + Properties props = new Properties(); + props.load(is); + is.close(); + serverInfo = props.getProperty("server.info"); + serverBuilt = props.getProperty("server.built"); + serverNumber = props.getProperty("server.number"); + } catch (Throwable t) { + ; + } + if (serverInfo == null) + serverInfo = "Apache Tomcat"; + if (serverBuilt == null) + serverBuilt = "unknown"; + if (serverNumber == null) + serverNumber = "5.5.0.0"; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the server identification for this version of Tomcat. + */ + public static String getServerInfo() { + + return (serverInfo); + + } + + /** + * Return the server built time for this version of Tomcat. + */ + public static String getServerBuilt() { + + return (serverBuilt); + + } + + /** + * Return the server's version number. + */ + public static String getServerNumber() { + + return (serverNumber); + + } + + public static void main(String args[]) { + System.out.println("Server version: " + getServerInfo()); + System.out.println("Server built: " + getServerBuilt()); + System.out.println("Server number: " + getServerNumber()); + System.out.println("OS Name: " + + System.getProperty("os.name")); + System.out.println("OS Version: " + + System.getProperty("os.version")); + System.out.println("Architecture: " + + System.getProperty("os.arch")); + System.out.println("JVM Version: " + + System.getProperty("java.runtime.version")); + System.out.println("JVM Vendor: " + + System.getProperty("java.vm.vendor")); + } + +} diff --git a/java/org/apache/catalina/util/ServerInfo.properties b/java/org/apache/catalina/util/ServerInfo.properties index c7be53c20..924afb11a 100644 --- a/java/org/apache/catalina/util/ServerInfo.properties +++ b/java/org/apache/catalina/util/ServerInfo.properties @@ -1,3 +1,3 @@ -server.info=Apache Tomcat/@VERSION@ -server.number=@VERSION_NUMBER@ +server.info=Apache Tomcat/@VERSION@ +server.number=@VERSION_NUMBER@ server.built=@VERSION_BUILT@ \ No newline at end of file diff --git a/java/org/apache/catalina/util/Strftime.java b/java/org/apache/catalina/util/Strftime.java index 981091dde..fc0579512 100644 --- a/java/org/apache/catalina/util/Strftime.java +++ b/java/org/apache/catalina/util/Strftime.java @@ -1,262 +1,262 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.text.SimpleDateFormat; -import java.util.Properties; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -/** - * Converts dates to strings using the same format specifiers as strftime - * - * Note: This does not mimic strftime perfectly. Certain strftime commands, - * are not supported, and will convert as if they were literals. - * - * Certain complicated commands, like those dealing with the week of the year - * probably don't have exactly the same behavior as strftime. - * - * These limitations are due to use SimpleDateTime. If the conversion was done - * manually, all these limitations could be eliminated. - * - * The interface looks like a subset of DateFormat. Maybe someday someone will make this class - * extend DateFormat. - * - * @author Bip Thelin - * @author Dan Sandberg - * @version $Revision: 303133 $, $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ -public class Strftime { - protected static Properties translate; - protected SimpleDateFormat simpleDateFormat; - - /** - * Initialize our pattern translation - */ - static { - translate = new Properties(); - translate.put("a","EEE"); - translate.put("A","EEEE"); - translate.put("b","MMM"); - translate.put("B","MMMM"); - translate.put("c","EEE MMM d HH:mm:ss yyyy"); - - //There's no way to specify the century in SimpleDateFormat. We don't want to hard-code - //20 since this could be wrong for the pre-2000 files. - //translate.put("C", "20"); - translate.put("d","dd"); - translate.put("D","MM/dd/yy"); - translate.put("e","dd"); //will show as '03' instead of ' 3' - translate.put("F","yyyy-MM-dd"); - translate.put("g","yy"); - translate.put("G","yyyy"); - translate.put("H","HH"); - translate.put("h","MMM"); - translate.put("I","hh"); - translate.put("j","DDD"); - translate.put("k","HH"); //will show as '07' instead of ' 7' - translate.put("l","hh"); //will show as '07' instead of ' 7' - translate.put("m","MM"); - translate.put("M","mm"); - translate.put("n","\n"); - translate.put("p","a"); - translate.put("P","a"); //will show as pm instead of PM - translate.put("r","hh:mm:ss a"); - translate.put("R","HH:mm"); - //There's no way to specify this with SimpleDateFormat - //translate.put("s","seconds since ecpoch"); - translate.put("S","ss"); - translate.put("t","\t"); - translate.put("T","HH:mm:ss"); - //There's no way to specify this with SimpleDateFormat - //translate.put("u","day of week ( 1-7 )"); - - //There's no way to specify this with SimpleDateFormat - //translate.put("U","week in year with first sunday as first day..."); - - translate.put("V","ww"); //I'm not sure this is always exactly the same - - //There's no way to specify this with SimpleDateFormat - //translate.put("W","week in year with first monday as first day..."); - - //There's no way to specify this with SimpleDateFormat - //translate.put("w","E"); - translate.put("X","HH:mm:ss"); - translate.put("x","MM/dd/yy"); - translate.put("y","yy"); - translate.put("Y","yyyy"); - translate.put("Z","z"); - translate.put("z","Z"); - translate.put("%","%"); - } - - - /** - * Create an instance of this date formatting class - * - * @see #Strftime( String, Locale ) - */ - public Strftime( String origFormat ) { - String convertedFormat = convertDateFormat( origFormat ); - simpleDateFormat = new SimpleDateFormat( convertedFormat ); - } - - /** - * Create an instance of this date formatting class - * - * @param origFormat the strftime-style formatting string - * @param locale the locale to use for locale-specific conversions - */ - public Strftime( String origFormat, Locale locale ) { - String convertedFormat = convertDateFormat( origFormat ); - simpleDateFormat = new SimpleDateFormat( convertedFormat, locale ); - } - - /** - * Format the date according to the strftime-style string given in the constructor. - * - * @param date the date to format - * @return the formatted date - */ - public String format( Date date ) { - return simpleDateFormat.format( date ); - } - - /** - * Get the timezone used for formatting conversions - * - * @return the timezone - */ - public TimeZone getTimeZone() { - return simpleDateFormat.getTimeZone(); - } - - /** - * Change the timezone used to format dates - * - * @see SimpleDateFormat#setTimeZone - */ - public void setTimeZone( TimeZone timeZone ) { - simpleDateFormat.setTimeZone( timeZone ); - } - - /** - * Search the provided pattern and get the C standard - * Date/Time formatting rules and convert them to the - * Java equivalent. - * - * @param pattern The pattern to search - * @return The modified pattern - */ - protected String convertDateFormat( String pattern ) { - boolean inside = false; - boolean mark = false; - boolean modifiedCommand = false; - - StringBuffer buf = new StringBuffer(); - - for(int i = 0; i < pattern.length(); i++) { - char c = pattern.charAt(i); - - if ( c=='%' && !mark ) { - mark=true; - } else { - if ( mark ) { - if ( modifiedCommand ) { - //don't do anything--we just wanted to skip a char - modifiedCommand = false; - mark = false; - } else { - inside = translateCommand( buf, pattern, i, inside ); - //It's a modifier code - if ( c=='O' || c=='E' ) { - modifiedCommand = true; - } else { - mark=false; - } - } - } else { - if ( !inside && c != ' ' ) { - //We start a literal, which we need to quote - buf.append("'"); - inside = true; - } - - buf.append(c); - } - } - } - - if ( buf.length() > 0 ) { - char lastChar = buf.charAt( buf.length() - 1 ); - - if( lastChar!='\'' && inside ) { - buf.append('\''); - } - } - return buf.toString(); - } - - protected String quote( String str, boolean insideQuotes ) { - String retVal = str; - if ( !insideQuotes ) { - retVal = '\'' + retVal + '\''; - } - return retVal; - } - - /** - * Try to get the Java Date/Time formatting associated with - * the C standard provided. - * - * @param buf The buffer - * @param pattern The date/time pattern - * @param index The char index - * @param oldInside Flag value - * @return True if new is inside buffer - */ - protected boolean translateCommand( StringBuffer buf, String pattern, int index, boolean oldInside ) { - char firstChar = pattern.charAt( index ); - boolean newInside = oldInside; - - //O and E are modifiers, they mean to present an alternative representation of the next char - //we just handle the next char as if the O or E wasn't there - if ( firstChar == 'O' || firstChar == 'E' ) { - if ( index + 1 < pattern.length() ) { - newInside = translateCommand( buf, pattern, index + 1, oldInside ); - } else { - buf.append( quote("%" + firstChar, oldInside ) ); - } - } else { - String command = translate.getProperty( String.valueOf( firstChar ) ); - - //If we don't find a format, treat it as a literal--That's what apache does - if ( command == null ) { - buf.append( quote( "%" + firstChar, oldInside ) ); - } else { - //If we were inside quotes, close the quotes - if ( oldInside ) { - buf.append( '\'' ); - } - buf.append( command ); - newInside = false; - } - } - return newInside; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.text.SimpleDateFormat; +import java.util.Properties; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +/** + * Converts dates to strings using the same format specifiers as strftime + * + * Note: This does not mimic strftime perfectly. Certain strftime commands, + * are not supported, and will convert as if they were literals. + * + * Certain complicated commands, like those dealing with the week of the year + * probably don't have exactly the same behavior as strftime. + * + * These limitations are due to use SimpleDateTime. If the conversion was done + * manually, all these limitations could be eliminated. + * + * The interface looks like a subset of DateFormat. Maybe someday someone will make this class + * extend DateFormat. + * + * @author Bip Thelin + * @author Dan Sandberg + * @version $Revision: 303133 $, $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ +public class Strftime { + protected static Properties translate; + protected SimpleDateFormat simpleDateFormat; + + /** + * Initialize our pattern translation + */ + static { + translate = new Properties(); + translate.put("a","EEE"); + translate.put("A","EEEE"); + translate.put("b","MMM"); + translate.put("B","MMMM"); + translate.put("c","EEE MMM d HH:mm:ss yyyy"); + + //There's no way to specify the century in SimpleDateFormat. We don't want to hard-code + //20 since this could be wrong for the pre-2000 files. + //translate.put("C", "20"); + translate.put("d","dd"); + translate.put("D","MM/dd/yy"); + translate.put("e","dd"); //will show as '03' instead of ' 3' + translate.put("F","yyyy-MM-dd"); + translate.put("g","yy"); + translate.put("G","yyyy"); + translate.put("H","HH"); + translate.put("h","MMM"); + translate.put("I","hh"); + translate.put("j","DDD"); + translate.put("k","HH"); //will show as '07' instead of ' 7' + translate.put("l","hh"); //will show as '07' instead of ' 7' + translate.put("m","MM"); + translate.put("M","mm"); + translate.put("n","\n"); + translate.put("p","a"); + translate.put("P","a"); //will show as pm instead of PM + translate.put("r","hh:mm:ss a"); + translate.put("R","HH:mm"); + //There's no way to specify this with SimpleDateFormat + //translate.put("s","seconds since ecpoch"); + translate.put("S","ss"); + translate.put("t","\t"); + translate.put("T","HH:mm:ss"); + //There's no way to specify this with SimpleDateFormat + //translate.put("u","day of week ( 1-7 )"); + + //There's no way to specify this with SimpleDateFormat + //translate.put("U","week in year with first sunday as first day..."); + + translate.put("V","ww"); //I'm not sure this is always exactly the same + + //There's no way to specify this with SimpleDateFormat + //translate.put("W","week in year with first monday as first day..."); + + //There's no way to specify this with SimpleDateFormat + //translate.put("w","E"); + translate.put("X","HH:mm:ss"); + translate.put("x","MM/dd/yy"); + translate.put("y","yy"); + translate.put("Y","yyyy"); + translate.put("Z","z"); + translate.put("z","Z"); + translate.put("%","%"); + } + + + /** + * Create an instance of this date formatting class + * + * @see #Strftime( String, Locale ) + */ + public Strftime( String origFormat ) { + String convertedFormat = convertDateFormat( origFormat ); + simpleDateFormat = new SimpleDateFormat( convertedFormat ); + } + + /** + * Create an instance of this date formatting class + * + * @param origFormat the strftime-style formatting string + * @param locale the locale to use for locale-specific conversions + */ + public Strftime( String origFormat, Locale locale ) { + String convertedFormat = convertDateFormat( origFormat ); + simpleDateFormat = new SimpleDateFormat( convertedFormat, locale ); + } + + /** + * Format the date according to the strftime-style string given in the constructor. + * + * @param date the date to format + * @return the formatted date + */ + public String format( Date date ) { + return simpleDateFormat.format( date ); + } + + /** + * Get the timezone used for formatting conversions + * + * @return the timezone + */ + public TimeZone getTimeZone() { + return simpleDateFormat.getTimeZone(); + } + + /** + * Change the timezone used to format dates + * + * @see SimpleDateFormat#setTimeZone + */ + public void setTimeZone( TimeZone timeZone ) { + simpleDateFormat.setTimeZone( timeZone ); + } + + /** + * Search the provided pattern and get the C standard + * Date/Time formatting rules and convert them to the + * Java equivalent. + * + * @param pattern The pattern to search + * @return The modified pattern + */ + protected String convertDateFormat( String pattern ) { + boolean inside = false; + boolean mark = false; + boolean modifiedCommand = false; + + StringBuffer buf = new StringBuffer(); + + for(int i = 0; i < pattern.length(); i++) { + char c = pattern.charAt(i); + + if ( c=='%' && !mark ) { + mark=true; + } else { + if ( mark ) { + if ( modifiedCommand ) { + //don't do anything--we just wanted to skip a char + modifiedCommand = false; + mark = false; + } else { + inside = translateCommand( buf, pattern, i, inside ); + //It's a modifier code + if ( c=='O' || c=='E' ) { + modifiedCommand = true; + } else { + mark=false; + } + } + } else { + if ( !inside && c != ' ' ) { + //We start a literal, which we need to quote + buf.append("'"); + inside = true; + } + + buf.append(c); + } + } + } + + if ( buf.length() > 0 ) { + char lastChar = buf.charAt( buf.length() - 1 ); + + if( lastChar!='\'' && inside ) { + buf.append('\''); + } + } + return buf.toString(); + } + + protected String quote( String str, boolean insideQuotes ) { + String retVal = str; + if ( !insideQuotes ) { + retVal = '\'' + retVal + '\''; + } + return retVal; + } + + /** + * Try to get the Java Date/Time formatting associated with + * the C standard provided. + * + * @param buf The buffer + * @param pattern The date/time pattern + * @param index The char index + * @param oldInside Flag value + * @return True if new is inside buffer + */ + protected boolean translateCommand( StringBuffer buf, String pattern, int index, boolean oldInside ) { + char firstChar = pattern.charAt( index ); + boolean newInside = oldInside; + + //O and E are modifiers, they mean to present an alternative representation of the next char + //we just handle the next char as if the O or E wasn't there + if ( firstChar == 'O' || firstChar == 'E' ) { + if ( index + 1 < pattern.length() ) { + newInside = translateCommand( buf, pattern, index + 1, oldInside ); + } else { + buf.append( quote("%" + firstChar, oldInside ) ); + } + } else { + String command = translate.getProperty( String.valueOf( firstChar ) ); + + //If we don't find a format, treat it as a literal--That's what apache does + if ( command == null ) { + buf.append( quote( "%" + firstChar, oldInside ) ); + } else { + //If we were inside quotes, close the quotes + if ( oldInside ) { + buf.append( '\'' ); + } + buf.append( command ); + newInside = false; + } + } + return newInside; + } +} diff --git a/java/org/apache/catalina/util/StringManager.java b/java/org/apache/catalina/util/StringManager.java index c04f60ece..386381e63 100644 --- a/java/org/apache/catalina/util/StringManager.java +++ b/java/org/apache/catalina/util/StringManager.java @@ -1,252 +1,252 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - -import java.text.MessageFormat; -import java.util.Hashtable; -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; -import java.net.URLClassLoader; - -/** - * An internationalization / localization helper class which reduces - * the bother of handling ResourceBundles and takes care of the - * common cases of message formating which otherwise require the - * creation of Object arrays and such. - * - *

        The StringManager operates on a package basis. One StringManager - * per package can be created and accessed via the getManager method - * call. - * - *

        The StringManager will look for a ResourceBundle named by - * the package name given plus the suffix of "LocalStrings". In - * practice, this means that the localized information will be contained - * in a LocalStrings.properties file located in the package - * directory of the classpath. - * - *

        Please see the documentation for java.util.ResourceBundle for - * more information. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - */ - -public class StringManager { - - /** - * The ResourceBundle for this StringManager. - */ - - private ResourceBundle bundle; - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( StringManager.class ); - - /** - * Creates a new StringManager for a given package. This is a - * private method and all access to it is arbitrated by the - * static getManager method call so that only one StringManager - * per package will be created. - * - * @param packageName Name of package to create StringManager for. - */ - - private StringManager(String packageName) { - String bundleName = packageName + ".LocalStrings"; - try { - bundle = ResourceBundle.getBundle(bundleName); - return; - } catch( MissingResourceException ex ) { - // Try from the current loader ( that's the case for trusted apps ) - ClassLoader cl=Thread.currentThread().getContextClassLoader(); - if( cl != null ) { - try { - bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl); - return; - } catch(MissingResourceException ex2) { - } - } - if( cl==null ) - cl=this.getClass().getClassLoader(); - - if (log.isDebugEnabled()) - log.debug("Can't find resource " + bundleName + - " " + cl); - if( cl instanceof URLClassLoader ) { - if (log.isDebugEnabled()) - log.debug( ((URLClassLoader)cl).getURLs()); - } - } - } - - /** - * Get a string from the underlying resource bundle. - * - * @param key The resource name - */ - public String getString(String key) { - return MessageFormat.format(getStringInternal(key), (Object [])null); - } - - - protected String getStringInternal(String key) { - if (key == null) { - String msg = "key is null"; - - throw new NullPointerException(msg); - } - - String str = null; - - if( bundle==null ) - return key; - try { - str = bundle.getString(key); - } catch (MissingResourceException mre) { - str = "Cannot find message associated with key '" + key + "'"; - } - - return str; - } - - /** - * Get a string from the underlying resource bundle and format - * it with the given set of arguments. - * - * @param key The resource name - * @param args Formatting directives - */ - - public String getString(String key, Object[] args) { - String iString = null; - String value = getStringInternal(key); - - // this check for the runtime exception is some pre 1.1.6 - // VM's don't do an automatic toString() on the passed in - // objects and barf out - - try { - // ensure the arguments are not null so pre 1.2 VM's don't barf - Object nonNullArgs[] = args; - for (int i=0; iThe StringManager operates on a package basis. One StringManager + * per package can be created and accessed via the getManager method + * call. + * + *

        The StringManager will look for a ResourceBundle named by + * the package name given plus the suffix of "LocalStrings". In + * practice, this means that the localized information will be contained + * in a LocalStrings.properties file located in the package + * directory of the classpath. + * + *

        Please see the documentation for java.util.ResourceBundle for + * more information. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + */ + +public class StringManager { + + /** + * The ResourceBundle for this StringManager. + */ + + private ResourceBundle bundle; + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( StringManager.class ); + + /** + * Creates a new StringManager for a given package. This is a + * private method and all access to it is arbitrated by the + * static getManager method call so that only one StringManager + * per package will be created. + * + * @param packageName Name of package to create StringManager for. + */ + + private StringManager(String packageName) { + String bundleName = packageName + ".LocalStrings"; + try { + bundle = ResourceBundle.getBundle(bundleName); + return; + } catch( MissingResourceException ex ) { + // Try from the current loader ( that's the case for trusted apps ) + ClassLoader cl=Thread.currentThread().getContextClassLoader(); + if( cl != null ) { + try { + bundle=ResourceBundle.getBundle(bundleName, Locale.getDefault(), cl); + return; + } catch(MissingResourceException ex2) { + } + } + if( cl==null ) + cl=this.getClass().getClassLoader(); + + if (log.isDebugEnabled()) + log.debug("Can't find resource " + bundleName + + " " + cl); + if( cl instanceof URLClassLoader ) { + if (log.isDebugEnabled()) + log.debug( ((URLClassLoader)cl).getURLs()); + } + } + } + + /** + * Get a string from the underlying resource bundle. + * + * @param key The resource name + */ + public String getString(String key) { + return MessageFormat.format(getStringInternal(key), (Object [])null); + } + + + protected String getStringInternal(String key) { + if (key == null) { + String msg = "key is null"; + + throw new NullPointerException(msg); + } + + String str = null; + + if( bundle==null ) + return key; + try { + str = bundle.getString(key); + } catch (MissingResourceException mre) { + str = "Cannot find message associated with key '" + key + "'"; + } + + return str; + } + + /** + * Get a string from the underlying resource bundle and format + * it with the given set of arguments. + * + * @param key The resource name + * @param args Formatting directives + */ + + public String getString(String key, Object[] args) { + String iString = null; + String value = getStringInternal(key); + + // this check for the runtime exception is some pre 1.1.6 + // VM's don't do an automatic toString() on the passed in + // objects and barf out + + try { + // ensure the arguments are not null so pre 1.2 VM's don't barf + Object nonNullArgs[] = args; + for (int i=0; ifindXxxx() and - * skipXxxx() families of methods to remember significant - * offsets. To retrieve the parsed substrings, call the extract() - * method with the appropriate saved offset values. - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class StringParser { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a string parser with no preset string to be parsed. - */ - public StringParser() { - - this(null); - - } - - - /** - * Construct a string parser that is initialized to parse the specified - * string. - * - * @param string The string to be parsed - */ - public StringParser(String string) { - - super(); - setString(string); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The characters of the current string, as a character array. Stored - * when the string is first specified to speed up access to characters - * being compared during parsing. - */ - private char chars[] = null; - - - /** - * The zero-relative index of the current point at which we are - * positioned within the string being parsed. NOTE: - * the value of this index can be one larger than the index of the last - * character of the string (i.e. equal to the string length) if you - * parse off the end of the string. This value is useful for extracting - * substrings that include the end of the string. - */ - private int index = 0; - - - /** - * The length of the String we are currently parsing. Stored when the - * string is first specified to avoid repeated recalculations. - */ - private int length = 0; - - - /** - * The String we are currently parsing. - */ - private String string = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the zero-relative index of our current parsing position - * within the string being parsed. - */ - public int getIndex() { - - return (this.index); - - } - - - /** - * Return the length of the string we are parsing. - */ - public int getLength() { - - return (this.length); - - } - - - /** - * Return the String we are currently parsing. - */ - public String getString() { - - return (this.string); - - } - - - /** - * Set the String we are currently parsing. The parser state is also reset - * to begin at the start of this string. - * - * @param string The string to be parsed. - */ - public void setString(String string) { - - this.string = string; - if (string != null) { - this.length = string.length(); - chars = this.string.toCharArray(); - } else { - this.length = 0; - chars = new char[0]; - } - reset(); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Advance the current parsing position by one, if we are not already - * past the end of the string. - */ - public void advance() { - - if (index < length) - index++; - - } - - - /** - * Extract and return a substring that starts at the specified position, - * and extends to the end of the string being parsed. If this is not - * possible, a zero-length string is returned. - * - * @param start Starting index, zero relative, inclusive - */ - public String extract(int start) { - - if ((start < 0) || (start >= length)) - return (""); - else - return (string.substring(start)); - - } - - - /** - * Extract and return a substring that starts at the specified position, - * and ends at the character before the specified position. If this is - * not possible, a zero-length string is returned. - * - * @param start Starting index, zero relative, inclusive - * @param end Ending index, zero relative, exclusive - */ - public String extract(int start, int end) { - - if ((start < 0) || (start >= end) || (end > length)) - return (""); - else - return (string.substring(start, end)); - - } - - - /** - * Return the index of the next occurrence of the specified character, - * or the index of the character after the last position of the string - * if no more occurrences of this character are found. The current - * parsing position is updated to the returned value. - * - * @param ch Character to be found - */ - public int findChar(char ch) { - - while ((index < length) && (ch != chars[index])) - index++; - return (index); - - } - - - /** - * Return the index of the next occurrence of a non-whitespace character, - * or the index of the character after the last position of the string - * if no more non-whitespace characters are found. The current - * parsing position is updated to the returned value. - */ - public int findText() { - - while ((index < length) && isWhite(chars[index])) - index++; - return (index); - - } - - - /** - * Return the index of the next occurrence of a whitespace character, - * or the index of the character after the last position of the string - * if no more whitespace characters are found. The current parsing - * position is updated to the returned value. - */ - public int findWhite() { - - while ((index < length) && !isWhite(chars[index])) - index++; - return (index); - - } - - - /** - * Reset the current state of the parser to the beginning of the - * current string being parsed. - */ - public void reset() { - - index = 0; - - } - - - /** - * Advance the current parsing position while it is pointing at the - * specified character, or until it moves past the end of the string. - * Return the final value. - * - * @param ch Character to be skipped - */ - public int skipChar(char ch) { - - while ((index < length) && (ch == chars[index])) - index++; - return (index); - - } - - - /** - * Advance the current parsing position while it is pointing at a - * non-whitespace character, or until it moves past the end of the string. - * Return the final value. - */ - public int skipText() { - - while ((index < length) && !isWhite(chars[index])) - index++; - return (index); - - } - - - /** - * Advance the current parsing position while it is pointing at a - * whitespace character, or until it moves past the end of the string. - * Return the final value. - */ - public int skipWhite() { - - while ((index < length) && isWhite(chars[index])) - index++; - return (index); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Is the specified character considered to be whitespace? - * - * @param ch Character to be checked - */ - protected boolean isWhite(char ch) { - - if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')) - return (true); - else - return (false); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +/** + * Utility class for string parsing that is higher performance than + * StringParser for simple delimited text cases. Parsing is performed + * by setting the string, and then using the findXxxx() and + * skipXxxx() families of methods to remember significant + * offsets. To retrieve the parsed substrings, call the extract() + * method with the appropriate saved offset values. + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class StringParser { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a string parser with no preset string to be parsed. + */ + public StringParser() { + + this(null); + + } + + + /** + * Construct a string parser that is initialized to parse the specified + * string. + * + * @param string The string to be parsed + */ + public StringParser(String string) { + + super(); + setString(string); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The characters of the current string, as a character array. Stored + * when the string is first specified to speed up access to characters + * being compared during parsing. + */ + private char chars[] = null; + + + /** + * The zero-relative index of the current point at which we are + * positioned within the string being parsed. NOTE: + * the value of this index can be one larger than the index of the last + * character of the string (i.e. equal to the string length) if you + * parse off the end of the string. This value is useful for extracting + * substrings that include the end of the string. + */ + private int index = 0; + + + /** + * The length of the String we are currently parsing. Stored when the + * string is first specified to avoid repeated recalculations. + */ + private int length = 0; + + + /** + * The String we are currently parsing. + */ + private String string = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the zero-relative index of our current parsing position + * within the string being parsed. + */ + public int getIndex() { + + return (this.index); + + } + + + /** + * Return the length of the string we are parsing. + */ + public int getLength() { + + return (this.length); + + } + + + /** + * Return the String we are currently parsing. + */ + public String getString() { + + return (this.string); + + } + + + /** + * Set the String we are currently parsing. The parser state is also reset + * to begin at the start of this string. + * + * @param string The string to be parsed. + */ + public void setString(String string) { + + this.string = string; + if (string != null) { + this.length = string.length(); + chars = this.string.toCharArray(); + } else { + this.length = 0; + chars = new char[0]; + } + reset(); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Advance the current parsing position by one, if we are not already + * past the end of the string. + */ + public void advance() { + + if (index < length) + index++; + + } + + + /** + * Extract and return a substring that starts at the specified position, + * and extends to the end of the string being parsed. If this is not + * possible, a zero-length string is returned. + * + * @param start Starting index, zero relative, inclusive + */ + public String extract(int start) { + + if ((start < 0) || (start >= length)) + return (""); + else + return (string.substring(start)); + + } + + + /** + * Extract and return a substring that starts at the specified position, + * and ends at the character before the specified position. If this is + * not possible, a zero-length string is returned. + * + * @param start Starting index, zero relative, inclusive + * @param end Ending index, zero relative, exclusive + */ + public String extract(int start, int end) { + + if ((start < 0) || (start >= end) || (end > length)) + return (""); + else + return (string.substring(start, end)); + + } + + + /** + * Return the index of the next occurrence of the specified character, + * or the index of the character after the last position of the string + * if no more occurrences of this character are found. The current + * parsing position is updated to the returned value. + * + * @param ch Character to be found + */ + public int findChar(char ch) { + + while ((index < length) && (ch != chars[index])) + index++; + return (index); + + } + + + /** + * Return the index of the next occurrence of a non-whitespace character, + * or the index of the character after the last position of the string + * if no more non-whitespace characters are found. The current + * parsing position is updated to the returned value. + */ + public int findText() { + + while ((index < length) && isWhite(chars[index])) + index++; + return (index); + + } + + + /** + * Return the index of the next occurrence of a whitespace character, + * or the index of the character after the last position of the string + * if no more whitespace characters are found. The current parsing + * position is updated to the returned value. + */ + public int findWhite() { + + while ((index < length) && !isWhite(chars[index])) + index++; + return (index); + + } + + + /** + * Reset the current state of the parser to the beginning of the + * current string being parsed. + */ + public void reset() { + + index = 0; + + } + + + /** + * Advance the current parsing position while it is pointing at the + * specified character, or until it moves past the end of the string. + * Return the final value. + * + * @param ch Character to be skipped + */ + public int skipChar(char ch) { + + while ((index < length) && (ch == chars[index])) + index++; + return (index); + + } + + + /** + * Advance the current parsing position while it is pointing at a + * non-whitespace character, or until it moves past the end of the string. + * Return the final value. + */ + public int skipText() { + + while ((index < length) && !isWhite(chars[index])) + index++; + return (index); + + } + + + /** + * Advance the current parsing position while it is pointing at a + * whitespace character, or until it moves past the end of the string. + * Return the final value. + */ + public int skipWhite() { + + while ((index < length) && isWhite(chars[index])) + index++; + return (index); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Is the specified character considered to be whitespace? + * + * @param ch Character to be checked + */ + protected boolean isWhite(char ch) { + + if ((ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n')) + return (true); + else + return (false); + + } + + +} diff --git a/java/org/apache/catalina/util/TomcatCSS.java b/java/org/apache/catalina/util/TomcatCSS.java index 9d54332c2..7d66b19cc 100644 --- a/java/org/apache/catalina/util/TomcatCSS.java +++ b/java/org/apache/catalina/util/TomcatCSS.java @@ -1,36 +1,36 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -public class TomcatCSS { - - public static final String TOMCAT_CSS = - "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " + - "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " + - "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " + - "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " + - "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " + - "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" + - "A {color : black;}" + - "A.name {color : black;}" + - "HR {color : #525D76;}"; - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +public class TomcatCSS { + + public static final String TOMCAT_CSS = + "H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} " + + "H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} " + + "H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} " + + "BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} " + + "B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} " + + "P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}" + + "A {color : black;}" + + "A.name {color : black;}" + + "HR {color : #525D76;}"; + + +} + diff --git a/java/org/apache/catalina/util/URL.java b/java/org/apache/catalina/util/URL.java index 9168adfd1..1cf77ce39 100644 --- a/java/org/apache/catalina/util/URL.java +++ b/java/org/apache/catalina/util/URL.java @@ -1,707 +1,707 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.util; - - -import java.io.Serializable; -import java.net.MalformedURLException; - - -/** - *

        URL is designed to provide public APIs for parsing - * and synthesizing Uniform Resource Locators as similar as possible to the - * APIs of java.net.URL, but without the ability to open a - * stream or connection. One of the consequences of this is that you can - * construct URLs for protocols for which a URLStreamHandler is not - * available (such as an "https" URL when JSSE is not installed).

        - * - *

        WARNING - This class assumes that the string - * representation of a URL conforms to the spec argument - * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax": - *

        - *   <scheme>//<authority><path>?<query>#<fragment>
        - * 

        - * - *

        FIXME - This class really ought to end up in a Commons - * package someplace.

        - * - * @author Craig R. McClanahan - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public final class URL implements Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a URL object from the specified String representation. - * - * @param spec String representation of the URL - * - * @exception MalformedURLException if the string representation - * cannot be parsed successfully - */ - public URL(String spec) throws MalformedURLException { - - this(null, spec); - - } - - - /** - * Create a URL object by parsing a string representation relative - * to a specified context. Based on logic from JDK 1.3.1's - * java.net.URL. - * - * @param context URL against which the relative representation - * is resolved - * @param spec String representation of the URL (usually relative) - * - * @exception MalformedURLException if the string representation - * cannot be parsed successfully - */ - public URL(URL context, String spec) throws MalformedURLException { - - String original = spec; - int i, limit, c; - int start = 0; - String newProtocol = null; - boolean aRef = false; - - try { - - // Eliminate leading and trailing whitespace - limit = spec.length(); - while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { - limit--; - } - while ((start < limit) && (spec.charAt(start) <= ' ')) { - start++; - } - - // If the string representation starts with "url:", skip it - if (spec.regionMatches(true, start, "url:", 0, 4)) { - start += 4; - } - - // Is this a ref relative to the context URL? - if ((start < spec.length()) && (spec.charAt(start) == '#')) { - aRef = true; - } - - // Parse out the new protocol - for (i = start; !aRef && (i < limit) && - ((c = spec.charAt(i)) != '/'); i++) { - if (c == ':') { - String s = spec.substring(start, i).toLowerCase(); - // Assume all protocols are valid - newProtocol = s; - start = i + 1; - break; - } - } - - // Only use our context if the protocols match - protocol = newProtocol; - if ((context != null) && ((newProtocol == null) || - newProtocol.equalsIgnoreCase(context.getProtocol()))) { - // If the context is a hierarchical URL scheme and the spec - // contains a matching scheme then maintain backwards - // compatibility and treat it as if the spec didn't contain - // the scheme; see 5.2.3 of RFC2396 - if ((context.getPath() != null) && - (context.getPath().startsWith("/"))) - newProtocol = null; - if (newProtocol == null) { - protocol = context.getProtocol(); - authority = context.getAuthority(); - userInfo = context.getUserInfo(); - host = context.getHost(); - port = context.getPort(); - file = context.getFile(); - int question = file.lastIndexOf("?"); - if (question < 0) - path = file; - else - path = file.substring(0, question); - } - } - - if (protocol == null) - throw new MalformedURLException("no protocol: " + original); - - // Parse out any ref portion of the spec - i = spec.indexOf('#', start); - if (i >= 0) { - ref = spec.substring(i + 1, limit); - limit = i; - } - - // Parse the remainder of the spec in a protocol-specific fashion - parse(spec, start, limit); - if (context != null) - normalize(); - - - } catch (MalformedURLException e) { - throw e; - } catch (Exception e) { - throw new MalformedURLException(e.toString()); - } - - } - - - - - - /** - * Create a URL object from the specified components. The default port - * number for the specified protocol will be used. - * - * @param protocol Name of the protocol to use - * @param host Name of the host addressed by this protocol - * @param file Filename on the specified host - * - * @exception MalformedURLException is never thrown, but present for - * compatible APIs - */ - public URL(String protocol, String host, String file) - throws MalformedURLException { - - this(protocol, host, -1, file); - - } - - - /** - * Create a URL object from the specified components. Specifying a port - * number of -1 indicates that the URL should use the default port for - * that protocol. Based on logic from JDK 1.3.1's - * java.net.URL. - * - * @param protocol Name of the protocol to use - * @param host Name of the host addressed by this protocol - * @param port Port number, or -1 for the default port for this protocol - * @param file Filename on the specified host - * - * @exception MalformedURLException is never thrown, but present for - * compatible APIs - */ - public URL(String protocol, String host, int port, String file) - throws MalformedURLException { - - this.protocol = protocol; - this.host = host; - this.port = port; - - int hash = file.indexOf('#'); - this.file = hash < 0 ? file : file.substring(0, hash); - this.ref = hash < 0 ? null : file.substring(hash + 1); - int question = file.lastIndexOf('?'); - if (question >= 0) { - query = file.substring(question + 1); - path = file.substring(0, question); - } else - path = file; - - if ((host != null) && (host.length() > 0)) - authority = (port == -1) ? host : host + ":" + port; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The authority part of the URL. - */ - private String authority = null; - - - /** - * The filename part of the URL. - */ - private String file = null; - - - /** - * The host name part of the URL. - */ - private String host = null; - - - /** - * The path part of the URL. - */ - private String path = null; - - - /** - * The port number part of the URL. - */ - private int port = -1; - - - /** - * The protocol name part of the URL. - */ - private String protocol = null; - - - /** - * The query part of the URL. - */ - private String query = null; - - - /** - * The reference part of the URL. - */ - private String ref = null; - - - /** - * The user info part of the URL. - */ - private String userInfo = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Compare two URLs for equality. The result is true if and - * only if the argument is not null, and is a URL object - * that represents the same URL as this object. Two - * URLs are equal if they have the same protocol and - * reference the same host, the same port number on the host, - * and the same file and anchor on the host. - * - * @param obj The URL to compare against - */ - public boolean equals(Object obj) { - - if (obj == null) - return (false); - if (!(obj instanceof URL)) - return (false); - URL other = (URL) obj; - if (!sameFile(other)) - return (false); - return (compare(ref, other.getRef())); - - } - - - /** - * Return the authority part of the URL. - */ - public String getAuthority() { - - return (this.authority); - - } - - - /** - * Return the filename part of the URL. NOTE - For - * compatibility with java.net.URL, this value includes - * the query string if there was one. For just the path portion, - * call getPath() instead. - */ - public String getFile() { - - if (file == null) - return (""); - return (this.file); - - } - - - /** - * Return the host name part of the URL. - */ - public String getHost() { - - return (this.host); - - } - - - /** - * Return the path part of the URL. - */ - public String getPath() { - - if (this.path == null) - return (""); - return (this.path); - - } - - - /** - * Return the port number part of the URL. - */ - public int getPort() { - - return (this.port); - - } - - - /** - * Return the protocol name part of the URL. - */ - public String getProtocol() { - - return (this.protocol); - - } - - - /** - * Return the query part of the URL. - */ - public String getQuery() { - - return (this.query); - - } - - - /** - * Return the reference part of the URL. - */ - public String getRef() { - - return (this.ref); - - } - - - /** - * Return the user info part of the URL. - */ - public String getUserInfo() { - - return (this.userInfo); - - } - - - /** - * Normalize the path (and therefore file) - * portions of this URL. - *

        - * NOTE - This method is not part of the public API - * of java.net.URL, but is provided as a value added - * service of this implementation. - * - * @exception MalformedURLException if a normalization error occurs, - * such as trying to move about the hierarchical root - */ - public void normalize() throws MalformedURLException { - - // Special case for null path - if (path == null) { - if (query != null) - file = "?" + query; - else - file = ""; - return; - } - - // Create a place for the normalized path - String normalized = path; - if (normalized.equals("/.")) { - path = "/"; - if (query != null) - file = path + "?" + query; - else - file = path; - return; - } - - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - if (!normalized.startsWith("/")) - normalized = "/" + normalized; - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - throw new MalformedURLException - ("Invalid relative URL reference"); - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Resolve occurrences of "/." at the end of the normalized path - if (normalized.endsWith("/.")) - normalized = normalized.substring(0, normalized.length() - 1); - - // Resolve occurrences of "/.." at the end of the normalized path - if (normalized.endsWith("/..")) { - int index = normalized.length() - 3; - int index2 = normalized.lastIndexOf('/', index - 1); - if (index2 < 0) - throw new MalformedURLException - ("Invalid relative URL reference"); - normalized = normalized.substring(0, index2 + 1); - } - - // Return the normalized path that we have completed - path = normalized; - if (query != null) - file = path + "?" + query; - else - file = path; - - } - - - /** - * Compare two URLs, excluding the "ref" fields. Returns true - * if this URL and the other argument both refer - * to the same resource. The two URLs might not both contain - * the same anchor. - */ - public boolean sameFile(URL other) { - - if (!compare(protocol, other.getProtocol())) - return (false); - if (!compare(host, other.getHost())) - return (false); - if (port != other.getPort()) - return (false); - if (!compare(file, other.getFile())) - return (false); - return (true); - - } - - - /** - * Return a string representation of this URL. This follow the rules in - * RFC 2396, Section 5.2, Step 7. - */ - public String toExternalForm() { - - StringBuffer sb = new StringBuffer(); - if (protocol != null) { - sb.append(protocol); - sb.append(":"); - } - if (authority != null) { - sb.append("//"); - sb.append(authority); - } - if (path != null) - sb.append(path); - if (query != null) { - sb.append('?'); - sb.append(query); - } - if (ref != null) { - sb.append('#'); - sb.append(ref); - } - return (sb.toString()); - - } - - - /** - * Return a string representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("URL["); - sb.append("authority="); - sb.append(authority); - sb.append(", file="); - sb.append(file); - sb.append(", host="); - sb.append(host); - sb.append(", port="); - sb.append(port); - sb.append(", protocol="); - sb.append(protocol); - sb.append(", query="); - sb.append(query); - sb.append(", ref="); - sb.append(ref); - sb.append(", userInfo="); - sb.append(userInfo); - sb.append("]"); - return (sb.toString()); - - // return (toExternalForm()); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Compare to String values for equality, taking appropriate care if one - * or both of the values are null. - * - * @param first First string - * @param second Second string - */ - private boolean compare(String first, String second) { - - if (first == null) { - if (second == null) - return (true); - else - return (false); - } else { - if (second == null) - return (false); - else - return (first.equals(second)); - } - - } - - - /** - * Parse the specified portion of the string representation of a URL, - * assuming that it has a format similar to that for http. - * - *

        FIXME - This algorithm can undoubtedly be optimized - * for performance. However, that needs to wait until after sufficient - * unit tests are implemented to guarantee correct behavior with no - * regressions.

        - * - * @param spec String representation being parsed - * @param start Starting offset, which will be just after the ':' (if - * there is one) that determined the protocol name - * @param limit Ending position, which will be the position of the '#' - * (if there is one) that delimited the anchor - * - * @exception MalformedURLException if a parsing error occurs - */ - private void parse(String spec, int start, int limit) - throws MalformedURLException { - - // Trim the query string (if any) off the tail end - int question = spec.lastIndexOf('?', limit - 1); - if ((question >= 0) && (question < limit)) { - query = spec.substring(question + 1, limit); - limit = question; - } else { - query = null; - } - - // Parse the authority section - if (spec.indexOf("//", start) == start) { - int pathStart = spec.indexOf("/", start + 2); - if ((pathStart >= 0) && (pathStart < limit)) { - authority = spec.substring(start + 2, pathStart); - start = pathStart; - } else { - authority = spec.substring(start + 2, limit); - start = limit; - } - if (authority.length() > 0) { - int at = authority.indexOf('@'); - if( at >= 0 ) { - userInfo = authority.substring(0,at); - } - int colon = authority.indexOf(':',at+1); - if (colon >= 0) { - try { - port = - Integer.parseInt(authority.substring(colon + 1)); - } catch (NumberFormatException e) { - throw new MalformedURLException(e.toString()); - } - host = authority.substring(at+1, colon); - } else { - host = authority.substring(at+1); - port = -1; - } - } - } - - // Parse the path section - if (spec.indexOf("/", start) == start) { // Absolute path - path = spec.substring(start, limit); - if (query != null) - file = path + "?" + query; - else - file = path; - return; - } - - // Resolve relative path against our context's file - if (path == null) { - if (query != null) - file = "?" + query; - else - file = null; - return; - } - if (!path.startsWith("/")) - throw new MalformedURLException - ("Base path does not start with '/'"); - if (!path.endsWith("/")) - path += "/../"; - path += spec.substring(start, limit); - if (query != null) - file = path + "?" + query; - else - file = path; - return; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.util; + + +import java.io.Serializable; +import java.net.MalformedURLException; + + +/** + *

        URL is designed to provide public APIs for parsing + * and synthesizing Uniform Resource Locators as similar as possible to the + * APIs of java.net.URL, but without the ability to open a + * stream or connection. One of the consequences of this is that you can + * construct URLs for protocols for which a URLStreamHandler is not + * available (such as an "https" URL when JSSE is not installed).

        + * + *

        WARNING - This class assumes that the string + * representation of a URL conforms to the spec argument + * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax": + *

        + *   <scheme>//<authority><path>?<query>#<fragment>
        + * 

        + * + *

        FIXME - This class really ought to end up in a Commons + * package someplace.

        + * + * @author Craig R. McClanahan + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public final class URL implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a URL object from the specified String representation. + * + * @param spec String representation of the URL + * + * @exception MalformedURLException if the string representation + * cannot be parsed successfully + */ + public URL(String spec) throws MalformedURLException { + + this(null, spec); + + } + + + /** + * Create a URL object by parsing a string representation relative + * to a specified context. Based on logic from JDK 1.3.1's + * java.net.URL. + * + * @param context URL against which the relative representation + * is resolved + * @param spec String representation of the URL (usually relative) + * + * @exception MalformedURLException if the string representation + * cannot be parsed successfully + */ + public URL(URL context, String spec) throws MalformedURLException { + + String original = spec; + int i, limit, c; + int start = 0; + String newProtocol = null; + boolean aRef = false; + + try { + + // Eliminate leading and trailing whitespace + limit = spec.length(); + while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { + limit--; + } + while ((start < limit) && (spec.charAt(start) <= ' ')) { + start++; + } + + // If the string representation starts with "url:", skip it + if (spec.regionMatches(true, start, "url:", 0, 4)) { + start += 4; + } + + // Is this a ref relative to the context URL? + if ((start < spec.length()) && (spec.charAt(start) == '#')) { + aRef = true; + } + + // Parse out the new protocol + for (i = start; !aRef && (i < limit) && + ((c = spec.charAt(i)) != '/'); i++) { + if (c == ':') { + String s = spec.substring(start, i).toLowerCase(); + // Assume all protocols are valid + newProtocol = s; + start = i + 1; + break; + } + } + + // Only use our context if the protocols match + protocol = newProtocol; + if ((context != null) && ((newProtocol == null) || + newProtocol.equalsIgnoreCase(context.getProtocol()))) { + // If the context is a hierarchical URL scheme and the spec + // contains a matching scheme then maintain backwards + // compatibility and treat it as if the spec didn't contain + // the scheme; see 5.2.3 of RFC2396 + if ((context.getPath() != null) && + (context.getPath().startsWith("/"))) + newProtocol = null; + if (newProtocol == null) { + protocol = context.getProtocol(); + authority = context.getAuthority(); + userInfo = context.getUserInfo(); + host = context.getHost(); + port = context.getPort(); + file = context.getFile(); + int question = file.lastIndexOf("?"); + if (question < 0) + path = file; + else + path = file.substring(0, question); + } + } + + if (protocol == null) + throw new MalformedURLException("no protocol: " + original); + + // Parse out any ref portion of the spec + i = spec.indexOf('#', start); + if (i >= 0) { + ref = spec.substring(i + 1, limit); + limit = i; + } + + // Parse the remainder of the spec in a protocol-specific fashion + parse(spec, start, limit); + if (context != null) + normalize(); + + + } catch (MalformedURLException e) { + throw e; + } catch (Exception e) { + throw new MalformedURLException(e.toString()); + } + + } + + + + + + /** + * Create a URL object from the specified components. The default port + * number for the specified protocol will be used. + * + * @param protocol Name of the protocol to use + * @param host Name of the host addressed by this protocol + * @param file Filename on the specified host + * + * @exception MalformedURLException is never thrown, but present for + * compatible APIs + */ + public URL(String protocol, String host, String file) + throws MalformedURLException { + + this(protocol, host, -1, file); + + } + + + /** + * Create a URL object from the specified components. Specifying a port + * number of -1 indicates that the URL should use the default port for + * that protocol. Based on logic from JDK 1.3.1's + * java.net.URL. + * + * @param protocol Name of the protocol to use + * @param host Name of the host addressed by this protocol + * @param port Port number, or -1 for the default port for this protocol + * @param file Filename on the specified host + * + * @exception MalformedURLException is never thrown, but present for + * compatible APIs + */ + public URL(String protocol, String host, int port, String file) + throws MalformedURLException { + + this.protocol = protocol; + this.host = host; + this.port = port; + + int hash = file.indexOf('#'); + this.file = hash < 0 ? file : file.substring(0, hash); + this.ref = hash < 0 ? null : file.substring(hash + 1); + int question = file.lastIndexOf('?'); + if (question >= 0) { + query = file.substring(question + 1); + path = file.substring(0, question); + } else + path = file; + + if ((host != null) && (host.length() > 0)) + authority = (port == -1) ? host : host + ":" + port; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The authority part of the URL. + */ + private String authority = null; + + + /** + * The filename part of the URL. + */ + private String file = null; + + + /** + * The host name part of the URL. + */ + private String host = null; + + + /** + * The path part of the URL. + */ + private String path = null; + + + /** + * The port number part of the URL. + */ + private int port = -1; + + + /** + * The protocol name part of the URL. + */ + private String protocol = null; + + + /** + * The query part of the URL. + */ + private String query = null; + + + /** + * The reference part of the URL. + */ + private String ref = null; + + + /** + * The user info part of the URL. + */ + private String userInfo = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Compare two URLs for equality. The result is true if and + * only if the argument is not null, and is a URL object + * that represents the same URL as this object. Two + * URLs are equal if they have the same protocol and + * reference the same host, the same port number on the host, + * and the same file and anchor on the host. + * + * @param obj The URL to compare against + */ + public boolean equals(Object obj) { + + if (obj == null) + return (false); + if (!(obj instanceof URL)) + return (false); + URL other = (URL) obj; + if (!sameFile(other)) + return (false); + return (compare(ref, other.getRef())); + + } + + + /** + * Return the authority part of the URL. + */ + public String getAuthority() { + + return (this.authority); + + } + + + /** + * Return the filename part of the URL. NOTE - For + * compatibility with java.net.URL, this value includes + * the query string if there was one. For just the path portion, + * call getPath() instead. + */ + public String getFile() { + + if (file == null) + return (""); + return (this.file); + + } + + + /** + * Return the host name part of the URL. + */ + public String getHost() { + + return (this.host); + + } + + + /** + * Return the path part of the URL. + */ + public String getPath() { + + if (this.path == null) + return (""); + return (this.path); + + } + + + /** + * Return the port number part of the URL. + */ + public int getPort() { + + return (this.port); + + } + + + /** + * Return the protocol name part of the URL. + */ + public String getProtocol() { + + return (this.protocol); + + } + + + /** + * Return the query part of the URL. + */ + public String getQuery() { + + return (this.query); + + } + + + /** + * Return the reference part of the URL. + */ + public String getRef() { + + return (this.ref); + + } + + + /** + * Return the user info part of the URL. + */ + public String getUserInfo() { + + return (this.userInfo); + + } + + + /** + * Normalize the path (and therefore file) + * portions of this URL. + *

        + * NOTE - This method is not part of the public API + * of java.net.URL, but is provided as a value added + * service of this implementation. + * + * @exception MalformedURLException if a normalization error occurs, + * such as trying to move about the hierarchical root + */ + public void normalize() throws MalformedURLException { + + // Special case for null path + if (path == null) { + if (query != null) + file = "?" + query; + else + file = ""; + return; + } + + // Create a place for the normalized path + String normalized = path; + if (normalized.equals("/.")) { + path = "/"; + if (query != null) + file = path + "?" + query; + else + file = path; + return; + } + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + throw new MalformedURLException + ("Invalid relative URL reference"); + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Resolve occurrences of "/." at the end of the normalized path + if (normalized.endsWith("/.")) + normalized = normalized.substring(0, normalized.length() - 1); + + // Resolve occurrences of "/.." at the end of the normalized path + if (normalized.endsWith("/..")) { + int index = normalized.length() - 3; + int index2 = normalized.lastIndexOf('/', index - 1); + if (index2 < 0) + throw new MalformedURLException + ("Invalid relative URL reference"); + normalized = normalized.substring(0, index2 + 1); + } + + // Return the normalized path that we have completed + path = normalized; + if (query != null) + file = path + "?" + query; + else + file = path; + + } + + + /** + * Compare two URLs, excluding the "ref" fields. Returns true + * if this URL and the other argument both refer + * to the same resource. The two URLs might not both contain + * the same anchor. + */ + public boolean sameFile(URL other) { + + if (!compare(protocol, other.getProtocol())) + return (false); + if (!compare(host, other.getHost())) + return (false); + if (port != other.getPort()) + return (false); + if (!compare(file, other.getFile())) + return (false); + return (true); + + } + + + /** + * Return a string representation of this URL. This follow the rules in + * RFC 2396, Section 5.2, Step 7. + */ + public String toExternalForm() { + + StringBuffer sb = new StringBuffer(); + if (protocol != null) { + sb.append(protocol); + sb.append(":"); + } + if (authority != null) { + sb.append("//"); + sb.append(authority); + } + if (path != null) + sb.append(path); + if (query != null) { + sb.append('?'); + sb.append(query); + } + if (ref != null) { + sb.append('#'); + sb.append(ref); + } + return (sb.toString()); + + } + + + /** + * Return a string representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("URL["); + sb.append("authority="); + sb.append(authority); + sb.append(", file="); + sb.append(file); + sb.append(", host="); + sb.append(host); + sb.append(", port="); + sb.append(port); + sb.append(", protocol="); + sb.append(protocol); + sb.append(", query="); + sb.append(query); + sb.append(", ref="); + sb.append(ref); + sb.append(", userInfo="); + sb.append(userInfo); + sb.append("]"); + return (sb.toString()); + + // return (toExternalForm()); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Compare to String values for equality, taking appropriate care if one + * or both of the values are null. + * + * @param first First string + * @param second Second string + */ + private boolean compare(String first, String second) { + + if (first == null) { + if (second == null) + return (true); + else + return (false); + } else { + if (second == null) + return (false); + else + return (first.equals(second)); + } + + } + + + /** + * Parse the specified portion of the string representation of a URL, + * assuming that it has a format similar to that for http. + * + *

        FIXME - This algorithm can undoubtedly be optimized + * for performance. However, that needs to wait until after sufficient + * unit tests are implemented to guarantee correct behavior with no + * regressions.

        + * + * @param spec String representation being parsed + * @param start Starting offset, which will be just after the ':' (if + * there is one) that determined the protocol name + * @param limit Ending position, which will be the position of the '#' + * (if there is one) that delimited the anchor + * + * @exception MalformedURLException if a parsing error occurs + */ + private void parse(String spec, int start, int limit) + throws MalformedURLException { + + // Trim the query string (if any) off the tail end + int question = spec.lastIndexOf('?', limit - 1); + if ((question >= 0) && (question < limit)) { + query = spec.substring(question + 1, limit); + limit = question; + } else { + query = null; + } + + // Parse the authority section + if (spec.indexOf("//", start) == start) { + int pathStart = spec.indexOf("/", start + 2); + if ((pathStart >= 0) && (pathStart < limit)) { + authority = spec.substring(start + 2, pathStart); + start = pathStart; + } else { + authority = spec.substring(start + 2, limit); + start = limit; + } + if (authority.length() > 0) { + int at = authority.indexOf('@'); + if( at >= 0 ) { + userInfo = authority.substring(0,at); + } + int colon = authority.indexOf(':',at+1); + if (colon >= 0) { + try { + port = + Integer.parseInt(authority.substring(colon + 1)); + } catch (NumberFormatException e) { + throw new MalformedURLException(e.toString()); + } + host = authority.substring(at+1, colon); + } else { + host = authority.substring(at+1); + port = -1; + } + } + } + + // Parse the path section + if (spec.indexOf("/", start) == start) { // Absolute path + path = spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + } + + // Resolve relative path against our context's file + if (path == null) { + if (query != null) + file = "?" + query; + else + file = null; + return; + } + if (!path.startsWith("/")) + throw new MalformedURLException + ("Base path does not start with '/'"); + if (!path.endsWith("/")) + path += "/../"; + path += spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + + } + + +} diff --git a/java/org/apache/catalina/util/URLEncoder.java b/java/org/apache/catalina/util/URLEncoder.java index c19d7490b..8d23dbf11 100644 --- a/java/org/apache/catalina/util/URLEncoder.java +++ b/java/org/apache/catalina/util/URLEncoder.java @@ -1,100 +1,100 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.catalina.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.util.BitSet; - -/** - * - * This class is very similar to the java.net.URLEncoder class. - * - * Unfortunately, with java.net.URLEncoder there is no way to specify to the - * java.net.URLEncoder which characters should NOT be encoded. - * - * This code was moved from DefaultServlet.java - * - * @author Craig R. McClanahan - * @author Remy Maucherat - */ -public class URLEncoder { - protected static final char[] hexadecimal = - {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', - 'A', 'B', 'C', 'D', 'E', 'F'}; - - //Array containing the safe characters set. - protected BitSet safeCharacters = new BitSet(256); - - public URLEncoder() { - for (char i = 'a'; i <= 'z'; i++) { - addSafeCharacter(i); - } - for (char i = 'A'; i <= 'Z'; i++) { - addSafeCharacter(i); - } - for (char i = '0'; i <= '9'; i++) { - addSafeCharacter(i); - } - } - - public void addSafeCharacter( char c ) { - safeCharacters.set( c ); - } - - public String encode( String path ) { - int maxBytesPerChar = 10; - int caseDiff = ('a' - 'A'); - StringBuffer rewrittenPath = new StringBuffer(path.length()); - ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar); - OutputStreamWriter writer = null; - try { - writer = new OutputStreamWriter(buf, "UTF8"); - } catch (Exception e) { - e.printStackTrace(); - writer = new OutputStreamWriter(buf); - } - - for (int i = 0; i < path.length(); i++) { - int c = (int) path.charAt(i); - if (safeCharacters.get(c)) { - rewrittenPath.append((char)c); - } else { - // convert to external encoding before hex conversion - try { - writer.write((char)c); - writer.flush(); - } catch(IOException e) { - buf.reset(); - continue; - } - byte[] ba = buf.toByteArray(); - for (int j = 0; j < ba.length; j++) { - // Converting each byte in the buffer - byte toEncode = ba[j]; - rewrittenPath.append('%'); - int low = (int) (toEncode & 0x0f); - int high = (int) ((toEncode & 0xf0) >> 4); - rewrittenPath.append(hexadecimal[high]); - rewrittenPath.append(hexadecimal[low]); - } - buf.reset(); - } - } - return rewrittenPath.toString(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.util.BitSet; + +/** + * + * This class is very similar to the java.net.URLEncoder class. + * + * Unfortunately, with java.net.URLEncoder there is no way to specify to the + * java.net.URLEncoder which characters should NOT be encoded. + * + * This code was moved from DefaultServlet.java + * + * @author Craig R. McClanahan + * @author Remy Maucherat + */ +public class URLEncoder { + protected static final char[] hexadecimal = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'A', 'B', 'C', 'D', 'E', 'F'}; + + //Array containing the safe characters set. + protected BitSet safeCharacters = new BitSet(256); + + public URLEncoder() { + for (char i = 'a'; i <= 'z'; i++) { + addSafeCharacter(i); + } + for (char i = 'A'; i <= 'Z'; i++) { + addSafeCharacter(i); + } + for (char i = '0'; i <= '9'; i++) { + addSafeCharacter(i); + } + } + + public void addSafeCharacter( char c ) { + safeCharacters.set( c ); + } + + public String encode( String path ) { + int maxBytesPerChar = 10; + int caseDiff = ('a' - 'A'); + StringBuffer rewrittenPath = new StringBuffer(path.length()); + ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar); + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter(buf, "UTF8"); + } catch (Exception e) { + e.printStackTrace(); + writer = new OutputStreamWriter(buf); + } + + for (int i = 0; i < path.length(); i++) { + int c = (int) path.charAt(i); + if (safeCharacters.get(c)) { + rewrittenPath.append((char)c); + } else { + // convert to external encoding before hex conversion + try { + writer.write((char)c); + writer.flush(); + } catch(IOException e) { + buf.reset(); + continue; + } + byte[] ba = buf.toByteArray(); + for (int j = 0; j < ba.length; j++) { + // Converting each byte in the buffer + byte toEncode = ba[j]; + rewrittenPath.append('%'); + int low = (int) (toEncode & 0x0f); + int high = (int) ((toEncode & 0xf0) >> 4); + rewrittenPath.append(hexadecimal[high]); + rewrittenPath.append(hexadecimal[low]); + } + buf.reset(); + } + } + return rewrittenPath.toString(); + } +} diff --git a/java/org/apache/catalina/util/XMLWriter.java b/java/org/apache/catalina/util/XMLWriter.java index eda1808a9..f1a71a6af 100644 --- a/java/org/apache/catalina/util/XMLWriter.java +++ b/java/org/apache/catalina/util/XMLWriter.java @@ -1,243 +1,243 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.catalina.util; - -import java.io.IOException; -import java.io.Writer; - -/** - * XMLWriter helper class. - * - * @author Remy Maucherat - */ -public class XMLWriter { - - - // -------------------------------------------------------------- Constants - - - /** - * Opening tag. - */ - public static final int OPENING = 0; - - - /** - * Closing tag. - */ - public static final int CLOSING = 1; - - - /** - * Element with no content. - */ - public static final int NO_CONTENT = 2; - - - // ----------------------------------------------------- Instance Variables - - - /** - * Buffer. - */ - protected StringBuffer buffer = new StringBuffer(); - - - /** - * Writer. - */ - protected Writer writer = null; - - - // ----------------------------------------------------------- Constructors - - - /** - * Constructor. - */ - public XMLWriter() { - } - - - /** - * Constructor. - */ - public XMLWriter(Writer writer) { - this.writer = writer; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieve generated XML. - * - * @return String containing the generated XML - */ - public String toString() { - return buffer.toString(); - } - - - /** - * Write property to the XML. - * - * @param namespace Namespace - * @param namespaceInfo Namespace info - * @param name Property name - * @param value Property value - */ - public void writeProperty(String namespace, String namespaceInfo, - String name, String value) { - writeElement(namespace, namespaceInfo, name, OPENING); - buffer.append(value); - writeElement(namespace, namespaceInfo, name, CLOSING); - - } - - - /** - * Write property to the XML. - * - * @param namespace Namespace - * @param name Property name - * @param value Property value - */ - public void writeProperty(String namespace, String name, String value) { - writeElement(namespace, name, OPENING); - buffer.append(value); - writeElement(namespace, name, CLOSING); - } - - - /** - * Write property to the XML. - * - * @param namespace Namespace - * @param name Property name - */ - public void writeProperty(String namespace, String name) { - writeElement(namespace, name, NO_CONTENT); - } - - - /** - * Write an element. - * - * @param name Element name - * @param namespace Namespace abbreviation - * @param type Element type - */ - public void writeElement(String namespace, String name, int type) { - writeElement(namespace, null, name, type); - } - - - /** - * Write an element. - * - * @param namespace Namespace abbreviation - * @param namespaceInfo Namespace info - * @param name Element name - * @param type Element type - */ - public void writeElement(String namespace, String namespaceInfo, - String name, int type) { - if ((namespace != null) && (namespace.length() > 0)) { - switch (type) { - case OPENING: - if (namespaceInfo != null) { - buffer.append("<" + namespace + ":" + name + " xmlns:" - + namespace + "=\"" - + namespaceInfo + "\">"); - } else { - buffer.append("<" + namespace + ":" + name + ">"); - } - break; - case CLOSING: - buffer.append("\n"); - break; - case NO_CONTENT: - default: - if (namespaceInfo != null) { - buffer.append("<" + namespace + ":" + name + " xmlns:" - + namespace + "=\"" - + namespaceInfo + "\"/>"); - } else { - buffer.append("<" + namespace + ":" + name + "/>"); - } - break; - } - } else { - switch (type) { - case OPENING: - buffer.append("<" + name + ">"); - break; - case CLOSING: - buffer.append("\n"); - break; - case NO_CONTENT: - default: - buffer.append("<" + name + "/>"); - break; - } - } - } - - - /** - * Write text. - * - * @param text Text to append - */ - public void writeText(String text) { - buffer.append(text); - } - - - /** - * Write data. - * - * @param data Data to append - */ - public void writeData(String data) { - buffer.append(""); - } - - - /** - * Write XML Header. - */ - public void writeXMLHeader() { - buffer.append("\n"); - } - - - /** - * Send data and reinitializes buffer. - */ - public void sendData() - throws IOException { - if (writer != null) { - writer.write(buffer.toString()); - buffer = new StringBuffer(); - } - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.catalina.util; + +import java.io.IOException; +import java.io.Writer; + +/** + * XMLWriter helper class. + * + * @author Remy Maucherat + */ +public class XMLWriter { + + + // -------------------------------------------------------------- Constants + + + /** + * Opening tag. + */ + public static final int OPENING = 0; + + + /** + * Closing tag. + */ + public static final int CLOSING = 1; + + + /** + * Element with no content. + */ + public static final int NO_CONTENT = 2; + + + // ----------------------------------------------------- Instance Variables + + + /** + * Buffer. + */ + protected StringBuffer buffer = new StringBuffer(); + + + /** + * Writer. + */ + protected Writer writer = null; + + + // ----------------------------------------------------------- Constructors + + + /** + * Constructor. + */ + public XMLWriter() { + } + + + /** + * Constructor. + */ + public XMLWriter(Writer writer) { + this.writer = writer; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieve generated XML. + * + * @return String containing the generated XML + */ + public String toString() { + return buffer.toString(); + } + + + /** + * Write property to the XML. + * + * @param namespace Namespace + * @param namespaceInfo Namespace info + * @param name Property name + * @param value Property value + */ + public void writeProperty(String namespace, String namespaceInfo, + String name, String value) { + writeElement(namespace, namespaceInfo, name, OPENING); + buffer.append(value); + writeElement(namespace, namespaceInfo, name, CLOSING); + + } + + + /** + * Write property to the XML. + * + * @param namespace Namespace + * @param name Property name + * @param value Property value + */ + public void writeProperty(String namespace, String name, String value) { + writeElement(namespace, name, OPENING); + buffer.append(value); + writeElement(namespace, name, CLOSING); + } + + + /** + * Write property to the XML. + * + * @param namespace Namespace + * @param name Property name + */ + public void writeProperty(String namespace, String name) { + writeElement(namespace, name, NO_CONTENT); + } + + + /** + * Write an element. + * + * @param name Element name + * @param namespace Namespace abbreviation + * @param type Element type + */ + public void writeElement(String namespace, String name, int type) { + writeElement(namespace, null, name, type); + } + + + /** + * Write an element. + * + * @param namespace Namespace abbreviation + * @param namespaceInfo Namespace info + * @param name Element name + * @param type Element type + */ + public void writeElement(String namespace, String namespaceInfo, + String name, int type) { + if ((namespace != null) && (namespace.length() > 0)) { + switch (type) { + case OPENING: + if (namespaceInfo != null) { + buffer.append("<" + namespace + ":" + name + " xmlns:" + + namespace + "=\"" + + namespaceInfo + "\">"); + } else { + buffer.append("<" + namespace + ":" + name + ">"); + } + break; + case CLOSING: + buffer.append("\n"); + break; + case NO_CONTENT: + default: + if (namespaceInfo != null) { + buffer.append("<" + namespace + ":" + name + " xmlns:" + + namespace + "=\"" + + namespaceInfo + "\"/>"); + } else { + buffer.append("<" + namespace + ":" + name + "/>"); + } + break; + } + } else { + switch (type) { + case OPENING: + buffer.append("<" + name + ">"); + break; + case CLOSING: + buffer.append("\n"); + break; + case NO_CONTENT: + default: + buffer.append("<" + name + "/>"); + break; + } + } + } + + + /** + * Write text. + * + * @param text Text to append + */ + public void writeText(String text) { + buffer.append(text); + } + + + /** + * Write data. + * + * @param data Data to append + */ + public void writeData(String data) { + buffer.append(""); + } + + + /** + * Write XML Header. + */ + public void writeXMLHeader() { + buffer.append("\n"); + } + + + /** + * Send data and reinitializes buffer. + */ + public void sendData() + throws IOException { + if (writer != null) { + writer.write(buffer.toString()); + buffer = new StringBuffer(); + } + } + + +} diff --git a/java/org/apache/catalina/valves/AccessLogValve.java b/java/org/apache/catalina/valves/AccessLogValve.java index 1e2b19aba..c0d80959b 100644 --- a/java/org/apache/catalina/valves/AccessLogValve.java +++ b/java/org/apache/catalina/valves/AccessLogValve.java @@ -1,1131 +1,1131 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; - - -/** - *

        Implementation of the Valve interface that generates a web server - * access log with the detailed line contents matching a configurable pattern. - * The syntax of the available patterns is similar to that supported by the - * Apache mod_log_config module. As an additional feature, - * automatic rollover of log files when the date changes is also supported.

        - * - *

        Patterns for the logged message may include constant text or any of the - * following replacement strings, for which the corresponding information - * from the specified Response is substituted:

        - *
          - *
        • %a - Remote IP address - *
        • %A - Local IP address - *
        • %b - Bytes sent, excluding HTTP headers, or '-' if no bytes - * were sent - *
        • %B - Bytes sent, excluding HTTP headers - *
        • %h - Remote host name - *
        • %H - Request protocol - *
        • %l - Remote logical username from identd (always returns '-') - *
        • %m - Request method - *
        • %p - Local port - *
        • %q - Query string (prepended with a '?' if it exists, otherwise - * an empty string - *
        • %r - First line of the request - *
        • %s - HTTP status code of the response - *
        • %S - User session ID - *
        • %t - Date and time, in Common Log Format format - *
        • %u - Remote user that was authenticated - *
        • %U - Requested URL path - *
        • %v - Local server name - *
        • %D - Time taken to process the request, in millis - *
        • %T - Time taken to process the request, in seconds - *
        - *

        In addition, the caller can specify one of the following aliases for - * commonly utilized patterns:

        - *
          - *
        • common - %h %l %u %t "%r" %s %b - *
        • combined - - * %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" - *
        - * - *

        - * There is also support to write information from the cookie, incoming - * header, the Session or something else in the ServletRequest.
        - * It is modeled after the apache syntax: - *

          - *
        • %{xxx}i for incoming headers - *
        • %{xxx}c for a specific cookie - *
        • %{xxx}r xxx is an attribute in the ServletRequest - *
        • %{xxx}s xxx is an attribute in the HttpSession - *
        - *

        - * - *

        - * Conditional logging is also supported. This can be done with the - * condition property. - * If the value returned from ServletRequest.getAttribute(condition) - * yields a non-null value. The logging will be skipped. - *

        - * - * @author Craig R. McClanahan - * @author Jason Brittain - * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public class AccessLogValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default property values. - */ - public AccessLogValve() { - - super(); - setPattern("common"); - - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The as-of date for the currently open log file, or a zero-length - * string if there is no open log file. - */ - private String dateStamp = ""; - - - /** - * The directory in which log files are created. - */ - private String directory = "logs"; - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.valves.AccessLogValve/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The set of month abbreviations for log messages. - */ - protected static final String months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - - /** - * If the current log pattern is the same as the common access log - * format pattern, then we'll set this variable to true and log in - * a more optimal and hard-coded way. - */ - private boolean common = false; - - - /** - * For the combined format (common, plus useragent and referer), we do - * the same - */ - private boolean combined = false; - - - /** - * The pattern used to format our access log lines. - */ - private String pattern = null; - - - /** - * The prefix that is added to log file filenames. - */ - private String prefix = "access_log."; - - - /** - * Should we rotate our log file? Default is true (like old behavior) - */ - private boolean rotatable = true; - - - /** - * The string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = ""; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = null; - - - /** - * A date formatter to format a Date into a date in the format - * "yyyy-MM-dd". - */ - private SimpleDateFormat dateFormatter = null; - - - /** - * A date formatter to format Dates into a day string in the format - * "dd". - */ - private SimpleDateFormat dayFormatter = null; - - - /** - * A date formatter to format a Date into a month string in the format - * "MM". - */ - private SimpleDateFormat monthFormatter = null; - - - /** - * Time taken formatter for 3 decimal places. - */ - private DecimalFormat timeTakenFormatter = null; - - - /** - * A date formatter to format a Date into a year string in the format - * "yyyy". - */ - private SimpleDateFormat yearFormatter = null; - - - /** - * A date formatter to format a Date into a time in the format - * "kk:mm:ss" (kk is a 24-hour representation of the hour). - */ - private SimpleDateFormat timeFormatter = null; - - - /** - * The system timezone. - */ - private TimeZone timezone = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is not in operation. - */ - private String timeZoneNoDST = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is in operation. - */ - private String timeZoneDST = null; - - - /** - * The system time when we last updated the Date that this valve - * uses for log lines. - */ - private Date currentDate = null; - - - /** - * When formatting log lines, we often use strings like this one (" "). - */ - private String space = " "; - - - /** - * Resolve hosts. - */ - private boolean resolveHosts = false; - - - /** - * Instant when the log daily rotation was last checked. - */ - private long rotationLastChecked = 0L; - - - /** - * Are we doing conditional logging. default false. - */ - private String condition = null; - - - /** - * Date format to place in log file name. Use at your own risk! - */ - private String fileDateFormat = null; - - // ------------------------------------------------------------- Properties - - - /** - * Return the directory in which we create log files. - */ - public String getDirectory() { - - return (directory); - - } - - - /** - * Set the directory in which we create log files. - * - * @param directory The new log file directory - */ - public void setDirectory(String directory) { - - this.directory = directory; - - } - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the format pattern. - */ - public String getPattern() { - - return (this.pattern); - - } - - - /** - * Set the format pattern, first translating any recognized alias. - * - * @param pattern The new pattern - */ - public void setPattern(String pattern) { - - if (pattern == null) - pattern = ""; - if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) - pattern = Constants.AccessLog.COMMON_PATTERN; - if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) - pattern = Constants.AccessLog.COMBINED_PATTERN; - this.pattern = pattern; - - if (this.pattern.equals(Constants.AccessLog.COMMON_PATTERN)) - common = true; - else - common = false; - - if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) - combined = true; - else - combined = false; - - } - - - /** - * Return the log file prefix. - */ - public String getPrefix() { - - return (prefix); - - } - - - /** - * Set the log file prefix. - * - * @param prefix The new log file prefix - */ - public void setPrefix(String prefix) { - - this.prefix = prefix; - - } - - - /** - * Should we rotate the logs - */ - public boolean isRotatable() { - - return rotatable; - - } - - - /** - * Set the value is we should we rotate the logs - * - * @param rotatable true is we should rotate. - */ - public void setRotatable(boolean rotatable) { - - this.rotatable = rotatable; - - } - - - /** - * Return the log file suffix. - */ - public String getSuffix() { - - return (suffix); - - } - - - /** - * Set the log file suffix. - * - * @param suffix The new log file suffix - */ - public void setSuffix(String suffix) { - - this.suffix = suffix; - - } - - - /** - * Set the resolve hosts flag. - * - * @param resolveHosts The new resolve hosts value - */ - public void setResolveHosts(boolean resolveHosts) { - - this.resolveHosts = resolveHosts; - - } - - - /** - * Get the value of the resolve hosts flag. - */ - public boolean isResolveHosts() { - - return resolveHosts; - - } - - - /** - * Return whether the attribute name to look for when - * performing conditional loggging. If null, every - * request is logged. - */ - public String getCondition() { - - return condition; - - } - - - /** - * Set the ServletRequest.attribute to look for to perform - * conditional logging. Set to null to log everything. - * - * @param condition Set to null to log everything - */ - public void setCondition(String condition) { - - this.condition = condition; - - } - - /** - * Return the date format date based log rotation. - */ - public String getFileDateFormat() { - return fileDateFormat; - } - - - /** - * Set the date format date based log rotation. - */ - public void setFileDateFormat(String fileDateFormat) { - this.fileDateFormat = fileDateFormat; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Log a message summarizing the specified request and response, according - * to the format specified by the pattern property. - * - * @param request Request being processed - * @param response Response being processed - * - * @exception IOException if an input/output error has occurred - * @exception ServletException if a servlet error has occurred - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - // Pass this request on to the next valve in our pipeline - long t1=System.currentTimeMillis(); - - getNext().invoke(request, response); - - long t2=System.currentTimeMillis(); - long time=t2-t1; - - if (condition!=null && - null!=request.getRequest().getAttribute(condition)) { - return; - } - - - Date date = getDate(); - StringBuffer result = new StringBuffer(); - - // Check to see if we should log using the "common" access log pattern - if (common || combined) { - String value = null; - - if (isResolveHosts()) - result.append(request.getRemoteHost()); - else - result.append(request.getRemoteAddr()); - - result.append(" - "); - - value = request.getRemoteUser(); - if (value == null) - result.append("- "); - else { - result.append(value); - result.append(space); - } - - result.append("["); - result.append(dayFormatter.format(date)); // Day - result.append('/'); - result.append(lookup(monthFormatter.format(date))); // Month - result.append('/'); - result.append(yearFormatter.format(date)); // Year - result.append(':'); - result.append(timeFormatter.format(date)); // Time - result.append(space); - result.append(getTimeZone(date)); // Time Zone - result.append("] \""); - - result.append(request.getMethod()); - result.append(space); - result.append(request.getRequestURI()); - if (request.getQueryString() != null) { - result.append('?'); - result.append(request.getQueryString()); - } - result.append(space); - result.append(request.getProtocol()); - result.append("\" "); - - result.append(response.getStatus()); - - result.append(space); - - int length = response.getContentCount(); - - if (length <= 0) - value = "-"; - else - value = "" + length; - result.append(value); - - if (combined) { - result.append(space); - result.append("\""); - String referer = request.getHeader("referer"); - if(referer != null) - result.append(referer); - else - result.append("-"); - result.append("\""); - - result.append(space); - result.append("\""); - String ua = request.getHeader("user-agent"); - if(ua != null) - result.append(ua); - else - result.append("-"); - result.append("\""); - } - - } else { - // Generate a message based on the defined pattern - boolean replace = false; - for (int i = 0; i < pattern.length(); i++) { - char ch = pattern.charAt(i); - if (replace) { - /* For code that processes {, the behavior will be ... if I - * do not enounter a closing } - then I ignore the { - */ - if ('{' == ch){ - StringBuffer name = new StringBuffer(); - int j = i + 1; - for(;j < pattern.length() && '}' != pattern.charAt(j); j++) { - name.append(pattern.charAt(j)); - } - if (j+1 < pattern.length()) { - /* the +1 was to account for } which we increment now */ - j++; - result.append(replace(name.toString(), - pattern.charAt(j), - request, - response)); - i=j; /*Since we walked more than one character*/ - } else { - //D'oh - end of string - pretend we never did this - //and do processing the "old way" - result.append(replace(ch, date, request, response, time)); - } - } else { - result.append(replace(ch, date, request, response,time )); - } - replace = false; - } else if (ch == '%') { - replace = true; - } else { - result.append(ch); - } - } - } - log(result.toString(), date); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Close the currently open log file (if any) - */ - private synchronized void close() { - - if (writer == null) - return; - writer.flush(); - writer.close(); - writer = null; - dateStamp = ""; - - } - - - /** - * Log the specified message to the log file, switching files if the date - * has changed since the previous log call. - * - * @param message Message to be logged - * @param date the current Date object (so this method doesn't need to - * create a new one) - */ - public void log(String message, Date date) { - - if (rotatable){ - // Only do a logfile switch check once a second, max. - long systime = System.currentTimeMillis(); - if ((systime - rotationLastChecked) > 1000) { - - // We need a new currentDate - currentDate = new Date(systime); - rotationLastChecked = systime; - - // Check for a change of date - String tsDate = dateFormatter.format(currentDate); - - // If the date has changed, switch log files - if (!dateStamp.equals(tsDate)) { - synchronized (this) { - if (!dateStamp.equals(tsDate)) { - close(); - dateStamp = tsDate; - open(); - } - } - } - - } - } - - // Log this message - if (writer != null) { - writer.println(message); - } - - } - - - /** - * Return the month abbreviation for the specified month, which must - * be a two-digit String. - * - * @param month Month number ("01" .. "12"). - */ - private String lookup(String month) { - - int index; - try { - index = Integer.parseInt(month) - 1; - } catch (Throwable t) { - index = 0; // Can not happen, in theory - } - return (months[index]); - - } - - - /** - * Open the new log file for the date specified by dateStamp. - */ - private synchronized void open() { - - // Create the directory if necessary - File dir = new File(directory); - if (!dir.isAbsolute()) - dir = new File(System.getProperty("catalina.base"), directory); - dir.mkdirs(); - - // Open the current log file - try { - String pathname; - // If no rotate - no need for dateStamp in fileName - if (rotatable){ - pathname = dir.getAbsolutePath() + File.separator + - prefix + dateStamp + suffix; - } else { - pathname = dir.getAbsolutePath() + File.separator + - prefix + suffix; - } - writer = new PrintWriter(new FileWriter(pathname, true), true); - } catch (IOException e) { - writer = null; - } - - } - - - /** - * Return the replacement text for the specified pattern character. - * - * @param pattern Pattern character identifying the desired text - * @param date the current Date so that this method doesn't need to - * create one - * @param request Request being processed - * @param response Response being processed - */ - private String replace(char pattern, Date date, Request request, - Response response, long time) { - - String value = null; - - if (pattern == 'a') { - value = request.getRemoteAddr(); - } else if (pattern == 'A') { - try { - value = InetAddress.getLocalHost().getHostAddress(); - } catch(Throwable e){ - value = "127.0.0.1"; - } - } else if (pattern == 'b') { - int length = response.getContentCount(); - if (length <= 0) - value = "-"; - else - value = "" + length; - } else if (pattern == 'B') { - value = "" + response.getContentLength(); - } else if (pattern == 'h') { - value = request.getRemoteHost(); - } else if (pattern == 'H') { - value = request.getProtocol(); - } else if (pattern == 'l') { - value = "-"; - } else if (pattern == 'm') { - if (request != null) - value = request.getMethod(); - else - value = ""; - } else if (pattern == 'p') { - value = "" + request.getServerPort(); - } else if (pattern == 'D') { - value = "" + time; - } else if (pattern == 'q') { - String query = null; - if (request != null) - query = request.getQueryString(); - if (query != null) - value = "?" + query; - else - value = ""; - } else if (pattern == 'r') { - StringBuffer sb = new StringBuffer(); - if (request != null) { - sb.append(request.getMethod()); - sb.append(space); - sb.append(request.getRequestURI()); - if (request.getQueryString() != null) { - sb.append('?'); - sb.append(request.getQueryString()); - } - sb.append(space); - sb.append(request.getProtocol()); - } else { - sb.append("- - "); - sb.append(request.getProtocol()); - } - value = sb.toString(); - } else if (pattern == 'S') { - if (request != null) - if (request.getSession(false) != null) - value = request.getSessionInternal(false).getIdInternal(); - else value = "-"; - else - value = "-"; - } else if (pattern == 's') { - if (response != null) - value = "" + response.getStatus(); - else - value = "-"; - } else if (pattern == 't') { - StringBuffer temp = new StringBuffer("["); - temp.append(dayFormatter.format(date)); // Day - temp.append('/'); - temp.append(lookup(monthFormatter.format(date))); // Month - temp.append('/'); - temp.append(yearFormatter.format(date)); // Year - temp.append(':'); - temp.append(timeFormatter.format(date)); // Time - temp.append(' '); - temp.append(getTimeZone(date)); // Timezone - temp.append(']'); - value = temp.toString(); - } else if (pattern == 'T') { - value = timeTakenFormatter.format(time/1000d); - } else if (pattern == 'u') { - if (request != null) - value = request.getRemoteUser(); - if (value == null) - value = "-"; - } else if (pattern == 'U') { - if (request != null) - value = request.getRequestURI(); - else - value = "-"; - } else if (pattern == 'v') { - value = request.getServerName(); - } else { - value = "???" + pattern + "???"; - } - - if (value == null) - return (""); - else - return (value); - - } - - - /** - * Return the replacement text for the specified "header/parameter". - * - * @param header The header/parameter to get - * @param type Where to get it from i=input,c=cookie,r=ServletRequest,s=Session - * @param request Request being processed - * @param response Response being processed - */ - private String replace(String header, char type, Request request, - Response response) { - - Object value = null; - - switch (type) { - case 'i': - if (null != request) - value = request.getHeader(header); - else - value= "??"; - break; -/* - // Someone please make me work - case 'o': - break; -*/ - case 'c': - Cookie[] c = request.getCookies(); - for (int i=0; c != null && i < c.length; i++){ - if (header.equals(c[i].getName())){ - value = c[i].getValue(); - break; - } - } - break; - case 'r': - if (null != request) - value = request.getAttribute(header); - else - value= "??"; - break; - case 's': - if (null != request) { - HttpSession sess = request.getSession(false); - if (null != sess) - value = sess.getAttribute(header); - } - break; - default: - value = "???"; - } - - /* try catch in case toString() barfs */ - try { - if (value!=null) - if (value instanceof String) - return (String)value; - else - return value.toString(); - else - return "-"; - } catch(Throwable e) { - return "-"; - } - } - - - /** - * This method returns a Date object that is accurate to within one - * second. If a thread calls this method to get a Date and it's been - * less than 1 second since a new Date was created, this method - * simply gives out the same Date again so that the system doesn't - * spend time creating Date objects unnecessarily. - * - * @return Date - */ - private Date getDate() { - if(currentDate == null) { - currentDate = new Date(); - } else { - // Only create a new Date once per second, max. - long systime = System.currentTimeMillis(); - if ((systime - currentDate.getTime()) > 1000) { - currentDate = new Date(systime); - } - } - - return currentDate; - } - - - private String getTimeZone(Date date) { - if (timezone.inDaylightTime(date)) { - return timeZoneDST; - } else { - return timeZoneNoDST; - } - } - - - private String calculateTimeZoneOffset(long offset) { - StringBuffer tz = new StringBuffer(); - if ((offset<0)) { - tz.append("-"); - offset = -offset; - } else { - tz.append("+"); - } - - long hourOffset = offset/(1000*60*60); - long minuteOffset = (offset/(1000*60)) % 60; - - if (hourOffset<10) - tz.append("0"); - tz.append(hourOffset); - - if (minuteOffset<10) - tz.append("0"); - tz.append(minuteOffset); - - return tz.toString(); - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to add - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("accessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Initialize the timeZone, Date formatters, and currentDate - timezone = TimeZone.getDefault(); - timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); - Calendar calendar = Calendar.getInstance(timezone); - int offset = calendar.get(Calendar.DST_OFFSET); - timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); - - if (fileDateFormat==null || fileDateFormat.length()==0) - fileDateFormat = "yyyy-MM-dd"; - dateFormatter = new SimpleDateFormat(fileDateFormat); - dateFormatter.setTimeZone(timezone); - dayFormatter = new SimpleDateFormat("dd"); - dayFormatter.setTimeZone(timezone); - monthFormatter = new SimpleDateFormat("MM"); - monthFormatter.setTimeZone(timezone); - yearFormatter = new SimpleDateFormat("yyyy"); - yearFormatter.setTimeZone(timezone); - timeFormatter = new SimpleDateFormat("HH:mm:ss"); - timeFormatter.setTimeZone(timezone); - currentDate = new Date(); - dateStamp = dateFormatter.format(currentDate); - timeTakenFormatter = new DecimalFormat("0.000"); - - open(); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("accessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - close(); - - } -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; + + +/** + *

        Implementation of the Valve interface that generates a web server + * access log with the detailed line contents matching a configurable pattern. + * The syntax of the available patterns is similar to that supported by the + * Apache mod_log_config module. As an additional feature, + * automatic rollover of log files when the date changes is also supported.

        + * + *

        Patterns for the logged message may include constant text or any of the + * following replacement strings, for which the corresponding information + * from the specified Response is substituted:

        + *
          + *
        • %a - Remote IP address + *
        • %A - Local IP address + *
        • %b - Bytes sent, excluding HTTP headers, or '-' if no bytes + * were sent + *
        • %B - Bytes sent, excluding HTTP headers + *
        • %h - Remote host name + *
        • %H - Request protocol + *
        • %l - Remote logical username from identd (always returns '-') + *
        • %m - Request method + *
        • %p - Local port + *
        • %q - Query string (prepended with a '?' if it exists, otherwise + * an empty string + *
        • %r - First line of the request + *
        • %s - HTTP status code of the response + *
        • %S - User session ID + *
        • %t - Date and time, in Common Log Format format + *
        • %u - Remote user that was authenticated + *
        • %U - Requested URL path + *
        • %v - Local server name + *
        • %D - Time taken to process the request, in millis + *
        • %T - Time taken to process the request, in seconds + *
        + *

        In addition, the caller can specify one of the following aliases for + * commonly utilized patterns:

        + *
          + *
        • common - %h %l %u %t "%r" %s %b + *
        • combined - + * %h %l %u %t "%r" %s %b "%{Referer}i" "%{User-Agent}i" + *
        + * + *

        + * There is also support to write information from the cookie, incoming + * header, the Session or something else in the ServletRequest.
        + * It is modeled after the apache syntax: + *

          + *
        • %{xxx}i for incoming headers + *
        • %{xxx}c for a specific cookie + *
        • %{xxx}r xxx is an attribute in the ServletRequest + *
        • %{xxx}s xxx is an attribute in the HttpSession + *
        + *

        + * + *

        + * Conditional logging is also supported. This can be done with the + * condition property. + * If the value returned from ServletRequest.getAttribute(condition) + * yields a non-null value. The logging will be skipped. + *

        + * + * @author Craig R. McClanahan + * @author Jason Brittain + * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public class AccessLogValve + extends ValveBase + implements Lifecycle { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class with default property values. + */ + public AccessLogValve() { + + super(); + setPattern("common"); + + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The as-of date for the currently open log file, or a zero-length + * string if there is no open log file. + */ + private String dateStamp = ""; + + + /** + * The directory in which log files are created. + */ + private String directory = "logs"; + + + /** + * The descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.valves.AccessLogValve/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The set of month abbreviations for log messages. + */ + protected static final String months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + + /** + * If the current log pattern is the same as the common access log + * format pattern, then we'll set this variable to true and log in + * a more optimal and hard-coded way. + */ + private boolean common = false; + + + /** + * For the combined format (common, plus useragent and referer), we do + * the same + */ + private boolean combined = false; + + + /** + * The pattern used to format our access log lines. + */ + private String pattern = null; + + + /** + * The prefix that is added to log file filenames. + */ + private String prefix = "access_log."; + + + /** + * Should we rotate our log file? Default is true (like old behavior) + */ + private boolean rotatable = true; + + + /** + * The string manager for this package. + */ + private StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + private boolean started = false; + + + /** + * The suffix that is added to log file filenames. + */ + private String suffix = ""; + + + /** + * The PrintWriter to which we are currently logging, if any. + */ + private PrintWriter writer = null; + + + /** + * A date formatter to format a Date into a date in the format + * "yyyy-MM-dd". + */ + private SimpleDateFormat dateFormatter = null; + + + /** + * A date formatter to format Dates into a day string in the format + * "dd". + */ + private SimpleDateFormat dayFormatter = null; + + + /** + * A date formatter to format a Date into a month string in the format + * "MM". + */ + private SimpleDateFormat monthFormatter = null; + + + /** + * Time taken formatter for 3 decimal places. + */ + private DecimalFormat timeTakenFormatter = null; + + + /** + * A date formatter to format a Date into a year string in the format + * "yyyy". + */ + private SimpleDateFormat yearFormatter = null; + + + /** + * A date formatter to format a Date into a time in the format + * "kk:mm:ss" (kk is a 24-hour representation of the hour). + */ + private SimpleDateFormat timeFormatter = null; + + + /** + * The system timezone. + */ + private TimeZone timezone = null; + + + /** + * The time zone offset relative to GMT in text form when daylight saving + * is not in operation. + */ + private String timeZoneNoDST = null; + + + /** + * The time zone offset relative to GMT in text form when daylight saving + * is in operation. + */ + private String timeZoneDST = null; + + + /** + * The system time when we last updated the Date that this valve + * uses for log lines. + */ + private Date currentDate = null; + + + /** + * When formatting log lines, we often use strings like this one (" "). + */ + private String space = " "; + + + /** + * Resolve hosts. + */ + private boolean resolveHosts = false; + + + /** + * Instant when the log daily rotation was last checked. + */ + private long rotationLastChecked = 0L; + + + /** + * Are we doing conditional logging. default false. + */ + private String condition = null; + + + /** + * Date format to place in log file name. Use at your own risk! + */ + private String fileDateFormat = null; + + // ------------------------------------------------------------- Properties + + + /** + * Return the directory in which we create log files. + */ + public String getDirectory() { + + return (directory); + + } + + + /** + * Set the directory in which we create log files. + * + * @param directory The new log file directory + */ + public void setDirectory(String directory) { + + this.directory = directory; + + } + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the format pattern. + */ + public String getPattern() { + + return (this.pattern); + + } + + + /** + * Set the format pattern, first translating any recognized alias. + * + * @param pattern The new pattern + */ + public void setPattern(String pattern) { + + if (pattern == null) + pattern = ""; + if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) + pattern = Constants.AccessLog.COMMON_PATTERN; + if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) + pattern = Constants.AccessLog.COMBINED_PATTERN; + this.pattern = pattern; + + if (this.pattern.equals(Constants.AccessLog.COMMON_PATTERN)) + common = true; + else + common = false; + + if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) + combined = true; + else + combined = false; + + } + + + /** + * Return the log file prefix. + */ + public String getPrefix() { + + return (prefix); + + } + + + /** + * Set the log file prefix. + * + * @param prefix The new log file prefix + */ + public void setPrefix(String prefix) { + + this.prefix = prefix; + + } + + + /** + * Should we rotate the logs + */ + public boolean isRotatable() { + + return rotatable; + + } + + + /** + * Set the value is we should we rotate the logs + * + * @param rotatable true is we should rotate. + */ + public void setRotatable(boolean rotatable) { + + this.rotatable = rotatable; + + } + + + /** + * Return the log file suffix. + */ + public String getSuffix() { + + return (suffix); + + } + + + /** + * Set the log file suffix. + * + * @param suffix The new log file suffix + */ + public void setSuffix(String suffix) { + + this.suffix = suffix; + + } + + + /** + * Set the resolve hosts flag. + * + * @param resolveHosts The new resolve hosts value + */ + public void setResolveHosts(boolean resolveHosts) { + + this.resolveHosts = resolveHosts; + + } + + + /** + * Get the value of the resolve hosts flag. + */ + public boolean isResolveHosts() { + + return resolveHosts; + + } + + + /** + * Return whether the attribute name to look for when + * performing conditional loggging. If null, every + * request is logged. + */ + public String getCondition() { + + return condition; + + } + + + /** + * Set the ServletRequest.attribute to look for to perform + * conditional logging. Set to null to log everything. + * + * @param condition Set to null to log everything + */ + public void setCondition(String condition) { + + this.condition = condition; + + } + + /** + * Return the date format date based log rotation. + */ + public String getFileDateFormat() { + return fileDateFormat; + } + + + /** + * Set the date format date based log rotation. + */ + public void setFileDateFormat(String fileDateFormat) { + this.fileDateFormat = fileDateFormat; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Log a message summarizing the specified request and response, according + * to the format specified by the pattern property. + * + * @param request Request being processed + * @param response Response being processed + * + * @exception IOException if an input/output error has occurred + * @exception ServletException if a servlet error has occurred + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + // Pass this request on to the next valve in our pipeline + long t1=System.currentTimeMillis(); + + getNext().invoke(request, response); + + long t2=System.currentTimeMillis(); + long time=t2-t1; + + if (condition!=null && + null!=request.getRequest().getAttribute(condition)) { + return; + } + + + Date date = getDate(); + StringBuffer result = new StringBuffer(); + + // Check to see if we should log using the "common" access log pattern + if (common || combined) { + String value = null; + + if (isResolveHosts()) + result.append(request.getRemoteHost()); + else + result.append(request.getRemoteAddr()); + + result.append(" - "); + + value = request.getRemoteUser(); + if (value == null) + result.append("- "); + else { + result.append(value); + result.append(space); + } + + result.append("["); + result.append(dayFormatter.format(date)); // Day + result.append('/'); + result.append(lookup(monthFormatter.format(date))); // Month + result.append('/'); + result.append(yearFormatter.format(date)); // Year + result.append(':'); + result.append(timeFormatter.format(date)); // Time + result.append(space); + result.append(getTimeZone(date)); // Time Zone + result.append("] \""); + + result.append(request.getMethod()); + result.append(space); + result.append(request.getRequestURI()); + if (request.getQueryString() != null) { + result.append('?'); + result.append(request.getQueryString()); + } + result.append(space); + result.append(request.getProtocol()); + result.append("\" "); + + result.append(response.getStatus()); + + result.append(space); + + int length = response.getContentCount(); + + if (length <= 0) + value = "-"; + else + value = "" + length; + result.append(value); + + if (combined) { + result.append(space); + result.append("\""); + String referer = request.getHeader("referer"); + if(referer != null) + result.append(referer); + else + result.append("-"); + result.append("\""); + + result.append(space); + result.append("\""); + String ua = request.getHeader("user-agent"); + if(ua != null) + result.append(ua); + else + result.append("-"); + result.append("\""); + } + + } else { + // Generate a message based on the defined pattern + boolean replace = false; + for (int i = 0; i < pattern.length(); i++) { + char ch = pattern.charAt(i); + if (replace) { + /* For code that processes {, the behavior will be ... if I + * do not enounter a closing } - then I ignore the { + */ + if ('{' == ch){ + StringBuffer name = new StringBuffer(); + int j = i + 1; + for(;j < pattern.length() && '}' != pattern.charAt(j); j++) { + name.append(pattern.charAt(j)); + } + if (j+1 < pattern.length()) { + /* the +1 was to account for } which we increment now */ + j++; + result.append(replace(name.toString(), + pattern.charAt(j), + request, + response)); + i=j; /*Since we walked more than one character*/ + } else { + //D'oh - end of string - pretend we never did this + //and do processing the "old way" + result.append(replace(ch, date, request, response, time)); + } + } else { + result.append(replace(ch, date, request, response,time )); + } + replace = false; + } else if (ch == '%') { + replace = true; + } else { + result.append(ch); + } + } + } + log(result.toString(), date); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Close the currently open log file (if any) + */ + private synchronized void close() { + + if (writer == null) + return; + writer.flush(); + writer.close(); + writer = null; + dateStamp = ""; + + } + + + /** + * Log the specified message to the log file, switching files if the date + * has changed since the previous log call. + * + * @param message Message to be logged + * @param date the current Date object (so this method doesn't need to + * create a new one) + */ + public void log(String message, Date date) { + + if (rotatable){ + // Only do a logfile switch check once a second, max. + long systime = System.currentTimeMillis(); + if ((systime - rotationLastChecked) > 1000) { + + // We need a new currentDate + currentDate = new Date(systime); + rotationLastChecked = systime; + + // Check for a change of date + String tsDate = dateFormatter.format(currentDate); + + // If the date has changed, switch log files + if (!dateStamp.equals(tsDate)) { + synchronized (this) { + if (!dateStamp.equals(tsDate)) { + close(); + dateStamp = tsDate; + open(); + } + } + } + + } + } + + // Log this message + if (writer != null) { + writer.println(message); + } + + } + + + /** + * Return the month abbreviation for the specified month, which must + * be a two-digit String. + * + * @param month Month number ("01" .. "12"). + */ + private String lookup(String month) { + + int index; + try { + index = Integer.parseInt(month) - 1; + } catch (Throwable t) { + index = 0; // Can not happen, in theory + } + return (months[index]); + + } + + + /** + * Open the new log file for the date specified by dateStamp. + */ + private synchronized void open() { + + // Create the directory if necessary + File dir = new File(directory); + if (!dir.isAbsolute()) + dir = new File(System.getProperty("catalina.base"), directory); + dir.mkdirs(); + + // Open the current log file + try { + String pathname; + // If no rotate - no need for dateStamp in fileName + if (rotatable){ + pathname = dir.getAbsolutePath() + File.separator + + prefix + dateStamp + suffix; + } else { + pathname = dir.getAbsolutePath() + File.separator + + prefix + suffix; + } + writer = new PrintWriter(new FileWriter(pathname, true), true); + } catch (IOException e) { + writer = null; + } + + } + + + /** + * Return the replacement text for the specified pattern character. + * + * @param pattern Pattern character identifying the desired text + * @param date the current Date so that this method doesn't need to + * create one + * @param request Request being processed + * @param response Response being processed + */ + private String replace(char pattern, Date date, Request request, + Response response, long time) { + + String value = null; + + if (pattern == 'a') { + value = request.getRemoteAddr(); + } else if (pattern == 'A') { + try { + value = InetAddress.getLocalHost().getHostAddress(); + } catch(Throwable e){ + value = "127.0.0.1"; + } + } else if (pattern == 'b') { + int length = response.getContentCount(); + if (length <= 0) + value = "-"; + else + value = "" + length; + } else if (pattern == 'B') { + value = "" + response.getContentLength(); + } else if (pattern == 'h') { + value = request.getRemoteHost(); + } else if (pattern == 'H') { + value = request.getProtocol(); + } else if (pattern == 'l') { + value = "-"; + } else if (pattern == 'm') { + if (request != null) + value = request.getMethod(); + else + value = ""; + } else if (pattern == 'p') { + value = "" + request.getServerPort(); + } else if (pattern == 'D') { + value = "" + time; + } else if (pattern == 'q') { + String query = null; + if (request != null) + query = request.getQueryString(); + if (query != null) + value = "?" + query; + else + value = ""; + } else if (pattern == 'r') { + StringBuffer sb = new StringBuffer(); + if (request != null) { + sb.append(request.getMethod()); + sb.append(space); + sb.append(request.getRequestURI()); + if (request.getQueryString() != null) { + sb.append('?'); + sb.append(request.getQueryString()); + } + sb.append(space); + sb.append(request.getProtocol()); + } else { + sb.append("- - "); + sb.append(request.getProtocol()); + } + value = sb.toString(); + } else if (pattern == 'S') { + if (request != null) + if (request.getSession(false) != null) + value = request.getSessionInternal(false).getIdInternal(); + else value = "-"; + else + value = "-"; + } else if (pattern == 's') { + if (response != null) + value = "" + response.getStatus(); + else + value = "-"; + } else if (pattern == 't') { + StringBuffer temp = new StringBuffer("["); + temp.append(dayFormatter.format(date)); // Day + temp.append('/'); + temp.append(lookup(monthFormatter.format(date))); // Month + temp.append('/'); + temp.append(yearFormatter.format(date)); // Year + temp.append(':'); + temp.append(timeFormatter.format(date)); // Time + temp.append(' '); + temp.append(getTimeZone(date)); // Timezone + temp.append(']'); + value = temp.toString(); + } else if (pattern == 'T') { + value = timeTakenFormatter.format(time/1000d); + } else if (pattern == 'u') { + if (request != null) + value = request.getRemoteUser(); + if (value == null) + value = "-"; + } else if (pattern == 'U') { + if (request != null) + value = request.getRequestURI(); + else + value = "-"; + } else if (pattern == 'v') { + value = request.getServerName(); + } else { + value = "???" + pattern + "???"; + } + + if (value == null) + return (""); + else + return (value); + + } + + + /** + * Return the replacement text for the specified "header/parameter". + * + * @param header The header/parameter to get + * @param type Where to get it from i=input,c=cookie,r=ServletRequest,s=Session + * @param request Request being processed + * @param response Response being processed + */ + private String replace(String header, char type, Request request, + Response response) { + + Object value = null; + + switch (type) { + case 'i': + if (null != request) + value = request.getHeader(header); + else + value= "??"; + break; +/* + // Someone please make me work + case 'o': + break; +*/ + case 'c': + Cookie[] c = request.getCookies(); + for (int i=0; c != null && i < c.length; i++){ + if (header.equals(c[i].getName())){ + value = c[i].getValue(); + break; + } + } + break; + case 'r': + if (null != request) + value = request.getAttribute(header); + else + value= "??"; + break; + case 's': + if (null != request) { + HttpSession sess = request.getSession(false); + if (null != sess) + value = sess.getAttribute(header); + } + break; + default: + value = "???"; + } + + /* try catch in case toString() barfs */ + try { + if (value!=null) + if (value instanceof String) + return (String)value; + else + return value.toString(); + else + return "-"; + } catch(Throwable e) { + return "-"; + } + } + + + /** + * This method returns a Date object that is accurate to within one + * second. If a thread calls this method to get a Date and it's been + * less than 1 second since a new Date was created, this method + * simply gives out the same Date again so that the system doesn't + * spend time creating Date objects unnecessarily. + * + * @return Date + */ + private Date getDate() { + if(currentDate == null) { + currentDate = new Date(); + } else { + // Only create a new Date once per second, max. + long systime = System.currentTimeMillis(); + if ((systime - currentDate.getTime()) > 1000) { + currentDate = new Date(systime); + } + } + + return currentDate; + } + + + private String getTimeZone(Date date) { + if (timezone.inDaylightTime(date)) { + return timeZoneDST; + } else { + return timeZoneNoDST; + } + } + + + private String calculateTimeZoneOffset(long offset) { + StringBuffer tz = new StringBuffer(); + if ((offset<0)) { + tz.append("-"); + offset = -offset; + } else { + tz.append("+"); + } + + long hourOffset = offset/(1000*60*60); + long minuteOffset = (offset/(1000*60)) % 60; + + if (hourOffset<10) + tz.append("0"); + tz.append(hourOffset); + + if (minuteOffset<10) + tz.append("0"); + tz.append(minuteOffset); + + return tz.toString(); + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("accessLogValve.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Initialize the timeZone, Date formatters, and currentDate + timezone = TimeZone.getDefault(); + timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); + Calendar calendar = Calendar.getInstance(timezone); + int offset = calendar.get(Calendar.DST_OFFSET); + timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); + + if (fileDateFormat==null || fileDateFormat.length()==0) + fileDateFormat = "yyyy-MM-dd"; + dateFormatter = new SimpleDateFormat(fileDateFormat); + dateFormatter.setTimeZone(timezone); + dayFormatter = new SimpleDateFormat("dd"); + dayFormatter.setTimeZone(timezone); + monthFormatter = new SimpleDateFormat("MM"); + monthFormatter.setTimeZone(timezone); + yearFormatter = new SimpleDateFormat("yyyy"); + yearFormatter.setTimeZone(timezone); + timeFormatter = new SimpleDateFormat("HH:mm:ss"); + timeFormatter.setTimeZone(timezone); + currentDate = new Date(); + dateStamp = dateFormatter.format(currentDate); + timeTakenFormatter = new DecimalFormat("0.000"); + + open(); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("accessLogValve.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + close(); + + } +} diff --git a/java/org/apache/catalina/valves/Constants.java b/java/org/apache/catalina/valves/Constants.java index 5220006f8..086432546 100644 --- a/java/org/apache/catalina/valves/Constants.java +++ b/java/org/apache/catalina/valves/Constants.java @@ -1,40 +1,40 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -/** - * Manifest constants for the org.apache.catalina.valves - * package. - * - * @author Craig R. McClanahan - */ - -public final class Constants { - - public static final String Package = "org.apache.catalina.valves"; - - // Constants for the AccessLogValve class - public static final class AccessLog { - public static final String COMMON_ALIAS = "common"; - public static final String COMMON_PATTERN = "%h %l %u %t \"%r\" %s %b"; - public static final String COMBINED_ALIAS = "combined"; - public static final String COMBINED_PATTERN = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\""; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +/** + * Manifest constants for the org.apache.catalina.valves + * package. + * + * @author Craig R. McClanahan + */ + +public final class Constants { + + public static final String Package = "org.apache.catalina.valves"; + + // Constants for the AccessLogValve class + public static final class AccessLog { + public static final String COMMON_ALIAS = "common"; + public static final String COMMON_PATTERN = "%h %l %u %t \"%r\" %s %b"; + public static final String COMBINED_ALIAS = "combined"; + public static final String COMBINED_PATTERN = "%h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-Agent}i\""; + } + +} diff --git a/java/org/apache/catalina/valves/ErrorReportValve.java b/java/org/apache/catalina/valves/ErrorReportValve.java index 0e8b0dbf7..e6897a26f 100644 --- a/java/org/apache/catalina/valves/ErrorReportValve.java +++ b/java/org/apache/catalina/valves/ErrorReportValve.java @@ -1,306 +1,306 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import java.io.Writer; - -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Globals; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.RequestUtil; -import org.apache.catalina.util.ServerInfo; -import org.apache.catalina.util.StringManager; -import org.apache.tomcat.util.IntrospectionUtils; - -/** - *

        Implementation of a Valve that outputs HTML error pages.

        - * - *

        This Valve should be attached at the Host level, although it will work - * if attached to a Context.

        - * - *

        HTML code from the Cocoon 2 project.

        - * - * @author Remy Maucherat - * @author Craig R. McClanahan - * @author Nicola Ken Barozzi Aisa - * @author Stefano Mazzocchi - * @author Yoav Shapira - * @version $Revision: 304023 $ $Date: 2005-07-26 14:45:22 +0200 (mar., 26 juil. 2005) $ - */ - -public class ErrorReportValve - extends ValveBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.ErrorReportValve/1.0"; - - - /** - * The StringManager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Invoke the next Valve in the sequence. When the invoke returns, check - * the response state, and output an error report is necessary. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - // Perform the request - getNext().invoke(request, response); - - ServletRequest sreq = (ServletRequest) request; - Throwable throwable = - (Throwable) sreq.getAttribute(Globals.EXCEPTION_ATTR); - - ServletResponse sresp = (ServletResponse) response; - if (sresp.isCommitted()) { - return; - } - - if (throwable != null) { - - // The response is an error - response.setError(); - - // Reset the response (if possible) - try { - sresp.reset(); - } catch (IllegalStateException e) { - ; - } - - response.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - - } - - response.setSuspended(false); - - try { - report(request, response, throwable); - } catch (Throwable tt) { - ; - } - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Prints out an error report. - * - * @param request The request being processed - * @param response The response being generated - * @param throwable The exception that occurred (which possibly wraps - * a root cause exception - */ - protected void report(Request request, Response response, - Throwable throwable) - throws IOException { - - // Do nothing on non-HTTP responses - int statusCode = response.getStatus(); - - // Do nothing on a 1xx, 2xx and 3xx status - // Do nothing if anything has been written already - if ((statusCode < 400) || (response.getContentCount() > 0)) - return; - - Throwable rootCause = null; - - if (throwable != null) { - - if (throwable instanceof ServletException) - rootCause = ((ServletException) throwable).getRootCause(); - - } - - String message = RequestUtil.filter(response.getMessage()); - if (message == null) - message = ""; - - // Do nothing if there is no report for the specified status code - String report = null; - try { - report = sm.getString("http." + statusCode, message); - } catch (Throwable t) { - ; - } - if (report == null) - return; - - StringBuffer sb = new StringBuffer(); - - sb.append(""); - sb.append(ServerInfo.getServerInfo()).append(" - "); - sb.append(sm.getString("errorReportValve.errorReport")); - sb.append(""); - sb.append(" "); - sb.append(""); - sb.append("

        "); - sb.append(sm.getString("errorReportValve.statusHeader", - "" + statusCode, message)).append("

        "); - sb.append("
        "); - sb.append("

        type "); - if (throwable != null) { - sb.append(sm.getString("errorReportValve.exceptionReport")); - } else { - sb.append(sm.getString("errorReportValve.statusReport")); - } - sb.append("

        "); - sb.append("

        "); - sb.append(sm.getString("errorReportValve.message")); - sb.append(" "); - sb.append(message).append("

        "); - sb.append("

        "); - sb.append(sm.getString("errorReportValve.description")); - sb.append(" "); - sb.append(report); - sb.append("

        "); - - if (throwable != null) { - - String stackTrace = getPartialServletStackTrace(throwable); - sb.append("

        "); - sb.append(sm.getString("errorReportValve.exception")); - sb.append("

        ");
        -            sb.append(RequestUtil.filter(stackTrace));
        -            sb.append("

        "); - - while (rootCause != null) { - stackTrace = getPartialServletStackTrace(rootCause); - sb.append("

        "); - sb.append(sm.getString("errorReportValve.rootCause")); - sb.append("

        ");
        -                sb.append(RequestUtil.filter(stackTrace));
        -                sb.append("

        "); - // In case root cause is somehow heavily nested - try { - rootCause = (Throwable)IntrospectionUtils.getProperty - (rootCause, "rootCause"); - } catch (ClassCastException e) { - rootCause = null; - } - } - - sb.append("

        "); - sb.append(sm.getString("errorReportValve.note")); - sb.append(" "); - sb.append(sm.getString("errorReportValve.rootCauseInLogs", - ServerInfo.getServerInfo())); - sb.append("

        "); - - } - - sb.append("
        "); - sb.append("

        ").append(ServerInfo.getServerInfo()).append("

        "); - sb.append(""); - - try { - try { - response.setContentType("text/html"); - response.setCharacterEncoding("utf-8"); - } catch (Throwable t) { - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("status.setContentType", t); - } - Writer writer = response.getReporter(); - if (writer != null) { - // If writer is null, it's an indication that the response has - // been hard committed already, which should never happen - writer.write(sb.toString()); - } - } catch (IOException e) { - ; - } catch (IllegalStateException e) { - ; - } - - } - - - /** - * Print out a partial servlet stack trace (truncating at the last - * occurrence of javax.servlet.). - */ - protected String getPartialServletStackTrace(Throwable t) { - StringBuffer trace = new StringBuffer(); - trace.append(t.toString()).append('\n'); - StackTraceElement[] elements = t.getStackTrace(); - int pos = elements.length; - for (int i = 0; i < elements.length; i++) { - if ((elements[i].getClassName().startsWith - ("org.apache.catalina.core.ApplicationFilterChain")) - && (elements[i].getMethodName().equals("internalDoFilter"))) { - pos = i; - } - } - for (int i = 0; i < pos; i++) { - if (!(elements[i].getClassName().startsWith - ("org.apache.catalina.core."))) { - trace.append('\t').append(elements[i].toString()).append('\n'); - } - } - return trace.toString(); - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import java.io.Writer; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Globals; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.RequestUtil; +import org.apache.catalina.util.ServerInfo; +import org.apache.catalina.util.StringManager; +import org.apache.tomcat.util.IntrospectionUtils; + +/** + *

        Implementation of a Valve that outputs HTML error pages.

        + * + *

        This Valve should be attached at the Host level, although it will work + * if attached to a Context.

        + * + *

        HTML code from the Cocoon 2 project.

        + * + * @author Remy Maucherat + * @author Craig R. McClanahan + * @author Nicola Ken Barozzi Aisa + * @author Stefano Mazzocchi + * @author Yoav Shapira + * @version $Revision: 304023 $ $Date: 2005-07-26 14:45:22 +0200 (mar., 26 juil. 2005) $ + */ + +public class ErrorReportValve + extends ValveBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.ErrorReportValve/1.0"; + + + /** + * The StringManager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Invoke the next Valve in the sequence. When the invoke returns, check + * the response state, and output an error report is necessary. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + // Perform the request + getNext().invoke(request, response); + + ServletRequest sreq = (ServletRequest) request; + Throwable throwable = + (Throwable) sreq.getAttribute(Globals.EXCEPTION_ATTR); + + ServletResponse sresp = (ServletResponse) response; + if (sresp.isCommitted()) { + return; + } + + if (throwable != null) { + + // The response is an error + response.setError(); + + // Reset the response (if possible) + try { + sresp.reset(); + } catch (IllegalStateException e) { + ; + } + + response.sendError + (HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + + } + + response.setSuspended(false); + + try { + report(request, response, throwable); + } catch (Throwable tt) { + ; + } + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Prints out an error report. + * + * @param request The request being processed + * @param response The response being generated + * @param throwable The exception that occurred (which possibly wraps + * a root cause exception + */ + protected void report(Request request, Response response, + Throwable throwable) + throws IOException { + + // Do nothing on non-HTTP responses + int statusCode = response.getStatus(); + + // Do nothing on a 1xx, 2xx and 3xx status + // Do nothing if anything has been written already + if ((statusCode < 400) || (response.getContentCount() > 0)) + return; + + Throwable rootCause = null; + + if (throwable != null) { + + if (throwable instanceof ServletException) + rootCause = ((ServletException) throwable).getRootCause(); + + } + + String message = RequestUtil.filter(response.getMessage()); + if (message == null) + message = ""; + + // Do nothing if there is no report for the specified status code + String report = null; + try { + report = sm.getString("http." + statusCode, message); + } catch (Throwable t) { + ; + } + if (report == null) + return; + + StringBuffer sb = new StringBuffer(); + + sb.append(""); + sb.append(ServerInfo.getServerInfo()).append(" - "); + sb.append(sm.getString("errorReportValve.errorReport")); + sb.append(""); + sb.append(" "); + sb.append(""); + sb.append("

        "); + sb.append(sm.getString("errorReportValve.statusHeader", + "" + statusCode, message)).append("

        "); + sb.append("
        "); + sb.append("

        type "); + if (throwable != null) { + sb.append(sm.getString("errorReportValve.exceptionReport")); + } else { + sb.append(sm.getString("errorReportValve.statusReport")); + } + sb.append("

        "); + sb.append("

        "); + sb.append(sm.getString("errorReportValve.message")); + sb.append(" "); + sb.append(message).append("

        "); + sb.append("

        "); + sb.append(sm.getString("errorReportValve.description")); + sb.append(" "); + sb.append(report); + sb.append("

        "); + + if (throwable != null) { + + String stackTrace = getPartialServletStackTrace(throwable); + sb.append("

        "); + sb.append(sm.getString("errorReportValve.exception")); + sb.append("

        ");
        +            sb.append(RequestUtil.filter(stackTrace));
        +            sb.append("

        "); + + while (rootCause != null) { + stackTrace = getPartialServletStackTrace(rootCause); + sb.append("

        "); + sb.append(sm.getString("errorReportValve.rootCause")); + sb.append("

        ");
        +                sb.append(RequestUtil.filter(stackTrace));
        +                sb.append("

        "); + // In case root cause is somehow heavily nested + try { + rootCause = (Throwable)IntrospectionUtils.getProperty + (rootCause, "rootCause"); + } catch (ClassCastException e) { + rootCause = null; + } + } + + sb.append("

        "); + sb.append(sm.getString("errorReportValve.note")); + sb.append(" "); + sb.append(sm.getString("errorReportValve.rootCauseInLogs", + ServerInfo.getServerInfo())); + sb.append("

        "); + + } + + sb.append("
        "); + sb.append("

        ").append(ServerInfo.getServerInfo()).append("

        "); + sb.append(""); + + try { + try { + response.setContentType("text/html"); + response.setCharacterEncoding("utf-8"); + } catch (Throwable t) { + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("status.setContentType", t); + } + Writer writer = response.getReporter(); + if (writer != null) { + // If writer is null, it's an indication that the response has + // been hard committed already, which should never happen + writer.write(sb.toString()); + } + } catch (IOException e) { + ; + } catch (IllegalStateException e) { + ; + } + + } + + + /** + * Print out a partial servlet stack trace (truncating at the last + * occurrence of javax.servlet.). + */ + protected String getPartialServletStackTrace(Throwable t) { + StringBuffer trace = new StringBuffer(); + trace.append(t.toString()).append('\n'); + StackTraceElement[] elements = t.getStackTrace(); + int pos = elements.length; + for (int i = 0; i < elements.length; i++) { + if ((elements[i].getClassName().startsWith + ("org.apache.catalina.core.ApplicationFilterChain")) + && (elements[i].getMethodName().equals("internalDoFilter"))) { + pos = i; + } + } + for (int i = 0; i < pos; i++) { + if (!(elements[i].getClassName().startsWith + ("org.apache.catalina.core."))) { + trace.append('\t').append(elements[i].toString()).append('\n'); + } + } + return trace.toString(); + } + +} diff --git a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java index 602d65926..ea1dfc12f 100644 --- a/java/org/apache/catalina/valves/ExtendedAccessLogValve.java +++ b/java/org/apache/catalina/valves/ExtendedAccessLogValve.java @@ -1,1429 +1,1429 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.net.InetAddress; -import java.net.URLEncoder; -import java.text.DecimalFormat; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.TimeZone; - -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpSession; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.ServerInfo; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - - -/** - * An implementation of the W3c Extended Log File Format. See - * http://www.w3.org/TR/WD-logfile.html for more information about the format. - * - * The following fields are supported: - *
          - *
        • c-dns: Client hostname
        • - *
        • c-ip: Client ip address
        • - *
        • bytes: bytes served
        • - *
        • cs-method: request method
        • - *
        • cs-uri: The full uri requested
        • - *
        • cs-uri-query: The query string
        • - *
        • cs-uri-stem: The uri without query string
        • - *
        • date: The date in yyyy-mm-dd format for GMT
        • - *
        • s-dns: The server dns entry
        • - *
        • s-ip: The server ip address
        • - *
        • cs(XXX): The value of header XXX from client to server
        • - *
        • sc(XXX): The value of header XXX from server to client
        • - *
        • sc-status: The status code
        • - *
        • time: Time the request was served
        • - *
        • time-taken: Time (in seconds) taken to serve the request
        • - *
        • x-A(XXX): Pull XXX attribute from the servlet context
        • - *
        • x-C(XXX): Pull the first cookie of the name XXX
        • - *
        • x-R(XXX): Pull XXX attribute from the servlet request
        • - *
        • x-S(XXX): Pull XXX attribute from the session
        • - *
        • x-P(...): Call request.getParameter(...) - * and URLencode it. Helpful to capture - * certain POST parameters. - *
        • - *
        • For any of the x-H(...) the following method will be called from the - * HttpServletRequestObject
        • - *
        • x-H(authType): getAuthType
        • - *
        • x-H(characterEncoding): getCharacterEncoding
        • - *
        • x-H(contentLength): getContentLength
        • - *
        • x-H(locale): getLocale
        • - *
        • x-H(protocol): getProtocol
        • - *
        • x-H(remoteUser): getRemoteUser
        • - *
        • x-H(requestedSessionId): getGequestedSessionId
        • - *
        • x-H(requestedSessionIdFromCookie): - * isRequestedSessionIdFromCookie
        • - *
        • x-H(requestedSessionIdValid): - * isRequestedSessionIdValid
        • - *
        • x-H(scheme): getScheme
        • - *
        • x-H(secure): isSecure
        • - *
        - * - * - * - *

        - * Log rotation can be on or off. This is dictated by the rotatable - * property. - *

        - * - *

        - * For UNIX users, another field called checkExistsis also - * available. If set to true, the log file's existence will be checked before - * each logging. This way an external log rotator can move the file - * somewhere and tomcat will start with a new file. - *

        - * - *

        - * For JMX junkies, a public method called rotate has - * been made available to allow you to tell this instance to move - * the existing log file to somewhere else start writing a new log file. - *

        - * - *

        - * Conditional logging is also supported. This can be done with the - * condition property. - * If the value returned from ServletRequest.getAttribute(condition) - * yields a non-null value. The logging will be skipped. - *

        - * - *

        - * For extended attributes coming from a getAttribute() call, - * it is you responsibility to ensure there are no newline or - * control characters. - *

        - * - * - * @author Tim Funk - * @version $Revision: 303601 $ $Date: 2004-12-24 00:58:07 +0100 (ven., 24 déc. 2004) $ - */ - -public class ExtendedAccessLogValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default property values. - */ - public ExtendedAccessLogValve() { - - super(); - - - } - - - // ----------------------------------------------------- Instance Variables - private static Log log = LogFactory.getLog(ExtendedAccessLogValve.class); - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.valves.ExtendedAccessLogValve/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - - /** - * The string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - /** - * The as-of date for the currently open log file, or a zero-length - * string if there is no open log file. - */ - private String dateStamp = ""; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = null; - - - /** - * The formatter for the date contained in the file name. - */ - private SimpleDateFormat fileDateFormatter = null; - - - /** - * A date formatter to format a Date into a date in the format - * "yyyy-MM-dd". - */ - private SimpleDateFormat dateFormatter = null; - - - /** - * A date formatter to format a Date into a time in the format - * "kk:mm:ss" (kk is a 24-hour representation of the hour). - */ - private SimpleDateFormat timeFormatter = null; - - - /** - * Time taken formatter for 3 decimal places. - */ - private DecimalFormat timeTakenFormatter = null; - - - /** - * My ip address. Look it up once and remember it. Dump this if we can - * determine another reliable way to get server ip address since this - * server may have many ip's. - */ - private String myIpAddress = null; - - - /** - * My dns name. Look it up once and remember it. Dump this if we can - * determine another reliable way to get server name address since this - * server may have many ip's. - */ - private String myDNSName = null; - - - /** - * Holder for all of the fields to log after the pattern is decoded. - */ - private FieldInfo[] fieldInfos; - - - /** - * The current log file we are writing to. Helpful when checkExists - * is true. - */ - private File currentLogFile = null; - - - - /** - * The system time when we last updated the Date that this valve - * uses for log lines. - */ - private Date currentDate = null; - - - /** - * Instant when the log daily rotation was last checked. - */ - private long rotationLastChecked = 0L; - - - /** - * The directory in which log files are created. - */ - private String directory = "logs"; - - - /** - * The pattern used to format our access log lines. - */ - private String pattern = null; - - - /** - * The prefix that is added to log file filenames. - */ - private String prefix = "access_log."; - - - /** - * Should we rotate our log file? Default is true (like old behavior) - */ - private boolean rotatable = true; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = ""; - - - /** - * Are we doing conditional logging. default false. - */ - private String condition = null; - - - /** - * Do we check for log file existence? Helpful if an external - * agent renames the log file so we can automagically recreate it. - */ - private boolean checkExists = false; - - - /** - * Date format to place in log file name. Use at your own risk! - */ - private String fileDateFormat = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the directory in which we create log files. - */ - public String getDirectory() { - - return (directory); - - } - - - /** - * Set the directory in which we create log files. - * - * @param directory The new log file directory - */ - public void setDirectory(String directory) { - - this.directory = directory; - - } - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the format pattern. - */ - public String getPattern() { - - return (this.pattern); - - } - - - /** - * Set the format pattern, first translating any recognized alias. - * - * @param pattern The new pattern pattern - */ - public void setPattern(String pattern) { - - FieldInfo[] f= decodePattern(pattern); - if (f!=null) { - this.pattern = pattern; - this.fieldInfos = f; - } - } - - - /** - * Return the log file prefix. - */ - public String getPrefix() { - - return (prefix); - - } - - - /** - * Set the log file prefix. - * - * @param prefix The new log file prefix - */ - public void setPrefix(String prefix) { - - this.prefix = prefix; - - } - - - /** - * Return true if logs are automatically rotated. - */ - public boolean isRotatable() { - - return rotatable; - - } - - - /** - * Set the value is we should we rotate the logs - * - * @param rotatable true is we should rotate. - */ - public void setRotatable(boolean rotatable) { - - this.rotatable = rotatable; - - } - - - /** - * Return the log file suffix. - */ - public String getSuffix() { - - return (suffix); - - } - - - /** - * Set the log file suffix. - * - * @param suffix The new log file suffix - */ - public void setSuffix(String suffix) { - - this.suffix = suffix; - - } - - - - /** - * Return whether the attribute name to look for when - * performing conditional loggging. If null, every - * request is logged. - */ - public String getCondition() { - - return condition; - - } - - - /** - * Set the ServletRequest.attribute to look for to perform - * conditional logging. Set to null to log everything. - * - * @param condition Set to null to log everything - */ - public void setCondition(String condition) { - - this.condition = condition; - - } - - - - /** - * Check for file existence before logging. - */ - public boolean isCheckExists() { - - return checkExists; - - } - - - /** - * Set whether to check for log file existence before logging. - * - * @param checkExists true meaning to check for file existence. - */ - public void setCheckExists(boolean checkExists) { - - this.checkExists = checkExists; - - } - - - /** - * Return the date format date based log rotation. - */ - public String getFileDateFormat() { - return fileDateFormat; - } - - - /** - * Set the date format date based log rotation. - */ - public void setFileDateFormat(String fileDateFormat) { - this.fileDateFormat = fileDateFormat; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Log a message summarizing the specified request and response, according - * to the format specified by the pattern property. - * - * @param request Request being processed - * @param response Response being processed - * - * @exception IOException if an input/output error has occurred - * @exception ServletException if a servlet error has occurred - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - // Pass this request on to the next valve in our pipeline - long endTime; - long runTime; - long startTime=System.currentTimeMillis(); - - getNext().invoke(request, response); - - endTime = System.currentTimeMillis(); - runTime = endTime-startTime; - - if (fieldInfos==null || condition!=null && - null!=request.getRequest().getAttribute(condition)) { - return; - } - - - Date date = getDate(endTime); - StringBuffer result = new StringBuffer(); - - for (int i=0; fieldInfos!=null && i 0) - result.append(length); - else - result.append("-"); - } else if (FieldInfo.SPECIAL_CACHED==fieldInfos[i].location) - result.append('-'); /* I don't know how to evaluate this! */ - else - result.append("?WTF?"); /* This should never happen! */ - break; - default: - result.append("?WTF?"); /* This should never happen! */ - } - - if (fieldInfos[i].postWhiteSpace!=null) { - result.append(fieldInfos[i].postWhiteSpace); - } - } - log(result.toString(), date); - - } - - - /** - * Rename the existing log file to something else. Then open the - * old log file name up once again. Intended to be called by a JMX - * agent. - * - * - * @param newFileName The file name to move the log file entry to - * @return true if a file was rotated with no error - */ - public synchronized boolean rotate(String newFileName) { - - if (currentLogFile!=null) { - File holder = currentLogFile; - close(); - try { - holder.renameTo(new File(newFileName)); - } catch(Throwable e){ - log.error("rotate failed", e); - } - - /* Make sure date is correct */ - currentDate = new Date(System.currentTimeMillis()); - dateStamp = fileDateFormatter.format(currentDate); - - open(); - return true; - } else { - return false; - } - - } - - // -------------------------------------------------------- Private Methods - - - /** - * Return the client to server data. - * @param fieldInfo The field to decode. - * @param request The object we pull data from. - * @return The appropriate value. - */ - private String getClientToServer(FieldInfo fieldInfo, Request request) { - - switch(fieldInfo.location) { - case FieldInfo.FIELD_METHOD: - return request.getMethod(); - case FieldInfo.FIELD_URI: - if (null==request.getQueryString()) - return request.getRequestURI(); - else - return request.getRequestURI() + "?" + request.getQueryString(); - case FieldInfo.FIELD_URI_STEM: - return request.getRequestURI(); - case FieldInfo.FIELD_URI_QUERY: - if (null==request.getQueryString()) - return "-"; - return request.getQueryString(); - case FieldInfo.FIELD_HEADER: - return wrap(request.getHeader(fieldInfo.value)); - default: - ; - } - - return "-"; - - } - - - /** - * Return the server to client data. - * @param fieldInfo The field to decode. - * @param response The object we pull data from. - * @return The appropriate value. - */ - private String getServerToClient(FieldInfo fieldInfo, Response response) { - switch(fieldInfo.location) { - case FieldInfo.FIELD_STATUS: - return "" + response.getStatus(); - case FieldInfo.FIELD_COMMENT: - return "?"; /* Not coded yet*/ - case FieldInfo.FIELD_HEADER: - return wrap(response.getHeader(fieldInfo.value)); - default: - ; - } - - return "-"; - - } - - - /** - * Get app specific data. - * @param fieldInfo The field to decode - * @param request Where we will pull the data from. - * @return The appropriate value - */ - private String getAppSpecific(FieldInfo fieldInfo, Request request) { - - switch(fieldInfo.xType) { - case FieldInfo.X_PARAMETER: - return wrap(urlEncode(request.getParameter(fieldInfo.value))); - case FieldInfo.X_REQUEST: - return wrap(request.getAttribute(fieldInfo.value)); - case FieldInfo.X_SESSION: - HttpSession session = null; - if (request!=null){ - session = request.getSession(false); - if (session!=null) - return wrap(session.getAttribute(fieldInfo.value)); - } - break; - case FieldInfo.X_COOKIE: - Cookie[] c = request.getCookies(); - for (int i=0; c != null && i < c.length; i++){ - if (fieldInfo.value.equals(c[i].getName())){ - return wrap(c[i].getValue()); - } - } - case FieldInfo.X_APP: - return wrap(request.getContext().getServletContext() - .getAttribute(fieldInfo.value)); - case FieldInfo.X_SERVLET_REQUEST: - if (fieldInfo.location==FieldInfo.X_LOC_AUTHTYPE) { - return wrap(request.getAuthType()); - } else if (fieldInfo.location==FieldInfo.X_LOC_REMOTEUSER) { - return wrap(request.getRemoteUser()); - } else if (fieldInfo.location== - FieldInfo.X_LOC_REQUESTEDSESSIONID) { - return wrap(request.getRequestedSessionId()); - } else if (fieldInfo.location== - FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE) { - return wrap(""+request.isRequestedSessionIdFromCookie()); - } else if (fieldInfo.location== - FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID) { - return wrap(""+request.isRequestedSessionIdValid()); - } else if (fieldInfo.location==FieldInfo.X_LOC_CONTENTLENGTH) { - return wrap(""+request.getContentLength()); - } else if (fieldInfo.location== - FieldInfo.X_LOC_CHARACTERENCODING) { - return wrap(request.getCharacterEncoding()); - } else if (fieldInfo.location==FieldInfo.X_LOC_LOCALE) { - return wrap(request.getLocale()); - } else if (fieldInfo.location==FieldInfo.X_LOC_PROTOCOL) { - return wrap(request.getProtocol()); - } else if (fieldInfo.location==FieldInfo.X_LOC_SCHEME) { - return wrap(request.getScheme()); - } else if (fieldInfo.location==FieldInfo.X_LOC_SECURE) { - return wrap(""+request.isSecure()); - } - break; - default: - ; - } - - return "-"; - - } - - - /** - * urlEncode the given string. If null or empty, return null. - */ - private String urlEncode(String value) { - if (null==value || value.length()==0) { - return null; - } - return URLEncoder.encode(value); - } - - - /** - * Wrap the incoming value into quotes and escape any inner - * quotes with double quotes. - * - * @param value - The value to wrap quotes around - * @return '-' if empty of null. Otherwise, toString() will - * be called on the object and the value will be wrapped - * in quotes and any quotes will be escaped with 2 - * sets of quotes. - */ - private String wrap(Object value) { - - String svalue; - // Does the value contain a " ? If so must encode it - if (value==null || "-".equals(value)) - return "-"; - - - try { - svalue = value.toString(); - if ("".equals(svalue)) - return "-"; - } catch(Throwable e){ - /* Log error */ - return "-"; - } - - /* Wrap all quotes in double quotes. */ - StringBuffer buffer = new StringBuffer(svalue.length()+2); - buffer.append('"'); - int i=0; - while (i 1000) { - - // We need a new currentDate - currentDate = new Date(systime); - rotationLastChecked = systime; - - // Check for a change of date - String tsDate = fileDateFormatter.format(currentDate); - - // If the date has changed, switch log files - if (!dateStamp.equals(tsDate)) { - synchronized (this) { - if (!dateStamp.equals(tsDate)) { - close(); - dateStamp = tsDate; - open(); - } - } - } - } - } - - /* In case something external rotated the file instead */ - if (checkExists){ - synchronized (this) { - if (currentLogFile!=null && !currentLogFile.exists()) { - try { - close(); - } catch (Throwable e){ - log.info("at least this wasn't swallowed", e); - } - - /* Make sure date is correct */ - currentDate = new Date(System.currentTimeMillis()); - dateStamp = fileDateFormatter.format(currentDate); - - open(); - } - } - } - - // Log this message - if (writer != null) { - writer.println(message); - } - - } - - - /** - * Open the new log file for the date specified by dateStamp. - */ - private synchronized void open() { - - // Create the directory if necessary - File dir = new File(directory); - if (!dir.isAbsolute()) - dir = new File(System.getProperty("catalina.base"), directory); - dir.mkdirs(); - - // Open the current log file - try { - String pathname; - - // If no rotate - no need for dateStamp in fileName - if (rotatable){ - pathname = dir.getAbsolutePath() + File.separator + - prefix + dateStamp + suffix; - } else { - pathname = dir.getAbsolutePath() + File.separator + - prefix + suffix; - } - - currentLogFile = new File(pathname); - writer = new PrintWriter(new FileWriter(pathname, true), true); - if (currentLogFile.length()==0) { - writer.println("#Fields: " + pattern); - writer.println("#Version: 1.0"); - writer.println("#Software: " + ServerInfo.getServerInfo()); - } - - - } catch (IOException e) { - writer = null; - currentLogFile = null; - } - - } - - - /** - * This method returns a Date object that is accurate to within one - * second. If a thread calls this method to get a Date and it's been - * less than 1 second since a new Date was created, this method - * simply gives out the same Date again so that the system doesn't - * spend time creating Date objects unnecessarily. - */ - private Date getDate(long systime) { - /* Avoid extra call to System.currentTimeMillis(); */ - if (0==systime) { - systime = System.currentTimeMillis(); - } - - // Only create a new Date once per second, max. - if ((systime - currentDate.getTime()) > 1000) { - currentDate.setTime(systime); - } - - return currentDate; - - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to add - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("extendedAccessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Initialize the timeZone, Date formatters, and currentDate - TimeZone tz = TimeZone.getTimeZone("GMT"); - dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); - dateFormatter.setTimeZone(tz); - timeFormatter = new SimpleDateFormat("HH:mm:ss"); - timeFormatter.setTimeZone(tz); - currentDate = new Date(System.currentTimeMillis()); - if (fileDateFormat==null || fileDateFormat.length()==0) - fileDateFormat = "yyyy-MM-dd"; - fileDateFormatter = new SimpleDateFormat(fileDateFormat); - dateStamp = fileDateFormatter.format(currentDate); - timeTakenFormatter = new DecimalFormat("0.000"); - - /* Everybody say ick ... ick */ - try { - InetAddress inetAddress = InetAddress.getLocalHost(); - myIpAddress = inetAddress.getHostAddress(); - myDNSName = inetAddress.getHostName(); - } catch(Throwable e){ - myIpAddress="127.0.0.1"; - myDNSName="localhost"; - } - - open(); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("extendedAccessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - close(); - - } - - - /** - * Decode the given pattern. Is public so a pattern may - * allows to be validated. - * @param fields The pattern to decode - * @return null on error. Otherwise array of decoded fields - */ - public FieldInfo[] decodePattern(String fields) { - - if (log.isDebugEnabled()) - log.debug("decodePattern, fields=" + fields); - - LinkedList list = new LinkedList(); - - //Ignore leading whitespace. - int i=0; - for (;i=fields.length()) { - log.info("fields was just empty or whitespace"); - return null; - } - - int j; - while(i=fields.length()) { - if (j==i) { - // Special case - end of string - currentFieldInfo.postWhiteSpace = ""; - } else { - currentFieldInfo.postWhiteSpace = fields.substring(i); - i=j; - } - } else { - currentFieldInfo.postWhiteSpace = fields.substring(i,j); - i=j; - } - - list.add(currentFieldInfo); - } - - i=0; - FieldInfo[] f = new FieldInfo[list.size()]; - for (Iterator k = list.iterator(); k.hasNext();) - f[i++] = (FieldInfo)k.next(); - - if (log.isDebugEnabled()) - log.debug("finished decoding with length of: " + i); - - return f; - } - - /** - * Decode the cs or sc fields. - * Returns negative on error. - * - * @param fields The pattern to decode - * @param i The string index where we are decoding. - * @param fieldInfo Where to store the results - * @param type The type we are decoding. - * @return -1 on error. Otherwise the new String index. - */ - private int decode(String fields, int i, FieldInfo fieldInfo, short type) { - - if (fields.startsWith("-status",i)) { - fieldInfo.location = FieldInfo.FIELD_STATUS; - i+="-status".length(); - } else if (fields.startsWith("-comment",i)) { - fieldInfo.location = FieldInfo.FIELD_COMMENT; - i+="-comment".length(); - } else if (fields.startsWith("-uri-query",i)) { - fieldInfo.location = FieldInfo.FIELD_URI_QUERY; - i+="-uri-query".length(); - } else if (fields.startsWith("-uri-stem",i)) { - fieldInfo.location = FieldInfo.FIELD_URI_STEM; - i+="-uri-stem".length(); - } else if (fields.startsWith("-uri",i)) { - fieldInfo.location = FieldInfo.FIELD_URI; - i+="-uri".length(); - } else if (fields.startsWith("-method",i)) { - fieldInfo.location = FieldInfo.FIELD_METHOD; - i+="-method".length(); - } else if (fields.startsWith("(",i)) { - fieldInfo.location = FieldInfo.FIELD_HEADER; - i++; /* Move past the ( */ - int j = fields.indexOf(')', i); - if (j==-1) { /* Not found */ - log.error("No closing ) found for in decode"); - return -1; - } - fieldInfo.value = fields.substring(i,j); - i=j+1; // Move pointer past ) */ - } else { - log.error("The next characters couldn't be decoded: " + fields.substring(i)); - return -1; - } - - fieldInfo.type = type; - return i; - - } - - - /** - * Decode app specific log entry. - * - * Special fields are of the form: - * x-C(...) - For cookie - * x-A(...) - Value in servletContext - * x-S(...) - Value in session - * x-R(...) - Value in servletRequest - * @param fields The pattern to decode - * @param i The string index where we are decoding. - * @param fieldInfo Where to store the results - * @return -1 on error. Otherwise the new String index. - */ - private int decodeAppSpecific(String fields, int i, FieldInfo fieldInfo) { - - fieldInfo.type = FieldInfo.DATA_APP_SPECIFIC; - /* Move past 'x-' */ - i+=2; - - if (i>=fields.length()) { - log.error("End of line reached before decoding x- param"); - return -1; - } - - switch(fields.charAt(i)) { - case 'A': - fieldInfo.xType = FieldInfo.X_APP; - break; - case 'C': - fieldInfo.xType = FieldInfo.X_COOKIE; - break; - case 'R': - fieldInfo.xType = FieldInfo.X_REQUEST; - break; - case 'S': - fieldInfo.xType = FieldInfo.X_SESSION; - break; - case 'H': - fieldInfo.xType = FieldInfo.X_SERVLET_REQUEST; - break; - case 'P': - fieldInfo.xType = FieldInfo.X_PARAMETER; - break; - default: - return -1; - } - - /* test that next char is a ( */ - if (i+1!=fields.indexOf('(',i)) { - log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!"); - return -1; - } - i+=2; /* Move inside of the () */ - - /* Look for ending ) and return error if not found. */ - int j = fields.indexOf(')',i); - if (j==-1) { - log.error("x param in wrong format. No closing ')'!"); - return -1; - } - - fieldInfo.value = fields.substring(i,j); - - if (fieldInfo.xType == FieldInfo.X_SERVLET_REQUEST) { - if ("authType".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_AUTHTYPE; - } else if ("remoteUser".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_REMOTEUSER; - } else if ("requestedSessionId".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONID; - } else if ("requestedSessionIdFromCookie".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE; - } else if ("requestedSessionIdValid".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID; - } else if ("contentLength".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_CONTENTLENGTH; - } else if ("characterEncoding".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_CHARACTERENCODING; - } else if ("locale".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_LOCALE; - } else if ("protocol".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_PROTOCOL; - } else if ("scheme".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_SCHEME; - } else if ("secure".equals(fieldInfo.value)){ - fieldInfo.location = FieldInfo.X_LOC_SECURE; - } else { - log.error("x param for servlet request, couldn't decode value: " + - fieldInfo.location); - return -1; - } - } - - return j+1; - - } - - -} - -/** - * A simple helper for decoding the pattern. - */ -class FieldInfo { - /* - The goal of the constants listed below is to make the construction of the log - entry as quick as possible via numerci decodings of the methods to call instead - of performing many String comparisons on each logging request. - */ - - /* Where the data is located. */ - static final short DATA_CLIENT = 0; - static final short DATA_SERVER = 1; - static final short DATA_REMOTE = 2; - static final short DATA_CLIENT_TO_SERVER = 3; - static final short DATA_SERVER_TO_CLIENT = 4; - static final short DATA_SERVER_TO_RSERVER = 5; /* Here to honor the spec. */ - static final short DATA_RSERVER_TO_SERVER = 6; /* Here to honor the spec. */ - static final short DATA_APP_SPECIFIC = 7; - static final short DATA_SPECIAL = 8; - - /* The type of special fields. */ - static final short SPECIAL_DATE = 1; - static final short SPECIAL_TIME_TAKEN = 2; - static final short SPECIAL_TIME = 3; - static final short SPECIAL_BYTES = 4; - static final short SPECIAL_CACHED = 5; - - /* Where to pull the data for prefixed values */ - static final short FIELD_IP = 1; - static final short FIELD_DNS = 2; - static final short FIELD_STATUS = 3; - static final short FIELD_COMMENT = 4; - static final short FIELD_METHOD = 5; - static final short FIELD_URI = 6; - static final short FIELD_URI_STEM = 7; - static final short FIELD_URI_QUERY = 8; - static final short FIELD_HEADER = 9; - - - /* Application Specific parameters */ - static final short X_REQUEST = 1; /* For x app specific */ - static final short X_SESSION = 2; /* For x app specific */ - static final short X_COOKIE = 3; /* For x app specific */ - static final short X_APP = 4; /* For x app specific */ - static final short X_SERVLET_REQUEST = 5; /* For x app specific */ - static final short X_PARAMETER = 6; /* For x app specific */ - - static final short X_LOC_AUTHTYPE = 1; - static final short X_LOC_REMOTEUSER = 2; - static final short X_LOC_REQUESTEDSESSIONID = 3; - static final short X_LOC_REQUESTEDSESSIONIDFROMCOOKIE = 4; - static final short X_LOC_REQUESTEDSESSIONIDVALID = 5; - static final short X_LOC_CONTENTLENGTH = 6; - static final short X_LOC_CHARACTERENCODING = 7; - static final short X_LOC_LOCALE = 8; - static final short X_LOC_PROTOCOL = 9; - static final short X_LOC_SCHEME = 10; - static final short X_LOC_SECURE = 11; - - - - /** The field type */ - short type; - - /** Where to pull the data from? Icky variable name. */ - short location; - - /** The x- specific place to pull the data from. */ - short xType; - - /** The field value if needed. Needed for headers and app specific. */ - String value; - - /** Any white space after this field? Put it here. */ - String postWhiteSpace = null; - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.net.InetAddress; +import java.net.URLEncoder; +import java.text.DecimalFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.TimeZone; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpSession; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.ServerInfo; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + + +/** + * An implementation of the W3c Extended Log File Format. See + * http://www.w3.org/TR/WD-logfile.html for more information about the format. + * + * The following fields are supported: + *
          + *
        • c-dns: Client hostname
        • + *
        • c-ip: Client ip address
        • + *
        • bytes: bytes served
        • + *
        • cs-method: request method
        • + *
        • cs-uri: The full uri requested
        • + *
        • cs-uri-query: The query string
        • + *
        • cs-uri-stem: The uri without query string
        • + *
        • date: The date in yyyy-mm-dd format for GMT
        • + *
        • s-dns: The server dns entry
        • + *
        • s-ip: The server ip address
        • + *
        • cs(XXX): The value of header XXX from client to server
        • + *
        • sc(XXX): The value of header XXX from server to client
        • + *
        • sc-status: The status code
        • + *
        • time: Time the request was served
        • + *
        • time-taken: Time (in seconds) taken to serve the request
        • + *
        • x-A(XXX): Pull XXX attribute from the servlet context
        • + *
        • x-C(XXX): Pull the first cookie of the name XXX
        • + *
        • x-R(XXX): Pull XXX attribute from the servlet request
        • + *
        • x-S(XXX): Pull XXX attribute from the session
        • + *
        • x-P(...): Call request.getParameter(...) + * and URLencode it. Helpful to capture + * certain POST parameters. + *
        • + *
        • For any of the x-H(...) the following method will be called from the + * HttpServletRequestObject
        • + *
        • x-H(authType): getAuthType
        • + *
        • x-H(characterEncoding): getCharacterEncoding
        • + *
        • x-H(contentLength): getContentLength
        • + *
        • x-H(locale): getLocale
        • + *
        • x-H(protocol): getProtocol
        • + *
        • x-H(remoteUser): getRemoteUser
        • + *
        • x-H(requestedSessionId): getGequestedSessionId
        • + *
        • x-H(requestedSessionIdFromCookie): + * isRequestedSessionIdFromCookie
        • + *
        • x-H(requestedSessionIdValid): + * isRequestedSessionIdValid
        • + *
        • x-H(scheme): getScheme
        • + *
        • x-H(secure): isSecure
        • + *
        + * + * + * + *

        + * Log rotation can be on or off. This is dictated by the rotatable + * property. + *

        + * + *

        + * For UNIX users, another field called checkExistsis also + * available. If set to true, the log file's existence will be checked before + * each logging. This way an external log rotator can move the file + * somewhere and tomcat will start with a new file. + *

        + * + *

        + * For JMX junkies, a public method called rotate has + * been made available to allow you to tell this instance to move + * the existing log file to somewhere else start writing a new log file. + *

        + * + *

        + * Conditional logging is also supported. This can be done with the + * condition property. + * If the value returned from ServletRequest.getAttribute(condition) + * yields a non-null value. The logging will be skipped. + *

        + * + *

        + * For extended attributes coming from a getAttribute() call, + * it is you responsibility to ensure there are no newline or + * control characters. + *

        + * + * + * @author Tim Funk + * @version $Revision: 303601 $ $Date: 2004-12-24 00:58:07 +0100 (ven., 24 déc. 2004) $ + */ + +public class ExtendedAccessLogValve + extends ValveBase + implements Lifecycle { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class with default property values. + */ + public ExtendedAccessLogValve() { + + super(); + + + } + + + // ----------------------------------------------------- Instance Variables + private static Log log = LogFactory.getLog(ExtendedAccessLogValve.class); + + + /** + * The descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.valves.ExtendedAccessLogValve/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + + /** + * The string manager for this package. + */ + private StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + private boolean started = false; + + + /** + * The as-of date for the currently open log file, or a zero-length + * string if there is no open log file. + */ + private String dateStamp = ""; + + + /** + * The PrintWriter to which we are currently logging, if any. + */ + private PrintWriter writer = null; + + + /** + * The formatter for the date contained in the file name. + */ + private SimpleDateFormat fileDateFormatter = null; + + + /** + * A date formatter to format a Date into a date in the format + * "yyyy-MM-dd". + */ + private SimpleDateFormat dateFormatter = null; + + + /** + * A date formatter to format a Date into a time in the format + * "kk:mm:ss" (kk is a 24-hour representation of the hour). + */ + private SimpleDateFormat timeFormatter = null; + + + /** + * Time taken formatter for 3 decimal places. + */ + private DecimalFormat timeTakenFormatter = null; + + + /** + * My ip address. Look it up once and remember it. Dump this if we can + * determine another reliable way to get server ip address since this + * server may have many ip's. + */ + private String myIpAddress = null; + + + /** + * My dns name. Look it up once and remember it. Dump this if we can + * determine another reliable way to get server name address since this + * server may have many ip's. + */ + private String myDNSName = null; + + + /** + * Holder for all of the fields to log after the pattern is decoded. + */ + private FieldInfo[] fieldInfos; + + + /** + * The current log file we are writing to. Helpful when checkExists + * is true. + */ + private File currentLogFile = null; + + + + /** + * The system time when we last updated the Date that this valve + * uses for log lines. + */ + private Date currentDate = null; + + + /** + * Instant when the log daily rotation was last checked. + */ + private long rotationLastChecked = 0L; + + + /** + * The directory in which log files are created. + */ + private String directory = "logs"; + + + /** + * The pattern used to format our access log lines. + */ + private String pattern = null; + + + /** + * The prefix that is added to log file filenames. + */ + private String prefix = "access_log."; + + + /** + * Should we rotate our log file? Default is true (like old behavior) + */ + private boolean rotatable = true; + + + /** + * The suffix that is added to log file filenames. + */ + private String suffix = ""; + + + /** + * Are we doing conditional logging. default false. + */ + private String condition = null; + + + /** + * Do we check for log file existence? Helpful if an external + * agent renames the log file so we can automagically recreate it. + */ + private boolean checkExists = false; + + + /** + * Date format to place in log file name. Use at your own risk! + */ + private String fileDateFormat = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the directory in which we create log files. + */ + public String getDirectory() { + + return (directory); + + } + + + /** + * Set the directory in which we create log files. + * + * @param directory The new log file directory + */ + public void setDirectory(String directory) { + + this.directory = directory; + + } + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the format pattern. + */ + public String getPattern() { + + return (this.pattern); + + } + + + /** + * Set the format pattern, first translating any recognized alias. + * + * @param pattern The new pattern pattern + */ + public void setPattern(String pattern) { + + FieldInfo[] f= decodePattern(pattern); + if (f!=null) { + this.pattern = pattern; + this.fieldInfos = f; + } + } + + + /** + * Return the log file prefix. + */ + public String getPrefix() { + + return (prefix); + + } + + + /** + * Set the log file prefix. + * + * @param prefix The new log file prefix + */ + public void setPrefix(String prefix) { + + this.prefix = prefix; + + } + + + /** + * Return true if logs are automatically rotated. + */ + public boolean isRotatable() { + + return rotatable; + + } + + + /** + * Set the value is we should we rotate the logs + * + * @param rotatable true is we should rotate. + */ + public void setRotatable(boolean rotatable) { + + this.rotatable = rotatable; + + } + + + /** + * Return the log file suffix. + */ + public String getSuffix() { + + return (suffix); + + } + + + /** + * Set the log file suffix. + * + * @param suffix The new log file suffix + */ + public void setSuffix(String suffix) { + + this.suffix = suffix; + + } + + + + /** + * Return whether the attribute name to look for when + * performing conditional loggging. If null, every + * request is logged. + */ + public String getCondition() { + + return condition; + + } + + + /** + * Set the ServletRequest.attribute to look for to perform + * conditional logging. Set to null to log everything. + * + * @param condition Set to null to log everything + */ + public void setCondition(String condition) { + + this.condition = condition; + + } + + + + /** + * Check for file existence before logging. + */ + public boolean isCheckExists() { + + return checkExists; + + } + + + /** + * Set whether to check for log file existence before logging. + * + * @param checkExists true meaning to check for file existence. + */ + public void setCheckExists(boolean checkExists) { + + this.checkExists = checkExists; + + } + + + /** + * Return the date format date based log rotation. + */ + public String getFileDateFormat() { + return fileDateFormat; + } + + + /** + * Set the date format date based log rotation. + */ + public void setFileDateFormat(String fileDateFormat) { + this.fileDateFormat = fileDateFormat; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Log a message summarizing the specified request and response, according + * to the format specified by the pattern property. + * + * @param request Request being processed + * @param response Response being processed + * + * @exception IOException if an input/output error has occurred + * @exception ServletException if a servlet error has occurred + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + // Pass this request on to the next valve in our pipeline + long endTime; + long runTime; + long startTime=System.currentTimeMillis(); + + getNext().invoke(request, response); + + endTime = System.currentTimeMillis(); + runTime = endTime-startTime; + + if (fieldInfos==null || condition!=null && + null!=request.getRequest().getAttribute(condition)) { + return; + } + + + Date date = getDate(endTime); + StringBuffer result = new StringBuffer(); + + for (int i=0; fieldInfos!=null && i 0) + result.append(length); + else + result.append("-"); + } else if (FieldInfo.SPECIAL_CACHED==fieldInfos[i].location) + result.append('-'); /* I don't know how to evaluate this! */ + else + result.append("?WTF?"); /* This should never happen! */ + break; + default: + result.append("?WTF?"); /* This should never happen! */ + } + + if (fieldInfos[i].postWhiteSpace!=null) { + result.append(fieldInfos[i].postWhiteSpace); + } + } + log(result.toString(), date); + + } + + + /** + * Rename the existing log file to something else. Then open the + * old log file name up once again. Intended to be called by a JMX + * agent. + * + * + * @param newFileName The file name to move the log file entry to + * @return true if a file was rotated with no error + */ + public synchronized boolean rotate(String newFileName) { + + if (currentLogFile!=null) { + File holder = currentLogFile; + close(); + try { + holder.renameTo(new File(newFileName)); + } catch(Throwable e){ + log.error("rotate failed", e); + } + + /* Make sure date is correct */ + currentDate = new Date(System.currentTimeMillis()); + dateStamp = fileDateFormatter.format(currentDate); + + open(); + return true; + } else { + return false; + } + + } + + // -------------------------------------------------------- Private Methods + + + /** + * Return the client to server data. + * @param fieldInfo The field to decode. + * @param request The object we pull data from. + * @return The appropriate value. + */ + private String getClientToServer(FieldInfo fieldInfo, Request request) { + + switch(fieldInfo.location) { + case FieldInfo.FIELD_METHOD: + return request.getMethod(); + case FieldInfo.FIELD_URI: + if (null==request.getQueryString()) + return request.getRequestURI(); + else + return request.getRequestURI() + "?" + request.getQueryString(); + case FieldInfo.FIELD_URI_STEM: + return request.getRequestURI(); + case FieldInfo.FIELD_URI_QUERY: + if (null==request.getQueryString()) + return "-"; + return request.getQueryString(); + case FieldInfo.FIELD_HEADER: + return wrap(request.getHeader(fieldInfo.value)); + default: + ; + } + + return "-"; + + } + + + /** + * Return the server to client data. + * @param fieldInfo The field to decode. + * @param response The object we pull data from. + * @return The appropriate value. + */ + private String getServerToClient(FieldInfo fieldInfo, Response response) { + switch(fieldInfo.location) { + case FieldInfo.FIELD_STATUS: + return "" + response.getStatus(); + case FieldInfo.FIELD_COMMENT: + return "?"; /* Not coded yet*/ + case FieldInfo.FIELD_HEADER: + return wrap(response.getHeader(fieldInfo.value)); + default: + ; + } + + return "-"; + + } + + + /** + * Get app specific data. + * @param fieldInfo The field to decode + * @param request Where we will pull the data from. + * @return The appropriate value + */ + private String getAppSpecific(FieldInfo fieldInfo, Request request) { + + switch(fieldInfo.xType) { + case FieldInfo.X_PARAMETER: + return wrap(urlEncode(request.getParameter(fieldInfo.value))); + case FieldInfo.X_REQUEST: + return wrap(request.getAttribute(fieldInfo.value)); + case FieldInfo.X_SESSION: + HttpSession session = null; + if (request!=null){ + session = request.getSession(false); + if (session!=null) + return wrap(session.getAttribute(fieldInfo.value)); + } + break; + case FieldInfo.X_COOKIE: + Cookie[] c = request.getCookies(); + for (int i=0; c != null && i < c.length; i++){ + if (fieldInfo.value.equals(c[i].getName())){ + return wrap(c[i].getValue()); + } + } + case FieldInfo.X_APP: + return wrap(request.getContext().getServletContext() + .getAttribute(fieldInfo.value)); + case FieldInfo.X_SERVLET_REQUEST: + if (fieldInfo.location==FieldInfo.X_LOC_AUTHTYPE) { + return wrap(request.getAuthType()); + } else if (fieldInfo.location==FieldInfo.X_LOC_REMOTEUSER) { + return wrap(request.getRemoteUser()); + } else if (fieldInfo.location== + FieldInfo.X_LOC_REQUESTEDSESSIONID) { + return wrap(request.getRequestedSessionId()); + } else if (fieldInfo.location== + FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE) { + return wrap(""+request.isRequestedSessionIdFromCookie()); + } else if (fieldInfo.location== + FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID) { + return wrap(""+request.isRequestedSessionIdValid()); + } else if (fieldInfo.location==FieldInfo.X_LOC_CONTENTLENGTH) { + return wrap(""+request.getContentLength()); + } else if (fieldInfo.location== + FieldInfo.X_LOC_CHARACTERENCODING) { + return wrap(request.getCharacterEncoding()); + } else if (fieldInfo.location==FieldInfo.X_LOC_LOCALE) { + return wrap(request.getLocale()); + } else if (fieldInfo.location==FieldInfo.X_LOC_PROTOCOL) { + return wrap(request.getProtocol()); + } else if (fieldInfo.location==FieldInfo.X_LOC_SCHEME) { + return wrap(request.getScheme()); + } else if (fieldInfo.location==FieldInfo.X_LOC_SECURE) { + return wrap(""+request.isSecure()); + } + break; + default: + ; + } + + return "-"; + + } + + + /** + * urlEncode the given string. If null or empty, return null. + */ + private String urlEncode(String value) { + if (null==value || value.length()==0) { + return null; + } + return URLEncoder.encode(value); + } + + + /** + * Wrap the incoming value into quotes and escape any inner + * quotes with double quotes. + * + * @param value - The value to wrap quotes around + * @return '-' if empty of null. Otherwise, toString() will + * be called on the object and the value will be wrapped + * in quotes and any quotes will be escaped with 2 + * sets of quotes. + */ + private String wrap(Object value) { + + String svalue; + // Does the value contain a " ? If so must encode it + if (value==null || "-".equals(value)) + return "-"; + + + try { + svalue = value.toString(); + if ("".equals(svalue)) + return "-"; + } catch(Throwable e){ + /* Log error */ + return "-"; + } + + /* Wrap all quotes in double quotes. */ + StringBuffer buffer = new StringBuffer(svalue.length()+2); + buffer.append('"'); + int i=0; + while (i 1000) { + + // We need a new currentDate + currentDate = new Date(systime); + rotationLastChecked = systime; + + // Check for a change of date + String tsDate = fileDateFormatter.format(currentDate); + + // If the date has changed, switch log files + if (!dateStamp.equals(tsDate)) { + synchronized (this) { + if (!dateStamp.equals(tsDate)) { + close(); + dateStamp = tsDate; + open(); + } + } + } + } + } + + /* In case something external rotated the file instead */ + if (checkExists){ + synchronized (this) { + if (currentLogFile!=null && !currentLogFile.exists()) { + try { + close(); + } catch (Throwable e){ + log.info("at least this wasn't swallowed", e); + } + + /* Make sure date is correct */ + currentDate = new Date(System.currentTimeMillis()); + dateStamp = fileDateFormatter.format(currentDate); + + open(); + } + } + } + + // Log this message + if (writer != null) { + writer.println(message); + } + + } + + + /** + * Open the new log file for the date specified by dateStamp. + */ + private synchronized void open() { + + // Create the directory if necessary + File dir = new File(directory); + if (!dir.isAbsolute()) + dir = new File(System.getProperty("catalina.base"), directory); + dir.mkdirs(); + + // Open the current log file + try { + String pathname; + + // If no rotate - no need for dateStamp in fileName + if (rotatable){ + pathname = dir.getAbsolutePath() + File.separator + + prefix + dateStamp + suffix; + } else { + pathname = dir.getAbsolutePath() + File.separator + + prefix + suffix; + } + + currentLogFile = new File(pathname); + writer = new PrintWriter(new FileWriter(pathname, true), true); + if (currentLogFile.length()==0) { + writer.println("#Fields: " + pattern); + writer.println("#Version: 1.0"); + writer.println("#Software: " + ServerInfo.getServerInfo()); + } + + + } catch (IOException e) { + writer = null; + currentLogFile = null; + } + + } + + + /** + * This method returns a Date object that is accurate to within one + * second. If a thread calls this method to get a Date and it's been + * less than 1 second since a new Date was created, this method + * simply gives out the same Date again so that the system doesn't + * spend time creating Date objects unnecessarily. + */ + private Date getDate(long systime) { + /* Avoid extra call to System.currentTimeMillis(); */ + if (0==systime) { + systime = System.currentTimeMillis(); + } + + // Only create a new Date once per second, max. + if ((systime - currentDate.getTime()) > 1000) { + currentDate.setTime(systime); + } + + return currentDate; + + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("extendedAccessLogValve.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Initialize the timeZone, Date formatters, and currentDate + TimeZone tz = TimeZone.getTimeZone("GMT"); + dateFormatter = new SimpleDateFormat("yyyy-MM-dd"); + dateFormatter.setTimeZone(tz); + timeFormatter = new SimpleDateFormat("HH:mm:ss"); + timeFormatter.setTimeZone(tz); + currentDate = new Date(System.currentTimeMillis()); + if (fileDateFormat==null || fileDateFormat.length()==0) + fileDateFormat = "yyyy-MM-dd"; + fileDateFormatter = new SimpleDateFormat(fileDateFormat); + dateStamp = fileDateFormatter.format(currentDate); + timeTakenFormatter = new DecimalFormat("0.000"); + + /* Everybody say ick ... ick */ + try { + InetAddress inetAddress = InetAddress.getLocalHost(); + myIpAddress = inetAddress.getHostAddress(); + myDNSName = inetAddress.getHostName(); + } catch(Throwable e){ + myIpAddress="127.0.0.1"; + myDNSName="localhost"; + } + + open(); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("extendedAccessLogValve.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + close(); + + } + + + /** + * Decode the given pattern. Is public so a pattern may + * allows to be validated. + * @param fields The pattern to decode + * @return null on error. Otherwise array of decoded fields + */ + public FieldInfo[] decodePattern(String fields) { + + if (log.isDebugEnabled()) + log.debug("decodePattern, fields=" + fields); + + LinkedList list = new LinkedList(); + + //Ignore leading whitespace. + int i=0; + for (;i=fields.length()) { + log.info("fields was just empty or whitespace"); + return null; + } + + int j; + while(i=fields.length()) { + if (j==i) { + // Special case - end of string + currentFieldInfo.postWhiteSpace = ""; + } else { + currentFieldInfo.postWhiteSpace = fields.substring(i); + i=j; + } + } else { + currentFieldInfo.postWhiteSpace = fields.substring(i,j); + i=j; + } + + list.add(currentFieldInfo); + } + + i=0; + FieldInfo[] f = new FieldInfo[list.size()]; + for (Iterator k = list.iterator(); k.hasNext();) + f[i++] = (FieldInfo)k.next(); + + if (log.isDebugEnabled()) + log.debug("finished decoding with length of: " + i); + + return f; + } + + /** + * Decode the cs or sc fields. + * Returns negative on error. + * + * @param fields The pattern to decode + * @param i The string index where we are decoding. + * @param fieldInfo Where to store the results + * @param type The type we are decoding. + * @return -1 on error. Otherwise the new String index. + */ + private int decode(String fields, int i, FieldInfo fieldInfo, short type) { + + if (fields.startsWith("-status",i)) { + fieldInfo.location = FieldInfo.FIELD_STATUS; + i+="-status".length(); + } else if (fields.startsWith("-comment",i)) { + fieldInfo.location = FieldInfo.FIELD_COMMENT; + i+="-comment".length(); + } else if (fields.startsWith("-uri-query",i)) { + fieldInfo.location = FieldInfo.FIELD_URI_QUERY; + i+="-uri-query".length(); + } else if (fields.startsWith("-uri-stem",i)) { + fieldInfo.location = FieldInfo.FIELD_URI_STEM; + i+="-uri-stem".length(); + } else if (fields.startsWith("-uri",i)) { + fieldInfo.location = FieldInfo.FIELD_URI; + i+="-uri".length(); + } else if (fields.startsWith("-method",i)) { + fieldInfo.location = FieldInfo.FIELD_METHOD; + i+="-method".length(); + } else if (fields.startsWith("(",i)) { + fieldInfo.location = FieldInfo.FIELD_HEADER; + i++; /* Move past the ( */ + int j = fields.indexOf(')', i); + if (j==-1) { /* Not found */ + log.error("No closing ) found for in decode"); + return -1; + } + fieldInfo.value = fields.substring(i,j); + i=j+1; // Move pointer past ) */ + } else { + log.error("The next characters couldn't be decoded: " + fields.substring(i)); + return -1; + } + + fieldInfo.type = type; + return i; + + } + + + /** + * Decode app specific log entry. + * + * Special fields are of the form: + * x-C(...) - For cookie + * x-A(...) - Value in servletContext + * x-S(...) - Value in session + * x-R(...) - Value in servletRequest + * @param fields The pattern to decode + * @param i The string index where we are decoding. + * @param fieldInfo Where to store the results + * @return -1 on error. Otherwise the new String index. + */ + private int decodeAppSpecific(String fields, int i, FieldInfo fieldInfo) { + + fieldInfo.type = FieldInfo.DATA_APP_SPECIFIC; + /* Move past 'x-' */ + i+=2; + + if (i>=fields.length()) { + log.error("End of line reached before decoding x- param"); + return -1; + } + + switch(fields.charAt(i)) { + case 'A': + fieldInfo.xType = FieldInfo.X_APP; + break; + case 'C': + fieldInfo.xType = FieldInfo.X_COOKIE; + break; + case 'R': + fieldInfo.xType = FieldInfo.X_REQUEST; + break; + case 'S': + fieldInfo.xType = FieldInfo.X_SESSION; + break; + case 'H': + fieldInfo.xType = FieldInfo.X_SERVLET_REQUEST; + break; + case 'P': + fieldInfo.xType = FieldInfo.X_PARAMETER; + break; + default: + return -1; + } + + /* test that next char is a ( */ + if (i+1!=fields.indexOf('(',i)) { + log.error("x param in wrong format. Needs to be 'x-#(...)' read the docs!"); + return -1; + } + i+=2; /* Move inside of the () */ + + /* Look for ending ) and return error if not found. */ + int j = fields.indexOf(')',i); + if (j==-1) { + log.error("x param in wrong format. No closing ')'!"); + return -1; + } + + fieldInfo.value = fields.substring(i,j); + + if (fieldInfo.xType == FieldInfo.X_SERVLET_REQUEST) { + if ("authType".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_AUTHTYPE; + } else if ("remoteUser".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_REMOTEUSER; + } else if ("requestedSessionId".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONID; + } else if ("requestedSessionIdFromCookie".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDFROMCOOKIE; + } else if ("requestedSessionIdValid".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_REQUESTEDSESSIONIDVALID; + } else if ("contentLength".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_CONTENTLENGTH; + } else if ("characterEncoding".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_CHARACTERENCODING; + } else if ("locale".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_LOCALE; + } else if ("protocol".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_PROTOCOL; + } else if ("scheme".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_SCHEME; + } else if ("secure".equals(fieldInfo.value)){ + fieldInfo.location = FieldInfo.X_LOC_SECURE; + } else { + log.error("x param for servlet request, couldn't decode value: " + + fieldInfo.location); + return -1; + } + } + + return j+1; + + } + + +} + +/** + * A simple helper for decoding the pattern. + */ +class FieldInfo { + /* + The goal of the constants listed below is to make the construction of the log + entry as quick as possible via numerci decodings of the methods to call instead + of performing many String comparisons on each logging request. + */ + + /* Where the data is located. */ + static final short DATA_CLIENT = 0; + static final short DATA_SERVER = 1; + static final short DATA_REMOTE = 2; + static final short DATA_CLIENT_TO_SERVER = 3; + static final short DATA_SERVER_TO_CLIENT = 4; + static final short DATA_SERVER_TO_RSERVER = 5; /* Here to honor the spec. */ + static final short DATA_RSERVER_TO_SERVER = 6; /* Here to honor the spec. */ + static final short DATA_APP_SPECIFIC = 7; + static final short DATA_SPECIAL = 8; + + /* The type of special fields. */ + static final short SPECIAL_DATE = 1; + static final short SPECIAL_TIME_TAKEN = 2; + static final short SPECIAL_TIME = 3; + static final short SPECIAL_BYTES = 4; + static final short SPECIAL_CACHED = 5; + + /* Where to pull the data for prefixed values */ + static final short FIELD_IP = 1; + static final short FIELD_DNS = 2; + static final short FIELD_STATUS = 3; + static final short FIELD_COMMENT = 4; + static final short FIELD_METHOD = 5; + static final short FIELD_URI = 6; + static final short FIELD_URI_STEM = 7; + static final short FIELD_URI_QUERY = 8; + static final short FIELD_HEADER = 9; + + + /* Application Specific parameters */ + static final short X_REQUEST = 1; /* For x app specific */ + static final short X_SESSION = 2; /* For x app specific */ + static final short X_COOKIE = 3; /* For x app specific */ + static final short X_APP = 4; /* For x app specific */ + static final short X_SERVLET_REQUEST = 5; /* For x app specific */ + static final short X_PARAMETER = 6; /* For x app specific */ + + static final short X_LOC_AUTHTYPE = 1; + static final short X_LOC_REMOTEUSER = 2; + static final short X_LOC_REQUESTEDSESSIONID = 3; + static final short X_LOC_REQUESTEDSESSIONIDFROMCOOKIE = 4; + static final short X_LOC_REQUESTEDSESSIONIDVALID = 5; + static final short X_LOC_CONTENTLENGTH = 6; + static final short X_LOC_CHARACTERENCODING = 7; + static final short X_LOC_LOCALE = 8; + static final short X_LOC_PROTOCOL = 9; + static final short X_LOC_SCHEME = 10; + static final short X_LOC_SECURE = 11; + + + + /** The field type */ + short type; + + /** Where to pull the data from? Icky variable name. */ + short location; + + /** The x- specific place to pull the data from. */ + short xType; + + /** The field value if needed. Needed for headers and app specific. */ + String value; + + /** Any white space after this field? Put it here. */ + String postWhiteSpace = null; + +} diff --git a/java/org/apache/catalina/valves/FastCommonAccessLogValve.java b/java/org/apache/catalina/valves/FastCommonAccessLogValve.java index a2254443a..606f77b40 100644 --- a/java/org/apache/catalina/valves/FastCommonAccessLogValve.java +++ b/java/org/apache/catalina/valves/FastCommonAccessLogValve.java @@ -1,855 +1,855 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.TimeZone; - -import javax.servlet.ServletException; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; - - -/** - *

        Implementation of the Valve interface that generates a web server - * access log with the detailed line contents matching either the common or - * combined patterns. As an additional feature, automatic rollover of log files - * when the date changes is also supported.

        - *

        - * Conditional logging is also supported. This can be done with the - * condition property. - * If the value returned from ServletRequest.getAttribute(condition) - * yields a non-null value. The logging will be skipped. - *

        - * - * @author Craig R. McClanahan - * @author Jason Brittain - * @author Remy Maucherat - * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ - */ - -public final class FastCommonAccessLogValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new instance of this class with default property values. - */ - public FastCommonAccessLogValve() { - - super(); - setPattern("common"); - - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The as-of date for the currently open log file, or a zero-length - * string if there is no open log file. - */ - private String dateStamp = ""; - - - /** - * The directory in which log files are created. - */ - private String directory = "logs"; - - - /** - * The descriptive information about this implementation. - */ - protected static final String info = - "org.apache.catalina.valves.FastCommonAccessLogValve/1.0"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The set of month abbreviations for log messages. - */ - protected static final String months[] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - - - /** - * If the current log pattern is the same as the common access log - * format pattern, then we'll set this variable to true and log in - * a more optimal and hard-coded way. - */ - private boolean common = false; - - - /** - * For the combined format (common, plus useragent and referer), we do - * the same - */ - private boolean combined = false; - - - /** - * The pattern used to format our access log lines. - */ - private String pattern = null; - - - /** - * The prefix that is added to log file filenames. - */ - private String prefix = "access_log."; - - - /** - * Should we rotate our log file? Default is true (like old behavior) - */ - private boolean rotatable = true; - - - /** - * The string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = ""; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = null; - - - /** - * A date formatter to format a Date into a date in the format - * "yyyy-MM-dd". - */ - private SimpleDateFormat dateFormatter = null; - - - /** - * A date formatter to format Dates into a day string in the format - * "dd". - */ - private SimpleDateFormat dayFormatter = null; - - - /** - * A date formatter to format a Date into a month string in the format - * "MM". - */ - private SimpleDateFormat monthFormatter = null; - - - /** - * A date formatter to format a Date into a year string in the format - * "yyyy". - */ - private SimpleDateFormat yearFormatter = null; - - - /** - * A date formatter to format a Date into a time in the format - * "kk:mm:ss" (kk is a 24-hour representation of the hour). - */ - private SimpleDateFormat timeFormatter = null; - - - /** - * The system timezone. - */ - private TimeZone timezone = null; - - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is not in operation. - */ - private String timeZoneNoDST = null; - - /** - * The time zone offset relative to GMT in text form when daylight saving - * is in operation. - */ - private String timeZoneDST = null; - - - /** - * The system time when we last updated the Date that this valve - * uses for log lines. - */ - private String currentDateString = null; - - - /** - * The instant where the date string was last updated. - */ - private long currentDate = 0L; - - - /** - * When formatting log lines, we often use strings like this one (" "). - */ - private String space = " "; - - - /** - * Resolve hosts. - */ - private boolean resolveHosts = false; - - - /** - * Instant when the log daily rotation was last checked. - */ - private long rotationLastChecked = 0L; - - - /** - * Are we doing conditional logging. default false. - */ - private String condition = null; - - - /** - * Date format to place in log file name. Use at your own risk! - */ - private String fileDateFormat = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the directory in which we create log files. - */ - public String getDirectory() { - - return (directory); - - } - - - /** - * Set the directory in which we create log files. - * - * @param directory The new log file directory - */ - public void setDirectory(String directory) { - - this.directory = directory; - - } - - - /** - * Return descriptive information about this implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the format pattern. - */ - public String getPattern() { - - return (this.pattern); - - } - - - /** - * Set the format pattern, first translating any recognized alias. - * - * @param pattern The new pattern - */ - public void setPattern(String pattern) { - - if (pattern == null) - pattern = ""; - if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) - pattern = Constants.AccessLog.COMMON_PATTERN; - if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) - pattern = Constants.AccessLog.COMBINED_PATTERN; - this.pattern = pattern; - - if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) - combined = true; - else - combined = false; - - } - - - /** - * Return the log file prefix. - */ - public String getPrefix() { - - return (prefix); - - } - - - /** - * Set the log file prefix. - * - * @param prefix The new log file prefix - */ - public void setPrefix(String prefix) { - - this.prefix = prefix; - - } - - - /** - * Should we rotate the logs - */ - public boolean isRotatable() { - - return rotatable; - - } - - - /** - * Set the value is we should we rotate the logs - * - * @param rotatable true is we should rotate. - */ - public void setRotatable(boolean rotatable) { - - this.rotatable = rotatable; - - } - - - /** - * Return the log file suffix. - */ - public String getSuffix() { - - return (suffix); - - } - - - /** - * Set the log file suffix. - * - * @param suffix The new log file suffix - */ - public void setSuffix(String suffix) { - - this.suffix = suffix; - - } - - - /** - * Set the resolve hosts flag. - * - * @param resolveHosts The new resolve hosts value - */ - public void setResolveHosts(boolean resolveHosts) { - - this.resolveHosts = resolveHosts; - - } - - - /** - * Get the value of the resolve hosts flag. - */ - public boolean isResolveHosts() { - - return resolveHosts; - - } - - - /** - * Return whether the attribute name to look for when - * performing conditional loggging. If null, every - * request is logged. - */ - public String getCondition() { - - return condition; - - } - - - /** - * Set the ServletRequest.attribute to look for to perform - * conditional logging. Set to null to log everything. - * - * @param condition Set to null to log everything - */ - public void setCondition(String condition) { - - this.condition = condition; - - } - - /** - * Return the date format date based log rotation. - */ - public String getFileDateFormat() { - return fileDateFormat; - } - - - /** - * Set the date format date based log rotation. - */ - public void setFileDateFormat(String fileDateFormat) { - this.fileDateFormat = fileDateFormat; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - if (writer != null) - writer.flush(); - } - - - /** - * Log a message summarizing the specified request and response, according - * to the format specified by the pattern property. - * - * @param request Request being processed - * @param response Response being processed - * - * @exception IOException if an input/output error has occurred - * @exception ServletException if a servlet error has occurred - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - // Pass this request on to the next valve in our pipeline - getNext().invoke(request, response); - - if (condition!=null && - null!=request.getRequest().getAttribute(condition)) { - return; - } - - StringBuffer result = new StringBuffer(); - - // Check to see if we should log using the "common" access log pattern - String value = null; - - if (isResolveHosts()) - result.append(request.getRemoteHost()); - else - result.append(request.getRemoteAddr()); - - result.append(" - "); - - value = request.getRemoteUser(); - if (value == null) - result.append("- "); - else { - result.append(value); - result.append(space); - } - - result.append(getCurrentDateString()); - - result.append(request.getMethod()); - result.append(space); - result.append(request.getRequestURI()); - if (request.getQueryString() != null) { - result.append('?'); - result.append(request.getQueryString()); - } - result.append(space); - result.append(request.getProtocol()); - result.append("\" "); - - result.append(response.getStatus()); - - result.append(space); - - int length = response.getContentCount(); - - if (length <= 0) - value = "-"; - else - value = "" + length; - result.append(value); - - if (combined) { - result.append(space); - result.append("\""); - String referer = request.getHeader("referer"); - if(referer != null) - result.append(referer); - else - result.append("-"); - result.append("\""); - - result.append(space); - result.append("\""); - String ua = request.getHeader("user-agent"); - if(ua != null) - result.append(ua); - else - result.append("-"); - result.append("\""); - } - - log(result.toString()); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Close the currently open log file (if any) - */ - private synchronized void close() { - - if (writer == null) - return; - writer.flush(); - writer.close(); - writer = null; - dateStamp = ""; - - } - - - /** - * Log the specified message to the log file, switching files if the date - * has changed since the previous log call. - * - * @param message Message to be logged - */ - public void log(String message) { - - // Log this message - if (writer != null) { - writer.println(message); - } - - } - - - /** - * Return the month abbreviation for the specified month, which must - * be a two-digit String. - * - * @param month Month number ("01" .. "12"). - */ - private String lookup(String month) { - - int index; - try { - index = Integer.parseInt(month) - 1; - } catch (Throwable t) { - index = 0; // Can not happen, in theory - } - return (months[index]); - - } - - - /** - * Open the new log file for the date specified by dateStamp. - */ - private synchronized void open() { - - // Create the directory if necessary - File dir = new File(directory); - if (!dir.isAbsolute()) - dir = new File(System.getProperty("catalina.base"), directory); - dir.mkdirs(); - - // Open the current log file - try { - String pathname; - // If no rotate - no need for dateStamp in fileName - if (rotatable){ - pathname = dir.getAbsolutePath() + File.separator + - prefix + dateStamp + suffix; - } else { - pathname = dir.getAbsolutePath() + File.separator + - prefix + suffix; - } - writer = new PrintWriter(new BufferedWriter - (new FileWriter(pathname, true), 128000), false); - } catch (IOException e) { - writer = null; - } - - } - - - /** - * This method returns a Date object that is accurate to within one - * second. If a thread calls this method to get a Date and it's been - * less than 1 second since a new Date was created, this method - * simply gives out the same Date again so that the system doesn't - * spend time creating Date objects unnecessarily. - * - * @return Date - */ - private String getCurrentDateString() { - // Only create a new Date once per second, max. - long systime = System.currentTimeMillis(); - if ((systime - currentDate) > 1000) { - synchronized (this) { - // We don't care about being exact here: if an entry does get - // logged as having happened during the previous second - // it will not make any difference - if ((systime - currentDate) > 1000) { - - // Format the new date - Date date = new Date(); - StringBuffer result = new StringBuffer(32); - result.append("["); - // Day - result.append(dayFormatter.format(date)); - result.append('/'); - // Month - result.append(lookup(monthFormatter.format(date))); - result.append('/'); - // Year - result.append(yearFormatter.format(date)); - result.append(':'); - // Time - result.append(timeFormatter.format(date)); - result.append(space); - // Time zone - result.append(getTimeZone(date)); - result.append("] \""); - - // Check for log rotation - if (rotatable) { - // Check for a change of date - String tsDate = dateFormatter.format(date); - // If the date has changed, switch log files - if (!dateStamp.equals(tsDate)) { - synchronized (this) { - if (!dateStamp.equals(tsDate)) { - close(); - dateStamp = tsDate; - open(); - } - } - } - } - - currentDateString = result.toString(); - currentDate = date.getTime(); - } - } - } - return currentDateString; - } - - - private String getTimeZone(Date date) { - if (timezone.inDaylightTime(date)) { - return timeZoneDST; - } else { - return timeZoneNoDST; - } - } - - - private String calculateTimeZoneOffset(long offset) { - StringBuffer tz = new StringBuffer(); - if ((offset<0)) { - tz.append("-"); - offset = -offset; - } else { - tz.append("+"); - } - - long hourOffset = offset/(1000*60*60); - long minuteOffset = (offset/(1000*60)) % 60; - - if (hourOffset<10) - tz.append("0"); - tz.append(hourOffset); - - if (minuteOffset<10) - tz.append("0"); - tz.append(minuteOffset); - - return tz.toString(); - } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to add - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("accessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - // Initialize the timeZone, Date formatters, and currentDate - timezone = TimeZone.getDefault(); - timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); - Calendar calendar = Calendar.getInstance(timezone); - int offset = calendar.get(Calendar.DST_OFFSET); - timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); - - if (fileDateFormat==null || fileDateFormat.length()==0) - fileDateFormat = "yyyy-MM-dd"; - dateFormatter = new SimpleDateFormat(fileDateFormat); - dateFormatter.setTimeZone(timezone); - dayFormatter = new SimpleDateFormat("dd"); - dayFormatter.setTimeZone(timezone); - monthFormatter = new SimpleDateFormat("MM"); - monthFormatter.setTimeZone(timezone); - yearFormatter = new SimpleDateFormat("yyyy"); - yearFormatter.setTimeZone(timezone); - timeFormatter = new SimpleDateFormat("HH:mm:ss"); - timeFormatter.setTimeZone(timezone); - currentDateString = getCurrentDateString(); - dateStamp = dateFormatter.format(new Date()); - - open(); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("accessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - close(); - - } -} +/* + * Copyright 1999-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.text.SimpleDateFormat; +import java.util.Calendar; +import java.util.Date; +import java.util.TimeZone; + +import javax.servlet.ServletException; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; + + +/** + *

        Implementation of the Valve interface that generates a web server + * access log with the detailed line contents matching either the common or + * combined patterns. As an additional feature, automatic rollover of log files + * when the date changes is also supported.

        + *

        + * Conditional logging is also supported. This can be done with the + * condition property. + * If the value returned from ServletRequest.getAttribute(condition) + * yields a non-null value. The logging will be skipped. + *

        + * + * @author Craig R. McClanahan + * @author Jason Brittain + * @author Remy Maucherat + * @version $Revision: 304032 $ $Date: 2005-07-27 17:11:55 +0200 (mer., 27 juil. 2005) $ + */ + +public final class FastCommonAccessLogValve + extends ValveBase + implements Lifecycle { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new instance of this class with default property values. + */ + public FastCommonAccessLogValve() { + + super(); + setPattern("common"); + + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The as-of date for the currently open log file, or a zero-length + * string if there is no open log file. + */ + private String dateStamp = ""; + + + /** + * The directory in which log files are created. + */ + private String directory = "logs"; + + + /** + * The descriptive information about this implementation. + */ + protected static final String info = + "org.apache.catalina.valves.FastCommonAccessLogValve/1.0"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The set of month abbreviations for log messages. + */ + protected static final String months[] = + { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + + + /** + * If the current log pattern is the same as the common access log + * format pattern, then we'll set this variable to true and log in + * a more optimal and hard-coded way. + */ + private boolean common = false; + + + /** + * For the combined format (common, plus useragent and referer), we do + * the same + */ + private boolean combined = false; + + + /** + * The pattern used to format our access log lines. + */ + private String pattern = null; + + + /** + * The prefix that is added to log file filenames. + */ + private String prefix = "access_log."; + + + /** + * Should we rotate our log file? Default is true (like old behavior) + */ + private boolean rotatable = true; + + + /** + * The string manager for this package. + */ + private StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + private boolean started = false; + + + /** + * The suffix that is added to log file filenames. + */ + private String suffix = ""; + + + /** + * The PrintWriter to which we are currently logging, if any. + */ + private PrintWriter writer = null; + + + /** + * A date formatter to format a Date into a date in the format + * "yyyy-MM-dd". + */ + private SimpleDateFormat dateFormatter = null; + + + /** + * A date formatter to format Dates into a day string in the format + * "dd". + */ + private SimpleDateFormat dayFormatter = null; + + + /** + * A date formatter to format a Date into a month string in the format + * "MM". + */ + private SimpleDateFormat monthFormatter = null; + + + /** + * A date formatter to format a Date into a year string in the format + * "yyyy". + */ + private SimpleDateFormat yearFormatter = null; + + + /** + * A date formatter to format a Date into a time in the format + * "kk:mm:ss" (kk is a 24-hour representation of the hour). + */ + private SimpleDateFormat timeFormatter = null; + + + /** + * The system timezone. + */ + private TimeZone timezone = null; + + + /** + * The time zone offset relative to GMT in text form when daylight saving + * is not in operation. + */ + private String timeZoneNoDST = null; + + /** + * The time zone offset relative to GMT in text form when daylight saving + * is in operation. + */ + private String timeZoneDST = null; + + + /** + * The system time when we last updated the Date that this valve + * uses for log lines. + */ + private String currentDateString = null; + + + /** + * The instant where the date string was last updated. + */ + private long currentDate = 0L; + + + /** + * When formatting log lines, we often use strings like this one (" "). + */ + private String space = " "; + + + /** + * Resolve hosts. + */ + private boolean resolveHosts = false; + + + /** + * Instant when the log daily rotation was last checked. + */ + private long rotationLastChecked = 0L; + + + /** + * Are we doing conditional logging. default false. + */ + private String condition = null; + + + /** + * Date format to place in log file name. Use at your own risk! + */ + private String fileDateFormat = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the directory in which we create log files. + */ + public String getDirectory() { + + return (directory); + + } + + + /** + * Set the directory in which we create log files. + * + * @param directory The new log file directory + */ + public void setDirectory(String directory) { + + this.directory = directory; + + } + + + /** + * Return descriptive information about this implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the format pattern. + */ + public String getPattern() { + + return (this.pattern); + + } + + + /** + * Set the format pattern, first translating any recognized alias. + * + * @param pattern The new pattern + */ + public void setPattern(String pattern) { + + if (pattern == null) + pattern = ""; + if (pattern.equals(Constants.AccessLog.COMMON_ALIAS)) + pattern = Constants.AccessLog.COMMON_PATTERN; + if (pattern.equals(Constants.AccessLog.COMBINED_ALIAS)) + pattern = Constants.AccessLog.COMBINED_PATTERN; + this.pattern = pattern; + + if (this.pattern.equals(Constants.AccessLog.COMBINED_PATTERN)) + combined = true; + else + combined = false; + + } + + + /** + * Return the log file prefix. + */ + public String getPrefix() { + + return (prefix); + + } + + + /** + * Set the log file prefix. + * + * @param prefix The new log file prefix + */ + public void setPrefix(String prefix) { + + this.prefix = prefix; + + } + + + /** + * Should we rotate the logs + */ + public boolean isRotatable() { + + return rotatable; + + } + + + /** + * Set the value is we should we rotate the logs + * + * @param rotatable true is we should rotate. + */ + public void setRotatable(boolean rotatable) { + + this.rotatable = rotatable; + + } + + + /** + * Return the log file suffix. + */ + public String getSuffix() { + + return (suffix); + + } + + + /** + * Set the log file suffix. + * + * @param suffix The new log file suffix + */ + public void setSuffix(String suffix) { + + this.suffix = suffix; + + } + + + /** + * Set the resolve hosts flag. + * + * @param resolveHosts The new resolve hosts value + */ + public void setResolveHosts(boolean resolveHosts) { + + this.resolveHosts = resolveHosts; + + } + + + /** + * Get the value of the resolve hosts flag. + */ + public boolean isResolveHosts() { + + return resolveHosts; + + } + + + /** + * Return whether the attribute name to look for when + * performing conditional loggging. If null, every + * request is logged. + */ + public String getCondition() { + + return condition; + + } + + + /** + * Set the ServletRequest.attribute to look for to perform + * conditional logging. Set to null to log everything. + * + * @param condition Set to null to log everything + */ + public void setCondition(String condition) { + + this.condition = condition; + + } + + /** + * Return the date format date based log rotation. + */ + public String getFileDateFormat() { + return fileDateFormat; + } + + + /** + * Set the date format date based log rotation. + */ + public void setFileDateFormat(String fileDateFormat) { + this.fileDateFormat = fileDateFormat; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + if (writer != null) + writer.flush(); + } + + + /** + * Log a message summarizing the specified request and response, according + * to the format specified by the pattern property. + * + * @param request Request being processed + * @param response Response being processed + * + * @exception IOException if an input/output error has occurred + * @exception ServletException if a servlet error has occurred + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + // Pass this request on to the next valve in our pipeline + getNext().invoke(request, response); + + if (condition!=null && + null!=request.getRequest().getAttribute(condition)) { + return; + } + + StringBuffer result = new StringBuffer(); + + // Check to see if we should log using the "common" access log pattern + String value = null; + + if (isResolveHosts()) + result.append(request.getRemoteHost()); + else + result.append(request.getRemoteAddr()); + + result.append(" - "); + + value = request.getRemoteUser(); + if (value == null) + result.append("- "); + else { + result.append(value); + result.append(space); + } + + result.append(getCurrentDateString()); + + result.append(request.getMethod()); + result.append(space); + result.append(request.getRequestURI()); + if (request.getQueryString() != null) { + result.append('?'); + result.append(request.getQueryString()); + } + result.append(space); + result.append(request.getProtocol()); + result.append("\" "); + + result.append(response.getStatus()); + + result.append(space); + + int length = response.getContentCount(); + + if (length <= 0) + value = "-"; + else + value = "" + length; + result.append(value); + + if (combined) { + result.append(space); + result.append("\""); + String referer = request.getHeader("referer"); + if(referer != null) + result.append(referer); + else + result.append("-"); + result.append("\""); + + result.append(space); + result.append("\""); + String ua = request.getHeader("user-agent"); + if(ua != null) + result.append(ua); + else + result.append("-"); + result.append("\""); + } + + log(result.toString()); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Close the currently open log file (if any) + */ + private synchronized void close() { + + if (writer == null) + return; + writer.flush(); + writer.close(); + writer = null; + dateStamp = ""; + + } + + + /** + * Log the specified message to the log file, switching files if the date + * has changed since the previous log call. + * + * @param message Message to be logged + */ + public void log(String message) { + + // Log this message + if (writer != null) { + writer.println(message); + } + + } + + + /** + * Return the month abbreviation for the specified month, which must + * be a two-digit String. + * + * @param month Month number ("01" .. "12"). + */ + private String lookup(String month) { + + int index; + try { + index = Integer.parseInt(month) - 1; + } catch (Throwable t) { + index = 0; // Can not happen, in theory + } + return (months[index]); + + } + + + /** + * Open the new log file for the date specified by dateStamp. + */ + private synchronized void open() { + + // Create the directory if necessary + File dir = new File(directory); + if (!dir.isAbsolute()) + dir = new File(System.getProperty("catalina.base"), directory); + dir.mkdirs(); + + // Open the current log file + try { + String pathname; + // If no rotate - no need for dateStamp in fileName + if (rotatable){ + pathname = dir.getAbsolutePath() + File.separator + + prefix + dateStamp + suffix; + } else { + pathname = dir.getAbsolutePath() + File.separator + + prefix + suffix; + } + writer = new PrintWriter(new BufferedWriter + (new FileWriter(pathname, true), 128000), false); + } catch (IOException e) { + writer = null; + } + + } + + + /** + * This method returns a Date object that is accurate to within one + * second. If a thread calls this method to get a Date and it's been + * less than 1 second since a new Date was created, this method + * simply gives out the same Date again so that the system doesn't + * spend time creating Date objects unnecessarily. + * + * @return Date + */ + private String getCurrentDateString() { + // Only create a new Date once per second, max. + long systime = System.currentTimeMillis(); + if ((systime - currentDate) > 1000) { + synchronized (this) { + // We don't care about being exact here: if an entry does get + // logged as having happened during the previous second + // it will not make any difference + if ((systime - currentDate) > 1000) { + + // Format the new date + Date date = new Date(); + StringBuffer result = new StringBuffer(32); + result.append("["); + // Day + result.append(dayFormatter.format(date)); + result.append('/'); + // Month + result.append(lookup(monthFormatter.format(date))); + result.append('/'); + // Year + result.append(yearFormatter.format(date)); + result.append(':'); + // Time + result.append(timeFormatter.format(date)); + result.append(space); + // Time zone + result.append(getTimeZone(date)); + result.append("] \""); + + // Check for log rotation + if (rotatable) { + // Check for a change of date + String tsDate = dateFormatter.format(date); + // If the date has changed, switch log files + if (!dateStamp.equals(tsDate)) { + synchronized (this) { + if (!dateStamp.equals(tsDate)) { + close(); + dateStamp = tsDate; + open(); + } + } + } + } + + currentDateString = result.toString(); + currentDate = date.getTime(); + } + } + } + return currentDateString; + } + + + private String getTimeZone(Date date) { + if (timezone.inDaylightTime(date)) { + return timeZoneDST; + } else { + return timeZoneNoDST; + } + } + + + private String calculateTimeZoneOffset(long offset) { + StringBuffer tz = new StringBuffer(); + if ((offset<0)) { + tz.append("-"); + offset = -offset; + } else { + tz.append("+"); + } + + long hourOffset = offset/(1000*60*60); + long minuteOffset = (offset/(1000*60)) % 60; + + if (hourOffset<10) + tz.append("0"); + tz.append(hourOffset); + + if (minuteOffset<10) + tz.append("0"); + tz.append(minuteOffset); + + return tz.toString(); + } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("accessLogValve.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + // Initialize the timeZone, Date formatters, and currentDate + timezone = TimeZone.getDefault(); + timeZoneNoDST = calculateTimeZoneOffset(timezone.getRawOffset()); + Calendar calendar = Calendar.getInstance(timezone); + int offset = calendar.get(Calendar.DST_OFFSET); + timeZoneDST = calculateTimeZoneOffset(timezone.getRawOffset()+offset); + + if (fileDateFormat==null || fileDateFormat.length()==0) + fileDateFormat = "yyyy-MM-dd"; + dateFormatter = new SimpleDateFormat(fileDateFormat); + dateFormatter.setTimeZone(timezone); + dayFormatter = new SimpleDateFormat("dd"); + dayFormatter.setTimeZone(timezone); + monthFormatter = new SimpleDateFormat("MM"); + monthFormatter.setTimeZone(timezone); + yearFormatter = new SimpleDateFormat("yyyy"); + yearFormatter.setTimeZone(timezone); + timeFormatter = new SimpleDateFormat("HH:mm:ss"); + timeFormatter.setTimeZone(timezone); + currentDateString = getCurrentDateString(); + dateStamp = dateFormatter.format(new Date()); + + open(); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("accessLogValve.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + close(); + + } +} diff --git a/java/org/apache/catalina/valves/JDBCAccessLogValve.java b/java/org/apache/catalina/valves/JDBCAccessLogValve.java index 228e4cc2c..593721ce6 100644 --- a/java/org/apache/catalina/valves/JDBCAccessLogValve.java +++ b/java/org/apache/catalina/valves/JDBCAccessLogValve.java @@ -1,681 +1,681 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import java.sql.Connection; -import java.sql.Driver; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.util.Properties; - -import javax.servlet.ServletException; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; - -/** - *

        - * This Tomcat extension logs server access directly to a database, and can - * be used instead of the regular file-based access log implemented in - * AccessLogValve. - * To use, copy into the server/classes directory of the Tomcat installation - * and configure in server.xml as: - *

        - * 		<Valve className="org.apache.catalina.valves.JDBCAccessLogValve"
        - *        	driverName="your_jdbc_driver"
        - *        	connectionURL="your_jdbc_url"
        - *        	pattern="combined" resolveHosts="false"
        - * 		/>
        - * 
        - *

        - *

        - * Many parameters can be configured, such as the database connection (with - * driverName and connectionURL), - * the table name (tableName) - * and the field names (corresponding to the get/set method names). - * The same options as AccessLogValve are supported, such as - * resolveHosts and pattern ("common" or "combined" - * only). - *

        - *

        - * When Tomcat is started, a database connection (with autoReconnect option) - * is created and used for all the log activity. When Tomcat is shutdown, the - * database connection is closed. - * This logger can be used at the level of the Engine context (being shared - * by all the defined hosts) or the Host context (one instance of the logger - * per host, possibly using different databases). - *

        - *

        - * The database table can be created with the following command: - *

        - *
        - * CREATE TABLE access (
        - * id INT UNSIGNED AUTO_INCREMENT NOT NULL,
        - * ts TIMESTAMP NOT NULL,
        - * remoteHost CHAR(15) NOT NULL,
        - * userName CHAR(15),
        - * timestamp TIMESTAMP NOT NULL,
        - * virtualHost VARCHAR(64) NOT NULL,
        - * method VARCHAR(8) NOT NULL,
        - * query VARCHAR(255) NOT NULL,
        - * status SMALLINT UNSIGNED NOT NULL,
        - * bytes INT UNSIGNED NOT NULL,
        - * referer VARCHAR(128),
        - * userAgent VARCHAR(128),
        - * PRIMARY KEY (id),
        - * INDEX (ts),
        - * INDEX (remoteHost),
        - * INDEX (virtualHost),
        - * INDEX (query),
        - * INDEX (userAgent)
        - * );
        - * 
        - *

        - * If the table is created as above, its name and the field names don't need - * to be defined. - *

        - *

        - * If the request method is "common", only these fields are used: - * remoteHost, user, timeStamp, query, status, bytes - *

        - *

        - * TO DO: provide option for excluding logging of certain MIME types. - *

        - * - * @author Andre de Jesus - * @author Peter Rossbach - */ - -public final class JDBCAccessLogValve - extends ValveBase - implements Lifecycle { - - // ----------------------------------------------------------- Constructors - - - /** - * Class constructor. Initializes the fields with the default values. - * The defaults are: - *
        -     * 		driverName = null;
        -     * 		connectionURL = null;
        -     * 		tableName = "access";
        -     * 		remoteHostField = "remoteHost";
        -     * 		userField = "userName";
        -     * 		timestampField = "timestamp";
        -     * 		virtualHostField = "virtualHost";
        -     * 		methodField = "method";
        -     * 		queryField = "query";
        -     * 		statusField = "status";
        -     * 		bytesField = "bytes";
        -     * 		refererField = "referer";
        -     * 		userAgentField = "userAgent";
        -     * 		pattern = "common";
        -     * 		resolveHosts = false;
        -     * 
        - */ - public JDBCAccessLogValve() { - super(); - driverName = null; - connectionURL = null; - tableName = "access"; - remoteHostField = "remoteHost"; - userField = "userName"; - timestampField = "timestamp"; - virtualHostField = "virtualHost"; - methodField = "method"; - queryField = "query"; - statusField = "status"; - bytesField = "bytes"; - refererField = "referer"; - userAgentField = "userAgent"; - pattern = "common"; - resolveHosts = false; - conn = null; - ps = null; - currentTimeMillis = new java.util.Date().getTime(); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The connection username to use when trying to connect to the database. - */ - protected String connectionName = null; - - - /** - * The connection URL to use when trying to connect to the database. - */ - protected String connectionPassword = null; - - /** - * Instance of the JDBC Driver class we use as a connection factory. - */ - protected Driver driver = null; - - - private String driverName; - private String connectionURL; - private String tableName; - private String remoteHostField; - private String userField; - private String timestampField; - private String virtualHostField; - private String methodField; - private String queryField; - private String statusField; - private String bytesField; - private String refererField; - private String userAgentField; - private String pattern; - private boolean resolveHosts; - - - private Connection conn; - private PreparedStatement ps; - - - private long currentTimeMillis; - - - /** - * The descriptive information about this implementation. - */ - protected static String info = - "org.apache.catalina.valves.JDBCAccessLogValve/1.1"; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * The string manager for this package. - */ - private StringManager sm = StringManager.getManager(Constants.Package); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - // ------------------------------------------------------------- Properties - - /** - * Return the username to use to connect to the database. - * - */ - public String getConnectionName() { - return connectionName; - } - - /** - * Set the username to use to connect to the database. - * - * @param connectionName Username - */ - public void setConnectionName(String connectionName) { - this.connectionName = connectionName; - } - - /** - * Sets the database driver name. - * - * @param driverName The complete name of the database driver class. - */ - public void setDriverName(String driverName) { - this.driverName = driverName; - } - - /** - * Return the password to use to connect to the database. - * - */ - public String getConnectionPassword() { - return connectionPassword; - } - - /** - * Set the password to use to connect to the database. - * - * @param connectionPassword User password - */ - public void setConnectionPassword(String connectionPassword) { - this.connectionPassword = connectionPassword; - } - - /** - * Sets the JDBC URL for the database where the log is stored. - * - * @param connectionURL The JDBC URL of the database. - */ - public void setConnectionURL(String connectionURL) { - this.connectionURL = connectionURL; - } - - - /** - * Sets the name of the table where the logs are stored. - * - * @param tableName The name of the table. - */ - public void setTableName(String tableName) { - this.tableName = tableName; - } - - - /** - * Sets the name of the field containing the remote host. - * - * @param remoteHostField The name of the remote host field. - */ - public void setRemoteHostField(String remoteHostField) { - this.remoteHostField = remoteHostField; - } - - - /** - * Sets the name of the field containing the remote user name. - * - * @param userField The name of the remote user field. - */ - public void setUserField(String userField) { - this.userField = userField; - } - - - /** - * Sets the name of the field containing the server-determined timestamp. - * - * @param timestampField The name of the server-determined timestamp field. - */ - public void setTimestampField(String timestampField) { - this.timestampField = timestampField; - } - - - /** - * Sets the name of the field containing the virtual host information - * (this is in fact the server name). - * - * @param virtualHostField The name of the virtual host field. - */ - public void setVirtualHostField(String virtualHostField) { - this.virtualHostField = virtualHostField; - } - - - /** - * Sets the name of the field containing the HTTP request method. - * - * @param methodField The name of the HTTP request method field. - */ - public void setMethodField(String methodField) { - this.methodField = methodField; - } - - - /** - * Sets the name of the field containing the URL part of the HTTP query. - * - * @param queryField The name of the field containing the URL part of - * the HTTP query. - */ - public void setQueryField(String queryField) { - this.queryField = queryField; - } - - - /** - * Sets the name of the field containing the HTTP response status code. - * - * @param statusField The name of the HTTP response status code field. - */ - public void setStatusField(String statusField) { - this.statusField = statusField; - } - - - /** - * Sets the name of the field containing the number of bytes returned. - * - * @param bytesField The name of the returned bytes field. - */ - public void setBytesField(String bytesField) { - this.bytesField = bytesField; - } - - - /** - * Sets the name of the field containing the referer. - * - * @param refererField The referer field name. - */ - public void setRefererField(String refererField) { - this.refererField = refererField; - } - - - /** - * Sets the name of the field containing the user agent. - * - * @param userAgentField The name of the user agent field. - */ - public void setUserAgentField(String userAgentField) { - this.userAgentField = userAgentField; - } - - - /** - * Sets the logging pattern. The patterns supported correspond to the - * file-based "common" and "combined". These are translated into the use - * of tables containing either set of fields. - *

        TO DO: more flexible field choices.

        - * - * @param pattern The name of the logging pattern. - */ - public void setPattern(String pattern) { - this.pattern = pattern; - } - - - /** - * Determines whether IP host name resolution is done. - * - * @param resolveHosts "true" or "false", if host IP resolution - * is desired or not. - */ - public void setResolveHosts(String resolveHosts) { - this.resolveHosts = new Boolean(resolveHosts).booleanValue(); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * This method is invoked by Tomcat on each query. - * - * @param request The Request object. - * @param response The Response object. - * - * @exception IOException Should not be thrown. - * @exception ServletException Database SQLException is wrapped - * in a ServletException. - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - getNext().invoke(request, response); - - String remoteHost = ""; - if(resolveHosts) - remoteHost = request.getRemoteHost(); - else - remoteHost = request.getRemoteAddr(); - String user = ""; - if(request != null) - user = request.getRemoteUser(); - String query=""; - if(request != null) - query = request.getRequestURI(); - int bytes = response.getContentCount(); - if(bytes < 0) - bytes = 0; - int status = response.getStatus(); - if (pattern.equals("combined")) { - String virtualHost = ""; - if(request != null) - virtualHost = request.getServerName(); - String method = ""; - if(request != null) - method = request.getMethod(); - String referer = ""; - if(request != null) - referer = request.getHeader("referer"); - String userAgent = ""; - if(request != null) - userAgent = request.getHeader("user-agent"); - } - synchronized (this) { - int numberOfTries = 2; - while (numberOfTries>0) { - try { - open(); - - ps.setString(1, remoteHost); - ps.setString(2, user); - ps.setTimestamp(3, new Timestamp(getCurrentTimeMillis())); - ps.setString(4, query); - ps.setInt(5, status); - ps.setInt(6, bytes); - if (pattern.equals("combined")) { - - String virtualHost = ""; - if(request != null) - virtualHost = request.getServerName(); - String method = ""; - if(request != null) - method = request.getMethod(); - String referer = ""; - if(request != null) - referer = request.getHeader("referer"); - String userAgent = ""; - if(request != null) - userAgent = request.getHeader("user-agent"); - ps.setString(7, virtualHost); - ps.setString(8, method); - ps.setString(9, referer); - ps.setString(10, userAgent); - } - ps.executeUpdate(); - return; - } catch (SQLException e) { - // Log the problem for posterity - container.getLogger().error(sm.getString("jdbcAccessLogValve.exception"), e); - - // Close the connection so that it gets reopened next time - if (conn != null) - close(); - } - numberOfTries--; - } - } - - } - - - /** - * Adds a Lifecycle listener. - * - * @param listener The listener to add. - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Removes a Lifecycle listener. - * - * @param listener The listener to remove. - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - /** - * Open (if necessary) and return a database connection for use by - * this AccessLogValve. - * - * @exception SQLException if a database error occurs - */ - protected void open() throws SQLException { - - // Do nothing if there is a database connection already open - if (conn != null) - return ; - - // Instantiate our database driver if necessary - if (driver == null) { - try { - Class clazz = Class.forName(driverName); - driver = (Driver) clazz.newInstance(); - } catch (Throwable e) { - throw new SQLException(e.getMessage()); - } - } - - // Open a new connection - Properties props = new Properties(); - props.put("autoReconnect", "true"); - if (connectionName != null) - props.put("user", connectionName); - if (connectionPassword != null) - props.put("password", connectionPassword); - conn = driver.connect(connectionURL, props); - conn.setAutoCommit(true); - if (pattern.equals("common")) { - ps = conn.prepareStatement - ("INSERT INTO " + tableName + " (" - + remoteHostField + ", " + userField + ", " - + timestampField +", " + queryField + ", " - + statusField + ", " + bytesField - + ") VALUES(?, ?, ?, ?, ?, ?)"); - } else if (pattern.equals("combined")) { - ps = conn.prepareStatement - ("INSERT INTO " + tableName + " (" - + remoteHostField + ", " + userField + ", " - + timestampField + ", " + queryField + ", " - + statusField + ", " + bytesField + ", " - + virtualHostField + ", " + methodField + ", " - + refererField + ", " + userAgentField - + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); - } - } - - /** - * Close the specified database connection. - */ - protected void close() { - - // Do nothing if the database connection is already closed - if (conn == null) - return; - - // Close our prepared statements (if any) - try { - ps.close(); - } catch (Throwable f) { - ; - } - this.ps = null; - - - - // Close this database connection, and log any errors - try { - conn.close(); - } catch (SQLException e) { - container.getLogger().error(sm.getString("jdbcAccessLogValeve.close"), e); // Just log it here - } finally { - this.conn = null; - } - - } - /** - * Invoked by Tomcat on startup. The database connection is set here. - * - * @exception LifecycleException Can be thrown on lifecycle - * inconsistencies or on database errors (as a wrapped SQLException). - */ - public void start() throws LifecycleException { - - if (started) - throw new LifecycleException - (sm.getString("accessLogValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - try { - open() ; - } catch (SQLException e) { - throw new LifecycleException(e); - } - - } - - - /** - * Invoked by tomcat on shutdown. The database connection is closed here. - * - * @exception LifecycleException Can be thrown on lifecycle - * inconsistencies or on database errors (as a wrapped SQLException). - */ - public void stop() throws LifecycleException { - - if (!started) - throw new LifecycleException - (sm.getString("accessLogValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - close() ; - - } - - - public long getCurrentTimeMillis() { - long systime = System.currentTimeMillis(); - if ((systime - currentTimeMillis) > 1000) { - currentTimeMillis = new java.util.Date(systime).getTime(); - } - return currentTimeMillis; - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import java.sql.Connection; +import java.sql.Driver; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.Properties; + +import javax.servlet.ServletException; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; + +/** + *

        + * This Tomcat extension logs server access directly to a database, and can + * be used instead of the regular file-based access log implemented in + * AccessLogValve. + * To use, copy into the server/classes directory of the Tomcat installation + * and configure in server.xml as: + *

        + * 		<Valve className="org.apache.catalina.valves.JDBCAccessLogValve"
        + *        	driverName="your_jdbc_driver"
        + *        	connectionURL="your_jdbc_url"
        + *        	pattern="combined" resolveHosts="false"
        + * 		/>
        + * 
        + *

        + *

        + * Many parameters can be configured, such as the database connection (with + * driverName and connectionURL), + * the table name (tableName) + * and the field names (corresponding to the get/set method names). + * The same options as AccessLogValve are supported, such as + * resolveHosts and pattern ("common" or "combined" + * only). + *

        + *

        + * When Tomcat is started, a database connection (with autoReconnect option) + * is created and used for all the log activity. When Tomcat is shutdown, the + * database connection is closed. + * This logger can be used at the level of the Engine context (being shared + * by all the defined hosts) or the Host context (one instance of the logger + * per host, possibly using different databases). + *

        + *

        + * The database table can be created with the following command: + *

        + *
        + * CREATE TABLE access (
        + * id INT UNSIGNED AUTO_INCREMENT NOT NULL,
        + * ts TIMESTAMP NOT NULL,
        + * remoteHost CHAR(15) NOT NULL,
        + * userName CHAR(15),
        + * timestamp TIMESTAMP NOT NULL,
        + * virtualHost VARCHAR(64) NOT NULL,
        + * method VARCHAR(8) NOT NULL,
        + * query VARCHAR(255) NOT NULL,
        + * status SMALLINT UNSIGNED NOT NULL,
        + * bytes INT UNSIGNED NOT NULL,
        + * referer VARCHAR(128),
        + * userAgent VARCHAR(128),
        + * PRIMARY KEY (id),
        + * INDEX (ts),
        + * INDEX (remoteHost),
        + * INDEX (virtualHost),
        + * INDEX (query),
        + * INDEX (userAgent)
        + * );
        + * 
        + *

        + * If the table is created as above, its name and the field names don't need + * to be defined. + *

        + *

        + * If the request method is "common", only these fields are used: + * remoteHost, user, timeStamp, query, status, bytes + *

        + *

        + * TO DO: provide option for excluding logging of certain MIME types. + *

        + * + * @author Andre de Jesus + * @author Peter Rossbach + */ + +public final class JDBCAccessLogValve + extends ValveBase + implements Lifecycle { + + // ----------------------------------------------------------- Constructors + + + /** + * Class constructor. Initializes the fields with the default values. + * The defaults are: + *
        +     * 		driverName = null;
        +     * 		connectionURL = null;
        +     * 		tableName = "access";
        +     * 		remoteHostField = "remoteHost";
        +     * 		userField = "userName";
        +     * 		timestampField = "timestamp";
        +     * 		virtualHostField = "virtualHost";
        +     * 		methodField = "method";
        +     * 		queryField = "query";
        +     * 		statusField = "status";
        +     * 		bytesField = "bytes";
        +     * 		refererField = "referer";
        +     * 		userAgentField = "userAgent";
        +     * 		pattern = "common";
        +     * 		resolveHosts = false;
        +     * 
        + */ + public JDBCAccessLogValve() { + super(); + driverName = null; + connectionURL = null; + tableName = "access"; + remoteHostField = "remoteHost"; + userField = "userName"; + timestampField = "timestamp"; + virtualHostField = "virtualHost"; + methodField = "method"; + queryField = "query"; + statusField = "status"; + bytesField = "bytes"; + refererField = "referer"; + userAgentField = "userAgent"; + pattern = "common"; + resolveHosts = false; + conn = null; + ps = null; + currentTimeMillis = new java.util.Date().getTime(); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The connection username to use when trying to connect to the database. + */ + protected String connectionName = null; + + + /** + * The connection URL to use when trying to connect to the database. + */ + protected String connectionPassword = null; + + /** + * Instance of the JDBC Driver class we use as a connection factory. + */ + protected Driver driver = null; + + + private String driverName; + private String connectionURL; + private String tableName; + private String remoteHostField; + private String userField; + private String timestampField; + private String virtualHostField; + private String methodField; + private String queryField; + private String statusField; + private String bytesField; + private String refererField; + private String userAgentField; + private String pattern; + private boolean resolveHosts; + + + private Connection conn; + private PreparedStatement ps; + + + private long currentTimeMillis; + + + /** + * The descriptive information about this implementation. + */ + protected static String info = + "org.apache.catalina.valves.JDBCAccessLogValve/1.1"; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * The string manager for this package. + */ + private StringManager sm = StringManager.getManager(Constants.Package); + + + /** + * Has this component been started yet? + */ + private boolean started = false; + + + // ------------------------------------------------------------- Properties + + /** + * Return the username to use to connect to the database. + * + */ + public String getConnectionName() { + return connectionName; + } + + /** + * Set the username to use to connect to the database. + * + * @param connectionName Username + */ + public void setConnectionName(String connectionName) { + this.connectionName = connectionName; + } + + /** + * Sets the database driver name. + * + * @param driverName The complete name of the database driver class. + */ + public void setDriverName(String driverName) { + this.driverName = driverName; + } + + /** + * Return the password to use to connect to the database. + * + */ + public String getConnectionPassword() { + return connectionPassword; + } + + /** + * Set the password to use to connect to the database. + * + * @param connectionPassword User password + */ + public void setConnectionPassword(String connectionPassword) { + this.connectionPassword = connectionPassword; + } + + /** + * Sets the JDBC URL for the database where the log is stored. + * + * @param connectionURL The JDBC URL of the database. + */ + public void setConnectionURL(String connectionURL) { + this.connectionURL = connectionURL; + } + + + /** + * Sets the name of the table where the logs are stored. + * + * @param tableName The name of the table. + */ + public void setTableName(String tableName) { + this.tableName = tableName; + } + + + /** + * Sets the name of the field containing the remote host. + * + * @param remoteHostField The name of the remote host field. + */ + public void setRemoteHostField(String remoteHostField) { + this.remoteHostField = remoteHostField; + } + + + /** + * Sets the name of the field containing the remote user name. + * + * @param userField The name of the remote user field. + */ + public void setUserField(String userField) { + this.userField = userField; + } + + + /** + * Sets the name of the field containing the server-determined timestamp. + * + * @param timestampField The name of the server-determined timestamp field. + */ + public void setTimestampField(String timestampField) { + this.timestampField = timestampField; + } + + + /** + * Sets the name of the field containing the virtual host information + * (this is in fact the server name). + * + * @param virtualHostField The name of the virtual host field. + */ + public void setVirtualHostField(String virtualHostField) { + this.virtualHostField = virtualHostField; + } + + + /** + * Sets the name of the field containing the HTTP request method. + * + * @param methodField The name of the HTTP request method field. + */ + public void setMethodField(String methodField) { + this.methodField = methodField; + } + + + /** + * Sets the name of the field containing the URL part of the HTTP query. + * + * @param queryField The name of the field containing the URL part of + * the HTTP query. + */ + public void setQueryField(String queryField) { + this.queryField = queryField; + } + + + /** + * Sets the name of the field containing the HTTP response status code. + * + * @param statusField The name of the HTTP response status code field. + */ + public void setStatusField(String statusField) { + this.statusField = statusField; + } + + + /** + * Sets the name of the field containing the number of bytes returned. + * + * @param bytesField The name of the returned bytes field. + */ + public void setBytesField(String bytesField) { + this.bytesField = bytesField; + } + + + /** + * Sets the name of the field containing the referer. + * + * @param refererField The referer field name. + */ + public void setRefererField(String refererField) { + this.refererField = refererField; + } + + + /** + * Sets the name of the field containing the user agent. + * + * @param userAgentField The name of the user agent field. + */ + public void setUserAgentField(String userAgentField) { + this.userAgentField = userAgentField; + } + + + /** + * Sets the logging pattern. The patterns supported correspond to the + * file-based "common" and "combined". These are translated into the use + * of tables containing either set of fields. + *

        TO DO: more flexible field choices.

        + * + * @param pattern The name of the logging pattern. + */ + public void setPattern(String pattern) { + this.pattern = pattern; + } + + + /** + * Determines whether IP host name resolution is done. + * + * @param resolveHosts "true" or "false", if host IP resolution + * is desired or not. + */ + public void setResolveHosts(String resolveHosts) { + this.resolveHosts = new Boolean(resolveHosts).booleanValue(); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * This method is invoked by Tomcat on each query. + * + * @param request The Request object. + * @param response The Response object. + * + * @exception IOException Should not be thrown. + * @exception ServletException Database SQLException is wrapped + * in a ServletException. + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + getNext().invoke(request, response); + + String remoteHost = ""; + if(resolveHosts) + remoteHost = request.getRemoteHost(); + else + remoteHost = request.getRemoteAddr(); + String user = ""; + if(request != null) + user = request.getRemoteUser(); + String query=""; + if(request != null) + query = request.getRequestURI(); + int bytes = response.getContentCount(); + if(bytes < 0) + bytes = 0; + int status = response.getStatus(); + if (pattern.equals("combined")) { + String virtualHost = ""; + if(request != null) + virtualHost = request.getServerName(); + String method = ""; + if(request != null) + method = request.getMethod(); + String referer = ""; + if(request != null) + referer = request.getHeader("referer"); + String userAgent = ""; + if(request != null) + userAgent = request.getHeader("user-agent"); + } + synchronized (this) { + int numberOfTries = 2; + while (numberOfTries>0) { + try { + open(); + + ps.setString(1, remoteHost); + ps.setString(2, user); + ps.setTimestamp(3, new Timestamp(getCurrentTimeMillis())); + ps.setString(4, query); + ps.setInt(5, status); + ps.setInt(6, bytes); + if (pattern.equals("combined")) { + + String virtualHost = ""; + if(request != null) + virtualHost = request.getServerName(); + String method = ""; + if(request != null) + method = request.getMethod(); + String referer = ""; + if(request != null) + referer = request.getHeader("referer"); + String userAgent = ""; + if(request != null) + userAgent = request.getHeader("user-agent"); + ps.setString(7, virtualHost); + ps.setString(8, method); + ps.setString(9, referer); + ps.setString(10, userAgent); + } + ps.executeUpdate(); + return; + } catch (SQLException e) { + // Log the problem for posterity + container.getLogger().error(sm.getString("jdbcAccessLogValve.exception"), e); + + // Close the connection so that it gets reopened next time + if (conn != null) + close(); + } + numberOfTries--; + } + } + + } + + + /** + * Adds a Lifecycle listener. + * + * @param listener The listener to add. + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Removes a Lifecycle listener. + * + * @param listener The listener to remove. + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + /** + * Open (if necessary) and return a database connection for use by + * this AccessLogValve. + * + * @exception SQLException if a database error occurs + */ + protected void open() throws SQLException { + + // Do nothing if there is a database connection already open + if (conn != null) + return ; + + // Instantiate our database driver if necessary + if (driver == null) { + try { + Class clazz = Class.forName(driverName); + driver = (Driver) clazz.newInstance(); + } catch (Throwable e) { + throw new SQLException(e.getMessage()); + } + } + + // Open a new connection + Properties props = new Properties(); + props.put("autoReconnect", "true"); + if (connectionName != null) + props.put("user", connectionName); + if (connectionPassword != null) + props.put("password", connectionPassword); + conn = driver.connect(connectionURL, props); + conn.setAutoCommit(true); + if (pattern.equals("common")) { + ps = conn.prepareStatement + ("INSERT INTO " + tableName + " (" + + remoteHostField + ", " + userField + ", " + + timestampField +", " + queryField + ", " + + statusField + ", " + bytesField + + ") VALUES(?, ?, ?, ?, ?, ?)"); + } else if (pattern.equals("combined")) { + ps = conn.prepareStatement + ("INSERT INTO " + tableName + " (" + + remoteHostField + ", " + userField + ", " + + timestampField + ", " + queryField + ", " + + statusField + ", " + bytesField + ", " + + virtualHostField + ", " + methodField + ", " + + refererField + ", " + userAgentField + + ") VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"); + } + } + + /** + * Close the specified database connection. + */ + protected void close() { + + // Do nothing if the database connection is already closed + if (conn == null) + return; + + // Close our prepared statements (if any) + try { + ps.close(); + } catch (Throwable f) { + ; + } + this.ps = null; + + + + // Close this database connection, and log any errors + try { + conn.close(); + } catch (SQLException e) { + container.getLogger().error(sm.getString("jdbcAccessLogValeve.close"), e); // Just log it here + } finally { + this.conn = null; + } + + } + /** + * Invoked by Tomcat on startup. The database connection is set here. + * + * @exception LifecycleException Can be thrown on lifecycle + * inconsistencies or on database errors (as a wrapped SQLException). + */ + public void start() throws LifecycleException { + + if (started) + throw new LifecycleException + (sm.getString("accessLogValve.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + try { + open() ; + } catch (SQLException e) { + throw new LifecycleException(e); + } + + } + + + /** + * Invoked by tomcat on shutdown. The database connection is closed here. + * + * @exception LifecycleException Can be thrown on lifecycle + * inconsistencies or on database errors (as a wrapped SQLException). + */ + public void stop() throws LifecycleException { + + if (!started) + throw new LifecycleException + (sm.getString("accessLogValve.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + close() ; + + } + + + public long getCurrentTimeMillis() { + long systime = System.currentTimeMillis(); + if ((systime - currentTimeMillis) > 1000) { + currentTimeMillis = new java.util.Date(systime).getTime(); + } + return currentTimeMillis; + } + +} diff --git a/java/org/apache/catalina/valves/LocalStrings.properties b/java/org/apache/catalina/valves/LocalStrings.properties index 68d8e11a7..c3d42039a 100644 --- a/java/org/apache/catalina/valves/LocalStrings.properties +++ b/java/org/apache/catalina/valves/LocalStrings.properties @@ -1,71 +1,71 @@ -accessLogValve.alreadyStarted=Access Logger has already been started -accessLogValve.notStarted=Access Logger has not yet been started -semaphoreValve.alreadyStarted=Semaphore valve has already been started -semaphoreValve.notStarted=Semaphore valve has not yet been started -certificatesValve.alreadyStarted=Certificates Valve has already been started -certificatesValve.notStarted=Certificates Valve has not yet been started -interceptorValve.alreadyStarted=Interceptor Valve has already been started -interceptorValve.notStarted=Interceptor Valve has not yet been started -requestFilterValve.next=No ''next'' valve has been configured -requestFilterValve.syntax=Syntax error in request filter pattern {0} -requestListenerValve.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0} -requestListenerValve.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0} -valveBase.noNext=Configuration error: No ''next'' valve configured -jdbcAccessLogValve.exception=Exception performing insert access entry -jdbcAccessLogValve.close=Exception closing database connection - -# Error report valve -errorReportValve.errorReport=Error report -errorReportValve.statusHeader=HTTP Status {0} - {1} -errorReportValve.exceptionReport=Exception report -errorReportValve.statusReport=Status report -errorReportValve.message=message -errorReportValve.description=description -errorReportValve.exception=exception -errorReportValve.rootCause=root cause -errorReportValve.note=note -errorReportValve.rootCauseInLogs=The full stack trace of the root cause is available in the {0} logs. - -# HTTP status reports -http.100=The client may continue ({0}). -http.101=The server is switching protocols according to the "Upgrade" header ({0}). -http.201=The request succeeded and a new resource ({0}) has been created on the server. -http.202=This request was accepted for processing, but has not been completed ({0}). -http.203=The meta information presented by the client did not originate from the server ({0}). -http.204=The request succeeded but there is no information to return ({0}). -http.205=The client should reset the document view which caused this request to be sent ({0}). -http.206=The server has fulfilled a partial GET request for this resource ({0}). -http.207=Multiple status values have been returned ({0}). -http.300=The requested resource ({0}) corresponds to any one of a set of representations, each with its own specific location. -http.301=The requested resource ({0}) has moved permanently to a new location. -http.302=The requested resource ({0}) has moved temporarily to a new location. -http.303=The response to this request can be found under a different URI ({0}). -http.304=The requested resource ({0}) is available and has not been modified. -http.305=The requested resource ({0}) must be accessed through the proxy given by the "Location" header. -http.400=The request sent by the client was syntactically incorrect ({0}). -http.401=This request requires HTTP authentication ({0}). -http.402=Payment is required for access to this resource ({0}). -http.403=Access to the specified resource ({0}) has been forbidden. -http.404=The requested resource ({0}) is not available. -http.405=The specified HTTP method is not allowed for the requested resource ({0}). -http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ({0}). -http.407=The client must first authenticate itself with the proxy ({0}). -http.408=The client did not produce a request within the time that the server was prepared to wait ({0}). -http.409=The request could not be completed due to a conflict with the current state of the resource ({0}). -http.410=The requested resource ({0}) is no longer available, and no forwarding address is known. -http.411=This request cannot be handled without a defined content length ({0}). -http.412=A specified precondition has failed for this request ({0}). -http.413=The request entity is larger than the server is willing or able to process. -http.414=The server refused this request because the request URI was too long ({0}). -http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ({0}). -http.416=The requested byte range cannot be satisfied ({0}). -http.417=The expectation given in the "Expect" request header ({0}) could not be fulfilled. -http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions ({0}). -http.423=The source or destination resource of a method is locked ({0}). -http.500=The server encountered an internal error ({0}) that prevented it from fulfilling this request. -http.501=The server does not support the functionality needed to fulfill this request ({0}). -http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway ({0}). -http.503=The requested service ({0}) is not currently available. -http.504=The server received a timeout from an upstream server while acting as a gateway or proxy ({0}). -http.505=The server does not support the requested HTTP protocol version ({0}). -http.507=The resource does not have sufficient space to record the state of the resource after execution of this method ({0}). +accessLogValve.alreadyStarted=Access Logger has already been started +accessLogValve.notStarted=Access Logger has not yet been started +semaphoreValve.alreadyStarted=Semaphore valve has already been started +semaphoreValve.notStarted=Semaphore valve has not yet been started +certificatesValve.alreadyStarted=Certificates Valve has already been started +certificatesValve.notStarted=Certificates Valve has not yet been started +interceptorValve.alreadyStarted=Interceptor Valve has already been started +interceptorValve.notStarted=Interceptor Valve has not yet been started +requestFilterValve.next=No ''next'' valve has been configured +requestFilterValve.syntax=Syntax error in request filter pattern {0} +requestListenerValve.requestInit=Exception sending request initialized lifecycle event to listener instance of class {0} +requestListenerValve.requestDestroy=Exception sending request destroyed lifecycle event to listener instance of class {0} +valveBase.noNext=Configuration error: No ''next'' valve configured +jdbcAccessLogValve.exception=Exception performing insert access entry +jdbcAccessLogValve.close=Exception closing database connection + +# Error report valve +errorReportValve.errorReport=Error report +errorReportValve.statusHeader=HTTP Status {0} - {1} +errorReportValve.exceptionReport=Exception report +errorReportValve.statusReport=Status report +errorReportValve.message=message +errorReportValve.description=description +errorReportValve.exception=exception +errorReportValve.rootCause=root cause +errorReportValve.note=note +errorReportValve.rootCauseInLogs=The full stack trace of the root cause is available in the {0} logs. + +# HTTP status reports +http.100=The client may continue ({0}). +http.101=The server is switching protocols according to the "Upgrade" header ({0}). +http.201=The request succeeded and a new resource ({0}) has been created on the server. +http.202=This request was accepted for processing, but has not been completed ({0}). +http.203=The meta information presented by the client did not originate from the server ({0}). +http.204=The request succeeded but there is no information to return ({0}). +http.205=The client should reset the document view which caused this request to be sent ({0}). +http.206=The server has fulfilled a partial GET request for this resource ({0}). +http.207=Multiple status values have been returned ({0}). +http.300=The requested resource ({0}) corresponds to any one of a set of representations, each with its own specific location. +http.301=The requested resource ({0}) has moved permanently to a new location. +http.302=The requested resource ({0}) has moved temporarily to a new location. +http.303=The response to this request can be found under a different URI ({0}). +http.304=The requested resource ({0}) is available and has not been modified. +http.305=The requested resource ({0}) must be accessed through the proxy given by the "Location" header. +http.400=The request sent by the client was syntactically incorrect ({0}). +http.401=This request requires HTTP authentication ({0}). +http.402=Payment is required for access to this resource ({0}). +http.403=Access to the specified resource ({0}) has been forbidden. +http.404=The requested resource ({0}) is not available. +http.405=The specified HTTP method is not allowed for the requested resource ({0}). +http.406=The resource identified by this request is only capable of generating responses with characteristics not acceptable according to the request "accept" headers ({0}). +http.407=The client must first authenticate itself with the proxy ({0}). +http.408=The client did not produce a request within the time that the server was prepared to wait ({0}). +http.409=The request could not be completed due to a conflict with the current state of the resource ({0}). +http.410=The requested resource ({0}) is no longer available, and no forwarding address is known. +http.411=This request cannot be handled without a defined content length ({0}). +http.412=A specified precondition has failed for this request ({0}). +http.413=The request entity is larger than the server is willing or able to process. +http.414=The server refused this request because the request URI was too long ({0}). +http.415=The server refused this request because the request entity is in a format not supported by the requested resource for the requested method ({0}). +http.416=The requested byte range cannot be satisfied ({0}). +http.417=The expectation given in the "Expect" request header ({0}) could not be fulfilled. +http.422=The server understood the content type and syntax of the request but was unable to process the contained instructions ({0}). +http.423=The source or destination resource of a method is locked ({0}). +http.500=The server encountered an internal error ({0}) that prevented it from fulfilling this request. +http.501=The server does not support the functionality needed to fulfill this request ({0}). +http.502=This server received an invalid response from a server it consulted when acting as a proxy or gateway ({0}). +http.503=The requested service ({0}) is not currently available. +http.504=The server received a timeout from an upstream server while acting as a gateway or proxy ({0}). +http.505=The server does not support the requested HTTP protocol version ({0}). +http.507=The resource does not have sufficient space to record the state of the resource after execution of this method ({0}). diff --git a/java/org/apache/catalina/valves/LocalStrings_es.properties b/java/org/apache/catalina/valves/LocalStrings_es.properties index f98445692..6373fba3a 100644 --- a/java/org/apache/catalina/valves/LocalStrings_es.properties +++ b/java/org/apache/catalina/valves/LocalStrings_es.properties @@ -1,69 +1,69 @@ -accessLogValve.alreadyStarted=El Registrador de accesos ya se había iniciado -accessLogValve.notStarted=El Registrador de accesos no se ha iniciado -certificatesValve.alreadyStarted=La válvula de certificados ya se había iniciado -certificatesValve.notStarted=La válvula de certificados no se ha iniciado -interceptorValve.alreadyStarted=La válvula interceptora ya se había iniciado -interceptorValve.notStarted=La válvula interceptora no se ha iniciado -requestFilterValve.next=No hay ''siguiente'' válvula configurada -requestFilterValve.syntax=Error de sintáxis en petición de filtro patrón {0} -requestListenerValve.requestInit=Una excepción durante el envío de requerimiento ha iniciado un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} -requestListenerValve.requestDestroy=Una excepción durante el envío de requerimiento ha destruído un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} -valveBase.noNext=Error de configuración: No hay ''siguiente'' válvula configurada -jdbcAccessLogValve.exception=Excepción realizando entrada de acceso a inserción -jdbcAccessLogValve.close=Excepción cerrando conexión a base de datos - -# Error report valve -errorReportValve.errorReport=Informe de Error -errorReportValve.statusHeader=Estado HTTP {0} - {1} -errorReportValve.exceptionReport=Informe de Excepción -errorReportValve.statusReport=Informe de estado -errorReportValve.message=mensaje -errorReportValve.description=descripción -errorReportValve.exception=excepción -errorReportValve.rootCause=causa raíz -errorReportValve.note=nota -errorReportValve.rootCauseInLogs=La traza completa de la causa de este error se encuentra en los archivos de diario de {0}. - -# HTTP status reports -http.100=El cliente puede continuar ({0}). -http.101=El servidor está conmutando protocolos con arreglo a la cabecera "Upgrade" ({0}). -http.201=El requerimiento tuvo éxito y un nuevo recurso ({0}) ha sido creado en el servidor. -http.202=Este requerimiento ha sido aceptado para ser procesado, pero no ha sido completado ({0}). -http.203=La información meta presentada por el cliente no se originó desde el servidor ({0}). -http.204=El requerimiento tuvo éxito pero no hay información que devolver ({0}). -http.205=El cliente no debería de limpiar la vista del documento que causó que este requerimiento fuera enviado ({0}). -http.206=El servidor ha rellenado paciálmente un requerimiento GET para este recurso ({0}). -http.207=Se han devuelto valores múltiples de estado ({0}). -http.300=El recurso requerido ({0}) corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localización específica. -http.301=El recurso requerido ({0}) ha sido movido permanéntemente a una nueva localización. -http.302=El recurso requerido ({0}) ha sido movido temporálmente a una nueva localización. -http.303=La respuesta a este requerimiento se puede hallar bajo una URI diferente ({0}). -http.304=El recurso requerido ({0}) está disponible y no ha sido modificado. -http.305=El recurso requerido ({0}) debe de ser accedido a través del apoderado (proxy) dado mediante la cabecera "Location". -http.400=El requerimiento enviado por el cliente era sintácticamente incorrecto ({0}). -http.401=Este requerimiento requiere autenticación HTTP ({0}). -http.402=Se requiere pago para acceder a este recurso ({0}). -http.403=El acceso al recurso especificado ({0}) ha sido prohibido. -http.404=El recurso requerido ({0}) no está disponible. -http.405=El método HTTP especificado no está permitido para el recurso requerido ({0}). -http.406=El recurso identificado por este requerimiento sólo es capaz de generar respuestas con características no aceptables con arreglo a las cabeceras "accept" de requerimiento ({0}). -http.407=El cliente debe de ser primero autenticado en el apoderado ({0}). -http.408=El cliente no produjo un requerimiento dentro del tiempo en que el servidor estaba preparado esperando ({0}). -http.409=El requerimiento no pudo ser completado debido a un conflicto con el estado actual del recurso ({0}). -http.410=El recurso requerido ({0}) ya no está disponible y no se conoce dirección de reenvío. -http.411=Este requerimiento no puede ser manejado sin un tamaño definido de contenido ({0}). -http.412=Una precondición especificada ha fallado para este requerimiento ({0}). -http.413=La entidad de requerimiento es mayor de lo que el servidor quiere o puede procesar. -http.414=El servidor rechazó este requerimiento porque la URI requerida era demasiado larga ({0}). -http.415=El servidor rechazó este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el método requerido ({0}). -http.416=El rango de byte requerido no puede ser satisfecho ({0}). -http.417=Lo que se espera dado por la cabecera "Expect" de requerimiento ({0}) no pudo ser completado. -http.422=El servidor entendió el tipo de contenido y la sintáxis del requerimiento pero no pudo procesar las instrucciones contenidas ({0}). -http.423=La fuente o recurso de destino de un método está bloqueada ({0}). -http.500=El servidor encontró un error interno ({0}) que hizo que no pudiera rellenar este requerimiento. -http.501=El servidor no soporta la funcionalidad necesaria para rellenar este requerimiento ({0}). -http.502=Este servidor recibió una respuesta inválida desde un servidor que consultó cuando actuaba como apoderado o pasarela ({0}). -http.503=El servicio requerido ({0}) no está disponible en este momento. -http.504=El servidor recibió un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado ({0}). -http.505=El servidor no soporta la versión de protocolo HTTP requerida ({0}). -http.507=El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecución de este método ({0}). +accessLogValve.alreadyStarted=El Registrador de accesos ya se había iniciado +accessLogValve.notStarted=El Registrador de accesos no se ha iniciado +certificatesValve.alreadyStarted=La válvula de certificados ya se había iniciado +certificatesValve.notStarted=La válvula de certificados no se ha iniciado +interceptorValve.alreadyStarted=La válvula interceptora ya se había iniciado +interceptorValve.notStarted=La válvula interceptora no se ha iniciado +requestFilterValve.next=No hay ''siguiente'' válvula configurada +requestFilterValve.syntax=Error de sintáxis en petición de filtro patrón {0} +requestListenerValve.requestInit=Una excepción durante el envío de requerimiento ha iniciado un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} +requestListenerValve.requestDestroy=Una excepción durante el envío de requerimiento ha destruído un evento de ciclo de vida (lifecycle event) para la instancia de clase a la escucha (listener) {0} +valveBase.noNext=Error de configuración: No hay ''siguiente'' válvula configurada +jdbcAccessLogValve.exception=Excepción realizando entrada de acceso a inserción +jdbcAccessLogValve.close=Excepción cerrando conexión a base de datos + +# Error report valve +errorReportValve.errorReport=Informe de Error +errorReportValve.statusHeader=Estado HTTP {0} - {1} +errorReportValve.exceptionReport=Informe de Excepción +errorReportValve.statusReport=Informe de estado +errorReportValve.message=mensaje +errorReportValve.description=descripción +errorReportValve.exception=excepción +errorReportValve.rootCause=causa raíz +errorReportValve.note=nota +errorReportValve.rootCauseInLogs=La traza completa de la causa de este error se encuentra en los archivos de diario de {0}. + +# HTTP status reports +http.100=El cliente puede continuar ({0}). +http.101=El servidor está conmutando protocolos con arreglo a la cabecera "Upgrade" ({0}). +http.201=El requerimiento tuvo éxito y un nuevo recurso ({0}) ha sido creado en el servidor. +http.202=Este requerimiento ha sido aceptado para ser procesado, pero no ha sido completado ({0}). +http.203=La información meta presentada por el cliente no se originó desde el servidor ({0}). +http.204=El requerimiento tuvo éxito pero no hay información que devolver ({0}). +http.205=El cliente no debería de limpiar la vista del documento que causó que este requerimiento fuera enviado ({0}). +http.206=El servidor ha rellenado paciálmente un requerimiento GET para este recurso ({0}). +http.207=Se han devuelto valores múltiples de estado ({0}). +http.300=El recurso requerido ({0}) corresponde a una cualquiera de un conjunto de representaciones, cada una con su propia localización específica. +http.301=El recurso requerido ({0}) ha sido movido permanéntemente a una nueva localización. +http.302=El recurso requerido ({0}) ha sido movido temporálmente a una nueva localización. +http.303=La respuesta a este requerimiento se puede hallar bajo una URI diferente ({0}). +http.304=El recurso requerido ({0}) está disponible y no ha sido modificado. +http.305=El recurso requerido ({0}) debe de ser accedido a través del apoderado (proxy) dado mediante la cabecera "Location". +http.400=El requerimiento enviado por el cliente era sintácticamente incorrecto ({0}). +http.401=Este requerimiento requiere autenticación HTTP ({0}). +http.402=Se requiere pago para acceder a este recurso ({0}). +http.403=El acceso al recurso especificado ({0}) ha sido prohibido. +http.404=El recurso requerido ({0}) no está disponible. +http.405=El método HTTP especificado no está permitido para el recurso requerido ({0}). +http.406=El recurso identificado por este requerimiento sólo es capaz de generar respuestas con características no aceptables con arreglo a las cabeceras "accept" de requerimiento ({0}). +http.407=El cliente debe de ser primero autenticado en el apoderado ({0}). +http.408=El cliente no produjo un requerimiento dentro del tiempo en que el servidor estaba preparado esperando ({0}). +http.409=El requerimiento no pudo ser completado debido a un conflicto con el estado actual del recurso ({0}). +http.410=El recurso requerido ({0}) ya no está disponible y no se conoce dirección de reenvío. +http.411=Este requerimiento no puede ser manejado sin un tamaño definido de contenido ({0}). +http.412=Una precondición especificada ha fallado para este requerimiento ({0}). +http.413=La entidad de requerimiento es mayor de lo que el servidor quiere o puede procesar. +http.414=El servidor rechazó este requerimiento porque la URI requerida era demasiado larga ({0}). +http.415=El servidor rechazó este requerimiento porque la entidad requerida se encuentra en un formato no soportado por el recurso requerido para el método requerido ({0}). +http.416=El rango de byte requerido no puede ser satisfecho ({0}). +http.417=Lo que se espera dado por la cabecera "Expect" de requerimiento ({0}) no pudo ser completado. +http.422=El servidor entendió el tipo de contenido y la sintáxis del requerimiento pero no pudo procesar las instrucciones contenidas ({0}). +http.423=La fuente o recurso de destino de un método está bloqueada ({0}). +http.500=El servidor encontró un error interno ({0}) que hizo que no pudiera rellenar este requerimiento. +http.501=El servidor no soporta la funcionalidad necesaria para rellenar este requerimiento ({0}). +http.502=Este servidor recibió una respuesta inválida desde un servidor que consultó cuando actuaba como apoderado o pasarela ({0}). +http.503=El servicio requerido ({0}) no está disponible en este momento. +http.504=El servidor recibió un Tiempo Agotado desde un servidor superior cuando actuaba como pasarela o apoderado ({0}). +http.505=El servidor no soporta la versión de protocolo HTTP requerida ({0}). +http.507=El recurso no tiene espacio suficiente para registrar el estado del recurso tras la ejecución de este método ({0}). diff --git a/java/org/apache/catalina/valves/LocalStrings_fr.properties b/java/org/apache/catalina/valves/LocalStrings_fr.properties index f7fcb3c6b..4ca79698d 100644 --- a/java/org/apache/catalina/valves/LocalStrings_fr.properties +++ b/java/org/apache/catalina/valves/LocalStrings_fr.properties @@ -1,67 +1,67 @@ -accessLogValve.alreadyStarted=Le traceur d''accès a déjà été démarré -accessLogValve.notStarted=Le traceur d''accès n''a pas encore été démarré -certificatesValve.alreadyStarted=La Valve de Certificats a déjà été démarrée -certificatesValve.notStarted=La Valve de Certificats n''a pas encore été démarrée -interceptorValve.alreadyStarted=La Valve d''Interception a déjà été démarré -interceptorValve.notStarted=La Valve d''Interception n''a pas encore été démarrée -requestFilterValve.next=Aucune Valve ''suivante'' n''a été configurée -requestFilterValve.syntax=Erreur de synthaxe dans le pattern de filtre de requête {0} -requestListenerValve.requestInit=Une exception lors de l''envoi de requête a initié un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0} -requestListenerValve.requestDestroy=Une exception lors de l''envoi de requête a détruit un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0} -valveBase.noNext=Erreur de configuration error: Aucune Valve ''suivante'' n''a été configurée - -# Error report valve -errorReportValve.errorReport=Rapport d''erreur -errorReportValve.statusHeader=Etat HTTP {0} - {1} -errorReportValve.exceptionReport=Rapport d''exception -errorReportValve.statusReport=Rapport d''état -errorReportValve.message=message -errorReportValve.description=description -errorReportValve.exception=exception -errorReportValve.rootCause=cause mère -errorReportValve.note=note -errorReportValve.rootCauseInLogs=La trace complète de la cause mère de cette erreur est disponible dans les fichiers journaux de {0}. - -# HTTP status reports -http.100=Le client peut continuer ({0}). -http.101=Le serveur change de protocoles suivant la directive "Upgrade" de l''entête ({0}). -http.201=La requête a réussi et une nouvelle ressource ({0}) a été créee sur le serveur. -http.202=La requête a été accepté pour traitement, mais n''a pas été terminée ({0}). -http.203=L''information meta présentée par le client n''a pas pour origine ce server ({0}). -http.204=La requête a réussi mais il n''y a aucune information à retourner ({0}). -http.205=Le client doit remettre à zéro la vue de document qui a causée l''envoi de cette requête ({0}). -http.206=Le serveur a satisfait une requête GET partielle pour cette ressource ({0}). -http.207=Plusieurs valeurs d''états ont été retournées ({0}). -http.300=La ressource demandée ({0}) correspond à plusieurs représentations, chacune avec sa propre localisation. -http.301=La ressource demandée ({0}) a été déplacée de façon permanente vers une nouvelle localisation. -http.302=La ressource demandée ({0}) a été déplacée de façon temporaire vers une nouvelle localisation. -http.303=La réponse à cette requête peut être trouvée à une URI différente ({0}). -http.304=La ressource demandée ({0}) est disponible et n''a pas été modifiée. -http.305=La ressource demandée ({0}) doit être accédée au travers du relais indiqué par la directive "Location" de l''entête. -http.400=La requête envoyée par le client était syntaxiquement incorrecte ({0}). -http.401=La requête nécessite une authentification HTTP ({0}). -http.402=Un paiement est demandé pour accéder à cette ressource ({0}). -http.403=L''accès à la ressource demandée ({0}) a été interdit. -http.404=La ressource demandée ({0}) n''est pas disponible. -http.405=La méthode HTTP spécifiée n''est pas autorisée pour la ressource demandée ({0}). -http.406=La ressource identifiée par cette requête n''est capable de générer des réponses qu''avec des caractéristiques incompatible avec la directive "accept" présente dans l''entête de requête ({0}). -http.407=Le client doit d''abord s''authentifier auprès du relais ({0}). -http.408=Le client n''a pas produit de requête pendant le temps d''attente du serveur ({0}). -http.409=La requête ne peut être finalisée suite à un conflit lié à l''état de la ressource ({0}). -http.410=La ressource demandée ({0}) n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue. -http.411=La requête ne peut être traitée sans définition d''une taille de contenu (content length) ({0}). -http.412=Une condition préalable demandée a échouée pour cette requête ({0}). -http.413=L''entité de requête est plus importante que ce que le serveur veut ou peut traiter. -http.414=Le serveur a refusé cette requête car URI de requête est trop longue ({0}). -http.415=Le serveur a refusé cette requête car l''entité de requête est dans un format non supporté par la ressource demandée avec la méthode spécifiée ({0}). -http.416=La place d''octets (byte range) ne peut être satisfaite ({0}). -http.417=L''attente indiqué dans la directive "Expect" de l''entête de requête ({0}) ne peut être satisfaite. -http.422=Le serveur a compris le type de contenu (content type) ainsi que la synthaxe de la requête mais a été incapable de traiter les instructions contenues ({0}). -http.423=La ressource source ou destination de la méthode est vérrouillée ({0}). -http.500=Le serveur a rencontré une erreur interne ({0}) qui l''a empêché de satisfaire la requête. -http.501=Le serveur ne supporte pas la fonctionnalité demandée pour satisfaire cette requête ({0}). -http.502=Le serveur a reçu une réponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle ({0}). -http.503=Le service demandé ({0}) n''est pas disponible actuellement. -http.504=Le serveur a reçu un dépassement de delais (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle ({0}). -http.505=Le serveur ne supporte pas la version de protocole HTTP demandé ({0}). -http.507=La ressource n''a pas assez d''espace pour enregistrer l''état de la ressource après exécution de cette méthode ({0}). +accessLogValve.alreadyStarted=Le traceur d''accès a déjà été démarré +accessLogValve.notStarted=Le traceur d''accès n''a pas encore été démarré +certificatesValve.alreadyStarted=La Valve de Certificats a déjà été démarrée +certificatesValve.notStarted=La Valve de Certificats n''a pas encore été démarrée +interceptorValve.alreadyStarted=La Valve d''Interception a déjà été démarré +interceptorValve.notStarted=La Valve d''Interception n''a pas encore été démarrée +requestFilterValve.next=Aucune Valve ''suivante'' n''a été configurée +requestFilterValve.syntax=Erreur de synthaxe dans le pattern de filtre de requête {0} +requestListenerValve.requestInit=Une exception lors de l''envoi de requête a initié un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0} +requestListenerValve.requestDestroy=Une exception lors de l''envoi de requête a détruit un évènement cycle de vie (lifecycle event) pour l''instance de classe à l''écoute (listener) {0} +valveBase.noNext=Erreur de configuration error: Aucune Valve ''suivante'' n''a été configurée + +# Error report valve +errorReportValve.errorReport=Rapport d''erreur +errorReportValve.statusHeader=Etat HTTP {0} - {1} +errorReportValve.exceptionReport=Rapport d''exception +errorReportValve.statusReport=Rapport d''état +errorReportValve.message=message +errorReportValve.description=description +errorReportValve.exception=exception +errorReportValve.rootCause=cause mère +errorReportValve.note=note +errorReportValve.rootCauseInLogs=La trace complète de la cause mère de cette erreur est disponible dans les fichiers journaux de {0}. + +# HTTP status reports +http.100=Le client peut continuer ({0}). +http.101=Le serveur change de protocoles suivant la directive "Upgrade" de l''entête ({0}). +http.201=La requête a réussi et une nouvelle ressource ({0}) a été créee sur le serveur. +http.202=La requête a été accepté pour traitement, mais n''a pas été terminée ({0}). +http.203=L''information meta présentée par le client n''a pas pour origine ce server ({0}). +http.204=La requête a réussi mais il n''y a aucune information à retourner ({0}). +http.205=Le client doit remettre à zéro la vue de document qui a causée l''envoi de cette requête ({0}). +http.206=Le serveur a satisfait une requête GET partielle pour cette ressource ({0}). +http.207=Plusieurs valeurs d''états ont été retournées ({0}). +http.300=La ressource demandée ({0}) correspond à plusieurs représentations, chacune avec sa propre localisation. +http.301=La ressource demandée ({0}) a été déplacée de façon permanente vers une nouvelle localisation. +http.302=La ressource demandée ({0}) a été déplacée de façon temporaire vers une nouvelle localisation. +http.303=La réponse à cette requête peut être trouvée à une URI différente ({0}). +http.304=La ressource demandée ({0}) est disponible et n''a pas été modifiée. +http.305=La ressource demandée ({0}) doit être accédée au travers du relais indiqué par la directive "Location" de l''entête. +http.400=La requête envoyée par le client était syntaxiquement incorrecte ({0}). +http.401=La requête nécessite une authentification HTTP ({0}). +http.402=Un paiement est demandé pour accéder à cette ressource ({0}). +http.403=L''accès à la ressource demandée ({0}) a été interdit. +http.404=La ressource demandée ({0}) n''est pas disponible. +http.405=La méthode HTTP spécifiée n''est pas autorisée pour la ressource demandée ({0}). +http.406=La ressource identifiée par cette requête n''est capable de générer des réponses qu''avec des caractéristiques incompatible avec la directive "accept" présente dans l''entête de requête ({0}). +http.407=Le client doit d''abord s''authentifier auprès du relais ({0}). +http.408=Le client n''a pas produit de requête pendant le temps d''attente du serveur ({0}). +http.409=La requête ne peut être finalisée suite à un conflit lié à l''état de la ressource ({0}). +http.410=La ressource demandée ({0}) n''est pas disponible, et aucune addresse de rebond (forwarding) n''est connue. +http.411=La requête ne peut être traitée sans définition d''une taille de contenu (content length) ({0}). +http.412=Une condition préalable demandée a échouée pour cette requête ({0}). +http.413=L''entité de requête est plus importante que ce que le serveur veut ou peut traiter. +http.414=Le serveur a refusé cette requête car URI de requête est trop longue ({0}). +http.415=Le serveur a refusé cette requête car l''entité de requête est dans un format non supporté par la ressource demandée avec la méthode spécifiée ({0}). +http.416=La place d''octets (byte range) ne peut être satisfaite ({0}). +http.417=L''attente indiqué dans la directive "Expect" de l''entête de requête ({0}) ne peut être satisfaite. +http.422=Le serveur a compris le type de contenu (content type) ainsi que la synthaxe de la requête mais a été incapable de traiter les instructions contenues ({0}). +http.423=La ressource source ou destination de la méthode est vérrouillée ({0}). +http.500=Le serveur a rencontré une erreur interne ({0}) qui l''a empêché de satisfaire la requête. +http.501=Le serveur ne supporte pas la fonctionnalité demandée pour satisfaire cette requête ({0}). +http.502=Le serveur a reçu une réponse invalide d''un serveur qu''il consultait en tant que relais ou passerelle ({0}). +http.503=Le service demandé ({0}) n''est pas disponible actuellement. +http.504=Le serveur a reçu un dépassement de delais (timeout) d''un serveur amont qu''il consultait en tant que relais ou passerelle ({0}). +http.505=Le serveur ne supporte pas la version de protocole HTTP demandé ({0}). +http.507=La ressource n''a pas assez d''espace pour enregistrer l''état de la ressource après exécution de cette méthode ({0}). diff --git a/java/org/apache/catalina/valves/LocalStrings_ja.properties b/java/org/apache/catalina/valves/LocalStrings_ja.properties index 1144bb5a3..dff409623 100644 --- a/java/org/apache/catalina/valves/LocalStrings_ja.properties +++ b/java/org/apache/catalina/valves/LocalStrings_ja.properties @@ -1,24 +1,24 @@ -accessLogValve.alreadyStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -accessLogValve.notStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -certificatesValve.alreadyStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -certificatesValve.notStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -interceptorValve.alreadyStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -interceptorValve.notStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -requestFilterValve.next=\u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -requestFilterValve.syntax=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d1\u30bf\u30fc\u30f3 {0} \u306b\u69cb\u6587\u30a8\u30e9\u30fc\u304c\u3042\u308a\u307e\u3059 -requestListenerValve.requestInit=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -requestListenerValve.requestDestroy=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jdbcAccessLogValve.exception=\u30a2\u30af\u30bb\u30b9\u30a8\u30f3\u30c8\u30ea\u306e\u633f\u5165\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 -jdbcAccessLogValve.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 - -# Error report valve -valveBase.noNext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -errorReportValve.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} -errorReportValve.exceptionReport=\u4f8b\u5916\u30ec\u30dd\u30fc\u30c8 -errorReportValve.statusReport=\u30b9\u30c6\u30fc\u30bf\u30b9\u30ec\u30dd\u30fc\u30c8 -errorReportValve.message=\u30e1\u30c3\u30bb\u30fc\u30b8 -errorReportValve.description=\u8aac\u660e -errorReportValve.exception=\u4f8b\u5916 -errorReportValve.rootCause=\u539f\u56e0 -errorReportValve.note=\u6ce8\u610f -errorReportValve.rootCauseInLogs=\u539f\u56e0\u306e\u3059\u3079\u3066\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u306f\u3001{0}\u306e\u30ed\u30b0\u306b\u8a18\u9332\u3055\u308c\u3066\u3044\u307e\u3059 +accessLogValve.alreadyStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +accessLogValve.notStarted=\u30a2\u30af\u30bb\u30b9\u30ed\u30ac\u30fc\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +certificatesValve.alreadyStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +certificatesValve.notStarted=\u8a8d\u8a3c\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +interceptorValve.alreadyStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +interceptorValve.notStarted=\u30a4\u30f3\u30bf\u30fc\u30bb\u30d7\u30bf\u30d0\u30eb\u30d6\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +requestFilterValve.next=\u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +requestFilterValve.syntax=\u30ea\u30af\u30a8\u30b9\u30c8\u30d5\u30a3\u30eb\u30bf\u30d1\u30bf\u30fc\u30f3 {0} \u306b\u69cb\u6587\u30a8\u30e9\u30fc\u304c\u3042\u308a\u307e\u3059 +requestListenerValve.requestInit=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u521d\u671f\u5316\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +requestListenerValve.requestDestroy=\u30af\u30e9\u30b9 {0} \u306e\u30ea\u30b9\u30ca\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u306b\u5ec3\u68c4\u3059\u308b\u30e9\u30a4\u30d5\u30b5\u30a4\u30af\u30eb\u30a4\u30d9\u30f3\u30c8\u306e\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u9001\u4fe1\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jdbcAccessLogValve.exception=\u30a2\u30af\u30bb\u30b9\u30a8\u30f3\u30c8\u30ea\u306e\u633f\u5165\u3092\u5b9f\u884c\u4e2d\u306e\u4f8b\u5916\u3067\u3059 +jdbcAccessLogValve.close=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u63a5\u7d9a\u3092\u30af\u30ed\u30fc\u30ba\u4e2d\u306e\u4f8b\u5916\u3067\u3059 + +# Error report valve +valveBase.noNext=\u8a2d\u5b9a\u30a8\u30e9\u30fc: \u6b21\u306e\u30d0\u30eb\u30d6\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +errorReportValve.statusHeader=HTTP\u30b9\u30c6\u30fc\u30bf\u30b9 {0} - {1} +errorReportValve.exceptionReport=\u4f8b\u5916\u30ec\u30dd\u30fc\u30c8 +errorReportValve.statusReport=\u30b9\u30c6\u30fc\u30bf\u30b9\u30ec\u30dd\u30fc\u30c8 +errorReportValve.message=\u30e1\u30c3\u30bb\u30fc\u30b8 +errorReportValve.description=\u8aac\u660e +errorReportValve.exception=\u4f8b\u5916 +errorReportValve.rootCause=\u539f\u56e0 +errorReportValve.note=\u6ce8\u610f +errorReportValve.rootCauseInLogs=\u539f\u56e0\u306e\u3059\u3079\u3066\u306e\u30b9\u30bf\u30c3\u30af\u30c8\u30ec\u30fc\u30b9\u306f\u3001{0}\u306e\u30ed\u30b0\u306b\u8a18\u9332\u3055\u308c\u3066\u3044\u307e\u3059 diff --git a/java/org/apache/catalina/valves/PersistentValve.java b/java/org/apache/catalina/valves/PersistentValve.java index 9450bda3e..8aabed285 100644 --- a/java/org/apache/catalina/valves/PersistentValve.java +++ b/java/org/apache/catalina/valves/PersistentValve.java @@ -1,210 +1,210 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.Context; -import org.apache.catalina.Manager; -import org.apache.catalina.Session; -import org.apache.catalina.Store; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.core.StandardHost; -import org.apache.catalina.session.PersistentManager; -import org.apache.catalina.util.StringManager; - - -/** - * Valve that implements the default basic behavior for the - * StandardHost container implementation. - *

        - * USAGE CONSTRAINT: To work correctly it requires a PersistentManager. - * - * @author Jean-Frederic Clere - * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ - */ - -public class PersistentValve - extends ValveBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.PersistentValve/1.0"; - - - /** - * The string manager for this package. - */ - private static final StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Select the appropriate child Context to process this request, - * based on the specified request URI. If no matching Context can - * be found, return an appropriate HTTP error. - * - * @param request Request to be processed - * @param response Response to be produced - * - * @exception IOException if an input/output error occurred - * @exception ServletException if a servlet error occurred - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - // Select the Context to be used for this Request - StandardHost host = (StandardHost) getContainer(); - Context context = request.getContext(); - if (context == null) { - response.sendError - (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, - sm.getString("standardHost.noContext")); - return; - } - - // Bind the context CL to the current thread - Thread.currentThread().setContextClassLoader - (context.getLoader().getClassLoader()); - - // Update the session last access time for our session (if any) - String sessionId = request.getRequestedSessionId(); - Manager manager = context.getManager(); - if (sessionId != null && manager != null) { - if (manager instanceof PersistentManager) { - Store store = ((PersistentManager) manager).getStore(); - if (store != null) { - Session session = null; - try { - session = store.load(sessionId); - } catch (Exception e) { - container.getLogger().error("deserializeError"); - } - if (session != null) { - if (!session.isValid() || - isSessionStale(session, System.currentTimeMillis())) { - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("session swapped in is invalid or expired"); - session.expire(); - store.remove(sessionId); - } else { - session.setManager(manager); - // session.setId(sessionId); Only if new ??? - manager.add(session); - // ((StandardSession)session).activate(); - session.access(); - } - } - } - } - } - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("sessionId: " + sessionId); - - // Ask the next valve to process the request. - getNext().invoke(request, response); - - // Read the sessionid after the response. - // HttpSession hsess = hreq.getSession(false); - Session hsess; - try { - hsess = request.getSessionInternal(); - } catch (Exception ex) { - hsess = null; - } - String newsessionId = null; - if (hsess!=null) - newsessionId = hsess.getIdInternal(); - - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("newsessionId: " + newsessionId); - if (newsessionId!=null) { - /* store the session in the store and remove it from the manager */ - if (manager instanceof PersistentManager) { - Session session = manager.findSession(newsessionId); - Store store = ((PersistentManager) manager).getStore(); - if (store != null && session!=null && - session.isValid() && - !isSessionStale(session, System.currentTimeMillis())) { - // ((StandardSession)session).passivate(); - store.save(session); - ((PersistentManager) manager).removeSuper(session); - session.recycle(); - } else { - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("newsessionId store: " + store + " session: " + - session + " valid: " + session.isValid() + - " Staled: " + - isSessionStale(session, System.currentTimeMillis())); - - } - } else { - if (container.getLogger().isDebugEnabled()) - container.getLogger().debug("newsessionId Manager: " + manager); - } - } - } - - /** - * Indicate whether the session has been idle for longer - * than its expiration date as of the supplied time. - * - * FIXME: Probably belongs in the Session class. - */ - protected boolean isSessionStale(Session session, long timeNow) { - - int maxInactiveInterval = session.getMaxInactiveInterval(); - if (maxInactiveInterval >= 0) { - int timeIdle = // Truncate, do not round up - (int) ((timeNow - session.getLastAccessedTime()) / 1000L); - if (timeIdle >= maxInactiveInterval) - return true; - } - - return false; - - } - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.Context; +import org.apache.catalina.Manager; +import org.apache.catalina.Session; +import org.apache.catalina.Store; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.core.StandardHost; +import org.apache.catalina.session.PersistentManager; +import org.apache.catalina.util.StringManager; + + +/** + * Valve that implements the default basic behavior for the + * StandardHost container implementation. + *

        + * USAGE CONSTRAINT: To work correctly it requires a PersistentManager. + * + * @author Jean-Frederic Clere + * @version $Revision: 303826 $ $Date: 2005-03-31 12:31:54 +0200 (jeu., 31 mars 2005) $ + */ + +public class PersistentValve + extends ValveBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.PersistentValve/1.0"; + + + /** + * The string manager for this package. + */ + private static final StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Select the appropriate child Context to process this request, + * based on the specified request URI. If no matching Context can + * be found, return an appropriate HTTP error. + * + * @param request Request to be processed + * @param response Response to be produced + * + * @exception IOException if an input/output error occurred + * @exception ServletException if a servlet error occurred + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + // Select the Context to be used for this Request + StandardHost host = (StandardHost) getContainer(); + Context context = request.getContext(); + if (context == null) { + response.sendError + (HttpServletResponse.SC_INTERNAL_SERVER_ERROR, + sm.getString("standardHost.noContext")); + return; + } + + // Bind the context CL to the current thread + Thread.currentThread().setContextClassLoader + (context.getLoader().getClassLoader()); + + // Update the session last access time for our session (if any) + String sessionId = request.getRequestedSessionId(); + Manager manager = context.getManager(); + if (sessionId != null && manager != null) { + if (manager instanceof PersistentManager) { + Store store = ((PersistentManager) manager).getStore(); + if (store != null) { + Session session = null; + try { + session = store.load(sessionId); + } catch (Exception e) { + container.getLogger().error("deserializeError"); + } + if (session != null) { + if (!session.isValid() || + isSessionStale(session, System.currentTimeMillis())) { + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("session swapped in is invalid or expired"); + session.expire(); + store.remove(sessionId); + } else { + session.setManager(manager); + // session.setId(sessionId); Only if new ??? + manager.add(session); + // ((StandardSession)session).activate(); + session.access(); + } + } + } + } + } + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("sessionId: " + sessionId); + + // Ask the next valve to process the request. + getNext().invoke(request, response); + + // Read the sessionid after the response. + // HttpSession hsess = hreq.getSession(false); + Session hsess; + try { + hsess = request.getSessionInternal(); + } catch (Exception ex) { + hsess = null; + } + String newsessionId = null; + if (hsess!=null) + newsessionId = hsess.getIdInternal(); + + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("newsessionId: " + newsessionId); + if (newsessionId!=null) { + /* store the session in the store and remove it from the manager */ + if (manager instanceof PersistentManager) { + Session session = manager.findSession(newsessionId); + Store store = ((PersistentManager) manager).getStore(); + if (store != null && session!=null && + session.isValid() && + !isSessionStale(session, System.currentTimeMillis())) { + // ((StandardSession)session).passivate(); + store.save(session); + ((PersistentManager) manager).removeSuper(session); + session.recycle(); + } else { + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("newsessionId store: " + store + " session: " + + session + " valid: " + session.isValid() + + " Staled: " + + isSessionStale(session, System.currentTimeMillis())); + + } + } else { + if (container.getLogger().isDebugEnabled()) + container.getLogger().debug("newsessionId Manager: " + manager); + } + } + } + + /** + * Indicate whether the session has been idle for longer + * than its expiration date as of the supplied time. + * + * FIXME: Probably belongs in the Session class. + */ + protected boolean isSessionStale(Session session, long timeNow) { + + int maxInactiveInterval = session.getMaxInactiveInterval(); + if (maxInactiveInterval >= 0) { + int timeIdle = // Truncate, do not round up + (int) ((timeNow - session.getLastAccessedTime()) / 1000L); + if (timeIdle >= maxInactiveInterval) + return true; + } + + return false; + + } + +} diff --git a/java/org/apache/catalina/valves/RemoteAddrValve.java b/java/org/apache/catalina/valves/RemoteAddrValve.java index 95308abe8..e14a54507 100644 --- a/java/org/apache/catalina/valves/RemoteAddrValve.java +++ b/java/org/apache/catalina/valves/RemoteAddrValve.java @@ -1,85 +1,85 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import javax.servlet.ServletException; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; - - -/** - * Concrete implementation of RequestFilterValve that filters - * based on the string representation of the remote client's IP address. - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public final class RemoteAddrValve - extends RequestFilterValve { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.RemoteAddrValve/1.0"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Extract the desired request property, and pass it (along with the - * specified request and response objects) to the protected - * process() method to perform the actual filtering. - * This method must be implemented by a concrete subclass. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - process(request.getRequest().getRemoteAddr(), request, response); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + + +/** + * Concrete implementation of RequestFilterValve that filters + * based on the string representation of the remote client's IP address. + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public final class RemoteAddrValve + extends RequestFilterValve { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.RemoteAddrValve/1.0"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() method to perform the actual filtering. + * This method must be implemented by a concrete subclass. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + process(request.getRequest().getRemoteAddr(), request, response); + + } + + +} diff --git a/java/org/apache/catalina/valves/RemoteHostValve.java b/java/org/apache/catalina/valves/RemoteHostValve.java index 893bcea7b..80d439d56 100644 --- a/java/org/apache/catalina/valves/RemoteHostValve.java +++ b/java/org/apache/catalina/valves/RemoteHostValve.java @@ -1,85 +1,85 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import javax.servlet.ServletException; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; - - -/** - * Concrete implementation of RequestFilterValve that filters - * based on the remote client's host name. - * - * @author Craig R. McClanahan - * @version $Revision: 304096 $ $Date: 2005-09-20 23:02:12 +0200 (mar., 20 sept. 2005) $ - */ - -public final class RemoteHostValve - extends RequestFilterValve { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.RemoteHostValve/1.0"; - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Extract the desired request property, and pass it (along with the - * specified request and response objects) to the protected - * process() method to perform the actual filtering. - * This method must be implemented by a concrete subclass. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - process(request.getRequest().getRemoteHost(), request, response); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import javax.servlet.ServletException; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; + + +/** + * Concrete implementation of RequestFilterValve that filters + * based on the remote client's host name. + * + * @author Craig R. McClanahan + * @version $Revision: 304096 $ $Date: 2005-09-20 23:02:12 +0200 (mar., 20 sept. 2005) $ + */ + +public final class RemoteHostValve + extends RequestFilterValve { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.RemoteHostValve/1.0"; + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() method to perform the actual filtering. + * This method must be implemented by a concrete subclass. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + process(request.getRequest().getRemoteHost(), request, response); + + } + + +} diff --git a/java/org/apache/catalina/valves/RequestDumperValve.java b/java/org/apache/catalina/valves/RequestDumperValve.java index c883d5c4c..c5b5041fd 100644 --- a/java/org/apache/catalina/valves/RequestDumperValve.java +++ b/java/org/apache/catalina/valves/RequestDumperValve.java @@ -1,191 +1,191 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import java.util.Enumeration; - -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; - - -/** - *

        Implementation of a Valve that logs interesting contents from the - * specified Request (before processing) and the corresponding Response - * (after processing). It is especially useful in debugging problems - * related to headers and cookies.

        - * - *

        This Valve may be attached to any Container, depending on the granularity - * of the logging you wish to perform.

        - * - * @author Craig R. McClanahan - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class RequestDumperValve - extends ValveBase { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.RequestDumperValve/1.0"; - - - /** - * The StringManager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------- Properties - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Log the interesting request parameters, invoke the next Valve in the - * sequence, and log the interesting response parameters. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - Log log = container.getLogger(); - - // Log pre-service information - log.info("REQUEST URI =" + request.getRequestURI()); - log.info(" authType=" + request.getAuthType()); - log.info(" characterEncoding=" + request.getCharacterEncoding()); - log.info(" contentLength=" + request.getContentLength()); - log.info(" contentType=" + request.getContentType()); - log.info(" contextPath=" + request.getContextPath()); - Cookie cookies[] = request.getCookies(); - if (cookies != null) { - for (int i = 0; i < cookies.length; i++) - log.info(" cookie=" + cookies[i].getName() + "=" + - cookies[i].getValue()); - } - Enumeration hnames = request.getHeaderNames(); - while (hnames.hasMoreElements()) { - String hname = (String) hnames.nextElement(); - Enumeration hvalues = request.getHeaders(hname); - while (hvalues.hasMoreElements()) { - String hvalue = (String) hvalues.nextElement(); - log.info(" header=" + hname + "=" + hvalue); - } - } - log.info(" locale=" + request.getLocale()); - log.info(" method=" + request.getMethod()); - Enumeration pnames = request.getParameterNames(); - while (pnames.hasMoreElements()) { - String pname = (String) pnames.nextElement(); - String pvalues[] = request.getParameterValues(pname); - StringBuffer result = new StringBuffer(pname); - result.append('='); - for (int i = 0; i < pvalues.length; i++) { - if (i > 0) - result.append(", "); - result.append(pvalues[i]); - } - log.info(" parameter=" + result.toString()); - } - log.info(" pathInfo=" + request.getPathInfo()); - log.info(" protocol=" + request.getProtocol()); - log.info(" queryString=" + request.getQueryString()); - log.info(" remoteAddr=" + request.getRemoteAddr()); - log.info(" remoteHost=" + request.getRemoteHost()); - log.info(" remoteUser=" + request.getRemoteUser()); - log.info("requestedSessionId=" + request.getRequestedSessionId()); - log.info(" scheme=" + request.getScheme()); - log.info(" serverName=" + request.getServerName()); - log.info(" serverPort=" + request.getServerPort()); - log.info(" servletPath=" + request.getServletPath()); - log.info(" isSecure=" + request.isSecure()); - log.info("---------------------------------------------------------------"); - - // Perform the request - getNext().invoke(request, response); - - // Log post-service information - log.info("---------------------------------------------------------------"); - log.info(" authType=" + request.getAuthType()); - log.info(" contentLength=" + response.getContentLength()); - log.info(" contentType=" + response.getContentType()); - Cookie rcookies[] = response.getCookies(); - for (int i = 0; i < rcookies.length; i++) { - log.info(" cookie=" + rcookies[i].getName() + "=" + - rcookies[i].getValue() + "; domain=" + - rcookies[i].getDomain() + "; path=" + rcookies[i].getPath()); - } - String rhnames[] = response.getHeaderNames(); - for (int i = 0; i < rhnames.length; i++) { - String rhvalues[] = response.getHeaderValues(rhnames[i]); - for (int j = 0; j < rhvalues.length; j++) - log.info(" header=" + rhnames[i] + "=" + rhvalues[j]); - } - log.info(" message=" + response.getMessage()); - log.info(" remoteUser=" + request.getRemoteUser()); - log.info(" status=" + response.getStatus()); - log.info("==============================================================="); - - } - - - /** - * Return a String rendering of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("RequestDumperValve["); - if (container != null) - sb.append(container.getName()); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import java.util.Enumeration; + +import javax.servlet.ServletException; +import javax.servlet.http.Cookie; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; + + +/** + *

        Implementation of a Valve that logs interesting contents from the + * specified Request (before processing) and the corresponding Response + * (after processing). It is especially useful in debugging problems + * related to headers and cookies.

        + * + *

        This Valve may be attached to any Container, depending on the granularity + * of the logging you wish to perform.

        + * + * @author Craig R. McClanahan + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class RequestDumperValve + extends ValveBase { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.RequestDumperValve/1.0"; + + + /** + * The StringManager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------- Properties + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Log the interesting request parameters, invoke the next Valve in the + * sequence, and log the interesting response parameters. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + Log log = container.getLogger(); + + // Log pre-service information + log.info("REQUEST URI =" + request.getRequestURI()); + log.info(" authType=" + request.getAuthType()); + log.info(" characterEncoding=" + request.getCharacterEncoding()); + log.info(" contentLength=" + request.getContentLength()); + log.info(" contentType=" + request.getContentType()); + log.info(" contextPath=" + request.getContextPath()); + Cookie cookies[] = request.getCookies(); + if (cookies != null) { + for (int i = 0; i < cookies.length; i++) + log.info(" cookie=" + cookies[i].getName() + "=" + + cookies[i].getValue()); + } + Enumeration hnames = request.getHeaderNames(); + while (hnames.hasMoreElements()) { + String hname = (String) hnames.nextElement(); + Enumeration hvalues = request.getHeaders(hname); + while (hvalues.hasMoreElements()) { + String hvalue = (String) hvalues.nextElement(); + log.info(" header=" + hname + "=" + hvalue); + } + } + log.info(" locale=" + request.getLocale()); + log.info(" method=" + request.getMethod()); + Enumeration pnames = request.getParameterNames(); + while (pnames.hasMoreElements()) { + String pname = (String) pnames.nextElement(); + String pvalues[] = request.getParameterValues(pname); + StringBuffer result = new StringBuffer(pname); + result.append('='); + for (int i = 0; i < pvalues.length; i++) { + if (i > 0) + result.append(", "); + result.append(pvalues[i]); + } + log.info(" parameter=" + result.toString()); + } + log.info(" pathInfo=" + request.getPathInfo()); + log.info(" protocol=" + request.getProtocol()); + log.info(" queryString=" + request.getQueryString()); + log.info(" remoteAddr=" + request.getRemoteAddr()); + log.info(" remoteHost=" + request.getRemoteHost()); + log.info(" remoteUser=" + request.getRemoteUser()); + log.info("requestedSessionId=" + request.getRequestedSessionId()); + log.info(" scheme=" + request.getScheme()); + log.info(" serverName=" + request.getServerName()); + log.info(" serverPort=" + request.getServerPort()); + log.info(" servletPath=" + request.getServletPath()); + log.info(" isSecure=" + request.isSecure()); + log.info("---------------------------------------------------------------"); + + // Perform the request + getNext().invoke(request, response); + + // Log post-service information + log.info("---------------------------------------------------------------"); + log.info(" authType=" + request.getAuthType()); + log.info(" contentLength=" + response.getContentLength()); + log.info(" contentType=" + response.getContentType()); + Cookie rcookies[] = response.getCookies(); + for (int i = 0; i < rcookies.length; i++) { + log.info(" cookie=" + rcookies[i].getName() + "=" + + rcookies[i].getValue() + "; domain=" + + rcookies[i].getDomain() + "; path=" + rcookies[i].getPath()); + } + String rhnames[] = response.getHeaderNames(); + for (int i = 0; i < rhnames.length; i++) { + String rhvalues[] = response.getHeaderValues(rhnames[i]); + for (int j = 0; j < rhvalues.length; j++) + log.info(" header=" + rhnames[i] + "=" + rhvalues[j]); + } + log.info(" message=" + response.getMessage()); + log.info(" remoteUser=" + request.getRemoteUser()); + log.info(" status=" + response.getStatus()); + log.info("==============================================================="); + + } + + + /** + * Return a String rendering of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("RequestDumperValve["); + if (container != null) + sb.append(container.getName()); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/catalina/valves/RequestFilterValve.java b/java/org/apache/catalina/valves/RequestFilterValve.java index c34fb9f56..f2417d150 100644 --- a/java/org/apache/catalina/valves/RequestFilterValve.java +++ b/java/org/apache/catalina/valves/RequestFilterValve.java @@ -1,285 +1,285 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import java.util.ArrayList; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; - -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.StringManager; - -/** - * Implementation of a Valve that performs filtering based on comparing the - * appropriate request property (selected based on which subclass you choose - * to configure into your Container's pipeline) against a set of regular - * expressions configured for this Valve. - *

        - * This valve is configured by setting the allow and/or - * deny properties to a comma-delimited list of regular - * expressions (in the syntax supported by the jakarta-regexp library) to - * which the appropriate request property will be compared. Evaluation - * proceeds as follows: - *

          - *
        • The subclass extracts the request property to be filtered, and - * calls the common process() method. - *
        • If there are any deny expressions configured, the property will - * be compared to each such expression. If a match is found, this - * request will be rejected with a "Forbidden" HTTP response.
        • - *
        • If there are any allow expressions configured, the property will - * be compared to each such expression. If a match is found, this - * request will be allowed to pass through to the next Valve in the - * current pipeline.
        • - *
        • If one or more deny expressions was specified but no allow expressions, - * allow this request to pass through (because none of the deny - * expressions matched it). - *
        • The request will be rejected with a "Forbidden" HTTP response.
        • - *
        - *

        - * This Valve may be attached to any Container, depending on the granularity - * of the filtering you wish to perform. - * - * @author Craig R. McClanahan - * @version $Revision: 303161 $ $Date: 2004-09-01 12:10:10 +0200 (mer., 01 sept. 2004) $ - */ - -public abstract class RequestFilterValve - extends ValveBase { - - - // ----------------------------------------------------- Class Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.RequestFilterValve/1.0"; - - - /** - * The StringManager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * The comma-delimited set of allow expressions. - */ - protected String allow = null; - - - /** - * The set of allow regular expressions we will evaluate. - */ - protected Pattern allows[] = new Pattern[0]; - - - /** - * The set of deny regular expressions we will evaluate. - */ - protected Pattern denies[] = new Pattern[0]; - - - /** - * The comma-delimited set of deny expressions. - */ - protected String deny = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return a comma-delimited set of the allow expressions - * configured for this Valve, if any; otherwise, return null. - */ - public String getAllow() { - - return (this.allow); - - } - - - /** - * Set the comma-delimited set of the allow expressions - * configured for this Valve, if any. - * - * @param allow The new set of allow expressions - */ - public void setAllow(String allow) { - - this.allow = allow; - allows = precalculate(allow); - - } - - - /** - * Return a comma-delimited set of the deny expressions - * configured for this Valve, if any; otherwise, return null. - */ - public String getDeny() { - - return (this.deny); - - } - - - /** - * Set the comma-delimited set of the deny expressions - * configured for this Valve, if any. - * - * @param deny The new set of deny expressions - */ - public void setDeny(String deny) { - - this.deny = deny; - denies = precalculate(deny); - - } - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Extract the desired request property, and pass it (along with the - * specified request and response objects) to the protected - * process() method to perform the actual filtering. - * This method must be implemented by a concrete subclass. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public abstract void invoke(Request request, Response response) - throws IOException, ServletException; - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return an array of regular expression objects initialized from the - * specified argument, which must be null or a comma-delimited - * list of regular expression patterns. - * - * @param list The comma-separated list of patterns - * - * @exception IllegalArgumentException if one of the patterns has - * invalid syntax - */ - protected Pattern[] precalculate(String list) { - - if (list == null) - return (new Pattern[0]); - list = list.trim(); - if (list.length() < 1) - return (new Pattern[0]); - list += ","; - - ArrayList reList = new ArrayList(); - while (list.length() > 0) { - int comma = list.indexOf(','); - if (comma < 0) - break; - String pattern = list.substring(0, comma).trim(); - try { - reList.add(Pattern.compile(pattern)); - } catch (PatternSyntaxException e) { - IllegalArgumentException iae = new IllegalArgumentException - (sm.getString("requestFilterValve.syntax", pattern)); - iae.initCause(e); - throw iae; - } - list = list.substring(comma + 1); - } - - Pattern reArray[] = new Pattern[reList.size()]; - return ((Pattern[]) reList.toArray(reArray)); - - } - - - /** - * Perform the filtering that has been configured for this Valve, matching - * against the specified request property. - * - * @param property The request property on which to filter - * @param request The servlet request to be processed - * @param response The servlet response to be processed - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - protected void process(String property, - Request request, Response response) - throws IOException, ServletException { - - // Check the deny patterns, if any - for (int i = 0; i < denies.length; i++) { - if (denies[i].matcher(property).matches()) { - response.sendError(HttpServletResponse.SC_FORBIDDEN); - return; - } - } - - // Check the allow patterns, if any - for (int i = 0; i < allows.length; i++) { - if (allows[i].matcher(property).matches()) { - getNext().invoke(request, response); - return; - } - } - - // Allow if denies specified but not allows - if ((denies.length > 0) && (allows.length == 0)) { - getNext().invoke(request, response); - return; - } - - // Deny this request - response.sendError(HttpServletResponse.SC_FORBIDDEN); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import java.util.ArrayList; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.StringManager; + +/** + * Implementation of a Valve that performs filtering based on comparing the + * appropriate request property (selected based on which subclass you choose + * to configure into your Container's pipeline) against a set of regular + * expressions configured for this Valve. + *

        + * This valve is configured by setting the allow and/or + * deny properties to a comma-delimited list of regular + * expressions (in the syntax supported by the jakarta-regexp library) to + * which the appropriate request property will be compared. Evaluation + * proceeds as follows: + *

          + *
        • The subclass extracts the request property to be filtered, and + * calls the common process() method. + *
        • If there are any deny expressions configured, the property will + * be compared to each such expression. If a match is found, this + * request will be rejected with a "Forbidden" HTTP response.
        • + *
        • If there are any allow expressions configured, the property will + * be compared to each such expression. If a match is found, this + * request will be allowed to pass through to the next Valve in the + * current pipeline.
        • + *
        • If one or more deny expressions was specified but no allow expressions, + * allow this request to pass through (because none of the deny + * expressions matched it). + *
        • The request will be rejected with a "Forbidden" HTTP response.
        • + *
        + *

        + * This Valve may be attached to any Container, depending on the granularity + * of the filtering you wish to perform. + * + * @author Craig R. McClanahan + * @version $Revision: 303161 $ $Date: 2004-09-01 12:10:10 +0200 (mer., 01 sept. 2004) $ + */ + +public abstract class RequestFilterValve + extends ValveBase { + + + // ----------------------------------------------------- Class Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.RequestFilterValve/1.0"; + + + /** + * The StringManager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * The comma-delimited set of allow expressions. + */ + protected String allow = null; + + + /** + * The set of allow regular expressions we will evaluate. + */ + protected Pattern allows[] = new Pattern[0]; + + + /** + * The set of deny regular expressions we will evaluate. + */ + protected Pattern denies[] = new Pattern[0]; + + + /** + * The comma-delimited set of deny expressions. + */ + protected String deny = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return a comma-delimited set of the allow expressions + * configured for this Valve, if any; otherwise, return null. + */ + public String getAllow() { + + return (this.allow); + + } + + + /** + * Set the comma-delimited set of the allow expressions + * configured for this Valve, if any. + * + * @param allow The new set of allow expressions + */ + public void setAllow(String allow) { + + this.allow = allow; + allows = precalculate(allow); + + } + + + /** + * Return a comma-delimited set of the deny expressions + * configured for this Valve, if any; otherwise, return null. + */ + public String getDeny() { + + return (this.deny); + + } + + + /** + * Set the comma-delimited set of the deny expressions + * configured for this Valve, if any. + * + * @param deny The new set of deny expressions + */ + public void setDeny(String deny) { + + this.deny = deny; + denies = precalculate(deny); + + } + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Extract the desired request property, and pass it (along with the + * specified request and response objects) to the protected + * process() method to perform the actual filtering. + * This method must be implemented by a concrete subclass. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public abstract void invoke(Request request, Response response) + throws IOException, ServletException; + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return an array of regular expression objects initialized from the + * specified argument, which must be null or a comma-delimited + * list of regular expression patterns. + * + * @param list The comma-separated list of patterns + * + * @exception IllegalArgumentException if one of the patterns has + * invalid syntax + */ + protected Pattern[] precalculate(String list) { + + if (list == null) + return (new Pattern[0]); + list = list.trim(); + if (list.length() < 1) + return (new Pattern[0]); + list += ","; + + ArrayList reList = new ArrayList(); + while (list.length() > 0) { + int comma = list.indexOf(','); + if (comma < 0) + break; + String pattern = list.substring(0, comma).trim(); + try { + reList.add(Pattern.compile(pattern)); + } catch (PatternSyntaxException e) { + IllegalArgumentException iae = new IllegalArgumentException + (sm.getString("requestFilterValve.syntax", pattern)); + iae.initCause(e); + throw iae; + } + list = list.substring(comma + 1); + } + + Pattern reArray[] = new Pattern[reList.size()]; + return ((Pattern[]) reList.toArray(reArray)); + + } + + + /** + * Perform the filtering that has been configured for this Valve, matching + * against the specified request property. + * + * @param property The request property on which to filter + * @param request The servlet request to be processed + * @param response The servlet response to be processed + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + protected void process(String property, + Request request, Response response) + throws IOException, ServletException { + + // Check the deny patterns, if any + for (int i = 0; i < denies.length; i++) { + if (denies[i].matcher(property).matches()) { + response.sendError(HttpServletResponse.SC_FORBIDDEN); + return; + } + } + + // Check the allow patterns, if any + for (int i = 0; i < allows.length; i++) { + if (allows[i].matcher(property).matches()) { + getNext().invoke(request, response); + return; + } + } + + // Allow if denies specified but not allows + if ((denies.length > 0) && (allows.length == 0)) { + getNext().invoke(request, response); + return; + } + + // Deny this request + response.sendError(HttpServletResponse.SC_FORBIDDEN); + + } + + +} diff --git a/java/org/apache/catalina/valves/SemaphoreValve.java b/java/org/apache/catalina/valves/SemaphoreValve.java index 990f0f0a5..3c54502cf 100644 --- a/java/org/apache/catalina/valves/SemaphoreValve.java +++ b/java/org/apache/catalina/valves/SemaphoreValve.java @@ -1,276 +1,276 @@ -/* - * Copyright 1999-2001,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; -import java.util.concurrent.Semaphore; - -import javax.servlet.ServletException; - -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleException; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.util.LifecycleSupport; -import org.apache.catalina.util.StringManager; - - -/** - *

        Implementation of a Valve that limits concurrency.

        - * - *

        This Valve may be attached to any Container, depending on the granularity - * of the concurrency control you wish to perform.

        - * - * @author Remy Maucherat - * @version $Revision: 386404 $ $Date: 2006-03-16 18:50:37 +0100 (jeu., 16 mars 2006) $ - */ - -public class SemaphoreValve - extends ValveBase - implements Lifecycle { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The descriptive information related to this implementation. - */ - private static final String info = - "org.apache.catalina.valves.SemaphoreValve/1.0"; - - - /** - * The string manager for this package. - */ - private StringManager sm = - StringManager.getManager(Constants.Package); - - - /** - * Semaphore. - */ - protected Semaphore semaphore = null; - - - /** - * The lifecycle event support for this component. - */ - protected LifecycleSupport lifecycle = new LifecycleSupport(this); - - - /** - * Has this component been started yet? - */ - private boolean started = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Concurrency level of the semaphore. - */ - protected int concurrency = 10; - public int getConcurrency() { return concurrency; } - public void setConcurrency(int concurrency) { this.concurrency = concurrency; } - - - /** - * Fairness of the semaphore. - */ - protected boolean fairness = false; - public boolean getFairness() { return fairness; } - public void setFairness(boolean fairness) { this.fairness = fairness; } - - - /** - * Block until a permit is available. - */ - protected boolean block = true; - public boolean getBlock() { return block; } - public void setBlock(boolean block) { this.block = block; } - - - /** - * Block interruptibly until a permit is available. - */ - protected boolean interruptible = false; - public boolean getInterruptible() { return interruptible; } - public void setInterruptible(boolean interruptible) { this.interruptible = interruptible; } - - - // ------------------------------------------------------ Lifecycle Methods - - - /** - * Add a lifecycle event listener to this component. - * - * @param listener The listener to add - */ - public void addLifecycleListener(LifecycleListener listener) { - - lifecycle.addLifecycleListener(listener); - - } - - - /** - * Get the lifecycle listeners associated with this lifecycle. If this - * Lifecycle has no listeners registered, a zero-length array is returned. - */ - public LifecycleListener[] findLifecycleListeners() { - - return lifecycle.findLifecycleListeners(); - - } - - - /** - * Remove a lifecycle event listener from this component. - * - * @param listener The listener to add - */ - public void removeLifecycleListener(LifecycleListener listener) { - - lifecycle.removeLifecycleListener(listener); - - } - - - /** - * Prepare for the beginning of active use of the public methods of this - * component. This method should be called after configure(), - * and before any of the public methods of the component are utilized. - * - * @exception LifecycleException if this component detects a fatal error - * that prevents this component from being used - */ - public void start() throws LifecycleException { - - // Validate and update our current component state - if (started) - throw new LifecycleException - (sm.getString("semaphoreValve.alreadyStarted")); - lifecycle.fireLifecycleEvent(START_EVENT, null); - started = true; - - semaphore = new Semaphore(concurrency, fairness); - - } - - - /** - * Gracefully terminate the active use of the public methods of this - * component. This method should be the last one called on a given - * instance of this component. - * - * @exception LifecycleException if this component detects a fatal error - * that needs to be reported - */ - public void stop() throws LifecycleException { - - // Validate and update our current component state - if (!started) - throw new LifecycleException - (sm.getString("semaphoreValve.notStarted")); - lifecycle.fireLifecycleEvent(STOP_EVENT, null); - started = false; - - semaphore = null; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - return (info); - } - - - /** - * Do concurrency control on the request using the semaphore. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public void invoke(Request request, Response response) - throws IOException, ServletException { - - if (controlConcurrency(request, response)) { - boolean shouldRelease = true; - try { - if (block) { - if (interruptible) { - try { - semaphore.acquire(); - } catch (InterruptedException e) { - shouldRelease = false; - permitDenied(request, response); - return; - } - } else { - semaphore.acquireUninterruptibly(); - } - } else { - if (!semaphore.tryAcquire()) { - shouldRelease = false; - permitDenied(request, response); - return; - } - } - getNext().invoke(request, response); - } finally { - if (shouldRelease) { - semaphore.release(); - } - } - } else { - getNext().invoke(request, response); - } - - } - - - /** - * Subclass friendly method to add conditions. - */ - public boolean controlConcurrency(Request request, Response response) { - return true; - } - - - /** - * Subclass friendly method to add error handling when a permit isn't granted. - */ - public void permitDenied(Request request, Response response) - throws IOException, ServletException { - } - - -} +/* + * Copyright 1999-2001,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; +import java.util.concurrent.Semaphore; + +import javax.servlet.ServletException; + +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleException; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.util.LifecycleSupport; +import org.apache.catalina.util.StringManager; + + +/** + *

        Implementation of a Valve that limits concurrency.

        + * + *

        This Valve may be attached to any Container, depending on the granularity + * of the concurrency control you wish to perform.

        + * + * @author Remy Maucherat + * @version $Revision: 386404 $ $Date: 2006-03-16 18:50:37 +0100 (jeu., 16 mars 2006) $ + */ + +public class SemaphoreValve + extends ValveBase + implements Lifecycle { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The descriptive information related to this implementation. + */ + private static final String info = + "org.apache.catalina.valves.SemaphoreValve/1.0"; + + + /** + * The string manager for this package. + */ + private StringManager sm = + StringManager.getManager(Constants.Package); + + + /** + * Semaphore. + */ + protected Semaphore semaphore = null; + + + /** + * The lifecycle event support for this component. + */ + protected LifecycleSupport lifecycle = new LifecycleSupport(this); + + + /** + * Has this component been started yet? + */ + private boolean started = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Concurrency level of the semaphore. + */ + protected int concurrency = 10; + public int getConcurrency() { return concurrency; } + public void setConcurrency(int concurrency) { this.concurrency = concurrency; } + + + /** + * Fairness of the semaphore. + */ + protected boolean fairness = false; + public boolean getFairness() { return fairness; } + public void setFairness(boolean fairness) { this.fairness = fairness; } + + + /** + * Block until a permit is available. + */ + protected boolean block = true; + public boolean getBlock() { return block; } + public void setBlock(boolean block) { this.block = block; } + + + /** + * Block interruptibly until a permit is available. + */ + protected boolean interruptible = false; + public boolean getInterruptible() { return interruptible; } + public void setInterruptible(boolean interruptible) { this.interruptible = interruptible; } + + + // ------------------------------------------------------ Lifecycle Methods + + + /** + * Add a lifecycle event listener to this component. + * + * @param listener The listener to add + */ + public void addLifecycleListener(LifecycleListener listener) { + + lifecycle.addLifecycleListener(listener); + + } + + + /** + * Get the lifecycle listeners associated with this lifecycle. If this + * Lifecycle has no listeners registered, a zero-length array is returned. + */ + public LifecycleListener[] findLifecycleListeners() { + + return lifecycle.findLifecycleListeners(); + + } + + + /** + * Remove a lifecycle event listener from this component. + * + * @param listener The listener to add + */ + public void removeLifecycleListener(LifecycleListener listener) { + + lifecycle.removeLifecycleListener(listener); + + } + + + /** + * Prepare for the beginning of active use of the public methods of this + * component. This method should be called after configure(), + * and before any of the public methods of the component are utilized. + * + * @exception LifecycleException if this component detects a fatal error + * that prevents this component from being used + */ + public void start() throws LifecycleException { + + // Validate and update our current component state + if (started) + throw new LifecycleException + (sm.getString("semaphoreValve.alreadyStarted")); + lifecycle.fireLifecycleEvent(START_EVENT, null); + started = true; + + semaphore = new Semaphore(concurrency, fairness); + + } + + + /** + * Gracefully terminate the active use of the public methods of this + * component. This method should be the last one called on a given + * instance of this component. + * + * @exception LifecycleException if this component detects a fatal error + * that needs to be reported + */ + public void stop() throws LifecycleException { + + // Validate and update our current component state + if (!started) + throw new LifecycleException + (sm.getString("semaphoreValve.notStarted")); + lifecycle.fireLifecycleEvent(STOP_EVENT, null); + started = false; + + semaphore = null; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + return (info); + } + + + /** + * Do concurrency control on the request using the semaphore. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public void invoke(Request request, Response response) + throws IOException, ServletException { + + if (controlConcurrency(request, response)) { + boolean shouldRelease = true; + try { + if (block) { + if (interruptible) { + try { + semaphore.acquire(); + } catch (InterruptedException e) { + shouldRelease = false; + permitDenied(request, response); + return; + } + } else { + semaphore.acquireUninterruptibly(); + } + } else { + if (!semaphore.tryAcquire()) { + shouldRelease = false; + permitDenied(request, response); + return; + } + } + getNext().invoke(request, response); + } finally { + if (shouldRelease) { + semaphore.release(); + } + } + } else { + getNext().invoke(request, response); + } + + } + + + /** + * Subclass friendly method to add conditions. + */ + public boolean controlConcurrency(Request request, Response response) { + return true; + } + + + /** + * Subclass friendly method to add error handling when a permit isn't granted. + */ + public void permitDenied(Request request, Response response) + throws IOException, ServletException { + } + + +} diff --git a/java/org/apache/catalina/valves/ValveBase.java b/java/org/apache/catalina/valves/ValveBase.java index 25cdf7f4c..6f1f94caf 100644 --- a/java/org/apache/catalina/valves/ValveBase.java +++ b/java/org/apache/catalina/valves/ValveBase.java @@ -1,320 +1,320 @@ -/* - * Copyright 1999-2001,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.catalina.valves; - - -import java.io.IOException; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; -import javax.servlet.ServletException; - -import org.apache.catalina.Contained; -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Pipeline; -import org.apache.catalina.Valve; -import org.apache.catalina.Wrapper; -import org.apache.catalina.connector.Request; -import org.apache.catalina.connector.Response; -import org.apache.catalina.core.ContainerBase; -import org.apache.catalina.util.StringManager; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - - -/** - * Convenience base class for implementations of the Valve interface. - * A subclass MUST implement an invoke() - * method to provide the required functionality, and MAY - * implement the Lifecycle interface to provide configuration - * management and lifecycle support. - * - * @author Craig R. McClanahan - * @version $Revision: 304023 $ $Date: 2005-07-26 14:45:22 +0200 (mar., 26 juil. 2005) $ - */ - -public abstract class ValveBase - implements Contained, Valve, MBeanRegistration { - private static Log log = LogFactory.getLog(ValveBase.class); - - //------------------------------------------------------ Instance Variables - - - /** - * The Container whose pipeline this Valve is a component of. - */ - protected Container container = null; - - - /** - * Container log - */ - protected Log containerLog = null; - - - /** - * Descriptive information about this Valve implementation. This value - * should be overridden by subclasses. - */ - protected static String info = - "org.apache.catalina.core.ValveBase/1.0"; - - - /** - * The next Valve in the pipeline this Valve is a component of. - */ - protected Valve next = null; - - - /** - * The string manager for this package. - */ - protected final static StringManager sm = - StringManager.getManager(Constants.Package); - - - //-------------------------------------------------------------- Properties - - - /** - * Return the Container with which this Valve is associated, if any. - */ - public Container getContainer() { - - return (container); - - } - - - /** - * Set the Container with which this Valve is associated, if any. - * - * @param container The new associated container - */ - public void setContainer(Container container) { - - this.container = container; - - } - - - /** - * Return descriptive information about this Valve implementation. - */ - public String getInfo() { - - return (info); - - } - - - /** - * Return the next Valve in this pipeline, or null if this - * is the last Valve in the pipeline. - */ - public Valve getNext() { - - return (next); - - } - - - /** - * Set the Valve that follows this one in the pipeline it is part of. - * - * @param valve The new next valve - */ - public void setNext(Valve valve) { - - this.next = valve; - - } - - - //---------------------------------------------------------- Public Methods - - - /** - * Execute a periodic task, such as reloading, etc. This method will be - * invoked inside the classloading context of this container. Unexpected - * throwables will be caught and logged. - */ - public void backgroundProcess() { - } - - - /** - * The implementation-specific logic represented by this Valve. See the - * Valve description for the normal design patterns for this method. - *

        - * This method MUST be provided by a subclass. - * - * @param request The servlet request to be processed - * @param response The servlet response to be created - * - * @exception IOException if an input/output error occurs - * @exception ServletException if a servlet error occurs - */ - public abstract void invoke(Request request, Response response) - throws IOException, ServletException; - - - /** - * Return a String rendering of this object. - */ - public String toString() { - StringBuffer sb = new StringBuffer(this.getClass().getName()); - sb.append("["); - if (container != null) - sb.append(container.getName()); - sb.append("]"); - return (sb.toString()); - } - - - // -------------------- JMX and Registration -------------------- - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - protected ObjectName controller; - - public ObjectName getObjectName() { - return oname; - } - - public void setObjectName(ObjectName oname) { - this.oname = oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - - - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - public ObjectName getController() { - return controller; - } - - public void setController(ObjectName controller) { - this.controller = controller; - } - - /** From the name, extract the parent object name - * - * @param valveName The valve name - * @return ObjectName The parent name - */ - public ObjectName getParentName( ObjectName valveName ) { - - return null; - } - - public ObjectName createObjectName(String domain, ObjectName parent) - throws MalformedObjectNameException - { - Container container=this.getContainer(); - if( container == null || ! (container instanceof ContainerBase) ) - return null; - this.containerLog = container.getLogger(); - ContainerBase containerBase=(ContainerBase)container; - Pipeline pipe=containerBase.getPipeline(); - Valve valves[]=pipe.getValves(); - - /* Compute the "parent name" part */ - String parentName=""; - if (container instanceof Engine) { - } else if (container instanceof Host) { - parentName=",host=" +container.getName(); - } else if (container instanceof Context) { - String path = ((Context)container).getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) container.getParent(); - parentName=",path=" + path + ",host=" + - host.getName(); - } else if (container instanceof Wrapper) { - Context ctx = (Context) container.getParent(); - String path = ctx.getPath(); - if (path.length() < 1) { - path = "/"; - } - Host host = (Host) ctx.getParent(); - parentName=",servlet=" + container.getName() + - ",path=" + path + ",host=" + host.getName(); - } - log.debug("valve parent=" + parentName + " " + parent); - - String className=this.getClass().getName(); - int period = className.lastIndexOf('.'); - if (period >= 0) - className = className.substring(period + 1); - - int seq=0; - for( int i=0; i 0 ) { - ext=",seq=" + seq; - } - - ObjectName objectName = - new ObjectName( domain + ":type=Valve,name=" + className + ext + parentName); - log.debug("valve objectname = "+objectName); - return objectName; - } - - // -------------------- JMX data -------------------- - - public ObjectName getContainerName() { - if( container== null) return null; - return ((ContainerBase)container).getJmxName(); - } -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.catalina.valves; + + +import java.io.IOException; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; +import javax.servlet.ServletException; + +import org.apache.catalina.Contained; +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Pipeline; +import org.apache.catalina.Valve; +import org.apache.catalina.Wrapper; +import org.apache.catalina.connector.Request; +import org.apache.catalina.connector.Response; +import org.apache.catalina.core.ContainerBase; +import org.apache.catalina.util.StringManager; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + + +/** + * Convenience base class for implementations of the Valve interface. + * A subclass MUST implement an invoke() + * method to provide the required functionality, and MAY + * implement the Lifecycle interface to provide configuration + * management and lifecycle support. + * + * @author Craig R. McClanahan + * @version $Revision: 304023 $ $Date: 2005-07-26 14:45:22 +0200 (mar., 26 juil. 2005) $ + */ + +public abstract class ValveBase + implements Contained, Valve, MBeanRegistration { + private static Log log = LogFactory.getLog(ValveBase.class); + + //------------------------------------------------------ Instance Variables + + + /** + * The Container whose pipeline this Valve is a component of. + */ + protected Container container = null; + + + /** + * Container log + */ + protected Log containerLog = null; + + + /** + * Descriptive information about this Valve implementation. This value + * should be overridden by subclasses. + */ + protected static String info = + "org.apache.catalina.core.ValveBase/1.0"; + + + /** + * The next Valve in the pipeline this Valve is a component of. + */ + protected Valve next = null; + + + /** + * The string manager for this package. + */ + protected final static StringManager sm = + StringManager.getManager(Constants.Package); + + + //-------------------------------------------------------------- Properties + + + /** + * Return the Container with which this Valve is associated, if any. + */ + public Container getContainer() { + + return (container); + + } + + + /** + * Set the Container with which this Valve is associated, if any. + * + * @param container The new associated container + */ + public void setContainer(Container container) { + + this.container = container; + + } + + + /** + * Return descriptive information about this Valve implementation. + */ + public String getInfo() { + + return (info); + + } + + + /** + * Return the next Valve in this pipeline, or null if this + * is the last Valve in the pipeline. + */ + public Valve getNext() { + + return (next); + + } + + + /** + * Set the Valve that follows this one in the pipeline it is part of. + * + * @param valve The new next valve + */ + public void setNext(Valve valve) { + + this.next = valve; + + } + + + //---------------------------------------------------------- Public Methods + + + /** + * Execute a periodic task, such as reloading, etc. This method will be + * invoked inside the classloading context of this container. Unexpected + * throwables will be caught and logged. + */ + public void backgroundProcess() { + } + + + /** + * The implementation-specific logic represented by this Valve. See the + * Valve description for the normal design patterns for this method. + *

        + * This method MUST be provided by a subclass. + * + * @param request The servlet request to be processed + * @param response The servlet response to be created + * + * @exception IOException if an input/output error occurs + * @exception ServletException if a servlet error occurs + */ + public abstract void invoke(Request request, Response response) + throws IOException, ServletException; + + + /** + * Return a String rendering of this object. + */ + public String toString() { + StringBuffer sb = new StringBuffer(this.getClass().getName()); + sb.append("["); + if (container != null) + sb.append(container.getName()); + sb.append("]"); + return (sb.toString()); + } + + + // -------------------- JMX and Registration -------------------- + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + protected ObjectName controller; + + public ObjectName getObjectName() { + return oname; + } + + public void setObjectName(ObjectName oname) { + this.oname = oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + + + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + public ObjectName getController() { + return controller; + } + + public void setController(ObjectName controller) { + this.controller = controller; + } + + /** From the name, extract the parent object name + * + * @param valveName The valve name + * @return ObjectName The parent name + */ + public ObjectName getParentName( ObjectName valveName ) { + + return null; + } + + public ObjectName createObjectName(String domain, ObjectName parent) + throws MalformedObjectNameException + { + Container container=this.getContainer(); + if( container == null || ! (container instanceof ContainerBase) ) + return null; + this.containerLog = container.getLogger(); + ContainerBase containerBase=(ContainerBase)container; + Pipeline pipe=containerBase.getPipeline(); + Valve valves[]=pipe.getValves(); + + /* Compute the "parent name" part */ + String parentName=""; + if (container instanceof Engine) { + } else if (container instanceof Host) { + parentName=",host=" +container.getName(); + } else if (container instanceof Context) { + String path = ((Context)container).getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) container.getParent(); + parentName=",path=" + path + ",host=" + + host.getName(); + } else if (container instanceof Wrapper) { + Context ctx = (Context) container.getParent(); + String path = ctx.getPath(); + if (path.length() < 1) { + path = "/"; + } + Host host = (Host) ctx.getParent(); + parentName=",servlet=" + container.getName() + + ",path=" + path + ",host=" + host.getName(); + } + log.debug("valve parent=" + parentName + " " + parent); + + String className=this.getClass().getName(); + int period = className.lastIndexOf('.'); + if (period >= 0) + className = className.substring(period + 1); + + int seq=0; + for( int i=0; i 0 ) { + ext=",seq=" + seq; + } + + ObjectName objectName = + new ObjectName( domain + ":type=Valve,name=" + className + ext + parentName); + log.debug("valve objectname = "+objectName); + return objectName; + } + + // -------------------- JMX data -------------------- + + public ObjectName getContainerName() { + if( container== null) return null; + return ((ContainerBase)container).getJmxName(); + } +} diff --git a/java/org/apache/catalina/valves/mbeans-descriptors.xml b/java/org/apache/catalina/valves/mbeans-descriptors.xml index 43e460879..2bf847dea 100644 --- a/java/org/apache/catalina/valves/mbeans-descriptors.xml +++ b/java/org/apache/catalina/valves/mbeans-descriptors.xml @@ -1,292 +1,292 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/catalina/valves/package.html b/java/org/apache/catalina/valves/package.html index f4aa39b57..23cd0ac4c 100644 --- a/java/org/apache/catalina/valves/package.html +++ b/java/org/apache/catalina/valves/package.html @@ -1,12 +1,12 @@ - - -

        This package contains a variety of small Valve implementations that do -not warrant being packaged separately. In addition, there is a convenience -base class (ValveBase) that supports the usual mechanisms for -including custom Valves into the corresponding Pipeline.

        - -

        Other packages that include Valves include -org.apache.tomcat.logger and -org.apache.tomcat.security.

        - - + + +

        This package contains a variety of small Valve implementations that do +not warrant being packaged separately. In addition, there is a convenience +base class (ValveBase) that supports the usual mechanisms for +including custom Valves into the corresponding Pipeline.

        + +

        Other packages that include Valves include +org.apache.tomcat.logger and +org.apache.tomcat.security.

        + + diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java index 10b8acd6b..b5edb1934 100644 --- a/java/org/apache/coyote/ActionCode.java +++ b/java/org/apache/coyote/ActionCode.java @@ -1,153 +1,153 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - - -/** - * Enumerated class containing the adapter event codes. - * Actions represent callbacks from the servlet container to the coyote - * connector. - * - * Actions are implemented by ProtocolHandler, using the ActionHook interface. - * - * @see ProtocolHandler - * @see ActionHook - * @author Remy Maucherat - */ -public final class ActionCode { - - - // -------------------------------------------------------------- Constants - - - public static final ActionCode ACTION_ACK = new ActionCode(1); - - - public static final ActionCode ACTION_CLOSE = new ActionCode(2); - - - public static final ActionCode ACTION_COMMIT = new ActionCode(3); - - - /** - * A flush() operation originated by the client ( i.e. a flush() on - * the servlet output stream or writer, called by a servlet ). - * - * Argument is the Response. - */ - public static final ActionCode ACTION_CLIENT_FLUSH = new ActionCode(4); - - - public static final ActionCode ACTION_CUSTOM = new ActionCode(5); - - - public static final ActionCode ACTION_RESET = new ActionCode(6); - - - public static final ActionCode ACTION_START = new ActionCode(7); - - - public static final ActionCode ACTION_STOP = new ActionCode(8); - - - public static final ActionCode ACTION_WEBAPP = new ActionCode(9); - - /** Hook called after request, but before recycling. Can be used - for logging, to update counters, custom cleanup - the request - is still visible - */ - public static final ActionCode ACTION_POST_REQUEST = new ActionCode(10); - - /** - * Callback for lazy evaluation - extract the remote host address. - */ - public static final ActionCode ACTION_REQ_HOST_ATTRIBUTE = - new ActionCode(11); - - - /** - * Callback for lazy evaluation - extract the remote host infos (address, name, port) and local address. - */ - public static final ActionCode ACTION_REQ_HOST_ADDR_ATTRIBUTE = new ActionCode(12); - - /** - * Callback for lazy evaluation - extract the SSL-related attributes. - */ - public static final ActionCode ACTION_REQ_SSL_ATTRIBUTE = new ActionCode(13); - - - /** Chain for request creation. Called each time a new request is created - ( requests are recycled ). - */ - public static final ActionCode ACTION_NEW_REQUEST = new ActionCode(14); - - - /** - * Callback for lazy evaluation - extract the SSL-certificate - * (including forcing a re-handshake if necessary) - */ - public static final ActionCode ACTION_REQ_SSL_CERTIFICATE = new ActionCode(15); - - - /** - * Callback for lazy evaluation - socket remote port. - **/ - public static final ActionCode ACTION_REQ_REMOTEPORT_ATTRIBUTE = new ActionCode(16); - - - /** - * Callback for lazy evaluation - socket local port. - **/ - public static final ActionCode ACTION_REQ_LOCALPORT_ATTRIBUTE = new ActionCode(17); - - - /** - * Callback for lazy evaluation - local address. - **/ - public static final ActionCode ACTION_REQ_LOCAL_ADDR_ATTRIBUTE = new ActionCode(18); - - - /** - * Callback for lazy evaluation - local address. - **/ - public static final ActionCode ACTION_REQ_LOCAL_NAME_ATTRIBUTE = new ActionCode(19); - - - /** - * Callback for setting FORM auth body replay - */ - public static final ActionCode ACTION_REQ_SET_BODY_REPLAY = new ActionCode(20); - - - // ----------------------------------------------------------- Constructors - int code; - - /** - * Private constructor. - */ - private ActionCode(int code) { - this.code=code; - } - - /** Action id, useable in switches and table indexes - */ - public int getCode() { - return code; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + + +/** + * Enumerated class containing the adapter event codes. + * Actions represent callbacks from the servlet container to the coyote + * connector. + * + * Actions are implemented by ProtocolHandler, using the ActionHook interface. + * + * @see ProtocolHandler + * @see ActionHook + * @author Remy Maucherat + */ +public final class ActionCode { + + + // -------------------------------------------------------------- Constants + + + public static final ActionCode ACTION_ACK = new ActionCode(1); + + + public static final ActionCode ACTION_CLOSE = new ActionCode(2); + + + public static final ActionCode ACTION_COMMIT = new ActionCode(3); + + + /** + * A flush() operation originated by the client ( i.e. a flush() on + * the servlet output stream or writer, called by a servlet ). + * + * Argument is the Response. + */ + public static final ActionCode ACTION_CLIENT_FLUSH = new ActionCode(4); + + + public static final ActionCode ACTION_CUSTOM = new ActionCode(5); + + + public static final ActionCode ACTION_RESET = new ActionCode(6); + + + public static final ActionCode ACTION_START = new ActionCode(7); + + + public static final ActionCode ACTION_STOP = new ActionCode(8); + + + public static final ActionCode ACTION_WEBAPP = new ActionCode(9); + + /** Hook called after request, but before recycling. Can be used + for logging, to update counters, custom cleanup - the request + is still visible + */ + public static final ActionCode ACTION_POST_REQUEST = new ActionCode(10); + + /** + * Callback for lazy evaluation - extract the remote host address. + */ + public static final ActionCode ACTION_REQ_HOST_ATTRIBUTE = + new ActionCode(11); + + + /** + * Callback for lazy evaluation - extract the remote host infos (address, name, port) and local address. + */ + public static final ActionCode ACTION_REQ_HOST_ADDR_ATTRIBUTE = new ActionCode(12); + + /** + * Callback for lazy evaluation - extract the SSL-related attributes. + */ + public static final ActionCode ACTION_REQ_SSL_ATTRIBUTE = new ActionCode(13); + + + /** Chain for request creation. Called each time a new request is created + ( requests are recycled ). + */ + public static final ActionCode ACTION_NEW_REQUEST = new ActionCode(14); + + + /** + * Callback for lazy evaluation - extract the SSL-certificate + * (including forcing a re-handshake if necessary) + */ + public static final ActionCode ACTION_REQ_SSL_CERTIFICATE = new ActionCode(15); + + + /** + * Callback for lazy evaluation - socket remote port. + **/ + public static final ActionCode ACTION_REQ_REMOTEPORT_ATTRIBUTE = new ActionCode(16); + + + /** + * Callback for lazy evaluation - socket local port. + **/ + public static final ActionCode ACTION_REQ_LOCALPORT_ATTRIBUTE = new ActionCode(17); + + + /** + * Callback for lazy evaluation - local address. + **/ + public static final ActionCode ACTION_REQ_LOCAL_ADDR_ATTRIBUTE = new ActionCode(18); + + + /** + * Callback for lazy evaluation - local address. + **/ + public static final ActionCode ACTION_REQ_LOCAL_NAME_ATTRIBUTE = new ActionCode(19); + + + /** + * Callback for setting FORM auth body replay + */ + public static final ActionCode ACTION_REQ_SET_BODY_REPLAY = new ActionCode(20); + + + // ----------------------------------------------------------- Constructors + int code; + + /** + * Private constructor. + */ + private ActionCode(int code) { + this.code=code; + } + + /** Action id, useable in switches and table indexes + */ + public int getCode() { + return code; + } + + +} diff --git a/java/org/apache/coyote/ActionHook.java b/java/org/apache/coyote/ActionHook.java index 74cde276d..bc3c6dc88 100644 --- a/java/org/apache/coyote/ActionHook.java +++ b/java/org/apache/coyote/ActionHook.java @@ -1,47 +1,47 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - - -/** - * Action hook. Actions represent the callback mechanism used by - * coyote servlet containers to request operations on the coyote connectors. - * Some standard actions are defined in ActionCode, however custom - * actions are permitted. - * - * The param object can be used to pass and return informations related with the - * action. - * - * - * This interface is typically implemented by ProtocolHandlers, and the param - * is usually a Request or Response object. - * - * @author Remy Maucherat - */ -public interface ActionHook { - - - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - public void action(ActionCode actionCode, Object param); - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + + +/** + * Action hook. Actions represent the callback mechanism used by + * coyote servlet containers to request operations on the coyote connectors. + * Some standard actions are defined in ActionCode, however custom + * actions are permitted. + * + * The param object can be used to pass and return informations related with the + * action. + * + * + * This interface is typically implemented by ProtocolHandlers, and the param + * is usually a Request or Response object. + * + * @author Remy Maucherat + */ +public interface ActionHook { + + + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + public void action(ActionCode actionCode, Object param); + + +} diff --git a/java/org/apache/coyote/Adapter.java b/java/org/apache/coyote/Adapter.java index e5a78a341..228d77085 100644 --- a/java/org/apache/coyote/Adapter.java +++ b/java/org/apache/coyote/Adapter.java @@ -1,51 +1,51 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - - -/** - * Adapter. This represents the entry point in a coyote-based servlet container. - * - * - * @author Remy Maucherat - * @see ProtocolHandler - */ -public interface Adapter { - - - /** - * Call the service method, and notify all listeners - * - * @exception Exception if an error happens during handling of - * the request. Common errors are: - *
        • IOException if an input/output error occurs and we are - * processing an included servlet (otherwise it is swallowed and - * handled by the top level error handler mechanism) - *
        • ServletException if a servlet throws an exception and - * we are processing an included servlet (otherwise it is swallowed - * and handled by the top level error handler mechanism) - *
        - * Tomcat should be able to handle and log any other exception ( including - * runtime exceptions ) - */ - public void service(Request req, Response res) - throws Exception; - - public boolean event(Request req, Response res, boolean error) - throws Exception; - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + + +/** + * Adapter. This represents the entry point in a coyote-based servlet container. + * + * + * @author Remy Maucherat + * @see ProtocolHandler + */ +public interface Adapter { + + + /** + * Call the service method, and notify all listeners + * + * @exception Exception if an error happens during handling of + * the request. Common errors are: + *
        • IOException if an input/output error occurs and we are + * processing an included servlet (otherwise it is swallowed and + * handled by the top level error handler mechanism) + *
        • ServletException if a servlet throws an exception and + * we are processing an included servlet (otherwise it is swallowed + * and handled by the top level error handler mechanism) + *
        + * Tomcat should be able to handle and log any other exception ( including + * runtime exceptions ) + */ + public void service(Request req, Response res) + throws Exception; + + public boolean event(Request req, Response res, boolean error) + throws Exception; + +} diff --git a/java/org/apache/coyote/Constants.java b/java/org/apache/coyote/Constants.java index dd387f48d..9a7715e03 100644 --- a/java/org/apache/coyote/Constants.java +++ b/java/org/apache/coyote/Constants.java @@ -1,55 +1,55 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.util.Locale; - -/** - * Constants. - * - * @author Remy Maucherat - */ -public final class Constants { - - - // -------------------------------------------------------------- Constants - - - public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; - - - public static final String LOCALE_DEFAULT = "en"; - - - public static final Locale DEFAULT_LOCALE = new Locale(LOCALE_DEFAULT, ""); - - - public static final int MAX_NOTES = 32; - - - // Request states - public static final int STAGE_NEW = 0; - public static final int STAGE_PARSE = 1; - public static final int STAGE_PREPARE = 2; - public static final int STAGE_SERVICE = 3; - public static final int STAGE_ENDINPUT = 4; - public static final int STAGE_ENDOUTPUT = 5; - public static final int STAGE_KEEPALIVE = 6; - public static final int STAGE_ENDED = 7; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.util.Locale; + +/** + * Constants. + * + * @author Remy Maucherat + */ +public final class Constants { + + + // -------------------------------------------------------------- Constants + + + public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; + + + public static final String LOCALE_DEFAULT = "en"; + + + public static final Locale DEFAULT_LOCALE = new Locale(LOCALE_DEFAULT, ""); + + + public static final int MAX_NOTES = 32; + + + // Request states + public static final int STAGE_NEW = 0; + public static final int STAGE_PARSE = 1; + public static final int STAGE_PREPARE = 2; + public static final int STAGE_SERVICE = 3; + public static final int STAGE_ENDINPUT = 4; + public static final int STAGE_ENDOUTPUT = 5; + public static final int STAGE_KEEPALIVE = 6; + public static final int STAGE_ENDED = 7; + + +} diff --git a/java/org/apache/coyote/InputBuffer.java b/java/org/apache/coyote/InputBuffer.java index a541beed0..acc590c87 100644 --- a/java/org/apache/coyote/InputBuffer.java +++ b/java/org/apache/coyote/InputBuffer.java @@ -1,45 +1,45 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - - -/** - * Input buffer. - * - * This class is used only in the protocol implementation. All reading from tomcat ( or adapter ) should be done - * using Request.doRead(). - * - * - * @author Remy Maucherat - */ -public interface InputBuffer { - - - /** Return from the input stream. - IMPORTANT: the current model assumes that the protocol will 'own' the - buffer and return a pointer to it in ByteChunk ( i.e. the param will - have chunk.getBytes()==null before call, and the result after the call ). - */ - public int doRead(ByteChunk chunk, Request request) - throws IOException; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + + +/** + * Input buffer. + * + * This class is used only in the protocol implementation. All reading from tomcat ( or adapter ) should be done + * using Request.doRead(). + * + * + * @author Remy Maucherat + */ +public interface InputBuffer { + + + /** Return from the input stream. + IMPORTANT: the current model assumes that the protocol will 'own' the + buffer and return a pointer to it in ByteChunk ( i.e. the param will + have chunk.getBytes()==null before call, and the result after the call ). + */ + public int doRead(ByteChunk chunk, Request request) + throws IOException; + + +} diff --git a/java/org/apache/coyote/OutputBuffer.java b/java/org/apache/coyote/OutputBuffer.java index 089b40177..1e2fa66b8 100644 --- a/java/org/apache/coyote/OutputBuffer.java +++ b/java/org/apache/coyote/OutputBuffer.java @@ -1,46 +1,46 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - - -/** - * Output buffer. - * - * This class is used internally by the protocol implementation. All writes from higher level code should happen - * via Resonse.doWrite(). - * - * @author Remy Maucherat - */ -public interface OutputBuffer { - - - /** Write the response. The caller ( tomcat ) owns the chunks. - * - * @param chunk data to write - * @param response used to allow buffers that can be shared by multiple responses. - * @return - * @throws IOException - */ - public int doWrite(ByteChunk chunk, Response response) - throws IOException; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + + +/** + * Output buffer. + * + * This class is used internally by the protocol implementation. All writes from higher level code should happen + * via Resonse.doWrite(). + * + * @author Remy Maucherat + */ +public interface OutputBuffer { + + + /** Write the response. The caller ( tomcat ) owns the chunks. + * + * @param chunk data to write + * @param response used to allow buffers that can be shared by multiple responses. + * @return + * @throws IOException + */ + public int doWrite(ByteChunk chunk, Response response) + throws IOException; + + +} diff --git a/java/org/apache/coyote/Processor.java b/java/org/apache/coyote/Processor.java index bda588649..19d3051c9 100644 --- a/java/org/apache/coyote/Processor.java +++ b/java/org/apache/coyote/Processor.java @@ -1,44 +1,44 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.io.InputStream; -import java.io.IOException; -import java.io.OutputStream; - - -/** - * Processor. - * - * Not really used, should be deprecated. - * - * @author Remy Maucherat - */ -public interface Processor { - - - public void setAdapter(Adapter adapter); - - - public Adapter getAdapter(); - - - public void process(InputStream input, OutputStream output) - throws IOException; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; + + +/** + * Processor. + * + * Not really used, should be deprecated. + * + * @author Remy Maucherat + */ +public interface Processor { + + + public void setAdapter(Adapter adapter); + + + public Adapter getAdapter(); + + + public void process(InputStream input, OutputStream output) + throws IOException; + + +} diff --git a/java/org/apache/coyote/ProtocolHandler.java b/java/org/apache/coyote/ProtocolHandler.java index a27dbce2e..121cd5372 100644 --- a/java/org/apache/coyote/ProtocolHandler.java +++ b/java/org/apache/coyote/ProtocolHandler.java @@ -1,84 +1,84 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.util.Iterator; - - -/** - * Abstract the protocol implementation, including threading, etc. - * Processor is single threaded and specific to stream-based protocols, - * will not fit Jk protocols like JNI. - * - * This is the main interface to be implemented by a coyoute connector. - * Adapter is the main interface to be impleneted by a coyote servlet container. - * - * @author Remy Maucherat - * @author Costin Manolache - * @see Adapter - */ -public interface ProtocolHandler { - - - /** - * Pass config info. - */ - public void setAttribute(String name, Object value); - - - public Object getAttribute(String name); - public Iterator getAttributeNames(); - - /** - * The adapter, used to call the connector. - */ - public void setAdapter(Adapter adapter); - - - public Adapter getAdapter(); - - - /** - * Init the protocol. - */ - public void init() - throws Exception; - - - /** - * Start the protocol. - */ - public void start() - throws Exception; - - /** - * Pause the protocol (optional). - */ - public void pause() - throws Exception; - - /** - * Resume the protocol (optional). - */ - public void resume() - throws Exception; - - public void destroy() - throws Exception; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.util.Iterator; + + +/** + * Abstract the protocol implementation, including threading, etc. + * Processor is single threaded and specific to stream-based protocols, + * will not fit Jk protocols like JNI. + * + * This is the main interface to be implemented by a coyoute connector. + * Adapter is the main interface to be impleneted by a coyote servlet container. + * + * @author Remy Maucherat + * @author Costin Manolache + * @see Adapter + */ +public interface ProtocolHandler { + + + /** + * Pass config info. + */ + public void setAttribute(String name, Object value); + + + public Object getAttribute(String name); + public Iterator getAttributeNames(); + + /** + * The adapter, used to call the connector. + */ + public void setAdapter(Adapter adapter); + + + public Adapter getAdapter(); + + + /** + * Init the protocol. + */ + public void init() + throws Exception; + + + /** + * Start the protocol. + */ + public void start() + throws Exception; + + /** + * Pause the protocol (optional). + */ + public void pause() + throws Exception; + + /** + * Resume the protocol (optional). + */ + public void resume() + throws Exception; + + public void destroy() + throws Exception; + + +} diff --git a/java/org/apache/coyote/Request.java b/java/org/apache/coyote/Request.java index 5265bee80..f4f3c4ca7 100644 --- a/java/org/apache/coyote/Request.java +++ b/java/org/apache/coyote/Request.java @@ -1,521 +1,521 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.io.IOException; -import java.util.HashMap; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.UDecoder; - -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.http.Parameters; -import org.apache.tomcat.util.http.ContentType; -import org.apache.tomcat.util.http.Cookies; - -/** - * This is a low-level, efficient representation of a server request. Most - * fields are GC-free, expensive operations are delayed until the user code - * needs the information. - * - * Processing is delegated to modules, using a hook mechanism. - * - * This class is not intended for user code - it is used internally by tomcat - * for processing the request in the most efficient way. Users ( servlets ) can - * access the information using a facade, which provides the high-level view - * of the request. - * - * For lazy evaluation, the request uses the getInfo() hook. The following ids - * are defined: - *
          - *
        • req.encoding - returns the request encoding - *
        • req.attribute - returns a module-specific attribute ( like SSL keys, etc ). - *
        - * - * Tomcat defines a number of attributes: - *
          - *
        • "org.apache.tomcat.request" - allows access to the low-level - * request object in trusted applications - *
        - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author Harish Prabandham - * @author Alex Cruikshank [alex@epitonic.com] - * @author Hans Bergsten [hans@gefionsoftware.com] - * @author Costin Manolache - * @author Remy Maucherat - */ -public final class Request { - - - // ----------------------------------------------------------- Constructors - - - public Request() { - - parameters.setQuery(queryMB); - parameters.setURLDecoder(urlDecoder); - parameters.setHeaders(headers); - - } - - - // ----------------------------------------------------- Instance Variables - - - private int serverPort = -1; - private MessageBytes serverNameMB = MessageBytes.newInstance(); - - private int remotePort; - private int localPort; - - private MessageBytes schemeMB = MessageBytes.newInstance(); - - private MessageBytes methodMB = MessageBytes.newInstance(); - private MessageBytes unparsedURIMB = MessageBytes.newInstance(); - private MessageBytes uriMB = MessageBytes.newInstance(); - private MessageBytes decodedUriMB = MessageBytes.newInstance(); - private MessageBytes queryMB = MessageBytes.newInstance(); - private MessageBytes protoMB = MessageBytes.newInstance(); - - // remote address/host - private MessageBytes remoteAddrMB = MessageBytes.newInstance(); - private MessageBytes localNameMB = MessageBytes.newInstance(); - private MessageBytes remoteHostMB = MessageBytes.newInstance(); - private MessageBytes localAddrMB = MessageBytes.newInstance(); - - private MimeHeaders headers = new MimeHeaders(); - - private MessageBytes instanceId = MessageBytes.newInstance(); - - /** - * Notes. - */ - private Object notes[] = new Object[Constants.MAX_NOTES]; - - - /** - * Associated input buffer. - */ - private InputBuffer inputBuffer = null; - - - /** - * URL decoder. - */ - private UDecoder urlDecoder = new UDecoder(); - - - /** - * HTTP specific fields. (remove them ?) - */ - private long contentLength = -1; - private MessageBytes contentTypeMB = null; - private String charEncoding = null; - private Cookies cookies = new Cookies(headers); - private Parameters parameters = new Parameters(); - - private MessageBytes remoteUser=MessageBytes.newInstance(); - private MessageBytes authType=MessageBytes.newInstance(); - private HashMap attributes=new HashMap(); - - private Response response; - private ActionHook hook; - - private int bytesRead=0; - // Time of the request - usefull to avoid repeated calls to System.currentTime - private long startTime = 0L; - - private RequestInfo reqProcessorMX=new RequestInfo(this); - // ------------------------------------------------------------- Properties - - - /** - * Get the instance id (or JVM route). Curently Ajp is sending it with each - * request. In future this should be fixed, and sent only once ( or - * 'negociated' at config time so both tomcat and apache share the same name. - * - * @return the instance id - */ - public MessageBytes instanceId() { - return instanceId; - } - - - public MimeHeaders getMimeHeaders() { - return headers; - } - - - public UDecoder getURLDecoder() { - return urlDecoder; - } - - // -------------------- Request data -------------------- - - - public MessageBytes scheme() { - return schemeMB; - } - - public MessageBytes method() { - return methodMB; - } - - public MessageBytes unparsedURI() { - return unparsedURIMB; - } - - public MessageBytes requestURI() { - return uriMB; - } - - public MessageBytes decodedURI() { - return decodedUriMB; - } - - public MessageBytes query() { - return queryMB; - } - - public MessageBytes queryString() { - return queryMB; - } - - public MessageBytes protocol() { - return protoMB; - } - - /** - * Return the buffer holding the server name, if - * any. Use isNull() to check if there is no value - * set. - * This is the "virtual host", derived from the - * Host: header. - */ - public MessageBytes serverName() { - return serverNameMB; - } - - public int getServerPort() { - return serverPort; - } - - public void setServerPort(int serverPort ) { - this.serverPort=serverPort; - } - - public MessageBytes remoteAddr() { - return remoteAddrMB; - } - - public MessageBytes remoteHost() { - return remoteHostMB; - } - - public MessageBytes localName() { - return localNameMB; - } - - public MessageBytes localAddr() { - return localAddrMB; - } - - public int getRemotePort(){ - return remotePort; - } - - public void setRemotePort(int port){ - this.remotePort = port; - } - - public int getLocalPort(){ - return localPort; - } - - public void setLocalPort(int port){ - this.localPort = port; - } - - // -------------------- encoding/type -------------------- - - - /** - * Get the character encoding used for this request. - */ - public String getCharacterEncoding() { - - if (charEncoding != null) - return charEncoding; - - charEncoding = ContentType.getCharsetFromContentType(getContentType()); - return charEncoding; - - } - - - public void setCharacterEncoding(String enc) { - this.charEncoding = enc; - } - - - public void setContentLength(int len) { - this.contentLength = len; - } - - - public int getContentLength() { - long length = getContentLengthLong(); - - if (length < Integer.MAX_VALUE) { - return (int) length; - } - return -1; - } - - public long getContentLengthLong() { - if( contentLength > -1 ) return contentLength; - - MessageBytes clB = headers.getValue("content-length"); - contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong(); - - return contentLength; - } - - public String getContentType() { - contentType(); - if ((contentTypeMB == null) || contentTypeMB.isNull()) - return null; - return contentTypeMB.toString(); - } - - - public void setContentType(String type) { - contentTypeMB.setString(type); - } - - - public MessageBytes contentType() { - if (contentTypeMB == null) - contentTypeMB = headers.getValue("content-type"); - return contentTypeMB; - } - - - public void setContentType(MessageBytes mb) { - contentTypeMB=mb; - } - - - public String getHeader(String name) { - return headers.getHeader(name); - } - - // -------------------- Associated response -------------------- - - public Response getResponse() { - return response; - } - - public void setResponse( Response response ) { - this.response=response; - response.setRequest( this ); - } - - public void action(ActionCode actionCode, Object param) { - if( hook==null && response!=null ) - hook=response.getHook(); - - if (hook != null) { - if( param==null ) - hook.action(actionCode, this); - else - hook.action(actionCode, param); - } - } - - - // -------------------- Cookies -------------------- - - - public Cookies getCookies() { - return cookies; - } - - - // -------------------- Parameters -------------------- - - - public Parameters getParameters() { - return parameters; - } - - - // -------------------- Other attributes -------------------- - // We can use notes for most - need to discuss what is of general interest - - public void setAttribute( String name, Object o ) { - attributes.put( name, o ); - } - - public HashMap getAttributes() { - return attributes; - } - - public Object getAttribute(String name ) { - return attributes.get(name); - } - - public MessageBytes getRemoteUser() { - return remoteUser; - } - - public MessageBytes getAuthType() { - return authType; - } - - // -------------------- Input Buffer -------------------- - - - public InputBuffer getInputBuffer() { - return inputBuffer; - } - - - public void setInputBuffer(InputBuffer inputBuffer) { - this.inputBuffer = inputBuffer; - } - - - /** - * Read data from the input buffer and put it into a byte chunk. - * - * The buffer is owned by the protocol implementation - it will be reused on the next read. - * The Adapter must either process the data in place or copy it to a separate buffer if it needs - * to hold it. In most cases this is done during byte->char conversions or via InputStream. Unlike - * InputStream, this interface allows the app to process data in place, without copy. - * - */ - public int doRead(ByteChunk chunk) - throws IOException { - int n = inputBuffer.doRead(chunk, this); - if (n > 0) { - bytesRead+=n; - } - return n; - } - - - // -------------------- debug -------------------- - - public String toString() { - return "R( " + requestURI().toString() + ")"; - } - - public long getStartTime() { - return startTime; - } - - public void setStartTime(long startTime) { - this.startTime = startTime; - } - - // -------------------- Per-Request "notes" -------------------- - - - /** - * Used to store private data. Thread data could be used instead - but - * if you have the req, getting/setting a note is just a array access, may - * be faster than ThreadLocal for very frequent operations. - * - * Example use: - * Jk: - * HandlerRequest.HOSTBUFFER = 10 CharChunk, buffer for Host decoding - * WorkerEnv: SSL_CERT_NOTE=16 - MessageBytes containing the cert - * - * Catalina CoyoteAdapter: - * ADAPTER_NOTES = 1 - stores the HttpServletRequest object ( req/res) - * - * To avoid conflicts, note in the range 0 - 8 are reserved for the - * servlet container ( catalina connector, etc ), and values in 9 - 16 - * for connector use. - * - * 17-31 range is not allocated or used. - */ - public final void setNote(int pos, Object value) { - notes[pos] = value; - } - - - public final Object getNote(int pos) { - return notes[pos]; - } - - - // -------------------- Recycling -------------------- - - - public void recycle() { - bytesRead=0; - - contentLength = -1; - contentTypeMB = null; - charEncoding = null; - headers.recycle(); - serverNameMB.recycle(); - serverPort=-1; - localPort = -1; - remotePort = -1; - - cookies.recycle(); - parameters.recycle(); - - unparsedURIMB.recycle(); - uriMB.recycle(); - decodedUriMB.recycle(); - queryMB.recycle(); - methodMB.recycle(); - protoMB.recycle(); - - schemeMB.recycle(); - - instanceId.recycle(); - remoteUser.recycle(); - authType.recycle(); - attributes.clear(); - } - - // -------------------- Info -------------------- - public void updateCounters() { - reqProcessorMX.updateCounters(); - } - - public RequestInfo getRequestProcessor() { - return reqProcessorMX; - } - - public int getBytesRead() { - return bytesRead; - } - - public void setBytesRead(int bytesRead) { - this.bytesRead = bytesRead; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.io.IOException; +import java.util.HashMap; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.buf.UDecoder; + +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.http.Parameters; +import org.apache.tomcat.util.http.ContentType; +import org.apache.tomcat.util.http.Cookies; + +/** + * This is a low-level, efficient representation of a server request. Most + * fields are GC-free, expensive operations are delayed until the user code + * needs the information. + * + * Processing is delegated to modules, using a hook mechanism. + * + * This class is not intended for user code - it is used internally by tomcat + * for processing the request in the most efficient way. Users ( servlets ) can + * access the information using a facade, which provides the high-level view + * of the request. + * + * For lazy evaluation, the request uses the getInfo() hook. The following ids + * are defined: + *
          + *
        • req.encoding - returns the request encoding + *
        • req.attribute - returns a module-specific attribute ( like SSL keys, etc ). + *
        + * + * Tomcat defines a number of attributes: + *
          + *
        • "org.apache.tomcat.request" - allows access to the low-level + * request object in trusted applications + *
        + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author Harish Prabandham + * @author Alex Cruikshank [alex@epitonic.com] + * @author Hans Bergsten [hans@gefionsoftware.com] + * @author Costin Manolache + * @author Remy Maucherat + */ +public final class Request { + + + // ----------------------------------------------------------- Constructors + + + public Request() { + + parameters.setQuery(queryMB); + parameters.setURLDecoder(urlDecoder); + parameters.setHeaders(headers); + + } + + + // ----------------------------------------------------- Instance Variables + + + private int serverPort = -1; + private MessageBytes serverNameMB = MessageBytes.newInstance(); + + private int remotePort; + private int localPort; + + private MessageBytes schemeMB = MessageBytes.newInstance(); + + private MessageBytes methodMB = MessageBytes.newInstance(); + private MessageBytes unparsedURIMB = MessageBytes.newInstance(); + private MessageBytes uriMB = MessageBytes.newInstance(); + private MessageBytes decodedUriMB = MessageBytes.newInstance(); + private MessageBytes queryMB = MessageBytes.newInstance(); + private MessageBytes protoMB = MessageBytes.newInstance(); + + // remote address/host + private MessageBytes remoteAddrMB = MessageBytes.newInstance(); + private MessageBytes localNameMB = MessageBytes.newInstance(); + private MessageBytes remoteHostMB = MessageBytes.newInstance(); + private MessageBytes localAddrMB = MessageBytes.newInstance(); + + private MimeHeaders headers = new MimeHeaders(); + + private MessageBytes instanceId = MessageBytes.newInstance(); + + /** + * Notes. + */ + private Object notes[] = new Object[Constants.MAX_NOTES]; + + + /** + * Associated input buffer. + */ + private InputBuffer inputBuffer = null; + + + /** + * URL decoder. + */ + private UDecoder urlDecoder = new UDecoder(); + + + /** + * HTTP specific fields. (remove them ?) + */ + private long contentLength = -1; + private MessageBytes contentTypeMB = null; + private String charEncoding = null; + private Cookies cookies = new Cookies(headers); + private Parameters parameters = new Parameters(); + + private MessageBytes remoteUser=MessageBytes.newInstance(); + private MessageBytes authType=MessageBytes.newInstance(); + private HashMap attributes=new HashMap(); + + private Response response; + private ActionHook hook; + + private int bytesRead=0; + // Time of the request - usefull to avoid repeated calls to System.currentTime + private long startTime = 0L; + + private RequestInfo reqProcessorMX=new RequestInfo(this); + // ------------------------------------------------------------- Properties + + + /** + * Get the instance id (or JVM route). Curently Ajp is sending it with each + * request. In future this should be fixed, and sent only once ( or + * 'negociated' at config time so both tomcat and apache share the same name. + * + * @return the instance id + */ + public MessageBytes instanceId() { + return instanceId; + } + + + public MimeHeaders getMimeHeaders() { + return headers; + } + + + public UDecoder getURLDecoder() { + return urlDecoder; + } + + // -------------------- Request data -------------------- + + + public MessageBytes scheme() { + return schemeMB; + } + + public MessageBytes method() { + return methodMB; + } + + public MessageBytes unparsedURI() { + return unparsedURIMB; + } + + public MessageBytes requestURI() { + return uriMB; + } + + public MessageBytes decodedURI() { + return decodedUriMB; + } + + public MessageBytes query() { + return queryMB; + } + + public MessageBytes queryString() { + return queryMB; + } + + public MessageBytes protocol() { + return protoMB; + } + + /** + * Return the buffer holding the server name, if + * any. Use isNull() to check if there is no value + * set. + * This is the "virtual host", derived from the + * Host: header. + */ + public MessageBytes serverName() { + return serverNameMB; + } + + public int getServerPort() { + return serverPort; + } + + public void setServerPort(int serverPort ) { + this.serverPort=serverPort; + } + + public MessageBytes remoteAddr() { + return remoteAddrMB; + } + + public MessageBytes remoteHost() { + return remoteHostMB; + } + + public MessageBytes localName() { + return localNameMB; + } + + public MessageBytes localAddr() { + return localAddrMB; + } + + public int getRemotePort(){ + return remotePort; + } + + public void setRemotePort(int port){ + this.remotePort = port; + } + + public int getLocalPort(){ + return localPort; + } + + public void setLocalPort(int port){ + this.localPort = port; + } + + // -------------------- encoding/type -------------------- + + + /** + * Get the character encoding used for this request. + */ + public String getCharacterEncoding() { + + if (charEncoding != null) + return charEncoding; + + charEncoding = ContentType.getCharsetFromContentType(getContentType()); + return charEncoding; + + } + + + public void setCharacterEncoding(String enc) { + this.charEncoding = enc; + } + + + public void setContentLength(int len) { + this.contentLength = len; + } + + + public int getContentLength() { + long length = getContentLengthLong(); + + if (length < Integer.MAX_VALUE) { + return (int) length; + } + return -1; + } + + public long getContentLengthLong() { + if( contentLength > -1 ) return contentLength; + + MessageBytes clB = headers.getValue("content-length"); + contentLength = (clB == null || clB.isNull()) ? -1 : clB.getLong(); + + return contentLength; + } + + public String getContentType() { + contentType(); + if ((contentTypeMB == null) || contentTypeMB.isNull()) + return null; + return contentTypeMB.toString(); + } + + + public void setContentType(String type) { + contentTypeMB.setString(type); + } + + + public MessageBytes contentType() { + if (contentTypeMB == null) + contentTypeMB = headers.getValue("content-type"); + return contentTypeMB; + } + + + public void setContentType(MessageBytes mb) { + contentTypeMB=mb; + } + + + public String getHeader(String name) { + return headers.getHeader(name); + } + + // -------------------- Associated response -------------------- + + public Response getResponse() { + return response; + } + + public void setResponse( Response response ) { + this.response=response; + response.setRequest( this ); + } + + public void action(ActionCode actionCode, Object param) { + if( hook==null && response!=null ) + hook=response.getHook(); + + if (hook != null) { + if( param==null ) + hook.action(actionCode, this); + else + hook.action(actionCode, param); + } + } + + + // -------------------- Cookies -------------------- + + + public Cookies getCookies() { + return cookies; + } + + + // -------------------- Parameters -------------------- + + + public Parameters getParameters() { + return parameters; + } + + + // -------------------- Other attributes -------------------- + // We can use notes for most - need to discuss what is of general interest + + public void setAttribute( String name, Object o ) { + attributes.put( name, o ); + } + + public HashMap getAttributes() { + return attributes; + } + + public Object getAttribute(String name ) { + return attributes.get(name); + } + + public MessageBytes getRemoteUser() { + return remoteUser; + } + + public MessageBytes getAuthType() { + return authType; + } + + // -------------------- Input Buffer -------------------- + + + public InputBuffer getInputBuffer() { + return inputBuffer; + } + + + public void setInputBuffer(InputBuffer inputBuffer) { + this.inputBuffer = inputBuffer; + } + + + /** + * Read data from the input buffer and put it into a byte chunk. + * + * The buffer is owned by the protocol implementation - it will be reused on the next read. + * The Adapter must either process the data in place or copy it to a separate buffer if it needs + * to hold it. In most cases this is done during byte->char conversions or via InputStream. Unlike + * InputStream, this interface allows the app to process data in place, without copy. + * + */ + public int doRead(ByteChunk chunk) + throws IOException { + int n = inputBuffer.doRead(chunk, this); + if (n > 0) { + bytesRead+=n; + } + return n; + } + + + // -------------------- debug -------------------- + + public String toString() { + return "R( " + requestURI().toString() + ")"; + } + + public long getStartTime() { + return startTime; + } + + public void setStartTime(long startTime) { + this.startTime = startTime; + } + + // -------------------- Per-Request "notes" -------------------- + + + /** + * Used to store private data. Thread data could be used instead - but + * if you have the req, getting/setting a note is just a array access, may + * be faster than ThreadLocal for very frequent operations. + * + * Example use: + * Jk: + * HandlerRequest.HOSTBUFFER = 10 CharChunk, buffer for Host decoding + * WorkerEnv: SSL_CERT_NOTE=16 - MessageBytes containing the cert + * + * Catalina CoyoteAdapter: + * ADAPTER_NOTES = 1 - stores the HttpServletRequest object ( req/res) + * + * To avoid conflicts, note in the range 0 - 8 are reserved for the + * servlet container ( catalina connector, etc ), and values in 9 - 16 + * for connector use. + * + * 17-31 range is not allocated or used. + */ + public final void setNote(int pos, Object value) { + notes[pos] = value; + } + + + public final Object getNote(int pos) { + return notes[pos]; + } + + + // -------------------- Recycling -------------------- + + + public void recycle() { + bytesRead=0; + + contentLength = -1; + contentTypeMB = null; + charEncoding = null; + headers.recycle(); + serverNameMB.recycle(); + serverPort=-1; + localPort = -1; + remotePort = -1; + + cookies.recycle(); + parameters.recycle(); + + unparsedURIMB.recycle(); + uriMB.recycle(); + decodedUriMB.recycle(); + queryMB.recycle(); + methodMB.recycle(); + protoMB.recycle(); + + schemeMB.recycle(); + + instanceId.recycle(); + remoteUser.recycle(); + authType.recycle(); + attributes.clear(); + } + + // -------------------- Info -------------------- + public void updateCounters() { + reqProcessorMX.updateCounters(); + } + + public RequestInfo getRequestProcessor() { + return reqProcessorMX; + } + + public int getBytesRead() { + return bytesRead; + } + + public void setBytesRead(int bytesRead) { + this.bytesRead = bytesRead; + } +} diff --git a/java/org/apache/coyote/RequestGroupInfo.java b/java/org/apache/coyote/RequestGroupInfo.java index ccbacb095..b8810b6da 100644 --- a/java/org/apache/coyote/RequestGroupInfo.java +++ b/java/org/apache/coyote/RequestGroupInfo.java @@ -1,163 +1,163 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.util.ArrayList; - -/** This can be moved to top level ( eventually with a better name ). - * It is currently used only as a JMX artifact, to agregate the data - * collected from each RequestProcessor thread. - */ -public class RequestGroupInfo { - ArrayList processors=new ArrayList(); - private long deadMaxTime = 0; - private long deadProcessingTime = 0; - private int deadRequestCount = 0; - private int deadErrorCount = 0; - private long deadBytesReceived = 0; - private long deadBytesSent = 0; - - public synchronized void addRequestProcessor( RequestInfo rp ) { - processors.add( rp ); - } - - public synchronized void removeRequestProcessor( RequestInfo rp ) { - if( rp != null ) { - if( deadMaxTime < rp.getMaxTime() ) - deadMaxTime = rp.getMaxTime(); - deadProcessingTime += rp.getProcessingTime(); - deadRequestCount += rp.getRequestCount(); - deadErrorCount += rp.getErrorCount(); - deadBytesReceived += rp.getBytesReceived(); - deadBytesSent += rp.getBytesSent(); - - processors.remove( rp ); - } - } - - public synchronized long getMaxTime() { - long maxTime=deadMaxTime; - for( int i=0; i= 400 - private int errorCount; - - - /** Called by the processor before recycling the request. It'll collect - * statistic information. - */ - void updateCounters() { - bytesReceived+=req.getBytesRead(); - bytesSent+=req.getResponse().getBytesWritten(); - - requestCount++; - if( req.getResponse().getStatus() >=400 ) - errorCount++; - long t0=req.getStartTime(); - long t1=System.currentTimeMillis(); - long time=t1-t0; - processingTime+=time; - if( maxTime < time ) { - maxTime=time; - maxRequestUri=req.requestURI().toString(); - } - } - - public int getStage() { - return stage; - } - - public void setStage(int stage) { - this.stage = stage; - } - - public long getBytesSent() { - return bytesSent; - } - - public void setBytesSent(long bytesSent) { - this.bytesSent = bytesSent; - } - - public long getBytesReceived() { - return bytesReceived; - } - - public void setBytesReceived(long bytesReceived) { - this.bytesReceived = bytesReceived; - } - - public long getProcessingTime() { - return processingTime; - } - - public void setProcessingTime(long processingTime) { - this.processingTime = processingTime; - } - - public long getMaxTime() { - return maxTime; - } - - public void setMaxTime(long maxTime) { - this.maxTime = maxTime; - } - - public String getMaxRequestUri() { - return maxRequestUri; - } - - public void setMaxRequestUri(String maxRequestUri) { - this.maxRequestUri = maxRequestUri; - } - - public int getRequestCount() { - return requestCount; - } - - public void setRequestCount(int requestCount) { - this.requestCount = requestCount; - } - - public int getErrorCount() { - return errorCount; - } - - public void setErrorCount(int errorCount) { - this.errorCount = errorCount; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + + +/** + * Structure holding the Request and Response objects. It also holds statistical + * informations about request processing and provide management informations + * about the requests beeing processed. + * + * Each thread uses a Request/Response pair that is recycled on each request. + * This object provides a place to collect global low-level statistics - without + * having to deal with synchronization ( since each thread will have it's own + * RequestProcessorMX ). + * + * TODO: Request notifications will be registered here. + * + * @author Costin Manolache + */ +public class RequestInfo { + RequestGroupInfo global=null; + + // ----------------------------------------------------------- Constructors + + public RequestInfo( Request req) { + this.req=req; + } + + public RequestGroupInfo getGlobalProcessor() { + return global; + } + + public void setGlobalProcessor(RequestGroupInfo global) { + if( global != null) { + this.global=global; + global.addRequestProcessor( this ); + } else { + if (this.global != null) { + this.global.removeRequestProcessor( this ); + this.global = null; + } + } + } + + + // ----------------------------------------------------- Instance Variables + Request req; + Response res; + int stage = Constants.STAGE_NEW; + + // -------------------- Information about the current request ----------- + // This is usefull for long-running requests only + + public String getMethod() { + return req.method().toString(); + } + + public String getCurrentUri() { + return req.requestURI().toString(); + } + + public String getCurrentQueryString() { + return req.queryString().toString(); + } + + public String getProtocol() { + return req.protocol().toString(); + } + + public String getVirtualHost() { + return req.serverName().toString(); + } + + public int getServerPort() { + return req.getServerPort(); + } + + public String getRemoteAddr() { + req.action(ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE, null); + return req.remoteAddr().toString(); + } + + public int getContentLength() { + return req.getContentLength(); + } + + public long getRequestBytesReceived() { + return req.getBytesRead(); + } + + public long getRequestBytesSent() { + return req.getResponse().getBytesWritten(); + } + + public long getRequestProcessingTime() { + return (System.currentTimeMillis() - req.getStartTime()); + } + + // -------------------- Statistical data -------------------- + // Collected at the end of each request. + private long bytesSent; + private long bytesReceived; + + // Total time = divide by requestCount to get average. + private long processingTime; + // The longest response time for a request + private long maxTime; + // URI of the request that took maxTime + private String maxRequestUri; + + private int requestCount; + // number of response codes >= 400 + private int errorCount; + + + /** Called by the processor before recycling the request. It'll collect + * statistic information. + */ + void updateCounters() { + bytesReceived+=req.getBytesRead(); + bytesSent+=req.getResponse().getBytesWritten(); + + requestCount++; + if( req.getResponse().getStatus() >=400 ) + errorCount++; + long t0=req.getStartTime(); + long t1=System.currentTimeMillis(); + long time=t1-t0; + processingTime+=time; + if( maxTime < time ) { + maxTime=time; + maxRequestUri=req.requestURI().toString(); + } + } + + public int getStage() { + return stage; + } + + public void setStage(int stage) { + this.stage = stage; + } + + public long getBytesSent() { + return bytesSent; + } + + public void setBytesSent(long bytesSent) { + this.bytesSent = bytesSent; + } + + public long getBytesReceived() { + return bytesReceived; + } + + public void setBytesReceived(long bytesReceived) { + this.bytesReceived = bytesReceived; + } + + public long getProcessingTime() { + return processingTime; + } + + public void setProcessingTime(long processingTime) { + this.processingTime = processingTime; + } + + public long getMaxTime() { + return maxTime; + } + + public void setMaxTime(long maxTime) { + this.maxTime = maxTime; + } + + public String getMaxRequestUri() { + return maxRequestUri; + } + + public void setMaxRequestUri(String maxRequestUri) { + this.maxRequestUri = maxRequestUri; + } + + public int getRequestCount() { + return requestCount; + } + + public void setRequestCount(int requestCount) { + this.requestCount = requestCount; + } + + public int getErrorCount() { + return errorCount; + } + + public void setErrorCount(int errorCount) { + this.errorCount = errorCount; + } + + +} diff --git a/java/org/apache/coyote/Response.java b/java/org/apache/coyote/Response.java index ed7b19402..267720a1c 100644 --- a/java/org/apache/coyote/Response.java +++ b/java/org/apache/coyote/Response.java @@ -1,591 +1,591 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote; - -import java.io.IOException; -import java.util.Locale; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.http.MimeHeaders; - -/** - * Response object. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Harish Prabandham - * @author Hans Bergsten - * @author Remy Maucherat - */ -public final class Response { - - - // ----------------------------------------------------------- Constructors - - - public Response() { - } - - - // ----------------------------------------------------- Class Variables - - /** - * Default locale as mandated by the spec. - */ - private static Locale DEFAULT_LOCALE = Locale.getDefault(); - - - // ----------------------------------------------------- Instance Variables - - /** - * Status code. - */ - protected int status = 200; - - - /** - * Status message. - */ - protected String message = null; - - - /** - * Response headers. - */ - protected MimeHeaders headers = new MimeHeaders(); - - - /** - * Associated output buffer. - */ - protected OutputBuffer outputBuffer; - - - /** - * Notes. - */ - protected Object notes[] = new Object[Constants.MAX_NOTES]; - - - /** - * Committed flag. - */ - protected boolean commited = false; - - - /** - * Action hook. - */ - public ActionHook hook; - - - /** - * HTTP specific fields. - */ - protected String contentType = null; - protected String contentLanguage = null; - protected String characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; - protected long contentLength = -1; - private Locale locale = DEFAULT_LOCALE; - - // General informations - private long bytesWritten=0; - - /** - * Holds request error exception. - */ - protected Exception errorException = null; - - /** - * Has the charset been explicitly set. - */ - protected boolean charsetSet = false; - - /** - * Request error URI. - */ - protected String errorURI = null; - - protected Request req; - - // ------------------------------------------------------------- Properties - - public Request getRequest() { - return req; - } - - public void setRequest( Request req ) { - this.req=req; - } - - public OutputBuffer getOutputBuffer() { - return outputBuffer; - } - - - public void setOutputBuffer(OutputBuffer outputBuffer) { - this.outputBuffer = outputBuffer; - } - - - public MimeHeaders getMimeHeaders() { - return headers; - } - - - public ActionHook getHook() { - return hook; - } - - - public void setHook(ActionHook hook) { - this.hook = hook; - } - - - // -------------------- Per-Response "notes" -------------------- - - - public final void setNote(int pos, Object value) { - notes[pos] = value; - } - - - public final Object getNote(int pos) { - return notes[pos]; - } - - - // -------------------- Actions -------------------- - - - public void action(ActionCode actionCode, Object param) { - if (hook != null) { - if( param==null ) - hook.action(actionCode, this); - else - hook.action(actionCode, param); - } - } - - - // -------------------- State -------------------- - - - public int getStatus() { - return status; - } - - - /** - * Set the response status - */ - public void setStatus( int status ) { - this.status = status; - } - - - /** - * Get the status message. - */ - public String getMessage() { - return message; - } - - - /** - * Set the status message. - */ - public void setMessage(String message) { - this.message = message; - } - - - public boolean isCommitted() { - return commited; - } - - - public void setCommitted(boolean v) { - this.commited = v; - } - - - // -----------------Error State -------------------- - - - /** - * Set the error Exception that occurred during - * request processing. - */ - public void setErrorException(Exception ex) { - errorException = ex; - } - - - /** - * Get the Exception that occurred during request - * processing. - */ - public Exception getErrorException() { - return errorException; - } - - - public boolean isExceptionPresent() { - return ( errorException != null ); - } - - - /** - * Set request URI that caused an error during - * request processing. - */ - public void setErrorURI(String uri) { - errorURI = uri; - } - - - /** Get the request URI that caused the original error. - */ - public String getErrorURI() { - return errorURI; - } - - - // -------------------- Methods -------------------- - - - public void reset() - throws IllegalStateException { - - // Reset the headers only if this is the main request, - // not for included - contentType = null; - locale = DEFAULT_LOCALE; - contentLanguage = null; - characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; - contentLength = -1; - charsetSet = false; - - status = 200; - message = null; - headers.clear(); - - // Force the PrintWriter to flush its data to the output - // stream before resetting the output stream - // - // Reset the stream - if (commited) { - //String msg = sm.getString("servletOutputStreamImpl.reset.ise"); - throw new IllegalStateException(); - } - - action(ActionCode.ACTION_RESET, this); - } - - - public void finish() throws IOException { - action(ActionCode.ACTION_CLOSE, this); - } - - - public void acknowledge() throws IOException { - action(ActionCode.ACTION_ACK, this); - } - - - // -------------------- Headers -------------------- - /** - * Warning: This method always returns false for Content-Type - * and Content-Length. - */ - public boolean containsHeader(String name) { - return headers.getHeader(name) != null; - } - - - public void setHeader(String name, String value) { - char cc=name.charAt(0); - if( cc=='C' || cc=='c' ) { - if( checkSpecialHeader(name, value) ) - return; - } - headers.setValue(name).setString( value); - } - - - public void addHeader(String name, String value) { - char cc=name.charAt(0); - if( cc=='C' || cc=='c' ) { - if( checkSpecialHeader(name, value) ) - return; - } - headers.addValue(name).setString( value ); - } - - - /** - * Set internal fields for special header names. - * Called from set/addHeader. - * Return true if the header is special, no need to set the header. - */ - private boolean checkSpecialHeader( String name, String value) { - // XXX Eliminate redundant fields !!! - // ( both header and in special fields ) - if( name.equalsIgnoreCase( "Content-Type" ) ) { - setContentType( value ); - return true; - } - if( name.equalsIgnoreCase( "Content-Length" ) ) { - try { - long cL=Long.parseLong( value ); - setContentLength( cL ); - return true; - } catch( NumberFormatException ex ) { - // Do nothing - the spec doesn't have any "throws" - // and the user might know what he's doing - return false; - } - } - if( name.equalsIgnoreCase( "Content-Language" ) ) { - // XXX XXX Need to construct Locale or something else - } - return false; - } - - - /** Signal that we're done with the headers, and body will follow. - * Any implementation needs to notify ContextManager, to allow - * interceptors to fix headers. - */ - public void sendHeaders() throws IOException { - action(ActionCode.ACTION_COMMIT, this); - commited = true; - } - - - // -------------------- I18N -------------------- - - - public Locale getLocale() { - return locale; - } - - /** - * Called explicitely by user to set the Content-Language and - * the default encoding - */ - public void setLocale(Locale locale) { - - if (locale == null) { - return; // throw an exception? - } - - // Save the locale for use by getLocale() - this.locale = locale; - - // Set the contentLanguage for header output - contentLanguage = locale.getLanguage(); - if ((contentLanguage != null) && (contentLanguage.length() > 0)) { - String country = locale.getCountry(); - StringBuffer value = new StringBuffer(contentLanguage); - if ((country != null) && (country.length() > 0)) { - value.append('-'); - value.append(country); - } - contentLanguage = value.toString(); - } - - } - - /** - * Return the content language. - */ - public String getContentLanguage() { - return contentLanguage; - } - - /* - * Overrides the name of the character encoding used in the body - * of the response. This method must be called prior to writing output - * using getWriter(). - * - * @param charset String containing the name of the chararacter encoding. - */ - public void setCharacterEncoding(String charset) { - - if (isCommitted()) - return; - if (charset == null) - return; - - characterEncoding = charset; - charsetSet=true; - } - - public String getCharacterEncoding() { - return characterEncoding; - } - - /** - * Sets the content type. - * - * This method must preserve any response charset that may already have - * been set via a call to response.setContentType(), response.setLocale(), - * or response.setCharacterEncoding(). - * - * @param type the content type - */ - public void setContentType(String type) { - - int semicolonIndex = -1; - - if (type == null) { - this.contentType = null; - return; - } - - /* - * Remove the charset param (if any) from the Content-Type, and use it - * to set the response encoding. - * The most recent response encoding setting will be appended to the - * response's Content-Type (as its charset param) by getContentType(); - */ - boolean hasCharset = false; - int len = type.length(); - int index = type.indexOf(';'); - while (index != -1) { - semicolonIndex = index; - index++; - while (index < len && Character.isSpace(type.charAt(index))) { - index++; - } - if (index+8 < len - && type.charAt(index) == 'c' - && type.charAt(index+1) == 'h' - && type.charAt(index+2) == 'a' - && type.charAt(index+3) == 'r' - && type.charAt(index+4) == 's' - && type.charAt(index+5) == 'e' - && type.charAt(index+6) == 't' - && type.charAt(index+7) == '=') { - hasCharset = true; - break; - } - index = type.indexOf(';', index); - } - - if (!hasCharset) { - this.contentType = type; - return; - } - - this.contentType = type.substring(0, semicolonIndex); - String tail = type.substring(index+8); - int nextParam = tail.indexOf(';'); - String charsetValue = null; - if (nextParam != -1) { - this.contentType += tail.substring(nextParam); - charsetValue = tail.substring(0, nextParam); - } else { - charsetValue = tail; - } - - // The charset value may be quoted, but must not contain any quotes. - if (charsetValue != null && charsetValue.length() > 0) { - charsetSet=true; - charsetValue = charsetValue.replace('"', ' '); - this.characterEncoding = charsetValue.trim(); - } - } - - public String getContentType() { - - String ret = contentType; - - if (ret != null - && characterEncoding != null - && charsetSet) { - ret = ret + ";charset=" + characterEncoding; - } - - return ret; - } - - public void setContentLength(int contentLength) { - this.contentLength = contentLength; - } - - public void setContentLength(long contentLength) { - this.contentLength = contentLength; - } - - public int getContentLength() { - long length = getContentLengthLong(); - - if (length < Integer.MAX_VALUE) { - return (int) length; - } - return -1; - } - - public long getContentLengthLong() { - return contentLength; - } - - - /** - * Write a chunk of bytes. - */ - public void doWrite(ByteChunk chunk/*byte buffer[], int pos, int count*/) - throws IOException - { - outputBuffer.doWrite(chunk, this); - bytesWritten+=chunk.getLength(); - } - - // -------------------- - - public void recycle() { - - contentType = null; - contentLanguage = null; - locale = DEFAULT_LOCALE; - characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; - charsetSet = false; - contentLength = -1; - status = 200; - message = null; - commited = false; - errorException = null; - errorURI = null; - headers.clear(); - - // update counters - bytesWritten=0; - } - - public long getBytesWritten() { - return bytesWritten; - } - - public void setBytesWritten(long bytesWritten) { - this.bytesWritten = bytesWritten; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote; + +import java.io.IOException; +import java.util.Locale; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.http.MimeHeaders; + +/** + * Response object. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Harish Prabandham + * @author Hans Bergsten + * @author Remy Maucherat + */ +public final class Response { + + + // ----------------------------------------------------------- Constructors + + + public Response() { + } + + + // ----------------------------------------------------- Class Variables + + /** + * Default locale as mandated by the spec. + */ + private static Locale DEFAULT_LOCALE = Locale.getDefault(); + + + // ----------------------------------------------------- Instance Variables + + /** + * Status code. + */ + protected int status = 200; + + + /** + * Status message. + */ + protected String message = null; + + + /** + * Response headers. + */ + protected MimeHeaders headers = new MimeHeaders(); + + + /** + * Associated output buffer. + */ + protected OutputBuffer outputBuffer; + + + /** + * Notes. + */ + protected Object notes[] = new Object[Constants.MAX_NOTES]; + + + /** + * Committed flag. + */ + protected boolean commited = false; + + + /** + * Action hook. + */ + public ActionHook hook; + + + /** + * HTTP specific fields. + */ + protected String contentType = null; + protected String contentLanguage = null; + protected String characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; + protected long contentLength = -1; + private Locale locale = DEFAULT_LOCALE; + + // General informations + private long bytesWritten=0; + + /** + * Holds request error exception. + */ + protected Exception errorException = null; + + /** + * Has the charset been explicitly set. + */ + protected boolean charsetSet = false; + + /** + * Request error URI. + */ + protected String errorURI = null; + + protected Request req; + + // ------------------------------------------------------------- Properties + + public Request getRequest() { + return req; + } + + public void setRequest( Request req ) { + this.req=req; + } + + public OutputBuffer getOutputBuffer() { + return outputBuffer; + } + + + public void setOutputBuffer(OutputBuffer outputBuffer) { + this.outputBuffer = outputBuffer; + } + + + public MimeHeaders getMimeHeaders() { + return headers; + } + + + public ActionHook getHook() { + return hook; + } + + + public void setHook(ActionHook hook) { + this.hook = hook; + } + + + // -------------------- Per-Response "notes" -------------------- + + + public final void setNote(int pos, Object value) { + notes[pos] = value; + } + + + public final Object getNote(int pos) { + return notes[pos]; + } + + + // -------------------- Actions -------------------- + + + public void action(ActionCode actionCode, Object param) { + if (hook != null) { + if( param==null ) + hook.action(actionCode, this); + else + hook.action(actionCode, param); + } + } + + + // -------------------- State -------------------- + + + public int getStatus() { + return status; + } + + + /** + * Set the response status + */ + public void setStatus( int status ) { + this.status = status; + } + + + /** + * Get the status message. + */ + public String getMessage() { + return message; + } + + + /** + * Set the status message. + */ + public void setMessage(String message) { + this.message = message; + } + + + public boolean isCommitted() { + return commited; + } + + + public void setCommitted(boolean v) { + this.commited = v; + } + + + // -----------------Error State -------------------- + + + /** + * Set the error Exception that occurred during + * request processing. + */ + public void setErrorException(Exception ex) { + errorException = ex; + } + + + /** + * Get the Exception that occurred during request + * processing. + */ + public Exception getErrorException() { + return errorException; + } + + + public boolean isExceptionPresent() { + return ( errorException != null ); + } + + + /** + * Set request URI that caused an error during + * request processing. + */ + public void setErrorURI(String uri) { + errorURI = uri; + } + + + /** Get the request URI that caused the original error. + */ + public String getErrorURI() { + return errorURI; + } + + + // -------------------- Methods -------------------- + + + public void reset() + throws IllegalStateException { + + // Reset the headers only if this is the main request, + // not for included + contentType = null; + locale = DEFAULT_LOCALE; + contentLanguage = null; + characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; + contentLength = -1; + charsetSet = false; + + status = 200; + message = null; + headers.clear(); + + // Force the PrintWriter to flush its data to the output + // stream before resetting the output stream + // + // Reset the stream + if (commited) { + //String msg = sm.getString("servletOutputStreamImpl.reset.ise"); + throw new IllegalStateException(); + } + + action(ActionCode.ACTION_RESET, this); + } + + + public void finish() throws IOException { + action(ActionCode.ACTION_CLOSE, this); + } + + + public void acknowledge() throws IOException { + action(ActionCode.ACTION_ACK, this); + } + + + // -------------------- Headers -------------------- + /** + * Warning: This method always returns false for Content-Type + * and Content-Length. + */ + public boolean containsHeader(String name) { + return headers.getHeader(name) != null; + } + + + public void setHeader(String name, String value) { + char cc=name.charAt(0); + if( cc=='C' || cc=='c' ) { + if( checkSpecialHeader(name, value) ) + return; + } + headers.setValue(name).setString( value); + } + + + public void addHeader(String name, String value) { + char cc=name.charAt(0); + if( cc=='C' || cc=='c' ) { + if( checkSpecialHeader(name, value) ) + return; + } + headers.addValue(name).setString( value ); + } + + + /** + * Set internal fields for special header names. + * Called from set/addHeader. + * Return true if the header is special, no need to set the header. + */ + private boolean checkSpecialHeader( String name, String value) { + // XXX Eliminate redundant fields !!! + // ( both header and in special fields ) + if( name.equalsIgnoreCase( "Content-Type" ) ) { + setContentType( value ); + return true; + } + if( name.equalsIgnoreCase( "Content-Length" ) ) { + try { + long cL=Long.parseLong( value ); + setContentLength( cL ); + return true; + } catch( NumberFormatException ex ) { + // Do nothing - the spec doesn't have any "throws" + // and the user might know what he's doing + return false; + } + } + if( name.equalsIgnoreCase( "Content-Language" ) ) { + // XXX XXX Need to construct Locale or something else + } + return false; + } + + + /** Signal that we're done with the headers, and body will follow. + * Any implementation needs to notify ContextManager, to allow + * interceptors to fix headers. + */ + public void sendHeaders() throws IOException { + action(ActionCode.ACTION_COMMIT, this); + commited = true; + } + + + // -------------------- I18N -------------------- + + + public Locale getLocale() { + return locale; + } + + /** + * Called explicitely by user to set the Content-Language and + * the default encoding + */ + public void setLocale(Locale locale) { + + if (locale == null) { + return; // throw an exception? + } + + // Save the locale for use by getLocale() + this.locale = locale; + + // Set the contentLanguage for header output + contentLanguage = locale.getLanguage(); + if ((contentLanguage != null) && (contentLanguage.length() > 0)) { + String country = locale.getCountry(); + StringBuffer value = new StringBuffer(contentLanguage); + if ((country != null) && (country.length() > 0)) { + value.append('-'); + value.append(country); + } + contentLanguage = value.toString(); + } + + } + + /** + * Return the content language. + */ + public String getContentLanguage() { + return contentLanguage; + } + + /* + * Overrides the name of the character encoding used in the body + * of the response. This method must be called prior to writing output + * using getWriter(). + * + * @param charset String containing the name of the chararacter encoding. + */ + public void setCharacterEncoding(String charset) { + + if (isCommitted()) + return; + if (charset == null) + return; + + characterEncoding = charset; + charsetSet=true; + } + + public String getCharacterEncoding() { + return characterEncoding; + } + + /** + * Sets the content type. + * + * This method must preserve any response charset that may already have + * been set via a call to response.setContentType(), response.setLocale(), + * or response.setCharacterEncoding(). + * + * @param type the content type + */ + public void setContentType(String type) { + + int semicolonIndex = -1; + + if (type == null) { + this.contentType = null; + return; + } + + /* + * Remove the charset param (if any) from the Content-Type, and use it + * to set the response encoding. + * The most recent response encoding setting will be appended to the + * response's Content-Type (as its charset param) by getContentType(); + */ + boolean hasCharset = false; + int len = type.length(); + int index = type.indexOf(';'); + while (index != -1) { + semicolonIndex = index; + index++; + while (index < len && Character.isSpace(type.charAt(index))) { + index++; + } + if (index+8 < len + && type.charAt(index) == 'c' + && type.charAt(index+1) == 'h' + && type.charAt(index+2) == 'a' + && type.charAt(index+3) == 'r' + && type.charAt(index+4) == 's' + && type.charAt(index+5) == 'e' + && type.charAt(index+6) == 't' + && type.charAt(index+7) == '=') { + hasCharset = true; + break; + } + index = type.indexOf(';', index); + } + + if (!hasCharset) { + this.contentType = type; + return; + } + + this.contentType = type.substring(0, semicolonIndex); + String tail = type.substring(index+8); + int nextParam = tail.indexOf(';'); + String charsetValue = null; + if (nextParam != -1) { + this.contentType += tail.substring(nextParam); + charsetValue = tail.substring(0, nextParam); + } else { + charsetValue = tail; + } + + // The charset value may be quoted, but must not contain any quotes. + if (charsetValue != null && charsetValue.length() > 0) { + charsetSet=true; + charsetValue = charsetValue.replace('"', ' '); + this.characterEncoding = charsetValue.trim(); + } + } + + public String getContentType() { + + String ret = contentType; + + if (ret != null + && characterEncoding != null + && charsetSet) { + ret = ret + ";charset=" + characterEncoding; + } + + return ret; + } + + public void setContentLength(int contentLength) { + this.contentLength = contentLength; + } + + public void setContentLength(long contentLength) { + this.contentLength = contentLength; + } + + public int getContentLength() { + long length = getContentLengthLong(); + + if (length < Integer.MAX_VALUE) { + return (int) length; + } + return -1; + } + + public long getContentLengthLong() { + return contentLength; + } + + + /** + * Write a chunk of bytes. + */ + public void doWrite(ByteChunk chunk/*byte buffer[], int pos, int count*/) + throws IOException + { + outputBuffer.doWrite(chunk, this); + bytesWritten+=chunk.getLength(); + } + + // -------------------- + + public void recycle() { + + contentType = null; + contentLanguage = null; + locale = DEFAULT_LOCALE; + characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; + charsetSet = false; + contentLength = -1; + status = 200; + message = null; + commited = false; + errorException = null; + errorURI = null; + headers.clear(); + + // update counters + bytesWritten=0; + } + + public long getBytesWritten() { + return bytesWritten; + } + + public void setBytesWritten(long bytesWritten) { + this.bytesWritten = bytesWritten; + } +} diff --git a/java/org/apache/coyote/ajp/AjpAprProcessor.java b/java/org/apache/coyote/ajp/AjpAprProcessor.java index bcd45e8f2..c94dde29b 100644 --- a/java/org/apache/coyote/ajp/AjpAprProcessor.java +++ b/java/org/apache/coyote/ajp/AjpAprProcessor.java @@ -1,1270 +1,1270 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.ajp; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.nio.ByteBuffer; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.InputBuffer; -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Response; -import org.apache.tomcat.jni.Socket; -import org.apache.tomcat.jni.Status; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.net.AprEndpoint; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Processes HTTP requests. - * - * @author Remy Maucherat - * @author Henri Gomez - * @author Dan Milstein - * @author Keith Wannamaker - * @author Kevin Seguin - * @author Costin Manolache - * @author Bill Barker - */ -public class AjpAprProcessor implements ActionHook { - - - /** - * Logger. - */ - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(AjpAprProcessor.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------------- Constructors - - - public AjpAprProcessor(AprEndpoint endpoint) { - - this.endpoint = endpoint; - - request = new Request(); - request.setInputBuffer(new SocketInputBuffer()); - - response = new Response(); - response.setHook(this); - response.setOutputBuffer(new SocketOutputBuffer()); - request.setResponse(response); - - if (endpoint.getFirstReadTimeout() > 0) { - readTimeout = endpoint.getFirstReadTimeout() * 1000; - } else { - readTimeout = 100 * 1000; - } - - // Allocate input and output buffers - inputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2); - inputBuffer.limit(0); - outputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2); - - // Cause loading of HexUtils - int foo = HexUtils.DEC[0]; - - // Cause loading of HttpMessages - HttpMessages.getMessage(200); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated adapter. - */ - protected Adapter adapter = null; - - - /** - * Request object. - */ - protected Request request = null; - - - /** - * Response object. - */ - protected Response response = null; - - - /** - * Header message. Note that this header is merely the one used during the - * processing of the first message of a "request", so it might not be a request - * header. It will stay unchanged during the processing of the whole request. - */ - protected AjpMessage requestHeaderMessage = new AjpMessage(); - - - /** - * Message used for response header composition. - */ - protected AjpMessage responseHeaderMessage = new AjpMessage(); - - - /** - * Body message. - */ - protected AjpMessage bodyMessage = new AjpMessage(); - - - /** - * Body message. - */ - protected MessageBytes bodyBytes = MessageBytes.newInstance(); - - - /** - * State flag. - */ - protected boolean started = false; - - - /** - * Error flag. - */ - protected boolean error = false; - - - /** - * Socket associated with the current connection. - */ - protected long socket; - - - /** - * Host name (used to avoid useless B2C conversion on the host name). - */ - protected char[] hostNameC = new char[0]; - - - /** - * Associated endpoint. - */ - protected AprEndpoint endpoint; - - - /** - * The socket timeout used when reading the first block of the request - * header. - */ - protected long readTimeout; - - - /** - * Temp message bytes used for processing. - */ - protected MessageBytes tmpMB = MessageBytes.newInstance(); - - - /** - * Byte chunk for certs. - */ - protected MessageBytes certificates = MessageBytes.newInstance(); - - - /** - * End of stream flag. - */ - protected boolean endOfStream = false; - - - /** - * Body empty flag. - */ - protected boolean empty = true; - - - /** - * First read. - */ - protected boolean first = true; - - - /** - * Replay read. - */ - protected boolean replay = false; - - - /** - * Finished response. - */ - protected boolean finished = false; - - - /** - * Direct buffer used for output. - */ - protected ByteBuffer outputBuffer = null; - - - /** - * Direct buffer used for input. - */ - protected ByteBuffer inputBuffer = null; - - - /** - * Direct buffer used for sending right away a get body message. - */ - protected static final ByteBuffer getBodyMessageBuffer; - - - /** - * Direct buffer used for sending right away a pong message. - */ - protected static final ByteBuffer pongMessageBuffer; - - - /** - * End message array. - */ - protected static final byte[] endMessageArray; - - - // ----------------------------------------------------- Static Initializer - - - static { - - // Set the get body message buffer - AjpMessage getBodyMessage = new AjpMessage(); - getBodyMessage.reset(); - getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK); - getBodyMessage.appendInt(Constants.MAX_READ_SIZE); - getBodyMessage.end(); - getBodyMessageBuffer = - ByteBuffer.allocateDirect(getBodyMessage.getLen()); - getBodyMessageBuffer.put(getBodyMessage.getBuffer(), 0, - getBodyMessage.getLen()); - - // Set the read body message buffer - AjpMessage pongMessage = new AjpMessage(); - pongMessage.reset(); - pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY); - pongMessage.end(); - pongMessageBuffer = ByteBuffer.allocateDirect(pongMessage.getLen()); - pongMessageBuffer.put(pongMessage.getBuffer(), 0, - pongMessage.getLen()); - - // Allocate the end message array - AjpMessage endMessage = new AjpMessage(); - endMessage.reset(); - endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE); - endMessage.appendByte(1); - endMessage.end(); - endMessageArray = new byte[endMessage.getLen()]; - System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0, - endMessage.getLen()); - - } - - - // ------------------------------------------------------------- Properties - - - /** - * Use Tomcat authentication ? - */ - protected boolean tomcatAuthentication = true; - public boolean getTomcatAuthentication() { return tomcatAuthentication; } - public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; } - - - /** - * Required secret. - */ - protected String requiredSecret = null; - public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; } - - - // --------------------------------------------------------- Public Methods - - - /** Get the request associated with this processor. - * - * @return The request - */ - public Request getRequest() { - return request; - } - - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @throws IOException error during an I/O operation - */ - public boolean process(long socket) - throws IOException { - RequestInfo rp = request.getRequestProcessor(); - rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); - - // Setting up the socket - this.socket = socket; - Socket.setrbb(this.socket, inputBuffer); - Socket.setsbb(this.socket, outputBuffer); - - // Error flag - error = false; - - long soTimeout = endpoint.getSoTimeout(); - - int limit = 0; - if (endpoint.getFirstReadTimeout() > 0) { - limit = endpoint.getMaxThreads() / 2; - } - - boolean openSocket = true; - boolean keptAlive = false; - - while (started && !error) { - - // Parsing the request header - try { - // Get first message of the request - if (!readMessage(requestHeaderMessage, true, - keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { - // This means that no data is available right now - // (long keepalive), so that the processor should be recycled - // and the method should return true - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - break; - } - // Check message type, process right away and break if - // not regular request processing - int type = requestHeaderMessage.getByte(); - if (type == Constants.JK_AJP13_CPING_REQUEST) { - if (Socket.sendb(socket, pongMessageBuffer, 0, - pongMessageBuffer.position()) < 0) { - error = true; - } - continue; - } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { - // Usually the servlet didn't read the previous request body - if(log.isDebugEnabled()) { - log.debug("Unexpected message: "+type); - } - continue; - } - - keptAlive = true; - request.setStartTime(System.currentTimeMillis()); - } catch (IOException e) { - error = true; - break; - } catch (Throwable t) { - log.debug(sm.getString("ajpprocessor.header.error"), t); - // 400 - Bad Request - response.setStatus(400); - error = true; - } - - // Setting up filters, and parse some request headers - rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); - try { - prepareRequest(); - } catch (Throwable t) { - log.debug(sm.getString("ajpprocessor.request.prepare"), t); - // 400 - Internal Server Error - response.setStatus(400); - error = true; - } - - // Process the request in the adapter - if (!error) { - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - adapter.service(request, response); - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("ajpprocessor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - } - - // Finish the response if not done yet - if (!finished) { - try { - finish(); - } catch (Throwable t) { - error = true; - } - } - - // If there was an error, make sure the request is counted as - // and error, and update the statistics counter - if (error) { - response.setStatus(500); - } - request.updateCounters(); - - rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - recycle(); - - } - - // Add the socket to the poller - if (!error) { - endpoint.getPoller().add(socket); - } else { - openSocket = false; - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - recycle(); - - return openSocket; - - } - - - // ----------------------------------------------------- ActionHook Methods - - - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - public void action(ActionCode actionCode, Object param) { - - if (actionCode == ActionCode.ACTION_COMMIT) { - - if (response.isCommitted()) - return; - - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { - - if (!response.isCommitted()) { - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - return; - } - } - - try { - flush(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_CLOSE) { - // Close - - // End the processing of the current request, and stop any further - // transactions with the client - - try { - finish(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_START) { - - started = true; - - } else if (actionCode == ActionCode.ACTION_STOP) { - - started = false; - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { - - if (!certificates.isNull()) { - ByteChunk certData = certificates.getByteChunk(); - X509Certificate jsseCerts[] = null; - ByteArrayInputStream bais = - new ByteArrayInputStream(certData.getBytes(), - certData.getStart(), - certData.getLength()); - // Fill the first element. - try { - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) - cf.generateCertificate(bais); - jsseCerts = new X509Certificate[1]; - jsseCerts[0] = cert; - request.setAttribute(AprEndpoint.CERTIFICATE_KEY, jsseCerts); - } catch (java.security.cert.CertificateException e) { - log.error(sm.getString("ajpprocessor.certs.fail"), e); - return; - } - } - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { - - // Get remote host name using a DNS resolution - if (request.remoteHost().isNull()) { - try { - request.remoteHost().setString(InetAddress.getByName - (request.remoteAddr().toString()).getHostName()); - } catch (IOException iex) { - // Ignore - } - } - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { - - // Copy from local name for now, which should simply be an address - request.localAddr().setString(request.localName().toString()); - - } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { - - // Set the given bytes as the content - ByteChunk bc = (ByteChunk) param; - bodyBytes.setBytes(bc.getBytes(), bc.getStart(), bc.getLength()); - first = false; - empty = false; - replay = true; - - } - - - } - - - // ------------------------------------------------------ Connector Methods - - - /** - * Set the associated adapter. - * - * @param adapter the new adapter - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - - /** - * Get the associated adapter. - * - * @return the associated adapter - */ - public Adapter getAdapter() { - return adapter; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * After reading the request headers, we have to setup the request filters. - */ - protected void prepareRequest() { - - // Translate the HTTP method code to a String. - byte methodCode = requestHeaderMessage.getByte(); - if (methodCode != Constants.SC_M_JK_STORED) { - String methodName = Constants.methodTransArray[(int)methodCode - 1]; - request.method().setString(methodName); - } - - requestHeaderMessage.getBytes(request.protocol()); - requestHeaderMessage.getBytes(request.requestURI()); - - requestHeaderMessage.getBytes(request.remoteAddr()); - requestHeaderMessage.getBytes(request.remoteHost()); - requestHeaderMessage.getBytes(request.localName()); - request.setLocalPort(requestHeaderMessage.getInt()); - - boolean isSSL = requestHeaderMessage.getByte() != 0; - if (isSSL) { - request.scheme().setString("https"); - } - - // Decode headers - MimeHeaders headers = request.getMimeHeaders(); - - int hCount = requestHeaderMessage.getInt(); - for(int i = 0 ; i < hCount ; i++) { - String hName = null; - - // Header names are encoded as either an integer code starting - // with 0xA0, or as a normal string (in which case the first - // two bytes are the length). - int isc = requestHeaderMessage.peekInt(); - int hId = isc & 0xFF; - - MessageBytes vMB = null; - isc &= 0xFF00; - if(0xA000 == isc) { - requestHeaderMessage.getInt(); // To advance the read position - hName = Constants.headerTransArray[hId - 1]; - vMB = headers.addValue(hName); - } else { - // reset hId -- if the header currently being read - // happens to be 7 or 8 bytes long, the code below - // will think it's the content-type header or the - // content-length header - SC_REQ_CONTENT_TYPE=7, - // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected - // behaviour. see bug 5861 for more information. - hId = -1; - requestHeaderMessage.getBytes(tmpMB); - ByteChunk bc = tmpMB.getByteChunk(); - vMB = headers.addValue(bc.getBuffer(), - bc.getStart(), bc.getLength()); - } - - requestHeaderMessage.getBytes(vMB); - - if (hId == Constants.SC_REQ_CONTENT_LENGTH || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { - // just read the content-length header, so set it - request.setContentLength( vMB.getInt() ); - } else if (hId == Constants.SC_REQ_CONTENT_TYPE || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { - // just read the content-type header, so set it - ByteChunk bchunk = vMB.getByteChunk(); - request.contentType().setBytes(bchunk.getBytes(), - bchunk.getOffset(), - bchunk.getLength()); - } - } - - // Decode extra attributes - boolean secret = false; - byte attributeCode; - while ((attributeCode = requestHeaderMessage.getByte()) - != Constants.SC_A_ARE_DONE) { - - switch (attributeCode) { - - case Constants.SC_A_REQ_ATTRIBUTE : - requestHeaderMessage.getBytes(tmpMB); - String n = tmpMB.toString(); - requestHeaderMessage.getBytes(tmpMB); - String v = tmpMB.toString(); - request.setAttribute(n, v); - break; - - case Constants.SC_A_CONTEXT : - requestHeaderMessage.getBytes(tmpMB); - // nothing - break; - - case Constants.SC_A_SERVLET_PATH : - requestHeaderMessage.getBytes(tmpMB); - // nothing - break; - - case Constants.SC_A_REMOTE_USER : - if (tomcatAuthentication) { - // ignore server - requestHeaderMessage.getBytes(tmpMB); - } else { - requestHeaderMessage.getBytes(request.getRemoteUser()); - } - break; - - case Constants.SC_A_AUTH_TYPE : - if (tomcatAuthentication) { - // ignore server - requestHeaderMessage.getBytes(tmpMB); - } else { - requestHeaderMessage.getBytes(request.getAuthType()); - } - break; - - case Constants.SC_A_QUERY_STRING : - requestHeaderMessage.getBytes(request.queryString()); - break; - - case Constants.SC_A_JVM_ROUTE : - requestHeaderMessage.getBytes(request.instanceId()); - break; - - case Constants.SC_A_SSL_CERT : - request.scheme().setString("https"); - // SSL certificate extraction is lazy, moved to JkCoyoteHandler - requestHeaderMessage.getBytes(certificates); - break; - - case Constants.SC_A_SSL_CIPHER : - request.scheme().setString("https"); - requestHeaderMessage.getBytes(tmpMB); - request.setAttribute(AprEndpoint.CIPHER_SUITE_KEY, - tmpMB.toString()); - break; - - case Constants.SC_A_SSL_SESSION : - request.scheme().setString("https"); - requestHeaderMessage.getBytes(tmpMB); - request.setAttribute(AprEndpoint.SESSION_ID_KEY, - tmpMB.toString()); - break; - - case Constants.SC_A_SSL_KEY_SIZE : - request.setAttribute(AprEndpoint.KEY_SIZE_KEY, - new Integer(requestHeaderMessage.getInt())); - break; - - case Constants.SC_A_STORED_METHOD: - requestHeaderMessage.getBytes(request.method()); - break; - - case Constants.SC_A_SECRET: - requestHeaderMessage.getBytes(tmpMB); - if (requiredSecret != null) { - secret = true; - if (!tmpMB.equals(requiredSecret)) { - response.setStatus(403); - error = true; - } - } - break; - - default: - // Ignore unknown attribute for backward compatibility - break; - - } - - } - - // Check if secret was submitted if required - if ((requiredSecret != null) && !secret) { - response.setStatus(403); - error = true; - } - - // Check for a full URI (including protocol://host:port/) - ByteChunk uriBC = request.requestURI().getByteChunk(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - - int pos = uriBC.indexOf("://", 0, 3, 4); - int uriBCStart = uriBC.getStart(); - int slashPos = -1; - if (pos != -1) { - byte[] uriB = uriBC.getBytes(); - slashPos = uriBC.indexOf('/', pos + 3); - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/" - request.requestURI().setBytes - (uriB, uriBCStart + pos + 1, 1); - } else { - request.requestURI().setBytes - (uriB, uriBCStart + slashPos, - uriBC.getLength() - slashPos); - } - MessageBytes hostMB = headers.setValue("host"); - hostMB.setBytes(uriB, uriBCStart + pos + 3, - slashPos - pos - 3); - } - - } - - MessageBytes valueMB = request.getMimeHeaders().getValue("host"); - parseHost(valueMB); - - } - - - /** - * Parse host. - */ - public void parseHost(MessageBytes valueMB) { - - if (valueMB == null || (valueMB != null && valueMB.isNull()) ) { - // HTTP/1.0 - // Default is what the socket tells us. Overriden if a host is - // found/parsed - request.setServerPort(endpoint.getPort()); - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - if (hostNameC.length < valueL) { - hostNameC = new char[valueL]; - } - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC[i] = b; - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (request.scheme().equalsIgnoreCase("https")) { - // 443 - Default HTTPS port - request.setServerPort(443); - } else { - // 80 - Default HTTTP port - request.setServerPort(80); - } - request.serverName().setChars(hostNameC, 0, valueL); - } else { - - request.serverName().setChars(hostNameC, 0, colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; - if (charValue == -1) { - // Invalid character - error = true; - // 400 - Bad request - response.setStatus(400); - break; - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - - } - - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - protected void prepareResponse() - throws IOException { - - response.setCommitted(true); - - responseHeaderMessage.reset(); - responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS); - - // HTTP header contents - responseHeaderMessage.appendInt(response.getStatus()); - String message = response.getMessage(); - if (message == null){ - message = HttpMessages.getMessage(response.getStatus()); - } else { - message = message.replace('\n', ' ').replace('\r', ' '); - } - tmpMB.setString(message); - responseHeaderMessage.appendBytes(tmpMB); - - // Special headers - MimeHeaders headers = response.getMimeHeaders(); - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language").setString(contentLanguage); - } - int contentLength = response.getContentLength(); - if (contentLength >= 0) { - headers.setValue("Content-Length").setInt(contentLength); - } - - // Other headers - int numHeaders = headers.size(); - responseHeaderMessage.appendInt(numHeaders); - for (int i = 0; i < numHeaders; i++) { - MessageBytes hN = headers.getName(i); - responseHeaderMessage.appendBytes(hN); - MessageBytes hV=headers.getValue(i); - responseHeaderMessage.appendBytes(hV); - } - - // Write to buffer - responseHeaderMessage.end(); - outputBuffer.put(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen()); - - } - - - /** - * Finish AJP response. - */ - protected void finish() - throws IOException { - - if (!response.isCommitted()) { - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - } - } - - if (finished) - return; - - finished = true; - - // Add the end message - if (outputBuffer.position() + endMessageArray.length > outputBuffer.capacity()) { - flush(); - } - outputBuffer.put(endMessageArray); - flush(); - - } - - - /** - * Read at least the specified amount of bytes, and place them - * in the input buffer. - */ - protected boolean read(int n) - throws IOException { - - if (inputBuffer.capacity() - inputBuffer.limit() <= - n - inputBuffer.remaining()) { - inputBuffer.compact(); - inputBuffer.limit(inputBuffer.position()); - inputBuffer.position(0); - } - while (inputBuffer.remaining() < n) { - int nRead = Socket.recvbb - (socket, inputBuffer.limit(), - inputBuffer.capacity() - inputBuffer.limit()); - if (nRead > 0) { - inputBuffer.limit(inputBuffer.limit() + nRead); - } else { - throw new IOException(sm.getString("ajpprotocol.failedread")); - } - } - - return true; - - } - - - /** - * Read at least the specified amount of bytes, and place them - * in the input buffer. - */ - protected boolean readt(int n, boolean useAvailableData) - throws IOException { - - if (useAvailableData && inputBuffer.remaining() == 0) { - return false; - } - if (inputBuffer.capacity() - inputBuffer.limit() <= - n - inputBuffer.remaining()) { - inputBuffer.compact(); - inputBuffer.limit(inputBuffer.position()); - inputBuffer.position(0); - } - while (inputBuffer.remaining() < n) { - int nRead = Socket.recvbbt - (socket, inputBuffer.limit(), - inputBuffer.capacity() - inputBuffer.limit(), readTimeout); - if (nRead > 0) { - inputBuffer.limit(inputBuffer.limit() + nRead); - } else { - if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { - return false; - } else { - throw new IOException(sm.getString("ajpprotocol.failedread")); - } - } - } - - return true; - - } - - - /** Receive a chunk of data. Called to implement the - * 'special' packet in ajp13 and to receive the data - * after we send a GET_BODY packet - */ - public boolean receive() throws IOException { - - first = false; - bodyMessage.reset(); - readMessage(bodyMessage, false, false); - - // No data received. - if (bodyMessage.getLen() == 0) { - // just the header - // Don't mark 'end of stream' for the first chunk. - return false; - } - int blen = bodyMessage.peekInt(); - if (blen == 0) { - return false; - } - - bodyMessage.getBytes(bodyBytes); - empty = false; - return true; - } - - /** - * Get more request body data from the web server and store it in the - * internal buffer. - * - * @return true if there is more data, false if not. - */ - private boolean refillReadBuffer() throws IOException { - // If the server returns an empty packet, assume that that end of - // the stream has been reached (yuck -- fix protocol??). - // FORM support - if (replay) { - endOfStream = true; // we've read everything there is - } - if (endOfStream) { - return false; - } - - // Request more data immediately - Socket.sendb(socket, getBodyMessageBuffer, 0, - getBodyMessageBuffer.position()); - - boolean moreData = receive(); - if( !moreData ) { - endOfStream = true; - } - return moreData; - } - - - /** - * Read an AJP message. - * - * @param first is true if the message is the first in the request, which - * will cause a short duration blocking read - * @return true if the message has been read, false if the short read - * didn't return anything - * @throws IOException any other failure, including incomplete reads - */ - protected boolean readMessage(AjpMessage message, boolean first, - boolean useAvailableData) - throws IOException { - - byte[] buf = message.getBuffer(); - int headerLength = message.getHeaderLength(); - - if (first) { - if (!readt(headerLength, useAvailableData)) { - return false; - } - } else { - read(headerLength); - } - inputBuffer.get(message.getBuffer(), 0, headerLength); - message.processHeader(); - read(message.getLen()); - inputBuffer.get(message.getBuffer(), headerLength, message.getLen()); - - return true; - - } - - - /** - * Recycle the processor. - */ - public void recycle() { - - // Recycle Request object - first = true; - endOfStream = false; - empty = true; - replay = false; - finished = false; - request.recycle(); - response.recycle(); - certificates.recycle(); - - inputBuffer.clear(); - inputBuffer.limit(0); - outputBuffer.clear(); - - } - - - /** - * Callback to write data from the buffer. - */ - protected void flush() - throws IOException { - if (outputBuffer.position() > 0) { - if (Socket.sendbb(socket, 0, outputBuffer.position()) < 0) { - throw new IOException(); - } - outputBuffer.clear(); - } - } - - - // ------------------------------------- InputStreamInputBuffer Inner Class - - - /** - * This class is an input buffer which will read its data from an input - * stream. - */ - protected class SocketInputBuffer - implements InputBuffer { - - - /** - * Read bytes into the specified chunk. - */ - public int doRead(ByteChunk chunk, Request req ) - throws IOException { - - if (endOfStream) { - return -1; - } - if (first && req.getContentLength() > 0) { - // Handle special first-body-chunk - if (!receive()) { - return 0; - } - } else if (empty) { - if (!refillReadBuffer()) { - return -1; - } - } - ByteChunk bc = bodyBytes.getByteChunk(); - chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength()); - empty = true; - return chunk.getLength(); - - } - - } - - - // ----------------------------------- OutputStreamOutputBuffer Inner Class - - - /** - * This class is an output buffer which will write data to an output - * stream. - */ - protected class SocketOutputBuffer - implements OutputBuffer { - - - /** - * Write chunk. - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!response.isCommitted()) { - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - } - } - - int len = chunk.getLength(); - // 4 - hardcoded, byte[] marshalling overhead - int chunkSize = Constants.MAX_SEND_SIZE; - int off = 0; - while (len > 0) { - int thisTime = len; - if (thisTime > chunkSize) { - thisTime = chunkSize; - } - len -= thisTime; - if (outputBuffer.position() + thisTime + - Constants.H_SIZE + 4 > outputBuffer.capacity()) { - flush(); - } - outputBuffer.put((byte) 0x41); - outputBuffer.put((byte) 0x42); - outputBuffer.putShort((short) (thisTime + 4)); - outputBuffer.put(Constants.JK_AJP13_SEND_BODY_CHUNK); - outputBuffer.putShort((short) thisTime); - outputBuffer.put(chunk.getBytes(), chunk.getOffset() + off, thisTime); - outputBuffer.put((byte) 0x00); - off += thisTime; - } - - return chunk.getLength(); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.ajp; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.nio.ByteBuffer; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.InputBuffer; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Request; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Response; +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.jni.Status; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.AprEndpoint; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Processes HTTP requests. + * + * @author Remy Maucherat + * @author Henri Gomez + * @author Dan Milstein + * @author Keith Wannamaker + * @author Kevin Seguin + * @author Costin Manolache + * @author Bill Barker + */ +public class AjpAprProcessor implements ActionHook { + + + /** + * Logger. + */ + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(AjpAprProcessor.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------------- Constructors + + + public AjpAprProcessor(AprEndpoint endpoint) { + + this.endpoint = endpoint; + + request = new Request(); + request.setInputBuffer(new SocketInputBuffer()); + + response = new Response(); + response.setHook(this); + response.setOutputBuffer(new SocketOutputBuffer()); + request.setResponse(response); + + if (endpoint.getFirstReadTimeout() > 0) { + readTimeout = endpoint.getFirstReadTimeout() * 1000; + } else { + readTimeout = 100 * 1000; + } + + // Allocate input and output buffers + inputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2); + inputBuffer.limit(0); + outputBuffer = ByteBuffer.allocateDirect(Constants.MAX_PACKET_SIZE * 2); + + // Cause loading of HexUtils + int foo = HexUtils.DEC[0]; + + // Cause loading of HttpMessages + HttpMessages.getMessage(200); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated adapter. + */ + protected Adapter adapter = null; + + + /** + * Request object. + */ + protected Request request = null; + + + /** + * Response object. + */ + protected Response response = null; + + + /** + * Header message. Note that this header is merely the one used during the + * processing of the first message of a "request", so it might not be a request + * header. It will stay unchanged during the processing of the whole request. + */ + protected AjpMessage requestHeaderMessage = new AjpMessage(); + + + /** + * Message used for response header composition. + */ + protected AjpMessage responseHeaderMessage = new AjpMessage(); + + + /** + * Body message. + */ + protected AjpMessage bodyMessage = new AjpMessage(); + + + /** + * Body message. + */ + protected MessageBytes bodyBytes = MessageBytes.newInstance(); + + + /** + * State flag. + */ + protected boolean started = false; + + + /** + * Error flag. + */ + protected boolean error = false; + + + /** + * Socket associated with the current connection. + */ + protected long socket; + + + /** + * Host name (used to avoid useless B2C conversion on the host name). + */ + protected char[] hostNameC = new char[0]; + + + /** + * Associated endpoint. + */ + protected AprEndpoint endpoint; + + + /** + * The socket timeout used when reading the first block of the request + * header. + */ + protected long readTimeout; + + + /** + * Temp message bytes used for processing. + */ + protected MessageBytes tmpMB = MessageBytes.newInstance(); + + + /** + * Byte chunk for certs. + */ + protected MessageBytes certificates = MessageBytes.newInstance(); + + + /** + * End of stream flag. + */ + protected boolean endOfStream = false; + + + /** + * Body empty flag. + */ + protected boolean empty = true; + + + /** + * First read. + */ + protected boolean first = true; + + + /** + * Replay read. + */ + protected boolean replay = false; + + + /** + * Finished response. + */ + protected boolean finished = false; + + + /** + * Direct buffer used for output. + */ + protected ByteBuffer outputBuffer = null; + + + /** + * Direct buffer used for input. + */ + protected ByteBuffer inputBuffer = null; + + + /** + * Direct buffer used for sending right away a get body message. + */ + protected static final ByteBuffer getBodyMessageBuffer; + + + /** + * Direct buffer used for sending right away a pong message. + */ + protected static final ByteBuffer pongMessageBuffer; + + + /** + * End message array. + */ + protected static final byte[] endMessageArray; + + + // ----------------------------------------------------- Static Initializer + + + static { + + // Set the get body message buffer + AjpMessage getBodyMessage = new AjpMessage(); + getBodyMessage.reset(); + getBodyMessage.appendByte(Constants.JK_AJP13_GET_BODY_CHUNK); + getBodyMessage.appendInt(Constants.MAX_READ_SIZE); + getBodyMessage.end(); + getBodyMessageBuffer = + ByteBuffer.allocateDirect(getBodyMessage.getLen()); + getBodyMessageBuffer.put(getBodyMessage.getBuffer(), 0, + getBodyMessage.getLen()); + + // Set the read body message buffer + AjpMessage pongMessage = new AjpMessage(); + pongMessage.reset(); + pongMessage.appendByte(Constants.JK_AJP13_CPONG_REPLY); + pongMessage.end(); + pongMessageBuffer = ByteBuffer.allocateDirect(pongMessage.getLen()); + pongMessageBuffer.put(pongMessage.getBuffer(), 0, + pongMessage.getLen()); + + // Allocate the end message array + AjpMessage endMessage = new AjpMessage(); + endMessage.reset(); + endMessage.appendByte(Constants.JK_AJP13_END_RESPONSE); + endMessage.appendByte(1); + endMessage.end(); + endMessageArray = new byte[endMessage.getLen()]; + System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0, + endMessage.getLen()); + + } + + + // ------------------------------------------------------------- Properties + + + /** + * Use Tomcat authentication ? + */ + protected boolean tomcatAuthentication = true; + public boolean getTomcatAuthentication() { return tomcatAuthentication; } + public void setTomcatAuthentication(boolean tomcatAuthentication) { this.tomcatAuthentication = tomcatAuthentication; } + + + /** + * Required secret. + */ + protected String requiredSecret = null; + public void setRequiredSecret(String requiredSecret) { this.requiredSecret = requiredSecret; } + + + // --------------------------------------------------------- Public Methods + + + /** Get the request associated with this processor. + * + * @return The request + */ + public Request getRequest() { + return request; + } + + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @throws IOException error during an I/O operation + */ + public boolean process(long socket) + throws IOException { + RequestInfo rp = request.getRequestProcessor(); + rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); + + // Setting up the socket + this.socket = socket; + Socket.setrbb(this.socket, inputBuffer); + Socket.setsbb(this.socket, outputBuffer); + + // Error flag + error = false; + + long soTimeout = endpoint.getSoTimeout(); + + int limit = 0; + if (endpoint.getFirstReadTimeout() > 0) { + limit = endpoint.getMaxThreads() / 2; + } + + boolean openSocket = true; + boolean keptAlive = false; + + while (started && !error) { + + // Parsing the request header + try { + // Get first message of the request + if (!readMessage(requestHeaderMessage, true, + keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { + // This means that no data is available right now + // (long keepalive), so that the processor should be recycled + // and the method should return true + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + break; + } + // Check message type, process right away and break if + // not regular request processing + int type = requestHeaderMessage.getByte(); + if (type == Constants.JK_AJP13_CPING_REQUEST) { + if (Socket.sendb(socket, pongMessageBuffer, 0, + pongMessageBuffer.position()) < 0) { + error = true; + } + continue; + } else if(type != Constants.JK_AJP13_FORWARD_REQUEST) { + // Usually the servlet didn't read the previous request body + if(log.isDebugEnabled()) { + log.debug("Unexpected message: "+type); + } + continue; + } + + keptAlive = true; + request.setStartTime(System.currentTimeMillis()); + } catch (IOException e) { + error = true; + break; + } catch (Throwable t) { + log.debug(sm.getString("ajpprocessor.header.error"), t); + // 400 - Bad Request + response.setStatus(400); + error = true; + } + + // Setting up filters, and parse some request headers + rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); + try { + prepareRequest(); + } catch (Throwable t) { + log.debug(sm.getString("ajpprocessor.request.prepare"), t); + // 400 - Internal Server Error + response.setStatus(400); + error = true; + } + + // Process the request in the adapter + if (!error) { + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + adapter.service(request, response); + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("ajpprocessor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + } + + // Finish the response if not done yet + if (!finished) { + try { + finish(); + } catch (Throwable t) { + error = true; + } + } + + // If there was an error, make sure the request is counted as + // and error, and update the statistics counter + if (error) { + response.setStatus(500); + } + request.updateCounters(); + + rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); + recycle(); + + } + + // Add the socket to the poller + if (!error) { + endpoint.getPoller().add(socket); + } else { + openSocket = false; + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + recycle(); + + return openSocket; + + } + + + // ----------------------------------------------------- ActionHook Methods + + + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + public void action(ActionCode actionCode, Object param) { + + if (actionCode == ActionCode.ACTION_COMMIT) { + + if (response.isCommitted()) + return; + + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { + + if (!response.isCommitted()) { + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + return; + } + } + + try { + flush(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_CLOSE) { + // Close + + // End the processing of the current request, and stop any further + // transactions with the client + + try { + finish(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_START) { + + started = true; + + } else if (actionCode == ActionCode.ACTION_STOP) { + + started = false; + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { + + if (!certificates.isNull()) { + ByteChunk certData = certificates.getByteChunk(); + X509Certificate jsseCerts[] = null; + ByteArrayInputStream bais = + new ByteArrayInputStream(certData.getBytes(), + certData.getStart(), + certData.getLength()); + // Fill the first element. + try { + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) + cf.generateCertificate(bais); + jsseCerts = new X509Certificate[1]; + jsseCerts[0] = cert; + request.setAttribute(AprEndpoint.CERTIFICATE_KEY, jsseCerts); + } catch (java.security.cert.CertificateException e) { + log.error(sm.getString("ajpprocessor.certs.fail"), e); + return; + } + } + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { + + // Get remote host name using a DNS resolution + if (request.remoteHost().isNull()) { + try { + request.remoteHost().setString(InetAddress.getByName + (request.remoteAddr().toString()).getHostName()); + } catch (IOException iex) { + // Ignore + } + } + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { + + // Copy from local name for now, which should simply be an address + request.localAddr().setString(request.localName().toString()); + + } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { + + // Set the given bytes as the content + ByteChunk bc = (ByteChunk) param; + bodyBytes.setBytes(bc.getBytes(), bc.getStart(), bc.getLength()); + first = false; + empty = false; + replay = true; + + } + + + } + + + // ------------------------------------------------------ Connector Methods + + + /** + * Set the associated adapter. + * + * @param adapter the new adapter + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + + /** + * Get the associated adapter. + * + * @return the associated adapter + */ + public Adapter getAdapter() { + return adapter; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * After reading the request headers, we have to setup the request filters. + */ + protected void prepareRequest() { + + // Translate the HTTP method code to a String. + byte methodCode = requestHeaderMessage.getByte(); + if (methodCode != Constants.SC_M_JK_STORED) { + String methodName = Constants.methodTransArray[(int)methodCode - 1]; + request.method().setString(methodName); + } + + requestHeaderMessage.getBytes(request.protocol()); + requestHeaderMessage.getBytes(request.requestURI()); + + requestHeaderMessage.getBytes(request.remoteAddr()); + requestHeaderMessage.getBytes(request.remoteHost()); + requestHeaderMessage.getBytes(request.localName()); + request.setLocalPort(requestHeaderMessage.getInt()); + + boolean isSSL = requestHeaderMessage.getByte() != 0; + if (isSSL) { + request.scheme().setString("https"); + } + + // Decode headers + MimeHeaders headers = request.getMimeHeaders(); + + int hCount = requestHeaderMessage.getInt(); + for(int i = 0 ; i < hCount ; i++) { + String hName = null; + + // Header names are encoded as either an integer code starting + // with 0xA0, or as a normal string (in which case the first + // two bytes are the length). + int isc = requestHeaderMessage.peekInt(); + int hId = isc & 0xFF; + + MessageBytes vMB = null; + isc &= 0xFF00; + if(0xA000 == isc) { + requestHeaderMessage.getInt(); // To advance the read position + hName = Constants.headerTransArray[hId - 1]; + vMB = headers.addValue(hName); + } else { + // reset hId -- if the header currently being read + // happens to be 7 or 8 bytes long, the code below + // will think it's the content-type header or the + // content-length header - SC_REQ_CONTENT_TYPE=7, + // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected + // behaviour. see bug 5861 for more information. + hId = -1; + requestHeaderMessage.getBytes(tmpMB); + ByteChunk bc = tmpMB.getByteChunk(); + vMB = headers.addValue(bc.getBuffer(), + bc.getStart(), bc.getLength()); + } + + requestHeaderMessage.getBytes(vMB); + + if (hId == Constants.SC_REQ_CONTENT_LENGTH || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { + // just read the content-length header, so set it + request.setContentLength( vMB.getInt() ); + } else if (hId == Constants.SC_REQ_CONTENT_TYPE || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { + // just read the content-type header, so set it + ByteChunk bchunk = vMB.getByteChunk(); + request.contentType().setBytes(bchunk.getBytes(), + bchunk.getOffset(), + bchunk.getLength()); + } + } + + // Decode extra attributes + boolean secret = false; + byte attributeCode; + while ((attributeCode = requestHeaderMessage.getByte()) + != Constants.SC_A_ARE_DONE) { + + switch (attributeCode) { + + case Constants.SC_A_REQ_ATTRIBUTE : + requestHeaderMessage.getBytes(tmpMB); + String n = tmpMB.toString(); + requestHeaderMessage.getBytes(tmpMB); + String v = tmpMB.toString(); + request.setAttribute(n, v); + break; + + case Constants.SC_A_CONTEXT : + requestHeaderMessage.getBytes(tmpMB); + // nothing + break; + + case Constants.SC_A_SERVLET_PATH : + requestHeaderMessage.getBytes(tmpMB); + // nothing + break; + + case Constants.SC_A_REMOTE_USER : + if (tomcatAuthentication) { + // ignore server + requestHeaderMessage.getBytes(tmpMB); + } else { + requestHeaderMessage.getBytes(request.getRemoteUser()); + } + break; + + case Constants.SC_A_AUTH_TYPE : + if (tomcatAuthentication) { + // ignore server + requestHeaderMessage.getBytes(tmpMB); + } else { + requestHeaderMessage.getBytes(request.getAuthType()); + } + break; + + case Constants.SC_A_QUERY_STRING : + requestHeaderMessage.getBytes(request.queryString()); + break; + + case Constants.SC_A_JVM_ROUTE : + requestHeaderMessage.getBytes(request.instanceId()); + break; + + case Constants.SC_A_SSL_CERT : + request.scheme().setString("https"); + // SSL certificate extraction is lazy, moved to JkCoyoteHandler + requestHeaderMessage.getBytes(certificates); + break; + + case Constants.SC_A_SSL_CIPHER : + request.scheme().setString("https"); + requestHeaderMessage.getBytes(tmpMB); + request.setAttribute(AprEndpoint.CIPHER_SUITE_KEY, + tmpMB.toString()); + break; + + case Constants.SC_A_SSL_SESSION : + request.scheme().setString("https"); + requestHeaderMessage.getBytes(tmpMB); + request.setAttribute(AprEndpoint.SESSION_ID_KEY, + tmpMB.toString()); + break; + + case Constants.SC_A_SSL_KEY_SIZE : + request.setAttribute(AprEndpoint.KEY_SIZE_KEY, + new Integer(requestHeaderMessage.getInt())); + break; + + case Constants.SC_A_STORED_METHOD: + requestHeaderMessage.getBytes(request.method()); + break; + + case Constants.SC_A_SECRET: + requestHeaderMessage.getBytes(tmpMB); + if (requiredSecret != null) { + secret = true; + if (!tmpMB.equals(requiredSecret)) { + response.setStatus(403); + error = true; + } + } + break; + + default: + // Ignore unknown attribute for backward compatibility + break; + + } + + } + + // Check if secret was submitted if required + if ((requiredSecret != null) && !secret) { + response.setStatus(403); + error = true; + } + + // Check for a full URI (including protocol://host:port/) + ByteChunk uriBC = request.requestURI().getByteChunk(); + if (uriBC.startsWithIgnoreCase("http", 0)) { + + int pos = uriBC.indexOf("://", 0, 3, 4); + int uriBCStart = uriBC.getStart(); + int slashPos = -1; + if (pos != -1) { + byte[] uriB = uriBC.getBytes(); + slashPos = uriBC.indexOf('/', pos + 3); + if (slashPos == -1) { + slashPos = uriBC.getLength(); + // Set URI as "/" + request.requestURI().setBytes + (uriB, uriBCStart + pos + 1, 1); + } else { + request.requestURI().setBytes + (uriB, uriBCStart + slashPos, + uriBC.getLength() - slashPos); + } + MessageBytes hostMB = headers.setValue("host"); + hostMB.setBytes(uriB, uriBCStart + pos + 3, + slashPos - pos - 3); + } + + } + + MessageBytes valueMB = request.getMimeHeaders().getValue("host"); + parseHost(valueMB); + + } + + + /** + * Parse host. + */ + public void parseHost(MessageBytes valueMB) { + + if (valueMB == null || (valueMB != null && valueMB.isNull()) ) { + // HTTP/1.0 + // Default is what the socket tells us. Overriden if a host is + // found/parsed + request.setServerPort(endpoint.getPort()); + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + if (hostNameC.length < valueL) { + hostNameC = new char[valueL]; + } + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC[i] = b; + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (request.scheme().equalsIgnoreCase("https")) { + // 443 - Default HTTPS port + request.setServerPort(443); + } else { + // 80 - Default HTTTP port + request.setServerPort(80); + } + request.serverName().setChars(hostNameC, 0, valueL); + } else { + + request.serverName().setChars(hostNameC, 0, colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; + if (charValue == -1) { + // Invalid character + error = true; + // 400 - Bad request + response.setStatus(400); + break; + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + + } + + } + + + /** + * When committing the response, we have to validate the set of headers, as + * well as setup the response filters. + */ + protected void prepareResponse() + throws IOException { + + response.setCommitted(true); + + responseHeaderMessage.reset(); + responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS); + + // HTTP header contents + responseHeaderMessage.appendInt(response.getStatus()); + String message = response.getMessage(); + if (message == null){ + message = HttpMessages.getMessage(response.getStatus()); + } else { + message = message.replace('\n', ' ').replace('\r', ' '); + } + tmpMB.setString(message); + responseHeaderMessage.appendBytes(tmpMB); + + // Special headers + MimeHeaders headers = response.getMimeHeaders(); + String contentType = response.getContentType(); + if (contentType != null) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = response.getContentLanguage(); + if (contentLanguage != null) { + headers.setValue("Content-Language").setString(contentLanguage); + } + int contentLength = response.getContentLength(); + if (contentLength >= 0) { + headers.setValue("Content-Length").setInt(contentLength); + } + + // Other headers + int numHeaders = headers.size(); + responseHeaderMessage.appendInt(numHeaders); + for (int i = 0; i < numHeaders; i++) { + MessageBytes hN = headers.getName(i); + responseHeaderMessage.appendBytes(hN); + MessageBytes hV=headers.getValue(i); + responseHeaderMessage.appendBytes(hV); + } + + // Write to buffer + responseHeaderMessage.end(); + outputBuffer.put(responseHeaderMessage.getBuffer(), 0, responseHeaderMessage.getLen()); + + } + + + /** + * Finish AJP response. + */ + protected void finish() + throws IOException { + + if (!response.isCommitted()) { + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + } + } + + if (finished) + return; + + finished = true; + + // Add the end message + if (outputBuffer.position() + endMessageArray.length > outputBuffer.capacity()) { + flush(); + } + outputBuffer.put(endMessageArray); + flush(); + + } + + + /** + * Read at least the specified amount of bytes, and place them + * in the input buffer. + */ + protected boolean read(int n) + throws IOException { + + if (inputBuffer.capacity() - inputBuffer.limit() <= + n - inputBuffer.remaining()) { + inputBuffer.compact(); + inputBuffer.limit(inputBuffer.position()); + inputBuffer.position(0); + } + while (inputBuffer.remaining() < n) { + int nRead = Socket.recvbb + (socket, inputBuffer.limit(), + inputBuffer.capacity() - inputBuffer.limit()); + if (nRead > 0) { + inputBuffer.limit(inputBuffer.limit() + nRead); + } else { + throw new IOException(sm.getString("ajpprotocol.failedread")); + } + } + + return true; + + } + + + /** + * Read at least the specified amount of bytes, and place them + * in the input buffer. + */ + protected boolean readt(int n, boolean useAvailableData) + throws IOException { + + if (useAvailableData && inputBuffer.remaining() == 0) { + return false; + } + if (inputBuffer.capacity() - inputBuffer.limit() <= + n - inputBuffer.remaining()) { + inputBuffer.compact(); + inputBuffer.limit(inputBuffer.position()); + inputBuffer.position(0); + } + while (inputBuffer.remaining() < n) { + int nRead = Socket.recvbbt + (socket, inputBuffer.limit(), + inputBuffer.capacity() - inputBuffer.limit(), readTimeout); + if (nRead > 0) { + inputBuffer.limit(inputBuffer.limit() + nRead); + } else { + if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { + return false; + } else { + throw new IOException(sm.getString("ajpprotocol.failedread")); + } + } + } + + return true; + + } + + + /** Receive a chunk of data. Called to implement the + * 'special' packet in ajp13 and to receive the data + * after we send a GET_BODY packet + */ + public boolean receive() throws IOException { + + first = false; + bodyMessage.reset(); + readMessage(bodyMessage, false, false); + + // No data received. + if (bodyMessage.getLen() == 0) { + // just the header + // Don't mark 'end of stream' for the first chunk. + return false; + } + int blen = bodyMessage.peekInt(); + if (blen == 0) { + return false; + } + + bodyMessage.getBytes(bodyBytes); + empty = false; + return true; + } + + /** + * Get more request body data from the web server and store it in the + * internal buffer. + * + * @return true if there is more data, false if not. + */ + private boolean refillReadBuffer() throws IOException { + // If the server returns an empty packet, assume that that end of + // the stream has been reached (yuck -- fix protocol??). + // FORM support + if (replay) { + endOfStream = true; // we've read everything there is + } + if (endOfStream) { + return false; + } + + // Request more data immediately + Socket.sendb(socket, getBodyMessageBuffer, 0, + getBodyMessageBuffer.position()); + + boolean moreData = receive(); + if( !moreData ) { + endOfStream = true; + } + return moreData; + } + + + /** + * Read an AJP message. + * + * @param first is true if the message is the first in the request, which + * will cause a short duration blocking read + * @return true if the message has been read, false if the short read + * didn't return anything + * @throws IOException any other failure, including incomplete reads + */ + protected boolean readMessage(AjpMessage message, boolean first, + boolean useAvailableData) + throws IOException { + + byte[] buf = message.getBuffer(); + int headerLength = message.getHeaderLength(); + + if (first) { + if (!readt(headerLength, useAvailableData)) { + return false; + } + } else { + read(headerLength); + } + inputBuffer.get(message.getBuffer(), 0, headerLength); + message.processHeader(); + read(message.getLen()); + inputBuffer.get(message.getBuffer(), headerLength, message.getLen()); + + return true; + + } + + + /** + * Recycle the processor. + */ + public void recycle() { + + // Recycle Request object + first = true; + endOfStream = false; + empty = true; + replay = false; + finished = false; + request.recycle(); + response.recycle(); + certificates.recycle(); + + inputBuffer.clear(); + inputBuffer.limit(0); + outputBuffer.clear(); + + } + + + /** + * Callback to write data from the buffer. + */ + protected void flush() + throws IOException { + if (outputBuffer.position() > 0) { + if (Socket.sendbb(socket, 0, outputBuffer.position()) < 0) { + throw new IOException(); + } + outputBuffer.clear(); + } + } + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class SocketInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (endOfStream) { + return -1; + } + if (first && req.getContentLength() > 0) { + // Handle special first-body-chunk + if (!receive()) { + return 0; + } + } else if (empty) { + if (!refillReadBuffer()) { + return -1; + } + } + ByteChunk bc = bodyBytes.getByteChunk(); + chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength()); + empty = true; + return chunk.getLength(); + + } + + } + + + // ----------------------------------- OutputStreamOutputBuffer Inner Class + + + /** + * This class is an output buffer which will write data to an output + * stream. + */ + protected class SocketOutputBuffer + implements OutputBuffer { + + + /** + * Write chunk. + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (!response.isCommitted()) { + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + } + } + + int len = chunk.getLength(); + // 4 - hardcoded, byte[] marshalling overhead + int chunkSize = Constants.MAX_SEND_SIZE; + int off = 0; + while (len > 0) { + int thisTime = len; + if (thisTime > chunkSize) { + thisTime = chunkSize; + } + len -= thisTime; + if (outputBuffer.position() + thisTime + + Constants.H_SIZE + 4 > outputBuffer.capacity()) { + flush(); + } + outputBuffer.put((byte) 0x41); + outputBuffer.put((byte) 0x42); + outputBuffer.putShort((short) (thisTime + 4)); + outputBuffer.put(Constants.JK_AJP13_SEND_BODY_CHUNK); + outputBuffer.putShort((short) thisTime); + outputBuffer.put(chunk.getBytes(), chunk.getOffset() + off, thisTime); + outputBuffer.put((byte) 0x00); + off += thisTime; + } + + return chunk.getLength(); + + } + + + } + + +} diff --git a/java/org/apache/coyote/ajp/AjpAprProtocol.java b/java/org/apache/coyote/ajp/AjpAprProtocol.java index 5670ecc7a..a0706a12b 100644 --- a/java/org/apache/coyote/ajp/AjpAprProtocol.java +++ b/java/org/apache/coyote/ajp/AjpAprProtocol.java @@ -1,538 +1,538 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.ajp; - -import java.net.InetAddress; -import java.net.URLEncoder; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.concurrent.Executor; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.RequestGroupInfo; -import org.apache.coyote.RequestInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.net.AprEndpoint; -import org.apache.tomcat.util.net.AprEndpoint.Handler; -import org.apache.tomcat.util.net.AprEndpoint.Handler.SocketState; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Abstract the protocol implementation, including threading, etc. - * Processor is single threaded and specific to stream-based protocols, - * will not fit Jk protocols like JNI. - * - * @author Remy Maucherat - * @author Costin Manolache - */ -public class AjpAprProtocol - implements ProtocolHandler, MBeanRegistration { - - - protected static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(AjpAprProtocol.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------ Constructor - - - public AjpAprProtocol() { - cHandler = new AjpConnectionHandler(this); - setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); - setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); - //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); - setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); - } - - - // ----------------------------------------------------- Instance Variables - - - protected ObjectName tpOname; - - - protected ObjectName rgOname; - - - /** - * Associated APR endpoint. - */ - protected AprEndpoint ep = new AprEndpoint(); - - - /** - * Configuration attributes. - */ - protected Hashtable attributes = new Hashtable(); - - - /** - * Should authentication be done in the native webserver layer, - * or in the Servlet container ? - */ - protected boolean tomcatAuthentication = true; - - - /** - * Required secret. - */ - protected String requiredSecret = null; - - - /** - * Adapter which will process the requests recieved by this endpoint. - */ - private Adapter adapter; - - - /** - * Connection handler for AJP. - */ - private AjpConnectionHandler cHandler; - - - // --------------------------------------------------------- Public Methods - - - /** - * Pass config info - */ - public void setAttribute(String name, Object value) { - if (log.isTraceEnabled()) { - log.trace(sm.getString("ajpprotocol.setattribute", name, value)); - } - attributes.put(name, value); - } - - public Object getAttribute(String key) { - if (log.isTraceEnabled()) { - log.trace(sm.getString("ajpprotocol.getattribute", key)); - } - return attributes.get(key); - } - - - public Iterator getAttributeNames() { - return attributes.keySet().iterator(); - } - - - /** - * Set a property. - */ - public void setProperty(String name, String value) { - setAttribute(name, value); - } - - - /** - * Get a property - */ - public String getProperty(String name) { - return (String) getAttribute(name); - } - - - /** - * The adapter, used to call the connector - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - - public Adapter getAdapter() { - return adapter; - } - - - /** Start the protocol - */ - public void init() throws Exception { - ep.setName(getName()); - ep.setHandler(cHandler); - ep.setUseSendfile(false); - - try { - ep.init(); - } catch (Exception ex) { - log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex); - throw ex; - } - if (log.isInfoEnabled()) { - log.info(sm.getString("ajpprotocol.init", getName())); - } - } - - - public void start() throws Exception { - if (this.domain != null ) { - try { - tpOname = new ObjectName - (domain + ":" + "type=ThreadPool,name=" + getName()); - Registry.getRegistry(null, null) - .registerComponent(ep, tpOname, null ); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - rgOname = new ObjectName - (domain + ":type=GlobalRequestProcessor,name=" + getName()); - Registry.getRegistry(null, null).registerComponent - (cHandler.global, rgOname, null); - } - - try { - ep.start(); - } catch (Exception ex) { - log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex); - throw ex; - } - if (log.isInfoEnabled()) - log.info(sm.getString("ajpprotocol.start", getName())); - } - - public void pause() throws Exception { - try { - ep.pause(); - } catch (Exception ex) { - log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex); - throw ex; - } - if (log.isInfoEnabled()) - log.info(sm.getString("ajpprotocol.pause", getName())); - } - - public void resume() throws Exception { - try { - ep.resume(); - } catch (Exception ex) { - log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex); - throw ex; - } - if (log.isInfoEnabled()) - log.info(sm.getString("ajpprotocol.resume", getName())); - } - - public void destroy() throws Exception { - if (log.isInfoEnabled()) - log.info(sm.getString("ajpprotocol.stop", getName())); - ep.destroy(); - if (tpOname!=null) - Registry.getRegistry(null, null).unregisterComponent(tpOname); - if (rgOname != null) - Registry.getRegistry(null, null).unregisterComponent(rgOname); - } - - - // * - public Executor getExecutor() { - return ep.getExecutor(); - } - - // * - public void setExecutor(Executor executor) { - ep.setExecutor(executor); - } - - public int getMaxThreads() { - return ep.getMaxThreads(); - } - - public void setMaxThreads(int maxThreads) { - ep.setMaxThreads(maxThreads); - setAttribute("maxThreads", "" + maxThreads); - } - - public void setThreadPriority(int threadPriority) { - ep.setThreadPriority(threadPriority); - setAttribute("threadPriority", "" + threadPriority); - } - - public int getThreadPriority() { - return ep.getThreadPriority(); - } - - - public int getBacklog() { - return ep.getBacklog(); - } - - - public void setBacklog( int i ) { - ep.setBacklog(i); - setAttribute("backlog", "" + i); - } - - - public int getPort() { - return ep.getPort(); - } - - - public void setPort( int port ) { - ep.setPort(port); - setAttribute("port", "" + port); - } - - - public boolean getUseSendfile() { - return ep.getUseSendfile(); - } - - - public void setUseSendfile(boolean useSendfile) { - // No sendfile for AJP - } - - - public InetAddress getAddress() { - return ep.getAddress(); - } - - - public void setAddress(InetAddress ia) { - ep.setAddress(ia); - setAttribute("address", "" + ia); - } - - - public String getName() { - String encodedAddr = ""; - if (getAddress() != null) { - encodedAddr = "" + getAddress(); - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) + "-"; - } - return ("ajp-" + encodedAddr + ep.getPort()); - } - - - public boolean getTcpNoDelay() { - return ep.getTcpNoDelay(); - } - - - public void setTcpNoDelay(boolean b) { - ep.setTcpNoDelay(b); - setAttribute("tcpNoDelay", "" + b); - } - - - public boolean getTomcatAuthentication() { - return tomcatAuthentication; - } - - - public void setTomcatAuthentication(boolean tomcatAuthentication) { - this.tomcatAuthentication = tomcatAuthentication; - } - - - public int getFirstReadTimeout() { - return ep.getFirstReadTimeout(); - } - - - public void setFirstReadTimeout(int i) { - ep.setFirstReadTimeout(i); - setAttribute("firstReadTimeout", "" + i); - } - - - public int getPollTime() { - return ep.getPollTime(); - } - - - public void setPollTime(int i) { - ep.setPollTime(i); - setAttribute("pollTime", "" + i); - } - - - public void setPollerSize(int i) { - ep.setPollerSize(i); - setAttribute("pollerSize", "" + i); - } - - - public int getPollerSize() { - return ep.getPollerSize(); - } - - - public int getSoLinger() { - return ep.getSoLinger(); - } - - - public void setSoLinger(int i) { - ep.setSoLinger(i); - setAttribute("soLinger", "" + i); - } - - - public int getSoTimeout() { - return ep.getSoTimeout(); - } - - - public void setSoTimeout( int i ) { - ep.setSoTimeout(i); - setAttribute("soTimeout", "" + i); - } - - - public void setRequiredSecret(String requiredSecret) { - this.requiredSecret = requiredSecret; - } - - - // -------------------------------------- AjpConnectionHandler Inner Class - - - protected static class AjpConnectionHandler implements Handler { - protected AjpAprProtocol proto; - protected static int count = 0; - protected RequestGroupInfo global=new RequestGroupInfo(); - protected ThreadLocal localProcessor = new ThreadLocal(); - - public AjpConnectionHandler(AjpAprProtocol proto) { - this.proto = proto; - } - - // FIXME: Support for this could be added in AJP as well - public SocketState event(long socket, boolean error) { - return SocketState.CLOSED; - } - - public SocketState process(long socket) { - AjpAprProcessor processor = null; - try { - processor = (AjpAprProcessor) localProcessor.get(); - if (processor == null) { - processor = new AjpAprProcessor(proto.ep); - processor.setAdapter(proto.adapter); - processor.setTomcatAuthentication(proto.tomcatAuthentication); - processor.setRequiredSecret(proto.requiredSecret); - localProcessor.set(processor); - if (proto.getDomain() != null) { - synchronized (this) { - try { - RequestInfo rp = processor.getRequest().getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName rpName = new ObjectName - (proto.getDomain() + ":type=RequestProcessor,worker=" - + proto.getName() + ",name=AjpRequest" + count++ ); - Registry.getRegistry(null, null) - .registerComponent(rp, rpName, null); - } catch (Exception ex) { - log.warn(sm.getString("ajpprotocol.request.register")); - } - } - } - } - - if (processor instanceof ActionHook) { - ((ActionHook) processor).action(ActionCode.ACTION_START, null); - } - - if (processor.process(socket)) { - return SocketState.OPEN; - } else { - return SocketState.CLOSED; - } - - } catch(java.net.SocketException e) { - // SocketExceptions are normal - AjpAprProtocol.log.debug - (sm.getString - ("ajpprotocol.proto.socketexception.debug"), e); - } catch (java.io.IOException e) { - // IOExceptions are normal - AjpAprProtocol.log.debug - (sm.getString - ("ajpprotocol.proto.ioexception.debug"), e); - } - // Future developers: if you discover any other - // rare-but-nonfatal exceptions, catch them here, and log as - // above. - catch (Throwable e) { - // any other exception or error is odd. Here we log it - // with "ERROR" level, so it will show up even on - // less-than-verbose logs. - AjpAprProtocol.log.error - (sm.getString("ajpprotocol.proto.error"), e); - } finally { - if (processor instanceof ActionHook) { - ((ActionHook) processor).action(ActionCode.ACTION_STOP, null); - } - } - return SocketState.CLOSED; - } - } - - - // -------------------- Various implementation classes -------------------- - - - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.ajp; + +import java.net.InetAddress; +import java.net.URLEncoder; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.concurrent.Executor; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.net.AprEndpoint; +import org.apache.tomcat.util.net.AprEndpoint.Handler; +import org.apache.tomcat.util.net.AprEndpoint.Handler.SocketState; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Abstract the protocol implementation, including threading, etc. + * Processor is single threaded and specific to stream-based protocols, + * will not fit Jk protocols like JNI. + * + * @author Remy Maucherat + * @author Costin Manolache + */ +public class AjpAprProtocol + implements ProtocolHandler, MBeanRegistration { + + + protected static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(AjpAprProtocol.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------ Constructor + + + public AjpAprProtocol() { + cHandler = new AjpConnectionHandler(this); + setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); + setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); + //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); + setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); + } + + + // ----------------------------------------------------- Instance Variables + + + protected ObjectName tpOname; + + + protected ObjectName rgOname; + + + /** + * Associated APR endpoint. + */ + protected AprEndpoint ep = new AprEndpoint(); + + + /** + * Configuration attributes. + */ + protected Hashtable attributes = new Hashtable(); + + + /** + * Should authentication be done in the native webserver layer, + * or in the Servlet container ? + */ + protected boolean tomcatAuthentication = true; + + + /** + * Required secret. + */ + protected String requiredSecret = null; + + + /** + * Adapter which will process the requests recieved by this endpoint. + */ + private Adapter adapter; + + + /** + * Connection handler for AJP. + */ + private AjpConnectionHandler cHandler; + + + // --------------------------------------------------------- Public Methods + + + /** + * Pass config info + */ + public void setAttribute(String name, Object value) { + if (log.isTraceEnabled()) { + log.trace(sm.getString("ajpprotocol.setattribute", name, value)); + } + attributes.put(name, value); + } + + public Object getAttribute(String key) { + if (log.isTraceEnabled()) { + log.trace(sm.getString("ajpprotocol.getattribute", key)); + } + return attributes.get(key); + } + + + public Iterator getAttributeNames() { + return attributes.keySet().iterator(); + } + + + /** + * Set a property. + */ + public void setProperty(String name, String value) { + setAttribute(name, value); + } + + + /** + * Get a property + */ + public String getProperty(String name) { + return (String) getAttribute(name); + } + + + /** + * The adapter, used to call the connector + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + + public Adapter getAdapter() { + return adapter; + } + + + /** Start the protocol + */ + public void init() throws Exception { + ep.setName(getName()); + ep.setHandler(cHandler); + ep.setUseSendfile(false); + + try { + ep.init(); + } catch (Exception ex) { + log.error(sm.getString("ajpprotocol.endpoint.initerror"), ex); + throw ex; + } + if (log.isInfoEnabled()) { + log.info(sm.getString("ajpprotocol.init", getName())); + } + } + + + public void start() throws Exception { + if (this.domain != null ) { + try { + tpOname = new ObjectName + (domain + ":" + "type=ThreadPool,name=" + getName()); + Registry.getRegistry(null, null) + .registerComponent(ep, tpOname, null ); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + rgOname = new ObjectName + (domain + ":type=GlobalRequestProcessor,name=" + getName()); + Registry.getRegistry(null, null).registerComponent + (cHandler.global, rgOname, null); + } + + try { + ep.start(); + } catch (Exception ex) { + log.error(sm.getString("ajpprotocol.endpoint.starterror"), ex); + throw ex; + } + if (log.isInfoEnabled()) + log.info(sm.getString("ajpprotocol.start", getName())); + } + + public void pause() throws Exception { + try { + ep.pause(); + } catch (Exception ex) { + log.error(sm.getString("ajpprotocol.endpoint.pauseerror"), ex); + throw ex; + } + if (log.isInfoEnabled()) + log.info(sm.getString("ajpprotocol.pause", getName())); + } + + public void resume() throws Exception { + try { + ep.resume(); + } catch (Exception ex) { + log.error(sm.getString("ajpprotocol.endpoint.resumeerror"), ex); + throw ex; + } + if (log.isInfoEnabled()) + log.info(sm.getString("ajpprotocol.resume", getName())); + } + + public void destroy() throws Exception { + if (log.isInfoEnabled()) + log.info(sm.getString("ajpprotocol.stop", getName())); + ep.destroy(); + if (tpOname!=null) + Registry.getRegistry(null, null).unregisterComponent(tpOname); + if (rgOname != null) + Registry.getRegistry(null, null).unregisterComponent(rgOname); + } + + + // * + public Executor getExecutor() { + return ep.getExecutor(); + } + + // * + public void setExecutor(Executor executor) { + ep.setExecutor(executor); + } + + public int getMaxThreads() { + return ep.getMaxThreads(); + } + + public void setMaxThreads(int maxThreads) { + ep.setMaxThreads(maxThreads); + setAttribute("maxThreads", "" + maxThreads); + } + + public void setThreadPriority(int threadPriority) { + ep.setThreadPriority(threadPriority); + setAttribute("threadPriority", "" + threadPriority); + } + + public int getThreadPriority() { + return ep.getThreadPriority(); + } + + + public int getBacklog() { + return ep.getBacklog(); + } + + + public void setBacklog( int i ) { + ep.setBacklog(i); + setAttribute("backlog", "" + i); + } + + + public int getPort() { + return ep.getPort(); + } + + + public void setPort( int port ) { + ep.setPort(port); + setAttribute("port", "" + port); + } + + + public boolean getUseSendfile() { + return ep.getUseSendfile(); + } + + + public void setUseSendfile(boolean useSendfile) { + // No sendfile for AJP + } + + + public InetAddress getAddress() { + return ep.getAddress(); + } + + + public void setAddress(InetAddress ia) { + ep.setAddress(ia); + setAttribute("address", "" + ia); + } + + + public String getName() { + String encodedAddr = ""; + if (getAddress() != null) { + encodedAddr = "" + getAddress(); + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) + "-"; + } + return ("ajp-" + encodedAddr + ep.getPort()); + } + + + public boolean getTcpNoDelay() { + return ep.getTcpNoDelay(); + } + + + public void setTcpNoDelay(boolean b) { + ep.setTcpNoDelay(b); + setAttribute("tcpNoDelay", "" + b); + } + + + public boolean getTomcatAuthentication() { + return tomcatAuthentication; + } + + + public void setTomcatAuthentication(boolean tomcatAuthentication) { + this.tomcatAuthentication = tomcatAuthentication; + } + + + public int getFirstReadTimeout() { + return ep.getFirstReadTimeout(); + } + + + public void setFirstReadTimeout(int i) { + ep.setFirstReadTimeout(i); + setAttribute("firstReadTimeout", "" + i); + } + + + public int getPollTime() { + return ep.getPollTime(); + } + + + public void setPollTime(int i) { + ep.setPollTime(i); + setAttribute("pollTime", "" + i); + } + + + public void setPollerSize(int i) { + ep.setPollerSize(i); + setAttribute("pollerSize", "" + i); + } + + + public int getPollerSize() { + return ep.getPollerSize(); + } + + + public int getSoLinger() { + return ep.getSoLinger(); + } + + + public void setSoLinger(int i) { + ep.setSoLinger(i); + setAttribute("soLinger", "" + i); + } + + + public int getSoTimeout() { + return ep.getSoTimeout(); + } + + + public void setSoTimeout( int i ) { + ep.setSoTimeout(i); + setAttribute("soTimeout", "" + i); + } + + + public void setRequiredSecret(String requiredSecret) { + this.requiredSecret = requiredSecret; + } + + + // -------------------------------------- AjpConnectionHandler Inner Class + + + protected static class AjpConnectionHandler implements Handler { + protected AjpAprProtocol proto; + protected static int count = 0; + protected RequestGroupInfo global=new RequestGroupInfo(); + protected ThreadLocal localProcessor = new ThreadLocal(); + + public AjpConnectionHandler(AjpAprProtocol proto) { + this.proto = proto; + } + + // FIXME: Support for this could be added in AJP as well + public SocketState event(long socket, boolean error) { + return SocketState.CLOSED; + } + + public SocketState process(long socket) { + AjpAprProcessor processor = null; + try { + processor = (AjpAprProcessor) localProcessor.get(); + if (processor == null) { + processor = new AjpAprProcessor(proto.ep); + processor.setAdapter(proto.adapter); + processor.setTomcatAuthentication(proto.tomcatAuthentication); + processor.setRequiredSecret(proto.requiredSecret); + localProcessor.set(processor); + if (proto.getDomain() != null) { + synchronized (this) { + try { + RequestInfo rp = processor.getRequest().getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName rpName = new ObjectName + (proto.getDomain() + ":type=RequestProcessor,worker=" + + proto.getName() + ",name=AjpRequest" + count++ ); + Registry.getRegistry(null, null) + .registerComponent(rp, rpName, null); + } catch (Exception ex) { + log.warn(sm.getString("ajpprotocol.request.register")); + } + } + } + } + + if (processor instanceof ActionHook) { + ((ActionHook) processor).action(ActionCode.ACTION_START, null); + } + + if (processor.process(socket)) { + return SocketState.OPEN; + } else { + return SocketState.CLOSED; + } + + } catch(java.net.SocketException e) { + // SocketExceptions are normal + AjpAprProtocol.log.debug + (sm.getString + ("ajpprotocol.proto.socketexception.debug"), e); + } catch (java.io.IOException e) { + // IOExceptions are normal + AjpAprProtocol.log.debug + (sm.getString + ("ajpprotocol.proto.ioexception.debug"), e); + } + // Future developers: if you discover any other + // rare-but-nonfatal exceptions, catch them here, and log as + // above. + catch (Throwable e) { + // any other exception or error is odd. Here we log it + // with "ERROR" level, so it will show up even on + // less-than-verbose logs. + AjpAprProtocol.log.error + (sm.getString("ajpprotocol.proto.error"), e); + } finally { + if (processor instanceof ActionHook) { + ((ActionHook) processor).action(ActionCode.ACTION_STOP, null); + } + } + return SocketState.CLOSED; + } + } + + + // -------------------- Various implementation classes -------------------- + + + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + +} diff --git a/java/org/apache/coyote/ajp/AjpMessage.java b/java/org/apache/coyote/ajp/AjpMessage.java index aef6be08e..71dbb3fd2 100644 --- a/java/org/apache/coyote/ajp/AjpMessage.java +++ b/java/org/apache/coyote/ajp/AjpMessage.java @@ -1,449 +1,449 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.ajp; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.res.StringManager; - -/** - * A single packet for communication between the web server and the - * container. Designed to be reused many times with no creation of - * garbage. Understands the format of data types for these packets. - * Can be used (somewhat confusingly) for both incoming and outgoing - * packets. - * - * @author Henri Gomez - * @author Dan Milstein - * @author Keith Wannamaker - * @author Kevin Seguin - * @author Costin Manolache - */ -public class AjpMessage { - - - protected static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(AjpMessage.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Fixed size buffer. - */ - protected byte buf[] = new byte[8 * 1024]; - - - /** - * The current read or write position in the buffer. - */ - protected int pos; - - - /** - * This actually means different things depending on whether the - * packet is read or write. For read, it's the length of the - * payload (excluding the header). For write, it's the length of - * the packet as a whole (counting the header). Oh, well. - */ - protected int len; - - - // --------------------------------------------------------- Public Methods - - - /** - * Prepare this packet for accumulating a message from the container to - * the web server. Set the write position to just after the header - * (but leave the length unwritten, because it is as yet unknown). - */ - public void reset() { - len = 4; - pos = 4; - } - - - /** - * For a packet to be sent to the web server, finish the process of - * accumulating data and write the length of the data payload into - * the header. - */ - public void end() { - len = pos; - int dLen = len - 4; - - buf[0] = (byte) 0x41; - buf[1] = (byte) 0x42; - buf[2] = (byte) ((dLen>>>8) & 0xFF); - buf[3] = (byte) (dLen & 0xFF); - } - - - /** - * Return the underlying byte buffer. - */ - public byte[] getBuffer() { - return buf; - } - - - /** - * Return the current message length. For read, it's the length of the - * payload (excluding the header). For write, it's the length of - * the packet as a whole (counting the header). - */ - public int getLen() { - return len; - } - - - /** - * Add a short integer (2 bytes) to the message. - */ - public void appendInt(int val) { - buf[pos++] = (byte) ((val >>> 8) & 0xFF); - buf[pos++] = (byte) (val & 0xFF); - } - - - /** - * Append a byte (1 byte) to the message. - */ - public void appendByte(int val) { - buf[pos++] = (byte) val; - } - - - /** - * Append an int (4 bytes) to the message. - */ - public void appendLongInt(int val) { - buf[pos++] = (byte) ((val >>> 24) & 0xFF); - buf[pos++] = (byte) ((val >>> 16) & 0xFF); - buf[pos++] = (byte) ((val >>> 8) & 0xFF); - buf[pos++] = (byte) (val & 0xFF); - } - - - /** - * Write a MessageBytes out at the current write position. - * A null MessageBytes is encoded as a string with length 0. - */ - public void appendBytes(MessageBytes mb) { - if (mb == null) { - log.error(sm.getString("ajpmessage.null"), - new NullPointerException()); - appendInt(0); - appendByte(0); - return; - } - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - appendByteChunk(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - CharChunk cc = mb.getCharChunk(); - appendCharChunk(cc); - } else { - appendString(mb.toString()); - } - } - - - /** - * Write a ByteChunk out at the current write position. - * A null ByteChunk is encoded as a string with length 0. - */ - public void appendByteChunk(ByteChunk bc) { - if (bc == null) { - log.error(sm.getString("ajpmessage.null"), - new NullPointerException()); - appendInt(0); - appendByte(0); - return; - } - appendBytes(bc.getBytes(), bc.getStart(), bc.getLength()); - } - - - /** - * Write a CharChunk out at the current write position. - * A null CharChunk is encoded as a string with length 0. - */ - public void appendCharChunk(CharChunk cc) { - if (cc == null) { - log.error(sm.getString("ajpmessage.null"), - new NullPointerException()); - appendInt(0); - appendByte(0); - return; - } - int start = cc.getStart(); - int end = cc.getEnd(); - appendInt(end - start); - char[] cbuf = cc.getBuffer(); - for (int i = start; i < end; i++) { - char c = cbuf[i]; - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - appendByte(c); - } - appendByte(0); - } - - - /** - * Write a String out at the current write position. Strings are - * encoded with the length in two bytes first, then the string, and - * then a terminating \0 (which is not included in the - * encoded length). The terminator is for the convenience of the C - * code, where it saves a round of copying. A null string is - * encoded as a string with length 0. - */ - public void appendString(String str) { - if (str == null) { - log.error(sm.getString("ajpmessage.null"), - new NullPointerException()); - appendInt(0); - appendByte(0); - return; - } - int len = str.length(); - appendInt(len); - for (int i = 0; i < len; i++) { - char c = str.charAt (i); - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - appendByte(c); - } - appendByte(0); - } - - - /** - * Copy a chunk of bytes into the packet, starting at the current - * write position. The chunk of bytes is encoded with the length - * in two bytes first, then the data itself, and finally a - * terminating \0 (which is not included in the encoded - * length). - * - * @param b The array from which to copy bytes. - * @param off The offset into the array at which to start copying - * @param numBytes The number of bytes to copy. - */ - public void appendBytes(byte[] b, int off, int numBytes) { - if (pos + numBytes + 3 >= buf.length) { - log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos), - new ArrayIndexOutOfBoundsException()); - if (log.isDebugEnabled()) { - dump("Overflow/coBytes"); - } - return; - } - appendInt(numBytes); - System.arraycopy(b, off, buf, pos, numBytes); - pos += numBytes; - appendByte(0); - } - - - /** - * Read an integer from packet, and advance the read position past - * it. Integers are encoded as two unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public int getInt() { - int b1 = buf[pos++] & 0xFF; - int b2 = buf[pos++] & 0xFF; - return (b1<<8) + b2; - } - - - public int peekInt() { - int b1 = buf[pos] & 0xFF; - int b2 = buf[pos+1] & 0xFF; - return (b1<<8) + b2; - } - - - public byte getByte() { - byte res = buf[pos++]; - return res; - } - - - public byte peekByte() { - byte res = buf[pos]; - return res; - } - - - public void getBytes(MessageBytes mb) { - int length = getInt(); - if ((length == 0xFFFF) || (length == -1)) { - mb.recycle(); - return; - } - mb.setBytes(buf, pos, length); - pos += length; - pos++; // Skip the terminating \0 - } - - - /** - * Copy a chunk of bytes from the packet into an array and advance - * the read position past the chunk. See appendBytes() for details - * on the encoding. - * - * @return The number of bytes copied. - */ - public int getBytes(byte[] dest) { - int length = getInt(); - if (pos + length > buf.length) { - log.error(sm.getString("ajpmessage.read", "" + length)); - return 0; - } - - if ((length == 0xFFFF) || (length == -1)) { - return 0; - } - - System.arraycopy(buf, pos, dest, 0, length); - pos += length; - pos++; // Skip terminating \0 - return length; - } - - - /** - * Read a 32 bits integer from packet, and advance the read position past - * it. Integers are encoded as four unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public int getLongInt() { - int b1 = buf[pos++] & 0xFF; // No swap, Java order - b1 <<= 8; - b1 |= (buf[pos++] & 0xFF); - b1 <<= 8; - b1 |= (buf[pos++] & 0xFF); - b1 <<=8; - b1 |= (buf[pos++] & 0xFF); - return b1; - } - - - public int getHeaderLength() { - return 4; - } - - - public int processHeader() { - pos = 0; - int mark = getInt(); - len = getInt(); - // Verify message signature - if ((mark != 0x1234) && (mark != 0x4142)) { - log.error(sm.getString("ajpmessage.invalid", "" + mark)); - if (log.isDebugEnabled()) { - dump("In: "); - } - return -1; - } - if (log.isDebugEnabled()) { - log.debug("Received " + len + " " + buf[0]); - } - return len; - } - - - /** - * Dump the contents of the message, prefixed with the given String. - */ - public void dump(String msg) { - if (log.isDebugEnabled()) { - log.debug(msg + ": " + buf + " " + pos +"/" + (len + 4)); - } - int max = pos; - if (len + 4 > pos) - max = len+4; - if (max > 1000) - max = 1000; - if (log.isDebugEnabled()) { - for (int j = 0; j < max; j += 16) { - log.debug(hexLine(buf, j, len)); - } - } - } - - - // ------------------------------------------------------ Protected Methods - - - protected static String hexLine(byte buf[], int start, int len) { - StringBuffer sb = new StringBuffer(); - for (int i = start; i < start + 16 ; i++) { - if (i < len + 4) { - sb.append(hex(buf[i]) + " "); - } else { - sb.append(" "); - } - } - sb.append(" | "); - for (int i = start; i < start + 16 && i < len + 4; i++) { - if (!Character.isISOControl((char) buf[i])) { - sb.append(new Character((char) buf[i])); - } else { - sb.append("."); - } - } - return sb.toString(); - } - - - protected static String hex(int x) { - String h = Integer.toHexString(x); - if (h.length() == 1) { - h = "0" + h; - } - return h.substring(h.length() - 2); - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.ajp; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.res.StringManager; + +/** + * A single packet for communication between the web server and the + * container. Designed to be reused many times with no creation of + * garbage. Understands the format of data types for these packets. + * Can be used (somewhat confusingly) for both incoming and outgoing + * packets. + * + * @author Henri Gomez + * @author Dan Milstein + * @author Keith Wannamaker + * @author Kevin Seguin + * @author Costin Manolache + */ +public class AjpMessage { + + + protected static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(AjpMessage.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Fixed size buffer. + */ + protected byte buf[] = new byte[8 * 1024]; + + + /** + * The current read or write position in the buffer. + */ + protected int pos; + + + /** + * This actually means different things depending on whether the + * packet is read or write. For read, it's the length of the + * payload (excluding the header). For write, it's the length of + * the packet as a whole (counting the header). Oh, well. + */ + protected int len; + + + // --------------------------------------------------------- Public Methods + + + /** + * Prepare this packet for accumulating a message from the container to + * the web server. Set the write position to just after the header + * (but leave the length unwritten, because it is as yet unknown). + */ + public void reset() { + len = 4; + pos = 4; + } + + + /** + * For a packet to be sent to the web server, finish the process of + * accumulating data and write the length of the data payload into + * the header. + */ + public void end() { + len = pos; + int dLen = len - 4; + + buf[0] = (byte) 0x41; + buf[1] = (byte) 0x42; + buf[2] = (byte) ((dLen>>>8) & 0xFF); + buf[3] = (byte) (dLen & 0xFF); + } + + + /** + * Return the underlying byte buffer. + */ + public byte[] getBuffer() { + return buf; + } + + + /** + * Return the current message length. For read, it's the length of the + * payload (excluding the header). For write, it's the length of + * the packet as a whole (counting the header). + */ + public int getLen() { + return len; + } + + + /** + * Add a short integer (2 bytes) to the message. + */ + public void appendInt(int val) { + buf[pos++] = (byte) ((val >>> 8) & 0xFF); + buf[pos++] = (byte) (val & 0xFF); + } + + + /** + * Append a byte (1 byte) to the message. + */ + public void appendByte(int val) { + buf[pos++] = (byte) val; + } + + + /** + * Append an int (4 bytes) to the message. + */ + public void appendLongInt(int val) { + buf[pos++] = (byte) ((val >>> 24) & 0xFF); + buf[pos++] = (byte) ((val >>> 16) & 0xFF); + buf[pos++] = (byte) ((val >>> 8) & 0xFF); + buf[pos++] = (byte) (val & 0xFF); + } + + + /** + * Write a MessageBytes out at the current write position. + * A null MessageBytes is encoded as a string with length 0. + */ + public void appendBytes(MessageBytes mb) { + if (mb == null) { + log.error(sm.getString("ajpmessage.null"), + new NullPointerException()); + appendInt(0); + appendByte(0); + return; + } + if (mb.getType() == MessageBytes.T_BYTES) { + ByteChunk bc = mb.getByteChunk(); + appendByteChunk(bc); + } else if (mb.getType() == MessageBytes.T_CHARS) { + CharChunk cc = mb.getCharChunk(); + appendCharChunk(cc); + } else { + appendString(mb.toString()); + } + } + + + /** + * Write a ByteChunk out at the current write position. + * A null ByteChunk is encoded as a string with length 0. + */ + public void appendByteChunk(ByteChunk bc) { + if (bc == null) { + log.error(sm.getString("ajpmessage.null"), + new NullPointerException()); + appendInt(0); + appendByte(0); + return; + } + appendBytes(bc.getBytes(), bc.getStart(), bc.getLength()); + } + + + /** + * Write a CharChunk out at the current write position. + * A null CharChunk is encoded as a string with length 0. + */ + public void appendCharChunk(CharChunk cc) { + if (cc == null) { + log.error(sm.getString("ajpmessage.null"), + new NullPointerException()); + appendInt(0); + appendByte(0); + return; + } + int start = cc.getStart(); + int end = cc.getEnd(); + appendInt(end - start); + char[] cbuf = cc.getBuffer(); + for (int i = start; i < end; i++) { + char c = cbuf[i]; + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + appendByte(c); + } + appendByte(0); + } + + + /** + * Write a String out at the current write position. Strings are + * encoded with the length in two bytes first, then the string, and + * then a terminating \0 (which is not included in the + * encoded length). The terminator is for the convenience of the C + * code, where it saves a round of copying. A null string is + * encoded as a string with length 0. + */ + public void appendString(String str) { + if (str == null) { + log.error(sm.getString("ajpmessage.null"), + new NullPointerException()); + appendInt(0); + appendByte(0); + return; + } + int len = str.length(); + appendInt(len); + for (int i = 0; i < len; i++) { + char c = str.charAt (i); + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + appendByte(c); + } + appendByte(0); + } + + + /** + * Copy a chunk of bytes into the packet, starting at the current + * write position. The chunk of bytes is encoded with the length + * in two bytes first, then the data itself, and finally a + * terminating \0 (which is not included in the encoded + * length). + * + * @param b The array from which to copy bytes. + * @param off The offset into the array at which to start copying + * @param numBytes The number of bytes to copy. + */ + public void appendBytes(byte[] b, int off, int numBytes) { + if (pos + numBytes + 3 >= buf.length) { + log.error(sm.getString("ajpmessage.overflow", "" + numBytes, "" + pos), + new ArrayIndexOutOfBoundsException()); + if (log.isDebugEnabled()) { + dump("Overflow/coBytes"); + } + return; + } + appendInt(numBytes); + System.arraycopy(b, off, buf, pos, numBytes); + pos += numBytes; + appendByte(0); + } + + + /** + * Read an integer from packet, and advance the read position past + * it. Integers are encoded as two unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public int getInt() { + int b1 = buf[pos++] & 0xFF; + int b2 = buf[pos++] & 0xFF; + return (b1<<8) + b2; + } + + + public int peekInt() { + int b1 = buf[pos] & 0xFF; + int b2 = buf[pos+1] & 0xFF; + return (b1<<8) + b2; + } + + + public byte getByte() { + byte res = buf[pos++]; + return res; + } + + + public byte peekByte() { + byte res = buf[pos]; + return res; + } + + + public void getBytes(MessageBytes mb) { + int length = getInt(); + if ((length == 0xFFFF) || (length == -1)) { + mb.recycle(); + return; + } + mb.setBytes(buf, pos, length); + pos += length; + pos++; // Skip the terminating \0 + } + + + /** + * Copy a chunk of bytes from the packet into an array and advance + * the read position past the chunk. See appendBytes() for details + * on the encoding. + * + * @return The number of bytes copied. + */ + public int getBytes(byte[] dest) { + int length = getInt(); + if (pos + length > buf.length) { + log.error(sm.getString("ajpmessage.read", "" + length)); + return 0; + } + + if ((length == 0xFFFF) || (length == -1)) { + return 0; + } + + System.arraycopy(buf, pos, dest, 0, length); + pos += length; + pos++; // Skip terminating \0 + return length; + } + + + /** + * Read a 32 bits integer from packet, and advance the read position past + * it. Integers are encoded as four unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public int getLongInt() { + int b1 = buf[pos++] & 0xFF; // No swap, Java order + b1 <<= 8; + b1 |= (buf[pos++] & 0xFF); + b1 <<= 8; + b1 |= (buf[pos++] & 0xFF); + b1 <<=8; + b1 |= (buf[pos++] & 0xFF); + return b1; + } + + + public int getHeaderLength() { + return 4; + } + + + public int processHeader() { + pos = 0; + int mark = getInt(); + len = getInt(); + // Verify message signature + if ((mark != 0x1234) && (mark != 0x4142)) { + log.error(sm.getString("ajpmessage.invalid", "" + mark)); + if (log.isDebugEnabled()) { + dump("In: "); + } + return -1; + } + if (log.isDebugEnabled()) { + log.debug("Received " + len + " " + buf[0]); + } + return len; + } + + + /** + * Dump the contents of the message, prefixed with the given String. + */ + public void dump(String msg) { + if (log.isDebugEnabled()) { + log.debug(msg + ": " + buf + " " + pos +"/" + (len + 4)); + } + int max = pos; + if (len + 4 > pos) + max = len+4; + if (max > 1000) + max = 1000; + if (log.isDebugEnabled()) { + for (int j = 0; j < max; j += 16) { + log.debug(hexLine(buf, j, len)); + } + } + } + + + // ------------------------------------------------------ Protected Methods + + + protected static String hexLine(byte buf[], int start, int len) { + StringBuffer sb = new StringBuffer(); + for (int i = start; i < start + 16 ; i++) { + if (i < len + 4) { + sb.append(hex(buf[i]) + " "); + } else { + sb.append(" "); + } + } + sb.append(" | "); + for (int i = start; i < start + 16 && i < len + 4; i++) { + if (!Character.isISOControl((char) buf[i])) { + sb.append(new Character((char) buf[i])); + } else { + sb.append("."); + } + } + return sb.toString(); + } + + + protected static String hex(int x) { + String h = Integer.toHexString(x); + if (h.length() == 1) { + h = "0" + h; + } + return h.substring(h.length() - 2); + } + + +} diff --git a/java/org/apache/coyote/ajp/Constants.java b/java/org/apache/coyote/ajp/Constants.java index 676989e95..077ee372a 100644 --- a/java/org/apache/coyote/ajp/Constants.java +++ b/java/org/apache/coyote/ajp/Constants.java @@ -1,337 +1,337 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.ajp; - -import org.apache.tomcat.util.buf.ByteChunk; - - -/** - * Constants. - * - * @author Remy Maucherat - */ -public final class Constants { - - - // -------------------------------------------------------------- Constants - - - /** - * Package name. - */ - public static final String Package = "org.apache.coyote.ajp"; - - public static final int DEFAULT_CONNECTION_LINGER = -1; - public static final int DEFAULT_CONNECTION_TIMEOUT = -1; - public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; - public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; - public static final boolean DEFAULT_TCP_NO_DELAY = true; - - // Prefix codes for message types from server to container - public static final byte JK_AJP13_FORWARD_REQUEST = 2; - public static final byte JK_AJP13_SHUTDOWN = 7; - public static final byte JK_AJP13_PING_REQUEST = 8; - public static final byte JK_AJP13_CPING_REQUEST = 10; - - // Prefix codes for message types from container to server - public static final byte JK_AJP13_SEND_BODY_CHUNK = 3; - public static final byte JK_AJP13_SEND_HEADERS = 4; - public static final byte JK_AJP13_END_RESPONSE = 5; - public static final byte JK_AJP13_GET_BODY_CHUNK = 6; - public static final byte JK_AJP13_CPONG_REPLY = 9; - - // Integer codes for common response header strings - public static final int SC_RESP_CONTENT_TYPE = 0xA001; - public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002; - public static final int SC_RESP_CONTENT_LENGTH = 0xA003; - public static final int SC_RESP_DATE = 0xA004; - public static final int SC_RESP_LAST_MODIFIED = 0xA005; - public static final int SC_RESP_LOCATION = 0xA006; - public static final int SC_RESP_SET_COOKIE = 0xA007; - public static final int SC_RESP_SET_COOKIE2 = 0xA008; - public static final int SC_RESP_SERVLET_ENGINE = 0xA009; - public static final int SC_RESP_STATUS = 0xA00A; - public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B; - - // Integer codes for common (optional) request attribute names - public static final byte SC_A_CONTEXT = 1; // XXX Unused - public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused - public static final byte SC_A_REMOTE_USER = 3; - public static final byte SC_A_AUTH_TYPE = 4; - public static final byte SC_A_QUERY_STRING = 5; - public static final byte SC_A_JVM_ROUTE = 6; - public static final byte SC_A_SSL_CERT = 7; - public static final byte SC_A_SSL_CIPHER = 8; - public static final byte SC_A_SSL_SESSION = 9; - public static final byte SC_A_SSL_KEYSIZE = 11; - public static final byte SC_A_SECRET = 12; - public static final byte SC_A_STORED_METHOD = 13; - - // Used for attributes which are not in the list above - public static final byte SC_A_REQ_ATTRIBUTE = 10; - - // Terminates list of attributes - public static final byte SC_A_ARE_DONE = (byte)0xFF; - - // Ajp13 specific - needs refactoring for the new model - /** - * Maximum Total byte size for a AJP packet - */ - public static final int MAX_PACKET_SIZE = 8192; - /** - * Size of basic packet header - */ - public static final int H_SIZE = 4; - /** - * Maximum size of data that can be sent in one packet - */ - public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2; - public static final int MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4; - - // Translates integer codes to names of HTTP methods - public static final String []methodTransArray = { - "OPTIONS", - "GET", - "HEAD", - "POST", - "PUT", - "DELETE", - "TRACE", - "PROPFIND", - "PROPPATCH", - "MKCOL", - "COPY", - "MOVE", - "LOCK", - "UNLOCK", - "ACL", - "REPORT", - "VERSION-CONTROL", - "CHECKIN", - "CHECKOUT", - "UNCHECKOUT", - "SEARCH", - "MKWORKSPACE", - "UPDATE", - "LABEL", - "MERGE", - "BASELINE-CONTROL", - "MKACTIVITY" - }; - public static final int SC_M_JK_STORED = (byte) 0xFF; - - // id's for common request headers - public static final int SC_REQ_ACCEPT = 1; - public static final int SC_REQ_ACCEPT_CHARSET = 2; - public static final int SC_REQ_ACCEPT_ENCODING = 3; - public static final int SC_REQ_ACCEPT_LANGUAGE = 4; - public static final int SC_REQ_AUTHORIZATION = 5; - public static final int SC_REQ_CONNECTION = 6; - public static final int SC_REQ_CONTENT_TYPE = 7; - public static final int SC_REQ_CONTENT_LENGTH = 8; - public static final int SC_REQ_COOKIE = 9; - public static final int SC_REQ_COOKIE2 = 10; - public static final int SC_REQ_HOST = 11; - public static final int SC_REQ_PRAGMA = 12; - public static final int SC_REQ_REFERER = 13; - public static final int SC_REQ_USER_AGENT = 14; - // AJP14 new header - public static final byte SC_A_SSL_KEY_SIZE = 11; // XXX ??? - - // Translates integer codes to request header names - public static final String []headerTransArray = { - "accept", - "accept-charset", - "accept-encoding", - "accept-language", - "authorization", - "connection", - "content-type", - "content-length", - "cookie", - "cookie2", - "host", - "pragma", - "referer", - "user-agent" - }; - - - /** - * CRLF. - */ - public static final String CRLF = "\r\n"; - - - /** - * Server string. - */ - public static final byte[] SERVER_BYTES = - ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); - - - /** - * CR. - */ - public static final byte CR = (byte) '\r'; - - - /** - * LF. - */ - public static final byte LF = (byte) '\n'; - - - /** - * SP. - */ - public static final byte SP = (byte) ' '; - - - /** - * HT. - */ - public static final byte HT = (byte) '\t'; - - - /** - * COLON. - */ - public static final byte COLON = (byte) ':'; - - - /** - * 'A'. - */ - public static final byte A = (byte) 'A'; - - - /** - * 'a'. - */ - public static final byte a = (byte) 'a'; - - - /** - * 'Z'. - */ - public static final byte Z = (byte) 'Z'; - - - /** - * '?'. - */ - public static final byte QUESTION = (byte) '?'; - - - /** - * Lower case offset. - */ - public static final byte LC_OFFSET = A - a; - - - /** - * Default HTTP header buffer size. - */ - public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024; - - - /* Various constant "strings" */ - public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF); - public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": "); - public static final String CONNECTION = "Connection"; - public static final String CLOSE = "close"; - public static final byte[] CLOSE_BYTES = - ByteChunk.convertToBytes(CLOSE); - public static final String KEEPALIVE = "keep-alive"; - public static final byte[] KEEPALIVE_BYTES = - ByteChunk.convertToBytes(KEEPALIVE); - public static final String CHUNKED = "chunked"; - public static final byte[] ACK_BYTES = - ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); - public static final String TRANSFERENCODING = "Transfer-Encoding"; - public static final byte[] _200_BYTES = - ByteChunk.convertToBytes("200"); - public static final byte[] _400_BYTES = - ByteChunk.convertToBytes("400"); - public static final byte[] _404_BYTES = - ByteChunk.convertToBytes("404"); - - - /** - * Identity filters (input and output). - */ - public static final int IDENTITY_FILTER = 0; - - - /** - * Chunked filters (input and output). - */ - public static final int CHUNKED_FILTER = 1; - - - /** - * Void filters (input and output). - */ - public static final int VOID_FILTER = 2; - - - /** - * GZIP filter (output). - */ - public static final int GZIP_FILTER = 3; - - - /** - * Buffered filter (input) - */ - public static final int BUFFERED_FILTER = 3; - - - /** - * HTTP/1.0. - */ - public static final String HTTP_10 = "HTTP/1.0"; - - - /** - * HTTP/1.1. - */ - public static final String HTTP_11 = "HTTP/1.1"; - public static final byte[] HTTP_11_BYTES = - ByteChunk.convertToBytes(HTTP_11); - - - /** - * GET. - */ - public static final String GET = "GET"; - - - /** - * HEAD. - */ - public static final String HEAD = "HEAD"; - - - /** - * POST. - */ - public static final String POST = "POST"; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.ajp; + +import org.apache.tomcat.util.buf.ByteChunk; + + +/** + * Constants. + * + * @author Remy Maucherat + */ +public final class Constants { + + + // -------------------------------------------------------------- Constants + + + /** + * Package name. + */ + public static final String Package = "org.apache.coyote.ajp"; + + public static final int DEFAULT_CONNECTION_LINGER = -1; + public static final int DEFAULT_CONNECTION_TIMEOUT = -1; + public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; + public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; + public static final boolean DEFAULT_TCP_NO_DELAY = true; + + // Prefix codes for message types from server to container + public static final byte JK_AJP13_FORWARD_REQUEST = 2; + public static final byte JK_AJP13_SHUTDOWN = 7; + public static final byte JK_AJP13_PING_REQUEST = 8; + public static final byte JK_AJP13_CPING_REQUEST = 10; + + // Prefix codes for message types from container to server + public static final byte JK_AJP13_SEND_BODY_CHUNK = 3; + public static final byte JK_AJP13_SEND_HEADERS = 4; + public static final byte JK_AJP13_END_RESPONSE = 5; + public static final byte JK_AJP13_GET_BODY_CHUNK = 6; + public static final byte JK_AJP13_CPONG_REPLY = 9; + + // Integer codes for common response header strings + public static final int SC_RESP_CONTENT_TYPE = 0xA001; + public static final int SC_RESP_CONTENT_LANGUAGE = 0xA002; + public static final int SC_RESP_CONTENT_LENGTH = 0xA003; + public static final int SC_RESP_DATE = 0xA004; + public static final int SC_RESP_LAST_MODIFIED = 0xA005; + public static final int SC_RESP_LOCATION = 0xA006; + public static final int SC_RESP_SET_COOKIE = 0xA007; + public static final int SC_RESP_SET_COOKIE2 = 0xA008; + public static final int SC_RESP_SERVLET_ENGINE = 0xA009; + public static final int SC_RESP_STATUS = 0xA00A; + public static final int SC_RESP_WWW_AUTHENTICATE = 0xA00B; + + // Integer codes for common (optional) request attribute names + public static final byte SC_A_CONTEXT = 1; // XXX Unused + public static final byte SC_A_SERVLET_PATH = 2; // XXX Unused + public static final byte SC_A_REMOTE_USER = 3; + public static final byte SC_A_AUTH_TYPE = 4; + public static final byte SC_A_QUERY_STRING = 5; + public static final byte SC_A_JVM_ROUTE = 6; + public static final byte SC_A_SSL_CERT = 7; + public static final byte SC_A_SSL_CIPHER = 8; + public static final byte SC_A_SSL_SESSION = 9; + public static final byte SC_A_SSL_KEYSIZE = 11; + public static final byte SC_A_SECRET = 12; + public static final byte SC_A_STORED_METHOD = 13; + + // Used for attributes which are not in the list above + public static final byte SC_A_REQ_ATTRIBUTE = 10; + + // Terminates list of attributes + public static final byte SC_A_ARE_DONE = (byte)0xFF; + + // Ajp13 specific - needs refactoring for the new model + /** + * Maximum Total byte size for a AJP packet + */ + public static final int MAX_PACKET_SIZE = 8192; + /** + * Size of basic packet header + */ + public static final int H_SIZE = 4; + /** + * Maximum size of data that can be sent in one packet + */ + public static final int MAX_READ_SIZE = MAX_PACKET_SIZE - H_SIZE - 2; + public static final int MAX_SEND_SIZE = MAX_PACKET_SIZE - H_SIZE - 4; + + // Translates integer codes to names of HTTP methods + public static final String []methodTransArray = { + "OPTIONS", + "GET", + "HEAD", + "POST", + "PUT", + "DELETE", + "TRACE", + "PROPFIND", + "PROPPATCH", + "MKCOL", + "COPY", + "MOVE", + "LOCK", + "UNLOCK", + "ACL", + "REPORT", + "VERSION-CONTROL", + "CHECKIN", + "CHECKOUT", + "UNCHECKOUT", + "SEARCH", + "MKWORKSPACE", + "UPDATE", + "LABEL", + "MERGE", + "BASELINE-CONTROL", + "MKACTIVITY" + }; + public static final int SC_M_JK_STORED = (byte) 0xFF; + + // id's for common request headers + public static final int SC_REQ_ACCEPT = 1; + public static final int SC_REQ_ACCEPT_CHARSET = 2; + public static final int SC_REQ_ACCEPT_ENCODING = 3; + public static final int SC_REQ_ACCEPT_LANGUAGE = 4; + public static final int SC_REQ_AUTHORIZATION = 5; + public static final int SC_REQ_CONNECTION = 6; + public static final int SC_REQ_CONTENT_TYPE = 7; + public static final int SC_REQ_CONTENT_LENGTH = 8; + public static final int SC_REQ_COOKIE = 9; + public static final int SC_REQ_COOKIE2 = 10; + public static final int SC_REQ_HOST = 11; + public static final int SC_REQ_PRAGMA = 12; + public static final int SC_REQ_REFERER = 13; + public static final int SC_REQ_USER_AGENT = 14; + // AJP14 new header + public static final byte SC_A_SSL_KEY_SIZE = 11; // XXX ??? + + // Translates integer codes to request header names + public static final String []headerTransArray = { + "accept", + "accept-charset", + "accept-encoding", + "accept-language", + "authorization", + "connection", + "content-type", + "content-length", + "cookie", + "cookie2", + "host", + "pragma", + "referer", + "user-agent" + }; + + + /** + * CRLF. + */ + public static final String CRLF = "\r\n"; + + + /** + * Server string. + */ + public static final byte[] SERVER_BYTES = + ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); + + + /** + * CR. + */ + public static final byte CR = (byte) '\r'; + + + /** + * LF. + */ + public static final byte LF = (byte) '\n'; + + + /** + * SP. + */ + public static final byte SP = (byte) ' '; + + + /** + * HT. + */ + public static final byte HT = (byte) '\t'; + + + /** + * COLON. + */ + public static final byte COLON = (byte) ':'; + + + /** + * 'A'. + */ + public static final byte A = (byte) 'A'; + + + /** + * 'a'. + */ + public static final byte a = (byte) 'a'; + + + /** + * 'Z'. + */ + public static final byte Z = (byte) 'Z'; + + + /** + * '?'. + */ + public static final byte QUESTION = (byte) '?'; + + + /** + * Lower case offset. + */ + public static final byte LC_OFFSET = A - a; + + + /** + * Default HTTP header buffer size. + */ + public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024; + + + /* Various constant "strings" */ + public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF); + public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": "); + public static final String CONNECTION = "Connection"; + public static final String CLOSE = "close"; + public static final byte[] CLOSE_BYTES = + ByteChunk.convertToBytes(CLOSE); + public static final String KEEPALIVE = "keep-alive"; + public static final byte[] KEEPALIVE_BYTES = + ByteChunk.convertToBytes(KEEPALIVE); + public static final String CHUNKED = "chunked"; + public static final byte[] ACK_BYTES = + ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); + public static final String TRANSFERENCODING = "Transfer-Encoding"; + public static final byte[] _200_BYTES = + ByteChunk.convertToBytes("200"); + public static final byte[] _400_BYTES = + ByteChunk.convertToBytes("400"); + public static final byte[] _404_BYTES = + ByteChunk.convertToBytes("404"); + + + /** + * Identity filters (input and output). + */ + public static final int IDENTITY_FILTER = 0; + + + /** + * Chunked filters (input and output). + */ + public static final int CHUNKED_FILTER = 1; + + + /** + * Void filters (input and output). + */ + public static final int VOID_FILTER = 2; + + + /** + * GZIP filter (output). + */ + public static final int GZIP_FILTER = 3; + + + /** + * Buffered filter (input) + */ + public static final int BUFFERED_FILTER = 3; + + + /** + * HTTP/1.0. + */ + public static final String HTTP_10 = "HTTP/1.0"; + + + /** + * HTTP/1.1. + */ + public static final String HTTP_11 = "HTTP/1.1"; + public static final byte[] HTTP_11_BYTES = + ByteChunk.convertToBytes(HTTP_11); + + + /** + * GET. + */ + public static final String GET = "GET"; + + + /** + * HEAD. + */ + public static final String HEAD = "HEAD"; + + + /** + * POST. + */ + public static final String POST = "POST"; + + +} diff --git a/java/org/apache/coyote/ajp/LocalStrings.properties b/java/org/apache/coyote/ajp/LocalStrings.properties index f477ccd1e..c175a8209 100644 --- a/java/org/apache/coyote/ajp/LocalStrings.properties +++ b/java/org/apache/coyote/ajp/LocalStrings.properties @@ -1,37 +1,37 @@ -# $Id: LocalStrings.properties 301021 2005-08-01 10:00:59Z remm $ - -# language - -# package org.apache.coyote.ajp - -# -# AjpAprProtocol -# - -ajpprotocol.endpoint.initerror=Error initializing endpoint -ajpprotocol.endpoint.starterror=Error starting endpoint -ajpprotocol.init=Initializing Coyote AJP/1.3 on {0} -ajpprotocol.proto.error=Error reading request, ignored -ajpprotocol.getattribute=Attribute {0} -ajpprotocol.setattribute=Attribute {0}: {1} -ajpprotocol.start=Starting Coyote AJP/1.3 on {0} -ajpprotocol.stop=Stopping Coyote AJP/1.3 on {0} -ajpprotocol.pause=Pausing Coyote AJP/1.3 on {0} -ajpprotocol.endpoint.pauseerror=Error pausing endpoint -ajpprotocol.resume=Resuming Coyote AJP/1.3 on {0} -ajpprotocol.endpoint.resumeerror=Error resuming endpoint -ajpprotocol.failedread=Socket read failed -ajpprotocol.failedwrite=Socket write failed -ajpprotocol.request.register=Error registering request processor in JMX - -ajpprocessor.header.error=Header message parsing failed -ajpprocessor.request.prepare=Error preparing request -ajpprocessor.request.process=Error processing request -ajpprocessor.certs.fail=Certificate convertion failed -ajpprocessor.socket.info=Exception getting socket information - -ajpmessage.null=Cannot append null value -ajpmessage.overflow=Overflow error for buffer adding {0} bytes at position {1} -ajpmessage.read=Requested {0} bytes exceeds message available data -ajpmessage.invalid=Invalid message recieved with signature {0} - +# $Id: LocalStrings.properties 301021 2005-08-01 10:00:59Z remm $ + +# language + +# package org.apache.coyote.ajp + +# +# AjpAprProtocol +# + +ajpprotocol.endpoint.initerror=Error initializing endpoint +ajpprotocol.endpoint.starterror=Error starting endpoint +ajpprotocol.init=Initializing Coyote AJP/1.3 on {0} +ajpprotocol.proto.error=Error reading request, ignored +ajpprotocol.getattribute=Attribute {0} +ajpprotocol.setattribute=Attribute {0}: {1} +ajpprotocol.start=Starting Coyote AJP/1.3 on {0} +ajpprotocol.stop=Stopping Coyote AJP/1.3 on {0} +ajpprotocol.pause=Pausing Coyote AJP/1.3 on {0} +ajpprotocol.endpoint.pauseerror=Error pausing endpoint +ajpprotocol.resume=Resuming Coyote AJP/1.3 on {0} +ajpprotocol.endpoint.resumeerror=Error resuming endpoint +ajpprotocol.failedread=Socket read failed +ajpprotocol.failedwrite=Socket write failed +ajpprotocol.request.register=Error registering request processor in JMX + +ajpprocessor.header.error=Header message parsing failed +ajpprocessor.request.prepare=Error preparing request +ajpprocessor.request.process=Error processing request +ajpprocessor.certs.fail=Certificate convertion failed +ajpprocessor.socket.info=Exception getting socket information + +ajpmessage.null=Cannot append null value +ajpmessage.overflow=Overflow error for buffer adding {0} bytes at position {1} +ajpmessage.read=Requested {0} bytes exceeds message available data +ajpmessage.invalid=Invalid message recieved with signature {0} + diff --git a/java/org/apache/coyote/http11/Constants.java b/java/org/apache/coyote/http11/Constants.java index 3a5ee857a..46dde8332 100644 --- a/java/org/apache/coyote/http11/Constants.java +++ b/java/org/apache/coyote/http11/Constants.java @@ -1,214 +1,214 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import org.apache.tomcat.util.buf.ByteChunk; - - -/** - * Constants. - * - * @author Remy Maucherat - */ -public final class Constants { - - - // -------------------------------------------------------------- Constants - - - /** - * Package name. - */ - public static final String Package = "org.apache.coyote.http11"; - - public static final int DEFAULT_CONNECTION_LINGER = -1; - public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; - public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; - public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; - public static final boolean DEFAULT_TCP_NO_DELAY = true; - - - /** - * CRLF. - */ - public static final String CRLF = "\r\n"; - - - /** - * Server string. - */ - public static final byte[] SERVER_BYTES = - ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); - - - /** - * CR. - */ - public static final byte CR = (byte) '\r'; - - - /** - * LF. - */ - public static final byte LF = (byte) '\n'; - - - /** - * SP. - */ - public static final byte SP = (byte) ' '; - - - /** - * HT. - */ - public static final byte HT = (byte) '\t'; - - - /** - * COLON. - */ - public static final byte COLON = (byte) ':'; - - /** - * SEMI_COLON. - */ - public static final byte SEMI_COLON = (byte) ';'; - - - - /** - * 'A'. - */ - public static final byte A = (byte) 'A'; - - - /** - * 'a'. - */ - public static final byte a = (byte) 'a'; - - - /** - * 'Z'. - */ - public static final byte Z = (byte) 'Z'; - - - /** - * '?'. - */ - public static final byte QUESTION = (byte) '?'; - - - /** - * Lower case offset. - */ - public static final byte LC_OFFSET = A - a; - - - /** - * Default HTTP header buffer size. - */ - public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024; - - - /* Various constant "strings" */ - public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF); - public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": "); - public static final String CONNECTION = "Connection"; - public static final String CLOSE = "close"; - public static final byte[] CLOSE_BYTES = - ByteChunk.convertToBytes(CLOSE); - public static final String KEEPALIVE = "keep-alive"; - public static final byte[] KEEPALIVE_BYTES = - ByteChunk.convertToBytes(KEEPALIVE); - public static final String CHUNKED = "chunked"; - public static final byte[] ACK_BYTES = - ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); - public static final String TRANSFERENCODING = "Transfer-Encoding"; - public static final byte[] _200_BYTES = - ByteChunk.convertToBytes("200"); - public static final byte[] _400_BYTES = - ByteChunk.convertToBytes("400"); - public static final byte[] _404_BYTES = - ByteChunk.convertToBytes("404"); - - - /** - * Identity filters (input and output). - */ - public static final int IDENTITY_FILTER = 0; - - - /** - * Chunked filters (input and output). - */ - public static final int CHUNKED_FILTER = 1; - - - /** - * Void filters (input and output). - */ - public static final int VOID_FILTER = 2; - - - /** - * GZIP filter (output). - */ - public static final int GZIP_FILTER = 3; - - - /** - * Buffered filter (input) - */ - public static final int BUFFERED_FILTER = 3; - - - /** - * HTTP/1.0. - */ - public static final String HTTP_10 = "HTTP/1.0"; - - - /** - * HTTP/1.1. - */ - public static final String HTTP_11 = "HTTP/1.1"; - public static final byte[] HTTP_11_BYTES = - ByteChunk.convertToBytes(HTTP_11); - - - /** - * GET. - */ - public static final String GET = "GET"; - - - /** - * HEAD. - */ - public static final String HEAD = "HEAD"; - - - /** - * POST. - */ - public static final String POST = "POST"; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import org.apache.tomcat.util.buf.ByteChunk; + + +/** + * Constants. + * + * @author Remy Maucherat + */ +public final class Constants { + + + // -------------------------------------------------------------- Constants + + + /** + * Package name. + */ + public static final String Package = "org.apache.coyote.http11"; + + public static final int DEFAULT_CONNECTION_LINGER = -1; + public static final int DEFAULT_CONNECTION_TIMEOUT = 60000; + public static final int DEFAULT_CONNECTION_UPLOAD_TIMEOUT = 300000; + public static final int DEFAULT_SERVER_SOCKET_TIMEOUT = 0; + public static final boolean DEFAULT_TCP_NO_DELAY = true; + + + /** + * CRLF. + */ + public static final String CRLF = "\r\n"; + + + /** + * Server string. + */ + public static final byte[] SERVER_BYTES = + ByteChunk.convertToBytes("Server: Apache-Coyote/1.1" + CRLF); + + + /** + * CR. + */ + public static final byte CR = (byte) '\r'; + + + /** + * LF. + */ + public static final byte LF = (byte) '\n'; + + + /** + * SP. + */ + public static final byte SP = (byte) ' '; + + + /** + * HT. + */ + public static final byte HT = (byte) '\t'; + + + /** + * COLON. + */ + public static final byte COLON = (byte) ':'; + + /** + * SEMI_COLON. + */ + public static final byte SEMI_COLON = (byte) ';'; + + + + /** + * 'A'. + */ + public static final byte A = (byte) 'A'; + + + /** + * 'a'. + */ + public static final byte a = (byte) 'a'; + + + /** + * 'Z'. + */ + public static final byte Z = (byte) 'Z'; + + + /** + * '?'. + */ + public static final byte QUESTION = (byte) '?'; + + + /** + * Lower case offset. + */ + public static final byte LC_OFFSET = A - a; + + + /** + * Default HTTP header buffer size. + */ + public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 48 * 1024; + + + /* Various constant "strings" */ + public static final byte[] CRLF_BYTES = ByteChunk.convertToBytes(CRLF); + public static final byte[] COLON_BYTES = ByteChunk.convertToBytes(": "); + public static final String CONNECTION = "Connection"; + public static final String CLOSE = "close"; + public static final byte[] CLOSE_BYTES = + ByteChunk.convertToBytes(CLOSE); + public static final String KEEPALIVE = "keep-alive"; + public static final byte[] KEEPALIVE_BYTES = + ByteChunk.convertToBytes(KEEPALIVE); + public static final String CHUNKED = "chunked"; + public static final byte[] ACK_BYTES = + ByteChunk.convertToBytes("HTTP/1.1 100 Continue" + CRLF + CRLF); + public static final String TRANSFERENCODING = "Transfer-Encoding"; + public static final byte[] _200_BYTES = + ByteChunk.convertToBytes("200"); + public static final byte[] _400_BYTES = + ByteChunk.convertToBytes("400"); + public static final byte[] _404_BYTES = + ByteChunk.convertToBytes("404"); + + + /** + * Identity filters (input and output). + */ + public static final int IDENTITY_FILTER = 0; + + + /** + * Chunked filters (input and output). + */ + public static final int CHUNKED_FILTER = 1; + + + /** + * Void filters (input and output). + */ + public static final int VOID_FILTER = 2; + + + /** + * GZIP filter (output). + */ + public static final int GZIP_FILTER = 3; + + + /** + * Buffered filter (input) + */ + public static final int BUFFERED_FILTER = 3; + + + /** + * HTTP/1.0. + */ + public static final String HTTP_10 = "HTTP/1.0"; + + + /** + * HTTP/1.1. + */ + public static final String HTTP_11 = "HTTP/1.1"; + public static final byte[] HTTP_11_BYTES = + ByteChunk.convertToBytes(HTTP_11); + + + /** + * GET. + */ + public static final String GET = "GET"; + + + /** + * HEAD. + */ + public static final String HEAD = "HEAD"; + + + /** + * POST. + */ + public static final String POST = "POST"; + + +} diff --git a/java/org/apache/coyote/http11/Http11AprProcessor.java b/java/org/apache/coyote/http11/Http11AprProcessor.java index 841e81fc9..961f39f0c 100644 --- a/java/org/apache/coyote/http11/Http11AprProcessor.java +++ b/java/org/apache/coyote/http11/Http11AprProcessor.java @@ -1,1804 +1,1804 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InterruptedIOException; -import java.util.StringTokenizer; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Response; -import org.apache.coyote.http11.filters.ChunkedInputFilter; -import org.apache.coyote.http11.filters.ChunkedOutputFilter; -import org.apache.coyote.http11.filters.GzipOutputFilter; -import org.apache.coyote.http11.filters.IdentityInputFilter; -import org.apache.coyote.http11.filters.IdentityOutputFilter; -import org.apache.coyote.http11.filters.SavedRequestInputFilter; -import org.apache.coyote.http11.filters.VoidInputFilter; -import org.apache.coyote.http11.filters.VoidOutputFilter; -import org.apache.coyote.http11.filters.BufferedInputFilter; -import org.apache.tomcat.jni.Address; -import org.apache.tomcat.jni.SSL; -import org.apache.tomcat.jni.SSLSocket; -import org.apache.tomcat.jni.Sockaddr; -import org.apache.tomcat.jni.Socket; -import org.apache.tomcat.util.buf.Ascii; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.net.AprEndpoint; -import org.apache.tomcat.util.net.AprEndpoint.Handler.SocketState; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Processes HTTP requests. - * - * @author Remy Maucherat - */ -public class Http11AprProcessor implements ActionHook { - - - /** - * Logger. - */ - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(Http11AprProcessor.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------------- Constructors - - - public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint) { - - this.endpoint = endpoint; - - request = new Request(); - int readTimeout = endpoint.getFirstReadTimeout(); - if (readTimeout == 0) { - readTimeout = 100; - } else if (readTimeout < 0) { - readTimeout = -1; - } - inputBuffer = new InternalAprInputBuffer(request, headerBufferSize, - readTimeout); - request.setInputBuffer(inputBuffer); - - response = new Response(); - response.setHook(this); - outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize); - response.setOutputBuffer(outputBuffer); - request.setResponse(response); - - ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine()); - - initializeFilters(); - - // Cause loading of HexUtils - int foo = HexUtils.DEC[0]; - - // Cause loading of FastHttpDateFormat - FastHttpDateFormat.getCurrentDate(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated adapter. - */ - protected Adapter adapter = null; - - - /** - * Request object. - */ - protected Request request = null; - - - /** - * Response object. - */ - protected Response response = null; - - - /** - * Input. - */ - protected InternalAprInputBuffer inputBuffer = null; - - - /** - * Output. - */ - protected InternalAprOutputBuffer outputBuffer = null; - - - /** - * Error flag. - */ - protected boolean error = false; - - - /** - * Keep-alive. - */ - protected boolean keepAlive = true; - - - /** - * HTTP/1.1 flag. - */ - protected boolean http11 = true; - - - /** - * HTTP/0.9 flag. - */ - protected boolean http09 = false; - - - /** - * Sendfile data. - */ - protected AprEndpoint.SendfileData sendfileData = null; - - - /** - * Comet used. - */ - protected boolean comet = false; - - - /** - * Content delimitator for the request (if false, the connection will - * be closed at the end of the request). - */ - protected boolean contentDelimitation = true; - - - /** - * Is there an expectation ? - */ - protected boolean expectation = false; - - - /** - * List of restricted user agents. - */ - protected Pattern[] restrictedUserAgents = null; - - - /** - * Maximum number of Keep-Alive requests to honor. - */ - protected int maxKeepAliveRequests = -1; - - - /** - * SSL enabled ? - */ - protected boolean ssl = false; - - - /** - * Socket associated with the current connection. - */ - protected long socket = 0; - - - /** - * Remote Address associated with the current connection. - */ - protected String remoteAddr = null; - - - /** - * Remote Host associated with the current connection. - */ - protected String remoteHost = null; - - - /** - * Local Host associated with the current connection. - */ - protected String localName = null; - - - - /** - * Local port to which the socket is connected - */ - protected int localPort = -1; - - - /** - * Remote port to which the socket is connected - */ - protected int remotePort = -1; - - - /** - * The local Host address. - */ - protected String localAddr = null; - - - /** - * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. - */ - protected int timeout = 300000; - - - /** - * Flag to disable setting a different time-out on uploads. - */ - protected boolean disableUploadTimeout = false; - - - /** - * Allowed compression level. - */ - protected int compressionLevel = 0; - - - /** - * Minimum contentsize to make compression. - */ - protected int compressionMinSize = 2048; - - - /** - * Socket buffering. - */ - protected int socketBuffer = -1; - - - /** - * Max save post size. - */ - protected int maxSavePostSize = 4 * 1024; - - - /** - * List of user agents to not use gzip with - */ - protected Pattern noCompressionUserAgents[] = null; - - /** - * List of MIMES which could be gzipped - */ - protected String[] compressableMimeTypes = - { "text/html", "text/xml", "text/plain" }; - - - /** - * Host name (used to avoid useless B2C conversion on the host name). - */ - protected char[] hostNameC = new char[0]; - - - /** - * Associated endpoint. - */ - protected AprEndpoint endpoint; - - - /** - * Allow a customized the server header for the tin-foil hat folks. - */ - protected String server = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return compression level. - */ - public String getCompression() { - switch (compressionLevel) { - case 0: - return "off"; - case 1: - return "on"; - case 2: - return "force"; - } - return "off"; - } - - - /** - * Set compression level. - */ - public void setCompression(String compression) { - if (compression.equals("on")) { - this.compressionLevel = 1; - } else if (compression.equals("force")) { - this.compressionLevel = 2; - } else if (compression.equals("off")) { - this.compressionLevel = 0; - } else { - try { - // Try to parse compression as an int, which would give the - // minimum compression size - compressionMinSize = Integer.parseInt(compression); - this.compressionLevel = 1; - } catch (Exception e) { - this.compressionLevel = 0; - } - } - } - - /** - * Set Minimum size to trigger compression. - */ - public void setCompressionMinSize(int compressionMinSize) { - this.compressionMinSize = compressionMinSize; - } - - - /** - * Add user-agent for which gzip compression didn't works - * The user agent String given will be exactly matched - * to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addNoCompressionUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - noCompressionUserAgents = - addREArray(noCompressionUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set no compression user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { - this.noCompressionUserAgents = noCompressionUserAgents; - } - - - /** - * Set no compression user agent list. - * List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setNoCompressionUserAgents(String noCompressionUserAgents) { - if (noCompressionUserAgents != null) { - StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); - - while (st.hasMoreTokens()) { - addNoCompressionUserAgent(st.nextToken().trim()); - } - } - } - - /** - * Add a mime-type which will be compressable - * The mime-type String will be exactly matched - * in the response mime-type header . - * - * @param mimeType mime-type string - */ - public void addCompressableMimeType(String mimeType) { - compressableMimeTypes = - addStringArray(compressableMimeTypes, mimeType); - } - - - /** - * Set compressable mime-type list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setCompressableMimeTypes(String[] compressableMimeTypes) { - this.compressableMimeTypes = compressableMimeTypes; - } - - - /** - * Set compressable mime-type list - * List contains users agents separated by ',' : - * - * ie: "text/html,text/xml,text/plain" - */ - public void setCompressableMimeTypes(String compressableMimeTypes) { - if (compressableMimeTypes != null) { - StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); - - while (st.hasMoreTokens()) { - addCompressableMimeType(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findCompressableMimeTypes() { - return (compressableMimeTypes); - } - - - - // --------------------------------------------------------- Public Methods - - - /** - * Add input or output filter. - * - * @param className class name of the filter - */ - protected void addFilter(String className) { - try { - Class clazz = Class.forName(className); - Object obj = clazz.newInstance(); - if (obj instanceof InputFilter) { - inputBuffer.addFilter((InputFilter) obj); - } else if (obj instanceof OutputFilter) { - outputBuffer.addFilter((OutputFilter) obj); - } else { - log.warn(sm.getString("http11processor.filter.unknown", className)); - } - } catch (Exception e) { - log.error(sm.getString("http11processor.filter.error", className), e); - } - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private String[] addStringArray(String sArray[], String value) { - String[] result = null; - if (sArray == null) { - result = new String[1]; - result[0] = value; - } - else { - result = new String[sArray.length + 1]; - for (int i = 0; i < sArray.length; i++) - result[i] = sArray[i]; - result[sArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param rArray the REArray - * @param value Obj - */ - private Pattern[] addREArray(Pattern rArray[], Pattern value) { - Pattern[] result = null; - if (rArray == null) { - result = new Pattern[1]; - result[0] = value; - } - else { - result = new Pattern[rArray.length + 1]; - for (int i = 0; i < rArray.length; i++) - result[i] = rArray[i]; - result[rArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private boolean inStringArray(String sArray[], String value) { - for (int i = 0; i < sArray.length; i++) { - if (sArray[i].equals(value)) { - return true; - } - } - return false; - } - - - /** - * Checks if any entry in the string array starts with the specified value - * - * @param sArray the StringArray - * @param value string - */ - private boolean startsWithStringArray(String sArray[], String value) { - if (value == null) - return false; - for (int i = 0; i < sArray.length; i++) { - if (value.startsWith(sArray[i])) { - return true; - } - } - return false; - } - - - /** - * Add restricted user-agent (which will downgrade the connector - * to HTTP/1.0 mode). The user agent String given will be matched - * via regexp to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addRestrictedUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - restrictedUserAgents = addREArray(restrictedUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set restricted user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { - this.restrictedUserAgents = restrictedUserAgents; - } - - - /** - * Set restricted user agent list (which will downgrade the connector - * to HTTP/1.0 mode). List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setRestrictedUserAgents(String restrictedUserAgents) { - if (restrictedUserAgents != null) { - StringTokenizer st = - new StringTokenizer(restrictedUserAgents, ","); - while (st.hasMoreTokens()) { - addRestrictedUserAgent(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findRestrictedUserAgents() { - String[] sarr = new String [restrictedUserAgents.length]; - - for (int i = 0; i < restrictedUserAgents.length; i++) - sarr[i] = restrictedUserAgents[i].toString(); - - return (sarr); - } - - - /** - * Set the maximum number of Keep-Alive requests to honor. - * This is to safeguard from DoS attacks. Setting to a negative - * value disables the check. - */ - public void setMaxKeepAliveRequests(int mkar) { - maxKeepAliveRequests = mkar; - } - - - /** - * Return the number of Keep-Alive requests that we will honor. - */ - public int getMaxKeepAliveRequests() { - return maxKeepAliveRequests; - } - - - /** - * Set the maximum size of a POST which will be buffered in SSL mode. - */ - public void setMaxSavePostSize(int msps) { - maxSavePostSize = msps; - } - - - /** - * Return the maximum size of a POST which will be buffered in SSL mode. - */ - public int getMaxSavePostSize() { - return maxSavePostSize; - } - - - /** - * Set the flag to control upload time-outs. - */ - public void setDisableUploadTimeout(boolean isDisabled) { - disableUploadTimeout = isDisabled; - } - - /** - * Get the flag that controls upload time-outs. - */ - public boolean getDisableUploadTimeout() { - return disableUploadTimeout; - } - - /** - * Set the socket buffer flag. - */ - public void setSocketBuffer(int socketBuffer) { - this.socketBuffer = socketBuffer; - outputBuffer.setSocketBuffer(socketBuffer); - } - - /** - * Get the socket buffer flag. - */ - public int getSocketBuffer() { - return socketBuffer; - } - - /** - * Set the upload timeout. - */ - public void setTimeout( int timeouts ) { - timeout = timeouts ; - } - - /** - * Get the upload timeout. - */ - public int getTimeout() { - return timeout; - } - - - /** - * Set the server header name. - */ - public void setServer( String server ) { - if (server==null || server.equals("")) { - this.server = null; - } else { - this.server = server; - } - } - - /** - * Get the server header name. - */ - public String getServer() { - return server; - } - - - /** Get the request associated with this processor. - * - * @return The request - */ - public Request getRequest() { - return request; - } - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @throws IOException error during an I/O operation - */ - public SocketState event(boolean error) - throws IOException { - - RequestInfo rp = request.getRequestProcessor(); - - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - error = !adapter.event(request, response, error); - if (request.getAttribute("org.apache.tomcat.comet") == null) { - comet = false; - } - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (error) { - recycle(); - return SocketState.CLOSED; - } else if (!comet) { - recycle(); - endpoint.getPoller().add(socket); - return SocketState.OPEN; - } else { - endpoint.getCometPoller().add(socket); - return SocketState.LONG; - } - } - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @throws IOException error during an I/O operation - */ - public SocketState process(long socket) - throws IOException { - RequestInfo rp = request.getRequestProcessor(); - rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); - - // Set the remote address - remoteAddr = null; - remoteHost = null; - localAddr = null; - localName = null; - remotePort = -1; - localPort = -1; - - // Setting up the socket - this.socket = socket; - inputBuffer.setSocket(socket); - outputBuffer.setSocket(socket); - - // Error flag - error = false; - keepAlive = true; - - int keepAliveLeft = maxKeepAliveRequests; - long soTimeout = endpoint.getSoTimeout(); - - int limit = 0; - if (endpoint.getFirstReadTimeout() > 0 || endpoint.getFirstReadTimeout() < -1) { - limit = endpoint.getMaxThreads() / 2; - } - - boolean keptAlive = false; - boolean openSocket = false; - - while (!error && keepAlive && !comet) { - - // Parsing the request header - try { - if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { - Socket.timeoutSet(socket, soTimeout * 1000); - } - if (!inputBuffer.parseRequestLine - (keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { - // This means that no data is available right now - // (long keepalive), so that the processor should be recycled - // and the method should return true - openSocket = true; - // Add the socket to the poller - endpoint.getPoller().add(socket); - break; - } - request.setStartTime(System.currentTimeMillis()); - keptAlive = true; - if (!disableUploadTimeout) { - Socket.timeoutSet(socket, timeout * 1000); - } - inputBuffer.parseHeaders(); - } catch (IOException e) { - error = true; - break; - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.header.parse"), t); - } - // 400 - Bad Request - response.setStatus(400); - error = true; - } - - // Setting up filters, and parse some request headers - rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); - try { - prepareRequest(); - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare"), t); - } - // 400 - Internal Server Error - response.setStatus(400); - error = true; - } - - if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) - keepAlive = false; - - // Process the request in the adapter - if (!error) { - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - adapter.service(request, response); - // Handle when the response was committed before a serious - // error occurred. Throwing a ServletException should both - // set the status to 500 and set the errorException. - // If we fail here, then the response is likely already - // committed, so we can't try and set headers. - if(keepAlive && !error) { // Avoid checking twice. - error = response.getErrorException() != null || - statusDropsConnection(response.getStatus()); - } - // Comet support - if (request.getAttribute("org.apache.tomcat.comet") != null) { - comet = true; - } - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - } - - // Finish the handling of the request - if (!comet) { - endRequest(); - } - - // If there was an error, make sure the request is counted as - // and error, and update the statistics counter - if (error) { - response.setStatus(500); - } - request.updateCounters(); - - // Do sendfile as needed: add socket to sendfile and end - if (sendfileData != null && !error) { - sendfileData.socket = socket; - sendfileData.keepAlive = keepAlive; - if (!endpoint.getSendfile().add(sendfileData)) { - openSocket = true; - break; - } - } - - rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (comet) { - if (error) { - recycle(); - return SocketState.CLOSED; - } else { - return SocketState.LONG; - } - } else { - recycle(); - return (openSocket) ? SocketState.OPEN : SocketState.CLOSED; - } - - } - - - public void endRequest() { - - // Finish the handling of the request - try { - inputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.finish"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - try { - outputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.response.finish"), t); - error = true; - } - - // Next request - inputBuffer.nextRequest(); - outputBuffer.nextRequest(); - - } - - - public void recycle() { - inputBuffer.recycle(); - outputBuffer.recycle(); - this.socket = 0; - } - - - // ----------------------------------------------------- ActionHook Methods - - - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - public void action(ActionCode actionCode, Object param) { - - if (actionCode == ActionCode.ACTION_COMMIT) { - // Commit current response - - if (response.isCommitted()) - return; - - // Validate and write response headers - prepareResponse(); - try { - outputBuffer.commit(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_ACK) { - - // Acknowlege request - - // Send a 100 status back if it makes sense (response not committed - // yet, and client specified an expectation for 100-continue) - - if ((response.isCommitted()) || !expectation) - return; - - inputBuffer.setSwallowInput(true); - try { - outputBuffer.sendAck(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { - - try { - outputBuffer.flush(); - } catch (IOException e) { - // Set error flag - error = true; - response.setErrorException(e); - } - - } else if (actionCode == ActionCode.ACTION_CLOSE) { - // Close - - // End the processing of the current request, and stop any further - // transactions with the client - - comet = false; - try { - outputBuffer.endRequest(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_RESET) { - - // Reset response - - // Note: This must be called before the response is committed - - outputBuffer.reset(); - - } else if (actionCode == ActionCode.ACTION_CUSTOM) { - - // Do nothing - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { - - // Get remote host address - if (remoteAddr == null && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_REMOTE, socket); - remoteAddr = Address.getip(sa); - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - request.remoteAddr().setString(remoteAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { - - // Get local host name - if (localName == null && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_LOCAL, socket); - localName = Address.getnameinfo(sa, 0); - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - request.localName().setString(localName); - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { - - // Get remote host name - if (remoteHost == null && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_REMOTE, socket); - remoteHost = Address.getnameinfo(sa, 0); - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - request.remoteHost().setString(remoteHost); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { - - // Get local host address - if (localAddr == null && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_LOCAL, socket); - localAddr = Address.getip(sa); - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - - request.localAddr().setString(localAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { - - // Get remote port - if (remotePort == -1 && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_REMOTE, socket); - Sockaddr addr = Address.getInfo(sa); - remotePort = addr.port; - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - request.setRemotePort(remotePort); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { - - // Get local port - if (localPort == -1 && (socket != 0)) { - try { - long sa = Address.get(Socket.APR_LOCAL, socket); - Sockaddr addr = Address.getInfo(sa); - localPort = addr.port; - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.info"), e); - } - } - request.setLocalPort(localPort); - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { - - if (ssl && (socket != 0)) { - try { - // Cipher suite - Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); - if (sslO != null) { - request.setAttribute - (AprEndpoint.CIPHER_SUITE_KEY, sslO); - } - // Client certificate chain if present - int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); - X509Certificate[] certs = null; - if (certLength > 0) { - certs = new X509Certificate[certLength]; - for (int i = 0; i < certLength; i++) { - byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); - ByteArrayInputStream stream = new ByteArrayInputStream(data); - certs[i] = (X509Certificate) cf.generateCertificate(stream); - } - } - if (certs != null) { - request.setAttribute - (AprEndpoint.CERTIFICATE_KEY, certs); - } - // User key size - sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); - if (sslO != null) { - request.setAttribute - (AprEndpoint.KEY_SIZE_KEY, sslO); - } - // SSL session ID - sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID); - if (sslO != null) { - request.setAttribute - (AprEndpoint.SESSION_ID_KEY, sslO); - } - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.ssl"), e); - } - } - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { - - if (ssl && (socket != 0)) { - // Consume and buffer the request body, so that it does not - // interfere with the client's handshake messages - InputFilter[] inputFilters = inputBuffer.getFilters(); - ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) - .setLimit(maxSavePostSize); - inputBuffer.addActiveFilter - (inputFilters[Constants.BUFFERED_FILTER]); - try { - // Renegociate certificates - SSLSocket.renegotiate(socket); - // Client certificate chain if present - int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); - X509Certificate[] certs = null; - if (certLength > 0) { - certs = new X509Certificate[certLength]; - for (int i = 0; i < certLength; i++) { - byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); - ByteArrayInputStream stream = new ByteArrayInputStream(data); - certs[i] = (X509Certificate) cf.generateCertificate(stream); - } - } - if (certs != null) { - request.setAttribute - (AprEndpoint.CERTIFICATE_KEY, certs); - } - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.ssl"), e); - } - } - - } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { - ByteChunk body = (ByteChunk) param; - - InputFilter savedBody = new SavedRequestInputFilter(body); - savedBody.setRequest(request); - - InternalAprInputBuffer internalBuffer = (InternalAprInputBuffer) - request.getInputBuffer(); - internalBuffer.addActiveFilter(savedBody); - } - - } - - - // ------------------------------------------------------ Connector Methods - - - /** - * Set the associated adapter. - * - * @param adapter the new adapter - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - - /** - * Get the associated adapter. - * - * @return the associated adapter - */ - public Adapter getAdapter() { - return adapter; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * After reading the request headers, we have to setup the request filters. - */ - protected void prepareRequest() { - - http11 = true; - http09 = false; - contentDelimitation = false; - expectation = false; - sendfileData = null; - if (ssl) { - request.scheme().setString("https"); - } - MessageBytes protocolMB = request.protocol(); - if (protocolMB.equals(Constants.HTTP_11)) { - http11 = true; - protocolMB.setString(Constants.HTTP_11); - } else if (protocolMB.equals(Constants.HTTP_10)) { - http11 = false; - keepAlive = false; - protocolMB.setString(Constants.HTTP_10); - } else if (protocolMB.equals("")) { - // HTTP/0.9 - http09 = true; - http11 = false; - keepAlive = false; - } else { - // Unsupported protocol - http11 = false; - error = true; - // Send 505; Unsupported HTTP version - response.setStatus(505); - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals(Constants.GET)) { - methodMB.setString(Constants.GET); - } else if (methodMB.equals(Constants.POST)) { - methodMB.setString(Constants.POST); - } - - MimeHeaders headers = request.getMimeHeaders(); - - // Check connection header - MessageBytes connectionValueMB = headers.getValue("connection"); - if (connectionValueMB != null) { - ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); - if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { - keepAlive = false; - } else if (findBytes(connectionValueBC, - Constants.KEEPALIVE_BYTES) != -1) { - keepAlive = true; - } - } - - MessageBytes expectMB = null; - if (http11) - expectMB = headers.getValue("expect"); - if ((expectMB != null) - && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { - inputBuffer.setSwallowInput(false); - expectation = true; - } - - // Check user-agent header - if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { - MessageBytes userAgentValueMB = headers.getValue("user-agent"); - // Check in the restricted list, and adjust the http11 - // and keepAlive flags accordingly - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - for (int i = 0; i < restrictedUserAgents.length; i++) { - if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { - http11 = false; - keepAlive = false; - break; - } - } - } - } - - // Check for a full URI (including protocol://host:port/) - ByteChunk uriBC = request.requestURI().getByteChunk(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - - int pos = uriBC.indexOf("://", 0, 3, 4); - int uriBCStart = uriBC.getStart(); - int slashPos = -1; - if (pos != -1) { - byte[] uriB = uriBC.getBytes(); - slashPos = uriBC.indexOf('/', pos + 3); - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/" - request.requestURI().setBytes - (uriB, uriBCStart + pos + 1, 1); - } else { - request.requestURI().setBytes - (uriB, uriBCStart + slashPos, - uriBC.getLength() - slashPos); - } - MessageBytes hostMB = headers.setValue("host"); - hostMB.setBytes(uriB, uriBCStart + pos + 3, - slashPos - pos - 3); - } - - } - - // Input filter setup - InputFilter[] inputFilters = inputBuffer.getFilters(); - - // Parse transfer-encoding header - MessageBytes transferEncodingValueMB = null; - if (http11) - transferEncodingValueMB = headers.getValue("transfer-encoding"); - if (transferEncodingValueMB != null) { - String transferEncodingValue = transferEncodingValueMB.toString(); - // Parse the comma separated list. "identity" codings are ignored - int startPos = 0; - int commaPos = transferEncodingValue.indexOf(','); - String encodingName = null; - while (commaPos != -1) { - encodingName = transferEncodingValue.substring - (startPos, commaPos).toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - startPos = commaPos + 1; - commaPos = transferEncodingValue.indexOf(',', startPos); - } - encodingName = transferEncodingValue.substring(startPos) - .toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - } - - // Parse content-length header - long contentLength = request.getContentLengthLong(); - if (contentLength >= 0 && !contentDelimitation) { - inputBuffer.addActiveFilter - (inputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } - - MessageBytes valueMB = headers.getValue("host"); - - // Check host header - if (http11 && (valueMB == null)) { - error = true; - // 400 - Bad request - response.setStatus(400); - } - - parseHost(valueMB); - - if (!contentDelimitation) { - // If there's no content length - // (broken HTTP/1.0 or HTTP/1.1), assume - // the client is not broken and didn't send a body - inputBuffer.addActiveFilter - (inputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - // Advertise sendfile support through a request attribute - if (endpoint.getUseSendfile()) { - request.setAttribute("org.apache.tomcat.sendfile.support", Boolean.TRUE); - } - // Advertise comet support through a request attribute - request.setAttribute("org.apache.tomcat.comet.support", Boolean.TRUE); - - } - - - /** - * Parse host. - */ - public void parseHost(MessageBytes valueMB) { - - if (valueMB == null || valueMB.isNull()) { - // HTTP/1.0 - // Default is what the socket tells us. Overriden if a host is - // found/parsed - request.setServerPort(endpoint.getPort()); - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - if (hostNameC.length < valueL) { - hostNameC = new char[valueL]; - } - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC[i] = b; - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (!ssl) { - // 80 - Default HTTP port - request.setServerPort(80); - } else { - // 443 - Default HTTPS port - request.setServerPort(443); - } - request.serverName().setChars(hostNameC, 0, valueL); - } else { - - request.serverName().setChars(hostNameC, 0, colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; - if (charValue == -1) { - // Invalid character - error = true; - // 400 - Bad request - response.setStatus(400); - break; - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - - } - - } - - - /** - * Check for compression - */ - private boolean isCompressable() { - - // Nope Compression could works in HTTP 1.0 also - // cf: mod_deflate - - // Compression only since HTTP 1.1 - // if (! http11) - // return false; - - // Check if browser support gzip encoding - MessageBytes acceptEncodingMB = - request.getMimeHeaders().getValue("accept-encoding"); - - if ((acceptEncodingMB == null) - || (acceptEncodingMB.indexOf("gzip") == -1)) - return false; - - // Check if content is not allready gzipped - MessageBytes contentEncodingMB = - response.getMimeHeaders().getValue("Content-Encoding"); - - if ((contentEncodingMB != null) - && (contentEncodingMB.indexOf("gzip") != -1)) - return false; - - // If force mode, allways compress (test purposes only) - if (compressionLevel == 2) - return true; - - // Check for incompatible Browser - if (noCompressionUserAgents != null) { - MessageBytes userAgentValueMB = - request.getMimeHeaders().getValue("user-agent"); - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - - // If one Regexp rule match, disable compression - for (int i = 0; i < noCompressionUserAgents.length; i++) - if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) - return false; - } - } - - // Check if suffisant len to trig the compression - long contentLength = response.getContentLengthLong(); - if ((contentLength == -1) - || (contentLength > compressionMinSize)) { - // Check for compatible MIME-TYPE - if (compressableMimeTypes != null) { - return (startsWithStringArray(compressableMimeTypes, - response.getContentType())); - } - } - - return false; - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - protected void prepareResponse() { - - boolean entityBody = true; - contentDelimitation = false; - - OutputFilter[] outputFilters = outputBuffer.getFilters(); - - if (http09 == true) { - // HTTP/0.9 - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - return; - } - - int statusCode = response.getStatus(); - if ((statusCode == 204) || (statusCode == 205) - || (statusCode == 304)) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - entityBody = false; - contentDelimitation = true; - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals("HEAD")) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - // Sendfile support - if (endpoint.getUseSendfile()) { - String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename"); - if (fileName != null) { - // No entity body sent here - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - sendfileData = new AprEndpoint.SendfileData(); - sendfileData.fileName = fileName; - sendfileData.start = - ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue(); - sendfileData.end = - ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue(); - } - } - - // Check for compression - boolean useCompression = false; - if (entityBody && (compressionLevel > 0) && (sendfileData == null)) { - useCompression = isCompressable(); - // Change content-length to -1 to force chunking - if (useCompression) { - response.setContentLength(-1); - } - } - - MimeHeaders headers = response.getMimeHeaders(); - if (!entityBody) { - response.setContentLength(-1); - } else { - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language") - .setString(contentLanguage); - } - } - - long contentLength = response.getContentLengthLong(); - if (contentLength != -1) { - headers.setValue("Content-Length").setLong(contentLength); - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } else { - if (entityBody && http11 && keepAlive) { - outputBuffer.addActiveFilter - (outputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); - } else { - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - } - } - - if (useCompression) { - outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); - headers.setValue("Content-Encoding").setString("gzip"); - // Make Proxies happy via Vary (from mod_deflate) - headers.setValue("Vary").setString("Accept-Encoding"); - } - - // Add date header - headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate()); - - // FIXME: Add transfer encoding header - - if ((entityBody) && (!contentDelimitation)) { - // Mark as close the connection after the request, and add the - // connection: close header - keepAlive = false; - } - - // If we know that the request is bad this early, add the - // Connection: close header. - keepAlive = keepAlive && !statusDropsConnection(statusCode); - if (!keepAlive) { - headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); - } else if (!http11 && !error) { - headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); - } - - // Build the response header - outputBuffer.sendStatus(); - - // Add server header - if (server != null) { - headers.setValue("Server").setString(server); - } else { - outputBuffer.write(Constants.SERVER_BYTES); - } - - int size = headers.size(); - for (int i = 0; i < size; i++) { - outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); - } - outputBuffer.endHeaders(); - - } - - - /** - * Initialize standard input and output filters. - */ - protected void initializeFilters() { - - // Create and add the identity filters. - inputBuffer.addFilter(new IdentityInputFilter()); - outputBuffer.addFilter(new IdentityOutputFilter()); - - // Create and add the chunked filters. - inputBuffer.addFilter(new ChunkedInputFilter()); - outputBuffer.addFilter(new ChunkedOutputFilter()); - - // Create and add the void filters. - inputBuffer.addFilter(new VoidInputFilter()); - outputBuffer.addFilter(new VoidOutputFilter()); - - // Create and add buffered input filter - inputBuffer.addFilter(new BufferedInputFilter()); - - // Create and add the chunked filters. - //inputBuffer.addFilter(new GzipInputFilter()); - outputBuffer.addFilter(new GzipOutputFilter()); - - } - - - /** - * Add an input filter to the current request. - * - * @return false if the encoding was not found (which would mean it is - * unsupported) - */ - protected boolean addInputFilter(InputFilter[] inputFilters, - String encodingName) { - if (encodingName.equals("identity")) { - // Skip - } else if (encodingName.equals("chunked")) { - inputBuffer.addActiveFilter - (inputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - } else { - for (int i = 2; i < inputFilters.length; i++) { - if (inputFilters[i].getEncodingName() - .toString().equals(encodingName)) { - inputBuffer.addActiveFilter(inputFilters[i]); - return true; - } - } - return false; - } - return true; - } - - - /** - * Specialized utility method: find a sequence of lower case bytes inside - * a ByteChunk. - */ - protected int findBytes(ByteChunk bc, byte[] b) { - - byte first = b[0]; - byte[] buff = bc.getBuffer(); - int start = bc.getStart(); - int end = bc.getEnd(); - - // Look for first char - int srcEnd = b.length; - - for (int i = start; i <= (end - srcEnd); i++) { - if (Ascii.toLower(buff[i]) != first) continue; - // found first char, now look for a match - int myPos = i+1; - for (int srcPos = 1; srcPos < srcEnd; ) { - if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) - break; - if (srcPos == srcEnd) return i - start; // found it - } - } - return -1; - - } - - /** - * Determine if we must drop the connection because of the HTTP status - * code. Use the same list of codes as Apache/httpd. - */ - protected boolean statusDropsConnection(int status) { - return status == 400 /* SC_BAD_REQUEST */ || - status == 408 /* SC_REQUEST_TIMEOUT */ || - status == 411 /* SC_LENGTH_REQUIRED */ || - status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || - status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || - status == 500 /* SC_INTERNAL_SERVER_ERROR */ || - status == 503 /* SC_SERVICE_UNAVAILABLE */ || - status == 501 /* SC_NOT_IMPLEMENTED */; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.util.StringTokenizer; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.Request; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Response; +import org.apache.coyote.http11.filters.ChunkedInputFilter; +import org.apache.coyote.http11.filters.ChunkedOutputFilter; +import org.apache.coyote.http11.filters.GzipOutputFilter; +import org.apache.coyote.http11.filters.IdentityInputFilter; +import org.apache.coyote.http11.filters.IdentityOutputFilter; +import org.apache.coyote.http11.filters.SavedRequestInputFilter; +import org.apache.coyote.http11.filters.VoidInputFilter; +import org.apache.coyote.http11.filters.VoidOutputFilter; +import org.apache.coyote.http11.filters.BufferedInputFilter; +import org.apache.tomcat.jni.Address; +import org.apache.tomcat.jni.SSL; +import org.apache.tomcat.jni.SSLSocket; +import org.apache.tomcat.jni.Sockaddr; +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.util.buf.Ascii; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.AprEndpoint; +import org.apache.tomcat.util.net.AprEndpoint.Handler.SocketState; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Processes HTTP requests. + * + * @author Remy Maucherat + */ +public class Http11AprProcessor implements ActionHook { + + + /** + * Logger. + */ + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(Http11AprProcessor.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------------- Constructors + + + public Http11AprProcessor(int headerBufferSize, AprEndpoint endpoint) { + + this.endpoint = endpoint; + + request = new Request(); + int readTimeout = endpoint.getFirstReadTimeout(); + if (readTimeout == 0) { + readTimeout = 100; + } else if (readTimeout < 0) { + readTimeout = -1; + } + inputBuffer = new InternalAprInputBuffer(request, headerBufferSize, + readTimeout); + request.setInputBuffer(inputBuffer); + + response = new Response(); + response.setHook(this); + outputBuffer = new InternalAprOutputBuffer(response, headerBufferSize); + response.setOutputBuffer(outputBuffer); + request.setResponse(response); + + ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine()); + + initializeFilters(); + + // Cause loading of HexUtils + int foo = HexUtils.DEC[0]; + + // Cause loading of FastHttpDateFormat + FastHttpDateFormat.getCurrentDate(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated adapter. + */ + protected Adapter adapter = null; + + + /** + * Request object. + */ + protected Request request = null; + + + /** + * Response object. + */ + protected Response response = null; + + + /** + * Input. + */ + protected InternalAprInputBuffer inputBuffer = null; + + + /** + * Output. + */ + protected InternalAprOutputBuffer outputBuffer = null; + + + /** + * Error flag. + */ + protected boolean error = false; + + + /** + * Keep-alive. + */ + protected boolean keepAlive = true; + + + /** + * HTTP/1.1 flag. + */ + protected boolean http11 = true; + + + /** + * HTTP/0.9 flag. + */ + protected boolean http09 = false; + + + /** + * Sendfile data. + */ + protected AprEndpoint.SendfileData sendfileData = null; + + + /** + * Comet used. + */ + protected boolean comet = false; + + + /** + * Content delimitator for the request (if false, the connection will + * be closed at the end of the request). + */ + protected boolean contentDelimitation = true; + + + /** + * Is there an expectation ? + */ + protected boolean expectation = false; + + + /** + * List of restricted user agents. + */ + protected Pattern[] restrictedUserAgents = null; + + + /** + * Maximum number of Keep-Alive requests to honor. + */ + protected int maxKeepAliveRequests = -1; + + + /** + * SSL enabled ? + */ + protected boolean ssl = false; + + + /** + * Socket associated with the current connection. + */ + protected long socket = 0; + + + /** + * Remote Address associated with the current connection. + */ + protected String remoteAddr = null; + + + /** + * Remote Host associated with the current connection. + */ + protected String remoteHost = null; + + + /** + * Local Host associated with the current connection. + */ + protected String localName = null; + + + + /** + * Local port to which the socket is connected + */ + protected int localPort = -1; + + + /** + * Remote port to which the socket is connected + */ + protected int remotePort = -1; + + + /** + * The local Host address. + */ + protected String localAddr = null; + + + /** + * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. + */ + protected int timeout = 300000; + + + /** + * Flag to disable setting a different time-out on uploads. + */ + protected boolean disableUploadTimeout = false; + + + /** + * Allowed compression level. + */ + protected int compressionLevel = 0; + + + /** + * Minimum contentsize to make compression. + */ + protected int compressionMinSize = 2048; + + + /** + * Socket buffering. + */ + protected int socketBuffer = -1; + + + /** + * Max save post size. + */ + protected int maxSavePostSize = 4 * 1024; + + + /** + * List of user agents to not use gzip with + */ + protected Pattern noCompressionUserAgents[] = null; + + /** + * List of MIMES which could be gzipped + */ + protected String[] compressableMimeTypes = + { "text/html", "text/xml", "text/plain" }; + + + /** + * Host name (used to avoid useless B2C conversion on the host name). + */ + protected char[] hostNameC = new char[0]; + + + /** + * Associated endpoint. + */ + protected AprEndpoint endpoint; + + + /** + * Allow a customized the server header for the tin-foil hat folks. + */ + protected String server = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return compression level. + */ + public String getCompression() { + switch (compressionLevel) { + case 0: + return "off"; + case 1: + return "on"; + case 2: + return "force"; + } + return "off"; + } + + + /** + * Set compression level. + */ + public void setCompression(String compression) { + if (compression.equals("on")) { + this.compressionLevel = 1; + } else if (compression.equals("force")) { + this.compressionLevel = 2; + } else if (compression.equals("off")) { + this.compressionLevel = 0; + } else { + try { + // Try to parse compression as an int, which would give the + // minimum compression size + compressionMinSize = Integer.parseInt(compression); + this.compressionLevel = 1; + } catch (Exception e) { + this.compressionLevel = 0; + } + } + } + + /** + * Set Minimum size to trigger compression. + */ + public void setCompressionMinSize(int compressionMinSize) { + this.compressionMinSize = compressionMinSize; + } + + + /** + * Add user-agent for which gzip compression didn't works + * The user agent String given will be exactly matched + * to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addNoCompressionUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + noCompressionUserAgents = + addREArray(noCompressionUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set no compression user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { + this.noCompressionUserAgents = noCompressionUserAgents; + } + + + /** + * Set no compression user agent list. + * List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setNoCompressionUserAgents(String noCompressionUserAgents) { + if (noCompressionUserAgents != null) { + StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); + + while (st.hasMoreTokens()) { + addNoCompressionUserAgent(st.nextToken().trim()); + } + } + } + + /** + * Add a mime-type which will be compressable + * The mime-type String will be exactly matched + * in the response mime-type header . + * + * @param mimeType mime-type string + */ + public void addCompressableMimeType(String mimeType) { + compressableMimeTypes = + addStringArray(compressableMimeTypes, mimeType); + } + + + /** + * Set compressable mime-type list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setCompressableMimeTypes(String[] compressableMimeTypes) { + this.compressableMimeTypes = compressableMimeTypes; + } + + + /** + * Set compressable mime-type list + * List contains users agents separated by ',' : + * + * ie: "text/html,text/xml,text/plain" + */ + public void setCompressableMimeTypes(String compressableMimeTypes) { + if (compressableMimeTypes != null) { + StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); + + while (st.hasMoreTokens()) { + addCompressableMimeType(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findCompressableMimeTypes() { + return (compressableMimeTypes); + } + + + + // --------------------------------------------------------- Public Methods + + + /** + * Add input or output filter. + * + * @param className class name of the filter + */ + protected void addFilter(String className) { + try { + Class clazz = Class.forName(className); + Object obj = clazz.newInstance(); + if (obj instanceof InputFilter) { + inputBuffer.addFilter((InputFilter) obj); + } else if (obj instanceof OutputFilter) { + outputBuffer.addFilter((OutputFilter) obj); + } else { + log.warn(sm.getString("http11processor.filter.unknown", className)); + } + } catch (Exception e) { + log.error(sm.getString("http11processor.filter.error", className), e); + } + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private String[] addStringArray(String sArray[], String value) { + String[] result = null; + if (sArray == null) { + result = new String[1]; + result[0] = value; + } + else { + result = new String[sArray.length + 1]; + for (int i = 0; i < sArray.length; i++) + result[i] = sArray[i]; + result[sArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param rArray the REArray + * @param value Obj + */ + private Pattern[] addREArray(Pattern rArray[], Pattern value) { + Pattern[] result = null; + if (rArray == null) { + result = new Pattern[1]; + result[0] = value; + } + else { + result = new Pattern[rArray.length + 1]; + for (int i = 0; i < rArray.length; i++) + result[i] = rArray[i]; + result[rArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private boolean inStringArray(String sArray[], String value) { + for (int i = 0; i < sArray.length; i++) { + if (sArray[i].equals(value)) { + return true; + } + } + return false; + } + + + /** + * Checks if any entry in the string array starts with the specified value + * + * @param sArray the StringArray + * @param value string + */ + private boolean startsWithStringArray(String sArray[], String value) { + if (value == null) + return false; + for (int i = 0; i < sArray.length; i++) { + if (value.startsWith(sArray[i])) { + return true; + } + } + return false; + } + + + /** + * Add restricted user-agent (which will downgrade the connector + * to HTTP/1.0 mode). The user agent String given will be matched + * via regexp to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addRestrictedUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + restrictedUserAgents = addREArray(restrictedUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set restricted user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { + this.restrictedUserAgents = restrictedUserAgents; + } + + + /** + * Set restricted user agent list (which will downgrade the connector + * to HTTP/1.0 mode). List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setRestrictedUserAgents(String restrictedUserAgents) { + if (restrictedUserAgents != null) { + StringTokenizer st = + new StringTokenizer(restrictedUserAgents, ","); + while (st.hasMoreTokens()) { + addRestrictedUserAgent(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findRestrictedUserAgents() { + String[] sarr = new String [restrictedUserAgents.length]; + + for (int i = 0; i < restrictedUserAgents.length; i++) + sarr[i] = restrictedUserAgents[i].toString(); + + return (sarr); + } + + + /** + * Set the maximum number of Keep-Alive requests to honor. + * This is to safeguard from DoS attacks. Setting to a negative + * value disables the check. + */ + public void setMaxKeepAliveRequests(int mkar) { + maxKeepAliveRequests = mkar; + } + + + /** + * Return the number of Keep-Alive requests that we will honor. + */ + public int getMaxKeepAliveRequests() { + return maxKeepAliveRequests; + } + + + /** + * Set the maximum size of a POST which will be buffered in SSL mode. + */ + public void setMaxSavePostSize(int msps) { + maxSavePostSize = msps; + } + + + /** + * Return the maximum size of a POST which will be buffered in SSL mode. + */ + public int getMaxSavePostSize() { + return maxSavePostSize; + } + + + /** + * Set the flag to control upload time-outs. + */ + public void setDisableUploadTimeout(boolean isDisabled) { + disableUploadTimeout = isDisabled; + } + + /** + * Get the flag that controls upload time-outs. + */ + public boolean getDisableUploadTimeout() { + return disableUploadTimeout; + } + + /** + * Set the socket buffer flag. + */ + public void setSocketBuffer(int socketBuffer) { + this.socketBuffer = socketBuffer; + outputBuffer.setSocketBuffer(socketBuffer); + } + + /** + * Get the socket buffer flag. + */ + public int getSocketBuffer() { + return socketBuffer; + } + + /** + * Set the upload timeout. + */ + public void setTimeout( int timeouts ) { + timeout = timeouts ; + } + + /** + * Get the upload timeout. + */ + public int getTimeout() { + return timeout; + } + + + /** + * Set the server header name. + */ + public void setServer( String server ) { + if (server==null || server.equals("")) { + this.server = null; + } else { + this.server = server; + } + } + + /** + * Get the server header name. + */ + public String getServer() { + return server; + } + + + /** Get the request associated with this processor. + * + * @return The request + */ + public Request getRequest() { + return request; + } + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @throws IOException error during an I/O operation + */ + public SocketState event(boolean error) + throws IOException { + + RequestInfo rp = request.getRequestProcessor(); + + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + error = !adapter.event(request, response, error); + if (request.getAttribute("org.apache.tomcat.comet") == null) { + comet = false; + } + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + if (error) { + recycle(); + return SocketState.CLOSED; + } else if (!comet) { + recycle(); + endpoint.getPoller().add(socket); + return SocketState.OPEN; + } else { + endpoint.getCometPoller().add(socket); + return SocketState.LONG; + } + } + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @throws IOException error during an I/O operation + */ + public SocketState process(long socket) + throws IOException { + RequestInfo rp = request.getRequestProcessor(); + rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); + + // Set the remote address + remoteAddr = null; + remoteHost = null; + localAddr = null; + localName = null; + remotePort = -1; + localPort = -1; + + // Setting up the socket + this.socket = socket; + inputBuffer.setSocket(socket); + outputBuffer.setSocket(socket); + + // Error flag + error = false; + keepAlive = true; + + int keepAliveLeft = maxKeepAliveRequests; + long soTimeout = endpoint.getSoTimeout(); + + int limit = 0; + if (endpoint.getFirstReadTimeout() > 0 || endpoint.getFirstReadTimeout() < -1) { + limit = endpoint.getMaxThreads() / 2; + } + + boolean keptAlive = false; + boolean openSocket = false; + + while (!error && keepAlive && !comet) { + + // Parsing the request header + try { + if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { + Socket.timeoutSet(socket, soTimeout * 1000); + } + if (!inputBuffer.parseRequestLine + (keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { + // This means that no data is available right now + // (long keepalive), so that the processor should be recycled + // and the method should return true + openSocket = true; + // Add the socket to the poller + endpoint.getPoller().add(socket); + break; + } + request.setStartTime(System.currentTimeMillis()); + keptAlive = true; + if (!disableUploadTimeout) { + Socket.timeoutSet(socket, timeout * 1000); + } + inputBuffer.parseHeaders(); + } catch (IOException e) { + error = true; + break; + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.header.parse"), t); + } + // 400 - Bad Request + response.setStatus(400); + error = true; + } + + // Setting up filters, and parse some request headers + rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); + try { + prepareRequest(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.request.prepare"), t); + } + // 400 - Internal Server Error + response.setStatus(400); + error = true; + } + + if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) + keepAlive = false; + + // Process the request in the adapter + if (!error) { + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + adapter.service(request, response); + // Handle when the response was committed before a serious + // error occurred. Throwing a ServletException should both + // set the status to 500 and set the errorException. + // If we fail here, then the response is likely already + // committed, so we can't try and set headers. + if(keepAlive && !error) { // Avoid checking twice. + error = response.getErrorException() != null || + statusDropsConnection(response.getStatus()); + } + // Comet support + if (request.getAttribute("org.apache.tomcat.comet") != null) { + comet = true; + } + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + } + + // Finish the handling of the request + if (!comet) { + endRequest(); + } + + // If there was an error, make sure the request is counted as + // and error, and update the statistics counter + if (error) { + response.setStatus(500); + } + request.updateCounters(); + + // Do sendfile as needed: add socket to sendfile and end + if (sendfileData != null && !error) { + sendfileData.socket = socket; + sendfileData.keepAlive = keepAlive; + if (!endpoint.getSendfile().add(sendfileData)) { + openSocket = true; + break; + } + } + + rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); + + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + if (comet) { + if (error) { + recycle(); + return SocketState.CLOSED; + } else { + return SocketState.LONG; + } + } else { + recycle(); + return (openSocket) ? SocketState.OPEN : SocketState.CLOSED; + } + + } + + + public void endRequest() { + + // Finish the handling of the request + try { + inputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.finish"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + try { + outputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.response.finish"), t); + error = true; + } + + // Next request + inputBuffer.nextRequest(); + outputBuffer.nextRequest(); + + } + + + public void recycle() { + inputBuffer.recycle(); + outputBuffer.recycle(); + this.socket = 0; + } + + + // ----------------------------------------------------- ActionHook Methods + + + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + public void action(ActionCode actionCode, Object param) { + + if (actionCode == ActionCode.ACTION_COMMIT) { + // Commit current response + + if (response.isCommitted()) + return; + + // Validate and write response headers + prepareResponse(); + try { + outputBuffer.commit(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_ACK) { + + // Acknowlege request + + // Send a 100 status back if it makes sense (response not committed + // yet, and client specified an expectation for 100-continue) + + if ((response.isCommitted()) || !expectation) + return; + + inputBuffer.setSwallowInput(true); + try { + outputBuffer.sendAck(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { + + try { + outputBuffer.flush(); + } catch (IOException e) { + // Set error flag + error = true; + response.setErrorException(e); + } + + } else if (actionCode == ActionCode.ACTION_CLOSE) { + // Close + + // End the processing of the current request, and stop any further + // transactions with the client + + comet = false; + try { + outputBuffer.endRequest(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_RESET) { + + // Reset response + + // Note: This must be called before the response is committed + + outputBuffer.reset(); + + } else if (actionCode == ActionCode.ACTION_CUSTOM) { + + // Do nothing + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { + + // Get remote host address + if (remoteAddr == null && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_REMOTE, socket); + remoteAddr = Address.getip(sa); + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + request.remoteAddr().setString(remoteAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { + + // Get local host name + if (localName == null && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_LOCAL, socket); + localName = Address.getnameinfo(sa, 0); + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + request.localName().setString(localName); + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { + + // Get remote host name + if (remoteHost == null && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_REMOTE, socket); + remoteHost = Address.getnameinfo(sa, 0); + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + request.remoteHost().setString(remoteHost); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { + + // Get local host address + if (localAddr == null && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_LOCAL, socket); + localAddr = Address.getip(sa); + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + + request.localAddr().setString(localAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { + + // Get remote port + if (remotePort == -1 && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_REMOTE, socket); + Sockaddr addr = Address.getInfo(sa); + remotePort = addr.port; + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + request.setRemotePort(remotePort); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { + + // Get local port + if (localPort == -1 && (socket != 0)) { + try { + long sa = Address.get(Socket.APR_LOCAL, socket); + Sockaddr addr = Address.getInfo(sa); + localPort = addr.port; + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.info"), e); + } + } + request.setLocalPort(localPort); + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { + + if (ssl && (socket != 0)) { + try { + // Cipher suite + Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); + if (sslO != null) { + request.setAttribute + (AprEndpoint.CIPHER_SUITE_KEY, sslO); + } + // Client certificate chain if present + int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); + X509Certificate[] certs = null; + if (certLength > 0) { + certs = new X509Certificate[certLength]; + for (int i = 0; i < certLength; i++) { + byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + ByteArrayInputStream stream = new ByteArrayInputStream(data); + certs[i] = (X509Certificate) cf.generateCertificate(stream); + } + } + if (certs != null) { + request.setAttribute + (AprEndpoint.CERTIFICATE_KEY, certs); + } + // User key size + sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); + if (sslO != null) { + request.setAttribute + (AprEndpoint.KEY_SIZE_KEY, sslO); + } + // SSL session ID + sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID); + if (sslO != null) { + request.setAttribute + (AprEndpoint.SESSION_ID_KEY, sslO); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } + } + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { + + if (ssl && (socket != 0)) { + // Consume and buffer the request body, so that it does not + // interfere with the client's handshake messages + InputFilter[] inputFilters = inputBuffer.getFilters(); + ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) + .setLimit(maxSavePostSize); + inputBuffer.addActiveFilter + (inputFilters[Constants.BUFFERED_FILTER]); + try { + // Renegociate certificates + SSLSocket.renegotiate(socket); + // Client certificate chain if present + int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); + X509Certificate[] certs = null; + if (certLength > 0) { + certs = new X509Certificate[certLength]; + for (int i = 0; i < certLength; i++) { + byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + ByteArrayInputStream stream = new ByteArrayInputStream(data); + certs[i] = (X509Certificate) cf.generateCertificate(stream); + } + } + if (certs != null) { + request.setAttribute + (AprEndpoint.CERTIFICATE_KEY, certs); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } + } + + } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { + ByteChunk body = (ByteChunk) param; + + InputFilter savedBody = new SavedRequestInputFilter(body); + savedBody.setRequest(request); + + InternalAprInputBuffer internalBuffer = (InternalAprInputBuffer) + request.getInputBuffer(); + internalBuffer.addActiveFilter(savedBody); + } + + } + + + // ------------------------------------------------------ Connector Methods + + + /** + * Set the associated adapter. + * + * @param adapter the new adapter + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + + /** + * Get the associated adapter. + * + * @return the associated adapter + */ + public Adapter getAdapter() { + return adapter; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * After reading the request headers, we have to setup the request filters. + */ + protected void prepareRequest() { + + http11 = true; + http09 = false; + contentDelimitation = false; + expectation = false; + sendfileData = null; + if (ssl) { + request.scheme().setString("https"); + } + MessageBytes protocolMB = request.protocol(); + if (protocolMB.equals(Constants.HTTP_11)) { + http11 = true; + protocolMB.setString(Constants.HTTP_11); + } else if (protocolMB.equals(Constants.HTTP_10)) { + http11 = false; + keepAlive = false; + protocolMB.setString(Constants.HTTP_10); + } else if (protocolMB.equals("")) { + // HTTP/0.9 + http09 = true; + http11 = false; + keepAlive = false; + } else { + // Unsupported protocol + http11 = false; + error = true; + // Send 505; Unsupported HTTP version + response.setStatus(505); + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals(Constants.GET)) { + methodMB.setString(Constants.GET); + } else if (methodMB.equals(Constants.POST)) { + methodMB.setString(Constants.POST); + } + + MimeHeaders headers = request.getMimeHeaders(); + + // Check connection header + MessageBytes connectionValueMB = headers.getValue("connection"); + if (connectionValueMB != null) { + ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); + if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { + keepAlive = false; + } else if (findBytes(connectionValueBC, + Constants.KEEPALIVE_BYTES) != -1) { + keepAlive = true; + } + } + + MessageBytes expectMB = null; + if (http11) + expectMB = headers.getValue("expect"); + if ((expectMB != null) + && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { + inputBuffer.setSwallowInput(false); + expectation = true; + } + + // Check user-agent header + if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { + MessageBytes userAgentValueMB = headers.getValue("user-agent"); + // Check in the restricted list, and adjust the http11 + // and keepAlive flags accordingly + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + for (int i = 0; i < restrictedUserAgents.length; i++) { + if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { + http11 = false; + keepAlive = false; + break; + } + } + } + } + + // Check for a full URI (including protocol://host:port/) + ByteChunk uriBC = request.requestURI().getByteChunk(); + if (uriBC.startsWithIgnoreCase("http", 0)) { + + int pos = uriBC.indexOf("://", 0, 3, 4); + int uriBCStart = uriBC.getStart(); + int slashPos = -1; + if (pos != -1) { + byte[] uriB = uriBC.getBytes(); + slashPos = uriBC.indexOf('/', pos + 3); + if (slashPos == -1) { + slashPos = uriBC.getLength(); + // Set URI as "/" + request.requestURI().setBytes + (uriB, uriBCStart + pos + 1, 1); + } else { + request.requestURI().setBytes + (uriB, uriBCStart + slashPos, + uriBC.getLength() - slashPos); + } + MessageBytes hostMB = headers.setValue("host"); + hostMB.setBytes(uriB, uriBCStart + pos + 3, + slashPos - pos - 3); + } + + } + + // Input filter setup + InputFilter[] inputFilters = inputBuffer.getFilters(); + + // Parse transfer-encoding header + MessageBytes transferEncodingValueMB = null; + if (http11) + transferEncodingValueMB = headers.getValue("transfer-encoding"); + if (transferEncodingValueMB != null) { + String transferEncodingValue = transferEncodingValueMB.toString(); + // Parse the comma separated list. "identity" codings are ignored + int startPos = 0; + int commaPos = transferEncodingValue.indexOf(','); + String encodingName = null; + while (commaPos != -1) { + encodingName = transferEncodingValue.substring + (startPos, commaPos).toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + startPos = commaPos + 1; + commaPos = transferEncodingValue.indexOf(',', startPos); + } + encodingName = transferEncodingValue.substring(startPos) + .toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + } + + // Parse content-length header + long contentLength = request.getContentLengthLong(); + if (contentLength >= 0 && !contentDelimitation) { + inputBuffer.addActiveFilter + (inputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } + + MessageBytes valueMB = headers.getValue("host"); + + // Check host header + if (http11 && (valueMB == null)) { + error = true; + // 400 - Bad request + response.setStatus(400); + } + + parseHost(valueMB); + + if (!contentDelimitation) { + // If there's no content length + // (broken HTTP/1.0 or HTTP/1.1), assume + // the client is not broken and didn't send a body + inputBuffer.addActiveFilter + (inputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + // Advertise sendfile support through a request attribute + if (endpoint.getUseSendfile()) { + request.setAttribute("org.apache.tomcat.sendfile.support", Boolean.TRUE); + } + // Advertise comet support through a request attribute + request.setAttribute("org.apache.tomcat.comet.support", Boolean.TRUE); + + } + + + /** + * Parse host. + */ + public void parseHost(MessageBytes valueMB) { + + if (valueMB == null || valueMB.isNull()) { + // HTTP/1.0 + // Default is what the socket tells us. Overriden if a host is + // found/parsed + request.setServerPort(endpoint.getPort()); + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + if (hostNameC.length < valueL) { + hostNameC = new char[valueL]; + } + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC[i] = b; + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (!ssl) { + // 80 - Default HTTP port + request.setServerPort(80); + } else { + // 443 - Default HTTPS port + request.setServerPort(443); + } + request.serverName().setChars(hostNameC, 0, valueL); + } else { + + request.serverName().setChars(hostNameC, 0, colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; + if (charValue == -1) { + // Invalid character + error = true; + // 400 - Bad request + response.setStatus(400); + break; + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + + } + + } + + + /** + * Check for compression + */ + private boolean isCompressable() { + + // Nope Compression could works in HTTP 1.0 also + // cf: mod_deflate + + // Compression only since HTTP 1.1 + // if (! http11) + // return false; + + // Check if browser support gzip encoding + MessageBytes acceptEncodingMB = + request.getMimeHeaders().getValue("accept-encoding"); + + if ((acceptEncodingMB == null) + || (acceptEncodingMB.indexOf("gzip") == -1)) + return false; + + // Check if content is not allready gzipped + MessageBytes contentEncodingMB = + response.getMimeHeaders().getValue("Content-Encoding"); + + if ((contentEncodingMB != null) + && (contentEncodingMB.indexOf("gzip") != -1)) + return false; + + // If force mode, allways compress (test purposes only) + if (compressionLevel == 2) + return true; + + // Check for incompatible Browser + if (noCompressionUserAgents != null) { + MessageBytes userAgentValueMB = + request.getMimeHeaders().getValue("user-agent"); + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + + // If one Regexp rule match, disable compression + for (int i = 0; i < noCompressionUserAgents.length; i++) + if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) + return false; + } + } + + // Check if suffisant len to trig the compression + long contentLength = response.getContentLengthLong(); + if ((contentLength == -1) + || (contentLength > compressionMinSize)) { + // Check for compatible MIME-TYPE + if (compressableMimeTypes != null) { + return (startsWithStringArray(compressableMimeTypes, + response.getContentType())); + } + } + + return false; + } + + + /** + * When committing the response, we have to validate the set of headers, as + * well as setup the response filters. + */ + protected void prepareResponse() { + + boolean entityBody = true; + contentDelimitation = false; + + OutputFilter[] outputFilters = outputBuffer.getFilters(); + + if (http09 == true) { + // HTTP/0.9 + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + return; + } + + int statusCode = response.getStatus(); + if ((statusCode == 204) || (statusCode == 205) + || (statusCode == 304)) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + entityBody = false; + contentDelimitation = true; + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals("HEAD")) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + // Sendfile support + if (endpoint.getUseSendfile()) { + String fileName = (String) request.getAttribute("org.apache.tomcat.sendfile.filename"); + if (fileName != null) { + // No entity body sent here + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + sendfileData = new AprEndpoint.SendfileData(); + sendfileData.fileName = fileName; + sendfileData.start = + ((Long) request.getAttribute("org.apache.tomcat.sendfile.start")).longValue(); + sendfileData.end = + ((Long) request.getAttribute("org.apache.tomcat.sendfile.end")).longValue(); + } + } + + // Check for compression + boolean useCompression = false; + if (entityBody && (compressionLevel > 0) && (sendfileData == null)) { + useCompression = isCompressable(); + // Change content-length to -1 to force chunking + if (useCompression) { + response.setContentLength(-1); + } + } + + MimeHeaders headers = response.getMimeHeaders(); + if (!entityBody) { + response.setContentLength(-1); + } else { + String contentType = response.getContentType(); + if (contentType != null) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = response.getContentLanguage(); + if (contentLanguage != null) { + headers.setValue("Content-Language") + .setString(contentLanguage); + } + } + + long contentLength = response.getContentLengthLong(); + if (contentLength != -1) { + headers.setValue("Content-Length").setLong(contentLength); + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } else { + if (entityBody && http11 && keepAlive) { + outputBuffer.addActiveFilter + (outputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); + } else { + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + } + } + + if (useCompression) { + outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); + headers.setValue("Content-Encoding").setString("gzip"); + // Make Proxies happy via Vary (from mod_deflate) + headers.setValue("Vary").setString("Accept-Encoding"); + } + + // Add date header + headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate()); + + // FIXME: Add transfer encoding header + + if ((entityBody) && (!contentDelimitation)) { + // Mark as close the connection after the request, and add the + // connection: close header + keepAlive = false; + } + + // If we know that the request is bad this early, add the + // Connection: close header. + keepAlive = keepAlive && !statusDropsConnection(statusCode); + if (!keepAlive) { + headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); + } else if (!http11 && !error) { + headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); + } + + // Build the response header + outputBuffer.sendStatus(); + + // Add server header + if (server != null) { + headers.setValue("Server").setString(server); + } else { + outputBuffer.write(Constants.SERVER_BYTES); + } + + int size = headers.size(); + for (int i = 0; i < size; i++) { + outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); + } + outputBuffer.endHeaders(); + + } + + + /** + * Initialize standard input and output filters. + */ + protected void initializeFilters() { + + // Create and add the identity filters. + inputBuffer.addFilter(new IdentityInputFilter()); + outputBuffer.addFilter(new IdentityOutputFilter()); + + // Create and add the chunked filters. + inputBuffer.addFilter(new ChunkedInputFilter()); + outputBuffer.addFilter(new ChunkedOutputFilter()); + + // Create and add the void filters. + inputBuffer.addFilter(new VoidInputFilter()); + outputBuffer.addFilter(new VoidOutputFilter()); + + // Create and add buffered input filter + inputBuffer.addFilter(new BufferedInputFilter()); + + // Create and add the chunked filters. + //inputBuffer.addFilter(new GzipInputFilter()); + outputBuffer.addFilter(new GzipOutputFilter()); + + } + + + /** + * Add an input filter to the current request. + * + * @return false if the encoding was not found (which would mean it is + * unsupported) + */ + protected boolean addInputFilter(InputFilter[] inputFilters, + String encodingName) { + if (encodingName.equals("identity")) { + // Skip + } else if (encodingName.equals("chunked")) { + inputBuffer.addActiveFilter + (inputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + } else { + for (int i = 2; i < inputFilters.length; i++) { + if (inputFilters[i].getEncodingName() + .toString().equals(encodingName)) { + inputBuffer.addActiveFilter(inputFilters[i]); + return true; + } + } + return false; + } + return true; + } + + + /** + * Specialized utility method: find a sequence of lower case bytes inside + * a ByteChunk. + */ + protected int findBytes(ByteChunk bc, byte[] b) { + + byte first = b[0]; + byte[] buff = bc.getBuffer(); + int start = bc.getStart(); + int end = bc.getEnd(); + + // Look for first char + int srcEnd = b.length; + + for (int i = start; i <= (end - srcEnd); i++) { + if (Ascii.toLower(buff[i]) != first) continue; + // found first char, now look for a match + int myPos = i+1; + for (int srcPos = 1; srcPos < srcEnd; ) { + if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) + break; + if (srcPos == srcEnd) return i - start; // found it + } + } + return -1; + + } + + /** + * Determine if we must drop the connection because of the HTTP status + * code. Use the same list of codes as Apache/httpd. + */ + protected boolean statusDropsConnection(int status) { + return status == 400 /* SC_BAD_REQUEST */ || + status == 408 /* SC_REQUEST_TIMEOUT */ || + status == 411 /* SC_LENGTH_REQUIRED */ || + status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || + status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || + status == 500 /* SC_INTERNAL_SERVER_ERROR */ || + status == 503 /* SC_SERVICE_UNAVAILABLE */ || + status == 501 /* SC_NOT_IMPLEMENTED */; + } + +} diff --git a/java/org/apache/coyote/http11/Http11AprProtocol.java b/java/org/apache/coyote/http11/Http11AprProtocol.java index 86d8b0f2b..4ae29d789 100644 --- a/java/org/apache/coyote/http11/Http11AprProtocol.java +++ b/java/org/apache/coyote/http11/Http11AprProtocol.java @@ -1,774 +1,774 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.net.InetAddress; -import java.net.URLEncoder; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.RequestGroupInfo; -import org.apache.coyote.RequestInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.net.AprEndpoint; -import org.apache.tomcat.util.net.AprEndpoint.Handler; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Abstract the protocol implementation, including threading, etc. - * Processor is single threaded and specific to stream-based protocols, - * will not fit Jk protocols like JNI. - * - * @author Remy Maucherat - * @author Costin Manolache - */ -public class Http11AprProtocol implements ProtocolHandler, MBeanRegistration -{ - public Http11AprProtocol() { - cHandler = new Http11ConnectionHandler( this ); - setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); - setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); - //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); - setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); - } - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - /** Pass config info - */ - public void setAttribute( String name, Object value ) { - if( log.isTraceEnabled()) - log.trace(sm.getString("http11protocol.setattribute", name, value)); - - attributes.put(name, value); - } - - public Object getAttribute( String key ) { - if( log.isTraceEnabled()) - log.trace(sm.getString("http11protocol.getattribute", key)); - return attributes.get(key); - } - - public Iterator getAttributeNames() { - return attributes.keySet().iterator(); - } - - /** - * Set a property. - */ - public void setProperty(String name, String value) { - setAttribute(name, value); - } - - /** - * Get a property - */ - public String getProperty(String name) { - return (String)getAttribute(name); - } - - /** The adapter, used to call the connector - */ - public void setAdapter(Adapter adapter) { - this.adapter=adapter; - } - - public Adapter getAdapter() { - return adapter; - } - - - /** Start the protocol - */ - public void init() throws Exception { - ep.setName(getName()); - ep.setHandler(cHandler); - - try { - ep.init(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.initerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.init", getName())); - - } - - ObjectName tpOname; - ObjectName rgOname; - - public void start() throws Exception { - if( this.domain != null ) { - try { - tpOname=new ObjectName - (domain + ":" + "type=ThreadPool,name=" + getName()); - Registry.getRegistry(null, null) - .registerComponent(ep, tpOname, null ); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - rgOname=new ObjectName - (domain + ":type=GlobalRequestProcessor,name=" + getName()); - Registry.getRegistry(null, null).registerComponent - ( cHandler.global, rgOname, null ); - } - - try { - ep.start(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.starterror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.start", getName())); - } - - public void pause() throws Exception { - try { - ep.pause(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.pause", getName())); - } - - public void resume() throws Exception { - try { - ep.resume(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.resume", getName())); - } - - public void destroy() throws Exception { - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.stop", getName())); - ep.destroy(); - if( tpOname!=null ) - Registry.getRegistry(null, null).unregisterComponent(tpOname); - if( rgOname != null ) - Registry.getRegistry(null, null).unregisterComponent(rgOname); - } - - // -------------------- Properties-------------------- - protected AprEndpoint ep=new AprEndpoint(); - protected boolean secure; - - protected Hashtable attributes = new Hashtable(); - - private int maxKeepAliveRequests=100; // as in Apache HTTPD server - private int timeout = 300000; // 5 minutes as in Apache HTTPD server - private int maxSavePostSize = 4 * 1024; - private int maxHttpHeaderSize = 8 * 1024; - private int socketCloseDelay=-1; - private boolean disableUploadTimeout = true; - private int socketBuffer = 9000; - private Adapter adapter; - private Http11ConnectionHandler cHandler; - - /** - * Compression value. - */ - private String compression = "off"; - private String noCompressionUserAgents = null; - private String restrictedUserAgents = null; - private String compressableMimeTypes = "text/html,text/xml,text/plain"; - private int compressionMinSize = 2048; - - private String server; - - // -------------------- Pool setup -------------------- - - // * - public Executor getExecutor() { - return ep.getExecutor(); - } - - // * - public void setExecutor(Executor executor) { - ep.setExecutor(executor); - } - - public int getMaxThreads() { - return ep.getMaxThreads(); - } - - public void setMaxThreads( int maxThreads ) { - ep.setMaxThreads(maxThreads); - setAttribute("maxThreads", "" + maxThreads); - } - - public void setThreadPriority(int threadPriority) { - ep.setThreadPriority(threadPriority); - setAttribute("threadPriority", "" + threadPriority); - } - - public int getThreadPriority() { - return ep.getThreadPriority(); - } - - // -------------------- Tcp setup -------------------- - - public int getBacklog() { - return ep.getBacklog(); - } - - public void setBacklog( int i ) { - ep.setBacklog(i); - setAttribute("backlog", "" + i); - } - - public int getPort() { - return ep.getPort(); - } - - public void setPort( int port ) { - ep.setPort(port); - setAttribute("port", "" + port); - } - - public int getFirstReadTimeout() { - return ep.getFirstReadTimeout(); - } - - public void setFirstReadTimeout( int i ) { - ep.setFirstReadTimeout(i); - setAttribute("firstReadTimeout", "" + i); - } - - public int getPollTime() { - return ep.getPollTime(); - } - - public void setPollTime( int i ) { - ep.setPollTime(i); - setAttribute("pollTime", "" + i); - } - - public void setPollerSize(int i) { - ep.setPollerSize(i); - setAttribute("pollerSize", "" + i); - } - - public int getPollerSize() { - return ep.getPollerSize(); - } - - public void setSendfileSize(int i) { - ep.setSendfileSize(i); - setAttribute("sendfileSize", "" + i); - } - - public int getSendfileSize() { - return ep.getSendfileSize(); - } - - public boolean getUseSendfile() { - return ep.getUseSendfile(); - } - - public void setUseSendfile(boolean useSendfile) { - ep.setUseSendfile(useSendfile); - } - - public InetAddress getAddress() { - return ep.getAddress(); - } - - public void setAddress(InetAddress ia) { - ep.setAddress( ia ); - setAttribute("address", "" + ia); - } - - public String getName() { - String encodedAddr = ""; - if (getAddress() != null) { - encodedAddr = "" + getAddress(); - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) + "-"; - } - return ("http-" + encodedAddr + ep.getPort()); - } - - public boolean getTcpNoDelay() { - return ep.getTcpNoDelay(); - } - - public void setTcpNoDelay( boolean b ) { - ep.setTcpNoDelay( b ); - setAttribute("tcpNoDelay", "" + b); - } - - public boolean getDisableUploadTimeout() { - return disableUploadTimeout; - } - - public void setDisableUploadTimeout(boolean isDisabled) { - disableUploadTimeout = isDisabled; - } - - public int getSocketBuffer() { - return socketBuffer; - } - - public void setSocketBuffer(int valueI) { - socketBuffer = valueI; - } - - public String getCompression() { - return compression; - } - - public void setCompression(String valueS) { - compression = valueS; - setAttribute("compression", valueS); - } - - public int getMaxSavePostSize() { - return maxSavePostSize; - } - - public void setMaxSavePostSize(int valueI) { - maxSavePostSize = valueI; - setAttribute("maxSavePostSize", "" + valueI); - } - - public int getMaxHttpHeaderSize() { - return maxHttpHeaderSize; - } - - public void setMaxHttpHeaderSize(int valueI) { - maxHttpHeaderSize = valueI; - setAttribute("maxHttpHeaderSize", "" + valueI); - } - - public String getRestrictedUserAgents() { - return restrictedUserAgents; - } - - public void setRestrictedUserAgents(String valueS) { - restrictedUserAgents = valueS; - setAttribute("restrictedUserAgents", valueS); - } - - public String getNoCompressionUserAgents() { - return noCompressionUserAgents; - } - - public void setNoCompressionUserAgents(String valueS) { - noCompressionUserAgents = valueS; - setAttribute("noCompressionUserAgents", valueS); - } - - public String getCompressableMimeType() { - return compressableMimeTypes; - } - - public void setCompressableMimeType(String valueS) { - compressableMimeTypes = valueS; - setAttribute("compressableMimeTypes", valueS); - } - - public int getCompressionMinSize() { - return compressionMinSize; - } - - public void setCompressionMinSize(int valueI) { - compressionMinSize = valueI; - setAttribute("compressionMinSize", "" + valueI); - } - - public int getSoLinger() { - return ep.getSoLinger(); - } - - public void setSoLinger( int i ) { - ep.setSoLinger( i ); - setAttribute("soLinger", "" + i); - } - - public int getSoTimeout() { - return ep.getSoTimeout(); - } - - public void setSoTimeout( int i ) { - ep.setSoTimeout(i); - setAttribute("soTimeout", "" + i); - } - - public String getProtocol() { - return getProperty("protocol"); - } - - public void setProtocol( String k ) { - setSecure(true); - setAttribute("protocol", k); - } - - public boolean getSecure() { - return secure; - } - - public void setSecure( boolean b ) { - secure=b; - setAttribute("secure", "" + b); - } - - public int getMaxKeepAliveRequests() { - return maxKeepAliveRequests; - } - - /** Set the maximum number of Keep-Alive requests that we will honor. - */ - public void setMaxKeepAliveRequests(int mkar) { - maxKeepAliveRequests = mkar; - setAttribute("maxKeepAliveRequests", "" + mkar); - } - - /** - * Return the Keep-Alive policy for the connection. - */ - public boolean getKeepAlive() { - return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1)); - } - - /** - * Set the keep-alive policy for this connection. - */ - public void setKeepAlive(boolean keepAlive) { - if (!keepAlive) { - setMaxKeepAliveRequests(1); - } - } - - public int getSocketCloseDelay() { - return socketCloseDelay; - } - - public void setSocketCloseDelay( int d ) { - socketCloseDelay=d; - setAttribute("socketCloseDelay", "" + d); - } - - public void setServer( String server ) { - this.server = server; - } - - public String getServer() { - return server; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout( int timeouts ) { - timeout = timeouts; - setAttribute("timeout", "" + timeouts); - } - - // -------------------- SSL related properties -------------------- - - /** - * SSL engine. - */ - public String getSSLEngine() { return ep.getSSLEngine(); } - public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); } - - - /** - * SSL protocol. - */ - public String getSSLProtocol() { return ep.getSSLProtocol(); } - public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - public String getSSLPassword() { return ep.getSSLPassword(); } - public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); } - - - /** - * SSL cipher suite. - */ - public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); } - public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); } - - - /** - * SSL certificate file. - */ - public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); } - public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); } - - - /** - * SSL certificate key file. - */ - public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); } - - - /** - * SSL certificate chain file. - */ - public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); } - - - /** - * SSL CA certificate path. - */ - public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); } - public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); } - - - /** - * SSL CA certificate file. - */ - public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); } - public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); } - - - /** - * SSL CA revocation path. - */ - public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); } - public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); } - - - /** - * SSL CA revocation file. - */ - public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); } - public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); } - - - /** - * SSL verify client. - */ - public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); } - public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); } - - - /** - * SSL verify depth. - */ - public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); } - public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); } - - // -------------------- Connection handler -------------------- - - static class Http11ConnectionHandler implements Handler { - - protected Http11AprProtocol proto; - protected static int count = 0; - protected RequestGroupInfo global = new RequestGroupInfo(); - - protected ThreadLocal localProcessor = - new ThreadLocal(); - protected ConcurrentHashMap connections = - new ConcurrentHashMap(); - protected java.util.Stack recycledProcessors = - new java.util.Stack(); - - Http11ConnectionHandler(Http11AprProtocol proto) { - this.proto = proto; - } - - public SocketState event(long socket, boolean error) { - Http11AprProcessor result = connections.get(socket); - - SocketState state = SocketState.CLOSED; - if (result != null) { - boolean recycle = error; - // Call the appropriate event - try { - state = result.event(error); - } catch (java.net.SocketException e) { - // SocketExceptions are normal - Http11AprProtocol.log.debug - (sm.getString - ("http11protocol.proto.socketexception.debug"), e); - } catch (java.io.IOException e) { - // IOExceptions are normal - Http11AprProtocol.log.debug - (sm.getString - ("http11protocol.proto.ioexception.debug"), e); - } - // Future developers: if you discover any other - // rare-but-nonfatal exceptions, catch them here, and log as - // above. - catch (Throwable e) { - // any other exception or error is odd. Here we log it - // with "ERROR" level, so it will show up even on - // less-than-verbose logs. - Http11AprProtocol.log.error - (sm.getString("http11protocol.proto.error"), e); - } finally { - if (state != SocketState.LONG) { - connections.remove(socket); - recycledProcessors.push(result); - } - } - } - return state; - } - - public SocketState process(long socket) { - Http11AprProcessor processor = null; - try { - processor = (Http11AprProcessor) localProcessor.get(); - if (processor == null) { - synchronized (recycledProcessors) { - if (!recycledProcessors.isEmpty()) { - processor = recycledProcessors.pop(); - localProcessor.set(processor); - } - } - } - if (processor == null) { - processor = - new Http11AprProcessor(proto.maxHttpHeaderSize, proto.ep); - processor.setAdapter(proto.adapter); - processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); - processor.setTimeout(proto.timeout); - processor.setDisableUploadTimeout(proto.disableUploadTimeout); - processor.setCompression(proto.compression); - processor.setCompressionMinSize(proto.compressionMinSize); - processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); - processor.setCompressableMimeTypes(proto.compressableMimeTypes); - processor.setRestrictedUserAgents(proto.restrictedUserAgents); - processor.setSocketBuffer(proto.socketBuffer); - processor.setMaxSavePostSize(proto.maxSavePostSize); - processor.setServer(proto.server); - localProcessor.set(processor); - if (proto.getDomain() != null) { - synchronized (this) { - try { - RequestInfo rp = processor.getRequest().getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName rpName = new ObjectName - (proto.getDomain() + ":type=RequestProcessor,worker=" - + proto.getName() + ",name=HttpRequest" + count++); - Registry.getRegistry(null, null).registerComponent(rp, rpName, null); - } catch (Exception e) { - log.warn("Error registering request"); - } - } - } - } - - if (processor instanceof ActionHook) { - ((ActionHook) processor).action(ActionCode.ACTION_START, null); - } - - SocketState state = processor.process(socket); - if (state == SocketState.LONG) { - // Associate the connection with the processor. The next request - // processed by this thread will use either a new or a recycled - // processor. - connections.put(socket, processor); - localProcessor.set(null); - proto.ep.getCometPoller().add(socket); - } - return state; - - } catch (java.net.SocketException e) { - // SocketExceptions are normal - Http11AprProtocol.log.debug - (sm.getString - ("http11protocol.proto.socketexception.debug"), e); - } catch (java.io.IOException e) { - // IOExceptions are normal - Http11AprProtocol.log.debug - (sm.getString - ("http11protocol.proto.ioexception.debug"), e); - } - // Future developers: if you discover any other - // rare-but-nonfatal exceptions, catch them here, and log as - // above. - catch (Throwable e) { - // any other exception or error is odd. Here we log it - // with "ERROR" level, so it will show up even on - // less-than-verbose logs. - Http11AprProtocol.log.error - (sm.getString("http11protocol.proto.error"), e); - } - return SocketState.CLOSED; - } - } - - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(Http11AprProtocol.class); - - // -------------------- Various implementation classes -------------------- - - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.net.InetAddress; +import java.net.URLEncoder; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.net.AprEndpoint; +import org.apache.tomcat.util.net.AprEndpoint.Handler; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Abstract the protocol implementation, including threading, etc. + * Processor is single threaded and specific to stream-based protocols, + * will not fit Jk protocols like JNI. + * + * @author Remy Maucherat + * @author Costin Manolache + */ +public class Http11AprProtocol implements ProtocolHandler, MBeanRegistration +{ + public Http11AprProtocol() { + cHandler = new Http11ConnectionHandler( this ); + setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); + setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); + //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); + setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); + } + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + /** Pass config info + */ + public void setAttribute( String name, Object value ) { + if( log.isTraceEnabled()) + log.trace(sm.getString("http11protocol.setattribute", name, value)); + + attributes.put(name, value); + } + + public Object getAttribute( String key ) { + if( log.isTraceEnabled()) + log.trace(sm.getString("http11protocol.getattribute", key)); + return attributes.get(key); + } + + public Iterator getAttributeNames() { + return attributes.keySet().iterator(); + } + + /** + * Set a property. + */ + public void setProperty(String name, String value) { + setAttribute(name, value); + } + + /** + * Get a property + */ + public String getProperty(String name) { + return (String)getAttribute(name); + } + + /** The adapter, used to call the connector + */ + public void setAdapter(Adapter adapter) { + this.adapter=adapter; + } + + public Adapter getAdapter() { + return adapter; + } + + + /** Start the protocol + */ + public void init() throws Exception { + ep.setName(getName()); + ep.setHandler(cHandler); + + try { + ep.init(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.initerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.init", getName())); + + } + + ObjectName tpOname; + ObjectName rgOname; + + public void start() throws Exception { + if( this.domain != null ) { + try { + tpOname=new ObjectName + (domain + ":" + "type=ThreadPool,name=" + getName()); + Registry.getRegistry(null, null) + .registerComponent(ep, tpOname, null ); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + rgOname=new ObjectName + (domain + ":type=GlobalRequestProcessor,name=" + getName()); + Registry.getRegistry(null, null).registerComponent + ( cHandler.global, rgOname, null ); + } + + try { + ep.start(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.starterror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.start", getName())); + } + + public void pause() throws Exception { + try { + ep.pause(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.pause", getName())); + } + + public void resume() throws Exception { + try { + ep.resume(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.resume", getName())); + } + + public void destroy() throws Exception { + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.stop", getName())); + ep.destroy(); + if( tpOname!=null ) + Registry.getRegistry(null, null).unregisterComponent(tpOname); + if( rgOname != null ) + Registry.getRegistry(null, null).unregisterComponent(rgOname); + } + + // -------------------- Properties-------------------- + protected AprEndpoint ep=new AprEndpoint(); + protected boolean secure; + + protected Hashtable attributes = new Hashtable(); + + private int maxKeepAliveRequests=100; // as in Apache HTTPD server + private int timeout = 300000; // 5 minutes as in Apache HTTPD server + private int maxSavePostSize = 4 * 1024; + private int maxHttpHeaderSize = 8 * 1024; + private int socketCloseDelay=-1; + private boolean disableUploadTimeout = true; + private int socketBuffer = 9000; + private Adapter adapter; + private Http11ConnectionHandler cHandler; + + /** + * Compression value. + */ + private String compression = "off"; + private String noCompressionUserAgents = null; + private String restrictedUserAgents = null; + private String compressableMimeTypes = "text/html,text/xml,text/plain"; + private int compressionMinSize = 2048; + + private String server; + + // -------------------- Pool setup -------------------- + + // * + public Executor getExecutor() { + return ep.getExecutor(); + } + + // * + public void setExecutor(Executor executor) { + ep.setExecutor(executor); + } + + public int getMaxThreads() { + return ep.getMaxThreads(); + } + + public void setMaxThreads( int maxThreads ) { + ep.setMaxThreads(maxThreads); + setAttribute("maxThreads", "" + maxThreads); + } + + public void setThreadPriority(int threadPriority) { + ep.setThreadPriority(threadPriority); + setAttribute("threadPriority", "" + threadPriority); + } + + public int getThreadPriority() { + return ep.getThreadPriority(); + } + + // -------------------- Tcp setup -------------------- + + public int getBacklog() { + return ep.getBacklog(); + } + + public void setBacklog( int i ) { + ep.setBacklog(i); + setAttribute("backlog", "" + i); + } + + public int getPort() { + return ep.getPort(); + } + + public void setPort( int port ) { + ep.setPort(port); + setAttribute("port", "" + port); + } + + public int getFirstReadTimeout() { + return ep.getFirstReadTimeout(); + } + + public void setFirstReadTimeout( int i ) { + ep.setFirstReadTimeout(i); + setAttribute("firstReadTimeout", "" + i); + } + + public int getPollTime() { + return ep.getPollTime(); + } + + public void setPollTime( int i ) { + ep.setPollTime(i); + setAttribute("pollTime", "" + i); + } + + public void setPollerSize(int i) { + ep.setPollerSize(i); + setAttribute("pollerSize", "" + i); + } + + public int getPollerSize() { + return ep.getPollerSize(); + } + + public void setSendfileSize(int i) { + ep.setSendfileSize(i); + setAttribute("sendfileSize", "" + i); + } + + public int getSendfileSize() { + return ep.getSendfileSize(); + } + + public boolean getUseSendfile() { + return ep.getUseSendfile(); + } + + public void setUseSendfile(boolean useSendfile) { + ep.setUseSendfile(useSendfile); + } + + public InetAddress getAddress() { + return ep.getAddress(); + } + + public void setAddress(InetAddress ia) { + ep.setAddress( ia ); + setAttribute("address", "" + ia); + } + + public String getName() { + String encodedAddr = ""; + if (getAddress() != null) { + encodedAddr = "" + getAddress(); + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) + "-"; + } + return ("http-" + encodedAddr + ep.getPort()); + } + + public boolean getTcpNoDelay() { + return ep.getTcpNoDelay(); + } + + public void setTcpNoDelay( boolean b ) { + ep.setTcpNoDelay( b ); + setAttribute("tcpNoDelay", "" + b); + } + + public boolean getDisableUploadTimeout() { + return disableUploadTimeout; + } + + public void setDisableUploadTimeout(boolean isDisabled) { + disableUploadTimeout = isDisabled; + } + + public int getSocketBuffer() { + return socketBuffer; + } + + public void setSocketBuffer(int valueI) { + socketBuffer = valueI; + } + + public String getCompression() { + return compression; + } + + public void setCompression(String valueS) { + compression = valueS; + setAttribute("compression", valueS); + } + + public int getMaxSavePostSize() { + return maxSavePostSize; + } + + public void setMaxSavePostSize(int valueI) { + maxSavePostSize = valueI; + setAttribute("maxSavePostSize", "" + valueI); + } + + public int getMaxHttpHeaderSize() { + return maxHttpHeaderSize; + } + + public void setMaxHttpHeaderSize(int valueI) { + maxHttpHeaderSize = valueI; + setAttribute("maxHttpHeaderSize", "" + valueI); + } + + public String getRestrictedUserAgents() { + return restrictedUserAgents; + } + + public void setRestrictedUserAgents(String valueS) { + restrictedUserAgents = valueS; + setAttribute("restrictedUserAgents", valueS); + } + + public String getNoCompressionUserAgents() { + return noCompressionUserAgents; + } + + public void setNoCompressionUserAgents(String valueS) { + noCompressionUserAgents = valueS; + setAttribute("noCompressionUserAgents", valueS); + } + + public String getCompressableMimeType() { + return compressableMimeTypes; + } + + public void setCompressableMimeType(String valueS) { + compressableMimeTypes = valueS; + setAttribute("compressableMimeTypes", valueS); + } + + public int getCompressionMinSize() { + return compressionMinSize; + } + + public void setCompressionMinSize(int valueI) { + compressionMinSize = valueI; + setAttribute("compressionMinSize", "" + valueI); + } + + public int getSoLinger() { + return ep.getSoLinger(); + } + + public void setSoLinger( int i ) { + ep.setSoLinger( i ); + setAttribute("soLinger", "" + i); + } + + public int getSoTimeout() { + return ep.getSoTimeout(); + } + + public void setSoTimeout( int i ) { + ep.setSoTimeout(i); + setAttribute("soTimeout", "" + i); + } + + public String getProtocol() { + return getProperty("protocol"); + } + + public void setProtocol( String k ) { + setSecure(true); + setAttribute("protocol", k); + } + + public boolean getSecure() { + return secure; + } + + public void setSecure( boolean b ) { + secure=b; + setAttribute("secure", "" + b); + } + + public int getMaxKeepAliveRequests() { + return maxKeepAliveRequests; + } + + /** Set the maximum number of Keep-Alive requests that we will honor. + */ + public void setMaxKeepAliveRequests(int mkar) { + maxKeepAliveRequests = mkar; + setAttribute("maxKeepAliveRequests", "" + mkar); + } + + /** + * Return the Keep-Alive policy for the connection. + */ + public boolean getKeepAlive() { + return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1)); + } + + /** + * Set the keep-alive policy for this connection. + */ + public void setKeepAlive(boolean keepAlive) { + if (!keepAlive) { + setMaxKeepAliveRequests(1); + } + } + + public int getSocketCloseDelay() { + return socketCloseDelay; + } + + public void setSocketCloseDelay( int d ) { + socketCloseDelay=d; + setAttribute("socketCloseDelay", "" + d); + } + + public void setServer( String server ) { + this.server = server; + } + + public String getServer() { + return server; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout( int timeouts ) { + timeout = timeouts; + setAttribute("timeout", "" + timeouts); + } + + // -------------------- SSL related properties -------------------- + + /** + * SSL engine. + */ + public String getSSLEngine() { return ep.getSSLEngine(); } + public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); } + + + /** + * SSL protocol. + */ + public String getSSLProtocol() { return ep.getSSLProtocol(); } + public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); } + + + /** + * SSL password (if a cert is encrypted, and no password has been provided, a callback + * will ask for a password). + */ + public String getSSLPassword() { return ep.getSSLPassword(); } + public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); } + + + /** + * SSL cipher suite. + */ + public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); } + public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); } + + + /** + * SSL certificate file. + */ + public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); } + public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); } + + + /** + * SSL certificate key file. + */ + public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); } + public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); } + + + /** + * SSL certificate chain file. + */ + public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); } + public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); } + + + /** + * SSL CA certificate path. + */ + public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); } + public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); } + + + /** + * SSL CA certificate file. + */ + public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); } + public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); } + + + /** + * SSL CA revocation path. + */ + public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); } + public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); } + + + /** + * SSL CA revocation file. + */ + public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); } + public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); } + + + /** + * SSL verify client. + */ + public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); } + public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); } + + + /** + * SSL verify depth. + */ + public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); } + public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); } + + // -------------------- Connection handler -------------------- + + static class Http11ConnectionHandler implements Handler { + + protected Http11AprProtocol proto; + protected static int count = 0; + protected RequestGroupInfo global = new RequestGroupInfo(); + + protected ThreadLocal localProcessor = + new ThreadLocal(); + protected ConcurrentHashMap connections = + new ConcurrentHashMap(); + protected java.util.Stack recycledProcessors = + new java.util.Stack(); + + Http11ConnectionHandler(Http11AprProtocol proto) { + this.proto = proto; + } + + public SocketState event(long socket, boolean error) { + Http11AprProcessor result = connections.get(socket); + + SocketState state = SocketState.CLOSED; + if (result != null) { + boolean recycle = error; + // Call the appropriate event + try { + state = result.event(error); + } catch (java.net.SocketException e) { + // SocketExceptions are normal + Http11AprProtocol.log.debug + (sm.getString + ("http11protocol.proto.socketexception.debug"), e); + } catch (java.io.IOException e) { + // IOExceptions are normal + Http11AprProtocol.log.debug + (sm.getString + ("http11protocol.proto.ioexception.debug"), e); + } + // Future developers: if you discover any other + // rare-but-nonfatal exceptions, catch them here, and log as + // above. + catch (Throwable e) { + // any other exception or error is odd. Here we log it + // with "ERROR" level, so it will show up even on + // less-than-verbose logs. + Http11AprProtocol.log.error + (sm.getString("http11protocol.proto.error"), e); + } finally { + if (state != SocketState.LONG) { + connections.remove(socket); + recycledProcessors.push(result); + } + } + } + return state; + } + + public SocketState process(long socket) { + Http11AprProcessor processor = null; + try { + processor = (Http11AprProcessor) localProcessor.get(); + if (processor == null) { + synchronized (recycledProcessors) { + if (!recycledProcessors.isEmpty()) { + processor = recycledProcessors.pop(); + localProcessor.set(processor); + } + } + } + if (processor == null) { + processor = + new Http11AprProcessor(proto.maxHttpHeaderSize, proto.ep); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); + processor.setTimeout(proto.timeout); + processor.setDisableUploadTimeout(proto.disableUploadTimeout); + processor.setCompression(proto.compression); + processor.setCompressionMinSize(proto.compressionMinSize); + processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); + processor.setCompressableMimeTypes(proto.compressableMimeTypes); + processor.setRestrictedUserAgents(proto.restrictedUserAgents); + processor.setSocketBuffer(proto.socketBuffer); + processor.setMaxSavePostSize(proto.maxSavePostSize); + processor.setServer(proto.server); + localProcessor.set(processor); + if (proto.getDomain() != null) { + synchronized (this) { + try { + RequestInfo rp = processor.getRequest().getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName rpName = new ObjectName + (proto.getDomain() + ":type=RequestProcessor,worker=" + + proto.getName() + ",name=HttpRequest" + count++); + Registry.getRegistry(null, null).registerComponent(rp, rpName, null); + } catch (Exception e) { + log.warn("Error registering request"); + } + } + } + } + + if (processor instanceof ActionHook) { + ((ActionHook) processor).action(ActionCode.ACTION_START, null); + } + + SocketState state = processor.process(socket); + if (state == SocketState.LONG) { + // Associate the connection with the processor. The next request + // processed by this thread will use either a new or a recycled + // processor. + connections.put(socket, processor); + localProcessor.set(null); + proto.ep.getCometPoller().add(socket); + } + return state; + + } catch (java.net.SocketException e) { + // SocketExceptions are normal + Http11AprProtocol.log.debug + (sm.getString + ("http11protocol.proto.socketexception.debug"), e); + } catch (java.io.IOException e) { + // IOExceptions are normal + Http11AprProtocol.log.debug + (sm.getString + ("http11protocol.proto.ioexception.debug"), e); + } + // Future developers: if you discover any other + // rare-but-nonfatal exceptions, catch them here, and log as + // above. + catch (Throwable e) { + // any other exception or error is odd. Here we log it + // with "ERROR" level, so it will show up even on + // less-than-verbose logs. + Http11AprProtocol.log.error + (sm.getString("http11protocol.proto.error"), e); + } + return SocketState.CLOSED; + } + } + + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(Http11AprProtocol.class); + + // -------------------- Various implementation classes -------------------- + + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } +} diff --git a/java/org/apache/coyote/http11/Http11NioProcessor.java b/java/org/apache/coyote/http11/Http11NioProcessor.java index e41a39138..f03587f44 100644 --- a/java/org/apache/coyote/http11/Http11NioProcessor.java +++ b/java/org/apache/coyote/http11/Http11NioProcessor.java @@ -1,1791 +1,1791 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.nio.channels.SocketChannel; -import java.util.StringTokenizer; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Response; -import org.apache.coyote.http11.filters.BufferedInputFilter; -import org.apache.coyote.http11.filters.ChunkedInputFilter; -import org.apache.coyote.http11.filters.ChunkedOutputFilter; -import org.apache.coyote.http11.filters.GzipOutputFilter; -import org.apache.coyote.http11.filters.IdentityInputFilter; -import org.apache.coyote.http11.filters.IdentityOutputFilter; -import org.apache.coyote.http11.filters.SavedRequestInputFilter; -import org.apache.coyote.http11.filters.VoidInputFilter; -import org.apache.coyote.http11.filters.VoidOutputFilter; -import org.apache.tomcat.util.buf.Ascii; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.net.NioEndpoint; -import org.apache.tomcat.util.net.NioEndpoint.Handler; -import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState; -import org.apache.tomcat.util.res.StringManager; -import java.nio.channels.SelectionKey; - - -/** - * Processes HTTP requests. - * - * @author Remy Maucherat - * @author Filip Hanik - */ -public class Http11NioProcessor implements ActionHook { - - - /** - * Logger. - */ - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(Http11NioProcessor.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------------- Constructors - - - public Http11NioProcessor(int headerBufferSize, NioEndpoint endpoint) { - - this.endpoint = endpoint; - - request = new Request(); - int readTimeout = endpoint.getFirstReadTimeout(); - if (readTimeout == 0) { - readTimeout = 100; - } else if (readTimeout < 0) { - readTimeout = timeout; - //readTimeout = -1; - } - inputBuffer = new InternalNioInputBuffer(request, headerBufferSize,readTimeout); - inputBuffer.setPoller(endpoint.getPoller()); - request.setInputBuffer(inputBuffer); - - response = new Response(); - response.setHook(this); - outputBuffer = new InternalNioOutputBuffer(response, headerBufferSize); - response.setOutputBuffer(outputBuffer); - request.setResponse(response); - - ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine()); - - initializeFilters(); - - // Cause loading of HexUtils - int foo = HexUtils.DEC[0]; - - // Cause loading of FastHttpDateFormat - FastHttpDateFormat.getCurrentDate(); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated adapter. - */ - protected Adapter adapter = null; - - - /** - * Request object. - */ - protected Request request = null; - - - /** - * Response object. - */ - protected Response response = null; - - - /** - * Input. - */ - protected InternalNioInputBuffer inputBuffer = null; - - - /** - * Output. - */ - protected InternalNioOutputBuffer outputBuffer = null; - - - /** - * Error flag. - */ - protected boolean error = false; - - - /** - * Keep-alive. - */ - protected boolean keepAlive = true; - - - /** - * HTTP/1.1 flag. - */ - protected boolean http11 = true; - - - /** - * HTTP/0.9 flag. - */ - protected boolean http09 = false; - - - - /** - * Comet used. - */ - protected boolean comet = false; - - /** - * Closed flag, a Comet async thread can - * signal for this Nio processor to be closed and recycled instead - * of waiting for a timeout. - * Closed by HttpServletResponse.getWriter().close() - */ - protected boolean cometClose = false; - - /** - * Content delimitator for the request (if false, the connection will - * be closed at the end of the request). - */ - protected boolean contentDelimitation = true; - - - /** - * Is there an expectation ? - */ - protected boolean expectation = false; - - - /** - * List of restricted user agents. - */ - protected Pattern[] restrictedUserAgents = null; - - - /** - * Maximum number of Keep-Alive requests to honor. - */ - protected int maxKeepAliveRequests = -1; - - - /** - * SSL enabled ? - */ - protected boolean ssl = false; - - - /** - * Socket associated with the current connection. - */ - protected SocketChannel socket = null; - - - /** - * Remote Address associated with the current connection. - */ - protected String remoteAddr = null; - - - /** - * Remote Host associated with the current connection. - */ - protected String remoteHost = null; - - - /** - * Local Host associated with the current connection. - */ - protected String localName = null; - - - - /** - * Local port to which the socket is connected - */ - protected int localPort = -1; - - - /** - * Remote port to which the socket is connected - */ - protected int remotePort = -1; - - - /** - * The local Host address. - */ - protected String localAddr = null; - - - /** - * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. - */ - protected int timeout = 300000; - - - /** - * Flag to disable setting a different time-out on uploads. - */ - protected boolean disableUploadTimeout = false; - - - /** - * Allowed compression level. - */ - protected int compressionLevel = 0; - - - /** - * Minimum contentsize to make compression. - */ - protected int compressionMinSize = 2048; - - - /** - * Socket buffering. - */ - protected int socketBuffer = -1; - - - /** - * Max save post size. - */ - protected int maxSavePostSize = 4 * 1024; - - - /** - * List of user agents to not use gzip with - */ - protected Pattern noCompressionUserAgents[] = null; - - /** - * List of MIMES which could be gzipped - */ - protected String[] compressableMimeTypes = - { "text/html", "text/xml", "text/plain" }; - - - /** - * Host name (used to avoid useless B2C conversion on the host name). - */ - protected char[] hostNameC = new char[0]; - - - /** - * Associated endpoint. - */ - protected NioEndpoint endpoint; - - - /** - * Allow a customized the server header for the tin-foil hat folks. - */ - protected String server = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return compression level. - */ - public String getCompression() { - switch (compressionLevel) { - case 0: - return "off"; - case 1: - return "on"; - case 2: - return "force"; - } - return "off"; - } - - - /** - * Set compression level. - */ - public void setCompression(String compression) { - if (compression.equals("on")) { - this.compressionLevel = 1; - } else if (compression.equals("force")) { - this.compressionLevel = 2; - } else if (compression.equals("off")) { - this.compressionLevel = 0; - } else { - try { - // Try to parse compression as an int, which would give the - // minimum compression size - compressionMinSize = Integer.parseInt(compression); - this.compressionLevel = 1; - } catch (Exception e) { - this.compressionLevel = 0; - } - } - } - - /** - * Set Minimum size to trigger compression. - */ - public void setCompressionMinSize(int compressionMinSize) { - this.compressionMinSize = compressionMinSize; - } - - - /** - * Add user-agent for which gzip compression didn't works - * The user agent String given will be exactly matched - * to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addNoCompressionUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - noCompressionUserAgents = - addREArray(noCompressionUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set no compression user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { - this.noCompressionUserAgents = noCompressionUserAgents; - } - - - /** - * Set no compression user agent list. - * List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setNoCompressionUserAgents(String noCompressionUserAgents) { - if (noCompressionUserAgents != null) { - StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); - - while (st.hasMoreTokens()) { - addNoCompressionUserAgent(st.nextToken().trim()); - } - } - } - - /** - * Add a mime-type which will be compressable - * The mime-type String will be exactly matched - * in the response mime-type header . - * - * @param mimeType mime-type string - */ - public void addCompressableMimeType(String mimeType) { - compressableMimeTypes = - addStringArray(compressableMimeTypes, mimeType); - } - - - /** - * Set compressable mime-type list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setCompressableMimeTypes(String[] compressableMimeTypes) { - this.compressableMimeTypes = compressableMimeTypes; - } - - - /** - * Set compressable mime-type list - * List contains users agents separated by ',' : - * - * ie: "text/html,text/xml,text/plain" - */ - public void setCompressableMimeTypes(String compressableMimeTypes) { - if (compressableMimeTypes != null) { - StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); - - while (st.hasMoreTokens()) { - addCompressableMimeType(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findCompressableMimeTypes() { - return (compressableMimeTypes); - } - - - - // --------------------------------------------------------- Public Methods - - - /** - * Add input or output filter. - * - * @param className class name of the filter - */ - protected void addFilter(String className) { - try { - Class clazz = Class.forName(className); - Object obj = clazz.newInstance(); - if (obj instanceof InputFilter) { - inputBuffer.addFilter((InputFilter) obj); - } else if (obj instanceof OutputFilter) { - outputBuffer.addFilter((OutputFilter) obj); - } else { - log.warn(sm.getString("http11processor.filter.unknown", className)); - } - } catch (Exception e) { - log.error(sm.getString("http11processor.filter.error", className), e); - } - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private String[] addStringArray(String sArray[], String value) { - String[] result = null; - if (sArray == null) { - result = new String[1]; - result[0] = value; - } - else { - result = new String[sArray.length + 1]; - for (int i = 0; i < sArray.length; i++) - result[i] = sArray[i]; - result[sArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param rArray the REArray - * @param value Obj - */ - private Pattern[] addREArray(Pattern rArray[], Pattern value) { - Pattern[] result = null; - if (rArray == null) { - result = new Pattern[1]; - result[0] = value; - } - else { - result = new Pattern[rArray.length + 1]; - for (int i = 0; i < rArray.length; i++) - result[i] = rArray[i]; - result[rArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private boolean inStringArray(String sArray[], String value) { - for (int i = 0; i < sArray.length; i++) { - if (sArray[i].equals(value)) { - return true; - } - } - return false; - } - - - /** - * Checks if any entry in the string array starts with the specified value - * - * @param sArray the StringArray - * @param value string - */ - private boolean startsWithStringArray(String sArray[], String value) { - if (value == null) - return false; - for (int i = 0; i < sArray.length; i++) { - if (value.startsWith(sArray[i])) { - return true; - } - } - return false; - } - - - /** - * Add restricted user-agent (which will downgrade the connector - * to HTTP/1.0 mode). The user agent String given will be matched - * via regexp to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addRestrictedUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - restrictedUserAgents = addREArray(restrictedUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set restricted user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { - this.restrictedUserAgents = restrictedUserAgents; - } - - - /** - * Set restricted user agent list (which will downgrade the connector - * to HTTP/1.0 mode). List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setRestrictedUserAgents(String restrictedUserAgents) { - if (restrictedUserAgents != null) { - StringTokenizer st = - new StringTokenizer(restrictedUserAgents, ","); - while (st.hasMoreTokens()) { - addRestrictedUserAgent(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findRestrictedUserAgents() { - String[] sarr = new String [restrictedUserAgents.length]; - - for (int i = 0; i < restrictedUserAgents.length; i++) - sarr[i] = restrictedUserAgents[i].toString(); - - return (sarr); - } - - - /** - * Set the maximum number of Keep-Alive requests to honor. - * This is to safeguard from DoS attacks. Setting to a negative - * value disables the check. - */ - public void setMaxKeepAliveRequests(int mkar) { - maxKeepAliveRequests = mkar; - } - - - /** - * Return the number of Keep-Alive requests that we will honor. - */ - public int getMaxKeepAliveRequests() { - return maxKeepAliveRequests; - } - - - /** - * Set the maximum size of a POST which will be buffered in SSL mode. - */ - public void setMaxSavePostSize(int msps) { - maxSavePostSize = msps; - } - - - /** - * Return the maximum size of a POST which will be buffered in SSL mode. - */ - public int getMaxSavePostSize() { - return maxSavePostSize; - } - - - /** - * Set the flag to control upload time-outs. - */ - public void setDisableUploadTimeout(boolean isDisabled) { - disableUploadTimeout = isDisabled; - } - - /** - * Get the flag that controls upload time-outs. - */ - public boolean getDisableUploadTimeout() { - return disableUploadTimeout; - } - - /** - * Set the socket buffer flag. - */ - public void setSocketBuffer(int socketBuffer) { - this.socketBuffer = socketBuffer; - outputBuffer.setSocketBuffer(socketBuffer); - } - - /** - * Get the socket buffer flag. - */ - public int getSocketBuffer() { - return socketBuffer; - } - - /** - * Set the upload timeout. - */ - public void setTimeout( int timeouts ) { - timeout = timeouts ; - } - - /** - * Get the upload timeout. - */ - public int getTimeout() { - return timeout; - } - - - /** - * Set the server header name. - */ - public void setServer( String server ) { - if (server==null || server.equals("")) { - this.server = null; - } else { - this.server = server; - } - } - - /** - * Get the server header name. - */ - public String getServer() { - return server; - } - - - /** Get the request associated with this processor. - * - * @return The request - */ - public Request getRequest() { - return request; - } - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @throws IOException error during an I/O operation - */ - public SocketState event(boolean error) - throws IOException { - - RequestInfo rp = request.getRequestProcessor(); - - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - error = !adapter.event(request, response, error); - if (request.getAttribute("org.apache.tomcat.comet") == null) { - comet = false; - } - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); - if ( key != null ) { - NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); - if ( attach!=null ) { - attach.setComet(comet); - Integer comettimeout = (Integer)request.getAttribute("org.apache.tomcat.comet.timeout"); - if ( comettimeout != null ) attach.setTimeout(comettimeout.longValue()); - } - } - - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (error) { - recycle(); - return SocketState.CLOSED; - } else if (!comet) { - recycle(); - endpoint.getPoller().add(socket); - return SocketState.OPEN; - } else { - endpoint.getCometPoller().add(socket); - return SocketState.LONG; - } - } - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @throws IOException error during an I/O operation - */ - public SocketState process(SocketChannel socket) - throws IOException { - RequestInfo rp = request.getRequestProcessor(); - rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); - - // Set the remote address - remoteAddr = null; - remoteHost = null; - localAddr = null; - localName = null; - remotePort = -1; - localPort = -1; - - // Setting up the socket - this.socket = socket; - inputBuffer.setSocket(socket); - outputBuffer.setSocket(socket); - outputBuffer.setSelector(endpoint.getPoller().getSelector()); - - // Error flag - error = false; - keepAlive = true; - - int keepAliveLeft = maxKeepAliveRequests; - long soTimeout = endpoint.getSoTimeout(); - - int limit = 0; - if (endpoint.getFirstReadTimeout() > 0 || endpoint.getFirstReadTimeout() < -1) { - limit = endpoint.getMaxThreads() / 2; - } - - boolean keptAlive = false; - boolean openSocket = false; - - while (!error && keepAlive && !comet) { - - // Parsing the request header - try { - if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { - socket.socket().setSoTimeout((int)soTimeout); - inputBuffer.readTimeout = soTimeout; - } - if (!inputBuffer.parseRequestLine - (keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { - // This means that no data is available right now - // (long keepalive), so that the processor should be recycled - // and the method should return true - openSocket = true; - // Add the socket to the poller - endpoint.getPoller().add(socket); - break; - } - request.setStartTime(System.currentTimeMillis()); - keptAlive = true; - if (!disableUploadTimeout) { - socket.socket().setSoTimeout((int)timeout); - inputBuffer.readTimeout = soTimeout; - } - inputBuffer.parseHeaders(); - } catch (IOException e) { - error = true; - break; - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.header.parse"), t); - } - // 400 - Bad Request - response.setStatus(400); - error = true; - } - - // Setting up filters, and parse some request headers - rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); - try { - prepareRequest(); - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare"), t); - } - // 400 - Internal Server Error - response.setStatus(400); - error = true; - } - - if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) - keepAlive = false; - - // Process the request in the adapter - if (!error) { - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - adapter.service(request, response); - // Handle when the response was committed before a serious - // error occurred. Throwing a ServletException should both - // set the status to 500 and set the errorException. - // If we fail here, then the response is likely already - // committed, so we can't try and set headers. - if(keepAlive && !error) { // Avoid checking twice. - error = response.getErrorException() != null || - statusDropsConnection(response.getStatus()); - } - // Comet support - if (request.getAttribute("org.apache.tomcat.comet") != null) { - comet = true; - } - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); - if (key != null) { - NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); - if (attach != null) { - attach.setComet(comet); - Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout"); - if (comettimeout != null) attach.setTimeout(comettimeout.longValue()); - } - } - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - } - - // Finish the handling of the request - if (!comet) { - endRequest(); - } - - // If there was an error, make sure the request is counted as - // and error, and update the statistics counter - if (error) { - response.setStatus(500); - } - request.updateCounters(); - - rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (comet) { - if (error) { - recycle(); - return SocketState.CLOSED; - } else { - return SocketState.LONG; - } - } else { - recycle(); - return (openSocket) ? SocketState.OPEN : SocketState.CLOSED; - } - - } - - - public void endRequest() { - - // Finish the handling of the request - try { - inputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.finish"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - try { - outputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.response.finish"), t); - error = true; - } - - // Next request - inputBuffer.nextRequest(); - outputBuffer.nextRequest(); - - } - - - public void recycle() { - inputBuffer.recycle(); - outputBuffer.recycle(); - this.socket = null; - this.cometClose = false; - this.comet = false; - } - - - // ----------------------------------------------------- ActionHook Methods - - - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - public void action(ActionCode actionCode, Object param) { - - if (actionCode == ActionCode.ACTION_COMMIT) { - // Commit current response - - if (response.isCommitted()) - return; - - // Validate and write response headers - prepareResponse(); - try { - outputBuffer.commit(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_ACK) { - - // Acknowlege request - - // Send a 100 status back if it makes sense (response not committed - // yet, and client specified an expectation for 100-continue) - - if ((response.isCommitted()) || !expectation) - return; - - inputBuffer.setSwallowInput(true); - try { - outputBuffer.sendAck(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { - - try { - outputBuffer.flush(); - } catch (IOException e) { - // Set error flag - error = true; - response.setErrorException(e); - } - - } else if (actionCode == ActionCode.ACTION_CLOSE) { - // Close - - // End the processing of the current request, and stop any further - // transactions with the client - - comet = false; - cometClose = true; - SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); - if ( key != null ) { - NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); - if ( attach!=null && attach.getComet()) { - //if this is a comet connection - //then execute the connection closure at the next selector loop - request.getAttributes().remove("org.apache.tomcat.comet.timeout"); - attach.setError(true); - } - } - - try { - outputBuffer.endRequest(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_RESET) { - - // Reset response - - // Note: This must be called before the response is committed - - outputBuffer.reset(); - - } else if (actionCode == ActionCode.ACTION_CUSTOM) { - - // Do nothing - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { - - // Get remote host address - if ((remoteAddr == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getInetAddress(); - if (inetAddr != null) { - remoteAddr = inetAddr.getHostAddress(); - } - } - request.remoteAddr().setString(remoteAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { - - // Get local host name - if ((localName == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getLocalAddress(); - if (inetAddr != null) { - localName = inetAddr.getHostName(); - } - } - request.localName().setString(localName); - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { - - // Get remote host name - if ((remoteHost == null) && (socket != null)) { - InetAddress inetAddr = socket.socket().getInetAddress(); - if (inetAddr != null) { - remoteHost = inetAddr.getHostName(); - } - if(remoteHost == null) { - if(remoteAddr != null) { - remoteHost = remoteAddr; - } else { // all we can do is punt - request.remoteHost().recycle(); - } - } - } - request.remoteHost().setString(remoteHost); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { - - if (localAddr == null) - localAddr = socket.socket().getLocalAddress().getHostAddress(); - - request.localAddr().setString(localAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { - - if ((remotePort == -1 ) && (socket !=null)) { - remotePort = socket.socket().getPort(); - } - request.setRemotePort(remotePort); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { - - if ((localPort == -1 ) && (socket !=null)) { - localPort = socket.socket().getLocalPort(); - } - request.setLocalPort(localPort); - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { - -// if (ssl && (socket != 0)) { -// try { -// // Cipher suite -// Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.CIPHER_SUITE_KEY, sslO); -// } -// // Client certificate chain if present -// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); -// X509Certificate[] certs = null; -// if (certLength > 0) { -// certs = new X509Certificate[certLength]; -// for (int i = 0; i < certLength; i++) { -// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); -// CertificateFactory cf = -// CertificateFactory.getInstance("X.509"); -// ByteArrayInputStream stream = new ByteArrayInputStream(data); -// certs[i] = (X509Certificate) cf.generateCertificate(stream); -// } -// } -// if (certs != null) { -// request.setAttribute -// (NioEndpoint.CERTIFICATE_KEY, certs); -// } -// // User key size -// sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.KEY_SIZE_KEY, sslO); -// } -// // SSL session ID -// sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID); -// if (sslO != null) { -// request.setAttribute -// (NioEndpoint.SESSION_ID_KEY, sslO); -// } -// } catch (Exception e) { -// log.warn(sm.getString("http11processor.socket.ssl"), e); -// } -// } - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { - -// if (ssl && (socket != 0)) { -// // Consume and buffer the request body, so that it does not -// // interfere with the client's handshake messages -// InputFilter[] inputFilters = inputBuffer.getFilters(); -// ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) -// .setLimit(maxSavePostSize); -// inputBuffer.addActiveFilter -// (inputFilters[Constants.BUFFERED_FILTER]); -// try { -// // Renegociate certificates -// SSLSocket.renegotiate(socket); -// // Client certificate chain if present -// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); -// X509Certificate[] certs = null; -// if (certLength > 0) { -// certs = new X509Certificate[certLength]; -// for (int i = 0; i < certLength; i++) { -// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); -// CertificateFactory cf = -// CertificateFactory.getInstance("X.509"); -// ByteArrayInputStream stream = new ByteArrayInputStream(data); -// certs[i] = (X509Certificate) cf.generateCertificate(stream); -// } -// } -// if (certs != null) { -// request.setAttribute -// (NioEndpoint.CERTIFICATE_KEY, certs); -// } -// } catch (Exception e) { -// log.warn(sm.getString("http11processor.socket.ssl"), e); -// } -// } - - } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { - ByteChunk body = (ByteChunk) param; - - InputFilter savedBody = new SavedRequestInputFilter(body); - savedBody.setRequest(request); - - InternalNioInputBuffer internalBuffer = (InternalNioInputBuffer) - request.getInputBuffer(); - internalBuffer.addActiveFilter(savedBody); - } - - } - - - // ------------------------------------------------------ Connector Methods - - - /** - * Set the associated adapter. - * - * @param adapter the new adapter - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - - /** - * Get the associated adapter. - * - * @return the associated adapter - */ - public Adapter getAdapter() { - return adapter; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * After reading the request headers, we have to setup the request filters. - */ - protected void prepareRequest() { - - http11 = true; - http09 = false; - contentDelimitation = false; - expectation = false; - if (ssl) { - request.scheme().setString("https"); - } - MessageBytes protocolMB = request.protocol(); - if (protocolMB.equals(Constants.HTTP_11)) { - http11 = true; - protocolMB.setString(Constants.HTTP_11); - } else if (protocolMB.equals(Constants.HTTP_10)) { - http11 = false; - keepAlive = false; - protocolMB.setString(Constants.HTTP_10); - } else if (protocolMB.equals("")) { - // HTTP/0.9 - http09 = true; - http11 = false; - keepAlive = false; - } else { - // Unsupported protocol - http11 = false; - error = true; - // Send 505; Unsupported HTTP version - response.setStatus(505); - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals(Constants.GET)) { - methodMB.setString(Constants.GET); - } else if (methodMB.equals(Constants.POST)) { - methodMB.setString(Constants.POST); - } - - MimeHeaders headers = request.getMimeHeaders(); - - // Check connection header - MessageBytes connectionValueMB = headers.getValue("connection"); - if (connectionValueMB != null) { - ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); - if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { - keepAlive = false; - } else if (findBytes(connectionValueBC, - Constants.KEEPALIVE_BYTES) != -1) { - keepAlive = true; - } - } - - MessageBytes expectMB = null; - if (http11) - expectMB = headers.getValue("expect"); - if ((expectMB != null) - && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { - inputBuffer.setSwallowInput(false); - expectation = true; - } - - // Check user-agent header - if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { - MessageBytes userAgentValueMB = headers.getValue("user-agent"); - // Check in the restricted list, and adjust the http11 - // and keepAlive flags accordingly - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - for (int i = 0; i < restrictedUserAgents.length; i++) { - if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { - http11 = false; - keepAlive = false; - break; - } - } - } - } - - // Check for a full URI (including protocol://host:port/) - ByteChunk uriBC = request.requestURI().getByteChunk(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - - int pos = uriBC.indexOf("://", 0, 3, 4); - int uriBCStart = uriBC.getStart(); - int slashPos = -1; - if (pos != -1) { - byte[] uriB = uriBC.getBytes(); - slashPos = uriBC.indexOf('/', pos + 3); - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/" - request.requestURI().setBytes - (uriB, uriBCStart + pos + 1, 1); - } else { - request.requestURI().setBytes - (uriB, uriBCStart + slashPos, - uriBC.getLength() - slashPos); - } - MessageBytes hostMB = headers.setValue("host"); - hostMB.setBytes(uriB, uriBCStart + pos + 3, - slashPos - pos - 3); - } - - } - - // Input filter setup - InputFilter[] inputFilters = inputBuffer.getFilters(); - - // Parse transfer-encoding header - MessageBytes transferEncodingValueMB = null; - if (http11) - transferEncodingValueMB = headers.getValue("transfer-encoding"); - if (transferEncodingValueMB != null) { - String transferEncodingValue = transferEncodingValueMB.toString(); - // Parse the comma separated list. "identity" codings are ignored - int startPos = 0; - int commaPos = transferEncodingValue.indexOf(','); - String encodingName = null; - while (commaPos != -1) { - encodingName = transferEncodingValue.substring - (startPos, commaPos).toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - startPos = commaPos + 1; - commaPos = transferEncodingValue.indexOf(',', startPos); - } - encodingName = transferEncodingValue.substring(startPos) - .toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - } - - // Parse content-length header - long contentLength = request.getContentLengthLong(); - if (contentLength >= 0 && !contentDelimitation) { - inputBuffer.addActiveFilter - (inputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } - - MessageBytes valueMB = headers.getValue("host"); - - // Check host header - if (http11 && (valueMB == null)) { - error = true; - // 400 - Bad request - response.setStatus(400); - } - - parseHost(valueMB); - - if (!contentDelimitation) { - // If there's no content length - // (broken HTTP/1.0 or HTTP/1.1), assume - // the client is not broken and didn't send a body - inputBuffer.addActiveFilter - (inputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - // Advertise comet support through a request attribute - request.setAttribute("org.apache.tomcat.comet.support", Boolean.TRUE); - // Advertise comet timeout support - request.setAttribute("org.apache.tomcat.comet.timeout.support", Boolean.TRUE); - - } - - - /** - * Parse host. - */ - public void parseHost(MessageBytes valueMB) { - - if (valueMB == null || valueMB.isNull()) { - // HTTP/1.0 - // Default is what the socket tells us. Overriden if a host is - // found/parsed - request.setServerPort(endpoint.getPort()); - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - if (hostNameC.length < valueL) { - hostNameC = new char[valueL]; - } - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC[i] = b; - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (!ssl) { - // 80 - Default HTTP port - request.setServerPort(80); - } else { - // 443 - Default HTTPS port - request.setServerPort(443); - } - request.serverName().setChars(hostNameC, 0, valueL); - } else { - - request.serverName().setChars(hostNameC, 0, colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; - if (charValue == -1) { - // Invalid character - error = true; - // 400 - Bad request - response.setStatus(400); - break; - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - - } - - } - - - /** - * Check for compression - */ - private boolean isCompressable() { - - // Nope Compression could works in HTTP 1.0 also - // cf: mod_deflate - - // Compression only since HTTP 1.1 - // if (! http11) - // return false; - - // Check if browser support gzip encoding - MessageBytes acceptEncodingMB = - request.getMimeHeaders().getValue("accept-encoding"); - - if ((acceptEncodingMB == null) - || (acceptEncodingMB.indexOf("gzip") == -1)) - return false; - - // Check if content is not allready gzipped - MessageBytes contentEncodingMB = - response.getMimeHeaders().getValue("Content-Encoding"); - - if ((contentEncodingMB != null) - && (contentEncodingMB.indexOf("gzip") != -1)) - return false; - - // If force mode, allways compress (test purposes only) - if (compressionLevel == 2) - return true; - - // Check for incompatible Browser - if (noCompressionUserAgents != null) { - MessageBytes userAgentValueMB = - request.getMimeHeaders().getValue("user-agent"); - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - - // If one Regexp rule match, disable compression - for (int i = 0; i < noCompressionUserAgents.length; i++) - if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) - return false; - } - } - - // Check if suffisant len to trig the compression - long contentLength = response.getContentLengthLong(); - if ((contentLength == -1) - || (contentLength > compressionMinSize)) { - // Check for compatible MIME-TYPE - if (compressableMimeTypes != null) { - return (startsWithStringArray(compressableMimeTypes, - response.getContentType())); - } - } - - return false; - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - protected void prepareResponse() { - - boolean entityBody = true; - contentDelimitation = false; - - OutputFilter[] outputFilters = outputBuffer.getFilters(); - - if (http09 == true) { - // HTTP/0.9 - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - return; - } - - int statusCode = response.getStatus(); - if ((statusCode == 204) || (statusCode == 205) - || (statusCode == 304)) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - entityBody = false; - contentDelimitation = true; - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals("HEAD")) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - - // Check for compression - boolean useCompression = false; - if (entityBody && (compressionLevel > 0)) { - useCompression = isCompressable(); - // Change content-length to -1 to force chunking - if (useCompression) { - response.setContentLength(-1); - } - } - - MimeHeaders headers = response.getMimeHeaders(); - if (!entityBody) { - response.setContentLength(-1); - } else { - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language") - .setString(contentLanguage); - } - } - - long contentLength = response.getContentLengthLong(); - if (contentLength != -1) { - headers.setValue("Content-Length").setLong(contentLength); - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } else { - if (entityBody && http11 && keepAlive) { - outputBuffer.addActiveFilter - (outputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); - } else { - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - } - } - - if (useCompression) { - outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); - headers.setValue("Content-Encoding").setString("gzip"); - // Make Proxies happy via Vary (from mod_deflate) - headers.setValue("Vary").setString("Accept-Encoding"); - } - - // Add date header - headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate()); - - // FIXME: Add transfer encoding header - - if ((entityBody) && (!contentDelimitation)) { - // Mark as close the connection after the request, and add the - // connection: close header - keepAlive = false; - } - - // If we know that the request is bad this early, add the - // Connection: close header. - keepAlive = keepAlive && !statusDropsConnection(statusCode); - if (!keepAlive) { - headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); - } else if (!http11 && !error) { - headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); - } - - // Build the response header - outputBuffer.sendStatus(); - - // Add server header - if (server != null) { - headers.setValue("Server").setString(server); - } else { - outputBuffer.write(Constants.SERVER_BYTES); - } - - int size = headers.size(); - for (int i = 0; i < size; i++) { - outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); - } - outputBuffer.endHeaders(); - - } - - - /** - * Initialize standard input and output filters. - */ - protected void initializeFilters() { - - // Create and add the identity filters. - inputBuffer.addFilter(new IdentityInputFilter()); - outputBuffer.addFilter(new IdentityOutputFilter()); - - // Create and add the chunked filters. - inputBuffer.addFilter(new ChunkedInputFilter()); - outputBuffer.addFilter(new ChunkedOutputFilter()); - - // Create and add the void filters. - inputBuffer.addFilter(new VoidInputFilter()); - outputBuffer.addFilter(new VoidOutputFilter()); - - // Create and add buffered input filter - inputBuffer.addFilter(new BufferedInputFilter()); - - // Create and add the chunked filters. - //inputBuffer.addFilter(new GzipInputFilter()); - outputBuffer.addFilter(new GzipOutputFilter()); - - } - - - /** - * Add an input filter to the current request. - * - * @return false if the encoding was not found (which would mean it is - * unsupported) - */ - protected boolean addInputFilter(InputFilter[] inputFilters, - String encodingName) { - if (encodingName.equals("identity")) { - // Skip - } else if (encodingName.equals("chunked")) { - inputBuffer.addActiveFilter - (inputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - } else { - for (int i = 2; i < inputFilters.length; i++) { - if (inputFilters[i].getEncodingName() - .toString().equals(encodingName)) { - inputBuffer.addActiveFilter(inputFilters[i]); - return true; - } - } - return false; - } - return true; - } - - - /** - * Specialized utility method: find a sequence of lower case bytes inside - * a ByteChunk. - */ - protected int findBytes(ByteChunk bc, byte[] b) { - - byte first = b[0]; - byte[] buff = bc.getBuffer(); - int start = bc.getStart(); - int end = bc.getEnd(); - - // Look for first char - int srcEnd = b.length; - - for (int i = start; i <= (end - srcEnd); i++) { - if (Ascii.toLower(buff[i]) != first) continue; - // found first char, now look for a match - int myPos = i+1; - for (int srcPos = 1; srcPos < srcEnd; ) { - if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) - break; - if (srcPos == srcEnd) return i - start; // found it - } - } - return -1; - - } - - /** - * Determine if we must drop the connection because of the HTTP status - * code. Use the same list of codes as Apache/httpd. - */ - protected boolean statusDropsConnection(int status) { - return status == 400 /* SC_BAD_REQUEST */ || - status == 408 /* SC_REQUEST_TIMEOUT */ || - status == 411 /* SC_LENGTH_REQUIRED */ || - status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || - status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || - status == 500 /* SC_INTERNAL_SERVER_ERROR */ || - status == 503 /* SC_SERVICE_UNAVAILABLE */ || - status == 501 /* SC_NOT_IMPLEMENTED */; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.nio.channels.SocketChannel; +import java.util.StringTokenizer; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.Request; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Response; +import org.apache.coyote.http11.filters.BufferedInputFilter; +import org.apache.coyote.http11.filters.ChunkedInputFilter; +import org.apache.coyote.http11.filters.ChunkedOutputFilter; +import org.apache.coyote.http11.filters.GzipOutputFilter; +import org.apache.coyote.http11.filters.IdentityInputFilter; +import org.apache.coyote.http11.filters.IdentityOutputFilter; +import org.apache.coyote.http11.filters.SavedRequestInputFilter; +import org.apache.coyote.http11.filters.VoidInputFilter; +import org.apache.coyote.http11.filters.VoidOutputFilter; +import org.apache.tomcat.util.buf.Ascii; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.NioEndpoint; +import org.apache.tomcat.util.net.NioEndpoint.Handler; +import org.apache.tomcat.util.net.NioEndpoint.Handler.SocketState; +import org.apache.tomcat.util.res.StringManager; +import java.nio.channels.SelectionKey; + + +/** + * Processes HTTP requests. + * + * @author Remy Maucherat + * @author Filip Hanik + */ +public class Http11NioProcessor implements ActionHook { + + + /** + * Logger. + */ + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(Http11NioProcessor.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------------- Constructors + + + public Http11NioProcessor(int headerBufferSize, NioEndpoint endpoint) { + + this.endpoint = endpoint; + + request = new Request(); + int readTimeout = endpoint.getFirstReadTimeout(); + if (readTimeout == 0) { + readTimeout = 100; + } else if (readTimeout < 0) { + readTimeout = timeout; + //readTimeout = -1; + } + inputBuffer = new InternalNioInputBuffer(request, headerBufferSize,readTimeout); + inputBuffer.setPoller(endpoint.getPoller()); + request.setInputBuffer(inputBuffer); + + response = new Response(); + response.setHook(this); + outputBuffer = new InternalNioOutputBuffer(response, headerBufferSize); + response.setOutputBuffer(outputBuffer); + request.setResponse(response); + + ssl = !"off".equalsIgnoreCase(endpoint.getSSLEngine()); + + initializeFilters(); + + // Cause loading of HexUtils + int foo = HexUtils.DEC[0]; + + // Cause loading of FastHttpDateFormat + FastHttpDateFormat.getCurrentDate(); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated adapter. + */ + protected Adapter adapter = null; + + + /** + * Request object. + */ + protected Request request = null; + + + /** + * Response object. + */ + protected Response response = null; + + + /** + * Input. + */ + protected InternalNioInputBuffer inputBuffer = null; + + + /** + * Output. + */ + protected InternalNioOutputBuffer outputBuffer = null; + + + /** + * Error flag. + */ + protected boolean error = false; + + + /** + * Keep-alive. + */ + protected boolean keepAlive = true; + + + /** + * HTTP/1.1 flag. + */ + protected boolean http11 = true; + + + /** + * HTTP/0.9 flag. + */ + protected boolean http09 = false; + + + + /** + * Comet used. + */ + protected boolean comet = false; + + /** + * Closed flag, a Comet async thread can + * signal for this Nio processor to be closed and recycled instead + * of waiting for a timeout. + * Closed by HttpServletResponse.getWriter().close() + */ + protected boolean cometClose = false; + + /** + * Content delimitator for the request (if false, the connection will + * be closed at the end of the request). + */ + protected boolean contentDelimitation = true; + + + /** + * Is there an expectation ? + */ + protected boolean expectation = false; + + + /** + * List of restricted user agents. + */ + protected Pattern[] restrictedUserAgents = null; + + + /** + * Maximum number of Keep-Alive requests to honor. + */ + protected int maxKeepAliveRequests = -1; + + + /** + * SSL enabled ? + */ + protected boolean ssl = false; + + + /** + * Socket associated with the current connection. + */ + protected SocketChannel socket = null; + + + /** + * Remote Address associated with the current connection. + */ + protected String remoteAddr = null; + + + /** + * Remote Host associated with the current connection. + */ + protected String remoteHost = null; + + + /** + * Local Host associated with the current connection. + */ + protected String localName = null; + + + + /** + * Local port to which the socket is connected + */ + protected int localPort = -1; + + + /** + * Remote port to which the socket is connected + */ + protected int remotePort = -1; + + + /** + * The local Host address. + */ + protected String localAddr = null; + + + /** + * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. + */ + protected int timeout = 300000; + + + /** + * Flag to disable setting a different time-out on uploads. + */ + protected boolean disableUploadTimeout = false; + + + /** + * Allowed compression level. + */ + protected int compressionLevel = 0; + + + /** + * Minimum contentsize to make compression. + */ + protected int compressionMinSize = 2048; + + + /** + * Socket buffering. + */ + protected int socketBuffer = -1; + + + /** + * Max save post size. + */ + protected int maxSavePostSize = 4 * 1024; + + + /** + * List of user agents to not use gzip with + */ + protected Pattern noCompressionUserAgents[] = null; + + /** + * List of MIMES which could be gzipped + */ + protected String[] compressableMimeTypes = + { "text/html", "text/xml", "text/plain" }; + + + /** + * Host name (used to avoid useless B2C conversion on the host name). + */ + protected char[] hostNameC = new char[0]; + + + /** + * Associated endpoint. + */ + protected NioEndpoint endpoint; + + + /** + * Allow a customized the server header for the tin-foil hat folks. + */ + protected String server = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return compression level. + */ + public String getCompression() { + switch (compressionLevel) { + case 0: + return "off"; + case 1: + return "on"; + case 2: + return "force"; + } + return "off"; + } + + + /** + * Set compression level. + */ + public void setCompression(String compression) { + if (compression.equals("on")) { + this.compressionLevel = 1; + } else if (compression.equals("force")) { + this.compressionLevel = 2; + } else if (compression.equals("off")) { + this.compressionLevel = 0; + } else { + try { + // Try to parse compression as an int, which would give the + // minimum compression size + compressionMinSize = Integer.parseInt(compression); + this.compressionLevel = 1; + } catch (Exception e) { + this.compressionLevel = 0; + } + } + } + + /** + * Set Minimum size to trigger compression. + */ + public void setCompressionMinSize(int compressionMinSize) { + this.compressionMinSize = compressionMinSize; + } + + + /** + * Add user-agent for which gzip compression didn't works + * The user agent String given will be exactly matched + * to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addNoCompressionUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + noCompressionUserAgents = + addREArray(noCompressionUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set no compression user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { + this.noCompressionUserAgents = noCompressionUserAgents; + } + + + /** + * Set no compression user agent list. + * List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setNoCompressionUserAgents(String noCompressionUserAgents) { + if (noCompressionUserAgents != null) { + StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); + + while (st.hasMoreTokens()) { + addNoCompressionUserAgent(st.nextToken().trim()); + } + } + } + + /** + * Add a mime-type which will be compressable + * The mime-type String will be exactly matched + * in the response mime-type header . + * + * @param mimeType mime-type string + */ + public void addCompressableMimeType(String mimeType) { + compressableMimeTypes = + addStringArray(compressableMimeTypes, mimeType); + } + + + /** + * Set compressable mime-type list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setCompressableMimeTypes(String[] compressableMimeTypes) { + this.compressableMimeTypes = compressableMimeTypes; + } + + + /** + * Set compressable mime-type list + * List contains users agents separated by ',' : + * + * ie: "text/html,text/xml,text/plain" + */ + public void setCompressableMimeTypes(String compressableMimeTypes) { + if (compressableMimeTypes != null) { + StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); + + while (st.hasMoreTokens()) { + addCompressableMimeType(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findCompressableMimeTypes() { + return (compressableMimeTypes); + } + + + + // --------------------------------------------------------- Public Methods + + + /** + * Add input or output filter. + * + * @param className class name of the filter + */ + protected void addFilter(String className) { + try { + Class clazz = Class.forName(className); + Object obj = clazz.newInstance(); + if (obj instanceof InputFilter) { + inputBuffer.addFilter((InputFilter) obj); + } else if (obj instanceof OutputFilter) { + outputBuffer.addFilter((OutputFilter) obj); + } else { + log.warn(sm.getString("http11processor.filter.unknown", className)); + } + } catch (Exception e) { + log.error(sm.getString("http11processor.filter.error", className), e); + } + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private String[] addStringArray(String sArray[], String value) { + String[] result = null; + if (sArray == null) { + result = new String[1]; + result[0] = value; + } + else { + result = new String[sArray.length + 1]; + for (int i = 0; i < sArray.length; i++) + result[i] = sArray[i]; + result[sArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param rArray the REArray + * @param value Obj + */ + private Pattern[] addREArray(Pattern rArray[], Pattern value) { + Pattern[] result = null; + if (rArray == null) { + result = new Pattern[1]; + result[0] = value; + } + else { + result = new Pattern[rArray.length + 1]; + for (int i = 0; i < rArray.length; i++) + result[i] = rArray[i]; + result[rArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private boolean inStringArray(String sArray[], String value) { + for (int i = 0; i < sArray.length; i++) { + if (sArray[i].equals(value)) { + return true; + } + } + return false; + } + + + /** + * Checks if any entry in the string array starts with the specified value + * + * @param sArray the StringArray + * @param value string + */ + private boolean startsWithStringArray(String sArray[], String value) { + if (value == null) + return false; + for (int i = 0; i < sArray.length; i++) { + if (value.startsWith(sArray[i])) { + return true; + } + } + return false; + } + + + /** + * Add restricted user-agent (which will downgrade the connector + * to HTTP/1.0 mode). The user agent String given will be matched + * via regexp to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addRestrictedUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + restrictedUserAgents = addREArray(restrictedUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set restricted user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { + this.restrictedUserAgents = restrictedUserAgents; + } + + + /** + * Set restricted user agent list (which will downgrade the connector + * to HTTP/1.0 mode). List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setRestrictedUserAgents(String restrictedUserAgents) { + if (restrictedUserAgents != null) { + StringTokenizer st = + new StringTokenizer(restrictedUserAgents, ","); + while (st.hasMoreTokens()) { + addRestrictedUserAgent(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findRestrictedUserAgents() { + String[] sarr = new String [restrictedUserAgents.length]; + + for (int i = 0; i < restrictedUserAgents.length; i++) + sarr[i] = restrictedUserAgents[i].toString(); + + return (sarr); + } + + + /** + * Set the maximum number of Keep-Alive requests to honor. + * This is to safeguard from DoS attacks. Setting to a negative + * value disables the check. + */ + public void setMaxKeepAliveRequests(int mkar) { + maxKeepAliveRequests = mkar; + } + + + /** + * Return the number of Keep-Alive requests that we will honor. + */ + public int getMaxKeepAliveRequests() { + return maxKeepAliveRequests; + } + + + /** + * Set the maximum size of a POST which will be buffered in SSL mode. + */ + public void setMaxSavePostSize(int msps) { + maxSavePostSize = msps; + } + + + /** + * Return the maximum size of a POST which will be buffered in SSL mode. + */ + public int getMaxSavePostSize() { + return maxSavePostSize; + } + + + /** + * Set the flag to control upload time-outs. + */ + public void setDisableUploadTimeout(boolean isDisabled) { + disableUploadTimeout = isDisabled; + } + + /** + * Get the flag that controls upload time-outs. + */ + public boolean getDisableUploadTimeout() { + return disableUploadTimeout; + } + + /** + * Set the socket buffer flag. + */ + public void setSocketBuffer(int socketBuffer) { + this.socketBuffer = socketBuffer; + outputBuffer.setSocketBuffer(socketBuffer); + } + + /** + * Get the socket buffer flag. + */ + public int getSocketBuffer() { + return socketBuffer; + } + + /** + * Set the upload timeout. + */ + public void setTimeout( int timeouts ) { + timeout = timeouts ; + } + + /** + * Get the upload timeout. + */ + public int getTimeout() { + return timeout; + } + + + /** + * Set the server header name. + */ + public void setServer( String server ) { + if (server==null || server.equals("")) { + this.server = null; + } else { + this.server = server; + } + } + + /** + * Get the server header name. + */ + public String getServer() { + return server; + } + + + /** Get the request associated with this processor. + * + * @return The request + */ + public Request getRequest() { + return request; + } + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @throws IOException error during an I/O operation + */ + public SocketState event(boolean error) + throws IOException { + + RequestInfo rp = request.getRequestProcessor(); + + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + error = !adapter.event(request, response, error); + if (request.getAttribute("org.apache.tomcat.comet") == null) { + comet = false; + } + SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + if ( key != null ) { + NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); + if ( attach!=null ) { + attach.setComet(comet); + Integer comettimeout = (Integer)request.getAttribute("org.apache.tomcat.comet.timeout"); + if ( comettimeout != null ) attach.setTimeout(comettimeout.longValue()); + } + } + + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + if (error) { + recycle(); + return SocketState.CLOSED; + } else if (!comet) { + recycle(); + endpoint.getPoller().add(socket); + return SocketState.OPEN; + } else { + endpoint.getCometPoller().add(socket); + return SocketState.LONG; + } + } + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @throws IOException error during an I/O operation + */ + public SocketState process(SocketChannel socket) + throws IOException { + RequestInfo rp = request.getRequestProcessor(); + rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); + + // Set the remote address + remoteAddr = null; + remoteHost = null; + localAddr = null; + localName = null; + remotePort = -1; + localPort = -1; + + // Setting up the socket + this.socket = socket; + inputBuffer.setSocket(socket); + outputBuffer.setSocket(socket); + outputBuffer.setSelector(endpoint.getPoller().getSelector()); + + // Error flag + error = false; + keepAlive = true; + + int keepAliveLeft = maxKeepAliveRequests; + long soTimeout = endpoint.getSoTimeout(); + + int limit = 0; + if (endpoint.getFirstReadTimeout() > 0 || endpoint.getFirstReadTimeout() < -1) { + limit = endpoint.getMaxThreads() / 2; + } + + boolean keptAlive = false; + boolean openSocket = false; + + while (!error && keepAlive && !comet) { + + // Parsing the request header + try { + if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { + socket.socket().setSoTimeout((int)soTimeout); + inputBuffer.readTimeout = soTimeout; + } + if (!inputBuffer.parseRequestLine + (keptAlive && (endpoint.getCurrentThreadsBusy() > limit))) { + // This means that no data is available right now + // (long keepalive), so that the processor should be recycled + // and the method should return true + openSocket = true; + // Add the socket to the poller + endpoint.getPoller().add(socket); + break; + } + request.setStartTime(System.currentTimeMillis()); + keptAlive = true; + if (!disableUploadTimeout) { + socket.socket().setSoTimeout((int)timeout); + inputBuffer.readTimeout = soTimeout; + } + inputBuffer.parseHeaders(); + } catch (IOException e) { + error = true; + break; + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.header.parse"), t); + } + // 400 - Bad Request + response.setStatus(400); + error = true; + } + + // Setting up filters, and parse some request headers + rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); + try { + prepareRequest(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.request.prepare"), t); + } + // 400 - Internal Server Error + response.setStatus(400); + error = true; + } + + if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) + keepAlive = false; + + // Process the request in the adapter + if (!error) { + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + adapter.service(request, response); + // Handle when the response was committed before a serious + // error occurred. Throwing a ServletException should both + // set the status to 500 and set the errorException. + // If we fail here, then the response is likely already + // committed, so we can't try and set headers. + if(keepAlive && !error) { // Avoid checking twice. + error = response.getErrorException() != null || + statusDropsConnection(response.getStatus()); + } + // Comet support + if (request.getAttribute("org.apache.tomcat.comet") != null) { + comet = true; + } + SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + if (key != null) { + NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); + if (attach != null) { + attach.setComet(comet); + Integer comettimeout = (Integer) request.getAttribute("org.apache.tomcat.comet.timeout"); + if (comettimeout != null) attach.setTimeout(comettimeout.longValue()); + } + } + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + } + + // Finish the handling of the request + if (!comet) { + endRequest(); + } + + // If there was an error, make sure the request is counted as + // and error, and update the statistics counter + if (error) { + response.setStatus(500); + } + request.updateCounters(); + + rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); + + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + if (comet) { + if (error) { + recycle(); + return SocketState.CLOSED; + } else { + return SocketState.LONG; + } + } else { + recycle(); + return (openSocket) ? SocketState.OPEN : SocketState.CLOSED; + } + + } + + + public void endRequest() { + + // Finish the handling of the request + try { + inputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.finish"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + try { + outputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.response.finish"), t); + error = true; + } + + // Next request + inputBuffer.nextRequest(); + outputBuffer.nextRequest(); + + } + + + public void recycle() { + inputBuffer.recycle(); + outputBuffer.recycle(); + this.socket = null; + this.cometClose = false; + this.comet = false; + } + + + // ----------------------------------------------------- ActionHook Methods + + + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + public void action(ActionCode actionCode, Object param) { + + if (actionCode == ActionCode.ACTION_COMMIT) { + // Commit current response + + if (response.isCommitted()) + return; + + // Validate and write response headers + prepareResponse(); + try { + outputBuffer.commit(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_ACK) { + + // Acknowlege request + + // Send a 100 status back if it makes sense (response not committed + // yet, and client specified an expectation for 100-continue) + + if ((response.isCommitted()) || !expectation) + return; + + inputBuffer.setSwallowInput(true); + try { + outputBuffer.sendAck(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { + + try { + outputBuffer.flush(); + } catch (IOException e) { + // Set error flag + error = true; + response.setErrorException(e); + } + + } else if (actionCode == ActionCode.ACTION_CLOSE) { + // Close + + // End the processing of the current request, and stop any further + // transactions with the client + + comet = false; + cometClose = true; + SelectionKey key = socket.keyFor(endpoint.getPoller().getSelector()); + if ( key != null ) { + NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); + if ( attach!=null && attach.getComet()) { + //if this is a comet connection + //then execute the connection closure at the next selector loop + request.getAttributes().remove("org.apache.tomcat.comet.timeout"); + attach.setError(true); + } + } + + try { + outputBuffer.endRequest(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_RESET) { + + // Reset response + + // Note: This must be called before the response is committed + + outputBuffer.reset(); + + } else if (actionCode == ActionCode.ACTION_CUSTOM) { + + // Do nothing + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { + + // Get remote host address + if ((remoteAddr == null) && (socket != null)) { + InetAddress inetAddr = socket.socket().getInetAddress(); + if (inetAddr != null) { + remoteAddr = inetAddr.getHostAddress(); + } + } + request.remoteAddr().setString(remoteAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { + + // Get local host name + if ((localName == null) && (socket != null)) { + InetAddress inetAddr = socket.socket().getLocalAddress(); + if (inetAddr != null) { + localName = inetAddr.getHostName(); + } + } + request.localName().setString(localName); + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { + + // Get remote host name + if ((remoteHost == null) && (socket != null)) { + InetAddress inetAddr = socket.socket().getInetAddress(); + if (inetAddr != null) { + remoteHost = inetAddr.getHostName(); + } + if(remoteHost == null) { + if(remoteAddr != null) { + remoteHost = remoteAddr; + } else { // all we can do is punt + request.remoteHost().recycle(); + } + } + } + request.remoteHost().setString(remoteHost); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { + + if (localAddr == null) + localAddr = socket.socket().getLocalAddress().getHostAddress(); + + request.localAddr().setString(localAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { + + if ((remotePort == -1 ) && (socket !=null)) { + remotePort = socket.socket().getPort(); + } + request.setRemotePort(remotePort); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { + + if ((localPort == -1 ) && (socket !=null)) { + localPort = socket.socket().getLocalPort(); + } + request.setLocalPort(localPort); + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { + +// if (ssl && (socket != 0)) { +// try { +// // Cipher suite +// Object sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_CIPHER); +// if (sslO != null) { +// request.setAttribute +// (NioEndpoint.CIPHER_SUITE_KEY, sslO); +// } +// // Client certificate chain if present +// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); +// X509Certificate[] certs = null; +// if (certLength > 0) { +// certs = new X509Certificate[certLength]; +// for (int i = 0; i < certLength; i++) { +// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); +// CertificateFactory cf = +// CertificateFactory.getInstance("X.509"); +// ByteArrayInputStream stream = new ByteArrayInputStream(data); +// certs[i] = (X509Certificate) cf.generateCertificate(stream); +// } +// } +// if (certs != null) { +// request.setAttribute +// (NioEndpoint.CERTIFICATE_KEY, certs); +// } +// // User key size +// sslO = new Integer(SSLSocket.getInfoI(socket, SSL.SSL_INFO_CIPHER_USEKEYSIZE)); +// if (sslO != null) { +// request.setAttribute +// (NioEndpoint.KEY_SIZE_KEY, sslO); +// } +// // SSL session ID +// sslO = SSLSocket.getInfoS(socket, SSL.SSL_INFO_SESSION_ID); +// if (sslO != null) { +// request.setAttribute +// (NioEndpoint.SESSION_ID_KEY, sslO); +// } +// } catch (Exception e) { +// log.warn(sm.getString("http11processor.socket.ssl"), e); +// } +// } + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { + +// if (ssl && (socket != 0)) { +// // Consume and buffer the request body, so that it does not +// // interfere with the client's handshake messages +// InputFilter[] inputFilters = inputBuffer.getFilters(); +// ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) +// .setLimit(maxSavePostSize); +// inputBuffer.addActiveFilter +// (inputFilters[Constants.BUFFERED_FILTER]); +// try { +// // Renegociate certificates +// SSLSocket.renegotiate(socket); +// // Client certificate chain if present +// int certLength = SSLSocket.getInfoI(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN); +// X509Certificate[] certs = null; +// if (certLength > 0) { +// certs = new X509Certificate[certLength]; +// for (int i = 0; i < certLength; i++) { +// byte[] data = SSLSocket.getInfoB(socket, SSL.SSL_INFO_CLIENT_CERT_CHAIN + i); +// CertificateFactory cf = +// CertificateFactory.getInstance("X.509"); +// ByteArrayInputStream stream = new ByteArrayInputStream(data); +// certs[i] = (X509Certificate) cf.generateCertificate(stream); +// } +// } +// if (certs != null) { +// request.setAttribute +// (NioEndpoint.CERTIFICATE_KEY, certs); +// } +// } catch (Exception e) { +// log.warn(sm.getString("http11processor.socket.ssl"), e); +// } +// } + + } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { + ByteChunk body = (ByteChunk) param; + + InputFilter savedBody = new SavedRequestInputFilter(body); + savedBody.setRequest(request); + + InternalNioInputBuffer internalBuffer = (InternalNioInputBuffer) + request.getInputBuffer(); + internalBuffer.addActiveFilter(savedBody); + } + + } + + + // ------------------------------------------------------ Connector Methods + + + /** + * Set the associated adapter. + * + * @param adapter the new adapter + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + + /** + * Get the associated adapter. + * + * @return the associated adapter + */ + public Adapter getAdapter() { + return adapter; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * After reading the request headers, we have to setup the request filters. + */ + protected void prepareRequest() { + + http11 = true; + http09 = false; + contentDelimitation = false; + expectation = false; + if (ssl) { + request.scheme().setString("https"); + } + MessageBytes protocolMB = request.protocol(); + if (protocolMB.equals(Constants.HTTP_11)) { + http11 = true; + protocolMB.setString(Constants.HTTP_11); + } else if (protocolMB.equals(Constants.HTTP_10)) { + http11 = false; + keepAlive = false; + protocolMB.setString(Constants.HTTP_10); + } else if (protocolMB.equals("")) { + // HTTP/0.9 + http09 = true; + http11 = false; + keepAlive = false; + } else { + // Unsupported protocol + http11 = false; + error = true; + // Send 505; Unsupported HTTP version + response.setStatus(505); + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals(Constants.GET)) { + methodMB.setString(Constants.GET); + } else if (methodMB.equals(Constants.POST)) { + methodMB.setString(Constants.POST); + } + + MimeHeaders headers = request.getMimeHeaders(); + + // Check connection header + MessageBytes connectionValueMB = headers.getValue("connection"); + if (connectionValueMB != null) { + ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); + if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { + keepAlive = false; + } else if (findBytes(connectionValueBC, + Constants.KEEPALIVE_BYTES) != -1) { + keepAlive = true; + } + } + + MessageBytes expectMB = null; + if (http11) + expectMB = headers.getValue("expect"); + if ((expectMB != null) + && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { + inputBuffer.setSwallowInput(false); + expectation = true; + } + + // Check user-agent header + if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { + MessageBytes userAgentValueMB = headers.getValue("user-agent"); + // Check in the restricted list, and adjust the http11 + // and keepAlive flags accordingly + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + for (int i = 0; i < restrictedUserAgents.length; i++) { + if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { + http11 = false; + keepAlive = false; + break; + } + } + } + } + + // Check for a full URI (including protocol://host:port/) + ByteChunk uriBC = request.requestURI().getByteChunk(); + if (uriBC.startsWithIgnoreCase("http", 0)) { + + int pos = uriBC.indexOf("://", 0, 3, 4); + int uriBCStart = uriBC.getStart(); + int slashPos = -1; + if (pos != -1) { + byte[] uriB = uriBC.getBytes(); + slashPos = uriBC.indexOf('/', pos + 3); + if (slashPos == -1) { + slashPos = uriBC.getLength(); + // Set URI as "/" + request.requestURI().setBytes + (uriB, uriBCStart + pos + 1, 1); + } else { + request.requestURI().setBytes + (uriB, uriBCStart + slashPos, + uriBC.getLength() - slashPos); + } + MessageBytes hostMB = headers.setValue("host"); + hostMB.setBytes(uriB, uriBCStart + pos + 3, + slashPos - pos - 3); + } + + } + + // Input filter setup + InputFilter[] inputFilters = inputBuffer.getFilters(); + + // Parse transfer-encoding header + MessageBytes transferEncodingValueMB = null; + if (http11) + transferEncodingValueMB = headers.getValue("transfer-encoding"); + if (transferEncodingValueMB != null) { + String transferEncodingValue = transferEncodingValueMB.toString(); + // Parse the comma separated list. "identity" codings are ignored + int startPos = 0; + int commaPos = transferEncodingValue.indexOf(','); + String encodingName = null; + while (commaPos != -1) { + encodingName = transferEncodingValue.substring + (startPos, commaPos).toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + startPos = commaPos + 1; + commaPos = transferEncodingValue.indexOf(',', startPos); + } + encodingName = transferEncodingValue.substring(startPos) + .toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + } + + // Parse content-length header + long contentLength = request.getContentLengthLong(); + if (contentLength >= 0 && !contentDelimitation) { + inputBuffer.addActiveFilter + (inputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } + + MessageBytes valueMB = headers.getValue("host"); + + // Check host header + if (http11 && (valueMB == null)) { + error = true; + // 400 - Bad request + response.setStatus(400); + } + + parseHost(valueMB); + + if (!contentDelimitation) { + // If there's no content length + // (broken HTTP/1.0 or HTTP/1.1), assume + // the client is not broken and didn't send a body + inputBuffer.addActiveFilter + (inputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + // Advertise comet support through a request attribute + request.setAttribute("org.apache.tomcat.comet.support", Boolean.TRUE); + // Advertise comet timeout support + request.setAttribute("org.apache.tomcat.comet.timeout.support", Boolean.TRUE); + + } + + + /** + * Parse host. + */ + public void parseHost(MessageBytes valueMB) { + + if (valueMB == null || valueMB.isNull()) { + // HTTP/1.0 + // Default is what the socket tells us. Overriden if a host is + // found/parsed + request.setServerPort(endpoint.getPort()); + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + if (hostNameC.length < valueL) { + hostNameC = new char[valueL]; + } + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC[i] = b; + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (!ssl) { + // 80 - Default HTTP port + request.setServerPort(80); + } else { + // 443 - Default HTTPS port + request.setServerPort(443); + } + request.serverName().setChars(hostNameC, 0, valueL); + } else { + + request.serverName().setChars(hostNameC, 0, colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; + if (charValue == -1) { + // Invalid character + error = true; + // 400 - Bad request + response.setStatus(400); + break; + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + + } + + } + + + /** + * Check for compression + */ + private boolean isCompressable() { + + // Nope Compression could works in HTTP 1.0 also + // cf: mod_deflate + + // Compression only since HTTP 1.1 + // if (! http11) + // return false; + + // Check if browser support gzip encoding + MessageBytes acceptEncodingMB = + request.getMimeHeaders().getValue("accept-encoding"); + + if ((acceptEncodingMB == null) + || (acceptEncodingMB.indexOf("gzip") == -1)) + return false; + + // Check if content is not allready gzipped + MessageBytes contentEncodingMB = + response.getMimeHeaders().getValue("Content-Encoding"); + + if ((contentEncodingMB != null) + && (contentEncodingMB.indexOf("gzip") != -1)) + return false; + + // If force mode, allways compress (test purposes only) + if (compressionLevel == 2) + return true; + + // Check for incompatible Browser + if (noCompressionUserAgents != null) { + MessageBytes userAgentValueMB = + request.getMimeHeaders().getValue("user-agent"); + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + + // If one Regexp rule match, disable compression + for (int i = 0; i < noCompressionUserAgents.length; i++) + if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) + return false; + } + } + + // Check if suffisant len to trig the compression + long contentLength = response.getContentLengthLong(); + if ((contentLength == -1) + || (contentLength > compressionMinSize)) { + // Check for compatible MIME-TYPE + if (compressableMimeTypes != null) { + return (startsWithStringArray(compressableMimeTypes, + response.getContentType())); + } + } + + return false; + } + + + /** + * When committing the response, we have to validate the set of headers, as + * well as setup the response filters. + */ + protected void prepareResponse() { + + boolean entityBody = true; + contentDelimitation = false; + + OutputFilter[] outputFilters = outputBuffer.getFilters(); + + if (http09 == true) { + // HTTP/0.9 + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + return; + } + + int statusCode = response.getStatus(); + if ((statusCode == 204) || (statusCode == 205) + || (statusCode == 304)) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + entityBody = false; + contentDelimitation = true; + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals("HEAD")) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + + // Check for compression + boolean useCompression = false; + if (entityBody && (compressionLevel > 0)) { + useCompression = isCompressable(); + // Change content-length to -1 to force chunking + if (useCompression) { + response.setContentLength(-1); + } + } + + MimeHeaders headers = response.getMimeHeaders(); + if (!entityBody) { + response.setContentLength(-1); + } else { + String contentType = response.getContentType(); + if (contentType != null) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = response.getContentLanguage(); + if (contentLanguage != null) { + headers.setValue("Content-Language") + .setString(contentLanguage); + } + } + + long contentLength = response.getContentLengthLong(); + if (contentLength != -1) { + headers.setValue("Content-Length").setLong(contentLength); + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } else { + if (entityBody && http11 && keepAlive) { + outputBuffer.addActiveFilter + (outputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); + } else { + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + } + } + + if (useCompression) { + outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); + headers.setValue("Content-Encoding").setString("gzip"); + // Make Proxies happy via Vary (from mod_deflate) + headers.setValue("Vary").setString("Accept-Encoding"); + } + + // Add date header + headers.setValue("Date").setString(FastHttpDateFormat.getCurrentDate()); + + // FIXME: Add transfer encoding header + + if ((entityBody) && (!contentDelimitation)) { + // Mark as close the connection after the request, and add the + // connection: close header + keepAlive = false; + } + + // If we know that the request is bad this early, add the + // Connection: close header. + keepAlive = keepAlive && !statusDropsConnection(statusCode); + if (!keepAlive) { + headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); + } else if (!http11 && !error) { + headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); + } + + // Build the response header + outputBuffer.sendStatus(); + + // Add server header + if (server != null) { + headers.setValue("Server").setString(server); + } else { + outputBuffer.write(Constants.SERVER_BYTES); + } + + int size = headers.size(); + for (int i = 0; i < size; i++) { + outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); + } + outputBuffer.endHeaders(); + + } + + + /** + * Initialize standard input and output filters. + */ + protected void initializeFilters() { + + // Create and add the identity filters. + inputBuffer.addFilter(new IdentityInputFilter()); + outputBuffer.addFilter(new IdentityOutputFilter()); + + // Create and add the chunked filters. + inputBuffer.addFilter(new ChunkedInputFilter()); + outputBuffer.addFilter(new ChunkedOutputFilter()); + + // Create and add the void filters. + inputBuffer.addFilter(new VoidInputFilter()); + outputBuffer.addFilter(new VoidOutputFilter()); + + // Create and add buffered input filter + inputBuffer.addFilter(new BufferedInputFilter()); + + // Create and add the chunked filters. + //inputBuffer.addFilter(new GzipInputFilter()); + outputBuffer.addFilter(new GzipOutputFilter()); + + } + + + /** + * Add an input filter to the current request. + * + * @return false if the encoding was not found (which would mean it is + * unsupported) + */ + protected boolean addInputFilter(InputFilter[] inputFilters, + String encodingName) { + if (encodingName.equals("identity")) { + // Skip + } else if (encodingName.equals("chunked")) { + inputBuffer.addActiveFilter + (inputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + } else { + for (int i = 2; i < inputFilters.length; i++) { + if (inputFilters[i].getEncodingName() + .toString().equals(encodingName)) { + inputBuffer.addActiveFilter(inputFilters[i]); + return true; + } + } + return false; + } + return true; + } + + + /** + * Specialized utility method: find a sequence of lower case bytes inside + * a ByteChunk. + */ + protected int findBytes(ByteChunk bc, byte[] b) { + + byte first = b[0]; + byte[] buff = bc.getBuffer(); + int start = bc.getStart(); + int end = bc.getEnd(); + + // Look for first char + int srcEnd = b.length; + + for (int i = start; i <= (end - srcEnd); i++) { + if (Ascii.toLower(buff[i]) != first) continue; + // found first char, now look for a match + int myPos = i+1; + for (int srcPos = 1; srcPos < srcEnd; ) { + if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) + break; + if (srcPos == srcEnd) return i - start; // found it + } + } + return -1; + + } + + /** + * Determine if we must drop the connection because of the HTTP status + * code. Use the same list of codes as Apache/httpd. + */ + protected boolean statusDropsConnection(int status) { + return status == 400 /* SC_BAD_REQUEST */ || + status == 408 /* SC_REQUEST_TIMEOUT */ || + status == 411 /* SC_LENGTH_REQUIRED */ || + status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || + status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || + status == 500 /* SC_INTERNAL_SERVER_ERROR */ || + status == 503 /* SC_SERVICE_UNAVAILABLE */ || + status == 501 /* SC_NOT_IMPLEMENTED */; + } + +} diff --git a/java/org/apache/coyote/http11/Http11NioProtocol.java b/java/org/apache/coyote/http11/Http11NioProtocol.java index 2f41de84b..467849d52 100644 --- a/java/org/apache/coyote/http11/Http11NioProtocol.java +++ b/java/org/apache/coyote/http11/Http11NioProtocol.java @@ -1,758 +1,758 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.net.InetAddress; -import java.net.URLEncoder; -import java.nio.channels.SocketChannel; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executor; -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.RequestGroupInfo; -import org.apache.coyote.RequestInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.net.NioEndpoint; -import org.apache.tomcat.util.net.NioEndpoint.Handler; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Abstract the protocol implementation, including threading, etc. - * Processor is single threaded and specific to stream-based protocols, - * will not fit Jk protocols like JNI. - * - * @author Remy Maucherat - * @author Costin Manolache - * @author Filip Hanik - */ -public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration -{ - public Http11NioProtocol() { - cHandler = new Http11ConnectionHandler( this ); - setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); - setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); - //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); - setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); - } - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - /** Pass config info - */ - public void setAttribute( String name, Object value ) { - if( log.isTraceEnabled()) - log.trace(sm.getString("http11protocol.setattribute", name, value)); - - attributes.put(name, value); - } - - public Object getAttribute( String key ) { - if( log.isTraceEnabled()) - log.trace(sm.getString("http11protocol.getattribute", key)); - return attributes.get(key); - } - - public Iterator getAttributeNames() { - return attributes.keySet().iterator(); - } - - /** - * Set a property. - */ - public void setProperty(String name, String value) { - setAttribute(name, value); - } - - /** - * Get a property - */ - public String getProperty(String name) { - return (String)getAttribute(name); - } - - /** The adapter, used to call the connector - */ - public void setAdapter(Adapter adapter) { - this.adapter=adapter; - } - - public Adapter getAdapter() { - return adapter; - } - - - /** Start the protocol - */ - public void init() throws Exception { - ep.setName(getName()); - ep.setHandler(cHandler); - - try { - ep.init(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.initerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.init", getName())); - - } - - ObjectName tpOname; - ObjectName rgOname; - - public void start() throws Exception { - if( this.domain != null ) { - try { - tpOname=new ObjectName - (domain + ":" + "type=ThreadPool,name=" + getName()); - Registry.getRegistry(null, null) - .registerComponent(ep, tpOname, null ); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - rgOname=new ObjectName - (domain + ":type=GlobalRequestProcessor,name=" + getName()); - Registry.getRegistry(null, null).registerComponent - ( cHandler.global, rgOname, null ); - } - - try { - ep.start(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.starterror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.start", getName())); - } - - public void pause() throws Exception { - try { - ep.pause(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.pause", getName())); - } - - public void resume() throws Exception { - try { - ep.resume(); - } catch (Exception ex) { - log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex); - throw ex; - } - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.resume", getName())); - } - - public void destroy() throws Exception { - if(log.isInfoEnabled()) - log.info(sm.getString("http11protocol.stop", getName())); - ep.destroy(); - if( tpOname!=null ) - Registry.getRegistry(null, null).unregisterComponent(tpOname); - if( rgOname != null ) - Registry.getRegistry(null, null).unregisterComponent(rgOname); - } - - // -------------------- Properties-------------------- - protected NioEndpoint ep=new NioEndpoint(); - protected boolean secure; - - protected Hashtable attributes = new Hashtable(); - - private int maxKeepAliveRequests=100; // as in Apache HTTPD server - private int timeout = 300000; // 5 minutes as in Apache HTTPD server - private int maxSavePostSize = 4 * 1024; - private int maxHttpHeaderSize = 8 * 1024; - private int socketCloseDelay=-1; - private boolean disableUploadTimeout = true; - private int socketBuffer = 9000; - private Adapter adapter; - private Http11ConnectionHandler cHandler; - - /** - * Compression value. - */ - private String compression = "off"; - private String noCompressionUserAgents = null; - private String restrictedUserAgents = null; - private String compressableMimeTypes = "text/html,text/xml,text/plain"; - private int compressionMinSize = 2048; - - private String server; - - // -------------------- Pool setup -------------------- - - // * - public Executor getExecutor() { - return ep.getExecutor(); - } - - // * - public void setExecutor(Executor executor) { - ep.setExecutor(executor); - } - - public int getMaxThreads() { - return ep.getMaxThreads(); - } - - public void setMaxThreads( int maxThreads ) { - ep.setMaxThreads(maxThreads); - setAttribute("maxThreads", "" + maxThreads); - } - - public void setThreadPriority(int threadPriority) { - ep.setThreadPriority(threadPriority); - setAttribute("threadPriority", "" + threadPriority); - } - - public int getThreadPriority() { - return ep.getThreadPriority(); - } - - // -------------------- Tcp setup -------------------- - - public int getBacklog() { - return ep.getBacklog(); - } - - public void setBacklog( int i ) { - ep.setBacklog(i); - setAttribute("backlog", "" + i); - } - - public int getPort() { - return ep.getPort(); - } - - public void setPort( int port ) { - ep.setPort(port); - setAttribute("port", "" + port); - } - - public int getFirstReadTimeout() { - return ep.getFirstReadTimeout(); - } - - public void setFirstReadTimeout( int i ) { - ep.setFirstReadTimeout(i); - setAttribute("firstReadTimeout", "" + i); - } - - public int getPollTime() { - return ep.getPollTime(); - } - - public void setPollTime( int i ) { - ep.setPollTime(i); - setAttribute("pollTime", "" + i); - } - - public void setPollerSize(int i) { - ep.setPollerSize(i); - setAttribute("pollerSize", "" + i); - } - - public int getPollerSize() { - return ep.getPollerSize(); - } - - public InetAddress getAddress() { - return ep.getAddress(); - } - - public void setAddress(InetAddress ia) { - ep.setAddress( ia ); - setAttribute("address", "" + ia); - } - - public String getName() { - String encodedAddr = ""; - if (getAddress() != null) { - encodedAddr = "" + getAddress(); - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) + "-"; - } - return ("http-" + encodedAddr + ep.getPort()); - } - - public boolean getTcpNoDelay() { - return ep.getTcpNoDelay(); - } - - public void setTcpNoDelay( boolean b ) { - ep.setTcpNoDelay( b ); - setAttribute("tcpNoDelay", "" + b); - } - - public boolean getDisableUploadTimeout() { - return disableUploadTimeout; - } - - public void setDisableUploadTimeout(boolean isDisabled) { - disableUploadTimeout = isDisabled; - } - - public int getSocketBuffer() { - return socketBuffer; - } - - public void setSocketBuffer(int valueI) { - socketBuffer = valueI; - } - - public String getCompression() { - return compression; - } - - public void setCompression(String valueS) { - compression = valueS; - setAttribute("compression", valueS); - } - - public int getMaxSavePostSize() { - return maxSavePostSize; - } - - public void setMaxSavePostSize(int valueI) { - maxSavePostSize = valueI; - setAttribute("maxSavePostSize", "" + valueI); - } - - public int getMaxHttpHeaderSize() { - return maxHttpHeaderSize; - } - - public void setMaxHttpHeaderSize(int valueI) { - maxHttpHeaderSize = valueI; - setAttribute("maxHttpHeaderSize", "" + valueI); - } - - public String getRestrictedUserAgents() { - return restrictedUserAgents; - } - - public void setRestrictedUserAgents(String valueS) { - restrictedUserAgents = valueS; - setAttribute("restrictedUserAgents", valueS); - } - - public String getNoCompressionUserAgents() { - return noCompressionUserAgents; - } - - public void setNoCompressionUserAgents(String valueS) { - noCompressionUserAgents = valueS; - setAttribute("noCompressionUserAgents", valueS); - } - - public String getCompressableMimeType() { - return compressableMimeTypes; - } - - public void setCompressableMimeType(String valueS) { - compressableMimeTypes = valueS; - setAttribute("compressableMimeTypes", valueS); - } - - public int getCompressionMinSize() { - return compressionMinSize; - } - - public void setCompressionMinSize(int valueI) { - compressionMinSize = valueI; - setAttribute("compressionMinSize", "" + valueI); - } - - public int getSoLinger() { - return ep.getSoLinger(); - } - - public void setSoLinger( int i ) { - ep.setSoLinger( i ); - setAttribute("soLinger", "" + i); - } - - public int getSoTimeout() { - return ep.getSoTimeout(); - } - - public void setSoTimeout( int i ) { - ep.setSoTimeout(i); - setAttribute("soTimeout", "" + i); - } - - public String getProtocol() { - return getProperty("protocol"); - } - - public void setProtocol( String k ) { - setSecure(true); - setAttribute("protocol", k); - } - - public boolean getSecure() { - return secure; - } - - public void setSecure( boolean b ) { - secure=b; - setAttribute("secure", "" + b); - } - - public int getMaxKeepAliveRequests() { - return maxKeepAliveRequests; - } - - /** Set the maximum number of Keep-Alive requests that we will honor. - */ - public void setMaxKeepAliveRequests(int mkar) { - maxKeepAliveRequests = mkar; - setAttribute("maxKeepAliveRequests", "" + mkar); - } - - /** - * Return the Keep-Alive policy for the connection. - */ - public boolean getKeepAlive() { - return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1)); - } - - /** - * Set the keep-alive policy for this connection. - */ - public void setKeepAlive(boolean keepAlive) { - if (!keepAlive) { - setMaxKeepAliveRequests(1); - } - } - - public int getSocketCloseDelay() { - return socketCloseDelay; - } - - public void setSocketCloseDelay( int d ) { - socketCloseDelay=d; - setAttribute("socketCloseDelay", "" + d); - } - - public void setServer( String server ) { - this.server = server; - } - - public String getServer() { - return server; - } - - public int getTimeout() { - return timeout; - } - - public void setTimeout( int timeouts ) { - timeout = timeouts; - setAttribute("timeout", "" + timeouts); - } - - // -------------------- SSL related properties -------------------- - - /** - * SSL engine. - */ - public String getSSLEngine() { return ep.getSSLEngine(); } - public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); } - - - /** - * SSL protocol. - */ - public String getSSLProtocol() { return ep.getSSLProtocol(); } - public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - public String getSSLPassword() { return ep.getSSLPassword(); } - public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); } - - - /** - * SSL cipher suite. - */ - public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); } - public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); } - - - /** - * SSL certificate file. - */ - public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); } - public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); } - - - /** - * SSL certificate key file. - */ - public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); } - - - /** - * SSL certificate chain file. - */ - public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); } - - - /** - * SSL CA certificate path. - */ - public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); } - public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); } - - - /** - * SSL CA certificate file. - */ - public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); } - public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); } - - - /** - * SSL CA revocation path. - */ - public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); } - public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); } - - - /** - * SSL CA revocation file. - */ - public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); } - public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); } - - - /** - * SSL verify client. - */ - public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); } - public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); } - - - /** - * SSL verify depth. - */ - public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); } - public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); } - - // -------------------- Connection handler -------------------- - - static class Http11ConnectionHandler implements Handler { - - protected Http11NioProtocol proto; - protected static int count = 0; - protected RequestGroupInfo global = new RequestGroupInfo(); - - protected ThreadLocal localProcessor = - new ThreadLocal(); - protected ConcurrentHashMap connections = - new ConcurrentHashMap(); - protected java.util.Stack recycledProcessors = - new java.util.Stack(); - - Http11ConnectionHandler(Http11NioProtocol proto) { - this.proto = proto; - } - - public SocketState event(SocketChannel socket, boolean error) { - Http11NioProcessor result = connections.get(socket); - - SocketState state = SocketState.CLOSED; - if (result != null) { - boolean recycle = error; - // Call the appropriate event - try { - state = result.event(error); - } catch (java.net.SocketException e) { - // SocketExceptions are normal - Http11NioProtocol.log.debug - (sm.getString - ("http11protocol.proto.socketexception.debug"), e); - } catch (java.io.IOException e) { - // IOExceptions are normal - Http11NioProtocol.log.debug - (sm.getString - ("http11protocol.proto.ioexception.debug"), e); - } - // Future developers: if you discover any other - // rare-but-nonfatal exceptions, catch them here, and log as - // above. - catch (Throwable e) { - // any other exception or error is odd. Here we log it - // with "ERROR" level, so it will show up even on - // less-than-verbose logs. - Http11NioProtocol.log.error - (sm.getString("http11protocol.proto.error"), e); - } finally { - if (state != SocketState.LONG) { - connections.remove(socket); - recycledProcessors.push(result); - } - } - } - return state; - } - - public SocketState process(SocketChannel socket) { - Http11NioProcessor processor = null; - try { - processor = (Http11NioProcessor) localProcessor.get(); - if (processor == null) { - synchronized (recycledProcessors) { - if (!recycledProcessors.isEmpty()) { - processor = recycledProcessors.pop(); - localProcessor.set(processor); - } - } - } - if (processor == null) { - processor = - new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep); - processor.setAdapter(proto.adapter); - processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); - processor.setTimeout(proto.timeout); - processor.setDisableUploadTimeout(proto.disableUploadTimeout); - processor.setCompression(proto.compression); - processor.setCompressionMinSize(proto.compressionMinSize); - processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); - processor.setCompressableMimeTypes(proto.compressableMimeTypes); - processor.setRestrictedUserAgents(proto.restrictedUserAgents); - processor.setSocketBuffer(proto.socketBuffer); - processor.setMaxSavePostSize(proto.maxSavePostSize); - processor.setServer(proto.server); - localProcessor.set(processor); - if (proto.getDomain() != null) { - synchronized (this) { - try { - RequestInfo rp = processor.getRequest().getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName rpName = new ObjectName - (proto.getDomain() + ":type=RequestProcessor,worker=" - + proto.getName() + ",name=HttpRequest" + count++); - Registry.getRegistry(null, null).registerComponent(rp, rpName, null); - } catch (Exception e) { - log.warn("Error registering request"); - } - } - } - } - - if (processor instanceof ActionHook) { - ((ActionHook) processor).action(ActionCode.ACTION_START, null); - } - - SocketState state = processor.process(socket); - if (state == SocketState.LONG) { - // Associate the connection with the processor. The next request - // processed by this thread will use either a new or a recycled - // processor. - connections.put(socket, processor); - localProcessor.set(null); - proto.ep.getCometPoller().add(socket); - } - return state; - - } catch (java.net.SocketException e) { - // SocketExceptions are normal - Http11NioProtocol.log.debug - (sm.getString - ("http11protocol.proto.socketexception.debug"), e); - } catch (java.io.IOException e) { - // IOExceptions are normal - Http11NioProtocol.log.debug - (sm.getString - ("http11protocol.proto.ioexception.debug"), e); - } - // Future developers: if you discover any other - // rare-but-nonfatal exceptions, catch them here, and log as - // above. - catch (Throwable e) { - // any other exception or error is odd. Here we log it - // with "ERROR" level, so it will show up even on - // less-than-verbose logs. - Http11NioProtocol.log.error - (sm.getString("http11protocol.proto.error"), e); - } - return SocketState.CLOSED; - } - } - - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(Http11NioProtocol.class); - - // -------------------- Various implementation classes -------------------- - - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception { - oname=name; - mserver=server; - domain=name.getDomain(); - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.net.InetAddress; +import java.net.URLEncoder; +import java.nio.channels.SocketChannel; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executor; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.net.NioEndpoint; +import org.apache.tomcat.util.net.NioEndpoint.Handler; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Abstract the protocol implementation, including threading, etc. + * Processor is single threaded and specific to stream-based protocols, + * will not fit Jk protocols like JNI. + * + * @author Remy Maucherat + * @author Costin Manolache + * @author Filip Hanik + */ +public class Http11NioProtocol implements ProtocolHandler, MBeanRegistration +{ + public Http11NioProtocol() { + cHandler = new Http11ConnectionHandler( this ); + setSoLinger(Constants.DEFAULT_CONNECTION_LINGER); + setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT); + //setServerSoTimeout(Constants.DEFAULT_SERVER_SOCKET_TIMEOUT); + setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY); + } + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + /** Pass config info + */ + public void setAttribute( String name, Object value ) { + if( log.isTraceEnabled()) + log.trace(sm.getString("http11protocol.setattribute", name, value)); + + attributes.put(name, value); + } + + public Object getAttribute( String key ) { + if( log.isTraceEnabled()) + log.trace(sm.getString("http11protocol.getattribute", key)); + return attributes.get(key); + } + + public Iterator getAttributeNames() { + return attributes.keySet().iterator(); + } + + /** + * Set a property. + */ + public void setProperty(String name, String value) { + setAttribute(name, value); + } + + /** + * Get a property + */ + public String getProperty(String name) { + return (String)getAttribute(name); + } + + /** The adapter, used to call the connector + */ + public void setAdapter(Adapter adapter) { + this.adapter=adapter; + } + + public Adapter getAdapter() { + return adapter; + } + + + /** Start the protocol + */ + public void init() throws Exception { + ep.setName(getName()); + ep.setHandler(cHandler); + + try { + ep.init(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.initerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.init", getName())); + + } + + ObjectName tpOname; + ObjectName rgOname; + + public void start() throws Exception { + if( this.domain != null ) { + try { + tpOname=new ObjectName + (domain + ":" + "type=ThreadPool,name=" + getName()); + Registry.getRegistry(null, null) + .registerComponent(ep, tpOname, null ); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + rgOname=new ObjectName + (domain + ":type=GlobalRequestProcessor,name=" + getName()); + Registry.getRegistry(null, null).registerComponent + ( cHandler.global, rgOname, null ); + } + + try { + ep.start(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.starterror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.start", getName())); + } + + public void pause() throws Exception { + try { + ep.pause(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.pauseerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.pause", getName())); + } + + public void resume() throws Exception { + try { + ep.resume(); + } catch (Exception ex) { + log.error(sm.getString("http11protocol.endpoint.resumeerror"), ex); + throw ex; + } + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.resume", getName())); + } + + public void destroy() throws Exception { + if(log.isInfoEnabled()) + log.info(sm.getString("http11protocol.stop", getName())); + ep.destroy(); + if( tpOname!=null ) + Registry.getRegistry(null, null).unregisterComponent(tpOname); + if( rgOname != null ) + Registry.getRegistry(null, null).unregisterComponent(rgOname); + } + + // -------------------- Properties-------------------- + protected NioEndpoint ep=new NioEndpoint(); + protected boolean secure; + + protected Hashtable attributes = new Hashtable(); + + private int maxKeepAliveRequests=100; // as in Apache HTTPD server + private int timeout = 300000; // 5 minutes as in Apache HTTPD server + private int maxSavePostSize = 4 * 1024; + private int maxHttpHeaderSize = 8 * 1024; + private int socketCloseDelay=-1; + private boolean disableUploadTimeout = true; + private int socketBuffer = 9000; + private Adapter adapter; + private Http11ConnectionHandler cHandler; + + /** + * Compression value. + */ + private String compression = "off"; + private String noCompressionUserAgents = null; + private String restrictedUserAgents = null; + private String compressableMimeTypes = "text/html,text/xml,text/plain"; + private int compressionMinSize = 2048; + + private String server; + + // -------------------- Pool setup -------------------- + + // * + public Executor getExecutor() { + return ep.getExecutor(); + } + + // * + public void setExecutor(Executor executor) { + ep.setExecutor(executor); + } + + public int getMaxThreads() { + return ep.getMaxThreads(); + } + + public void setMaxThreads( int maxThreads ) { + ep.setMaxThreads(maxThreads); + setAttribute("maxThreads", "" + maxThreads); + } + + public void setThreadPriority(int threadPriority) { + ep.setThreadPriority(threadPriority); + setAttribute("threadPriority", "" + threadPriority); + } + + public int getThreadPriority() { + return ep.getThreadPriority(); + } + + // -------------------- Tcp setup -------------------- + + public int getBacklog() { + return ep.getBacklog(); + } + + public void setBacklog( int i ) { + ep.setBacklog(i); + setAttribute("backlog", "" + i); + } + + public int getPort() { + return ep.getPort(); + } + + public void setPort( int port ) { + ep.setPort(port); + setAttribute("port", "" + port); + } + + public int getFirstReadTimeout() { + return ep.getFirstReadTimeout(); + } + + public void setFirstReadTimeout( int i ) { + ep.setFirstReadTimeout(i); + setAttribute("firstReadTimeout", "" + i); + } + + public int getPollTime() { + return ep.getPollTime(); + } + + public void setPollTime( int i ) { + ep.setPollTime(i); + setAttribute("pollTime", "" + i); + } + + public void setPollerSize(int i) { + ep.setPollerSize(i); + setAttribute("pollerSize", "" + i); + } + + public int getPollerSize() { + return ep.getPollerSize(); + } + + public InetAddress getAddress() { + return ep.getAddress(); + } + + public void setAddress(InetAddress ia) { + ep.setAddress( ia ); + setAttribute("address", "" + ia); + } + + public String getName() { + String encodedAddr = ""; + if (getAddress() != null) { + encodedAddr = "" + getAddress(); + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) + "-"; + } + return ("http-" + encodedAddr + ep.getPort()); + } + + public boolean getTcpNoDelay() { + return ep.getTcpNoDelay(); + } + + public void setTcpNoDelay( boolean b ) { + ep.setTcpNoDelay( b ); + setAttribute("tcpNoDelay", "" + b); + } + + public boolean getDisableUploadTimeout() { + return disableUploadTimeout; + } + + public void setDisableUploadTimeout(boolean isDisabled) { + disableUploadTimeout = isDisabled; + } + + public int getSocketBuffer() { + return socketBuffer; + } + + public void setSocketBuffer(int valueI) { + socketBuffer = valueI; + } + + public String getCompression() { + return compression; + } + + public void setCompression(String valueS) { + compression = valueS; + setAttribute("compression", valueS); + } + + public int getMaxSavePostSize() { + return maxSavePostSize; + } + + public void setMaxSavePostSize(int valueI) { + maxSavePostSize = valueI; + setAttribute("maxSavePostSize", "" + valueI); + } + + public int getMaxHttpHeaderSize() { + return maxHttpHeaderSize; + } + + public void setMaxHttpHeaderSize(int valueI) { + maxHttpHeaderSize = valueI; + setAttribute("maxHttpHeaderSize", "" + valueI); + } + + public String getRestrictedUserAgents() { + return restrictedUserAgents; + } + + public void setRestrictedUserAgents(String valueS) { + restrictedUserAgents = valueS; + setAttribute("restrictedUserAgents", valueS); + } + + public String getNoCompressionUserAgents() { + return noCompressionUserAgents; + } + + public void setNoCompressionUserAgents(String valueS) { + noCompressionUserAgents = valueS; + setAttribute("noCompressionUserAgents", valueS); + } + + public String getCompressableMimeType() { + return compressableMimeTypes; + } + + public void setCompressableMimeType(String valueS) { + compressableMimeTypes = valueS; + setAttribute("compressableMimeTypes", valueS); + } + + public int getCompressionMinSize() { + return compressionMinSize; + } + + public void setCompressionMinSize(int valueI) { + compressionMinSize = valueI; + setAttribute("compressionMinSize", "" + valueI); + } + + public int getSoLinger() { + return ep.getSoLinger(); + } + + public void setSoLinger( int i ) { + ep.setSoLinger( i ); + setAttribute("soLinger", "" + i); + } + + public int getSoTimeout() { + return ep.getSoTimeout(); + } + + public void setSoTimeout( int i ) { + ep.setSoTimeout(i); + setAttribute("soTimeout", "" + i); + } + + public String getProtocol() { + return getProperty("protocol"); + } + + public void setProtocol( String k ) { + setSecure(true); + setAttribute("protocol", k); + } + + public boolean getSecure() { + return secure; + } + + public void setSecure( boolean b ) { + secure=b; + setAttribute("secure", "" + b); + } + + public int getMaxKeepAliveRequests() { + return maxKeepAliveRequests; + } + + /** Set the maximum number of Keep-Alive requests that we will honor. + */ + public void setMaxKeepAliveRequests(int mkar) { + maxKeepAliveRequests = mkar; + setAttribute("maxKeepAliveRequests", "" + mkar); + } + + /** + * Return the Keep-Alive policy for the connection. + */ + public boolean getKeepAlive() { + return ((maxKeepAliveRequests != 0) && (maxKeepAliveRequests != 1)); + } + + /** + * Set the keep-alive policy for this connection. + */ + public void setKeepAlive(boolean keepAlive) { + if (!keepAlive) { + setMaxKeepAliveRequests(1); + } + } + + public int getSocketCloseDelay() { + return socketCloseDelay; + } + + public void setSocketCloseDelay( int d ) { + socketCloseDelay=d; + setAttribute("socketCloseDelay", "" + d); + } + + public void setServer( String server ) { + this.server = server; + } + + public String getServer() { + return server; + } + + public int getTimeout() { + return timeout; + } + + public void setTimeout( int timeouts ) { + timeout = timeouts; + setAttribute("timeout", "" + timeouts); + } + + // -------------------- SSL related properties -------------------- + + /** + * SSL engine. + */ + public String getSSLEngine() { return ep.getSSLEngine(); } + public void setSSLEngine(String SSLEngine) { ep.setSSLEngine(SSLEngine); } + + + /** + * SSL protocol. + */ + public String getSSLProtocol() { return ep.getSSLProtocol(); } + public void setSSLProtocol(String SSLProtocol) { ep.setSSLProtocol(SSLProtocol); } + + + /** + * SSL password (if a cert is encrypted, and no password has been provided, a callback + * will ask for a password). + */ + public String getSSLPassword() { return ep.getSSLPassword(); } + public void setSSLPassword(String SSLPassword) { ep.setSSLPassword(SSLPassword); } + + + /** + * SSL cipher suite. + */ + public String getSSLCipherSuite() { return ep.getSSLCipherSuite(); } + public void setSSLCipherSuite(String SSLCipherSuite) { ep.setSSLCipherSuite(SSLCipherSuite); } + + + /** + * SSL certificate file. + */ + public String getSSLCertificateFile() { return ep.getSSLCertificateFile(); } + public void setSSLCertificateFile(String SSLCertificateFile) { ep.setSSLCertificateFile(SSLCertificateFile); } + + + /** + * SSL certificate key file. + */ + public String getSSLCertificateKeyFile() { return ep.getSSLCertificateKeyFile(); } + public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { ep.setSSLCertificateKeyFile(SSLCertificateKeyFile); } + + + /** + * SSL certificate chain file. + */ + public String getSSLCertificateChainFile() { return ep.getSSLCertificateChainFile(); } + public void setSSLCertificateChainFile(String SSLCertificateChainFile) { ep.setSSLCertificateChainFile(SSLCertificateChainFile); } + + + /** + * SSL CA certificate path. + */ + public String getSSLCACertificatePath() { return ep.getSSLCACertificatePath(); } + public void setSSLCACertificatePath(String SSLCACertificatePath) { ep.setSSLCACertificatePath(SSLCACertificatePath); } + + + /** + * SSL CA certificate file. + */ + public String getSSLCACertificateFile() { return ep.getSSLCACertificateFile(); } + public void setSSLCACertificateFile(String SSLCACertificateFile) { ep.setSSLCACertificateFile(SSLCACertificateFile); } + + + /** + * SSL CA revocation path. + */ + public String getSSLCARevocationPath() { return ep.getSSLCARevocationPath(); } + public void setSSLCARevocationPath(String SSLCARevocationPath) { ep.setSSLCARevocationPath(SSLCARevocationPath); } + + + /** + * SSL CA revocation file. + */ + public String getSSLCARevocationFile() { return ep.getSSLCARevocationFile(); } + public void setSSLCARevocationFile(String SSLCARevocationFile) { ep.setSSLCARevocationFile(SSLCARevocationFile); } + + + /** + * SSL verify client. + */ + public String getSSLVerifyClient() { return ep.getSSLVerifyClient(); } + public void setSSLVerifyClient(String SSLVerifyClient) { ep.setSSLVerifyClient(SSLVerifyClient); } + + + /** + * SSL verify depth. + */ + public int getSSLVerifyDepth() { return ep.getSSLVerifyDepth(); } + public void setSSLVerifyDepth(int SSLVerifyDepth) { ep.setSSLVerifyDepth(SSLVerifyDepth); } + + // -------------------- Connection handler -------------------- + + static class Http11ConnectionHandler implements Handler { + + protected Http11NioProtocol proto; + protected static int count = 0; + protected RequestGroupInfo global = new RequestGroupInfo(); + + protected ThreadLocal localProcessor = + new ThreadLocal(); + protected ConcurrentHashMap connections = + new ConcurrentHashMap(); + protected java.util.Stack recycledProcessors = + new java.util.Stack(); + + Http11ConnectionHandler(Http11NioProtocol proto) { + this.proto = proto; + } + + public SocketState event(SocketChannel socket, boolean error) { + Http11NioProcessor result = connections.get(socket); + + SocketState state = SocketState.CLOSED; + if (result != null) { + boolean recycle = error; + // Call the appropriate event + try { + state = result.event(error); + } catch (java.net.SocketException e) { + // SocketExceptions are normal + Http11NioProtocol.log.debug + (sm.getString + ("http11protocol.proto.socketexception.debug"), e); + } catch (java.io.IOException e) { + // IOExceptions are normal + Http11NioProtocol.log.debug + (sm.getString + ("http11protocol.proto.ioexception.debug"), e); + } + // Future developers: if you discover any other + // rare-but-nonfatal exceptions, catch them here, and log as + // above. + catch (Throwable e) { + // any other exception or error is odd. Here we log it + // with "ERROR" level, so it will show up even on + // less-than-verbose logs. + Http11NioProtocol.log.error + (sm.getString("http11protocol.proto.error"), e); + } finally { + if (state != SocketState.LONG) { + connections.remove(socket); + recycledProcessors.push(result); + } + } + } + return state; + } + + public SocketState process(SocketChannel socket) { + Http11NioProcessor processor = null; + try { + processor = (Http11NioProcessor) localProcessor.get(); + if (processor == null) { + synchronized (recycledProcessors) { + if (!recycledProcessors.isEmpty()) { + processor = recycledProcessors.pop(); + localProcessor.set(processor); + } + } + } + if (processor == null) { + processor = + new Http11NioProcessor(proto.maxHttpHeaderSize, proto.ep); + processor.setAdapter(proto.adapter); + processor.setMaxKeepAliveRequests(proto.maxKeepAliveRequests); + processor.setTimeout(proto.timeout); + processor.setDisableUploadTimeout(proto.disableUploadTimeout); + processor.setCompression(proto.compression); + processor.setCompressionMinSize(proto.compressionMinSize); + processor.setNoCompressionUserAgents(proto.noCompressionUserAgents); + processor.setCompressableMimeTypes(proto.compressableMimeTypes); + processor.setRestrictedUserAgents(proto.restrictedUserAgents); + processor.setSocketBuffer(proto.socketBuffer); + processor.setMaxSavePostSize(proto.maxSavePostSize); + processor.setServer(proto.server); + localProcessor.set(processor); + if (proto.getDomain() != null) { + synchronized (this) { + try { + RequestInfo rp = processor.getRequest().getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName rpName = new ObjectName + (proto.getDomain() + ":type=RequestProcessor,worker=" + + proto.getName() + ",name=HttpRequest" + count++); + Registry.getRegistry(null, null).registerComponent(rp, rpName, null); + } catch (Exception e) { + log.warn("Error registering request"); + } + } + } + } + + if (processor instanceof ActionHook) { + ((ActionHook) processor).action(ActionCode.ACTION_START, null); + } + + SocketState state = processor.process(socket); + if (state == SocketState.LONG) { + // Associate the connection with the processor. The next request + // processed by this thread will use either a new or a recycled + // processor. + connections.put(socket, processor); + localProcessor.set(null); + proto.ep.getCometPoller().add(socket); + } + return state; + + } catch (java.net.SocketException e) { + // SocketExceptions are normal + Http11NioProtocol.log.debug + (sm.getString + ("http11protocol.proto.socketexception.debug"), e); + } catch (java.io.IOException e) { + // IOExceptions are normal + Http11NioProtocol.log.debug + (sm.getString + ("http11protocol.proto.ioexception.debug"), e); + } + // Future developers: if you discover any other + // rare-but-nonfatal exceptions, catch them here, and log as + // above. + catch (Throwable e) { + // any other exception or error is odd. Here we log it + // with "ERROR" level, so it will show up even on + // less-than-verbose logs. + Http11NioProtocol.log.error + (sm.getString("http11protocol.proto.error"), e); + } + return SocketState.CLOSED; + } + } + + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(Http11NioProtocol.class); + + // -------------------- Various implementation classes -------------------- + + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception { + oname=name; + mserver=server; + domain=name.getDomain(); + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } +} diff --git a/java/org/apache/coyote/http11/Http11Processor.java b/java/org/apache/coyote/http11/Http11Processor.java index 11cd2ec99..58c823071 100644 --- a/java/org/apache/coyote/http11/Http11Processor.java +++ b/java/org/apache/coyote/http11/Http11Processor.java @@ -1,1671 +1,1671 @@ -/* - * Copyright 1999-2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.InetAddress; -import java.net.Socket; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.StringTokenizer; -import java.util.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Adapter; -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Response; -import org.apache.coyote.http11.filters.BufferedInputFilter; -import org.apache.coyote.http11.filters.ChunkedInputFilter; -import org.apache.coyote.http11.filters.ChunkedOutputFilter; -import org.apache.coyote.http11.filters.GzipOutputFilter; -import org.apache.coyote.http11.filters.IdentityInputFilter; -import org.apache.coyote.http11.filters.IdentityOutputFilter; -import org.apache.coyote.http11.filters.SavedRequestInputFilter; -import org.apache.coyote.http11.filters.VoidInputFilter; -import org.apache.coyote.http11.filters.VoidOutputFilter; -import org.apache.tomcat.util.buf.Ascii; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.FastHttpDateFormat; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.net.JIoEndpoint; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.res.StringManager; - - -/** - * Processes HTTP requests. - * - * @author Remy Maucherat - */ -public class Http11Processor implements ActionHook { - - - /** - * Logger. - */ - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(Http11Processor.class); - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ------------------------------------------------------------ Constructor - - - public Http11Processor(int headerBufferSize, JIoEndpoint endpoint) { - - this.endpoint = endpoint; - - request = new Request(); - inputBuffer = new InternalInputBuffer(request, headerBufferSize); - request.setInputBuffer(inputBuffer); - - response = new Response(); - response.setHook(this); - outputBuffer = new InternalOutputBuffer(response, headerBufferSize); - response.setOutputBuffer(outputBuffer); - request.setResponse(response); - - initializeFilters(); - - // Cause loading of HexUtils - int foo = HexUtils.DEC[0]; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated adapter. - */ - protected Adapter adapter = null; - - - /** - * Request object. - */ - protected Request request = null; - - - /** - * Response object. - */ - protected Response response = null; - - - /** - * Input. - */ - protected InternalInputBuffer inputBuffer = null; - - - /** - * Output. - */ - protected InternalOutputBuffer outputBuffer = null; - - - /** - * State flag. - */ - protected boolean started = false; - - - /** - * Error flag. - */ - protected boolean error = false; - - - /** - * Keep-alive. - */ - protected boolean keepAlive = true; - - - /** - * HTTP/1.1 flag. - */ - protected boolean http11 = true; - - - /** - * HTTP/0.9 flag. - */ - protected boolean http09 = false; - - - /** - * Content delimitator for the request (if false, the connection will - * be closed at the end of the request). - */ - protected boolean contentDelimitation = true; - - - /** - * Is there an expectation ? - */ - protected boolean expectation = false; - - - /** - * List of restricted user agents. - */ - protected Pattern[] restrictedUserAgents = null; - - - /** - * Maximum number of Keep-Alive requests to honor. - */ - protected int maxKeepAliveRequests = -1; - - - /** - * SSL information. - */ - protected SSLSupport sslSupport; - - - /** - * Socket associated with the current connection. - */ - protected Socket socket; - - - /** - * Remote Address associated with the current connection. - */ - protected String remoteAddr = null; - - - /** - * Remote Host associated with the current connection. - */ - protected String remoteHost = null; - - - /** - * Local Host associated with the current connection. - */ - protected String localName = null; - - - - /** - * Local port to which the socket is connected - */ - protected int localPort = -1; - - - /** - * Remote port to which the socket is connected - */ - protected int remotePort = -1; - - - /** - * The local Host address. - */ - protected String localAddr = null; - - - /** - * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. - */ - protected int timeout = 300000; - - - /** - * Flag to disable setting a different time-out on uploads. - */ - protected boolean disableUploadTimeout = false; - - - /** - * Allowed compression level. - */ - protected int compressionLevel = 0; - - - /** - * Minimum contentsize to make compression. - */ - protected int compressionMinSize = 2048; - - - /** - * Socket buffering. - */ - protected int socketBuffer = -1; - - - /** - * Max saved post size. - */ - protected int maxSavePostSize = 4 * 1024; - - - /** - * List of user agents to not use gzip with - */ - protected Pattern noCompressionUserAgents[] = null; - - /** - * List of MIMES which could be gzipped - */ - protected String[] compressableMimeTypes = - { "text/html", "text/xml", "text/plain" }; - - - /** - * Host name (used to avoid useless B2C conversion on the host name). - */ - protected char[] hostNameC = new char[0]; - - - /** - * Associated endpoint. - */ - protected JIoEndpoint endpoint; - - - /** - * Allow a customized the server header for the tin-foil hat folks. - */ - protected String server = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return compression level. - */ - public String getCompression() { - switch (compressionLevel) { - case 0: - return "off"; - case 1: - return "on"; - case 2: - return "force"; - } - return "off"; - } - - - /** - * Set compression level. - */ - public void setCompression(String compression) { - if (compression.equals("on")) { - this.compressionLevel = 1; - } else if (compression.equals("force")) { - this.compressionLevel = 2; - } else if (compression.equals("off")) { - this.compressionLevel = 0; - } else { - try { - // Try to parse compression as an int, which would give the - // minimum compression size - compressionMinSize = Integer.parseInt(compression); - this.compressionLevel = 1; - } catch (Exception e) { - this.compressionLevel = 0; - } - } - } - - /** - * Set Minimum size to trigger compression. - */ - public void setCompressionMinSize(int compressionMinSize) { - this.compressionMinSize = compressionMinSize; - } - - - /** - * Add user-agent for which gzip compression didn't works - * The user agent String given will be exactly matched - * to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addNoCompressionUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - noCompressionUserAgents = - addREArray(noCompressionUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set no compression user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { - this.noCompressionUserAgents = noCompressionUserAgents; - } - - - /** - * Set no compression user agent list. - * List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setNoCompressionUserAgents(String noCompressionUserAgents) { - if (noCompressionUserAgents != null) { - StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); - - while (st.hasMoreTokens()) { - addNoCompressionUserAgent(st.nextToken().trim()); - } - } - } - - /** - * Add a mime-type which will be compressable - * The mime-type String will be exactly matched - * in the response mime-type header . - * - * @param mimeType mime-type string - */ - public void addCompressableMimeType(String mimeType) { - compressableMimeTypes = - addStringArray(compressableMimeTypes, mimeType); - } - - - /** - * Set compressable mime-type list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setCompressableMimeTypes(String[] compressableMimeTypes) { - this.compressableMimeTypes = compressableMimeTypes; - } - - - /** - * Set compressable mime-type list - * List contains users agents separated by ',' : - * - * ie: "text/html,text/xml,text/plain" - */ - public void setCompressableMimeTypes(String compressableMimeTypes) { - if (compressableMimeTypes != null) { - StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); - - while (st.hasMoreTokens()) { - addCompressableMimeType(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findCompressableMimeTypes() { - return (compressableMimeTypes); - } - - - - // --------------------------------------------------------- Public Methods - - - /** - * Add input or output filter. - * - * @param className class name of the filter - */ - protected void addFilter(String className) { - try { - Class clazz = Class.forName(className); - Object obj = clazz.newInstance(); - if (obj instanceof InputFilter) { - inputBuffer.addFilter((InputFilter) obj); - } else if (obj instanceof OutputFilter) { - outputBuffer.addFilter((OutputFilter) obj); - } else { - log.warn(sm.getString("http11processor.filter.unknown", className)); - } - } catch (Exception e) { - log.error(sm.getString("http11processor.filter.error", className), e); - } - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private String[] addStringArray(String sArray[], String value) { - String[] result = null; - if (sArray == null) { - result = new String[1]; - result[0] = value; - } - else { - result = new String[sArray.length + 1]; - for (int i = 0; i < sArray.length; i++) - result[i] = sArray[i]; - result[sArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param rArray the REArray - * @param value Obj - */ - private Pattern[] addREArray(Pattern rArray[], Pattern value) { - Pattern[] result = null; - if (rArray == null) { - result = new Pattern[1]; - result[0] = value; - } - else { - result = new Pattern[rArray.length + 1]; - for (int i = 0; i < rArray.length; i++) - result[i] = rArray[i]; - result[rArray.length] = value; - } - return result; - } - - - /** - * General use method - * - * @param sArray the StringArray - * @param value string - */ - private boolean inStringArray(String sArray[], String value) { - for (int i = 0; i < sArray.length; i++) { - if (sArray[i].equals(value)) { - return true; - } - } - return false; - } - - - /** - * Checks if any entry in the string array starts with the specified value - * - * @param sArray the StringArray - * @param value string - */ - private boolean startsWithStringArray(String sArray[], String value) { - if (value == null) - return false; - for (int i = 0; i < sArray.length; i++) { - if (value.startsWith(sArray[i])) { - return true; - } - } - return false; - } - - - /** - * Add restricted user-agent (which will downgrade the connector - * to HTTP/1.0 mode). The user agent String given will be matched - * via regexp to the user-agent header submitted by the client. - * - * @param userAgent user-agent string - */ - public void addRestrictedUserAgent(String userAgent) { - try { - Pattern nRule = Pattern.compile(userAgent); - restrictedUserAgents = addREArray(restrictedUserAgents, nRule); - } catch (PatternSyntaxException pse) { - log.error(sm.getString("http11processor.regexp.error", userAgent), pse); - } - } - - - /** - * Set restricted user agent list (this method is best when used with - * a large number of connectors, where it would be better to have all of - * them referenced a single array). - */ - public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { - this.restrictedUserAgents = restrictedUserAgents; - } - - - /** - * Set restricted user agent list (which will downgrade the connector - * to HTTP/1.0 mode). List contains users agents separated by ',' : - * - * ie: "gorilla,desesplorer,tigrus" - */ - public void setRestrictedUserAgents(String restrictedUserAgents) { - if (restrictedUserAgents != null) { - StringTokenizer st = - new StringTokenizer(restrictedUserAgents, ","); - while (st.hasMoreTokens()) { - addRestrictedUserAgent(st.nextToken().trim()); - } - } - } - - - /** - * Return the list of restricted user agents. - */ - public String[] findRestrictedUserAgents() { - String[] sarr = new String [restrictedUserAgents.length]; - - for (int i = 0; i < restrictedUserAgents.length; i++) - sarr[i] = restrictedUserAgents[i].toString(); - - return (sarr); - } - - - /** - * Set the maximum number of Keep-Alive requests to honor. - * This is to safeguard from DoS attacks. Setting to a negative - * value disables the check. - */ - public void setMaxKeepAliveRequests(int mkar) { - maxKeepAliveRequests = mkar; - } - - - /** - * Return the number of Keep-Alive requests that we will honor. - */ - public int getMaxKeepAliveRequests() { - return maxKeepAliveRequests; - } - - - /** - * Set the maximum size of a POST which will be buffered in SSL mode. - */ - public void setMaxSavePostSize(int msps) { - maxSavePostSize = msps; - } - - - /** - * Return the maximum size of a POST which will be buffered in SSL mode. - */ - public int getMaxSavePostSize() { - return maxSavePostSize; - } - - - /** - * Set the SSL information for this HTTP connection. - */ - public void setSSLSupport(SSLSupport sslSupport) { - this.sslSupport = sslSupport; - } - - - /** - * Set the flag to control upload time-outs. - */ - public void setDisableUploadTimeout(boolean isDisabled) { - disableUploadTimeout = isDisabled; - } - - /** - * Get the flag that controls upload time-outs. - */ - public boolean getDisableUploadTimeout() { - return disableUploadTimeout; - } - - /** - * Set the socket buffer flag. - */ - public void setSocketBuffer(int socketBuffer) { - this.socketBuffer = socketBuffer; - outputBuffer.setSocketBuffer(socketBuffer); - } - - /** - * Get the socket buffer flag. - */ - public int getSocketBuffer() { - return socketBuffer; - } - - /** - * Set the upload timeout. - */ - public void setTimeout( int timeouts ) { - timeout = timeouts ; - } - - /** - * Get the upload timeout. - */ - public int getTimeout() { - return timeout; - } - - - /** - * Set the server header name. - */ - public void setServer( String server ) { - if (server==null || server.equals("")) { - this.server = null; - } else { - this.server = server; - } - } - - /** - * Get the server header name. - */ - public String getServer() { - return server; - } - - - /** Get the request associated with this processor. - * - * @return The request - */ - public Request getRequest() { - return request; - } - - /** - * Process pipelined HTTP requests using the specified input and output - * streams. - * - * @param input stream from which the HTTP requests will be read - * @param output stream which will be used to output the HTTP - * responses - * @throws IOException error during an I/O operation - */ - public void process(Socket socket) - throws IOException { - RequestInfo rp = request.getRequestProcessor(); - rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); - - // Set the remote address - remoteAddr = null; - remoteHost = null; - localAddr = null; - localName = null; - remotePort = -1; - localPort = -1; - - // Setting up the I/O - this.socket = socket; - inputBuffer.setInputStream(socket.getInputStream()); - outputBuffer.setOutputStream(socket.getOutputStream()); - - // Error flag - error = false; - keepAlive = true; - - int keepAliveLeft = maxKeepAliveRequests; - int soTimeout = socket.getSoTimeout(); - int oldSoTimeout = soTimeout; - - int threadRatio = (endpoint.getCurrentThreadsBusy() * 100) - / endpoint.getMaxThreads(); - if ((threadRatio > 33) && (threadRatio <= 66)) { - soTimeout = soTimeout / 2; - } else if ((threadRatio > 66) && (threadRatio <= 90)) { - soTimeout = soTimeout / 3; - keepAliveLeft = 1; - } else if (threadRatio > 90) { - soTimeout = soTimeout / 20; - keepAliveLeft = 1; - } - - if (soTimeout != oldSoTimeout) { - try { - socket.setSoTimeout(soTimeout); - } catch (Throwable t) { - log.debug(sm.getString("http11processor.socket.timeout"), t); - error = true; - } - } - - boolean keptAlive = false; - - while (started && !error && keepAlive) { - - // Parsing the request header - try { - if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { - socket.setSoTimeout(soTimeout); - } - inputBuffer.parseRequestLine(); - request.setStartTime(System.currentTimeMillis()); - keptAlive = true; - if (!disableUploadTimeout) { - socket.setSoTimeout(timeout); - } - inputBuffer.parseHeaders(); - } catch (IOException e) { - error = true; - break; - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.header.parse"), t); - } - // 400 - Bad Request - response.setStatus(400); - error = true; - } - - // Setting up filters, and parse some request headers - rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); - try { - prepareRequest(); - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("http11processor.request.prepare"), t); - } - // 400 - Internal Server Error - response.setStatus(400); - error = true; - } - - if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) - keepAlive = false; - - // Process the request in the adapter - if (!error) { - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - adapter.service(request, response); - // Handle when the response was committed before a serious - // error occurred. Throwing a ServletException should both - // set the status to 500 and set the errorException. - // If we fail here, then the response is likely already - // committed, so we can't try and set headers. - if(keepAlive && !error) { // Avoid checking twice. - error = response.getErrorException() != null || - statusDropsConnection(response.getStatus()); - } - - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.process"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - } - - // Finish the handling of the request - try { - rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT); - inputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.request.finish"), t); - // 500 - Internal Server Error - response.setStatus(500); - error = true; - } - try { - rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT); - outputBuffer.endRequest(); - } catch (IOException e) { - error = true; - } catch (Throwable t) { - log.error(sm.getString("http11processor.response.finish"), t); - error = true; - } - - // If there was an error, make sure the request is counted as - // and error, and update the statistics counter - if (error) { - response.setStatus(500); - } - request.updateCounters(); - - rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); - - // Don't reset the param - we'll see it as ended. Next request - // will reset it - // thrA.setParam(null); - // Next request - inputBuffer.nextRequest(); - outputBuffer.nextRequest(); - - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - // Recycle - inputBuffer.recycle(); - outputBuffer.recycle(); - - // Recycle ssl info - sslSupport = null; - } - - - // ----------------------------------------------------- ActionHook Methods - - - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - public void action(ActionCode actionCode, Object param) { - - if (actionCode == ActionCode.ACTION_COMMIT) { - // Commit current response - - if (response.isCommitted()) - return; - - // Validate and write response headers - prepareResponse(); - try { - outputBuffer.commit(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_ACK) { - - // Acknowlege request - - // Send a 100 status back if it makes sense (response not committed - // yet, and client specified an expectation for 100-continue) - - if ((response.isCommitted()) || !expectation) - return; - - inputBuffer.setSwallowInput(true); - try { - outputBuffer.sendAck(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { - - try { - outputBuffer.flush(); - } catch (IOException e) { - // Set error flag - error = true; - response.setErrorException(e); - } - - } else if (actionCode == ActionCode.ACTION_CLOSE) { - // Close - - // End the processing of the current request, and stop any further - // transactions with the client - - try { - outputBuffer.endRequest(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.ACTION_RESET) { - - // Reset response - - // Note: This must be called before the response is committed - - outputBuffer.reset(); - - } else if (actionCode == ActionCode.ACTION_CUSTOM) { - - // Do nothing - - } else if (actionCode == ActionCode.ACTION_START) { - - started = true; - - } else if (actionCode == ActionCode.ACTION_STOP) { - - started = false; - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { - - try { - if (sslSupport != null) { - Object sslO = sslSupport.getCipherSuite(); - if (sslO != null) - request.setAttribute - (SSLSupport.CIPHER_SUITE_KEY, sslO); - sslO = sslSupport.getPeerCertificateChain(false); - if (sslO != null) - request.setAttribute - (SSLSupport.CERTIFICATE_KEY, sslO); - sslO = sslSupport.getKeySize(); - if (sslO != null) - request.setAttribute - (SSLSupport.KEY_SIZE_KEY, sslO); - sslO = sslSupport.getSessionId(); - if (sslO != null) - request.setAttribute - (SSLSupport.SESSION_ID_KEY, sslO); - } - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.ssl"), e); - } - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { - - if ((remoteAddr == null) && (socket != null)) { - InetAddress inetAddr = socket.getInetAddress(); - if (inetAddr != null) { - remoteAddr = inetAddr.getHostAddress(); - } - } - request.remoteAddr().setString(remoteAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { - - if ((localName == null) && (socket != null)) { - InetAddress inetAddr = socket.getLocalAddress(); - if (inetAddr != null) { - localName = inetAddr.getHostName(); - } - } - request.localName().setString(localName); - - } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { - - if ((remoteHost == null) && (socket != null)) { - InetAddress inetAddr = socket.getInetAddress(); - if (inetAddr != null) { - remoteHost = inetAddr.getHostName(); - } - if(remoteHost == null) { - if(remoteAddr != null) { - remoteHost = remoteAddr; - } else { // all we can do is punt - request.remoteHost().recycle(); - } - } - } - request.remoteHost().setString(remoteHost); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { - - if (localAddr == null) - localAddr = socket.getLocalAddress().getHostAddress(); - - request.localAddr().setString(localAddr); - - } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { - - if ((remotePort == -1 ) && (socket !=null)) { - remotePort = socket.getPort(); - } - request.setRemotePort(remotePort); - - } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { - - if ((localPort == -1 ) && (socket !=null)) { - localPort = socket.getLocalPort(); - } - request.setLocalPort(localPort); - - } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { - if( sslSupport != null) { - /* - * Consume and buffer the request body, so that it does not - * interfere with the client's handshake messages - */ - InputFilter[] inputFilters = inputBuffer.getFilters(); - ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) - .setLimit(maxSavePostSize); - inputBuffer.addActiveFilter - (inputFilters[Constants.BUFFERED_FILTER]); - try { - Object sslO = sslSupport.getPeerCertificateChain(true); - if( sslO != null) { - request.setAttribute - (SSLSupport.CERTIFICATE_KEY, sslO); - } - } catch (Exception e) { - log.warn(sm.getString("http11processor.socket.ssl"), e); - } - } - } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { - ByteChunk body = (ByteChunk) param; - - InputFilter savedBody = new SavedRequestInputFilter(body); - savedBody.setRequest(request); - - InternalInputBuffer internalBuffer = (InternalInputBuffer) - request.getInputBuffer(); - internalBuffer.addActiveFilter(savedBody); - } - - } - - - // ------------------------------------------------------ Connector Methods - - - /** - * Set the associated adapter. - * - * @param adapter the new adapter - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - - /** - * Get the associated adapter. - * - * @return the associated adapter - */ - public Adapter getAdapter() { - return adapter; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * After reading the request headers, we have to setup the request filters. - */ - protected void prepareRequest() { - - http11 = true; - http09 = false; - contentDelimitation = false; - expectation = false; - if (sslSupport != null) { - request.scheme().setString("https"); - } - MessageBytes protocolMB = request.protocol(); - if (protocolMB.equals(Constants.HTTP_11)) { - http11 = true; - protocolMB.setString(Constants.HTTP_11); - } else if (protocolMB.equals(Constants.HTTP_10)) { - http11 = false; - keepAlive = false; - protocolMB.setString(Constants.HTTP_10); - } else if (protocolMB.equals("")) { - // HTTP/0.9 - http09 = true; - http11 = false; - keepAlive = false; - } else { - // Unsupported protocol - http11 = false; - error = true; - // Send 505; Unsupported HTTP version - response.setStatus(505); - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals(Constants.GET)) { - methodMB.setString(Constants.GET); - } else if (methodMB.equals(Constants.POST)) { - methodMB.setString(Constants.POST); - } - - MimeHeaders headers = request.getMimeHeaders(); - - // Check connection header - MessageBytes connectionValueMB = headers.getValue("connection"); - if (connectionValueMB != null) { - ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); - if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { - keepAlive = false; - } else if (findBytes(connectionValueBC, - Constants.KEEPALIVE_BYTES) != -1) { - keepAlive = true; - } - } - - MessageBytes expectMB = null; - if (http11) - expectMB = headers.getValue("expect"); - if ((expectMB != null) - && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { - inputBuffer.setSwallowInput(false); - expectation = true; - } - - // Check user-agent header - if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { - MessageBytes userAgentValueMB = headers.getValue("user-agent"); - // Check in the restricted list, and adjust the http11 - // and keepAlive flags accordingly - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - for (int i = 0; i < restrictedUserAgents.length; i++) { - if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { - http11 = false; - keepAlive = false; - break; - } - } - } - } - - // Check for a full URI (including protocol://host:port/) - ByteChunk uriBC = request.requestURI().getByteChunk(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - - int pos = uriBC.indexOf("://", 0, 3, 4); - int uriBCStart = uriBC.getStart(); - int slashPos = -1; - if (pos != -1) { - byte[] uriB = uriBC.getBytes(); - slashPos = uriBC.indexOf('/', pos + 3); - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/" - request.requestURI().setBytes - (uriB, uriBCStart + pos + 1, 1); - } else { - request.requestURI().setBytes - (uriB, uriBCStart + slashPos, - uriBC.getLength() - slashPos); - } - MessageBytes hostMB = headers.setValue("host"); - hostMB.setBytes(uriB, uriBCStart + pos + 3, - slashPos - pos - 3); - } - - } - - // Input filter setup - InputFilter[] inputFilters = inputBuffer.getFilters(); - - // Parse transfer-encoding header - MessageBytes transferEncodingValueMB = null; - if (http11) - transferEncodingValueMB = headers.getValue("transfer-encoding"); - if (transferEncodingValueMB != null) { - String transferEncodingValue = transferEncodingValueMB.toString(); - // Parse the comma separated list. "identity" codings are ignored - int startPos = 0; - int commaPos = transferEncodingValue.indexOf(','); - String encodingName = null; - while (commaPos != -1) { - encodingName = transferEncodingValue.substring - (startPos, commaPos).toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - startPos = commaPos + 1; - commaPos = transferEncodingValue.indexOf(',', startPos); - } - encodingName = transferEncodingValue.substring(startPos) - .toLowerCase().trim(); - if (!addInputFilter(inputFilters, encodingName)) { - // Unsupported transfer encoding - error = true; - // 501 - Unimplemented - response.setStatus(501); - } - } - - // Parse content-length header - long contentLength = request.getContentLengthLong(); - if (contentLength >= 0 && !contentDelimitation) { - inputBuffer.addActiveFilter - (inputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } - - MessageBytes valueMB = headers.getValue("host"); - - // Check host header - if (http11 && (valueMB == null)) { - error = true; - // 400 - Bad request - response.setStatus(400); - } - - parseHost(valueMB); - - if (!contentDelimitation) { - // If there's no content length - // (broken HTTP/1.0 or HTTP/1.1), assume - // the client is not broken and didn't send a body - inputBuffer.addActiveFilter - (inputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - } - - - /** - * Parse host. - */ - public void parseHost(MessageBytes valueMB) { - - if (valueMB == null || valueMB.isNull()) { - // HTTP/1.0 - // Default is what the socket tells us. Overriden if a host is - // found/parsed - request.setServerPort(socket.getLocalPort()); - InetAddress localAddress = socket.getLocalAddress(); - // Setting the socket-related fields. The adapter doesn't know - // about socket. - request.serverName().setString(localAddress.getHostName()); - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - if (hostNameC.length < valueL) { - hostNameC = new char[valueL]; - } - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC[i] = b; - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (sslSupport == null) { - // 80 - Default HTTP port - request.setServerPort(80); - } else { - // 443 - Default HTTPS port - request.setServerPort(443); - } - request.serverName().setChars(hostNameC, 0, valueL); - } else { - - request.serverName().setChars(hostNameC, 0, colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; - if (charValue == -1) { - // Invalid character - error = true; - // 400 - Bad request - response.setStatus(400); - break; - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - - } - - } - - - /** - * Check for compression - */ - private boolean isCompressable() { - - // Nope Compression could works in HTTP 1.0 also - // cf: mod_deflate - - // Compression only since HTTP 1.1 - // if (! http11) - // return false; - - // Check if browser support gzip encoding - MessageBytes acceptEncodingMB = - request.getMimeHeaders().getValue("accept-encoding"); - - if ((acceptEncodingMB == null) - || (acceptEncodingMB.indexOf("gzip") == -1)) - return false; - - // Check if content is not allready gzipped - MessageBytes contentEncodingMB = - response.getMimeHeaders().getValue("Content-Encoding"); - - if ((contentEncodingMB != null) - && (contentEncodingMB.indexOf("gzip") != -1)) - return false; - - // If force mode, allways compress (test purposes only) - if (compressionLevel == 2) - return true; - - // Check for incompatible Browser - if (noCompressionUserAgents != null) { - MessageBytes userAgentValueMB = - request.getMimeHeaders().getValue("user-agent"); - if(userAgentValueMB != null) { - String userAgentValue = userAgentValueMB.toString(); - - // If one Regexp rule match, disable compression - for (int i = 0; i < noCompressionUserAgents.length; i++) - if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) - return false; - } - } - - // Check if suffisant len to trig the compression - long contentLength = response.getContentLengthLong(); - if ((contentLength == -1) - || (contentLength > compressionMinSize)) { - // Check for compatible MIME-TYPE - if (compressableMimeTypes != null) { - return (startsWithStringArray(compressableMimeTypes, - response.getContentType())); - } - } - - return false; - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - protected void prepareResponse() { - - boolean entityBody = true; - contentDelimitation = false; - - OutputFilter[] outputFilters = outputBuffer.getFilters(); - - if (http09 == true) { - // HTTP/0.9 - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - return; - } - - int statusCode = response.getStatus(); - if ((statusCode == 204) || (statusCode == 205) - || (statusCode == 304)) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - entityBody = false; - contentDelimitation = true; - } - - MessageBytes methodMB = request.method(); - if (methodMB.equals("HEAD")) { - // No entity body - outputBuffer.addActiveFilter - (outputFilters[Constants.VOID_FILTER]); - contentDelimitation = true; - } - - // Check for compression - boolean useCompression = false; - if (entityBody && (compressionLevel > 0)) { - useCompression = isCompressable(); - - // Change content-length to -1 to force chunking - if (useCompression) { - response.setContentLength(-1); - } - } - - MimeHeaders headers = response.getMimeHeaders(); - if (!entityBody) { - response.setContentLength(-1); - } else { - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language") - .setString(contentLanguage); - } - } - - long contentLength = response.getContentLengthLong(); - if (contentLength != -1) { - headers.setValue("Content-Length").setLong(contentLength); - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - contentDelimitation = true; - } else { - if (entityBody && http11 && keepAlive) { - outputBuffer.addActiveFilter - (outputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); - } else { - outputBuffer.addActiveFilter - (outputFilters[Constants.IDENTITY_FILTER]); - } - } - - if (useCompression) { - outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); - headers.setValue("Content-Encoding").setString("gzip"); - // Make Proxies happy via Vary (from mod_deflate) - headers.setValue("Vary").setString("Accept-Encoding"); - } - - // Add date header - String date = null; - if (System.getSecurityManager() != null){ - date = (String)AccessController.doPrivileged( - new PrivilegedAction() { - public Object run(){ - return FastHttpDateFormat.getCurrentDate(); - } - } - ); - } else { - date = FastHttpDateFormat.getCurrentDate(); - } - headers.setValue("Date").setString(date); - - // FIXME: Add transfer encoding header - - if ((entityBody) && (!contentDelimitation)) { - // Mark as close the connection after the request, and add the - // connection: close header - keepAlive = false; - } - - // If we know that the request is bad this early, add the - // Connection: close header. - keepAlive = keepAlive && !statusDropsConnection(statusCode); - if (!keepAlive) { - headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); - } else if (!http11 && !error) { - headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); - } - - // Build the response header - outputBuffer.sendStatus(); - - // Add server header - if (server != null) { - headers.setValue("Server").setString(server); - } else { - outputBuffer.write(Constants.SERVER_BYTES); - } - - int size = headers.size(); - for (int i = 0; i < size; i++) { - outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); - } - outputBuffer.endHeaders(); - - } - - - /** - * Initialize standard input and output filters. - */ - protected void initializeFilters() { - - // Create and add the identity filters. - inputBuffer.addFilter(new IdentityInputFilter()); - outputBuffer.addFilter(new IdentityOutputFilter()); - - // Create and add the chunked filters. - inputBuffer.addFilter(new ChunkedInputFilter()); - outputBuffer.addFilter(new ChunkedOutputFilter()); - - // Create and add the void filters. - inputBuffer.addFilter(new VoidInputFilter()); - outputBuffer.addFilter(new VoidOutputFilter()); - - // Create and add buffered input filter - inputBuffer.addFilter(new BufferedInputFilter()); - - // Create and add the chunked filters. - //inputBuffer.addFilter(new GzipInputFilter()); - outputBuffer.addFilter(new GzipOutputFilter()); - - } - - - /** - * Add an input filter to the current request. - * - * @return false if the encoding was not found (which would mean it is - * unsupported) - */ - protected boolean addInputFilter(InputFilter[] inputFilters, - String encodingName) { - if (encodingName.equals("identity")) { - // Skip - } else if (encodingName.equals("chunked")) { - inputBuffer.addActiveFilter - (inputFilters[Constants.CHUNKED_FILTER]); - contentDelimitation = true; - } else { - for (int i = 2; i < inputFilters.length; i++) { - if (inputFilters[i].getEncodingName() - .toString().equals(encodingName)) { - inputBuffer.addActiveFilter(inputFilters[i]); - return true; - } - } - return false; - } - return true; - } - - - /** - * Specialized utility method: find a sequence of lower case bytes inside - * a ByteChunk. - */ - protected int findBytes(ByteChunk bc, byte[] b) { - - byte first = b[0]; - byte[] buff = bc.getBuffer(); - int start = bc.getStart(); - int end = bc.getEnd(); - - // Look for first char - int srcEnd = b.length; - - for (int i = start; i <= (end - srcEnd); i++) { - if (Ascii.toLower(buff[i]) != first) continue; - // found first char, now look for a match - int myPos = i+1; - for (int srcPos = 1; srcPos < srcEnd; ) { - if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) - break; - if (srcPos == srcEnd) return i - start; // found it - } - } - return -1; - - } - - /** - * Determine if we must drop the connection because of the HTTP status - * code. Use the same list of codes as Apache/httpd. - */ - protected boolean statusDropsConnection(int status) { - return status == 400 /* SC_BAD_REQUEST */ || - status == 408 /* SC_REQUEST_TIMEOUT */ || - status == 411 /* SC_LENGTH_REQUIRED */ || - status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || - status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || - status == 500 /* SC_INTERNAL_SERVER_ERROR */ || - status == 503 /* SC_SERVICE_UNAVAILABLE */ || - status == 501 /* SC_NOT_IMPLEMENTED */; - } - -} +/* + * Copyright 1999-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.StringTokenizer; +import java.util.regex.Pattern; +import java.util.regex.PatternSyntaxException; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Adapter; +import org.apache.coyote.Request; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Response; +import org.apache.coyote.http11.filters.BufferedInputFilter; +import org.apache.coyote.http11.filters.ChunkedInputFilter; +import org.apache.coyote.http11.filters.ChunkedOutputFilter; +import org.apache.coyote.http11.filters.GzipOutputFilter; +import org.apache.coyote.http11.filters.IdentityInputFilter; +import org.apache.coyote.http11.filters.IdentityOutputFilter; +import org.apache.coyote.http11.filters.SavedRequestInputFilter; +import org.apache.coyote.http11.filters.VoidInputFilter; +import org.apache.coyote.http11.filters.VoidOutputFilter; +import org.apache.tomcat.util.buf.Ascii; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.FastHttpDateFormat; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.JIoEndpoint; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.res.StringManager; + + +/** + * Processes HTTP requests. + * + * @author Remy Maucherat + */ +public class Http11Processor implements ActionHook { + + + /** + * Logger. + */ + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(Http11Processor.class); + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ------------------------------------------------------------ Constructor + + + public Http11Processor(int headerBufferSize, JIoEndpoint endpoint) { + + this.endpoint = endpoint; + + request = new Request(); + inputBuffer = new InternalInputBuffer(request, headerBufferSize); + request.setInputBuffer(inputBuffer); + + response = new Response(); + response.setHook(this); + outputBuffer = new InternalOutputBuffer(response, headerBufferSize); + response.setOutputBuffer(outputBuffer); + request.setResponse(response); + + initializeFilters(); + + // Cause loading of HexUtils + int foo = HexUtils.DEC[0]; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated adapter. + */ + protected Adapter adapter = null; + + + /** + * Request object. + */ + protected Request request = null; + + + /** + * Response object. + */ + protected Response response = null; + + + /** + * Input. + */ + protected InternalInputBuffer inputBuffer = null; + + + /** + * Output. + */ + protected InternalOutputBuffer outputBuffer = null; + + + /** + * State flag. + */ + protected boolean started = false; + + + /** + * Error flag. + */ + protected boolean error = false; + + + /** + * Keep-alive. + */ + protected boolean keepAlive = true; + + + /** + * HTTP/1.1 flag. + */ + protected boolean http11 = true; + + + /** + * HTTP/0.9 flag. + */ + protected boolean http09 = false; + + + /** + * Content delimitator for the request (if false, the connection will + * be closed at the end of the request). + */ + protected boolean contentDelimitation = true; + + + /** + * Is there an expectation ? + */ + protected boolean expectation = false; + + + /** + * List of restricted user agents. + */ + protected Pattern[] restrictedUserAgents = null; + + + /** + * Maximum number of Keep-Alive requests to honor. + */ + protected int maxKeepAliveRequests = -1; + + + /** + * SSL information. + */ + protected SSLSupport sslSupport; + + + /** + * Socket associated with the current connection. + */ + protected Socket socket; + + + /** + * Remote Address associated with the current connection. + */ + protected String remoteAddr = null; + + + /** + * Remote Host associated with the current connection. + */ + protected String remoteHost = null; + + + /** + * Local Host associated with the current connection. + */ + protected String localName = null; + + + + /** + * Local port to which the socket is connected + */ + protected int localPort = -1; + + + /** + * Remote port to which the socket is connected + */ + protected int remotePort = -1; + + + /** + * The local Host address. + */ + protected String localAddr = null; + + + /** + * Maximum timeout on uploads. 5 minutes as in Apache HTTPD server. + */ + protected int timeout = 300000; + + + /** + * Flag to disable setting a different time-out on uploads. + */ + protected boolean disableUploadTimeout = false; + + + /** + * Allowed compression level. + */ + protected int compressionLevel = 0; + + + /** + * Minimum contentsize to make compression. + */ + protected int compressionMinSize = 2048; + + + /** + * Socket buffering. + */ + protected int socketBuffer = -1; + + + /** + * Max saved post size. + */ + protected int maxSavePostSize = 4 * 1024; + + + /** + * List of user agents to not use gzip with + */ + protected Pattern noCompressionUserAgents[] = null; + + /** + * List of MIMES which could be gzipped + */ + protected String[] compressableMimeTypes = + { "text/html", "text/xml", "text/plain" }; + + + /** + * Host name (used to avoid useless B2C conversion on the host name). + */ + protected char[] hostNameC = new char[0]; + + + /** + * Associated endpoint. + */ + protected JIoEndpoint endpoint; + + + /** + * Allow a customized the server header for the tin-foil hat folks. + */ + protected String server = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return compression level. + */ + public String getCompression() { + switch (compressionLevel) { + case 0: + return "off"; + case 1: + return "on"; + case 2: + return "force"; + } + return "off"; + } + + + /** + * Set compression level. + */ + public void setCompression(String compression) { + if (compression.equals("on")) { + this.compressionLevel = 1; + } else if (compression.equals("force")) { + this.compressionLevel = 2; + } else if (compression.equals("off")) { + this.compressionLevel = 0; + } else { + try { + // Try to parse compression as an int, which would give the + // minimum compression size + compressionMinSize = Integer.parseInt(compression); + this.compressionLevel = 1; + } catch (Exception e) { + this.compressionLevel = 0; + } + } + } + + /** + * Set Minimum size to trigger compression. + */ + public void setCompressionMinSize(int compressionMinSize) { + this.compressionMinSize = compressionMinSize; + } + + + /** + * Add user-agent for which gzip compression didn't works + * The user agent String given will be exactly matched + * to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addNoCompressionUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + noCompressionUserAgents = + addREArray(noCompressionUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set no compression user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setNoCompressionUserAgents(Pattern[] noCompressionUserAgents) { + this.noCompressionUserAgents = noCompressionUserAgents; + } + + + /** + * Set no compression user agent list. + * List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setNoCompressionUserAgents(String noCompressionUserAgents) { + if (noCompressionUserAgents != null) { + StringTokenizer st = new StringTokenizer(noCompressionUserAgents, ","); + + while (st.hasMoreTokens()) { + addNoCompressionUserAgent(st.nextToken().trim()); + } + } + } + + /** + * Add a mime-type which will be compressable + * The mime-type String will be exactly matched + * in the response mime-type header . + * + * @param mimeType mime-type string + */ + public void addCompressableMimeType(String mimeType) { + compressableMimeTypes = + addStringArray(compressableMimeTypes, mimeType); + } + + + /** + * Set compressable mime-type list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setCompressableMimeTypes(String[] compressableMimeTypes) { + this.compressableMimeTypes = compressableMimeTypes; + } + + + /** + * Set compressable mime-type list + * List contains users agents separated by ',' : + * + * ie: "text/html,text/xml,text/plain" + */ + public void setCompressableMimeTypes(String compressableMimeTypes) { + if (compressableMimeTypes != null) { + StringTokenizer st = new StringTokenizer(compressableMimeTypes, ","); + + while (st.hasMoreTokens()) { + addCompressableMimeType(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findCompressableMimeTypes() { + return (compressableMimeTypes); + } + + + + // --------------------------------------------------------- Public Methods + + + /** + * Add input or output filter. + * + * @param className class name of the filter + */ + protected void addFilter(String className) { + try { + Class clazz = Class.forName(className); + Object obj = clazz.newInstance(); + if (obj instanceof InputFilter) { + inputBuffer.addFilter((InputFilter) obj); + } else if (obj instanceof OutputFilter) { + outputBuffer.addFilter((OutputFilter) obj); + } else { + log.warn(sm.getString("http11processor.filter.unknown", className)); + } + } catch (Exception e) { + log.error(sm.getString("http11processor.filter.error", className), e); + } + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private String[] addStringArray(String sArray[], String value) { + String[] result = null; + if (sArray == null) { + result = new String[1]; + result[0] = value; + } + else { + result = new String[sArray.length + 1]; + for (int i = 0; i < sArray.length; i++) + result[i] = sArray[i]; + result[sArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param rArray the REArray + * @param value Obj + */ + private Pattern[] addREArray(Pattern rArray[], Pattern value) { + Pattern[] result = null; + if (rArray == null) { + result = new Pattern[1]; + result[0] = value; + } + else { + result = new Pattern[rArray.length + 1]; + for (int i = 0; i < rArray.length; i++) + result[i] = rArray[i]; + result[rArray.length] = value; + } + return result; + } + + + /** + * General use method + * + * @param sArray the StringArray + * @param value string + */ + private boolean inStringArray(String sArray[], String value) { + for (int i = 0; i < sArray.length; i++) { + if (sArray[i].equals(value)) { + return true; + } + } + return false; + } + + + /** + * Checks if any entry in the string array starts with the specified value + * + * @param sArray the StringArray + * @param value string + */ + private boolean startsWithStringArray(String sArray[], String value) { + if (value == null) + return false; + for (int i = 0; i < sArray.length; i++) { + if (value.startsWith(sArray[i])) { + return true; + } + } + return false; + } + + + /** + * Add restricted user-agent (which will downgrade the connector + * to HTTP/1.0 mode). The user agent String given will be matched + * via regexp to the user-agent header submitted by the client. + * + * @param userAgent user-agent string + */ + public void addRestrictedUserAgent(String userAgent) { + try { + Pattern nRule = Pattern.compile(userAgent); + restrictedUserAgents = addREArray(restrictedUserAgents, nRule); + } catch (PatternSyntaxException pse) { + log.error(sm.getString("http11processor.regexp.error", userAgent), pse); + } + } + + + /** + * Set restricted user agent list (this method is best when used with + * a large number of connectors, where it would be better to have all of + * them referenced a single array). + */ + public void setRestrictedUserAgents(Pattern[] restrictedUserAgents) { + this.restrictedUserAgents = restrictedUserAgents; + } + + + /** + * Set restricted user agent list (which will downgrade the connector + * to HTTP/1.0 mode). List contains users agents separated by ',' : + * + * ie: "gorilla,desesplorer,tigrus" + */ + public void setRestrictedUserAgents(String restrictedUserAgents) { + if (restrictedUserAgents != null) { + StringTokenizer st = + new StringTokenizer(restrictedUserAgents, ","); + while (st.hasMoreTokens()) { + addRestrictedUserAgent(st.nextToken().trim()); + } + } + } + + + /** + * Return the list of restricted user agents. + */ + public String[] findRestrictedUserAgents() { + String[] sarr = new String [restrictedUserAgents.length]; + + for (int i = 0; i < restrictedUserAgents.length; i++) + sarr[i] = restrictedUserAgents[i].toString(); + + return (sarr); + } + + + /** + * Set the maximum number of Keep-Alive requests to honor. + * This is to safeguard from DoS attacks. Setting to a negative + * value disables the check. + */ + public void setMaxKeepAliveRequests(int mkar) { + maxKeepAliveRequests = mkar; + } + + + /** + * Return the number of Keep-Alive requests that we will honor. + */ + public int getMaxKeepAliveRequests() { + return maxKeepAliveRequests; + } + + + /** + * Set the maximum size of a POST which will be buffered in SSL mode. + */ + public void setMaxSavePostSize(int msps) { + maxSavePostSize = msps; + } + + + /** + * Return the maximum size of a POST which will be buffered in SSL mode. + */ + public int getMaxSavePostSize() { + return maxSavePostSize; + } + + + /** + * Set the SSL information for this HTTP connection. + */ + public void setSSLSupport(SSLSupport sslSupport) { + this.sslSupport = sslSupport; + } + + + /** + * Set the flag to control upload time-outs. + */ + public void setDisableUploadTimeout(boolean isDisabled) { + disableUploadTimeout = isDisabled; + } + + /** + * Get the flag that controls upload time-outs. + */ + public boolean getDisableUploadTimeout() { + return disableUploadTimeout; + } + + /** + * Set the socket buffer flag. + */ + public void setSocketBuffer(int socketBuffer) { + this.socketBuffer = socketBuffer; + outputBuffer.setSocketBuffer(socketBuffer); + } + + /** + * Get the socket buffer flag. + */ + public int getSocketBuffer() { + return socketBuffer; + } + + /** + * Set the upload timeout. + */ + public void setTimeout( int timeouts ) { + timeout = timeouts ; + } + + /** + * Get the upload timeout. + */ + public int getTimeout() { + return timeout; + } + + + /** + * Set the server header name. + */ + public void setServer( String server ) { + if (server==null || server.equals("")) { + this.server = null; + } else { + this.server = server; + } + } + + /** + * Get the server header name. + */ + public String getServer() { + return server; + } + + + /** Get the request associated with this processor. + * + * @return The request + */ + public Request getRequest() { + return request; + } + + /** + * Process pipelined HTTP requests using the specified input and output + * streams. + * + * @param input stream from which the HTTP requests will be read + * @param output stream which will be used to output the HTTP + * responses + * @throws IOException error during an I/O operation + */ + public void process(Socket socket) + throws IOException { + RequestInfo rp = request.getRequestProcessor(); + rp.setStage(org.apache.coyote.Constants.STAGE_PARSE); + + // Set the remote address + remoteAddr = null; + remoteHost = null; + localAddr = null; + localName = null; + remotePort = -1; + localPort = -1; + + // Setting up the I/O + this.socket = socket; + inputBuffer.setInputStream(socket.getInputStream()); + outputBuffer.setOutputStream(socket.getOutputStream()); + + // Error flag + error = false; + keepAlive = true; + + int keepAliveLeft = maxKeepAliveRequests; + int soTimeout = socket.getSoTimeout(); + int oldSoTimeout = soTimeout; + + int threadRatio = (endpoint.getCurrentThreadsBusy() * 100) + / endpoint.getMaxThreads(); + if ((threadRatio > 33) && (threadRatio <= 66)) { + soTimeout = soTimeout / 2; + } else if ((threadRatio > 66) && (threadRatio <= 90)) { + soTimeout = soTimeout / 3; + keepAliveLeft = 1; + } else if (threadRatio > 90) { + soTimeout = soTimeout / 20; + keepAliveLeft = 1; + } + + if (soTimeout != oldSoTimeout) { + try { + socket.setSoTimeout(soTimeout); + } catch (Throwable t) { + log.debug(sm.getString("http11processor.socket.timeout"), t); + error = true; + } + } + + boolean keptAlive = false; + + while (started && !error && keepAlive) { + + // Parsing the request header + try { + if( !disableUploadTimeout && keptAlive && soTimeout > 0 ) { + socket.setSoTimeout(soTimeout); + } + inputBuffer.parseRequestLine(); + request.setStartTime(System.currentTimeMillis()); + keptAlive = true; + if (!disableUploadTimeout) { + socket.setSoTimeout(timeout); + } + inputBuffer.parseHeaders(); + } catch (IOException e) { + error = true; + break; + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.header.parse"), t); + } + // 400 - Bad Request + response.setStatus(400); + error = true; + } + + // Setting up filters, and parse some request headers + rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE); + try { + prepareRequest(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("http11processor.request.prepare"), t); + } + // 400 - Internal Server Error + response.setStatus(400); + error = true; + } + + if (maxKeepAliveRequests > 0 && --keepAliveLeft == 0) + keepAlive = false; + + // Process the request in the adapter + if (!error) { + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + adapter.service(request, response); + // Handle when the response was committed before a serious + // error occurred. Throwing a ServletException should both + // set the status to 500 and set the errorException. + // If we fail here, then the response is likely already + // committed, so we can't try and set headers. + if(keepAlive && !error) { // Avoid checking twice. + error = response.getErrorException() != null || + statusDropsConnection(response.getStatus()); + } + + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.process"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + } + + // Finish the handling of the request + try { + rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT); + inputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.request.finish"), t); + // 500 - Internal Server Error + response.setStatus(500); + error = true; + } + try { + rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT); + outputBuffer.endRequest(); + } catch (IOException e) { + error = true; + } catch (Throwable t) { + log.error(sm.getString("http11processor.response.finish"), t); + error = true; + } + + // If there was an error, make sure the request is counted as + // and error, and update the statistics counter + if (error) { + response.setStatus(500); + } + request.updateCounters(); + + rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE); + + // Don't reset the param - we'll see it as ended. Next request + // will reset it + // thrA.setParam(null); + // Next request + inputBuffer.nextRequest(); + outputBuffer.nextRequest(); + + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + // Recycle + inputBuffer.recycle(); + outputBuffer.recycle(); + + // Recycle ssl info + sslSupport = null; + } + + + // ----------------------------------------------------- ActionHook Methods + + + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + public void action(ActionCode actionCode, Object param) { + + if (actionCode == ActionCode.ACTION_COMMIT) { + // Commit current response + + if (response.isCommitted()) + return; + + // Validate and write response headers + prepareResponse(); + try { + outputBuffer.commit(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_ACK) { + + // Acknowlege request + + // Send a 100 status back if it makes sense (response not committed + // yet, and client specified an expectation for 100-continue) + + if ((response.isCommitted()) || !expectation) + return; + + inputBuffer.setSwallowInput(true); + try { + outputBuffer.sendAck(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_CLIENT_FLUSH) { + + try { + outputBuffer.flush(); + } catch (IOException e) { + // Set error flag + error = true; + response.setErrorException(e); + } + + } else if (actionCode == ActionCode.ACTION_CLOSE) { + // Close + + // End the processing of the current request, and stop any further + // transactions with the client + + try { + outputBuffer.endRequest(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.ACTION_RESET) { + + // Reset response + + // Note: This must be called before the response is committed + + outputBuffer.reset(); + + } else if (actionCode == ActionCode.ACTION_CUSTOM) { + + // Do nothing + + } else if (actionCode == ActionCode.ACTION_START) { + + started = true; + + } else if (actionCode == ActionCode.ACTION_STOP) { + + started = false; + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { + + try { + if (sslSupport != null) { + Object sslO = sslSupport.getCipherSuite(); + if (sslO != null) + request.setAttribute + (SSLSupport.CIPHER_SUITE_KEY, sslO); + sslO = sslSupport.getPeerCertificateChain(false); + if (sslO != null) + request.setAttribute + (SSLSupport.CERTIFICATE_KEY, sslO); + sslO = sslSupport.getKeySize(); + if (sslO != null) + request.setAttribute + (SSLSupport.KEY_SIZE_KEY, sslO); + sslO = sslSupport.getSessionId(); + if (sslO != null) + request.setAttribute + (SSLSupport.SESSION_ID_KEY, sslO); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ADDR_ATTRIBUTE) { + + if ((remoteAddr == null) && (socket != null)) { + InetAddress inetAddr = socket.getInetAddress(); + if (inetAddr != null) { + remoteAddr = inetAddr.getHostAddress(); + } + } + request.remoteAddr().setString(remoteAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE) { + + if ((localName == null) && (socket != null)) { + InetAddress inetAddr = socket.getLocalAddress(); + if (inetAddr != null) { + localName = inetAddr.getHostName(); + } + } + request.localName().setString(localName); + + } else if (actionCode == ActionCode.ACTION_REQ_HOST_ATTRIBUTE) { + + if ((remoteHost == null) && (socket != null)) { + InetAddress inetAddr = socket.getInetAddress(); + if (inetAddr != null) { + remoteHost = inetAddr.getHostName(); + } + if(remoteHost == null) { + if(remoteAddr != null) { + remoteHost = remoteAddr; + } else { // all we can do is punt + request.remoteHost().recycle(); + } + } + } + request.remoteHost().setString(remoteHost); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCAL_ADDR_ATTRIBUTE) { + + if (localAddr == null) + localAddr = socket.getLocalAddress().getHostAddress(); + + request.localAddr().setString(localAddr); + + } else if (actionCode == ActionCode.ACTION_REQ_REMOTEPORT_ATTRIBUTE) { + + if ((remotePort == -1 ) && (socket !=null)) { + remotePort = socket.getPort(); + } + request.setRemotePort(remotePort); + + } else if (actionCode == ActionCode.ACTION_REQ_LOCALPORT_ATTRIBUTE) { + + if ((localPort == -1 ) && (socket !=null)) { + localPort = socket.getLocalPort(); + } + request.setLocalPort(localPort); + + } else if (actionCode == ActionCode.ACTION_REQ_SSL_CERTIFICATE) { + if( sslSupport != null) { + /* + * Consume and buffer the request body, so that it does not + * interfere with the client's handshake messages + */ + InputFilter[] inputFilters = inputBuffer.getFilters(); + ((BufferedInputFilter) inputFilters[Constants.BUFFERED_FILTER]) + .setLimit(maxSavePostSize); + inputBuffer.addActiveFilter + (inputFilters[Constants.BUFFERED_FILTER]); + try { + Object sslO = sslSupport.getPeerCertificateChain(true); + if( sslO != null) { + request.setAttribute + (SSLSupport.CERTIFICATE_KEY, sslO); + } + } catch (Exception e) { + log.warn(sm.getString("http11processor.socket.ssl"), e); + } + } + } else if (actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY) { + ByteChunk body = (ByteChunk) param; + + InputFilter savedBody = new SavedRequestInputFilter(body); + savedBody.setRequest(request); + + InternalInputBuffer internalBuffer = (InternalInputBuffer) + request.getInputBuffer(); + internalBuffer.addActiveFilter(savedBody); + } + + } + + + // ------------------------------------------------------ Connector Methods + + + /** + * Set the associated adapter. + * + * @param adapter the new adapter + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + + /** + * Get the associated adapter. + * + * @return the associated adapter + */ + public Adapter getAdapter() { + return adapter; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * After reading the request headers, we have to setup the request filters. + */ + protected void prepareRequest() { + + http11 = true; + http09 = false; + contentDelimitation = false; + expectation = false; + if (sslSupport != null) { + request.scheme().setString("https"); + } + MessageBytes protocolMB = request.protocol(); + if (protocolMB.equals(Constants.HTTP_11)) { + http11 = true; + protocolMB.setString(Constants.HTTP_11); + } else if (protocolMB.equals(Constants.HTTP_10)) { + http11 = false; + keepAlive = false; + protocolMB.setString(Constants.HTTP_10); + } else if (protocolMB.equals("")) { + // HTTP/0.9 + http09 = true; + http11 = false; + keepAlive = false; + } else { + // Unsupported protocol + http11 = false; + error = true; + // Send 505; Unsupported HTTP version + response.setStatus(505); + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals(Constants.GET)) { + methodMB.setString(Constants.GET); + } else if (methodMB.equals(Constants.POST)) { + methodMB.setString(Constants.POST); + } + + MimeHeaders headers = request.getMimeHeaders(); + + // Check connection header + MessageBytes connectionValueMB = headers.getValue("connection"); + if (connectionValueMB != null) { + ByteChunk connectionValueBC = connectionValueMB.getByteChunk(); + if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) { + keepAlive = false; + } else if (findBytes(connectionValueBC, + Constants.KEEPALIVE_BYTES) != -1) { + keepAlive = true; + } + } + + MessageBytes expectMB = null; + if (http11) + expectMB = headers.getValue("expect"); + if ((expectMB != null) + && (expectMB.indexOfIgnoreCase("100-continue", 0) != -1)) { + inputBuffer.setSwallowInput(false); + expectation = true; + } + + // Check user-agent header + if ((restrictedUserAgents != null) && ((http11) || (keepAlive))) { + MessageBytes userAgentValueMB = headers.getValue("user-agent"); + // Check in the restricted list, and adjust the http11 + // and keepAlive flags accordingly + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + for (int i = 0; i < restrictedUserAgents.length; i++) { + if (restrictedUserAgents[i].matcher(userAgentValue).matches()) { + http11 = false; + keepAlive = false; + break; + } + } + } + } + + // Check for a full URI (including protocol://host:port/) + ByteChunk uriBC = request.requestURI().getByteChunk(); + if (uriBC.startsWithIgnoreCase("http", 0)) { + + int pos = uriBC.indexOf("://", 0, 3, 4); + int uriBCStart = uriBC.getStart(); + int slashPos = -1; + if (pos != -1) { + byte[] uriB = uriBC.getBytes(); + slashPos = uriBC.indexOf('/', pos + 3); + if (slashPos == -1) { + slashPos = uriBC.getLength(); + // Set URI as "/" + request.requestURI().setBytes + (uriB, uriBCStart + pos + 1, 1); + } else { + request.requestURI().setBytes + (uriB, uriBCStart + slashPos, + uriBC.getLength() - slashPos); + } + MessageBytes hostMB = headers.setValue("host"); + hostMB.setBytes(uriB, uriBCStart + pos + 3, + slashPos - pos - 3); + } + + } + + // Input filter setup + InputFilter[] inputFilters = inputBuffer.getFilters(); + + // Parse transfer-encoding header + MessageBytes transferEncodingValueMB = null; + if (http11) + transferEncodingValueMB = headers.getValue("transfer-encoding"); + if (transferEncodingValueMB != null) { + String transferEncodingValue = transferEncodingValueMB.toString(); + // Parse the comma separated list. "identity" codings are ignored + int startPos = 0; + int commaPos = transferEncodingValue.indexOf(','); + String encodingName = null; + while (commaPos != -1) { + encodingName = transferEncodingValue.substring + (startPos, commaPos).toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + startPos = commaPos + 1; + commaPos = transferEncodingValue.indexOf(',', startPos); + } + encodingName = transferEncodingValue.substring(startPos) + .toLowerCase().trim(); + if (!addInputFilter(inputFilters, encodingName)) { + // Unsupported transfer encoding + error = true; + // 501 - Unimplemented + response.setStatus(501); + } + } + + // Parse content-length header + long contentLength = request.getContentLengthLong(); + if (contentLength >= 0 && !contentDelimitation) { + inputBuffer.addActiveFilter + (inputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } + + MessageBytes valueMB = headers.getValue("host"); + + // Check host header + if (http11 && (valueMB == null)) { + error = true; + // 400 - Bad request + response.setStatus(400); + } + + parseHost(valueMB); + + if (!contentDelimitation) { + // If there's no content length + // (broken HTTP/1.0 or HTTP/1.1), assume + // the client is not broken and didn't send a body + inputBuffer.addActiveFilter + (inputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + } + + + /** + * Parse host. + */ + public void parseHost(MessageBytes valueMB) { + + if (valueMB == null || valueMB.isNull()) { + // HTTP/1.0 + // Default is what the socket tells us. Overriden if a host is + // found/parsed + request.setServerPort(socket.getLocalPort()); + InetAddress localAddress = socket.getLocalAddress(); + // Setting the socket-related fields. The adapter doesn't know + // about socket. + request.serverName().setString(localAddress.getHostName()); + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + if (hostNameC.length < valueL) { + hostNameC = new char[valueL]; + } + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC[i] = b; + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (sslSupport == null) { + // 80 - Default HTTP port + request.setServerPort(80); + } else { + // 443 - Default HTTPS port + request.setServerPort(443); + } + request.serverName().setChars(hostNameC, 0, valueL); + } else { + + request.serverName().setChars(hostNameC, 0, colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; + if (charValue == -1) { + // Invalid character + error = true; + // 400 - Bad request + response.setStatus(400); + break; + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + + } + + } + + + /** + * Check for compression + */ + private boolean isCompressable() { + + // Nope Compression could works in HTTP 1.0 also + // cf: mod_deflate + + // Compression only since HTTP 1.1 + // if (! http11) + // return false; + + // Check if browser support gzip encoding + MessageBytes acceptEncodingMB = + request.getMimeHeaders().getValue("accept-encoding"); + + if ((acceptEncodingMB == null) + || (acceptEncodingMB.indexOf("gzip") == -1)) + return false; + + // Check if content is not allready gzipped + MessageBytes contentEncodingMB = + response.getMimeHeaders().getValue("Content-Encoding"); + + if ((contentEncodingMB != null) + && (contentEncodingMB.indexOf("gzip") != -1)) + return false; + + // If force mode, allways compress (test purposes only) + if (compressionLevel == 2) + return true; + + // Check for incompatible Browser + if (noCompressionUserAgents != null) { + MessageBytes userAgentValueMB = + request.getMimeHeaders().getValue("user-agent"); + if(userAgentValueMB != null) { + String userAgentValue = userAgentValueMB.toString(); + + // If one Regexp rule match, disable compression + for (int i = 0; i < noCompressionUserAgents.length; i++) + if (noCompressionUserAgents[i].matcher(userAgentValue).matches()) + return false; + } + } + + // Check if suffisant len to trig the compression + long contentLength = response.getContentLengthLong(); + if ((contentLength == -1) + || (contentLength > compressionMinSize)) { + // Check for compatible MIME-TYPE + if (compressableMimeTypes != null) { + return (startsWithStringArray(compressableMimeTypes, + response.getContentType())); + } + } + + return false; + } + + + /** + * When committing the response, we have to validate the set of headers, as + * well as setup the response filters. + */ + protected void prepareResponse() { + + boolean entityBody = true; + contentDelimitation = false; + + OutputFilter[] outputFilters = outputBuffer.getFilters(); + + if (http09 == true) { + // HTTP/0.9 + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + return; + } + + int statusCode = response.getStatus(); + if ((statusCode == 204) || (statusCode == 205) + || (statusCode == 304)) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + entityBody = false; + contentDelimitation = true; + } + + MessageBytes methodMB = request.method(); + if (methodMB.equals("HEAD")) { + // No entity body + outputBuffer.addActiveFilter + (outputFilters[Constants.VOID_FILTER]); + contentDelimitation = true; + } + + // Check for compression + boolean useCompression = false; + if (entityBody && (compressionLevel > 0)) { + useCompression = isCompressable(); + + // Change content-length to -1 to force chunking + if (useCompression) { + response.setContentLength(-1); + } + } + + MimeHeaders headers = response.getMimeHeaders(); + if (!entityBody) { + response.setContentLength(-1); + } else { + String contentType = response.getContentType(); + if (contentType != null) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = response.getContentLanguage(); + if (contentLanguage != null) { + headers.setValue("Content-Language") + .setString(contentLanguage); + } + } + + long contentLength = response.getContentLengthLong(); + if (contentLength != -1) { + headers.setValue("Content-Length").setLong(contentLength); + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + contentDelimitation = true; + } else { + if (entityBody && http11 && keepAlive) { + outputBuffer.addActiveFilter + (outputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED); + } else { + outputBuffer.addActiveFilter + (outputFilters[Constants.IDENTITY_FILTER]); + } + } + + if (useCompression) { + outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]); + headers.setValue("Content-Encoding").setString("gzip"); + // Make Proxies happy via Vary (from mod_deflate) + headers.setValue("Vary").setString("Accept-Encoding"); + } + + // Add date header + String date = null; + if (System.getSecurityManager() != null){ + date = (String)AccessController.doPrivileged( + new PrivilegedAction() { + public Object run(){ + return FastHttpDateFormat.getCurrentDate(); + } + } + ); + } else { + date = FastHttpDateFormat.getCurrentDate(); + } + headers.setValue("Date").setString(date); + + // FIXME: Add transfer encoding header + + if ((entityBody) && (!contentDelimitation)) { + // Mark as close the connection after the request, and add the + // connection: close header + keepAlive = false; + } + + // If we know that the request is bad this early, add the + // Connection: close header. + keepAlive = keepAlive && !statusDropsConnection(statusCode); + if (!keepAlive) { + headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE); + } else if (!http11 && !error) { + headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE); + } + + // Build the response header + outputBuffer.sendStatus(); + + // Add server header + if (server != null) { + headers.setValue("Server").setString(server); + } else { + outputBuffer.write(Constants.SERVER_BYTES); + } + + int size = headers.size(); + for (int i = 0; i < size; i++) { + outputBuffer.sendHeader(headers.getName(i), headers.getValue(i)); + } + outputBuffer.endHeaders(); + + } + + + /** + * Initialize standard input and output filters. + */ + protected void initializeFilters() { + + // Create and add the identity filters. + inputBuffer.addFilter(new IdentityInputFilter()); + outputBuffer.addFilter(new IdentityOutputFilter()); + + // Create and add the chunked filters. + inputBuffer.addFilter(new ChunkedInputFilter()); + outputBuffer.addFilter(new ChunkedOutputFilter()); + + // Create and add the void filters. + inputBuffer.addFilter(new VoidInputFilter()); + outputBuffer.addFilter(new VoidOutputFilter()); + + // Create and add buffered input filter + inputBuffer.addFilter(new BufferedInputFilter()); + + // Create and add the chunked filters. + //inputBuffer.addFilter(new GzipInputFilter()); + outputBuffer.addFilter(new GzipOutputFilter()); + + } + + + /** + * Add an input filter to the current request. + * + * @return false if the encoding was not found (which would mean it is + * unsupported) + */ + protected boolean addInputFilter(InputFilter[] inputFilters, + String encodingName) { + if (encodingName.equals("identity")) { + // Skip + } else if (encodingName.equals("chunked")) { + inputBuffer.addActiveFilter + (inputFilters[Constants.CHUNKED_FILTER]); + contentDelimitation = true; + } else { + for (int i = 2; i < inputFilters.length; i++) { + if (inputFilters[i].getEncodingName() + .toString().equals(encodingName)) { + inputBuffer.addActiveFilter(inputFilters[i]); + return true; + } + } + return false; + } + return true; + } + + + /** + * Specialized utility method: find a sequence of lower case bytes inside + * a ByteChunk. + */ + protected int findBytes(ByteChunk bc, byte[] b) { + + byte first = b[0]; + byte[] buff = bc.getBuffer(); + int start = bc.getStart(); + int end = bc.getEnd(); + + // Look for first char + int srcEnd = b.length; + + for (int i = start; i <= (end - srcEnd); i++) { + if (Ascii.toLower(buff[i]) != first) continue; + // found first char, now look for a match + int myPos = i+1; + for (int srcPos = 1; srcPos < srcEnd; ) { + if (Ascii.toLower(buff[myPos++]) != b[srcPos++]) + break; + if (srcPos == srcEnd) return i - start; // found it + } + } + return -1; + + } + + /** + * Determine if we must drop the connection because of the HTTP status + * code. Use the same list of codes as Apache/httpd. + */ + protected boolean statusDropsConnection(int status) { + return status == 400 /* SC_BAD_REQUEST */ || + status == 408 /* SC_REQUEST_TIMEOUT */ || + status == 411 /* SC_LENGTH_REQUIRED */ || + status == 413 /* SC_REQUEST_ENTITY_TOO_LARGE */ || + status == 414 /* SC_REQUEST_URI_TOO_LARGE */ || + status == 500 /* SC_INTERNAL_SERVER_ERROR */ || + status == 503 /* SC_SERVICE_UNAVAILABLE */ || + status == 501 /* SC_NOT_IMPLEMENTED */; + } + +} diff --git a/java/org/apache/coyote/http11/InputFilter.java b/java/org/apache/coyote/http11/InputFilter.java index b9394e283..a734c6047 100644 --- a/java/org/apache/coyote/http11/InputFilter.java +++ b/java/org/apache/coyote/http11/InputFilter.java @@ -1,81 +1,81 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; - -/** - * Input filter interface. - * - * @author Remy Maucherat - */ -public interface InputFilter extends InputBuffer { - - - /** - * Read bytes. - * - * @return Number of bytes read. - */ - public int doRead(ByteChunk chunk, Request unused) - throws IOException; - - - /** - * Some filters need additional parameters from the request. All the - * necessary reading can occur in that method, as this method is called - * after the request header processing is complete. - */ - public void setRequest(Request request); - - - /** - * Make the filter ready to process the next request. - */ - public void recycle(); - - - /** - * Get the name of the encoding handled by this filter. - */ - public ByteChunk getEncodingName(); - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(InputBuffer buffer); - - - /** - * End the current request. - * - * @return 0 is the expected return value. A positive value indicates that - * too many bytes were read. This method is allowed to use buffer.doRead - * to consume extra bytes. The result of this method can't be negative (if - * an error happens, an IOException should be thrown instead). - */ - public long end() - throws IOException; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; + +/** + * Input filter interface. + * + * @author Remy Maucherat + */ +public interface InputFilter extends InputBuffer { + + + /** + * Read bytes. + * + * @return Number of bytes read. + */ + public int doRead(ByteChunk chunk, Request unused) + throws IOException; + + + /** + * Some filters need additional parameters from the request. All the + * necessary reading can occur in that method, as this method is called + * after the request header processing is complete. + */ + public void setRequest(Request request); + + + /** + * Make the filter ready to process the next request. + */ + public void recycle(); + + + /** + * Get the name of the encoding handled by this filter. + */ + public ByteChunk getEncodingName(); + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(InputBuffer buffer); + + + /** + * End the current request. + * + * @return 0 is the expected return value. A positive value indicates that + * too many bytes were read. This method is allowed to use buffer.doRead + * to consume extra bytes. The result of this method can't be negative (if + * an error happens, an IOException should be thrown instead). + */ + public long end() + throws IOException; + + +} diff --git a/java/org/apache/coyote/http11/InternalAprInputBuffer.java b/java/org/apache/coyote/http11/InternalAprInputBuffer.java index 699e2f8c1..74de37cee 100644 --- a/java/org/apache/coyote/http11/InternalAprInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalAprInputBuffer.java @@ -1,839 +1,839 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.io.EOFException; -import java.nio.ByteBuffer; - -import org.apache.tomcat.jni.Socket; -import org.apache.tomcat.jni.Status; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; - -/** - * Implementation of InputBuffer which provides HTTP request header parsing as - * well as transfer decoding. - * - * @author Remy Maucherat - */ -public class InternalAprInputBuffer implements InputBuffer { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Alternate constructor. - */ - public InternalAprInputBuffer(Request request, int headerBufferSize, - long readTimeout) { - - this.request = request; - headers = request.getMimeHeaders(); - - buf = new byte[headerBufferSize]; - if (headerBufferSize < (8 * 1024)) { - bbuf = ByteBuffer.allocateDirect(6 * 1500); - } else { - bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); - } - - inputStreamInputBuffer = new SocketInputBuffer(); - - filterLibrary = new InputFilter[0]; - activeFilters = new InputFilter[0]; - lastActiveFilter = -1; - - parsingHeader = true; - swallowInput = true; - - if (readTimeout < 0) { - this.readTimeout = -1; - } else { - this.readTimeout = readTimeout * 1000; - } - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote request. - */ - protected Request request; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * State. - */ - protected boolean parsingHeader; - - - /** - * Swallow input ? (in the case of an expectation) - */ - protected boolean swallowInput; - - - /** - * Pointer to the current read buffer. - */ - protected byte[] buf; - - - /** - * Last valid byte. - */ - protected int lastValid; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * Pos of the end of the header in the buffer, which is also the - * start of the body. - */ - protected int end; - - - /** - * Direct byte buffer used to perform actual reading. - */ - protected ByteBuffer bbuf; - - - /** - * Underlying socket. - */ - protected long socket; - - - /** - * Underlying input buffer. - */ - protected InputBuffer inputStreamInputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected InputFilter[] filterLibrary; - - - /** - * Active filters (in order). - */ - protected InputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - /** - * The socket timeout used when reading the first block of the request - * header. - */ - protected long readTimeout; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket. - */ - public void setSocket(long socket) { - this.socket = socket; - Socket.setrbb(this.socket, bbuf); - } - - - /** - * Get the underlying socket input stream. - */ - public long getSocket() { - return socket; - } - - - /** - * Add an input filter to the filter library. - */ - public void addFilter(InputFilter filter) { - - InputFilter[] newFilterLibrary = - new InputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new InputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public InputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new InputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an input filter to the filter library. - */ - public void addActiveFilter(InputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(inputStreamInputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setRequest(request); - - } - - - /** - * Set the swallow input flag. - */ - public void setSwallowInput(boolean swallowInput) { - this.swallowInput = swallowInput; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Recycle the input buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - request.recycle(); - - socket = 0; - lastValid = 0; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() { - - // Recycle Request object - request.recycle(); - - //System.out.println("LV-pos: " + (lastValid - pos)); - // Copy leftover bytes to the beginning of the buffer - if (lastValid - pos > 0) { - int npos = 0; - int opos = pos; - while (lastValid - opos > opos - npos) { - System.arraycopy(buf, opos, buf, npos, opos - npos); - npos += pos; - opos += pos; - } - System.arraycopy(buf, opos, buf, npos, lastValid - opos); - } - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - lastValid = lastValid - pos; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End request (consumes leftover bytes). - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (swallowInput && (lastActiveFilter != -1)) { - int extraBytes = (int) activeFilters[lastActiveFilter].end(); - pos = pos - extraBytes; - } - - } - - - /** - * Read the request line. This function is meant to be used during the - * HTTP request header parsing. Do NOT attempt to read the request body - * using it. - * - * @throws IOException If an exception occurs during the underlying socket - * read operations, or if the given buffer is not big enough to accomodate - * the whole line. - * @return true if data is properly fed; false if no data is available - * immediately and thread should be freed - */ - public boolean parseRequestLine(boolean useAvailableData) - throws IOException { - - int start = 0; - - // - // Skipping blank lines - // - - byte chr = 0; - do { - - // Read new bytes if needed - if (pos >= lastValid) { - if (useAvailableData) { - return false; - } - if (readTimeout == -1) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } else { - // Do a simple read with a short timeout - bbuf.clear(); - int nRead = Socket.recvbbt - (socket, 0, buf.length - lastValid, readTimeout); - if (nRead > 0) { - bbuf.limit(nRead); - bbuf.get(buf, pos, nRead); - lastValid = pos + nRead; - } else { - if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { - return false; - } else { - throw new IOException(sm.getString("iib.failedread")); - } - } - } - } - - chr = buf[pos++]; - - } while ((chr == Constants.CR) || (chr == Constants.LF)); - - pos--; - - // Mark the current buffer position - start = pos; - - if (pos >= lastValid) { - if (useAvailableData) { - return false; - } - if (readTimeout == -1) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } else { - // Do a simple read with a short timeout - bbuf.clear(); - int nRead = Socket.recvbbt - (socket, 0, buf.length - lastValid, readTimeout); - if (nRead > 0) { - bbuf.limit(nRead); - bbuf.get(buf, pos, nRead); - lastValid = pos + nRead; - } else { - if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { - return false; - } else { - throw new IOException(sm.getString("iib.failedread")); - } - } - } - } - - // - // Reading the method name - // Method name is always US-ASCII - // - - boolean space = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.SP) { - space = true; - request.method().setBytes(buf, start, pos - start); - } - - pos++; - - } - - // Mark the current buffer position - start = pos; - int end = 0; - int questionPos = -1; - - // - // Reading the URI - // - - space = false; - boolean eol = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.SP) { - space = true; - end = pos; - } else if ((buf[pos] == Constants.CR) - || (buf[pos] == Constants.LF)) { - // HTTP/0.9 style request - eol = true; - space = true; - end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (questionPos == -1)) { - questionPos = pos; - } - - pos++; - - } - - request.unparsedURI().setBytes(buf, start, end - start); - if (questionPos >= 0) { - request.queryString().setBytes(buf, questionPos + 1, - end - questionPos - 1); - request.requestURI().setBytes(buf, start, questionPos - start); - } else { - request.requestURI().setBytes(buf, start, end - start); - } - - // Mark the current buffer position - start = pos; - end = 0; - - // - // Reading the protocol - // Protocol is always US-ASCII - // - - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.CR) { - end = pos; - } else if (buf[pos] == Constants.LF) { - if (end == 0) - end = pos; - eol = true; - } - - pos++; - - } - - if ((end - start) > 0) { - request.protocol().setBytes(buf, start, end - start); - } else { - request.protocol().setString(""); - } - - return true; - - } - - - /** - * Parse the HTTP headers. - */ - public void parseHeaders() - throws IOException { - - while (parseHeader()) { - } - - parsingHeader = false; - end = pos; - - } - - - /** - * Parse an HTTP header. - * - * @return false after reading a blank line (which indicates that the - * HTTP header parsing is done - */ - public boolean parseHeader() - throws IOException { - - // - // Check for blank line - // - - byte chr = 0; - while (true) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - - if ((chr == Constants.CR) || (chr == Constants.LF)) { - if (chr == Constants.LF) { - pos++; - return false; - } - } else { - break; - } - - pos++; - - } - - // Mark the current buffer position - int start = pos; - - // - // Reading the header name - // Header name is always US-ASCII - // - - boolean colon = false; - MessageBytes headerValue = null; - - while (!colon) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.COLON) { - colon = true; - headerValue = headers.addValue(buf, start, pos - start); - } - chr = buf[pos]; - if ((chr >= Constants.A) && (chr <= Constants.Z)) { - buf[pos] = (byte) (chr - Constants.LC_OFFSET); - } - - pos++; - - } - - // Mark the current buffer position - start = pos; - int realPos = pos; - - // - // Reading the header value (which can be spanned over multiple lines) - // - - boolean eol = false; - boolean validLine = true; - - while (validLine) { - - boolean space = true; - - // Skipping spaces - while (space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { - pos++; - } else { - space = false; - } - - } - - int lastSignificantChar = realPos; - - // Reading bytes until the end of the line - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.CR) { - } else if (buf[pos] == Constants.LF) { - eol = true; - } else if (buf[pos] == Constants.SP) { - buf[realPos] = buf[pos]; - realPos++; - } else { - buf[realPos] = buf[pos]; - realPos++; - lastSignificantChar = realPos; - } - - pos++; - - } - - realPos = lastSignificantChar; - - // Checking the first character of the new line. If the character - // is a LWS, then it's a multiline header - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - if ((chr != Constants.SP) && (chr != Constants.HT)) { - validLine = false; - } else { - eol = false; - // Copying one extra space in the buffer (since there must - // be at least one space inserted between the lines) - buf[realPos] = chr; - realPos++; - } - - } - - // Set the header value - headerValue.setBytes(buf, start, realPos - start); - - return true; - - } - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Read some bytes. - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - if (lastActiveFilter == -1) - return inputStreamInputBuffer.doRead(chunk, req); - else - return activeFilters[lastActiveFilter].doRead(chunk,req); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Fill the internal buffer using data from the undelying input stream. - * - * @return false if at end of stream - */ - protected boolean fill() - throws IOException { - - int nRead = 0; - - if (parsingHeader) { - - if (lastValid == buf.length) { - throw new IOException - (sm.getString("iib.requestheadertoolarge.error")); - } - - bbuf.clear(); - nRead = Socket.recvbb(socket, 0, buf.length - lastValid); - if (nRead > 0) { - bbuf.limit(nRead); - bbuf.get(buf, pos, nRead); - lastValid = pos + nRead; - } else { - if ((-nRead) == Status.EAGAIN) { - return false; - } else { - throw new IOException(sm.getString("iib.failedread")); - } - } - - } else { - - if (buf.length - end < 4500) { - // In this case, the request header was really large, so we allocate a - // brand new one; the old one will get GCed when subsequent requests - // clear all references - buf = new byte[buf.length]; - end = 0; - } - pos = end; - lastValid = pos; - bbuf.clear(); - nRead = Socket.recvbb(socket, 0, buf.length - lastValid); - if (nRead > 0) { - bbuf.limit(nRead); - bbuf.get(buf, pos, nRead); - lastValid = pos + nRead; - } else { - throw new IOException(sm.getString("iib.failedread")); - } - - } - - return (nRead > 0); - - } - - - // ------------------------------------- InputStreamInputBuffer Inner Class - - - /** - * This class is an input buffer which will read its data from an input - * stream. - */ - protected class SocketInputBuffer - implements InputBuffer { - - - /** - * Read bytes into the specified chunk. - */ - public int doRead(ByteChunk chunk, Request req ) - throws IOException { - - if (pos >= lastValid) { - if (!fill()) - return -1; - } - - int length = lastValid - pos; - chunk.setBytes(buf, pos, length); - pos = lastValid; - - return (length); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.io.EOFException; +import java.nio.ByteBuffer; + +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.jni.Status; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; + +/** + * Implementation of InputBuffer which provides HTTP request header parsing as + * well as transfer decoding. + * + * @author Remy Maucherat + */ +public class InternalAprInputBuffer implements InputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Alternate constructor. + */ + public InternalAprInputBuffer(Request request, int headerBufferSize, + long readTimeout) { + + this.request = request; + headers = request.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + if (headerBufferSize < (8 * 1024)) { + bbuf = ByteBuffer.allocateDirect(6 * 1500); + } else { + bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); + } + + inputStreamInputBuffer = new SocketInputBuffer(); + + filterLibrary = new InputFilter[0]; + activeFilters = new InputFilter[0]; + lastActiveFilter = -1; + + parsingHeader = true; + swallowInput = true; + + if (readTimeout < 0) { + this.readTimeout = -1; + } else { + this.readTimeout = readTimeout * 1000; + } + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote request. + */ + protected Request request; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * State. + */ + protected boolean parsingHeader; + + + /** + * Swallow input ? (in the case of an expectation) + */ + protected boolean swallowInput; + + + /** + * Pointer to the current read buffer. + */ + protected byte[] buf; + + + /** + * Last valid byte. + */ + protected int lastValid; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * Pos of the end of the header in the buffer, which is also the + * start of the body. + */ + protected int end; + + + /** + * Direct byte buffer used to perform actual reading. + */ + protected ByteBuffer bbuf; + + + /** + * Underlying socket. + */ + protected long socket; + + + /** + * Underlying input buffer. + */ + protected InputBuffer inputStreamInputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected InputFilter[] filterLibrary; + + + /** + * Active filters (in order). + */ + protected InputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + /** + * The socket timeout used when reading the first block of the request + * header. + */ + protected long readTimeout; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(long socket) { + this.socket = socket; + Socket.setrbb(this.socket, bbuf); + } + + + /** + * Get the underlying socket input stream. + */ + public long getSocket() { + return socket; + } + + + /** + * Add an input filter to the filter library. + */ + public void addFilter(InputFilter filter) { + + InputFilter[] newFilterLibrary = + new InputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new InputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public InputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new InputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an input filter to the filter library. + */ + public void addActiveFilter(InputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(inputStreamInputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setRequest(request); + + } + + + /** + * Set the swallow input flag. + */ + public void setSwallowInput(boolean swallowInput) { + this.swallowInput = swallowInput; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the input buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + request.recycle(); + + socket = 0; + lastValid = 0; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() { + + // Recycle Request object + request.recycle(); + + //System.out.println("LV-pos: " + (lastValid - pos)); + // Copy leftover bytes to the beginning of the buffer + if (lastValid - pos > 0) { + int npos = 0; + int opos = pos; + while (lastValid - opos > opos - npos) { + System.arraycopy(buf, opos, buf, npos, opos - npos); + npos += pos; + opos += pos; + } + System.arraycopy(buf, opos, buf, npos, lastValid - opos); + } + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + lastValid = lastValid - pos; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End request (consumes leftover bytes). + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (swallowInput && (lastActiveFilter != -1)) { + int extraBytes = (int) activeFilters[lastActiveFilter].end(); + pos = pos - extraBytes; + } + + } + + + /** + * Read the request line. This function is meant to be used during the + * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accomodate + * the whole line. + * @return true if data is properly fed; false if no data is available + * immediately and thread should be freed + */ + public boolean parseRequestLine(boolean useAvailableData) + throws IOException { + + int start = 0; + + // + // Skipping blank lines + // + + byte chr = 0; + do { + + // Read new bytes if needed + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (readTimeout == -1) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } else { + // Do a simple read with a short timeout + bbuf.clear(); + int nRead = Socket.recvbbt + (socket, 0, buf.length - lastValid, readTimeout); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { + return false; + } else { + throw new IOException(sm.getString("iib.failedread")); + } + } + } + } + + chr = buf[pos++]; + + } while ((chr == Constants.CR) || (chr == Constants.LF)); + + pos--; + + // Mark the current buffer position + start = pos; + + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (readTimeout == -1) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } else { + // Do a simple read with a short timeout + bbuf.clear(); + int nRead = Socket.recvbbt + (socket, 0, buf.length - lastValid, readTimeout); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + if ((-nRead) == Status.ETIMEDOUT || (-nRead) == Status.TIMEUP) { + return false; + } else { + throw new IOException(sm.getString("iib.failedread")); + } + } + } + } + + // + // Reading the method name + // Method name is always US-ASCII + // + + boolean space = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + request.method().setBytes(buf, start, pos - start); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int end = 0; + int questionPos = -1; + + // + // Reading the URI + // + + space = false; + boolean eol = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + end = pos; + } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; + } else if ((buf[pos] == Constants.QUESTION) + && (questionPos == -1)) { + questionPos = pos; + } + + pos++; + + } + + request.unparsedURI().setBytes(buf, start, end - start); + if (questionPos >= 0) { + request.queryString().setBytes(buf, questionPos + 1, + end - questionPos - 1); + request.requestURI().setBytes(buf, start, questionPos - start); + } else { + request.requestURI().setBytes(buf, start, end - start); + } + + // Mark the current buffer position + start = pos; + end = 0; + + // + // Reading the protocol + // Protocol is always US-ASCII + // + + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + end = pos; + } else if (buf[pos] == Constants.LF) { + if (end == 0) + end = pos; + eol = true; + } + + pos++; + + } + + if ((end - start) > 0) { + request.protocol().setBytes(buf, start, end - start); + } else { + request.protocol().setString(""); + } + + return true; + + } + + + /** + * Parse the HTTP headers. + */ + public void parseHeaders() + throws IOException { + + while (parseHeader()) { + } + + parsingHeader = false; + end = pos; + + } + + + /** + * Parse an HTTP header. + * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ + public boolean parseHeader() + throws IOException { + + // + // Check for blank line + // + + byte chr = 0; + while (true) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + + if ((chr == Constants.CR) || (chr == Constants.LF)) { + if (chr == Constants.LF) { + pos++; + return false; + } + } else { + break; + } + + pos++; + + } + + // Mark the current buffer position + int start = pos; + + // + // Reading the header name + // Header name is always US-ASCII + // + + boolean colon = false; + MessageBytes headerValue = null; + + while (!colon) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); + } + chr = buf[pos]; + if ((chr >= Constants.A) && (chr <= Constants.Z)) { + buf[pos] = (byte) (chr - Constants.LC_OFFSET); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int realPos = pos; + + // + // Reading the header value (which can be spanned over multiple lines) + // + + boolean eol = false; + boolean validLine = true; + + while (validLine) { + + boolean space = true; + + // Skipping spaces + while (space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { + pos++; + } else { + space = false; + } + + } + + int lastSignificantChar = realPos; + + // Reading bytes until the end of the line + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else if (buf[pos] == Constants.SP) { + buf[realPos] = buf[pos]; + realPos++; + } else { + buf[realPos] = buf[pos]; + realPos++; + lastSignificantChar = realPos; + } + + pos++; + + } + + realPos = lastSignificantChar; + + // Checking the first character of the new line. If the character + // is a LWS, then it's a multiline header + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + if ((chr != Constants.SP) && (chr != Constants.HT)) { + validLine = false; + } else { + eol = false; + // Copying one extra space in the buffer (since there must + // be at least one space inserted between the lines) + buf[realPos] = chr; + realPos++; + } + + } + + // Set the header value + headerValue.setBytes(buf, start, realPos - start); + + return true; + + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read some bytes. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (lastActiveFilter == -1) + return inputStreamInputBuffer.doRead(chunk, req); + else + return activeFilters[lastActiveFilter].doRead(chunk,req); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Fill the internal buffer using data from the undelying input stream. + * + * @return false if at end of stream + */ + protected boolean fill() + throws IOException { + + int nRead = 0; + + if (parsingHeader) { + + if (lastValid == buf.length) { + throw new IOException + (sm.getString("iib.requestheadertoolarge.error")); + } + + bbuf.clear(); + nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + if ((-nRead) == Status.EAGAIN) { + return false; + } else { + throw new IOException(sm.getString("iib.failedread")); + } + } + + } else { + + if (buf.length - end < 4500) { + // In this case, the request header was really large, so we allocate a + // brand new one; the old one will get GCed when subsequent requests + // clear all references + buf = new byte[buf.length]; + end = 0; + } + pos = end; + lastValid = pos; + bbuf.clear(); + nRead = Socket.recvbb(socket, 0, buf.length - lastValid); + if (nRead > 0) { + bbuf.limit(nRead); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + } else { + throw new IOException(sm.getString("iib.failedread")); + } + + } + + return (nRead > 0); + + } + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class SocketInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { + if (!fill()) + return -1; + } + + int length = lastValid - pos; + chunk.setBytes(buf, pos, length); + pos = lastValid; + + return (length); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/InternalAprOutputBuffer.java b/java/org/apache/coyote/http11/InternalAprOutputBuffer.java index e153dd909..518db74c9 100644 --- a/java/org/apache/coyote/http11/InternalAprOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalAprOutputBuffer.java @@ -1,738 +1,738 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.nio.ByteBuffer; - -import org.apache.tomcat.jni.Socket; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; - -/** - * Output buffer. - * - * @author Remy Maucherat - */ -public class InternalAprOutputBuffer - implements OutputBuffer { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. - */ - public InternalAprOutputBuffer(Response response) { - this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); - } - - - /** - * Alternate constructor. - */ - public InternalAprOutputBuffer(Response response, int headerBufferSize) { - - this.response = response; - headers = response.getMimeHeaders(); - - buf = new byte[headerBufferSize]; - if (headerBufferSize < (8 * 1024)) { - bbuf = ByteBuffer.allocateDirect(6 * 1500); - } else { - bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); - } - - outputStreamOutputBuffer = new SocketOutputBuffer(); - - filterLibrary = new OutputFilter[0]; - activeFilters = new OutputFilter[0]; - lastActiveFilter = -1; - - committed = false; - finished = false; - - // Cause loading of HttpMessages - HttpMessages.getMessage(200); - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote response. - */ - protected Response response; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * Committed flag. - */ - protected boolean committed; - - - /** - * Finished flag. - */ - protected boolean finished; - - - /** - * Pointer to the current write buffer. - */ - protected byte[] buf; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * Underlying socket. - */ - protected long socket; - - - /** - * Underlying output buffer. - */ - protected OutputBuffer outputStreamOutputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected OutputFilter[] filterLibrary; - - - /** - * Active filter (which is actually the top of the pipeline). - */ - protected OutputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - /** - * Direct byte buffer used for writing. - */ - protected ByteBuffer bbuf = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket. - */ - public void setSocket(long socket) { - this.socket = socket; - Socket.setsbb(this.socket, bbuf); - } - - - /** - * Get the underlying socket input stream. - */ - public long getSocket() { - return socket; - } - - - /** - * Set the socket buffer size. - */ - public void setSocketBuffer(int socketBufferSize) { - // FIXME: Remove - } - - - /** - * Add an output filter to the filter library. - */ - public void addFilter(OutputFilter filter) { - - OutputFilter[] newFilterLibrary = - new OutputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new OutputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public OutputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new OutputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an output filter to the filter library. - */ - public void addActiveFilter(OutputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(outputStreamOutputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setResponse(response); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Flush the response. - * - * @throws IOException an undelying I/O error occured - */ - public void flush() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - // Flush the current buffer - flushBuffer(); - - } - - - /** - * Reset current response. - * - * @throws IllegalStateException if the response has already been committed - */ - public void reset() { - - if (committed) - throw new IllegalStateException(/*FIXME:Put an error message*/); - - // Recycle Request object - response.recycle(); - - } - - - /** - * Recycle the output buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - response.recycle(); - bbuf.clear(); - - socket = 0; - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() { - - // Recycle Request object - response.recycle(); - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End request. - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (finished) - return; - - if (lastActiveFilter != -1) - activeFilters[lastActiveFilter].end(); - - flushBuffer(); - - finished = true; - - } - - - // ------------------------------------------------ HTTP/1.1 Output Methods - - - /** - * Send an acknoledgement. - */ - public void sendAck() - throws IOException { - - if (!committed) { - if (Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0) - throw new IOException(sm.getString("iib.failedwrite")); - } - - } - - - /** - * Send the response status line. - */ - public void sendStatus() { - - // Write protocol name - write(Constants.HTTP_11_BYTES); - buf[pos++] = Constants.SP; - - // Write status code - int status = response.getStatus(); - switch (status) { - case 200: - write(Constants._200_BYTES); - break; - case 400: - write(Constants._400_BYTES); - break; - case 404: - write(Constants._404_BYTES); - break; - default: - write(status); - } - - buf[pos++] = Constants.SP; - - // Write message - String message = response.getMessage(); - if (message == null) { - write(HttpMessages.getMessage(status)); - } else { - write(message); - } - - // End the response status line - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(MessageBytes name, MessageBytes value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(ByteChunk name, ByteChunk value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(String name, String value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * End the header block. - */ - public void endHeaders() { - - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write the contents of a byte chunk. - * - * @param chunk byte chunk - * @return number of bytes written - * @throws IOException an undelying I/O error occured - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeaders) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (lastActiveFilter == -1) - return outputStreamOutputBuffer.doWrite(chunk, res); - else - return activeFilters[lastActiveFilter].doWrite(chunk, res); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Commit the response. - * - * @throws IOException an undelying I/O error occured - */ - protected void commit() - throws IOException { - - // The response is now committed - committed = true; - response.setCommitted(true); - - if (pos > 0) { - // Sending the response header buffer - bbuf.put(buf, 0, pos); - } - - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param mb data to be written - */ - protected void write(MessageBytes mb) { - - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - write(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - CharChunk cc = mb.getCharChunk(); - write(cc); - } else { - write(mb.toString()); - } - - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param bc data to be written - */ - protected void write(ByteChunk bc) { - - // Writing the byte chunk to the output buffer - System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, - bc.getLength()); - pos = pos + bc.getLength(); - - } - - - /** - * This method will write the contents of the specyfied char - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param cc data to be written - */ - protected void write(CharChunk cc) { - - int start = cc.getStart(); - int end = cc.getEnd(); - char[] cbuf = cc.getBuffer(); - for (int i = start; i < end; i++) { - char c = cbuf[i]; - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will write the contents of the specyfied byte - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param b data to be written - */ - public void write(byte[] b) { - - // Writing the byte chunk to the output buffer - System.arraycopy(b, 0, buf, pos, b.length); - pos = pos + b.length; - - } - - - /** - * This method will write the contents of the specyfied String to the - * output stream, without filtering. This method is meant to be used to - * write the response header. - * - * @param s data to be written - */ - protected void write(String s) { - - if (s == null) - return; - - // From the Tomcat 3.3 HTTP/1.0 connector - int len = s.length(); - for (int i = 0; i < len; i++) { - char c = s.charAt (i); - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will print the specified integer to the output stream, - * without filtering. This method is meant to be used to write the - * response header. - * - * @param i data to be written - */ - protected void write(int i) { - - write(String.valueOf(i)); - - } - - - /** - * Callback to write data from the buffer. - */ - protected void flushBuffer() - throws IOException { - if (bbuf.position() > 0) { - if (Socket.sendbb(socket, 0, bbuf.position()) < 0) { - throw new IOException(); - } - bbuf.clear(); - } - } - - - // ----------------------------------- OutputStreamOutputBuffer Inner Class - - - /** - * This class is an output buffer which will write data to an output - * stream. - */ - protected class SocketOutputBuffer - implements OutputBuffer { - - - /** - * Write chunk. - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - int len = chunk.getLength(); - int start = chunk.getStart(); - byte[] b = chunk.getBuffer(); - while (len > 0) { - int thisTime = len; - if (bbuf.position() == bbuf.capacity()) { - flushBuffer(); - } - if (thisTime > bbuf.capacity() - bbuf.position()) { - thisTime = bbuf.capacity() - bbuf.position(); - } - bbuf.put(b, start, thisTime); - len = len - thisTime; - start = start + thisTime; - } - return chunk.getLength(); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.nio.ByteBuffer; + +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; + +/** + * Output buffer. + * + * @author Remy Maucherat + */ +public class InternalAprOutputBuffer + implements OutputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. + */ + public InternalAprOutputBuffer(Response response) { + this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); + } + + + /** + * Alternate constructor. + */ + public InternalAprOutputBuffer(Response response, int headerBufferSize) { + + this.response = response; + headers = response.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + if (headerBufferSize < (8 * 1024)) { + bbuf = ByteBuffer.allocateDirect(6 * 1500); + } else { + bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); + } + + outputStreamOutputBuffer = new SocketOutputBuffer(); + + filterLibrary = new OutputFilter[0]; + activeFilters = new OutputFilter[0]; + lastActiveFilter = -1; + + committed = false; + finished = false; + + // Cause loading of HttpMessages + HttpMessages.getMessage(200); + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote response. + */ + protected Response response; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * Committed flag. + */ + protected boolean committed; + + + /** + * Finished flag. + */ + protected boolean finished; + + + /** + * Pointer to the current write buffer. + */ + protected byte[] buf; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * Underlying socket. + */ + protected long socket; + + + /** + * Underlying output buffer. + */ + protected OutputBuffer outputStreamOutputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected OutputFilter[] filterLibrary; + + + /** + * Active filter (which is actually the top of the pipeline). + */ + protected OutputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + /** + * Direct byte buffer used for writing. + */ + protected ByteBuffer bbuf = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(long socket) { + this.socket = socket; + Socket.setsbb(this.socket, bbuf); + } + + + /** + * Get the underlying socket input stream. + */ + public long getSocket() { + return socket; + } + + + /** + * Set the socket buffer size. + */ + public void setSocketBuffer(int socketBufferSize) { + // FIXME: Remove + } + + + /** + * Add an output filter to the filter library. + */ + public void addFilter(OutputFilter filter) { + + OutputFilter[] newFilterLibrary = + new OutputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new OutputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public OutputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new OutputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an output filter to the filter library. + */ + public void addActiveFilter(OutputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(outputStreamOutputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setResponse(response); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Flush the response. + * + * @throws IOException an undelying I/O error occured + */ + public void flush() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + // Flush the current buffer + flushBuffer(); + + } + + + /** + * Reset current response. + * + * @throws IllegalStateException if the response has already been committed + */ + public void reset() { + + if (committed) + throw new IllegalStateException(/*FIXME:Put an error message*/); + + // Recycle Request object + response.recycle(); + + } + + + /** + * Recycle the output buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + response.recycle(); + bbuf.clear(); + + socket = 0; + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() { + + // Recycle Request object + response.recycle(); + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End request. + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (finished) + return; + + if (lastActiveFilter != -1) + activeFilters[lastActiveFilter].end(); + + flushBuffer(); + + finished = true; + + } + + + // ------------------------------------------------ HTTP/1.1 Output Methods + + + /** + * Send an acknoledgement. + */ + public void sendAck() + throws IOException { + + if (!committed) { + if (Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0) + throw new IOException(sm.getString("iib.failedwrite")); + } + + } + + + /** + * Send the response status line. + */ + public void sendStatus() { + + // Write protocol name + write(Constants.HTTP_11_BYTES); + buf[pos++] = Constants.SP; + + // Write status code + int status = response.getStatus(); + switch (status) { + case 200: + write(Constants._200_BYTES); + break; + case 400: + write(Constants._400_BYTES); + break; + case 404: + write(Constants._404_BYTES); + break; + default: + write(status); + } + + buf[pos++] = Constants.SP; + + // Write message + String message = response.getMessage(); + if (message == null) { + write(HttpMessages.getMessage(status)); + } else { + write(message); + } + + // End the response status line + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(MessageBytes name, MessageBytes value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(ByteChunk name, ByteChunk value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(String name, String value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * End the header block. + */ + public void endHeaders() { + + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write the contents of a byte chunk. + * + * @param chunk byte chunk + * @return number of bytes written + * @throws IOException an undelying I/O error occured + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeaders) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (lastActiveFilter == -1) + return outputStreamOutputBuffer.doWrite(chunk, res); + else + return activeFilters[lastActiveFilter].doWrite(chunk, res); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Commit the response. + * + * @throws IOException an undelying I/O error occured + */ + protected void commit() + throws IOException { + + // The response is now committed + committed = true; + response.setCommitted(true); + + if (pos > 0) { + // Sending the response header buffer + bbuf.put(buf, 0, pos); + } + + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param mb data to be written + */ + protected void write(MessageBytes mb) { + + if (mb.getType() == MessageBytes.T_BYTES) { + ByteChunk bc = mb.getByteChunk(); + write(bc); + } else if (mb.getType() == MessageBytes.T_CHARS) { + CharChunk cc = mb.getCharChunk(); + write(cc); + } else { + write(mb.toString()); + } + + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param bc data to be written + */ + protected void write(ByteChunk bc) { + + // Writing the byte chunk to the output buffer + System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, + bc.getLength()); + pos = pos + bc.getLength(); + + } + + + /** + * This method will write the contents of the specyfied char + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param cc data to be written + */ + protected void write(CharChunk cc) { + + int start = cc.getStart(); + int end = cc.getEnd(); + char[] cbuf = cc.getBuffer(); + for (int i = start; i < end; i++) { + char c = cbuf[i]; + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will write the contents of the specyfied byte + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param b data to be written + */ + public void write(byte[] b) { + + // Writing the byte chunk to the output buffer + System.arraycopy(b, 0, buf, pos, b.length); + pos = pos + b.length; + + } + + + /** + * This method will write the contents of the specyfied String to the + * output stream, without filtering. This method is meant to be used to + * write the response header. + * + * @param s data to be written + */ + protected void write(String s) { + + if (s == null) + return; + + // From the Tomcat 3.3 HTTP/1.0 connector + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt (i); + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will print the specified integer to the output stream, + * without filtering. This method is meant to be used to write the + * response header. + * + * @param i data to be written + */ + protected void write(int i) { + + write(String.valueOf(i)); + + } + + + /** + * Callback to write data from the buffer. + */ + protected void flushBuffer() + throws IOException { + if (bbuf.position() > 0) { + if (Socket.sendbb(socket, 0, bbuf.position()) < 0) { + throw new IOException(); + } + bbuf.clear(); + } + } + + + // ----------------------------------- OutputStreamOutputBuffer Inner Class + + + /** + * This class is an output buffer which will write data to an output + * stream. + */ + protected class SocketOutputBuffer + implements OutputBuffer { + + + /** + * Write chunk. + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + int len = chunk.getLength(); + int start = chunk.getStart(); + byte[] b = chunk.getBuffer(); + while (len > 0) { + int thisTime = len; + if (bbuf.position() == bbuf.capacity()) { + flushBuffer(); + } + if (thisTime > bbuf.capacity() - bbuf.position()) { + thisTime = bbuf.capacity() - bbuf.position(); + } + bbuf.put(b, start, thisTime); + len = len - thisTime; + start = start + thisTime; + } + return chunk.getLength(); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/InternalInputBuffer.java b/java/org/apache/coyote/http11/InternalInputBuffer.java index 3c199581c..a4a41d30d 100644 --- a/java/org/apache/coyote/http11/InternalInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalInputBuffer.java @@ -1,793 +1,793 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.io.InputStream; -import java.io.EOFException; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; - -/** - * Implementation of InputBuffer which provides HTTP request header parsing as - * well as transfer decoding. - * - * @author Remy Maucherat - */ -public class InternalInputBuffer implements InputBuffer { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. - */ - public InternalInputBuffer(Request request) { - this(request, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); - } - - - /** - * Alternate constructor. - */ - public InternalInputBuffer(Request request, int headerBufferSize) { - - this.request = request; - headers = request.getMimeHeaders(); - - headerBuffer1 = new byte[headerBufferSize]; - headerBuffer2 = new byte[headerBufferSize]; - bodyBuffer = new byte[headerBufferSize]; - buf = headerBuffer1; - - headerBuffer = new char[headerBufferSize]; - ascbuf = headerBuffer; - - inputStreamInputBuffer = new InputStreamInputBuffer(); - - filterLibrary = new InputFilter[0]; - activeFilters = new InputFilter[0]; - lastActiveFilter = -1; - - parsingHeader = true; - swallowInput = true; - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote request. - */ - protected Request request; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * State. - */ - protected boolean parsingHeader; - - - /** - * Swallow input ? (in the case of an expectation) - */ - protected boolean swallowInput; - - - /** - * Pointer to the current read buffer. - */ - protected byte[] buf; - - - /** - * Pointer to the US-ASCII header buffer. - */ - protected char[] ascbuf; - - - /** - * Last valid byte. - */ - protected int lastValid; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * HTTP header buffer no 1. - */ - protected byte[] headerBuffer1; - - - /** - * HTTP header buffer no 2. - */ - protected byte[] headerBuffer2; - - - /** - * HTTP body buffer. - */ - protected byte[] bodyBuffer; - - - /** - * US-ASCII header buffer. - */ - protected char[] headerBuffer; - - - /** - * Underlying input stream. - */ - protected InputStream inputStream; - - - /** - * Underlying input buffer. - */ - protected InputBuffer inputStreamInputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected InputFilter[] filterLibrary; - - - /** - * Active filters (in order). - */ - protected InputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket input stream. - */ - public void setInputStream(InputStream inputStream) { - - // FIXME: Check for null ? - - this.inputStream = inputStream; - - } - - - /** - * Get the underlying socket input stream. - */ - public InputStream getInputStream() { - - return inputStream; - - } - - - /** - * Add an input filter to the filter library. - */ - public void addFilter(InputFilter filter) { - - // FIXME: Check for null ? - - InputFilter[] newFilterLibrary = - new InputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new InputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public InputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new InputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an input filter to the filter library. - */ - public void addActiveFilter(InputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(inputStreamInputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setRequest(request); - - } - - - /** - * Set the swallow input flag. - */ - public void setSwallowInput(boolean swallowInput) { - this.swallowInput = swallowInput; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Recycle the input buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - request.recycle(); - - inputStream = null; - buf = headerBuffer1; - lastValid = 0; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() - throws IOException { - - // Recycle Request object - request.recycle(); - - // Determine the header buffer used for next request - byte[] newHeaderBuf = null; - if (buf == headerBuffer1) { - newHeaderBuf = headerBuffer2; - } else { - newHeaderBuf = headerBuffer1; - } - - // Copy leftover bytes from buf to newHeaderBuf - System.arraycopy(buf, pos, newHeaderBuf, 0, lastValid - pos); - - // Swap buffers - buf = newHeaderBuf; - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - lastValid = lastValid - pos; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End request (consumes leftover bytes). - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (swallowInput && (lastActiveFilter != -1)) { - int extraBytes = (int) activeFilters[lastActiveFilter].end(); - pos = pos - extraBytes; - } - - } - - - /** - * Read the request line. This function is meant to be used during the - * HTTP request header parsing. Do NOT attempt to read the request body - * using it. - * - * @throws IOException If an exception occurs during the underlying socket - * read operations, or if the given buffer is not big enough to accomodate - * the whole line. - */ - public void parseRequestLine() - throws IOException { - - int start = 0; - - // - // Skipping blank lines - // - - byte chr = 0; - do { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos++]; - - } while ((chr == Constants.CR) || (chr == Constants.LF)); - - pos--; - - // Mark the current buffer position - start = pos; - - // - // Reading the method name - // Method name is always US-ASCII - // - - boolean space = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - ascbuf[pos] = (char) buf[pos]; - - if (buf[pos] == Constants.SP) { - space = true; - request.method().setChars(ascbuf, start, pos - start); - } - - pos++; - - } - - // Mark the current buffer position - start = pos; - int end = 0; - int questionPos = -1; - - // - // Reading the URI - // - - space = false; - boolean eol = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.SP) { - space = true; - end = pos; - } else if ((buf[pos] == Constants.CR) - || (buf[pos] == Constants.LF)) { - // HTTP/0.9 style request - eol = true; - space = true; - end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (questionPos == -1)) { - questionPos = pos; - } - - pos++; - - } - - request.unparsedURI().setBytes(buf, start, end - start); - if (questionPos >= 0) { - request.queryString().setBytes(buf, questionPos + 1, - end - questionPos - 1); - request.requestURI().setBytes(buf, start, questionPos - start); - } else { - request.requestURI().setBytes(buf, start, end - start); - } - - // Mark the current buffer position - start = pos; - end = 0; - - // - // Reading the protocol - // Protocol is always US-ASCII - // - - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - ascbuf[pos] = (char) buf[pos]; - - if (buf[pos] == Constants.CR) { - end = pos; - } else if (buf[pos] == Constants.LF) { - if (end == 0) - end = pos; - eol = true; - } - - pos++; - - } - - if ((end - start) > 0) { - request.protocol().setChars(ascbuf, start, end - start); - } else { - request.protocol().setString(""); - } - - } - - - /** - * Parse the HTTP headers. - */ - public void parseHeaders() - throws IOException { - - while (parseHeader()) { - } - - parsingHeader = false; - - } - - - /** - * Parse an HTTP header. - * - * @return false after reading a blank line (which indicates that the - * HTTP header parsing is done - */ - public boolean parseHeader() - throws IOException { - - // - // Check for blank line - // - - byte chr = 0; - while (true) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - - if ((chr == Constants.CR) || (chr == Constants.LF)) { - if (chr == Constants.LF) { - pos++; - return false; - } - } else { - break; - } - - pos++; - - } - - // Mark the current buffer position - int start = pos; - - // - // Reading the header name - // Header name is always US-ASCII - // - - boolean colon = false; - MessageBytes headerValue = null; - - while (!colon) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.COLON) { - colon = true; - headerValue = headers.addValue(ascbuf, start, pos - start); - } - chr = buf[pos]; - if ((chr >= Constants.A) && (chr <= Constants.Z)) { - buf[pos] = (byte) (chr - Constants.LC_OFFSET); - } - - ascbuf[pos] = (char) buf[pos]; - - pos++; - - } - - // Mark the current buffer position - start = pos; - int realPos = pos; - - // - // Reading the header value (which can be spanned over multiple lines) - // - - boolean eol = false; - boolean validLine = true; - - while (validLine) { - - boolean space = true; - - // Skipping spaces - while (space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { - pos++; - } else { - space = false; - } - - } - - int lastSignificantChar = realPos; - - // Reading bytes until the end of the line - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.CR) { - } else if (buf[pos] == Constants.LF) { - eol = true; - } else if (buf[pos] == Constants.SP) { - buf[realPos] = buf[pos]; - realPos++; - } else { - buf[realPos] = buf[pos]; - realPos++; - lastSignificantChar = realPos; - } - - pos++; - - } - - realPos = lastSignificantChar; - - // Checking the first character of the new line. If the character - // is a LWS, then it's a multiline header - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - if ((chr != Constants.SP) && (chr != Constants.HT)) { - validLine = false; - } else { - eol = false; - // Copying one extra space in the buffer (since there must - // be at least one space inserted between the lines) - buf[realPos] = chr; - realPos++; - } - - } - - // Set the header value - headerValue.setBytes(buf, start, realPos - start); - - return true; - - } - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Read some bytes. - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - if (lastActiveFilter == -1) - return inputStreamInputBuffer.doRead(chunk, req); - else - return activeFilters[lastActiveFilter].doRead(chunk,req); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Fill the internal buffer using data from the undelying input stream. - * - * @return false if at end of stream - */ - protected boolean fill() - throws IOException { - - int nRead = 0; - - if (parsingHeader) { - - if (lastValid == buf.length) { - throw new IOException - (sm.getString("iib.requestheadertoolarge.error")); - } - - nRead = inputStream.read(buf, pos, buf.length - lastValid); - if (nRead > 0) { - lastValid = pos + nRead; - } - - } else { - - buf = bodyBuffer; - pos = 0; - lastValid = 0; - nRead = inputStream.read(buf, 0, buf.length); - if (nRead > 0) { - lastValid = nRead; - } - - } - - return (nRead > 0); - - } - - - // ------------------------------------- InputStreamInputBuffer Inner Class - - - /** - * This class is an input buffer which will read its data from an input - * stream. - */ - protected class InputStreamInputBuffer - implements InputBuffer { - - - /** - * Read bytes into the specified chunk. - */ - public int doRead(ByteChunk chunk, Request req ) - throws IOException { - - if (pos >= lastValid) { - if (!fill()) - return -1; - } - - int length = lastValid - pos; - chunk.setBytes(buf, pos, length); - pos = lastValid; - - return (length); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.io.InputStream; +import java.io.EOFException; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; + +/** + * Implementation of InputBuffer which provides HTTP request header parsing as + * well as transfer decoding. + * + * @author Remy Maucherat + */ +public class InternalInputBuffer implements InputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. + */ + public InternalInputBuffer(Request request) { + this(request, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); + } + + + /** + * Alternate constructor. + */ + public InternalInputBuffer(Request request, int headerBufferSize) { + + this.request = request; + headers = request.getMimeHeaders(); + + headerBuffer1 = new byte[headerBufferSize]; + headerBuffer2 = new byte[headerBufferSize]; + bodyBuffer = new byte[headerBufferSize]; + buf = headerBuffer1; + + headerBuffer = new char[headerBufferSize]; + ascbuf = headerBuffer; + + inputStreamInputBuffer = new InputStreamInputBuffer(); + + filterLibrary = new InputFilter[0]; + activeFilters = new InputFilter[0]; + lastActiveFilter = -1; + + parsingHeader = true; + swallowInput = true; + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote request. + */ + protected Request request; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * State. + */ + protected boolean parsingHeader; + + + /** + * Swallow input ? (in the case of an expectation) + */ + protected boolean swallowInput; + + + /** + * Pointer to the current read buffer. + */ + protected byte[] buf; + + + /** + * Pointer to the US-ASCII header buffer. + */ + protected char[] ascbuf; + + + /** + * Last valid byte. + */ + protected int lastValid; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * HTTP header buffer no 1. + */ + protected byte[] headerBuffer1; + + + /** + * HTTP header buffer no 2. + */ + protected byte[] headerBuffer2; + + + /** + * HTTP body buffer. + */ + protected byte[] bodyBuffer; + + + /** + * US-ASCII header buffer. + */ + protected char[] headerBuffer; + + + /** + * Underlying input stream. + */ + protected InputStream inputStream; + + + /** + * Underlying input buffer. + */ + protected InputBuffer inputStreamInputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected InputFilter[] filterLibrary; + + + /** + * Active filters (in order). + */ + protected InputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket input stream. + */ + public void setInputStream(InputStream inputStream) { + + // FIXME: Check for null ? + + this.inputStream = inputStream; + + } + + + /** + * Get the underlying socket input stream. + */ + public InputStream getInputStream() { + + return inputStream; + + } + + + /** + * Add an input filter to the filter library. + */ + public void addFilter(InputFilter filter) { + + // FIXME: Check for null ? + + InputFilter[] newFilterLibrary = + new InputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new InputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public InputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new InputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an input filter to the filter library. + */ + public void addActiveFilter(InputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(inputStreamInputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setRequest(request); + + } + + + /** + * Set the swallow input flag. + */ + public void setSwallowInput(boolean swallowInput) { + this.swallowInput = swallowInput; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the input buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + request.recycle(); + + inputStream = null; + buf = headerBuffer1; + lastValid = 0; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() + throws IOException { + + // Recycle Request object + request.recycle(); + + // Determine the header buffer used for next request + byte[] newHeaderBuf = null; + if (buf == headerBuffer1) { + newHeaderBuf = headerBuffer2; + } else { + newHeaderBuf = headerBuffer1; + } + + // Copy leftover bytes from buf to newHeaderBuf + System.arraycopy(buf, pos, newHeaderBuf, 0, lastValid - pos); + + // Swap buffers + buf = newHeaderBuf; + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + lastValid = lastValid - pos; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End request (consumes leftover bytes). + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (swallowInput && (lastActiveFilter != -1)) { + int extraBytes = (int) activeFilters[lastActiveFilter].end(); + pos = pos - extraBytes; + } + + } + + + /** + * Read the request line. This function is meant to be used during the + * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accomodate + * the whole line. + */ + public void parseRequestLine() + throws IOException { + + int start = 0; + + // + // Skipping blank lines + // + + byte chr = 0; + do { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos++]; + + } while ((chr == Constants.CR) || (chr == Constants.LF)); + + pos--; + + // Mark the current buffer position + start = pos; + + // + // Reading the method name + // Method name is always US-ASCII + // + + boolean space = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + ascbuf[pos] = (char) buf[pos]; + + if (buf[pos] == Constants.SP) { + space = true; + request.method().setChars(ascbuf, start, pos - start); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int end = 0; + int questionPos = -1; + + // + // Reading the URI + // + + space = false; + boolean eol = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + end = pos; + } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; + } else if ((buf[pos] == Constants.QUESTION) + && (questionPos == -1)) { + questionPos = pos; + } + + pos++; + + } + + request.unparsedURI().setBytes(buf, start, end - start); + if (questionPos >= 0) { + request.queryString().setBytes(buf, questionPos + 1, + end - questionPos - 1); + request.requestURI().setBytes(buf, start, questionPos - start); + } else { + request.requestURI().setBytes(buf, start, end - start); + } + + // Mark the current buffer position + start = pos; + end = 0; + + // + // Reading the protocol + // Protocol is always US-ASCII + // + + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + ascbuf[pos] = (char) buf[pos]; + + if (buf[pos] == Constants.CR) { + end = pos; + } else if (buf[pos] == Constants.LF) { + if (end == 0) + end = pos; + eol = true; + } + + pos++; + + } + + if ((end - start) > 0) { + request.protocol().setChars(ascbuf, start, end - start); + } else { + request.protocol().setString(""); + } + + } + + + /** + * Parse the HTTP headers. + */ + public void parseHeaders() + throws IOException { + + while (parseHeader()) { + } + + parsingHeader = false; + + } + + + /** + * Parse an HTTP header. + * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ + public boolean parseHeader() + throws IOException { + + // + // Check for blank line + // + + byte chr = 0; + while (true) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + + if ((chr == Constants.CR) || (chr == Constants.LF)) { + if (chr == Constants.LF) { + pos++; + return false; + } + } else { + break; + } + + pos++; + + } + + // Mark the current buffer position + int start = pos; + + // + // Reading the header name + // Header name is always US-ASCII + // + + boolean colon = false; + MessageBytes headerValue = null; + + while (!colon) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(ascbuf, start, pos - start); + } + chr = buf[pos]; + if ((chr >= Constants.A) && (chr <= Constants.Z)) { + buf[pos] = (byte) (chr - Constants.LC_OFFSET); + } + + ascbuf[pos] = (char) buf[pos]; + + pos++; + + } + + // Mark the current buffer position + start = pos; + int realPos = pos; + + // + // Reading the header value (which can be spanned over multiple lines) + // + + boolean eol = false; + boolean validLine = true; + + while (validLine) { + + boolean space = true; + + // Skipping spaces + while (space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { + pos++; + } else { + space = false; + } + + } + + int lastSignificantChar = realPos; + + // Reading bytes until the end of the line + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else if (buf[pos] == Constants.SP) { + buf[realPos] = buf[pos]; + realPos++; + } else { + buf[realPos] = buf[pos]; + realPos++; + lastSignificantChar = realPos; + } + + pos++; + + } + + realPos = lastSignificantChar; + + // Checking the first character of the new line. If the character + // is a LWS, then it's a multiline header + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + if ((chr != Constants.SP) && (chr != Constants.HT)) { + validLine = false; + } else { + eol = false; + // Copying one extra space in the buffer (since there must + // be at least one space inserted between the lines) + buf[realPos] = chr; + realPos++; + } + + } + + // Set the header value + headerValue.setBytes(buf, start, realPos - start); + + return true; + + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read some bytes. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (lastActiveFilter == -1) + return inputStreamInputBuffer.doRead(chunk, req); + else + return activeFilters[lastActiveFilter].doRead(chunk,req); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Fill the internal buffer using data from the undelying input stream. + * + * @return false if at end of stream + */ + protected boolean fill() + throws IOException { + + int nRead = 0; + + if (parsingHeader) { + + if (lastValid == buf.length) { + throw new IOException + (sm.getString("iib.requestheadertoolarge.error")); + } + + nRead = inputStream.read(buf, pos, buf.length - lastValid); + if (nRead > 0) { + lastValid = pos + nRead; + } + + } else { + + buf = bodyBuffer; + pos = 0; + lastValid = 0; + nRead = inputStream.read(buf, 0, buf.length); + if (nRead > 0) { + lastValid = nRead; + } + + } + + return (nRead > 0); + + } + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class InputStreamInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { + if (!fill()) + return -1; + } + + int length = lastValid - pos; + chunk.setBytes(buf, pos, length); + pos = lastValid; + + return (length); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/InternalNioInputBuffer.java b/java/org/apache/coyote/http11/InternalNioInputBuffer.java index 76f26dd82..9375e3f3e 100644 --- a/java/org/apache/coyote/http11/InternalNioInputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioInputBuffer.java @@ -1,876 +1,876 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.coyote.http11; - -import java.io.EOFException; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; -import java.nio.channels.Selector; -import java.nio.channels.SelectionKey; -import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; -import org.apache.tomcat.util.net.NioEndpoint.Poller; -import java.nio.channels.CancelledKeyException; - -/** - * Implementation of InputBuffer which provides HTTP request header parsing as - * well as transfer decoding. - * - * @author Remy Maucherat - * @author Filip Hanik - */ -public class InternalNioInputBuffer implements InputBuffer { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Alternate constructor. - */ - public InternalNioInputBuffer(Request request, int headerBufferSize, - long readTimeout) { - - this.request = request; - headers = request.getMimeHeaders(); - - buf = new byte[headerBufferSize]; - if (headerBufferSize < (8 * 1024)) { - bbuf = ByteBuffer.allocateDirect(6 * 1500); - } else { - bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); - } - - inputStreamInputBuffer = new SocketInputBuffer(); - - filterLibrary = new InputFilter[0]; - activeFilters = new InputFilter[0]; - lastActiveFilter = -1; - - parsingHeader = true; - swallowInput = true; - - if (readTimeout < 0) { - this.readTimeout = -1; - } else { - this.readTimeout = readTimeout; - } - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote request. - */ - protected Request request; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * State. - */ - protected boolean parsingHeader; - - - /** - * Swallow input ? (in the case of an expectation) - */ - protected boolean swallowInput; - - - /** - * Pointer to the current read buffer. - */ - protected byte[] buf; - - - /** - * Last valid byte. - */ - protected int lastValid; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * Pos of the end of the header in the buffer, which is also the - * start of the body. - */ - protected int end; - - - /** - * Direct byte buffer used to perform actual reading. - */ - protected ByteBuffer bbuf; - - - /** - * Underlying socket. - */ - protected SocketChannel socket; - - - /** - * Underlying input buffer. - */ - protected InputBuffer inputStreamInputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected InputFilter[] filterLibrary; - - - /** - * Active filters (in order). - */ - protected InputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - /** - * The socket timeout used when reading the first block of the request - * header. - */ - protected long readTimeout; - private Poller poller; - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket. - */ - public void setSocket(SocketChannel socket) { - this.socket = socket; - } - - - /** - * Get the underlying socket input stream. - */ - public SocketChannel getSocket() { - return socket; - } - - public Poller getPoller() { - return poller; - } - - /** - * Add an input filter to the filter library. - */ - public void addFilter(InputFilter filter) { - - InputFilter[] newFilterLibrary = - new InputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new InputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public InputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new InputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an input filter to the filter library. - */ - public void addActiveFilter(InputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(inputStreamInputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setRequest(request); - - } - - - /** - * Set the swallow input flag. - */ - public void setSwallowInput(boolean swallowInput) { - this.swallowInput = swallowInput; - } - - public void setPoller(Poller poller) { - this.poller = poller; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Recycle the input buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - request.recycle(); - - socket = null; - lastValid = 0; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() { - - // Recycle Request object - request.recycle(); - - //System.out.println("LV-pos: " + (lastValid - pos)); - // Copy leftover bytes to the beginning of the buffer - if (lastValid - pos > 0) { - int npos = 0; - int opos = pos; - while (lastValid - opos > opos - npos) { - System.arraycopy(buf, opos, buf, npos, opos - npos); - npos += pos; - opos += pos; - } - System.arraycopy(buf, opos, buf, npos, lastValid - opos); - } - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - lastValid = lastValid - pos; - pos = 0; - lastActiveFilter = -1; - parsingHeader = true; - swallowInput = true; - - } - - - /** - * End request (consumes leftover bytes). - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (swallowInput && (lastActiveFilter != -1)) { - int extraBytes = (int) activeFilters[lastActiveFilter].end(); - pos = pos - extraBytes; - } - - } - - - /** - * Read the request line. This function is meant to be used during the - * HTTP request header parsing. Do NOT attempt to read the request body - * using it. - * - * @throws IOException If an exception occurs during the underlying socket - * read operations, or if the given buffer is not big enough to accomodate - * the whole line. - * @return true if data is properly fed; false if no data is available - * immediately and thread should be freed - */ - public boolean parseRequestLine(boolean useAvailableData) - throws IOException { - - int start = 0; - - // - // Skipping blank lines - // - - byte chr = 0; - do { - - // Read new bytes if needed - if (pos >= lastValid) { - if (useAvailableData) { - return false; - } - if (readTimeout == -1) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } else { - // Do a simple read with a short timeout - if ( !readSocket(true) ) return false; - } - } - - chr = buf[pos++]; - - } while ((chr == Constants.CR) || (chr == Constants.LF)); - - pos--; - - // Mark the current buffer position - start = pos; - - if (pos >= lastValid) { - if (useAvailableData) { - return false; - } - if (readTimeout == -1) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } else { - // Do a simple read with a short timeout - if ( !readSocket(true) ) return false; - } - } - - // - // Reading the method name - // Method name is always US-ASCII - // - - boolean space = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.SP) { - space = true; - request.method().setBytes(buf, start, pos - start); - } - - pos++; - - } - - // Mark the current buffer position - start = pos; - int end = 0; - int questionPos = -1; - - // - // Reading the URI - // - - space = false; - boolean eol = false; - - while (!space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.SP) { - space = true; - end = pos; - } else if ((buf[pos] == Constants.CR) - || (buf[pos] == Constants.LF)) { - // HTTP/0.9 style request - eol = true; - space = true; - end = pos; - } else if ((buf[pos] == Constants.QUESTION) - && (questionPos == -1)) { - questionPos = pos; - } - - pos++; - - } - - request.unparsedURI().setBytes(buf, start, end - start); - if (questionPos >= 0) { - request.queryString().setBytes(buf, questionPos + 1, - end - questionPos - 1); - request.requestURI().setBytes(buf, start, questionPos - start); - } else { - request.requestURI().setBytes(buf, start, end - start); - } - - // Mark the current buffer position - start = pos; - end = 0; - - // - // Reading the protocol - // Protocol is always US-ASCII - // - - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.CR) { - end = pos; - } else if (buf[pos] == Constants.LF) { - if (end == 0) - end = pos; - eol = true; - } - - pos++; - - } - - if ((end - start) > 0) { - request.protocol().setBytes(buf, start, end - start); - } else { - request.protocol().setString(""); - } - - return true; - - } - - private void expand(int newsize) { - if ( newsize > buf.length ) { - byte[] tmp = new byte[newsize]; - System.arraycopy(buf,0,tmp,0,buf.length); - buf = tmp; - tmp = null; - } - } - /** - * Perform blocking read with a timeout if desired - * @param timeout boolean - set to true if the system will time out - * @return boolean - true if data was read, false is EOF is reached - * @throws IOException - */ - private boolean readSocket(boolean timeout) throws IOException { - int nRead = 0; - long start = System.currentTimeMillis(); - boolean timedOut = false; - do { - bbuf.clear(); - nRead = socket.read(bbuf); - if (nRead > 0) { - bbuf.flip(); - bbuf.limit(nRead); - expand(nRead + pos); - bbuf.get(buf, pos, nRead); - lastValid = pos + nRead; - return true; - } else if (nRead == -1) { - //return false; - throw new IOException("end of stream reached."); - } - timedOut = (readTimeout != -1) && ((System.currentTimeMillis()-start)>this.readTimeout); - if ( !timedOut && nRead == 0 ) - try { - final SelectionKey key = socket.keyFor(poller.getSelector()); - final KeyAttachment att = (KeyAttachment)key.attachment(); - //to do, add in a check, we might have just timed out on the wait, - //so there is no need to register us again. - boolean addToQueue = false; - try { addToQueue = ((key.interestOps()&SelectionKey.OP_READ) != SelectionKey.OP_READ); } catch ( CancelledKeyException ignore ){} - if ( addToQueue ) { - addToReadQueue(key, att); - }//end if - synchronized (att.getMutex()) { - if ( att.getWakeUp() ) att.getMutex().wait(25); - } - }catch ( Exception x ) {} - }while ( nRead == 0 && (!timedOut) ); - //else throw new IOException(sm.getString("iib.failedread")); - //return false; //timeout - throw new IOException("read timed out."); - } - - private void addToReadQueue(final SelectionKey key, final KeyAttachment att) { - att.setWakeUp(true); - poller.addEvent( - new Runnable() { - public void run() { - try { - if (key != null) key.interestOps(SelectionKey.OP_READ); - } catch (CancelledKeyException ckx) { - try { - if ( key != null && key.attachment() != null ) { - KeyAttachment ka = (KeyAttachment)key.attachment(); - ka.setError(true); //set to collect this socket immediately - } - socket.socket().close(); - socket.close(); - att.setWakeUp(false); - } catch (Exception ignore) {} - } - } - }); - } - - - /** - * Parse the HTTP headers. - */ - public void parseHeaders() - throws IOException { - - while (parseHeader()) { - } - - parsingHeader = false; - end = pos; - - } - - - /** - * Parse an HTTP header. - * - * @return false after reading a blank line (which indicates that the - * HTTP header parsing is done - */ - public boolean parseHeader() - throws IOException { - - // - // Check for blank line - // - - byte chr = 0; - while (true) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - - if ((chr == Constants.CR) || (chr == Constants.LF)) { - if (chr == Constants.LF) { - pos++; - return false; - } - } else { - break; - } - - pos++; - - } - - // Mark the current buffer position - int start = pos; - - // - // Reading the header name - // Header name is always US-ASCII - // - - boolean colon = false; - MessageBytes headerValue = null; - - while (!colon) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.COLON) { - colon = true; - headerValue = headers.addValue(buf, start, pos - start); - } - chr = buf[pos]; - if ((chr >= Constants.A) && (chr <= Constants.Z)) { - buf[pos] = (byte) (chr - Constants.LC_OFFSET); - } - - pos++; - - } - - // Mark the current buffer position - start = pos; - int realPos = pos; - - // - // Reading the header value (which can be spanned over multiple lines) - // - - boolean eol = false; - boolean validLine = true; - - while (validLine) { - - boolean space = true; - - // Skipping spaces - while (space) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { - pos++; - } else { - space = false; - } - - } - - int lastSignificantChar = realPos; - - // Reading bytes until the end of the line - while (!eol) { - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - if (buf[pos] == Constants.CR) { - } else if (buf[pos] == Constants.LF) { - eol = true; - } else if (buf[pos] == Constants.SP) { - buf[realPos] = buf[pos]; - realPos++; - } else { - buf[realPos] = buf[pos]; - realPos++; - lastSignificantChar = realPos; - } - - pos++; - - } - - realPos = lastSignificantChar; - - // Checking the first character of the new line. If the character - // is a LWS, then it's a multiline header - - // Read new bytes if needed - if (pos >= lastValid) { - if (!fill()) - throw new EOFException(sm.getString("iib.eof.error")); - } - - chr = buf[pos]; - if ((chr != Constants.SP) && (chr != Constants.HT)) { - validLine = false; - } else { - eol = false; - // Copying one extra space in the buffer (since there must - // be at least one space inserted between the lines) - buf[realPos] = chr; - realPos++; - } - - } - - // Set the header value - headerValue.setBytes(buf, start, realPos - start); - - return true; - - } - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Read some bytes. - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - if (lastActiveFilter == -1) - return inputStreamInputBuffer.doRead(chunk, req); - else - return activeFilters[lastActiveFilter].doRead(chunk,req); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Fill the internal buffer using data from the undelying input stream. - * - * @return false if at end of stream - */ - protected boolean fill() - throws IOException { - - boolean read = false; - - if (parsingHeader) { - - if (lastValid == buf.length) { - throw new IOException - (sm.getString("iib.requestheadertoolarge.error")); - } - - // Do a simple read with a short timeout - read = readSocket(true); - } else { - - if (buf.length - end < 4500) { - // In this case, the request header was really large, so we allocate a - // brand new one; the old one will get GCed when subsequent requests - // clear all references - buf = new byte[buf.length]; - end = 0; - } - pos = end; - lastValid = pos; - // Do a simple read with a short timeout - read = readSocket(true); - } - return read; - } - - - // ------------------------------------- InputStreamInputBuffer Inner Class - - - /** - * This class is an input buffer which will read its data from an input - * stream. - */ - protected class SocketInputBuffer - implements InputBuffer { - - - /** - * Read bytes into the specified chunk. - */ - public int doRead(ByteChunk chunk, Request req ) - throws IOException { - - if (pos >= lastValid) { - if (!fill()) - return -1; - } - - int length = lastValid - pos; - chunk.setBytes(buf, pos, length); - pos = lastValid; - - return (length); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.coyote.http11; + +import java.io.EOFException; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; +import java.nio.channels.Selector; +import java.nio.channels.SelectionKey; +import org.apache.tomcat.util.net.NioEndpoint.KeyAttachment; +import org.apache.tomcat.util.net.NioEndpoint.Poller; +import java.nio.channels.CancelledKeyException; + +/** + * Implementation of InputBuffer which provides HTTP request header parsing as + * well as transfer decoding. + * + * @author Remy Maucherat + * @author Filip Hanik + */ +public class InternalNioInputBuffer implements InputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Alternate constructor. + */ + public InternalNioInputBuffer(Request request, int headerBufferSize, + long readTimeout) { + + this.request = request; + headers = request.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + if (headerBufferSize < (8 * 1024)) { + bbuf = ByteBuffer.allocateDirect(6 * 1500); + } else { + bbuf = ByteBuffer.allocateDirect((headerBufferSize / 1500 + 1) * 1500); + } + + inputStreamInputBuffer = new SocketInputBuffer(); + + filterLibrary = new InputFilter[0]; + activeFilters = new InputFilter[0]; + lastActiveFilter = -1; + + parsingHeader = true; + swallowInput = true; + + if (readTimeout < 0) { + this.readTimeout = -1; + } else { + this.readTimeout = readTimeout; + } + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote request. + */ + protected Request request; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * State. + */ + protected boolean parsingHeader; + + + /** + * Swallow input ? (in the case of an expectation) + */ + protected boolean swallowInput; + + + /** + * Pointer to the current read buffer. + */ + protected byte[] buf; + + + /** + * Last valid byte. + */ + protected int lastValid; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * Pos of the end of the header in the buffer, which is also the + * start of the body. + */ + protected int end; + + + /** + * Direct byte buffer used to perform actual reading. + */ + protected ByteBuffer bbuf; + + + /** + * Underlying socket. + */ + protected SocketChannel socket; + + + /** + * Underlying input buffer. + */ + protected InputBuffer inputStreamInputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected InputFilter[] filterLibrary; + + + /** + * Active filters (in order). + */ + protected InputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + /** + * The socket timeout used when reading the first block of the request + * header. + */ + protected long readTimeout; + private Poller poller; + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(SocketChannel socket) { + this.socket = socket; + } + + + /** + * Get the underlying socket input stream. + */ + public SocketChannel getSocket() { + return socket; + } + + public Poller getPoller() { + return poller; + } + + /** + * Add an input filter to the filter library. + */ + public void addFilter(InputFilter filter) { + + InputFilter[] newFilterLibrary = + new InputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new InputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public InputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new InputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an input filter to the filter library. + */ + public void addActiveFilter(InputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(inputStreamInputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setRequest(request); + + } + + + /** + * Set the swallow input flag. + */ + public void setSwallowInput(boolean swallowInput) { + this.swallowInput = swallowInput; + } + + public void setPoller(Poller poller) { + this.poller = poller; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Recycle the input buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + request.recycle(); + + socket = null; + lastValid = 0; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() { + + // Recycle Request object + request.recycle(); + + //System.out.println("LV-pos: " + (lastValid - pos)); + // Copy leftover bytes to the beginning of the buffer + if (lastValid - pos > 0) { + int npos = 0; + int opos = pos; + while (lastValid - opos > opos - npos) { + System.arraycopy(buf, opos, buf, npos, opos - npos); + npos += pos; + opos += pos; + } + System.arraycopy(buf, opos, buf, npos, lastValid - opos); + } + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + lastValid = lastValid - pos; + pos = 0; + lastActiveFilter = -1; + parsingHeader = true; + swallowInput = true; + + } + + + /** + * End request (consumes leftover bytes). + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (swallowInput && (lastActiveFilter != -1)) { + int extraBytes = (int) activeFilters[lastActiveFilter].end(); + pos = pos - extraBytes; + } + + } + + + /** + * Read the request line. This function is meant to be used during the + * HTTP request header parsing. Do NOT attempt to read the request body + * using it. + * + * @throws IOException If an exception occurs during the underlying socket + * read operations, or if the given buffer is not big enough to accomodate + * the whole line. + * @return true if data is properly fed; false if no data is available + * immediately and thread should be freed + */ + public boolean parseRequestLine(boolean useAvailableData) + throws IOException { + + int start = 0; + + // + // Skipping blank lines + // + + byte chr = 0; + do { + + // Read new bytes if needed + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (readTimeout == -1) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } else { + // Do a simple read with a short timeout + if ( !readSocket(true) ) return false; + } + } + + chr = buf[pos++]; + + } while ((chr == Constants.CR) || (chr == Constants.LF)); + + pos--; + + // Mark the current buffer position + start = pos; + + if (pos >= lastValid) { + if (useAvailableData) { + return false; + } + if (readTimeout == -1) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } else { + // Do a simple read with a short timeout + if ( !readSocket(true) ) return false; + } + } + + // + // Reading the method name + // Method name is always US-ASCII + // + + boolean space = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + request.method().setBytes(buf, start, pos - start); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int end = 0; + int questionPos = -1; + + // + // Reading the URI + // + + space = false; + boolean eol = false; + + while (!space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.SP) { + space = true; + end = pos; + } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; + } else if ((buf[pos] == Constants.QUESTION) + && (questionPos == -1)) { + questionPos = pos; + } + + pos++; + + } + + request.unparsedURI().setBytes(buf, start, end - start); + if (questionPos >= 0) { + request.queryString().setBytes(buf, questionPos + 1, + end - questionPos - 1); + request.requestURI().setBytes(buf, start, questionPos - start); + } else { + request.requestURI().setBytes(buf, start, end - start); + } + + // Mark the current buffer position + start = pos; + end = 0; + + // + // Reading the protocol + // Protocol is always US-ASCII + // + + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + end = pos; + } else if (buf[pos] == Constants.LF) { + if (end == 0) + end = pos; + eol = true; + } + + pos++; + + } + + if ((end - start) > 0) { + request.protocol().setBytes(buf, start, end - start); + } else { + request.protocol().setString(""); + } + + return true; + + } + + private void expand(int newsize) { + if ( newsize > buf.length ) { + byte[] tmp = new byte[newsize]; + System.arraycopy(buf,0,tmp,0,buf.length); + buf = tmp; + tmp = null; + } + } + /** + * Perform blocking read with a timeout if desired + * @param timeout boolean - set to true if the system will time out + * @return boolean - true if data was read, false is EOF is reached + * @throws IOException + */ + private boolean readSocket(boolean timeout) throws IOException { + int nRead = 0; + long start = System.currentTimeMillis(); + boolean timedOut = false; + do { + bbuf.clear(); + nRead = socket.read(bbuf); + if (nRead > 0) { + bbuf.flip(); + bbuf.limit(nRead); + expand(nRead + pos); + bbuf.get(buf, pos, nRead); + lastValid = pos + nRead; + return true; + } else if (nRead == -1) { + //return false; + throw new IOException("end of stream reached."); + } + timedOut = (readTimeout != -1) && ((System.currentTimeMillis()-start)>this.readTimeout); + if ( !timedOut && nRead == 0 ) + try { + final SelectionKey key = socket.keyFor(poller.getSelector()); + final KeyAttachment att = (KeyAttachment)key.attachment(); + //to do, add in a check, we might have just timed out on the wait, + //so there is no need to register us again. + boolean addToQueue = false; + try { addToQueue = ((key.interestOps()&SelectionKey.OP_READ) != SelectionKey.OP_READ); } catch ( CancelledKeyException ignore ){} + if ( addToQueue ) { + addToReadQueue(key, att); + }//end if + synchronized (att.getMutex()) { + if ( att.getWakeUp() ) att.getMutex().wait(25); + } + }catch ( Exception x ) {} + }while ( nRead == 0 && (!timedOut) ); + //else throw new IOException(sm.getString("iib.failedread")); + //return false; //timeout + throw new IOException("read timed out."); + } + + private void addToReadQueue(final SelectionKey key, final KeyAttachment att) { + att.setWakeUp(true); + poller.addEvent( + new Runnable() { + public void run() { + try { + if (key != null) key.interestOps(SelectionKey.OP_READ); + } catch (CancelledKeyException ckx) { + try { + if ( key != null && key.attachment() != null ) { + KeyAttachment ka = (KeyAttachment)key.attachment(); + ka.setError(true); //set to collect this socket immediately + } + socket.socket().close(); + socket.close(); + att.setWakeUp(false); + } catch (Exception ignore) {} + } + } + }); + } + + + /** + * Parse the HTTP headers. + */ + public void parseHeaders() + throws IOException { + + while (parseHeader()) { + } + + parsingHeader = false; + end = pos; + + } + + + /** + * Parse an HTTP header. + * + * @return false after reading a blank line (which indicates that the + * HTTP header parsing is done + */ + public boolean parseHeader() + throws IOException { + + // + // Check for blank line + // + + byte chr = 0; + while (true) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + + if ((chr == Constants.CR) || (chr == Constants.LF)) { + if (chr == Constants.LF) { + pos++; + return false; + } + } else { + break; + } + + pos++; + + } + + // Mark the current buffer position + int start = pos; + + // + // Reading the header name + // Header name is always US-ASCII + // + + boolean colon = false; + MessageBytes headerValue = null; + + while (!colon) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); + } + chr = buf[pos]; + if ((chr >= Constants.A) && (chr <= Constants.Z)) { + buf[pos] = (byte) (chr - Constants.LC_OFFSET); + } + + pos++; + + } + + // Mark the current buffer position + start = pos; + int realPos = pos; + + // + // Reading the header value (which can be spanned over multiple lines) + // + + boolean eol = false; + boolean validLine = true; + + while (validLine) { + + boolean space = true; + + // Skipping spaces + while (space) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if ((buf[pos] == Constants.SP) || (buf[pos] == Constants.HT)) { + pos++; + } else { + space = false; + } + + } + + int lastSignificantChar = realPos; + + // Reading bytes until the end of the line + while (!eol) { + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else if (buf[pos] == Constants.SP) { + buf[realPos] = buf[pos]; + realPos++; + } else { + buf[realPos] = buf[pos]; + realPos++; + lastSignificantChar = realPos; + } + + pos++; + + } + + realPos = lastSignificantChar; + + // Checking the first character of the new line. If the character + // is a LWS, then it's a multiline header + + // Read new bytes if needed + if (pos >= lastValid) { + if (!fill()) + throw new EOFException(sm.getString("iib.eof.error")); + } + + chr = buf[pos]; + if ((chr != Constants.SP) && (chr != Constants.HT)) { + validLine = false; + } else { + eol = false; + // Copying one extra space in the buffer (since there must + // be at least one space inserted between the lines) + buf[realPos] = chr; + realPos++; + } + + } + + // Set the header value + headerValue.setBytes(buf, start, realPos - start); + + return true; + + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read some bytes. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (lastActiveFilter == -1) + return inputStreamInputBuffer.doRead(chunk, req); + else + return activeFilters[lastActiveFilter].doRead(chunk,req); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Fill the internal buffer using data from the undelying input stream. + * + * @return false if at end of stream + */ + protected boolean fill() + throws IOException { + + boolean read = false; + + if (parsingHeader) { + + if (lastValid == buf.length) { + throw new IOException + (sm.getString("iib.requestheadertoolarge.error")); + } + + // Do a simple read with a short timeout + read = readSocket(true); + } else { + + if (buf.length - end < 4500) { + // In this case, the request header was really large, so we allocate a + // brand new one; the old one will get GCed when subsequent requests + // clear all references + buf = new byte[buf.length]; + end = 0; + } + pos = end; + lastValid = pos; + // Do a simple read with a short timeout + read = readSocket(true); + } + return read; + } + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class SocketInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (pos >= lastValid) { + if (!fill()) + return -1; + } + + int length = lastValid - pos; + chunk.setBytes(buf, pos, length); + pos = lastValid; + + return (length); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java index 7947e42ed..2b76a4c95 100644 --- a/java/org/apache/coyote/http11/InternalNioOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalNioOutputBuffer.java @@ -1,771 +1,771 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.SocketChannel; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; -import java.nio.channels.SelectionKey; -import org.apache.tomcat.util.net.NioEndpoint; -import java.nio.channels.Selector; - -/** - * Output buffer. - * - * @author Remy Maucherat - * @author Filip Hanik - */ -public class InternalNioOutputBuffer - implements OutputBuffer { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - int bbufLimit = 0; - - Selector selector; - - /** - * Default constructor. - */ - public InternalNioOutputBuffer(Response response) { - this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); - } - - - /** - * Alternate constructor. - */ - public InternalNioOutputBuffer(Response response, int headerBufferSize) { - - this.response = response; - headers = response.getMimeHeaders(); - - buf = new byte[headerBufferSize]; - - if (headerBufferSize < (8 * 1024)) { - bbufLimit = 6 * 1500; - } else { - bbufLimit = (headerBufferSize / 1500 + 1) * 1500; - } - bbuf = ByteBuffer.allocateDirect(bbufLimit); - - outputStreamOutputBuffer = new SocketOutputBuffer(); - - filterLibrary = new OutputFilter[0]; - activeFilters = new OutputFilter[0]; - lastActiveFilter = -1; - - committed = false; - finished = false; - - // Cause loading of HttpMessages - HttpMessages.getMessage(200); - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote response. - */ - protected Response response; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * Committed flag. - */ - protected boolean committed; - - - /** - * Finished flag. - */ - protected boolean finished; - - - /** - * Pointer to the current write buffer. - */ - protected byte[] buf; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * Underlying socket. - */ - protected SocketChannel socket; - - - /** - * Underlying output buffer. - */ - protected OutputBuffer outputStreamOutputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected OutputFilter[] filterLibrary; - - - /** - * Active filter (which is actually the top of the pipeline). - */ - protected OutputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - /** - * Direct byte buffer used for writing. - */ - protected ByteBuffer bbuf = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket. - */ - public void setSocket(SocketChannel socket) { - this.socket = socket; - } - - public void setSelector(Selector selector) { - this.selector = selector; - } - - /** - * Get the underlying socket input stream. - */ - public SocketChannel getSocket() { - return socket; - } - /** - * Set the socket buffer size. - */ - public void setSocketBuffer(int socketBufferSize) { - // FIXME: Remove - } - - - /** - * Add an output filter to the filter library. - */ - public void addFilter(OutputFilter filter) { - - OutputFilter[] newFilterLibrary = - new OutputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new OutputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public OutputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new OutputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an output filter to the filter library. - */ - public void addActiveFilter(OutputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(outputStreamOutputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setResponse(response); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Flush the response. - * - * @throws IOException an undelying I/O error occured - */ - public void flush() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - // Flush the current buffer - flushBuffer(); - - } - - - /** - * Reset current response. - * - * @throws IllegalStateException if the response has already been committed - */ - public void reset() { - - if (committed) - throw new IllegalStateException(/*FIXME:Put an error message*/); - - // Recycle Request object - response.recycle(); - - } - - - /** - * Recycle the output buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - response.recycle(); - bbuf.clear(); - - socket = null; - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() { - - // Recycle Request object - response.recycle(); - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End request. - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (finished) - return; - - if (lastActiveFilter != -1) - activeFilters[lastActiveFilter].end(); - - flushBuffer(); - - finished = true; - - } - - - // ------------------------------------------------ HTTP/1.1 Output Methods - - - /** - * Send an acknoledgement. - */ - public void sendAck() - throws IOException { - - if (!committed) { - //Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0 - ByteBuffer buf = ByteBuffer.wrap(Constants.ACK_BYTES,0,Constants.ACK_BYTES.length); - writeToSocket(buf,false); - } - - } - - private synchronized void writeToSocket(ByteBuffer bytebuffer, boolean flip) throws IOException { - int limit = bytebuffer.position(); - if ( flip ) bytebuffer.flip(); - while ( bytebuffer.hasRemaining() ) { - int written = socket.write(bytebuffer); - } - bbuf.clear(); - this.total = 0; - } - - - /** - * Send the response status line. - */ - public void sendStatus() { - - // Write protocol name - write(Constants.HTTP_11_BYTES); - buf[pos++] = Constants.SP; - - // Write status code - int status = response.getStatus(); - switch (status) { - case 200: - write(Constants._200_BYTES); - break; - case 400: - write(Constants._400_BYTES); - break; - case 404: - write(Constants._404_BYTES); - break; - default: - write(status); - } - - buf[pos++] = Constants.SP; - - // Write message - String message = response.getMessage(); - if (message == null) { - write(HttpMessages.getMessage(status)); - } else { - write(message); - } - - // End the response status line - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(MessageBytes name, MessageBytes value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(ByteChunk name, ByteChunk value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(String name, String value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * End the header block. - */ - public void endHeaders() { - - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write the contents of a byte chunk. - * - * @param chunk byte chunk - * @return number of bytes written - * @throws IOException an undelying I/O error occured - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeaders) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (lastActiveFilter == -1) - return outputStreamOutputBuffer.doWrite(chunk, res); - else - return activeFilters[lastActiveFilter].doWrite(chunk, res); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Commit the response. - * - * @throws IOException an undelying I/O error occured - */ - protected void commit() - throws IOException { - - // The response is now committed - committed = true; - response.setCommitted(true); - - if (pos > 0) { - // Sending the response header buffer - addToBB(buf, 0, pos); - } - - } - - int total = 0; - private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException { - if (bbuf.capacity() <= (offset + length)) { - flushBuffer(); - } - bbuf.put(buf, offset, length); - total += length; - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param mb data to be written - */ - protected void write(MessageBytes mb) { - - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - write(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - CharChunk cc = mb.getCharChunk(); - write(cc); - } else { - write(mb.toString()); - } - - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param bc data to be written - */ - protected void write(ByteChunk bc) { - - // Writing the byte chunk to the output buffer - System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, - bc.getLength()); - pos = pos + bc.getLength(); - - } - - - /** - * This method will write the contents of the specyfied char - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param cc data to be written - */ - protected void write(CharChunk cc) { - - int start = cc.getStart(); - int end = cc.getEnd(); - char[] cbuf = cc.getBuffer(); - for (int i = start; i < end; i++) { - char c = cbuf[i]; - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will write the contents of the specyfied byte - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param b data to be written - */ - public void write(byte[] b) { - - // Writing the byte chunk to the output buffer - System.arraycopy(b, 0, buf, pos, b.length); - pos = pos + b.length; - - } - - - /** - * This method will write the contents of the specyfied String to the - * output stream, without filtering. This method is meant to be used to - * write the response header. - * - * @param s data to be written - */ - protected void write(String s) { - - if (s == null) - return; - - // From the Tomcat 3.3 HTTP/1.0 connector - int len = s.length(); - for (int i = 0; i < len; i++) { - char c = s.charAt (i); - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will print the specified integer to the output stream, - * without filtering. This method is meant to be used to write the - * response header. - * - * @param i data to be written - */ - protected void write(int i) { - - write(String.valueOf(i)); - - } - - - /** - * Callback to write data from the buffer. - */ - protected void flushBuffer() - throws IOException { - - //prevent timeout for async, - SelectionKey key = socket.keyFor(selector); - if (key != null) { - NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); - attach.access(); - } - - //write to the socket, if there is anything to write - if (bbuf.position() > 0) { - writeToSocket(bbuf,true); - } - } - - - // ----------------------------------- OutputStreamOutputBuffer Inner Class - - - /** - * This class is an output buffer which will write data to an output - * stream. - */ - protected class SocketOutputBuffer - implements OutputBuffer { - - - /** - * Write chunk. - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - int len = chunk.getLength(); - int start = chunk.getStart(); - byte[] b = chunk.getBuffer(); - while (len > 0) { - int thisTime = len; - if (bbuf.position() == bbuf.capacity()) { - flushBuffer(); - } - if (thisTime > bbuf.capacity() - bbuf.position()) { - thisTime = bbuf.capacity() - bbuf.position(); - } - addToBB(b,start,thisTime); - len = len - thisTime; - start = start + thisTime; - } - return chunk.getLength(); - - } - - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SocketChannel; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; +import java.nio.channels.SelectionKey; +import org.apache.tomcat.util.net.NioEndpoint; +import java.nio.channels.Selector; + +/** + * Output buffer. + * + * @author Remy Maucherat + * @author Filip Hanik + */ +public class InternalNioOutputBuffer + implements OutputBuffer { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + int bbufLimit = 0; + + Selector selector; + + /** + * Default constructor. + */ + public InternalNioOutputBuffer(Response response) { + this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); + } + + + /** + * Alternate constructor. + */ + public InternalNioOutputBuffer(Response response, int headerBufferSize) { + + this.response = response; + headers = response.getMimeHeaders(); + + buf = new byte[headerBufferSize]; + + if (headerBufferSize < (8 * 1024)) { + bbufLimit = 6 * 1500; + } else { + bbufLimit = (headerBufferSize / 1500 + 1) * 1500; + } + bbuf = ByteBuffer.allocateDirect(bbufLimit); + + outputStreamOutputBuffer = new SocketOutputBuffer(); + + filterLibrary = new OutputFilter[0]; + activeFilters = new OutputFilter[0]; + lastActiveFilter = -1; + + committed = false; + finished = false; + + // Cause loading of HttpMessages + HttpMessages.getMessage(200); + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote response. + */ + protected Response response; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * Committed flag. + */ + protected boolean committed; + + + /** + * Finished flag. + */ + protected boolean finished; + + + /** + * Pointer to the current write buffer. + */ + protected byte[] buf; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * Underlying socket. + */ + protected SocketChannel socket; + + + /** + * Underlying output buffer. + */ + protected OutputBuffer outputStreamOutputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected OutputFilter[] filterLibrary; + + + /** + * Active filter (which is actually the top of the pipeline). + */ + protected OutputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + /** + * Direct byte buffer used for writing. + */ + protected ByteBuffer bbuf = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket. + */ + public void setSocket(SocketChannel socket) { + this.socket = socket; + } + + public void setSelector(Selector selector) { + this.selector = selector; + } + + /** + * Get the underlying socket input stream. + */ + public SocketChannel getSocket() { + return socket; + } + /** + * Set the socket buffer size. + */ + public void setSocketBuffer(int socketBufferSize) { + // FIXME: Remove + } + + + /** + * Add an output filter to the filter library. + */ + public void addFilter(OutputFilter filter) { + + OutputFilter[] newFilterLibrary = + new OutputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new OutputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public OutputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new OutputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an output filter to the filter library. + */ + public void addActiveFilter(OutputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(outputStreamOutputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setResponse(response); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Flush the response. + * + * @throws IOException an undelying I/O error occured + */ + public void flush() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + // Flush the current buffer + flushBuffer(); + + } + + + /** + * Reset current response. + * + * @throws IllegalStateException if the response has already been committed + */ + public void reset() { + + if (committed) + throw new IllegalStateException(/*FIXME:Put an error message*/); + + // Recycle Request object + response.recycle(); + + } + + + /** + * Recycle the output buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + response.recycle(); + bbuf.clear(); + + socket = null; + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() { + + // Recycle Request object + response.recycle(); + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End request. + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (finished) + return; + + if (lastActiveFilter != -1) + activeFilters[lastActiveFilter].end(); + + flushBuffer(); + + finished = true; + + } + + + // ------------------------------------------------ HTTP/1.1 Output Methods + + + /** + * Send an acknoledgement. + */ + public void sendAck() + throws IOException { + + if (!committed) { + //Socket.send(socket, Constants.ACK_BYTES, 0, Constants.ACK_BYTES.length) < 0 + ByteBuffer buf = ByteBuffer.wrap(Constants.ACK_BYTES,0,Constants.ACK_BYTES.length); + writeToSocket(buf,false); + } + + } + + private synchronized void writeToSocket(ByteBuffer bytebuffer, boolean flip) throws IOException { + int limit = bytebuffer.position(); + if ( flip ) bytebuffer.flip(); + while ( bytebuffer.hasRemaining() ) { + int written = socket.write(bytebuffer); + } + bbuf.clear(); + this.total = 0; + } + + + /** + * Send the response status line. + */ + public void sendStatus() { + + // Write protocol name + write(Constants.HTTP_11_BYTES); + buf[pos++] = Constants.SP; + + // Write status code + int status = response.getStatus(); + switch (status) { + case 200: + write(Constants._200_BYTES); + break; + case 400: + write(Constants._400_BYTES); + break; + case 404: + write(Constants._404_BYTES); + break; + default: + write(status); + } + + buf[pos++] = Constants.SP; + + // Write message + String message = response.getMessage(); + if (message == null) { + write(HttpMessages.getMessage(status)); + } else { + write(message); + } + + // End the response status line + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(MessageBytes name, MessageBytes value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(ByteChunk name, ByteChunk value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(String name, String value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * End the header block. + */ + public void endHeaders() { + + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write the contents of a byte chunk. + * + * @param chunk byte chunk + * @return number of bytes written + * @throws IOException an undelying I/O error occured + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeaders) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (lastActiveFilter == -1) + return outputStreamOutputBuffer.doWrite(chunk, res); + else + return activeFilters[lastActiveFilter].doWrite(chunk, res); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Commit the response. + * + * @throws IOException an undelying I/O error occured + */ + protected void commit() + throws IOException { + + // The response is now committed + committed = true; + response.setCommitted(true); + + if (pos > 0) { + // Sending the response header buffer + addToBB(buf, 0, pos); + } + + } + + int total = 0; + private synchronized void addToBB(byte[] buf, int offset, int length) throws IOException { + if (bbuf.capacity() <= (offset + length)) { + flushBuffer(); + } + bbuf.put(buf, offset, length); + total += length; + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param mb data to be written + */ + protected void write(MessageBytes mb) { + + if (mb.getType() == MessageBytes.T_BYTES) { + ByteChunk bc = mb.getByteChunk(); + write(bc); + } else if (mb.getType() == MessageBytes.T_CHARS) { + CharChunk cc = mb.getCharChunk(); + write(cc); + } else { + write(mb.toString()); + } + + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param bc data to be written + */ + protected void write(ByteChunk bc) { + + // Writing the byte chunk to the output buffer + System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, + bc.getLength()); + pos = pos + bc.getLength(); + + } + + + /** + * This method will write the contents of the specyfied char + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param cc data to be written + */ + protected void write(CharChunk cc) { + + int start = cc.getStart(); + int end = cc.getEnd(); + char[] cbuf = cc.getBuffer(); + for (int i = start; i < end; i++) { + char c = cbuf[i]; + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will write the contents of the specyfied byte + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param b data to be written + */ + public void write(byte[] b) { + + // Writing the byte chunk to the output buffer + System.arraycopy(b, 0, buf, pos, b.length); + pos = pos + b.length; + + } + + + /** + * This method will write the contents of the specyfied String to the + * output stream, without filtering. This method is meant to be used to + * write the response header. + * + * @param s data to be written + */ + protected void write(String s) { + + if (s == null) + return; + + // From the Tomcat 3.3 HTTP/1.0 connector + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt (i); + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will print the specified integer to the output stream, + * without filtering. This method is meant to be used to write the + * response header. + * + * @param i data to be written + */ + protected void write(int i) { + + write(String.valueOf(i)); + + } + + + /** + * Callback to write data from the buffer. + */ + protected void flushBuffer() + throws IOException { + + //prevent timeout for async, + SelectionKey key = socket.keyFor(selector); + if (key != null) { + NioEndpoint.KeyAttachment attach = (NioEndpoint.KeyAttachment) key.attachment(); + attach.access(); + } + + //write to the socket, if there is anything to write + if (bbuf.position() > 0) { + writeToSocket(bbuf,true); + } + } + + + // ----------------------------------- OutputStreamOutputBuffer Inner Class + + + /** + * This class is an output buffer which will write data to an output + * stream. + */ + protected class SocketOutputBuffer + implements OutputBuffer { + + + /** + * Write chunk. + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + int len = chunk.getLength(); + int start = chunk.getStart(); + byte[] b = chunk.getBuffer(); + while (len > 0) { + int thisTime = len; + if (bbuf.position() == bbuf.capacity()) { + flushBuffer(); + } + if (thisTime > bbuf.capacity() - bbuf.position()) { + thisTime = bbuf.capacity() - bbuf.position(); + } + addToBB(b,start,thisTime); + len = len - thisTime; + start = start + thisTime; + } + return chunk.getLength(); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/InternalOutputBuffer.java b/java/org/apache/coyote/http11/InternalOutputBuffer.java index e589b3206..0c5073934 100644 --- a/java/org/apache/coyote/http11/InternalOutputBuffer.java +++ b/java/org/apache/coyote/http11/InternalOutputBuffer.java @@ -1,783 +1,783 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; -import java.io.OutputStream; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.res.StringManager; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; - -/** - * Output buffer. - * - * @author Remy Maucherat - */ -public class InternalOutputBuffer - implements OutputBuffer, ByteChunk.ByteOutputChannel { - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. - */ - public InternalOutputBuffer(Response response) { - this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); - } - - - /** - * Alternate constructor. - */ - public InternalOutputBuffer(Response response, int headerBufferSize) { - - this.response = response; - headers = response.getMimeHeaders(); - - headerBuffer = new byte[headerBufferSize]; - buf = headerBuffer; - - outputStreamOutputBuffer = new OutputStreamOutputBuffer(); - - filterLibrary = new OutputFilter[0]; - activeFilters = new OutputFilter[0]; - lastActiveFilter = -1; - - socketBuffer = new ByteChunk(); - socketBuffer.setByteOutputChannel(this); - - committed = false; - finished = false; - - } - - - // -------------------------------------------------------------- Variables - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Associated Coyote response. - */ - protected Response response; - - - /** - * Headers of the associated request. - */ - protected MimeHeaders headers; - - - /** - * Committed flag. - */ - protected boolean committed; - - - /** - * Finished flag. - */ - protected boolean finished; - - - /** - * Pointer to the current read buffer. - */ - protected byte[] buf; - - - /** - * Position in the buffer. - */ - protected int pos; - - - /** - * HTTP header buffer. - */ - protected byte[] headerBuffer; - - - /** - * Underlying output stream. - */ - protected OutputStream outputStream; - - - /** - * Underlying output buffer. - */ - protected OutputBuffer outputStreamOutputBuffer; - - - /** - * Filter library. - * Note: Filter[0] is always the "chunked" filter. - */ - protected OutputFilter[] filterLibrary; - - - /** - * Active filter (which is actually the top of the pipeline). - */ - protected OutputFilter[] activeFilters; - - - /** - * Index of the last active filter. - */ - protected int lastActiveFilter; - - - /** - * Socket buffer. - */ - protected ByteChunk socketBuffer; - - - /** - * Socket buffer (extra buffering to reduce number of packets sent). - */ - protected boolean useSocketBuffer = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the underlying socket output stream. - */ - public void setOutputStream(OutputStream outputStream) { - - // FIXME: Check for null ? - - this.outputStream = outputStream; - - } - - - /** - * Get the underlying socket output stream. - */ - public OutputStream getOutputStream() { - - return outputStream; - - } - - - /** - * Set the socket buffer size. - */ - public void setSocketBuffer(int socketBufferSize) { - - if (socketBufferSize > 500) { - useSocketBuffer = true; - socketBuffer.allocate(socketBufferSize, socketBufferSize); - } else { - useSocketBuffer = false; - } - - } - - - /** - * Add an output filter to the filter library. - */ - public void addFilter(OutputFilter filter) { - - OutputFilter[] newFilterLibrary = - new OutputFilter[filterLibrary.length + 1]; - for (int i = 0; i < filterLibrary.length; i++) { - newFilterLibrary[i] = filterLibrary[i]; - } - newFilterLibrary[filterLibrary.length] = filter; - filterLibrary = newFilterLibrary; - - activeFilters = new OutputFilter[filterLibrary.length]; - - } - - - /** - * Get filters. - */ - public OutputFilter[] getFilters() { - - return filterLibrary; - - } - - - /** - * Clear filters. - */ - public void clearFilters() { - - filterLibrary = new OutputFilter[0]; - lastActiveFilter = -1; - - } - - - /** - * Add an output filter to the filter library. - */ - public void addActiveFilter(OutputFilter filter) { - - if (lastActiveFilter == -1) { - filter.setBuffer(outputStreamOutputBuffer); - } else { - for (int i = 0; i <= lastActiveFilter; i++) { - if (activeFilters[i] == filter) - return; - } - filter.setBuffer(activeFilters[lastActiveFilter]); - } - - activeFilters[++lastActiveFilter] = filter; - - filter.setResponse(response); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Flush the response. - * - * @throws IOException an undelying I/O error occured - */ - public void flush() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - // Flush the current buffer - if (useSocketBuffer) { - socketBuffer.flushBuffer(); - } - - } - - - /** - * Reset current response. - * - * @throws IllegalStateException if the response has already been committed - */ - public void reset() { - - if (committed) - throw new IllegalStateException(/*FIXME:Put an error message*/); - - // Recycle Request object - response.recycle(); - - } - - - /** - * Recycle the output buffer. This should be called when closing the - * connection. - */ - public void recycle() { - - // Recycle Request object - response.recycle(); - socketBuffer.recycle(); - - outputStream = null; - buf = headerBuffer; - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End processing of current HTTP request. - * Note: All bytes of the current request should have been already - * consumed. This method only resets all the pointers so that we are ready - * to parse the next HTTP request. - */ - public void nextRequest() { - - // Recycle Request object - response.recycle(); - socketBuffer.recycle(); - - // Determine the header buffer used for next request - buf = headerBuffer; - - // Recycle filters - for (int i = 0; i <= lastActiveFilter; i++) { - activeFilters[i].recycle(); - } - - // Reset pointers - pos = 0; - lastActiveFilter = -1; - committed = false; - finished = false; - - } - - - /** - * End request. - * - * @throws IOException an undelying I/O error occured - */ - public void endRequest() - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (finished) - return; - - if (lastActiveFilter != -1) - activeFilters[lastActiveFilter].end(); - - if (useSocketBuffer) { - socketBuffer.flushBuffer(); - } - - finished = true; - - } - - - // ------------------------------------------------ HTTP/1.1 Output Methods - - - /** - * Send an acknoledgement. - */ - public void sendAck() - throws IOException { - - if (!committed) - outputStream.write(Constants.ACK_BYTES); - - } - - - /** - * Send the response status line. - */ - public void sendStatus() { - - // Write protocol name - write(Constants.HTTP_11_BYTES); - buf[pos++] = Constants.SP; - - // Write status code - int status = response.getStatus(); - switch (status) { - case 200: - write(Constants._200_BYTES); - break; - case 400: - write(Constants._400_BYTES); - break; - case 404: - write(Constants._404_BYTES); - break; - default: - write(status); - } - - buf[pos++] = Constants.SP; - - // Write message - String message = response.getMessage(); - if (message == null) { - write(getMessage(status)); - } else { - write(message); - } - - // End the response status line - if (System.getSecurityManager() != null){ - AccessController.doPrivileged( - new PrivilegedAction(){ - public Object run(){ - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - return null; - } - } - ); - } else { - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - } - - } - - private String getMessage(final int message){ - if (System.getSecurityManager() != null){ - return (String)AccessController.doPrivileged( - new PrivilegedAction(){ - public Object run(){ - return HttpMessages.getMessage(message); - } - } - ); - } else { - return HttpMessages.getMessage(message); - } - } - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(MessageBytes name, MessageBytes value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(ByteChunk name, ByteChunk value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * Send a header. - * - * @param name Header name - * @param value Header value - */ - public void sendHeader(String name, String value) { - - write(name); - buf[pos++] = Constants.COLON; - buf[pos++] = Constants.SP; - write(value); - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - /** - * End the header block. - */ - public void endHeaders() { - - buf[pos++] = Constants.CR; - buf[pos++] = Constants.LF; - - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write the contents of a byte chunk. - * - * @param chunk byte chunk - * @return number of bytes written - * @throws IOException an undelying I/O error occured - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (!committed) { - - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeaders) and - // set the filters accordingly. - response.action(ActionCode.ACTION_COMMIT, null); - - } - - if (lastActiveFilter == -1) - return outputStreamOutputBuffer.doWrite(chunk, res); - else - return activeFilters[lastActiveFilter].doWrite(chunk, res); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Commit the response. - * - * @throws IOException an undelying I/O error occured - */ - protected void commit() - throws IOException { - - // The response is now committed - committed = true; - response.setCommitted(true); - - if (pos > 0) { - // Sending the response header buffer - if (useSocketBuffer) { - socketBuffer.append(buf, 0, pos); - } else { - outputStream.write(buf, 0, pos); - } - } - - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param mb data to be written - */ - protected void write(MessageBytes mb) { - - if (mb.getType() == MessageBytes.T_BYTES) { - ByteChunk bc = mb.getByteChunk(); - write(bc); - } else if (mb.getType() == MessageBytes.T_CHARS) { - CharChunk cc = mb.getCharChunk(); - write(cc); - } else { - write(mb.toString()); - } - - } - - - /** - * This method will write the contents of the specyfied message bytes - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param bc data to be written - */ - protected void write(ByteChunk bc) { - - // Writing the byte chunk to the output buffer - System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, - bc.getLength()); - pos = pos + bc.getLength(); - - } - - - /** - * This method will write the contents of the specyfied char - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param cc data to be written - */ - protected void write(CharChunk cc) { - - int start = cc.getStart(); - int end = cc.getEnd(); - char[] cbuf = cc.getBuffer(); - for (int i = start; i < end; i++) { - char c = cbuf[i]; - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will write the contents of the specyfied byte - * buffer to the output stream, without filtering. This method is meant to - * be used to write the response header. - * - * @param b data to be written - */ - public void write(byte[] b) { - - // Writing the byte chunk to the output buffer - System.arraycopy(b, 0, buf, pos, b.length); - pos = pos + b.length; - - } - - - /** - * This method will write the contents of the specyfied String to the - * output stream, without filtering. This method is meant to be used to - * write the response header. - * - * @param s data to be written - */ - protected void write(String s) { - - if (s == null) - return; - - // From the Tomcat 3.3 HTTP/1.0 connector - int len = s.length(); - for (int i = 0; i < len; i++) { - char c = s.charAt (i); - // Note: This is clearly incorrect for many strings, - // but is the only consistent approach within the current - // servlet framework. It must suffice until servlet output - // streams properly encode their output. - if ((c <= 31) && (c != 9)) { - c = ' '; - } else if (c == 127) { - c = ' '; - } - buf[pos++] = (byte) c; - } - - } - - - /** - * This method will print the specified integer to the output stream, - * without filtering. This method is meant to be used to write the - * response header. - * - * @param i data to be written - */ - protected void write(int i) { - - write(String.valueOf(i)); - - } - - - /** - * Callback to write data from the buffer. - */ - public void realWriteBytes(byte cbuf[], int off, int len) - throws IOException { - if (len > 0) { - outputStream.write(cbuf, off, len); - } - } - - - // ----------------------------------- OutputStreamOutputBuffer Inner Class - - - /** - * This class is an output buffer which will write data to an output - * stream. - */ - protected class OutputStreamOutputBuffer - implements OutputBuffer { - - - /** - * Write chunk. - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - if (useSocketBuffer) { - socketBuffer.append(chunk.getBuffer(), chunk.getStart(), - chunk.getLength()); - } else { - outputStream.write(chunk.getBuffer(), chunk.getStart(), - chunk.getLength()); - } - return chunk.getLength(); - - } - - - } - - -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.res.StringManager; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; + +/** + * Output buffer. + * + * @author Remy Maucherat + */ +public class InternalOutputBuffer + implements OutputBuffer, ByteChunk.ByteOutputChannel { + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. + */ + public InternalOutputBuffer(Response response) { + this(response, Constants.DEFAULT_HTTP_HEADER_BUFFER_SIZE); + } + + + /** + * Alternate constructor. + */ + public InternalOutputBuffer(Response response, int headerBufferSize) { + + this.response = response; + headers = response.getMimeHeaders(); + + headerBuffer = new byte[headerBufferSize]; + buf = headerBuffer; + + outputStreamOutputBuffer = new OutputStreamOutputBuffer(); + + filterLibrary = new OutputFilter[0]; + activeFilters = new OutputFilter[0]; + lastActiveFilter = -1; + + socketBuffer = new ByteChunk(); + socketBuffer.setByteOutputChannel(this); + + committed = false; + finished = false; + + } + + + // -------------------------------------------------------------- Variables + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Associated Coyote response. + */ + protected Response response; + + + /** + * Headers of the associated request. + */ + protected MimeHeaders headers; + + + /** + * Committed flag. + */ + protected boolean committed; + + + /** + * Finished flag. + */ + protected boolean finished; + + + /** + * Pointer to the current read buffer. + */ + protected byte[] buf; + + + /** + * Position in the buffer. + */ + protected int pos; + + + /** + * HTTP header buffer. + */ + protected byte[] headerBuffer; + + + /** + * Underlying output stream. + */ + protected OutputStream outputStream; + + + /** + * Underlying output buffer. + */ + protected OutputBuffer outputStreamOutputBuffer; + + + /** + * Filter library. + * Note: Filter[0] is always the "chunked" filter. + */ + protected OutputFilter[] filterLibrary; + + + /** + * Active filter (which is actually the top of the pipeline). + */ + protected OutputFilter[] activeFilters; + + + /** + * Index of the last active filter. + */ + protected int lastActiveFilter; + + + /** + * Socket buffer. + */ + protected ByteChunk socketBuffer; + + + /** + * Socket buffer (extra buffering to reduce number of packets sent). + */ + protected boolean useSocketBuffer = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the underlying socket output stream. + */ + public void setOutputStream(OutputStream outputStream) { + + // FIXME: Check for null ? + + this.outputStream = outputStream; + + } + + + /** + * Get the underlying socket output stream. + */ + public OutputStream getOutputStream() { + + return outputStream; + + } + + + /** + * Set the socket buffer size. + */ + public void setSocketBuffer(int socketBufferSize) { + + if (socketBufferSize > 500) { + useSocketBuffer = true; + socketBuffer.allocate(socketBufferSize, socketBufferSize); + } else { + useSocketBuffer = false; + } + + } + + + /** + * Add an output filter to the filter library. + */ + public void addFilter(OutputFilter filter) { + + OutputFilter[] newFilterLibrary = + new OutputFilter[filterLibrary.length + 1]; + for (int i = 0; i < filterLibrary.length; i++) { + newFilterLibrary[i] = filterLibrary[i]; + } + newFilterLibrary[filterLibrary.length] = filter; + filterLibrary = newFilterLibrary; + + activeFilters = new OutputFilter[filterLibrary.length]; + + } + + + /** + * Get filters. + */ + public OutputFilter[] getFilters() { + + return filterLibrary; + + } + + + /** + * Clear filters. + */ + public void clearFilters() { + + filterLibrary = new OutputFilter[0]; + lastActiveFilter = -1; + + } + + + /** + * Add an output filter to the filter library. + */ + public void addActiveFilter(OutputFilter filter) { + + if (lastActiveFilter == -1) { + filter.setBuffer(outputStreamOutputBuffer); + } else { + for (int i = 0; i <= lastActiveFilter; i++) { + if (activeFilters[i] == filter) + return; + } + filter.setBuffer(activeFilters[lastActiveFilter]); + } + + activeFilters[++lastActiveFilter] = filter; + + filter.setResponse(response); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Flush the response. + * + * @throws IOException an undelying I/O error occured + */ + public void flush() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + // Flush the current buffer + if (useSocketBuffer) { + socketBuffer.flushBuffer(); + } + + } + + + /** + * Reset current response. + * + * @throws IllegalStateException if the response has already been committed + */ + public void reset() { + + if (committed) + throw new IllegalStateException(/*FIXME:Put an error message*/); + + // Recycle Request object + response.recycle(); + + } + + + /** + * Recycle the output buffer. This should be called when closing the + * connection. + */ + public void recycle() { + + // Recycle Request object + response.recycle(); + socketBuffer.recycle(); + + outputStream = null; + buf = headerBuffer; + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End processing of current HTTP request. + * Note: All bytes of the current request should have been already + * consumed. This method only resets all the pointers so that we are ready + * to parse the next HTTP request. + */ + public void nextRequest() { + + // Recycle Request object + response.recycle(); + socketBuffer.recycle(); + + // Determine the header buffer used for next request + buf = headerBuffer; + + // Recycle filters + for (int i = 0; i <= lastActiveFilter; i++) { + activeFilters[i].recycle(); + } + + // Reset pointers + pos = 0; + lastActiveFilter = -1; + committed = false; + finished = false; + + } + + + /** + * End request. + * + * @throws IOException an undelying I/O error occured + */ + public void endRequest() + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeader) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (finished) + return; + + if (lastActiveFilter != -1) + activeFilters[lastActiveFilter].end(); + + if (useSocketBuffer) { + socketBuffer.flushBuffer(); + } + + finished = true; + + } + + + // ------------------------------------------------ HTTP/1.1 Output Methods + + + /** + * Send an acknoledgement. + */ + public void sendAck() + throws IOException { + + if (!committed) + outputStream.write(Constants.ACK_BYTES); + + } + + + /** + * Send the response status line. + */ + public void sendStatus() { + + // Write protocol name + write(Constants.HTTP_11_BYTES); + buf[pos++] = Constants.SP; + + // Write status code + int status = response.getStatus(); + switch (status) { + case 200: + write(Constants._200_BYTES); + break; + case 400: + write(Constants._400_BYTES); + break; + case 404: + write(Constants._404_BYTES); + break; + default: + write(status); + } + + buf[pos++] = Constants.SP; + + // Write message + String message = response.getMessage(); + if (message == null) { + write(getMessage(status)); + } else { + write(message); + } + + // End the response status line + if (System.getSecurityManager() != null){ + AccessController.doPrivileged( + new PrivilegedAction(){ + public Object run(){ + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + return null; + } + } + ); + } else { + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + } + + } + + private String getMessage(final int message){ + if (System.getSecurityManager() != null){ + return (String)AccessController.doPrivileged( + new PrivilegedAction(){ + public Object run(){ + return HttpMessages.getMessage(message); + } + } + ); + } else { + return HttpMessages.getMessage(message); + } + } + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(MessageBytes name, MessageBytes value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(ByteChunk name, ByteChunk value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * Send a header. + * + * @param name Header name + * @param value Header value + */ + public void sendHeader(String name, String value) { + + write(name); + buf[pos++] = Constants.COLON; + buf[pos++] = Constants.SP; + write(value); + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + /** + * End the header block. + */ + public void endHeaders() { + + buf[pos++] = Constants.CR; + buf[pos++] = Constants.LF; + + } + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write the contents of a byte chunk. + * + * @param chunk byte chunk + * @return number of bytes written + * @throws IOException an undelying I/O error occured + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (!committed) { + + // Send the connector a request for commit. The connector should + // then validate the headers, send them (using sendHeaders) and + // set the filters accordingly. + response.action(ActionCode.ACTION_COMMIT, null); + + } + + if (lastActiveFilter == -1) + return outputStreamOutputBuffer.doWrite(chunk, res); + else + return activeFilters[lastActiveFilter].doWrite(chunk, res); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Commit the response. + * + * @throws IOException an undelying I/O error occured + */ + protected void commit() + throws IOException { + + // The response is now committed + committed = true; + response.setCommitted(true); + + if (pos > 0) { + // Sending the response header buffer + if (useSocketBuffer) { + socketBuffer.append(buf, 0, pos); + } else { + outputStream.write(buf, 0, pos); + } + } + + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param mb data to be written + */ + protected void write(MessageBytes mb) { + + if (mb.getType() == MessageBytes.T_BYTES) { + ByteChunk bc = mb.getByteChunk(); + write(bc); + } else if (mb.getType() == MessageBytes.T_CHARS) { + CharChunk cc = mb.getCharChunk(); + write(cc); + } else { + write(mb.toString()); + } + + } + + + /** + * This method will write the contents of the specyfied message bytes + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param bc data to be written + */ + protected void write(ByteChunk bc) { + + // Writing the byte chunk to the output buffer + System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos, + bc.getLength()); + pos = pos + bc.getLength(); + + } + + + /** + * This method will write the contents of the specyfied char + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param cc data to be written + */ + protected void write(CharChunk cc) { + + int start = cc.getStart(); + int end = cc.getEnd(); + char[] cbuf = cc.getBuffer(); + for (int i = start; i < end; i++) { + char c = cbuf[i]; + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will write the contents of the specyfied byte + * buffer to the output stream, without filtering. This method is meant to + * be used to write the response header. + * + * @param b data to be written + */ + public void write(byte[] b) { + + // Writing the byte chunk to the output buffer + System.arraycopy(b, 0, buf, pos, b.length); + pos = pos + b.length; + + } + + + /** + * This method will write the contents of the specyfied String to the + * output stream, without filtering. This method is meant to be used to + * write the response header. + * + * @param s data to be written + */ + protected void write(String s) { + + if (s == null) + return; + + // From the Tomcat 3.3 HTTP/1.0 connector + int len = s.length(); + for (int i = 0; i < len; i++) { + char c = s.charAt (i); + // Note: This is clearly incorrect for many strings, + // but is the only consistent approach within the current + // servlet framework. It must suffice until servlet output + // streams properly encode their output. + if ((c <= 31) && (c != 9)) { + c = ' '; + } else if (c == 127) { + c = ' '; + } + buf[pos++] = (byte) c; + } + + } + + + /** + * This method will print the specified integer to the output stream, + * without filtering. This method is meant to be used to write the + * response header. + * + * @param i data to be written + */ + protected void write(int i) { + + write(String.valueOf(i)); + + } + + + /** + * Callback to write data from the buffer. + */ + public void realWriteBytes(byte cbuf[], int off, int len) + throws IOException { + if (len > 0) { + outputStream.write(cbuf, off, len); + } + } + + + // ----------------------------------- OutputStreamOutputBuffer Inner Class + + + /** + * This class is an output buffer which will write data to an output + * stream. + */ + protected class OutputStreamOutputBuffer + implements OutputBuffer { + + + /** + * Write chunk. + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + if (useSocketBuffer) { + socketBuffer.append(chunk.getBuffer(), chunk.getStart(), + chunk.getLength()); + } else { + outputStream.write(chunk.getBuffer(), chunk.getStart(), + chunk.getLength()); + } + return chunk.getLength(); + + } + + + } + + +} diff --git a/java/org/apache/coyote/http11/LocalStrings.properties b/java/org/apache/coyote/http11/LocalStrings.properties index e3ba577b0..883df52ac 100644 --- a/java/org/apache/coyote/http11/LocalStrings.properties +++ b/java/org/apache/coyote/http11/LocalStrings.properties @@ -1,51 +1,51 @@ -# $Id: LocalStrings.properties 301004 2005-07-29 10:23:56Z remm $ - -# language - -# package org.apache.coyote.http11 - -# -# Http11Protocol -# - -http11protocol.endpoint.initerror=Error initializing endpoint -http11protocol.endpoint.starterror=Error starting endpoint -http11protocol.init=Initializing Coyote HTTP/1.1 on {0} -http11protocol.proto.error=Error reading request, ignored -http11protocol.proto.ioexception.debug=IOException reading request -http11protocol.proto.ioexception.info=IOException reading request, ignored -http11protocol.proto.socketexception.debug=SocketException reading request -http11protocol.proto.socketexception.info=SocketException reading request, ignored -http11protocol.getattribute=Attribute {0} -http11protocol.setattribute=Attribute {0}: {1} -http11protocol.socketfactory.initerror=Error initializing socket factory -http11protocol.start=Starting Coyote HTTP/1.1 on {0} -http11protocol.stop=Stopping Coyote HTTP/1.1 on {0} -http11protocol.pause=Pausing Coyote HTTP/1.1 on {0} -http11protocol.endpoint.pauseerror=Error pausing endpoint -http11protocol.resume=Resuming Coyote HTTP/1.1 on {0} -http11protocol.endpoint.resumeerror=Error resuming endpoint - -# -# Http11Processor -# - -http11processor.regexp.error=Error parsing regular expression {0} -http11processor.filter.unknown=Unknown filter {0} -http11processor.filter.error=Error intializing filter {0} -http11processor.header.parse=Error parsing HTTP request header -http11processor.request.prepare=Error preparing request -http11processor.request.process=Error processing request -http11processor.request.finish=Error finishing request -http11processor.response.finish=Error finishing response -http11processor.socket.info=Exception getting socket information -http11processor.socket.ssl=Exception getting SSL attributes -http11processor.socket.timeout=Error setting socket timeout - -# -# InternalInputBuffer -# - -iib.eof.error=Unexpected EOF read on the socket -iib.requestheadertoolarge.error=Request header is too large - +# $Id: LocalStrings.properties 301004 2005-07-29 10:23:56Z remm $ + +# language + +# package org.apache.coyote.http11 + +# +# Http11Protocol +# + +http11protocol.endpoint.initerror=Error initializing endpoint +http11protocol.endpoint.starterror=Error starting endpoint +http11protocol.init=Initializing Coyote HTTP/1.1 on {0} +http11protocol.proto.error=Error reading request, ignored +http11protocol.proto.ioexception.debug=IOException reading request +http11protocol.proto.ioexception.info=IOException reading request, ignored +http11protocol.proto.socketexception.debug=SocketException reading request +http11protocol.proto.socketexception.info=SocketException reading request, ignored +http11protocol.getattribute=Attribute {0} +http11protocol.setattribute=Attribute {0}: {1} +http11protocol.socketfactory.initerror=Error initializing socket factory +http11protocol.start=Starting Coyote HTTP/1.1 on {0} +http11protocol.stop=Stopping Coyote HTTP/1.1 on {0} +http11protocol.pause=Pausing Coyote HTTP/1.1 on {0} +http11protocol.endpoint.pauseerror=Error pausing endpoint +http11protocol.resume=Resuming Coyote HTTP/1.1 on {0} +http11protocol.endpoint.resumeerror=Error resuming endpoint + +# +# Http11Processor +# + +http11processor.regexp.error=Error parsing regular expression {0} +http11processor.filter.unknown=Unknown filter {0} +http11processor.filter.error=Error intializing filter {0} +http11processor.header.parse=Error parsing HTTP request header +http11processor.request.prepare=Error preparing request +http11processor.request.process=Error processing request +http11processor.request.finish=Error finishing request +http11processor.response.finish=Error finishing response +http11processor.socket.info=Exception getting socket information +http11processor.socket.ssl=Exception getting SSL attributes +http11processor.socket.timeout=Error setting socket timeout + +# +# InternalInputBuffer +# + +iib.eof.error=Unexpected EOF read on the socket +iib.requestheadertoolarge.error=Request header is too large + diff --git a/java/org/apache/coyote/http11/LocalStrings_es.properties b/java/org/apache/coyote/http11/LocalStrings_es.properties index fe4669c94..63cd15b4c 100644 --- a/java/org/apache/coyote/http11/LocalStrings_es.properties +++ b/java/org/apache/coyote/http11/LocalStrings_es.properties @@ -1,34 +1,34 @@ -# $Id: LocalStrings_es.properties 299220 2004-02-24 08:50:56Z hgomez $ - -# language es - -# package org.apache.coyote.http11 - -# -# Http11Protocol -# - -http11protocol.endpoint.initerror=Error inicializando punto final (endpoint) -http11protocol.endpoint.starterror=Error arrancando punto final (endpoint) -http11protocol.init=Inicializando Coyote HTTP/1.1 en puerto {0} -http11protocol.proto.error=Error leyendo requerimiento, ignorado -http11protocol.proto.ioexception.debug=IOException leyendo requerimiento -http11protocol.proto.ioexception.info=IOException leyendo requerimiento, ignorada -http11protocol.proto.socketexception.debug=SocketException leyendo requerimiento -http11protocol.proto.socketexception.info=SocketException leyendo requerimiento, ignorada -http11protocol.getattribute=Atributo {0} -http11protocol.setattribute=Atributo {0}: {1} -http11protocol.socketfactory.initerror=Error inicializando fábrica de enchufes (sockets) -http11protocol.start=Arrancando Coyote HTTP/1.1 en puerto {0} - -# -# Http11Processor -# - -# -# InternalInputBuffer -# - -iib.eof.error=Inesperado Fin De Archivo (EOF) leído en el enchufe (socket) -iib.requestheadertoolarge.error=La cabecera del requerimiento es demasido grande - +# $Id: LocalStrings_es.properties 299220 2004-02-24 08:50:56Z hgomez $ + +# language es + +# package org.apache.coyote.http11 + +# +# Http11Protocol +# + +http11protocol.endpoint.initerror=Error inicializando punto final (endpoint) +http11protocol.endpoint.starterror=Error arrancando punto final (endpoint) +http11protocol.init=Inicializando Coyote HTTP/1.1 en puerto {0} +http11protocol.proto.error=Error leyendo requerimiento, ignorado +http11protocol.proto.ioexception.debug=IOException leyendo requerimiento +http11protocol.proto.ioexception.info=IOException leyendo requerimiento, ignorada +http11protocol.proto.socketexception.debug=SocketException leyendo requerimiento +http11protocol.proto.socketexception.info=SocketException leyendo requerimiento, ignorada +http11protocol.getattribute=Atributo {0} +http11protocol.setattribute=Atributo {0}: {1} +http11protocol.socketfactory.initerror=Error inicializando fábrica de enchufes (sockets) +http11protocol.start=Arrancando Coyote HTTP/1.1 en puerto {0} + +# +# Http11Processor +# + +# +# InternalInputBuffer +# + +iib.eof.error=Inesperado Fin De Archivo (EOF) leído en el enchufe (socket) +iib.requestheadertoolarge.error=La cabecera del requerimiento es demasido grande + diff --git a/java/org/apache/coyote/http11/LocalStrings_fr.properties b/java/org/apache/coyote/http11/LocalStrings_fr.properties index 21a2d79e9..374635c98 100644 --- a/java/org/apache/coyote/http11/LocalStrings_fr.properties +++ b/java/org/apache/coyote/http11/LocalStrings_fr.properties @@ -1,36 +1,36 @@ -# $Id: LocalStrings_fr.properties 299220 2004-02-24 08:50:56Z hgomez $ - -# language fr - -# package org.apache.coyote.http11 - -# -# Http11Protocol -# - -http11protocol.endpoint.initerror=Erreur à l'initialisation du point de contact -http11protocol.endpoint.starterror=Erreur au démarrage du point de contact -http11protocol.init=Initialisation de Coyote HTTP/1.1 sur {0} -http11protocol.proto.error=Erreur à la lecture de la requête, ignoré -http11protocol.proto.ioexception.debug=Exception d'entrée/sortie (IOException) à la lecture de la requête -http11protocol.proto.ioexception.info=Exception d'entrée/sortie à la lecture de la requête, ignoré -http11protocol.proto.socketexception.debug=Exception "Socket" (SocketException) à la lecture de la requête -http11protocol.proto.socketexception.info=Exception "Socket" (SocketException) à la lecture de la requête, ignoré -http11protocol.setattribute=Attribut {0}: {1} -http11protocol.socketfactory.initerror=Erreur à l'initialisation du créateur de socket (socket factory) -http11protocol.start=Démarrage de Coyote HTTP/1.1 sur {0} -http11protocol.stop=Arrêt de Coyote HTTP/1.1 sur {0} -http11protocol.pause=Suspension de Coyote HTTP/1.1 sur {0} -http11protocol.resume=Redémarrage de Coyote HTTP/1.1 sur {0} - -# -# Http11Processor -# - -# -# InternalInputBuffer -# - -iib.eof.error=Fin de flux (EOF) inattendue à la lecture sur la socket -iib.requestheadertoolarge.error=L'entête de requête est trop important - +# $Id: LocalStrings_fr.properties 299220 2004-02-24 08:50:56Z hgomez $ + +# language fr + +# package org.apache.coyote.http11 + +# +# Http11Protocol +# + +http11protocol.endpoint.initerror=Erreur à l'initialisation du point de contact +http11protocol.endpoint.starterror=Erreur au démarrage du point de contact +http11protocol.init=Initialisation de Coyote HTTP/1.1 sur {0} +http11protocol.proto.error=Erreur à la lecture de la requête, ignoré +http11protocol.proto.ioexception.debug=Exception d'entrée/sortie (IOException) à la lecture de la requête +http11protocol.proto.ioexception.info=Exception d'entrée/sortie à la lecture de la requête, ignoré +http11protocol.proto.socketexception.debug=Exception "Socket" (SocketException) à la lecture de la requête +http11protocol.proto.socketexception.info=Exception "Socket" (SocketException) à la lecture de la requête, ignoré +http11protocol.setattribute=Attribut {0}: {1} +http11protocol.socketfactory.initerror=Erreur à l'initialisation du créateur de socket (socket factory) +http11protocol.start=Démarrage de Coyote HTTP/1.1 sur {0} +http11protocol.stop=Arrêt de Coyote HTTP/1.1 sur {0} +http11protocol.pause=Suspension de Coyote HTTP/1.1 sur {0} +http11protocol.resume=Redémarrage de Coyote HTTP/1.1 sur {0} + +# +# Http11Processor +# + +# +# InternalInputBuffer +# + +iib.eof.error=Fin de flux (EOF) inattendue à la lecture sur la socket +iib.requestheadertoolarge.error=L'entête de requête est trop important + diff --git a/java/org/apache/coyote/http11/LocalStrings_ja.properties b/java/org/apache/coyote/http11/LocalStrings_ja.properties index 3f74d31a0..e4cd2087e 100644 --- a/java/org/apache/coyote/http11/LocalStrings_ja.properties +++ b/java/org/apache/coyote/http11/LocalStrings_ja.properties @@ -1,39 +1,39 @@ -# $Id: LocalStrings_ja.properties 299758 2004-08-30 17:29:47Z amyroh $ - -# language ja - -# package org.apache.coyote.http11 - -# -# Http11Protocol -# - -http11protocol.endpoint.initerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -http11protocol.endpoint.starterror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -http11protocol.init=Coyote HTTP/1.1\u3092 {0} \u3067\u521d\u671f\u5316\u3057\u307e\u3059 -http11protocol.proto.error=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f -http11protocol.proto.ioexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 -http11protocol.proto.ioexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f -http11protocol.proto.socketexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059 -http11protocol.proto.socketexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f -http11protocol.setattribute=\u5c5e\u6027 {0}: {1} -http11protocol.socketfactory.initerror=\u30bd\u30b1\u30c3\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -http11protocol.start=Coyote HTTP/1.1\u3092 {0} \u3067\u8d77\u52d5\u3057\u307e\u3059 -http11protocol.stop=Coyote HTTP/1.1\u3092 {0} \u3067\u505c\u6b62\u3057\u307e\u3059 -http11protocol.pause=Coyote HTTP/1.1\u3092 {0} \u3067\u4e00\u6642\u505c\u6b62\u3057\u307e\u3059 -http11protocol.endpoint.pauseerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u4e00\u6642\u505c\u6b62\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -http11protocol.resume=Coyote HTTP/1.1\u3092 {0} \u3067\u518d\u958b\u3057\u307e\u3059 -http11protocol.endpoint.resumeerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u518d\u958b\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 - - -# -# Http11Processor -# - -# -# InternalInputBuffer -# - -iib.eof.error=\u30bd\u30b1\u30c3\u30c8\u304b\u3089\u4e88\u671f\u3057\u306a\u3044EOF\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3057\u305f -iib.requestheadertoolarge.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30d8\u30c3\u30c0\u304c\u9577\u3059\u304e\u307e\u3059 - +# $Id: LocalStrings_ja.properties 299758 2004-08-30 17:29:47Z amyroh $ + +# language ja + +# package org.apache.coyote.http11 + +# +# Http11Protocol +# + +http11protocol.endpoint.initerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +http11protocol.endpoint.starterror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u8d77\u52d5\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +http11protocol.init=Coyote HTTP/1.1\u3092 {0} \u3067\u521d\u671f\u5316\u3057\u307e\u3059 +http11protocol.proto.error=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f +http11protocol.proto.ioexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059 +http11protocol.proto.ioexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eIOException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f +http11protocol.proto.socketexception.debug=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059 +http11protocol.proto.socketexception.info=\u30ea\u30af\u30a8\u30b9\u30c8\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306eSocketException\u3067\u3059\u304c\u3001\u7121\u8996\u3055\u308c\u307e\u3057\u305f +http11protocol.setattribute=\u5c5e\u6027 {0}: {1} +http11protocol.socketfactory.initerror=\u30bd\u30b1\u30c3\u30c8\u30d5\u30a1\u30af\u30c8\u30ea\u3092\u521d\u671f\u5316\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +http11protocol.start=Coyote HTTP/1.1\u3092 {0} \u3067\u8d77\u52d5\u3057\u307e\u3059 +http11protocol.stop=Coyote HTTP/1.1\u3092 {0} \u3067\u505c\u6b62\u3057\u307e\u3059 +http11protocol.pause=Coyote HTTP/1.1\u3092 {0} \u3067\u4e00\u6642\u505c\u6b62\u3057\u307e\u3059 +http11protocol.endpoint.pauseerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u4e00\u6642\u505c\u6b62\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +http11protocol.resume=Coyote HTTP/1.1\u3092 {0} \u3067\u518d\u958b\u3057\u307e\u3059 +http11protocol.endpoint.resumeerror=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u306e\u518d\u958b\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 + + +# +# Http11Processor +# + +# +# InternalInputBuffer +# + +iib.eof.error=\u30bd\u30b1\u30c3\u30c8\u304b\u3089\u4e88\u671f\u3057\u306a\u3044EOF\u3092\u8aad\u307f\u8fbc\u307f\u307e\u3057\u305f +iib.requestheadertoolarge.error=\u30ea\u30af\u30a8\u30b9\u30c8\u30d8\u30c3\u30c0\u304c\u9577\u3059\u304e\u307e\u3059 + diff --git a/java/org/apache/coyote/http11/OutputFilter.java b/java/org/apache/coyote/http11/OutputFilter.java index cbbb7a27e..bd073c523 100644 --- a/java/org/apache/coyote/http11/OutputFilter.java +++ b/java/org/apache/coyote/http11/OutputFilter.java @@ -1,82 +1,82 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; - -/** - * Output filter. - * - * @author Remy Maucherat - */ -public interface OutputFilter extends OutputBuffer { - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doWrite(ByteChunk chunk, Response unused) - throws IOException; - - - /** - * Some filters need additional parameters from the response. All the - * necessary reading can occur in that method, as this method is called - * after the response header processing is complete. - */ - public void setResponse(Response response); - - - /** - * Make the filter ready to process the next request. - */ - public void recycle(); - - - /** - * Get the name of the encoding handled by this filter. - */ - public ByteChunk getEncodingName(); - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(OutputBuffer buffer); - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - * - * @return Should return 0 unless the filter does some content length - * delimitation, in which case the number is the amount of extra bytes or - * missing bytes, which would indicate an error. - * Note: It is recommended that extra bytes be swallowed by the filter. - */ - public long end() - throws IOException; - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; + +/** + * Output filter. + * + * @author Remy Maucherat + */ +public interface OutputFilter extends OutputBuffer { + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doWrite(ByteChunk chunk, Response unused) + throws IOException; + + + /** + * Some filters need additional parameters from the response. All the + * necessary reading can occur in that method, as this method is called + * after the response header processing is complete. + */ + public void setResponse(Response response); + + + /** + * Make the filter ready to process the next request. + */ + public void recycle(); + + + /** + * Get the name of the encoding handled by this filter. + */ + public ByteChunk getEncodingName(); + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(OutputBuffer buffer); + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + * + * @return Should return 0 unless the filter does some content length + * delimitation, in which case the number is the amount of extra bytes or + * missing bytes, which would indicate an error. + * Note: It is recommended that extra bytes be swallowed by the filter. + */ + public long end() + throws IOException; + + +} diff --git a/java/org/apache/coyote/http11/filters/BufferedInputFilter.java b/java/org/apache/coyote/http11/filters/BufferedInputFilter.java index f56d06154..411cd53c6 100644 --- a/java/org/apache/coyote/http11/filters/BufferedInputFilter.java +++ b/java/org/apache/coyote/http11/filters/BufferedInputFilter.java @@ -1,122 +1,122 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; -import org.apache.coyote.Request; -import org.apache.coyote.InputBuffer; -import org.apache.coyote.http11.InputFilter; -import org.apache.tomcat.util.buf.ByteChunk; - -/** - * Input filter responsible for reading and buffering the request body, so that - * it does not interfere with client SSL handshake messages. - */ -public class BufferedInputFilter implements InputFilter { - - // -------------------------------------------------------------- Constants - - private static final String ENCODING_NAME = "buffered"; - private static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Instance Variables - - private ByteChunk buffered = null; - private ByteChunk tempRead = new ByteChunk(1024); - private InputBuffer buffer; - private boolean hasRead = false; - - - // ----------------------------------------------------- Static Initializer - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Set the buffering limit. This should be reset every time the buffer is - * used. - */ - public void setLimit(int limit) { - if (buffered == null) { - buffered = new ByteChunk(4048); - buffered.setLimit(limit); - } - } - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Reads the request body and buffers it. - */ - public void setRequest(Request request) { - // save off the Request body - try { - while (buffer.doRead(tempRead, request) >= 0) { - buffered.append(tempRead); - tempRead.recycle(); - } - } catch(IOException iex) { - // Ignore - } - } - - /** - * Fills the given ByteChunk with the buffered request body. - */ - public int doRead(ByteChunk chunk, Request request) throws IOException { - if (hasRead || buffered.getLength() <= 0) { - return -1; - } else { - chunk.setBytes(buffered.getBytes(), buffered.getStart(), - buffered.getLength()); - hasRead = true; - } - return chunk.getLength(); - } - - public void setBuffer(InputBuffer buffer) { - this.buffer = buffer; - } - - public void recycle() { - if (buffered.getBuffer().length > 65536) { - buffered = null; - } else { - buffered.recycle(); - } - tempRead.recycle(); - hasRead = false; - buffer = null; - } - - public ByteChunk getEncodingName() { - return ENCODING; - } - - public long end() throws IOException { - return 0; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; +import org.apache.coyote.Request; +import org.apache.coyote.InputBuffer; +import org.apache.coyote.http11.InputFilter; +import org.apache.tomcat.util.buf.ByteChunk; + +/** + * Input filter responsible for reading and buffering the request body, so that + * it does not interfere with client SSL handshake messages. + */ +public class BufferedInputFilter implements InputFilter { + + // -------------------------------------------------------------- Constants + + private static final String ENCODING_NAME = "buffered"; + private static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Instance Variables + + private ByteChunk buffered = null; + private ByteChunk tempRead = new ByteChunk(1024); + private InputBuffer buffer; + private boolean hasRead = false; + + + // ----------------------------------------------------- Static Initializer + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Set the buffering limit. This should be reset every time the buffer is + * used. + */ + public void setLimit(int limit) { + if (buffered == null) { + buffered = new ByteChunk(4048); + buffered.setLimit(limit); + } + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Reads the request body and buffers it. + */ + public void setRequest(Request request) { + // save off the Request body + try { + while (buffer.doRead(tempRead, request) >= 0) { + buffered.append(tempRead); + tempRead.recycle(); + } + } catch(IOException iex) { + // Ignore + } + } + + /** + * Fills the given ByteChunk with the buffered request body. + */ + public int doRead(ByteChunk chunk, Request request) throws IOException { + if (hasRead || buffered.getLength() <= 0) { + return -1; + } else { + chunk.setBytes(buffered.getBytes(), buffered.getStart(), + buffered.getLength()); + hasRead = true; + } + return chunk.getLength(); + } + + public void setBuffer(InputBuffer buffer) { + this.buffer = buffer; + } + + public void recycle() { + if (buffered.getBuffer().length > 65536) { + buffered = null; + } else { + buffered.recycle(); + } + tempRead.recycle(); + hasRead = false; + buffer = null; + } + + public ByteChunk getEncodingName() { + return ENCODING; + } + + public long end() throws IOException { + return 0; + } + +} diff --git a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java index fe4634487..fbc0050a9 100644 --- a/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java +++ b/java/org/apache/coyote/http11/filters/ChunkedInputFilter.java @@ -1,341 +1,341 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; -import org.apache.coyote.http11.Constants; -import org.apache.coyote.http11.InputFilter; - -/** - * Chunked input filter. Parses chunked data according to - * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
        - * - * @author Remy Maucherat - * @author Filip Hanik - */ -public class ChunkedInputFilter implements InputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "chunked"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Next buffer in the pipeline. - */ - protected InputBuffer buffer; - - - /** - * Number of bytes remaining in the current chunk. - */ - protected int remaining = 0; - - - /** - * Position in the buffer. - */ - protected int pos = 0; - - - /** - * Last valid byte in the buffer. - */ - protected int lastValid = 0; - - - /** - * Read bytes buffer. - */ - protected byte[] buf = null; - - - /** - * Byte chunk used to read bytes. - */ - protected ByteChunk readChunk = new ByteChunk(); - - - /** - * Flag set to true when the end chunk has been read. - */ - protected boolean endChunk = false; - - /** - * Flag set to true if the next call to doRead() must parse a CRLF pair - * before doing anything else. - */ - protected boolean needCRLFParse = false; - - // ------------------------------------------------------------- Properties - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Read bytes. - * - * @return If the filter does request length control, this value is - * significant; it should be the number of bytes consumed from the buffer, - * up until the end of the current request body, or the buffer length, - * whichever is greater. If the filter does not do request body length - * control, the returned value should be -1. - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - if (endChunk) - return -1; - - if(needCRLFParse) { - needCRLFParse = false; - parseCRLF(); - } - - if (remaining <= 0) { - if (!parseChunkHeader()) { - throw new IOException("Invalid chunk header"); - } - if (endChunk) { - parseEndChunk(); - return -1; - } - } - - int result = 0; - - if (pos >= lastValid) { - readBytes(); - } - - if (remaining > (lastValid - pos)) { - result = lastValid - pos; - remaining = remaining - result; - chunk.setBytes(buf, pos, result); - pos = lastValid; - } else { - result = remaining; - chunk.setBytes(buf, pos, remaining); - pos = pos + remaining; - remaining = 0; - needCRLFParse = true; - } - - return result; - - } - - - // ---------------------------------------------------- InputFilter Methods - - - /** - * Read the content length from the request. - */ - public void setRequest(Request request) { - } - - - /** - * End the current request. - */ - public long end() - throws IOException { - - // Consume extra bytes : parse the stream until the end chunk is found - while (doRead(readChunk, null) >= 0) { - } - - // Return the number of extra bytes which were consumed - return (lastValid - pos); - - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(InputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - remaining = 0; - pos = 0; - lastValid = 0; - endChunk = false; - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Read bytes from the previous buffer. - */ - protected int readBytes() - throws IOException { - - int nRead = buffer.doRead(readChunk, null); - pos = readChunk.getStart(); - lastValid = pos + nRead; - buf = readChunk.getBytes(); - - return nRead; - - } - - - /** - * Parse the header of a chunk. - * A chunk header can look like - * A10CRLF - * F23;chunk-extension to be ignoredCRLF - * The letters before CRLF but after the trailer mark, must be valid hex digits, - * we should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid header - * according to spec - */ - protected boolean parseChunkHeader() - throws IOException { - - int result = 0; - boolean eol = false; - boolean readDigit = false; - boolean trailer = false; - - while (!eol) { - - if (pos >= lastValid) { - if (readBytes() <= 0) - return false; - } - - if (buf[pos] == Constants.CR) { - } else if (buf[pos] == Constants.LF) { - eol = true; - } else if (buf[pos] == Constants.SEMI_COLON) { - trailer = true; - } else if (!trailer) { - //don't read data after the trailer - if (HexUtils.DEC[buf[pos]] != -1) { - readDigit = true; - result *= 16; - result += HexUtils.DEC[buf[pos]]; - } else { - //we shouldn't allow invalid, non hex characters - //in the chunked header - return false; - } - } - - pos++; - - } - - if (!readDigit) - return false; - - if (result == 0) - endChunk = true; - - remaining = result; - if (remaining < 0) - return false; - - return true; - - } - - - /** - * Parse CRLF at end of chunk. - */ - protected boolean parseCRLF() - throws IOException { - - boolean eol = false; - - while (!eol) { - - if (pos >= lastValid) { - if (readBytes() <= 0) - throw new IOException("Invalid CRLF"); - } - - if (buf[pos] == Constants.CR) { - } else if (buf[pos] == Constants.LF) { - eol = true; - } else { - throw new IOException("Invalid CRLF"); - } - - pos++; - - } - - return true; - - } - - - /** - * Parse end chunk data. - * FIXME: Handle trailers - */ - protected boolean parseEndChunk() - throws IOException { - - return parseCRLF(); // FIXME - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; +import org.apache.coyote.http11.Constants; +import org.apache.coyote.http11.InputFilter; + +/** + * Chunked input filter. Parses chunked data according to + * http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.6.1
        + * + * @author Remy Maucherat + * @author Filip Hanik + */ +public class ChunkedInputFilter implements InputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "chunked"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Next buffer in the pipeline. + */ + protected InputBuffer buffer; + + + /** + * Number of bytes remaining in the current chunk. + */ + protected int remaining = 0; + + + /** + * Position in the buffer. + */ + protected int pos = 0; + + + /** + * Last valid byte in the buffer. + */ + protected int lastValid = 0; + + + /** + * Read bytes buffer. + */ + protected byte[] buf = null; + + + /** + * Byte chunk used to read bytes. + */ + protected ByteChunk readChunk = new ByteChunk(); + + + /** + * Flag set to true when the end chunk has been read. + */ + protected boolean endChunk = false; + + /** + * Flag set to true if the next call to doRead() must parse a CRLF pair + * before doing anything else. + */ + protected boolean needCRLFParse = false; + + // ------------------------------------------------------------- Properties + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read bytes. + * + * @return If the filter does request length control, this value is + * significant; it should be the number of bytes consumed from the buffer, + * up until the end of the current request body, or the buffer length, + * whichever is greater. If the filter does not do request body length + * control, the returned value should be -1. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + if (endChunk) + return -1; + + if(needCRLFParse) { + needCRLFParse = false; + parseCRLF(); + } + + if (remaining <= 0) { + if (!parseChunkHeader()) { + throw new IOException("Invalid chunk header"); + } + if (endChunk) { + parseEndChunk(); + return -1; + } + } + + int result = 0; + + if (pos >= lastValid) { + readBytes(); + } + + if (remaining > (lastValid - pos)) { + result = lastValid - pos; + remaining = remaining - result; + chunk.setBytes(buf, pos, result); + pos = lastValid; + } else { + result = remaining; + chunk.setBytes(buf, pos, remaining); + pos = pos + remaining; + remaining = 0; + needCRLFParse = true; + } + + return result; + + } + + + // ---------------------------------------------------- InputFilter Methods + + + /** + * Read the content length from the request. + */ + public void setRequest(Request request) { + } + + + /** + * End the current request. + */ + public long end() + throws IOException { + + // Consume extra bytes : parse the stream until the end chunk is found + while (doRead(readChunk, null) >= 0) { + } + + // Return the number of extra bytes which were consumed + return (lastValid - pos); + + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(InputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + remaining = 0; + pos = 0; + lastValid = 0; + endChunk = false; + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Read bytes from the previous buffer. + */ + protected int readBytes() + throws IOException { + + int nRead = buffer.doRead(readChunk, null); + pos = readChunk.getStart(); + lastValid = pos + nRead; + buf = readChunk.getBytes(); + + return nRead; + + } + + + /** + * Parse the header of a chunk. + * A chunk header can look like + * A10CRLF + * F23;chunk-extension to be ignoredCRLF + * The letters before CRLF but after the trailer mark, must be valid hex digits, + * we should not parse F23IAMGONNAMESSTHISUP34CRLF as a valid header + * according to spec + */ + protected boolean parseChunkHeader() + throws IOException { + + int result = 0; + boolean eol = false; + boolean readDigit = false; + boolean trailer = false; + + while (!eol) { + + if (pos >= lastValid) { + if (readBytes() <= 0) + return false; + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else if (buf[pos] == Constants.SEMI_COLON) { + trailer = true; + } else if (!trailer) { + //don't read data after the trailer + if (HexUtils.DEC[buf[pos]] != -1) { + readDigit = true; + result *= 16; + result += HexUtils.DEC[buf[pos]]; + } else { + //we shouldn't allow invalid, non hex characters + //in the chunked header + return false; + } + } + + pos++; + + } + + if (!readDigit) + return false; + + if (result == 0) + endChunk = true; + + remaining = result; + if (remaining < 0) + return false; + + return true; + + } + + + /** + * Parse CRLF at end of chunk. + */ + protected boolean parseCRLF() + throws IOException { + + boolean eol = false; + + while (!eol) { + + if (pos >= lastValid) { + if (readBytes() <= 0) + throw new IOException("Invalid CRLF"); + } + + if (buf[pos] == Constants.CR) { + } else if (buf[pos] == Constants.LF) { + eol = true; + } else { + throw new IOException("Invalid CRLF"); + } + + pos++; + + } + + return true; + + } + + + /** + * Parse end chunk data. + * FIXME: Handle trailers + */ + protected boolean parseEndChunk() + throws IOException { + + return parseCRLF(); // FIXME + + } + + +} diff --git a/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java b/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java index d9a5aef2d..9b01e3bc8 100644 --- a/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/ChunkedOutputFilter.java @@ -1,186 +1,186 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.HexUtils; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; -import org.apache.coyote.http11.OutputFilter; - -/** - * Chunked output filter. - * - * @author Remy Maucherat - */ -public class ChunkedOutputFilter implements OutputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "chunked"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - /** - * End chunk. - */ - protected static final ByteChunk END_CHUNK = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - byte[] END_CHUNK_BYTES = {(byte) '0', (byte) '\r', (byte) '\n', - (byte) '\r', (byte) '\n'}; - END_CHUNK.setBytes(END_CHUNK_BYTES, 0, END_CHUNK_BYTES.length); - } - - - // ------------------------------------------------------------ Constructor - - - /** - * Default constructor. - */ - public ChunkedOutputFilter() { - chunkLength = new byte[10]; - chunkLength[8] = (byte) '\r'; - chunkLength[9] = (byte) '\n'; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Next buffer in the pipeline. - */ - protected OutputBuffer buffer; - - - /** - * Buffer used for chunk length conversion. - */ - protected byte[] chunkLength = new byte[10]; - - - /** - * Chunk header. - */ - protected ByteChunk chunkHeader = new ByteChunk(); - - - // ------------------------------------------------------------- Properties - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - int result = chunk.getLength(); - - if (result <= 0) { - return 0; - } - - // Calculate chunk header - int pos = 7; - int current = result; - while (current > 0) { - int digit = current % 16; - current = current / 16; - chunkLength[pos--] = HexUtils.HEX[digit]; - } - chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos); - buffer.doWrite(chunkHeader, res); - - buffer.doWrite(chunk, res); - - chunkHeader.setBytes(chunkLength, 8, 2); - buffer.doWrite(chunkHeader, res); - - return result; - - } - - - // --------------------------------------------------- OutputFilter Methods - - - /** - * Some filters need additional parameters from the response. All the - * necessary reading can occur in that method, as this method is called - * after the response header processing is complete. - */ - public void setResponse(Response response) { - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(OutputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - */ - public long end() - throws IOException { - - // Write end chunk - buffer.doWrite(END_CHUNK, null); - - return 0; - - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.HexUtils; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.coyote.http11.OutputFilter; + +/** + * Chunked output filter. + * + * @author Remy Maucherat + */ +public class ChunkedOutputFilter implements OutputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "chunked"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + /** + * End chunk. + */ + protected static final ByteChunk END_CHUNK = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + byte[] END_CHUNK_BYTES = {(byte) '0', (byte) '\r', (byte) '\n', + (byte) '\r', (byte) '\n'}; + END_CHUNK.setBytes(END_CHUNK_BYTES, 0, END_CHUNK_BYTES.length); + } + + + // ------------------------------------------------------------ Constructor + + + /** + * Default constructor. + */ + public ChunkedOutputFilter() { + chunkLength = new byte[10]; + chunkLength[8] = (byte) '\r'; + chunkLength[9] = (byte) '\n'; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Next buffer in the pipeline. + */ + protected OutputBuffer buffer; + + + /** + * Buffer used for chunk length conversion. + */ + protected byte[] chunkLength = new byte[10]; + + + /** + * Chunk header. + */ + protected ByteChunk chunkHeader = new ByteChunk(); + + + // ------------------------------------------------------------- Properties + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + int result = chunk.getLength(); + + if (result <= 0) { + return 0; + } + + // Calculate chunk header + int pos = 7; + int current = result; + while (current > 0) { + int digit = current % 16; + current = current / 16; + chunkLength[pos--] = HexUtils.HEX[digit]; + } + chunkHeader.setBytes(chunkLength, pos + 1, 9 - pos); + buffer.doWrite(chunkHeader, res); + + buffer.doWrite(chunk, res); + + chunkHeader.setBytes(chunkLength, 8, 2); + buffer.doWrite(chunkHeader, res); + + return result; + + } + + + // --------------------------------------------------- OutputFilter Methods + + + /** + * Some filters need additional parameters from the response. All the + * necessary reading can occur in that method, as this method is called + * after the response header processing is complete. + */ + public void setResponse(Response response) { + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(OutputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + */ + public long end() + throws IOException { + + // Write end chunk + buffer.doWrite(END_CHUNK, null); + + return 0; + + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + +} diff --git a/java/org/apache/coyote/http11/filters/GzipOutputFilter.java b/java/org/apache/coyote/http11/filters/GzipOutputFilter.java index f97da4554..dbd19d74a 100644 --- a/java/org/apache/coyote/http11/filters/GzipOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/GzipOutputFilter.java @@ -1,170 +1,170 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.zip.GZIPOutputStream; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; -import org.apache.coyote.http11.OutputFilter; - -/** - * Gzip output filter. - * - * @author Remy Maucherat - */ -public class GzipOutputFilter implements OutputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "gzip"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Next buffer in the pipeline. - */ - protected OutputBuffer buffer; - - - /** - * Compression output stream. - */ - protected GZIPOutputStream compressionStream = null; - - - /** - * Fake internal output stream. - */ - protected OutputStream fakeOutputStream = new FakeOutputStream(); - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - if (compressionStream == null) { - compressionStream = new GZIPOutputStream(fakeOutputStream); - } - compressionStream.write(chunk.getBytes(), chunk.getStart(), - chunk.getLength()); - return chunk.getLength(); - } - - - // --------------------------------------------------- OutputFilter Methods - - - /** - * Some filters need additional parameters from the response. All the - * necessary reading can occur in that method, as this method is called - * after the response header processing is complete. - */ - public void setResponse(Response response) { - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(OutputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - */ - public long end() - throws IOException { - if (compressionStream == null) { - compressionStream = new GZIPOutputStream(fakeOutputStream); - } - compressionStream.finish(); - compressionStream.close(); - return ((OutputFilter) buffer).end(); - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - // Set compression stream to null - compressionStream = null; - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - - // ------------------------------------------- FakeOutputStream Inner Class - - - protected class FakeOutputStream - extends OutputStream { - protected ByteChunk outputChunk = new ByteChunk(); - protected byte[] singleByteBuffer = new byte[1]; - public void write(int b) - throws IOException { - // Shouldn't get used for good performance, but is needed for - // compatibility with Sun JDK 1.4.0 - singleByteBuffer[0] = (byte) (b & 0xff); - outputChunk.setBytes(singleByteBuffer, 0, 1); - buffer.doWrite(outputChunk, null); - } - public void write(byte[] b, int off, int len) - throws IOException { - outputChunk.setBytes(b, off, len); - buffer.doWrite(outputChunk, null); - } - public void flush() throws IOException {} - public void close() throws IOException {} - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.zip.GZIPOutputStream; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.coyote.http11.OutputFilter; + +/** + * Gzip output filter. + * + * @author Remy Maucherat + */ +public class GzipOutputFilter implements OutputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "gzip"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Next buffer in the pipeline. + */ + protected OutputBuffer buffer; + + + /** + * Compression output stream. + */ + protected GZIPOutputStream compressionStream = null; + + + /** + * Fake internal output stream. + */ + protected OutputStream fakeOutputStream = new FakeOutputStream(); + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + if (compressionStream == null) { + compressionStream = new GZIPOutputStream(fakeOutputStream); + } + compressionStream.write(chunk.getBytes(), chunk.getStart(), + chunk.getLength()); + return chunk.getLength(); + } + + + // --------------------------------------------------- OutputFilter Methods + + + /** + * Some filters need additional parameters from the response. All the + * necessary reading can occur in that method, as this method is called + * after the response header processing is complete. + */ + public void setResponse(Response response) { + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(OutputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + */ + public long end() + throws IOException { + if (compressionStream == null) { + compressionStream = new GZIPOutputStream(fakeOutputStream); + } + compressionStream.finish(); + compressionStream.close(); + return ((OutputFilter) buffer).end(); + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + // Set compression stream to null + compressionStream = null; + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + + // ------------------------------------------- FakeOutputStream Inner Class + + + protected class FakeOutputStream + extends OutputStream { + protected ByteChunk outputChunk = new ByteChunk(); + protected byte[] singleByteBuffer = new byte[1]; + public void write(int b) + throws IOException { + // Shouldn't get used for good performance, but is needed for + // compatibility with Sun JDK 1.4.0 + singleByteBuffer[0] = (byte) (b & 0xff); + outputChunk.setBytes(singleByteBuffer, 0, 1); + buffer.doWrite(outputChunk, null); + } + public void write(byte[] b, int off, int len) + throws IOException { + outputChunk.setBytes(b, off, len); + buffer.doWrite(outputChunk, null); + } + public void flush() throws IOException {} + public void close() throws IOException {} + } + + +} diff --git a/java/org/apache/coyote/http11/filters/IdentityInputFilter.java b/java/org/apache/coyote/http11/filters/IdentityInputFilter.java index d730c5775..2545fbc9c 100644 --- a/java/org/apache/coyote/http11/filters/IdentityInputFilter.java +++ b/java/org/apache/coyote/http11/filters/IdentityInputFilter.java @@ -1,201 +1,201 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; -import org.apache.coyote.http11.InputFilter; - -/** - * Identity input filter. - * - * @author Remy Maucherat - */ -public class IdentityInputFilter implements InputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "identity"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Content length. - */ - protected long contentLength = -1; - - - /** - * Remaining bytes. - */ - protected long remaining = 0; - - - /** - * Next buffer in the pipeline. - */ - protected InputBuffer buffer; - - - /** - * Chunk used to read leftover bytes. - */ - protected ByteChunk endChunk = new ByteChunk(); - - - // ------------------------------------------------------------- Properties - - - /** - * Get content length. - */ - public long getContentLength() { - return contentLength; - } - - - /** - * Get remaining bytes. - */ - public long getRemaining() { - return remaining; - } - - - // ---------------------------------------------------- InputBuffer Methods - - - /** - * Read bytes. - * - * @return If the filter does request length control, this value is - * significant; it should be the number of bytes consumed from the buffer, - * up until the end of the current request body, or the buffer length, - * whichever is greater. If the filter does not do request body length - * control, the returned value should be -1. - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - int result = -1; - - if (contentLength >= 0) { - if (remaining > 0) { - int nRead = buffer.doRead(chunk, req); - if (nRead > remaining) { - // The chunk is longer than the number of bytes remaining - // in the body; changing the chunk length to the number - // of bytes remaining - chunk.setBytes(chunk.getBytes(), chunk.getStart(), - (int) remaining); - result = (int) remaining; - } else { - result = nRead; - } - remaining = remaining - nRead; - } else { - // No more bytes left to be read : return -1 and clear the - // buffer - chunk.recycle(); - result = -1; - } - } - - return result; - - } - - - // ---------------------------------------------------- InputFilter Methods - - - /** - * Read the content length from the request. - */ - public void setRequest(Request request) { - contentLength = request.getContentLengthLong(); - remaining = contentLength; - } - - - /** - * End the current request. - */ - public long end() - throws IOException { - - // Consume extra bytes. - while (remaining > 0) { - int nread = buffer.doRead(endChunk, null); - if (nread > 0 ) { - remaining = remaining - nread; - } else { // errors are handled higher up. - remaining = 0; - } - } - - // If too many bytes were read, return the amount. - return -remaining; - - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(InputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - contentLength = -1; - remaining = 0; - endChunk.recycle(); - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; +import org.apache.coyote.http11.InputFilter; + +/** + * Identity input filter. + * + * @author Remy Maucherat + */ +public class IdentityInputFilter implements InputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "identity"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Content length. + */ + protected long contentLength = -1; + + + /** + * Remaining bytes. + */ + protected long remaining = 0; + + + /** + * Next buffer in the pipeline. + */ + protected InputBuffer buffer; + + + /** + * Chunk used to read leftover bytes. + */ + protected ByteChunk endChunk = new ByteChunk(); + + + // ------------------------------------------------------------- Properties + + + /** + * Get content length. + */ + public long getContentLength() { + return contentLength; + } + + + /** + * Get remaining bytes. + */ + public long getRemaining() { + return remaining; + } + + + // ---------------------------------------------------- InputBuffer Methods + + + /** + * Read bytes. + * + * @return If the filter does request length control, this value is + * significant; it should be the number of bytes consumed from the buffer, + * up until the end of the current request body, or the buffer length, + * whichever is greater. If the filter does not do request body length + * control, the returned value should be -1. + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + int result = -1; + + if (contentLength >= 0) { + if (remaining > 0) { + int nRead = buffer.doRead(chunk, req); + if (nRead > remaining) { + // The chunk is longer than the number of bytes remaining + // in the body; changing the chunk length to the number + // of bytes remaining + chunk.setBytes(chunk.getBytes(), chunk.getStart(), + (int) remaining); + result = (int) remaining; + } else { + result = nRead; + } + remaining = remaining - nRead; + } else { + // No more bytes left to be read : return -1 and clear the + // buffer + chunk.recycle(); + result = -1; + } + } + + return result; + + } + + + // ---------------------------------------------------- InputFilter Methods + + + /** + * Read the content length from the request. + */ + public void setRequest(Request request) { + contentLength = request.getContentLengthLong(); + remaining = contentLength; + } + + + /** + * End the current request. + */ + public long end() + throws IOException { + + // Consume extra bytes. + while (remaining > 0) { + int nread = buffer.doRead(endChunk, null); + if (nread > 0 ) { + remaining = remaining - nread; + } else { // errors are handled higher up. + remaining = 0; + } + } + + // If too many bytes were read, return the amount. + return -remaining; + + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(InputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + contentLength = -1; + remaining = 0; + endChunk.recycle(); + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + +} diff --git a/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java b/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java index 0e2b7ec7c..2f09598ee 100644 --- a/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/IdentityOutputFilter.java @@ -1,189 +1,189 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; -import org.apache.coyote.http11.OutputFilter; - -/** - * Identity output filter. - * - * @author Remy Maucherat - */ -public class IdentityOutputFilter implements OutputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "identity"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Content length. - */ - protected long contentLength = -1; - - - /** - * Remaining bytes. - */ - protected long remaining = 0; - - - /** - * Next buffer in the pipeline. - */ - protected OutputBuffer buffer; - - - // ------------------------------------------------------------- Properties - - - /** - * Get content length. - */ - public long getContentLength() { - return contentLength; - } - - - /** - * Get remaining bytes. - */ - public long getRemaining() { - return remaining; - } - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - int result = -1; - - if (contentLength >= 0) { - if (remaining > 0) { - result = chunk.getLength(); - if (result > remaining) { - // The chunk is longer than the number of bytes remaining - // in the body; changing the chunk length to the number - // of bytes remaining - chunk.setBytes(chunk.getBytes(), chunk.getStart(), - (int) remaining); - result = (int) remaining; - remaining = 0; - } else { - remaining = remaining - result; - } - buffer.doWrite(chunk, res); - } else { - // No more bytes left to be written : return -1 and clear the - // buffer - chunk.recycle(); - result = -1; - } - } else { - // If no content length was set, just write the bytes - buffer.doWrite(chunk, res); - result = chunk.getLength(); - } - - return result; - - } - - - // --------------------------------------------------- OutputFilter Methods - - - /** - * Some filters need additional parameters from the response. All the - * necessary reading can occur in that method, as this method is called - * after the response header processing is complete. - */ - public void setResponse(Response response) { - contentLength = response.getContentLengthLong(); - remaining = contentLength; - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(OutputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - */ - public long end() - throws IOException { - - if (remaining > 0) - return remaining; - return 0; - - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - contentLength = -1; - remaining = 0; - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.coyote.http11.OutputFilter; + +/** + * Identity output filter. + * + * @author Remy Maucherat + */ +public class IdentityOutputFilter implements OutputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "identity"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Content length. + */ + protected long contentLength = -1; + + + /** + * Remaining bytes. + */ + protected long remaining = 0; + + + /** + * Next buffer in the pipeline. + */ + protected OutputBuffer buffer; + + + // ------------------------------------------------------------- Properties + + + /** + * Get content length. + */ + public long getContentLength() { + return contentLength; + } + + + /** + * Get remaining bytes. + */ + public long getRemaining() { + return remaining; + } + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + int result = -1; + + if (contentLength >= 0) { + if (remaining > 0) { + result = chunk.getLength(); + if (result > remaining) { + // The chunk is longer than the number of bytes remaining + // in the body; changing the chunk length to the number + // of bytes remaining + chunk.setBytes(chunk.getBytes(), chunk.getStart(), + (int) remaining); + result = (int) remaining; + remaining = 0; + } else { + remaining = remaining - result; + } + buffer.doWrite(chunk, res); + } else { + // No more bytes left to be written : return -1 and clear the + // buffer + chunk.recycle(); + result = -1; + } + } else { + // If no content length was set, just write the bytes + buffer.doWrite(chunk, res); + result = chunk.getLength(); + } + + return result; + + } + + + // --------------------------------------------------- OutputFilter Methods + + + /** + * Some filters need additional parameters from the response. All the + * necessary reading can occur in that method, as this method is called + * after the response header processing is complete. + */ + public void setResponse(Response response) { + contentLength = response.getContentLengthLong(); + remaining = contentLength; + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(OutputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + */ + public long end() + throws IOException { + + if (remaining > 0) + return remaining; + return 0; + + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + contentLength = -1; + remaining = 0; + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + +} diff --git a/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java b/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java index fedbbaa8d..2fd2f6533 100644 --- a/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java +++ b/java/org/apache/coyote/http11/filters/SavedRequestInputFilter.java @@ -1,99 +1,99 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.http11.InputFilter; -import org.apache.tomcat.util.buf.ByteChunk; - -/** - * Input filter responsible for replaying the request body when restoring the - * saved request after FORM authentication. - */ -public class SavedRequestInputFilter implements InputFilter { - - /** - * The original request body. - */ - protected ByteChunk input = null; - - /** - * Create a new SavedRequestInputFilter. - * - * @param input The saved request body to be replayed. - */ - public SavedRequestInputFilter(ByteChunk input) { - this.input = input; - } - - /** - * Read bytes. - */ - public int doRead(ByteChunk chunk, org.apache.coyote.Request request) - throws IOException { - int writeLength = 0; - - if (chunk.getLimit() > 0 && chunk.getLimit() < input.getLength()) { - writeLength = chunk.getLimit(); - } else { - writeLength = input.getLength(); - } - - input.substract(chunk.getBuffer(), 0, writeLength); - chunk.setOffset(0); - chunk.setEnd(writeLength); - - return writeLength; - } - - /** - * Set the content length on the request. - */ - public void setRequest(org.apache.coyote.Request request) { - request.setContentLength(input.getLength()); - } - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - input = null; - } - - /** - * Return the name of the associated encoding; here, the value is null. - */ - public ByteChunk getEncodingName() { - return null; - } - - /** - * Set the next buffer in the filter pipeline (has no effect). - */ - public void setBuffer(InputBuffer buffer) { - } - - /** - * End the current request (has no effect). - */ - public long end() throws IOException { - return 0; - } - -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.http11.InputFilter; +import org.apache.tomcat.util.buf.ByteChunk; + +/** + * Input filter responsible for replaying the request body when restoring the + * saved request after FORM authentication. + */ +public class SavedRequestInputFilter implements InputFilter { + + /** + * The original request body. + */ + protected ByteChunk input = null; + + /** + * Create a new SavedRequestInputFilter. + * + * @param input The saved request body to be replayed. + */ + public SavedRequestInputFilter(ByteChunk input) { + this.input = input; + } + + /** + * Read bytes. + */ + public int doRead(ByteChunk chunk, org.apache.coyote.Request request) + throws IOException { + int writeLength = 0; + + if (chunk.getLimit() > 0 && chunk.getLimit() < input.getLength()) { + writeLength = chunk.getLimit(); + } else { + writeLength = input.getLength(); + } + + input.substract(chunk.getBuffer(), 0, writeLength); + chunk.setOffset(0); + chunk.setEnd(writeLength); + + return writeLength; + } + + /** + * Set the content length on the request. + */ + public void setRequest(org.apache.coyote.Request request) { + request.setContentLength(input.getLength()); + } + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + input = null; + } + + /** + * Return the name of the associated encoding; here, the value is null. + */ + public ByteChunk getEncodingName() { + return null; + } + + /** + * Set the next buffer in the filter pipeline (has no effect). + */ + public void setBuffer(InputBuffer buffer) { + } + + /** + * End the current request (has no effect). + */ + public long end() throws IOException { + return 0; + } + +} diff --git a/java/org/apache/coyote/http11/filters/VoidInputFilter.java b/java/org/apache/coyote/http11/filters/VoidInputFilter.java index e9abdf9f2..e8551b03e 100644 --- a/java/org/apache/coyote/http11/filters/VoidInputFilter.java +++ b/java/org/apache/coyote/http11/filters/VoidInputFilter.java @@ -1,118 +1,118 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; -import org.apache.coyote.http11.InputFilter; - -/** - * Void input filter, which returns -1 when attempting a read. Used with a GET, - * HEAD, or a similar request. - * - * @author Remy Maucherat - */ -public class VoidInputFilter implements InputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "void"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doRead(ByteChunk chunk, Request req) - throws IOException { - - return -1; - - } - - - // --------------------------------------------------- OutputFilter Methods - - - /** - * Set the associated reauest. - */ - public void setRequest(Request request) { - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(InputBuffer buffer) { - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "void". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - * - * @return Should return 0 unless the filter does some content length - * delimitation, in which case the number is the amount of extra bytes or - * missing bytes, which would indicate an error. - * Note: It is recommended that extra bytes be swallowed by the filter. - */ - public long end() - throws IOException { - return 0; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.InputBuffer; +import org.apache.coyote.Request; +import org.apache.coyote.http11.InputFilter; + +/** + * Void input filter, which returns -1 when attempting a read. Used with a GET, + * HEAD, or a similar request. + * + * @author Remy Maucherat + */ +public class VoidInputFilter implements InputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "void"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doRead(ByteChunk chunk, Request req) + throws IOException { + + return -1; + + } + + + // --------------------------------------------------- OutputFilter Methods + + + /** + * Set the associated reauest. + */ + public void setRequest(Request request) { + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(InputBuffer buffer) { + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "void". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + * + * @return Should return 0 unless the filter does some content length + * delimitation, in which case the number is the amount of extra bytes or + * missing bytes, which would indicate an error. + * Note: It is recommended that extra bytes be swallowed by the filter. + */ + public long end() + throws IOException { + return 0; + } + + +} diff --git a/java/org/apache/coyote/http11/filters/VoidOutputFilter.java b/java/org/apache/coyote/http11/filters/VoidOutputFilter.java index 543462af6..efe6fafe5 100644 --- a/java/org/apache/coyote/http11/filters/VoidOutputFilter.java +++ b/java/org/apache/coyote/http11/filters/VoidOutputFilter.java @@ -1,127 +1,127 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.http11.filters; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.Response; -import org.apache.coyote.http11.OutputFilter; - -/** - * Void output filter, which silently swallows bytes written. Used with a 204 - * status (no content) or a HEAD request. - * - * @author Remy Maucherat - */ -public class VoidOutputFilter implements OutputFilter { - - - // -------------------------------------------------------------- Constants - - - protected static final String ENCODING_NAME = "void"; - protected static final ByteChunk ENCODING = new ByteChunk(); - - - // ----------------------------------------------------- Static Initializer - - - static { - ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Next buffer in the pipeline. - */ - protected OutputBuffer buffer; - - - // --------------------------------------------------- OutputBuffer Methods - - - /** - * Write some bytes. - * - * @return number of bytes written by the filter - */ - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - - return chunk.getLength(); - - } - - - // --------------------------------------------------- OutputFilter Methods - - - /** - * Some filters need additional parameters from the response. All the - * necessary reading can occur in that method, as this method is called - * after the response header processing is complete. - */ - public void setResponse(Response response) { - } - - - /** - * Set the next buffer in the filter pipeline. - */ - public void setBuffer(OutputBuffer buffer) { - this.buffer = buffer; - } - - - /** - * Make the filter ready to process the next request. - */ - public void recycle() { - } - - - /** - * Return the name of the associated encoding; Here, the value is - * "identity". - */ - public ByteChunk getEncodingName() { - return ENCODING; - } - - - /** - * End the current request. It is acceptable to write extra bytes using - * buffer.doWrite during the execution of this method. - * - * @return Should return 0 unless the filter does some content length - * delimitation, in which case the number is the amount of extra bytes or - * missing bytes, which would indicate an error. - * Note: It is recommended that extra bytes be swallowed by the filter. - */ - public long end() - throws IOException { - return 0; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.http11.filters; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.Response; +import org.apache.coyote.http11.OutputFilter; + +/** + * Void output filter, which silently swallows bytes written. Used with a 204 + * status (no content) or a HEAD request. + * + * @author Remy Maucherat + */ +public class VoidOutputFilter implements OutputFilter { + + + // -------------------------------------------------------------- Constants + + + protected static final String ENCODING_NAME = "void"; + protected static final ByteChunk ENCODING = new ByteChunk(); + + + // ----------------------------------------------------- Static Initializer + + + static { + ENCODING.setBytes(ENCODING_NAME.getBytes(), 0, ENCODING_NAME.length()); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Next buffer in the pipeline. + */ + protected OutputBuffer buffer; + + + // --------------------------------------------------- OutputBuffer Methods + + + /** + * Write some bytes. + * + * @return number of bytes written by the filter + */ + public int doWrite(ByteChunk chunk, Response res) + throws IOException { + + return chunk.getLength(); + + } + + + // --------------------------------------------------- OutputFilter Methods + + + /** + * Some filters need additional parameters from the response. All the + * necessary reading can occur in that method, as this method is called + * after the response header processing is complete. + */ + public void setResponse(Response response) { + } + + + /** + * Set the next buffer in the filter pipeline. + */ + public void setBuffer(OutputBuffer buffer) { + this.buffer = buffer; + } + + + /** + * Make the filter ready to process the next request. + */ + public void recycle() { + } + + + /** + * Return the name of the associated encoding; Here, the value is + * "identity". + */ + public ByteChunk getEncodingName() { + return ENCODING; + } + + + /** + * End the current request. It is acceptable to write extra bytes using + * buffer.doWrite during the execution of this method. + * + * @return Should return 0 unless the filter does some content length + * delimitation, in which case the number is the amount of extra bytes or + * missing bytes, which would indicate an error. + * Note: It is recommended that extra bytes be swallowed by the filter. + */ + public long end() + throws IOException { + return 0; + } + + +} diff --git a/java/org/apache/coyote/memory/MemoryProtocolHandler.java b/java/org/apache/coyote/memory/MemoryProtocolHandler.java index c4c2cc489..7d399c97d 100644 --- a/java/org/apache/coyote/memory/MemoryProtocolHandler.java +++ b/java/org/apache/coyote/memory/MemoryProtocolHandler.java @@ -1,166 +1,166 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.coyote.memory; - -import java.io.IOException; -import java.util.Iterator; -import org.apache.tomcat.util.buf.ByteChunk; - -import org.apache.coyote.Adapter; -import org.apache.coyote.InputBuffer; -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.Request; -import org.apache.coyote.Response; - - -/** - * Abstract the protocol implementation, including threading, etc. - * Processor is single threaded and specific to stream-based protocols, - * will not fit Jk protocols like JNI. - * - * @author Remy Maucherat - */ -public class MemoryProtocolHandler - implements ProtocolHandler { - - - // ------------------------------------------------------------- Properties - - - /** - * Pass config info. - */ - public void setAttribute(String name, Object value) { - } - - public Object getAttribute(String name) { - return null; - } - - public Iterator getAttributeNames() { return null ; } - /** - * Associated adapter. - */ - protected Adapter adapter = null; - - /** - * The adapter, used to call the connector. - */ - public void setAdapter(Adapter adapter) { - this.adapter = adapter; - } - - public Adapter getAdapter() { - return (adapter); - } - - - // ------------------------------------------------ ProtocolHandler Methods - - - /** - * Init the protocol. - */ - public void init() - throws Exception { - } - - - /** - * Start the protocol. - */ - public void start() - throws Exception { - } - - - public void pause() - throws Exception { - } - - public void resume() - throws Exception { - } - - public void destroy() - throws Exception { - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Process specified request. - */ - public void process(Request request, ByteChunk input, - Response response, ByteChunk output) - throws Exception { - - InputBuffer inputBuffer = new ByteChunkInputBuffer(input); - OutputBuffer outputBuffer = new ByteChunkOutputBuffer(output); - request.setInputBuffer(inputBuffer); - response.setOutputBuffer(outputBuffer); - - adapter.service(request, response); - - } - - - // --------------------------------------------- ByteChunkInputBuffer Class - - - protected class ByteChunkInputBuffer - implements InputBuffer { - - protected ByteChunk input = null; - - public ByteChunkInputBuffer(ByteChunk input) { - this.input = input; - } - - public int doRead(ByteChunk chunk, Request request) - throws IOException { - return input.substract(chunk); - } - - } - - - // -------------------------------------------- ByteChunkOuptutBuffer Class - - - protected class ByteChunkOutputBuffer - implements OutputBuffer { - - protected ByteChunk output = null; - - public ByteChunkOutputBuffer(ByteChunk output) { - this.output = output; - } - - public int doWrite(ByteChunk chunk, Response response) - throws IOException { - output.append(chunk); - return chunk.getLength(); - } - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.coyote.memory; + +import java.io.IOException; +import java.util.Iterator; +import org.apache.tomcat.util.buf.ByteChunk; + +import org.apache.coyote.Adapter; +import org.apache.coyote.InputBuffer; +import org.apache.coyote.OutputBuffer; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.Request; +import org.apache.coyote.Response; + + +/** + * Abstract the protocol implementation, including threading, etc. + * Processor is single threaded and specific to stream-based protocols, + * will not fit Jk protocols like JNI. + * + * @author Remy Maucherat + */ +public class MemoryProtocolHandler + implements ProtocolHandler { + + + // ------------------------------------------------------------- Properties + + + /** + * Pass config info. + */ + public void setAttribute(String name, Object value) { + } + + public Object getAttribute(String name) { + return null; + } + + public Iterator getAttributeNames() { return null ; } + /** + * Associated adapter. + */ + protected Adapter adapter = null; + + /** + * The adapter, used to call the connector. + */ + public void setAdapter(Adapter adapter) { + this.adapter = adapter; + } + + public Adapter getAdapter() { + return (adapter); + } + + + // ------------------------------------------------ ProtocolHandler Methods + + + /** + * Init the protocol. + */ + public void init() + throws Exception { + } + + + /** + * Start the protocol. + */ + public void start() + throws Exception { + } + + + public void pause() + throws Exception { + } + + public void resume() + throws Exception { + } + + public void destroy() + throws Exception { + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Process specified request. + */ + public void process(Request request, ByteChunk input, + Response response, ByteChunk output) + throws Exception { + + InputBuffer inputBuffer = new ByteChunkInputBuffer(input); + OutputBuffer outputBuffer = new ByteChunkOutputBuffer(output); + request.setInputBuffer(inputBuffer); + response.setOutputBuffer(outputBuffer); + + adapter.service(request, response); + + } + + + // --------------------------------------------- ByteChunkInputBuffer Class + + + protected class ByteChunkInputBuffer + implements InputBuffer { + + protected ByteChunk input = null; + + public ByteChunkInputBuffer(ByteChunk input) { + this.input = input; + } + + public int doRead(ByteChunk chunk, Request request) + throws IOException { + return input.substract(chunk); + } + + } + + + // -------------------------------------------- ByteChunkOuptutBuffer Class + + + protected class ByteChunkOutputBuffer + implements OutputBuffer { + + protected ByteChunk output = null; + + public ByteChunkOutputBuffer(ByteChunk output) { + this.output = output; + } + + public int doWrite(ByteChunk chunk, Response response) + throws IOException { + output.append(chunk); + return chunk.getLength(); + } + + } + + +} diff --git a/java/org/apache/el/ExpressionFactoryImpl.java b/java/org/apache/el/ExpressionFactoryImpl.java index c9eb495aa..108375e8f 100644 --- a/java/org/apache/el/ExpressionFactoryImpl.java +++ b/java/org/apache/el/ExpressionFactoryImpl.java @@ -1,78 +1,78 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el; - -import javax.el.ELContext; -import javax.el.ExpressionFactory; -import javax.el.MethodExpression; -import javax.el.ValueExpression; - -import org.apache.el.lang.ELSupport; -import org.apache.el.lang.ExpressionBuilder; -import org.apache.el.util.MessageFactory; - - -/** - * @see javax.el.ExpressionFactory - * - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public class ExpressionFactoryImpl extends ExpressionFactory { - - /** - * - */ - public ExpressionFactoryImpl() { - super(); - } - - public Object coerceToType(Object obj, Class type) { - return ELSupport.coerceToType(obj, type); - } - - public MethodExpression createMethodExpression(ELContext context, - String expression, Class expectedReturnType, - Class[] expectedParamTypes) { - if (expectedParamTypes == null) { - throw new NullPointerException(MessageFactory - .get("error.method.nullParms")); - } - ExpressionBuilder builder = new ExpressionBuilder(expression, context); - return builder.createMethodExpression(expectedReturnType, - expectedParamTypes); - } - - public ValueExpression createValueExpression(ELContext context, - String expression, Class expectedType) { - if (expectedType == null) { - throw new NullPointerException(MessageFactory - .get("error.value.expectedType")); - } - ExpressionBuilder builder = new ExpressionBuilder(expression, context); - return builder.createValueExpression(expectedType); - } - - public ValueExpression createValueExpression(Object instance, - Class expectedType) { - if (expectedType == null) { - throw new NullPointerException(MessageFactory - .get("error.value.expectedType")); - } - return new ValueExpressionLiteral(instance, expectedType); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el; + +import javax.el.ELContext; +import javax.el.ExpressionFactory; +import javax.el.MethodExpression; +import javax.el.ValueExpression; + +import org.apache.el.lang.ELSupport; +import org.apache.el.lang.ExpressionBuilder; +import org.apache.el.util.MessageFactory; + + +/** + * @see javax.el.ExpressionFactory + * + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public class ExpressionFactoryImpl extends ExpressionFactory { + + /** + * + */ + public ExpressionFactoryImpl() { + super(); + } + + public Object coerceToType(Object obj, Class type) { + return ELSupport.coerceToType(obj, type); + } + + public MethodExpression createMethodExpression(ELContext context, + String expression, Class expectedReturnType, + Class[] expectedParamTypes) { + if (expectedParamTypes == null) { + throw new NullPointerException(MessageFactory + .get("error.method.nullParms")); + } + ExpressionBuilder builder = new ExpressionBuilder(expression, context); + return builder.createMethodExpression(expectedReturnType, + expectedParamTypes); + } + + public ValueExpression createValueExpression(ELContext context, + String expression, Class expectedType) { + if (expectedType == null) { + throw new NullPointerException(MessageFactory + .get("error.value.expectedType")); + } + ExpressionBuilder builder = new ExpressionBuilder(expression, context); + return builder.createValueExpression(expectedType); + } + + public ValueExpression createValueExpression(Object instance, + Class expectedType) { + if (expectedType == null) { + throw new NullPointerException(MessageFactory + .get("error.value.expectedType")); + } + return new ValueExpressionLiteral(instance, expectedType); + } +} diff --git a/java/org/apache/el/Messages.properties b/java/org/apache/el/Messages.properties index b4fce603b..d5890204e 100644 --- a/java/org/apache/el/Messages.properties +++ b/java/org/apache/el/Messages.properties @@ -1,48 +1,48 @@ -# General Errors -error.convert=Cannot convert {0} of type {1} to {2} -error.compare=Cannot compare {0} to {1} -error.function=Problems calling function ''{0}'' -error.unreachable.base=Target Unreachable, identifier ''{0}'' resolved to null -error.unreachable.property=Target Unreachable, ''{0}'' returned null -error.resolver.unhandled=ELResolver did not handle type: {0} with property of ''{1}'' -error.resolver.unhandled.null=ELResolver cannot handle a null base Object with identifier ''{0}'' - -# ValueExpressionLiteral -error.value.literal.write=ValueExpression is a literal and not writable: {0} - -# ExpressionFactoryImpl -error.null=Expression cannot be null -error.mixed=Expression cannot contain both '#{..}' and '${..}' : {0} -error.method=Not a valid MethodExpression : {0} -error.method.nullParms=Parameter types cannot be null -error.value.expectedType=Expected type cannot be null - -# ExpressionMediator -error.eval=Error Evaluating {0} : {1} - -# ValueSetVisitor -error.syntax.set=Illegal Syntax for Set Operation - -# ReflectionUtil -error.method.notfound=Method not found: {0}.{1}({2}) -error.property.notfound=Property ''{1}'' not found on {0} - -# ValidatingVisitor -error.fnMapper.null=Expression uses functions, but no FunctionMapper was provided -error.fnMapper.method=Function ''{0}'' not found -error.fnMapper.paramcount=Function ''{0}'' specifies {1} params, but {2} were declared - -# **ExpressionImpl -error.context.null=ELContext was null - -# ArrayELResolver -error.array.outofbounds=Index {0} is out of bounds for array of size {1} - -# ListELResolver -error.list.outofbounds=Index {0} is out of bounds for list of size {1} - -# BeanELResolver -error.property.notfound=Property ''{1}'' not found on type: {0} -error.property.invocation=Property ''{1}'' threw an exception from type: {0} -error.property.notreadable=Property ''{1}'' doesn't have a 'get' specified on type: {0} +# General Errors +error.convert=Cannot convert {0} of type {1} to {2} +error.compare=Cannot compare {0} to {1} +error.function=Problems calling function ''{0}'' +error.unreachable.base=Target Unreachable, identifier ''{0}'' resolved to null +error.unreachable.property=Target Unreachable, ''{0}'' returned null +error.resolver.unhandled=ELResolver did not handle type: {0} with property of ''{1}'' +error.resolver.unhandled.null=ELResolver cannot handle a null base Object with identifier ''{0}'' + +# ValueExpressionLiteral +error.value.literal.write=ValueExpression is a literal and not writable: {0} + +# ExpressionFactoryImpl +error.null=Expression cannot be null +error.mixed=Expression cannot contain both '#{..}' and '${..}' : {0} +error.method=Not a valid MethodExpression : {0} +error.method.nullParms=Parameter types cannot be null +error.value.expectedType=Expected type cannot be null + +# ExpressionMediator +error.eval=Error Evaluating {0} : {1} + +# ValueSetVisitor +error.syntax.set=Illegal Syntax for Set Operation + +# ReflectionUtil +error.method.notfound=Method not found: {0}.{1}({2}) +error.property.notfound=Property ''{1}'' not found on {0} + +# ValidatingVisitor +error.fnMapper.null=Expression uses functions, but no FunctionMapper was provided +error.fnMapper.method=Function ''{0}'' not found +error.fnMapper.paramcount=Function ''{0}'' specifies {1} params, but {2} were declared + +# **ExpressionImpl +error.context.null=ELContext was null + +# ArrayELResolver +error.array.outofbounds=Index {0} is out of bounds for array of size {1} + +# ListELResolver +error.list.outofbounds=Index {0} is out of bounds for list of size {1} + +# BeanELResolver +error.property.notfound=Property ''{1}'' not found on type: {0} +error.property.invocation=Property ''{1}'' threw an exception from type: {0} +error.property.notreadable=Property ''{1}'' doesn't have a 'get' specified on type: {0} error.property.notwritable=Property ''{1}'' doesn't have a 'set' specified on type: {0} \ No newline at end of file diff --git a/java/org/apache/el/MethodExpressionImpl.java b/java/org/apache/el/MethodExpressionImpl.java index e3bd3cdbf..bb7eadf5c 100644 --- a/java/org/apache/el/MethodExpressionImpl.java +++ b/java/org/apache/el/MethodExpressionImpl.java @@ -1,314 +1,314 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.Expression; -import javax.el.ExpressionFactory; -import javax.el.FunctionMapper; -import javax.el.MethodExpression; -import javax.el.MethodInfo; -import javax.el.MethodNotFoundException; -import javax.el.PropertyNotFoundException; -import javax.el.VariableMapper; - -import org.apache.el.lang.ELSupport; -import org.apache.el.lang.EvaluationContext; -import org.apache.el.lang.ExpressionBuilder; -import org.apache.el.parser.Node; -import org.apache.el.util.ReflectionUtil; - - -/** - * An Expression that refers to a method on an object. - * - *

        - * The {@link ExpressionFactory#createMethodExpression} method - * can be used to parse an expression string and return a concrete instance - * of MethodExpression that encapsulates the parsed expression. - * The {@link FunctionMapper} is used at parse time, not evaluation time, - * so one is not needed to evaluate an expression using this class. - * However, the {@link ELContext} is needed at evaluation time.

        - * - *

        The {@link #getMethodInfo} and {@link #invoke} methods will evaluate the - * expression each time they are called. The {@link ELResolver} in the - * ELContext is used to resolve the top-level variables and to - * determine the behavior of the . and [] - * operators. For any of the two methods, the {@link ELResolver#getValue} - * method is used to resolve all properties up to but excluding the last - * one. This provides the base object on which the method - * appears. If the base object is null, a - * NullPointerException must be thrown. At the last resolution, - * the final property is then coerced to a String, - * which provides the name of the method to be found. A method matching the - * name and expected parameters provided at parse time is found and it is - * either queried or invoked (depending on the method called on this - * MethodExpression).

        - * - *

        See the notes about comparison, serialization and immutability in - * the {@link Expression} javadocs. - * - * @see javax.el.ELResolver - * @see javax.el.Expression - * @see javax.el.ExpressionFactory - * @see javax.el.MethodExpression - * - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public final class MethodExpressionImpl extends MethodExpression implements - Externalizable { - - private Class expectedType; - - private String expr; - - private FunctionMapper fnMapper; - - private VariableMapper varMapper; - - private transient Node node; - - private Class[] paramTypes; - - /** - * - */ - public MethodExpressionImpl() { - super(); - } - - /** - * @param expr - * @param node - * @param fnMapper - * @param expectedType - * @param paramTypes - */ - public MethodExpressionImpl(String expr, Node node, - FunctionMapper fnMapper, VariableMapper varMapper, - Class expectedType, Class[] paramTypes) { - super(); - this.expr = expr; - this.node = node; - this.fnMapper = fnMapper; - this.varMapper = varMapper; - this.expectedType = expectedType; - this.paramTypes = paramTypes; - } - - /** - * Determines whether the specified object is equal to this - * Expression. - * - *

        - * The result is true if and only if the argument is not - * null, is an Expression object that is the - * of the same type (ValueExpression or - * MethodExpression), and has an identical parsed - * representation. - *

        - * - *

        - * Note that two expressions can be equal if their expression Strings are - * different. For example, ${fn1:foo()} and - * ${fn2:foo()} are equal if their corresponding - * FunctionMappers mapped fn1:foo and - * fn2:foo to the same method. - *

        - * - * @param obj - * the Object to test for equality. - * @return true if obj equals this - * Expression; false otherwise. - * @see java.util.Hashtable - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object obj) { - return (obj instanceof MethodExpressionImpl && obj.hashCode() == this - .hashCode()); - } - - /** - * Returns the original String used to create this Expression, - * unmodified. - * - *

        - * This is used for debugging purposes but also for the purposes of - * comparison (e.g. to ensure the expression in a configuration file has not - * changed). - *

        - * - *

        - * This method does not provide sufficient information to re-create an - * expression. Two different expressions can have exactly the same - * expression string but different function mappings. Serialization should - * be used to save and restore the state of an Expression. - *

        - * - * @return The original expression String. - * - * @see javax.el.Expression#getExpressionString() - */ - public String getExpressionString() { - return this.expr; - } - - /** - * Evaluates the expression relative to the provided context, and returns - * information about the actual referenced method. - * - * @param context - * The context of this evaluation - * @return an instance of MethodInfo containing information - * about the method the expression evaluated to. - * @throws NullPointerException - * if context is null or the base object is - * null on the last resolution. - * @throws PropertyNotFoundException - * if one of the property resolutions failed because a specified - * variable or property does not exist or is not readable. - * @throws MethodNotFoundException - * if no suitable method can be found. - * @throws ELException - * if an exception was thrown while performing property or - * variable resolution. The thrown exception must be included as - * the cause property of this exception, if available. - * @see javax.el.MethodExpression#getMethodInfo(javax.el.ELContext) - */ - public MethodInfo getMethodInfo(ELContext context) - throws PropertyNotFoundException, MethodNotFoundException, - ELException { - Node n = this.getNode(); - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - return n.getMethodInfo(ctx, this.paramTypes); - } - - /** - * @return - * @throws ELException - */ - private Node getNode() throws ELException { - if (this.node == null) { - this.node = ExpressionBuilder.createNode(this.expr); - } - return this.node; - } - - /** - * Returns the hash code for this Expression. - * - *

        - * See the note in the {@link #equals} method on how two expressions can be - * equal if their expression Strings are different. Recall that if two - * objects are equal according to the equals(Object) method, - * then calling the hashCode method on each of the two - * objects must produce the same integer result. Implementations must take - * special note and implement hashCode correctly. - *

        - * - * @return The hash code for this Expression. - * @see #equals - * @see java.util.Hashtable - * @see java.lang.Object#hashCode() - */ - public int hashCode() { - return this.expr.hashCode(); - } - - /** - * Evaluates the expression relative to the provided context, invokes the - * method that was found using the supplied parameters, and returns the - * result of the method invocation. - * - * @param context - * The context of this evaluation. - * @param params - * The parameters to pass to the method, or null - * if no parameters. - * @return the result of the method invocation (null if the - * method has a void return type). - * @throws NullPointerException - * if context is null or the base object is - * null on the last resolution. - * @throws PropertyNotFoundException - * if one of the property resolutions failed because a specified - * variable or property does not exist or is not readable. - * @throws MethodNotFoundException - * if no suitable method can be found. - * @throws ELException - * if an exception was thrown while performing property or - * variable resolution. The thrown exception must be included as - * the cause property of this exception, if available. If the - * exception thrown is an InvocationTargetException, - * extract its cause and pass it to the - * ELException constructor. - * @see javax.el.MethodExpression#invoke(javax.el.ELContext, - * java.lang.Object[]) - */ - public Object invoke(ELContext context, Object[] params) - throws PropertyNotFoundException, MethodNotFoundException, - ELException { - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - return this.getNode().invoke(ctx, this.paramTypes, params); - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#readExternal(java.io.ObjectInput) - */ - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.expr = in.readUTF(); - String type = in.readUTF(); - if (!"".equals(type)) { - this.expectedType = ReflectionUtil.forName(type); - } - this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in - .readObject())); - this.fnMapper = (FunctionMapper) in.readObject(); - this.varMapper = (VariableMapper) in.readObject(); - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) - */ - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(this.expr); - out.writeUTF((this.expectedType != null) ? this.expectedType.getName() - : ""); - out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); - out.writeObject(this.fnMapper); - out.writeObject(this.varMapper); - } - - public boolean isLiteralText() { - return false; - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.Expression; +import javax.el.ExpressionFactory; +import javax.el.FunctionMapper; +import javax.el.MethodExpression; +import javax.el.MethodInfo; +import javax.el.MethodNotFoundException; +import javax.el.PropertyNotFoundException; +import javax.el.VariableMapper; + +import org.apache.el.lang.ELSupport; +import org.apache.el.lang.EvaluationContext; +import org.apache.el.lang.ExpressionBuilder; +import org.apache.el.parser.Node; +import org.apache.el.util.ReflectionUtil; + + +/** + * An Expression that refers to a method on an object. + * + *

        + * The {@link ExpressionFactory#createMethodExpression} method + * can be used to parse an expression string and return a concrete instance + * of MethodExpression that encapsulates the parsed expression. + * The {@link FunctionMapper} is used at parse time, not evaluation time, + * so one is not needed to evaluate an expression using this class. + * However, the {@link ELContext} is needed at evaluation time.

        + * + *

        The {@link #getMethodInfo} and {@link #invoke} methods will evaluate the + * expression each time they are called. The {@link ELResolver} in the + * ELContext is used to resolve the top-level variables and to + * determine the behavior of the . and [] + * operators. For any of the two methods, the {@link ELResolver#getValue} + * method is used to resolve all properties up to but excluding the last + * one. This provides the base object on which the method + * appears. If the base object is null, a + * NullPointerException must be thrown. At the last resolution, + * the final property is then coerced to a String, + * which provides the name of the method to be found. A method matching the + * name and expected parameters provided at parse time is found and it is + * either queried or invoked (depending on the method called on this + * MethodExpression).

        + * + *

        See the notes about comparison, serialization and immutability in + * the {@link Expression} javadocs. + * + * @see javax.el.ELResolver + * @see javax.el.Expression + * @see javax.el.ExpressionFactory + * @see javax.el.MethodExpression + * + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public final class MethodExpressionImpl extends MethodExpression implements + Externalizable { + + private Class expectedType; + + private String expr; + + private FunctionMapper fnMapper; + + private VariableMapper varMapper; + + private transient Node node; + + private Class[] paramTypes; + + /** + * + */ + public MethodExpressionImpl() { + super(); + } + + /** + * @param expr + * @param node + * @param fnMapper + * @param expectedType + * @param paramTypes + */ + public MethodExpressionImpl(String expr, Node node, + FunctionMapper fnMapper, VariableMapper varMapper, + Class expectedType, Class[] paramTypes) { + super(); + this.expr = expr; + this.node = node; + this.fnMapper = fnMapper; + this.varMapper = varMapper; + this.expectedType = expectedType; + this.paramTypes = paramTypes; + } + + /** + * Determines whether the specified object is equal to this + * Expression. + * + *

        + * The result is true if and only if the argument is not + * null, is an Expression object that is the + * of the same type (ValueExpression or + * MethodExpression), and has an identical parsed + * representation. + *

        + * + *

        + * Note that two expressions can be equal if their expression Strings are + * different. For example, ${fn1:foo()} and + * ${fn2:foo()} are equal if their corresponding + * FunctionMappers mapped fn1:foo and + * fn2:foo to the same method. + *

        + * + * @param obj + * the Object to test for equality. + * @return true if obj equals this + * Expression; false otherwise. + * @see java.util.Hashtable + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + return (obj instanceof MethodExpressionImpl && obj.hashCode() == this + .hashCode()); + } + + /** + * Returns the original String used to create this Expression, + * unmodified. + * + *

        + * This is used for debugging purposes but also for the purposes of + * comparison (e.g. to ensure the expression in a configuration file has not + * changed). + *

        + * + *

        + * This method does not provide sufficient information to re-create an + * expression. Two different expressions can have exactly the same + * expression string but different function mappings. Serialization should + * be used to save and restore the state of an Expression. + *

        + * + * @return The original expression String. + * + * @see javax.el.Expression#getExpressionString() + */ + public String getExpressionString() { + return this.expr; + } + + /** + * Evaluates the expression relative to the provided context, and returns + * information about the actual referenced method. + * + * @param context + * The context of this evaluation + * @return an instance of MethodInfo containing information + * about the method the expression evaluated to. + * @throws NullPointerException + * if context is null or the base object is + * null on the last resolution. + * @throws PropertyNotFoundException + * if one of the property resolutions failed because a specified + * variable or property does not exist or is not readable. + * @throws MethodNotFoundException + * if no suitable method can be found. + * @throws ELException + * if an exception was thrown while performing property or + * variable resolution. The thrown exception must be included as + * the cause property of this exception, if available. + * @see javax.el.MethodExpression#getMethodInfo(javax.el.ELContext) + */ + public MethodInfo getMethodInfo(ELContext context) + throws PropertyNotFoundException, MethodNotFoundException, + ELException { + Node n = this.getNode(); + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + return n.getMethodInfo(ctx, this.paramTypes); + } + + /** + * @return + * @throws ELException + */ + private Node getNode() throws ELException { + if (this.node == null) { + this.node = ExpressionBuilder.createNode(this.expr); + } + return this.node; + } + + /** + * Returns the hash code for this Expression. + * + *

        + * See the note in the {@link #equals} method on how two expressions can be + * equal if their expression Strings are different. Recall that if two + * objects are equal according to the equals(Object) method, + * then calling the hashCode method on each of the two + * objects must produce the same integer result. Implementations must take + * special note and implement hashCode correctly. + *

        + * + * @return The hash code for this Expression. + * @see #equals + * @see java.util.Hashtable + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return this.expr.hashCode(); + } + + /** + * Evaluates the expression relative to the provided context, invokes the + * method that was found using the supplied parameters, and returns the + * result of the method invocation. + * + * @param context + * The context of this evaluation. + * @param params + * The parameters to pass to the method, or null + * if no parameters. + * @return the result of the method invocation (null if the + * method has a void return type). + * @throws NullPointerException + * if context is null or the base object is + * null on the last resolution. + * @throws PropertyNotFoundException + * if one of the property resolutions failed because a specified + * variable or property does not exist or is not readable. + * @throws MethodNotFoundException + * if no suitable method can be found. + * @throws ELException + * if an exception was thrown while performing property or + * variable resolution. The thrown exception must be included as + * the cause property of this exception, if available. If the + * exception thrown is an InvocationTargetException, + * extract its cause and pass it to the + * ELException constructor. + * @see javax.el.MethodExpression#invoke(javax.el.ELContext, + * java.lang.Object[]) + */ + public Object invoke(ELContext context, Object[] params) + throws PropertyNotFoundException, MethodNotFoundException, + ELException { + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + return this.getNode().invoke(ctx, this.paramTypes, params); + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#readExternal(java.io.ObjectInput) + */ + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.expr = in.readUTF(); + String type = in.readUTF(); + if (!"".equals(type)) { + this.expectedType = ReflectionUtil.forName(type); + } + this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in + .readObject())); + this.fnMapper = (FunctionMapper) in.readObject(); + this.varMapper = (VariableMapper) in.readObject(); + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) + */ + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(this.expr); + out.writeUTF((this.expectedType != null) ? this.expectedType.getName() + : ""); + out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); + out.writeObject(this.fnMapper); + out.writeObject(this.varMapper); + } + + public boolean isLiteralText() { + return false; + } +} diff --git a/java/org/apache/el/MethodExpressionLiteral.java b/java/org/apache/el/MethodExpressionLiteral.java index 0d55bb9cc..5cdafad49 100644 --- a/java/org/apache/el/MethodExpressionLiteral.java +++ b/java/org/apache/el/MethodExpressionLiteral.java @@ -1,95 +1,95 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.MethodExpression; -import javax.el.MethodInfo; - -import org.apache.el.lang.ELSupport; -import org.apache.el.util.ReflectionUtil; - - -public class MethodExpressionLiteral extends MethodExpression implements Externalizable { - - private Class expectedType; - - private String expr; - - private Class[] paramTypes; - - public MethodExpressionLiteral() { - // do nothing - } - - public MethodExpressionLiteral(String expr, Class expectedType, Class[] paramTypes) { - this.expr = expr; - this.expectedType = expectedType; - this.paramTypes = paramTypes; - } - - public MethodInfo getMethodInfo(ELContext context) throws ELException { - return new MethodInfo(this.expr, this.expectedType, this.paramTypes); - } - - public Object invoke(ELContext context, Object[] params) throws ELException { - if (this.expectedType != null) { - return ELSupport.coerceToType(this.expr, this.expectedType); - } else { - return this.expr; - } - } - - public String getExpressionString() { - return this.expr; - } - - public boolean equals(Object obj) { - return (obj instanceof MethodExpressionLiteral && this.hashCode() == obj.hashCode()); - } - - public int hashCode() { - return this.expr.hashCode(); - } - - public boolean isLiteralText() { - return true; - } - - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - this.expr = in.readUTF(); - String type = in.readUTF(); - if (!"".equals(type)) { - this.expectedType = ReflectionUtil.forName(type); - } - this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in - .readObject())); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(this.expr); - out.writeUTF((this.expectedType != null) ? this.expectedType.getName() - : ""); - out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.MethodExpression; +import javax.el.MethodInfo; + +import org.apache.el.lang.ELSupport; +import org.apache.el.util.ReflectionUtil; + + +public class MethodExpressionLiteral extends MethodExpression implements Externalizable { + + private Class expectedType; + + private String expr; + + private Class[] paramTypes; + + public MethodExpressionLiteral() { + // do nothing + } + + public MethodExpressionLiteral(String expr, Class expectedType, Class[] paramTypes) { + this.expr = expr; + this.expectedType = expectedType; + this.paramTypes = paramTypes; + } + + public MethodInfo getMethodInfo(ELContext context) throws ELException { + return new MethodInfo(this.expr, this.expectedType, this.paramTypes); + } + + public Object invoke(ELContext context, Object[] params) throws ELException { + if (this.expectedType != null) { + return ELSupport.coerceToType(this.expr, this.expectedType); + } else { + return this.expr; + } + } + + public String getExpressionString() { + return this.expr; + } + + public boolean equals(Object obj) { + return (obj instanceof MethodExpressionLiteral && this.hashCode() == obj.hashCode()); + } + + public int hashCode() { + return this.expr.hashCode(); + } + + public boolean isLiteralText() { + return true; + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.expr = in.readUTF(); + String type = in.readUTF(); + if (!"".equals(type)) { + this.expectedType = ReflectionUtil.forName(type); + } + this.paramTypes = ReflectionUtil.toTypeArray(((String[]) in + .readObject())); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(this.expr); + out.writeUTF((this.expectedType != null) ? this.expectedType.getName() + : ""); + out.writeObject(ReflectionUtil.toTypeNameArray(this.paramTypes)); + } +} diff --git a/java/org/apache/el/ValueExpressionImpl.java b/java/org/apache/el/ValueExpressionImpl.java index c8cdcbee8..807e4e0da 100644 --- a/java/org/apache/el/ValueExpressionImpl.java +++ b/java/org/apache/el/ValueExpressionImpl.java @@ -1,262 +1,262 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.Expression; -import javax.el.ExpressionFactory; -import javax.el.FunctionMapper; -import javax.el.PropertyNotFoundException; -import javax.el.PropertyNotWritableException; -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -import org.apache.el.lang.ELSupport; -import org.apache.el.lang.EvaluationContext; -import org.apache.el.lang.ExpressionBuilder; -import org.apache.el.parser.AstLiteralExpression; -import org.apache.el.parser.Node; -import org.apache.el.util.ReflectionUtil; - - -/** - * An Expression that can get or set a value. - * - *

        - * In previous incarnations of this API, expressions could only be read. - * ValueExpression objects can now be used both to retrieve a - * value and to set a value. Expressions that can have a value set on them are - * referred to as l-value expressions. Those that cannot are referred to as - * r-value expressions. Not all r-value expressions can be used as l-value - * expressions (e.g. "${1+1}" or - * "${firstName} ${lastName}"). See the EL Specification for - * details. Expressions that cannot be used as l-values must always return - * true from isReadOnly(). - *

        - * - *

        - * The {@link ExpressionFactory#createValueExpression} method - * can be used to parse an expression string and return a concrete instance - * of ValueExpression that encapsulates the parsed expression. - * The {@link FunctionMapper} is used at parse time, not evaluation time, - * so one is not needed to evaluate an expression using this class. - * However, the {@link ELContext} is needed at evaluation time.

        - * - *

        The {@link #getValue}, {@link #setValue}, {@link #isReadOnly} and - * {@link #getType} methods will evaluate the expression each time they are - * called. The {@link ELResolver} in the ELContext is used to - * resolve the top-level variables and to determine the behavior of the - * . and [] operators. For any of the four methods, - * the {@link ELResolver#getValue} method is used to resolve all properties - * up to but excluding the last one. This provides the base - * object. At the last resolution, the ValueExpression will - * call the corresponding {@link ELResolver#getValue}, - * {@link ELResolver#setValue}, {@link ELResolver#isReadOnly} or - * {@link ELResolver#getType} method, depending on which was called on - * the ValueExpression. - *

        - * - *

        See the notes about comparison, serialization and immutability in - * the {@link Expression} javadocs. - * - * @see javax.el.ELResolver - * @see javax.el.Expression - * @see javax.el.ExpressionFactory - * @see javax.el.ValueExpression - * - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class ValueExpressionImpl extends ValueExpression implements - Externalizable { - - private Class expectedType; - - private String expr; - - private FunctionMapper fnMapper; - - private VariableMapper varMapper; - - private transient Node node; - - public ValueExpressionImpl() { - - } - - /** - * - */ - public ValueExpressionImpl(String expr, Node node, FunctionMapper fnMapper, - VariableMapper varMapper, Class expectedType) { - this.expr = expr; - this.node = node; - this.fnMapper = fnMapper; - this.varMapper = varMapper; - this.expectedType = expectedType; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object obj) { - return (obj instanceof ValueExpressionImpl && obj.hashCode() == this - .hashCode()); - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#getExpectedType() - */ - public Class getExpectedType() { - return this.expectedType; - } - - /** - * Returns the type the result of the expression will be coerced to after - * evaluation. - * - * @return the expectedType passed to the - * ExpressionFactory.createValueExpression method - * that created this ValueExpression. - * - * @see javax.el.Expression#getExpressionString() - */ - public String getExpressionString() { - return this.expr; - } - - /** - * @return - * @throws ELException - */ - private Node getNode() throws ELException { - if (this.node == null) { - this.node = ExpressionBuilder.createNode(this.expr); - } - return this.node; - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#getType(javax.el.ELContext) - */ - public Class getType(ELContext context) throws PropertyNotFoundException, - ELException { - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - return this.getNode().getType(ctx); - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#getValue(javax.el.ELContext) - */ - public Object getValue(ELContext context) throws PropertyNotFoundException, - ELException { - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - Object value = this.getNode().getValue(ctx); - if (this.expectedType != null) { - return ELSupport.coerceToType(value, this.expectedType); - } - return value; - } - - /* - * (non-Javadoc) - * - * @see java.lang.Object#hashCode() - */ - public int hashCode() { - return this.expr.hashCode(); - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#isLiteralText() - */ - public boolean isLiteralText() { - try { - return this.getNode() instanceof AstLiteralExpression; - } catch (ELException ele) { - return false; - } - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#isReadOnly(javax.el.ELContext) - */ - public boolean isReadOnly(ELContext context) - throws PropertyNotFoundException, ELException { - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - return this.getNode().isReadOnly(ctx); - } - - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.expr = in.readUTF(); - String type = in.readUTF(); - if (!"".equals(type)) { - this.expectedType = ReflectionUtil.forName(type); - } - this.fnMapper = (FunctionMapper) in.readObject(); - this.varMapper = (VariableMapper) in.readObject(); - } - - /* - * (non-Javadoc) - * - * @see javax.el.ValueExpression#setValue(javax.el.ELContext, - * java.lang.Object) - */ - public void setValue(ELContext context, Object value) - throws PropertyNotFoundException, PropertyNotWritableException, - ELException { - EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, - this.varMapper); - this.getNode().setValue(ctx, value); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(this.expr); - out.writeUTF((this.expectedType != null) ? this.expectedType.getName() - : ""); - out.writeObject(this.fnMapper); - out.writeObject(this.varMapper); - } - - public String toString() { - return "ValueExpression["+this.expr+"]"; - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.Expression; +import javax.el.ExpressionFactory; +import javax.el.FunctionMapper; +import javax.el.PropertyNotFoundException; +import javax.el.PropertyNotWritableException; +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +import org.apache.el.lang.ELSupport; +import org.apache.el.lang.EvaluationContext; +import org.apache.el.lang.ExpressionBuilder; +import org.apache.el.parser.AstLiteralExpression; +import org.apache.el.parser.Node; +import org.apache.el.util.ReflectionUtil; + + +/** + * An Expression that can get or set a value. + * + *

        + * In previous incarnations of this API, expressions could only be read. + * ValueExpression objects can now be used both to retrieve a + * value and to set a value. Expressions that can have a value set on them are + * referred to as l-value expressions. Those that cannot are referred to as + * r-value expressions. Not all r-value expressions can be used as l-value + * expressions (e.g. "${1+1}" or + * "${firstName} ${lastName}"). See the EL Specification for + * details. Expressions that cannot be used as l-values must always return + * true from isReadOnly(). + *

        + * + *

        + * The {@link ExpressionFactory#createValueExpression} method + * can be used to parse an expression string and return a concrete instance + * of ValueExpression that encapsulates the parsed expression. + * The {@link FunctionMapper} is used at parse time, not evaluation time, + * so one is not needed to evaluate an expression using this class. + * However, the {@link ELContext} is needed at evaluation time.

        + * + *

        The {@link #getValue}, {@link #setValue}, {@link #isReadOnly} and + * {@link #getType} methods will evaluate the expression each time they are + * called. The {@link ELResolver} in the ELContext is used to + * resolve the top-level variables and to determine the behavior of the + * . and [] operators. For any of the four methods, + * the {@link ELResolver#getValue} method is used to resolve all properties + * up to but excluding the last one. This provides the base + * object. At the last resolution, the ValueExpression will + * call the corresponding {@link ELResolver#getValue}, + * {@link ELResolver#setValue}, {@link ELResolver#isReadOnly} or + * {@link ELResolver#getType} method, depending on which was called on + * the ValueExpression. + *

        + * + *

        See the notes about comparison, serialization and immutability in + * the {@link Expression} javadocs. + * + * @see javax.el.ELResolver + * @see javax.el.Expression + * @see javax.el.ExpressionFactory + * @see javax.el.ValueExpression + * + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class ValueExpressionImpl extends ValueExpression implements + Externalizable { + + private Class expectedType; + + private String expr; + + private FunctionMapper fnMapper; + + private VariableMapper varMapper; + + private transient Node node; + + public ValueExpressionImpl() { + + } + + /** + * + */ + public ValueExpressionImpl(String expr, Node node, FunctionMapper fnMapper, + VariableMapper varMapper, Class expectedType) { + this.expr = expr; + this.node = node; + this.fnMapper = fnMapper; + this.varMapper = varMapper; + this.expectedType = expectedType; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + return (obj instanceof ValueExpressionImpl && obj.hashCode() == this + .hashCode()); + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#getExpectedType() + */ + public Class getExpectedType() { + return this.expectedType; + } + + /** + * Returns the type the result of the expression will be coerced to after + * evaluation. + * + * @return the expectedType passed to the + * ExpressionFactory.createValueExpression method + * that created this ValueExpression. + * + * @see javax.el.Expression#getExpressionString() + */ + public String getExpressionString() { + return this.expr; + } + + /** + * @return + * @throws ELException + */ + private Node getNode() throws ELException { + if (this.node == null) { + this.node = ExpressionBuilder.createNode(this.expr); + } + return this.node; + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#getType(javax.el.ELContext) + */ + public Class getType(ELContext context) throws PropertyNotFoundException, + ELException { + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + return this.getNode().getType(ctx); + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#getValue(javax.el.ELContext) + */ + public Object getValue(ELContext context) throws PropertyNotFoundException, + ELException { + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + Object value = this.getNode().getValue(ctx); + if (this.expectedType != null) { + return ELSupport.coerceToType(value, this.expectedType); + } + return value; + } + + /* + * (non-Javadoc) + * + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return this.expr.hashCode(); + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#isLiteralText() + */ + public boolean isLiteralText() { + try { + return this.getNode() instanceof AstLiteralExpression; + } catch (ELException ele) { + return false; + } + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#isReadOnly(javax.el.ELContext) + */ + public boolean isReadOnly(ELContext context) + throws PropertyNotFoundException, ELException { + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + return this.getNode().isReadOnly(ctx); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.expr = in.readUTF(); + String type = in.readUTF(); + if (!"".equals(type)) { + this.expectedType = ReflectionUtil.forName(type); + } + this.fnMapper = (FunctionMapper) in.readObject(); + this.varMapper = (VariableMapper) in.readObject(); + } + + /* + * (non-Javadoc) + * + * @see javax.el.ValueExpression#setValue(javax.el.ELContext, + * java.lang.Object) + */ + public void setValue(ELContext context, Object value) + throws PropertyNotFoundException, PropertyNotWritableException, + ELException { + EvaluationContext ctx = new EvaluationContext(context, this.fnMapper, + this.varMapper); + this.getNode().setValue(ctx, value); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(this.expr); + out.writeUTF((this.expectedType != null) ? this.expectedType.getName() + : ""); + out.writeObject(this.fnMapper); + out.writeObject(this.varMapper); + } + + public String toString() { + return "ValueExpression["+this.expr+"]"; + } +} diff --git a/java/org/apache/el/ValueExpressionLiteral.java b/java/org/apache/el/ValueExpressionLiteral.java index e850632f6..1557e4338 100644 --- a/java/org/apache/el/ValueExpressionLiteral.java +++ b/java/org/apache/el/ValueExpressionLiteral.java @@ -1,112 +1,112 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el; - -import java.io.Externalizable; -import java.io.IOException; -import javax.el.ELContext; -import javax.el.PropertyNotWritableException; - -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ValueExpression; - -import org.apache.el.lang.ELSupport; -import org.apache.el.util.MessageFactory; -import org.apache.el.util.ReflectionUtil; - - -public final class ValueExpressionLiteral extends ValueExpression implements - Externalizable { - - private static final long serialVersionUID = 1L; - - private Object value; - - private Class expectedType; - - public ValueExpressionLiteral() { - super(); - } - - public ValueExpressionLiteral(Object value, Class expectedType) { - this.value = value; - this.expectedType = expectedType; - } - - public Object getValue(ELContext context) { - if (this.expectedType != null) { - return ELSupport.coerceToType(this.value, this.expectedType); - } - return this.value; - } - - public void setValue(ELContext context, Object value) { - throw new PropertyNotWritableException(MessageFactory.get( - "error.value.literal.write", this.value)); - } - - public boolean isReadOnly(ELContext context) { - return true; - } - - public Class getType(ELContext context) { - return (this.value != null) ? this.value.getClass() : null; - } - - public Class getExpectedType() { - return this.expectedType; - } - - public String getExpressionString() { - return (this.value != null) ? this.value.toString() : null; - } - - public boolean equals(Object obj) { - return (obj instanceof ValueExpressionLiteral && this - .equals((ValueExpressionLiteral) obj)); - } - - public boolean equals(ValueExpressionLiteral ve) { - return (ve != null && (this.value != null && ve.value != null && (this.value == ve.value || this.value - .equals(ve.value)))); - } - - public int hashCode() { - return (this.value != null) ? this.value.hashCode() : 0; - } - - public boolean isLiteralText() { - return true; - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeObject(this.value); - out.writeUTF((this.expectedType != null) ? this.expectedType.getName() - : ""); - } - - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.value = in.readObject(); - String type = in.readUTF(); - if (!"".equals(type)) { - this.expectedType = ReflectionUtil.forName(type); - } - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el; + +import java.io.Externalizable; +import java.io.IOException; +import javax.el.ELContext; +import javax.el.PropertyNotWritableException; + +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ValueExpression; + +import org.apache.el.lang.ELSupport; +import org.apache.el.util.MessageFactory; +import org.apache.el.util.ReflectionUtil; + + +public final class ValueExpressionLiteral extends ValueExpression implements + Externalizable { + + private static final long serialVersionUID = 1L; + + private Object value; + + private Class expectedType; + + public ValueExpressionLiteral() { + super(); + } + + public ValueExpressionLiteral(Object value, Class expectedType) { + this.value = value; + this.expectedType = expectedType; + } + + public Object getValue(ELContext context) { + if (this.expectedType != null) { + return ELSupport.coerceToType(this.value, this.expectedType); + } + return this.value; + } + + public void setValue(ELContext context, Object value) { + throw new PropertyNotWritableException(MessageFactory.get( + "error.value.literal.write", this.value)); + } + + public boolean isReadOnly(ELContext context) { + return true; + } + + public Class getType(ELContext context) { + return (this.value != null) ? this.value.getClass() : null; + } + + public Class getExpectedType() { + return this.expectedType; + } + + public String getExpressionString() { + return (this.value != null) ? this.value.toString() : null; + } + + public boolean equals(Object obj) { + return (obj instanceof ValueExpressionLiteral && this + .equals((ValueExpressionLiteral) obj)); + } + + public boolean equals(ValueExpressionLiteral ve) { + return (ve != null && (this.value != null && ve.value != null && (this.value == ve.value || this.value + .equals(ve.value)))); + } + + public int hashCode() { + return (this.value != null) ? this.value.hashCode() : 0; + } + + public boolean isLiteralText() { + return true; + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(this.value); + out.writeUTF((this.expectedType != null) ? this.expectedType.getName() + : ""); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.value = in.readObject(); + String type = in.readUTF(); + if (!"".equals(type)) { + this.expectedType = ReflectionUtil.forName(type); + } + } +} diff --git a/java/org/apache/el/lang/ELArithmetic.java b/java/org/apache/el/lang/ELArithmetic.java index 179b01e79..94ceaddb8 100644 --- a/java/org/apache/el/lang/ELArithmetic.java +++ b/java/org/apache/el/lang/ELArithmetic.java @@ -1,376 +1,376 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import org.apache.el.util.MessageFactory; - - -/** - * A helper class of Arithmetic defined by the EL Specification - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public abstract class ELArithmetic { - - public final static class BigDecimalDelegate extends ELArithmetic { - - protected Number add(Number num0, Number num1) { - return ((BigDecimal) num0).add((BigDecimal) num1); - } - - protected Number coerce(Number num) { - if (num instanceof BigDecimal) - return num; - if (num instanceof BigInteger) - return new BigDecimal((BigInteger) num); - return new BigDecimal(num.doubleValue()); - } - - protected Number coerce(String str) { - return new BigDecimal(str); - } - - protected Number divide(Number num0, Number num1) { - return ((BigDecimal) num0).divide((BigDecimal) num1, - BigDecimal.ROUND_HALF_UP); - } - - protected Number subtract(Number num0, Number num1) { - return ((BigDecimal) num0).subtract((BigDecimal) num1); - } - - protected Number mod(Number num0, Number num1) { - return new Double(num0.doubleValue() % num1.doubleValue()); - } - - protected Number multiply(Number num0, Number num1) { - return ((BigDecimal) num0).multiply((BigDecimal) num1); - } - - public boolean matches(Object obj0, Object obj1) { - return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); - } - } - - public final static class BigIntegerDelegate extends ELArithmetic { - - protected Number add(Number num0, Number num1) { - return ((BigInteger) num0).add((BigInteger) num1); - } - - protected Number coerce(Number num) { - if (num instanceof BigInteger) - return num; - return new BigInteger(num.toString()); - } - - protected Number coerce(String str) { - return new BigInteger(str); - } - - protected Number divide(Number num0, Number num1) { - return (new BigDecimal((BigInteger) num0)).divide(new BigDecimal((BigInteger) num1), BigDecimal.ROUND_HALF_UP); - } - - protected Number multiply(Number num0, Number num1) { - return ((BigInteger) num0).multiply((BigInteger) num1); - } - - protected Number mod(Number num0, Number num1) { - return ((BigInteger) num0).mod((BigInteger) num1); - } - - protected Number subtract(Number num0, Number num1) { - return ((BigInteger) num0).subtract((BigInteger) num1); - } - - public boolean matches(Object obj0, Object obj1) { - return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); - } - } - - public final static class DoubleDelegate extends ELArithmetic { - - protected Number add(Number num0, Number num1) { - // could only be one of these - if (num0 instanceof BigDecimal) { - return ((BigDecimal) num0).add(new BigDecimal(num1.doubleValue())); - } else if (num1 instanceof BigDecimal) { - return ((new BigDecimal(num0.doubleValue()).add((BigDecimal) num1))); - } - return new Double(num0.doubleValue() + num1.doubleValue()); - } - - protected Number coerce(Number num) { - if (num instanceof Double) - return num; - if (num instanceof BigInteger) - return new BigDecimal((BigInteger) num); - return new Double(num.doubleValue()); - } - - protected Number coerce(String str) { - return new Double(str); - } - - protected Number divide(Number num0, Number num1) { - return new Double(num0.doubleValue() / num1.doubleValue()); - } - - protected Number mod(Number num0, Number num1) { - return new Double(num0.doubleValue() % num1.doubleValue()); - } - - protected Number subtract(Number num0, Number num1) { - // could only be one of these - if (num0 instanceof BigDecimal) { - return ((BigDecimal) num0).subtract(new BigDecimal(num1.doubleValue())); - } else if (num1 instanceof BigDecimal) { - return ((new BigDecimal(num0.doubleValue()).subtract((BigDecimal) num1))); - } - return new Double(num0.doubleValue() - num1.doubleValue()); - } - - protected Number multiply(Number num0, Number num1) { - // could only be one of these - if (num0 instanceof BigDecimal) { - return ((BigDecimal) num0).multiply(new BigDecimal(num1.doubleValue())); - } else if (num1 instanceof BigDecimal) { - return ((new BigDecimal(num0.doubleValue()).multiply((BigDecimal) num1))); - } - return new Double(num0.doubleValue() * num1.doubleValue()); - } - - public boolean matches(Object obj0, Object obj1) { - return (obj0 instanceof Double - || obj1 instanceof Double - || obj0 instanceof Float - || obj1 instanceof Float - || (obj0 != null && (Double.TYPE == obj0.getClass() || Float.TYPE == obj0.getClass())) - || (obj1 != null && (Double.TYPE == obj1.getClass() || Float.TYPE == obj1.getClass())) - || (obj0 instanceof String && ELSupport - .isStringFloat((String) obj0)) || (obj1 instanceof String && ELSupport - .isStringFloat((String) obj1))); - } - } - - public final static class LongDelegate extends ELArithmetic { - - protected Number add(Number num0, Number num1) { - return new Long(num0.longValue() + num1.longValue()); - } - - protected Number coerce(Number num) { - if (num instanceof Long) - return num; - return new Long(num.longValue()); - } - - protected Number coerce(String str) { - return new Long(str); - } - - protected Number divide(Number num0, Number num1) { - return new Long(num0.longValue() / num1.longValue()); - } - - protected Number mod(Number num0, Number num1) { - return new Long(num0.longValue() % num1.longValue()); - } - - protected Number subtract(Number num0, Number num1) { - return new Long(num0.longValue() - num1.longValue()); - } - - protected Number multiply(Number num0, Number num1) { - return new Long(num0.longValue() * num1.longValue()); - } - - public boolean matches(Object obj0, Object obj1) { - return (obj0 instanceof Long || obj1 instanceof Long); - } - } - - public final static BigDecimalDelegate BIGDECIMAL = new BigDecimalDelegate(); - - public final static BigIntegerDelegate BIGINTEGER = new BigIntegerDelegate(); - - public final static DoubleDelegate DOUBLE = new DoubleDelegate(); - - public final static LongDelegate LONG = new LongDelegate(); - - private final static Long ZERO = new Long(0); - - public final static Number add(final Object obj0, final Object obj1) { - if (obj0 == null && obj1 == null) { - return new Long(0); - } - - final ELArithmetic delegate; - if (BIGDECIMAL.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else if (DOUBLE.matches(obj0, obj1)) - delegate = DOUBLE; - else if (BIGINTEGER.matches(obj0, obj1)) - delegate = BIGINTEGER; - else - delegate = LONG; - - Number num0 = delegate.coerce(obj0); - Number num1 = delegate.coerce(obj1); - - return delegate.add(num0, num1); - } - - public final static Number mod(final Object obj0, final Object obj1) { - if (obj0 == null && obj1 == null) { - return new Long(0); - } - - final ELArithmetic delegate; - if (BIGDECIMAL.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else if (DOUBLE.matches(obj0, obj1)) - delegate = DOUBLE; - else if (BIGINTEGER.matches(obj0, obj1)) - delegate = BIGINTEGER; - else - delegate = LONG; - - Number num0 = delegate.coerce(obj0); - Number num1 = delegate.coerce(obj1); - - return delegate.mod(num0, num1); - } - - public final static Number subtract(final Object obj0, final Object obj1) { - if (obj0 == null && obj1 == null) { - return new Long(0); - } - - final ELArithmetic delegate; - if (BIGDECIMAL.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else if (DOUBLE.matches(obj0, obj1)) - delegate = DOUBLE; - else if (BIGINTEGER.matches(obj0, obj1)) - delegate = BIGINTEGER; - else - delegate = LONG; - - Number num0 = delegate.coerce(obj0); - Number num1 = delegate.coerce(obj1); - - return delegate.subtract(num0, num1); - } - - public final static Number divide(final Object obj0, final Object obj1) { - if (obj0 == null && obj1 == null) { - return ZERO; - } - - final ELArithmetic delegate; - if (BIGDECIMAL.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else if (BIGINTEGER.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else - delegate = DOUBLE; - - Number num0 = delegate.coerce(obj0); - Number num1 = delegate.coerce(obj1); - - return delegate.divide(num0, num1); - } - - public final static Number multiply(final Object obj0, final Object obj1) { - if (obj0 == null && obj1 == null) { - return new Long(0); - } - - final ELArithmetic delegate; - if (BIGDECIMAL.matches(obj0, obj1)) - delegate = BIGDECIMAL; - else if (DOUBLE.matches(obj0, obj1)) - delegate = DOUBLE; - else if (BIGINTEGER.matches(obj0, obj1)) - delegate = BIGINTEGER; - else - delegate = LONG; - - Number num0 = delegate.coerce(obj0); - Number num1 = delegate.coerce(obj1); - - return delegate.multiply(num0, num1); - } - - public final static boolean isNumber(final Object obj) { - return (obj != null && isNumberType(obj.getClass())); - } - - public final static boolean isNumberType(final Class type) { - return type == (java.lang.Long.class) || type == Long.TYPE || type == (java.lang.Double.class) || type == Double.TYPE || type == (java.lang.Byte.class) || type == Byte.TYPE || type == (java.lang.Short.class) || type == Short.TYPE || type == (java.lang.Integer.class) || type == Integer.TYPE || type == (java.lang.Float.class) || type == Float.TYPE || type == (java.math.BigInteger.class) || type == (java.math.BigDecimal.class); - } - - /** - * - */ - protected ELArithmetic() { - super(); - } - - protected abstract Number add(final Number num0, final Number num1); - - protected abstract Number multiply(final Number num0, final Number num1); - - protected abstract Number subtract(final Number num0, final Number num1); - - protected abstract Number mod(final Number num0, final Number num1); - - protected abstract Number coerce(final Number num); - - protected final Number coerce(final Object obj) { - - if (isNumber(obj)) { - return coerce((Number) obj); - } - if (obj instanceof String) { - return coerce((String) obj); - } - if (obj == null || "".equals(obj)) { - return coerce(ZERO); - } - - Class objType = obj.getClass(); - if (Character.class.equals(objType) || Character.TYPE == objType) { - return coerce(new Short((short) ((Character) obj).charValue())); - } - - throw new IllegalArgumentException(MessageFactory.get("el.convert", obj, - objType)); - } - - protected abstract Number coerce(final String str); - - protected abstract Number divide(final Number num0, final Number num1); - - protected abstract boolean matches(final Object obj0, final Object obj1); - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import org.apache.el.util.MessageFactory; + + +/** + * A helper class of Arithmetic defined by the EL Specification + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public abstract class ELArithmetic { + + public final static class BigDecimalDelegate extends ELArithmetic { + + protected Number add(Number num0, Number num1) { + return ((BigDecimal) num0).add((BigDecimal) num1); + } + + protected Number coerce(Number num) { + if (num instanceof BigDecimal) + return num; + if (num instanceof BigInteger) + return new BigDecimal((BigInteger) num); + return new BigDecimal(num.doubleValue()); + } + + protected Number coerce(String str) { + return new BigDecimal(str); + } + + protected Number divide(Number num0, Number num1) { + return ((BigDecimal) num0).divide((BigDecimal) num1, + BigDecimal.ROUND_HALF_UP); + } + + protected Number subtract(Number num0, Number num1) { + return ((BigDecimal) num0).subtract((BigDecimal) num1); + } + + protected Number mod(Number num0, Number num1) { + return new Double(num0.doubleValue() % num1.doubleValue()); + } + + protected Number multiply(Number num0, Number num1) { + return ((BigDecimal) num0).multiply((BigDecimal) num1); + } + + public boolean matches(Object obj0, Object obj1) { + return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); + } + } + + public final static class BigIntegerDelegate extends ELArithmetic { + + protected Number add(Number num0, Number num1) { + return ((BigInteger) num0).add((BigInteger) num1); + } + + protected Number coerce(Number num) { + if (num instanceof BigInteger) + return num; + return new BigInteger(num.toString()); + } + + protected Number coerce(String str) { + return new BigInteger(str); + } + + protected Number divide(Number num0, Number num1) { + return (new BigDecimal((BigInteger) num0)).divide(new BigDecimal((BigInteger) num1), BigDecimal.ROUND_HALF_UP); + } + + protected Number multiply(Number num0, Number num1) { + return ((BigInteger) num0).multiply((BigInteger) num1); + } + + protected Number mod(Number num0, Number num1) { + return ((BigInteger) num0).mod((BigInteger) num1); + } + + protected Number subtract(Number num0, Number num1) { + return ((BigInteger) num0).subtract((BigInteger) num1); + } + + public boolean matches(Object obj0, Object obj1) { + return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); + } + } + + public final static class DoubleDelegate extends ELArithmetic { + + protected Number add(Number num0, Number num1) { + // could only be one of these + if (num0 instanceof BigDecimal) { + return ((BigDecimal) num0).add(new BigDecimal(num1.doubleValue())); + } else if (num1 instanceof BigDecimal) { + return ((new BigDecimal(num0.doubleValue()).add((BigDecimal) num1))); + } + return new Double(num0.doubleValue() + num1.doubleValue()); + } + + protected Number coerce(Number num) { + if (num instanceof Double) + return num; + if (num instanceof BigInteger) + return new BigDecimal((BigInteger) num); + return new Double(num.doubleValue()); + } + + protected Number coerce(String str) { + return new Double(str); + } + + protected Number divide(Number num0, Number num1) { + return new Double(num0.doubleValue() / num1.doubleValue()); + } + + protected Number mod(Number num0, Number num1) { + return new Double(num0.doubleValue() % num1.doubleValue()); + } + + protected Number subtract(Number num0, Number num1) { + // could only be one of these + if (num0 instanceof BigDecimal) { + return ((BigDecimal) num0).subtract(new BigDecimal(num1.doubleValue())); + } else if (num1 instanceof BigDecimal) { + return ((new BigDecimal(num0.doubleValue()).subtract((BigDecimal) num1))); + } + return new Double(num0.doubleValue() - num1.doubleValue()); + } + + protected Number multiply(Number num0, Number num1) { + // could only be one of these + if (num0 instanceof BigDecimal) { + return ((BigDecimal) num0).multiply(new BigDecimal(num1.doubleValue())); + } else if (num1 instanceof BigDecimal) { + return ((new BigDecimal(num0.doubleValue()).multiply((BigDecimal) num1))); + } + return new Double(num0.doubleValue() * num1.doubleValue()); + } + + public boolean matches(Object obj0, Object obj1) { + return (obj0 instanceof Double + || obj1 instanceof Double + || obj0 instanceof Float + || obj1 instanceof Float + || (obj0 != null && (Double.TYPE == obj0.getClass() || Float.TYPE == obj0.getClass())) + || (obj1 != null && (Double.TYPE == obj1.getClass() || Float.TYPE == obj1.getClass())) + || (obj0 instanceof String && ELSupport + .isStringFloat((String) obj0)) || (obj1 instanceof String && ELSupport + .isStringFloat((String) obj1))); + } + } + + public final static class LongDelegate extends ELArithmetic { + + protected Number add(Number num0, Number num1) { + return new Long(num0.longValue() + num1.longValue()); + } + + protected Number coerce(Number num) { + if (num instanceof Long) + return num; + return new Long(num.longValue()); + } + + protected Number coerce(String str) { + return new Long(str); + } + + protected Number divide(Number num0, Number num1) { + return new Long(num0.longValue() / num1.longValue()); + } + + protected Number mod(Number num0, Number num1) { + return new Long(num0.longValue() % num1.longValue()); + } + + protected Number subtract(Number num0, Number num1) { + return new Long(num0.longValue() - num1.longValue()); + } + + protected Number multiply(Number num0, Number num1) { + return new Long(num0.longValue() * num1.longValue()); + } + + public boolean matches(Object obj0, Object obj1) { + return (obj0 instanceof Long || obj1 instanceof Long); + } + } + + public final static BigDecimalDelegate BIGDECIMAL = new BigDecimalDelegate(); + + public final static BigIntegerDelegate BIGINTEGER = new BigIntegerDelegate(); + + public final static DoubleDelegate DOUBLE = new DoubleDelegate(); + + public final static LongDelegate LONG = new LongDelegate(); + + private final static Long ZERO = new Long(0); + + public final static Number add(final Object obj0, final Object obj1) { + if (obj0 == null && obj1 == null) { + return new Long(0); + } + + final ELArithmetic delegate; + if (BIGDECIMAL.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else if (DOUBLE.matches(obj0, obj1)) + delegate = DOUBLE; + else if (BIGINTEGER.matches(obj0, obj1)) + delegate = BIGINTEGER; + else + delegate = LONG; + + Number num0 = delegate.coerce(obj0); + Number num1 = delegate.coerce(obj1); + + return delegate.add(num0, num1); + } + + public final static Number mod(final Object obj0, final Object obj1) { + if (obj0 == null && obj1 == null) { + return new Long(0); + } + + final ELArithmetic delegate; + if (BIGDECIMAL.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else if (DOUBLE.matches(obj0, obj1)) + delegate = DOUBLE; + else if (BIGINTEGER.matches(obj0, obj1)) + delegate = BIGINTEGER; + else + delegate = LONG; + + Number num0 = delegate.coerce(obj0); + Number num1 = delegate.coerce(obj1); + + return delegate.mod(num0, num1); + } + + public final static Number subtract(final Object obj0, final Object obj1) { + if (obj0 == null && obj1 == null) { + return new Long(0); + } + + final ELArithmetic delegate; + if (BIGDECIMAL.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else if (DOUBLE.matches(obj0, obj1)) + delegate = DOUBLE; + else if (BIGINTEGER.matches(obj0, obj1)) + delegate = BIGINTEGER; + else + delegate = LONG; + + Number num0 = delegate.coerce(obj0); + Number num1 = delegate.coerce(obj1); + + return delegate.subtract(num0, num1); + } + + public final static Number divide(final Object obj0, final Object obj1) { + if (obj0 == null && obj1 == null) { + return ZERO; + } + + final ELArithmetic delegate; + if (BIGDECIMAL.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else if (BIGINTEGER.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else + delegate = DOUBLE; + + Number num0 = delegate.coerce(obj0); + Number num1 = delegate.coerce(obj1); + + return delegate.divide(num0, num1); + } + + public final static Number multiply(final Object obj0, final Object obj1) { + if (obj0 == null && obj1 == null) { + return new Long(0); + } + + final ELArithmetic delegate; + if (BIGDECIMAL.matches(obj0, obj1)) + delegate = BIGDECIMAL; + else if (DOUBLE.matches(obj0, obj1)) + delegate = DOUBLE; + else if (BIGINTEGER.matches(obj0, obj1)) + delegate = BIGINTEGER; + else + delegate = LONG; + + Number num0 = delegate.coerce(obj0); + Number num1 = delegate.coerce(obj1); + + return delegate.multiply(num0, num1); + } + + public final static boolean isNumber(final Object obj) { + return (obj != null && isNumberType(obj.getClass())); + } + + public final static boolean isNumberType(final Class type) { + return type == (java.lang.Long.class) || type == Long.TYPE || type == (java.lang.Double.class) || type == Double.TYPE || type == (java.lang.Byte.class) || type == Byte.TYPE || type == (java.lang.Short.class) || type == Short.TYPE || type == (java.lang.Integer.class) || type == Integer.TYPE || type == (java.lang.Float.class) || type == Float.TYPE || type == (java.math.BigInteger.class) || type == (java.math.BigDecimal.class); + } + + /** + * + */ + protected ELArithmetic() { + super(); + } + + protected abstract Number add(final Number num0, final Number num1); + + protected abstract Number multiply(final Number num0, final Number num1); + + protected abstract Number subtract(final Number num0, final Number num1); + + protected abstract Number mod(final Number num0, final Number num1); + + protected abstract Number coerce(final Number num); + + protected final Number coerce(final Object obj) { + + if (isNumber(obj)) { + return coerce((Number) obj); + } + if (obj instanceof String) { + return coerce((String) obj); + } + if (obj == null || "".equals(obj)) { + return coerce(ZERO); + } + + Class objType = obj.getClass(); + if (Character.class.equals(objType) || Character.TYPE == objType) { + return coerce(new Short((short) ((Character) obj).charValue())); + } + + throw new IllegalArgumentException(MessageFactory.get("el.convert", obj, + objType)); + } + + protected abstract Number coerce(final String str); + + protected abstract Number divide(final Number num0, final Number num1); + + protected abstract boolean matches(final Object obj0, final Object obj1); + +} diff --git a/java/org/apache/el/lang/ELSupport.java b/java/org/apache/el/lang/ELSupport.java index 03cd3f074..0393c9f1f 100644 --- a/java/org/apache/el/lang/ELSupport.java +++ b/java/org/apache/el/lang/ELSupport.java @@ -1,442 +1,442 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.beans.PropertyEditor; -import java.beans.PropertyEditorManager; -import java.math.BigDecimal; -import java.math.BigInteger; - -import javax.el.ELException; -import javax.el.PropertyNotFoundException; - -import org.apache.el.util.MessageFactory; - - -/** - * A helper class that implements the EL Specification - * - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public class ELSupport { - - private final static ELSupport REF = new ELSupport(); - - private final static Long ZERO = new Long(0L); - - public final static void throwUnhandled(Object base, Object property) - throws ELException { - if (base == null) { - throw new PropertyNotFoundException(MessageFactory.get( - "error.resolver.unhandled.null", property)); - } else { - throw new PropertyNotFoundException(MessageFactory.get( - "error.resolver.unhandled", base.getClass(), property)); - } - } - - /** - * @param obj0 - * @param obj1 - * @return - * @throws EvaluationException - */ - public final static int compare(final Object obj0, final Object obj1) - throws ELException { - if (obj0 == obj1 || equals(obj0, obj1)) { - return 0; - } - if (isBigDecimalOp(obj0, obj1)) { - BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); - BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); - return bd0.compareTo(bd1); - } - if (isDoubleOp(obj0, obj1)) { - Double d0 = (Double) coerceToNumber(obj0, Double.class); - Double d1 = (Double) coerceToNumber(obj1, Double.class); - return d0.compareTo(d1); - } - if (isBigIntegerOp(obj0, obj1)) { - BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); - BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); - return bi0.compareTo(bi1); - } - if (isLongOp(obj0, obj1)) { - Long l0 = (Long) coerceToNumber(obj0, Long.class); - Long l1 = (Long) coerceToNumber(obj1, Long.class); - return l0.compareTo(l1); - } - if (obj0 instanceof String || obj1 instanceof String) { - return coerceToString(obj0).compareTo(coerceToString(obj1)); - } - if (obj0 instanceof Comparable) { - return (obj1 != null) ? ((Comparable) obj0).compareTo(obj1) : 1; - } - if (obj1 instanceof Comparable) { - return (obj0 != null) ? -((Comparable) obj1).compareTo(obj0) : -1; - } - throw new ELException(MessageFactory.get("error.compare", obj0, obj1)); - } - - /** - * @param obj0 - * @param obj1 - * @return - * @throws EvaluationException - */ - public final static boolean equals(final Object obj0, final Object obj1) - throws ELException { - if (obj0 == obj1) { - return true; - } else if (obj0 == null || obj1 == null) { - return false; - } else if (obj0 instanceof Boolean || obj1 instanceof Boolean) { - return coerceToBoolean(obj0).equals(coerceToBoolean(obj1)); - } - if (isBigDecimalOp(obj0, obj1)) { - BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); - BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); - return bd0.equals(bd1); - } - if (isDoubleOp(obj0, obj1)) { - Double d0 = (Double) coerceToNumber(obj0, Double.class); - Double d1 = (Double) coerceToNumber(obj1, Double.class); - return d0.equals(d1); - } - if (isBigIntegerOp(obj0, obj1)) { - BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); - BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); - return bi0.equals(bi1); - } - if (isLongOp(obj0, obj1)) { - Long l0 = (Long) coerceToNumber(obj0, Long.class); - Long l1 = (Long) coerceToNumber(obj1, Long.class); - return l0.equals(l1); - } else { - return obj0.equals(obj1); - } - } - - /** - * @param obj - * @return - */ - public final static Boolean coerceToBoolean(final Object obj) - throws IllegalArgumentException { - if (obj == null || "".equals(obj)) { - return Boolean.FALSE; - } - if (obj instanceof Boolean || obj.getClass() == Boolean.TYPE) { - return (Boolean) obj; - } - if (obj instanceof String) { - return Boolean.valueOf((String) obj); - } - - throw new IllegalArgumentException(MessageFactory.get("error.convert", - obj, obj.getClass(), Boolean.class)); - } - - public final static Character coerceToCharacter(final Object obj) - throws IllegalArgumentException { - if (obj == null || "".equals(obj)) { - return new Character((char) 0); - } - if (obj instanceof String) { - return new Character(((String) obj).charAt(0)); - } - if (ELArithmetic.isNumber(obj)) { - return new Character((char) ((Number) obj).shortValue()); - } - Class objType = obj.getClass(); - if (obj instanceof Character || objType == Character.TYPE) { - return (Character) obj; - } - - throw new IllegalArgumentException(MessageFactory.get("error.convert", - obj, objType, Character.class)); - } - - public final static Number coerceToNumber(final Object obj) { - if (obj == null) { - return ZERO; - } else if (obj instanceof Number) { - return (Number) obj; - } else { - String str = coerceToString(obj); - if (isStringFloat(str)) { - return toFloat(str); - } else { - return toNumber(str); - } - } - } - - protected final static Number coerceToNumber(final Number number, - final Class type) throws IllegalArgumentException { - if (Long.TYPE == type || Long.class.equals(type)) { - return new Long(number.longValue()); - } - if (Double.TYPE == type || Double.class.equals(type)) { - return new Double(number.doubleValue()); - } - if (Integer.TYPE == type || Integer.class.equals(type)) { - return new Integer(number.intValue()); - } - if (BigInteger.class.equals(type)) { - if (number instanceof BigDecimal) { - return ((BigDecimal) number).toBigInteger(); - } - return BigInteger.valueOf(number.longValue()); - } - if (BigDecimal.class.equals(type)) { - if (number instanceof BigInteger) { - return new BigDecimal((BigInteger) number); - } - return new BigDecimal(number.doubleValue()); - } - if (Byte.TYPE == type || Byte.class.equals(type)) { - return new Byte(number.byteValue()); - } - if (Short.TYPE == type || Short.class.equals(type)) { - return new Short(number.shortValue()); - } - if (Float.TYPE == type || Float.class.equals(type)) { - return new Float(number.floatValue()); - } - - throw new IllegalArgumentException(MessageFactory.get("error.convert", - number, number.getClass(), type)); - } - - public final static Number coerceToNumber(final Object obj, final Class type) - throws IllegalArgumentException { - if (obj == null || "".equals(obj)) { - return coerceToNumber(ZERO, type); - } - if (obj instanceof String) { - return coerceToNumber((String) obj, type); - } - if (ELArithmetic.isNumber(obj)) { - return coerceToNumber((Number) obj, type); - } - - Class objType = obj.getClass(); - if (Character.class.equals(objType) || Character.TYPE == objType) { - return coerceToNumber(new Short((short) ((Character) obj) - .charValue()), type); - } - - throw new IllegalArgumentException(MessageFactory.get("error.convert", - obj, objType, type)); - } - - protected final static Number coerceToNumber(final String val, - final Class type) throws IllegalArgumentException { - if (Long.TYPE == type || Long.class.equals(type)) { - return Long.valueOf(val); - } - if (Integer.TYPE == type || Integer.class.equals(type)) { - return Integer.valueOf(val); - } - if (Double.TYPE == type || Double.class.equals(type)) { - return Double.valueOf(val); - } - if (BigInteger.class.equals(type)) { - return new BigInteger(val); - } - if (BigDecimal.class.equals(type)) { - return new BigDecimal(val); - } - if (Byte.TYPE == type || Byte.class.equals(type)) { - return Byte.valueOf(val); - } - if (Short.TYPE == type || Short.class.equals(type)) { - return Short.valueOf(val); - } - if (Float.TYPE == type || Float.class.equals(type)) { - return Float.valueOf(val); - } - - throw new IllegalArgumentException(MessageFactory.get("error.convert", - val, String.class, type)); - } - - /** - * @param obj - * @return - */ - public final static String coerceToString(final Object obj) { - if (obj == null) { - return ""; - } else if (obj instanceof String) { - return (String) obj; - } else { - return obj.toString(); - } - } - - public final static Object coerceToType(final Object obj, final Class type) - throws IllegalArgumentException { - if (type == null || Object.class.equals(type)) { - return obj; - } - if (String.class.equals(type)) { - return coerceToString(obj); - } - if (ELArithmetic.isNumberType(type)) { - return coerceToNumber(obj, type); - } - if (Character.class.equals(type) || Character.TYPE == type) { - return coerceToCharacter(obj); - } - if (Boolean.class.equals(type) || Boolean.TYPE == type) { - return coerceToBoolean(obj); - } - if (obj != null && type.isAssignableFrom(obj.getClass())) { - return obj; - } - - // new to spec - if (obj == null) - return null; - if (obj instanceof String) { - if ("".equals(obj)) - return null; - PropertyEditor editor = PropertyEditorManager.findEditor(type); - if (editor != null) { - editor.setAsText((String) obj); - return editor.getValue(); - } - } - throw new IllegalArgumentException(MessageFactory.get("error.convert", - obj, obj.getClass(), type)); - } - - /** - * @param obj - * @return - */ - public final static boolean containsNulls(final Object[] obj) { - for (int i = 0; i < obj.length; i++) { - if (obj[0] == null) { - return true; - } - } - return false; - } - - public final static boolean isBigDecimalOp(final Object obj0, - final Object obj1) { - return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); - } - - public final static boolean isBigIntegerOp(final Object obj0, - final Object obj1) { - return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); - } - - public final static boolean isDoubleOp(final Object obj0, final Object obj1) { - return (obj0 instanceof Double - || obj1 instanceof Double - || obj0 instanceof Float - || obj1 instanceof Float - || (obj0 != null && (Double.TYPE == obj0.getClass() || Float.TYPE == obj0 - .getClass())) || (obj1 != null && (Double.TYPE == obj1 - .getClass() || Float.TYPE == obj1.getClass()))); - } - - public final static boolean isDoubleStringOp(final Object obj0, - final Object obj1) { - return (isDoubleOp(obj0, obj1) - || (obj0 instanceof String && isStringFloat((String) obj0)) || (obj1 instanceof String && isStringFloat((String) obj1))); - } - - public final static boolean isLongOp(final Object obj0, final Object obj1) { - return (obj0 instanceof Long - || obj1 instanceof Long - || obj0 instanceof Integer - || obj1 instanceof Integer - || obj0 instanceof Character - || obj1 instanceof Character - || obj0 instanceof Short - || obj1 instanceof Short - || obj0 instanceof Byte - || obj1 instanceof Byte - || (obj0 != null && (Long.TYPE == obj0.getClass() - || Integer.TYPE == obj0.getClass() - || Character.TYPE == obj0.getClass() - || Short.TYPE == obj0.getClass() || Byte.TYPE == obj0 - .getClass())) || (obj0 != null && (Long.TYPE == obj0 - .getClass() - || Integer.TYPE == obj0.getClass() - || Character.TYPE == obj0.getClass() - || Short.TYPE == obj0.getClass() || Byte.TYPE == obj0 - .getClass()))); - } - - public final static boolean isStringFloat(final String str) { - int len = str.length(); - if (len > 1) { - char c = 0; - for (int i = 0; i < len; i++) { - switch (c = str.charAt(i)) { - case 'E': - return true; - case 'e': - return true; - case '.': - return true; - } - } - } - return false; - } - - public final static Number toFloat(final String value) { - try { - if (Double.parseDouble(value) > Double.MAX_VALUE) { - return new BigDecimal(value); - } else { - return new Double(value); - } - } catch (NumberFormatException e0) { - return new BigDecimal(value); - } - } - - public final static Number toNumber(final String value) { - try { - return new Integer(Integer.parseInt(value)); - } catch (NumberFormatException e0) { - try { - return new Long(Long.parseLong(value)); - } catch (NumberFormatException e1) { - return new BigInteger(value); - } - } - } - - /** - * - */ - public ELSupport() { - super(); - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.beans.PropertyEditor; +import java.beans.PropertyEditorManager; +import java.math.BigDecimal; +import java.math.BigInteger; + +import javax.el.ELException; +import javax.el.PropertyNotFoundException; + +import org.apache.el.util.MessageFactory; + + +/** + * A helper class that implements the EL Specification + * + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public class ELSupport { + + private final static ELSupport REF = new ELSupport(); + + private final static Long ZERO = new Long(0L); + + public final static void throwUnhandled(Object base, Object property) + throws ELException { + if (base == null) { + throw new PropertyNotFoundException(MessageFactory.get( + "error.resolver.unhandled.null", property)); + } else { + throw new PropertyNotFoundException(MessageFactory.get( + "error.resolver.unhandled", base.getClass(), property)); + } + } + + /** + * @param obj0 + * @param obj1 + * @return + * @throws EvaluationException + */ + public final static int compare(final Object obj0, final Object obj1) + throws ELException { + if (obj0 == obj1 || equals(obj0, obj1)) { + return 0; + } + if (isBigDecimalOp(obj0, obj1)) { + BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); + BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); + return bd0.compareTo(bd1); + } + if (isDoubleOp(obj0, obj1)) { + Double d0 = (Double) coerceToNumber(obj0, Double.class); + Double d1 = (Double) coerceToNumber(obj1, Double.class); + return d0.compareTo(d1); + } + if (isBigIntegerOp(obj0, obj1)) { + BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); + BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); + return bi0.compareTo(bi1); + } + if (isLongOp(obj0, obj1)) { + Long l0 = (Long) coerceToNumber(obj0, Long.class); + Long l1 = (Long) coerceToNumber(obj1, Long.class); + return l0.compareTo(l1); + } + if (obj0 instanceof String || obj1 instanceof String) { + return coerceToString(obj0).compareTo(coerceToString(obj1)); + } + if (obj0 instanceof Comparable) { + return (obj1 != null) ? ((Comparable) obj0).compareTo(obj1) : 1; + } + if (obj1 instanceof Comparable) { + return (obj0 != null) ? -((Comparable) obj1).compareTo(obj0) : -1; + } + throw new ELException(MessageFactory.get("error.compare", obj0, obj1)); + } + + /** + * @param obj0 + * @param obj1 + * @return + * @throws EvaluationException + */ + public final static boolean equals(final Object obj0, final Object obj1) + throws ELException { + if (obj0 == obj1) { + return true; + } else if (obj0 == null || obj1 == null) { + return false; + } else if (obj0 instanceof Boolean || obj1 instanceof Boolean) { + return coerceToBoolean(obj0).equals(coerceToBoolean(obj1)); + } + if (isBigDecimalOp(obj0, obj1)) { + BigDecimal bd0 = (BigDecimal) coerceToNumber(obj0, BigDecimal.class); + BigDecimal bd1 = (BigDecimal) coerceToNumber(obj1, BigDecimal.class); + return bd0.equals(bd1); + } + if (isDoubleOp(obj0, obj1)) { + Double d0 = (Double) coerceToNumber(obj0, Double.class); + Double d1 = (Double) coerceToNumber(obj1, Double.class); + return d0.equals(d1); + } + if (isBigIntegerOp(obj0, obj1)) { + BigInteger bi0 = (BigInteger) coerceToNumber(obj0, BigInteger.class); + BigInteger bi1 = (BigInteger) coerceToNumber(obj1, BigInteger.class); + return bi0.equals(bi1); + } + if (isLongOp(obj0, obj1)) { + Long l0 = (Long) coerceToNumber(obj0, Long.class); + Long l1 = (Long) coerceToNumber(obj1, Long.class); + return l0.equals(l1); + } else { + return obj0.equals(obj1); + } + } + + /** + * @param obj + * @return + */ + public final static Boolean coerceToBoolean(final Object obj) + throws IllegalArgumentException { + if (obj == null || "".equals(obj)) { + return Boolean.FALSE; + } + if (obj instanceof Boolean || obj.getClass() == Boolean.TYPE) { + return (Boolean) obj; + } + if (obj instanceof String) { + return Boolean.valueOf((String) obj); + } + + throw new IllegalArgumentException(MessageFactory.get("error.convert", + obj, obj.getClass(), Boolean.class)); + } + + public final static Character coerceToCharacter(final Object obj) + throws IllegalArgumentException { + if (obj == null || "".equals(obj)) { + return new Character((char) 0); + } + if (obj instanceof String) { + return new Character(((String) obj).charAt(0)); + } + if (ELArithmetic.isNumber(obj)) { + return new Character((char) ((Number) obj).shortValue()); + } + Class objType = obj.getClass(); + if (obj instanceof Character || objType == Character.TYPE) { + return (Character) obj; + } + + throw new IllegalArgumentException(MessageFactory.get("error.convert", + obj, objType, Character.class)); + } + + public final static Number coerceToNumber(final Object obj) { + if (obj == null) { + return ZERO; + } else if (obj instanceof Number) { + return (Number) obj; + } else { + String str = coerceToString(obj); + if (isStringFloat(str)) { + return toFloat(str); + } else { + return toNumber(str); + } + } + } + + protected final static Number coerceToNumber(final Number number, + final Class type) throws IllegalArgumentException { + if (Long.TYPE == type || Long.class.equals(type)) { + return new Long(number.longValue()); + } + if (Double.TYPE == type || Double.class.equals(type)) { + return new Double(number.doubleValue()); + } + if (Integer.TYPE == type || Integer.class.equals(type)) { + return new Integer(number.intValue()); + } + if (BigInteger.class.equals(type)) { + if (number instanceof BigDecimal) { + return ((BigDecimal) number).toBigInteger(); + } + return BigInteger.valueOf(number.longValue()); + } + if (BigDecimal.class.equals(type)) { + if (number instanceof BigInteger) { + return new BigDecimal((BigInteger) number); + } + return new BigDecimal(number.doubleValue()); + } + if (Byte.TYPE == type || Byte.class.equals(type)) { + return new Byte(number.byteValue()); + } + if (Short.TYPE == type || Short.class.equals(type)) { + return new Short(number.shortValue()); + } + if (Float.TYPE == type || Float.class.equals(type)) { + return new Float(number.floatValue()); + } + + throw new IllegalArgumentException(MessageFactory.get("error.convert", + number, number.getClass(), type)); + } + + public final static Number coerceToNumber(final Object obj, final Class type) + throws IllegalArgumentException { + if (obj == null || "".equals(obj)) { + return coerceToNumber(ZERO, type); + } + if (obj instanceof String) { + return coerceToNumber((String) obj, type); + } + if (ELArithmetic.isNumber(obj)) { + return coerceToNumber((Number) obj, type); + } + + Class objType = obj.getClass(); + if (Character.class.equals(objType) || Character.TYPE == objType) { + return coerceToNumber(new Short((short) ((Character) obj) + .charValue()), type); + } + + throw new IllegalArgumentException(MessageFactory.get("error.convert", + obj, objType, type)); + } + + protected final static Number coerceToNumber(final String val, + final Class type) throws IllegalArgumentException { + if (Long.TYPE == type || Long.class.equals(type)) { + return Long.valueOf(val); + } + if (Integer.TYPE == type || Integer.class.equals(type)) { + return Integer.valueOf(val); + } + if (Double.TYPE == type || Double.class.equals(type)) { + return Double.valueOf(val); + } + if (BigInteger.class.equals(type)) { + return new BigInteger(val); + } + if (BigDecimal.class.equals(type)) { + return new BigDecimal(val); + } + if (Byte.TYPE == type || Byte.class.equals(type)) { + return Byte.valueOf(val); + } + if (Short.TYPE == type || Short.class.equals(type)) { + return Short.valueOf(val); + } + if (Float.TYPE == type || Float.class.equals(type)) { + return Float.valueOf(val); + } + + throw new IllegalArgumentException(MessageFactory.get("error.convert", + val, String.class, type)); + } + + /** + * @param obj + * @return + */ + public final static String coerceToString(final Object obj) { + if (obj == null) { + return ""; + } else if (obj instanceof String) { + return (String) obj; + } else { + return obj.toString(); + } + } + + public final static Object coerceToType(final Object obj, final Class type) + throws IllegalArgumentException { + if (type == null || Object.class.equals(type)) { + return obj; + } + if (String.class.equals(type)) { + return coerceToString(obj); + } + if (ELArithmetic.isNumberType(type)) { + return coerceToNumber(obj, type); + } + if (Character.class.equals(type) || Character.TYPE == type) { + return coerceToCharacter(obj); + } + if (Boolean.class.equals(type) || Boolean.TYPE == type) { + return coerceToBoolean(obj); + } + if (obj != null && type.isAssignableFrom(obj.getClass())) { + return obj; + } + + // new to spec + if (obj == null) + return null; + if (obj instanceof String) { + if ("".equals(obj)) + return null; + PropertyEditor editor = PropertyEditorManager.findEditor(type); + if (editor != null) { + editor.setAsText((String) obj); + return editor.getValue(); + } + } + throw new IllegalArgumentException(MessageFactory.get("error.convert", + obj, obj.getClass(), type)); + } + + /** + * @param obj + * @return + */ + public final static boolean containsNulls(final Object[] obj) { + for (int i = 0; i < obj.length; i++) { + if (obj[0] == null) { + return true; + } + } + return false; + } + + public final static boolean isBigDecimalOp(final Object obj0, + final Object obj1) { + return (obj0 instanceof BigDecimal || obj1 instanceof BigDecimal); + } + + public final static boolean isBigIntegerOp(final Object obj0, + final Object obj1) { + return (obj0 instanceof BigInteger || obj1 instanceof BigInteger); + } + + public final static boolean isDoubleOp(final Object obj0, final Object obj1) { + return (obj0 instanceof Double + || obj1 instanceof Double + || obj0 instanceof Float + || obj1 instanceof Float + || (obj0 != null && (Double.TYPE == obj0.getClass() || Float.TYPE == obj0 + .getClass())) || (obj1 != null && (Double.TYPE == obj1 + .getClass() || Float.TYPE == obj1.getClass()))); + } + + public final static boolean isDoubleStringOp(final Object obj0, + final Object obj1) { + return (isDoubleOp(obj0, obj1) + || (obj0 instanceof String && isStringFloat((String) obj0)) || (obj1 instanceof String && isStringFloat((String) obj1))); + } + + public final static boolean isLongOp(final Object obj0, final Object obj1) { + return (obj0 instanceof Long + || obj1 instanceof Long + || obj0 instanceof Integer + || obj1 instanceof Integer + || obj0 instanceof Character + || obj1 instanceof Character + || obj0 instanceof Short + || obj1 instanceof Short + || obj0 instanceof Byte + || obj1 instanceof Byte + || (obj0 != null && (Long.TYPE == obj0.getClass() + || Integer.TYPE == obj0.getClass() + || Character.TYPE == obj0.getClass() + || Short.TYPE == obj0.getClass() || Byte.TYPE == obj0 + .getClass())) || (obj0 != null && (Long.TYPE == obj0 + .getClass() + || Integer.TYPE == obj0.getClass() + || Character.TYPE == obj0.getClass() + || Short.TYPE == obj0.getClass() || Byte.TYPE == obj0 + .getClass()))); + } + + public final static boolean isStringFloat(final String str) { + int len = str.length(); + if (len > 1) { + char c = 0; + for (int i = 0; i < len; i++) { + switch (c = str.charAt(i)) { + case 'E': + return true; + case 'e': + return true; + case '.': + return true; + } + } + } + return false; + } + + public final static Number toFloat(final String value) { + try { + if (Double.parseDouble(value) > Double.MAX_VALUE) { + return new BigDecimal(value); + } else { + return new Double(value); + } + } catch (NumberFormatException e0) { + return new BigDecimal(value); + } + } + + public final static Number toNumber(final String value) { + try { + return new Integer(Integer.parseInt(value)); + } catch (NumberFormatException e0) { + try { + return new Long(Long.parseLong(value)); + } catch (NumberFormatException e1) { + return new BigInteger(value); + } + } + } + + /** + * + */ + public ELSupport() { + super(); + } + +} diff --git a/java/org/apache/el/lang/EvaluationContext.java b/java/org/apache/el/lang/EvaluationContext.java index c59da001c..eeb93e9dd 100644 --- a/java/org/apache/el/lang/EvaluationContext.java +++ b/java/org/apache/el/lang/EvaluationContext.java @@ -1,70 +1,70 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import javax.el.ELContext; -import javax.el.ELResolver; -import javax.el.FunctionMapper; -import javax.el.VariableMapper; - -public final class EvaluationContext extends ELContext { - - private final ELContext elContext; - - private final FunctionMapper fnMapper; - - private final VariableMapper varMapper; - - public EvaluationContext(ELContext elContext, FunctionMapper fnMapper, - VariableMapper varMapper) { - this.elContext = elContext; - this.fnMapper = fnMapper; - this.varMapper = varMapper; - } - - public ELContext getELContext() { - return this.elContext; - } - - public FunctionMapper getFunctionMapper() { - return this.fnMapper; - } - - public VariableMapper getVariableMapper() { - return this.varMapper; - } - - public Object getContext(Class key) { - return this.elContext.getContext(key); - } - - public ELResolver getELResolver() { - return this.elContext.getELResolver(); - } - - public boolean isPropertyResolved() { - return this.elContext.isPropertyResolved(); - } - - public void putContext(Class key, Object contextObject) { - this.elContext.putContext(key, contextObject); - } - - public void setPropertyResolved(boolean resolved) { - this.elContext.setPropertyResolved(resolved); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.VariableMapper; + +public final class EvaluationContext extends ELContext { + + private final ELContext elContext; + + private final FunctionMapper fnMapper; + + private final VariableMapper varMapper; + + public EvaluationContext(ELContext elContext, FunctionMapper fnMapper, + VariableMapper varMapper) { + this.elContext = elContext; + this.fnMapper = fnMapper; + this.varMapper = varMapper; + } + + public ELContext getELContext() { + return this.elContext; + } + + public FunctionMapper getFunctionMapper() { + return this.fnMapper; + } + + public VariableMapper getVariableMapper() { + return this.varMapper; + } + + public Object getContext(Class key) { + return this.elContext.getContext(key); + } + + public ELResolver getELResolver() { + return this.elContext.getELResolver(); + } + + public boolean isPropertyResolved() { + return this.elContext.isPropertyResolved(); + } + + public void putContext(Class key, Object contextObject) { + this.elContext.putContext(key, contextObject); + } + + public void setPropertyResolved(boolean resolved) { + this.elContext.setPropertyResolved(resolved); + } +} diff --git a/java/org/apache/el/lang/ExpressionBuilder.java b/java/org/apache/el/lang/ExpressionBuilder.java index 4eb368e83..4e1b44ff3 100644 --- a/java/org/apache/el/lang/ExpressionBuilder.java +++ b/java/org/apache/el/lang/ExpressionBuilder.java @@ -1,213 +1,213 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.io.StringReader; -import java.lang.ref.SoftReference; -import java.lang.reflect.Method; -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.FunctionMapper; -import javax.el.MethodExpression; -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -import org.apache.el.MethodExpressionImpl; -import org.apache.el.MethodExpressionLiteral; -import org.apache.el.ValueExpressionImpl; -import org.apache.el.parser.AstCompositeExpression; -import org.apache.el.parser.AstDeferredExpression; -import org.apache.el.parser.AstDynamicExpression; -import org.apache.el.parser.AstFunction; -import org.apache.el.parser.AstIdentifier; -import org.apache.el.parser.AstLiteralExpression; -import org.apache.el.parser.AstValue; -import org.apache.el.parser.ELParser; -import org.apache.el.parser.Node; -import org.apache.el.parser.NodeVisitor; -import org.apache.el.parser.ParseException; -import org.apache.el.util.ConcurrentCache; -import org.apache.el.util.MessageFactory; - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public final class ExpressionBuilder implements NodeVisitor { - - private static final ConcurrentCache cache = new ConcurrentCache(5000); - - private FunctionMapper fnMapper; - - private VariableMapper varMapper; - - private String expression; - - /** - * - */ - public ExpressionBuilder(String expression, ELContext ctx) - throws ELException { - this.expression = expression; - - FunctionMapper ctxFn = ctx.getFunctionMapper(); - VariableMapper ctxVar = ctx.getVariableMapper(); - - if (ctxFn != null) { - this.fnMapper = new FunctionMapperFactory(ctxFn); - } - if (ctxVar != null) { - this.varMapper = new VariableMapperFactory(ctxVar); - } - } - - public final static Node createNode(String expr) throws ELException { - Node n = createNodeInternal(expr); - return n; - } - - private final static Node createNodeInternal(String expr) - throws ELException { - if (expr == null) { - throw new ELException(MessageFactory.get("error.null")); - } - - Node n = (Node) cache.get(expr); - if (n == null) { - try { - n = (new ELParser(new StringReader(expr))) - .CompositeExpression(); - - // validate composite expression - if (n instanceof AstCompositeExpression) { - int numChildren = n.jjtGetNumChildren(); - if (numChildren == 1) { - n = n.jjtGetChild(0); - } else { - Class type = null; - Node child = null; - for (int i = 0; i < numChildren; i++) { - child = n.jjtGetChild(i); - if (child instanceof AstLiteralExpression) - continue; - if (type == null) - type = child.getClass(); - else { - if (!type.equals(child.getClass())) { - throw new ELException(MessageFactory.get( - "error.mixed", expr)); - } - } - } - } - } - if (n instanceof AstDeferredExpression - || n instanceof AstDynamicExpression) { - n = n.jjtGetChild(0); - } - cache.put(expr, n); - } catch (ParseException pe) { - throw new ELException("Error Parsing: " + expr, pe); - } - } - return n; - } - - private void prepare(Node node) throws ELException { - try { - node.accept(this); - } catch (Exception e) { - throw (ELException) e; - } - if (this.fnMapper instanceof FunctionMapperFactory) { - this.fnMapper = ((FunctionMapperFactory) this.fnMapper).create(); - } - if (this.varMapper instanceof VariableMapperFactory) { - this.varMapper = ((VariableMapperFactory) this.varMapper).create(); - } - } - - private Node build() throws ELException { - Node n = createNodeInternal(this.expression); - this.prepare(n); - if (n instanceof AstDeferredExpression - || n instanceof AstDynamicExpression) { - n = n.jjtGetChild(0); - } - return n; - } - - /* - * (non-Javadoc) - * - * @see com.sun.el.parser.NodeVisitor#visit(com.sun.el.parser.Node) - */ - public void visit(Node node) throws ELException { - if (node instanceof AstFunction) { - - AstFunction funcNode = (AstFunction) node; - - if (this.fnMapper == null) { - throw new ELException(MessageFactory.get("error.fnMapper.null")); - } - Method m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode - .getLocalName()); - if (m == null) { - throw new ELException(MessageFactory.get( - "error.fnMapper.method", funcNode.getOutputName())); - } - int pcnt = m.getParameterTypes().length; - if (node.jjtGetNumChildren() != pcnt) { - throw new ELException(MessageFactory.get( - "error.fnMapper.paramcount", funcNode.getOutputName(), - "" + pcnt, "" + node.jjtGetNumChildren())); - } - } else if (node instanceof AstIdentifier && this.varMapper != null) { - String variable = ((AstIdentifier) node).getImage(); - - // simply capture it - this.varMapper.resolveVariable(variable); - } - } - - public ValueExpression createValueExpression(Class expectedType) - throws ELException { - Node n = this.build(); - return new ValueExpressionImpl(this.expression, n, this.fnMapper, - this.varMapper, expectedType); - } - - public MethodExpression createMethodExpression(Class expectedReturnType, - Class[] expectedParamTypes) throws ELException { - Node n = this.build(); - if (n instanceof AstValue || n instanceof AstIdentifier) { - return new MethodExpressionImpl(expression, n, this.fnMapper, - this.varMapper, expectedReturnType, expectedParamTypes); - } else if (n instanceof AstLiteralExpression) { - return new MethodExpressionLiteral(expression, expectedReturnType, - expectedParamTypes); - } else { - throw new ELException("Not a Valid Method Expression: " - + expression); - } - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.io.StringReader; +import java.lang.ref.SoftReference; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.FunctionMapper; +import javax.el.MethodExpression; +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +import org.apache.el.MethodExpressionImpl; +import org.apache.el.MethodExpressionLiteral; +import org.apache.el.ValueExpressionImpl; +import org.apache.el.parser.AstCompositeExpression; +import org.apache.el.parser.AstDeferredExpression; +import org.apache.el.parser.AstDynamicExpression; +import org.apache.el.parser.AstFunction; +import org.apache.el.parser.AstIdentifier; +import org.apache.el.parser.AstLiteralExpression; +import org.apache.el.parser.AstValue; +import org.apache.el.parser.ELParser; +import org.apache.el.parser.Node; +import org.apache.el.parser.NodeVisitor; +import org.apache.el.parser.ParseException; +import org.apache.el.util.ConcurrentCache; +import org.apache.el.util.MessageFactory; + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public final class ExpressionBuilder implements NodeVisitor { + + private static final ConcurrentCache cache = new ConcurrentCache(5000); + + private FunctionMapper fnMapper; + + private VariableMapper varMapper; + + private String expression; + + /** + * + */ + public ExpressionBuilder(String expression, ELContext ctx) + throws ELException { + this.expression = expression; + + FunctionMapper ctxFn = ctx.getFunctionMapper(); + VariableMapper ctxVar = ctx.getVariableMapper(); + + if (ctxFn != null) { + this.fnMapper = new FunctionMapperFactory(ctxFn); + } + if (ctxVar != null) { + this.varMapper = new VariableMapperFactory(ctxVar); + } + } + + public final static Node createNode(String expr) throws ELException { + Node n = createNodeInternal(expr); + return n; + } + + private final static Node createNodeInternal(String expr) + throws ELException { + if (expr == null) { + throw new ELException(MessageFactory.get("error.null")); + } + + Node n = (Node) cache.get(expr); + if (n == null) { + try { + n = (new ELParser(new StringReader(expr))) + .CompositeExpression(); + + // validate composite expression + if (n instanceof AstCompositeExpression) { + int numChildren = n.jjtGetNumChildren(); + if (numChildren == 1) { + n = n.jjtGetChild(0); + } else { + Class type = null; + Node child = null; + for (int i = 0; i < numChildren; i++) { + child = n.jjtGetChild(i); + if (child instanceof AstLiteralExpression) + continue; + if (type == null) + type = child.getClass(); + else { + if (!type.equals(child.getClass())) { + throw new ELException(MessageFactory.get( + "error.mixed", expr)); + } + } + } + } + } + if (n instanceof AstDeferredExpression + || n instanceof AstDynamicExpression) { + n = n.jjtGetChild(0); + } + cache.put(expr, n); + } catch (ParseException pe) { + throw new ELException("Error Parsing: " + expr, pe); + } + } + return n; + } + + private void prepare(Node node) throws ELException { + try { + node.accept(this); + } catch (Exception e) { + throw (ELException) e; + } + if (this.fnMapper instanceof FunctionMapperFactory) { + this.fnMapper = ((FunctionMapperFactory) this.fnMapper).create(); + } + if (this.varMapper instanceof VariableMapperFactory) { + this.varMapper = ((VariableMapperFactory) this.varMapper).create(); + } + } + + private Node build() throws ELException { + Node n = createNodeInternal(this.expression); + this.prepare(n); + if (n instanceof AstDeferredExpression + || n instanceof AstDynamicExpression) { + n = n.jjtGetChild(0); + } + return n; + } + + /* + * (non-Javadoc) + * + * @see com.sun.el.parser.NodeVisitor#visit(com.sun.el.parser.Node) + */ + public void visit(Node node) throws ELException { + if (node instanceof AstFunction) { + + AstFunction funcNode = (AstFunction) node; + + if (this.fnMapper == null) { + throw new ELException(MessageFactory.get("error.fnMapper.null")); + } + Method m = fnMapper.resolveFunction(funcNode.getPrefix(), funcNode + .getLocalName()); + if (m == null) { + throw new ELException(MessageFactory.get( + "error.fnMapper.method", funcNode.getOutputName())); + } + int pcnt = m.getParameterTypes().length; + if (node.jjtGetNumChildren() != pcnt) { + throw new ELException(MessageFactory.get( + "error.fnMapper.paramcount", funcNode.getOutputName(), + "" + pcnt, "" + node.jjtGetNumChildren())); + } + } else if (node instanceof AstIdentifier && this.varMapper != null) { + String variable = ((AstIdentifier) node).getImage(); + + // simply capture it + this.varMapper.resolveVariable(variable); + } + } + + public ValueExpression createValueExpression(Class expectedType) + throws ELException { + Node n = this.build(); + return new ValueExpressionImpl(this.expression, n, this.fnMapper, + this.varMapper, expectedType); + } + + public MethodExpression createMethodExpression(Class expectedReturnType, + Class[] expectedParamTypes) throws ELException { + Node n = this.build(); + if (n instanceof AstValue || n instanceof AstIdentifier) { + return new MethodExpressionImpl(expression, n, this.fnMapper, + this.varMapper, expectedReturnType, expectedParamTypes); + } else if (n instanceof AstLiteralExpression) { + return new MethodExpressionLiteral(expression, expectedReturnType, + expectedParamTypes); + } else { + throw new ELException("Not a Valid Method Expression: " + + expression); + } + } +} diff --git a/java/org/apache/el/lang/FunctionMapperFactory.java b/java/org/apache/el/lang/FunctionMapperFactory.java index fe659c6ef..0c47dd459 100644 --- a/java/org/apache/el/lang/FunctionMapperFactory.java +++ b/java/org/apache/el/lang/FunctionMapperFactory.java @@ -1,58 +1,58 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.lang.reflect.Method; - -import javax.el.FunctionMapper; - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public class FunctionMapperFactory extends FunctionMapper { - - protected FunctionMapperImpl memento = null; - protected FunctionMapper target; - - public FunctionMapperFactory(FunctionMapper mapper) { - if (mapper == null) { - throw new NullPointerException("FunctionMapper target cannot be null"); - } - this.target = mapper; - } - - - /* (non-Javadoc) - * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, java.lang.String) - */ - public Method resolveFunction(String prefix, String localName) { - if (this.memento == null) { - this.memento = new FunctionMapperImpl(); - } - Method m = this.target.resolveFunction(prefix, localName); - if (m != null) { - this.memento.addFunction(prefix, localName, m); - } - return m; - } - - public FunctionMapper create() { - return this.memento; - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.lang.reflect.Method; + +import javax.el.FunctionMapper; + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public class FunctionMapperFactory extends FunctionMapper { + + protected FunctionMapperImpl memento = null; + protected FunctionMapper target; + + public FunctionMapperFactory(FunctionMapper mapper) { + if (mapper == null) { + throw new NullPointerException("FunctionMapper target cannot be null"); + } + this.target = mapper; + } + + + /* (non-Javadoc) + * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, java.lang.String) + */ + public Method resolveFunction(String prefix, String localName) { + if (this.memento == null) { + this.memento = new FunctionMapperImpl(); + } + Method m = this.target.resolveFunction(prefix, localName); + if (m != null) { + this.memento.addFunction(prefix, localName, m); + } + return m; + } + + public FunctionMapper create() { + return this.memento; + } + +} diff --git a/java/org/apache/el/lang/FunctionMapperImpl.java b/java/org/apache/el/lang/FunctionMapperImpl.java index c7e958704..dc02e28f2 100644 --- a/java/org/apache/el/lang/FunctionMapperImpl.java +++ b/java/org/apache/el/lang/FunctionMapperImpl.java @@ -1,182 +1,182 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import javax.el.FunctionMapper; - -import org.apache.el.util.ReflectionUtil; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public class FunctionMapperImpl extends FunctionMapper implements - Externalizable { - - private static final long serialVersionUID = 1L; - - protected Map functions = null; - - /* - * (non-Javadoc) - * - * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, - * java.lang.String) - */ - public Method resolveFunction(String prefix, String localName) { - if (this.functions != null) { - Function f = (Function) this.functions.get(prefix + ":" + localName); - return f.getMethod(); - } - return null; - } - - public void addFunction(String prefix, String localName, Method m) { - if (this.functions == null) { - this.functions = new HashMap(); - } - Function f = new Function(prefix, localName, m); - synchronized (this) { - this.functions.put(prefix+":"+localName, f); - } - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) - */ - public void writeExternal(ObjectOutput out) throws IOException { - out.writeObject(this.functions); - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#readExternal(java.io.ObjectInput) - */ - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.functions = (Map) in.readObject(); - } - - public static class Function implements Externalizable { - - protected transient Method m; - protected String owner; - protected String name; - protected String[] types; - protected String prefix; - protected String localName; - - /** - * - */ - public Function(String prefix, String localName, Method m) { - if (localName == null) { - throw new NullPointerException("LocalName cannot be null"); - } - if (m == null) { - throw new NullPointerException("Method cannot be null"); - } - this.prefix = prefix; - this.localName = localName; - this.m = m; - } - - public Function() { - // for serialization - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) - */ - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF((this.prefix != null) ? this.prefix : ""); - out.writeUTF(this.localName); - out.writeUTF(this.m.getDeclaringClass().getName()); - out.writeUTF(this.m.getName()); - out.writeObject(ReflectionUtil.toTypeNameArray(this.m.getParameterTypes())); - } - - /* - * (non-Javadoc) - * - * @see java.io.Externalizable#readExternal(java.io.ObjectInput) - */ - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - - this.prefix = in.readUTF(); - if ("".equals(this.prefix)) this.prefix = null; - this.localName = in.readUTF(); - this.owner = in.readUTF(); - this.name = in.readUTF(); - this.types = (String[]) in.readObject(); - } - - public Method getMethod() { - if (this.m == null) { - try { - Class t = Class.forName(this.owner); - Class[] p = ReflectionUtil.toTypeArray(this.types); - this.m = t.getMethod(this.name, p); - } catch (Exception e) { - e.printStackTrace(); - } - } - return this.m; - } - - public boolean matches(String prefix, String localName) { - if (this.prefix != null) { - if (prefix == null) return false; - if (!this.prefix.equals(prefix)) return false; - } - return this.localName.equals(localName); - } - - /* (non-Javadoc) - * @see java.lang.Object#equals(java.lang.Object) - */ - public boolean equals(Object obj) { - if (obj instanceof Function) { - return this.hashCode() == obj.hashCode(); - } - return false; - } - - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - public int hashCode() { - return (this.prefix + this.localName).hashCode(); - } - } - -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.el.FunctionMapper; + +import org.apache.el.util.ReflectionUtil; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public class FunctionMapperImpl extends FunctionMapper implements + Externalizable { + + private static final long serialVersionUID = 1L; + + protected Map functions = null; + + /* + * (non-Javadoc) + * + * @see javax.el.FunctionMapper#resolveFunction(java.lang.String, + * java.lang.String) + */ + public Method resolveFunction(String prefix, String localName) { + if (this.functions != null) { + Function f = (Function) this.functions.get(prefix + ":" + localName); + return f.getMethod(); + } + return null; + } + + public void addFunction(String prefix, String localName, Method m) { + if (this.functions == null) { + this.functions = new HashMap(); + } + Function f = new Function(prefix, localName, m); + synchronized (this) { + this.functions.put(prefix+":"+localName, f); + } + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) + */ + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(this.functions); + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#readExternal(java.io.ObjectInput) + */ + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.functions = (Map) in.readObject(); + } + + public static class Function implements Externalizable { + + protected transient Method m; + protected String owner; + protected String name; + protected String[] types; + protected String prefix; + protected String localName; + + /** + * + */ + public Function(String prefix, String localName, Method m) { + if (localName == null) { + throw new NullPointerException("LocalName cannot be null"); + } + if (m == null) { + throw new NullPointerException("Method cannot be null"); + } + this.prefix = prefix; + this.localName = localName; + this.m = m; + } + + public Function() { + // for serialization + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput) + */ + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF((this.prefix != null) ? this.prefix : ""); + out.writeUTF(this.localName); + out.writeUTF(this.m.getDeclaringClass().getName()); + out.writeUTF(this.m.getName()); + out.writeObject(ReflectionUtil.toTypeNameArray(this.m.getParameterTypes())); + } + + /* + * (non-Javadoc) + * + * @see java.io.Externalizable#readExternal(java.io.ObjectInput) + */ + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + + this.prefix = in.readUTF(); + if ("".equals(this.prefix)) this.prefix = null; + this.localName = in.readUTF(); + this.owner = in.readUTF(); + this.name = in.readUTF(); + this.types = (String[]) in.readObject(); + } + + public Method getMethod() { + if (this.m == null) { + try { + Class t = Class.forName(this.owner); + Class[] p = ReflectionUtil.toTypeArray(this.types); + this.m = t.getMethod(this.name, p); + } catch (Exception e) { + e.printStackTrace(); + } + } + return this.m; + } + + public boolean matches(String prefix, String localName) { + if (this.prefix != null) { + if (prefix == null) return false; + if (!this.prefix.equals(prefix)) return false; + } + return this.localName.equals(localName); + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + public boolean equals(Object obj) { + if (obj instanceof Function) { + return this.hashCode() == obj.hashCode(); + } + return false; + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + public int hashCode() { + return (this.prefix + this.localName).hashCode(); + } + } + +} diff --git a/java/org/apache/el/lang/VariableMapperFactory.java b/java/org/apache/el/lang/VariableMapperFactory.java index 1f37e4246..f74f4e7d5 100644 --- a/java/org/apache/el/lang/VariableMapperFactory.java +++ b/java/org/apache/el/lang/VariableMapperFactory.java @@ -1,52 +1,52 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -public class VariableMapperFactory extends VariableMapper { - - private final VariableMapper target; - private VariableMapper momento; - - public VariableMapperFactory(VariableMapper target) { - if (target == null) { - throw new NullPointerException("Target VariableMapper cannot be null"); - } - this.target = target; - } - - public VariableMapper create() { - return this.momento; - } - - public ValueExpression resolveVariable(String variable) { - ValueExpression expr = this.target.resolveVariable(variable); - if (expr != null) { - if (this.momento == null) { - this.momento = new VariableMapperImpl(); - } - this.momento.setVariable(variable, expr); - } - return expr; - } - - public ValueExpression setVariable(String variable, ValueExpression expression) { - throw new UnsupportedOperationException("Cannot Set Variables on Factory"); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +public class VariableMapperFactory extends VariableMapper { + + private final VariableMapper target; + private VariableMapper momento; + + public VariableMapperFactory(VariableMapper target) { + if (target == null) { + throw new NullPointerException("Target VariableMapper cannot be null"); + } + this.target = target; + } + + public VariableMapper create() { + return this.momento; + } + + public ValueExpression resolveVariable(String variable) { + ValueExpression expr = this.target.resolveVariable(variable); + if (expr != null) { + if (this.momento == null) { + this.momento = new VariableMapperImpl(); + } + this.momento.setVariable(variable, expr); + } + return expr; + } + + public ValueExpression setVariable(String variable, ValueExpression expression) { + throw new UnsupportedOperationException("Cannot Set Variables on Factory"); + } +} diff --git a/java/org/apache/el/lang/VariableMapperImpl.java b/java/org/apache/el/lang/VariableMapperImpl.java index 96868dad7..c1cf43706 100644 --- a/java/org/apache/el/lang/VariableMapperImpl.java +++ b/java/org/apache/el/lang/VariableMapperImpl.java @@ -1,55 +1,55 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.lang; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; -import java.util.HashMap; -import java.util.Map; - -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -public class VariableMapperImpl extends VariableMapper implements Externalizable { - - private static final long serialVersionUID = 1L; - - private Map vars = new HashMap(); - - public VariableMapperImpl() { - super(); - } - - public ValueExpression resolveVariable(String variable) { - return (ValueExpression) this.vars.get(variable); - } - - public ValueExpression setVariable(String variable, - ValueExpression expression) { - return (ValueExpression) this.vars.put(variable, expression); - } - - public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { - this.vars = (Map) in.readObject(); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeObject(this.vars); - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.lang; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; +import java.util.HashMap; +import java.util.Map; + +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +public class VariableMapperImpl extends VariableMapper implements Externalizable { + + private static final long serialVersionUID = 1L; + + private Map vars = new HashMap(); + + public VariableMapperImpl() { + super(); + } + + public ValueExpression resolveVariable(String variable) { + return (ValueExpression) this.vars.get(variable); + } + + public ValueExpression setVariable(String variable, + ValueExpression expression) { + return (ValueExpression) this.vars.put(variable, expression); + } + + public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { + this.vars = (Map) in.readObject(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeObject(this.vars); + } +} diff --git a/java/org/apache/el/parser/ArithmeticNode.java b/java/org/apache/el/parser/ArithmeticNode.java index 2c211b2b1..e831ee72f 100644 --- a/java/org/apache/el/parser/ArithmeticNode.java +++ b/java/org/apache/el/parser/ArithmeticNode.java @@ -1,41 +1,41 @@ -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public class ArithmeticNode extends SimpleNode { - - /** - * @param i - */ - public ArithmeticNode(int i) { - super(i); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return Number.class; - } -} +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public class ArithmeticNode extends SimpleNode { + + /** + * @param i + */ + public ArithmeticNode(int i) { + super(i); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return Number.class; + } +} diff --git a/java/org/apache/el/parser/AstAnd.java b/java/org/apache/el/parser/AstAnd.java index 91995db10..41f8e8fa2 100644 --- a/java/org/apache/el/parser/AstAnd.java +++ b/java/org/apache/el/parser/AstAnd.java @@ -1,30 +1,30 @@ -/* Generated By:JJTree: Do not edit this line. AstAnd.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstAnd extends BooleanNode { - public AstAnd(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj = children[0].getValue(ctx); - Boolean b = coerceToBoolean(obj); - if (!b.booleanValue()) { - return b; - } - obj = children[1].getValue(ctx); - b = coerceToBoolean(obj); - return b; - } -} +/* Generated By:JJTree: Do not edit this line. AstAnd.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstAnd extends BooleanNode { + public AstAnd(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj = children[0].getValue(ctx); + Boolean b = coerceToBoolean(obj); + if (!b.booleanValue()) { + return b; + } + obj = children[1].getValue(ctx); + b = coerceToBoolean(obj); + return b; + } +} diff --git a/java/org/apache/el/parser/AstBracketSuffix.java b/java/org/apache/el/parser/AstBracketSuffix.java index e5c833ca5..2734d833f 100644 --- a/java/org/apache/el/parser/AstBracketSuffix.java +++ b/java/org/apache/el/parser/AstBracketSuffix.java @@ -1,23 +1,23 @@ -/* Generated By:JJTree: Do not edit this line. AstBracketSuffix.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstBracketSuffix extends SimpleNode { - public AstBracketSuffix(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.children[0].getValue(ctx); - } -} +/* Generated By:JJTree: Do not edit this line. AstBracketSuffix.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstBracketSuffix extends SimpleNode { + public AstBracketSuffix(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.children[0].getValue(ctx); + } +} diff --git a/java/org/apache/el/parser/AstChoice.java b/java/org/apache/el/parser/AstChoice.java index 3fbcaf57f..02c1307ef 100644 --- a/java/org/apache/el/parser/AstChoice.java +++ b/java/org/apache/el/parser/AstChoice.java @@ -1,31 +1,31 @@ -/* Generated By:JJTree: Do not edit this line. AstChoice.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstChoice extends SimpleNode { - public AstChoice(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - Object val = this.getValue(ctx); - return (val != null) ? val.getClass() : null; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Boolean b0 = coerceToBoolean(obj0); - return this.children[((b0.booleanValue() ? 1 : 2))].getValue(ctx); - } -} +/* Generated By:JJTree: Do not edit this line. AstChoice.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstChoice extends SimpleNode { + public AstChoice(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + Object val = this.getValue(ctx); + return (val != null) ? val.getClass() : null; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Boolean b0 = coerceToBoolean(obj0); + return this.children[((b0.booleanValue() ? 1 : 2))].getValue(ctx); + } +} diff --git a/java/org/apache/el/parser/AstCompositeExpression.java b/java/org/apache/el/parser/AstCompositeExpression.java index 2f8e97c0d..db3d7eb62 100644 --- a/java/org/apache/el/parser/AstCompositeExpression.java +++ b/java/org/apache/el/parser/AstCompositeExpression.java @@ -1,39 +1,39 @@ -/* Generated By:JJTree: Do not edit this line. AstCompositeExpression.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstCompositeExpression extends SimpleNode { - - public AstCompositeExpression(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return String.class; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - StringBuffer sb = new StringBuffer(16); - Object obj = null; - if (this.children != null) { - for (int i = 0; i < this.children.length; i++) { - obj = this.children[i].getValue(ctx); - if (obj != null) { - sb.append(obj); - } - } - } - return sb.toString(); - } -} +/* Generated By:JJTree: Do not edit this line. AstCompositeExpression.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstCompositeExpression extends SimpleNode { + + public AstCompositeExpression(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return String.class; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + StringBuffer sb = new StringBuffer(16); + Object obj = null; + if (this.children != null) { + for (int i = 0; i < this.children.length; i++) { + obj = this.children[i].getValue(ctx); + if (obj != null) { + sb.append(obj); + } + } + } + return sb.toString(); + } +} diff --git a/java/org/apache/el/parser/AstDeferredExpression.java b/java/org/apache/el/parser/AstDeferredExpression.java index 0db0c4404..d965b8abc 100644 --- a/java/org/apache/el/parser/AstDeferredExpression.java +++ b/java/org/apache/el/parser/AstDeferredExpression.java @@ -1,38 +1,38 @@ -/* Generated By:JJTree: Do not edit this line. AstDeferredExpression.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstDeferredExpression extends SimpleNode { - public AstDeferredExpression(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return this.children[0].getType(ctx); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.children[0].getValue(ctx); - } - - public boolean isReadOnly(EvaluationContext ctx) - throws ELException { - return this.children[0].isReadOnly(ctx); - } - - public void setValue(EvaluationContext ctx, Object value) - throws ELException { - this.children[0].setValue(ctx, value); - } -} +/* Generated By:JJTree: Do not edit this line. AstDeferredExpression.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstDeferredExpression extends SimpleNode { + public AstDeferredExpression(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return this.children[0].getType(ctx); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.children[0].getValue(ctx); + } + + public boolean isReadOnly(EvaluationContext ctx) + throws ELException { + return this.children[0].isReadOnly(ctx); + } + + public void setValue(EvaluationContext ctx, Object value) + throws ELException { + this.children[0].setValue(ctx, value); + } +} diff --git a/java/org/apache/el/parser/AstDiv.java b/java/org/apache/el/parser/AstDiv.java index e54f0d841..ca0095d63 100644 --- a/java/org/apache/el/parser/AstDiv.java +++ b/java/org/apache/el/parser/AstDiv.java @@ -1,26 +1,26 @@ -/* Generated By:JJTree: Do not edit this line. AstDiv.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.ELArithmetic; -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstDiv extends ArithmeticNode { - public AstDiv(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return ELArithmetic.divide(obj0, obj1); - } -} +/* Generated By:JJTree: Do not edit this line. AstDiv.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.ELArithmetic; +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstDiv extends ArithmeticNode { + public AstDiv(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return ELArithmetic.divide(obj0, obj1); + } +} diff --git a/java/org/apache/el/parser/AstDotSuffix.java b/java/org/apache/el/parser/AstDotSuffix.java index 7548a7a76..6edcb88c8 100644 --- a/java/org/apache/el/parser/AstDotSuffix.java +++ b/java/org/apache/el/parser/AstDotSuffix.java @@ -1,23 +1,23 @@ -/* Generated By:JJTree: Do not edit this line. AstDotSuffix.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstDotSuffix extends SimpleNode { - public AstDotSuffix(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.image; - } -} +/* Generated By:JJTree: Do not edit this line. AstDotSuffix.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstDotSuffix extends SimpleNode { + public AstDotSuffix(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.image; + } +} diff --git a/java/org/apache/el/parser/AstDynamicExpression.java b/java/org/apache/el/parser/AstDynamicExpression.java index 9e6068f5b..0004a44b7 100644 --- a/java/org/apache/el/parser/AstDynamicExpression.java +++ b/java/org/apache/el/parser/AstDynamicExpression.java @@ -1,38 +1,38 @@ -/* Generated By:JJTree: Do not edit this line. AstDynamicExpression.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstDynamicExpression extends SimpleNode { - public AstDynamicExpression(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return this.children[0].getType(ctx); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.children[0].getValue(ctx); - } - - public boolean isReadOnly(EvaluationContext ctx) - throws ELException { - return this.children[0].isReadOnly(ctx); - } - - public void setValue(EvaluationContext ctx, Object value) - throws ELException { - this.children[0].setValue(ctx, value); - } -} +/* Generated By:JJTree: Do not edit this line. AstDynamicExpression.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstDynamicExpression extends SimpleNode { + public AstDynamicExpression(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return this.children[0].getType(ctx); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.children[0].getValue(ctx); + } + + public boolean isReadOnly(EvaluationContext ctx) + throws ELException { + return this.children[0].isReadOnly(ctx); + } + + public void setValue(EvaluationContext ctx, Object value) + throws ELException { + this.children[0].setValue(ctx, value); + } +} diff --git a/java/org/apache/el/parser/AstEmpty.java b/java/org/apache/el/parser/AstEmpty.java index 2f7831666..5416304a4 100644 --- a/java/org/apache/el/parser/AstEmpty.java +++ b/java/org/apache/el/parser/AstEmpty.java @@ -1,43 +1,43 @@ -/* Generated By:JJTree: Do not edit this line. AstEmpty.java */ - -package org.apache.el.parser; - -import java.util.Collection; -import java.util.Map; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstEmpty extends SimpleNode { - public AstEmpty(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return Boolean.class; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj = this.children[0].getValue(ctx); - if (obj == null) { - return Boolean.TRUE; - } else if (obj instanceof String) { - return Boolean.valueOf(((String) obj).length() == 0); - } else if (obj instanceof Object[]) { - return Boolean.valueOf(((Object[]) obj).length == 0); - } else if (obj instanceof Collection) { - return Boolean.valueOf(((Collection) obj).isEmpty()); - } else if (obj instanceof Map) { - return Boolean.valueOf(((Map) obj).isEmpty()); - } - return Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstEmpty.java */ + +package org.apache.el.parser; + +import java.util.Collection; +import java.util.Map; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstEmpty extends SimpleNode { + public AstEmpty(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return Boolean.class; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj = this.children[0].getValue(ctx); + if (obj == null) { + return Boolean.TRUE; + } else if (obj instanceof String) { + return Boolean.valueOf(((String) obj).length() == 0); + } else if (obj instanceof Object[]) { + return Boolean.valueOf(((Object[]) obj).length == 0); + } else if (obj instanceof Collection) { + return Boolean.valueOf(((Collection) obj).isEmpty()); + } else if (obj instanceof Map) { + return Boolean.valueOf(((Map) obj).isEmpty()); + } + return Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstEqual.java b/java/org/apache/el/parser/AstEqual.java index f1236585f..b550311ba 100644 --- a/java/org/apache/el/parser/AstEqual.java +++ b/java/org/apache/el/parser/AstEqual.java @@ -1,25 +1,25 @@ -/* Generated By:JJTree: Do not edit this line. AstEqual.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstEqual extends BooleanNode { - public AstEqual(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return Boolean.valueOf(equals(obj0, obj1)); - } -} +/* Generated By:JJTree: Do not edit this line. AstEqual.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstEqual extends BooleanNode { + public AstEqual(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return Boolean.valueOf(equals(obj0, obj1)); + } +} diff --git a/java/org/apache/el/parser/AstFalse.java b/java/org/apache/el/parser/AstFalse.java index 5e065fe04..0477953d3 100644 --- a/java/org/apache/el/parser/AstFalse.java +++ b/java/org/apache/el/parser/AstFalse.java @@ -1,23 +1,23 @@ -/* Generated By:JJTree: Do not edit this line. AstFalse.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstFalse extends BooleanNode { - public AstFalse(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstFalse.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstFalse extends BooleanNode { + public AstFalse(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstFloatingPoint.java b/java/org/apache/el/parser/AstFloatingPoint.java index 3af6a85ba..2e1d978cf 100644 --- a/java/org/apache/el/parser/AstFloatingPoint.java +++ b/java/org/apache/el/parser/AstFloatingPoint.java @@ -1,43 +1,43 @@ -/* Generated By:JJTree: Do not edit this line. AstFloatingPoint.java */ - -package org.apache.el.parser; - -import java.math.BigDecimal; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstFloatingPoint extends SimpleNode { - public AstFloatingPoint(int id) { - super(id); - } - - private Number number; - - public Number getFloatingPoint() { - if (this.number == null) { - try { - this.number = new Double(this.image); - } catch (ArithmeticException e0) { - this.number = new BigDecimal(this.image); - } - } - return this.number; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.getFloatingPoint(); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return this.getFloatingPoint().getClass(); - } -} +/* Generated By:JJTree: Do not edit this line. AstFloatingPoint.java */ + +package org.apache.el.parser; + +import java.math.BigDecimal; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstFloatingPoint extends SimpleNode { + public AstFloatingPoint(int id) { + super(id); + } + + private Number number; + + public Number getFloatingPoint() { + if (this.number == null) { + try { + this.number = new Double(this.image); + } catch (ArithmeticException e0) { + this.number = new BigDecimal(this.image); + } + } + return this.number; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.getFloatingPoint(); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return this.getFloatingPoint().getClass(); + } +} diff --git a/java/org/apache/el/parser/AstFunction.java b/java/org/apache/el/parser/AstFunction.java index 208909f74..92b563b0c 100644 --- a/java/org/apache/el/parser/AstFunction.java +++ b/java/org/apache/el/parser/AstFunction.java @@ -1,118 +1,118 @@ -/* Generated By:JJTree: Do not edit this line. AstFunction.java */ - -package org.apache.el.parser; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.el.ELException; -import javax.el.FunctionMapper; - -import org.apache.el.lang.EvaluationContext; -import org.apache.el.util.MessageFactory; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstFunction extends SimpleNode { - - protected String localName = ""; - - protected String prefix = ""; - - public AstFunction(int id) { - super(id); - } - - public String getLocalName() { - return localName; - } - - public String getOutputName() { - if (this.prefix == null) { - return this.localName; - } else { - return this.prefix + ":" + this.localName; - } - } - - public String getPrefix() { - return prefix; - } - - public Class getType(EvaluationContext ctx) - throws ELException { - - FunctionMapper fnMapper = ctx.getFunctionMapper(); - - // quickly validate again for this request - if (fnMapper == null) { - throw new ELException(MessageFactory.get("error.fnMapper.null")); - } - Method m = fnMapper.resolveFunction(this.prefix, this.localName); - if (m == null) { - throw new ELException(MessageFactory.get("error.fnMapper.method", - this.getOutputName())); - } - return m.getReturnType(); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - - FunctionMapper fnMapper = ctx.getFunctionMapper(); - - // quickly validate again for this request - if (fnMapper == null) { - throw new ELException(MessageFactory.get("error.fnMapper.null")); - } - Method m = fnMapper.resolveFunction(this.prefix, this.localName); - if (m == null) { - throw new ELException(MessageFactory.get("error.fnMapper.method", - this.getOutputName())); - } - - Class[] paramTypes = m.getParameterTypes(); - Object[] params = null; - Object result = null; - int numParams = this.jjtGetNumChildren(); - if (numParams > 0) { - params = new Object[numParams]; - try { - for (int i = 0; i < numParams; i++) { - params[i] = this.children[i].getValue(ctx); - params[i] = coerceToType(params[i], paramTypes[i]); - } - } catch (ELException ele) { - throw new ELException(MessageFactory.get("error.function", this - .getOutputName()), ele); - } - } - try { - result = m.invoke(null, params); - } catch (IllegalAccessException iae) { - throw new ELException(MessageFactory.get("error.function", this - .getOutputName()), iae); - } catch (InvocationTargetException ite) { - throw new ELException(MessageFactory.get("error.function", this - .getOutputName()), ite.getCause()); - } - return result; - } - - public void setLocalName(String localName) { - this.localName = localName; - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - } - - - public String toString() - { - return ELParserTreeConstants.jjtNodeName[id] + "[" + this.getOutputName() + "]"; - } -} +/* Generated By:JJTree: Do not edit this line. AstFunction.java */ + +package org.apache.el.parser; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.el.ELException; +import javax.el.FunctionMapper; + +import org.apache.el.lang.EvaluationContext; +import org.apache.el.util.MessageFactory; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstFunction extends SimpleNode { + + protected String localName = ""; + + protected String prefix = ""; + + public AstFunction(int id) { + super(id); + } + + public String getLocalName() { + return localName; + } + + public String getOutputName() { + if (this.prefix == null) { + return this.localName; + } else { + return this.prefix + ":" + this.localName; + } + } + + public String getPrefix() { + return prefix; + } + + public Class getType(EvaluationContext ctx) + throws ELException { + + FunctionMapper fnMapper = ctx.getFunctionMapper(); + + // quickly validate again for this request + if (fnMapper == null) { + throw new ELException(MessageFactory.get("error.fnMapper.null")); + } + Method m = fnMapper.resolveFunction(this.prefix, this.localName); + if (m == null) { + throw new ELException(MessageFactory.get("error.fnMapper.method", + this.getOutputName())); + } + return m.getReturnType(); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + + FunctionMapper fnMapper = ctx.getFunctionMapper(); + + // quickly validate again for this request + if (fnMapper == null) { + throw new ELException(MessageFactory.get("error.fnMapper.null")); + } + Method m = fnMapper.resolveFunction(this.prefix, this.localName); + if (m == null) { + throw new ELException(MessageFactory.get("error.fnMapper.method", + this.getOutputName())); + } + + Class[] paramTypes = m.getParameterTypes(); + Object[] params = null; + Object result = null; + int numParams = this.jjtGetNumChildren(); + if (numParams > 0) { + params = new Object[numParams]; + try { + for (int i = 0; i < numParams; i++) { + params[i] = this.children[i].getValue(ctx); + params[i] = coerceToType(params[i], paramTypes[i]); + } + } catch (ELException ele) { + throw new ELException(MessageFactory.get("error.function", this + .getOutputName()), ele); + } + } + try { + result = m.invoke(null, params); + } catch (IllegalAccessException iae) { + throw new ELException(MessageFactory.get("error.function", this + .getOutputName()), iae); + } catch (InvocationTargetException ite) { + throw new ELException(MessageFactory.get("error.function", this + .getOutputName()), ite.getCause()); + } + return result; + } + + public void setLocalName(String localName) { + this.localName = localName; + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + } + + + public String toString() + { + return ELParserTreeConstants.jjtNodeName[id] + "[" + this.getOutputName() + "]"; + } +} diff --git a/java/org/apache/el/parser/AstGreaterThan.java b/java/org/apache/el/parser/AstGreaterThan.java index 469e86fe2..9c952c589 100644 --- a/java/org/apache/el/parser/AstGreaterThan.java +++ b/java/org/apache/el/parser/AstGreaterThan.java @@ -1,31 +1,31 @@ -/* Generated By:JJTree: Do not edit this line. AstGreaterThan.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstGreaterThan extends BooleanNode { - public AstGreaterThan(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - if (obj0 == null) { - return Boolean.FALSE; - } - Object obj1 = this.children[1].getValue(ctx); - if (obj1 == null) { - return Boolean.FALSE; - } - return (compare(obj0, obj1) > 0) ? Boolean.TRUE : Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstGreaterThan.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstGreaterThan extends BooleanNode { + public AstGreaterThan(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + if (obj0 == null) { + return Boolean.FALSE; + } + Object obj1 = this.children[1].getValue(ctx); + if (obj1 == null) { + return Boolean.FALSE; + } + return (compare(obj0, obj1) > 0) ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstGreaterThanEqual.java b/java/org/apache/el/parser/AstGreaterThanEqual.java index 8417d08b2..6704a2b98 100644 --- a/java/org/apache/el/parser/AstGreaterThanEqual.java +++ b/java/org/apache/el/parser/AstGreaterThanEqual.java @@ -1,31 +1,31 @@ -/* Generated By:JJTree: Do not edit this line. AstGreaterThanEqual.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public final class AstGreaterThanEqual extends BooleanNode { - public AstGreaterThanEqual(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - if (obj0 == obj1) { - return Boolean.TRUE; - } - if (obj0 == null || obj1 == null) { - return Boolean.FALSE; - } - return (compare(obj0, obj1) >= 0) ? Boolean.TRUE : Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstGreaterThanEqual.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public final class AstGreaterThanEqual extends BooleanNode { + public AstGreaterThanEqual(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + if (obj0 == obj1) { + return Boolean.TRUE; + } + if (obj0 == null || obj1 == null) { + return Boolean.FALSE; + } + return (compare(obj0, obj1) >= 0) ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstIdentifier.java b/java/org/apache/el/parser/AstIdentifier.java index a8a2127e4..eb8c0e17b 100644 --- a/java/org/apache/el/parser/AstIdentifier.java +++ b/java/org/apache/el/parser/AstIdentifier.java @@ -1,138 +1,138 @@ -/* Generated By:JJTree: Do not edit this line. AstIdentifier.java */ - -package org.apache.el.parser; - -import javax.el.ELException; -import javax.el.MethodExpression; -import javax.el.MethodInfo; -import javax.el.MethodNotFoundException; -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public final class AstIdentifier extends SimpleNode { - public AstIdentifier(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) throws ELException { - VariableMapper varMapper = ctx.getVariableMapper(); - if (varMapper != null) { - ValueExpression expr = varMapper.resolveVariable(this.image); - if (expr != null) { - return expr.getType(ctx.getELContext()); - } - } - ctx.setPropertyResolved(false); - return ctx.getELResolver().getType(ctx, null, this.image); - } - - public Object getValue(EvaluationContext ctx) throws ELException { - VariableMapper varMapper = ctx.getVariableMapper(); - if (varMapper != null) { - ValueExpression expr = varMapper.resolveVariable(this.image); - if (expr != null) { - return expr.getValue(ctx.getELContext()); - } - } - ctx.setPropertyResolved(false); - return ctx.getELResolver().getValue(ctx, null, this.image); - } - - public boolean isReadOnly(EvaluationContext ctx) throws ELException { - VariableMapper varMapper = ctx.getVariableMapper(); - if (varMapper != null) { - ValueExpression expr = varMapper.resolveVariable(this.image); - if (expr != null) { - return expr.isReadOnly(ctx.getELContext()); - } - } - ctx.setPropertyResolved(false); - return ctx.getELResolver().isReadOnly(ctx, null, this.image); - } - - public void setValue(EvaluationContext ctx, Object value) - throws ELException { - VariableMapper varMapper = ctx.getVariableMapper(); - if (varMapper != null) { - ValueExpression expr = varMapper.resolveVariable(this.image); - if (expr != null) { - expr.setValue(ctx.getELContext(), value); - return; - } - } - ctx.setPropertyResolved(false); - ctx.getELResolver().setValue(ctx, null, this.image, value); - } - - private final Object invokeTarget(EvaluationContext ctx, Object target, - Object[] paramValues) throws ELException { - if (target instanceof MethodExpression) { - MethodExpression me = (MethodExpression) target; - return me.invoke(ctx.getELContext(), paramValues); - } else if (target == null) { - throw new MethodNotFoundException("Identity '" + this.image - + "' was null and was unable to invoke"); - } else { - throw new ELException( - "Identity '" - + this.image - + "' does not reference a MethodExpression instance, returned type: " - + target.getClass().getName()); - } - } - - public Object invoke(EvaluationContext ctx, Class[] paramTypes, - Object[] paramValues) throws ELException { - return this.getMethodExpression(ctx).invoke(ctx.getELContext(), paramValues); - } - - - public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) - throws ELException { - return this.getMethodExpression(ctx).getMethodInfo(ctx.getELContext()); - } - - private final MethodExpression getMethodExpression(EvaluationContext ctx) - throws ELException { - Object obj = null; - - // case A: ValueExpression exists, getValue which must - // be a MethodExpression - VariableMapper varMapper = ctx.getVariableMapper(); - ValueExpression ve = null; - if (varMapper != null) { - ve = varMapper.resolveVariable(this.image); - if (ve != null) { - obj = ve.getValue(ctx); - } - } - - // case B: evaluate the identity against the ELResolver, again, must be - // a MethodExpression to be able to invoke - if (ve == null) { - ctx.setPropertyResolved(false); - obj = ctx.getELResolver().getValue(ctx, null, this.image); - } - - // finally provide helpful hints - if (obj instanceof MethodExpression) { - return (MethodExpression) obj; - } else if (obj == null) { - throw new MethodNotFoundException("Identity '" + this.image - + "' was null and was unable to invoke"); - } else { - throw new ELException( - "Identity '" - + this.image - + "' does not reference a MethodExpression instance, returned type: " - + obj.getClass().getName()); - } - } -} +/* Generated By:JJTree: Do not edit this line. AstIdentifier.java */ + +package org.apache.el.parser; + +import javax.el.ELException; +import javax.el.MethodExpression; +import javax.el.MethodInfo; +import javax.el.MethodNotFoundException; +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public final class AstIdentifier extends SimpleNode { + public AstIdentifier(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) throws ELException { + VariableMapper varMapper = ctx.getVariableMapper(); + if (varMapper != null) { + ValueExpression expr = varMapper.resolveVariable(this.image); + if (expr != null) { + return expr.getType(ctx.getELContext()); + } + } + ctx.setPropertyResolved(false); + return ctx.getELResolver().getType(ctx, null, this.image); + } + + public Object getValue(EvaluationContext ctx) throws ELException { + VariableMapper varMapper = ctx.getVariableMapper(); + if (varMapper != null) { + ValueExpression expr = varMapper.resolveVariable(this.image); + if (expr != null) { + return expr.getValue(ctx.getELContext()); + } + } + ctx.setPropertyResolved(false); + return ctx.getELResolver().getValue(ctx, null, this.image); + } + + public boolean isReadOnly(EvaluationContext ctx) throws ELException { + VariableMapper varMapper = ctx.getVariableMapper(); + if (varMapper != null) { + ValueExpression expr = varMapper.resolveVariable(this.image); + if (expr != null) { + return expr.isReadOnly(ctx.getELContext()); + } + } + ctx.setPropertyResolved(false); + return ctx.getELResolver().isReadOnly(ctx, null, this.image); + } + + public void setValue(EvaluationContext ctx, Object value) + throws ELException { + VariableMapper varMapper = ctx.getVariableMapper(); + if (varMapper != null) { + ValueExpression expr = varMapper.resolveVariable(this.image); + if (expr != null) { + expr.setValue(ctx.getELContext(), value); + return; + } + } + ctx.setPropertyResolved(false); + ctx.getELResolver().setValue(ctx, null, this.image, value); + } + + private final Object invokeTarget(EvaluationContext ctx, Object target, + Object[] paramValues) throws ELException { + if (target instanceof MethodExpression) { + MethodExpression me = (MethodExpression) target; + return me.invoke(ctx.getELContext(), paramValues); + } else if (target == null) { + throw new MethodNotFoundException("Identity '" + this.image + + "' was null and was unable to invoke"); + } else { + throw new ELException( + "Identity '" + + this.image + + "' does not reference a MethodExpression instance, returned type: " + + target.getClass().getName()); + } + } + + public Object invoke(EvaluationContext ctx, Class[] paramTypes, + Object[] paramValues) throws ELException { + return this.getMethodExpression(ctx).invoke(ctx.getELContext(), paramValues); + } + + + public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) + throws ELException { + return this.getMethodExpression(ctx).getMethodInfo(ctx.getELContext()); + } + + private final MethodExpression getMethodExpression(EvaluationContext ctx) + throws ELException { + Object obj = null; + + // case A: ValueExpression exists, getValue which must + // be a MethodExpression + VariableMapper varMapper = ctx.getVariableMapper(); + ValueExpression ve = null; + if (varMapper != null) { + ve = varMapper.resolveVariable(this.image); + if (ve != null) { + obj = ve.getValue(ctx); + } + } + + // case B: evaluate the identity against the ELResolver, again, must be + // a MethodExpression to be able to invoke + if (ve == null) { + ctx.setPropertyResolved(false); + obj = ctx.getELResolver().getValue(ctx, null, this.image); + } + + // finally provide helpful hints + if (obj instanceof MethodExpression) { + return (MethodExpression) obj; + } else if (obj == null) { + throw new MethodNotFoundException("Identity '" + this.image + + "' was null and was unable to invoke"); + } else { + throw new ELException( + "Identity '" + + this.image + + "' does not reference a MethodExpression instance, returned type: " + + obj.getClass().getName()); + } + } +} diff --git a/java/org/apache/el/parser/AstInteger.java b/java/org/apache/el/parser/AstInteger.java index e8272c66b..4133a7fdd 100644 --- a/java/org/apache/el/parser/AstInteger.java +++ b/java/org/apache/el/parser/AstInteger.java @@ -1,43 +1,43 @@ -/* Generated By:JJTree: Do not edit this line. AstInteger.java */ - -package org.apache.el.parser; - -import java.math.BigInteger; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstInteger extends SimpleNode { - public AstInteger(int id) { - super(id); - } - - private Number number; - - protected Number getInteger() { - if (this.number == null) { - try { - this.number = new Long(this.image); - } catch (ArithmeticException e1) { - this.number = new BigInteger(this.image); - } - } - return number; - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return this.getInteger().getClass(); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.getInteger(); - } -} +/* Generated By:JJTree: Do not edit this line. AstInteger.java */ + +package org.apache.el.parser; + +import java.math.BigInteger; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstInteger extends SimpleNode { + public AstInteger(int id) { + super(id); + } + + private Number number; + + protected Number getInteger() { + if (this.number == null) { + try { + this.number = new Long(this.image); + } catch (ArithmeticException e1) { + this.number = new BigInteger(this.image); + } + } + return number; + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return this.getInteger().getClass(); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.getInteger(); + } +} diff --git a/java/org/apache/el/parser/AstLessThan.java b/java/org/apache/el/parser/AstLessThan.java index 558ed7de2..6020ed2db 100644 --- a/java/org/apache/el/parser/AstLessThan.java +++ b/java/org/apache/el/parser/AstLessThan.java @@ -1,31 +1,31 @@ -/* Generated By:JJTree: Do not edit this line. AstLessThan.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstLessThan extends BooleanNode { - public AstLessThan(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - if (obj0 == null) { - return Boolean.FALSE; - } - Object obj1 = this.children[1].getValue(ctx); - if (obj1 == null) { - return Boolean.FALSE; - } - return (compare(obj0, obj1) < 0) ? Boolean.TRUE : Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstLessThan.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstLessThan extends BooleanNode { + public AstLessThan(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + if (obj0 == null) { + return Boolean.FALSE; + } + Object obj1 = this.children[1].getValue(ctx); + if (obj1 == null) { + return Boolean.FALSE; + } + return (compare(obj0, obj1) < 0) ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstLessThanEqual.java b/java/org/apache/el/parser/AstLessThanEqual.java index 49a36bcc1..3b5c582db 100644 --- a/java/org/apache/el/parser/AstLessThanEqual.java +++ b/java/org/apache/el/parser/AstLessThanEqual.java @@ -1,31 +1,31 @@ -/* Generated By:JJTree: Do not edit this line. AstLessThanEqual.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public final class AstLessThanEqual extends BooleanNode { - public AstLessThanEqual(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - if (obj0 == obj1) { - return Boolean.TRUE; - } - if (obj0 == null || obj1 == null) { - return Boolean.FALSE; - } - return (compare(obj0, obj1) <= 0) ? Boolean.TRUE : Boolean.FALSE; - } -} +/* Generated By:JJTree: Do not edit this line. AstLessThanEqual.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public final class AstLessThanEqual extends BooleanNode { + public AstLessThanEqual(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + if (obj0 == obj1) { + return Boolean.TRUE; + } + if (obj0 == null || obj1 == null) { + return Boolean.FALSE; + } + return (compare(obj0, obj1) <= 0) ? Boolean.TRUE : Boolean.FALSE; + } +} diff --git a/java/org/apache/el/parser/AstLiteralExpression.java b/java/org/apache/el/parser/AstLiteralExpression.java index 424a340cc..cd83c2cdf 100644 --- a/java/org/apache/el/parser/AstLiteralExpression.java +++ b/java/org/apache/el/parser/AstLiteralExpression.java @@ -1,48 +1,48 @@ -/* Generated By:JJTree: Do not edit this line. AstLiteralExpression.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public final class AstLiteralExpression extends SimpleNode { - public AstLiteralExpression(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) throws ELException { - return String.class; - } - - public Object getValue(EvaluationContext ctx) throws ELException { - return this.image; - } - - public void setImage(String image) { - if (image.indexOf('\\') == -1) { - this.image = image; - return; - } - int size = image.length(); - StringBuffer buf = new StringBuffer(size); - for (int i = 0; i < size; i++) { - char c = image.charAt(i); - if (c == '\\' && i + 1 < size) { - char c1 = image.charAt(i + 1); - if (c1 == '\\' || c1 == '"' || c1 == '\'' || c1 == '#' - || c1 == '$') { - c = c1; - i++; - } - } - buf.append(c); - } - this.image = buf.toString(); - } -} +/* Generated By:JJTree: Do not edit this line. AstLiteralExpression.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public final class AstLiteralExpression extends SimpleNode { + public AstLiteralExpression(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) throws ELException { + return String.class; + } + + public Object getValue(EvaluationContext ctx) throws ELException { + return this.image; + } + + public void setImage(String image) { + if (image.indexOf('\\') == -1) { + this.image = image; + return; + } + int size = image.length(); + StringBuffer buf = new StringBuffer(size); + for (int i = 0; i < size; i++) { + char c = image.charAt(i); + if (c == '\\' && i + 1 < size) { + char c1 = image.charAt(i + 1); + if (c1 == '\\' || c1 == '"' || c1 == '\'' || c1 == '#' + || c1 == '$') { + c = c1; + i++; + } + } + buf.append(c); + } + this.image = buf.toString(); + } +} diff --git a/java/org/apache/el/parser/AstMinus.java b/java/org/apache/el/parser/AstMinus.java index ce1614dbc..55268045a 100644 --- a/java/org/apache/el/parser/AstMinus.java +++ b/java/org/apache/el/parser/AstMinus.java @@ -1,26 +1,26 @@ -/* Generated By:JJTree: Do not edit this line. AstMinus.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.ELArithmetic; -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstMinus extends ArithmeticNode { - public AstMinus(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return ELArithmetic.subtract(obj0, obj1); - } -} +/* Generated By:JJTree: Do not edit this line. AstMinus.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.ELArithmetic; +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstMinus extends ArithmeticNode { + public AstMinus(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return ELArithmetic.subtract(obj0, obj1); + } +} diff --git a/java/org/apache/el/parser/AstMod.java b/java/org/apache/el/parser/AstMod.java index 68d082fe2..b3b2deb52 100644 --- a/java/org/apache/el/parser/AstMod.java +++ b/java/org/apache/el/parser/AstMod.java @@ -1,26 +1,26 @@ -/* Generated By:JJTree: Do not edit this line. AstMod.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.ELArithmetic; -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstMod extends ArithmeticNode { - public AstMod(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return ELArithmetic.mod(obj0, obj1); - } -} +/* Generated By:JJTree: Do not edit this line. AstMod.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.ELArithmetic; +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstMod extends ArithmeticNode { + public AstMod(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return ELArithmetic.mod(obj0, obj1); + } +} diff --git a/java/org/apache/el/parser/AstMult.java b/java/org/apache/el/parser/AstMult.java index 4da7e6a1a..6b3aefee6 100644 --- a/java/org/apache/el/parser/AstMult.java +++ b/java/org/apache/el/parser/AstMult.java @@ -1,26 +1,26 @@ -/* Generated By:JJTree: Do not edit this line. AstMult.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.ELArithmetic; -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstMult extends ArithmeticNode { - public AstMult(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return ELArithmetic.multiply(obj0, obj1); - } -} +/* Generated By:JJTree: Do not edit this line. AstMult.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.ELArithmetic; +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstMult extends ArithmeticNode { + public AstMult(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return ELArithmetic.multiply(obj0, obj1); + } +} diff --git a/java/org/apache/el/parser/AstNegative.java b/java/org/apache/el/parser/AstNegative.java index e287c684a..d7609d233 100644 --- a/java/org/apache/el/parser/AstNegative.java +++ b/java/org/apache/el/parser/AstNegative.java @@ -1,68 +1,68 @@ -/* Generated By:JJTree: Do not edit this line. AstNegative.java */ - -package org.apache.el.parser; - -import java.math.BigDecimal; -import java.math.BigInteger; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstNegative extends SimpleNode { - public AstNegative(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return Number.class; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj = this.children[0].getValue(ctx); - - if (obj == null) { - return new Long(0); - } - if (obj instanceof BigDecimal) { - return ((BigDecimal) obj).negate(); - } - if (obj instanceof BigInteger) { - return ((BigInteger) obj).negate(); - } - if (obj instanceof String) { - if (isStringFloat((String) obj)) { - return new Double(-Double.parseDouble((String) obj)); - } - return new Long(-Long.parseLong((String) obj)); - } - Class type = obj.getClass(); - if (obj instanceof Long || Long.TYPE == type) { - return new Long(-((Long) obj).longValue()); - } - if (obj instanceof Double || Double.TYPE == type) { - return new Double(-((Double) obj).doubleValue()); - } - if (obj instanceof Integer || Integer.TYPE == type) { - return new Integer(-((Integer) obj).intValue()); - } - if (obj instanceof Float || Float.TYPE == type) { - return new Float(-((Float) obj).floatValue()); - } - if (obj instanceof Short || Short.TYPE == type) { - return new Short((short) -((Short) obj).shortValue()); - } - if (obj instanceof Byte || Byte.TYPE == type) { - return new Byte((byte) -((Byte) obj).byteValue()); - } - Long num = (Long) coerceToNumber(obj, Long.class); - return new Long(-num.longValue()); - } -} +/* Generated By:JJTree: Do not edit this line. AstNegative.java */ + +package org.apache.el.parser; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstNegative extends SimpleNode { + public AstNegative(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return Number.class; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj = this.children[0].getValue(ctx); + + if (obj == null) { + return new Long(0); + } + if (obj instanceof BigDecimal) { + return ((BigDecimal) obj).negate(); + } + if (obj instanceof BigInteger) { + return ((BigInteger) obj).negate(); + } + if (obj instanceof String) { + if (isStringFloat((String) obj)) { + return new Double(-Double.parseDouble((String) obj)); + } + return new Long(-Long.parseLong((String) obj)); + } + Class type = obj.getClass(); + if (obj instanceof Long || Long.TYPE == type) { + return new Long(-((Long) obj).longValue()); + } + if (obj instanceof Double || Double.TYPE == type) { + return new Double(-((Double) obj).doubleValue()); + } + if (obj instanceof Integer || Integer.TYPE == type) { + return new Integer(-((Integer) obj).intValue()); + } + if (obj instanceof Float || Float.TYPE == type) { + return new Float(-((Float) obj).floatValue()); + } + if (obj instanceof Short || Short.TYPE == type) { + return new Short((short) -((Short) obj).shortValue()); + } + if (obj instanceof Byte || Byte.TYPE == type) { + return new Byte((byte) -((Byte) obj).byteValue()); + } + Long num = (Long) coerceToNumber(obj, Long.class); + return new Long(-num.longValue()); + } +} diff --git a/java/org/apache/el/parser/AstNot.java b/java/org/apache/el/parser/AstNot.java index 5f9237f3d..a1b8ae111 100644 --- a/java/org/apache/el/parser/AstNot.java +++ b/java/org/apache/el/parser/AstNot.java @@ -1,30 +1,30 @@ -/* Generated By:JJTree: Do not edit this line. AstNot.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstNot extends SimpleNode { - public AstNot(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return Boolean.class; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj = this.children[0].getValue(ctx); - Boolean b = coerceToBoolean(obj); - return Boolean.valueOf(!b.booleanValue()); - } -} +/* Generated By:JJTree: Do not edit this line. AstNot.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstNot extends SimpleNode { + public AstNot(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return Boolean.class; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj = this.children[0].getValue(ctx); + Boolean b = coerceToBoolean(obj); + return Boolean.valueOf(!b.booleanValue()); + } +} diff --git a/java/org/apache/el/parser/AstNotEqual.java b/java/org/apache/el/parser/AstNotEqual.java index 5024111ef..2ea2dd660 100644 --- a/java/org/apache/el/parser/AstNotEqual.java +++ b/java/org/apache/el/parser/AstNotEqual.java @@ -1,25 +1,25 @@ -/* Generated By:JJTree: Do not edit this line. AstNotEqual.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstNotEqual extends BooleanNode { - public AstNotEqual(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return Boolean.valueOf(!equals(obj0, obj1)); - } -} +/* Generated By:JJTree: Do not edit this line. AstNotEqual.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstNotEqual extends BooleanNode { + public AstNotEqual(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return Boolean.valueOf(!equals(obj0, obj1)); + } +} diff --git a/java/org/apache/el/parser/AstNull.java b/java/org/apache/el/parser/AstNull.java index 185b49119..876272d56 100644 --- a/java/org/apache/el/parser/AstNull.java +++ b/java/org/apache/el/parser/AstNull.java @@ -1,28 +1,28 @@ -/* Generated By:JJTree: Do not edit this line. AstNull.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstNull extends SimpleNode { - public AstNull(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return null; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return null; - } -} +/* Generated By:JJTree: Do not edit this line. AstNull.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstNull extends SimpleNode { + public AstNull(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return null; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return null; + } +} diff --git a/java/org/apache/el/parser/AstOr.java b/java/org/apache/el/parser/AstOr.java index a334db4af..7827c3859 100644 --- a/java/org/apache/el/parser/AstOr.java +++ b/java/org/apache/el/parser/AstOr.java @@ -1,30 +1,30 @@ -/* Generated By:JJTree: Do not edit this line. AstOr.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstOr extends BooleanNode { - public AstOr(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj = this.children[0].getValue(ctx); - Boolean b = coerceToBoolean(obj); - if (b.booleanValue()) { - return b; - } - obj = this.children[1].getValue(ctx); - b = coerceToBoolean(obj); - return b; - } -} +/* Generated By:JJTree: Do not edit this line. AstOr.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstOr extends BooleanNode { + public AstOr(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj = this.children[0].getValue(ctx); + Boolean b = coerceToBoolean(obj); + if (b.booleanValue()) { + return b; + } + obj = this.children[1].getValue(ctx); + b = coerceToBoolean(obj); + return b; + } +} diff --git a/java/org/apache/el/parser/AstPlus.java b/java/org/apache/el/parser/AstPlus.java index 53167ae89..0924e29f3 100644 --- a/java/org/apache/el/parser/AstPlus.java +++ b/java/org/apache/el/parser/AstPlus.java @@ -1,26 +1,26 @@ -/* Generated By:JJTree: Do not edit this line. AstPlus.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.ELArithmetic; -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstPlus extends ArithmeticNode { - public AstPlus(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - Object obj0 = this.children[0].getValue(ctx); - Object obj1 = this.children[1].getValue(ctx); - return ELArithmetic.add(obj0, obj1); - } -} +/* Generated By:JJTree: Do not edit this line. AstPlus.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.ELArithmetic; +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstPlus extends ArithmeticNode { + public AstPlus(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + Object obj0 = this.children[0].getValue(ctx); + Object obj1 = this.children[1].getValue(ctx); + return ELArithmetic.add(obj0, obj1); + } +} diff --git a/java/org/apache/el/parser/AstString.java b/java/org/apache/el/parser/AstString.java index 2af09bb5c..39ac13ebf 100644 --- a/java/org/apache/el/parser/AstString.java +++ b/java/org/apache/el/parser/AstString.java @@ -1,59 +1,59 @@ -/* Generated By:JJTree: Do not edit this line. AstString.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ - */ -public final class AstString extends SimpleNode { - public AstString(int id) { - super(id); - } - - private String string; - - public String getString() { - if (this.string == null) { - this.string = this.image.substring(1, this.image.length() - 1); - } - return this.string; - } - - public Class getType(EvaluationContext ctx) - throws ELException { - return String.class; - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return this.getString(); - } - - public void setImage(String image) { - if (image.indexOf('\\') == -1) { - this.image = image; - return; - } - int size = image.length(); - StringBuffer buf = new StringBuffer(size); - for (int i = 0; i < size; i++) { - char c = image.charAt(i); - if (c == '\\' && i + 1 < size) { - char c1 = image.charAt(i + 1); - if (c1 == '\\' || c1 == '"' || c1 == '\'' || c1 == '#' - || c1 == '$') { - c = c1; - i++; - } - } - buf.append(c); - } - this.image = buf.toString(); - } -} +/* Generated By:JJTree: Do not edit this line. AstString.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: kchung $ + */ +public final class AstString extends SimpleNode { + public AstString(int id) { + super(id); + } + + private String string; + + public String getString() { + if (this.string == null) { + this.string = this.image.substring(1, this.image.length() - 1); + } + return this.string; + } + + public Class getType(EvaluationContext ctx) + throws ELException { + return String.class; + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return this.getString(); + } + + public void setImage(String image) { + if (image.indexOf('\\') == -1) { + this.image = image; + return; + } + int size = image.length(); + StringBuffer buf = new StringBuffer(size); + for (int i = 0; i < size; i++) { + char c = image.charAt(i); + if (c == '\\' && i + 1 < size) { + char c1 = image.charAt(i + 1); + if (c1 == '\\' || c1 == '"' || c1 == '\'' || c1 == '#' + || c1 == '$') { + c = c1; + i++; + } + } + buf.append(c); + } + this.image = buf.toString(); + } +} diff --git a/java/org/apache/el/parser/AstTrue.java b/java/org/apache/el/parser/AstTrue.java index eecb23912..d7df8ec19 100644 --- a/java/org/apache/el/parser/AstTrue.java +++ b/java/org/apache/el/parser/AstTrue.java @@ -1,23 +1,23 @@ -/* Generated By:JJTree: Do not edit this line. AstTrue.java */ - -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstTrue extends BooleanNode { - public AstTrue(int id) { - super(id); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - return Boolean.TRUE; - } -} +/* Generated By:JJTree: Do not edit this line. AstTrue.java */ + +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstTrue extends BooleanNode { + public AstTrue(int id) { + super(id); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + return Boolean.TRUE; + } +} diff --git a/java/org/apache/el/parser/AstValue.java b/java/org/apache/el/parser/AstValue.java index ee34fa5ff..1d8c486ec 100644 --- a/java/org/apache/el/parser/AstValue.java +++ b/java/org/apache/el/parser/AstValue.java @@ -1,139 +1,139 @@ -/* Generated By:JJTree: Do not edit this line. AstValue.java */ - -package org.apache.el.parser; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.MethodInfo; -import javax.el.PropertyNotFoundException; - -import org.apache.el.lang.EvaluationContext; -import org.apache.el.util.MessageFactory; -import org.apache.el.util.ReflectionUtil; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class AstValue extends SimpleNode { - - protected static class Target { - protected Object base; - - protected Object property; - } - - public AstValue(int id) { - super(id); - } - - public Class getType(EvaluationContext ctx) throws ELException { - Target t = getTarget(ctx); - ctx.setPropertyResolved(false); - return ctx.getELResolver().getType(ctx, t.base, t.property); - } - - private final Target getTarget(EvaluationContext ctx) throws ELException { - // evaluate expr-a to value-a - Object base = this.children[0].getValue(ctx); - - // if our base is null (we know there are more properites to evaluate) - if (base == null) { - throw new PropertyNotFoundException(MessageFactory.get( - "error.unreachable.base", this.children[0].getImage())); - } - - // set up our start/end - Object property = null; - int propCount = this.jjtGetNumChildren() - 1; - int i = 1; - - // evaluate any properties before our target - ELResolver resolver = ctx.getELResolver(); - if (propCount > 1) { - while (base != null && i < propCount) { - property = this.children[i].getValue(ctx); - ctx.setPropertyResolved(false); - base = resolver.getValue(ctx, base, property); - i++; - } - // if we are in this block, we have more properties to resolve, - // but our base was null - if (base == null || property == null) { - throw new PropertyNotFoundException(MessageFactory.get( - "error.unreachable.property", property)); - } - } - - property = this.children[i].getValue(ctx); - - if (property == null) { - throw new PropertyNotFoundException(MessageFactory.get( - "error.unreachable.property", this.children[i])); - } - - Target t = new Target(); - t.base = base; - t.property = property; - return t; - } - - public Object getValue(EvaluationContext ctx) throws ELException { - Object base = this.children[0].getValue(ctx); - int propCount = this.jjtGetNumChildren(); - int i = 1; - Object property = null; - ELResolver resolver = ctx.getELResolver(); - while (base != null && i < propCount) { - property = this.children[i].getValue(ctx); - if (property == null) { - return null; - } else { - ctx.setPropertyResolved(false); - base = resolver.getValue(ctx, base, property); - } - i++; - } - return base; - } - - public boolean isReadOnly(EvaluationContext ctx) throws ELException { - Target t = getTarget(ctx); - ctx.setPropertyResolved(false); - return ctx.getELResolver().isReadOnly(ctx, t.base, t.property); - } - - public void setValue(EvaluationContext ctx, Object value) - throws ELException { - Target t = getTarget(ctx); - ctx.setPropertyResolved(false); - ctx.getELResolver().setValue(ctx, t.base, t.property, value); - } - - public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) - throws ELException { - Target t = getTarget(ctx); - Method m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); - return new MethodInfo(m.getName(), m.getReturnType(), m - .getParameterTypes()); - } - - public Object invoke(EvaluationContext ctx, Class[] paramTypes, - Object[] paramValues) throws ELException { - Target t = getTarget(ctx); - Method m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); - Object result = null; - try { - result = m.invoke(t.base, (Object[]) paramValues); - } catch (IllegalAccessException iae) { - throw new ELException(iae); - } catch (InvocationTargetException ite) { - throw new ELException(ite.getCause()); - } - return result; - } -} +/* Generated By:JJTree: Do not edit this line. AstValue.java */ + +package org.apache.el.parser; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.MethodInfo; +import javax.el.PropertyNotFoundException; + +import org.apache.el.lang.EvaluationContext; +import org.apache.el.util.MessageFactory; +import org.apache.el.util.ReflectionUtil; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class AstValue extends SimpleNode { + + protected static class Target { + protected Object base; + + protected Object property; + } + + public AstValue(int id) { + super(id); + } + + public Class getType(EvaluationContext ctx) throws ELException { + Target t = getTarget(ctx); + ctx.setPropertyResolved(false); + return ctx.getELResolver().getType(ctx, t.base, t.property); + } + + private final Target getTarget(EvaluationContext ctx) throws ELException { + // evaluate expr-a to value-a + Object base = this.children[0].getValue(ctx); + + // if our base is null (we know there are more properites to evaluate) + if (base == null) { + throw new PropertyNotFoundException(MessageFactory.get( + "error.unreachable.base", this.children[0].getImage())); + } + + // set up our start/end + Object property = null; + int propCount = this.jjtGetNumChildren() - 1; + int i = 1; + + // evaluate any properties before our target + ELResolver resolver = ctx.getELResolver(); + if (propCount > 1) { + while (base != null && i < propCount) { + property = this.children[i].getValue(ctx); + ctx.setPropertyResolved(false); + base = resolver.getValue(ctx, base, property); + i++; + } + // if we are in this block, we have more properties to resolve, + // but our base was null + if (base == null || property == null) { + throw new PropertyNotFoundException(MessageFactory.get( + "error.unreachable.property", property)); + } + } + + property = this.children[i].getValue(ctx); + + if (property == null) { + throw new PropertyNotFoundException(MessageFactory.get( + "error.unreachable.property", this.children[i])); + } + + Target t = new Target(); + t.base = base; + t.property = property; + return t; + } + + public Object getValue(EvaluationContext ctx) throws ELException { + Object base = this.children[0].getValue(ctx); + int propCount = this.jjtGetNumChildren(); + int i = 1; + Object property = null; + ELResolver resolver = ctx.getELResolver(); + while (base != null && i < propCount) { + property = this.children[i].getValue(ctx); + if (property == null) { + return null; + } else { + ctx.setPropertyResolved(false); + base = resolver.getValue(ctx, base, property); + } + i++; + } + return base; + } + + public boolean isReadOnly(EvaluationContext ctx) throws ELException { + Target t = getTarget(ctx); + ctx.setPropertyResolved(false); + return ctx.getELResolver().isReadOnly(ctx, t.base, t.property); + } + + public void setValue(EvaluationContext ctx, Object value) + throws ELException { + Target t = getTarget(ctx); + ctx.setPropertyResolved(false); + ctx.getELResolver().setValue(ctx, t.base, t.property, value); + } + + public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) + throws ELException { + Target t = getTarget(ctx); + Method m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); + return new MethodInfo(m.getName(), m.getReturnType(), m + .getParameterTypes()); + } + + public Object invoke(EvaluationContext ctx, Class[] paramTypes, + Object[] paramValues) throws ELException { + Target t = getTarget(ctx); + Method m = ReflectionUtil.getMethod(t.base, t.property, paramTypes); + Object result = null; + try { + result = m.invoke(t.base, (Object[]) paramValues); + } catch (IllegalAccessException iae) { + throw new ELException(iae); + } catch (InvocationTargetException ite) { + throw new ELException(ite.getCause()); + } + return result; + } +} diff --git a/java/org/apache/el/parser/BooleanNode.java b/java/org/apache/el/parser/BooleanNode.java index 156777a7b..7863718b8 100644 --- a/java/org/apache/el/parser/BooleanNode.java +++ b/java/org/apache/el/parser/BooleanNode.java @@ -1,38 +1,38 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.el.parser; - -import javax.el.ELException; - -import org.apache.el.lang.EvaluationContext; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public class BooleanNode extends SimpleNode { - /** - * @param i - */ - public BooleanNode(int i) { - super(i); - } - public Class getType(EvaluationContext ctx) - throws ELException { - return Boolean.class; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.el.parser; + +import javax.el.ELException; + +import org.apache.el.lang.EvaluationContext; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public class BooleanNode extends SimpleNode { + /** + * @param i + */ + public BooleanNode(int i) { + super(i); + } + public Class getType(EvaluationContext ctx) + throws ELException { + return Boolean.class; + } +} diff --git a/java/org/apache/el/parser/ELParser.java b/java/org/apache/el/parser/ELParser.java index e46e51566..b3e8c9b57 100644 --- a/java/org/apache/el/parser/ELParser.java +++ b/java/org/apache/el/parser/ELParser.java @@ -1,1672 +1,1672 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. ELParser.java */ -package org.apache.el.parser; -import java.io.StringReader; -import javax.el.ELException; -public class ELParser/*@bgen(jjtree)*/implements ELParserTreeConstants, ELParserConstants {/*@bgen(jjtree)*/ - protected JJTELParserState jjtree = new JJTELParserState();public static Node parse(String ref) throws ELException - { - try { - return (new ELParser(new StringReader(ref))).CompositeExpression(); - } catch (ParseException pe) { - throw new ELException(pe.getMessage()); - } - } - -/* - * CompositeExpression - * Allow most flexible parsing, restrict by examining - * type of returned node - */ - final public AstCompositeExpression CompositeExpression() throws ParseException { - /*@bgen(jjtree) CompositeExpression */ - AstCompositeExpression jjtn000 = new AstCompositeExpression(JJTCOMPOSITEEXPRESSION); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - try { - label_1: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LITERAL_EXPRESSION: - case START_DYNAMIC_EXPRESSION: - case START_DEFERRED_EXPRESSION: - ; - break; - default: - jj_la1[0] = jj_gen; - break label_1; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case START_DEFERRED_EXPRESSION: - DeferredExpression(); - break; - case START_DYNAMIC_EXPRESSION: - DynamicExpression(); - break; - case LITERAL_EXPRESSION: - LiteralExpression(); - break; - default: - jj_la1[1] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - jj_consume_token(0); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - {if (true) return jjtn000;} - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - throw new Error("Missing return statement in function"); - } - -/* - * LiteralExpression - * Non-EL Expression blocks - */ - final public void LiteralExpression() throws ParseException { - /*@bgen(jjtree) LiteralExpression */ - AstLiteralExpression jjtn000 = new AstLiteralExpression(JJTLITERALEXPRESSION); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - t = jj_consume_token(LITERAL_EXPRESSION); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * DeferredExpression - * #{..} Expressions - */ - final public void DeferredExpression() throws ParseException { - /*@bgen(jjtree) DeferredExpression */ - AstDeferredExpression jjtn000 = new AstDeferredExpression(JJTDEFERREDEXPRESSION); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - try { - jj_consume_token(START_DEFERRED_EXPRESSION); - Expression(); - jj_consume_token(END_EXPRESSION); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * DynamicExpression - * ${..} Expressions - */ - final public void DynamicExpression() throws ParseException { - /*@bgen(jjtree) DynamicExpression */ - AstDynamicExpression jjtn000 = new AstDynamicExpression(JJTDYNAMICEXPRESSION); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - try { - jj_consume_token(START_DYNAMIC_EXPRESSION); - Expression(); - jj_consume_token(END_EXPRESSION); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * Expression - * EL Expression Language Root, goes to Choice - */ - final public void Expression() throws ParseException { - Choice(); - } - -/* - * Choice - * For Choice markup a ? b : c, then Or - */ - final public void Choice() throws ParseException { - Or(); - label_2: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case QUESTIONMARK: - ; - break; - default: - jj_la1[2] = jj_gen; - break label_2; - } - jj_consume_token(QUESTIONMARK); - Or(); - jj_consume_token(COLON); - AstChoice jjtn001 = new AstChoice(JJTCHOICE); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Choice(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 3); - } - } - } - } - -/* - * Or - * For 'or' '||', then And - */ - final public void Or() throws ParseException { - And(); - label_3: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OR0: - case OR1: - ; - break; - default: - jj_la1[3] = jj_gen; - break label_3; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case OR0: - jj_consume_token(OR0); - break; - case OR1: - jj_consume_token(OR1); - break; - default: - jj_la1[4] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstOr jjtn001 = new AstOr(JJTOR); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - And(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - } - } - -/* - * And - * For 'and' '&&', then Equality - */ - final public void And() throws ParseException { - Equality(); - label_4: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case AND0: - case AND1: - ; - break; - default: - jj_la1[5] = jj_gen; - break label_4; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case AND0: - jj_consume_token(AND0); - break; - case AND1: - jj_consume_token(AND1); - break; - default: - jj_la1[6] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstAnd jjtn001 = new AstAnd(JJTAND); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Equality(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - } - } - -/* - * Equality - * For '==' 'eq' '!=' 'ne', then Compare - */ - final public void Equality() throws ParseException { - Compare(); - label_5: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EQ0: - case EQ1: - case NE0: - case NE1: - ; - break; - default: - jj_la1[7] = jj_gen; - break label_5; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EQ0: - case EQ1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case EQ0: - jj_consume_token(EQ0); - break; - case EQ1: - jj_consume_token(EQ1); - break; - default: - jj_la1[8] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstEqual jjtn001 = new AstEqual(JJTEQUAL); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Compare(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - break; - case NE0: - case NE1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NE0: - jj_consume_token(NE0); - break; - case NE1: - jj_consume_token(NE1); - break; - default: - jj_la1[9] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstNotEqual jjtn002 = new AstNotEqual(JJTNOTEQUAL); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - Compare(); - } catch (Throwable jjte002) { - if (jjtc002) { - jjtree.clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree.popNode(); - } - if (jjte002 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte002;} - } - if (jjte002 instanceof ParseException) { - {if (true) throw (ParseException)jjte002;} - } - {if (true) throw (Error)jjte002;} - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, 2); - } - } - break; - default: - jj_la1[10] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - -/* - * Compare - * For a bunch of them, then Math - */ - final public void Compare() throws ParseException { - Math(); - label_6: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case GT0: - case GT1: - case LT0: - case LT1: - case GE0: - case GE1: - case LE0: - case LE1: - ; - break; - default: - jj_la1[11] = jj_gen; - break label_6; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LT0: - case LT1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LT0: - jj_consume_token(LT0); - break; - case LT1: - jj_consume_token(LT1); - break; - default: - jj_la1[12] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstLessThan jjtn001 = new AstLessThan(JJTLESSTHAN); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Math(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - break; - case GT0: - case GT1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case GT0: - jj_consume_token(GT0); - break; - case GT1: - jj_consume_token(GT1); - break; - default: - jj_la1[13] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstGreaterThan jjtn002 = new AstGreaterThan(JJTGREATERTHAN); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - Math(); - } catch (Throwable jjte002) { - if (jjtc002) { - jjtree.clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree.popNode(); - } - if (jjte002 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte002;} - } - if (jjte002 instanceof ParseException) { - {if (true) throw (ParseException)jjte002;} - } - {if (true) throw (Error)jjte002;} - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, 2); - } - } - break; - case LE0: - case LE1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LE0: - jj_consume_token(LE0); - break; - case LE1: - jj_consume_token(LE1); - break; - default: - jj_la1[14] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstLessThanEqual jjtn003 = new AstLessThanEqual(JJTLESSTHANEQUAL); - boolean jjtc003 = true; - jjtree.openNodeScope(jjtn003); - try { - Math(); - } catch (Throwable jjte003) { - if (jjtc003) { - jjtree.clearNodeScope(jjtn003); - jjtc003 = false; - } else { - jjtree.popNode(); - } - if (jjte003 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte003;} - } - if (jjte003 instanceof ParseException) { - {if (true) throw (ParseException)jjte003;} - } - {if (true) throw (Error)jjte003;} - } finally { - if (jjtc003) { - jjtree.closeNodeScope(jjtn003, 2); - } - } - break; - case GE0: - case GE1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case GE0: - jj_consume_token(GE0); - break; - case GE1: - jj_consume_token(GE1); - break; - default: - jj_la1[15] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstGreaterThanEqual jjtn004 = new AstGreaterThanEqual(JJTGREATERTHANEQUAL); - boolean jjtc004 = true; - jjtree.openNodeScope(jjtn004); - try { - Math(); - } catch (Throwable jjte004) { - if (jjtc004) { - jjtree.clearNodeScope(jjtn004); - jjtc004 = false; - } else { - jjtree.popNode(); - } - if (jjte004 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte004;} - } - if (jjte004 instanceof ParseException) { - {if (true) throw (ParseException)jjte004;} - } - {if (true) throw (Error)jjte004;} - } finally { - if (jjtc004) { - jjtree.closeNodeScope(jjtn004, 2); - } - } - break; - default: - jj_la1[16] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - -/* - * Math - * For '+' '-', then Multiplication - */ - final public void Math() throws ParseException { - Multiplication(); - label_7: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case PLUS: - case MINUS: - ; - break; - default: - jj_la1[17] = jj_gen; - break label_7; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case PLUS: - jj_consume_token(PLUS); - AstPlus jjtn001 = new AstPlus(JJTPLUS); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Multiplication(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - break; - case MINUS: - jj_consume_token(MINUS); - AstMinus jjtn002 = new AstMinus(JJTMINUS); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - Multiplication(); - } catch (Throwable jjte002) { - if (jjtc002) { - jjtree.clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree.popNode(); - } - if (jjte002 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte002;} - } - if (jjte002 instanceof ParseException) { - {if (true) throw (ParseException)jjte002;} - } - {if (true) throw (Error)jjte002;} - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, 2); - } - } - break; - default: - jj_la1[18] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - -/* - * Multiplication - * For a bunch of them, then Unary - */ - final public void Multiplication() throws ParseException { - Unary(); - label_8: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MULT: - case DIV0: - case DIV1: - case MOD0: - case MOD1: - ; - break; - default: - jj_la1[19] = jj_gen; - break label_8; - } - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MULT: - jj_consume_token(MULT); - AstMult jjtn001 = new AstMult(JJTMULT); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Unary(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, 2); - } - } - break; - case DIV0: - case DIV1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DIV0: - jj_consume_token(DIV0); - break; - case DIV1: - jj_consume_token(DIV1); - break; - default: - jj_la1[20] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstDiv jjtn002 = new AstDiv(JJTDIV); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - Unary(); - } catch (Throwable jjte002) { - if (jjtc002) { - jjtree.clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree.popNode(); - } - if (jjte002 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte002;} - } - if (jjte002 instanceof ParseException) { - {if (true) throw (ParseException)jjte002;} - } - {if (true) throw (Error)jjte002;} - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, 2); - } - } - break; - case MOD0: - case MOD1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MOD0: - jj_consume_token(MOD0); - break; - case MOD1: - jj_consume_token(MOD1); - break; - default: - jj_la1[21] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstMod jjtn003 = new AstMod(JJTMOD); - boolean jjtc003 = true; - jjtree.openNodeScope(jjtn003); - try { - Unary(); - } catch (Throwable jjte003) { - if (jjtc003) { - jjtree.clearNodeScope(jjtn003); - jjtc003 = false; - } else { - jjtree.popNode(); - } - if (jjte003 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte003;} - } - if (jjte003 instanceof ParseException) { - {if (true) throw (ParseException)jjte003;} - } - {if (true) throw (Error)jjte003;} - } finally { - if (jjtc003) { - jjtree.closeNodeScope(jjtn003, 2); - } - } - break; - default: - jj_la1[22] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - -/* - * Unary - * For '-' '!' 'not' 'empty', then Value - */ - final public void Unary() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case MINUS: - jj_consume_token(MINUS); - AstNegative jjtn001 = new AstNegative(JJTNEGATIVE); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - Unary(); - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, true); - } - } - break; - case NOT0: - case NOT1: - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case NOT0: - jj_consume_token(NOT0); - break; - case NOT1: - jj_consume_token(NOT1); - break; - default: - jj_la1[23] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - AstNot jjtn002 = new AstNot(JJTNOT); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - Unary(); - } catch (Throwable jjte002) { - if (jjtc002) { - jjtree.clearNodeScope(jjtn002); - jjtc002 = false; - } else { - jjtree.popNode(); - } - if (jjte002 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte002;} - } - if (jjte002 instanceof ParseException) { - {if (true) throw (ParseException)jjte002;} - } - {if (true) throw (Error)jjte002;} - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, true); - } - } - break; - case EMPTY: - jj_consume_token(EMPTY); - AstEmpty jjtn003 = new AstEmpty(JJTEMPTY); - boolean jjtc003 = true; - jjtree.openNodeScope(jjtn003); - try { - Unary(); - } catch (Throwable jjte003) { - if (jjtc003) { - jjtree.clearNodeScope(jjtn003); - jjtc003 = false; - } else { - jjtree.popNode(); - } - if (jjte003 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte003;} - } - if (jjte003 instanceof ParseException) { - {if (true) throw (ParseException)jjte003;} - } - {if (true) throw (Error)jjte003;} - } finally { - if (jjtc003) { - jjtree.closeNodeScope(jjtn003, true); - } - } - break; - case INTEGER_LITERAL: - case FLOATING_POINT_LITERAL: - case STRING_LITERAL: - case TRUE: - case FALSE: - case NULL: - case LPAREN: - case IDENTIFIER: - Value(); - break; - default: - jj_la1[24] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - -/* - * Value - * Defines Prefix plus zero or more Suffixes - */ - final public void Value() throws ParseException { - AstValue jjtn001 = new AstValue(JJTVALUE); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - ValuePrefix(); - label_9: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOT: - case LBRACK: - ; - break; - default: - jj_la1[25] = jj_gen; - break label_9; - } - ValueSuffix(); - } - } catch (Throwable jjte001) { - if (jjtc001) { - jjtree.clearNodeScope(jjtn001); - jjtc001 = false; - } else { - jjtree.popNode(); - } - if (jjte001 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte001;} - } - if (jjte001 instanceof ParseException) { - {if (true) throw (ParseException)jjte001;} - } - {if (true) throw (Error)jjte001;} - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1); - } - } - } - -/* - * ValuePrefix - * For Literals, Variables, and Functions - */ - final public void ValuePrefix() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case INTEGER_LITERAL: - case FLOATING_POINT_LITERAL: - case STRING_LITERAL: - case TRUE: - case FALSE: - case NULL: - Literal(); - break; - case LPAREN: - case IDENTIFIER: - NonLiteral(); - break; - default: - jj_la1[26] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - -/* - * ValueSuffix - * Either dot or bracket notation - */ - final public void ValueSuffix() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case DOT: - DotSuffix(); - break; - case LBRACK: - BracketSuffix(); - break; - default: - jj_la1[27] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - -/* - * DotSuffix - * Dot Property - */ - final public void DotSuffix() throws ParseException { - /*@bgen(jjtree) DotSuffix */ - AstDotSuffix jjtn000 = new AstDotSuffix(JJTDOTSUFFIX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - jj_consume_token(DOT); - t = jj_consume_token(IDENTIFIER); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * BracketSuffix - * Sub Expression Suffix - */ - final public void BracketSuffix() throws ParseException { - /*@bgen(jjtree) BracketSuffix */ - AstBracketSuffix jjtn000 = new AstBracketSuffix(JJTBRACKETSUFFIX); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - try { - jj_consume_token(LBRACK); - Expression(); - jj_consume_token(RBRACK); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * NonLiteral - * For Grouped Operations, Identifiers, and Functions - */ - final public void NonLiteral() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case LPAREN: - jj_consume_token(LPAREN); - Expression(); - jj_consume_token(RPAREN); - break; - default: - jj_la1[28] = jj_gen; - if (jj_2_1(2)) { - Function(); - } else { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case IDENTIFIER: - Identifier(); - break; - default: - jj_la1[29] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - } - } - -/* - * Identifier - * Java Language Identifier - */ - final public void Identifier() throws ParseException { - /*@bgen(jjtree) Identifier */ - AstIdentifier jjtn000 = new AstIdentifier(JJTIDENTIFIER); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - t = jj_consume_token(IDENTIFIER); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * Function - * Namespace:Name(a,b,c) - */ - final public void Function() throws ParseException { - /*@bgen(jjtree) Function */ - AstFunction jjtn000 = new AstFunction(JJTFUNCTION); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t0 = null; - Token t1 = null; - try { - t0 = jj_consume_token(IDENTIFIER); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case FUNCTIONSUFFIX: - t1 = jj_consume_token(FUNCTIONSUFFIX); - break; - default: - jj_la1[30] = jj_gen; - ; - } - if (t1 != null) { - jjtn000.setPrefix(t0.image); - jjtn000.setLocalName(t1.image.substring(1)); - } else { - jjtn000.setLocalName(t0.image); - } - jj_consume_token(LPAREN); - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case INTEGER_LITERAL: - case FLOATING_POINT_LITERAL: - case STRING_LITERAL: - case TRUE: - case FALSE: - case NULL: - case LPAREN: - case NOT0: - case NOT1: - case EMPTY: - case MINUS: - case IDENTIFIER: - Expression(); - label_10: - while (true) { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case COMMA: - ; - break; - default: - jj_la1[31] = jj_gen; - break label_10; - } - jj_consume_token(COMMA); - Expression(); - } - break; - default: - jj_la1[32] = jj_gen; - ; - } - jj_consume_token(RPAREN); - } catch (Throwable jjte000) { - if (jjtc000) { - jjtree.clearNodeScope(jjtn000); - jjtc000 = false; - } else { - jjtree.popNode(); - } - if (jjte000 instanceof RuntimeException) { - {if (true) throw (RuntimeException)jjte000;} - } - if (jjte000 instanceof ParseException) { - {if (true) throw (ParseException)jjte000;} - } - {if (true) throw (Error)jjte000;} - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * Literal - * Reserved Keywords - */ - final public void Literal() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case TRUE: - case FALSE: - Boolean(); - break; - case FLOATING_POINT_LITERAL: - FloatingPoint(); - break; - case INTEGER_LITERAL: - Integer(); - break; - case STRING_LITERAL: - String(); - break; - case NULL: - Null(); - break; - default: - jj_la1[33] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - -/* - * Boolean - * For 'true' 'false' - */ - final public void Boolean() throws ParseException { - switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { - case TRUE: - AstTrue jjtn001 = new AstTrue(JJTTRUE); - boolean jjtc001 = true; - jjtree.openNodeScope(jjtn001); - try { - jj_consume_token(TRUE); - } finally { - if (jjtc001) { - jjtree.closeNodeScope(jjtn001, true); - } - } - break; - case FALSE: - AstFalse jjtn002 = new AstFalse(JJTFALSE); - boolean jjtc002 = true; - jjtree.openNodeScope(jjtn002); - try { - jj_consume_token(FALSE); - } finally { - if (jjtc002) { - jjtree.closeNodeScope(jjtn002, true); - } - } - break; - default: - jj_la1[34] = jj_gen; - jj_consume_token(-1); - throw new ParseException(); - } - } - -/* - * FloatinPoint - * For Decimal and Floating Point Literals - */ - final public void FloatingPoint() throws ParseException { - /*@bgen(jjtree) FloatingPoint */ - AstFloatingPoint jjtn000 = new AstFloatingPoint(JJTFLOATINGPOINT); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - t = jj_consume_token(FLOATING_POINT_LITERAL); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * Integer - * For Simple Numeric Literals - */ - final public void Integer() throws ParseException { - /*@bgen(jjtree) Integer */ - AstInteger jjtn000 = new AstInteger(JJTINTEGER); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - t = jj_consume_token(INTEGER_LITERAL); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * String - * For Quoted Literals - */ - final public void String() throws ParseException { - /*@bgen(jjtree) String */ - AstString jjtn000 = new AstString(JJTSTRING); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000);Token t = null; - try { - t = jj_consume_token(STRING_LITERAL); - jjtree.closeNodeScope(jjtn000, true); - jjtc000 = false; - jjtn000.setImage(t.image); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - -/* - * Null - * For 'null' - */ - final public void Null() throws ParseException { - /*@bgen(jjtree) Null */ - AstNull jjtn000 = new AstNull(JJTNULL); - boolean jjtc000 = true; - jjtree.openNodeScope(jjtn000); - try { - jj_consume_token(NULL); - } finally { - if (jjtc000) { - jjtree.closeNodeScope(jjtn000, true); - } - } - } - - final private boolean jj_2_1(int xla) { - jj_la = xla; jj_lastpos = jj_scanpos = token; - try { return !jj_3_1(); } - catch(LookaheadSuccess ls) { return true; } - finally { jj_save(0, xla); } - } - - final private boolean jj_3_1() { - if (jj_3R_11()) return true; - return false; - } - - final private boolean jj_3R_11() { - if (jj_scan_token(IDENTIFIER)) return true; - Token xsp; - xsp = jj_scanpos; - if (jj_scan_token(54)) jj_scanpos = xsp; - if (jj_scan_token(LPAREN)) return true; - return false; - } - - public ELParserTokenManager token_source; - SimpleCharStream jj_input_stream; - public Token token, jj_nt; - private int jj_ntk; - private Token jj_scanpos, jj_lastpos; - private int jj_la; - public boolean lookingAhead = false; - private boolean jj_semLA; - private int jj_gen; - final private int[] jj_la1 = new int[35]; - static private int[] jj_la1_0; - static private int[] jj_la1_1; - static { - jj_la1_0(); - jj_la1_1(); - } - private static void jj_la1_0() { - jj_la1_0 = new int[] {0xe,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe000000,0x18000000,0x6000000,0x80000000,0x60000000,0xfe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9d600,0x240000,0x9d600,0x240000,0x80000,0x0,0x0,0x1000000,0x9d600,0x1d600,0xc000,}; - } - private static void jj_la1_1() { - jj_la1_1 = new int[] {0x0,0x0,0x10000,0x600,0x600,0x180,0x180,0x1e,0x6,0x18,0x1e,0x1,0x0,0x0,0x1,0x0,0x1,0xc000,0xc000,0x1e2000,0x60000,0x180000,0x1e2000,0x60,0x208860,0x0,0x200000,0x0,0x0,0x200000,0x400000,0x0,0x208860,0x0,0x0,}; - } - final private JJCalls[] jj_2_rtns = new JJCalls[1]; - private boolean jj_rescan = false; - private int jj_gc = 0; - - public ELParser(java.io.InputStream stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new ELParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.InputStream stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public ELParser(java.io.Reader stream) { - jj_input_stream = new SimpleCharStream(stream, 1, 1); - token_source = new ELParserTokenManager(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(java.io.Reader stream) { - jj_input_stream.ReInit(stream, 1, 1); - token_source.ReInit(jj_input_stream); - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public ELParser(ELParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - public void ReInit(ELParserTokenManager tm) { - token_source = tm; - token = new Token(); - jj_ntk = -1; - jjtree.reset(); - jj_gen = 0; - for (int i = 0; i < 35; i++) jj_la1[i] = -1; - for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); - } - - final private Token jj_consume_token(int kind) throws ParseException { - Token oldToken; - if ((oldToken = token).next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - if (token.kind == kind) { - jj_gen++; - if (++jj_gc > 100) { - jj_gc = 0; - for (int i = 0; i < jj_2_rtns.length; i++) { - JJCalls c = jj_2_rtns[i]; - while (c != null) { - if (c.gen < jj_gen) c.first = null; - c = c.next; - } - } - } - return token; - } - token = oldToken; - jj_kind = kind; - throw generateParseException(); - } - - static private final class LookaheadSuccess extends java.lang.Error { } - final private LookaheadSuccess jj_ls = new LookaheadSuccess(); - final private boolean jj_scan_token(int kind) { - if (jj_scanpos == jj_lastpos) { - jj_la--; - if (jj_scanpos.next == null) { - jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); - } else { - jj_lastpos = jj_scanpos = jj_scanpos.next; - } - } else { - jj_scanpos = jj_scanpos.next; - } - if (jj_rescan) { - int i = 0; Token tok = token; - while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } - if (tok != null) jj_add_error_token(kind, i); - } - if (jj_scanpos.kind != kind) return true; - if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; - return false; - } - - final public Token getNextToken() { - if (token.next != null) token = token.next; - else token = token.next = token_source.getNextToken(); - jj_ntk = -1; - jj_gen++; - return token; - } - - final public Token getToken(int index) { - Token t = lookingAhead ? jj_scanpos : token; - for (int i = 0; i < index; i++) { - if (t.next != null) t = t.next; - else t = t.next = token_source.getNextToken(); - } - return t; - } - - final private int jj_ntk() { - if ((jj_nt=token.next) == null) - return (jj_ntk = (token.next=token_source.getNextToken()).kind); - else - return (jj_ntk = jj_nt.kind); - } - - private java.util.Vector jj_expentries = new java.util.Vector(); - private int[] jj_expentry; - private int jj_kind = -1; - private int[] jj_lasttokens = new int[100]; - private int jj_endpos; - - private void jj_add_error_token(int kind, int pos) { - if (pos >= 100) return; - if (pos == jj_endpos + 1) { - jj_lasttokens[jj_endpos++] = kind; - } else if (jj_endpos != 0) { - jj_expentry = new int[jj_endpos]; - for (int i = 0; i < jj_endpos; i++) { - jj_expentry[i] = jj_lasttokens[i]; - } - boolean exists = false; - for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) { - int[] oldentry = (int[])(e.nextElement()); - if (oldentry.length == jj_expentry.length) { - exists = true; - for (int i = 0; i < jj_expentry.length; i++) { - if (oldentry[i] != jj_expentry[i]) { - exists = false; - break; - } - } - if (exists) break; - } - } - if (!exists) jj_expentries.addElement(jj_expentry); - if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; - } - } - - public ParseException generateParseException() { - jj_expentries.removeAllElements(); - boolean[] la1tokens = new boolean[59]; - for (int i = 0; i < 59; i++) { - la1tokens[i] = false; - } - if (jj_kind >= 0) { - la1tokens[jj_kind] = true; - jj_kind = -1; - } - for (int i = 0; i < 35; i++) { - if (jj_la1[i] == jj_gen) { - for (int j = 0; j < 32; j++) { - if ((jj_la1_0[i] & (1< jj_gen) { - jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; - switch (i) { - case 0: jj_3_1(); break; - } - } - p = p.next; - } while (p != null); - } - jj_rescan = false; - } - - final private void jj_save(int index, int xla) { - JJCalls p = jj_2_rtns[index]; - while (p.gen > jj_gen) { - if (p.next == null) { p = p.next = new JJCalls(); break; } - p = p.next; - } - p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; - } - - static final class JJCalls { - int gen; - Token first; - int arg; - JJCalls next; - } - -} +/* Generated By:JJTree&JavaCC: Do not edit this line. ELParser.java */ +package org.apache.el.parser; +import java.io.StringReader; +import javax.el.ELException; +public class ELParser/*@bgen(jjtree)*/implements ELParserTreeConstants, ELParserConstants {/*@bgen(jjtree)*/ + protected JJTELParserState jjtree = new JJTELParserState();public static Node parse(String ref) throws ELException + { + try { + return (new ELParser(new StringReader(ref))).CompositeExpression(); + } catch (ParseException pe) { + throw new ELException(pe.getMessage()); + } + } + +/* + * CompositeExpression + * Allow most flexible parsing, restrict by examining + * type of returned node + */ + final public AstCompositeExpression CompositeExpression() throws ParseException { + /*@bgen(jjtree) CompositeExpression */ + AstCompositeExpression jjtn000 = new AstCompositeExpression(JJTCOMPOSITEEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + try { + label_1: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case LITERAL_EXPRESSION: + case START_DYNAMIC_EXPRESSION: + case START_DEFERRED_EXPRESSION: + ; + break; + default: + jj_la1[0] = jj_gen; + break label_1; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case START_DEFERRED_EXPRESSION: + DeferredExpression(); + break; + case START_DYNAMIC_EXPRESSION: + DynamicExpression(); + break; + case LITERAL_EXPRESSION: + LiteralExpression(); + break; + default: + jj_la1[1] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + jj_consume_token(0); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + {if (true) return jjtn000;} + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte000;} + } + if (jjte000 instanceof ParseException) { + {if (true) throw (ParseException)jjte000;} + } + {if (true) throw (Error)jjte000;} + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + throw new Error("Missing return statement in function"); + } + +/* + * LiteralExpression + * Non-EL Expression blocks + */ + final public void LiteralExpression() throws ParseException { + /*@bgen(jjtree) LiteralExpression */ + AstLiteralExpression jjtn000 = new AstLiteralExpression(JJTLITERALEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + t = jj_consume_token(LITERAL_EXPRESSION); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * DeferredExpression + * #{..} Expressions + */ + final public void DeferredExpression() throws ParseException { + /*@bgen(jjtree) DeferredExpression */ + AstDeferredExpression jjtn000 = new AstDeferredExpression(JJTDEFERREDEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + try { + jj_consume_token(START_DEFERRED_EXPRESSION); + Expression(); + jj_consume_token(END_EXPRESSION); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte000;} + } + if (jjte000 instanceof ParseException) { + {if (true) throw (ParseException)jjte000;} + } + {if (true) throw (Error)jjte000;} + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * DynamicExpression + * ${..} Expressions + */ + final public void DynamicExpression() throws ParseException { + /*@bgen(jjtree) DynamicExpression */ + AstDynamicExpression jjtn000 = new AstDynamicExpression(JJTDYNAMICEXPRESSION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + try { + jj_consume_token(START_DYNAMIC_EXPRESSION); + Expression(); + jj_consume_token(END_EXPRESSION); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte000;} + } + if (jjte000 instanceof ParseException) { + {if (true) throw (ParseException)jjte000;} + } + {if (true) throw (Error)jjte000;} + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * Expression + * EL Expression Language Root, goes to Choice + */ + final public void Expression() throws ParseException { + Choice(); + } + +/* + * Choice + * For Choice markup a ? b : c, then Or + */ + final public void Choice() throws ParseException { + Or(); + label_2: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case QUESTIONMARK: + ; + break; + default: + jj_la1[2] = jj_gen; + break label_2; + } + jj_consume_token(QUESTIONMARK); + Or(); + jj_consume_token(COLON); + AstChoice jjtn001 = new AstChoice(JJTCHOICE); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Choice(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 3); + } + } + } + } + +/* + * Or + * For 'or' '||', then And + */ + final public void Or() throws ParseException { + And(); + label_3: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case OR0: + case OR1: + ; + break; + default: + jj_la1[3] = jj_gen; + break label_3; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case OR0: + jj_consume_token(OR0); + break; + case OR1: + jj_consume_token(OR1); + break; + default: + jj_la1[4] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstOr jjtn001 = new AstOr(JJTOR); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + And(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + } + } + +/* + * And + * For 'and' '&&', then Equality + */ + final public void And() throws ParseException { + Equality(); + label_4: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case AND0: + case AND1: + ; + break; + default: + jj_la1[5] = jj_gen; + break label_4; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case AND0: + jj_consume_token(AND0); + break; + case AND1: + jj_consume_token(AND1); + break; + default: + jj_la1[6] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstAnd jjtn001 = new AstAnd(JJTAND); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Equality(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + } + } + +/* + * Equality + * For '==' 'eq' '!=' 'ne', then Compare + */ + final public void Equality() throws ParseException { + Compare(); + label_5: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case EQ0: + case EQ1: + case NE0: + case NE1: + ; + break; + default: + jj_la1[7] = jj_gen; + break label_5; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case EQ0: + case EQ1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case EQ0: + jj_consume_token(EQ0); + break; + case EQ1: + jj_consume_token(EQ1); + break; + default: + jj_la1[8] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstEqual jjtn001 = new AstEqual(JJTEQUAL); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Compare(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + break; + case NE0: + case NE1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case NE0: + jj_consume_token(NE0); + break; + case NE1: + jj_consume_token(NE1); + break; + default: + jj_la1[9] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstNotEqual jjtn002 = new AstNotEqual(JJTNOTEQUAL); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + Compare(); + } catch (Throwable jjte002) { + if (jjtc002) { + jjtree.clearNodeScope(jjtn002); + jjtc002 = false; + } else { + jjtree.popNode(); + } + if (jjte002 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte002;} + } + if (jjte002 instanceof ParseException) { + {if (true) throw (ParseException)jjte002;} + } + {if (true) throw (Error)jjte002;} + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, 2); + } + } + break; + default: + jj_la1[10] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + +/* + * Compare + * For a bunch of them, then Math + */ + final public void Compare() throws ParseException { + Math(); + label_6: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case GT0: + case GT1: + case LT0: + case LT1: + case GE0: + case GE1: + case LE0: + case LE1: + ; + break; + default: + jj_la1[11] = jj_gen; + break label_6; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case LT0: + case LT1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case LT0: + jj_consume_token(LT0); + break; + case LT1: + jj_consume_token(LT1); + break; + default: + jj_la1[12] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstLessThan jjtn001 = new AstLessThan(JJTLESSTHAN); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Math(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + break; + case GT0: + case GT1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case GT0: + jj_consume_token(GT0); + break; + case GT1: + jj_consume_token(GT1); + break; + default: + jj_la1[13] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstGreaterThan jjtn002 = new AstGreaterThan(JJTGREATERTHAN); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + Math(); + } catch (Throwable jjte002) { + if (jjtc002) { + jjtree.clearNodeScope(jjtn002); + jjtc002 = false; + } else { + jjtree.popNode(); + } + if (jjte002 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte002;} + } + if (jjte002 instanceof ParseException) { + {if (true) throw (ParseException)jjte002;} + } + {if (true) throw (Error)jjte002;} + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, 2); + } + } + break; + case LE0: + case LE1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case LE0: + jj_consume_token(LE0); + break; + case LE1: + jj_consume_token(LE1); + break; + default: + jj_la1[14] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstLessThanEqual jjtn003 = new AstLessThanEqual(JJTLESSTHANEQUAL); + boolean jjtc003 = true; + jjtree.openNodeScope(jjtn003); + try { + Math(); + } catch (Throwable jjte003) { + if (jjtc003) { + jjtree.clearNodeScope(jjtn003); + jjtc003 = false; + } else { + jjtree.popNode(); + } + if (jjte003 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte003;} + } + if (jjte003 instanceof ParseException) { + {if (true) throw (ParseException)jjte003;} + } + {if (true) throw (Error)jjte003;} + } finally { + if (jjtc003) { + jjtree.closeNodeScope(jjtn003, 2); + } + } + break; + case GE0: + case GE1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case GE0: + jj_consume_token(GE0); + break; + case GE1: + jj_consume_token(GE1); + break; + default: + jj_la1[15] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstGreaterThanEqual jjtn004 = new AstGreaterThanEqual(JJTGREATERTHANEQUAL); + boolean jjtc004 = true; + jjtree.openNodeScope(jjtn004); + try { + Math(); + } catch (Throwable jjte004) { + if (jjtc004) { + jjtree.clearNodeScope(jjtn004); + jjtc004 = false; + } else { + jjtree.popNode(); + } + if (jjte004 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte004;} + } + if (jjte004 instanceof ParseException) { + {if (true) throw (ParseException)jjte004;} + } + {if (true) throw (Error)jjte004;} + } finally { + if (jjtc004) { + jjtree.closeNodeScope(jjtn004, 2); + } + } + break; + default: + jj_la1[16] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + +/* + * Math + * For '+' '-', then Multiplication + */ + final public void Math() throws ParseException { + Multiplication(); + label_7: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case PLUS: + case MINUS: + ; + break; + default: + jj_la1[17] = jj_gen; + break label_7; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case PLUS: + jj_consume_token(PLUS); + AstPlus jjtn001 = new AstPlus(JJTPLUS); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Multiplication(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + break; + case MINUS: + jj_consume_token(MINUS); + AstMinus jjtn002 = new AstMinus(JJTMINUS); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + Multiplication(); + } catch (Throwable jjte002) { + if (jjtc002) { + jjtree.clearNodeScope(jjtn002); + jjtc002 = false; + } else { + jjtree.popNode(); + } + if (jjte002 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte002;} + } + if (jjte002 instanceof ParseException) { + {if (true) throw (ParseException)jjte002;} + } + {if (true) throw (Error)jjte002;} + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, 2); + } + } + break; + default: + jj_la1[18] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + +/* + * Multiplication + * For a bunch of them, then Unary + */ + final public void Multiplication() throws ParseException { + Unary(); + label_8: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case MULT: + case DIV0: + case DIV1: + case MOD0: + case MOD1: + ; + break; + default: + jj_la1[19] = jj_gen; + break label_8; + } + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case MULT: + jj_consume_token(MULT); + AstMult jjtn001 = new AstMult(JJTMULT); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Unary(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, 2); + } + } + break; + case DIV0: + case DIV1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case DIV0: + jj_consume_token(DIV0); + break; + case DIV1: + jj_consume_token(DIV1); + break; + default: + jj_la1[20] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstDiv jjtn002 = new AstDiv(JJTDIV); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + Unary(); + } catch (Throwable jjte002) { + if (jjtc002) { + jjtree.clearNodeScope(jjtn002); + jjtc002 = false; + } else { + jjtree.popNode(); + } + if (jjte002 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte002;} + } + if (jjte002 instanceof ParseException) { + {if (true) throw (ParseException)jjte002;} + } + {if (true) throw (Error)jjte002;} + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, 2); + } + } + break; + case MOD0: + case MOD1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case MOD0: + jj_consume_token(MOD0); + break; + case MOD1: + jj_consume_token(MOD1); + break; + default: + jj_la1[21] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstMod jjtn003 = new AstMod(JJTMOD); + boolean jjtc003 = true; + jjtree.openNodeScope(jjtn003); + try { + Unary(); + } catch (Throwable jjte003) { + if (jjtc003) { + jjtree.clearNodeScope(jjtn003); + jjtc003 = false; + } else { + jjtree.popNode(); + } + if (jjte003 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte003;} + } + if (jjte003 instanceof ParseException) { + {if (true) throw (ParseException)jjte003;} + } + {if (true) throw (Error)jjte003;} + } finally { + if (jjtc003) { + jjtree.closeNodeScope(jjtn003, 2); + } + } + break; + default: + jj_la1[22] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + +/* + * Unary + * For '-' '!' 'not' 'empty', then Value + */ + final public void Unary() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case MINUS: + jj_consume_token(MINUS); + AstNegative jjtn001 = new AstNegative(JJTNEGATIVE); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + Unary(); + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, true); + } + } + break; + case NOT0: + case NOT1: + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case NOT0: + jj_consume_token(NOT0); + break; + case NOT1: + jj_consume_token(NOT1); + break; + default: + jj_la1[23] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + AstNot jjtn002 = new AstNot(JJTNOT); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + Unary(); + } catch (Throwable jjte002) { + if (jjtc002) { + jjtree.clearNodeScope(jjtn002); + jjtc002 = false; + } else { + jjtree.popNode(); + } + if (jjte002 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte002;} + } + if (jjte002 instanceof ParseException) { + {if (true) throw (ParseException)jjte002;} + } + {if (true) throw (Error)jjte002;} + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, true); + } + } + break; + case EMPTY: + jj_consume_token(EMPTY); + AstEmpty jjtn003 = new AstEmpty(JJTEMPTY); + boolean jjtc003 = true; + jjtree.openNodeScope(jjtn003); + try { + Unary(); + } catch (Throwable jjte003) { + if (jjtc003) { + jjtree.clearNodeScope(jjtn003); + jjtc003 = false; + } else { + jjtree.popNode(); + } + if (jjte003 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte003;} + } + if (jjte003 instanceof ParseException) { + {if (true) throw (ParseException)jjte003;} + } + {if (true) throw (Error)jjte003;} + } finally { + if (jjtc003) { + jjtree.closeNodeScope(jjtn003, true); + } + } + break; + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case STRING_LITERAL: + case TRUE: + case FALSE: + case NULL: + case LPAREN: + case IDENTIFIER: + Value(); + break; + default: + jj_la1[24] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + +/* + * Value + * Defines Prefix plus zero or more Suffixes + */ + final public void Value() throws ParseException { + AstValue jjtn001 = new AstValue(JJTVALUE); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + ValuePrefix(); + label_9: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case DOT: + case LBRACK: + ; + break; + default: + jj_la1[25] = jj_gen; + break label_9; + } + ValueSuffix(); + } + } catch (Throwable jjte001) { + if (jjtc001) { + jjtree.clearNodeScope(jjtn001); + jjtc001 = false; + } else { + jjtree.popNode(); + } + if (jjte001 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte001;} + } + if (jjte001 instanceof ParseException) { + {if (true) throw (ParseException)jjte001;} + } + {if (true) throw (Error)jjte001;} + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, jjtree.nodeArity() > 1); + } + } + } + +/* + * ValuePrefix + * For Literals, Variables, and Functions + */ + final public void ValuePrefix() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case STRING_LITERAL: + case TRUE: + case FALSE: + case NULL: + Literal(); + break; + case LPAREN: + case IDENTIFIER: + NonLiteral(); + break; + default: + jj_la1[26] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + +/* + * ValueSuffix + * Either dot or bracket notation + */ + final public void ValueSuffix() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case DOT: + DotSuffix(); + break; + case LBRACK: + BracketSuffix(); + break; + default: + jj_la1[27] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + +/* + * DotSuffix + * Dot Property + */ + final public void DotSuffix() throws ParseException { + /*@bgen(jjtree) DotSuffix */ + AstDotSuffix jjtn000 = new AstDotSuffix(JJTDOTSUFFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + jj_consume_token(DOT); + t = jj_consume_token(IDENTIFIER); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * BracketSuffix + * Sub Expression Suffix + */ + final public void BracketSuffix() throws ParseException { + /*@bgen(jjtree) BracketSuffix */ + AstBracketSuffix jjtn000 = new AstBracketSuffix(JJTBRACKETSUFFIX); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + try { + jj_consume_token(LBRACK); + Expression(); + jj_consume_token(RBRACK); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte000;} + } + if (jjte000 instanceof ParseException) { + {if (true) throw (ParseException)jjte000;} + } + {if (true) throw (Error)jjte000;} + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * NonLiteral + * For Grouped Operations, Identifiers, and Functions + */ + final public void NonLiteral() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case LPAREN: + jj_consume_token(LPAREN); + Expression(); + jj_consume_token(RPAREN); + break; + default: + jj_la1[28] = jj_gen; + if (jj_2_1(2)) { + Function(); + } else { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case IDENTIFIER: + Identifier(); + break; + default: + jj_la1[29] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + } + } + +/* + * Identifier + * Java Language Identifier + */ + final public void Identifier() throws ParseException { + /*@bgen(jjtree) Identifier */ + AstIdentifier jjtn000 = new AstIdentifier(JJTIDENTIFIER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + t = jj_consume_token(IDENTIFIER); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * Function + * Namespace:Name(a,b,c) + */ + final public void Function() throws ParseException { + /*@bgen(jjtree) Function */ + AstFunction jjtn000 = new AstFunction(JJTFUNCTION); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t0 = null; + Token t1 = null; + try { + t0 = jj_consume_token(IDENTIFIER); + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case FUNCTIONSUFFIX: + t1 = jj_consume_token(FUNCTIONSUFFIX); + break; + default: + jj_la1[30] = jj_gen; + ; + } + if (t1 != null) { + jjtn000.setPrefix(t0.image); + jjtn000.setLocalName(t1.image.substring(1)); + } else { + jjtn000.setLocalName(t0.image); + } + jj_consume_token(LPAREN); + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case INTEGER_LITERAL: + case FLOATING_POINT_LITERAL: + case STRING_LITERAL: + case TRUE: + case FALSE: + case NULL: + case LPAREN: + case NOT0: + case NOT1: + case EMPTY: + case MINUS: + case IDENTIFIER: + Expression(); + label_10: + while (true) { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case COMMA: + ; + break; + default: + jj_la1[31] = jj_gen; + break label_10; + } + jj_consume_token(COMMA); + Expression(); + } + break; + default: + jj_la1[32] = jj_gen; + ; + } + jj_consume_token(RPAREN); + } catch (Throwable jjte000) { + if (jjtc000) { + jjtree.clearNodeScope(jjtn000); + jjtc000 = false; + } else { + jjtree.popNode(); + } + if (jjte000 instanceof RuntimeException) { + {if (true) throw (RuntimeException)jjte000;} + } + if (jjte000 instanceof ParseException) { + {if (true) throw (ParseException)jjte000;} + } + {if (true) throw (Error)jjte000;} + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * Literal + * Reserved Keywords + */ + final public void Literal() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case TRUE: + case FALSE: + Boolean(); + break; + case FLOATING_POINT_LITERAL: + FloatingPoint(); + break; + case INTEGER_LITERAL: + Integer(); + break; + case STRING_LITERAL: + String(); + break; + case NULL: + Null(); + break; + default: + jj_la1[33] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + +/* + * Boolean + * For 'true' 'false' + */ + final public void Boolean() throws ParseException { + switch ((jj_ntk==-1)?jj_ntk():jj_ntk) { + case TRUE: + AstTrue jjtn001 = new AstTrue(JJTTRUE); + boolean jjtc001 = true; + jjtree.openNodeScope(jjtn001); + try { + jj_consume_token(TRUE); + } finally { + if (jjtc001) { + jjtree.closeNodeScope(jjtn001, true); + } + } + break; + case FALSE: + AstFalse jjtn002 = new AstFalse(JJTFALSE); + boolean jjtc002 = true; + jjtree.openNodeScope(jjtn002); + try { + jj_consume_token(FALSE); + } finally { + if (jjtc002) { + jjtree.closeNodeScope(jjtn002, true); + } + } + break; + default: + jj_la1[34] = jj_gen; + jj_consume_token(-1); + throw new ParseException(); + } + } + +/* + * FloatinPoint + * For Decimal and Floating Point Literals + */ + final public void FloatingPoint() throws ParseException { + /*@bgen(jjtree) FloatingPoint */ + AstFloatingPoint jjtn000 = new AstFloatingPoint(JJTFLOATINGPOINT); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + t = jj_consume_token(FLOATING_POINT_LITERAL); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * Integer + * For Simple Numeric Literals + */ + final public void Integer() throws ParseException { + /*@bgen(jjtree) Integer */ + AstInteger jjtn000 = new AstInteger(JJTINTEGER); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + t = jj_consume_token(INTEGER_LITERAL); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * String + * For Quoted Literals + */ + final public void String() throws ParseException { + /*@bgen(jjtree) String */ + AstString jjtn000 = new AstString(JJTSTRING); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000);Token t = null; + try { + t = jj_consume_token(STRING_LITERAL); + jjtree.closeNodeScope(jjtn000, true); + jjtc000 = false; + jjtn000.setImage(t.image); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + +/* + * Null + * For 'null' + */ + final public void Null() throws ParseException { + /*@bgen(jjtree) Null */ + AstNull jjtn000 = new AstNull(JJTNULL); + boolean jjtc000 = true; + jjtree.openNodeScope(jjtn000); + try { + jj_consume_token(NULL); + } finally { + if (jjtc000) { + jjtree.closeNodeScope(jjtn000, true); + } + } + } + + final private boolean jj_2_1(int xla) { + jj_la = xla; jj_lastpos = jj_scanpos = token; + try { return !jj_3_1(); } + catch(LookaheadSuccess ls) { return true; } + finally { jj_save(0, xla); } + } + + final private boolean jj_3_1() { + if (jj_3R_11()) return true; + return false; + } + + final private boolean jj_3R_11() { + if (jj_scan_token(IDENTIFIER)) return true; + Token xsp; + xsp = jj_scanpos; + if (jj_scan_token(54)) jj_scanpos = xsp; + if (jj_scan_token(LPAREN)) return true; + return false; + } + + public ELParserTokenManager token_source; + SimpleCharStream jj_input_stream; + public Token token, jj_nt; + private int jj_ntk; + private Token jj_scanpos, jj_lastpos; + private int jj_la; + public boolean lookingAhead = false; + private boolean jj_semLA; + private int jj_gen; + final private int[] jj_la1 = new int[35]; + static private int[] jj_la1_0; + static private int[] jj_la1_1; + static { + jj_la1_0(); + jj_la1_1(); + } + private static void jj_la1_0() { + jj_la1_0 = new int[] {0xe,0xe,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0xfe000000,0x18000000,0x6000000,0x80000000,0x60000000,0xfe000000,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x9d600,0x240000,0x9d600,0x240000,0x80000,0x0,0x0,0x1000000,0x9d600,0x1d600,0xc000,}; + } + private static void jj_la1_1() { + jj_la1_1 = new int[] {0x0,0x0,0x10000,0x600,0x600,0x180,0x180,0x1e,0x6,0x18,0x1e,0x1,0x0,0x0,0x1,0x0,0x1,0xc000,0xc000,0x1e2000,0x60000,0x180000,0x1e2000,0x60,0x208860,0x0,0x200000,0x0,0x0,0x200000,0x400000,0x0,0x208860,0x0,0x0,}; + } + final private JJCalls[] jj_2_rtns = new JJCalls[1]; + private boolean jj_rescan = false; + private int jj_gc = 0; + + public ELParser(java.io.InputStream stream) { + jj_input_stream = new SimpleCharStream(stream, 1, 1); + token_source = new ELParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + public void ReInit(java.io.InputStream stream) { + jj_input_stream.ReInit(stream, 1, 1); + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + public ELParser(java.io.Reader stream) { + jj_input_stream = new SimpleCharStream(stream, 1, 1); + token_source = new ELParserTokenManager(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + public void ReInit(java.io.Reader stream) { + jj_input_stream.ReInit(stream, 1, 1); + token_source.ReInit(jj_input_stream); + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + public ELParser(ELParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + public void ReInit(ELParserTokenManager tm) { + token_source = tm; + token = new Token(); + jj_ntk = -1; + jjtree.reset(); + jj_gen = 0; + for (int i = 0; i < 35; i++) jj_la1[i] = -1; + for (int i = 0; i < jj_2_rtns.length; i++) jj_2_rtns[i] = new JJCalls(); + } + + final private Token jj_consume_token(int kind) throws ParseException { + Token oldToken; + if ((oldToken = token).next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + if (token.kind == kind) { + jj_gen++; + if (++jj_gc > 100) { + jj_gc = 0; + for (int i = 0; i < jj_2_rtns.length; i++) { + JJCalls c = jj_2_rtns[i]; + while (c != null) { + if (c.gen < jj_gen) c.first = null; + c = c.next; + } + } + } + return token; + } + token = oldToken; + jj_kind = kind; + throw generateParseException(); + } + + static private final class LookaheadSuccess extends java.lang.Error { } + final private LookaheadSuccess jj_ls = new LookaheadSuccess(); + final private boolean jj_scan_token(int kind) { + if (jj_scanpos == jj_lastpos) { + jj_la--; + if (jj_scanpos.next == null) { + jj_lastpos = jj_scanpos = jj_scanpos.next = token_source.getNextToken(); + } else { + jj_lastpos = jj_scanpos = jj_scanpos.next; + } + } else { + jj_scanpos = jj_scanpos.next; + } + if (jj_rescan) { + int i = 0; Token tok = token; + while (tok != null && tok != jj_scanpos) { i++; tok = tok.next; } + if (tok != null) jj_add_error_token(kind, i); + } + if (jj_scanpos.kind != kind) return true; + if (jj_la == 0 && jj_scanpos == jj_lastpos) throw jj_ls; + return false; + } + + final public Token getNextToken() { + if (token.next != null) token = token.next; + else token = token.next = token_source.getNextToken(); + jj_ntk = -1; + jj_gen++; + return token; + } + + final public Token getToken(int index) { + Token t = lookingAhead ? jj_scanpos : token; + for (int i = 0; i < index; i++) { + if (t.next != null) t = t.next; + else t = t.next = token_source.getNextToken(); + } + return t; + } + + final private int jj_ntk() { + if ((jj_nt=token.next) == null) + return (jj_ntk = (token.next=token_source.getNextToken()).kind); + else + return (jj_ntk = jj_nt.kind); + } + + private java.util.Vector jj_expentries = new java.util.Vector(); + private int[] jj_expentry; + private int jj_kind = -1; + private int[] jj_lasttokens = new int[100]; + private int jj_endpos; + + private void jj_add_error_token(int kind, int pos) { + if (pos >= 100) return; + if (pos == jj_endpos + 1) { + jj_lasttokens[jj_endpos++] = kind; + } else if (jj_endpos != 0) { + jj_expentry = new int[jj_endpos]; + for (int i = 0; i < jj_endpos; i++) { + jj_expentry[i] = jj_lasttokens[i]; + } + boolean exists = false; + for (java.util.Enumeration e = jj_expentries.elements(); e.hasMoreElements();) { + int[] oldentry = (int[])(e.nextElement()); + if (oldentry.length == jj_expentry.length) { + exists = true; + for (int i = 0; i < jj_expentry.length; i++) { + if (oldentry[i] != jj_expentry[i]) { + exists = false; + break; + } + } + if (exists) break; + } + } + if (!exists) jj_expentries.addElement(jj_expentry); + if (pos != 0) jj_lasttokens[(jj_endpos = pos) - 1] = kind; + } + } + + public ParseException generateParseException() { + jj_expentries.removeAllElements(); + boolean[] la1tokens = new boolean[59]; + for (int i = 0; i < 59; i++) { + la1tokens[i] = false; + } + if (jj_kind >= 0) { + la1tokens[jj_kind] = true; + jj_kind = -1; + } + for (int i = 0; i < 35; i++) { + if (jj_la1[i] == jj_gen) { + for (int j = 0; j < 32; j++) { + if ((jj_la1_0[i] & (1< jj_gen) { + jj_la = p.arg; jj_lastpos = jj_scanpos = p.first; + switch (i) { + case 0: jj_3_1(); break; + } + } + p = p.next; + } while (p != null); + } + jj_rescan = false; + } + + final private void jj_save(int index, int xla) { + JJCalls p = jj_2_rtns[index]; + while (p.gen > jj_gen) { + if (p.next == null) { p = p.next = new JJCalls(); break; } + p = p.next; + } + p.gen = jj_gen + xla - jj_la; p.first = token; p.arg = xla; + } + + static final class JJCalls { + int gen; + Token first; + int arg; + JJCalls next; + } + +} diff --git a/java/org/apache/el/parser/ELParserConstants.java b/java/org/apache/el/parser/ELParserConstants.java index a1d9588eb..1fec4600c 100644 --- a/java/org/apache/el/parser/ELParserConstants.java +++ b/java/org/apache/el/parser/ELParserConstants.java @@ -1,126 +1,126 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserConstants.java */ -package org.apache.el.parser; - -public interface ELParserConstants { - - int EOF = 0; - int LITERAL_EXPRESSION = 1; - int START_DYNAMIC_EXPRESSION = 2; - int START_DEFERRED_EXPRESSION = 3; - int INTEGER_LITERAL = 9; - int FLOATING_POINT_LITERAL = 10; - int EXPONENT = 11; - int STRING_LITERAL = 12; - int BADLY_ESCAPED_STRING_LITERAL = 13; - int TRUE = 14; - int FALSE = 15; - int NULL = 16; - int END_EXPRESSION = 17; - int DOT = 18; - int LPAREN = 19; - int RPAREN = 20; - int LBRACK = 21; - int RBRACK = 22; - int COLON = 23; - int COMMA = 24; - int GT0 = 25; - int GT1 = 26; - int LT0 = 27; - int LT1 = 28; - int GE0 = 29; - int GE1 = 30; - int LE0 = 31; - int LE1 = 32; - int EQ0 = 33; - int EQ1 = 34; - int NE0 = 35; - int NE1 = 36; - int NOT0 = 37; - int NOT1 = 38; - int AND0 = 39; - int AND1 = 40; - int OR0 = 41; - int OR1 = 42; - int EMPTY = 43; - int INSTANCEOF = 44; - int MULT = 45; - int PLUS = 46; - int MINUS = 47; - int QUESTIONMARK = 48; - int DIV0 = 49; - int DIV1 = 50; - int MOD0 = 51; - int MOD1 = 52; - int IDENTIFIER = 53; - int FUNCTIONSUFFIX = 54; - int IMPL_OBJ_START = 55; - int LETTER = 56; - int DIGIT = 57; - int ILLEGAL_CHARACTER = 58; - - int DEFAULT = 0; - int IN_EXPRESSION = 1; - - String[] tokenImage = { - "", - "", - "\"${\"", - "\"#{\"", - "\"\\\\\"", - "\" \"", - "\"\\t\"", - "\"\\n\"", - "\"\\r\"", - "", - "", - "", - "", - "", - "\"true\"", - "\"false\"", - "\"null\"", - "\"}\"", - "\".\"", - "\"(\"", - "\")\"", - "\"[\"", - "\"]\"", - "\":\"", - "\",\"", - "\">\"", - "\"gt\"", - "\"<\"", - "\"lt\"", - "\">=\"", - "\"ge\"", - "\"<=\"", - "\"le\"", - "\"==\"", - "\"eq\"", - "\"!=\"", - "\"ne\"", - "\"!\"", - "\"not\"", - "\"&&\"", - "\"and\"", - "\"||\"", - "\"or\"", - "\"empty\"", - "\"instanceof\"", - "\"*\"", - "\"+\"", - "\"-\"", - "\"?\"", - "\"/\"", - "\"div\"", - "\"%\"", - "\"mod\"", - "", - "", - "\"#\"", - "", - "", - "", - }; - -} +/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserConstants.java */ +package org.apache.el.parser; + +public interface ELParserConstants { + + int EOF = 0; + int LITERAL_EXPRESSION = 1; + int START_DYNAMIC_EXPRESSION = 2; + int START_DEFERRED_EXPRESSION = 3; + int INTEGER_LITERAL = 9; + int FLOATING_POINT_LITERAL = 10; + int EXPONENT = 11; + int STRING_LITERAL = 12; + int BADLY_ESCAPED_STRING_LITERAL = 13; + int TRUE = 14; + int FALSE = 15; + int NULL = 16; + int END_EXPRESSION = 17; + int DOT = 18; + int LPAREN = 19; + int RPAREN = 20; + int LBRACK = 21; + int RBRACK = 22; + int COLON = 23; + int COMMA = 24; + int GT0 = 25; + int GT1 = 26; + int LT0 = 27; + int LT1 = 28; + int GE0 = 29; + int GE1 = 30; + int LE0 = 31; + int LE1 = 32; + int EQ0 = 33; + int EQ1 = 34; + int NE0 = 35; + int NE1 = 36; + int NOT0 = 37; + int NOT1 = 38; + int AND0 = 39; + int AND1 = 40; + int OR0 = 41; + int OR1 = 42; + int EMPTY = 43; + int INSTANCEOF = 44; + int MULT = 45; + int PLUS = 46; + int MINUS = 47; + int QUESTIONMARK = 48; + int DIV0 = 49; + int DIV1 = 50; + int MOD0 = 51; + int MOD1 = 52; + int IDENTIFIER = 53; + int FUNCTIONSUFFIX = 54; + int IMPL_OBJ_START = 55; + int LETTER = 56; + int DIGIT = 57; + int ILLEGAL_CHARACTER = 58; + + int DEFAULT = 0; + int IN_EXPRESSION = 1; + + String[] tokenImage = { + "", + "", + "\"${\"", + "\"#{\"", + "\"\\\\\"", + "\" \"", + "\"\\t\"", + "\"\\n\"", + "\"\\r\"", + "", + "", + "", + "", + "", + "\"true\"", + "\"false\"", + "\"null\"", + "\"}\"", + "\".\"", + "\"(\"", + "\")\"", + "\"[\"", + "\"]\"", + "\":\"", + "\",\"", + "\">\"", + "\"gt\"", + "\"<\"", + "\"lt\"", + "\">=\"", + "\"ge\"", + "\"<=\"", + "\"le\"", + "\"==\"", + "\"eq\"", + "\"!=\"", + "\"ne\"", + "\"!\"", + "\"not\"", + "\"&&\"", + "\"and\"", + "\"||\"", + "\"or\"", + "\"empty\"", + "\"instanceof\"", + "\"*\"", + "\"+\"", + "\"-\"", + "\"?\"", + "\"/\"", + "\"div\"", + "\"%\"", + "\"mod\"", + "", + "", + "\"#\"", + "", + "", + "", + }; + +} diff --git a/java/org/apache/el/parser/ELParserTokenManager.java b/java/org/apache/el/parser/ELParserTokenManager.java index d1d2b53df..23b56dfb0 100644 --- a/java/org/apache/el/parser/ELParserTokenManager.java +++ b/java/org/apache/el/parser/ELParserTokenManager.java @@ -1,1281 +1,1281 @@ -/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserTokenManager.java */ -package org.apache.el.parser; -import java.io.StringReader; -import javax.el.ELException; - -public class ELParserTokenManager implements ELParserConstants -{ - public java.io.PrintStream debugStream = System.out; - public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } -private final int jjStopStringLiteralDfa_0(int pos, long active0) -{ - switch (pos) - { - case 0: - if ((active0 & 0x10L) != 0L) - return 2; - if ((active0 & 0x4L) != 0L) - { - jjmatchedKind = 1; - return 4; - } - if ((active0 & 0x8L) != 0L) - { - jjmatchedKind = 1; - return 6; - } - return -1; - default : - return -1; - } -} -private final int jjStartNfa_0(int pos, long active0) -{ - return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); -} -private final int jjStopAtPos(int pos, int kind) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - return pos + 1; -} -private final int jjStartNfaWithStates_0(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_0(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_0() -{ - switch(curChar) - { - case 35: - return jjMoveStringLiteralDfa1_0(0x8L); - case 36: - return jjMoveStringLiteralDfa1_0(0x4L); - case 92: - return jjStartNfaWithStates_0(0, 4, 2); - default : - return jjMoveNfa_0(7, 0); - } -} -private final int jjMoveStringLiteralDfa1_0(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_0(0, active0); - return 1; - } - switch(curChar) - { - case 123: - if ((active0 & 0x4L) != 0L) - return jjStopAtPos(1, 2); - else if ((active0 & 0x8L) != 0L) - return jjStopAtPos(1, 3); - break; - default : - break; - } - return jjStartNfa_0(0, active0); -} -private final void jjCheckNAdd(int state) -{ - if (jjrounds[state] != jjround) - { - jjstateSet[jjnewStateCnt++] = state; - jjrounds[state] = jjround; - } -} -private final void jjAddStates(int start, int end) -{ - do { - jjstateSet[jjnewStateCnt++] = jjnextStates[start]; - } while (start++ != end); -} -private final void jjCheckNAddTwoStates(int state1, int state2) -{ - jjCheckNAdd(state1); - jjCheckNAdd(state2); -} -private final void jjCheckNAddStates(int start, int end) -{ - do { - jjCheckNAdd(jjnextStates[start]); - } while (start++ != end); -} -private final void jjCheckNAddStates(int start) -{ - jjCheckNAdd(jjnextStates[start]); - jjCheckNAdd(jjnextStates[start + 1]); -} -static final long[] jjbitVec0 = { - 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -static final long[] jjbitVec2 = { - 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -private final int jjMoveNfa_0(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 8; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 7: - if ((0xffffffe7ffffffffL & l) != 0L) - { - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - } - else if ((0x1800000000L & l) != 0L) - { - if (kind > 1) - kind = 1; - } - if (curChar == 35) - jjstateSet[jjnewStateCnt++] = 6; - else if (curChar == 36) - jjstateSet[jjnewStateCnt++] = 4; - break; - case 0: - if ((0xffffffe7ffffffffL & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - case 2: - if ((0x1800000000L & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - case 3: - if (curChar == 36) - jjstateSet[jjnewStateCnt++] = 4; - break; - case 4: - if ((0xffffffefffffffffL & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - case 5: - if (curChar == 35) - jjstateSet[jjnewStateCnt++] = 6; - break; - case 6: - if ((0xfffffff7ffffffffL & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 7: - if ((0xffffffffefffffffL & l) != 0L) - { - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - } - else if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 2; - break; - case 0: - if ((0xffffffffefffffffL & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - case 1: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 2; - break; - case 2: - if (curChar != 92) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - case 4: - case 6: - if ((0xf7ffffffffffffffL & l) == 0L) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - default : break; - } - } while(i != startsAt); - } - else - { - int hiByte = (int)(curChar >> 8); - int i1 = hiByte >> 6; - long l1 = 1L << (hiByte & 077); - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 7: - case 0: - case 4: - case 6: - if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) - break; - if (kind > 1) - kind = 1; - jjCheckNAddStates(0, 3); - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 8 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -private final int jjStopStringLiteralDfa_1(int pos, long active0) -{ - switch (pos) - { - case 0: - if ((active0 & 0x800000L) != 0L) - return 8; - if ((active0 & 0x40000L) != 0L) - return 1; - if ((active0 & 0x141d555401c000L) != 0L) - { - jjmatchedKind = 53; - return 6; - } - return -1; - case 1: - if ((active0 & 0x41554000000L) != 0L) - return 6; - if ((active0 & 0x1419400001c000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 1; - return 6; - } - return -1; - case 2: - if ((active0 & 0x14014000000000L) != 0L) - return 6; - if ((active0 & 0x18000001c000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 2; - return 6; - } - return -1; - case 3: - if ((active0 & 0x14000L) != 0L) - return 6; - if ((active0 & 0x180000008000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 3; - return 6; - } - return -1; - case 4: - if ((active0 & 0x80000008000L) != 0L) - return 6; - if ((active0 & 0x100000000000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 4; - return 6; - } - return -1; - case 5: - if ((active0 & 0x100000000000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 5; - return 6; - } - return -1; - case 6: - if ((active0 & 0x100000000000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 6; - return 6; - } - return -1; - case 7: - if ((active0 & 0x100000000000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 7; - return 6; - } - return -1; - case 8: - if ((active0 & 0x100000000000L) != 0L) - { - jjmatchedKind = 53; - jjmatchedPos = 8; - return 6; - } - return -1; - default : - return -1; - } -} -private final int jjStartNfa_1(int pos, long active0) -{ - return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); -} -private final int jjStartNfaWithStates_1(int pos, int kind, int state) -{ - jjmatchedKind = kind; - jjmatchedPos = pos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return pos + 1; } - return jjMoveNfa_1(state, pos + 1); -} -private final int jjMoveStringLiteralDfa0_1() -{ - switch(curChar) - { - case 33: - jjmatchedKind = 37; - return jjMoveStringLiteralDfa1_1(0x800000000L); - case 37: - return jjStopAtPos(0, 51); - case 38: - return jjMoveStringLiteralDfa1_1(0x8000000000L); - case 40: - return jjStopAtPos(0, 19); - case 41: - return jjStopAtPos(0, 20); - case 42: - return jjStopAtPos(0, 45); - case 43: - return jjStopAtPos(0, 46); - case 44: - return jjStopAtPos(0, 24); - case 45: - return jjStopAtPos(0, 47); - case 46: - return jjStartNfaWithStates_1(0, 18, 1); - case 47: - return jjStopAtPos(0, 49); - case 58: - return jjStartNfaWithStates_1(0, 23, 8); - case 60: - jjmatchedKind = 27; - return jjMoveStringLiteralDfa1_1(0x80000000L); - case 61: - return jjMoveStringLiteralDfa1_1(0x200000000L); - case 62: - jjmatchedKind = 25; - return jjMoveStringLiteralDfa1_1(0x20000000L); - case 63: - return jjStopAtPos(0, 48); - case 91: - return jjStopAtPos(0, 21); - case 93: - return jjStopAtPos(0, 22); - case 97: - return jjMoveStringLiteralDfa1_1(0x10000000000L); - case 100: - return jjMoveStringLiteralDfa1_1(0x4000000000000L); - case 101: - return jjMoveStringLiteralDfa1_1(0x80400000000L); - case 102: - return jjMoveStringLiteralDfa1_1(0x8000L); - case 103: - return jjMoveStringLiteralDfa1_1(0x44000000L); - case 105: - return jjMoveStringLiteralDfa1_1(0x100000000000L); - case 108: - return jjMoveStringLiteralDfa1_1(0x110000000L); - case 109: - return jjMoveStringLiteralDfa1_1(0x10000000000000L); - case 110: - return jjMoveStringLiteralDfa1_1(0x5000010000L); - case 111: - return jjMoveStringLiteralDfa1_1(0x40000000000L); - case 116: - return jjMoveStringLiteralDfa1_1(0x4000L); - case 124: - return jjMoveStringLiteralDfa1_1(0x20000000000L); - case 125: - return jjStopAtPos(0, 17); - default : - return jjMoveNfa_1(0, 0); - } -} -private final int jjMoveStringLiteralDfa1_1(long active0) -{ - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(0, active0); - return 1; - } - switch(curChar) - { - case 38: - if ((active0 & 0x8000000000L) != 0L) - return jjStopAtPos(1, 39); - break; - case 61: - if ((active0 & 0x20000000L) != 0L) - return jjStopAtPos(1, 29); - else if ((active0 & 0x80000000L) != 0L) - return jjStopAtPos(1, 31); - else if ((active0 & 0x200000000L) != 0L) - return jjStopAtPos(1, 33); - else if ((active0 & 0x800000000L) != 0L) - return jjStopAtPos(1, 35); - break; - case 97: - return jjMoveStringLiteralDfa2_1(active0, 0x8000L); - case 101: - if ((active0 & 0x40000000L) != 0L) - return jjStartNfaWithStates_1(1, 30, 6); - else if ((active0 & 0x100000000L) != 0L) - return jjStartNfaWithStates_1(1, 32, 6); - else if ((active0 & 0x1000000000L) != 0L) - return jjStartNfaWithStates_1(1, 36, 6); - break; - case 105: - return jjMoveStringLiteralDfa2_1(active0, 0x4000000000000L); - case 109: - return jjMoveStringLiteralDfa2_1(active0, 0x80000000000L); - case 110: - return jjMoveStringLiteralDfa2_1(active0, 0x110000000000L); - case 111: - return jjMoveStringLiteralDfa2_1(active0, 0x10004000000000L); - case 113: - if ((active0 & 0x400000000L) != 0L) - return jjStartNfaWithStates_1(1, 34, 6); - break; - case 114: - if ((active0 & 0x40000000000L) != 0L) - return jjStartNfaWithStates_1(1, 42, 6); - return jjMoveStringLiteralDfa2_1(active0, 0x4000L); - case 116: - if ((active0 & 0x4000000L) != 0L) - return jjStartNfaWithStates_1(1, 26, 6); - else if ((active0 & 0x10000000L) != 0L) - return jjStartNfaWithStates_1(1, 28, 6); - break; - case 117: - return jjMoveStringLiteralDfa2_1(active0, 0x10000L); - case 124: - if ((active0 & 0x20000000000L) != 0L) - return jjStopAtPos(1, 41); - break; - default : - break; - } - return jjStartNfa_1(0, active0); -} -private final int jjMoveStringLiteralDfa2_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(0, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(1, active0); - return 2; - } - switch(curChar) - { - case 100: - if ((active0 & 0x10000000000L) != 0L) - return jjStartNfaWithStates_1(2, 40, 6); - else if ((active0 & 0x10000000000000L) != 0L) - return jjStartNfaWithStates_1(2, 52, 6); - break; - case 108: - return jjMoveStringLiteralDfa3_1(active0, 0x18000L); - case 112: - return jjMoveStringLiteralDfa3_1(active0, 0x80000000000L); - case 115: - return jjMoveStringLiteralDfa3_1(active0, 0x100000000000L); - case 116: - if ((active0 & 0x4000000000L) != 0L) - return jjStartNfaWithStates_1(2, 38, 6); - break; - case 117: - return jjMoveStringLiteralDfa3_1(active0, 0x4000L); - case 118: - if ((active0 & 0x4000000000000L) != 0L) - return jjStartNfaWithStates_1(2, 50, 6); - break; - default : - break; - } - return jjStartNfa_1(1, active0); -} -private final int jjMoveStringLiteralDfa3_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(1, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(2, active0); - return 3; - } - switch(curChar) - { - case 101: - if ((active0 & 0x4000L) != 0L) - return jjStartNfaWithStates_1(3, 14, 6); - break; - case 108: - if ((active0 & 0x10000L) != 0L) - return jjStartNfaWithStates_1(3, 16, 6); - break; - case 115: - return jjMoveStringLiteralDfa4_1(active0, 0x8000L); - case 116: - return jjMoveStringLiteralDfa4_1(active0, 0x180000000000L); - default : - break; - } - return jjStartNfa_1(2, active0); -} -private final int jjMoveStringLiteralDfa4_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(2, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(3, active0); - return 4; - } - switch(curChar) - { - case 97: - return jjMoveStringLiteralDfa5_1(active0, 0x100000000000L); - case 101: - if ((active0 & 0x8000L) != 0L) - return jjStartNfaWithStates_1(4, 15, 6); - break; - case 121: - if ((active0 & 0x80000000000L) != 0L) - return jjStartNfaWithStates_1(4, 43, 6); - break; - default : - break; - } - return jjStartNfa_1(3, active0); -} -private final int jjMoveStringLiteralDfa5_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(3, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(4, active0); - return 5; - } - switch(curChar) - { - case 110: - return jjMoveStringLiteralDfa6_1(active0, 0x100000000000L); - default : - break; - } - return jjStartNfa_1(4, active0); -} -private final int jjMoveStringLiteralDfa6_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(4, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(5, active0); - return 6; - } - switch(curChar) - { - case 99: - return jjMoveStringLiteralDfa7_1(active0, 0x100000000000L); - default : - break; - } - return jjStartNfa_1(5, active0); -} -private final int jjMoveStringLiteralDfa7_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(5, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(6, active0); - return 7; - } - switch(curChar) - { - case 101: - return jjMoveStringLiteralDfa8_1(active0, 0x100000000000L); - default : - break; - } - return jjStartNfa_1(6, active0); -} -private final int jjMoveStringLiteralDfa8_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(6, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(7, active0); - return 8; - } - switch(curChar) - { - case 111: - return jjMoveStringLiteralDfa9_1(active0, 0x100000000000L); - default : - break; - } - return jjStartNfa_1(7, active0); -} -private final int jjMoveStringLiteralDfa9_1(long old0, long active0) -{ - if (((active0 &= old0)) == 0L) - return jjStartNfa_1(7, old0); - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { - jjStopStringLiteralDfa_1(8, active0); - return 9; - } - switch(curChar) - { - case 102: - if ((active0 & 0x100000000000L) != 0L) - return jjStartNfaWithStates_1(9, 44, 6); - break; - default : - break; - } - return jjStartNfa_1(8, active0); -} -static final long[] jjbitVec3 = { - 0x1ff00000fffffffeL, 0xffffffffffffc000L, 0xffffffffL, 0x600000000000000L -}; -static final long[] jjbitVec4 = { - 0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL -}; -static final long[] jjbitVec5 = { - 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL -}; -static final long[] jjbitVec6 = { - 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffL, 0x0L -}; -static final long[] jjbitVec7 = { - 0xffffffffffffffffL, 0xffffffffffffffffL, 0x0L, 0x0L -}; -static final long[] jjbitVec8 = { - 0x3fffffffffffL, 0x0L, 0x0L, 0x0L -}; -private final int jjMoveNfa_1(int startState, int curPos) -{ - int[] nextStates; - int startsAt = 0; - jjnewStateCnt = 38; - int i = 1; - jjstateSet[0] = startState; - int j, kind = 0x7fffffff; - for (;;) - { - if (++jjround == 0x7fffffff) - ReInitRounds(); - if (curChar < 64) - { - long l = 1L << curChar; - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - if ((0x3ff000000000000L & l) != 0L) - { - if (kind > 9) - kind = 9; - jjCheckNAddStates(4, 8); - } - else if ((0x1800000000L & l) != 0L) - { - if (kind > 53) - kind = 53; - jjCheckNAdd(6); - } - else if (curChar == 39) - jjCheckNAddStates(9, 13); - else if (curChar == 34) - jjCheckNAddStates(14, 18); - else if (curChar == 58) - jjstateSet[jjnewStateCnt++] = 8; - else if (curChar == 46) - jjCheckNAdd(1); - break; - case 1: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 10) - kind = 10; - jjCheckNAddTwoStates(1, 2); - break; - case 3: - if ((0x280000000000L & l) != 0L) - jjCheckNAdd(4); - break; - case 4: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 10) - kind = 10; - jjCheckNAdd(4); - break; - case 5: - if ((0x1800000000L & l) == 0L) - break; - if (kind > 53) - kind = 53; - jjCheckNAdd(6); - break; - case 6: - if ((0x3ff001000000000L & l) == 0L) - break; - if (kind > 53) - kind = 53; - jjCheckNAdd(6); - break; - case 7: - if (curChar == 58) - jjstateSet[jjnewStateCnt++] = 8; - break; - case 8: - if ((0x1800000000L & l) == 0L) - break; - if (kind > 54) - kind = 54; - jjCheckNAdd(9); - break; - case 9: - if ((0x3ff001000000000L & l) == 0L) - break; - if (kind > 54) - kind = 54; - jjCheckNAdd(9); - break; - case 10: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 9) - kind = 9; - jjCheckNAddStates(4, 8); - break; - case 11: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 9) - kind = 9; - jjCheckNAdd(11); - break; - case 12: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(12, 13); - break; - case 13: - if (curChar != 46) - break; - if (kind > 10) - kind = 10; - jjCheckNAddTwoStates(14, 15); - break; - case 14: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 10) - kind = 10; - jjCheckNAddTwoStates(14, 15); - break; - case 16: - if ((0x280000000000L & l) != 0L) - jjCheckNAdd(17); - break; - case 17: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 10) - kind = 10; - jjCheckNAdd(17); - break; - case 18: - if ((0x3ff000000000000L & l) != 0L) - jjCheckNAddTwoStates(18, 19); - break; - case 20: - if ((0x280000000000L & l) != 0L) - jjCheckNAdd(21); - break; - case 21: - if ((0x3ff000000000000L & l) == 0L) - break; - if (kind > 10) - kind = 10; - jjCheckNAdd(21); - break; - case 22: - if (curChar == 34) - jjCheckNAddStates(14, 18); - break; - case 23: - if ((0xfffffffbffffffffL & l) != 0L) - jjCheckNAddStates(19, 21); - break; - case 25: - if (curChar == 34) - jjCheckNAddStates(19, 21); - break; - case 26: - if (curChar == 34 && kind > 12) - kind = 12; - break; - case 27: - if ((0xfffffffbffffffffL & l) != 0L) - jjCheckNAddTwoStates(27, 28); - break; - case 29: - if ((0xfffffffbffffffffL & l) != 0L && kind > 13) - kind = 13; - break; - case 30: - if (curChar == 39) - jjCheckNAddStates(9, 13); - break; - case 31: - if ((0xffffff7fffffffffL & l) != 0L) - jjCheckNAddStates(22, 24); - break; - case 33: - if (curChar == 39) - jjCheckNAddStates(22, 24); - break; - case 34: - if (curChar == 39 && kind > 12) - kind = 12; - break; - case 35: - if ((0xffffff7fffffffffL & l) != 0L) - jjCheckNAddTwoStates(35, 36); - break; - case 37: - if ((0xffffff7fffffffffL & l) != 0L && kind > 13) - kind = 13; - break; - default : break; - } - } while(i != startsAt); - } - else if (curChar < 128) - { - long l = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 6: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 53) - kind = 53; - jjCheckNAdd(6); - break; - case 2: - if ((0x2000000020L & l) != 0L) - jjAddStates(25, 26); - break; - case 8: - case 9: - if ((0x7fffffe87fffffeL & l) == 0L) - break; - if (kind > 54) - kind = 54; - jjCheckNAdd(9); - break; - case 15: - if ((0x2000000020L & l) != 0L) - jjAddStates(27, 28); - break; - case 19: - if ((0x2000000020L & l) != 0L) - jjAddStates(29, 30); - break; - case 23: - if ((0xffffffffefffffffL & l) != 0L) - jjCheckNAddStates(19, 21); - break; - case 24: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 25; - break; - case 25: - if (curChar == 92) - jjCheckNAddStates(19, 21); - break; - case 27: - if ((0xffffffffefffffffL & l) != 0L) - jjAddStates(31, 32); - break; - case 28: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 29; - break; - case 29: - case 37: - if ((0xffffffffefffffffL & l) != 0L && kind > 13) - kind = 13; - break; - case 31: - if ((0xffffffffefffffffL & l) != 0L) - jjCheckNAddStates(22, 24); - break; - case 32: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 33; - break; - case 33: - if (curChar == 92) - jjCheckNAddStates(22, 24); - break; - case 35: - if ((0xffffffffefffffffL & l) != 0L) - jjAddStates(33, 34); - break; - case 36: - if (curChar == 92) - jjstateSet[jjnewStateCnt++] = 37; - break; - default : break; - } - } while(i != startsAt); - } - else - { - int hiByte = (int)(curChar >> 8); - int i1 = hiByte >> 6; - long l1 = 1L << (hiByte & 077); - int i2 = (curChar & 0xff) >> 6; - long l2 = 1L << (curChar & 077); - MatchLoop: do - { - switch(jjstateSet[--i]) - { - case 0: - case 6: - if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) - break; - if (kind > 53) - kind = 53; - jjCheckNAdd(6); - break; - case 8: - case 9: - if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) - break; - if (kind > 54) - kind = 54; - jjCheckNAdd(9); - break; - case 23: - if (jjCanMove_0(hiByte, i1, i2, l1, l2)) - jjAddStates(19, 21); - break; - case 27: - if (jjCanMove_0(hiByte, i1, i2, l1, l2)) - jjAddStates(31, 32); - break; - case 29: - case 37: - if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 13) - kind = 13; - break; - case 31: - if (jjCanMove_0(hiByte, i1, i2, l1, l2)) - jjAddStates(22, 24); - break; - case 35: - if (jjCanMove_0(hiByte, i1, i2, l1, l2)) - jjAddStates(33, 34); - break; - default : break; - } - } while(i != startsAt); - } - if (kind != 0x7fffffff) - { - jjmatchedKind = kind; - jjmatchedPos = curPos; - kind = 0x7fffffff; - } - ++curPos; - if ((i = jjnewStateCnt) == (startsAt = 38 - (jjnewStateCnt = startsAt))) - return curPos; - try { curChar = input_stream.readChar(); } - catch(java.io.IOException e) { return curPos; } - } -} -static final int[] jjnextStates = { - 0, 1, 3, 5, 11, 12, 13, 18, 19, 31, 32, 34, 35, 36, 23, 24, - 26, 27, 28, 23, 24, 26, 31, 32, 34, 3, 4, 16, 17, 20, 21, 27, - 28, 35, 36, -}; -private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) -{ - switch(hiByte) - { - case 0: - return ((jjbitVec2[i2] & l2) != 0L); - default : - if ((jjbitVec0[i1] & l1) != 0L) - return true; - return false; - } -} -private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) -{ - switch(hiByte) - { - case 0: - return ((jjbitVec4[i2] & l2) != 0L); - case 48: - return ((jjbitVec5[i2] & l2) != 0L); - case 49: - return ((jjbitVec6[i2] & l2) != 0L); - case 51: - return ((jjbitVec7[i2] & l2) != 0L); - case 61: - return ((jjbitVec8[i2] & l2) != 0L); - default : - if ((jjbitVec3[i1] & l1) != 0L) - return true; - return false; - } -} -public static final String[] jjstrLiteralImages = { -"", null, "\44\173", "\43\173", null, null, null, null, null, null, null, null, -null, null, "\164\162\165\145", "\146\141\154\163\145", "\156\165\154\154", "\175", -"\56", "\50", "\51", "\133", "\135", "\72", "\54", "\76", "\147\164", "\74", -"\154\164", "\76\75", "\147\145", "\74\75", "\154\145", "\75\75", "\145\161", "\41\75", -"\156\145", "\41", "\156\157\164", "\46\46", "\141\156\144", "\174\174", "\157\162", -"\145\155\160\164\171", "\151\156\163\164\141\156\143\145\157\146", "\52", "\53", "\55", "\77", "\57", -"\144\151\166", "\45", "\155\157\144", null, null, null, null, null, null, }; -public static final String[] lexStateNames = { - "DEFAULT", - "IN_EXPRESSION", -}; -public static final int[] jjnewLexState = { - -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -}; -static final long[] jjtoToken = { - 0x47ffffffffff60fL, -}; -static final long[] jjtoSkip = { - 0x1f0L, -}; -protected SimpleCharStream input_stream; -private final int[] jjrounds = new int[38]; -private final int[] jjstateSet = new int[76]; -protected char curChar; -public ELParserTokenManager(SimpleCharStream stream) -{ - if (SimpleCharStream.staticFlag) - throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); - input_stream = stream; -} -public ELParserTokenManager(SimpleCharStream stream, int lexState) -{ - this(stream); - SwitchTo(lexState); -} -public void ReInit(SimpleCharStream stream) -{ - jjmatchedPos = jjnewStateCnt = 0; - curLexState = defaultLexState; - input_stream = stream; - ReInitRounds(); -} -private final void ReInitRounds() -{ - int i; - jjround = 0x80000001; - for (i = 38; i-- > 0;) - jjrounds[i] = 0x80000000; -} -public void ReInit(SimpleCharStream stream, int lexState) -{ - ReInit(stream); - SwitchTo(lexState); -} -public void SwitchTo(int lexState) -{ - if (lexState >= 2 || lexState < 0) - throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); - else - curLexState = lexState; -} - -protected Token jjFillToken() -{ - Token t = Token.newToken(jjmatchedKind); - t.kind = jjmatchedKind; - String im = jjstrLiteralImages[jjmatchedKind]; - t.image = (im == null) ? input_stream.GetImage() : im; - t.beginLine = input_stream.getBeginLine(); - t.beginColumn = input_stream.getBeginColumn(); - t.endLine = input_stream.getEndLine(); - t.endColumn = input_stream.getEndColumn(); - return t; -} - -int curLexState = 0; -int defaultLexState = 0; -int jjnewStateCnt; -int jjround; -int jjmatchedPos; -int jjmatchedKind; - -public Token getNextToken() -{ - int kind; - Token specialToken = null; - Token matchedToken; - int curPos = 0; - - EOFLoop : - for (;;) - { - try - { - curChar = input_stream.BeginToken(); - } - catch(java.io.IOException e) - { - jjmatchedKind = 0; - matchedToken = jjFillToken(); - return matchedToken; - } - - switch(curLexState) - { - case 0: - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_0(); - break; - case 1: - try { input_stream.backup(0); - while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) - curChar = input_stream.BeginToken(); - } - catch (java.io.IOException e1) { continue EOFLoop; } - jjmatchedKind = 0x7fffffff; - jjmatchedPos = 0; - curPos = jjMoveStringLiteralDfa0_1(); - if (jjmatchedPos == 0 && jjmatchedKind > 58) - { - jjmatchedKind = 58; - } - break; - } - if (jjmatchedKind != 0x7fffffff) - { - if (jjmatchedPos + 1 < curPos) - input_stream.backup(curPos - jjmatchedPos - 1); - if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) - { - matchedToken = jjFillToken(); - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - return matchedToken; - } - else - { - if (jjnewLexState[jjmatchedKind] != -1) - curLexState = jjnewLexState[jjmatchedKind]; - continue EOFLoop; - } - } - int error_line = input_stream.getEndLine(); - int error_column = input_stream.getEndColumn(); - String error_after = null; - boolean EOFSeen = false; - try { input_stream.readChar(); input_stream.backup(1); } - catch (java.io.IOException e1) { - EOFSeen = true; - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - if (curChar == '\n' || curChar == '\r') { - error_line++; - error_column = 0; - } - else - error_column++; - } - if (!EOFSeen) { - input_stream.backup(1); - error_after = curPos <= 1 ? "" : input_stream.GetImage(); - } - throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); - } -} - -} +/* Generated By:JJTree&JavaCC: Do not edit this line. ELParserTokenManager.java */ +package org.apache.el.parser; +import java.io.StringReader; +import javax.el.ELException; + +public class ELParserTokenManager implements ELParserConstants +{ + public java.io.PrintStream debugStream = System.out; + public void setDebugStream(java.io.PrintStream ds) { debugStream = ds; } +private final int jjStopStringLiteralDfa_0(int pos, long active0) +{ + switch (pos) + { + case 0: + if ((active0 & 0x10L) != 0L) + return 2; + if ((active0 & 0x4L) != 0L) + { + jjmatchedKind = 1; + return 4; + } + if ((active0 & 0x8L) != 0L) + { + jjmatchedKind = 1; + return 6; + } + return -1; + default : + return -1; + } +} +private final int jjStartNfa_0(int pos, long active0) +{ + return jjMoveNfa_0(jjStopStringLiteralDfa_0(pos, active0), pos + 1); +} +private final int jjStopAtPos(int pos, int kind) +{ + jjmatchedKind = kind; + jjmatchedPos = pos; + return pos + 1; +} +private final int jjStartNfaWithStates_0(int pos, int kind, int state) +{ + jjmatchedKind = kind; + jjmatchedPos = pos; + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return pos + 1; } + return jjMoveNfa_0(state, pos + 1); +} +private final int jjMoveStringLiteralDfa0_0() +{ + switch(curChar) + { + case 35: + return jjMoveStringLiteralDfa1_0(0x8L); + case 36: + return jjMoveStringLiteralDfa1_0(0x4L); + case 92: + return jjStartNfaWithStates_0(0, 4, 2); + default : + return jjMoveNfa_0(7, 0); + } +} +private final int jjMoveStringLiteralDfa1_0(long active0) +{ + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_0(0, active0); + return 1; + } + switch(curChar) + { + case 123: + if ((active0 & 0x4L) != 0L) + return jjStopAtPos(1, 2); + else if ((active0 & 0x8L) != 0L) + return jjStopAtPos(1, 3); + break; + default : + break; + } + return jjStartNfa_0(0, active0); +} +private final void jjCheckNAdd(int state) +{ + if (jjrounds[state] != jjround) + { + jjstateSet[jjnewStateCnt++] = state; + jjrounds[state] = jjround; + } +} +private final void jjAddStates(int start, int end) +{ + do { + jjstateSet[jjnewStateCnt++] = jjnextStates[start]; + } while (start++ != end); +} +private final void jjCheckNAddTwoStates(int state1, int state2) +{ + jjCheckNAdd(state1); + jjCheckNAdd(state2); +} +private final void jjCheckNAddStates(int start, int end) +{ + do { + jjCheckNAdd(jjnextStates[start]); + } while (start++ != end); +} +private final void jjCheckNAddStates(int start) +{ + jjCheckNAdd(jjnextStates[start]); + jjCheckNAdd(jjnextStates[start + 1]); +} +static final long[] jjbitVec0 = { + 0xfffffffffffffffeL, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL +}; +static final long[] jjbitVec2 = { + 0x0L, 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL +}; +private final int jjMoveNfa_0(int startState, int curPos) +{ + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 8; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (;;) + { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) + { + long l = 1L << curChar; + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 7: + if ((0xffffffe7ffffffffL & l) != 0L) + { + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + } + else if ((0x1800000000L & l) != 0L) + { + if (kind > 1) + kind = 1; + } + if (curChar == 35) + jjstateSet[jjnewStateCnt++] = 6; + else if (curChar == 36) + jjstateSet[jjnewStateCnt++] = 4; + break; + case 0: + if ((0xffffffe7ffffffffL & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + case 2: + if ((0x1800000000L & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + case 3: + if (curChar == 36) + jjstateSet[jjnewStateCnt++] = 4; + break; + case 4: + if ((0xffffffefffffffffL & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + case 5: + if (curChar == 35) + jjstateSet[jjnewStateCnt++] = 6; + break; + case 6: + if ((0xfffffff7ffffffffL & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + default : break; + } + } while(i != startsAt); + } + else if (curChar < 128) + { + long l = 1L << (curChar & 077); + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 7: + if ((0xffffffffefffffffL & l) != 0L) + { + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + } + else if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 2; + break; + case 0: + if ((0xffffffffefffffffL & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + case 1: + if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 2; + break; + case 2: + if (curChar != 92) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + case 4: + case 6: + if ((0xf7ffffffffffffffL & l) == 0L) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + default : break; + } + } while(i != startsAt); + } + else + { + int hiByte = (int)(curChar >> 8); + int i1 = hiByte >> 6; + long l1 = 1L << (hiByte & 077); + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 7: + case 0: + case 4: + case 6: + if (!jjCanMove_0(hiByte, i1, i2, l1, l2)) + break; + if (kind > 1) + kind = 1; + jjCheckNAddStates(0, 3); + break; + default : break; + } + } while(i != startsAt); + } + if (kind != 0x7fffffff) + { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 8 - (jjnewStateCnt = startsAt))) + return curPos; + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return curPos; } + } +} +private final int jjStopStringLiteralDfa_1(int pos, long active0) +{ + switch (pos) + { + case 0: + if ((active0 & 0x800000L) != 0L) + return 8; + if ((active0 & 0x40000L) != 0L) + return 1; + if ((active0 & 0x141d555401c000L) != 0L) + { + jjmatchedKind = 53; + return 6; + } + return -1; + case 1: + if ((active0 & 0x41554000000L) != 0L) + return 6; + if ((active0 & 0x1419400001c000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 1; + return 6; + } + return -1; + case 2: + if ((active0 & 0x14014000000000L) != 0L) + return 6; + if ((active0 & 0x18000001c000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 2; + return 6; + } + return -1; + case 3: + if ((active0 & 0x14000L) != 0L) + return 6; + if ((active0 & 0x180000008000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 3; + return 6; + } + return -1; + case 4: + if ((active0 & 0x80000008000L) != 0L) + return 6; + if ((active0 & 0x100000000000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 4; + return 6; + } + return -1; + case 5: + if ((active0 & 0x100000000000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 5; + return 6; + } + return -1; + case 6: + if ((active0 & 0x100000000000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 6; + return 6; + } + return -1; + case 7: + if ((active0 & 0x100000000000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 7; + return 6; + } + return -1; + case 8: + if ((active0 & 0x100000000000L) != 0L) + { + jjmatchedKind = 53; + jjmatchedPos = 8; + return 6; + } + return -1; + default : + return -1; + } +} +private final int jjStartNfa_1(int pos, long active0) +{ + return jjMoveNfa_1(jjStopStringLiteralDfa_1(pos, active0), pos + 1); +} +private final int jjStartNfaWithStates_1(int pos, int kind, int state) +{ + jjmatchedKind = kind; + jjmatchedPos = pos; + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return pos + 1; } + return jjMoveNfa_1(state, pos + 1); +} +private final int jjMoveStringLiteralDfa0_1() +{ + switch(curChar) + { + case 33: + jjmatchedKind = 37; + return jjMoveStringLiteralDfa1_1(0x800000000L); + case 37: + return jjStopAtPos(0, 51); + case 38: + return jjMoveStringLiteralDfa1_1(0x8000000000L); + case 40: + return jjStopAtPos(0, 19); + case 41: + return jjStopAtPos(0, 20); + case 42: + return jjStopAtPos(0, 45); + case 43: + return jjStopAtPos(0, 46); + case 44: + return jjStopAtPos(0, 24); + case 45: + return jjStopAtPos(0, 47); + case 46: + return jjStartNfaWithStates_1(0, 18, 1); + case 47: + return jjStopAtPos(0, 49); + case 58: + return jjStartNfaWithStates_1(0, 23, 8); + case 60: + jjmatchedKind = 27; + return jjMoveStringLiteralDfa1_1(0x80000000L); + case 61: + return jjMoveStringLiteralDfa1_1(0x200000000L); + case 62: + jjmatchedKind = 25; + return jjMoveStringLiteralDfa1_1(0x20000000L); + case 63: + return jjStopAtPos(0, 48); + case 91: + return jjStopAtPos(0, 21); + case 93: + return jjStopAtPos(0, 22); + case 97: + return jjMoveStringLiteralDfa1_1(0x10000000000L); + case 100: + return jjMoveStringLiteralDfa1_1(0x4000000000000L); + case 101: + return jjMoveStringLiteralDfa1_1(0x80400000000L); + case 102: + return jjMoveStringLiteralDfa1_1(0x8000L); + case 103: + return jjMoveStringLiteralDfa1_1(0x44000000L); + case 105: + return jjMoveStringLiteralDfa1_1(0x100000000000L); + case 108: + return jjMoveStringLiteralDfa1_1(0x110000000L); + case 109: + return jjMoveStringLiteralDfa1_1(0x10000000000000L); + case 110: + return jjMoveStringLiteralDfa1_1(0x5000010000L); + case 111: + return jjMoveStringLiteralDfa1_1(0x40000000000L); + case 116: + return jjMoveStringLiteralDfa1_1(0x4000L); + case 124: + return jjMoveStringLiteralDfa1_1(0x20000000000L); + case 125: + return jjStopAtPos(0, 17); + default : + return jjMoveNfa_1(0, 0); + } +} +private final int jjMoveStringLiteralDfa1_1(long active0) +{ + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(0, active0); + return 1; + } + switch(curChar) + { + case 38: + if ((active0 & 0x8000000000L) != 0L) + return jjStopAtPos(1, 39); + break; + case 61: + if ((active0 & 0x20000000L) != 0L) + return jjStopAtPos(1, 29); + else if ((active0 & 0x80000000L) != 0L) + return jjStopAtPos(1, 31); + else if ((active0 & 0x200000000L) != 0L) + return jjStopAtPos(1, 33); + else if ((active0 & 0x800000000L) != 0L) + return jjStopAtPos(1, 35); + break; + case 97: + return jjMoveStringLiteralDfa2_1(active0, 0x8000L); + case 101: + if ((active0 & 0x40000000L) != 0L) + return jjStartNfaWithStates_1(1, 30, 6); + else if ((active0 & 0x100000000L) != 0L) + return jjStartNfaWithStates_1(1, 32, 6); + else if ((active0 & 0x1000000000L) != 0L) + return jjStartNfaWithStates_1(1, 36, 6); + break; + case 105: + return jjMoveStringLiteralDfa2_1(active0, 0x4000000000000L); + case 109: + return jjMoveStringLiteralDfa2_1(active0, 0x80000000000L); + case 110: + return jjMoveStringLiteralDfa2_1(active0, 0x110000000000L); + case 111: + return jjMoveStringLiteralDfa2_1(active0, 0x10004000000000L); + case 113: + if ((active0 & 0x400000000L) != 0L) + return jjStartNfaWithStates_1(1, 34, 6); + break; + case 114: + if ((active0 & 0x40000000000L) != 0L) + return jjStartNfaWithStates_1(1, 42, 6); + return jjMoveStringLiteralDfa2_1(active0, 0x4000L); + case 116: + if ((active0 & 0x4000000L) != 0L) + return jjStartNfaWithStates_1(1, 26, 6); + else if ((active0 & 0x10000000L) != 0L) + return jjStartNfaWithStates_1(1, 28, 6); + break; + case 117: + return jjMoveStringLiteralDfa2_1(active0, 0x10000L); + case 124: + if ((active0 & 0x20000000000L) != 0L) + return jjStopAtPos(1, 41); + break; + default : + break; + } + return jjStartNfa_1(0, active0); +} +private final int jjMoveStringLiteralDfa2_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(0, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(1, active0); + return 2; + } + switch(curChar) + { + case 100: + if ((active0 & 0x10000000000L) != 0L) + return jjStartNfaWithStates_1(2, 40, 6); + else if ((active0 & 0x10000000000000L) != 0L) + return jjStartNfaWithStates_1(2, 52, 6); + break; + case 108: + return jjMoveStringLiteralDfa3_1(active0, 0x18000L); + case 112: + return jjMoveStringLiteralDfa3_1(active0, 0x80000000000L); + case 115: + return jjMoveStringLiteralDfa3_1(active0, 0x100000000000L); + case 116: + if ((active0 & 0x4000000000L) != 0L) + return jjStartNfaWithStates_1(2, 38, 6); + break; + case 117: + return jjMoveStringLiteralDfa3_1(active0, 0x4000L); + case 118: + if ((active0 & 0x4000000000000L) != 0L) + return jjStartNfaWithStates_1(2, 50, 6); + break; + default : + break; + } + return jjStartNfa_1(1, active0); +} +private final int jjMoveStringLiteralDfa3_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(1, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(2, active0); + return 3; + } + switch(curChar) + { + case 101: + if ((active0 & 0x4000L) != 0L) + return jjStartNfaWithStates_1(3, 14, 6); + break; + case 108: + if ((active0 & 0x10000L) != 0L) + return jjStartNfaWithStates_1(3, 16, 6); + break; + case 115: + return jjMoveStringLiteralDfa4_1(active0, 0x8000L); + case 116: + return jjMoveStringLiteralDfa4_1(active0, 0x180000000000L); + default : + break; + } + return jjStartNfa_1(2, active0); +} +private final int jjMoveStringLiteralDfa4_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(2, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(3, active0); + return 4; + } + switch(curChar) + { + case 97: + return jjMoveStringLiteralDfa5_1(active0, 0x100000000000L); + case 101: + if ((active0 & 0x8000L) != 0L) + return jjStartNfaWithStates_1(4, 15, 6); + break; + case 121: + if ((active0 & 0x80000000000L) != 0L) + return jjStartNfaWithStates_1(4, 43, 6); + break; + default : + break; + } + return jjStartNfa_1(3, active0); +} +private final int jjMoveStringLiteralDfa5_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(3, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(4, active0); + return 5; + } + switch(curChar) + { + case 110: + return jjMoveStringLiteralDfa6_1(active0, 0x100000000000L); + default : + break; + } + return jjStartNfa_1(4, active0); +} +private final int jjMoveStringLiteralDfa6_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(4, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(5, active0); + return 6; + } + switch(curChar) + { + case 99: + return jjMoveStringLiteralDfa7_1(active0, 0x100000000000L); + default : + break; + } + return jjStartNfa_1(5, active0); +} +private final int jjMoveStringLiteralDfa7_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(5, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(6, active0); + return 7; + } + switch(curChar) + { + case 101: + return jjMoveStringLiteralDfa8_1(active0, 0x100000000000L); + default : + break; + } + return jjStartNfa_1(6, active0); +} +private final int jjMoveStringLiteralDfa8_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(6, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(7, active0); + return 8; + } + switch(curChar) + { + case 111: + return jjMoveStringLiteralDfa9_1(active0, 0x100000000000L); + default : + break; + } + return jjStartNfa_1(7, active0); +} +private final int jjMoveStringLiteralDfa9_1(long old0, long active0) +{ + if (((active0 &= old0)) == 0L) + return jjStartNfa_1(7, old0); + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { + jjStopStringLiteralDfa_1(8, active0); + return 9; + } + switch(curChar) + { + case 102: + if ((active0 & 0x100000000000L) != 0L) + return jjStartNfaWithStates_1(9, 44, 6); + break; + default : + break; + } + return jjStartNfa_1(8, active0); +} +static final long[] jjbitVec3 = { + 0x1ff00000fffffffeL, 0xffffffffffffc000L, 0xffffffffL, 0x600000000000000L +}; +static final long[] jjbitVec4 = { + 0x0L, 0x0L, 0x0L, 0xff7fffffff7fffffL +}; +static final long[] jjbitVec5 = { + 0x0L, 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffffffffffffffL +}; +static final long[] jjbitVec6 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0xffffL, 0x0L +}; +static final long[] jjbitVec7 = { + 0xffffffffffffffffL, 0xffffffffffffffffL, 0x0L, 0x0L +}; +static final long[] jjbitVec8 = { + 0x3fffffffffffL, 0x0L, 0x0L, 0x0L +}; +private final int jjMoveNfa_1(int startState, int curPos) +{ + int[] nextStates; + int startsAt = 0; + jjnewStateCnt = 38; + int i = 1; + jjstateSet[0] = startState; + int j, kind = 0x7fffffff; + for (;;) + { + if (++jjround == 0x7fffffff) + ReInitRounds(); + if (curChar < 64) + { + long l = 1L << curChar; + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 0: + if ((0x3ff000000000000L & l) != 0L) + { + if (kind > 9) + kind = 9; + jjCheckNAddStates(4, 8); + } + else if ((0x1800000000L & l) != 0L) + { + if (kind > 53) + kind = 53; + jjCheckNAdd(6); + } + else if (curChar == 39) + jjCheckNAddStates(9, 13); + else if (curChar == 34) + jjCheckNAddStates(14, 18); + else if (curChar == 58) + jjstateSet[jjnewStateCnt++] = 8; + else if (curChar == 46) + jjCheckNAdd(1); + break; + case 1: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 10) + kind = 10; + jjCheckNAddTwoStates(1, 2); + break; + case 3: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(4); + break; + case 4: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 10) + kind = 10; + jjCheckNAdd(4); + break; + case 5: + if ((0x1800000000L & l) == 0L) + break; + if (kind > 53) + kind = 53; + jjCheckNAdd(6); + break; + case 6: + if ((0x3ff001000000000L & l) == 0L) + break; + if (kind > 53) + kind = 53; + jjCheckNAdd(6); + break; + case 7: + if (curChar == 58) + jjstateSet[jjnewStateCnt++] = 8; + break; + case 8: + if ((0x1800000000L & l) == 0L) + break; + if (kind > 54) + kind = 54; + jjCheckNAdd(9); + break; + case 9: + if ((0x3ff001000000000L & l) == 0L) + break; + if (kind > 54) + kind = 54; + jjCheckNAdd(9); + break; + case 10: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAddStates(4, 8); + break; + case 11: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 9) + kind = 9; + jjCheckNAdd(11); + break; + case 12: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(12, 13); + break; + case 13: + if (curChar != 46) + break; + if (kind > 10) + kind = 10; + jjCheckNAddTwoStates(14, 15); + break; + case 14: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 10) + kind = 10; + jjCheckNAddTwoStates(14, 15); + break; + case 16: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(17); + break; + case 17: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 10) + kind = 10; + jjCheckNAdd(17); + break; + case 18: + if ((0x3ff000000000000L & l) != 0L) + jjCheckNAddTwoStates(18, 19); + break; + case 20: + if ((0x280000000000L & l) != 0L) + jjCheckNAdd(21); + break; + case 21: + if ((0x3ff000000000000L & l) == 0L) + break; + if (kind > 10) + kind = 10; + jjCheckNAdd(21); + break; + case 22: + if (curChar == 34) + jjCheckNAddStates(14, 18); + break; + case 23: + if ((0xfffffffbffffffffL & l) != 0L) + jjCheckNAddStates(19, 21); + break; + case 25: + if (curChar == 34) + jjCheckNAddStates(19, 21); + break; + case 26: + if (curChar == 34 && kind > 12) + kind = 12; + break; + case 27: + if ((0xfffffffbffffffffL & l) != 0L) + jjCheckNAddTwoStates(27, 28); + break; + case 29: + if ((0xfffffffbffffffffL & l) != 0L && kind > 13) + kind = 13; + break; + case 30: + if (curChar == 39) + jjCheckNAddStates(9, 13); + break; + case 31: + if ((0xffffff7fffffffffL & l) != 0L) + jjCheckNAddStates(22, 24); + break; + case 33: + if (curChar == 39) + jjCheckNAddStates(22, 24); + break; + case 34: + if (curChar == 39 && kind > 12) + kind = 12; + break; + case 35: + if ((0xffffff7fffffffffL & l) != 0L) + jjCheckNAddTwoStates(35, 36); + break; + case 37: + if ((0xffffff7fffffffffL & l) != 0L && kind > 13) + kind = 13; + break; + default : break; + } + } while(i != startsAt); + } + else if (curChar < 128) + { + long l = 1L << (curChar & 077); + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 0: + case 6: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 53) + kind = 53; + jjCheckNAdd(6); + break; + case 2: + if ((0x2000000020L & l) != 0L) + jjAddStates(25, 26); + break; + case 8: + case 9: + if ((0x7fffffe87fffffeL & l) == 0L) + break; + if (kind > 54) + kind = 54; + jjCheckNAdd(9); + break; + case 15: + if ((0x2000000020L & l) != 0L) + jjAddStates(27, 28); + break; + case 19: + if ((0x2000000020L & l) != 0L) + jjAddStates(29, 30); + break; + case 23: + if ((0xffffffffefffffffL & l) != 0L) + jjCheckNAddStates(19, 21); + break; + case 24: + if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 25; + break; + case 25: + if (curChar == 92) + jjCheckNAddStates(19, 21); + break; + case 27: + if ((0xffffffffefffffffL & l) != 0L) + jjAddStates(31, 32); + break; + case 28: + if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 29; + break; + case 29: + case 37: + if ((0xffffffffefffffffL & l) != 0L && kind > 13) + kind = 13; + break; + case 31: + if ((0xffffffffefffffffL & l) != 0L) + jjCheckNAddStates(22, 24); + break; + case 32: + if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 33; + break; + case 33: + if (curChar == 92) + jjCheckNAddStates(22, 24); + break; + case 35: + if ((0xffffffffefffffffL & l) != 0L) + jjAddStates(33, 34); + break; + case 36: + if (curChar == 92) + jjstateSet[jjnewStateCnt++] = 37; + break; + default : break; + } + } while(i != startsAt); + } + else + { + int hiByte = (int)(curChar >> 8); + int i1 = hiByte >> 6; + long l1 = 1L << (hiByte & 077); + int i2 = (curChar & 0xff) >> 6; + long l2 = 1L << (curChar & 077); + MatchLoop: do + { + switch(jjstateSet[--i]) + { + case 0: + case 6: + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) + break; + if (kind > 53) + kind = 53; + jjCheckNAdd(6); + break; + case 8: + case 9: + if (!jjCanMove_1(hiByte, i1, i2, l1, l2)) + break; + if (kind > 54) + kind = 54; + jjCheckNAdd(9); + break; + case 23: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjAddStates(19, 21); + break; + case 27: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjAddStates(31, 32); + break; + case 29: + case 37: + if (jjCanMove_0(hiByte, i1, i2, l1, l2) && kind > 13) + kind = 13; + break; + case 31: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjAddStates(22, 24); + break; + case 35: + if (jjCanMove_0(hiByte, i1, i2, l1, l2)) + jjAddStates(33, 34); + break; + default : break; + } + } while(i != startsAt); + } + if (kind != 0x7fffffff) + { + jjmatchedKind = kind; + jjmatchedPos = curPos; + kind = 0x7fffffff; + } + ++curPos; + if ((i = jjnewStateCnt) == (startsAt = 38 - (jjnewStateCnt = startsAt))) + return curPos; + try { curChar = input_stream.readChar(); } + catch(java.io.IOException e) { return curPos; } + } +} +static final int[] jjnextStates = { + 0, 1, 3, 5, 11, 12, 13, 18, 19, 31, 32, 34, 35, 36, 23, 24, + 26, 27, 28, 23, 24, 26, 31, 32, 34, 3, 4, 16, 17, 20, 21, 27, + 28, 35, 36, +}; +private static final boolean jjCanMove_0(int hiByte, int i1, int i2, long l1, long l2) +{ + switch(hiByte) + { + case 0: + return ((jjbitVec2[i2] & l2) != 0L); + default : + if ((jjbitVec0[i1] & l1) != 0L) + return true; + return false; + } +} +private static final boolean jjCanMove_1(int hiByte, int i1, int i2, long l1, long l2) +{ + switch(hiByte) + { + case 0: + return ((jjbitVec4[i2] & l2) != 0L); + case 48: + return ((jjbitVec5[i2] & l2) != 0L); + case 49: + return ((jjbitVec6[i2] & l2) != 0L); + case 51: + return ((jjbitVec7[i2] & l2) != 0L); + case 61: + return ((jjbitVec8[i2] & l2) != 0L); + default : + if ((jjbitVec3[i1] & l1) != 0L) + return true; + return false; + } +} +public static final String[] jjstrLiteralImages = { +"", null, "\44\173", "\43\173", null, null, null, null, null, null, null, null, +null, null, "\164\162\165\145", "\146\141\154\163\145", "\156\165\154\154", "\175", +"\56", "\50", "\51", "\133", "\135", "\72", "\54", "\76", "\147\164", "\74", +"\154\164", "\76\75", "\147\145", "\74\75", "\154\145", "\75\75", "\145\161", "\41\75", +"\156\145", "\41", "\156\157\164", "\46\46", "\141\156\144", "\174\174", "\157\162", +"\145\155\160\164\171", "\151\156\163\164\141\156\143\145\157\146", "\52", "\53", "\55", "\77", "\57", +"\144\151\166", "\45", "\155\157\144", null, null, null, null, null, null, }; +public static final String[] lexStateNames = { + "DEFAULT", + "IN_EXPRESSION", +}; +public static final int[] jjnewLexState = { + -1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, +}; +static final long[] jjtoToken = { + 0x47ffffffffff60fL, +}; +static final long[] jjtoSkip = { + 0x1f0L, +}; +protected SimpleCharStream input_stream; +private final int[] jjrounds = new int[38]; +private final int[] jjstateSet = new int[76]; +protected char curChar; +public ELParserTokenManager(SimpleCharStream stream) +{ + if (SimpleCharStream.staticFlag) + throw new Error("ERROR: Cannot use a static CharStream class with a non-static lexical analyzer."); + input_stream = stream; +} +public ELParserTokenManager(SimpleCharStream stream, int lexState) +{ + this(stream); + SwitchTo(lexState); +} +public void ReInit(SimpleCharStream stream) +{ + jjmatchedPos = jjnewStateCnt = 0; + curLexState = defaultLexState; + input_stream = stream; + ReInitRounds(); +} +private final void ReInitRounds() +{ + int i; + jjround = 0x80000001; + for (i = 38; i-- > 0;) + jjrounds[i] = 0x80000000; +} +public void ReInit(SimpleCharStream stream, int lexState) +{ + ReInit(stream); + SwitchTo(lexState); +} +public void SwitchTo(int lexState) +{ + if (lexState >= 2 || lexState < 0) + throw new TokenMgrError("Error: Ignoring invalid lexical state : " + lexState + ". State unchanged.", TokenMgrError.INVALID_LEXICAL_STATE); + else + curLexState = lexState; +} + +protected Token jjFillToken() +{ + Token t = Token.newToken(jjmatchedKind); + t.kind = jjmatchedKind; + String im = jjstrLiteralImages[jjmatchedKind]; + t.image = (im == null) ? input_stream.GetImage() : im; + t.beginLine = input_stream.getBeginLine(); + t.beginColumn = input_stream.getBeginColumn(); + t.endLine = input_stream.getEndLine(); + t.endColumn = input_stream.getEndColumn(); + return t; +} + +int curLexState = 0; +int defaultLexState = 0; +int jjnewStateCnt; +int jjround; +int jjmatchedPos; +int jjmatchedKind; + +public Token getNextToken() +{ + int kind; + Token specialToken = null; + Token matchedToken; + int curPos = 0; + + EOFLoop : + for (;;) + { + try + { + curChar = input_stream.BeginToken(); + } + catch(java.io.IOException e) + { + jjmatchedKind = 0; + matchedToken = jjFillToken(); + return matchedToken; + } + + switch(curLexState) + { + case 0: + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_0(); + break; + case 1: + try { input_stream.backup(0); + while (curChar <= 32 && (0x100002600L & (1L << curChar)) != 0L) + curChar = input_stream.BeginToken(); + } + catch (java.io.IOException e1) { continue EOFLoop; } + jjmatchedKind = 0x7fffffff; + jjmatchedPos = 0; + curPos = jjMoveStringLiteralDfa0_1(); + if (jjmatchedPos == 0 && jjmatchedKind > 58) + { + jjmatchedKind = 58; + } + break; + } + if (jjmatchedKind != 0x7fffffff) + { + if (jjmatchedPos + 1 < curPos) + input_stream.backup(curPos - jjmatchedPos - 1); + if ((jjtoToken[jjmatchedKind >> 6] & (1L << (jjmatchedKind & 077))) != 0L) + { + matchedToken = jjFillToken(); + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + return matchedToken; + } + else + { + if (jjnewLexState[jjmatchedKind] != -1) + curLexState = jjnewLexState[jjmatchedKind]; + continue EOFLoop; + } + } + int error_line = input_stream.getEndLine(); + int error_column = input_stream.getEndColumn(); + String error_after = null; + boolean EOFSeen = false; + try { input_stream.readChar(); input_stream.backup(1); } + catch (java.io.IOException e1) { + EOFSeen = true; + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + if (curChar == '\n' || curChar == '\r') { + error_line++; + error_column = 0; + } + else + error_column++; + } + if (!EOFSeen) { + input_stream.backup(1); + error_after = curPos <= 1 ? "" : input_stream.GetImage(); + } + throw new TokenMgrError(EOFSeen, curLexState, error_line, error_column, error_after, curChar, TokenMgrError.LEXICAL_ERROR); + } +} + +} diff --git a/java/org/apache/el/parser/ELParserTreeConstants.java b/java/org/apache/el/parser/ELParserTreeConstants.java index 3207623a0..4c225fe4d 100644 --- a/java/org/apache/el/parser/ELParserTreeConstants.java +++ b/java/org/apache/el/parser/ELParserTreeConstants.java @@ -1,77 +1,77 @@ -/* Generated By:JJTree: Do not edit this line. /tomc/web.align/webtier-alignment/prototype/el-ri/src/com/sun/el/parser/ELParserTreeConstants.java */ - -package org.apache.el.parser; - -public interface ELParserTreeConstants -{ - public int JJTCOMPOSITEEXPRESSION = 0; - public int JJTLITERALEXPRESSION = 1; - public int JJTDEFERREDEXPRESSION = 2; - public int JJTDYNAMICEXPRESSION = 3; - public int JJTVOID = 4; - public int JJTCHOICE = 5; - public int JJTOR = 6; - public int JJTAND = 7; - public int JJTEQUAL = 8; - public int JJTNOTEQUAL = 9; - public int JJTLESSTHAN = 10; - public int JJTGREATERTHAN = 11; - public int JJTLESSTHANEQUAL = 12; - public int JJTGREATERTHANEQUAL = 13; - public int JJTPLUS = 14; - public int JJTMINUS = 15; - public int JJTMULT = 16; - public int JJTDIV = 17; - public int JJTMOD = 18; - public int JJTNEGATIVE = 19; - public int JJTNOT = 20; - public int JJTEMPTY = 21; - public int JJTVALUE = 22; - public int JJTDOTSUFFIX = 23; - public int JJTBRACKETSUFFIX = 24; - public int JJTIDENTIFIER = 25; - public int JJTFUNCTION = 26; - public int JJTTRUE = 27; - public int JJTFALSE = 28; - public int JJTFLOATINGPOINT = 29; - public int JJTINTEGER = 30; - public int JJTSTRING = 31; - public int JJTNULL = 32; - - - public String[] jjtNodeName = { - "CompositeExpression", - "LiteralExpression", - "DeferredExpression", - "DynamicExpression", - "void", - "Choice", - "Or", - "And", - "Equal", - "NotEqual", - "LessThan", - "GreaterThan", - "LessThanEqual", - "GreaterThanEqual", - "Plus", - "Minus", - "Mult", - "Div", - "Mod", - "Negative", - "Not", - "Empty", - "Value", - "DotSuffix", - "BracketSuffix", - "Identifier", - "Function", - "True", - "False", - "FloatingPoint", - "Integer", - "String", - "Null", - }; -} +/* Generated By:JJTree: Do not edit this line. /tomc/web.align/webtier-alignment/prototype/el-ri/src/com/sun/el/parser/ELParserTreeConstants.java */ + +package org.apache.el.parser; + +public interface ELParserTreeConstants +{ + public int JJTCOMPOSITEEXPRESSION = 0; + public int JJTLITERALEXPRESSION = 1; + public int JJTDEFERREDEXPRESSION = 2; + public int JJTDYNAMICEXPRESSION = 3; + public int JJTVOID = 4; + public int JJTCHOICE = 5; + public int JJTOR = 6; + public int JJTAND = 7; + public int JJTEQUAL = 8; + public int JJTNOTEQUAL = 9; + public int JJTLESSTHAN = 10; + public int JJTGREATERTHAN = 11; + public int JJTLESSTHANEQUAL = 12; + public int JJTGREATERTHANEQUAL = 13; + public int JJTPLUS = 14; + public int JJTMINUS = 15; + public int JJTMULT = 16; + public int JJTDIV = 17; + public int JJTMOD = 18; + public int JJTNEGATIVE = 19; + public int JJTNOT = 20; + public int JJTEMPTY = 21; + public int JJTVALUE = 22; + public int JJTDOTSUFFIX = 23; + public int JJTBRACKETSUFFIX = 24; + public int JJTIDENTIFIER = 25; + public int JJTFUNCTION = 26; + public int JJTTRUE = 27; + public int JJTFALSE = 28; + public int JJTFLOATINGPOINT = 29; + public int JJTINTEGER = 30; + public int JJTSTRING = 31; + public int JJTNULL = 32; + + + public String[] jjtNodeName = { + "CompositeExpression", + "LiteralExpression", + "DeferredExpression", + "DynamicExpression", + "void", + "Choice", + "Or", + "And", + "Equal", + "NotEqual", + "LessThan", + "GreaterThan", + "LessThanEqual", + "GreaterThanEqual", + "Plus", + "Minus", + "Mult", + "Div", + "Mod", + "Negative", + "Not", + "Empty", + "Value", + "DotSuffix", + "BracketSuffix", + "Identifier", + "Function", + "True", + "False", + "FloatingPoint", + "Integer", + "String", + "Null", + }; +} diff --git a/java/org/apache/el/parser/JJTELParserState.java b/java/org/apache/el/parser/JJTELParserState.java index 116f776eb..0780c6e11 100644 --- a/java/org/apache/el/parser/JJTELParserState.java +++ b/java/org/apache/el/parser/JJTELParserState.java @@ -1,123 +1,123 @@ -/* Generated By:JJTree: Do not edit this line. /tomc/web.align/webtier-alignment/prototype/el-ri/src/com/sun/el/parser/JJTELParserState.java */ - -package org.apache.el.parser; - -class JJTELParserState { - private java.util.Stack nodes; - private java.util.Stack marks; - - private int sp; // number of nodes on stack - private int mk; // current mark - private boolean node_created; - - JJTELParserState() { - nodes = new java.util.Stack(); - marks = new java.util.Stack(); - sp = 0; - mk = 0; - } - - /* Determines whether the current node was actually closed and - pushed. This should only be called in the final user action of a - node scope. */ - boolean nodeCreated() { - return node_created; - } - - /* Call this to reinitialize the node stack. It is called - automatically by the parser's ReInit() method. */ - void reset() { - nodes.removeAllElements(); - marks.removeAllElements(); - sp = 0; - mk = 0; - } - - /* Returns the root node of the AST. It only makes sense to call - this after a successful parse. */ - Node rootNode() { - return (Node)nodes.elementAt(0); - } - - /* Pushes a node on to the stack. */ - void pushNode(Node n) { - nodes.push(n); - ++sp; - } - - /* Returns the node on the top of the stack, and remove it from the - stack. */ - Node popNode() { - if (--sp < mk) { - mk = ((Integer)marks.pop()).intValue(); - } - return (Node)nodes.pop(); - } - - /* Returns the node currently on the top of the stack. */ - Node peekNode() { - return (Node)nodes.peek(); - } - - /* Returns the number of children on the stack in the current node - scope. */ - int nodeArity() { - return sp - mk; - } - - - void clearNodeScope(Node n) { - while (sp > mk) { - popNode(); - } - mk = ((Integer)marks.pop()).intValue(); - } - - - void openNodeScope(Node n) { - marks.push(new Integer(mk)); - mk = sp; - n.jjtOpen(); - } - - - /* A definite node is constructed from a specified number of - children. That number of nodes are popped from the stack and - made the children of the definite node. Then the definite node - is pushed on to the stack. */ - void closeNodeScope(Node n, int num) { - mk = ((Integer)marks.pop()).intValue(); - while (num-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, num); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } - - - /* A conditional node is constructed if its condition is true. All - the nodes that have been pushed since the node was opened are - made children of the the conditional node, which is then pushed - on to the stack. If the condition is false the node is not - constructed and they are left on the stack. */ - void closeNodeScope(Node n, boolean condition) { - if (condition) { - int a = nodeArity(); - mk = ((Integer)marks.pop()).intValue(); - while (a-- > 0) { - Node c = popNode(); - c.jjtSetParent(n); - n.jjtAddChild(c, a); - } - n.jjtClose(); - pushNode(n); - node_created = true; - } else { - mk = ((Integer)marks.pop()).intValue(); - node_created = false; - } - } -} +/* Generated By:JJTree: Do not edit this line. /tomc/web.align/webtier-alignment/prototype/el-ri/src/com/sun/el/parser/JJTELParserState.java */ + +package org.apache.el.parser; + +class JJTELParserState { + private java.util.Stack nodes; + private java.util.Stack marks; + + private int sp; // number of nodes on stack + private int mk; // current mark + private boolean node_created; + + JJTELParserState() { + nodes = new java.util.Stack(); + marks = new java.util.Stack(); + sp = 0; + mk = 0; + } + + /* Determines whether the current node was actually closed and + pushed. This should only be called in the final user action of a + node scope. */ + boolean nodeCreated() { + return node_created; + } + + /* Call this to reinitialize the node stack. It is called + automatically by the parser's ReInit() method. */ + void reset() { + nodes.removeAllElements(); + marks.removeAllElements(); + sp = 0; + mk = 0; + } + + /* Returns the root node of the AST. It only makes sense to call + this after a successful parse. */ + Node rootNode() { + return (Node)nodes.elementAt(0); + } + + /* Pushes a node on to the stack. */ + void pushNode(Node n) { + nodes.push(n); + ++sp; + } + + /* Returns the node on the top of the stack, and remove it from the + stack. */ + Node popNode() { + if (--sp < mk) { + mk = ((Integer)marks.pop()).intValue(); + } + return (Node)nodes.pop(); + } + + /* Returns the node currently on the top of the stack. */ + Node peekNode() { + return (Node)nodes.peek(); + } + + /* Returns the number of children on the stack in the current node + scope. */ + int nodeArity() { + return sp - mk; + } + + + void clearNodeScope(Node n) { + while (sp > mk) { + popNode(); + } + mk = ((Integer)marks.pop()).intValue(); + } + + + void openNodeScope(Node n) { + marks.push(new Integer(mk)); + mk = sp; + n.jjtOpen(); + } + + + /* A definite node is constructed from a specified number of + children. That number of nodes are popped from the stack and + made the children of the definite node. Then the definite node + is pushed on to the stack. */ + void closeNodeScope(Node n, int num) { + mk = ((Integer)marks.pop()).intValue(); + while (num-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, num); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } + + + /* A conditional node is constructed if its condition is true. All + the nodes that have been pushed since the node was opened are + made children of the the conditional node, which is then pushed + on to the stack. If the condition is false the node is not + constructed and they are left on the stack. */ + void closeNodeScope(Node n, boolean condition) { + if (condition) { + int a = nodeArity(); + mk = ((Integer)marks.pop()).intValue(); + while (a-- > 0) { + Node c = popNode(); + c.jjtSetParent(n); + n.jjtAddChild(c, a); + } + n.jjtClose(); + pushNode(n); + node_created = true; + } else { + mk = ((Integer)marks.pop()).intValue(); + node_created = false; + } + } +} diff --git a/java/org/apache/el/parser/Node.java b/java/org/apache/el/parser/Node.java index bd8b479a5..008d6880e 100644 --- a/java/org/apache/el/parser/Node.java +++ b/java/org/apache/el/parser/Node.java @@ -1,70 +1,70 @@ -/* Generated By:JJTree: Do not edit this line. Node.java */ - -/* - * Copyright 2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.el.parser; - -import javax.el.ELException; -import javax.el.MethodInfo; - -import org.apache.el.lang.EvaluationContext; - - -/* All AST nodes must implement this interface. It provides basic - machinery for constructing the parent and child relationships - between nodes. */ - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public interface Node { - - /** This method is called after the node has been made the current - node. It indicates that child nodes can now be added to it. */ - public void jjtOpen(); - - /** This method is called after all the child nodes have been - added. */ - public void jjtClose(); - - /** This pair of methods are used to inform the node of its - parent. */ - public void jjtSetParent(Node n); - public Node jjtGetParent(); - - /** This method tells the node to add its argument to the node's - list of children. */ - public void jjtAddChild(Node n, int i); - - /** This method returns a child node. The children are numbered - from zero, left to right. */ - public Node jjtGetChild(int i); - - /** Return the number of children the node has. */ - public int jjtGetNumChildren(); - - public String getImage(); - - public Object getValue(EvaluationContext ctx) throws ELException; - public void setValue(EvaluationContext ctx, Object value) throws ELException; - public Class getType(EvaluationContext ctx) throws ELException; - public boolean isReadOnly(EvaluationContext ctx) throws ELException; - public void accept(NodeVisitor visitor) throws Exception; - public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException; - public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException; -} +/* Generated By:JJTree: Do not edit this line. Node.java */ + +/* + * Copyright 2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.el.parser; + +import javax.el.ELException; +import javax.el.MethodInfo; + +import org.apache.el.lang.EvaluationContext; + + +/* All AST nodes must implement this interface. It provides basic + machinery for constructing the parent and child relationships + between nodes. */ + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public interface Node { + + /** This method is called after the node has been made the current + node. It indicates that child nodes can now be added to it. */ + public void jjtOpen(); + + /** This method is called after all the child nodes have been + added. */ + public void jjtClose(); + + /** This pair of methods are used to inform the node of its + parent. */ + public void jjtSetParent(Node n); + public Node jjtGetParent(); + + /** This method tells the node to add its argument to the node's + list of children. */ + public void jjtAddChild(Node n, int i); + + /** This method returns a child node. The children are numbered + from zero, left to right. */ + public Node jjtGetChild(int i); + + /** Return the number of children the node has. */ + public int jjtGetNumChildren(); + + public String getImage(); + + public Object getValue(EvaluationContext ctx) throws ELException; + public void setValue(EvaluationContext ctx, Object value) throws ELException; + public Class getType(EvaluationContext ctx) throws ELException; + public boolean isReadOnly(EvaluationContext ctx) throws ELException; + public void accept(NodeVisitor visitor) throws Exception; + public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException; + public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException; +} diff --git a/java/org/apache/el/parser/NodeVisitor.java b/java/org/apache/el/parser/NodeVisitor.java index ff54a9ab1..5ce72ee76 100644 --- a/java/org/apache/el/parser/NodeVisitor.java +++ b/java/org/apache/el/parser/NodeVisitor.java @@ -1,24 +1,24 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.el.parser; - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public interface NodeVisitor { - public void visit(Node node) throws Exception; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.el.parser; + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public interface NodeVisitor { + public void visit(Node node) throws Exception; +} diff --git a/java/org/apache/el/parser/ParseException.java b/java/org/apache/el/parser/ParseException.java index 9afa7ccdf..8556af908 100644 --- a/java/org/apache/el/parser/ParseException.java +++ b/java/org/apache/el/parser/ParseException.java @@ -1,192 +1,192 @@ -/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ -package org.apache.el.parser; - -/** - * This exception is thrown when parse errors are encountered. - * You can explicitly create objects of this exception type by - * calling the method generateParseException in the generated - * parser. - * - * You can modify this class to customize your error reporting - * mechanisms so long as you retain the public fields. - */ -public class ParseException extends Exception { - - /** - * This constructor is used by the method "generateParseException" - * in the generated parser. Calling this constructor generates - * a new object of this type with the fields "currentToken", - * "expectedTokenSequences", and "tokenImage" set. The boolean - * flag "specialConstructor" is also set to true to indicate that - * this constructor was used to create this object. - * This constructor calls its super class with the empty string - * to force the "toString" method of parent class "Throwable" to - * print the error message in the form: - * ParseException: - */ - public ParseException(Token currentTokenVal, - int[][] expectedTokenSequencesVal, - String[] tokenImageVal - ) - { - super(""); - specialConstructor = true; - currentToken = currentTokenVal; - expectedTokenSequences = expectedTokenSequencesVal; - tokenImage = tokenImageVal; - } - - /** - * The following constructors are for use by you for whatever - * purpose you can think of. Constructing the exception in this - * manner makes the exception behave in the normal way - i.e., as - * documented in the class "Throwable". The fields "errorToken", - * "expectedTokenSequences", and "tokenImage" do not contain - * relevant information. The JavaCC generated code does not use - * these constructors. - */ - - public ParseException() { - super(); - specialConstructor = false; - } - - public ParseException(String message) { - super(message); - specialConstructor = false; - } - - /** - * This variable determines which constructor was used to create - * this object and thereby affects the semantics of the - * "getMessage" method (see below). - */ - protected boolean specialConstructor; - - /** - * This is the last token that has been consumed successfully. If - * this object has been created due to a parse error, the token - * followng this token will (therefore) be the first error token. - */ - public Token currentToken; - - /** - * Each entry in this array is an array of integers. Each array - * of integers represents a sequence of tokens (by their ordinal - * values) that is expected at this point of the parse. - */ - public int[][] expectedTokenSequences; - - /** - * This is a reference to the "tokenImage" array of the generated - * parser within which the parse error occurred. This array is - * defined in the generated ...Constants interface. - */ - public String[] tokenImage; - - /** - * This method has the standard behavior when this object has been - * created using the standard constructors. Otherwise, it uses - * "currentToken" and "expectedTokenSequences" to generate a parse - * error message and returns it. If this object has been created - * due to a parse error, and you do not catch it (it gets thrown - * from the parser), then this method is called during the printing - * of the final stack trace, and hence the correct error message - * gets displayed. - */ - public String getMessage() { - if (!specialConstructor) { - return super.getMessage(); - } - String expected = ""; - int maxSize = 0; - for (int i = 0; i < expectedTokenSequences.length; i++) { - if (maxSize < expectedTokenSequences[i].length) { - maxSize = expectedTokenSequences[i].length; - } - for (int j = 0; j < expectedTokenSequences[i].length; j++) { - expected += tokenImage[expectedTokenSequences[i][j]] + " "; - } - if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { - expected += "..."; - } - expected += eol + " "; - } - String retval = "Encountered \""; - Token tok = currentToken.next; - for (int i = 0; i < maxSize; i++) { - if (i != 0) retval += " "; - if (tok.kind == 0) { - retval += tokenImage[0]; - break; - } - retval += add_escapes(tok.image); - tok = tok.next; - } - retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; - retval += "." + eol; - if (expectedTokenSequences.length == 1) { - retval += "Was expecting:" + eol + " "; - } else { - retval += "Was expecting one of:" + eol + " "; - } - retval += expected; - return retval; - } - - /** - * The end of line string for this machine. - */ - protected String eol = System.getProperty("line.separator", "\n"); - - /** - * Used to convert raw characters to their escaped version - * when these raw version cannot be used as part of an ASCII - * string literal. - */ - protected String add_escapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - -} +/* Generated By:JavaCC: Do not edit this line. ParseException.java Version 3.0 */ +package org.apache.el.parser; + +/** + * This exception is thrown when parse errors are encountered. + * You can explicitly create objects of this exception type by + * calling the method generateParseException in the generated + * parser. + * + * You can modify this class to customize your error reporting + * mechanisms so long as you retain the public fields. + */ +public class ParseException extends Exception { + + /** + * This constructor is used by the method "generateParseException" + * in the generated parser. Calling this constructor generates + * a new object of this type with the fields "currentToken", + * "expectedTokenSequences", and "tokenImage" set. The boolean + * flag "specialConstructor" is also set to true to indicate that + * this constructor was used to create this object. + * This constructor calls its super class with the empty string + * to force the "toString" method of parent class "Throwable" to + * print the error message in the form: + * ParseException: + */ + public ParseException(Token currentTokenVal, + int[][] expectedTokenSequencesVal, + String[] tokenImageVal + ) + { + super(""); + specialConstructor = true; + currentToken = currentTokenVal; + expectedTokenSequences = expectedTokenSequencesVal; + tokenImage = tokenImageVal; + } + + /** + * The following constructors are for use by you for whatever + * purpose you can think of. Constructing the exception in this + * manner makes the exception behave in the normal way - i.e., as + * documented in the class "Throwable". The fields "errorToken", + * "expectedTokenSequences", and "tokenImage" do not contain + * relevant information. The JavaCC generated code does not use + * these constructors. + */ + + public ParseException() { + super(); + specialConstructor = false; + } + + public ParseException(String message) { + super(message); + specialConstructor = false; + } + + /** + * This variable determines which constructor was used to create + * this object and thereby affects the semantics of the + * "getMessage" method (see below). + */ + protected boolean specialConstructor; + + /** + * This is the last token that has been consumed successfully. If + * this object has been created due to a parse error, the token + * followng this token will (therefore) be the first error token. + */ + public Token currentToken; + + /** + * Each entry in this array is an array of integers. Each array + * of integers represents a sequence of tokens (by their ordinal + * values) that is expected at this point of the parse. + */ + public int[][] expectedTokenSequences; + + /** + * This is a reference to the "tokenImage" array of the generated + * parser within which the parse error occurred. This array is + * defined in the generated ...Constants interface. + */ + public String[] tokenImage; + + /** + * This method has the standard behavior when this object has been + * created using the standard constructors. Otherwise, it uses + * "currentToken" and "expectedTokenSequences" to generate a parse + * error message and returns it. If this object has been created + * due to a parse error, and you do not catch it (it gets thrown + * from the parser), then this method is called during the printing + * of the final stack trace, and hence the correct error message + * gets displayed. + */ + public String getMessage() { + if (!specialConstructor) { + return super.getMessage(); + } + String expected = ""; + int maxSize = 0; + for (int i = 0; i < expectedTokenSequences.length; i++) { + if (maxSize < expectedTokenSequences[i].length) { + maxSize = expectedTokenSequences[i].length; + } + for (int j = 0; j < expectedTokenSequences[i].length; j++) { + expected += tokenImage[expectedTokenSequences[i][j]] + " "; + } + if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 0) { + expected += "..."; + } + expected += eol + " "; + } + String retval = "Encountered \""; + Token tok = currentToken.next; + for (int i = 0; i < maxSize; i++) { + if (i != 0) retval += " "; + if (tok.kind == 0) { + retval += tokenImage[0]; + break; + } + retval += add_escapes(tok.image); + tok = tok.next; + } + retval += "\" at line " + currentToken.next.beginLine + ", column " + currentToken.next.beginColumn; + retval += "." + eol; + if (expectedTokenSequences.length == 1) { + retval += "Was expecting:" + eol + " "; + } else { + retval += "Was expecting one of:" + eol + " "; + } + retval += expected; + return retval; + } + + /** + * The end of line string for this machine. + */ + protected String eol = System.getProperty("line.separator", "\n"); + + /** + * Used to convert raw characters to their escaped version + * when these raw version cannot be used as part of an ASCII + * string literal. + */ + protected String add_escapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) + { + case 0 : + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u" + s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + continue; + } + } + return retval.toString(); + } + +} diff --git a/java/org/apache/el/parser/SimpleCharStream.java b/java/org/apache/el/parser/SimpleCharStream.java index 4964d6da3..1122037b8 100644 --- a/java/org/apache/el/parser/SimpleCharStream.java +++ b/java/org/apache/el/parser/SimpleCharStream.java @@ -1,401 +1,401 @@ -/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 3.0 */ -package org.apache.el.parser; - -/** - * An implementation of interface CharStream, where the stream is assumed to - * contain only ASCII characters (without unicode processing). - */ - -public class SimpleCharStream -{ - public static final boolean staticFlag = false; - int bufsize; - int available; - int tokenBegin; - public int bufpos = -1; - protected int bufline[]; - protected int bufcolumn[]; - - protected int column = 0; - protected int line = 1; - - protected boolean prevCharIsCR = false; - protected boolean prevCharIsLF = false; - - protected java.io.Reader inputStream; - - protected char[] buffer; - protected int maxNextCharInd = 0; - protected int inBuf = 0; - - protected void ExpandBuff(boolean wrapAround) - { - char[] newbuffer = new char[bufsize + 2048]; - int newbufline[] = new int[bufsize + 2048]; - int newbufcolumn[] = new int[bufsize + 2048]; - - try - { - if (wrapAround) - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - System.arraycopy(buffer, 0, newbuffer, - bufsize - tokenBegin, bufpos); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos += (bufsize - tokenBegin)); - } - else - { - System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); - buffer = newbuffer; - - System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); - bufline = newbufline; - - System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); - bufcolumn = newbufcolumn; - - maxNextCharInd = (bufpos -= tokenBegin); - } - } - catch (Throwable t) - { - throw new Error(t.getMessage()); - } - - - bufsize += 2048; - available = bufsize; - tokenBegin = 0; - } - - protected void FillBuff() throws java.io.IOException - { - if (maxNextCharInd == available) - { - if (available == bufsize) - { - if (tokenBegin > 2048) - { - bufpos = maxNextCharInd = 0; - available = tokenBegin; - } - else if (tokenBegin < 0) - bufpos = maxNextCharInd = 0; - else - ExpandBuff(false); - } - else if (available > tokenBegin) - available = bufsize; - else if ((tokenBegin - available) < 2048) - ExpandBuff(true); - else - available = tokenBegin; - } - - int i; - try { - if ((i = inputStream.read(buffer, maxNextCharInd, - available - maxNextCharInd)) == -1) - { - inputStream.close(); - throw new java.io.IOException(); - } - else - maxNextCharInd += i; - return; - } - catch(java.io.IOException e) { - --bufpos; - backup(0); - if (tokenBegin == -1) - tokenBegin = bufpos; - throw e; - } - } - - public char BeginToken() throws java.io.IOException - { - tokenBegin = -1; - char c = readChar(); - tokenBegin = bufpos; - - return c; - } - - protected void UpdateLineColumn(char c) - { - column++; - - if (prevCharIsLF) - { - prevCharIsLF = false; - line += (column = 1); - } - else if (prevCharIsCR) - { - prevCharIsCR = false; - if (c == '\n') - { - prevCharIsLF = true; - } - else - line += (column = 1); - } - - switch (c) - { - case '\r' : - prevCharIsCR = true; - break; - case '\n' : - prevCharIsLF = true; - break; - case '\t' : - column--; - column += (8 - (column & 07)); - break; - default : - break; - } - - bufline[bufpos] = line; - bufcolumn[bufpos] = column; - } - - public char readChar() throws java.io.IOException - { - if (inBuf > 0) - { - --inBuf; - - if (++bufpos == bufsize) - bufpos = 0; - - return buffer[bufpos]; - } - - if (++bufpos >= maxNextCharInd) - FillBuff(); - - char c = buffer[bufpos]; - - UpdateLineColumn(c); - return (c); - } - - /** - * @deprecated - * @see #getEndColumn - */ - - public int getColumn() { - return bufcolumn[bufpos]; - } - - /** - * @deprecated - * @see #getEndLine - */ - - public int getLine() { - return bufline[bufpos]; - } - - public int getEndColumn() { - return bufcolumn[bufpos]; - } - - public int getEndLine() { - return bufline[bufpos]; - } - - public int getBeginColumn() { - return bufcolumn[tokenBegin]; - } - - public int getBeginLine() { - return bufline[tokenBegin]; - } - - public void backup(int amount) { - - inBuf += amount; - if ((bufpos -= amount) < 0) - bufpos += bufsize; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - - public SimpleCharStream(java.io.Reader dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.Reader dstream) - { - this(dstream, 1, 1, 4096); - } - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn, int buffersize) - { - inputStream = dstream; - line = startline; - column = startcolumn - 1; - - if (buffer == null || buffersize != buffer.length) - { - available = bufsize = buffersize; - buffer = new char[buffersize]; - bufline = new int[buffersize]; - bufcolumn = new int[buffersize]; - } - prevCharIsLF = prevCharIsCR = false; - tokenBegin = inBuf = maxNextCharInd = 0; - bufpos = -1; - } - - public void ReInit(java.io.Reader dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - - public void ReInit(java.io.Reader dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream, int startline, - int startcolumn) - { - this(dstream, startline, startcolumn, 4096); - } - - public SimpleCharStream(java.io.InputStream dstream) - { - this(dstream, 1, 1, 4096); - } - - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn, int buffersize) - { - ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); - } - - public void ReInit(java.io.InputStream dstream) - { - ReInit(dstream, 1, 1, 4096); - } - public void ReInit(java.io.InputStream dstream, int startline, - int startcolumn) - { - ReInit(dstream, startline, startcolumn, 4096); - } - public String GetImage() - { - if (bufpos >= tokenBegin) - return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); - else - return new String(buffer, tokenBegin, bufsize - tokenBegin) + - new String(buffer, 0, bufpos + 1); - } - - public char[] GetSuffix(int len) - { - char[] ret = new char[len]; - - if ((bufpos + 1) >= len) - System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); - else - { - System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, - len - bufpos - 1); - System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); - } - - return ret; - } - - public void Done() - { - buffer = null; - bufline = null; - bufcolumn = null; - } - - /** - * Method to adjust line and column numbers for the start of a token. - */ - public void adjustBeginLineColumn(int newLine, int newCol) - { - int start = tokenBegin; - int len; - - if (bufpos >= tokenBegin) - { - len = bufpos - tokenBegin + inBuf + 1; - } - else - { - len = bufsize - tokenBegin + bufpos + 1 + inBuf; - } - - int i = 0, j = 0, k = 0; - int nextColDiff = 0, columnDiff = 0; - - while (i < len && - bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) - { - bufline[j] = newLine; - nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; - bufcolumn[j] = newCol + columnDiff; - columnDiff = nextColDiff; - i++; - } - - if (i < len) - { - bufline[j] = newLine++; - bufcolumn[j] = newCol + columnDiff; - - while (i++ < len) - { - if (bufline[j = start % bufsize] != bufline[++start % bufsize]) - bufline[j] = newLine++; - else - bufline[j] = newLine; - } - } - - line = bufline[j]; - column = bufcolumn[j]; - } - -} +/* Generated By:JavaCC: Do not edit this line. SimpleCharStream.java Version 3.0 */ +package org.apache.el.parser; + +/** + * An implementation of interface CharStream, where the stream is assumed to + * contain only ASCII characters (without unicode processing). + */ + +public class SimpleCharStream +{ + public static final boolean staticFlag = false; + int bufsize; + int available; + int tokenBegin; + public int bufpos = -1; + protected int bufline[]; + protected int bufcolumn[]; + + protected int column = 0; + protected int line = 1; + + protected boolean prevCharIsCR = false; + protected boolean prevCharIsLF = false; + + protected java.io.Reader inputStream; + + protected char[] buffer; + protected int maxNextCharInd = 0; + protected int inBuf = 0; + + protected void ExpandBuff(boolean wrapAround) + { + char[] newbuffer = new char[bufsize + 2048]; + int newbufline[] = new int[bufsize + 2048]; + int newbufcolumn[] = new int[bufsize + 2048]; + + try + { + if (wrapAround) + { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + System.arraycopy(buffer, 0, newbuffer, + bufsize - tokenBegin, bufpos); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + System.arraycopy(bufline, 0, newbufline, bufsize - tokenBegin, bufpos); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + System.arraycopy(bufcolumn, 0, newbufcolumn, bufsize - tokenBegin, bufpos); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos += (bufsize - tokenBegin)); + } + else + { + System.arraycopy(buffer, tokenBegin, newbuffer, 0, bufsize - tokenBegin); + buffer = newbuffer; + + System.arraycopy(bufline, tokenBegin, newbufline, 0, bufsize - tokenBegin); + bufline = newbufline; + + System.arraycopy(bufcolumn, tokenBegin, newbufcolumn, 0, bufsize - tokenBegin); + bufcolumn = newbufcolumn; + + maxNextCharInd = (bufpos -= tokenBegin); + } + } + catch (Throwable t) + { + throw new Error(t.getMessage()); + } + + + bufsize += 2048; + available = bufsize; + tokenBegin = 0; + } + + protected void FillBuff() throws java.io.IOException + { + if (maxNextCharInd == available) + { + if (available == bufsize) + { + if (tokenBegin > 2048) + { + bufpos = maxNextCharInd = 0; + available = tokenBegin; + } + else if (tokenBegin < 0) + bufpos = maxNextCharInd = 0; + else + ExpandBuff(false); + } + else if (available > tokenBegin) + available = bufsize; + else if ((tokenBegin - available) < 2048) + ExpandBuff(true); + else + available = tokenBegin; + } + + int i; + try { + if ((i = inputStream.read(buffer, maxNextCharInd, + available - maxNextCharInd)) == -1) + { + inputStream.close(); + throw new java.io.IOException(); + } + else + maxNextCharInd += i; + return; + } + catch(java.io.IOException e) { + --bufpos; + backup(0); + if (tokenBegin == -1) + tokenBegin = bufpos; + throw e; + } + } + + public char BeginToken() throws java.io.IOException + { + tokenBegin = -1; + char c = readChar(); + tokenBegin = bufpos; + + return c; + } + + protected void UpdateLineColumn(char c) + { + column++; + + if (prevCharIsLF) + { + prevCharIsLF = false; + line += (column = 1); + } + else if (prevCharIsCR) + { + prevCharIsCR = false; + if (c == '\n') + { + prevCharIsLF = true; + } + else + line += (column = 1); + } + + switch (c) + { + case '\r' : + prevCharIsCR = true; + break; + case '\n' : + prevCharIsLF = true; + break; + case '\t' : + column--; + column += (8 - (column & 07)); + break; + default : + break; + } + + bufline[bufpos] = line; + bufcolumn[bufpos] = column; + } + + public char readChar() throws java.io.IOException + { + if (inBuf > 0) + { + --inBuf; + + if (++bufpos == bufsize) + bufpos = 0; + + return buffer[bufpos]; + } + + if (++bufpos >= maxNextCharInd) + FillBuff(); + + char c = buffer[bufpos]; + + UpdateLineColumn(c); + return (c); + } + + /** + * @deprecated + * @see #getEndColumn + */ + + public int getColumn() { + return bufcolumn[bufpos]; + } + + /** + * @deprecated + * @see #getEndLine + */ + + public int getLine() { + return bufline[bufpos]; + } + + public int getEndColumn() { + return bufcolumn[bufpos]; + } + + public int getEndLine() { + return bufline[bufpos]; + } + + public int getBeginColumn() { + return bufcolumn[tokenBegin]; + } + + public int getBeginLine() { + return bufline[tokenBegin]; + } + + public void backup(int amount) { + + inBuf += amount; + if ((bufpos -= amount) < 0) + bufpos += bufsize; + } + + public SimpleCharStream(java.io.Reader dstream, int startline, + int startcolumn, int buffersize) + { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + + public SimpleCharStream(java.io.Reader dstream, int startline, + int startcolumn) + { + this(dstream, startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.Reader dstream) + { + this(dstream, 1, 1, 4096); + } + public void ReInit(java.io.Reader dstream, int startline, + int startcolumn, int buffersize) + { + inputStream = dstream; + line = startline; + column = startcolumn - 1; + + if (buffer == null || buffersize != buffer.length) + { + available = bufsize = buffersize; + buffer = new char[buffersize]; + bufline = new int[buffersize]; + bufcolumn = new int[buffersize]; + } + prevCharIsLF = prevCharIsCR = false; + tokenBegin = inBuf = maxNextCharInd = 0; + bufpos = -1; + } + + public void ReInit(java.io.Reader dstream, int startline, + int startcolumn) + { + ReInit(dstream, startline, startcolumn, 4096); + } + + public void ReInit(java.io.Reader dstream) + { + ReInit(dstream, 1, 1, 4096); + } + public SimpleCharStream(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) + { + this(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream, int startline, + int startcolumn) + { + this(dstream, startline, startcolumn, 4096); + } + + public SimpleCharStream(java.io.InputStream dstream) + { + this(dstream, 1, 1, 4096); + } + + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn, int buffersize) + { + ReInit(new java.io.InputStreamReader(dstream), startline, startcolumn, 4096); + } + + public void ReInit(java.io.InputStream dstream) + { + ReInit(dstream, 1, 1, 4096); + } + public void ReInit(java.io.InputStream dstream, int startline, + int startcolumn) + { + ReInit(dstream, startline, startcolumn, 4096); + } + public String GetImage() + { + if (bufpos >= tokenBegin) + return new String(buffer, tokenBegin, bufpos - tokenBegin + 1); + else + return new String(buffer, tokenBegin, bufsize - tokenBegin) + + new String(buffer, 0, bufpos + 1); + } + + public char[] GetSuffix(int len) + { + char[] ret = new char[len]; + + if ((bufpos + 1) >= len) + System.arraycopy(buffer, bufpos - len + 1, ret, 0, len); + else + { + System.arraycopy(buffer, bufsize - (len - bufpos - 1), ret, 0, + len - bufpos - 1); + System.arraycopy(buffer, 0, ret, len - bufpos - 1, bufpos + 1); + } + + return ret; + } + + public void Done() + { + buffer = null; + bufline = null; + bufcolumn = null; + } + + /** + * Method to adjust line and column numbers for the start of a token. + */ + public void adjustBeginLineColumn(int newLine, int newCol) + { + int start = tokenBegin; + int len; + + if (bufpos >= tokenBegin) + { + len = bufpos - tokenBegin + inBuf + 1; + } + else + { + len = bufsize - tokenBegin + bufpos + 1 + inBuf; + } + + int i = 0, j = 0, k = 0; + int nextColDiff = 0, columnDiff = 0; + + while (i < len && + bufline[j = start % bufsize] == bufline[k = ++start % bufsize]) + { + bufline[j] = newLine; + nextColDiff = columnDiff + bufcolumn[k] - bufcolumn[j]; + bufcolumn[j] = newCol + columnDiff; + columnDiff = nextColDiff; + i++; + } + + if (i < len) + { + bufline[j] = newLine++; + bufcolumn[j] = newCol + columnDiff; + + while (i++ < len) + { + if (bufline[j = start % bufsize] != bufline[++start % bufsize]) + bufline[j] = newLine++; + else + bufline[j] = newLine; + } + } + + line = bufline[j]; + column = bufcolumn[j]; + } + +} diff --git a/java/org/apache/el/parser/SimpleNode.java b/java/org/apache/el/parser/SimpleNode.java index 270fef6a6..784bc1646 100644 --- a/java/org/apache/el/parser/SimpleNode.java +++ b/java/org/apache/el/parser/SimpleNode.java @@ -1,144 +1,144 @@ -/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ - -package org.apache.el.parser; - -import javax.el.ELException; -import javax.el.MethodInfo; -import javax.el.PropertyNotWritableException; - -import org.apache.el.lang.ELSupport; -import org.apache.el.lang.EvaluationContext; -import org.apache.el.util.MessageFactory; - - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public abstract class SimpleNode extends ELSupport implements Node { - protected Node parent; - - protected Node[] children; - - protected int id; - - protected String image; - - public SimpleNode(int i) { - id = i; - } - - public void jjtOpen() { - } - - public void jjtClose() { - } - - public void jjtSetParent(Node n) { - parent = n; - } - - public Node jjtGetParent() { - return parent; - } - - public void jjtAddChild(Node n, int i) { - if (children == null) { - children = new Node[i + 1]; - } else if (i >= children.length) { - Node c[] = new Node[i + 1]; - System.arraycopy(children, 0, c, 0, children.length); - children = c; - } - children[i] = n; - } - - public Node jjtGetChild(int i) { - return children[i]; - } - - public int jjtGetNumChildren() { - return (children == null) ? 0 : children.length; - } - - /* - * You can override these two methods in subclasses of SimpleNode to - * customize the way the node appears when the tree is dumped. If your - * output uses more than one line you should override toString(String), - * otherwise overriding toString() is probably all you need to do. - */ - - public String toString() { - if (this.image != null) { - return ELParserTreeConstants.jjtNodeName[id] + "[" + this.image - + "]"; - } - return ELParserTreeConstants.jjtNodeName[id]; - } - - public String toString(String prefix) { - return prefix + toString(); - } - - /* - * Override this method if you want to customize how the node dumps out its - * children. - */ - - public void dump(String prefix) { - System.out.println(toString(prefix)); - if (children != null) { - for (int i = 0; i < children.length; ++i) { - SimpleNode n = (SimpleNode) children[i]; - if (n != null) { - n.dump(prefix + " "); - } - } - } - } - - public String getImage() { - return image; - } - - public void setImage(String image) { - this.image = image; - } - - public Class getType(EvaluationContext ctx) - throws ELException { - throw new UnsupportedOperationException(); - } - - public Object getValue(EvaluationContext ctx) - throws ELException { - throw new UnsupportedOperationException(); - } - - public boolean isReadOnly(EvaluationContext ctx) - throws ELException { - return true; - } - - public void setValue(EvaluationContext ctx, Object value) - throws ELException { - throw new PropertyNotWritableException(MessageFactory.get("error.syntax.set")); - } - - public void accept(NodeVisitor visitor) throws Exception { - visitor.visit(this); - if (this.children != null && this.children.length > 0) { - for (int i = 0; i < this.children.length; i++) { - this.children[i].accept(visitor); - } - } - } - - public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException { - throw new UnsupportedOperationException(); - } - - public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException { - throw new UnsupportedOperationException(); - } -} +/* Generated By:JJTree: Do not edit this line. SimpleNode.java */ + +package org.apache.el.parser; + +import javax.el.ELException; +import javax.el.MethodInfo; +import javax.el.PropertyNotWritableException; + +import org.apache.el.lang.ELSupport; +import org.apache.el.lang.EvaluationContext; +import org.apache.el.util.MessageFactory; + + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public abstract class SimpleNode extends ELSupport implements Node { + protected Node parent; + + protected Node[] children; + + protected int id; + + protected String image; + + public SimpleNode(int i) { + id = i; + } + + public void jjtOpen() { + } + + public void jjtClose() { + } + + public void jjtSetParent(Node n) { + parent = n; + } + + public Node jjtGetParent() { + return parent; + } + + public void jjtAddChild(Node n, int i) { + if (children == null) { + children = new Node[i + 1]; + } else if (i >= children.length) { + Node c[] = new Node[i + 1]; + System.arraycopy(children, 0, c, 0, children.length); + children = c; + } + children[i] = n; + } + + public Node jjtGetChild(int i) { + return children[i]; + } + + public int jjtGetNumChildren() { + return (children == null) ? 0 : children.length; + } + + /* + * You can override these two methods in subclasses of SimpleNode to + * customize the way the node appears when the tree is dumped. If your + * output uses more than one line you should override toString(String), + * otherwise overriding toString() is probably all you need to do. + */ + + public String toString() { + if (this.image != null) { + return ELParserTreeConstants.jjtNodeName[id] + "[" + this.image + + "]"; + } + return ELParserTreeConstants.jjtNodeName[id]; + } + + public String toString(String prefix) { + return prefix + toString(); + } + + /* + * Override this method if you want to customize how the node dumps out its + * children. + */ + + public void dump(String prefix) { + System.out.println(toString(prefix)); + if (children != null) { + for (int i = 0; i < children.length; ++i) { + SimpleNode n = (SimpleNode) children[i]; + if (n != null) { + n.dump(prefix + " "); + } + } + } + } + + public String getImage() { + return image; + } + + public void setImage(String image) { + this.image = image; + } + + public Class getType(EvaluationContext ctx) + throws ELException { + throw new UnsupportedOperationException(); + } + + public Object getValue(EvaluationContext ctx) + throws ELException { + throw new UnsupportedOperationException(); + } + + public boolean isReadOnly(EvaluationContext ctx) + throws ELException { + return true; + } + + public void setValue(EvaluationContext ctx, Object value) + throws ELException { + throw new PropertyNotWritableException(MessageFactory.get("error.syntax.set")); + } + + public void accept(NodeVisitor visitor) throws Exception { + visitor.visit(this); + if (this.children != null && this.children.length > 0) { + for (int i = 0; i < this.children.length; i++) { + this.children[i].accept(visitor); + } + } + } + + public Object invoke(EvaluationContext ctx, Class[] paramTypes, Object[] paramValues) throws ELException { + throw new UnsupportedOperationException(); + } + + public MethodInfo getMethodInfo(EvaluationContext ctx, Class[] paramTypes) throws ELException { + throw new UnsupportedOperationException(); + } +} diff --git a/java/org/apache/el/parser/Token.java b/java/org/apache/el/parser/Token.java index 054743fc7..431f559aa 100644 --- a/java/org/apache/el/parser/Token.java +++ b/java/org/apache/el/parser/Token.java @@ -1,81 +1,81 @@ -/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ -package org.apache.el.parser; - -/** - * Describes the input token stream. - */ - -public class Token { - - /** - * An integer that describes the kind of this token. This numbering - * system is determined by JavaCCParser, and a table of these numbers is - * stored in the file ...Constants.java. - */ - public int kind; - - /** - * beginLine and beginColumn describe the position of the first character - * of this token; endLine and endColumn describe the position of the - * last character of this token. - */ - public int beginLine, beginColumn, endLine, endColumn; - - /** - * The string image of the token. - */ - public String image; - - /** - * A reference to the next regular (non-special) token from the input - * stream. If this is the last token from the input stream, or if the - * token manager has not read tokens beyond this one, this field is - * set to null. This is true only if this token is also a regular - * token. Otherwise, see below for a description of the contents of - * this field. - */ - public Token next; - - /** - * This field is used to access special tokens that occur prior to this - * token, but after the immediately preceding regular (non-special) token. - * If there are no such special tokens, this field is set to null. - * When there are more than one such special token, this field refers - * to the last of these special tokens, which in turn refers to the next - * previous special token through its specialToken field, and so on - * until the first special token (whose specialToken field is null). - * The next fields of special tokens refer to other special tokens that - * immediately follow it (without an intervening regular token). If there - * is no such token, this field is null. - */ - public Token specialToken; - - /** - * Returns the image. - */ - public String toString() - { - return image; - } - - /** - * Returns a new Token object, by default. However, if you want, you - * can create and return subclass objects based on the value of ofKind. - * Simply add the cases to the switch for all those special cases. - * For example, if you have a subclass of Token called IDToken that - * you want to create if ofKind is ID, simlpy add something like : - * - * case MyParserConstants.ID : return new IDToken(); - * - * to the following switch statement. Then you can cast matchedToken - * variable to the appropriate type and use it in your lexical actions. - */ - public static final Token newToken(int ofKind) - { - switch(ofKind) - { - default : return new Token(); - } - } - -} +/* Generated By:JavaCC: Do not edit this line. Token.java Version 3.0 */ +package org.apache.el.parser; + +/** + * Describes the input token stream. + */ + +public class Token { + + /** + * An integer that describes the kind of this token. This numbering + * system is determined by JavaCCParser, and a table of these numbers is + * stored in the file ...Constants.java. + */ + public int kind; + + /** + * beginLine and beginColumn describe the position of the first character + * of this token; endLine and endColumn describe the position of the + * last character of this token. + */ + public int beginLine, beginColumn, endLine, endColumn; + + /** + * The string image of the token. + */ + public String image; + + /** + * A reference to the next regular (non-special) token from the input + * stream. If this is the last token from the input stream, or if the + * token manager has not read tokens beyond this one, this field is + * set to null. This is true only if this token is also a regular + * token. Otherwise, see below for a description of the contents of + * this field. + */ + public Token next; + + /** + * This field is used to access special tokens that occur prior to this + * token, but after the immediately preceding regular (non-special) token. + * If there are no such special tokens, this field is set to null. + * When there are more than one such special token, this field refers + * to the last of these special tokens, which in turn refers to the next + * previous special token through its specialToken field, and so on + * until the first special token (whose specialToken field is null). + * The next fields of special tokens refer to other special tokens that + * immediately follow it (without an intervening regular token). If there + * is no such token, this field is null. + */ + public Token specialToken; + + /** + * Returns the image. + */ + public String toString() + { + return image; + } + + /** + * Returns a new Token object, by default. However, if you want, you + * can create and return subclass objects based on the value of ofKind. + * Simply add the cases to the switch for all those special cases. + * For example, if you have a subclass of Token called IDToken that + * you want to create if ofKind is ID, simlpy add something like : + * + * case MyParserConstants.ID : return new IDToken(); + * + * to the following switch statement. Then you can cast matchedToken + * variable to the appropriate type and use it in your lexical actions. + */ + public static final Token newToken(int ofKind) + { + switch(ofKind) + { + default : return new Token(); + } + } + +} diff --git a/java/org/apache/el/parser/TokenMgrError.java b/java/org/apache/el/parser/TokenMgrError.java index 36844f35f..8210a3c10 100644 --- a/java/org/apache/el/parser/TokenMgrError.java +++ b/java/org/apache/el/parser/TokenMgrError.java @@ -1,133 +1,133 @@ -/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ -package org.apache.el.parser; - -public class TokenMgrError extends Error -{ - /* - * Ordinals for various reasons why an Error of this type can be thrown. - */ - - /** - * Lexical error occured. - */ - static final int LEXICAL_ERROR = 0; - - /** - * An attempt wass made to create a second instance of a static token manager. - */ - static final int STATIC_LEXER_ERROR = 1; - - /** - * Tried to change to an invalid lexical state. - */ - static final int INVALID_LEXICAL_STATE = 2; - - /** - * Detected (and bailed out of) an infinite loop in the token manager. - */ - static final int LOOP_DETECTED = 3; - - /** - * Indicates the reason why the exception is thrown. It will have - * one of the above 4 values. - */ - int errorCode; - - /** - * Replaces unprintable characters by their espaced (or unicode escaped) - * equivalents in the given string - */ - protected static final String addEscapes(String str) { - StringBuffer retval = new StringBuffer(); - char ch; - for (int i = 0; i < str.length(); i++) { - switch (str.charAt(i)) - { - case 0 : - continue; - case '\b': - retval.append("\\b"); - continue; - case '\t': - retval.append("\\t"); - continue; - case '\n': - retval.append("\\n"); - continue; - case '\f': - retval.append("\\f"); - continue; - case '\r': - retval.append("\\r"); - continue; - case '\"': - retval.append("\\\""); - continue; - case '\'': - retval.append("\\\'"); - continue; - case '\\': - retval.append("\\\\"); - continue; - default: - if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { - String s = "0000" + Integer.toString(ch, 16); - retval.append("\\u" + s.substring(s.length() - 4, s.length())); - } else { - retval.append(ch); - } - continue; - } - } - return retval.toString(); - } - - /** - * Returns a detailed message for the Error when it is thrown by the - * token manager to indicate a lexical error. - * Parameters : - * EOFSeen : indicates if EOF caused the lexicl error - * curLexState : lexical state in which this error occured - * errorLine : line number when the error occured - * errorColumn : column number when the error occured - * errorAfter : prefix that was seen before this error occured - * curchar : the offending character - * Note: You can customize the lexical error message by modifying this method. - */ - protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { - return("Lexical error at line " + - errorLine + ", column " + - errorColumn + ". Encountered: " + - (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + - "after : \"" + addEscapes(errorAfter) + "\""); - } - - /** - * You can also modify the body of this method to customize your error messages. - * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not - * of end-users concern, so you can return something like : - * - * "Internal Error : Please file a bug report .... " - * - * from this method for such cases in the release version of your parser. - */ - public String getMessage() { - return super.getMessage(); - } - - /* - * Constructors of various flavors follow. - */ - - public TokenMgrError() { - } - - public TokenMgrError(String message, int reason) { - super(message); - errorCode = reason; - } - - public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { - this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); - } -} +/* Generated By:JavaCC: Do not edit this line. TokenMgrError.java Version 3.0 */ +package org.apache.el.parser; + +public class TokenMgrError extends Error +{ + /* + * Ordinals for various reasons why an Error of this type can be thrown. + */ + + /** + * Lexical error occured. + */ + static final int LEXICAL_ERROR = 0; + + /** + * An attempt wass made to create a second instance of a static token manager. + */ + static final int STATIC_LEXER_ERROR = 1; + + /** + * Tried to change to an invalid lexical state. + */ + static final int INVALID_LEXICAL_STATE = 2; + + /** + * Detected (and bailed out of) an infinite loop in the token manager. + */ + static final int LOOP_DETECTED = 3; + + /** + * Indicates the reason why the exception is thrown. It will have + * one of the above 4 values. + */ + int errorCode; + + /** + * Replaces unprintable characters by their espaced (or unicode escaped) + * equivalents in the given string + */ + protected static final String addEscapes(String str) { + StringBuffer retval = new StringBuffer(); + char ch; + for (int i = 0; i < str.length(); i++) { + switch (str.charAt(i)) + { + case 0 : + continue; + case '\b': + retval.append("\\b"); + continue; + case '\t': + retval.append("\\t"); + continue; + case '\n': + retval.append("\\n"); + continue; + case '\f': + retval.append("\\f"); + continue; + case '\r': + retval.append("\\r"); + continue; + case '\"': + retval.append("\\\""); + continue; + case '\'': + retval.append("\\\'"); + continue; + case '\\': + retval.append("\\\\"); + continue; + default: + if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) { + String s = "0000" + Integer.toString(ch, 16); + retval.append("\\u" + s.substring(s.length() - 4, s.length())); + } else { + retval.append(ch); + } + continue; + } + } + return retval.toString(); + } + + /** + * Returns a detailed message for the Error when it is thrown by the + * token manager to indicate a lexical error. + * Parameters : + * EOFSeen : indicates if EOF caused the lexicl error + * curLexState : lexical state in which this error occured + * errorLine : line number when the error occured + * errorColumn : column number when the error occured + * errorAfter : prefix that was seen before this error occured + * curchar : the offending character + * Note: You can customize the lexical error message by modifying this method. + */ + protected static String LexicalError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar) { + return("Lexical error at line " + + errorLine + ", column " + + errorColumn + ". Encountered: " + + (EOFSeen ? " " : ("\"" + addEscapes(String.valueOf(curChar)) + "\"") + " (" + (int)curChar + "), ") + + "after : \"" + addEscapes(errorAfter) + "\""); + } + + /** + * You can also modify the body of this method to customize your error messages. + * For example, cases like LOOP_DETECTED and INVALID_LEXICAL_STATE are not + * of end-users concern, so you can return something like : + * + * "Internal Error : Please file a bug report .... " + * + * from this method for such cases in the release version of your parser. + */ + public String getMessage() { + return super.getMessage(); + } + + /* + * Constructors of various flavors follow. + */ + + public TokenMgrError() { + } + + public TokenMgrError(String message, int reason) { + super(message); + errorCode = reason; + } + + public TokenMgrError(boolean EOFSeen, int lexState, int errorLine, int errorColumn, String errorAfter, char curChar, int reason) { + this(LexicalError(EOFSeen, lexState, errorLine, errorColumn, errorAfter, curChar), reason); + } +} diff --git a/java/org/apache/el/util/ConcurrentCache.java b/java/org/apache/el/util/ConcurrentCache.java index 119fdaf0c..780b5b56f 100644 --- a/java/org/apache/el/util/ConcurrentCache.java +++ b/java/org/apache/el/util/ConcurrentCache.java @@ -1,39 +1,39 @@ -package org.apache.el.util; - -import java.util.Map; -import java.util.WeakHashMap; -import java.util.concurrent.ConcurrentHashMap; - -public final class ConcurrentCache { - - private final int size; - - private final Map eden; - - private final Map longterm; - - public ConcurrentCache(int size) { - this.size = size; - this.eden = new ConcurrentHashMap(size); - this.longterm = new WeakHashMap(size); - } - - public V get(K k) { - V v = this.eden.get(k); - if (v == null) { - v = this.longterm.get(k); - if (v != null) { - this.eden.put(k, v); - } - } - return v; - } - - public void put(K k, V v) { - if (this.eden.size() >= size) { - this.longterm.putAll(this.eden); - this.eden.clear(); - } - this.eden.put(k, v); - } -} +package org.apache.el.util; + +import java.util.Map; +import java.util.WeakHashMap; +import java.util.concurrent.ConcurrentHashMap; + +public final class ConcurrentCache { + + private final int size; + + private final Map eden; + + private final Map longterm; + + public ConcurrentCache(int size) { + this.size = size; + this.eden = new ConcurrentHashMap(size); + this.longterm = new WeakHashMap(size); + } + + public V get(K k) { + V v = this.eden.get(k); + if (v == null) { + v = this.longterm.get(k); + if (v != null) { + this.eden.put(k, v); + } + } + return v; + } + + public void put(K k, V v) { + if (this.eden.size() >= size) { + this.longterm.putAll(this.eden); + this.eden.clear(); + } + this.eden.put(k, v); + } +} diff --git a/java/org/apache/el/util/MessageFactory.java b/java/org/apache/el/util/MessageFactory.java index b261e14e7..27c249e7d 100644 --- a/java/org/apache/el/util/MessageFactory.java +++ b/java/org/apache/el/util/MessageFactory.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.el.util; - -import java.text.MessageFormat; -import java.util.ResourceBundle; - -/** - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ - */ -public final class MessageFactory { - - protected final static ResourceBundle bundle = ResourceBundle - .getBundle("org.apache.el.Messages"); - /** - * - */ - public MessageFactory() { - super(); - } - - public static String get(final String key) { - return bundle.getString(key); - } - - public static String get(final String key, final Object obj0) { - return getArray(key, new Object[] { obj0 }); - } - - public static String get(final String key, final Object obj0, - final Object obj1) { - return getArray(key, new Object[] { obj0, obj1 }); - } - - public static String get(final String key, final Object obj0, - final Object obj1, final Object obj2) { - return getArray(key, new Object[] { obj0, obj1, obj2 }); - } - - public static String get(final String key, final Object obj0, - final Object obj1, final Object obj2, final Object obj3) { - return getArray(key, new Object[] { obj0, obj1, obj2, obj3 }); - } - - public static String get(final String key, final Object obj0, - final Object obj1, final Object obj2, final Object obj3, - final Object obj4) { - return getArray(key, new Object[] { obj0, obj1, obj2, obj3, obj4 }); - } - - public static String getArray(final String key, final Object[] objA) { - return MessageFormat.format(bundle.getString(key), objA); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.el.util; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +/** + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: dpatil $ + */ +public final class MessageFactory { + + protected final static ResourceBundle bundle = ResourceBundle + .getBundle("org.apache.el.Messages"); + /** + * + */ + public MessageFactory() { + super(); + } + + public static String get(final String key) { + return bundle.getString(key); + } + + public static String get(final String key, final Object obj0) { + return getArray(key, new Object[] { obj0 }); + } + + public static String get(final String key, final Object obj0, + final Object obj1) { + return getArray(key, new Object[] { obj0, obj1 }); + } + + public static String get(final String key, final Object obj0, + final Object obj1, final Object obj2) { + return getArray(key, new Object[] { obj0, obj1, obj2 }); + } + + public static String get(final String key, final Object obj0, + final Object obj1, final Object obj2, final Object obj3) { + return getArray(key, new Object[] { obj0, obj1, obj2, obj3 }); + } + + public static String get(final String key, final Object obj0, + final Object obj1, final Object obj2, final Object obj3, + final Object obj4) { + return getArray(key, new Object[] { obj0, obj1, obj2, obj3, obj4 }); + } + + public static String getArray(final String key, final Object[] objA) { + return MessageFormat.format(bundle.getString(key), objA); + } + +} diff --git a/java/org/apache/el/util/ReflectionUtil.java b/java/org/apache/el/util/ReflectionUtil.java index 3a87e3103..b825f418b 100644 --- a/java/org/apache/el/util/ReflectionUtil.java +++ b/java/org/apache/el/util/ReflectionUtil.java @@ -1,183 +1,183 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.el.util; - -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Array; -import java.lang.reflect.Method; -import java.util.Arrays; - -import javax.el.ELException; -import javax.el.MethodNotFoundException; -import javax.el.PropertyNotFoundException; - -import org.apache.el.lang.ELSupport; - - -/** - * Utilities for Managing Serialization and Reflection - * - * @author Jacob Hookom [jacob@hookom.net] - * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ - */ -public class ReflectionUtil { - - protected static final String[] EMPTY_STRING = new String[0]; - - protected static final String[] PRIMITIVE_NAMES = new String[] { "boolean", - "byte", "char", "double", "float", "int", "long", "short", "void" }; - - protected static final Class[] PRIMITIVES = new Class[] { boolean.class, - byte.class, char.class, double.class, float.class, int.class, - long.class, short.class, Void.TYPE }; - - /** - * - */ - private ReflectionUtil() { - super(); - } - - public static Class forName(String name) throws ClassNotFoundException { - if (null == name || "".equals(name)) { - return null; - } - Class c = forNamePrimitive(name); - if (c == null) { - if (name.endsWith("[]")) { - String nc = name.substring(0, name.length() - 2); - c = Class.forName(nc, true, Thread.currentThread().getContextClassLoader()); - c = Array.newInstance(c, 0).getClass(); - } else { - c = Class.forName(name, true, Thread.currentThread().getContextClassLoader()); - } - } - return c; - } - - protected static Class forNamePrimitive(String name) { - if (name.length() <= 8) { - int p = Arrays.binarySearch(PRIMITIVE_NAMES, name); - if (p >= 0) { - return PRIMITIVES[p]; - } - } - return null; - } - - /** - * Converts an array of Class names to Class types - * @param s - * @return - * @throws ClassNotFoundException - */ - public static Class[] toTypeArray(String[] s) throws ClassNotFoundException { - if (s == null) - return null; - Class[] c = new Class[s.length]; - for (int i = 0; i < s.length; i++) { - c[i] = forName(s[i]); - } - return c; - } - - /** - * Converts an array of Class types to Class names - * @param c - * @return - */ - public static String[] toTypeNameArray(Class[] c) { - if (c == null) - return null; - String[] s = new String[c.length]; - for (int i = 0; i < c.length; i++) { - s[i] = c[i].getName(); - } - return s; - } - - /** - * Returns a method based on the criteria - * @param base the object that owns the method - * @param property the name of the method - * @param paramTypes the parameter types to use - * @return the method specified - * @throws MethodNotFoundException - */ - public static Method getMethod(Object base, Object property, - Class[] paramTypes) throws MethodNotFoundException { - if (base == null || property == null) { - throw new MethodNotFoundException(MessageFactory.get( - "error.method.notfound", base, property, - paramString(paramTypes))); - } - - String methodName = (property instanceof String) ? (String) property - : property.toString(); - - Method method = null; - try { - method = base.getClass().getMethod(methodName, paramTypes); - } catch (NoSuchMethodException nsme) { - throw new MethodNotFoundException(MessageFactory.get( - "error.method.notfound", base, property, - paramString(paramTypes))); - } - return method; - } - - protected static final String paramString(Class[] types) { - if (types != null) { - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < types.length; i++) { - sb.append(types[i].getName()).append(", "); - } - if (sb.length() > 2) { - sb.setLength(sb.length() - 2); - } - return sb.toString(); - } - return null; - } - - /** - * @param base - * @param property - * @return - * @throws ELException - * @throws PropertyNotFoundException - */ - public static PropertyDescriptor getPropertyDescriptor(Object base, - Object property) throws ELException, PropertyNotFoundException { - String name = ELSupport.coerceToString(property); - PropertyDescriptor p = null; - try { - PropertyDescriptor[] desc = Introspector.getBeanInfo( - base.getClass()).getPropertyDescriptors(); - for (int i = 0; i < desc.length; i++) { - if (desc[i].getName().equals(name)) { - return desc[i]; - } - } - } catch (IntrospectionException ie) { - throw new ELException(ie); - } - throw new PropertyNotFoundException(MessageFactory.get( - "error.property.notfound", base, name)); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.el.util; + +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.util.Arrays; + +import javax.el.ELException; +import javax.el.MethodNotFoundException; +import javax.el.PropertyNotFoundException; + +import org.apache.el.lang.ELSupport; + + +/** + * Utilities for Managing Serialization and Reflection + * + * @author Jacob Hookom [jacob@hookom.net] + * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: jhook $ + */ +public class ReflectionUtil { + + protected static final String[] EMPTY_STRING = new String[0]; + + protected static final String[] PRIMITIVE_NAMES = new String[] { "boolean", + "byte", "char", "double", "float", "int", "long", "short", "void" }; + + protected static final Class[] PRIMITIVES = new Class[] { boolean.class, + byte.class, char.class, double.class, float.class, int.class, + long.class, short.class, Void.TYPE }; + + /** + * + */ + private ReflectionUtil() { + super(); + } + + public static Class forName(String name) throws ClassNotFoundException { + if (null == name || "".equals(name)) { + return null; + } + Class c = forNamePrimitive(name); + if (c == null) { + if (name.endsWith("[]")) { + String nc = name.substring(0, name.length() - 2); + c = Class.forName(nc, true, Thread.currentThread().getContextClassLoader()); + c = Array.newInstance(c, 0).getClass(); + } else { + c = Class.forName(name, true, Thread.currentThread().getContextClassLoader()); + } + } + return c; + } + + protected static Class forNamePrimitive(String name) { + if (name.length() <= 8) { + int p = Arrays.binarySearch(PRIMITIVE_NAMES, name); + if (p >= 0) { + return PRIMITIVES[p]; + } + } + return null; + } + + /** + * Converts an array of Class names to Class types + * @param s + * @return + * @throws ClassNotFoundException + */ + public static Class[] toTypeArray(String[] s) throws ClassNotFoundException { + if (s == null) + return null; + Class[] c = new Class[s.length]; + for (int i = 0; i < s.length; i++) { + c[i] = forName(s[i]); + } + return c; + } + + /** + * Converts an array of Class types to Class names + * @param c + * @return + */ + public static String[] toTypeNameArray(Class[] c) { + if (c == null) + return null; + String[] s = new String[c.length]; + for (int i = 0; i < c.length; i++) { + s[i] = c[i].getName(); + } + return s; + } + + /** + * Returns a method based on the criteria + * @param base the object that owns the method + * @param property the name of the method + * @param paramTypes the parameter types to use + * @return the method specified + * @throws MethodNotFoundException + */ + public static Method getMethod(Object base, Object property, + Class[] paramTypes) throws MethodNotFoundException { + if (base == null || property == null) { + throw new MethodNotFoundException(MessageFactory.get( + "error.method.notfound", base, property, + paramString(paramTypes))); + } + + String methodName = (property instanceof String) ? (String) property + : property.toString(); + + Method method = null; + try { + method = base.getClass().getMethod(methodName, paramTypes); + } catch (NoSuchMethodException nsme) { + throw new MethodNotFoundException(MessageFactory.get( + "error.method.notfound", base, property, + paramString(paramTypes))); + } + return method; + } + + protected static final String paramString(Class[] types) { + if (types != null) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < types.length; i++) { + sb.append(types[i].getName()).append(", "); + } + if (sb.length() > 2) { + sb.setLength(sb.length() - 2); + } + return sb.toString(); + } + return null; + } + + /** + * @param base + * @param property + * @return + * @throws ELException + * @throws PropertyNotFoundException + */ + public static PropertyDescriptor getPropertyDescriptor(Object base, + Object property) throws ELException, PropertyNotFoundException { + String name = ELSupport.coerceToString(property); + PropertyDescriptor p = null; + try { + PropertyDescriptor[] desc = Introspector.getBeanInfo( + base.getClass()).getPropertyDescriptors(); + for (int i = 0; i < desc.length; i++) { + if (desc[i].getName().equals(name)) { + return desc[i]; + } + } + } catch (IntrospectionException ie) { + throw new ELException(ie); + } + throw new PropertyNotFoundException(MessageFactory.get( + "error.property.notfound", base, name)); + } +} diff --git a/java/org/apache/jasper/Constants.java b/java/org/apache/jasper/Constants.java index 17f9de472..1017d98a9 100644 --- a/java/org/apache/jasper/Constants.java +++ b/java/org/apache/jasper/Constants.java @@ -1,194 +1,194 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - - -/** - * Some constants and other global data that are used by the compiler and the runtime. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Shawn Bayern - * @author Mark Roth - */ -public class Constants { - /** - * The base class of the generated servlets. - */ - public static final String JSP_SERVLET_BASE = "org.apache.jasper.runtime.HttpJspBase"; - - /** - * _jspService is the name of the method that is called by - * HttpJspBase.service(). This is where most of the code generated - * from JSPs go. - */ - public static final String SERVICE_METHOD_NAME = "_jspService"; - - /** - * Default servlet content type. - */ - public static final String SERVLET_CONTENT_TYPE = "text/html"; - - /** - * These classes/packages are automatically imported by the - * generated code. - */ - public static final String[] STANDARD_IMPORTS = { - "javax.servlet.*", - "javax.servlet.http.*", - "javax.servlet.jsp.*" - }; - - /** - * FIXME - * ServletContext attribute for classpath. This is tomcat specific. - * Other servlet engines may choose to support this attribute if they - * want to have this JSP engine running on them. - */ - public static final String SERVLET_CLASSPATH = "org.apache.catalina.jsp_classpath"; - - /** - * FIXME - * Request attribute for <jsp-file> element of a - * servlet definition. If present on a request, this overrides the - * value returned by request.getServletPath() to select - * the JSP page to be executed. - */ - public static final String JSP_FILE = "org.apache.catalina.jsp_file"; - - - /** - * FIXME - * ServletContext attribute for class loader. This is tomcat specific. - * Other servlet engines can choose to have this attribute if they - * want to have this JSP engine running on them. - */ - //public static final String SERVLET_CLASS_LOADER = "org.apache.tomcat.classloader"; - public static final String SERVLET_CLASS_LOADER = "org.apache.catalina.classloader"; - - /** - * Default size of the JSP buffer. - */ - public static final int K = 1024; - public static final int DEFAULT_BUFFER_SIZE = 8*K; - - /** - * Default size for the tag buffers. - */ - public static final int DEFAULT_TAG_BUFFER_SIZE = 512; - - /** - * Default tag handler pool size. - */ - public static final int MAX_POOL_SIZE = 5; - - /** - * The query parameter that causes the JSP engine to just - * pregenerated the servlet but not invoke it. - */ - public static final String PRECOMPILE = "jsp_precompile"; - - /** - * The default package name for compiled jsp pages. - */ - public static final String JSP_PACKAGE_NAME = "org.apache.jsp"; - - /** - * The default package name for tag handlers generated from tag files - */ - public static final String TAG_FILE_PACKAGE_NAME = "org.apache.jsp.tag"; - - /** - * Servlet context and request attributes that the JSP engine - * uses. - */ - public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri"; - public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path"; - public static final String TMP_DIR = "javax.servlet.context.tempdir"; - public static final String FORWARD_SEEN = "javax.servlet.forward.seen"; - - // Must be kept in sync with org/apache/catalina/Globals.java - public static final String ALT_DD_ATTR = "org.apache.catalina.deploy.alt_dd"; - - /** - * Public Id and the Resource path (of the cached copy) - * of the DTDs for tag library descriptors. - */ - public static final String TAGLIB_DTD_PUBLIC_ID_11 = - "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; - public static final String TAGLIB_DTD_RESOURCE_PATH_11 = - "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd"; - public static final String TAGLIB_DTD_PUBLIC_ID_12 = - "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; - public static final String TAGLIB_DTD_RESOURCE_PATH_12 = - "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd"; - - /** - * Public Id and the Resource path (of the cached copy) - * of the DTDs for web application deployment descriptors - */ - public static final String WEBAPP_DTD_PUBLIC_ID_22 = - "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; - public static final String WEBAPP_DTD_RESOURCE_PATH_22 = - "/javax/servlet/resources/web-app_2_2.dtd"; - public static final String WEBAPP_DTD_PUBLIC_ID_23 = - "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; - public static final String WEBAPP_DTD_RESOURCE_PATH_23 = - "/javax/servlet/resources/web-app_2_3.dtd"; - - /** - * List of the Public IDs that we cache, and their - * associated location. This is used by - * an EntityResolver to return the location of the - * cached copy of a DTD. - */ - public static final String[] CACHED_DTD_PUBLIC_IDS = { - TAGLIB_DTD_PUBLIC_ID_11, - TAGLIB_DTD_PUBLIC_ID_12, - WEBAPP_DTD_PUBLIC_ID_22, - WEBAPP_DTD_PUBLIC_ID_23, - }; - public static final String[] CACHED_DTD_RESOURCE_PATHS = { - TAGLIB_DTD_RESOURCE_PATH_11, - TAGLIB_DTD_RESOURCE_PATH_12, - WEBAPP_DTD_RESOURCE_PATH_22, - WEBAPP_DTD_RESOURCE_PATH_23, - }; - - /** - * Default URLs to download the pluging for Netscape and IE. - */ - public static final String NS_PLUGIN_URL = - "http://java.sun.com/products/plugin/"; - - public static final String IE_PLUGIN_URL = - "http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0"; - - /** - * Prefix to use for generated temporary variable names - */ - public static final String TEMP_VARIABLE_NAME_PREFIX = - "_jspx_temp"; - - /** - * A replacement char for "\$". - * XXX This is a hack to avoid changing EL interpreter to recognize "\$" - */ - public static final char ESC='\u001b'; - public static final String ESCStr="'\\u001b'"; -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + + +/** + * Some constants and other global data that are used by the compiler and the runtime. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Shawn Bayern + * @author Mark Roth + */ +public class Constants { + /** + * The base class of the generated servlets. + */ + public static final String JSP_SERVLET_BASE = "org.apache.jasper.runtime.HttpJspBase"; + + /** + * _jspService is the name of the method that is called by + * HttpJspBase.service(). This is where most of the code generated + * from JSPs go. + */ + public static final String SERVICE_METHOD_NAME = "_jspService"; + + /** + * Default servlet content type. + */ + public static final String SERVLET_CONTENT_TYPE = "text/html"; + + /** + * These classes/packages are automatically imported by the + * generated code. + */ + public static final String[] STANDARD_IMPORTS = { + "javax.servlet.*", + "javax.servlet.http.*", + "javax.servlet.jsp.*" + }; + + /** + * FIXME + * ServletContext attribute for classpath. This is tomcat specific. + * Other servlet engines may choose to support this attribute if they + * want to have this JSP engine running on them. + */ + public static final String SERVLET_CLASSPATH = "org.apache.catalina.jsp_classpath"; + + /** + * FIXME + * Request attribute for <jsp-file> element of a + * servlet definition. If present on a request, this overrides the + * value returned by request.getServletPath() to select + * the JSP page to be executed. + */ + public static final String JSP_FILE = "org.apache.catalina.jsp_file"; + + + /** + * FIXME + * ServletContext attribute for class loader. This is tomcat specific. + * Other servlet engines can choose to have this attribute if they + * want to have this JSP engine running on them. + */ + //public static final String SERVLET_CLASS_LOADER = "org.apache.tomcat.classloader"; + public static final String SERVLET_CLASS_LOADER = "org.apache.catalina.classloader"; + + /** + * Default size of the JSP buffer. + */ + public static final int K = 1024; + public static final int DEFAULT_BUFFER_SIZE = 8*K; + + /** + * Default size for the tag buffers. + */ + public static final int DEFAULT_TAG_BUFFER_SIZE = 512; + + /** + * Default tag handler pool size. + */ + public static final int MAX_POOL_SIZE = 5; + + /** + * The query parameter that causes the JSP engine to just + * pregenerated the servlet but not invoke it. + */ + public static final String PRECOMPILE = "jsp_precompile"; + + /** + * The default package name for compiled jsp pages. + */ + public static final String JSP_PACKAGE_NAME = "org.apache.jsp"; + + /** + * The default package name for tag handlers generated from tag files + */ + public static final String TAG_FILE_PACKAGE_NAME = "org.apache.jsp.tag"; + + /** + * Servlet context and request attributes that the JSP engine + * uses. + */ + public static final String INC_REQUEST_URI = "javax.servlet.include.request_uri"; + public static final String INC_SERVLET_PATH = "javax.servlet.include.servlet_path"; + public static final String TMP_DIR = "javax.servlet.context.tempdir"; + public static final String FORWARD_SEEN = "javax.servlet.forward.seen"; + + // Must be kept in sync with org/apache/catalina/Globals.java + public static final String ALT_DD_ATTR = "org.apache.catalina.deploy.alt_dd"; + + /** + * Public Id and the Resource path (of the cached copy) + * of the DTDs for tag library descriptors. + */ + public static final String TAGLIB_DTD_PUBLIC_ID_11 = + "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.1//EN"; + public static final String TAGLIB_DTD_RESOURCE_PATH_11 = + "/javax/servlet/jsp/resources/web-jsptaglibrary_1_1.dtd"; + public static final String TAGLIB_DTD_PUBLIC_ID_12 = + "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN"; + public static final String TAGLIB_DTD_RESOURCE_PATH_12 = + "/javax/servlet/jsp/resources/web-jsptaglibrary_1_2.dtd"; + + /** + * Public Id and the Resource path (of the cached copy) + * of the DTDs for web application deployment descriptors + */ + public static final String WEBAPP_DTD_PUBLIC_ID_22 = + "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"; + public static final String WEBAPP_DTD_RESOURCE_PATH_22 = + "/javax/servlet/resources/web-app_2_2.dtd"; + public static final String WEBAPP_DTD_PUBLIC_ID_23 = + "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"; + public static final String WEBAPP_DTD_RESOURCE_PATH_23 = + "/javax/servlet/resources/web-app_2_3.dtd"; + + /** + * List of the Public IDs that we cache, and their + * associated location. This is used by + * an EntityResolver to return the location of the + * cached copy of a DTD. + */ + public static final String[] CACHED_DTD_PUBLIC_IDS = { + TAGLIB_DTD_PUBLIC_ID_11, + TAGLIB_DTD_PUBLIC_ID_12, + WEBAPP_DTD_PUBLIC_ID_22, + WEBAPP_DTD_PUBLIC_ID_23, + }; + public static final String[] CACHED_DTD_RESOURCE_PATHS = { + TAGLIB_DTD_RESOURCE_PATH_11, + TAGLIB_DTD_RESOURCE_PATH_12, + WEBAPP_DTD_RESOURCE_PATH_22, + WEBAPP_DTD_RESOURCE_PATH_23, + }; + + /** + * Default URLs to download the pluging for Netscape and IE. + */ + public static final String NS_PLUGIN_URL = + "http://java.sun.com/products/plugin/"; + + public static final String IE_PLUGIN_URL = + "http://java.sun.com/products/plugin/1.2.2/jinstall-1_2_2-win.cab#Version=1,2,2,0"; + + /** + * Prefix to use for generated temporary variable names + */ + public static final String TEMP_VARIABLE_NAME_PREFIX = + "_jspx_temp"; + + /** + * A replacement char for "\$". + * XXX This is a hack to avoid changing EL interpreter to recognize "\$" + */ + public static final char ESC='\u001b'; + public static final String ESCStr="'\\u001b'"; +} + diff --git a/java/org/apache/jasper/EmbeddedServletOptions.java b/java/org/apache/jasper/EmbeddedServletOptions.java index 8059b33a1..b2accd653 100644 --- a/java/org/apache/jasper/EmbeddedServletOptions.java +++ b/java/org/apache/jasper/EmbeddedServletOptions.java @@ -1,668 +1,668 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.util.*; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; - -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * A class to hold all init parameters specific to the JSP engine. - * - * @author Anil K. Vijendran - * @author Hans Bergsten - * @author Pierre Delisle - */ -public final class EmbeddedServletOptions implements Options { - - // Logger - private Log log = LogFactory.getLog(EmbeddedServletOptions.class); - - private Properties settings = new Properties(); - - /** - * Is Jasper being used in development mode? - */ - private boolean development = true; - - /** - * Should Ant fork its java compiles of JSP pages. - */ - public boolean fork = true; - - /** - * Do you want to keep the generated Java files around? - */ - private boolean keepGenerated = true; - - /** - * Should white spaces between directives or actions be trimmed? - */ - private boolean trimSpaces = false; - - /** - * Determines whether tag handler pooling is enabled. - */ - private boolean isPoolingEnabled = true; - - /** - * Do you want support for "mapped" files? This will generate - * servlet that has a print statement per line of the JSP file. - * This seems like a really nice feature to have for debugging. - */ - private boolean mappedFile = true; - - /** - * Do you want stack traces and such displayed in the client's - * browser? If this is false, such messages go to the standard - * error or a log file if the standard error is redirected. - */ - private boolean sendErrorToClient = false; - - /** - * Do we want to include debugging information in the class file? - */ - private boolean classDebugInfo = true; - - /** - * Background compile thread check interval in seconds. - */ - private int checkInterval = 0; - - /** - * Is the generation of SMAP info for JSR45 debuggin suppressed? - */ - private boolean isSmapSuppressed = false; - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - private boolean isSmapDumped = false; - - /** - * Are Text strings to be generated as char arrays? - */ - private boolean genStringAsCharArray = false; - - private boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * I want to see my generated servlets. Which directory are they - * in? - */ - private File scratchDir; - - /** - * Need to have this as is for versions 4 and 5 of IE. Can be set from - * the initParams so if it changes in the future all that is needed is - * to have a jsp initParam of type ieClassId="" - */ - private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - /** - * What classpath should I use while compiling generated servlets? - */ - private String classpath = null; - - /** - * Compiler to use. - */ - private String compiler = null; - - /** - * Compiler target VM. - */ - private String compilerTargetVM = "1.5"; - - /** - * The compiler source VM. - */ - private String compilerSourceVM = "1.5"; - - /** - * Cache for the TLD locations - */ - private TldLocationsCache tldLocationsCache = null; - - /** - * Jsp config information - */ - private JspConfig jspConfig = null; - - /** - * TagPluginManager - */ - private TagPluginManager tagPluginManager = null; - - /** - * Java platform encoding to generate the JSP - * page servlet. - */ - private String javaEncoding = "UTF8"; - - /** - * Modification test interval. - */ - private int modificationTestInterval = 4; - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - private boolean xpoweredBy; - - /** - * Should annotations be ignored? - */ - private boolean ignoreAnnotations = false; - - public String getProperty(String name ) { - return settings.getProperty( name ); - } - - public void setProperty(String name, String value ) { - if (name != null && value != null){ - settings.setProperty( name, value ); - } - } - - /** - * Are we keeping generated code around? - */ - public boolean getKeepGenerated() { - return keepGenerated; - } - - /** - * Should white spaces between directives or actions be trimmed? - */ - public boolean getTrimSpaces() { - return trimSpaces; - } - - public boolean isPoolingEnabled() { - return isPoolingEnabled; - } - - /** - * Are we supporting HTML mapped servlets? - */ - public boolean getMappedFile() { - return mappedFile; - } - - /** - * Should errors be sent to client or thrown into stderr? - */ - public boolean getSendErrorToClient() { - return sendErrorToClient; - } - - /** - * Should class files be compiled with debug information? - */ - public boolean getClassDebugInfo() { - return classDebugInfo; - } - - /** - * Background JSP compile thread check intervall - */ - public int getCheckInterval() { - return checkInterval; - } - - /** - * Modification test interval. - */ - public int getModificationTestInterval() { - return modificationTestInterval; - } - - /** - * Is Jasper being used in development mode? - */ - public boolean getDevelopment() { - return development; - } - - /** - * Should annotations on tags be ignored? - */ - public boolean getIgnoreAnnotations() { - return ignoreAnnotations; - } - - /** - * Is the generation of SMAP info for JSR45 debuggin suppressed? - */ - public boolean isSmapSuppressed() { - return isSmapSuppressed; - } - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - public boolean isSmapDumped() { - return isSmapDumped; - } - - /** - * Are Text strings to be generated as char arrays? - */ - public boolean genStringAsCharArray() { - return this.genStringAsCharArray; - } - - /** - * Class ID for use in the plugin tag when the browser is IE. - */ - public String getIeClassId() { - return ieClassId; - } - - /** - * What is my scratch dir? - */ - public File getScratchDir() { - return scratchDir; - } - - /** - * What classpath should I use while compiling the servlets - * generated from JSP files? - */ - public String getClassPath() { - return classpath; - } - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - public boolean isXpoweredBy() { - return xpoweredBy; - } - - /** - * Compiler to use. - */ - public String getCompiler() { - return compiler; - } - - /** - * @see Options#getCompilerTargetVM - */ - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - /** - * @see Options#getCompilerSourceVM - */ - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - public void setTldLocationsCache( TldLocationsCache tldC ) { - tldLocationsCache = tldC; - } - - public String getJavaEncoding() { - return javaEncoding; - } - - public boolean getFork() { - return fork; - } - - public JspConfig getJspConfig() { - return jspConfig; - } - - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - public boolean isCaching() { - return false; - } - - public Map getCache() { - return null; - } - - /** - * Create an EmbeddedServletOptions object using data available from - * ServletConfig and ServletContext. - */ - public EmbeddedServletOptions(ServletConfig config, - ServletContext context) { - - // JVM version numbers - try { - if (Float.parseFloat(System.getProperty("java.specification.version")) > 1.4) { - compilerSourceVM = compilerTargetVM = "1.5"; - } else { - compilerSourceVM = compilerTargetVM = "1.4"; - } - } catch (NumberFormatException e) { - // Ignore - } - - Enumeration enumeration=config.getInitParameterNames(); - while( enumeration.hasMoreElements() ) { - String k=(String)enumeration.nextElement(); - String v=config.getInitParameter( k ); - setProperty( k, v); - } - - // quick hack - String validating=config.getInitParameter( "validating"); - if( "false".equals( validating )) ParserUtils.validating=false; - - String annotations = config.getInitParameter("org.apache.jasper.IGNORE_ANNOTATIONS"); - if ("true".equals(annotations)) { - ignoreAnnotations = true; - } - - String keepgen = config.getInitParameter("keepgenerated"); - if (keepgen != null) { - if (keepgen.equalsIgnoreCase("true")) { - this.keepGenerated = true; - } else if (keepgen.equalsIgnoreCase("false")) { - this.keepGenerated = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.keepgen")); - } - } - } - - - String trimsp = config.getInitParameter("trimSpaces"); - if (trimsp != null) { - if (trimsp.equalsIgnoreCase("true")) { - trimSpaces = true; - } else if (trimsp.equalsIgnoreCase("false")) { - trimSpaces = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.trimspaces")); - } - } - } - - this.isPoolingEnabled = true; - String poolingEnabledParam - = config.getInitParameter("enablePooling"); - if (poolingEnabledParam != null - && !poolingEnabledParam.equalsIgnoreCase("true")) { - if (poolingEnabledParam.equalsIgnoreCase("false")) { - this.isPoolingEnabled = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.enablePooling")); - } - } - } - - String mapFile = config.getInitParameter("mappedfile"); - if (mapFile != null) { - if (mapFile.equalsIgnoreCase("true")) { - this.mappedFile = true; - } else if (mapFile.equalsIgnoreCase("false")) { - this.mappedFile = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.mappedFile")); - } - } - } - - String senderr = config.getInitParameter("sendErrToClient"); - if (senderr != null) { - if (senderr.equalsIgnoreCase("true")) { - this.sendErrorToClient = true; - } else if (senderr.equalsIgnoreCase("false")) { - this.sendErrorToClient = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.sendErrToClient")); - } - } - } - - String debugInfo = config.getInitParameter("classdebuginfo"); - if (debugInfo != null) { - if (debugInfo.equalsIgnoreCase("true")) { - this.classDebugInfo = true; - } else if (debugInfo.equalsIgnoreCase("false")) { - this.classDebugInfo = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); - } - } - } - - String checkInterval = config.getInitParameter("checkInterval"); - if (checkInterval != null) { - try { - this.checkInterval = Integer.parseInt(checkInterval); - if (this.checkInterval == 0) { - this.checkInterval = 300; - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.checkInterval")); - } - } - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.checkInterval")); - } - } - } - - String modificationTestInterval = config.getInitParameter("modificationTestInterval"); - if (modificationTestInterval != null) { - try { - this.modificationTestInterval = Integer.parseInt(modificationTestInterval); - } catch(NumberFormatException ex) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); - } - } - } - - String development = config.getInitParameter("development"); - if (development != null) { - if (development.equalsIgnoreCase("true")) { - this.development = true; - } else if (development.equalsIgnoreCase("false")) { - this.development = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.development")); - } - } - } - - String suppressSmap = config.getInitParameter("suppressSmap"); - if (suppressSmap != null) { - if (suppressSmap.equalsIgnoreCase("true")) { - isSmapSuppressed = true; - } else if (suppressSmap.equalsIgnoreCase("false")) { - isSmapSuppressed = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); - } - } - } - - String dumpSmap = config.getInitParameter("dumpSmap"); - if (dumpSmap != null) { - if (dumpSmap.equalsIgnoreCase("true")) { - isSmapDumped = true; - } else if (dumpSmap.equalsIgnoreCase("false")) { - isSmapDumped = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); - } - } - } - - String genCharArray = config.getInitParameter("genStrAsCharArray"); - if (genCharArray != null) { - if (genCharArray.equalsIgnoreCase("true")) { - genStringAsCharArray = true; - } else if (genCharArray.equalsIgnoreCase("false")) { - genStringAsCharArray = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.genchararray")); - } - } - } - - String errBeanClass = - config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); - if (errBeanClass != null) { - if (errBeanClass.equalsIgnoreCase("true")) { - errorOnUseBeanInvalidClassAttribute = true; - } else if (errBeanClass.equalsIgnoreCase("false")) { - errorOnUseBeanInvalidClassAttribute = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.errBean")); - } - } - } - - String ieClassId = config.getInitParameter("ieClassId"); - if (ieClassId != null) - this.ieClassId = ieClassId; - - String classpath = config.getInitParameter("classpath"); - if (classpath != null) - this.classpath = classpath; - - /* - * scratchdir - */ - String dir = config.getInitParameter("scratchdir"); - if (dir != null) { - scratchDir = new File(dir); - } else { - // First try the Servlet 2.2 javax.servlet.context.tempdir property - scratchDir = (File) context.getAttribute(Constants.TMP_DIR); - if (scratchDir == null) { - // Not running in a Servlet 2.2 container. - // Try to get the JDK 1.2 java.io.tmpdir property - dir = System.getProperty("java.io.tmpdir"); - if (dir != null) - scratchDir = new File(dir); - } - } - if (this.scratchDir == null) { - log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); - return; - } - - if (!(scratchDir.exists() && scratchDir.canRead() && - scratchDir.canWrite() && scratchDir.isDirectory())) - log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", - scratchDir.getAbsolutePath())); - - this.compiler = config.getInitParameter("compiler"); - - String compilerTargetVM = config.getInitParameter("compilerTargetVM"); - if(compilerTargetVM != null) { - this.compilerTargetVM = compilerTargetVM; - } - - String compilerSourceVM = config.getInitParameter("compilerSourceVM"); - if(compilerSourceVM != null) { - this.compilerSourceVM = compilerSourceVM; - } - - String javaEncoding = config.getInitParameter("javaEncoding"); - if (javaEncoding != null) { - this.javaEncoding = javaEncoding; - } - - String fork = config.getInitParameter("fork"); - if (fork != null) { - if (fork.equalsIgnoreCase("true")) { - this.fork = true; - } else if (fork.equalsIgnoreCase("false")) { - this.fork = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.fork")); - } - } - } - - String xpoweredBy = config.getInitParameter("xpoweredBy"); - if (xpoweredBy != null) { - if (xpoweredBy.equalsIgnoreCase("true")) { - this.xpoweredBy = true; - } else if (xpoweredBy.equalsIgnoreCase("false")) { - this.xpoweredBy = false; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); - } - } - } - - // Setup the global Tag Libraries location cache for this - // web-application. - tldLocationsCache = new TldLocationsCache(context); - - // Setup the jsp config info for this web app. - jspConfig = new JspConfig(context); - - // Create a Tag plugin instance - tagPluginManager = new TagPluginManager(context); - } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.util.*; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; + +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * A class to hold all init parameters specific to the JSP engine. + * + * @author Anil K. Vijendran + * @author Hans Bergsten + * @author Pierre Delisle + */ +public final class EmbeddedServletOptions implements Options { + + // Logger + private Log log = LogFactory.getLog(EmbeddedServletOptions.class); + + private Properties settings = new Properties(); + + /** + * Is Jasper being used in development mode? + */ + private boolean development = true; + + /** + * Should Ant fork its java compiles of JSP pages. + */ + public boolean fork = true; + + /** + * Do you want to keep the generated Java files around? + */ + private boolean keepGenerated = true; + + /** + * Should white spaces between directives or actions be trimmed? + */ + private boolean trimSpaces = false; + + /** + * Determines whether tag handler pooling is enabled. + */ + private boolean isPoolingEnabled = true; + + /** + * Do you want support for "mapped" files? This will generate + * servlet that has a print statement per line of the JSP file. + * This seems like a really nice feature to have for debugging. + */ + private boolean mappedFile = true; + + /** + * Do you want stack traces and such displayed in the client's + * browser? If this is false, such messages go to the standard + * error or a log file if the standard error is redirected. + */ + private boolean sendErrorToClient = false; + + /** + * Do we want to include debugging information in the class file? + */ + private boolean classDebugInfo = true; + + /** + * Background compile thread check interval in seconds. + */ + private int checkInterval = 0; + + /** + * Is the generation of SMAP info for JSR45 debuggin suppressed? + */ + private boolean isSmapSuppressed = false; + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + private boolean isSmapDumped = false; + + /** + * Are Text strings to be generated as char arrays? + */ + private boolean genStringAsCharArray = false; + + private boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * I want to see my generated servlets. Which directory are they + * in? + */ + private File scratchDir; + + /** + * Need to have this as is for versions 4 and 5 of IE. Can be set from + * the initParams so if it changes in the future all that is needed is + * to have a jsp initParam of type ieClassId="" + */ + private String ieClassId = "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + /** + * What classpath should I use while compiling generated servlets? + */ + private String classpath = null; + + /** + * Compiler to use. + */ + private String compiler = null; + + /** + * Compiler target VM. + */ + private String compilerTargetVM = "1.5"; + + /** + * The compiler source VM. + */ + private String compilerSourceVM = "1.5"; + + /** + * Cache for the TLD locations + */ + private TldLocationsCache tldLocationsCache = null; + + /** + * Jsp config information + */ + private JspConfig jspConfig = null; + + /** + * TagPluginManager + */ + private TagPluginManager tagPluginManager = null; + + /** + * Java platform encoding to generate the JSP + * page servlet. + */ + private String javaEncoding = "UTF8"; + + /** + * Modification test interval. + */ + private int modificationTestInterval = 4; + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + private boolean xpoweredBy; + + /** + * Should annotations be ignored? + */ + private boolean ignoreAnnotations = false; + + public String getProperty(String name ) { + return settings.getProperty( name ); + } + + public void setProperty(String name, String value ) { + if (name != null && value != null){ + settings.setProperty( name, value ); + } + } + + /** + * Are we keeping generated code around? + */ + public boolean getKeepGenerated() { + return keepGenerated; + } + + /** + * Should white spaces between directives or actions be trimmed? + */ + public boolean getTrimSpaces() { + return trimSpaces; + } + + public boolean isPoolingEnabled() { + return isPoolingEnabled; + } + + /** + * Are we supporting HTML mapped servlets? + */ + public boolean getMappedFile() { + return mappedFile; + } + + /** + * Should errors be sent to client or thrown into stderr? + */ + public boolean getSendErrorToClient() { + return sendErrorToClient; + } + + /** + * Should class files be compiled with debug information? + */ + public boolean getClassDebugInfo() { + return classDebugInfo; + } + + /** + * Background JSP compile thread check intervall + */ + public int getCheckInterval() { + return checkInterval; + } + + /** + * Modification test interval. + */ + public int getModificationTestInterval() { + return modificationTestInterval; + } + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment() { + return development; + } + + /** + * Should annotations on tags be ignored? + */ + public boolean getIgnoreAnnotations() { + return ignoreAnnotations; + } + + /** + * Is the generation of SMAP info for JSR45 debuggin suppressed? + */ + public boolean isSmapSuppressed() { + return isSmapSuppressed; + } + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + public boolean isSmapDumped() { + return isSmapDumped; + } + + /** + * Are Text strings to be generated as char arrays? + */ + public boolean genStringAsCharArray() { + return this.genStringAsCharArray; + } + + /** + * Class ID for use in the plugin tag when the browser is IE. + */ + public String getIeClassId() { + return ieClassId; + } + + /** + * What is my scratch dir? + */ + public File getScratchDir() { + return scratchDir; + } + + /** + * What classpath should I use while compiling the servlets + * generated from JSP files? + */ + public String getClassPath() { + return classpath; + } + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + public boolean isXpoweredBy() { + return xpoweredBy; + } + + /** + * Compiler to use. + */ + public String getCompiler() { + return compiler; + } + + /** + * @see Options#getCompilerTargetVM + */ + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + /** + * @see Options#getCompilerSourceVM + */ + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + public void setTldLocationsCache( TldLocationsCache tldC ) { + tldLocationsCache = tldC; + } + + public String getJavaEncoding() { + return javaEncoding; + } + + public boolean getFork() { + return fork; + } + + public JspConfig getJspConfig() { + return jspConfig; + } + + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + public boolean isCaching() { + return false; + } + + public Map getCache() { + return null; + } + + /** + * Create an EmbeddedServletOptions object using data available from + * ServletConfig and ServletContext. + */ + public EmbeddedServletOptions(ServletConfig config, + ServletContext context) { + + // JVM version numbers + try { + if (Float.parseFloat(System.getProperty("java.specification.version")) > 1.4) { + compilerSourceVM = compilerTargetVM = "1.5"; + } else { + compilerSourceVM = compilerTargetVM = "1.4"; + } + } catch (NumberFormatException e) { + // Ignore + } + + Enumeration enumeration=config.getInitParameterNames(); + while( enumeration.hasMoreElements() ) { + String k=(String)enumeration.nextElement(); + String v=config.getInitParameter( k ); + setProperty( k, v); + } + + // quick hack + String validating=config.getInitParameter( "validating"); + if( "false".equals( validating )) ParserUtils.validating=false; + + String annotations = config.getInitParameter("org.apache.jasper.IGNORE_ANNOTATIONS"); + if ("true".equals(annotations)) { + ignoreAnnotations = true; + } + + String keepgen = config.getInitParameter("keepgenerated"); + if (keepgen != null) { + if (keepgen.equalsIgnoreCase("true")) { + this.keepGenerated = true; + } else if (keepgen.equalsIgnoreCase("false")) { + this.keepGenerated = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.keepgen")); + } + } + } + + + String trimsp = config.getInitParameter("trimSpaces"); + if (trimsp != null) { + if (trimsp.equalsIgnoreCase("true")) { + trimSpaces = true; + } else if (trimsp.equalsIgnoreCase("false")) { + trimSpaces = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.trimspaces")); + } + } + } + + this.isPoolingEnabled = true; + String poolingEnabledParam + = config.getInitParameter("enablePooling"); + if (poolingEnabledParam != null + && !poolingEnabledParam.equalsIgnoreCase("true")) { + if (poolingEnabledParam.equalsIgnoreCase("false")) { + this.isPoolingEnabled = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.enablePooling")); + } + } + } + + String mapFile = config.getInitParameter("mappedfile"); + if (mapFile != null) { + if (mapFile.equalsIgnoreCase("true")) { + this.mappedFile = true; + } else if (mapFile.equalsIgnoreCase("false")) { + this.mappedFile = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.mappedFile")); + } + } + } + + String senderr = config.getInitParameter("sendErrToClient"); + if (senderr != null) { + if (senderr.equalsIgnoreCase("true")) { + this.sendErrorToClient = true; + } else if (senderr.equalsIgnoreCase("false")) { + this.sendErrorToClient = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.sendErrToClient")); + } + } + } + + String debugInfo = config.getInitParameter("classdebuginfo"); + if (debugInfo != null) { + if (debugInfo.equalsIgnoreCase("true")) { + this.classDebugInfo = true; + } else if (debugInfo.equalsIgnoreCase("false")) { + this.classDebugInfo = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.classDebugInfo")); + } + } + } + + String checkInterval = config.getInitParameter("checkInterval"); + if (checkInterval != null) { + try { + this.checkInterval = Integer.parseInt(checkInterval); + if (this.checkInterval == 0) { + this.checkInterval = 300; + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.checkInterval")); + } + } + } catch(NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.checkInterval")); + } + } + } + + String modificationTestInterval = config.getInitParameter("modificationTestInterval"); + if (modificationTestInterval != null) { + try { + this.modificationTestInterval = Integer.parseInt(modificationTestInterval); + } catch(NumberFormatException ex) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.modificationTestInterval")); + } + } + } + + String development = config.getInitParameter("development"); + if (development != null) { + if (development.equalsIgnoreCase("true")) { + this.development = true; + } else if (development.equalsIgnoreCase("false")) { + this.development = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.development")); + } + } + } + + String suppressSmap = config.getInitParameter("suppressSmap"); + if (suppressSmap != null) { + if (suppressSmap.equalsIgnoreCase("true")) { + isSmapSuppressed = true; + } else if (suppressSmap.equalsIgnoreCase("false")) { + isSmapSuppressed = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.suppressSmap")); + } + } + } + + String dumpSmap = config.getInitParameter("dumpSmap"); + if (dumpSmap != null) { + if (dumpSmap.equalsIgnoreCase("true")) { + isSmapDumped = true; + } else if (dumpSmap.equalsIgnoreCase("false")) { + isSmapDumped = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.dumpSmap")); + } + } + } + + String genCharArray = config.getInitParameter("genStrAsCharArray"); + if (genCharArray != null) { + if (genCharArray.equalsIgnoreCase("true")) { + genStringAsCharArray = true; + } else if (genCharArray.equalsIgnoreCase("false")) { + genStringAsCharArray = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.genchararray")); + } + } + } + + String errBeanClass = + config.getInitParameter("errorOnUseBeanInvalidClassAttribute"); + if (errBeanClass != null) { + if (errBeanClass.equalsIgnoreCase("true")) { + errorOnUseBeanInvalidClassAttribute = true; + } else if (errBeanClass.equalsIgnoreCase("false")) { + errorOnUseBeanInvalidClassAttribute = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.errBean")); + } + } + } + + String ieClassId = config.getInitParameter("ieClassId"); + if (ieClassId != null) + this.ieClassId = ieClassId; + + String classpath = config.getInitParameter("classpath"); + if (classpath != null) + this.classpath = classpath; + + /* + * scratchdir + */ + String dir = config.getInitParameter("scratchdir"); + if (dir != null) { + scratchDir = new File(dir); + } else { + // First try the Servlet 2.2 javax.servlet.context.tempdir property + scratchDir = (File) context.getAttribute(Constants.TMP_DIR); + if (scratchDir == null) { + // Not running in a Servlet 2.2 container. + // Try to get the JDK 1.2 java.io.tmpdir property + dir = System.getProperty("java.io.tmpdir"); + if (dir != null) + scratchDir = new File(dir); + } + } + if (this.scratchDir == null) { + log.fatal(Localizer.getMessage("jsp.error.no.scratch.dir")); + return; + } + + if (!(scratchDir.exists() && scratchDir.canRead() && + scratchDir.canWrite() && scratchDir.isDirectory())) + log.fatal(Localizer.getMessage("jsp.error.bad.scratch.dir", + scratchDir.getAbsolutePath())); + + this.compiler = config.getInitParameter("compiler"); + + String compilerTargetVM = config.getInitParameter("compilerTargetVM"); + if(compilerTargetVM != null) { + this.compilerTargetVM = compilerTargetVM; + } + + String compilerSourceVM = config.getInitParameter("compilerSourceVM"); + if(compilerSourceVM != null) { + this.compilerSourceVM = compilerSourceVM; + } + + String javaEncoding = config.getInitParameter("javaEncoding"); + if (javaEncoding != null) { + this.javaEncoding = javaEncoding; + } + + String fork = config.getInitParameter("fork"); + if (fork != null) { + if (fork.equalsIgnoreCase("true")) { + this.fork = true; + } else if (fork.equalsIgnoreCase("false")) { + this.fork = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.fork")); + } + } + } + + String xpoweredBy = config.getInitParameter("xpoweredBy"); + if (xpoweredBy != null) { + if (xpoweredBy.equalsIgnoreCase("true")) { + this.xpoweredBy = true; + } else if (xpoweredBy.equalsIgnoreCase("false")) { + this.xpoweredBy = false; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jsp.warning.xpoweredBy")); + } + } + } + + // Setup the global Tag Libraries location cache for this + // web-application. + tldLocationsCache = new TldLocationsCache(context); + + // Setup the jsp config info for this web app. + jspConfig = new JspConfig(context); + + // Create a Tag plugin instance + tagPluginManager = new TagPluginManager(context); + } + +} + diff --git a/java/org/apache/jasper/JasperException.java b/java/org/apache/jasper/JasperException.java index 00757876a..3135a5117 100644 --- a/java/org/apache/jasper/JasperException.java +++ b/java/org/apache/jasper/JasperException.java @@ -1,45 +1,45 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -/** - * Base class for all exceptions generated by the JSP engine. Makes it - * convienient to catch just this at the top-level. - * - * @author Anil K. Vijendran - */ -public class JasperException extends javax.servlet.ServletException { - - public JasperException(String reason) { - super(reason); - } - - /** - * Creates a JasperException with the embedded exception and the reason for - * throwing a JasperException - */ - public JasperException (String reason, Throwable exception) { - super(reason, exception); - } - - /** - * Creates a JasperException with the embedded exception - */ - public JasperException (Throwable exception) { - super(exception); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +/** + * Base class for all exceptions generated by the JSP engine. Makes it + * convienient to catch just this at the top-level. + * + * @author Anil K. Vijendran + */ +public class JasperException extends javax.servlet.ServletException { + + public JasperException(String reason) { + super(reason); + } + + /** + * Creates a JasperException with the embedded exception and the reason for + * throwing a JasperException + */ + public JasperException (String reason, Throwable exception) { + super(reason, exception); + } + + /** + * Creates a JasperException with the embedded exception + */ + public JasperException (Throwable exception) { + super(exception); + } +} diff --git a/java/org/apache/jasper/JspC.java b/java/org/apache/jasper/JspC.java index cede8b4c6..adb719ac0 100644 --- a/java/org/apache/jasper/JspC.java +++ b/java/org/apache/jasper/JspC.java @@ -1,1415 +1,1415 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.BufferedReader; -import java.io.CharArrayWriter; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.Writer; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.HashMap; -import java.util.Stack; -import java.util.StringTokenizer; -import java.util.Vector; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; -import org.apache.jasper.servlet.JspCServletContext; - -import org.apache.tools.ant.AntClassLoader; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.util.FileUtils; - -/** - * Shell for the jspc compiler. Handles all options associated with the - * command line and creates compilation contexts which it then compiles - * according to the specified options. - * - * This version can process files from a _single_ webapp at once, i.e. - * a single docbase can be specified. - * - * It can be used as an Ant task using: - *

        - *   <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
        - *      <classpath>
        - *          <pathelement location="${java.home}/../lib/tools.jar"/>
        - *          <fileset dir="${ENV.CATALINA_HOME}/server/lib">
        - *              <include name="*.jar"/>
        - *          </fileset>
        - *          <fileset dir="${ENV.CATALINA_HOME}/common/lib">
        - *              <include name="*.jar"/>
        - *          </fileset>
        - *          <path refid="myjars"/>
        - *       </classpath>
        - *  </taskdef>
        - *
        - *  <jasper2 verbose="0"
        - *           package="my.package"
        - *           uriroot="${webapps.dir}/${webapp.name}"
        - *           webXmlFragment="${build.dir}/generated_web.xml"
        - *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
        - * 
        - * - * @author Danno Ferrin - * @author Pierre Delisle - * @author Costin Manolache - * @author Yoav Shapira - */ -public class JspC implements Options { - - public static final String DEFAULT_IE_CLASS_ID = - "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; - - // Logger - private static Log log = LogFactory.getLog(JspC.class); - - private static final String SWITCH_VERBOSE = "-v"; - private static final String SWITCH_HELP = "-help"; - private static final String SWITCH_QUIET = "-q"; - private static final String SWITCH_OUTPUT_DIR = "-d"; - private static final String SWITCH_IE_CLASS_ID = "-ieplugin"; - private static final String SWITCH_PACKAGE_NAME = "-p"; - private static final String SWITCH_CACHE = "-cache"; - private static final String SWITCH_CLASS_NAME = "-c"; - private static final String SWITCH_FULL_STOP = "--"; - private static final String SWITCH_COMPILE = "-compile"; - private static final String SWITCH_SOURCE = "-source"; - private static final String SWITCH_TARGET = "-target"; - private static final String SWITCH_URI_BASE = "-uribase"; - private static final String SWITCH_URI_ROOT = "-uriroot"; - private static final String SWITCH_FILE_WEBAPP = "-webapp"; - private static final String SWITCH_WEBAPP_INC = "-webinc"; - private static final String SWITCH_WEBAPP_XML = "-webxml"; - private static final String SWITCH_MAPPED = "-mapped"; - private static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; - private static final String SWITCH_TRIM_SPACES = "-trimSpaces"; - private static final String SWITCH_CLASSPATH = "-classpath"; - private static final String SWITCH_DIE = "-die"; - private static final String SWITCH_POOLING = "-poolingEnabled"; - private static final String SWITCH_ENCODING = "-javaEncoding"; - private static final String SWITCH_SMAP = "-smap"; - private static final String SWITCH_DUMP_SMAP = "-dumpsmap"; - - private static final String SHOW_SUCCESS ="-s"; - private static final String LIST_ERRORS = "-l"; - private static final int NO_WEBXML = 0; - private static final int INC_WEBXML = 10; - private static final int ALL_WEBXML = 20; - private static final int DEFAULT_DIE_LEVEL = 1; - private static final int NO_DIE_LEVEL = 0; - - private static final String[] insertBefore = - { "", "", "", - "", "", "", "", - "", "", "", - "", "", "", "", - "" }; - - private static int die; - private String classPath = null; - private URLClassLoader loader = null; - private boolean trimSpaces = false; - private boolean genStringAsCharArray = false; - private boolean xpoweredBy; - private boolean mappedFile = false; - private boolean poolingEnabled = true; - private File scratchDir; - private String ieClassId = DEFAULT_IE_CLASS_ID; - private String targetPackage; - private String targetClassName; - private String uriBase; - private String uriRoot; - private Project project; - private int dieLevel; - private boolean helpNeeded = false; - private boolean compile = false; - private boolean smapSuppressed = true; - private boolean smapDumped = false; - private boolean caching = true; - private boolean ignoreAnnotations = false; - private Map cache = new HashMap(); - - private String compiler = null; - - private String compilerTargetVM = "1.4"; - private String compilerSourceVM = "1.4"; - - private boolean classDebugInfo = true; - - /** - * Throw an exception if there's a compilation error, or swallow it. - * Default is true to preserve old behavior. - */ - private boolean failOnError = true; - - /** - * The file extensions to be handled as JSP files. - * Default list is .jsp and .jspx. - */ - private List extensions; - - /** - * The pages. - */ - private List pages = new Vector(); - - /** - * Needs better documentation, this data member does. - * True by default. - */ - private boolean errorOnUseBeanInvalidClassAttribute = true; - - /** - * The java file encoding. Default - * is UTF-8. Added per bugzilla 19622. - */ - private String javaEncoding = "UTF-8"; - - // Generation of web.xml fragments - private String webxmlFile; - private int webxmlLevel; - private boolean addWebXmlMappings = false; - - private Writer mapout; - private CharArrayWriter servletout; - private CharArrayWriter mappingout; - - /** - * The servlet context. - */ - private JspCServletContext context; - - /** - * The runtime context. - * Maintain a dummy JspRuntimeContext for compiling tag files. - */ - private JspRuntimeContext rctxt; - - /** - * Cache for the TLD locations - */ - private TldLocationsCache tldLocationsCache = null; - - private JspConfig jspConfig = null; - private TagPluginManager tagPluginManager = null; - - private boolean verbose = false; - private boolean listErrors = false; - private boolean showSuccess = false; - private int argPos; - private boolean fullstop = false; - private String args[]; - - public static void main(String arg[]) { - if (arg.length == 0) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - try { - JspC jspc = new JspC(); - jspc.setArgs(arg); - if (jspc.helpNeeded) { - System.out.println(Localizer.getMessage("jspc.usage")); - } else { - jspc.execute(); - } - } catch (JasperException je) { - System.err.println(je); - //System.err.println(je.getMessage()); - if (die != NO_DIE_LEVEL) { - System.exit(die); - } - } - } - } - - public void setArgs(String[] arg) throws JasperException { - args = arg; - String tok; - - dieLevel = NO_DIE_LEVEL; - die = dieLevel; - - while ((tok = nextArg()) != null) { - if (tok.equals(SWITCH_VERBOSE)) { - verbose = true; - showSuccess = true; - listErrors = true; - } else if (tok.equals(SWITCH_OUTPUT_DIR)) { - tok = nextArg(); - setOutputDir( tok ); - } else if (tok.equals(SWITCH_PACKAGE_NAME)) { - targetPackage = nextArg(); - } else if (tok.equals(SWITCH_COMPILE)) { - compile=true; - } else if (tok.equals(SWITCH_CLASS_NAME)) { - targetClassName = nextArg(); - } else if (tok.equals(SWITCH_URI_BASE)) { - uriBase=nextArg(); - } else if (tok.equals(SWITCH_URI_ROOT)) { - setUriroot( nextArg()); - } else if (tok.equals(SWITCH_FILE_WEBAPP)) { - setUriroot( nextArg()); - } else if ( tok.equals( SHOW_SUCCESS ) ) { - showSuccess = true; - } else if ( tok.equals( LIST_ERRORS ) ) { - listErrors = true; - } else if (tok.equals(SWITCH_WEBAPP_INC)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = INC_WEBXML; - } - } else if (tok.equals(SWITCH_WEBAPP_XML)) { - webxmlFile = nextArg(); - if (webxmlFile != null) { - webxmlLevel = ALL_WEBXML; - } - } else if (tok.equals(SWITCH_MAPPED)) { - mappedFile = true; - } else if (tok.equals(SWITCH_XPOWERED_BY)) { - xpoweredBy = true; - } else if (tok.equals(SWITCH_TRIM_SPACES)) { - setTrimSpaces(true); - } else if (tok.equals(SWITCH_CACHE)) { - tok = nextArg(); - if ("false".equals(tok)) { - caching = false; - } else { - caching = true; - } - } else if (tok.equals(SWITCH_CLASSPATH)) { - setClassPath(nextArg()); - } else if (tok.startsWith(SWITCH_DIE)) { - try { - dieLevel = Integer.parseInt( - tok.substring(SWITCH_DIE.length())); - } catch (NumberFormatException nfe) { - dieLevel = DEFAULT_DIE_LEVEL; - } - die = dieLevel; - } else if (tok.equals(SWITCH_HELP)) { - helpNeeded = true; - } else if (tok.equals(SWITCH_POOLING)) { - tok = nextArg(); - if ("false".equals(tok)) { - poolingEnabled = false; - } else { - poolingEnabled = true; - } - } else if (tok.equals(SWITCH_ENCODING)) { - setJavaEncoding(nextArg()); - } else if (tok.equals(SWITCH_SOURCE)) { - setCompilerSourceVM(nextArg()); - } else if (tok.equals(SWITCH_TARGET)) { - setCompilerTargetVM(nextArg()); - } else if (tok.equals(SWITCH_SMAP)) { - smapSuppressed = false; - } else if (tok.equals(SWITCH_DUMP_SMAP)) { - smapDumped = true; - } else { - if (tok.startsWith("-")) { - throw new JasperException("Unrecognized option: " + tok + - ". Use -help for help."); - } - if (!fullstop) { - argPos--; - } - // Start treating the rest as JSP Pages - break; - } - } - - // Add all extra arguments to the list of files - while( true ) { - String file = nextFile(); - if( file==null ) { - break; - } - pages.add( file ); - } - } - - public boolean getKeepGenerated() { - // isn't this why we are running jspc? - return true; - } - - public boolean getTrimSpaces() { - return trimSpaces; - } - - public void setTrimSpaces(boolean ts) { - this.trimSpaces = ts; - } - - public boolean isPoolingEnabled() { - return poolingEnabled; - } - - public void setPoolingEnabled(boolean poolingEnabled) { - this.poolingEnabled = poolingEnabled; - } - - public boolean isXpoweredBy() { - return xpoweredBy; - } - - public void setXpoweredBy(boolean xpoweredBy) { - this.xpoweredBy = xpoweredBy; - } - - public boolean getErrorOnUseBeanInvalidClassAttribute() { - return errorOnUseBeanInvalidClassAttribute; - } - - public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { - errorOnUseBeanInvalidClassAttribute = b; - } - - public int getTagPoolSize() { - return Constants.MAX_POOL_SIZE; - } - - /** - * Are we supporting HTML mapped servlets? - */ - public boolean getMappedFile() { - return mappedFile; - } - - // Off-line compiler, no need for security manager - public Object getProtectionDomain() { - return null; - } - - public boolean getSendErrorToClient() { - // implied send to System.err - return true; - } - - public void setClassDebugInfo( boolean b ) { - classDebugInfo=b; - } - - public boolean getClassDebugInfo() { - // compile with debug info - return classDebugInfo; - } - - /** - * @see Options#isCaching() - */ - public boolean isCaching() { - return caching; - } - - /** - * @see Options#isCaching() - */ - public void setCaching(boolean caching) { - this.caching = caching; - } - - /** - * @see Options#getCache() - */ - public Map getCache() { - return cache; - } - - /** - * Background compilation check intervals in seconds - */ - public int getCheckInterval() { - return 0; - } - - /** - * Modification test interval. - */ - public int getModificationTestInterval() { - return 0; - } - - /** - * Is Jasper being used in development mode? - */ - public boolean getDevelopment() { - return false; - } - - /** - * Is the generation of SMAP info for JSR45 debuggin suppressed? - */ - public boolean isSmapSuppressed() { - return smapSuppressed; - } - - /** - * Set smapSuppressed flag. - */ - public void setSmapSuppressed(boolean smapSuppressed) { - this.smapSuppressed = smapSuppressed; - } - - - /** - * Should SMAP info for JSR45 debugging be dumped to a file? - */ - public boolean isSmapDumped() { - return smapDumped; - } - - /** - * Set smapSuppressed flag. - */ - public void setSmapDumped(boolean smapDumped) { - this.smapDumped = smapDumped; - } - - - /** - * Determines whether text strings are to be generated as char arrays, - * which improves performance in some cases. - * - * @param genStringAsCharArray true if text strings are to be generated as - * char arrays, false otherwise - */ - public void setGenStringAsCharArray(boolean genStringAsCharArray) { - this.genStringAsCharArray = genStringAsCharArray; - } - - /** - * Indicates whether text strings are to be generated as char arrays. - * - * @return true if text strings are to be generated as char arrays, false - * otherwise - */ - public boolean genStringAsCharArray() { - return genStringAsCharArray; - } - - /** - * Sets the class-id value to be sent to Internet Explorer when using - * tags. - * - * @param ieClassId Class-id value - */ - public void setIeClassId(String ieClassId) { - this.ieClassId = ieClassId; - } - - /** - * Gets the class-id value that is sent to Internet Explorer when using - * tags. - * - * @return Class-id value - */ - public String getIeClassId() { - return ieClassId; - } - - public File getScratchDir() { - return scratchDir; - } - - public Class getJspCompilerPlugin() { - // we don't compile, so this is meanlingless - return null; - } - - public String getJspCompilerPath() { - // we don't compile, so this is meanlingless - return null; - } - - /** - * Compiler to use. - */ - public String getCompiler() { - return compiler; - } - - public void setCompiler(String c) { - compiler=c; - } - - /** - * @see Options#getCompilerTargetVM - */ - public String getCompilerTargetVM() { - return compilerTargetVM; - } - - public void setCompilerTargetVM(String vm) { - compilerTargetVM = vm; - } - - /** - * @see Options#getCompilerSourceVM() - */ - public String getCompilerSourceVM() { - return compilerSourceVM; - } - - /** - * @see Options#getCompilerSourceVM() - */ - public void setCompilerSourceVM(String vm) { - compilerSourceVM = vm; - } - - /** - * Should annotations on tags be ignored? - */ - public boolean getIgnoreAnnotations() { - return ignoreAnnotations; - } - - /** - * Should annotations on tags be ignored? - */ - public void setIgnoreAnnotations(boolean ignoreAnnotations) { - this.ignoreAnnotations = ignoreAnnotations; - } - - public TldLocationsCache getTldLocationsCache() { - return tldLocationsCache; - } - - /** - * Returns the encoding to use for - * java files. The default is UTF-8. - * - * @return String The encoding - */ - public String getJavaEncoding() { - return javaEncoding; - } - - /** - * Sets the encoding to use for - * java files. - * - * @param encodingName The name, e.g. "UTF-8" - */ - public void setJavaEncoding(String encodingName) { - javaEncoding = encodingName; - } - - public boolean getFork() { - return false; - } - - public String getClassPath() { - if( classPath != null ) - return classPath; - return System.getProperty("java.class.path"); - } - - public void setClassPath(String s) { - classPath=s; - } - - /** - * Returns the list of file extensions - * that are treated as JSP files. - * - * @return The list of extensions - */ - public List getExtensions() { - return extensions; - } - - /** - * Adds the given file extension to the - * list of extensions handled as JSP files. - * - * @param extension The extension to add, e.g. "myjsp" - */ - protected void addExtension(final String extension) { - if(extension != null) { - if(extensions == null) { - extensions = new Vector(); - } - - extensions.add(extension); - } - } - - /** - * Sets the project. - * - * @param theProject The project - */ - public void setProject(final Project theProject) { - project = theProject; - } - - /** - * Returns the project: may be null if not running - * inside an Ant project. - * - * @return The project - */ - public Project getProject() { - return project; - } - - /** - * Base dir for the webapp. Used to generate class names and resolve - * includes - */ - public void setUriroot( String s ) { - if( s==null ) { - uriRoot = s; - return; - } - try { - uriRoot = resolveFile(s).getCanonicalPath(); - } catch( Exception ex ) { - uriRoot = s; - } - } - - /** - * Parses comma-separated list of JSP files to be processed. If the argument - * is null, nothing is done. - * - *

        Each file is interpreted relative to uriroot, unless it is absolute, - * in which case it must start with uriroot.

        - * - * @param jspFiles Comma-separated list of JSP files to be processed - */ - public void setJspFiles(final String jspFiles) { - if(jspFiles == null) { - return; - } - - StringTokenizer tok = new StringTokenizer(jspFiles, ","); - while (tok.hasMoreTokens()) { - pages.add(tok.nextToken()); - } - } - - /** - * Sets the compile flag. - * - * @param b Flag value - */ - public void setCompile( final boolean b ) { - compile = b; - } - - /** - * Sets the verbosity level. The actual number doesn't - * matter: if it's greater than zero, the verbose flag will - * be true. - * - * @param level Positive means verbose - */ - public void setVerbose( final int level ) { - if (level > 0) { - verbose = true; - showSuccess = true; - listErrors = true; - } - } - - public void setValidateXml( boolean b ) { - org.apache.jasper.xmlparser.ParserUtils.validating=b; - } - - public void setListErrors( boolean b ) { - listErrors = b; - } - - public void setOutputDir( String s ) { - if( s!= null ) { - scratchDir = resolveFile(s).getAbsoluteFile(); - } else { - scratchDir=null; - } - } - - public void setPackage( String p ) { - targetPackage=p; - } - - /** - * Class name of the generated file ( without package ). - * Can only be used if a single file is converted. - * XXX Do we need this feature ? - */ - public void setClassName( String p ) { - targetClassName=p; - } - - /** - * File where we generate a web.xml fragment with the class definitions. - */ - public void setWebXmlFragment( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=INC_WEBXML; - } - - /** - * File where we generate a complete web.xml with the class definitions. - */ - public void setWebXml( String s ) { - webxmlFile=resolveFile(s).getAbsolutePath(); - webxmlLevel=ALL_WEBXML; - } - - public void setAddWebXmlMappings(boolean b) { - addWebXmlMappings = b; - } - - /** - * Set the option that throws an exception in case of a compilation error. - */ - public void setFailOnError(final boolean b) { - failOnError = b; - } - - public boolean getFailOnError() { - return failOnError; - } - - /** - * Obtain JSP configuration informantion specified in web.xml. - */ - public JspConfig getJspConfig() { - return jspConfig; - } - - public TagPluginManager getTagPluginManager() { - return tagPluginManager; - } - - public void generateWebMapping( String file, JspCompilationContext clctxt ) - throws IOException - { - String className = clctxt.getServletClassName(); - String packageName = clctxt.getServletPackageName(); - - String thisServletName; - if ("".equals(packageName)) { - thisServletName = className; - } else { - thisServletName = packageName + '.' + className; - } - - if (servletout != null) { - servletout.write("\n \n "); - servletout.write(thisServletName); - servletout.write("\n "); - servletout.write(thisServletName); - servletout.write("\n \n"); - } - if (mappingout != null) { - mappingout.write("\n \n "); - mappingout.write(thisServletName); - mappingout.write("\n "); - mappingout.write(file.replace('\\', '/')); - mappingout.write("\n \n"); - - } - } - - /** - * Include the generated web.xml inside the webapp's web.xml. - */ - protected void mergeIntoWebXml() throws IOException { - - File webappBase = new File(uriRoot); - File webXml = new File(webappBase, "WEB-INF/web.xml"); - File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); - String insertStartMarker = - Localizer.getMessage("jspc.webinc.insertStart"); - String insertEndMarker = - Localizer.getMessage("jspc.webinc.insertEnd"); - - BufferedReader reader = new BufferedReader(new FileReader(webXml)); - BufferedReader fragmentReader = - new BufferedReader(new FileReader(webxmlFile)); - PrintWriter writer = new PrintWriter(new FileWriter(webXml2)); - - // Insert the and declarations - int pos = -1; - String line = null; - while (true) { - line = reader.readLine(); - if (line == null) { - break; - } - // Skip anything previously generated by JSPC - if (line.indexOf(insertStartMarker) >= 0) { - while (true) { - line = reader.readLine(); - if (line == null) { - return; - } - if (line.indexOf(insertEndMarker) >= 0) { - line = reader.readLine(); - line = reader.readLine(); - if (line == null) { - return; - } - break; - } - } - } - for (int i = 0; i < insertBefore.length; i++) { - pos = line.indexOf(insertBefore[i]); - if (pos >= 0) - break; - } - if (pos >= 0) { - writer.print(line.substring(0, pos)); - break; - } else { - writer.println(line); - } - } - - writer.println(insertStartMarker); - while (true) { - String line2 = fragmentReader.readLine(); - if (line2 == null) { - writer.println(); - break; - } - writer.println(line2); - } - writer.println(insertEndMarker); - writer.println(); - - for (int i = 0; i < pos; i++) { - writer.print(" "); - } - writer.println(line.substring(pos)); - - while (true) { - line = reader.readLine(); - if (line == null) { - break; - } - writer.println(line); - } - writer.close(); - - reader.close(); - fragmentReader.close(); - - FileInputStream fis = new FileInputStream(webXml2); - FileOutputStream fos = new FileOutputStream(webXml); - - byte buf[] = new byte[512]; - while (true) { - int n = fis.read(buf); - if (n < 0) { - break; - } - fos.write(buf, 0, n); - } - - fis.close(); - fos.close(); - - webXml2.delete(); - (new File(webxmlFile)).delete(); - - } - - private void processFile(String file) - throws JasperException - { - ClassLoader originalClassLoader = null; - - try { - // set up a scratch/output dir if none is provided - if (scratchDir == null) { - String temp = System.getProperty("java.io.tmpdir"); - if (temp == null) { - temp = ""; - } - scratchDir = new File(new File(temp).getAbsolutePath()); - } - - String jspUri=file.replace('\\','/'); - JspCompilationContext clctxt = new JspCompilationContext - ( jspUri, false, this, context, null, rctxt ); - - /* Override the defaults */ - if ((targetClassName != null) && (targetClassName.length() > 0)) { - clctxt.setServletClassName(targetClassName); - targetClassName = null; - } - if (targetPackage != null) { - clctxt.setServletPackageName(targetPackage); - } - - originalClassLoader = Thread.currentThread().getContextClassLoader(); - if( loader==null ) { - initClassLoader( clctxt ); - } - Thread.currentThread().setContextClassLoader(loader); - - clctxt.setClassLoader(loader); - clctxt.setClassPath(classPath); - - Compiler clc = clctxt.createCompiler(); - - // If compile is set, generate both .java and .class, if - // .jsp file is newer than .class file; - // Otherwise only generate .java, if .jsp file is newer than - // the .java file - if( clc.isOutDated(compile) ) { - clc.compile(compile, true); - } - - // Generate mapping - generateWebMapping( file, clctxt ); - if ( showSuccess ) { - log.info( "Built File: " + file ); - } - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - log.error(Localizer.getMessage("jspc.error.generalException", - file), - rootCause); - } - - // Bugzilla 35114. - if(getFailOnError()) { - throw je; - } else { - log.error(je.getMessage()); - } - - } catch (Exception e) { - if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { - log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", - e.getMessage())); - } - throw new JasperException(e); - } finally { - if(originalClassLoader != null) { - Thread.currentThread().setContextClassLoader(originalClassLoader); - } - } - } - - /** - * Locate all jsp files in the webapp. Used if no explicit - * jsps are specified. - */ - public void scanFiles( File base ) throws JasperException { - Stack dirs = new Stack(); - dirs.push(base); - - // Make sure default extensions are always included - if ((getExtensions() == null) || (getExtensions().size() < 2)) { - addExtension("jsp"); - addExtension("jspx"); - } - - while (!dirs.isEmpty()) { - String s = dirs.pop().toString(); - File f = new File(s); - if (f.exists() && f.isDirectory()) { - String[] files = f.list(); - String ext; - for (int i = 0; (files != null) && i < files.length; i++) { - File f2 = new File(s, files[i]); - if (f2.isDirectory()) { - dirs.push(f2.getPath()); - } else { - String path = f2.getPath(); - String uri = path.substring(uriRoot.length()); - ext = files[i].substring(files[i].lastIndexOf('.') +1); - if (getExtensions().contains(ext) || - jspConfig.isJspPage(uri)) { - pages.add(path); - } - } - } - } - } - } - - /** - * Executes the compilation. - * - * @throws JasperException If an error occurs - */ - public void execute() throws JasperException { - if(log.isDebugEnabled()) { - log.debug("execute() starting for " + pages.size() + " pages."); - } - - try { - if (uriRoot == null) { - if( pages.size() == 0 ) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.missingTarget")); - } - String firstJsp = (String) pages.get( 0 ); - File firstJspF = new File( firstJsp ); - if (!firstJspF.exists()) { - throw new JasperException( - Localizer.getMessage("jspc.error.fileDoesNotExist", - firstJsp)); - } - locateUriRoot( firstJspF ); - } - - if (uriRoot == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.no_uriroot")); - } - - if( context==null ) { - initServletContext(); - } - - // No explicit pages, we'll process all .jsp in the webapp - if (pages.size() == 0) { - scanFiles( new File( uriRoot )); - } - - File uriRootF = new File(uriRoot); - if (!uriRootF.exists() || !uriRootF.isDirectory()) { - throw new JasperException( - Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); - } - - initWebXml(); - - Iterator iter = pages.iterator(); - while (iter.hasNext()) { - String nextjsp = iter.next().toString(); - File fjsp = new File(nextjsp); - if (!fjsp.isAbsolute()) { - fjsp = new File(uriRootF, nextjsp); - } - if (!fjsp.exists()) { - if (log.isWarnEnabled()) { - log.warn - (Localizer.getMessage - ("jspc.error.fileDoesNotExist", fjsp.toString())); - } - continue; - } - String s = fjsp.getAbsolutePath(); - if (s.startsWith(uriRoot)) { - nextjsp = s.substring(uriRoot.length()); - } - if (nextjsp.startsWith("." + File.separatorChar)) { - nextjsp = nextjsp.substring(2); - } - processFile(nextjsp); - } - - completeWebXml(); - - if (addWebXmlMappings) { - mergeIntoWebXml(); - } - - } catch (IOException ioe) { - throw new JasperException(ioe); - - } catch (JasperException je) { - Throwable rootCause = je; - while (rootCause instanceof JasperException - && ((JasperException) rootCause).getRootCause() != null) { - rootCause = ((JasperException) rootCause).getRootCause(); - } - if (rootCause != je) { - rootCause.printStackTrace(); - } - throw je; - } finally { - if (loader != null) { - LogFactory.release(loader); - } - } - } - - // ==================== Private utility methods ==================== - - private String nextArg() { - if ((argPos >= args.length) - || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { - return null; - } else { - return args[argPos++]; - } - } - - private String nextFile() { - if (fullstop) argPos++; - if (argPos >= args.length) { - return null; - } else { - return args[argPos++]; - } - } - - private void initWebXml() { - try { - if (webxmlLevel >= INC_WEBXML) { - File fmapings = new File(webxmlFile); - mapout = new FileWriter(fmapings); - servletout = new CharArrayWriter(); - mappingout = new CharArrayWriter(); - } else { - mapout = null; - servletout = null; - mappingout = null; - } - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.header")); - mapout.flush(); - } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.header")); - mapout.flush(); - } - } catch (IOException ioe) { - mapout = null; - servletout = null; - mappingout = null; - } - } - - private void completeWebXml() { - if (mapout != null) { - try { - servletout.writeTo(mapout); - mappingout.writeTo(mapout); - if (webxmlLevel >= ALL_WEBXML) { - mapout.write(Localizer.getMessage("jspc.webxml.footer")); - } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { - mapout.write(Localizer.getMessage("jspc.webinc.footer")); - } - mapout.close(); - } catch (IOException ioe) { - // noting to do if it fails since we are done with it - } - } - } - - private void initServletContext() { - try { - context =new JspCServletContext - (new PrintWriter(System.out), - new URL("file:" + uriRoot.replace('\\','/') + '/')); - tldLocationsCache = new TldLocationsCache(context, true); - } catch (MalformedURLException me) { - System.out.println("**" + me); - } - rctxt = new JspRuntimeContext(context, this); - jspConfig = new JspConfig(context); - tagPluginManager = new TagPluginManager(context); - } - - /** - * Initializes the classloader as/if needed for the given - * compilation context. - * - * @param clctxt The compilation context - * @throws IOException If an error occurs - */ - private void initClassLoader(JspCompilationContext clctxt) - throws IOException { - - classPath = getClassPath(); - - ClassLoader jspcLoader = getClass().getClassLoader(); - if (jspcLoader instanceof AntClassLoader) { - classPath += File.pathSeparator - + ((AntClassLoader) jspcLoader).getClasspath(); - } - - // Turn the classPath into URLs - ArrayList urls = new ArrayList(); - StringTokenizer tokenizer = new StringTokenizer(classPath, - File.pathSeparator); - while (tokenizer.hasMoreTokens()) { - String path = tokenizer.nextToken(); - try { - File libFile = new File(path); - urls.add(libFile.toURL()); - } catch (IOException ioe) { - // Failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak uot - throw new RuntimeException(ioe.toString()); - } - } - - File webappBase = new File(uriRoot); - if (webappBase.exists()) { - File classes = new File(webappBase, "/WEB-INF/classes"); - try { - if (classes.exists()) { - classPath = classPath + File.pathSeparator - + classes.getCanonicalPath(); - urls.add(classes.getCanonicalFile().toURL()); - } - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - File lib = new File(webappBase, "/WEB-INF/lib"); - if (lib.exists() && lib.isDirectory()) { - String[] libs = lib.list(); - for (int i = 0; i < libs.length; i++) { - if( libs[i].length() <5 ) continue; - String ext=libs[i].substring( libs[i].length() - 4 ); - if (! ".jar".equalsIgnoreCase(ext)) { - if (".tld".equalsIgnoreCase(ext)) { - log.warn("TLD files should not be placed in " - + "/WEB-INF/lib"); - } - continue; - } - try { - File libFile = new File(lib, libs[i]); - classPath = classPath + File.pathSeparator - + libFile.getAbsolutePath(); - urls.add(libFile.getAbsoluteFile().toURL()); - } catch (IOException ioe) { - // failing a toCanonicalPath on a file that - // exists() should be a JVM regression test, - // therefore we have permission to freak out - throw new RuntimeException(ioe.toString()); - } - } - } - } - - // What is this ?? - urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); - - URL urlsA[]=new URL[urls.size()]; - urls.toArray(urlsA); - loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); - - } - - /** - * Find the WEB-INF dir by looking up in the directory tree. - * This is used if no explicit docbase is set, but only files. - * XXX Maybe we should require the docbase. - */ - private void locateUriRoot( File f ) { - String tUriBase = uriBase; - if (tUriBase == null) { - tUriBase = "/"; - } - try { - if (f.exists()) { - f = new File(f.getAbsolutePath()); - while (f != null) { - File g = new File(f, "WEB-INF"); - if (g.exists() && g.isDirectory()) { - uriRoot = f.getCanonicalPath(); - uriBase = tUriBase; - if (log.isInfoEnabled()) { - log.info(Localizer.getMessage( - "jspc.implicit.uriRoot", - uriRoot)); - } - break; - } - if (f.exists() && f.isDirectory()) { - tUriBase = "/" + f.getName() + "/" + tUriBase; - } - - String fParent = f.getParent(); - if (fParent == null) { - break; - } else { - f = new File(fParent); - } - - // If there is no acceptible candidate, uriRoot will - // remain null to indicate to the CompilerContext to - // use the current working/user dir. - } - - if (uriRoot != null) { - File froot = new File(uriRoot); - uriRoot = froot.getCanonicalPath(); - } - } - } catch (IOException ioe) { - // since this is an optional default and a null value - // for uriRoot has a non-error meaning, we can just - // pass straight through - } - } - - /** - * Resolves the relative or absolute pathname correctly - * in both Ant and command-line situations. If Ant launched - * us, we should use the basedir of the current project - * to resolve relative paths. - * - * See Bugzilla 35571. - * - * @param s The file - * @return The file resolved - */ - protected File resolveFile(final String s) { - if(getProject() == null) { - // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3 - return FileUtils.newFileUtils().resolveFile(null, s); - } else { - return FileUtils.newFileUtils().resolveFile(getProject().getBaseDir(), s); - } - } -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.BufferedReader; +import java.io.CharArrayWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Writer; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.HashMap; +import java.util.Stack; +import java.util.StringTokenizer; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; +import org.apache.jasper.servlet.JspCServletContext; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.util.FileUtils; + +/** + * Shell for the jspc compiler. Handles all options associated with the + * command line and creates compilation contexts which it then compiles + * according to the specified options. + * + * This version can process files from a _single_ webapp at once, i.e. + * a single docbase can be specified. + * + * It can be used as an Ant task using: + *
        + *   <taskdef classname="org.apache.jasper.JspC" name="jasper2" >
        + *      <classpath>
        + *          <pathelement location="${java.home}/../lib/tools.jar"/>
        + *          <fileset dir="${ENV.CATALINA_HOME}/server/lib">
        + *              <include name="*.jar"/>
        + *          </fileset>
        + *          <fileset dir="${ENV.CATALINA_HOME}/common/lib">
        + *              <include name="*.jar"/>
        + *          </fileset>
        + *          <path refid="myjars"/>
        + *       </classpath>
        + *  </taskdef>
        + *
        + *  <jasper2 verbose="0"
        + *           package="my.package"
        + *           uriroot="${webapps.dir}/${webapp.name}"
        + *           webXmlFragment="${build.dir}/generated_web.xml"
        + *           outputDir="${webapp.dir}/${webapp.name}/WEB-INF/src/my/package" />
        + * 
        + * + * @author Danno Ferrin + * @author Pierre Delisle + * @author Costin Manolache + * @author Yoav Shapira + */ +public class JspC implements Options { + + public static final String DEFAULT_IE_CLASS_ID = + "clsid:8AD9C840-044E-11D1-B3E9-00805F499D93"; + + // Logger + private static Log log = LogFactory.getLog(JspC.class); + + private static final String SWITCH_VERBOSE = "-v"; + private static final String SWITCH_HELP = "-help"; + private static final String SWITCH_QUIET = "-q"; + private static final String SWITCH_OUTPUT_DIR = "-d"; + private static final String SWITCH_IE_CLASS_ID = "-ieplugin"; + private static final String SWITCH_PACKAGE_NAME = "-p"; + private static final String SWITCH_CACHE = "-cache"; + private static final String SWITCH_CLASS_NAME = "-c"; + private static final String SWITCH_FULL_STOP = "--"; + private static final String SWITCH_COMPILE = "-compile"; + private static final String SWITCH_SOURCE = "-source"; + private static final String SWITCH_TARGET = "-target"; + private static final String SWITCH_URI_BASE = "-uribase"; + private static final String SWITCH_URI_ROOT = "-uriroot"; + private static final String SWITCH_FILE_WEBAPP = "-webapp"; + private static final String SWITCH_WEBAPP_INC = "-webinc"; + private static final String SWITCH_WEBAPP_XML = "-webxml"; + private static final String SWITCH_MAPPED = "-mapped"; + private static final String SWITCH_XPOWERED_BY = "-xpoweredBy"; + private static final String SWITCH_TRIM_SPACES = "-trimSpaces"; + private static final String SWITCH_CLASSPATH = "-classpath"; + private static final String SWITCH_DIE = "-die"; + private static final String SWITCH_POOLING = "-poolingEnabled"; + private static final String SWITCH_ENCODING = "-javaEncoding"; + private static final String SWITCH_SMAP = "-smap"; + private static final String SWITCH_DUMP_SMAP = "-dumpsmap"; + + private static final String SHOW_SUCCESS ="-s"; + private static final String LIST_ERRORS = "-l"; + private static final int NO_WEBXML = 0; + private static final int INC_WEBXML = 10; + private static final int ALL_WEBXML = 20; + private static final int DEFAULT_DIE_LEVEL = 1; + private static final int NO_DIE_LEVEL = 0; + + private static final String[] insertBefore = + { "", "", "", + "", "", "", "", + "", "", "", + "", "", "", "", + "" }; + + private static int die; + private String classPath = null; + private URLClassLoader loader = null; + private boolean trimSpaces = false; + private boolean genStringAsCharArray = false; + private boolean xpoweredBy; + private boolean mappedFile = false; + private boolean poolingEnabled = true; + private File scratchDir; + private String ieClassId = DEFAULT_IE_CLASS_ID; + private String targetPackage; + private String targetClassName; + private String uriBase; + private String uriRoot; + private Project project; + private int dieLevel; + private boolean helpNeeded = false; + private boolean compile = false; + private boolean smapSuppressed = true; + private boolean smapDumped = false; + private boolean caching = true; + private boolean ignoreAnnotations = false; + private Map cache = new HashMap(); + + private String compiler = null; + + private String compilerTargetVM = "1.4"; + private String compilerSourceVM = "1.4"; + + private boolean classDebugInfo = true; + + /** + * Throw an exception if there's a compilation error, or swallow it. + * Default is true to preserve old behavior. + */ + private boolean failOnError = true; + + /** + * The file extensions to be handled as JSP files. + * Default list is .jsp and .jspx. + */ + private List extensions; + + /** + * The pages. + */ + private List pages = new Vector(); + + /** + * Needs better documentation, this data member does. + * True by default. + */ + private boolean errorOnUseBeanInvalidClassAttribute = true; + + /** + * The java file encoding. Default + * is UTF-8. Added per bugzilla 19622. + */ + private String javaEncoding = "UTF-8"; + + // Generation of web.xml fragments + private String webxmlFile; + private int webxmlLevel; + private boolean addWebXmlMappings = false; + + private Writer mapout; + private CharArrayWriter servletout; + private CharArrayWriter mappingout; + + /** + * The servlet context. + */ + private JspCServletContext context; + + /** + * The runtime context. + * Maintain a dummy JspRuntimeContext for compiling tag files. + */ + private JspRuntimeContext rctxt; + + /** + * Cache for the TLD locations + */ + private TldLocationsCache tldLocationsCache = null; + + private JspConfig jspConfig = null; + private TagPluginManager tagPluginManager = null; + + private boolean verbose = false; + private boolean listErrors = false; + private boolean showSuccess = false; + private int argPos; + private boolean fullstop = false; + private String args[]; + + public static void main(String arg[]) { + if (arg.length == 0) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + try { + JspC jspc = new JspC(); + jspc.setArgs(arg); + if (jspc.helpNeeded) { + System.out.println(Localizer.getMessage("jspc.usage")); + } else { + jspc.execute(); + } + } catch (JasperException je) { + System.err.println(je); + //System.err.println(je.getMessage()); + if (die != NO_DIE_LEVEL) { + System.exit(die); + } + } + } + } + + public void setArgs(String[] arg) throws JasperException { + args = arg; + String tok; + + dieLevel = NO_DIE_LEVEL; + die = dieLevel; + + while ((tok = nextArg()) != null) { + if (tok.equals(SWITCH_VERBOSE)) { + verbose = true; + showSuccess = true; + listErrors = true; + } else if (tok.equals(SWITCH_OUTPUT_DIR)) { + tok = nextArg(); + setOutputDir( tok ); + } else if (tok.equals(SWITCH_PACKAGE_NAME)) { + targetPackage = nextArg(); + } else if (tok.equals(SWITCH_COMPILE)) { + compile=true; + } else if (tok.equals(SWITCH_CLASS_NAME)) { + targetClassName = nextArg(); + } else if (tok.equals(SWITCH_URI_BASE)) { + uriBase=nextArg(); + } else if (tok.equals(SWITCH_URI_ROOT)) { + setUriroot( nextArg()); + } else if (tok.equals(SWITCH_FILE_WEBAPP)) { + setUriroot( nextArg()); + } else if ( tok.equals( SHOW_SUCCESS ) ) { + showSuccess = true; + } else if ( tok.equals( LIST_ERRORS ) ) { + listErrors = true; + } else if (tok.equals(SWITCH_WEBAPP_INC)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = INC_WEBXML; + } + } else if (tok.equals(SWITCH_WEBAPP_XML)) { + webxmlFile = nextArg(); + if (webxmlFile != null) { + webxmlLevel = ALL_WEBXML; + } + } else if (tok.equals(SWITCH_MAPPED)) { + mappedFile = true; + } else if (tok.equals(SWITCH_XPOWERED_BY)) { + xpoweredBy = true; + } else if (tok.equals(SWITCH_TRIM_SPACES)) { + setTrimSpaces(true); + } else if (tok.equals(SWITCH_CACHE)) { + tok = nextArg(); + if ("false".equals(tok)) { + caching = false; + } else { + caching = true; + } + } else if (tok.equals(SWITCH_CLASSPATH)) { + setClassPath(nextArg()); + } else if (tok.startsWith(SWITCH_DIE)) { + try { + dieLevel = Integer.parseInt( + tok.substring(SWITCH_DIE.length())); + } catch (NumberFormatException nfe) { + dieLevel = DEFAULT_DIE_LEVEL; + } + die = dieLevel; + } else if (tok.equals(SWITCH_HELP)) { + helpNeeded = true; + } else if (tok.equals(SWITCH_POOLING)) { + tok = nextArg(); + if ("false".equals(tok)) { + poolingEnabled = false; + } else { + poolingEnabled = true; + } + } else if (tok.equals(SWITCH_ENCODING)) { + setJavaEncoding(nextArg()); + } else if (tok.equals(SWITCH_SOURCE)) { + setCompilerSourceVM(nextArg()); + } else if (tok.equals(SWITCH_TARGET)) { + setCompilerTargetVM(nextArg()); + } else if (tok.equals(SWITCH_SMAP)) { + smapSuppressed = false; + } else if (tok.equals(SWITCH_DUMP_SMAP)) { + smapDumped = true; + } else { + if (tok.startsWith("-")) { + throw new JasperException("Unrecognized option: " + tok + + ". Use -help for help."); + } + if (!fullstop) { + argPos--; + } + // Start treating the rest as JSP Pages + break; + } + } + + // Add all extra arguments to the list of files + while( true ) { + String file = nextFile(); + if( file==null ) { + break; + } + pages.add( file ); + } + } + + public boolean getKeepGenerated() { + // isn't this why we are running jspc? + return true; + } + + public boolean getTrimSpaces() { + return trimSpaces; + } + + public void setTrimSpaces(boolean ts) { + this.trimSpaces = ts; + } + + public boolean isPoolingEnabled() { + return poolingEnabled; + } + + public void setPoolingEnabled(boolean poolingEnabled) { + this.poolingEnabled = poolingEnabled; + } + + public boolean isXpoweredBy() { + return xpoweredBy; + } + + public void setXpoweredBy(boolean xpoweredBy) { + this.xpoweredBy = xpoweredBy; + } + + public boolean getErrorOnUseBeanInvalidClassAttribute() { + return errorOnUseBeanInvalidClassAttribute; + } + + public void setErrorOnUseBeanInvalidClassAttribute(boolean b) { + errorOnUseBeanInvalidClassAttribute = b; + } + + public int getTagPoolSize() { + return Constants.MAX_POOL_SIZE; + } + + /** + * Are we supporting HTML mapped servlets? + */ + public boolean getMappedFile() { + return mappedFile; + } + + // Off-line compiler, no need for security manager + public Object getProtectionDomain() { + return null; + } + + public boolean getSendErrorToClient() { + // implied send to System.err + return true; + } + + public void setClassDebugInfo( boolean b ) { + classDebugInfo=b; + } + + public boolean getClassDebugInfo() { + // compile with debug info + return classDebugInfo; + } + + /** + * @see Options#isCaching() + */ + public boolean isCaching() { + return caching; + } + + /** + * @see Options#isCaching() + */ + public void setCaching(boolean caching) { + this.caching = caching; + } + + /** + * @see Options#getCache() + */ + public Map getCache() { + return cache; + } + + /** + * Background compilation check intervals in seconds + */ + public int getCheckInterval() { + return 0; + } + + /** + * Modification test interval. + */ + public int getModificationTestInterval() { + return 0; + } + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment() { + return false; + } + + /** + * Is the generation of SMAP info for JSR45 debuggin suppressed? + */ + public boolean isSmapSuppressed() { + return smapSuppressed; + } + + /** + * Set smapSuppressed flag. + */ + public void setSmapSuppressed(boolean smapSuppressed) { + this.smapSuppressed = smapSuppressed; + } + + + /** + * Should SMAP info for JSR45 debugging be dumped to a file? + */ + public boolean isSmapDumped() { + return smapDumped; + } + + /** + * Set smapSuppressed flag. + */ + public void setSmapDumped(boolean smapDumped) { + this.smapDumped = smapDumped; + } + + + /** + * Determines whether text strings are to be generated as char arrays, + * which improves performance in some cases. + * + * @param genStringAsCharArray true if text strings are to be generated as + * char arrays, false otherwise + */ + public void setGenStringAsCharArray(boolean genStringAsCharArray) { + this.genStringAsCharArray = genStringAsCharArray; + } + + /** + * Indicates whether text strings are to be generated as char arrays. + * + * @return true if text strings are to be generated as char arrays, false + * otherwise + */ + public boolean genStringAsCharArray() { + return genStringAsCharArray; + } + + /** + * Sets the class-id value to be sent to Internet Explorer when using + * tags. + * + * @param ieClassId Class-id value + */ + public void setIeClassId(String ieClassId) { + this.ieClassId = ieClassId; + } + + /** + * Gets the class-id value that is sent to Internet Explorer when using + * tags. + * + * @return Class-id value + */ + public String getIeClassId() { + return ieClassId; + } + + public File getScratchDir() { + return scratchDir; + } + + public Class getJspCompilerPlugin() { + // we don't compile, so this is meanlingless + return null; + } + + public String getJspCompilerPath() { + // we don't compile, so this is meanlingless + return null; + } + + /** + * Compiler to use. + */ + public String getCompiler() { + return compiler; + } + + public void setCompiler(String c) { + compiler=c; + } + + /** + * @see Options#getCompilerTargetVM + */ + public String getCompilerTargetVM() { + return compilerTargetVM; + } + + public void setCompilerTargetVM(String vm) { + compilerTargetVM = vm; + } + + /** + * @see Options#getCompilerSourceVM() + */ + public String getCompilerSourceVM() { + return compilerSourceVM; + } + + /** + * @see Options#getCompilerSourceVM() + */ + public void setCompilerSourceVM(String vm) { + compilerSourceVM = vm; + } + + /** + * Should annotations on tags be ignored? + */ + public boolean getIgnoreAnnotations() { + return ignoreAnnotations; + } + + /** + * Should annotations on tags be ignored? + */ + public void setIgnoreAnnotations(boolean ignoreAnnotations) { + this.ignoreAnnotations = ignoreAnnotations; + } + + public TldLocationsCache getTldLocationsCache() { + return tldLocationsCache; + } + + /** + * Returns the encoding to use for + * java files. The default is UTF-8. + * + * @return String The encoding + */ + public String getJavaEncoding() { + return javaEncoding; + } + + /** + * Sets the encoding to use for + * java files. + * + * @param encodingName The name, e.g. "UTF-8" + */ + public void setJavaEncoding(String encodingName) { + javaEncoding = encodingName; + } + + public boolean getFork() { + return false; + } + + public String getClassPath() { + if( classPath != null ) + return classPath; + return System.getProperty("java.class.path"); + } + + public void setClassPath(String s) { + classPath=s; + } + + /** + * Returns the list of file extensions + * that are treated as JSP files. + * + * @return The list of extensions + */ + public List getExtensions() { + return extensions; + } + + /** + * Adds the given file extension to the + * list of extensions handled as JSP files. + * + * @param extension The extension to add, e.g. "myjsp" + */ + protected void addExtension(final String extension) { + if(extension != null) { + if(extensions == null) { + extensions = new Vector(); + } + + extensions.add(extension); + } + } + + /** + * Sets the project. + * + * @param theProject The project + */ + public void setProject(final Project theProject) { + project = theProject; + } + + /** + * Returns the project: may be null if not running + * inside an Ant project. + * + * @return The project + */ + public Project getProject() { + return project; + } + + /** + * Base dir for the webapp. Used to generate class names and resolve + * includes + */ + public void setUriroot( String s ) { + if( s==null ) { + uriRoot = s; + return; + } + try { + uriRoot = resolveFile(s).getCanonicalPath(); + } catch( Exception ex ) { + uriRoot = s; + } + } + + /** + * Parses comma-separated list of JSP files to be processed. If the argument + * is null, nothing is done. + * + *

        Each file is interpreted relative to uriroot, unless it is absolute, + * in which case it must start with uriroot.

        + * + * @param jspFiles Comma-separated list of JSP files to be processed + */ + public void setJspFiles(final String jspFiles) { + if(jspFiles == null) { + return; + } + + StringTokenizer tok = new StringTokenizer(jspFiles, ","); + while (tok.hasMoreTokens()) { + pages.add(tok.nextToken()); + } + } + + /** + * Sets the compile flag. + * + * @param b Flag value + */ + public void setCompile( final boolean b ) { + compile = b; + } + + /** + * Sets the verbosity level. The actual number doesn't + * matter: if it's greater than zero, the verbose flag will + * be true. + * + * @param level Positive means verbose + */ + public void setVerbose( final int level ) { + if (level > 0) { + verbose = true; + showSuccess = true; + listErrors = true; + } + } + + public void setValidateXml( boolean b ) { + org.apache.jasper.xmlparser.ParserUtils.validating=b; + } + + public void setListErrors( boolean b ) { + listErrors = b; + } + + public void setOutputDir( String s ) { + if( s!= null ) { + scratchDir = resolveFile(s).getAbsoluteFile(); + } else { + scratchDir=null; + } + } + + public void setPackage( String p ) { + targetPackage=p; + } + + /** + * Class name of the generated file ( without package ). + * Can only be used if a single file is converted. + * XXX Do we need this feature ? + */ + public void setClassName( String p ) { + targetClassName=p; + } + + /** + * File where we generate a web.xml fragment with the class definitions. + */ + public void setWebXmlFragment( String s ) { + webxmlFile=resolveFile(s).getAbsolutePath(); + webxmlLevel=INC_WEBXML; + } + + /** + * File where we generate a complete web.xml with the class definitions. + */ + public void setWebXml( String s ) { + webxmlFile=resolveFile(s).getAbsolutePath(); + webxmlLevel=ALL_WEBXML; + } + + public void setAddWebXmlMappings(boolean b) { + addWebXmlMappings = b; + } + + /** + * Set the option that throws an exception in case of a compilation error. + */ + public void setFailOnError(final boolean b) { + failOnError = b; + } + + public boolean getFailOnError() { + return failOnError; + } + + /** + * Obtain JSP configuration informantion specified in web.xml. + */ + public JspConfig getJspConfig() { + return jspConfig; + } + + public TagPluginManager getTagPluginManager() { + return tagPluginManager; + } + + public void generateWebMapping( String file, JspCompilationContext clctxt ) + throws IOException + { + String className = clctxt.getServletClassName(); + String packageName = clctxt.getServletPackageName(); + + String thisServletName; + if ("".equals(packageName)) { + thisServletName = className; + } else { + thisServletName = packageName + '.' + className; + } + + if (servletout != null) { + servletout.write("\n \n "); + servletout.write(thisServletName); + servletout.write("\n "); + servletout.write(thisServletName); + servletout.write("\n \n"); + } + if (mappingout != null) { + mappingout.write("\n \n "); + mappingout.write(thisServletName); + mappingout.write("\n "); + mappingout.write(file.replace('\\', '/')); + mappingout.write("\n \n"); + + } + } + + /** + * Include the generated web.xml inside the webapp's web.xml. + */ + protected void mergeIntoWebXml() throws IOException { + + File webappBase = new File(uriRoot); + File webXml = new File(webappBase, "WEB-INF/web.xml"); + File webXml2 = new File(webappBase, "WEB-INF/web2.xml"); + String insertStartMarker = + Localizer.getMessage("jspc.webinc.insertStart"); + String insertEndMarker = + Localizer.getMessage("jspc.webinc.insertEnd"); + + BufferedReader reader = new BufferedReader(new FileReader(webXml)); + BufferedReader fragmentReader = + new BufferedReader(new FileReader(webxmlFile)); + PrintWriter writer = new PrintWriter(new FileWriter(webXml2)); + + // Insert the and declarations + int pos = -1; + String line = null; + while (true) { + line = reader.readLine(); + if (line == null) { + break; + } + // Skip anything previously generated by JSPC + if (line.indexOf(insertStartMarker) >= 0) { + while (true) { + line = reader.readLine(); + if (line == null) { + return; + } + if (line.indexOf(insertEndMarker) >= 0) { + line = reader.readLine(); + line = reader.readLine(); + if (line == null) { + return; + } + break; + } + } + } + for (int i = 0; i < insertBefore.length; i++) { + pos = line.indexOf(insertBefore[i]); + if (pos >= 0) + break; + } + if (pos >= 0) { + writer.print(line.substring(0, pos)); + break; + } else { + writer.println(line); + } + } + + writer.println(insertStartMarker); + while (true) { + String line2 = fragmentReader.readLine(); + if (line2 == null) { + writer.println(); + break; + } + writer.println(line2); + } + writer.println(insertEndMarker); + writer.println(); + + for (int i = 0; i < pos; i++) { + writer.print(" "); + } + writer.println(line.substring(pos)); + + while (true) { + line = reader.readLine(); + if (line == null) { + break; + } + writer.println(line); + } + writer.close(); + + reader.close(); + fragmentReader.close(); + + FileInputStream fis = new FileInputStream(webXml2); + FileOutputStream fos = new FileOutputStream(webXml); + + byte buf[] = new byte[512]; + while (true) { + int n = fis.read(buf); + if (n < 0) { + break; + } + fos.write(buf, 0, n); + } + + fis.close(); + fos.close(); + + webXml2.delete(); + (new File(webxmlFile)).delete(); + + } + + private void processFile(String file) + throws JasperException + { + ClassLoader originalClassLoader = null; + + try { + // set up a scratch/output dir if none is provided + if (scratchDir == null) { + String temp = System.getProperty("java.io.tmpdir"); + if (temp == null) { + temp = ""; + } + scratchDir = new File(new File(temp).getAbsolutePath()); + } + + String jspUri=file.replace('\\','/'); + JspCompilationContext clctxt = new JspCompilationContext + ( jspUri, false, this, context, null, rctxt ); + + /* Override the defaults */ + if ((targetClassName != null) && (targetClassName.length() > 0)) { + clctxt.setServletClassName(targetClassName); + targetClassName = null; + } + if (targetPackage != null) { + clctxt.setServletPackageName(targetPackage); + } + + originalClassLoader = Thread.currentThread().getContextClassLoader(); + if( loader==null ) { + initClassLoader( clctxt ); + } + Thread.currentThread().setContextClassLoader(loader); + + clctxt.setClassLoader(loader); + clctxt.setClassPath(classPath); + + Compiler clc = clctxt.createCompiler(); + + // If compile is set, generate both .java and .class, if + // .jsp file is newer than .class file; + // Otherwise only generate .java, if .jsp file is newer than + // the .java file + if( clc.isOutDated(compile) ) { + clc.compile(compile, true); + } + + // Generate mapping + generateWebMapping( file, clctxt ); + if ( showSuccess ) { + log.info( "Built File: " + file ); + } + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException + && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + log.error(Localizer.getMessage("jspc.error.generalException", + file), + rootCause); + } + + // Bugzilla 35114. + if(getFailOnError()) { + throw je; + } else { + log.error(je.getMessage()); + } + + } catch (Exception e) { + if ((e instanceof FileNotFoundException) && log.isWarnEnabled()) { + log.warn(Localizer.getMessage("jspc.error.fileDoesNotExist", + e.getMessage())); + } + throw new JasperException(e); + } finally { + if(originalClassLoader != null) { + Thread.currentThread().setContextClassLoader(originalClassLoader); + } + } + } + + /** + * Locate all jsp files in the webapp. Used if no explicit + * jsps are specified. + */ + public void scanFiles( File base ) throws JasperException { + Stack dirs = new Stack(); + dirs.push(base); + + // Make sure default extensions are always included + if ((getExtensions() == null) || (getExtensions().size() < 2)) { + addExtension("jsp"); + addExtension("jspx"); + } + + while (!dirs.isEmpty()) { + String s = dirs.pop().toString(); + File f = new File(s); + if (f.exists() && f.isDirectory()) { + String[] files = f.list(); + String ext; + for (int i = 0; (files != null) && i < files.length; i++) { + File f2 = new File(s, files[i]); + if (f2.isDirectory()) { + dirs.push(f2.getPath()); + } else { + String path = f2.getPath(); + String uri = path.substring(uriRoot.length()); + ext = files[i].substring(files[i].lastIndexOf('.') +1); + if (getExtensions().contains(ext) || + jspConfig.isJspPage(uri)) { + pages.add(path); + } + } + } + } + } + } + + /** + * Executes the compilation. + * + * @throws JasperException If an error occurs + */ + public void execute() throws JasperException { + if(log.isDebugEnabled()) { + log.debug("execute() starting for " + pages.size() + " pages."); + } + + try { + if (uriRoot == null) { + if( pages.size() == 0 ) { + throw new JasperException( + Localizer.getMessage("jsp.error.jspc.missingTarget")); + } + String firstJsp = (String) pages.get( 0 ); + File firstJspF = new File( firstJsp ); + if (!firstJspF.exists()) { + throw new JasperException( + Localizer.getMessage("jspc.error.fileDoesNotExist", + firstJsp)); + } + locateUriRoot( firstJspF ); + } + + if (uriRoot == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.jspc.no_uriroot")); + } + + if( context==null ) { + initServletContext(); + } + + // No explicit pages, we'll process all .jsp in the webapp + if (pages.size() == 0) { + scanFiles( new File( uriRoot )); + } + + File uriRootF = new File(uriRoot); + if (!uriRootF.exists() || !uriRootF.isDirectory()) { + throw new JasperException( + Localizer.getMessage("jsp.error.jspc.uriroot_not_dir")); + } + + initWebXml(); + + Iterator iter = pages.iterator(); + while (iter.hasNext()) { + String nextjsp = iter.next().toString(); + File fjsp = new File(nextjsp); + if (!fjsp.isAbsolute()) { + fjsp = new File(uriRootF, nextjsp); + } + if (!fjsp.exists()) { + if (log.isWarnEnabled()) { + log.warn + (Localizer.getMessage + ("jspc.error.fileDoesNotExist", fjsp.toString())); + } + continue; + } + String s = fjsp.getAbsolutePath(); + if (s.startsWith(uriRoot)) { + nextjsp = s.substring(uriRoot.length()); + } + if (nextjsp.startsWith("." + File.separatorChar)) { + nextjsp = nextjsp.substring(2); + } + processFile(nextjsp); + } + + completeWebXml(); + + if (addWebXmlMappings) { + mergeIntoWebXml(); + } + + } catch (IOException ioe) { + throw new JasperException(ioe); + + } catch (JasperException je) { + Throwable rootCause = je; + while (rootCause instanceof JasperException + && ((JasperException) rootCause).getRootCause() != null) { + rootCause = ((JasperException) rootCause).getRootCause(); + } + if (rootCause != je) { + rootCause.printStackTrace(); + } + throw je; + } finally { + if (loader != null) { + LogFactory.release(loader); + } + } + } + + // ==================== Private utility methods ==================== + + private String nextArg() { + if ((argPos >= args.length) + || (fullstop = SWITCH_FULL_STOP.equals(args[argPos]))) { + return null; + } else { + return args[argPos++]; + } + } + + private String nextFile() { + if (fullstop) argPos++; + if (argPos >= args.length) { + return null; + } else { + return args[argPos++]; + } + } + + private void initWebXml() { + try { + if (webxmlLevel >= INC_WEBXML) { + File fmapings = new File(webxmlFile); + mapout = new FileWriter(fmapings); + servletout = new CharArrayWriter(); + mappingout = new CharArrayWriter(); + } else { + mapout = null; + servletout = null; + mappingout = null; + } + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.header")); + mapout.flush(); + } else if ((webxmlLevel>= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.header")); + mapout.flush(); + } + } catch (IOException ioe) { + mapout = null; + servletout = null; + mappingout = null; + } + } + + private void completeWebXml() { + if (mapout != null) { + try { + servletout.writeTo(mapout); + mappingout.writeTo(mapout); + if (webxmlLevel >= ALL_WEBXML) { + mapout.write(Localizer.getMessage("jspc.webxml.footer")); + } else if ((webxmlLevel >= INC_WEBXML) && !addWebXmlMappings) { + mapout.write(Localizer.getMessage("jspc.webinc.footer")); + } + mapout.close(); + } catch (IOException ioe) { + // noting to do if it fails since we are done with it + } + } + } + + private void initServletContext() { + try { + context =new JspCServletContext + (new PrintWriter(System.out), + new URL("file:" + uriRoot.replace('\\','/') + '/')); + tldLocationsCache = new TldLocationsCache(context, true); + } catch (MalformedURLException me) { + System.out.println("**" + me); + } + rctxt = new JspRuntimeContext(context, this); + jspConfig = new JspConfig(context); + tagPluginManager = new TagPluginManager(context); + } + + /** + * Initializes the classloader as/if needed for the given + * compilation context. + * + * @param clctxt The compilation context + * @throws IOException If an error occurs + */ + private void initClassLoader(JspCompilationContext clctxt) + throws IOException { + + classPath = getClassPath(); + + ClassLoader jspcLoader = getClass().getClassLoader(); + if (jspcLoader instanceof AntClassLoader) { + classPath += File.pathSeparator + + ((AntClassLoader) jspcLoader).getClasspath(); + } + + // Turn the classPath into URLs + ArrayList urls = new ArrayList(); + StringTokenizer tokenizer = new StringTokenizer(classPath, + File.pathSeparator); + while (tokenizer.hasMoreTokens()) { + String path = tokenizer.nextToken(); + try { + File libFile = new File(path); + urls.add(libFile.toURL()); + } catch (IOException ioe) { + // Failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak uot + throw new RuntimeException(ioe.toString()); + } + } + + File webappBase = new File(uriRoot); + if (webappBase.exists()) { + File classes = new File(webappBase, "/WEB-INF/classes"); + try { + if (classes.exists()) { + classPath = classPath + File.pathSeparator + + classes.getCanonicalPath(); + urls.add(classes.getCanonicalFile().toURL()); + } + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + File lib = new File(webappBase, "/WEB-INF/lib"); + if (lib.exists() && lib.isDirectory()) { + String[] libs = lib.list(); + for (int i = 0; i < libs.length; i++) { + if( libs[i].length() <5 ) continue; + String ext=libs[i].substring( libs[i].length() - 4 ); + if (! ".jar".equalsIgnoreCase(ext)) { + if (".tld".equalsIgnoreCase(ext)) { + log.warn("TLD files should not be placed in " + + "/WEB-INF/lib"); + } + continue; + } + try { + File libFile = new File(lib, libs[i]); + classPath = classPath + File.pathSeparator + + libFile.getAbsolutePath(); + urls.add(libFile.getAbsoluteFile().toURL()); + } catch (IOException ioe) { + // failing a toCanonicalPath on a file that + // exists() should be a JVM regression test, + // therefore we have permission to freak out + throw new RuntimeException(ioe.toString()); + } + } + } + } + + // What is this ?? + urls.add(new File(clctxt.getRealPath("/")).getCanonicalFile().toURL()); + + URL urlsA[]=new URL[urls.size()]; + urls.toArray(urlsA); + loader = new URLClassLoader(urlsA, this.getClass().getClassLoader()); + + } + + /** + * Find the WEB-INF dir by looking up in the directory tree. + * This is used if no explicit docbase is set, but only files. + * XXX Maybe we should require the docbase. + */ + private void locateUriRoot( File f ) { + String tUriBase = uriBase; + if (tUriBase == null) { + tUriBase = "/"; + } + try { + if (f.exists()) { + f = new File(f.getAbsolutePath()); + while (f != null) { + File g = new File(f, "WEB-INF"); + if (g.exists() && g.isDirectory()) { + uriRoot = f.getCanonicalPath(); + uriBase = tUriBase; + if (log.isInfoEnabled()) { + log.info(Localizer.getMessage( + "jspc.implicit.uriRoot", + uriRoot)); + } + break; + } + if (f.exists() && f.isDirectory()) { + tUriBase = "/" + f.getName() + "/" + tUriBase; + } + + String fParent = f.getParent(); + if (fParent == null) { + break; + } else { + f = new File(fParent); + } + + // If there is no acceptible candidate, uriRoot will + // remain null to indicate to the CompilerContext to + // use the current working/user dir. + } + + if (uriRoot != null) { + File froot = new File(uriRoot); + uriRoot = froot.getCanonicalPath(); + } + } + } catch (IOException ioe) { + // since this is an optional default and a null value + // for uriRoot has a non-error meaning, we can just + // pass straight through + } + } + + /** + * Resolves the relative or absolute pathname correctly + * in both Ant and command-line situations. If Ant launched + * us, we should use the basedir of the current project + * to resolve relative paths. + * + * See Bugzilla 35571. + * + * @param s The file + * @return The file resolved + */ + protected File resolveFile(final String s) { + if(getProject() == null) { + // Note FileUtils.getFileUtils replaces FileUtils.newFileUtils in Ant 1.6.3 + return FileUtils.newFileUtils().resolveFile(null, s); + } else { + return FileUtils.newFileUtils().resolveFile(getProject().getBaseDir(), s); + } + } +} diff --git a/java/org/apache/jasper/JspCompilationContext.java b/java/org/apache/jasper/JspCompilationContext.java index f452cb7dd..344d29fbb 100644 --- a/java/org/apache/jasper/JspCompilationContext.java +++ b/java/org/apache/jasper/JspCompilationContext.java @@ -1,705 +1,705 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Hashtable; -import java.util.Set; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.jasper.compiler.Compiler; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.JspUtil; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.compiler.ServletWriter; -import org.apache.jasper.servlet.JasperLoader; -import org.apache.jasper.servlet.JspServletWrapper; - -/** - * A place holder for various things that are used through out the JSP - * engine. This is a per-request/per-context data structure. Some of - * the instance variables are set at different points. - * - * Most of the path-related stuff is here - mangling names, versions, dirs, - * loading resources and dealing with uris. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Pierre Delisle - * @author Costin Manolache - * @author Kin-man Chung - */ -public class JspCompilationContext { - - protected org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class); - - private Hashtable tagFileJarUrls; - private boolean isPackagedTagFile; - - private String className; - private String jspUri; - private boolean isErrPage; - private String basePackageName; - private String derivedPackageName; - private String servletJavaFileName; - private String javaPath; - private String classFileName; - private String contentType; - private ServletWriter writer; - private Options options; - private JspServletWrapper jsw; - private Compiler jspCompiler; - private String classPath; - - private String baseURI; - private String baseOutputDir; - private String outputDir; - private ServletContext context; - private URLClassLoader loader; - - private JspRuntimeContext rctxt; - - private int removed = 0; - - private URLClassLoader jspLoader; - private URL baseUrl; - private Class servletClass; - - private boolean isTagFile; - private boolean protoTypeMode; - private TagInfo tagInfo; - private URL tagFileJarUrl; - - // jspURI _must_ be relative to the context - public JspCompilationContext(String jspUri, - boolean isErrPage, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt) { - - this.jspUri = canonicalURI(jspUri); - this.isErrPage = isErrPage; - this.options = options; - this.jsw = jsw; - this.context = context; - - this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); - // hack fix for resolveRelativeURI - if (baseURI == null) { - baseURI = "/"; - } else if (baseURI.charAt(0) != '/') { - // strip the basde slash since it will be combined with the - // uriBase to generate a file - baseURI = "/" + baseURI; - } - if (baseURI.charAt(baseURI.length() - 1) != '/') { - baseURI += '/'; - } - - this.rctxt = rctxt; - this.tagFileJarUrls = new Hashtable(); - this.basePackageName = Constants.JSP_PACKAGE_NAME; - } - - public JspCompilationContext(String tagfile, - TagInfo tagInfo, - Options options, - ServletContext context, - JspServletWrapper jsw, - JspRuntimeContext rctxt, - URL tagFileJarUrl) { - this(tagfile, false, options, context, jsw, rctxt); - this.isTagFile = true; - this.tagInfo = tagInfo; - this.tagFileJarUrl = tagFileJarUrl; - if (tagFileJarUrl != null) { - isPackagedTagFile = true; - } - } - - /* ==================== Methods to override ==================== */ - - /** ---------- Class path and loader ---------- */ - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - if( classPath != null ) - return classPath; - return rctxt.getClassPath(); - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public void setClassPath(String classPath) { - this.classPath = classPath; - } - - /** - * What class loader to use for loading classes while compiling - * this JSP? - */ - public ClassLoader getClassLoader() { - if( loader != null ) - return loader; - return rctxt.getParentClassLoader(); - } - - public void setClassLoader(URLClassLoader loader) { - this.loader = loader; - } - - public ClassLoader getJspLoader() { - if( jspLoader == null ) { - jspLoader = new JasperLoader - (new URL[] {baseUrl}, - getClassLoader(), - rctxt.getPermissionCollection(), - rctxt.getCodeSource()); - } - return jspLoader; - } - - /** ---------- Input/Output ---------- */ - - /** - * The output directory to generate code into. The output directory - * is make up of the scratch directory, which is provide in Options, - * plus the directory derived from the package name. - */ - public String getOutputDir() { - if (outputDir == null) { - createOutputDir(); - } - - return outputDir; - } - - /** - * Create a "Compiler" object based on some init param data. This - * is not done yet. Right now we're just hardcoding the actual - * compilers that are created. - */ - public Compiler createCompiler() throws JasperException { - if (jspCompiler != null ) { - return jspCompiler; - } - jspCompiler = null; - if (options.getCompiler() == null) { - jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler"); - if (jspCompiler == null) { - jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler"); - } - } else { - jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler"); - if (jspCompiler == null) { - jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler"); - } - } - if (jspCompiler == null) { - throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); - } - jspCompiler.init(this, jsw); - return jspCompiler; - } - - private Compiler createCompiler(String className) { - Compiler compiler = null; - try { - compiler = (Compiler) Class.forName(className).newInstance(); - } catch (Throwable t) { - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.error.compiler"), t); - } - } - return compiler; - } - - public Compiler getCompiler() { - return jspCompiler; - } - - /** ---------- Access resources in the webapp ---------- */ - - /** - * Get the full value of a URI relative to this compilations context - * uses current file as the base. - */ - public String resolveRelativeUri(String uri) { - // sometimes we get uri's massaged from File(String), so check for - // a root directory deperator char - if (uri.startsWith("/") || uri.startsWith(File.separator)) { - return uri; - } else { - return baseURI + uri; - } - } - - /** - * Gets a resource as a stream, relative to the meanings of this - * context's implementation. - * @return a null if the resource cannot be found or represented - * as an InputStream. - */ - public java.io.InputStream getResourceAsStream(String res) { - return context.getResourceAsStream(canonicalURI(res)); - } - - - public URL getResource(String res) throws MalformedURLException { - return context.getResource(canonicalURI(res)); - } - - public Set getResourcePaths(String path) { - return context.getResourcePaths(canonicalURI(path)); - } - - /** - * Gets the actual path of a URI relative to the context of - * the compilation. - */ - public String getRealPath(String path) { - if (context != null) { - return context.getRealPath(path); - } - return path; - } - - /** - * Returns the tag-file-name-to-JAR-file map of this compilation unit, - * which maps tag file names to the JAR files in which the tag files are - * packaged. - * - * The map is populated when parsing the tag-file elements of the TLDs - * of any imported taglibs. - */ - public Hashtable getTagFileJarUrls() { - return this.tagFileJarUrls; - } - - /** - * Returns the JAR file in which the tag file for which this - * JspCompilationContext was created is packaged, or null if this - * JspCompilationContext does not correspond to a tag file, or if the - * corresponding tag file is not packaged in a JAR. - */ - public URL getTagFileJarUrl() { - return this.tagFileJarUrl; - } - - /* ==================== Common implementation ==================== */ - - /** - * Just the class name (does not include package name) of the - * generated class. - */ - public String getServletClassName() { - - if (className != null) { - return className; - } - - if (isTagFile) { - className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - className = className.substring(lastIndex + 1); - } - } else { - int iSep = jspUri.lastIndexOf('/') + 1; - className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); - } - return className; - } - - public void setServletClassName(String className) { - this.className = className; - } - - /** - * Path of the JSP URI. Note that this is not a file name. This is - * the context rooted URI of the JSP file. - */ - public String getJspFile() { - return jspUri; - } - - /** - * Are we processing something that has been declared as an - * errorpage? - */ - public boolean isErrorPage() { - return isErrPage; - } - - public void setErrorPage(boolean isErrPage) { - this.isErrPage = isErrPage; - } - - public boolean isTagFile() { - return isTagFile; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public void setTagInfo(TagInfo tagi) { - tagInfo = tagi; - } - - /** - * True if we are compiling a tag file in prototype mode. - * ie we only generate codes with class for the tag handler with empty - * method bodies. - */ - public boolean isPrototypeMode() { - return protoTypeMode; - } - - public void setPrototypeMode(boolean pm) { - protoTypeMode = pm; - } - - /** - * Package name for the generated class is make up of the base package - * name, which is user settable, and the derived package name. The - * derived package name directly mirrors the file heirachy of the JSP page. - */ - public String getServletPackageName() { - if (isTagFile()) { - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - String pkgName = ""; - if (lastIndex != -1) { - pkgName = className.substring(0, lastIndex); - } - return pkgName; - } else { - String dPackageName = getDerivedPackageName(); - if (dPackageName.length() == 0) { - return basePackageName; - } - return basePackageName + '.' + getDerivedPackageName(); - } - } - - private String getDerivedPackageName() { - if (derivedPackageName == null) { - int iSep = jspUri.lastIndexOf('/'); - derivedPackageName = (iSep > 0) ? - JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; - } - return derivedPackageName; - } - - /** - * The package name into which the servlet class is generated. - */ - public void setServletPackageName(String servletPackageName) { - this.basePackageName = servletPackageName; - } - - /** - * Full path name of the Java file into which the servlet is being - * generated. - */ - public String getServletJavaFileName() { - - if (servletJavaFileName == null) { - servletJavaFileName = - getOutputDir() + getServletClassName() + ".java"; - } else { - // Make sure output dir exists - makeOutputDir(); - } - return servletJavaFileName; - } - - public void setServletJavaFileName(String servletJavaFileName) { - this.servletJavaFileName = servletJavaFileName; - } - - /** - * Get hold of the Options object for this context. - */ - public Options getOptions() { - return options; - } - - public ServletContext getServletContext() { - return context; - } - - public JspRuntimeContext getRuntimeContext() { - return rctxt; - } - - /** - * Path of the Java file relative to the work directory. - */ - public String getJavaPath() { - - if (javaPath != null) { - return javaPath; - } - - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - javaPath = tagName.replace('.', '/') + ".java"; - } else { - javaPath = getServletPackageName().replace('.', '/') + '/' + - getServletClassName() + ".java"; - } - return javaPath; - } - - public String getClassFileName() { - - if (classFileName == null) { - classFileName = getOutputDir() + getServletClassName() + ".class"; - } else { - // Make sure output dir exists - makeOutputDir(); - } - return classFileName; - } - - /** - * Get the content type of this JSP. - * - * Content type includes content type and encoding. - */ - public String getContentType() { - return contentType; - } - - public void setContentType(String contentType) { - this.contentType = contentType; - } - - /** - * Where is the servlet being generated? - */ - public ServletWriter getWriter() { - return writer; - } - - public void setWriter(ServletWriter writer) { - this.writer = writer; - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the given uri is not associated with any tag library - * 'exposed' in the web application. - */ - public String[] getTldLocation(String uri) throws JasperException { - String[] location = - getOptions().getTldLocationsCache().getLocation(uri); - return location; - } - - /** - * Are we keeping generated code around? - */ - public boolean keepGenerated() { - return getOptions().getKeepGenerated(); - } - - // ==================== Removal ==================== - - public void incrementRemoved() { - if (removed > 1) { - jspCompiler.removeGeneratedFiles(); - if( rctxt != null ) - rctxt.removeWrapper(jspUri); - } - removed++; - } - - public boolean isRemoved() { - if (removed > 1 ) { - return true; - } - return false; - } - - // ==================== Compile and reload ==================== - - public void compile() throws JasperException, FileNotFoundException { - createCompiler(); - if (isPackagedTagFile || jspCompiler.isOutDated()) { - try { - jspLoader = null; - jspCompiler.compile(); - jsw.setReload(true); - jsw.setCompilationException(null); - } catch (JasperException ex) { - // Cache compilation exception - jsw.setCompilationException(ex); - throw ex; - } catch (Exception ex) { - ex.printStackTrace(); - JasperException je = new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), - ex); - // Cache compilation exception - jsw.setCompilationException(je); - throw je; - } - } - } - - // ==================== Manipulating the class ==================== - - public Class load() - throws JasperException, FileNotFoundException - { - try { - getJspLoader(); - - String name; - if (isTagFile()) { - name = tagInfo.getTagClassName(); - } else { - name = getServletPackageName() + "." + getServletClassName(); - } - servletClass = jspLoader.loadClass(name); - } catch (ClassNotFoundException cex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), - cex); - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), - ex); - } - removed = 0; - return servletClass; - } - - // ==================== Private methods ==================== - - static Object outputDirLock = new Object(); - - private void makeOutputDir() { - synchronized(outputDirLock) { - File outDirFile = new File(outputDir); - outDirFile.mkdirs(); - } - } - - private void createOutputDir() { - String path = null; - if (isTagFile()) { - String tagName = tagInfo.getTagClassName(); - path = tagName.replace('.', '/'); - path = path.substring(0, path.lastIndexOf('/')); - } else { - path = getServletPackageName().replace('.', '/'); - } - - try { - // Append servlet or tag handler path to scratch dir - baseUrl = options.getScratchDir().toURL(); - String outUrlString = baseUrl.toString() + '/' + path; - URL outUrl = new URL(outUrlString); - outputDir = outUrl.getFile() + File.separator; - makeOutputDir(); - } catch (Exception e) { - throw new IllegalStateException("No output directory: " + - e.getMessage()); - } - } - - private static final boolean isPathSeparator(char c) { - return (c == '/' || c == '\\'); - } - - private static final String canonicalURI(String s) { - if (s == null) return null; - StringBuffer result = new StringBuffer(); - final int len = s.length(); - int pos = 0; - while (pos < len) { - char c = s.charAt(pos); - if ( isPathSeparator(c) ) { - /* - * multiple path separators. - * 'foo///bar' -> 'foo/bar' - */ - while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { - ++pos; - } - - if (pos+1 < len && s.charAt(pos+1) == '.') { - /* - * a single dot at the end of the path - we are done. - */ - if (pos+2 >= len) break; - - switch (s.charAt(pos+2)) { - /* - * self directory in path - * foo/./bar -> foo/bar - */ - case '/': - case '\\': - pos += 2; - continue; - - /* - * two dots in a path: go back one hierarchy. - * foo/bar/../baz -> foo/baz - */ - case '.': - // only if we have exactly _two_ dots. - if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { - pos += 3; - int separatorPos = result.length()-1; - while (separatorPos >= 0 && - ! isPathSeparator(result - .charAt(separatorPos))) { - --separatorPos; - } - if (separatorPos >= 0) - result.setLength(separatorPos); - continue; - } - } - } - } - result.append(c); - ++pos; - } - return result.toString(); - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.io.FileNotFoundException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Hashtable; +import java.util.Set; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.tagext.TagInfo; + +import org.apache.jasper.compiler.Compiler; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.JspUtil; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.compiler.ServletWriter; +import org.apache.jasper.servlet.JasperLoader; +import org.apache.jasper.servlet.JspServletWrapper; + +/** + * A place holder for various things that are used through out the JSP + * engine. This is a per-request/per-context data structure. Some of + * the instance variables are set at different points. + * + * Most of the path-related stuff is here - mangling names, versions, dirs, + * loading resources and dealing with uris. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Pierre Delisle + * @author Costin Manolache + * @author Kin-man Chung + */ +public class JspCompilationContext { + + protected org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(JspCompilationContext.class); + + private Hashtable tagFileJarUrls; + private boolean isPackagedTagFile; + + private String className; + private String jspUri; + private boolean isErrPage; + private String basePackageName; + private String derivedPackageName; + private String servletJavaFileName; + private String javaPath; + private String classFileName; + private String contentType; + private ServletWriter writer; + private Options options; + private JspServletWrapper jsw; + private Compiler jspCompiler; + private String classPath; + + private String baseURI; + private String baseOutputDir; + private String outputDir; + private ServletContext context; + private URLClassLoader loader; + + private JspRuntimeContext rctxt; + + private int removed = 0; + + private URLClassLoader jspLoader; + private URL baseUrl; + private Class servletClass; + + private boolean isTagFile; + private boolean protoTypeMode; + private TagInfo tagInfo; + private URL tagFileJarUrl; + + // jspURI _must_ be relative to the context + public JspCompilationContext(String jspUri, + boolean isErrPage, + Options options, + ServletContext context, + JspServletWrapper jsw, + JspRuntimeContext rctxt) { + + this.jspUri = canonicalURI(jspUri); + this.isErrPage = isErrPage; + this.options = options; + this.jsw = jsw; + this.context = context; + + this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1); + // hack fix for resolveRelativeURI + if (baseURI == null) { + baseURI = "/"; + } else if (baseURI.charAt(0) != '/') { + // strip the basde slash since it will be combined with the + // uriBase to generate a file + baseURI = "/" + baseURI; + } + if (baseURI.charAt(baseURI.length() - 1) != '/') { + baseURI += '/'; + } + + this.rctxt = rctxt; + this.tagFileJarUrls = new Hashtable(); + this.basePackageName = Constants.JSP_PACKAGE_NAME; + } + + public JspCompilationContext(String tagfile, + TagInfo tagInfo, + Options options, + ServletContext context, + JspServletWrapper jsw, + JspRuntimeContext rctxt, + URL tagFileJarUrl) { + this(tagfile, false, options, context, jsw, rctxt); + this.isTagFile = true; + this.tagInfo = tagInfo; + this.tagFileJarUrl = tagFileJarUrl; + if (tagFileJarUrl != null) { + isPackagedTagFile = true; + } + } + + /* ==================== Methods to override ==================== */ + + /** ---------- Class path and loader ---------- */ + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + if( classPath != null ) + return classPath; + return rctxt.getClassPath(); + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public void setClassPath(String classPath) { + this.classPath = classPath; + } + + /** + * What class loader to use for loading classes while compiling + * this JSP? + */ + public ClassLoader getClassLoader() { + if( loader != null ) + return loader; + return rctxt.getParentClassLoader(); + } + + public void setClassLoader(URLClassLoader loader) { + this.loader = loader; + } + + public ClassLoader getJspLoader() { + if( jspLoader == null ) { + jspLoader = new JasperLoader + (new URL[] {baseUrl}, + getClassLoader(), + rctxt.getPermissionCollection(), + rctxt.getCodeSource()); + } + return jspLoader; + } + + /** ---------- Input/Output ---------- */ + + /** + * The output directory to generate code into. The output directory + * is make up of the scratch directory, which is provide in Options, + * plus the directory derived from the package name. + */ + public String getOutputDir() { + if (outputDir == null) { + createOutputDir(); + } + + return outputDir; + } + + /** + * Create a "Compiler" object based on some init param data. This + * is not done yet. Right now we're just hardcoding the actual + * compilers that are created. + */ + public Compiler createCompiler() throws JasperException { + if (jspCompiler != null ) { + return jspCompiler; + } + jspCompiler = null; + if (options.getCompiler() == null) { + jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler"); + if (jspCompiler == null) { + jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler"); + } + } else { + jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler"); + if (jspCompiler == null) { + jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler"); + } + } + if (jspCompiler == null) { + throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler")); + } + jspCompiler.init(this, jsw); + return jspCompiler; + } + + private Compiler createCompiler(String className) { + Compiler compiler = null; + try { + compiler = (Compiler) Class.forName(className).newInstance(); + } catch (Throwable t) { + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.error.compiler"), t); + } + } + return compiler; + } + + public Compiler getCompiler() { + return jspCompiler; + } + + /** ---------- Access resources in the webapp ---------- */ + + /** + * Get the full value of a URI relative to this compilations context + * uses current file as the base. + */ + public String resolveRelativeUri(String uri) { + // sometimes we get uri's massaged from File(String), so check for + // a root directory deperator char + if (uri.startsWith("/") || uri.startsWith(File.separator)) { + return uri; + } else { + return baseURI + uri; + } + } + + /** + * Gets a resource as a stream, relative to the meanings of this + * context's implementation. + * @return a null if the resource cannot be found or represented + * as an InputStream. + */ + public java.io.InputStream getResourceAsStream(String res) { + return context.getResourceAsStream(canonicalURI(res)); + } + + + public URL getResource(String res) throws MalformedURLException { + return context.getResource(canonicalURI(res)); + } + + public Set getResourcePaths(String path) { + return context.getResourcePaths(canonicalURI(path)); + } + + /** + * Gets the actual path of a URI relative to the context of + * the compilation. + */ + public String getRealPath(String path) { + if (context != null) { + return context.getRealPath(path); + } + return path; + } + + /** + * Returns the tag-file-name-to-JAR-file map of this compilation unit, + * which maps tag file names to the JAR files in which the tag files are + * packaged. + * + * The map is populated when parsing the tag-file elements of the TLDs + * of any imported taglibs. + */ + public Hashtable getTagFileJarUrls() { + return this.tagFileJarUrls; + } + + /** + * Returns the JAR file in which the tag file for which this + * JspCompilationContext was created is packaged, or null if this + * JspCompilationContext does not correspond to a tag file, or if the + * corresponding tag file is not packaged in a JAR. + */ + public URL getTagFileJarUrl() { + return this.tagFileJarUrl; + } + + /* ==================== Common implementation ==================== */ + + /** + * Just the class name (does not include package name) of the + * generated class. + */ + public String getServletClassName() { + + if (className != null) { + return className; + } + + if (isTagFile) { + className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if (lastIndex != -1) { + className = className.substring(lastIndex + 1); + } + } else { + int iSep = jspUri.lastIndexOf('/') + 1; + className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep)); + } + return className; + } + + public void setServletClassName(String className) { + this.className = className; + } + + /** + * Path of the JSP URI. Note that this is not a file name. This is + * the context rooted URI of the JSP file. + */ + public String getJspFile() { + return jspUri; + } + + /** + * Are we processing something that has been declared as an + * errorpage? + */ + public boolean isErrorPage() { + return isErrPage; + } + + public void setErrorPage(boolean isErrPage) { + this.isErrPage = isErrPage; + } + + public boolean isTagFile() { + return isTagFile; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public void setTagInfo(TagInfo tagi) { + tagInfo = tagi; + } + + /** + * True if we are compiling a tag file in prototype mode. + * ie we only generate codes with class for the tag handler with empty + * method bodies. + */ + public boolean isPrototypeMode() { + return protoTypeMode; + } + + public void setPrototypeMode(boolean pm) { + protoTypeMode = pm; + } + + /** + * Package name for the generated class is make up of the base package + * name, which is user settable, and the derived package name. The + * derived package name directly mirrors the file heirachy of the JSP page. + */ + public String getServletPackageName() { + if (isTagFile()) { + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + String pkgName = ""; + if (lastIndex != -1) { + pkgName = className.substring(0, lastIndex); + } + return pkgName; + } else { + String dPackageName = getDerivedPackageName(); + if (dPackageName.length() == 0) { + return basePackageName; + } + return basePackageName + '.' + getDerivedPackageName(); + } + } + + private String getDerivedPackageName() { + if (derivedPackageName == null) { + int iSep = jspUri.lastIndexOf('/'); + derivedPackageName = (iSep > 0) ? + JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : ""; + } + return derivedPackageName; + } + + /** + * The package name into which the servlet class is generated. + */ + public void setServletPackageName(String servletPackageName) { + this.basePackageName = servletPackageName; + } + + /** + * Full path name of the Java file into which the servlet is being + * generated. + */ + public String getServletJavaFileName() { + + if (servletJavaFileName == null) { + servletJavaFileName = + getOutputDir() + getServletClassName() + ".java"; + } else { + // Make sure output dir exists + makeOutputDir(); + } + return servletJavaFileName; + } + + public void setServletJavaFileName(String servletJavaFileName) { + this.servletJavaFileName = servletJavaFileName; + } + + /** + * Get hold of the Options object for this context. + */ + public Options getOptions() { + return options; + } + + public ServletContext getServletContext() { + return context; + } + + public JspRuntimeContext getRuntimeContext() { + return rctxt; + } + + /** + * Path of the Java file relative to the work directory. + */ + public String getJavaPath() { + + if (javaPath != null) { + return javaPath; + } + + if (isTagFile()) { + String tagName = tagInfo.getTagClassName(); + javaPath = tagName.replace('.', '/') + ".java"; + } else { + javaPath = getServletPackageName().replace('.', '/') + '/' + + getServletClassName() + ".java"; + } + return javaPath; + } + + public String getClassFileName() { + + if (classFileName == null) { + classFileName = getOutputDir() + getServletClassName() + ".class"; + } else { + // Make sure output dir exists + makeOutputDir(); + } + return classFileName; + } + + /** + * Get the content type of this JSP. + * + * Content type includes content type and encoding. + */ + public String getContentType() { + return contentType; + } + + public void setContentType(String contentType) { + this.contentType = contentType; + } + + /** + * Where is the servlet being generated? + */ + public ServletWriter getWriter() { + return writer; + } + + public void setWriter(ServletWriter writer) { + this.writer = writer; + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the given uri is not associated with any tag library + * 'exposed' in the web application. + */ + public String[] getTldLocation(String uri) throws JasperException { + String[] location = + getOptions().getTldLocationsCache().getLocation(uri); + return location; + } + + /** + * Are we keeping generated code around? + */ + public boolean keepGenerated() { + return getOptions().getKeepGenerated(); + } + + // ==================== Removal ==================== + + public void incrementRemoved() { + if (removed > 1) { + jspCompiler.removeGeneratedFiles(); + if( rctxt != null ) + rctxt.removeWrapper(jspUri); + } + removed++; + } + + public boolean isRemoved() { + if (removed > 1 ) { + return true; + } + return false; + } + + // ==================== Compile and reload ==================== + + public void compile() throws JasperException, FileNotFoundException { + createCompiler(); + if (isPackagedTagFile || jspCompiler.isOutDated()) { + try { + jspLoader = null; + jspCompiler.compile(); + jsw.setReload(true); + jsw.setCompilationException(null); + } catch (JasperException ex) { + // Cache compilation exception + jsw.setCompilationException(ex); + throw ex; + } catch (Exception ex) { + ex.printStackTrace(); + JasperException je = new JasperException( + Localizer.getMessage("jsp.error.unable.compile"), + ex); + // Cache compilation exception + jsw.setCompilationException(je); + throw je; + } + } + } + + // ==================== Manipulating the class ==================== + + public Class load() + throws JasperException, FileNotFoundException + { + try { + getJspLoader(); + + String name; + if (isTagFile()) { + name = tagInfo.getTagClassName(); + } else { + name = getServletPackageName() + "." + getServletClassName(); + } + servletClass = jspLoader.loadClass(name); + } catch (ClassNotFoundException cex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.load"), + cex); + } catch (Exception ex) { + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"), + ex); + } + removed = 0; + return servletClass; + } + + // ==================== Private methods ==================== + + static Object outputDirLock = new Object(); + + private void makeOutputDir() { + synchronized(outputDirLock) { + File outDirFile = new File(outputDir); + outDirFile.mkdirs(); + } + } + + private void createOutputDir() { + String path = null; + if (isTagFile()) { + String tagName = tagInfo.getTagClassName(); + path = tagName.replace('.', '/'); + path = path.substring(0, path.lastIndexOf('/')); + } else { + path = getServletPackageName().replace('.', '/'); + } + + try { + // Append servlet or tag handler path to scratch dir + baseUrl = options.getScratchDir().toURL(); + String outUrlString = baseUrl.toString() + '/' + path; + URL outUrl = new URL(outUrlString); + outputDir = outUrl.getFile() + File.separator; + makeOutputDir(); + } catch (Exception e) { + throw new IllegalStateException("No output directory: " + + e.getMessage()); + } + } + + private static final boolean isPathSeparator(char c) { + return (c == '/' || c == '\\'); + } + + private static final String canonicalURI(String s) { + if (s == null) return null; + StringBuffer result = new StringBuffer(); + final int len = s.length(); + int pos = 0; + while (pos < len) { + char c = s.charAt(pos); + if ( isPathSeparator(c) ) { + /* + * multiple path separators. + * 'foo///bar' -> 'foo/bar' + */ + while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) { + ++pos; + } + + if (pos+1 < len && s.charAt(pos+1) == '.') { + /* + * a single dot at the end of the path - we are done. + */ + if (pos+2 >= len) break; + + switch (s.charAt(pos+2)) { + /* + * self directory in path + * foo/./bar -> foo/bar + */ + case '/': + case '\\': + pos += 2; + continue; + + /* + * two dots in a path: go back one hierarchy. + * foo/bar/../baz -> foo/baz + */ + case '.': + // only if we have exactly _two_ dots. + if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) { + pos += 3; + int separatorPos = result.length()-1; + while (separatorPos >= 0 && + ! isPathSeparator(result + .charAt(separatorPos))) { + --separatorPos; + } + if (separatorPos >= 0) + result.setLength(separatorPos); + continue; + } + } + } + } + result.append(c); + ++pos; + } + return result.toString(); + } +} + diff --git a/java/org/apache/jasper/Options.java b/java/org/apache/jasper/Options.java index 56e48dc3d..5ffeba56c 100644 --- a/java/org/apache/jasper/Options.java +++ b/java/org/apache/jasper/Options.java @@ -1,193 +1,193 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper; - -import java.io.File; -import java.util.Map; - -import org.apache.jasper.compiler.JspConfig; -import org.apache.jasper.compiler.TagPluginManager; -import org.apache.jasper.compiler.TldLocationsCache; - -/** - * A class to hold all init parameters specific to the JSP engine. - * - * @author Anil K. Vijendran - * @author Hans Bergsten - * @author Pierre Delisle - */ -public interface Options { - - /** - * Returns true if Jasper issues a compilation error instead of a runtime - * Instantiation error if the class attribute specified in useBean action - * is invalid. - */ - public boolean getErrorOnUseBeanInvalidClassAttribute(); - - /** - * Are we keeping generated code around? - */ - public boolean getKeepGenerated(); - - /** - * Returns true if tag handler pooling is enabled, false otherwise. - */ - public boolean isPoolingEnabled(); - - /** - * Are we supporting HTML mapped servlets? - */ - public boolean getMappedFile(); - - /** - * Should errors be sent to client or thrown into stderr? - */ - public boolean getSendErrorToClient(); - - /** - * Should we include debug information in compiled class? - */ - public boolean getClassDebugInfo(); - - /** - * Background compile thread check interval in seconds - */ - public int getCheckInterval(); - - /** - * Is Jasper being used in development mode? - */ - public boolean getDevelopment(); - - /** - * Is the generation of SMAP info for JSR45 debugging suppressed? - */ - public boolean isSmapSuppressed(); - - /** - * Indicates whether SMAP info for JSR45 debugging should be dumped to a - * file. - * Ignored is suppressSmap() is true - */ - public boolean isSmapDumped(); - - /** - * Should white spaces between directives or actions be trimmed? - */ - public boolean getTrimSpaces(); - - /** - * Should annotations on tags be ignored? - */ - public boolean getIgnoreAnnotations(); - - /** - * Class ID for use in the plugin tag when the browser is IE. - */ - public String getIeClassId(); - - /** - * What is my scratch dir? - */ - public File getScratchDir(); - - /** - * What classpath should I use while compiling the servlets - * generated from JSP files? - */ - public String getClassPath(); - - /** - * Compiler to use. - */ - public String getCompiler(); - - /** - * The compiler target VM, e.g. 1.1, 1.2, 1.3, 1.4, or 1.5. - */ - public String getCompilerTargetVM(); - - /** - * Compiler source VM, e.g. 1.3, 1.4, or 1.5. - */ - public String getCompilerSourceVM(); - - /** - * The cache for the location of the TLD's - * for the various tag libraries 'exposed' - * by the web application. - * A tag library is 'exposed' either explicitely in - * web.xml or implicitely via the uri tag in the TLD - * of a taglib deployed in a jar file (WEB-INF/lib). - * - * @return the instance of the TldLocationsCache - * for the web-application. - */ - public TldLocationsCache getTldLocationsCache(); - - /** - * Java platform encoding to generate the JSP - * page servlet. - */ - public String getJavaEncoding(); - - /** - * boolean flag to tell Ant whether to fork JSP page compilations. - */ - public boolean getFork(); - - /** - * Obtain JSP configuration informantion specified in web.xml. - */ - public JspConfig getJspConfig(); - - /** - * Is generation of X-Powered-By response header enabled/disabled? - */ - public boolean isXpoweredBy(); - - /** - * Obtain a Tag Plugin Manager - */ - public TagPluginManager getTagPluginManager(); - - /** - * Are Text strings to be generated as char arrays? - */ - public boolean genStringAsCharArray(); - - /** - * Modification test interval. - */ - public int getModificationTestInterval(); - - /** - * Is caching enabled (used for precompilation). - */ - public boolean isCaching(); - - /** - * The web-application wide cache for the returned TreeNode - * by parseXMLDocument in TagLibraryInfoImpl.parseTLD, - * if isCaching returns true. - * - * @return the Map(String uri, TreeNode tld) instance. - */ - public Map getCache(); - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper; + +import java.io.File; +import java.util.Map; + +import org.apache.jasper.compiler.JspConfig; +import org.apache.jasper.compiler.TagPluginManager; +import org.apache.jasper.compiler.TldLocationsCache; + +/** + * A class to hold all init parameters specific to the JSP engine. + * + * @author Anil K. Vijendran + * @author Hans Bergsten + * @author Pierre Delisle + */ +public interface Options { + + /** + * Returns true if Jasper issues a compilation error instead of a runtime + * Instantiation error if the class attribute specified in useBean action + * is invalid. + */ + public boolean getErrorOnUseBeanInvalidClassAttribute(); + + /** + * Are we keeping generated code around? + */ + public boolean getKeepGenerated(); + + /** + * Returns true if tag handler pooling is enabled, false otherwise. + */ + public boolean isPoolingEnabled(); + + /** + * Are we supporting HTML mapped servlets? + */ + public boolean getMappedFile(); + + /** + * Should errors be sent to client or thrown into stderr? + */ + public boolean getSendErrorToClient(); + + /** + * Should we include debug information in compiled class? + */ + public boolean getClassDebugInfo(); + + /** + * Background compile thread check interval in seconds + */ + public int getCheckInterval(); + + /** + * Is Jasper being used in development mode? + */ + public boolean getDevelopment(); + + /** + * Is the generation of SMAP info for JSR45 debugging suppressed? + */ + public boolean isSmapSuppressed(); + + /** + * Indicates whether SMAP info for JSR45 debugging should be dumped to a + * file. + * Ignored is suppressSmap() is true + */ + public boolean isSmapDumped(); + + /** + * Should white spaces between directives or actions be trimmed? + */ + public boolean getTrimSpaces(); + + /** + * Should annotations on tags be ignored? + */ + public boolean getIgnoreAnnotations(); + + /** + * Class ID for use in the plugin tag when the browser is IE. + */ + public String getIeClassId(); + + /** + * What is my scratch dir? + */ + public File getScratchDir(); + + /** + * What classpath should I use while compiling the servlets + * generated from JSP files? + */ + public String getClassPath(); + + /** + * Compiler to use. + */ + public String getCompiler(); + + /** + * The compiler target VM, e.g. 1.1, 1.2, 1.3, 1.4, or 1.5. + */ + public String getCompilerTargetVM(); + + /** + * Compiler source VM, e.g. 1.3, 1.4, or 1.5. + */ + public String getCompilerSourceVM(); + + /** + * The cache for the location of the TLD's + * for the various tag libraries 'exposed' + * by the web application. + * A tag library is 'exposed' either explicitely in + * web.xml or implicitely via the uri tag in the TLD + * of a taglib deployed in a jar file (WEB-INF/lib). + * + * @return the instance of the TldLocationsCache + * for the web-application. + */ + public TldLocationsCache getTldLocationsCache(); + + /** + * Java platform encoding to generate the JSP + * page servlet. + */ + public String getJavaEncoding(); + + /** + * boolean flag to tell Ant whether to fork JSP page compilations. + */ + public boolean getFork(); + + /** + * Obtain JSP configuration informantion specified in web.xml. + */ + public JspConfig getJspConfig(); + + /** + * Is generation of X-Powered-By response header enabled/disabled? + */ + public boolean isXpoweredBy(); + + /** + * Obtain a Tag Plugin Manager + */ + public TagPluginManager getTagPluginManager(); + + /** + * Are Text strings to be generated as char arrays? + */ + public boolean genStringAsCharArray(); + + /** + * Modification test interval. + */ + public int getModificationTestInterval(); + + /** + * Is caching enabled (used for precompilation). + */ + public boolean isCaching(); + + /** + * The web-application wide cache for the returned TreeNode + * by parseXMLDocument in TagLibraryInfoImpl.parseTLD, + * if isCaching returns true. + * + * @return the Map(String uri, TreeNode tld) instance. + */ + public Map getCache(); + +} diff --git a/java/org/apache/jasper/compiler/AntCompiler.java b/java/org/apache/jasper/compiler/AntCompiler.java index 8181a40b4..50136ab61 100644 --- a/java/org/apache/jasper/compiler/AntCompiler.java +++ b/java/org/apache/jasper/compiler/AntCompiler.java @@ -1,275 +1,275 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.PrintStream; -import java.util.StringTokenizer; - -import org.apache.jasper.JasperException; -import org.apache.jasper.util.SystemLogHandler; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DefaultLogger; -import org.apache.tools.ant.Project; -import org.apache.tools.ant.taskdefs.Javac; -import org.apache.tools.ant.types.Path; -import org.apache.tools.ant.types.PatternSet; - -/** - * Main JSP compiler class. This class uses Ant for compiling. - * - * @author Anil K. Vijendran - * @author Mandar Raje - * @author Pierre Delisle - * @author Kin-man Chung - * @author Remy Maucherat - * @author Mark Roth - */ -public class AntCompiler extends Compiler { - - static { - System.setErr(new SystemLogHandler(System.err)); - } - - // ----------------------------------------------------- Instance Variables - - protected Project project=null; - protected JasperAntLogger logger; - - // ------------------------------------------------------------ Constructor - - // Lazy eval - if we don't need to compile we probably don't need the project - protected Project getProject() { - - if( project!=null ) return project; - - // Initializing project - project = new Project(); - logger = new JasperAntLogger(); - logger.setOutputPrintStream(System.out); - logger.setErrorPrintStream(System.err); - logger.setMessageOutputLevel(Project.MSG_INFO); - project.addBuildListener( logger); - if (System.getProperty("catalina.home") != null) { - project.setBasedir( System.getProperty("catalina.home")); - } - - if( options.getCompiler() != null ) { - if( log.isDebugEnabled() ) - log.debug("Compiler " + options.getCompiler() ); - project.setProperty("build.compiler", options.getCompiler() ); - } - project.init(); - return project; - } - - class JasperAntLogger extends DefaultLogger { - - protected StringBuffer reportBuf = new StringBuffer(); - - protected void printMessage(final String message, - final PrintStream stream, - final int priority) { - } - - protected void log(String message) { - reportBuf.append(message); - reportBuf.append(System.getProperty("line.separator")); - } - - protected String getReport() { - String report = reportBuf.toString(); - reportBuf.setLength(0); - return report; - } - } - - // --------------------------------------------------------- Public Methods - - - /** - * Compile the servlet from .java file to .class file - */ - protected void generateClass(String[] smap) - throws FileNotFoundException, JasperException, Exception { - - long t1 = 0; - if (log.isDebugEnabled()) { - t1 = System.currentTimeMillis(); - } - - String javaEncoding = ctxt.getOptions().getJavaEncoding(); - String javaFileName = ctxt.getServletJavaFileName(); - String classpath = ctxt.getClassPath(); - - String sep = System.getProperty("path.separator"); - - StringBuffer errorReport = new StringBuffer(); - - StringBuffer info=new StringBuffer(); - info.append("Compile: javaFileName=" + javaFileName + "\n" ); - info.append(" classpath=" + classpath + "\n" ); - - // Start capturing the System.err output for this thread - SystemLogHandler.setThread(); - - // Initializing javac task - getProject(); - Javac javac = (Javac) project.createTask("javac"); - - // Initializing classpath - Path path = new Path(project); - path.setPath(System.getProperty("java.class.path")); - info.append(" cp=" + System.getProperty("java.class.path") + "\n"); - StringTokenizer tokenizer = new StringTokenizer(classpath, sep); - while (tokenizer.hasMoreElements()) { - String pathElement = tokenizer.nextToken(); - File repository = new File(pathElement); - path.setLocation(repository); - info.append(" cp=" + repository + "\n"); - } - - if( log.isDebugEnabled() ) - log.debug( "Using classpath: " + System.getProperty("java.class.path") + sep - + classpath); - - // Initializing sourcepath - Path srcPath = new Path(project); - srcPath.setLocation(options.getScratchDir()); - - info.append(" work dir=" + options.getScratchDir() + "\n"); - - // Initialize and set java extensions - String exts = System.getProperty("java.ext.dirs"); - if (exts != null) { - Path extdirs = new Path(project); - extdirs.setPath(exts); - javac.setExtdirs(extdirs); - info.append(" extension dir=" + exts + "\n"); - } - - // Add endorsed directories if any are specified and we're forking - // See Bugzilla 31257 - if(ctxt.getOptions().getFork()) { - String endorsed = System.getProperty("java.endorsed.dirs"); - if(endorsed != null) { - Javac.ImplementationSpecificArgument endorsedArg = - javac.createCompilerArg(); - endorsedArg.setLine("-J-Djava.endorsed.dirs="+endorsed); - info.append(" endorsed dir=" + endorsed + "\n"); - } else { - info.append(" no endorsed dirs specified\n"); - } - } - - // Configure the compiler object - javac.setEncoding(javaEncoding); - javac.setClasspath(path); - javac.setDebug(ctxt.getOptions().getClassDebugInfo()); - javac.setSrcdir(srcPath); - javac.setTempdir(options.getScratchDir()); - javac.setOptimize(! ctxt.getOptions().getClassDebugInfo() ); - javac.setFork(ctxt.getOptions().getFork()); - info.append(" srcDir=" + srcPath + "\n" ); - - // Set the Java compiler to use - if (options.getCompiler() != null) { - javac.setCompiler(options.getCompiler()); - info.append(" compiler=" + options.getCompiler() + "\n"); - } - - if (options.getCompilerTargetVM() != null) { - javac.setTarget(options.getCompilerTargetVM()); - info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); - } - - if (options.getCompilerSourceVM() != null) { - javac.setSource(options.getCompilerSourceVM()); - info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); - } - - // Build includes path - PatternSet.NameEntry includes = javac.createInclude(); - - includes.setName(ctxt.getJavaPath()); - info.append(" include="+ ctxt.getJavaPath() + "\n" ); - - BuildException be = null; - - try { - if (ctxt.getOptions().getFork()) { - javac.execute(); - } else { - synchronized(javacLock) { - javac.execute(); - } - } - } catch (BuildException e) { - be = e; - log.error( "Javac exception ", e); - log.error( "Env: " + info.toString()); - } - - errorReport.append(logger.getReport()); - - // Stop capturing the System.err output for this thread - String errorCapture = SystemLogHandler.unsetThread(); - if (errorCapture != null) { - errorReport.append(System.getProperty("line.separator")); - errorReport.append(errorCapture); - } - - if (!ctxt.keepGenerated()) { - File javaFile = new File(javaFileName); - javaFile.delete(); - } - - if (be != null) { - String errorReportString = errorReport.toString(); - log.error("Error compiling file: " + javaFileName + " " - + errorReportString); - JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors( - errorReportString, javaFileName, pageNodes); - if (javacErrors != null) { - errDispatcher.javacError(javacErrors); - } else { - errDispatcher.javacError(errorReportString, be); - } - } - - if( log.isDebugEnabled() ) { - long t2=System.currentTimeMillis(); - log.debug("Compiled " + ctxt.getServletJavaFileName() + " " - + (t2-t1) + "ms"); - } - - logger = null; - project = null; - - if (ctxt.isPrototypeMode()) { - return; - } - - // JSR45 Support - if (! options.isSmapSuppressed()) { - SmapUtil.installSmap(smap); - } - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.PrintStream; +import java.util.StringTokenizer; + +import org.apache.jasper.JasperException; +import org.apache.jasper.util.SystemLogHandler; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DefaultLogger; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.Javac; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.PatternSet; + +/** + * Main JSP compiler class. This class uses Ant for compiling. + * + * @author Anil K. Vijendran + * @author Mandar Raje + * @author Pierre Delisle + * @author Kin-man Chung + * @author Remy Maucherat + * @author Mark Roth + */ +public class AntCompiler extends Compiler { + + static { + System.setErr(new SystemLogHandler(System.err)); + } + + // ----------------------------------------------------- Instance Variables + + protected Project project=null; + protected JasperAntLogger logger; + + // ------------------------------------------------------------ Constructor + + // Lazy eval - if we don't need to compile we probably don't need the project + protected Project getProject() { + + if( project!=null ) return project; + + // Initializing project + project = new Project(); + logger = new JasperAntLogger(); + logger.setOutputPrintStream(System.out); + logger.setErrorPrintStream(System.err); + logger.setMessageOutputLevel(Project.MSG_INFO); + project.addBuildListener( logger); + if (System.getProperty("catalina.home") != null) { + project.setBasedir( System.getProperty("catalina.home")); + } + + if( options.getCompiler() != null ) { + if( log.isDebugEnabled() ) + log.debug("Compiler " + options.getCompiler() ); + project.setProperty("build.compiler", options.getCompiler() ); + } + project.init(); + return project; + } + + class JasperAntLogger extends DefaultLogger { + + protected StringBuffer reportBuf = new StringBuffer(); + + protected void printMessage(final String message, + final PrintStream stream, + final int priority) { + } + + protected void log(String message) { + reportBuf.append(message); + reportBuf.append(System.getProperty("line.separator")); + } + + protected String getReport() { + String report = reportBuf.toString(); + reportBuf.setLength(0); + return report; + } + } + + // --------------------------------------------------------- Public Methods + + + /** + * Compile the servlet from .java file to .class file + */ + protected void generateClass(String[] smap) + throws FileNotFoundException, JasperException, Exception { + + long t1 = 0; + if (log.isDebugEnabled()) { + t1 = System.currentTimeMillis(); + } + + String javaEncoding = ctxt.getOptions().getJavaEncoding(); + String javaFileName = ctxt.getServletJavaFileName(); + String classpath = ctxt.getClassPath(); + + String sep = System.getProperty("path.separator"); + + StringBuffer errorReport = new StringBuffer(); + + StringBuffer info=new StringBuffer(); + info.append("Compile: javaFileName=" + javaFileName + "\n" ); + info.append(" classpath=" + classpath + "\n" ); + + // Start capturing the System.err output for this thread + SystemLogHandler.setThread(); + + // Initializing javac task + getProject(); + Javac javac = (Javac) project.createTask("javac"); + + // Initializing classpath + Path path = new Path(project); + path.setPath(System.getProperty("java.class.path")); + info.append(" cp=" + System.getProperty("java.class.path") + "\n"); + StringTokenizer tokenizer = new StringTokenizer(classpath, sep); + while (tokenizer.hasMoreElements()) { + String pathElement = tokenizer.nextToken(); + File repository = new File(pathElement); + path.setLocation(repository); + info.append(" cp=" + repository + "\n"); + } + + if( log.isDebugEnabled() ) + log.debug( "Using classpath: " + System.getProperty("java.class.path") + sep + + classpath); + + // Initializing sourcepath + Path srcPath = new Path(project); + srcPath.setLocation(options.getScratchDir()); + + info.append(" work dir=" + options.getScratchDir() + "\n"); + + // Initialize and set java extensions + String exts = System.getProperty("java.ext.dirs"); + if (exts != null) { + Path extdirs = new Path(project); + extdirs.setPath(exts); + javac.setExtdirs(extdirs); + info.append(" extension dir=" + exts + "\n"); + } + + // Add endorsed directories if any are specified and we're forking + // See Bugzilla 31257 + if(ctxt.getOptions().getFork()) { + String endorsed = System.getProperty("java.endorsed.dirs"); + if(endorsed != null) { + Javac.ImplementationSpecificArgument endorsedArg = + javac.createCompilerArg(); + endorsedArg.setLine("-J-Djava.endorsed.dirs="+endorsed); + info.append(" endorsed dir=" + endorsed + "\n"); + } else { + info.append(" no endorsed dirs specified\n"); + } + } + + // Configure the compiler object + javac.setEncoding(javaEncoding); + javac.setClasspath(path); + javac.setDebug(ctxt.getOptions().getClassDebugInfo()); + javac.setSrcdir(srcPath); + javac.setTempdir(options.getScratchDir()); + javac.setOptimize(! ctxt.getOptions().getClassDebugInfo() ); + javac.setFork(ctxt.getOptions().getFork()); + info.append(" srcDir=" + srcPath + "\n" ); + + // Set the Java compiler to use + if (options.getCompiler() != null) { + javac.setCompiler(options.getCompiler()); + info.append(" compiler=" + options.getCompiler() + "\n"); + } + + if (options.getCompilerTargetVM() != null) { + javac.setTarget(options.getCompilerTargetVM()); + info.append(" compilerTargetVM=" + options.getCompilerTargetVM() + "\n"); + } + + if (options.getCompilerSourceVM() != null) { + javac.setSource(options.getCompilerSourceVM()); + info.append(" compilerSourceVM=" + options.getCompilerSourceVM() + "\n"); + } + + // Build includes path + PatternSet.NameEntry includes = javac.createInclude(); + + includes.setName(ctxt.getJavaPath()); + info.append(" include="+ ctxt.getJavaPath() + "\n" ); + + BuildException be = null; + + try { + if (ctxt.getOptions().getFork()) { + javac.execute(); + } else { + synchronized(javacLock) { + javac.execute(); + } + } + } catch (BuildException e) { + be = e; + log.error( "Javac exception ", e); + log.error( "Env: " + info.toString()); + } + + errorReport.append(logger.getReport()); + + // Stop capturing the System.err output for this thread + String errorCapture = SystemLogHandler.unsetThread(); + if (errorCapture != null) { + errorReport.append(System.getProperty("line.separator")); + errorReport.append(errorCapture); + } + + if (!ctxt.keepGenerated()) { + File javaFile = new File(javaFileName); + javaFile.delete(); + } + + if (be != null) { + String errorReportString = errorReport.toString(); + log.error("Error compiling file: " + javaFileName + " " + + errorReportString); + JavacErrorDetail[] javacErrors = ErrorDispatcher.parseJavacErrors( + errorReportString, javaFileName, pageNodes); + if (javacErrors != null) { + errDispatcher.javacError(javacErrors); + } else { + errDispatcher.javacError(errorReportString, be); + } + } + + if( log.isDebugEnabled() ) { + long t2=System.currentTimeMillis(); + log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + + (t2-t1) + "ms"); + } + + logger = null; + project = null; + + if (ctxt.isPrototypeMode()) { + return; + } + + // JSR45 Support + if (! options.isSmapSuppressed()) { + SmapUtil.installSmap(smap); + } + } + + +} diff --git a/java/org/apache/jasper/compiler/BeanRepository.java b/java/org/apache/jasper/compiler/BeanRepository.java index c7b05ca8a..f31cadb5d 100644 --- a/java/org/apache/jasper/compiler/BeanRepository.java +++ b/java/org/apache/jasper/compiler/BeanRepository.java @@ -1,114 +1,114 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - - -import java.util.Vector; -import java.util.Hashtable; - -import org.apache.jasper.JasperException; - -/** - * Repository of {page, request, session, application}-scoped beans - * - * @author Mandar Raje - */ -class BeanRepository { - - private Vector sessionBeans; - private Vector pageBeans; - private Vector appBeans; - private Vector requestBeans; - private Hashtable beanTypes; - private ClassLoader loader; - private ErrorDispatcher errDispatcher; - - /* - * Constructor. - */ - public BeanRepository(ClassLoader loader, ErrorDispatcher err) { - - this.loader = loader; - this.errDispatcher = err; - - sessionBeans = new Vector(11); - pageBeans = new Vector(11); - appBeans = new Vector(11); - requestBeans = new Vector(11); - beanTypes = new Hashtable(); - } - - public void addBean(Node.UseBean n, String s, String type, String scope) - throws JasperException { - - if (scope == null || scope.equals("page")) { - pageBeans.addElement(s); - } else if (scope.equals("request")) { - requestBeans.addElement(s); - } else if (scope.equals("session")) { - sessionBeans.addElement(s); - } else if (scope.equals("application")) { - appBeans.addElement(s); - } else { - errDispatcher.jspError(n, "jsp.error.usebean.badScope"); - } - - putBeanType(s, type); - } - - public Class getBeanType(String bean) throws JasperException { - Class clazz = null; - try { - clazz = loader.loadClass ((String)beanTypes.get(bean)); - } catch (ClassNotFoundException ex) { - throw new JasperException (ex); - } - return clazz; - } - - public boolean checkVariable (String bean) { - // XXX Not sure if this is the correct way. - // After pageContext is finalised this will change. - return (checkPageBean(bean) || checkSessionBean(bean) || - checkRequestBean(bean) || checkApplicationBean(bean)); - } - - - private void putBeanType(String bean, String type) { - beanTypes.put (bean, type); - } - - private boolean checkPageBean (String s) { - return pageBeans.contains (s); - } - - private boolean checkRequestBean (String s) { - return requestBeans.contains (s); - } - - private boolean checkSessionBean (String s) { - return sessionBeans.contains (s); - } - - private boolean checkApplicationBean (String s) { - return appBeans.contains (s); - } - -} - - - - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + + +import java.util.Vector; +import java.util.Hashtable; + +import org.apache.jasper.JasperException; + +/** + * Repository of {page, request, session, application}-scoped beans + * + * @author Mandar Raje + */ +class BeanRepository { + + private Vector sessionBeans; + private Vector pageBeans; + private Vector appBeans; + private Vector requestBeans; + private Hashtable beanTypes; + private ClassLoader loader; + private ErrorDispatcher errDispatcher; + + /* + * Constructor. + */ + public BeanRepository(ClassLoader loader, ErrorDispatcher err) { + + this.loader = loader; + this.errDispatcher = err; + + sessionBeans = new Vector(11); + pageBeans = new Vector(11); + appBeans = new Vector(11); + requestBeans = new Vector(11); + beanTypes = new Hashtable(); + } + + public void addBean(Node.UseBean n, String s, String type, String scope) + throws JasperException { + + if (scope == null || scope.equals("page")) { + pageBeans.addElement(s); + } else if (scope.equals("request")) { + requestBeans.addElement(s); + } else if (scope.equals("session")) { + sessionBeans.addElement(s); + } else if (scope.equals("application")) { + appBeans.addElement(s); + } else { + errDispatcher.jspError(n, "jsp.error.usebean.badScope"); + } + + putBeanType(s, type); + } + + public Class getBeanType(String bean) throws JasperException { + Class clazz = null; + try { + clazz = loader.loadClass ((String)beanTypes.get(bean)); + } catch (ClassNotFoundException ex) { + throw new JasperException (ex); + } + return clazz; + } + + public boolean checkVariable (String bean) { + // XXX Not sure if this is the correct way. + // After pageContext is finalised this will change. + return (checkPageBean(bean) || checkSessionBean(bean) || + checkRequestBean(bean) || checkApplicationBean(bean)); + } + + + private void putBeanType(String bean, String type) { + beanTypes.put (bean, type); + } + + private boolean checkPageBean (String s) { + return pageBeans.contains (s); + } + + private boolean checkRequestBean (String s) { + return requestBeans.contains (s); + } + + private boolean checkSessionBean (String s) { + return sessionBeans.contains (s); + } + + private boolean checkApplicationBean (String s) { + return appBeans.contains (s); + } + +} + + + + diff --git a/java/org/apache/jasper/compiler/Collector.java b/java/org/apache/jasper/compiler/Collector.java index a3f0d8204..3f720c854 100644 --- a/java/org/apache/jasper/compiler/Collector.java +++ b/java/org/apache/jasper/compiler/Collector.java @@ -1,203 +1,203 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import org.apache.jasper.JasperException; - -/** - * Collect info about the page and nodes, and make them availabe through - * the PageInfo object. - * - * @author Kin-man Chung - * @author Mark Roth - */ - -class Collector { - - /** - * A visitor for collecting information on the page and the body of - * the custom tags. - */ - static class CollectVisitor extends Node.Visitor { - - private boolean scriptingElementSeen = false; - private boolean usebeanSeen = false; - private boolean includeActionSeen = false; - private boolean paramActionSeen = false; - private boolean setPropertySeen = false; - private boolean hasScriptingVars = false; - - public void visit(Node.ParamAction n) throws JasperException { - if (n.getValue().isExpression()) { - scriptingElementSeen = true; - } - paramActionSeen = true; - } - - public void visit(Node.IncludeAction n) throws JasperException { - if (n.getPage().isExpression()) { - scriptingElementSeen = true; - } - includeActionSeen = true; - visitBody(n); - } - - public void visit(Node.ForwardAction n) throws JasperException { - if (n.getPage().isExpression()) { - scriptingElementSeen = true; - } - visitBody(n); - } - - public void visit(Node.SetProperty n) throws JasperException { - if (n.getValue() != null && n.getValue().isExpression()) { - scriptingElementSeen = true; - } - setPropertySeen = true; - } - - public void visit(Node.UseBean n) throws JasperException { - if (n.getBeanName() != null && n.getBeanName().isExpression()) { - scriptingElementSeen = true; - } - usebeanSeen = true; - visitBody(n); - } - - public void visit(Node.PlugIn n) throws JasperException { - if (n.getHeight() != null && n.getHeight().isExpression()) { - scriptingElementSeen = true; - } - if (n.getWidth() != null && n.getWidth().isExpression()) { - scriptingElementSeen = true; - } - visitBody(n); - } - - public void visit(Node.CustomTag n) throws JasperException { - // Check to see what kinds of element we see as child elements - checkSeen( n.getChildInfo(), n ); - } - - /** - * Check all child nodes for various elements and update the given - * ChildInfo object accordingly. Visits body in the process. - */ - private void checkSeen( Node.ChildInfo ci, Node n ) - throws JasperException - { - // save values collected so far - boolean scriptingElementSeenSave = scriptingElementSeen; - scriptingElementSeen = false; - boolean usebeanSeenSave = usebeanSeen; - usebeanSeen = false; - boolean includeActionSeenSave = includeActionSeen; - includeActionSeen = false; - boolean paramActionSeenSave = paramActionSeen; - paramActionSeen = false; - boolean setPropertySeenSave = setPropertySeen; - setPropertySeen = false; - boolean hasScriptingVarsSave = hasScriptingVars; - hasScriptingVars = false; - - // Scan attribute list for expressions - if( n instanceof Node.CustomTag ) { - Node.CustomTag ct = (Node.CustomTag)n; - Node.JspAttribute[] attrs = ct.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - if (attrs[i].isExpression()) { - scriptingElementSeen = true; - break; - } - } - } - - visitBody(n); - - if( (n instanceof Node.CustomTag) && !hasScriptingVars) { - Node.CustomTag ct = (Node.CustomTag)n; - hasScriptingVars = ct.getVariableInfos().length > 0 || - ct.getTagVariableInfos().length > 0; - } - - // Record if the tag element and its body contains any scriptlet. - ci.setScriptless(! scriptingElementSeen); - ci.setHasUseBean(usebeanSeen); - ci.setHasIncludeAction(includeActionSeen); - ci.setHasParamAction(paramActionSeen); - ci.setHasSetProperty(setPropertySeen); - ci.setHasScriptingVars(hasScriptingVars); - - // Propagate value of scriptingElementSeen up. - scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave; - usebeanSeen = usebeanSeen || usebeanSeenSave; - setPropertySeen = setPropertySeen || setPropertySeenSave; - includeActionSeen = includeActionSeen || includeActionSeenSave; - paramActionSeen = paramActionSeen || paramActionSeenSave; - hasScriptingVars = hasScriptingVars || hasScriptingVarsSave; - } - - public void visit(Node.JspElement n) throws JasperException { - if (n.getNameAttribute().isExpression()) - scriptingElementSeen = true; - - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; i < attrs.length; i++) { - if (attrs[i].isExpression()) { - scriptingElementSeen = true; - break; - } - } - visitBody(n); - } - - public void visit(Node.JspBody n) throws JasperException { - checkSeen( n.getChildInfo(), n ); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - checkSeen( n.getChildInfo(), n ); - } - - public void visit(Node.Declaration n) throws JasperException { - scriptingElementSeen = true; - } - - public void visit(Node.Expression n) throws JasperException { - scriptingElementSeen = true; - } - - public void visit(Node.Scriptlet n) throws JasperException { - scriptingElementSeen = true; - } - - public void updatePageInfo(PageInfo pageInfo) { - pageInfo.setScriptless(! scriptingElementSeen); - } - } - - - public static void collect(Compiler compiler, Node.Nodes page) - throws JasperException { - - CollectVisitor collectVisitor = new CollectVisitor(); - page.visit(collectVisitor); - collectVisitor.updatePageInfo(compiler.getPageInfo()); - - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import org.apache.jasper.JasperException; + +/** + * Collect info about the page and nodes, and make them availabe through + * the PageInfo object. + * + * @author Kin-man Chung + * @author Mark Roth + */ + +class Collector { + + /** + * A visitor for collecting information on the page and the body of + * the custom tags. + */ + static class CollectVisitor extends Node.Visitor { + + private boolean scriptingElementSeen = false; + private boolean usebeanSeen = false; + private boolean includeActionSeen = false; + private boolean paramActionSeen = false; + private boolean setPropertySeen = false; + private boolean hasScriptingVars = false; + + public void visit(Node.ParamAction n) throws JasperException { + if (n.getValue().isExpression()) { + scriptingElementSeen = true; + } + paramActionSeen = true; + } + + public void visit(Node.IncludeAction n) throws JasperException { + if (n.getPage().isExpression()) { + scriptingElementSeen = true; + } + includeActionSeen = true; + visitBody(n); + } + + public void visit(Node.ForwardAction n) throws JasperException { + if (n.getPage().isExpression()) { + scriptingElementSeen = true; + } + visitBody(n); + } + + public void visit(Node.SetProperty n) throws JasperException { + if (n.getValue() != null && n.getValue().isExpression()) { + scriptingElementSeen = true; + } + setPropertySeen = true; + } + + public void visit(Node.UseBean n) throws JasperException { + if (n.getBeanName() != null && n.getBeanName().isExpression()) { + scriptingElementSeen = true; + } + usebeanSeen = true; + visitBody(n); + } + + public void visit(Node.PlugIn n) throws JasperException { + if (n.getHeight() != null && n.getHeight().isExpression()) { + scriptingElementSeen = true; + } + if (n.getWidth() != null && n.getWidth().isExpression()) { + scriptingElementSeen = true; + } + visitBody(n); + } + + public void visit(Node.CustomTag n) throws JasperException { + // Check to see what kinds of element we see as child elements + checkSeen( n.getChildInfo(), n ); + } + + /** + * Check all child nodes for various elements and update the given + * ChildInfo object accordingly. Visits body in the process. + */ + private void checkSeen( Node.ChildInfo ci, Node n ) + throws JasperException + { + // save values collected so far + boolean scriptingElementSeenSave = scriptingElementSeen; + scriptingElementSeen = false; + boolean usebeanSeenSave = usebeanSeen; + usebeanSeen = false; + boolean includeActionSeenSave = includeActionSeen; + includeActionSeen = false; + boolean paramActionSeenSave = paramActionSeen; + paramActionSeen = false; + boolean setPropertySeenSave = setPropertySeen; + setPropertySeen = false; + boolean hasScriptingVarsSave = hasScriptingVars; + hasScriptingVars = false; + + // Scan attribute list for expressions + if( n instanceof Node.CustomTag ) { + Node.CustomTag ct = (Node.CustomTag)n; + Node.JspAttribute[] attrs = ct.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + if (attrs[i].isExpression()) { + scriptingElementSeen = true; + break; + } + } + } + + visitBody(n); + + if( (n instanceof Node.CustomTag) && !hasScriptingVars) { + Node.CustomTag ct = (Node.CustomTag)n; + hasScriptingVars = ct.getVariableInfos().length > 0 || + ct.getTagVariableInfos().length > 0; + } + + // Record if the tag element and its body contains any scriptlet. + ci.setScriptless(! scriptingElementSeen); + ci.setHasUseBean(usebeanSeen); + ci.setHasIncludeAction(includeActionSeen); + ci.setHasParamAction(paramActionSeen); + ci.setHasSetProperty(setPropertySeen); + ci.setHasScriptingVars(hasScriptingVars); + + // Propagate value of scriptingElementSeen up. + scriptingElementSeen = scriptingElementSeen || scriptingElementSeenSave; + usebeanSeen = usebeanSeen || usebeanSeenSave; + setPropertySeen = setPropertySeen || setPropertySeenSave; + includeActionSeen = includeActionSeen || includeActionSeenSave; + paramActionSeen = paramActionSeen || paramActionSeenSave; + hasScriptingVars = hasScriptingVars || hasScriptingVarsSave; + } + + public void visit(Node.JspElement n) throws JasperException { + if (n.getNameAttribute().isExpression()) + scriptingElementSeen = true; + + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; i < attrs.length; i++) { + if (attrs[i].isExpression()) { + scriptingElementSeen = true; + break; + } + } + visitBody(n); + } + + public void visit(Node.JspBody n) throws JasperException { + checkSeen( n.getChildInfo(), n ); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + checkSeen( n.getChildInfo(), n ); + } + + public void visit(Node.Declaration n) throws JasperException { + scriptingElementSeen = true; + } + + public void visit(Node.Expression n) throws JasperException { + scriptingElementSeen = true; + } + + public void visit(Node.Scriptlet n) throws JasperException { + scriptingElementSeen = true; + } + + public void updatePageInfo(PageInfo pageInfo) { + pageInfo.setScriptless(! scriptingElementSeen); + } + } + + + public static void collect(Compiler compiler, Node.Nodes page) + throws JasperException { + + CollectVisitor collectVisitor = new CollectVisitor(); + page.visit(collectVisitor); + collectVisitor.updatePageInfo(compiler.getPageInfo()); + + } +} + diff --git a/java/org/apache/jasper/compiler/Compiler.java b/java/org/apache/jasper/compiler/Compiler.java index 542061ee0..f2d43bf94 100644 --- a/java/org/apache/jasper/compiler/Compiler.java +++ b/java/org/apache/jasper/compiler/Compiler.java @@ -1,501 +1,501 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.net.URL; -import java.net.URLConnection; -import java.util.Iterator; -import java.util.List; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.Options; -import org.apache.jasper.servlet.JspServletWrapper; - -/** - * Main JSP compiler class. This class uses Ant for compiling. - * - * @author Anil K. Vijendran - * @author Mandar Raje - * @author Pierre Delisle - * @author Kin-man Chung - * @author Remy Maucherat - * @author Mark Roth - */ -public abstract class Compiler { - protected org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory - .getLog(Compiler.class); - - // ----------------------------------------------------------------- Static - - // Some javac are not thread safe; use a lock to serialize compilation, - static Object javacLock = new Object(); - - // ----------------------------------------------------- Instance Variables - - protected JspCompilationContext ctxt; - - protected ErrorDispatcher errDispatcher; - - protected PageInfo pageInfo; - - protected JspServletWrapper jsw; - - protected TagFileProcessor tfp; - - protected Options options; - - protected Node.Nodes pageNodes; - - // ------------------------------------------------------------ Constructor - - public void init(JspCompilationContext ctxt, JspServletWrapper jsw) { - this.jsw = jsw; - this.ctxt = ctxt; - this.options = ctxt.getOptions(); - } - - // --------------------------------------------------------- Public Methods - - /** - *

        - * Retrieves the parsed nodes of the JSP page, if they are available. May - * return null. Used in development mode for generating detailed error - * messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062. - *

        - */ - public Node.Nodes getPageNodes() { - return this.pageNodes; - } - - /** - * Compile the jsp file into equivalent servlet in .java file - * - * @return a smap for the current JSP page, if one is generated, null - * otherwise - */ - protected String[] generateJava() throws Exception { - - String[] smapStr = null; - - long t1, t2, t3, t4; - - t1 = t2 = t3 = t4 = 0; - - if (log.isDebugEnabled()) { - t1 = System.currentTimeMillis(); - } - - // Setup page info area - pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(), - errDispatcher), ctxt.getJspFile()); - - JspConfig jspConfig = options.getJspConfig(); - JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt - .getJspFile()); - - /* - * If the current uri is matched by a pattern specified in a - * jsp-property-group in web.xml, initialize pageInfo with those - * properties. - */ - if (jspProperty.isELIgnored() != null) { - pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty - .isELIgnored())); - } - if (jspProperty.isScriptingInvalid() != null) { - pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty - .isScriptingInvalid())); - } - if (jspProperty.getIncludePrelude() != null) { - pageInfo.setIncludePrelude(jspProperty.getIncludePrelude()); - } - if (jspProperty.getIncludeCoda() != null) { - pageInfo.setIncludeCoda(jspProperty.getIncludeCoda()); - } - - String javaFileName = ctxt.getServletJavaFileName(); - ServletWriter writer = null; - - try { - // Setup the ServletWriter - String javaEncoding = ctxt.getOptions().getJavaEncoding(); - OutputStreamWriter osw = null; - - try { - osw = new OutputStreamWriter( - new FileOutputStream(javaFileName), javaEncoding); - } catch (UnsupportedEncodingException ex) { - errDispatcher.jspError("jsp.error.needAlternateJavaEncoding", - javaEncoding); - } - - writer = new ServletWriter(new PrintWriter(osw)); - ctxt.setWriter(writer); - - // Reset the temporary variable counter for the generator. - JspUtil.resetTemporaryVariableName(); - - // Parse the file - ParserController parserCtl = new ParserController(ctxt, this); - pageNodes = parserCtl.parse(ctxt.getJspFile()); - - if (ctxt.isPrototypeMode()) { - // generate prototype .java file for the tag file - Generator.generate(writer, this, pageNodes); - writer.close(); - writer = null; - return null; - } - - // Validate and process attributes - Validator.validate(this, pageNodes); - - if (log.isDebugEnabled()) { - t2 = System.currentTimeMillis(); - } - - // Collect page info - Collector.collect(this, pageNodes); - - // Compile (if necessary) and load the tag files referenced in - // this compilation unit. - tfp = new TagFileProcessor(); - tfp.loadTagFiles(this, pageNodes); - - if (log.isDebugEnabled()) { - t3 = System.currentTimeMillis(); - } - - // Determine which custom tag needs to declare which scripting vars - ScriptingVariabler.set(pageNodes, errDispatcher); - - // Optimizations by Tag Plugins - TagPluginManager tagPluginManager = options.getTagPluginManager(); - tagPluginManager.apply(pageNodes, errDispatcher, pageInfo); - - // Optimization: concatenate contiguous template texts. - TextOptimizer.concatenate(this, pageNodes); - - // Generate static function mapper codes. - ELFunctionMapper.map(this, pageNodes); - - // generate servlet .java file - Generator.generate(writer, this, pageNodes); - writer.close(); - writer = null; - - // The writer is only used during the compile, dereference - // it in the JspCompilationContext when done to allow it - // to be GC'd and save memory. - ctxt.setWriter(null); - - if (log.isDebugEnabled()) { - t4 = System.currentTimeMillis(); - log.debug("Generated " + javaFileName + " total=" + (t4 - t1) - + " generate=" + (t4 - t3) + " validate=" + (t2 - t1)); - } - - } catch (Exception e) { - if (writer != null) { - try { - writer.close(); - writer = null; - } catch (Exception e1) { - // do nothing - } - } - // Remove the generated .java file - new File(javaFileName).delete(); - throw e; - } finally { - if (writer != null) { - try { - writer.close(); - } catch (Exception e2) { - // do nothing - } - } - } - - // JSR45 Support - if (!options.isSmapSuppressed()) { - smapStr = SmapUtil.generateSmap(ctxt, pageNodes); - } - - // If any proto type .java and .class files was generated, - // the prototype .java may have been replaced by the current - // compilation (if the tag file is self referencing), but the - // .class file need to be removed, to make sure that javac would - // generate .class again from the new .java file just generated. - tfp.removeProtoTypeFiles(ctxt.getClassFileName()); - - return smapStr; - } - - /** - * Compile the servlet from .java file to .class file - */ - protected abstract void generateClass(String[] smap) - throws FileNotFoundException, JasperException, Exception; - - /** - * Compile the jsp file from the current engine context - */ - public void compile() throws FileNotFoundException, JasperException, - Exception { - compile(true); - } - - /** - * Compile the jsp file from the current engine context. As an side- effect, - * tag files that are referenced by this page are also compiled. - * - * @param compileClass - * If true, generate both .java and .class file If false, - * generate only .java file - */ - public void compile(boolean compileClass) throws FileNotFoundException, - JasperException, Exception { - compile(compileClass, false); - } - - /** - * Compile the jsp file from the current engine context. As an side- effect, - * tag files that are referenced by this page are also compiled. - * - * @param compileClass - * If true, generate both .java and .class file If false, - * generate only .java file - * @param jspcMode - * true if invoked from JspC, false otherwise - */ - public void compile(boolean compileClass, boolean jspcMode) - throws FileNotFoundException, JasperException, Exception { - if (errDispatcher == null) { - this.errDispatcher = new ErrorDispatcher(jspcMode); - } - - try { - String[] smap = generateJava(); - if (compileClass) { - generateClass(smap); - } - } finally { - if (tfp != null) { - tfp.removeProtoTypeFiles(null); - } - // Make sure these object which are only used during the - // generation and compilation of the JSP page get - // dereferenced so that they can be GC'd and reduce the - // memory footprint. - tfp = null; - errDispatcher = null; - pageInfo = null; - - // Only get rid of the pageNodes if in production. - // In development mode, they are used for detailed - // error messages. - // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 - if (!this.options.getDevelopment()) { - pageNodes = null; - } - - if (ctxt.getWriter() != null) { - ctxt.getWriter().close(); - ctxt.setWriter(null); - } - } - } - - /** - * This is a protected method intended to be overridden by subclasses of - * Compiler. This is used by the compile method to do all the compilation. - */ - public boolean isOutDated() { - return isOutDated(true); - } - - /** - * Determine if a compilation is necessary by checking the time stamp of the - * JSP page with that of the corresponding .class or .java file. If the page - * has dependencies, the check is also extended to its dependeants, and so - * on. This method can by overidden by a subclasses of Compiler. - * - * @param checkClass - * If true, check against .class file, if false, check against - * .java file. - */ - public boolean isOutDated(boolean checkClass) { - - String jsp = ctxt.getJspFile(); - - if (jsw != null - && (ctxt.getOptions().getModificationTestInterval() > 0)) { - - if (jsw.getLastModificationTest() - + (ctxt.getOptions().getModificationTestInterval() * 1000) > System - .currentTimeMillis()) { - return false; - } else { - jsw.setLastModificationTest(System.currentTimeMillis()); - } - } - - long jspRealLastModified = 0; - try { - URL jspUrl = ctxt.getResource(jsp); - if (jspUrl == null) { - ctxt.incrementRemoved(); - return false; - } - URLConnection uc = jspUrl.openConnection(); - jspRealLastModified = uc.getLastModified(); - uc.getInputStream().close(); - } catch (Exception e) { - e.printStackTrace(); - return true; - } - - long targetLastModified = 0; - File targetFile; - - if (checkClass) { - targetFile = new File(ctxt.getClassFileName()); - } else { - targetFile = new File(ctxt.getServletJavaFileName()); - } - - if (!targetFile.exists()) { - return true; - } - - targetLastModified = targetFile.lastModified(); - if (checkClass && jsw != null) { - jsw.setServletClassLastModifiedTime(targetLastModified); - } - if (targetLastModified < jspRealLastModified) { - if (log.isDebugEnabled()) { - log.debug("Compiler: outdated: " + targetFile + " " - + targetLastModified); - } - return true; - } - - // determine if source dependent files (e.g. includes using include - // directives) have been changed. - if (jsw == null) { - return false; - } - - List depends = jsw.getDependants(); - if (depends == null) { - return false; - } - - Iterator it = depends.iterator(); - while (it.hasNext()) { - String include = (String) it.next(); - try { - URL includeUrl = ctxt.getResource(include); - if (includeUrl == null) { - return true; - } - - URLConnection includeUconn = includeUrl.openConnection(); - long includeLastModified = includeUconn.getLastModified(); - includeUconn.getInputStream().close(); - - if (includeLastModified > targetLastModified) { - return true; - } - } catch (Exception e) { - e.printStackTrace(); - return true; - } - } - - return false; - - } - - /** - * Gets the error dispatcher. - */ - public ErrorDispatcher getErrorDispatcher() { - return errDispatcher; - } - - /** - * Gets the info about the page under compilation - */ - public PageInfo getPageInfo() { - return pageInfo; - } - - public JspCompilationContext getCompilationContext() { - return ctxt; - } - - /** - * Remove generated files - */ - public void removeGeneratedFiles() { - try { - String classFileName = ctxt.getClassFileName(); - if (classFileName != null) { - File classFile = new File(classFileName); - if (log.isDebugEnabled()) - log.debug("Deleting " + classFile); - classFile.delete(); - } - } catch (Exception e) { - // Remove as much as possible, ignore possible exceptions - } - try { - String javaFileName = ctxt.getServletJavaFileName(); - if (javaFileName != null) { - File javaFile = new File(javaFileName); - if (log.isDebugEnabled()) - log.debug("Deleting " + javaFile); - javaFile.delete(); - } - } catch (Exception e) { - // Remove as much as possible, ignore possible exceptions - } - } - - public void removeGeneratedClassFiles() { - try { - String classFileName = ctxt.getClassFileName(); - if (classFileName != null) { - File classFile = new File(classFileName); - if (log.isDebugEnabled()) - log.debug("Deleting " + classFile); - classFile.delete(); - } - } catch (Exception e) { - // Remove as much as possible, ignore possible exceptions - } - } -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.List; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.Options; +import org.apache.jasper.servlet.JspServletWrapper; + +/** + * Main JSP compiler class. This class uses Ant for compiling. + * + * @author Anil K. Vijendran + * @author Mandar Raje + * @author Pierre Delisle + * @author Kin-man Chung + * @author Remy Maucherat + * @author Mark Roth + */ +public abstract class Compiler { + protected org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory + .getLog(Compiler.class); + + // ----------------------------------------------------------------- Static + + // Some javac are not thread safe; use a lock to serialize compilation, + static Object javacLock = new Object(); + + // ----------------------------------------------------- Instance Variables + + protected JspCompilationContext ctxt; + + protected ErrorDispatcher errDispatcher; + + protected PageInfo pageInfo; + + protected JspServletWrapper jsw; + + protected TagFileProcessor tfp; + + protected Options options; + + protected Node.Nodes pageNodes; + + // ------------------------------------------------------------ Constructor + + public void init(JspCompilationContext ctxt, JspServletWrapper jsw) { + this.jsw = jsw; + this.ctxt = ctxt; + this.options = ctxt.getOptions(); + } + + // --------------------------------------------------------- Public Methods + + /** + *

        + * Retrieves the parsed nodes of the JSP page, if they are available. May + * return null. Used in development mode for generating detailed error + * messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062. + *

        + */ + public Node.Nodes getPageNodes() { + return this.pageNodes; + } + + /** + * Compile the jsp file into equivalent servlet in .java file + * + * @return a smap for the current JSP page, if one is generated, null + * otherwise + */ + protected String[] generateJava() throws Exception { + + String[] smapStr = null; + + long t1, t2, t3, t4; + + t1 = t2 = t3 = t4 = 0; + + if (log.isDebugEnabled()) { + t1 = System.currentTimeMillis(); + } + + // Setup page info area + pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(), + errDispatcher), ctxt.getJspFile()); + + JspConfig jspConfig = options.getJspConfig(); + JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt + .getJspFile()); + + /* + * If the current uri is matched by a pattern specified in a + * jsp-property-group in web.xml, initialize pageInfo with those + * properties. + */ + if (jspProperty.isELIgnored() != null) { + pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty + .isELIgnored())); + } + if (jspProperty.isScriptingInvalid() != null) { + pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty + .isScriptingInvalid())); + } + if (jspProperty.getIncludePrelude() != null) { + pageInfo.setIncludePrelude(jspProperty.getIncludePrelude()); + } + if (jspProperty.getIncludeCoda() != null) { + pageInfo.setIncludeCoda(jspProperty.getIncludeCoda()); + } + + String javaFileName = ctxt.getServletJavaFileName(); + ServletWriter writer = null; + + try { + // Setup the ServletWriter + String javaEncoding = ctxt.getOptions().getJavaEncoding(); + OutputStreamWriter osw = null; + + try { + osw = new OutputStreamWriter( + new FileOutputStream(javaFileName), javaEncoding); + } catch (UnsupportedEncodingException ex) { + errDispatcher.jspError("jsp.error.needAlternateJavaEncoding", + javaEncoding); + } + + writer = new ServletWriter(new PrintWriter(osw)); + ctxt.setWriter(writer); + + // Reset the temporary variable counter for the generator. + JspUtil.resetTemporaryVariableName(); + + // Parse the file + ParserController parserCtl = new ParserController(ctxt, this); + pageNodes = parserCtl.parse(ctxt.getJspFile()); + + if (ctxt.isPrototypeMode()) { + // generate prototype .java file for the tag file + Generator.generate(writer, this, pageNodes); + writer.close(); + writer = null; + return null; + } + + // Validate and process attributes + Validator.validate(this, pageNodes); + + if (log.isDebugEnabled()) { + t2 = System.currentTimeMillis(); + } + + // Collect page info + Collector.collect(this, pageNodes); + + // Compile (if necessary) and load the tag files referenced in + // this compilation unit. + tfp = new TagFileProcessor(); + tfp.loadTagFiles(this, pageNodes); + + if (log.isDebugEnabled()) { + t3 = System.currentTimeMillis(); + } + + // Determine which custom tag needs to declare which scripting vars + ScriptingVariabler.set(pageNodes, errDispatcher); + + // Optimizations by Tag Plugins + TagPluginManager tagPluginManager = options.getTagPluginManager(); + tagPluginManager.apply(pageNodes, errDispatcher, pageInfo); + + // Optimization: concatenate contiguous template texts. + TextOptimizer.concatenate(this, pageNodes); + + // Generate static function mapper codes. + ELFunctionMapper.map(this, pageNodes); + + // generate servlet .java file + Generator.generate(writer, this, pageNodes); + writer.close(); + writer = null; + + // The writer is only used during the compile, dereference + // it in the JspCompilationContext when done to allow it + // to be GC'd and save memory. + ctxt.setWriter(null); + + if (log.isDebugEnabled()) { + t4 = System.currentTimeMillis(); + log.debug("Generated " + javaFileName + " total=" + (t4 - t1) + + " generate=" + (t4 - t3) + " validate=" + (t2 - t1)); + } + + } catch (Exception e) { + if (writer != null) { + try { + writer.close(); + writer = null; + } catch (Exception e1) { + // do nothing + } + } + // Remove the generated .java file + new File(javaFileName).delete(); + throw e; + } finally { + if (writer != null) { + try { + writer.close(); + } catch (Exception e2) { + // do nothing + } + } + } + + // JSR45 Support + if (!options.isSmapSuppressed()) { + smapStr = SmapUtil.generateSmap(ctxt, pageNodes); + } + + // If any proto type .java and .class files was generated, + // the prototype .java may have been replaced by the current + // compilation (if the tag file is self referencing), but the + // .class file need to be removed, to make sure that javac would + // generate .class again from the new .java file just generated. + tfp.removeProtoTypeFiles(ctxt.getClassFileName()); + + return smapStr; + } + + /** + * Compile the servlet from .java file to .class file + */ + protected abstract void generateClass(String[] smap) + throws FileNotFoundException, JasperException, Exception; + + /** + * Compile the jsp file from the current engine context + */ + public void compile() throws FileNotFoundException, JasperException, + Exception { + compile(true); + } + + /** + * Compile the jsp file from the current engine context. As an side- effect, + * tag files that are referenced by this page are also compiled. + * + * @param compileClass + * If true, generate both .java and .class file If false, + * generate only .java file + */ + public void compile(boolean compileClass) throws FileNotFoundException, + JasperException, Exception { + compile(compileClass, false); + } + + /** + * Compile the jsp file from the current engine context. As an side- effect, + * tag files that are referenced by this page are also compiled. + * + * @param compileClass + * If true, generate both .java and .class file If false, + * generate only .java file + * @param jspcMode + * true if invoked from JspC, false otherwise + */ + public void compile(boolean compileClass, boolean jspcMode) + throws FileNotFoundException, JasperException, Exception { + if (errDispatcher == null) { + this.errDispatcher = new ErrorDispatcher(jspcMode); + } + + try { + String[] smap = generateJava(); + if (compileClass) { + generateClass(smap); + } + } finally { + if (tfp != null) { + tfp.removeProtoTypeFiles(null); + } + // Make sure these object which are only used during the + // generation and compilation of the JSP page get + // dereferenced so that they can be GC'd and reduce the + // memory footprint. + tfp = null; + errDispatcher = null; + pageInfo = null; + + // Only get rid of the pageNodes if in production. + // In development mode, they are used for detailed + // error messages. + // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 + if (!this.options.getDevelopment()) { + pageNodes = null; + } + + if (ctxt.getWriter() != null) { + ctxt.getWriter().close(); + ctxt.setWriter(null); + } + } + } + + /** + * This is a protected method intended to be overridden by subclasses of + * Compiler. This is used by the compile method to do all the compilation. + */ + public boolean isOutDated() { + return isOutDated(true); + } + + /** + * Determine if a compilation is necessary by checking the time stamp of the + * JSP page with that of the corresponding .class or .java file. If the page + * has dependencies, the check is also extended to its dependeants, and so + * on. This method can by overidden by a subclasses of Compiler. + * + * @param checkClass + * If true, check against .class file, if false, check against + * .java file. + */ + public boolean isOutDated(boolean checkClass) { + + String jsp = ctxt.getJspFile(); + + if (jsw != null + && (ctxt.getOptions().getModificationTestInterval() > 0)) { + + if (jsw.getLastModificationTest() + + (ctxt.getOptions().getModificationTestInterval() * 1000) > System + .currentTimeMillis()) { + return false; + } else { + jsw.setLastModificationTest(System.currentTimeMillis()); + } + } + + long jspRealLastModified = 0; + try { + URL jspUrl = ctxt.getResource(jsp); + if (jspUrl == null) { + ctxt.incrementRemoved(); + return false; + } + URLConnection uc = jspUrl.openConnection(); + jspRealLastModified = uc.getLastModified(); + uc.getInputStream().close(); + } catch (Exception e) { + e.printStackTrace(); + return true; + } + + long targetLastModified = 0; + File targetFile; + + if (checkClass) { + targetFile = new File(ctxt.getClassFileName()); + } else { + targetFile = new File(ctxt.getServletJavaFileName()); + } + + if (!targetFile.exists()) { + return true; + } + + targetLastModified = targetFile.lastModified(); + if (checkClass && jsw != null) { + jsw.setServletClassLastModifiedTime(targetLastModified); + } + if (targetLastModified < jspRealLastModified) { + if (log.isDebugEnabled()) { + log.debug("Compiler: outdated: " + targetFile + " " + + targetLastModified); + } + return true; + } + + // determine if source dependent files (e.g. includes using include + // directives) have been changed. + if (jsw == null) { + return false; + } + + List depends = jsw.getDependants(); + if (depends == null) { + return false; + } + + Iterator it = depends.iterator(); + while (it.hasNext()) { + String include = (String) it.next(); + try { + URL includeUrl = ctxt.getResource(include); + if (includeUrl == null) { + return true; + } + + URLConnection includeUconn = includeUrl.openConnection(); + long includeLastModified = includeUconn.getLastModified(); + includeUconn.getInputStream().close(); + + if (includeLastModified > targetLastModified) { + return true; + } + } catch (Exception e) { + e.printStackTrace(); + return true; + } + } + + return false; + + } + + /** + * Gets the error dispatcher. + */ + public ErrorDispatcher getErrorDispatcher() { + return errDispatcher; + } + + /** + * Gets the info about the page under compilation + */ + public PageInfo getPageInfo() { + return pageInfo; + } + + public JspCompilationContext getCompilationContext() { + return ctxt; + } + + /** + * Remove generated files + */ + public void removeGeneratedFiles() { + try { + String classFileName = ctxt.getClassFileName(); + if (classFileName != null) { + File classFile = new File(classFileName); + if (log.isDebugEnabled()) + log.debug("Deleting " + classFile); + classFile.delete(); + } + } catch (Exception e) { + // Remove as much as possible, ignore possible exceptions + } + try { + String javaFileName = ctxt.getServletJavaFileName(); + if (javaFileName != null) { + File javaFile = new File(javaFileName); + if (log.isDebugEnabled()) + log.debug("Deleting " + javaFile); + javaFile.delete(); + } + } catch (Exception e) { + // Remove as much as possible, ignore possible exceptions + } + } + + public void removeGeneratedClassFiles() { + try { + String classFileName = ctxt.getClassFileName(); + if (classFileName != null) { + File classFile = new File(classFileName); + if (log.isDebugEnabled()) + log.debug("Deleting " + classFile); + classFile.delete(); + } + } catch (Exception e) { + // Remove as much as possible, ignore possible exceptions + } + } +} diff --git a/java/org/apache/jasper/compiler/DefaultErrorHandler.java b/java/org/apache/jasper/compiler/DefaultErrorHandler.java index f12cb90e0..c1b47b551 100644 --- a/java/org/apache/jasper/compiler/DefaultErrorHandler.java +++ b/java/org/apache/jasper/compiler/DefaultErrorHandler.java @@ -1,100 +1,100 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import org.apache.jasper.JasperException; - -/** - * Default implementation of ErrorHandler interface. - * - * @author Jan Luehe - */ -class DefaultErrorHandler implements ErrorHandler { - - /* - * Processes the given JSP parse error. - * - * @param fname Name of the JSP file in which the parse error occurred - * @param line Parse error line number - * @param column Parse error column number - * @param errMsg Parse error message - * @param exception Parse exception - */ - public void jspError(String fname, int line, int column, String errMsg, - Exception ex) throws JasperException { - throw new JasperException(fname + "(" + line + "," + column + ")" - + " " + errMsg, ex); - } - - /* - * Processes the given JSP parse error. - * - * @param errMsg Parse error message - * @param exception Parse exception - */ - public void jspError(String errMsg, Exception ex) throws JasperException { - throw new JasperException(errMsg, ex); - } - - /* - * Processes the given javac compilation errors. - * - * @param details Array of JavacErrorDetail instances corresponding to the - * compilation errors - */ - public void javacError(JavacErrorDetail[] details) throws JasperException { - - if (details == null) { - return; - } - - Object[] args = null; - StringBuffer buf = new StringBuffer(); - - for (int i=0; i < details.length; i++) { - if (details[i].getJspBeginLineNumber() >= 0) { - args = new Object[] { - new Integer(details[i].getJspBeginLineNumber()), - details[i].getJspFileName() }; - buf.append(Localizer.getMessage("jsp.error.single.line.number", - args)); - buf.append("\n"); - } - - buf.append( - Localizer.getMessage("jsp.error.corresponding.servlet")); - buf.append(details[i].getErrorMessage()); - buf.append("\n\n"); - } - - throw new JasperException(Localizer.getMessage("jsp.error.unable.compile") + "\n\n" + buf); - } - - /** - * Processes the given javac error report and exception. - * - * @param errorReport Compilation error report - * @param exception Compilation exception - */ - public void javacError(String errorReport, Exception exception) - throws JasperException { - - throw new JasperException( - Localizer.getMessage("jsp.error.unable.compile"), exception); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import org.apache.jasper.JasperException; + +/** + * Default implementation of ErrorHandler interface. + * + * @author Jan Luehe + */ +class DefaultErrorHandler implements ErrorHandler { + + /* + * Processes the given JSP parse error. + * + * @param fname Name of the JSP file in which the parse error occurred + * @param line Parse error line number + * @param column Parse error column number + * @param errMsg Parse error message + * @param exception Parse exception + */ + public void jspError(String fname, int line, int column, String errMsg, + Exception ex) throws JasperException { + throw new JasperException(fname + "(" + line + "," + column + ")" + + " " + errMsg, ex); + } + + /* + * Processes the given JSP parse error. + * + * @param errMsg Parse error message + * @param exception Parse exception + */ + public void jspError(String errMsg, Exception ex) throws JasperException { + throw new JasperException(errMsg, ex); + } + + /* + * Processes the given javac compilation errors. + * + * @param details Array of JavacErrorDetail instances corresponding to the + * compilation errors + */ + public void javacError(JavacErrorDetail[] details) throws JasperException { + + if (details == null) { + return; + } + + Object[] args = null; + StringBuffer buf = new StringBuffer(); + + for (int i=0; i < details.length; i++) { + if (details[i].getJspBeginLineNumber() >= 0) { + args = new Object[] { + new Integer(details[i].getJspBeginLineNumber()), + details[i].getJspFileName() }; + buf.append(Localizer.getMessage("jsp.error.single.line.number", + args)); + buf.append("\n"); + } + + buf.append( + Localizer.getMessage("jsp.error.corresponding.servlet")); + buf.append(details[i].getErrorMessage()); + buf.append("\n\n"); + } + + throw new JasperException(Localizer.getMessage("jsp.error.unable.compile") + "\n\n" + buf); + } + + /** + * Processes the given javac error report and exception. + * + * @param errorReport Compilation error report + * @param exception Compilation exception + */ + public void javacError(String errorReport, Exception exception) + throws JasperException { + + throw new JasperException( + Localizer.getMessage("jsp.error.unable.compile"), exception); + } + +} diff --git a/java/org/apache/jasper/compiler/Dumper.java b/java/org/apache/jasper/compiler/Dumper.java index ff70228e5..ac4ad7f3b 100644 --- a/java/org/apache/jasper/compiler/Dumper.java +++ b/java/org/apache/jasper/compiler/Dumper.java @@ -1,206 +1,206 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import org.xml.sax.Attributes; -import org.apache.jasper.JasperException; - -class Dumper { - - static class DumpVisitor extends Node.Visitor { - private int indent = 0; - - private String getAttributes(Attributes attrs) { - if (attrs == null) - return ""; - - StringBuffer buf = new StringBuffer(); - for (int i=0; i < attrs.getLength(); i++) { - buf.append(" " + attrs.getQName(i) + "=\"" - + attrs.getValue(i) + "\""); - } - return buf.toString(); - } - - private void printString(String str) { - printIndent(); - System.out.print(str); - } - - private void printString(String prefix, char[] chars, String suffix) { - String str = null; - if (chars != null) { - str = new String(chars); - } - printString(prefix, str, suffix); - } - - private void printString(String prefix, String str, String suffix) { - printIndent(); - if (str != null) { - System.out.print(prefix + str + suffix); - } else { - System.out.print(prefix + suffix); - } - } - - private void printAttributes(String prefix, Attributes attrs, - String suffix) { - printString(prefix, getAttributes(attrs), suffix); - } - - private void dumpBody(Node n) throws JasperException { - Node.Nodes page = n.getBody(); - if (page != null) { -// indent++; - page.visit(this); -// indent--; - } - } - - public void visit(Node.PageDirective n) throws JasperException { - printAttributes("<%@ page", n.getAttributes(), "%>"); - } - - public void visit(Node.TaglibDirective n) throws JasperException { - printAttributes("<%@ taglib", n.getAttributes(), "%>"); - } - - public void visit(Node.IncludeDirective n) throws JasperException { - printAttributes("<%@ include", n.getAttributes(), "%>"); - dumpBody(n); - } - - public void visit(Node.Comment n) throws JasperException { - printString("<%--", n.getText(), "--%>"); - } - - public void visit(Node.Declaration n) throws JasperException { - printString("<%!", n.getText(), "%>"); - } - - public void visit(Node.Expression n) throws JasperException { - printString("<%=", n.getText(), "%>"); - } - - public void visit(Node.Scriptlet n) throws JasperException { - printString("<%", n.getText(), "%>"); - } - - public void visit(Node.IncludeAction n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.ForwardAction n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.GetProperty n) throws JasperException { - printAttributes(""); - } - - public void visit(Node.SetProperty n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.UseBean n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.PlugIn n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString("
        "); - } - - public void visit(Node.ParamsAction n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.ParamAction n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.JspBody n) throws JasperException { - printAttributes(""); - dumpBody(n); - printString(""); - } - - public void visit(Node.ELExpression n) throws JasperException { - printString( "${" + new String( n.getText() ) + "}" ); - } - - public void visit(Node.CustomTag n) throws JasperException { - printAttributes("<" + n.getQName(), n.getAttributes(), ">"); - dumpBody(n); - printString(""); - } - - public void visit(Node.UninterpretedTag n) throws JasperException { - String tag = n.getQName(); - printAttributes("<"+tag, n.getAttributes(), ">"); - dumpBody(n); - printString(""); - } - - public void visit(Node.TemplateText n) throws JasperException { - printString(new String(n.getText())); - } - - private void printIndent() { - for (int i=0; i < indent; i++) { - System.out.print(" "); - } - } - } - - public static void dump(Node n) { - try { - n.accept(new DumpVisitor()); - } catch (JasperException e) { - e.printStackTrace(); - } - } - - public static void dump(Node.Nodes page) { - try { - page.visit(new DumpVisitor()); - } catch (JasperException e) { - e.printStackTrace(); - } - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import org.xml.sax.Attributes; +import org.apache.jasper.JasperException; + +class Dumper { + + static class DumpVisitor extends Node.Visitor { + private int indent = 0; + + private String getAttributes(Attributes attrs) { + if (attrs == null) + return ""; + + StringBuffer buf = new StringBuffer(); + for (int i=0; i < attrs.getLength(); i++) { + buf.append(" " + attrs.getQName(i) + "=\"" + + attrs.getValue(i) + "\""); + } + return buf.toString(); + } + + private void printString(String str) { + printIndent(); + System.out.print(str); + } + + private void printString(String prefix, char[] chars, String suffix) { + String str = null; + if (chars != null) { + str = new String(chars); + } + printString(prefix, str, suffix); + } + + private void printString(String prefix, String str, String suffix) { + printIndent(); + if (str != null) { + System.out.print(prefix + str + suffix); + } else { + System.out.print(prefix + suffix); + } + } + + private void printAttributes(String prefix, Attributes attrs, + String suffix) { + printString(prefix, getAttributes(attrs), suffix); + } + + private void dumpBody(Node n) throws JasperException { + Node.Nodes page = n.getBody(); + if (page != null) { +// indent++; + page.visit(this); +// indent--; + } + } + + public void visit(Node.PageDirective n) throws JasperException { + printAttributes("<%@ page", n.getAttributes(), "%>"); + } + + public void visit(Node.TaglibDirective n) throws JasperException { + printAttributes("<%@ taglib", n.getAttributes(), "%>"); + } + + public void visit(Node.IncludeDirective n) throws JasperException { + printAttributes("<%@ include", n.getAttributes(), "%>"); + dumpBody(n); + } + + public void visit(Node.Comment n) throws JasperException { + printString("<%--", n.getText(), "--%>"); + } + + public void visit(Node.Declaration n) throws JasperException { + printString("<%!", n.getText(), "%>"); + } + + public void visit(Node.Expression n) throws JasperException { + printString("<%=", n.getText(), "%>"); + } + + public void visit(Node.Scriptlet n) throws JasperException { + printString("<%", n.getText(), "%>"); + } + + public void visit(Node.IncludeAction n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.ForwardAction n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.GetProperty n) throws JasperException { + printAttributes(""); + } + + public void visit(Node.SetProperty n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.UseBean n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.PlugIn n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString("
        "); + } + + public void visit(Node.ParamsAction n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.ParamAction n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.JspBody n) throws JasperException { + printAttributes(""); + dumpBody(n); + printString(""); + } + + public void visit(Node.ELExpression n) throws JasperException { + printString( "${" + new String( n.getText() ) + "}" ); + } + + public void visit(Node.CustomTag n) throws JasperException { + printAttributes("<" + n.getQName(), n.getAttributes(), ">"); + dumpBody(n); + printString(""); + } + + public void visit(Node.UninterpretedTag n) throws JasperException { + String tag = n.getQName(); + printAttributes("<"+tag, n.getAttributes(), ">"); + dumpBody(n); + printString(""); + } + + public void visit(Node.TemplateText n) throws JasperException { + printString(new String(n.getText())); + } + + private void printIndent() { + for (int i=0; i < indent; i++) { + System.out.print(" "); + } + } + } + + public static void dump(Node n) { + try { + n.accept(new DumpVisitor()); + } catch (JasperException e) { + e.printStackTrace(); + } + } + + public static void dump(Node.Nodes page) { + try { + page.visit(new DumpVisitor()); + } catch (JasperException e) { + e.printStackTrace(); + } + } +} + diff --git a/java/org/apache/jasper/compiler/ELFunctionMapper.java b/java/org/apache/jasper/compiler/ELFunctionMapper.java index f916183c8..173adb0c9 100644 --- a/java/org/apache/jasper/compiler/ELFunctionMapper.java +++ b/java/org/apache/jasper/compiler/ELFunctionMapper.java @@ -1,282 +1,282 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.*; -import javax.servlet.jsp.tagext.FunctionInfo; -import org.apache.jasper.JasperException; - -/** - * This class generates functions mappers for the EL expressions in the page. - * Instead of a global mapper, a mapper is used for ecah call to EL - * evaluator, thus avoiding the prefix overlapping and redefinition - * issues. - * - * @author Kin-man Chung - */ - -public class ELFunctionMapper { - static private int currFunc = 0; - private ErrorDispatcher err; - StringBuffer ds; // Contains codes to initialize the functions mappers. - StringBuffer ss; // Contains declarations of the functions mappers. - - /** - * Creates the functions mappers for all EL expressions in the JSP page. - * - * @param compiler Current compiler, mainly for accessing error dispatcher. - * @param page The current compilation unit. - */ - public static void map(Compiler compiler, Node.Nodes page) - throws JasperException { - - currFunc = 0; - ELFunctionMapper map = new ELFunctionMapper(); - map.err = compiler.getErrorDispatcher(); - map.ds = new StringBuffer(); - map.ss = new StringBuffer(); - - page.visit(map.new ELFunctionVisitor()); - - // Append the declarations to the root node - String ds = map.ds.toString(); - if (ds.length() > 0) { - Node root = page.getRoot(); - new Node.Declaration(map.ss.toString(), null, root); - new Node.Declaration("static {\n" + ds + "}\n", null, root); - } - } - - /** - * A visitor for the page. The places where EL is allowed are scanned - * for functions, and if found functions mappers are created. - */ - class ELFunctionVisitor extends Node.Visitor { - - /** - * Use a global name map to facilitate reuse of function maps. - * The key used is prefix:function:uri. - */ - private HashMap gMap = new HashMap(); - - public void visit(Node.ParamAction n) throws JasperException { - doMap(n.getValue()); - visitBody(n); - } - - public void visit(Node.IncludeAction n) throws JasperException { - doMap(n.getPage()); - visitBody(n); - } - - public void visit(Node.ForwardAction n) throws JasperException { - doMap(n.getPage()); - visitBody(n); - } - - public void visit(Node.SetProperty n) throws JasperException { - doMap(n.getValue()); - visitBody(n); - } - - public void visit(Node.UseBean n) throws JasperException { - doMap(n.getBeanName()); - visitBody(n); - } - - public void visit(Node.PlugIn n) throws JasperException { - doMap(n.getHeight()); - doMap(n.getWidth()); - visitBody(n); - } - - public void visit(Node.JspElement n) throws JasperException { - - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - doMap(attrs[i]); - } - doMap(n.getNameAttribute()); - visitBody(n); - } - - public void visit(Node.UninterpretedTag n) throws JasperException { - - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - doMap(attrs[i]); - } - visitBody(n); - } - - public void visit(Node.CustomTag n) throws JasperException { - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - doMap(attrs[i]); - } - visitBody(n); - } - - public void visit(Node.ELExpression n) throws JasperException { - doMap(n.getEL()); - } - - private void doMap(Node.JspAttribute attr) - throws JasperException { - if (attr != null) { - doMap(attr.getEL()); - } - } - - /** - * Creates function mappers, if needed, from ELNodes - */ - private void doMap(ELNode.Nodes el) - throws JasperException { - - // Only care about functions in ELNode's - class Fvisitor extends ELNode.Visitor { - ArrayList funcs = new ArrayList(); - HashMap keyMap = new HashMap(); - public void visit(ELNode.Function n) throws JasperException { - String key = n.getPrefix() + ":" + n.getName(); - if (! keyMap.containsKey(key)) { - keyMap.put(key,""); - funcs.add(n); - } - } - } - - if (el == null) { - return; - } - - // First locate all unique functions in this EL - Fvisitor fv = new Fvisitor(); - el.visit(fv); - ArrayList functions = fv.funcs; - - if (functions.size() == 0) { - return; - } - - // Reuse a previous map if possible - String decName = matchMap(functions); - if (decName != null) { - el.setMapName(decName); - return; - } - - // Generate declaration for the map statically - decName = getMapName(); - ss.append("static private org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n"); - - ds.append(" " + decName + "= "); - ds.append("org.apache.jasper.runtime.ProtectedFunctionMapper"); - - // Special case if there is only one function in the map - String funcMethod = null; - if (functions.size() == 1) { - funcMethod = ".getMapForFunction"; - } else { - ds.append(".getInstance();\n"); - funcMethod = " " + decName + ".mapFunction"; - } - - // Setup arguments for either getMapForFunction or mapFunction - for (int i = 0; i < functions.size(); i++) { - ELNode.Function f = (ELNode.Function)functions.get(i); - FunctionInfo funcInfo = f.getFunctionInfo(); - String key = f.getPrefix()+ ":" + f.getName(); - ds.append(funcMethod + "(\"" + key + "\", " + - funcInfo.getFunctionClass() + ".class, " + - '\"' + f.getMethodName() + "\", " + - "new Class[] {"); - String params[] = f.getParameters(); - for (int k = 0; k < params.length; k++) { - if (k != 0) { - ds.append(", "); - } - int iArray = params[k].indexOf('['); - if (iArray < 0) { - ds.append(params[k] + ".class"); - } - else { - String baseType = params[k].substring(0, iArray); - ds.append("java.lang.reflect.Array.newInstance("); - ds.append(baseType); - ds.append(".class,"); - - // Count the number of array dimension - int aCount = 0; - for (int jj = iArray; jj < params[k].length(); jj++ ) { - if (params[k].charAt(jj) == '[') { - aCount++; - } - } - if (aCount == 1) { - ds.append("0).getClass()"); - } else { - ds.append("new int[" + aCount + "]).getClass()"); - } - } - } - ds.append("});\n"); - // Put the current name in the global function map - gMap.put(f.getPrefix() + ':' + f.getName() + ':' + f.getUri(), - decName); - } - el.setMapName(decName); - } - - /** - * Find the name of the function mapper for an EL. Reuse a - * previously generated one if possible. - * @param functions An ArrayList of ELNode.Function instances that - * represents the functions in an EL - * @return A previous generated function mapper name that can be used - * by this EL; null if none found. - */ - private String matchMap(ArrayList functions) { - - String mapName = null; - for (int i = 0; i < functions.size(); i++) { - ELNode.Function f = (ELNode.Function)functions.get(i); - String temName = (String) gMap.get(f.getPrefix() + ':' + - f.getName() + ':' + f.getUri()); - if (temName == null) { - return null; - } - if (mapName == null) { - mapName = temName; - } else if (!temName.equals(mapName)) { - // If not all in the previous match, then no match. - return null; - } - } - return mapName; - } - - /* - * @return An unique name for a function mapper. - */ - private String getMapName() { - return "_jspx_fnmap_" + currFunc++; - } - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.*; +import javax.servlet.jsp.tagext.FunctionInfo; +import org.apache.jasper.JasperException; + +/** + * This class generates functions mappers for the EL expressions in the page. + * Instead of a global mapper, a mapper is used for ecah call to EL + * evaluator, thus avoiding the prefix overlapping and redefinition + * issues. + * + * @author Kin-man Chung + */ + +public class ELFunctionMapper { + static private int currFunc = 0; + private ErrorDispatcher err; + StringBuffer ds; // Contains codes to initialize the functions mappers. + StringBuffer ss; // Contains declarations of the functions mappers. + + /** + * Creates the functions mappers for all EL expressions in the JSP page. + * + * @param compiler Current compiler, mainly for accessing error dispatcher. + * @param page The current compilation unit. + */ + public static void map(Compiler compiler, Node.Nodes page) + throws JasperException { + + currFunc = 0; + ELFunctionMapper map = new ELFunctionMapper(); + map.err = compiler.getErrorDispatcher(); + map.ds = new StringBuffer(); + map.ss = new StringBuffer(); + + page.visit(map.new ELFunctionVisitor()); + + // Append the declarations to the root node + String ds = map.ds.toString(); + if (ds.length() > 0) { + Node root = page.getRoot(); + new Node.Declaration(map.ss.toString(), null, root); + new Node.Declaration("static {\n" + ds + "}\n", null, root); + } + } + + /** + * A visitor for the page. The places where EL is allowed are scanned + * for functions, and if found functions mappers are created. + */ + class ELFunctionVisitor extends Node.Visitor { + + /** + * Use a global name map to facilitate reuse of function maps. + * The key used is prefix:function:uri. + */ + private HashMap gMap = new HashMap(); + + public void visit(Node.ParamAction n) throws JasperException { + doMap(n.getValue()); + visitBody(n); + } + + public void visit(Node.IncludeAction n) throws JasperException { + doMap(n.getPage()); + visitBody(n); + } + + public void visit(Node.ForwardAction n) throws JasperException { + doMap(n.getPage()); + visitBody(n); + } + + public void visit(Node.SetProperty n) throws JasperException { + doMap(n.getValue()); + visitBody(n); + } + + public void visit(Node.UseBean n) throws JasperException { + doMap(n.getBeanName()); + visitBody(n); + } + + public void visit(Node.PlugIn n) throws JasperException { + doMap(n.getHeight()); + doMap(n.getWidth()); + visitBody(n); + } + + public void visit(Node.JspElement n) throws JasperException { + + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + doMap(attrs[i]); + } + doMap(n.getNameAttribute()); + visitBody(n); + } + + public void visit(Node.UninterpretedTag n) throws JasperException { + + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + doMap(attrs[i]); + } + visitBody(n); + } + + public void visit(Node.CustomTag n) throws JasperException { + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + doMap(attrs[i]); + } + visitBody(n); + } + + public void visit(Node.ELExpression n) throws JasperException { + doMap(n.getEL()); + } + + private void doMap(Node.JspAttribute attr) + throws JasperException { + if (attr != null) { + doMap(attr.getEL()); + } + } + + /** + * Creates function mappers, if needed, from ELNodes + */ + private void doMap(ELNode.Nodes el) + throws JasperException { + + // Only care about functions in ELNode's + class Fvisitor extends ELNode.Visitor { + ArrayList funcs = new ArrayList(); + HashMap keyMap = new HashMap(); + public void visit(ELNode.Function n) throws JasperException { + String key = n.getPrefix() + ":" + n.getName(); + if (! keyMap.containsKey(key)) { + keyMap.put(key,""); + funcs.add(n); + } + } + } + + if (el == null) { + return; + } + + // First locate all unique functions in this EL + Fvisitor fv = new Fvisitor(); + el.visit(fv); + ArrayList functions = fv.funcs; + + if (functions.size() == 0) { + return; + } + + // Reuse a previous map if possible + String decName = matchMap(functions); + if (decName != null) { + el.setMapName(decName); + return; + } + + // Generate declaration for the map statically + decName = getMapName(); + ss.append("static private org.apache.jasper.runtime.ProtectedFunctionMapper " + decName + ";\n"); + + ds.append(" " + decName + "= "); + ds.append("org.apache.jasper.runtime.ProtectedFunctionMapper"); + + // Special case if there is only one function in the map + String funcMethod = null; + if (functions.size() == 1) { + funcMethod = ".getMapForFunction"; + } else { + ds.append(".getInstance();\n"); + funcMethod = " " + decName + ".mapFunction"; + } + + // Setup arguments for either getMapForFunction or mapFunction + for (int i = 0; i < functions.size(); i++) { + ELNode.Function f = (ELNode.Function)functions.get(i); + FunctionInfo funcInfo = f.getFunctionInfo(); + String key = f.getPrefix()+ ":" + f.getName(); + ds.append(funcMethod + "(\"" + key + "\", " + + funcInfo.getFunctionClass() + ".class, " + + '\"' + f.getMethodName() + "\", " + + "new Class[] {"); + String params[] = f.getParameters(); + for (int k = 0; k < params.length; k++) { + if (k != 0) { + ds.append(", "); + } + int iArray = params[k].indexOf('['); + if (iArray < 0) { + ds.append(params[k] + ".class"); + } + else { + String baseType = params[k].substring(0, iArray); + ds.append("java.lang.reflect.Array.newInstance("); + ds.append(baseType); + ds.append(".class,"); + + // Count the number of array dimension + int aCount = 0; + for (int jj = iArray; jj < params[k].length(); jj++ ) { + if (params[k].charAt(jj) == '[') { + aCount++; + } + } + if (aCount == 1) { + ds.append("0).getClass()"); + } else { + ds.append("new int[" + aCount + "]).getClass()"); + } + } + } + ds.append("});\n"); + // Put the current name in the global function map + gMap.put(f.getPrefix() + ':' + f.getName() + ':' + f.getUri(), + decName); + } + el.setMapName(decName); + } + + /** + * Find the name of the function mapper for an EL. Reuse a + * previously generated one if possible. + * @param functions An ArrayList of ELNode.Function instances that + * represents the functions in an EL + * @return A previous generated function mapper name that can be used + * by this EL; null if none found. + */ + private String matchMap(ArrayList functions) { + + String mapName = null; + for (int i = 0; i < functions.size(); i++) { + ELNode.Function f = (ELNode.Function)functions.get(i); + String temName = (String) gMap.get(f.getPrefix() + ':' + + f.getName() + ':' + f.getUri()); + if (temName == null) { + return null; + } + if (mapName == null) { + mapName = temName; + } else if (!temName.equals(mapName)) { + // If not all in the previous match, then no match. + return null; + } + } + return mapName; + } + + /* + * @return An unique name for a function mapper. + */ + private String getMapName() { + return "_jspx_fnmap_" + currFunc++; + } + } +} + diff --git a/java/org/apache/jasper/compiler/ELNode.java b/java/org/apache/jasper/compiler/ELNode.java index ae15ca448..06f6d6db9 100644 --- a/java/org/apache/jasper/compiler/ELNode.java +++ b/java/org/apache/jasper/compiler/ELNode.java @@ -1,247 +1,247 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.*; -import javax.servlet.jsp.tagext.FunctionInfo; -import org.apache.jasper.JasperException; - -/** - * This class defines internal representation for an EL Expression - * - * It currently only defines functions. It can be expanded to define - * all the components of an EL expression, if need to. - * - * @author Kin-man Chung - */ - -abstract class ELNode { - - abstract public void accept(Visitor v) throws JasperException; - - /** - * Child classes - */ - - - /** - * Represents an EL expression: anything in ${ and }. - */ - public static class Root extends ELNode { - - private ELNode.Nodes expr; - - Root(ELNode.Nodes expr) { - this.expr = expr; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public ELNode.Nodes getExpression() { - return expr; - } - } - - /** - * Represents text outside of EL expression. - */ - public static class Text extends ELNode { - - private String text; - - Text(String text) { - this.text = text; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public String getText() { - return text; - } - } - - /** - * Represents anything in EL expression, other than functions, including - * function arguments etc - */ - public static class ELText extends ELNode { - - private String text; - - ELText(String text) { - this.text = text; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public String getText() { - return text; - } - } - - /** - * Represents a function - * Currently only include the prefix and function name, but not its - * arguments. - */ - public static class Function extends ELNode { - - private String prefix; - private String name; - private String uri; - private FunctionInfo functionInfo; - private String methodName; - private String[] parameters; - - Function(String prefix, String name) { - this.prefix = prefix; - this.name = name; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public String getPrefix() { - return prefix; - } - - public String getName() { - return name; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public String getUri() { - return uri; - } - - public void setFunctionInfo(FunctionInfo f) { - this.functionInfo = f; - } - - public FunctionInfo getFunctionInfo() { - return functionInfo; - } - - public void setMethodName(String methodName) { - this.methodName = methodName; - } - - public String getMethodName() { - return methodName; - } - - public void setParameters(String[] parameters) { - this.parameters = parameters; - } - - public String[] getParameters() { - return parameters; - } - } - - /** - * An ordered list of ELNode. - */ - public static class Nodes { - - /* Name used for creating a map for the functions in this - EL expression, for communication to Generator. - */ - String mapName = null; // The function map associated this EL - private List list; - - public Nodes() { - list = new ArrayList(); - } - - public void add(ELNode en) { - list.add(en); - } - - /** - * Visit the nodes in the list with the supplied visitor - * @param v The visitor used - */ - public void visit(Visitor v) throws JasperException { - Iterator iter = list.iterator(); - while (iter.hasNext()) { - ELNode n = (ELNode) iter.next(); - n.accept(v); - } - } - - public Iterator iterator() { - return list.iterator(); - } - - public boolean isEmpty() { - return list.size() == 0; - } - - /** - * @return true if the expression contains a ${...} - */ - public boolean containsEL() { - Iterator iter = list.iterator(); - while (iter.hasNext()) { - ELNode n = (ELNode) iter.next(); - if (n instanceof Root) { - return true; - } - } - return false; - } - - public void setMapName(String name) { - this.mapName = name; - } - - public String getMapName() { - return mapName; - } - } - - /* - * A visitor class for traversing ELNodes - */ - public static class Visitor { - - public void visit(Root n) throws JasperException { - n.getExpression().visit(this); - } - - public void visit(Function n) throws JasperException { - } - - public void visit(Text n) throws JasperException { - } - - public void visit(ELText n) throws JasperException { - } - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.*; +import javax.servlet.jsp.tagext.FunctionInfo; +import org.apache.jasper.JasperException; + +/** + * This class defines internal representation for an EL Expression + * + * It currently only defines functions. It can be expanded to define + * all the components of an EL expression, if need to. + * + * @author Kin-man Chung + */ + +abstract class ELNode { + + abstract public void accept(Visitor v) throws JasperException; + + /** + * Child classes + */ + + + /** + * Represents an EL expression: anything in ${ and }. + */ + public static class Root extends ELNode { + + private ELNode.Nodes expr; + + Root(ELNode.Nodes expr) { + this.expr = expr; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public ELNode.Nodes getExpression() { + return expr; + } + } + + /** + * Represents text outside of EL expression. + */ + public static class Text extends ELNode { + + private String text; + + Text(String text) { + this.text = text; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public String getText() { + return text; + } + } + + /** + * Represents anything in EL expression, other than functions, including + * function arguments etc + */ + public static class ELText extends ELNode { + + private String text; + + ELText(String text) { + this.text = text; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public String getText() { + return text; + } + } + + /** + * Represents a function + * Currently only include the prefix and function name, but not its + * arguments. + */ + public static class Function extends ELNode { + + private String prefix; + private String name; + private String uri; + private FunctionInfo functionInfo; + private String methodName; + private String[] parameters; + + Function(String prefix, String name) { + this.prefix = prefix; + this.name = name; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public String getPrefix() { + return prefix; + } + + public String getName() { + return name; + } + + public void setUri(String uri) { + this.uri = uri; + } + + public String getUri() { + return uri; + } + + public void setFunctionInfo(FunctionInfo f) { + this.functionInfo = f; + } + + public FunctionInfo getFunctionInfo() { + return functionInfo; + } + + public void setMethodName(String methodName) { + this.methodName = methodName; + } + + public String getMethodName() { + return methodName; + } + + public void setParameters(String[] parameters) { + this.parameters = parameters; + } + + public String[] getParameters() { + return parameters; + } + } + + /** + * An ordered list of ELNode. + */ + public static class Nodes { + + /* Name used for creating a map for the functions in this + EL expression, for communication to Generator. + */ + String mapName = null; // The function map associated this EL + private List list; + + public Nodes() { + list = new ArrayList(); + } + + public void add(ELNode en) { + list.add(en); + } + + /** + * Visit the nodes in the list with the supplied visitor + * @param v The visitor used + */ + public void visit(Visitor v) throws JasperException { + Iterator iter = list.iterator(); + while (iter.hasNext()) { + ELNode n = (ELNode) iter.next(); + n.accept(v); + } + } + + public Iterator iterator() { + return list.iterator(); + } + + public boolean isEmpty() { + return list.size() == 0; + } + + /** + * @return true if the expression contains a ${...} + */ + public boolean containsEL() { + Iterator iter = list.iterator(); + while (iter.hasNext()) { + ELNode n = (ELNode) iter.next(); + if (n instanceof Root) { + return true; + } + } + return false; + } + + public void setMapName(String name) { + this.mapName = name; + } + + public String getMapName() { + return mapName; + } + } + + /* + * A visitor class for traversing ELNodes + */ + public static class Visitor { + + public void visit(Root n) throws JasperException { + n.getExpression().visit(this); + } + + public void visit(Function n) throws JasperException { + } + + public void visit(Text n) throws JasperException { + } + + public void visit(ELText n) throws JasperException { + } + } +} + diff --git a/java/org/apache/jasper/compiler/ELParser.java b/java/org/apache/jasper/compiler/ELParser.java index 9af813d9a..e0f1e204c 100644 --- a/java/org/apache/jasper/compiler/ELParser.java +++ b/java/org/apache/jasper/compiler/ELParser.java @@ -1,380 +1,380 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -/** - * This class implements a parser for EL expressions. - * - * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into a - * ELNode.Nodes. - * - * Currently, it only handles text outside ${..} and functions in ${ ..}. - * - * @author Kin-man Chung - */ - -public class ELParser { - - private Token curToken; // current token - - private ELNode.Nodes expr; - - private ELNode.Nodes ELexpr; - - private int index; // Current index of the expression - - private String expression; // The EL expression - - private char type; - - private boolean escapeBS; // is '\' an escape char in text outside EL? - - private static final String reservedWords[] = { "and", "div", "empty", - "eq", "false", "ge", "gt", "instanceof", "le", "lt", "mod", "ne", - "not", "null", "or", "true" }; - - public ELParser(String expression) { - index = 0; - this.expression = expression; - expr = new ELNode.Nodes(); - } - - /** - * Parse an EL expression - * - * @param expression - * The input expression string of the form Char* ('${' Char* - * '}')* Char* - * @return Parsed EL expression in ELNode.Nodes - */ - public static ELNode.Nodes parse(String expression) { - ELParser parser = new ELParser(expression); - while (parser.hasNextChar()) { - String text = parser.skipUntilEL(); - if (text.length() > 0) { - parser.expr.add(new ELNode.Text(text)); - } - ELNode.Nodes elexpr = parser.parseEL(); - if (!elexpr.isEmpty()) { - parser.expr.add(new ELNode.Root(elexpr)); - } - } - return parser.expr; - } - - /** - * Parse an EL expression string '${...}' - * - * @return An ELNode.Nodes representing the EL expression TODO: Currently - * only parsed into functions and text strings. This should be - * rewritten for a full parser. - */ - private ELNode.Nodes parseEL() { - - StringBuffer buf = new StringBuffer(); - ELexpr = new ELNode.Nodes(); - while (hasNext()) { - curToken = nextToken(); - if (curToken instanceof Char) { - if (curToken.toChar() == '}') { - break; - } - buf.append(curToken.toChar()); - } else { - // Output whatever is in buffer - if (buf.length() > 0) { - ELexpr.add(new ELNode.ELText(buf.toString())); - } - if (!parseFunction()) { - ELexpr.add(new ELNode.ELText(curToken.toString())); - } - } - } - if (buf.length() > 0) { - ELexpr.add(new ELNode.ELText(buf.toString())); - } - - return ELexpr; - } - - /** - * Parse for a function FunctionInvokation ::= (identifier ':')? identifier - * '(' (Expression (,Expression)*)? ')' Note: currently we don't parse - * arguments - */ - private boolean parseFunction() { - if (!(curToken instanceof Id) || isELReserved(curToken.toString())) { - return false; - } - String s1 = null; // Function prefix - String s2 = curToken.toString(); // Function name - int mark = getIndex(); - if (hasNext()) { - Token t = nextToken(); - if (t.toChar() == ':') { - if (hasNext()) { - Token t2 = nextToken(); - if (t2 instanceof Id) { - s1 = s2; - s2 = t2.toString(); - if (hasNext()) { - t = nextToken(); - } - } - } - } - if (t.toChar() == '(') { - ELexpr.add(new ELNode.Function(s1, s2)); - return true; - } - } - setIndex(mark); - return false; - } - - /** - * Test if an id is a reserved word in EL - */ - private boolean isELReserved(String id) { - int i = 0; - int j = reservedWords.length; - while (i < j) { - int k = (i + j) / 2; - int result = reservedWords[k].compareTo(id); - if (result == 0) { - return true; - } - if (result < 0) { - i = k + 1; - } else { - j = k; - } - } - return false; - } - - /** - * Skip until an EL expression ('${' || '#{') is reached, allowing escape - * sequences '\\' and '\$' and '\#'. - * - * @return The text string up to the EL expression - */ - private String skipUntilEL() { - char prev = 0; - StringBuffer buf = new StringBuffer(); - while (hasNextChar()) { - char ch = nextChar(); - if (prev == '\\') { - prev = 0; - if (ch == '\\') { - buf.append('\\'); - if (!escapeBS) - prev = '\\'; - } else if (ch == '$' || ch == '#') { - buf.append(ch); - } - // else error! - } else if (prev == '$' || prev == '#') { - if (ch == '{') { - this.type = prev; - prev = 0; - break; - } - buf.append(prev); - } - if (ch == '\\' || ch == '$' || ch == '#') { - prev = ch; - } else { - buf.append(ch); - } - } - if (prev != 0) { - buf.append(prev); - } - return buf.toString(); - } - - /* - * @return true if there is something left in EL expression buffer other - * than white spaces. - */ - private boolean hasNext() { - skipSpaces(); - return hasNextChar(); - } - - /* - * @return The next token in the EL expression buffer. - */ - private Token nextToken() { - skipSpaces(); - if (hasNextChar()) { - char ch = nextChar(); - if (Character.isJavaIdentifierStart(ch)) { - StringBuffer buf = new StringBuffer(); - buf.append(ch); - while ((ch = peekChar()) != -1 - && Character.isJavaIdentifierPart(ch)) { - buf.append(ch); - nextChar(); - } - return new Id(buf.toString()); - } - - if (ch == '\'' || ch == '"') { - return parseQuotedChars(ch); - } else { - // For now... - return new Char(ch); - } - } - return null; - } - - /* - * Parse a string in single or double quotes, allowing for escape sequences - * '\\', and ('\"', or "\'") - */ - private Token parseQuotedChars(char quote) { - StringBuffer buf = new StringBuffer(); - buf.append(quote); - while (hasNextChar()) { - char ch = nextChar(); - if (ch == '\\') { - ch = nextChar(); - if (ch == '\\' || ch == quote) { - buf.append(ch); - } - // else error! - } else if (ch == quote) { - buf.append(ch); - break; - } else { - buf.append(ch); - } - } - return new QuotedString(buf.toString()); - } - - /* - * A collection of low level parse methods dealing with character in the EL - * expression buffer. - */ - - private void skipSpaces() { - while (hasNextChar()) { - if (expression.charAt(index) > ' ') - break; - index++; - } - } - - private boolean hasNextChar() { - return index < expression.length(); - } - - private char nextChar() { - if (index >= expression.length()) { - return (char) -1; - } - return expression.charAt(index++); - } - - private char peekChar() { - if (index >= expression.length()) { - return (char) -1; - } - return expression.charAt(index); - } - - private int getIndex() { - return index; - } - - private void setIndex(int i) { - index = i; - } - - /* - * Represents a token in EL expression string - */ - private static class Token { - - char toChar() { - return 0; - } - - public String toString() { - return ""; - } - } - - /* - * Represents an ID token in EL - */ - private static class Id extends Token { - String id; - - Id(String id) { - this.id = id; - } - - public String toString() { - return id; - } - } - - /* - * Represents a character token in EL - */ - private static class Char extends Token { - - private char ch; - - Char(char ch) { - this.ch = ch; - } - - char toChar() { - return ch; - } - - public String toString() { - return (new Character(ch)).toString(); - } - } - - /* - * Represents a quoted (single or double) string token in EL - */ - private static class QuotedString extends Token { - - private String value; - - QuotedString(String v) { - this.value = v; - } - - public String toString() { - return value; - } - } - - public char getType() { - return type; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +/** + * This class implements a parser for EL expressions. + * + * It takes strings of the form xxx${..}yyy${..}zzz etc, and turn it into a + * ELNode.Nodes. + * + * Currently, it only handles text outside ${..} and functions in ${ ..}. + * + * @author Kin-man Chung + */ + +public class ELParser { + + private Token curToken; // current token + + private ELNode.Nodes expr; + + private ELNode.Nodes ELexpr; + + private int index; // Current index of the expression + + private String expression; // The EL expression + + private char type; + + private boolean escapeBS; // is '\' an escape char in text outside EL? + + private static final String reservedWords[] = { "and", "div", "empty", + "eq", "false", "ge", "gt", "instanceof", "le", "lt", "mod", "ne", + "not", "null", "or", "true" }; + + public ELParser(String expression) { + index = 0; + this.expression = expression; + expr = new ELNode.Nodes(); + } + + /** + * Parse an EL expression + * + * @param expression + * The input expression string of the form Char* ('${' Char* + * '}')* Char* + * @return Parsed EL expression in ELNode.Nodes + */ + public static ELNode.Nodes parse(String expression) { + ELParser parser = new ELParser(expression); + while (parser.hasNextChar()) { + String text = parser.skipUntilEL(); + if (text.length() > 0) { + parser.expr.add(new ELNode.Text(text)); + } + ELNode.Nodes elexpr = parser.parseEL(); + if (!elexpr.isEmpty()) { + parser.expr.add(new ELNode.Root(elexpr)); + } + } + return parser.expr; + } + + /** + * Parse an EL expression string '${...}' + * + * @return An ELNode.Nodes representing the EL expression TODO: Currently + * only parsed into functions and text strings. This should be + * rewritten for a full parser. + */ + private ELNode.Nodes parseEL() { + + StringBuffer buf = new StringBuffer(); + ELexpr = new ELNode.Nodes(); + while (hasNext()) { + curToken = nextToken(); + if (curToken instanceof Char) { + if (curToken.toChar() == '}') { + break; + } + buf.append(curToken.toChar()); + } else { + // Output whatever is in buffer + if (buf.length() > 0) { + ELexpr.add(new ELNode.ELText(buf.toString())); + } + if (!parseFunction()) { + ELexpr.add(new ELNode.ELText(curToken.toString())); + } + } + } + if (buf.length() > 0) { + ELexpr.add(new ELNode.ELText(buf.toString())); + } + + return ELexpr; + } + + /** + * Parse for a function FunctionInvokation ::= (identifier ':')? identifier + * '(' (Expression (,Expression)*)? ')' Note: currently we don't parse + * arguments + */ + private boolean parseFunction() { + if (!(curToken instanceof Id) || isELReserved(curToken.toString())) { + return false; + } + String s1 = null; // Function prefix + String s2 = curToken.toString(); // Function name + int mark = getIndex(); + if (hasNext()) { + Token t = nextToken(); + if (t.toChar() == ':') { + if (hasNext()) { + Token t2 = nextToken(); + if (t2 instanceof Id) { + s1 = s2; + s2 = t2.toString(); + if (hasNext()) { + t = nextToken(); + } + } + } + } + if (t.toChar() == '(') { + ELexpr.add(new ELNode.Function(s1, s2)); + return true; + } + } + setIndex(mark); + return false; + } + + /** + * Test if an id is a reserved word in EL + */ + private boolean isELReserved(String id) { + int i = 0; + int j = reservedWords.length; + while (i < j) { + int k = (i + j) / 2; + int result = reservedWords[k].compareTo(id); + if (result == 0) { + return true; + } + if (result < 0) { + i = k + 1; + } else { + j = k; + } + } + return false; + } + + /** + * Skip until an EL expression ('${' || '#{') is reached, allowing escape + * sequences '\\' and '\$' and '\#'. + * + * @return The text string up to the EL expression + */ + private String skipUntilEL() { + char prev = 0; + StringBuffer buf = new StringBuffer(); + while (hasNextChar()) { + char ch = nextChar(); + if (prev == '\\') { + prev = 0; + if (ch == '\\') { + buf.append('\\'); + if (!escapeBS) + prev = '\\'; + } else if (ch == '$' || ch == '#') { + buf.append(ch); + } + // else error! + } else if (prev == '$' || prev == '#') { + if (ch == '{') { + this.type = prev; + prev = 0; + break; + } + buf.append(prev); + } + if (ch == '\\' || ch == '$' || ch == '#') { + prev = ch; + } else { + buf.append(ch); + } + } + if (prev != 0) { + buf.append(prev); + } + return buf.toString(); + } + + /* + * @return true if there is something left in EL expression buffer other + * than white spaces. + */ + private boolean hasNext() { + skipSpaces(); + return hasNextChar(); + } + + /* + * @return The next token in the EL expression buffer. + */ + private Token nextToken() { + skipSpaces(); + if (hasNextChar()) { + char ch = nextChar(); + if (Character.isJavaIdentifierStart(ch)) { + StringBuffer buf = new StringBuffer(); + buf.append(ch); + while ((ch = peekChar()) != -1 + && Character.isJavaIdentifierPart(ch)) { + buf.append(ch); + nextChar(); + } + return new Id(buf.toString()); + } + + if (ch == '\'' || ch == '"') { + return parseQuotedChars(ch); + } else { + // For now... + return new Char(ch); + } + } + return null; + } + + /* + * Parse a string in single or double quotes, allowing for escape sequences + * '\\', and ('\"', or "\'") + */ + private Token parseQuotedChars(char quote) { + StringBuffer buf = new StringBuffer(); + buf.append(quote); + while (hasNextChar()) { + char ch = nextChar(); + if (ch == '\\') { + ch = nextChar(); + if (ch == '\\' || ch == quote) { + buf.append(ch); + } + // else error! + } else if (ch == quote) { + buf.append(ch); + break; + } else { + buf.append(ch); + } + } + return new QuotedString(buf.toString()); + } + + /* + * A collection of low level parse methods dealing with character in the EL + * expression buffer. + */ + + private void skipSpaces() { + while (hasNextChar()) { + if (expression.charAt(index) > ' ') + break; + index++; + } + } + + private boolean hasNextChar() { + return index < expression.length(); + } + + private char nextChar() { + if (index >= expression.length()) { + return (char) -1; + } + return expression.charAt(index++); + } + + private char peekChar() { + if (index >= expression.length()) { + return (char) -1; + } + return expression.charAt(index); + } + + private int getIndex() { + return index; + } + + private void setIndex(int i) { + index = i; + } + + /* + * Represents a token in EL expression string + */ + private static class Token { + + char toChar() { + return 0; + } + + public String toString() { + return ""; + } + } + + /* + * Represents an ID token in EL + */ + private static class Id extends Token { + String id; + + Id(String id) { + this.id = id; + } + + public String toString() { + return id; + } + } + + /* + * Represents a character token in EL + */ + private static class Char extends Token { + + private char ch; + + Char(char ch) { + this.ch = ch; + } + + char toChar() { + return ch; + } + + public String toString() { + return (new Character(ch)).toString(); + } + } + + /* + * Represents a quoted (single or double) string token in EL + */ + private static class QuotedString extends Token { + + private String value; + + QuotedString(String v) { + this.value = v; + } + + public String toString() { + return value; + } + } + + public char getType() { + return type; + } +} diff --git a/java/org/apache/jasper/compiler/ErrorDispatcher.java b/java/org/apache/jasper/compiler/ErrorDispatcher.java index c83098743..5eecf5284 100644 --- a/java/org/apache/jasper/compiler/ErrorDispatcher.java +++ b/java/org/apache/jasper/compiler/ErrorDispatcher.java @@ -1,582 +1,582 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.io.BufferedReader; -import java.io.IOException; -import java.io.StringReader; -import java.util.Vector; -import java.net.MalformedURLException; - -import org.apache.jasper.JasperException; -import org.xml.sax.SAXException; - -/** - * Class responsible for dispatching JSP parse and javac compilation errors - * to the configured error handler. - * - * This class is also responsible for localizing any error codes before they - * are passed on to the configured error handler. - * - * In the case of a Java compilation error, the compiler error message is - * parsed into an array of JavacErrorDetail instances, which is passed on to - * the configured error handler. - * - * @author Jan Luehe - * @author Kin-man Chung - */ -public class ErrorDispatcher { - - // Custom error handler - private ErrorHandler errHandler; - - // Indicates whether the compilation was initiated by JspServlet or JspC - private boolean jspcMode = false; - - - /* - * Constructor. - * - * @param jspcMode true if compilation has been initiated by JspC, false - * otherwise - */ - public ErrorDispatcher(boolean jspcMode) { - // XXX check web.xml for custom error handler - errHandler = new DefaultErrorHandler(); - this.jspcMode = jspcMode; - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param errCode Error code - */ - public void jspError(String errCode) throws JasperException { - dispatch(null, errCode, null, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param where Error location - * @param errCode Error code - */ - public void jspError(Mark where, String errCode) throws JasperException { - dispatch(where, errCode, null, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param n Node that caused the error - * @param errCode Error code - */ - public void jspError(Node n, String errCode) throws JasperException { - dispatch(n.getStart(), errCode, null, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param errCode Error code - * @param arg Argument for parametric replacement - */ - public void jspError(String errCode, String arg) throws JasperException { - dispatch(null, errCode, new Object[] {arg}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param where Error location - * @param errCode Error code - * @param arg Argument for parametric replacement - */ - public void jspError(Mark where, String errCode, String arg) - throws JasperException { - dispatch(where, errCode, new Object[] {arg}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param n Node that caused the error - * @param errCode Error code - * @param arg Argument for parametric replacement - */ - public void jspError(Node n, String errCode, String arg) - throws JasperException { - dispatch(n.getStart(), errCode, new Object[] {arg}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - */ - public void jspError(String errCode, String arg1, String arg2) - throws JasperException { - dispatch(null, errCode, new Object[] {arg1, arg2}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * @param arg3 Third argument for parametric replacement - */ - public void jspError(String errCode, String arg1, String arg2, String arg3) - throws JasperException { - dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param where Error location - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - */ - public void jspError(Mark where, String errCode, String arg1, String arg2) - throws JasperException { - dispatch(where, errCode, new Object[] {arg1, arg2}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param where Error location - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * @param arg3 Third argument for parametric replacement - */ - - public void jspError(Mark where, String errCode, String arg1, String arg2, - String arg3) - throws JasperException { - dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param n Node that caused the error - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - */ - - public void jspError(Node n, String errCode, String arg1, String arg2) - throws JasperException { - dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param n Node that caused the error - * @param errCode Error code - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * @param arg3 Third argument for parametric replacement - */ - - public void jspError(Node n, String errCode, String arg1, String arg2, - String arg3) - throws JasperException { - dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null); - } - - /* - * Dispatches the given parsing exception to the configured error handler. - * - * @param e Parsing exception - */ - public void jspError(Exception e) throws JasperException { - dispatch(null, null, null, e); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param errCode Error code - * @param arg Argument for parametric replacement - * @param e Parsing exception - */ - public void jspError(String errCode, String arg, Exception e) - throws JasperException { - dispatch(null, errCode, new Object[] {arg}, e); - } - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param n Node that caused the error - * @param errCode Error code - * @param arg Argument for parametric replacement - * @param e Parsing exception - */ - public void jspError(Node n, String errCode, String arg, Exception e) - throws JasperException { - dispatch(n.getStart(), errCode, new Object[] {arg}, e); - } - - /** - * Parses the given error message into an array of javac compilation error - * messages (one per javac compilation error line number). - * - * @param errMsg Error message - * @param fname Name of Java source file whose compilation failed - * @param page Node representation of JSP page from which the Java source - * file was generated - * - * @return Array of javac compilation errors, or null if the given error - * message does not contain any compilation error line numbers - */ - public static JavacErrorDetail[] parseJavacErrors(String errMsg, - String fname, - Node.Nodes page) - throws JasperException, IOException { - - return parseJavacMessage(errMsg, fname, page); - } - - /* - * Dispatches the given javac compilation errors to the configured error - * handler. - * - * @param javacErrors Array of javac compilation errors - */ - public void javacError(JavacErrorDetail[] javacErrors) - throws JasperException { - - errHandler.javacError(javacErrors); - } - - - /* - * Dispatches the given compilation error report and exception to the - * configured error handler. - * - * @param errorReport Compilation error report - * @param e Compilation exception - */ - public void javacError(String errorReport, Exception e) - throws JasperException { - - errHandler.javacError(errorReport, e); - } - - - //********************************************************************* - // Private utility methods - - /* - * Dispatches the given JSP parse error to the configured error handler. - * - * The given error code is localized. If it is not found in the - * resource bundle for localized error messages, it is used as the error - * message. - * - * @param where Error location - * @param errCode Error code - * @param args Arguments for parametric replacement - * @param e Parsing exception - */ - private void dispatch(Mark where, String errCode, Object[] args, - Exception e) throws JasperException { - String file = null; - String errMsg = null; - int line = -1; - int column = -1; - boolean hasLocation = false; - - // Localize - if (errCode != null) { - errMsg = Localizer.getMessage(errCode, args); - } else if (e != null) { - // give a hint about what's wrong - errMsg = e.getMessage(); - } - - // Get error location - if (where != null) { - if (jspcMode) { - // Get the full URL of the resource that caused the error - try { - file = where.getURL().toString(); - } catch (MalformedURLException me) { - // Fallback to using context-relative path - file = where.getFile(); - } - } else { - // Get the context-relative resource path, so as to not - // disclose any local filesystem details - file = where.getFile(); - } - line = where.getLineNumber(); - column = where.getColumnNumber(); - hasLocation = true; - } - - // Get nested exception - Exception nestedEx = e; - if ((e instanceof SAXException) - && (((SAXException) e).getException() != null)) { - nestedEx = ((SAXException) e).getException(); - } - - if (hasLocation) { - errHandler.jspError(file, line, column, errMsg, nestedEx); - } else { - errHandler.jspError(errMsg, nestedEx); - } - } - - /* - * Parses the given Java compilation error message, which may contain one - * or more compilation errors, into an array of JavacErrorDetail instances. - * - * Each JavacErrorDetail instance contains the information about a single - * compilation error. - * - * @param errMsg Compilation error message that was generated by the - * javac compiler - * @param fname Name of Java source file whose compilation failed - * @param page Node representation of JSP page from which the Java source - * file was generated - * - * @return Array of JavacErrorDetail instances corresponding to the - * compilation errors - */ - private static JavacErrorDetail[] parseJavacMessage( - String errMsg, String fname, Node.Nodes page) - throws IOException, JasperException { - - Vector errVec = new Vector(); - StringBuffer errMsgBuf = null; - int lineNum = -1; - JavacErrorDetail javacError = null; - - BufferedReader reader = new BufferedReader(new StringReader(errMsg)); - - /* - * Parse compilation errors. Each compilation error consists of a file - * path and error line number, followed by a number of lines describing - * the error. - */ - String line = null; - while ((line = reader.readLine()) != null) { - - /* - * Error line number is delimited by set of colons. - * Ignore colon following drive letter on Windows (fromIndex = 2). - * XXX Handle deprecation warnings that don't have line info - */ - int beginColon = line.indexOf(':', 2); - int endColon = line.indexOf(':', beginColon + 1); - if ((beginColon >= 0) && (endColon >= 0)) { - if (javacError != null) { - // add previous error to error vector - errVec.add(javacError); - } - - String lineNumStr = line.substring(beginColon + 1, endColon); - try { - lineNum = Integer.parseInt(lineNumStr); - } catch (NumberFormatException e) { - // XXX - } - - errMsgBuf = new StringBuffer(); - - javacError = createJavacError(fname, page, errMsgBuf, lineNum); - } - - // Ignore messages preceding first error - if (errMsgBuf != null) { - errMsgBuf.append(line); - errMsgBuf.append("\n"); - } - } - - // Add last error to error vector - if (javacError != null) { - errVec.add(javacError); - } - - reader.close(); - - JavacErrorDetail[] errDetails = null; - if (errVec.size() > 0) { - errDetails = new JavacErrorDetail[errVec.size()]; - errVec.copyInto(errDetails); - } - - return errDetails; - } - - - /** - * @param fname - * @param page - * @param errMsgBuf - * @param lineNum - * @return JavacErrorDetail The error details - * @throws JasperException - */ - public static JavacErrorDetail createJavacError(String fname, Node.Nodes page, - StringBuffer errMsgBuf, int lineNum) throws JasperException { - JavacErrorDetail javacError; - // Attempt to map javac error line number to line in JSP page - ErrorVisitor errVisitor = new ErrorVisitor(lineNum); - page.visit(errVisitor); - Node errNode = errVisitor.getJspSourceNode(); - if ((errNode != null) && (errNode.getStart() != null)) { - javacError = new JavacErrorDetail( - fname, - lineNum, - errNode.getStart().getFile(), - errNode.getStart().getLineNumber(), - errMsgBuf); - } else { - /* - * javac error line number cannot be mapped to JSP page - * line number. For example, this is the case if a - * scriptlet is missing a closing brace, which causes - * havoc with the try-catch-finally block that the code - * generator places around all generated code: As a result - * of this, the javac error line numbers will be outside - * the range of begin and end java line numbers that were - * generated for the scriptlet, and therefore cannot be - * mapped to the start line number of the scriptlet in the - * JSP page. - * Include just the javac error info in the error detail. - */ - javacError = new JavacErrorDetail( - fname, - lineNum, - errMsgBuf); - } - return javacError; - } - - - /* - * Visitor responsible for mapping a line number in the generated servlet - * source code to the corresponding JSP node. - */ - static class ErrorVisitor extends Node.Visitor { - - // Java source line number to be mapped - private int lineNum; - - /* - * JSP node whose Java source code range in the generated servlet - * contains the Java source line number to be mapped - */ - Node found; - - /* - * Constructor. - * - * @param lineNum Source line number in the generated servlet code - */ - public ErrorVisitor(int lineNum) { - this.lineNum = lineNum; - } - - public void doVisit(Node n) throws JasperException { - if ((lineNum >= n.getBeginJavaLine()) - && (lineNum < n.getEndJavaLine())) { - found = n; - } - } - - /* - * Gets the JSP node to which the source line number in the generated - * servlet code was mapped. - * - * @return JSP node to which the source line number in the generated - * servlet code was mapped - */ - public Node getJspSourceNode() { - return found; - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.StringReader; +import java.util.Vector; +import java.net.MalformedURLException; + +import org.apache.jasper.JasperException; +import org.xml.sax.SAXException; + +/** + * Class responsible for dispatching JSP parse and javac compilation errors + * to the configured error handler. + * + * This class is also responsible for localizing any error codes before they + * are passed on to the configured error handler. + * + * In the case of a Java compilation error, the compiler error message is + * parsed into an array of JavacErrorDetail instances, which is passed on to + * the configured error handler. + * + * @author Jan Luehe + * @author Kin-man Chung + */ +public class ErrorDispatcher { + + // Custom error handler + private ErrorHandler errHandler; + + // Indicates whether the compilation was initiated by JspServlet or JspC + private boolean jspcMode = false; + + + /* + * Constructor. + * + * @param jspcMode true if compilation has been initiated by JspC, false + * otherwise + */ + public ErrorDispatcher(boolean jspcMode) { + // XXX check web.xml for custom error handler + errHandler = new DefaultErrorHandler(); + this.jspcMode = jspcMode; + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param errCode Error code + */ + public void jspError(String errCode) throws JasperException { + dispatch(null, errCode, null, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param where Error location + * @param errCode Error code + */ + public void jspError(Mark where, String errCode) throws JasperException { + dispatch(where, errCode, null, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param n Node that caused the error + * @param errCode Error code + */ + public void jspError(Node n, String errCode) throws JasperException { + dispatch(n.getStart(), errCode, null, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param errCode Error code + * @param arg Argument for parametric replacement + */ + public void jspError(String errCode, String arg) throws JasperException { + dispatch(null, errCode, new Object[] {arg}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param where Error location + * @param errCode Error code + * @param arg Argument for parametric replacement + */ + public void jspError(Mark where, String errCode, String arg) + throws JasperException { + dispatch(where, errCode, new Object[] {arg}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param n Node that caused the error + * @param errCode Error code + * @param arg Argument for parametric replacement + */ + public void jspError(Node n, String errCode, String arg) + throws JasperException { + dispatch(n.getStart(), errCode, new Object[] {arg}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + */ + public void jspError(String errCode, String arg1, String arg2) + throws JasperException { + dispatch(null, errCode, new Object[] {arg1, arg2}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * @param arg3 Third argument for parametric replacement + */ + public void jspError(String errCode, String arg1, String arg2, String arg3) + throws JasperException { + dispatch(null, errCode, new Object[] {arg1, arg2, arg3}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param where Error location + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + */ + public void jspError(Mark where, String errCode, String arg1, String arg2) + throws JasperException { + dispatch(where, errCode, new Object[] {arg1, arg2}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param where Error location + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * @param arg3 Third argument for parametric replacement + */ + + public void jspError(Mark where, String errCode, String arg1, String arg2, + String arg3) + throws JasperException { + dispatch(where, errCode, new Object[] {arg1, arg2, arg3}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param n Node that caused the error + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + */ + + public void jspError(Node n, String errCode, String arg1, String arg2) + throws JasperException { + dispatch(n.getStart(), errCode, new Object[] {arg1, arg2}, null); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param n Node that caused the error + * @param errCode Error code + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * @param arg3 Third argument for parametric replacement + */ + + public void jspError(Node n, String errCode, String arg1, String arg2, + String arg3) + throws JasperException { + dispatch(n.getStart(), errCode, new Object[] {arg1, arg2, arg3}, null); + } + + /* + * Dispatches the given parsing exception to the configured error handler. + * + * @param e Parsing exception + */ + public void jspError(Exception e) throws JasperException { + dispatch(null, null, null, e); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param errCode Error code + * @param arg Argument for parametric replacement + * @param e Parsing exception + */ + public void jspError(String errCode, String arg, Exception e) + throws JasperException { + dispatch(null, errCode, new Object[] {arg}, e); + } + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param n Node that caused the error + * @param errCode Error code + * @param arg Argument for parametric replacement + * @param e Parsing exception + */ + public void jspError(Node n, String errCode, String arg, Exception e) + throws JasperException { + dispatch(n.getStart(), errCode, new Object[] {arg}, e); + } + + /** + * Parses the given error message into an array of javac compilation error + * messages (one per javac compilation error line number). + * + * @param errMsg Error message + * @param fname Name of Java source file whose compilation failed + * @param page Node representation of JSP page from which the Java source + * file was generated + * + * @return Array of javac compilation errors, or null if the given error + * message does not contain any compilation error line numbers + */ + public static JavacErrorDetail[] parseJavacErrors(String errMsg, + String fname, + Node.Nodes page) + throws JasperException, IOException { + + return parseJavacMessage(errMsg, fname, page); + } + + /* + * Dispatches the given javac compilation errors to the configured error + * handler. + * + * @param javacErrors Array of javac compilation errors + */ + public void javacError(JavacErrorDetail[] javacErrors) + throws JasperException { + + errHandler.javacError(javacErrors); + } + + + /* + * Dispatches the given compilation error report and exception to the + * configured error handler. + * + * @param errorReport Compilation error report + * @param e Compilation exception + */ + public void javacError(String errorReport, Exception e) + throws JasperException { + + errHandler.javacError(errorReport, e); + } + + + //********************************************************************* + // Private utility methods + + /* + * Dispatches the given JSP parse error to the configured error handler. + * + * The given error code is localized. If it is not found in the + * resource bundle for localized error messages, it is used as the error + * message. + * + * @param where Error location + * @param errCode Error code + * @param args Arguments for parametric replacement + * @param e Parsing exception + */ + private void dispatch(Mark where, String errCode, Object[] args, + Exception e) throws JasperException { + String file = null; + String errMsg = null; + int line = -1; + int column = -1; + boolean hasLocation = false; + + // Localize + if (errCode != null) { + errMsg = Localizer.getMessage(errCode, args); + } else if (e != null) { + // give a hint about what's wrong + errMsg = e.getMessage(); + } + + // Get error location + if (where != null) { + if (jspcMode) { + // Get the full URL of the resource that caused the error + try { + file = where.getURL().toString(); + } catch (MalformedURLException me) { + // Fallback to using context-relative path + file = where.getFile(); + } + } else { + // Get the context-relative resource path, so as to not + // disclose any local filesystem details + file = where.getFile(); + } + line = where.getLineNumber(); + column = where.getColumnNumber(); + hasLocation = true; + } + + // Get nested exception + Exception nestedEx = e; + if ((e instanceof SAXException) + && (((SAXException) e).getException() != null)) { + nestedEx = ((SAXException) e).getException(); + } + + if (hasLocation) { + errHandler.jspError(file, line, column, errMsg, nestedEx); + } else { + errHandler.jspError(errMsg, nestedEx); + } + } + + /* + * Parses the given Java compilation error message, which may contain one + * or more compilation errors, into an array of JavacErrorDetail instances. + * + * Each JavacErrorDetail instance contains the information about a single + * compilation error. + * + * @param errMsg Compilation error message that was generated by the + * javac compiler + * @param fname Name of Java source file whose compilation failed + * @param page Node representation of JSP page from which the Java source + * file was generated + * + * @return Array of JavacErrorDetail instances corresponding to the + * compilation errors + */ + private static JavacErrorDetail[] parseJavacMessage( + String errMsg, String fname, Node.Nodes page) + throws IOException, JasperException { + + Vector errVec = new Vector(); + StringBuffer errMsgBuf = null; + int lineNum = -1; + JavacErrorDetail javacError = null; + + BufferedReader reader = new BufferedReader(new StringReader(errMsg)); + + /* + * Parse compilation errors. Each compilation error consists of a file + * path and error line number, followed by a number of lines describing + * the error. + */ + String line = null; + while ((line = reader.readLine()) != null) { + + /* + * Error line number is delimited by set of colons. + * Ignore colon following drive letter on Windows (fromIndex = 2). + * XXX Handle deprecation warnings that don't have line info + */ + int beginColon = line.indexOf(':', 2); + int endColon = line.indexOf(':', beginColon + 1); + if ((beginColon >= 0) && (endColon >= 0)) { + if (javacError != null) { + // add previous error to error vector + errVec.add(javacError); + } + + String lineNumStr = line.substring(beginColon + 1, endColon); + try { + lineNum = Integer.parseInt(lineNumStr); + } catch (NumberFormatException e) { + // XXX + } + + errMsgBuf = new StringBuffer(); + + javacError = createJavacError(fname, page, errMsgBuf, lineNum); + } + + // Ignore messages preceding first error + if (errMsgBuf != null) { + errMsgBuf.append(line); + errMsgBuf.append("\n"); + } + } + + // Add last error to error vector + if (javacError != null) { + errVec.add(javacError); + } + + reader.close(); + + JavacErrorDetail[] errDetails = null; + if (errVec.size() > 0) { + errDetails = new JavacErrorDetail[errVec.size()]; + errVec.copyInto(errDetails); + } + + return errDetails; + } + + + /** + * @param fname + * @param page + * @param errMsgBuf + * @param lineNum + * @return JavacErrorDetail The error details + * @throws JasperException + */ + public static JavacErrorDetail createJavacError(String fname, Node.Nodes page, + StringBuffer errMsgBuf, int lineNum) throws JasperException { + JavacErrorDetail javacError; + // Attempt to map javac error line number to line in JSP page + ErrorVisitor errVisitor = new ErrorVisitor(lineNum); + page.visit(errVisitor); + Node errNode = errVisitor.getJspSourceNode(); + if ((errNode != null) && (errNode.getStart() != null)) { + javacError = new JavacErrorDetail( + fname, + lineNum, + errNode.getStart().getFile(), + errNode.getStart().getLineNumber(), + errMsgBuf); + } else { + /* + * javac error line number cannot be mapped to JSP page + * line number. For example, this is the case if a + * scriptlet is missing a closing brace, which causes + * havoc with the try-catch-finally block that the code + * generator places around all generated code: As a result + * of this, the javac error line numbers will be outside + * the range of begin and end java line numbers that were + * generated for the scriptlet, and therefore cannot be + * mapped to the start line number of the scriptlet in the + * JSP page. + * Include just the javac error info in the error detail. + */ + javacError = new JavacErrorDetail( + fname, + lineNum, + errMsgBuf); + } + return javacError; + } + + + /* + * Visitor responsible for mapping a line number in the generated servlet + * source code to the corresponding JSP node. + */ + static class ErrorVisitor extends Node.Visitor { + + // Java source line number to be mapped + private int lineNum; + + /* + * JSP node whose Java source code range in the generated servlet + * contains the Java source line number to be mapped + */ + Node found; + + /* + * Constructor. + * + * @param lineNum Source line number in the generated servlet code + */ + public ErrorVisitor(int lineNum) { + this.lineNum = lineNum; + } + + public void doVisit(Node n) throws JasperException { + if ((lineNum >= n.getBeginJavaLine()) + && (lineNum < n.getEndJavaLine())) { + found = n; + } + } + + /* + * Gets the JSP node to which the source line number in the generated + * servlet code was mapped. + * + * @return JSP node to which the source line number in the generated + * servlet code was mapped + */ + public Node getJspSourceNode() { + return found; + } + } +} diff --git a/java/org/apache/jasper/compiler/ErrorHandler.java b/java/org/apache/jasper/compiler/ErrorHandler.java index 163ceaa08..212d44279 100644 --- a/java/org/apache/jasper/compiler/ErrorHandler.java +++ b/java/org/apache/jasper/compiler/ErrorHandler.java @@ -1,72 +1,72 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import org.apache.jasper.JasperException; - -/** - * Interface for handling JSP parse and javac compilation errors. - * - * An implementation of this interface may be registered with the - * ErrorDispatcher by setting the XXX initialization parameter in the JSP - * page compiler and execution servlet in Catalina's web.xml file to the - * implementation's fully qualified class name. - * - * @author Jan Luehe - * @author Kin-man Chung - */ -public interface ErrorHandler { - - /** - * Processes the given JSP parse error. - * - * @param fname Name of the JSP file in which the parse error occurred - * @param line Parse error line number - * @param column Parse error column number - * @param msg Parse error message - * @param exception Parse exception - */ - public void jspError(String fname, int line, int column, String msg, - Exception exception) throws JasperException; - - /** - * Processes the given JSP parse error. - * - * @param msg Parse error message - * @param exception Parse exception - */ - public void jspError(String msg, Exception exception) - throws JasperException; - - /** - * Processes the given javac compilation errors. - * - * @param details Array of JavacErrorDetail instances corresponding to the - * compilation errors - */ - public void javacError(JavacErrorDetail[] details) - throws JasperException; - - /** - * Processes the given javac error report and exception. - * - * @param errorReport Compilation error report - * @param exception Compilation exception - */ - public void javacError(String errorReport, Exception exception) - throws JasperException; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import org.apache.jasper.JasperException; + +/** + * Interface for handling JSP parse and javac compilation errors. + * + * An implementation of this interface may be registered with the + * ErrorDispatcher by setting the XXX initialization parameter in the JSP + * page compiler and execution servlet in Catalina's web.xml file to the + * implementation's fully qualified class name. + * + * @author Jan Luehe + * @author Kin-man Chung + */ +public interface ErrorHandler { + + /** + * Processes the given JSP parse error. + * + * @param fname Name of the JSP file in which the parse error occurred + * @param line Parse error line number + * @param column Parse error column number + * @param msg Parse error message + * @param exception Parse exception + */ + public void jspError(String fname, int line, int column, String msg, + Exception exception) throws JasperException; + + /** + * Processes the given JSP parse error. + * + * @param msg Parse error message + * @param exception Parse exception + */ + public void jspError(String msg, Exception exception) + throws JasperException; + + /** + * Processes the given javac compilation errors. + * + * @param details Array of JavacErrorDetail instances corresponding to the + * compilation errors + */ + public void javacError(JavacErrorDetail[] details) + throws JasperException; + + /** + * Processes the given javac error report and exception. + * + * @param errorReport Compilation error report + * @param exception Compilation exception + */ + public void javacError(String errorReport, Exception exception) + throws JasperException; +} diff --git a/java/org/apache/jasper/compiler/Generator.java b/java/org/apache/jasper/compiler/Generator.java index dfd6a5267..674c63db5 100644 --- a/java/org/apache/jasper/compiler/Generator.java +++ b/java/org/apache/jasper/compiler/Generator.java @@ -1,4126 +1,4126 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.beans.BeanInfo; -import java.beans.IntrospectionException; -import java.beans.Introspector; -import java.beans.PropertyDescriptor; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; - -import javax.el.MethodExpression; -import javax.el.ValueExpression; -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagVariableInfo; -import javax.servlet.jsp.tagext.VariableInfo; - -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.runtime.JspRuntimeLibrary; -import org.xml.sax.Attributes; - -/** - * Generate Java source from Nodes - * - * @author Anil K. Vijendran - * @author Danno Ferrin - * @author Mandar Raje - * @author Rajiv Mordani - * @author Pierre Delisle - * - * Tomcat 4.1.x and Tomcat 5: - * @author Kin-man Chung - * @author Jan Luehe - * @author Shawn Bayern - * @author Mark Roth - * @author Denis Benoit - * - * Tomcat 6.x - * @author Jacob Hookom - */ - -class Generator { - - private static final Class[] OBJECT_CLASS = { Object.class }; - - private static final String VAR_EXPRESSIONFACTORY = "_el_expressionfactory"; - - private ServletWriter out; - - private ArrayList methodsBuffered; - - private FragmentHelperClass fragmentHelperClass; - - private ErrorDispatcher err; - - private BeanRepository beanInfo; - - private JspCompilationContext ctxt; - - private boolean isPoolingEnabled; - - private boolean breakAtLF; - - private String jspIdPrefix; - - private int jspId; - - private PageInfo pageInfo; - - private Vector tagHandlerPoolNames; - - private GenBuffer charArrayBuffer; - - /** - * @param s - * the input string - * @return quoted and escaped string, per Java rule - */ - static String quote(String s) { - - if (s == null) - return "null"; - - return '"' + escape(s) + '"'; - } - - /** - * @param s - * the input string - * @return escaped string, per Java rule - */ - static String escape(String s) { - - if (s == null) - return ""; - - StringBuffer b = new StringBuffer(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '"') - b.append('\\').append('"'); - else if (c == '\\') - b.append('\\').append('\\'); - else if (c == '\n') - b.append('\\').append('n'); - else if (c == '\r') - b.append('\\').append('r'); - else - b.append(c); - } - return b.toString(); - } - - /** - * Single quote and escape a character - */ - static String quote(char c) { - - StringBuffer b = new StringBuffer(); - b.append('\''); - if (c == '\'') - b.append('\\').append('\''); - else if (c == '\\') - b.append('\\').append('\\'); - else if (c == '\n') - b.append('\\').append('n'); - else if (c == '\r') - b.append('\\').append('r'); - else - b.append(c); - b.append('\''); - return b.toString(); - } - - private String createJspId() throws JasperException { - if (this.jspIdPrefix == null) { - StringBuffer sb = new StringBuffer(32); - String name = ctxt.getServletJavaFileName(); - sb.append("jsp_").append(Math.abs(name.hashCode())).append('_'); - this.jspIdPrefix = sb.toString(); - } - return this.jspIdPrefix + (this.jspId++); - } - - /** - * Generates declarations. This includes "info" of the page directive, and - * scriptlet declarations. - */ - private void generateDeclarations(Node.Nodes page) throws JasperException { - - class DeclarationVisitor extends Node.Visitor { - - private boolean getServletInfoGenerated = false; - - /* - * Generates getServletInfo() method that returns the value of the - * page directive's 'info' attribute, if present. - * - * The Validator has already ensured that if the translation unit - * contains more than one page directive with an 'info' attribute, - * their values match. - */ - public void visit(Node.PageDirective n) throws JasperException { - - if (getServletInfoGenerated) { - return; - } - - String info = n.getAttributeValue("info"); - if (info == null) - return; - - getServletInfoGenerated = true; - out.printil("public String getServletInfo() {"); - out.pushIndent(); - out.printin("return "); - out.print(quote(info)); - out.println(";"); - out.popIndent(); - out.printil("}"); - out.println(); - } - - public void visit(Node.Declaration n) throws JasperException { - n.setBeginJavaLine(out.getJavaLine()); - out.printMultiLn(new String(n.getText())); - out.println(); - n.setEndJavaLine(out.getJavaLine()); - } - - // Custom Tags may contain declarations from tag plugins. - public void visit(Node.CustomTag n) throws JasperException { - if (n.useTagPlugin()) { - if (n.getAtSTag() != null) { - n.getAtSTag().visit(this); - } - visitBody(n); - if (n.getAtETag() != null) { - n.getAtETag().visit(this); - } - } else { - visitBody(n); - } - } - } - - out.println(); - page.visit(new DeclarationVisitor()); - } - - /** - * Compiles list of tag handler pool names. - */ - private void compileTagHandlerPoolList(Node.Nodes page) - throws JasperException { - - class TagHandlerPoolVisitor extends Node.Visitor { - - private Vector names; - - /* - * Constructor - * - * @param v Vector of tag handler pool names to populate - */ - TagHandlerPoolVisitor(Vector v) { - names = v; - } - - /* - * Gets the name of the tag handler pool for the given custom tag - * and adds it to the list of tag handler pool names unless it is - * already contained in it. - */ - public void visit(Node.CustomTag n) throws JasperException { - - if (!n.implementsSimpleTag()) { - String name = createTagHandlerPoolName(n.getPrefix(), n - .getLocalName(), n.getAttributes(), n - .hasEmptyBody()); - n.setTagHandlerPoolName(name); - if (!names.contains(name)) { - names.add(name); - } - } - visitBody(n); - } - - /* - * Creates the name of the tag handler pool whose tag handlers may - * be (re)used to service this action. - * - * @return The name of the tag handler pool - */ - private String createTagHandlerPoolName(String prefix, - String shortName, Attributes attrs, boolean hasEmptyBody) { - String poolName = null; - - poolName = "_jspx_tagPool_" + prefix + "_" + shortName; - if (attrs != null) { - String[] attrNames = new String[attrs.getLength()]; - for (int i = 0; i < attrNames.length; i++) { - attrNames[i] = attrs.getQName(i); - } - Arrays.sort(attrNames, Collections.reverseOrder()); - for (int i = 0; i < attrNames.length; i++) { - poolName = poolName + "_" + attrNames[i]; - } - } - if (hasEmptyBody) { - poolName = poolName + "_nobody"; - } - return JspUtil.makeXmlJavaIdentifier(poolName); - } - } - - page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames)); - } - - private void declareTemporaryScriptingVars(Node.Nodes page) - throws JasperException { - - class ScriptingVarVisitor extends Node.Visitor { - - private Vector vars; - - ScriptingVarVisitor() { - vars = new Vector(); - } - - public void visit(Node.CustomTag n) throws JasperException { - - if (n.getCustomNestingLevel() > 0) { - TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); - VariableInfo[] varInfos = n.getVariableInfos(); - - if (varInfos.length > 0) { - for (int i = 0; i < varInfos.length; i++) { - String varName = varInfos[i].getVarName(); - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - if (!vars.contains(tmpVarName)) { - vars.add(tmpVarName); - out.printin(varInfos[i].getClassName()); - out.print(" "); - out.print(tmpVarName); - out.print(" = "); - out.print(null); - out.println(";"); - } - } - } else { - for (int i = 0; i < tagVarInfos.length; i++) { - String varName = tagVarInfos[i].getNameGiven(); - if (varName == null) { - varName = n.getTagData().getAttributeString( - tagVarInfos[i].getNameFromAttribute()); - } else if (tagVarInfos[i].getNameFromAttribute() != null) { - // alias - continue; - } - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - if (!vars.contains(tmpVarName)) { - vars.add(tmpVarName); - out.printin(tagVarInfos[i].getClassName()); - out.print(" "); - out.print(tmpVarName); - out.print(" = "); - out.print(null); - out.println(";"); - } - } - } - } - - visitBody(n); - } - } - - page.visit(new ScriptingVarVisitor()); - } - - /** - * Generates the _jspInit() method for instantiating the tag handler pools. - * For tag file, _jspInit has to be invoked manually, and the ServletConfig - * object explicitly passed. - * - * In JSP 2.1, we also instantiate an ExpressionFactory - */ - private void generateInit() { - - if (ctxt.isTagFile()) { - out.printil("private void _jspInit(ServletConfig config) {"); - } else { - out.printil("public void _jspInit() {"); - } - - out.pushIndent(); - if (isPoolingEnabled) { - for (int i = 0; i < tagHandlerPoolNames.size(); i++) { - out.printin(tagHandlerPoolNames.elementAt(i)); - out - .print(" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool("); - if (ctxt.isTagFile()) { - out.print("config"); - } else { - out.print("getServletConfig()"); - } - out.println(");"); - } - } - - out.printin(VAR_EXPRESSIONFACTORY); - out.print(" = JspFactory.getDefaultFactory().getJspApplicationContext("); - if (ctxt.isTagFile()) { - out.print("config"); - } else { - out.print("getServletConfig()"); - } - out.println(".getServletContext()).getExpressionFactory();"); - - out.popIndent(); - out.printil("}"); - out.println(); - } - - /** - * Generates the _jspDestroy() method which is responsible for calling the - * release() method on every tag handler in any of the tag handler pools. - */ - private void generateDestroy() { - - out.printil("public void _jspDestroy() {"); - out.pushIndent(); - - if (isPoolingEnabled) { - for (int i = 0; i < tagHandlerPoolNames.size(); i++) { - out.printin((String) tagHandlerPoolNames.elementAt(i)); - out.println(".release();"); - } - } - - out.popIndent(); - out.printil("}"); - out.println(); - } - - /** - * Generate preamble package name (shared by servlet and tag handler - * preamble generation) - */ - private void genPreamblePackage(String packageName) throws JasperException { - if (!"".equals(packageName) && packageName != null) { - out.printil("package " + packageName + ";"); - out.println(); - } - } - - /** - * Generate preamble imports (shared by servlet and tag handler preamble - * generation) - */ - private void genPreambleImports() throws JasperException { - Iterator iter = pageInfo.getImports().iterator(); - while (iter.hasNext()) { - out.printin("import "); - out.print((String) iter.next()); - out.println(";"); - } - - out.println(); - } - - /** - * Generation of static initializers in preamble. For example, dependant - * list, el function map, prefix map. (shared by servlet and tag handler - * preamble generation) - */ - private void genPreambleStaticInitializers() throws JasperException { - // Static data for getDependants() - out.printil("private static java.util.List _jspx_dependants;"); - out.println(); - List dependants = pageInfo.getDependants(); - Iterator iter = dependants.iterator(); - if (!dependants.isEmpty()) { - out.printil("static {"); - out.pushIndent(); - out.printin("_jspx_dependants = new java.util.ArrayList("); - out.print("" + dependants.size()); - out.println(");"); - while (iter.hasNext()) { - out.printin("_jspx_dependants.add(\""); - out.print((String) iter.next()); - out.println("\");"); - } - out.popIndent(); - out.printil("}"); - out.println(); - } - } - - /** - * Declare tag handler pools (tags of the same type and with the same - * attribute set share the same tag handler pool) (shared by servlet and tag - * handler preamble generation) - * - * In JSP 2.1, we also scope an instance of ExpressionFactory - */ - private void genPreambleClassVariableDeclarations(String className) - throws JasperException { - if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { - for (int i = 0; i < tagHandlerPoolNames.size(); i++) { - out.printil("private org.apache.jasper.runtime.TagHandlerPool " - + tagHandlerPoolNames.elementAt(i) + ";"); - } - out.println(); - } - out.printin("private javax.el.ExpressionFactory "); - out.print(VAR_EXPRESSIONFACTORY); - out.println(";"); - out.println(); - } - - /** - * Declare general-purpose methods (shared by servlet and tag handler - * preamble generation) - */ - private void genPreambleMethods() throws JasperException { - // Method used to get compile time file dependencies - out.printil("public Object getDependants() {"); - out.pushIndent(); - out.printil("return _jspx_dependants;"); - out.popIndent(); - out.printil("}"); - out.println(); - - generateInit(); - generateDestroy(); - } - - /** - * Generates the beginning of the static portion of the servlet. - */ - private void generatePreamble(Node.Nodes page) throws JasperException { - - String servletPackageName = ctxt.getServletPackageName(); - String servletClassName = ctxt.getServletClassName(); - String serviceMethodName = Constants.SERVICE_METHOD_NAME; - - // First the package name: - genPreamblePackage(servletPackageName); - - // Generate imports - genPreambleImports(); - - // Generate class declaration - out.printin("public final class "); - out.print(servletClassName); - out.print(" extends "); - out.println(pageInfo.getExtends()); - out - .printin(" implements org.apache.jasper.runtime.JspSourceDependent"); - if (!pageInfo.isThreadSafe()) { - out.println(","); - out.printin(" SingleThreadModel"); - } - out.println(" {"); - out.pushIndent(); - - // Class body begins here - generateDeclarations(page); - - // Static initializations here - genPreambleStaticInitializers(); - - // Class variable declarations - genPreambleClassVariableDeclarations(servletClassName); - - // Constructor - // generateConstructor(className); - - // Methods here - genPreambleMethods(); - - // Now the service method - out.printin("public void "); - out.print(serviceMethodName); - out - .println("(HttpServletRequest request, HttpServletResponse response)"); - out.println(" throws java.io.IOException, ServletException {"); - - out.pushIndent(); - out.println(); - - // Local variable declarations - out.printil("JspFactory _jspxFactory = null;"); - out.printil("PageContext pageContext = null;"); - - if (pageInfo.isSession()) - out.printil("HttpSession session = null;"); - - if (pageInfo.isErrorPage()) { - out - .printil("Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);"); - out.printil("if (exception != null) {"); - out.pushIndent(); - out - .printil("response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);"); - out.popIndent(); - out.printil("}"); - } - - out.printil("ServletContext application = null;"); - out.printil("ServletConfig config = null;"); - out.printil("JspWriter out = null;"); - out.printil("Object page = this;"); - - out.printil("JspWriter _jspx_out = null;"); - out.printil("PageContext _jspx_page_context = null;"); - out.println(); - - declareTemporaryScriptingVars(page); - out.println(); - - out.printil("try {"); - out.pushIndent(); - - out.printil("_jspxFactory = JspFactory.getDefaultFactory();"); - - out.printin("response.setContentType("); - out.print(quote(pageInfo.getContentType())); - out.println(");"); - - if (ctxt.getOptions().isXpoweredBy()) { - out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.0\");"); - } - - out - .printil("pageContext = _jspxFactory.getPageContext(this, request, response,"); - out.printin("\t\t\t"); - out.print(quote(pageInfo.getErrorPage())); - out.print(", " + pageInfo.isSession()); - out.print(", " + pageInfo.getBuffer()); - out.print(", " + pageInfo.isAutoFlush()); - out.println(");"); - out.printil("_jspx_page_context = pageContext;"); - - out.printil("application = pageContext.getServletContext();"); - out.printil("config = pageContext.getServletConfig();"); - - if (pageInfo.isSession()) - out.printil("session = pageContext.getSession();"); - out.printil("out = pageContext.getOut();"); - out.printil("_jspx_out = out;"); - out.println(); - } - - /** - * Generates an XML Prolog, which includes an XML declaration and an XML - * doctype declaration. - */ - private void generateXmlProlog(Node.Nodes page) { - - /* - * An XML declaration is generated under the following conditions: - - * 'omit-xml-declaration' attribute of action is set to - * "no" or "false" - JSP document without a - */ - String omitXmlDecl = pageInfo.getOmitXmlDecl(); - if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl)) - || (omitXmlDecl == null && page.getRoot().isXmlSyntax() - && !pageInfo.hasJspRoot() && !ctxt.isTagFile())) { - String cType = pageInfo.getContentType(); - String charSet = cType.substring(cType.indexOf("charset=") + 8); - out.printil("out.write(\"\\n\");"); - } - - /* - * Output a DOCTYPE declaration if the doctype-root-element appears. If - * doctype-public appears: else - */ - - String doctypeName = pageInfo.getDoctypeName(); - if (doctypeName != null) { - String doctypePublic = pageInfo.getDoctypePublic(); - String doctypeSystem = pageInfo.getDoctypeSystem(); - out.printin("out.write(\"\\n\");"); - } - } - - /* - * Generates the constructor. (shared by servlet and tag handler preamble - * generation) - */ - private void generateConstructor(String className) { - out.printil("public " + className + "() {"); - out.printil("}"); - out.println(); - } - - /** - * A visitor that generates codes for the elements in the page. - */ - class GenerateVisitor extends Node.Visitor { - - /* - * Hashtable containing introspection information on tag handlers: - * : tag prefix : hashtable containing introspection on tag - * handlers: : tag short name : introspection info of tag - * handler for tag - */ - private Hashtable handlerInfos; - - private Hashtable tagVarNumbers; - - private String parent; - - private boolean isSimpleTagParent; // Is parent a SimpleTag? - - private String pushBodyCountVar; - - private String simpleTagHandlerVar; - - private boolean isSimpleTagHandler; - - private boolean isFragment; - - private boolean isTagFile; - - private ServletWriter out; - - private ArrayList methodsBuffered; - - private FragmentHelperClass fragmentHelperClass; - - private int methodNesting; - - private TagInfo tagInfo; - - private ClassLoader loader; - - private int charArrayCount; - - private HashMap textMap; - - /** - * Constructor. - */ - public GenerateVisitor(boolean isTagFile, ServletWriter out, - ArrayList methodsBuffered, - FragmentHelperClass fragmentHelperClass, ClassLoader loader, - TagInfo tagInfo) { - - this.isTagFile = isTagFile; - this.out = out; - this.methodsBuffered = methodsBuffered; - this.fragmentHelperClass = fragmentHelperClass; - this.loader = loader; - this.tagInfo = tagInfo; - methodNesting = 0; - handlerInfos = new Hashtable(); - tagVarNumbers = new Hashtable(); - textMap = new HashMap(); - } - - /** - * Returns an attribute value, optionally URL encoded. If the value is a - * runtime expression, the result is the expression itself, as a string. - * If the result is an EL expression, we insert a call to the - * interpreter. If the result is a Named Attribute we insert the - * generated variable name. Otherwise the result is a string literal, - * quoted and escaped. - * - * @param attr - * An JspAttribute object - * @param encode - * true if to be URL encoded - * @param expectedType - * the expected type for an EL evaluation (ignored for - * attributes that aren't EL expressions) - */ - private String attributeValue(Node.JspAttribute attr, boolean encode, - Class expectedType) { - String v = attr.getValue(); - if (!attr.isNamedAttribute() && (v == null)) - return ""; - - if (attr.isExpression()) { - if (encode) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf(" - + v + "), request.getCharacterEncoding())"; - } - return v; - } else if (attr.isELInterpreterInput()) { - boolean replaceESC = v.indexOf(Constants.ESC) > 0; - v = JspUtil.interpreterCall(this.isTagFile, v, expectedType, - attr.getEL().getMapName(), false); - // XXX ESC replacement hack - if (replaceESC) { - v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')"; - } - if (encode) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(" - + v + ", request.getCharacterEncoding())"; - } - return v; - } else if (attr.isNamedAttribute()) { - return attr.getNamedAttributeNode().getTemporaryVariableName(); - } else { - if (encode) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(" - + quote(v) + ", request.getCharacterEncoding())"; - } - return quote(v); - } - } - - /** - * Prints the attribute value specified in the param action, in the form - * of name=value string. - * - * @param n - * the parent node for the param action nodes. - */ - private void printParams(Node n, String pageParam, boolean literal) - throws JasperException { - - class ParamVisitor extends Node.Visitor { - String separator; - - ParamVisitor(String separator) { - this.separator = separator; - } - - public void visit(Node.ParamAction n) throws JasperException { - - out.print(" + "); - out.print(separator); - out.print(" + "); - out.print("org.apache.jasper.runtime.JspRuntimeLibrary." - + "URLEncode(" + quote(n.getTextAttribute("name")) - + ", request.getCharacterEncoding())"); - out.print("+ \"=\" + "); - out.print(attributeValue(n.getValue(), true, String.class)); - - // The separator is '&' after the second use - separator = "\"&\""; - } - } - - String sep; - if (literal) { - sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\""; - } else { - sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')"; - } - if (n.getBody() != null) { - n.getBody().visit(new ParamVisitor(sep)); - } - } - - public void visit(Node.Expression n) throws JasperException { - n.setBeginJavaLine(out.getJavaLine()); - out.printin("out.print("); - out.printMultiLn(n.getText()); - out.println(");"); - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.Scriptlet n) throws JasperException { - n.setBeginJavaLine(out.getJavaLine()); - out.printMultiLn(n.getText()); - out.println(); - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.ELExpression n) throws JasperException { - n.setBeginJavaLine(out.getJavaLine()); - if (!pageInfo.isELIgnored()) { - out.printil("out.write(" - + JspUtil.interpreterCall(this.isTagFile, "${" - + new String(n.getText()) + "}", String.class, - n.getEL().getMapName(), false) + ");"); - } else { - out.printil("out.write(" - + quote("${" + new String(n.getText()) + "}") + ");"); - } - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.IncludeAction n) throws JasperException { - - String flush = n.getTextAttribute("flush"); - Node.JspAttribute page = n.getPage(); - - boolean isFlush = false; // default to false; - if ("true".equals(flush)) - isFlush = true; - - n.setBeginJavaLine(out.getJavaLine()); - - String pageParam; - if (page.isNamedAttribute()) { - // If the page for jsp:include was specified via - // jsp:attribute, first generate code to evaluate - // that body. - pageParam = generateNamedAttributeValue(page - .getNamedAttributeNode()); - } else { - pageParam = attributeValue(page, false, String.class); - } - - // If any of the params have their values specified by - // jsp:attribute, prepare those values first. - Node jspBody = findJspBody(n); - if (jspBody != null) { - prepareParams(jspBody); - } else { - prepareParams(n); - } - - out - .printin("org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, " - + pageParam); - printParams(n, pageParam, page.isLiteral()); - out.println(", out, " + isFlush + ");"); - - n.setEndJavaLine(out.getJavaLine()); - } - - /** - * Scans through all child nodes of the given parent for - * subelements. For each element, if its value is specified via - * a Named Attribute (), generate the code to evaluate - * those bodies first. - *

        - * If parent is null, simply returns. - */ - private void prepareParams(Node parent) throws JasperException { - if (parent == null) - return; - - Node.Nodes subelements = parent.getBody(); - if (subelements != null) { - for (int i = 0; i < subelements.size(); i++) { - Node n = subelements.getNode(i); - if (n instanceof Node.ParamAction) { - Node.Nodes paramSubElements = n.getBody(); - for (int j = 0; (paramSubElements != null) - && (j < paramSubElements.size()); j++) { - Node m = paramSubElements.getNode(j); - if (m instanceof Node.NamedAttribute) { - generateNamedAttributeValue((Node.NamedAttribute) m); - } - } - } - } - } - } - - /** - * Finds the subelement of the given parent node. If not - * found, null is returned. - */ - private Node.JspBody findJspBody(Node parent) throws JasperException { - Node.JspBody result = null; - - Node.Nodes subelements = parent.getBody(); - for (int i = 0; (subelements != null) && (i < subelements.size()); i++) { - Node n = subelements.getNode(i); - if (n instanceof Node.JspBody) { - result = (Node.JspBody) n; - break; - } - } - - return result; - } - - public void visit(Node.ForwardAction n) throws JasperException { - Node.JspAttribute page = n.getPage(); - - n.setBeginJavaLine(out.getJavaLine()); - - out.printil("if (true) {"); // So that javac won't complain about - out.pushIndent(); // codes after "return" - - String pageParam; - if (page.isNamedAttribute()) { - // If the page for jsp:forward was specified via - // jsp:attribute, first generate code to evaluate - // that body. - pageParam = generateNamedAttributeValue(page - .getNamedAttributeNode()); - } else { - pageParam = attributeValue(page, false, String.class); - } - - // If any of the params have their values specified by - // jsp:attribute, prepare those values first. - Node jspBody = findJspBody(n); - if (jspBody != null) { - prepareParams(jspBody); - } else { - prepareParams(n); - } - - out.printin("_jspx_page_context.forward("); - out.print(pageParam); - printParams(n, pageParam, page.isLiteral()); - out.println(");"); - if (isTagFile || isFragment) { - out.printil("throw new SkipPageException();"); - } else { - out.printil((methodNesting > 0) ? "return true;" : "return;"); - } - out.popIndent(); - out.printil("}"); - - n.setEndJavaLine(out.getJavaLine()); - // XXX Not sure if we can eliminate dead codes after this. - } - - public void visit(Node.GetProperty n) throws JasperException { - String name = n.getTextAttribute("name"); - String property = n.getTextAttribute("property"); - - n.setBeginJavaLine(out.getJavaLine()); - - if (beanInfo.checkVariable(name)) { - // Bean is defined using useBean, introspect at compile time - Class bean = beanInfo.getBeanType(name); - String beanName = JspUtil.getCanonicalName(bean); - java.lang.reflect.Method meth = JspRuntimeLibrary - .getReadMethod(bean, property); - String methodName = meth.getName(); - out - .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString(" - + "(((" - + beanName - + ")_jspx_page_context.findAttribute(" - + "\"" - + name + "\"))." + methodName + "())));"); - } else { - // The object could be a custom action with an associated - // VariableInfo entry for this name. - // Get the class name and then introspect at runtime. - out - .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString" - + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty" - + "(_jspx_page_context.getAttribute(\"" - + name - + "\", PageContext.PAGE_SCOPE), \"" - + property - + "\")));"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.SetProperty n) throws JasperException { - String name = n.getTextAttribute("name"); - String property = n.getTextAttribute("property"); - String param = n.getTextAttribute("param"); - Node.JspAttribute value = n.getValue(); - - n.setBeginJavaLine(out.getJavaLine()); - - if ("*".equals(property)) { - out - .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspect(" - + "_jspx_page_context.findAttribute(" - + "\"" - + name + "\"), request);"); - } else if (value == null) { - if (param == null) - param = property; // default to same as property - out - .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" - + "_jspx_page_context.findAttribute(\"" - + name - + "\"), \"" - + property - + "\", request.getParameter(\"" - + param - + "\"), " - + "request, \"" - + param - + "\", false);"); - } else if (value.isExpression()) { - out - .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty(" - + "_jspx_page_context.findAttribute(\"" - + name - + "\"), \"" + property + "\","); - out.print(attributeValue(value, false, null)); - out.println(");"); - } else if (value.isELInterpreterInput()) { - // We've got to resolve the very call to the interpreter - // at runtime since we don't know what type to expect - // in the general case; we thus can't hard-wire the call - // into the generated code. (XXX We could, however, - // optimize the case where the bean is exposed with - // , much as the code here does for - // getProperty.) - - // The following holds true for the arguments passed to - // JspRuntimeLibrary.handleSetPropertyExpression(): - // - 'pageContext' is a VariableResolver. - // - 'this' (either the generated Servlet or the generated tag - // handler for Tag files) is a FunctionMapper. - out - .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression(" - + "_jspx_page_context.findAttribute(\"" - + name - + "\"), \"" - + property - + "\", " - + quote(value.getValue()) - + ", " - + "_jspx_page_context, " - + value.getEL().getMapName() + ");"); - } else if (value.isNamedAttribute()) { - // If the value for setProperty was specified via - // jsp:attribute, first generate code to evaluate - // that body. - String valueVarName = generateNamedAttributeValue(value - .getNamedAttributeNode()); - out - .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" - + "_jspx_page_context.findAttribute(\"" - + name - + "\"), \"" - + property - + "\", " - + valueVarName - + ", null, null, false);"); - } else { - out - .printin("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" - + "_jspx_page_context.findAttribute(\"" - + name - + "\"), \"" + property + "\", "); - out.print(attributeValue(value, false, null)); - out.println(", null, null, false);"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.UseBean n) throws JasperException { - - String name = n.getTextAttribute("id"); - String scope = n.getTextAttribute("scope"); - String klass = n.getTextAttribute("class"); - String type = n.getTextAttribute("type"); - Node.JspAttribute beanName = n.getBeanName(); - - // If "class" is specified, try an instantiation at compile time - boolean generateNew = false; - String canonicalName = null; // Canonical name for klass - if (klass != null) { - try { - Class bean = ctxt.getClassLoader().loadClass(klass); - if (klass.indexOf('$') >= 0) { - // Obtain the canonical type name - canonicalName = JspUtil.getCanonicalName(bean); - } else { - canonicalName = klass; - } - int modifiers = bean.getModifiers(); - if (!Modifier.isPublic(modifiers) - || Modifier.isInterface(modifiers) - || Modifier.isAbstract(modifiers)) { - throw new Exception("Invalid bean class modifier"); - } - // Check that there is a 0 arg constructor - bean.getConstructor(new Class[] {}); - // At compile time, we have determined that the bean class - // exists, with a public zero constructor, new() can be - // used for bean instantiation. - generateNew = true; - } catch (Exception e) { - // Cannot instantiate the specified class, either a - // compilation error or a runtime error will be raised, - // depending on a compiler flag. - if (ctxt.getOptions() - .getErrorOnUseBeanInvalidClassAttribute()) { - err.jspError(n, "jsp.error.invalid.bean", klass); - } - if (canonicalName == null) { - // Doing our best here to get a canonical name - // from the binary name, should work 99.99% of time. - canonicalName = klass.replace('$', '.'); - } - } - if (type == null) { - // if type is unspecified, use "class" as type of bean - type = canonicalName; - } - } - - String scopename = "PageContext.PAGE_SCOPE"; // Default to page - String lock = "_jspx_page_context"; - - if ("request".equals(scope)) { - scopename = "PageContext.REQUEST_SCOPE"; - lock = "request"; - } else if ("session".equals(scope)) { - scopename = "PageContext.SESSION_SCOPE"; - lock = "session"; - } else if ("application".equals(scope)) { - scopename = "PageContext.APPLICATION_SCOPE"; - lock = "application"; - } - - n.setBeginJavaLine(out.getJavaLine()); - - // Declare bean - out.printin(type); - out.print(' '); - out.print(name); - out.println(" = null;"); - - // Lock while getting or creating bean - out.printin("synchronized ("); - out.print(lock); - out.println(") {"); - out.pushIndent(); - - // Locate bean from context - out.printin(name); - out.print(" = ("); - out.print(type); - out.print(") _jspx_page_context.getAttribute("); - out.print(quote(name)); - out.print(", "); - out.print(scopename); - out.println(");"); - - // Create bean - /* - * Check if bean is alredy there - */ - out.printin("if ("); - out.print(name); - out.println(" == null){"); - out.pushIndent(); - if (klass == null && beanName == null) { - /* - * If both class name and beanName is not specified, the bean - * must be found locally, otherwise it's an error - */ - out - .printin("throw new java.lang.InstantiationException(\"bean "); - out.print(name); - out.println(" not found within scope\");"); - } else { - /* - * Instantiate the bean if it is not in the specified scope. - */ - if (!generateNew) { - String binaryName; - if (beanName != null) { - if (beanName.isNamedAttribute()) { - // If the value for beanName was specified via - // jsp:attribute, first generate code to evaluate - // that body. - binaryName = generateNamedAttributeValue(beanName - .getNamedAttributeNode()); - } else { - binaryName = attributeValue(beanName, false, - String.class); - } - } else { - // Implies klass is not null - binaryName = quote(klass); - } - out.printil("try {"); - out.pushIndent(); - out.printin(name); - out.print(" = ("); - out.print(type); - out.print(") java.beans.Beans.instantiate("); - out.print("this.getClass().getClassLoader(), "); - out.print(binaryName); - out.println(");"); - out.popIndent(); - /* - * Note: Beans.instantiate throws ClassNotFoundException if - * the bean class is abstract. - */ - out.printil("} catch (ClassNotFoundException exc) {"); - out.pushIndent(); - out - .printil("throw new InstantiationException(exc.getMessage());"); - out.popIndent(); - out.printil("} catch (Exception exc) {"); - out.pushIndent(); - out.printin("throw new ServletException("); - out.print("\"Cannot create bean of class \" + "); - out.print(binaryName); - out.println(", exc);"); - out.popIndent(); - out.printil("}"); // close of try - } else { - // Implies klass is not null - // Generate codes to instantiate the bean class - out.printin(name); - out.print(" = new "); - out.print(canonicalName); - out.println("();"); - } - /* - * Set attribute for bean in the specified scope - */ - out.printin("_jspx_page_context.setAttribute("); - out.print(quote(name)); - out.print(", "); - out.print(name); - out.print(", "); - out.print(scopename); - out.println(");"); - - // Only visit the body when bean is instantiated - visitBody(n); - } - out.popIndent(); - out.printil("}"); - - // End of lock block - out.popIndent(); - out.printil("}"); - - n.setEndJavaLine(out.getJavaLine()); - } - - /** - * @return a string for the form 'attr = "value"' - */ - private String makeAttr(String attr, String value) { - if (value == null) - return ""; - - return " " + attr + "=\"" + value + '\"'; - } - - public void visit(Node.PlugIn n) throws JasperException { - - /** - * A visitor to handle in a plugin - */ - class ParamVisitor extends Node.Visitor { - - private boolean ie; - - ParamVisitor(boolean ie) { - this.ie = ie; - } - - public void visit(Node.ParamAction n) throws JasperException { - - String name = n.getTextAttribute("name"); - if (name.equalsIgnoreCase("object")) - name = "java_object"; - else if (name.equalsIgnoreCase("type")) - name = "java_type"; - - n.setBeginJavaLine(out.getJavaLine()); - // XXX - Fixed a bug here - value used to be output - // inline, which is only okay if value is not an EL - // expression. Also, key/value pairs for the - // embed tag were not being generated correctly. - // Double check that this is now the correct behavior. - if (ie) { - // We want something of the form - // out.println( "" ); - out.printil("out.write( \"\" );"); - out.printil("out.write(\"\\n\");"); - } else { - // We want something of the form - // out.print( " blah=\"" + ... + "\"" ); - out.printil("out.write( \" " - + escape(name) - + "=\\\"\" + " - + attributeValue(n.getValue(), false, - String.class) + " + \"\\\"\" );"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - } - - String type = n.getTextAttribute("type"); - String code = n.getTextAttribute("code"); - String name = n.getTextAttribute("name"); - Node.JspAttribute height = n.getHeight(); - Node.JspAttribute width = n.getWidth(); - String hspace = n.getTextAttribute("hspace"); - String vspace = n.getTextAttribute("vspace"); - String align = n.getTextAttribute("align"); - String iepluginurl = n.getTextAttribute("iepluginurl"); - String nspluginurl = n.getTextAttribute("nspluginurl"); - String codebase = n.getTextAttribute("codebase"); - String archive = n.getTextAttribute("archive"); - String jreversion = n.getTextAttribute("jreversion"); - - String widthStr = null; - if (width != null) { - if (width.isNamedAttribute()) { - widthStr = generateNamedAttributeValue(width - .getNamedAttributeNode()); - } else { - widthStr = attributeValue(width, false, String.class); - } - } - - String heightStr = null; - if (height != null) { - if (height.isNamedAttribute()) { - heightStr = generateNamedAttributeValue(height - .getNamedAttributeNode()); - } else { - heightStr = attributeValue(height, false, String.class); - } - } - - if (iepluginurl == null) - iepluginurl = Constants.IE_PLUGIN_URL; - if (nspluginurl == null) - nspluginurl = Constants.NS_PLUGIN_URL; - - n.setBeginJavaLine(out.getJavaLine()); - - // If any of the params have their values specified by - // jsp:attribute, prepare those values first. - // Look for a params node and prepare its param subelements: - Node.JspBody jspBody = findJspBody(n); - if (jspBody != null) { - Node.Nodes subelements = jspBody.getBody(); - if (subelements != null) { - for (int i = 0; i < subelements.size(); i++) { - Node m = subelements.getNode(i); - if (m instanceof Node.ParamsAction) { - prepareParams(m); - break; - } - } - } - } - - // XXX - Fixed a bug here - width and height can be set - // dynamically. Double-check if this generation is correct. - - // IE style plugin - // - // First compose the runtime output string - String s0 = "'; - - // Then print the output string to the java file - out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3) - + ");"); - out.printil("out.write(\"\\n\");"); - - // for java_code - s0 = "'; - out.printil("out.write(" + quote(s0) + ");"); - out.printil("out.write(\"\\n\");"); - - // for java_codebase - if (codebase != null) { - s0 = "'; - out.printil("out.write(" + quote(s0) + ");"); - out.printil("out.write(\"\\n\");"); - } - - // for java_archive - if (archive != null) { - s0 = "'; - out.printil("out.write(" + quote(s0) + ");"); - out.printil("out.write(\"\\n\");"); - } - - // for type - s0 = " for each in the plugin body - */ - if (n.getBody() != null) - n.getBody().visit(new ParamVisitor(true)); - - /* - * Netscape style plugin part - */ - out.printil("out.write(" + quote("") + ");"); - out.printil("out.write(\"\\n\");"); - s0 = " in plugin body - */ - if (n.getBody() != null) - n.getBody().visit(new ParamVisitor(false)); - - out.printil("out.write(" + quote("/>") + ");"); - out.printil("out.write(\"\\n\");"); - - out.printil("out.write(" + quote("") + ");"); - out.printil("out.write(\"\\n\");"); - - /* - * Fallback - */ - if (n.getBody() != null) { - visitBody(n); - out.printil("out.write(\"\\n\");"); - } - - out.printil("out.write(" + quote("") + ");"); - out.printil("out.write(\"\\n\");"); - - out.printil("out.write(" + quote("") + ");"); - out.printil("out.write(\"\\n\");"); - - out.printil("out.write(" + quote("") + ");"); - out.printil("out.write(\"\\n\");"); - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - // Don't visit body of this tag - we already did earlier. - } - - public void visit(Node.CustomTag n) throws JasperException { - - // Use plugin to generate more efficient code if there is one. - if (n.useTagPlugin()) { - generateTagPlugin(n); - return; - } - - TagHandlerInfo handlerInfo = getTagHandlerInfo(n); - - // Create variable names - String baseVar = createTagVarName(n.getQName(), n.getPrefix(), n - .getLocalName()); - String tagEvalVar = "_jspx_eval_" + baseVar; - String tagHandlerVar = "_jspx_th_" + baseVar; - String tagPushBodyCountVar = "_jspx_push_body_count_" + baseVar; - - // If the tag contains no scripting element, generate its codes - // to a method. - ServletWriter outSave = null; - Node.ChildInfo ci = n.getChildInfo(); - if (ci.isScriptless() && !ci.hasScriptingVars()) { - // The tag handler and its body code can reside in a separate - // method if it is scriptless and does not have any scripting - // variable defined. - - String tagMethod = "_jspx_meth_" + baseVar; - - // Generate a call to this method - out.printin("if ("); - out.print(tagMethod); - out.print("("); - if (parent != null) { - out.print(parent); - out.print(", "); - } - out.print("_jspx_page_context"); - if (pushBodyCountVar != null) { - out.print(", "); - out.print(pushBodyCountVar); - } - out.println("))"); - out.pushIndent(); - out.printil((methodNesting > 0) ? "return true;" : "return;"); - out.popIndent(); - - // Set up new buffer for the method - outSave = out; - /* - * For fragments, their bodies will be generated in fragment - * helper classes, and the Java line adjustments will be done - * there, hence they are set to null here to avoid double - * adjustments. - */ - GenBuffer genBuffer = new GenBuffer(n, - n.implementsSimpleTag() ? null : n.getBody()); - methodsBuffered.add(genBuffer); - out = genBuffer.getOut(); - - methodNesting++; - // Generate code for method declaration - out.println(); - out.pushIndent(); - out.printin("private boolean "); - out.print(tagMethod); - out.print("("); - if (parent != null) { - out.print("javax.servlet.jsp.tagext.JspTag "); - out.print(parent); - out.print(", "); - } - out.print("PageContext _jspx_page_context"); - if (pushBodyCountVar != null) { - out.print(", int[] "); - out.print(pushBodyCountVar); - } - out.println(")"); - out.printil(" throws Throwable {"); - out.pushIndent(); - - // Initilaize local variables used in this method. - if (!isTagFile) { - out - .printil("PageContext pageContext = _jspx_page_context;"); - } - out.printil("JspWriter out = _jspx_page_context.getOut();"); - generateLocalVariables(out, n); - } - - if (n.implementsSimpleTag()) { - generateCustomDoTag(n, handlerInfo, tagHandlerVar); - } else { - /* - * Classic tag handler: Generate code for start element, body, - * and end element - */ - generateCustomStart(n, handlerInfo, tagHandlerVar, tagEvalVar, - tagPushBodyCountVar); - - // visit body - String tmpParent = parent; - parent = tagHandlerVar; - boolean isSimpleTagParentSave = isSimpleTagParent; - isSimpleTagParent = false; - String tmpPushBodyCountVar = null; - if (n.implementsTryCatchFinally()) { - tmpPushBodyCountVar = pushBodyCountVar; - pushBodyCountVar = tagPushBodyCountVar; - } - boolean tmpIsSimpleTagHandler = isSimpleTagHandler; - isSimpleTagHandler = false; - - visitBody(n); - - parent = tmpParent; - isSimpleTagParent = isSimpleTagParentSave; - if (n.implementsTryCatchFinally()) { - pushBodyCountVar = tmpPushBodyCountVar; - } - isSimpleTagHandler = tmpIsSimpleTagHandler; - - generateCustomEnd(n, tagHandlerVar, tagEvalVar, - tagPushBodyCountVar); - } - - if (ci.isScriptless() && !ci.hasScriptingVars()) { - // Generate end of method - if (methodNesting > 0) { - out.printil("return false;"); - } - out.popIndent(); - out.printil("}"); - out.popIndent(); - - methodNesting--; - - // restore previous writer - out = outSave; - } - } - - private static final String SINGLE_QUOTE = "'"; - - private static final String DOUBLE_QUOTE = "\\\""; - - public void visit(Node.UninterpretedTag n) throws JasperException { - - n.setBeginJavaLine(out.getJavaLine()); - - /* - * Write begin tag - */ - out.printin("out.write(\"<"); - out.print(n.getQName()); - - Attributes attrs = n.getNonTaglibXmlnsAttributes(); - int attrsLen = (attrs == null) ? 0 : attrs.getLength(); - for (int i = 0; i < attrsLen; i++) { - out.print(" "); - out.print(attrs.getQName(i)); - out.print("="); - String quote = DOUBLE_QUOTE; - String value = attrs.getValue(i); - if (value.indexOf('"') != -1) { - quote = SINGLE_QUOTE; - } - out.print(quote); - out.print(value); - out.print(quote); - } - - attrs = n.getAttributes(); - attrsLen = (attrs == null) ? 0 : attrs.getLength(); - Node.JspAttribute[] jspAttrs = n.getJspAttributes(); - for (int i = 0; i < attrsLen; i++) { - out.print(" "); - out.print(attrs.getQName(i)); - out.print("="); - if (jspAttrs[i].isELInterpreterInput()) { - out.print("\\\"\" + "); - out.print(attributeValue(jspAttrs[i], false, String.class)); - out.print(" + \"\\\""); - } else { - String quote = DOUBLE_QUOTE; - String value = attrs.getValue(i); - if (value.indexOf('"') != -1) { - quote = SINGLE_QUOTE; - } - out.print(quote); - out.print(value); - out.print(quote); - } - } - - if (n.getBody() != null) { - out.println(">\");"); - - // Visit tag body - visitBody(n); - - /* - * Write end tag - */ - out.printin("out.write(\"\");"); - } else { - out.println("/>\");"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.JspElement n) throws JasperException { - - n.setBeginJavaLine(out.getJavaLine()); - - // Compute attribute value string for XML-style and named - // attributes - Hashtable map = new Hashtable(); - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - String attrStr = null; - if (attrs[i].isNamedAttribute()) { - attrStr = generateNamedAttributeValue(attrs[i] - .getNamedAttributeNode()); - } else { - attrStr = attributeValue(attrs[i], false, Object.class); - } - String s = " + \" " + attrs[i].getName() + "=\\\"\" + " - + attrStr + " + \"\\\"\""; - map.put(attrs[i].getName(), s); - } - - // Write begin tag, using XML-style 'name' attribute as the - // element name - String elemName = attributeValue(n.getNameAttribute(), false, - String.class); - out.printin("out.write(\"<\""); - out.print(" + " + elemName); - - // Write remaining attributes - Enumeration enumeration = map.keys(); - while (enumeration.hasMoreElements()) { - String attrName = (String) enumeration.nextElement(); - out.print((String) map.get(attrName)); - } - - // Does the have nested tags other than - // - boolean hasBody = false; - Node.Nodes subelements = n.getBody(); - if (subelements != null) { - for (int i = 0; i < subelements.size(); i++) { - Node subelem = subelements.getNode(i); - if (!(subelem instanceof Node.NamedAttribute)) { - hasBody = true; - break; - } - } - } - if (hasBody) { - out.println(" + \">\");"); - - // Smap should not include the body - n.setEndJavaLine(out.getJavaLine()); - - // Visit tag body - visitBody(n); - - // Write end tag - out.printin("out.write(\"\");"); - } else { - out.println(" + \"/>\");"); - n.setEndJavaLine(out.getJavaLine()); - } - } - - public void visit(Node.TemplateText n) throws JasperException { - - String text = n.getText(); - - int textSize = text.length(); - if (textSize == 0) { - return; - } - - if (textSize <= 3) { - // Special case small text strings - n.setBeginJavaLine(out.getJavaLine()); - int lineInc = 0; - for (int i = 0; i < textSize; i++) { - char ch = text.charAt(i); - out.printil("out.write(" + quote(ch) + ");"); - if (i > 0) { - n.addSmap(lineInc); - } - if (ch == '\n') { - lineInc++; - } - } - n.setEndJavaLine(out.getJavaLine()); - return; - } - - if (ctxt.getOptions().genStringAsCharArray()) { - // Generate Strings as char arrays, for performance - ServletWriter caOut; - if (charArrayBuffer == null) { - charArrayBuffer = new GenBuffer(); - caOut = charArrayBuffer.getOut(); - caOut.pushIndent(); - textMap = new HashMap(); - } else { - caOut = charArrayBuffer.getOut(); - } - String charArrayName = (String) textMap.get(text); - if (charArrayName == null) { - charArrayName = "_jspx_char_array_" + charArrayCount++; - textMap.put(text, charArrayName); - caOut.printin("static char[] "); - caOut.print(charArrayName); - caOut.print(" = "); - caOut.print(quote(text)); - caOut.println(".toCharArray();"); - } - - n.setBeginJavaLine(out.getJavaLine()); - out.printil("out.write(" + charArrayName + ");"); - n.setEndJavaLine(out.getJavaLine()); - return; - } - - n.setBeginJavaLine(out.getJavaLine()); - - out.printin(); - StringBuffer sb = new StringBuffer("out.write(\""); - int initLength = sb.length(); - int count = JspUtil.CHUNKSIZE; - int srcLine = 0; // relative to starting srouce line - for (int i = 0; i < text.length(); i++) { - char ch = text.charAt(i); - --count; - switch (ch) { - case '"': - sb.append('\\').append('\"'); - break; - case '\\': - sb.append('\\').append('\\'); - break; - case '\r': - sb.append('\\').append('r'); - break; - case '\n': - sb.append('\\').append('n'); - srcLine++; - - if (breakAtLF || count < 0) { - // Generate an out.write() when see a '\n' in template - sb.append("\");"); - out.println(sb.toString()); - if (i < text.length() - 1) { - out.printin(); - } - sb.setLength(initLength); - count = JspUtil.CHUNKSIZE; - } - // add a Smap for this line - n.addSmap(srcLine); - break; - case '\t': // Not sure we need this - sb.append('\\').append('t'); - break; - default: - sb.append(ch); - } - } - - if (sb.length() > initLength) { - sb.append("\");"); - out.println(sb.toString()); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.JspBody n) throws JasperException { - if (n.getBody() != null) { - if (isSimpleTagHandler) { - out.printin(simpleTagHandlerVar); - out.print(".setJspBody("); - generateJspFragment(n, simpleTagHandlerVar); - out.println(");"); - } else { - visitBody(n); - } - } - } - - public void visit(Node.InvokeAction n) throws JasperException { - - n.setBeginJavaLine(out.getJavaLine()); - - // Copy virtual page scope of tag file to page scope of invoking - // page - out - .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();"); - String varReaderAttr = n.getTextAttribute("varReader"); - String varAttr = n.getTextAttribute("var"); - if (varReaderAttr != null || varAttr != null) { - out.printil("_jspx_sout = new java.io.StringWriter();"); - } else { - out.printil("_jspx_sout = null;"); - } - - // Invoke fragment, unless fragment is null - out.printin("if ("); - out.print(toGetterMethod(n.getTextAttribute("fragment"))); - out.println(" != null) {"); - out.pushIndent(); - out.printin(toGetterMethod(n.getTextAttribute("fragment"))); - out.println(".invoke(_jspx_sout);"); - out.popIndent(); - out.printil("}"); - - // Store varReader in appropriate scope - if (varReaderAttr != null || varAttr != null) { - String scopeName = n.getTextAttribute("scope"); - out.printin("_jspx_page_context.setAttribute("); - if (varReaderAttr != null) { - out.print(quote(varReaderAttr)); - out - .print(", new java.io.StringReader(_jspx_sout.toString())"); - } else { - out.print(quote(varAttr)); - out.print(", _jspx_sout.toString()"); - } - if (scopeName != null) { - out.print(", "); - out.print(getScopeConstant(scopeName)); - } - out.println(");"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.DoBodyAction n) throws JasperException { - - n.setBeginJavaLine(out.getJavaLine()); - - // Copy virtual page scope of tag file to page scope of invoking - // page - out - .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();"); - - // Invoke body - String varReaderAttr = n.getTextAttribute("varReader"); - String varAttr = n.getTextAttribute("var"); - if (varReaderAttr != null || varAttr != null) { - out.printil("_jspx_sout = new java.io.StringWriter();"); - } else { - out.printil("_jspx_sout = null;"); - } - out.printil("if (getJspBody() != null)"); - out.pushIndent(); - out.printil("getJspBody().invoke(_jspx_sout);"); - out.popIndent(); - - // Store varReader in appropriate scope - if (varReaderAttr != null || varAttr != null) { - String scopeName = n.getTextAttribute("scope"); - out.printin("_jspx_page_context.setAttribute("); - if (varReaderAttr != null) { - out.print(quote(varReaderAttr)); - out - .print(", new java.io.StringReader(_jspx_sout.toString())"); - } else { - out.print(quote(varAttr)); - out.print(", _jspx_sout.toString()"); - } - if (scopeName != null) { - out.print(", "); - out.print(getScopeConstant(scopeName)); - } - out.println(");"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - public void visit(Node.AttributeGenerator n) throws JasperException { - Node.CustomTag tag = n.getTag(); - Node.JspAttribute[] attrs = tag.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - if (attrs[i].getName().equals(n.getName())) { - out.print(evaluateAttribute(getTagHandlerInfo(tag), - attrs[i], tag, null)); - break; - } - } - } - - private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n) - throws JasperException { - Hashtable handlerInfosByShortName = (Hashtable) handlerInfos.get(n - .getPrefix()); - if (handlerInfosByShortName == null) { - handlerInfosByShortName = new Hashtable(); - handlerInfos.put(n.getPrefix(), handlerInfosByShortName); - } - TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName - .get(n.getLocalName()); - if (handlerInfo == null) { - handlerInfo = new TagHandlerInfo(n, n.getTagHandlerClass(), err); - handlerInfosByShortName.put(n.getLocalName(), handlerInfo); - } - return handlerInfo; - } - - private void generateTagPlugin(Node.CustomTag n) throws JasperException { - if (n.getAtSTag() != null) { - n.getAtSTag().visit(this); - } - visitBody(n); - if (n.getAtETag() != null) { - n.getAtETag().visit(this); - } - } - - private void generateCustomStart(Node.CustomTag n, - TagHandlerInfo handlerInfo, String tagHandlerVar, - String tagEvalVar, String tagPushBodyCountVar) - throws JasperException { - - Class tagHandlerClass = handlerInfo.getTagHandlerClass(); - - out.printin("// "); - out.println(n.getQName()); - n.setBeginJavaLine(out.getJavaLine()); - - // Declare AT_BEGIN scripting variables - declareScriptingVars(n, VariableInfo.AT_BEGIN); - saveScriptingVars(n, VariableInfo.AT_BEGIN); - - String tagHandlerClassName = JspUtil - .getCanonicalName(tagHandlerClass); - out.printin(tagHandlerClassName); - out.print(" "); - out.print(tagHandlerVar); - out.print(" = "); - if (isPoolingEnabled) { - out.print("("); - out.print(tagHandlerClassName); - out.print(") "); - out.print(n.getTagHandlerPoolName()); - out.print(".get("); - out.print(tagHandlerClassName); - out.println(".class);"); - } else { - out.print("new "); - out.print(tagHandlerClassName); - out.println("();"); - if (!ctxt.getOptions().getIgnoreAnnotations()) { - out.printin("org.apache.jasper.runtime.AnnotationProcessor.postConstruct("); - out.print(tagHandlerVar); - out.println(");"); - } - } - - // includes setting the context - generateSetters(n, tagHandlerVar, handlerInfo, false); - - // JspIdConsumer (after context has been set) - if (n.implementsJspIdConsumer()) { - out.printin(tagHandlerVar); - out.print(".setJspId(\""); - out.print(createJspId()); - out.println("\");"); - } - - if (n.implementsTryCatchFinally()) { - out.printin("int[] "); - out.print(tagPushBodyCountVar); - out.println(" = new int[] { 0 };"); - out.printil("try {"); - out.pushIndent(); - } - out.printin("int "); - out.print(tagEvalVar); - out.print(" = "); - out.print(tagHandlerVar); - out.println(".doStartTag();"); - - if (!n.implementsBodyTag()) { - // Synchronize AT_BEGIN scripting variables - syncScriptingVars(n, VariableInfo.AT_BEGIN); - } - - if (!n.hasEmptyBody()) { - out.printin("if ("); - out.print(tagEvalVar); - out.println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {"); - out.pushIndent(); - - // Declare NESTED scripting variables - declareScriptingVars(n, VariableInfo.NESTED); - saveScriptingVars(n, VariableInfo.NESTED); - - if (n.implementsBodyTag()) { - out.printin("if ("); - out.print(tagEvalVar); - out - .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {"); - // Assume EVAL_BODY_BUFFERED - out.pushIndent(); - out.printil("out = _jspx_page_context.pushBody();"); - if (n.implementsTryCatchFinally()) { - out.printin(tagPushBodyCountVar); - out.println("[0]++;"); - } else if (pushBodyCountVar != null) { - out.printin(pushBodyCountVar); - out.println("[0]++;"); - } - out.printin(tagHandlerVar); - out - .println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);"); - out.printin(tagHandlerVar); - out.println(".doInitBody();"); - - out.popIndent(); - out.printil("}"); - - // Synchronize AT_BEGIN and NESTED scripting variables - syncScriptingVars(n, VariableInfo.AT_BEGIN); - syncScriptingVars(n, VariableInfo.NESTED); - - } else { - // Synchronize NESTED scripting variables - syncScriptingVars(n, VariableInfo.NESTED); - } - - if (n.implementsIterationTag()) { - out.printil("do {"); - out.pushIndent(); - } - } - // Map the Java lines that handles start of custom tags to the - // JSP line for this tag - n.setEndJavaLine(out.getJavaLine()); - } - - private void generateCustomEnd(Node.CustomTag n, String tagHandlerVar, - String tagEvalVar, String tagPushBodyCountVar) { - - if (!n.hasEmptyBody()) { - if (n.implementsIterationTag()) { - out.printin("int evalDoAfterBody = "); - out.print(tagHandlerVar); - out.println(".doAfterBody();"); - - // Synchronize AT_BEGIN and NESTED scripting variables - syncScriptingVars(n, VariableInfo.AT_BEGIN); - syncScriptingVars(n, VariableInfo.NESTED); - - out - .printil("if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)"); - out.pushIndent(); - out.printil("break;"); - out.popIndent(); - - out.popIndent(); - out.printil("} while (true);"); - } - - restoreScriptingVars(n, VariableInfo.NESTED); - - if (n.implementsBodyTag()) { - out.printin("if ("); - out.print(tagEvalVar); - out - .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {"); - out.pushIndent(); - out.printil("out = _jspx_page_context.popBody();"); - if (n.implementsTryCatchFinally()) { - out.printin(tagPushBodyCountVar); - out.println("[0]--;"); - } else if (pushBodyCountVar != null) { - out.printin(pushBodyCountVar); - out.println("[0]--;"); - } - out.popIndent(); - out.printil("}"); - } - - out.popIndent(); // EVAL_BODY - out.printil("}"); - } - - out.printin("if ("); - out.print(tagHandlerVar); - out - .println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {"); - out.pushIndent(); - if (!n.implementsTryCatchFinally()) { - if (isPoolingEnabled) { - out.printin(n.getTagHandlerPoolName()); - out.print(".reuse("); - out.print(tagHandlerVar); - out.println(");"); - } else { - out.printin(tagHandlerVar); - out.println(".release();"); - if (!ctxt.getOptions().getIgnoreAnnotations()) { - out.printil("try {"); - out.pushIndent(); - out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); - out.print(tagHandlerVar); - out.println(");"); - out.popIndent(); - out.printil("} catch (Exception e) {"); - out.pushIndent(); - out.printin("log(\"Error processing preDestroy on tag instance of \" +"); - out.print(tagHandlerVar); - out.println(".getClass().getName());"); - out.popIndent(); - out.printil("}"); - } - } - } - if (isTagFile || isFragment) { - out.printil("throw new SkipPageException();"); - } else { - out.printil((methodNesting > 0) ? "return true;" : "return;"); - } - out.popIndent(); - out.printil("}"); - // Synchronize AT_BEGIN scripting variables - syncScriptingVars(n, VariableInfo.AT_BEGIN); - - // TryCatchFinally - if (n.implementsTryCatchFinally()) { - out.popIndent(); // try - out.printil("} catch (Throwable _jspx_exception) {"); - out.pushIndent(); - - out.printin("while ("); - out.print(tagPushBodyCountVar); - out.println("[0]-- > 0)"); - out.pushIndent(); - out.printil("out = _jspx_page_context.popBody();"); - out.popIndent(); - - out.printin(tagHandlerVar); - out.println(".doCatch(_jspx_exception);"); - out.popIndent(); - out.printil("} finally {"); - out.pushIndent(); - out.printin(tagHandlerVar); - out.println(".doFinally();"); - } - - if (isPoolingEnabled) { - out.printin(n.getTagHandlerPoolName()); - out.print(".reuse("); - out.print(tagHandlerVar); - out.println(");"); - } else { - out.printin(tagHandlerVar); - out.println(".release();"); - if (!ctxt.getOptions().getIgnoreAnnotations()) { - out.printil("try {"); - out.pushIndent(); - out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); - out.print(tagHandlerVar); - out.println(");"); - out.popIndent(); - out.printil("} catch (Exception e) {"); - out.pushIndent(); - out.printin("log(\"Error processing preDestroy on tag instance of \" +"); - out.print(tagHandlerVar); - out.println(".getClass().getName());"); - out.popIndent(); - out.printil("}"); - } - } - - if (n.implementsTryCatchFinally()) { - out.popIndent(); - out.printil("}"); - } - - // Declare and synchronize AT_END scripting variables (must do this - // outside the try/catch/finally block) - declareScriptingVars(n, VariableInfo.AT_END); - syncScriptingVars(n, VariableInfo.AT_END); - - restoreScriptingVars(n, VariableInfo.AT_BEGIN); - } - - private void generateCustomDoTag(Node.CustomTag n, - TagHandlerInfo handlerInfo, String tagHandlerVar) - throws JasperException { - - Class tagHandlerClass = handlerInfo.getTagHandlerClass(); - - n.setBeginJavaLine(out.getJavaLine()); - out.printin("// "); - out.println(n.getQName()); - - // Declare AT_BEGIN scripting variables - declareScriptingVars(n, VariableInfo.AT_BEGIN); - saveScriptingVars(n, VariableInfo.AT_BEGIN); - - String tagHandlerClassName = JspUtil - .getCanonicalName(tagHandlerClass); - out.printin(tagHandlerClassName); - out.print(" "); - out.print(tagHandlerVar); - out.print(" = "); - out.print("new "); - out.print(tagHandlerClassName); - out.println("();"); - - // Resource injection - if (!ctxt.getOptions().getIgnoreAnnotations()) { - out.printin("org.apache.jasper.runtime.AnnotationProcessor.postConstruct("); - out.print(tagHandlerVar); - out.println(");"); - } - - generateSetters(n, tagHandlerVar, handlerInfo, true); - - // Set the body - if (findJspBody(n) == null) { - /* - * Encapsulate body of custom tag invocation in JspFragment and - * pass it to tag handler's setJspBody(), unless tag body is - * empty - */ - if (!n.hasEmptyBody()) { - out.printin(tagHandlerVar); - out.print(".setJspBody("); - generateJspFragment(n, tagHandlerVar); - out.println(");"); - } - } else { - /* - * Body of tag is the body of the element. The visit - * method for that element is going to encapsulate that - * element's body in a JspFragment and pass it to the tag - * handler's setJspBody() - */ - String tmpTagHandlerVar = simpleTagHandlerVar; - simpleTagHandlerVar = tagHandlerVar; - boolean tmpIsSimpleTagHandler = isSimpleTagHandler; - isSimpleTagHandler = true; - visitBody(n); - simpleTagHandlerVar = tmpTagHandlerVar; - isSimpleTagHandler = tmpIsSimpleTagHandler; - } - - out.printin(tagHandlerVar); - out.println(".doTag();"); - - restoreScriptingVars(n, VariableInfo.AT_BEGIN); - - // Synchronize AT_BEGIN scripting variables - syncScriptingVars(n, VariableInfo.AT_BEGIN); - - // Declare and synchronize AT_END scripting variables - declareScriptingVars(n, VariableInfo.AT_END); - syncScriptingVars(n, VariableInfo.AT_END); - - // Resource injection - if (!ctxt.getOptions().getIgnoreAnnotations()) { - out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); - out.print(tagHandlerVar); - out.println(");"); - } - - n.setEndJavaLine(out.getJavaLine()); - } - - private void declareScriptingVars(Node.CustomTag n, int scope) { - - Vector vec = n.getScriptingVars(scope); - if (vec != null) { - for (int i = 0; i < vec.size(); i++) { - Object elem = vec.elementAt(i); - if (elem instanceof VariableInfo) { - VariableInfo varInfo = (VariableInfo) elem; - if (varInfo.getDeclare()) { - out.printin(varInfo.getClassName()); - out.print(" "); - out.print(varInfo.getVarName()); - out.println(" = null;"); - } - } else { - TagVariableInfo tagVarInfo = (TagVariableInfo) elem; - if (tagVarInfo.getDeclare()) { - String varName = tagVarInfo.getNameGiven(); - if (varName == null) { - varName = n.getTagData().getAttributeString( - tagVarInfo.getNameFromAttribute()); - } else if (tagVarInfo.getNameFromAttribute() != null) { - // alias - continue; - } - out.printin(tagVarInfo.getClassName()); - out.print(" "); - out.print(varName); - out.println(" = null;"); - } - } - } - } - } - - /* - * This method is called as part of the custom tag's start element. - * - * If the given custom tag has a custom nesting level greater than 0, - * save the current values of its scripting variables to temporary - * variables, so those values may be restored in the tag's end element. - * This way, the scripting variables may be synchronized by the given - * tag without affecting their original values. - */ - private void saveScriptingVars(Node.CustomTag n, int scope) { - if (n.getCustomNestingLevel() == 0) { - return; - } - - TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); - VariableInfo[] varInfos = n.getVariableInfos(); - if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { - return; - } - - if (varInfos.length > 0) { - for (int i = 0; i < varInfos.length; i++) { - if (varInfos[i].getScope() != scope) - continue; - // If the scripting variable has been declared, skip codes - // for saving and restoring it. - if (n.getScriptingVars(scope).contains(varInfos[i])) - continue; - String varName = varInfos[i].getVarName(); - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - out.printin(tmpVarName); - out.print(" = "); - out.print(varName); - out.println(";"); - } - } else { - for (int i = 0; i < tagVarInfos.length; i++) { - if (tagVarInfos[i].getScope() != scope) - continue; - // If the scripting variable has been declared, skip codes - // for saving and restoring it. - if (n.getScriptingVars(scope).contains(tagVarInfos[i])) - continue; - String varName = tagVarInfos[i].getNameGiven(); - if (varName == null) { - varName = n.getTagData().getAttributeString( - tagVarInfos[i].getNameFromAttribute()); - } else if (tagVarInfos[i].getNameFromAttribute() != null) { - // alias - continue; - } - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - out.printin(tmpVarName); - out.print(" = "); - out.print(varName); - out.println(";"); - } - } - } - - /* - * This method is called as part of the custom tag's end element. - * - * If the given custom tag has a custom nesting level greater than 0, - * restore its scripting variables to their original values that were - * saved in the tag's start element. - */ - private void restoreScriptingVars(Node.CustomTag n, int scope) { - if (n.getCustomNestingLevel() == 0) { - return; - } - - TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); - VariableInfo[] varInfos = n.getVariableInfos(); - if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { - return; - } - - if (varInfos.length > 0) { - for (int i = 0; i < varInfos.length; i++) { - if (varInfos[i].getScope() != scope) - continue; - // If the scripting variable has been declared, skip codes - // for saving and restoring it. - if (n.getScriptingVars(scope).contains(varInfos[i])) - continue; - String varName = varInfos[i].getVarName(); - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - out.printin(varName); - out.print(" = "); - out.print(tmpVarName); - out.println(";"); - } - } else { - for (int i = 0; i < tagVarInfos.length; i++) { - if (tagVarInfos[i].getScope() != scope) - continue; - // If the scripting variable has been declared, skip codes - // for saving and restoring it. - if (n.getScriptingVars(scope).contains(tagVarInfos[i])) - continue; - String varName = tagVarInfos[i].getNameGiven(); - if (varName == null) { - varName = n.getTagData().getAttributeString( - tagVarInfos[i].getNameFromAttribute()); - } else if (tagVarInfos[i].getNameFromAttribute() != null) { - // alias - continue; - } - String tmpVarName = "_jspx_" + varName + "_" - + n.getCustomNestingLevel(); - out.printin(varName); - out.print(" = "); - out.print(tmpVarName); - out.println(";"); - } - } - } - - /* - * Synchronizes the scripting variables of the given custom tag for the - * given scope. - */ - private void syncScriptingVars(Node.CustomTag n, int scope) { - TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); - VariableInfo[] varInfos = n.getVariableInfos(); - - if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { - return; - } - - if (varInfos.length > 0) { - for (int i = 0; i < varInfos.length; i++) { - if (varInfos[i].getScope() == scope) { - out.printin(varInfos[i].getVarName()); - out.print(" = ("); - out.print(varInfos[i].getClassName()); - out.print(") _jspx_page_context.findAttribute("); - out.print(quote(varInfos[i].getVarName())); - out.println(");"); - } - } - } else { - for (int i = 0; i < tagVarInfos.length; i++) { - if (tagVarInfos[i].getScope() == scope) { - String name = tagVarInfos[i].getNameGiven(); - if (name == null) { - name = n.getTagData().getAttributeString( - tagVarInfos[i].getNameFromAttribute()); - } else if (tagVarInfos[i].getNameFromAttribute() != null) { - // alias - continue; - } - out.printin(name); - out.print(" = ("); - out.print(tagVarInfos[i].getClassName()); - out.print(") _jspx_page_context.findAttribute("); - out.print(quote(name)); - out.println(");"); - } - } - } - } - - private String getJspContextVar() { - if (this.isTagFile) { - return "this.getJspContext()"; - } else { - return "_jspx_page_context"; - } - } - - private String getExpressionFactoryVar() { - return VAR_EXPRESSIONFACTORY; - } - - /* - * Creates a tag variable name by concatenating the given prefix and - * shortName and endcoded to make the resultant string a valid Java - * Identifier. - */ - private String createTagVarName(String fullName, String prefix, - String shortName) { - - String varName; - synchronized (tagVarNumbers) { - varName = prefix + "_" + shortName + "_"; - if (tagVarNumbers.get(fullName) != null) { - Integer i = (Integer) tagVarNumbers.get(fullName); - varName = varName + i.intValue(); - tagVarNumbers.put(fullName, new Integer(i.intValue() + 1)); - } else { - tagVarNumbers.put(fullName, new Integer(1)); - varName = varName + "0"; - } - } - return JspUtil.makeXmlJavaIdentifier(varName); - } - - private String evaluateAttribute(TagHandlerInfo handlerInfo, - Node.JspAttribute attr, Node.CustomTag n, String tagHandlerVar) - throws JasperException { - - String attrValue = attr.getValue(); - if (attrValue == null) { - if (attr.isNamedAttribute()) { - if (n.checkIfAttributeIsJspFragment(attr.getName())) { - // XXX - no need to generate temporary variable here - attrValue = generateNamedAttributeJspFragment(attr - .getNamedAttributeNode(), tagHandlerVar); - } else { - attrValue = generateNamedAttributeValue(attr - .getNamedAttributeNode()); - } - } else { - return null; - } - } - - String localName = attr.getLocalName(); - - Method m = null; - Class[] c = null; - if (attr.isDynamic()) { - c = OBJECT_CLASS; - } else { - m = handlerInfo.getSetterMethod(localName); - if (m == null) { - err.jspError(n, "jsp.error.unable.to_find_method", attr - .getName()); - } - c = m.getParameterTypes(); - // XXX assert(c.length > 0) - } - - if (attr.isExpression()) { - // Do nothing - } else if (attr.isNamedAttribute()) { - if (!n.checkIfAttributeIsJspFragment(attr.getName()) - && !attr.isDynamic()) { - attrValue = convertString(c[0], attrValue, localName, - handlerInfo.getPropertyEditorClass(localName), true); - } - } else if (attr.isELInterpreterInput()) { - - // results buffer - StringBuffer sb = new StringBuffer(64); - - TagAttributeInfo tai = attr.getTagAttributeInfo(); - String type = tai.getTypeName(); - String returnType = JspUtil.toJavaSourceTypeFromTld(attr - .getExpectedTypeName()); - - // generate elContext reference - sb.append(getJspContextVar()); - sb.append(".getELContext()"); - String elContext = sb.toString(); - if (attr.getEL() != null && attr.getEL().getMapName() != null) { - sb.setLength(0); - sb.append("new org.apache.jasper.el.ELContextWrapper("); - sb.append(elContext); - sb.append(','); - sb.append(attr.getEL().getMapName()); - sb.append(')'); - elContext = sb.toString(); - } - - // reset buffer - sb.setLength(0); - - // create our mark - sb.append(n.getStart().toString()); - sb.append(" '"); - sb.append(attrValue); - sb.append('\''); - String mark = sb.toString(); - - // reset buffer - sb.setLength(0); - - // depending on type - if (attr.isDeferredInput() - || ValueExpression.class.getName().equals(type)) { - sb.append("new org.apache.jasper.el.JspValueExpression("); - sb.append(quote(mark)); - sb.append(','); - sb.append(getExpressionFactoryVar()); - sb.append(".createValueExpression("); - if (attr.getEL() != null) { // optimize - sb.append(elContext); - sb.append(','); - } - sb.append(quote(attrValue)); - sb.append(','); - sb.append(returnType); - sb.append("))"); - attrValue = sb.toString(); - } else if (attr.isDeferredMethodInput() - || MethodExpression.class.getName().equals(type)) { - sb.append("new org.apache.jasper.el.JspMethodExpression("); - sb.append(quote(mark)); - sb.append(','); - sb.append(getExpressionFactoryVar()); - sb.append(".createMethodExpression("); - sb.append(elContext); - sb.append(','); - sb.append(quote(attrValue)); - sb.append(','); - sb.append(returnType); - sb.append(','); - sb.append("new Class[] {"); - - String[] p = attr.getParameterTypeNames(); - for (int i = 0; i < p.length; i++) { - sb.append(JspUtil.toJavaSourceTypeFromTld(p[i])); - sb.append(','); - } - if (p.length > 0) { - sb.setLength(sb.length() - 1); - } - - sb.append("}))"); - attrValue = sb.toString(); - } else { - // run attrValue through the expression interpreter - boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0; - String mapName = (attr.getEL() != null) ? attr.getEL() - .getMapName() : null; - attrValue = JspUtil.interpreterCall(this.isTagFile, - attrValue, c[0], mapName, false); - // XXX hack: Replace ESC with '$' - if (replaceESC) { - attrValue = "(" + attrValue + ").replace(" - + Constants.ESCStr + ", '$')"; - } - } - } else { - attrValue = convertString(c[0], attrValue, localName, - handlerInfo.getPropertyEditorClass(localName), false); - } - return attrValue; - } - - /** - * Generate code to create a map for the alias variables - * - * @return the name of the map - */ - private String generateAliasMap(Node.CustomTag n, String tagHandlerVar) - throws JasperException { - - TagVariableInfo[] tagVars = n.getTagVariableInfos(); - String aliasMapVar = null; - - boolean aliasSeen = false; - for (int i = 0; i < tagVars.length; i++) { - - String nameFrom = tagVars[i].getNameFromAttribute(); - if (nameFrom != null) { - String aliasedName = n.getAttributeValue(nameFrom); - if (aliasedName == null) - continue; - - if (!aliasSeen) { - out.printin("java.util.HashMap "); - aliasMapVar = tagHandlerVar + "_aliasMap"; - out.print(aliasMapVar); - out.println(" = new java.util.HashMap();"); - aliasSeen = true; - } - out.printin(aliasMapVar); - out.print(".put("); - out.print(quote(tagVars[i].getNameGiven())); - out.print(", "); - out.print(quote(aliasedName)); - out.println(");"); - } - } - return aliasMapVar; - } - - private void generateSetters(Node.CustomTag n, String tagHandlerVar, - TagHandlerInfo handlerInfo, boolean simpleTag) - throws JasperException { - - // Set context - if (simpleTag) { - // Generate alias map - String aliasMapVar = null; - if (n.isTagFile()) { - aliasMapVar = generateAliasMap(n, tagHandlerVar); - } - out.printin(tagHandlerVar); - if (aliasMapVar == null) { - out.println(".setJspContext(_jspx_page_context);"); - } else { - out.print(".setJspContext(_jspx_page_context, "); - out.print(aliasMapVar); - out.println(");"); - } - } else { - out.printin(tagHandlerVar); - out.println(".setPageContext(_jspx_page_context);"); - } - - // Set parent - if (!simpleTag) { - out.printin(tagHandlerVar); - out.print(".setParent("); - if (parent != null) { - if (isSimpleTagParent) { - out.print("new javax.servlet.jsp.tagext.TagAdapter("); - out.print("(javax.servlet.jsp.tagext.SimpleTag) "); - out.print(parent); - out.println("));"); - } else { - out.print("(javax.servlet.jsp.tagext.Tag) "); - out.print(parent); - out.println(");"); - } - } else { - out.println("null);"); - } - } else { - // The setParent() method need not be called if the value being - // passed is null, since SimpleTag instances are not reused - if (parent != null) { - out.printin(tagHandlerVar); - out.print(".setParent("); - out.print(parent); - out.println(");"); - } - } - - // need to handle deferred values and methods - Node.JspAttribute[] attrs = n.getJspAttributes(); - for (int i = 0; attrs != null && i < attrs.length; i++) { - String attrValue = evaluateAttribute(handlerInfo, attrs[i], n, - tagHandlerVar); - - Mark m = n.getStart(); - out.printil("// "+m.getFile()+"("+m.getLineNumber()+","+m.getColumnNumber()+") "+ attrs[i].getTagAttributeInfo()); - if (attrs[i].isDynamic()) { - out.printin(tagHandlerVar); - out.print("."); - out.print("setDynamicAttribute("); - String uri = attrs[i].getURI(); - if ("".equals(uri) || (uri == null)) { - out.print("null"); - } else { - out.print("\"" + attrs[i].getURI() + "\""); - } - out.print(", \""); - out.print(attrs[i].getLocalName()); - out.print("\", "); - out.print(attrValue); - out.println(");"); - } else { - out.printin(tagHandlerVar); - out.print("."); - out.print(handlerInfo.getSetterMethod( - attrs[i].getLocalName()).getName()); - out.print("("); - out.print(attrValue); - out.println(");"); - } - } - } - - /* - * @param c The target class to which to coerce the given string @param - * s The string value @param attrName The name of the attribute whose - * value is being supplied @param propEditorClass The property editor - * for the given attribute @param isNamedAttribute true if the given - * attribute is a named attribute (that is, specified using the - * jsp:attribute standard action), and false otherwise - */ - private String convertString(Class c, String s, String attrName, - Class propEditorClass, boolean isNamedAttribute) - throws JasperException { - - String quoted = s; - if (!isNamedAttribute) { - quoted = quote(s); - } - - if (propEditorClass != null) { - String className = JspUtil.getCanonicalName(c); - return "(" - + className - + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor(" - + className + ".class, \"" + attrName + "\", " + quoted - + ", " + JspUtil.getCanonicalName(propEditorClass) - + ".class)"; - } else if (c == String.class) { - return quoted; - } else if (c == boolean.class) { - return JspUtil.coerceToPrimitiveBoolean(s, isNamedAttribute); - } else if (c == Boolean.class) { - return JspUtil.coerceToBoolean(s, isNamedAttribute); - } else if (c == byte.class) { - return JspUtil.coerceToPrimitiveByte(s, isNamedAttribute); - } else if (c == Byte.class) { - return JspUtil.coerceToByte(s, isNamedAttribute); - } else if (c == char.class) { - return JspUtil.coerceToChar(s, isNamedAttribute); - } else if (c == Character.class) { - return JspUtil.coerceToCharacter(s, isNamedAttribute); - } else if (c == double.class) { - return JspUtil.coerceToPrimitiveDouble(s, isNamedAttribute); - } else if (c == Double.class) { - return JspUtil.coerceToDouble(s, isNamedAttribute); - } else if (c == float.class) { - return JspUtil.coerceToPrimitiveFloat(s, isNamedAttribute); - } else if (c == Float.class) { - return JspUtil.coerceToFloat(s, isNamedAttribute); - } else if (c == int.class) { - return JspUtil.coerceToInt(s, isNamedAttribute); - } else if (c == Integer.class) { - return JspUtil.coerceToInteger(s, isNamedAttribute); - } else if (c == short.class) { - return JspUtil.coerceToPrimitiveShort(s, isNamedAttribute); - } else if (c == Short.class) { - return JspUtil.coerceToShort(s, isNamedAttribute); - } else if (c == long.class) { - return JspUtil.coerceToPrimitiveLong(s, isNamedAttribute); - } else if (c == Long.class) { - return JspUtil.coerceToLong(s, isNamedAttribute); - } else if (c == Object.class) { - return "new String(" + quoted + ")"; - } else { - String className = JspUtil.getCanonicalName(c); - return "(" - + className - + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromPropertyEditorManager(" - + className + ".class, \"" + attrName + "\", " + quoted - + ")"; - } - } - - /* - * Converts the scope string representation, whose possible values are - * "page", "request", "session", and "application", to the corresponding - * scope constant. - */ - private String getScopeConstant(String scope) { - String scopeName = "PageContext.PAGE_SCOPE"; // Default to page - - if ("request".equals(scope)) { - scopeName = "PageContext.REQUEST_SCOPE"; - } else if ("session".equals(scope)) { - scopeName = "PageContext.SESSION_SCOPE"; - } else if ("application".equals(scope)) { - scopeName = "PageContext.APPLICATION_SCOPE"; - } - - return scopeName; - } - - /** - * Generates anonymous JspFragment inner class which is passed as an - * argument to SimpleTag.setJspBody(). - */ - private void generateJspFragment(Node n, String tagHandlerVar) - throws JasperException { - // XXX - A possible optimization here would be to check to see - // if the only child of the parent node is TemplateText. If so, - // we know there won't be any parameters, etc, so we can - // generate a low-overhead JspFragment that just echoes its - // body. The implementation of this fragment can come from - // the org.apache.jasper.runtime package as a support class. - FragmentHelperClass.Fragment fragment = fragmentHelperClass - .openFragment(n, tagHandlerVar, methodNesting); - ServletWriter outSave = out; - out = fragment.getGenBuffer().getOut(); - String tmpParent = parent; - parent = "_jspx_parent"; - boolean isSimpleTagParentSave = isSimpleTagParent; - isSimpleTagParent = true; - boolean tmpIsFragment = isFragment; - isFragment = true; - String pushBodyCountVarSave = pushBodyCountVar; - if (pushBodyCountVar != null) { - // Use a fixed name for push body count, to simplify code gen - pushBodyCountVar = "_jspx_push_body_count"; - } - visitBody(n); - out = outSave; - parent = tmpParent; - isSimpleTagParent = isSimpleTagParentSave; - isFragment = tmpIsFragment; - pushBodyCountVar = pushBodyCountVarSave; - fragmentHelperClass.closeFragment(fragment, methodNesting); - // XXX - Need to change pageContext to jspContext if - // we're not in a place where pageContext is defined (e.g. - // in a fragment or in a tag file. - out.print("new " + fragmentHelperClass.getClassName() + "( " - + fragment.getId() + ", _jspx_page_context, " - + tagHandlerVar + ", " + pushBodyCountVar + ")"); - } - - /** - * Generate the code required to obtain the runtime value of the given - * named attribute. - * - * @return The name of the temporary variable the result is stored in. - */ - public String generateNamedAttributeValue(Node.NamedAttribute n) - throws JasperException { - - String varName = n.getTemporaryVariableName(); - - // If the only body element for this named attribute node is - // template text, we need not generate an extra call to - // pushBody and popBody. Maybe we can further optimize - // here by getting rid of the temporary variable, but in - // reality it looks like javac does this for us. - Node.Nodes body = n.getBody(); - if (body != null) { - boolean templateTextOptimization = false; - if (body.size() == 1) { - Node bodyElement = body.getNode(0); - if (bodyElement instanceof Node.TemplateText) { - templateTextOptimization = true; - out.printil("String " - + varName - + " = " - + quote(new String( - ((Node.TemplateText) bodyElement) - .getText())) + ";"); - } - } - - // XXX - Another possible optimization would be for - // lone EL expressions (no need to pushBody here either). - - if (!templateTextOptimization) { - out.printil("out = _jspx_page_context.pushBody();"); - visitBody(n); - out.printil("String " + varName + " = " - + "((javax.servlet.jsp.tagext.BodyContent)" - + "out).getString();"); - out.printil("out = _jspx_page_context.popBody();"); - } - } else { - // Empty body must be treated as "" - out.printil("String " + varName + " = \"\";"); - } - - return varName; - } - - /** - * Similar to generateNamedAttributeValue, but create a JspFragment - * instead. - * - * @param n - * The parent node of the named attribute - * @param tagHandlerVar - * The variable the tag handler is stored in, so the fragment - * knows its parent tag. - * @return The name of the temporary variable the fragment is stored in. - */ - public String generateNamedAttributeJspFragment(Node.NamedAttribute n, - String tagHandlerVar) throws JasperException { - String varName = n.getTemporaryVariableName(); - - out.printin("javax.servlet.jsp.tagext.JspFragment " + varName - + " = "); - generateJspFragment(n, tagHandlerVar); - out.println(";"); - - return varName; - } - } - - private static void generateLocalVariables(ServletWriter out, Node n) - throws JasperException { - Node.ChildInfo ci; - if (n instanceof Node.CustomTag) { - ci = ((Node.CustomTag) n).getChildInfo(); - } else if (n instanceof Node.JspBody) { - ci = ((Node.JspBody) n).getChildInfo(); - } else if (n instanceof Node.NamedAttribute) { - ci = ((Node.NamedAttribute) n).getChildInfo(); - } else { - // Cannot access err since this method is static, but at - // least flag an error. - throw new JasperException("Unexpected Node Type"); - // err.getString( - // "jsp.error.internal.unexpected_node_type" ) ); - } - - if (ci.hasUseBean()) { - out - .printil("HttpSession session = _jspx_page_context.getSession();"); - out - .printil("ServletContext application = _jspx_page_context.getServletContext();"); - } - if (ci.hasUseBean() || ci.hasIncludeAction() || ci.hasSetProperty() - || ci.hasParamAction()) { - out - .printil("HttpServletRequest request = (HttpServletRequest)_jspx_page_context.getRequest();"); - } - if (ci.hasIncludeAction()) { - out - .printil("HttpServletResponse response = (HttpServletResponse)_jspx_page_context.getResponse();"); - } - } - - /** - * Common part of postamble, shared by both servlets and tag files. - */ - private void genCommonPostamble() { - // Append any methods that were generated in the buffer. - for (int i = 0; i < methodsBuffered.size(); i++) { - GenBuffer methodBuffer = (GenBuffer) methodsBuffered.get(i); - methodBuffer.adjustJavaLines(out.getJavaLine() - 1); - out.printMultiLn(methodBuffer.toString()); - } - - // Append the helper class - if (fragmentHelperClass.isUsed()) { - fragmentHelperClass.generatePostamble(); - fragmentHelperClass.adjustJavaLines(out.getJavaLine() - 1); - out.printMultiLn(fragmentHelperClass.toString()); - } - - // Append char array declarations - if (charArrayBuffer != null) { - out.printMultiLn(charArrayBuffer.toString()); - } - - // Close the class definition - out.popIndent(); - out.printil("}"); - } - - /** - * Generates the ending part of the static portion of the servlet. - */ - private void generatePostamble(Node.Nodes page) { - out.popIndent(); - out.printil("} catch (Throwable t) {"); - out.pushIndent(); - out.printil("if (!(t instanceof SkipPageException)){"); - out.pushIndent(); - out.printil("out = _jspx_out;"); - out.printil("if (out != null && out.getBufferSize() != 0)"); - out.pushIndent(); - out.printil("out.clearBuffer();"); - out.popIndent(); - - out - .printil("if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);"); - out.popIndent(); - out.printil("}"); - out.popIndent(); - out.printil("} finally {"); - out.pushIndent(); - - out - .printil("if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);"); - - out.popIndent(); - out.printil("}"); - - // Close the service method - out.popIndent(); - out.printil("}"); - - // Generated methods, helper classes, etc. - genCommonPostamble(); - } - - /** - * Constructor. - */ - Generator(ServletWriter out, Compiler compiler) { - this.out = out; - methodsBuffered = new ArrayList(); - charArrayBuffer = null; - err = compiler.getErrorDispatcher(); - ctxt = compiler.getCompilationContext(); - fragmentHelperClass = new FragmentHelperClass(ctxt - .getServletClassName() - + "Helper"); - pageInfo = compiler.getPageInfo(); - - /* - * Temporary hack. If a JSP page uses the "extends" attribute of the - * page directive, the _jspInit() method of the generated servlet class - * will not be called (it is only called for those generated servlets - * that extend HttpJspBase, the default), causing the tag handler pools - * not to be initialized and resulting in a NPE. The JSP spec needs to - * clarify whether containers can override init() and destroy(). For - * now, we just disable tag pooling for pages that use "extends". - */ - if (pageInfo.getExtends(false) == null) { - isPoolingEnabled = ctxt.getOptions().isPoolingEnabled(); - } else { - isPoolingEnabled = false; - } - beanInfo = pageInfo.getBeanRepository(); - breakAtLF = ctxt.getOptions().getMappedFile(); - if (isPoolingEnabled) { - tagHandlerPoolNames = new Vector(); - } - } - - /** - * The main entry for Generator. - * - * @param out - * The servlet output writer - * @param compiler - * The compiler - * @param page - * The input page - */ - public static void generate(ServletWriter out, Compiler compiler, - Node.Nodes page) throws JasperException { - - Generator gen = new Generator(out, compiler); - - if (gen.isPoolingEnabled) { - gen.compileTagHandlerPoolList(page); - } - if (gen.ctxt.isTagFile()) { - JasperTagInfo tagInfo = (JasperTagInfo) gen.ctxt.getTagInfo(); - gen.generateTagHandlerPreamble(tagInfo, page); - - if (gen.ctxt.isPrototypeMode()) { - return; - } - - gen.generateXmlProlog(page); - gen.fragmentHelperClass.generatePreamble(); - page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out, - gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt - .getClassLoader(), tagInfo)); - gen.generateTagHandlerPostamble(tagInfo); - } else { - gen.generatePreamble(page); - gen.generateXmlProlog(page); - gen.fragmentHelperClass.generatePreamble(); - page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out, - gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt - .getClassLoader(), null)); - gen.generatePostamble(page); - } - } - - /* - * Generates tag handler preamble. - */ - private void generateTagHandlerPreamble(JasperTagInfo tagInfo, - Node.Nodes tag) throws JasperException { - - // Generate package declaration - String className = tagInfo.getTagClassName(); - int lastIndex = className.lastIndexOf('.'); - if (lastIndex != -1) { - String pkgName = className.substring(0, lastIndex); - genPreamblePackage(pkgName); - className = className.substring(lastIndex + 1); - } - - // Generate imports - genPreambleImports(); - - // Generate class declaration - out.printin("public final class "); - out.println(className); - out.printil(" extends javax.servlet.jsp.tagext.SimpleTagSupport"); - out - .printin(" implements org.apache.jasper.runtime.JspSourceDependent"); - if (tagInfo.hasDynamicAttributes()) { - out.println(","); - out - .printin(" javax.servlet.jsp.tagext.DynamicAttributes"); - } - out.println(" {"); - out.println(); - out.pushIndent(); - - /* - * Class body begins here - */ - - generateDeclarations(tag); - - // Static initializations here - genPreambleStaticInitializers(); - - out.printil("private JspContext jspContext;"); - - // Declare writer used for storing result of fragment/body invocation - // if 'varReader' or 'var' attribute is specified - out.printil("private java.io.Writer _jspx_sout;"); - - // Class variable declarations - genPreambleClassVariableDeclarations(tagInfo.getTagName()); - - generateSetJspContext(tagInfo); - - // Tag-handler specific declarations - generateTagHandlerAttributes(tagInfo); - if (tagInfo.hasDynamicAttributes()) - generateSetDynamicAttribute(); - - // Methods here - genPreambleMethods(); - - // Now the doTag() method - out - .printil("public void doTag() throws JspException, java.io.IOException {"); - - if (ctxt.isPrototypeMode()) { - out.printil("}"); - out.popIndent(); - out.printil("}"); - return; - } - - out.pushIndent(); - - /* - * According to the spec, 'pageContext' must not be made available as an - * implicit object in tag files. Declare _jspx_page_context, so we can - * share the code generator with JSPs. - */ - out - .printil("PageContext _jspx_page_context = (PageContext)jspContext;"); - - // Declare implicit objects. - out.printil("HttpServletRequest request = " - + "(HttpServletRequest) _jspx_page_context.getRequest();"); - out.printil("HttpServletResponse response = " - + "(HttpServletResponse) _jspx_page_context.getResponse();"); - out.printil("HttpSession session = _jspx_page_context.getSession();"); - out - .printil("ServletContext application = _jspx_page_context.getServletContext();"); - out - .printil("ServletConfig config = _jspx_page_context.getServletConfig();"); - out.printil("JspWriter out = jspContext.getOut();"); - if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { - out.printil("_jspInit(config);"); - } - - // set current JspContext on ELContext - out.printil("jspContext.getELContext().putContext(JspContext.class,jspContext);"); - - generatePageScopedVariables(tagInfo); - - declareTemporaryScriptingVars(tag); - out.println(); - - out.printil("try {"); - out.pushIndent(); - } - - private void generateTagHandlerPostamble(TagInfo tagInfo) { - out.popIndent(); - - // Have to catch Throwable because a classic tag handler - // helper method is declared to throw Throwable. - out.printil("} catch( Throwable t ) {"); - out.pushIndent(); - out.printil("if( t instanceof SkipPageException )"); - out.printil(" throw (SkipPageException) t;"); - out.printil("if( t instanceof java.io.IOException )"); - out.printil(" throw (java.io.IOException) t;"); - out.printil("if( t instanceof IllegalStateException )"); - out.printil(" throw (IllegalStateException) t;"); - out.printil("if( t instanceof JspException )"); - out.printil(" throw (JspException) t;"); - out.printil("throw new JspException(t);"); - out.popIndent(); - out.printil("} finally {"); - out.pushIndent(); - - // handle restoring VariableMapper - TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); - for (int i = 0; i < attrInfos.length; i++) { - if (attrInfos[i].isDeferredMethod() || attrInfos[i].isDeferredValue()) { - out.printin("_el_variablemapper.setVariable("); - out.print(quote(attrInfos[i].getName())); - out.print(",_el_ve"); - out.print(i); - out.println(");"); - } - } - - // restore nested JspContext on ELContext - out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());"); - - out - .printil("((org.apache.jasper.runtime.JspContextWrapper) jspContext).syncEndTagFile();"); - if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { - out.printil("_jspDestroy();"); - } - out.popIndent(); - out.printil("}"); - - // Close the doTag method - out.popIndent(); - out.printil("}"); - - // Generated methods, helper classes, etc. - genCommonPostamble(); - } - - /** - * Generates declarations for tag handler attributes, and defines the getter - * and setter methods for each. - */ - private void generateTagHandlerAttributes(TagInfo tagInfo) - throws JasperException { - - if (tagInfo.hasDynamicAttributes()) { - out - .printil("private java.util.HashMap _jspx_dynamic_attrs = new java.util.HashMap();"); - } - - // Declare attributes - TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); - for (int i = 0; i < attrInfos.length; i++) { - out.printin("private "); - if (attrInfos[i].isFragment()) { - out.print("javax.servlet.jsp.tagext.JspFragment "); - } else { - out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName())); - out.print(" "); - } - out.print(attrInfos[i].getName()); - out.println(";"); - } - out.println(); - - // Define attribute getter and setter methods - if (attrInfos != null) { - for (int i = 0; i < attrInfos.length; i++) { - // getter method - out.printin("public "); - if (attrInfos[i].isFragment()) { - out.print("javax.servlet.jsp.tagext.JspFragment "); - } else { - out.print(JspUtil.toJavaSourceType(attrInfos[i] - .getTypeName())); - out.print(" "); - } - out.print(toGetterMethod(attrInfos[i].getName())); - out.println(" {"); - out.pushIndent(); - out.printin("return this."); - out.print(attrInfos[i].getName()); - out.println(";"); - out.popIndent(); - out.printil("}"); - out.println(); - - // setter method - out.printin("public void "); - out.print(toSetterMethodName(attrInfos[i].getName())); - if (attrInfos[i].isFragment()) { - out.print("(javax.servlet.jsp.tagext.JspFragment "); - } else { - out.print("("); - out.print(JspUtil.toJavaSourceType(attrInfos[i] - .getTypeName())); - out.print(" "); - } - out.print(attrInfos[i].getName()); - out.println(") {"); - out.pushIndent(); - out.printin("this."); - out.print(attrInfos[i].getName()); - out.print(" = "); - out.print(attrInfos[i].getName()); - out.println(";"); - out.popIndent(); - out.printil("}"); - out.println(); - } - } - } - - /* - * Generate setter for JspContext so we can create a wrapper and store both - * the original and the wrapper. We need the wrapper to mask the page - * context from the tag file and simulate a fresh page context. We need the - * original to do things like sync AT_BEGIN and AT_END scripting variables. - */ - private void generateSetJspContext(TagInfo tagInfo) { - - boolean nestedSeen = false; - boolean atBeginSeen = false; - boolean atEndSeen = false; - - // Determine if there are any aliases - boolean aliasSeen = false; - TagVariableInfo[] tagVars = tagInfo.getTagVariableInfos(); - for (int i = 0; i < tagVars.length; i++) { - if (tagVars[i].getNameFromAttribute() != null - && tagVars[i].getNameGiven() != null) { - aliasSeen = true; - break; - } - } - - if (aliasSeen) { - out - .printil("public void setJspContext(JspContext ctx, java.util.Map aliasMap) {"); - } else { - out.printil("public void setJspContext(JspContext ctx) {"); - } - out.pushIndent(); - out.printil("super.setJspContext(ctx);"); - out.printil("java.util.ArrayList _jspx_nested = null;"); - out.printil("java.util.ArrayList _jspx_at_begin = null;"); - out.printil("java.util.ArrayList _jspx_at_end = null;"); - - for (int i = 0; i < tagVars.length; i++) { - - switch (tagVars[i].getScope()) { - case VariableInfo.NESTED: - if (!nestedSeen) { - out.printil("_jspx_nested = new java.util.ArrayList();"); - nestedSeen = true; - } - out.printin("_jspx_nested.add("); - break; - - case VariableInfo.AT_BEGIN: - if (!atBeginSeen) { - out.printil("_jspx_at_begin = new java.util.ArrayList();"); - atBeginSeen = true; - } - out.printin("_jspx_at_begin.add("); - break; - - case VariableInfo.AT_END: - if (!atEndSeen) { - out.printil("_jspx_at_end = new java.util.ArrayList();"); - atEndSeen = true; - } - out.printin("_jspx_at_end.add("); - break; - } // switch - - out.print(quote(tagVars[i].getNameGiven())); - out.println(");"); - } - if (aliasSeen) { - out - .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, aliasMap);"); - } else { - out - .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, null);"); - } - out.popIndent(); - out.printil("}"); - out.println(); - out.printil("public JspContext getJspContext() {"); - out.pushIndent(); - out.printil("return this.jspContext;"); - out.popIndent(); - out.printil("}"); - } - - /* - * Generates implementation of - * javax.servlet.jsp.tagext.DynamicAttributes.setDynamicAttribute() method, - * which saves each dynamic attribute that is passed in so that a scoped - * variable can later be created for it. - */ - public void generateSetDynamicAttribute() { - out - .printil("public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {"); - out.pushIndent(); - /* - * According to the spec, only dynamic attributes with no uri are to be - * present in the Map; all other dynamic attributes are ignored. - */ - out.printil("if (uri == null)"); - out.pushIndent(); - out.printil("_jspx_dynamic_attrs.put(localName, value);"); - out.popIndent(); - out.popIndent(); - out.printil("}"); - } - - /* - * Creates a page-scoped variable for each declared tag attribute. Also, if - * the tag accepts dynamic attributes, a page-scoped variable is made - * available for each dynamic attribute that was passed in. - */ - private void generatePageScopedVariables(JasperTagInfo tagInfo) { - - // "normal" attributes - TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); - boolean variableMapperVar = false; - for (int i = 0; i < attrInfos.length; i++) { - String attrName = attrInfos[i].getName(); - - // handle assigning deferred vars to VariableMapper, storing - // previous values under '_el_ve[i]' for later re-assignment - if (attrInfos[i].isDeferredValue() || attrInfos[i].isDeferredMethod()) { - - // we need to scope the modified VariableMapper for consistency and performance - if (!variableMapperVar) { - out.println("javax.el.VariableMapper _el_variablemapper = jspContext.getELContext().getVariableMapper();"); - variableMapperVar = true; - } - - out.printin("javax.el.ValueExpression _el_ve"); - out.print(i); - out.print(" = _el_variablemapper.setVariable("); - out.print(quote(attrName)); - out.print(','); - if (attrInfos[i].isDeferredMethod()) { - out.print(VAR_EXPRESSIONFACTORY); - out.print(".createValueExpression("); - out.print(toGetterMethod(attrName)); - out.print(",javax.el.MethodExpression.class)"); - } else { - out.print(toGetterMethod(attrName)); - } - out.println(");"); - } else { - out.printil("if( " + toGetterMethod(attrName) + " != null ) "); - out.pushIndent(); - out.printin("_jspx_page_context.setAttribute("); - out.print(quote(attrName)); - out.print(", "); - out.print(toGetterMethod(attrName)); - out.println(");"); - out.popIndent(); - } - } - - // Expose the Map containing dynamic attributes as a page-scoped var - if (tagInfo.hasDynamicAttributes()) { - out.printin("_jspx_page_context.setAttribute(\""); - out.print(tagInfo.getDynamicAttributesMapName()); - out.print("\", _jspx_dynamic_attrs);"); - } - } - - /* - * Generates the getter method for the given attribute name. - */ - private String toGetterMethod(String attrName) { - char[] attrChars = attrName.toCharArray(); - attrChars[0] = Character.toUpperCase(attrChars[0]); - return "get" + new String(attrChars) + "()"; - } - - /* - * Generates the setter method name for the given attribute name. - */ - private String toSetterMethodName(String attrName) { - char[] attrChars = attrName.toCharArray(); - attrChars[0] = Character.toUpperCase(attrChars[0]); - return "set" + new String(attrChars); - } - - /** - * Class storing the result of introspecting a custom tag handler. - */ - private static class TagHandlerInfo { - - private Hashtable methodMaps; - - private Hashtable propertyEditorMaps; - - private Class tagHandlerClass; - - /** - * Constructor. - * - * @param n - * The custom tag whose tag handler class is to be - * introspected - * @param tagHandlerClass - * Tag handler class - * @param err - * Error dispatcher - */ - TagHandlerInfo(Node n, Class tagHandlerClass, ErrorDispatcher err) - throws JasperException { - this.tagHandlerClass = tagHandlerClass; - this.methodMaps = new Hashtable(); - this.propertyEditorMaps = new Hashtable(); - - try { - BeanInfo tagClassInfo = Introspector - .getBeanInfo(tagHandlerClass); - PropertyDescriptor[] pd = tagClassInfo.getPropertyDescriptors(); - for (int i = 0; i < pd.length; i++) { - /* - * FIXME: should probably be checking for things like - * pageContext, bodyContent, and parent here -akv - */ - if (pd[i].getWriteMethod() != null) { - methodMaps.put(pd[i].getName(), pd[i].getWriteMethod()); - } - if (pd[i].getPropertyEditorClass() != null) - propertyEditorMaps.put(pd[i].getName(), pd[i] - .getPropertyEditorClass()); - } - } catch (IntrospectionException ie) { - err.jspError(n, "jsp.error.introspect.taghandler", - tagHandlerClass.getName(), ie); - } - } - - /** - * XXX - */ - public Method getSetterMethod(String attrName) { - return (Method) methodMaps.get(attrName); - } - - /** - * XXX - */ - public Class getPropertyEditorClass(String attrName) { - return (Class) propertyEditorMaps.get(attrName); - } - - /** - * XXX - */ - public Class getTagHandlerClass() { - return tagHandlerClass; - } - } - - /** - * A class for generating codes to a buffer. Included here are some support - * for tracking source to Java lines mapping. - */ - private static class GenBuffer { - - /* - * For a CustomTag, the codes that are generated at the beginning of the - * tag may not be in the same buffer as those for the body of the tag. - * Two fields are used here to keep this straight. For codes that do not - * corresponds to any JSP lines, they should be null. - */ - private Node node; - - private Node.Nodes body; - - private java.io.CharArrayWriter charWriter; - - protected ServletWriter out; - - GenBuffer() { - this(null, null); - } - - GenBuffer(Node n, Node.Nodes b) { - node = n; - body = b; - if (body != null) { - body.setGeneratedInBuffer(true); - } - charWriter = new java.io.CharArrayWriter(); - out = new ServletWriter(new java.io.PrintWriter(charWriter)); - } - - public ServletWriter getOut() { - return out; - } - - public String toString() { - return charWriter.toString(); - } - - /** - * Adjust the Java Lines. This is necessary because the Java lines - * stored with the nodes are relative the beginning of this buffer and - * need to be adjusted when this buffer is inserted into the source. - */ - public void adjustJavaLines(final int offset) { - - if (node != null) { - adjustJavaLine(node, offset); - } - - if (body != null) { - try { - body.visit(new Node.Visitor() { - - public void doVisit(Node n) { - adjustJavaLine(n, offset); - } - - public void visit(Node.CustomTag n) - throws JasperException { - Node.Nodes b = n.getBody(); - if (b != null && !b.isGeneratedInBuffer()) { - // Don't adjust lines for the nested tags that - // are also generated in buffers, because the - // adjustments will be done elsewhere. - b.visit(this); - } - } - }); - } catch (JasperException ex) { - } - } - } - - private static void adjustJavaLine(Node n, int offset) { - if (n.getBeginJavaLine() > 0) { - n.setBeginJavaLine(n.getBeginJavaLine() + offset); - n.setEndJavaLine(n.getEndJavaLine() + offset); - } - } - } - - /** - * Keeps track of the generated Fragment Helper Class - */ - private static class FragmentHelperClass { - - private static class Fragment { - private GenBuffer genBuffer; - - private int id; - - public Fragment(int id, Node node) { - this.id = id; - genBuffer = new GenBuffer(null, node.getBody()); - } - - public GenBuffer getGenBuffer() { - return this.genBuffer; - } - - public int getId() { - return this.id; - } - } - - // True if the helper class should be generated. - private boolean used = false; - - private ArrayList fragments = new ArrayList(); - - private String className; - - // Buffer for entire helper class - private GenBuffer classBuffer = new GenBuffer(); - - public FragmentHelperClass(String className) { - this.className = className; - } - - public String getClassName() { - return this.className; - } - - public boolean isUsed() { - return this.used; - } - - public void generatePreamble() { - ServletWriter out = this.classBuffer.getOut(); - out.println(); - out.pushIndent(); - // Note: cannot be static, as we need to reference things like - // _jspx_meth_* - out.printil("private class " + className); - out.printil(" extends " - + "org.apache.jasper.runtime.JspFragmentHelper"); - out.printil("{"); - out.pushIndent(); - out - .printil("private javax.servlet.jsp.tagext.JspTag _jspx_parent;"); - out.printil("private int[] _jspx_push_body_count;"); - out.println(); - out.printil("public " + className - + "( int discriminator, JspContext jspContext, " - + "javax.servlet.jsp.tagext.JspTag _jspx_parent, " - + "int[] _jspx_push_body_count ) {"); - out.pushIndent(); - out.printil("super( discriminator, jspContext, _jspx_parent );"); - out.printil("this._jspx_parent = _jspx_parent;"); - out.printil("this._jspx_push_body_count = _jspx_push_body_count;"); - out.popIndent(); - out.printil("}"); - } - - public Fragment openFragment(Node parent, String tagHandlerVar, - int methodNesting) throws JasperException { - Fragment result = new Fragment(fragments.size(), parent); - fragments.add(result); - this.used = true; - parent.setInnerClassName(className); - - ServletWriter out = result.getGenBuffer().getOut(); - out.pushIndent(); - out.pushIndent(); - // XXX - Returns boolean because if a tag is invoked from - // within this fragment, the Generator sometimes might - // generate code like "return true". This is ignored for now, - // meaning only the fragment is skipped. The JSR-152 - // expert group is currently discussing what to do in this case. - // See comment in closeFragment() - if (methodNesting > 0) { - out.printin("public boolean invoke"); - } else { - out.printin("public void invoke"); - } - out.println(result.getId() + "( " + "JspWriter out ) "); - out.pushIndent(); - // Note: Throwable required because methods like _jspx_meth_* - // throw Throwable. - out.printil("throws Throwable"); - out.popIndent(); - out.printil("{"); - out.pushIndent(); - generateLocalVariables(out, parent); - - return result; - } - - public void closeFragment(Fragment fragment, int methodNesting) { - ServletWriter out = fragment.getGenBuffer().getOut(); - // XXX - See comment in openFragment() - if (methodNesting > 0) { - out.printil("return false;"); - } else { - out.printil("return;"); - } - out.popIndent(); - out.printil("}"); - } - - public void generatePostamble() { - ServletWriter out = this.classBuffer.getOut(); - // Generate all fragment methods: - for (int i = 0; i < fragments.size(); i++) { - Fragment fragment = (Fragment) fragments.get(i); - fragment.getGenBuffer().adjustJavaLines(out.getJavaLine() - 1); - out.printMultiLn(fragment.getGenBuffer().toString()); - } - - // Generate postamble: - out.printil("public void invoke( java.io.Writer writer )"); - out.pushIndent(); - out.printil("throws JspException"); - out.popIndent(); - out.printil("{"); - out.pushIndent(); - out.printil("JspWriter out = null;"); - out.printil("if( writer != null ) {"); - out.pushIndent(); - out.printil("out = this.jspContext.pushBody(writer);"); - out.popIndent(); - out.printil("} else {"); - out.pushIndent(); - out.printil("out = this.jspContext.getOut();"); - out.popIndent(); - out.printil("}"); - out.printil("try {"); - out.pushIndent(); - out.printil("switch( this.discriminator ) {"); - out.pushIndent(); - for (int i = 0; i < fragments.size(); i++) { - out.printil("case " + i + ":"); - out.pushIndent(); - out.printil("invoke" + i + "( out );"); - out.printil("break;"); - out.popIndent(); - } - out.popIndent(); - out.printil("}"); // switch - out.popIndent(); - out.printil("}"); // try - out.printil("catch( Throwable e ) {"); - out.pushIndent(); - out.printil("if (e instanceof SkipPageException)"); - out.printil(" throw (SkipPageException) e;"); - out.printil("throw new JspException( e );"); - out.popIndent(); - out.printil("}"); // catch - out.printil("finally {"); - out.pushIndent(); - - out.printil("if( writer != null ) {"); - out.pushIndent(); - out.printil("this.jspContext.popBody();"); - out.popIndent(); - out.printil("}"); - - out.popIndent(); - out.printil("}"); // finally - out.popIndent(); - out.printil("}"); // invoke method - out.popIndent(); - out.printil("}"); // helper class - out.popIndent(); - } - - public String toString() { - return classBuffer.toString(); - } - - public void adjustJavaLines(int offset) { - for (int i = 0; i < fragments.size(); i++) { - Fragment fragment = (Fragment) fragments.get(i); - fragment.getGenBuffer().adjustJavaLines(offset); - } - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; + +import javax.el.MethodExpression; +import javax.el.ValueExpression; +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagVariableInfo; +import javax.servlet.jsp.tagext.VariableInfo; + +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.runtime.JspRuntimeLibrary; +import org.xml.sax.Attributes; + +/** + * Generate Java source from Nodes + * + * @author Anil K. Vijendran + * @author Danno Ferrin + * @author Mandar Raje + * @author Rajiv Mordani + * @author Pierre Delisle + * + * Tomcat 4.1.x and Tomcat 5: + * @author Kin-man Chung + * @author Jan Luehe + * @author Shawn Bayern + * @author Mark Roth + * @author Denis Benoit + * + * Tomcat 6.x + * @author Jacob Hookom + */ + +class Generator { + + private static final Class[] OBJECT_CLASS = { Object.class }; + + private static final String VAR_EXPRESSIONFACTORY = "_el_expressionfactory"; + + private ServletWriter out; + + private ArrayList methodsBuffered; + + private FragmentHelperClass fragmentHelperClass; + + private ErrorDispatcher err; + + private BeanRepository beanInfo; + + private JspCompilationContext ctxt; + + private boolean isPoolingEnabled; + + private boolean breakAtLF; + + private String jspIdPrefix; + + private int jspId; + + private PageInfo pageInfo; + + private Vector tagHandlerPoolNames; + + private GenBuffer charArrayBuffer; + + /** + * @param s + * the input string + * @return quoted and escaped string, per Java rule + */ + static String quote(String s) { + + if (s == null) + return "null"; + + return '"' + escape(s) + '"'; + } + + /** + * @param s + * the input string + * @return escaped string, per Java rule + */ + static String escape(String s) { + + if (s == null) + return ""; + + StringBuffer b = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '"') + b.append('\\').append('"'); + else if (c == '\\') + b.append('\\').append('\\'); + else if (c == '\n') + b.append('\\').append('n'); + else if (c == '\r') + b.append('\\').append('r'); + else + b.append(c); + } + return b.toString(); + } + + /** + * Single quote and escape a character + */ + static String quote(char c) { + + StringBuffer b = new StringBuffer(); + b.append('\''); + if (c == '\'') + b.append('\\').append('\''); + else if (c == '\\') + b.append('\\').append('\\'); + else if (c == '\n') + b.append('\\').append('n'); + else if (c == '\r') + b.append('\\').append('r'); + else + b.append(c); + b.append('\''); + return b.toString(); + } + + private String createJspId() throws JasperException { + if (this.jspIdPrefix == null) { + StringBuffer sb = new StringBuffer(32); + String name = ctxt.getServletJavaFileName(); + sb.append("jsp_").append(Math.abs(name.hashCode())).append('_'); + this.jspIdPrefix = sb.toString(); + } + return this.jspIdPrefix + (this.jspId++); + } + + /** + * Generates declarations. This includes "info" of the page directive, and + * scriptlet declarations. + */ + private void generateDeclarations(Node.Nodes page) throws JasperException { + + class DeclarationVisitor extends Node.Visitor { + + private boolean getServletInfoGenerated = false; + + /* + * Generates getServletInfo() method that returns the value of the + * page directive's 'info' attribute, if present. + * + * The Validator has already ensured that if the translation unit + * contains more than one page directive with an 'info' attribute, + * their values match. + */ + public void visit(Node.PageDirective n) throws JasperException { + + if (getServletInfoGenerated) { + return; + } + + String info = n.getAttributeValue("info"); + if (info == null) + return; + + getServletInfoGenerated = true; + out.printil("public String getServletInfo() {"); + out.pushIndent(); + out.printin("return "); + out.print(quote(info)); + out.println(";"); + out.popIndent(); + out.printil("}"); + out.println(); + } + + public void visit(Node.Declaration n) throws JasperException { + n.setBeginJavaLine(out.getJavaLine()); + out.printMultiLn(new String(n.getText())); + out.println(); + n.setEndJavaLine(out.getJavaLine()); + } + + // Custom Tags may contain declarations from tag plugins. + public void visit(Node.CustomTag n) throws JasperException { + if (n.useTagPlugin()) { + if (n.getAtSTag() != null) { + n.getAtSTag().visit(this); + } + visitBody(n); + if (n.getAtETag() != null) { + n.getAtETag().visit(this); + } + } else { + visitBody(n); + } + } + } + + out.println(); + page.visit(new DeclarationVisitor()); + } + + /** + * Compiles list of tag handler pool names. + */ + private void compileTagHandlerPoolList(Node.Nodes page) + throws JasperException { + + class TagHandlerPoolVisitor extends Node.Visitor { + + private Vector names; + + /* + * Constructor + * + * @param v Vector of tag handler pool names to populate + */ + TagHandlerPoolVisitor(Vector v) { + names = v; + } + + /* + * Gets the name of the tag handler pool for the given custom tag + * and adds it to the list of tag handler pool names unless it is + * already contained in it. + */ + public void visit(Node.CustomTag n) throws JasperException { + + if (!n.implementsSimpleTag()) { + String name = createTagHandlerPoolName(n.getPrefix(), n + .getLocalName(), n.getAttributes(), n + .hasEmptyBody()); + n.setTagHandlerPoolName(name); + if (!names.contains(name)) { + names.add(name); + } + } + visitBody(n); + } + + /* + * Creates the name of the tag handler pool whose tag handlers may + * be (re)used to service this action. + * + * @return The name of the tag handler pool + */ + private String createTagHandlerPoolName(String prefix, + String shortName, Attributes attrs, boolean hasEmptyBody) { + String poolName = null; + + poolName = "_jspx_tagPool_" + prefix + "_" + shortName; + if (attrs != null) { + String[] attrNames = new String[attrs.getLength()]; + for (int i = 0; i < attrNames.length; i++) { + attrNames[i] = attrs.getQName(i); + } + Arrays.sort(attrNames, Collections.reverseOrder()); + for (int i = 0; i < attrNames.length; i++) { + poolName = poolName + "_" + attrNames[i]; + } + } + if (hasEmptyBody) { + poolName = poolName + "_nobody"; + } + return JspUtil.makeXmlJavaIdentifier(poolName); + } + } + + page.visit(new TagHandlerPoolVisitor(tagHandlerPoolNames)); + } + + private void declareTemporaryScriptingVars(Node.Nodes page) + throws JasperException { + + class ScriptingVarVisitor extends Node.Visitor { + + private Vector vars; + + ScriptingVarVisitor() { + vars = new Vector(); + } + + public void visit(Node.CustomTag n) throws JasperException { + + if (n.getCustomNestingLevel() > 0) { + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + + if (varInfos.length > 0) { + for (int i = 0; i < varInfos.length; i++) { + String varName = varInfos[i].getVarName(); + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + if (!vars.contains(tmpVarName)) { + vars.add(tmpVarName); + out.printin(varInfos[i].getClassName()); + out.print(" "); + out.print(tmpVarName); + out.print(" = "); + out.print(null); + out.println(";"); + } + } + } else { + for (int i = 0; i < tagVarInfos.length; i++) { + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } else if (tagVarInfos[i].getNameFromAttribute() != null) { + // alias + continue; + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + if (!vars.contains(tmpVarName)) { + vars.add(tmpVarName); + out.printin(tagVarInfos[i].getClassName()); + out.print(" "); + out.print(tmpVarName); + out.print(" = "); + out.print(null); + out.println(";"); + } + } + } + } + + visitBody(n); + } + } + + page.visit(new ScriptingVarVisitor()); + } + + /** + * Generates the _jspInit() method for instantiating the tag handler pools. + * For tag file, _jspInit has to be invoked manually, and the ServletConfig + * object explicitly passed. + * + * In JSP 2.1, we also instantiate an ExpressionFactory + */ + private void generateInit() { + + if (ctxt.isTagFile()) { + out.printil("private void _jspInit(ServletConfig config) {"); + } else { + out.printil("public void _jspInit() {"); + } + + out.pushIndent(); + if (isPoolingEnabled) { + for (int i = 0; i < tagHandlerPoolNames.size(); i++) { + out.printin(tagHandlerPoolNames.elementAt(i)); + out + .print(" = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool("); + if (ctxt.isTagFile()) { + out.print("config"); + } else { + out.print("getServletConfig()"); + } + out.println(");"); + } + } + + out.printin(VAR_EXPRESSIONFACTORY); + out.print(" = JspFactory.getDefaultFactory().getJspApplicationContext("); + if (ctxt.isTagFile()) { + out.print("config"); + } else { + out.print("getServletConfig()"); + } + out.println(".getServletContext()).getExpressionFactory();"); + + out.popIndent(); + out.printil("}"); + out.println(); + } + + /** + * Generates the _jspDestroy() method which is responsible for calling the + * release() method on every tag handler in any of the tag handler pools. + */ + private void generateDestroy() { + + out.printil("public void _jspDestroy() {"); + out.pushIndent(); + + if (isPoolingEnabled) { + for (int i = 0; i < tagHandlerPoolNames.size(); i++) { + out.printin((String) tagHandlerPoolNames.elementAt(i)); + out.println(".release();"); + } + } + + out.popIndent(); + out.printil("}"); + out.println(); + } + + /** + * Generate preamble package name (shared by servlet and tag handler + * preamble generation) + */ + private void genPreamblePackage(String packageName) throws JasperException { + if (!"".equals(packageName) && packageName != null) { + out.printil("package " + packageName + ";"); + out.println(); + } + } + + /** + * Generate preamble imports (shared by servlet and tag handler preamble + * generation) + */ + private void genPreambleImports() throws JasperException { + Iterator iter = pageInfo.getImports().iterator(); + while (iter.hasNext()) { + out.printin("import "); + out.print((String) iter.next()); + out.println(";"); + } + + out.println(); + } + + /** + * Generation of static initializers in preamble. For example, dependant + * list, el function map, prefix map. (shared by servlet and tag handler + * preamble generation) + */ + private void genPreambleStaticInitializers() throws JasperException { + // Static data for getDependants() + out.printil("private static java.util.List _jspx_dependants;"); + out.println(); + List dependants = pageInfo.getDependants(); + Iterator iter = dependants.iterator(); + if (!dependants.isEmpty()) { + out.printil("static {"); + out.pushIndent(); + out.printin("_jspx_dependants = new java.util.ArrayList("); + out.print("" + dependants.size()); + out.println(");"); + while (iter.hasNext()) { + out.printin("_jspx_dependants.add(\""); + out.print((String) iter.next()); + out.println("\");"); + } + out.popIndent(); + out.printil("}"); + out.println(); + } + } + + /** + * Declare tag handler pools (tags of the same type and with the same + * attribute set share the same tag handler pool) (shared by servlet and tag + * handler preamble generation) + * + * In JSP 2.1, we also scope an instance of ExpressionFactory + */ + private void genPreambleClassVariableDeclarations(String className) + throws JasperException { + if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { + for (int i = 0; i < tagHandlerPoolNames.size(); i++) { + out.printil("private org.apache.jasper.runtime.TagHandlerPool " + + tagHandlerPoolNames.elementAt(i) + ";"); + } + out.println(); + } + out.printin("private javax.el.ExpressionFactory "); + out.print(VAR_EXPRESSIONFACTORY); + out.println(";"); + out.println(); + } + + /** + * Declare general-purpose methods (shared by servlet and tag handler + * preamble generation) + */ + private void genPreambleMethods() throws JasperException { + // Method used to get compile time file dependencies + out.printil("public Object getDependants() {"); + out.pushIndent(); + out.printil("return _jspx_dependants;"); + out.popIndent(); + out.printil("}"); + out.println(); + + generateInit(); + generateDestroy(); + } + + /** + * Generates the beginning of the static portion of the servlet. + */ + private void generatePreamble(Node.Nodes page) throws JasperException { + + String servletPackageName = ctxt.getServletPackageName(); + String servletClassName = ctxt.getServletClassName(); + String serviceMethodName = Constants.SERVICE_METHOD_NAME; + + // First the package name: + genPreamblePackage(servletPackageName); + + // Generate imports + genPreambleImports(); + + // Generate class declaration + out.printin("public final class "); + out.print(servletClassName); + out.print(" extends "); + out.println(pageInfo.getExtends()); + out + .printin(" implements org.apache.jasper.runtime.JspSourceDependent"); + if (!pageInfo.isThreadSafe()) { + out.println(","); + out.printin(" SingleThreadModel"); + } + out.println(" {"); + out.pushIndent(); + + // Class body begins here + generateDeclarations(page); + + // Static initializations here + genPreambleStaticInitializers(); + + // Class variable declarations + genPreambleClassVariableDeclarations(servletClassName); + + // Constructor + // generateConstructor(className); + + // Methods here + genPreambleMethods(); + + // Now the service method + out.printin("public void "); + out.print(serviceMethodName); + out + .println("(HttpServletRequest request, HttpServletResponse response)"); + out.println(" throws java.io.IOException, ServletException {"); + + out.pushIndent(); + out.println(); + + // Local variable declarations + out.printil("JspFactory _jspxFactory = null;"); + out.printil("PageContext pageContext = null;"); + + if (pageInfo.isSession()) + out.printil("HttpSession session = null;"); + + if (pageInfo.isErrorPage()) { + out + .printil("Throwable exception = org.apache.jasper.runtime.JspRuntimeLibrary.getThrowable(request);"); + out.printil("if (exception != null) {"); + out.pushIndent(); + out + .printil("response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);"); + out.popIndent(); + out.printil("}"); + } + + out.printil("ServletContext application = null;"); + out.printil("ServletConfig config = null;"); + out.printil("JspWriter out = null;"); + out.printil("Object page = this;"); + + out.printil("JspWriter _jspx_out = null;"); + out.printil("PageContext _jspx_page_context = null;"); + out.println(); + + declareTemporaryScriptingVars(page); + out.println(); + + out.printil("try {"); + out.pushIndent(); + + out.printil("_jspxFactory = JspFactory.getDefaultFactory();"); + + out.printin("response.setContentType("); + out.print(quote(pageInfo.getContentType())); + out.println(");"); + + if (ctxt.getOptions().isXpoweredBy()) { + out.printil("response.addHeader(\"X-Powered-By\", \"JSP/2.0\");"); + } + + out + .printil("pageContext = _jspxFactory.getPageContext(this, request, response,"); + out.printin("\t\t\t"); + out.print(quote(pageInfo.getErrorPage())); + out.print(", " + pageInfo.isSession()); + out.print(", " + pageInfo.getBuffer()); + out.print(", " + pageInfo.isAutoFlush()); + out.println(");"); + out.printil("_jspx_page_context = pageContext;"); + + out.printil("application = pageContext.getServletContext();"); + out.printil("config = pageContext.getServletConfig();"); + + if (pageInfo.isSession()) + out.printil("session = pageContext.getSession();"); + out.printil("out = pageContext.getOut();"); + out.printil("_jspx_out = out;"); + out.println(); + } + + /** + * Generates an XML Prolog, which includes an XML declaration and an XML + * doctype declaration. + */ + private void generateXmlProlog(Node.Nodes page) { + + /* + * An XML declaration is generated under the following conditions: - + * 'omit-xml-declaration' attribute of action is set to + * "no" or "false" - JSP document without a + */ + String omitXmlDecl = pageInfo.getOmitXmlDecl(); + if ((omitXmlDecl != null && !JspUtil.booleanValue(omitXmlDecl)) + || (omitXmlDecl == null && page.getRoot().isXmlSyntax() + && !pageInfo.hasJspRoot() && !ctxt.isTagFile())) { + String cType = pageInfo.getContentType(); + String charSet = cType.substring(cType.indexOf("charset=") + 8); + out.printil("out.write(\"\\n\");"); + } + + /* + * Output a DOCTYPE declaration if the doctype-root-element appears. If + * doctype-public appears: else + */ + + String doctypeName = pageInfo.getDoctypeName(); + if (doctypeName != null) { + String doctypePublic = pageInfo.getDoctypePublic(); + String doctypeSystem = pageInfo.getDoctypeSystem(); + out.printin("out.write(\"\\n\");"); + } + } + + /* + * Generates the constructor. (shared by servlet and tag handler preamble + * generation) + */ + private void generateConstructor(String className) { + out.printil("public " + className + "() {"); + out.printil("}"); + out.println(); + } + + /** + * A visitor that generates codes for the elements in the page. + */ + class GenerateVisitor extends Node.Visitor { + + /* + * Hashtable containing introspection information on tag handlers: + * : tag prefix : hashtable containing introspection on tag + * handlers: : tag short name : introspection info of tag + * handler for tag + */ + private Hashtable handlerInfos; + + private Hashtable tagVarNumbers; + + private String parent; + + private boolean isSimpleTagParent; // Is parent a SimpleTag? + + private String pushBodyCountVar; + + private String simpleTagHandlerVar; + + private boolean isSimpleTagHandler; + + private boolean isFragment; + + private boolean isTagFile; + + private ServletWriter out; + + private ArrayList methodsBuffered; + + private FragmentHelperClass fragmentHelperClass; + + private int methodNesting; + + private TagInfo tagInfo; + + private ClassLoader loader; + + private int charArrayCount; + + private HashMap textMap; + + /** + * Constructor. + */ + public GenerateVisitor(boolean isTagFile, ServletWriter out, + ArrayList methodsBuffered, + FragmentHelperClass fragmentHelperClass, ClassLoader loader, + TagInfo tagInfo) { + + this.isTagFile = isTagFile; + this.out = out; + this.methodsBuffered = methodsBuffered; + this.fragmentHelperClass = fragmentHelperClass; + this.loader = loader; + this.tagInfo = tagInfo; + methodNesting = 0; + handlerInfos = new Hashtable(); + tagVarNumbers = new Hashtable(); + textMap = new HashMap(); + } + + /** + * Returns an attribute value, optionally URL encoded. If the value is a + * runtime expression, the result is the expression itself, as a string. + * If the result is an EL expression, we insert a call to the + * interpreter. If the result is a Named Attribute we insert the + * generated variable name. Otherwise the result is a string literal, + * quoted and escaped. + * + * @param attr + * An JspAttribute object + * @param encode + * true if to be URL encoded + * @param expectedType + * the expected type for an EL evaluation (ignored for + * attributes that aren't EL expressions) + */ + private String attributeValue(Node.JspAttribute attr, boolean encode, + Class expectedType) { + String v = attr.getValue(); + if (!attr.isNamedAttribute() && (v == null)) + return ""; + + if (attr.isExpression()) { + if (encode) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(String.valueOf(" + + v + "), request.getCharacterEncoding())"; + } + return v; + } else if (attr.isELInterpreterInput()) { + boolean replaceESC = v.indexOf(Constants.ESC) > 0; + v = JspUtil.interpreterCall(this.isTagFile, v, expectedType, + attr.getEL().getMapName(), false); + // XXX ESC replacement hack + if (replaceESC) { + v = "(" + v + ").replace(" + Constants.ESCStr + ", '$')"; + } + if (encode) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(" + + v + ", request.getCharacterEncoding())"; + } + return v; + } else if (attr.isNamedAttribute()) { + return attr.getNamedAttributeNode().getTemporaryVariableName(); + } else { + if (encode) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.URLEncode(" + + quote(v) + ", request.getCharacterEncoding())"; + } + return quote(v); + } + } + + /** + * Prints the attribute value specified in the param action, in the form + * of name=value string. + * + * @param n + * the parent node for the param action nodes. + */ + private void printParams(Node n, String pageParam, boolean literal) + throws JasperException { + + class ParamVisitor extends Node.Visitor { + String separator; + + ParamVisitor(String separator) { + this.separator = separator; + } + + public void visit(Node.ParamAction n) throws JasperException { + + out.print(" + "); + out.print(separator); + out.print(" + "); + out.print("org.apache.jasper.runtime.JspRuntimeLibrary." + + "URLEncode(" + quote(n.getTextAttribute("name")) + + ", request.getCharacterEncoding())"); + out.print("+ \"=\" + "); + out.print(attributeValue(n.getValue(), true, String.class)); + + // The separator is '&' after the second use + separator = "\"&\""; + } + } + + String sep; + if (literal) { + sep = pageParam.indexOf('?') > 0 ? "\"&\"" : "\"?\""; + } else { + sep = "((" + pageParam + ").indexOf('?')>0? '&': '?')"; + } + if (n.getBody() != null) { + n.getBody().visit(new ParamVisitor(sep)); + } + } + + public void visit(Node.Expression n) throws JasperException { + n.setBeginJavaLine(out.getJavaLine()); + out.printin("out.print("); + out.printMultiLn(n.getText()); + out.println(");"); + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.Scriptlet n) throws JasperException { + n.setBeginJavaLine(out.getJavaLine()); + out.printMultiLn(n.getText()); + out.println(); + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.ELExpression n) throws JasperException { + n.setBeginJavaLine(out.getJavaLine()); + if (!pageInfo.isELIgnored()) { + out.printil("out.write(" + + JspUtil.interpreterCall(this.isTagFile, "${" + + new String(n.getText()) + "}", String.class, + n.getEL().getMapName(), false) + ");"); + } else { + out.printil("out.write(" + + quote("${" + new String(n.getText()) + "}") + ");"); + } + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.IncludeAction n) throws JasperException { + + String flush = n.getTextAttribute("flush"); + Node.JspAttribute page = n.getPage(); + + boolean isFlush = false; // default to false; + if ("true".equals(flush)) + isFlush = true; + + n.setBeginJavaLine(out.getJavaLine()); + + String pageParam; + if (page.isNamedAttribute()) { + // If the page for jsp:include was specified via + // jsp:attribute, first generate code to evaluate + // that body. + pageParam = generateNamedAttributeValue(page + .getNamedAttributeNode()); + } else { + pageParam = attributeValue(page, false, String.class); + } + + // If any of the params have their values specified by + // jsp:attribute, prepare those values first. + Node jspBody = findJspBody(n); + if (jspBody != null) { + prepareParams(jspBody); + } else { + prepareParams(n); + } + + out + .printin("org.apache.jasper.runtime.JspRuntimeLibrary.include(request, response, " + + pageParam); + printParams(n, pageParam, page.isLiteral()); + out.println(", out, " + isFlush + ");"); + + n.setEndJavaLine(out.getJavaLine()); + } + + /** + * Scans through all child nodes of the given parent for + * subelements. For each element, if its value is specified via + * a Named Attribute (), generate the code to evaluate + * those bodies first. + *

        + * If parent is null, simply returns. + */ + private void prepareParams(Node parent) throws JasperException { + if (parent == null) + return; + + Node.Nodes subelements = parent.getBody(); + if (subelements != null) { + for (int i = 0; i < subelements.size(); i++) { + Node n = subelements.getNode(i); + if (n instanceof Node.ParamAction) { + Node.Nodes paramSubElements = n.getBody(); + for (int j = 0; (paramSubElements != null) + && (j < paramSubElements.size()); j++) { + Node m = paramSubElements.getNode(j); + if (m instanceof Node.NamedAttribute) { + generateNamedAttributeValue((Node.NamedAttribute) m); + } + } + } + } + } + } + + /** + * Finds the subelement of the given parent node. If not + * found, null is returned. + */ + private Node.JspBody findJspBody(Node parent) throws JasperException { + Node.JspBody result = null; + + Node.Nodes subelements = parent.getBody(); + for (int i = 0; (subelements != null) && (i < subelements.size()); i++) { + Node n = subelements.getNode(i); + if (n instanceof Node.JspBody) { + result = (Node.JspBody) n; + break; + } + } + + return result; + } + + public void visit(Node.ForwardAction n) throws JasperException { + Node.JspAttribute page = n.getPage(); + + n.setBeginJavaLine(out.getJavaLine()); + + out.printil("if (true) {"); // So that javac won't complain about + out.pushIndent(); // codes after "return" + + String pageParam; + if (page.isNamedAttribute()) { + // If the page for jsp:forward was specified via + // jsp:attribute, first generate code to evaluate + // that body. + pageParam = generateNamedAttributeValue(page + .getNamedAttributeNode()); + } else { + pageParam = attributeValue(page, false, String.class); + } + + // If any of the params have their values specified by + // jsp:attribute, prepare those values first. + Node jspBody = findJspBody(n); + if (jspBody != null) { + prepareParams(jspBody); + } else { + prepareParams(n); + } + + out.printin("_jspx_page_context.forward("); + out.print(pageParam); + printParams(n, pageParam, page.isLiteral()); + out.println(");"); + if (isTagFile || isFragment) { + out.printil("throw new SkipPageException();"); + } else { + out.printil((methodNesting > 0) ? "return true;" : "return;"); + } + out.popIndent(); + out.printil("}"); + + n.setEndJavaLine(out.getJavaLine()); + // XXX Not sure if we can eliminate dead codes after this. + } + + public void visit(Node.GetProperty n) throws JasperException { + String name = n.getTextAttribute("name"); + String property = n.getTextAttribute("property"); + + n.setBeginJavaLine(out.getJavaLine()); + + if (beanInfo.checkVariable(name)) { + // Bean is defined using useBean, introspect at compile time + Class bean = beanInfo.getBeanType(name); + String beanName = JspUtil.getCanonicalName(bean); + java.lang.reflect.Method meth = JspRuntimeLibrary + .getReadMethod(bean, property); + String methodName = meth.getName(); + out + .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString(" + + "(((" + + beanName + + ")_jspx_page_context.findAttribute(" + + "\"" + + name + "\"))." + methodName + "())));"); + } else { + // The object could be a custom action with an associated + // VariableInfo entry for this name. + // Get the class name and then introspect at runtime. + out + .printil("out.write(org.apache.jasper.runtime.JspRuntimeLibrary.toString" + + "(org.apache.jasper.runtime.JspRuntimeLibrary.handleGetProperty" + + "(_jspx_page_context.getAttribute(\"" + + name + + "\", PageContext.PAGE_SCOPE), \"" + + property + + "\")));"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.SetProperty n) throws JasperException { + String name = n.getTextAttribute("name"); + String property = n.getTextAttribute("property"); + String param = n.getTextAttribute("param"); + Node.JspAttribute value = n.getValue(); + + n.setBeginJavaLine(out.getJavaLine()); + + if ("*".equals(property)) { + out + .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspect(" + + "_jspx_page_context.findAttribute(" + + "\"" + + name + "\"), request);"); + } else if (value == null) { + if (param == null) + param = property; // default to same as property + out + .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" + + "_jspx_page_context.findAttribute(\"" + + name + + "\"), \"" + + property + + "\", request.getParameter(\"" + + param + + "\"), " + + "request, \"" + + param + + "\", false);"); + } else if (value.isExpression()) { + out + .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetProperty(" + + "_jspx_page_context.findAttribute(\"" + + name + + "\"), \"" + property + "\","); + out.print(attributeValue(value, false, null)); + out.println(");"); + } else if (value.isELInterpreterInput()) { + // We've got to resolve the very call to the interpreter + // at runtime since we don't know what type to expect + // in the general case; we thus can't hard-wire the call + // into the generated code. (XXX We could, however, + // optimize the case where the bean is exposed with + // , much as the code here does for + // getProperty.) + + // The following holds true for the arguments passed to + // JspRuntimeLibrary.handleSetPropertyExpression(): + // - 'pageContext' is a VariableResolver. + // - 'this' (either the generated Servlet or the generated tag + // handler for Tag files) is a FunctionMapper. + out + .printil("org.apache.jasper.runtime.JspRuntimeLibrary.handleSetPropertyExpression(" + + "_jspx_page_context.findAttribute(\"" + + name + + "\"), \"" + + property + + "\", " + + quote(value.getValue()) + + ", " + + "_jspx_page_context, " + + value.getEL().getMapName() + ");"); + } else if (value.isNamedAttribute()) { + // If the value for setProperty was specified via + // jsp:attribute, first generate code to evaluate + // that body. + String valueVarName = generateNamedAttributeValue(value + .getNamedAttributeNode()); + out + .printil("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" + + "_jspx_page_context.findAttribute(\"" + + name + + "\"), \"" + + property + + "\", " + + valueVarName + + ", null, null, false);"); + } else { + out + .printin("org.apache.jasper.runtime.JspRuntimeLibrary.introspecthelper(" + + "_jspx_page_context.findAttribute(\"" + + name + + "\"), \"" + property + "\", "); + out.print(attributeValue(value, false, null)); + out.println(", null, null, false);"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.UseBean n) throws JasperException { + + String name = n.getTextAttribute("id"); + String scope = n.getTextAttribute("scope"); + String klass = n.getTextAttribute("class"); + String type = n.getTextAttribute("type"); + Node.JspAttribute beanName = n.getBeanName(); + + // If "class" is specified, try an instantiation at compile time + boolean generateNew = false; + String canonicalName = null; // Canonical name for klass + if (klass != null) { + try { + Class bean = ctxt.getClassLoader().loadClass(klass); + if (klass.indexOf('$') >= 0) { + // Obtain the canonical type name + canonicalName = JspUtil.getCanonicalName(bean); + } else { + canonicalName = klass; + } + int modifiers = bean.getModifiers(); + if (!Modifier.isPublic(modifiers) + || Modifier.isInterface(modifiers) + || Modifier.isAbstract(modifiers)) { + throw new Exception("Invalid bean class modifier"); + } + // Check that there is a 0 arg constructor + bean.getConstructor(new Class[] {}); + // At compile time, we have determined that the bean class + // exists, with a public zero constructor, new() can be + // used for bean instantiation. + generateNew = true; + } catch (Exception e) { + // Cannot instantiate the specified class, either a + // compilation error or a runtime error will be raised, + // depending on a compiler flag. + if (ctxt.getOptions() + .getErrorOnUseBeanInvalidClassAttribute()) { + err.jspError(n, "jsp.error.invalid.bean", klass); + } + if (canonicalName == null) { + // Doing our best here to get a canonical name + // from the binary name, should work 99.99% of time. + canonicalName = klass.replace('$', '.'); + } + } + if (type == null) { + // if type is unspecified, use "class" as type of bean + type = canonicalName; + } + } + + String scopename = "PageContext.PAGE_SCOPE"; // Default to page + String lock = "_jspx_page_context"; + + if ("request".equals(scope)) { + scopename = "PageContext.REQUEST_SCOPE"; + lock = "request"; + } else if ("session".equals(scope)) { + scopename = "PageContext.SESSION_SCOPE"; + lock = "session"; + } else if ("application".equals(scope)) { + scopename = "PageContext.APPLICATION_SCOPE"; + lock = "application"; + } + + n.setBeginJavaLine(out.getJavaLine()); + + // Declare bean + out.printin(type); + out.print(' '); + out.print(name); + out.println(" = null;"); + + // Lock while getting or creating bean + out.printin("synchronized ("); + out.print(lock); + out.println(") {"); + out.pushIndent(); + + // Locate bean from context + out.printin(name); + out.print(" = ("); + out.print(type); + out.print(") _jspx_page_context.getAttribute("); + out.print(quote(name)); + out.print(", "); + out.print(scopename); + out.println(");"); + + // Create bean + /* + * Check if bean is alredy there + */ + out.printin("if ("); + out.print(name); + out.println(" == null){"); + out.pushIndent(); + if (klass == null && beanName == null) { + /* + * If both class name and beanName is not specified, the bean + * must be found locally, otherwise it's an error + */ + out + .printin("throw new java.lang.InstantiationException(\"bean "); + out.print(name); + out.println(" not found within scope\");"); + } else { + /* + * Instantiate the bean if it is not in the specified scope. + */ + if (!generateNew) { + String binaryName; + if (beanName != null) { + if (beanName.isNamedAttribute()) { + // If the value for beanName was specified via + // jsp:attribute, first generate code to evaluate + // that body. + binaryName = generateNamedAttributeValue(beanName + .getNamedAttributeNode()); + } else { + binaryName = attributeValue(beanName, false, + String.class); + } + } else { + // Implies klass is not null + binaryName = quote(klass); + } + out.printil("try {"); + out.pushIndent(); + out.printin(name); + out.print(" = ("); + out.print(type); + out.print(") java.beans.Beans.instantiate("); + out.print("this.getClass().getClassLoader(), "); + out.print(binaryName); + out.println(");"); + out.popIndent(); + /* + * Note: Beans.instantiate throws ClassNotFoundException if + * the bean class is abstract. + */ + out.printil("} catch (ClassNotFoundException exc) {"); + out.pushIndent(); + out + .printil("throw new InstantiationException(exc.getMessage());"); + out.popIndent(); + out.printil("} catch (Exception exc) {"); + out.pushIndent(); + out.printin("throw new ServletException("); + out.print("\"Cannot create bean of class \" + "); + out.print(binaryName); + out.println(", exc);"); + out.popIndent(); + out.printil("}"); // close of try + } else { + // Implies klass is not null + // Generate codes to instantiate the bean class + out.printin(name); + out.print(" = new "); + out.print(canonicalName); + out.println("();"); + } + /* + * Set attribute for bean in the specified scope + */ + out.printin("_jspx_page_context.setAttribute("); + out.print(quote(name)); + out.print(", "); + out.print(name); + out.print(", "); + out.print(scopename); + out.println(");"); + + // Only visit the body when bean is instantiated + visitBody(n); + } + out.popIndent(); + out.printil("}"); + + // End of lock block + out.popIndent(); + out.printil("}"); + + n.setEndJavaLine(out.getJavaLine()); + } + + /** + * @return a string for the form 'attr = "value"' + */ + private String makeAttr(String attr, String value) { + if (value == null) + return ""; + + return " " + attr + "=\"" + value + '\"'; + } + + public void visit(Node.PlugIn n) throws JasperException { + + /** + * A visitor to handle in a plugin + */ + class ParamVisitor extends Node.Visitor { + + private boolean ie; + + ParamVisitor(boolean ie) { + this.ie = ie; + } + + public void visit(Node.ParamAction n) throws JasperException { + + String name = n.getTextAttribute("name"); + if (name.equalsIgnoreCase("object")) + name = "java_object"; + else if (name.equalsIgnoreCase("type")) + name = "java_type"; + + n.setBeginJavaLine(out.getJavaLine()); + // XXX - Fixed a bug here - value used to be output + // inline, which is only okay if value is not an EL + // expression. Also, key/value pairs for the + // embed tag were not being generated correctly. + // Double check that this is now the correct behavior. + if (ie) { + // We want something of the form + // out.println( "" ); + out.printil("out.write( \"\" );"); + out.printil("out.write(\"\\n\");"); + } else { + // We want something of the form + // out.print( " blah=\"" + ... + "\"" ); + out.printil("out.write( \" " + + escape(name) + + "=\\\"\" + " + + attributeValue(n.getValue(), false, + String.class) + " + \"\\\"\" );"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + } + + String type = n.getTextAttribute("type"); + String code = n.getTextAttribute("code"); + String name = n.getTextAttribute("name"); + Node.JspAttribute height = n.getHeight(); + Node.JspAttribute width = n.getWidth(); + String hspace = n.getTextAttribute("hspace"); + String vspace = n.getTextAttribute("vspace"); + String align = n.getTextAttribute("align"); + String iepluginurl = n.getTextAttribute("iepluginurl"); + String nspluginurl = n.getTextAttribute("nspluginurl"); + String codebase = n.getTextAttribute("codebase"); + String archive = n.getTextAttribute("archive"); + String jreversion = n.getTextAttribute("jreversion"); + + String widthStr = null; + if (width != null) { + if (width.isNamedAttribute()) { + widthStr = generateNamedAttributeValue(width + .getNamedAttributeNode()); + } else { + widthStr = attributeValue(width, false, String.class); + } + } + + String heightStr = null; + if (height != null) { + if (height.isNamedAttribute()) { + heightStr = generateNamedAttributeValue(height + .getNamedAttributeNode()); + } else { + heightStr = attributeValue(height, false, String.class); + } + } + + if (iepluginurl == null) + iepluginurl = Constants.IE_PLUGIN_URL; + if (nspluginurl == null) + nspluginurl = Constants.NS_PLUGIN_URL; + + n.setBeginJavaLine(out.getJavaLine()); + + // If any of the params have their values specified by + // jsp:attribute, prepare those values first. + // Look for a params node and prepare its param subelements: + Node.JspBody jspBody = findJspBody(n); + if (jspBody != null) { + Node.Nodes subelements = jspBody.getBody(); + if (subelements != null) { + for (int i = 0; i < subelements.size(); i++) { + Node m = subelements.getNode(i); + if (m instanceof Node.ParamsAction) { + prepareParams(m); + break; + } + } + } + } + + // XXX - Fixed a bug here - width and height can be set + // dynamically. Double-check if this generation is correct. + + // IE style plugin + // + // First compose the runtime output string + String s0 = "'; + + // Then print the output string to the java file + out.printil("out.write(" + quote(s0) + s1 + s2 + " + " + quote(s3) + + ");"); + out.printil("out.write(\"\\n\");"); + + // for java_code + s0 = "'; + out.printil("out.write(" + quote(s0) + ");"); + out.printil("out.write(\"\\n\");"); + + // for java_codebase + if (codebase != null) { + s0 = "'; + out.printil("out.write(" + quote(s0) + ");"); + out.printil("out.write(\"\\n\");"); + } + + // for java_archive + if (archive != null) { + s0 = "'; + out.printil("out.write(" + quote(s0) + ");"); + out.printil("out.write(\"\\n\");"); + } + + // for type + s0 = " for each in the plugin body + */ + if (n.getBody() != null) + n.getBody().visit(new ParamVisitor(true)); + + /* + * Netscape style plugin part + */ + out.printil("out.write(" + quote("") + ");"); + out.printil("out.write(\"\\n\");"); + s0 = " in plugin body + */ + if (n.getBody() != null) + n.getBody().visit(new ParamVisitor(false)); + + out.printil("out.write(" + quote("/>") + ");"); + out.printil("out.write(\"\\n\");"); + + out.printil("out.write(" + quote("") + ");"); + out.printil("out.write(\"\\n\");"); + + /* + * Fallback + */ + if (n.getBody() != null) { + visitBody(n); + out.printil("out.write(\"\\n\");"); + } + + out.printil("out.write(" + quote("") + ");"); + out.printil("out.write(\"\\n\");"); + + out.printil("out.write(" + quote("") + ");"); + out.printil("out.write(\"\\n\");"); + + out.printil("out.write(" + quote("") + ");"); + out.printil("out.write(\"\\n\");"); + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + // Don't visit body of this tag - we already did earlier. + } + + public void visit(Node.CustomTag n) throws JasperException { + + // Use plugin to generate more efficient code if there is one. + if (n.useTagPlugin()) { + generateTagPlugin(n); + return; + } + + TagHandlerInfo handlerInfo = getTagHandlerInfo(n); + + // Create variable names + String baseVar = createTagVarName(n.getQName(), n.getPrefix(), n + .getLocalName()); + String tagEvalVar = "_jspx_eval_" + baseVar; + String tagHandlerVar = "_jspx_th_" + baseVar; + String tagPushBodyCountVar = "_jspx_push_body_count_" + baseVar; + + // If the tag contains no scripting element, generate its codes + // to a method. + ServletWriter outSave = null; + Node.ChildInfo ci = n.getChildInfo(); + if (ci.isScriptless() && !ci.hasScriptingVars()) { + // The tag handler and its body code can reside in a separate + // method if it is scriptless and does not have any scripting + // variable defined. + + String tagMethod = "_jspx_meth_" + baseVar; + + // Generate a call to this method + out.printin("if ("); + out.print(tagMethod); + out.print("("); + if (parent != null) { + out.print(parent); + out.print(", "); + } + out.print("_jspx_page_context"); + if (pushBodyCountVar != null) { + out.print(", "); + out.print(pushBodyCountVar); + } + out.println("))"); + out.pushIndent(); + out.printil((methodNesting > 0) ? "return true;" : "return;"); + out.popIndent(); + + // Set up new buffer for the method + outSave = out; + /* + * For fragments, their bodies will be generated in fragment + * helper classes, and the Java line adjustments will be done + * there, hence they are set to null here to avoid double + * adjustments. + */ + GenBuffer genBuffer = new GenBuffer(n, + n.implementsSimpleTag() ? null : n.getBody()); + methodsBuffered.add(genBuffer); + out = genBuffer.getOut(); + + methodNesting++; + // Generate code for method declaration + out.println(); + out.pushIndent(); + out.printin("private boolean "); + out.print(tagMethod); + out.print("("); + if (parent != null) { + out.print("javax.servlet.jsp.tagext.JspTag "); + out.print(parent); + out.print(", "); + } + out.print("PageContext _jspx_page_context"); + if (pushBodyCountVar != null) { + out.print(", int[] "); + out.print(pushBodyCountVar); + } + out.println(")"); + out.printil(" throws Throwable {"); + out.pushIndent(); + + // Initilaize local variables used in this method. + if (!isTagFile) { + out + .printil("PageContext pageContext = _jspx_page_context;"); + } + out.printil("JspWriter out = _jspx_page_context.getOut();"); + generateLocalVariables(out, n); + } + + if (n.implementsSimpleTag()) { + generateCustomDoTag(n, handlerInfo, tagHandlerVar); + } else { + /* + * Classic tag handler: Generate code for start element, body, + * and end element + */ + generateCustomStart(n, handlerInfo, tagHandlerVar, tagEvalVar, + tagPushBodyCountVar); + + // visit body + String tmpParent = parent; + parent = tagHandlerVar; + boolean isSimpleTagParentSave = isSimpleTagParent; + isSimpleTagParent = false; + String tmpPushBodyCountVar = null; + if (n.implementsTryCatchFinally()) { + tmpPushBodyCountVar = pushBodyCountVar; + pushBodyCountVar = tagPushBodyCountVar; + } + boolean tmpIsSimpleTagHandler = isSimpleTagHandler; + isSimpleTagHandler = false; + + visitBody(n); + + parent = tmpParent; + isSimpleTagParent = isSimpleTagParentSave; + if (n.implementsTryCatchFinally()) { + pushBodyCountVar = tmpPushBodyCountVar; + } + isSimpleTagHandler = tmpIsSimpleTagHandler; + + generateCustomEnd(n, tagHandlerVar, tagEvalVar, + tagPushBodyCountVar); + } + + if (ci.isScriptless() && !ci.hasScriptingVars()) { + // Generate end of method + if (methodNesting > 0) { + out.printil("return false;"); + } + out.popIndent(); + out.printil("}"); + out.popIndent(); + + methodNesting--; + + // restore previous writer + out = outSave; + } + } + + private static final String SINGLE_QUOTE = "'"; + + private static final String DOUBLE_QUOTE = "\\\""; + + public void visit(Node.UninterpretedTag n) throws JasperException { + + n.setBeginJavaLine(out.getJavaLine()); + + /* + * Write begin tag + */ + out.printin("out.write(\"<"); + out.print(n.getQName()); + + Attributes attrs = n.getNonTaglibXmlnsAttributes(); + int attrsLen = (attrs == null) ? 0 : attrs.getLength(); + for (int i = 0; i < attrsLen; i++) { + out.print(" "); + out.print(attrs.getQName(i)); + out.print("="); + String quote = DOUBLE_QUOTE; + String value = attrs.getValue(i); + if (value.indexOf('"') != -1) { + quote = SINGLE_QUOTE; + } + out.print(quote); + out.print(value); + out.print(quote); + } + + attrs = n.getAttributes(); + attrsLen = (attrs == null) ? 0 : attrs.getLength(); + Node.JspAttribute[] jspAttrs = n.getJspAttributes(); + for (int i = 0; i < attrsLen; i++) { + out.print(" "); + out.print(attrs.getQName(i)); + out.print("="); + if (jspAttrs[i].isELInterpreterInput()) { + out.print("\\\"\" + "); + out.print(attributeValue(jspAttrs[i], false, String.class)); + out.print(" + \"\\\""); + } else { + String quote = DOUBLE_QUOTE; + String value = attrs.getValue(i); + if (value.indexOf('"') != -1) { + quote = SINGLE_QUOTE; + } + out.print(quote); + out.print(value); + out.print(quote); + } + } + + if (n.getBody() != null) { + out.println(">\");"); + + // Visit tag body + visitBody(n); + + /* + * Write end tag + */ + out.printin("out.write(\"\");"); + } else { + out.println("/>\");"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.JspElement n) throws JasperException { + + n.setBeginJavaLine(out.getJavaLine()); + + // Compute attribute value string for XML-style and named + // attributes + Hashtable map = new Hashtable(); + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + String attrStr = null; + if (attrs[i].isNamedAttribute()) { + attrStr = generateNamedAttributeValue(attrs[i] + .getNamedAttributeNode()); + } else { + attrStr = attributeValue(attrs[i], false, Object.class); + } + String s = " + \" " + attrs[i].getName() + "=\\\"\" + " + + attrStr + " + \"\\\"\""; + map.put(attrs[i].getName(), s); + } + + // Write begin tag, using XML-style 'name' attribute as the + // element name + String elemName = attributeValue(n.getNameAttribute(), false, + String.class); + out.printin("out.write(\"<\""); + out.print(" + " + elemName); + + // Write remaining attributes + Enumeration enumeration = map.keys(); + while (enumeration.hasMoreElements()) { + String attrName = (String) enumeration.nextElement(); + out.print((String) map.get(attrName)); + } + + // Does the have nested tags other than + // + boolean hasBody = false; + Node.Nodes subelements = n.getBody(); + if (subelements != null) { + for (int i = 0; i < subelements.size(); i++) { + Node subelem = subelements.getNode(i); + if (!(subelem instanceof Node.NamedAttribute)) { + hasBody = true; + break; + } + } + } + if (hasBody) { + out.println(" + \">\");"); + + // Smap should not include the body + n.setEndJavaLine(out.getJavaLine()); + + // Visit tag body + visitBody(n); + + // Write end tag + out.printin("out.write(\"\");"); + } else { + out.println(" + \"/>\");"); + n.setEndJavaLine(out.getJavaLine()); + } + } + + public void visit(Node.TemplateText n) throws JasperException { + + String text = n.getText(); + + int textSize = text.length(); + if (textSize == 0) { + return; + } + + if (textSize <= 3) { + // Special case small text strings + n.setBeginJavaLine(out.getJavaLine()); + int lineInc = 0; + for (int i = 0; i < textSize; i++) { + char ch = text.charAt(i); + out.printil("out.write(" + quote(ch) + ");"); + if (i > 0) { + n.addSmap(lineInc); + } + if (ch == '\n') { + lineInc++; + } + } + n.setEndJavaLine(out.getJavaLine()); + return; + } + + if (ctxt.getOptions().genStringAsCharArray()) { + // Generate Strings as char arrays, for performance + ServletWriter caOut; + if (charArrayBuffer == null) { + charArrayBuffer = new GenBuffer(); + caOut = charArrayBuffer.getOut(); + caOut.pushIndent(); + textMap = new HashMap(); + } else { + caOut = charArrayBuffer.getOut(); + } + String charArrayName = (String) textMap.get(text); + if (charArrayName == null) { + charArrayName = "_jspx_char_array_" + charArrayCount++; + textMap.put(text, charArrayName); + caOut.printin("static char[] "); + caOut.print(charArrayName); + caOut.print(" = "); + caOut.print(quote(text)); + caOut.println(".toCharArray();"); + } + + n.setBeginJavaLine(out.getJavaLine()); + out.printil("out.write(" + charArrayName + ");"); + n.setEndJavaLine(out.getJavaLine()); + return; + } + + n.setBeginJavaLine(out.getJavaLine()); + + out.printin(); + StringBuffer sb = new StringBuffer("out.write(\""); + int initLength = sb.length(); + int count = JspUtil.CHUNKSIZE; + int srcLine = 0; // relative to starting srouce line + for (int i = 0; i < text.length(); i++) { + char ch = text.charAt(i); + --count; + switch (ch) { + case '"': + sb.append('\\').append('\"'); + break; + case '\\': + sb.append('\\').append('\\'); + break; + case '\r': + sb.append('\\').append('r'); + break; + case '\n': + sb.append('\\').append('n'); + srcLine++; + + if (breakAtLF || count < 0) { + // Generate an out.write() when see a '\n' in template + sb.append("\");"); + out.println(sb.toString()); + if (i < text.length() - 1) { + out.printin(); + } + sb.setLength(initLength); + count = JspUtil.CHUNKSIZE; + } + // add a Smap for this line + n.addSmap(srcLine); + break; + case '\t': // Not sure we need this + sb.append('\\').append('t'); + break; + default: + sb.append(ch); + } + } + + if (sb.length() > initLength) { + sb.append("\");"); + out.println(sb.toString()); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.JspBody n) throws JasperException { + if (n.getBody() != null) { + if (isSimpleTagHandler) { + out.printin(simpleTagHandlerVar); + out.print(".setJspBody("); + generateJspFragment(n, simpleTagHandlerVar); + out.println(");"); + } else { + visitBody(n); + } + } + } + + public void visit(Node.InvokeAction n) throws JasperException { + + n.setBeginJavaLine(out.getJavaLine()); + + // Copy virtual page scope of tag file to page scope of invoking + // page + out + .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();"); + String varReaderAttr = n.getTextAttribute("varReader"); + String varAttr = n.getTextAttribute("var"); + if (varReaderAttr != null || varAttr != null) { + out.printil("_jspx_sout = new java.io.StringWriter();"); + } else { + out.printil("_jspx_sout = null;"); + } + + // Invoke fragment, unless fragment is null + out.printin("if ("); + out.print(toGetterMethod(n.getTextAttribute("fragment"))); + out.println(" != null) {"); + out.pushIndent(); + out.printin(toGetterMethod(n.getTextAttribute("fragment"))); + out.println(".invoke(_jspx_sout);"); + out.popIndent(); + out.printil("}"); + + // Store varReader in appropriate scope + if (varReaderAttr != null || varAttr != null) { + String scopeName = n.getTextAttribute("scope"); + out.printin("_jspx_page_context.setAttribute("); + if (varReaderAttr != null) { + out.print(quote(varReaderAttr)); + out + .print(", new java.io.StringReader(_jspx_sout.toString())"); + } else { + out.print(quote(varAttr)); + out.print(", _jspx_sout.toString()"); + } + if (scopeName != null) { + out.print(", "); + out.print(getScopeConstant(scopeName)); + } + out.println(");"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.DoBodyAction n) throws JasperException { + + n.setBeginJavaLine(out.getJavaLine()); + + // Copy virtual page scope of tag file to page scope of invoking + // page + out + .printil("((org.apache.jasper.runtime.JspContextWrapper) this.jspContext).syncBeforeInvoke();"); + + // Invoke body + String varReaderAttr = n.getTextAttribute("varReader"); + String varAttr = n.getTextAttribute("var"); + if (varReaderAttr != null || varAttr != null) { + out.printil("_jspx_sout = new java.io.StringWriter();"); + } else { + out.printil("_jspx_sout = null;"); + } + out.printil("if (getJspBody() != null)"); + out.pushIndent(); + out.printil("getJspBody().invoke(_jspx_sout);"); + out.popIndent(); + + // Store varReader in appropriate scope + if (varReaderAttr != null || varAttr != null) { + String scopeName = n.getTextAttribute("scope"); + out.printin("_jspx_page_context.setAttribute("); + if (varReaderAttr != null) { + out.print(quote(varReaderAttr)); + out + .print(", new java.io.StringReader(_jspx_sout.toString())"); + } else { + out.print(quote(varAttr)); + out.print(", _jspx_sout.toString()"); + } + if (scopeName != null) { + out.print(", "); + out.print(getScopeConstant(scopeName)); + } + out.println(");"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + public void visit(Node.AttributeGenerator n) throws JasperException { + Node.CustomTag tag = n.getTag(); + Node.JspAttribute[] attrs = tag.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + if (attrs[i].getName().equals(n.getName())) { + out.print(evaluateAttribute(getTagHandlerInfo(tag), + attrs[i], tag, null)); + break; + } + } + } + + private TagHandlerInfo getTagHandlerInfo(Node.CustomTag n) + throws JasperException { + Hashtable handlerInfosByShortName = (Hashtable) handlerInfos.get(n + .getPrefix()); + if (handlerInfosByShortName == null) { + handlerInfosByShortName = new Hashtable(); + handlerInfos.put(n.getPrefix(), handlerInfosByShortName); + } + TagHandlerInfo handlerInfo = (TagHandlerInfo) handlerInfosByShortName + .get(n.getLocalName()); + if (handlerInfo == null) { + handlerInfo = new TagHandlerInfo(n, n.getTagHandlerClass(), err); + handlerInfosByShortName.put(n.getLocalName(), handlerInfo); + } + return handlerInfo; + } + + private void generateTagPlugin(Node.CustomTag n) throws JasperException { + if (n.getAtSTag() != null) { + n.getAtSTag().visit(this); + } + visitBody(n); + if (n.getAtETag() != null) { + n.getAtETag().visit(this); + } + } + + private void generateCustomStart(Node.CustomTag n, + TagHandlerInfo handlerInfo, String tagHandlerVar, + String tagEvalVar, String tagPushBodyCountVar) + throws JasperException { + + Class tagHandlerClass = handlerInfo.getTagHandlerClass(); + + out.printin("// "); + out.println(n.getQName()); + n.setBeginJavaLine(out.getJavaLine()); + + // Declare AT_BEGIN scripting variables + declareScriptingVars(n, VariableInfo.AT_BEGIN); + saveScriptingVars(n, VariableInfo.AT_BEGIN); + + String tagHandlerClassName = JspUtil + .getCanonicalName(tagHandlerClass); + out.printin(tagHandlerClassName); + out.print(" "); + out.print(tagHandlerVar); + out.print(" = "); + if (isPoolingEnabled) { + out.print("("); + out.print(tagHandlerClassName); + out.print(") "); + out.print(n.getTagHandlerPoolName()); + out.print(".get("); + out.print(tagHandlerClassName); + out.println(".class);"); + } else { + out.print("new "); + out.print(tagHandlerClassName); + out.println("();"); + if (!ctxt.getOptions().getIgnoreAnnotations()) { + out.printin("org.apache.jasper.runtime.AnnotationProcessor.postConstruct("); + out.print(tagHandlerVar); + out.println(");"); + } + } + + // includes setting the context + generateSetters(n, tagHandlerVar, handlerInfo, false); + + // JspIdConsumer (after context has been set) + if (n.implementsJspIdConsumer()) { + out.printin(tagHandlerVar); + out.print(".setJspId(\""); + out.print(createJspId()); + out.println("\");"); + } + + if (n.implementsTryCatchFinally()) { + out.printin("int[] "); + out.print(tagPushBodyCountVar); + out.println(" = new int[] { 0 };"); + out.printil("try {"); + out.pushIndent(); + } + out.printin("int "); + out.print(tagEvalVar); + out.print(" = "); + out.print(tagHandlerVar); + out.println(".doStartTag();"); + + if (!n.implementsBodyTag()) { + // Synchronize AT_BEGIN scripting variables + syncScriptingVars(n, VariableInfo.AT_BEGIN); + } + + if (!n.hasEmptyBody()) { + out.printin("if ("); + out.print(tagEvalVar); + out.println(" != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {"); + out.pushIndent(); + + // Declare NESTED scripting variables + declareScriptingVars(n, VariableInfo.NESTED); + saveScriptingVars(n, VariableInfo.NESTED); + + if (n.implementsBodyTag()) { + out.printin("if ("); + out.print(tagEvalVar); + out + .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {"); + // Assume EVAL_BODY_BUFFERED + out.pushIndent(); + out.printil("out = _jspx_page_context.pushBody();"); + if (n.implementsTryCatchFinally()) { + out.printin(tagPushBodyCountVar); + out.println("[0]++;"); + } else if (pushBodyCountVar != null) { + out.printin(pushBodyCountVar); + out.println("[0]++;"); + } + out.printin(tagHandlerVar); + out + .println(".setBodyContent((javax.servlet.jsp.tagext.BodyContent) out);"); + out.printin(tagHandlerVar); + out.println(".doInitBody();"); + + out.popIndent(); + out.printil("}"); + + // Synchronize AT_BEGIN and NESTED scripting variables + syncScriptingVars(n, VariableInfo.AT_BEGIN); + syncScriptingVars(n, VariableInfo.NESTED); + + } else { + // Synchronize NESTED scripting variables + syncScriptingVars(n, VariableInfo.NESTED); + } + + if (n.implementsIterationTag()) { + out.printil("do {"); + out.pushIndent(); + } + } + // Map the Java lines that handles start of custom tags to the + // JSP line for this tag + n.setEndJavaLine(out.getJavaLine()); + } + + private void generateCustomEnd(Node.CustomTag n, String tagHandlerVar, + String tagEvalVar, String tagPushBodyCountVar) { + + if (!n.hasEmptyBody()) { + if (n.implementsIterationTag()) { + out.printin("int evalDoAfterBody = "); + out.print(tagHandlerVar); + out.println(".doAfterBody();"); + + // Synchronize AT_BEGIN and NESTED scripting variables + syncScriptingVars(n, VariableInfo.AT_BEGIN); + syncScriptingVars(n, VariableInfo.NESTED); + + out + .printil("if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)"); + out.pushIndent(); + out.printil("break;"); + out.popIndent(); + + out.popIndent(); + out.printil("} while (true);"); + } + + restoreScriptingVars(n, VariableInfo.NESTED); + + if (n.implementsBodyTag()) { + out.printin("if ("); + out.print(tagEvalVar); + out + .println(" != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {"); + out.pushIndent(); + out.printil("out = _jspx_page_context.popBody();"); + if (n.implementsTryCatchFinally()) { + out.printin(tagPushBodyCountVar); + out.println("[0]--;"); + } else if (pushBodyCountVar != null) { + out.printin(pushBodyCountVar); + out.println("[0]--;"); + } + out.popIndent(); + out.printil("}"); + } + + out.popIndent(); // EVAL_BODY + out.printil("}"); + } + + out.printin("if ("); + out.print(tagHandlerVar); + out + .println(".doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {"); + out.pushIndent(); + if (!n.implementsTryCatchFinally()) { + if (isPoolingEnabled) { + out.printin(n.getTagHandlerPoolName()); + out.print(".reuse("); + out.print(tagHandlerVar); + out.println(");"); + } else { + out.printin(tagHandlerVar); + out.println(".release();"); + if (!ctxt.getOptions().getIgnoreAnnotations()) { + out.printil("try {"); + out.pushIndent(); + out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); + out.print(tagHandlerVar); + out.println(");"); + out.popIndent(); + out.printil("} catch (Exception e) {"); + out.pushIndent(); + out.printin("log(\"Error processing preDestroy on tag instance of \" +"); + out.print(tagHandlerVar); + out.println(".getClass().getName());"); + out.popIndent(); + out.printil("}"); + } + } + } + if (isTagFile || isFragment) { + out.printil("throw new SkipPageException();"); + } else { + out.printil((methodNesting > 0) ? "return true;" : "return;"); + } + out.popIndent(); + out.printil("}"); + // Synchronize AT_BEGIN scripting variables + syncScriptingVars(n, VariableInfo.AT_BEGIN); + + // TryCatchFinally + if (n.implementsTryCatchFinally()) { + out.popIndent(); // try + out.printil("} catch (Throwable _jspx_exception) {"); + out.pushIndent(); + + out.printin("while ("); + out.print(tagPushBodyCountVar); + out.println("[0]-- > 0)"); + out.pushIndent(); + out.printil("out = _jspx_page_context.popBody();"); + out.popIndent(); + + out.printin(tagHandlerVar); + out.println(".doCatch(_jspx_exception);"); + out.popIndent(); + out.printil("} finally {"); + out.pushIndent(); + out.printin(tagHandlerVar); + out.println(".doFinally();"); + } + + if (isPoolingEnabled) { + out.printin(n.getTagHandlerPoolName()); + out.print(".reuse("); + out.print(tagHandlerVar); + out.println(");"); + } else { + out.printin(tagHandlerVar); + out.println(".release();"); + if (!ctxt.getOptions().getIgnoreAnnotations()) { + out.printil("try {"); + out.pushIndent(); + out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); + out.print(tagHandlerVar); + out.println(");"); + out.popIndent(); + out.printil("} catch (Exception e) {"); + out.pushIndent(); + out.printin("log(\"Error processing preDestroy on tag instance of \" +"); + out.print(tagHandlerVar); + out.println(".getClass().getName());"); + out.popIndent(); + out.printil("}"); + } + } + + if (n.implementsTryCatchFinally()) { + out.popIndent(); + out.printil("}"); + } + + // Declare and synchronize AT_END scripting variables (must do this + // outside the try/catch/finally block) + declareScriptingVars(n, VariableInfo.AT_END); + syncScriptingVars(n, VariableInfo.AT_END); + + restoreScriptingVars(n, VariableInfo.AT_BEGIN); + } + + private void generateCustomDoTag(Node.CustomTag n, + TagHandlerInfo handlerInfo, String tagHandlerVar) + throws JasperException { + + Class tagHandlerClass = handlerInfo.getTagHandlerClass(); + + n.setBeginJavaLine(out.getJavaLine()); + out.printin("// "); + out.println(n.getQName()); + + // Declare AT_BEGIN scripting variables + declareScriptingVars(n, VariableInfo.AT_BEGIN); + saveScriptingVars(n, VariableInfo.AT_BEGIN); + + String tagHandlerClassName = JspUtil + .getCanonicalName(tagHandlerClass); + out.printin(tagHandlerClassName); + out.print(" "); + out.print(tagHandlerVar); + out.print(" = "); + out.print("new "); + out.print(tagHandlerClassName); + out.println("();"); + + // Resource injection + if (!ctxt.getOptions().getIgnoreAnnotations()) { + out.printin("org.apache.jasper.runtime.AnnotationProcessor.postConstruct("); + out.print(tagHandlerVar); + out.println(");"); + } + + generateSetters(n, tagHandlerVar, handlerInfo, true); + + // Set the body + if (findJspBody(n) == null) { + /* + * Encapsulate body of custom tag invocation in JspFragment and + * pass it to tag handler's setJspBody(), unless tag body is + * empty + */ + if (!n.hasEmptyBody()) { + out.printin(tagHandlerVar); + out.print(".setJspBody("); + generateJspFragment(n, tagHandlerVar); + out.println(");"); + } + } else { + /* + * Body of tag is the body of the element. The visit + * method for that element is going to encapsulate that + * element's body in a JspFragment and pass it to the tag + * handler's setJspBody() + */ + String tmpTagHandlerVar = simpleTagHandlerVar; + simpleTagHandlerVar = tagHandlerVar; + boolean tmpIsSimpleTagHandler = isSimpleTagHandler; + isSimpleTagHandler = true; + visitBody(n); + simpleTagHandlerVar = tmpTagHandlerVar; + isSimpleTagHandler = tmpIsSimpleTagHandler; + } + + out.printin(tagHandlerVar); + out.println(".doTag();"); + + restoreScriptingVars(n, VariableInfo.AT_BEGIN); + + // Synchronize AT_BEGIN scripting variables + syncScriptingVars(n, VariableInfo.AT_BEGIN); + + // Declare and synchronize AT_END scripting variables + declareScriptingVars(n, VariableInfo.AT_END); + syncScriptingVars(n, VariableInfo.AT_END); + + // Resource injection + if (!ctxt.getOptions().getIgnoreAnnotations()) { + out.printin("org.apache.jasper.runtime.AnnotationProcessor.preDestroy("); + out.print(tagHandlerVar); + out.println(");"); + } + + n.setEndJavaLine(out.getJavaLine()); + } + + private void declareScriptingVars(Node.CustomTag n, int scope) { + + Vector vec = n.getScriptingVars(scope); + if (vec != null) { + for (int i = 0; i < vec.size(); i++) { + Object elem = vec.elementAt(i); + if (elem instanceof VariableInfo) { + VariableInfo varInfo = (VariableInfo) elem; + if (varInfo.getDeclare()) { + out.printin(varInfo.getClassName()); + out.print(" "); + out.print(varInfo.getVarName()); + out.println(" = null;"); + } + } else { + TagVariableInfo tagVarInfo = (TagVariableInfo) elem; + if (tagVarInfo.getDeclare()) { + String varName = tagVarInfo.getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfo.getNameFromAttribute()); + } else if (tagVarInfo.getNameFromAttribute() != null) { + // alias + continue; + } + out.printin(tagVarInfo.getClassName()); + out.print(" "); + out.print(varName); + out.println(" = null;"); + } + } + } + } + } + + /* + * This method is called as part of the custom tag's start element. + * + * If the given custom tag has a custom nesting level greater than 0, + * save the current values of its scripting variables to temporary + * variables, so those values may be restored in the tag's end element. + * This way, the scripting variables may be synchronized by the given + * tag without affecting their original values. + */ + private void saveScriptingVars(Node.CustomTag n, int scope) { + if (n.getCustomNestingLevel() == 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { + return; + } + + if (varInfos.length > 0) { + for (int i = 0; i < varInfos.length; i++) { + if (varInfos[i].getScope() != scope) + continue; + // If the scripting variable has been declared, skip codes + // for saving and restoring it. + if (n.getScriptingVars(scope).contains(varInfos[i])) + continue; + String varName = varInfos[i].getVarName(); + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(tmpVarName); + out.print(" = "); + out.print(varName); + out.println(";"); + } + } else { + for (int i = 0; i < tagVarInfos.length; i++) { + if (tagVarInfos[i].getScope() != scope) + continue; + // If the scripting variable has been declared, skip codes + // for saving and restoring it. + if (n.getScriptingVars(scope).contains(tagVarInfos[i])) + continue; + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } else if (tagVarInfos[i].getNameFromAttribute() != null) { + // alias + continue; + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(tmpVarName); + out.print(" = "); + out.print(varName); + out.println(";"); + } + } + } + + /* + * This method is called as part of the custom tag's end element. + * + * If the given custom tag has a custom nesting level greater than 0, + * restore its scripting variables to their original values that were + * saved in the tag's start element. + */ + private void restoreScriptingVars(Node.CustomTag n, int scope) { + if (n.getCustomNestingLevel() == 0) { + return; + } + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { + return; + } + + if (varInfos.length > 0) { + for (int i = 0; i < varInfos.length; i++) { + if (varInfos[i].getScope() != scope) + continue; + // If the scripting variable has been declared, skip codes + // for saving and restoring it. + if (n.getScriptingVars(scope).contains(varInfos[i])) + continue; + String varName = varInfos[i].getVarName(); + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(varName); + out.print(" = "); + out.print(tmpVarName); + out.println(";"); + } + } else { + for (int i = 0; i < tagVarInfos.length; i++) { + if (tagVarInfos[i].getScope() != scope) + continue; + // If the scripting variable has been declared, skip codes + // for saving and restoring it. + if (n.getScriptingVars(scope).contains(tagVarInfos[i])) + continue; + String varName = tagVarInfos[i].getNameGiven(); + if (varName == null) { + varName = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } else if (tagVarInfos[i].getNameFromAttribute() != null) { + // alias + continue; + } + String tmpVarName = "_jspx_" + varName + "_" + + n.getCustomNestingLevel(); + out.printin(varName); + out.print(" = "); + out.print(tmpVarName); + out.println(";"); + } + } + } + + /* + * Synchronizes the scripting variables of the given custom tag for the + * given scope. + */ + private void syncScriptingVars(Node.CustomTag n, int scope) { + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + + if ((varInfos.length == 0) && (tagVarInfos.length == 0)) { + return; + } + + if (varInfos.length > 0) { + for (int i = 0; i < varInfos.length; i++) { + if (varInfos[i].getScope() == scope) { + out.printin(varInfos[i].getVarName()); + out.print(" = ("); + out.print(varInfos[i].getClassName()); + out.print(") _jspx_page_context.findAttribute("); + out.print(quote(varInfos[i].getVarName())); + out.println(");"); + } + } + } else { + for (int i = 0; i < tagVarInfos.length; i++) { + if (tagVarInfos[i].getScope() == scope) { + String name = tagVarInfos[i].getNameGiven(); + if (name == null) { + name = n.getTagData().getAttributeString( + tagVarInfos[i].getNameFromAttribute()); + } else if (tagVarInfos[i].getNameFromAttribute() != null) { + // alias + continue; + } + out.printin(name); + out.print(" = ("); + out.print(tagVarInfos[i].getClassName()); + out.print(") _jspx_page_context.findAttribute("); + out.print(quote(name)); + out.println(");"); + } + } + } + } + + private String getJspContextVar() { + if (this.isTagFile) { + return "this.getJspContext()"; + } else { + return "_jspx_page_context"; + } + } + + private String getExpressionFactoryVar() { + return VAR_EXPRESSIONFACTORY; + } + + /* + * Creates a tag variable name by concatenating the given prefix and + * shortName and endcoded to make the resultant string a valid Java + * Identifier. + */ + private String createTagVarName(String fullName, String prefix, + String shortName) { + + String varName; + synchronized (tagVarNumbers) { + varName = prefix + "_" + shortName + "_"; + if (tagVarNumbers.get(fullName) != null) { + Integer i = (Integer) tagVarNumbers.get(fullName); + varName = varName + i.intValue(); + tagVarNumbers.put(fullName, new Integer(i.intValue() + 1)); + } else { + tagVarNumbers.put(fullName, new Integer(1)); + varName = varName + "0"; + } + } + return JspUtil.makeXmlJavaIdentifier(varName); + } + + private String evaluateAttribute(TagHandlerInfo handlerInfo, + Node.JspAttribute attr, Node.CustomTag n, String tagHandlerVar) + throws JasperException { + + String attrValue = attr.getValue(); + if (attrValue == null) { + if (attr.isNamedAttribute()) { + if (n.checkIfAttributeIsJspFragment(attr.getName())) { + // XXX - no need to generate temporary variable here + attrValue = generateNamedAttributeJspFragment(attr + .getNamedAttributeNode(), tagHandlerVar); + } else { + attrValue = generateNamedAttributeValue(attr + .getNamedAttributeNode()); + } + } else { + return null; + } + } + + String localName = attr.getLocalName(); + + Method m = null; + Class[] c = null; + if (attr.isDynamic()) { + c = OBJECT_CLASS; + } else { + m = handlerInfo.getSetterMethod(localName); + if (m == null) { + err.jspError(n, "jsp.error.unable.to_find_method", attr + .getName()); + } + c = m.getParameterTypes(); + // XXX assert(c.length > 0) + } + + if (attr.isExpression()) { + // Do nothing + } else if (attr.isNamedAttribute()) { + if (!n.checkIfAttributeIsJspFragment(attr.getName()) + && !attr.isDynamic()) { + attrValue = convertString(c[0], attrValue, localName, + handlerInfo.getPropertyEditorClass(localName), true); + } + } else if (attr.isELInterpreterInput()) { + + // results buffer + StringBuffer sb = new StringBuffer(64); + + TagAttributeInfo tai = attr.getTagAttributeInfo(); + String type = tai.getTypeName(); + String returnType = JspUtil.toJavaSourceTypeFromTld(attr + .getExpectedTypeName()); + + // generate elContext reference + sb.append(getJspContextVar()); + sb.append(".getELContext()"); + String elContext = sb.toString(); + if (attr.getEL() != null && attr.getEL().getMapName() != null) { + sb.setLength(0); + sb.append("new org.apache.jasper.el.ELContextWrapper("); + sb.append(elContext); + sb.append(','); + sb.append(attr.getEL().getMapName()); + sb.append(')'); + elContext = sb.toString(); + } + + // reset buffer + sb.setLength(0); + + // create our mark + sb.append(n.getStart().toString()); + sb.append(" '"); + sb.append(attrValue); + sb.append('\''); + String mark = sb.toString(); + + // reset buffer + sb.setLength(0); + + // depending on type + if (attr.isDeferredInput() + || ValueExpression.class.getName().equals(type)) { + sb.append("new org.apache.jasper.el.JspValueExpression("); + sb.append(quote(mark)); + sb.append(','); + sb.append(getExpressionFactoryVar()); + sb.append(".createValueExpression("); + if (attr.getEL() != null) { // optimize + sb.append(elContext); + sb.append(','); + } + sb.append(quote(attrValue)); + sb.append(','); + sb.append(returnType); + sb.append("))"); + attrValue = sb.toString(); + } else if (attr.isDeferredMethodInput() + || MethodExpression.class.getName().equals(type)) { + sb.append("new org.apache.jasper.el.JspMethodExpression("); + sb.append(quote(mark)); + sb.append(','); + sb.append(getExpressionFactoryVar()); + sb.append(".createMethodExpression("); + sb.append(elContext); + sb.append(','); + sb.append(quote(attrValue)); + sb.append(','); + sb.append(returnType); + sb.append(','); + sb.append("new Class[] {"); + + String[] p = attr.getParameterTypeNames(); + for (int i = 0; i < p.length; i++) { + sb.append(JspUtil.toJavaSourceTypeFromTld(p[i])); + sb.append(','); + } + if (p.length > 0) { + sb.setLength(sb.length() - 1); + } + + sb.append("}))"); + attrValue = sb.toString(); + } else { + // run attrValue through the expression interpreter + boolean replaceESC = attrValue.indexOf(Constants.ESC) > 0; + String mapName = (attr.getEL() != null) ? attr.getEL() + .getMapName() : null; + attrValue = JspUtil.interpreterCall(this.isTagFile, + attrValue, c[0], mapName, false); + // XXX hack: Replace ESC with '$' + if (replaceESC) { + attrValue = "(" + attrValue + ").replace(" + + Constants.ESCStr + ", '$')"; + } + } + } else { + attrValue = convertString(c[0], attrValue, localName, + handlerInfo.getPropertyEditorClass(localName), false); + } + return attrValue; + } + + /** + * Generate code to create a map for the alias variables + * + * @return the name of the map + */ + private String generateAliasMap(Node.CustomTag n, String tagHandlerVar) + throws JasperException { + + TagVariableInfo[] tagVars = n.getTagVariableInfos(); + String aliasMapVar = null; + + boolean aliasSeen = false; + for (int i = 0; i < tagVars.length; i++) { + + String nameFrom = tagVars[i].getNameFromAttribute(); + if (nameFrom != null) { + String aliasedName = n.getAttributeValue(nameFrom); + if (aliasedName == null) + continue; + + if (!aliasSeen) { + out.printin("java.util.HashMap "); + aliasMapVar = tagHandlerVar + "_aliasMap"; + out.print(aliasMapVar); + out.println(" = new java.util.HashMap();"); + aliasSeen = true; + } + out.printin(aliasMapVar); + out.print(".put("); + out.print(quote(tagVars[i].getNameGiven())); + out.print(", "); + out.print(quote(aliasedName)); + out.println(");"); + } + } + return aliasMapVar; + } + + private void generateSetters(Node.CustomTag n, String tagHandlerVar, + TagHandlerInfo handlerInfo, boolean simpleTag) + throws JasperException { + + // Set context + if (simpleTag) { + // Generate alias map + String aliasMapVar = null; + if (n.isTagFile()) { + aliasMapVar = generateAliasMap(n, tagHandlerVar); + } + out.printin(tagHandlerVar); + if (aliasMapVar == null) { + out.println(".setJspContext(_jspx_page_context);"); + } else { + out.print(".setJspContext(_jspx_page_context, "); + out.print(aliasMapVar); + out.println(");"); + } + } else { + out.printin(tagHandlerVar); + out.println(".setPageContext(_jspx_page_context);"); + } + + // Set parent + if (!simpleTag) { + out.printin(tagHandlerVar); + out.print(".setParent("); + if (parent != null) { + if (isSimpleTagParent) { + out.print("new javax.servlet.jsp.tagext.TagAdapter("); + out.print("(javax.servlet.jsp.tagext.SimpleTag) "); + out.print(parent); + out.println("));"); + } else { + out.print("(javax.servlet.jsp.tagext.Tag) "); + out.print(parent); + out.println(");"); + } + } else { + out.println("null);"); + } + } else { + // The setParent() method need not be called if the value being + // passed is null, since SimpleTag instances are not reused + if (parent != null) { + out.printin(tagHandlerVar); + out.print(".setParent("); + out.print(parent); + out.println(");"); + } + } + + // need to handle deferred values and methods + Node.JspAttribute[] attrs = n.getJspAttributes(); + for (int i = 0; attrs != null && i < attrs.length; i++) { + String attrValue = evaluateAttribute(handlerInfo, attrs[i], n, + tagHandlerVar); + + Mark m = n.getStart(); + out.printil("// "+m.getFile()+"("+m.getLineNumber()+","+m.getColumnNumber()+") "+ attrs[i].getTagAttributeInfo()); + if (attrs[i].isDynamic()) { + out.printin(tagHandlerVar); + out.print("."); + out.print("setDynamicAttribute("); + String uri = attrs[i].getURI(); + if ("".equals(uri) || (uri == null)) { + out.print("null"); + } else { + out.print("\"" + attrs[i].getURI() + "\""); + } + out.print(", \""); + out.print(attrs[i].getLocalName()); + out.print("\", "); + out.print(attrValue); + out.println(");"); + } else { + out.printin(tagHandlerVar); + out.print("."); + out.print(handlerInfo.getSetterMethod( + attrs[i].getLocalName()).getName()); + out.print("("); + out.print(attrValue); + out.println(");"); + } + } + } + + /* + * @param c The target class to which to coerce the given string @param + * s The string value @param attrName The name of the attribute whose + * value is being supplied @param propEditorClass The property editor + * for the given attribute @param isNamedAttribute true if the given + * attribute is a named attribute (that is, specified using the + * jsp:attribute standard action), and false otherwise + */ + private String convertString(Class c, String s, String attrName, + Class propEditorClass, boolean isNamedAttribute) + throws JasperException { + + String quoted = s; + if (!isNamedAttribute) { + quoted = quote(s); + } + + if (propEditorClass != null) { + String className = JspUtil.getCanonicalName(c); + return "(" + + className + + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromBeanInfoPropertyEditor(" + + className + ".class, \"" + attrName + "\", " + quoted + + ", " + JspUtil.getCanonicalName(propEditorClass) + + ".class)"; + } else if (c == String.class) { + return quoted; + } else if (c == boolean.class) { + return JspUtil.coerceToPrimitiveBoolean(s, isNamedAttribute); + } else if (c == Boolean.class) { + return JspUtil.coerceToBoolean(s, isNamedAttribute); + } else if (c == byte.class) { + return JspUtil.coerceToPrimitiveByte(s, isNamedAttribute); + } else if (c == Byte.class) { + return JspUtil.coerceToByte(s, isNamedAttribute); + } else if (c == char.class) { + return JspUtil.coerceToChar(s, isNamedAttribute); + } else if (c == Character.class) { + return JspUtil.coerceToCharacter(s, isNamedAttribute); + } else if (c == double.class) { + return JspUtil.coerceToPrimitiveDouble(s, isNamedAttribute); + } else if (c == Double.class) { + return JspUtil.coerceToDouble(s, isNamedAttribute); + } else if (c == float.class) { + return JspUtil.coerceToPrimitiveFloat(s, isNamedAttribute); + } else if (c == Float.class) { + return JspUtil.coerceToFloat(s, isNamedAttribute); + } else if (c == int.class) { + return JspUtil.coerceToInt(s, isNamedAttribute); + } else if (c == Integer.class) { + return JspUtil.coerceToInteger(s, isNamedAttribute); + } else if (c == short.class) { + return JspUtil.coerceToPrimitiveShort(s, isNamedAttribute); + } else if (c == Short.class) { + return JspUtil.coerceToShort(s, isNamedAttribute); + } else if (c == long.class) { + return JspUtil.coerceToPrimitiveLong(s, isNamedAttribute); + } else if (c == Long.class) { + return JspUtil.coerceToLong(s, isNamedAttribute); + } else if (c == Object.class) { + return "new String(" + quoted + ")"; + } else { + String className = JspUtil.getCanonicalName(c); + return "(" + + className + + ")org.apache.jasper.runtime.JspRuntimeLibrary.getValueFromPropertyEditorManager(" + + className + ".class, \"" + attrName + "\", " + quoted + + ")"; + } + } + + /* + * Converts the scope string representation, whose possible values are + * "page", "request", "session", and "application", to the corresponding + * scope constant. + */ + private String getScopeConstant(String scope) { + String scopeName = "PageContext.PAGE_SCOPE"; // Default to page + + if ("request".equals(scope)) { + scopeName = "PageContext.REQUEST_SCOPE"; + } else if ("session".equals(scope)) { + scopeName = "PageContext.SESSION_SCOPE"; + } else if ("application".equals(scope)) { + scopeName = "PageContext.APPLICATION_SCOPE"; + } + + return scopeName; + } + + /** + * Generates anonymous JspFragment inner class which is passed as an + * argument to SimpleTag.setJspBody(). + */ + private void generateJspFragment(Node n, String tagHandlerVar) + throws JasperException { + // XXX - A possible optimization here would be to check to see + // if the only child of the parent node is TemplateText. If so, + // we know there won't be any parameters, etc, so we can + // generate a low-overhead JspFragment that just echoes its + // body. The implementation of this fragment can come from + // the org.apache.jasper.runtime package as a support class. + FragmentHelperClass.Fragment fragment = fragmentHelperClass + .openFragment(n, tagHandlerVar, methodNesting); + ServletWriter outSave = out; + out = fragment.getGenBuffer().getOut(); + String tmpParent = parent; + parent = "_jspx_parent"; + boolean isSimpleTagParentSave = isSimpleTagParent; + isSimpleTagParent = true; + boolean tmpIsFragment = isFragment; + isFragment = true; + String pushBodyCountVarSave = pushBodyCountVar; + if (pushBodyCountVar != null) { + // Use a fixed name for push body count, to simplify code gen + pushBodyCountVar = "_jspx_push_body_count"; + } + visitBody(n); + out = outSave; + parent = tmpParent; + isSimpleTagParent = isSimpleTagParentSave; + isFragment = tmpIsFragment; + pushBodyCountVar = pushBodyCountVarSave; + fragmentHelperClass.closeFragment(fragment, methodNesting); + // XXX - Need to change pageContext to jspContext if + // we're not in a place where pageContext is defined (e.g. + // in a fragment or in a tag file. + out.print("new " + fragmentHelperClass.getClassName() + "( " + + fragment.getId() + ", _jspx_page_context, " + + tagHandlerVar + ", " + pushBodyCountVar + ")"); + } + + /** + * Generate the code required to obtain the runtime value of the given + * named attribute. + * + * @return The name of the temporary variable the result is stored in. + */ + public String generateNamedAttributeValue(Node.NamedAttribute n) + throws JasperException { + + String varName = n.getTemporaryVariableName(); + + // If the only body element for this named attribute node is + // template text, we need not generate an extra call to + // pushBody and popBody. Maybe we can further optimize + // here by getting rid of the temporary variable, but in + // reality it looks like javac does this for us. + Node.Nodes body = n.getBody(); + if (body != null) { + boolean templateTextOptimization = false; + if (body.size() == 1) { + Node bodyElement = body.getNode(0); + if (bodyElement instanceof Node.TemplateText) { + templateTextOptimization = true; + out.printil("String " + + varName + + " = " + + quote(new String( + ((Node.TemplateText) bodyElement) + .getText())) + ";"); + } + } + + // XXX - Another possible optimization would be for + // lone EL expressions (no need to pushBody here either). + + if (!templateTextOptimization) { + out.printil("out = _jspx_page_context.pushBody();"); + visitBody(n); + out.printil("String " + varName + " = " + + "((javax.servlet.jsp.tagext.BodyContent)" + + "out).getString();"); + out.printil("out = _jspx_page_context.popBody();"); + } + } else { + // Empty body must be treated as "" + out.printil("String " + varName + " = \"\";"); + } + + return varName; + } + + /** + * Similar to generateNamedAttributeValue, but create a JspFragment + * instead. + * + * @param n + * The parent node of the named attribute + * @param tagHandlerVar + * The variable the tag handler is stored in, so the fragment + * knows its parent tag. + * @return The name of the temporary variable the fragment is stored in. + */ + public String generateNamedAttributeJspFragment(Node.NamedAttribute n, + String tagHandlerVar) throws JasperException { + String varName = n.getTemporaryVariableName(); + + out.printin("javax.servlet.jsp.tagext.JspFragment " + varName + + " = "); + generateJspFragment(n, tagHandlerVar); + out.println(";"); + + return varName; + } + } + + private static void generateLocalVariables(ServletWriter out, Node n) + throws JasperException { + Node.ChildInfo ci; + if (n instanceof Node.CustomTag) { + ci = ((Node.CustomTag) n).getChildInfo(); + } else if (n instanceof Node.JspBody) { + ci = ((Node.JspBody) n).getChildInfo(); + } else if (n instanceof Node.NamedAttribute) { + ci = ((Node.NamedAttribute) n).getChildInfo(); + } else { + // Cannot access err since this method is static, but at + // least flag an error. + throw new JasperException("Unexpected Node Type"); + // err.getString( + // "jsp.error.internal.unexpected_node_type" ) ); + } + + if (ci.hasUseBean()) { + out + .printil("HttpSession session = _jspx_page_context.getSession();"); + out + .printil("ServletContext application = _jspx_page_context.getServletContext();"); + } + if (ci.hasUseBean() || ci.hasIncludeAction() || ci.hasSetProperty() + || ci.hasParamAction()) { + out + .printil("HttpServletRequest request = (HttpServletRequest)_jspx_page_context.getRequest();"); + } + if (ci.hasIncludeAction()) { + out + .printil("HttpServletResponse response = (HttpServletResponse)_jspx_page_context.getResponse();"); + } + } + + /** + * Common part of postamble, shared by both servlets and tag files. + */ + private void genCommonPostamble() { + // Append any methods that were generated in the buffer. + for (int i = 0; i < methodsBuffered.size(); i++) { + GenBuffer methodBuffer = (GenBuffer) methodsBuffered.get(i); + methodBuffer.adjustJavaLines(out.getJavaLine() - 1); + out.printMultiLn(methodBuffer.toString()); + } + + // Append the helper class + if (fragmentHelperClass.isUsed()) { + fragmentHelperClass.generatePostamble(); + fragmentHelperClass.adjustJavaLines(out.getJavaLine() - 1); + out.printMultiLn(fragmentHelperClass.toString()); + } + + // Append char array declarations + if (charArrayBuffer != null) { + out.printMultiLn(charArrayBuffer.toString()); + } + + // Close the class definition + out.popIndent(); + out.printil("}"); + } + + /** + * Generates the ending part of the static portion of the servlet. + */ + private void generatePostamble(Node.Nodes page) { + out.popIndent(); + out.printil("} catch (Throwable t) {"); + out.pushIndent(); + out.printil("if (!(t instanceof SkipPageException)){"); + out.pushIndent(); + out.printil("out = _jspx_out;"); + out.printil("if (out != null && out.getBufferSize() != 0)"); + out.pushIndent(); + out.printil("out.clearBuffer();"); + out.popIndent(); + + out + .printil("if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);"); + out.popIndent(); + out.printil("}"); + out.popIndent(); + out.printil("} finally {"); + out.pushIndent(); + + out + .printil("if (_jspxFactory != null) _jspxFactory.releasePageContext(_jspx_page_context);"); + + out.popIndent(); + out.printil("}"); + + // Close the service method + out.popIndent(); + out.printil("}"); + + // Generated methods, helper classes, etc. + genCommonPostamble(); + } + + /** + * Constructor. + */ + Generator(ServletWriter out, Compiler compiler) { + this.out = out; + methodsBuffered = new ArrayList(); + charArrayBuffer = null; + err = compiler.getErrorDispatcher(); + ctxt = compiler.getCompilationContext(); + fragmentHelperClass = new FragmentHelperClass(ctxt + .getServletClassName() + + "Helper"); + pageInfo = compiler.getPageInfo(); + + /* + * Temporary hack. If a JSP page uses the "extends" attribute of the + * page directive, the _jspInit() method of the generated servlet class + * will not be called (it is only called for those generated servlets + * that extend HttpJspBase, the default), causing the tag handler pools + * not to be initialized and resulting in a NPE. The JSP spec needs to + * clarify whether containers can override init() and destroy(). For + * now, we just disable tag pooling for pages that use "extends". + */ + if (pageInfo.getExtends(false) == null) { + isPoolingEnabled = ctxt.getOptions().isPoolingEnabled(); + } else { + isPoolingEnabled = false; + } + beanInfo = pageInfo.getBeanRepository(); + breakAtLF = ctxt.getOptions().getMappedFile(); + if (isPoolingEnabled) { + tagHandlerPoolNames = new Vector(); + } + } + + /** + * The main entry for Generator. + * + * @param out + * The servlet output writer + * @param compiler + * The compiler + * @param page + * The input page + */ + public static void generate(ServletWriter out, Compiler compiler, + Node.Nodes page) throws JasperException { + + Generator gen = new Generator(out, compiler); + + if (gen.isPoolingEnabled) { + gen.compileTagHandlerPoolList(page); + } + if (gen.ctxt.isTagFile()) { + JasperTagInfo tagInfo = (JasperTagInfo) gen.ctxt.getTagInfo(); + gen.generateTagHandlerPreamble(tagInfo, page); + + if (gen.ctxt.isPrototypeMode()) { + return; + } + + gen.generateXmlProlog(page); + gen.fragmentHelperClass.generatePreamble(); + page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out, + gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt + .getClassLoader(), tagInfo)); + gen.generateTagHandlerPostamble(tagInfo); + } else { + gen.generatePreamble(page); + gen.generateXmlProlog(page); + gen.fragmentHelperClass.generatePreamble(); + page.visit(gen.new GenerateVisitor(gen.ctxt.isTagFile(), out, + gen.methodsBuffered, gen.fragmentHelperClass, gen.ctxt + .getClassLoader(), null)); + gen.generatePostamble(page); + } + } + + /* + * Generates tag handler preamble. + */ + private void generateTagHandlerPreamble(JasperTagInfo tagInfo, + Node.Nodes tag) throws JasperException { + + // Generate package declaration + String className = tagInfo.getTagClassName(); + int lastIndex = className.lastIndexOf('.'); + if (lastIndex != -1) { + String pkgName = className.substring(0, lastIndex); + genPreamblePackage(pkgName); + className = className.substring(lastIndex + 1); + } + + // Generate imports + genPreambleImports(); + + // Generate class declaration + out.printin("public final class "); + out.println(className); + out.printil(" extends javax.servlet.jsp.tagext.SimpleTagSupport"); + out + .printin(" implements org.apache.jasper.runtime.JspSourceDependent"); + if (tagInfo.hasDynamicAttributes()) { + out.println(","); + out + .printin(" javax.servlet.jsp.tagext.DynamicAttributes"); + } + out.println(" {"); + out.println(); + out.pushIndent(); + + /* + * Class body begins here + */ + + generateDeclarations(tag); + + // Static initializations here + genPreambleStaticInitializers(); + + out.printil("private JspContext jspContext;"); + + // Declare writer used for storing result of fragment/body invocation + // if 'varReader' or 'var' attribute is specified + out.printil("private java.io.Writer _jspx_sout;"); + + // Class variable declarations + genPreambleClassVariableDeclarations(tagInfo.getTagName()); + + generateSetJspContext(tagInfo); + + // Tag-handler specific declarations + generateTagHandlerAttributes(tagInfo); + if (tagInfo.hasDynamicAttributes()) + generateSetDynamicAttribute(); + + // Methods here + genPreambleMethods(); + + // Now the doTag() method + out + .printil("public void doTag() throws JspException, java.io.IOException {"); + + if (ctxt.isPrototypeMode()) { + out.printil("}"); + out.popIndent(); + out.printil("}"); + return; + } + + out.pushIndent(); + + /* + * According to the spec, 'pageContext' must not be made available as an + * implicit object in tag files. Declare _jspx_page_context, so we can + * share the code generator with JSPs. + */ + out + .printil("PageContext _jspx_page_context = (PageContext)jspContext;"); + + // Declare implicit objects. + out.printil("HttpServletRequest request = " + + "(HttpServletRequest) _jspx_page_context.getRequest();"); + out.printil("HttpServletResponse response = " + + "(HttpServletResponse) _jspx_page_context.getResponse();"); + out.printil("HttpSession session = _jspx_page_context.getSession();"); + out + .printil("ServletContext application = _jspx_page_context.getServletContext();"); + out + .printil("ServletConfig config = _jspx_page_context.getServletConfig();"); + out.printil("JspWriter out = jspContext.getOut();"); + if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { + out.printil("_jspInit(config);"); + } + + // set current JspContext on ELContext + out.printil("jspContext.getELContext().putContext(JspContext.class,jspContext);"); + + generatePageScopedVariables(tagInfo); + + declareTemporaryScriptingVars(tag); + out.println(); + + out.printil("try {"); + out.pushIndent(); + } + + private void generateTagHandlerPostamble(TagInfo tagInfo) { + out.popIndent(); + + // Have to catch Throwable because a classic tag handler + // helper method is declared to throw Throwable. + out.printil("} catch( Throwable t ) {"); + out.pushIndent(); + out.printil("if( t instanceof SkipPageException )"); + out.printil(" throw (SkipPageException) t;"); + out.printil("if( t instanceof java.io.IOException )"); + out.printil(" throw (java.io.IOException) t;"); + out.printil("if( t instanceof IllegalStateException )"); + out.printil(" throw (IllegalStateException) t;"); + out.printil("if( t instanceof JspException )"); + out.printil(" throw (JspException) t;"); + out.printil("throw new JspException(t);"); + out.popIndent(); + out.printil("} finally {"); + out.pushIndent(); + + // handle restoring VariableMapper + TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); + for (int i = 0; i < attrInfos.length; i++) { + if (attrInfos[i].isDeferredMethod() || attrInfos[i].isDeferredValue()) { + out.printin("_el_variablemapper.setVariable("); + out.print(quote(attrInfos[i].getName())); + out.print(",_el_ve"); + out.print(i); + out.println(");"); + } + } + + // restore nested JspContext on ELContext + out.printil("jspContext.getELContext().putContext(JspContext.class,getJspContext());"); + + out + .printil("((org.apache.jasper.runtime.JspContextWrapper) jspContext).syncEndTagFile();"); + if (isPoolingEnabled && !tagHandlerPoolNames.isEmpty()) { + out.printil("_jspDestroy();"); + } + out.popIndent(); + out.printil("}"); + + // Close the doTag method + out.popIndent(); + out.printil("}"); + + // Generated methods, helper classes, etc. + genCommonPostamble(); + } + + /** + * Generates declarations for tag handler attributes, and defines the getter + * and setter methods for each. + */ + private void generateTagHandlerAttributes(TagInfo tagInfo) + throws JasperException { + + if (tagInfo.hasDynamicAttributes()) { + out + .printil("private java.util.HashMap _jspx_dynamic_attrs = new java.util.HashMap();"); + } + + // Declare attributes + TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); + for (int i = 0; i < attrInfos.length; i++) { + out.printin("private "); + if (attrInfos[i].isFragment()) { + out.print("javax.servlet.jsp.tagext.JspFragment "); + } else { + out.print(JspUtil.toJavaSourceType(attrInfos[i].getTypeName())); + out.print(" "); + } + out.print(attrInfos[i].getName()); + out.println(";"); + } + out.println(); + + // Define attribute getter and setter methods + if (attrInfos != null) { + for (int i = 0; i < attrInfos.length; i++) { + // getter method + out.printin("public "); + if (attrInfos[i].isFragment()) { + out.print("javax.servlet.jsp.tagext.JspFragment "); + } else { + out.print(JspUtil.toJavaSourceType(attrInfos[i] + .getTypeName())); + out.print(" "); + } + out.print(toGetterMethod(attrInfos[i].getName())); + out.println(" {"); + out.pushIndent(); + out.printin("return this."); + out.print(attrInfos[i].getName()); + out.println(";"); + out.popIndent(); + out.printil("}"); + out.println(); + + // setter method + out.printin("public void "); + out.print(toSetterMethodName(attrInfos[i].getName())); + if (attrInfos[i].isFragment()) { + out.print("(javax.servlet.jsp.tagext.JspFragment "); + } else { + out.print("("); + out.print(JspUtil.toJavaSourceType(attrInfos[i] + .getTypeName())); + out.print(" "); + } + out.print(attrInfos[i].getName()); + out.println(") {"); + out.pushIndent(); + out.printin("this."); + out.print(attrInfos[i].getName()); + out.print(" = "); + out.print(attrInfos[i].getName()); + out.println(";"); + out.popIndent(); + out.printil("}"); + out.println(); + } + } + } + + /* + * Generate setter for JspContext so we can create a wrapper and store both + * the original and the wrapper. We need the wrapper to mask the page + * context from the tag file and simulate a fresh page context. We need the + * original to do things like sync AT_BEGIN and AT_END scripting variables. + */ + private void generateSetJspContext(TagInfo tagInfo) { + + boolean nestedSeen = false; + boolean atBeginSeen = false; + boolean atEndSeen = false; + + // Determine if there are any aliases + boolean aliasSeen = false; + TagVariableInfo[] tagVars = tagInfo.getTagVariableInfos(); + for (int i = 0; i < tagVars.length; i++) { + if (tagVars[i].getNameFromAttribute() != null + && tagVars[i].getNameGiven() != null) { + aliasSeen = true; + break; + } + } + + if (aliasSeen) { + out + .printil("public void setJspContext(JspContext ctx, java.util.Map aliasMap) {"); + } else { + out.printil("public void setJspContext(JspContext ctx) {"); + } + out.pushIndent(); + out.printil("super.setJspContext(ctx);"); + out.printil("java.util.ArrayList _jspx_nested = null;"); + out.printil("java.util.ArrayList _jspx_at_begin = null;"); + out.printil("java.util.ArrayList _jspx_at_end = null;"); + + for (int i = 0; i < tagVars.length; i++) { + + switch (tagVars[i].getScope()) { + case VariableInfo.NESTED: + if (!nestedSeen) { + out.printil("_jspx_nested = new java.util.ArrayList();"); + nestedSeen = true; + } + out.printin("_jspx_nested.add("); + break; + + case VariableInfo.AT_BEGIN: + if (!atBeginSeen) { + out.printil("_jspx_at_begin = new java.util.ArrayList();"); + atBeginSeen = true; + } + out.printin("_jspx_at_begin.add("); + break; + + case VariableInfo.AT_END: + if (!atEndSeen) { + out.printil("_jspx_at_end = new java.util.ArrayList();"); + atEndSeen = true; + } + out.printin("_jspx_at_end.add("); + break; + } // switch + + out.print(quote(tagVars[i].getNameGiven())); + out.println(");"); + } + if (aliasSeen) { + out + .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, aliasMap);"); + } else { + out + .printil("this.jspContext = new org.apache.jasper.runtime.JspContextWrapper(ctx, _jspx_nested, _jspx_at_begin, _jspx_at_end, null);"); + } + out.popIndent(); + out.printil("}"); + out.println(); + out.printil("public JspContext getJspContext() {"); + out.pushIndent(); + out.printil("return this.jspContext;"); + out.popIndent(); + out.printil("}"); + } + + /* + * Generates implementation of + * javax.servlet.jsp.tagext.DynamicAttributes.setDynamicAttribute() method, + * which saves each dynamic attribute that is passed in so that a scoped + * variable can later be created for it. + */ + public void generateSetDynamicAttribute() { + out + .printil("public void setDynamicAttribute(String uri, String localName, Object value) throws JspException {"); + out.pushIndent(); + /* + * According to the spec, only dynamic attributes with no uri are to be + * present in the Map; all other dynamic attributes are ignored. + */ + out.printil("if (uri == null)"); + out.pushIndent(); + out.printil("_jspx_dynamic_attrs.put(localName, value);"); + out.popIndent(); + out.popIndent(); + out.printil("}"); + } + + /* + * Creates a page-scoped variable for each declared tag attribute. Also, if + * the tag accepts dynamic attributes, a page-scoped variable is made + * available for each dynamic attribute that was passed in. + */ + private void generatePageScopedVariables(JasperTagInfo tagInfo) { + + // "normal" attributes + TagAttributeInfo[] attrInfos = tagInfo.getAttributes(); + boolean variableMapperVar = false; + for (int i = 0; i < attrInfos.length; i++) { + String attrName = attrInfos[i].getName(); + + // handle assigning deferred vars to VariableMapper, storing + // previous values under '_el_ve[i]' for later re-assignment + if (attrInfos[i].isDeferredValue() || attrInfos[i].isDeferredMethod()) { + + // we need to scope the modified VariableMapper for consistency and performance + if (!variableMapperVar) { + out.println("javax.el.VariableMapper _el_variablemapper = jspContext.getELContext().getVariableMapper();"); + variableMapperVar = true; + } + + out.printin("javax.el.ValueExpression _el_ve"); + out.print(i); + out.print(" = _el_variablemapper.setVariable("); + out.print(quote(attrName)); + out.print(','); + if (attrInfos[i].isDeferredMethod()) { + out.print(VAR_EXPRESSIONFACTORY); + out.print(".createValueExpression("); + out.print(toGetterMethod(attrName)); + out.print(",javax.el.MethodExpression.class)"); + } else { + out.print(toGetterMethod(attrName)); + } + out.println(");"); + } else { + out.printil("if( " + toGetterMethod(attrName) + " != null ) "); + out.pushIndent(); + out.printin("_jspx_page_context.setAttribute("); + out.print(quote(attrName)); + out.print(", "); + out.print(toGetterMethod(attrName)); + out.println(");"); + out.popIndent(); + } + } + + // Expose the Map containing dynamic attributes as a page-scoped var + if (tagInfo.hasDynamicAttributes()) { + out.printin("_jspx_page_context.setAttribute(\""); + out.print(tagInfo.getDynamicAttributesMapName()); + out.print("\", _jspx_dynamic_attrs);"); + } + } + + /* + * Generates the getter method for the given attribute name. + */ + private String toGetterMethod(String attrName) { + char[] attrChars = attrName.toCharArray(); + attrChars[0] = Character.toUpperCase(attrChars[0]); + return "get" + new String(attrChars) + "()"; + } + + /* + * Generates the setter method name for the given attribute name. + */ + private String toSetterMethodName(String attrName) { + char[] attrChars = attrName.toCharArray(); + attrChars[0] = Character.toUpperCase(attrChars[0]); + return "set" + new String(attrChars); + } + + /** + * Class storing the result of introspecting a custom tag handler. + */ + private static class TagHandlerInfo { + + private Hashtable methodMaps; + + private Hashtable propertyEditorMaps; + + private Class tagHandlerClass; + + /** + * Constructor. + * + * @param n + * The custom tag whose tag handler class is to be + * introspected + * @param tagHandlerClass + * Tag handler class + * @param err + * Error dispatcher + */ + TagHandlerInfo(Node n, Class tagHandlerClass, ErrorDispatcher err) + throws JasperException { + this.tagHandlerClass = tagHandlerClass; + this.methodMaps = new Hashtable(); + this.propertyEditorMaps = new Hashtable(); + + try { + BeanInfo tagClassInfo = Introspector + .getBeanInfo(tagHandlerClass); + PropertyDescriptor[] pd = tagClassInfo.getPropertyDescriptors(); + for (int i = 0; i < pd.length; i++) { + /* + * FIXME: should probably be checking for things like + * pageContext, bodyContent, and parent here -akv + */ + if (pd[i].getWriteMethod() != null) { + methodMaps.put(pd[i].getName(), pd[i].getWriteMethod()); + } + if (pd[i].getPropertyEditorClass() != null) + propertyEditorMaps.put(pd[i].getName(), pd[i] + .getPropertyEditorClass()); + } + } catch (IntrospectionException ie) { + err.jspError(n, "jsp.error.introspect.taghandler", + tagHandlerClass.getName(), ie); + } + } + + /** + * XXX + */ + public Method getSetterMethod(String attrName) { + return (Method) methodMaps.get(attrName); + } + + /** + * XXX + */ + public Class getPropertyEditorClass(String attrName) { + return (Class) propertyEditorMaps.get(attrName); + } + + /** + * XXX + */ + public Class getTagHandlerClass() { + return tagHandlerClass; + } + } + + /** + * A class for generating codes to a buffer. Included here are some support + * for tracking source to Java lines mapping. + */ + private static class GenBuffer { + + /* + * For a CustomTag, the codes that are generated at the beginning of the + * tag may not be in the same buffer as those for the body of the tag. + * Two fields are used here to keep this straight. For codes that do not + * corresponds to any JSP lines, they should be null. + */ + private Node node; + + private Node.Nodes body; + + private java.io.CharArrayWriter charWriter; + + protected ServletWriter out; + + GenBuffer() { + this(null, null); + } + + GenBuffer(Node n, Node.Nodes b) { + node = n; + body = b; + if (body != null) { + body.setGeneratedInBuffer(true); + } + charWriter = new java.io.CharArrayWriter(); + out = new ServletWriter(new java.io.PrintWriter(charWriter)); + } + + public ServletWriter getOut() { + return out; + } + + public String toString() { + return charWriter.toString(); + } + + /** + * Adjust the Java Lines. This is necessary because the Java lines + * stored with the nodes are relative the beginning of this buffer and + * need to be adjusted when this buffer is inserted into the source. + */ + public void adjustJavaLines(final int offset) { + + if (node != null) { + adjustJavaLine(node, offset); + } + + if (body != null) { + try { + body.visit(new Node.Visitor() { + + public void doVisit(Node n) { + adjustJavaLine(n, offset); + } + + public void visit(Node.CustomTag n) + throws JasperException { + Node.Nodes b = n.getBody(); + if (b != null && !b.isGeneratedInBuffer()) { + // Don't adjust lines for the nested tags that + // are also generated in buffers, because the + // adjustments will be done elsewhere. + b.visit(this); + } + } + }); + } catch (JasperException ex) { + } + } + } + + private static void adjustJavaLine(Node n, int offset) { + if (n.getBeginJavaLine() > 0) { + n.setBeginJavaLine(n.getBeginJavaLine() + offset); + n.setEndJavaLine(n.getEndJavaLine() + offset); + } + } + } + + /** + * Keeps track of the generated Fragment Helper Class + */ + private static class FragmentHelperClass { + + private static class Fragment { + private GenBuffer genBuffer; + + private int id; + + public Fragment(int id, Node node) { + this.id = id; + genBuffer = new GenBuffer(null, node.getBody()); + } + + public GenBuffer getGenBuffer() { + return this.genBuffer; + } + + public int getId() { + return this.id; + } + } + + // True if the helper class should be generated. + private boolean used = false; + + private ArrayList fragments = new ArrayList(); + + private String className; + + // Buffer for entire helper class + private GenBuffer classBuffer = new GenBuffer(); + + public FragmentHelperClass(String className) { + this.className = className; + } + + public String getClassName() { + return this.className; + } + + public boolean isUsed() { + return this.used; + } + + public void generatePreamble() { + ServletWriter out = this.classBuffer.getOut(); + out.println(); + out.pushIndent(); + // Note: cannot be static, as we need to reference things like + // _jspx_meth_* + out.printil("private class " + className); + out.printil(" extends " + + "org.apache.jasper.runtime.JspFragmentHelper"); + out.printil("{"); + out.pushIndent(); + out + .printil("private javax.servlet.jsp.tagext.JspTag _jspx_parent;"); + out.printil("private int[] _jspx_push_body_count;"); + out.println(); + out.printil("public " + className + + "( int discriminator, JspContext jspContext, " + + "javax.servlet.jsp.tagext.JspTag _jspx_parent, " + + "int[] _jspx_push_body_count ) {"); + out.pushIndent(); + out.printil("super( discriminator, jspContext, _jspx_parent );"); + out.printil("this._jspx_parent = _jspx_parent;"); + out.printil("this._jspx_push_body_count = _jspx_push_body_count;"); + out.popIndent(); + out.printil("}"); + } + + public Fragment openFragment(Node parent, String tagHandlerVar, + int methodNesting) throws JasperException { + Fragment result = new Fragment(fragments.size(), parent); + fragments.add(result); + this.used = true; + parent.setInnerClassName(className); + + ServletWriter out = result.getGenBuffer().getOut(); + out.pushIndent(); + out.pushIndent(); + // XXX - Returns boolean because if a tag is invoked from + // within this fragment, the Generator sometimes might + // generate code like "return true". This is ignored for now, + // meaning only the fragment is skipped. The JSR-152 + // expert group is currently discussing what to do in this case. + // See comment in closeFragment() + if (methodNesting > 0) { + out.printin("public boolean invoke"); + } else { + out.printin("public void invoke"); + } + out.println(result.getId() + "( " + "JspWriter out ) "); + out.pushIndent(); + // Note: Throwable required because methods like _jspx_meth_* + // throw Throwable. + out.printil("throws Throwable"); + out.popIndent(); + out.printil("{"); + out.pushIndent(); + generateLocalVariables(out, parent); + + return result; + } + + public void closeFragment(Fragment fragment, int methodNesting) { + ServletWriter out = fragment.getGenBuffer().getOut(); + // XXX - See comment in openFragment() + if (methodNesting > 0) { + out.printil("return false;"); + } else { + out.printil("return;"); + } + out.popIndent(); + out.printil("}"); + } + + public void generatePostamble() { + ServletWriter out = this.classBuffer.getOut(); + // Generate all fragment methods: + for (int i = 0; i < fragments.size(); i++) { + Fragment fragment = (Fragment) fragments.get(i); + fragment.getGenBuffer().adjustJavaLines(out.getJavaLine() - 1); + out.printMultiLn(fragment.getGenBuffer().toString()); + } + + // Generate postamble: + out.printil("public void invoke( java.io.Writer writer )"); + out.pushIndent(); + out.printil("throws JspException"); + out.popIndent(); + out.printil("{"); + out.pushIndent(); + out.printil("JspWriter out = null;"); + out.printil("if( writer != null ) {"); + out.pushIndent(); + out.printil("out = this.jspContext.pushBody(writer);"); + out.popIndent(); + out.printil("} else {"); + out.pushIndent(); + out.printil("out = this.jspContext.getOut();"); + out.popIndent(); + out.printil("}"); + out.printil("try {"); + out.pushIndent(); + out.printil("switch( this.discriminator ) {"); + out.pushIndent(); + for (int i = 0; i < fragments.size(); i++) { + out.printil("case " + i + ":"); + out.pushIndent(); + out.printil("invoke" + i + "( out );"); + out.printil("break;"); + out.popIndent(); + } + out.popIndent(); + out.printil("}"); // switch + out.popIndent(); + out.printil("}"); // try + out.printil("catch( Throwable e ) {"); + out.pushIndent(); + out.printil("if (e instanceof SkipPageException)"); + out.printil(" throw (SkipPageException) e;"); + out.printil("throw new JspException( e );"); + out.popIndent(); + out.printil("}"); // catch + out.printil("finally {"); + out.pushIndent(); + + out.printil("if( writer != null ) {"); + out.pushIndent(); + out.printil("this.jspContext.popBody();"); + out.popIndent(); + out.printil("}"); + + out.popIndent(); + out.printil("}"); // finally + out.popIndent(); + out.printil("}"); // invoke method + out.popIndent(); + out.printil("}"); // helper class + out.popIndent(); + } + + public String toString() { + return classBuffer.toString(); + } + + public void adjustJavaLines(int offset) { + for (int i = 0; i < fragments.size(); i++) { + Fragment fragment = (Fragment) fragments.get(i); + fragment.getGenBuffer().adjustJavaLines(offset); + } + } + } +} diff --git a/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java b/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java index 8bc4fac39..9707c1cee 100644 --- a/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java +++ b/java/org/apache/jasper/compiler/ImplicitTagLibraryInfo.java @@ -1,141 +1,141 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.*; -import javax.servlet.jsp.tagext.FunctionInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagFileInfo; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.JasperException; - -/** - * Class responsible for generating an implicit tag library containing tag - * handlers corresponding to the tag files in "/WEB-INF/tags/" or a - * subdirectory of it. - * - * @author Jan Luehe - */ -class ImplicitTagLibraryInfo extends TagLibraryInfo { - - private static final String WEB_INF_TAGS = "/WEB-INF/tags"; - private static final String TAG_FILE_SUFFIX = ".tag"; - private static final String TAGX_FILE_SUFFIX = ".tagx"; - private static final String TAGS_SHORTNAME = "tags"; - private static final String TLIB_VERSION = "1.0"; - private static final String JSP_VERSION = "2.0"; - - // Maps tag names to tag file paths - private Hashtable tagFileMap; - - private ParserController pc; - private Vector vec; - - /** - * Constructor. - */ - public ImplicitTagLibraryInfo(JspCompilationContext ctxt, - ParserController pc, - String prefix, - String tagdir, - ErrorDispatcher err) throws JasperException { - super(prefix, null); - this.pc = pc; - this.tagFileMap = new Hashtable(); - this.vec = new Vector(); - - // Implicit tag libraries have no functions: - this.functions = new FunctionInfo[0]; - - tlibversion = TLIB_VERSION; - jspversion = JSP_VERSION; - - if (!tagdir.startsWith(WEB_INF_TAGS)) { - err.jspError("jsp.error.invalid.tagdir", tagdir); - } - - // Determine the value of the subelement of the - // "imaginary" element - if (tagdir.equals(WEB_INF_TAGS) - || tagdir.equals( WEB_INF_TAGS + "/")) { - shortname = TAGS_SHORTNAME; - } else { - shortname = tagdir.substring(WEB_INF_TAGS.length()); - shortname = shortname.replace('/', '-'); - } - - // Populate mapping of tag names to tag file paths - Set dirList = ctxt.getResourcePaths(tagdir); - if (dirList != null) { - Iterator it = dirList.iterator(); - while (it.hasNext()) { - String path = (String) it.next(); - if (path.endsWith(TAG_FILE_SUFFIX) - || path.endsWith(TAGX_FILE_SUFFIX)) { - /* - * Use the filename of the tag file, without the .tag or - * .tagx extension, respectively, as the subelement - * of the "imaginary" element - */ - String suffix = path.endsWith(TAG_FILE_SUFFIX) ? - TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX; - String tagName = path.substring(path.lastIndexOf("/") + 1); - tagName = tagName.substring(0, - tagName.lastIndexOf(suffix)); - tagFileMap.put(tagName, path); - } - } - } - } - - /** - * Checks to see if the given tag name maps to a tag file path, - * and if so, parses the corresponding tag file. - * - * @return The TagFileInfo corresponding to the given tag name, or null if - * the given tag name is not implemented as a tag file - */ - public TagFileInfo getTagFile(String shortName) { - - TagFileInfo tagFile = super.getTagFile(shortName); - if (tagFile == null) { - String path = (String) tagFileMap.get(shortName); - if (path == null) { - return null; - } - - TagInfo tagInfo = null; - try { - tagInfo = TagFileProcessor.parseTagFileDirectives(pc, - shortName, - path, - this); - } catch (JasperException je) { - throw new RuntimeException(je.toString(), je); - } - - tagFile = new TagFileInfo(shortName, path, tagInfo); - vec.addElement(tagFile); - - this.tagFiles = new TagFileInfo[vec.size()]; - vec.copyInto(this.tagFiles); - } - - return tagFile; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.*; +import javax.servlet.jsp.tagext.FunctionInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagFileInfo; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.JasperException; + +/** + * Class responsible for generating an implicit tag library containing tag + * handlers corresponding to the tag files in "/WEB-INF/tags/" or a + * subdirectory of it. + * + * @author Jan Luehe + */ +class ImplicitTagLibraryInfo extends TagLibraryInfo { + + private static final String WEB_INF_TAGS = "/WEB-INF/tags"; + private static final String TAG_FILE_SUFFIX = ".tag"; + private static final String TAGX_FILE_SUFFIX = ".tagx"; + private static final String TAGS_SHORTNAME = "tags"; + private static final String TLIB_VERSION = "1.0"; + private static final String JSP_VERSION = "2.0"; + + // Maps tag names to tag file paths + private Hashtable tagFileMap; + + private ParserController pc; + private Vector vec; + + /** + * Constructor. + */ + public ImplicitTagLibraryInfo(JspCompilationContext ctxt, + ParserController pc, + String prefix, + String tagdir, + ErrorDispatcher err) throws JasperException { + super(prefix, null); + this.pc = pc; + this.tagFileMap = new Hashtable(); + this.vec = new Vector(); + + // Implicit tag libraries have no functions: + this.functions = new FunctionInfo[0]; + + tlibversion = TLIB_VERSION; + jspversion = JSP_VERSION; + + if (!tagdir.startsWith(WEB_INF_TAGS)) { + err.jspError("jsp.error.invalid.tagdir", tagdir); + } + + // Determine the value of the subelement of the + // "imaginary" element + if (tagdir.equals(WEB_INF_TAGS) + || tagdir.equals( WEB_INF_TAGS + "/")) { + shortname = TAGS_SHORTNAME; + } else { + shortname = tagdir.substring(WEB_INF_TAGS.length()); + shortname = shortname.replace('/', '-'); + } + + // Populate mapping of tag names to tag file paths + Set dirList = ctxt.getResourcePaths(tagdir); + if (dirList != null) { + Iterator it = dirList.iterator(); + while (it.hasNext()) { + String path = (String) it.next(); + if (path.endsWith(TAG_FILE_SUFFIX) + || path.endsWith(TAGX_FILE_SUFFIX)) { + /* + * Use the filename of the tag file, without the .tag or + * .tagx extension, respectively, as the subelement + * of the "imaginary" element + */ + String suffix = path.endsWith(TAG_FILE_SUFFIX) ? + TAG_FILE_SUFFIX : TAGX_FILE_SUFFIX; + String tagName = path.substring(path.lastIndexOf("/") + 1); + tagName = tagName.substring(0, + tagName.lastIndexOf(suffix)); + tagFileMap.put(tagName, path); + } + } + } + } + + /** + * Checks to see if the given tag name maps to a tag file path, + * and if so, parses the corresponding tag file. + * + * @return The TagFileInfo corresponding to the given tag name, or null if + * the given tag name is not implemented as a tag file + */ + public TagFileInfo getTagFile(String shortName) { + + TagFileInfo tagFile = super.getTagFile(shortName); + if (tagFile == null) { + String path = (String) tagFileMap.get(shortName); + if (path == null) { + return null; + } + + TagInfo tagInfo = null; + try { + tagInfo = TagFileProcessor.parseTagFileDirectives(pc, + shortName, + path, + this); + } catch (JasperException je) { + throw new RuntimeException(je.toString(), je); + } + + tagFile = new TagFileInfo(shortName, path, tagInfo); + vec.addElement(tagFile); + + this.tagFiles = new TagFileInfo[vec.size()]; + vec.copyInto(this.tagFiles); + } + + return tagFile; + } +} diff --git a/java/org/apache/jasper/compiler/JDTCompiler.java b/java/org/apache/jasper/compiler/JDTCompiler.java index e93ee919f..ce5f0ff96 100644 --- a/java/org/apache/jasper/compiler/JDTCompiler.java +++ b/java/org/apache/jasper/compiler/JDTCompiler.java @@ -1,435 +1,435 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.BufferedOutputStream; -import java.io.BufferedReader; -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.StringTokenizer; - -import org.apache.jasper.JasperException; -import org.eclipse.jdt.core.compiler.IProblem; -import org.eclipse.jdt.internal.compiler.ClassFile; -import org.eclipse.jdt.internal.compiler.CompilationResult; -import org.eclipse.jdt.internal.compiler.Compiler; -import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; -import org.eclipse.jdt.internal.compiler.ICompilerRequestor; -import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; -import org.eclipse.jdt.internal.compiler.IProblemFactory; -import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; -import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; -import org.eclipse.jdt.internal.compiler.env.INameEnvironment; -import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; -import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; -import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; - -/** - * JDT class compiler. This compiler will load source dependencies from the - * context classloader, reducing dramatically disk access during - * the compilation process. - * - * @author Cocoon2 - * @author Remy Maucherat - */ -public class JDTCompiler extends org.apache.jasper.compiler.Compiler { - - - /** - * Compile the servlet from .java file to .class file - */ - protected void generateClass(String[] smap) - throws FileNotFoundException, JasperException, Exception { - - long t1 = 0; - if (log.isDebugEnabled()) { - t1 = System.currentTimeMillis(); - } - - final String sourceFile = ctxt.getServletJavaFileName(); - final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath(); - String packageName = ctxt.getServletPackageName(); - final String targetClassName = - ((packageName.length() != 0) ? (packageName + ".") : "") - + ctxt.getServletClassName(); - final ClassLoader classLoader = ctxt.getJspLoader(); - String[] fileNames = new String[] {sourceFile}; - String[] classNames = new String[] {targetClassName}; - final ArrayList problemList = new ArrayList(); - - class CompilationUnit implements ICompilationUnit { - - String className; - String sourceFile; - - CompilationUnit(String sourceFile, String className) { - this.className = className; - this.sourceFile = sourceFile; - } - - public char[] getFileName() { - return sourceFile.toCharArray(); - } - - public char[] getContents() { - char[] result = null; - try { - InputStreamReader isReader = - new InputStreamReader(new FileInputStream(sourceFile), - ctxt.getOptions().getJavaEncoding()); - Reader reader = new BufferedReader(isReader); - if (reader != null) { - char[] chars = new char[8192]; - StringBuffer buf = new StringBuffer(); - int count; - while ((count = reader.read(chars, 0, - chars.length)) > 0) { - buf.append(chars, 0, count); - } - result = new char[buf.length()]; - buf.getChars(0, result.length, result, 0); - } - } catch (IOException e) { - log.error("Compilation error", e); - } - return result; - } - - public char[] getMainTypeName() { - int dot = className.lastIndexOf('.'); - if (dot > 0) { - return className.substring(dot + 1).toCharArray(); - } - return className.toCharArray(); - } - - public char[][] getPackageName() { - StringTokenizer izer = - new StringTokenizer(className, "."); - char[][] result = new char[izer.countTokens()-1][]; - for (int i = 0; i < result.length; i++) { - String tok = izer.nextToken(); - result[i] = tok.toCharArray(); - } - return result; - } - } - - final INameEnvironment env = new INameEnvironment() { - - public NameEnvironmentAnswer - findType(char[][] compoundTypeName) { - String result = ""; - String sep = ""; - for (int i = 0; i < compoundTypeName.length; i++) { - result += sep; - result += new String(compoundTypeName[i]); - sep = "."; - } - return findType(result); - } - - public NameEnvironmentAnswer - findType(char[] typeName, - char[][] packageName) { - String result = ""; - String sep = ""; - for (int i = 0; i < packageName.length; i++) { - result += sep; - result += new String(packageName[i]); - sep = "."; - } - result += sep; - result += new String(typeName); - return findType(result); - } - - private NameEnvironmentAnswer findType(String className) { - - InputStream is = null; - try { - if (className.equals(targetClassName)) { - ICompilationUnit compilationUnit = - new CompilationUnit(sourceFile, className); - return - new NameEnvironmentAnswer(compilationUnit, null); - } - String resourceName = - className.replace('.', '/') + ".class"; - is = classLoader.getResourceAsStream(resourceName); - if (is != null) { - byte[] classBytes; - byte[] buf = new byte[8192]; - ByteArrayOutputStream baos = - new ByteArrayOutputStream(buf.length); - int count; - while ((count = is.read(buf, 0, buf.length)) > 0) { - baos.write(buf, 0, count); - } - baos.flush(); - classBytes = baos.toByteArray(); - char[] fileName = className.toCharArray(); - ClassFileReader classFileReader = - new ClassFileReader(classBytes, fileName, - true); - return - new NameEnvironmentAnswer(classFileReader, null); - } - } catch (IOException exc) { - log.error("Compilation error", exc); - } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) { - log.error("Compilation error", exc); - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException exc) { - // Ignore - } - } - } - return null; - } - - private boolean isPackage(String result) { - if (result.equals(targetClassName)) { - return false; - } - String resourceName = result.replace('.', '/') + ".class"; - InputStream is = - classLoader.getResourceAsStream(resourceName); - return is == null; - } - - public boolean isPackage(char[][] parentPackageName, - char[] packageName) { - String result = ""; - String sep = ""; - if (parentPackageName != null) { - for (int i = 0; i < parentPackageName.length; i++) { - result += sep; - String str = new String(parentPackageName[i]); - result += str; - sep = "."; - } - } - String str = new String(packageName); - if (Character.isUpperCase(str.charAt(0))) { - if (!isPackage(result)) { - return false; - } - } - result += sep; - result += str; - return isPackage(result); - } - - public void cleanup() { - } - - }; - - final IErrorHandlingPolicy policy = - DefaultErrorHandlingPolicies.proceedWithAllProblems(); - - final Map settings = new HashMap(); - settings.put(CompilerOptions.OPTION_LineNumberAttribute, - CompilerOptions.GENERATE); - settings.put(CompilerOptions.OPTION_SourceFileAttribute, - CompilerOptions.GENERATE); - settings.put(CompilerOptions.OPTION_ReportDeprecation, - CompilerOptions.IGNORE); - if (ctxt.getOptions().getJavaEncoding() != null) { - settings.put(CompilerOptions.OPTION_Encoding, - ctxt.getOptions().getJavaEncoding()); - } - if (ctxt.getOptions().getClassDebugInfo()) { - settings.put(CompilerOptions.OPTION_LocalVariableAttribute, - CompilerOptions.GENERATE); - } - - // Source JVM - if(ctxt.getOptions().getCompilerSourceVM() != null) { - String opt = ctxt.getOptions().getCompilerSourceVM(); - if(opt.equals("1.1")) { - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_1); - } else if(opt.equals("1.2")) { - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_2); - } else if(opt.equals("1.3")) { - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_3); - } else if(opt.equals("1.4")) { - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_4); - } else if(opt.equals("1.5")) { - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_5); - } else { - log.warn("Unknown source VM " + opt + " ignored."); - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_5); - } - } else { - // Default to 1.5 - settings.put(CompilerOptions.OPTION_Source, - CompilerOptions.VERSION_1_5); - } - - // Target JVM - if(ctxt.getOptions().getCompilerTargetVM() != null) { - String opt = ctxt.getOptions().getCompilerTargetVM(); - if(opt.equals("1.1")) { - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_1); - } else if(opt.equals("1.2")) { - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_2); - } else if(opt.equals("1.3")) { - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_3); - } else if(opt.equals("1.4")) { - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_4); - } else if(opt.equals("1.5")) { - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_5); - settings.put(CompilerOptions.OPTION_Compliance, - CompilerOptions.VERSION_1_5); - } else { - log.warn("Unknown target VM " + opt + " ignored."); - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_5); - } - } else { - // Default to 1.5 - settings.put(CompilerOptions.OPTION_TargetPlatform, - CompilerOptions.VERSION_1_5); - settings.put(CompilerOptions.OPTION_Compliance, - CompilerOptions.VERSION_1_5); - } - - final IProblemFactory problemFactory = - new DefaultProblemFactory(Locale.getDefault()); - - final ICompilerRequestor requestor = new ICompilerRequestor() { - public void acceptResult(CompilationResult result) { - try { - if (result.hasProblems()) { - IProblem[] problems = result.getProblems(); - for (int i = 0; i < problems.length; i++) { - IProblem problem = problems[i]; - if (problem.isError()) { - String name = - new String(problems[i].getOriginatingFileName()); - try { - problemList.add(ErrorDispatcher.createJavacError - (name, pageNodes, new StringBuffer(problem.getMessage()), - problem.getSourceLineNumber())); - } catch (JasperException e) { - log.error("Error visiting node", e); - } - } - } - } - if (problemList.isEmpty()) { - ClassFile[] classFiles = result.getClassFiles(); - for (int i = 0; i < classFiles.length; i++) { - ClassFile classFile = classFiles[i]; - char[][] compoundName = - classFile.getCompoundName(); - String className = ""; - String sep = ""; - for (int j = 0; - j < compoundName.length; j++) { - className += sep; - className += new String(compoundName[j]); - sep = "."; - } - byte[] bytes = classFile.getBytes(); - String outFile = outputDir + "/" + - className.replace('.', '/') + ".class"; - FileOutputStream fout = - new FileOutputStream(outFile); - BufferedOutputStream bos = - new BufferedOutputStream(fout); - bos.write(bytes); - bos.close(); - } - } - } catch (IOException exc) { - log.error("Compilation error", exc); - } - } - }; - - ICompilationUnit[] compilationUnits = - new ICompilationUnit[classNames.length]; - for (int i = 0; i < compilationUnits.length; i++) { - String className = classNames[i]; - compilationUnits[i] = new CompilationUnit(fileNames[i], className); - } - Compiler compiler = new Compiler(env, - policy, - settings, - requestor, - problemFactory, - true); - compiler.compile(compilationUnits); - - if (!ctxt.keepGenerated()) { - File javaFile = new File(ctxt.getServletJavaFileName()); - javaFile.delete(); - } - - if (!problemList.isEmpty()) { - JavacErrorDetail[] jeds = - (JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]); - errDispatcher.javacError(jeds); - } - - if( log.isDebugEnabled() ) { - long t2=System.currentTimeMillis(); - log.debug("Compiled " + ctxt.getServletJavaFileName() + " " - + (t2-t1) + "ms"); - } - - if (ctxt.isPrototypeMode()) { - return; - } - - // JSR45 Support - if (! options.isSmapSuppressed()) { - SmapUtil.installSmap(smap); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.StringTokenizer; + +import org.apache.jasper.JasperException; +import org.eclipse.jdt.core.compiler.IProblem; +import org.eclipse.jdt.internal.compiler.ClassFile; +import org.eclipse.jdt.internal.compiler.CompilationResult; +import org.eclipse.jdt.internal.compiler.Compiler; +import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; +import org.eclipse.jdt.internal.compiler.ICompilerRequestor; +import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; +import org.eclipse.jdt.internal.compiler.IProblemFactory; +import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; +import org.eclipse.jdt.internal.compiler.env.ICompilationUnit; +import org.eclipse.jdt.internal.compiler.env.INameEnvironment; +import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer; +import org.eclipse.jdt.internal.compiler.impl.CompilerOptions; +import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory; + +/** + * JDT class compiler. This compiler will load source dependencies from the + * context classloader, reducing dramatically disk access during + * the compilation process. + * + * @author Cocoon2 + * @author Remy Maucherat + */ +public class JDTCompiler extends org.apache.jasper.compiler.Compiler { + + + /** + * Compile the servlet from .java file to .class file + */ + protected void generateClass(String[] smap) + throws FileNotFoundException, JasperException, Exception { + + long t1 = 0; + if (log.isDebugEnabled()) { + t1 = System.currentTimeMillis(); + } + + final String sourceFile = ctxt.getServletJavaFileName(); + final String outputDir = ctxt.getOptions().getScratchDir().getAbsolutePath(); + String packageName = ctxt.getServletPackageName(); + final String targetClassName = + ((packageName.length() != 0) ? (packageName + ".") : "") + + ctxt.getServletClassName(); + final ClassLoader classLoader = ctxt.getJspLoader(); + String[] fileNames = new String[] {sourceFile}; + String[] classNames = new String[] {targetClassName}; + final ArrayList problemList = new ArrayList(); + + class CompilationUnit implements ICompilationUnit { + + String className; + String sourceFile; + + CompilationUnit(String sourceFile, String className) { + this.className = className; + this.sourceFile = sourceFile; + } + + public char[] getFileName() { + return sourceFile.toCharArray(); + } + + public char[] getContents() { + char[] result = null; + try { + InputStreamReader isReader = + new InputStreamReader(new FileInputStream(sourceFile), + ctxt.getOptions().getJavaEncoding()); + Reader reader = new BufferedReader(isReader); + if (reader != null) { + char[] chars = new char[8192]; + StringBuffer buf = new StringBuffer(); + int count; + while ((count = reader.read(chars, 0, + chars.length)) > 0) { + buf.append(chars, 0, count); + } + result = new char[buf.length()]; + buf.getChars(0, result.length, result, 0); + } + } catch (IOException e) { + log.error("Compilation error", e); + } + return result; + } + + public char[] getMainTypeName() { + int dot = className.lastIndexOf('.'); + if (dot > 0) { + return className.substring(dot + 1).toCharArray(); + } + return className.toCharArray(); + } + + public char[][] getPackageName() { + StringTokenizer izer = + new StringTokenizer(className, "."); + char[][] result = new char[izer.countTokens()-1][]; + for (int i = 0; i < result.length; i++) { + String tok = izer.nextToken(); + result[i] = tok.toCharArray(); + } + return result; + } + } + + final INameEnvironment env = new INameEnvironment() { + + public NameEnvironmentAnswer + findType(char[][] compoundTypeName) { + String result = ""; + String sep = ""; + for (int i = 0; i < compoundTypeName.length; i++) { + result += sep; + result += new String(compoundTypeName[i]); + sep = "."; + } + return findType(result); + } + + public NameEnvironmentAnswer + findType(char[] typeName, + char[][] packageName) { + String result = ""; + String sep = ""; + for (int i = 0; i < packageName.length; i++) { + result += sep; + result += new String(packageName[i]); + sep = "."; + } + result += sep; + result += new String(typeName); + return findType(result); + } + + private NameEnvironmentAnswer findType(String className) { + + InputStream is = null; + try { + if (className.equals(targetClassName)) { + ICompilationUnit compilationUnit = + new CompilationUnit(sourceFile, className); + return + new NameEnvironmentAnswer(compilationUnit, null); + } + String resourceName = + className.replace('.', '/') + ".class"; + is = classLoader.getResourceAsStream(resourceName); + if (is != null) { + byte[] classBytes; + byte[] buf = new byte[8192]; + ByteArrayOutputStream baos = + new ByteArrayOutputStream(buf.length); + int count; + while ((count = is.read(buf, 0, buf.length)) > 0) { + baos.write(buf, 0, count); + } + baos.flush(); + classBytes = baos.toByteArray(); + char[] fileName = className.toCharArray(); + ClassFileReader classFileReader = + new ClassFileReader(classBytes, fileName, + true); + return + new NameEnvironmentAnswer(classFileReader, null); + } + } catch (IOException exc) { + log.error("Compilation error", exc); + } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) { + log.error("Compilation error", exc); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException exc) { + // Ignore + } + } + } + return null; + } + + private boolean isPackage(String result) { + if (result.equals(targetClassName)) { + return false; + } + String resourceName = result.replace('.', '/') + ".class"; + InputStream is = + classLoader.getResourceAsStream(resourceName); + return is == null; + } + + public boolean isPackage(char[][] parentPackageName, + char[] packageName) { + String result = ""; + String sep = ""; + if (parentPackageName != null) { + for (int i = 0; i < parentPackageName.length; i++) { + result += sep; + String str = new String(parentPackageName[i]); + result += str; + sep = "."; + } + } + String str = new String(packageName); + if (Character.isUpperCase(str.charAt(0))) { + if (!isPackage(result)) { + return false; + } + } + result += sep; + result += str; + return isPackage(result); + } + + public void cleanup() { + } + + }; + + final IErrorHandlingPolicy policy = + DefaultErrorHandlingPolicies.proceedWithAllProblems(); + + final Map settings = new HashMap(); + settings.put(CompilerOptions.OPTION_LineNumberAttribute, + CompilerOptions.GENERATE); + settings.put(CompilerOptions.OPTION_SourceFileAttribute, + CompilerOptions.GENERATE); + settings.put(CompilerOptions.OPTION_ReportDeprecation, + CompilerOptions.IGNORE); + if (ctxt.getOptions().getJavaEncoding() != null) { + settings.put(CompilerOptions.OPTION_Encoding, + ctxt.getOptions().getJavaEncoding()); + } + if (ctxt.getOptions().getClassDebugInfo()) { + settings.put(CompilerOptions.OPTION_LocalVariableAttribute, + CompilerOptions.GENERATE); + } + + // Source JVM + if(ctxt.getOptions().getCompilerSourceVM() != null) { + String opt = ctxt.getOptions().getCompilerSourceVM(); + if(opt.equals("1.1")) { + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_1); + } else if(opt.equals("1.2")) { + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_2); + } else if(opt.equals("1.3")) { + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_3); + } else if(opt.equals("1.4")) { + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_4); + } else if(opt.equals("1.5")) { + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_5); + } else { + log.warn("Unknown source VM " + opt + " ignored."); + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_5); + } + } else { + // Default to 1.5 + settings.put(CompilerOptions.OPTION_Source, + CompilerOptions.VERSION_1_5); + } + + // Target JVM + if(ctxt.getOptions().getCompilerTargetVM() != null) { + String opt = ctxt.getOptions().getCompilerTargetVM(); + if(opt.equals("1.1")) { + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_1); + } else if(opt.equals("1.2")) { + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_2); + } else if(opt.equals("1.3")) { + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_3); + } else if(opt.equals("1.4")) { + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_4); + } else if(opt.equals("1.5")) { + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_5); + settings.put(CompilerOptions.OPTION_Compliance, + CompilerOptions.VERSION_1_5); + } else { + log.warn("Unknown target VM " + opt + " ignored."); + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_5); + } + } else { + // Default to 1.5 + settings.put(CompilerOptions.OPTION_TargetPlatform, + CompilerOptions.VERSION_1_5); + settings.put(CompilerOptions.OPTION_Compliance, + CompilerOptions.VERSION_1_5); + } + + final IProblemFactory problemFactory = + new DefaultProblemFactory(Locale.getDefault()); + + final ICompilerRequestor requestor = new ICompilerRequestor() { + public void acceptResult(CompilationResult result) { + try { + if (result.hasProblems()) { + IProblem[] problems = result.getProblems(); + for (int i = 0; i < problems.length; i++) { + IProblem problem = problems[i]; + if (problem.isError()) { + String name = + new String(problems[i].getOriginatingFileName()); + try { + problemList.add(ErrorDispatcher.createJavacError + (name, pageNodes, new StringBuffer(problem.getMessage()), + problem.getSourceLineNumber())); + } catch (JasperException e) { + log.error("Error visiting node", e); + } + } + } + } + if (problemList.isEmpty()) { + ClassFile[] classFiles = result.getClassFiles(); + for (int i = 0; i < classFiles.length; i++) { + ClassFile classFile = classFiles[i]; + char[][] compoundName = + classFile.getCompoundName(); + String className = ""; + String sep = ""; + for (int j = 0; + j < compoundName.length; j++) { + className += sep; + className += new String(compoundName[j]); + sep = "."; + } + byte[] bytes = classFile.getBytes(); + String outFile = outputDir + "/" + + className.replace('.', '/') + ".class"; + FileOutputStream fout = + new FileOutputStream(outFile); + BufferedOutputStream bos = + new BufferedOutputStream(fout); + bos.write(bytes); + bos.close(); + } + } + } catch (IOException exc) { + log.error("Compilation error", exc); + } + } + }; + + ICompilationUnit[] compilationUnits = + new ICompilationUnit[classNames.length]; + for (int i = 0; i < compilationUnits.length; i++) { + String className = classNames[i]; + compilationUnits[i] = new CompilationUnit(fileNames[i], className); + } + Compiler compiler = new Compiler(env, + policy, + settings, + requestor, + problemFactory, + true); + compiler.compile(compilationUnits); + + if (!ctxt.keepGenerated()) { + File javaFile = new File(ctxt.getServletJavaFileName()); + javaFile.delete(); + } + + if (!problemList.isEmpty()) { + JavacErrorDetail[] jeds = + (JavacErrorDetail[]) problemList.toArray(new JavacErrorDetail[0]); + errDispatcher.javacError(jeds); + } + + if( log.isDebugEnabled() ) { + long t2=System.currentTimeMillis(); + log.debug("Compiled " + ctxt.getServletJavaFileName() + " " + + (t2-t1) + "ms"); + } + + if (ctxt.isPrototypeMode()) { + return; + } + + // JSR45 Support + if (! options.isSmapSuppressed()) { + SmapUtil.installSmap(smap); + } + + } + + +} diff --git a/java/org/apache/jasper/compiler/JasperTagInfo.java b/java/org/apache/jasper/compiler/JasperTagInfo.java index d322f8d0e..6a671526c 100644 --- a/java/org/apache/jasper/compiler/JasperTagInfo.java +++ b/java/org/apache/jasper/compiler/JasperTagInfo.java @@ -1,57 +1,57 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import javax.servlet.jsp.tagext.*; - -/** - * TagInfo extension used by tag handlers that are implemented via tag files. - * This class provides access to the name of the Map used to store the - * dynamic attribute names and values passed to the custom action invocation. - * This information is used by the code generator. - */ -class JasperTagInfo extends TagInfo { - - private String dynamicAttrsMapName; - - public JasperTagInfo(String tagName, - String tagClassName, - String bodyContent, - String infoString, - TagLibraryInfo taglib, - TagExtraInfo tagExtraInfo, - TagAttributeInfo[] attributeInfo, - String displayName, - String smallIcon, - String largeIcon, - TagVariableInfo[] tvi, - String mapName) { - - super(tagName, tagClassName, bodyContent, infoString, taglib, - tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon, - tvi); - this.dynamicAttrsMapName = mapName; - } - - public String getDynamicAttributesMapName() { - return dynamicAttrsMapName; - } - - public boolean hasDynamicAttributes() { - return dynamicAttrsMapName != null; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import javax.servlet.jsp.tagext.*; + +/** + * TagInfo extension used by tag handlers that are implemented via tag files. + * This class provides access to the name of the Map used to store the + * dynamic attribute names and values passed to the custom action invocation. + * This information is used by the code generator. + */ +class JasperTagInfo extends TagInfo { + + private String dynamicAttrsMapName; + + public JasperTagInfo(String tagName, + String tagClassName, + String bodyContent, + String infoString, + TagLibraryInfo taglib, + TagExtraInfo tagExtraInfo, + TagAttributeInfo[] attributeInfo, + String displayName, + String smallIcon, + String largeIcon, + TagVariableInfo[] tvi, + String mapName) { + + super(tagName, tagClassName, bodyContent, infoString, taglib, + tagExtraInfo, attributeInfo, displayName, smallIcon, largeIcon, + tvi); + this.dynamicAttrsMapName = mapName; + } + + public String getDynamicAttributesMapName() { + return dynamicAttrsMapName; + } + + public boolean hasDynamicAttributes() { + return dynamicAttrsMapName != null; + } +} diff --git a/java/org/apache/jasper/compiler/JavacErrorDetail.java b/java/org/apache/jasper/compiler/JavacErrorDetail.java index 22054d046..bc7bef388 100644 --- a/java/org/apache/jasper/compiler/JavacErrorDetail.java +++ b/java/org/apache/jasper/compiler/JavacErrorDetail.java @@ -1,122 +1,122 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -/** - * Class providing details about a javac compilation error. - * - * @author Jan Luehe - * @author Kin-man Chung - */ -public class JavacErrorDetail { - - private String javaFileName; - private int javaLineNum; - private String jspFileName; - private int jspBeginLineNum; - private StringBuffer errMsg; - - /** - * Constructor. - * - * @param javaFileName The name of the Java file in which the - * compilation error occurred - * @param javaLineNum The compilation error line number - * @param errMsg The compilation error message - */ - public JavacErrorDetail(String javaFileName, - int javaLineNum, - StringBuffer errMsg) { - - this.javaFileName = javaFileName; - this.javaLineNum = javaLineNum; - this.errMsg = errMsg; - this.jspBeginLineNum = -1; - } - - /** - * Constructor. - * - * @param javaFileName The name of the Java file in which the - * compilation error occurred - * @param javaLineNum The compilation error line number - * @param jspFileName The name of the JSP file from which the Java source - * file was generated - * @param jspBeginLineNum The start line number of the JSP element - * responsible for the compilation error - * @param errMsg The compilation error message - */ - public JavacErrorDetail(String javaFileName, - int javaLineNum, - String jspFileName, - int jspBeginLineNum, - StringBuffer errMsg) { - - this(javaFileName, javaLineNum, errMsg); - this.jspFileName = jspFileName; - this.jspBeginLineNum = jspBeginLineNum; - } - - /** - * Gets the name of the Java source file in which the compilation error - * occurred. - * - * @return Java source file name - */ - public String getJavaFileName() { - return this.javaFileName; - } - - /** - * Gets the compilation error line number. - * - * @return Compilation error line number - */ - public int getJavaLineNumber() { - return this.javaLineNum; - } - - /** - * Gets the name of the JSP file from which the Java source file was - * generated. - * - * @return JSP file from which the Java source file was generated. - */ - public String getJspFileName() { - return this.jspFileName; - } - - /** - * Gets the start line number (in the JSP file) of the JSP element - * responsible for the compilation error. - * - * @return Start line number of the JSP element responsible for the - * compilation error - */ - public int getJspBeginLineNumber() { - return this.jspBeginLineNum; - } - - /** - * Gets the compilation error message. - * - * @return Compilation error message - */ - public String getErrorMessage() { - return this.errMsg.toString(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +/** + * Class providing details about a javac compilation error. + * + * @author Jan Luehe + * @author Kin-man Chung + */ +public class JavacErrorDetail { + + private String javaFileName; + private int javaLineNum; + private String jspFileName; + private int jspBeginLineNum; + private StringBuffer errMsg; + + /** + * Constructor. + * + * @param javaFileName The name of the Java file in which the + * compilation error occurred + * @param javaLineNum The compilation error line number + * @param errMsg The compilation error message + */ + public JavacErrorDetail(String javaFileName, + int javaLineNum, + StringBuffer errMsg) { + + this.javaFileName = javaFileName; + this.javaLineNum = javaLineNum; + this.errMsg = errMsg; + this.jspBeginLineNum = -1; + } + + /** + * Constructor. + * + * @param javaFileName The name of the Java file in which the + * compilation error occurred + * @param javaLineNum The compilation error line number + * @param jspFileName The name of the JSP file from which the Java source + * file was generated + * @param jspBeginLineNum The start line number of the JSP element + * responsible for the compilation error + * @param errMsg The compilation error message + */ + public JavacErrorDetail(String javaFileName, + int javaLineNum, + String jspFileName, + int jspBeginLineNum, + StringBuffer errMsg) { + + this(javaFileName, javaLineNum, errMsg); + this.jspFileName = jspFileName; + this.jspBeginLineNum = jspBeginLineNum; + } + + /** + * Gets the name of the Java source file in which the compilation error + * occurred. + * + * @return Java source file name + */ + public String getJavaFileName() { + return this.javaFileName; + } + + /** + * Gets the compilation error line number. + * + * @return Compilation error line number + */ + public int getJavaLineNumber() { + return this.javaLineNum; + } + + /** + * Gets the name of the JSP file from which the Java source file was + * generated. + * + * @return JSP file from which the Java source file was generated. + */ + public String getJspFileName() { + return this.jspFileName; + } + + /** + * Gets the start line number (in the JSP file) of the JSP element + * responsible for the compilation error. + * + * @return Start line number of the JSP element responsible for the + * compilation error + */ + public int getJspBeginLineNumber() { + return this.jspBeginLineNum; + } + + /** + * Gets the compilation error message. + * + * @return Compilation error message + */ + public String getErrorMessage() { + return this.errMsg.toString(); + } +} diff --git a/java/org/apache/jasper/compiler/JspConfig.java b/java/org/apache/jasper/compiler/JspConfig.java index dc7d72d88..c31e9e67b 100644 --- a/java/org/apache/jasper/compiler/JspConfig.java +++ b/java/org/apache/jasper/compiler/JspConfig.java @@ -1,484 +1,484 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.InputStream; -import java.util.Iterator; -import java.util.Vector; -import java.net.URL; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.JasperException; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.jasper.xmlparser.TreeNode; -import org.xml.sax.InputSource; - -/** - * Handles the jsp-config element in WEB_INF/web.xml. This is used - * for specifying the JSP configuration information on a JSP page - * - * @author Kin-man Chung - */ - -public class JspConfig { - - private static final String WEB_XML = "/WEB-INF/web.xml"; - - // Logger - private Log log = LogFactory.getLog(JspConfig.class); - - private Vector jspProperties = null; - private ServletContext ctxt; - private boolean initialized = false; - - private String defaultIsXml = null; // unspecified - private String defaultIsELIgnored = null; // unspecified - private String defaultIsScriptingInvalid = "false"; - private JspProperty defaultJspProperty; - - public JspConfig(ServletContext ctxt) { - this.ctxt = ctxt; - } - - private double getVersion(TreeNode webApp) { - if (webApp == null) { - String v = webApp.findAttribute("version"); - if (v != null) { - try { - return Double.parseDouble(v); - } catch (Exception e) {} - } - } - return 2.4; - } - - private void processWebDotXml(ServletContext ctxt) throws JasperException { - - InputStream is = null; - - try { - URL uri = ctxt.getResource(WEB_XML); - if (uri == null) { - // no web.xml - return; - } - - is = uri.openStream(); - InputSource ip = new InputSource(is); - ip.setSystemId(uri.toExternalForm()); - - ParserUtils pu = new ParserUtils(); - TreeNode webApp = pu.parseXMLDocument(WEB_XML, ip); - - if (webApp == null - || getVersion(webApp) < 2.4) { - defaultIsELIgnored = "true"; - return; - } - TreeNode jspConfig = webApp.findChild("jsp-config"); - if (jspConfig == null) { - return; - } - - jspProperties = new Vector(); - Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group"); - while (jspPropertyList.hasNext()) { - - TreeNode element = (TreeNode) jspPropertyList.next(); - Iterator list = element.findChildren(); - - Vector urlPatterns = new Vector(); - String pageEncoding = null; - String scriptingInvalid = null; - String elIgnored = null; - String isXml = null; - Vector includePrelude = new Vector(); - Vector includeCoda = new Vector(); - - while (list.hasNext()) { - - element = (TreeNode) list.next(); - String tname = element.getName(); - - if ("url-pattern".equals(tname)) - urlPatterns.addElement( element.getBody() ); - else if ("page-encoding".equals(tname)) - pageEncoding = element.getBody(); - else if ("is-xml".equals(tname)) - isXml = element.getBody(); - else if ("el-ignored".equals(tname)) - elIgnored = element.getBody(); - else if ("scripting-invalid".equals(tname)) - scriptingInvalid = element.getBody(); - else if ("include-prelude".equals(tname)) - includePrelude.addElement(element.getBody()); - else if ("include-coda".equals(tname)) - includeCoda.addElement(element.getBody()); - } - - if (urlPatterns.size() == 0) { - continue; - } - - // Add one JspPropertyGroup for each URL Pattern. This makes - // the matching logic easier. - for( int p = 0; p < urlPatterns.size(); p++ ) { - String urlPattern = (String)urlPatterns.elementAt( p ); - String path = null; - String extension = null; - - if (urlPattern.indexOf('*') < 0) { - // Exact match - path = urlPattern; - } else { - int i = urlPattern.lastIndexOf('/'); - String file; - if (i >= 0) { - path = urlPattern.substring(0,i+1); - file = urlPattern.substring(i+1); - } else { - file = urlPattern; - } - - // pattern must be "*", or of the form "*.jsp" - if (file.equals("*")) { - extension = "*"; - } else if (file.startsWith("*.")) { - extension = file.substring(file.indexOf('.')+1); - } - - // The url patterns are reconstructed as the follwoing: - // path != null, extension == null: / or /foo/bar.ext - // path == null, extension != null: *.ext - // path != null, extension == "*": /foo/* - boolean isStar = "*".equals(extension); - if ((path == null && (extension == null || isStar)) - || (path != null && !isStar)) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.bad.urlpattern.propertygroup", - urlPattern)); - } - continue; - } - } - - JspProperty property = new JspProperty(isXml, - elIgnored, - scriptingInvalid, - pageEncoding, - includePrelude, - includeCoda); - JspPropertyGroup propertyGroup = - new JspPropertyGroup(path, extension, property); - - jspProperties.addElement(propertyGroup); - } - } - } catch (Exception ex) { - throw new JasperException(ex); - } finally { - if (is != null) { - try { - is.close(); - } catch (Throwable t) {} - } - } - } - - private void init() throws JasperException { - - if (!initialized) { - processWebDotXml(ctxt); - defaultJspProperty = new JspProperty(defaultIsXml, - defaultIsELIgnored, - defaultIsScriptingInvalid, - null, null, null); - initialized = true; - } - } - - /** - * Select the property group that has more restrictive url-pattern. - * In case of tie, select the first. - */ - private JspPropertyGroup selectProperty(JspPropertyGroup prev, - JspPropertyGroup curr) { - if (prev == null) { - return curr; - } - if (prev.getExtension() == null) { - // exact match - return prev; - } - if (curr.getExtension() == null) { - // exact match - return curr; - } - String prevPath = prev.getPath(); - String currPath = curr.getPath(); - if (prevPath == null && currPath == null) { - // Both specifies a *.ext, keep the first one - return prev; - } - if (prevPath == null && currPath != null) { - return curr; - } - if (prevPath != null && currPath == null) { - return prev; - } - if (prevPath.length() >= currPath.length()) { - return prev; - } - return curr; - } - - - /** - * Find a property that best matches the supplied resource. - * @param uri the resource supplied. - * @return a JspProperty indicating the best match, or some default. - */ - public JspProperty findJspProperty(String uri) throws JasperException { - - init(); - - // JSP Configuration settings do not apply to tag files - if (jspProperties == null || uri.endsWith(".tag") - || uri.endsWith(".tagx")) { - return defaultJspProperty; - } - - String uriPath = null; - int index = uri.lastIndexOf('/'); - if (index >=0 ) { - uriPath = uri.substring(0, index+1); - } - String uriExtension = null; - index = uri.lastIndexOf('.'); - if (index >=0) { - uriExtension = uri.substring(index+1); - } - - Vector includePreludes = new Vector(); - Vector includeCodas = new Vector(); - - JspPropertyGroup isXmlMatch = null; - JspPropertyGroup elIgnoredMatch = null; - JspPropertyGroup scriptingInvalidMatch = null; - JspPropertyGroup pageEncodingMatch = null; - - Iterator iter = jspProperties.iterator(); - while (iter.hasNext()) { - - JspPropertyGroup jpg = (JspPropertyGroup) iter.next(); - JspProperty jp = jpg.getJspProperty(); - - // (arrays will be the same length) - String extension = jpg.getExtension(); - String path = jpg.getPath(); - - if (extension == null) { - // exact match pattern: /a/foo.jsp - if (!uri.equals(path)) { - // not matched; - continue; - } - } else { - // Matching patterns *.ext or /p/* - if (path != null && uriPath != null && - ! uriPath.startsWith(path)) { - // not matched - continue; - } - if (!extension.equals("*") && - !extension.equals(uriExtension)) { - // not matched - continue; - } - } - // We have a match - // Add include-preludes and include-codas - if (jp.getIncludePrelude() != null) { - includePreludes.addAll(jp.getIncludePrelude()); - } - if (jp.getIncludeCoda() != null) { - includeCodas.addAll(jp.getIncludeCoda()); - } - - // If there is a previous match for the same property, remember - // the one that is more restrictive. - if (jp.isXml() != null) { - isXmlMatch = selectProperty(isXmlMatch, jpg); - } - if (jp.isELIgnored() != null) { - elIgnoredMatch = selectProperty(elIgnoredMatch, jpg); - } - if (jp.isScriptingInvalid() != null) { - scriptingInvalidMatch = - selectProperty(scriptingInvalidMatch, jpg); - } - if (jp.getPageEncoding() != null) { - pageEncodingMatch = selectProperty(pageEncodingMatch, jpg); - } - } - - - String isXml = defaultIsXml; - String isELIgnored = defaultIsELIgnored; - String isScriptingInvalid = defaultIsScriptingInvalid; - String pageEncoding = null; - - if (isXmlMatch != null) { - isXml = isXmlMatch.getJspProperty().isXml(); - } - if (elIgnoredMatch != null) { - isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored(); - } - if (scriptingInvalidMatch != null) { - isScriptingInvalid = - scriptingInvalidMatch.getJspProperty().isScriptingInvalid(); - } - if (pageEncodingMatch != null) { - pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding(); - } - - return new JspProperty(isXml, isELIgnored, isScriptingInvalid, - pageEncoding, includePreludes, includeCodas); - } - - /** - * To find out if an uri matches an url pattern in jsp config. If so, - * then the uri is a JSP page. This is used primarily for jspc. - */ - public boolean isJspPage(String uri) throws JasperException { - - init(); - if (jspProperties == null) { - return false; - } - - String uriPath = null; - int index = uri.lastIndexOf('/'); - if (index >=0 ) { - uriPath = uri.substring(0, index+1); - } - String uriExtension = null; - index = uri.lastIndexOf('.'); - if (index >=0) { - uriExtension = uri.substring(index+1); - } - - Iterator iter = jspProperties.iterator(); - while (iter.hasNext()) { - - JspPropertyGroup jpg = (JspPropertyGroup) iter.next(); - JspProperty jp = jpg.getJspProperty(); - - String extension = jpg.getExtension(); - String path = jpg.getPath(); - - if (extension == null) { - if (uri.equals(path)) { - // There is an exact match - return true; - } - } else { - if ((path == null || path.equals(uriPath)) && - (extension.equals("*") || extension.equals(uriExtension))) { - // Matches *, *.ext, /p/*, or /p/*.ext - return true; - } - } - } - return false; - } - - static class JspPropertyGroup { - private String path; - private String extension; - private JspProperty jspProperty; - - JspPropertyGroup(String path, String extension, - JspProperty jspProperty) { - this.path = path; - this.extension = extension; - this.jspProperty = jspProperty; - } - - public String getPath() { - return path; - } - - public String getExtension() { - return extension; - } - - public JspProperty getJspProperty() { - return jspProperty; - } - } - - static public class JspProperty { - - private String isXml; - private String elIgnored; - private String scriptingInvalid; - private String pageEncoding; - private Vector includePrelude; - private Vector includeCoda; - - public JspProperty(String isXml, String elIgnored, - String scriptingInvalid, String pageEncoding, - Vector includePrelude, Vector includeCoda) { - - this.isXml = isXml; - this.elIgnored = elIgnored; - this.scriptingInvalid = scriptingInvalid; - this.pageEncoding = pageEncoding; - this.includePrelude = includePrelude; - this.includeCoda = includeCoda; - } - - public String isXml() { - return isXml; - } - - public String isELIgnored() { - return elIgnored; - } - - public String isScriptingInvalid() { - return scriptingInvalid; - } - - public String getPageEncoding() { - return pageEncoding; - } - - public Vector getIncludePrelude() { - return includePrelude; - } - - public Vector getIncludeCoda() { - return includeCoda; - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.InputStream; +import java.util.Iterator; +import java.util.Vector; +import java.net.URL; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.JasperException; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.jasper.xmlparser.TreeNode; +import org.xml.sax.InputSource; + +/** + * Handles the jsp-config element in WEB_INF/web.xml. This is used + * for specifying the JSP configuration information on a JSP page + * + * @author Kin-man Chung + */ + +public class JspConfig { + + private static final String WEB_XML = "/WEB-INF/web.xml"; + + // Logger + private Log log = LogFactory.getLog(JspConfig.class); + + private Vector jspProperties = null; + private ServletContext ctxt; + private boolean initialized = false; + + private String defaultIsXml = null; // unspecified + private String defaultIsELIgnored = null; // unspecified + private String defaultIsScriptingInvalid = "false"; + private JspProperty defaultJspProperty; + + public JspConfig(ServletContext ctxt) { + this.ctxt = ctxt; + } + + private double getVersion(TreeNode webApp) { + if (webApp == null) { + String v = webApp.findAttribute("version"); + if (v != null) { + try { + return Double.parseDouble(v); + } catch (Exception e) {} + } + } + return 2.4; + } + + private void processWebDotXml(ServletContext ctxt) throws JasperException { + + InputStream is = null; + + try { + URL uri = ctxt.getResource(WEB_XML); + if (uri == null) { + // no web.xml + return; + } + + is = uri.openStream(); + InputSource ip = new InputSource(is); + ip.setSystemId(uri.toExternalForm()); + + ParserUtils pu = new ParserUtils(); + TreeNode webApp = pu.parseXMLDocument(WEB_XML, ip); + + if (webApp == null + || getVersion(webApp) < 2.4) { + defaultIsELIgnored = "true"; + return; + } + TreeNode jspConfig = webApp.findChild("jsp-config"); + if (jspConfig == null) { + return; + } + + jspProperties = new Vector(); + Iterator jspPropertyList = jspConfig.findChildren("jsp-property-group"); + while (jspPropertyList.hasNext()) { + + TreeNode element = (TreeNode) jspPropertyList.next(); + Iterator list = element.findChildren(); + + Vector urlPatterns = new Vector(); + String pageEncoding = null; + String scriptingInvalid = null; + String elIgnored = null; + String isXml = null; + Vector includePrelude = new Vector(); + Vector includeCoda = new Vector(); + + while (list.hasNext()) { + + element = (TreeNode) list.next(); + String tname = element.getName(); + + if ("url-pattern".equals(tname)) + urlPatterns.addElement( element.getBody() ); + else if ("page-encoding".equals(tname)) + pageEncoding = element.getBody(); + else if ("is-xml".equals(tname)) + isXml = element.getBody(); + else if ("el-ignored".equals(tname)) + elIgnored = element.getBody(); + else if ("scripting-invalid".equals(tname)) + scriptingInvalid = element.getBody(); + else if ("include-prelude".equals(tname)) + includePrelude.addElement(element.getBody()); + else if ("include-coda".equals(tname)) + includeCoda.addElement(element.getBody()); + } + + if (urlPatterns.size() == 0) { + continue; + } + + // Add one JspPropertyGroup for each URL Pattern. This makes + // the matching logic easier. + for( int p = 0; p < urlPatterns.size(); p++ ) { + String urlPattern = (String)urlPatterns.elementAt( p ); + String path = null; + String extension = null; + + if (urlPattern.indexOf('*') < 0) { + // Exact match + path = urlPattern; + } else { + int i = urlPattern.lastIndexOf('/'); + String file; + if (i >= 0) { + path = urlPattern.substring(0,i+1); + file = urlPattern.substring(i+1); + } else { + file = urlPattern; + } + + // pattern must be "*", or of the form "*.jsp" + if (file.equals("*")) { + extension = "*"; + } else if (file.startsWith("*.")) { + extension = file.substring(file.indexOf('.')+1); + } + + // The url patterns are reconstructed as the follwoing: + // path != null, extension == null: / or /foo/bar.ext + // path == null, extension != null: *.ext + // path != null, extension == "*": /foo/* + boolean isStar = "*".equals(extension); + if ((path == null && (extension == null || isStar)) + || (path != null && !isStar)) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.bad.urlpattern.propertygroup", + urlPattern)); + } + continue; + } + } + + JspProperty property = new JspProperty(isXml, + elIgnored, + scriptingInvalid, + pageEncoding, + includePrelude, + includeCoda); + JspPropertyGroup propertyGroup = + new JspPropertyGroup(path, extension, property); + + jspProperties.addElement(propertyGroup); + } + } + } catch (Exception ex) { + throw new JasperException(ex); + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t) {} + } + } + } + + private void init() throws JasperException { + + if (!initialized) { + processWebDotXml(ctxt); + defaultJspProperty = new JspProperty(defaultIsXml, + defaultIsELIgnored, + defaultIsScriptingInvalid, + null, null, null); + initialized = true; + } + } + + /** + * Select the property group that has more restrictive url-pattern. + * In case of tie, select the first. + */ + private JspPropertyGroup selectProperty(JspPropertyGroup prev, + JspPropertyGroup curr) { + if (prev == null) { + return curr; + } + if (prev.getExtension() == null) { + // exact match + return prev; + } + if (curr.getExtension() == null) { + // exact match + return curr; + } + String prevPath = prev.getPath(); + String currPath = curr.getPath(); + if (prevPath == null && currPath == null) { + // Both specifies a *.ext, keep the first one + return prev; + } + if (prevPath == null && currPath != null) { + return curr; + } + if (prevPath != null && currPath == null) { + return prev; + } + if (prevPath.length() >= currPath.length()) { + return prev; + } + return curr; + } + + + /** + * Find a property that best matches the supplied resource. + * @param uri the resource supplied. + * @return a JspProperty indicating the best match, or some default. + */ + public JspProperty findJspProperty(String uri) throws JasperException { + + init(); + + // JSP Configuration settings do not apply to tag files + if (jspProperties == null || uri.endsWith(".tag") + || uri.endsWith(".tagx")) { + return defaultJspProperty; + } + + String uriPath = null; + int index = uri.lastIndexOf('/'); + if (index >=0 ) { + uriPath = uri.substring(0, index+1); + } + String uriExtension = null; + index = uri.lastIndexOf('.'); + if (index >=0) { + uriExtension = uri.substring(index+1); + } + + Vector includePreludes = new Vector(); + Vector includeCodas = new Vector(); + + JspPropertyGroup isXmlMatch = null; + JspPropertyGroup elIgnoredMatch = null; + JspPropertyGroup scriptingInvalidMatch = null; + JspPropertyGroup pageEncodingMatch = null; + + Iterator iter = jspProperties.iterator(); + while (iter.hasNext()) { + + JspPropertyGroup jpg = (JspPropertyGroup) iter.next(); + JspProperty jp = jpg.getJspProperty(); + + // (arrays will be the same length) + String extension = jpg.getExtension(); + String path = jpg.getPath(); + + if (extension == null) { + // exact match pattern: /a/foo.jsp + if (!uri.equals(path)) { + // not matched; + continue; + } + } else { + // Matching patterns *.ext or /p/* + if (path != null && uriPath != null && + ! uriPath.startsWith(path)) { + // not matched + continue; + } + if (!extension.equals("*") && + !extension.equals(uriExtension)) { + // not matched + continue; + } + } + // We have a match + // Add include-preludes and include-codas + if (jp.getIncludePrelude() != null) { + includePreludes.addAll(jp.getIncludePrelude()); + } + if (jp.getIncludeCoda() != null) { + includeCodas.addAll(jp.getIncludeCoda()); + } + + // If there is a previous match for the same property, remember + // the one that is more restrictive. + if (jp.isXml() != null) { + isXmlMatch = selectProperty(isXmlMatch, jpg); + } + if (jp.isELIgnored() != null) { + elIgnoredMatch = selectProperty(elIgnoredMatch, jpg); + } + if (jp.isScriptingInvalid() != null) { + scriptingInvalidMatch = + selectProperty(scriptingInvalidMatch, jpg); + } + if (jp.getPageEncoding() != null) { + pageEncodingMatch = selectProperty(pageEncodingMatch, jpg); + } + } + + + String isXml = defaultIsXml; + String isELIgnored = defaultIsELIgnored; + String isScriptingInvalid = defaultIsScriptingInvalid; + String pageEncoding = null; + + if (isXmlMatch != null) { + isXml = isXmlMatch.getJspProperty().isXml(); + } + if (elIgnoredMatch != null) { + isELIgnored = elIgnoredMatch.getJspProperty().isELIgnored(); + } + if (scriptingInvalidMatch != null) { + isScriptingInvalid = + scriptingInvalidMatch.getJspProperty().isScriptingInvalid(); + } + if (pageEncodingMatch != null) { + pageEncoding = pageEncodingMatch.getJspProperty().getPageEncoding(); + } + + return new JspProperty(isXml, isELIgnored, isScriptingInvalid, + pageEncoding, includePreludes, includeCodas); + } + + /** + * To find out if an uri matches an url pattern in jsp config. If so, + * then the uri is a JSP page. This is used primarily for jspc. + */ + public boolean isJspPage(String uri) throws JasperException { + + init(); + if (jspProperties == null) { + return false; + } + + String uriPath = null; + int index = uri.lastIndexOf('/'); + if (index >=0 ) { + uriPath = uri.substring(0, index+1); + } + String uriExtension = null; + index = uri.lastIndexOf('.'); + if (index >=0) { + uriExtension = uri.substring(index+1); + } + + Iterator iter = jspProperties.iterator(); + while (iter.hasNext()) { + + JspPropertyGroup jpg = (JspPropertyGroup) iter.next(); + JspProperty jp = jpg.getJspProperty(); + + String extension = jpg.getExtension(); + String path = jpg.getPath(); + + if (extension == null) { + if (uri.equals(path)) { + // There is an exact match + return true; + } + } else { + if ((path == null || path.equals(uriPath)) && + (extension.equals("*") || extension.equals(uriExtension))) { + // Matches *, *.ext, /p/*, or /p/*.ext + return true; + } + } + } + return false; + } + + static class JspPropertyGroup { + private String path; + private String extension; + private JspProperty jspProperty; + + JspPropertyGroup(String path, String extension, + JspProperty jspProperty) { + this.path = path; + this.extension = extension; + this.jspProperty = jspProperty; + } + + public String getPath() { + return path; + } + + public String getExtension() { + return extension; + } + + public JspProperty getJspProperty() { + return jspProperty; + } + } + + static public class JspProperty { + + private String isXml; + private String elIgnored; + private String scriptingInvalid; + private String pageEncoding; + private Vector includePrelude; + private Vector includeCoda; + + public JspProperty(String isXml, String elIgnored, + String scriptingInvalid, String pageEncoding, + Vector includePrelude, Vector includeCoda) { + + this.isXml = isXml; + this.elIgnored = elIgnored; + this.scriptingInvalid = scriptingInvalid; + this.pageEncoding = pageEncoding; + this.includePrelude = includePrelude; + this.includeCoda = includeCoda; + } + + public String isXml() { + return isXml; + } + + public String isELIgnored() { + return elIgnored; + } + + public String isScriptingInvalid() { + return scriptingInvalid; + } + + public String getPageEncoding() { + return pageEncoding; + } + + public Vector getIncludePrelude() { + return includePrelude; + } + + public Vector getIncludeCoda() { + return includeCoda; + } + } +} diff --git a/java/org/apache/jasper/compiler/JspDocumentParser.java b/java/org/apache/jasper/compiler/JspDocumentParser.java index 41a82ef43..ce88fa317 100644 --- a/java/org/apache/jasper/compiler/JspDocumentParser.java +++ b/java/org/apache/jasper/compiler/JspDocumentParser.java @@ -1,1439 +1,1439 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.io.CharArrayWriter; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -import java.util.Iterator; -import java.util.List; -import java.util.jar.JarFile; - -import javax.servlet.jsp.tagext.TagFileInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.xml.sax.Attributes; -import org.xml.sax.InputSource; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.ext.LexicalHandler; -import org.xml.sax.helpers.AttributesImpl; -import org.xml.sax.helpers.DefaultHandler; - -/** - * Class implementing a parser for a JSP document, that is, a JSP page in XML - * syntax. - * - * @author Jan Luehe - * @author Kin-man Chung - */ - -class JspDocumentParser - extends DefaultHandler - implements LexicalHandler, TagConstants { - - private static final String JSP_VERSION = "version"; - private static final String LEXICAL_HANDLER_PROPERTY = - "http://xml.org/sax/properties/lexical-handler"; - private static final String JSP_URI = "http://java.sun.com/JSP/Page"; - - private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION = - new EnableDTDValidationException( - "jsp.error.enable_dtd_validation", - null); - - private ParserController parserController; - private JspCompilationContext ctxt; - private PageInfo pageInfo; - private String path; - private StringBuffer charBuffer; - - // Node representing the XML element currently being parsed - private Node current; - - /* - * Outermost (in the nesting hierarchy) node whose body is declared to be - * scriptless. If a node's body is declared to be scriptless, all its - * nested nodes must be scriptless, too. - */ - private Node scriptlessBodyNode; - - private Locator locator; - - //Mark representing the start of the current element. Note - //that locator.getLineNumber() and locator.getColumnNumber() - //return the line and column numbers for the character - //immediately _following_ the current element. The underlying - //XMl parser eats white space that is not part of character - //data, so for Nodes that are not created from character data, - //this is the best we can do. But when we parse character data, - //we get an accurate starting location by starting with startMark - //as set by the previous element, and updating it as we advance - //through the characters. - private Mark startMark; - - // Flag indicating whether we are inside DTD declarations - private boolean inDTD; - - private boolean isValidating; - - private ErrorDispatcher err; - private boolean isTagFile; - private boolean directivesOnly; - private boolean isTop; - - // Nesting level of Tag dependent bodies - private int tagDependentNesting = 0; - // Flag set to delay incrmenting tagDependentNesting until jsp:body - // is first encountered - private boolean tagDependentPending = false; - - /* - * Constructor - */ - public JspDocumentParser( - ParserController pc, - String path, - boolean isTagFile, - boolean directivesOnly) { - this.parserController = pc; - this.ctxt = pc.getJspCompilationContext(); - this.pageInfo = pc.getCompiler().getPageInfo(); - this.err = pc.getCompiler().getErrorDispatcher(); - this.path = path; - this.isTagFile = isTagFile; - this.directivesOnly = directivesOnly; - this.isTop = true; - } - - /* - * Parses a JSP document by responding to SAX events. - * - * @throws JasperException - */ - public static Node.Nodes parse( - ParserController pc, - String path, - JarFile jarFile, - Node parent, - boolean isTagFile, - boolean directivesOnly, - String pageEnc, - String jspConfigPageEnc, - boolean isEncodingSpecifiedInProlog) - throws JasperException { - - JspDocumentParser jspDocParser = - new JspDocumentParser(pc, path, isTagFile, directivesOnly); - Node.Nodes pageNodes = null; - - try { - - // Create dummy root and initialize it with given page encodings - Node.Root dummyRoot = new Node.Root(null, parent, true); - dummyRoot.setPageEncoding(pageEnc); - dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc); - dummyRoot.setIsEncodingSpecifiedInProlog( - isEncodingSpecifiedInProlog); - jspDocParser.current = dummyRoot; - if (parent == null) { - jspDocParser.addInclude( - dummyRoot, - jspDocParser.pageInfo.getIncludePrelude()); - } else { - jspDocParser.isTop = false; - } - - // Parse the input - SAXParser saxParser = getSAXParser(false, jspDocParser); - InputStream inStream = null; - try { - inStream = JspUtil.getInputStream(path, jarFile, - jspDocParser.ctxt, - jspDocParser.err); - saxParser.parse(new InputSource(inStream), jspDocParser); - } catch (EnableDTDValidationException e) { - saxParser = getSAXParser(true, jspDocParser); - jspDocParser.isValidating = true; - if (inStream != null) { - try { - inStream.close(); - } catch (Exception any) { - } - } - inStream = JspUtil.getInputStream(path, jarFile, - jspDocParser.ctxt, - jspDocParser.err); - saxParser.parse(new InputSource(inStream), jspDocParser); - } finally { - if (inStream != null) { - try { - inStream.close(); - } catch (Exception any) { - } - } - } - - if (parent == null) { - jspDocParser.addInclude( - dummyRoot, - jspDocParser.pageInfo.getIncludeCoda()); - } - - // Create Node.Nodes from dummy root - pageNodes = new Node.Nodes(dummyRoot); - - } catch (IOException ioe) { - jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe); - } catch (SAXParseException e) { - jspDocParser.err.jspError - (new Mark(jspDocParser.ctxt, path, e.getLineNumber(), - e.getColumnNumber()), - e.getMessage()); - } catch (Exception e) { - jspDocParser.err.jspError(e); - } - - return pageNodes; - } - - /* - * Processes the given list of included files. - * - * This is used to implement the include-prelude and include-coda - * subelements of the jsp-config element in web.xml - */ - private void addInclude(Node parent, List files) throws SAXException { - if (files != null) { - Iterator iter = files.iterator(); - while (iter.hasNext()) { - String file = (String)iter.next(); - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute("", "file", "file", "CDATA", file); - - // Create a dummy Include directive node - Node includeDir = - new Node.IncludeDirective(attrs, null, // XXX - parent); - processIncludeDirective(file, includeDir); - } - } - } - - /* - * Receives notification of the start of an element. - * - * This method assigns the given tag attributes to one of 3 buckets: - * - * - "xmlns" attributes that represent (standard or custom) tag libraries. - * - "xmlns" attributes that do not represent tag libraries. - * - all remaining attributes. - * - * For each "xmlns" attribute that represents a custom tag library, the - * corresponding TagLibraryInfo object is added to the set of custom - * tag libraries. - */ - public void startElement( - String uri, - String localName, - String qName, - Attributes attrs) - throws SAXException { - - AttributesImpl taglibAttrs = null; - AttributesImpl nonTaglibAttrs = null; - AttributesImpl nonTaglibXmlnsAttrs = null; - - processChars(); - - checkPrefixes(uri, qName, attrs); - - if (directivesOnly && - !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) { - return; - } - - // jsp:text must not have any subelements - if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) { - throw new SAXParseException( - Localizer.getMessage("jsp.error.text.has_subelement"), - locator); - } - - startMark = new Mark(ctxt, path, locator.getLineNumber(), - locator.getColumnNumber()); - - if (attrs != null) { - /* - * Notice that due to a bug in the underlying SAX parser, the - * attributes must be enumerated in descending order. - */ - boolean isTaglib = false; - for (int i = attrs.getLength() - 1; i >= 0; i--) { - isTaglib = false; - String attrQName = attrs.getQName(i); - if (!attrQName.startsWith("xmlns")) { - if (nonTaglibAttrs == null) { - nonTaglibAttrs = new AttributesImpl(); - } - nonTaglibAttrs.addAttribute( - attrs.getURI(i), - attrs.getLocalName(i), - attrs.getQName(i), - attrs.getType(i), - attrs.getValue(i)); - } else { - if (attrQName.startsWith("xmlns:jsp")) { - isTaglib = true; - } else { - String attrUri = attrs.getValue(i); - // TaglibInfo for this uri already established in - // startPrefixMapping - isTaglib = pageInfo.hasTaglib(attrUri); - } - if (isTaglib) { - if (taglibAttrs == null) { - taglibAttrs = new AttributesImpl(); - } - taglibAttrs.addAttribute( - attrs.getURI(i), - attrs.getLocalName(i), - attrs.getQName(i), - attrs.getType(i), - attrs.getValue(i)); - } else { - if (nonTaglibXmlnsAttrs == null) { - nonTaglibXmlnsAttrs = new AttributesImpl(); - } - nonTaglibXmlnsAttrs.addAttribute( - attrs.getURI(i), - attrs.getLocalName(i), - attrs.getQName(i), - attrs.getType(i), - attrs.getValue(i)); - } - } - } - } - - Node node = null; - - if (tagDependentPending && JSP_URI.equals(uri) && - localName.equals(BODY_ACTION)) { - tagDependentPending = false; - tagDependentNesting++; - current = - parseStandardAction( - qName, - localName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - return; - } - - if (tagDependentPending && JSP_URI.equals(uri) && - localName.equals(ATTRIBUTE_ACTION)) { - current = - parseStandardAction( - qName, - localName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - return; - } - - if (tagDependentPending) { - tagDependentPending = false; - tagDependentNesting++; - } - - if (tagDependentNesting > 0) { - node = - new Node.UninterpretedTag( - qName, - localName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - } else if (JSP_URI.equals(uri)) { - node = - parseStandardAction( - qName, - localName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - } else { - node = - parseCustomAction( - qName, - localName, - uri, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - if (node == null) { - node = - new Node.UninterpretedTag( - qName, - localName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - startMark, - current); - } else { - // custom action - String bodyType = getBodyType((Node.CustomTag) node); - - if (scriptlessBodyNode == null - && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) { - scriptlessBodyNode = node; - } - else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) { - tagDependentPending = true; - } - } - } - - current = node; - } - - /* - * Receives notification of character data inside an element. - * - * The SAX does not call this method with all of the template text, but may - * invoke this method with chunks of it. This is a problem when we try - * to determine if the text contains only whitespaces, or when we are - * looking for an EL expression string. Therefore it is necessary to - * buffer and concatenate the chunks and process the concatenated text - * later (at beginTag and endTag) - * - * @param buf The characters - * @param offset The start position in the character array - * @param len The number of characters to use from the character array - * - * @throws SAXException - */ - public void characters(char[] buf, int offset, int len) { - - if (charBuffer == null) { - charBuffer = new StringBuffer(); - } - charBuffer.append(buf, offset, len); - } - - private void processChars() throws SAXException { - - if (charBuffer == null || directivesOnly) { - return; - } - - /* - * JSP.6.1.1: All textual nodes that have only white space are to be - * dropped from the document, except for nodes in a jsp:text element, - * and any leading and trailing white-space-only textual nodes in a - * jsp:attribute whose 'trim' attribute is set to FALSE, which are to - * be kept verbatim. - * JSP.6.2.3 defines white space characters. - */ - boolean isAllSpace = true; - if (!(current instanceof Node.JspText) - && !(current instanceof Node.NamedAttribute)) { - for (int i = 0; i < charBuffer.length(); i++) { - if (!(charBuffer.charAt(i) == ' ' - || charBuffer.charAt(i) == '\n' - || charBuffer.charAt(i) == '\r' - || charBuffer.charAt(i) == '\t')) { - isAllSpace = false; - break; - } - } - } - - if (!isAllSpace && tagDependentPending) { - tagDependentPending = false; - tagDependentNesting++; - } - - if (tagDependentNesting > 0) { - if (charBuffer.length() > 0) { - new Node.TemplateText(charBuffer.toString(), startMark, current); - } - startMark = new Mark(ctxt, path, locator.getLineNumber(), - locator.getColumnNumber()); - charBuffer = null; - return; - } - - if ((current instanceof Node.JspText) - || (current instanceof Node.NamedAttribute) - || !isAllSpace) { - - int line = startMark.getLineNumber(); - int column = startMark.getColumnNumber(); - - CharArrayWriter ttext = new CharArrayWriter(); - int lastCh = 0, elType = 0; - for (int i = 0; i < charBuffer.length(); i++) { - - int ch = charBuffer.charAt(i); - if (ch == '\n') { - column = 1; - line++; - } else { - column++; - } - if ((lastCh == '$' || lastCh == '#') && ch == '{') { - elType = lastCh; - if (ttext.size() > 0) { - new Node.TemplateText( - ttext.toString(), - startMark, - current); - ttext = new CharArrayWriter(); - //We subtract two from the column number to - //account for the '[$,#]{' that we've already parsed - startMark = new Mark(ctxt, path, line, column - 2); - } - // following "${" || "#{" to first unquoted "}" - i++; - boolean singleQ = false; - boolean doubleQ = false; - lastCh = 0; - for (;; i++) { - if (i >= charBuffer.length()) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.unterminated", - (char) elType + "{"), - locator); - - } - ch = charBuffer.charAt(i); - if (ch == '\n') { - column = 1; - line++; - } else { - column++; - } - if (lastCh == '\\' && (singleQ || doubleQ)) { - ttext.write(ch); - lastCh = 0; - continue; - } - if (ch == '}') { - new Node.ELExpression((char) elType, - ttext.toString(), - startMark, - current); - ttext = new CharArrayWriter(); - startMark = new Mark(ctxt, path, line, column); - break; - } - if (ch == '"') - doubleQ = !doubleQ; - else if (ch == '\'') - singleQ = !singleQ; - - ttext.write(ch); - lastCh = ch; - } - } else if (lastCh == '\\' && (ch == '$' || ch == '#')) { - ttext.write(ch); - ch = 0; // Not start of EL anymore - } else { - if (lastCh == '$' || lastCh == '#' || lastCh == '\\') { - ttext.write(lastCh); - } - if (ch != '$' && ch != '#' && ch != '\\') { - ttext.write(ch); - } - } - lastCh = ch; - } - if (lastCh == '$' || lastCh == '#' || lastCh == '\\') { - ttext.write(lastCh); - } - if (ttext.size() > 0) { - new Node.TemplateText(ttext.toString(), startMark, current); - } - } - startMark = new Mark(ctxt, path, locator.getLineNumber(), - locator.getColumnNumber()); - - charBuffer = null; - } - - /* - * Receives notification of the end of an element. - */ - public void endElement(String uri, String localName, String qName) - throws SAXException { - - processChars(); - - if (directivesOnly && - !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) { - return; - } - - if (current instanceof Node.NamedAttribute) { - boolean isTrim = ((Node.NamedAttribute)current).isTrim(); - Node.Nodes subElems = ((Node.NamedAttribute)current).getBody(); - for (int i = 0; subElems != null && i < subElems.size(); i++) { - Node subElem = subElems.getNode(i); - if (!(subElem instanceof Node.TemplateText)) { - continue; - } - // Ignore any whitespace (including spaces, carriage returns, - // line feeds, and tabs, that appear at the beginning and at - // the end of the body of the action, if the - // action's 'trim' attribute is set to TRUE (default). - // In addition, any textual nodes in the that - // have only white space are dropped from the document, with - // the exception of leading and trailing white-space-only - // textual nodes in a whose 'trim' attribute - // is set to FALSE, which must be kept verbatim. - if (i == 0) { - if (isTrim) { - ((Node.TemplateText)subElem).ltrim(); - } - } else if (i == subElems.size() - 1) { - if (isTrim) { - ((Node.TemplateText)subElem).rtrim(); - } - } else { - if (((Node.TemplateText)subElem).isAllSpace()) { - subElems.remove(subElem); - } - } - } - } else if (current instanceof Node.ScriptingElement) { - checkScriptingBody((Node.ScriptingElement)current); - } - - if ( isTagDependent(current)) { - tagDependentNesting--; - } - - if (scriptlessBodyNode != null - && current.equals(scriptlessBodyNode)) { - scriptlessBodyNode = null; - } - - if (current.getParent() != null) { - current = current.getParent(); - } - } - - /* - * Receives the document locator. - * - * @param locator the document locator - */ - public void setDocumentLocator(Locator locator) { - this.locator = locator; - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void comment(char[] buf, int offset, int len) throws SAXException { - - processChars(); // Flush char buffer and remove white spaces - - // ignore comments in the DTD - if (!inDTD) { - startMark = - new Mark( - ctxt, - path, - locator.getLineNumber(), - locator.getColumnNumber()); - new Node.Comment(new String(buf, offset, len), startMark, current); - } - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void startCDATA() throws SAXException { - - processChars(); // Flush char buffer and remove white spaces - startMark = new Mark(ctxt, path, locator.getLineNumber(), - locator.getColumnNumber()); - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void endCDATA() throws SAXException { - processChars(); // Flush char buffer and remove white spaces - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void startEntity(String name) throws SAXException { - // do nothing - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void endEntity(String name) throws SAXException { - // do nothing - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void startDTD(String name, String publicId, String systemId) - throws SAXException { - if (!isValidating) { - fatalError(ENABLE_DTD_VALIDATION_EXCEPTION); - } - - inDTD = true; - } - - /* - * See org.xml.sax.ext.LexicalHandler. - */ - public void endDTD() throws SAXException { - inDTD = false; - } - - /* - * Receives notification of a non-recoverable error. - */ - public void fatalError(SAXParseException e) throws SAXException { - throw e; - } - - /* - * Receives notification of a recoverable error. - */ - public void error(SAXParseException e) throws SAXException { - throw e; - } - - /* - * Receives notification of the start of a Namespace mapping. - */ - public void startPrefixMapping(String prefix, String uri) - throws SAXException { - TagLibraryInfo taglibInfo; - - if (directivesOnly && !(JSP_URI.equals(uri))) { - return; - } - - try { - taglibInfo = getTaglibInfo(prefix, uri); - } catch (JasperException je) { - throw new SAXParseException( - Localizer.getMessage("jsp.error.could.not.add.taglibraries"), - locator, - je); - } - - if (taglibInfo != null) { - if (pageInfo.getTaglib(uri) == null) { - pageInfo.addTaglib(uri, taglibInfo); - } - pageInfo.pushPrefixMapping(prefix, uri); - } else { - pageInfo.pushPrefixMapping(prefix, null); - } - } - - /* - * Receives notification of the end of a Namespace mapping. - */ - public void endPrefixMapping(String prefix) throws SAXException { - - if (directivesOnly) { - String uri = pageInfo.getURI(prefix); - if (!JSP_URI.equals(uri)) { - return; - } - } - - pageInfo.popPrefixMapping(prefix); - } - - //********************************************************************* - // Private utility methods - - private Node parseStandardAction( - String qName, - String localName, - Attributes nonTaglibAttrs, - Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, - Mark start, - Node parent) - throws SAXException { - - Node node = null; - - if (localName.equals(ROOT_ACTION)) { - if (!(current instanceof Node.Root)) { - throw new SAXParseException( - Localizer.getMessage("jsp.error.nested_jsproot"), - locator); - } - node = - new Node.JspRoot( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - if (isTop) { - pageInfo.setHasJspRoot(true); - } - } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) { - if (isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.istagfile", - localName), - locator); - } - node = - new Node.PageDirective( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - String imports = nonTaglibAttrs.getValue("import"); - // There can only be one 'import' attribute per page directive - if (imports != null) { - ((Node.PageDirective)node).addImport(imports); - } - } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) { - node = - new Node.IncludeDirective( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - processIncludeDirective(nonTaglibAttrs.getValue("file"), node); - } else if (localName.equals(DECLARATION_ACTION)) { - if (scriptlessBodyNode != null) { - // We're nested inside a node whose body is - // declared to be scriptless - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.no.scriptlets", - localName), - locator); - } - node = - new Node.Declaration( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(SCRIPTLET_ACTION)) { - if (scriptlessBodyNode != null) { - // We're nested inside a node whose body is - // declared to be scriptless - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.no.scriptlets", - localName), - locator); - } - node = - new Node.Scriptlet( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(EXPRESSION_ACTION)) { - if (scriptlessBodyNode != null) { - // We're nested inside a node whose body is - // declared to be scriptless - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.no.scriptlets", - localName), - locator); - } - node = - new Node.Expression( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(USE_BEAN_ACTION)) { - node = - new Node.UseBean( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(SET_PROPERTY_ACTION)) { - node = - new Node.SetProperty( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(GET_PROPERTY_ACTION)) { - node = - new Node.GetProperty( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(INCLUDE_ACTION)) { - node = - new Node.IncludeAction( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(FORWARD_ACTION)) { - node = - new Node.ForwardAction( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(PARAM_ACTION)) { - node = - new Node.ParamAction( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(PARAMS_ACTION)) { - node = - new Node.ParamsAction( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(PLUGIN_ACTION)) { - node = - new Node.PlugIn( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(TEXT_ACTION)) { - node = - new Node.JspText( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(BODY_ACTION)) { - node = - new Node.JspBody( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(ATTRIBUTE_ACTION)) { - node = - new Node.NamedAttribute( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(OUTPUT_ACTION)) { - node = - new Node.JspOutput( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(TAG_DIRECTIVE_ACTION)) { - if (!isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.isnottagfile", - localName), - locator); - } - node = - new Node.TagDirective( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - String imports = nonTaglibAttrs.getValue("import"); - // There can only be one 'import' attribute per tag directive - if (imports != null) { - ((Node.TagDirective)node).addImport(imports); - } - } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) { - if (!isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.isnottagfile", - localName), - locator); - } - node = - new Node.AttributeDirective( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) { - if (!isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.isnottagfile", - localName), - locator); - } - node = - new Node.VariableDirective( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(INVOKE_ACTION)) { - if (!isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.isnottagfile", - localName), - locator); - } - node = - new Node.InvokeAction( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(DOBODY_ACTION)) { - if (!isTagFile) { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.action.isnottagfile", - localName), - locator); - } - node = - new Node.DoBodyAction( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(ELEMENT_ACTION)) { - node = - new Node.JspElement( - qName, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else if (localName.equals(FALLBACK_ACTION)) { - node = - new Node.FallBackAction( - qName, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - current); - } else { - throw new SAXParseException( - Localizer.getMessage( - "jsp.error.xml.badStandardAction", - localName), - locator); - } - - return node; - } - - /* - * Checks if the XML element with the given tag name is a custom action, - * and returns the corresponding Node object. - */ - private Node parseCustomAction( - String qName, - String localName, - String uri, - Attributes nonTaglibAttrs, - Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, - Mark start, - Node parent) - throws SAXException { - - // Check if this is a user-defined (custom) tag - TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri); - if (tagLibInfo == null) { - return null; - } - - TagInfo tagInfo = tagLibInfo.getTag(localName); - TagFileInfo tagFileInfo = tagLibInfo.getTagFile(localName); - if (tagInfo == null && tagFileInfo == null) { - throw new SAXException( - Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri)); - } - Class tagHandlerClass = null; - if (tagInfo != null) { - String handlerClassName = tagInfo.getTagClassName(); - try { - tagHandlerClass = - ctxt.getClassLoader().loadClass(handlerClassName); - } catch (Exception e) { - throw new SAXException( - Localizer.getMessage("jsp.error.loadclass.taghandler", - handlerClassName, - qName), - e); - } - } - - String prefix = ""; - int colon = qName.indexOf(':'); - if (colon != -1) { - prefix = qName.substring(0, colon); - } - - Node.CustomTag ret = null; - if (tagInfo != null) { - ret = - new Node.CustomTag( - qName, - prefix, - localName, - uri, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - parent, - tagInfo, - tagHandlerClass); - } else { - ret = - new Node.CustomTag( - qName, - prefix, - localName, - uri, - nonTaglibAttrs, - nonTaglibXmlnsAttrs, - taglibAttrs, - start, - parent, - tagFileInfo); - } - - return ret; - } - - /* - * Creates the tag library associated with the given uri namespace, and - * returns it. - * - * @param prefix The prefix of the xmlns attribute - * @param uri The uri namespace (value of the xmlns attribute) - * - * @return The tag library associated with the given uri namespace - */ - private TagLibraryInfo getTaglibInfo(String prefix, String uri) - throws JasperException { - - TagLibraryInfo result = null; - - if (uri.startsWith(URN_JSPTAGDIR)) { - // uri (of the form "urn:jsptagdir:path") references tag file dir - String tagdir = uri.substring(URN_JSPTAGDIR.length()); - result = - new ImplicitTagLibraryInfo( - ctxt, - parserController, - prefix, - tagdir, - err); - } else { - // uri references TLD file - boolean isPlainUri = false; - if (uri.startsWith(URN_JSPTLD)) { - // uri is of the form "urn:jsptld:path" - uri = uri.substring(URN_JSPTLD.length()); - } else { - isPlainUri = true; - } - - String[] location = ctxt.getTldLocation(uri); - if (location != null || !isPlainUri) { - if (ctxt.getOptions().isCaching()) { - result = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri); - } - if (result == null) { - /* - * If the uri value is a plain uri, a translation error must - * not be generated if the uri is not found in the taglib map. - * Instead, any actions in the namespace defined by the uri - * value must be treated as uninterpreted. - */ - result = - new TagLibraryInfoImpl( - ctxt, - parserController, - prefix, - uri, - location, - err); - if (ctxt.getOptions().isCaching()) { - ctxt.getOptions().getCache().put(uri, result); - } - } - } - } - - return result; - } - - /* - * Ensures that the given body only contains nodes that are instances of - * TemplateText. - * - * This check is performed only for the body of a scripting (that is: - * declaration, scriptlet, or expression) element, after the end tag of a - * scripting element has been reached. - */ - private void checkScriptingBody(Node.ScriptingElement scriptingElem) - throws SAXException { - Node.Nodes body = scriptingElem.getBody(); - if (body != null) { - int size = body.size(); - for (int i = 0; i < size; i++) { - Node n = body.getNode(i); - if (!(n instanceof Node.TemplateText)) { - String elemType = SCRIPTLET_ACTION; - if (scriptingElem instanceof Node.Declaration) - elemType = DECLARATION_ACTION; - if (scriptingElem instanceof Node.Expression) - elemType = EXPRESSION_ACTION; - String msg = - Localizer.getMessage( - "jsp.error.parse.xml.scripting.invalid.body", - elemType); - throw new SAXException(msg); - } - } - } - } - - /* - * Parses the given file included via an include directive. - * - * @param fname The path to the included resource, as specified by the - * 'file' attribute of the include directive - * @param parent The Node representing the include directive - */ - private void processIncludeDirective(String fname, Node parent) - throws SAXException { - - if (fname == null) { - return; - } - - try { - parserController.parse(fname, parent, null); - } catch (FileNotFoundException fnfe) { - throw new SAXParseException( - Localizer.getMessage("jsp.error.file.not.found", fname), - locator, - fnfe); - } catch (Exception e) { - throw new SAXException(e); - } - } - - /* - * Checks an element's given URI, qname, and attributes to see if any - * of them hijack the 'jsp' prefix, that is, bind it to a namespace other - * than http://java.sun.com/JSP/Page. - * - * @param uri The element's URI - * @param qName The element's qname - * @param attrs The element's attributes - */ - private void checkPrefixes(String uri, String qName, Attributes attrs) { - - checkPrefix(uri, qName); - - int len = attrs.getLength(); - for (int i = 0; i < len; i++) { - checkPrefix(attrs.getURI(i), attrs.getQName(i)); - } - } - - /* - * Checks the given URI and qname to see if they hijack the 'jsp' prefix, - * which would be the case if qName contained the 'jsp' prefix and - * uri was different from http://java.sun.com/JSP/Page. - * - * @param uri The URI to check - * @param qName The qname to check - */ - private void checkPrefix(String uri, String qName) { - - int index = qName.indexOf(':'); - if (index != -1) { - String prefix = qName.substring(0, index); - pageInfo.addPrefix(prefix); - if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) { - pageInfo.setIsJspPrefixHijacked(true); - } - } - } - - /* - * Gets SAXParser. - * - * @param validating Indicates whether the requested SAXParser should - * be validating - * @param jspDocParser The JSP document parser - * - * @return The SAXParser - */ - private static SAXParser getSAXParser( - boolean validating, - JspDocumentParser jspDocParser) - throws Exception { - - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(true); - - // Preserve xmlns attributes - factory.setFeature( - "http://xml.org/sax/features/namespace-prefixes", - true); - factory.setValidating(validating); - //factory.setFeature( - // "http://xml.org/sax/features/validation", - // validating); - - // Configure the parser - SAXParser saxParser = factory.newSAXParser(); - XMLReader xmlReader = saxParser.getXMLReader(); - xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser); - xmlReader.setErrorHandler(jspDocParser); - - return saxParser; - } - - /* - * Exception indicating that a DOCTYPE declaration is present, but - * validation is turned off. - */ - private static class EnableDTDValidationException - extends SAXParseException { - - EnableDTDValidationException(String message, Locator loc) { - super(message, loc); - } - } - - private static String getBodyType(Node.CustomTag custom) { - - if (custom.getTagInfo() != null) { - return custom.getTagInfo().getBodyContent(); - } - - return custom.getTagFileInfo().getTagInfo().getBodyContent(); - } - - private boolean isTagDependent(Node n) { - - if (n instanceof Node.CustomTag) { - String bodyType = getBodyType((Node.CustomTag) n); - return - TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType); - } - return false; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.CharArrayWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; + +import java.util.Iterator; +import java.util.List; +import java.util.jar.JarFile; + +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.ext.LexicalHandler; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Class implementing a parser for a JSP document, that is, a JSP page in XML + * syntax. + * + * @author Jan Luehe + * @author Kin-man Chung + */ + +class JspDocumentParser + extends DefaultHandler + implements LexicalHandler, TagConstants { + + private static final String JSP_VERSION = "version"; + private static final String LEXICAL_HANDLER_PROPERTY = + "http://xml.org/sax/properties/lexical-handler"; + private static final String JSP_URI = "http://java.sun.com/JSP/Page"; + + private static final EnableDTDValidationException ENABLE_DTD_VALIDATION_EXCEPTION = + new EnableDTDValidationException( + "jsp.error.enable_dtd_validation", + null); + + private ParserController parserController; + private JspCompilationContext ctxt; + private PageInfo pageInfo; + private String path; + private StringBuffer charBuffer; + + // Node representing the XML element currently being parsed + private Node current; + + /* + * Outermost (in the nesting hierarchy) node whose body is declared to be + * scriptless. If a node's body is declared to be scriptless, all its + * nested nodes must be scriptless, too. + */ + private Node scriptlessBodyNode; + + private Locator locator; + + //Mark representing the start of the current element. Note + //that locator.getLineNumber() and locator.getColumnNumber() + //return the line and column numbers for the character + //immediately _following_ the current element. The underlying + //XMl parser eats white space that is not part of character + //data, so for Nodes that are not created from character data, + //this is the best we can do. But when we parse character data, + //we get an accurate starting location by starting with startMark + //as set by the previous element, and updating it as we advance + //through the characters. + private Mark startMark; + + // Flag indicating whether we are inside DTD declarations + private boolean inDTD; + + private boolean isValidating; + + private ErrorDispatcher err; + private boolean isTagFile; + private boolean directivesOnly; + private boolean isTop; + + // Nesting level of Tag dependent bodies + private int tagDependentNesting = 0; + // Flag set to delay incrmenting tagDependentNesting until jsp:body + // is first encountered + private boolean tagDependentPending = false; + + /* + * Constructor + */ + public JspDocumentParser( + ParserController pc, + String path, + boolean isTagFile, + boolean directivesOnly) { + this.parserController = pc; + this.ctxt = pc.getJspCompilationContext(); + this.pageInfo = pc.getCompiler().getPageInfo(); + this.err = pc.getCompiler().getErrorDispatcher(); + this.path = path; + this.isTagFile = isTagFile; + this.directivesOnly = directivesOnly; + this.isTop = true; + } + + /* + * Parses a JSP document by responding to SAX events. + * + * @throws JasperException + */ + public static Node.Nodes parse( + ParserController pc, + String path, + JarFile jarFile, + Node parent, + boolean isTagFile, + boolean directivesOnly, + String pageEnc, + String jspConfigPageEnc, + boolean isEncodingSpecifiedInProlog) + throws JasperException { + + JspDocumentParser jspDocParser = + new JspDocumentParser(pc, path, isTagFile, directivesOnly); + Node.Nodes pageNodes = null; + + try { + + // Create dummy root and initialize it with given page encodings + Node.Root dummyRoot = new Node.Root(null, parent, true); + dummyRoot.setPageEncoding(pageEnc); + dummyRoot.setJspConfigPageEncoding(jspConfigPageEnc); + dummyRoot.setIsEncodingSpecifiedInProlog( + isEncodingSpecifiedInProlog); + jspDocParser.current = dummyRoot; + if (parent == null) { + jspDocParser.addInclude( + dummyRoot, + jspDocParser.pageInfo.getIncludePrelude()); + } else { + jspDocParser.isTop = false; + } + + // Parse the input + SAXParser saxParser = getSAXParser(false, jspDocParser); + InputStream inStream = null; + try { + inStream = JspUtil.getInputStream(path, jarFile, + jspDocParser.ctxt, + jspDocParser.err); + saxParser.parse(new InputSource(inStream), jspDocParser); + } catch (EnableDTDValidationException e) { + saxParser = getSAXParser(true, jspDocParser); + jspDocParser.isValidating = true; + if (inStream != null) { + try { + inStream.close(); + } catch (Exception any) { + } + } + inStream = JspUtil.getInputStream(path, jarFile, + jspDocParser.ctxt, + jspDocParser.err); + saxParser.parse(new InputSource(inStream), jspDocParser); + } finally { + if (inStream != null) { + try { + inStream.close(); + } catch (Exception any) { + } + } + } + + if (parent == null) { + jspDocParser.addInclude( + dummyRoot, + jspDocParser.pageInfo.getIncludeCoda()); + } + + // Create Node.Nodes from dummy root + pageNodes = new Node.Nodes(dummyRoot); + + } catch (IOException ioe) { + jspDocParser.err.jspError("jsp.error.data.file.read", path, ioe); + } catch (SAXParseException e) { + jspDocParser.err.jspError + (new Mark(jspDocParser.ctxt, path, e.getLineNumber(), + e.getColumnNumber()), + e.getMessage()); + } catch (Exception e) { + jspDocParser.err.jspError(e); + } + + return pageNodes; + } + + /* + * Processes the given list of included files. + * + * This is used to implement the include-prelude and include-coda + * subelements of the jsp-config element in web.xml + */ + private void addInclude(Node parent, List files) throws SAXException { + if (files != null) { + Iterator iter = files.iterator(); + while (iter.hasNext()) { + String file = (String)iter.next(); + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "file", "file", "CDATA", file); + + // Create a dummy Include directive node + Node includeDir = + new Node.IncludeDirective(attrs, null, // XXX + parent); + processIncludeDirective(file, includeDir); + } + } + } + + /* + * Receives notification of the start of an element. + * + * This method assigns the given tag attributes to one of 3 buckets: + * + * - "xmlns" attributes that represent (standard or custom) tag libraries. + * - "xmlns" attributes that do not represent tag libraries. + * - all remaining attributes. + * + * For each "xmlns" attribute that represents a custom tag library, the + * corresponding TagLibraryInfo object is added to the set of custom + * tag libraries. + */ + public void startElement( + String uri, + String localName, + String qName, + Attributes attrs) + throws SAXException { + + AttributesImpl taglibAttrs = null; + AttributesImpl nonTaglibAttrs = null; + AttributesImpl nonTaglibXmlnsAttrs = null; + + processChars(); + + checkPrefixes(uri, qName, attrs); + + if (directivesOnly && + !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) { + return; + } + + // jsp:text must not have any subelements + if (JSP_URI.equals(uri) && TEXT_ACTION.equals(current.getLocalName())) { + throw new SAXParseException( + Localizer.getMessage("jsp.error.text.has_subelement"), + locator); + } + + startMark = new Mark(ctxt, path, locator.getLineNumber(), + locator.getColumnNumber()); + + if (attrs != null) { + /* + * Notice that due to a bug in the underlying SAX parser, the + * attributes must be enumerated in descending order. + */ + boolean isTaglib = false; + for (int i = attrs.getLength() - 1; i >= 0; i--) { + isTaglib = false; + String attrQName = attrs.getQName(i); + if (!attrQName.startsWith("xmlns")) { + if (nonTaglibAttrs == null) { + nonTaglibAttrs = new AttributesImpl(); + } + nonTaglibAttrs.addAttribute( + attrs.getURI(i), + attrs.getLocalName(i), + attrs.getQName(i), + attrs.getType(i), + attrs.getValue(i)); + } else { + if (attrQName.startsWith("xmlns:jsp")) { + isTaglib = true; + } else { + String attrUri = attrs.getValue(i); + // TaglibInfo for this uri already established in + // startPrefixMapping + isTaglib = pageInfo.hasTaglib(attrUri); + } + if (isTaglib) { + if (taglibAttrs == null) { + taglibAttrs = new AttributesImpl(); + } + taglibAttrs.addAttribute( + attrs.getURI(i), + attrs.getLocalName(i), + attrs.getQName(i), + attrs.getType(i), + attrs.getValue(i)); + } else { + if (nonTaglibXmlnsAttrs == null) { + nonTaglibXmlnsAttrs = new AttributesImpl(); + } + nonTaglibXmlnsAttrs.addAttribute( + attrs.getURI(i), + attrs.getLocalName(i), + attrs.getQName(i), + attrs.getType(i), + attrs.getValue(i)); + } + } + } + } + + Node node = null; + + if (tagDependentPending && JSP_URI.equals(uri) && + localName.equals(BODY_ACTION)) { + tagDependentPending = false; + tagDependentNesting++; + current = + parseStandardAction( + qName, + localName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + return; + } + + if (tagDependentPending && JSP_URI.equals(uri) && + localName.equals(ATTRIBUTE_ACTION)) { + current = + parseStandardAction( + qName, + localName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + return; + } + + if (tagDependentPending) { + tagDependentPending = false; + tagDependentNesting++; + } + + if (tagDependentNesting > 0) { + node = + new Node.UninterpretedTag( + qName, + localName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + } else if (JSP_URI.equals(uri)) { + node = + parseStandardAction( + qName, + localName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + } else { + node = + parseCustomAction( + qName, + localName, + uri, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + if (node == null) { + node = + new Node.UninterpretedTag( + qName, + localName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + startMark, + current); + } else { + // custom action + String bodyType = getBodyType((Node.CustomTag) node); + + if (scriptlessBodyNode == null + && bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) { + scriptlessBodyNode = node; + } + else if (TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType)) { + tagDependentPending = true; + } + } + } + + current = node; + } + + /* + * Receives notification of character data inside an element. + * + * The SAX does not call this method with all of the template text, but may + * invoke this method with chunks of it. This is a problem when we try + * to determine if the text contains only whitespaces, or when we are + * looking for an EL expression string. Therefore it is necessary to + * buffer and concatenate the chunks and process the concatenated text + * later (at beginTag and endTag) + * + * @param buf The characters + * @param offset The start position in the character array + * @param len The number of characters to use from the character array + * + * @throws SAXException + */ + public void characters(char[] buf, int offset, int len) { + + if (charBuffer == null) { + charBuffer = new StringBuffer(); + } + charBuffer.append(buf, offset, len); + } + + private void processChars() throws SAXException { + + if (charBuffer == null || directivesOnly) { + return; + } + + /* + * JSP.6.1.1: All textual nodes that have only white space are to be + * dropped from the document, except for nodes in a jsp:text element, + * and any leading and trailing white-space-only textual nodes in a + * jsp:attribute whose 'trim' attribute is set to FALSE, which are to + * be kept verbatim. + * JSP.6.2.3 defines white space characters. + */ + boolean isAllSpace = true; + if (!(current instanceof Node.JspText) + && !(current instanceof Node.NamedAttribute)) { + for (int i = 0; i < charBuffer.length(); i++) { + if (!(charBuffer.charAt(i) == ' ' + || charBuffer.charAt(i) == '\n' + || charBuffer.charAt(i) == '\r' + || charBuffer.charAt(i) == '\t')) { + isAllSpace = false; + break; + } + } + } + + if (!isAllSpace && tagDependentPending) { + tagDependentPending = false; + tagDependentNesting++; + } + + if (tagDependentNesting > 0) { + if (charBuffer.length() > 0) { + new Node.TemplateText(charBuffer.toString(), startMark, current); + } + startMark = new Mark(ctxt, path, locator.getLineNumber(), + locator.getColumnNumber()); + charBuffer = null; + return; + } + + if ((current instanceof Node.JspText) + || (current instanceof Node.NamedAttribute) + || !isAllSpace) { + + int line = startMark.getLineNumber(); + int column = startMark.getColumnNumber(); + + CharArrayWriter ttext = new CharArrayWriter(); + int lastCh = 0, elType = 0; + for (int i = 0; i < charBuffer.length(); i++) { + + int ch = charBuffer.charAt(i); + if (ch == '\n') { + column = 1; + line++; + } else { + column++; + } + if ((lastCh == '$' || lastCh == '#') && ch == '{') { + elType = lastCh; + if (ttext.size() > 0) { + new Node.TemplateText( + ttext.toString(), + startMark, + current); + ttext = new CharArrayWriter(); + //We subtract two from the column number to + //account for the '[$,#]{' that we've already parsed + startMark = new Mark(ctxt, path, line, column - 2); + } + // following "${" || "#{" to first unquoted "}" + i++; + boolean singleQ = false; + boolean doubleQ = false; + lastCh = 0; + for (;; i++) { + if (i >= charBuffer.length()) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.unterminated", + (char) elType + "{"), + locator); + + } + ch = charBuffer.charAt(i); + if (ch == '\n') { + column = 1; + line++; + } else { + column++; + } + if (lastCh == '\\' && (singleQ || doubleQ)) { + ttext.write(ch); + lastCh = 0; + continue; + } + if (ch == '}') { + new Node.ELExpression((char) elType, + ttext.toString(), + startMark, + current); + ttext = new CharArrayWriter(); + startMark = new Mark(ctxt, path, line, column); + break; + } + if (ch == '"') + doubleQ = !doubleQ; + else if (ch == '\'') + singleQ = !singleQ; + + ttext.write(ch); + lastCh = ch; + } + } else if (lastCh == '\\' && (ch == '$' || ch == '#')) { + ttext.write(ch); + ch = 0; // Not start of EL anymore + } else { + if (lastCh == '$' || lastCh == '#' || lastCh == '\\') { + ttext.write(lastCh); + } + if (ch != '$' && ch != '#' && ch != '\\') { + ttext.write(ch); + } + } + lastCh = ch; + } + if (lastCh == '$' || lastCh == '#' || lastCh == '\\') { + ttext.write(lastCh); + } + if (ttext.size() > 0) { + new Node.TemplateText(ttext.toString(), startMark, current); + } + } + startMark = new Mark(ctxt, path, locator.getLineNumber(), + locator.getColumnNumber()); + + charBuffer = null; + } + + /* + * Receives notification of the end of an element. + */ + public void endElement(String uri, String localName, String qName) + throws SAXException { + + processChars(); + + if (directivesOnly && + !(JSP_URI.equals(uri) && localName.startsWith(DIRECTIVE_ACTION))) { + return; + } + + if (current instanceof Node.NamedAttribute) { + boolean isTrim = ((Node.NamedAttribute)current).isTrim(); + Node.Nodes subElems = ((Node.NamedAttribute)current).getBody(); + for (int i = 0; subElems != null && i < subElems.size(); i++) { + Node subElem = subElems.getNode(i); + if (!(subElem instanceof Node.TemplateText)) { + continue; + } + // Ignore any whitespace (including spaces, carriage returns, + // line feeds, and tabs, that appear at the beginning and at + // the end of the body of the action, if the + // action's 'trim' attribute is set to TRUE (default). + // In addition, any textual nodes in the that + // have only white space are dropped from the document, with + // the exception of leading and trailing white-space-only + // textual nodes in a whose 'trim' attribute + // is set to FALSE, which must be kept verbatim. + if (i == 0) { + if (isTrim) { + ((Node.TemplateText)subElem).ltrim(); + } + } else if (i == subElems.size() - 1) { + if (isTrim) { + ((Node.TemplateText)subElem).rtrim(); + } + } else { + if (((Node.TemplateText)subElem).isAllSpace()) { + subElems.remove(subElem); + } + } + } + } else if (current instanceof Node.ScriptingElement) { + checkScriptingBody((Node.ScriptingElement)current); + } + + if ( isTagDependent(current)) { + tagDependentNesting--; + } + + if (scriptlessBodyNode != null + && current.equals(scriptlessBodyNode)) { + scriptlessBodyNode = null; + } + + if (current.getParent() != null) { + current = current.getParent(); + } + } + + /* + * Receives the document locator. + * + * @param locator the document locator + */ + public void setDocumentLocator(Locator locator) { + this.locator = locator; + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void comment(char[] buf, int offset, int len) throws SAXException { + + processChars(); // Flush char buffer and remove white spaces + + // ignore comments in the DTD + if (!inDTD) { + startMark = + new Mark( + ctxt, + path, + locator.getLineNumber(), + locator.getColumnNumber()); + new Node.Comment(new String(buf, offset, len), startMark, current); + } + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void startCDATA() throws SAXException { + + processChars(); // Flush char buffer and remove white spaces + startMark = new Mark(ctxt, path, locator.getLineNumber(), + locator.getColumnNumber()); + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void endCDATA() throws SAXException { + processChars(); // Flush char buffer and remove white spaces + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void startEntity(String name) throws SAXException { + // do nothing + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void endEntity(String name) throws SAXException { + // do nothing + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void startDTD(String name, String publicId, String systemId) + throws SAXException { + if (!isValidating) { + fatalError(ENABLE_DTD_VALIDATION_EXCEPTION); + } + + inDTD = true; + } + + /* + * See org.xml.sax.ext.LexicalHandler. + */ + public void endDTD() throws SAXException { + inDTD = false; + } + + /* + * Receives notification of a non-recoverable error. + */ + public void fatalError(SAXParseException e) throws SAXException { + throw e; + } + + /* + * Receives notification of a recoverable error. + */ + public void error(SAXParseException e) throws SAXException { + throw e; + } + + /* + * Receives notification of the start of a Namespace mapping. + */ + public void startPrefixMapping(String prefix, String uri) + throws SAXException { + TagLibraryInfo taglibInfo; + + if (directivesOnly && !(JSP_URI.equals(uri))) { + return; + } + + try { + taglibInfo = getTaglibInfo(prefix, uri); + } catch (JasperException je) { + throw new SAXParseException( + Localizer.getMessage("jsp.error.could.not.add.taglibraries"), + locator, + je); + } + + if (taglibInfo != null) { + if (pageInfo.getTaglib(uri) == null) { + pageInfo.addTaglib(uri, taglibInfo); + } + pageInfo.pushPrefixMapping(prefix, uri); + } else { + pageInfo.pushPrefixMapping(prefix, null); + } + } + + /* + * Receives notification of the end of a Namespace mapping. + */ + public void endPrefixMapping(String prefix) throws SAXException { + + if (directivesOnly) { + String uri = pageInfo.getURI(prefix); + if (!JSP_URI.equals(uri)) { + return; + } + } + + pageInfo.popPrefixMapping(prefix); + } + + //********************************************************************* + // Private utility methods + + private Node parseStandardAction( + String qName, + String localName, + Attributes nonTaglibAttrs, + Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, + Mark start, + Node parent) + throws SAXException { + + Node node = null; + + if (localName.equals(ROOT_ACTION)) { + if (!(current instanceof Node.Root)) { + throw new SAXParseException( + Localizer.getMessage("jsp.error.nested_jsproot"), + locator); + } + node = + new Node.JspRoot( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + if (isTop) { + pageInfo.setHasJspRoot(true); + } + } else if (localName.equals(PAGE_DIRECTIVE_ACTION)) { + if (isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.istagfile", + localName), + locator); + } + node = + new Node.PageDirective( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + String imports = nonTaglibAttrs.getValue("import"); + // There can only be one 'import' attribute per page directive + if (imports != null) { + ((Node.PageDirective)node).addImport(imports); + } + } else if (localName.equals(INCLUDE_DIRECTIVE_ACTION)) { + node = + new Node.IncludeDirective( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + processIncludeDirective(nonTaglibAttrs.getValue("file"), node); + } else if (localName.equals(DECLARATION_ACTION)) { + if (scriptlessBodyNode != null) { + // We're nested inside a node whose body is + // declared to be scriptless + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.no.scriptlets", + localName), + locator); + } + node = + new Node.Declaration( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(SCRIPTLET_ACTION)) { + if (scriptlessBodyNode != null) { + // We're nested inside a node whose body is + // declared to be scriptless + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.no.scriptlets", + localName), + locator); + } + node = + new Node.Scriptlet( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(EXPRESSION_ACTION)) { + if (scriptlessBodyNode != null) { + // We're nested inside a node whose body is + // declared to be scriptless + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.no.scriptlets", + localName), + locator); + } + node = + new Node.Expression( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(USE_BEAN_ACTION)) { + node = + new Node.UseBean( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(SET_PROPERTY_ACTION)) { + node = + new Node.SetProperty( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(GET_PROPERTY_ACTION)) { + node = + new Node.GetProperty( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(INCLUDE_ACTION)) { + node = + new Node.IncludeAction( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(FORWARD_ACTION)) { + node = + new Node.ForwardAction( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(PARAM_ACTION)) { + node = + new Node.ParamAction( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(PARAMS_ACTION)) { + node = + new Node.ParamsAction( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(PLUGIN_ACTION)) { + node = + new Node.PlugIn( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(TEXT_ACTION)) { + node = + new Node.JspText( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(BODY_ACTION)) { + node = + new Node.JspBody( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(ATTRIBUTE_ACTION)) { + node = + new Node.NamedAttribute( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(OUTPUT_ACTION)) { + node = + new Node.JspOutput( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(TAG_DIRECTIVE_ACTION)) { + if (!isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.isnottagfile", + localName), + locator); + } + node = + new Node.TagDirective( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + String imports = nonTaglibAttrs.getValue("import"); + // There can only be one 'import' attribute per tag directive + if (imports != null) { + ((Node.TagDirective)node).addImport(imports); + } + } else if (localName.equals(ATTRIBUTE_DIRECTIVE_ACTION)) { + if (!isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.isnottagfile", + localName), + locator); + } + node = + new Node.AttributeDirective( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(VARIABLE_DIRECTIVE_ACTION)) { + if (!isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.isnottagfile", + localName), + locator); + } + node = + new Node.VariableDirective( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(INVOKE_ACTION)) { + if (!isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.isnottagfile", + localName), + locator); + } + node = + new Node.InvokeAction( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(DOBODY_ACTION)) { + if (!isTagFile) { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.action.isnottagfile", + localName), + locator); + } + node = + new Node.DoBodyAction( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(ELEMENT_ACTION)) { + node = + new Node.JspElement( + qName, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else if (localName.equals(FALLBACK_ACTION)) { + node = + new Node.FallBackAction( + qName, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + current); + } else { + throw new SAXParseException( + Localizer.getMessage( + "jsp.error.xml.badStandardAction", + localName), + locator); + } + + return node; + } + + /* + * Checks if the XML element with the given tag name is a custom action, + * and returns the corresponding Node object. + */ + private Node parseCustomAction( + String qName, + String localName, + String uri, + Attributes nonTaglibAttrs, + Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, + Mark start, + Node parent) + throws SAXException { + + // Check if this is a user-defined (custom) tag + TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri); + if (tagLibInfo == null) { + return null; + } + + TagInfo tagInfo = tagLibInfo.getTag(localName); + TagFileInfo tagFileInfo = tagLibInfo.getTagFile(localName); + if (tagInfo == null && tagFileInfo == null) { + throw new SAXException( + Localizer.getMessage("jsp.error.xml.bad_tag", localName, uri)); + } + Class tagHandlerClass = null; + if (tagInfo != null) { + String handlerClassName = tagInfo.getTagClassName(); + try { + tagHandlerClass = + ctxt.getClassLoader().loadClass(handlerClassName); + } catch (Exception e) { + throw new SAXException( + Localizer.getMessage("jsp.error.loadclass.taghandler", + handlerClassName, + qName), + e); + } + } + + String prefix = ""; + int colon = qName.indexOf(':'); + if (colon != -1) { + prefix = qName.substring(0, colon); + } + + Node.CustomTag ret = null; + if (tagInfo != null) { + ret = + new Node.CustomTag( + qName, + prefix, + localName, + uri, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + parent, + tagInfo, + tagHandlerClass); + } else { + ret = + new Node.CustomTag( + qName, + prefix, + localName, + uri, + nonTaglibAttrs, + nonTaglibXmlnsAttrs, + taglibAttrs, + start, + parent, + tagFileInfo); + } + + return ret; + } + + /* + * Creates the tag library associated with the given uri namespace, and + * returns it. + * + * @param prefix The prefix of the xmlns attribute + * @param uri The uri namespace (value of the xmlns attribute) + * + * @return The tag library associated with the given uri namespace + */ + private TagLibraryInfo getTaglibInfo(String prefix, String uri) + throws JasperException { + + TagLibraryInfo result = null; + + if (uri.startsWith(URN_JSPTAGDIR)) { + // uri (of the form "urn:jsptagdir:path") references tag file dir + String tagdir = uri.substring(URN_JSPTAGDIR.length()); + result = + new ImplicitTagLibraryInfo( + ctxt, + parserController, + prefix, + tagdir, + err); + } else { + // uri references TLD file + boolean isPlainUri = false; + if (uri.startsWith(URN_JSPTLD)) { + // uri is of the form "urn:jsptld:path" + uri = uri.substring(URN_JSPTLD.length()); + } else { + isPlainUri = true; + } + + String[] location = ctxt.getTldLocation(uri); + if (location != null || !isPlainUri) { + if (ctxt.getOptions().isCaching()) { + result = (TagLibraryInfoImpl) ctxt.getOptions().getCache().get(uri); + } + if (result == null) { + /* + * If the uri value is a plain uri, a translation error must + * not be generated if the uri is not found in the taglib map. + * Instead, any actions in the namespace defined by the uri + * value must be treated as uninterpreted. + */ + result = + new TagLibraryInfoImpl( + ctxt, + parserController, + prefix, + uri, + location, + err); + if (ctxt.getOptions().isCaching()) { + ctxt.getOptions().getCache().put(uri, result); + } + } + } + } + + return result; + } + + /* + * Ensures that the given body only contains nodes that are instances of + * TemplateText. + * + * This check is performed only for the body of a scripting (that is: + * declaration, scriptlet, or expression) element, after the end tag of a + * scripting element has been reached. + */ + private void checkScriptingBody(Node.ScriptingElement scriptingElem) + throws SAXException { + Node.Nodes body = scriptingElem.getBody(); + if (body != null) { + int size = body.size(); + for (int i = 0; i < size; i++) { + Node n = body.getNode(i); + if (!(n instanceof Node.TemplateText)) { + String elemType = SCRIPTLET_ACTION; + if (scriptingElem instanceof Node.Declaration) + elemType = DECLARATION_ACTION; + if (scriptingElem instanceof Node.Expression) + elemType = EXPRESSION_ACTION; + String msg = + Localizer.getMessage( + "jsp.error.parse.xml.scripting.invalid.body", + elemType); + throw new SAXException(msg); + } + } + } + } + + /* + * Parses the given file included via an include directive. + * + * @param fname The path to the included resource, as specified by the + * 'file' attribute of the include directive + * @param parent The Node representing the include directive + */ + private void processIncludeDirective(String fname, Node parent) + throws SAXException { + + if (fname == null) { + return; + } + + try { + parserController.parse(fname, parent, null); + } catch (FileNotFoundException fnfe) { + throw new SAXParseException( + Localizer.getMessage("jsp.error.file.not.found", fname), + locator, + fnfe); + } catch (Exception e) { + throw new SAXException(e); + } + } + + /* + * Checks an element's given URI, qname, and attributes to see if any + * of them hijack the 'jsp' prefix, that is, bind it to a namespace other + * than http://java.sun.com/JSP/Page. + * + * @param uri The element's URI + * @param qName The element's qname + * @param attrs The element's attributes + */ + private void checkPrefixes(String uri, String qName, Attributes attrs) { + + checkPrefix(uri, qName); + + int len = attrs.getLength(); + for (int i = 0; i < len; i++) { + checkPrefix(attrs.getURI(i), attrs.getQName(i)); + } + } + + /* + * Checks the given URI and qname to see if they hijack the 'jsp' prefix, + * which would be the case if qName contained the 'jsp' prefix and + * uri was different from http://java.sun.com/JSP/Page. + * + * @param uri The URI to check + * @param qName The qname to check + */ + private void checkPrefix(String uri, String qName) { + + int index = qName.indexOf(':'); + if (index != -1) { + String prefix = qName.substring(0, index); + pageInfo.addPrefix(prefix); + if ("jsp".equals(prefix) && !JSP_URI.equals(uri)) { + pageInfo.setIsJspPrefixHijacked(true); + } + } + } + + /* + * Gets SAXParser. + * + * @param validating Indicates whether the requested SAXParser should + * be validating + * @param jspDocParser The JSP document parser + * + * @return The SAXParser + */ + private static SAXParser getSAXParser( + boolean validating, + JspDocumentParser jspDocParser) + throws Exception { + + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + + // Preserve xmlns attributes + factory.setFeature( + "http://xml.org/sax/features/namespace-prefixes", + true); + factory.setValidating(validating); + //factory.setFeature( + // "http://xml.org/sax/features/validation", + // validating); + + // Configure the parser + SAXParser saxParser = factory.newSAXParser(); + XMLReader xmlReader = saxParser.getXMLReader(); + xmlReader.setProperty(LEXICAL_HANDLER_PROPERTY, jspDocParser); + xmlReader.setErrorHandler(jspDocParser); + + return saxParser; + } + + /* + * Exception indicating that a DOCTYPE declaration is present, but + * validation is turned off. + */ + private static class EnableDTDValidationException + extends SAXParseException { + + EnableDTDValidationException(String message, Locator loc) { + super(message, loc); + } + } + + private static String getBodyType(Node.CustomTag custom) { + + if (custom.getTagInfo() != null) { + return custom.getTagInfo().getBodyContent(); + } + + return custom.getTagFileInfo().getTagInfo().getBodyContent(); + } + + private boolean isTagDependent(Node n) { + + if (n instanceof Node.CustomTag) { + String bodyType = getBodyType((Node.CustomTag) n); + return + TagInfo.BODY_CONTENT_TAG_DEPENDENT.equalsIgnoreCase(bodyType); + } + return false; + } +} diff --git a/java/org/apache/jasper/compiler/JspReader.java b/java/org/apache/jasper/compiler/JspReader.java index 7c200addc..324d1977b 100644 --- a/java/org/apache/jasper/compiler/JspReader.java +++ b/java/org/apache/jasper/compiler/JspReader.java @@ -1,656 +1,656 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.CharArrayWriter; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.util.List; -import java.util.Vector; -import java.util.jar.JarFile; -import java.net.URL; -import java.net.MalformedURLException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; - -/** - * JspReader is an input buffer for the JSP parser. It should allow - * unlimited lookahead and pushback. It also has a bunch of parsing - * utility methods for understanding htmlesque thingies. - * - * @author Anil K. Vijendran - * @author Anselm Baird-Smith - * @author Harish Prabandham - * @author Rajiv Mordani - * @author Mandar Raje - * @author Danno Ferrin - * @author Kin-man Chung - * @author Shawn Bayern - * @author Mark Roth - */ - -class JspReader { - - /** - * Logger. - */ - private Log log = LogFactory.getLog(JspReader.class); - - /** - * The current spot in the file. - */ - private Mark current; - - /** - * What is this? - */ - private String master; - - /** - * The list of source files. - */ - private List sourceFiles; - - /** - * The current file ID (-1 indicates an error or no file). - */ - private int currFileId; - - /** - * Seems redundant. - */ - private int size; - - /** - * The compilation context. - */ - private JspCompilationContext context; - - /** - * The Jasper error dispatcher. - */ - private ErrorDispatcher err; - - /** - * Set to true when using the JspReader on a single file where we read up - * to the end and reset to the beginning many times. - * (as in ParserController.figureOutJspDocument()). - */ - private boolean singleFile; - - /** - * Constructor. - * - * @param ctxt The compilation context - * @param fname The file name - * @param encoding The file encoding - * @param jarFile ? - * @param err The error dispatcher - * @throws JasperException If a Jasper-internal error occurs - * @throws FileNotFoundException If the JSP file is not found (or is unreadable) - * @throws IOException If an IO-level error occurs, e.g. reading the file - */ - public JspReader(JspCompilationContext ctxt, - String fname, - String encoding, - JarFile jarFile, - ErrorDispatcher err) - throws JasperException, FileNotFoundException, IOException { - - this(ctxt, fname, encoding, - JspUtil.getReader(fname, encoding, jarFile, ctxt, err), - err); - } - - /** - * Constructor: same as above constructor but with initialized reader - * to the file given. - */ - public JspReader(JspCompilationContext ctxt, - String fname, - String encoding, - InputStreamReader reader, - ErrorDispatcher err) - throws JasperException, FileNotFoundException { - - this.context = ctxt; - this.err = err; - sourceFiles = new Vector(); - currFileId = 0; - size = 0; - singleFile = false; - pushFile(fname, encoding, reader); - } - - /** - * @return JSP compilation context with which this JspReader is - * associated - */ - JspCompilationContext getJspCompilationContext() { - return context; - } - - /** - * Returns the file at the given position in the list. - * - * @param fileid The file position in the list - * @return The file at that position, if found, null otherwise - */ - String getFile(final int fileid) { - return (String) sourceFiles.get(fileid); - } - - /** - * Checks if the current file has more input. - * - * @return True if more reading is possible - * @throws JasperException if an error occurs - */ - boolean hasMoreInput() throws JasperException { - if (current.cursor >= current.stream.length) { - if (singleFile) return false; - while (popFile()) { - if (current.cursor < current.stream.length) return true; - } - return false; - } - return true; - } - - int nextChar() throws JasperException { - if (!hasMoreInput()) - return -1; - - int ch = current.stream[current.cursor]; - - current.cursor++; - - if (ch == '\n') { - current.line++; - current.col = 0; - } else { - current.col++; - } - return ch; - } - - /** - * Back up the current cursor by one char, assumes current.cursor > 0, - * and that the char to be pushed back is not '\n'. - */ - void pushChar() { - current.cursor--; - current.col--; - } - - String getText(Mark start, Mark stop) throws JasperException { - Mark oldstart = mark(); - reset(start); - CharArrayWriter caw = new CharArrayWriter(); - while (!stop.equals(mark())) - caw.write(nextChar()); - caw.close(); - reset(oldstart); - return caw.toString(); - } - - int peekChar() throws JasperException { - if (!hasMoreInput()) - return -1; - return current.stream[current.cursor]; - } - - Mark mark() { - return new Mark(current); - } - - void reset(Mark mark) { - current = new Mark(mark); - } - - boolean matchesIgnoreCase(String string) throws JasperException { - Mark mark = mark(); - int ch = 0; - int i = 0; - do { - ch = nextChar(); - if (Character.toLowerCase((char) ch) != string.charAt(i++)) { - reset(mark); - return false; - } - } while (i < string.length()); - reset(mark); - return true; - } - - /** - * search the stream for a match to a string - * @param string The string to match - * @return true is one is found, the current position - * in stream is positioned after the search string, - * false otherwise, position in stream unchanged. - */ - boolean matches(String string) throws JasperException { - Mark mark = mark(); - int ch = 0; - int i = 0; - do { - ch = nextChar(); - if (((char) ch) != string.charAt(i++)) { - reset(mark); - return false; - } - } while (i < string.length()); - return true; - } - - boolean matchesETag(String tagName) throws JasperException { - Mark mark = mark(); - - if (!matches("') - return true; - - reset(mark); - return false; - } - - boolean matchesETagWithoutLessThan(String tagName) - throws JasperException - { - Mark mark = mark(); - - if (!matches("/" + tagName)) - return false; - skipSpaces(); - if (nextChar() == '>') - return true; - - reset(mark); - return false; - } - - - /** - * Looks ahead to see if there are optional spaces followed by - * the given String. If so, true is returned and those spaces and - * characters are skipped. If not, false is returned and the - * position is restored to where we were before. - */ - boolean matchesOptionalSpacesFollowedBy( String s ) - throws JasperException - { - Mark mark = mark(); - - skipSpaces(); - boolean result = matches( s ); - if( !result ) { - reset( mark ); - } - - return result; - } - - int skipSpaces() throws JasperException { - int i = 0; - while (hasMoreInput() && isSpace()) { - i++; - nextChar(); - } - return i; - } - - /** - * Skip until the given string is matched in the stream. - * When returned, the context is positioned past the end of the match. - * - * @param s The String to match. - * @return A non-null Mark instance (positioned immediately - * before the search string) if found, null - * otherwise. - */ - Mark skipUntil(String limit) throws JasperException { - Mark ret = null; - int limlen = limit.length(); - int ch; - - skip: - for (ret = mark(), ch = nextChar() ; ch != -1 ; - ret = mark(), ch = nextChar()) { - if (ch == limit.charAt(0)) { - Mark restart = mark(); - for (int i = 1 ; i < limlen ; i++) { - if (peekChar() == limit.charAt(i)) - nextChar(); - else { - reset(restart); - continue skip; - } - } - return ret; - } - } - return null; - } - - /** - * Skip until the given string is matched in the stream, but ignoring - * chars initially escaped by a '\'. - * When returned, the context is positioned past the end of the match. - * - * @param s The String to match. - * @return A non-null Mark instance (positioned immediately - * before the search string) if found, null - * otherwise. - */ - Mark skipUntilIgnoreEsc(String limit) throws JasperException { - Mark ret = null; - int limlen = limit.length(); - int ch; - int prev = 'x'; // Doesn't matter - - skip: - for (ret = mark(), ch = nextChar() ; ch != -1 ; - ret = mark(), prev = ch, ch = nextChar()) { - if (ch == '\\' && prev == '\\') { - ch = 0; // Double \ is not an escape char anymore - } - else if (ch == limit.charAt(0) && prev != '\\') { - for (int i = 1 ; i < limlen ; i++) { - if (peekChar() == limit.charAt(i)) - nextChar(); - else - continue skip; - } - return ret; - } - } - return null; - } - - /** - * Skip until the given end tag is matched in the stream. - * When returned, the context is positioned past the end of the tag. - * - * @param tag The name of the tag whose ETag () to match. - * @return A non-null Mark instance (positioned immediately - * before the ETag) if found, null otherwise. - */ - Mark skipUntilETag(String tag) throws JasperException { - Mark ret = skipUntil("') - ret = null; - } - return ret; - } - - final boolean isSpace() throws JasperException { - // Note: If this logic changes, also update Node.TemplateText.rtrim() - return peekChar() <= ' '; - } - - /** - * Parse a space delimited token. - * If quoted the token will consume all characters up to a matching quote, - * otherwise, it consumes up to the first delimiter character. - * - * @param quoted If true accept quoted strings. - */ - String parseToken(boolean quoted) throws JasperException { - StringBuffer stringBuffer = new StringBuffer(); - skipSpaces(); - stringBuffer.setLength(0); - - if (!hasMoreInput()) { - return ""; - } - - int ch = peekChar(); - - if (quoted) { - if (ch == '"' || ch == '\'') { - - char endQuote = ch == '"' ? '"' : '\''; - // Consume the open quote: - ch = nextChar(); - for (ch = nextChar(); ch != -1 && ch != endQuote; - ch = nextChar()) { - if (ch == '\\') - ch = nextChar(); - stringBuffer.append((char) ch); - } - // Check end of quote, skip closing quote: - if (ch == -1) { - err.jspError(mark(), "jsp.error.quotes.unterminated"); - } - } else { - err.jspError(mark(), "jsp.error.attr.quoted"); - } - } else { - if (!isDelimiter()) { - // Read value until delimiter is found: - do { - ch = nextChar(); - // Take care of the quoting here. - if (ch == '\\') { - if (peekChar() == '"' || peekChar() == '\'' || - peekChar() == '>' || peekChar() == '%') - ch = nextChar(); - } - stringBuffer.append((char) ch); - } while (!isDelimiter()); - } - } - - return stringBuffer.toString(); - } - - void setSingleFile(boolean val) { - singleFile = val; - } - - - /** - * Gets the URL for the given path name. - * - * @param path Path name - * - * @return URL for the given path name. - * - * @exception MalformedURLException if the path name is not given in - * the correct form - */ - URL getResource(String path) throws MalformedURLException { - return context.getResource(path); - } - - - /** - * Parse utils - Is current character a token delimiter ? - * Delimiters are currently defined to be =, >, <, ", and ' or any - * any space character as defined by isSpace. - * - * @return A boolean. - */ - private boolean isDelimiter() throws JasperException { - if (! isSpace()) { - int ch = peekChar(); - // Look for a single-char work delimiter: - if (ch == '=' || ch == '>' || ch == '"' || ch == '\'' - || ch == '/') { - return true; - } - // Look for an end-of-comment or end-of-tag: - if (ch == '-') { - Mark mark = mark(); - if (((ch = nextChar()) == '>') - || ((ch == '-') && (nextChar() == '>'))) { - reset(mark); - return true; - } else { - reset(mark); - return false; - } - } - return false; - } else { - return true; - } - } - - /** - * Register a new source file. - * This method is used to implement file inclusion. Each included file - * gets a unique identifier (which is the index in the array of source - * files). - * - * @return The index of the now registered file. - */ - private int registerSourceFile(final String file) { - if (sourceFiles.contains(file)) { - return -1; - } - - sourceFiles.add(file); - this.size++; - - return sourceFiles.size() - 1; - } - - - /** - * Unregister the source file. - * This method is used to implement file inclusion. Each included file - * gets a uniq identifier (which is the index in the array of source - * files). - * - * @return The index of the now registered file. - */ - private int unregisterSourceFile(final String file) { - if (!sourceFiles.contains(file)) { - return -1; - } - - sourceFiles.remove(file); - this.size--; - return sourceFiles.size() - 1; - } - - /** - * Push a file (and its associated Stream) on the file stack. THe - * current position in the current file is remembered. - */ - private void pushFile(String file, String encoding, - InputStreamReader reader) - throws JasperException, FileNotFoundException { - - // Register the file - String longName = file; - - int fileid = registerSourceFile(longName); - - if (fileid == -1) { - // Bugzilla 37407: http://issues.apache.org/bugzilla/show_bug.cgi?id=37407 - if(reader != null) { - try { - reader.close(); - } catch (Exception any) { - if(log.isDebugEnabled()) { - log.debug("Exception closing reader: ", any); - } - } - } - - err.jspError("jsp.error.file.already.registered", file); - } - - currFileId = fileid; - - try { - CharArrayWriter caw = new CharArrayWriter(); - char buf[] = new char[1024]; - for (int i = 0 ; (i = reader.read(buf)) != -1 ;) - caw.write(buf, 0, i); - caw.close(); - if (current == null) { - current = new Mark(this, caw.toCharArray(), fileid, - getFile(fileid), master, encoding); - } else { - current.pushStream(caw.toCharArray(), fileid, getFile(fileid), - longName, encoding); - } - } catch (Throwable ex) { - log.error("Exception parsing file ", ex); - // Pop state being constructed: - popFile(); - err.jspError("jsp.error.file.cannot.read", file); - } finally { - if (reader != null) { - try { - reader.close(); - } catch (Exception any) { - if(log.isDebugEnabled()) { - log.debug("Exception closing reader: ", any); - } - } - } - } - } - - /** - * Pop a file from the file stack. The field "current" is retored - * to the value to point to the previous files, if any, and is set - * to null otherwise. - * @return true is there is a previous file on the stack. - * false otherwise. - */ - private boolean popFile() throws JasperException { - - // Is stack created ? (will happen if the Jsp file we're looking at is - // missing. - if (current == null || currFileId < 0) { - return false; - } - - // Restore parser state: - String fName = getFile(currFileId); - currFileId = unregisterSourceFile(fName); - if (currFileId < -1) { - err.jspError("jsp.error.file.not.registered", fName); - } - - Mark previous = current.popStream(); - if (previous != null) { - master = current.baseDir; - current = previous; - return true; - } - // Note that although the current file is undefined here, "current" - // is not set to null just for convience, for it maybe used to - // set the current (undefined) position. - return false; - } -} - +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.CharArrayWriter; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.List; +import java.util.Vector; +import java.util.jar.JarFile; +import java.net.URL; +import java.net.MalformedURLException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; + +/** + * JspReader is an input buffer for the JSP parser. It should allow + * unlimited lookahead and pushback. It also has a bunch of parsing + * utility methods for understanding htmlesque thingies. + * + * @author Anil K. Vijendran + * @author Anselm Baird-Smith + * @author Harish Prabandham + * @author Rajiv Mordani + * @author Mandar Raje + * @author Danno Ferrin + * @author Kin-man Chung + * @author Shawn Bayern + * @author Mark Roth + */ + +class JspReader { + + /** + * Logger. + */ + private Log log = LogFactory.getLog(JspReader.class); + + /** + * The current spot in the file. + */ + private Mark current; + + /** + * What is this? + */ + private String master; + + /** + * The list of source files. + */ + private List sourceFiles; + + /** + * The current file ID (-1 indicates an error or no file). + */ + private int currFileId; + + /** + * Seems redundant. + */ + private int size; + + /** + * The compilation context. + */ + private JspCompilationContext context; + + /** + * The Jasper error dispatcher. + */ + private ErrorDispatcher err; + + /** + * Set to true when using the JspReader on a single file where we read up + * to the end and reset to the beginning many times. + * (as in ParserController.figureOutJspDocument()). + */ + private boolean singleFile; + + /** + * Constructor. + * + * @param ctxt The compilation context + * @param fname The file name + * @param encoding The file encoding + * @param jarFile ? + * @param err The error dispatcher + * @throws JasperException If a Jasper-internal error occurs + * @throws FileNotFoundException If the JSP file is not found (or is unreadable) + * @throws IOException If an IO-level error occurs, e.g. reading the file + */ + public JspReader(JspCompilationContext ctxt, + String fname, + String encoding, + JarFile jarFile, + ErrorDispatcher err) + throws JasperException, FileNotFoundException, IOException { + + this(ctxt, fname, encoding, + JspUtil.getReader(fname, encoding, jarFile, ctxt, err), + err); + } + + /** + * Constructor: same as above constructor but with initialized reader + * to the file given. + */ + public JspReader(JspCompilationContext ctxt, + String fname, + String encoding, + InputStreamReader reader, + ErrorDispatcher err) + throws JasperException, FileNotFoundException { + + this.context = ctxt; + this.err = err; + sourceFiles = new Vector(); + currFileId = 0; + size = 0; + singleFile = false; + pushFile(fname, encoding, reader); + } + + /** + * @return JSP compilation context with which this JspReader is + * associated + */ + JspCompilationContext getJspCompilationContext() { + return context; + } + + /** + * Returns the file at the given position in the list. + * + * @param fileid The file position in the list + * @return The file at that position, if found, null otherwise + */ + String getFile(final int fileid) { + return (String) sourceFiles.get(fileid); + } + + /** + * Checks if the current file has more input. + * + * @return True if more reading is possible + * @throws JasperException if an error occurs + */ + boolean hasMoreInput() throws JasperException { + if (current.cursor >= current.stream.length) { + if (singleFile) return false; + while (popFile()) { + if (current.cursor < current.stream.length) return true; + } + return false; + } + return true; + } + + int nextChar() throws JasperException { + if (!hasMoreInput()) + return -1; + + int ch = current.stream[current.cursor]; + + current.cursor++; + + if (ch == '\n') { + current.line++; + current.col = 0; + } else { + current.col++; + } + return ch; + } + + /** + * Back up the current cursor by one char, assumes current.cursor > 0, + * and that the char to be pushed back is not '\n'. + */ + void pushChar() { + current.cursor--; + current.col--; + } + + String getText(Mark start, Mark stop) throws JasperException { + Mark oldstart = mark(); + reset(start); + CharArrayWriter caw = new CharArrayWriter(); + while (!stop.equals(mark())) + caw.write(nextChar()); + caw.close(); + reset(oldstart); + return caw.toString(); + } + + int peekChar() throws JasperException { + if (!hasMoreInput()) + return -1; + return current.stream[current.cursor]; + } + + Mark mark() { + return new Mark(current); + } + + void reset(Mark mark) { + current = new Mark(mark); + } + + boolean matchesIgnoreCase(String string) throws JasperException { + Mark mark = mark(); + int ch = 0; + int i = 0; + do { + ch = nextChar(); + if (Character.toLowerCase((char) ch) != string.charAt(i++)) { + reset(mark); + return false; + } + } while (i < string.length()); + reset(mark); + return true; + } + + /** + * search the stream for a match to a string + * @param string The string to match + * @return true is one is found, the current position + * in stream is positioned after the search string, + * false otherwise, position in stream unchanged. + */ + boolean matches(String string) throws JasperException { + Mark mark = mark(); + int ch = 0; + int i = 0; + do { + ch = nextChar(); + if (((char) ch) != string.charAt(i++)) { + reset(mark); + return false; + } + } while (i < string.length()); + return true; + } + + boolean matchesETag(String tagName) throws JasperException { + Mark mark = mark(); + + if (!matches("') + return true; + + reset(mark); + return false; + } + + boolean matchesETagWithoutLessThan(String tagName) + throws JasperException + { + Mark mark = mark(); + + if (!matches("/" + tagName)) + return false; + skipSpaces(); + if (nextChar() == '>') + return true; + + reset(mark); + return false; + } + + + /** + * Looks ahead to see if there are optional spaces followed by + * the given String. If so, true is returned and those spaces and + * characters are skipped. If not, false is returned and the + * position is restored to where we were before. + */ + boolean matchesOptionalSpacesFollowedBy( String s ) + throws JasperException + { + Mark mark = mark(); + + skipSpaces(); + boolean result = matches( s ); + if( !result ) { + reset( mark ); + } + + return result; + } + + int skipSpaces() throws JasperException { + int i = 0; + while (hasMoreInput() && isSpace()) { + i++; + nextChar(); + } + return i; + } + + /** + * Skip until the given string is matched in the stream. + * When returned, the context is positioned past the end of the match. + * + * @param s The String to match. + * @return A non-null Mark instance (positioned immediately + * before the search string) if found, null + * otherwise. + */ + Mark skipUntil(String limit) throws JasperException { + Mark ret = null; + int limlen = limit.length(); + int ch; + + skip: + for (ret = mark(), ch = nextChar() ; ch != -1 ; + ret = mark(), ch = nextChar()) { + if (ch == limit.charAt(0)) { + Mark restart = mark(); + for (int i = 1 ; i < limlen ; i++) { + if (peekChar() == limit.charAt(i)) + nextChar(); + else { + reset(restart); + continue skip; + } + } + return ret; + } + } + return null; + } + + /** + * Skip until the given string is matched in the stream, but ignoring + * chars initially escaped by a '\'. + * When returned, the context is positioned past the end of the match. + * + * @param s The String to match. + * @return A non-null Mark instance (positioned immediately + * before the search string) if found, null + * otherwise. + */ + Mark skipUntilIgnoreEsc(String limit) throws JasperException { + Mark ret = null; + int limlen = limit.length(); + int ch; + int prev = 'x'; // Doesn't matter + + skip: + for (ret = mark(), ch = nextChar() ; ch != -1 ; + ret = mark(), prev = ch, ch = nextChar()) { + if (ch == '\\' && prev == '\\') { + ch = 0; // Double \ is not an escape char anymore + } + else if (ch == limit.charAt(0) && prev != '\\') { + for (int i = 1 ; i < limlen ; i++) { + if (peekChar() == limit.charAt(i)) + nextChar(); + else + continue skip; + } + return ret; + } + } + return null; + } + + /** + * Skip until the given end tag is matched in the stream. + * When returned, the context is positioned past the end of the tag. + * + * @param tag The name of the tag whose ETag () to match. + * @return A non-null Mark instance (positioned immediately + * before the ETag) if found, null otherwise. + */ + Mark skipUntilETag(String tag) throws JasperException { + Mark ret = skipUntil("') + ret = null; + } + return ret; + } + + final boolean isSpace() throws JasperException { + // Note: If this logic changes, also update Node.TemplateText.rtrim() + return peekChar() <= ' '; + } + + /** + * Parse a space delimited token. + * If quoted the token will consume all characters up to a matching quote, + * otherwise, it consumes up to the first delimiter character. + * + * @param quoted If true accept quoted strings. + */ + String parseToken(boolean quoted) throws JasperException { + StringBuffer stringBuffer = new StringBuffer(); + skipSpaces(); + stringBuffer.setLength(0); + + if (!hasMoreInput()) { + return ""; + } + + int ch = peekChar(); + + if (quoted) { + if (ch == '"' || ch == '\'') { + + char endQuote = ch == '"' ? '"' : '\''; + // Consume the open quote: + ch = nextChar(); + for (ch = nextChar(); ch != -1 && ch != endQuote; + ch = nextChar()) { + if (ch == '\\') + ch = nextChar(); + stringBuffer.append((char) ch); + } + // Check end of quote, skip closing quote: + if (ch == -1) { + err.jspError(mark(), "jsp.error.quotes.unterminated"); + } + } else { + err.jspError(mark(), "jsp.error.attr.quoted"); + } + } else { + if (!isDelimiter()) { + // Read value until delimiter is found: + do { + ch = nextChar(); + // Take care of the quoting here. + if (ch == '\\') { + if (peekChar() == '"' || peekChar() == '\'' || + peekChar() == '>' || peekChar() == '%') + ch = nextChar(); + } + stringBuffer.append((char) ch); + } while (!isDelimiter()); + } + } + + return stringBuffer.toString(); + } + + void setSingleFile(boolean val) { + singleFile = val; + } + + + /** + * Gets the URL for the given path name. + * + * @param path Path name + * + * @return URL for the given path name. + * + * @exception MalformedURLException if the path name is not given in + * the correct form + */ + URL getResource(String path) throws MalformedURLException { + return context.getResource(path); + } + + + /** + * Parse utils - Is current character a token delimiter ? + * Delimiters are currently defined to be =, >, <, ", and ' or any + * any space character as defined by isSpace. + * + * @return A boolean. + */ + private boolean isDelimiter() throws JasperException { + if (! isSpace()) { + int ch = peekChar(); + // Look for a single-char work delimiter: + if (ch == '=' || ch == '>' || ch == '"' || ch == '\'' + || ch == '/') { + return true; + } + // Look for an end-of-comment or end-of-tag: + if (ch == '-') { + Mark mark = mark(); + if (((ch = nextChar()) == '>') + || ((ch == '-') && (nextChar() == '>'))) { + reset(mark); + return true; + } else { + reset(mark); + return false; + } + } + return false; + } else { + return true; + } + } + + /** + * Register a new source file. + * This method is used to implement file inclusion. Each included file + * gets a unique identifier (which is the index in the array of source + * files). + * + * @return The index of the now registered file. + */ + private int registerSourceFile(final String file) { + if (sourceFiles.contains(file)) { + return -1; + } + + sourceFiles.add(file); + this.size++; + + return sourceFiles.size() - 1; + } + + + /** + * Unregister the source file. + * This method is used to implement file inclusion. Each included file + * gets a uniq identifier (which is the index in the array of source + * files). + * + * @return The index of the now registered file. + */ + private int unregisterSourceFile(final String file) { + if (!sourceFiles.contains(file)) { + return -1; + } + + sourceFiles.remove(file); + this.size--; + return sourceFiles.size() - 1; + } + + /** + * Push a file (and its associated Stream) on the file stack. THe + * current position in the current file is remembered. + */ + private void pushFile(String file, String encoding, + InputStreamReader reader) + throws JasperException, FileNotFoundException { + + // Register the file + String longName = file; + + int fileid = registerSourceFile(longName); + + if (fileid == -1) { + // Bugzilla 37407: http://issues.apache.org/bugzilla/show_bug.cgi?id=37407 + if(reader != null) { + try { + reader.close(); + } catch (Exception any) { + if(log.isDebugEnabled()) { + log.debug("Exception closing reader: ", any); + } + } + } + + err.jspError("jsp.error.file.already.registered", file); + } + + currFileId = fileid; + + try { + CharArrayWriter caw = new CharArrayWriter(); + char buf[] = new char[1024]; + for (int i = 0 ; (i = reader.read(buf)) != -1 ;) + caw.write(buf, 0, i); + caw.close(); + if (current == null) { + current = new Mark(this, caw.toCharArray(), fileid, + getFile(fileid), master, encoding); + } else { + current.pushStream(caw.toCharArray(), fileid, getFile(fileid), + longName, encoding); + } + } catch (Throwable ex) { + log.error("Exception parsing file ", ex); + // Pop state being constructed: + popFile(); + err.jspError("jsp.error.file.cannot.read", file); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (Exception any) { + if(log.isDebugEnabled()) { + log.debug("Exception closing reader: ", any); + } + } + } + } + } + + /** + * Pop a file from the file stack. The field "current" is retored + * to the value to point to the previous files, if any, and is set + * to null otherwise. + * @return true is there is a previous file on the stack. + * false otherwise. + */ + private boolean popFile() throws JasperException { + + // Is stack created ? (will happen if the Jsp file we're looking at is + // missing. + if (current == null || currFileId < 0) { + return false; + } + + // Restore parser state: + String fName = getFile(currFileId); + currFileId = unregisterSourceFile(fName); + if (currFileId < -1) { + err.jspError("jsp.error.file.not.registered", fName); + } + + Mark previous = current.popStream(); + if (previous != null) { + master = current.baseDir; + current = previous; + return true; + } + // Note that although the current file is undefined here, "current" + // is not set to null just for convience, for it maybe used to + // set the current (undefined) position. + return false; + } +} + diff --git a/java/org/apache/jasper/compiler/JspRuntimeContext.java b/java/org/apache/jasper/compiler/JspRuntimeContext.java index 024812692..9b9436c0f 100644 --- a/java/org/apache/jasper/compiler/JspRuntimeContext.java +++ b/java/org/apache/jasper/compiler/JspRuntimeContext.java @@ -1,524 +1,524 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FilePermission; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.CodeSource; -import java.security.PermissionCollection; -import java.security.Policy; -import java.security.cert.Certificate; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import javax.servlet.ServletContext; -import javax.servlet.jsp.JspFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.Options; -import org.apache.jasper.runtime.JspFactoryImpl; -import org.apache.jasper.security.SecurityClassLoad; -import org.apache.jasper.servlet.JspServletWrapper; - -/** - * Class for tracking JSP compile time file dependencies when the - * &060;%@include file="..."%&062; directive is used. - * - * A background thread periodically checks the files a JSP page - * is dependent upon. If a dpendent file changes the JSP page - * which included it is recompiled. - * - * Only used if a web application context is a directory. - * - * @author Glenn L. Nielsen - * @version $Revision: 306189 $ - */ -public final class JspRuntimeContext implements Runnable { - - // Logger - private Log log = LogFactory.getLog(JspRuntimeContext.class); - - /* - * Counts how many times the webapp's JSPs have been reloaded. - */ - private int jspReloadCount; - - /** - * Preload classes required at runtime by a JSP servlet so that - * we don't get a defineClassInPackage security exception. - */ - static { - JspFactoryImpl factory = new JspFactoryImpl(); - SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader()); - JspFactory.setDefaultFactory(factory); - } - - // ----------------------------------------------------------- Constructors - - /** - * Create a JspRuntimeContext for a web application context. - * - * Loads in any previously generated dependencies from file. - * - * @param context ServletContext for web application - */ - public JspRuntimeContext(ServletContext context, Options options) { - - this.context = context; - this.options = options; - - // Get the parent class loader - parentClassLoader = - (URLClassLoader) Thread.currentThread().getContextClassLoader(); - if (parentClassLoader == null) { - parentClassLoader = - (URLClassLoader)this.getClass().getClassLoader(); - } - - if (log.isDebugEnabled()) { - if (parentClassLoader != null) { - log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", - parentClassLoader.toString())); - } else { - log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", - "")); - } - } - - initClassPath(); - - if (context instanceof org.apache.jasper.servlet.JspCServletContext) { - return; - } - - if (System.getSecurityManager() != null) { - initSecurity(); - } - - // If this web application context is running from a - // directory, start the background compilation thread - String appBase = context.getRealPath("/"); - if (!options.getDevelopment() - && appBase != null - && options.getCheckInterval() > 0) { - if (appBase.endsWith(File.separator) ) { - appBase = appBase.substring(0,appBase.length()-1); - } - String directory = - appBase.substring(appBase.lastIndexOf(File.separator)); - threadName = threadName + "[" + directory + "]"; - threadStart(); - } - } - - // ----------------------------------------------------- Instance Variables - - /** - * This web applications ServletContext - */ - private ServletContext context; - private Options options; - private URLClassLoader parentClassLoader; - private PermissionCollection permissionCollection; - private CodeSource codeSource; - private String classpath; - - /** - * Maps JSP pages to their JspServletWrapper's - */ - private Map jsps = Collections.synchronizedMap( new HashMap()); - - - /** - * The background thread. - */ - private Thread thread = null; - - - /** - * The background thread completion semaphore. - */ - private boolean threadDone = false; - - - /** - * Name to register for the background thread. - */ - private String threadName = "JspRuntimeContext"; - - // ------------------------------------------------------ Public Methods - - /** - * Add a new JspServletWrapper. - * - * @param jspUri JSP URI - * @param jsw Servlet wrapper for JSP - */ - public void addWrapper(String jspUri, JspServletWrapper jsw) { - jsps.remove(jspUri); - jsps.put(jspUri,jsw); - } - - /** - * Get an already existing JspServletWrapper. - * - * @param jspUri JSP URI - * @return JspServletWrapper for JSP - */ - public JspServletWrapper getWrapper(String jspUri) { - return (JspServletWrapper) jsps.get(jspUri); - } - - /** - * Remove a JspServletWrapper. - * - * @param jspUri JSP URI of JspServletWrapper to remove - */ - public void removeWrapper(String jspUri) { - jsps.remove(jspUri); - } - - /** - * Returns the number of JSPs for which JspServletWrappers exist, i.e., - * the number of JSPs that have been loaded into the webapp. - * - * @return The number of JSPs that have been loaded into the webapp - */ - public int getJspCount() { - return jsps.size(); - } - - /** - * Get the SecurityManager Policy CodeSource for this web - * applicaiton context. - * - * @return CodeSource for JSP - */ - public CodeSource getCodeSource() { - return codeSource; - } - - /** - * Get the parent URLClassLoader. - * - * @return URLClassLoader parent - */ - public URLClassLoader getParentClassLoader() { - return parentClassLoader; - } - - /** - * Get the SecurityManager PermissionCollection for this - * web application context. - * - * @return PermissionCollection permissions - */ - public PermissionCollection getPermissionCollection() { - return permissionCollection; - } - - /** - * Process a "destory" event for this web application context. - */ - public void destroy() { - threadStop(); - - Iterator servlets = jsps.values().iterator(); - while (servlets.hasNext()) { - ((JspServletWrapper) servlets.next()).destroy(); - } - } - - /** - * Increments the JSP reload counter. - */ - public synchronized void incrementJspReloadCount() { - jspReloadCount++; - } - - /** - * Resets the JSP reload counter. - * - * @param count Value to which to reset the JSP reload counter - */ - public synchronized void setJspReloadCount(int count) { - this.jspReloadCount = count; - } - - /** - * Gets the current value of the JSP reload counter. - * - * @return The current value of the JSP reload counter - */ - public int getJspReloadCount() { - return jspReloadCount; - } - - - // -------------------------------------------------------- Private Methods - - /** - * Method used by background thread to check the JSP dependencies - * registered with this class for JSP's. - */ - private void checkCompile() { - Object [] wrappers = jsps.values().toArray(); - for (int i = 0; i < wrappers.length; i++ ) { - JspServletWrapper jsw = (JspServletWrapper)wrappers[i]; - JspCompilationContext ctxt = jsw.getJspEngineContext(); - // JspServletWrapper also synchronizes on this when - // it detects it has to do a reload - synchronized(jsw) { - try { - ctxt.compile(); - } catch (FileNotFoundException ex) { - ctxt.incrementRemoved(); - } catch (Throwable t) { - jsw.getServletContext().log("Background compile failed", - t); - } - } - } - } - - /** - * The classpath that is passed off to the Java compiler. - */ - public String getClassPath() { - return classpath; - } - - /** - * Method used to initialize classpath for compiles. - */ - private void initClassPath() { - - URL [] urls = parentClassLoader.getURLs(); - StringBuffer cpath = new StringBuffer(); - String sep = System.getProperty("path.separator"); - - for(int i = 0; i < urls.length; i++) { - // Tomcat 4 can use URL's other than file URL's, - // a protocol other than file: will generate a - // bad file system path, so only add file: - // protocol URL's to the classpath. - - if( urls[i].getProtocol().equals("file") ) { - cpath.append((String)urls[i].getFile()+sep); - } - } - - cpath.append(options.getScratchDir() + sep); - - String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); - if (cp == null || cp.equals("")) { - cp = options.getClassPath(); - } - - classpath = cpath.toString() + cp; - - if(log.isDebugEnabled()) { - log.debug("Compilation classpath initialized: " + getClassPath()); - } - } - - /** - * Method used to initialize SecurityManager data. - */ - private void initSecurity() { - - // Setup the PermissionCollection for this web app context - // based on the permissions configured for the root of the - // web app context directory, then add a file read permission - // for that directory. - Policy policy = Policy.getPolicy(); - if( policy != null ) { - try { - // Get the permissions for the web app context - String docBase = context.getRealPath("/"); - if( docBase == null ) { - docBase = options.getScratchDir().toString(); - } - String codeBase = docBase; - if (!codeBase.endsWith(File.separator)){ - codeBase = codeBase + File.separator; - } - File contextDir = new File(codeBase); - URL url = contextDir.getCanonicalFile().toURL(); - codeSource = new CodeSource(url,(Certificate[])null); - permissionCollection = policy.getPermissions(codeSource); - - // Create a file read permission for web app context directory - if (!docBase.endsWith(File.separator)){ - permissionCollection.add - (new FilePermission(docBase,"read")); - docBase = docBase + File.separator; - } else { - permissionCollection.add - (new FilePermission - (docBase.substring(0,docBase.length() - 1),"read")); - } - docBase = docBase + "-"; - permissionCollection.add(new FilePermission(docBase,"read")); - - // Create a file read permission for web app tempdir (work) - // directory - String workDir = options.getScratchDir().toString(); - if (!workDir.endsWith(File.separator)){ - permissionCollection.add - (new FilePermission(workDir,"read")); - workDir = workDir + File.separator; - } - workDir = workDir + "-"; - permissionCollection.add(new FilePermission(workDir,"read")); - - // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase - permissionCollection.add( new RuntimePermission( - "accessClassInPackage.org.apache.jasper.runtime") ); - - if (parentClassLoader instanceof URLClassLoader) { - URL [] urls = parentClassLoader.getURLs(); - String jarUrl = null; - String jndiUrl = null; - for (int i=0; icheckInterval - * property. - */ - protected void threadSleep() { - - try { - Thread.sleep(options.getCheckInterval() * 1000L); - } catch (InterruptedException e) { - ; - } - - } - - - // ------------------------------------------------------ Background Thread - - - /** - * The background thread that checks for changes to files - * included by a JSP and flags that a recompile is required. - */ - public void run() { - - // Loop until the termination semaphore is set - while (!threadDone) { - - // Wait for our check interval - threadSleep(); - - // Check for included files which are newer than the - // JSP which uses them. - try { - checkCompile(); - } catch (Throwable t) { - log.error("Exception checking if recompile needed: ", t); - } - } - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilePermission; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; +import java.security.PermissionCollection; +import java.security.Policy; +import java.security.cert.Certificate; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.jsp.JspFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.Options; +import org.apache.jasper.runtime.JspFactoryImpl; +import org.apache.jasper.security.SecurityClassLoad; +import org.apache.jasper.servlet.JspServletWrapper; + +/** + * Class for tracking JSP compile time file dependencies when the + * &060;%@include file="..."%&062; directive is used. + * + * A background thread periodically checks the files a JSP page + * is dependent upon. If a dpendent file changes the JSP page + * which included it is recompiled. + * + * Only used if a web application context is a directory. + * + * @author Glenn L. Nielsen + * @version $Revision: 306189 $ + */ +public final class JspRuntimeContext implements Runnable { + + // Logger + private Log log = LogFactory.getLog(JspRuntimeContext.class); + + /* + * Counts how many times the webapp's JSPs have been reloaded. + */ + private int jspReloadCount; + + /** + * Preload classes required at runtime by a JSP servlet so that + * we don't get a defineClassInPackage security exception. + */ + static { + JspFactoryImpl factory = new JspFactoryImpl(); + SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader()); + JspFactory.setDefaultFactory(factory); + } + + // ----------------------------------------------------------- Constructors + + /** + * Create a JspRuntimeContext for a web application context. + * + * Loads in any previously generated dependencies from file. + * + * @param context ServletContext for web application + */ + public JspRuntimeContext(ServletContext context, Options options) { + + this.context = context; + this.options = options; + + // Get the parent class loader + parentClassLoader = + (URLClassLoader) Thread.currentThread().getContextClassLoader(); + if (parentClassLoader == null) { + parentClassLoader = + (URLClassLoader)this.getClass().getClassLoader(); + } + + if (log.isDebugEnabled()) { + if (parentClassLoader != null) { + log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", + parentClassLoader.toString())); + } else { + log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is", + "")); + } + } + + initClassPath(); + + if (context instanceof org.apache.jasper.servlet.JspCServletContext) { + return; + } + + if (System.getSecurityManager() != null) { + initSecurity(); + } + + // If this web application context is running from a + // directory, start the background compilation thread + String appBase = context.getRealPath("/"); + if (!options.getDevelopment() + && appBase != null + && options.getCheckInterval() > 0) { + if (appBase.endsWith(File.separator) ) { + appBase = appBase.substring(0,appBase.length()-1); + } + String directory = + appBase.substring(appBase.lastIndexOf(File.separator)); + threadName = threadName + "[" + directory + "]"; + threadStart(); + } + } + + // ----------------------------------------------------- Instance Variables + + /** + * This web applications ServletContext + */ + private ServletContext context; + private Options options; + private URLClassLoader parentClassLoader; + private PermissionCollection permissionCollection; + private CodeSource codeSource; + private String classpath; + + /** + * Maps JSP pages to their JspServletWrapper's + */ + private Map jsps = Collections.synchronizedMap( new HashMap()); + + + /** + * The background thread. + */ + private Thread thread = null; + + + /** + * The background thread completion semaphore. + */ + private boolean threadDone = false; + + + /** + * Name to register for the background thread. + */ + private String threadName = "JspRuntimeContext"; + + // ------------------------------------------------------ Public Methods + + /** + * Add a new JspServletWrapper. + * + * @param jspUri JSP URI + * @param jsw Servlet wrapper for JSP + */ + public void addWrapper(String jspUri, JspServletWrapper jsw) { + jsps.remove(jspUri); + jsps.put(jspUri,jsw); + } + + /** + * Get an already existing JspServletWrapper. + * + * @param jspUri JSP URI + * @return JspServletWrapper for JSP + */ + public JspServletWrapper getWrapper(String jspUri) { + return (JspServletWrapper) jsps.get(jspUri); + } + + /** + * Remove a JspServletWrapper. + * + * @param jspUri JSP URI of JspServletWrapper to remove + */ + public void removeWrapper(String jspUri) { + jsps.remove(jspUri); + } + + /** + * Returns the number of JSPs for which JspServletWrappers exist, i.e., + * the number of JSPs that have been loaded into the webapp. + * + * @return The number of JSPs that have been loaded into the webapp + */ + public int getJspCount() { + return jsps.size(); + } + + /** + * Get the SecurityManager Policy CodeSource for this web + * applicaiton context. + * + * @return CodeSource for JSP + */ + public CodeSource getCodeSource() { + return codeSource; + } + + /** + * Get the parent URLClassLoader. + * + * @return URLClassLoader parent + */ + public URLClassLoader getParentClassLoader() { + return parentClassLoader; + } + + /** + * Get the SecurityManager PermissionCollection for this + * web application context. + * + * @return PermissionCollection permissions + */ + public PermissionCollection getPermissionCollection() { + return permissionCollection; + } + + /** + * Process a "destory" event for this web application context. + */ + public void destroy() { + threadStop(); + + Iterator servlets = jsps.values().iterator(); + while (servlets.hasNext()) { + ((JspServletWrapper) servlets.next()).destroy(); + } + } + + /** + * Increments the JSP reload counter. + */ + public synchronized void incrementJspReloadCount() { + jspReloadCount++; + } + + /** + * Resets the JSP reload counter. + * + * @param count Value to which to reset the JSP reload counter + */ + public synchronized void setJspReloadCount(int count) { + this.jspReloadCount = count; + } + + /** + * Gets the current value of the JSP reload counter. + * + * @return The current value of the JSP reload counter + */ + public int getJspReloadCount() { + return jspReloadCount; + } + + + // -------------------------------------------------------- Private Methods + + /** + * Method used by background thread to check the JSP dependencies + * registered with this class for JSP's. + */ + private void checkCompile() { + Object [] wrappers = jsps.values().toArray(); + for (int i = 0; i < wrappers.length; i++ ) { + JspServletWrapper jsw = (JspServletWrapper)wrappers[i]; + JspCompilationContext ctxt = jsw.getJspEngineContext(); + // JspServletWrapper also synchronizes on this when + // it detects it has to do a reload + synchronized(jsw) { + try { + ctxt.compile(); + } catch (FileNotFoundException ex) { + ctxt.incrementRemoved(); + } catch (Throwable t) { + jsw.getServletContext().log("Background compile failed", + t); + } + } + } + } + + /** + * The classpath that is passed off to the Java compiler. + */ + public String getClassPath() { + return classpath; + } + + /** + * Method used to initialize classpath for compiles. + */ + private void initClassPath() { + + URL [] urls = parentClassLoader.getURLs(); + StringBuffer cpath = new StringBuffer(); + String sep = System.getProperty("path.separator"); + + for(int i = 0; i < urls.length; i++) { + // Tomcat 4 can use URL's other than file URL's, + // a protocol other than file: will generate a + // bad file system path, so only add file: + // protocol URL's to the classpath. + + if( urls[i].getProtocol().equals("file") ) { + cpath.append((String)urls[i].getFile()+sep); + } + } + + cpath.append(options.getScratchDir() + sep); + + String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH); + if (cp == null || cp.equals("")) { + cp = options.getClassPath(); + } + + classpath = cpath.toString() + cp; + + if(log.isDebugEnabled()) { + log.debug("Compilation classpath initialized: " + getClassPath()); + } + } + + /** + * Method used to initialize SecurityManager data. + */ + private void initSecurity() { + + // Setup the PermissionCollection for this web app context + // based on the permissions configured for the root of the + // web app context directory, then add a file read permission + // for that directory. + Policy policy = Policy.getPolicy(); + if( policy != null ) { + try { + // Get the permissions for the web app context + String docBase = context.getRealPath("/"); + if( docBase == null ) { + docBase = options.getScratchDir().toString(); + } + String codeBase = docBase; + if (!codeBase.endsWith(File.separator)){ + codeBase = codeBase + File.separator; + } + File contextDir = new File(codeBase); + URL url = contextDir.getCanonicalFile().toURL(); + codeSource = new CodeSource(url,(Certificate[])null); + permissionCollection = policy.getPermissions(codeSource); + + // Create a file read permission for web app context directory + if (!docBase.endsWith(File.separator)){ + permissionCollection.add + (new FilePermission(docBase,"read")); + docBase = docBase + File.separator; + } else { + permissionCollection.add + (new FilePermission + (docBase.substring(0,docBase.length() - 1),"read")); + } + docBase = docBase + "-"; + permissionCollection.add(new FilePermission(docBase,"read")); + + // Create a file read permission for web app tempdir (work) + // directory + String workDir = options.getScratchDir().toString(); + if (!workDir.endsWith(File.separator)){ + permissionCollection.add + (new FilePermission(workDir,"read")); + workDir = workDir + File.separator; + } + workDir = workDir + "-"; + permissionCollection.add(new FilePermission(workDir,"read")); + + // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase + permissionCollection.add( new RuntimePermission( + "accessClassInPackage.org.apache.jasper.runtime") ); + + if (parentClassLoader instanceof URLClassLoader) { + URL [] urls = parentClassLoader.getURLs(); + String jarUrl = null; + String jndiUrl = null; + for (int i=0; icheckInterval + * property. + */ + protected void threadSleep() { + + try { + Thread.sleep(options.getCheckInterval() * 1000L); + } catch (InterruptedException e) { + ; + } + + } + + + // ------------------------------------------------------ Background Thread + + + /** + * The background thread that checks for changes to files + * included by a JSP and flags that a recompile is required. + */ + public void run() { + + // Loop until the termination semaphore is set + while (!threadDone) { + + // Wait for our check interval + threadSleep(); + + // Check for included files which are newer than the + // JSP which uses them. + try { + checkCompile(); + } catch (Throwable t) { + log.error("Exception checking if recompile needed: ", t); + } + } + + } + +} diff --git a/java/org/apache/jasper/compiler/JspUtil.java b/java/org/apache/jasper/compiler/JspUtil.java index 8d02cce8a..83d0da08b 100644 --- a/java/org/apache/jasper/compiler/JspUtil.java +++ b/java/org/apache/jasper/compiler/JspUtil.java @@ -1,1134 +1,1134 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.util.Vector; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; - -import javax.el.FunctionMapper; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.ELParseException; -import javax.servlet.jsp.el.ExpressionEvaluator; - - -import org.apache.el.ExpressionFactoryImpl; -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.el.ExpressionEvaluatorImpl; -import org.xml.sax.Attributes; - -/** - * This class has all the utility method(s). - * Ideally should move all the bean containers here. - * - * @author Mandar Raje. - * @author Rajiv Mordani. - * @author Danno Ferrin - * @author Pierre Delisle - * @author Shawn Bayern - * @author Mark Roth - */ -public class JspUtil { - - private static final String WEB_INF_TAGS = "/WEB-INF/tags/"; - private static final String META_INF_TAGS = "/META-INF/tags/"; - - // Delimiters for request-time expressions (JSP and XML syntax) - private static final String OPEN_EXPR = "<%="; - private static final String CLOSE_EXPR = "%>"; - private static final String OPEN_EXPR_XML = "%="; - private static final String CLOSE_EXPR_XML = "%"; - - private static int tempSequenceNumber = 0; - - //private static ExpressionEvaluatorImpl expressionEvaluator - //= new ExpressionEvaluatorImpl(); - - //tc6 - private final static ExpressionEvaluator expressionEvaluator = - new ExpressionEvaluatorImpl(new ExpressionFactoryImpl()); - - private static final String javaKeywords[] = { - "abstract", "assert", "boolean", "break", "byte", "case", - "catch", "char", "class", "const", "continue", - "default", "do", "double", "else", "enum", "extends", - "final", "finally", "float", "for", "goto", - "if", "implements", "import", "instanceof", "int", - "interface", "long", "native", "new", "package", - "private", "protected", "public", "return", "short", - "static", "strictfp", "super", "switch", "synchronized", - "this", "throws", "transient", "try", "void", - "volatile", "while" }; - - public static final int CHUNKSIZE = 1024; - - public static char[] removeQuotes(char []chars) { - CharArrayWriter caw = new CharArrayWriter(); - for (int i = 0; i < chars.length; i++) { - if (chars[i] == '%' && chars[i+1] == '\\' && - chars[i+2] == '>') { - caw.write('%'); - caw.write('>'); - i = i + 2; - } else { - caw.write(chars[i]); - } - } - return caw.toCharArray(); - } - - public static char[] escapeQuotes (char []chars) { - // Prescan to convert %\> to %> - String s = new String(chars); - while (true) { - int n = s.indexOf("%\\>"); - if (n < 0) - break; - StringBuffer sb = new StringBuffer(s.substring(0, n)); - sb.append("%>"); - sb.append(s.substring(n + 3)); - s = sb.toString(); - } - chars = s.toCharArray(); - return (chars); - - - // Escape all backslashes not inside a Java string literal - /* - CharArrayWriter caw = new CharArrayWriter(); - boolean inJavaString = false; - for (int i = 0; i < chars.length; i++) { - if (chars[i] == '"') inJavaString = !inJavaString; - // escape out the escape character - if (!inJavaString && (chars[i] == '\\')) caw.write('\\'); - caw.write(chars[i]); - } - return caw.toCharArray(); - */ - } - - /** - * Checks if the token is a runtime expression. - * In standard JSP syntax, a runtime expression starts with '<%' and - * ends with '%>'. When the JSP document is in XML syntax, a runtime - * expression starts with '%=' and ends with '%'. - * - * @param token The token to be checked - * return whether the token is a runtime expression or not. - */ - public static boolean isExpression(String token, boolean isXml) { - String openExpr; - String closeExpr; - if (isXml) { - openExpr = OPEN_EXPR_XML; - closeExpr = CLOSE_EXPR_XML; - } else { - openExpr = OPEN_EXPR; - closeExpr = CLOSE_EXPR; - } - if (token.startsWith(openExpr) && token.endsWith(closeExpr)) { - return true; - } else { - return false; - } - } - - /** - * @return the "expression" part of a runtime expression, - * taking the delimiters out. - */ - public static String getExpr (String expression, boolean isXml) { - String returnString; - String openExpr; - String closeExpr; - if (isXml) { - openExpr = OPEN_EXPR_XML; - closeExpr = CLOSE_EXPR_XML; - } else { - openExpr = OPEN_EXPR; - closeExpr = CLOSE_EXPR; - } - int length = expression.length(); - if (expression.startsWith(openExpr) && - expression.endsWith(closeExpr)) { - returnString = expression.substring( - openExpr.length(), length - closeExpr.length()); - } else { - returnString = ""; - } - return returnString; - } - - /** - * Takes a potential expression and converts it into XML form - */ - public static String getExprInXml(String expression) { - String returnString; - int length = expression.length(); - - if (expression.startsWith(OPEN_EXPR) - && expression.endsWith(CLOSE_EXPR)) { - returnString = expression.substring (1, length - 1); - } else { - returnString = expression; - } - - return escapeXml(returnString.replace(Constants.ESC, '$')); - } - - /** - * Checks to see if the given scope is valid. - * - * @param scope The scope to be checked - * @param n The Node containing the 'scope' attribute whose value is to be - * checked - * @param err error dispatcher - * - * @throws JasperException if scope is not null and different from - * "page", "request", "session", and - * "application" - */ - public static void checkScope(String scope, Node n, ErrorDispatcher err) - throws JasperException { - if (scope != null && !scope.equals("page") && !scope.equals("request") - && !scope.equals("session") && !scope.equals("application")) { - err.jspError(n, "jsp.error.invalid.scope", scope); - } - } - - /** - * Checks if all mandatory attributes are present and if all attributes - * present have valid names. Checks attributes specified as XML-style - * attributes as well as attributes specified using the jsp:attribute - * standard action. - */ - public static void checkAttributes(String typeOfTag, - Node n, - ValidAttribute[] validAttributes, - ErrorDispatcher err) - throws JasperException { - Attributes attrs = n.getAttributes(); - Mark start = n.getStart(); - boolean valid = true; - - // AttributesImpl.removeAttribute is broken, so we do this... - int tempLength = (attrs == null) ? 0 : attrs.getLength(); - Vector temp = new Vector(tempLength, 1); - for (int i = 0; i < tempLength; i++) { - String qName = attrs.getQName(i); - if ((!qName.equals("xmlns")) && (!qName.startsWith("xmlns:"))) - temp.addElement(qName); - } - - // Add names of attributes specified using jsp:attribute - Node.Nodes tagBody = n.getBody(); - if( tagBody != null ) { - int numSubElements = tagBody.size(); - for( int i = 0; i < numSubElements; i++ ) { - Node node = tagBody.getNode( i ); - if( node instanceof Node.NamedAttribute ) { - String attrName = node.getAttributeValue( "name" ); - temp.addElement( attrName ); - // Check if this value appear in the attribute of the node - if (n.getAttributeValue(attrName) != null) { - err.jspError(n, "jsp.error.duplicate.name.jspattribute", - attrName); - } - } - else { - // Nothing can come before jsp:attribute, and only - // jsp:body can come after it. - break; - } - } - } - - /* - * First check to see if all the mandatory attributes are present. - * If so only then proceed to see if the other attributes are valid - * for the particular tag. - */ - String missingAttribute = null; - - for (int i = 0; i < validAttributes.length; i++) { - int attrPos; - if (validAttributes[i].mandatory) { - attrPos = temp.indexOf(validAttributes[i].name); - if (attrPos != -1) { - temp.remove(attrPos); - valid = true; - } else { - valid = false; - missingAttribute = validAttributes[i].name; - break; - } - } - } - - // If mandatory attribute is missing then the exception is thrown - if (!valid) - err.jspError(start, "jsp.error.mandatory.attribute", typeOfTag, - missingAttribute); - - // Check to see if there are any more attributes for the specified tag. - int attrLeftLength = temp.size(); - if (attrLeftLength == 0) - return; - - // Now check to see if the rest of the attributes are valid too. - String attribute = null; - - for (int j = 0; j < attrLeftLength; j++) { - valid = false; - attribute = (String) temp.elementAt(j); - for (int i = 0; i < validAttributes.length; i++) { - if (attribute.equals(validAttributes[i].name)) { - valid = true; - break; - } - } - if (!valid) - err.jspError(start, "jsp.error.invalid.attribute", typeOfTag, - attribute); - } - // XXX *could* move EL-syntax validation here... (sb) - } - - public static String escapeQueryString(String unescString) { - if ( unescString == null ) - return null; - - String escString = ""; - String shellSpChars = "\\\""; - - for(int index=0; index') { - sb.append(">"); - } else if (c == '\'') { - sb.append("'"); - } else if (c == '&') { - sb.append("&"); - } else if (c == '"') { - sb.append("""); - } else { - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Replaces any occurrences of the character replace with the - * string with. - */ - public static String replace(String name, char replace, String with) { - StringBuffer buf = new StringBuffer(); - int begin = 0; - int end; - int last = name.length(); - - while (true) { - end = name.indexOf(replace, begin); - if (end < 0) { - end = last; - } - buf.append(name.substring(begin, end)); - if (end == last) { - break; - } - buf.append(with); - begin = end + 1; - } - - return buf.toString(); - } - - public static class ValidAttribute { - String name; - boolean mandatory; - boolean rtexprvalue; // not used now - - public ValidAttribute (String name, boolean mandatory, - boolean rtexprvalue ) - { - this.name = name; - this.mandatory = mandatory; - this.rtexprvalue = rtexprvalue; - } - - public ValidAttribute (String name, boolean mandatory) { - this( name, mandatory, false ); - } - - public ValidAttribute (String name) { - this (name, false); - } - } - - /** - * Convert a String value to 'boolean'. - * Besides the standard conversions done by - * Boolean.valueOf(s).booleanValue(), the value "yes" - * (ignore case) is also converted to 'true'. - * If 's' is null, then 'false' is returned. - * - * @param s the string to be converted - * @return the boolean value associated with the string s - */ - public static boolean booleanValue(String s) { - boolean b = false; - if (s != null) { - if (s.equalsIgnoreCase("yes")) { - b = true; - } else { - b = Boolean.valueOf(s).booleanValue(); - } - } - return b; - } - - /** - * Returns the Class object associated with the class or - * interface with the given string name. - * - *

        The Class object is determined by passing the given string - * name to the Class.forName() method, unless the given string - * name represents a primitive type, in which case it is converted to a - * Class object by appending ".class" to it (e.g., "int.class"). - */ - public static Class toClass(String type, ClassLoader loader) - throws ClassNotFoundException { - - Class c = null; - int i0 = type.indexOf('['); - int dims = 0; - if (i0 > 0) { - // This is an array. Count the dimensions - for (int i = 0; i < type.length(); i++) { - if (type.charAt(i) == '[') - dims++; - } - type = type.substring(0, i0); - } - - if ("boolean".equals(type)) - c = boolean.class; - else if ("char".equals(type)) - c = char.class; - else if ("byte".equals(type)) - c = byte.class; - else if ("short".equals(type)) - c = short.class; - else if ("int".equals(type)) - c = int.class; - else if ("long".equals(type)) - c = long.class; - else if ("float".equals(type)) - c = float.class; - else if ("double".equals(type)) - c = double.class; - else if (type.indexOf('[') < 0) - c = loader.loadClass(type); - - if (dims == 0) - return c; - - if (dims == 1) - return java.lang.reflect.Array.newInstance(c, 1).getClass(); - - // Array of more than i dimension - return java.lang.reflect.Array.newInstance(c, new int[dims]).getClass(); - } - - /** - * Produces a String representing a call to the EL interpreter. - * @param expression a String containing zero or more "${}" expressions - * @param expectedType the expected type of the interpreted result - * @param fnmapvar Variable pointing to a function map. - * @param XmlEscape True if the result should do XML escaping - * @return a String representing a call to the EL interpreter. - */ - public static String interpreterCall(boolean isTagFile, - String expression, - Class expectedType, - String fnmapvar, - boolean XmlEscape ) - { - /* - * Determine which context object to use. - */ - String jspCtxt = null; - if (isTagFile) - jspCtxt = "this.getJspContext()"; - else - jspCtxt = "_jspx_page_context"; - - /* - * Determine whether to use the expected type's textual name - * or, if it's a primitive, the name of its correspondent boxed - * type. - */ - String targetType = expectedType.getName(); - String primitiveConverterMethod = null; - if (expectedType.isPrimitive()) { - if (expectedType.equals(Boolean.TYPE)) { - targetType = Boolean.class.getName(); - primitiveConverterMethod = "booleanValue"; - } else if (expectedType.equals(Byte.TYPE)) { - targetType = Byte.class.getName(); - primitiveConverterMethod = "byteValue"; - } else if (expectedType.equals(Character.TYPE)) { - targetType = Character.class.getName(); - primitiveConverterMethod = "charValue"; - } else if (expectedType.equals(Short.TYPE)) { - targetType = Short.class.getName(); - primitiveConverterMethod = "shortValue"; - } else if (expectedType.equals(Integer.TYPE)) { - targetType = Integer.class.getName(); - primitiveConverterMethod = "intValue"; - } else if (expectedType.equals(Long.TYPE)) { - targetType = Long.class.getName(); - primitiveConverterMethod = "longValue"; - } else if (expectedType.equals(Float.TYPE)) { - targetType = Float.class.getName(); - primitiveConverterMethod = "floatValue"; - } else if (expectedType.equals(Double.TYPE)) { - targetType = Double.class.getName(); - primitiveConverterMethod = "doubleValue"; - } - } - - if (primitiveConverterMethod != null) { - XmlEscape = false; - } - - /* - * Build up the base call to the interpreter. - */ - // XXX - We use a proprietary call to the interpreter for now - // as the current standard machinery is inefficient and requires - // lots of wrappers and adapters. This should all clear up once - // the EL interpreter moves out of JSTL and into its own project. - // In the future, this should be replaced by code that calls - // ExpressionEvaluator.parseExpression() and then cache the resulting - // expression objects. The interpreterCall would simply select - // one of the pre-cached expressions and evaluate it. - // Note that PageContextImpl implements VariableResolver and - // the generated Servlet/SimpleTag implements FunctionMapper, so - // that machinery is already in place (mroth). - targetType = toJavaSourceType(targetType); - StringBuffer call = new StringBuffer( - "(" + targetType + ") " - + "org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate" - + "(" + Generator.quote(expression) + ", " - + targetType + ".class, " - + "(PageContext)" + jspCtxt - + ", " + fnmapvar - + ", " + XmlEscape - + ")"); - - /* - * Add the primitive converter method if we need to. - */ - if (primitiveConverterMethod != null) { - call.insert(0, "("); - call.append(")." + primitiveConverterMethod + "()"); - } - - return call.toString(); - } - - /** - * Validates the syntax of all ${} expressions within the given string. - * @param where the approximate location of the expressions in the JSP page - * @param expressions a string containing zero or more "${}" expressions - * @param err an error dispatcher to use - * @deprecated now delegated to the org.apache.el Package - */ - public static void validateExpressions(Mark where, - String expressions, - Class expectedType, - FunctionMapper functionMapper, - ErrorDispatcher err) - throws JasperException { - -// try { -// -// JspUtil.expressionEvaluator.parseExpression( expressions, -// expectedType, functionMapper ); -// } -// catch( ELParseException e ) { -// err.jspError(where, "jsp.error.invalid.expression", expressions, -// e.toString() ); -// } -// catch( ELException e ) { -// err.jspError(where, "jsp.error.invalid.expression", expressions, -// e.toString() ); -// } - } - - /** - * Resets the temporary variable name. - * (not thread-safe) - */ - public static void resetTemporaryVariableName() { - tempSequenceNumber = 0; - } - - /** - * Generates a new temporary variable name. - * (not thread-safe) - */ - public static String nextTemporaryVariableName() { - return Constants.TEMP_VARIABLE_NAME_PREFIX + (tempSequenceNumber++); - } - - public static String coerceToPrimitiveBoolean(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToBoolean(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "false"; - else - return Boolean.valueOf(s).toString(); - } - } - - public static String coerceToBoolean(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Boolean) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Boolean.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Boolean(false)"; - } else { - // Detect format error at translation time - return "new Boolean(" + Boolean.valueOf(s).toString() + ")"; - } - } - } - - public static String coerceToPrimitiveByte(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToByte(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "(byte) 0"; - else - return "((byte)" + Byte.valueOf(s).toString() + ")"; - } - } - - public static String coerceToByte(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Byte) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Byte.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Byte((byte) 0)"; - } else { - // Detect format error at translation time - return "new Byte((byte)" + Byte.valueOf(s).toString() + ")"; - } - } - } - - public static String coerceToChar(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToChar(" + s + ")"; - } else { - if (s == null || s.length() == 0) { - return "(char) 0"; - } else { - char ch = s.charAt(0); - // this trick avoids escaping issues - return "((char) " + (int) ch + ")"; - } - } - } - - public static String coerceToCharacter(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Character) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Character.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Character((char) 0)"; - } else { - char ch = s.charAt(0); - // this trick avoids escaping issues - return "new Character((char) " + (int) ch + ")"; - } - } - } - - public static String coerceToPrimitiveDouble(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToDouble(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "(double) 0"; - else - return Double.valueOf(s).toString(); - } - } - - public static String coerceToDouble(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Double) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Double.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Double(0)"; - } else { - // Detect format error at translation time - return "new Double(" + Double.valueOf(s).toString() + ")"; - } - } - } - - public static String coerceToPrimitiveFloat(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToFloat(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "(float) 0"; - else - return Float.valueOf(s).toString() + "f"; - } - } - - public static String coerceToFloat(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Float) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Float.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Float(0)"; - } else { - // Detect format error at translation time - return "new Float(" + Float.valueOf(s).toString() + "f)"; - } - } - } - - public static String coerceToInt(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToInt(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "0"; - else - return Integer.valueOf(s).toString(); - } - } - - public static String coerceToInteger(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Integer) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Integer.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Integer(0)"; - } else { - // Detect format error at translation time - return "new Integer(" + Integer.valueOf(s).toString() + ")"; - } - } - } - - public static String coerceToPrimitiveShort(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToShort(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "(short) 0"; - else - return "((short) " + Short.valueOf(s).toString() + ")"; - } - } - - public static String coerceToShort(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Short) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Short.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Short((short) 0)"; - } else { - // Detect format error at translation time - return "new Short(\"" + Short.valueOf(s).toString() + "\")"; - } - } - } - - public static String coerceToPrimitiveLong(String s, - boolean isNamedAttribute) { - if (isNamedAttribute) { - return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToLong(" + s + ")"; - } else { - if (s == null || s.length() == 0) - return "(long) 0"; - else - return Long.valueOf(s).toString() + "l"; - } - } - - public static String coerceToLong(String s, boolean isNamedAttribute) { - if (isNamedAttribute) { - return "(Long) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Long.class)"; - } else { - if (s == null || s.length() == 0) { - return "new Long(0)"; - } else { - // Detect format error at translation time - return "new Long(" + Long.valueOf(s).toString() + "l)"; - } - } - } - - public static InputStream getInputStream(String fname, JarFile jarFile, - JspCompilationContext ctxt, - ErrorDispatcher err) - throws JasperException, IOException { - - InputStream in = null; - - if (jarFile != null) { - String jarEntryName = fname.substring(1, fname.length()); - ZipEntry jarEntry = jarFile.getEntry(jarEntryName); - if (jarEntry == null) { - err.jspError("jsp.error.file.not.found", fname); - } - in = jarFile.getInputStream(jarEntry); - } else { - in = ctxt.getResourceAsStream(fname); - } - - if (in == null) { - err.jspError("jsp.error.file.not.found", fname); - } - - return in; - } - - /** - * Gets the fully-qualified class name of the tag handler corresponding to - * the given tag file path. - * - * @param path Tag file path - * @param err Error dispatcher - * - * @return Fully-qualified class name of the tag handler corresponding to - * the given tag file path - */ - public static String getTagHandlerClassName(String path, - ErrorDispatcher err) - throws JasperException { - - String className = null; - int begin = 0; - int index; - - index = path.lastIndexOf(".tag"); - if (index == -1) { - err.jspError("jsp.error.tagfile.badSuffix", path); - } - - //It's tempting to remove the ".tag" suffix here, but we can't. - //If we remove it, the fully-qualified class name of this tag - //could conflict with the package name of other tags. - //For instance, the tag file - // /WEB-INF/tags/foo.tag - //would have fully-qualified class name - // org.apache.jsp.tag.web.foo - //which would conflict with the package name of the tag file - // /WEB-INF/tags/foo/bar.tag - - index = path.indexOf(WEB_INF_TAGS); - if (index != -1) { - className = "org.apache.jsp.tag.web."; - begin = index + WEB_INF_TAGS.length(); - } else { - index = path.indexOf(META_INF_TAGS); - if (index != -1) { - className = "org.apache.jsp.tag.meta."; - begin = index + META_INF_TAGS.length(); - } else { - err.jspError("jsp.error.tagfile.illegalPath", path); - } - } - - className += makeJavaPackage(path.substring(begin)); - - return className; - } - - /** - * Converts the given path to a Java package or fully-qualified class name - * - * @param path Path to convert - * - * @return Java package corresponding to the given path - */ - public static final String makeJavaPackage(String path) { - String classNameComponents[] = split(path,"/"); - StringBuffer legalClassNames = new StringBuffer(); - for (int i = 0; i < classNameComponents.length; i++) { - legalClassNames.append(makeJavaIdentifier(classNameComponents[i])); - if (i < classNameComponents.length - 1) { - legalClassNames.append('.'); - } - } - return legalClassNames.toString(); - } - - /** - * Splits a string into it's components. - * @param path String to split - * @param pat Pattern to split at - * @return the components of the path - */ - private static final String [] split(String path, String pat) { - Vector comps = new Vector(); - int pos = path.indexOf(pat); - int start = 0; - while( pos >= 0 ) { - if(pos > start ) { - String comp = path.substring(start,pos); - comps.add(comp); - } - start = pos + pat.length(); - pos = path.indexOf(pat,start); - } - if( start < path.length()) { - comps.add(path.substring(start)); - } - String [] result = new String[comps.size()]; - for(int i=0; i < comps.size(); i++) { - result[i] = (String)comps.elementAt(i); - } - return result; - } - - /** - * Converts the given identifier to a legal Java identifier - * - * @param identifier Identifier to convert - * - * @return Legal Java identifier corresponding to the given identifier - */ - public static final String makeJavaIdentifier(String identifier) { - StringBuffer modifiedIdentifier = - new StringBuffer(identifier.length()); - if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { - modifiedIdentifier.append('_'); - } - for (int i = 0; i < identifier.length(); i++) { - char ch = identifier.charAt(i); - if (Character.isJavaIdentifierPart(ch) && ch != '_') { - modifiedIdentifier.append(ch); - } else if (ch == '.') { - modifiedIdentifier.append('_'); - } else { - modifiedIdentifier.append(mangleChar(ch)); - } - } - if (isJavaKeyword(modifiedIdentifier.toString())) { - modifiedIdentifier.append('_'); - } - return modifiedIdentifier.toString(); - } - - /** - * Mangle the specified character to create a legal Java class name. - */ - public static final String mangleChar(char ch) { - char[] result = new char[5]; - result[0] = '_'; - result[1] = Character.forDigit((ch >> 12) & 0xf, 16); - result[2] = Character.forDigit((ch >> 8) & 0xf, 16); - result[3] = Character.forDigit((ch >> 4) & 0xf, 16); - result[4] = Character.forDigit(ch & 0xf, 16); - return new String(result); - } - - /** - * Test whether the argument is a Java keyword - */ - public static boolean isJavaKeyword(String key) { - int i = 0; - int j = javaKeywords.length; - while (i < j) { - int k = (i+j)/2; - int result = javaKeywords[k].compareTo(key); - if (result == 0) { - return true; - } - if (result < 0) { - i = k+1; - } else { - j = k; - } - } - return false; - } - - /** - * Converts the given Xml name to a legal Java identifier. This is - * slightly more efficient than makeJavaIdentifier in that we only need - * to worry about '.', '-', and ':' in the string. We also assume that - * the resultant string is further concatenated with some prefix string - * so that we don't have to worry about it being a Java key word. - * - * @param name Identifier to convert - * - * @return Legal Java identifier corresponding to the given identifier - */ - public static final String makeXmlJavaIdentifier(String name) { - if (name.indexOf('-') >= 0) - name = replace(name, '-', "$1"); - if (name.indexOf('.') >= 0) - name = replace(name, '.', "$2"); - if (name.indexOf(':') >= 0) - name = replace(name, ':', "$3"); - return name; - } - - static InputStreamReader getReader(String fname, String encoding, - JarFile jarFile, - JspCompilationContext ctxt, - ErrorDispatcher err) - throws JasperException, IOException { - - InputStreamReader reader = null; - InputStream in = getInputStream(fname, jarFile, ctxt, err); - - try { - reader = new InputStreamReader(in, encoding); - } catch (UnsupportedEncodingException ex) { - err.jspError("jsp.error.unsupported.encoding", encoding); - } - - return reader; - } - - /** - * Handles taking input from TLDs - * 'java.lang.Object' -> 'java.lang.Object.class' - * 'int' -> 'int.class' - * 'void' -> 'Void.TYPE' - * 'int[]' -> 'int[].class' - * - * @param type - * @return - */ - public static String toJavaSourceTypeFromTld(String type) { - if (type == null || "void".equals(type)) { - return "Void.TYPE"; - } - return type + ".class"; - } - - /** - * Class.getName() return arrays in the form "[[[", where et, - * the element type can be one of ZBCDFIJS or L; - * It is converted into forms that can be understood by javac. - */ - public static String toJavaSourceType(String type) { - - if (type.charAt(0) != '[') { - return type; - } - - int dims = 1; - String t = null; - for (int i = 1; i < type.length(); i++) { - if (type.charAt(i) == '[') { - dims++; - } else { - switch (type.charAt(i)) { - case 'Z': t = "boolean"; break; - case 'B': t = "byte"; break; - case 'C': t = "char"; break; - case 'D': t = "double"; break; - case 'F': t = "float"; break; - case 'I': t = "int"; break; - case 'J': t = "long"; break; - case 'S': t = "short"; break; - case 'L': t = type.substring(i+1, type.indexOf(';')); break; - } - break; - } - } - StringBuffer resultType = new StringBuffer(t); - for (; dims > 0; dims--) { - resultType.append("[]"); - } - return resultType.toString(); - } - - /** - * Compute the canonical name from a Class instance. Note that a - * simple replacment of '$' with '.' of a binary name would not work, - * as '$' is a legal Java Identifier character. - * @param c A instance of java.lang.Class - * @return The canonical name of c. - */ - public static String getCanonicalName(Class c) { - - String binaryName = c.getName(); - c = c.getDeclaringClass(); - - if (c == null) { - return binaryName; - } - - StringBuffer buf = new StringBuffer(binaryName); - do { - buf.setCharAt(c.getName().length(), '.'); - c = c.getDeclaringClass(); - } while ( c != null); - - return buf.toString(); - } +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.Vector; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +import javax.el.FunctionMapper; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.ELParseException; +import javax.servlet.jsp.el.ExpressionEvaluator; + + +import org.apache.el.ExpressionFactoryImpl; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.el.ExpressionEvaluatorImpl; +import org.xml.sax.Attributes; + +/** + * This class has all the utility method(s). + * Ideally should move all the bean containers here. + * + * @author Mandar Raje. + * @author Rajiv Mordani. + * @author Danno Ferrin + * @author Pierre Delisle + * @author Shawn Bayern + * @author Mark Roth + */ +public class JspUtil { + + private static final String WEB_INF_TAGS = "/WEB-INF/tags/"; + private static final String META_INF_TAGS = "/META-INF/tags/"; + + // Delimiters for request-time expressions (JSP and XML syntax) + private static final String OPEN_EXPR = "<%="; + private static final String CLOSE_EXPR = "%>"; + private static final String OPEN_EXPR_XML = "%="; + private static final String CLOSE_EXPR_XML = "%"; + + private static int tempSequenceNumber = 0; + + //private static ExpressionEvaluatorImpl expressionEvaluator + //= new ExpressionEvaluatorImpl(); + + //tc6 + private final static ExpressionEvaluator expressionEvaluator = + new ExpressionEvaluatorImpl(new ExpressionFactoryImpl()); + + private static final String javaKeywords[] = { + "abstract", "assert", "boolean", "break", "byte", "case", + "catch", "char", "class", "const", "continue", + "default", "do", "double", "else", "enum", "extends", + "final", "finally", "float", "for", "goto", + "if", "implements", "import", "instanceof", "int", + "interface", "long", "native", "new", "package", + "private", "protected", "public", "return", "short", + "static", "strictfp", "super", "switch", "synchronized", + "this", "throws", "transient", "try", "void", + "volatile", "while" }; + + public static final int CHUNKSIZE = 1024; + + public static char[] removeQuotes(char []chars) { + CharArrayWriter caw = new CharArrayWriter(); + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '%' && chars[i+1] == '\\' && + chars[i+2] == '>') { + caw.write('%'); + caw.write('>'); + i = i + 2; + } else { + caw.write(chars[i]); + } + } + return caw.toCharArray(); + } + + public static char[] escapeQuotes (char []chars) { + // Prescan to convert %\> to %> + String s = new String(chars); + while (true) { + int n = s.indexOf("%\\>"); + if (n < 0) + break; + StringBuffer sb = new StringBuffer(s.substring(0, n)); + sb.append("%>"); + sb.append(s.substring(n + 3)); + s = sb.toString(); + } + chars = s.toCharArray(); + return (chars); + + + // Escape all backslashes not inside a Java string literal + /* + CharArrayWriter caw = new CharArrayWriter(); + boolean inJavaString = false; + for (int i = 0; i < chars.length; i++) { + if (chars[i] == '"') inJavaString = !inJavaString; + // escape out the escape character + if (!inJavaString && (chars[i] == '\\')) caw.write('\\'); + caw.write(chars[i]); + } + return caw.toCharArray(); + */ + } + + /** + * Checks if the token is a runtime expression. + * In standard JSP syntax, a runtime expression starts with '<%' and + * ends with '%>'. When the JSP document is in XML syntax, a runtime + * expression starts with '%=' and ends with '%'. + * + * @param token The token to be checked + * return whether the token is a runtime expression or not. + */ + public static boolean isExpression(String token, boolean isXml) { + String openExpr; + String closeExpr; + if (isXml) { + openExpr = OPEN_EXPR_XML; + closeExpr = CLOSE_EXPR_XML; + } else { + openExpr = OPEN_EXPR; + closeExpr = CLOSE_EXPR; + } + if (token.startsWith(openExpr) && token.endsWith(closeExpr)) { + return true; + } else { + return false; + } + } + + /** + * @return the "expression" part of a runtime expression, + * taking the delimiters out. + */ + public static String getExpr (String expression, boolean isXml) { + String returnString; + String openExpr; + String closeExpr; + if (isXml) { + openExpr = OPEN_EXPR_XML; + closeExpr = CLOSE_EXPR_XML; + } else { + openExpr = OPEN_EXPR; + closeExpr = CLOSE_EXPR; + } + int length = expression.length(); + if (expression.startsWith(openExpr) && + expression.endsWith(closeExpr)) { + returnString = expression.substring( + openExpr.length(), length - closeExpr.length()); + } else { + returnString = ""; + } + return returnString; + } + + /** + * Takes a potential expression and converts it into XML form + */ + public static String getExprInXml(String expression) { + String returnString; + int length = expression.length(); + + if (expression.startsWith(OPEN_EXPR) + && expression.endsWith(CLOSE_EXPR)) { + returnString = expression.substring (1, length - 1); + } else { + returnString = expression; + } + + return escapeXml(returnString.replace(Constants.ESC, '$')); + } + + /** + * Checks to see if the given scope is valid. + * + * @param scope The scope to be checked + * @param n The Node containing the 'scope' attribute whose value is to be + * checked + * @param err error dispatcher + * + * @throws JasperException if scope is not null and different from + * "page", "request", "session", and + * "application" + */ + public static void checkScope(String scope, Node n, ErrorDispatcher err) + throws JasperException { + if (scope != null && !scope.equals("page") && !scope.equals("request") + && !scope.equals("session") && !scope.equals("application")) { + err.jspError(n, "jsp.error.invalid.scope", scope); + } + } + + /** + * Checks if all mandatory attributes are present and if all attributes + * present have valid names. Checks attributes specified as XML-style + * attributes as well as attributes specified using the jsp:attribute + * standard action. + */ + public static void checkAttributes(String typeOfTag, + Node n, + ValidAttribute[] validAttributes, + ErrorDispatcher err) + throws JasperException { + Attributes attrs = n.getAttributes(); + Mark start = n.getStart(); + boolean valid = true; + + // AttributesImpl.removeAttribute is broken, so we do this... + int tempLength = (attrs == null) ? 0 : attrs.getLength(); + Vector temp = new Vector(tempLength, 1); + for (int i = 0; i < tempLength; i++) { + String qName = attrs.getQName(i); + if ((!qName.equals("xmlns")) && (!qName.startsWith("xmlns:"))) + temp.addElement(qName); + } + + // Add names of attributes specified using jsp:attribute + Node.Nodes tagBody = n.getBody(); + if( tagBody != null ) { + int numSubElements = tagBody.size(); + for( int i = 0; i < numSubElements; i++ ) { + Node node = tagBody.getNode( i ); + if( node instanceof Node.NamedAttribute ) { + String attrName = node.getAttributeValue( "name" ); + temp.addElement( attrName ); + // Check if this value appear in the attribute of the node + if (n.getAttributeValue(attrName) != null) { + err.jspError(n, "jsp.error.duplicate.name.jspattribute", + attrName); + } + } + else { + // Nothing can come before jsp:attribute, and only + // jsp:body can come after it. + break; + } + } + } + + /* + * First check to see if all the mandatory attributes are present. + * If so only then proceed to see if the other attributes are valid + * for the particular tag. + */ + String missingAttribute = null; + + for (int i = 0; i < validAttributes.length; i++) { + int attrPos; + if (validAttributes[i].mandatory) { + attrPos = temp.indexOf(validAttributes[i].name); + if (attrPos != -1) { + temp.remove(attrPos); + valid = true; + } else { + valid = false; + missingAttribute = validAttributes[i].name; + break; + } + } + } + + // If mandatory attribute is missing then the exception is thrown + if (!valid) + err.jspError(start, "jsp.error.mandatory.attribute", typeOfTag, + missingAttribute); + + // Check to see if there are any more attributes for the specified tag. + int attrLeftLength = temp.size(); + if (attrLeftLength == 0) + return; + + // Now check to see if the rest of the attributes are valid too. + String attribute = null; + + for (int j = 0; j < attrLeftLength; j++) { + valid = false; + attribute = (String) temp.elementAt(j); + for (int i = 0; i < validAttributes.length; i++) { + if (attribute.equals(validAttributes[i].name)) { + valid = true; + break; + } + } + if (!valid) + err.jspError(start, "jsp.error.invalid.attribute", typeOfTag, + attribute); + } + // XXX *could* move EL-syntax validation here... (sb) + } + + public static String escapeQueryString(String unescString) { + if ( unescString == null ) + return null; + + String escString = ""; + String shellSpChars = "\\\""; + + for(int index=0; index') { + sb.append(">"); + } else if (c == '\'') { + sb.append("'"); + } else if (c == '&') { + sb.append("&"); + } else if (c == '"') { + sb.append("""); + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Replaces any occurrences of the character replace with the + * string with. + */ + public static String replace(String name, char replace, String with) { + StringBuffer buf = new StringBuffer(); + int begin = 0; + int end; + int last = name.length(); + + while (true) { + end = name.indexOf(replace, begin); + if (end < 0) { + end = last; + } + buf.append(name.substring(begin, end)); + if (end == last) { + break; + } + buf.append(with); + begin = end + 1; + } + + return buf.toString(); + } + + public static class ValidAttribute { + String name; + boolean mandatory; + boolean rtexprvalue; // not used now + + public ValidAttribute (String name, boolean mandatory, + boolean rtexprvalue ) + { + this.name = name; + this.mandatory = mandatory; + this.rtexprvalue = rtexprvalue; + } + + public ValidAttribute (String name, boolean mandatory) { + this( name, mandatory, false ); + } + + public ValidAttribute (String name) { + this (name, false); + } + } + + /** + * Convert a String value to 'boolean'. + * Besides the standard conversions done by + * Boolean.valueOf(s).booleanValue(), the value "yes" + * (ignore case) is also converted to 'true'. + * If 's' is null, then 'false' is returned. + * + * @param s the string to be converted + * @return the boolean value associated with the string s + */ + public static boolean booleanValue(String s) { + boolean b = false; + if (s != null) { + if (s.equalsIgnoreCase("yes")) { + b = true; + } else { + b = Boolean.valueOf(s).booleanValue(); + } + } + return b; + } + + /** + * Returns the Class object associated with the class or + * interface with the given string name. + * + *

        The Class object is determined by passing the given string + * name to the Class.forName() method, unless the given string + * name represents a primitive type, in which case it is converted to a + * Class object by appending ".class" to it (e.g., "int.class"). + */ + public static Class toClass(String type, ClassLoader loader) + throws ClassNotFoundException { + + Class c = null; + int i0 = type.indexOf('['); + int dims = 0; + if (i0 > 0) { + // This is an array. Count the dimensions + for (int i = 0; i < type.length(); i++) { + if (type.charAt(i) == '[') + dims++; + } + type = type.substring(0, i0); + } + + if ("boolean".equals(type)) + c = boolean.class; + else if ("char".equals(type)) + c = char.class; + else if ("byte".equals(type)) + c = byte.class; + else if ("short".equals(type)) + c = short.class; + else if ("int".equals(type)) + c = int.class; + else if ("long".equals(type)) + c = long.class; + else if ("float".equals(type)) + c = float.class; + else if ("double".equals(type)) + c = double.class; + else if (type.indexOf('[') < 0) + c = loader.loadClass(type); + + if (dims == 0) + return c; + + if (dims == 1) + return java.lang.reflect.Array.newInstance(c, 1).getClass(); + + // Array of more than i dimension + return java.lang.reflect.Array.newInstance(c, new int[dims]).getClass(); + } + + /** + * Produces a String representing a call to the EL interpreter. + * @param expression a String containing zero or more "${}" expressions + * @param expectedType the expected type of the interpreted result + * @param fnmapvar Variable pointing to a function map. + * @param XmlEscape True if the result should do XML escaping + * @return a String representing a call to the EL interpreter. + */ + public static String interpreterCall(boolean isTagFile, + String expression, + Class expectedType, + String fnmapvar, + boolean XmlEscape ) + { + /* + * Determine which context object to use. + */ + String jspCtxt = null; + if (isTagFile) + jspCtxt = "this.getJspContext()"; + else + jspCtxt = "_jspx_page_context"; + + /* + * Determine whether to use the expected type's textual name + * or, if it's a primitive, the name of its correspondent boxed + * type. + */ + String targetType = expectedType.getName(); + String primitiveConverterMethod = null; + if (expectedType.isPrimitive()) { + if (expectedType.equals(Boolean.TYPE)) { + targetType = Boolean.class.getName(); + primitiveConverterMethod = "booleanValue"; + } else if (expectedType.equals(Byte.TYPE)) { + targetType = Byte.class.getName(); + primitiveConverterMethod = "byteValue"; + } else if (expectedType.equals(Character.TYPE)) { + targetType = Character.class.getName(); + primitiveConverterMethod = "charValue"; + } else if (expectedType.equals(Short.TYPE)) { + targetType = Short.class.getName(); + primitiveConverterMethod = "shortValue"; + } else if (expectedType.equals(Integer.TYPE)) { + targetType = Integer.class.getName(); + primitiveConverterMethod = "intValue"; + } else if (expectedType.equals(Long.TYPE)) { + targetType = Long.class.getName(); + primitiveConverterMethod = "longValue"; + } else if (expectedType.equals(Float.TYPE)) { + targetType = Float.class.getName(); + primitiveConverterMethod = "floatValue"; + } else if (expectedType.equals(Double.TYPE)) { + targetType = Double.class.getName(); + primitiveConverterMethod = "doubleValue"; + } + } + + if (primitiveConverterMethod != null) { + XmlEscape = false; + } + + /* + * Build up the base call to the interpreter. + */ + // XXX - We use a proprietary call to the interpreter for now + // as the current standard machinery is inefficient and requires + // lots of wrappers and adapters. This should all clear up once + // the EL interpreter moves out of JSTL and into its own project. + // In the future, this should be replaced by code that calls + // ExpressionEvaluator.parseExpression() and then cache the resulting + // expression objects. The interpreterCall would simply select + // one of the pre-cached expressions and evaluate it. + // Note that PageContextImpl implements VariableResolver and + // the generated Servlet/SimpleTag implements FunctionMapper, so + // that machinery is already in place (mroth). + targetType = toJavaSourceType(targetType); + StringBuffer call = new StringBuffer( + "(" + targetType + ") " + + "org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate" + + "(" + Generator.quote(expression) + ", " + + targetType + ".class, " + + "(PageContext)" + jspCtxt + + ", " + fnmapvar + + ", " + XmlEscape + + ")"); + + /* + * Add the primitive converter method if we need to. + */ + if (primitiveConverterMethod != null) { + call.insert(0, "("); + call.append(")." + primitiveConverterMethod + "()"); + } + + return call.toString(); + } + + /** + * Validates the syntax of all ${} expressions within the given string. + * @param where the approximate location of the expressions in the JSP page + * @param expressions a string containing zero or more "${}" expressions + * @param err an error dispatcher to use + * @deprecated now delegated to the org.apache.el Package + */ + public static void validateExpressions(Mark where, + String expressions, + Class expectedType, + FunctionMapper functionMapper, + ErrorDispatcher err) + throws JasperException { + +// try { +// +// JspUtil.expressionEvaluator.parseExpression( expressions, +// expectedType, functionMapper ); +// } +// catch( ELParseException e ) { +// err.jspError(where, "jsp.error.invalid.expression", expressions, +// e.toString() ); +// } +// catch( ELException e ) { +// err.jspError(where, "jsp.error.invalid.expression", expressions, +// e.toString() ); +// } + } + + /** + * Resets the temporary variable name. + * (not thread-safe) + */ + public static void resetTemporaryVariableName() { + tempSequenceNumber = 0; + } + + /** + * Generates a new temporary variable name. + * (not thread-safe) + */ + public static String nextTemporaryVariableName() { + return Constants.TEMP_VARIABLE_NAME_PREFIX + (tempSequenceNumber++); + } + + public static String coerceToPrimitiveBoolean(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToBoolean(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "false"; + else + return Boolean.valueOf(s).toString(); + } + } + + public static String coerceToBoolean(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Boolean) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Boolean.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Boolean(false)"; + } else { + // Detect format error at translation time + return "new Boolean(" + Boolean.valueOf(s).toString() + ")"; + } + } + } + + public static String coerceToPrimitiveByte(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToByte(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "(byte) 0"; + else + return "((byte)" + Byte.valueOf(s).toString() + ")"; + } + } + + public static String coerceToByte(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Byte) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Byte.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Byte((byte) 0)"; + } else { + // Detect format error at translation time + return "new Byte((byte)" + Byte.valueOf(s).toString() + ")"; + } + } + } + + public static String coerceToChar(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToChar(" + s + ")"; + } else { + if (s == null || s.length() == 0) { + return "(char) 0"; + } else { + char ch = s.charAt(0); + // this trick avoids escaping issues + return "((char) " + (int) ch + ")"; + } + } + } + + public static String coerceToCharacter(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Character) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Character.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Character((char) 0)"; + } else { + char ch = s.charAt(0); + // this trick avoids escaping issues + return "new Character((char) " + (int) ch + ")"; + } + } + } + + public static String coerceToPrimitiveDouble(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToDouble(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "(double) 0"; + else + return Double.valueOf(s).toString(); + } + } + + public static String coerceToDouble(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Double) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Double.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Double(0)"; + } else { + // Detect format error at translation time + return "new Double(" + Double.valueOf(s).toString() + ")"; + } + } + } + + public static String coerceToPrimitiveFloat(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToFloat(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "(float) 0"; + else + return Float.valueOf(s).toString() + "f"; + } + } + + public static String coerceToFloat(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Float) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Float.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Float(0)"; + } else { + // Detect format error at translation time + return "new Float(" + Float.valueOf(s).toString() + "f)"; + } + } + } + + public static String coerceToInt(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToInt(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "0"; + else + return Integer.valueOf(s).toString(); + } + } + + public static String coerceToInteger(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Integer) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Integer.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Integer(0)"; + } else { + // Detect format error at translation time + return "new Integer(" + Integer.valueOf(s).toString() + ")"; + } + } + } + + public static String coerceToPrimitiveShort(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToShort(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "(short) 0"; + else + return "((short) " + Short.valueOf(s).toString() + ")"; + } + } + + public static String coerceToShort(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Short) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Short.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Short((short) 0)"; + } else { + // Detect format error at translation time + return "new Short(\"" + Short.valueOf(s).toString() + "\")"; + } + } + } + + public static String coerceToPrimitiveLong(String s, + boolean isNamedAttribute) { + if (isNamedAttribute) { + return "org.apache.jasper.runtime.JspRuntimeLibrary.coerceToLong(" + s + ")"; + } else { + if (s == null || s.length() == 0) + return "(long) 0"; + else + return Long.valueOf(s).toString() + "l"; + } + } + + public static String coerceToLong(String s, boolean isNamedAttribute) { + if (isNamedAttribute) { + return "(Long) org.apache.jasper.runtime.JspRuntimeLibrary.coerce(" + s + ", Long.class)"; + } else { + if (s == null || s.length() == 0) { + return "new Long(0)"; + } else { + // Detect format error at translation time + return "new Long(" + Long.valueOf(s).toString() + "l)"; + } + } + } + + public static InputStream getInputStream(String fname, JarFile jarFile, + JspCompilationContext ctxt, + ErrorDispatcher err) + throws JasperException, IOException { + + InputStream in = null; + + if (jarFile != null) { + String jarEntryName = fname.substring(1, fname.length()); + ZipEntry jarEntry = jarFile.getEntry(jarEntryName); + if (jarEntry == null) { + err.jspError("jsp.error.file.not.found", fname); + } + in = jarFile.getInputStream(jarEntry); + } else { + in = ctxt.getResourceAsStream(fname); + } + + if (in == null) { + err.jspError("jsp.error.file.not.found", fname); + } + + return in; + } + + /** + * Gets the fully-qualified class name of the tag handler corresponding to + * the given tag file path. + * + * @param path Tag file path + * @param err Error dispatcher + * + * @return Fully-qualified class name of the tag handler corresponding to + * the given tag file path + */ + public static String getTagHandlerClassName(String path, + ErrorDispatcher err) + throws JasperException { + + String className = null; + int begin = 0; + int index; + + index = path.lastIndexOf(".tag"); + if (index == -1) { + err.jspError("jsp.error.tagfile.badSuffix", path); + } + + //It's tempting to remove the ".tag" suffix here, but we can't. + //If we remove it, the fully-qualified class name of this tag + //could conflict with the package name of other tags. + //For instance, the tag file + // /WEB-INF/tags/foo.tag + //would have fully-qualified class name + // org.apache.jsp.tag.web.foo + //which would conflict with the package name of the tag file + // /WEB-INF/tags/foo/bar.tag + + index = path.indexOf(WEB_INF_TAGS); + if (index != -1) { + className = "org.apache.jsp.tag.web."; + begin = index + WEB_INF_TAGS.length(); + } else { + index = path.indexOf(META_INF_TAGS); + if (index != -1) { + className = "org.apache.jsp.tag.meta."; + begin = index + META_INF_TAGS.length(); + } else { + err.jspError("jsp.error.tagfile.illegalPath", path); + } + } + + className += makeJavaPackage(path.substring(begin)); + + return className; + } + + /** + * Converts the given path to a Java package or fully-qualified class name + * + * @param path Path to convert + * + * @return Java package corresponding to the given path + */ + public static final String makeJavaPackage(String path) { + String classNameComponents[] = split(path,"/"); + StringBuffer legalClassNames = new StringBuffer(); + for (int i = 0; i < classNameComponents.length; i++) { + legalClassNames.append(makeJavaIdentifier(classNameComponents[i])); + if (i < classNameComponents.length - 1) { + legalClassNames.append('.'); + } + } + return legalClassNames.toString(); + } + + /** + * Splits a string into it's components. + * @param path String to split + * @param pat Pattern to split at + * @return the components of the path + */ + private static final String [] split(String path, String pat) { + Vector comps = new Vector(); + int pos = path.indexOf(pat); + int start = 0; + while( pos >= 0 ) { + if(pos > start ) { + String comp = path.substring(start,pos); + comps.add(comp); + } + start = pos + pat.length(); + pos = path.indexOf(pat,start); + } + if( start < path.length()) { + comps.add(path.substring(start)); + } + String [] result = new String[comps.size()]; + for(int i=0; i < comps.size(); i++) { + result[i] = (String)comps.elementAt(i); + } + return result; + } + + /** + * Converts the given identifier to a legal Java identifier + * + * @param identifier Identifier to convert + * + * @return Legal Java identifier corresponding to the given identifier + */ + public static final String makeJavaIdentifier(String identifier) { + StringBuffer modifiedIdentifier = + new StringBuffer(identifier.length()); + if (!Character.isJavaIdentifierStart(identifier.charAt(0))) { + modifiedIdentifier.append('_'); + } + for (int i = 0; i < identifier.length(); i++) { + char ch = identifier.charAt(i); + if (Character.isJavaIdentifierPart(ch) && ch != '_') { + modifiedIdentifier.append(ch); + } else if (ch == '.') { + modifiedIdentifier.append('_'); + } else { + modifiedIdentifier.append(mangleChar(ch)); + } + } + if (isJavaKeyword(modifiedIdentifier.toString())) { + modifiedIdentifier.append('_'); + } + return modifiedIdentifier.toString(); + } + + /** + * Mangle the specified character to create a legal Java class name. + */ + public static final String mangleChar(char ch) { + char[] result = new char[5]; + result[0] = '_'; + result[1] = Character.forDigit((ch >> 12) & 0xf, 16); + result[2] = Character.forDigit((ch >> 8) & 0xf, 16); + result[3] = Character.forDigit((ch >> 4) & 0xf, 16); + result[4] = Character.forDigit(ch & 0xf, 16); + return new String(result); + } + + /** + * Test whether the argument is a Java keyword + */ + public static boolean isJavaKeyword(String key) { + int i = 0; + int j = javaKeywords.length; + while (i < j) { + int k = (i+j)/2; + int result = javaKeywords[k].compareTo(key); + if (result == 0) { + return true; + } + if (result < 0) { + i = k+1; + } else { + j = k; + } + } + return false; + } + + /** + * Converts the given Xml name to a legal Java identifier. This is + * slightly more efficient than makeJavaIdentifier in that we only need + * to worry about '.', '-', and ':' in the string. We also assume that + * the resultant string is further concatenated with some prefix string + * so that we don't have to worry about it being a Java key word. + * + * @param name Identifier to convert + * + * @return Legal Java identifier corresponding to the given identifier + */ + public static final String makeXmlJavaIdentifier(String name) { + if (name.indexOf('-') >= 0) + name = replace(name, '-', "$1"); + if (name.indexOf('.') >= 0) + name = replace(name, '.', "$2"); + if (name.indexOf(':') >= 0) + name = replace(name, ':', "$3"); + return name; + } + + static InputStreamReader getReader(String fname, String encoding, + JarFile jarFile, + JspCompilationContext ctxt, + ErrorDispatcher err) + throws JasperException, IOException { + + InputStreamReader reader = null; + InputStream in = getInputStream(fname, jarFile, ctxt, err); + + try { + reader = new InputStreamReader(in, encoding); + } catch (UnsupportedEncodingException ex) { + err.jspError("jsp.error.unsupported.encoding", encoding); + } + + return reader; + } + + /** + * Handles taking input from TLDs + * 'java.lang.Object' -> 'java.lang.Object.class' + * 'int' -> 'int.class' + * 'void' -> 'Void.TYPE' + * 'int[]' -> 'int[].class' + * + * @param type + * @return + */ + public static String toJavaSourceTypeFromTld(String type) { + if (type == null || "void".equals(type)) { + return "Void.TYPE"; + } + return type + ".class"; + } + + /** + * Class.getName() return arrays in the form "[[[", where et, + * the element type can be one of ZBCDFIJS or L; + * It is converted into forms that can be understood by javac. + */ + public static String toJavaSourceType(String type) { + + if (type.charAt(0) != '[') { + return type; + } + + int dims = 1; + String t = null; + for (int i = 1; i < type.length(); i++) { + if (type.charAt(i) == '[') { + dims++; + } else { + switch (type.charAt(i)) { + case 'Z': t = "boolean"; break; + case 'B': t = "byte"; break; + case 'C': t = "char"; break; + case 'D': t = "double"; break; + case 'F': t = "float"; break; + case 'I': t = "int"; break; + case 'J': t = "long"; break; + case 'S': t = "short"; break; + case 'L': t = type.substring(i+1, type.indexOf(';')); break; + } + break; + } + } + StringBuffer resultType = new StringBuffer(t); + for (; dims > 0; dims--) { + resultType.append("[]"); + } + return resultType.toString(); + } + + /** + * Compute the canonical name from a Class instance. Note that a + * simple replacment of '$' with '.' of a binary name would not work, + * as '$' is a legal Java Identifier character. + * @param c A instance of java.lang.Class + * @return The canonical name of c. + */ + public static String getCanonicalName(Class c) { + + String binaryName = c.getName(); + c = c.getDeclaringClass(); + + if (c == null) { + return binaryName; + } + + StringBuffer buf = new StringBuffer(binaryName); + do { + buf.setCharAt(c.getName().length(), '.'); + c = c.getDeclaringClass(); + } while ( c != null); + + return buf.toString(); + } } \ No newline at end of file diff --git a/java/org/apache/jasper/compiler/Localizer.java b/java/org/apache/jasper/compiler/Localizer.java index e1efc5bd9..3645561b7 100644 --- a/java/org/apache/jasper/compiler/Localizer.java +++ b/java/org/apache/jasper/compiler/Localizer.java @@ -1,159 +1,159 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.text.MessageFormat; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -/** - * Class responsible for converting error codes to corresponding localized - * error messages. - * - * @author Jan Luehe - */ -public class Localizer { - - private static ResourceBundle bundle = null; - - static { - try { - bundle = ResourceBundle.getBundle( - "org.apache.jasper.resources.LocalStrings"); - } catch (Throwable t) { - t.printStackTrace(); - } - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * - * @return Localized error message - */ - public static String getMessage(String errCode) { - String errMsg = errCode; - try { - errMsg = bundle.getString(errCode); - } catch (MissingResourceException e) { - } - return errMsg; - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * @param arg Argument for parametric replacement - * - * @return Localized error message - */ - public static String getMessage(String errCode, String arg) { - return getMessage(errCode, new Object[] {arg}); - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * - * @return Localized error message - */ - public static String getMessage(String errCode, String arg1, String arg2) { - return getMessage(errCode, new Object[] {arg1, arg2}); - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * @param arg3 Third argument for parametric replacement - * - * @return Localized error message - */ - public static String getMessage(String errCode, String arg1, String arg2, - String arg3) { - return getMessage(errCode, new Object[] {arg1, arg2, arg3}); - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * @param arg1 First argument for parametric replacement - * @param arg2 Second argument for parametric replacement - * @param arg3 Third argument for parametric replacement - * @param arg4 Fourth argument for parametric replacement - * - * @return Localized error message - */ - public static String getMessage(String errCode, String arg1, String arg2, - String arg3, String arg4) { - return getMessage(errCode, new Object[] {arg1, arg2, arg3, arg4}); - } - - /* - * Returns the localized error message corresponding to the given error - * code. - * - * If the given error code is not defined in the resource bundle for - * localized error messages, it is used as the error message. - * - * @param errCode Error code to localize - * @param args Arguments for parametric replacement - * - * @return Localized error message - */ - public static String getMessage(String errCode, Object[] args) { - String errMsg = errCode; - try { - errMsg = bundle.getString(errCode); - if (args != null) { - MessageFormat formatter = new MessageFormat(errMsg); - errMsg = formatter.format(args); - } - } catch (MissingResourceException e) { - } - - return errMsg; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.text.MessageFormat; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +/** + * Class responsible for converting error codes to corresponding localized + * error messages. + * + * @author Jan Luehe + */ +public class Localizer { + + private static ResourceBundle bundle = null; + + static { + try { + bundle = ResourceBundle.getBundle( + "org.apache.jasper.resources.LocalStrings"); + } catch (Throwable t) { + t.printStackTrace(); + } + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * + * @return Localized error message + */ + public static String getMessage(String errCode) { + String errMsg = errCode; + try { + errMsg = bundle.getString(errCode); + } catch (MissingResourceException e) { + } + return errMsg; + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * @param arg Argument for parametric replacement + * + * @return Localized error message + */ + public static String getMessage(String errCode, String arg) { + return getMessage(errCode, new Object[] {arg}); + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * + * @return Localized error message + */ + public static String getMessage(String errCode, String arg1, String arg2) { + return getMessage(errCode, new Object[] {arg1, arg2}); + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * @param arg3 Third argument for parametric replacement + * + * @return Localized error message + */ + public static String getMessage(String errCode, String arg1, String arg2, + String arg3) { + return getMessage(errCode, new Object[] {arg1, arg2, arg3}); + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * @param arg1 First argument for parametric replacement + * @param arg2 Second argument for parametric replacement + * @param arg3 Third argument for parametric replacement + * @param arg4 Fourth argument for parametric replacement + * + * @return Localized error message + */ + public static String getMessage(String errCode, String arg1, String arg2, + String arg3, String arg4) { + return getMessage(errCode, new Object[] {arg1, arg2, arg3, arg4}); + } + + /* + * Returns the localized error message corresponding to the given error + * code. + * + * If the given error code is not defined in the resource bundle for + * localized error messages, it is used as the error message. + * + * @param errCode Error code to localize + * @param args Arguments for parametric replacement + * + * @return Localized error message + */ + public static String getMessage(String errCode, Object[] args) { + String errMsg = errCode; + try { + errMsg = bundle.getString(errCode); + if (args != null) { + MessageFormat formatter = new MessageFormat(errMsg); + errMsg = formatter.format(args); + } + } catch (MissingResourceException e) { + } + + return errMsg; + } +} diff --git a/java/org/apache/jasper/compiler/Mark.java b/java/org/apache/jasper/compiler/Mark.java index e3bf5c5ba..81ea18671 100644 --- a/java/org/apache/jasper/compiler/Mark.java +++ b/java/org/apache/jasper/compiler/Mark.java @@ -1,281 +1,281 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.util.Stack; -import java.net.URL; -import java.net.MalformedURLException; -import org.apache.jasper.JspCompilationContext; - -/** - * Mark represents a point in the JSP input. - * - * @author Anil K. Vijendran - */ -final class Mark { - - // position within current stream - int cursor, line, col; - - // directory of file for current stream - String baseDir; - - // current stream - char[] stream = null; - - // fileid of current stream - private int fileId; - - // name of the current file - private String fileName; - - /* - * stack of stream and stream state of streams that have included - * current stream - */ - private Stack includeStack = null; - - // encoding of current file - private String encoding = null; - - // reader that owns this mark (so we can look up fileid's) - private JspReader reader; - - private JspCompilationContext ctxt; - - /** - * Constructor - * - * @param reader JspReader this mark belongs to - * @param inStream current stream for this mark - * @param fileId id of requested jsp file - * @param name JSP file name - * @param inBaseDir base directory of requested jsp file - * @param inEncoding encoding of current file - */ - Mark(JspReader reader, char[] inStream, int fileId, String name, - String inBaseDir, String inEncoding) { - - this.reader = reader; - this.ctxt = reader.getJspCompilationContext(); - this.stream = inStream; - this.cursor = 0; - this.line = 1; - this.col = 1; - this.fileId = fileId; - this.fileName = name; - this.baseDir = inBaseDir; - this.encoding = inEncoding; - this.includeStack = new Stack(); - } - - - /** - * Constructor - */ - Mark(Mark other) { - - this.reader = other.reader; - this.ctxt = other.reader.getJspCompilationContext(); - this.stream = other.stream; - this.fileId = other.fileId; - this.fileName = other.fileName; - this.cursor = other.cursor; - this.line = other.line; - this.col = other.col; - this.baseDir = other.baseDir; - this.encoding = other.encoding; - - // clone includeStack without cloning contents - includeStack = new Stack(); - for ( int i=0; i < other.includeStack.size(); i++ ) { - includeStack.addElement( other.includeStack.elementAt(i) ); - } - } - - - /** - * Constructor - */ - Mark(JspCompilationContext ctxt, String filename, int line, int col) { - - this.reader = null; - this.ctxt = ctxt; - this.stream = null; - this.cursor = 0; - this.line = line; - this.col = col; - this.fileId = -1; - this.fileName = filename; - this.baseDir = "le-basedir"; - this.encoding = "le-endocing"; - this.includeStack = null; - } - - - /** - * Sets this mark's state to a new stream. - * It will store the current stream in it's includeStack. - * - * @param inStream new stream for mark - * @param inFileId id of new file from which stream comes from - * @param inBaseDir directory of file - * @param inEncoding encoding of new file - */ - public void pushStream(char[] inStream, int inFileId, String name, - String inBaseDir, String inEncoding) - { - // store current state in stack - includeStack.push(new IncludeState(cursor, line, col, fileId, - fileName, baseDir, - encoding, stream) ); - - // set new variables - cursor = 0; - line = 1; - col = 1; - fileId = inFileId; - fileName = name; - baseDir = inBaseDir; - encoding = inEncoding; - stream = inStream; - } - - - /** - * Restores this mark's state to a previously stored stream. - * @return The previous Mark instance when the stream was pushed, or null - * if there is no previous stream - */ - public Mark popStream() { - // make sure we have something to pop - if ( includeStack.size() <= 0 ) { - return null; - } - - // get previous state in stack - IncludeState state = (IncludeState) includeStack.pop( ); - - // set new variables - cursor = state.cursor; - line = state.line; - col = state.col; - fileId = state.fileId; - fileName = state.fileName; - baseDir = state.baseDir; - stream = state.stream; - return this; - } - - - // -------------------- Locator interface -------------------- - - public int getLineNumber() { - return line; - } - - public int getColumnNumber() { - return col; - } - - public String getSystemId() { - return getFile(); - } - - public String getPublicId() { - return null; - } - - public String toString() { - return getFile()+"("+line+","+col+")"; - } - - public String getFile() { - return this.fileName; - } - - /** - * Gets the URL of the resource with which this Mark is associated - * - * @return URL of the resource with which this Mark is associated - * - * @exception MalformedURLException if the resource pathname is incorrect - */ - public URL getURL() throws MalformedURLException { - return ctxt.getResource(getFile()); - } - - public String toShortString() { - return "("+line+","+col+")"; - } - - public boolean equals(Object other) { - if (other instanceof Mark) { - Mark m = (Mark) other; - return this.reader == m.reader && this.fileId == m.fileId - && this.cursor == m.cursor && this.line == m.line - && this.col == m.col; - } - return false; - } - - /** - * @return true if this Mark is greather than the other - * Mark, false otherwise. - */ - public boolean isGreater(Mark other) { - - boolean greater = false; - - if (this.line > other.line) { - greater = true; - } else if (this.line == other.line && this.col > other.col) { - greater = true; - } - - return greater; - } - - /** - * Keep track of parser before parsing an included file. - * This class keeps track of the parser before we switch to parsing an - * included file. In other words, it's the parser's continuation to be - * reinstalled after the included file parsing is done. - */ - class IncludeState { - int cursor, line, col; - int fileId; - String fileName; - String baseDir; - String encoding; - char[] stream = null; - - IncludeState(int inCursor, int inLine, int inCol, int inFileId, - String name, String inBaseDir, String inEncoding, - char[] inStream) { - cursor = inCursor; - line = inLine; - col = inCol; - fileId = inFileId; - fileName = name; - baseDir = inBaseDir; - encoding = inEncoding; - stream = inStream; - } - } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.util.Stack; +import java.net.URL; +import java.net.MalformedURLException; +import org.apache.jasper.JspCompilationContext; + +/** + * Mark represents a point in the JSP input. + * + * @author Anil K. Vijendran + */ +final class Mark { + + // position within current stream + int cursor, line, col; + + // directory of file for current stream + String baseDir; + + // current stream + char[] stream = null; + + // fileid of current stream + private int fileId; + + // name of the current file + private String fileName; + + /* + * stack of stream and stream state of streams that have included + * current stream + */ + private Stack includeStack = null; + + // encoding of current file + private String encoding = null; + + // reader that owns this mark (so we can look up fileid's) + private JspReader reader; + + private JspCompilationContext ctxt; + + /** + * Constructor + * + * @param reader JspReader this mark belongs to + * @param inStream current stream for this mark + * @param fileId id of requested jsp file + * @param name JSP file name + * @param inBaseDir base directory of requested jsp file + * @param inEncoding encoding of current file + */ + Mark(JspReader reader, char[] inStream, int fileId, String name, + String inBaseDir, String inEncoding) { + + this.reader = reader; + this.ctxt = reader.getJspCompilationContext(); + this.stream = inStream; + this.cursor = 0; + this.line = 1; + this.col = 1; + this.fileId = fileId; + this.fileName = name; + this.baseDir = inBaseDir; + this.encoding = inEncoding; + this.includeStack = new Stack(); + } + + + /** + * Constructor + */ + Mark(Mark other) { + + this.reader = other.reader; + this.ctxt = other.reader.getJspCompilationContext(); + this.stream = other.stream; + this.fileId = other.fileId; + this.fileName = other.fileName; + this.cursor = other.cursor; + this.line = other.line; + this.col = other.col; + this.baseDir = other.baseDir; + this.encoding = other.encoding; + + // clone includeStack without cloning contents + includeStack = new Stack(); + for ( int i=0; i < other.includeStack.size(); i++ ) { + includeStack.addElement( other.includeStack.elementAt(i) ); + } + } + + + /** + * Constructor + */ + Mark(JspCompilationContext ctxt, String filename, int line, int col) { + + this.reader = null; + this.ctxt = ctxt; + this.stream = null; + this.cursor = 0; + this.line = line; + this.col = col; + this.fileId = -1; + this.fileName = filename; + this.baseDir = "le-basedir"; + this.encoding = "le-endocing"; + this.includeStack = null; + } + + + /** + * Sets this mark's state to a new stream. + * It will store the current stream in it's includeStack. + * + * @param inStream new stream for mark + * @param inFileId id of new file from which stream comes from + * @param inBaseDir directory of file + * @param inEncoding encoding of new file + */ + public void pushStream(char[] inStream, int inFileId, String name, + String inBaseDir, String inEncoding) + { + // store current state in stack + includeStack.push(new IncludeState(cursor, line, col, fileId, + fileName, baseDir, + encoding, stream) ); + + // set new variables + cursor = 0; + line = 1; + col = 1; + fileId = inFileId; + fileName = name; + baseDir = inBaseDir; + encoding = inEncoding; + stream = inStream; + } + + + /** + * Restores this mark's state to a previously stored stream. + * @return The previous Mark instance when the stream was pushed, or null + * if there is no previous stream + */ + public Mark popStream() { + // make sure we have something to pop + if ( includeStack.size() <= 0 ) { + return null; + } + + // get previous state in stack + IncludeState state = (IncludeState) includeStack.pop( ); + + // set new variables + cursor = state.cursor; + line = state.line; + col = state.col; + fileId = state.fileId; + fileName = state.fileName; + baseDir = state.baseDir; + stream = state.stream; + return this; + } + + + // -------------------- Locator interface -------------------- + + public int getLineNumber() { + return line; + } + + public int getColumnNumber() { + return col; + } + + public String getSystemId() { + return getFile(); + } + + public String getPublicId() { + return null; + } + + public String toString() { + return getFile()+"("+line+","+col+")"; + } + + public String getFile() { + return this.fileName; + } + + /** + * Gets the URL of the resource with which this Mark is associated + * + * @return URL of the resource with which this Mark is associated + * + * @exception MalformedURLException if the resource pathname is incorrect + */ + public URL getURL() throws MalformedURLException { + return ctxt.getResource(getFile()); + } + + public String toShortString() { + return "("+line+","+col+")"; + } + + public boolean equals(Object other) { + if (other instanceof Mark) { + Mark m = (Mark) other; + return this.reader == m.reader && this.fileId == m.fileId + && this.cursor == m.cursor && this.line == m.line + && this.col == m.col; + } + return false; + } + + /** + * @return true if this Mark is greather than the other + * Mark, false otherwise. + */ + public boolean isGreater(Mark other) { + + boolean greater = false; + + if (this.line > other.line) { + greater = true; + } else if (this.line == other.line && this.col > other.col) { + greater = true; + } + + return greater; + } + + /** + * Keep track of parser before parsing an included file. + * This class keeps track of the parser before we switch to parsing an + * included file. In other words, it's the parser's continuation to be + * reinstalled after the included file parsing is done. + */ + class IncludeState { + int cursor, line, col; + int fileId; + String fileName; + String baseDir; + String encoding; + char[] stream = null; + + IncludeState(int inCursor, int inLine, int inCol, int inFileId, + String name, String inBaseDir, String inEncoding, + char[] inStream) { + cursor = inCursor; + line = inLine; + col = inCol; + fileId = inFileId; + fileName = name; + baseDir = inBaseDir; + encoding = inEncoding; + stream = inStream; + } + } + +} + diff --git a/java/org/apache/jasper/compiler/Node.java b/java/org/apache/jasper/compiler/Node.java index 2b2d0a81e..5ece8562e 100644 --- a/java/org/apache/jasper/compiler/Node.java +++ b/java/org/apache/jasper/compiler/Node.java @@ -1,2527 +1,2527 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.Iterator; -import java.util.List; -import java.util.Vector; -import java.util.ArrayList; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ExpressionFactory; -import javax.el.ValueExpression; -import javax.servlet.jsp.tagext.BodyTag; -import javax.servlet.jsp.tagext.DynamicAttributes; -import javax.servlet.jsp.tagext.IterationTag; -import javax.servlet.jsp.tagext.JspIdConsumer; -import javax.servlet.jsp.tagext.SimpleTag; -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagData; -import javax.servlet.jsp.tagext.TagFileInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagVariableInfo; -import javax.servlet.jsp.tagext.TryCatchFinally; -import javax.servlet.jsp.tagext.VariableInfo; - -import org.apache.jasper.JasperException; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; -import org.xml.sax.Attributes; - -/** - * An internal data representation of a JSP page or a JSP docuement (XML). Also - * included here is a visitor class for tranversing nodes. - * - * @author Kin-man Chung - * @author Jan Luehe - * @author Shawn Bayern - * @author Mark Roth - */ - -abstract class Node implements TagConstants { - - private static final VariableInfo[] ZERO_VARIABLE_INFO = {}; - - protected Attributes attrs; - - // xmlns attributes that represent tag libraries (only in XML syntax) - protected Attributes taglibAttrs; - - /* - * xmlns attributes that do not represent tag libraries (only in XML syntax) - */ - protected Attributes nonTaglibXmlnsAttrs; - - protected Nodes body; - - protected String text; - - protected Mark startMark; - - protected int beginJavaLine; - - protected int endJavaLine; - - protected Node parent; - - protected Nodes namedAttributeNodes; // cached for performance - - protected String qName; - - protected String localName; - - /* - * The name of the inner class to which the codes for this node and its body - * are generated. For instance, for in foo.jsp, this is - * "foo_jspHelper". This is primarily used for communicating such info from - * Generator to Smap generator. - */ - protected String innerClassName; - - private boolean isDummy; - - /** - * Zero-arg Constructor. - */ - public Node() { - this.isDummy = true; - } - - /** - * Constructor. - * - * @param start - * The location of the jsp page - * @param parent - * The enclosing node - */ - public Node(Mark start, Node parent) { - this.startMark = start; - this.isDummy = (start == null); - addToParent(parent); - } - - /** - * Constructor. - * - * @param qName - * The action's qualified name - * @param localName - * The action's local name - * @param start - * The location of the jsp page - * @param parent - * The enclosing node - */ - public Node(String qName, String localName, Mark start, Node parent) { - this.qName = qName; - this.localName = localName; - this.startMark = start; - this.isDummy = (start == null); - addToParent(parent); - } - - /** - * Constructor for Nodes parsed from standard syntax. - * - * @param qName - * The action's qualified name - * @param localName - * The action's local name - * @param attrs - * The attributes for this node - * @param start - * The location of the jsp page - * @param parent - * The enclosing node - */ - public Node(String qName, String localName, Attributes attrs, Mark start, - Node parent) { - this.qName = qName; - this.localName = localName; - this.attrs = attrs; - this.startMark = start; - this.isDummy = (start == null); - addToParent(parent); - } - - /** - * Constructor for Nodes parsed from XML syntax. - * - * @param qName - * The action's qualified name - * @param localName - * The action's local name - * @param attrs - * The action's attributes whose name does not start with xmlns - * @param nonTaglibXmlnsAttrs - * The action's xmlns attributes that do not represent tag - * libraries - * @param taglibAttrs - * The action's xmlns attributes that represent tag libraries - * @param start - * The location of the jsp page - * @param parent - * The enclosing node - */ - public Node(String qName, String localName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, Mark start, - Node parent) { - this.qName = qName; - this.localName = localName; - this.attrs = attrs; - this.nonTaglibXmlnsAttrs = nonTaglibXmlnsAttrs; - this.taglibAttrs = taglibAttrs; - this.startMark = start; - this.isDummy = (start == null); - addToParent(parent); - } - - /* - * Constructor. - * - * @param qName The action's qualified name @param localName The action's - * local name @param text The text associated with this node @param start - * The location of the jsp page @param parent The enclosing node - */ - public Node(String qName, String localName, String text, Mark start, - Node parent) { - this.qName = qName; - this.localName = localName; - this.text = text; - this.startMark = start; - this.isDummy = (start == null); - addToParent(parent); - } - - public String getQName() { - return this.qName; - } - - public String getLocalName() { - return this.localName; - } - - /* - * Gets this Node's attributes. - * - * In the case of a Node parsed from standard syntax, this method returns - * all the Node's attributes. - * - * In the case of a Node parsed from XML syntax, this method returns only - * those attributes whose name does not start with xmlns. - */ - public Attributes getAttributes() { - return this.attrs; - } - - /* - * Gets this Node's xmlns attributes that represent tag libraries (only - * meaningful for Nodes parsed from XML syntax) - */ - public Attributes getTaglibAttributes() { - return this.taglibAttrs; - } - - /* - * Gets this Node's xmlns attributes that do not represent tag libraries - * (only meaningful for Nodes parsed from XML syntax) - */ - public Attributes getNonTaglibXmlnsAttributes() { - return this.nonTaglibXmlnsAttrs; - } - - public void setAttributes(Attributes attrs) { - this.attrs = attrs; - } - - public String getAttributeValue(String name) { - return (attrs == null) ? null : attrs.getValue(name); - } - - /** - * Get the attribute that is non request time expression, either from the - * attribute of the node, or from a jsp:attrbute - */ - public String getTextAttribute(String name) { - - String attr = getAttributeValue(name); - if (attr != null) { - return attr; - } - - NamedAttribute namedAttribute = getNamedAttributeNode(name); - if (namedAttribute == null) { - return null; - } - - return namedAttribute.getText(); - } - - /** - * Searches all subnodes of this node for jsp:attribute standard actions - * with the given name, and returns the NamedAttribute node of the matching - * named attribute, nor null if no such node is found. - *

        - * This should always be called and only be called for nodes that accept - * dynamic runtime attribute expressions. - */ - public NamedAttribute getNamedAttributeNode(String name) { - NamedAttribute result = null; - - // Look for the attribute in NamedAttribute children - Nodes nodes = getNamedAttributeNodes(); - int numChildNodes = nodes.size(); - for (int i = 0; i < numChildNodes; i++) { - NamedAttribute na = (NamedAttribute) nodes.getNode(i); - boolean found = false; - int index = name.indexOf(':'); - if (index != -1) { - // qualified name - found = na.getName().equals(name); - } else { - found = na.getLocalName().equals(name); - } - if (found) { - result = na; - break; - } - } - - return result; - } - - /** - * Searches all subnodes of this node for jsp:attribute standard actions, - * and returns that set of nodes as a Node.Nodes object. - * - * @return Possibly empty Node.Nodes object containing any jsp:attribute - * subnodes of this Node - */ - public Node.Nodes getNamedAttributeNodes() { - - if (namedAttributeNodes != null) { - return namedAttributeNodes; - } - - Node.Nodes result = new Node.Nodes(); - - // Look for the attribute in NamedAttribute children - Nodes nodes = getBody(); - if (nodes != null) { - int numChildNodes = nodes.size(); - for (int i = 0; i < numChildNodes; i++) { - Node n = nodes.getNode(i); - if (n instanceof NamedAttribute) { - result.add(n); - } else if (!(n instanceof Comment)) { - // Nothing can come before jsp:attribute, and only - // jsp:body can come after it. - break; - } - } - } - - namedAttributeNodes = result; - return result; - } - - public Nodes getBody() { - return body; - } - - public void setBody(Nodes body) { - this.body = body; - } - - public String getText() { - return text; - } - - public Mark getStart() { - return startMark; - } - - public Node getParent() { - return parent; - } - - public int getBeginJavaLine() { - return beginJavaLine; - } - - public void setBeginJavaLine(int begin) { - beginJavaLine = begin; - } - - public int getEndJavaLine() { - return endJavaLine; - } - - public void setEndJavaLine(int end) { - endJavaLine = end; - } - - public boolean isDummy() { - return isDummy; - } - - public Node.Root getRoot() { - Node n = this; - while (!(n instanceof Node.Root)) { - n = n.getParent(); - } - return (Node.Root) n; - } - - public String getInnerClassName() { - return innerClassName; - } - - public void setInnerClassName(String icn) { - innerClassName = icn; - } - - /** - * Selects and invokes a method in the visitor class based on the node type. - * This is abstract and should be overrode by the extending classes. - * - * @param v - * The visitor class - */ - abstract void accept(Visitor v) throws JasperException; - - // ********************************************************************* - // Private utility methods - - /* - * Adds this Node to the body of the given parent. - */ - private void addToParent(Node parent) { - if (parent != null) { - this.parent = parent; - Nodes parentBody = parent.getBody(); - if (parentBody == null) { - parentBody = new Nodes(); - parent.setBody(parentBody); - } - parentBody.add(this); - } - } - - /*************************************************************************** - * Child classes - */ - - /** - * Represents the root of a Jsp page or Jsp document - */ - public static class Root extends Node { - - private Root parentRoot; - - private boolean isXmlSyntax; - - // Source encoding of the page containing this Root - private String pageEnc; - - // Page encoding specified in JSP config element - private String jspConfigPageEnc; - - /* - * Flag indicating if the default page encoding is being used (only - * applicable with standard syntax). - * - * True if the page does not provide a page directive with a - * 'contentType' attribute (or the 'contentType' attribute doesn't have - * a CHARSET value), the page does not provide a page directive with a - * 'pageEncoding' attribute, and there is no JSP configuration element - * page-encoding whose URL pattern matches the page. - */ - private boolean isDefaultPageEncoding; - - /* - * Indicates whether an encoding has been explicitly specified in the - * page's XML prolog (only used for pages in XML syntax). This - * information is used to decide whether a translation error must be - * reported for encoding conflicts. - */ - private boolean isEncodingSpecifiedInProlog; - - /* - * Constructor. - */ - Root(Mark start, Node parent, boolean isXmlSyntax) { - super(start, parent); - this.isXmlSyntax = isXmlSyntax; - this.qName = JSP_ROOT_ACTION; - this.localName = ROOT_ACTION; - - // Figure out and set the parent root - Node r = parent; - while ((r != null) && !(r instanceof Node.Root)) - r = r.getParent(); - parentRoot = (Node.Root) r; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public boolean isXmlSyntax() { - return isXmlSyntax; - } - - /* - * Sets the encoding specified in the JSP config element whose URL - * pattern matches the page containing this Root. - */ - public void setJspConfigPageEncoding(String enc) { - jspConfigPageEnc = enc; - } - - /* - * Gets the encoding specified in the JSP config element whose URL - * pattern matches the page containing this Root. - */ - public String getJspConfigPageEncoding() { - return jspConfigPageEnc; - } - - public void setPageEncoding(String enc) { - pageEnc = enc; - } - - public String getPageEncoding() { - return pageEnc; - } - - public void setIsDefaultPageEncoding(boolean isDefault) { - isDefaultPageEncoding = isDefault; - } - - public boolean isDefaultPageEncoding() { - return isDefaultPageEncoding; - } - - public void setIsEncodingSpecifiedInProlog(boolean isSpecified) { - isEncodingSpecifiedInProlog = isSpecified; - } - - public boolean isEncodingSpecifiedInProlog() { - return isEncodingSpecifiedInProlog; - } - - /** - * @return The enclosing root to this Root. Usually represents the page - * that includes this one. - */ - public Root getParentRoot() { - return parentRoot; - } - } - - /** - * Represents the root of a Jsp document (XML syntax) - */ - public static class JspRoot extends Node { - - public JspRoot(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, ROOT_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a page directive - */ - public static class PageDirective extends Node { - - private Vector imports; - - public PageDirective(Attributes attrs, Mark start, Node parent) { - this(JSP_PAGE_DIRECTIVE_ACTION, attrs, null, null, start, parent); - } - - public PageDirective(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, PAGE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - imports = new Vector(); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - /** - * Parses the comma-separated list of class or package names in the - * given attribute value and adds each component to this PageDirective's - * vector of imported classes and packages. - * - * @param value - * A comma-separated string of imports. - */ - public void addImport(String value) { - int start = 0; - int index; - while ((index = value.indexOf(',', start)) != -1) { - imports.add(value.substring(start, index).trim()); - start = index + 1; - } - if (start == 0) { - // No comma found - imports.add(value.trim()); - } else { - imports.add(value.substring(start).trim()); - } - } - - public List getImports() { - return imports; - } - } - - /** - * Represents an include directive - */ - public static class IncludeDirective extends Node { - - public IncludeDirective(Attributes attrs, Mark start, Node parent) { - this(JSP_INCLUDE_DIRECTIVE_ACTION, attrs, null, null, start, parent); - } - - public IncludeDirective(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, INCLUDE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a custom taglib directive - */ - public static class TaglibDirective extends Node { - - public TaglibDirective(Attributes attrs, Mark start, Node parent) { - super(JSP_TAGLIB_DIRECTIVE_ACTION, TAGLIB_DIRECTIVE_ACTION, attrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a tag directive - */ - public static class TagDirective extends Node { - private Vector imports; - - public TagDirective(Attributes attrs, Mark start, Node parent) { - this(JSP_TAG_DIRECTIVE_ACTION, attrs, null, null, start, parent); - } - - public TagDirective(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, TAG_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - imports = new Vector(); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - /** - * Parses the comma-separated list of class or package names in the - * given attribute value and adds each component to this PageDirective's - * vector of imported classes and packages. - * - * @param value - * A comma-separated string of imports. - */ - public void addImport(String value) { - int start = 0; - int index; - while ((index = value.indexOf(',', start)) != -1) { - imports.add(value.substring(start, index).trim()); - start = index + 1; - } - if (start == 0) { - // No comma found - imports.add(value.trim()); - } else { - imports.add(value.substring(start).trim()); - } - } - - public List getImports() { - return imports; - } - } - - /** - * Represents an attribute directive - */ - public static class AttributeDirective extends Node { - - public AttributeDirective(Attributes attrs, Mark start, Node parent) { - this(JSP_ATTRIBUTE_DIRECTIVE_ACTION, attrs, null, null, start, - parent); - } - - public AttributeDirective(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, ATTRIBUTE_DIRECTIVE_ACTION, attrs, - nonTaglibXmlnsAttrs, taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a variable directive - */ - public static class VariableDirective extends Node { - - public VariableDirective(Attributes attrs, Mark start, Node parent) { - this(JSP_VARIABLE_DIRECTIVE_ACTION, attrs, null, null, start, - parent); - } - - public VariableDirective(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, VARIABLE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a tag file action - */ - public static class InvokeAction extends Node { - - public InvokeAction(Attributes attrs, Mark start, Node parent) { - this(JSP_INVOKE_ACTION, attrs, null, null, start, parent); - } - - public InvokeAction(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, INVOKE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a tag file action - */ - public static class DoBodyAction extends Node { - - public DoBodyAction(Attributes attrs, Mark start, Node parent) { - this(JSP_DOBODY_ACTION, attrs, null, null, start, parent); - } - - public DoBodyAction(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, DOBODY_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a Jsp comment Comments are kept for completeness. - */ - public static class Comment extends Node { - - public Comment(String text, Mark start, Node parent) { - super(null, null, text, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents an expression, declaration, or scriptlet - */ - public static abstract class ScriptingElement extends Node { - - public ScriptingElement(String qName, String localName, String text, - Mark start, Node parent) { - super(qName, localName, text, start, parent); - } - - public ScriptingElement(String qName, String localName, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, localName, null, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - /** - * When this node was created from a JSP page in JSP syntax, its text - * was stored as a String in the "text" field, whereas when this node - * was created from a JSP document, its text was stored as one or more - * TemplateText nodes in its body. This method handles either case. - * - * @return The text string - */ - public String getText() { - String ret = text; - if ((ret == null) && (body != null)) { - StringBuffer buf = new StringBuffer(); - for (int i = 0; i < body.size(); i++) { - buf.append(body.getNode(i).getText()); - } - ret = buf.toString(); - } - return ret; - } - - /** - * For the same reason as above, the source line information in the - * contained TemplateText node should be used. - */ - public Mark getStart() { - if (text == null && body != null && body.size() > 0) { - return body.getNode(0).getStart(); - } else { - return super.getStart(); - } - } - } - - /** - * Represents a declaration - */ - public static class Declaration extends ScriptingElement { - - public Declaration(String text, Mark start, Node parent) { - super(JSP_DECLARATION_ACTION, DECLARATION_ACTION, text, start, - parent); - } - - public Declaration(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, DECLARATION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents an expression. Expressions in attributes are embedded in the - * attribute string and not here. - */ - public static class Expression extends ScriptingElement { - - public Expression(String text, Mark start, Node parent) { - super(JSP_EXPRESSION_ACTION, EXPRESSION_ACTION, text, start, parent); - } - - public Expression(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, EXPRESSION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a scriptlet - */ - public static class Scriptlet extends ScriptingElement { - - public Scriptlet(String text, Mark start, Node parent) { - super(JSP_SCRIPTLET_ACTION, SCRIPTLET_ACTION, text, start, parent); - } - - public Scriptlet(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, SCRIPTLET_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents an EL expression. Expressions in attributes are embedded in - * the attribute string and not here. - */ - public static class ELExpression extends Node { - - private ELNode.Nodes el; - - private final char type; - - public ELExpression(char type, String text, Mark start, Node parent) { - super(null, null, text, start, parent); - this.type = type; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setEL(ELNode.Nodes el) { - this.el = el; - } - - public ELNode.Nodes getEL() { - return el; - } - - public char getType() { - return this.type; - } - } - - /** - * Represents a param action - */ - public static class ParamAction extends Node { - - JspAttribute value; - - public ParamAction(Attributes attrs, Mark start, Node parent) { - this(JSP_PARAM_ACTION, attrs, null, null, start, parent); - } - - public ParamAction(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, PARAM_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setValue(JspAttribute value) { - this.value = value; - } - - public JspAttribute getValue() { - return value; - } - } - - /** - * Represents a params action - */ - public static class ParamsAction extends Node { - - public ParamsAction(Mark start, Node parent) { - this(JSP_PARAMS_ACTION, null, null, start, parent); - } - - public ParamsAction(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, PARAMS_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a fallback action - */ - public static class FallBackAction extends Node { - - public FallBackAction(Mark start, Node parent) { - this(JSP_FALLBACK_ACTION, null, null, start, parent); - } - - public FallBackAction(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, FALLBACK_ACTION, null, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents an include action - */ - public static class IncludeAction extends Node { - - private JspAttribute page; - - public IncludeAction(Attributes attrs, Mark start, Node parent) { - this(JSP_INCLUDE_ACTION, attrs, null, null, start, parent); - } - - public IncludeAction(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, INCLUDE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setPage(JspAttribute page) { - this.page = page; - } - - public JspAttribute getPage() { - return page; - } - } - - /** - * Represents a forward action - */ - public static class ForwardAction extends Node { - - private JspAttribute page; - - public ForwardAction(Attributes attrs, Mark start, Node parent) { - this(JSP_FORWARD_ACTION, attrs, null, null, start, parent); - } - - public ForwardAction(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, FORWARD_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setPage(JspAttribute page) { - this.page = page; - } - - public JspAttribute getPage() { - return page; - } - } - - /** - * Represents a getProperty action - */ - public static class GetProperty extends Node { - - public GetProperty(Attributes attrs, Mark start, Node parent) { - this(JSP_GET_PROPERTY_ACTION, attrs, null, null, start, parent); - } - - public GetProperty(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, GET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a setProperty action - */ - public static class SetProperty extends Node { - - private JspAttribute value; - - public SetProperty(Attributes attrs, Mark start, Node parent) { - this(JSP_SET_PROPERTY_ACTION, attrs, null, null, start, parent); - } - - public SetProperty(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, SET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setValue(JspAttribute value) { - this.value = value; - } - - public JspAttribute getValue() { - return value; - } - } - - /** - * Represents a useBean action - */ - public static class UseBean extends Node { - - JspAttribute beanName; - - public UseBean(Attributes attrs, Mark start, Node parent) { - this(JSP_USE_BEAN_ACTION, attrs, null, null, start, parent); - } - - public UseBean(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, USE_BEAN_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setBeanName(JspAttribute beanName) { - this.beanName = beanName; - } - - public JspAttribute getBeanName() { - return beanName; - } - } - - /** - * Represents a plugin action - */ - public static class PlugIn extends Node { - - private JspAttribute width; - - private JspAttribute height; - - public PlugIn(Attributes attrs, Mark start, Node parent) { - this(JSP_PLUGIN_ACTION, attrs, null, null, start, parent); - } - - public PlugIn(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, PLUGIN_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setHeight(JspAttribute height) { - this.height = height; - } - - public void setWidth(JspAttribute width) { - this.width = width; - } - - public JspAttribute getHeight() { - return height; - } - - public JspAttribute getWidth() { - return width; - } - } - - /** - * Represents an uninterpreted tag, from a Jsp document - */ - public static class UninterpretedTag extends Node { - - private JspAttribute[] jspAttrs; - - public UninterpretedTag(String qName, String localName, - Attributes attrs, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setJspAttributes(JspAttribute[] jspAttrs) { - this.jspAttrs = jspAttrs; - } - - public JspAttribute[] getJspAttributes() { - return jspAttrs; - } - } - - /** - * Represents a . - */ - public static class JspElement extends Node { - - private JspAttribute[] jspAttrs; - - private JspAttribute nameAttr; - - public JspElement(Attributes attrs, Mark start, Node parent) { - this(JSP_ELEMENT_ACTION, attrs, null, null, start, parent); - } - - public JspElement(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, ELEMENT_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public void setJspAttributes(JspAttribute[] jspAttrs) { - this.jspAttrs = jspAttrs; - } - - public JspAttribute[] getJspAttributes() { - return jspAttrs; - } - - /* - * Sets the XML-style 'name' attribute - */ - public void setNameAttribute(JspAttribute nameAttr) { - this.nameAttr = nameAttr; - } - - /* - * Gets the XML-style 'name' attribute - */ - public JspAttribute getNameAttribute() { - return this.nameAttr; - } - } - - /** - * Represents a . - */ - public static class JspOutput extends Node { - - public JspOutput(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - super(qName, OUTPUT_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Collected information about child elements. Used by nodes like CustomTag, - * JspBody, and NamedAttribute. The information is set in the Collector. - */ - public static class ChildInfo { - private boolean scriptless; // true if the tag and its body - - // contain no scripting elements. - private boolean hasUseBean; - - private boolean hasIncludeAction; - - private boolean hasParamAction; - - private boolean hasSetProperty; - - private boolean hasScriptingVars; - - public void setScriptless(boolean s) { - scriptless = s; - } - - public boolean isScriptless() { - return scriptless; - } - - public void setHasUseBean(boolean u) { - hasUseBean = u; - } - - public boolean hasUseBean() { - return hasUseBean; - } - - public void setHasIncludeAction(boolean i) { - hasIncludeAction = i; - } - - public boolean hasIncludeAction() { - return hasIncludeAction; - } - - public void setHasParamAction(boolean i) { - hasParamAction = i; - } - - public boolean hasParamAction() { - return hasParamAction; - } - - public void setHasSetProperty(boolean s) { - hasSetProperty = s; - } - - public boolean hasSetProperty() { - return hasSetProperty; - } - - public void setHasScriptingVars(boolean s) { - hasScriptingVars = s; - } - - public boolean hasScriptingVars() { - return hasScriptingVars; - } - } - - /** - * Represents a custom tag - */ - public static class CustomTag extends Node { - - private String uri; - - private String prefix; - - private JspAttribute[] jspAttrs; - - private TagData tagData; - - private String tagHandlerPoolName; - - private TagInfo tagInfo; - - private TagFileInfo tagFileInfo; - - private Class tagHandlerClass; - - private VariableInfo[] varInfos; - - private int customNestingLevel; - - private ChildInfo childInfo; - - private boolean implementsIterationTag; - - private boolean implementsBodyTag; - - private boolean implementsTryCatchFinally; - - private boolean implementsJspIdConsumer; - - private boolean implementsSimpleTag; - - private boolean implementsDynamicAttributes; - - private Vector atBeginScriptingVars; - - private Vector atEndScriptingVars; - - private Vector nestedScriptingVars; - - private Node.CustomTag customTagParent; - - private Integer numCount; - - private boolean useTagPlugin; - - private TagPluginContext tagPluginContext; - - /** - * The following two fields are used for holding the Java scriptlets - * that the tag plugins may generate. Meaningful only if useTagPlugin is - * true; Could move them into TagPluginContextImpl, but we'll need to - * cast tagPluginContext to TagPluginContextImpl all the time... - */ - private Nodes atSTag; - - private Nodes atETag; - - /* - * Constructor for custom action implemented by tag handler. - */ - public CustomTag(String qName, String prefix, String localName, - String uri, Attributes attrs, Mark start, Node parent, - TagInfo tagInfo, Class tagHandlerClass) { - this(qName, prefix, localName, uri, attrs, null, null, start, - parent, tagInfo, tagHandlerClass); - } - - /* - * Constructor for custom action implemented by tag handler. - */ - public CustomTag(String qName, String prefix, String localName, - String uri, Attributes attrs, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent, - TagInfo tagInfo, Class tagHandlerClass) { - super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - - this.uri = uri; - this.prefix = prefix; - this.tagInfo = tagInfo; - this.tagHandlerClass = tagHandlerClass; - this.customNestingLevel = makeCustomNestingLevel(); - this.childInfo = new ChildInfo(); - - this.implementsIterationTag = IterationTag.class - .isAssignableFrom(tagHandlerClass); - this.implementsBodyTag = BodyTag.class - .isAssignableFrom(tagHandlerClass); - this.implementsTryCatchFinally = TryCatchFinally.class - .isAssignableFrom(tagHandlerClass); - this.implementsSimpleTag = SimpleTag.class - .isAssignableFrom(tagHandlerClass); - this.implementsDynamicAttributes = DynamicAttributes.class - .isAssignableFrom(tagHandlerClass); - this.implementsJspIdConsumer = JspIdConsumer.class - .isAssignableFrom(tagHandlerClass); - } - - /* - * Constructor for custom action implemented by tag file. - */ - public CustomTag(String qName, String prefix, String localName, - String uri, Attributes attrs, Mark start, Node parent, - TagFileInfo tagFileInfo) { - this(qName, prefix, localName, uri, attrs, null, null, start, - parent, tagFileInfo); - } - - /* - * Constructor for custom action implemented by tag file. - */ - public CustomTag(String qName, String prefix, String localName, - String uri, Attributes attrs, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent, - TagFileInfo tagFileInfo) { - - super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - - this.uri = uri; - this.prefix = prefix; - this.tagFileInfo = tagFileInfo; - this.tagInfo = tagFileInfo.getTagInfo(); - this.customNestingLevel = makeCustomNestingLevel(); - this.childInfo = new ChildInfo(); - - this.implementsIterationTag = false; - this.implementsBodyTag = false; - this.implementsTryCatchFinally = false; - this.implementsSimpleTag = true; - this.implementsJspIdConsumer = false; - this.implementsDynamicAttributes = tagInfo.hasDynamicAttributes(); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - /** - * @return The URI namespace that this custom action belongs to - */ - public String getURI() { - return this.uri; - } - - /** - * @return The tag prefix - */ - public String getPrefix() { - return prefix; - } - - public void setJspAttributes(JspAttribute[] jspAttrs) { - this.jspAttrs = jspAttrs; - } - - public TagAttributeInfo getTagAttributeInfo(String name) { - TagInfo info = this.getTagInfo(); - if (info == null) - return null; - TagAttributeInfo[] tai = info.getAttributes(); - for (int i = 0; i < tai.length; i++) { - if (tai[i].getName().equals(name)) { - return tai[i]; - } - } - return null; - } - - public JspAttribute[] getJspAttributes() { - return jspAttrs; - } - - public ChildInfo getChildInfo() { - return childInfo; - } - - public void setTagData(TagData tagData) { - this.tagData = tagData; - this.varInfos = tagInfo.getVariableInfo(tagData); - if (this.varInfos == null) { - this.varInfos = ZERO_VARIABLE_INFO; - } - } - - public TagData getTagData() { - return tagData; - } - - public void setTagHandlerPoolName(String s) { - tagHandlerPoolName = s; - } - - public String getTagHandlerPoolName() { - return tagHandlerPoolName; - } - - public TagInfo getTagInfo() { - return tagInfo; - } - - public TagFileInfo getTagFileInfo() { - return tagFileInfo; - } - - /* - * @return true if this custom action is supported by a tag file, false - * otherwise - */ - public boolean isTagFile() { - return tagFileInfo != null; - } - - public Class getTagHandlerClass() { - return tagHandlerClass; - } - - public void setTagHandlerClass(Class hc) { - tagHandlerClass = hc; - } - - public boolean implementsIterationTag() { - return implementsIterationTag; - } - - public boolean implementsBodyTag() { - return implementsBodyTag; - } - - public boolean implementsTryCatchFinally() { - return implementsTryCatchFinally; - } - - public boolean implementsJspIdConsumer() { - return implementsJspIdConsumer; - } - - public boolean implementsSimpleTag() { - return implementsSimpleTag; - } - - public boolean implementsDynamicAttributes() { - return implementsDynamicAttributes; - } - - public TagVariableInfo[] getTagVariableInfos() { - return tagInfo.getTagVariableInfos(); - } - - public VariableInfo[] getVariableInfos() { - return varInfos; - } - - public void setCustomTagParent(Node.CustomTag n) { - this.customTagParent = n; - } - - public Node.CustomTag getCustomTagParent() { - return this.customTagParent; - } - - public void setNumCount(Integer count) { - this.numCount = count; - } - - public Integer getNumCount() { - return this.numCount; - } - - public void setScriptingVars(Vector vec, int scope) { - switch (scope) { - case VariableInfo.AT_BEGIN: - this.atBeginScriptingVars = vec; - break; - case VariableInfo.AT_END: - this.atEndScriptingVars = vec; - break; - case VariableInfo.NESTED: - this.nestedScriptingVars = vec; - break; - } - } - - /* - * Gets the scripting variables for the given scope that need to be - * declared. - */ - public Vector getScriptingVars(int scope) { - Vector vec = null; - - switch (scope) { - case VariableInfo.AT_BEGIN: - vec = this.atBeginScriptingVars; - break; - case VariableInfo.AT_END: - vec = this.atEndScriptingVars; - break; - case VariableInfo.NESTED: - vec = this.nestedScriptingVars; - break; - } - - return vec; - } - - /* - * Gets this custom tag's custom nesting level, which is given as the - * number of times this custom tag is nested inside itself. - */ - public int getCustomNestingLevel() { - return customNestingLevel; - } - - /** - * Checks to see if the attribute of the given name is of type - * JspFragment. - */ - public boolean checkIfAttributeIsJspFragment(String name) { - boolean result = false; - - TagAttributeInfo[] attributes = tagInfo.getAttributes(); - for (int i = 0; i < attributes.length; i++) { - if (attributes[i].getName().equals(name) - && attributes[i].isFragment()) { - result = true; - break; - } - } - - return result; - } - - public void setUseTagPlugin(boolean use) { - useTagPlugin = use; - } - - public boolean useTagPlugin() { - return useTagPlugin; - } - - public void setTagPluginContext(TagPluginContext tagPluginContext) { - this.tagPluginContext = tagPluginContext; - } - - public TagPluginContext getTagPluginContext() { - return tagPluginContext; - } - - public void setAtSTag(Nodes sTag) { - atSTag = sTag; - } - - public Nodes getAtSTag() { - return atSTag; - } - - public void setAtETag(Nodes eTag) { - atETag = eTag; - } - - public Nodes getAtETag() { - return atETag; - } - - /* - * Computes this custom tag's custom nesting level, which corresponds to - * the number of times this custom tag is nested inside itself. - * - * Example: - * - * -- nesting level 0 -- nesting level 1 - * -- nesting level 2 -- nesting level 1 - * - * - * @return Custom tag's nesting level - */ - private int makeCustomNestingLevel() { - int n = 0; - Node p = parent; - while (p != null) { - if ((p instanceof Node.CustomTag) - && qName.equals(((Node.CustomTag) p).qName)) { - n++; - } - p = p.parent; - } - return n; - } - - /** - * Returns true if this custom action has an empty body, and false - * otherwise. - * - * A custom action is considered to have an empty body if the following - * holds true: - getBody() returns null, or - all immediate children are - * jsp:attribute actions, or - the action's jsp:body is empty. - */ - public boolean hasEmptyBody() { - boolean hasEmptyBody = true; - Nodes nodes = getBody(); - if (nodes != null) { - int numChildNodes = nodes.size(); - for (int i = 0; i < numChildNodes; i++) { - Node n = nodes.getNode(i); - if (!(n instanceof NamedAttribute)) { - if (n instanceof JspBody) { - hasEmptyBody = (n.getBody() == null); - } else { - hasEmptyBody = false; - } - break; - } - } - } - - return hasEmptyBody; - } - } - - /** - * Used as a placeholder for the evaluation code of a custom action - * attribute (used by the tag plugin machinery only). - */ - public static class AttributeGenerator extends Node { - String name; // name of the attribute - - CustomTag tag; // The tag this attribute belongs to - - public AttributeGenerator(Mark start, String name, CustomTag tag) { - super(start, null); - this.name = name; - this.tag = tag; - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public String getName() { - return name; - } - - public CustomTag getTag() { - return tag; - } - } - - /** - * Represents the body of a <jsp:text> element - */ - public static class JspText extends Node { - - public JspText(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, TEXT_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - } - - /** - * Represents a Named Attribute (<jsp:attribute>) - */ - public static class NamedAttribute extends Node { - - // A unique temporary variable name suitable for code generation - private String temporaryVariableName; - - // True if this node is to be trimmed, or false otherwise - private boolean trim = true; - - private ChildInfo childInfo; - - private String name; - - private String localName; - - private String prefix; - - public NamedAttribute(Attributes attrs, Mark start, Node parent) { - this(JSP_ATTRIBUTE_ACTION, attrs, null, null, start, parent); - } - - public NamedAttribute(String qName, Attributes attrs, - Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, - Mark start, Node parent) { - - super(qName, ATTRIBUTE_ACTION, attrs, nonTaglibXmlnsAttrs, - taglibAttrs, start, parent); - temporaryVariableName = JspUtil.nextTemporaryVariableName(); - if ("false".equals(this.getAttributeValue("trim"))) { - // (if null or true, leave default of true) - trim = false; - } - childInfo = new ChildInfo(); - name = this.getAttributeValue("name"); - if (name != null) { - // Mandatary attribute "name" will be checked in Validator - localName = name; - int index = name.indexOf(':'); - if (index != -1) { - prefix = name.substring(0, index); - localName = name.substring(index + 1); - } - } - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public String getName() { - return this.name; - } - - public String getLocalName() { - return this.localName; - } - - public String getPrefix() { - return this.prefix; - } - - public ChildInfo getChildInfo() { - return this.childInfo; - } - - public boolean isTrim() { - return trim; - } - - /** - * @return A unique temporary variable name to store the result in. - * (this probably could go elsewhere, but it's convenient here) - */ - public String getTemporaryVariableName() { - return temporaryVariableName; - } - - /* - * Get the attribute value from this named attribute (). - * Since this method is only for attributes that are not rtexpr, we can - * assume the body of the jsp:attribute is a template text. - */ - public String getText() { - - class AttributeVisitor extends Visitor { - String attrValue = null; - - public void visit(TemplateText txt) { - attrValue = new String(txt.getText()); - } - - public String getAttrValue() { - return attrValue; - } - } - - // According to JSP 2.0, if the body of the - // action is empty, it is equivalent of specifying "" as the value - // of the attribute. - String text = ""; - if (getBody() != null) { - AttributeVisitor attributeVisitor = new AttributeVisitor(); - try { - getBody().visit(attributeVisitor); - } catch (JasperException e) { - } - text = attributeVisitor.getAttrValue(); - } - - return text; - } - } - - /** - * Represents a JspBody node (<jsp:body>) - */ - public static class JspBody extends Node { - - private ChildInfo childInfo; - - public JspBody(Mark start, Node parent) { - this(JSP_BODY_ACTION, null, null, start, parent); - } - - public JspBody(String qName, Attributes nonTaglibXmlnsAttrs, - Attributes taglibAttrs, Mark start, Node parent) { - super(qName, BODY_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, - start, parent); - this.childInfo = new ChildInfo(); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - public ChildInfo getChildInfo() { - return childInfo; - } - } - - /** - * Represents a template text string - */ - public static class TemplateText extends Node { - - private ArrayList extraSmap = null; - - public TemplateText(String text, Mark start, Node parent) { - super(null, null, text, start, parent); - } - - public void accept(Visitor v) throws JasperException { - v.visit(this); - } - - /** - * Trim all whitespace from the left of the template text - */ - public void ltrim() { - int index = 0; - while ((index < text.length()) && (text.charAt(index) <= ' ')) { - index++; - } - text = text.substring(index); - } - - public void setText(String text) { - this.text = text; - } - - /** - * Trim all whitespace from the right of the template text - */ - public void rtrim() { - int index = text.length(); - while ((index > 0) && (text.charAt(index - 1) <= ' ')) { - index--; - } - text = text.substring(0, index); - } - - /** - * Returns true if this template text contains whitespace only. - */ - public boolean isAllSpace() { - boolean isAllSpace = true; - for (int i = 0; i < text.length(); i++) { - if (!Character.isWhitespace(text.charAt(i))) { - isAllSpace = false; - break; - } - } - return isAllSpace; - } - - /** - * Add a source to Java line mapping - * - * @param srcLine - * The postion of the source line, relative to the line at - * the start of this node. The corresponding java line is - * assumed to be consecutive, i.e. one more than the last. - */ - public void addSmap(int srcLine) { - if (extraSmap == null) { - extraSmap = new ArrayList(); - } - extraSmap.add(new Integer(srcLine)); - } - - public ArrayList getExtraSmap() { - return extraSmap; - } - } - - /*************************************************************************** - * Auxillary classes used in Node - */ - - /** - * Represents attributes that can be request time expressions. - * - * Can either be a plain attribute, an attribute that represents a request - * time expression value, or a named attribute (specified using the - * jsp:attribute standard action). - */ - - public static class JspAttribute { - - private String qName; - - private String uri; - - private String localName; - - private String value; - - private boolean expression; - - private boolean dynamic; - - private final ELNode.Nodes el; - - private final TagAttributeInfo tai; - - // If true, this JspAttribute represents a - private boolean namedAttribute; - - // The node in the parse tree for the NamedAttribute - private NamedAttribute namedAttributeNode; - - JspAttribute(TagAttributeInfo tai, String qName, String uri, - String localName, String value, boolean expr, ELNode.Nodes el, - boolean dyn) { - this.qName = qName; - this.uri = uri; - this.localName = localName; - this.value = value; - this.namedAttributeNode = null; - this.expression = expr; - this.el = el; - this.dynamic = dyn; - this.namedAttribute = false; - this.tai = tai; - } - - /** - * Allow node to validate itself - * - * @param ef - * @param ctx - * @throws ELException - */ - public void validateEL(ExpressionFactory ef, ELContext ctx) - throws ELException { - if (this.el != null) { - // determine exact type - ValueExpression ve = ef.createValueExpression(ctx, this.value, - String.class); - } - } - - /** - * Use this constructor if the JspAttribute represents a named - * attribute. In this case, we have to store the nodes of the body of - * the attribute. - */ - JspAttribute(NamedAttribute na, TagAttributeInfo tai, boolean dyn) { - this.qName = na.getName(); - this.localName = na.getLocalName(); - this.value = null; - this.namedAttributeNode = na; - this.expression = false; - this.el = null; - this.dynamic = dyn; - this.namedAttribute = true; - this.tai = null; - } - - /** - * @return The name of the attribute - */ - public String getName() { - return qName; - } - - /** - * @return The local name of the attribute - */ - public String getLocalName() { - return localName; - } - - /** - * @return The namespace of the attribute, or null if in the default - * namespace - */ - public String getURI() { - return uri; - } - - public TagAttributeInfo getTagAttributeInfo() { - return this.tai; - } - - /** - * - * @return return true if there's TagAttributeInfo meaning we need to - * assign a ValueExpression - */ - public boolean isDeferredInput() { - return (this.tai != null) ? this.tai.isDeferredValue() : false; - } - - /** - * - * @return return true if there's TagAttributeInfo meaning we need to - * assign a MethodExpression - */ - public boolean isDeferredMethodInput() { - return (this.tai != null) ? this.tai.isDeferredMethod() : false; - } - - public String getExpectedTypeName() { - if (this.tai != null) { - if (this.isDeferredInput()) { - return this.tai.getExpectedTypeName(); - } else if (this.isDeferredMethodInput()) { - String m = this.tai.getMethodSignature(); - if (m != null) { - int rti = m.trim().indexOf(' '); - if (rti > 0) { - return m.substring(0, rti).trim(); - } - } - } - } - return "java.lang.Object"; - } - - public String[] getParameterTypeNames() { - if (this.tai != null) { - if (this.isDeferredMethodInput()) { - String m = this.tai.getMethodSignature(); - if (m != null) { - m = m.trim(); - m = m.substring(m.indexOf('(') + 1); - m = m.substring(0, m.length() - 1); - if (m.trim().length() > 0) { - String[] p = m.split(","); - for (int i = 0; i < p.length; i++) { - p[i] = p[i].trim(); - } - return p; - } - } - } - } - return new String[0]; - } - - /** - * Only makes sense if namedAttribute is false. - * - * @return the value for the attribute, or the expression string - * (stripped of "<%=", "%>", "%=", or "%" but containing "${" - * and "}" for EL expressions) - */ - public String getValue() { - return value; - } - - /** - * Only makes sense if namedAttribute is true. - * - * @return the nodes that evaluate to the body of this attribute. - */ - public NamedAttribute getNamedAttributeNode() { - return namedAttributeNode; - } - - /** - * @return true if the value represents a traditional rtexprvalue - */ - public boolean isExpression() { - return expression; - } - - /** - * @return true if the value represents a NamedAttribute value. - */ - public boolean isNamedAttribute() { - return namedAttribute; - } - - /** - * @return true if the value represents an expression that should be fed - * to the expression interpreter - * @return false for string literals or rtexprvalues that should not be - * interpreted or reevaluated - */ - public boolean isELInterpreterInput() { - return el != null || this.isDeferredInput() - || this.isDeferredMethodInput(); - } - - /** - * @return true if the value is a string literal known at translation - * time. - */ - public boolean isLiteral() { - return !expression && (el != null) && !namedAttribute; - } - - /** - * XXX - */ - public boolean isDynamic() { - return dynamic; - } - - public ELNode.Nodes getEL() { - return el; - } - } - - /** - * An ordered list of Node, used to represent the body of an element, or a - * jsp page of jsp document. - */ - public static class Nodes { - - private List list; - - private Node.Root root; // null if this is not a page - - private boolean generatedInBuffer; - - public Nodes() { - list = new Vector(); - } - - public Nodes(Node.Root root) { - this.root = root; - list = new Vector(); - list.add(root); - } - - /** - * Appends a node to the list - * - * @param n - * The node to add - */ - public void add(Node n) { - list.add(n); - root = null; - } - - /** - * Removes the given node from the list. - * - * @param n - * The node to be removed - */ - public void remove(Node n) { - list.remove(n); - } - - /** - * Visit the nodes in the list with the supplied visitor - * - * @param v - * The visitor used - */ - public void visit(Visitor v) throws JasperException { - Iterator iter = list.iterator(); - while (iter.hasNext()) { - Node n = (Node) iter.next(); - n.accept(v); - } - } - - public int size() { - return list.size(); - } - - public Node getNode(int index) { - Node n = null; - try { - n = (Node) list.get(index); - } catch (ArrayIndexOutOfBoundsException e) { - } - return n; - } - - public Node.Root getRoot() { - return root; - } - - public boolean isGeneratedInBuffer() { - return generatedInBuffer; - } - - public void setGeneratedInBuffer(boolean g) { - generatedInBuffer = g; - } - } - - /** - * A visitor class for visiting the node. This class also provides the - * default action (i.e. nop) for each of the child class of the Node. An - * actual visitor should extend this class and supply the visit method for - * the nodes that it cares. - */ - public static class Visitor { - - /** - * This method provides a place to put actions that are common to all - * nodes. Override this in the child visitor class if need to. - */ - protected void doVisit(Node n) throws JasperException { - } - - /** - * Visit the body of a node, using the current visitor - */ - protected void visitBody(Node n) throws JasperException { - if (n.getBody() != null) { - n.getBody().visit(this); - } - } - - public void visit(Root n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(JspRoot n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(PageDirective n) throws JasperException { - doVisit(n); - } - - public void visit(TagDirective n) throws JasperException { - doVisit(n); - } - - public void visit(IncludeDirective n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(TaglibDirective n) throws JasperException { - doVisit(n); - } - - public void visit(AttributeDirective n) throws JasperException { - doVisit(n); - } - - public void visit(VariableDirective n) throws JasperException { - doVisit(n); - } - - public void visit(Comment n) throws JasperException { - doVisit(n); - } - - public void visit(Declaration n) throws JasperException { - doVisit(n); - } - - public void visit(Expression n) throws JasperException { - doVisit(n); - } - - public void visit(Scriptlet n) throws JasperException { - doVisit(n); - } - - public void visit(ELExpression n) throws JasperException { - doVisit(n); - } - - public void visit(IncludeAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(ForwardAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(GetProperty n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(SetProperty n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(ParamAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(ParamsAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(FallBackAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(UseBean n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(PlugIn n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(CustomTag n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(UninterpretedTag n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(JspElement n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(JspText n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(NamedAttribute n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(JspBody n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(InvokeAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(DoBodyAction n) throws JasperException { - doVisit(n); - visitBody(n); - } - - public void visit(TemplateText n) throws JasperException { - doVisit(n); - } - - public void visit(JspOutput n) throws JasperException { - doVisit(n); - } - - public void visit(AttributeGenerator n) throws JasperException { - doVisit(n); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.Iterator; +import java.util.List; +import java.util.Vector; +import java.util.ArrayList; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ExpressionFactory; +import javax.el.ValueExpression; +import javax.servlet.jsp.tagext.BodyTag; +import javax.servlet.jsp.tagext.DynamicAttributes; +import javax.servlet.jsp.tagext.IterationTag; +import javax.servlet.jsp.tagext.JspIdConsumer; +import javax.servlet.jsp.tagext.SimpleTag; +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagData; +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagVariableInfo; +import javax.servlet.jsp.tagext.TryCatchFinally; +import javax.servlet.jsp.tagext.VariableInfo; + +import org.apache.jasper.JasperException; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; +import org.xml.sax.Attributes; + +/** + * An internal data representation of a JSP page or a JSP docuement (XML). Also + * included here is a visitor class for tranversing nodes. + * + * @author Kin-man Chung + * @author Jan Luehe + * @author Shawn Bayern + * @author Mark Roth + */ + +abstract class Node implements TagConstants { + + private static final VariableInfo[] ZERO_VARIABLE_INFO = {}; + + protected Attributes attrs; + + // xmlns attributes that represent tag libraries (only in XML syntax) + protected Attributes taglibAttrs; + + /* + * xmlns attributes that do not represent tag libraries (only in XML syntax) + */ + protected Attributes nonTaglibXmlnsAttrs; + + protected Nodes body; + + protected String text; + + protected Mark startMark; + + protected int beginJavaLine; + + protected int endJavaLine; + + protected Node parent; + + protected Nodes namedAttributeNodes; // cached for performance + + protected String qName; + + protected String localName; + + /* + * The name of the inner class to which the codes for this node and its body + * are generated. For instance, for in foo.jsp, this is + * "foo_jspHelper". This is primarily used for communicating such info from + * Generator to Smap generator. + */ + protected String innerClassName; + + private boolean isDummy; + + /** + * Zero-arg Constructor. + */ + public Node() { + this.isDummy = true; + } + + /** + * Constructor. + * + * @param start + * The location of the jsp page + * @param parent + * The enclosing node + */ + public Node(Mark start, Node parent) { + this.startMark = start; + this.isDummy = (start == null); + addToParent(parent); + } + + /** + * Constructor. + * + * @param qName + * The action's qualified name + * @param localName + * The action's local name + * @param start + * The location of the jsp page + * @param parent + * The enclosing node + */ + public Node(String qName, String localName, Mark start, Node parent) { + this.qName = qName; + this.localName = localName; + this.startMark = start; + this.isDummy = (start == null); + addToParent(parent); + } + + /** + * Constructor for Nodes parsed from standard syntax. + * + * @param qName + * The action's qualified name + * @param localName + * The action's local name + * @param attrs + * The attributes for this node + * @param start + * The location of the jsp page + * @param parent + * The enclosing node + */ + public Node(String qName, String localName, Attributes attrs, Mark start, + Node parent) { + this.qName = qName; + this.localName = localName; + this.attrs = attrs; + this.startMark = start; + this.isDummy = (start == null); + addToParent(parent); + } + + /** + * Constructor for Nodes parsed from XML syntax. + * + * @param qName + * The action's qualified name + * @param localName + * The action's local name + * @param attrs + * The action's attributes whose name does not start with xmlns + * @param nonTaglibXmlnsAttrs + * The action's xmlns attributes that do not represent tag + * libraries + * @param taglibAttrs + * The action's xmlns attributes that represent tag libraries + * @param start + * The location of the jsp page + * @param parent + * The enclosing node + */ + public Node(String qName, String localName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, Mark start, + Node parent) { + this.qName = qName; + this.localName = localName; + this.attrs = attrs; + this.nonTaglibXmlnsAttrs = nonTaglibXmlnsAttrs; + this.taglibAttrs = taglibAttrs; + this.startMark = start; + this.isDummy = (start == null); + addToParent(parent); + } + + /* + * Constructor. + * + * @param qName The action's qualified name @param localName The action's + * local name @param text The text associated with this node @param start + * The location of the jsp page @param parent The enclosing node + */ + public Node(String qName, String localName, String text, Mark start, + Node parent) { + this.qName = qName; + this.localName = localName; + this.text = text; + this.startMark = start; + this.isDummy = (start == null); + addToParent(parent); + } + + public String getQName() { + return this.qName; + } + + public String getLocalName() { + return this.localName; + } + + /* + * Gets this Node's attributes. + * + * In the case of a Node parsed from standard syntax, this method returns + * all the Node's attributes. + * + * In the case of a Node parsed from XML syntax, this method returns only + * those attributes whose name does not start with xmlns. + */ + public Attributes getAttributes() { + return this.attrs; + } + + /* + * Gets this Node's xmlns attributes that represent tag libraries (only + * meaningful for Nodes parsed from XML syntax) + */ + public Attributes getTaglibAttributes() { + return this.taglibAttrs; + } + + /* + * Gets this Node's xmlns attributes that do not represent tag libraries + * (only meaningful for Nodes parsed from XML syntax) + */ + public Attributes getNonTaglibXmlnsAttributes() { + return this.nonTaglibXmlnsAttrs; + } + + public void setAttributes(Attributes attrs) { + this.attrs = attrs; + } + + public String getAttributeValue(String name) { + return (attrs == null) ? null : attrs.getValue(name); + } + + /** + * Get the attribute that is non request time expression, either from the + * attribute of the node, or from a jsp:attrbute + */ + public String getTextAttribute(String name) { + + String attr = getAttributeValue(name); + if (attr != null) { + return attr; + } + + NamedAttribute namedAttribute = getNamedAttributeNode(name); + if (namedAttribute == null) { + return null; + } + + return namedAttribute.getText(); + } + + /** + * Searches all subnodes of this node for jsp:attribute standard actions + * with the given name, and returns the NamedAttribute node of the matching + * named attribute, nor null if no such node is found. + *

        + * This should always be called and only be called for nodes that accept + * dynamic runtime attribute expressions. + */ + public NamedAttribute getNamedAttributeNode(String name) { + NamedAttribute result = null; + + // Look for the attribute in NamedAttribute children + Nodes nodes = getNamedAttributeNodes(); + int numChildNodes = nodes.size(); + for (int i = 0; i < numChildNodes; i++) { + NamedAttribute na = (NamedAttribute) nodes.getNode(i); + boolean found = false; + int index = name.indexOf(':'); + if (index != -1) { + // qualified name + found = na.getName().equals(name); + } else { + found = na.getLocalName().equals(name); + } + if (found) { + result = na; + break; + } + } + + return result; + } + + /** + * Searches all subnodes of this node for jsp:attribute standard actions, + * and returns that set of nodes as a Node.Nodes object. + * + * @return Possibly empty Node.Nodes object containing any jsp:attribute + * subnodes of this Node + */ + public Node.Nodes getNamedAttributeNodes() { + + if (namedAttributeNodes != null) { + return namedAttributeNodes; + } + + Node.Nodes result = new Node.Nodes(); + + // Look for the attribute in NamedAttribute children + Nodes nodes = getBody(); + if (nodes != null) { + int numChildNodes = nodes.size(); + for (int i = 0; i < numChildNodes; i++) { + Node n = nodes.getNode(i); + if (n instanceof NamedAttribute) { + result.add(n); + } else if (!(n instanceof Comment)) { + // Nothing can come before jsp:attribute, and only + // jsp:body can come after it. + break; + } + } + } + + namedAttributeNodes = result; + return result; + } + + public Nodes getBody() { + return body; + } + + public void setBody(Nodes body) { + this.body = body; + } + + public String getText() { + return text; + } + + public Mark getStart() { + return startMark; + } + + public Node getParent() { + return parent; + } + + public int getBeginJavaLine() { + return beginJavaLine; + } + + public void setBeginJavaLine(int begin) { + beginJavaLine = begin; + } + + public int getEndJavaLine() { + return endJavaLine; + } + + public void setEndJavaLine(int end) { + endJavaLine = end; + } + + public boolean isDummy() { + return isDummy; + } + + public Node.Root getRoot() { + Node n = this; + while (!(n instanceof Node.Root)) { + n = n.getParent(); + } + return (Node.Root) n; + } + + public String getInnerClassName() { + return innerClassName; + } + + public void setInnerClassName(String icn) { + innerClassName = icn; + } + + /** + * Selects and invokes a method in the visitor class based on the node type. + * This is abstract and should be overrode by the extending classes. + * + * @param v + * The visitor class + */ + abstract void accept(Visitor v) throws JasperException; + + // ********************************************************************* + // Private utility methods + + /* + * Adds this Node to the body of the given parent. + */ + private void addToParent(Node parent) { + if (parent != null) { + this.parent = parent; + Nodes parentBody = parent.getBody(); + if (parentBody == null) { + parentBody = new Nodes(); + parent.setBody(parentBody); + } + parentBody.add(this); + } + } + + /*************************************************************************** + * Child classes + */ + + /** + * Represents the root of a Jsp page or Jsp document + */ + public static class Root extends Node { + + private Root parentRoot; + + private boolean isXmlSyntax; + + // Source encoding of the page containing this Root + private String pageEnc; + + // Page encoding specified in JSP config element + private String jspConfigPageEnc; + + /* + * Flag indicating if the default page encoding is being used (only + * applicable with standard syntax). + * + * True if the page does not provide a page directive with a + * 'contentType' attribute (or the 'contentType' attribute doesn't have + * a CHARSET value), the page does not provide a page directive with a + * 'pageEncoding' attribute, and there is no JSP configuration element + * page-encoding whose URL pattern matches the page. + */ + private boolean isDefaultPageEncoding; + + /* + * Indicates whether an encoding has been explicitly specified in the + * page's XML prolog (only used for pages in XML syntax). This + * information is used to decide whether a translation error must be + * reported for encoding conflicts. + */ + private boolean isEncodingSpecifiedInProlog; + + /* + * Constructor. + */ + Root(Mark start, Node parent, boolean isXmlSyntax) { + super(start, parent); + this.isXmlSyntax = isXmlSyntax; + this.qName = JSP_ROOT_ACTION; + this.localName = ROOT_ACTION; + + // Figure out and set the parent root + Node r = parent; + while ((r != null) && !(r instanceof Node.Root)) + r = r.getParent(); + parentRoot = (Node.Root) r; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public boolean isXmlSyntax() { + return isXmlSyntax; + } + + /* + * Sets the encoding specified in the JSP config element whose URL + * pattern matches the page containing this Root. + */ + public void setJspConfigPageEncoding(String enc) { + jspConfigPageEnc = enc; + } + + /* + * Gets the encoding specified in the JSP config element whose URL + * pattern matches the page containing this Root. + */ + public String getJspConfigPageEncoding() { + return jspConfigPageEnc; + } + + public void setPageEncoding(String enc) { + pageEnc = enc; + } + + public String getPageEncoding() { + return pageEnc; + } + + public void setIsDefaultPageEncoding(boolean isDefault) { + isDefaultPageEncoding = isDefault; + } + + public boolean isDefaultPageEncoding() { + return isDefaultPageEncoding; + } + + public void setIsEncodingSpecifiedInProlog(boolean isSpecified) { + isEncodingSpecifiedInProlog = isSpecified; + } + + public boolean isEncodingSpecifiedInProlog() { + return isEncodingSpecifiedInProlog; + } + + /** + * @return The enclosing root to this Root. Usually represents the page + * that includes this one. + */ + public Root getParentRoot() { + return parentRoot; + } + } + + /** + * Represents the root of a Jsp document (XML syntax) + */ + public static class JspRoot extends Node { + + public JspRoot(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, ROOT_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a page directive + */ + public static class PageDirective extends Node { + + private Vector imports; + + public PageDirective(Attributes attrs, Mark start, Node parent) { + this(JSP_PAGE_DIRECTIVE_ACTION, attrs, null, null, start, parent); + } + + public PageDirective(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, PAGE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + imports = new Vector(); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + /** + * Parses the comma-separated list of class or package names in the + * given attribute value and adds each component to this PageDirective's + * vector of imported classes and packages. + * + * @param value + * A comma-separated string of imports. + */ + public void addImport(String value) { + int start = 0; + int index; + while ((index = value.indexOf(',', start)) != -1) { + imports.add(value.substring(start, index).trim()); + start = index + 1; + } + if (start == 0) { + // No comma found + imports.add(value.trim()); + } else { + imports.add(value.substring(start).trim()); + } + } + + public List getImports() { + return imports; + } + } + + /** + * Represents an include directive + */ + public static class IncludeDirective extends Node { + + public IncludeDirective(Attributes attrs, Mark start, Node parent) { + this(JSP_INCLUDE_DIRECTIVE_ACTION, attrs, null, null, start, parent); + } + + public IncludeDirective(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, INCLUDE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a custom taglib directive + */ + public static class TaglibDirective extends Node { + + public TaglibDirective(Attributes attrs, Mark start, Node parent) { + super(JSP_TAGLIB_DIRECTIVE_ACTION, TAGLIB_DIRECTIVE_ACTION, attrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a tag directive + */ + public static class TagDirective extends Node { + private Vector imports; + + public TagDirective(Attributes attrs, Mark start, Node parent) { + this(JSP_TAG_DIRECTIVE_ACTION, attrs, null, null, start, parent); + } + + public TagDirective(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, TAG_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + imports = new Vector(); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + /** + * Parses the comma-separated list of class or package names in the + * given attribute value and adds each component to this PageDirective's + * vector of imported classes and packages. + * + * @param value + * A comma-separated string of imports. + */ + public void addImport(String value) { + int start = 0; + int index; + while ((index = value.indexOf(',', start)) != -1) { + imports.add(value.substring(start, index).trim()); + start = index + 1; + } + if (start == 0) { + // No comma found + imports.add(value.trim()); + } else { + imports.add(value.substring(start).trim()); + } + } + + public List getImports() { + return imports; + } + } + + /** + * Represents an attribute directive + */ + public static class AttributeDirective extends Node { + + public AttributeDirective(Attributes attrs, Mark start, Node parent) { + this(JSP_ATTRIBUTE_DIRECTIVE_ACTION, attrs, null, null, start, + parent); + } + + public AttributeDirective(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, ATTRIBUTE_DIRECTIVE_ACTION, attrs, + nonTaglibXmlnsAttrs, taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a variable directive + */ + public static class VariableDirective extends Node { + + public VariableDirective(Attributes attrs, Mark start, Node parent) { + this(JSP_VARIABLE_DIRECTIVE_ACTION, attrs, null, null, start, + parent); + } + + public VariableDirective(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, VARIABLE_DIRECTIVE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a tag file action + */ + public static class InvokeAction extends Node { + + public InvokeAction(Attributes attrs, Mark start, Node parent) { + this(JSP_INVOKE_ACTION, attrs, null, null, start, parent); + } + + public InvokeAction(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, INVOKE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a tag file action + */ + public static class DoBodyAction extends Node { + + public DoBodyAction(Attributes attrs, Mark start, Node parent) { + this(JSP_DOBODY_ACTION, attrs, null, null, start, parent); + } + + public DoBodyAction(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, DOBODY_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a Jsp comment Comments are kept for completeness. + */ + public static class Comment extends Node { + + public Comment(String text, Mark start, Node parent) { + super(null, null, text, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents an expression, declaration, or scriptlet + */ + public static abstract class ScriptingElement extends Node { + + public ScriptingElement(String qName, String localName, String text, + Mark start, Node parent) { + super(qName, localName, text, start, parent); + } + + public ScriptingElement(String qName, String localName, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, localName, null, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + /** + * When this node was created from a JSP page in JSP syntax, its text + * was stored as a String in the "text" field, whereas when this node + * was created from a JSP document, its text was stored as one or more + * TemplateText nodes in its body. This method handles either case. + * + * @return The text string + */ + public String getText() { + String ret = text; + if ((ret == null) && (body != null)) { + StringBuffer buf = new StringBuffer(); + for (int i = 0; i < body.size(); i++) { + buf.append(body.getNode(i).getText()); + } + ret = buf.toString(); + } + return ret; + } + + /** + * For the same reason as above, the source line information in the + * contained TemplateText node should be used. + */ + public Mark getStart() { + if (text == null && body != null && body.size() > 0) { + return body.getNode(0).getStart(); + } else { + return super.getStart(); + } + } + } + + /** + * Represents a declaration + */ + public static class Declaration extends ScriptingElement { + + public Declaration(String text, Mark start, Node parent) { + super(JSP_DECLARATION_ACTION, DECLARATION_ACTION, text, start, + parent); + } + + public Declaration(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, DECLARATION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents an expression. Expressions in attributes are embedded in the + * attribute string and not here. + */ + public static class Expression extends ScriptingElement { + + public Expression(String text, Mark start, Node parent) { + super(JSP_EXPRESSION_ACTION, EXPRESSION_ACTION, text, start, parent); + } + + public Expression(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, EXPRESSION_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a scriptlet + */ + public static class Scriptlet extends ScriptingElement { + + public Scriptlet(String text, Mark start, Node parent) { + super(JSP_SCRIPTLET_ACTION, SCRIPTLET_ACTION, text, start, parent); + } + + public Scriptlet(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, SCRIPTLET_ACTION, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents an EL expression. Expressions in attributes are embedded in + * the attribute string and not here. + */ + public static class ELExpression extends Node { + + private ELNode.Nodes el; + + private final char type; + + public ELExpression(char type, String text, Mark start, Node parent) { + super(null, null, text, start, parent); + this.type = type; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setEL(ELNode.Nodes el) { + this.el = el; + } + + public ELNode.Nodes getEL() { + return el; + } + + public char getType() { + return this.type; + } + } + + /** + * Represents a param action + */ + public static class ParamAction extends Node { + + JspAttribute value; + + public ParamAction(Attributes attrs, Mark start, Node parent) { + this(JSP_PARAM_ACTION, attrs, null, null, start, parent); + } + + public ParamAction(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, PARAM_ACTION, attrs, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setValue(JspAttribute value) { + this.value = value; + } + + public JspAttribute getValue() { + return value; + } + } + + /** + * Represents a params action + */ + public static class ParamsAction extends Node { + + public ParamsAction(Mark start, Node parent) { + this(JSP_PARAMS_ACTION, null, null, start, parent); + } + + public ParamsAction(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, PARAMS_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a fallback action + */ + public static class FallBackAction extends Node { + + public FallBackAction(Mark start, Node parent) { + this(JSP_FALLBACK_ACTION, null, null, start, parent); + } + + public FallBackAction(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, FALLBACK_ACTION, null, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents an include action + */ + public static class IncludeAction extends Node { + + private JspAttribute page; + + public IncludeAction(Attributes attrs, Mark start, Node parent) { + this(JSP_INCLUDE_ACTION, attrs, null, null, start, parent); + } + + public IncludeAction(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, INCLUDE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setPage(JspAttribute page) { + this.page = page; + } + + public JspAttribute getPage() { + return page; + } + } + + /** + * Represents a forward action + */ + public static class ForwardAction extends Node { + + private JspAttribute page; + + public ForwardAction(Attributes attrs, Mark start, Node parent) { + this(JSP_FORWARD_ACTION, attrs, null, null, start, parent); + } + + public ForwardAction(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, FORWARD_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setPage(JspAttribute page) { + this.page = page; + } + + public JspAttribute getPage() { + return page; + } + } + + /** + * Represents a getProperty action + */ + public static class GetProperty extends Node { + + public GetProperty(Attributes attrs, Mark start, Node parent) { + this(JSP_GET_PROPERTY_ACTION, attrs, null, null, start, parent); + } + + public GetProperty(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, GET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a setProperty action + */ + public static class SetProperty extends Node { + + private JspAttribute value; + + public SetProperty(Attributes attrs, Mark start, Node parent) { + this(JSP_SET_PROPERTY_ACTION, attrs, null, null, start, parent); + } + + public SetProperty(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, SET_PROPERTY_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setValue(JspAttribute value) { + this.value = value; + } + + public JspAttribute getValue() { + return value; + } + } + + /** + * Represents a useBean action + */ + public static class UseBean extends Node { + + JspAttribute beanName; + + public UseBean(Attributes attrs, Mark start, Node parent) { + this(JSP_USE_BEAN_ACTION, attrs, null, null, start, parent); + } + + public UseBean(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, USE_BEAN_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setBeanName(JspAttribute beanName) { + this.beanName = beanName; + } + + public JspAttribute getBeanName() { + return beanName; + } + } + + /** + * Represents a plugin action + */ + public static class PlugIn extends Node { + + private JspAttribute width; + + private JspAttribute height; + + public PlugIn(Attributes attrs, Mark start, Node parent) { + this(JSP_PLUGIN_ACTION, attrs, null, null, start, parent); + } + + public PlugIn(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, PLUGIN_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setHeight(JspAttribute height) { + this.height = height; + } + + public void setWidth(JspAttribute width) { + this.width = width; + } + + public JspAttribute getHeight() { + return height; + } + + public JspAttribute getWidth() { + return width; + } + } + + /** + * Represents an uninterpreted tag, from a Jsp document + */ + public static class UninterpretedTag extends Node { + + private JspAttribute[] jspAttrs; + + public UninterpretedTag(String qName, String localName, + Attributes attrs, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setJspAttributes(JspAttribute[] jspAttrs) { + this.jspAttrs = jspAttrs; + } + + public JspAttribute[] getJspAttributes() { + return jspAttrs; + } + } + + /** + * Represents a . + */ + public static class JspElement extends Node { + + private JspAttribute[] jspAttrs; + + private JspAttribute nameAttr; + + public JspElement(Attributes attrs, Mark start, Node parent) { + this(JSP_ELEMENT_ACTION, attrs, null, null, start, parent); + } + + public JspElement(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, ELEMENT_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public void setJspAttributes(JspAttribute[] jspAttrs) { + this.jspAttrs = jspAttrs; + } + + public JspAttribute[] getJspAttributes() { + return jspAttrs; + } + + /* + * Sets the XML-style 'name' attribute + */ + public void setNameAttribute(JspAttribute nameAttr) { + this.nameAttr = nameAttr; + } + + /* + * Gets the XML-style 'name' attribute + */ + public JspAttribute getNameAttribute() { + return this.nameAttr; + } + } + + /** + * Represents a . + */ + public static class JspOutput extends Node { + + public JspOutput(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + super(qName, OUTPUT_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Collected information about child elements. Used by nodes like CustomTag, + * JspBody, and NamedAttribute. The information is set in the Collector. + */ + public static class ChildInfo { + private boolean scriptless; // true if the tag and its body + + // contain no scripting elements. + private boolean hasUseBean; + + private boolean hasIncludeAction; + + private boolean hasParamAction; + + private boolean hasSetProperty; + + private boolean hasScriptingVars; + + public void setScriptless(boolean s) { + scriptless = s; + } + + public boolean isScriptless() { + return scriptless; + } + + public void setHasUseBean(boolean u) { + hasUseBean = u; + } + + public boolean hasUseBean() { + return hasUseBean; + } + + public void setHasIncludeAction(boolean i) { + hasIncludeAction = i; + } + + public boolean hasIncludeAction() { + return hasIncludeAction; + } + + public void setHasParamAction(boolean i) { + hasParamAction = i; + } + + public boolean hasParamAction() { + return hasParamAction; + } + + public void setHasSetProperty(boolean s) { + hasSetProperty = s; + } + + public boolean hasSetProperty() { + return hasSetProperty; + } + + public void setHasScriptingVars(boolean s) { + hasScriptingVars = s; + } + + public boolean hasScriptingVars() { + return hasScriptingVars; + } + } + + /** + * Represents a custom tag + */ + public static class CustomTag extends Node { + + private String uri; + + private String prefix; + + private JspAttribute[] jspAttrs; + + private TagData tagData; + + private String tagHandlerPoolName; + + private TagInfo tagInfo; + + private TagFileInfo tagFileInfo; + + private Class tagHandlerClass; + + private VariableInfo[] varInfos; + + private int customNestingLevel; + + private ChildInfo childInfo; + + private boolean implementsIterationTag; + + private boolean implementsBodyTag; + + private boolean implementsTryCatchFinally; + + private boolean implementsJspIdConsumer; + + private boolean implementsSimpleTag; + + private boolean implementsDynamicAttributes; + + private Vector atBeginScriptingVars; + + private Vector atEndScriptingVars; + + private Vector nestedScriptingVars; + + private Node.CustomTag customTagParent; + + private Integer numCount; + + private boolean useTagPlugin; + + private TagPluginContext tagPluginContext; + + /** + * The following two fields are used for holding the Java scriptlets + * that the tag plugins may generate. Meaningful only if useTagPlugin is + * true; Could move them into TagPluginContextImpl, but we'll need to + * cast tagPluginContext to TagPluginContextImpl all the time... + */ + private Nodes atSTag; + + private Nodes atETag; + + /* + * Constructor for custom action implemented by tag handler. + */ + public CustomTag(String qName, String prefix, String localName, + String uri, Attributes attrs, Mark start, Node parent, + TagInfo tagInfo, Class tagHandlerClass) { + this(qName, prefix, localName, uri, attrs, null, null, start, + parent, tagInfo, tagHandlerClass); + } + + /* + * Constructor for custom action implemented by tag handler. + */ + public CustomTag(String qName, String prefix, String localName, + String uri, Attributes attrs, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent, + TagInfo tagInfo, Class tagHandlerClass) { + super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + + this.uri = uri; + this.prefix = prefix; + this.tagInfo = tagInfo; + this.tagHandlerClass = tagHandlerClass; + this.customNestingLevel = makeCustomNestingLevel(); + this.childInfo = new ChildInfo(); + + this.implementsIterationTag = IterationTag.class + .isAssignableFrom(tagHandlerClass); + this.implementsBodyTag = BodyTag.class + .isAssignableFrom(tagHandlerClass); + this.implementsTryCatchFinally = TryCatchFinally.class + .isAssignableFrom(tagHandlerClass); + this.implementsSimpleTag = SimpleTag.class + .isAssignableFrom(tagHandlerClass); + this.implementsDynamicAttributes = DynamicAttributes.class + .isAssignableFrom(tagHandlerClass); + this.implementsJspIdConsumer = JspIdConsumer.class + .isAssignableFrom(tagHandlerClass); + } + + /* + * Constructor for custom action implemented by tag file. + */ + public CustomTag(String qName, String prefix, String localName, + String uri, Attributes attrs, Mark start, Node parent, + TagFileInfo tagFileInfo) { + this(qName, prefix, localName, uri, attrs, null, null, start, + parent, tagFileInfo); + } + + /* + * Constructor for custom action implemented by tag file. + */ + public CustomTag(String qName, String prefix, String localName, + String uri, Attributes attrs, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent, + TagFileInfo tagFileInfo) { + + super(qName, localName, attrs, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + + this.uri = uri; + this.prefix = prefix; + this.tagFileInfo = tagFileInfo; + this.tagInfo = tagFileInfo.getTagInfo(); + this.customNestingLevel = makeCustomNestingLevel(); + this.childInfo = new ChildInfo(); + + this.implementsIterationTag = false; + this.implementsBodyTag = false; + this.implementsTryCatchFinally = false; + this.implementsSimpleTag = true; + this.implementsJspIdConsumer = false; + this.implementsDynamicAttributes = tagInfo.hasDynamicAttributes(); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + /** + * @return The URI namespace that this custom action belongs to + */ + public String getURI() { + return this.uri; + } + + /** + * @return The tag prefix + */ + public String getPrefix() { + return prefix; + } + + public void setJspAttributes(JspAttribute[] jspAttrs) { + this.jspAttrs = jspAttrs; + } + + public TagAttributeInfo getTagAttributeInfo(String name) { + TagInfo info = this.getTagInfo(); + if (info == null) + return null; + TagAttributeInfo[] tai = info.getAttributes(); + for (int i = 0; i < tai.length; i++) { + if (tai[i].getName().equals(name)) { + return tai[i]; + } + } + return null; + } + + public JspAttribute[] getJspAttributes() { + return jspAttrs; + } + + public ChildInfo getChildInfo() { + return childInfo; + } + + public void setTagData(TagData tagData) { + this.tagData = tagData; + this.varInfos = tagInfo.getVariableInfo(tagData); + if (this.varInfos == null) { + this.varInfos = ZERO_VARIABLE_INFO; + } + } + + public TagData getTagData() { + return tagData; + } + + public void setTagHandlerPoolName(String s) { + tagHandlerPoolName = s; + } + + public String getTagHandlerPoolName() { + return tagHandlerPoolName; + } + + public TagInfo getTagInfo() { + return tagInfo; + } + + public TagFileInfo getTagFileInfo() { + return tagFileInfo; + } + + /* + * @return true if this custom action is supported by a tag file, false + * otherwise + */ + public boolean isTagFile() { + return tagFileInfo != null; + } + + public Class getTagHandlerClass() { + return tagHandlerClass; + } + + public void setTagHandlerClass(Class hc) { + tagHandlerClass = hc; + } + + public boolean implementsIterationTag() { + return implementsIterationTag; + } + + public boolean implementsBodyTag() { + return implementsBodyTag; + } + + public boolean implementsTryCatchFinally() { + return implementsTryCatchFinally; + } + + public boolean implementsJspIdConsumer() { + return implementsJspIdConsumer; + } + + public boolean implementsSimpleTag() { + return implementsSimpleTag; + } + + public boolean implementsDynamicAttributes() { + return implementsDynamicAttributes; + } + + public TagVariableInfo[] getTagVariableInfos() { + return tagInfo.getTagVariableInfos(); + } + + public VariableInfo[] getVariableInfos() { + return varInfos; + } + + public void setCustomTagParent(Node.CustomTag n) { + this.customTagParent = n; + } + + public Node.CustomTag getCustomTagParent() { + return this.customTagParent; + } + + public void setNumCount(Integer count) { + this.numCount = count; + } + + public Integer getNumCount() { + return this.numCount; + } + + public void setScriptingVars(Vector vec, int scope) { + switch (scope) { + case VariableInfo.AT_BEGIN: + this.atBeginScriptingVars = vec; + break; + case VariableInfo.AT_END: + this.atEndScriptingVars = vec; + break; + case VariableInfo.NESTED: + this.nestedScriptingVars = vec; + break; + } + } + + /* + * Gets the scripting variables for the given scope that need to be + * declared. + */ + public Vector getScriptingVars(int scope) { + Vector vec = null; + + switch (scope) { + case VariableInfo.AT_BEGIN: + vec = this.atBeginScriptingVars; + break; + case VariableInfo.AT_END: + vec = this.atEndScriptingVars; + break; + case VariableInfo.NESTED: + vec = this.nestedScriptingVars; + break; + } + + return vec; + } + + /* + * Gets this custom tag's custom nesting level, which is given as the + * number of times this custom tag is nested inside itself. + */ + public int getCustomNestingLevel() { + return customNestingLevel; + } + + /** + * Checks to see if the attribute of the given name is of type + * JspFragment. + */ + public boolean checkIfAttributeIsJspFragment(String name) { + boolean result = false; + + TagAttributeInfo[] attributes = tagInfo.getAttributes(); + for (int i = 0; i < attributes.length; i++) { + if (attributes[i].getName().equals(name) + && attributes[i].isFragment()) { + result = true; + break; + } + } + + return result; + } + + public void setUseTagPlugin(boolean use) { + useTagPlugin = use; + } + + public boolean useTagPlugin() { + return useTagPlugin; + } + + public void setTagPluginContext(TagPluginContext tagPluginContext) { + this.tagPluginContext = tagPluginContext; + } + + public TagPluginContext getTagPluginContext() { + return tagPluginContext; + } + + public void setAtSTag(Nodes sTag) { + atSTag = sTag; + } + + public Nodes getAtSTag() { + return atSTag; + } + + public void setAtETag(Nodes eTag) { + atETag = eTag; + } + + public Nodes getAtETag() { + return atETag; + } + + /* + * Computes this custom tag's custom nesting level, which corresponds to + * the number of times this custom tag is nested inside itself. + * + * Example: + * + * -- nesting level 0 -- nesting level 1 + * -- nesting level 2 -- nesting level 1 + * + * + * @return Custom tag's nesting level + */ + private int makeCustomNestingLevel() { + int n = 0; + Node p = parent; + while (p != null) { + if ((p instanceof Node.CustomTag) + && qName.equals(((Node.CustomTag) p).qName)) { + n++; + } + p = p.parent; + } + return n; + } + + /** + * Returns true if this custom action has an empty body, and false + * otherwise. + * + * A custom action is considered to have an empty body if the following + * holds true: - getBody() returns null, or - all immediate children are + * jsp:attribute actions, or - the action's jsp:body is empty. + */ + public boolean hasEmptyBody() { + boolean hasEmptyBody = true; + Nodes nodes = getBody(); + if (nodes != null) { + int numChildNodes = nodes.size(); + for (int i = 0; i < numChildNodes; i++) { + Node n = nodes.getNode(i); + if (!(n instanceof NamedAttribute)) { + if (n instanceof JspBody) { + hasEmptyBody = (n.getBody() == null); + } else { + hasEmptyBody = false; + } + break; + } + } + } + + return hasEmptyBody; + } + } + + /** + * Used as a placeholder for the evaluation code of a custom action + * attribute (used by the tag plugin machinery only). + */ + public static class AttributeGenerator extends Node { + String name; // name of the attribute + + CustomTag tag; // The tag this attribute belongs to + + public AttributeGenerator(Mark start, String name, CustomTag tag) { + super(start, null); + this.name = name; + this.tag = tag; + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public String getName() { + return name; + } + + public CustomTag getTag() { + return tag; + } + } + + /** + * Represents the body of a <jsp:text> element + */ + public static class JspText extends Node { + + public JspText(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, TEXT_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + } + + /** + * Represents a Named Attribute (<jsp:attribute>) + */ + public static class NamedAttribute extends Node { + + // A unique temporary variable name suitable for code generation + private String temporaryVariableName; + + // True if this node is to be trimmed, or false otherwise + private boolean trim = true; + + private ChildInfo childInfo; + + private String name; + + private String localName; + + private String prefix; + + public NamedAttribute(Attributes attrs, Mark start, Node parent) { + this(JSP_ATTRIBUTE_ACTION, attrs, null, null, start, parent); + } + + public NamedAttribute(String qName, Attributes attrs, + Attributes nonTaglibXmlnsAttrs, Attributes taglibAttrs, + Mark start, Node parent) { + + super(qName, ATTRIBUTE_ACTION, attrs, nonTaglibXmlnsAttrs, + taglibAttrs, start, parent); + temporaryVariableName = JspUtil.nextTemporaryVariableName(); + if ("false".equals(this.getAttributeValue("trim"))) { + // (if null or true, leave default of true) + trim = false; + } + childInfo = new ChildInfo(); + name = this.getAttributeValue("name"); + if (name != null) { + // Mandatary attribute "name" will be checked in Validator + localName = name; + int index = name.indexOf(':'); + if (index != -1) { + prefix = name.substring(0, index); + localName = name.substring(index + 1); + } + } + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public String getName() { + return this.name; + } + + public String getLocalName() { + return this.localName; + } + + public String getPrefix() { + return this.prefix; + } + + public ChildInfo getChildInfo() { + return this.childInfo; + } + + public boolean isTrim() { + return trim; + } + + /** + * @return A unique temporary variable name to store the result in. + * (this probably could go elsewhere, but it's convenient here) + */ + public String getTemporaryVariableName() { + return temporaryVariableName; + } + + /* + * Get the attribute value from this named attribute (). + * Since this method is only for attributes that are not rtexpr, we can + * assume the body of the jsp:attribute is a template text. + */ + public String getText() { + + class AttributeVisitor extends Visitor { + String attrValue = null; + + public void visit(TemplateText txt) { + attrValue = new String(txt.getText()); + } + + public String getAttrValue() { + return attrValue; + } + } + + // According to JSP 2.0, if the body of the + // action is empty, it is equivalent of specifying "" as the value + // of the attribute. + String text = ""; + if (getBody() != null) { + AttributeVisitor attributeVisitor = new AttributeVisitor(); + try { + getBody().visit(attributeVisitor); + } catch (JasperException e) { + } + text = attributeVisitor.getAttrValue(); + } + + return text; + } + } + + /** + * Represents a JspBody node (<jsp:body>) + */ + public static class JspBody extends Node { + + private ChildInfo childInfo; + + public JspBody(Mark start, Node parent) { + this(JSP_BODY_ACTION, null, null, start, parent); + } + + public JspBody(String qName, Attributes nonTaglibXmlnsAttrs, + Attributes taglibAttrs, Mark start, Node parent) { + super(qName, BODY_ACTION, null, nonTaglibXmlnsAttrs, taglibAttrs, + start, parent); + this.childInfo = new ChildInfo(); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + public ChildInfo getChildInfo() { + return childInfo; + } + } + + /** + * Represents a template text string + */ + public static class TemplateText extends Node { + + private ArrayList extraSmap = null; + + public TemplateText(String text, Mark start, Node parent) { + super(null, null, text, start, parent); + } + + public void accept(Visitor v) throws JasperException { + v.visit(this); + } + + /** + * Trim all whitespace from the left of the template text + */ + public void ltrim() { + int index = 0; + while ((index < text.length()) && (text.charAt(index) <= ' ')) { + index++; + } + text = text.substring(index); + } + + public void setText(String text) { + this.text = text; + } + + /** + * Trim all whitespace from the right of the template text + */ + public void rtrim() { + int index = text.length(); + while ((index > 0) && (text.charAt(index - 1) <= ' ')) { + index--; + } + text = text.substring(0, index); + } + + /** + * Returns true if this template text contains whitespace only. + */ + public boolean isAllSpace() { + boolean isAllSpace = true; + for (int i = 0; i < text.length(); i++) { + if (!Character.isWhitespace(text.charAt(i))) { + isAllSpace = false; + break; + } + } + return isAllSpace; + } + + /** + * Add a source to Java line mapping + * + * @param srcLine + * The postion of the source line, relative to the line at + * the start of this node. The corresponding java line is + * assumed to be consecutive, i.e. one more than the last. + */ + public void addSmap(int srcLine) { + if (extraSmap == null) { + extraSmap = new ArrayList(); + } + extraSmap.add(new Integer(srcLine)); + } + + public ArrayList getExtraSmap() { + return extraSmap; + } + } + + /*************************************************************************** + * Auxillary classes used in Node + */ + + /** + * Represents attributes that can be request time expressions. + * + * Can either be a plain attribute, an attribute that represents a request + * time expression value, or a named attribute (specified using the + * jsp:attribute standard action). + */ + + public static class JspAttribute { + + private String qName; + + private String uri; + + private String localName; + + private String value; + + private boolean expression; + + private boolean dynamic; + + private final ELNode.Nodes el; + + private final TagAttributeInfo tai; + + // If true, this JspAttribute represents a + private boolean namedAttribute; + + // The node in the parse tree for the NamedAttribute + private NamedAttribute namedAttributeNode; + + JspAttribute(TagAttributeInfo tai, String qName, String uri, + String localName, String value, boolean expr, ELNode.Nodes el, + boolean dyn) { + this.qName = qName; + this.uri = uri; + this.localName = localName; + this.value = value; + this.namedAttributeNode = null; + this.expression = expr; + this.el = el; + this.dynamic = dyn; + this.namedAttribute = false; + this.tai = tai; + } + + /** + * Allow node to validate itself + * + * @param ef + * @param ctx + * @throws ELException + */ + public void validateEL(ExpressionFactory ef, ELContext ctx) + throws ELException { + if (this.el != null) { + // determine exact type + ValueExpression ve = ef.createValueExpression(ctx, this.value, + String.class); + } + } + + /** + * Use this constructor if the JspAttribute represents a named + * attribute. In this case, we have to store the nodes of the body of + * the attribute. + */ + JspAttribute(NamedAttribute na, TagAttributeInfo tai, boolean dyn) { + this.qName = na.getName(); + this.localName = na.getLocalName(); + this.value = null; + this.namedAttributeNode = na; + this.expression = false; + this.el = null; + this.dynamic = dyn; + this.namedAttribute = true; + this.tai = null; + } + + /** + * @return The name of the attribute + */ + public String getName() { + return qName; + } + + /** + * @return The local name of the attribute + */ + public String getLocalName() { + return localName; + } + + /** + * @return The namespace of the attribute, or null if in the default + * namespace + */ + public String getURI() { + return uri; + } + + public TagAttributeInfo getTagAttributeInfo() { + return this.tai; + } + + /** + * + * @return return true if there's TagAttributeInfo meaning we need to + * assign a ValueExpression + */ + public boolean isDeferredInput() { + return (this.tai != null) ? this.tai.isDeferredValue() : false; + } + + /** + * + * @return return true if there's TagAttributeInfo meaning we need to + * assign a MethodExpression + */ + public boolean isDeferredMethodInput() { + return (this.tai != null) ? this.tai.isDeferredMethod() : false; + } + + public String getExpectedTypeName() { + if (this.tai != null) { + if (this.isDeferredInput()) { + return this.tai.getExpectedTypeName(); + } else if (this.isDeferredMethodInput()) { + String m = this.tai.getMethodSignature(); + if (m != null) { + int rti = m.trim().indexOf(' '); + if (rti > 0) { + return m.substring(0, rti).trim(); + } + } + } + } + return "java.lang.Object"; + } + + public String[] getParameterTypeNames() { + if (this.tai != null) { + if (this.isDeferredMethodInput()) { + String m = this.tai.getMethodSignature(); + if (m != null) { + m = m.trim(); + m = m.substring(m.indexOf('(') + 1); + m = m.substring(0, m.length() - 1); + if (m.trim().length() > 0) { + String[] p = m.split(","); + for (int i = 0; i < p.length; i++) { + p[i] = p[i].trim(); + } + return p; + } + } + } + } + return new String[0]; + } + + /** + * Only makes sense if namedAttribute is false. + * + * @return the value for the attribute, or the expression string + * (stripped of "<%=", "%>", "%=", or "%" but containing "${" + * and "}" for EL expressions) + */ + public String getValue() { + return value; + } + + /** + * Only makes sense if namedAttribute is true. + * + * @return the nodes that evaluate to the body of this attribute. + */ + public NamedAttribute getNamedAttributeNode() { + return namedAttributeNode; + } + + /** + * @return true if the value represents a traditional rtexprvalue + */ + public boolean isExpression() { + return expression; + } + + /** + * @return true if the value represents a NamedAttribute value. + */ + public boolean isNamedAttribute() { + return namedAttribute; + } + + /** + * @return true if the value represents an expression that should be fed + * to the expression interpreter + * @return false for string literals or rtexprvalues that should not be + * interpreted or reevaluated + */ + public boolean isELInterpreterInput() { + return el != null || this.isDeferredInput() + || this.isDeferredMethodInput(); + } + + /** + * @return true if the value is a string literal known at translation + * time. + */ + public boolean isLiteral() { + return !expression && (el != null) && !namedAttribute; + } + + /** + * XXX + */ + public boolean isDynamic() { + return dynamic; + } + + public ELNode.Nodes getEL() { + return el; + } + } + + /** + * An ordered list of Node, used to represent the body of an element, or a + * jsp page of jsp document. + */ + public static class Nodes { + + private List list; + + private Node.Root root; // null if this is not a page + + private boolean generatedInBuffer; + + public Nodes() { + list = new Vector(); + } + + public Nodes(Node.Root root) { + this.root = root; + list = new Vector(); + list.add(root); + } + + /** + * Appends a node to the list + * + * @param n + * The node to add + */ + public void add(Node n) { + list.add(n); + root = null; + } + + /** + * Removes the given node from the list. + * + * @param n + * The node to be removed + */ + public void remove(Node n) { + list.remove(n); + } + + /** + * Visit the nodes in the list with the supplied visitor + * + * @param v + * The visitor used + */ + public void visit(Visitor v) throws JasperException { + Iterator iter = list.iterator(); + while (iter.hasNext()) { + Node n = (Node) iter.next(); + n.accept(v); + } + } + + public int size() { + return list.size(); + } + + public Node getNode(int index) { + Node n = null; + try { + n = (Node) list.get(index); + } catch (ArrayIndexOutOfBoundsException e) { + } + return n; + } + + public Node.Root getRoot() { + return root; + } + + public boolean isGeneratedInBuffer() { + return generatedInBuffer; + } + + public void setGeneratedInBuffer(boolean g) { + generatedInBuffer = g; + } + } + + /** + * A visitor class for visiting the node. This class also provides the + * default action (i.e. nop) for each of the child class of the Node. An + * actual visitor should extend this class and supply the visit method for + * the nodes that it cares. + */ + public static class Visitor { + + /** + * This method provides a place to put actions that are common to all + * nodes. Override this in the child visitor class if need to. + */ + protected void doVisit(Node n) throws JasperException { + } + + /** + * Visit the body of a node, using the current visitor + */ + protected void visitBody(Node n) throws JasperException { + if (n.getBody() != null) { + n.getBody().visit(this); + } + } + + public void visit(Root n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(JspRoot n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(PageDirective n) throws JasperException { + doVisit(n); + } + + public void visit(TagDirective n) throws JasperException { + doVisit(n); + } + + public void visit(IncludeDirective n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(TaglibDirective n) throws JasperException { + doVisit(n); + } + + public void visit(AttributeDirective n) throws JasperException { + doVisit(n); + } + + public void visit(VariableDirective n) throws JasperException { + doVisit(n); + } + + public void visit(Comment n) throws JasperException { + doVisit(n); + } + + public void visit(Declaration n) throws JasperException { + doVisit(n); + } + + public void visit(Expression n) throws JasperException { + doVisit(n); + } + + public void visit(Scriptlet n) throws JasperException { + doVisit(n); + } + + public void visit(ELExpression n) throws JasperException { + doVisit(n); + } + + public void visit(IncludeAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(ForwardAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(GetProperty n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(SetProperty n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(ParamAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(ParamsAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(FallBackAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(UseBean n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(PlugIn n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(CustomTag n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(UninterpretedTag n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(JspElement n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(JspText n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(NamedAttribute n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(JspBody n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(InvokeAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(DoBodyAction n) throws JasperException { + doVisit(n); + visitBody(n); + } + + public void visit(TemplateText n) throws JasperException { + doVisit(n); + } + + public void visit(JspOutput n) throws JasperException { + doVisit(n); + } + + public void visit(AttributeGenerator n) throws JasperException { + doVisit(n); + } + } +} diff --git a/java/org/apache/jasper/compiler/PageDataImpl.java b/java/org/apache/jasper/compiler/PageDataImpl.java index 6b314d874..af51b0312 100644 --- a/java/org/apache/jasper/compiler/PageDataImpl.java +++ b/java/org/apache/jasper/compiler/PageDataImpl.java @@ -1,710 +1,710 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.io.CharArrayWriter; -import java.io.UnsupportedEncodingException; -import java.util.ListIterator; -import javax.servlet.jsp.tagext.PageData; -import org.xml.sax.Attributes; -import org.xml.sax.helpers.AttributesImpl; -import org.apache.jasper.JasperException; - -/** - * An implementation of javax.servlet.jsp.tagext.PageData which - * builds the XML view of a given page. - * - * The XML view is built in two passes: - * - * During the first pass, the FirstPassVisitor collects the attributes of the - * top-level jsp:root and those of the jsp:root elements of any included - * pages, and adds them to the jsp:root element of the XML view. - * In addition, any taglib directives are converted into xmlns: attributes and - * added to the jsp:root element of the XML view. - * This pass ignores any nodes other than JspRoot and TaglibDirective. - * - * During the second pass, the SecondPassVisitor produces the XML view, using - * the combined jsp:root attributes determined in the first pass and any - * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective - * nodes). - * - * @author Jan Luehe - */ -class PageDataImpl extends PageData implements TagConstants { - - private static final String JSP_VERSION = "2.0"; - private static final String CDATA_START_SECTION = "\n"; - - // string buffer used to build XML view - private StringBuffer buf; - - /** - * Constructor. - * - * @param page the page nodes from which to generate the XML view - */ - public PageDataImpl(Node.Nodes page, Compiler compiler) - throws JasperException { - - // First pass - FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(), - compiler.getPageInfo()); - page.visit(firstPass); - - // Second pass - buf = new StringBuffer(); - SecondPassVisitor secondPass - = new SecondPassVisitor(page.getRoot(), buf, compiler, - firstPass.getJspIdPrefix()); - page.visit(secondPass); - } - - /** - * Returns the input stream of the XML view. - * - * @return the input stream of the XML view - */ - public InputStream getInputStream() { - // Turn StringBuffer into InputStream - try { - return new ByteArrayInputStream(buf.toString().getBytes("UTF-8")); - } catch (UnsupportedEncodingException uee) { - // should never happen - throw new RuntimeException(uee.toString()); - } - } - - /* - * First-pass Visitor for JspRoot nodes (representing jsp:root elements) - * and TablibDirective nodes, ignoring any other nodes. - * - * The purpose of this Visitor is to collect the attributes of the - * top-level jsp:root and those of the jsp:root elements of any included - * pages, and add them to the jsp:root element of the XML view. - * In addition, this Visitor converts any taglib directives into xmlns: - * attributes and adds them to the jsp:root element of the XML view. - */ - static class FirstPassVisitor - extends Node.Visitor implements TagConstants { - - private Node.Root root; - private AttributesImpl rootAttrs; - private PageInfo pageInfo; - - // Prefix for the 'id' attribute - private String jspIdPrefix; - - /* - * Constructor - */ - public FirstPassVisitor(Node.Root root, PageInfo pageInfo) { - this.root = root; - this.pageInfo = pageInfo; - this.rootAttrs = new AttributesImpl(); - this.rootAttrs.addAttribute("", "", "version", "CDATA", - JSP_VERSION); - this.jspIdPrefix = "jsp"; - } - - public void visit(Node.Root n) throws JasperException { - visitBody(n); - if (n == root) { - /* - * Top-level page. - * - * Add - * xmlns:jsp="http://java.sun.com/JSP/Page" - * attribute only if not already present. - */ - if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) { - rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA", - JSP_URI); - } - - if (pageInfo.isJspPrefixHijacked()) { - /* - * 'jsp' prefix has been hijacked, that is, bound to a - * namespace other than the JSP namespace. This means that - * when adding an 'id' attribute to each element, we can't - * use the 'jsp' prefix. Therefore, create a new prefix - * (one that is unique across the translation unit) for use - * by the 'id' attribute, and bind it to the JSP namespace - */ - jspIdPrefix += "jsp"; - while (pageInfo.containsPrefix(jspIdPrefix)) { - jspIdPrefix += "jsp"; - } - rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix, - "CDATA", JSP_URI); - } - - root.setAttributes(rootAttrs); - } - } - - public void visit(Node.JspRoot n) throws JasperException { - addAttributes(n.getTaglibAttributes()); - addAttributes(n.getNonTaglibXmlnsAttributes()); - addAttributes(n.getAttributes()); - - visitBody(n); - } - - /* - * Converts taglib directive into "xmlns:..." attribute of jsp:root - * element. - */ - public void visit(Node.TaglibDirective n) throws JasperException { - Attributes attrs = n.getAttributes(); - if (attrs != null) { - String qName = "xmlns:" + attrs.getValue("prefix"); - /* - * According to javadocs of org.xml.sax.helpers.AttributesImpl, - * the addAttribute method does not check to see if the - * specified attribute is already contained in the list: This - * is the application's responsibility! - */ - if (rootAttrs.getIndex(qName) == -1) { - String location = attrs.getValue("uri"); - if (location != null) { - if (location.startsWith("/")) { - location = URN_JSPTLD + location; - } - rootAttrs.addAttribute("", "", qName, "CDATA", - location); - } else { - location = attrs.getValue("tagdir"); - rootAttrs.addAttribute("", "", qName, "CDATA", - URN_JSPTAGDIR + location); - } - } - } - } - - public String getJspIdPrefix() { - return jspIdPrefix; - } - - private void addAttributes(Attributes attrs) { - if (attrs != null) { - int len = attrs.getLength(); - - for (int i=0; i"); - } - buf.append("${"); - buf.append(JspUtil.escapeXml(n.getText())); - buf.append("}"); - if (!n.getRoot().isXmlSyntax()) { - buf.append(JSP_TEXT_ACTION_END); - } - buf.append("\n"); - } - - public void visit(Node.IncludeAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.ForwardAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.GetProperty n) throws JasperException { - appendTag(n); - } - - public void visit(Node.SetProperty n) throws JasperException { - appendTag(n); - } - - public void visit(Node.ParamAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.ParamsAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.FallBackAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.UseBean n) throws JasperException { - appendTag(n); - } - - public void visit(Node.PlugIn n) throws JasperException { - appendTag(n); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - appendTag(n); - } - - public void visit(Node.JspBody n) throws JasperException { - appendTag(n); - } - - public void visit(Node.CustomTag n) throws JasperException { - boolean resetDefaultNSSave = resetDefaultNS; - appendTag(n, resetDefaultNS); - resetDefaultNS = resetDefaultNSSave; - } - - public void visit(Node.UninterpretedTag n) throws JasperException { - boolean resetDefaultNSSave = resetDefaultNS; - appendTag(n, resetDefaultNS); - resetDefaultNS = resetDefaultNSSave; - } - - public void visit(Node.JspText n) throws JasperException { - appendTag(n); - } - - public void visit(Node.DoBodyAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.InvokeAction n) throws JasperException { - appendTag(n); - } - - public void visit(Node.TagDirective n) throws JasperException { - appendTagDirective(n); - } - - public void visit(Node.AttributeDirective n) throws JasperException { - appendTag(n); - } - - public void visit(Node.VariableDirective n) throws JasperException { - appendTag(n); - } - - public void visit(Node.TemplateText n) throws JasperException { - /* - * If the template text came from a JSP page written in JSP syntax, - * create a jsp:text element for it (JSP 5.3.2). - */ - appendText(n.getText(), !n.getRoot().isXmlSyntax()); - } - - /* - * Appends the given tag, including its body, to the XML view. - */ - private void appendTag(Node n) throws JasperException { - appendTag(n, false); - } - - /* - * Appends the given tag, including its body, to the XML view, - * and optionally reset default namespace to "", if none specified. - */ - private void appendTag(Node n, boolean addDefaultNS) - throws JasperException { - - Node.Nodes body = n.getBody(); - String text = n.getText(); - - buf.append("<").append(n.getQName()); - buf.append("\n"); - - printAttributes(n, addDefaultNS); - buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); - buf.append(jspId++).append("\"\n"); - - if (ROOT_ACTION.equals(n.getLocalName()) || body != null - || text != null) { - buf.append(">\n"); - if (ROOT_ACTION.equals(n.getLocalName())) { - if (compiler.getCompilationContext().isTagFile()) { - appendTagDirective(); - } else { - appendPageDirective(); - } - } - if (body != null) { - body.visit(this); - } else { - appendText(text, false); - } - buf.append("\n"); - } else { - buf.append("/>\n"); - } - } - - /* - * Appends the page directive with the given attributes to the XML - * view. - * - * Since the import attribute of the page directive is the only page - * attribute that is allowed to appear multiple times within the same - * document, and since XML allows only single-value attributes, - * the values of multiple import attributes must be combined into one, - * separated by comma. - * - * If the given page directive contains just 'contentType' and/or - * 'pageEncoding' attributes, we ignore it, as we've already appended - * a page directive containing just these two attributes. - */ - private void appendPageDirective(Node.PageDirective n) { - boolean append = false; - Attributes attrs = n.getAttributes(); - int len = (attrs == null) ? 0 : attrs.getLength(); - for (int i=0; i 0) { - // Concatenate names of imported classes/packages - boolean first = true; - ListIterator iter = n.getImports().listIterator(); - while (iter.hasNext()) { - if (first) { - first = false; - buf.append(" import=\""); - } else { - buf.append(","); - } - buf.append(JspUtil.getExprInXml((String) iter.next())); - } - buf.append("\"\n"); - } - buf.append("/>\n"); - } - - /* - * Appends a page directive with 'pageEncoding' and 'contentType' - * attributes. - * - * The value of the 'pageEncoding' attribute is hard-coded - * to UTF-8, whereas the value of the 'contentType' attribute, which - * is identical to what the container will pass to - * ServletResponse.setContentType(), is derived from the pageInfo. - */ - private void appendPageDirective() { - buf.append("<").append(JSP_PAGE_DIRECTIVE_ACTION); - buf.append("\n"); - - // append jsp:id - buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); - buf.append(jspId++).append("\"\n"); - buf.append(" ").append("pageEncoding").append("=\"UTF-8\"\n"); - buf.append(" ").append("contentType").append("=\""); - buf.append(compiler.getPageInfo().getContentType()).append("\"\n"); - buf.append("/>\n"); - } - - /* - * Appends the tag directive with the given attributes to the XML - * view. - * - * If the given tag directive contains just a 'pageEncoding' - * attributes, we ignore it, as we've already appended - * a tag directive containing just this attributes. - */ - private void appendTagDirective(Node.TagDirective n) - throws JasperException { - - boolean append = false; - Attributes attrs = n.getAttributes(); - int len = (attrs == null) ? 0 : attrs.getLength(); - for (int i=0; i\n"); - } - - private void appendText(String text, boolean createJspTextElement) { - if (createJspTextElement) { - buf.append("<").append(JSP_TEXT_ACTION); - buf.append("\n"); - - // append jsp:id - buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); - buf.append(jspId++).append("\"\n"); - buf.append(">\n"); - - appendCDATA(text); - buf.append(JSP_TEXT_ACTION_END); - buf.append("\n"); - } else { - appendCDATA(text); - } - } - - /* - * Appends the given text as a CDATA section to the XML view, unless - * the text has already been marked as CDATA. - */ - private void appendCDATA(String text) { - buf.append(CDATA_START_SECTION); - buf.append(escapeCDATA(text)); - buf.append(CDATA_END_SECTION); - } - - /* - * Escapes any occurrences of "]]>" (by replacing them with "]]>") - * within the given text, so it can be included in a CDATA section. - */ - private String escapeCDATA(String text) { - if( text==null ) return ""; - int len = text.length(); - CharArrayWriter result = new CharArrayWriter(len); - for (int i=0; i')) { - // match found - result.write(']'); - result.write(']'); - result.write('&'); - result.write('g'); - result.write('t'); - result.write(';'); - i += 2; - } else { - result.write(text.charAt(i)); - } - } - return result.toString(); - } - - /* - * Appends the attributes of the given Node to the XML view. - */ - private void printAttributes(Node n, boolean addDefaultNS) { - - /* - * Append "xmlns" attributes that represent tag libraries - */ - Attributes attrs = n.getTaglibAttributes(); - int len = (attrs == null) ? 0 : attrs.getLength(); - for (int i=0; i\n"); - } - } -} - +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.CharArrayWriter; +import java.io.UnsupportedEncodingException; +import java.util.ListIterator; +import javax.servlet.jsp.tagext.PageData; +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; +import org.apache.jasper.JasperException; + +/** + * An implementation of javax.servlet.jsp.tagext.PageData which + * builds the XML view of a given page. + * + * The XML view is built in two passes: + * + * During the first pass, the FirstPassVisitor collects the attributes of the + * top-level jsp:root and those of the jsp:root elements of any included + * pages, and adds them to the jsp:root element of the XML view. + * In addition, any taglib directives are converted into xmlns: attributes and + * added to the jsp:root element of the XML view. + * This pass ignores any nodes other than JspRoot and TaglibDirective. + * + * During the second pass, the SecondPassVisitor produces the XML view, using + * the combined jsp:root attributes determined in the first pass and any + * remaining pages nodes (this pass ignores any JspRoot and TaglibDirective + * nodes). + * + * @author Jan Luehe + */ +class PageDataImpl extends PageData implements TagConstants { + + private static final String JSP_VERSION = "2.0"; + private static final String CDATA_START_SECTION = "\n"; + + // string buffer used to build XML view + private StringBuffer buf; + + /** + * Constructor. + * + * @param page the page nodes from which to generate the XML view + */ + public PageDataImpl(Node.Nodes page, Compiler compiler) + throws JasperException { + + // First pass + FirstPassVisitor firstPass = new FirstPassVisitor(page.getRoot(), + compiler.getPageInfo()); + page.visit(firstPass); + + // Second pass + buf = new StringBuffer(); + SecondPassVisitor secondPass + = new SecondPassVisitor(page.getRoot(), buf, compiler, + firstPass.getJspIdPrefix()); + page.visit(secondPass); + } + + /** + * Returns the input stream of the XML view. + * + * @return the input stream of the XML view + */ + public InputStream getInputStream() { + // Turn StringBuffer into InputStream + try { + return new ByteArrayInputStream(buf.toString().getBytes("UTF-8")); + } catch (UnsupportedEncodingException uee) { + // should never happen + throw new RuntimeException(uee.toString()); + } + } + + /* + * First-pass Visitor for JspRoot nodes (representing jsp:root elements) + * and TablibDirective nodes, ignoring any other nodes. + * + * The purpose of this Visitor is to collect the attributes of the + * top-level jsp:root and those of the jsp:root elements of any included + * pages, and add them to the jsp:root element of the XML view. + * In addition, this Visitor converts any taglib directives into xmlns: + * attributes and adds them to the jsp:root element of the XML view. + */ + static class FirstPassVisitor + extends Node.Visitor implements TagConstants { + + private Node.Root root; + private AttributesImpl rootAttrs; + private PageInfo pageInfo; + + // Prefix for the 'id' attribute + private String jspIdPrefix; + + /* + * Constructor + */ + public FirstPassVisitor(Node.Root root, PageInfo pageInfo) { + this.root = root; + this.pageInfo = pageInfo; + this.rootAttrs = new AttributesImpl(); + this.rootAttrs.addAttribute("", "", "version", "CDATA", + JSP_VERSION); + this.jspIdPrefix = "jsp"; + } + + public void visit(Node.Root n) throws JasperException { + visitBody(n); + if (n == root) { + /* + * Top-level page. + * + * Add + * xmlns:jsp="http://java.sun.com/JSP/Page" + * attribute only if not already present. + */ + if (!JSP_URI.equals(rootAttrs.getValue("xmlns:jsp"))) { + rootAttrs.addAttribute("", "", "xmlns:jsp", "CDATA", + JSP_URI); + } + + if (pageInfo.isJspPrefixHijacked()) { + /* + * 'jsp' prefix has been hijacked, that is, bound to a + * namespace other than the JSP namespace. This means that + * when adding an 'id' attribute to each element, we can't + * use the 'jsp' prefix. Therefore, create a new prefix + * (one that is unique across the translation unit) for use + * by the 'id' attribute, and bind it to the JSP namespace + */ + jspIdPrefix += "jsp"; + while (pageInfo.containsPrefix(jspIdPrefix)) { + jspIdPrefix += "jsp"; + } + rootAttrs.addAttribute("", "", "xmlns:" + jspIdPrefix, + "CDATA", JSP_URI); + } + + root.setAttributes(rootAttrs); + } + } + + public void visit(Node.JspRoot n) throws JasperException { + addAttributes(n.getTaglibAttributes()); + addAttributes(n.getNonTaglibXmlnsAttributes()); + addAttributes(n.getAttributes()); + + visitBody(n); + } + + /* + * Converts taglib directive into "xmlns:..." attribute of jsp:root + * element. + */ + public void visit(Node.TaglibDirective n) throws JasperException { + Attributes attrs = n.getAttributes(); + if (attrs != null) { + String qName = "xmlns:" + attrs.getValue("prefix"); + /* + * According to javadocs of org.xml.sax.helpers.AttributesImpl, + * the addAttribute method does not check to see if the + * specified attribute is already contained in the list: This + * is the application's responsibility! + */ + if (rootAttrs.getIndex(qName) == -1) { + String location = attrs.getValue("uri"); + if (location != null) { + if (location.startsWith("/")) { + location = URN_JSPTLD + location; + } + rootAttrs.addAttribute("", "", qName, "CDATA", + location); + } else { + location = attrs.getValue("tagdir"); + rootAttrs.addAttribute("", "", qName, "CDATA", + URN_JSPTAGDIR + location); + } + } + } + } + + public String getJspIdPrefix() { + return jspIdPrefix; + } + + private void addAttributes(Attributes attrs) { + if (attrs != null) { + int len = attrs.getLength(); + + for (int i=0; i"); + } + buf.append("${"); + buf.append(JspUtil.escapeXml(n.getText())); + buf.append("}"); + if (!n.getRoot().isXmlSyntax()) { + buf.append(JSP_TEXT_ACTION_END); + } + buf.append("\n"); + } + + public void visit(Node.IncludeAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.ForwardAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.GetProperty n) throws JasperException { + appendTag(n); + } + + public void visit(Node.SetProperty n) throws JasperException { + appendTag(n); + } + + public void visit(Node.ParamAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.ParamsAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.FallBackAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.UseBean n) throws JasperException { + appendTag(n); + } + + public void visit(Node.PlugIn n) throws JasperException { + appendTag(n); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + appendTag(n); + } + + public void visit(Node.JspBody n) throws JasperException { + appendTag(n); + } + + public void visit(Node.CustomTag n) throws JasperException { + boolean resetDefaultNSSave = resetDefaultNS; + appendTag(n, resetDefaultNS); + resetDefaultNS = resetDefaultNSSave; + } + + public void visit(Node.UninterpretedTag n) throws JasperException { + boolean resetDefaultNSSave = resetDefaultNS; + appendTag(n, resetDefaultNS); + resetDefaultNS = resetDefaultNSSave; + } + + public void visit(Node.JspText n) throws JasperException { + appendTag(n); + } + + public void visit(Node.DoBodyAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.InvokeAction n) throws JasperException { + appendTag(n); + } + + public void visit(Node.TagDirective n) throws JasperException { + appendTagDirective(n); + } + + public void visit(Node.AttributeDirective n) throws JasperException { + appendTag(n); + } + + public void visit(Node.VariableDirective n) throws JasperException { + appendTag(n); + } + + public void visit(Node.TemplateText n) throws JasperException { + /* + * If the template text came from a JSP page written in JSP syntax, + * create a jsp:text element for it (JSP 5.3.2). + */ + appendText(n.getText(), !n.getRoot().isXmlSyntax()); + } + + /* + * Appends the given tag, including its body, to the XML view. + */ + private void appendTag(Node n) throws JasperException { + appendTag(n, false); + } + + /* + * Appends the given tag, including its body, to the XML view, + * and optionally reset default namespace to "", if none specified. + */ + private void appendTag(Node n, boolean addDefaultNS) + throws JasperException { + + Node.Nodes body = n.getBody(); + String text = n.getText(); + + buf.append("<").append(n.getQName()); + buf.append("\n"); + + printAttributes(n, addDefaultNS); + buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); + buf.append(jspId++).append("\"\n"); + + if (ROOT_ACTION.equals(n.getLocalName()) || body != null + || text != null) { + buf.append(">\n"); + if (ROOT_ACTION.equals(n.getLocalName())) { + if (compiler.getCompilationContext().isTagFile()) { + appendTagDirective(); + } else { + appendPageDirective(); + } + } + if (body != null) { + body.visit(this); + } else { + appendText(text, false); + } + buf.append("\n"); + } else { + buf.append("/>\n"); + } + } + + /* + * Appends the page directive with the given attributes to the XML + * view. + * + * Since the import attribute of the page directive is the only page + * attribute that is allowed to appear multiple times within the same + * document, and since XML allows only single-value attributes, + * the values of multiple import attributes must be combined into one, + * separated by comma. + * + * If the given page directive contains just 'contentType' and/or + * 'pageEncoding' attributes, we ignore it, as we've already appended + * a page directive containing just these two attributes. + */ + private void appendPageDirective(Node.PageDirective n) { + boolean append = false; + Attributes attrs = n.getAttributes(); + int len = (attrs == null) ? 0 : attrs.getLength(); + for (int i=0; i 0) { + // Concatenate names of imported classes/packages + boolean first = true; + ListIterator iter = n.getImports().listIterator(); + while (iter.hasNext()) { + if (first) { + first = false; + buf.append(" import=\""); + } else { + buf.append(","); + } + buf.append(JspUtil.getExprInXml((String) iter.next())); + } + buf.append("\"\n"); + } + buf.append("/>\n"); + } + + /* + * Appends a page directive with 'pageEncoding' and 'contentType' + * attributes. + * + * The value of the 'pageEncoding' attribute is hard-coded + * to UTF-8, whereas the value of the 'contentType' attribute, which + * is identical to what the container will pass to + * ServletResponse.setContentType(), is derived from the pageInfo. + */ + private void appendPageDirective() { + buf.append("<").append(JSP_PAGE_DIRECTIVE_ACTION); + buf.append("\n"); + + // append jsp:id + buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); + buf.append(jspId++).append("\"\n"); + buf.append(" ").append("pageEncoding").append("=\"UTF-8\"\n"); + buf.append(" ").append("contentType").append("=\""); + buf.append(compiler.getPageInfo().getContentType()).append("\"\n"); + buf.append("/>\n"); + } + + /* + * Appends the tag directive with the given attributes to the XML + * view. + * + * If the given tag directive contains just a 'pageEncoding' + * attributes, we ignore it, as we've already appended + * a tag directive containing just this attributes. + */ + private void appendTagDirective(Node.TagDirective n) + throws JasperException { + + boolean append = false; + Attributes attrs = n.getAttributes(); + int len = (attrs == null) ? 0 : attrs.getLength(); + for (int i=0; i\n"); + } + + private void appendText(String text, boolean createJspTextElement) { + if (createJspTextElement) { + buf.append("<").append(JSP_TEXT_ACTION); + buf.append("\n"); + + // append jsp:id + buf.append(" ").append(jspIdPrefix).append(":id").append("=\""); + buf.append(jspId++).append("\"\n"); + buf.append(">\n"); + + appendCDATA(text); + buf.append(JSP_TEXT_ACTION_END); + buf.append("\n"); + } else { + appendCDATA(text); + } + } + + /* + * Appends the given text as a CDATA section to the XML view, unless + * the text has already been marked as CDATA. + */ + private void appendCDATA(String text) { + buf.append(CDATA_START_SECTION); + buf.append(escapeCDATA(text)); + buf.append(CDATA_END_SECTION); + } + + /* + * Escapes any occurrences of "]]>" (by replacing them with "]]>") + * within the given text, so it can be included in a CDATA section. + */ + private String escapeCDATA(String text) { + if( text==null ) return ""; + int len = text.length(); + CharArrayWriter result = new CharArrayWriter(len); + for (int i=0; i')) { + // match found + result.write(']'); + result.write(']'); + result.write('&'); + result.write('g'); + result.write('t'); + result.write(';'); + i += 2; + } else { + result.write(text.charAt(i)); + } + } + return result.toString(); + } + + /* + * Appends the attributes of the given Node to the XML view. + */ + private void printAttributes(Node n, boolean addDefaultNS) { + + /* + * Append "xmlns" attributes that represent tag libraries + */ + Attributes attrs = n.getTaglibAttributes(); + int len = (attrs == null) ? 0 : attrs.getLength(); + for (int i=0; i\n"); + } + } +} + diff --git a/java/org/apache/jasper/compiler/PageInfo.java b/java/org/apache/jasper/compiler/PageInfo.java index 3a54e8289..801099eba 100644 --- a/java/org/apache/jasper/compiler/PageInfo.java +++ b/java/org/apache/jasper/compiler/PageInfo.java @@ -1,710 +1,710 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Vector; - -import org.apache.el.ExpressionFactoryImpl; -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; - -import javax.el.ExpressionFactory; -import javax.servlet.jsp.tagext.TagLibraryInfo; - -/** - * A repository for various info about the translation unit under compilation. - * - * @author Kin-man Chung - */ - -class PageInfo { - - private Vector imports; - private Vector dependants; - - private BeanRepository beanRepository; - private HashMap taglibsMap; - private HashMap jspPrefixMapper; - private HashMap xmlPrefixMapper; - private HashMap nonCustomTagPrefixMap; - private String jspFile; - private String defaultLanguage = "java"; - private String language; - private String defaultExtends = Constants.JSP_SERVLET_BASE; - private String xtends; - private String contentType = null; - private String session; - private boolean isSession = true; - private String bufferValue; - private int buffer = 8*1024; // XXX confirm - private String autoFlush; - private boolean isAutoFlush = true; - private String isThreadSafeValue; - private boolean isThreadSafe = true; - private String isErrorPageValue; - private boolean isErrorPage = false; - private String errorPage = null; - private String info; - - private boolean scriptless = false; - private boolean scriptingInvalid = false; - - private String isELIgnoredValue; - private boolean isELIgnored = false; - - // JSP 2.1 - private String deferredSyntaxAllowedAsLiteralValue; - private boolean deferredSyntaxAllowedAsLiteral = false; - private ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); - private String trimDirectiveWhitespacesValue; - private boolean trimDirectiveWhitespaces = false; - - private String omitXmlDecl = null; - private String doctypeName = null; - private String doctypePublic = null; - private String doctypeSystem = null; - - private boolean isJspPrefixHijacked; - - // Set of all element and attribute prefixes used in this translation unit - private HashSet prefixes; - - private boolean hasJspRoot = false; - private Vector includePrelude; - private Vector includeCoda; - private Vector pluginDcls; // Id's for tagplugin declarations - - - PageInfo(BeanRepository beanRepository, String jspFile) { - - this.jspFile = jspFile; - this.beanRepository = beanRepository; - this.taglibsMap = new HashMap(); - this.jspPrefixMapper = new HashMap(); - this.xmlPrefixMapper = new HashMap(); - this.nonCustomTagPrefixMap = new HashMap(); - this.imports = new Vector(); - this.dependants = new Vector(); - this.includePrelude = new Vector(); - this.includeCoda = new Vector(); - this.pluginDcls = new Vector(); - this.prefixes = new HashSet(); - - // Enter standard imports - for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++) - imports.add(Constants.STANDARD_IMPORTS[i]); - } - - /** - * Check if the plugin ID has been previously declared. Make a not - * that this Id is now declared. - * @return true if Id has been declared. - */ - public boolean isPluginDeclared(String id) { - if (pluginDcls.contains(id)) - return true; - pluginDcls.add(id); - return false; - } - - public void addImports(List imports) { - this.imports.addAll(imports); - } - - public void addImport(String imp) { - this.imports.add(imp); - } - - public List getImports() { - return imports; - } - - public String getJspFile() { - return jspFile; - } - - public void addDependant(String d) { - if (!dependants.contains(d) && !jspFile.equals(d)) - dependants.add(d); - } - - public List getDependants() { - return dependants; - } - - public BeanRepository getBeanRepository() { - return beanRepository; - } - - public void setScriptless(boolean s) { - scriptless = s; - } - - public boolean isScriptless() { - return scriptless; - } - - public void setScriptingInvalid(boolean s) { - scriptingInvalid = s; - } - - public boolean isScriptingInvalid() { - return scriptingInvalid; - } - - public List getIncludePrelude() { - return includePrelude; - } - - public void setIncludePrelude(Vector prelude) { - includePrelude = prelude; - } - - public List getIncludeCoda() { - return includeCoda; - } - - public void setIncludeCoda(Vector coda) { - includeCoda = coda; - } - - public void setHasJspRoot(boolean s) { - hasJspRoot = s; - } - - public boolean hasJspRoot() { - return hasJspRoot; - } - - public String getOmitXmlDecl() { - return omitXmlDecl; - } - - public void setOmitXmlDecl(String omit) { - omitXmlDecl = omit; - } - - public String getDoctypeName() { - return doctypeName; - } - - public void setDoctypeName(String doctypeName) { - this.doctypeName = doctypeName; - } - - public String getDoctypeSystem() { - return doctypeSystem; - } - - public void setDoctypeSystem(String doctypeSystem) { - this.doctypeSystem = doctypeSystem; - } - - public String getDoctypePublic() { - return doctypePublic; - } - - public void setDoctypePublic(String doctypePublic) { - this.doctypePublic = doctypePublic; - } - - /* Tag library and XML namespace management methods */ - - public void setIsJspPrefixHijacked(boolean isHijacked) { - isJspPrefixHijacked = isHijacked; - } - - public boolean isJspPrefixHijacked() { - return isJspPrefixHijacked; - } - - /* - * Adds the given prefix to the set of prefixes of this translation unit. - * - * @param prefix The prefix to add - */ - public void addPrefix(String prefix) { - prefixes.add(prefix); - } - - /* - * Checks to see if this translation unit contains the given prefix. - * - * @param prefix The prefix to check - * - * @return true if this translation unit contains the given prefix, false - * otherwise - */ - public boolean containsPrefix(String prefix) { - return prefixes.contains(prefix); - } - - /* - * Maps the given URI to the given tag library. - * - * @param uri The URI to map - * @param info The tag library to be associated with the given URI - */ - public void addTaglib(String uri, TagLibraryInfo info) { - taglibsMap.put(uri, info); - } - - /* - * Gets the tag library corresponding to the given URI. - * - * @return Tag library corresponding to the given URI - */ - public TagLibraryInfo getTaglib(String uri) { - return (TagLibraryInfo) taglibsMap.get(uri); - } - - /* - * Gets the collection of tag libraries that are associated with a URI - * - * @return Collection of tag libraries that are associated with a URI - */ - public Collection getTaglibs() { - return taglibsMap.values(); - } - - /* - * Checks to see if the given URI is mapped to a tag library. - * - * @param uri The URI to map - * - * @return true if the given URI is mapped to a tag library, false - * otherwise - */ - public boolean hasTaglib(String uri) { - return taglibsMap.containsKey(uri); - } - - /* - * Maps the given prefix to the given URI. - * - * @param prefix The prefix to map - * @param uri The URI to be associated with the given prefix - */ - public void addPrefixMapping(String prefix, String uri) { - jspPrefixMapper.put(prefix, uri); - } - - /* - * Pushes the given URI onto the stack of URIs to which the given prefix - * is mapped. - * - * @param prefix The prefix whose stack of URIs is to be pushed - * @param uri The URI to be pushed onto the stack - */ - public void pushPrefixMapping(String prefix, String uri) { - LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); - if (stack == null) { - stack = new LinkedList(); - xmlPrefixMapper.put(prefix, stack); - } - stack.addFirst(uri); - } - - /* - * Removes the URI at the top of the stack of URIs to which the given - * prefix is mapped. - * - * @param prefix The prefix whose stack of URIs is to be popped - */ - public void popPrefixMapping(String prefix) { - LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); - if (stack == null || stack.size() == 0) { - // XXX throw new Exception("XXX"); - } - stack.removeFirst(); - } - - /* - * Returns the URI to which the given prefix maps. - * - * @param prefix The prefix whose URI is sought - * - * @return The URI to which the given prefix maps - */ - public String getURI(String prefix) { - - String uri = null; - - LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); - if (stack == null || stack.size() == 0) { - uri = (String) jspPrefixMapper.get(prefix); - } else { - uri = (String) stack.getFirst(); - } - - return uri; - } - - - /* Page/Tag directive attributes */ - - /* - * language - */ - public void setLanguage(String value, Node n, ErrorDispatcher err, - boolean pagedir) - throws JasperException { - - if (!"java".equalsIgnoreCase(value)) { - if (pagedir) - err.jspError(n, "jsp.error.page.language.nonjava"); - else - err.jspError(n, "jsp.error.tag.language.nonjava"); - } - - language = value; - } - - public String getLanguage(boolean useDefault) { - return (language == null && useDefault ? defaultLanguage : language); - } - - public String getLanguage() { - return getLanguage(true); - } - - - /* - * extends - */ - public void setExtends(String value, Node.PageDirective n) { - - xtends = value; - - /* - * If page superclass is top level class (i.e. not in a package) - * explicitly import it. If this is not done, the compiler will assume - * the extended class is in the same pkg as the generated servlet. - */ - if (value.indexOf('.') < 0) - n.addImport(value); - } - - /** - * Gets the value of the 'extends' page directive attribute. - * - * @param useDefault TRUE if the default - * (org.apache.jasper.runtime.HttpJspBase) should be returned if this - * attribute has not been set, FALSE otherwise - * - * @return The value of the 'extends' page directive attribute, or the - * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has - * not been set and useDefault is TRUE - */ - public String getExtends(boolean useDefault) { - return (xtends == null && useDefault ? defaultExtends : xtends); - } - - /** - * Gets the value of the 'extends' page directive attribute. - * - * @return The value of the 'extends' page directive attribute, or the - * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has - * not been set - */ - public String getExtends() { - return getExtends(true); - } - - - /* - * contentType - */ - public void setContentType(String value) { - contentType = value; - } - - public String getContentType() { - return contentType; - } - - - /* - * buffer - */ - public void setBufferValue(String value, Node n, ErrorDispatcher err) - throws JasperException { - - if ("none".equalsIgnoreCase(value)) - buffer = 0; - else { - if (value == null || !value.endsWith("kb")) - err.jspError(n, "jsp.error.page.invalid.buffer"); - try { - Integer k = new Integer(value.substring(0, value.length()-2)); - buffer = k.intValue() * 1024; - } catch (NumberFormatException e) { - err.jspError(n, "jsp.error.page.invalid.buffer"); - } - } - - bufferValue = value; - } - - public String getBufferValue() { - return bufferValue; - } - - public int getBuffer() { - return buffer; - } - - - /* - * session - */ - public void setSession(String value, Node n, ErrorDispatcher err) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - isSession = true; - else if ("false".equalsIgnoreCase(value)) - isSession = false; - else - err.jspError(n, "jsp.error.page.invalid.session"); - - session = value; - } - - public String getSession() { - return session; - } - - public boolean isSession() { - return isSession; - } - - - /* - * autoFlush - */ - public void setAutoFlush(String value, Node n, ErrorDispatcher err) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - isAutoFlush = true; - else if ("false".equalsIgnoreCase(value)) - isAutoFlush = false; - else - err.jspError(n, "jsp.error.autoFlush.invalid"); - - autoFlush = value; - } - - public String getAutoFlush() { - return autoFlush; - } - - public boolean isAutoFlush() { - return isAutoFlush; - } - - - /* - * isThreadSafe - */ - public void setIsThreadSafe(String value, Node n, ErrorDispatcher err) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - isThreadSafe = true; - else if ("false".equalsIgnoreCase(value)) - isThreadSafe = false; - else - err.jspError(n, "jsp.error.page.invalid.isthreadsafe"); - - isThreadSafeValue = value; - } - - public String getIsThreadSafe() { - return isThreadSafeValue; - } - - public boolean isThreadSafe() { - return isThreadSafe; - } - - - /* - * info - */ - public void setInfo(String value) { - info = value; - } - - public String getInfo() { - return info; - } - - - /* - * errorPage - */ - public void setErrorPage(String value) { - errorPage = value; - } - - public String getErrorPage() { - return errorPage; - } - - - /* - * isErrorPage - */ - public void setIsErrorPage(String value, Node n, ErrorDispatcher err) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - isErrorPage = true; - else if ("false".equalsIgnoreCase(value)) - isErrorPage = false; - else - err.jspError(n, "jsp.error.page.invalid.iserrorpage"); - - isErrorPageValue = value; - } - - public String getIsErrorPage() { - return isErrorPageValue; - } - - public boolean isErrorPage() { - return isErrorPage; - } - - - /* - * isELIgnored - */ - public void setIsELIgnored(String value, Node n, ErrorDispatcher err, - boolean pagedir) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - isELIgnored = true; - else if ("false".equalsIgnoreCase(value)) - isELIgnored = false; - else { - if (pagedir) - err.jspError(n, "jsp.error.page.invalid.iselignored"); - else - err.jspError(n, "jsp.error.tag.invalid.iselignored"); - } - - isELIgnoredValue = value; - } - - /* - * deferredSyntaxAllowedAsLiteral - */ - public void setDeferredSyntaxAllowedAsLiteral(String value, Node n, ErrorDispatcher err, - boolean pagedir) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - deferredSyntaxAllowedAsLiteral = true; - else if ("false".equalsIgnoreCase(value)) - deferredSyntaxAllowedAsLiteral = false; - else { - if (pagedir) - err.jspError(n, "jsp.error.page.invalid.deferredsyntaxallowedasliteral"); - else - err.jspError(n, "jsp.error.tag.invalid.deferredsyntaxallowedasliteral"); - } - - deferredSyntaxAllowedAsLiteralValue = value; - } - - /* - * trimDirectiveWhitespaces - */ - public void setTrimDirectiveWhitespaces(String value, Node n, ErrorDispatcher err, - boolean pagedir) - throws JasperException { - - if ("true".equalsIgnoreCase(value)) - trimDirectiveWhitespaces = true; - else if ("false".equalsIgnoreCase(value)) - trimDirectiveWhitespaces = false; - else { - if (pagedir) - err.jspError(n, "jsp.error.page.invalid.trimdirectivewhitespaces"); - else - err.jspError(n, "jsp.error.tag.invalid.trimdirectivewhitespaces"); - } - - deferredSyntaxAllowedAsLiteralValue = value; - } - - public void setELIgnored(boolean s) { - isELIgnored = s; - } - - public String getIsELIgnored() { - return isELIgnoredValue; - } - - public boolean isELIgnored() { - return isELIgnored; - } - - public void putNonCustomTagPrefix(String prefix, Mark where) { - nonCustomTagPrefixMap.put(prefix, where); - } - - public Mark getNonCustomTagPrefix(String prefix) { - return (Mark) nonCustomTagPrefixMap.get(prefix); - } - - public String getDeferredSyntaxAllowedAsLiteral() { - return deferredSyntaxAllowedAsLiteralValue; - } - - public boolean isDeferredSyntaxAllowedAsLiteral() { - return deferredSyntaxAllowedAsLiteral; - } - - public void setDeferredSyntaxAllowedAsLiteral(boolean isELDeferred) { - this.deferredSyntaxAllowedAsLiteral = isELDeferred; - } - - public ExpressionFactory getExpressionFactory() { - return expressionFactory; - } - - public String getTrimDirectiveWhitespaces() { - return trimDirectiveWhitespacesValue; - } - - public boolean isTrimDirectiveWhitespaces() { - return trimDirectiveWhitespaces; - } - - public void setTrimDirectiveWhitespaces(boolean trimDirectiveWhitespaces) { - this.trimDirectiveWhitespaces = trimDirectiveWhitespaces; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Vector; + +import org.apache.el.ExpressionFactoryImpl; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; + +import javax.el.ExpressionFactory; +import javax.servlet.jsp.tagext.TagLibraryInfo; + +/** + * A repository for various info about the translation unit under compilation. + * + * @author Kin-man Chung + */ + +class PageInfo { + + private Vector imports; + private Vector dependants; + + private BeanRepository beanRepository; + private HashMap taglibsMap; + private HashMap jspPrefixMapper; + private HashMap xmlPrefixMapper; + private HashMap nonCustomTagPrefixMap; + private String jspFile; + private String defaultLanguage = "java"; + private String language; + private String defaultExtends = Constants.JSP_SERVLET_BASE; + private String xtends; + private String contentType = null; + private String session; + private boolean isSession = true; + private String bufferValue; + private int buffer = 8*1024; // XXX confirm + private String autoFlush; + private boolean isAutoFlush = true; + private String isThreadSafeValue; + private boolean isThreadSafe = true; + private String isErrorPageValue; + private boolean isErrorPage = false; + private String errorPage = null; + private String info; + + private boolean scriptless = false; + private boolean scriptingInvalid = false; + + private String isELIgnoredValue; + private boolean isELIgnored = false; + + // JSP 2.1 + private String deferredSyntaxAllowedAsLiteralValue; + private boolean deferredSyntaxAllowedAsLiteral = false; + private ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); + private String trimDirectiveWhitespacesValue; + private boolean trimDirectiveWhitespaces = false; + + private String omitXmlDecl = null; + private String doctypeName = null; + private String doctypePublic = null; + private String doctypeSystem = null; + + private boolean isJspPrefixHijacked; + + // Set of all element and attribute prefixes used in this translation unit + private HashSet prefixes; + + private boolean hasJspRoot = false; + private Vector includePrelude; + private Vector includeCoda; + private Vector pluginDcls; // Id's for tagplugin declarations + + + PageInfo(BeanRepository beanRepository, String jspFile) { + + this.jspFile = jspFile; + this.beanRepository = beanRepository; + this.taglibsMap = new HashMap(); + this.jspPrefixMapper = new HashMap(); + this.xmlPrefixMapper = new HashMap(); + this.nonCustomTagPrefixMap = new HashMap(); + this.imports = new Vector(); + this.dependants = new Vector(); + this.includePrelude = new Vector(); + this.includeCoda = new Vector(); + this.pluginDcls = new Vector(); + this.prefixes = new HashSet(); + + // Enter standard imports + for(int i = 0; i < Constants.STANDARD_IMPORTS.length; i++) + imports.add(Constants.STANDARD_IMPORTS[i]); + } + + /** + * Check if the plugin ID has been previously declared. Make a not + * that this Id is now declared. + * @return true if Id has been declared. + */ + public boolean isPluginDeclared(String id) { + if (pluginDcls.contains(id)) + return true; + pluginDcls.add(id); + return false; + } + + public void addImports(List imports) { + this.imports.addAll(imports); + } + + public void addImport(String imp) { + this.imports.add(imp); + } + + public List getImports() { + return imports; + } + + public String getJspFile() { + return jspFile; + } + + public void addDependant(String d) { + if (!dependants.contains(d) && !jspFile.equals(d)) + dependants.add(d); + } + + public List getDependants() { + return dependants; + } + + public BeanRepository getBeanRepository() { + return beanRepository; + } + + public void setScriptless(boolean s) { + scriptless = s; + } + + public boolean isScriptless() { + return scriptless; + } + + public void setScriptingInvalid(boolean s) { + scriptingInvalid = s; + } + + public boolean isScriptingInvalid() { + return scriptingInvalid; + } + + public List getIncludePrelude() { + return includePrelude; + } + + public void setIncludePrelude(Vector prelude) { + includePrelude = prelude; + } + + public List getIncludeCoda() { + return includeCoda; + } + + public void setIncludeCoda(Vector coda) { + includeCoda = coda; + } + + public void setHasJspRoot(boolean s) { + hasJspRoot = s; + } + + public boolean hasJspRoot() { + return hasJspRoot; + } + + public String getOmitXmlDecl() { + return omitXmlDecl; + } + + public void setOmitXmlDecl(String omit) { + omitXmlDecl = omit; + } + + public String getDoctypeName() { + return doctypeName; + } + + public void setDoctypeName(String doctypeName) { + this.doctypeName = doctypeName; + } + + public String getDoctypeSystem() { + return doctypeSystem; + } + + public void setDoctypeSystem(String doctypeSystem) { + this.doctypeSystem = doctypeSystem; + } + + public String getDoctypePublic() { + return doctypePublic; + } + + public void setDoctypePublic(String doctypePublic) { + this.doctypePublic = doctypePublic; + } + + /* Tag library and XML namespace management methods */ + + public void setIsJspPrefixHijacked(boolean isHijacked) { + isJspPrefixHijacked = isHijacked; + } + + public boolean isJspPrefixHijacked() { + return isJspPrefixHijacked; + } + + /* + * Adds the given prefix to the set of prefixes of this translation unit. + * + * @param prefix The prefix to add + */ + public void addPrefix(String prefix) { + prefixes.add(prefix); + } + + /* + * Checks to see if this translation unit contains the given prefix. + * + * @param prefix The prefix to check + * + * @return true if this translation unit contains the given prefix, false + * otherwise + */ + public boolean containsPrefix(String prefix) { + return prefixes.contains(prefix); + } + + /* + * Maps the given URI to the given tag library. + * + * @param uri The URI to map + * @param info The tag library to be associated with the given URI + */ + public void addTaglib(String uri, TagLibraryInfo info) { + taglibsMap.put(uri, info); + } + + /* + * Gets the tag library corresponding to the given URI. + * + * @return Tag library corresponding to the given URI + */ + public TagLibraryInfo getTaglib(String uri) { + return (TagLibraryInfo) taglibsMap.get(uri); + } + + /* + * Gets the collection of tag libraries that are associated with a URI + * + * @return Collection of tag libraries that are associated with a URI + */ + public Collection getTaglibs() { + return taglibsMap.values(); + } + + /* + * Checks to see if the given URI is mapped to a tag library. + * + * @param uri The URI to map + * + * @return true if the given URI is mapped to a tag library, false + * otherwise + */ + public boolean hasTaglib(String uri) { + return taglibsMap.containsKey(uri); + } + + /* + * Maps the given prefix to the given URI. + * + * @param prefix The prefix to map + * @param uri The URI to be associated with the given prefix + */ + public void addPrefixMapping(String prefix, String uri) { + jspPrefixMapper.put(prefix, uri); + } + + /* + * Pushes the given URI onto the stack of URIs to which the given prefix + * is mapped. + * + * @param prefix The prefix whose stack of URIs is to be pushed + * @param uri The URI to be pushed onto the stack + */ + public void pushPrefixMapping(String prefix, String uri) { + LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); + if (stack == null) { + stack = new LinkedList(); + xmlPrefixMapper.put(prefix, stack); + } + stack.addFirst(uri); + } + + /* + * Removes the URI at the top of the stack of URIs to which the given + * prefix is mapped. + * + * @param prefix The prefix whose stack of URIs is to be popped + */ + public void popPrefixMapping(String prefix) { + LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); + if (stack == null || stack.size() == 0) { + // XXX throw new Exception("XXX"); + } + stack.removeFirst(); + } + + /* + * Returns the URI to which the given prefix maps. + * + * @param prefix The prefix whose URI is sought + * + * @return The URI to which the given prefix maps + */ + public String getURI(String prefix) { + + String uri = null; + + LinkedList stack = (LinkedList) xmlPrefixMapper.get(prefix); + if (stack == null || stack.size() == 0) { + uri = (String) jspPrefixMapper.get(prefix); + } else { + uri = (String) stack.getFirst(); + } + + return uri; + } + + + /* Page/Tag directive attributes */ + + /* + * language + */ + public void setLanguage(String value, Node n, ErrorDispatcher err, + boolean pagedir) + throws JasperException { + + if (!"java".equalsIgnoreCase(value)) { + if (pagedir) + err.jspError(n, "jsp.error.page.language.nonjava"); + else + err.jspError(n, "jsp.error.tag.language.nonjava"); + } + + language = value; + } + + public String getLanguage(boolean useDefault) { + return (language == null && useDefault ? defaultLanguage : language); + } + + public String getLanguage() { + return getLanguage(true); + } + + + /* + * extends + */ + public void setExtends(String value, Node.PageDirective n) { + + xtends = value; + + /* + * If page superclass is top level class (i.e. not in a package) + * explicitly import it. If this is not done, the compiler will assume + * the extended class is in the same pkg as the generated servlet. + */ + if (value.indexOf('.') < 0) + n.addImport(value); + } + + /** + * Gets the value of the 'extends' page directive attribute. + * + * @param useDefault TRUE if the default + * (org.apache.jasper.runtime.HttpJspBase) should be returned if this + * attribute has not been set, FALSE otherwise + * + * @return The value of the 'extends' page directive attribute, or the + * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has + * not been set and useDefault is TRUE + */ + public String getExtends(boolean useDefault) { + return (xtends == null && useDefault ? defaultExtends : xtends); + } + + /** + * Gets the value of the 'extends' page directive attribute. + * + * @return The value of the 'extends' page directive attribute, or the + * default (org.apache.jasper.runtime.HttpJspBase) if this attribute has + * not been set + */ + public String getExtends() { + return getExtends(true); + } + + + /* + * contentType + */ + public void setContentType(String value) { + contentType = value; + } + + public String getContentType() { + return contentType; + } + + + /* + * buffer + */ + public void setBufferValue(String value, Node n, ErrorDispatcher err) + throws JasperException { + + if ("none".equalsIgnoreCase(value)) + buffer = 0; + else { + if (value == null || !value.endsWith("kb")) + err.jspError(n, "jsp.error.page.invalid.buffer"); + try { + Integer k = new Integer(value.substring(0, value.length()-2)); + buffer = k.intValue() * 1024; + } catch (NumberFormatException e) { + err.jspError(n, "jsp.error.page.invalid.buffer"); + } + } + + bufferValue = value; + } + + public String getBufferValue() { + return bufferValue; + } + + public int getBuffer() { + return buffer; + } + + + /* + * session + */ + public void setSession(String value, Node n, ErrorDispatcher err) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + isSession = true; + else if ("false".equalsIgnoreCase(value)) + isSession = false; + else + err.jspError(n, "jsp.error.page.invalid.session"); + + session = value; + } + + public String getSession() { + return session; + } + + public boolean isSession() { + return isSession; + } + + + /* + * autoFlush + */ + public void setAutoFlush(String value, Node n, ErrorDispatcher err) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + isAutoFlush = true; + else if ("false".equalsIgnoreCase(value)) + isAutoFlush = false; + else + err.jspError(n, "jsp.error.autoFlush.invalid"); + + autoFlush = value; + } + + public String getAutoFlush() { + return autoFlush; + } + + public boolean isAutoFlush() { + return isAutoFlush; + } + + + /* + * isThreadSafe + */ + public void setIsThreadSafe(String value, Node n, ErrorDispatcher err) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + isThreadSafe = true; + else if ("false".equalsIgnoreCase(value)) + isThreadSafe = false; + else + err.jspError(n, "jsp.error.page.invalid.isthreadsafe"); + + isThreadSafeValue = value; + } + + public String getIsThreadSafe() { + return isThreadSafeValue; + } + + public boolean isThreadSafe() { + return isThreadSafe; + } + + + /* + * info + */ + public void setInfo(String value) { + info = value; + } + + public String getInfo() { + return info; + } + + + /* + * errorPage + */ + public void setErrorPage(String value) { + errorPage = value; + } + + public String getErrorPage() { + return errorPage; + } + + + /* + * isErrorPage + */ + public void setIsErrorPage(String value, Node n, ErrorDispatcher err) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + isErrorPage = true; + else if ("false".equalsIgnoreCase(value)) + isErrorPage = false; + else + err.jspError(n, "jsp.error.page.invalid.iserrorpage"); + + isErrorPageValue = value; + } + + public String getIsErrorPage() { + return isErrorPageValue; + } + + public boolean isErrorPage() { + return isErrorPage; + } + + + /* + * isELIgnored + */ + public void setIsELIgnored(String value, Node n, ErrorDispatcher err, + boolean pagedir) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + isELIgnored = true; + else if ("false".equalsIgnoreCase(value)) + isELIgnored = false; + else { + if (pagedir) + err.jspError(n, "jsp.error.page.invalid.iselignored"); + else + err.jspError(n, "jsp.error.tag.invalid.iselignored"); + } + + isELIgnoredValue = value; + } + + /* + * deferredSyntaxAllowedAsLiteral + */ + public void setDeferredSyntaxAllowedAsLiteral(String value, Node n, ErrorDispatcher err, + boolean pagedir) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + deferredSyntaxAllowedAsLiteral = true; + else if ("false".equalsIgnoreCase(value)) + deferredSyntaxAllowedAsLiteral = false; + else { + if (pagedir) + err.jspError(n, "jsp.error.page.invalid.deferredsyntaxallowedasliteral"); + else + err.jspError(n, "jsp.error.tag.invalid.deferredsyntaxallowedasliteral"); + } + + deferredSyntaxAllowedAsLiteralValue = value; + } + + /* + * trimDirectiveWhitespaces + */ + public void setTrimDirectiveWhitespaces(String value, Node n, ErrorDispatcher err, + boolean pagedir) + throws JasperException { + + if ("true".equalsIgnoreCase(value)) + trimDirectiveWhitespaces = true; + else if ("false".equalsIgnoreCase(value)) + trimDirectiveWhitespaces = false; + else { + if (pagedir) + err.jspError(n, "jsp.error.page.invalid.trimdirectivewhitespaces"); + else + err.jspError(n, "jsp.error.tag.invalid.trimdirectivewhitespaces"); + } + + deferredSyntaxAllowedAsLiteralValue = value; + } + + public void setELIgnored(boolean s) { + isELIgnored = s; + } + + public String getIsELIgnored() { + return isELIgnoredValue; + } + + public boolean isELIgnored() { + return isELIgnored; + } + + public void putNonCustomTagPrefix(String prefix, Mark where) { + nonCustomTagPrefixMap.put(prefix, where); + } + + public Mark getNonCustomTagPrefix(String prefix) { + return (Mark) nonCustomTagPrefixMap.get(prefix); + } + + public String getDeferredSyntaxAllowedAsLiteral() { + return deferredSyntaxAllowedAsLiteralValue; + } + + public boolean isDeferredSyntaxAllowedAsLiteral() { + return deferredSyntaxAllowedAsLiteral; + } + + public void setDeferredSyntaxAllowedAsLiteral(boolean isELDeferred) { + this.deferredSyntaxAllowedAsLiteral = isELDeferred; + } + + public ExpressionFactory getExpressionFactory() { + return expressionFactory; + } + + public String getTrimDirectiveWhitespaces() { + return trimDirectiveWhitespacesValue; + } + + public boolean isTrimDirectiveWhitespaces() { + return trimDirectiveWhitespaces; + } + + public void setTrimDirectiveWhitespaces(boolean trimDirectiveWhitespaces) { + this.trimDirectiveWhitespaces = trimDirectiveWhitespaces; + } +} diff --git a/java/org/apache/jasper/compiler/Parser.java b/java/org/apache/jasper/compiler/Parser.java index 5f0c3345c..97fda85a7 100644 --- a/java/org/apache/jasper/compiler/Parser.java +++ b/java/org/apache/jasper/compiler/Parser.java @@ -1,1776 +1,1776 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.io.CharArrayWriter; -import java.io.FileNotFoundException; -import java.net.URL; -import java.util.Iterator; -import java.util.List; - -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagFileInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; - -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.xml.sax.Attributes; -import org.xml.sax.helpers.AttributesImpl; - -/** - * This class implements a parser for a JSP page (non-xml view). JSP page - * grammar is included here for reference. The token '#' that appears in the - * production indicates the current input token location in the production. - * - * @author Kin-man Chung - * @author Shawn Bayern - * @author Mark Roth - */ - -class Parser implements TagConstants { - - private ParserController parserController; - - private JspCompilationContext ctxt; - - private JspReader reader; - - private String currentFile; - - private Mark start; - - private ErrorDispatcher err; - - private int scriptlessCount; - - private boolean isTagFile; - - private boolean directivesOnly; - - private URL jarFileUrl; - - private PageInfo pageInfo; - - // Virtual body content types, to make parsing a little easier. - // These are not accessible from outside the parser. - private static final String JAVAX_BODY_CONTENT_PARAM = "JAVAX_BODY_CONTENT_PARAM"; - - private static final String JAVAX_BODY_CONTENT_PLUGIN = "JAVAX_BODY_CONTENT_PLUGIN"; - - private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = "JAVAX_BODY_CONTENT_TEMPLATE_TEXT"; - - /** - * The constructor - */ - private Parser(ParserController pc, JspReader reader, boolean isTagFile, - boolean directivesOnly, URL jarFileUrl) { - this.parserController = pc; - this.ctxt = pc.getJspCompilationContext(); - this.pageInfo = pc.getCompiler().getPageInfo(); - this.err = pc.getCompiler().getErrorDispatcher(); - this.reader = reader; - this.currentFile = reader.mark().getFile(); - this.scriptlessCount = 0; - this.isTagFile = isTagFile; - this.directivesOnly = directivesOnly; - this.jarFileUrl = jarFileUrl; - start = reader.mark(); - } - - /** - * The main entry for Parser - * - * @param pc - * The ParseController, use for getting other objects in compiler - * and for parsing included pages - * @param reader - * To read the page - * @param parent - * The parent node to this page, null for top level page - * @return list of nodes representing the parsed page - */ - public static Node.Nodes parse(ParserController pc, JspReader reader, - Node parent, boolean isTagFile, boolean directivesOnly, - URL jarFileUrl, String pageEnc, String jspConfigPageEnc, - boolean isDefaultPageEncoding) throws JasperException { - - Parser parser = new Parser(pc, reader, isTagFile, directivesOnly, - jarFileUrl); - - Node.Root root = new Node.Root(reader.mark(), parent, false); - root.setPageEncoding(pageEnc); - root.setJspConfigPageEncoding(jspConfigPageEnc); - root.setIsDefaultPageEncoding(isDefaultPageEncoding); - - if (directivesOnly) { - parser.parseTagFileDirectives(root); - return new Node.Nodes(root); - } - - // For the Top level page, add inlcude-prelude and include-coda - PageInfo pageInfo = pc.getCompiler().getPageInfo(); - if (parent == null) { - parser.addInclude(root, pageInfo.getIncludePrelude()); - } - while (reader.hasMoreInput()) { - parser.parseElements(root); - } - if (parent == null) { - parser.addInclude(root, pageInfo.getIncludeCoda()); - } - - Node.Nodes page = new Node.Nodes(root); - return page; - } - - /** - * Attributes ::= (S Attribute)* S? - */ - Attributes parseAttributes() throws JasperException { - AttributesImpl attrs = new AttributesImpl(); - - reader.skipSpaces(); - while (parseAttribute(attrs)) - reader.skipSpaces(); - - return attrs; - } - - /** - * Parse Attributes for a reader, provided for external use - */ - public static Attributes parseAttributes(ParserController pc, - JspReader reader) throws JasperException { - Parser tmpParser = new Parser(pc, reader, false, false, null); - return tmpParser.parseAttributes(); - } - - /** - * Attribute ::= Name S? Eq S? ( '"<%=' RTAttributeValueDouble | '"' - * AttributeValueDouble | "'<%=" RTAttributeValueSingle | "'" - * AttributeValueSingle } Note: JSP and XML spec does not allow while spaces - * around Eq. It is added to be backward compatible with Tomcat, and with - * other xml parsers. - */ - private boolean parseAttribute(AttributesImpl attrs) throws JasperException { - - // Get the qualified name - String qName = parseName(); - if (qName == null) - return false; - - // Determine prefix and local name components - String localName = qName; - String uri = ""; - int index = qName.indexOf(':'); - if (index != -1) { - String prefix = qName.substring(0, index); - uri = pageInfo.getURI(prefix); - if (uri == null) { - err.jspError(reader.mark(), - "jsp.error.attribute.invalidPrefix", prefix); - } - localName = qName.substring(index + 1); - } - - reader.skipSpaces(); - if (!reader.matches("=")) - err.jspError(reader.mark(), "jsp.error.attribute.noequal"); - - reader.skipSpaces(); - char quote = (char) reader.nextChar(); - if (quote != '\'' && quote != '"') - err.jspError(reader.mark(), "jsp.error.attribute.noquote"); - - String watchString = ""; - if (reader.matches("<%=")) - watchString = "%>"; - watchString = watchString + quote; - - String attrValue = parseAttributeValue(watchString); - attrs.addAttribute(uri, localName, qName, "CDATA", attrValue); - return true; - } - - /** - * Name ::= (Letter | '_' | ':') (Letter | Digit | '.' | '_' | '-' | ':')* - */ - private String parseName() throws JasperException { - char ch = (char) reader.peekChar(); - if (Character.isLetter(ch) || ch == '_' || ch == ':') { - StringBuffer buf = new StringBuffer(); - buf.append(ch); - reader.nextChar(); - ch = (char) reader.peekChar(); - while (Character.isLetter(ch) || Character.isDigit(ch) || ch == '.' - || ch == '_' || ch == '-' || ch == ':') { - buf.append(ch); - reader.nextChar(); - ch = (char) reader.peekChar(); - } - return buf.toString(); - } - return null; - } - - /** - * AttributeValueDouble ::= (QuotedChar - '"')* ('"' | ) - * RTAttributeValueDouble ::= ((QuotedChar - '"')* - ((QuotedChar-'"')'%>"') - * ('%>"' | TRANSLATION_ERROR) - */ - private String parseAttributeValue(String watch) throws JasperException { - Mark start = reader.mark(); - Mark stop = reader.skipUntilIgnoreEsc(watch); - if (stop == null) { - err.jspError(start, "jsp.error.attribute.unterminated", watch); - } - - String ret = parseQuoted(reader.getText(start, stop)); - if (watch.length() == 1) // quote - return ret; - - // putback delimiter '<%=' and '%>', since they are needed if the - // attribute does not allow RTexpression. - return "<%=" + ret + "%>"; - } - - /** - * QuotedChar ::= ''' | '"' | '\\' | '\"' | "\'" | '\>' | '\$' | - * Char - */ - private String parseQuoted(String tx) { - StringBuffer buf = new StringBuffer(); - int size = tx.length(); - int i = 0; - while (i < size) { - char ch = tx.charAt(i); - if (ch == '&') { - if (i + 5 < size && tx.charAt(i + 1) == 'a' - && tx.charAt(i + 2) == 'p' && tx.charAt(i + 3) == 'o' - && tx.charAt(i + 4) == 's' && tx.charAt(i + 5) == ';') { - buf.append('\''); - i += 6; - } else if (i + 5 < size && tx.charAt(i + 1) == 'q' - && tx.charAt(i + 2) == 'u' && tx.charAt(i + 3) == 'o' - && tx.charAt(i + 4) == 't' && tx.charAt(i + 5) == ';') { - buf.append('"'); - i += 6; - } else { - buf.append(ch); - ++i; - } - } else if (ch == '\\' && i + 1 < size) { - ch = tx.charAt(i + 1); - if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') { - buf.append(ch); - i += 2; - } else if (ch == '$') { - // Replace "\$" with some special char. XXX hack! - buf.append(Constants.ESC); - i += 2; - } else { - buf.append('\\'); - ++i; - } - } else { - buf.append(ch); - ++i; - } - } - return buf.toString(); - } - - private String parseScriptText(String tx) { - CharArrayWriter cw = new CharArrayWriter(); - int size = tx.length(); - int i = 0; - while (i < size) { - char ch = tx.charAt(i); - if (i + 2 < size && ch == '%' && tx.charAt(i + 1) == '\\' - && tx.charAt(i + 2) == '>') { - cw.write('%'); - cw.write('>'); - i += 3; - } else { - cw.write(ch); - ++i; - } - } - cw.close(); - return cw.toString(); - } - - /* - * Invokes parserController to parse the included page - */ - private void processIncludeDirective(String file, Node parent) - throws JasperException { - if (file == null) { - return; - } - - try { - parserController.parse(file, parent, jarFileUrl); - } catch (FileNotFoundException ex) { - err.jspError(start, "jsp.error.file.not.found", file); - } catch (Exception ex) { - err.jspError(start, ex.getMessage()); - } - } - - /* - * Parses a page directive with the following syntax: PageDirective ::= ( S - * Attribute)* - */ - private void parsePageDirective(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - Node.PageDirective n = new Node.PageDirective(attrs, start, parent); - - /* - * A page directive may contain multiple 'import' attributes, each of - * which consists of a comma-separated list of package names. Store each - * list with the node, where it is parsed. - */ - for (int i = 0; i < attrs.getLength(); i++) { - if ("import".equals(attrs.getQName(i))) { - n.addImport(attrs.getValue(i)); - } - } - } - - /* - * Parses an include directive with the following syntax: IncludeDirective - * ::= ( S Attribute)* - */ - private void parseIncludeDirective(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - - // Included file expanded here - Node includeNode = new Node.IncludeDirective(attrs, start, parent); - processIncludeDirective(attrs.getValue("file"), includeNode); - } - - /** - * Add a list of files. This is used for implementing include-prelude and - * include-coda of jsp-config element in web.xml - */ - private void addInclude(Node parent, List files) throws JasperException { - if (files != null) { - Iterator iter = files.iterator(); - while (iter.hasNext()) { - String file = (String) iter.next(); - AttributesImpl attrs = new AttributesImpl(); - attrs.addAttribute("", "file", "file", "CDATA", file); - - // Create a dummy Include directive node - Node includeNode = new Node.IncludeDirective(attrs, reader - .mark(), parent); - processIncludeDirective(file, includeNode); - } - } - } - - /* - * Parses a taglib directive with the following syntax: Directive ::= ( S - * Attribute)* - */ - private void parseTaglibDirective(Node parent) throws JasperException { - - Attributes attrs = parseAttributes(); - String uri = attrs.getValue("uri"); - String prefix = attrs.getValue("prefix"); - if (prefix != null) { - Mark prevMark = pageInfo.getNonCustomTagPrefix(prefix); - if (prevMark != null) { - err.jspError(reader.mark(), "jsp.error.prefix.use_before_dcl", - prefix, prevMark.getFile(), "" - + prevMark.getLineNumber()); - } - if (uri != null) { - String uriPrev = pageInfo.getURI(prefix); - if (uriPrev != null && !uriPrev.equals(uri)) { - err.jspError(reader.mark(), "jsp.error.prefix.refined", - prefix, uri, uriPrev); - } - if (pageInfo.getTaglib(uri) == null) { - TagLibraryInfoImpl impl = null; - if (ctxt.getOptions().isCaching()) { - impl = (TagLibraryInfoImpl) ctxt.getOptions() - .getCache().get(uri); - } - if (impl == null) { - String[] location = ctxt.getTldLocation(uri); - impl = new TagLibraryInfoImpl(ctxt, parserController, - prefix, uri, location, err); - if (ctxt.getOptions().isCaching()) { - ctxt.getOptions().getCache().put(uri, impl); - } - } - pageInfo.addTaglib(uri, impl); - } - pageInfo.addPrefixMapping(prefix, uri); - } else { - String tagdir = attrs.getValue("tagdir"); - if (tagdir != null) { - String urnTagdir = URN_JSPTAGDIR + tagdir; - if (pageInfo.getTaglib(urnTagdir) == null) { - pageInfo.addTaglib(urnTagdir, - new ImplicitTagLibraryInfo(ctxt, - parserController, prefix, tagdir, err)); - } - pageInfo.addPrefixMapping(prefix, urnTagdir); - } - } - } - - new Node.TaglibDirective(attrs, start, parent); - } - - /* - * Parses a directive with the following syntax: Directive ::= S? ( 'page' - * PageDirective | 'include' IncludeDirective | 'taglib' TagLibDirective) S? - * '%>' - * - * TagDirective ::= S? ('tag' PageDirective | 'include' IncludeDirective | - * 'taglib' TagLibDirective) | 'attribute AttributeDirective | 'variable - * VariableDirective S? '%>' - */ - private void parseDirective(Node parent) throws JasperException { - reader.skipSpaces(); - - String directive = null; - if (reader.matches("page")) { - directive = "<%@ page"; - if (isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.istagfile", - directive); - } - parsePageDirective(parent); - } else if (reader.matches("include")) { - directive = "<%@ include"; - parseIncludeDirective(parent); - } else if (reader.matches("taglib")) { - if (directivesOnly) { - // No need to get the tagLibInfo objects. This alos suppresses - // parsing of any tag files used in this tag file. - return; - } - directive = "<%@ taglib"; - parseTaglibDirective(parent); - } else if (reader.matches("tag")) { - directive = "<%@ tag"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - directive); - } - parseTagDirective(parent); - } else if (reader.matches("attribute")) { - directive = "<%@ attribute"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - directive); - } - parseAttributeDirective(parent); - } else if (reader.matches("variable")) { - directive = "<%@ variable"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - directive); - } - parseVariableDirective(parent); - } else { - err.jspError(reader.mark(), "jsp.error.invalid.directive"); - } - - reader.skipSpaces(); - if (!reader.matches("%>")) { - err.jspError(start, "jsp.error.unterminated", directive); - } - } - - /* - * Parses a directive with the following syntax: - * - * XMLJSPDirectiveBody ::= S? ( ( 'page' PageDirectiveAttrList S? ( '/>' | ( - * '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>' - * S? ETag ) ) | - * - * XMLTagDefDirectiveBody ::= ( ( 'tag' TagDirectiveAttrList S? ( '/>' | ( - * '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>' - * S? ETag ) ) | ( 'attribute' AttributeDirectiveAttrList S? ( '/>' | ( '>' - * S? ETag ) ) | ( 'variable' VariableDirectiveAttrList S? ( '/>' | ( '>' S? - * ETag ) ) ) | - */ - private void parseXMLDirective(Node parent) throws JasperException { - reader.skipSpaces(); - - String eTag = null; - if (reader.matches("page")) { - eTag = "jsp:directive.page"; - if (isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.istagfile", - "<" + eTag); - } - parsePageDirective(parent); - } else if (reader.matches("include")) { - eTag = "jsp:directive.include"; - parseIncludeDirective(parent); - } else if (reader.matches("tag")) { - eTag = "jsp:directive.tag"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - "<" + eTag); - } - parseTagDirective(parent); - } else if (reader.matches("attribute")) { - eTag = "jsp:directive.attribute"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - "<" + eTag); - } - parseAttributeDirective(parent); - } else if (reader.matches("variable")) { - eTag = "jsp:directive.variable"; - if (!isTagFile) { - err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", - "<" + eTag); - } - parseVariableDirective(parent); - } else { - err.jspError(reader.mark(), "jsp.error.invalid.directive"); - } - - reader.skipSpaces(); - if (reader.matches(">")) { - reader.skipSpaces(); - if (!reader.matchesETag(eTag)) { - err.jspError(start, "jsp.error.unterminated", "<" + eTag); - } - } else if (!reader.matches("/>")) { - err.jspError(start, "jsp.error.unterminated", "<" + eTag); - } - } - - /* - * Parses a tag directive with the following syntax: PageDirective ::= ( S - * Attribute)* - */ - private void parseTagDirective(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - Node.TagDirective n = new Node.TagDirective(attrs, start, parent); - - /* - * A page directive may contain multiple 'import' attributes, each of - * which consists of a comma-separated list of package names. Store each - * list with the node, where it is parsed. - */ - for (int i = 0; i < attrs.getLength(); i++) { - if ("import".equals(attrs.getQName(i))) { - n.addImport(attrs.getValue(i)); - } - } - } - - /* - * Parses a attribute directive with the following syntax: - * AttributeDirective ::= ( S Attribute)* - */ - private void parseAttributeDirective(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - Node.AttributeDirective n = new Node.AttributeDirective(attrs, start, - parent); - } - - /* - * Parses a variable directive with the following syntax: PageDirective ::= ( - * S Attribute)* - */ - private void parseVariableDirective(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - Node.VariableDirective n = new Node.VariableDirective(attrs, start, - parent); - } - - /* - * JSPCommentBody ::= (Char* - (Char* '--%>')) '--%>' - */ - private void parseComment(Node parent) throws JasperException { - start = reader.mark(); - Mark stop = reader.skipUntil("--%>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "<%--"); - } - - new Node.Comment(reader.getText(start, stop), start, parent); - } - - /* - * DeclarationBody ::= (Char* - (char* '%>')) '%>' - */ - private void parseDeclaration(Node parent) throws JasperException { - start = reader.mark(); - Mark stop = reader.skipUntil("%>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "<%!"); - } - - new Node.Declaration(parseScriptText(reader.getText(start, stop)), - start, parent); - } - - /* - * XMLDeclarationBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) - * CDSect?)* ETag | CDSect ::= CDStart CData CDEnd - * CDStart ::= '' Char*)) CDEnd - * ::= ']]>' - */ - private void parseXMLDeclaration(Node parent) throws JasperException { - reader.skipSpaces(); - if (!reader.matches("/>")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:declaration>"); - } - Mark stop; - String text; - while (true) { - start = reader.mark(); - stop = reader.skipUntil("<"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:declaration>"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Declaration(text, start, parent); - if (reader.matches("![CDATA[")) { - start = reader.mark(); - stop = reader.skipUntil("]]>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "CDATA"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Declaration(text, start, parent); - } else { - break; - } - } - - if (!reader.matchesETagWithoutLessThan("jsp:declaration")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:declaration>"); - } - } - } - - /* - * ExpressionBody ::= (Char* - (char* '%>')) '%>' - */ - private void parseExpression(Node parent) throws JasperException { - start = reader.mark(); - Mark stop = reader.skipUntil("%>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "<%="); - } - - new Node.Expression(parseScriptText(reader.getText(start, stop)), - start, parent); - } - - /* - * XMLExpressionBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) - * CDSect?)* ETag ) | - */ - private void parseXMLExpression(Node parent) throws JasperException { - reader.skipSpaces(); - if (!reader.matches("/>")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:expression>"); - } - Mark stop; - String text; - while (true) { - start = reader.mark(); - stop = reader.skipUntil("<"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:expression>"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Expression(text, start, parent); - if (reader.matches("![CDATA[")) { - start = reader.mark(); - stop = reader.skipUntil("]]>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "CDATA"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Expression(text, start, parent); - } else { - break; - } - } - if (!reader.matchesETagWithoutLessThan("jsp:expression")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:expression>"); - } - } - } - - /* - * ELExpressionBody (following "${" to first unquoted "}") // XXX add formal - * production and confirm implementation against it, // once it's decided - */ - private void parseELExpression(Node parent, char type) throws JasperException { - start = reader.mark(); - Mark last = null; - boolean singleQuoted = false, doubleQuoted = false; - int currentChar; - do { - // XXX could move this logic to JspReader - last = reader.mark(); // XXX somewhat wasteful - currentChar = reader.nextChar(); - if (currentChar == '\\' && (singleQuoted || doubleQuoted)) { - // skip character following '\' within quotes - reader.nextChar(); - currentChar = reader.nextChar(); - } - if (currentChar == -1) - err.jspError(start, "jsp.error.unterminated", type + "{"); - if (currentChar == '"') - doubleQuoted = !doubleQuoted; - if (currentChar == '\'') - singleQuoted = !singleQuoted; - } while (currentChar != '}' || (singleQuoted || doubleQuoted)); - - new Node.ELExpression(type, reader.getText(start, last), start, parent); - } - - /* - * ScriptletBody ::= (Char* - (char* '%>')) '%>' - */ - private void parseScriptlet(Node parent) throws JasperException { - start = reader.mark(); - Mark stop = reader.skipUntil("%>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "<%"); - } - - new Node.Scriptlet(parseScriptText(reader.getText(start, stop)), start, - parent); - } - - /* - * XMLScriptletBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) - * CDSect?)* ETag ) | - */ - private void parseXMLScriptlet(Node parent) throws JasperException { - reader.skipSpaces(); - if (!reader.matches("/>")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:scriptlet>"); - } - Mark stop; - String text; - while (true) { - start = reader.mark(); - stop = reader.skipUntil("<"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:scriptlet>"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Scriptlet(text, start, parent); - if (reader.matches("![CDATA[")) { - start = reader.mark(); - stop = reader.skipUntil("]]>"); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "CDATA"); - } - text = parseScriptText(reader.getText(start, stop)); - new Node.Scriptlet(text, start, parent); - } else { - break; - } - } - - if (!reader.matchesETagWithoutLessThan("jsp:scriptlet")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:scriptlet>"); - } - } - } - - /** - * Param ::= '' S? ( ' ) S? ETag ) | ( '>' S? Param* ETag ) - * - * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '' Param* '' - */ - private void parseInclude(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node includeNode = new Node.IncludeAction(attrs, start, parent); - - parseOptionalBody(includeNode, "jsp:include", JAVAX_BODY_CONTENT_PARAM); - } - - /* - * For Forward: StdActionContent ::= Attributes ParamBody - */ - private void parseForward(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node forwardNode = new Node.ForwardAction(attrs, start, parent); - - parseOptionalBody(forwardNode, "jsp:forward", JAVAX_BODY_CONTENT_PARAM); - } - - private void parseInvoke(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node invokeNode = new Node.InvokeAction(attrs, start, parent); - - parseEmptyBody(invokeNode, "jsp:invoke"); - } - - private void parseDoBody(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node doBodyNode = new Node.DoBodyAction(attrs, start, parent); - - parseEmptyBody(doBodyNode, "jsp:doBody"); - } - - private void parseElement(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node elementNode = new Node.JspElement(attrs, start, parent); - - parseOptionalBody(elementNode, "jsp:element", TagInfo.BODY_CONTENT_JSP); - } - - /* - * For GetProperty: StdActionContent ::= Attributes EmptyBody - */ - private void parseGetProperty(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node getPropertyNode = new Node.GetProperty(attrs, start, parent); - - parseOptionalBody(getPropertyNode, "jsp:getProperty", - TagInfo.BODY_CONTENT_EMPTY); - } - - /* - * For SetProperty: StdActionContent ::= Attributes EmptyBody - */ - private void parseSetProperty(Node parent) throws JasperException { - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - Node setPropertyNode = new Node.SetProperty(attrs, start, parent); - - parseOptionalBody(setPropertyNode, "jsp:setProperty", - TagInfo.BODY_CONTENT_EMPTY); - } - - /* - * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '")) { - // Done - } else if (reader.matches(">")) { - if (reader.matchesETag(tag)) { - // Done - } else if (reader.matchesOptionalSpacesFollowedBy("' ETag ) | ( '>' S? '' Body ETag ) - * - * ScriptlessActionBody ::= JspAttributeAndBody | ( '>' ScriptlessBody ETag ) - * - * TagDependentActionBody ::= JspAttributeAndBody | ( '>' TagDependentBody - * ETag ) - * - */ - private void parseOptionalBody(Node parent, String tag, String bodyType) - throws JasperException { - if (reader.matches("/>")) { - // EmptyBody - return; - } - - if (!reader.matches(">")) { - err.jspError(reader.mark(), "jsp.error.unterminated", "<" + tag); - } - - if (reader.matchesETag(tag)) { - // EmptyBody - return; - } - - if (!parseJspAttributeAndBody(parent, tag, bodyType)) { - // Must be ( '>' # Body ETag ) - parseBody(parent, tag, bodyType); - } - } - - /** - * Attempts to parse 'JspAttributeAndBody' production. Returns true if it - * matched, or false if not. Assumes EmptyBody is okay as well. - * - * JspAttributeAndBody ::= ( '>' # S? ( ' ) S? ETag ) - */ - private boolean parseJspAttributeAndBody(Node parent, String tag, - String bodyType) throws JasperException { - boolean result = false; - - if (reader.matchesOptionalSpacesFollowedBy(" elements: - parseNamedAttributes(parent); - - result = true; - } - - if (reader.matchesOptionalSpacesFollowedBy(" but something other than - // or the end tag, translation error. - err.jspError(reader.mark(), "jsp.error.jspbody.required", "<" - + tag); - } - - return result; - } - - /* - * Params ::= `>' S? ( ( `' ( ( S? Param+ S? `' ) | - * ) ) | Param+ ) '' - */ - private void parseJspParams(Node parent) throws JasperException { - Node jspParamsNode = new Node.ParamsAction(start, parent); - parseOptionalBody(jspParamsNode, "jsp:params", JAVAX_BODY_CONTENT_PARAM); - } - - /* - * Fallback ::= '/>' | ( `>' S? `' ( ( S? ( Char* - ( Char* `' ) ) `' - * S? ) | ) `' ) | ( '>' ( Char* - ( - * Char* '' ) ) '' ) - */ - private void parseFallBack(Node parent) throws JasperException { - Node fallBackNode = new Node.FallBackAction(start, parent); - parseOptionalBody(fallBackNode, "jsp:fallback", - JAVAX_BODY_CONTENT_TEMPLATE_TEXT); - } - - /* - * For Plugin: StdActionContent ::= Attributes PluginBody - * - * PluginBody ::= EmptyBody | ( '>' S? ( ' ) S? ETag ) | ( '>' S? PluginTags - * ETag ) - * - * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? ' - * - * Attributes ::= ( S Attribute )* S? - * - * CustomActionEnd ::= CustomActionTagDependent | CustomActionJSPContent | - * CustomActionScriptlessContent - * - * CustomActionTagDependent ::= TagDependentOptionalBody - * - * CustomActionJSPContent ::= OptionalBody - * - * CustomActionScriptlessContent ::= ScriptlessOptionalBody - */ - private boolean parseCustomTag(Node parent) throws JasperException { - - if (reader.peekChar() != '<') { - return false; - } - - // Parse 'CustomAction' production (tag prefix and custom action name) - reader.nextChar(); // skip '<' - String tagName = reader.parseToken(false); - int i = tagName.indexOf(':'); - if (i == -1) { - reader.reset(start); - return false; - } - - String prefix = tagName.substring(0, i); - String shortTagName = tagName.substring(i + 1); - - // Check if this is a user-defined tag. - String uri = pageInfo.getURI(prefix); - if (uri == null) { - reader.reset(start); - // Remember the prefix for later error checking - pageInfo.putNonCustomTagPrefix(prefix, reader.mark()); - return false; - } - - TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri); - TagInfo tagInfo = tagLibInfo.getTag(shortTagName); - TagFileInfo tagFileInfo = tagLibInfo.getTagFile(shortTagName); - if (tagInfo == null && tagFileInfo == null) { - err.jspError(start, "jsp.error.bad_tag", shortTagName, prefix); - } - Class tagHandlerClass = null; - if (tagInfo != null) { - // Must be a classic tag, load it here. - // tag files will be loaded later, in TagFileProcessor - String handlerClassName = tagInfo.getTagClassName(); - try { - tagHandlerClass = ctxt.getClassLoader().loadClass( - handlerClassName); - } catch (Exception e) { - err.jspError(start, "jsp.error.loadclass.taghandler", - handlerClassName, tagName); - } - } - - // Parse 'CustomActionBody' production: - // At this point we are committed - if anything fails, we produce - // a translation error. - - // Parse 'Attributes' production: - Attributes attrs = parseAttributes(); - reader.skipSpaces(); - - // Parse 'CustomActionEnd' production: - if (reader.matches("/>")) { - if (tagInfo != null) { - new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs, - start, parent, tagInfo, tagHandlerClass); - } else { - new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs, - start, parent, tagFileInfo); - } - return true; - } - - // Now we parse one of 'CustomActionTagDependent', - // 'CustomActionJSPContent', or 'CustomActionScriptlessContent'. - // depending on body-content in TLD. - - // Looking for a body, it still can be empty; but if there is a - // a tag body, its syntax would be dependent on the type of - // body content declared in the TLD. - String bc; - if (tagInfo != null) { - bc = tagInfo.getBodyContent(); - } else { - bc = tagFileInfo.getTagInfo().getBodyContent(); - } - - Node tagNode = null; - if (tagInfo != null) { - tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri, - attrs, start, parent, tagInfo, tagHandlerClass); - } else { - tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri, - attrs, start, parent, tagFileInfo); - } - - parseOptionalBody(tagNode, tagName, bc); - - return true; - } - - /* - * Parse for a template text string until '<' or "${" or "#{" is encountered, - * recognizing escape sequences "\%", "\$", and "\#". - */ - private void parseTemplateText(Node parent) throws JasperException { - - if (!reader.hasMoreInput()) - return; - - CharArrayWriter ttext = new CharArrayWriter(); - // Output the first character - int ch = reader.nextChar(); - if (ch == '\\') { - reader.pushChar(); - } else { - ttext.write(ch); - } - - while (reader.hasMoreInput()) { - ch = reader.nextChar(); - if (ch == '<') { - reader.pushChar(); - break; - } else if (ch == '$' || ch == '#') { - if (!reader.hasMoreInput()) { - ttext.write(ch); - break; - } - if (reader.nextChar() == '{') { - reader.pushChar(); - reader.pushChar(); - break; - } - ttext.write(ch); - reader.pushChar(); - continue; - } else if (ch == '\\') { - if (!reader.hasMoreInput()) { - ttext.write('\\'); - break; - } - char next = (char) reader.peekChar(); - // Looking for \% or \$ or \# - // TODO: only recognize \$ or \# if isELIgnored is false, but since - // it can be set in a page directive, it cannot be determined - // here. Argh! (which is the way it should be since we shouldn't - // convolude multiple steps at once and create confusing parsers...) - if (next == '%' || next == '$' || next == '#') { - ch = reader.nextChar(); - } - } - ttext.write(ch); - } - new Node.TemplateText(ttext.toString(), start, parent); - } - - /* - * XMLTemplateText ::= ( S? '/>' ) | ( S? '>' ( ( Char* - ( Char* ( '<' | - * '${' ) ) ) ( '${' ELExpressionBody )? CDSect? )* ETag ) | - * - */ - private void parseXMLTemplateText(Node parent) throws JasperException { - reader.skipSpaces(); - if (!reader.matches("/>")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:text>"); - } - CharArrayWriter ttext = new CharArrayWriter(); - while (reader.hasMoreInput()) { - int ch = reader.nextChar(); - if (ch == '<') { - // Check for "); - if (stop == null) { - err.jspError(start, "jsp.error.unterminated", "CDATA"); - } - String text = reader.getText(start, stop); - ttext.write(text, 0, text.length()); - } else if (ch == '\\') { - if (!reader.hasMoreInput()) { - ttext.write('\\'); - break; - } - ch = reader.nextChar(); - if (ch != '$' && ch != '#') { - ttext.write('\\'); - } - ttext.write(ch); - } else if (ch == '$' || ch == '#') { - if (!reader.hasMoreInput()) { - ttext.write(ch); - break; - } - if (reader.nextChar() != '{') { - ttext.write(ch); - reader.pushChar(); - continue; - } - // Create a template text node - new Node.TemplateText(ttext.toString(), start, parent); - - // Mark and parse the EL expression and create its node: - start = reader.mark(); - parseELExpression(parent, (char) ch); - - start = reader.mark(); - ttext = new CharArrayWriter(); - } else { - ttext.write(ch); - } - } - - new Node.TemplateText(ttext.toString(), start, parent); - - if (!reader.hasMoreInput()) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:text>"); - } else if (!reader.matchesETagWithoutLessThan("jsp:text")) { - err.jspError(start, "jsp.error.jsptext.badcontent"); - } - } - } - - /* - * AllBody ::= ( '<%--' JSPCommentBody ) | ( '<%@' DirectiveBody ) | ( ' 0) { - // vc: ScriptlessBody - // We must follow the ScriptlessBody production if one of - // our parents is ScriptlessBody. - parseElementsScriptless(parent); - return; - } - - start = reader.mark(); - if (reader.matches("<%--")) { - parseComment(parent); - } else if (reader.matches("<%@")) { - parseDirective(parent); - } else if (reader.matches(" ) | ( ' ) | ( '<%=' ) | ( ' ) | ( '<%' ) | ( ' ) | ( ' ) | ( ' ) | ( '<%=' ) | ( ' ) | ( '<%' ) | ( ' ) | ( ' ) | ( '${' - * ) | ( ' ) | TemplateText - */ - private void parseElementsTemplateText(Node parent) throws JasperException { - start = reader.mark(); - if (reader.matches("<%--")) { - parseComment(parent); - } else if (reader.matches("<%@")) { - parseDirective(parent); - } else if (reader.matches("")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", "<jsp:body"); - } - parseBody(bodyNode, "jsp:body", bodyType); - } - } - - /* - * Parse the body as JSP content. @param tag The name of the tag whose end - * tag would terminate the body @param bodyType One of the TagInfo body - * types - */ - private void parseBody(Node parent, String tag, String bodyType) - throws JasperException { - if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT)) { - parseTagDependentBody(parent, tag); - } else if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) { - if (!reader.matchesETag(tag)) { - err.jspError(start, "jasper.error.emptybodycontent.nonempty", - tag); - } - } else if (bodyType == JAVAX_BODY_CONTENT_PLUGIN) { - // (note the == since we won't recognize JAVAX_* - // from outside this module). - parsePluginTags(parent); - if (!reader.matchesETag(tag)) { - err.jspError(reader.mark(), "jsp.error.unterminated", "<" - + tag); - } - } else if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP) - || bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS) - || (bodyType == JAVAX_BODY_CONTENT_PARAM) - || (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT)) { - while (reader.hasMoreInput()) { - if (reader.matchesETag(tag)) { - return; - } - - // Check for nested jsp:body or jsp:attribute - if (tag.equals("jsp:body") || tag.equals("jsp:attribute")) { - if (reader.matches("")) { - if (!reader.matches(">")) { - err.jspError(start, "jsp.error.unterminated", - "<jsp:attribute"); - } - if (namedAttributeNode.isTrim()) { - reader.skipSpaces(); - } - parseBody(namedAttributeNode, "jsp:attribute", - getAttributeBodyType(parent, attrs.getValue("name"))); - if (namedAttributeNode.isTrim()) { - Node.Nodes subElems = namedAttributeNode.getBody(); - if (subElems != null) { - Node lastNode = subElems.getNode(subElems.size() - 1); - if (lastNode instanceof Node.TemplateText) { - ((Node.TemplateText) lastNode).rtrim(); - } - } - } - } - reader.skipSpaces(); - } while (reader.matches(" from the enclosing node - */ - private String getAttributeBodyType(Node n, String name) { - - if (n instanceof Node.CustomTag) { - TagInfo tagInfo = ((Node.CustomTag) n).getTagInfo(); - TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); - for (int i = 0; i < tldAttrs.length; i++) { - if (name.equals(tldAttrs[i].getName())) { - if (tldAttrs[i].isFragment()) { - return TagInfo.BODY_CONTENT_SCRIPTLESS; - } - if (tldAttrs[i].canBeRequestTime()) { - return TagInfo.BODY_CONTENT_JSP; - } - } - } - if (tagInfo.hasDynamicAttributes()) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.IncludeAction) { - if ("page".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.ForwardAction) { - if ("page".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.SetProperty) { - if ("value".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.UseBean) { - if ("beanName".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.PlugIn) { - if ("width".equals(name) || "height".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.ParamAction) { - if ("value".equals(name)) { - return TagInfo.BODY_CONTENT_JSP; - } - } else if (n instanceof Node.JspElement) { - return TagInfo.BODY_CONTENT_JSP; - } - - return JAVAX_BODY_CONTENT_TEMPLATE_TEXT; - } - - private void parseTagFileDirectives(Node parent) throws JasperException { - reader.setSingleFile(true); - reader.skipUntil("<"); - while (reader.hasMoreInput()) { - start = reader.mark(); - if (reader.matches("%--")) { - parseComment(parent); - } else if (reader.matches("%@")) { - parseDirective(parent); - } else if (reader.matches("jsp:directive.")) { - parseXMLDirective(parent); - } - reader.skipUntil("<"); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.CharArrayWriter; +import java.io.FileNotFoundException; +import java.net.URL; +import java.util.Iterator; +import java.util.List; + +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; + +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; + +/** + * This class implements a parser for a JSP page (non-xml view). JSP page + * grammar is included here for reference. The token '#' that appears in the + * production indicates the current input token location in the production. + * + * @author Kin-man Chung + * @author Shawn Bayern + * @author Mark Roth + */ + +class Parser implements TagConstants { + + private ParserController parserController; + + private JspCompilationContext ctxt; + + private JspReader reader; + + private String currentFile; + + private Mark start; + + private ErrorDispatcher err; + + private int scriptlessCount; + + private boolean isTagFile; + + private boolean directivesOnly; + + private URL jarFileUrl; + + private PageInfo pageInfo; + + // Virtual body content types, to make parsing a little easier. + // These are not accessible from outside the parser. + private static final String JAVAX_BODY_CONTENT_PARAM = "JAVAX_BODY_CONTENT_PARAM"; + + private static final String JAVAX_BODY_CONTENT_PLUGIN = "JAVAX_BODY_CONTENT_PLUGIN"; + + private static final String JAVAX_BODY_CONTENT_TEMPLATE_TEXT = "JAVAX_BODY_CONTENT_TEMPLATE_TEXT"; + + /** + * The constructor + */ + private Parser(ParserController pc, JspReader reader, boolean isTagFile, + boolean directivesOnly, URL jarFileUrl) { + this.parserController = pc; + this.ctxt = pc.getJspCompilationContext(); + this.pageInfo = pc.getCompiler().getPageInfo(); + this.err = pc.getCompiler().getErrorDispatcher(); + this.reader = reader; + this.currentFile = reader.mark().getFile(); + this.scriptlessCount = 0; + this.isTagFile = isTagFile; + this.directivesOnly = directivesOnly; + this.jarFileUrl = jarFileUrl; + start = reader.mark(); + } + + /** + * The main entry for Parser + * + * @param pc + * The ParseController, use for getting other objects in compiler + * and for parsing included pages + * @param reader + * To read the page + * @param parent + * The parent node to this page, null for top level page + * @return list of nodes representing the parsed page + */ + public static Node.Nodes parse(ParserController pc, JspReader reader, + Node parent, boolean isTagFile, boolean directivesOnly, + URL jarFileUrl, String pageEnc, String jspConfigPageEnc, + boolean isDefaultPageEncoding) throws JasperException { + + Parser parser = new Parser(pc, reader, isTagFile, directivesOnly, + jarFileUrl); + + Node.Root root = new Node.Root(reader.mark(), parent, false); + root.setPageEncoding(pageEnc); + root.setJspConfigPageEncoding(jspConfigPageEnc); + root.setIsDefaultPageEncoding(isDefaultPageEncoding); + + if (directivesOnly) { + parser.parseTagFileDirectives(root); + return new Node.Nodes(root); + } + + // For the Top level page, add inlcude-prelude and include-coda + PageInfo pageInfo = pc.getCompiler().getPageInfo(); + if (parent == null) { + parser.addInclude(root, pageInfo.getIncludePrelude()); + } + while (reader.hasMoreInput()) { + parser.parseElements(root); + } + if (parent == null) { + parser.addInclude(root, pageInfo.getIncludeCoda()); + } + + Node.Nodes page = new Node.Nodes(root); + return page; + } + + /** + * Attributes ::= (S Attribute)* S? + */ + Attributes parseAttributes() throws JasperException { + AttributesImpl attrs = new AttributesImpl(); + + reader.skipSpaces(); + while (parseAttribute(attrs)) + reader.skipSpaces(); + + return attrs; + } + + /** + * Parse Attributes for a reader, provided for external use + */ + public static Attributes parseAttributes(ParserController pc, + JspReader reader) throws JasperException { + Parser tmpParser = new Parser(pc, reader, false, false, null); + return tmpParser.parseAttributes(); + } + + /** + * Attribute ::= Name S? Eq S? ( '"<%=' RTAttributeValueDouble | '"' + * AttributeValueDouble | "'<%=" RTAttributeValueSingle | "'" + * AttributeValueSingle } Note: JSP and XML spec does not allow while spaces + * around Eq. It is added to be backward compatible with Tomcat, and with + * other xml parsers. + */ + private boolean parseAttribute(AttributesImpl attrs) throws JasperException { + + // Get the qualified name + String qName = parseName(); + if (qName == null) + return false; + + // Determine prefix and local name components + String localName = qName; + String uri = ""; + int index = qName.indexOf(':'); + if (index != -1) { + String prefix = qName.substring(0, index); + uri = pageInfo.getURI(prefix); + if (uri == null) { + err.jspError(reader.mark(), + "jsp.error.attribute.invalidPrefix", prefix); + } + localName = qName.substring(index + 1); + } + + reader.skipSpaces(); + if (!reader.matches("=")) + err.jspError(reader.mark(), "jsp.error.attribute.noequal"); + + reader.skipSpaces(); + char quote = (char) reader.nextChar(); + if (quote != '\'' && quote != '"') + err.jspError(reader.mark(), "jsp.error.attribute.noquote"); + + String watchString = ""; + if (reader.matches("<%=")) + watchString = "%>"; + watchString = watchString + quote; + + String attrValue = parseAttributeValue(watchString); + attrs.addAttribute(uri, localName, qName, "CDATA", attrValue); + return true; + } + + /** + * Name ::= (Letter | '_' | ':') (Letter | Digit | '.' | '_' | '-' | ':')* + */ + private String parseName() throws JasperException { + char ch = (char) reader.peekChar(); + if (Character.isLetter(ch) || ch == '_' || ch == ':') { + StringBuffer buf = new StringBuffer(); + buf.append(ch); + reader.nextChar(); + ch = (char) reader.peekChar(); + while (Character.isLetter(ch) || Character.isDigit(ch) || ch == '.' + || ch == '_' || ch == '-' || ch == ':') { + buf.append(ch); + reader.nextChar(); + ch = (char) reader.peekChar(); + } + return buf.toString(); + } + return null; + } + + /** + * AttributeValueDouble ::= (QuotedChar - '"')* ('"' | ) + * RTAttributeValueDouble ::= ((QuotedChar - '"')* - ((QuotedChar-'"')'%>"') + * ('%>"' | TRANSLATION_ERROR) + */ + private String parseAttributeValue(String watch) throws JasperException { + Mark start = reader.mark(); + Mark stop = reader.skipUntilIgnoreEsc(watch); + if (stop == null) { + err.jspError(start, "jsp.error.attribute.unterminated", watch); + } + + String ret = parseQuoted(reader.getText(start, stop)); + if (watch.length() == 1) // quote + return ret; + + // putback delimiter '<%=' and '%>', since they are needed if the + // attribute does not allow RTexpression. + return "<%=" + ret + "%>"; + } + + /** + * QuotedChar ::= ''' | '"' | '\\' | '\"' | "\'" | '\>' | '\$' | + * Char + */ + private String parseQuoted(String tx) { + StringBuffer buf = new StringBuffer(); + int size = tx.length(); + int i = 0; + while (i < size) { + char ch = tx.charAt(i); + if (ch == '&') { + if (i + 5 < size && tx.charAt(i + 1) == 'a' + && tx.charAt(i + 2) == 'p' && tx.charAt(i + 3) == 'o' + && tx.charAt(i + 4) == 's' && tx.charAt(i + 5) == ';') { + buf.append('\''); + i += 6; + } else if (i + 5 < size && tx.charAt(i + 1) == 'q' + && tx.charAt(i + 2) == 'u' && tx.charAt(i + 3) == 'o' + && tx.charAt(i + 4) == 't' && tx.charAt(i + 5) == ';') { + buf.append('"'); + i += 6; + } else { + buf.append(ch); + ++i; + } + } else if (ch == '\\' && i + 1 < size) { + ch = tx.charAt(i + 1); + if (ch == '\\' || ch == '\"' || ch == '\'' || ch == '>') { + buf.append(ch); + i += 2; + } else if (ch == '$') { + // Replace "\$" with some special char. XXX hack! + buf.append(Constants.ESC); + i += 2; + } else { + buf.append('\\'); + ++i; + } + } else { + buf.append(ch); + ++i; + } + } + return buf.toString(); + } + + private String parseScriptText(String tx) { + CharArrayWriter cw = new CharArrayWriter(); + int size = tx.length(); + int i = 0; + while (i < size) { + char ch = tx.charAt(i); + if (i + 2 < size && ch == '%' && tx.charAt(i + 1) == '\\' + && tx.charAt(i + 2) == '>') { + cw.write('%'); + cw.write('>'); + i += 3; + } else { + cw.write(ch); + ++i; + } + } + cw.close(); + return cw.toString(); + } + + /* + * Invokes parserController to parse the included page + */ + private void processIncludeDirective(String file, Node parent) + throws JasperException { + if (file == null) { + return; + } + + try { + parserController.parse(file, parent, jarFileUrl); + } catch (FileNotFoundException ex) { + err.jspError(start, "jsp.error.file.not.found", file); + } catch (Exception ex) { + err.jspError(start, ex.getMessage()); + } + } + + /* + * Parses a page directive with the following syntax: PageDirective ::= ( S + * Attribute)* + */ + private void parsePageDirective(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + Node.PageDirective n = new Node.PageDirective(attrs, start, parent); + + /* + * A page directive may contain multiple 'import' attributes, each of + * which consists of a comma-separated list of package names. Store each + * list with the node, where it is parsed. + */ + for (int i = 0; i < attrs.getLength(); i++) { + if ("import".equals(attrs.getQName(i))) { + n.addImport(attrs.getValue(i)); + } + } + } + + /* + * Parses an include directive with the following syntax: IncludeDirective + * ::= ( S Attribute)* + */ + private void parseIncludeDirective(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + + // Included file expanded here + Node includeNode = new Node.IncludeDirective(attrs, start, parent); + processIncludeDirective(attrs.getValue("file"), includeNode); + } + + /** + * Add a list of files. This is used for implementing include-prelude and + * include-coda of jsp-config element in web.xml + */ + private void addInclude(Node parent, List files) throws JasperException { + if (files != null) { + Iterator iter = files.iterator(); + while (iter.hasNext()) { + String file = (String) iter.next(); + AttributesImpl attrs = new AttributesImpl(); + attrs.addAttribute("", "file", "file", "CDATA", file); + + // Create a dummy Include directive node + Node includeNode = new Node.IncludeDirective(attrs, reader + .mark(), parent); + processIncludeDirective(file, includeNode); + } + } + } + + /* + * Parses a taglib directive with the following syntax: Directive ::= ( S + * Attribute)* + */ + private void parseTaglibDirective(Node parent) throws JasperException { + + Attributes attrs = parseAttributes(); + String uri = attrs.getValue("uri"); + String prefix = attrs.getValue("prefix"); + if (prefix != null) { + Mark prevMark = pageInfo.getNonCustomTagPrefix(prefix); + if (prevMark != null) { + err.jspError(reader.mark(), "jsp.error.prefix.use_before_dcl", + prefix, prevMark.getFile(), "" + + prevMark.getLineNumber()); + } + if (uri != null) { + String uriPrev = pageInfo.getURI(prefix); + if (uriPrev != null && !uriPrev.equals(uri)) { + err.jspError(reader.mark(), "jsp.error.prefix.refined", + prefix, uri, uriPrev); + } + if (pageInfo.getTaglib(uri) == null) { + TagLibraryInfoImpl impl = null; + if (ctxt.getOptions().isCaching()) { + impl = (TagLibraryInfoImpl) ctxt.getOptions() + .getCache().get(uri); + } + if (impl == null) { + String[] location = ctxt.getTldLocation(uri); + impl = new TagLibraryInfoImpl(ctxt, parserController, + prefix, uri, location, err); + if (ctxt.getOptions().isCaching()) { + ctxt.getOptions().getCache().put(uri, impl); + } + } + pageInfo.addTaglib(uri, impl); + } + pageInfo.addPrefixMapping(prefix, uri); + } else { + String tagdir = attrs.getValue("tagdir"); + if (tagdir != null) { + String urnTagdir = URN_JSPTAGDIR + tagdir; + if (pageInfo.getTaglib(urnTagdir) == null) { + pageInfo.addTaglib(urnTagdir, + new ImplicitTagLibraryInfo(ctxt, + parserController, prefix, tagdir, err)); + } + pageInfo.addPrefixMapping(prefix, urnTagdir); + } + } + } + + new Node.TaglibDirective(attrs, start, parent); + } + + /* + * Parses a directive with the following syntax: Directive ::= S? ( 'page' + * PageDirective | 'include' IncludeDirective | 'taglib' TagLibDirective) S? + * '%>' + * + * TagDirective ::= S? ('tag' PageDirective | 'include' IncludeDirective | + * 'taglib' TagLibDirective) | 'attribute AttributeDirective | 'variable + * VariableDirective S? '%>' + */ + private void parseDirective(Node parent) throws JasperException { + reader.skipSpaces(); + + String directive = null; + if (reader.matches("page")) { + directive = "<%@ page"; + if (isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.istagfile", + directive); + } + parsePageDirective(parent); + } else if (reader.matches("include")) { + directive = "<%@ include"; + parseIncludeDirective(parent); + } else if (reader.matches("taglib")) { + if (directivesOnly) { + // No need to get the tagLibInfo objects. This alos suppresses + // parsing of any tag files used in this tag file. + return; + } + directive = "<%@ taglib"; + parseTaglibDirective(parent); + } else if (reader.matches("tag")) { + directive = "<%@ tag"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + directive); + } + parseTagDirective(parent); + } else if (reader.matches("attribute")) { + directive = "<%@ attribute"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + directive); + } + parseAttributeDirective(parent); + } else if (reader.matches("variable")) { + directive = "<%@ variable"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + directive); + } + parseVariableDirective(parent); + } else { + err.jspError(reader.mark(), "jsp.error.invalid.directive"); + } + + reader.skipSpaces(); + if (!reader.matches("%>")) { + err.jspError(start, "jsp.error.unterminated", directive); + } + } + + /* + * Parses a directive with the following syntax: + * + * XMLJSPDirectiveBody ::= S? ( ( 'page' PageDirectiveAttrList S? ( '/>' | ( + * '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>' + * S? ETag ) ) | + * + * XMLTagDefDirectiveBody ::= ( ( 'tag' TagDirectiveAttrList S? ( '/>' | ( + * '>' S? ETag ) ) | ( 'include' IncludeDirectiveAttrList S? ( '/>' | ( '>' + * S? ETag ) ) | ( 'attribute' AttributeDirectiveAttrList S? ( '/>' | ( '>' + * S? ETag ) ) | ( 'variable' VariableDirectiveAttrList S? ( '/>' | ( '>' S? + * ETag ) ) ) | + */ + private void parseXMLDirective(Node parent) throws JasperException { + reader.skipSpaces(); + + String eTag = null; + if (reader.matches("page")) { + eTag = "jsp:directive.page"; + if (isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.istagfile", + "<" + eTag); + } + parsePageDirective(parent); + } else if (reader.matches("include")) { + eTag = "jsp:directive.include"; + parseIncludeDirective(parent); + } else if (reader.matches("tag")) { + eTag = "jsp:directive.tag"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + "<" + eTag); + } + parseTagDirective(parent); + } else if (reader.matches("attribute")) { + eTag = "jsp:directive.attribute"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + "<" + eTag); + } + parseAttributeDirective(parent); + } else if (reader.matches("variable")) { + eTag = "jsp:directive.variable"; + if (!isTagFile) { + err.jspError(reader.mark(), "jsp.error.directive.isnottagfile", + "<" + eTag); + } + parseVariableDirective(parent); + } else { + err.jspError(reader.mark(), "jsp.error.invalid.directive"); + } + + reader.skipSpaces(); + if (reader.matches(">")) { + reader.skipSpaces(); + if (!reader.matchesETag(eTag)) { + err.jspError(start, "jsp.error.unterminated", "<" + eTag); + } + } else if (!reader.matches("/>")) { + err.jspError(start, "jsp.error.unterminated", "<" + eTag); + } + } + + /* + * Parses a tag directive with the following syntax: PageDirective ::= ( S + * Attribute)* + */ + private void parseTagDirective(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + Node.TagDirective n = new Node.TagDirective(attrs, start, parent); + + /* + * A page directive may contain multiple 'import' attributes, each of + * which consists of a comma-separated list of package names. Store each + * list with the node, where it is parsed. + */ + for (int i = 0; i < attrs.getLength(); i++) { + if ("import".equals(attrs.getQName(i))) { + n.addImport(attrs.getValue(i)); + } + } + } + + /* + * Parses a attribute directive with the following syntax: + * AttributeDirective ::= ( S Attribute)* + */ + private void parseAttributeDirective(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + Node.AttributeDirective n = new Node.AttributeDirective(attrs, start, + parent); + } + + /* + * Parses a variable directive with the following syntax: PageDirective ::= ( + * S Attribute)* + */ + private void parseVariableDirective(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + Node.VariableDirective n = new Node.VariableDirective(attrs, start, + parent); + } + + /* + * JSPCommentBody ::= (Char* - (Char* '--%>')) '--%>' + */ + private void parseComment(Node parent) throws JasperException { + start = reader.mark(); + Mark stop = reader.skipUntil("--%>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "<%--"); + } + + new Node.Comment(reader.getText(start, stop), start, parent); + } + + /* + * DeclarationBody ::= (Char* - (char* '%>')) '%>' + */ + private void parseDeclaration(Node parent) throws JasperException { + start = reader.mark(); + Mark stop = reader.skipUntil("%>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "<%!"); + } + + new Node.Declaration(parseScriptText(reader.getText(start, stop)), + start, parent); + } + + /* + * XMLDeclarationBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) + * CDSect?)* ETag | CDSect ::= CDStart CData CDEnd + * CDStart ::= '' Char*)) CDEnd + * ::= ']]>' + */ + private void parseXMLDeclaration(Node parent) throws JasperException { + reader.skipSpaces(); + if (!reader.matches("/>")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:declaration>"); + } + Mark stop; + String text; + while (true) { + start = reader.mark(); + stop = reader.skipUntil("<"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:declaration>"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Declaration(text, start, parent); + if (reader.matches("![CDATA[")) { + start = reader.mark(); + stop = reader.skipUntil("]]>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "CDATA"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Declaration(text, start, parent); + } else { + break; + } + } + + if (!reader.matchesETagWithoutLessThan("jsp:declaration")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:declaration>"); + } + } + } + + /* + * ExpressionBody ::= (Char* - (char* '%>')) '%>' + */ + private void parseExpression(Node parent) throws JasperException { + start = reader.mark(); + Mark stop = reader.skipUntil("%>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "<%="); + } + + new Node.Expression(parseScriptText(reader.getText(start, stop)), + start, parent); + } + + /* + * XMLExpressionBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) + * CDSect?)* ETag ) | + */ + private void parseXMLExpression(Node parent) throws JasperException { + reader.skipSpaces(); + if (!reader.matches("/>")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:expression>"); + } + Mark stop; + String text; + while (true) { + start = reader.mark(); + stop = reader.skipUntil("<"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:expression>"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Expression(text, start, parent); + if (reader.matches("![CDATA[")) { + start = reader.mark(); + stop = reader.skipUntil("]]>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "CDATA"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Expression(text, start, parent); + } else { + break; + } + } + if (!reader.matchesETagWithoutLessThan("jsp:expression")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:expression>"); + } + } + } + + /* + * ELExpressionBody (following "${" to first unquoted "}") // XXX add formal + * production and confirm implementation against it, // once it's decided + */ + private void parseELExpression(Node parent, char type) throws JasperException { + start = reader.mark(); + Mark last = null; + boolean singleQuoted = false, doubleQuoted = false; + int currentChar; + do { + // XXX could move this logic to JspReader + last = reader.mark(); // XXX somewhat wasteful + currentChar = reader.nextChar(); + if (currentChar == '\\' && (singleQuoted || doubleQuoted)) { + // skip character following '\' within quotes + reader.nextChar(); + currentChar = reader.nextChar(); + } + if (currentChar == -1) + err.jspError(start, "jsp.error.unterminated", type + "{"); + if (currentChar == '"') + doubleQuoted = !doubleQuoted; + if (currentChar == '\'') + singleQuoted = !singleQuoted; + } while (currentChar != '}' || (singleQuoted || doubleQuoted)); + + new Node.ELExpression(type, reader.getText(start, last), start, parent); + } + + /* + * ScriptletBody ::= (Char* - (char* '%>')) '%>' + */ + private void parseScriptlet(Node parent) throws JasperException { + start = reader.mark(); + Mark stop = reader.skipUntil("%>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "<%"); + } + + new Node.Scriptlet(parseScriptText(reader.getText(start, stop)), start, + parent); + } + + /* + * XMLScriptletBody ::= ( S? '/>' ) | ( S? '>' (Char* - (char* '<')) + * CDSect?)* ETag ) | + */ + private void parseXMLScriptlet(Node parent) throws JasperException { + reader.skipSpaces(); + if (!reader.matches("/>")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:scriptlet>"); + } + Mark stop; + String text; + while (true) { + start = reader.mark(); + stop = reader.skipUntil("<"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:scriptlet>"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Scriptlet(text, start, parent); + if (reader.matches("![CDATA[")) { + start = reader.mark(); + stop = reader.skipUntil("]]>"); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "CDATA"); + } + text = parseScriptText(reader.getText(start, stop)); + new Node.Scriptlet(text, start, parent); + } else { + break; + } + } + + if (!reader.matchesETagWithoutLessThan("jsp:scriptlet")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:scriptlet>"); + } + } + } + + /** + * Param ::= '' S? ( ' ) S? ETag ) | ( '>' S? Param* ETag ) + * + * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '' Param* '' + */ + private void parseInclude(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node includeNode = new Node.IncludeAction(attrs, start, parent); + + parseOptionalBody(includeNode, "jsp:include", JAVAX_BODY_CONTENT_PARAM); + } + + /* + * For Forward: StdActionContent ::= Attributes ParamBody + */ + private void parseForward(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node forwardNode = new Node.ForwardAction(attrs, start, parent); + + parseOptionalBody(forwardNode, "jsp:forward", JAVAX_BODY_CONTENT_PARAM); + } + + private void parseInvoke(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node invokeNode = new Node.InvokeAction(attrs, start, parent); + + parseEmptyBody(invokeNode, "jsp:invoke"); + } + + private void parseDoBody(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node doBodyNode = new Node.DoBodyAction(attrs, start, parent); + + parseEmptyBody(doBodyNode, "jsp:doBody"); + } + + private void parseElement(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node elementNode = new Node.JspElement(attrs, start, parent); + + parseOptionalBody(elementNode, "jsp:element", TagInfo.BODY_CONTENT_JSP); + } + + /* + * For GetProperty: StdActionContent ::= Attributes EmptyBody + */ + private void parseGetProperty(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node getPropertyNode = new Node.GetProperty(attrs, start, parent); + + parseOptionalBody(getPropertyNode, "jsp:getProperty", + TagInfo.BODY_CONTENT_EMPTY); + } + + /* + * For SetProperty: StdActionContent ::= Attributes EmptyBody + */ + private void parseSetProperty(Node parent) throws JasperException { + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + Node setPropertyNode = new Node.SetProperty(attrs, start, parent); + + parseOptionalBody(setPropertyNode, "jsp:setProperty", + TagInfo.BODY_CONTENT_EMPTY); + } + + /* + * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? '")) { + // Done + } else if (reader.matches(">")) { + if (reader.matchesETag(tag)) { + // Done + } else if (reader.matchesOptionalSpacesFollowedBy("' ETag ) | ( '>' S? '' Body ETag ) + * + * ScriptlessActionBody ::= JspAttributeAndBody | ( '>' ScriptlessBody ETag ) + * + * TagDependentActionBody ::= JspAttributeAndBody | ( '>' TagDependentBody + * ETag ) + * + */ + private void parseOptionalBody(Node parent, String tag, String bodyType) + throws JasperException { + if (reader.matches("/>")) { + // EmptyBody + return; + } + + if (!reader.matches(">")) { + err.jspError(reader.mark(), "jsp.error.unterminated", "<" + tag); + } + + if (reader.matchesETag(tag)) { + // EmptyBody + return; + } + + if (!parseJspAttributeAndBody(parent, tag, bodyType)) { + // Must be ( '>' # Body ETag ) + parseBody(parent, tag, bodyType); + } + } + + /** + * Attempts to parse 'JspAttributeAndBody' production. Returns true if it + * matched, or false if not. Assumes EmptyBody is okay as well. + * + * JspAttributeAndBody ::= ( '>' # S? ( ' ) S? ETag ) + */ + private boolean parseJspAttributeAndBody(Node parent, String tag, + String bodyType) throws JasperException { + boolean result = false; + + if (reader.matchesOptionalSpacesFollowedBy(" elements: + parseNamedAttributes(parent); + + result = true; + } + + if (reader.matchesOptionalSpacesFollowedBy(" but something other than + // or the end tag, translation error. + err.jspError(reader.mark(), "jsp.error.jspbody.required", "<" + + tag); + } + + return result; + } + + /* + * Params ::= `>' S? ( ( `' ( ( S? Param+ S? `' ) | + * ) ) | Param+ ) '' + */ + private void parseJspParams(Node parent) throws JasperException { + Node jspParamsNode = new Node.ParamsAction(start, parent); + parseOptionalBody(jspParamsNode, "jsp:params", JAVAX_BODY_CONTENT_PARAM); + } + + /* + * Fallback ::= '/>' | ( `>' S? `' ( ( S? ( Char* - ( Char* `' ) ) `' + * S? ) | ) `' ) | ( '>' ( Char* - ( + * Char* '' ) ) '' ) + */ + private void parseFallBack(Node parent) throws JasperException { + Node fallBackNode = new Node.FallBackAction(start, parent); + parseOptionalBody(fallBackNode, "jsp:fallback", + JAVAX_BODY_CONTENT_TEMPLATE_TEXT); + } + + /* + * For Plugin: StdActionContent ::= Attributes PluginBody + * + * PluginBody ::= EmptyBody | ( '>' S? ( ' ) S? ETag ) | ( '>' S? PluginTags + * ETag ) + * + * EmptyBody ::= '/>' | ( '>' ETag ) | ( '>' S? ' + * + * Attributes ::= ( S Attribute )* S? + * + * CustomActionEnd ::= CustomActionTagDependent | CustomActionJSPContent | + * CustomActionScriptlessContent + * + * CustomActionTagDependent ::= TagDependentOptionalBody + * + * CustomActionJSPContent ::= OptionalBody + * + * CustomActionScriptlessContent ::= ScriptlessOptionalBody + */ + private boolean parseCustomTag(Node parent) throws JasperException { + + if (reader.peekChar() != '<') { + return false; + } + + // Parse 'CustomAction' production (tag prefix and custom action name) + reader.nextChar(); // skip '<' + String tagName = reader.parseToken(false); + int i = tagName.indexOf(':'); + if (i == -1) { + reader.reset(start); + return false; + } + + String prefix = tagName.substring(0, i); + String shortTagName = tagName.substring(i + 1); + + // Check if this is a user-defined tag. + String uri = pageInfo.getURI(prefix); + if (uri == null) { + reader.reset(start); + // Remember the prefix for later error checking + pageInfo.putNonCustomTagPrefix(prefix, reader.mark()); + return false; + } + + TagLibraryInfo tagLibInfo = pageInfo.getTaglib(uri); + TagInfo tagInfo = tagLibInfo.getTag(shortTagName); + TagFileInfo tagFileInfo = tagLibInfo.getTagFile(shortTagName); + if (tagInfo == null && tagFileInfo == null) { + err.jspError(start, "jsp.error.bad_tag", shortTagName, prefix); + } + Class tagHandlerClass = null; + if (tagInfo != null) { + // Must be a classic tag, load it here. + // tag files will be loaded later, in TagFileProcessor + String handlerClassName = tagInfo.getTagClassName(); + try { + tagHandlerClass = ctxt.getClassLoader().loadClass( + handlerClassName); + } catch (Exception e) { + err.jspError(start, "jsp.error.loadclass.taghandler", + handlerClassName, tagName); + } + } + + // Parse 'CustomActionBody' production: + // At this point we are committed - if anything fails, we produce + // a translation error. + + // Parse 'Attributes' production: + Attributes attrs = parseAttributes(); + reader.skipSpaces(); + + // Parse 'CustomActionEnd' production: + if (reader.matches("/>")) { + if (tagInfo != null) { + new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs, + start, parent, tagInfo, tagHandlerClass); + } else { + new Node.CustomTag(tagName, prefix, shortTagName, uri, attrs, + start, parent, tagFileInfo); + } + return true; + } + + // Now we parse one of 'CustomActionTagDependent', + // 'CustomActionJSPContent', or 'CustomActionScriptlessContent'. + // depending on body-content in TLD. + + // Looking for a body, it still can be empty; but if there is a + // a tag body, its syntax would be dependent on the type of + // body content declared in the TLD. + String bc; + if (tagInfo != null) { + bc = tagInfo.getBodyContent(); + } else { + bc = tagFileInfo.getTagInfo().getBodyContent(); + } + + Node tagNode = null; + if (tagInfo != null) { + tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri, + attrs, start, parent, tagInfo, tagHandlerClass); + } else { + tagNode = new Node.CustomTag(tagName, prefix, shortTagName, uri, + attrs, start, parent, tagFileInfo); + } + + parseOptionalBody(tagNode, tagName, bc); + + return true; + } + + /* + * Parse for a template text string until '<' or "${" or "#{" is encountered, + * recognizing escape sequences "\%", "\$", and "\#". + */ + private void parseTemplateText(Node parent) throws JasperException { + + if (!reader.hasMoreInput()) + return; + + CharArrayWriter ttext = new CharArrayWriter(); + // Output the first character + int ch = reader.nextChar(); + if (ch == '\\') { + reader.pushChar(); + } else { + ttext.write(ch); + } + + while (reader.hasMoreInput()) { + ch = reader.nextChar(); + if (ch == '<') { + reader.pushChar(); + break; + } else if (ch == '$' || ch == '#') { + if (!reader.hasMoreInput()) { + ttext.write(ch); + break; + } + if (reader.nextChar() == '{') { + reader.pushChar(); + reader.pushChar(); + break; + } + ttext.write(ch); + reader.pushChar(); + continue; + } else if (ch == '\\') { + if (!reader.hasMoreInput()) { + ttext.write('\\'); + break; + } + char next = (char) reader.peekChar(); + // Looking for \% or \$ or \# + // TODO: only recognize \$ or \# if isELIgnored is false, but since + // it can be set in a page directive, it cannot be determined + // here. Argh! (which is the way it should be since we shouldn't + // convolude multiple steps at once and create confusing parsers...) + if (next == '%' || next == '$' || next == '#') { + ch = reader.nextChar(); + } + } + ttext.write(ch); + } + new Node.TemplateText(ttext.toString(), start, parent); + } + + /* + * XMLTemplateText ::= ( S? '/>' ) | ( S? '>' ( ( Char* - ( Char* ( '<' | + * '${' ) ) ) ( '${' ELExpressionBody )? CDSect? )* ETag ) | + * + */ + private void parseXMLTemplateText(Node parent) throws JasperException { + reader.skipSpaces(); + if (!reader.matches("/>")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:text>"); + } + CharArrayWriter ttext = new CharArrayWriter(); + while (reader.hasMoreInput()) { + int ch = reader.nextChar(); + if (ch == '<') { + // Check for "); + if (stop == null) { + err.jspError(start, "jsp.error.unterminated", "CDATA"); + } + String text = reader.getText(start, stop); + ttext.write(text, 0, text.length()); + } else if (ch == '\\') { + if (!reader.hasMoreInput()) { + ttext.write('\\'); + break; + } + ch = reader.nextChar(); + if (ch != '$' && ch != '#') { + ttext.write('\\'); + } + ttext.write(ch); + } else if (ch == '$' || ch == '#') { + if (!reader.hasMoreInput()) { + ttext.write(ch); + break; + } + if (reader.nextChar() != '{') { + ttext.write(ch); + reader.pushChar(); + continue; + } + // Create a template text node + new Node.TemplateText(ttext.toString(), start, parent); + + // Mark and parse the EL expression and create its node: + start = reader.mark(); + parseELExpression(parent, (char) ch); + + start = reader.mark(); + ttext = new CharArrayWriter(); + } else { + ttext.write(ch); + } + } + + new Node.TemplateText(ttext.toString(), start, parent); + + if (!reader.hasMoreInput()) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:text>"); + } else if (!reader.matchesETagWithoutLessThan("jsp:text")) { + err.jspError(start, "jsp.error.jsptext.badcontent"); + } + } + } + + /* + * AllBody ::= ( '<%--' JSPCommentBody ) | ( '<%@' DirectiveBody ) | ( ' 0) { + // vc: ScriptlessBody + // We must follow the ScriptlessBody production if one of + // our parents is ScriptlessBody. + parseElementsScriptless(parent); + return; + } + + start = reader.mark(); + if (reader.matches("<%--")) { + parseComment(parent); + } else if (reader.matches("<%@")) { + parseDirective(parent); + } else if (reader.matches(" ) | ( ' ) | ( '<%=' ) | ( ' ) | ( '<%' ) | ( ' ) | ( ' ) | ( ' ) | ( '<%=' ) | ( ' ) | ( '<%' ) | ( ' ) | ( ' ) | ( '${' + * ) | ( ' ) | TemplateText + */ + private void parseElementsTemplateText(Node parent) throws JasperException { + start = reader.mark(); + if (reader.matches("<%--")) { + parseComment(parent); + } else if (reader.matches("<%@")) { + parseDirective(parent); + } else if (reader.matches("")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", "<jsp:body"); + } + parseBody(bodyNode, "jsp:body", bodyType); + } + } + + /* + * Parse the body as JSP content. @param tag The name of the tag whose end + * tag would terminate the body @param bodyType One of the TagInfo body + * types + */ + private void parseBody(Node parent, String tag, String bodyType) + throws JasperException { + if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT)) { + parseTagDependentBody(parent, tag); + } else if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY)) { + if (!reader.matchesETag(tag)) { + err.jspError(start, "jasper.error.emptybodycontent.nonempty", + tag); + } + } else if (bodyType == JAVAX_BODY_CONTENT_PLUGIN) { + // (note the == since we won't recognize JAVAX_* + // from outside this module). + parsePluginTags(parent); + if (!reader.matchesETag(tag)) { + err.jspError(reader.mark(), "jsp.error.unterminated", "<" + + tag); + } + } else if (bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_JSP) + || bodyType.equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS) + || (bodyType == JAVAX_BODY_CONTENT_PARAM) + || (bodyType == JAVAX_BODY_CONTENT_TEMPLATE_TEXT)) { + while (reader.hasMoreInput()) { + if (reader.matchesETag(tag)) { + return; + } + + // Check for nested jsp:body or jsp:attribute + if (tag.equals("jsp:body") || tag.equals("jsp:attribute")) { + if (reader.matches("")) { + if (!reader.matches(">")) { + err.jspError(start, "jsp.error.unterminated", + "<jsp:attribute"); + } + if (namedAttributeNode.isTrim()) { + reader.skipSpaces(); + } + parseBody(namedAttributeNode, "jsp:attribute", + getAttributeBodyType(parent, attrs.getValue("name"))); + if (namedAttributeNode.isTrim()) { + Node.Nodes subElems = namedAttributeNode.getBody(); + if (subElems != null) { + Node lastNode = subElems.getNode(subElems.size() - 1); + if (lastNode instanceof Node.TemplateText) { + ((Node.TemplateText) lastNode).rtrim(); + } + } + } + } + reader.skipSpaces(); + } while (reader.matches(" from the enclosing node + */ + private String getAttributeBodyType(Node n, String name) { + + if (n instanceof Node.CustomTag) { + TagInfo tagInfo = ((Node.CustomTag) n).getTagInfo(); + TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); + for (int i = 0; i < tldAttrs.length; i++) { + if (name.equals(tldAttrs[i].getName())) { + if (tldAttrs[i].isFragment()) { + return TagInfo.BODY_CONTENT_SCRIPTLESS; + } + if (tldAttrs[i].canBeRequestTime()) { + return TagInfo.BODY_CONTENT_JSP; + } + } + } + if (tagInfo.hasDynamicAttributes()) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.IncludeAction) { + if ("page".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.ForwardAction) { + if ("page".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.SetProperty) { + if ("value".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.UseBean) { + if ("beanName".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.PlugIn) { + if ("width".equals(name) || "height".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.ParamAction) { + if ("value".equals(name)) { + return TagInfo.BODY_CONTENT_JSP; + } + } else if (n instanceof Node.JspElement) { + return TagInfo.BODY_CONTENT_JSP; + } + + return JAVAX_BODY_CONTENT_TEMPLATE_TEXT; + } + + private void parseTagFileDirectives(Node parent) throws JasperException { + reader.setSingleFile(true); + reader.skipUntil("<"); + while (reader.hasMoreInput()) { + start = reader.mark(); + if (reader.matches("%--")) { + parseComment(parent); + } else if (reader.matches("%@")) { + parseDirective(parent); + } else if (reader.matches("jsp:directive.")) { + parseXMLDirective(parent); + } + reader.skipUntil("<"); + } + } +} diff --git a/java/org/apache/jasper/compiler/ParserController.java b/java/org/apache/jasper/compiler/ParserController.java index eb29f247a..d84e8ccdb 100644 --- a/java/org/apache/jasper/compiler/ParserController.java +++ b/java/org/apache/jasper/compiler/ParserController.java @@ -1,582 +1,582 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.JarURLConnection; -import java.net.URL; -import java.util.Stack; -import java.util.jar.JarFile; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.xmlparser.XMLEncodingDetector; -import org.xml.sax.Attributes; - -/** - * Controller for the parsing of a JSP page. - *

        - * The same ParserController instance is used for a JSP page and any JSP - * segments included by it (via an include directive), where each segment may - * be provided in standard or XML syntax. This class selects and invokes the - * appropriate parser for the JSP page and its included segments. - * - * @author Pierre Delisle - * @author Jan Luehe - */ -class ParserController implements TagConstants { - - private static final String CHARSET = "charset="; - - private JspCompilationContext ctxt; - private Compiler compiler; - private ErrorDispatcher err; - - /* - * Indicates the syntax (XML or standard) of the file being processed - */ - private boolean isXml; - - /* - * A stack to keep track of the 'current base directory' - * for include directives that refer to relative paths. - */ - private Stack baseDirStack = new Stack(); - - private boolean isEncodingSpecifiedInProlog; - - private String sourceEnc; - - private boolean isDefaultPageEncoding; - private boolean isTagFile; - private boolean directiveOnly; - - /* - * Constructor - */ - public ParserController(JspCompilationContext ctxt, Compiler compiler) { - this.ctxt = ctxt; - this.compiler = compiler; - this.err = compiler.getErrorDispatcher(); - } - - public JspCompilationContext getJspCompilationContext () { - return ctxt; - } - - public Compiler getCompiler () { - return compiler; - } - - /** - * Parses a JSP page or tag file. This is invoked by the compiler. - * - * @param inFileName The path to the JSP page or tag file to be parsed. - */ - public Node.Nodes parse(String inFileName) - throws FileNotFoundException, JasperException, IOException { - // If we're parsing a packaged tag file or a resource included by it - // (using an include directive), ctxt.getTagFileJar() returns the - // JAR file from which to read the tag file or included resource, - // respectively. - isTagFile = ctxt.isTagFile(); - directiveOnly = false; - return doParse(inFileName, null, ctxt.getTagFileJarUrl()); - } - - /** - * Processes an include directive with the given path. - * - * @param inFileName The path to the resource to be included. - * @param parent The parent node of the include directive. - * @param jarFile The JAR file from which to read the included resource, - * or null of the included resource is to be read from the filesystem - */ - public Node.Nodes parse(String inFileName, Node parent, - URL jarFileUrl) - throws FileNotFoundException, JasperException, IOException { - // For files that are statically included, isTagfile and directiveOnly - // remain unchanged. - return doParse(inFileName, parent, jarFileUrl); - } - - /** - * Extracts tag file directive information from the tag file with the - * given name. - * - * This is invoked by the compiler - * - * @param inFileName The name of the tag file to be parsed. - */ - public Node.Nodes parseTagFileDirectives(String inFileName) - throws FileNotFoundException, JasperException, IOException { - boolean isTagFileSave = isTagFile; - boolean directiveOnlySave = directiveOnly; - isTagFile = true; - directiveOnly = true; - Node.Nodes page = doParse(inFileName, null, - (URL) ctxt.getTagFileJarUrls().get(inFileName)); - directiveOnly = directiveOnlySave; - isTagFile = isTagFileSave; - return page; - } - - /** - * Parses the JSP page or tag file with the given path name. - * - * @param inFileName The name of the JSP page or tag file to be parsed. - * @param parent The parent node (non-null when processing an include - * directive) - * @param isTagFile true if file to be parsed is tag file, and false if it - * is a regular JSP page - * @param directivesOnly true if the file to be parsed is a tag file and - * we are only interested in the directives needed for constructing a - * TagFileInfo. - * @param jarFile The JAR file from which to read the JSP page or tag file, - * or null if the JSP page or tag file is to be read from the filesystem - */ - private Node.Nodes doParse(String inFileName, - Node parent, - URL jarFileUrl) - throws FileNotFoundException, JasperException, IOException { - - Node.Nodes parsedPage = null; - isEncodingSpecifiedInProlog = false; - isDefaultPageEncoding = false; - - JarFile jarFile = getJarFile(jarFileUrl); - String absFileName = resolveFileName(inFileName); - String jspConfigPageEnc = getJspConfigPageEncoding(absFileName); - - // Figure out what type of JSP document and encoding type we are - // dealing with - determineSyntaxAndEncoding(absFileName, jarFile, jspConfigPageEnc); - - if (parent != null) { - // Included resource, add to dependent list - compiler.getPageInfo().addDependant(absFileName); - } - - if (isXml && isEncodingSpecifiedInProlog) { - /* - * Make sure the encoding explicitly specified in the XML - * prolog (if any) matches that in the JSP config element - * (if any), treating "UTF-16", "UTF-16BE", and "UTF-16LE" as - * identical. - */ - if (jspConfigPageEnc != null && !jspConfigPageEnc.equals(sourceEnc) - && (!jspConfigPageEnc.startsWith("UTF-16") - || !sourceEnc.startsWith("UTF-16"))) { - err.jspError("jsp.error.prolog_config_encoding_mismatch", - sourceEnc, jspConfigPageEnc); - } - } - - // Dispatch to the appropriate parser - if (isXml) { - // JSP document (XML syntax) - // InputStream for jspx page is created and properly closed in - // JspDocumentParser. - parsedPage = JspDocumentParser.parse(this, absFileName, - jarFile, parent, - isTagFile, directiveOnly, - sourceEnc, - jspConfigPageEnc, - isEncodingSpecifiedInProlog); - } else { - // Standard syntax - InputStreamReader inStreamReader = null; - try { - inStreamReader = JspUtil.getReader(absFileName, sourceEnc, - jarFile, ctxt, err); - JspReader jspReader = new JspReader(ctxt, absFileName, - sourceEnc, inStreamReader, - err); - parsedPage = Parser.parse(this, jspReader, parent, isTagFile, - directiveOnly, jarFileUrl, - sourceEnc, jspConfigPageEnc, - isDefaultPageEncoding); - } finally { - if (inStreamReader != null) { - try { - inStreamReader.close(); - } catch (Exception any) { - } - } - } - } - - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) {} - } - - baseDirStack.pop(); - - return parsedPage; - } - - /* - * Checks to see if the given URI is matched by a URL pattern specified in - * a jsp-property-group in web.xml, and if so, returns the value of the - * element. - * - * @param absFileName The URI to match - * - * @return The value of the attribute of the - * jsp-property-group with matching URL pattern - */ - private String getJspConfigPageEncoding(String absFileName) - throws JasperException { - - JspConfig jspConfig = ctxt.getOptions().getJspConfig(); - JspConfig.JspProperty jspProperty - = jspConfig.findJspProperty(absFileName); - return jspProperty.getPageEncoding(); - } - - /** - * Determines the syntax (standard or XML) and page encoding properties - * for the given file, and stores them in the 'isXml' and 'sourceEnc' - * instance variables, respectively. - */ - private void determineSyntaxAndEncoding(String absFileName, - JarFile jarFile, - String jspConfigPageEnc) - throws JasperException, IOException { - - isXml = false; - - /* - * 'true' if the syntax (XML or standard) of the file is given - * from external information: either via a JSP configuration element, - * the ".jspx" suffix, or the enclosing file (for included resources) - */ - boolean isExternal = false; - - /* - * Indicates whether we need to revert from temporary usage of - * "ISO-8859-1" back to "UTF-8" - */ - boolean revert = false; - - JspConfig jspConfig = ctxt.getOptions().getJspConfig(); - JspConfig.JspProperty jspProperty = jspConfig.findJspProperty( - absFileName); - if (jspProperty.isXml() != null) { - // If is specified in a , it is used. - isXml = JspUtil.booleanValue(jspProperty.isXml()); - isExternal = true; - } else if (absFileName.endsWith(".jspx") - || absFileName.endsWith(".tagx")) { - isXml = true; - isExternal = true; - } - - if (isExternal && !isXml) { - // JSP (standard) syntax. Use encoding specified in jsp-config - // if provided. - sourceEnc = jspConfigPageEnc; - if (sourceEnc != null) { - return; - } - // We don't know the encoding - sourceEnc = "ISO-8859-1"; - } else { - // XML syntax or unknown, (auto)detect encoding ... - Object[] ret = XMLEncodingDetector.getEncoding(absFileName, - jarFile, ctxt, err); - sourceEnc = (String) ret[0]; - if (((Boolean) ret[1]).booleanValue()) { - isEncodingSpecifiedInProlog = true; - } - - if (!isXml && sourceEnc.equals("UTF-8")) { - /* - * We don't know if we're dealing with XML or standard syntax. - * Therefore, we need to check to see if the page contains - * a element. - * - * We need to be careful, because the page may be encoded in - * ISO-8859-1 (or something entirely different), and may - * contain byte sequences that will cause a UTF-8 converter to - * throw exceptions. - * - * It is safe to use a source encoding of ISO-8859-1 in this - * case, as there are no invalid byte sequences in ISO-8859-1, - * and the byte/character sequences we're looking for (i.e., - * ) are identical in either encoding (both UTF-8 - * and ISO-8859-1 are extensions of ASCII). - */ - sourceEnc = "ISO-8859-1"; - revert = true; - } - } - - if (isXml) { - // (This implies 'isExternal' is TRUE.) - // We know we're dealing with a JSP document (via JSP config or - // ".jspx" suffix), so we're done. - return; - } - - /* - * At this point, 'isExternal' or 'isXml' is FALSE. - * Search for jsp:root action, in order to determine if we're dealing - * with XML or standard syntax (unless we already know what we're - * dealing with, i.e., when 'isExternal' is TRUE and 'isXml' is FALSE). - * No check for XML prolog, since nothing prevents a page from - * outputting XML and still using JSP syntax (in this case, the - * XML prolog is treated as template text). - */ - JspReader jspReader = null; - try { - jspReader = new JspReader(ctxt, absFileName, sourceEnc, jarFile, - err); - } catch (FileNotFoundException ex) { - throw new JasperException(ex); - } - jspReader.setSingleFile(true); - Mark startMark = jspReader.mark(); - if (!isExternal) { - jspReader.reset(startMark); - if (hasJspRoot(jspReader)) { - isXml = true; - if (revert) sourceEnc = "UTF-8"; - return; - } else { - isXml = false; - } - } - - /* - * At this point, we know we're dealing with JSP syntax. - * If an XML prolog is provided, it's treated as template text. - * Determine the page encoding from the page directive, unless it's - * specified via JSP config. - */ - sourceEnc = jspConfigPageEnc; - if (sourceEnc == null) { - sourceEnc = getPageEncodingForJspSyntax(jspReader, startMark); - if (sourceEnc == null) { - // Default to "ISO-8859-1" per JSP spec - sourceEnc = "ISO-8859-1"; - isDefaultPageEncoding = true; - } - } - } - - /* - * Determines page source encoding for page or tag file in JSP syntax, - * by reading (in this order) the value of the 'pageEncoding' page - * directive attribute, or the charset value of the 'contentType' page - * directive attribute. - * - * @return The page encoding, or null if not found - */ - private String getPageEncodingForJspSyntax(JspReader jspReader, - Mark startMark) - throws JasperException { - - String encoding = null; - String saveEncoding = null; - - jspReader.reset(startMark); - - /* - * Determine page encoding from directive of the form <%@ page %>, - * <%@ tag %>, or . - */ - while (true) { - if (jspReader.skipUntil("<") == null) { - break; - } - // If this is a comment, skip until its end - if (jspReader.matches("%--")) { - if (jspReader.skipUntil("--%>") == null) { - // error will be caught in Parser - break; - } - continue; - } - boolean isDirective = jspReader.matches("%@"); - if (isDirective) { - jspReader.skipSpaces(); - } - else { - isDirective = jspReader.matches("jsp:directive."); - } - if (!isDirective) { - continue; - } - - // compare for "tag ", so we don't match "taglib" - if (jspReader.matches("tag ") || jspReader.matches("page")) { - - jspReader.skipSpaces(); - Attributes attrs = Parser.parseAttributes(this, jspReader); - encoding = getPageEncodingFromDirective(attrs, "pageEncoding"); - if (encoding != null) { - break; - } - encoding = getPageEncodingFromDirective(attrs, "contentType"); - if (encoding != null) { - saveEncoding = encoding; - } - } - } - - if (encoding == null) { - encoding = saveEncoding; - } - - return encoding; - } - - /* - * Scans the given attributes for the attribute with the given name, - * which is either 'pageEncoding' or 'contentType', and returns the - * specified page encoding. - * - * In the case of 'contentType', the page encoding is taken from the - * content type's 'charset' component. - * - * @param attrs The page directive attributes - * @param attrName The name of the attribute to search for (either - * 'pageEncoding' or 'contentType') - * - * @return The page encoding, or null - */ - private String getPageEncodingFromDirective(Attributes attrs, - String attrName) { - String value = attrs.getValue(attrName); - if (attrName.equals("pageEncoding")) { - return value; - } - - // attrName = contentType - String contentType = value; - String encoding = null; - if (contentType != null) { - int loc = contentType.indexOf(CHARSET); - if (loc != -1) { - encoding = contentType.substring(loc + CHARSET.length()); - } - } - - return encoding; - } - - /* - * Resolve the name of the file and update baseDirStack() to keep track of - * the current base directory for each included file. - * The 'root' file is always an 'absolute' path, so no need to put an - * initial value in the baseDirStack. - */ - private String resolveFileName(String inFileName) { - String fileName = inFileName.replace('\\', '/'); - boolean isAbsolute = fileName.startsWith("/"); - fileName = isAbsolute ? fileName - : (String) baseDirStack.peek() + fileName; - String baseDir = - fileName.substring(0, fileName.lastIndexOf("/") + 1); - baseDirStack.push(baseDir); - return fileName; - } - - /* - * Checks to see if the given page contains, as its first element, a - * element whose prefix is bound to the JSP namespace, as in: - * - * - * ... - * - * - * @param reader The reader for this page - * - * @return true if this page contains a root element whose prefix is bound - * to the JSP namespace, and false otherwise - */ - private boolean hasJspRoot(JspReader reader) throws JasperException { - - // :root must be the first element - Mark start = null; - while ((start = reader.skipUntil("<")) != null) { - int c = reader.nextChar(); - if (c != '!' && c != '?') break; - } - if (start == null) { - return false; - } - Mark stop = reader.skipUntil(":root"); - if (stop == null) { - return false; - } - // call substring to get rid of leading '<' - String prefix = reader.getText(start, stop).substring(1); - - start = stop; - stop = reader.skipUntil(">"); - if (stop == null) { - return false; - } - - // Determine namespace associated with element's prefix - String root = reader.getText(start, stop); - String xmlnsDecl = "xmlns:" + prefix; - int index = root.indexOf(xmlnsDecl); - if (index == -1) { - return false; - } - index += xmlnsDecl.length(); - while (index < root.length() - && Character.isWhitespace(root.charAt(index))) { - index++; - } - if (index < root.length() && root.charAt(index) == '=') { - index++; - while (index < root.length() - && Character.isWhitespace(root.charAt(index))) { - index++; - } - if (index < root.length() && root.charAt(index++) == '"' - && root.regionMatches(index, JSP_URI, 0, - JSP_URI.length())) { - return true; - } - } - - return false; - } - - private JarFile getJarFile(URL jarFileUrl) throws IOException { - JarFile jarFile = null; - - if (jarFileUrl != null) { - JarURLConnection conn = (JarURLConnection) jarFileUrl.openConnection(); - conn.setUseCaches(false); - conn.connect(); - jarFile = conn.getJarFile(); - } - - return jarFile; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.Stack; +import java.util.jar.JarFile; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.xmlparser.XMLEncodingDetector; +import org.xml.sax.Attributes; + +/** + * Controller for the parsing of a JSP page. + *

        + * The same ParserController instance is used for a JSP page and any JSP + * segments included by it (via an include directive), where each segment may + * be provided in standard or XML syntax. This class selects and invokes the + * appropriate parser for the JSP page and its included segments. + * + * @author Pierre Delisle + * @author Jan Luehe + */ +class ParserController implements TagConstants { + + private static final String CHARSET = "charset="; + + private JspCompilationContext ctxt; + private Compiler compiler; + private ErrorDispatcher err; + + /* + * Indicates the syntax (XML or standard) of the file being processed + */ + private boolean isXml; + + /* + * A stack to keep track of the 'current base directory' + * for include directives that refer to relative paths. + */ + private Stack baseDirStack = new Stack(); + + private boolean isEncodingSpecifiedInProlog; + + private String sourceEnc; + + private boolean isDefaultPageEncoding; + private boolean isTagFile; + private boolean directiveOnly; + + /* + * Constructor + */ + public ParserController(JspCompilationContext ctxt, Compiler compiler) { + this.ctxt = ctxt; + this.compiler = compiler; + this.err = compiler.getErrorDispatcher(); + } + + public JspCompilationContext getJspCompilationContext () { + return ctxt; + } + + public Compiler getCompiler () { + return compiler; + } + + /** + * Parses a JSP page or tag file. This is invoked by the compiler. + * + * @param inFileName The path to the JSP page or tag file to be parsed. + */ + public Node.Nodes parse(String inFileName) + throws FileNotFoundException, JasperException, IOException { + // If we're parsing a packaged tag file or a resource included by it + // (using an include directive), ctxt.getTagFileJar() returns the + // JAR file from which to read the tag file or included resource, + // respectively. + isTagFile = ctxt.isTagFile(); + directiveOnly = false; + return doParse(inFileName, null, ctxt.getTagFileJarUrl()); + } + + /** + * Processes an include directive with the given path. + * + * @param inFileName The path to the resource to be included. + * @param parent The parent node of the include directive. + * @param jarFile The JAR file from which to read the included resource, + * or null of the included resource is to be read from the filesystem + */ + public Node.Nodes parse(String inFileName, Node parent, + URL jarFileUrl) + throws FileNotFoundException, JasperException, IOException { + // For files that are statically included, isTagfile and directiveOnly + // remain unchanged. + return doParse(inFileName, parent, jarFileUrl); + } + + /** + * Extracts tag file directive information from the tag file with the + * given name. + * + * This is invoked by the compiler + * + * @param inFileName The name of the tag file to be parsed. + */ + public Node.Nodes parseTagFileDirectives(String inFileName) + throws FileNotFoundException, JasperException, IOException { + boolean isTagFileSave = isTagFile; + boolean directiveOnlySave = directiveOnly; + isTagFile = true; + directiveOnly = true; + Node.Nodes page = doParse(inFileName, null, + (URL) ctxt.getTagFileJarUrls().get(inFileName)); + directiveOnly = directiveOnlySave; + isTagFile = isTagFileSave; + return page; + } + + /** + * Parses the JSP page or tag file with the given path name. + * + * @param inFileName The name of the JSP page or tag file to be parsed. + * @param parent The parent node (non-null when processing an include + * directive) + * @param isTagFile true if file to be parsed is tag file, and false if it + * is a regular JSP page + * @param directivesOnly true if the file to be parsed is a tag file and + * we are only interested in the directives needed for constructing a + * TagFileInfo. + * @param jarFile The JAR file from which to read the JSP page or tag file, + * or null if the JSP page or tag file is to be read from the filesystem + */ + private Node.Nodes doParse(String inFileName, + Node parent, + URL jarFileUrl) + throws FileNotFoundException, JasperException, IOException { + + Node.Nodes parsedPage = null; + isEncodingSpecifiedInProlog = false; + isDefaultPageEncoding = false; + + JarFile jarFile = getJarFile(jarFileUrl); + String absFileName = resolveFileName(inFileName); + String jspConfigPageEnc = getJspConfigPageEncoding(absFileName); + + // Figure out what type of JSP document and encoding type we are + // dealing with + determineSyntaxAndEncoding(absFileName, jarFile, jspConfigPageEnc); + + if (parent != null) { + // Included resource, add to dependent list + compiler.getPageInfo().addDependant(absFileName); + } + + if (isXml && isEncodingSpecifiedInProlog) { + /* + * Make sure the encoding explicitly specified in the XML + * prolog (if any) matches that in the JSP config element + * (if any), treating "UTF-16", "UTF-16BE", and "UTF-16LE" as + * identical. + */ + if (jspConfigPageEnc != null && !jspConfigPageEnc.equals(sourceEnc) + && (!jspConfigPageEnc.startsWith("UTF-16") + || !sourceEnc.startsWith("UTF-16"))) { + err.jspError("jsp.error.prolog_config_encoding_mismatch", + sourceEnc, jspConfigPageEnc); + } + } + + // Dispatch to the appropriate parser + if (isXml) { + // JSP document (XML syntax) + // InputStream for jspx page is created and properly closed in + // JspDocumentParser. + parsedPage = JspDocumentParser.parse(this, absFileName, + jarFile, parent, + isTagFile, directiveOnly, + sourceEnc, + jspConfigPageEnc, + isEncodingSpecifiedInProlog); + } else { + // Standard syntax + InputStreamReader inStreamReader = null; + try { + inStreamReader = JspUtil.getReader(absFileName, sourceEnc, + jarFile, ctxt, err); + JspReader jspReader = new JspReader(ctxt, absFileName, + sourceEnc, inStreamReader, + err); + parsedPage = Parser.parse(this, jspReader, parent, isTagFile, + directiveOnly, jarFileUrl, + sourceEnc, jspConfigPageEnc, + isDefaultPageEncoding); + } finally { + if (inStreamReader != null) { + try { + inStreamReader.close(); + } catch (Exception any) { + } + } + } + } + + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) {} + } + + baseDirStack.pop(); + + return parsedPage; + } + + /* + * Checks to see if the given URI is matched by a URL pattern specified in + * a jsp-property-group in web.xml, and if so, returns the value of the + * element. + * + * @param absFileName The URI to match + * + * @return The value of the attribute of the + * jsp-property-group with matching URL pattern + */ + private String getJspConfigPageEncoding(String absFileName) + throws JasperException { + + JspConfig jspConfig = ctxt.getOptions().getJspConfig(); + JspConfig.JspProperty jspProperty + = jspConfig.findJspProperty(absFileName); + return jspProperty.getPageEncoding(); + } + + /** + * Determines the syntax (standard or XML) and page encoding properties + * for the given file, and stores them in the 'isXml' and 'sourceEnc' + * instance variables, respectively. + */ + private void determineSyntaxAndEncoding(String absFileName, + JarFile jarFile, + String jspConfigPageEnc) + throws JasperException, IOException { + + isXml = false; + + /* + * 'true' if the syntax (XML or standard) of the file is given + * from external information: either via a JSP configuration element, + * the ".jspx" suffix, or the enclosing file (for included resources) + */ + boolean isExternal = false; + + /* + * Indicates whether we need to revert from temporary usage of + * "ISO-8859-1" back to "UTF-8" + */ + boolean revert = false; + + JspConfig jspConfig = ctxt.getOptions().getJspConfig(); + JspConfig.JspProperty jspProperty = jspConfig.findJspProperty( + absFileName); + if (jspProperty.isXml() != null) { + // If is specified in a , it is used. + isXml = JspUtil.booleanValue(jspProperty.isXml()); + isExternal = true; + } else if (absFileName.endsWith(".jspx") + || absFileName.endsWith(".tagx")) { + isXml = true; + isExternal = true; + } + + if (isExternal && !isXml) { + // JSP (standard) syntax. Use encoding specified in jsp-config + // if provided. + sourceEnc = jspConfigPageEnc; + if (sourceEnc != null) { + return; + } + // We don't know the encoding + sourceEnc = "ISO-8859-1"; + } else { + // XML syntax or unknown, (auto)detect encoding ... + Object[] ret = XMLEncodingDetector.getEncoding(absFileName, + jarFile, ctxt, err); + sourceEnc = (String) ret[0]; + if (((Boolean) ret[1]).booleanValue()) { + isEncodingSpecifiedInProlog = true; + } + + if (!isXml && sourceEnc.equals("UTF-8")) { + /* + * We don't know if we're dealing with XML or standard syntax. + * Therefore, we need to check to see if the page contains + * a element. + * + * We need to be careful, because the page may be encoded in + * ISO-8859-1 (or something entirely different), and may + * contain byte sequences that will cause a UTF-8 converter to + * throw exceptions. + * + * It is safe to use a source encoding of ISO-8859-1 in this + * case, as there are no invalid byte sequences in ISO-8859-1, + * and the byte/character sequences we're looking for (i.e., + * ) are identical in either encoding (both UTF-8 + * and ISO-8859-1 are extensions of ASCII). + */ + sourceEnc = "ISO-8859-1"; + revert = true; + } + } + + if (isXml) { + // (This implies 'isExternal' is TRUE.) + // We know we're dealing with a JSP document (via JSP config or + // ".jspx" suffix), so we're done. + return; + } + + /* + * At this point, 'isExternal' or 'isXml' is FALSE. + * Search for jsp:root action, in order to determine if we're dealing + * with XML or standard syntax (unless we already know what we're + * dealing with, i.e., when 'isExternal' is TRUE and 'isXml' is FALSE). + * No check for XML prolog, since nothing prevents a page from + * outputting XML and still using JSP syntax (in this case, the + * XML prolog is treated as template text). + */ + JspReader jspReader = null; + try { + jspReader = new JspReader(ctxt, absFileName, sourceEnc, jarFile, + err); + } catch (FileNotFoundException ex) { + throw new JasperException(ex); + } + jspReader.setSingleFile(true); + Mark startMark = jspReader.mark(); + if (!isExternal) { + jspReader.reset(startMark); + if (hasJspRoot(jspReader)) { + isXml = true; + if (revert) sourceEnc = "UTF-8"; + return; + } else { + isXml = false; + } + } + + /* + * At this point, we know we're dealing with JSP syntax. + * If an XML prolog is provided, it's treated as template text. + * Determine the page encoding from the page directive, unless it's + * specified via JSP config. + */ + sourceEnc = jspConfigPageEnc; + if (sourceEnc == null) { + sourceEnc = getPageEncodingForJspSyntax(jspReader, startMark); + if (sourceEnc == null) { + // Default to "ISO-8859-1" per JSP spec + sourceEnc = "ISO-8859-1"; + isDefaultPageEncoding = true; + } + } + } + + /* + * Determines page source encoding for page or tag file in JSP syntax, + * by reading (in this order) the value of the 'pageEncoding' page + * directive attribute, or the charset value of the 'contentType' page + * directive attribute. + * + * @return The page encoding, or null if not found + */ + private String getPageEncodingForJspSyntax(JspReader jspReader, + Mark startMark) + throws JasperException { + + String encoding = null; + String saveEncoding = null; + + jspReader.reset(startMark); + + /* + * Determine page encoding from directive of the form <%@ page %>, + * <%@ tag %>, or . + */ + while (true) { + if (jspReader.skipUntil("<") == null) { + break; + } + // If this is a comment, skip until its end + if (jspReader.matches("%--")) { + if (jspReader.skipUntil("--%>") == null) { + // error will be caught in Parser + break; + } + continue; + } + boolean isDirective = jspReader.matches("%@"); + if (isDirective) { + jspReader.skipSpaces(); + } + else { + isDirective = jspReader.matches("jsp:directive."); + } + if (!isDirective) { + continue; + } + + // compare for "tag ", so we don't match "taglib" + if (jspReader.matches("tag ") || jspReader.matches("page")) { + + jspReader.skipSpaces(); + Attributes attrs = Parser.parseAttributes(this, jspReader); + encoding = getPageEncodingFromDirective(attrs, "pageEncoding"); + if (encoding != null) { + break; + } + encoding = getPageEncodingFromDirective(attrs, "contentType"); + if (encoding != null) { + saveEncoding = encoding; + } + } + } + + if (encoding == null) { + encoding = saveEncoding; + } + + return encoding; + } + + /* + * Scans the given attributes for the attribute with the given name, + * which is either 'pageEncoding' or 'contentType', and returns the + * specified page encoding. + * + * In the case of 'contentType', the page encoding is taken from the + * content type's 'charset' component. + * + * @param attrs The page directive attributes + * @param attrName The name of the attribute to search for (either + * 'pageEncoding' or 'contentType') + * + * @return The page encoding, or null + */ + private String getPageEncodingFromDirective(Attributes attrs, + String attrName) { + String value = attrs.getValue(attrName); + if (attrName.equals("pageEncoding")) { + return value; + } + + // attrName = contentType + String contentType = value; + String encoding = null; + if (contentType != null) { + int loc = contentType.indexOf(CHARSET); + if (loc != -1) { + encoding = contentType.substring(loc + CHARSET.length()); + } + } + + return encoding; + } + + /* + * Resolve the name of the file and update baseDirStack() to keep track of + * the current base directory for each included file. + * The 'root' file is always an 'absolute' path, so no need to put an + * initial value in the baseDirStack. + */ + private String resolveFileName(String inFileName) { + String fileName = inFileName.replace('\\', '/'); + boolean isAbsolute = fileName.startsWith("/"); + fileName = isAbsolute ? fileName + : (String) baseDirStack.peek() + fileName; + String baseDir = + fileName.substring(0, fileName.lastIndexOf("/") + 1); + baseDirStack.push(baseDir); + return fileName; + } + + /* + * Checks to see if the given page contains, as its first element, a + * element whose prefix is bound to the JSP namespace, as in: + * + * + * ... + * + * + * @param reader The reader for this page + * + * @return true if this page contains a root element whose prefix is bound + * to the JSP namespace, and false otherwise + */ + private boolean hasJspRoot(JspReader reader) throws JasperException { + + // :root must be the first element + Mark start = null; + while ((start = reader.skipUntil("<")) != null) { + int c = reader.nextChar(); + if (c != '!' && c != '?') break; + } + if (start == null) { + return false; + } + Mark stop = reader.skipUntil(":root"); + if (stop == null) { + return false; + } + // call substring to get rid of leading '<' + String prefix = reader.getText(start, stop).substring(1); + + start = stop; + stop = reader.skipUntil(">"); + if (stop == null) { + return false; + } + + // Determine namespace associated with element's prefix + String root = reader.getText(start, stop); + String xmlnsDecl = "xmlns:" + prefix; + int index = root.indexOf(xmlnsDecl); + if (index == -1) { + return false; + } + index += xmlnsDecl.length(); + while (index < root.length() + && Character.isWhitespace(root.charAt(index))) { + index++; + } + if (index < root.length() && root.charAt(index) == '=') { + index++; + while (index < root.length() + && Character.isWhitespace(root.charAt(index))) { + index++; + } + if (index < root.length() && root.charAt(index++) == '"' + && root.regionMatches(index, JSP_URI, 0, + JSP_URI.length())) { + return true; + } + } + + return false; + } + + private JarFile getJarFile(URL jarFileUrl) throws IOException { + JarFile jarFile = null; + + if (jarFileUrl != null) { + JarURLConnection conn = (JarURLConnection) jarFileUrl.openConnection(); + conn.setUseCaches(false); + conn.connect(); + jarFile = conn.getJarFile(); + } + + return jarFile; + } + +} diff --git a/java/org/apache/jasper/compiler/ScriptingVariabler.java b/java/org/apache/jasper/compiler/ScriptingVariabler.java index e6bff9de2..5c91dbfa1 100644 --- a/java/org/apache/jasper/compiler/ScriptingVariabler.java +++ b/java/org/apache/jasper/compiler/ScriptingVariabler.java @@ -1,147 +1,147 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.*; -import javax.servlet.jsp.tagext.*; -import org.apache.jasper.JasperException; - -/** - * Class responsible for determining the scripting variables that every - * custom action needs to declare. - * - * @author Jan Luehe - */ -class ScriptingVariabler { - - private static final Integer MAX_SCOPE = new Integer(Integer.MAX_VALUE); - - /* - * Assigns an identifier (of type integer) to every custom tag, in order - * to help identify, for every custom tag, the scripting variables that it - * needs to declare. - */ - static class CustomTagCounter extends Node.Visitor { - - private int count; - private Node.CustomTag parent; - - public void visit(Node.CustomTag n) throws JasperException { - n.setCustomTagParent(parent); - Node.CustomTag tmpParent = parent; - parent = n; - visitBody(n); - parent = tmpParent; - n.setNumCount(new Integer(count++)); - } - } - - /* - * For every custom tag, determines the scripting variables it needs to - * declare. - */ - static class ScriptingVariableVisitor extends Node.Visitor { - - private ErrorDispatcher err; - private Hashtable scriptVars; - - public ScriptingVariableVisitor(ErrorDispatcher err) { - this.err = err; - scriptVars = new Hashtable(); - } - - public void visit(Node.CustomTag n) throws JasperException { - setScriptingVars(n, VariableInfo.AT_BEGIN); - setScriptingVars(n, VariableInfo.NESTED); - visitBody(n); - setScriptingVars(n, VariableInfo.AT_END); - } - - private void setScriptingVars(Node.CustomTag n, int scope) - throws JasperException { - - TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); - VariableInfo[] varInfos = n.getVariableInfos(); - if (tagVarInfos.length == 0 && varInfos.length == 0) { - return; - } - - Vector vec = new Vector(); - - Integer ownRange = null; - if (scope == VariableInfo.AT_BEGIN - || scope == VariableInfo.AT_END) { - Node.CustomTag parent = n.getCustomTagParent(); - if (parent == null) - ownRange = MAX_SCOPE; - else - ownRange = parent.getNumCount(); - } else { - // NESTED - ownRange = n.getNumCount(); - } - - if (varInfos.length > 0) { - for (int i=0; i 0) { - scriptVars.put(varName, ownRange); - vec.add(varInfos[i]); - } - } - } else { - for (int i=0; i 0) { - scriptVars.put(varName, ownRange); - vec.add(tagVarInfos[i]); - } - } - } - - n.setScriptingVars(vec, scope); - } - } - - public static void set(Node.Nodes page, ErrorDispatcher err) - throws JasperException { - page.visit(new CustomTagCounter()); - page.visit(new ScriptingVariableVisitor(err)); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.*; +import javax.servlet.jsp.tagext.*; +import org.apache.jasper.JasperException; + +/** + * Class responsible for determining the scripting variables that every + * custom action needs to declare. + * + * @author Jan Luehe + */ +class ScriptingVariabler { + + private static final Integer MAX_SCOPE = new Integer(Integer.MAX_VALUE); + + /* + * Assigns an identifier (of type integer) to every custom tag, in order + * to help identify, for every custom tag, the scripting variables that it + * needs to declare. + */ + static class CustomTagCounter extends Node.Visitor { + + private int count; + private Node.CustomTag parent; + + public void visit(Node.CustomTag n) throws JasperException { + n.setCustomTagParent(parent); + Node.CustomTag tmpParent = parent; + parent = n; + visitBody(n); + parent = tmpParent; + n.setNumCount(new Integer(count++)); + } + } + + /* + * For every custom tag, determines the scripting variables it needs to + * declare. + */ + static class ScriptingVariableVisitor extends Node.Visitor { + + private ErrorDispatcher err; + private Hashtable scriptVars; + + public ScriptingVariableVisitor(ErrorDispatcher err) { + this.err = err; + scriptVars = new Hashtable(); + } + + public void visit(Node.CustomTag n) throws JasperException { + setScriptingVars(n, VariableInfo.AT_BEGIN); + setScriptingVars(n, VariableInfo.NESTED); + visitBody(n); + setScriptingVars(n, VariableInfo.AT_END); + } + + private void setScriptingVars(Node.CustomTag n, int scope) + throws JasperException { + + TagVariableInfo[] tagVarInfos = n.getTagVariableInfos(); + VariableInfo[] varInfos = n.getVariableInfos(); + if (tagVarInfos.length == 0 && varInfos.length == 0) { + return; + } + + Vector vec = new Vector(); + + Integer ownRange = null; + if (scope == VariableInfo.AT_BEGIN + || scope == VariableInfo.AT_END) { + Node.CustomTag parent = n.getCustomTagParent(); + if (parent == null) + ownRange = MAX_SCOPE; + else + ownRange = parent.getNumCount(); + } else { + // NESTED + ownRange = n.getNumCount(); + } + + if (varInfos.length > 0) { + for (int i=0; i 0) { + scriptVars.put(varName, ownRange); + vec.add(varInfos[i]); + } + } + } else { + for (int i=0; i 0) { + scriptVars.put(varName, ownRange); + vec.add(tagVarInfos[i]); + } + } + } + + n.setScriptingVars(vec, scope); + } + } + + public static void set(Node.Nodes page, ErrorDispatcher err) + throws JasperException { + page.visit(new CustomTagCounter()); + page.visit(new ScriptingVariableVisitor(err)); + } +} diff --git a/java/org/apache/jasper/compiler/ServletWriter.java b/java/org/apache/jasper/compiler/ServletWriter.java index 32310297a..7e37dbaa7 100644 --- a/java/org/apache/jasper/compiler/ServletWriter.java +++ b/java/org/apache/jasper/compiler/ServletWriter.java @@ -1,175 +1,175 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import java.io.IOException; -import java.io.PrintWriter; - -/** - * This is what is used to generate servlets. - * - * @author Anil K. Vijendran - * @author Kin-man Chung - */ -public class ServletWriter { - public static int TAB_WIDTH = 2; - public static String SPACES = " "; - - // Current indent level: - private int indent = 0; - private int virtual_indent = 0; - - // The sink writer: - PrintWriter writer; - - // servlet line numbers start from 1 - private int javaLine = 1; - - - public ServletWriter(PrintWriter writer) { - this.writer = writer; - } - - public void close() throws IOException { - writer.close(); - } - - - // -------------------- Access informations -------------------- - - public int getJavaLine() { - return javaLine; - } - - - // -------------------- Formatting -------------------- - - public void pushIndent() { - virtual_indent += TAB_WIDTH; - if (virtual_indent >= 0 && virtual_indent <= SPACES.length()) - indent = virtual_indent; - } - - public void popIndent() { - virtual_indent -= TAB_WIDTH; - if (virtual_indent >= 0 && virtual_indent <= SPACES.length()) - indent = virtual_indent; - } - - /** - * Print a standard comment for echo outputed chunk. - * @param start The starting position of the JSP chunk being processed. - * @param stop The ending position of the JSP chunk being processed. - */ - public void printComment(Mark start, Mark stop, char[] chars) { - if (start != null && stop != null) { - println("// from="+start); - println("// to="+stop); - } - - if (chars != null) - for(int i = 0; i < chars.length;) { - printin(); - print("// "); - while (chars[i] != '\n' && i < chars.length) - writer.print(chars[i++]); - } - } - - /** - * Prints the given string followed by '\n' - */ - public void println(String s) { - javaLine++; - writer.println(s); - } - - /** - * Prints a '\n' - */ - public void println() { - javaLine++; - writer.println(""); - } - - /** - * Prints the current indention - */ - public void printin() { - writer.print(SPACES.substring(0, indent)); - } - - /** - * Prints the current indention, followed by the given string - */ - public void printin(String s) { - writer.print(SPACES.substring(0, indent)); - writer.print(s); - } - - /** - * Prints the current indention, and then the string, and a '\n'. - */ - public void printil(String s) { - javaLine++; - writer.print(SPACES.substring(0, indent)); - writer.println(s); - } - - /** - * Prints the given char. - * - * Use println() to print a '\n'. - */ - public void print(char c) { - writer.print(c); - } - - /** - * Prints the given int. - */ - public void print(int i) { - writer.print(i); - } - - /** - * Prints the given string. - * - * The string must not contain any '\n', otherwise the line count will be - * off. - */ - public void print(String s) { - writer.print(s); - } - - /** - * Prints the given string. - * - * If the string spans multiple lines, the line count will be adjusted - * accordingly. - */ - public void printMultiLn(String s) { - int index = 0; - - // look for hidden newlines inside strings - while ((index=s.indexOf('\n',index)) > -1 ) { - javaLine++; - index++; - } - - writer.print(s); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import java.io.IOException; +import java.io.PrintWriter; + +/** + * This is what is used to generate servlets. + * + * @author Anil K. Vijendran + * @author Kin-man Chung + */ +public class ServletWriter { + public static int TAB_WIDTH = 2; + public static String SPACES = " "; + + // Current indent level: + private int indent = 0; + private int virtual_indent = 0; + + // The sink writer: + PrintWriter writer; + + // servlet line numbers start from 1 + private int javaLine = 1; + + + public ServletWriter(PrintWriter writer) { + this.writer = writer; + } + + public void close() throws IOException { + writer.close(); + } + + + // -------------------- Access informations -------------------- + + public int getJavaLine() { + return javaLine; + } + + + // -------------------- Formatting -------------------- + + public void pushIndent() { + virtual_indent += TAB_WIDTH; + if (virtual_indent >= 0 && virtual_indent <= SPACES.length()) + indent = virtual_indent; + } + + public void popIndent() { + virtual_indent -= TAB_WIDTH; + if (virtual_indent >= 0 && virtual_indent <= SPACES.length()) + indent = virtual_indent; + } + + /** + * Print a standard comment for echo outputed chunk. + * @param start The starting position of the JSP chunk being processed. + * @param stop The ending position of the JSP chunk being processed. + */ + public void printComment(Mark start, Mark stop, char[] chars) { + if (start != null && stop != null) { + println("// from="+start); + println("// to="+stop); + } + + if (chars != null) + for(int i = 0; i < chars.length;) { + printin(); + print("// "); + while (chars[i] != '\n' && i < chars.length) + writer.print(chars[i++]); + } + } + + /** + * Prints the given string followed by '\n' + */ + public void println(String s) { + javaLine++; + writer.println(s); + } + + /** + * Prints a '\n' + */ + public void println() { + javaLine++; + writer.println(""); + } + + /** + * Prints the current indention + */ + public void printin() { + writer.print(SPACES.substring(0, indent)); + } + + /** + * Prints the current indention, followed by the given string + */ + public void printin(String s) { + writer.print(SPACES.substring(0, indent)); + writer.print(s); + } + + /** + * Prints the current indention, and then the string, and a '\n'. + */ + public void printil(String s) { + javaLine++; + writer.print(SPACES.substring(0, indent)); + writer.println(s); + } + + /** + * Prints the given char. + * + * Use println() to print a '\n'. + */ + public void print(char c) { + writer.print(c); + } + + /** + * Prints the given int. + */ + public void print(int i) { + writer.print(i); + } + + /** + * Prints the given string. + * + * The string must not contain any '\n', otherwise the line count will be + * off. + */ + public void print(String s) { + writer.print(s); + } + + /** + * Prints the given string. + * + * If the string spans multiple lines, the line count will be adjusted + * accordingly. + */ + public void printMultiLn(String s) { + int index = 0; + + // look for hidden newlines inside strings + while ((index=s.indexOf('\n',index)) > -1 ) { + javaLine++; + index++; + } + + writer.print(s); + } +} diff --git a/java/org/apache/jasper/compiler/SmapGenerator.java b/java/org/apache/jasper/compiler/SmapGenerator.java index f32d44062..217b67e4b 100644 --- a/java/org/apache/jasper/compiler/SmapGenerator.java +++ b/java/org/apache/jasper/compiler/SmapGenerator.java @@ -1,170 +1,170 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.List; -import java.util.ArrayList; - -/** - * Represents a source map (SMAP), which serves to associate lines - * of the input JSP file(s) to lines in the generated servlet in the - * final .class file, according to the JSR-045 spec. - * - * @author Shawn Bayern - */ -public class SmapGenerator { - - //********************************************************************* - // Overview - - /* - * The SMAP syntax is reasonably straightforward. The purpose of this - * class is currently twofold: - * - to provide a simple but low-level Java interface to build - * a logical SMAP - * - to serialize this logical SMAP for eventual inclusion directly - * into a .class file. - */ - - - //********************************************************************* - // Private state - - private String outputFileName; - private String defaultStratum = "Java"; - private List strata = new ArrayList(); - private List embedded = new ArrayList(); - private boolean doEmbedded = true; - - //********************************************************************* - // Methods for adding mapping data - - /** - * Sets the filename (without path information) for the generated - * source file. E.g., "foo$jsp.java". - */ - public synchronized void setOutputFileName(String x) { - outputFileName = x; - } - - /** - * Adds the given SmapStratum object, representing a Stratum with - * logically associated FileSection and LineSection blocks, to - * the current SmapGenerator. If default is true, this - * stratum is made the default stratum, overriding any previously - * set default. - * - * @param stratum the SmapStratum object to add - * @param defaultStratum if true, this SmapStratum is considered - * to represent the default SMAP stratum unless - * overwritten - */ - public synchronized void addStratum(SmapStratum stratum, - boolean defaultStratum) { - strata.add(stratum); - if (defaultStratum) - this.defaultStratum = stratum.getStratumName(); - } - - /** - * Adds the given string as an embedded SMAP with the given stratum name. - * - * @param smap the SMAP to embed - * @param stratumName the name of the stratum output by the compilation - * that produced the smap to be embedded - */ - public synchronized void addSmap(String smap, String stratumName) { - embedded.add("*O " + stratumName + "\n" - + smap - + "*C " + stratumName + "\n"); - } - - /** - * Instructs the SmapGenerator whether to actually print any embedded - * SMAPs or not. Intended for situations without an SMAP resolver. - * - * @param status If false, ignore any embedded SMAPs. - */ - public void setDoEmbedded(boolean status) { - doEmbedded = status; - } - - //********************************************************************* - // Methods for serializing the logical SMAP - - public synchronized String getString() { - // check state and initialize buffer - if (outputFileName == null) - throw new IllegalStateException(); - StringBuffer out = new StringBuffer(); - - // start the SMAP - out.append("SMAP\n"); - out.append(outputFileName + '\n'); - out.append(defaultStratum + '\n'); - - // include embedded SMAPs - if (doEmbedded) { - int nEmbedded = embedded.size(); - for (int i = 0; i < nEmbedded; i++) { - out.append(embedded.get(i)); - } - } - - // print our StratumSections, FileSections, and LineSections - int nStrata = strata.size(); - for (int i = 0; i < nStrata; i++) { - SmapStratum s = (SmapStratum) strata.get(i); - out.append(s.getString()); - } - - // end the SMAP - out.append("*E\n"); - - return out.toString(); - } - - public String toString() { return getString(); } - - //********************************************************************* - // For testing (and as an example of use)... - - public static void main(String args[]) { - SmapGenerator g = new SmapGenerator(); - g.setOutputFileName("foo.java"); - SmapStratum s = new SmapStratum("JSP"); - s.addFile("foo.jsp"); - s.addFile("bar.jsp", "/foo/foo/bar.jsp"); - s.addLineData(1, "foo.jsp", 1, 1, 1); - s.addLineData(2, "foo.jsp", 1, 6, 1); - s.addLineData(3, "foo.jsp", 2, 10, 5); - s.addLineData(20, "bar.jsp", 1, 30, 1); - g.addStratum(s, true); - System.out.print(g); - - System.out.println("---"); - - SmapGenerator embedded = new SmapGenerator(); - embedded.setOutputFileName("blargh.tier2"); - s = new SmapStratum("Tier2"); - s.addFile("1.tier2"); - s.addLineData(1, "1.tier2", 1, 1, 1); - embedded.addStratum(s, true); - g.addSmap(embedded.toString(), "JSP"); - System.out.println(g); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.List; +import java.util.ArrayList; + +/** + * Represents a source map (SMAP), which serves to associate lines + * of the input JSP file(s) to lines in the generated servlet in the + * final .class file, according to the JSR-045 spec. + * + * @author Shawn Bayern + */ +public class SmapGenerator { + + //********************************************************************* + // Overview + + /* + * The SMAP syntax is reasonably straightforward. The purpose of this + * class is currently twofold: + * - to provide a simple but low-level Java interface to build + * a logical SMAP + * - to serialize this logical SMAP for eventual inclusion directly + * into a .class file. + */ + + + //********************************************************************* + // Private state + + private String outputFileName; + private String defaultStratum = "Java"; + private List strata = new ArrayList(); + private List embedded = new ArrayList(); + private boolean doEmbedded = true; + + //********************************************************************* + // Methods for adding mapping data + + /** + * Sets the filename (without path information) for the generated + * source file. E.g., "foo$jsp.java". + */ + public synchronized void setOutputFileName(String x) { + outputFileName = x; + } + + /** + * Adds the given SmapStratum object, representing a Stratum with + * logically associated FileSection and LineSection blocks, to + * the current SmapGenerator. If default is true, this + * stratum is made the default stratum, overriding any previously + * set default. + * + * @param stratum the SmapStratum object to add + * @param defaultStratum if true, this SmapStratum is considered + * to represent the default SMAP stratum unless + * overwritten + */ + public synchronized void addStratum(SmapStratum stratum, + boolean defaultStratum) { + strata.add(stratum); + if (defaultStratum) + this.defaultStratum = stratum.getStratumName(); + } + + /** + * Adds the given string as an embedded SMAP with the given stratum name. + * + * @param smap the SMAP to embed + * @param stratumName the name of the stratum output by the compilation + * that produced the smap to be embedded + */ + public synchronized void addSmap(String smap, String stratumName) { + embedded.add("*O " + stratumName + "\n" + + smap + + "*C " + stratumName + "\n"); + } + + /** + * Instructs the SmapGenerator whether to actually print any embedded + * SMAPs or not. Intended for situations without an SMAP resolver. + * + * @param status If false, ignore any embedded SMAPs. + */ + public void setDoEmbedded(boolean status) { + doEmbedded = status; + } + + //********************************************************************* + // Methods for serializing the logical SMAP + + public synchronized String getString() { + // check state and initialize buffer + if (outputFileName == null) + throw new IllegalStateException(); + StringBuffer out = new StringBuffer(); + + // start the SMAP + out.append("SMAP\n"); + out.append(outputFileName + '\n'); + out.append(defaultStratum + '\n'); + + // include embedded SMAPs + if (doEmbedded) { + int nEmbedded = embedded.size(); + for (int i = 0; i < nEmbedded; i++) { + out.append(embedded.get(i)); + } + } + + // print our StratumSections, FileSections, and LineSections + int nStrata = strata.size(); + for (int i = 0; i < nStrata; i++) { + SmapStratum s = (SmapStratum) strata.get(i); + out.append(s.getString()); + } + + // end the SMAP + out.append("*E\n"); + + return out.toString(); + } + + public String toString() { return getString(); } + + //********************************************************************* + // For testing (and as an example of use)... + + public static void main(String args[]) { + SmapGenerator g = new SmapGenerator(); + g.setOutputFileName("foo.java"); + SmapStratum s = new SmapStratum("JSP"); + s.addFile("foo.jsp"); + s.addFile("bar.jsp", "/foo/foo/bar.jsp"); + s.addLineData(1, "foo.jsp", 1, 1, 1); + s.addLineData(2, "foo.jsp", 1, 6, 1); + s.addLineData(3, "foo.jsp", 2, 10, 5); + s.addLineData(20, "bar.jsp", 1, 30, 1); + g.addStratum(s, true); + System.out.print(g); + + System.out.println("---"); + + SmapGenerator embedded = new SmapGenerator(); + embedded.setOutputFileName("blargh.tier2"); + s = new SmapStratum("Tier2"); + s.addFile("1.tier2"); + s.addLineData(1, "1.tier2", 1, 1, 1); + embedded.addStratum(s, true); + g.addSmap(embedded.toString(), "JSP"); + System.out.println(g); + } +} diff --git a/java/org/apache/jasper/compiler/SmapStratum.java b/java/org/apache/jasper/compiler/SmapStratum.java index 28745d133..91f9d33a0 100644 --- a/java/org/apache/jasper/compiler/SmapStratum.java +++ b/java/org/apache/jasper/compiler/SmapStratum.java @@ -1,335 +1,335 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.List; -import java.util.ArrayList; - -/** - * Represents the line and file mappings associated with a JSR-045 - * "stratum". - * - * @author Jayson Falkner - * @author Shawn Bayern - */ -public class SmapStratum { - - //********************************************************************* - // Class for storing LineInfo data - - /** - * Represents a single LineSection in an SMAP, associated with - * a particular stratum. - */ - public static class LineInfo { - private int inputStartLine = -1; - private int outputStartLine = -1; - private int lineFileID = 0; - private int inputLineCount = 1; - private int outputLineIncrement = 1; - private boolean lineFileIDSet = false; - - /** Sets InputStartLine. */ - public void setInputStartLine(int inputStartLine) { - if (inputStartLine < 0) - throw new IllegalArgumentException("" + inputStartLine); - this.inputStartLine = inputStartLine; - } - - /** Sets OutputStartLine. */ - public void setOutputStartLine(int outputStartLine) { - if (outputStartLine < 0) - throw new IllegalArgumentException("" + outputStartLine); - this.outputStartLine = outputStartLine; - } - - /** - * Sets lineFileID. Should be called only when different from - * that of prior LineInfo object (in any given context) or 0 - * if the current LineInfo has no (logical) predecessor. - * LineInfo will print this file number no matter what. - */ - public void setLineFileID(int lineFileID) { - if (lineFileID < 0) - throw new IllegalArgumentException("" + lineFileID); - this.lineFileID = lineFileID; - this.lineFileIDSet = true; - } - - /** Sets InputLineCount. */ - public void setInputLineCount(int inputLineCount) { - if (inputLineCount < 0) - throw new IllegalArgumentException("" + inputLineCount); - this.inputLineCount = inputLineCount; - } - - /** Sets OutputLineIncrement. */ - public void setOutputLineIncrement(int outputLineIncrement) { - if (outputLineIncrement < 0) - throw new IllegalArgumentException("" + outputLineIncrement); - this.outputLineIncrement = outputLineIncrement; - } - - /** - * Retrieves the current LineInfo as a String, print all values - * only when appropriate (but LineInfoID if and only if it's been - * specified, as its necessity is sensitive to context). - */ - public String getString() { - if (inputStartLine == -1 || outputStartLine == -1) - throw new IllegalStateException(); - StringBuffer out = new StringBuffer(); - out.append(inputStartLine); - if (lineFileIDSet) - out.append("#" + lineFileID); - if (inputLineCount != 1) - out.append("," + inputLineCount); - out.append(":" + outputStartLine); - if (outputLineIncrement != 1) - out.append("," + outputLineIncrement); - out.append('\n'); - return out.toString(); - } - - public String toString() { - return getString(); - } - } - - //********************************************************************* - // Private state - - private String stratumName; - private List fileNameList; - private List filePathList; - private List lineData; - private int lastFileID; - - //********************************************************************* - // Constructor - - /** - * Constructs a new SmapStratum object for the given stratum name - * (e.g., JSP). - * - * @param stratumName the name of the stratum (e.g., JSP) - */ - public SmapStratum(String stratumName) { - this.stratumName = stratumName; - fileNameList = new ArrayList(); - filePathList = new ArrayList(); - lineData = new ArrayList(); - lastFileID = 0; - } - - //********************************************************************* - // Methods to add mapping information - - /** - * Adds record of a new file, by filename. - * - * @param filename the filename to add, unqualified by path. - */ - public void addFile(String filename) { - addFile(filename, filename); - } - - /** - * Adds record of a new file, by filename and path. The path - * may be relative to a source compilation path. - * - * @param filename the filename to add, unqualified by path - * @param filePath the path for the filename, potentially relative - * to a source compilation path - */ - public void addFile(String filename, String filePath) { - int pathIndex = filePathList.indexOf(filePath); - if (pathIndex == -1) { - fileNameList.add(filename); - filePathList.add(filePath); - } - } - - /** - * Combines consecutive LineInfos wherever possible - */ - public void optimizeLineSection() { - -/* Some debugging code - for (int i = 0; i < lineData.size(); i++) { - LineInfo li = (LineInfo)lineData.get(i); - System.out.print(li.toString()); - } -*/ - //Incorporate each LineInfo into the previous LineInfo's - //outputLineIncrement, if possible - int i = 0; - while (i < lineData.size() - 1) { - LineInfo li = (LineInfo)lineData.get(i); - LineInfo liNext = (LineInfo)lineData.get(i + 1); - if (!liNext.lineFileIDSet - && liNext.inputStartLine == li.inputStartLine - && liNext.inputLineCount == 1 - && li.inputLineCount == 1 - && liNext.outputStartLine - == li.outputStartLine - + li.inputLineCount * li.outputLineIncrement) { - li.setOutputLineIncrement( - liNext.outputStartLine - - li.outputStartLine - + liNext.outputLineIncrement); - lineData.remove(i + 1); - } else { - i++; - } - } - - //Incorporate each LineInfo into the previous LineInfo's - //inputLineCount, if possible - i = 0; - while (i < lineData.size() - 1) { - LineInfo li = (LineInfo)lineData.get(i); - LineInfo liNext = (LineInfo)lineData.get(i + 1); - if (!liNext.lineFileIDSet - && liNext.inputStartLine == li.inputStartLine + li.inputLineCount - && liNext.outputLineIncrement == li.outputLineIncrement - && liNext.outputStartLine - == li.outputStartLine - + li.inputLineCount * li.outputLineIncrement) { - li.setInputLineCount(li.inputLineCount + liNext.inputLineCount); - lineData.remove(i + 1); - } else { - i++; - } - } - } - - /** - * Adds complete information about a simple line mapping. Specify - * all the fields in this method; the back-end machinery takes care - * of printing only those that are necessary in the final SMAP. - * (My view is that fields are optional primarily for spatial efficiency, - * not for programmer convenience. Could always add utility methods - * later.) - * - * @param inputStartLine starting line in the source file - * (SMAP InputStartLine) - * @param inputFileName the filepath (or name) from which the input comes - * (yields SMAP LineFileID) Use unqualified names - * carefully, and only when they uniquely identify a file. - * @param inputLineCount the number of lines in the input to map - * (SMAP LineFileCount) - * @param outputStartLine starting line in the output file - * (SMAP OutputStartLine) - * @param outputLineIncrement number of output lines to map to each - * input line (SMAP OutputLineIncrement). Given the - * fact that the name starts with "output", I continuously have - * the subconscious urge to call this field - * OutputLineExcrement. - */ - public void addLineData( - int inputStartLine, - String inputFileName, - int inputLineCount, - int outputStartLine, - int outputLineIncrement) { - // check the input - what are you doing here?? - int fileIndex = filePathList.indexOf(inputFileName); - if (fileIndex == -1) // still - throw new IllegalArgumentException( - "inputFileName: " + inputFileName); - - //Jasper incorrectly SMAPs certain Nodes, giving them an - //outputStartLine of 0. This can cause a fatal error in - //optimizeLineSection, making it impossible for Jasper to - //compile the JSP. Until we can fix the underlying - //SMAPping problem, we simply ignore the flawed SMAP entries. - if (outputStartLine == 0) - return; - - // build the LineInfo - LineInfo li = new LineInfo(); - li.setInputStartLine(inputStartLine); - li.setInputLineCount(inputLineCount); - li.setOutputStartLine(outputStartLine); - li.setOutputLineIncrement(outputLineIncrement); - if (fileIndex != lastFileID) - li.setLineFileID(fileIndex); - lastFileID = fileIndex; - - // save it - lineData.add(li); - } - - //********************************************************************* - // Methods to retrieve information - - /** - * Returns the name of the stratum. - */ - public String getStratumName() { - return stratumName; - } - - /** - * Returns the given stratum as a String: a StratumSection, - * followed by at least one FileSection and at least one LineSection. - */ - public String getString() { - // check state and initialize buffer - if (fileNameList.size() == 0 || lineData.size() == 0) - return null; - - StringBuffer out = new StringBuffer(); - - // print StratumSection - out.append("*S " + stratumName + "\n"); - - // print FileSection - out.append("*F\n"); - int bound = fileNameList.size(); - for (int i = 0; i < bound; i++) { - if (filePathList.get(i) != null) { - out.append("+ " + i + " " + fileNameList.get(i) + "\n"); - // Source paths must be relative, not absolute, so we - // remove the leading "/", if one exists. - String filePath = (String)filePathList.get(i); - if (filePath.startsWith("/")) { - filePath = filePath.substring(1); - } - out.append(filePath + "\n"); - } else { - out.append(i + " " + fileNameList.get(i) + "\n"); - } - } - - // print LineSection - out.append("*L\n"); - bound = lineData.size(); - for (int i = 0; i < bound; i++) { - LineInfo li = (LineInfo)lineData.get(i); - out.append(li.getString()); - } - - return out.toString(); - } - - public String toString() { - return getString(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.List; +import java.util.ArrayList; + +/** + * Represents the line and file mappings associated with a JSR-045 + * "stratum". + * + * @author Jayson Falkner + * @author Shawn Bayern + */ +public class SmapStratum { + + //********************************************************************* + // Class for storing LineInfo data + + /** + * Represents a single LineSection in an SMAP, associated with + * a particular stratum. + */ + public static class LineInfo { + private int inputStartLine = -1; + private int outputStartLine = -1; + private int lineFileID = 0; + private int inputLineCount = 1; + private int outputLineIncrement = 1; + private boolean lineFileIDSet = false; + + /** Sets InputStartLine. */ + public void setInputStartLine(int inputStartLine) { + if (inputStartLine < 0) + throw new IllegalArgumentException("" + inputStartLine); + this.inputStartLine = inputStartLine; + } + + /** Sets OutputStartLine. */ + public void setOutputStartLine(int outputStartLine) { + if (outputStartLine < 0) + throw new IllegalArgumentException("" + outputStartLine); + this.outputStartLine = outputStartLine; + } + + /** + * Sets lineFileID. Should be called only when different from + * that of prior LineInfo object (in any given context) or 0 + * if the current LineInfo has no (logical) predecessor. + * LineInfo will print this file number no matter what. + */ + public void setLineFileID(int lineFileID) { + if (lineFileID < 0) + throw new IllegalArgumentException("" + lineFileID); + this.lineFileID = lineFileID; + this.lineFileIDSet = true; + } + + /** Sets InputLineCount. */ + public void setInputLineCount(int inputLineCount) { + if (inputLineCount < 0) + throw new IllegalArgumentException("" + inputLineCount); + this.inputLineCount = inputLineCount; + } + + /** Sets OutputLineIncrement. */ + public void setOutputLineIncrement(int outputLineIncrement) { + if (outputLineIncrement < 0) + throw new IllegalArgumentException("" + outputLineIncrement); + this.outputLineIncrement = outputLineIncrement; + } + + /** + * Retrieves the current LineInfo as a String, print all values + * only when appropriate (but LineInfoID if and only if it's been + * specified, as its necessity is sensitive to context). + */ + public String getString() { + if (inputStartLine == -1 || outputStartLine == -1) + throw new IllegalStateException(); + StringBuffer out = new StringBuffer(); + out.append(inputStartLine); + if (lineFileIDSet) + out.append("#" + lineFileID); + if (inputLineCount != 1) + out.append("," + inputLineCount); + out.append(":" + outputStartLine); + if (outputLineIncrement != 1) + out.append("," + outputLineIncrement); + out.append('\n'); + return out.toString(); + } + + public String toString() { + return getString(); + } + } + + //********************************************************************* + // Private state + + private String stratumName; + private List fileNameList; + private List filePathList; + private List lineData; + private int lastFileID; + + //********************************************************************* + // Constructor + + /** + * Constructs a new SmapStratum object for the given stratum name + * (e.g., JSP). + * + * @param stratumName the name of the stratum (e.g., JSP) + */ + public SmapStratum(String stratumName) { + this.stratumName = stratumName; + fileNameList = new ArrayList(); + filePathList = new ArrayList(); + lineData = new ArrayList(); + lastFileID = 0; + } + + //********************************************************************* + // Methods to add mapping information + + /** + * Adds record of a new file, by filename. + * + * @param filename the filename to add, unqualified by path. + */ + public void addFile(String filename) { + addFile(filename, filename); + } + + /** + * Adds record of a new file, by filename and path. The path + * may be relative to a source compilation path. + * + * @param filename the filename to add, unqualified by path + * @param filePath the path for the filename, potentially relative + * to a source compilation path + */ + public void addFile(String filename, String filePath) { + int pathIndex = filePathList.indexOf(filePath); + if (pathIndex == -1) { + fileNameList.add(filename); + filePathList.add(filePath); + } + } + + /** + * Combines consecutive LineInfos wherever possible + */ + public void optimizeLineSection() { + +/* Some debugging code + for (int i = 0; i < lineData.size(); i++) { + LineInfo li = (LineInfo)lineData.get(i); + System.out.print(li.toString()); + } +*/ + //Incorporate each LineInfo into the previous LineInfo's + //outputLineIncrement, if possible + int i = 0; + while (i < lineData.size() - 1) { + LineInfo li = (LineInfo)lineData.get(i); + LineInfo liNext = (LineInfo)lineData.get(i + 1); + if (!liNext.lineFileIDSet + && liNext.inputStartLine == li.inputStartLine + && liNext.inputLineCount == 1 + && li.inputLineCount == 1 + && liNext.outputStartLine + == li.outputStartLine + + li.inputLineCount * li.outputLineIncrement) { + li.setOutputLineIncrement( + liNext.outputStartLine + - li.outputStartLine + + liNext.outputLineIncrement); + lineData.remove(i + 1); + } else { + i++; + } + } + + //Incorporate each LineInfo into the previous LineInfo's + //inputLineCount, if possible + i = 0; + while (i < lineData.size() - 1) { + LineInfo li = (LineInfo)lineData.get(i); + LineInfo liNext = (LineInfo)lineData.get(i + 1); + if (!liNext.lineFileIDSet + && liNext.inputStartLine == li.inputStartLine + li.inputLineCount + && liNext.outputLineIncrement == li.outputLineIncrement + && liNext.outputStartLine + == li.outputStartLine + + li.inputLineCount * li.outputLineIncrement) { + li.setInputLineCount(li.inputLineCount + liNext.inputLineCount); + lineData.remove(i + 1); + } else { + i++; + } + } + } + + /** + * Adds complete information about a simple line mapping. Specify + * all the fields in this method; the back-end machinery takes care + * of printing only those that are necessary in the final SMAP. + * (My view is that fields are optional primarily for spatial efficiency, + * not for programmer convenience. Could always add utility methods + * later.) + * + * @param inputStartLine starting line in the source file + * (SMAP InputStartLine) + * @param inputFileName the filepath (or name) from which the input comes + * (yields SMAP LineFileID) Use unqualified names + * carefully, and only when they uniquely identify a file. + * @param inputLineCount the number of lines in the input to map + * (SMAP LineFileCount) + * @param outputStartLine starting line in the output file + * (SMAP OutputStartLine) + * @param outputLineIncrement number of output lines to map to each + * input line (SMAP OutputLineIncrement). Given the + * fact that the name starts with "output", I continuously have + * the subconscious urge to call this field + * OutputLineExcrement. + */ + public void addLineData( + int inputStartLine, + String inputFileName, + int inputLineCount, + int outputStartLine, + int outputLineIncrement) { + // check the input - what are you doing here?? + int fileIndex = filePathList.indexOf(inputFileName); + if (fileIndex == -1) // still + throw new IllegalArgumentException( + "inputFileName: " + inputFileName); + + //Jasper incorrectly SMAPs certain Nodes, giving them an + //outputStartLine of 0. This can cause a fatal error in + //optimizeLineSection, making it impossible for Jasper to + //compile the JSP. Until we can fix the underlying + //SMAPping problem, we simply ignore the flawed SMAP entries. + if (outputStartLine == 0) + return; + + // build the LineInfo + LineInfo li = new LineInfo(); + li.setInputStartLine(inputStartLine); + li.setInputLineCount(inputLineCount); + li.setOutputStartLine(outputStartLine); + li.setOutputLineIncrement(outputLineIncrement); + if (fileIndex != lastFileID) + li.setLineFileID(fileIndex); + lastFileID = fileIndex; + + // save it + lineData.add(li); + } + + //********************************************************************* + // Methods to retrieve information + + /** + * Returns the name of the stratum. + */ + public String getStratumName() { + return stratumName; + } + + /** + * Returns the given stratum as a String: a StratumSection, + * followed by at least one FileSection and at least one LineSection. + */ + public String getString() { + // check state and initialize buffer + if (fileNameList.size() == 0 || lineData.size() == 0) + return null; + + StringBuffer out = new StringBuffer(); + + // print StratumSection + out.append("*S " + stratumName + "\n"); + + // print FileSection + out.append("*F\n"); + int bound = fileNameList.size(); + for (int i = 0; i < bound; i++) { + if (filePathList.get(i) != null) { + out.append("+ " + i + " " + fileNameList.get(i) + "\n"); + // Source paths must be relative, not absolute, so we + // remove the leading "/", if one exists. + String filePath = (String)filePathList.get(i); + if (filePath.startsWith("/")) { + filePath = filePath.substring(1); + } + out.append(filePath + "\n"); + } else { + out.append(i + " " + fileNameList.get(i) + "\n"); + } + } + + // print LineSection + out.append("*L\n"); + bound = lineData.size(); + for (int i = 0; i < bound; i++) { + LineInfo li = (LineInfo)lineData.get(i); + out.append(li.getString()); + } + + return out.toString(); + } + + public String toString() { + return getString(); + } + +} diff --git a/java/org/apache/jasper/compiler/SmapUtil.java b/java/org/apache/jasper/compiler/SmapUtil.java index 7da1fba00..8ff4a38f4 100644 --- a/java/org/apache/jasper/compiler/SmapUtil.java +++ b/java/org/apache/jasper/compiler/SmapUtil.java @@ -1,728 +1,728 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; - -/** - * Contains static utilities for generating SMAP data based on the - * current version of Jasper. - * - * @author Jayson Falkner - * @author Shawn Bayern - * @author Robert Field (inner SDEInstaller class) - * @author Mark Roth - * @author Kin-man Chung - */ -public class SmapUtil { - - private org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SmapUtil.class ); - - //********************************************************************* - // Constants - - public static final String SMAP_ENCODING = "UTF-8"; - - //********************************************************************* - // Public entry points - - /** - * Generates an appropriate SMAP representing the current compilation - * context. (JSR-045.) - * - * @param ctxt Current compilation context - * @param pageNodes The current JSP page - * @return a SMAP for the page - */ - public static String[] generateSmap( - JspCompilationContext ctxt, - Node.Nodes pageNodes) - throws IOException { - - // Scan the nodes for presence of Jasper generated inner classes - PreScanVisitor psVisitor = new PreScanVisitor(); - try { - pageNodes.visit(psVisitor); - } catch (JasperException ex) { - } - HashMap map = psVisitor.getMap(); - - // set up our SMAP generator - SmapGenerator g = new SmapGenerator(); - - /** Disable reading of input SMAP because: - 1. There is a bug here: getRealPath() is null if .jsp is in a jar - Bugzilla 14660. - 2. Mappings from other sources into .jsp files are not supported. - TODO: fix 1. if 2. is not true. - // determine if we have an input SMAP - String smapPath = inputSmapPath(ctxt.getRealPath(ctxt.getJspFile())); - File inputSmap = new File(smapPath); - if (inputSmap.exists()) { - byte[] embeddedSmap = null; - byte[] subSmap = SDEInstaller.readWhole(inputSmap); - String subSmapString = new String(subSmap, SMAP_ENCODING); - g.addSmap(subSmapString, "JSP"); - } - **/ - - // now, assemble info about our own stratum (JSP) using JspLineMap - SmapStratum s = new SmapStratum("JSP"); - - g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); - - // Map out Node.Nodes - evaluateNodes(pageNodes, s, map, ctxt.getOptions().getMappedFile()); - s.optimizeLineSection(); - g.addStratum(s, true); - - if (ctxt.getOptions().isSmapDumped()) { - File outSmap = new File(ctxt.getClassFileName() + ".smap"); - PrintWriter so = - new PrintWriter( - new OutputStreamWriter( - new FileOutputStream(outSmap), - SMAP_ENCODING)); - so.print(g.getString()); - so.close(); - } - - String classFileName = ctxt.getClassFileName(); - int innerClassCount = map.size(); - String [] smapInfo = new String[2 + innerClassCount*2]; - smapInfo[0] = classFileName; - smapInfo[1] = g.getString(); - - int count = 2; - Iterator iter = map.entrySet().iterator(); - while (iter.hasNext()) { - Map.Entry entry = (Map.Entry) iter.next(); - String innerClass = (String) entry.getKey(); - s = (SmapStratum) entry.getValue(); - s.optimizeLineSection(); - g = new SmapGenerator(); - g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); - g.addStratum(s, true); - - String innerClassFileName = - classFileName.substring(0, classFileName.indexOf(".class")) + - '$' + innerClass + ".class"; - if (ctxt.getOptions().isSmapDumped()) { - File outSmap = new File(innerClassFileName + ".smap"); - PrintWriter so = - new PrintWriter( - new OutputStreamWriter( - new FileOutputStream(outSmap), - SMAP_ENCODING)); - so.print(g.getString()); - so.close(); - } - smapInfo[count] = innerClassFileName; - smapInfo[count+1] = g.getString(); - count += 2; - } - - return smapInfo; - } - - public static void installSmap(String[] smap) - throws IOException { - if (smap == null) { - return; - } - - for (int i = 0; i < smap.length; i += 2) { - File outServlet = new File(smap[i]); - SDEInstaller.install(outServlet, smap[i+1].getBytes()); - } - } - - //********************************************************************* - // Private utilities - - /** - * Returns an unqualified version of the given file path. - */ - private static String unqualify(String path) { - path = path.replace('\\', '/'); - return path.substring(path.lastIndexOf('/') + 1); - } - - /** - * Returns a file path corresponding to a potential SMAP input - * for the given compilation input (JSP file). - */ - private static String inputSmapPath(String path) { - return path.substring(0, path.lastIndexOf('.') + 1) + "smap"; - } - - //********************************************************************* - // Installation logic (from Robert Field, JSR-045 spec lead) - private static class SDEInstaller { - - private org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SDEInstaller.class ); - - static final String nameSDE = "SourceDebugExtension"; - - byte[] orig; - byte[] sdeAttr; - byte[] gen; - - int origPos = 0; - int genPos = 0; - - int sdeIndex; - - public static void main(String[] args) throws IOException { - if (args.length == 2) { - install(new File(args[0]), new File(args[1])); - } else if (args.length == 3) { - install( - new File(args[0]), - new File(args[1]), - new File(args[2])); - } else { - System.err.println( - "Usage: " - + " \n" - + " "); - } - } - - static void install(File inClassFile, File attrFile, File outClassFile) - throws IOException { - new SDEInstaller(inClassFile, attrFile, outClassFile); - } - - static void install(File inOutClassFile, File attrFile) - throws IOException { - File tmpFile = new File(inOutClassFile.getPath() + "tmp"); - new SDEInstaller(inOutClassFile, attrFile, tmpFile); - if (!inOutClassFile.delete()) { - throw new IOException("inOutClassFile.delete() failed"); - } - if (!tmpFile.renameTo(inOutClassFile)) { - throw new IOException("tmpFile.renameTo(inOutClassFile) failed"); - } - } - - static void install(File classFile, byte[] smap) throws IOException { - File tmpFile = new File(classFile.getPath() + "tmp"); - new SDEInstaller(classFile, smap, tmpFile); - if (!classFile.delete()) { - throw new IOException("classFile.delete() failed"); - } - if (!tmpFile.renameTo(classFile)) { - throw new IOException("tmpFile.renameTo(classFile) failed"); - } - } - - SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile) - throws IOException { - if (!inClassFile.exists()) { - throw new FileNotFoundException("no such file: " + inClassFile); - } - - this.sdeAttr = sdeAttr; - // get the bytes - orig = readWhole(inClassFile); - gen = new byte[orig.length + sdeAttr.length + 100]; - - // do it - addSDE(); - - // write result - FileOutputStream outStream = new FileOutputStream(outClassFile); - outStream.write(gen, 0, genPos); - outStream.close(); - } - - SDEInstaller(File inClassFile, File attrFile, File outClassFile) - throws IOException { - this(inClassFile, readWhole(attrFile), outClassFile); - } - - static byte[] readWhole(File input) throws IOException { - FileInputStream inStream = new FileInputStream(input); - int len = (int)input.length(); - byte[] bytes = new byte[len]; - if (inStream.read(bytes, 0, len) != len) { - throw new IOException("expected size: " + len); - } - inStream.close(); - return bytes; - } - - void addSDE() throws UnsupportedEncodingException, IOException { - int i; - copy(4 + 2 + 2); // magic min/maj version - int constantPoolCountPos = genPos; - int constantPoolCount = readU2(); - if (log.isDebugEnabled()) - log.debug("constant pool count: " + constantPoolCount); - writeU2(constantPoolCount); - - // copy old constant pool return index of SDE symbol, if found - sdeIndex = copyConstantPool(constantPoolCount); - if (sdeIndex < 0) { - // if "SourceDebugExtension" symbol not there add it - writeUtf8ForSDE(); - - // increment the countantPoolCount - sdeIndex = constantPoolCount; - ++constantPoolCount; - randomAccessWriteU2(constantPoolCountPos, constantPoolCount); - - if (log.isDebugEnabled()) - log.debug("SourceDebugExtension not found, installed at: " + sdeIndex); - } else { - if (log.isDebugEnabled()) - log.debug("SourceDebugExtension found at: " + sdeIndex); - } - copy(2 + 2 + 2); // access, this, super - int interfaceCount = readU2(); - writeU2(interfaceCount); - if (log.isDebugEnabled()) - log.debug("interfaceCount: " + interfaceCount); - copy(interfaceCount * 2); - copyMembers(); // fields - copyMembers(); // methods - int attrCountPos = genPos; - int attrCount = readU2(); - writeU2(attrCount); - if (log.isDebugEnabled()) - log.debug("class attrCount: " + attrCount); - // copy the class attributes, return true if SDE attr found (not copied) - if (!copyAttrs(attrCount)) { - // we will be adding SDE and it isn't already counted - ++attrCount; - randomAccessWriteU2(attrCountPos, attrCount); - if (log.isDebugEnabled()) - log.debug("class attrCount incremented"); - } - writeAttrForSDE(sdeIndex); - } - - void copyMembers() { - int count = readU2(); - writeU2(count); - if (log.isDebugEnabled()) - log.debug("members count: " + count); - for (int i = 0; i < count; ++i) { - copy(6); // access, name, descriptor - int attrCount = readU2(); - writeU2(attrCount); - if (log.isDebugEnabled()) - log.debug("member attr count: " + attrCount); - copyAttrs(attrCount); - } - } - - boolean copyAttrs(int attrCount) { - boolean sdeFound = false; - for (int i = 0; i < attrCount; ++i) { - int nameIndex = readU2(); - // don't write old SDE - if (nameIndex == sdeIndex) { - sdeFound = true; - if (log.isDebugEnabled()) - log.debug("SDE attr found"); - } else { - writeU2(nameIndex); // name - int len = readU4(); - writeU4(len); - copy(len); - if (log.isDebugEnabled()) - log.debug("attr len: " + len); - } - } - return sdeFound; - } - - void writeAttrForSDE(int index) { - writeU2(index); - writeU4(sdeAttr.length); - for (int i = 0; i < sdeAttr.length; ++i) { - writeU1(sdeAttr[i]); - } - } - - void randomAccessWriteU2(int pos, int val) { - int savePos = genPos; - genPos = pos; - writeU2(val); - genPos = savePos; - } - - int readU1() { - return ((int)orig[origPos++]) & 0xFF; - } - - int readU2() { - int res = readU1(); - return (res << 8) + readU1(); - } - - int readU4() { - int res = readU2(); - return (res << 16) + readU2(); - } - - void writeU1(int val) { - gen[genPos++] = (byte)val; - } - - void writeU2(int val) { - writeU1(val >> 8); - writeU1(val & 0xFF); - } - - void writeU4(int val) { - writeU2(val >> 16); - writeU2(val & 0xFFFF); - } - - void copy(int count) { - for (int i = 0; i < count; ++i) { - gen[genPos++] = orig[origPos++]; - } - } - - byte[] readBytes(int count) { - byte[] bytes = new byte[count]; - for (int i = 0; i < count; ++i) { - bytes[i] = orig[origPos++]; - } - return bytes; - } - - void writeBytes(byte[] bytes) { - for (int i = 0; i < bytes.length; ++i) { - gen[genPos++] = bytes[i]; - } - } - - int copyConstantPool(int constantPoolCount) - throws UnsupportedEncodingException, IOException { - int sdeIndex = -1; - // copy const pool index zero not in class file - for (int i = 1; i < constantPoolCount; ++i) { - int tag = readU1(); - writeU1(tag); - switch (tag) { - case 7 : // Class - case 8 : // String - if (log.isDebugEnabled()) - log.debug(i + " copying 2 bytes"); - copy(2); - break; - case 9 : // Field - case 10 : // Method - case 11 : // InterfaceMethod - case 3 : // Integer - case 4 : // Float - case 12 : // NameAndType - if (log.isDebugEnabled()) - log.debug(i + " copying 4 bytes"); - copy(4); - break; - case 5 : // Long - case 6 : // Double - if (log.isDebugEnabled()) - log.debug(i + " copying 8 bytes"); - copy(8); - i++; - break; - case 1 : // Utf8 - int len = readU2(); - writeU2(len); - byte[] utf8 = readBytes(len); - String str = new String(utf8, "UTF-8"); - if (log.isDebugEnabled()) - log.debug(i + " read class attr -- '" + str + "'"); - if (str.equals(nameSDE)) { - sdeIndex = i; - } - writeBytes(utf8); - break; - default : - throw new IOException("unexpected tag: " + tag); - } - } - return sdeIndex; - } - - void writeUtf8ForSDE() { - int len = nameSDE.length(); - writeU1(1); // Utf8 tag - writeU2(len); - for (int i = 0; i < len; ++i) { - writeU1(nameSDE.charAt(i)); - } - } - } - - public static void evaluateNodes( - Node.Nodes nodes, - SmapStratum s, - HashMap innerClassMap, - boolean breakAtLF) { - try { - nodes.visit(new SmapGenVisitor(s, breakAtLF, innerClassMap)); - } catch (JasperException ex) { - } - } - - static class SmapGenVisitor extends Node.Visitor { - - private SmapStratum smap; - private boolean breakAtLF; - private HashMap innerClassMap; - - SmapGenVisitor(SmapStratum s, boolean breakAtLF, HashMap map) { - this.smap = s; - this.breakAtLF = breakAtLF; - this.innerClassMap = map; - } - - public void visitBody(Node n) throws JasperException { - SmapStratum smapSave = smap; - String innerClass = n.getInnerClassName(); - if (innerClass != null) { - this.smap = (SmapStratum) innerClassMap.get(innerClass); - } - super.visitBody(n); - smap = smapSave; - } - - public void visit(Node.Declaration n) throws JasperException { - doSmapText(n); - } - - public void visit(Node.Expression n) throws JasperException { - doSmapText(n); - } - - public void visit(Node.Scriptlet n) throws JasperException { - doSmapText(n); - } - - public void visit(Node.IncludeAction n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.ForwardAction n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.GetProperty n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.SetProperty n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.UseBean n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.PlugIn n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.CustomTag n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.UninterpretedTag n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.JspElement n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.JspText n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - visitBody(n); - } - - public void visit(Node.JspBody n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.InvokeAction n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.DoBodyAction n) throws JasperException { - doSmap(n); - visitBody(n); - } - - public void visit(Node.ELExpression n) throws JasperException { - doSmap(n); - } - - public void visit(Node.TemplateText n) throws JasperException { - Mark mark = n.getStart(); - if (mark == null) { - return; - } - - //Add the file information - String fileName = mark.getFile(); - smap.addFile(unqualify(fileName), fileName); - - //Add a LineInfo that corresponds to the beginning of this node - int iInputStartLine = mark.getLineNumber(); - int iOutputStartLine = n.getBeginJavaLine(); - int iOutputLineIncrement = breakAtLF? 1: 0; - smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine, - iOutputLineIncrement); - - // Output additional mappings in the text - java.util.ArrayList extraSmap = n.getExtraSmap(); - - if (extraSmap != null) { - for (int i = 0; i < extraSmap.size(); i++) { - iOutputStartLine += iOutputLineIncrement; - smap.addLineData( - iInputStartLine+((Integer)extraSmap.get(i)).intValue(), - fileName, - 1, - iOutputStartLine, - iOutputLineIncrement); - } - } - } - - private void doSmap( - Node n, - int inLineCount, - int outIncrement, - int skippedLines) { - Mark mark = n.getStart(); - if (mark == null) { - return; - } - - String unqualifiedName = unqualify(mark.getFile()); - smap.addFile(unqualifiedName, mark.getFile()); - smap.addLineData( - mark.getLineNumber() + skippedLines, - mark.getFile(), - inLineCount - skippedLines, - n.getBeginJavaLine() + skippedLines, - outIncrement); - } - - private void doSmap(Node n) { - doSmap(n, 1, n.getEndJavaLine() - n.getBeginJavaLine(), 0); - } - - private void doSmapText(Node n) { - String text = n.getText(); - int index = 0; - int next = 0; - int lineCount = 1; - int skippedLines = 0; - boolean slashStarSeen = false; - boolean beginning = true; - - // Count lines inside text, but skipping comment lines at the - // beginning of the text. - while ((next = text.indexOf('\n', index)) > -1) { - if (beginning) { - String line = text.substring(index, next).trim(); - if (!slashStarSeen && line.startsWith("/*")) { - slashStarSeen = true; - } - if (slashStarSeen) { - skippedLines++; - int endIndex = line.indexOf("*/"); - if (endIndex >= 0) { - // End of /* */ comment - slashStarSeen = false; - if (endIndex < line.length() - 2) { - // Some executable code after comment - skippedLines--; - beginning = false; - } - } - } else if (line.length() == 0 || line.startsWith("//")) { - skippedLines++; - } else { - beginning = false; - } - } - lineCount++; - index = next + 1; - } - - doSmap(n, lineCount, 1, skippedLines); - } - } - - private static class PreScanVisitor extends Node.Visitor { - - HashMap map = new HashMap(); - - public void doVisit(Node n) { - String inner = n.getInnerClassName(); - if (inner != null && !map.containsKey(inner)) { - map.put(inner, new SmapStratum("JSP")); - } - } - - HashMap getMap() { - return map; - } - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; + +/** + * Contains static utilities for generating SMAP data based on the + * current version of Jasper. + * + * @author Jayson Falkner + * @author Shawn Bayern + * @author Robert Field (inner SDEInstaller class) + * @author Mark Roth + * @author Kin-man Chung + */ +public class SmapUtil { + + private org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SmapUtil.class ); + + //********************************************************************* + // Constants + + public static final String SMAP_ENCODING = "UTF-8"; + + //********************************************************************* + // Public entry points + + /** + * Generates an appropriate SMAP representing the current compilation + * context. (JSR-045.) + * + * @param ctxt Current compilation context + * @param pageNodes The current JSP page + * @return a SMAP for the page + */ + public static String[] generateSmap( + JspCompilationContext ctxt, + Node.Nodes pageNodes) + throws IOException { + + // Scan the nodes for presence of Jasper generated inner classes + PreScanVisitor psVisitor = new PreScanVisitor(); + try { + pageNodes.visit(psVisitor); + } catch (JasperException ex) { + } + HashMap map = psVisitor.getMap(); + + // set up our SMAP generator + SmapGenerator g = new SmapGenerator(); + + /** Disable reading of input SMAP because: + 1. There is a bug here: getRealPath() is null if .jsp is in a jar + Bugzilla 14660. + 2. Mappings from other sources into .jsp files are not supported. + TODO: fix 1. if 2. is not true. + // determine if we have an input SMAP + String smapPath = inputSmapPath(ctxt.getRealPath(ctxt.getJspFile())); + File inputSmap = new File(smapPath); + if (inputSmap.exists()) { + byte[] embeddedSmap = null; + byte[] subSmap = SDEInstaller.readWhole(inputSmap); + String subSmapString = new String(subSmap, SMAP_ENCODING); + g.addSmap(subSmapString, "JSP"); + } + **/ + + // now, assemble info about our own stratum (JSP) using JspLineMap + SmapStratum s = new SmapStratum("JSP"); + + g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); + + // Map out Node.Nodes + evaluateNodes(pageNodes, s, map, ctxt.getOptions().getMappedFile()); + s.optimizeLineSection(); + g.addStratum(s, true); + + if (ctxt.getOptions().isSmapDumped()) { + File outSmap = new File(ctxt.getClassFileName() + ".smap"); + PrintWriter so = + new PrintWriter( + new OutputStreamWriter( + new FileOutputStream(outSmap), + SMAP_ENCODING)); + so.print(g.getString()); + so.close(); + } + + String classFileName = ctxt.getClassFileName(); + int innerClassCount = map.size(); + String [] smapInfo = new String[2 + innerClassCount*2]; + smapInfo[0] = classFileName; + smapInfo[1] = g.getString(); + + int count = 2; + Iterator iter = map.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry) iter.next(); + String innerClass = (String) entry.getKey(); + s = (SmapStratum) entry.getValue(); + s.optimizeLineSection(); + g = new SmapGenerator(); + g.setOutputFileName(unqualify(ctxt.getServletJavaFileName())); + g.addStratum(s, true); + + String innerClassFileName = + classFileName.substring(0, classFileName.indexOf(".class")) + + '$' + innerClass + ".class"; + if (ctxt.getOptions().isSmapDumped()) { + File outSmap = new File(innerClassFileName + ".smap"); + PrintWriter so = + new PrintWriter( + new OutputStreamWriter( + new FileOutputStream(outSmap), + SMAP_ENCODING)); + so.print(g.getString()); + so.close(); + } + smapInfo[count] = innerClassFileName; + smapInfo[count+1] = g.getString(); + count += 2; + } + + return smapInfo; + } + + public static void installSmap(String[] smap) + throws IOException { + if (smap == null) { + return; + } + + for (int i = 0; i < smap.length; i += 2) { + File outServlet = new File(smap[i]); + SDEInstaller.install(outServlet, smap[i+1].getBytes()); + } + } + + //********************************************************************* + // Private utilities + + /** + * Returns an unqualified version of the given file path. + */ + private static String unqualify(String path) { + path = path.replace('\\', '/'); + return path.substring(path.lastIndexOf('/') + 1); + } + + /** + * Returns a file path corresponding to a potential SMAP input + * for the given compilation input (JSP file). + */ + private static String inputSmapPath(String path) { + return path.substring(0, path.lastIndexOf('.') + 1) + "smap"; + } + + //********************************************************************* + // Installation logic (from Robert Field, JSR-045 spec lead) + private static class SDEInstaller { + + private org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SDEInstaller.class ); + + static final String nameSDE = "SourceDebugExtension"; + + byte[] orig; + byte[] sdeAttr; + byte[] gen; + + int origPos = 0; + int genPos = 0; + + int sdeIndex; + + public static void main(String[] args) throws IOException { + if (args.length == 2) { + install(new File(args[0]), new File(args[1])); + } else if (args.length == 3) { + install( + new File(args[0]), + new File(args[1]), + new File(args[2])); + } else { + System.err.println( + "Usage: " + + " \n" + + " "); + } + } + + static void install(File inClassFile, File attrFile, File outClassFile) + throws IOException { + new SDEInstaller(inClassFile, attrFile, outClassFile); + } + + static void install(File inOutClassFile, File attrFile) + throws IOException { + File tmpFile = new File(inOutClassFile.getPath() + "tmp"); + new SDEInstaller(inOutClassFile, attrFile, tmpFile); + if (!inOutClassFile.delete()) { + throw new IOException("inOutClassFile.delete() failed"); + } + if (!tmpFile.renameTo(inOutClassFile)) { + throw new IOException("tmpFile.renameTo(inOutClassFile) failed"); + } + } + + static void install(File classFile, byte[] smap) throws IOException { + File tmpFile = new File(classFile.getPath() + "tmp"); + new SDEInstaller(classFile, smap, tmpFile); + if (!classFile.delete()) { + throw new IOException("classFile.delete() failed"); + } + if (!tmpFile.renameTo(classFile)) { + throw new IOException("tmpFile.renameTo(classFile) failed"); + } + } + + SDEInstaller(File inClassFile, byte[] sdeAttr, File outClassFile) + throws IOException { + if (!inClassFile.exists()) { + throw new FileNotFoundException("no such file: " + inClassFile); + } + + this.sdeAttr = sdeAttr; + // get the bytes + orig = readWhole(inClassFile); + gen = new byte[orig.length + sdeAttr.length + 100]; + + // do it + addSDE(); + + // write result + FileOutputStream outStream = new FileOutputStream(outClassFile); + outStream.write(gen, 0, genPos); + outStream.close(); + } + + SDEInstaller(File inClassFile, File attrFile, File outClassFile) + throws IOException { + this(inClassFile, readWhole(attrFile), outClassFile); + } + + static byte[] readWhole(File input) throws IOException { + FileInputStream inStream = new FileInputStream(input); + int len = (int)input.length(); + byte[] bytes = new byte[len]; + if (inStream.read(bytes, 0, len) != len) { + throw new IOException("expected size: " + len); + } + inStream.close(); + return bytes; + } + + void addSDE() throws UnsupportedEncodingException, IOException { + int i; + copy(4 + 2 + 2); // magic min/maj version + int constantPoolCountPos = genPos; + int constantPoolCount = readU2(); + if (log.isDebugEnabled()) + log.debug("constant pool count: " + constantPoolCount); + writeU2(constantPoolCount); + + // copy old constant pool return index of SDE symbol, if found + sdeIndex = copyConstantPool(constantPoolCount); + if (sdeIndex < 0) { + // if "SourceDebugExtension" symbol not there add it + writeUtf8ForSDE(); + + // increment the countantPoolCount + sdeIndex = constantPoolCount; + ++constantPoolCount; + randomAccessWriteU2(constantPoolCountPos, constantPoolCount); + + if (log.isDebugEnabled()) + log.debug("SourceDebugExtension not found, installed at: " + sdeIndex); + } else { + if (log.isDebugEnabled()) + log.debug("SourceDebugExtension found at: " + sdeIndex); + } + copy(2 + 2 + 2); // access, this, super + int interfaceCount = readU2(); + writeU2(interfaceCount); + if (log.isDebugEnabled()) + log.debug("interfaceCount: " + interfaceCount); + copy(interfaceCount * 2); + copyMembers(); // fields + copyMembers(); // methods + int attrCountPos = genPos; + int attrCount = readU2(); + writeU2(attrCount); + if (log.isDebugEnabled()) + log.debug("class attrCount: " + attrCount); + // copy the class attributes, return true if SDE attr found (not copied) + if (!copyAttrs(attrCount)) { + // we will be adding SDE and it isn't already counted + ++attrCount; + randomAccessWriteU2(attrCountPos, attrCount); + if (log.isDebugEnabled()) + log.debug("class attrCount incremented"); + } + writeAttrForSDE(sdeIndex); + } + + void copyMembers() { + int count = readU2(); + writeU2(count); + if (log.isDebugEnabled()) + log.debug("members count: " + count); + for (int i = 0; i < count; ++i) { + copy(6); // access, name, descriptor + int attrCount = readU2(); + writeU2(attrCount); + if (log.isDebugEnabled()) + log.debug("member attr count: " + attrCount); + copyAttrs(attrCount); + } + } + + boolean copyAttrs(int attrCount) { + boolean sdeFound = false; + for (int i = 0; i < attrCount; ++i) { + int nameIndex = readU2(); + // don't write old SDE + if (nameIndex == sdeIndex) { + sdeFound = true; + if (log.isDebugEnabled()) + log.debug("SDE attr found"); + } else { + writeU2(nameIndex); // name + int len = readU4(); + writeU4(len); + copy(len); + if (log.isDebugEnabled()) + log.debug("attr len: " + len); + } + } + return sdeFound; + } + + void writeAttrForSDE(int index) { + writeU2(index); + writeU4(sdeAttr.length); + for (int i = 0; i < sdeAttr.length; ++i) { + writeU1(sdeAttr[i]); + } + } + + void randomAccessWriteU2(int pos, int val) { + int savePos = genPos; + genPos = pos; + writeU2(val); + genPos = savePos; + } + + int readU1() { + return ((int)orig[origPos++]) & 0xFF; + } + + int readU2() { + int res = readU1(); + return (res << 8) + readU1(); + } + + int readU4() { + int res = readU2(); + return (res << 16) + readU2(); + } + + void writeU1(int val) { + gen[genPos++] = (byte)val; + } + + void writeU2(int val) { + writeU1(val >> 8); + writeU1(val & 0xFF); + } + + void writeU4(int val) { + writeU2(val >> 16); + writeU2(val & 0xFFFF); + } + + void copy(int count) { + for (int i = 0; i < count; ++i) { + gen[genPos++] = orig[origPos++]; + } + } + + byte[] readBytes(int count) { + byte[] bytes = new byte[count]; + for (int i = 0; i < count; ++i) { + bytes[i] = orig[origPos++]; + } + return bytes; + } + + void writeBytes(byte[] bytes) { + for (int i = 0; i < bytes.length; ++i) { + gen[genPos++] = bytes[i]; + } + } + + int copyConstantPool(int constantPoolCount) + throws UnsupportedEncodingException, IOException { + int sdeIndex = -1; + // copy const pool index zero not in class file + for (int i = 1; i < constantPoolCount; ++i) { + int tag = readU1(); + writeU1(tag); + switch (tag) { + case 7 : // Class + case 8 : // String + if (log.isDebugEnabled()) + log.debug(i + " copying 2 bytes"); + copy(2); + break; + case 9 : // Field + case 10 : // Method + case 11 : // InterfaceMethod + case 3 : // Integer + case 4 : // Float + case 12 : // NameAndType + if (log.isDebugEnabled()) + log.debug(i + " copying 4 bytes"); + copy(4); + break; + case 5 : // Long + case 6 : // Double + if (log.isDebugEnabled()) + log.debug(i + " copying 8 bytes"); + copy(8); + i++; + break; + case 1 : // Utf8 + int len = readU2(); + writeU2(len); + byte[] utf8 = readBytes(len); + String str = new String(utf8, "UTF-8"); + if (log.isDebugEnabled()) + log.debug(i + " read class attr -- '" + str + "'"); + if (str.equals(nameSDE)) { + sdeIndex = i; + } + writeBytes(utf8); + break; + default : + throw new IOException("unexpected tag: " + tag); + } + } + return sdeIndex; + } + + void writeUtf8ForSDE() { + int len = nameSDE.length(); + writeU1(1); // Utf8 tag + writeU2(len); + for (int i = 0; i < len; ++i) { + writeU1(nameSDE.charAt(i)); + } + } + } + + public static void evaluateNodes( + Node.Nodes nodes, + SmapStratum s, + HashMap innerClassMap, + boolean breakAtLF) { + try { + nodes.visit(new SmapGenVisitor(s, breakAtLF, innerClassMap)); + } catch (JasperException ex) { + } + } + + static class SmapGenVisitor extends Node.Visitor { + + private SmapStratum smap; + private boolean breakAtLF; + private HashMap innerClassMap; + + SmapGenVisitor(SmapStratum s, boolean breakAtLF, HashMap map) { + this.smap = s; + this.breakAtLF = breakAtLF; + this.innerClassMap = map; + } + + public void visitBody(Node n) throws JasperException { + SmapStratum smapSave = smap; + String innerClass = n.getInnerClassName(); + if (innerClass != null) { + this.smap = (SmapStratum) innerClassMap.get(innerClass); + } + super.visitBody(n); + smap = smapSave; + } + + public void visit(Node.Declaration n) throws JasperException { + doSmapText(n); + } + + public void visit(Node.Expression n) throws JasperException { + doSmapText(n); + } + + public void visit(Node.Scriptlet n) throws JasperException { + doSmapText(n); + } + + public void visit(Node.IncludeAction n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.ForwardAction n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.GetProperty n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.SetProperty n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.UseBean n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.PlugIn n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.CustomTag n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.UninterpretedTag n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.JspElement n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.JspText n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + visitBody(n); + } + + public void visit(Node.JspBody n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.InvokeAction n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.DoBodyAction n) throws JasperException { + doSmap(n); + visitBody(n); + } + + public void visit(Node.ELExpression n) throws JasperException { + doSmap(n); + } + + public void visit(Node.TemplateText n) throws JasperException { + Mark mark = n.getStart(); + if (mark == null) { + return; + } + + //Add the file information + String fileName = mark.getFile(); + smap.addFile(unqualify(fileName), fileName); + + //Add a LineInfo that corresponds to the beginning of this node + int iInputStartLine = mark.getLineNumber(); + int iOutputStartLine = n.getBeginJavaLine(); + int iOutputLineIncrement = breakAtLF? 1: 0; + smap.addLineData(iInputStartLine, fileName, 1, iOutputStartLine, + iOutputLineIncrement); + + // Output additional mappings in the text + java.util.ArrayList extraSmap = n.getExtraSmap(); + + if (extraSmap != null) { + for (int i = 0; i < extraSmap.size(); i++) { + iOutputStartLine += iOutputLineIncrement; + smap.addLineData( + iInputStartLine+((Integer)extraSmap.get(i)).intValue(), + fileName, + 1, + iOutputStartLine, + iOutputLineIncrement); + } + } + } + + private void doSmap( + Node n, + int inLineCount, + int outIncrement, + int skippedLines) { + Mark mark = n.getStart(); + if (mark == null) { + return; + } + + String unqualifiedName = unqualify(mark.getFile()); + smap.addFile(unqualifiedName, mark.getFile()); + smap.addLineData( + mark.getLineNumber() + skippedLines, + mark.getFile(), + inLineCount - skippedLines, + n.getBeginJavaLine() + skippedLines, + outIncrement); + } + + private void doSmap(Node n) { + doSmap(n, 1, n.getEndJavaLine() - n.getBeginJavaLine(), 0); + } + + private void doSmapText(Node n) { + String text = n.getText(); + int index = 0; + int next = 0; + int lineCount = 1; + int skippedLines = 0; + boolean slashStarSeen = false; + boolean beginning = true; + + // Count lines inside text, but skipping comment lines at the + // beginning of the text. + while ((next = text.indexOf('\n', index)) > -1) { + if (beginning) { + String line = text.substring(index, next).trim(); + if (!slashStarSeen && line.startsWith("/*")) { + slashStarSeen = true; + } + if (slashStarSeen) { + skippedLines++; + int endIndex = line.indexOf("*/"); + if (endIndex >= 0) { + // End of /* */ comment + slashStarSeen = false; + if (endIndex < line.length() - 2) { + // Some executable code after comment + skippedLines--; + beginning = false; + } + } + } else if (line.length() == 0 || line.startsWith("//")) { + skippedLines++; + } else { + beginning = false; + } + } + lineCount++; + index = next + 1; + } + + doSmap(n, lineCount, 1, skippedLines); + } + } + + private static class PreScanVisitor extends Node.Visitor { + + HashMap map = new HashMap(); + + public void doVisit(Node n) { + String inner = n.getInnerClassName(); + if (inner != null && !map.containsKey(inner)) { + map.put(inner, new SmapStratum("JSP")); + } + } + + HashMap getMap() { + return map; + } + } + +} diff --git a/java/org/apache/jasper/compiler/TagConstants.java b/java/org/apache/jasper/compiler/TagConstants.java index ec7054ba9..ce118af2b 100644 --- a/java/org/apache/jasper/compiler/TagConstants.java +++ b/java/org/apache/jasper/compiler/TagConstants.java @@ -1,115 +1,115 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -public interface TagConstants { - - public static final String JSP_URI = "http://java.sun.com/JSP/Page"; - - public static final String DIRECTIVE_ACTION = "directive."; - - public static final String ROOT_ACTION = "root"; - public static final String JSP_ROOT_ACTION = "jsp:root"; - - public static final String PAGE_DIRECTIVE_ACTION = "directive.page"; - public static final String JSP_PAGE_DIRECTIVE_ACTION = "jsp:directive.page"; - - public static final String INCLUDE_DIRECTIVE_ACTION = "directive.include"; - public static final String JSP_INCLUDE_DIRECTIVE_ACTION = "jsp:directive.include"; - - public static final String DECLARATION_ACTION = "declaration"; - public static final String JSP_DECLARATION_ACTION = "jsp:declaration"; - - public static final String SCRIPTLET_ACTION = "scriptlet"; - public static final String JSP_SCRIPTLET_ACTION = "jsp:scriptlet"; - - public static final String EXPRESSION_ACTION = "expression"; - public static final String JSP_EXPRESSION_ACTION = "jsp:expression"; - - public static final String USE_BEAN_ACTION = "useBean"; - public static final String JSP_USE_BEAN_ACTION = "jsp:useBean"; - - public static final String SET_PROPERTY_ACTION = "setProperty"; - public static final String JSP_SET_PROPERTY_ACTION = "jsp:setProperty"; - - public static final String GET_PROPERTY_ACTION = "getProperty"; - public static final String JSP_GET_PROPERTY_ACTION = "jsp:getProperty"; - - public static final String INCLUDE_ACTION = "include"; - public static final String JSP_INCLUDE_ACTION = "jsp:include"; - - public static final String FORWARD_ACTION = "forward"; - public static final String JSP_FORWARD_ACTION = "jsp:forward"; - - public static final String PARAM_ACTION = "param"; - public static final String JSP_PARAM_ACTION = "jsp:param"; - - public static final String PARAMS_ACTION = "params"; - public static final String JSP_PARAMS_ACTION = "jsp:params"; - - public static final String PLUGIN_ACTION = "plugin"; - public static final String JSP_PLUGIN_ACTION = "jsp:plugin"; - - public static final String FALLBACK_ACTION = "fallback"; - public static final String JSP_FALLBACK_ACTION = "jsp:fallback"; - - public static final String TEXT_ACTION = "text"; - public static final String JSP_TEXT_ACTION = "jsp:text"; - public static final String JSP_TEXT_ACTION_END = ""; - - public static final String ATTRIBUTE_ACTION = "attribute"; - public static final String JSP_ATTRIBUTE_ACTION = "jsp:attribute"; - - public static final String BODY_ACTION = "body"; - public static final String JSP_BODY_ACTION = "jsp:body"; - - public static final String ELEMENT_ACTION = "element"; - public static final String JSP_ELEMENT_ACTION = "jsp:element"; - - public static final String OUTPUT_ACTION = "output"; - public static final String JSP_OUTPUT_ACTION = "jsp:output"; - - public static final String TAGLIB_DIRECTIVE_ACTION = "taglib"; - public static final String JSP_TAGLIB_DIRECTIVE_ACTION = "jsp:taglib"; - - /* - * Tag Files - */ - public static final String INVOKE_ACTION = "invoke"; - public static final String JSP_INVOKE_ACTION = "jsp:invoke"; - - public static final String DOBODY_ACTION = "doBody"; - public static final String JSP_DOBODY_ACTION = "jsp:doBody"; - - /* - * Tag File Directives - */ - public static final String TAG_DIRECTIVE_ACTION = "directive.tag"; - public static final String JSP_TAG_DIRECTIVE_ACTION = "jsp:directive.tag"; - - public static final String ATTRIBUTE_DIRECTIVE_ACTION = "directive.attribute"; - public static final String JSP_ATTRIBUTE_DIRECTIVE_ACTION = "jsp:directive.attribute"; - - public static final String VARIABLE_DIRECTIVE_ACTION = "directive.variable"; - public static final String JSP_VARIABLE_DIRECTIVE_ACTION = "jsp:directive.variable"; - - /* - * Directive attributes - */ - public static final String URN_JSPTAGDIR = "urn:jsptagdir:"; - public static final String URN_JSPTLD = "urn:jsptld:"; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +public interface TagConstants { + + public static final String JSP_URI = "http://java.sun.com/JSP/Page"; + + public static final String DIRECTIVE_ACTION = "directive."; + + public static final String ROOT_ACTION = "root"; + public static final String JSP_ROOT_ACTION = "jsp:root"; + + public static final String PAGE_DIRECTIVE_ACTION = "directive.page"; + public static final String JSP_PAGE_DIRECTIVE_ACTION = "jsp:directive.page"; + + public static final String INCLUDE_DIRECTIVE_ACTION = "directive.include"; + public static final String JSP_INCLUDE_DIRECTIVE_ACTION = "jsp:directive.include"; + + public static final String DECLARATION_ACTION = "declaration"; + public static final String JSP_DECLARATION_ACTION = "jsp:declaration"; + + public static final String SCRIPTLET_ACTION = "scriptlet"; + public static final String JSP_SCRIPTLET_ACTION = "jsp:scriptlet"; + + public static final String EXPRESSION_ACTION = "expression"; + public static final String JSP_EXPRESSION_ACTION = "jsp:expression"; + + public static final String USE_BEAN_ACTION = "useBean"; + public static final String JSP_USE_BEAN_ACTION = "jsp:useBean"; + + public static final String SET_PROPERTY_ACTION = "setProperty"; + public static final String JSP_SET_PROPERTY_ACTION = "jsp:setProperty"; + + public static final String GET_PROPERTY_ACTION = "getProperty"; + public static final String JSP_GET_PROPERTY_ACTION = "jsp:getProperty"; + + public static final String INCLUDE_ACTION = "include"; + public static final String JSP_INCLUDE_ACTION = "jsp:include"; + + public static final String FORWARD_ACTION = "forward"; + public static final String JSP_FORWARD_ACTION = "jsp:forward"; + + public static final String PARAM_ACTION = "param"; + public static final String JSP_PARAM_ACTION = "jsp:param"; + + public static final String PARAMS_ACTION = "params"; + public static final String JSP_PARAMS_ACTION = "jsp:params"; + + public static final String PLUGIN_ACTION = "plugin"; + public static final String JSP_PLUGIN_ACTION = "jsp:plugin"; + + public static final String FALLBACK_ACTION = "fallback"; + public static final String JSP_FALLBACK_ACTION = "jsp:fallback"; + + public static final String TEXT_ACTION = "text"; + public static final String JSP_TEXT_ACTION = "jsp:text"; + public static final String JSP_TEXT_ACTION_END = ""; + + public static final String ATTRIBUTE_ACTION = "attribute"; + public static final String JSP_ATTRIBUTE_ACTION = "jsp:attribute"; + + public static final String BODY_ACTION = "body"; + public static final String JSP_BODY_ACTION = "jsp:body"; + + public static final String ELEMENT_ACTION = "element"; + public static final String JSP_ELEMENT_ACTION = "jsp:element"; + + public static final String OUTPUT_ACTION = "output"; + public static final String JSP_OUTPUT_ACTION = "jsp:output"; + + public static final String TAGLIB_DIRECTIVE_ACTION = "taglib"; + public static final String JSP_TAGLIB_DIRECTIVE_ACTION = "jsp:taglib"; + + /* + * Tag Files + */ + public static final String INVOKE_ACTION = "invoke"; + public static final String JSP_INVOKE_ACTION = "jsp:invoke"; + + public static final String DOBODY_ACTION = "doBody"; + public static final String JSP_DOBODY_ACTION = "jsp:doBody"; + + /* + * Tag File Directives + */ + public static final String TAG_DIRECTIVE_ACTION = "directive.tag"; + public static final String JSP_TAG_DIRECTIVE_ACTION = "jsp:directive.tag"; + + public static final String ATTRIBUTE_DIRECTIVE_ACTION = "directive.attribute"; + public static final String JSP_ATTRIBUTE_DIRECTIVE_ACTION = "jsp:directive.attribute"; + + public static final String VARIABLE_DIRECTIVE_ACTION = "directive.variable"; + public static final String JSP_VARIABLE_DIRECTIVE_ACTION = "jsp:directive.variable"; + + /* + * Directive attributes + */ + public static final String URN_JSPTAGDIR = "urn:jsptagdir:"; + public static final String URN_JSPTLD = "urn:jsptld:"; +} diff --git a/java/org/apache/jasper/compiler/TagFileProcessor.java b/java/org/apache/jasper/compiler/TagFileProcessor.java index 863f2a938..bec57c2d2 100644 --- a/java/org/apache/jasper/compiler/TagFileProcessor.java +++ b/java/org/apache/jasper/compiler/TagFileProcessor.java @@ -1,646 +1,646 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.URL; -import java.net.URLClassLoader; -import java.util.Iterator; -import java.util.List; -import java.util.Vector; -import java.util.HashMap; - -import javax.el.MethodExpression; -import javax.el.ValueExpression; -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagExtraInfo; -import javax.servlet.jsp.tagext.TagFileInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; -import javax.servlet.jsp.tagext.TagVariableInfo; -import javax.servlet.jsp.tagext.VariableInfo; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.servlet.JspServletWrapper; -import org.apache.jasper.runtime.JspSourceDependent; - -/** - * 1. Processes and extracts the directive info in a tag file. 2. Compiles and - * loads tag files used in a JSP file. - * - * @author Kin-man Chung - */ - -class TagFileProcessor { - - private Vector tempVector; - - /** - * A visitor the tag file - */ - private static class TagFileDirectiveVisitor extends Node.Visitor { - - private static final JspUtil.ValidAttribute[] tagDirectiveAttrs = { - new JspUtil.ValidAttribute("display-name"), - new JspUtil.ValidAttribute("body-content"), - new JspUtil.ValidAttribute("dynamic-attributes"), - new JspUtil.ValidAttribute("small-icon"), - new JspUtil.ValidAttribute("large-icon"), - new JspUtil.ValidAttribute("description"), - new JspUtil.ValidAttribute("example"), - new JspUtil.ValidAttribute("pageEncoding"), - new JspUtil.ValidAttribute("language"), - new JspUtil.ValidAttribute("import"), - new JspUtil.ValidAttribute("isELIgnored") }; - - private static final JspUtil.ValidAttribute[] attributeDirectiveAttrs = { - new JspUtil.ValidAttribute("name", true), - new JspUtil.ValidAttribute("required"), - new JspUtil.ValidAttribute("fragment"), - new JspUtil.ValidAttribute("rtexprvalue"), - new JspUtil.ValidAttribute("type"), - new JspUtil.ValidAttribute("deferredValue"), // JSP 2.1 - new JspUtil.ValidAttribute("deferredValueType"), // JSP 2.1 - new JspUtil.ValidAttribute("deferredMethod"), // JSP 2 - new JspUtil.ValidAttribute("deferredMethodSignature"), // JSP 21 - new JspUtil.ValidAttribute("description") }; - - private static final JspUtil.ValidAttribute[] variableDirectiveAttrs = { - new JspUtil.ValidAttribute("name-given"), - new JspUtil.ValidAttribute("name-from-attribute"), - new JspUtil.ValidAttribute("alias"), - new JspUtil.ValidAttribute("variable-class"), - new JspUtil.ValidAttribute("scope"), - new JspUtil.ValidAttribute("declare"), - new JspUtil.ValidAttribute("description") }; - - private ErrorDispatcher err; - - private TagLibraryInfo tagLibInfo; - - private String name = null; - - private String path = null; - - private TagExtraInfo tei = null; - - private String bodycontent = null; - - private String description = null; - - private String displayName = null; - - private String smallIcon = null; - - private String largeIcon = null; - - private String dynamicAttrsMapName; - - private String example = null; - - private Vector attributeVector; - - private Vector variableVector; - - private static final String ATTR_NAME = "the name attribute of the attribute directive"; - - private static final String VAR_NAME_GIVEN = "the name-given attribute of the variable directive"; - - private static final String VAR_NAME_FROM = "the name-from-attribute attribute of the variable directive"; - - private static final String VAR_ALIAS = "the alias attribute of the variable directive"; - - private static final String TAG_DYNAMIC = "the dynamic-attributes attribute of the tag directive"; - - private HashMap nameTable = new HashMap(); - - private HashMap nameFromTable = new HashMap(); - - public TagFileDirectiveVisitor(Compiler compiler, - TagLibraryInfo tagLibInfo, String name, String path) { - err = compiler.getErrorDispatcher(); - this.tagLibInfo = tagLibInfo; - this.name = name; - this.path = path; - attributeVector = new Vector(); - variableVector = new Vector(); - } - - public void visit(Node.TagDirective n) throws JasperException { - - JspUtil.checkAttributes("Tag directive", n, tagDirectiveAttrs, err); - - bodycontent = checkConflict(n, bodycontent, "body-content"); - if (bodycontent != null - && !bodycontent - .equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY) - && !bodycontent - .equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT) - && !bodycontent - .equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) { - err.jspError(n, "jsp.error.tagdirective.badbodycontent", - bodycontent); - } - dynamicAttrsMapName = checkConflict(n, dynamicAttrsMapName, - "dynamic-attributes"); - if (dynamicAttrsMapName != null) { - checkUniqueName(dynamicAttrsMapName, TAG_DYNAMIC, n); - } - smallIcon = checkConflict(n, smallIcon, "small-icon"); - largeIcon = checkConflict(n, largeIcon, "large-icon"); - description = checkConflict(n, description, "description"); - displayName = checkConflict(n, displayName, "display-name"); - example = checkConflict(n, example, "example"); - } - - private String checkConflict(Node n, String oldAttrValue, String attr) - throws JasperException { - - String result = oldAttrValue; - String attrValue = n.getAttributeValue(attr); - if (attrValue != null) { - if (oldAttrValue != null && !oldAttrValue.equals(attrValue)) { - err.jspError(n, "jsp.error.tag.conflict.attr", attr, - oldAttrValue, attrValue); - } - result = attrValue; - } - return result; - } - - public void visit(Node.AttributeDirective n) throws JasperException { - - JspUtil.checkAttributes("Attribute directive", n, - attributeDirectiveAttrs, err); - - // JSP 2.1 Table JSP.8-3 - // handle deferredValue and deferredValueType - boolean deferredValue = false; - String deferredValueString = n.getAttributeValue("deferredValue"); - if (deferredValueString != null) { - deferredValue = JspUtil.booleanValue(deferredValueString); - } - String deferredValueType = n.getAttributeValue("deferredValueType"); - if (deferredValueType != null) { - deferredValue = true; - } else if (deferredValue) { - deferredValueType = "java.lang.Object"; - } else { - deferredValueType = "java.lang.String"; - } - - // JSP 2.1 Table JSP.8-3 - // handle deferredMethod and deferredMethodSignature - boolean deferredMethod = false; - String deferredMethodString = n.getAttributeValue("deferredMethod"); - if (deferredMethodString != null) { - deferredMethod = JspUtil.booleanValue(deferredMethodString); - } - String deferredMethodSignature = n - .getAttributeValue("deferredMethodSignature"); - if (deferredMethodSignature != null) { - deferredMethod = true; - } else if (deferredMethod) { - deferredMethodSignature = "void methodname()"; - } - - String attrName = n.getAttributeValue("name"); - boolean required = JspUtil.booleanValue(n - .getAttributeValue("required")); - boolean rtexprvalue = true; - String rtexprvalueString = n.getAttributeValue("rtexprvalue"); - if (rtexprvalueString != null) { - rtexprvalue = JspUtil.booleanValue(rtexprvalueString); - } - boolean fragment = JspUtil.booleanValue(n - .getAttributeValue("fragment")); - String type = n.getAttributeValue("type"); - if (fragment) { - // type is fixed to "JspFragment" and a translation error - // must occur if specified. - if (type != null) { - err.jspError(n, "jsp.error.fragmentwithtype"); - } - // rtexprvalue is fixed to "true" and a translation error - // must occur if specified. - rtexprvalue = true; - if (rtexprvalueString != null) { - err.jspError(n, "jsp.error.frgmentwithrtexprvalue"); - } - } else { - if (type == null) - type = "java.lang.String"; - - if (deferredValue) { - type = ValueExpression.class.getName(); - } else if (deferredMethod) { - type = MethodExpression.class.getName(); - } - } - - TagAttributeInfo tagAttributeInfo = new TagAttributeInfo(attrName, - required, type, rtexprvalue, fragment, null, deferredValue, - deferredMethod, deferredValueType, deferredMethodSignature); - attributeVector.addElement(tagAttributeInfo); - checkUniqueName(attrName, ATTR_NAME, n, tagAttributeInfo); - } - - public void visit(Node.VariableDirective n) throws JasperException { - - JspUtil.checkAttributes("Variable directive", n, - variableDirectiveAttrs, err); - - String nameGiven = n.getAttributeValue("name-given"); - String nameFromAttribute = n - .getAttributeValue("name-from-attribute"); - if (nameGiven == null && nameFromAttribute == null) { - err.jspError("jsp.error.variable.either.name"); - } - - if (nameGiven != null && nameFromAttribute != null) { - err.jspError("jsp.error.variable.both.name"); - } - - String alias = n.getAttributeValue("alias"); - if (nameFromAttribute != null && alias == null - || nameFromAttribute == null && alias != null) { - err.jspError("jsp.error.variable.alias"); - } - - String className = n.getAttributeValue("variable-class"); - if (className == null) - className = "java.lang.String"; - - String declareStr = n.getAttributeValue("declare"); - boolean declare = true; - if (declareStr != null) - declare = JspUtil.booleanValue(declareStr); - - int scope = VariableInfo.NESTED; - String scopeStr = n.getAttributeValue("scope"); - if (scopeStr != null) { - if ("NESTED".equals(scopeStr)) { - // Already the default - } else if ("AT_BEGIN".equals(scopeStr)) { - scope = VariableInfo.AT_BEGIN; - } else if ("AT_END".equals(scopeStr)) { - scope = VariableInfo.AT_END; - } - } - - if (nameFromAttribute != null) { - /* - * An alias has been specified. We use 'nameGiven' to hold the - * value of the alias, and 'nameFromAttribute' to hold the name - * of the attribute whose value (at invocation-time) denotes the - * name of the variable that is being aliased - */ - nameGiven = alias; - checkUniqueName(nameFromAttribute, VAR_NAME_FROM, n); - checkUniqueName(alias, VAR_ALIAS, n); - } else { - // name-given specified - checkUniqueName(nameGiven, VAR_NAME_GIVEN, n); - } - - variableVector.addElement(new TagVariableInfo(nameGiven, - nameFromAttribute, className, declare, scope)); - } - - /* - * Returns the vector of attributes corresponding to attribute - * directives. - */ - public Vector getAttributesVector() { - return attributeVector; - } - - /* - * Returns the vector of variables corresponding to variable directives. - */ - public Vector getVariablesVector() { - return variableVector; - } - - /* - * Returns the value of the dynamic-attributes tag directive attribute. - */ - public String getDynamicAttributesMapName() { - return dynamicAttrsMapName; - } - - public TagInfo getTagInfo() throws JasperException { - - if (name == null) { - // XXX Get it from tag file name - } - - if (bodycontent == null) { - bodycontent = TagInfo.BODY_CONTENT_SCRIPTLESS; - } - - String tagClassName = JspUtil.getTagHandlerClassName(path, err); - - TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector - .size()]; - variableVector.copyInto(tagVariableInfos); - - TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector - .size()]; - attributeVector.copyInto(tagAttributeInfo); - - return new JasperTagInfo(name, tagClassName, bodycontent, - description, tagLibInfo, tei, tagAttributeInfo, - displayName, smallIcon, largeIcon, tagVariableInfos, - dynamicAttrsMapName); - } - - static class NameEntry { - private String type; - - private Node node; - - private TagAttributeInfo attr; - - NameEntry(String type, Node node, TagAttributeInfo attr) { - this.type = type; - this.node = node; - this.attr = attr; - } - - String getType() { - return type; - } - - Node getNode() { - return node; - } - - TagAttributeInfo getTagAttributeInfo() { - return attr; - } - } - - /** - * Reports a translation error if names specified in attributes of - * directives are not unique in this translation unit. - * - * The value of the following attributes must be unique. 1. 'name' - * attribute of an attribute directive 2. 'name-given' attribute of a - * variable directive 3. 'alias' attribute of variable directive 4. - * 'dynamic-attributes' of a tag directive except that - * 'dynamic-attributes' can (and must) have the same value when it - * appears in multiple tag directives. - * - * Also, 'name-from' attribute of a variable directive cannot have the - * same value as that from another variable directive. - */ - private void checkUniqueName(String name, String type, Node n) - throws JasperException { - checkUniqueName(name, type, n, null); - } - - private void checkUniqueName(String name, String type, Node n, - TagAttributeInfo attr) throws JasperException { - - HashMap table = (type == VAR_NAME_FROM) ? nameFromTable : nameTable; - NameEntry nameEntry = (NameEntry) table.get(name); - if (nameEntry != null) { - if (type != TAG_DYNAMIC || nameEntry.getType() != TAG_DYNAMIC) { - int line = nameEntry.getNode().getStart().getLineNumber(); - err.jspError(n, "jsp.error.tagfile.nameNotUnique", type, - nameEntry.getType(), Integer.toString(line)); - } - } else { - table.put(name, new NameEntry(type, n, attr)); - } - } - - /** - * Perform miscellean checks after the nodes are visited. - */ - void postCheck() throws JasperException { - // Check that var.name-from-attributes has valid values. - Iterator iter = nameFromTable.keySet().iterator(); - while (iter.hasNext()) { - String nameFrom = (String) iter.next(); - NameEntry nameEntry = (NameEntry) nameTable.get(nameFrom); - NameEntry nameFromEntry = (NameEntry) nameFromTable - .get(nameFrom); - Node nameFromNode = nameFromEntry.getNode(); - if (nameEntry == null) { - err.jspError(nameFromNode, - "jsp.error.tagfile.nameFrom.noAttribute", nameFrom); - } else { - Node node = nameEntry.getNode(); - TagAttributeInfo tagAttr = nameEntry.getTagAttributeInfo(); - if (!"java.lang.String".equals(tagAttr.getTypeName()) - || !tagAttr.isRequired() - || tagAttr.canBeRequestTime()) { - err.jspError(nameFromNode, - "jsp.error.tagfile.nameFrom.badAttribute", - nameFrom, Integer.toString(node.getStart() - .getLineNumber())); - } - } - } - } - } - - /** - * Parses the tag file, and collects information on the directives included - * in it. The method is used to obtain the info on the tag file, when the - * handler that it represents is referenced. The tag file is not compiled - * here. - * - * @param pc - * the current ParserController used in this compilation - * @param name - * the tag name as specified in the TLD - * @param tagfile - * the path for the tagfile - * @param tagLibInfo - * the TagLibraryInfo object associated with this TagInfo - * @return a TagInfo object assembled from the directives in the tag file. - */ - public static TagInfo parseTagFileDirectives(ParserController pc, - String name, String path, TagLibraryInfo tagLibInfo) - throws JasperException { - - ErrorDispatcher err = pc.getCompiler().getErrorDispatcher(); - - Node.Nodes page = null; - try { - page = pc.parseTagFileDirectives(path); - } catch (FileNotFoundException e) { - err.jspError("jsp.error.file.not.found", path); - } catch (IOException e) { - err.jspError("jsp.error.file.not.found", path); - } - - TagFileDirectiveVisitor tagFileVisitor = new TagFileDirectiveVisitor(pc - .getCompiler(), tagLibInfo, name, path); - page.visit(tagFileVisitor); - tagFileVisitor.postCheck(); - - return tagFileVisitor.getTagInfo(); - } - - /** - * Compiles and loads a tagfile. - */ - private Class loadTagFile(Compiler compiler, String tagFilePath, - TagInfo tagInfo, PageInfo parentPageInfo) throws JasperException { - - JspCompilationContext ctxt = compiler.getCompilationContext(); - JspRuntimeContext rctxt = ctxt.getRuntimeContext(); - JspServletWrapper wrapper = (JspServletWrapper) rctxt - .getWrapper(tagFilePath); - - synchronized (rctxt) { - if (wrapper == null) { - wrapper = new JspServletWrapper(ctxt.getServletContext(), ctxt - .getOptions(), tagFilePath, tagInfo, ctxt - .getRuntimeContext(), (URL) ctxt.getTagFileJarUrls() - .get(tagFilePath)); - rctxt.addWrapper(tagFilePath, wrapper); - - // Use same classloader and classpath for compiling tag files - wrapper.getJspEngineContext().setClassLoader( - (URLClassLoader) ctxt.getClassLoader()); - wrapper.getJspEngineContext().setClassPath(ctxt.getClassPath()); - } else { - // Make sure that JspCompilationContext gets the latest TagInfo - // for the tag file. TagInfo instance was created the last - // time the tag file was scanned for directives, and the tag - // file may have been modified since then. - wrapper.getJspEngineContext().setTagInfo(tagInfo); - } - - Class tagClazz; - int tripCount = wrapper.incTripCount(); - try { - if (tripCount > 0) { - // When tripCount is greater than zero, a circular - // dependency exists. The circularily dependant tag - // file is compiled in prototype mode, to avoid infinite - // recursion. - - JspServletWrapper tempWrapper = new JspServletWrapper(ctxt - .getServletContext(), ctxt.getOptions(), - tagFilePath, tagInfo, ctxt.getRuntimeContext(), - (URL) ctxt.getTagFileJarUrls().get(tagFilePath)); - tagClazz = tempWrapper.loadTagFilePrototype(); - tempVector.add(tempWrapper.getJspEngineContext() - .getCompiler()); - } else { - tagClazz = wrapper.loadTagFile(); - } - } finally { - wrapper.decTripCount(); - } - - // Add the dependants for this tag file to its parent's - // dependant list. The only reliable dependency information - // can only be obtained from the tag instance. - try { - Object tagIns = tagClazz.newInstance(); - if (tagIns instanceof JspSourceDependent) { - Iterator iter = ((List) ((JspSourceDependent) tagIns) - .getDependants()).iterator(); - while (iter.hasNext()) { - parentPageInfo.addDependant((String) iter.next()); - } - } - } catch (Exception e) { - // ignore errors - } - - return tagClazz; - } - } - - /* - * Visitor which scans the page and looks for tag handlers that are tag - * files, compiling (if necessary) and loading them. - */ - private class TagFileLoaderVisitor extends Node.Visitor { - - private Compiler compiler; - - private PageInfo pageInfo; - - TagFileLoaderVisitor(Compiler compiler) { - - this.compiler = compiler; - this.pageInfo = compiler.getPageInfo(); - } - - public void visit(Node.CustomTag n) throws JasperException { - TagFileInfo tagFileInfo = n.getTagFileInfo(); - if (tagFileInfo != null) { - String tagFilePath = tagFileInfo.getPath(); - JspCompilationContext ctxt = compiler.getCompilationContext(); - if (ctxt.getTagFileJarUrls().get(tagFilePath) == null) { - // Omit tag file dependency info on jar files for now. - pageInfo.addDependant(tagFilePath); - } - Class c = loadTagFile(compiler, tagFilePath, n.getTagInfo(), - pageInfo); - n.setTagHandlerClass(c); - } - visitBody(n); - } - } - - /** - * Implements a phase of the translation that compiles (if necessary) the - * tag files used in a JSP files. The directives in the tag files are - * assumed to have been proccessed and encapsulated as TagFileInfo in the - * CustomTag nodes. - */ - public void loadTagFiles(Compiler compiler, Node.Nodes page) - throws JasperException { - - tempVector = new Vector(); - page.visit(new TagFileLoaderVisitor(compiler)); - } - - /** - * Removed the java and class files for the tag prototype generated from the - * current compilation. - * - * @param classFileName - * If non-null, remove only the class file with with this name. - */ - public void removeProtoTypeFiles(String classFileName) { - Iterator iter = tempVector.iterator(); - while (iter.hasNext()) { - Compiler c = (Compiler) iter.next(); - if (classFileName == null) { - c.removeGeneratedClassFiles(); - } else if (classFileName.equals(c.getCompilationContext() - .getClassFileName())) { - c.removeGeneratedClassFiles(); - tempVector.remove(c); - return; - } - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.URL; +import java.net.URLClassLoader; +import java.util.Iterator; +import java.util.List; +import java.util.Vector; +import java.util.HashMap; + +import javax.el.MethodExpression; +import javax.el.ValueExpression; +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagExtraInfo; +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.servlet.jsp.tagext.TagVariableInfo; +import javax.servlet.jsp.tagext.VariableInfo; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.servlet.JspServletWrapper; +import org.apache.jasper.runtime.JspSourceDependent; + +/** + * 1. Processes and extracts the directive info in a tag file. 2. Compiles and + * loads tag files used in a JSP file. + * + * @author Kin-man Chung + */ + +class TagFileProcessor { + + private Vector tempVector; + + /** + * A visitor the tag file + */ + private static class TagFileDirectiveVisitor extends Node.Visitor { + + private static final JspUtil.ValidAttribute[] tagDirectiveAttrs = { + new JspUtil.ValidAttribute("display-name"), + new JspUtil.ValidAttribute("body-content"), + new JspUtil.ValidAttribute("dynamic-attributes"), + new JspUtil.ValidAttribute("small-icon"), + new JspUtil.ValidAttribute("large-icon"), + new JspUtil.ValidAttribute("description"), + new JspUtil.ValidAttribute("example"), + new JspUtil.ValidAttribute("pageEncoding"), + new JspUtil.ValidAttribute("language"), + new JspUtil.ValidAttribute("import"), + new JspUtil.ValidAttribute("isELIgnored") }; + + private static final JspUtil.ValidAttribute[] attributeDirectiveAttrs = { + new JspUtil.ValidAttribute("name", true), + new JspUtil.ValidAttribute("required"), + new JspUtil.ValidAttribute("fragment"), + new JspUtil.ValidAttribute("rtexprvalue"), + new JspUtil.ValidAttribute("type"), + new JspUtil.ValidAttribute("deferredValue"), // JSP 2.1 + new JspUtil.ValidAttribute("deferredValueType"), // JSP 2.1 + new JspUtil.ValidAttribute("deferredMethod"), // JSP 2 + new JspUtil.ValidAttribute("deferredMethodSignature"), // JSP 21 + new JspUtil.ValidAttribute("description") }; + + private static final JspUtil.ValidAttribute[] variableDirectiveAttrs = { + new JspUtil.ValidAttribute("name-given"), + new JspUtil.ValidAttribute("name-from-attribute"), + new JspUtil.ValidAttribute("alias"), + new JspUtil.ValidAttribute("variable-class"), + new JspUtil.ValidAttribute("scope"), + new JspUtil.ValidAttribute("declare"), + new JspUtil.ValidAttribute("description") }; + + private ErrorDispatcher err; + + private TagLibraryInfo tagLibInfo; + + private String name = null; + + private String path = null; + + private TagExtraInfo tei = null; + + private String bodycontent = null; + + private String description = null; + + private String displayName = null; + + private String smallIcon = null; + + private String largeIcon = null; + + private String dynamicAttrsMapName; + + private String example = null; + + private Vector attributeVector; + + private Vector variableVector; + + private static final String ATTR_NAME = "the name attribute of the attribute directive"; + + private static final String VAR_NAME_GIVEN = "the name-given attribute of the variable directive"; + + private static final String VAR_NAME_FROM = "the name-from-attribute attribute of the variable directive"; + + private static final String VAR_ALIAS = "the alias attribute of the variable directive"; + + private static final String TAG_DYNAMIC = "the dynamic-attributes attribute of the tag directive"; + + private HashMap nameTable = new HashMap(); + + private HashMap nameFromTable = new HashMap(); + + public TagFileDirectiveVisitor(Compiler compiler, + TagLibraryInfo tagLibInfo, String name, String path) { + err = compiler.getErrorDispatcher(); + this.tagLibInfo = tagLibInfo; + this.name = name; + this.path = path; + attributeVector = new Vector(); + variableVector = new Vector(); + } + + public void visit(Node.TagDirective n) throws JasperException { + + JspUtil.checkAttributes("Tag directive", n, tagDirectiveAttrs, err); + + bodycontent = checkConflict(n, bodycontent, "body-content"); + if (bodycontent != null + && !bodycontent + .equalsIgnoreCase(TagInfo.BODY_CONTENT_EMPTY) + && !bodycontent + .equalsIgnoreCase(TagInfo.BODY_CONTENT_TAG_DEPENDENT) + && !bodycontent + .equalsIgnoreCase(TagInfo.BODY_CONTENT_SCRIPTLESS)) { + err.jspError(n, "jsp.error.tagdirective.badbodycontent", + bodycontent); + } + dynamicAttrsMapName = checkConflict(n, dynamicAttrsMapName, + "dynamic-attributes"); + if (dynamicAttrsMapName != null) { + checkUniqueName(dynamicAttrsMapName, TAG_DYNAMIC, n); + } + smallIcon = checkConflict(n, smallIcon, "small-icon"); + largeIcon = checkConflict(n, largeIcon, "large-icon"); + description = checkConflict(n, description, "description"); + displayName = checkConflict(n, displayName, "display-name"); + example = checkConflict(n, example, "example"); + } + + private String checkConflict(Node n, String oldAttrValue, String attr) + throws JasperException { + + String result = oldAttrValue; + String attrValue = n.getAttributeValue(attr); + if (attrValue != null) { + if (oldAttrValue != null && !oldAttrValue.equals(attrValue)) { + err.jspError(n, "jsp.error.tag.conflict.attr", attr, + oldAttrValue, attrValue); + } + result = attrValue; + } + return result; + } + + public void visit(Node.AttributeDirective n) throws JasperException { + + JspUtil.checkAttributes("Attribute directive", n, + attributeDirectiveAttrs, err); + + // JSP 2.1 Table JSP.8-3 + // handle deferredValue and deferredValueType + boolean deferredValue = false; + String deferredValueString = n.getAttributeValue("deferredValue"); + if (deferredValueString != null) { + deferredValue = JspUtil.booleanValue(deferredValueString); + } + String deferredValueType = n.getAttributeValue("deferredValueType"); + if (deferredValueType != null) { + deferredValue = true; + } else if (deferredValue) { + deferredValueType = "java.lang.Object"; + } else { + deferredValueType = "java.lang.String"; + } + + // JSP 2.1 Table JSP.8-3 + // handle deferredMethod and deferredMethodSignature + boolean deferredMethod = false; + String deferredMethodString = n.getAttributeValue("deferredMethod"); + if (deferredMethodString != null) { + deferredMethod = JspUtil.booleanValue(deferredMethodString); + } + String deferredMethodSignature = n + .getAttributeValue("deferredMethodSignature"); + if (deferredMethodSignature != null) { + deferredMethod = true; + } else if (deferredMethod) { + deferredMethodSignature = "void methodname()"; + } + + String attrName = n.getAttributeValue("name"); + boolean required = JspUtil.booleanValue(n + .getAttributeValue("required")); + boolean rtexprvalue = true; + String rtexprvalueString = n.getAttributeValue("rtexprvalue"); + if (rtexprvalueString != null) { + rtexprvalue = JspUtil.booleanValue(rtexprvalueString); + } + boolean fragment = JspUtil.booleanValue(n + .getAttributeValue("fragment")); + String type = n.getAttributeValue("type"); + if (fragment) { + // type is fixed to "JspFragment" and a translation error + // must occur if specified. + if (type != null) { + err.jspError(n, "jsp.error.fragmentwithtype"); + } + // rtexprvalue is fixed to "true" and a translation error + // must occur if specified. + rtexprvalue = true; + if (rtexprvalueString != null) { + err.jspError(n, "jsp.error.frgmentwithrtexprvalue"); + } + } else { + if (type == null) + type = "java.lang.String"; + + if (deferredValue) { + type = ValueExpression.class.getName(); + } else if (deferredMethod) { + type = MethodExpression.class.getName(); + } + } + + TagAttributeInfo tagAttributeInfo = new TagAttributeInfo(attrName, + required, type, rtexprvalue, fragment, null, deferredValue, + deferredMethod, deferredValueType, deferredMethodSignature); + attributeVector.addElement(tagAttributeInfo); + checkUniqueName(attrName, ATTR_NAME, n, tagAttributeInfo); + } + + public void visit(Node.VariableDirective n) throws JasperException { + + JspUtil.checkAttributes("Variable directive", n, + variableDirectiveAttrs, err); + + String nameGiven = n.getAttributeValue("name-given"); + String nameFromAttribute = n + .getAttributeValue("name-from-attribute"); + if (nameGiven == null && nameFromAttribute == null) { + err.jspError("jsp.error.variable.either.name"); + } + + if (nameGiven != null && nameFromAttribute != null) { + err.jspError("jsp.error.variable.both.name"); + } + + String alias = n.getAttributeValue("alias"); + if (nameFromAttribute != null && alias == null + || nameFromAttribute == null && alias != null) { + err.jspError("jsp.error.variable.alias"); + } + + String className = n.getAttributeValue("variable-class"); + if (className == null) + className = "java.lang.String"; + + String declareStr = n.getAttributeValue("declare"); + boolean declare = true; + if (declareStr != null) + declare = JspUtil.booleanValue(declareStr); + + int scope = VariableInfo.NESTED; + String scopeStr = n.getAttributeValue("scope"); + if (scopeStr != null) { + if ("NESTED".equals(scopeStr)) { + // Already the default + } else if ("AT_BEGIN".equals(scopeStr)) { + scope = VariableInfo.AT_BEGIN; + } else if ("AT_END".equals(scopeStr)) { + scope = VariableInfo.AT_END; + } + } + + if (nameFromAttribute != null) { + /* + * An alias has been specified. We use 'nameGiven' to hold the + * value of the alias, and 'nameFromAttribute' to hold the name + * of the attribute whose value (at invocation-time) denotes the + * name of the variable that is being aliased + */ + nameGiven = alias; + checkUniqueName(nameFromAttribute, VAR_NAME_FROM, n); + checkUniqueName(alias, VAR_ALIAS, n); + } else { + // name-given specified + checkUniqueName(nameGiven, VAR_NAME_GIVEN, n); + } + + variableVector.addElement(new TagVariableInfo(nameGiven, + nameFromAttribute, className, declare, scope)); + } + + /* + * Returns the vector of attributes corresponding to attribute + * directives. + */ + public Vector getAttributesVector() { + return attributeVector; + } + + /* + * Returns the vector of variables corresponding to variable directives. + */ + public Vector getVariablesVector() { + return variableVector; + } + + /* + * Returns the value of the dynamic-attributes tag directive attribute. + */ + public String getDynamicAttributesMapName() { + return dynamicAttrsMapName; + } + + public TagInfo getTagInfo() throws JasperException { + + if (name == null) { + // XXX Get it from tag file name + } + + if (bodycontent == null) { + bodycontent = TagInfo.BODY_CONTENT_SCRIPTLESS; + } + + String tagClassName = JspUtil.getTagHandlerClassName(path, err); + + TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector + .size()]; + variableVector.copyInto(tagVariableInfos); + + TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector + .size()]; + attributeVector.copyInto(tagAttributeInfo); + + return new JasperTagInfo(name, tagClassName, bodycontent, + description, tagLibInfo, tei, tagAttributeInfo, + displayName, smallIcon, largeIcon, tagVariableInfos, + dynamicAttrsMapName); + } + + static class NameEntry { + private String type; + + private Node node; + + private TagAttributeInfo attr; + + NameEntry(String type, Node node, TagAttributeInfo attr) { + this.type = type; + this.node = node; + this.attr = attr; + } + + String getType() { + return type; + } + + Node getNode() { + return node; + } + + TagAttributeInfo getTagAttributeInfo() { + return attr; + } + } + + /** + * Reports a translation error if names specified in attributes of + * directives are not unique in this translation unit. + * + * The value of the following attributes must be unique. 1. 'name' + * attribute of an attribute directive 2. 'name-given' attribute of a + * variable directive 3. 'alias' attribute of variable directive 4. + * 'dynamic-attributes' of a tag directive except that + * 'dynamic-attributes' can (and must) have the same value when it + * appears in multiple tag directives. + * + * Also, 'name-from' attribute of a variable directive cannot have the + * same value as that from another variable directive. + */ + private void checkUniqueName(String name, String type, Node n) + throws JasperException { + checkUniqueName(name, type, n, null); + } + + private void checkUniqueName(String name, String type, Node n, + TagAttributeInfo attr) throws JasperException { + + HashMap table = (type == VAR_NAME_FROM) ? nameFromTable : nameTable; + NameEntry nameEntry = (NameEntry) table.get(name); + if (nameEntry != null) { + if (type != TAG_DYNAMIC || nameEntry.getType() != TAG_DYNAMIC) { + int line = nameEntry.getNode().getStart().getLineNumber(); + err.jspError(n, "jsp.error.tagfile.nameNotUnique", type, + nameEntry.getType(), Integer.toString(line)); + } + } else { + table.put(name, new NameEntry(type, n, attr)); + } + } + + /** + * Perform miscellean checks after the nodes are visited. + */ + void postCheck() throws JasperException { + // Check that var.name-from-attributes has valid values. + Iterator iter = nameFromTable.keySet().iterator(); + while (iter.hasNext()) { + String nameFrom = (String) iter.next(); + NameEntry nameEntry = (NameEntry) nameTable.get(nameFrom); + NameEntry nameFromEntry = (NameEntry) nameFromTable + .get(nameFrom); + Node nameFromNode = nameFromEntry.getNode(); + if (nameEntry == null) { + err.jspError(nameFromNode, + "jsp.error.tagfile.nameFrom.noAttribute", nameFrom); + } else { + Node node = nameEntry.getNode(); + TagAttributeInfo tagAttr = nameEntry.getTagAttributeInfo(); + if (!"java.lang.String".equals(tagAttr.getTypeName()) + || !tagAttr.isRequired() + || tagAttr.canBeRequestTime()) { + err.jspError(nameFromNode, + "jsp.error.tagfile.nameFrom.badAttribute", + nameFrom, Integer.toString(node.getStart() + .getLineNumber())); + } + } + } + } + } + + /** + * Parses the tag file, and collects information on the directives included + * in it. The method is used to obtain the info on the tag file, when the + * handler that it represents is referenced. The tag file is not compiled + * here. + * + * @param pc + * the current ParserController used in this compilation + * @param name + * the tag name as specified in the TLD + * @param tagfile + * the path for the tagfile + * @param tagLibInfo + * the TagLibraryInfo object associated with this TagInfo + * @return a TagInfo object assembled from the directives in the tag file. + */ + public static TagInfo parseTagFileDirectives(ParserController pc, + String name, String path, TagLibraryInfo tagLibInfo) + throws JasperException { + + ErrorDispatcher err = pc.getCompiler().getErrorDispatcher(); + + Node.Nodes page = null; + try { + page = pc.parseTagFileDirectives(path); + } catch (FileNotFoundException e) { + err.jspError("jsp.error.file.not.found", path); + } catch (IOException e) { + err.jspError("jsp.error.file.not.found", path); + } + + TagFileDirectiveVisitor tagFileVisitor = new TagFileDirectiveVisitor(pc + .getCompiler(), tagLibInfo, name, path); + page.visit(tagFileVisitor); + tagFileVisitor.postCheck(); + + return tagFileVisitor.getTagInfo(); + } + + /** + * Compiles and loads a tagfile. + */ + private Class loadTagFile(Compiler compiler, String tagFilePath, + TagInfo tagInfo, PageInfo parentPageInfo) throws JasperException { + + JspCompilationContext ctxt = compiler.getCompilationContext(); + JspRuntimeContext rctxt = ctxt.getRuntimeContext(); + JspServletWrapper wrapper = (JspServletWrapper) rctxt + .getWrapper(tagFilePath); + + synchronized (rctxt) { + if (wrapper == null) { + wrapper = new JspServletWrapper(ctxt.getServletContext(), ctxt + .getOptions(), tagFilePath, tagInfo, ctxt + .getRuntimeContext(), (URL) ctxt.getTagFileJarUrls() + .get(tagFilePath)); + rctxt.addWrapper(tagFilePath, wrapper); + + // Use same classloader and classpath for compiling tag files + wrapper.getJspEngineContext().setClassLoader( + (URLClassLoader) ctxt.getClassLoader()); + wrapper.getJspEngineContext().setClassPath(ctxt.getClassPath()); + } else { + // Make sure that JspCompilationContext gets the latest TagInfo + // for the tag file. TagInfo instance was created the last + // time the tag file was scanned for directives, and the tag + // file may have been modified since then. + wrapper.getJspEngineContext().setTagInfo(tagInfo); + } + + Class tagClazz; + int tripCount = wrapper.incTripCount(); + try { + if (tripCount > 0) { + // When tripCount is greater than zero, a circular + // dependency exists. The circularily dependant tag + // file is compiled in prototype mode, to avoid infinite + // recursion. + + JspServletWrapper tempWrapper = new JspServletWrapper(ctxt + .getServletContext(), ctxt.getOptions(), + tagFilePath, tagInfo, ctxt.getRuntimeContext(), + (URL) ctxt.getTagFileJarUrls().get(tagFilePath)); + tagClazz = tempWrapper.loadTagFilePrototype(); + tempVector.add(tempWrapper.getJspEngineContext() + .getCompiler()); + } else { + tagClazz = wrapper.loadTagFile(); + } + } finally { + wrapper.decTripCount(); + } + + // Add the dependants for this tag file to its parent's + // dependant list. The only reliable dependency information + // can only be obtained from the tag instance. + try { + Object tagIns = tagClazz.newInstance(); + if (tagIns instanceof JspSourceDependent) { + Iterator iter = ((List) ((JspSourceDependent) tagIns) + .getDependants()).iterator(); + while (iter.hasNext()) { + parentPageInfo.addDependant((String) iter.next()); + } + } + } catch (Exception e) { + // ignore errors + } + + return tagClazz; + } + } + + /* + * Visitor which scans the page and looks for tag handlers that are tag + * files, compiling (if necessary) and loading them. + */ + private class TagFileLoaderVisitor extends Node.Visitor { + + private Compiler compiler; + + private PageInfo pageInfo; + + TagFileLoaderVisitor(Compiler compiler) { + + this.compiler = compiler; + this.pageInfo = compiler.getPageInfo(); + } + + public void visit(Node.CustomTag n) throws JasperException { + TagFileInfo tagFileInfo = n.getTagFileInfo(); + if (tagFileInfo != null) { + String tagFilePath = tagFileInfo.getPath(); + JspCompilationContext ctxt = compiler.getCompilationContext(); + if (ctxt.getTagFileJarUrls().get(tagFilePath) == null) { + // Omit tag file dependency info on jar files for now. + pageInfo.addDependant(tagFilePath); + } + Class c = loadTagFile(compiler, tagFilePath, n.getTagInfo(), + pageInfo); + n.setTagHandlerClass(c); + } + visitBody(n); + } + } + + /** + * Implements a phase of the translation that compiles (if necessary) the + * tag files used in a JSP files. The directives in the tag files are + * assumed to have been proccessed and encapsulated as TagFileInfo in the + * CustomTag nodes. + */ + public void loadTagFiles(Compiler compiler, Node.Nodes page) + throws JasperException { + + tempVector = new Vector(); + page.visit(new TagFileLoaderVisitor(compiler)); + } + + /** + * Removed the java and class files for the tag prototype generated from the + * current compilation. + * + * @param classFileName + * If non-null, remove only the class file with with this name. + */ + public void removeProtoTypeFiles(String classFileName) { + Iterator iter = tempVector.iterator(); + while (iter.hasNext()) { + Compiler c = (Compiler) iter.next(); + if (classFileName == null) { + c.removeGeneratedClassFiles(); + } else if (classFileName.equals(c.getCompilationContext() + .getClassFileName())) { + c.removeGeneratedClassFiles(); + tempVector.remove(c); + return; + } + } + } +} diff --git a/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java b/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java index d7d4681a8..8d6744915 100644 --- a/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java +++ b/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java @@ -1,757 +1,757 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.net.JarURLConnection; -import java.net.URL; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; -import java.util.Vector; -import java.util.jar.JarFile; -import java.util.zip.ZipEntry; - -import javax.servlet.jsp.tagext.FunctionInfo; -import javax.servlet.jsp.tagext.PageData; -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagExtraInfo; -import javax.servlet.jsp.tagext.TagFileInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; -import javax.servlet.jsp.tagext.TagLibraryValidator; -import javax.servlet.jsp.tagext.TagVariableInfo; -import javax.servlet.jsp.tagext.ValidationMessage; -import javax.servlet.jsp.tagext.VariableInfo; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.jasper.xmlparser.TreeNode; - -/** - * Implementation of the TagLibraryInfo class from the JSP spec. - * - * @author Anil K. Vijendran - * @author Mandar Raje - * @author Pierre Delisle - * @author Kin-man Chung - * @author Jan Luehe - */ -class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants { - - // Logger - private Log log = LogFactory.getLog(TagLibraryInfoImpl.class); - - private Hashtable jarEntries; - - private JspCompilationContext ctxt; - - private ErrorDispatcher err; - - private ParserController parserController; - - private final void print(String name, String value, PrintWriter w) { - if (value != null) { - w.print(name + " = {\n\t"); - w.print(value); - w.print("\n}\n"); - } - } - - public String toString() { - StringWriter sw = new StringWriter(); - PrintWriter out = new PrintWriter(sw); - print("tlibversion", tlibversion, out); - print("jspversion", jspversion, out); - print("shortname", shortname, out); - print("urn", urn, out); - print("info", info, out); - print("uri", uri, out); - print("tagLibraryValidator", "" + tagLibraryValidator, out); - - for (int i = 0; i < tags.length; i++) - out.println(tags[i].toString()); - - for (int i = 0; i < tagFiles.length; i++) - out.println(tagFiles[i].toString()); - - for (int i = 0; i < functions.length; i++) - out.println(functions[i].toString()); - - return sw.toString(); - } - - // XXX FIXME - // resolveRelativeUri and/or getResourceAsStream don't seem to properly - // handle relative paths when dealing when home and getDocBase are set - // the following is a workaround until these problems are resolved. - private InputStream getResourceAsStream(String uri) - throws FileNotFoundException { - try { - // see if file exists on the filesystem first - String real = ctxt.getRealPath(uri); - if (real == null) { - return ctxt.getResourceAsStream(uri); - } else { - return new FileInputStream(real); - } - } catch (FileNotFoundException ex) { - // if file not found on filesystem, get the resource through - // the context - return ctxt.getResourceAsStream(uri); - } - - } - - /** - * Constructor. - */ - public TagLibraryInfoImpl(JspCompilationContext ctxt, ParserController pc, - String prefix, String uriIn, String[] location, ErrorDispatcher err) - throws JasperException { - super(prefix, uriIn); - - this.ctxt = ctxt; - this.parserController = pc; - this.err = err; - InputStream in = null; - JarFile jarFile = null; - - if (location == null) { - // The URI points to the TLD itself or to a JAR file in which the - // TLD is stored - location = generateTLDLocation(uri, ctxt); - } - - try { - if (!location[0].endsWith("jar")) { - // Location points to TLD file - try { - in = getResourceAsStream(location[0]); - if (in == null) { - throw new FileNotFoundException(location[0]); - } - } catch (FileNotFoundException ex) { - err.jspError("jsp.error.file.not.found", location[0]); - } - - parseTLD(ctxt, location[0], in, null); - // Add TLD to dependency list - PageInfo pageInfo = ctxt.createCompiler().getPageInfo(); - if (pageInfo != null) { - pageInfo.addDependant(location[0]); - } - } else { - // Tag library is packaged in JAR file - try { - URL jarFileUrl = new URL("jar:" + location[0] + "!/"); - JarURLConnection conn = (JarURLConnection) jarFileUrl - .openConnection(); - conn.setUseCaches(false); - conn.connect(); - jarFile = conn.getJarFile(); - ZipEntry jarEntry = jarFile.getEntry(location[1]); - in = jarFile.getInputStream(jarEntry); - parseTLD(ctxt, location[0], in, jarFileUrl); - } catch (Exception ex) { - err.jspError("jsp.error.tld.unable_to_read", location[0], - location[1], ex.toString()); - } - } - } finally { - if (in != null) { - try { - in.close(); - } catch (Throwable t) { - } - } - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - } - } - } - - } - - /* - * @param ctxt The JSP compilation context @param uri The TLD's uri @param - * in The TLD's input stream @param jarFileUrl The JAR file containing the - * TLD, or null if the tag library is not packaged in a JAR - */ - private void parseTLD(JspCompilationContext ctxt, String uri, - InputStream in, URL jarFileUrl) throws JasperException { - Vector tagVector = new Vector(); - Vector tagFileVector = new Vector(); - Hashtable functionTable = new Hashtable(); - - // Create an iterator over the child elements of our element - ParserUtils pu = new ParserUtils(); - TreeNode tld = pu.parseXMLDocument(uri, in); - - // Check to see if the root element contains a 'version' - // attribute, which was added in JSP 2.0 to replace the - // subelement - this.jspversion = tld.findAttribute("version"); - - // Process each child element of our element - Iterator list = tld.findChildren(); - - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - - if ("tlibversion".equals(tname) // JSP 1.1 - || "tlib-version".equals(tname)) { // JSP 1.2 - this.tlibversion = element.getBody(); - } else if ("jspversion".equals(tname) - || "jsp-version".equals(tname)) { - this.jspversion = element.getBody(); - } else if ("shortname".equals(tname) || "short-name".equals(tname)) - this.shortname = element.getBody(); - else if ("uri".equals(tname)) - this.urn = element.getBody(); - else if ("info".equals(tname) || "description".equals(tname)) - this.info = element.getBody(); - else if ("validator".equals(tname)) - this.tagLibraryValidator = createValidator(element); - else if ("tag".equals(tname)) - tagVector.addElement(createTagInfo(element, jspversion)); - else if ("tag-file".equals(tname)) { - TagFileInfo tagFileInfo = createTagFileInfo(element, uri, - jarFileUrl); - tagFileVector.addElement(tagFileInfo); - } else if ("function".equals(tname)) { // JSP2.0 - FunctionInfo funcInfo = createFunctionInfo(element); - String funcName = funcInfo.getName(); - if (functionTable.containsKey(funcName)) { - err.jspError("jsp.error.tld.fn.duplicate.name", funcName, - uri); - - } - functionTable.put(funcName, funcInfo); - } else if ("display-name".equals(tname) || // Ignored elements - "small-icon".equals(tname) || "large-icon".equals(tname) - || "listener".equals(tname)) { - ; - } else if ("taglib-extension".equals(tname)) { - // Recognized but ignored - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.taglib", tname)); - } - } - - } - - if (tlibversion == null) { - err.jspError("jsp.error.tld.mandatory.element.missing", - "tlib-version"); - } - if (jspversion == null) { - err.jspError("jsp.error.tld.mandatory.element.missing", - "jsp-version"); - } - - this.tags = new TagInfo[tagVector.size()]; - tagVector.copyInto(this.tags); - - this.tagFiles = new TagFileInfo[tagFileVector.size()]; - tagFileVector.copyInto(this.tagFiles); - - this.functions = new FunctionInfo[functionTable.size()]; - int i = 0; - Enumeration enumeration = functionTable.elements(); - while (enumeration.hasMoreElements()) { - this.functions[i++] = (FunctionInfo) enumeration.nextElement(); - } - } - - /* - * @param uri The uri of the TLD @param ctxt The compilation context - * - * @return String array whose first element denotes the path to the TLD. If - * the path to the TLD points to a jar file, then the second element denotes - * the name of the TLD entry in the jar file, which is hardcoded to - * META-INF/taglib.tld. - */ - private String[] generateTLDLocation(String uri, JspCompilationContext ctxt) - throws JasperException { - - int uriType = TldLocationsCache.uriType(uri); - if (uriType == TldLocationsCache.ABS_URI) { - err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved", - uri); - } else if (uriType == TldLocationsCache.NOROOT_REL_URI) { - uri = ctxt.resolveRelativeUri(uri); - } - - String[] location = new String[2]; - location[0] = uri; - if (location[0].endsWith("jar")) { - URL url = null; - try { - url = ctxt.getResource(location[0]); - } catch (Exception ex) { - err.jspError("jsp.error.tld.unable_to_get_jar", location[0], ex - .toString()); - } - if (url == null) { - err.jspError("jsp.error.tld.missing_jar", location[0]); - } - location[0] = url.toString(); - location[1] = "META-INF/taglib.tld"; - } - - return location; - } - - private TagInfo createTagInfo(TreeNode elem, String jspVersion) - throws JasperException { - - String tagName = null; - String tagClassName = null; - String teiClassName = null; - - /* - * Default body content for JSP 1.2 tag handlers ( has - * become mandatory in JSP 2.0, because the default would be invalid for - * simple tag handlers) - */ - String bodycontent = "JSP"; - - String info = null; - String displayName = null; - String smallIcon = null; - String largeIcon = null; - boolean dynamicAttributes = false; - - Vector attributeVector = new Vector(); - Vector variableVector = new Vector(); - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - - if ("name".equals(tname)) { - tagName = element.getBody(); - } else if ("tagclass".equals(tname) || "tag-class".equals(tname)) { - tagClassName = element.getBody(); - } else if ("teiclass".equals(tname) || "tei-class".equals(tname)) { - teiClassName = element.getBody(); - } else if ("bodycontent".equals(tname) - || "body-content".equals(tname)) { - bodycontent = element.getBody(); - } else if ("display-name".equals(tname)) { - displayName = element.getBody(); - } else if ("small-icon".equals(tname)) { - smallIcon = element.getBody(); - } else if ("large-icon".equals(tname)) { - largeIcon = element.getBody(); - } else if ("icon".equals(tname)) { - TreeNode icon = element.findChild("small-icon"); - if (icon != null) { - smallIcon = icon.getBody(); - } - icon = element.findChild("large-icon"); - if (icon != null) { - largeIcon = icon.getBody(); - } - } else if ("info".equals(tname) || "description".equals(tname)) { - info = element.getBody(); - } else if ("variable".equals(tname)) { - variableVector.addElement(createVariable(element)); - } else if ("attribute".equals(tname)) { - attributeVector - .addElement(createAttribute(element, jspVersion)); - } else if ("dynamic-attributes".equals(tname)) { - dynamicAttributes = JspUtil.booleanValue(element.getBody()); - } else if ("example".equals(tname)) { - // Ignored elements - } else if ("tag-extension".equals(tname)) { - // Ignored - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.tag", tname)); - } - } - } - - TagExtraInfo tei = null; - if (teiClassName != null && !teiClassName.equals("")) { - try { - Class teiClass = ctxt.getClassLoader().loadClass(teiClassName); - tei = (TagExtraInfo) teiClass.newInstance(); - } catch (Exception e) { - err.jspError("jsp.error.teiclass.instantiation", teiClassName, - e); - } - } - - TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector - .size()]; - attributeVector.copyInto(tagAttributeInfo); - - TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector - .size()]; - variableVector.copyInto(tagVariableInfos); - - TagInfo taginfo = new TagInfo(tagName, tagClassName, bodycontent, info, - this, tei, tagAttributeInfo, displayName, smallIcon, largeIcon, - tagVariableInfos, dynamicAttributes); - return taginfo; - } - - /* - * Parses the tag file directives of the given TagFile and turns them into a - * TagInfo. - * - * @param elem The element in the TLD @param uri The location of - * the TLD, in case the tag file is specified relative to it @param jarFile - * The JAR file, in case the tag file is packaged in a JAR - * - * @return TagInfo correspoding to tag file directives - */ - private TagFileInfo createTagFileInfo(TreeNode elem, String uri, - URL jarFileUrl) throws JasperException { - - String name = null; - String path = null; - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode child = (TreeNode) list.next(); - String tname = child.getName(); - if ("name".equals(tname)) { - name = child.getBody(); - } else if ("path".equals(tname)) { - path = child.getBody(); - } else if ("example".equals(tname)) { - // Ignore element: Bugzilla 33538 - } else if ("tag-extension".equals(tname)) { - // Ignore element: Bugzilla 33538 - } else if ("icon".equals(tname) - || "display-name".equals(tname) - || "description".equals(tname)) { - // Ignore these elements: Bugzilla 38015 - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.tagfile", tname)); - } - } - } - - if (path.startsWith("/META-INF/tags")) { - // Tag file packaged in JAR - ctxt.getTagFileJarUrls().put(path, jarFileUrl); - } else if (!path.startsWith("/WEB-INF/tags")) { - err.jspError("jsp.error.tagfile.illegalPath", path); - } - - TagInfo tagInfo = TagFileProcessor.parseTagFileDirectives( - parserController, name, path, this); - return new TagFileInfo(name, path, tagInfo); - } - - TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) { - String name = null; - String type = null; - String expectedType = null; - String methodSignature = null; - boolean required = false, rtexprvalue = false, reqTime = false, isFragment = false, deferredValue = false, deferredMethod = false; - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - - if ("name".equals(tname)) { - name = element.getBody(); - } else if ("required".equals(tname)) { - String s = element.getBody(); - if (s != null) - required = JspUtil.booleanValue(s); - } else if ("rtexprvalue".equals(tname)) { - String s = element.getBody(); - if (s != null) - rtexprvalue = JspUtil.booleanValue(s); - } else if ("type".equals(tname)) { - type = element.getBody(); - if ("1.2".equals(jspVersion) - && (type.equals("Boolean") || type.equals("Byte") - || type.equals("Character") - || type.equals("Double") - || type.equals("Float") - || type.equals("Integer") - || type.equals("Long") || type.equals("Object") - || type.equals("Short") || type - .equals("String"))) { - type = "java.lang." + type; - } - } else if ("fragment".equals(tname)) { - String s = element.getBody(); - if (s != null) { - isFragment = JspUtil.booleanValue(s); - } - } else if ("deferred-value".equals(tname)) { - deferredValue = true; - type = "javax.el.ValueExpression"; - TreeNode child = element.findChild("type"); - if (child != null) { - expectedType = child.getBody(); - if (expectedType != null) { - expectedType = expectedType.trim(); - } - } else { - expectedType = "java.lang.Object"; - } - } else if ("deferred-method".equals(tname)) { - deferredMethod = true; - type = "javax.el.MethodExpression"; - TreeNode child = element.findChild("method-signature"); - if (child != null) { - methodSignature = child.getBody(); - if (methodSignature != null) { - methodSignature = methodSignature.trim(); - } - } else { - methodSignature = "java.lang.Object method()"; - } - } else if ("description".equals(tname) || // Ignored elements - false) { - ; - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.attribute", tname)); - } - } - } - - if (isFragment) { - /* - * According to JSP.C-3 ("TLD Schema Element Structure - tag"), - * 'type' and 'rtexprvalue' must not be specified if 'fragment' has - * been specified (this will be enforced by validating parser). - * Also, if 'fragment' is TRUE, 'type' is fixed at - * javax.servlet.jsp.tagext.JspFragment, and 'rtexprvalue' is fixed - * at true. See also JSP.8.5.2. - */ - type = "javax.servlet.jsp.tagext.JspFragment"; - rtexprvalue = true; - } - - if (!rtexprvalue && type == null) { - // According to JSP spec, for static values (those determined at - // translation time) the type is fixed at java.lang.String. - type = "java.lang.String"; - } - - return new TagAttributeInfo(name, required, type, rtexprvalue, - isFragment, null, deferredValue, deferredMethod, expectedType, - methodSignature); - } - - TagVariableInfo createVariable(TreeNode elem) { - String nameGiven = null; - String nameFromAttribute = null; - String className = "java.lang.String"; - boolean declare = true; - int scope = VariableInfo.NESTED; - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - if ("name-given".equals(tname)) - nameGiven = element.getBody(); - else if ("name-from-attribute".equals(tname)) - nameFromAttribute = element.getBody(); - else if ("variable-class".equals(tname)) - className = element.getBody(); - else if ("declare".equals(tname)) { - String s = element.getBody(); - if (s != null) - declare = JspUtil.booleanValue(s); - } else if ("scope".equals(tname)) { - String s = element.getBody(); - if (s != null) { - if ("NESTED".equals(s)) { - scope = VariableInfo.NESTED; - } else if ("AT_BEGIN".equals(s)) { - scope = VariableInfo.AT_BEGIN; - } else if ("AT_END".equals(s)) { - scope = VariableInfo.AT_END; - } - } - } else if ("description".equals(tname) || // Ignored elements - false) { - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.variable", tname)); - } - } - } - return new TagVariableInfo(nameGiven, nameFromAttribute, className, - declare, scope); - } - - private TagLibraryValidator createValidator(TreeNode elem) - throws JasperException { - - String validatorClass = null; - Map initParams = new Hashtable(); - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - if ("validator-class".equals(tname)) - validatorClass = element.getBody(); - else if ("init-param".equals(tname)) { - String[] initParam = createInitParam(element); - initParams.put(initParam[0], initParam[1]); - } else if ("description".equals(tname) || // Ignored elements - false) { - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.validator", tname)); - } - } - } - - TagLibraryValidator tlv = null; - if (validatorClass != null && !validatorClass.equals("")) { - try { - Class tlvClass = ctxt.getClassLoader() - .loadClass(validatorClass); - tlv = (TagLibraryValidator) tlvClass.newInstance(); - } catch (Exception e) { - err.jspError("jsp.error.tlvclass.instantiation", - validatorClass, e); - } - } - if (tlv != null) { - tlv.setInitParameters(initParams); - } - return tlv; - } - - String[] createInitParam(TreeNode elem) { - String[] initParam = new String[2]; - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - if ("param-name".equals(tname)) { - initParam[0] = element.getBody(); - } else if ("param-value".equals(tname)) { - initParam[1] = element.getBody(); - } else if ("description".equals(tname)) { - ; // Do nothing - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.initParam", tname)); - } - } - } - return initParam; - } - - FunctionInfo createFunctionInfo(TreeNode elem) { - - String name = null; - String klass = null; - String signature = null; - - Iterator list = elem.findChildren(); - while (list.hasNext()) { - TreeNode element = (TreeNode) list.next(); - String tname = element.getName(); - - if ("name".equals(tname)) { - name = element.getBody(); - } else if ("function-class".equals(tname)) { - klass = element.getBody(); - } else if ("function-signature".equals(tname)) { - signature = element.getBody(); - } else if ("display-name".equals(tname) || // Ignored elements - "small-icon".equals(tname) || "large-icon".equals(tname) - || "description".equals(tname) || "example".equals(tname)) { - } else { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.warning.unknown.element.in.function", tname)); - } - } - } - - return new FunctionInfo(name, klass, signature); - } - - // ********************************************************************* - // Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed - - /** - * The instance (if any) for the TagLibraryValidator class. - * - * @return The TagLibraryValidator instance, if any. - */ - public TagLibraryValidator getTagLibraryValidator() { - return tagLibraryValidator; - } - - /** - * Translation-time validation of the XML document associated with the JSP - * page. This is a convenience method on the associated TagLibraryValidator - * class. - * - * @param thePage - * The JSP page object - * @return A string indicating whether the page is valid or not. - */ - public ValidationMessage[] validate(PageData thePage) { - TagLibraryValidator tlv = getTagLibraryValidator(); - if (tlv == null) - return null; - - String uri = getURI(); - if (uri.startsWith("/")) { - uri = URN_JSPTLD + uri; - } - - return tlv.validate(getPrefixString(), uri, thePage); - } - - protected TagLibraryValidator tagLibraryValidator; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.net.JarURLConnection; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.Vector; +import java.util.jar.JarFile; +import java.util.zip.ZipEntry; + +import javax.servlet.jsp.tagext.FunctionInfo; +import javax.servlet.jsp.tagext.PageData; +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagExtraInfo; +import javax.servlet.jsp.tagext.TagFileInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.servlet.jsp.tagext.TagLibraryValidator; +import javax.servlet.jsp.tagext.TagVariableInfo; +import javax.servlet.jsp.tagext.ValidationMessage; +import javax.servlet.jsp.tagext.VariableInfo; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.jasper.xmlparser.TreeNode; + +/** + * Implementation of the TagLibraryInfo class from the JSP spec. + * + * @author Anil K. Vijendran + * @author Mandar Raje + * @author Pierre Delisle + * @author Kin-man Chung + * @author Jan Luehe + */ +class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants { + + // Logger + private Log log = LogFactory.getLog(TagLibraryInfoImpl.class); + + private Hashtable jarEntries; + + private JspCompilationContext ctxt; + + private ErrorDispatcher err; + + private ParserController parserController; + + private final void print(String name, String value, PrintWriter w) { + if (value != null) { + w.print(name + " = {\n\t"); + w.print(value); + w.print("\n}\n"); + } + } + + public String toString() { + StringWriter sw = new StringWriter(); + PrintWriter out = new PrintWriter(sw); + print("tlibversion", tlibversion, out); + print("jspversion", jspversion, out); + print("shortname", shortname, out); + print("urn", urn, out); + print("info", info, out); + print("uri", uri, out); + print("tagLibraryValidator", "" + tagLibraryValidator, out); + + for (int i = 0; i < tags.length; i++) + out.println(tags[i].toString()); + + for (int i = 0; i < tagFiles.length; i++) + out.println(tagFiles[i].toString()); + + for (int i = 0; i < functions.length; i++) + out.println(functions[i].toString()); + + return sw.toString(); + } + + // XXX FIXME + // resolveRelativeUri and/or getResourceAsStream don't seem to properly + // handle relative paths when dealing when home and getDocBase are set + // the following is a workaround until these problems are resolved. + private InputStream getResourceAsStream(String uri) + throws FileNotFoundException { + try { + // see if file exists on the filesystem first + String real = ctxt.getRealPath(uri); + if (real == null) { + return ctxt.getResourceAsStream(uri); + } else { + return new FileInputStream(real); + } + } catch (FileNotFoundException ex) { + // if file not found on filesystem, get the resource through + // the context + return ctxt.getResourceAsStream(uri); + } + + } + + /** + * Constructor. + */ + public TagLibraryInfoImpl(JspCompilationContext ctxt, ParserController pc, + String prefix, String uriIn, String[] location, ErrorDispatcher err) + throws JasperException { + super(prefix, uriIn); + + this.ctxt = ctxt; + this.parserController = pc; + this.err = err; + InputStream in = null; + JarFile jarFile = null; + + if (location == null) { + // The URI points to the TLD itself or to a JAR file in which the + // TLD is stored + location = generateTLDLocation(uri, ctxt); + } + + try { + if (!location[0].endsWith("jar")) { + // Location points to TLD file + try { + in = getResourceAsStream(location[0]); + if (in == null) { + throw new FileNotFoundException(location[0]); + } + } catch (FileNotFoundException ex) { + err.jspError("jsp.error.file.not.found", location[0]); + } + + parseTLD(ctxt, location[0], in, null); + // Add TLD to dependency list + PageInfo pageInfo = ctxt.createCompiler().getPageInfo(); + if (pageInfo != null) { + pageInfo.addDependant(location[0]); + } + } else { + // Tag library is packaged in JAR file + try { + URL jarFileUrl = new URL("jar:" + location[0] + "!/"); + JarURLConnection conn = (JarURLConnection) jarFileUrl + .openConnection(); + conn.setUseCaches(false); + conn.connect(); + jarFile = conn.getJarFile(); + ZipEntry jarEntry = jarFile.getEntry(location[1]); + in = jarFile.getInputStream(jarEntry); + parseTLD(ctxt, location[0], in, jarFileUrl); + } catch (Exception ex) { + err.jspError("jsp.error.tld.unable_to_read", location[0], + location[1], ex.toString()); + } + } + } finally { + if (in != null) { + try { + in.close(); + } catch (Throwable t) { + } + } + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + } + } + } + + } + + /* + * @param ctxt The JSP compilation context @param uri The TLD's uri @param + * in The TLD's input stream @param jarFileUrl The JAR file containing the + * TLD, or null if the tag library is not packaged in a JAR + */ + private void parseTLD(JspCompilationContext ctxt, String uri, + InputStream in, URL jarFileUrl) throws JasperException { + Vector tagVector = new Vector(); + Vector tagFileVector = new Vector(); + Hashtable functionTable = new Hashtable(); + + // Create an iterator over the child elements of our element + ParserUtils pu = new ParserUtils(); + TreeNode tld = pu.parseXMLDocument(uri, in); + + // Check to see if the root element contains a 'version' + // attribute, which was added in JSP 2.0 to replace the + // subelement + this.jspversion = tld.findAttribute("version"); + + // Process each child element of our element + Iterator list = tld.findChildren(); + + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + + if ("tlibversion".equals(tname) // JSP 1.1 + || "tlib-version".equals(tname)) { // JSP 1.2 + this.tlibversion = element.getBody(); + } else if ("jspversion".equals(tname) + || "jsp-version".equals(tname)) { + this.jspversion = element.getBody(); + } else if ("shortname".equals(tname) || "short-name".equals(tname)) + this.shortname = element.getBody(); + else if ("uri".equals(tname)) + this.urn = element.getBody(); + else if ("info".equals(tname) || "description".equals(tname)) + this.info = element.getBody(); + else if ("validator".equals(tname)) + this.tagLibraryValidator = createValidator(element); + else if ("tag".equals(tname)) + tagVector.addElement(createTagInfo(element, jspversion)); + else if ("tag-file".equals(tname)) { + TagFileInfo tagFileInfo = createTagFileInfo(element, uri, + jarFileUrl); + tagFileVector.addElement(tagFileInfo); + } else if ("function".equals(tname)) { // JSP2.0 + FunctionInfo funcInfo = createFunctionInfo(element); + String funcName = funcInfo.getName(); + if (functionTable.containsKey(funcName)) { + err.jspError("jsp.error.tld.fn.duplicate.name", funcName, + uri); + + } + functionTable.put(funcName, funcInfo); + } else if ("display-name".equals(tname) || // Ignored elements + "small-icon".equals(tname) || "large-icon".equals(tname) + || "listener".equals(tname)) { + ; + } else if ("taglib-extension".equals(tname)) { + // Recognized but ignored + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.taglib", tname)); + } + } + + } + + if (tlibversion == null) { + err.jspError("jsp.error.tld.mandatory.element.missing", + "tlib-version"); + } + if (jspversion == null) { + err.jspError("jsp.error.tld.mandatory.element.missing", + "jsp-version"); + } + + this.tags = new TagInfo[tagVector.size()]; + tagVector.copyInto(this.tags); + + this.tagFiles = new TagFileInfo[tagFileVector.size()]; + tagFileVector.copyInto(this.tagFiles); + + this.functions = new FunctionInfo[functionTable.size()]; + int i = 0; + Enumeration enumeration = functionTable.elements(); + while (enumeration.hasMoreElements()) { + this.functions[i++] = (FunctionInfo) enumeration.nextElement(); + } + } + + /* + * @param uri The uri of the TLD @param ctxt The compilation context + * + * @return String array whose first element denotes the path to the TLD. If + * the path to the TLD points to a jar file, then the second element denotes + * the name of the TLD entry in the jar file, which is hardcoded to + * META-INF/taglib.tld. + */ + private String[] generateTLDLocation(String uri, JspCompilationContext ctxt) + throws JasperException { + + int uriType = TldLocationsCache.uriType(uri); + if (uriType == TldLocationsCache.ABS_URI) { + err.jspError("jsp.error.taglibDirective.absUriCannotBeResolved", + uri); + } else if (uriType == TldLocationsCache.NOROOT_REL_URI) { + uri = ctxt.resolveRelativeUri(uri); + } + + String[] location = new String[2]; + location[0] = uri; + if (location[0].endsWith("jar")) { + URL url = null; + try { + url = ctxt.getResource(location[0]); + } catch (Exception ex) { + err.jspError("jsp.error.tld.unable_to_get_jar", location[0], ex + .toString()); + } + if (url == null) { + err.jspError("jsp.error.tld.missing_jar", location[0]); + } + location[0] = url.toString(); + location[1] = "META-INF/taglib.tld"; + } + + return location; + } + + private TagInfo createTagInfo(TreeNode elem, String jspVersion) + throws JasperException { + + String tagName = null; + String tagClassName = null; + String teiClassName = null; + + /* + * Default body content for JSP 1.2 tag handlers ( has + * become mandatory in JSP 2.0, because the default would be invalid for + * simple tag handlers) + */ + String bodycontent = "JSP"; + + String info = null; + String displayName = null; + String smallIcon = null; + String largeIcon = null; + boolean dynamicAttributes = false; + + Vector attributeVector = new Vector(); + Vector variableVector = new Vector(); + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + + if ("name".equals(tname)) { + tagName = element.getBody(); + } else if ("tagclass".equals(tname) || "tag-class".equals(tname)) { + tagClassName = element.getBody(); + } else if ("teiclass".equals(tname) || "tei-class".equals(tname)) { + teiClassName = element.getBody(); + } else if ("bodycontent".equals(tname) + || "body-content".equals(tname)) { + bodycontent = element.getBody(); + } else if ("display-name".equals(tname)) { + displayName = element.getBody(); + } else if ("small-icon".equals(tname)) { + smallIcon = element.getBody(); + } else if ("large-icon".equals(tname)) { + largeIcon = element.getBody(); + } else if ("icon".equals(tname)) { + TreeNode icon = element.findChild("small-icon"); + if (icon != null) { + smallIcon = icon.getBody(); + } + icon = element.findChild("large-icon"); + if (icon != null) { + largeIcon = icon.getBody(); + } + } else if ("info".equals(tname) || "description".equals(tname)) { + info = element.getBody(); + } else if ("variable".equals(tname)) { + variableVector.addElement(createVariable(element)); + } else if ("attribute".equals(tname)) { + attributeVector + .addElement(createAttribute(element, jspVersion)); + } else if ("dynamic-attributes".equals(tname)) { + dynamicAttributes = JspUtil.booleanValue(element.getBody()); + } else if ("example".equals(tname)) { + // Ignored elements + } else if ("tag-extension".equals(tname)) { + // Ignored + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.tag", tname)); + } + } + } + + TagExtraInfo tei = null; + if (teiClassName != null && !teiClassName.equals("")) { + try { + Class teiClass = ctxt.getClassLoader().loadClass(teiClassName); + tei = (TagExtraInfo) teiClass.newInstance(); + } catch (Exception e) { + err.jspError("jsp.error.teiclass.instantiation", teiClassName, + e); + } + } + + TagAttributeInfo[] tagAttributeInfo = new TagAttributeInfo[attributeVector + .size()]; + attributeVector.copyInto(tagAttributeInfo); + + TagVariableInfo[] tagVariableInfos = new TagVariableInfo[variableVector + .size()]; + variableVector.copyInto(tagVariableInfos); + + TagInfo taginfo = new TagInfo(tagName, tagClassName, bodycontent, info, + this, tei, tagAttributeInfo, displayName, smallIcon, largeIcon, + tagVariableInfos, dynamicAttributes); + return taginfo; + } + + /* + * Parses the tag file directives of the given TagFile and turns them into a + * TagInfo. + * + * @param elem The element in the TLD @param uri The location of + * the TLD, in case the tag file is specified relative to it @param jarFile + * The JAR file, in case the tag file is packaged in a JAR + * + * @return TagInfo correspoding to tag file directives + */ + private TagFileInfo createTagFileInfo(TreeNode elem, String uri, + URL jarFileUrl) throws JasperException { + + String name = null; + String path = null; + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode child = (TreeNode) list.next(); + String tname = child.getName(); + if ("name".equals(tname)) { + name = child.getBody(); + } else if ("path".equals(tname)) { + path = child.getBody(); + } else if ("example".equals(tname)) { + // Ignore element: Bugzilla 33538 + } else if ("tag-extension".equals(tname)) { + // Ignore element: Bugzilla 33538 + } else if ("icon".equals(tname) + || "display-name".equals(tname) + || "description".equals(tname)) { + // Ignore these elements: Bugzilla 38015 + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.tagfile", tname)); + } + } + } + + if (path.startsWith("/META-INF/tags")) { + // Tag file packaged in JAR + ctxt.getTagFileJarUrls().put(path, jarFileUrl); + } else if (!path.startsWith("/WEB-INF/tags")) { + err.jspError("jsp.error.tagfile.illegalPath", path); + } + + TagInfo tagInfo = TagFileProcessor.parseTagFileDirectives( + parserController, name, path, this); + return new TagFileInfo(name, path, tagInfo); + } + + TagAttributeInfo createAttribute(TreeNode elem, String jspVersion) { + String name = null; + String type = null; + String expectedType = null; + String methodSignature = null; + boolean required = false, rtexprvalue = false, reqTime = false, isFragment = false, deferredValue = false, deferredMethod = false; + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + + if ("name".equals(tname)) { + name = element.getBody(); + } else if ("required".equals(tname)) { + String s = element.getBody(); + if (s != null) + required = JspUtil.booleanValue(s); + } else if ("rtexprvalue".equals(tname)) { + String s = element.getBody(); + if (s != null) + rtexprvalue = JspUtil.booleanValue(s); + } else if ("type".equals(tname)) { + type = element.getBody(); + if ("1.2".equals(jspVersion) + && (type.equals("Boolean") || type.equals("Byte") + || type.equals("Character") + || type.equals("Double") + || type.equals("Float") + || type.equals("Integer") + || type.equals("Long") || type.equals("Object") + || type.equals("Short") || type + .equals("String"))) { + type = "java.lang." + type; + } + } else if ("fragment".equals(tname)) { + String s = element.getBody(); + if (s != null) { + isFragment = JspUtil.booleanValue(s); + } + } else if ("deferred-value".equals(tname)) { + deferredValue = true; + type = "javax.el.ValueExpression"; + TreeNode child = element.findChild("type"); + if (child != null) { + expectedType = child.getBody(); + if (expectedType != null) { + expectedType = expectedType.trim(); + } + } else { + expectedType = "java.lang.Object"; + } + } else if ("deferred-method".equals(tname)) { + deferredMethod = true; + type = "javax.el.MethodExpression"; + TreeNode child = element.findChild("method-signature"); + if (child != null) { + methodSignature = child.getBody(); + if (methodSignature != null) { + methodSignature = methodSignature.trim(); + } + } else { + methodSignature = "java.lang.Object method()"; + } + } else if ("description".equals(tname) || // Ignored elements + false) { + ; + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.attribute", tname)); + } + } + } + + if (isFragment) { + /* + * According to JSP.C-3 ("TLD Schema Element Structure - tag"), + * 'type' and 'rtexprvalue' must not be specified if 'fragment' has + * been specified (this will be enforced by validating parser). + * Also, if 'fragment' is TRUE, 'type' is fixed at + * javax.servlet.jsp.tagext.JspFragment, and 'rtexprvalue' is fixed + * at true. See also JSP.8.5.2. + */ + type = "javax.servlet.jsp.tagext.JspFragment"; + rtexprvalue = true; + } + + if (!rtexprvalue && type == null) { + // According to JSP spec, for static values (those determined at + // translation time) the type is fixed at java.lang.String. + type = "java.lang.String"; + } + + return new TagAttributeInfo(name, required, type, rtexprvalue, + isFragment, null, deferredValue, deferredMethod, expectedType, + methodSignature); + } + + TagVariableInfo createVariable(TreeNode elem) { + String nameGiven = null; + String nameFromAttribute = null; + String className = "java.lang.String"; + boolean declare = true; + int scope = VariableInfo.NESTED; + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + if ("name-given".equals(tname)) + nameGiven = element.getBody(); + else if ("name-from-attribute".equals(tname)) + nameFromAttribute = element.getBody(); + else if ("variable-class".equals(tname)) + className = element.getBody(); + else if ("declare".equals(tname)) { + String s = element.getBody(); + if (s != null) + declare = JspUtil.booleanValue(s); + } else if ("scope".equals(tname)) { + String s = element.getBody(); + if (s != null) { + if ("NESTED".equals(s)) { + scope = VariableInfo.NESTED; + } else if ("AT_BEGIN".equals(s)) { + scope = VariableInfo.AT_BEGIN; + } else if ("AT_END".equals(s)) { + scope = VariableInfo.AT_END; + } + } + } else if ("description".equals(tname) || // Ignored elements + false) { + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.variable", tname)); + } + } + } + return new TagVariableInfo(nameGiven, nameFromAttribute, className, + declare, scope); + } + + private TagLibraryValidator createValidator(TreeNode elem) + throws JasperException { + + String validatorClass = null; + Map initParams = new Hashtable(); + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + if ("validator-class".equals(tname)) + validatorClass = element.getBody(); + else if ("init-param".equals(tname)) { + String[] initParam = createInitParam(element); + initParams.put(initParam[0], initParam[1]); + } else if ("description".equals(tname) || // Ignored elements + false) { + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.validator", tname)); + } + } + } + + TagLibraryValidator tlv = null; + if (validatorClass != null && !validatorClass.equals("")) { + try { + Class tlvClass = ctxt.getClassLoader() + .loadClass(validatorClass); + tlv = (TagLibraryValidator) tlvClass.newInstance(); + } catch (Exception e) { + err.jspError("jsp.error.tlvclass.instantiation", + validatorClass, e); + } + } + if (tlv != null) { + tlv.setInitParameters(initParams); + } + return tlv; + } + + String[] createInitParam(TreeNode elem) { + String[] initParam = new String[2]; + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + if ("param-name".equals(tname)) { + initParam[0] = element.getBody(); + } else if ("param-value".equals(tname)) { + initParam[1] = element.getBody(); + } else if ("description".equals(tname)) { + ; // Do nothing + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.initParam", tname)); + } + } + } + return initParam; + } + + FunctionInfo createFunctionInfo(TreeNode elem) { + + String name = null; + String klass = null; + String signature = null; + + Iterator list = elem.findChildren(); + while (list.hasNext()) { + TreeNode element = (TreeNode) list.next(); + String tname = element.getName(); + + if ("name".equals(tname)) { + name = element.getBody(); + } else if ("function-class".equals(tname)) { + klass = element.getBody(); + } else if ("function-signature".equals(tname)) { + signature = element.getBody(); + } else if ("display-name".equals(tname) || // Ignored elements + "small-icon".equals(tname) || "large-icon".equals(tname) + || "description".equals(tname) || "example".equals(tname)) { + } else { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.warning.unknown.element.in.function", tname)); + } + } + } + + return new FunctionInfo(name, klass, signature); + } + + // ********************************************************************* + // Until javax.servlet.jsp.tagext.TagLibraryInfo is fixed + + /** + * The instance (if any) for the TagLibraryValidator class. + * + * @return The TagLibraryValidator instance, if any. + */ + public TagLibraryValidator getTagLibraryValidator() { + return tagLibraryValidator; + } + + /** + * Translation-time validation of the XML document associated with the JSP + * page. This is a convenience method on the associated TagLibraryValidator + * class. + * + * @param thePage + * The JSP page object + * @return A string indicating whether the page is valid or not. + */ + public ValidationMessage[] validate(PageData thePage) { + TagLibraryValidator tlv = getTagLibraryValidator(); + if (tlv == null) + return null; + + String uri = getURI(); + if (uri.startsWith("/")) { + uri = URN_JSPTLD + uri; + } + + return tlv.validate(getPrefixString(), uri, thePage); + } + + protected TagLibraryValidator tagLibraryValidator; +} diff --git a/java/org/apache/jasper/compiler/TagPluginManager.java b/java/org/apache/jasper/compiler/TagPluginManager.java index 4b26e60fd..a918f0052 100644 --- a/java/org/apache/jasper/compiler/TagPluginManager.java +++ b/java/org/apache/jasper/compiler/TagPluginManager.java @@ -1,239 +1,239 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.util.*; -import java.io.*; -import javax.servlet.ServletContext; - -import org.apache.jasper.JasperException; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.jasper.xmlparser.TreeNode; -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - -/** - * Manages tag plugin optimizations. - * @author Kin-man Chung - */ - -public class TagPluginManager { - - private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml"; - private static final String TAG_PLUGINS_ROOT_ELEM = "tag-plugins"; - - private boolean initialized = false; - private HashMap tagPlugins = null; - private ServletContext ctxt; - private PageInfo pageInfo; - - public TagPluginManager(ServletContext ctxt) { - this.ctxt = ctxt; - } - - public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo) - throws JasperException { - - init(err); - if (tagPlugins == null || tagPlugins.size() == 0) { - return; - } - - this.pageInfo = pageInfo; - - page.visit(new Node.Visitor() { - public void visit(Node.CustomTag n) - throws JasperException { - invokePlugin(n); - visitBody(n); - } - }); - - } - - private void init(ErrorDispatcher err) throws JasperException { - if (initialized) - return; - - InputStream is = ctxt.getResourceAsStream(TAG_PLUGINS_XML); - if (is == null) - return; - - TreeNode root = (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML, - is); - if (root == null) { - return; - } - - if (!TAG_PLUGINS_ROOT_ELEM.equals(root.getName())) { - err.jspError("jsp.error.plugin.wrongRootElement", TAG_PLUGINS_XML, - TAG_PLUGINS_ROOT_ELEM); - } - - tagPlugins = new HashMap(); - Iterator pluginList = root.findChildren("tag-plugin"); - while (pluginList.hasNext()) { - TreeNode pluginNode = (TreeNode) pluginList.next(); - TreeNode tagClassNode = pluginNode.findChild("tag-class"); - if (tagClassNode == null) { - // Error - return; - } - String tagClass = tagClassNode.getBody().trim(); - TreeNode pluginClassNode = pluginNode.findChild("plugin-class"); - if (pluginClassNode == null) { - // Error - return; - } - - String pluginClassStr = pluginClassNode.getBody(); - TagPlugin tagPlugin = null; - try { - Class pluginClass = Class.forName(pluginClassStr); - tagPlugin = (TagPlugin) pluginClass.newInstance(); - } catch (Exception e) { - throw new JasperException(e); - } - if (tagPlugin == null) { - return; - } - tagPlugins.put(tagClass, tagPlugin); - } - initialized = true; - } - - /** - * Invoke tag plugin for the given custom tag, if a plugin exists for - * the custom tag's tag handler. - * - * The given custom tag node will be manipulated by the plugin. - */ - private void invokePlugin(Node.CustomTag n) { - TagPlugin tagPlugin = (TagPlugin) - tagPlugins.get(n.getTagHandlerClass().getName()); - if (tagPlugin == null) { - return; - } - - TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo); - n.setTagPluginContext(tagPluginContext); - tagPlugin.doTag(tagPluginContext); - } - - static class TagPluginContextImpl implements TagPluginContext { - private Node.CustomTag node; - private Node.Nodes curNodes; - private PageInfo pageInfo; - private HashMap pluginAttributes; - - TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) { - this.node = n; - this.pageInfo = pageInfo; - curNodes = new Node.Nodes(); - n.setAtETag(curNodes); - curNodes = new Node.Nodes(); - n.setAtSTag(curNodes); - n.setUseTagPlugin(true); - pluginAttributes = new HashMap(); - } - - public TagPluginContext getParentContext() { - Node parent = node.getParent(); - if (! (parent instanceof Node.CustomTag)) { - return null; - } - return ((Node.CustomTag) parent).getTagPluginContext(); - } - - public void setPluginAttribute(String key, Object value) { - pluginAttributes.put(key, value); - } - - public Object getPluginAttribute(String key) { - return pluginAttributes.get(key); - } - - public boolean isScriptless() { - return node.getChildInfo().isScriptless(); - } - - public boolean isConstantAttribute(String attribute) { - Node.JspAttribute attr = getNodeAttribute(attribute); - if (attr == null) - return false; - return attr.isLiteral(); - } - - public String getConstantAttribute(String attribute) { - Node.JspAttribute attr = getNodeAttribute(attribute); - if (attr == null) - return null; - return attr.getValue(); - } - - public boolean isAttributeSpecified(String attribute) { - return getNodeAttribute(attribute) != null; - } - - public String getTemporaryVariableName() { - return JspUtil.nextTemporaryVariableName(); - } - - public void generateImport(String imp) { - pageInfo.addImport(imp); - } - - public void generateDeclaration(String id, String text) { - if (pageInfo.isPluginDeclared(id)) { - return; - } - curNodes.add(new Node.Declaration(text, node.getStart(), null)); - } - - public void generateJavaSource(String sourceCode) { - curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(), - null)); - } - - public void generateAttribute(String attributeName) { - curNodes.add(new Node.AttributeGenerator(node.getStart(), - attributeName, - node)); - } - - public void dontUseTagPlugin() { - node.setUseTagPlugin(false); - } - - public void generateBody() { - // Since we'll generate the body anyway, this is really a nop, - // except for the fact that it lets us put the Java sources the - // plugins produce in the correct order (w.r.t the body). - curNodes = node.getAtETag(); - } - - private Node.JspAttribute getNodeAttribute(String attribute) { - Node.JspAttribute[] attrs = node.getJspAttributes(); - for (int i=0; attrs != null && i < attrs.length; i++) { - if (attrs[i].getName().equals(attribute)) { - return attrs[i]; - } - } - return null; - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.util.*; +import java.io.*; +import javax.servlet.ServletContext; + +import org.apache.jasper.JasperException; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.jasper.xmlparser.TreeNode; +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + +/** + * Manages tag plugin optimizations. + * @author Kin-man Chung + */ + +public class TagPluginManager { + + private static final String TAG_PLUGINS_XML = "/WEB-INF/tagPlugins.xml"; + private static final String TAG_PLUGINS_ROOT_ELEM = "tag-plugins"; + + private boolean initialized = false; + private HashMap tagPlugins = null; + private ServletContext ctxt; + private PageInfo pageInfo; + + public TagPluginManager(ServletContext ctxt) { + this.ctxt = ctxt; + } + + public void apply(Node.Nodes page, ErrorDispatcher err, PageInfo pageInfo) + throws JasperException { + + init(err); + if (tagPlugins == null || tagPlugins.size() == 0) { + return; + } + + this.pageInfo = pageInfo; + + page.visit(new Node.Visitor() { + public void visit(Node.CustomTag n) + throws JasperException { + invokePlugin(n); + visitBody(n); + } + }); + + } + + private void init(ErrorDispatcher err) throws JasperException { + if (initialized) + return; + + InputStream is = ctxt.getResourceAsStream(TAG_PLUGINS_XML); + if (is == null) + return; + + TreeNode root = (new ParserUtils()).parseXMLDocument(TAG_PLUGINS_XML, + is); + if (root == null) { + return; + } + + if (!TAG_PLUGINS_ROOT_ELEM.equals(root.getName())) { + err.jspError("jsp.error.plugin.wrongRootElement", TAG_PLUGINS_XML, + TAG_PLUGINS_ROOT_ELEM); + } + + tagPlugins = new HashMap(); + Iterator pluginList = root.findChildren("tag-plugin"); + while (pluginList.hasNext()) { + TreeNode pluginNode = (TreeNode) pluginList.next(); + TreeNode tagClassNode = pluginNode.findChild("tag-class"); + if (tagClassNode == null) { + // Error + return; + } + String tagClass = tagClassNode.getBody().trim(); + TreeNode pluginClassNode = pluginNode.findChild("plugin-class"); + if (pluginClassNode == null) { + // Error + return; + } + + String pluginClassStr = pluginClassNode.getBody(); + TagPlugin tagPlugin = null; + try { + Class pluginClass = Class.forName(pluginClassStr); + tagPlugin = (TagPlugin) pluginClass.newInstance(); + } catch (Exception e) { + throw new JasperException(e); + } + if (tagPlugin == null) { + return; + } + tagPlugins.put(tagClass, tagPlugin); + } + initialized = true; + } + + /** + * Invoke tag plugin for the given custom tag, if a plugin exists for + * the custom tag's tag handler. + * + * The given custom tag node will be manipulated by the plugin. + */ + private void invokePlugin(Node.CustomTag n) { + TagPlugin tagPlugin = (TagPlugin) + tagPlugins.get(n.getTagHandlerClass().getName()); + if (tagPlugin == null) { + return; + } + + TagPluginContext tagPluginContext = new TagPluginContextImpl(n, pageInfo); + n.setTagPluginContext(tagPluginContext); + tagPlugin.doTag(tagPluginContext); + } + + static class TagPluginContextImpl implements TagPluginContext { + private Node.CustomTag node; + private Node.Nodes curNodes; + private PageInfo pageInfo; + private HashMap pluginAttributes; + + TagPluginContextImpl(Node.CustomTag n, PageInfo pageInfo) { + this.node = n; + this.pageInfo = pageInfo; + curNodes = new Node.Nodes(); + n.setAtETag(curNodes); + curNodes = new Node.Nodes(); + n.setAtSTag(curNodes); + n.setUseTagPlugin(true); + pluginAttributes = new HashMap(); + } + + public TagPluginContext getParentContext() { + Node parent = node.getParent(); + if (! (parent instanceof Node.CustomTag)) { + return null; + } + return ((Node.CustomTag) parent).getTagPluginContext(); + } + + public void setPluginAttribute(String key, Object value) { + pluginAttributes.put(key, value); + } + + public Object getPluginAttribute(String key) { + return pluginAttributes.get(key); + } + + public boolean isScriptless() { + return node.getChildInfo().isScriptless(); + } + + public boolean isConstantAttribute(String attribute) { + Node.JspAttribute attr = getNodeAttribute(attribute); + if (attr == null) + return false; + return attr.isLiteral(); + } + + public String getConstantAttribute(String attribute) { + Node.JspAttribute attr = getNodeAttribute(attribute); + if (attr == null) + return null; + return attr.getValue(); + } + + public boolean isAttributeSpecified(String attribute) { + return getNodeAttribute(attribute) != null; + } + + public String getTemporaryVariableName() { + return JspUtil.nextTemporaryVariableName(); + } + + public void generateImport(String imp) { + pageInfo.addImport(imp); + } + + public void generateDeclaration(String id, String text) { + if (pageInfo.isPluginDeclared(id)) { + return; + } + curNodes.add(new Node.Declaration(text, node.getStart(), null)); + } + + public void generateJavaSource(String sourceCode) { + curNodes.add(new Node.Scriptlet(sourceCode, node.getStart(), + null)); + } + + public void generateAttribute(String attributeName) { + curNodes.add(new Node.AttributeGenerator(node.getStart(), + attributeName, + node)); + } + + public void dontUseTagPlugin() { + node.setUseTagPlugin(false); + } + + public void generateBody() { + // Since we'll generate the body anyway, this is really a nop, + // except for the fact that it lets us put the Java sources the + // plugins produce in the correct order (w.r.t the body). + curNodes = node.getAtETag(); + } + + private Node.JspAttribute getNodeAttribute(String attribute) { + Node.JspAttribute[] attrs = node.getJspAttributes(); + for (int i=0; attrs != null && i < attrs.length; i++) { + if (attrs[i].getName().equals(attribute)) { + return attrs[i]; + } + } + return null; + } + } +} diff --git a/java/org/apache/jasper/compiler/TextOptimizer.java b/java/org/apache/jasper/compiler/TextOptimizer.java index e0de0addc..e4f209c90 100644 --- a/java/org/apache/jasper/compiler/TextOptimizer.java +++ b/java/org/apache/jasper/compiler/TextOptimizer.java @@ -1,112 +1,112 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.compiler; - -import org.apache.jasper.JasperException; -import org.apache.jasper.Options; - -/** - */ -public class TextOptimizer { - - /** - * A visitor to concatenate contiguous template texts. - */ - static class TextCatVisitor extends Node.Visitor { - - private Options options; - private int textNodeCount = 0; - private Node.TemplateText firstTextNode = null; - private StringBuffer textBuffer; - private final String emptyText = new String(""); - - public TextCatVisitor(Compiler compiler) { - options = compiler.getCompilationContext().getOptions(); - } - - public void doVisit(Node n) throws JasperException { - collectText(); - } - - /* - * The following directis are ignored in text concatenation - */ - - public void visit(Node.PageDirective n) throws JasperException { - } - - public void visit(Node.TagDirective n) throws JasperException { - } - - public void visit(Node.TaglibDirective n) throws JasperException { - } - - public void visit(Node.AttributeDirective n) throws JasperException { - } - - public void visit(Node.VariableDirective n) throws JasperException { - } - - /* - * Don't concatenate text across body boundaries - */ - public void visitBody(Node n) throws JasperException { - super.visitBody(n); - collectText(); - } - - public void visit(Node.TemplateText n) throws JasperException { - - if (options.getTrimSpaces() && n.isAllSpace()) { - n.setText(emptyText); - return; - } - - if (textNodeCount++ == 0) { - firstTextNode = n; - textBuffer = new StringBuffer(n.getText()); - } else { - // Append text to text buffer - textBuffer.append(n.getText()); - n.setText(emptyText); - } - } - - /** - * This method breaks concatenation mode. As a side effect it copies - * the concatenated string to the first text node - */ - private void collectText() { - - if (textNodeCount > 1) { - // Copy the text in buffer into the first template text node. - firstTextNode.setText(textBuffer.toString()); - } - textNodeCount = 0; - } - - } - - public static void concatenate(Compiler compiler, Node.Nodes page) - throws JasperException { - - TextCatVisitor v = new TextCatVisitor(compiler); - page.visit(v); - - // Cleanup, in case the page ends with a template text - v.collectText(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.compiler; + +import org.apache.jasper.JasperException; +import org.apache.jasper.Options; + +/** + */ +public class TextOptimizer { + + /** + * A visitor to concatenate contiguous template texts. + */ + static class TextCatVisitor extends Node.Visitor { + + private Options options; + private int textNodeCount = 0; + private Node.TemplateText firstTextNode = null; + private StringBuffer textBuffer; + private final String emptyText = new String(""); + + public TextCatVisitor(Compiler compiler) { + options = compiler.getCompilationContext().getOptions(); + } + + public void doVisit(Node n) throws JasperException { + collectText(); + } + + /* + * The following directis are ignored in text concatenation + */ + + public void visit(Node.PageDirective n) throws JasperException { + } + + public void visit(Node.TagDirective n) throws JasperException { + } + + public void visit(Node.TaglibDirective n) throws JasperException { + } + + public void visit(Node.AttributeDirective n) throws JasperException { + } + + public void visit(Node.VariableDirective n) throws JasperException { + } + + /* + * Don't concatenate text across body boundaries + */ + public void visitBody(Node n) throws JasperException { + super.visitBody(n); + collectText(); + } + + public void visit(Node.TemplateText n) throws JasperException { + + if (options.getTrimSpaces() && n.isAllSpace()) { + n.setText(emptyText); + return; + } + + if (textNodeCount++ == 0) { + firstTextNode = n; + textBuffer = new StringBuffer(n.getText()); + } else { + // Append text to text buffer + textBuffer.append(n.getText()); + n.setText(emptyText); + } + } + + /** + * This method breaks concatenation mode. As a side effect it copies + * the concatenated string to the first text node + */ + private void collectText() { + + if (textNodeCount > 1) { + // Copy the text in buffer into the first template text node. + firstTextNode.setText(textBuffer.toString()); + } + textNodeCount = 0; + } + + } + + public static void concatenate(Compiler compiler, Node.Nodes page) + throws JasperException { + + TextCatVisitor v = new TextCatVisitor(compiler); + page.visit(v); + + // Cleanup, in case the page ends with a template text + v.collectText(); + } +} diff --git a/java/org/apache/jasper/compiler/TldLocationsCache.java b/java/org/apache/jasper/compiler/TldLocationsCache.java index cd9588e44..f8b8b1a3b 100644 --- a/java/org/apache/jasper/compiler/TldLocationsCache.java +++ b/java/org/apache/jasper/compiler/TldLocationsCache.java @@ -1,554 +1,554 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.io.InputStream; -import java.io.IOException; -import java.net.JarURLConnection; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLClassLoader; -import java.net.URLConnection; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; -import org.xml.sax.InputSource; - -import javax.servlet.ServletContext; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.xmlparser.ParserUtils; -import org.apache.jasper.xmlparser.TreeNode; - -/** - * A container for all tag libraries that are defined "globally" - * for the web application. - * - * Tag Libraries can be defined globally in one of two ways: - * 1. Via elements in web.xml: - * the uri and location of the tag-library are specified in - * the element. - * 2. Via packaged jar files that contain .tld files - * within the META-INF directory, or some subdirectory - * of it. The taglib is 'global' if it has the - * element defined. - * - * A mapping between the taglib URI and its associated TaglibraryInfoImpl - * is maintained in this container. - * Actually, that's what we'd like to do. However, because of the - * way the classes TagLibraryInfo and TagInfo have been defined, - * it is not currently possible to share an instance of TagLibraryInfo - * across page invocations. A bug has been submitted to the spec lead. - * In the mean time, all we do is save the 'location' where the - * TLD associated with a taglib URI can be found. - * - * When a JSP page has a taglib directive, the mappings in this container - * are first searched (see method getLocation()). - * If a mapping is found, then the location of the TLD is returned. - * If no mapping is found, then the uri specified - * in the taglib directive is to be interpreted as the location for - * the TLD of this tag library. - * - * @author Pierre Delisle - * @author Jan Luehe - */ - -public class TldLocationsCache { - - // Logger - private Log log = LogFactory.getLog(TldLocationsCache.class); - - /** - * The types of URI one may specify for a tag library - */ - public static final int ABS_URI = 0; - public static final int ROOT_REL_URI = 1; - public static final int NOROOT_REL_URI = 2; - - private static final String WEB_XML = "/WEB-INF/web.xml"; - private static final String FILE_PROTOCOL = "file:"; - private static final String JAR_FILE_SUFFIX = ".jar"; - - // Names of JARs that are known not to contain any TLDs - private static HashSet noTldJars; - - /** - * The mapping of the 'global' tag library URI to the location (resource - * path) of the TLD associated with that tag library. The location is - * returned as a String array: - * [0] The location - * [1] If the location is a jar file, this is the location of the tld. - */ - private Hashtable mappings; - - private boolean initialized; - private ServletContext ctxt; - private boolean redeployMode; - - //********************************************************************* - // Constructor and Initilizations - - /* - * Initializes the set of JARs that are known not to contain any TLDs - */ - static { - noTldJars = new HashSet(); - noTldJars.add("ant.jar"); - noTldJars.add("catalina.jar"); - noTldJars.add("catalina-ant.jar"); - noTldJars.add("catalina-cluster.jar"); - noTldJars.add("catalina-optional.jar"); - noTldJars.add("catalina-i18n-fr.jar"); - noTldJars.add("catalina-i18n-ja.jar"); - noTldJars.add("catalina-i18n-es.jar"); - noTldJars.add("commons-dbcp.jar"); - noTldJars.add("commons-modeler.jar"); - noTldJars.add("commons-logging-api.jar"); - noTldJars.add("commons-beanutils.jar"); - noTldJars.add("commons-fileupload-1.0.jar"); - noTldJars.add("commons-pool.jar"); - noTldJars.add("commons-digester.jar"); - noTldJars.add("commons-logging.jar"); - noTldJars.add("commons-collections.jar"); - noTldJars.add("commons-el.jar"); - noTldJars.add("jakarta-regexp-1.2.jar"); - noTldJars.add("jasper-compiler.jar"); - noTldJars.add("jasper-runtime.jar"); - noTldJars.add("jmx.jar"); - noTldJars.add("jmx-tools.jar"); - noTldJars.add("jsp-api.jar"); - noTldJars.add("jkshm.jar"); - noTldJars.add("jkconfig.jar"); - noTldJars.add("naming-common.jar"); - noTldJars.add("naming-resources.jar"); - noTldJars.add("naming-factory.jar"); - noTldJars.add("naming-java.jar"); - noTldJars.add("servlet-api.jar"); - noTldJars.add("servlets-default.jar"); - noTldJars.add("servlets-invoker.jar"); - noTldJars.add("servlets-common.jar"); - noTldJars.add("servlets-webdav.jar"); - noTldJars.add("tomcat-util.jar"); - noTldJars.add("tomcat-http11.jar"); - noTldJars.add("tomcat-jni.jar"); - noTldJars.add("tomcat-jk.jar"); - noTldJars.add("tomcat-jk2.jar"); - noTldJars.add("tomcat-coyote.jar"); - noTldJars.add("xercesImpl.jar"); - noTldJars.add("xmlParserAPIs.jar"); - noTldJars.add("xml-apis.jar"); - // JARs from J2SE runtime - noTldJars.add("sunjce_provider.jar"); - noTldJars.add("ldapsec.jar"); - noTldJars.add("localedata.jar"); - noTldJars.add("dnsns.jar"); - } - - public TldLocationsCache(ServletContext ctxt) { - this(ctxt, true); - } - - /** Constructor. - * - * @param ctxt the servlet context of the web application in which Jasper - * is running - * @param redeployMode if true, then the compiler will allow redeploying - * a tag library from the same jar, at the expense of slowing down the - * server a bit. Note that this may only work on JDK 1.3.1_01a and later, - * because of JDK bug 4211817 fixed in this release. - * If redeployMode is false, a faster but less capable mode will be used. - */ - public TldLocationsCache(ServletContext ctxt, boolean redeployMode) { - this.ctxt = ctxt; - this.redeployMode = redeployMode; - mappings = new Hashtable(); - initialized = false; - } - - /** - * Sets the list of JARs that are known not to contain any TLDs. - * - * @param jarNames List of comma-separated names of JAR files that are - * known not to contain any TLDs - */ - public static void setNoTldJars(String jarNames) { - if (jarNames != null) { - noTldJars.clear(); - StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); - while (tokenizer.hasMoreElements()) { - noTldJars.add(tokenizer.nextToken()); - } - } - } - - /** - * Gets the 'location' of the TLD associated with the given taglib 'uri'. - * - * Returns null if the uri is not associated with any tag library 'exposed' - * in the web application. A tag library is 'exposed' either explicitly in - * web.xml or implicitly via the uri tag in the TLD of a taglib deployed - * in a jar file (WEB-INF/lib). - * - * @param uri The taglib uri - * - * @return An array of two Strings: The first element denotes the real - * path to the TLD. If the path to the TLD points to a jar file, then the - * second element denotes the name of the TLD entry in the jar file. - * Returns null if the uri is not associated with any tag library 'exposed' - * in the web application. - */ - public String[] getLocation(String uri) throws JasperException { - if (!initialized) { - init(); - } - return (String[]) mappings.get(uri); - } - - /** - * Returns the type of a URI: - * ABS_URI - * ROOT_REL_URI - * NOROOT_REL_URI - */ - public static int uriType(String uri) { - if (uri.indexOf(':') != -1) { - return ABS_URI; - } else if (uri.startsWith("/")) { - return ROOT_REL_URI; - } else { - return NOROOT_REL_URI; - } - } - - private void init() throws JasperException { - if (initialized) return; - try { - processWebDotXml(); - scanJars(); - processTldsInFileSystem("/WEB-INF/"); - initialized = true; - } catch (Exception ex) { - throw new JasperException(Localizer.getMessage( - "jsp.error.internal.tldinit", ex.getMessage())); - } - } - - /* - * Populates taglib map described in web.xml. - */ - private void processWebDotXml() throws Exception { - - InputStream is = null; - - try { - // Acquire input stream to web application deployment descriptor - String altDDName = (String)ctxt.getAttribute( - Constants.ALT_DD_ATTR); - URL uri = null; - if (altDDName != null) { - try { - uri = new URL(FILE_PROTOCOL+altDDName.replace('\\', '/')); - } catch (MalformedURLException e) { - if (log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.error.internal.filenotfound", - altDDName)); - } - } - } else { - uri = ctxt.getResource(WEB_XML); - if (uri == null && log.isWarnEnabled()) { - log.warn(Localizer.getMessage( - "jsp.error.internal.filenotfound", - WEB_XML)); - } - } - - if (uri == null) { - return; - } - is = uri.openStream(); - InputSource ip = new InputSource(is); - ip.setSystemId(uri.toExternalForm()); - - // Parse the web application deployment descriptor - TreeNode webtld = null; - // altDDName is the absolute path of the DD - if (altDDName != null) { - webtld = new ParserUtils().parseXMLDocument(altDDName, ip); - } else { - webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip); - } - - // Allow taglib to be an element of the root or jsp-config (JSP2.0) - TreeNode jspConfig = webtld.findChild("jsp-config"); - if (jspConfig != null) { - webtld = jspConfig; - } - Iterator taglibs = webtld.findChildren("taglib"); - while (taglibs.hasNext()) { - - // Parse the next element - TreeNode taglib = (TreeNode) taglibs.next(); - String tagUri = null; - String tagLoc = null; - TreeNode child = taglib.findChild("taglib-uri"); - if (child != null) - tagUri = child.getBody(); - child = taglib.findChild("taglib-location"); - if (child != null) - tagLoc = child.getBody(); - - // Save this location if appropriate - if (tagLoc == null) - continue; - if (uriType(tagLoc) == NOROOT_REL_URI) - tagLoc = "/WEB-INF/" + tagLoc; - String tagLoc2 = null; - if (tagLoc.endsWith(JAR_FILE_SUFFIX)) { - tagLoc = ctxt.getResource(tagLoc).toString(); - tagLoc2 = "META-INF/taglib.tld"; - } - mappings.put(tagUri, new String[] { tagLoc, tagLoc2 }); - } - } finally { - if (is != null) { - try { - is.close(); - } catch (Throwable t) {} - } - } - } - - /** - * Scans the given JarURLConnection for TLD files located in META-INF - * (or a subdirectory of it), adding an implicit map entry to the taglib - * map for any TLD that has a element. - * - * @param conn The JarURLConnection to the JAR file to scan - * @param ignore true if any exceptions raised when processing the given - * JAR should be ignored, false otherwise - */ - private void scanJar(JarURLConnection conn, boolean ignore) - throws JasperException { - - JarFile jarFile = null; - String resourcePath = conn.getJarFileURL().toString(); - try { - if (redeployMode) { - conn.setUseCaches(false); - } - jarFile = conn.getJarFile(); - Enumeration entries = jarFile.entries(); - while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry) entries.nextElement(); - String name = entry.getName(); - if (!name.startsWith("META-INF/")) continue; - if (!name.endsWith(".tld")) continue; - InputStream stream = jarFile.getInputStream(entry); - try { - String uri = getUriFromTld(resourcePath, stream); - // Add implicit map entry only if its uri is not already - // present in the map - if (uri != null && mappings.get(uri) == null) { - mappings.put(uri, new String[]{ resourcePath, name }); - } - } finally { - if (stream != null) { - try { - stream.close(); - } catch (Throwable t) { - // do nothing - } - } - } - } - } catch (Exception ex) { - if (!redeployMode) { - // if not in redeploy mode, close the jar in case of an error - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - // ignore - } - } - } - if (!ignore) { - throw new JasperException(ex); - } - } finally { - if (redeployMode) { - // if in redeploy mode, always close the jar - if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - // ignore - } - } - } - } - } - - /* - * Searches the filesystem under /WEB-INF for any TLD files, and adds - * an implicit map entry to the taglib map for any TLD that has a - * element. - */ - private void processTldsInFileSystem(String startPath) - throws Exception { - - Set dirList = ctxt.getResourcePaths(startPath); - if (dirList != null) { - Iterator it = dirList.iterator(); - while (it.hasNext()) { - String path = (String) it.next(); - if (path.endsWith("/")) { - processTldsInFileSystem(path); - } - if (!path.endsWith(".tld")) { - continue; - } - InputStream stream = ctxt.getResourceAsStream(path); - String uri = null; - try { - uri = getUriFromTld(path, stream); - } finally { - if (stream != null) { - try { - stream.close(); - } catch (Throwable t) { - // do nothing - } - } - } - // Add implicit map entry only if its uri is not already - // present in the map - if (uri != null && mappings.get(uri) == null) { - mappings.put(uri, new String[] { path, null }); - } - } - } - } - - /* - * Returns the value of the uri element of the given TLD, or null if the - * given TLD does not contain any such element. - */ - private String getUriFromTld(String resourcePath, InputStream in) - throws JasperException - { - // Parse the tag library descriptor at the specified resource path - TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in); - TreeNode uri = tld.findChild("uri"); - if (uri != null) { - String body = uri.getBody(); - if (body != null) - return body; - } - - return null; - } - - /* - * Scans all JARs accessible to the webapp's classloader and its - * parent classloaders for TLDs. - * - * The list of JARs always includes the JARs under WEB-INF/lib, as well as - * all shared JARs in the classloader delegation chain of the webapp's - * classloader. - * - * Considering JARs in the classloader delegation chain constitutes a - * Tomcat-specific extension to the TLD search - * order defined in the JSP spec. It allows tag libraries packaged as JAR - * files to be shared by web applications by simply dropping them in a - * location that all web applications have access to (e.g., - * /common/lib). - * - * The set of shared JARs to be scanned for TLDs is narrowed down by - * the noTldJars class variable, which contains the names of JARs - * that are known not to contain any TLDs. - */ - private void scanJars() throws Exception { - - ClassLoader webappLoader - = Thread.currentThread().getContextClassLoader(); - ClassLoader loader = webappLoader; - - while (loader != null) { - if (loader instanceof URLClassLoader) { - URL[] urls = ((URLClassLoader) loader).getURLs(); - for (int i=0; ijarPath needs to be - * scanned for TLDs. - * - * @param loader The current classloader in the parent chain - * @param webappLoader The webapp classloader - * @param jarPath The JAR file path - * - * @return TRUE if the JAR file identified by jarPath needs to be - * scanned for TLDs, FALSE otherwise - */ - private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader, - String jarPath) { - if (loader == webappLoader) { - // JARs under WEB-INF/lib must be scanned unconditionally according - // to the spec. - return true; - } else { - String jarName = jarPath; - int slash = jarPath.lastIndexOf('/'); - if (slash >= 0) { - jarName = jarPath.substring(slash + 1); - } - return (!noTldJars.contains(jarName)); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.InputStream; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import org.xml.sax.InputSource; + +import javax.servlet.ServletContext; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.xmlparser.ParserUtils; +import org.apache.jasper.xmlparser.TreeNode; + +/** + * A container for all tag libraries that are defined "globally" + * for the web application. + * + * Tag Libraries can be defined globally in one of two ways: + * 1. Via elements in web.xml: + * the uri and location of the tag-library are specified in + * the element. + * 2. Via packaged jar files that contain .tld files + * within the META-INF directory, or some subdirectory + * of it. The taglib is 'global' if it has the + * element defined. + * + * A mapping between the taglib URI and its associated TaglibraryInfoImpl + * is maintained in this container. + * Actually, that's what we'd like to do. However, because of the + * way the classes TagLibraryInfo and TagInfo have been defined, + * it is not currently possible to share an instance of TagLibraryInfo + * across page invocations. A bug has been submitted to the spec lead. + * In the mean time, all we do is save the 'location' where the + * TLD associated with a taglib URI can be found. + * + * When a JSP page has a taglib directive, the mappings in this container + * are first searched (see method getLocation()). + * If a mapping is found, then the location of the TLD is returned. + * If no mapping is found, then the uri specified + * in the taglib directive is to be interpreted as the location for + * the TLD of this tag library. + * + * @author Pierre Delisle + * @author Jan Luehe + */ + +public class TldLocationsCache { + + // Logger + private Log log = LogFactory.getLog(TldLocationsCache.class); + + /** + * The types of URI one may specify for a tag library + */ + public static final int ABS_URI = 0; + public static final int ROOT_REL_URI = 1; + public static final int NOROOT_REL_URI = 2; + + private static final String WEB_XML = "/WEB-INF/web.xml"; + private static final String FILE_PROTOCOL = "file:"; + private static final String JAR_FILE_SUFFIX = ".jar"; + + // Names of JARs that are known not to contain any TLDs + private static HashSet noTldJars; + + /** + * The mapping of the 'global' tag library URI to the location (resource + * path) of the TLD associated with that tag library. The location is + * returned as a String array: + * [0] The location + * [1] If the location is a jar file, this is the location of the tld. + */ + private Hashtable mappings; + + private boolean initialized; + private ServletContext ctxt; + private boolean redeployMode; + + //********************************************************************* + // Constructor and Initilizations + + /* + * Initializes the set of JARs that are known not to contain any TLDs + */ + static { + noTldJars = new HashSet(); + noTldJars.add("ant.jar"); + noTldJars.add("catalina.jar"); + noTldJars.add("catalina-ant.jar"); + noTldJars.add("catalina-cluster.jar"); + noTldJars.add("catalina-optional.jar"); + noTldJars.add("catalina-i18n-fr.jar"); + noTldJars.add("catalina-i18n-ja.jar"); + noTldJars.add("catalina-i18n-es.jar"); + noTldJars.add("commons-dbcp.jar"); + noTldJars.add("commons-modeler.jar"); + noTldJars.add("commons-logging-api.jar"); + noTldJars.add("commons-beanutils.jar"); + noTldJars.add("commons-fileupload-1.0.jar"); + noTldJars.add("commons-pool.jar"); + noTldJars.add("commons-digester.jar"); + noTldJars.add("commons-logging.jar"); + noTldJars.add("commons-collections.jar"); + noTldJars.add("commons-el.jar"); + noTldJars.add("jakarta-regexp-1.2.jar"); + noTldJars.add("jasper-compiler.jar"); + noTldJars.add("jasper-runtime.jar"); + noTldJars.add("jmx.jar"); + noTldJars.add("jmx-tools.jar"); + noTldJars.add("jsp-api.jar"); + noTldJars.add("jkshm.jar"); + noTldJars.add("jkconfig.jar"); + noTldJars.add("naming-common.jar"); + noTldJars.add("naming-resources.jar"); + noTldJars.add("naming-factory.jar"); + noTldJars.add("naming-java.jar"); + noTldJars.add("servlet-api.jar"); + noTldJars.add("servlets-default.jar"); + noTldJars.add("servlets-invoker.jar"); + noTldJars.add("servlets-common.jar"); + noTldJars.add("servlets-webdav.jar"); + noTldJars.add("tomcat-util.jar"); + noTldJars.add("tomcat-http11.jar"); + noTldJars.add("tomcat-jni.jar"); + noTldJars.add("tomcat-jk.jar"); + noTldJars.add("tomcat-jk2.jar"); + noTldJars.add("tomcat-coyote.jar"); + noTldJars.add("xercesImpl.jar"); + noTldJars.add("xmlParserAPIs.jar"); + noTldJars.add("xml-apis.jar"); + // JARs from J2SE runtime + noTldJars.add("sunjce_provider.jar"); + noTldJars.add("ldapsec.jar"); + noTldJars.add("localedata.jar"); + noTldJars.add("dnsns.jar"); + } + + public TldLocationsCache(ServletContext ctxt) { + this(ctxt, true); + } + + /** Constructor. + * + * @param ctxt the servlet context of the web application in which Jasper + * is running + * @param redeployMode if true, then the compiler will allow redeploying + * a tag library from the same jar, at the expense of slowing down the + * server a bit. Note that this may only work on JDK 1.3.1_01a and later, + * because of JDK bug 4211817 fixed in this release. + * If redeployMode is false, a faster but less capable mode will be used. + */ + public TldLocationsCache(ServletContext ctxt, boolean redeployMode) { + this.ctxt = ctxt; + this.redeployMode = redeployMode; + mappings = new Hashtable(); + initialized = false; + } + + /** + * Sets the list of JARs that are known not to contain any TLDs. + * + * @param jarNames List of comma-separated names of JAR files that are + * known not to contain any TLDs + */ + public static void setNoTldJars(String jarNames) { + if (jarNames != null) { + noTldJars.clear(); + StringTokenizer tokenizer = new StringTokenizer(jarNames, ","); + while (tokenizer.hasMoreElements()) { + noTldJars.add(tokenizer.nextToken()); + } + } + } + + /** + * Gets the 'location' of the TLD associated with the given taglib 'uri'. + * + * Returns null if the uri is not associated with any tag library 'exposed' + * in the web application. A tag library is 'exposed' either explicitly in + * web.xml or implicitly via the uri tag in the TLD of a taglib deployed + * in a jar file (WEB-INF/lib). + * + * @param uri The taglib uri + * + * @return An array of two Strings: The first element denotes the real + * path to the TLD. If the path to the TLD points to a jar file, then the + * second element denotes the name of the TLD entry in the jar file. + * Returns null if the uri is not associated with any tag library 'exposed' + * in the web application. + */ + public String[] getLocation(String uri) throws JasperException { + if (!initialized) { + init(); + } + return (String[]) mappings.get(uri); + } + + /** + * Returns the type of a URI: + * ABS_URI + * ROOT_REL_URI + * NOROOT_REL_URI + */ + public static int uriType(String uri) { + if (uri.indexOf(':') != -1) { + return ABS_URI; + } else if (uri.startsWith("/")) { + return ROOT_REL_URI; + } else { + return NOROOT_REL_URI; + } + } + + private void init() throws JasperException { + if (initialized) return; + try { + processWebDotXml(); + scanJars(); + processTldsInFileSystem("/WEB-INF/"); + initialized = true; + } catch (Exception ex) { + throw new JasperException(Localizer.getMessage( + "jsp.error.internal.tldinit", ex.getMessage())); + } + } + + /* + * Populates taglib map described in web.xml. + */ + private void processWebDotXml() throws Exception { + + InputStream is = null; + + try { + // Acquire input stream to web application deployment descriptor + String altDDName = (String)ctxt.getAttribute( + Constants.ALT_DD_ATTR); + URL uri = null; + if (altDDName != null) { + try { + uri = new URL(FILE_PROTOCOL+altDDName.replace('\\', '/')); + } catch (MalformedURLException e) { + if (log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.error.internal.filenotfound", + altDDName)); + } + } + } else { + uri = ctxt.getResource(WEB_XML); + if (uri == null && log.isWarnEnabled()) { + log.warn(Localizer.getMessage( + "jsp.error.internal.filenotfound", + WEB_XML)); + } + } + + if (uri == null) { + return; + } + is = uri.openStream(); + InputSource ip = new InputSource(is); + ip.setSystemId(uri.toExternalForm()); + + // Parse the web application deployment descriptor + TreeNode webtld = null; + // altDDName is the absolute path of the DD + if (altDDName != null) { + webtld = new ParserUtils().parseXMLDocument(altDDName, ip); + } else { + webtld = new ParserUtils().parseXMLDocument(WEB_XML, ip); + } + + // Allow taglib to be an element of the root or jsp-config (JSP2.0) + TreeNode jspConfig = webtld.findChild("jsp-config"); + if (jspConfig != null) { + webtld = jspConfig; + } + Iterator taglibs = webtld.findChildren("taglib"); + while (taglibs.hasNext()) { + + // Parse the next element + TreeNode taglib = (TreeNode) taglibs.next(); + String tagUri = null; + String tagLoc = null; + TreeNode child = taglib.findChild("taglib-uri"); + if (child != null) + tagUri = child.getBody(); + child = taglib.findChild("taglib-location"); + if (child != null) + tagLoc = child.getBody(); + + // Save this location if appropriate + if (tagLoc == null) + continue; + if (uriType(tagLoc) == NOROOT_REL_URI) + tagLoc = "/WEB-INF/" + tagLoc; + String tagLoc2 = null; + if (tagLoc.endsWith(JAR_FILE_SUFFIX)) { + tagLoc = ctxt.getResource(tagLoc).toString(); + tagLoc2 = "META-INF/taglib.tld"; + } + mappings.put(tagUri, new String[] { tagLoc, tagLoc2 }); + } + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t) {} + } + } + } + + /** + * Scans the given JarURLConnection for TLD files located in META-INF + * (or a subdirectory of it), adding an implicit map entry to the taglib + * map for any TLD that has a element. + * + * @param conn The JarURLConnection to the JAR file to scan + * @param ignore true if any exceptions raised when processing the given + * JAR should be ignored, false otherwise + */ + private void scanJar(JarURLConnection conn, boolean ignore) + throws JasperException { + + JarFile jarFile = null; + String resourcePath = conn.getJarFileURL().toString(); + try { + if (redeployMode) { + conn.setUseCaches(false); + } + jarFile = conn.getJarFile(); + Enumeration entries = jarFile.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = (JarEntry) entries.nextElement(); + String name = entry.getName(); + if (!name.startsWith("META-INF/")) continue; + if (!name.endsWith(".tld")) continue; + InputStream stream = jarFile.getInputStream(entry); + try { + String uri = getUriFromTld(resourcePath, stream); + // Add implicit map entry only if its uri is not already + // present in the map + if (uri != null && mappings.get(uri) == null) { + mappings.put(uri, new String[]{ resourcePath, name }); + } + } finally { + if (stream != null) { + try { + stream.close(); + } catch (Throwable t) { + // do nothing + } + } + } + } + } catch (Exception ex) { + if (!redeployMode) { + // if not in redeploy mode, close the jar in case of an error + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + // ignore + } + } + } + if (!ignore) { + throw new JasperException(ex); + } + } finally { + if (redeployMode) { + // if in redeploy mode, always close the jar + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + // ignore + } + } + } + } + } + + /* + * Searches the filesystem under /WEB-INF for any TLD files, and adds + * an implicit map entry to the taglib map for any TLD that has a + * element. + */ + private void processTldsInFileSystem(String startPath) + throws Exception { + + Set dirList = ctxt.getResourcePaths(startPath); + if (dirList != null) { + Iterator it = dirList.iterator(); + while (it.hasNext()) { + String path = (String) it.next(); + if (path.endsWith("/")) { + processTldsInFileSystem(path); + } + if (!path.endsWith(".tld")) { + continue; + } + InputStream stream = ctxt.getResourceAsStream(path); + String uri = null; + try { + uri = getUriFromTld(path, stream); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (Throwable t) { + // do nothing + } + } + } + // Add implicit map entry only if its uri is not already + // present in the map + if (uri != null && mappings.get(uri) == null) { + mappings.put(uri, new String[] { path, null }); + } + } + } + } + + /* + * Returns the value of the uri element of the given TLD, or null if the + * given TLD does not contain any such element. + */ + private String getUriFromTld(String resourcePath, InputStream in) + throws JasperException + { + // Parse the tag library descriptor at the specified resource path + TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in); + TreeNode uri = tld.findChild("uri"); + if (uri != null) { + String body = uri.getBody(); + if (body != null) + return body; + } + + return null; + } + + /* + * Scans all JARs accessible to the webapp's classloader and its + * parent classloaders for TLDs. + * + * The list of JARs always includes the JARs under WEB-INF/lib, as well as + * all shared JARs in the classloader delegation chain of the webapp's + * classloader. + * + * Considering JARs in the classloader delegation chain constitutes a + * Tomcat-specific extension to the TLD search + * order defined in the JSP spec. It allows tag libraries packaged as JAR + * files to be shared by web applications by simply dropping them in a + * location that all web applications have access to (e.g., + * /common/lib). + * + * The set of shared JARs to be scanned for TLDs is narrowed down by + * the noTldJars class variable, which contains the names of JARs + * that are known not to contain any TLDs. + */ + private void scanJars() throws Exception { + + ClassLoader webappLoader + = Thread.currentThread().getContextClassLoader(); + ClassLoader loader = webappLoader; + + while (loader != null) { + if (loader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) loader).getURLs(); + for (int i=0; ijarPath needs to be + * scanned for TLDs. + * + * @param loader The current classloader in the parent chain + * @param webappLoader The webapp classloader + * @param jarPath The JAR file path + * + * @return TRUE if the JAR file identified by jarPath needs to be + * scanned for TLDs, FALSE otherwise + */ + private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader, + String jarPath) { + if (loader == webappLoader) { + // JARs under WEB-INF/lib must be scanned unconditionally according + // to the spec. + return true; + } else { + String jarName = jarPath; + int slash = jarPath.lastIndexOf('/'); + if (slash >= 0) { + jarName = jarPath.substring(slash + 1); + } + return (!noTldJars.contains(jarName)); + } + } +} diff --git a/java/org/apache/jasper/compiler/Validator.java b/java/org/apache/jasper/compiler/Validator.java index 0261b6cf8..00e1f76c6 100644 --- a/java/org/apache/jasper/compiler/Validator.java +++ b/java/org/apache/jasper/compiler/Validator.java @@ -1,1609 +1,1609 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler; - -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ExpressionFactory; -import javax.el.FunctionMapper; -import javax.servlet.jsp.tagext.FunctionInfo; -import javax.servlet.jsp.tagext.JspFragment; -import javax.servlet.jsp.tagext.PageData; -import javax.servlet.jsp.tagext.TagAttributeInfo; -import javax.servlet.jsp.tagext.TagData; -import javax.servlet.jsp.tagext.TagExtraInfo; -import javax.servlet.jsp.tagext.TagInfo; -import javax.servlet.jsp.tagext.TagLibraryInfo; -import javax.servlet.jsp.tagext.ValidationMessage; - -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.el.ELContextImpl; -import org.xml.sax.Attributes; - -/** - * Performs validation on the page elements. Attributes are checked for - * mandatory presence, entry value validity, and consistency. As a side effect, - * some page global value (such as those from page direcitves) are stored, for - * later use. - * - * @author Kin-man Chung - * @author Jan Luehe - * @author Shawn Bayern - * @author Mark Roth - */ -class Validator { - - /** - * A visitor to validate and extract page directive info - */ - static class DirectiveVisitor extends Node.Visitor { - - private PageInfo pageInfo; - - private ErrorDispatcher err; - - private static final JspUtil.ValidAttribute[] pageDirectiveAttrs = { - new JspUtil.ValidAttribute("language"), - new JspUtil.ValidAttribute("extends"), - new JspUtil.ValidAttribute("import"), - new JspUtil.ValidAttribute("session"), - new JspUtil.ValidAttribute("buffer"), - new JspUtil.ValidAttribute("autoFlush"), - new JspUtil.ValidAttribute("isThreadSafe"), - new JspUtil.ValidAttribute("info"), - new JspUtil.ValidAttribute("errorPage"), - new JspUtil.ValidAttribute("isErrorPage"), - new JspUtil.ValidAttribute("contentType"), - new JspUtil.ValidAttribute("pageEncoding"), - new JspUtil.ValidAttribute("isELIgnored") }; - - private boolean pageEncodingSeen = false; - - /* - * Constructor - */ - DirectiveVisitor(Compiler compiler) throws JasperException { - this.pageInfo = compiler.getPageInfo(); - this.err = compiler.getErrorDispatcher(); - JspCompilationContext ctxt = compiler.getCompilationContext(); - } - - public void visit(Node.IncludeDirective n) throws JasperException { - // Since pageDirectiveSeen flag only applies to the Current page - // save it here and restore it after the file is included. - boolean pageEncodingSeenSave = pageEncodingSeen; - pageEncodingSeen = false; - visitBody(n); - pageEncodingSeen = pageEncodingSeenSave; - } - - public void visit(Node.PageDirective n) throws JasperException { - - JspUtil.checkAttributes("Page directive", n, pageDirectiveAttrs, - err); - - // JSP.2.10.1 - Attributes attrs = n.getAttributes(); - for (int i = 0; attrs != null && i < attrs.getLength(); i++) { - String attr = attrs.getQName(i); - String value = attrs.getValue(i); - - if ("language".equals(attr)) { - if (pageInfo.getLanguage(false) == null) { - pageInfo.setLanguage(value, n, err, true); - } else if (!pageInfo.getLanguage(false).equals(value)) { - err.jspError(n, "jsp.error.page.conflict.language", - pageInfo.getLanguage(false), value); - } - } else if ("extends".equals(attr)) { - if (pageInfo.getExtends(false) == null) { - pageInfo.setExtends(value, n); - } else if (!pageInfo.getExtends(false).equals(value)) { - err.jspError(n, "jsp.error.page.conflict.extends", - pageInfo.getExtends(false), value); - } - } else if ("contentType".equals(attr)) { - if (pageInfo.getContentType() == null) { - pageInfo.setContentType(value); - } else if (!pageInfo.getContentType().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.contenttype", - pageInfo.getContentType(), value); - } - } else if ("session".equals(attr)) { - if (pageInfo.getSession() == null) { - pageInfo.setSession(value, n, err); - } else if (!pageInfo.getSession().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.session", - pageInfo.getSession(), value); - } - } else if ("buffer".equals(attr)) { - if (pageInfo.getBufferValue() == null) { - pageInfo.setBufferValue(value, n, err); - } else if (!pageInfo.getBufferValue().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.buffer", - pageInfo.getBufferValue(), value); - } - } else if ("autoFlush".equals(attr)) { - if (pageInfo.getAutoFlush() == null) { - pageInfo.setAutoFlush(value, n, err); - } else if (!pageInfo.getAutoFlush().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.autoflush", - pageInfo.getAutoFlush(), value); - } - } else if ("isThreadSafe".equals(attr)) { - if (pageInfo.getIsThreadSafe() == null) { - pageInfo.setIsThreadSafe(value, n, err); - } else if (!pageInfo.getIsThreadSafe().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.isthreadsafe", - pageInfo.getIsThreadSafe(), value); - } - } else if ("isELIgnored".equals(attr)) { - if (pageInfo.getIsELIgnored() == null) { - pageInfo.setIsELIgnored(value, n, err, true); - } else if (!pageInfo.getIsELIgnored().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.iselignored", - pageInfo.getIsELIgnored(), value); - } - } else if ("isErrorPage".equals(attr)) { - if (pageInfo.getIsErrorPage() == null) { - pageInfo.setIsErrorPage(value, n, err); - } else if (!pageInfo.getIsErrorPage().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.iserrorpage", - pageInfo.getIsErrorPage(), value); - } - } else if ("errorPage".equals(attr)) { - if (pageInfo.getErrorPage() == null) { - pageInfo.setErrorPage(value); - } else if (!pageInfo.getErrorPage().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.errorpage", - pageInfo.getErrorPage(), value); - } - } else if ("info".equals(attr)) { - if (pageInfo.getInfo() == null) { - pageInfo.setInfo(value); - } else if (!pageInfo.getInfo().equals(value)) { - err.jspError(n, "jsp.error.page.conflict.info", - pageInfo.getInfo(), value); - } - } else if ("pageEncoding".equals(attr)) { - if (pageEncodingSeen) - err.jspError(n, "jsp.error.page.multi.pageencoding"); - // 'pageEncoding' can occur at most once per file - pageEncodingSeen = true; - comparePageEncodings(value, n); - } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) { - if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) { - pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n, - err, true); - } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral() - .equals(value)) { - err - .jspError( - n, - "jsp.error.page.conflict.deferredsyntaxallowedasliteral", - pageInfo - .getDeferredSyntaxAllowedAsLiteral(), - value); - } - } else if ("trimDirectiveWhitespaces".equals(attr)) { - if (pageInfo.getTrimDirectiveWhitespaces() == null) { - pageInfo.setTrimDirectiveWhitespaces(value, n, err, - true); - } else if (!pageInfo.getTrimDirectiveWhitespaces().equals( - value)) { - err - .jspError( - n, - "jsp.error.page.conflict.trimdirectivewhitespaces", - pageInfo.getTrimDirectiveWhitespaces(), - value); - } - } - } - - // Check for bad combinations - if (pageInfo.getBuffer() == 0 && !pageInfo.isAutoFlush()) - err.jspError(n, "jsp.error.page.badCombo"); - - // Attributes for imports for this node have been processed by - // the parsers, just add them to pageInfo. - pageInfo.addImports(n.getImports()); - } - - public void visit(Node.TagDirective n) throws JasperException { - // Note: Most of the validation is done in TagFileProcessor - // when it created a TagInfo object from the - // tag file in which the directive appeared. - - // This method does additional processing to collect page info - - Attributes attrs = n.getAttributes(); - for (int i = 0; attrs != null && i < attrs.getLength(); i++) { - String attr = attrs.getQName(i); - String value = attrs.getValue(i); - - if ("language".equals(attr)) { - if (pageInfo.getLanguage(false) == null) { - pageInfo.setLanguage(value, n, err, false); - } else if (!pageInfo.getLanguage(false).equals(value)) { - err.jspError(n, "jsp.error.tag.conflict.language", - pageInfo.getLanguage(false), value); - } - } else if ("isELIgnored".equals(attr)) { - if (pageInfo.getIsELIgnored() == null) { - pageInfo.setIsELIgnored(value, n, err, false); - } else if (!pageInfo.getIsELIgnored().equals(value)) { - err.jspError(n, "jsp.error.tag.conflict.iselignored", - pageInfo.getIsELIgnored(), value); - } - } else if ("pageEncoding".equals(attr)) { - if (pageEncodingSeen) - err.jspError(n, "jsp.error.tag.multi.pageencoding"); - pageEncodingSeen = true; - n.getRoot().setPageEncoding(value); - } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) { - if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) { - pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n, - err, false); - } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral() - .equals(value)) { - err - .jspError( - n, - "jsp.error.tag.conflict.deferredsyntaxallowedasliteral", - pageInfo - .getDeferredSyntaxAllowedAsLiteral(), - value); - } - } else if ("trimDirectiveWhitespaces".equals(attr)) { - if (pageInfo.getTrimDirectiveWhitespaces() == null) { - pageInfo.setTrimDirectiveWhitespaces(value, n, err, - false); - } else if (!pageInfo.getTrimDirectiveWhitespaces().equals( - value)) { - err - .jspError( - n, - "jsp.error.tag.conflict.trimdirectivewhitespaces", - pageInfo.getTrimDirectiveWhitespaces(), - value); - } - } - } - - // Attributes for imports for this node have been processed by - // the parsers, just add them to pageInfo. - pageInfo.addImports(n.getImports()); - } - - public void visit(Node.AttributeDirective n) throws JasperException { - // Do nothing, since this attribute directive has already been - // validated by TagFileProcessor when it created a TagInfo object - // from the tag file in which the directive appeared - } - - public void visit(Node.VariableDirective n) throws JasperException { - // Do nothing, since this variable directive has already been - // validated by TagFileProcessor when it created a TagInfo object - // from the tag file in which the directive appeared - } - - /* - * Compares page encodings specified in various places, and throws - * exception in case of page encoding mismatch. - * - * @param pageDirEnc The value of the pageEncoding attribute of the page - * directive @param pageDir The page directive node - * - * @throws JasperException in case of page encoding mismatch - */ - private void comparePageEncodings(String pageDirEnc, - Node.PageDirective pageDir) throws JasperException { - - Node.Root root = pageDir.getRoot(); - String configEnc = root.getJspConfigPageEncoding(); - - /* - * Compare the 'pageEncoding' attribute of the page directive with - * the encoding specified in the JSP config element whose URL - * pattern matches this page. Treat "UTF-16", "UTF-16BE", and - * "UTF-16LE" as identical. - */ - if (configEnc != null - && !pageDirEnc.equals(configEnc) - && (!pageDirEnc.startsWith("UTF-16") || !configEnc - .startsWith("UTF-16"))) { - err.jspError(pageDir, - "jsp.error.config_pagedir_encoding_mismatch", - configEnc, pageDirEnc); - } - - /* - * Compare the 'pageEncoding' attribute of the page directive with - * the encoding specified in the XML prolog (only for XML syntax, - * and only if JSP document contains XML prolog with encoding - * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as - * identical. - */ - if (root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) { - String pageEnc = root.getPageEncoding(); - if (!pageDirEnc.equals(pageEnc) - && (!pageDirEnc.startsWith("UTF-16") || !pageEnc - .startsWith("UTF-16"))) { - err.jspError(pageDir, - "jsp.error.prolog_pagedir_encoding_mismatch", - pageEnc, pageDirEnc); - } - } - } - } - - /** - * A visitor for validating nodes other than page directives - */ - static class ValidateVisitor extends Node.Visitor { - - private PageInfo pageInfo; - - private ErrorDispatcher err; - - private TagInfo tagInfo; - - private ClassLoader loader; - - private final StringBuffer buf = new StringBuffer(32); - - private static final JspUtil.ValidAttribute[] jspRootAttrs = { - new JspUtil.ValidAttribute("xsi:schemaLocation"), - new JspUtil.ValidAttribute("version", true) }; - - private static final JspUtil.ValidAttribute[] includeDirectiveAttrs = { new JspUtil.ValidAttribute( - "file", true) }; - - private static final JspUtil.ValidAttribute[] taglibDirectiveAttrs = { - new JspUtil.ValidAttribute("uri"), - new JspUtil.ValidAttribute("tagdir"), - new JspUtil.ValidAttribute("prefix", true) }; - - private static final JspUtil.ValidAttribute[] includeActionAttrs = { - new JspUtil.ValidAttribute("page", true, true), - new JspUtil.ValidAttribute("flush") }; - - private static final JspUtil.ValidAttribute[] paramActionAttrs = { - new JspUtil.ValidAttribute("name", true), - new JspUtil.ValidAttribute("value", true, true) }; - - private static final JspUtil.ValidAttribute[] forwardActionAttrs = { new JspUtil.ValidAttribute( - "page", true, true) }; - - private static final JspUtil.ValidAttribute[] getPropertyAttrs = { - new JspUtil.ValidAttribute("name", true), - new JspUtil.ValidAttribute("property", true) }; - - private static final JspUtil.ValidAttribute[] setPropertyAttrs = { - new JspUtil.ValidAttribute("name", true), - new JspUtil.ValidAttribute("property", true), - new JspUtil.ValidAttribute("value", false, true), - new JspUtil.ValidAttribute("param") }; - - private static final JspUtil.ValidAttribute[] useBeanAttrs = { - new JspUtil.ValidAttribute("id", true), - new JspUtil.ValidAttribute("scope"), - new JspUtil.ValidAttribute("class"), - new JspUtil.ValidAttribute("type"), - new JspUtil.ValidAttribute("beanName", false, true) }; - - private static final JspUtil.ValidAttribute[] plugInAttrs = { - new JspUtil.ValidAttribute("type", true), - new JspUtil.ValidAttribute("code", true), - new JspUtil.ValidAttribute("codebase"), - new JspUtil.ValidAttribute("align"), - new JspUtil.ValidAttribute("archive"), - new JspUtil.ValidAttribute("height", false, true), - new JspUtil.ValidAttribute("hspace"), - new JspUtil.ValidAttribute("jreversion"), - new JspUtil.ValidAttribute("name"), - new JspUtil.ValidAttribute("vspace"), - new JspUtil.ValidAttribute("width", false, true), - new JspUtil.ValidAttribute("nspluginurl"), - new JspUtil.ValidAttribute("iepluginurl") }; - - private static final JspUtil.ValidAttribute[] attributeAttrs = { - new JspUtil.ValidAttribute("name", true), - new JspUtil.ValidAttribute("trim") }; - - private static final JspUtil.ValidAttribute[] invokeAttrs = { - new JspUtil.ValidAttribute("fragment", true), - new JspUtil.ValidAttribute("var"), - new JspUtil.ValidAttribute("varReader"), - new JspUtil.ValidAttribute("scope") }; - - private static final JspUtil.ValidAttribute[] doBodyAttrs = { - new JspUtil.ValidAttribute("var"), - new JspUtil.ValidAttribute("varReader"), - new JspUtil.ValidAttribute("scope") }; - - private static final JspUtil.ValidAttribute[] jspOutputAttrs = { - new JspUtil.ValidAttribute("omit-xml-declaration"), - new JspUtil.ValidAttribute("doctype-root-element"), - new JspUtil.ValidAttribute("doctype-public"), - new JspUtil.ValidAttribute("doctype-system") }; - - /* - * Constructor - */ - ValidateVisitor(Compiler compiler) { - this.pageInfo = compiler.getPageInfo(); - this.err = compiler.getErrorDispatcher(); - this.tagInfo = compiler.getCompilationContext().getTagInfo(); - this.loader = compiler.getCompilationContext().getClassLoader(); - } - - public void visit(Node.JspRoot n) throws JasperException { - JspUtil.checkAttributes("Jsp:root", n, jspRootAttrs, err); - String version = n.getTextAttribute("version"); - if (!version.equals("1.2") && !version.equals("2.0")) { - err.jspError(n, "jsp.error.jsproot.version.invalid", version); - } - visitBody(n); - } - - public void visit(Node.IncludeDirective n) throws JasperException { - JspUtil.checkAttributes("Include directive", n, - includeDirectiveAttrs, err); - visitBody(n); - } - - public void visit(Node.TaglibDirective n) throws JasperException { - JspUtil.checkAttributes("Taglib directive", n, - taglibDirectiveAttrs, err); - // Either 'uri' or 'tagdir' attribute must be specified - String uri = n.getAttributeValue("uri"); - String tagdir = n.getAttributeValue("tagdir"); - if (uri == null && tagdir == null) { - err.jspError(n, "jsp.error.taglibDirective.missing.location"); - } - if (uri != null && tagdir != null) { - err - .jspError(n, - "jsp.error.taglibDirective.both_uri_and_tagdir"); - } - } - - public void visit(Node.ParamAction n) throws JasperException { - JspUtil.checkAttributes("Param action", n, paramActionAttrs, err); - // make sure the value of the 'name' attribute is not a - // request-time expression - throwErrorIfExpression(n, "name", "jsp:param"); - n.setValue(getJspAttribute(null, "value", null, null, n - .getAttributeValue("value"), java.lang.String.class, n, - false)); - visitBody(n); - } - - public void visit(Node.ParamsAction n) throws JasperException { - // Make sure we've got at least one nested jsp:param - Node.Nodes subElems = n.getBody(); - if (subElems == null) { - err.jspError(n, "jsp.error.params.emptyBody"); - } - visitBody(n); - } - - public void visit(Node.IncludeAction n) throws JasperException { - JspUtil.checkAttributes("Include action", n, includeActionAttrs, - err); - n.setPage(getJspAttribute(null, "page", null, null, n - .getAttributeValue("page"), java.lang.String.class, n, - false)); - visitBody(n); - }; - - public void visit(Node.ForwardAction n) throws JasperException { - JspUtil.checkAttributes("Forward", n, forwardActionAttrs, err); - n.setPage(getJspAttribute(null, "page", null, null, n - .getAttributeValue("page"), java.lang.String.class, n, - false)); - visitBody(n); - } - - public void visit(Node.GetProperty n) throws JasperException { - JspUtil.checkAttributes("GetProperty", n, getPropertyAttrs, err); - } - - public void visit(Node.SetProperty n) throws JasperException { - JspUtil.checkAttributes("SetProperty", n, setPropertyAttrs, err); - String name = n.getTextAttribute("name"); - String property = n.getTextAttribute("property"); - String param = n.getTextAttribute("param"); - String value = n.getAttributeValue("value"); - - n.setValue(getJspAttribute(null, "value", null, null, value, - java.lang.Object.class, n, false)); - - boolean valueSpecified = n.getValue() != null; - - if ("*".equals(property)) { - if (param != null || valueSpecified) - err.jspError(n, "jsp.error.setProperty.invalid"); - - } else if (param != null && valueSpecified) { - err.jspError(n, "jsp.error.setProperty.invalid"); - } - - visitBody(n); - } - - public void visit(Node.UseBean n) throws JasperException { - JspUtil.checkAttributes("UseBean", n, useBeanAttrs, err); - - String name = n.getTextAttribute("id"); - String scope = n.getTextAttribute("scope"); - JspUtil.checkScope(scope, n, err); - String className = n.getTextAttribute("class"); - String type = n.getTextAttribute("type"); - BeanRepository beanInfo = pageInfo.getBeanRepository(); - - if (className == null && type == null) - err.jspError(n, "jsp.error.usebean.missingType"); - - if (beanInfo.checkVariable(name)) - err.jspError(n, "jsp.error.usebean.duplicate"); - - if ("session".equals(scope) && !pageInfo.isSession()) - err.jspError(n, "jsp.error.usebean.noSession"); - - Node.JspAttribute jattr = getJspAttribute(null, "beanName", null, - null, n.getAttributeValue("beanName"), - java.lang.String.class, n, false); - n.setBeanName(jattr); - if (className != null && jattr != null) - err.jspError(n, "jsp.error.usebean.notBoth"); - - if (className == null) - className = type; - - beanInfo.addBean(n, name, className, scope); - - visitBody(n); - } - - public void visit(Node.PlugIn n) throws JasperException { - JspUtil.checkAttributes("Plugin", n, plugInAttrs, err); - - throwErrorIfExpression(n, "type", "jsp:plugin"); - throwErrorIfExpression(n, "code", "jsp:plugin"); - throwErrorIfExpression(n, "codebase", "jsp:plugin"); - throwErrorIfExpression(n, "align", "jsp:plugin"); - throwErrorIfExpression(n, "archive", "jsp:plugin"); - throwErrorIfExpression(n, "hspace", "jsp:plugin"); - throwErrorIfExpression(n, "jreversion", "jsp:plugin"); - throwErrorIfExpression(n, "name", "jsp:plugin"); - throwErrorIfExpression(n, "vspace", "jsp:plugin"); - throwErrorIfExpression(n, "nspluginurl", "jsp:plugin"); - throwErrorIfExpression(n, "iepluginurl", "jsp:plugin"); - - String type = n.getTextAttribute("type"); - if (type == null) - err.jspError(n, "jsp.error.plugin.notype"); - if (!type.equals("bean") && !type.equals("applet")) - err.jspError(n, "jsp.error.plugin.badtype"); - if (n.getTextAttribute("code") == null) - err.jspError(n, "jsp.error.plugin.nocode"); - - Node.JspAttribute width = getJspAttribute(null, "width", null, - null, n.getAttributeValue("width"), java.lang.String.class, - n, false); - n.setWidth(width); - - Node.JspAttribute height = getJspAttribute(null, "height", null, - null, n.getAttributeValue("height"), - java.lang.String.class, n, false); - n.setHeight(height); - - visitBody(n); - } - - public void visit(Node.NamedAttribute n) throws JasperException { - JspUtil.checkAttributes("Attribute", n, attributeAttrs, err); - visitBody(n); - } - - public void visit(Node.JspBody n) throws JasperException { - visitBody(n); - } - - public void visit(Node.Declaration n) throws JasperException { - if (pageInfo.isScriptingInvalid()) { - err.jspError(n.getStart(), "jsp.error.no.scriptlets"); - } - } - - public void visit(Node.Expression n) throws JasperException { - if (pageInfo.isScriptingInvalid()) { - err.jspError(n.getStart(), "jsp.error.no.scriptlets"); - } - } - - public void visit(Node.Scriptlet n) throws JasperException { - if (pageInfo.isScriptingInvalid()) { - err.jspError(n.getStart(), "jsp.error.no.scriptlets"); - } - } - - public void visit(Node.ELExpression n) throws JasperException { - // exit if we are ignoring EL all together - if (pageInfo.isELIgnored()) - return; - - // JSP.2.2 - '#{' not allowed in template text - if (n.getType() == '#') { - if (pageInfo.isDeferredSyntaxAllowedAsLiteral()) - return; - err.jspError(n, "jsp.error.el.template.deferred"); - } - - // build expression - StringBuffer expr = this.getBuffer(); - expr.append(n.getType()).append('{').append(n.getText()) - .append('}'); - ELNode.Nodes el = ELParser.parse(expr.toString()); - - // validate/prepare expression - prepareExpression(el, n, expr.toString()); - - // store it - n.setEL(el); - } - - public void visit(Node.UninterpretedTag n) throws JasperException { - if (n.getNamedAttributeNodes().size() != 0) { - err.jspError(n, "jsp.error.namedAttribute.invalidUse"); - } - - Attributes attrs = n.getAttributes(); - if (attrs != null) { - int attrSize = attrs.getLength(); - Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize]; - for (int i = 0; i < attrSize; i++) { - jspAttrs[i] = getJspAttribute(null, attrs.getQName(i), - attrs.getURI(i), attrs.getLocalName(i), attrs - .getValue(i), java.lang.Object.class, n, - false); - } - n.setJspAttributes(jspAttrs); - } - - visitBody(n); - } - - public void visit(Node.CustomTag n) throws JasperException { - - TagInfo tagInfo = n.getTagInfo(); - if (tagInfo == null) { - err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); - } - - /* - * The bodyconet of a SimpleTag cannot be JSP. - */ - if (n.implementsSimpleTag() - && tagInfo.getBodyContent().equalsIgnoreCase( - TagInfo.BODY_CONTENT_JSP)) { - err.jspError(n, "jsp.error.simpletag.badbodycontent", tagInfo - .getTagClassName()); - } - - /* - * If the tag handler declares in the TLD that it supports dynamic - * attributes, it also must implement the DynamicAttributes - * interface. - */ - if (tagInfo.hasDynamicAttributes() - && !n.implementsDynamicAttributes()) { - err.jspError(n, "jsp.error.dynamic.attributes.not.implemented", - n.getQName()); - } - - /* - * Make sure all required attributes are present, either as - * attributes or named attributes (). Also make sure - * that the same attribute is not specified in both attributes or - * named attributes. - */ - TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); - String customActionUri = n.getURI(); - Attributes attrs = n.getAttributes(); - int attrsSize = (attrs == null) ? 0 : attrs.getLength(); - for (int i = 0; i < tldAttrs.length; i++) { - String attr = null; - if (attrs != null) { - attr = attrs.getValue(tldAttrs[i].getName()); - if (attr == null) { - attr = attrs.getValue(customActionUri, tldAttrs[i] - .getName()); - } - } - Node.NamedAttribute na = n.getNamedAttributeNode(tldAttrs[i] - .getName()); - - if (tldAttrs[i].isRequired() && attr == null && na == null) { - err.jspError(n, "jsp.error.missing_attribute", tldAttrs[i] - .getName(), n.getLocalName()); - } - if (attr != null && na != null) { - err.jspError(n, "jsp.error.duplicate.name.jspattribute", - tldAttrs[i].getName()); - } - } - - Node.Nodes naNodes = n.getNamedAttributeNodes(); - int jspAttrsSize = naNodes.size() + attrsSize; - Node.JspAttribute[] jspAttrs = null; - if (jspAttrsSize > 0) { - jspAttrs = new Node.JspAttribute[jspAttrsSize]; - } - Hashtable tagDataAttrs = new Hashtable(attrsSize); - - checkXmlAttributes(n, jspAttrs, tagDataAttrs); - checkNamedAttributes(n, jspAttrs, attrsSize, tagDataAttrs); - - TagData tagData = new TagData(tagDataAttrs); - - // JSP.C1: It is a (translation time) error for an action that - // has one or more variable subelements to have a TagExtraInfo - // class that returns a non-null object. - TagExtraInfo tei = tagInfo.getTagExtraInfo(); - if (tei != null && tei.getVariableInfo(tagData) != null - && tei.getVariableInfo(tagData).length > 0 - && tagInfo.getTagVariableInfos().length > 0) { - err.jspError("jsp.error.non_null_tei_and_var_subelems", n - .getQName()); - } - - n.setTagData(tagData); - n.setJspAttributes(jspAttrs); - - visitBody(n); - } - - public void visit(Node.JspElement n) throws JasperException { - - Attributes attrs = n.getAttributes(); - if (attrs == null) { - err.jspError(n, "jsp.error.jspelement.missing.name"); - } - int xmlAttrLen = attrs.getLength(); - - Node.Nodes namedAttrs = n.getNamedAttributeNodes(); - - // XML-style 'name' attribute, which is mandatory, must not be - // included in JspAttribute array - int jspAttrSize = xmlAttrLen - 1 + namedAttrs.size(); - - Node.JspAttribute[] jspAttrs = new Node.JspAttribute[jspAttrSize]; - int jspAttrIndex = 0; - - // Process XML-style attributes - for (int i = 0; i < xmlAttrLen; i++) { - if ("name".equals(attrs.getLocalName(i))) { - n.setNameAttribute(getJspAttribute(null, attrs.getQName(i), - attrs.getURI(i), attrs.getLocalName(i), attrs - .getValue(i), java.lang.String.class, n, - false)); - } else { - if (jspAttrIndex < jspAttrSize) { - jspAttrs[jspAttrIndex++] = getJspAttribute(null, attrs - .getQName(i), attrs.getURI(i), attrs - .getLocalName(i), attrs.getValue(i), - java.lang.Object.class, n, false); - } - } - } - if (n.getNameAttribute() == null) { - err.jspError(n, "jsp.error.jspelement.missing.name"); - } - - // Process named attributes - for (int i = 0; i < namedAttrs.size(); i++) { - Node.NamedAttribute na = (Node.NamedAttribute) namedAttrs - .getNode(i); - jspAttrs[jspAttrIndex++] = new Node.JspAttribute(na, null, - false); - } - - n.setJspAttributes(jspAttrs); - - visitBody(n); - } - - public void visit(Node.JspOutput n) throws JasperException { - JspUtil.checkAttributes("jsp:output", n, jspOutputAttrs, err); - - if (n.getBody() != null) { - err.jspError(n, "jsp.error.jspoutput.nonemptybody"); - } - - String omitXmlDecl = n.getAttributeValue("omit-xml-declaration"); - String doctypeName = n.getAttributeValue("doctype-root-element"); - String doctypePublic = n.getAttributeValue("doctype-public"); - String doctypeSystem = n.getAttributeValue("doctype-system"); - - String omitXmlDeclOld = pageInfo.getOmitXmlDecl(); - String doctypeNameOld = pageInfo.getDoctypeName(); - String doctypePublicOld = pageInfo.getDoctypePublic(); - String doctypeSystemOld = pageInfo.getDoctypeSystem(); - - if (omitXmlDecl != null && omitXmlDeclOld != null - && !omitXmlDecl.equals(omitXmlDeclOld)) { - err.jspError(n, "jsp.error.jspoutput.conflict", - "omit-xml-declaration", omitXmlDeclOld, omitXmlDecl); - } - - if (doctypeName != null && doctypeNameOld != null - && !doctypeName.equals(doctypeNameOld)) { - err.jspError(n, "jsp.error.jspoutput.conflict", - "doctype-root-element", doctypeNameOld, doctypeName); - } - - if (doctypePublic != null && doctypePublicOld != null - && !doctypePublic.equals(doctypePublicOld)) { - err.jspError(n, "jsp.error.jspoutput.conflict", - "doctype-public", doctypePublicOld, doctypePublic); - } - - if (doctypeSystem != null && doctypeSystemOld != null - && !doctypeSystem.equals(doctypeSystemOld)) { - err.jspError(n, "jsp.error.jspoutput.conflict", - "doctype-system", doctypeSystemOld, doctypeSystem); - } - - if (doctypeName == null && doctypeSystem != null - || doctypeName != null && doctypeSystem == null) { - err.jspError(n, "jsp.error.jspoutput.doctypenamesystem"); - } - - if (doctypePublic != null && doctypeSystem == null) { - err.jspError(n, "jsp.error.jspoutput.doctypepulicsystem"); - } - - if (omitXmlDecl != null) { - pageInfo.setOmitXmlDecl(omitXmlDecl); - } - if (doctypeName != null) { - pageInfo.setDoctypeName(doctypeName); - } - if (doctypeSystem != null) { - pageInfo.setDoctypeSystem(doctypeSystem); - } - if (doctypePublic != null) { - pageInfo.setDoctypePublic(doctypePublic); - } - } - - public void visit(Node.InvokeAction n) throws JasperException { - - JspUtil.checkAttributes("Invoke", n, invokeAttrs, err); - - String scope = n.getTextAttribute("scope"); - JspUtil.checkScope(scope, n, err); - - String var = n.getTextAttribute("var"); - String varReader = n.getTextAttribute("varReader"); - if (scope != null && var == null && varReader == null) { - err.jspError(n, "jsp.error.missing_var_or_varReader"); - } - if (var != null && varReader != null) { - err.jspError(n, "jsp.error.var_and_varReader"); - } - } - - public void visit(Node.DoBodyAction n) throws JasperException { - - JspUtil.checkAttributes("DoBody", n, doBodyAttrs, err); - - String scope = n.getTextAttribute("scope"); - JspUtil.checkScope(scope, n, err); - - String var = n.getTextAttribute("var"); - String varReader = n.getTextAttribute("varReader"); - if (scope != null && var == null && varReader == null) { - err.jspError(n, "jsp.error.missing_var_or_varReader"); - } - if (var != null && varReader != null) { - err.jspError(n, "jsp.error.var_and_varReader"); - } - } - - /* - * Make sure the given custom action does not have any invalid - * attributes. - * - * A custom action and its declared attributes always belong to the same - * namespace, which is identified by the prefix name of the custom tag - * invocation. For example, in this invocation: - * - * , the action - * - * "test" and its attributes "a", "b", and "c" all belong to the - * namespace identified by the prefix "my". The above invocation would - * be equivalent to: - * - * - * - * An action attribute may have a prefix different from that of the - * action invocation only if the underlying tag handler supports dynamic - * attributes, in which case the attribute with the different prefix is - * considered a dynamic attribute. - */ - private void checkXmlAttributes(Node.CustomTag n, - Node.JspAttribute[] jspAttrs, Hashtable tagDataAttrs) - throws JasperException { - - TagInfo tagInfo = n.getTagInfo(); - if (tagInfo == null) { - err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); - } - TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); - Attributes attrs = n.getAttributes(); - - for (int i = 0; attrs != null && i < attrs.getLength(); i++) { - boolean found = false; - for (int j = 0; tldAttrs != null && j < tldAttrs.length; j++) { - if (attrs.getLocalName(i).equals(tldAttrs[j].getName()) - && (attrs.getURI(i) == null - || attrs.getURI(i).length() == 0 || attrs - .getURI(i).equals(n.getURI()))) { - if (tldAttrs[j].canBeRequestTime() - || tldAttrs[j].isDeferredMethod() // JSP 2.1 - || tldAttrs[j].isDeferredValue()) { // JSP 2.1 - Class expectedType = String.class; - try { - String typeStr = tldAttrs[j].getTypeName(); - if (tldAttrs[j].isFragment()) { - expectedType = JspFragment.class; - } else if (typeStr != null) { - expectedType = JspUtil.toClass(typeStr, - loader); - } - jspAttrs[i] = getJspAttribute(tldAttrs[j], - attrs.getQName(i), attrs.getURI(i), - attrs.getLocalName(i), attrs - .getValue(i), expectedType, n, - false); - } catch (ClassNotFoundException e) { - err.jspError(n, - "jsp.error.unknown_attribute_type", - tldAttrs[j].getName(), tldAttrs[j] - .getTypeName()); - } - } else { - // Attribute does not accept any expressions. - // Make sure its value does not contain any. - if (isExpression(n, attrs.getValue(i))) { - err - .jspError( - n, - "jsp.error.attribute.custom.non_rt_with_expr", - tldAttrs[j].getName()); - } - jspAttrs[i] = new Node.JspAttribute(tldAttrs[j], - attrs.getQName(i), attrs.getURI(i), attrs - .getLocalName(i), - attrs.getValue(i), false, null, false); - } - if (jspAttrs[i].isExpression()) { - tagDataAttrs.put(attrs.getQName(i), - TagData.REQUEST_TIME_VALUE); - } else { - tagDataAttrs.put(attrs.getQName(i), attrs - .getValue(i)); - } - found = true; - break; - } - } - if (!found) { - if (tagInfo.hasDynamicAttributes()) { - jspAttrs[i] = getJspAttribute(null, attrs.getQName(i), - attrs.getURI(i), attrs.getLocalName(i), attrs - .getValue(i), java.lang.Object.class, - n, true); - } else { - err.jspError(n, "jsp.error.bad_attribute", attrs - .getQName(i), n.getLocalName()); - } - } - } - } - - /* - * Make sure the given custom action does not have any invalid named - * attributes - */ - private void checkNamedAttributes(Node.CustomTag n, - Node.JspAttribute[] jspAttrs, int start, Hashtable tagDataAttrs) - throws JasperException { - - TagInfo tagInfo = n.getTagInfo(); - if (tagInfo == null) { - err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); - } - TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); - Node.Nodes naNodes = n.getNamedAttributeNodes(); - - for (int i = 0; i < naNodes.size(); i++) { - Node.NamedAttribute na = (Node.NamedAttribute) naNodes - .getNode(i); - boolean found = false; - for (int j = 0; j < tldAttrs.length; j++) { - /* - * See above comment about namespace matches. For named - * attributes, we use the prefix instead of URI as the match - * criterion, because in the case of a JSP document, we'd - * have to keep track of which namespaces are in scope when - * parsing a named attribute, in order to determine the URI - * that the prefix of the named attribute's name matches to. - */ - String attrPrefix = na.getPrefix(); - if (na.getLocalName().equals(tldAttrs[j].getName()) - && (attrPrefix == null || attrPrefix.length() == 0 || attrPrefix - .equals(n.getPrefix()))) { - jspAttrs[start + i] = new Node.JspAttribute(na, - tldAttrs[j], false); - NamedAttributeVisitor nav = null; - if (na.getBody() != null) { - nav = new NamedAttributeVisitor(); - na.getBody().visit(nav); - } - if (nav != null && nav.hasDynamicContent()) { - tagDataAttrs.put(na.getName(), - TagData.REQUEST_TIME_VALUE); - } else { - tagDataAttrs.put(na.getName(), na.getText()); - } - found = true; - break; - } - } - if (!found) { - if (tagInfo.hasDynamicAttributes()) { - jspAttrs[start + i] = new Node.JspAttribute(na, null, - true); - } else { - err.jspError(n, "jsp.error.bad_attribute", - na.getName(), n.getLocalName()); - } - } - } - } - - /** - * Preprocess attributes that can be expressions. Expression delimiters - * are stripped. - *

        - * If value is null, checks if there are any NamedAttribute subelements - * in the tree node, and if so, constructs a JspAttribute out of a child - * NamedAttribute node. - */ - private Node.JspAttribute getJspAttribute(TagAttributeInfo tai, - String qName, String uri, String localName, String value, - Class expectedType, Node n, boolean dynamic) - throws JasperException { - - Node.JspAttribute result = null; - - // XXX Is it an error to see "%=foo%" in non-Xml page? - // (We won't see "<%=foo%> in xml page because '<' is not a - // valid attribute value in xml). - - if (value != null) { - if (n.getRoot().isXmlSyntax() && value.startsWith("%=")) { - result = new Node.JspAttribute(tai, qName, uri, localName, - value.substring(2, value.length() - 1), true, null, - dynamic); - } else if (!n.getRoot().isXmlSyntax() - && value.startsWith("<%=")) { - result = new Node.JspAttribute(tai, qName, uri, localName, - value.substring(3, value.length() - 2), true, null, - dynamic); - } else { - // The attribute can contain expressions but is not a - // scriptlet expression; thus, we want to run it through - // the expression interpreter - - // validate expression syntax if string contains - // expression(s) - ELNode.Nodes el = ELParser.parse(value); - - if (el.containsEL() && !pageInfo.isELIgnored()) { - validateFunctions(el, n); - - result = new Node.JspAttribute(tai, qName, uri, - localName, value, false, el, dynamic); - - ELContextImpl ctx = new ELContextImpl(); - ctx.setFunctionMapper(getFunctionMapper(el)); - - try { - result.validateEL(this.pageInfo - .getExpressionFactory(), ctx); - } catch (ELException e) { - this.err.jspError(n.getStart(), - "jsp.error.invalid.expression", value, e - .toString()); - } - - } else { - value = value.replace(Constants.ESC, '$'); - result = new Node.JspAttribute(tai, qName, uri, - localName, value, false, null, dynamic); - } - } - } else { - // Value is null. Check for any NamedAttribute subnodes - // that might contain the value for this attribute. - // Otherwise, the attribute wasn't found so we return null. - - Node.NamedAttribute namedAttributeNode = n - .getNamedAttributeNode(qName); - if (namedAttributeNode != null) { - result = new Node.JspAttribute(namedAttributeNode, tai, - dynamic); - } - } - - return result; - } - - /* - * Return an empty StringBuffer [not thread-safe] - */ - private StringBuffer getBuffer() { - this.buf.setLength(0); - return this.buf; - } - - /* - * Checks to see if the given attribute value represents a runtime or EL - * expression. - */ - private boolean isExpression(Node n, String value) { - if ((n.getRoot().isXmlSyntax() && value.startsWith("%=")) - || (!n.getRoot().isXmlSyntax() && value.startsWith("<%=")) - || (value.indexOf("${") != -1 && !pageInfo.isELIgnored())) - return true; - else - return false; - } - - /* - * Throws exception if the value of the attribute with the given name in - * the given node is given as an RT or EL expression, but the spec - * requires a static value. - */ - private void throwErrorIfExpression(Node n, String attrName, - String actionName) throws JasperException { - if (n.getAttributes() != null - && n.getAttributes().getValue(attrName) != null - && isExpression(n, n.getAttributes().getValue(attrName))) { - err.jspError(n, - "jsp.error.attribute.standard.non_rt_with_expr", - attrName, actionName); - } - } - - private static class NamedAttributeVisitor extends Node.Visitor { - private boolean hasDynamicContent; - - public void doVisit(Node n) throws JasperException { - if (!(n instanceof Node.JspText) - && !(n instanceof Node.TemplateText)) { - hasDynamicContent = true; - } - visitBody(n); - } - - public boolean hasDynamicContent() { - return hasDynamicContent; - } - } - - private String findUri(String prefix, Node n) { - - for (Node p = n; p != null; p = p.getParent()) { - Attributes attrs = p.getTaglibAttributes(); - if (attrs == null) { - continue; - } - for (int i = 0; i < attrs.getLength(); i++) { - String name = attrs.getQName(i); - int k = name.indexOf(':'); - if (prefix == null && k < 0) { - // prefix not specified and a default ns found - return attrs.getValue(i); - } - if (prefix != null && k >= 0 - && prefix.equals(name.substring(k + 1))) { - return attrs.getValue(i); - } - } - } - return null; - } - - /** - * Validate functions in EL expressions - */ - private void validateFunctions(ELNode.Nodes el, Node n) - throws JasperException { - - class FVVisitor extends ELNode.Visitor { - - Node n; - - FVVisitor(Node n) { - this.n = n; - } - - public void visit(ELNode.Function func) throws JasperException { - String prefix = func.getPrefix(); - String function = func.getName(); - String uri = null; - - if (n.getRoot().isXmlSyntax()) { - uri = findUri(prefix, n); - } else if (prefix != null) { - uri = pageInfo.getURI(prefix); - } - - if (uri == null) { - if (prefix == null) { - err.jspError(n, "jsp.error.noFunctionPrefix", - function); - } else { - err - .jspError( - n, - "jsp.error.attribute.invalidPrefix", - prefix); - } - } - TagLibraryInfo taglib = pageInfo.getTaglib(uri); - FunctionInfo funcInfo = null; - if (taglib != null) { - funcInfo = taglib.getFunction(function); - } - if (funcInfo == null) { - err.jspError(n, "jsp.error.noFunction", function); - } - // Skip TLD function uniqueness check. Done by Schema ? - func.setUri(uri); - func.setFunctionInfo(funcInfo); - processSignature(func); - } - } - - el.visit(new FVVisitor(n)); - } - - private void prepareExpression(ELNode.Nodes el, Node n, String expr) - throws JasperException { - validateFunctions(el, n); - - // test it out - ELContextImpl ctx = new ELContextImpl(); - ctx.setFunctionMapper(this.getFunctionMapper(el)); - ExpressionFactory ef = this.pageInfo.getExpressionFactory(); - try { - ef.createValueExpression(ctx, expr, Object.class); - } catch (ELException e) { - - } - } - - private void processSignature(ELNode.Function func) - throws JasperException { - func.setMethodName(getMethod(func)); - func.setParameters(getParameters(func)); - } - - /** - * Get the method name from the signature. - */ - private String getMethod(ELNode.Function func) throws JasperException { - FunctionInfo funcInfo = func.getFunctionInfo(); - String signature = funcInfo.getFunctionSignature(); - - int start = signature.indexOf(' '); - if (start < 0) { - err.jspError("jsp.error.tld.fn.invalid.signature", func - .getPrefix(), func.getName()); - } - int end = signature.indexOf('('); - if (end < 0) { - err.jspError( - "jsp.error.tld.fn.invalid.signature.parenexpected", - func.getPrefix(), func.getName()); - } - return signature.substring(start + 1, end).trim(); - } - - /** - * Get the parameters types from the function signature. - * - * @return An array of parameter class names - */ - private String[] getParameters(ELNode.Function func) - throws JasperException { - FunctionInfo funcInfo = func.getFunctionInfo(); - String signature = funcInfo.getFunctionSignature(); - ArrayList params = new ArrayList(); - // Signature is of the form - // S ( ',' )* )? ')' - int start = signature.indexOf('(') + 1; - boolean lastArg = false; - while (true) { - int p = signature.indexOf(',', start); - if (p < 0) { - p = signature.indexOf(')', start); - if (p < 0) { - err.jspError("jsp.error.tld.fn.invalid.signature", func - .getPrefix(), func.getName()); - } - lastArg = true; - } - String arg = signature.substring(start, p).trim(); - if (!"".equals(arg)) { - params.add(arg); - } - if (lastArg) { - break; - } - start = p + 1; - } - return (String[]) params.toArray(new String[params.size()]); - } - - private FunctionMapper getFunctionMapper(ELNode.Nodes el) - throws JasperException { - - class ValidateFunctionMapper extends FunctionMapper { - - private HashMap fnmap = new java.util.HashMap(); - - public void mapFunction(String fnQName, Method method) { - fnmap.put(fnQName, method); - } - - public Method resolveFunction(String prefix, String localName) { - return (Method) this.fnmap.get(prefix + ":" + localName); - } - } - - class MapperELVisitor extends ELNode.Visitor { - ValidateFunctionMapper fmapper; - - MapperELVisitor(ValidateFunctionMapper fmapper) { - this.fmapper = fmapper; - } - - public void visit(ELNode.Function n) throws JasperException { - - Class c = null; - Method method = null; - try { - c = loader.loadClass(n.getFunctionInfo() - .getFunctionClass()); - } catch (ClassNotFoundException e) { - err.jspError("jsp.error.function.classnotfound", n - .getFunctionInfo().getFunctionClass(), n - .getPrefix() - + ':' + n.getName(), e.getMessage()); - } - String paramTypes[] = n.getParameters(); - int size = paramTypes.length; - Class params[] = new Class[size]; - int i = 0; - try { - for (i = 0; i < size; i++) { - params[i] = JspUtil.toClass(paramTypes[i], loader); - } - method = c.getDeclaredMethod(n.getMethodName(), params); - } catch (ClassNotFoundException e) { - err.jspError("jsp.error.signature.classnotfound", - paramTypes[i], n.getPrefix() + ':' - + n.getName(), e.getMessage()); - } catch (NoSuchMethodException e) { - err.jspError("jsp.error.noFunctionMethod", n - .getMethodName(), n.getName(), c.getName()); - } - fmapper.mapFunction(n.getPrefix() + ':' + n.getName(), - method); - } - } - - ValidateFunctionMapper fmapper = new ValidateFunctionMapper(); - el.visit(new MapperELVisitor(fmapper)); - return fmapper; - } - } // End of ValidateVisitor - - /** - * A visitor for validating TagExtraInfo classes of all tags - */ - static class TagExtraInfoVisitor extends Node.Visitor { - - private PageInfo pageInfo; - - private ErrorDispatcher err; - - /* - * Constructor - */ - TagExtraInfoVisitor(Compiler compiler) { - this.pageInfo = compiler.getPageInfo(); - this.err = compiler.getErrorDispatcher(); - } - - public void visit(Node.CustomTag n) throws JasperException { - TagInfo tagInfo = n.getTagInfo(); - if (tagInfo == null) { - err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); - } - - ValidationMessage[] errors = tagInfo.validate(n.getTagData()); - if (errors != null && errors.length != 0) { - StringBuffer errMsg = new StringBuffer(); - errMsg.append("

        "); - errMsg.append(Localizer.getMessage( - "jsp.error.tei.invalid.attributes", n.getQName())); - errMsg.append("

        "); - for (int i = 0; i < errors.length; i++) { - errMsg.append("

        "); - if (errors[i].getId() != null) { - errMsg.append(errors[i].getId()); - errMsg.append(": "); - } - errMsg.append(errors[i].getMessage()); - errMsg.append("

        "); - } - - err.jspError(n, errMsg.toString()); - } - - visitBody(n); - } - } - - public static void validate(Compiler compiler, Node.Nodes page) - throws JasperException { - - /* - * Visit the page/tag directives first, as they are global to the page - * and are position independent. - */ - page.visit(new DirectiveVisitor(compiler)); - - // Determine the default output content type - PageInfo pageInfo = compiler.getPageInfo(); - String contentType = pageInfo.getContentType(); - - if (contentType == null || contentType.indexOf("charset=") < 0) { - boolean isXml = page.getRoot().isXmlSyntax(); - String defaultType; - if (contentType == null) { - defaultType = isXml ? "text/xml" : "text/html"; - } else { - defaultType = contentType; - } - - String charset = null; - if (isXml) { - charset = "UTF-8"; - } else { - if (!page.getRoot().isDefaultPageEncoding()) { - charset = page.getRoot().getPageEncoding(); - } - } - - if (charset != null) { - pageInfo.setContentType(defaultType + ";charset=" + charset); - } else { - pageInfo.setContentType(defaultType); - } - } - - /* - * Validate all other nodes. This validation step includes checking a - * custom tag's mandatory and optional attributes against information in - * the TLD (first validation step for custom tags according to - * JSP.10.5). - */ - page.visit(new ValidateVisitor(compiler)); - - /* - * Invoke TagLibraryValidator classes of all imported tags (second - * validation step for custom tags according to JSP.10.5). - */ - validateXmlView(new PageDataImpl(page, compiler), compiler); - - /* - * Invoke TagExtraInfo method isValid() for all imported tags (third - * validation step for custom tags according to JSP.10.5). - */ - page.visit(new TagExtraInfoVisitor(compiler)); - - } - - // ********************************************************************* - // Private (utility) methods - - /** - * Validate XML view against the TagLibraryValidator classes of all imported - * tag libraries. - */ - private static void validateXmlView(PageData xmlView, Compiler compiler) - throws JasperException { - - StringBuffer errMsg = null; - ErrorDispatcher errDisp = compiler.getErrorDispatcher(); - - for (Iterator iter = compiler.getPageInfo().getTaglibs().iterator(); iter - .hasNext();) { - - Object o = iter.next(); - if (!(o instanceof TagLibraryInfoImpl)) - continue; - TagLibraryInfoImpl tli = (TagLibraryInfoImpl) o; - - ValidationMessage[] errors = tli.validate(xmlView); - if ((errors != null) && (errors.length != 0)) { - if (errMsg == null) { - errMsg = new StringBuffer(); - } - errMsg.append("

        "); - errMsg.append(Localizer.getMessage( - "jsp.error.tlv.invalid.page", tli.getShortName(), - compiler.getPageInfo().getJspFile())); - errMsg.append("

        "); - for (int i = 0; i < errors.length; i++) { - if (errors[i] != null) { - errMsg.append("

        "); - errMsg.append(errors[i].getId()); - errMsg.append(": "); - errMsg.append(errors[i].getMessage()); - errMsg.append("

        "); - } - } - } - } - - if (errMsg != null) { - errDisp.jspError(errMsg.toString()); - } - } -} +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ExpressionFactory; +import javax.el.FunctionMapper; +import javax.servlet.jsp.tagext.FunctionInfo; +import javax.servlet.jsp.tagext.JspFragment; +import javax.servlet.jsp.tagext.PageData; +import javax.servlet.jsp.tagext.TagAttributeInfo; +import javax.servlet.jsp.tagext.TagData; +import javax.servlet.jsp.tagext.TagExtraInfo; +import javax.servlet.jsp.tagext.TagInfo; +import javax.servlet.jsp.tagext.TagLibraryInfo; +import javax.servlet.jsp.tagext.ValidationMessage; + +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.el.ELContextImpl; +import org.xml.sax.Attributes; + +/** + * Performs validation on the page elements. Attributes are checked for + * mandatory presence, entry value validity, and consistency. As a side effect, + * some page global value (such as those from page direcitves) are stored, for + * later use. + * + * @author Kin-man Chung + * @author Jan Luehe + * @author Shawn Bayern + * @author Mark Roth + */ +class Validator { + + /** + * A visitor to validate and extract page directive info + */ + static class DirectiveVisitor extends Node.Visitor { + + private PageInfo pageInfo; + + private ErrorDispatcher err; + + private static final JspUtil.ValidAttribute[] pageDirectiveAttrs = { + new JspUtil.ValidAttribute("language"), + new JspUtil.ValidAttribute("extends"), + new JspUtil.ValidAttribute("import"), + new JspUtil.ValidAttribute("session"), + new JspUtil.ValidAttribute("buffer"), + new JspUtil.ValidAttribute("autoFlush"), + new JspUtil.ValidAttribute("isThreadSafe"), + new JspUtil.ValidAttribute("info"), + new JspUtil.ValidAttribute("errorPage"), + new JspUtil.ValidAttribute("isErrorPage"), + new JspUtil.ValidAttribute("contentType"), + new JspUtil.ValidAttribute("pageEncoding"), + new JspUtil.ValidAttribute("isELIgnored") }; + + private boolean pageEncodingSeen = false; + + /* + * Constructor + */ + DirectiveVisitor(Compiler compiler) throws JasperException { + this.pageInfo = compiler.getPageInfo(); + this.err = compiler.getErrorDispatcher(); + JspCompilationContext ctxt = compiler.getCompilationContext(); + } + + public void visit(Node.IncludeDirective n) throws JasperException { + // Since pageDirectiveSeen flag only applies to the Current page + // save it here and restore it after the file is included. + boolean pageEncodingSeenSave = pageEncodingSeen; + pageEncodingSeen = false; + visitBody(n); + pageEncodingSeen = pageEncodingSeenSave; + } + + public void visit(Node.PageDirective n) throws JasperException { + + JspUtil.checkAttributes("Page directive", n, pageDirectiveAttrs, + err); + + // JSP.2.10.1 + Attributes attrs = n.getAttributes(); + for (int i = 0; attrs != null && i < attrs.getLength(); i++) { + String attr = attrs.getQName(i); + String value = attrs.getValue(i); + + if ("language".equals(attr)) { + if (pageInfo.getLanguage(false) == null) { + pageInfo.setLanguage(value, n, err, true); + } else if (!pageInfo.getLanguage(false).equals(value)) { + err.jspError(n, "jsp.error.page.conflict.language", + pageInfo.getLanguage(false), value); + } + } else if ("extends".equals(attr)) { + if (pageInfo.getExtends(false) == null) { + pageInfo.setExtends(value, n); + } else if (!pageInfo.getExtends(false).equals(value)) { + err.jspError(n, "jsp.error.page.conflict.extends", + pageInfo.getExtends(false), value); + } + } else if ("contentType".equals(attr)) { + if (pageInfo.getContentType() == null) { + pageInfo.setContentType(value); + } else if (!pageInfo.getContentType().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.contenttype", + pageInfo.getContentType(), value); + } + } else if ("session".equals(attr)) { + if (pageInfo.getSession() == null) { + pageInfo.setSession(value, n, err); + } else if (!pageInfo.getSession().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.session", + pageInfo.getSession(), value); + } + } else if ("buffer".equals(attr)) { + if (pageInfo.getBufferValue() == null) { + pageInfo.setBufferValue(value, n, err); + } else if (!pageInfo.getBufferValue().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.buffer", + pageInfo.getBufferValue(), value); + } + } else if ("autoFlush".equals(attr)) { + if (pageInfo.getAutoFlush() == null) { + pageInfo.setAutoFlush(value, n, err); + } else if (!pageInfo.getAutoFlush().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.autoflush", + pageInfo.getAutoFlush(), value); + } + } else if ("isThreadSafe".equals(attr)) { + if (pageInfo.getIsThreadSafe() == null) { + pageInfo.setIsThreadSafe(value, n, err); + } else if (!pageInfo.getIsThreadSafe().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.isthreadsafe", + pageInfo.getIsThreadSafe(), value); + } + } else if ("isELIgnored".equals(attr)) { + if (pageInfo.getIsELIgnored() == null) { + pageInfo.setIsELIgnored(value, n, err, true); + } else if (!pageInfo.getIsELIgnored().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.iselignored", + pageInfo.getIsELIgnored(), value); + } + } else if ("isErrorPage".equals(attr)) { + if (pageInfo.getIsErrorPage() == null) { + pageInfo.setIsErrorPage(value, n, err); + } else if (!pageInfo.getIsErrorPage().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.iserrorpage", + pageInfo.getIsErrorPage(), value); + } + } else if ("errorPage".equals(attr)) { + if (pageInfo.getErrorPage() == null) { + pageInfo.setErrorPage(value); + } else if (!pageInfo.getErrorPage().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.errorpage", + pageInfo.getErrorPage(), value); + } + } else if ("info".equals(attr)) { + if (pageInfo.getInfo() == null) { + pageInfo.setInfo(value); + } else if (!pageInfo.getInfo().equals(value)) { + err.jspError(n, "jsp.error.page.conflict.info", + pageInfo.getInfo(), value); + } + } else if ("pageEncoding".equals(attr)) { + if (pageEncodingSeen) + err.jspError(n, "jsp.error.page.multi.pageencoding"); + // 'pageEncoding' can occur at most once per file + pageEncodingSeen = true; + comparePageEncodings(value, n); + } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) { + if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) { + pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n, + err, true); + } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral() + .equals(value)) { + err + .jspError( + n, + "jsp.error.page.conflict.deferredsyntaxallowedasliteral", + pageInfo + .getDeferredSyntaxAllowedAsLiteral(), + value); + } + } else if ("trimDirectiveWhitespaces".equals(attr)) { + if (pageInfo.getTrimDirectiveWhitespaces() == null) { + pageInfo.setTrimDirectiveWhitespaces(value, n, err, + true); + } else if (!pageInfo.getTrimDirectiveWhitespaces().equals( + value)) { + err + .jspError( + n, + "jsp.error.page.conflict.trimdirectivewhitespaces", + pageInfo.getTrimDirectiveWhitespaces(), + value); + } + } + } + + // Check for bad combinations + if (pageInfo.getBuffer() == 0 && !pageInfo.isAutoFlush()) + err.jspError(n, "jsp.error.page.badCombo"); + + // Attributes for imports for this node have been processed by + // the parsers, just add them to pageInfo. + pageInfo.addImports(n.getImports()); + } + + public void visit(Node.TagDirective n) throws JasperException { + // Note: Most of the validation is done in TagFileProcessor + // when it created a TagInfo object from the + // tag file in which the directive appeared. + + // This method does additional processing to collect page info + + Attributes attrs = n.getAttributes(); + for (int i = 0; attrs != null && i < attrs.getLength(); i++) { + String attr = attrs.getQName(i); + String value = attrs.getValue(i); + + if ("language".equals(attr)) { + if (pageInfo.getLanguage(false) == null) { + pageInfo.setLanguage(value, n, err, false); + } else if (!pageInfo.getLanguage(false).equals(value)) { + err.jspError(n, "jsp.error.tag.conflict.language", + pageInfo.getLanguage(false), value); + } + } else if ("isELIgnored".equals(attr)) { + if (pageInfo.getIsELIgnored() == null) { + pageInfo.setIsELIgnored(value, n, err, false); + } else if (!pageInfo.getIsELIgnored().equals(value)) { + err.jspError(n, "jsp.error.tag.conflict.iselignored", + pageInfo.getIsELIgnored(), value); + } + } else if ("pageEncoding".equals(attr)) { + if (pageEncodingSeen) + err.jspError(n, "jsp.error.tag.multi.pageencoding"); + pageEncodingSeen = true; + n.getRoot().setPageEncoding(value); + } else if ("deferredSyntaxAllowedAsLiteral".equals(attr)) { + if (pageInfo.getDeferredSyntaxAllowedAsLiteral() == null) { + pageInfo.setDeferredSyntaxAllowedAsLiteral(value, n, + err, false); + } else if (!pageInfo.getDeferredSyntaxAllowedAsLiteral() + .equals(value)) { + err + .jspError( + n, + "jsp.error.tag.conflict.deferredsyntaxallowedasliteral", + pageInfo + .getDeferredSyntaxAllowedAsLiteral(), + value); + } + } else if ("trimDirectiveWhitespaces".equals(attr)) { + if (pageInfo.getTrimDirectiveWhitespaces() == null) { + pageInfo.setTrimDirectiveWhitespaces(value, n, err, + false); + } else if (!pageInfo.getTrimDirectiveWhitespaces().equals( + value)) { + err + .jspError( + n, + "jsp.error.tag.conflict.trimdirectivewhitespaces", + pageInfo.getTrimDirectiveWhitespaces(), + value); + } + } + } + + // Attributes for imports for this node have been processed by + // the parsers, just add them to pageInfo. + pageInfo.addImports(n.getImports()); + } + + public void visit(Node.AttributeDirective n) throws JasperException { + // Do nothing, since this attribute directive has already been + // validated by TagFileProcessor when it created a TagInfo object + // from the tag file in which the directive appeared + } + + public void visit(Node.VariableDirective n) throws JasperException { + // Do nothing, since this variable directive has already been + // validated by TagFileProcessor when it created a TagInfo object + // from the tag file in which the directive appeared + } + + /* + * Compares page encodings specified in various places, and throws + * exception in case of page encoding mismatch. + * + * @param pageDirEnc The value of the pageEncoding attribute of the page + * directive @param pageDir The page directive node + * + * @throws JasperException in case of page encoding mismatch + */ + private void comparePageEncodings(String pageDirEnc, + Node.PageDirective pageDir) throws JasperException { + + Node.Root root = pageDir.getRoot(); + String configEnc = root.getJspConfigPageEncoding(); + + /* + * Compare the 'pageEncoding' attribute of the page directive with + * the encoding specified in the JSP config element whose URL + * pattern matches this page. Treat "UTF-16", "UTF-16BE", and + * "UTF-16LE" as identical. + */ + if (configEnc != null + && !pageDirEnc.equals(configEnc) + && (!pageDirEnc.startsWith("UTF-16") || !configEnc + .startsWith("UTF-16"))) { + err.jspError(pageDir, + "jsp.error.config_pagedir_encoding_mismatch", + configEnc, pageDirEnc); + } + + /* + * Compare the 'pageEncoding' attribute of the page directive with + * the encoding specified in the XML prolog (only for XML syntax, + * and only if JSP document contains XML prolog with encoding + * declaration). Treat "UTF-16", "UTF-16BE", and "UTF-16LE" as + * identical. + */ + if (root.isXmlSyntax() && root.isEncodingSpecifiedInProlog()) { + String pageEnc = root.getPageEncoding(); + if (!pageDirEnc.equals(pageEnc) + && (!pageDirEnc.startsWith("UTF-16") || !pageEnc + .startsWith("UTF-16"))) { + err.jspError(pageDir, + "jsp.error.prolog_pagedir_encoding_mismatch", + pageEnc, pageDirEnc); + } + } + } + } + + /** + * A visitor for validating nodes other than page directives + */ + static class ValidateVisitor extends Node.Visitor { + + private PageInfo pageInfo; + + private ErrorDispatcher err; + + private TagInfo tagInfo; + + private ClassLoader loader; + + private final StringBuffer buf = new StringBuffer(32); + + private static final JspUtil.ValidAttribute[] jspRootAttrs = { + new JspUtil.ValidAttribute("xsi:schemaLocation"), + new JspUtil.ValidAttribute("version", true) }; + + private static final JspUtil.ValidAttribute[] includeDirectiveAttrs = { new JspUtil.ValidAttribute( + "file", true) }; + + private static final JspUtil.ValidAttribute[] taglibDirectiveAttrs = { + new JspUtil.ValidAttribute("uri"), + new JspUtil.ValidAttribute("tagdir"), + new JspUtil.ValidAttribute("prefix", true) }; + + private static final JspUtil.ValidAttribute[] includeActionAttrs = { + new JspUtil.ValidAttribute("page", true, true), + new JspUtil.ValidAttribute("flush") }; + + private static final JspUtil.ValidAttribute[] paramActionAttrs = { + new JspUtil.ValidAttribute("name", true), + new JspUtil.ValidAttribute("value", true, true) }; + + private static final JspUtil.ValidAttribute[] forwardActionAttrs = { new JspUtil.ValidAttribute( + "page", true, true) }; + + private static final JspUtil.ValidAttribute[] getPropertyAttrs = { + new JspUtil.ValidAttribute("name", true), + new JspUtil.ValidAttribute("property", true) }; + + private static final JspUtil.ValidAttribute[] setPropertyAttrs = { + new JspUtil.ValidAttribute("name", true), + new JspUtil.ValidAttribute("property", true), + new JspUtil.ValidAttribute("value", false, true), + new JspUtil.ValidAttribute("param") }; + + private static final JspUtil.ValidAttribute[] useBeanAttrs = { + new JspUtil.ValidAttribute("id", true), + new JspUtil.ValidAttribute("scope"), + new JspUtil.ValidAttribute("class"), + new JspUtil.ValidAttribute("type"), + new JspUtil.ValidAttribute("beanName", false, true) }; + + private static final JspUtil.ValidAttribute[] plugInAttrs = { + new JspUtil.ValidAttribute("type", true), + new JspUtil.ValidAttribute("code", true), + new JspUtil.ValidAttribute("codebase"), + new JspUtil.ValidAttribute("align"), + new JspUtil.ValidAttribute("archive"), + new JspUtil.ValidAttribute("height", false, true), + new JspUtil.ValidAttribute("hspace"), + new JspUtil.ValidAttribute("jreversion"), + new JspUtil.ValidAttribute("name"), + new JspUtil.ValidAttribute("vspace"), + new JspUtil.ValidAttribute("width", false, true), + new JspUtil.ValidAttribute("nspluginurl"), + new JspUtil.ValidAttribute("iepluginurl") }; + + private static final JspUtil.ValidAttribute[] attributeAttrs = { + new JspUtil.ValidAttribute("name", true), + new JspUtil.ValidAttribute("trim") }; + + private static final JspUtil.ValidAttribute[] invokeAttrs = { + new JspUtil.ValidAttribute("fragment", true), + new JspUtil.ValidAttribute("var"), + new JspUtil.ValidAttribute("varReader"), + new JspUtil.ValidAttribute("scope") }; + + private static final JspUtil.ValidAttribute[] doBodyAttrs = { + new JspUtil.ValidAttribute("var"), + new JspUtil.ValidAttribute("varReader"), + new JspUtil.ValidAttribute("scope") }; + + private static final JspUtil.ValidAttribute[] jspOutputAttrs = { + new JspUtil.ValidAttribute("omit-xml-declaration"), + new JspUtil.ValidAttribute("doctype-root-element"), + new JspUtil.ValidAttribute("doctype-public"), + new JspUtil.ValidAttribute("doctype-system") }; + + /* + * Constructor + */ + ValidateVisitor(Compiler compiler) { + this.pageInfo = compiler.getPageInfo(); + this.err = compiler.getErrorDispatcher(); + this.tagInfo = compiler.getCompilationContext().getTagInfo(); + this.loader = compiler.getCompilationContext().getClassLoader(); + } + + public void visit(Node.JspRoot n) throws JasperException { + JspUtil.checkAttributes("Jsp:root", n, jspRootAttrs, err); + String version = n.getTextAttribute("version"); + if (!version.equals("1.2") && !version.equals("2.0")) { + err.jspError(n, "jsp.error.jsproot.version.invalid", version); + } + visitBody(n); + } + + public void visit(Node.IncludeDirective n) throws JasperException { + JspUtil.checkAttributes("Include directive", n, + includeDirectiveAttrs, err); + visitBody(n); + } + + public void visit(Node.TaglibDirective n) throws JasperException { + JspUtil.checkAttributes("Taglib directive", n, + taglibDirectiveAttrs, err); + // Either 'uri' or 'tagdir' attribute must be specified + String uri = n.getAttributeValue("uri"); + String tagdir = n.getAttributeValue("tagdir"); + if (uri == null && tagdir == null) { + err.jspError(n, "jsp.error.taglibDirective.missing.location"); + } + if (uri != null && tagdir != null) { + err + .jspError(n, + "jsp.error.taglibDirective.both_uri_and_tagdir"); + } + } + + public void visit(Node.ParamAction n) throws JasperException { + JspUtil.checkAttributes("Param action", n, paramActionAttrs, err); + // make sure the value of the 'name' attribute is not a + // request-time expression + throwErrorIfExpression(n, "name", "jsp:param"); + n.setValue(getJspAttribute(null, "value", null, null, n + .getAttributeValue("value"), java.lang.String.class, n, + false)); + visitBody(n); + } + + public void visit(Node.ParamsAction n) throws JasperException { + // Make sure we've got at least one nested jsp:param + Node.Nodes subElems = n.getBody(); + if (subElems == null) { + err.jspError(n, "jsp.error.params.emptyBody"); + } + visitBody(n); + } + + public void visit(Node.IncludeAction n) throws JasperException { + JspUtil.checkAttributes("Include action", n, includeActionAttrs, + err); + n.setPage(getJspAttribute(null, "page", null, null, n + .getAttributeValue("page"), java.lang.String.class, n, + false)); + visitBody(n); + }; + + public void visit(Node.ForwardAction n) throws JasperException { + JspUtil.checkAttributes("Forward", n, forwardActionAttrs, err); + n.setPage(getJspAttribute(null, "page", null, null, n + .getAttributeValue("page"), java.lang.String.class, n, + false)); + visitBody(n); + } + + public void visit(Node.GetProperty n) throws JasperException { + JspUtil.checkAttributes("GetProperty", n, getPropertyAttrs, err); + } + + public void visit(Node.SetProperty n) throws JasperException { + JspUtil.checkAttributes("SetProperty", n, setPropertyAttrs, err); + String name = n.getTextAttribute("name"); + String property = n.getTextAttribute("property"); + String param = n.getTextAttribute("param"); + String value = n.getAttributeValue("value"); + + n.setValue(getJspAttribute(null, "value", null, null, value, + java.lang.Object.class, n, false)); + + boolean valueSpecified = n.getValue() != null; + + if ("*".equals(property)) { + if (param != null || valueSpecified) + err.jspError(n, "jsp.error.setProperty.invalid"); + + } else if (param != null && valueSpecified) { + err.jspError(n, "jsp.error.setProperty.invalid"); + } + + visitBody(n); + } + + public void visit(Node.UseBean n) throws JasperException { + JspUtil.checkAttributes("UseBean", n, useBeanAttrs, err); + + String name = n.getTextAttribute("id"); + String scope = n.getTextAttribute("scope"); + JspUtil.checkScope(scope, n, err); + String className = n.getTextAttribute("class"); + String type = n.getTextAttribute("type"); + BeanRepository beanInfo = pageInfo.getBeanRepository(); + + if (className == null && type == null) + err.jspError(n, "jsp.error.usebean.missingType"); + + if (beanInfo.checkVariable(name)) + err.jspError(n, "jsp.error.usebean.duplicate"); + + if ("session".equals(scope) && !pageInfo.isSession()) + err.jspError(n, "jsp.error.usebean.noSession"); + + Node.JspAttribute jattr = getJspAttribute(null, "beanName", null, + null, n.getAttributeValue("beanName"), + java.lang.String.class, n, false); + n.setBeanName(jattr); + if (className != null && jattr != null) + err.jspError(n, "jsp.error.usebean.notBoth"); + + if (className == null) + className = type; + + beanInfo.addBean(n, name, className, scope); + + visitBody(n); + } + + public void visit(Node.PlugIn n) throws JasperException { + JspUtil.checkAttributes("Plugin", n, plugInAttrs, err); + + throwErrorIfExpression(n, "type", "jsp:plugin"); + throwErrorIfExpression(n, "code", "jsp:plugin"); + throwErrorIfExpression(n, "codebase", "jsp:plugin"); + throwErrorIfExpression(n, "align", "jsp:plugin"); + throwErrorIfExpression(n, "archive", "jsp:plugin"); + throwErrorIfExpression(n, "hspace", "jsp:plugin"); + throwErrorIfExpression(n, "jreversion", "jsp:plugin"); + throwErrorIfExpression(n, "name", "jsp:plugin"); + throwErrorIfExpression(n, "vspace", "jsp:plugin"); + throwErrorIfExpression(n, "nspluginurl", "jsp:plugin"); + throwErrorIfExpression(n, "iepluginurl", "jsp:plugin"); + + String type = n.getTextAttribute("type"); + if (type == null) + err.jspError(n, "jsp.error.plugin.notype"); + if (!type.equals("bean") && !type.equals("applet")) + err.jspError(n, "jsp.error.plugin.badtype"); + if (n.getTextAttribute("code") == null) + err.jspError(n, "jsp.error.plugin.nocode"); + + Node.JspAttribute width = getJspAttribute(null, "width", null, + null, n.getAttributeValue("width"), java.lang.String.class, + n, false); + n.setWidth(width); + + Node.JspAttribute height = getJspAttribute(null, "height", null, + null, n.getAttributeValue("height"), + java.lang.String.class, n, false); + n.setHeight(height); + + visitBody(n); + } + + public void visit(Node.NamedAttribute n) throws JasperException { + JspUtil.checkAttributes("Attribute", n, attributeAttrs, err); + visitBody(n); + } + + public void visit(Node.JspBody n) throws JasperException { + visitBody(n); + } + + public void visit(Node.Declaration n) throws JasperException { + if (pageInfo.isScriptingInvalid()) { + err.jspError(n.getStart(), "jsp.error.no.scriptlets"); + } + } + + public void visit(Node.Expression n) throws JasperException { + if (pageInfo.isScriptingInvalid()) { + err.jspError(n.getStart(), "jsp.error.no.scriptlets"); + } + } + + public void visit(Node.Scriptlet n) throws JasperException { + if (pageInfo.isScriptingInvalid()) { + err.jspError(n.getStart(), "jsp.error.no.scriptlets"); + } + } + + public void visit(Node.ELExpression n) throws JasperException { + // exit if we are ignoring EL all together + if (pageInfo.isELIgnored()) + return; + + // JSP.2.2 - '#{' not allowed in template text + if (n.getType() == '#') { + if (pageInfo.isDeferredSyntaxAllowedAsLiteral()) + return; + err.jspError(n, "jsp.error.el.template.deferred"); + } + + // build expression + StringBuffer expr = this.getBuffer(); + expr.append(n.getType()).append('{').append(n.getText()) + .append('}'); + ELNode.Nodes el = ELParser.parse(expr.toString()); + + // validate/prepare expression + prepareExpression(el, n, expr.toString()); + + // store it + n.setEL(el); + } + + public void visit(Node.UninterpretedTag n) throws JasperException { + if (n.getNamedAttributeNodes().size() != 0) { + err.jspError(n, "jsp.error.namedAttribute.invalidUse"); + } + + Attributes attrs = n.getAttributes(); + if (attrs != null) { + int attrSize = attrs.getLength(); + Node.JspAttribute[] jspAttrs = new Node.JspAttribute[attrSize]; + for (int i = 0; i < attrSize; i++) { + jspAttrs[i] = getJspAttribute(null, attrs.getQName(i), + attrs.getURI(i), attrs.getLocalName(i), attrs + .getValue(i), java.lang.Object.class, n, + false); + } + n.setJspAttributes(jspAttrs); + } + + visitBody(n); + } + + public void visit(Node.CustomTag n) throws JasperException { + + TagInfo tagInfo = n.getTagInfo(); + if (tagInfo == null) { + err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); + } + + /* + * The bodyconet of a SimpleTag cannot be JSP. + */ + if (n.implementsSimpleTag() + && tagInfo.getBodyContent().equalsIgnoreCase( + TagInfo.BODY_CONTENT_JSP)) { + err.jspError(n, "jsp.error.simpletag.badbodycontent", tagInfo + .getTagClassName()); + } + + /* + * If the tag handler declares in the TLD that it supports dynamic + * attributes, it also must implement the DynamicAttributes + * interface. + */ + if (tagInfo.hasDynamicAttributes() + && !n.implementsDynamicAttributes()) { + err.jspError(n, "jsp.error.dynamic.attributes.not.implemented", + n.getQName()); + } + + /* + * Make sure all required attributes are present, either as + * attributes or named attributes (). Also make sure + * that the same attribute is not specified in both attributes or + * named attributes. + */ + TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); + String customActionUri = n.getURI(); + Attributes attrs = n.getAttributes(); + int attrsSize = (attrs == null) ? 0 : attrs.getLength(); + for (int i = 0; i < tldAttrs.length; i++) { + String attr = null; + if (attrs != null) { + attr = attrs.getValue(tldAttrs[i].getName()); + if (attr == null) { + attr = attrs.getValue(customActionUri, tldAttrs[i] + .getName()); + } + } + Node.NamedAttribute na = n.getNamedAttributeNode(tldAttrs[i] + .getName()); + + if (tldAttrs[i].isRequired() && attr == null && na == null) { + err.jspError(n, "jsp.error.missing_attribute", tldAttrs[i] + .getName(), n.getLocalName()); + } + if (attr != null && na != null) { + err.jspError(n, "jsp.error.duplicate.name.jspattribute", + tldAttrs[i].getName()); + } + } + + Node.Nodes naNodes = n.getNamedAttributeNodes(); + int jspAttrsSize = naNodes.size() + attrsSize; + Node.JspAttribute[] jspAttrs = null; + if (jspAttrsSize > 0) { + jspAttrs = new Node.JspAttribute[jspAttrsSize]; + } + Hashtable tagDataAttrs = new Hashtable(attrsSize); + + checkXmlAttributes(n, jspAttrs, tagDataAttrs); + checkNamedAttributes(n, jspAttrs, attrsSize, tagDataAttrs); + + TagData tagData = new TagData(tagDataAttrs); + + // JSP.C1: It is a (translation time) error for an action that + // has one or more variable subelements to have a TagExtraInfo + // class that returns a non-null object. + TagExtraInfo tei = tagInfo.getTagExtraInfo(); + if (tei != null && tei.getVariableInfo(tagData) != null + && tei.getVariableInfo(tagData).length > 0 + && tagInfo.getTagVariableInfos().length > 0) { + err.jspError("jsp.error.non_null_tei_and_var_subelems", n + .getQName()); + } + + n.setTagData(tagData); + n.setJspAttributes(jspAttrs); + + visitBody(n); + } + + public void visit(Node.JspElement n) throws JasperException { + + Attributes attrs = n.getAttributes(); + if (attrs == null) { + err.jspError(n, "jsp.error.jspelement.missing.name"); + } + int xmlAttrLen = attrs.getLength(); + + Node.Nodes namedAttrs = n.getNamedAttributeNodes(); + + // XML-style 'name' attribute, which is mandatory, must not be + // included in JspAttribute array + int jspAttrSize = xmlAttrLen - 1 + namedAttrs.size(); + + Node.JspAttribute[] jspAttrs = new Node.JspAttribute[jspAttrSize]; + int jspAttrIndex = 0; + + // Process XML-style attributes + for (int i = 0; i < xmlAttrLen; i++) { + if ("name".equals(attrs.getLocalName(i))) { + n.setNameAttribute(getJspAttribute(null, attrs.getQName(i), + attrs.getURI(i), attrs.getLocalName(i), attrs + .getValue(i), java.lang.String.class, n, + false)); + } else { + if (jspAttrIndex < jspAttrSize) { + jspAttrs[jspAttrIndex++] = getJspAttribute(null, attrs + .getQName(i), attrs.getURI(i), attrs + .getLocalName(i), attrs.getValue(i), + java.lang.Object.class, n, false); + } + } + } + if (n.getNameAttribute() == null) { + err.jspError(n, "jsp.error.jspelement.missing.name"); + } + + // Process named attributes + for (int i = 0; i < namedAttrs.size(); i++) { + Node.NamedAttribute na = (Node.NamedAttribute) namedAttrs + .getNode(i); + jspAttrs[jspAttrIndex++] = new Node.JspAttribute(na, null, + false); + } + + n.setJspAttributes(jspAttrs); + + visitBody(n); + } + + public void visit(Node.JspOutput n) throws JasperException { + JspUtil.checkAttributes("jsp:output", n, jspOutputAttrs, err); + + if (n.getBody() != null) { + err.jspError(n, "jsp.error.jspoutput.nonemptybody"); + } + + String omitXmlDecl = n.getAttributeValue("omit-xml-declaration"); + String doctypeName = n.getAttributeValue("doctype-root-element"); + String doctypePublic = n.getAttributeValue("doctype-public"); + String doctypeSystem = n.getAttributeValue("doctype-system"); + + String omitXmlDeclOld = pageInfo.getOmitXmlDecl(); + String doctypeNameOld = pageInfo.getDoctypeName(); + String doctypePublicOld = pageInfo.getDoctypePublic(); + String doctypeSystemOld = pageInfo.getDoctypeSystem(); + + if (omitXmlDecl != null && omitXmlDeclOld != null + && !omitXmlDecl.equals(omitXmlDeclOld)) { + err.jspError(n, "jsp.error.jspoutput.conflict", + "omit-xml-declaration", omitXmlDeclOld, omitXmlDecl); + } + + if (doctypeName != null && doctypeNameOld != null + && !doctypeName.equals(doctypeNameOld)) { + err.jspError(n, "jsp.error.jspoutput.conflict", + "doctype-root-element", doctypeNameOld, doctypeName); + } + + if (doctypePublic != null && doctypePublicOld != null + && !doctypePublic.equals(doctypePublicOld)) { + err.jspError(n, "jsp.error.jspoutput.conflict", + "doctype-public", doctypePublicOld, doctypePublic); + } + + if (doctypeSystem != null && doctypeSystemOld != null + && !doctypeSystem.equals(doctypeSystemOld)) { + err.jspError(n, "jsp.error.jspoutput.conflict", + "doctype-system", doctypeSystemOld, doctypeSystem); + } + + if (doctypeName == null && doctypeSystem != null + || doctypeName != null && doctypeSystem == null) { + err.jspError(n, "jsp.error.jspoutput.doctypenamesystem"); + } + + if (doctypePublic != null && doctypeSystem == null) { + err.jspError(n, "jsp.error.jspoutput.doctypepulicsystem"); + } + + if (omitXmlDecl != null) { + pageInfo.setOmitXmlDecl(omitXmlDecl); + } + if (doctypeName != null) { + pageInfo.setDoctypeName(doctypeName); + } + if (doctypeSystem != null) { + pageInfo.setDoctypeSystem(doctypeSystem); + } + if (doctypePublic != null) { + pageInfo.setDoctypePublic(doctypePublic); + } + } + + public void visit(Node.InvokeAction n) throws JasperException { + + JspUtil.checkAttributes("Invoke", n, invokeAttrs, err); + + String scope = n.getTextAttribute("scope"); + JspUtil.checkScope(scope, n, err); + + String var = n.getTextAttribute("var"); + String varReader = n.getTextAttribute("varReader"); + if (scope != null && var == null && varReader == null) { + err.jspError(n, "jsp.error.missing_var_or_varReader"); + } + if (var != null && varReader != null) { + err.jspError(n, "jsp.error.var_and_varReader"); + } + } + + public void visit(Node.DoBodyAction n) throws JasperException { + + JspUtil.checkAttributes("DoBody", n, doBodyAttrs, err); + + String scope = n.getTextAttribute("scope"); + JspUtil.checkScope(scope, n, err); + + String var = n.getTextAttribute("var"); + String varReader = n.getTextAttribute("varReader"); + if (scope != null && var == null && varReader == null) { + err.jspError(n, "jsp.error.missing_var_or_varReader"); + } + if (var != null && varReader != null) { + err.jspError(n, "jsp.error.var_and_varReader"); + } + } + + /* + * Make sure the given custom action does not have any invalid + * attributes. + * + * A custom action and its declared attributes always belong to the same + * namespace, which is identified by the prefix name of the custom tag + * invocation. For example, in this invocation: + * + * , the action + * + * "test" and its attributes "a", "b", and "c" all belong to the + * namespace identified by the prefix "my". The above invocation would + * be equivalent to: + * + * + * + * An action attribute may have a prefix different from that of the + * action invocation only if the underlying tag handler supports dynamic + * attributes, in which case the attribute with the different prefix is + * considered a dynamic attribute. + */ + private void checkXmlAttributes(Node.CustomTag n, + Node.JspAttribute[] jspAttrs, Hashtable tagDataAttrs) + throws JasperException { + + TagInfo tagInfo = n.getTagInfo(); + if (tagInfo == null) { + err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); + } + TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); + Attributes attrs = n.getAttributes(); + + for (int i = 0; attrs != null && i < attrs.getLength(); i++) { + boolean found = false; + for (int j = 0; tldAttrs != null && j < tldAttrs.length; j++) { + if (attrs.getLocalName(i).equals(tldAttrs[j].getName()) + && (attrs.getURI(i) == null + || attrs.getURI(i).length() == 0 || attrs + .getURI(i).equals(n.getURI()))) { + if (tldAttrs[j].canBeRequestTime() + || tldAttrs[j].isDeferredMethod() // JSP 2.1 + || tldAttrs[j].isDeferredValue()) { // JSP 2.1 + Class expectedType = String.class; + try { + String typeStr = tldAttrs[j].getTypeName(); + if (tldAttrs[j].isFragment()) { + expectedType = JspFragment.class; + } else if (typeStr != null) { + expectedType = JspUtil.toClass(typeStr, + loader); + } + jspAttrs[i] = getJspAttribute(tldAttrs[j], + attrs.getQName(i), attrs.getURI(i), + attrs.getLocalName(i), attrs + .getValue(i), expectedType, n, + false); + } catch (ClassNotFoundException e) { + err.jspError(n, + "jsp.error.unknown_attribute_type", + tldAttrs[j].getName(), tldAttrs[j] + .getTypeName()); + } + } else { + // Attribute does not accept any expressions. + // Make sure its value does not contain any. + if (isExpression(n, attrs.getValue(i))) { + err + .jspError( + n, + "jsp.error.attribute.custom.non_rt_with_expr", + tldAttrs[j].getName()); + } + jspAttrs[i] = new Node.JspAttribute(tldAttrs[j], + attrs.getQName(i), attrs.getURI(i), attrs + .getLocalName(i), + attrs.getValue(i), false, null, false); + } + if (jspAttrs[i].isExpression()) { + tagDataAttrs.put(attrs.getQName(i), + TagData.REQUEST_TIME_VALUE); + } else { + tagDataAttrs.put(attrs.getQName(i), attrs + .getValue(i)); + } + found = true; + break; + } + } + if (!found) { + if (tagInfo.hasDynamicAttributes()) { + jspAttrs[i] = getJspAttribute(null, attrs.getQName(i), + attrs.getURI(i), attrs.getLocalName(i), attrs + .getValue(i), java.lang.Object.class, + n, true); + } else { + err.jspError(n, "jsp.error.bad_attribute", attrs + .getQName(i), n.getLocalName()); + } + } + } + } + + /* + * Make sure the given custom action does not have any invalid named + * attributes + */ + private void checkNamedAttributes(Node.CustomTag n, + Node.JspAttribute[] jspAttrs, int start, Hashtable tagDataAttrs) + throws JasperException { + + TagInfo tagInfo = n.getTagInfo(); + if (tagInfo == null) { + err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); + } + TagAttributeInfo[] tldAttrs = tagInfo.getAttributes(); + Node.Nodes naNodes = n.getNamedAttributeNodes(); + + for (int i = 0; i < naNodes.size(); i++) { + Node.NamedAttribute na = (Node.NamedAttribute) naNodes + .getNode(i); + boolean found = false; + for (int j = 0; j < tldAttrs.length; j++) { + /* + * See above comment about namespace matches. For named + * attributes, we use the prefix instead of URI as the match + * criterion, because in the case of a JSP document, we'd + * have to keep track of which namespaces are in scope when + * parsing a named attribute, in order to determine the URI + * that the prefix of the named attribute's name matches to. + */ + String attrPrefix = na.getPrefix(); + if (na.getLocalName().equals(tldAttrs[j].getName()) + && (attrPrefix == null || attrPrefix.length() == 0 || attrPrefix + .equals(n.getPrefix()))) { + jspAttrs[start + i] = new Node.JspAttribute(na, + tldAttrs[j], false); + NamedAttributeVisitor nav = null; + if (na.getBody() != null) { + nav = new NamedAttributeVisitor(); + na.getBody().visit(nav); + } + if (nav != null && nav.hasDynamicContent()) { + tagDataAttrs.put(na.getName(), + TagData.REQUEST_TIME_VALUE); + } else { + tagDataAttrs.put(na.getName(), na.getText()); + } + found = true; + break; + } + } + if (!found) { + if (tagInfo.hasDynamicAttributes()) { + jspAttrs[start + i] = new Node.JspAttribute(na, null, + true); + } else { + err.jspError(n, "jsp.error.bad_attribute", + na.getName(), n.getLocalName()); + } + } + } + } + + /** + * Preprocess attributes that can be expressions. Expression delimiters + * are stripped. + *

        + * If value is null, checks if there are any NamedAttribute subelements + * in the tree node, and if so, constructs a JspAttribute out of a child + * NamedAttribute node. + */ + private Node.JspAttribute getJspAttribute(TagAttributeInfo tai, + String qName, String uri, String localName, String value, + Class expectedType, Node n, boolean dynamic) + throws JasperException { + + Node.JspAttribute result = null; + + // XXX Is it an error to see "%=foo%" in non-Xml page? + // (We won't see "<%=foo%> in xml page because '<' is not a + // valid attribute value in xml). + + if (value != null) { + if (n.getRoot().isXmlSyntax() && value.startsWith("%=")) { + result = new Node.JspAttribute(tai, qName, uri, localName, + value.substring(2, value.length() - 1), true, null, + dynamic); + } else if (!n.getRoot().isXmlSyntax() + && value.startsWith("<%=")) { + result = new Node.JspAttribute(tai, qName, uri, localName, + value.substring(3, value.length() - 2), true, null, + dynamic); + } else { + // The attribute can contain expressions but is not a + // scriptlet expression; thus, we want to run it through + // the expression interpreter + + // validate expression syntax if string contains + // expression(s) + ELNode.Nodes el = ELParser.parse(value); + + if (el.containsEL() && !pageInfo.isELIgnored()) { + validateFunctions(el, n); + + result = new Node.JspAttribute(tai, qName, uri, + localName, value, false, el, dynamic); + + ELContextImpl ctx = new ELContextImpl(); + ctx.setFunctionMapper(getFunctionMapper(el)); + + try { + result.validateEL(this.pageInfo + .getExpressionFactory(), ctx); + } catch (ELException e) { + this.err.jspError(n.getStart(), + "jsp.error.invalid.expression", value, e + .toString()); + } + + } else { + value = value.replace(Constants.ESC, '$'); + result = new Node.JspAttribute(tai, qName, uri, + localName, value, false, null, dynamic); + } + } + } else { + // Value is null. Check for any NamedAttribute subnodes + // that might contain the value for this attribute. + // Otherwise, the attribute wasn't found so we return null. + + Node.NamedAttribute namedAttributeNode = n + .getNamedAttributeNode(qName); + if (namedAttributeNode != null) { + result = new Node.JspAttribute(namedAttributeNode, tai, + dynamic); + } + } + + return result; + } + + /* + * Return an empty StringBuffer [not thread-safe] + */ + private StringBuffer getBuffer() { + this.buf.setLength(0); + return this.buf; + } + + /* + * Checks to see if the given attribute value represents a runtime or EL + * expression. + */ + private boolean isExpression(Node n, String value) { + if ((n.getRoot().isXmlSyntax() && value.startsWith("%=")) + || (!n.getRoot().isXmlSyntax() && value.startsWith("<%=")) + || (value.indexOf("${") != -1 && !pageInfo.isELIgnored())) + return true; + else + return false; + } + + /* + * Throws exception if the value of the attribute with the given name in + * the given node is given as an RT or EL expression, but the spec + * requires a static value. + */ + private void throwErrorIfExpression(Node n, String attrName, + String actionName) throws JasperException { + if (n.getAttributes() != null + && n.getAttributes().getValue(attrName) != null + && isExpression(n, n.getAttributes().getValue(attrName))) { + err.jspError(n, + "jsp.error.attribute.standard.non_rt_with_expr", + attrName, actionName); + } + } + + private static class NamedAttributeVisitor extends Node.Visitor { + private boolean hasDynamicContent; + + public void doVisit(Node n) throws JasperException { + if (!(n instanceof Node.JspText) + && !(n instanceof Node.TemplateText)) { + hasDynamicContent = true; + } + visitBody(n); + } + + public boolean hasDynamicContent() { + return hasDynamicContent; + } + } + + private String findUri(String prefix, Node n) { + + for (Node p = n; p != null; p = p.getParent()) { + Attributes attrs = p.getTaglibAttributes(); + if (attrs == null) { + continue; + } + for (int i = 0; i < attrs.getLength(); i++) { + String name = attrs.getQName(i); + int k = name.indexOf(':'); + if (prefix == null && k < 0) { + // prefix not specified and a default ns found + return attrs.getValue(i); + } + if (prefix != null && k >= 0 + && prefix.equals(name.substring(k + 1))) { + return attrs.getValue(i); + } + } + } + return null; + } + + /** + * Validate functions in EL expressions + */ + private void validateFunctions(ELNode.Nodes el, Node n) + throws JasperException { + + class FVVisitor extends ELNode.Visitor { + + Node n; + + FVVisitor(Node n) { + this.n = n; + } + + public void visit(ELNode.Function func) throws JasperException { + String prefix = func.getPrefix(); + String function = func.getName(); + String uri = null; + + if (n.getRoot().isXmlSyntax()) { + uri = findUri(prefix, n); + } else if (prefix != null) { + uri = pageInfo.getURI(prefix); + } + + if (uri == null) { + if (prefix == null) { + err.jspError(n, "jsp.error.noFunctionPrefix", + function); + } else { + err + .jspError( + n, + "jsp.error.attribute.invalidPrefix", + prefix); + } + } + TagLibraryInfo taglib = pageInfo.getTaglib(uri); + FunctionInfo funcInfo = null; + if (taglib != null) { + funcInfo = taglib.getFunction(function); + } + if (funcInfo == null) { + err.jspError(n, "jsp.error.noFunction", function); + } + // Skip TLD function uniqueness check. Done by Schema ? + func.setUri(uri); + func.setFunctionInfo(funcInfo); + processSignature(func); + } + } + + el.visit(new FVVisitor(n)); + } + + private void prepareExpression(ELNode.Nodes el, Node n, String expr) + throws JasperException { + validateFunctions(el, n); + + // test it out + ELContextImpl ctx = new ELContextImpl(); + ctx.setFunctionMapper(this.getFunctionMapper(el)); + ExpressionFactory ef = this.pageInfo.getExpressionFactory(); + try { + ef.createValueExpression(ctx, expr, Object.class); + } catch (ELException e) { + + } + } + + private void processSignature(ELNode.Function func) + throws JasperException { + func.setMethodName(getMethod(func)); + func.setParameters(getParameters(func)); + } + + /** + * Get the method name from the signature. + */ + private String getMethod(ELNode.Function func) throws JasperException { + FunctionInfo funcInfo = func.getFunctionInfo(); + String signature = funcInfo.getFunctionSignature(); + + int start = signature.indexOf(' '); + if (start < 0) { + err.jspError("jsp.error.tld.fn.invalid.signature", func + .getPrefix(), func.getName()); + } + int end = signature.indexOf('('); + if (end < 0) { + err.jspError( + "jsp.error.tld.fn.invalid.signature.parenexpected", + func.getPrefix(), func.getName()); + } + return signature.substring(start + 1, end).trim(); + } + + /** + * Get the parameters types from the function signature. + * + * @return An array of parameter class names + */ + private String[] getParameters(ELNode.Function func) + throws JasperException { + FunctionInfo funcInfo = func.getFunctionInfo(); + String signature = funcInfo.getFunctionSignature(); + ArrayList params = new ArrayList(); + // Signature is of the form + // S ( ',' )* )? ')' + int start = signature.indexOf('(') + 1; + boolean lastArg = false; + while (true) { + int p = signature.indexOf(',', start); + if (p < 0) { + p = signature.indexOf(')', start); + if (p < 0) { + err.jspError("jsp.error.tld.fn.invalid.signature", func + .getPrefix(), func.getName()); + } + lastArg = true; + } + String arg = signature.substring(start, p).trim(); + if (!"".equals(arg)) { + params.add(arg); + } + if (lastArg) { + break; + } + start = p + 1; + } + return (String[]) params.toArray(new String[params.size()]); + } + + private FunctionMapper getFunctionMapper(ELNode.Nodes el) + throws JasperException { + + class ValidateFunctionMapper extends FunctionMapper { + + private HashMap fnmap = new java.util.HashMap(); + + public void mapFunction(String fnQName, Method method) { + fnmap.put(fnQName, method); + } + + public Method resolveFunction(String prefix, String localName) { + return (Method) this.fnmap.get(prefix + ":" + localName); + } + } + + class MapperELVisitor extends ELNode.Visitor { + ValidateFunctionMapper fmapper; + + MapperELVisitor(ValidateFunctionMapper fmapper) { + this.fmapper = fmapper; + } + + public void visit(ELNode.Function n) throws JasperException { + + Class c = null; + Method method = null; + try { + c = loader.loadClass(n.getFunctionInfo() + .getFunctionClass()); + } catch (ClassNotFoundException e) { + err.jspError("jsp.error.function.classnotfound", n + .getFunctionInfo().getFunctionClass(), n + .getPrefix() + + ':' + n.getName(), e.getMessage()); + } + String paramTypes[] = n.getParameters(); + int size = paramTypes.length; + Class params[] = new Class[size]; + int i = 0; + try { + for (i = 0; i < size; i++) { + params[i] = JspUtil.toClass(paramTypes[i], loader); + } + method = c.getDeclaredMethod(n.getMethodName(), params); + } catch (ClassNotFoundException e) { + err.jspError("jsp.error.signature.classnotfound", + paramTypes[i], n.getPrefix() + ':' + + n.getName(), e.getMessage()); + } catch (NoSuchMethodException e) { + err.jspError("jsp.error.noFunctionMethod", n + .getMethodName(), n.getName(), c.getName()); + } + fmapper.mapFunction(n.getPrefix() + ':' + n.getName(), + method); + } + } + + ValidateFunctionMapper fmapper = new ValidateFunctionMapper(); + el.visit(new MapperELVisitor(fmapper)); + return fmapper; + } + } // End of ValidateVisitor + + /** + * A visitor for validating TagExtraInfo classes of all tags + */ + static class TagExtraInfoVisitor extends Node.Visitor { + + private PageInfo pageInfo; + + private ErrorDispatcher err; + + /* + * Constructor + */ + TagExtraInfoVisitor(Compiler compiler) { + this.pageInfo = compiler.getPageInfo(); + this.err = compiler.getErrorDispatcher(); + } + + public void visit(Node.CustomTag n) throws JasperException { + TagInfo tagInfo = n.getTagInfo(); + if (tagInfo == null) { + err.jspError(n, "jsp.error.missing.tagInfo", n.getQName()); + } + + ValidationMessage[] errors = tagInfo.validate(n.getTagData()); + if (errors != null && errors.length != 0) { + StringBuffer errMsg = new StringBuffer(); + errMsg.append("

        "); + errMsg.append(Localizer.getMessage( + "jsp.error.tei.invalid.attributes", n.getQName())); + errMsg.append("

        "); + for (int i = 0; i < errors.length; i++) { + errMsg.append("

        "); + if (errors[i].getId() != null) { + errMsg.append(errors[i].getId()); + errMsg.append(": "); + } + errMsg.append(errors[i].getMessage()); + errMsg.append("

        "); + } + + err.jspError(n, errMsg.toString()); + } + + visitBody(n); + } + } + + public static void validate(Compiler compiler, Node.Nodes page) + throws JasperException { + + /* + * Visit the page/tag directives first, as they are global to the page + * and are position independent. + */ + page.visit(new DirectiveVisitor(compiler)); + + // Determine the default output content type + PageInfo pageInfo = compiler.getPageInfo(); + String contentType = pageInfo.getContentType(); + + if (contentType == null || contentType.indexOf("charset=") < 0) { + boolean isXml = page.getRoot().isXmlSyntax(); + String defaultType; + if (contentType == null) { + defaultType = isXml ? "text/xml" : "text/html"; + } else { + defaultType = contentType; + } + + String charset = null; + if (isXml) { + charset = "UTF-8"; + } else { + if (!page.getRoot().isDefaultPageEncoding()) { + charset = page.getRoot().getPageEncoding(); + } + } + + if (charset != null) { + pageInfo.setContentType(defaultType + ";charset=" + charset); + } else { + pageInfo.setContentType(defaultType); + } + } + + /* + * Validate all other nodes. This validation step includes checking a + * custom tag's mandatory and optional attributes against information in + * the TLD (first validation step for custom tags according to + * JSP.10.5). + */ + page.visit(new ValidateVisitor(compiler)); + + /* + * Invoke TagLibraryValidator classes of all imported tags (second + * validation step for custom tags according to JSP.10.5). + */ + validateXmlView(new PageDataImpl(page, compiler), compiler); + + /* + * Invoke TagExtraInfo method isValid() for all imported tags (third + * validation step for custom tags according to JSP.10.5). + */ + page.visit(new TagExtraInfoVisitor(compiler)); + + } + + // ********************************************************************* + // Private (utility) methods + + /** + * Validate XML view against the TagLibraryValidator classes of all imported + * tag libraries. + */ + private static void validateXmlView(PageData xmlView, Compiler compiler) + throws JasperException { + + StringBuffer errMsg = null; + ErrorDispatcher errDisp = compiler.getErrorDispatcher(); + + for (Iterator iter = compiler.getPageInfo().getTaglibs().iterator(); iter + .hasNext();) { + + Object o = iter.next(); + if (!(o instanceof TagLibraryInfoImpl)) + continue; + TagLibraryInfoImpl tli = (TagLibraryInfoImpl) o; + + ValidationMessage[] errors = tli.validate(xmlView); + if ((errors != null) && (errors.length != 0)) { + if (errMsg == null) { + errMsg = new StringBuffer(); + } + errMsg.append("

        "); + errMsg.append(Localizer.getMessage( + "jsp.error.tlv.invalid.page", tli.getShortName(), + compiler.getPageInfo().getJspFile())); + errMsg.append("

        "); + for (int i = 0; i < errors.length; i++) { + if (errors[i] != null) { + errMsg.append("

        "); + errMsg.append(errors[i].getId()); + errMsg.append(": "); + errMsg.append(errors[i].getMessage()); + errMsg.append("

        "); + } + } + } + } + + if (errMsg != null) { + errDisp.jspError(errMsg.toString()); + } + } +} diff --git a/java/org/apache/jasper/compiler/tagplugin/TagPlugin.java b/java/org/apache/jasper/compiler/tagplugin/TagPlugin.java index 97490582b..34af677ed 100644 --- a/java/org/apache/jasper/compiler/tagplugin/TagPlugin.java +++ b/java/org/apache/jasper/compiler/tagplugin/TagPlugin.java @@ -1,36 +1,36 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler.tagplugin; - -/** - * This interface is to be implemented by the plugin author, to supply - * an alternate implementation of the tag handlers. It can be used to - * specify the Java codes to be generated when a tag is invoked. - * - * An implementation of this interface must be registered in a file - * named "tagPlugins.xml" under WEB-INF. - */ - -public interface TagPlugin { - - /** - * Generate codes for a custom tag. - * @param ctxt a TagPluginContext for accessing Jasper functions - */ - void doTag(TagPluginContext ctxt); -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler.tagplugin; + +/** + * This interface is to be implemented by the plugin author, to supply + * an alternate implementation of the tag handlers. It can be used to + * specify the Java codes to be generated when a tag is invoked. + * + * An implementation of this interface must be registered in a file + * named "tagPlugins.xml" under WEB-INF. + */ + +public interface TagPlugin { + + /** + * Generate codes for a custom tag. + * @param ctxt a TagPluginContext for accessing Jasper functions + */ + void doTag(TagPluginContext ctxt); +} + diff --git a/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java b/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java index fed41b3a8..40490deff 100644 --- a/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java +++ b/java/org/apache/jasper/compiler/tagplugin/TagPluginContext.java @@ -1,123 +1,123 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.compiler.tagplugin; - - -/** - * This interface allows the plugin author to make inqueries about the - * properties of the current tag, and to use Jasper resources to generate - * direct Java codes in place of tag handler invocations. - */ - -public interface TagPluginContext { - /** - * @return true if the body of the tag is scriptless. - */ - boolean isScriptless(); - - /** - * @param attribute Name of the attribute - * @return true if the attribute is specified in the tag - */ - boolean isAttributeSpecified(String attribute); - - /** - * @return An unique temporary variable name that the plugin can use. - */ - String getTemporaryVariableName(); - - /** - * Generate an import statement - * @param s Name of the import class, '*' allowed. - */ - void generateImport(String s); - - /** - * Generate a declaration in the of the generated class. This can be - * used to declare an innter class, a method, or a class variable. - * @param id An unique ID identifying the declaration. It is not - * part of the declaration, and is used to ensure that the - * declaration will only appear once. If this method is - * invoked with the same id more than once in the translation - * unit, only the first declaration will be taken. - * @param text The text of the declaration. - **/ - void generateDeclaration(String id, String text); - - /** - * Generate Java source codes - */ - void generateJavaSource(String s); - - /** - * @return true if the attribute is specified and its value is a - * translation-time constant. - */ - boolean isConstantAttribute(String attribute); - - /** - * @return A string that is the value of a constant attribute. Undefined - * if the attribute is not a (translation-time) constant. - * null if the attribute is not specified. - */ - String getConstantAttribute(String attribute); - - /** - * Generate codesto evaluate value of a attribute in the custom tag - * The codes is a Java expression. - * NOTE: Currently cannot handle attributes that are fragments. - * @param attribute The specified attribute - */ - void generateAttribute(String attribute); - - /** - * Generate codes for the body of the custom tag - */ - void generateBody(); - - /** - * Abandon optimization for this tag handler, and instruct - * Jasper to generate the tag handler calls, as usual. - * Should be invoked if errors are detected, or when the tag body - * is deemed too compilicated for optimization. - */ - void dontUseTagPlugin(); - - /** - * Get the PluginContext for the parent of this custom tag. NOTE: - * The operations available for PluginContext so obtained is limited - * to getPluginAttribute and setPluginAttribute, and queries (e.g. - * isScriptless(). There should be no calls to generate*(). - * @return The pluginContext for the parent node. - * null if the parent is not a custom tag, or if the pluginConxt - * if not available (because useTagPlugin is false, e.g). - */ - TagPluginContext getParentContext(); - - /** - * Associate the attribute with a value in the current tagplugin context. - * The plugin attributes can be used for communication among tags that - * must work together as a group. See for an example. - */ - void setPluginAttribute(String attr, Object value); - - /** - * Get the value of an attribute in the current tagplugin context. - */ - Object getPluginAttribute(String attr); -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler.tagplugin; + + +/** + * This interface allows the plugin author to make inqueries about the + * properties of the current tag, and to use Jasper resources to generate + * direct Java codes in place of tag handler invocations. + */ + +public interface TagPluginContext { + /** + * @return true if the body of the tag is scriptless. + */ + boolean isScriptless(); + + /** + * @param attribute Name of the attribute + * @return true if the attribute is specified in the tag + */ + boolean isAttributeSpecified(String attribute); + + /** + * @return An unique temporary variable name that the plugin can use. + */ + String getTemporaryVariableName(); + + /** + * Generate an import statement + * @param s Name of the import class, '*' allowed. + */ + void generateImport(String s); + + /** + * Generate a declaration in the of the generated class. This can be + * used to declare an innter class, a method, or a class variable. + * @param id An unique ID identifying the declaration. It is not + * part of the declaration, and is used to ensure that the + * declaration will only appear once. If this method is + * invoked with the same id more than once in the translation + * unit, only the first declaration will be taken. + * @param text The text of the declaration. + **/ + void generateDeclaration(String id, String text); + + /** + * Generate Java source codes + */ + void generateJavaSource(String s); + + /** + * @return true if the attribute is specified and its value is a + * translation-time constant. + */ + boolean isConstantAttribute(String attribute); + + /** + * @return A string that is the value of a constant attribute. Undefined + * if the attribute is not a (translation-time) constant. + * null if the attribute is not specified. + */ + String getConstantAttribute(String attribute); + + /** + * Generate codesto evaluate value of a attribute in the custom tag + * The codes is a Java expression. + * NOTE: Currently cannot handle attributes that are fragments. + * @param attribute The specified attribute + */ + void generateAttribute(String attribute); + + /** + * Generate codes for the body of the custom tag + */ + void generateBody(); + + /** + * Abandon optimization for this tag handler, and instruct + * Jasper to generate the tag handler calls, as usual. + * Should be invoked if errors are detected, or when the tag body + * is deemed too compilicated for optimization. + */ + void dontUseTagPlugin(); + + /** + * Get the PluginContext for the parent of this custom tag. NOTE: + * The operations available for PluginContext so obtained is limited + * to getPluginAttribute and setPluginAttribute, and queries (e.g. + * isScriptless(). There should be no calls to generate*(). + * @return The pluginContext for the parent node. + * null if the parent is not a custom tag, or if the pluginConxt + * if not available (because useTagPlugin is false, e.g). + */ + TagPluginContext getParentContext(); + + /** + * Associate the attribute with a value in the current tagplugin context. + * The plugin attributes can be used for communication among tags that + * must work together as a group. See for an example. + */ + void setPluginAttribute(String attr, Object value); + + /** + * Get the value of an attribute in the current tagplugin context. + */ + Object getPluginAttribute(String attr); +} + diff --git a/java/org/apache/jasper/el/ELContextImpl.java b/java/org/apache/jasper/el/ELContextImpl.java index 38d064b1a..56b8786c1 100644 --- a/java/org/apache/jasper/el/ELContextImpl.java +++ b/java/org/apache/jasper/el/ELContextImpl.java @@ -1,98 +1,98 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import javax.el.ELContext; -import javax.el.ELResolver; -import javax.el.FunctionMapper; -import javax.el.ValueExpression; -import javax.el.VariableMapper; - -/** - * Implementation of ELContext - * - * @author Jacob Hookom - */ -public final class ELContextImpl extends ELContext { - - private final static FunctionMapper NullFunctionMapper = new FunctionMapper() { - public Method resolveFunction(String prefix, String localName) { - return null; - } - }; - - private final static class VariableMapperImpl extends VariableMapper { - - private Map vars; - - public ValueExpression resolveVariable(String variable) { - if (vars == null) { - return null; - } - return vars.get(variable); - } - - public ValueExpression setVariable(String variable, - ValueExpression expression) { - if (vars == null) - vars = new HashMap(); - return vars.put(variable, expression); - } - - } - - private final ELResolver resolver; - - private FunctionMapper functionMapper = NullFunctionMapper; // immutable - - private VariableMapper variableMapper; - - public ELContextImpl() { - this(ELResolverImpl.DefaultResolver); - } - - public ELContextImpl(ELResolver resolver) { - this.resolver = resolver; - } - - public ELResolver getELResolver() { - return this.resolver; - } - - public FunctionMapper getFunctionMapper() { - return this.functionMapper; - } - - public VariableMapper getVariableMapper() { - if (this.variableMapper == null) { - this.variableMapper = new VariableMapperImpl(); - } - return this.variableMapper; - } - - public void setFunctionMapper(FunctionMapper functionMapper) { - this.functionMapper = functionMapper; - } - - public void setVariableMapper(VariableMapper variableMapper) { - this.variableMapper = variableMapper; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.ValueExpression; +import javax.el.VariableMapper; + +/** + * Implementation of ELContext + * + * @author Jacob Hookom + */ +public final class ELContextImpl extends ELContext { + + private final static FunctionMapper NullFunctionMapper = new FunctionMapper() { + public Method resolveFunction(String prefix, String localName) { + return null; + } + }; + + private final static class VariableMapperImpl extends VariableMapper { + + private Map vars; + + public ValueExpression resolveVariable(String variable) { + if (vars == null) { + return null; + } + return vars.get(variable); + } + + public ValueExpression setVariable(String variable, + ValueExpression expression) { + if (vars == null) + vars = new HashMap(); + return vars.put(variable, expression); + } + + } + + private final ELResolver resolver; + + private FunctionMapper functionMapper = NullFunctionMapper; // immutable + + private VariableMapper variableMapper; + + public ELContextImpl() { + this(ELResolverImpl.DefaultResolver); + } + + public ELContextImpl(ELResolver resolver) { + this.resolver = resolver; + } + + public ELResolver getELResolver() { + return this.resolver; + } + + public FunctionMapper getFunctionMapper() { + return this.functionMapper; + } + + public VariableMapper getVariableMapper() { + if (this.variableMapper == null) { + this.variableMapper = new VariableMapperImpl(); + } + return this.variableMapper; + } + + public void setFunctionMapper(FunctionMapper functionMapper) { + this.functionMapper = functionMapper; + } + + public void setVariableMapper(VariableMapper variableMapper) { + this.variableMapper = variableMapper; + } + +} diff --git a/java/org/apache/jasper/el/ELContextWrapper.java b/java/org/apache/jasper/el/ELContextWrapper.java index f795e910c..7accf4987 100644 --- a/java/org/apache/jasper/el/ELContextWrapper.java +++ b/java/org/apache/jasper/el/ELContextWrapper.java @@ -1,77 +1,77 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.util.Locale; - -import javax.el.ELContext; -import javax.el.ELResolver; -import javax.el.FunctionMapper; -import javax.el.VariableMapper; - -/** - * Simple ELContextWrapper for runtime evaluation of EL w/ dynamic FunctionMappers - * - * @author jhook - */ -public final class ELContextWrapper extends ELContext { - - private final ELContext target; - private final FunctionMapper fnMapper; - - public ELContextWrapper(ELContext target, FunctionMapper fnMapper) { - this.target = target; - this.fnMapper = fnMapper; - } - - public ELResolver getELResolver() { - return this.target.getELResolver(); - } - - public FunctionMapper getFunctionMapper() { - if (this.fnMapper != null) return this.fnMapper; - return this.target.getFunctionMapper(); - } - - public VariableMapper getVariableMapper() { - return this.target.getVariableMapper(); - } - - public Object getContext(Class key) { - return this.target.getContext(key); - } - - public Locale getLocale() { - return this.target.getLocale(); - } - - public boolean isPropertyResolved() { - return this.target.isPropertyResolved(); - } - - public void putContext(Class key, Object contextObject) throws NullPointerException { - this.target.putContext(key, contextObject); - } - - public void setLocale(Locale locale) { - this.target.setLocale(locale); - } - - public void setPropertyResolved(boolean resolved) { - this.target.setPropertyResolved(resolved); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.util.Locale; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.VariableMapper; + +/** + * Simple ELContextWrapper for runtime evaluation of EL w/ dynamic FunctionMappers + * + * @author jhook + */ +public final class ELContextWrapper extends ELContext { + + private final ELContext target; + private final FunctionMapper fnMapper; + + public ELContextWrapper(ELContext target, FunctionMapper fnMapper) { + this.target = target; + this.fnMapper = fnMapper; + } + + public ELResolver getELResolver() { + return this.target.getELResolver(); + } + + public FunctionMapper getFunctionMapper() { + if (this.fnMapper != null) return this.fnMapper; + return this.target.getFunctionMapper(); + } + + public VariableMapper getVariableMapper() { + return this.target.getVariableMapper(); + } + + public Object getContext(Class key) { + return this.target.getContext(key); + } + + public Locale getLocale() { + return this.target.getLocale(); + } + + public boolean isPropertyResolved() { + return this.target.isPropertyResolved(); + } + + public void putContext(Class key, Object contextObject) throws NullPointerException { + this.target.putContext(key, contextObject); + } + + public void setLocale(Locale locale) { + this.target.setLocale(locale); + } + + public void setPropertyResolved(boolean resolved) { + this.target.setPropertyResolved(resolved); + } + +} diff --git a/java/org/apache/jasper/el/ELResolverImpl.java b/java/org/apache/jasper/el/ELResolverImpl.java index 8b1deaa4c..69139a97f 100644 --- a/java/org/apache/jasper/el/ELResolverImpl.java +++ b/java/org/apache/jasper/el/ELResolverImpl.java @@ -1,144 +1,144 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.util.Iterator; - -import javax.el.ArrayELResolver; -import javax.el.BeanELResolver; -import javax.el.CompositeELResolver; -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.ELResolver; -import javax.el.ListELResolver; -import javax.el.MapELResolver; -import javax.el.PropertyNotFoundException; -import javax.el.PropertyNotWritableException; -import javax.el.ResourceBundleELResolver; -import javax.servlet.jsp.el.VariableResolver; - -public final class ELResolverImpl extends ELResolver { - - public final static ELResolver DefaultResolver = new CompositeELResolver(); - - static { - ((CompositeELResolver) DefaultResolver).add(new MapELResolver()); - ((CompositeELResolver) DefaultResolver).add(new ResourceBundleELResolver()); - ((CompositeELResolver) DefaultResolver).add(new ListELResolver()); - ((CompositeELResolver) DefaultResolver).add(new ArrayELResolver()); - ((CompositeELResolver) DefaultResolver).add(new BeanELResolver()); - } - - private final VariableResolver variableResolver; - - public ELResolverImpl(VariableResolver variableResolver) { - this.variableResolver = variableResolver; - } - - public Object getValue(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - if (property != null) { - try { - return this.variableResolver.resolveVariable(property - .toString()); - } catch (javax.servlet.jsp.el.ELException e) { - throw new ELException(e.getMessage(), e.getCause()); - } - } - } - - if (!context.isPropertyResolved()) { - return DefaultResolver.getValue(context, base, property); - } - return null; - } - - public Class getType(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - if (property != null) { - try { - Object obj = this.variableResolver.resolveVariable(property - .toString()); - return (obj != null) ? obj.getClass() : null; - } catch (javax.servlet.jsp.el.ELException e) { - throw new ELException(e.getMessage(), e.getCause()); - } - } - } - - if (!context.isPropertyResolved()) { - return DefaultResolver.getType(context, base, property); - } - return null; - } - - public void setValue(ELContext context, Object base, Object property, - Object value) throws NullPointerException, - PropertyNotFoundException, PropertyNotWritableException, - ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - throw new PropertyNotWritableException( - "Legacy VariableResolver wrapped, not writable"); - } - - if (!context.isPropertyResolved()) { - DefaultResolver.setValue(context, base, property, value); - } - } - - public boolean isReadOnly(ELContext context, Object base, Object property) - throws NullPointerException, PropertyNotFoundException, ELException { - if (context == null) { - throw new NullPointerException(); - } - - if (base == null) { - context.setPropertyResolved(true); - return true; - } - - return DefaultResolver.isReadOnly(context, base, property); - } - - public Iterator getFeatureDescriptors(ELContext context, Object base) { - return DefaultResolver.getFeatureDescriptors(context, base); - } - - public Class getCommonPropertyType(ELContext context, Object base) { - if (base == null) { - return String.class; - } - return DefaultResolver.getCommonPropertyType(context, base); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.util.Iterator; + +import javax.el.ArrayELResolver; +import javax.el.BeanELResolver; +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ELResolver; +import javax.el.ListELResolver; +import javax.el.MapELResolver; +import javax.el.PropertyNotFoundException; +import javax.el.PropertyNotWritableException; +import javax.el.ResourceBundleELResolver; +import javax.servlet.jsp.el.VariableResolver; + +public final class ELResolverImpl extends ELResolver { + + public final static ELResolver DefaultResolver = new CompositeELResolver(); + + static { + ((CompositeELResolver) DefaultResolver).add(new MapELResolver()); + ((CompositeELResolver) DefaultResolver).add(new ResourceBundleELResolver()); + ((CompositeELResolver) DefaultResolver).add(new ListELResolver()); + ((CompositeELResolver) DefaultResolver).add(new ArrayELResolver()); + ((CompositeELResolver) DefaultResolver).add(new BeanELResolver()); + } + + private final VariableResolver variableResolver; + + public ELResolverImpl(VariableResolver variableResolver) { + this.variableResolver = variableResolver; + } + + public Object getValue(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + if (property != null) { + try { + return this.variableResolver.resolveVariable(property + .toString()); + } catch (javax.servlet.jsp.el.ELException e) { + throw new ELException(e.getMessage(), e.getCause()); + } + } + } + + if (!context.isPropertyResolved()) { + return DefaultResolver.getValue(context, base, property); + } + return null; + } + + public Class getType(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + if (property != null) { + try { + Object obj = this.variableResolver.resolveVariable(property + .toString()); + return (obj != null) ? obj.getClass() : null; + } catch (javax.servlet.jsp.el.ELException e) { + throw new ELException(e.getMessage(), e.getCause()); + } + } + } + + if (!context.isPropertyResolved()) { + return DefaultResolver.getType(context, base, property); + } + return null; + } + + public void setValue(ELContext context, Object base, Object property, + Object value) throws NullPointerException, + PropertyNotFoundException, PropertyNotWritableException, + ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + throw new PropertyNotWritableException( + "Legacy VariableResolver wrapped, not writable"); + } + + if (!context.isPropertyResolved()) { + DefaultResolver.setValue(context, base, property, value); + } + } + + public boolean isReadOnly(ELContext context, Object base, Object property) + throws NullPointerException, PropertyNotFoundException, ELException { + if (context == null) { + throw new NullPointerException(); + } + + if (base == null) { + context.setPropertyResolved(true); + return true; + } + + return DefaultResolver.isReadOnly(context, base, property); + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + return DefaultResolver.getFeatureDescriptors(context, base); + } + + public Class getCommonPropertyType(ELContext context, Object base) { + if (base == null) { + return String.class; + } + return DefaultResolver.getCommonPropertyType(context, base); + } + +} diff --git a/java/org/apache/jasper/el/ExpressionEvaluatorImpl.java b/java/org/apache/jasper/el/ExpressionEvaluatorImpl.java index cb585adfa..4b37e7d76 100644 --- a/java/org/apache/jasper/el/ExpressionEvaluatorImpl.java +++ b/java/org/apache/jasper/el/ExpressionEvaluatorImpl.java @@ -1,57 +1,57 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.ELContext; -import javax.el.ExpressionFactory; -import javax.el.ValueExpression; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.ELParseException; -import javax.servlet.jsp.el.Expression; -import javax.servlet.jsp.el.ExpressionEvaluator; -import javax.servlet.jsp.el.FunctionMapper; -import javax.servlet.jsp.el.VariableResolver; - - -public final class ExpressionEvaluatorImpl extends ExpressionEvaluator { - - private final ExpressionFactory factory; - - public ExpressionEvaluatorImpl(ExpressionFactory factory) { - this.factory = factory; - } - - public Expression parseExpression(String expression, Class expectedType, - FunctionMapper fMapper) throws ELException { - try { - ELContextImpl ctx = new ELContextImpl(ELResolverImpl.DefaultResolver); - if (fMapper != null) { - ctx.setFunctionMapper(new FunctionMapperImpl(fMapper)); - } - ValueExpression ve = this.factory.createValueExpression(ctx, expression, expectedType); - return new ExpressionImpl(ve); - } catch (javax.el.ELException e) { - throw new ELParseException(e.getMessage()); - } - } - - public Object evaluate(String expression, Class expectedType, - VariableResolver vResolver, FunctionMapper fMapper) - throws ELException { - return this.parseExpression(expression, expectedType, fMapper).evaluate(vResolver); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.ELContext; +import javax.el.ExpressionFactory; +import javax.el.ValueExpression; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.ELParseException; +import javax.servlet.jsp.el.Expression; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.FunctionMapper; +import javax.servlet.jsp.el.VariableResolver; + + +public final class ExpressionEvaluatorImpl extends ExpressionEvaluator { + + private final ExpressionFactory factory; + + public ExpressionEvaluatorImpl(ExpressionFactory factory) { + this.factory = factory; + } + + public Expression parseExpression(String expression, Class expectedType, + FunctionMapper fMapper) throws ELException { + try { + ELContextImpl ctx = new ELContextImpl(ELResolverImpl.DefaultResolver); + if (fMapper != null) { + ctx.setFunctionMapper(new FunctionMapperImpl(fMapper)); + } + ValueExpression ve = this.factory.createValueExpression(ctx, expression, expectedType); + return new ExpressionImpl(ve); + } catch (javax.el.ELException e) { + throw new ELParseException(e.getMessage()); + } + } + + public Object evaluate(String expression, Class expectedType, + VariableResolver vResolver, FunctionMapper fMapper) + throws ELException { + return this.parseExpression(expression, expectedType, fMapper).evaluate(vResolver); + } + +} diff --git a/java/org/apache/jasper/el/ExpressionImpl.java b/java/org/apache/jasper/el/ExpressionImpl.java index a0e4a9680..5b4cef1fd 100644 --- a/java/org/apache/jasper/el/ExpressionImpl.java +++ b/java/org/apache/jasper/el/ExpressionImpl.java @@ -1,41 +1,41 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.CompositeELResolver; -import javax.el.ELContext; -import javax.el.ELResolver; -import javax.el.ValueExpression; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.Expression; -import javax.servlet.jsp.el.VariableResolver; - -import org.apache.jasper.runtime.JspApplicationContextImpl; - -public final class ExpressionImpl extends Expression { - - private final ValueExpression ve; - - public ExpressionImpl(ValueExpression ve) { - this.ve = ve; - } - - public Object evaluate(VariableResolver vResolver) throws ELException { - ELContext ctx = new ELContextImpl(new ELResolverImpl(vResolver)); - return ve.getValue(ctx); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.ValueExpression; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.Expression; +import javax.servlet.jsp.el.VariableResolver; + +import org.apache.jasper.runtime.JspApplicationContextImpl; + +public final class ExpressionImpl extends Expression { + + private final ValueExpression ve; + + public ExpressionImpl(ValueExpression ve) { + this.ve = ve; + } + + public Object evaluate(VariableResolver vResolver) throws ELException { + ELContext ctx = new ELContextImpl(new ELResolverImpl(vResolver)); + return ve.getValue(ctx); + } + +} diff --git a/java/org/apache/jasper/el/FunctionMapperImpl.java b/java/org/apache/jasper/el/FunctionMapperImpl.java index f12828b63..3ff29eb94 100644 --- a/java/org/apache/jasper/el/FunctionMapperImpl.java +++ b/java/org/apache/jasper/el/FunctionMapperImpl.java @@ -1,34 +1,34 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.lang.reflect.Method; - -import javax.servlet.jsp.el.FunctionMapper; - -public final class FunctionMapperImpl extends javax.el.FunctionMapper { - - private final FunctionMapper fnMapper; - - public FunctionMapperImpl(FunctionMapper fnMapper) { - this.fnMapper = fnMapper; - } - - public Method resolveFunction(String prefix, String localName) { - return this.fnMapper.resolveFunction(prefix, localName); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.lang.reflect.Method; + +import javax.servlet.jsp.el.FunctionMapper; + +public final class FunctionMapperImpl extends javax.el.FunctionMapper { + + private final FunctionMapper fnMapper; + + public FunctionMapperImpl(FunctionMapper fnMapper) { + this.fnMapper = fnMapper; + } + + public Method resolveFunction(String prefix, String localName) { + return this.fnMapper.resolveFunction(prefix, localName); + } + +} diff --git a/java/org/apache/jasper/el/JspELException.java b/java/org/apache/jasper/el/JspELException.java index 360f958f4..dcd1c7353 100644 --- a/java/org/apache/jasper/el/JspELException.java +++ b/java/org/apache/jasper/el/JspELException.java @@ -1,25 +1,25 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.ELException; - -public class JspELException extends ELException { - - public JspELException(String mark, ELException e) { - super(mark + " " + e.getMessage(), e.getCause()); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.ELException; + +public class JspELException extends ELException { + + public JspELException(String mark, ELException e) { + super(mark + " " + e.getMessage(), e.getCause()); + } +} diff --git a/java/org/apache/jasper/el/JspMethodExpression.java b/java/org/apache/jasper/el/JspMethodExpression.java index f9971af38..5589b9b64 100644 --- a/java/org/apache/jasper/el/JspMethodExpression.java +++ b/java/org/apache/jasper/el/JspMethodExpression.java @@ -1,107 +1,107 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.MethodExpression; -import javax.el.MethodInfo; -import javax.el.MethodNotFoundException; -import javax.el.PropertyNotFoundException; - -public final class JspMethodExpression extends MethodExpression implements - Externalizable { - - private String mark; - - private MethodExpression target; - - public JspMethodExpression() { - super(); - } - - public JspMethodExpression(String mark, MethodExpression target) { - this.target = target; - this.mark = mark; - } - - public MethodInfo getMethodInfo(ELContext context) - throws NullPointerException, PropertyNotFoundException, - MethodNotFoundException, ELException { - try { - return this.target.getMethodInfo(context); - } catch (MethodNotFoundException e) { - if (e instanceof JspMethodNotFoundException) throw e; - throw new JspMethodNotFoundException(this.mark, e); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public Object invoke(ELContext context, Object[] params) - throws NullPointerException, PropertyNotFoundException, - MethodNotFoundException, ELException { - try { - return this.target.invoke(context, params); - } catch (MethodNotFoundException e) { - if (e instanceof JspMethodNotFoundException) throw e; - throw new JspMethodNotFoundException(this.mark, e); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public boolean equals(Object obj) { - return this.target.equals(obj); - } - - public int hashCode() { - return this.target.hashCode(); - } - - public String getExpressionString() { - return this.target.getExpressionString(); - } - - public boolean isLiteralText() { - return this.target.isLiteralText(); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(this.mark); - out.writeObject(this.target); - } - - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.mark = in.readUTF(); - this.target = (MethodExpression) in.readObject(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.MethodExpression; +import javax.el.MethodInfo; +import javax.el.MethodNotFoundException; +import javax.el.PropertyNotFoundException; + +public final class JspMethodExpression extends MethodExpression implements + Externalizable { + + private String mark; + + private MethodExpression target; + + public JspMethodExpression() { + super(); + } + + public JspMethodExpression(String mark, MethodExpression target) { + this.target = target; + this.mark = mark; + } + + public MethodInfo getMethodInfo(ELContext context) + throws NullPointerException, PropertyNotFoundException, + MethodNotFoundException, ELException { + try { + return this.target.getMethodInfo(context); + } catch (MethodNotFoundException e) { + if (e instanceof JspMethodNotFoundException) throw e; + throw new JspMethodNotFoundException(this.mark, e); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public Object invoke(ELContext context, Object[] params) + throws NullPointerException, PropertyNotFoundException, + MethodNotFoundException, ELException { + try { + return this.target.invoke(context, params); + } catch (MethodNotFoundException e) { + if (e instanceof JspMethodNotFoundException) throw e; + throw new JspMethodNotFoundException(this.mark, e); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public boolean equals(Object obj) { + return this.target.equals(obj); + } + + public int hashCode() { + return this.target.hashCode(); + } + + public String getExpressionString() { + return this.target.getExpressionString(); + } + + public boolean isLiteralText() { + return this.target.isLiteralText(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(this.mark); + out.writeObject(this.target); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.mark = in.readUTF(); + this.target = (MethodExpression) in.readObject(); + } + +} diff --git a/java/org/apache/jasper/el/JspMethodNotFoundException.java b/java/org/apache/jasper/el/JspMethodNotFoundException.java index be9e7a526..cc7b9099c 100644 --- a/java/org/apache/jasper/el/JspMethodNotFoundException.java +++ b/java/org/apache/jasper/el/JspMethodNotFoundException.java @@ -1,25 +1,25 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.MethodNotFoundException; - -public class JspMethodNotFoundException extends MethodNotFoundException { - - public JspMethodNotFoundException(String mark, MethodNotFoundException e) { - super(mark + " " + e.getMessage(), e.getCause()); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.MethodNotFoundException; + +public class JspMethodNotFoundException extends MethodNotFoundException { + + public JspMethodNotFoundException(String mark, MethodNotFoundException e) { + super(mark + " " + e.getMessage(), e.getCause()); + } +} diff --git a/java/org/apache/jasper/el/JspPropertyNotFoundException.java b/java/org/apache/jasper/el/JspPropertyNotFoundException.java index 92c64d0df..3dcca4f09 100644 --- a/java/org/apache/jasper/el/JspPropertyNotFoundException.java +++ b/java/org/apache/jasper/el/JspPropertyNotFoundException.java @@ -1,27 +1,27 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.PropertyNotFoundException; - -public final class JspPropertyNotFoundException extends - PropertyNotFoundException { - - public JspPropertyNotFoundException(String mark, PropertyNotFoundException e) { - super(mark + " " + e.getMessage(), e.getCause()); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.PropertyNotFoundException; + +public final class JspPropertyNotFoundException extends + PropertyNotFoundException { + + public JspPropertyNotFoundException(String mark, PropertyNotFoundException e) { + super(mark + " " + e.getMessage(), e.getCause()); + } + +} diff --git a/java/org/apache/jasper/el/JspPropertyNotWritableException.java b/java/org/apache/jasper/el/JspPropertyNotWritableException.java index c22dd7016..b8bda2213 100644 --- a/java/org/apache/jasper/el/JspPropertyNotWritableException.java +++ b/java/org/apache/jasper/el/JspPropertyNotWritableException.java @@ -1,26 +1,26 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.PropertyNotWritableException; - -public class JspPropertyNotWritableException extends - PropertyNotWritableException { - - public JspPropertyNotWritableException(String mark, PropertyNotWritableException e) { - super(mark + " " + e.getMessage(), e.getCause()); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.PropertyNotWritableException; + +public class JspPropertyNotWritableException extends + PropertyNotWritableException { + + public JspPropertyNotWritableException(String mark, PropertyNotWritableException e) { + super(mark + " " + e.getMessage(), e.getCause()); + } +} diff --git a/java/org/apache/jasper/el/JspValueExpression.java b/java/org/apache/jasper/el/JspValueExpression.java index 833f4046d..7f6b80fec 100644 --- a/java/org/apache/jasper/el/JspValueExpression.java +++ b/java/org/apache/jasper/el/JspValueExpression.java @@ -1,136 +1,136 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import java.io.Externalizable; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectOutput; - -import javax.el.ELContext; -import javax.el.ELException; -import javax.el.PropertyNotFoundException; -import javax.el.PropertyNotWritableException; -import javax.el.ValueExpression; - -/** - * Wrapper for providing context to ValueExpressions - * - * @author Jacob Hookom - */ -public final class JspValueExpression extends ValueExpression implements - Externalizable { - - private ValueExpression target; - - private String mark; - - public JspValueExpression() { - super(); - } - - public JspValueExpression(String mark, ValueExpression target) { - this.target = target; - this.mark = mark; - } - - public Class getExpectedType() { - return this.target.getExpectedType(); - } - - public Class getType(ELContext context) throws NullPointerException, - PropertyNotFoundException, ELException { - try { - return this.target.getType(context); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public boolean isReadOnly(ELContext context) throws NullPointerException, - PropertyNotFoundException, ELException { - try { - return this.target.isReadOnly(context); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public void setValue(ELContext context, Object value) - throws NullPointerException, PropertyNotFoundException, - PropertyNotWritableException, ELException { - try { - this.target.setValue(context, value); - } catch (PropertyNotWritableException e) { - if (e instanceof JspPropertyNotWritableException) throw e; - throw new JspPropertyNotWritableException(this.mark, e); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public Object getValue(ELContext context) throws NullPointerException, - PropertyNotFoundException, ELException { - try { - return this.target.getValue(context); - } catch (PropertyNotFoundException e) { - if (e instanceof JspPropertyNotFoundException) throw e; - throw new JspPropertyNotFoundException(this.mark, e); - } catch (ELException e) { - if (e instanceof JspELException) throw e; - throw new JspELException(this.mark, e); - } - } - - public boolean equals(Object obj) { - return this.target.equals(obj); - } - - public int hashCode() { - return this.target.hashCode(); - } - - public String getExpressionString() { - return this.target.getExpressionString(); - } - - public boolean isLiteralText() { - return this.target.isLiteralText(); - } - - public void writeExternal(ObjectOutput out) throws IOException { - out.writeUTF(this.mark); - out.writeObject(this.target); - } - - public void readExternal(ObjectInput in) throws IOException, - ClassNotFoundException { - this.mark = in.readUTF(); - this.target = (ValueExpression) in.readObject(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectOutput; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.PropertyNotFoundException; +import javax.el.PropertyNotWritableException; +import javax.el.ValueExpression; + +/** + * Wrapper for providing context to ValueExpressions + * + * @author Jacob Hookom + */ +public final class JspValueExpression extends ValueExpression implements + Externalizable { + + private ValueExpression target; + + private String mark; + + public JspValueExpression() { + super(); + } + + public JspValueExpression(String mark, ValueExpression target) { + this.target = target; + this.mark = mark; + } + + public Class getExpectedType() { + return this.target.getExpectedType(); + } + + public Class getType(ELContext context) throws NullPointerException, + PropertyNotFoundException, ELException { + try { + return this.target.getType(context); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public boolean isReadOnly(ELContext context) throws NullPointerException, + PropertyNotFoundException, ELException { + try { + return this.target.isReadOnly(context); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public void setValue(ELContext context, Object value) + throws NullPointerException, PropertyNotFoundException, + PropertyNotWritableException, ELException { + try { + this.target.setValue(context, value); + } catch (PropertyNotWritableException e) { + if (e instanceof JspPropertyNotWritableException) throw e; + throw new JspPropertyNotWritableException(this.mark, e); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public Object getValue(ELContext context) throws NullPointerException, + PropertyNotFoundException, ELException { + try { + return this.target.getValue(context); + } catch (PropertyNotFoundException e) { + if (e instanceof JspPropertyNotFoundException) throw e; + throw new JspPropertyNotFoundException(this.mark, e); + } catch (ELException e) { + if (e instanceof JspELException) throw e; + throw new JspELException(this.mark, e); + } + } + + public boolean equals(Object obj) { + return this.target.equals(obj); + } + + public int hashCode() { + return this.target.hashCode(); + } + + public String getExpressionString() { + return this.target.getExpressionString(); + } + + public boolean isLiteralText() { + return this.target.isLiteralText(); + } + + public void writeExternal(ObjectOutput out) throws IOException { + out.writeUTF(this.mark); + out.writeObject(this.target); + } + + public void readExternal(ObjectInput in) throws IOException, + ClassNotFoundException { + this.mark = in.readUTF(); + this.target = (ValueExpression) in.readObject(); + } +} diff --git a/java/org/apache/jasper/el/VariableResolverImpl.java b/java/org/apache/jasper/el/VariableResolverImpl.java index c2b3fd43d..81b0f8bef 100644 --- a/java/org/apache/jasper/el/VariableResolverImpl.java +++ b/java/org/apache/jasper/el/VariableResolverImpl.java @@ -1,34 +1,34 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.el; - -import javax.el.ELContext; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.VariableResolver; - -public final class VariableResolverImpl implements VariableResolver { - - private final ELContext ctx; - - public VariableResolverImpl(ELContext ctx) { - this.ctx = ctx; - } - - public Object resolveVariable(String pName) throws ELException { - return this.ctx.getELResolver().getValue(this.ctx, null, pName); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.el; + +import javax.el.ELContext; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.VariableResolver; + +public final class VariableResolverImpl implements VariableResolver { + + private final ELContext ctx; + + public VariableResolverImpl(ELContext ctx) { + this.ctx = ctx; + } + + public Object resolveVariable(String pName) throws ELException { + return this.ctx.getELResolver().getValue(this.ctx, null, pName); + } + +} diff --git a/java/org/apache/jasper/resources/LocalStrings.properties b/java/org/apache/jasper/resources/LocalStrings.properties index 990a21c44..93c1519f7 100644 --- a/java/org/apache/jasper/resources/LocalStrings.properties +++ b/java/org/apache/jasper/resources/LocalStrings.properties @@ -1,423 +1,423 @@ -# $Id: LocalStrings.properties 379417 2006-02-21 10:57:35Z remm $ -# -# Default localized string information -# Localized this the Default Locale as is en_US - -jsp.error.compiler=No Java compiler available -jsp.error.bad.servlet.engine=Incorrect servlet engine version! -jsp.error.no.scratch.dir=The JSP engine is not configured with a scratch dir.\ -\n Please add \"jsp.initparams=scratchdir=\" \ -\n in the servlets.properties file for this context. -jsp.error.bad.scratch.dir=The scratchDir you specified: {0} is unusable. -jsp.message.scratch.dir.is=Scratch dir for the JSP engine is: {0} -jsp.message.parent_class_loader_is=Parent class loader is: {0} -jsp.message.dont.modify.servlets=IMPORTANT: Do not modify the generated servlets -jsp.error.not.impl.comments=Internal error: Comments not implemented -jsp.error.not.impl.directives=Internal error: Directives not implemented -jsp.error.not.impl.declarations=Internal error: Declarations not implemented -jsp.error.not.impl.expressions=Internal error: Expressions not implemented -jsp.error.not.impl.scriptlets=Internal error: Scriptlets not implemented -jsp.error.not.impl.usebean=Internal error: useBean not implemented -jsp.error.not.impl.getp=Internal error: getProperty not implemented -jsp.error.not.impl.setp=Internal error: setProperty not implemented -jsp.error.not.impl.plugin=Internal error: plugin not implemented -jsp.error.not.impl.forward=Internal error: forward not implemented -jsp.error.not.impl.include=Internal error: include not implemented -jsp.error.unavailable=JSP has been marked unavailable -jsp.error.usebean.missing.attribute=useBean: id attribute missing or misspelled -jsp.error.usebean.missing.type=useBean ({0}): Either class or type attribute must be \ -specified: -jsp.error.usebean.duplicate=useBean: Duplicate bean name: {0} -jsp.error.usebean.prohibited.as.session=Can't use as session bean {0} since it is prohibited \ -by jsp directive defined earlier: -jsp.error.usebean.not.both=useBean: Can't specify both class and beanName attribute: -jsp.error.usebean.bad.type.cast=useBean ({0}): Type ({1}) is not assignable from class ({2}) -jsp.error.invalid.scope=Illegal value of \'scope\' attribute: {0} (must be one of \"page\", \"request\", \"session\", or \"application\") -jsp.error.classname=Can't determine classname from .class file -jsp.warning.bad.type=Warning: bad type in .class file -jsp.error.data.file.write=Error while writing data file -jsp.error.page.invalid.buffer=Page directive: invalid buffer size -jsp.error.page.conflict.contenttype=Page directive: illegal to have multiple occurrences of 'contentType' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.contenttype=Page directive: invalid value for contentType -jsp.error.page.conflict.session=Page directive: illegal to have multiple occurrences of 'session' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.session=Page directive: invalid value for session -jsp.error.page.conflict.buffer=Page directive: illegal to have multiple occurrences of 'buffer' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.buffer=Page directive: invalid value for buffer -jsp.error.page.conflict.autoflush=Page directive: illegal to have multiple occurrences of 'autoFlush' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.autoflush=Page directive: invalid value for autoFlush -jsp.error.page.conflict.isthreadsafe=Page directive: illegal to have multiple occurrences of 'isThreadSafe' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.isthreadsafe=Page directive: invalid value for isThreadSafe -jsp.error.page.conflict.info=Page directive: illegal to have multiple occurrences of 'info' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.info=Page directive: invalid value for info -jsp.error.page.conflict.iserrorpage=Page directive: illegal to have multiple occurrences of 'isErrorPage' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.iserrorpage=Page directive: invalid value for isErrorPage -jsp.error.page.conflict.errorpage=Page directive: illegal to have multiple occurrences of 'errorPage' with different values (old: {0}, new: {1}) -jsp.error.page.conflict.language=Page directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1}) -jsp.error.tag.conflict.language=Tag directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1}) -jsp.error.page.language.nonjava=Page directive: invalid language attribute -jsp.error.tag.language.nonjava=Tag directive: invalid language attribute -jsp.error.page.defafteruse.language=Page directive: can't define language after a scriptlet -jsp.error.page.nomapping.language=Page directive: No mapping for language: -jsp.error.page.conflict.extends=Page directive: illegal to have multiple occurrences of 'extends' with different values (old: {0}, new: {1}) -jsp.error.page.conflict.iselignored=Page directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1}) -jsp.error.tag.conflict.iselignored=Tag directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1}) -jsp.error.page.invalid.iselignored=Page directive: invalid value for isELIgnored -jsp.error.tag.invalid.iselignored=Tag directive: invalid value for isELIgnored -jsp.error.page.multi.pageencoding=Page directive must not have multiple occurrences of pageencoding -jsp.error.tag.conflict.attr=Tag directive: illegal to have multiple occurrences of the attribute \"{0}\" with different values (old: {1}, new: {2}) -jsp.error.tag.multi.pageencoding=Tag directive must not have multiple occurrences of pageencoding -jsp.error.page.bad_b_and_a_combo=Page directive: Illegal combination of buffer=\"none\" && autoFlush=\"false\" -jsp.error.not.impl.taglib=Internal error: Tag extensions not implemented -jsp.error.include.missing.file=Missing file argument to include -jsp.error.include.bad.file=Bad file argument to include -jsp.error.include.exception=Unable to include {0} -jsp.error.stream.closed=Stream closed -jsp.error.invalid.forward=Invalid forward tag -jsp.error.unknownException=Unhandled error! You might want to consider having an error page \ -to report such errors more gracefully -jsp.error.invalid.directive=Invalid directive -jsp.error.directive.istagfile={0} directive cannot be used in a tag file -jsp.error.directive.isnottagfile={0} directive can only be used in a tag file -jsp.error.tagfile.tld.name=The \"name\" attribute of the tag directive has a value {0} while the \"name\" tag of the \"tag-file\" element in the TLD is {1} -jsp.error.action.istagfile={0} action cannot be used in a tag file -jsp.error.action.isnottagfile={0} action can be used in tag files only -jsp.error.unterminated=Unterminated {0} tag -jsp.error.usebean.notinsamefile=useBean tag must begin and end in the same physical file -jsp.error.loadclass.taghandler=Unable to load tag handler class \"{0}\" for tag \"{1}\" -jsp.error.unable.compile=Unable to compile class for JSP -jsp.error.unable.load=Unable to load class for JSP -jsp.error.unable.rename=Unable to rename class file {0} to {1} -jsp.error.mandatory.attribute={0}: Mandatory attribute {1} missing -jsp.engine.info=Jasper JSP 2.0 Engine -jsp.error.invalid.expression="{0}" contains invalid expression(s): {1} -jsp.error.invalid.attribute={0} has invalid attribute: {1} -jsp.error.usebean.class.notfound=Class: {0} not found -jsp.error.file.cannot.read=Cannot read file: {0} -jsp.error.file.already.registered=Recursive include of file {0} -jsp.error.file.not.registered=file {0} not seen in include -jsp.error.quotes.unterminated=Unterminated quotes -jsp.error.attr.quoted=Attribute value should be quoted -jsp.error.attr.novalue=Attribute {0} has no value -jsp.error.tag.attr.unterminated=Unterminated tag attribute list -jsp.error.param.noname=No name in PARAM tag -jsp.error.param.novalue=No value in PARAM tag -jsp.error.beans.nullbean=Attempted a bean operation on a null object. -jsp.error.beans.nobeaninfo=No BeanInfo for the bean of type ''{0}'' could be found, the class likely does not exist. -jsp.error.beans.introspection=An exception occurred while introspecting the read method of property ''{0}'' in a bean of type ''{1}'':\n{2} -jsp.error.beans.nomethod=Cannot find a method to read property ''{0}'' in a bean of type ''{1}'' -jsp.error.beans.nomethod.setproperty=Can''t find a method to write property ''{0}'' of type ''{1}'' in a bean of type ''{2}'' -jsp.error.beans.noproperty=Cannot find any information on property ''{0}'' in a bean of type ''{1}'' -jsp.error.beans.setproperty.noindexset=Cannot set indexed property -jsp.error.include.tag=Invalid jsp:include tag -jsp.error.include.noflush=jsp:include needs to have \"flush=true\" -jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" is the only valid combination in JSP 1.0 -jsp.error.attempt_to_clear_flushed_buffer=Error: Attempt to clear a buffer that's already been flushed -jsp.error.overflow=Error: JSP Buffer overflow -jsp.error.paramexpected=Expecting \"jsp:param\" standard action with \"name\" and \"value\" attributes -jsp.error.param.invalidUse=The jsp:param action must not be used outside the jsp:include, jsp:forward, or jsp:params elements -jsp.error.params.invalidUse=jsp:params must be a direct child of jsp:plugin -jsp.error.fallback.invalidUse=jsp:fallback must be a direct child of jsp:plugin -jsp.error.namedAttribute.invalidUse=jsp:attribute must be the subelement of a standard or custom action -jsp.error.jspbody.invalidUse=jsp:body must be the subelement of a standard or custom action -jsp.error.closeindividualparam=param tag needs to be closed with \"/>\" -jsp.error.closeparams=param tag needs to be closed with /params -jsp.error.params.emptyBody=jsp:params must contain at least one nested jsp:param -jsp.error.params.illegalChild=jsp:params must not have any nested elements other than jsp:param -jsp.error.plugin.notype=type not declared in jsp:plugin -jsp.error.plugin.badtype=Illegal value for 'type' attribute in jsp:plugin: must be 'bean' or 'applet' -jsp.error.plugin.nocode=code not declared in jsp:plugin -jsp.error.ise_on_clear=Illegal to clear() when buffer size == 0 -jsp.error.setproperty.beanNotFound=setProperty: Bean {0} not found -jsp.error.getproperty.beanNotFound=getProperty: Bean {0} not found -jsp.error.setproperty.ClassNotFound=setProperty: Class {0} not found -# typo ? -#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=* -jsp.error.setproperty.invalidSyntax=setProperty: can't have non-null value when property=* -jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo for bean {0} not found -jsp.error.setproperty.paramOrValue=setProperty: either param or value can be present -jsp.error.setproperty.arrayVal=setProperty: can't set array property {0} through a string constant value -jsp.warning.keepgen=Warning: Invalid value for the initParam keepgenerated. Will use the default value of \"false\" -jsp.warning.xpoweredBy=Warning: Invalid value for the initParam xpoweredBy. Will use the default value of \"false\" -jsp.warning.enablePooling=Warning: Invalid value for the initParam enablePooling. Will use the default value of \"true\" -jsp.warning.invalidTagPoolSize=Warning: Invalid value for the init parameter named tagPoolSize. Will use default size of {0} -jsp.warning.mappedFile=Warning: Invalid value for the initParam mappedFile. Will use the default value of \"false\" -jsp.warning.sendErrToClient=Warning: Invalid value for the initParam sendErrToClient. Will use the default value of \"false\" -jsp.warning.classDebugInfo=Warning: Invalid value for the initParam classdebuginfo. Will use the default value of \"false\" -jsp.warning.checkInterval=Warning: Invalid value for the initParam checkInterval. Will use the default value of \"300\" seconds -jsp.warning.modificationTestInterval=Warning: Invalid value for the initParam modificationTestInterval. Will use the default value of \"4\" seconds -jsp.warning.development=Warning: Invalid value for the initParam development. Will use the default value of \"true\" -jsp.warning.fork=Warning: Invalid value for the initParam fork. Will use the default value of \"true\" -jsp.warning.reloading=Warning: Invalid value for the initParam reloading. Will use the default value of \"true\" -jsp.warning.dumpSmap=Warning: Invalid value for the initParam dumpSmap. Will use the default value of \"false\" -jsp.warning.genchararray=Warning: Invalid value for the initParam genStrAsCharArray. Will use the default value of \"false\" -jsp.warning.suppressSmap=Warning: Invalid value for the initParam suppressSmap. Will use the default value of \"false\" -jsp.error.badtaglib=Unable to open taglibrary {0} : {1} -jsp.error.badGetReader=Cannot create a reader when the stream is not buffered -jsp.warning.unknown.element.in.taglib=Unknown element ({0}) in taglib -jsp.warning.unknown.element.in.tag=Unknown element ({0}) in tag -jsp.warning.unknown.element.in.tagfile=Unknown element ({0}) in tag-file -jsp.warning.unknown.element.in.attribute=Unknown element ({0}) in attribute -jsp.warning.unknown.element.in.variable=Unknown element ({0}) in variable -jsp.warning.unknown.element.in.validator=Unknown element ({0}) in validator -jsp.warning.unknown.element.in.initParam=Unknown element ({0}) in validator's init-param -jsp.warning.unknown.element.in.function=Unknown element ({0}) in function -jsp.error.more.than.one.taglib=More than one taglib in the TLD: {0} -jsp.error.teiclass.instantiation=Failed to load or instantiate TagExtraInfo class: {0} -jsp.error.non_null_tei_and_var_subelems=Tag {0} has one or more variable subelements and a TagExtraInfo class that returns one or more VariableInfo -jsp.error.parse.error.in.TLD=Parse Error in the tag library descriptor: {0} -jsp.error.unable.to.open.TLD=Unable to open the tag library descriptor: {0} -jsp.buffer.size.zero=Buffer size <= 0 -jsp.error.file.not.found=File \"{0}\" not found -jsp.message.copyinguri=Copying {0} into {1} -jsp.message.htmlcomment=\nStripping Comment: \t{0} -jsp.message.handling_directive=\nHandling Directive: {0}\t{1} -jsp.message.handling_plugin=\nPlugin: {0} -jsp.message.package_name_is=Package name is: {0} -jsp.message.class_name_is=Class name is: {0} -jsp.message.java_file_name_is=Java file name is: {0} -jsp.message.class_file_name_is=Class file name is: {0} -jsp.message.accepted=Accepted {0} at {1} -jsp.message.adding_jar=Adding jar {0} to my classpath -jsp.message.compiling_with=Compiling with: {0} -jsp.message.template_text=template text -jsp.error.missing_attribute=According to the TLD or the tag file, attribute {0} is mandatory for tag {1} -jsp.error.bad_attribute=Attribute {0} invalid for tag {1} according to TLD -jsp.error.tld.unable_to_read=Unable to read TLD \"{1}\" from JAR file \"{0}\": {2} -jsp.error.tld.unable_to_get_jar=Unable to get JAR resource \"{0}\" containing TLD: {1} -jsp.error.tld.missing_jar=Missing JAR resource \"{0}\" containing TLD -jsp.error.webxml_not_found=Could not locate web.xml -jsp.cmd_line.usage=Usage: jsptoservlet [-dd ] [-keepgenerated] \ -<.jsp files> -jsp.message.cp_is=Classpath {0} is: {1} -jsp.error.unable.to_load_taghandler_class=Unable to load tag handler class {0} because of {1} -jsp.error.unable.to_find_method=Unable to find setter method for attribute: {0} -jsp.error.unable.to_convert_string=Unable to convert a String to {0} for attribute {1} -jsp.error.unable.to_introspect=Unable to introspect on tag handler class: {0} because of {1} -jsp.error.bad_tag=No tag \"{0}\" defined in tag library imported with prefix \"{1}\" -jsp.error.xml.bad_tag=No tag \"{0}\" defined in tag library associated with uri \"{1}\" -jsp.error.bad_string_Character=Cannot extract a Character from a zero length array -jsp.error.bad_string_char=Cannot extract a char from a zero length array -jsp.warning.compiler.class.cantcreate=Can't create an instance of specified compiler plugin class {0} due to {1}. Will default to Sun Java Compiler. -jsp.warning.compiler.class.notfound=Specified compiler plugin class {0} not found. Will default to Sun Java Compiler. -jsp.warning.compiler.path.notfound=Specified compiler path {0} not found. Will default to system PATH. -jsp.error.jspc.uriroot_not_dir=The -uriroot option must specify a pre-existing directory -jsp.error.jspc.missingTarget=Missing target: Must specify -webapp or -uriroot, or one or more JSP pages -jsp.error.jspc.no_uriroot=The uriroot is not specified and cannot be located with the specified JSP file(s) -jspc.implicit.uriRoot=uriRoot implicitly set to "{0}" -jspc.usage=Usage: jspc [--] \n\ -where jsp files is\n\ -\ -webapp A directory containing a web-app, whose JSP pages\n\ -\ will be processed recursively\n\ -or any number of\n\ -\ A file to be parsed as a JSP page\n\ -where options include:\n\ -\ -help Print this help message\n\ -\ -v Verbose mode\n\ -\ -d Output Directory (default -Djava.io.tmpdir)\n\ -\ -l Outputs the name of the JSP page upon failure\n\ -\ -s Outputs the name of the JSP page upon success\n\ -\ -p Name of target package (default org.apache.jsp)\n\ -\ -c Name of target class name (only applies to first JSP page)\n\ -\ -mapped Generates separate write() calls for each HTML line in the JSP\n\ -\ -die[#] Generates an error return code (#) on fatal errors (default 1)\n\ -\ -uribase The uri directory compilations should be relative to\n\ -\ (default "/")\n\ -\ -uriroot Same as -webapp\n\ -\ -compile Compiles generated servlets\n\ -\ -webinc Creates a partial servlet mappings in the file\n\ -\ -webxml Creates a complete web.xml in the file\n\ -\ -ieplugin Java Plugin classid for Internet Explorer\n\ -\ -classpath Overrides java.class.path system property\n\ -\ -xpoweredBy Add X-Powered-By response header\n\ -\ -trimSpaces Trim spaces in template text between actions, directives\n\ -\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ -\ -source Set the -source argument to the compiler (default 1.4)\n\ -\ -target Set the -target argument to the compiler (default 1.4)\n\ - -jspc.webxml.header=\n\ -\n\ -\n\ -\n\ -\n\ -\n -jspc.webxml.footer=\n\ -\n\ -\n -jspc.webinc.header=\n\ -\n -jspc.webinc.footer=\n\ -\n -jspc.webinc.insertEnd= -jspc.webinc.insertStart= -jspc.error.jasperException=error-the file ''{0}'' generated the following parse exception: {1} -jspc.error.generalException=ERROR-the file ''{0}'' generated the following general exception: -jspc.error.fileDoesNotExist=The file argument ''{0}'' does not exist -jspc.error.emptyWebApp=-webapp requires a trailing file argument -jsp.error.library.invalid=JSP page is invalid according to library {0}: {1} -jsp.error.tlvclass.instantiation=Failed to load or instantiate TagLibraryValidator class: {0} -jsp.error.tlv.invalid.page=Validation error messages from TagLibraryValidator for {0} in {1} -jsp.error.tei.invalid.attributes=Validation error messages from TagExtraInfo for {0} -jsp.parser.sax.propertynotsupported=SAX property not supported: {0} -jsp.parser.sax.propertynotrecognized=SAX property not recognized: {0} -jsp.parser.sax.featurenotsupported=SAX feature not supported: {0} -jsp.parser.sax.featurenotrecognized=SAX feature not recognized: {0} -jsp.error.no.more.content=End of content reached while more parsing required: tag nesting error? -jsp.error.parse.xml=XML parsing error on file {0} -jsp.error.parse.xml.line=XML parsing error on file {0}: (line {1}, col {2}) -jsp.error.parse.xml.scripting.invalid.body=Body of {0} element must not contain any XML elements -jsp.error.internal.tldinit=Unable to initialize TldLocationsCache: {0} -jsp.error.internal.filenotfound=Internal Error: File {0} not found -jsp.error.internal.evaluator_not_found=Internal error: unable to load expression evaluator -jsp.error.parse.xml.invalidPublicId=Invalid PUBLIC ID: {0} -jsp.error.include.flush.invalid.value=Invalid value for the flush attribute: {0} -jsp.error.unsupported.encoding=Unsupported encoding: {0} -tld.error.variableNotAllowed=It is an error for a tag that has one or more variable subelements to have a TagExtraInfo class that returns a non-null object. -jsp.error.tldInWebDotXmlNotFound=Could not locate TLD {1} for URI {0} specified in web.xml -jsp.error.taglibDirective.absUriCannotBeResolved=The absolute uri: {0} cannot be resolved in either web.xml or the jar files deployed with this application -jsp.error.taglibDirective.missing.location=Neither \'uri\' nor \'tagdir\' attribute specified -jsp.error.taglibDirective.both_uri_and_tagdir=Both \'uri\' and \'tagdir\' attributes specified -jsp.error.invalid.tagdir=Tag file directory {0} does not start with \"/WEB-INF/tags\" -jsp.error.unterminated.user.tag=Unterminated user-defined tag: ending tag {0} not found or incorrectly nested -#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} -jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:text> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} -#Error while processing taglib jar file {0}: {1} -jsp.error.taglib.reserved.prefix=The taglib prefix {0} is reserved -jsp.error.invalid.javaEncoding=Invalid java encodings. Tried {0} and then {1}. Both failed. -jsp.error.needAlternateJavaEncoding=Default java encoding {0} is invalid on your java platform. An alternate can be specified via the 'javaEncoding' parameter of JspServlet. -#Error when compiling, used for jsp line number error messages -jsp.error.single.line.number=An error occurred at line: {0} in the jsp file: {1} -jsp.error.multiple.line.number=\n\nAn error occurred between lines: {0} and {1} in the jsp file: {2}\n\n -jsp.error.corresponding.servlet=Generated servlet error:\n -jsp.error.empty.body.not.allowed=Empty body not allowed for {0} -jsp.error.jspbody.required=Must use jsp:body to specify tag body for {0} if jsp:attribute is used. -jsp.error.jspbody.emptybody.only=The {0} tag can only have jsp:attribute in its body. -jsp.error.no.scriptlets=Scripting elements ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) are disallowed here. -jsp.error.internal.unexpected_node_type=Internal Error: Unexpected node type encountered -jsp.error.tld.fn.invalid.signature=Invalid syntax for function signature in TLD. Tag Library: {0}, Function: {1} -jsp.error.tld.fn.duplicate.name=Duplicate function name {0} in tag library {1} -jsp.error.tld.fn.invalid.signature.commaexpected=Invalid syntax for function signature in TLD. Comma ',' expected. Tag Library: {0}, Function: {1}. -jsp.error.tld.fn.invalid.signature.parenexpected=Invalid syntax for function signature in TLD. Parenthesis '(' expected. Tag Library: {0}, Function: {1}. -jsp.error.tld.mandatory.element.missing=Mandatory TLD element missing or empty: {0} -jsp.error.dynamic.attributes.not.implemented=The {0} tag declares that it accepts dynamic attributes but does not implement the required interface -jsp.error.nomatching.fragment=Cannot find an attribute directive (with name={0} and fragment=true) prior to the fragment directive. -jsp.error.attribute.noequal=equal symbol expected -jsp.error.attribute.noquote=quote symbol expected -jsp.error.attribute.unterminated=attribute for {0} is not properly terminated -jsp.error.missing.tagInfo=TagInfo object for {0} is missing from TLD -jsp.error.fragmentwithtype=Cannot specify both 'fragment' and 'type' attributes. If 'fragment' is present, 'type' is fixed as 'javax.servlet.jsp.tagext.JspFragment' -jsp.error.fragmentwithrtexprvalue=Cannot specify both 'fragment' and 'rtexprvalue' attributes. If 'fragment' is present, 'rtexprvalue' is fixed as 'true' -jsp.error.fragmentWithDeclareOrScope=Both 'fragment' and 'declare' or 'scope' attributes specified in variable directive -jsp.error.var_and_varReader=Only one of \'var\' or \'varReader\' may be specified -jsp.error.missing_var_or_varReader=Missing \'var\' or \'varReader\' attribute -jsp.warning.bad.urlpattern.propertygroup=Bad value {0} in the url-pattern subelement in web.xml -jsp.error.unknown_attribute_type=Unknown attribute type ({1}) for attribute {0}. -jsp.error.jspelement.missing.name=Mandatory XML-style \'name\' attribute missing -jsp.error.xmlns.redefinition.notimplemented=Internal error: Attempt to redefine xmlns:{0}. Redefinition of namespaces is not implemented. -jsp.error.could.not.add.taglibraries=Could not add one or more tag libraries. -jsp.error.duplicate.name.jspattribute=The attribute {0} specified in the standard or custom action also appears as the value of the name attribute in the enclosed jsp:attribute -jsp.error.not.in.template={0} not allowed in a template text body. -jsp.error.badStandardAction=Invalid standard action -jsp.error.xml.badStandardAction=Invalid standard action: {0} -jsp.error.tagdirective.badbodycontent=Invalid body-content ({0}) in tag directive -jsp.error.simpletag.badbodycontent=The TLD for the class {0} specifies an invalid body-content (JSP) for a SimpleTag. -jsp.error.config_pagedir_encoding_mismatch=Page-encoding specified in jsp-property-group ({0}) is different from that specified in page directive ({1}) -jsp.error.prolog_pagedir_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in page directive ({1}) -jsp.error.prolog_config_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in jsp-property-group ({1}) -jsp.error.attribute.custom.non_rt_with_expr=According to TLD or attribute directive in tag file, attribute {0} does not accept any expressions -jsp.error.attribute.standard.non_rt_with_expr=The {0} attribute of the {1} standard action does not accept any expressions -jsp.error.scripting.variable.missing_name=Unable to determine scripting variable name from attribute {0} -jasper.error.emptybodycontent.nonempty=According to TLD, tag {0} must be empty, but is not -jsp.error.tagfile.nameNotUnique=The value of {0} and the value of {1} in line {2} are the same. -jsp.error.tagfile.nameFrom.noAttribute=Cannot find an attribute directive with a name attribute with a value \"{0}\", the value of this name-from-attribute attribute. -jsp.error.tagfile.nameFrom.badAttribute=The attribute directive (declared in line {1} and whose name attribute is \"{0}\", the value of this name-from-attribute attribute) must be of type java.lang.String, is \"required\" and not a \"rtexprvalue\". -jsp.error.page.noSession=Cannot access session scope in page that does not participate in any session -jsp.error.usebean.noSession=Illegal for useBean to use session scope when JSP page declares (via page directive) that it does not participate in sessions -jsp.error.xml.encodingByteOrderUnsupported = Given byte order for encoding \"{0}\" is not supported. -jsp.error.xml.encodingDeclInvalid = Invalid encoding name \"{0}\". -jsp.error.xml.encodingDeclRequired = The encoding declaration is required in the text declaration. -jsp.error.xml.morePseudoAttributes = more pseudo attributes is expected. -jsp.error.xml.noMorePseudoAttributes = no more pseudo attributes is allowed. -jsp.error.xml.versionInfoRequired = The version is required in the XML declaration. -jsp.error.xml.xmlDeclUnterminated = The XML declaration must end with \"?>\". -jsp.error.xml.reservedPITarget = The processing instruction target matching \"[xX][mM][lL]\" is not allowed. -jsp.error.xml.spaceRequiredInPI = White space is required between the processing instruction target and data. -jsp.error.xml.invalidCharInContent = An invalid XML character (Unicode: 0x{0}) was found in the element content of the document. -jsp.error.xml.spaceRequiredBeforeStandalone = White space is required before the encoding pseudo attribute in the XML declaration. -jsp.error.xml.sdDeclInvalid = The standalone document declaration value must be \"yes\" or \"no\", not \"{0}\". -jsp.error.xml.invalidCharInPI = An invalid XML character (Unicode: 0x{0}) was found in the processing instruction. -jsp.error.xml.versionNotSupported = XML version \"{0}\" is not supported, only XML 1.0 is supported. -jsp.error.xml.pseudoAttrNameExpected = a pseudo attribute name is expected. -jsp.error.xml.expectedByte = Expected byte {0} of {1}-byte UTF-8 sequence. -jsp.error.xml.invalidByte = Invalid byte {0} of {1}-byte UTF-8 sequence. -jsp.error.xml.operationNotSupported = Operation \"{0}\" not supported by {1} reader. -jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}. -jsp.error.xml.invalidASCII = Byte \"{0}\" not 7-bit ASCII. -jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = White space is required before the encoding pseudo attribute in the XML declaration. -jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = White space is required before the encoding pseudo attribute in the text declaration. -jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = White space is required before the version pseudo attribute in the text declaration. -jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = White space is required before the version pseudo attribute in the XML declaration. -jsp.error.xml.eqRequiredInXMLDecl = The '' = '' character must follow \"{0}\" in the XML declaration. -jsp.error.xml.eqRequiredInTextDecl = The '' = '' character must follow \"{0}\" in the text declaration. -jsp.error.xml.quoteRequiredInTextDecl = The value following \"{0}\" in the text declaration must be a quoted string. -jsp.error.xml.quoteRequiredInXMLDecl = The value following \"{0}\" in the XML declaration must be a quoted string. -jsp.error.xml.invalidCharInTextDecl = An invalid XML character (Unicode: 0x{0}) was found in the text declaration. -jsp.error.xml.invalidCharInXMLDecl = An invalid XML character (Unicode: 0x{0}) was found in the XML declaration. -jsp.error.xml.closeQuoteMissingInTextDecl = closing quote in the value following \"{0}\" in the text declaration is missing. -jsp.error.xml.closeQuoteMissingInXMLDecl = closing quote in the value following \"{0}\" in the XML declaration is missing. -jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}. -jsp.error.multiple.jsp = Cannot have multiple specifications of -jsp.error.jspoutput.conflict=<jsp:output>: illegal to have multiple occurrences of \"{0}\" with different values (old: {1}, new: {2}) -jsp.error.jspoutput.doctypenamesystem=<jsp:output>: 'doctype-root-element' and 'doctype-system' attributes must appear together -jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: 'doctype-system' attribute must appear if 'doctype-public' attribute appears -jsp.error.jspoutput.nonemptybody=<jsp:output> must not have a body -jsp.error.jspoutput.invalidUse=<jsp:output> must not be used in standard syntax -jsp.error.attributes.not.allowed = {0} must not have any attributes -jsp.error.tagfile.badSuffix=Missing \".tag\" suffix in tag file path {0} -jsp.error.tagfile.illegalPath=Illegal tag file path: {0}, must start with \"/WEB-INF/tags\" or \"/META-INF/tags\" -jsp.error.plugin.wrongRootElement=Name of root element in {0} different from {1} -jsp.error.attribute.invalidPrefix=The attribute prefix {0} does not correspond to any imported tag library -jsp.error.nested.jspattribute=A jsp:attribute standard action cannot be nested within another jsp:attribute standard action -jsp.error.nested.jspbody=A jsp:body standard action cannot be nested within another jsp:body or jsp:attribute standard action -jsp.error.variable.either.name=Either name-given or name-from-attribute attribute must be specified in a variable directive -jsp.error.variable.both.name=Cannot specify both name-given or name-from-attribute attributes in a variable directive -jsp.error.variable.alias=Both or none of the name-from-attribute and alias attributes must be specified in a variable directive -jsp.error.attribute.null_name=Null attribute name -jsp.error.jsptext.badcontent=\'<\', when appears in the body of <jsp:text>, must be encapsulated within a CDATA -jsp.error.jsproot.version.invalid=Invalid version number: \"{0}\", must be \"1.2\" or \"2.0\" -jsp.error.noFunctionPrefix=The function {0} must be used with a prefix when a default namespace is not specified -jsp.error.noFunction=The function {0} cannot be located with the specified prefix -jsp.error.noFunctionMethod=Method \"{0}\" for function \"{1}\" not found in class \"{2}\" -jsp.error.function.classnotfound=The class {0} specified in TLD for the function {1} cannot be found: {2} -jsp.error.signature.classnotfound=The class {0} specified in the method signature in TLD for the function {1} cannot be found. {2} -jsp.error.text.has_subelement=<jsp:text> must not have any subelements -jsp.error.data.file.read=Error reading file \"{0}\" -jsp.error.prefix.refined=Attempt to redefine the prefix {0} to {1}, when it was already defined as {2} in the current scope. -jsp.error.nested_jsproot=Nested <jsp:root> -jsp.error.unbalanced.endtag=The end tag \"</{0}\" is unbalanced -jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid. -jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}. - -# JSP 2.1 -jsp.error.el.template.deferred=#{..} is not allowed in template text -jsp.error.el.parse={0} : {1} -jsp.error.page.invalid.deferredsyntaxallowedasliteral=Page directive: invalid value for deferredSyntaxAllowedAsLiteral -jsp.error.tag.invalid.deferredsyntaxallowedasliteral=Tag directive: invalid value for deferredSyntaxAllowedAsLiteral -jsp.error.page.conflict.deferredsyntaxallowedasliteral=Page directive: illegal to have multiple occurrences of 'deferredSyntaxAllowedAsLiteral' with different values (old: {0}, new: {1}) -jsp.error.tag.conflict.deferredsyntaxallowedasliteral=Tag directive: illegal to have multiple occurrences of 'deferredSyntaxAllowedAsLiteral' with different values (old: {0}, new: {1}) - -jsp.error.page.invalid.trimdirectivewhitespaces=Page directive: invalid value for trimDirectiveWhitespaces -jsp.error.tag.invalid.trimdirectivewhitespaces=Tag directive: invalid value for trimDirectiveWhitespaces -jsp.error.page.conflict.trimdirectivewhitespaces=Page directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1}) +# $Id: LocalStrings.properties 379417 2006-02-21 10:57:35Z remm $ +# +# Default localized string information +# Localized this the Default Locale as is en_US + +jsp.error.compiler=No Java compiler available +jsp.error.bad.servlet.engine=Incorrect servlet engine version! +jsp.error.no.scratch.dir=The JSP engine is not configured with a scratch dir.\ +\n Please add \"jsp.initparams=scratchdir=\" \ +\n in the servlets.properties file for this context. +jsp.error.bad.scratch.dir=The scratchDir you specified: {0} is unusable. +jsp.message.scratch.dir.is=Scratch dir for the JSP engine is: {0} +jsp.message.parent_class_loader_is=Parent class loader is: {0} +jsp.message.dont.modify.servlets=IMPORTANT: Do not modify the generated servlets +jsp.error.not.impl.comments=Internal error: Comments not implemented +jsp.error.not.impl.directives=Internal error: Directives not implemented +jsp.error.not.impl.declarations=Internal error: Declarations not implemented +jsp.error.not.impl.expressions=Internal error: Expressions not implemented +jsp.error.not.impl.scriptlets=Internal error: Scriptlets not implemented +jsp.error.not.impl.usebean=Internal error: useBean not implemented +jsp.error.not.impl.getp=Internal error: getProperty not implemented +jsp.error.not.impl.setp=Internal error: setProperty not implemented +jsp.error.not.impl.plugin=Internal error: plugin not implemented +jsp.error.not.impl.forward=Internal error: forward not implemented +jsp.error.not.impl.include=Internal error: include not implemented +jsp.error.unavailable=JSP has been marked unavailable +jsp.error.usebean.missing.attribute=useBean: id attribute missing or misspelled +jsp.error.usebean.missing.type=useBean ({0}): Either class or type attribute must be \ +specified: +jsp.error.usebean.duplicate=useBean: Duplicate bean name: {0} +jsp.error.usebean.prohibited.as.session=Can't use as session bean {0} since it is prohibited \ +by jsp directive defined earlier: +jsp.error.usebean.not.both=useBean: Can't specify both class and beanName attribute: +jsp.error.usebean.bad.type.cast=useBean ({0}): Type ({1}) is not assignable from class ({2}) +jsp.error.invalid.scope=Illegal value of \'scope\' attribute: {0} (must be one of \"page\", \"request\", \"session\", or \"application\") +jsp.error.classname=Can't determine classname from .class file +jsp.warning.bad.type=Warning: bad type in .class file +jsp.error.data.file.write=Error while writing data file +jsp.error.page.invalid.buffer=Page directive: invalid buffer size +jsp.error.page.conflict.contenttype=Page directive: illegal to have multiple occurrences of 'contentType' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.contenttype=Page directive: invalid value for contentType +jsp.error.page.conflict.session=Page directive: illegal to have multiple occurrences of 'session' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.session=Page directive: invalid value for session +jsp.error.page.conflict.buffer=Page directive: illegal to have multiple occurrences of 'buffer' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.buffer=Page directive: invalid value for buffer +jsp.error.page.conflict.autoflush=Page directive: illegal to have multiple occurrences of 'autoFlush' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.autoflush=Page directive: invalid value for autoFlush +jsp.error.page.conflict.isthreadsafe=Page directive: illegal to have multiple occurrences of 'isThreadSafe' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.isthreadsafe=Page directive: invalid value for isThreadSafe +jsp.error.page.conflict.info=Page directive: illegal to have multiple occurrences of 'info' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.info=Page directive: invalid value for info +jsp.error.page.conflict.iserrorpage=Page directive: illegal to have multiple occurrences of 'isErrorPage' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.iserrorpage=Page directive: invalid value for isErrorPage +jsp.error.page.conflict.errorpage=Page directive: illegal to have multiple occurrences of 'errorPage' with different values (old: {0}, new: {1}) +jsp.error.page.conflict.language=Page directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1}) +jsp.error.tag.conflict.language=Tag directive: illegal to have multiple occurrences of 'language' with different values (old: {0}, new: {1}) +jsp.error.page.language.nonjava=Page directive: invalid language attribute +jsp.error.tag.language.nonjava=Tag directive: invalid language attribute +jsp.error.page.defafteruse.language=Page directive: can't define language after a scriptlet +jsp.error.page.nomapping.language=Page directive: No mapping for language: +jsp.error.page.conflict.extends=Page directive: illegal to have multiple occurrences of 'extends' with different values (old: {0}, new: {1}) +jsp.error.page.conflict.iselignored=Page directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1}) +jsp.error.tag.conflict.iselignored=Tag directive: illegal to have multiple occurrences of 'isELIgnored' with different values (old: {0}, new: {1}) +jsp.error.page.invalid.iselignored=Page directive: invalid value for isELIgnored +jsp.error.tag.invalid.iselignored=Tag directive: invalid value for isELIgnored +jsp.error.page.multi.pageencoding=Page directive must not have multiple occurrences of pageencoding +jsp.error.tag.conflict.attr=Tag directive: illegal to have multiple occurrences of the attribute \"{0}\" with different values (old: {1}, new: {2}) +jsp.error.tag.multi.pageencoding=Tag directive must not have multiple occurrences of pageencoding +jsp.error.page.bad_b_and_a_combo=Page directive: Illegal combination of buffer=\"none\" && autoFlush=\"false\" +jsp.error.not.impl.taglib=Internal error: Tag extensions not implemented +jsp.error.include.missing.file=Missing file argument to include +jsp.error.include.bad.file=Bad file argument to include +jsp.error.include.exception=Unable to include {0} +jsp.error.stream.closed=Stream closed +jsp.error.invalid.forward=Invalid forward tag +jsp.error.unknownException=Unhandled error! You might want to consider having an error page \ +to report such errors more gracefully +jsp.error.invalid.directive=Invalid directive +jsp.error.directive.istagfile={0} directive cannot be used in a tag file +jsp.error.directive.isnottagfile={0} directive can only be used in a tag file +jsp.error.tagfile.tld.name=The \"name\" attribute of the tag directive has a value {0} while the \"name\" tag of the \"tag-file\" element in the TLD is {1} +jsp.error.action.istagfile={0} action cannot be used in a tag file +jsp.error.action.isnottagfile={0} action can be used in tag files only +jsp.error.unterminated=Unterminated {0} tag +jsp.error.usebean.notinsamefile=useBean tag must begin and end in the same physical file +jsp.error.loadclass.taghandler=Unable to load tag handler class \"{0}\" for tag \"{1}\" +jsp.error.unable.compile=Unable to compile class for JSP +jsp.error.unable.load=Unable to load class for JSP +jsp.error.unable.rename=Unable to rename class file {0} to {1} +jsp.error.mandatory.attribute={0}: Mandatory attribute {1} missing +jsp.engine.info=Jasper JSP 2.0 Engine +jsp.error.invalid.expression="{0}" contains invalid expression(s): {1} +jsp.error.invalid.attribute={0} has invalid attribute: {1} +jsp.error.usebean.class.notfound=Class: {0} not found +jsp.error.file.cannot.read=Cannot read file: {0} +jsp.error.file.already.registered=Recursive include of file {0} +jsp.error.file.not.registered=file {0} not seen in include +jsp.error.quotes.unterminated=Unterminated quotes +jsp.error.attr.quoted=Attribute value should be quoted +jsp.error.attr.novalue=Attribute {0} has no value +jsp.error.tag.attr.unterminated=Unterminated tag attribute list +jsp.error.param.noname=No name in PARAM tag +jsp.error.param.novalue=No value in PARAM tag +jsp.error.beans.nullbean=Attempted a bean operation on a null object. +jsp.error.beans.nobeaninfo=No BeanInfo for the bean of type ''{0}'' could be found, the class likely does not exist. +jsp.error.beans.introspection=An exception occurred while introspecting the read method of property ''{0}'' in a bean of type ''{1}'':\n{2} +jsp.error.beans.nomethod=Cannot find a method to read property ''{0}'' in a bean of type ''{1}'' +jsp.error.beans.nomethod.setproperty=Can''t find a method to write property ''{0}'' of type ''{1}'' in a bean of type ''{2}'' +jsp.error.beans.noproperty=Cannot find any information on property ''{0}'' in a bean of type ''{1}'' +jsp.error.beans.setproperty.noindexset=Cannot set indexed property +jsp.error.include.tag=Invalid jsp:include tag +jsp.error.include.noflush=jsp:include needs to have \"flush=true\" +jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" is the only valid combination in JSP 1.0 +jsp.error.attempt_to_clear_flushed_buffer=Error: Attempt to clear a buffer that's already been flushed +jsp.error.overflow=Error: JSP Buffer overflow +jsp.error.paramexpected=Expecting \"jsp:param\" standard action with \"name\" and \"value\" attributes +jsp.error.param.invalidUse=The jsp:param action must not be used outside the jsp:include, jsp:forward, or jsp:params elements +jsp.error.params.invalidUse=jsp:params must be a direct child of jsp:plugin +jsp.error.fallback.invalidUse=jsp:fallback must be a direct child of jsp:plugin +jsp.error.namedAttribute.invalidUse=jsp:attribute must be the subelement of a standard or custom action +jsp.error.jspbody.invalidUse=jsp:body must be the subelement of a standard or custom action +jsp.error.closeindividualparam=param tag needs to be closed with \"/>\" +jsp.error.closeparams=param tag needs to be closed with /params +jsp.error.params.emptyBody=jsp:params must contain at least one nested jsp:param +jsp.error.params.illegalChild=jsp:params must not have any nested elements other than jsp:param +jsp.error.plugin.notype=type not declared in jsp:plugin +jsp.error.plugin.badtype=Illegal value for 'type' attribute in jsp:plugin: must be 'bean' or 'applet' +jsp.error.plugin.nocode=code not declared in jsp:plugin +jsp.error.ise_on_clear=Illegal to clear() when buffer size == 0 +jsp.error.setproperty.beanNotFound=setProperty: Bean {0} not found +jsp.error.getproperty.beanNotFound=getProperty: Bean {0} not found +jsp.error.setproperty.ClassNotFound=setProperty: Class {0} not found +# typo ? +#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=* +jsp.error.setproperty.invalidSyntax=setProperty: can't have non-null value when property=* +jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo for bean {0} not found +jsp.error.setproperty.paramOrValue=setProperty: either param or value can be present +jsp.error.setproperty.arrayVal=setProperty: can't set array property {0} through a string constant value +jsp.warning.keepgen=Warning: Invalid value for the initParam keepgenerated. Will use the default value of \"false\" +jsp.warning.xpoweredBy=Warning: Invalid value for the initParam xpoweredBy. Will use the default value of \"false\" +jsp.warning.enablePooling=Warning: Invalid value for the initParam enablePooling. Will use the default value of \"true\" +jsp.warning.invalidTagPoolSize=Warning: Invalid value for the init parameter named tagPoolSize. Will use default size of {0} +jsp.warning.mappedFile=Warning: Invalid value for the initParam mappedFile. Will use the default value of \"false\" +jsp.warning.sendErrToClient=Warning: Invalid value for the initParam sendErrToClient. Will use the default value of \"false\" +jsp.warning.classDebugInfo=Warning: Invalid value for the initParam classdebuginfo. Will use the default value of \"false\" +jsp.warning.checkInterval=Warning: Invalid value for the initParam checkInterval. Will use the default value of \"300\" seconds +jsp.warning.modificationTestInterval=Warning: Invalid value for the initParam modificationTestInterval. Will use the default value of \"4\" seconds +jsp.warning.development=Warning: Invalid value for the initParam development. Will use the default value of \"true\" +jsp.warning.fork=Warning: Invalid value for the initParam fork. Will use the default value of \"true\" +jsp.warning.reloading=Warning: Invalid value for the initParam reloading. Will use the default value of \"true\" +jsp.warning.dumpSmap=Warning: Invalid value for the initParam dumpSmap. Will use the default value of \"false\" +jsp.warning.genchararray=Warning: Invalid value for the initParam genStrAsCharArray. Will use the default value of \"false\" +jsp.warning.suppressSmap=Warning: Invalid value for the initParam suppressSmap. Will use the default value of \"false\" +jsp.error.badtaglib=Unable to open taglibrary {0} : {1} +jsp.error.badGetReader=Cannot create a reader when the stream is not buffered +jsp.warning.unknown.element.in.taglib=Unknown element ({0}) in taglib +jsp.warning.unknown.element.in.tag=Unknown element ({0}) in tag +jsp.warning.unknown.element.in.tagfile=Unknown element ({0}) in tag-file +jsp.warning.unknown.element.in.attribute=Unknown element ({0}) in attribute +jsp.warning.unknown.element.in.variable=Unknown element ({0}) in variable +jsp.warning.unknown.element.in.validator=Unknown element ({0}) in validator +jsp.warning.unknown.element.in.initParam=Unknown element ({0}) in validator's init-param +jsp.warning.unknown.element.in.function=Unknown element ({0}) in function +jsp.error.more.than.one.taglib=More than one taglib in the TLD: {0} +jsp.error.teiclass.instantiation=Failed to load or instantiate TagExtraInfo class: {0} +jsp.error.non_null_tei_and_var_subelems=Tag {0} has one or more variable subelements and a TagExtraInfo class that returns one or more VariableInfo +jsp.error.parse.error.in.TLD=Parse Error in the tag library descriptor: {0} +jsp.error.unable.to.open.TLD=Unable to open the tag library descriptor: {0} +jsp.buffer.size.zero=Buffer size <= 0 +jsp.error.file.not.found=File \"{0}\" not found +jsp.message.copyinguri=Copying {0} into {1} +jsp.message.htmlcomment=\nStripping Comment: \t{0} +jsp.message.handling_directive=\nHandling Directive: {0}\t{1} +jsp.message.handling_plugin=\nPlugin: {0} +jsp.message.package_name_is=Package name is: {0} +jsp.message.class_name_is=Class name is: {0} +jsp.message.java_file_name_is=Java file name is: {0} +jsp.message.class_file_name_is=Class file name is: {0} +jsp.message.accepted=Accepted {0} at {1} +jsp.message.adding_jar=Adding jar {0} to my classpath +jsp.message.compiling_with=Compiling with: {0} +jsp.message.template_text=template text +jsp.error.missing_attribute=According to the TLD or the tag file, attribute {0} is mandatory for tag {1} +jsp.error.bad_attribute=Attribute {0} invalid for tag {1} according to TLD +jsp.error.tld.unable_to_read=Unable to read TLD \"{1}\" from JAR file \"{0}\": {2} +jsp.error.tld.unable_to_get_jar=Unable to get JAR resource \"{0}\" containing TLD: {1} +jsp.error.tld.missing_jar=Missing JAR resource \"{0}\" containing TLD +jsp.error.webxml_not_found=Could not locate web.xml +jsp.cmd_line.usage=Usage: jsptoservlet [-dd ] [-keepgenerated] \ +<.jsp files> +jsp.message.cp_is=Classpath {0} is: {1} +jsp.error.unable.to_load_taghandler_class=Unable to load tag handler class {0} because of {1} +jsp.error.unable.to_find_method=Unable to find setter method for attribute: {0} +jsp.error.unable.to_convert_string=Unable to convert a String to {0} for attribute {1} +jsp.error.unable.to_introspect=Unable to introspect on tag handler class: {0} because of {1} +jsp.error.bad_tag=No tag \"{0}\" defined in tag library imported with prefix \"{1}\" +jsp.error.xml.bad_tag=No tag \"{0}\" defined in tag library associated with uri \"{1}\" +jsp.error.bad_string_Character=Cannot extract a Character from a zero length array +jsp.error.bad_string_char=Cannot extract a char from a zero length array +jsp.warning.compiler.class.cantcreate=Can't create an instance of specified compiler plugin class {0} due to {1}. Will default to Sun Java Compiler. +jsp.warning.compiler.class.notfound=Specified compiler plugin class {0} not found. Will default to Sun Java Compiler. +jsp.warning.compiler.path.notfound=Specified compiler path {0} not found. Will default to system PATH. +jsp.error.jspc.uriroot_not_dir=The -uriroot option must specify a pre-existing directory +jsp.error.jspc.missingTarget=Missing target: Must specify -webapp or -uriroot, or one or more JSP pages +jsp.error.jspc.no_uriroot=The uriroot is not specified and cannot be located with the specified JSP file(s) +jspc.implicit.uriRoot=uriRoot implicitly set to "{0}" +jspc.usage=Usage: jspc [--] \n\ +where jsp files is\n\ +\ -webapp A directory containing a web-app, whose JSP pages\n\ +\ will be processed recursively\n\ +or any number of\n\ +\ A file to be parsed as a JSP page\n\ +where options include:\n\ +\ -help Print this help message\n\ +\ -v Verbose mode\n\ +\ -d Output Directory (default -Djava.io.tmpdir)\n\ +\ -l Outputs the name of the JSP page upon failure\n\ +\ -s Outputs the name of the JSP page upon success\n\ +\ -p Name of target package (default org.apache.jsp)\n\ +\ -c Name of target class name (only applies to first JSP page)\n\ +\ -mapped Generates separate write() calls for each HTML line in the JSP\n\ +\ -die[#] Generates an error return code (#) on fatal errors (default 1)\n\ +\ -uribase The uri directory compilations should be relative to\n\ +\ (default "/")\n\ +\ -uriroot Same as -webapp\n\ +\ -compile Compiles generated servlets\n\ +\ -webinc Creates a partial servlet mappings in the file\n\ +\ -webxml Creates a complete web.xml in the file\n\ +\ -ieplugin Java Plugin classid for Internet Explorer\n\ +\ -classpath Overrides java.class.path system property\n\ +\ -xpoweredBy Add X-Powered-By response header\n\ +\ -trimSpaces Trim spaces in template text between actions, directives\n\ +\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ +\ -source Set the -source argument to the compiler (default 1.4)\n\ +\ -target Set the -target argument to the compiler (default 1.4)\n\ + +jspc.webxml.header=\n\ +\n\ +\n\ +\n\ +\n\ +\n +jspc.webxml.footer=\n\ +\n\ +\n +jspc.webinc.header=\n\ +\n +jspc.webinc.footer=\n\ +\n +jspc.webinc.insertEnd= +jspc.webinc.insertStart= +jspc.error.jasperException=error-the file ''{0}'' generated the following parse exception: {1} +jspc.error.generalException=ERROR-the file ''{0}'' generated the following general exception: +jspc.error.fileDoesNotExist=The file argument ''{0}'' does not exist +jspc.error.emptyWebApp=-webapp requires a trailing file argument +jsp.error.library.invalid=JSP page is invalid according to library {0}: {1} +jsp.error.tlvclass.instantiation=Failed to load or instantiate TagLibraryValidator class: {0} +jsp.error.tlv.invalid.page=Validation error messages from TagLibraryValidator for {0} in {1} +jsp.error.tei.invalid.attributes=Validation error messages from TagExtraInfo for {0} +jsp.parser.sax.propertynotsupported=SAX property not supported: {0} +jsp.parser.sax.propertynotrecognized=SAX property not recognized: {0} +jsp.parser.sax.featurenotsupported=SAX feature not supported: {0} +jsp.parser.sax.featurenotrecognized=SAX feature not recognized: {0} +jsp.error.no.more.content=End of content reached while more parsing required: tag nesting error? +jsp.error.parse.xml=XML parsing error on file {0} +jsp.error.parse.xml.line=XML parsing error on file {0}: (line {1}, col {2}) +jsp.error.parse.xml.scripting.invalid.body=Body of {0} element must not contain any XML elements +jsp.error.internal.tldinit=Unable to initialize TldLocationsCache: {0} +jsp.error.internal.filenotfound=Internal Error: File {0} not found +jsp.error.internal.evaluator_not_found=Internal error: unable to load expression evaluator +jsp.error.parse.xml.invalidPublicId=Invalid PUBLIC ID: {0} +jsp.error.include.flush.invalid.value=Invalid value for the flush attribute: {0} +jsp.error.unsupported.encoding=Unsupported encoding: {0} +tld.error.variableNotAllowed=It is an error for a tag that has one or more variable subelements to have a TagExtraInfo class that returns a non-null object. +jsp.error.tldInWebDotXmlNotFound=Could not locate TLD {1} for URI {0} specified in web.xml +jsp.error.taglibDirective.absUriCannotBeResolved=The absolute uri: {0} cannot be resolved in either web.xml or the jar files deployed with this application +jsp.error.taglibDirective.missing.location=Neither \'uri\' nor \'tagdir\' attribute specified +jsp.error.taglibDirective.both_uri_and_tagdir=Both \'uri\' and \'tagdir\' attributes specified +jsp.error.invalid.tagdir=Tag file directory {0} does not start with \"/WEB-INF/tags\" +jsp.error.unterminated.user.tag=Unterminated user-defined tag: ending tag {0} not found or incorrectly nested +#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} +jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:text> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} +#Error while processing taglib jar file {0}: {1} +jsp.error.taglib.reserved.prefix=The taglib prefix {0} is reserved +jsp.error.invalid.javaEncoding=Invalid java encodings. Tried {0} and then {1}. Both failed. +jsp.error.needAlternateJavaEncoding=Default java encoding {0} is invalid on your java platform. An alternate can be specified via the 'javaEncoding' parameter of JspServlet. +#Error when compiling, used for jsp line number error messages +jsp.error.single.line.number=An error occurred at line: {0} in the jsp file: {1} +jsp.error.multiple.line.number=\n\nAn error occurred between lines: {0} and {1} in the jsp file: {2}\n\n +jsp.error.corresponding.servlet=Generated servlet error:\n +jsp.error.empty.body.not.allowed=Empty body not allowed for {0} +jsp.error.jspbody.required=Must use jsp:body to specify tag body for {0} if jsp:attribute is used. +jsp.error.jspbody.emptybody.only=The {0} tag can only have jsp:attribute in its body. +jsp.error.no.scriptlets=Scripting elements ( <%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) are disallowed here. +jsp.error.internal.unexpected_node_type=Internal Error: Unexpected node type encountered +jsp.error.tld.fn.invalid.signature=Invalid syntax for function signature in TLD. Tag Library: {0}, Function: {1} +jsp.error.tld.fn.duplicate.name=Duplicate function name {0} in tag library {1} +jsp.error.tld.fn.invalid.signature.commaexpected=Invalid syntax for function signature in TLD. Comma ',' expected. Tag Library: {0}, Function: {1}. +jsp.error.tld.fn.invalid.signature.parenexpected=Invalid syntax for function signature in TLD. Parenthesis '(' expected. Tag Library: {0}, Function: {1}. +jsp.error.tld.mandatory.element.missing=Mandatory TLD element missing or empty: {0} +jsp.error.dynamic.attributes.not.implemented=The {0} tag declares that it accepts dynamic attributes but does not implement the required interface +jsp.error.nomatching.fragment=Cannot find an attribute directive (with name={0} and fragment=true) prior to the fragment directive. +jsp.error.attribute.noequal=equal symbol expected +jsp.error.attribute.noquote=quote symbol expected +jsp.error.attribute.unterminated=attribute for {0} is not properly terminated +jsp.error.missing.tagInfo=TagInfo object for {0} is missing from TLD +jsp.error.fragmentwithtype=Cannot specify both 'fragment' and 'type' attributes. If 'fragment' is present, 'type' is fixed as 'javax.servlet.jsp.tagext.JspFragment' +jsp.error.fragmentwithrtexprvalue=Cannot specify both 'fragment' and 'rtexprvalue' attributes. If 'fragment' is present, 'rtexprvalue' is fixed as 'true' +jsp.error.fragmentWithDeclareOrScope=Both 'fragment' and 'declare' or 'scope' attributes specified in variable directive +jsp.error.var_and_varReader=Only one of \'var\' or \'varReader\' may be specified +jsp.error.missing_var_or_varReader=Missing \'var\' or \'varReader\' attribute +jsp.warning.bad.urlpattern.propertygroup=Bad value {0} in the url-pattern subelement in web.xml +jsp.error.unknown_attribute_type=Unknown attribute type ({1}) for attribute {0}. +jsp.error.jspelement.missing.name=Mandatory XML-style \'name\' attribute missing +jsp.error.xmlns.redefinition.notimplemented=Internal error: Attempt to redefine xmlns:{0}. Redefinition of namespaces is not implemented. +jsp.error.could.not.add.taglibraries=Could not add one or more tag libraries. +jsp.error.duplicate.name.jspattribute=The attribute {0} specified in the standard or custom action also appears as the value of the name attribute in the enclosed jsp:attribute +jsp.error.not.in.template={0} not allowed in a template text body. +jsp.error.badStandardAction=Invalid standard action +jsp.error.xml.badStandardAction=Invalid standard action: {0} +jsp.error.tagdirective.badbodycontent=Invalid body-content ({0}) in tag directive +jsp.error.simpletag.badbodycontent=The TLD for the class {0} specifies an invalid body-content (JSP) for a SimpleTag. +jsp.error.config_pagedir_encoding_mismatch=Page-encoding specified in jsp-property-group ({0}) is different from that specified in page directive ({1}) +jsp.error.prolog_pagedir_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in page directive ({1}) +jsp.error.prolog_config_encoding_mismatch=Page-encoding specified in XML prolog ({0}) is different from that specified in jsp-property-group ({1}) +jsp.error.attribute.custom.non_rt_with_expr=According to TLD or attribute directive in tag file, attribute {0} does not accept any expressions +jsp.error.attribute.standard.non_rt_with_expr=The {0} attribute of the {1} standard action does not accept any expressions +jsp.error.scripting.variable.missing_name=Unable to determine scripting variable name from attribute {0} +jasper.error.emptybodycontent.nonempty=According to TLD, tag {0} must be empty, but is not +jsp.error.tagfile.nameNotUnique=The value of {0} and the value of {1} in line {2} are the same. +jsp.error.tagfile.nameFrom.noAttribute=Cannot find an attribute directive with a name attribute with a value \"{0}\", the value of this name-from-attribute attribute. +jsp.error.tagfile.nameFrom.badAttribute=The attribute directive (declared in line {1} and whose name attribute is \"{0}\", the value of this name-from-attribute attribute) must be of type java.lang.String, is \"required\" and not a \"rtexprvalue\". +jsp.error.page.noSession=Cannot access session scope in page that does not participate in any session +jsp.error.usebean.noSession=Illegal for useBean to use session scope when JSP page declares (via page directive) that it does not participate in sessions +jsp.error.xml.encodingByteOrderUnsupported = Given byte order for encoding \"{0}\" is not supported. +jsp.error.xml.encodingDeclInvalid = Invalid encoding name \"{0}\". +jsp.error.xml.encodingDeclRequired = The encoding declaration is required in the text declaration. +jsp.error.xml.morePseudoAttributes = more pseudo attributes is expected. +jsp.error.xml.noMorePseudoAttributes = no more pseudo attributes is allowed. +jsp.error.xml.versionInfoRequired = The version is required in the XML declaration. +jsp.error.xml.xmlDeclUnterminated = The XML declaration must end with \"?>\". +jsp.error.xml.reservedPITarget = The processing instruction target matching \"[xX][mM][lL]\" is not allowed. +jsp.error.xml.spaceRequiredInPI = White space is required between the processing instruction target and data. +jsp.error.xml.invalidCharInContent = An invalid XML character (Unicode: 0x{0}) was found in the element content of the document. +jsp.error.xml.spaceRequiredBeforeStandalone = White space is required before the encoding pseudo attribute in the XML declaration. +jsp.error.xml.sdDeclInvalid = The standalone document declaration value must be \"yes\" or \"no\", not \"{0}\". +jsp.error.xml.invalidCharInPI = An invalid XML character (Unicode: 0x{0}) was found in the processing instruction. +jsp.error.xml.versionNotSupported = XML version \"{0}\" is not supported, only XML 1.0 is supported. +jsp.error.xml.pseudoAttrNameExpected = a pseudo attribute name is expected. +jsp.error.xml.expectedByte = Expected byte {0} of {1}-byte UTF-8 sequence. +jsp.error.xml.invalidByte = Invalid byte {0} of {1}-byte UTF-8 sequence. +jsp.error.xml.operationNotSupported = Operation \"{0}\" not supported by {1} reader. +jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}. +jsp.error.xml.invalidASCII = Byte \"{0}\" not 7-bit ASCII. +jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = White space is required before the encoding pseudo attribute in the XML declaration. +jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = White space is required before the encoding pseudo attribute in the text declaration. +jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = White space is required before the version pseudo attribute in the text declaration. +jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = White space is required before the version pseudo attribute in the XML declaration. +jsp.error.xml.eqRequiredInXMLDecl = The '' = '' character must follow \"{0}\" in the XML declaration. +jsp.error.xml.eqRequiredInTextDecl = The '' = '' character must follow \"{0}\" in the text declaration. +jsp.error.xml.quoteRequiredInTextDecl = The value following \"{0}\" in the text declaration must be a quoted string. +jsp.error.xml.quoteRequiredInXMLDecl = The value following \"{0}\" in the XML declaration must be a quoted string. +jsp.error.xml.invalidCharInTextDecl = An invalid XML character (Unicode: 0x{0}) was found in the text declaration. +jsp.error.xml.invalidCharInXMLDecl = An invalid XML character (Unicode: 0x{0}) was found in the XML declaration. +jsp.error.xml.closeQuoteMissingInTextDecl = closing quote in the value following \"{0}\" in the text declaration is missing. +jsp.error.xml.closeQuoteMissingInXMLDecl = closing quote in the value following \"{0}\" in the XML declaration is missing. +jsp.error.xml.invalidHighSurrogate = High surrogate bits in UTF-8 sequence must not exceed 0x10 but found 0x{0}. +jsp.error.multiple.jsp = Cannot have multiple specifications of +jsp.error.jspoutput.conflict=<jsp:output>: illegal to have multiple occurrences of \"{0}\" with different values (old: {1}, new: {2}) +jsp.error.jspoutput.doctypenamesystem=<jsp:output>: 'doctype-root-element' and 'doctype-system' attributes must appear together +jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: 'doctype-system' attribute must appear if 'doctype-public' attribute appears +jsp.error.jspoutput.nonemptybody=<jsp:output> must not have a body +jsp.error.jspoutput.invalidUse=<jsp:output> must not be used in standard syntax +jsp.error.attributes.not.allowed = {0} must not have any attributes +jsp.error.tagfile.badSuffix=Missing \".tag\" suffix in tag file path {0} +jsp.error.tagfile.illegalPath=Illegal tag file path: {0}, must start with \"/WEB-INF/tags\" or \"/META-INF/tags\" +jsp.error.plugin.wrongRootElement=Name of root element in {0} different from {1} +jsp.error.attribute.invalidPrefix=The attribute prefix {0} does not correspond to any imported tag library +jsp.error.nested.jspattribute=A jsp:attribute standard action cannot be nested within another jsp:attribute standard action +jsp.error.nested.jspbody=A jsp:body standard action cannot be nested within another jsp:body or jsp:attribute standard action +jsp.error.variable.either.name=Either name-given or name-from-attribute attribute must be specified in a variable directive +jsp.error.variable.both.name=Cannot specify both name-given or name-from-attribute attributes in a variable directive +jsp.error.variable.alias=Both or none of the name-from-attribute and alias attributes must be specified in a variable directive +jsp.error.attribute.null_name=Null attribute name +jsp.error.jsptext.badcontent=\'<\', when appears in the body of <jsp:text>, must be encapsulated within a CDATA +jsp.error.jsproot.version.invalid=Invalid version number: \"{0}\", must be \"1.2\" or \"2.0\" +jsp.error.noFunctionPrefix=The function {0} must be used with a prefix when a default namespace is not specified +jsp.error.noFunction=The function {0} cannot be located with the specified prefix +jsp.error.noFunctionMethod=Method \"{0}\" for function \"{1}\" not found in class \"{2}\" +jsp.error.function.classnotfound=The class {0} specified in TLD for the function {1} cannot be found: {2} +jsp.error.signature.classnotfound=The class {0} specified in the method signature in TLD for the function {1} cannot be found. {2} +jsp.error.text.has_subelement=<jsp:text> must not have any subelements +jsp.error.data.file.read=Error reading file \"{0}\" +jsp.error.prefix.refined=Attempt to redefine the prefix {0} to {1}, when it was already defined as {2} in the current scope. +jsp.error.nested_jsproot=Nested <jsp:root> +jsp.error.unbalanced.endtag=The end tag \"</{0}\" is unbalanced +jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid. +jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}. + +# JSP 2.1 +jsp.error.el.template.deferred=#{..} is not allowed in template text +jsp.error.el.parse={0} : {1} +jsp.error.page.invalid.deferredsyntaxallowedasliteral=Page directive: invalid value for deferredSyntaxAllowedAsLiteral +jsp.error.tag.invalid.deferredsyntaxallowedasliteral=Tag directive: invalid value for deferredSyntaxAllowedAsLiteral +jsp.error.page.conflict.deferredsyntaxallowedasliteral=Page directive: illegal to have multiple occurrences of 'deferredSyntaxAllowedAsLiteral' with different values (old: {0}, new: {1}) +jsp.error.tag.conflict.deferredsyntaxallowedasliteral=Tag directive: illegal to have multiple occurrences of 'deferredSyntaxAllowedAsLiteral' with different values (old: {0}, new: {1}) + +jsp.error.page.invalid.trimdirectivewhitespaces=Page directive: invalid value for trimDirectiveWhitespaces +jsp.error.tag.invalid.trimdirectivewhitespaces=Tag directive: invalid value for trimDirectiveWhitespaces +jsp.error.page.conflict.trimdirectivewhitespaces=Page directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1}) jsp.error.tag.conflict.trimdirectivewhitespaces=Tag directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1}) \ No newline at end of file diff --git a/java/org/apache/jasper/resources/LocalStrings_es.properties b/java/org/apache/jasper/resources/LocalStrings_es.properties index f123253e0..34aee5051 100644 --- a/java/org/apache/jasper/resources/LocalStrings_es.properties +++ b/java/org/apache/jasper/resources/LocalStrings_es.properties @@ -1,408 +1,408 @@ -# $Id: LocalStrings_es.properties 349479 2005-11-28 19:44:47Z yoavs $ -# -# Default localized string information -# Localized para Locale es_ES - -jsp.error.bad.servlet.engine=¡Versión incorrecta del motor servlet! -jsp.error.no.scratch.dir=El motor JSP no tiene configurado un directorio de trabajo.\ -\n Añada \"jsp.initparams=scratchdir=\" \ -\n en el fichero servlets.properties para este contexto. -jsp.error.bad.scratch.dir=El directorio de trabajo especificado: {0} no es utilizable. -jsp.message.scratch.dir.is=El directorio de trabajo para el motor JSP es: {0} -jsp.message.parent_class_loader_is=El cargador de clases es: {0} -jsp.message.dont.modify.servlets=IMPORTANTE: No modifique los servlets generados -jsp.error.not.impl.comments=Error Interno: Comments no implementado -jsp.error.not.impl.directives=Error Interno: Directives no implementado -jsp.error.not.impl.declarations=Error Interno: Declarations no implementado -jsp.error.not.impl.expressions=Error Interno: Expressions no implementado -jsp.error.not.impl.scriptlets=Error Interno: Scriptlets no implementado -jsp.error.not.impl.useBean=Error Interno: useBean no implementado -jsp.error.not.impl.getp=Error Interno: getProperty no implementado -jsp.error.not.impl.setp=Error Interno: setProperty no implementado -jsp.error.not.impl.plugin=Error Interno: plugin no implementado -jsp.error.not.impl.forward=Error Interno: forward no implementado -jsp.error.not.impl.include=Error Interno: include no implementado -jsp.error.unavailable=JSP ha sido marcado como no disponible -jsp.error.usebean.missing.attribute=useBean: falta atributo id o está mal digitado -jsp.error.usebean.missing.type=useBean ({0}): Se debe de especificar atributo class o type: -jsp.error.usebean.duplicate=useBean: Nombre de bean duplicado: {0} -jsp.error.usebean.prohibited.as.session=No puedo usar como bean de sesión {0} ya que está prohibido \ -por directiva jsp definida previamente: -jsp.error.usebean.not.both=useBean: No puede especificar ambos atributos class y beanName: -jsp.error.usebean.bad.type.cast=useBean ({0}): Tipo ({1}) no es asignable desde clase ({2}) -jsp.error.invalid.scope=Valor ilegal de atributo \'scope\': {0} (debe de ser uno de \"page\", \"request\", \"session\", o \"application\") -jsp.error.classname=No pude determinar el nombre de clase desde el fichero .class -jsp.warning.bad.type=Aviso: tipo incorrecto en archivo .class -jsp.error.data.file.write=Error mientras escribía el archivo de datos -jsp.error.page.invalid.buffer=Directiva Page: medida de buffer inválida -jsp.error.page.conflict.contenttype=Directiva Page: es ilegal tener múltiples ocurrencias de 'contentType' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.contenttype=Directiva Page: valor incorrecto para contentType -jsp.error.page.conflict.session=Directiva Page: es ilegal tener múltiples ocurrencias de 'session' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.session=Directiva Page: valor incorrecto para session -jsp.error.page.conflict.buffer=Directiva Page: es ilegal tener múltiples ocurrencias de 'buffer'con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.buffer=Directiva Page: valor incorrecto para buffer -jsp.error.page.conflict.autoflush=Directiva Page: es ilegal tener múltiples ocurrencias de 'autoFlush' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.autoflush==Directiva Page: valor incorrecto para autoFlush -jsp.error.page.conflict.isthreadsafe=Directiva Page: es ilegal tener múltiples ocurrencias de 'isThreadSafe' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.isthreadsafe==Directiva Page: valor incorrecto para isThreadSafe -jsp.error.page.conflict.info=Directiva Page: es ilegal tener múltiples ocurrencias de 'info' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.info==Directiva Page: valor incorrecto para info -jsp.error.page.conflict.iserrorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'isErrorPage' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.iserrorpage==Directiva Page: valor incorrecto para isErrorPage -jsp.error.page.conflict.errorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'errorPage' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.conflict.language=Directiva Page: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.tag.conflict.language=Directiva Tag: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.language.nonjava=Directiva Page: atributo language incorrecto -jsp.error.tag.language.nonjava=Directiva Tag: atributo language incorrecto -jsp.error.page.defafterusar.language=Directiva Page: No puede definir language tras un scriptlet -jsp.error.page.nomapping.language=Directiva Page: No hay mapeado para language: -jsp.error.page.conflict.extends=Directiva Page: es ilegal tener múltiples ocurrencias de 'extends' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.conflict.iselignored=Directiva Page: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.tag.conflict.iselignored=Directiva Tag: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1}) -jsp.error.page.invalid.iselignored=Directiva Page: valor inválido para isELIgnored -jsp.error.tag.invalid.iselignored=Directiva Tag: valor incorrecto para isELIgnored -jsp.error.page.multi.pageencoding=La directiva Page no debe de tener múltiples ocurrencias de pageencoding -jsp.error.tag.conflict.attr=Directiva Tag: es ilegal tener múltiples ocurrencias del atributo \"{0}\" con valores distintos (viejo: {1}, nuevo: {2}) -jsp.error.tag.multi.pageencoding=La directiva Tag no debe de tener múltiples ocurrencias de pageencoding -jsp.error.page.bad_b_and_a_combo=Directiva Page: Combinación ilegal de buffer=\"none\" y autoFlush=\"false\" -jsp.error.not.impl.taglib=Error Interno: Tag extensions no implementado -jsp.error.include.missing.file=No tiene argumento de nombre de fichero -jsp.error.include.bad.file=Argumento de nombre de fichero no válido -jsp.error.include.exception=No se puede incluir {0} -jsp.error.stream.closed=Stream cerrado -jsp.error.invalid.forward=Tag forward no válido -jsp.error.unknownException=¡Error no caturado!. Deberías de considerar el poner una página de error para avisar de los errores más elegantemente -jsp.error.invalid.directive=Directiva no válida -jsp.error.directive.istagfile=La Directiva {0} no puede usarse en archivo de tag -jsp.error.directive.isnottagfile=La Directiva {0} sólo se puede usar en un archivo de tag -jsp.error.tagfile.tld.name=El atributo \"name\" de la directiva tag tiene un valor {0} mientras que el tag \"name\" del elemento \"tag-file\" en el TLD es {1} -jsp.error.action.istagfile=La acción {0} no se puede usar en un archivo tag -jsp.error.action.isnottagfile=La acción {0} sólo se puede usar en archivos tag -jsp.error.unterminated=Tag {0} no terminado -jsp.error.usebean.notinsamefile=El Tag useBean debe de empezar y terminar en el mismo archivo físico -jsp.error.loadclass.taghandler=No se puede cargar la clase {0} -jsp.error.unable.compile=No se puede compilar la clase para JSP -jsp.error.unable.load=No se puede cargar la clase para JSP -jsp.error.unable.rename=No se puede renombrar el archivo de clase {0} a {1} -jsp.error.mandatory.atributo={0}: atributo obligatorio {1} perdido -jsp.engine.info=Motor Jasper JSP 2.0 -jsp.error.invalid.expression="{0}" contiene expresiones incorrectas: {1} -jsp.error.invalid.attribute={0}: Atributo incorrecto, {1} -jsp.error.usebean.class.notfound=Clase: {0} no hallada -jsp.error.file.cannot.read=No se puede leer el archivo: {0} -jsp.error.file.already.registered=El archivo {0} ya se ha visto, ¿podría ser un include recursivo? -jsp.error.file.not.registered=Archivo {0} not visto en include -jsp.error.quotes.unterminated=Comillas no terminadas -jsp.error.attr.quoted=El valor del atributo debería ir entre comillas -jsp.error.attr.novalue=Atributo {0} no tiene valor -jsp.error.tag.attr.unterminated=Lista de atributos del tag no terminada -jsp.error.param.noname=No hay nombre en el tag PARAM -jsp.error.param.novalue=No hay valor en el tag PARAM -jsp.error.beans.nullbean=Se ha intentado una operación de bean en un objeto nulo -jsp.error.beans.nobeaninfo=No se puede encontrar BeanInfo para el bean ''{0}'' seguramente la clase no existe -jsp.error.beans.introspection=Una excepción ha tenido lugar mientras se leía el método de lectura de la propiedad ''{0}'' en un bean del tipo ''{1}'':\n{2} -jsp.error.beans.nomethod=No puedo encontrar un método para leer la propiedad ''{0}'' en un bean del tipo ''{1}'' -jsp.error.beans.nomethod.setproperty=No puedo encontrar un método para escribir la propiedad ''{0}'' en un bean del tipo ''{2}'' -jsp.error.beans.noproperty=No puedo encontrar información de la propiedad ''{0}'' en un bean del tipo ''{1}'' -jsp.error.beans.setproperty.noindexset=No puedo poner la propiedad indexada -jsp.error.include.tag=Tag jsp:include no válido -jsp.error.include.noflush=jsp:include necesita tener \"flush=true\" -jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" es la única combinación válida en JSP 1.0 -jsp.error.attempt_to_clear_flushed_buffer=Error: Se ha intentado limpiar un buffer que ya había sido escrito -jsp.error.overflow=Error:Buffer de JSP desbordado -jsp.error.paramexpected=El tag \"param\" era esperado con los atributos \"name\" y \"value\" después del tag \"params\". -jsp.error.param.invalidUse=La acción jsp:param no debe de ser usada fuera de los elementos jsp:include, jsp:forward o jsp:params -jsp.error.params.invalidUse=jsp:params debe de ser un hijo directo de jsp:plugin -jsp.error.fallback.invalidUse=jsp:fallback debe de ser un hijo directo de jsp:plugin -jsp.error.namedAttribute.invalidUse=jsp:attribute debe de ser el subelemento de una acción estándar o de cliente -jsp.error.jspbody.invalidUse=jsp:body debe de ser el subelemento de una acción estándar o de cliente -jsp.error.closeindividualparam=El tag param necesita ser cerrado con \"/>\" -jsp.error.closeparams=El tag param necesita ser cerrado con /params -jsp.error.params.emptyBody=jsp:params debe de contener al menos un jsp:param anidado -jsp.error.params.illegalChild=jsp:params no debe de contener elementos anidados que no sean jsp:param -jsp.error.plugin.notype=Tipo no declarado en jsp:plugin -jsp.error.plugin.badtype=Valor ilegal para atributo 'type' en jsp:plugin: debe de ser 'bean' o 'applet' -jsp.error.plugin.nocode=Código no declarado en jsp:plugin -jsp.error.ise_on_clear=Es ilegal usar clear() cuando el tamaño del buffer es cero -jsp.error.setproperty.beanNotFound=setProperty: Bean {0} no encontrado -jsp.error.getproperty.beanNotFound=getProperty: Bean {0} no encontrado -jsp.error.setproperty.ClassNotFound=setProperty: clase {0} no encontrada -# typo ? -#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=* -jsp.error.setproperty.invalidSyantax=setProperty: No puede haber un valor no nulo cuando se ha especificado property=* -jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo para bean {0} no encontrado -jsp.error.setproperty.paramOrValue=setProperty: O param o value pueden estar presentes -jsp.error.setproperty.arrayVal=setProperty: No puede escribir en la propiedad de array {0} a través de una valor de cadena literal -jsp.warning.keepgen=Aviso: valor incorrecto para el initParam keepgen. Se usará el valor por defecto de \"false\" -jsp.warning.xpoweredBy=Aviso: valor incorrecto para el initParam xpoweredBy. Se usará el valor por defecto de \"false\" -jsp.warning.enablePooling=Aviso: valor incorrecto para el initParam enablePooling. Se usará el valor por defecto de \"true\" -jsp.warning.invalidTagPoolSize=Aviso: valor incorrecto para el parámetro init llamado tagPoolSize. Se usará la medida por defecto de {0} -jsp.warning.mappedFile=Aviso: valor incorrecto para el initParam mappedFile. Se usará el valor por defecto de \"false\" -jsp.warning.sendErrToClient=Aviso: valor incorrecto para el initParam sendErrToClient. Se usará el valor por defecto de \"false\" -jsp.warning.classDebugInfo=Aviso: valor incorrecto para el initParam classdebuginfo. Se usará el valor por defecto de \"false\" -jsp.warning.checkInterval=Aviso: valor incorrecto para el initParam checkInterval. Se usará el valor por defecto de \"300\" segundos -jsp.warning.development=Aviso: valor incorrecto para el initParam development. Se usará el valor por defecto de \"true\" -jsp.warning.fork=Aviso: valor incorrecto para el initParam fork. Se usará el valor por defecto de \"true\" -jsp.warning.reloading=Aviso: valor incorrecto para el initParam reloading. Se usará el valor por defecto de \"true\" -jsp.warning.dumpSmap=Aviso: valor incorrecto para el initParam dumpSmap. Se usará el valor por defecto de \"false\" -jsp.warning.genchararray=Aviso: valor incorrecto para el initParam genStrAsCharArray. Se usará el valor por defecto de \"false\" -jsp.warning.suppressSmap=Aviso: valor incorrecto para el initParam suppressSmap. Se usará el valor por defecto de \"false\" -jsp.error.badtaglib=No se puede abrir la biblioteca de tags {0}: {1} -jsp.error.badGetReader=No se puede crear un reader cuando el stream no tiene buffer -jsp.warning.unknown.element.in.taglib=Elemento desconocido ({0}) en taglib -jsp.warning.unknown.element.in.tag=Elemento desconocido ({0}) en tag -jsp.warning.unknown.element.in.tagfile=Elemento desconocido ({0}) en tag-file -jsp.warning.unknown.element.in.attribute=Elemento desconocido ({0}) en attribute -jsp.warning.unknown.element.in.variable=Elemento desconocido ({0}) en variable -jsp.warning.unknown.element.in.validator=Elemento desconocido ({0}) en validator -jsp.warning.unknown.element.in.initParam=Elemento desconocido ({0}) en init-param de validator -jsp.warning.unknown.element.in.function=Elemento desconocido ({0}) en function -jsp.error.more.than.one.taglib=Más de una biblioteca de tags en el TLD: {0} -jsp.error.teiclass.instantiation=No se puede cargar la clase TagExtraInfo llamada: {0} -jsp.error.non_null_tei_and_var_subelems=Tag {0} tiene uno o más subelementos variable y una clase TagExtraInfo que devuelve una o más VariableInfo -jsp.error.parse.error.in.TLD=Error de análisis en el descriptor de biblioteca de tags: {0} -jsp.error.unable.to.open.TLD=No se puede abrir el descriptor de biblioteca de tags: {0} -jsp.buffer.size.zero=Tamaño de buffer <= 0 -jsp.error.file.not.found=Archivo JSP \"{0}\" no encontrado -jsp.message.copyinguri=Copiando {0} en {1} -jsp.message.htmlcomment=\nQuitando comentario: \t{0} -jsp.message.handling_directive=\nResolviendo directiva: {0}\t{1} -jsp.message.handling_plugin=\nPlugin: {0} -jsp.message.package_name_is=El Nombre del Package es: {0} -jsp.message.class_name_is=El Nombre de la clase es: {0} -jsp.message.java_file_name_is=El Nombre del Archivo Java es: {0} -jsp.message.class_file_name_is=El Nombre del Archivo de clase es: {0} -jsp.message.accepted=Aceptó {0} en {1} -jsp.message.adding_jar=Añadiendo jar {0} a mi classpath -jsp.message.compiling_with=Compilado con: {0} -jsp.message.template_text=texto plantilla -jsp.error.missing_attribute=De acuerdo con el TLD el atributo {0} es obligatorio para el tag {1} -jsp.error.bad_attribute=El atributo {0} no es válido según el TLD especificado -jsp.error.tld.unable_to_read=Imposible de leer TLD \"{1}\" desde archivo JAR \"{0}\": {2} -jsp.error.tld.unable_to_get_jar=Imposible obtener recurso JAR \"{0}\" conteniendo TLD: {1} -jsp.error.tld.missing_jar=Falta recurso JAR \"{0}\" conteniendo TLD -jsp.error.webxml_not_found=No puedo localizar web.xml -jsp.cmd_line.usage=Uso: jsptoservlet [-dd ] [-keepgenerated] -jsp.message.cp_is=Classpath {0} es: {1} -jsp.error.unable.to_load_taghandler_class=No se puede cargar clase manejadora {0} del tag a causa de {1} -jsp.error.unable.to_find_method=No se puede encontrar el método de escritura para el atributo: {0} -jsp.error.unable.to_convert_string=No pude convertir un String a {0} para atributo {1} -jsp.error.unable.to_introspect=No se puede hacer introspección en manejador de tag clase: {0} a causa de {1} -jsp.error.bad_tag=No existe el tag {0} en la biblioteca importada con prefijo {1} -jsp.error.xml.bad_tag=No se ha definido el tag \"{0}\" en la biblioteca tag asociada con uri \"{1}\" -jsp.error.bad_string_Character=No puede extraer un Character desde un array de tamaño cero -jsp.error.bad_string_char=No puede extraer un char desde un array de tamaño cero -jsp.warning.compiler.class.cantcreate=No puedo crear una instancia de la clase especificada {0} de plugin del compilador debido a {1}. Se usará el compilador Java de Sun. -jsp.warning.compiler.class.notfound=No puedo encontrar una instancia de la clase {0} de plugin de compilador. Se usará el compilador del Java de Sun. -jsp.warning.compiler.path.notfound=Trayectoria del compilador especificado {0} no encontrada. Se usará el PATH del sistema. -jsp.error.jspc.uriroot_not_dir=La opción -uriroot debe de especificar un directorio ya existente -jsp.error.jspc.missingTarget=Falta target: Debe de especificar -webapp o -uriroot o una o más páginas JSP -jsp.error.jspc.no_uriroot=No se ha especificado uriroot y no puede ser localizado en los archivos JSP especificados -jspc.implicit.uriRoot=uriRoot implicitamente puesto a "{0}" -jspc.usage=Uso: jspc [--] \n\ -donde son:\n\ -\ -webapp Un directorio conteniendo una web-app. Todas las\n\ -\ páginas jsp serán compiladas recursivamente\n\ -o cualquier número de\n\ -\ Un Archivo para ser interpretado como una página jsp\n\ -y donde incluyen:\n\ -\ -help Muestra este mensaje de ayuda\n\ -\ -v Modo detallado\n\ -\ -d Directorio de salida\n\ -\ -l Muestra el nombre de la página JSP al ocurrir un fallo\n\ -\ -s Muestra el nombre de la página JSP al tener éxito\n\ -\ -p Nombre del package objetivo\n\ -\ (por defecto org.apache.jsp)\n\ -\ -c Nombre de la clase objetivo\n\ -\ (sólo se aplica a la primera página JSP)\n\ -\ -mapped Genera llamadas separadas a write() para cada línea de\n\ -\ HTML en el JSP\n\ -\ -die[#] Genera un código de retorno de error (#) en errores\n\ -\ fatales. (por defecto 1).\n\ -\ -uribase El directorio uri de donde deben de partir las\n\ -\ compilaciones. (por defecto "/")\n\ -\ -uriroot Igual que -webapp\n\ -\ -compile Compila los servlets generados\n\ -\ -webinc Crea unos mapeos parciales de servlet en el archivo\n\ -\ -webxml Crea un web.xml completo en el archivo.\n\ -\ -ieplugin Java Plugin classid para Internet Explorer\n\ -\ -classpath Pasa por alto la propiedad de sistema java.class.path\n\ -\ -xpoweredBy Añade cabecera de respuesta X-Powered-By\n\ -\ -trimSpaces Trim spaces in template text between actions, directives\n\ -\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ -\ -source Set the -source argument to the compiler (default 1.4)\n\ -\ -target Set the -target argument to the compiler (default 1.4)\n\ - -jspc.webxml.header=\n\ -\n\ -\n\ -\n\ -\n\ -\n -jspc.webxml.footer=\n\ -\n\ -\n -jspc.webinc.header=\n\ -\n -jspc.webinc.footer=\n\ -\n -jspc.webinc.insertEnd= -jspc.webinc.insertStart= -jspc.error.jasperException=error-el archivo ''{0}'' ha generado la excepción de sintáxis siguiente: {1} -jspc.error.generalException=ERROR-el archivo ''{0}'' ha generado la excepción general siguiente: -jspc.error.fileDoesNotExist=El archivo ''{0}'' utilizado como argumento no existe. -jspc.error.emptyWebApp=-webapp necesita un argumento de archivo -jsp.error.library.invalid=La página JSP es incorrecta de acuerdo a la biblioteca {0}: {1} -jsp.error.tlvclass.instantiation=No pude cargar o instanciar clase TagLibraryValidator: {0} -jsp.error.tlv.invalid.page=Mensajes de error de validación desde TagLibraryValidator para {0} in {1} -jsp.error.tei.invalid.attributes=Mensajes de error de validación desde TagExtraInfo para {0} -jsp.parser.sax.propertynotsupported=Propiedad SAX no soportada: {0} -jsp.parser.sax.propertynotrecognized=Propiedad SAX no reconocida: {0} -jsp.parser.sax.featurenotsupported=Característica SAX no soportada: {0} -jsp.parser.sax.featurenotrecognized=Característica SAX no reconocida: {0} -jsp.error.no.more.content=Alcanzado fin de contenido mietras se requería más análisis: ¿error de anidamiento de tag? -jsp.error.parse.xml=Error de análisis XML en archivo {0} -jsp.error.parse.xml.line=Error de análisis XML en archivo {0}: (línea {1}, col {2}) -jsp.error.parse.xml.scripting.invalid.body=El cuerpo de elemento {0} no debe de contener elementos XML -jsp.error.internal.tldinit=No pude inicializar TldLocationsCache: {0} -jsp.error.internal.filenotfound=Error Interno: Archivo {0} no hallado -jsp.error.internal.evaluator_not_found=Error interno: no pude cargar evaluador de expresiones -jsp.error.parse.xml.invalidPublicId=PUBLIC ID incorrecta: {0} -jsp.error.include.flush.invalid.value=Valor incorrecto para atributo flush: {0} -jsp.error.unsupported.encoding=Codificación no soportada: {0} -tld.error.variableNotAllowed=Es un error para un tag, que tiene uno o más subelementos variables, el tener una clase TagExtraInfo que devuelve un objeto no nulo. -jsp.error.tldInWebDotXmlNotFound=No pude localizar TLD {1} para URI {0} especificado en web.xml -jsp.error.taglibDirective.absUriCannotBeResolved=La uri absoluta: {0} no puede resolverse o en web.xml o el los archivos jar desplegados con esta aplicación -jsp.error.taglibDirective.missing.location=No se ha especificado ni el atributo \'uri\' ni el \'tagdir\' -jsp.error.taglibDirective.both_uri_and_tagdir=Se han especificado ambos atributos \'uri\' y \'tagdir\' -jsp.error.invalid.tagdir=El directorio de archivo Tag {0} no comienza con \"/WEB-INF/tags\" -jsp.error.unterminated.user.tag=Tag definido por usuario no terminado: tag final {0} no hallado o anidado incorrectamente -#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} -jspx.error.templateDataNotInJspCdata=Error de Validación: El Elemento <{0}> no puede tener datos plantilla. Los datos plantilla deben de estar encapsulados dentro de un elemento <jsp:text>. [JSP1.2 PFD sección 5.1.9]\nDatos de Plantilla en error: {1} -#Error while processing taglib jar file {0}: {1} -jsp.error.taglib.reserved.prefix=El prefijo taglib {0} está reservado -jsp.error.invalid.javaEncoding=Codificaciones java incorrectas. Intenté {0} y luego {1}. Ambas fallaron. -jsp.error.needAlternateJavaEncoding=La codificación java por defecto {0} es incorrecta en tu plataforma java. Se puede especificar una alternativa vía parámetro 'javaEncoding' de JspServlet. -#Error when compiling, used for jsp line number error messages -jsp.error.single.line.number=Ha tenido lugar un error en la línea: {0} en el archivo jsp: {1} -jsp.error.multiple.line.number=\n\nHa tenido lugar un error entre las líneas: {0} y {1} en el archivo jsp: {2}\n\n -jsp.error.corresponding.servlet=Error de servlet generado:\n -jsp.error.empty.body.not.allowed=Cuerpo vacío no permitido para {0} -jsp.error.jspbody.required=Se debe de usar jsp:body para especificar cuerpo tag para {0} si se usa jsp:attribute. -jsp.error.jspbody.emptybody.only=El tag {0} sólo puede tener jsp:attribute en su cuerpo. -jsp.error.no.scriptlets=Los elementos de Scripting (<%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) no están permitidos aquí. -jsp.error.internal.unexpected_node_type=Error Interno: Encontrado tipo de nodo inesperado -jsp.error.tld.fn.invalid.signature=Sintáxis incorrecta para firma de función en TLD. Biblioteca de Tag: {0}, Función: {1} -jsp.error.tld.fn.duplicate.name=Nombre duplicado de función {0} en biblioteca de tag {1} -jsp.error.tld.fn.invalid.signature.commaexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Coma ','. Biblioteca de Tag: {0}, Función: {1}. -jsp.error.tld.fn.invalid.signature.parenexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Paréntesis '('. Biblioteca de Tag: {0}, Función: {1}. -jsp.error.tld.mandatory.element.missing=Falta o está vacío elemento TLD obligatorio: {0} -jsp.error.dynamic.attributes.not.implemented=El tag {0} declara que acepta atributos dinámicos pero no implementa la interfaz requerida -jsp.error.nomatching.fragment=No puedo hallar una directiva de atributo (con name={0} y fragment=true) antes de la directiva de fragment. -jsp.error.attribute.noequal=se esperaba símbolo igual -jsp.error.attribute.noquote=se esperaba símbolo comillas -jsp.error.attribute.unterminated=el atributo para {0} no está terminado correctamente -jsp.error.missing.tagInfo=El objeto TagInfo para {0} falta del TLD -jsp.error.fragmentwithtype=No puede especificar ambos atributos 'fragment' y 'type'. Si está presente 'fragment', 'type' se pone como 'javax.servlet.jsp.tagext.JspFragment' -jsp.error.fragmentwithrtexprvalue=No puede especificar ambos atributos 'fragment' y 'rtexprvalue'. Si está presente 'fragment', 'rtexprvalue' se pone como 'true' -jsp.error.fragmentWithDeclareOrScope=Ambos atributos 'fragment' y 'declare' o 'scope' se han especificado en la directiva variable -jsp.error.var_and_varReader=Sólo se puede especificar uno de \'var\' o \'varReader\' -jsp.error.missing_var_or_varReader=Falta atributo \'var\' o \'varReader\' -jsp.warning.bad.urlpattern.propertygroup=Valor malo {0} en el subelemento url-pattern en web.xml -jsp.error.unknown_attribute_type=Tipo de atributo desconocido ({1}) para atributo {0}. -jsp.error.jspelement.missing.name=Falta atributo obligatorio XML-style \'name\' -jsp.error.xmlns.redefinition.notimplemented=Error interno: Intento de redefinir xmlns:{0}. La redefinición de espacios de nombre no está implementada. -jsp.error.could.not.add.taglibraries=No pude añadir una o más bibliotecas. -jsp.error.duplicate.name.jspattribute=El atributo {0} especificado en la acción standard o custom también aparece como el valor del atributo name en jsp:attribute -jsp.error.not.in.template={0} no permitido en una plantilla cuerpo de texto. -jsp.error.badStandardAction=Acción estándar incorrecta -jsp.error.xml.badStandardAction=Acción estándar incorrecta: {0} -jsp.error.tagdirective.badbodycontent=body-content incorrecto ({0}) en directiva tag -jsp.error.simpletag.badbodycontent=El TLD para la clase {0} especifica un body-content es incorrecto (JSP) para un SimpleTag. -jsp.error.config_pagedir_encoding_mismatch=El Page-encoding especificado en jsp-property-group ({0}) es diferente del especificado en la diectiva page ({1}) -jsp.error.prolog_pagedir_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en la directiva page ({1}) -jsp.error.prolog_config_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en jsp-property-group ({1}) -jsp.error.attribute.custom.non_rt_with_expr=Según el TLD o la directiva attribute del archivo tag, el atributo {0} no acepta expresiones -jsp.error.attribute.standard.non_rt_with_expr=El atributo {0} de la acción estándar {1} no acepta expresiones -jsp.error.scripting.variable.missing_name=Imposible determinar nombre de variable de scripting desde atributo {0} -jasper.error.emptybodycontent.nonempty=Según el TLD, el tag {0} debe de estar vacío, pero no lo está -jsp.error.tagfile.nameNotUnique=El valor de {0} y el valor de {1} en la línea {2} son el mismo. -jsp.error.tagfile.nameFrom.noAttribute=No puedo hallar una directiva attribute con un atributo name con un valor \"{0}\", el valor de este atributo name-from-attribute. -jsp.error.tagfile.nameFrom.badAttribute=La directiva attribute (declarada en la línea {1} y cuyo atributo name es \"{0}\", el valor de este atributo name-from-attribute attribute) debe de ser del tipo java.lang.String, es \"required\" y no un \"rtexprvalue\". -jsp.error.page.noSession=No puedo acceder al ámbito de sesión en una página que no participa en una sesión -jsp.error.useBean.noSession=Es ilegal para useBean usar un ámbito de sesión cuando la página JSP declara (vía directiva page) que no participa en sesiones -jsp.error.xml.encodingByteOrderUnsupported=El orden de byte dado para encoding \"{0}\" no está soportado -jsp.error.xml.encodingDeclInvalid=Nombre de codificación \"{0}\" incorrecto. -jsp.error.xml.encodingDeclRequired=Se necesita la declaración encoding en la declaración de texto -jsp.error.xml.morePseudoAttributes=se esperan más pseudo-atributos -jsp.error.xml.noMorePseudoAttributes=no se permiten más pseudo-atributos. -jsp.error.xml.versionInfoRequired=Se requiere la versión en la declaración XML. -jsp.error.xml.xmlDeclUnterminated=La declaración XML debe de terminar con \"?>\". -jsp.error.xml.reservedPITarget=La instrucción de procesamiento que coincide con \"[xX][mM][lL]\" no está permitida. -jsp.error.xml.spaceRequiredInPI=Se necesita un espacio en blanco entre la instrucción de procesamiento y los datos. -jsp.error.xml.invalidCharInContent=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en el contenido del elemento del documento. -jsp.error.xml.spaceRequiredBeforeStandalone=Se necesita un espacio en blanco antes del pseudo-atributo encoding en la declaración XML. -jsp.error.xml.sdDeclInvalid=El valor de declaración de documento standalone debe de ser \"yes\" o \"no\", no \"{0}\". -jsp.error.xml.invalidCharInPI=Se halló un carácter XML incorrecto (Unicode: 0x{0}) en la instrucción de procesamiento -jsp.error.xml.versionNotSupported=No se soporta la versión XML \"{0}\", sólo se soporta XML 1.0 -jsp.error.xml.pseudoAttrNameExpected=se esperaba un pseudo-atributo name. -jsp.error.xml.expectedByte=Se esperaba byte {0} de {1}-byte de secuencia UTF-8. -jsp.error.xml.invalidByte=Incorrecto byte {0} de {1}-byte de secuencia UTF-8. -jsp.error.xml.operationNotSupported=La operación \"{0}\" no está soportada por lector {1}. -jsp.error.xml.invalidHighSurrogate=Surrogación Alta de bits en secuencia UTF-8 no debe de exceder 0x10, pero se halló 0x{0}. -jsp.error.xml.invalidASCII=El Byte \"{0}\" no es ASCII de 7-bit. -jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración XML. -jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración text. -jsp.error.xml.spaceRequiredBeforeVersionInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración text. -jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración XML. -jsp.error.xml.eqRequiredInXMLDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración XML. -jsp.error.xml.eqRequiredInTextDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración text. -jsp.error.xml.quoteRequiredInTextDecl=El valor que sigue a \"{0}\" en la declaración text debe de ser una cadena entre comillas. -jsp.error.xml.quoteRequiredInXMLDecl=El valor que sigue a \"{0}\" en la declaración XML debe de ser un cadena entre comillas. -jsp.error.xml.invalidCharInTextDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración text -jsp.error.xml.invalidCharInXMLDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración XML -jsp.error.xml.closeQuoteMissingInTextDecl=Faltan las comillas de cierre en el valor que sigue a \"{0}\" en la declaración text. -jsp.error.xml.closeQuoteMissingInXMLDecl=Faltan las comillas de cierre en el valor que sigue a \"{0}\" en la declaración XML. -jsp.error.multiple.jsp=No puedo tener múltiples especificaciones de -jsp.error.jspoutput.conflict=<jsp:output>: ilegal tener ocurrencias múltiples de \"{0}\" con diferentes valores (viejo: {1}, nuevo: {2}) -jsp.error.jspoutput.doctypenamesystem=<jsp:output>: atributos 'doctype-root-element' y 'doctype-system' deben de aparecer juntos -jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: atributo 'doctype-system' debe de aparecer si aparece atributo 'doctype-public' -jsp.error.jspoutput.nonemptybody=<jsp:output> no debe de tener un cuerpo -jsp.error.jspoutput.invalidUse=<jsp:output> no se debe de usar en sintáxis estándar -jsp.error.attributes.not.allowed = {0} no debe de tener atributos -jsp.error.tagfile.badSuffix=Falta sufijo \".tag\" en trayectoria de archivo de tag {0} -jsp.error.tagfile.illegalPath=Trayectoria de archivo de tag: {0}, debe de comenzar con \"/WEB-INF/tags\" o \"/META-INF/tags\" -jsp.error.plugin.wrongRootElement=El nombre del elemento raíz en {0} difiere de {1} -jsp.error.attribute.invalidPrefix=El prefijo de atributo {0} no se correponde con ninguna biblioteca importada -jsp.error.nested.jspattribute=Una acción estándar jsp:attribute no puede estar anidada dentro de otra acción estándar jsp:attribute -jsp.error.nested.jspbody=Una acción estándar jsp:body no puede estar anidada dentro de otra acción estándar jsp:body o jsp:attribute -jsp.error.variable.either.name=O el atributo name-given o name-from-attribute deben de ser especificados en una directiva variable -jsp.error.variable.both.name=No se puede especificar ambos atributos name-given o name-from-attribute en una directiva variable -jsp.error.variable.alias=Ambos atributos o ninguno de name-from-attribute y alias pueden ser especificados en una directiva variable -jsp.error.attribute.null_name=Nombre de atributo nulo -jsp.error.jsptext.badcontent=\'<\', cuando aparece en el cuerpo de <jsp:text>, debe de estar encapsulado dentro de un CDATA -jsp.error.jsproot.version.invalid=Número incorrecto de versión: \"{0}\", debe de ser \"1.2\" o \"2.0\" -jsp.error.noFunctionPrefix=La función {0} debe de usarse con un prefijo cuando no se especifica un espacio de nombres por defecto -jsp.error.noFunction=La función {0} no puede ser localizada mediante el prefijo especificado -jsp.error.noFunctionMethod=El método \"{0}\" para la función \"{1}\" no se pudo hallar en la clase \"{2}\" -jsp.error.function.classnotfound=La clase {0} especificada en el TLD para la función {1} no se puede hallar: {2} -jsp.error.signature.classnotfound=La clase {0} especificada en la firma del método en el TLD para la función {1} no se puede hallar. {2} -jsp.error.text.has_subelement=<jsp:text> no debe de tener subelementos -jsp.error.data.file.read=Error leyendo archivo \"{0}\" -jsp.error.prefix.refined=Intento de redefinir el prefijo {0} por {1}, cuando ya estaba definido como {2} en el ámbito en curso. -jsp.error.nested_jsproot=<jsp:root> anidado -jsp.error.unbalanced.endtag=El tgag final \"</{0}\" está desequilibrado -jsp.error.invalid.bean= +# $Id: LocalStrings_es.properties 349479 2005-11-28 19:44:47Z yoavs $ +# +# Default localized string information +# Localized para Locale es_ES + +jsp.error.bad.servlet.engine=¡Versión incorrecta del motor servlet! +jsp.error.no.scratch.dir=El motor JSP no tiene configurado un directorio de trabajo.\ +\n Añada \"jsp.initparams=scratchdir=\" \ +\n en el fichero servlets.properties para este contexto. +jsp.error.bad.scratch.dir=El directorio de trabajo especificado: {0} no es utilizable. +jsp.message.scratch.dir.is=El directorio de trabajo para el motor JSP es: {0} +jsp.message.parent_class_loader_is=El cargador de clases es: {0} +jsp.message.dont.modify.servlets=IMPORTANTE: No modifique los servlets generados +jsp.error.not.impl.comments=Error Interno: Comments no implementado +jsp.error.not.impl.directives=Error Interno: Directives no implementado +jsp.error.not.impl.declarations=Error Interno: Declarations no implementado +jsp.error.not.impl.expressions=Error Interno: Expressions no implementado +jsp.error.not.impl.scriptlets=Error Interno: Scriptlets no implementado +jsp.error.not.impl.useBean=Error Interno: useBean no implementado +jsp.error.not.impl.getp=Error Interno: getProperty no implementado +jsp.error.not.impl.setp=Error Interno: setProperty no implementado +jsp.error.not.impl.plugin=Error Interno: plugin no implementado +jsp.error.not.impl.forward=Error Interno: forward no implementado +jsp.error.not.impl.include=Error Interno: include no implementado +jsp.error.unavailable=JSP ha sido marcado como no disponible +jsp.error.usebean.missing.attribute=useBean: falta atributo id o está mal digitado +jsp.error.usebean.missing.type=useBean ({0}): Se debe de especificar atributo class o type: +jsp.error.usebean.duplicate=useBean: Nombre de bean duplicado: {0} +jsp.error.usebean.prohibited.as.session=No puedo usar como bean de sesión {0} ya que está prohibido \ +por directiva jsp definida previamente: +jsp.error.usebean.not.both=useBean: No puede especificar ambos atributos class y beanName: +jsp.error.usebean.bad.type.cast=useBean ({0}): Tipo ({1}) no es asignable desde clase ({2}) +jsp.error.invalid.scope=Valor ilegal de atributo \'scope\': {0} (debe de ser uno de \"page\", \"request\", \"session\", o \"application\") +jsp.error.classname=No pude determinar el nombre de clase desde el fichero .class +jsp.warning.bad.type=Aviso: tipo incorrecto en archivo .class +jsp.error.data.file.write=Error mientras escribía el archivo de datos +jsp.error.page.invalid.buffer=Directiva Page: medida de buffer inválida +jsp.error.page.conflict.contenttype=Directiva Page: es ilegal tener múltiples ocurrencias de 'contentType' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.contenttype=Directiva Page: valor incorrecto para contentType +jsp.error.page.conflict.session=Directiva Page: es ilegal tener múltiples ocurrencias de 'session' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.session=Directiva Page: valor incorrecto para session +jsp.error.page.conflict.buffer=Directiva Page: es ilegal tener múltiples ocurrencias de 'buffer'con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.buffer=Directiva Page: valor incorrecto para buffer +jsp.error.page.conflict.autoflush=Directiva Page: es ilegal tener múltiples ocurrencias de 'autoFlush' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.autoflush==Directiva Page: valor incorrecto para autoFlush +jsp.error.page.conflict.isthreadsafe=Directiva Page: es ilegal tener múltiples ocurrencias de 'isThreadSafe' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.isthreadsafe==Directiva Page: valor incorrecto para isThreadSafe +jsp.error.page.conflict.info=Directiva Page: es ilegal tener múltiples ocurrencias de 'info' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.info==Directiva Page: valor incorrecto para info +jsp.error.page.conflict.iserrorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'isErrorPage' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.iserrorpage==Directiva Page: valor incorrecto para isErrorPage +jsp.error.page.conflict.errorpage=Directiva Page: es ilegal tener múltiples ocurrencias de 'errorPage' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.conflict.language=Directiva Page: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.tag.conflict.language=Directiva Tag: es ilegal tener múltiples ocurrencias de 'language' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.language.nonjava=Directiva Page: atributo language incorrecto +jsp.error.tag.language.nonjava=Directiva Tag: atributo language incorrecto +jsp.error.page.defafterusar.language=Directiva Page: No puede definir language tras un scriptlet +jsp.error.page.nomapping.language=Directiva Page: No hay mapeado para language: +jsp.error.page.conflict.extends=Directiva Page: es ilegal tener múltiples ocurrencias de 'extends' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.conflict.iselignored=Directiva Page: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.tag.conflict.iselignored=Directiva Tag: es ilegal tener múltiples ocurrencias de 'isELIgnored' con valores distintos (viejo: {0}, nuevo: {1}) +jsp.error.page.invalid.iselignored=Directiva Page: valor inválido para isELIgnored +jsp.error.tag.invalid.iselignored=Directiva Tag: valor incorrecto para isELIgnored +jsp.error.page.multi.pageencoding=La directiva Page no debe de tener múltiples ocurrencias de pageencoding +jsp.error.tag.conflict.attr=Directiva Tag: es ilegal tener múltiples ocurrencias del atributo \"{0}\" con valores distintos (viejo: {1}, nuevo: {2}) +jsp.error.tag.multi.pageencoding=La directiva Tag no debe de tener múltiples ocurrencias de pageencoding +jsp.error.page.bad_b_and_a_combo=Directiva Page: Combinación ilegal de buffer=\"none\" y autoFlush=\"false\" +jsp.error.not.impl.taglib=Error Interno: Tag extensions no implementado +jsp.error.include.missing.file=No tiene argumento de nombre de fichero +jsp.error.include.bad.file=Argumento de nombre de fichero no válido +jsp.error.include.exception=No se puede incluir {0} +jsp.error.stream.closed=Stream cerrado +jsp.error.invalid.forward=Tag forward no válido +jsp.error.unknownException=¡Error no caturado!. Deberías de considerar el poner una página de error para avisar de los errores más elegantemente +jsp.error.invalid.directive=Directiva no válida +jsp.error.directive.istagfile=La Directiva {0} no puede usarse en archivo de tag +jsp.error.directive.isnottagfile=La Directiva {0} sólo se puede usar en un archivo de tag +jsp.error.tagfile.tld.name=El atributo \"name\" de la directiva tag tiene un valor {0} mientras que el tag \"name\" del elemento \"tag-file\" en el TLD es {1} +jsp.error.action.istagfile=La acción {0} no se puede usar en un archivo tag +jsp.error.action.isnottagfile=La acción {0} sólo se puede usar en archivos tag +jsp.error.unterminated=Tag {0} no terminado +jsp.error.usebean.notinsamefile=El Tag useBean debe de empezar y terminar en el mismo archivo físico +jsp.error.loadclass.taghandler=No se puede cargar la clase {0} +jsp.error.unable.compile=No se puede compilar la clase para JSP +jsp.error.unable.load=No se puede cargar la clase para JSP +jsp.error.unable.rename=No se puede renombrar el archivo de clase {0} a {1} +jsp.error.mandatory.atributo={0}: atributo obligatorio {1} perdido +jsp.engine.info=Motor Jasper JSP 2.0 +jsp.error.invalid.expression="{0}" contiene expresiones incorrectas: {1} +jsp.error.invalid.attribute={0}: Atributo incorrecto, {1} +jsp.error.usebean.class.notfound=Clase: {0} no hallada +jsp.error.file.cannot.read=No se puede leer el archivo: {0} +jsp.error.file.already.registered=El archivo {0} ya se ha visto, ¿podría ser un include recursivo? +jsp.error.file.not.registered=Archivo {0} not visto en include +jsp.error.quotes.unterminated=Comillas no terminadas +jsp.error.attr.quoted=El valor del atributo debería ir entre comillas +jsp.error.attr.novalue=Atributo {0} no tiene valor +jsp.error.tag.attr.unterminated=Lista de atributos del tag no terminada +jsp.error.param.noname=No hay nombre en el tag PARAM +jsp.error.param.novalue=No hay valor en el tag PARAM +jsp.error.beans.nullbean=Se ha intentado una operación de bean en un objeto nulo +jsp.error.beans.nobeaninfo=No se puede encontrar BeanInfo para el bean ''{0}'' seguramente la clase no existe +jsp.error.beans.introspection=Una excepción ha tenido lugar mientras se leía el método de lectura de la propiedad ''{0}'' en un bean del tipo ''{1}'':\n{2} +jsp.error.beans.nomethod=No puedo encontrar un método para leer la propiedad ''{0}'' en un bean del tipo ''{1}'' +jsp.error.beans.nomethod.setproperty=No puedo encontrar un método para escribir la propiedad ''{0}'' en un bean del tipo ''{2}'' +jsp.error.beans.noproperty=No puedo encontrar información de la propiedad ''{0}'' en un bean del tipo ''{1}'' +jsp.error.beans.setproperty.noindexset=No puedo poner la propiedad indexada +jsp.error.include.tag=Tag jsp:include no válido +jsp.error.include.noflush=jsp:include necesita tener \"flush=true\" +jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" es la única combinación válida en JSP 1.0 +jsp.error.attempt_to_clear_flushed_buffer=Error: Se ha intentado limpiar un buffer que ya había sido escrito +jsp.error.overflow=Error:Buffer de JSP desbordado +jsp.error.paramexpected=El tag \"param\" era esperado con los atributos \"name\" y \"value\" después del tag \"params\". +jsp.error.param.invalidUse=La acción jsp:param no debe de ser usada fuera de los elementos jsp:include, jsp:forward o jsp:params +jsp.error.params.invalidUse=jsp:params debe de ser un hijo directo de jsp:plugin +jsp.error.fallback.invalidUse=jsp:fallback debe de ser un hijo directo de jsp:plugin +jsp.error.namedAttribute.invalidUse=jsp:attribute debe de ser el subelemento de una acción estándar o de cliente +jsp.error.jspbody.invalidUse=jsp:body debe de ser el subelemento de una acción estándar o de cliente +jsp.error.closeindividualparam=El tag param necesita ser cerrado con \"/>\" +jsp.error.closeparams=El tag param necesita ser cerrado con /params +jsp.error.params.emptyBody=jsp:params debe de contener al menos un jsp:param anidado +jsp.error.params.illegalChild=jsp:params no debe de contener elementos anidados que no sean jsp:param +jsp.error.plugin.notype=Tipo no declarado en jsp:plugin +jsp.error.plugin.badtype=Valor ilegal para atributo 'type' en jsp:plugin: debe de ser 'bean' o 'applet' +jsp.error.plugin.nocode=Código no declarado en jsp:plugin +jsp.error.ise_on_clear=Es ilegal usar clear() cuando el tamaño del buffer es cero +jsp.error.setproperty.beanNotFound=setProperty: Bean {0} no encontrado +jsp.error.getproperty.beanNotFound=getProperty: Bean {0} no encontrado +jsp.error.setproperty.ClassNotFound=setProperty: clase {0} no encontrada +# typo ? +#jsp.error.setproperty.invalidSayntax=setProperty: can't have non-null value when property=* +jsp.error.setproperty.invalidSyantax=setProperty: No puede haber un valor no nulo cuando se ha especificado property=* +jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo para bean {0} no encontrado +jsp.error.setproperty.paramOrValue=setProperty: O param o value pueden estar presentes +jsp.error.setproperty.arrayVal=setProperty: No puede escribir en la propiedad de array {0} a través de una valor de cadena literal +jsp.warning.keepgen=Aviso: valor incorrecto para el initParam keepgen. Se usará el valor por defecto de \"false\" +jsp.warning.xpoweredBy=Aviso: valor incorrecto para el initParam xpoweredBy. Se usará el valor por defecto de \"false\" +jsp.warning.enablePooling=Aviso: valor incorrecto para el initParam enablePooling. Se usará el valor por defecto de \"true\" +jsp.warning.invalidTagPoolSize=Aviso: valor incorrecto para el parámetro init llamado tagPoolSize. Se usará la medida por defecto de {0} +jsp.warning.mappedFile=Aviso: valor incorrecto para el initParam mappedFile. Se usará el valor por defecto de \"false\" +jsp.warning.sendErrToClient=Aviso: valor incorrecto para el initParam sendErrToClient. Se usará el valor por defecto de \"false\" +jsp.warning.classDebugInfo=Aviso: valor incorrecto para el initParam classdebuginfo. Se usará el valor por defecto de \"false\" +jsp.warning.checkInterval=Aviso: valor incorrecto para el initParam checkInterval. Se usará el valor por defecto de \"300\" segundos +jsp.warning.development=Aviso: valor incorrecto para el initParam development. Se usará el valor por defecto de \"true\" +jsp.warning.fork=Aviso: valor incorrecto para el initParam fork. Se usará el valor por defecto de \"true\" +jsp.warning.reloading=Aviso: valor incorrecto para el initParam reloading. Se usará el valor por defecto de \"true\" +jsp.warning.dumpSmap=Aviso: valor incorrecto para el initParam dumpSmap. Se usará el valor por defecto de \"false\" +jsp.warning.genchararray=Aviso: valor incorrecto para el initParam genStrAsCharArray. Se usará el valor por defecto de \"false\" +jsp.warning.suppressSmap=Aviso: valor incorrecto para el initParam suppressSmap. Se usará el valor por defecto de \"false\" +jsp.error.badtaglib=No se puede abrir la biblioteca de tags {0}: {1} +jsp.error.badGetReader=No se puede crear un reader cuando el stream no tiene buffer +jsp.warning.unknown.element.in.taglib=Elemento desconocido ({0}) en taglib +jsp.warning.unknown.element.in.tag=Elemento desconocido ({0}) en tag +jsp.warning.unknown.element.in.tagfile=Elemento desconocido ({0}) en tag-file +jsp.warning.unknown.element.in.attribute=Elemento desconocido ({0}) en attribute +jsp.warning.unknown.element.in.variable=Elemento desconocido ({0}) en variable +jsp.warning.unknown.element.in.validator=Elemento desconocido ({0}) en validator +jsp.warning.unknown.element.in.initParam=Elemento desconocido ({0}) en init-param de validator +jsp.warning.unknown.element.in.function=Elemento desconocido ({0}) en function +jsp.error.more.than.one.taglib=Más de una biblioteca de tags en el TLD: {0} +jsp.error.teiclass.instantiation=No se puede cargar la clase TagExtraInfo llamada: {0} +jsp.error.non_null_tei_and_var_subelems=Tag {0} tiene uno o más subelementos variable y una clase TagExtraInfo que devuelve una o más VariableInfo +jsp.error.parse.error.in.TLD=Error de análisis en el descriptor de biblioteca de tags: {0} +jsp.error.unable.to.open.TLD=No se puede abrir el descriptor de biblioteca de tags: {0} +jsp.buffer.size.zero=Tamaño de buffer <= 0 +jsp.error.file.not.found=Archivo JSP \"{0}\" no encontrado +jsp.message.copyinguri=Copiando {0} en {1} +jsp.message.htmlcomment=\nQuitando comentario: \t{0} +jsp.message.handling_directive=\nResolviendo directiva: {0}\t{1} +jsp.message.handling_plugin=\nPlugin: {0} +jsp.message.package_name_is=El Nombre del Package es: {0} +jsp.message.class_name_is=El Nombre de la clase es: {0} +jsp.message.java_file_name_is=El Nombre del Archivo Java es: {0} +jsp.message.class_file_name_is=El Nombre del Archivo de clase es: {0} +jsp.message.accepted=Aceptó {0} en {1} +jsp.message.adding_jar=Añadiendo jar {0} a mi classpath +jsp.message.compiling_with=Compilado con: {0} +jsp.message.template_text=texto plantilla +jsp.error.missing_attribute=De acuerdo con el TLD el atributo {0} es obligatorio para el tag {1} +jsp.error.bad_attribute=El atributo {0} no es válido según el TLD especificado +jsp.error.tld.unable_to_read=Imposible de leer TLD \"{1}\" desde archivo JAR \"{0}\": {2} +jsp.error.tld.unable_to_get_jar=Imposible obtener recurso JAR \"{0}\" conteniendo TLD: {1} +jsp.error.tld.missing_jar=Falta recurso JAR \"{0}\" conteniendo TLD +jsp.error.webxml_not_found=No puedo localizar web.xml +jsp.cmd_line.usage=Uso: jsptoservlet [-dd ] [-keepgenerated] +jsp.message.cp_is=Classpath {0} es: {1} +jsp.error.unable.to_load_taghandler_class=No se puede cargar clase manejadora {0} del tag a causa de {1} +jsp.error.unable.to_find_method=No se puede encontrar el método de escritura para el atributo: {0} +jsp.error.unable.to_convert_string=No pude convertir un String a {0} para atributo {1} +jsp.error.unable.to_introspect=No se puede hacer introspección en manejador de tag clase: {0} a causa de {1} +jsp.error.bad_tag=No existe el tag {0} en la biblioteca importada con prefijo {1} +jsp.error.xml.bad_tag=No se ha definido el tag \"{0}\" en la biblioteca tag asociada con uri \"{1}\" +jsp.error.bad_string_Character=No puede extraer un Character desde un array de tamaño cero +jsp.error.bad_string_char=No puede extraer un char desde un array de tamaño cero +jsp.warning.compiler.class.cantcreate=No puedo crear una instancia de la clase especificada {0} de plugin del compilador debido a {1}. Se usará el compilador Java de Sun. +jsp.warning.compiler.class.notfound=No puedo encontrar una instancia de la clase {0} de plugin de compilador. Se usará el compilador del Java de Sun. +jsp.warning.compiler.path.notfound=Trayectoria del compilador especificado {0} no encontrada. Se usará el PATH del sistema. +jsp.error.jspc.uriroot_not_dir=La opción -uriroot debe de especificar un directorio ya existente +jsp.error.jspc.missingTarget=Falta target: Debe de especificar -webapp o -uriroot o una o más páginas JSP +jsp.error.jspc.no_uriroot=No se ha especificado uriroot y no puede ser localizado en los archivos JSP especificados +jspc.implicit.uriRoot=uriRoot implicitamente puesto a "{0}" +jspc.usage=Uso: jspc [--] \n\ +donde son:\n\ +\ -webapp Un directorio conteniendo una web-app. Todas las\n\ +\ páginas jsp serán compiladas recursivamente\n\ +o cualquier número de\n\ +\ Un Archivo para ser interpretado como una página jsp\n\ +y donde incluyen:\n\ +\ -help Muestra este mensaje de ayuda\n\ +\ -v Modo detallado\n\ +\ -d Directorio de salida\n\ +\ -l Muestra el nombre de la página JSP al ocurrir un fallo\n\ +\ -s Muestra el nombre de la página JSP al tener éxito\n\ +\ -p Nombre del package objetivo\n\ +\ (por defecto org.apache.jsp)\n\ +\ -c Nombre de la clase objetivo\n\ +\ (sólo se aplica a la primera página JSP)\n\ +\ -mapped Genera llamadas separadas a write() para cada línea de\n\ +\ HTML en el JSP\n\ +\ -die[#] Genera un código de retorno de error (#) en errores\n\ +\ fatales. (por defecto 1).\n\ +\ -uribase El directorio uri de donde deben de partir las\n\ +\ compilaciones. (por defecto "/")\n\ +\ -uriroot Igual que -webapp\n\ +\ -compile Compila los servlets generados\n\ +\ -webinc Crea unos mapeos parciales de servlet en el archivo\n\ +\ -webxml Crea un web.xml completo en el archivo.\n\ +\ -ieplugin Java Plugin classid para Internet Explorer\n\ +\ -classpath Pasa por alto la propiedad de sistema java.class.path\n\ +\ -xpoweredBy Añade cabecera de respuesta X-Powered-By\n\ +\ -trimSpaces Trim spaces in template text between actions, directives\n\ +\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ +\ -source Set the -source argument to the compiler (default 1.4)\n\ +\ -target Set the -target argument to the compiler (default 1.4)\n\ + +jspc.webxml.header=\n\ +\n\ +\n\ +\n\ +\n\ +\n +jspc.webxml.footer=\n\ +\n\ +\n +jspc.webinc.header=\n\ +\n +jspc.webinc.footer=\n\ +\n +jspc.webinc.insertEnd= +jspc.webinc.insertStart= +jspc.error.jasperException=error-el archivo ''{0}'' ha generado la excepción de sintáxis siguiente: {1} +jspc.error.generalException=ERROR-el archivo ''{0}'' ha generado la excepción general siguiente: +jspc.error.fileDoesNotExist=El archivo ''{0}'' utilizado como argumento no existe. +jspc.error.emptyWebApp=-webapp necesita un argumento de archivo +jsp.error.library.invalid=La página JSP es incorrecta de acuerdo a la biblioteca {0}: {1} +jsp.error.tlvclass.instantiation=No pude cargar o instanciar clase TagLibraryValidator: {0} +jsp.error.tlv.invalid.page=Mensajes de error de validación desde TagLibraryValidator para {0} in {1} +jsp.error.tei.invalid.attributes=Mensajes de error de validación desde TagExtraInfo para {0} +jsp.parser.sax.propertynotsupported=Propiedad SAX no soportada: {0} +jsp.parser.sax.propertynotrecognized=Propiedad SAX no reconocida: {0} +jsp.parser.sax.featurenotsupported=Característica SAX no soportada: {0} +jsp.parser.sax.featurenotrecognized=Característica SAX no reconocida: {0} +jsp.error.no.more.content=Alcanzado fin de contenido mietras se requería más análisis: ¿error de anidamiento de tag? +jsp.error.parse.xml=Error de análisis XML en archivo {0} +jsp.error.parse.xml.line=Error de análisis XML en archivo {0}: (línea {1}, col {2}) +jsp.error.parse.xml.scripting.invalid.body=El cuerpo de elemento {0} no debe de contener elementos XML +jsp.error.internal.tldinit=No pude inicializar TldLocationsCache: {0} +jsp.error.internal.filenotfound=Error Interno: Archivo {0} no hallado +jsp.error.internal.evaluator_not_found=Error interno: no pude cargar evaluador de expresiones +jsp.error.parse.xml.invalidPublicId=PUBLIC ID incorrecta: {0} +jsp.error.include.flush.invalid.value=Valor incorrecto para atributo flush: {0} +jsp.error.unsupported.encoding=Codificación no soportada: {0} +tld.error.variableNotAllowed=Es un error para un tag, que tiene uno o más subelementos variables, el tener una clase TagExtraInfo que devuelve un objeto no nulo. +jsp.error.tldInWebDotXmlNotFound=No pude localizar TLD {1} para URI {0} especificado en web.xml +jsp.error.taglibDirective.absUriCannotBeResolved=La uri absoluta: {0} no puede resolverse o en web.xml o el los archivos jar desplegados con esta aplicación +jsp.error.taglibDirective.missing.location=No se ha especificado ni el atributo \'uri\' ni el \'tagdir\' +jsp.error.taglibDirective.both_uri_and_tagdir=Se han especificado ambos atributos \'uri\' y \'tagdir\' +jsp.error.invalid.tagdir=El directorio de archivo Tag {0} no comienza con \"/WEB-INF/tags\" +jsp.error.unterminated.user.tag=Tag definido por usuario no terminado: tag final {0} no hallado o anidado incorrectamente +#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} +jspx.error.templateDataNotInJspCdata=Error de Validación: El Elemento <{0}> no puede tener datos plantilla. Los datos plantilla deben de estar encapsulados dentro de un elemento <jsp:text>. [JSP1.2 PFD sección 5.1.9]\nDatos de Plantilla en error: {1} +#Error while processing taglib jar file {0}: {1} +jsp.error.taglib.reserved.prefix=El prefijo taglib {0} está reservado +jsp.error.invalid.javaEncoding=Codificaciones java incorrectas. Intenté {0} y luego {1}. Ambas fallaron. +jsp.error.needAlternateJavaEncoding=La codificación java por defecto {0} es incorrecta en tu plataforma java. Se puede especificar una alternativa vía parámetro 'javaEncoding' de JspServlet. +#Error when compiling, used for jsp line number error messages +jsp.error.single.line.number=Ha tenido lugar un error en la línea: {0} en el archivo jsp: {1} +jsp.error.multiple.line.number=\n\nHa tenido lugar un error entre las líneas: {0} y {1} en el archivo jsp: {2}\n\n +jsp.error.corresponding.servlet=Error de servlet generado:\n +jsp.error.empty.body.not.allowed=Cuerpo vacío no permitido para {0} +jsp.error.jspbody.required=Se debe de usar jsp:body para especificar cuerpo tag para {0} si se usa jsp:attribute. +jsp.error.jspbody.emptybody.only=El tag {0} sólo puede tener jsp:attribute en su cuerpo. +jsp.error.no.scriptlets=Los elementos de Scripting (<%!, <jsp:declaration, <%=, <jsp:expression, <%, <jsp:scriptlet ) no están permitidos aquí. +jsp.error.internal.unexpected_node_type=Error Interno: Encontrado tipo de nodo inesperado +jsp.error.tld.fn.invalid.signature=Sintáxis incorrecta para firma de función en TLD. Biblioteca de Tag: {0}, Función: {1} +jsp.error.tld.fn.duplicate.name=Nombre duplicado de función {0} en biblioteca de tag {1} +jsp.error.tld.fn.invalid.signature.commaexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Coma ','. Biblioteca de Tag: {0}, Función: {1}. +jsp.error.tld.fn.invalid.signature.parenexpected=Sintáxis incorrecta para firma de función en TLD. Se esperaba Paréntesis '('. Biblioteca de Tag: {0}, Función: {1}. +jsp.error.tld.mandatory.element.missing=Falta o está vacío elemento TLD obligatorio: {0} +jsp.error.dynamic.attributes.not.implemented=El tag {0} declara que acepta atributos dinámicos pero no implementa la interfaz requerida +jsp.error.nomatching.fragment=No puedo hallar una directiva de atributo (con name={0} y fragment=true) antes de la directiva de fragment. +jsp.error.attribute.noequal=se esperaba símbolo igual +jsp.error.attribute.noquote=se esperaba símbolo comillas +jsp.error.attribute.unterminated=el atributo para {0} no está terminado correctamente +jsp.error.missing.tagInfo=El objeto TagInfo para {0} falta del TLD +jsp.error.fragmentwithtype=No puede especificar ambos atributos 'fragment' y 'type'. Si está presente 'fragment', 'type' se pone como 'javax.servlet.jsp.tagext.JspFragment' +jsp.error.fragmentwithrtexprvalue=No puede especificar ambos atributos 'fragment' y 'rtexprvalue'. Si está presente 'fragment', 'rtexprvalue' se pone como 'true' +jsp.error.fragmentWithDeclareOrScope=Ambos atributos 'fragment' y 'declare' o 'scope' se han especificado en la directiva variable +jsp.error.var_and_varReader=Sólo se puede especificar uno de \'var\' o \'varReader\' +jsp.error.missing_var_or_varReader=Falta atributo \'var\' o \'varReader\' +jsp.warning.bad.urlpattern.propertygroup=Valor malo {0} en el subelemento url-pattern en web.xml +jsp.error.unknown_attribute_type=Tipo de atributo desconocido ({1}) para atributo {0}. +jsp.error.jspelement.missing.name=Falta atributo obligatorio XML-style \'name\' +jsp.error.xmlns.redefinition.notimplemented=Error interno: Intento de redefinir xmlns:{0}. La redefinición de espacios de nombre no está implementada. +jsp.error.could.not.add.taglibraries=No pude añadir una o más bibliotecas. +jsp.error.duplicate.name.jspattribute=El atributo {0} especificado en la acción standard o custom también aparece como el valor del atributo name en jsp:attribute +jsp.error.not.in.template={0} no permitido en una plantilla cuerpo de texto. +jsp.error.badStandardAction=Acción estándar incorrecta +jsp.error.xml.badStandardAction=Acción estándar incorrecta: {0} +jsp.error.tagdirective.badbodycontent=body-content incorrecto ({0}) en directiva tag +jsp.error.simpletag.badbodycontent=El TLD para la clase {0} especifica un body-content es incorrecto (JSP) para un SimpleTag. +jsp.error.config_pagedir_encoding_mismatch=El Page-encoding especificado en jsp-property-group ({0}) es diferente del especificado en la diectiva page ({1}) +jsp.error.prolog_pagedir_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en la directiva page ({1}) +jsp.error.prolog_config_encoding_mismatch=El Page-encoding especificado en XML prolog ({0}) difiere del especificado en jsp-property-group ({1}) +jsp.error.attribute.custom.non_rt_with_expr=Según el TLD o la directiva attribute del archivo tag, el atributo {0} no acepta expresiones +jsp.error.attribute.standard.non_rt_with_expr=El atributo {0} de la acción estándar {1} no acepta expresiones +jsp.error.scripting.variable.missing_name=Imposible determinar nombre de variable de scripting desde atributo {0} +jasper.error.emptybodycontent.nonempty=Según el TLD, el tag {0} debe de estar vacío, pero no lo está +jsp.error.tagfile.nameNotUnique=El valor de {0} y el valor de {1} en la línea {2} son el mismo. +jsp.error.tagfile.nameFrom.noAttribute=No puedo hallar una directiva attribute con un atributo name con un valor \"{0}\", el valor de este atributo name-from-attribute. +jsp.error.tagfile.nameFrom.badAttribute=La directiva attribute (declarada en la línea {1} y cuyo atributo name es \"{0}\", el valor de este atributo name-from-attribute attribute) debe de ser del tipo java.lang.String, es \"required\" y no un \"rtexprvalue\". +jsp.error.page.noSession=No puedo acceder al ámbito de sesión en una página que no participa en una sesión +jsp.error.useBean.noSession=Es ilegal para useBean usar un ámbito de sesión cuando la página JSP declara (vía directiva page) que no participa en sesiones +jsp.error.xml.encodingByteOrderUnsupported=El orden de byte dado para encoding \"{0}\" no está soportado +jsp.error.xml.encodingDeclInvalid=Nombre de codificación \"{0}\" incorrecto. +jsp.error.xml.encodingDeclRequired=Se necesita la declaración encoding en la declaración de texto +jsp.error.xml.morePseudoAttributes=se esperan más pseudo-atributos +jsp.error.xml.noMorePseudoAttributes=no se permiten más pseudo-atributos. +jsp.error.xml.versionInfoRequired=Se requiere la versión en la declaración XML. +jsp.error.xml.xmlDeclUnterminated=La declaración XML debe de terminar con \"?>\". +jsp.error.xml.reservedPITarget=La instrucción de procesamiento que coincide con \"[xX][mM][lL]\" no está permitida. +jsp.error.xml.spaceRequiredInPI=Se necesita un espacio en blanco entre la instrucción de procesamiento y los datos. +jsp.error.xml.invalidCharInContent=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en el contenido del elemento del documento. +jsp.error.xml.spaceRequiredBeforeStandalone=Se necesita un espacio en blanco antes del pseudo-atributo encoding en la declaración XML. +jsp.error.xml.sdDeclInvalid=El valor de declaración de documento standalone debe de ser \"yes\" o \"no\", no \"{0}\". +jsp.error.xml.invalidCharInPI=Se halló un carácter XML incorrecto (Unicode: 0x{0}) en la instrucción de procesamiento +jsp.error.xml.versionNotSupported=No se soporta la versión XML \"{0}\", sólo se soporta XML 1.0 +jsp.error.xml.pseudoAttrNameExpected=se esperaba un pseudo-atributo name. +jsp.error.xml.expectedByte=Se esperaba byte {0} de {1}-byte de secuencia UTF-8. +jsp.error.xml.invalidByte=Incorrecto byte {0} de {1}-byte de secuencia UTF-8. +jsp.error.xml.operationNotSupported=La operación \"{0}\" no está soportada por lector {1}. +jsp.error.xml.invalidHighSurrogate=Surrogación Alta de bits en secuencia UTF-8 no debe de exceder 0x10, pero se halló 0x{0}. +jsp.error.xml.invalidASCII=El Byte \"{0}\" no es ASCII de 7-bit. +jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración XML. +jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo encoding en la declaración text. +jsp.error.xml.spaceRequiredBeforeVersionInTextDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración text. +jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl=Se necesita espacio en blanco antes del pseudo-atributo version en la declaración XML. +jsp.error.xml.eqRequiredInXMLDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración XML. +jsp.error.xml.eqRequiredInTextDecl=El carácter '' = '' debe de serguir a \"{0}\" en la declaración text. +jsp.error.xml.quoteRequiredInTextDecl=El valor que sigue a \"{0}\" en la declaración text debe de ser una cadena entre comillas. +jsp.error.xml.quoteRequiredInXMLDecl=El valor que sigue a \"{0}\" en la declaración XML debe de ser un cadena entre comillas. +jsp.error.xml.invalidCharInTextDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración text +jsp.error.xml.invalidCharInXMLDecl=Un carácter XML incorrecto (Unicode: 0x{0}) se halló en la declaración XML +jsp.error.xml.closeQuoteMissingInTextDecl=Faltan las comillas de cierre en el valor que sigue a \"{0}\" en la declaración text. +jsp.error.xml.closeQuoteMissingInXMLDecl=Faltan las comillas de cierre en el valor que sigue a \"{0}\" en la declaración XML. +jsp.error.multiple.jsp=No puedo tener múltiples especificaciones de +jsp.error.jspoutput.conflict=<jsp:output>: ilegal tener ocurrencias múltiples de \"{0}\" con diferentes valores (viejo: {1}, nuevo: {2}) +jsp.error.jspoutput.doctypenamesystem=<jsp:output>: atributos 'doctype-root-element' y 'doctype-system' deben de aparecer juntos +jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: atributo 'doctype-system' debe de aparecer si aparece atributo 'doctype-public' +jsp.error.jspoutput.nonemptybody=<jsp:output> no debe de tener un cuerpo +jsp.error.jspoutput.invalidUse=<jsp:output> no se debe de usar en sintáxis estándar +jsp.error.attributes.not.allowed = {0} no debe de tener atributos +jsp.error.tagfile.badSuffix=Falta sufijo \".tag\" en trayectoria de archivo de tag {0} +jsp.error.tagfile.illegalPath=Trayectoria de archivo de tag: {0}, debe de comenzar con \"/WEB-INF/tags\" o \"/META-INF/tags\" +jsp.error.plugin.wrongRootElement=El nombre del elemento raíz en {0} difiere de {1} +jsp.error.attribute.invalidPrefix=El prefijo de atributo {0} no se correponde con ninguna biblioteca importada +jsp.error.nested.jspattribute=Una acción estándar jsp:attribute no puede estar anidada dentro de otra acción estándar jsp:attribute +jsp.error.nested.jspbody=Una acción estándar jsp:body no puede estar anidada dentro de otra acción estándar jsp:body o jsp:attribute +jsp.error.variable.either.name=O el atributo name-given o name-from-attribute deben de ser especificados en una directiva variable +jsp.error.variable.both.name=No se puede especificar ambos atributos name-given o name-from-attribute en una directiva variable +jsp.error.variable.alias=Ambos atributos o ninguno de name-from-attribute y alias pueden ser especificados en una directiva variable +jsp.error.attribute.null_name=Nombre de atributo nulo +jsp.error.jsptext.badcontent=\'<\', cuando aparece en el cuerpo de <jsp:text>, debe de estar encapsulado dentro de un CDATA +jsp.error.jsproot.version.invalid=Número incorrecto de versión: \"{0}\", debe de ser \"1.2\" o \"2.0\" +jsp.error.noFunctionPrefix=La función {0} debe de usarse con un prefijo cuando no se especifica un espacio de nombres por defecto +jsp.error.noFunction=La función {0} no puede ser localizada mediante el prefijo especificado +jsp.error.noFunctionMethod=El método \"{0}\" para la función \"{1}\" no se pudo hallar en la clase \"{2}\" +jsp.error.function.classnotfound=La clase {0} especificada en el TLD para la función {1} no se puede hallar: {2} +jsp.error.signature.classnotfound=La clase {0} especificada en la firma del método en el TLD para la función {1} no se puede hallar. {2} +jsp.error.text.has_subelement=<jsp:text> no debe de tener subelementos +jsp.error.data.file.read=Error leyendo archivo \"{0}\" +jsp.error.prefix.refined=Intento de redefinir el prefijo {0} por {1}, cuando ya estaba definido como {2} en el ámbito en curso. +jsp.error.nested_jsproot=<jsp:root> anidado +jsp.error.unbalanced.endtag=El tgag final \"</{0}\" está desequilibrado +jsp.error.invalid.bean= diff --git a/java/org/apache/jasper/resources/LocalStrings_fr.properties b/java/org/apache/jasper/resources/LocalStrings_fr.properties index c29a5a8f3..c7588ad42 100644 --- a/java/org/apache/jasper/resources/LocalStrings_fr.properties +++ b/java/org/apache/jasper/resources/LocalStrings_fr.properties @@ -1,305 +1,305 @@ -# $Id: LocalStrings_fr.properties 349479 2005-11-28 19:44:47Z yoavs $ -# -# Default localized string information -# Localized this the Default Locale as is fr_FR - -jsp.error.bad.servlet.engine=Version de moteur de servlet incorrecte! -jsp.error.no.scratch.dir=Le moteur de JSP engine n''est pas configuré avec un répertoire de travail.\ -\n Merci d''ajouter \"jsp.initparams=scratchdir=\" \ -\n dans le fichier "servlets.properties" de ce contexte. -jsp.error.bad.scratch.dir=Le paramêtre "scratchDir" que vous avez spécifié: {0} est inutilisable. -jsp.message.scratch.dir.is=Le répertoire de travail (scratch dir) pour le moteur de JSP est: {0} -jsp.message.parent_class_loader_is=Le chargeur de classe parent (class loader) est: {0} -jsp.message.dont.modify.servlets=IMPORTANT: Ne pas modifier les servlets générées -jsp.error.not.impl.comments=Erreur interne: Commentaires non implémentés -jsp.error.not.impl.directives=Erreur interne: Directives non implémentées -jsp.error.not.impl.declarations=Erreur interne: Declarations non implémentées -jsp.error.not.impl.expressions=Erreur interne: Expressions non implémentées -jsp.error.not.impl.scriptlets=Erreur interne: Scriptlets non implémentés -jsp.error.not.impl.usebean=Erreur interne: useBean non implémenté -jsp.error.not.impl.getp=Erreur interne: getProperty non implémenté -jsp.error.not.impl.setp=Erreur interne: setProperty non implémenté -jsp.error.not.impl.plugin=Erreur interne: plugin non implémenté -jsp.error.not.impl.forward=Erreur interne: forward non implémenté -jsp.error.not.impl.include=Erreur interne: include non implémenté -jsp.error.unavailable=La JSP a été marquée comme non disponible -jsp.error.usebean.missing.attribute=useBean: l''identificateur d''attribut (id attribute) est manquant ou mal orthographié -jsp.error.usebean.missing.type=useBean ({0}): La classe ou le type d''attribut doit être\ -spécifié: -jsp.error.usebean.duplicate=useBean: Nom de bean dupliqué: {0} -jsp.error.usebean.prohibited.as.session=Impossible d''utiliser comme bean de session {0} car c''est interdit\ -par la directive jsp définie précédemment: -jsp.error.usebean.not.both=useBean: Impossible de spécifier à la fois la classe et l''attribut beanName: -jsp.error.usebean.bad.type.cast=useBean ({0}): Le type ({1}) n''est pas assignable depuis la classe ({2}) -jsp.error.classname=Impossible de déterminer le nom de classe d''après le fichier .class -jsp.warning.bad.type=Attention: mauvais type dans le fichier .class -jsp.error.data.file.write=Erreur lors de l''écriture du fichier de données -#Directive de Page: valeur incorrecte pour pageEncoding -jsp.error.page.invalid.contenttype=Directive de Page: valeur incorrecte pour contentType -jsp.error.page.invalid.session=Directive de Page: valeur incorrecte pour session -jsp.error.page.invalid.buffer=Directive de Page: valeur incorrecte pour "buffer" -jsp.error.page.invalid.autoflush=Directive de Page: valeur incorrecte pour autoFlush -jsp.error.page.invalid.isthreadsafe=Directive de Page: valeur incorrecte pour isThreadSafe -jsp.error.page.invalid.info=Directive de Page: valeur incorrecte pour info -jsp.error.page.invalid.iserrorpage=Directive de Page: valeur incorrecte pour isErrorPage -jsp.error.page.defafteruse.language=Directive de Page: on ne peut définir language après un scriptlet -jsp.error.page.nomapping.language=Directive de Page: Pas de correspondance pour language: -jsp.error.page.bad_b_and_a_combo=Directive de Page: combinaison illégale de buffer=\"none\" && autoFlush=\"false\" -jsp.error.not.impl.taglib=Internal error: Tag extensions non implémentés -jsp.error.include.missing.file=l''argument fichier (file) pour l''inclusion (include) est absent -jsp.error.include.bad.file=Mauvais argument fichier (file) pour l''inclusion (include) -jsp.error.include.exception=Impossible d''inclure (include) {0} -jsp.error.stream.closed=Flux fermé -jsp.error.invalid.forward=Tag forward incorrect -jsp.error.unknownException=Erreur non traitée! Vous devriez penser à utiliser une page d''erreur \ -pour rapporter ce type d''erreur plus élégamment -jsp.error.invalid.directive=Directive incorrecte -jsp.error.directive.istagfile=La directive {0} ne peut être utilisée dans un fichier tag -jsp.error.directive.isnottagfile=La directive {0} ne peut être utilisée que dans un fichier tag -jsp.error.tagfile.tld.name=L''attribut \"name\" de la directive tag contient la valeur {0} alors que le tag \"name\" de l''élément \"tag-file\" dans le TLD est {1} -jsp.error.action.istagfile=L''action {0} ne peut être utilisée dans un fichier tag -jsp.error.action.isnottagfile=L''action {0} ne peut être utilisée que dans un fichier tag -jsp.error.unterminated=Tag {0} non terminé -jsp.error.usebean.notinsamefile=le tag useBean doit commencé et finir dans le même fichier physique -jsp.error.loadclass.taghandler=Impossible de charger la classe {0} -jsp.error.unable.compile=Impossible de compiler la classe pour la JSP -jsp.error.unable.load=Impossible de charger la classe pour la JSP -jsp.error.unable.rename=Impossible de renommer le fichier classe de {0} vers {1} -jsp.error.mandatory.attribute={0}: L''attribut obligatoire {1} est manquant -jsp.engine.info=Moteur Jasper JSP 2.0 -jsp.error.invalid.expression="{0}" contient d''incorrecte(s) expression(s): {1} -jsp.error.invalid.attribute={0}: Attribut incorrect: {1} -jsp.error.usebean.class.notfound=Classe: {0} non trouvée -jsp.error.file.cannot.read=Impossible de lire le fichier: {0} -jsp.error.file.already.registered=Inclusion récursive du fichier {0} -jsp.error.file.not.registered=Le fichier {0} n''apparaît pas dans l''inclusion (include) -jsp.error.quotes.unterminated=guillemets non terminés -jsp.error.attr.quoted=La valeur de l''attribute doit être entre guillemets -jsp.error.attr.novalue=L''attribute {0} n''a pas de valeur -jsp.error.tag.attr.unterminated=Liste de tag d''attribut non terminée -jsp.error.param.noname=Pas de nom dans le tag PARAM -jsp.error.param.novalue=Pas de valeur dans le tag PARAM -jsp.error.beans.nullbean=Tentative d''opération bean sur un objet nul. -jsp.error.beans.nobeaninfo=Pas d''information bean (BeanInfo) pour le bean de type ''{0}'' n''a pu être trouvée, la classe n''existe probablement pas. -jsp.error.beans.introspection=Une exception s''est produite lors de l''introspection de la méthode read de la propriété ''{0}'' dans le bean de type ''{1}'':\n{2} -jsp.error.beans.nomethod=Impossible de trouver une méthode pour lire la propriété ''{0}'' dans le bean de type ''{1}'' -jsp.error.beans.nomethod.setproperty=Impossible de trouver une méthode pour mettre à jour la propriété ''{0}'' de type ''{1}''dans le bean de type ''{2}'' -jsp.error.beans.noproperty==Impossible de trouver de l''information sur la propriété ''{0}'' dans le bean de type ''{1}'' -jsp.error.beans.setproperty.noindexset=Impossible de renseigner la propriété indéxée -jsp.error.include.tag=Tag jsp:include incorrect -jsp.error.include.noflush=jsp:include doit avoir \"flush=true\" -jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" est la seule combinaison valide dans JSP 1.0 -jsp.error.attempt_to_clear_flushed_buffer=Erreur: Tentative d''effacement d''un tampon qui a déjà été vidangé (flush) -jsp.error.overflow=Erreur: Dépassement de capacité du tampon JSP -jsp.error.paramexpected=Le tag \"param\" est attendu avec les attributs \"name\" et \"value\" après le tag \"params\". -jsp.error.closeindividualparam=Le tag param doit être fermé avec \"/>\" -jsp.error.closeparams=Le tag param tag doit être fermé avec /params -jsp.error.plugin.notype=type non déclaré dans jsp:plugin -jsp.error.plugin.nocode=code non déclaré dans jsp:plugin -jsp.error.ise_on_clear=Il est interdit d''utiliser clear() quand la taille de tampon== 0 -jsp.error.setproperty.beanNotFound=setProperty: le Bean {0} est introuvable -jsp.error.getproperty.beanNotFound=getProperty: le Bean {0} est introuvable -jsp.error.setproperty.ClassNotFound=setProperty: la Classe {0} est introuvable -jsp.error.setproperty.invalidSyntax=setProperty: On ne peut avoir de valeur non nulle quand property=* -jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo pour le bean {0} est introuvable -jsp.error.setproperty.paramOrValue=setProperty: param ou value doit être présent -jsp.error.setproperty.arrayVal=setProperty: on ne peut renseigner les array property {0} au travers d''une valeur chaîne constante (string constant value) -jsp.warning.keepgen=Attention: Valeur incorrecte pour le initParam keepgenerated. Utilisation de la valeur par défaut \"false\" -jsp.warning.enablePooling=Attention: Valeur incorrecte pour le initParam enablePooling. Utilisation de la valeur par défaut \"true\" -jsp.warning.mappedFile=Attention: Valeur incorrecte pour le initParam mappedFile. Utilisation de la valeur par défaut \"false\" -jsp.warning.sendErrToClient=Attention: Valeur incorrecte pour le initParam sendErrToClient. Utilisation de la valeur par défaut \"false\" -jsp.warning.classDebugInfo=Attention: Valeur incorrecte pour le initParam classdebuginfo. Utilisation de la valeur par défaut \"false\" -jsp.warning.checkInterval=Attention: Valeur incorrecte pour le initParam checkInterval. Utilisation de la valeur par défaut \"300\" secondes -jsp.warning.development=Attention: Valeur incorrecte pour le initParam development. Utilisation de la valeur par défaut \"true\" -jsp.warning.reloading=Attention: Valeur incorrecte pour le initParam reloading. Utilisation de la valeur par défaut \"true\" -jsp.warning.reloading= -jsp.error.badtaglib=Impossible d''ouvrir le taglibrary {0} : {1} -jsp.error.badGetReader=Impossible de créer un lecteur (reader) quand le flux n''utilse pas des tampons (not buffered) -jsp.warning.unknown.element.in.TLD=Attention: Elément inconnu {0} dans le TLD -jsp.warning.unknown.element.in.tag=Attention: Elément inconnu {0} dans le tag -jsp.warning.unknown.element.in.tagfile=Attention: El?ment inconnu {0} dans le tag-file -jsp.warning.unknown.element.in.attribute=Attention: Elément inconnu {0} dans l''attribute -jsp.error.more.than.one.taglib=plus d''un taglib dans le TLD: {0} -jsp.error.teiclass.instantiation=Impossible de charger ou d''instancier la classe TagExtraInfo: {0} -jsp.error.non_null_tei_and_var_subelems=Le tag {0} possède une ou plusieurs variables subelements et une classe TagExtraInfo qui retourne une ou plusieurs VariableInfo -jsp.error.parse.error.in.TLD=Erreur d''évaluation (parse) dans le descripteur de librairie de tag (TLD): {0} -jsp.error.unable.to.open.TLD=Impossible d''ouvrir le descripteur de librairie de tag (TLD): {0} -jsp.buffer.size.zero=Taille du tampon <= 0 -jsp.error.file.not.found=Le fichier \"{0}\" n''a pas été trouvé -jsp.message.copyinguri=Copie de {0} dans {1} -jsp.message.htmlcomment=\nEffacement des commentaires: \t{0} -jsp.message.handling_directive=\nDirective de gestion (handling): {0}\t{1} -jsp.message.handling_plugin=\nPlugin: {0} -jsp.message.package_name_is=Le nom de package est: {0} -jsp.message.class_name_is=Le nom de classe est: {0} -jsp.message.java_file_name_is=Le nom de fichier Java est: {0} -jsp.message.class_file_name_is=Le nom de fichier Class est: {0} -jsp.message.accepted=Accepté {0} à {1} -jsp.message.adding_jar=Ajout du jar {0} à mon classpath -jsp.message.compiling_with=Compilation avec: {0} -jsp.message.template_text=texte template -jsp.error.missing_attribute=D''après le TLD l''attribut {0} est obligatoire pour le tag {1} -jsp.error.bad_attribute=L''attribut {0} est incorrect pour le tag {1} d''après la TLD indiquée -jsp.error.webxml_not_found=Impossible de localiser le fichier web.xml -jsp.cmd_line.usage=Usage: jsptoservlet [-dd ] [-keepgenerated] \ -<.jsp files> -jsp.message.cp_is=Le Classpath {0} est: {1} -jsp.error.unable.to_load_taghandler_class=Impossible de charger la classe gestionnaire de tag {0} car {1} -jsp.error.unable.to_find_method=Impossible de trouver une méthode de mise à jour pour l''attribut: {0} -jsp.error.unable.to_convert_string=Impossible de convertir une chaîne vers {0} pour l''attribut {1} -jsp.error.unable.to_introspect=Impossible d''introspecter la classe gestionnaire de tag : {0} car {1} -jsp.error.bad_tag=Aucun tag {0} dans la librairie de tag importée avec le préfixe {1} -jsp.error.bad_string_Character=Impossible d''extraire un caractère depuis un tableau vide -jsp.error.bad_string_char=Impossible d''extraire un caractère depuis un tableau vide -jsp.warning.compiler.class.cantcreate=Impossible de créer une instance de classe plugin pour le compilateur indiqué {0} due to {1}. Utilisation par défaut du Compilateur Java Sun. -jsp.warning.compiler.class.notfound=La classe plugin de compilateur {0} est introuvable. Utilisation par défaut du Compilateur Java Sun. -jsp.warning.compiler.path.notfound=le chemin de compilateur indiqué {0} est introuvable. Utilisation par défaut du chemin système (system PATH). -jsp.error.jspc.uriroot_not_dir=L''option -uriroot doit indiqué un répertoire déjà existant -jspc.implicit.uriRoot=uriRoot réglé implicitement à "{0}" -jspc.usage=Usage: jspc [--] \n\ -où les fichiers jsp sont n''importe quel nombre de:\n\ -\ Un fichier à évaluer (parser) comme page jsp\n\ -\ -webapp Un répertoire contenant une application web, toutes les pages jsp\n\ -\ seront récursivement évaluées\n\ -où les options comprennet:\n\ -\ -q Mode silencieux (identique à -v0)\n\ -\ -v[#] Mode bavard (Le nombre optionnel indique le niveau, 2 par défaut)\n\ -\ -d Dossier de sortie\n\ -\ -dd Dossier de sortie literal. (Les dossiers de paquets ne seront pas construits)\n\ -\ -l Sortie du nom la page JSP en cas d''échec\n\ -\ -s Sortie du nom la page JSP en cas de succès\n\ -\ -p Nom du paquet cible\n\ -\ -c Nom d'un nom de classe cible\n\ -\ (s''applique seulement à la première page JSP)\n\ -\ -mapped Génère des appels à write() séparés pour chaque ligne HTML dans la JSP\n\ -\ -die[#] Génère un code d''erreur de retour (#) en cas d''erreurs fatales.\n\ -\ Si le nombre est absent ou non numérique, le défaut est 1.\n\ -\ -uribase Le répertoire uri de compilations relatif\n\ -\ (Par défaut "/")\n\ -\ -uriroot The répertoire racine contre lequel les fichiers seront résolus\n\ -\ , (Par défaut le répertoire depuis lequel jspc est appelé)\n\ -\ -webinc Création d''association partielle de servlet pour l''option -webapp.\n\ -\ -webxml Création d''un fichier web.xml complet pour l''option -webapp.\n\ -\ -ieplugin Le classid du Plugin Java Plugin pour Internet Explorer\n\ -\ -sax2 Le nom de classe du Driver SAX 2.0 à utiliser\n\ -\ -trimSpaces Trim spaces in template text between actions, directives\n\ -\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ -\ -source Set the -source argument to the compiler (default 1.4)\n\ -\ -target Set the -target argument to the compiler (default 1.4)\n\ - -jspc.webxml.header=\n\ -\n\ -\n\ -\n\ -\n\ -\n -jspc.webxml.footer=\n\ -\n\ -\n -jspc.webinc.header=\n\ -\n -jspc.webinc.footer=\n\ -\n -jspc.error.jasperException=erreur-le fichier ''{0}'' a généré l''exception d''évaluation suivante: {1} -jspc.error.generalException=ERREUR-le fichier ''{0}'' a généré l''exception générale suivante: -jspc.error.fileDoesNotExist=L''argument fichier ''{0}'' n''existe pas -jspc.error.emptyWebApp=-webapp nécessite à sa suite un argument fichier -jsp.error.library.invalid=La page JSP page est incorrecte d''après la librairie {0}: {1} -jsp.error.tlvclass.instantiation=Impossible de charger ou d''instancier la classe TagLibraryValidator: {0} -jsp.error.tlv.invalid.page=Message d''erreurs de validation provenant du TagLibraryValidator pour {0} en {1} -jsp.error.tei.invalid.attributes=Message d''erreurs de validation provenant du TagExtraInfo pour {0} -jsp.parser.sax.propertynotsupported=Propriété SAX non supportée: {0} -jsp.parser.sax.propertynotrecognized=Propriété SAX non reconnue: {0} -jsp.parser.sax.featurenotsupported=Fonctionnalité SAX non supportée: {0} -jsp.parser.sax.featurenotrecognized=Fonctionnalité SAX non reconnue: {0} -jsp.error.no.more.content=Fin de contenu alors que l''évalution n''était pas terminée: erreur de tags imbriqués? -jsp.error.parse.xml=Erreur d''évaluation XML sur le fichier {0} -jsp.error.parse.xml.line=Erreur d''évaluation XML sur le fichier {0}: (ligne {1}, col {2}) -jsp.error.parse.xml.scripting.invalid.body=Le corps de l''élément {0} ne doit contenir aucun éléments XML -jsp.error.internal.tldinit=Exception lors de l'initialisation de TldLocationsCache: {0} -jsp.error.internal.filenotfound=Erreur interne: Fichier {0} introuvable -jsp.error.internal.evaluator_not_found=Erreur interne: Impossible de charger l''évaluateur d''expression -jsp.error.parse.xml.invalidPublicId=PUBLIC ID invalide: {0} -jsp.error.include.flush.invalid.value=Valeur incorrecte pour l''attribut flush: {0} -jsp.error.unsupported.encoding=Encodage non supporté: {0} -jsp.warning.unknown.element.in.variable=Attention: Element inconnu {0} dans la variable -tld.error.variableNotAllowed=Ceci est une erreur pour le tag qui possède une ou plusieurs variables subelements pour avoir une classe TagExtraInfo qui retourne un objet non-nul. -jsp.error.tldInWebDotXmlNotFound=Ne peut trouver le TLD {1} pour l''URI {0} indiquée dans le fichier web.xml -jsp.error.taglibDirective.absUriCannotBeResolved=L''uri absolue: {0} ne peut être résolu dans le fichier web.xml ou dans les fichiers jar déployés avec cette application -jsp.error.taglibDirective.missing.location=Ni l''uri' ni l''attribut 'tagdir' n''ont été indiqués dans la directive taglib -jsp.error.invalid.tagdir=Le répertoire du fichier Tag {0} ne commence pas par \"/WEB-INF/tags\" -jsp.error.unterminated.user.tag=Tag user-defined non terminé: Le tag de fermeture {0} est introuvable found ou incorrectement imbriqué -#jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément <{0}> ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément <jsp:cdata>. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1} -jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément <{0}> ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément <jsp:text>. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1} -#Erreur lors du traitement du fichier jar de la taglib {0}: {1} -jsp.error.taglib.reserved.prefix=Le préfixe taglib {0} est réservé -jsp.error.invalid.javaEncoding=Encodage java incorrect. Essai de {0} puis de {1}. Les deux ont échoué. -jsp.error.needAlternateJavaEncoding=L''encodage java par défaut {0} est incorrect sur votre environnement java. Une alternative peut être indiquée via le paramêtre 'javaEncoding' de la JspServlet. -#Erreur lors de la compilation, utilisé pour la ligne jsp des messages d''erreur -jsp.error.single.line.number=Une erreur s''est produite à la ligne: {0} dans le fichier jsp: {1} -jsp.error.multiple.line.number=\n\nUne erreur s''est produite entre les lignes: {0} et {1} dans le fichier jsp: {2}\n\n -jsp.error.corresponding.servlet=Erreur de servlet générée:\n -jsp.error.empty.body.not.allowed=Un corps vide n'est pas autorisé pour {0} -jsp.error.jspbody.required=Doit utiliser jsp:body pour indiqué le corps de tag body de {0} si jsp:attribute est utilisé. -jsp.error.jspbody.emptybody.only=Le tag {0} ne peut avoir que jsp:attribute dans son corps. -jsp.error.no.scriptlets=Les éléments de Scripting ( <%!, \" \ +\n dans le fichier "servlets.properties" de ce contexte. +jsp.error.bad.scratch.dir=Le paramêtre "scratchDir" que vous avez spécifié: {0} est inutilisable. +jsp.message.scratch.dir.is=Le répertoire de travail (scratch dir) pour le moteur de JSP est: {0} +jsp.message.parent_class_loader_is=Le chargeur de classe parent (class loader) est: {0} +jsp.message.dont.modify.servlets=IMPORTANT: Ne pas modifier les servlets générées +jsp.error.not.impl.comments=Erreur interne: Commentaires non implémentés +jsp.error.not.impl.directives=Erreur interne: Directives non implémentées +jsp.error.not.impl.declarations=Erreur interne: Declarations non implémentées +jsp.error.not.impl.expressions=Erreur interne: Expressions non implémentées +jsp.error.not.impl.scriptlets=Erreur interne: Scriptlets non implémentés +jsp.error.not.impl.usebean=Erreur interne: useBean non implémenté +jsp.error.not.impl.getp=Erreur interne: getProperty non implémenté +jsp.error.not.impl.setp=Erreur interne: setProperty non implémenté +jsp.error.not.impl.plugin=Erreur interne: plugin non implémenté +jsp.error.not.impl.forward=Erreur interne: forward non implémenté +jsp.error.not.impl.include=Erreur interne: include non implémenté +jsp.error.unavailable=La JSP a été marquée comme non disponible +jsp.error.usebean.missing.attribute=useBean: l''identificateur d''attribut (id attribute) est manquant ou mal orthographié +jsp.error.usebean.missing.type=useBean ({0}): La classe ou le type d''attribut doit être\ +spécifié: +jsp.error.usebean.duplicate=useBean: Nom de bean dupliqué: {0} +jsp.error.usebean.prohibited.as.session=Impossible d''utiliser comme bean de session {0} car c''est interdit\ +par la directive jsp définie précédemment: +jsp.error.usebean.not.both=useBean: Impossible de spécifier à la fois la classe et l''attribut beanName: +jsp.error.usebean.bad.type.cast=useBean ({0}): Le type ({1}) n''est pas assignable depuis la classe ({2}) +jsp.error.classname=Impossible de déterminer le nom de classe d''après le fichier .class +jsp.warning.bad.type=Attention: mauvais type dans le fichier .class +jsp.error.data.file.write=Erreur lors de l''écriture du fichier de données +#Directive de Page: valeur incorrecte pour pageEncoding +jsp.error.page.invalid.contenttype=Directive de Page: valeur incorrecte pour contentType +jsp.error.page.invalid.session=Directive de Page: valeur incorrecte pour session +jsp.error.page.invalid.buffer=Directive de Page: valeur incorrecte pour "buffer" +jsp.error.page.invalid.autoflush=Directive de Page: valeur incorrecte pour autoFlush +jsp.error.page.invalid.isthreadsafe=Directive de Page: valeur incorrecte pour isThreadSafe +jsp.error.page.invalid.info=Directive de Page: valeur incorrecte pour info +jsp.error.page.invalid.iserrorpage=Directive de Page: valeur incorrecte pour isErrorPage +jsp.error.page.defafteruse.language=Directive de Page: on ne peut définir language après un scriptlet +jsp.error.page.nomapping.language=Directive de Page: Pas de correspondance pour language: +jsp.error.page.bad_b_and_a_combo=Directive de Page: combinaison illégale de buffer=\"none\" && autoFlush=\"false\" +jsp.error.not.impl.taglib=Internal error: Tag extensions non implémentés +jsp.error.include.missing.file=l''argument fichier (file) pour l''inclusion (include) est absent +jsp.error.include.bad.file=Mauvais argument fichier (file) pour l''inclusion (include) +jsp.error.include.exception=Impossible d''inclure (include) {0} +jsp.error.stream.closed=Flux fermé +jsp.error.invalid.forward=Tag forward incorrect +jsp.error.unknownException=Erreur non traitée! Vous devriez penser à utiliser une page d''erreur \ +pour rapporter ce type d''erreur plus élégamment +jsp.error.invalid.directive=Directive incorrecte +jsp.error.directive.istagfile=La directive {0} ne peut être utilisée dans un fichier tag +jsp.error.directive.isnottagfile=La directive {0} ne peut être utilisée que dans un fichier tag +jsp.error.tagfile.tld.name=L''attribut \"name\" de la directive tag contient la valeur {0} alors que le tag \"name\" de l''élément \"tag-file\" dans le TLD est {1} +jsp.error.action.istagfile=L''action {0} ne peut être utilisée dans un fichier tag +jsp.error.action.isnottagfile=L''action {0} ne peut être utilisée que dans un fichier tag +jsp.error.unterminated=Tag {0} non terminé +jsp.error.usebean.notinsamefile=le tag useBean doit commencé et finir dans le même fichier physique +jsp.error.loadclass.taghandler=Impossible de charger la classe {0} +jsp.error.unable.compile=Impossible de compiler la classe pour la JSP +jsp.error.unable.load=Impossible de charger la classe pour la JSP +jsp.error.unable.rename=Impossible de renommer le fichier classe de {0} vers {1} +jsp.error.mandatory.attribute={0}: L''attribut obligatoire {1} est manquant +jsp.engine.info=Moteur Jasper JSP 2.0 +jsp.error.invalid.expression="{0}" contient d''incorrecte(s) expression(s): {1} +jsp.error.invalid.attribute={0}: Attribut incorrect: {1} +jsp.error.usebean.class.notfound=Classe: {0} non trouvée +jsp.error.file.cannot.read=Impossible de lire le fichier: {0} +jsp.error.file.already.registered=Inclusion récursive du fichier {0} +jsp.error.file.not.registered=Le fichier {0} n''apparaît pas dans l''inclusion (include) +jsp.error.quotes.unterminated=guillemets non terminés +jsp.error.attr.quoted=La valeur de l''attribute doit être entre guillemets +jsp.error.attr.novalue=L''attribute {0} n''a pas de valeur +jsp.error.tag.attr.unterminated=Liste de tag d''attribut non terminée +jsp.error.param.noname=Pas de nom dans le tag PARAM +jsp.error.param.novalue=Pas de valeur dans le tag PARAM +jsp.error.beans.nullbean=Tentative d''opération bean sur un objet nul. +jsp.error.beans.nobeaninfo=Pas d''information bean (BeanInfo) pour le bean de type ''{0}'' n''a pu être trouvée, la classe n''existe probablement pas. +jsp.error.beans.introspection=Une exception s''est produite lors de l''introspection de la méthode read de la propriété ''{0}'' dans le bean de type ''{1}'':\n{2} +jsp.error.beans.nomethod=Impossible de trouver une méthode pour lire la propriété ''{0}'' dans le bean de type ''{1}'' +jsp.error.beans.nomethod.setproperty=Impossible de trouver une méthode pour mettre à jour la propriété ''{0}'' de type ''{1}''dans le bean de type ''{2}'' +jsp.error.beans.noproperty==Impossible de trouver de l''information sur la propriété ''{0}'' dans le bean de type ''{1}'' +jsp.error.beans.setproperty.noindexset=Impossible de renseigner la propriété indéxée +jsp.error.include.tag=Tag jsp:include incorrect +jsp.error.include.noflush=jsp:include doit avoir \"flush=true\" +jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" est la seule combinaison valide dans JSP 1.0 +jsp.error.attempt_to_clear_flushed_buffer=Erreur: Tentative d''effacement d''un tampon qui a déjà été vidangé (flush) +jsp.error.overflow=Erreur: Dépassement de capacité du tampon JSP +jsp.error.paramexpected=Le tag \"param\" est attendu avec les attributs \"name\" et \"value\" après le tag \"params\". +jsp.error.closeindividualparam=Le tag param doit être fermé avec \"/>\" +jsp.error.closeparams=Le tag param tag doit être fermé avec /params +jsp.error.plugin.notype=type non déclaré dans jsp:plugin +jsp.error.plugin.nocode=code non déclaré dans jsp:plugin +jsp.error.ise_on_clear=Il est interdit d''utiliser clear() quand la taille de tampon== 0 +jsp.error.setproperty.beanNotFound=setProperty: le Bean {0} est introuvable +jsp.error.getproperty.beanNotFound=getProperty: le Bean {0} est introuvable +jsp.error.setproperty.ClassNotFound=setProperty: la Classe {0} est introuvable +jsp.error.setproperty.invalidSyntax=setProperty: On ne peut avoir de valeur non nulle quand property=* +jsp.error.setproperty.beanInfoNotFound=setproperty: beanInfo pour le bean {0} est introuvable +jsp.error.setproperty.paramOrValue=setProperty: param ou value doit être présent +jsp.error.setproperty.arrayVal=setProperty: on ne peut renseigner les array property {0} au travers d''une valeur chaîne constante (string constant value) +jsp.warning.keepgen=Attention: Valeur incorrecte pour le initParam keepgenerated. Utilisation de la valeur par défaut \"false\" +jsp.warning.enablePooling=Attention: Valeur incorrecte pour le initParam enablePooling. Utilisation de la valeur par défaut \"true\" +jsp.warning.mappedFile=Attention: Valeur incorrecte pour le initParam mappedFile. Utilisation de la valeur par défaut \"false\" +jsp.warning.sendErrToClient=Attention: Valeur incorrecte pour le initParam sendErrToClient. Utilisation de la valeur par défaut \"false\" +jsp.warning.classDebugInfo=Attention: Valeur incorrecte pour le initParam classdebuginfo. Utilisation de la valeur par défaut \"false\" +jsp.warning.checkInterval=Attention: Valeur incorrecte pour le initParam checkInterval. Utilisation de la valeur par défaut \"300\" secondes +jsp.warning.development=Attention: Valeur incorrecte pour le initParam development. Utilisation de la valeur par défaut \"true\" +jsp.warning.reloading=Attention: Valeur incorrecte pour le initParam reloading. Utilisation de la valeur par défaut \"true\" +jsp.warning.reloading= +jsp.error.badtaglib=Impossible d''ouvrir le taglibrary {0} : {1} +jsp.error.badGetReader=Impossible de créer un lecteur (reader) quand le flux n''utilse pas des tampons (not buffered) +jsp.warning.unknown.element.in.TLD=Attention: Elément inconnu {0} dans le TLD +jsp.warning.unknown.element.in.tag=Attention: Elément inconnu {0} dans le tag +jsp.warning.unknown.element.in.tagfile=Attention: El?ment inconnu {0} dans le tag-file +jsp.warning.unknown.element.in.attribute=Attention: Elément inconnu {0} dans l''attribute +jsp.error.more.than.one.taglib=plus d''un taglib dans le TLD: {0} +jsp.error.teiclass.instantiation=Impossible de charger ou d''instancier la classe TagExtraInfo: {0} +jsp.error.non_null_tei_and_var_subelems=Le tag {0} possède une ou plusieurs variables subelements et une classe TagExtraInfo qui retourne une ou plusieurs VariableInfo +jsp.error.parse.error.in.TLD=Erreur d''évaluation (parse) dans le descripteur de librairie de tag (TLD): {0} +jsp.error.unable.to.open.TLD=Impossible d''ouvrir le descripteur de librairie de tag (TLD): {0} +jsp.buffer.size.zero=Taille du tampon <= 0 +jsp.error.file.not.found=Le fichier \"{0}\" n''a pas été trouvé +jsp.message.copyinguri=Copie de {0} dans {1} +jsp.message.htmlcomment=\nEffacement des commentaires: \t{0} +jsp.message.handling_directive=\nDirective de gestion (handling): {0}\t{1} +jsp.message.handling_plugin=\nPlugin: {0} +jsp.message.package_name_is=Le nom de package est: {0} +jsp.message.class_name_is=Le nom de classe est: {0} +jsp.message.java_file_name_is=Le nom de fichier Java est: {0} +jsp.message.class_file_name_is=Le nom de fichier Class est: {0} +jsp.message.accepted=Accepté {0} à {1} +jsp.message.adding_jar=Ajout du jar {0} à mon classpath +jsp.message.compiling_with=Compilation avec: {0} +jsp.message.template_text=texte template +jsp.error.missing_attribute=D''après le TLD l''attribut {0} est obligatoire pour le tag {1} +jsp.error.bad_attribute=L''attribut {0} est incorrect pour le tag {1} d''après la TLD indiquée +jsp.error.webxml_not_found=Impossible de localiser le fichier web.xml +jsp.cmd_line.usage=Usage: jsptoservlet [-dd ] [-keepgenerated] \ +<.jsp files> +jsp.message.cp_is=Le Classpath {0} est: {1} +jsp.error.unable.to_load_taghandler_class=Impossible de charger la classe gestionnaire de tag {0} car {1} +jsp.error.unable.to_find_method=Impossible de trouver une méthode de mise à jour pour l''attribut: {0} +jsp.error.unable.to_convert_string=Impossible de convertir une chaîne vers {0} pour l''attribut {1} +jsp.error.unable.to_introspect=Impossible d''introspecter la classe gestionnaire de tag : {0} car {1} +jsp.error.bad_tag=Aucun tag {0} dans la librairie de tag importée avec le préfixe {1} +jsp.error.bad_string_Character=Impossible d''extraire un caractère depuis un tableau vide +jsp.error.bad_string_char=Impossible d''extraire un caractère depuis un tableau vide +jsp.warning.compiler.class.cantcreate=Impossible de créer une instance de classe plugin pour le compilateur indiqué {0} due to {1}. Utilisation par défaut du Compilateur Java Sun. +jsp.warning.compiler.class.notfound=La classe plugin de compilateur {0} est introuvable. Utilisation par défaut du Compilateur Java Sun. +jsp.warning.compiler.path.notfound=le chemin de compilateur indiqué {0} est introuvable. Utilisation par défaut du chemin système (system PATH). +jsp.error.jspc.uriroot_not_dir=L''option -uriroot doit indiqué un répertoire déjà existant +jspc.implicit.uriRoot=uriRoot réglé implicitement à "{0}" +jspc.usage=Usage: jspc [--] \n\ +où les fichiers jsp sont n''importe quel nombre de:\n\ +\ Un fichier à évaluer (parser) comme page jsp\n\ +\ -webapp Un répertoire contenant une application web, toutes les pages jsp\n\ +\ seront récursivement évaluées\n\ +où les options comprennet:\n\ +\ -q Mode silencieux (identique à -v0)\n\ +\ -v[#] Mode bavard (Le nombre optionnel indique le niveau, 2 par défaut)\n\ +\ -d Dossier de sortie\n\ +\ -dd Dossier de sortie literal. (Les dossiers de paquets ne seront pas construits)\n\ +\ -l Sortie du nom la page JSP en cas d''échec\n\ +\ -s Sortie du nom la page JSP en cas de succès\n\ +\ -p Nom du paquet cible\n\ +\ -c Nom d'un nom de classe cible\n\ +\ (s''applique seulement à la première page JSP)\n\ +\ -mapped Génère des appels à write() séparés pour chaque ligne HTML dans la JSP\n\ +\ -die[#] Génère un code d''erreur de retour (#) en cas d''erreurs fatales.\n\ +\ Si le nombre est absent ou non numérique, le défaut est 1.\n\ +\ -uribase Le répertoire uri de compilations relatif\n\ +\ (Par défaut "/")\n\ +\ -uriroot The répertoire racine contre lequel les fichiers seront résolus\n\ +\ , (Par défaut le répertoire depuis lequel jspc est appelé)\n\ +\ -webinc Création d''association partielle de servlet pour l''option -webapp.\n\ +\ -webxml Création d''un fichier web.xml complet pour l''option -webapp.\n\ +\ -ieplugin Le classid du Plugin Java Plugin pour Internet Explorer\n\ +\ -sax2 Le nom de classe du Driver SAX 2.0 à utiliser\n\ +\ -trimSpaces Trim spaces in template text between actions, directives\n\ +\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ +\ -source Set the -source argument to the compiler (default 1.4)\n\ +\ -target Set the -target argument to the compiler (default 1.4)\n\ + +jspc.webxml.header=\n\ +\n\ +\n\ +\n\ +\n\ +\n +jspc.webxml.footer=\n\ +\n\ +\n +jspc.webinc.header=\n\ +\n +jspc.webinc.footer=\n\ +\n +jspc.error.jasperException=erreur-le fichier ''{0}'' a généré l''exception d''évaluation suivante: {1} +jspc.error.generalException=ERREUR-le fichier ''{0}'' a généré l''exception générale suivante: +jspc.error.fileDoesNotExist=L''argument fichier ''{0}'' n''existe pas +jspc.error.emptyWebApp=-webapp nécessite à sa suite un argument fichier +jsp.error.library.invalid=La page JSP page est incorrecte d''après la librairie {0}: {1} +jsp.error.tlvclass.instantiation=Impossible de charger ou d''instancier la classe TagLibraryValidator: {0} +jsp.error.tlv.invalid.page=Message d''erreurs de validation provenant du TagLibraryValidator pour {0} en {1} +jsp.error.tei.invalid.attributes=Message d''erreurs de validation provenant du TagExtraInfo pour {0} +jsp.parser.sax.propertynotsupported=Propriété SAX non supportée: {0} +jsp.parser.sax.propertynotrecognized=Propriété SAX non reconnue: {0} +jsp.parser.sax.featurenotsupported=Fonctionnalité SAX non supportée: {0} +jsp.parser.sax.featurenotrecognized=Fonctionnalité SAX non reconnue: {0} +jsp.error.no.more.content=Fin de contenu alors que l''évalution n''était pas terminée: erreur de tags imbriqués? +jsp.error.parse.xml=Erreur d''évaluation XML sur le fichier {0} +jsp.error.parse.xml.line=Erreur d''évaluation XML sur le fichier {0}: (ligne {1}, col {2}) +jsp.error.parse.xml.scripting.invalid.body=Le corps de l''élément {0} ne doit contenir aucun éléments XML +jsp.error.internal.tldinit=Exception lors de l'initialisation de TldLocationsCache: {0} +jsp.error.internal.filenotfound=Erreur interne: Fichier {0} introuvable +jsp.error.internal.evaluator_not_found=Erreur interne: Impossible de charger l''évaluateur d''expression +jsp.error.parse.xml.invalidPublicId=PUBLIC ID invalide: {0} +jsp.error.include.flush.invalid.value=Valeur incorrecte pour l''attribut flush: {0} +jsp.error.unsupported.encoding=Encodage non supporté: {0} +jsp.warning.unknown.element.in.variable=Attention: Element inconnu {0} dans la variable +tld.error.variableNotAllowed=Ceci est une erreur pour le tag qui possède une ou plusieurs variables subelements pour avoir une classe TagExtraInfo qui retourne un objet non-nul. +jsp.error.tldInWebDotXmlNotFound=Ne peut trouver le TLD {1} pour l''URI {0} indiquée dans le fichier web.xml +jsp.error.taglibDirective.absUriCannotBeResolved=L''uri absolue: {0} ne peut être résolu dans le fichier web.xml ou dans les fichiers jar déployés avec cette application +jsp.error.taglibDirective.missing.location=Ni l''uri' ni l''attribut 'tagdir' n''ont été indiqués dans la directive taglib +jsp.error.invalid.tagdir=Le répertoire du fichier Tag {0} ne commence pas par \"/WEB-INF/tags\" +jsp.error.unterminated.user.tag=Tag user-defined non terminé: Le tag de fermeture {0} est introuvable found ou incorrectement imbriqué +#jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément <{0}> ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément <jsp:cdata>. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1} +jspx.error.templateDataNotInJspCdata=Erreur de validation: l''élément <{0}> ne peut avoir de données template. Les données Template doivent être encapsulées à l''intérieur d''un élément <jsp:text>. [JSP1.2 PFD section 5.1.9]\nDonnée Template en erreur: {1} +#Erreur lors du traitement du fichier jar de la taglib {0}: {1} +jsp.error.taglib.reserved.prefix=Le préfixe taglib {0} est réservé +jsp.error.invalid.javaEncoding=Encodage java incorrect. Essai de {0} puis de {1}. Les deux ont échoué. +jsp.error.needAlternateJavaEncoding=L''encodage java par défaut {0} est incorrect sur votre environnement java. Une alternative peut être indiquée via le paramêtre 'javaEncoding' de la JspServlet. +#Erreur lors de la compilation, utilisé pour la ligne jsp des messages d''erreur +jsp.error.single.line.number=Une erreur s''est produite à la ligne: {0} dans le fichier jsp: {1} +jsp.error.multiple.line.number=\n\nUne erreur s''est produite entre les lignes: {0} et {1} dans le fichier jsp: {2}\n\n +jsp.error.corresponding.servlet=Erreur de servlet générée:\n +jsp.error.empty.body.not.allowed=Un corps vide n'est pas autorisé pour {0} +jsp.error.jspbody.required=Doit utiliser jsp:body pour indiqué le corps de tag body de {0} si jsp:attribute est utilisé. +jsp.error.jspbody.emptybody.only=Le tag {0} ne peut avoir que jsp:attribute dans son corps. +jsp.error.no.scriptlets=Les éléments de Scripting ( <%!, \" \u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002 -jsp.error.bad.scratch.dir=\u3042\u306a\u305f\u304c\u6307\u5b9a\u3057\u305fscratchDir\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.message.scratch.dir.is=JSP\u30a8\u30f3\u30b8\u30f3\u306eScratchdir: {0} -jsp.message.parent_class_loader_is=\u89aa\u30af\u30e9\u30b9\u30ed\u30fc\u30c0: {0} -jsp.message.dont.modify.servlets=\u91cd\u8981: \u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u5909\u66f4\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.not.impl.comments=\u5185\u90e8\u30a8\u30e9\u30fc: Comments\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.directives=\u5185\u90e8\u30a8\u30e9\u30fc: Directives\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.declarations=\u5185\u90e8\u30a8\u30e9\u30fc: Declarations\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.expressions=\u5185\u90e8\u30a8\u30e9\u30fc: Expressions\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.scriptlets=\u5185\u90e8\u30a8\u30e9\u30fc: Scriptlets\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.usebean=\u5185\u90e8\u30a8\u30e9\u30fc: useBean\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.getp=\u5185\u90e8\u30a8\u30e9\u30fc: getProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.setp=\u5185\u90e8\u30a8\u30e9\u30fc: setProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.plugin=\u5185\u90e8\u30a8\u30e9\u30fc: plugin\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.forward=\u5185\u90e8\u30a8\u30e9\u30fc: forward\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.not.impl.include=\u5185\u90e8\u30a8\u30e9\u30fc: include\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.unavailable=JSP\u306f\u5229\u7528\u4e0d\u53ef\u3068\u30de\u30fc\u30af\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.usebean.missing.attribute=useBean: id\u5c5e\u6027\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3001\u30b9\u30da\u30eb\u30df\u30b9\u3067\u3059 -jsp.error.usebean.missing.type=useBean ({0}): class\u5c5e\u6027\u304btype\u5c5e\u6027\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044: -jsp.error.usebean.duplicate=useBean: beanName\u5c5e\u6027\u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059: {0} -jsp.error.usebean.prohibited.as.session=\u4ee5\u524d\u306b\u5b9a\u7fa9\u3057\u305fJSP\u6307\u793a\u5b50\u306b\u3088\u3063\u3066\u7981\u6b62\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u3001session bean {0} \u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093: -jsp.error.usebean.not.both=useBean: class\u5c5e\u6027\u3068beanName\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u540c\u6642\u306b\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093: -jsp.error.usebean.bad.type.cast=useBean ({0}): type ({1}) \u306fclass ({2}) \u304b\u3089\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093 -jsp.error.invalid.scope='scope'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: {0} (\"page\"\u3001\"request\"\u3001\"session\"\u53c8\u306f\"application\"\u306e\u3069\u308c\u304b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093) -jsp.error.classname=.class\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u30af\u30e9\u30b9\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.warning.bad.type=\u8b66\u544a: .class\u30d5\u30a1\u30a4\u30eb\u4e2d\u306e\u578b\u304c\u9055\u3044\u307e\u3059 -jsp.error.data.file.write=\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304d\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 -jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: \u7121\u52b9\u306a\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3067\u3059 -jsp.error.page.conflict.contenttype=page\u6307\u793a\u5b50: 'contentType'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.contenttype=page\u6307\u793a\u5b50: contentType\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.session=page\u6307\u793a\u5b50: 'session'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.session=page\u6307\u793a\u5b50: session\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.buffer=page\u6307\u793a\u5b50: 'buffer'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: buffer\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.autoflush=page\u6307\u793a\u5b50: 'autoFlush'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.autoflush=page\u6307\u793a\u5b50: autoFlush\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.isthreadsafe=page\u6307\u793a\u5b50: 'isThreadSafe'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.isthreadsafe=page\u6307\u793a\u5b50: isThreadSafe\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.info=page\u6307\u793a\u5b50: 'info'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.info=page\u6307\u793a\u5b50: info\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.iserrorpage=page\u6307\u793a\u5b50: 'isErrorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.iserrorpage=page\u6307\u793a\u5b50: isErrorPage\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.page.conflict.errorpage=page\u6307\u793a\u5b50: 'errorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.conflict.language=page\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.tag.conflict.language=tag\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.language.nonjava=page\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059 -jsp.error.tag.language.nonjava=tag\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059 -jsp.error.page.defafteruse.language=page\u6307\u793a\u5b50: scriptlet\u306e\u5f8c\u3067language\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.error.page.nomapping.language=page\u6307\u793a\u5b50 language\u5c5e\u6027\u306e\u30de\u30c3\u30d4\u30f3\u30b0\u304c\u5b58\u5728\u3057\u307e\u305b\u3093: -jsp.error.page.conflict.extends=page\u6307\u793a\u5b50: 'extends'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.conflict.iselignored=page\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.tag.conflict.iselignored=tag\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) -jsp.error.page.invalid.iselignored=page\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.tag.invalid.iselignored=tag\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.page.multi.pageencoding=page\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.tag.conflict.attr=Tag\u6307\u793a\u5b50: \u5c5e\u6027\"{0}\"\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u4e0d\u6b63\u3067\u3059 (\u65e7: {1}, \u65b0: {2}) -jsp.error.tag.multi.pageencoding=tag\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.page.bad_b_and_a_combo=page\u6307\u793a\u5b50: buffer=\"none\"\u3068autoFlush=\"false\"\u3092\u540c\u6642\u306b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.error.not.impl.taglib=\u5185\u90e8\u30a8\u30e9\u30fc: \u30bf\u30b0\u62e1\u5f35\u5b50\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.include.missing.file=\u53d6\u308a\u8fbc\u3080\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.include.bad.file=include\u5c5e\u6027\u306e\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059 -jsp.error.include.exception={0} \u3092\u53d6\u308a\u8fbc\u3081\u307e\u305b\u3093 -jsp.error.stream.closed=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.invalid.forward=\u7121\u52b9\u306aforward\u30bf\u30b0\u3067\u3059 -jsp.error.unknownException=\u51e6\u7406\u4e0d\u53ef\u80fd\u306a\u30a8\u30e9\u30fc\u3067\u3059! \u3053\u306e\u3088\u3046\u306a\u30a8\u30e9\u30fc\u3092\u3088\u308a\u8a73\u7d30\u306b\u5831\u544a\u3059\u308b\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u3092\u6301\u3063\u305f\u65b9\u304c\u3088\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093 -jsp.error.invalid.directive=\u7121\u52b9\u306a\u6307\u793a\u5b50\u3067\u3059 -jsp.error.directive.istagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.error.directive.isnottagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u3057\u304b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.error.tagfile.tld.name=TLD\u4e2d\u306e\u30bf\u30b0\u6307\u793a\u5b50\u306e\"tag-file\"\u8981\u7d20\u306e\"name\"\u30bf\u30b0\u306f {1} \u3067\u3059\u304c\uff0c\"name\"\u5c5e\u6027\u306f\u5024 {0} \u3092\u6301\u3063\u3066\u3044\u307e\u3059 -jsp.error.action.istagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.error.action.isnottagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306e\u307f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 -jsp.error.unterminated={0} \u30bf\u30b0\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.usebean.notinsamefile=useBean\u30bf\u30b0\u306f\u3001\u540c\u4e00\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u958b\u59cb\u3057\u3001\u7d42\u4e86\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.loadclass.taghandler=\u30bf\u30b0 \"{1}\" \u306b\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 \"{0}\" \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -jsp.error.unable.compile=JSP\u306e\u30af\u30e9\u30b9\u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u3067\u304d\u307e\u305b\u3093 -jsp.error.unable.load=JSP\u306e\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -jsp.error.unable.rename=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u30d5\u30a1\u30a4\u30eb\u540d\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 -jsp.error.mandatory.attribute={0}: \u5fc5\u9808\u5c5e\u6027 {1} \u304c\u3042\u308a\u307e\u305b\u3093 -jsp.engine.info=Jasper JSP 2.0\u30a8\u30f3\u30b8\u30f3 -jsp.error.invalid.expression="{0}" \u306f\u7121\u52b9\u306a\u5f0f\u3092\u542b\u3093\u3067\u3044\u307e\u3059: {1} -jsp.error.invalid.attribute={0}\u306f\u7121\u52b9\u306a\u5c5e\u6027\u3092\u6301\u3063\u3066\u3044\u307e\u3059: {1} -jsp.error.usebean.class.notfound=\u30af\u30e9\u30b9: {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.file.cannot.read=\u30d5\u30a1\u30a4\u30eb\u304c\u8aad\u3081\u307e\u305b\u3093: {0} -jsp.error.file.already.registered=\u30d5\u30a1\u30a4\u30eb {0} \u306e\u518d\u5e30\u7684\u306a\u53d6\u308a\u8fbc\u307f\u3067\u3059 -jsp.error.file.not.registered=include\u5c5e\u6027\u4e2d\u306e\u30d5\u30a1\u30a4\u30eb {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 -jsp.error.quotes.unterminated=\u5f15\u7528\u7b26\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.attr.quoted=\u5c5e\u6027\u5024\u306f\u5f15\u7528\u7b26\u3067\u56f2\u308f\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.attr.novalue=\u5c5e\u6027 {0} \u306b\u306f\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.tag.attr.unterminated=\u30bf\u30b0\u306e\u5c5e\u6027\u30ea\u30b9\u30c8\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.param.noname=PARAM\u30bf\u30b0\u306bname\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.param.novalue=PARAM\u30bf\u30b0\u306bvalue\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.beans.nullbean=null\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306bBean\u64cd\u4f5c\u3092\u304a\u3053\u306a\u304a\u3046\u3068\u3057\u307e\u3057\u305f -jsp.error.beans.nobeaninfo=\u30bf\u30a4\u30d7 ''{0}'' \u306eBean\u306bBeanInfo\u304c\u306a\u3044\u306e\u3092\u691c\u51fa\u3057\u307e\u3057\u305f, \u30af\u30e9\u30b9\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093 -jsp.error.beans.introspection=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306eread\u30e1\u30bd\u30c3\u30c9\u3092\u5185\u7701\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f:\n{2} -jsp.error.beans.nomethod=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u3092\u8aad\u307f\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f -jsp.error.beans.nomethod.setproperty=\u30bf\u30a4\u30d7''{2}''\u306eBean\u306e\u30bf\u30a4\u30d7 ''{1}'' \u306e\u5c5e\u6027 ''{0}'' \u3092\u66f8\u304d\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f -jsp.error.beans.noproperty=\u30bf\u30a4\u30d7 ''{1}'' \u306ebean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306e\u60c5\u5831\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f -jsp.error.beans.setproperty.noindexset=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4ed8\u304d\u306e\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.error.include.tag=\u7121\u52b9\u306ajsp:include\u30bf\u30b0\u3067\u3059 -jsp.error.include.noflush=jsp:include\u30bf\u30b0\u306b \"flush=true\" \u3092\u5b9a\u7fa9\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" \u306f\u3001JSP 1.0\u3067\u306e\u307f\u6709\u52b9\u306a\u7d44\u307f\u5408\u308f\u305b\u3067\u3059 -jsp.error.attempt_to_clear_flushed_buffer=\u30a8\u30e9\u30fc: \u65e2\u306b\u30d5\u30e9\u30c3\u30b7\u30e5\u3055\u308c\u3066\u3044\u308b\u30d0\u30c3\u30d5\u30a1\u3092\u30af\u30ea\u30a2\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f -jsp.error.overflow=\u30a8\u30e9\u30fc: JSP\u30d0\u30c3\u30d5\u30a1\u304c\u30aa\u30fc\u30d0\u30fc\u30d5\u30ed\u30fc\u3057\u307e\u3057\u305f -jsp.error.paramexpected=\"name\"\u5c5e\u6027 \u3068 \"value\" \u5c5e\u6027\u3092\u6301\u3064 \"jsp:param\" \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.param.invalidUse=jsp:include\u3001jsp:forward\u3001\u53c8\u306fjsp:params\u8981\u7d20\u306e\u5916\u3067jsp:param\u30a2\u30af\u30b7\u30e7\u30f3\u3092\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.params.invalidUse=jsp:params\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.fallback.invalidUse=jsp:fallback\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.namedAttribute.invalidUse=jsp:attribute\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspbody.invalidUse=jsp:body\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.closeindividualparam=param\u30bf\u30b0\u306f \"/>\" \u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.closeparams=param\u30bf\u30b0\u306f/params\u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.params.emptyBody=jsp:params\u306f\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u30cd\u30b9\u30c8\u3057\u305fjsp:param\u3092\u542b\u307e\u306d\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.params.illegalChild=jsp:params\u306fjsp:param\u4ee5\u5916\u306e\u30cd\u30b9\u30c8\u3057\u305f\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.plugin.notype=jsp:plugin\u3067type\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.plugin.badtype=jsp:plugin\u306e 'type'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: 'bean'\u53c8\u306f'applet'\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.plugin.nocode=jsp:plugin\u3067code\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.ise_on_clear=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u306e\u6642\u306bclear()\u3092\u5b9f\u884c\u3057\u3066\u3082\u7121\u52b9\u3067\u3059 -jsp.error.setproperty.beanNotFound=setProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.getproperty.beanNotFound=getProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.setproperty.ClassNotFound=setProperty: \u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -# typo ? -#jsp.error.setproperty.invalidSayntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.error.setproperty.invalidSyntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.error.setproperty.beanInfoNotFound=setproperty: Bean {0} \u306ebeanInfo\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.setproperty.paramOrValue=setProperty: param\u5c5e\u6027\u304bvalue\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3060\u3051\u3092\u6307\u5b9a\u3067\u304d\u307e\u3059 -jsp.error.setproperty.arrayVal=setProperty: \u5c5e\u6027\u914d\u5217 {0} \u3092\u6587\u5b57\u5217\u5b9a\u6570\u5024\u3067\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 -jsp.warning.keepgen=\u8b66\u544a: initParam keepgenerated\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002 \u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.xpoweredBy=\u8b66\u544a: Invalid value for the initParam xpoweredBy\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.enablePooling=\u8b66\u544a: initParam enablePooling\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.invalidTagPoolSize=\u8b66\u544a: tagPoolSize\u306e\u521d\u671f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002{0}\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b5\u30a4\u30ba\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.mappedFile=\u8b66\u544a: initParam mappedFile\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.sendErrToClient=\u8b66\u544a: initParam sendErrToClient\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.classDebugInfo=\u8b66\u544a: initParam classDebugInfo\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\"\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.checkInterval=\u8b66\u544a: initParam checkInterval\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"300\"\u79d2\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.development=\u8b66\u544a: initParam development\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.fork=\u8b66\u544a: initParam fork\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.reloading=\u8b66\u544a: initParam reloading\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.dumpSmap=\u8b66\u544a: initParam dumpSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.genchararray=\u8b66\u544a: initParam genStrAsCharArray\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.warning.suppressSmap=\u8b66\u544a: initParam suppressSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 -jsp.error.badtaglib=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093: {1} -jsp.error.badGetReader=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u3055\u308c\u3066\u3044\u306a\u3044\u5834\u5408\u306b\u306f\u3001Reader\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 -jsp.warning.unknown.element.in.taglib=taglib\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.tag=tag\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.tagfile=tag-file\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.attribute=attribute\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.variable=variable\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.validator=validator\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.initParam=validator\u306einit-param\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.warning.unknown.element.in.function=function\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 -jsp.error.more.than.one.taglib=TLD\u306e\u4e2d\u306b\u8907\u6570\u306etaglib\u304c\u5b58\u5728\u3057\u307e\u3059: {0} -jsp.error.teiclass.instantiation=TagExtraInfo class\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -jsp.error.non_null_tei_and_var_subelems=\u30bf\u30b0 {0} \u306f\u4e00\u3064\u4ee5\u4e0a\u306evariable\u526f\u8981\u7d20\u3068\u4e00\u3064\u4ee5\u4e0a\u306eVariableInfo\u3092\u8fd4\u3059TagExtraInfo\u30af\u30e9\u30b9\u3092\u6301\u3063\u3066\u3044\u307e\u3059 -jsp.error.parse.error.in.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 -jsp.error.unable.to.open.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093 -jsp.buffer.size.zero=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u4ee5\u4e0b\u3067\u3059 -jsp.error.file.not.found=JSP \u30d5\u30a1\u30a4\u30eb \"{0}\" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.message.copyinguri={0} \u3092 {1} \u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059 -jsp.message.htmlcomment=\n\u524a\u9664\u3059\u308b\u30b3\u30e1\u30f3\u30c8: \t{0} -jsp.message.handling_directive=\n\u51e6\u7406\u3059\u308b\u6307\u793a\u5b50: {0}\t{1} -jsp.message.handling_plugin=\nPlugin: {0} -jsp.message.package_name_is=\u30d1\u30c3\u30b1\u30fc\u30b8\u540d: {0} -jsp.message.class_name_is=\u30af\u30e9\u30b9\u540d: {0} -jsp.message.java_file_name_is=Java\u30d5\u30a1\u30a4\u30eb\u540d: {0} -jsp.message.class_file_name_is=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb\u540d: {0} -jsp.message.accepted={1} \u3067 {0} \u3092\u53d7\u3051\u5165\u308c\u307e\u3059 -jsp.message.adding_jar=jar {0} \u3092\u30af\u30e9\u30b9\u30d1\u30b9\u306b\u8ffd\u52a0\u3057\u307e\u3059 -jsp.message.compiling_with={0} \u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u4e2d\u3067\u3059 -jsp.message.template_text=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8 -jsp.error.missing_attribute=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u306b\u3088\u308b\u3068\u3001\u5c5e\u6027 {0} \u306f\u30bf\u30b0 {1} \u306b\u306f\u5fc5\u9808\u3067\u3059 -jsp.error.bad_attribute=TLD\u306b\u3088\u308b\u3068\u3001\u30bf\u30b0 {1} \u306e\u5c5e\u6027 {0} \u306f\u7121\u52b9\u3067\u3059 -jsp.error.tld.unable_to_read=JAR\u30d5\u30a1\u30a4\u30eb \"{0}\" \u304b\u3089TLD \"{1}\" \u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093: {2} -jsp.error.tld.unable_to_get_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 : {1} -jsp.error.tld.missing_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.webxml_not_found=web.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.cmd_line.usage=\u4f7f\u7528\u6cd5: [-dd <\u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30d1\u30b9>] [-keepgenerated] \ -<.jsp\u30d5\u30a1\u30a4\u30eb\u7fa4> -jsp.message.cp_is=\u30af\u30e9\u30b9\u30d1\u30b9 {0} \u306f {1} \u3067\u3059 -jsp.error.unable.to_load_taghandler_class=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -jsp.error.unable.to_find_method=\u5c5e\u6027 {0} \u306esetter\u30e1\u30bd\u30c3\u30c9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.unable.to_convert_string=\u5c5e\u6027 {1}\u306e\u6587\u5b57\u5217\u3092 {0}\u306b\u5909\u63db\u3067\u304d\u307e\u305b\u3093 -jsp.error.unable.to_introspect=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u5185\u7701\u3067\u304d\u307e\u305b\u3093 -jsp.error.bad_tag=\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {1}\u3067\u30a4\u30f3\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u306f\u3001\u30bf\u30b0 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 -jsp.error.xml.bad_tag=URI \"{1}\" \u306b\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u4e2d\u306b\u306f\u30bf\u30b0 \"{0}\" \u306f\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.bad_string_Character=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 -jsp.error.bad_string_char=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 -jsp.warning.compiler.class.cantcreate=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092 {1} \u306e\u305f\u3081\u306b\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002 -jsp.warning.compiler.class.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002not found. \u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002 -jsp.warning.compiler.path.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d1\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u30b7\u30b9\u30c6\u30e0\u306ePATH\u3092\u30c7\u30d5\u30a9\u30eb\u30c8\u306b\u3057\u307e\u3059\u3002 -jsp.error.jspc.uriroot_not_dir=-uriroot \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u3001\u65e2\u306b\u5b58\u5728\u3059\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspc.missingTarget=\u30bf\u30fc\u30b2\u30c3\u30c8\u304c\u3042\u308a\u307e\u305b\u3093: -webapp\u53c8\u306f-uriroot\uff0c\u53c8\u306f\u4e00\u3064\u4ee5\u4e0a\u306eJSP\u30da\u30fc\u30b8\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspc.no_uriroot=uriroot\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u6307\u5b9a\u3055\u308c\u305fJSP\u30d5\u30a1\u30a4\u30eb(\u7fa4)\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 -jspc.implicit.uriRoot=uriRoot\u306f\u30c7\u30d5\u30a9\u30eb\u30c8"{0}"\u306b\u8a2d\u5b9a\u3055\u308c\u307e\u3059 -jspc.usage=\u4f7f\u7528\u6cd5: jspc [--] \n\ -JSP\u30d5\u30a1\u30a4\u30eb\u306e\u5834\u6240\u306f\u6b21\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u6307\u5b9a\u3059\u308b\u304b\u3001\n\ -\ -webapp web-app\u3092\u542b\u3080\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3002\u3059\u3079\u3066\u306eJSP\u30d5\u30a1\u30a4\u30eb\u306f\n\ -\ \u518d\u5e30\u7684\u306b\u89e3\u6790\u3055\u308c\u308b\n\ -\u53c8\u306f\u6b21\u306e\u4efb\u610f\u306e\u6570\u306e\u30d5\u30a1\u30a4\u30eb\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002\n\ -\ JSP\u3068\u3057\u3066\u89e3\u6790\u3055\u308c\u308b\u30d5\u30a1\u30a4\u30eb\n\ -\u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3067\u3059\n\ -\ -help \u3053\u306e\u30d8\u30eb\u30d7\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u8868\u793a\n\ -\ -v Verbose\u30e2\u30fc\u30c9\n\ -\ -d \u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\ -\ -l \u5931\u6557\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\ -\ -s \u6210\u529f\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\ -\ -p \u30bf\u30fc\u30b2\u30c3\u30c8\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u540d\u524d (\u30c7\u30d5\u30a9\u30eb\u30c8\u306forg.apache.jsp)\n\ -\ -c \u30bf\u30fc\u30b2\u30c3\u30c8\u30af\u30e9\u30b9\u306e\u540d\u524d (\u6700\u521d\u306eJSP\u30da\u30fc\u30b8\u3060\u3051\u306b\u9069\u7528\u3055\u308c\u308b)\n\ -\ -mapped JSP\u306e\u5404HTML\u884c\u3054\u3068\u306bwrite()\u30b3\u30fc\u30eb\u3092\u751f\u6210\n\ -\ -die[#] \u81f4\u547d\u7684\u30a8\u30e9\u30fc\u306b\u30a8\u30e9\u30fc\u30ea\u30bf\u30fc\u30f3\u30b3\u30fc\u30c9(#)\u3092\u751f\u6210 (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f1)\n\ -\ -uribase \u30b3\u30f3\u30d1\u30a4\u30eb\u304c\u76f8\u5bfe\u7684\u306b\u304a\u3053\u306a\u308f\u308c\u308buri\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\ -\ (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f"/")\n\ -\ -uriroot -webapp\u3068\u540c\u3058\n\ -\ -compile \u751f\u6210\u3057\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\n\ -\ -webinc \u30d5\u30a1\u30a4\u30eb\u306b\u90e8\u5206\u7684\u306a\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u3092\u4f5c\u6210\n\ -\ -webxml \u30d5\u30a1\u30a4\u30eb\u306b\u5b8c\u5168\u306aweb.xml\u3092\u4f5c\u6210\n\ -\ -ieplugin Internet Explorer\u306eJava Plugin\u306eclassid\n\ -\ -classpath java.class.path\u30b7\u30b9\u30c6\u30e0\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4e0a\u66f8\u304d\n\ -\ -xpoweredBy X-Powered-By\u30ec\u30b9\u30dd\u30f3\u30b9\u30d8\u30c3\u30c0\u306e\u8ffd\u52a0\n\ -\ -trimSpaces \u30a2\u30af\u30b7\u30e7\u30f3\u3084\u6307\u793a\u5b50\u306e\u9593\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u4e2d\u306e\u30b9\u30da\u30fc\u30b9\u3092\u524a\u9664\n\ -\ -trimSpaces Trim spaces in template text between actions, directives\n\ -\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ -\ -source Set the -source argument to the compiler (default 1.4)\n\ -\ -target Set the -target argument to the compiler (default 1.4)\n\ - -jspc.webxml.header=\n\ -\n\ -\n\ -\n\ -\n\ -\n -jspc.webxml.footer=\n\ -\n\ -\n -jspc.webinc.header=\n\ -\n -jspc.webinc.footer=\n\ -\n -jspc.webinc.insertEnd= -jspc.webinc.insertStart= -jspc.error.jasperException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f: {1} -jspc.error.generalException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f: -jspc.error.fileDoesNotExist=\u30d5\u30a1\u30a4\u30eb\u5f15\u6570 ''{0}'' \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 -jspc.error.emptyWebApp=-webapp\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u3001\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.library.invalid=\u30e9\u30a4\u30d6\u30e9\u30ea{0}\u306b\u5f93\u3046\u3068JSP\u30da\u30fc\u30b8\u306f\u7121\u52b9\u3067\u3059: {1} -jsp.error.tlvclass.instantiation=TagLibraryValidator\u30af\u30e9\u30b9\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} -jsp.error.tlv.invalid.page={0} \u306b\u5bfe\u3059\u308bTagLibraryValidator\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059 ({1}) -jsp.error.tei.invalid.attributes={0} \u306b\u5bfe\u3059\u308bTagExtraInfo\u304b\u3089\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059 -jsp.parser.sax.propertynotsupported=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0} -jsp.parser.sax.propertynotrecognized=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0} -jsp.parser.sax.featurenotsupported=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0} -jsp.parser.sax.featurenotrecognized=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0} -jsp.error.no.more.content=\u5fc5\u8981\u306a\u89e3\u6790\u4e2d\u306b\u5185\u5bb9\u306e\u6700\u5f8c\u307e\u3067\u9054\u3057\u307e\u3057\u305f: \u30bf\u30b0\u306e\u30cd\u30b9\u30c8\u306e\u30a8\u30e9\u30fc\u304b\u3082\u3057\u308c\u307e\u305b\u3093 -jsp.error.parse.xml=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc -jsp.error.parse.xml.line=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc: (\u884c {1}, \u5217 {2}) -jsp.error.parse.xml.scripting.invalid.body={0} \u8981\u7d20\u306e\u30dc\u30c7\u30a3\u306fXML\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.internal.tldinit=TldLocationsCache\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0} -jsp.error.internal.filenotfound=\u5185\u90e8\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.internal.evaluator_not_found=\u5185\u90e8\u30a8\u30e9\u30fc: \u5f0f\u691c\u8a3c\u5668\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 -jsp.error.parse.xml.invalidPublicId=\u7121\u52b9\u306aPUBLIC ID: {0} -jsp.error.include.flush.invalid.value=flush\u5c5e\u6027\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059: {0} -jsp.error.unsupported.encoding=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059: {0} -tld.error.variableNotAllowed=null\u3067\u306a\u3044\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8fd4\u3059TagExtraInfo\u3092\u6301\u3064\u4e00\u3064\u4ee5\u4e0a\u306e\u5909\u6570\u526f\u8981\u7d20\u3092\u6301\u3064\u30bf\u30b0\u306f\u30a8\u30e9\u30fc\u3067\u3059\u3002 -jsp.error.tldInWebDotXmlNotFound=web.xml\u3067\u6307\u5b9a\u3055\u308c\u305fURI {0} \u306bTLD\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 -jsp.error.taglibDirective.absUriCannotBeResolved=\u7d76\u5bfeURI: {0} \u306fweb.xml\u3068\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u305fJAR\u30d5\u30a1\u30a4\u30eb\u306e\u3069\u3061\u3089\u304b\u3067\u3082\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093 -jsp.error.taglibDirective.missing.location=taglib\u6307\u793a\u5b50\u306e\u4e2d\u306b'uri'\u5c5e\u6027\u3068'tagdir'\u5c5e\u6027\u306e\u3069\u3061\u3089\u3082\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.taglibDirective.both_uri_and_tagdir=\'uri\'\u5c5e\u6027 \u3068 \'tagdir\'\u5c5e\u6027\u306e\u4e21\u65b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.invalid.tagdir=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\"/WEB-INF/tags\"\u3067\u59cb\u307e\u308a\u307e\u305b\u3093 -jsp.error.unterminated.user.tag=\u672a\u7d42\u4e86\u306e\u30e6\u30fc\u30b6\u5b9a\u7fa9\u30bf\u30b0: \u7d42\u4e86\u30bf\u30b0 {0} \u304c\u898b\u3064\u304b\u3089\u306a\u3044\u304b\u3001\u30cd\u30b9\u30c8\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059 -#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} -jspx.error.templateDataNotInJspCdata=\u8a3c\u660e\u30a8\u30e9\u30fc: \u8981\u7d20<{0}>\u306f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306f\u3001<jsp:text>\u8981\u7d20\u306e\u4e2d\u3067\u96a0\u853d\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002[JSP1.2 PFD 5.1.9]\n\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} -#Error while processing taglib jar file {0}: {1} -jsp.error.taglib.reserved.prefix=taglib\u30d7\u30ea\u30d5\u30a3\u30af\u30b9 {0} \u306f\u4e88\u7d04\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.invalid.javaEncoding=\u7121\u52b9\u306aJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059\u3002{0}\u3092\u8a66\u3057\u3066\u3001\u305d\u308c\u304b\u3089{1}\u3092\u8a66\u3057\u307e\u3057\u305f\u304c\u3001\u4e21\u65b9\u304c\u5931\u6557\u3057\u307e\u3057\u305f -jsp.error.needAlternateJavaEncoding=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 {0} \u306f\u3042\u306a\u305f\u306e\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3067\u306f\u7121\u52b9\u3067\u3059\u3002JspServlet\u306e 'javaEncoding' \u30d1\u30e9\u30e1\u30bf\u3067\u3001\u5225\u306e\u5024\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 -#Error when compiling, used for jsp line number error messages -jsp.error.single.line.number=JSP\u30d5\u30a1\u30a4\u30eb: {1} \u306e\u4e2d\u306e{0}\u884c\u76ee\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -jsp.error.multiple.line.number=\n\nJPS\u30d5\u30a1\u30a4\u30eb: {2}\u306e\u4e2d\u306e{0}\u884c\u76ee\u3068{1}\u884c\u76ee\u306e\u9593\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\n\n -jsp.error.corresponding.servlet=\u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30a8\u30e9\u30fc\u3067\u3059:\n -jsp.error.empty.body.not.allowed={0} \u306b\u5bfe\u3057\u3066\u7a7a\u306e\u30dc\u30c7\u30a3\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 -jsp.error.jspbody.required=jsp:attribute\u304c\u4f7f\u7528\u3055\u308c\u305f\u5834\u5408\u306b\u306f\u3001{0}\u306b\u30bf\u30b0\u30dc\u30c7\u30a3\u3092\u6307\u5b9a\u3059\u308b\u305f\u3081\u306bjsp:body\u3092\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspbody.emptybody.only={0} \u30bf\u30b0\u306f\u3001\u305d\u306e\u30dc\u30c7\u30a3\u4e2d\u306bjsp:attribute\u3060\u3051\u3092\u6301\u3064\u3053\u3068\u304c\u3067\u304d\u307e\u3059 -jsp.error.no.scriptlets=\u30b9\u30af\u30ea\u30d7\u30c6\u30a3\u30f3\u30b0\u8981\u7d20 ( <%!\u3001<jsp:declaration\u3001<%=\u3001<jsp:expression\u3001<%\u3001<jsp:scriptlet ) \u306f\u3053\u3053\u3067\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 -jsp.error.internal.unexpected_node_type=\u5185\u90e8\u30a8\u30e9\u30fc: \u672a\u77e5\u306e\u30ce\u30fc\u30c9\u30bf\u30a4\u30d7\u304c\u8868\u308c\u307e\u3057\u305f -jsp.error.tld.fn.invalid.signature=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1} -jsp.error.tld.fn.duplicate.name=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {1} \u306e\u4e2d\u306e\u95a2\u6570\u540d {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059 -jsp.error.tld.fn.invalid.signature.commaexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30b3\u30f3\u30de ',' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002 -jsp.error.tld.fn.invalid.signature.parenexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u62ec\u5f27 '(' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002 -jsp.error.tld.mandatory.element.missing=\u5fc5\u9808TLD\u8981\u7d20\u304c\u306a\u3044\u3001\u53c8\u306f\u7a7a\u3067\u3059: {0} -jsp.error.dynamic.attributes.not.implemented={0} \u30bf\u30b0\u306f\u305d\u308c\u304cdynamic\u5c5e\u6027\u3092\u53d7\u3051\u4ed8\u3051\u308b\u3068\u5ba3\u8a00\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u305d\u308c\u306b\u5fc5\u8981\u306a\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9\u3092\u5b9f\u88c5\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.nomatching.fragment=attribute\u6307\u793a\u5b50 (name={0}\u304a\u3088\u3073fragment=true\u3092\u6301\u3064) \u304cfragment\u6307\u793a\u5b50\u3088\u308a\u524d\u306b\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.attribute.noequal=\u7b49\u53f7\u8a18\u53f7\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.attribute.noquote=\u5f15\u7528\u7b26\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.attribute.unterminated={0} \u306e\u5c5e\u6027\u304c\u6b63\u3057\u304f\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.missing.tagInfo={0} \u306b\u5bfe\u3059\u308bTagInfo\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304cTLD\u304b\u3089\u5931\u308f\u308c\u307e\u3057\u305f -jsp.error.fragmentwithtype='fragment'\u5c5e\u6027\u3068'type'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'type'\u306f'javax.servlet.jsp.tagext.JspFragment'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059 -jsp.error.fragmentwithrtexprvalue='fragment'\u5c5e\u6027\u3068'rtexprvalue'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'rtexprvalue'\u306f'true'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059 -jsp.error.fragmentWithDeclareOrScope='fragment'\u5c5e\u6027\u3068'declare'\u5c5e\u6027\u306e\u4e21\u65b9\u53c8\u306f'scope'\u5c5e\u6027\u304cvariable\u6307\u793a\u5b50\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 -jsp.error.var_and_varReader=\'var\'\u53c8\u306f\'varReader\'\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059 -jsp.error.missing_var_or_varReader=\'var\'\u53c8\u306f\'varReader\'\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.warning.bad.urlpattern.propertygroup=web.xml\u4e2d\u306eurl-pattern\u526f\u8981\u7d20\u4e2d\u306b\u8aa4\u3063\u305f\u5024 {0} \u304c\u3042\u308a\u307e\u3059 -jsp.error.unknown_attribute_type=\u5c5e\u6027 {0} \u306b\u5bfe\u3059\u308b\u672a\u77e5\u306e\u5c5e\u6027\u30bf\u30a4\u30d7\u3067\u3059 -jsp.error.jspelement.missing.name=\u5fc5\u9808\u306eXML\u30b9\u30bf\u30a4\u30eb\u306e'name'\u5c5e\u6027\u304cjsp:element\u4e2d\u306b\u3042\u308a\u307e\u305b\u3093 -jsp.error.xmlns.redefinition.notimplemented=\u5185\u90e8\u30a8\u30e9\u30fc: xmlns:{0}\u3092\u518d\u5b9a\u7fa9\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u3002\u540d\u524d\u7a7a\u9593\u306e\u518d\u5b9a\u7fa9\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 -jsp.error.could.not.add.taglibraries=1\u3064\u4ee5\u4e0a\u306e\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093 -jsp.error.duplicate.name.jspattribute=\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u5c5e\u6027 {0} \u306f\u305d\u308c\u306b\u56f2\u307e\u308c\u305fjsp:attribute\u4e2d\u306ename\u5c5e\u6027\u306e\u5024\u3068\u3057\u3066\u3082\u8868\u308c\u307e\u3059 -jsp.error.not.in.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u30dc\u30c7\u30a3\u4e2d\u3067\u306f {0} \u306f\u8a31\u3055\u308c\u307e\u305b\u3093 -jsp.error.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059 -jsp.error.xml.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059: {0} -jsp.error.tagdirective.badbodycontent=tag\u6307\u793a\u5b50\u4e2d\u306e\u7121\u52b9\u306abody-content ({0})\u3067\u3059 -jsp.error.simpletag.badbodycontent=\u30af\u30e9\u30b9 {0} \u306eTLD\u306fSimpleTag\u306b\u7121\u52b9\u306abody-content (JSP)\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059 -jsp.error.config_pagedir_encoding_mismatch=jsp-property-group\u4e2d\u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308bPage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059 -jsp.error.prolog_pagedir_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059 -jsp.error.prolog_config_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cjsp-property-group\u4e2d\u306e\u6307\u5b9a\u3068\u9055\u3044\u307e\u3059 ({1}) -jsp.error.attribute.custom.non_rt_with_expr=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u306eattribute\u6307\u793a\u5b50\u306b\u5f93\u3063\u3066\u5c5e\u6027{0}\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093 -jsp.error.attribute.standard.non_rt_with_expr={1} \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e {0} \u5c5e\u6027\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093 -jsp.error.scripting.variable.missing_name=\u5c5e\u6027 {0} \u304b\u3089\u30b9\u30af\u30ea\u30d7\u30c8\u5909\u6570\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093 -jasper.error.emptybodycontent.nonempty=TLD\u306b\u5f93\u3063\u3066\u30bf\u30b0 {0} \u306f\u7a7a\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u304c\u3001\u305d\u3046\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -jsp.error.tagfile.nameNotUnique={2}\u884c\u76ee\u306e {0} \u306e\u5024\u3068 {1} \u306e\u5024\u306f\u540c\u3058\u3067\u3059 -jsp.error.tagfile.nameFrom.noAttribute=\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024\u3067\u3042\u308b\u5024 \"{0}\" \u306ename\u5c5e\u6027\u3092\u6301\u3064attribute\u6307\u793a\u5b50\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.tagfile.nameFrom.badAttribute=attribute\u6307\u793a\u5b50 ({1}\u884c\u76ee\u3067\u5ba3\u8a00\u3055\u308c\u3001\u305d\u306ename\u5c5e\u6027\u304c\"{0}\"\u3001\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024) \u306fjava.lang.String\u578b\u306e\"required\" \u3067 \"rtexprvalue\".\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.page.noSession=\u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u52a0\u308f\u3063\u3066\u3044\u306a\u3044\u30da\u30fc\u30b8\u306e\u4e2d\u3067\u306f\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093 -jsp.error.useBean.noSession=JSP\u30da\u30fc\u30b8\u304c(page\u6307\u793a\u5b50\u306b\u3088\u308a)\u30bb\u30c3\u30b7\u30e7\u30f3\u4e2d\u3067\u5354\u8abf\u3057\u306a\u3044\u3053\u3068\u3092\u5ba3\u8a00\u3057\u3066\u3044\u308b\u6642\u3001\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\u3059\u308b\u305f\u3081\u306euseBean\u304c\u4e0d\u6b63\u3067\u3059 -jsp.error.xml.encodingByteOrderUnsupported = \u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 \"{0}\" \u306b\u6307\u5b9a\u3055\u308c\u305f\u30d0\u30a4\u30c8\u30aa\u30fc\u30c0\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.xml.encodingDeclInvalid = \u7121\u52b9\u306a\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u540d \"{0}\" \u3067\u3059 -jsp.error.xml.encodingDeclRequired = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306b\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u5ba3\u8a00\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.morePseudoAttributes = \u3088\u308a\u591a\u304f\u306e\u7591\u4f3c\u5c5e\u6027\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.noMorePseudoAttributes = \u3053\u308c\u4ee5\u4e0a\u306e\u7591\u4f3c\u5c5e\u6027\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 -jsp.error.xml.versionInfoRequired = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.xmlDeclUnterminated = XML\u5ba3\u8a00\u306f\"?>\"\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.reservedPITarget = \"[xX][mM][lL]\"\u306b\u4e00\u81f4\u3059\u308b\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u306f\u8a31\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.xml.spaceRequiredInPI = \u7a7a\u767d\u304c\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u3068\u30c7\u30fc\u30bf\u306e\u9593\u306b\u5fc5\u8981\u3067\u3059 -jsp.error.xml.invalidCharInContent = \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u8981\u7d20\u5185\u5bb9\u306e\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.xml.spaceRequiredBeforeStandalone = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.sdDeclInvalid = \u30b9\u30bf\u30f3\u30c9\u30a2\u30ed\u30f3\u6587\u66f8\u5ba3\u8a00\u5024\u306f\"yes\"\u53c8\u306f\"no\"\u306e\u3069\u3061\u3089\u304b\u3067\u3042\u308a\u3001\"{0}\"\u3067\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.invalidCharInPI = \u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u547d\u4ee4\u51e6\u7406\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.xml.versionNotSupported = XML\u30d0\u30fc\u30b8\u30e7\u30f3 \"{0}\" \u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3001XML 1.0\u3060\u3051\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059 -jsp.error.xml.pseudoAttrNameExpected = \u7591\u4f3c\u5c5e\u6027\u540d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.expectedByte ={1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30d0\u30a4\u30c8 {0} \u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.invalidByte = {1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u7121\u52b9\u306a\u30d0\u30a4\u30c8 {0} \u3067\u3059 -jsp.error.xml.operationNotSupported = {1} reader\u306f\u64cd\u4f5c \"{0}\" \u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093 -jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.xml.invalidASCII = \u30d0\u30a4\u30c8 \"{0}\" \u306f7\u30d3\u30c3\u30c8ASCII\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = XML\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 -jsp.error.xml.eqRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = '' \u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.eqRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = ''\u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.quoteRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.quoteRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.xml.invalidCharInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.xml.invalidCharInXMLDecl = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.xml.closeQuoteMissingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.xml.closeQuoteMissingInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f -jsp.error.multiple.jsp = \u8907\u6570\u306e\u4ed5\u69d8\u3092\u6e80\u305f\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.jspoutput.conflict=<jsp:output>: \"{0}\"\u306b\u7570\u306a\u308b\u5024\u3092\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {1}, \u65b0: {2}) -jsp.error.jspoutput.doctypenamesystem=<jsp:output>: 'doctype-root-element' \u53ca\u3073 'doctype-system' \u5c5e\u6027\u306f\u540c\u6642\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: 'doctype-public'\u5c5e\u6027\u3092\u6307\u5b9a\u3059\u308b\u5834\u5408\u306f\u3001'doctype-system' \u5c5e\u6027\u3082\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspoutput.nonemptybody=<jsp:output> \u30dc\u30c7\u30a3\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.jspoutput.invalidUse=<jsp:output> \u6a19\u6e96\u69cb\u6587\u306e\u4e2d\u3067\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.attributes.not.allowed = {0} \u306f\u5c5e\u6027\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.tagfile.badSuffix=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 {0} \u306e\u4e2d\u306b\".tag\" \u62e1\u5f35\u5b50\u304c\u3042\u308a\u307e\u305b\u3093 -jsp.error.tagfile.illegalPath=\u4e0d\u6b63\u306a\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u3067\u3059: {0}\u3001\u3053\u308c\u306f\"/WEB-INF/tags\"\u53c8\u306f\"/META-INF/tags\"\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.plugin.wrongRootElement={0} \u306e\u4e2d\u306e\u30eb\u30fc\u30c8\u8981\u7d20\u306e\u540d\u524d\u306f {1} \u3067\u306f\u3042\u308a\u307e\u305b\u3093 -jsp.error.attribute.invalidPrefix=\u5c5e\u6027\u306e\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3069\u306e\u53d6\u308a\u8fbc\u307e\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u3082\u5bfe\u5fdc\u3057\u307e\u305b\u3093 -jsp.error.nested.jspattribute=jsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.nested.jspbody=jsp:body\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:body\u53c8\u306fjsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.variable.either.name=name-given\u53c8\u306fname-from-attribute\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u3092variable\u6307\u793a\u5b50\u306e\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.variable.both.name=variable\u6307\u793a\u5b50\u4e2d\u3067name-given\u3068name-from-attribute\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 -jsp.error.variable.alias=name-from-attribute\u304a\u3088\u3073alias\u5c5e\u6027\u306e\u4e21\u65b9\u3092variable\u6307\u793a\u5b50\u4e2d\u306b\u6307\u5b9a\u3059\u308b\u3001\u53c8\u306f\u3069\u3061\u3089\u3082\u6307\u5b9a\u3057\u306a\u3044\u3053\u3068\u304c\u3067\u304d\u307e\u3059 -jsp.error.attribute.null_name=\u7a7a\u306e\u5c5e\u6027\u540d\u3067\u3059 -jsp.error.jsptext.badcontent=\'<\'\u304c<jsp:text>\u306e\u30dc\u30c7\u30a3\u306e\u4e2d\u306b\u73fe\u308c\u308b\u6642\u306f\u3001CDATA\u306e\u4e2d\u306b\u96a0\u853d\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.jsproot.version.invalid=\u7121\u52b9\u306a\u30d0\u30fc\u30b8\u30e7\u30f3\u756a\u53f7\u3067\u3059: \"{0}\"\u3001\"1.2\" \u53c8\u306f \"2.0\"\u3000\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.noFunctionPrefix=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u540d\u524d\u7a7a\u9593\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u6642\u306b\u306f\u3001\u95a2\u6570 {0} \u306f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u4ed8\u304d\u3067\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -jsp.error.noFunction=\u95a2\u6570 {0} \u3092\u6307\u5b9a\u3055\u308c\u305f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u3067\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 -jsp.error.noFunctionMethod=\u95a2\u6570 \"{1}\" \u306e\u30e1\u30bd\u30c3\u30c9 \"{0}\" \u304c \"{2}\" \u4e2d\u3067\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -jsp.error.function.classnotfound=TLD\u306e\u4e2d\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093: {2} -jsp.error.signature.classnotfound=TLD\u306e\u4e2d\u306e\u30e1\u30bd\u30c3\u30c9\u30b7\u30b0\u30cd\u30c1\u30e3\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 {2} -jsp.error.text.has_subelement=<jsp:text> \u306f\u526f\u8981\u7d20\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -jsp.error.data.file.read=\u30d5\u30a1\u30a4\u30eb \"{0}\" \u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f -jsp.error.prefix.refined=\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u304c\u73fe\u5728\u306e\u30b9\u30b3\u30fc\u30d7\u4e2d\u3067\u65e2\u306b {2} \u3068\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u308b\u306e\u3067 {1} \u306b\u518d\u5b9a\u7fa9\u3057\u307e\u3057\u305f -jsp.error.nested_jsproot=\u5165\u308c\u5b50\u306b\u306a\u3063\u305f <jsp:root> \u3067\u3059 -jsp.error.unbalanced.endtag=\u7d42\u4e86\u30bf\u30b0 \"</{0}\" \u306e\u5bfe\u5fdc\u304c\u53d6\u308c\u3066\u3044\u307e\u305b\u3093 -jsp.error.invalid.bean=useBean\u306e\u30af\u30e9\u30b9\u5c5e\u6027 {0} \u306e\u5024\u304c\u7121\u52b9\u3067\u3059 -jsp.error.prefix.use_before_dcl=\u3053\u306e\u30bf\u30b0\u6307\u793a\u5b50\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3001\u3059\u3067\u306b\u30d5\u30a1\u30a4\u30eb {1} \u306e {2} \u884c\u76ee\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 - +# $Id: LocalStrings_ja.properties 349479 2005-11-28 19:44:47Z yoavs $ +# +# Default localized string information +# Localized this the Default Locale as is ja_JP + +jsp.error.bad.servlet.engine=\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30a8\u30f3\u30b8\u30f3\u306e\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u6b63\u3057\u304f\u3042\u308a\u307e\u305b\u3093 +jsp.error.no.scratch.dir=JSP\u30a8\u30f3\u30b8\u30f3\u306b\u30c7\u30d5\u30a9\u30eb\u30c8\u306escratchDir\u304c\u8a2d\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002\ +\n \u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306eservlets.properties\u30d5\u30a1\u30a4\u30eb\u306b\u3001\ +\n \"jsp.initparams=scratchdir=\" \u3092\u8ffd\u52a0\u3057\u3066\u304f\u3060\u3055\u3044\u3002 +jsp.error.bad.scratch.dir=\u3042\u306a\u305f\u304c\u6307\u5b9a\u3057\u305fscratchDir\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.message.scratch.dir.is=JSP\u30a8\u30f3\u30b8\u30f3\u306eScratchdir: {0} +jsp.message.parent_class_loader_is=\u89aa\u30af\u30e9\u30b9\u30ed\u30fc\u30c0: {0} +jsp.message.dont.modify.servlets=\u91cd\u8981: \u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u3092\u5909\u66f4\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.not.impl.comments=\u5185\u90e8\u30a8\u30e9\u30fc: Comments\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.directives=\u5185\u90e8\u30a8\u30e9\u30fc: Directives\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.declarations=\u5185\u90e8\u30a8\u30e9\u30fc: Declarations\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.expressions=\u5185\u90e8\u30a8\u30e9\u30fc: Expressions\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.scriptlets=\u5185\u90e8\u30a8\u30e9\u30fc: Scriptlets\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.usebean=\u5185\u90e8\u30a8\u30e9\u30fc: useBean\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.getp=\u5185\u90e8\u30a8\u30e9\u30fc: getProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.setp=\u5185\u90e8\u30a8\u30e9\u30fc: setProperty\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.plugin=\u5185\u90e8\u30a8\u30e9\u30fc: plugin\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.forward=\u5185\u90e8\u30a8\u30e9\u30fc: forward\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.not.impl.include=\u5185\u90e8\u30a8\u30e9\u30fc: include\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.unavailable=JSP\u306f\u5229\u7528\u4e0d\u53ef\u3068\u30de\u30fc\u30af\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.usebean.missing.attribute=useBean: id\u5c5e\u6027\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3001\u30b9\u30da\u30eb\u30df\u30b9\u3067\u3059 +jsp.error.usebean.missing.type=useBean ({0}): class\u5c5e\u6027\u304btype\u5c5e\u6027\u3092\u6307\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044: +jsp.error.usebean.duplicate=useBean: beanName\u5c5e\u6027\u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059: {0} +jsp.error.usebean.prohibited.as.session=\u4ee5\u524d\u306b\u5b9a\u7fa9\u3057\u305fJSP\u6307\u793a\u5b50\u306b\u3088\u3063\u3066\u7981\u6b62\u3055\u308c\u3066\u3044\u308b\u305f\u3081\u306b\u3001session bean {0} \u3068\u3057\u3066\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093: +jsp.error.usebean.not.both=useBean: class\u5c5e\u6027\u3068beanName\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u540c\u6642\u306b\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093: +jsp.error.usebean.bad.type.cast=useBean ({0}): type ({1}) \u306fclass ({2}) \u304b\u3089\u5272\u308a\u5f53\u3066\u3089\u308c\u307e\u305b\u3093 +jsp.error.invalid.scope='scope'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: {0} (\"page\"\u3001\"request\"\u3001\"session\"\u53c8\u306f\"application\"\u306e\u3069\u308c\u304b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093) +jsp.error.classname=.class\u30d5\u30a1\u30a4\u30eb\u304b\u3089\u30af\u30e9\u30b9\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.warning.bad.type=\u8b66\u544a: .class\u30d5\u30a1\u30a4\u30eb\u4e2d\u306e\u578b\u304c\u9055\u3044\u307e\u3059 +jsp.error.data.file.write=\u30c7\u30fc\u30bf\u30d5\u30a1\u30a4\u30eb\u3092\u66f8\u304d\u8fbc\u307f\u4e2d\u306e\u30a8\u30e9\u30fc\u3067\u3059 +jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: \u7121\u52b9\u306a\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u3067\u3059 +jsp.error.page.conflict.contenttype=page\u6307\u793a\u5b50: 'contentType'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.contenttype=page\u6307\u793a\u5b50: contentType\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.session=page\u6307\u793a\u5b50: 'session'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.session=page\u6307\u793a\u5b50: session\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.buffer=page\u6307\u793a\u5b50: 'buffer'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.buffer=page\u6307\u793a\u5b50: buffer\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.autoflush=page\u6307\u793a\u5b50: 'autoFlush'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.autoflush=page\u6307\u793a\u5b50: autoFlush\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.isthreadsafe=page\u6307\u793a\u5b50: 'isThreadSafe'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.isthreadsafe=page\u6307\u793a\u5b50: isThreadSafe\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.info=page\u6307\u793a\u5b50: 'info'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.info=page\u6307\u793a\u5b50: info\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.iserrorpage=page\u6307\u793a\u5b50: 'isErrorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.iserrorpage=page\u6307\u793a\u5b50: isErrorPage\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.page.conflict.errorpage=page\u6307\u793a\u5b50: 'errorPage'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.conflict.language=page\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.tag.conflict.language=tag\u6307\u793a\u5b50: 'language'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.language.nonjava=page\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059 +jsp.error.tag.language.nonjava=tag\u6307\u793a\u5b50: \u7121\u52b9\u306alanguage\u5c5e\u6027\u3067\u3059 +jsp.error.page.defafteruse.language=page\u6307\u793a\u5b50: scriptlet\u306e\u5f8c\u3067language\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.error.page.nomapping.language=page\u6307\u793a\u5b50 language\u5c5e\u6027\u306e\u30de\u30c3\u30d4\u30f3\u30b0\u304c\u5b58\u5728\u3057\u307e\u305b\u3093: +jsp.error.page.conflict.extends=page\u6307\u793a\u5b50: 'extends'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.conflict.iselignored=page\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.tag.conflict.iselignored=tag\u6307\u793a\u5b50: 'isELIgnored'\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {0}, \u65b0: {1}) +jsp.error.page.invalid.iselignored=page\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.tag.invalid.iselignored=tag\u6307\u793a\u5b50: isELIgnored\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.page.multi.pageencoding=page\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.tag.conflict.attr=Tag\u6307\u793a\u5b50: \u5c5e\u6027\"{0}\"\u3092\u7570\u306a\u308b\u5024\u3067\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u4e0d\u6b63\u3067\u3059 (\u65e7: {1}, \u65b0: {2}) +jsp.error.tag.multi.pageencoding=tag\u6307\u793a\u5b50\u306f\u8907\u6570\u306epageencoding\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.page.bad_b_and_a_combo=page\u6307\u793a\u5b50: buffer=\"none\"\u3068autoFlush=\"false\"\u3092\u540c\u6642\u306b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.error.not.impl.taglib=\u5185\u90e8\u30a8\u30e9\u30fc: \u30bf\u30b0\u62e1\u5f35\u5b50\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.include.missing.file=\u53d6\u308a\u8fbc\u3080\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.include.bad.file=include\u5c5e\u6027\u306e\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059 +jsp.error.include.exception={0} \u3092\u53d6\u308a\u8fbc\u3081\u307e\u305b\u3093 +jsp.error.stream.closed=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30af\u30ed\u30fc\u30ba\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.invalid.forward=\u7121\u52b9\u306aforward\u30bf\u30b0\u3067\u3059 +jsp.error.unknownException=\u51e6\u7406\u4e0d\u53ef\u80fd\u306a\u30a8\u30e9\u30fc\u3067\u3059! \u3053\u306e\u3088\u3046\u306a\u30a8\u30e9\u30fc\u3092\u3088\u308a\u8a73\u7d30\u306b\u5831\u544a\u3059\u308b\u30a8\u30e9\u30fc\u30da\u30fc\u30b8\u3092\u6301\u3063\u305f\u65b9\u304c\u3088\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093 +jsp.error.invalid.directive=\u7121\u52b9\u306a\u6307\u793a\u5b50\u3067\u3059 +jsp.error.directive.istagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.error.directive.isnottagfile={0} \u6307\u793a\u5b50\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u3057\u304b\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.error.tagfile.tld.name=TLD\u4e2d\u306e\u30bf\u30b0\u6307\u793a\u5b50\u306e\"tag-file\"\u8981\u7d20\u306e\"name\"\u30bf\u30b0\u306f {1} \u3067\u3059\u304c\uff0c\"name\"\u5c5e\u6027\u306f\u5024 {0} \u3092\u6301\u3063\u3066\u3044\u307e\u3059 +jsp.error.action.istagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.error.action.isnottagfile={0} \u30a2\u30af\u30b7\u30e7\u30f3\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u306e\u307f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093 +jsp.error.unterminated={0} \u30bf\u30b0\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.usebean.notinsamefile=useBean\u30bf\u30b0\u306f\u3001\u540c\u4e00\u30d5\u30a1\u30a4\u30eb\u4e2d\u3067\u958b\u59cb\u3057\u3001\u7d42\u4e86\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.loadclass.taghandler=\u30bf\u30b0 \"{1}\" \u306b\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 \"{0}\" \u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +jsp.error.unable.compile=JSP\u306e\u30af\u30e9\u30b9\u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u3067\u304d\u307e\u305b\u3093 +jsp.error.unable.load=JSP\u306e\u30af\u30e9\u30b9\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +jsp.error.unable.rename=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb {0} \u3092 {1} \u306b\u30d5\u30a1\u30a4\u30eb\u540d\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093 +jsp.error.mandatory.attribute={0}: \u5fc5\u9808\u5c5e\u6027 {1} \u304c\u3042\u308a\u307e\u305b\u3093 +jsp.engine.info=Jasper JSP 2.0\u30a8\u30f3\u30b8\u30f3 +jsp.error.invalid.expression="{0}" \u306f\u7121\u52b9\u306a\u5f0f\u3092\u542b\u3093\u3067\u3044\u307e\u3059: {1} +jsp.error.invalid.attribute={0}\u306f\u7121\u52b9\u306a\u5c5e\u6027\u3092\u6301\u3063\u3066\u3044\u307e\u3059: {1} +jsp.error.usebean.class.notfound=\u30af\u30e9\u30b9: {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.file.cannot.read=\u30d5\u30a1\u30a4\u30eb\u304c\u8aad\u3081\u307e\u305b\u3093: {0} +jsp.error.file.already.registered=\u30d5\u30a1\u30a4\u30eb {0} \u306e\u518d\u5e30\u7684\u306a\u53d6\u308a\u8fbc\u307f\u3067\u3059 +jsp.error.file.not.registered=include\u5c5e\u6027\u4e2d\u306e\u30d5\u30a1\u30a4\u30eb {0} \u304c\u5b58\u5728\u3057\u307e\u305b\u3093 +jsp.error.quotes.unterminated=\u5f15\u7528\u7b26\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.attr.quoted=\u5c5e\u6027\u5024\u306f\u5f15\u7528\u7b26\u3067\u56f2\u308f\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.attr.novalue=\u5c5e\u6027 {0} \u306b\u306f\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.tag.attr.unterminated=\u30bf\u30b0\u306e\u5c5e\u6027\u30ea\u30b9\u30c8\u304c\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.param.noname=PARAM\u30bf\u30b0\u306bname\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.param.novalue=PARAM\u30bf\u30b0\u306bvalue\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.beans.nullbean=null\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u306bBean\u64cd\u4f5c\u3092\u304a\u3053\u306a\u304a\u3046\u3068\u3057\u307e\u3057\u305f +jsp.error.beans.nobeaninfo=\u30bf\u30a4\u30d7 ''{0}'' \u306eBean\u306bBeanInfo\u304c\u306a\u3044\u306e\u3092\u691c\u51fa\u3057\u307e\u3057\u305f, \u30af\u30e9\u30b9\u304c\u5b58\u5728\u3057\u306a\u3044\u304b\u3082\u3057\u308c\u307e\u305b\u3093 +jsp.error.beans.introspection=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306eread\u30e1\u30bd\u30c3\u30c9\u3092\u5185\u7701\u4e2d\u306b\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f:\n{2} +jsp.error.beans.nomethod=\u30bf\u30a4\u30d7 ''{1}'' \u306eBean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u3092\u8aad\u307f\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +jsp.error.beans.nomethod.setproperty=\u30bf\u30a4\u30d7''{2}''\u306eBean\u306e\u30bf\u30a4\u30d7 ''{1}'' \u306e\u5c5e\u6027 ''{0}'' \u3092\u66f8\u304d\u8fbc\u3080\u30e1\u30bd\u30c3\u30c9\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +jsp.error.beans.noproperty=\u30bf\u30a4\u30d7 ''{1}'' \u306ebean\u4e2d\u306e\u5c5e\u6027 ''{0}'' \u306e\u60c5\u5831\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f +jsp.error.beans.setproperty.noindexset=\u30a4\u30f3\u30c7\u30c3\u30af\u30b9\u4ed8\u304d\u306e\u5c5e\u6027\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.error.include.tag=\u7121\u52b9\u306ajsp:include\u30bf\u30b0\u3067\u3059 +jsp.error.include.noflush=jsp:include\u30bf\u30b0\u306b \"flush=true\" \u3092\u5b9a\u7fa9\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.include.badflush=jsp:include page=\"...\" flush=\"true\" \u306f\u3001JSP 1.0\u3067\u306e\u307f\u6709\u52b9\u306a\u7d44\u307f\u5408\u308f\u305b\u3067\u3059 +jsp.error.attempt_to_clear_flushed_buffer=\u30a8\u30e9\u30fc: \u65e2\u306b\u30d5\u30e9\u30c3\u30b7\u30e5\u3055\u308c\u3066\u3044\u308b\u30d0\u30c3\u30d5\u30a1\u3092\u30af\u30ea\u30a2\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f +jsp.error.overflow=\u30a8\u30e9\u30fc: JSP\u30d0\u30c3\u30d5\u30a1\u304c\u30aa\u30fc\u30d0\u30fc\u30d5\u30ed\u30fc\u3057\u307e\u3057\u305f +jsp.error.paramexpected=\"name\"\u5c5e\u6027 \u3068 \"value\" \u5c5e\u6027\u3092\u6301\u3064 \"jsp:param\" \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.param.invalidUse=jsp:include\u3001jsp:forward\u3001\u53c8\u306fjsp:params\u8981\u7d20\u306e\u5916\u3067jsp:param\u30a2\u30af\u30b7\u30e7\u30f3\u3092\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.params.invalidUse=jsp:params\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.fallback.invalidUse=jsp:fallback\u306fjsp:plugin\u306e\u76f4\u63a5\u306e\u5b50\u4f9b\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.namedAttribute.invalidUse=jsp:attribute\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspbody.invalidUse=jsp:body\u306f\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u526f\u8981\u7d20\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.closeindividualparam=param\u30bf\u30b0\u306f \"/>\" \u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.closeparams=param\u30bf\u30b0\u306f/params\u3067\u9589\u3058\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.params.emptyBody=jsp:params\u306f\u5c11\u306a\u304f\u3068\u3082\u4e00\u3064\u306e\u30cd\u30b9\u30c8\u3057\u305fjsp:param\u3092\u542b\u307e\u306d\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.params.illegalChild=jsp:params\u306fjsp:param\u4ee5\u5916\u306e\u30cd\u30b9\u30c8\u3057\u305f\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.plugin.notype=jsp:plugin\u3067type\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.plugin.badtype=jsp:plugin\u306e 'type'\u5c5e\u6027\u306e\u5024\u304c\u7121\u52b9\u3067\u3059: 'bean'\u53c8\u306f'applet'\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.plugin.nocode=jsp:plugin\u3067code\u5c5e\u6027\u304c\u5ba3\u8a00\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.ise_on_clear=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u306e\u6642\u306bclear()\u3092\u5b9f\u884c\u3057\u3066\u3082\u7121\u52b9\u3067\u3059 +jsp.error.setproperty.beanNotFound=setProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.getproperty.beanNotFound=getProperty: Bean {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.setproperty.ClassNotFound=setProperty: \u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +# typo ? +#jsp.error.setproperty.invalidSayntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.error.setproperty.invalidSyntax=setProperty: property=*\u306e\u5834\u5408\u306fnull\u3067\u306a\u3044\u5024\u3092\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.error.setproperty.beanInfoNotFound=setproperty: Bean {0} \u306ebeanInfo\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.setproperty.paramOrValue=setProperty: param\u5c5e\u6027\u304bvalue\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3060\u3051\u3092\u6307\u5b9a\u3067\u304d\u307e\u3059 +jsp.error.setproperty.arrayVal=setProperty: \u5c5e\u6027\u914d\u5217 {0} \u3092\u6587\u5b57\u5217\u5b9a\u6570\u5024\u3067\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093 +jsp.warning.keepgen=\u8b66\u544a: initParam keepgenerated\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002 \u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.xpoweredBy=\u8b66\u544a: Invalid value for the initParam xpoweredBy\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.enablePooling=\u8b66\u544a: initParam enablePooling\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.invalidTagPoolSize=\u8b66\u544a: tagPoolSize\u306e\u521d\u671f\u30d1\u30e9\u30e1\u30fc\u30bf\u304c\u7121\u52b9\u306a\u5024\u3067\u3059\u3002{0}\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u30b5\u30a4\u30ba\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.mappedFile=\u8b66\u544a: initParam mappedFile\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.sendErrToClient=\u8b66\u544a: initParam sendErrToClient\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.classDebugInfo=\u8b66\u544a: initParam classDebugInfo\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\"\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.checkInterval=\u8b66\u544a: initParam checkInterval\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"300\"\u79d2\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.development=\u8b66\u544a: initParam development\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.fork=\u8b66\u544a: initParam fork\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.reloading=\u8b66\u544a: initParam reloading\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"true\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.dumpSmap=\u8b66\u544a: initParam dumpSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.genchararray=\u8b66\u544a: initParam genStrAsCharArray\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\"false\"\u306e\u30c7\u30d5\u30a9\u30eb\u30c8\u5024\u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.warning.suppressSmap=\u8b66\u544a: initParam suppressSmap\u306e\u5024\u304c\u7121\u52b9\u3067\u3059\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u5024 \"false\" \u3092\u4f7f\u7528\u3057\u307e\u3059 +jsp.error.badtaglib=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093: {1} +jsp.error.badGetReader=\u30b9\u30c8\u30ea\u30fc\u30e0\u304c\u30d0\u30c3\u30d5\u30a1\u30ea\u30f3\u30b0\u3055\u308c\u3066\u3044\u306a\u3044\u5834\u5408\u306b\u306f\u3001Reader\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 +jsp.warning.unknown.element.in.taglib=taglib\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.tag=tag\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.tagfile=tag-file\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.attribute=attribute\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.variable=variable\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.validator=validator\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.initParam=validator\u306einit-param\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.warning.unknown.element.in.function=function\u4e2d\u306b\u672a\u77e5\u306e\u8981\u7d20 ({0}) \u304c\u3042\u308a\u307e\u3059 +jsp.error.more.than.one.taglib=TLD\u306e\u4e2d\u306b\u8907\u6570\u306etaglib\u304c\u5b58\u5728\u3057\u307e\u3059: {0} +jsp.error.teiclass.instantiation=TagExtraInfo class\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +jsp.error.non_null_tei_and_var_subelems=\u30bf\u30b0 {0} \u306f\u4e00\u3064\u4ee5\u4e0a\u306evariable\u526f\u8981\u7d20\u3068\u4e00\u3064\u4ee5\u4e0a\u306eVariableInfo\u3092\u8fd4\u3059TagExtraInfo\u30af\u30e9\u30b9\u3092\u6301\u3063\u3066\u3044\u307e\u3059 +jsp.error.parse.error.in.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u4e2d\u306e\u89e3\u6790\u30a8\u30e9\u30fc\u3067\u3059 +jsp.error.unable.to.open.TLD=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u8a18\u8ff0\u5b50 {0} \u3092\u30aa\u30fc\u30d7\u30f3\u3067\u304d\u307e\u305b\u3093 +jsp.buffer.size.zero=\u30d0\u30c3\u30d5\u30a1\u30b5\u30a4\u30ba\u304c0\u4ee5\u4e0b\u3067\u3059 +jsp.error.file.not.found=JSP \u30d5\u30a1\u30a4\u30eb \"{0}\" \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.message.copyinguri={0} \u3092 {1} \u306b\u30b3\u30d4\u30fc\u3057\u307e\u3059 +jsp.message.htmlcomment=\n\u524a\u9664\u3059\u308b\u30b3\u30e1\u30f3\u30c8: \t{0} +jsp.message.handling_directive=\n\u51e6\u7406\u3059\u308b\u6307\u793a\u5b50: {0}\t{1} +jsp.message.handling_plugin=\nPlugin: {0} +jsp.message.package_name_is=\u30d1\u30c3\u30b1\u30fc\u30b8\u540d: {0} +jsp.message.class_name_is=\u30af\u30e9\u30b9\u540d: {0} +jsp.message.java_file_name_is=Java\u30d5\u30a1\u30a4\u30eb\u540d: {0} +jsp.message.class_file_name_is=\u30af\u30e9\u30b9\u30d5\u30a1\u30a4\u30eb\u540d: {0} +jsp.message.accepted={1} \u3067 {0} \u3092\u53d7\u3051\u5165\u308c\u307e\u3059 +jsp.message.adding_jar=jar {0} \u3092\u30af\u30e9\u30b9\u30d1\u30b9\u306b\u8ffd\u52a0\u3057\u307e\u3059 +jsp.message.compiling_with={0} \u3092\u30b3\u30f3\u30d1\u30a4\u30eb\u4e2d\u3067\u3059 +jsp.message.template_text=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8 +jsp.error.missing_attribute=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u306b\u3088\u308b\u3068\u3001\u5c5e\u6027 {0} \u306f\u30bf\u30b0 {1} \u306b\u306f\u5fc5\u9808\u3067\u3059 +jsp.error.bad_attribute=TLD\u306b\u3088\u308b\u3068\u3001\u30bf\u30b0 {1} \u306e\u5c5e\u6027 {0} \u306f\u7121\u52b9\u3067\u3059 +jsp.error.tld.unable_to_read=JAR\u30d5\u30a1\u30a4\u30eb \"{0}\" \u304b\u3089TLD \"{1}\" \u3092\u8aad\u307f\u8fbc\u3081\u307e\u305b\u3093: {2} +jsp.error.tld.unable_to_get_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 : {1} +jsp.error.tld.missing_jar=TLD\u3092\u542b\u3080JAR\u30ea\u30bd\u30fc\u30b9 \"{0}\" \u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.webxml_not_found=web.xml\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.cmd_line.usage=\u4f7f\u7528\u6cd5: [-dd <\u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30d1\u30b9>] [-keepgenerated] \ +<.jsp\u30d5\u30a1\u30a4\u30eb\u7fa4> +jsp.message.cp_is=\u30af\u30e9\u30b9\u30d1\u30b9 {0} \u306f {1} \u3067\u3059 +jsp.error.unable.to_load_taghandler_class=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +jsp.error.unable.to_find_method=\u5c5e\u6027 {0} \u306esetter\u30e1\u30bd\u30c3\u30c9\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.unable.to_convert_string=\u5c5e\u6027 {1}\u306e\u6587\u5b57\u5217\u3092 {0}\u306b\u5909\u63db\u3067\u304d\u307e\u305b\u3093 +jsp.error.unable.to_introspect=\u30bf\u30b0\u30cf\u30f3\u30c9\u30e9\u30af\u30e9\u30b9 {0} \u3092 {1} \u306e\u305f\u3081\u306b\u5185\u7701\u3067\u304d\u307e\u305b\u3093 +jsp.error.bad_tag=\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {1}\u3067\u30a4\u30f3\u30dd\u30fc\u30c8\u3055\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u306f\u3001\u30bf\u30b0 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 +jsp.error.xml.bad_tag=URI \"{1}\" \u306b\u95a2\u9023\u3065\u3051\u3089\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306e\u4e2d\u306b\u306f\u30bf\u30b0 \"{0}\" \u306f\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.bad_string_Character=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 +jsp.error.bad_string_char=\u9577\u30550\u306e\u914d\u5217\u304b\u3089\u306f\u6587\u5b57\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 +jsp.warning.compiler.class.cantcreate=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u306e\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u3092 {1} \u306e\u305f\u3081\u306b\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093\u3002\u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002 +jsp.warning.compiler.class.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d7\u30e9\u30b0\u30a4\u30f3\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002not found. \u30c7\u30d5\u30a9\u30eb\u30c8\u3092Sun\u306eJava\u30b3\u30f3\u30d1\u30a4\u30e9\u306b\u3057\u307e\u3059\u3002 +jsp.warning.compiler.path.notfound=\u6307\u5b9a\u3055\u308c\u305f\u30b3\u30f3\u30d1\u30a4\u30e9\u30d1\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002\u30b7\u30b9\u30c6\u30e0\u306ePATH\u3092\u30c7\u30d5\u30a9\u30eb\u30c8\u306b\u3057\u307e\u3059\u3002 +jsp.error.jspc.uriroot_not_dir=-uriroot \u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u3001\u65e2\u306b\u5b58\u5728\u3059\u308b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspc.missingTarget=\u30bf\u30fc\u30b2\u30c3\u30c8\u304c\u3042\u308a\u307e\u305b\u3093: -webapp\u53c8\u306f-uriroot\uff0c\u53c8\u306f\u4e00\u3064\u4ee5\u4e0a\u306eJSP\u30da\u30fc\u30b8\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspc.no_uriroot=uriroot\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u306e\u3067\u3001\u6307\u5b9a\u3055\u308c\u305fJSP\u30d5\u30a1\u30a4\u30eb(\u7fa4)\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 +jspc.implicit.uriRoot=uriRoot\u306f\u30c7\u30d5\u30a9\u30eb\u30c8"{0}"\u306b\u8a2d\u5b9a\u3055\u308c\u307e\u3059 +jspc.usage=\u4f7f\u7528\u6cd5: jspc [--] \n\ +JSP\u30d5\u30a1\u30a4\u30eb\u306e\u5834\u6240\u306f\u6b21\u306e\u30aa\u30d7\u30b7\u30e7\u30f3\u3067\u6307\u5b9a\u3059\u308b\u304b\u3001\n\ +\ -webapp web-app\u3092\u542b\u3080\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3002\u3059\u3079\u3066\u306eJSP\u30d5\u30a1\u30a4\u30eb\u306f\n\ +\ \u518d\u5e30\u7684\u306b\u89e3\u6790\u3055\u308c\u308b\n\ +\u53c8\u306f\u6b21\u306e\u4efb\u610f\u306e\u6570\u306e\u30d5\u30a1\u30a4\u30eb\u3067\u6307\u5b9a\u3057\u307e\u3059\u3002\n\ +\ JSP\u3068\u3057\u3066\u89e3\u6790\u3055\u308c\u308b\u30d5\u30a1\u30a4\u30eb\n\ +\u30aa\u30d7\u30b7\u30e7\u30f3\u306f\u4ee5\u4e0b\u306e\u901a\u308a\u3067\u3059\n\ +\ -help \u3053\u306e\u30d8\u30eb\u30d7\u30e1\u30c3\u30bb\u30fc\u30b8\u306e\u8868\u793a\n\ +\ -v Verbose\u30e2\u30fc\u30c9\n\ +\ -d \u51fa\u529b\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\ +\ -l \u5931\u6557\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\ +\ -s \u6210\u529f\u3057\u305fJSP\u30da\u30fc\u30b8\u306e\u540d\u524d\u306e\u51fa\u529b\n\ +\ -p \u30bf\u30fc\u30b2\u30c3\u30c8\u30d1\u30c3\u30b1\u30fc\u30b8\u306e\u540d\u524d (\u30c7\u30d5\u30a9\u30eb\u30c8\u306forg.apache.jsp)\n\ +\ -c \u30bf\u30fc\u30b2\u30c3\u30c8\u30af\u30e9\u30b9\u306e\u540d\u524d (\u6700\u521d\u306eJSP\u30da\u30fc\u30b8\u3060\u3051\u306b\u9069\u7528\u3055\u308c\u308b)\n\ +\ -mapped JSP\u306e\u5404HTML\u884c\u3054\u3068\u306bwrite()\u30b3\u30fc\u30eb\u3092\u751f\u6210\n\ +\ -die[#] \u81f4\u547d\u7684\u30a8\u30e9\u30fc\u306b\u30a8\u30e9\u30fc\u30ea\u30bf\u30fc\u30f3\u30b3\u30fc\u30c9(#)\u3092\u751f\u6210 (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f1)\n\ +\ -uribase \u30b3\u30f3\u30d1\u30a4\u30eb\u304c\u76f8\u5bfe\u7684\u306b\u304a\u3053\u306a\u308f\u308c\u308buri\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\n\ +\ (\u30c7\u30d5\u30a9\u30eb\u30c8\u306f"/")\n\ +\ -uriroot -webapp\u3068\u540c\u3058\n\ +\ -compile \u751f\u6210\u3057\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b3\u30f3\u30d1\u30a4\u30eb\n\ +\ -webinc \u30d5\u30a1\u30a4\u30eb\u306b\u90e8\u5206\u7684\u306a\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u30de\u30c3\u30d4\u30f3\u30b0\u3092\u4f5c\u6210\n\ +\ -webxml \u30d5\u30a1\u30a4\u30eb\u306b\u5b8c\u5168\u306aweb.xml\u3092\u4f5c\u6210\n\ +\ -ieplugin Internet Explorer\u306eJava Plugin\u306eclassid\n\ +\ -classpath java.class.path\u30b7\u30b9\u30c6\u30e0\u30d7\u30ed\u30d1\u30c6\u30a3\u306e\u4e0a\u66f8\u304d\n\ +\ -xpoweredBy X-Powered-By\u30ec\u30b9\u30dd\u30f3\u30b9\u30d8\u30c3\u30c0\u306e\u8ffd\u52a0\n\ +\ -trimSpaces \u30a2\u30af\u30b7\u30e7\u30f3\u3084\u6307\u793a\u5b50\u306e\u9593\u306e\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u4e2d\u306e\u30b9\u30da\u30fc\u30b9\u3092\u524a\u9664\n\ +\ -trimSpaces Trim spaces in template text between actions, directives\n\ +\ -javaEncoding Set the encoding charset for Java classes (default UTF-8)\n\ +\ -source Set the -source argument to the compiler (default 1.4)\n\ +\ -target Set the -target argument to the compiler (default 1.4)\n\ + +jspc.webxml.header=\n\ +\n\ +\n\ +\n\ +\n\ +\n +jspc.webxml.footer=\n\ +\n\ +\n +jspc.webinc.header=\n\ +\n +jspc.webinc.footer=\n\ +\n +jspc.webinc.insertEnd= +jspc.webinc.insertStart= +jspc.error.jasperException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f: {1} +jspc.error.generalException=\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb ''{0}'' \u306f\u6b21\u306e\u4f8b\u5916\u3092\u767a\u751f\u3057\u307e\u3057\u305f: +jspc.error.fileDoesNotExist=\u30d5\u30a1\u30a4\u30eb\u5f15\u6570 ''{0}'' \u306f\u5b58\u5728\u3057\u307e\u305b\u3093\u3002 +jspc.error.emptyWebApp=-webapp\u30aa\u30d7\u30b7\u30e7\u30f3\u306b\u306f\u3001\u30d5\u30a1\u30a4\u30eb\u5f15\u6570\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.library.invalid=\u30e9\u30a4\u30d6\u30e9\u30ea{0}\u306b\u5f93\u3046\u3068JSP\u30da\u30fc\u30b8\u306f\u7121\u52b9\u3067\u3059: {1} +jsp.error.tlvclass.instantiation=TagLibraryValidator\u30af\u30e9\u30b9\u306e\u30ed\u30fc\u30c9\u53c8\u306f\u30a4\u30f3\u30b9\u30bf\u30f3\u30b9\u5316\u306b\u5931\u6557\u3057\u307e\u3057\u305f: {0} +jsp.error.tlv.invalid.page={0} \u306b\u5bfe\u3059\u308bTagLibraryValidator\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059 ({1}) +jsp.error.tei.invalid.attributes={0} \u306b\u5bfe\u3059\u308bTagExtraInfo\u304b\u3089\u306e\u691c\u8a3c\u30a8\u30e9\u30fc\u30e1\u30c3\u30bb\u30fc\u30b8\u3067\u3059 +jsp.parser.sax.propertynotsupported=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0} +jsp.parser.sax.propertynotrecognized=SAX\u30d7\u30ed\u30d1\u30c6\u30a3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0} +jsp.parser.sax.featurenotsupported=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093: {0} +jsp.parser.sax.featurenotrecognized=SAX\u30d5\u30a3\u30fc\u30c1\u30e3\u304c\u8a8d\u8b58\u3055\u308c\u307e\u305b\u3093: {0} +jsp.error.no.more.content=\u5fc5\u8981\u306a\u89e3\u6790\u4e2d\u306b\u5185\u5bb9\u306e\u6700\u5f8c\u307e\u3067\u9054\u3057\u307e\u3057\u305f: \u30bf\u30b0\u306e\u30cd\u30b9\u30c8\u306e\u30a8\u30e9\u30fc\u304b\u3082\u3057\u308c\u307e\u305b\u3093 +jsp.error.parse.xml=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc +jsp.error.parse.xml.line=\u30d5\u30a1\u30a4\u30eb{0}\u306eXML\u89e3\u6790\u30a8\u30e9\u30fc: (\u884c {1}, \u5217 {2}) +jsp.error.parse.xml.scripting.invalid.body={0} \u8981\u7d20\u306e\u30dc\u30c7\u30a3\u306fXML\u8981\u7d20\u3092\u542b\u3093\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.internal.tldinit=TldLocationsCache\u3092\u521d\u671f\u5316\u4e2d\u306e\u4f8b\u5916\u3067\u3059: {0} +jsp.error.internal.filenotfound=\u5185\u90e8\u30a8\u30e9\u30fc: \u30d5\u30a1\u30a4\u30eb {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.internal.evaluator_not_found=\u5185\u90e8\u30a8\u30e9\u30fc: \u5f0f\u691c\u8a3c\u5668\u3092\u30ed\u30fc\u30c9\u3067\u304d\u307e\u305b\u3093 +jsp.error.parse.xml.invalidPublicId=\u7121\u52b9\u306aPUBLIC ID: {0} +jsp.error.include.flush.invalid.value=flush\u5c5e\u6027\u306b\u7121\u52b9\u306a\u5024\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059: {0} +jsp.error.unsupported.encoding=\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u306a\u3044\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059: {0} +tld.error.variableNotAllowed=null\u3067\u306a\u3044\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u3092\u8fd4\u3059TagExtraInfo\u3092\u6301\u3064\u4e00\u3064\u4ee5\u4e0a\u306e\u5909\u6570\u526f\u8981\u7d20\u3092\u6301\u3064\u30bf\u30b0\u306f\u30a8\u30e9\u30fc\u3067\u3059\u3002 +jsp.error.tldInWebDotXmlNotFound=web.xml\u3067\u6307\u5b9a\u3055\u308c\u305fURI {0} \u306bTLD\u3092\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 +jsp.error.taglibDirective.absUriCannotBeResolved=\u7d76\u5bfeURI: {0} \u306fweb.xml\u3068\u3053\u306e\u30a2\u30d7\u30ea\u30b1\u30fc\u30b7\u30e7\u30f3\u3092\u914d\u5099\u3057\u305fJAR\u30d5\u30a1\u30a4\u30eb\u306e\u3069\u3061\u3089\u304b\u3067\u3082\u89e3\u6c7a\u3067\u304d\u307e\u305b\u3093 +jsp.error.taglibDirective.missing.location=taglib\u6307\u793a\u5b50\u306e\u4e2d\u306b'uri'\u5c5e\u6027\u3068'tagdir'\u5c5e\u6027\u306e\u3069\u3061\u3089\u3082\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.taglibDirective.both_uri_and_tagdir=\'uri\'\u5c5e\u6027 \u3068 \'tagdir\'\u5c5e\u6027\u306e\u4e21\u65b9\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.invalid.tagdir=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30c7\u30a3\u30ec\u30af\u30c8\u30ea {0} \u304c\"/WEB-INF/tags\"\u3067\u59cb\u307e\u308a\u307e\u305b\u3093 +jsp.error.unterminated.user.tag=\u672a\u7d42\u4e86\u306e\u30e6\u30fc\u30b6\u5b9a\u7fa9\u30bf\u30b0: \u7d42\u4e86\u30bf\u30b0 {0} \u304c\u898b\u3064\u304b\u3089\u306a\u3044\u304b\u3001\u30cd\u30b9\u30c8\u304c\u9593\u9055\u3063\u3066\u3044\u307e\u3059 +#jspx.error.templateDataNotInJspCdata=Validation Error: Element <{0}> cannot have template data. Template data must be encapsulated within a <jsp:cdata> element. [JSP1.2 PFD section 5.1.9]\nTemplate data in error: {1} +jspx.error.templateDataNotInJspCdata=\u8a3c\u660e\u30a8\u30e9\u30fc: \u8981\u7d20<{0}>\u306f\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093\u3002\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306f\u3001<jsp:text>\u8981\u7d20\u306e\u4e2d\u3067\u96a0\u853d\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u3002[JSP1.2 PFD 5.1.9]\n\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c7\u30fc\u30bf\u306e\u30a8\u30e9\u30fc\u3067\u3059: {1} +#Error while processing taglib jar file {0}: {1} +jsp.error.taglib.reserved.prefix=taglib\u30d7\u30ea\u30d5\u30a3\u30af\u30b9 {0} \u306f\u4e88\u7d04\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.invalid.javaEncoding=\u7121\u52b9\u306aJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u3067\u3059\u3002{0}\u3092\u8a66\u3057\u3066\u3001\u305d\u308c\u304b\u3089{1}\u3092\u8a66\u3057\u307e\u3057\u305f\u304c\u3001\u4e21\u65b9\u304c\u5931\u6557\u3057\u307e\u3057\u305f +jsp.error.needAlternateJavaEncoding=\u30c7\u30d5\u30a9\u30eb\u30c8\u306eJava\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 {0} \u306f\u3042\u306a\u305f\u306e\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0\u3067\u306f\u7121\u52b9\u3067\u3059\u3002JspServlet\u306e 'javaEncoding' \u30d1\u30e9\u30e1\u30bf\u3067\u3001\u5225\u306e\u5024\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059\u3002 +#Error when compiling, used for jsp line number error messages +jsp.error.single.line.number=JSP\u30d5\u30a1\u30a4\u30eb: {1} \u306e\u4e2d\u306e{0}\u884c\u76ee\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +jsp.error.multiple.line.number=\n\nJPS\u30d5\u30a1\u30a4\u30eb: {2}\u306e\u4e2d\u306e{0}\u884c\u76ee\u3068{1}\u884c\u76ee\u306e\u9593\u3067\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\n\n +jsp.error.corresponding.servlet=\u751f\u6210\u3055\u308c\u305f\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30a8\u30e9\u30fc\u3067\u3059:\n +jsp.error.empty.body.not.allowed={0} \u306b\u5bfe\u3057\u3066\u7a7a\u306e\u30dc\u30c7\u30a3\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 +jsp.error.jspbody.required=jsp:attribute\u304c\u4f7f\u7528\u3055\u308c\u305f\u5834\u5408\u306b\u306f\u3001{0}\u306b\u30bf\u30b0\u30dc\u30c7\u30a3\u3092\u6307\u5b9a\u3059\u308b\u305f\u3081\u306bjsp:body\u3092\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspbody.emptybody.only={0} \u30bf\u30b0\u306f\u3001\u305d\u306e\u30dc\u30c7\u30a3\u4e2d\u306bjsp:attribute\u3060\u3051\u3092\u6301\u3064\u3053\u3068\u304c\u3067\u304d\u307e\u3059 +jsp.error.no.scriptlets=\u30b9\u30af\u30ea\u30d7\u30c6\u30a3\u30f3\u30b0\u8981\u7d20 ( <%!\u3001<jsp:declaration\u3001<%=\u3001<jsp:expression\u3001<%\u3001<jsp:scriptlet ) \u306f\u3053\u3053\u3067\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 +jsp.error.internal.unexpected_node_type=\u5185\u90e8\u30a8\u30e9\u30fc: \u672a\u77e5\u306e\u30ce\u30fc\u30c9\u30bf\u30a4\u30d7\u304c\u8868\u308c\u307e\u3057\u305f +jsp.error.tld.fn.invalid.signature=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1} +jsp.error.tld.fn.duplicate.name=\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea {1} \u306e\u4e2d\u306e\u95a2\u6570\u540d {0} \u304c\u91cd\u8907\u3057\u3066\u3044\u307e\u3059 +jsp.error.tld.fn.invalid.signature.commaexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u30b3\u30f3\u30de ',' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002 +jsp.error.tld.fn.invalid.signature.parenexpected=TLD\u306e\u4e2d\u306e\u95a2\u6570\u30b7\u30b0\u30cd\u30c1\u30e3\u306b\u5bfe\u3059\u308b\u7121\u52b9\u306a\u69cb\u6587\u3067\u3059\u3002\u62ec\u5f27 '(' \u304c\u3042\u308a\u307e\u305b\u3093\u3002\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea: {0}\u3001\u95a2\u6570: {1}\u3002 +jsp.error.tld.mandatory.element.missing=\u5fc5\u9808TLD\u8981\u7d20\u304c\u306a\u3044\u3001\u53c8\u306f\u7a7a\u3067\u3059: {0} +jsp.error.dynamic.attributes.not.implemented={0} \u30bf\u30b0\u306f\u305d\u308c\u304cdynamic\u5c5e\u6027\u3092\u53d7\u3051\u4ed8\u3051\u308b\u3068\u5ba3\u8a00\u3057\u3066\u3044\u307e\u3059\u304c\u3001\u305d\u308c\u306b\u5fc5\u8981\u306a\u30a4\u30f3\u30bf\u30d5\u30a7\u30fc\u30b9\u3092\u5b9f\u88c5\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.nomatching.fragment=attribute\u6307\u793a\u5b50 (name={0}\u304a\u3088\u3073fragment=true\u3092\u6301\u3064) \u304cfragment\u6307\u793a\u5b50\u3088\u308a\u524d\u306b\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.attribute.noequal=\u7b49\u53f7\u8a18\u53f7\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.attribute.noquote=\u5f15\u7528\u7b26\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.attribute.unterminated={0} \u306e\u5c5e\u6027\u304c\u6b63\u3057\u304f\u7d42\u4e86\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.missing.tagInfo={0} \u306b\u5bfe\u3059\u308bTagInfo\u30aa\u30d6\u30b8\u30a7\u30af\u30c8\u304cTLD\u304b\u3089\u5931\u308f\u308c\u307e\u3057\u305f +jsp.error.fragmentwithtype='fragment'\u5c5e\u6027\u3068'type'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'type'\u306f'javax.servlet.jsp.tagext.JspFragment'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059 +jsp.error.fragmentwithrtexprvalue='fragment'\u5c5e\u6027\u3068'rtexprvalue'\u5c5e\u6027\u3092\u4e21\u65b9\u6307\u5b9a\u3067\u304d\u307e\u305b\u3093\u3002'fragment'\u304c\u5b58\u5728\u3059\u308b\u5834\u5408\u306b\u306f'rtexprvalue'\u306f'true'\u306b\u56fa\u5b9a\u3055\u308c\u307e\u3059 +jsp.error.fragmentWithDeclareOrScope='fragment'\u5c5e\u6027\u3068'declare'\u5c5e\u6027\u306e\u4e21\u65b9\u53c8\u306f'scope'\u5c5e\u6027\u304cvariable\u6307\u793a\u5b50\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u307e\u3059 +jsp.error.var_and_varReader=\'var\'\u53c8\u306f\'varReader\'\u306e\u3069\u3061\u3089\u304b\u4e00\u3064\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u304c\u3067\u304d\u307e\u3059 +jsp.error.missing_var_or_varReader=\'var\'\u53c8\u306f\'varReader\'\u5c5e\u6027\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.warning.bad.urlpattern.propertygroup=web.xml\u4e2d\u306eurl-pattern\u526f\u8981\u7d20\u4e2d\u306b\u8aa4\u3063\u305f\u5024 {0} \u304c\u3042\u308a\u307e\u3059 +jsp.error.unknown_attribute_type=\u5c5e\u6027 {0} \u306b\u5bfe\u3059\u308b\u672a\u77e5\u306e\u5c5e\u6027\u30bf\u30a4\u30d7\u3067\u3059 +jsp.error.jspelement.missing.name=\u5fc5\u9808\u306eXML\u30b9\u30bf\u30a4\u30eb\u306e'name'\u5c5e\u6027\u304cjsp:element\u4e2d\u306b\u3042\u308a\u307e\u305b\u3093 +jsp.error.xmlns.redefinition.notimplemented=\u5185\u90e8\u30a8\u30e9\u30fc: xmlns:{0}\u3092\u518d\u5b9a\u7fa9\u3057\u3088\u3046\u3068\u3057\u307e\u3057\u305f\u3002\u540d\u524d\u7a7a\u9593\u306e\u518d\u5b9a\u7fa9\u306f\u5b9f\u88c5\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002 +jsp.error.could.not.add.taglibraries=1\u3064\u4ee5\u4e0a\u306e\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093 +jsp.error.duplicate.name.jspattribute=\u6a19\u6e96\u53c8\u306f\u30ab\u30b9\u30bf\u30e0\u30a2\u30af\u30b7\u30e7\u30f3\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u5c5e\u6027 {0} \u306f\u305d\u308c\u306b\u56f2\u307e\u308c\u305fjsp:attribute\u4e2d\u306ename\u5c5e\u6027\u306e\u5024\u3068\u3057\u3066\u3082\u8868\u308c\u307e\u3059 +jsp.error.not.in.template=\u30c6\u30f3\u30d7\u30ec\u30fc\u30c8\u30c6\u30ad\u30b9\u30c8\u30dc\u30c7\u30a3\u4e2d\u3067\u306f {0} \u306f\u8a31\u3055\u308c\u307e\u305b\u3093 +jsp.error.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059 +jsp.error.xml.badStandardAction=\u7121\u52b9\u306a\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u3059: {0} +jsp.error.tagdirective.badbodycontent=tag\u6307\u793a\u5b50\u4e2d\u306e\u7121\u52b9\u306abody-content ({0})\u3067\u3059 +jsp.error.simpletag.badbodycontent=\u30af\u30e9\u30b9 {0} \u306eTLD\u306fSimpleTag\u306b\u7121\u52b9\u306abody-content (JSP)\u3092\u6307\u5b9a\u3057\u3066\u3044\u307e\u3059 +jsp.error.config_pagedir_encoding_mismatch=jsp-property-group\u4e2d\u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308bPage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059 +jsp.error.prolog_pagedir_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cpage\u6307\u793a\u5b50\u4e2d\u306e\u6307\u5b9a ({1}) \u3068\u9055\u3044\u307e\u3059 +jsp.error.prolog_config_encoding_mismatch=XML\u5c0e\u5165\u90e8\u3067\u6307\u5b9a\u3055\u308c\u305fpage-encoding ({0}) \u304cjsp-property-group\u4e2d\u306e\u6307\u5b9a\u3068\u9055\u3044\u307e\u3059 ({1}) +jsp.error.attribute.custom.non_rt_with_expr=TLD\u53c8\u306f\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u4e2d\u306eattribute\u6307\u793a\u5b50\u306b\u5f93\u3063\u3066\u5c5e\u6027{0}\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093 +jsp.error.attribute.standard.non_rt_with_expr={1} \u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e {0} \u5c5e\u6027\u306f\u3069\u3093\u306a\u5f0f\u3082\u53d7\u3051\u4ed8\u3051\u307e\u305b\u3093 +jsp.error.scripting.variable.missing_name=\u5c5e\u6027 {0} \u304b\u3089\u30b9\u30af\u30ea\u30d7\u30c8\u5909\u6570\u540d\u3092\u6c7a\u5b9a\u3067\u304d\u307e\u305b\u3093 +jasper.error.emptybodycontent.nonempty=TLD\u306b\u5f93\u3063\u3066\u30bf\u30b0 {0} \u306f\u7a7a\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093\u304c\u3001\u305d\u3046\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +jsp.error.tagfile.nameNotUnique={2}\u884c\u76ee\u306e {0} \u306e\u5024\u3068 {1} \u306e\u5024\u306f\u540c\u3058\u3067\u3059 +jsp.error.tagfile.nameFrom.noAttribute=\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024\u3067\u3042\u308b\u5024 \"{0}\" \u306ename\u5c5e\u6027\u3092\u6301\u3064attribute\u6307\u793a\u5b50\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.tagfile.nameFrom.badAttribute=attribute\u6307\u793a\u5b50 ({1}\u884c\u76ee\u3067\u5ba3\u8a00\u3055\u308c\u3001\u305d\u306ename\u5c5e\u6027\u304c\"{0}\"\u3001\u3053\u306ename-from-attribute\u5c5e\u6027\u306e\u5024) \u306fjava.lang.String\u578b\u306e\"required\" \u3067 \"rtexprvalue\".\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.page.noSession=\u30bb\u30c3\u30b7\u30e7\u30f3\u306b\u52a0\u308f\u3063\u3066\u3044\u306a\u3044\u30da\u30fc\u30b8\u306e\u4e2d\u3067\u306f\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u306b\u30a2\u30af\u30bb\u30b9\u3067\u304d\u307e\u305b\u3093 +jsp.error.useBean.noSession=JSP\u30da\u30fc\u30b8\u304c(page\u6307\u793a\u5b50\u306b\u3088\u308a)\u30bb\u30c3\u30b7\u30e7\u30f3\u4e2d\u3067\u5354\u8abf\u3057\u306a\u3044\u3053\u3068\u3092\u5ba3\u8a00\u3057\u3066\u3044\u308b\u6642\u3001\u30bb\u30c3\u30b7\u30e7\u30f3\u30b9\u30b3\u30fc\u30d7\u3092\u4f7f\u7528\u3059\u308b\u305f\u3081\u306euseBean\u304c\u4e0d\u6b63\u3067\u3059 +jsp.error.xml.encodingByteOrderUnsupported = \u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0 \"{0}\" \u306b\u6307\u5b9a\u3055\u308c\u305f\u30d0\u30a4\u30c8\u30aa\u30fc\u30c0\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.xml.encodingDeclInvalid = \u7121\u52b9\u306a\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u540d \"{0}\" \u3067\u3059 +jsp.error.xml.encodingDeclRequired = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306b\u30a8\u30f3\u30b3\u30fc\u30c7\u30a3\u30f3\u30b0\u5ba3\u8a00\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.morePseudoAttributes = \u3088\u308a\u591a\u304f\u306e\u7591\u4f3c\u5c5e\u6027\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.noMorePseudoAttributes = \u3053\u308c\u4ee5\u4e0a\u306e\u7591\u4f3c\u5c5e\u6027\u306f\u8a31\u3055\u308c\u307e\u305b\u3093 +jsp.error.xml.versionInfoRequired = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u30d0\u30fc\u30b8\u30e7\u30f3\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.xmlDeclUnterminated = XML\u5ba3\u8a00\u306f\"?>\"\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.reservedPITarget = \"[xX][mM][lL]\"\u306b\u4e00\u81f4\u3059\u308b\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u306f\u8a31\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.xml.spaceRequiredInPI = \u7a7a\u767d\u304c\u51e6\u7406\u547d\u4ee4\u30bf\u30fc\u30b2\u30c3\u30c8\u3068\u30c7\u30fc\u30bf\u306e\u9593\u306b\u5fc5\u8981\u3067\u3059 +jsp.error.xml.invalidCharInContent = \u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u306e\u8981\u7d20\u5185\u5bb9\u306e\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.xml.spaceRequiredBeforeStandalone = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.sdDeclInvalid = \u30b9\u30bf\u30f3\u30c9\u30a2\u30ed\u30f3\u6587\u66f8\u5ba3\u8a00\u5024\u306f\"yes\"\u53c8\u306f\"no\"\u306e\u3069\u3061\u3089\u304b\u3067\u3042\u308a\u3001\"{0}\"\u3067\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.invalidCharInPI = \u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u547d\u4ee4\u51e6\u7406\u4e2d\u306b\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.xml.versionNotSupported = XML\u30d0\u30fc\u30b8\u30e7\u30f3 \"{0}\" \u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3001XML 1.0\u3060\u3051\u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u3059 +jsp.error.xml.pseudoAttrNameExpected = \u7591\u4f3c\u5c5e\u6027\u540d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.expectedByte ={1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30d0\u30a4\u30c8 {0} \u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.invalidByte = {1}\u30d0\u30a4\u30c8UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u7121\u52b9\u306a\u30d0\u30a4\u30c8 {0} \u3067\u3059 +jsp.error.xml.operationNotSupported = {1} reader\u306f\u64cd\u4f5c \"{0}\" \u3092\u30b5\u30dd\u30fc\u30c8\u3057\u3066\u3044\u307e\u305b\u3093 +jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.xml.invalidASCII = \u30d0\u30a4\u30c8 \"{0}\" \u306f7\u30d3\u30c3\u30c8ASCII\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl = XML\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eencoding\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.spaceRequiredBeforeVersionInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl = XML\u5ba3\u8a00\u306eversion\u7591\u4f3c\u5c5e\u6027\u306e\u524d\u306b\u7a7a\u767d\u304c\u5fc5\u8981\u3067\u3059 +jsp.error.xml.eqRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = '' \u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.eqRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u3067\"{0}\"\u306e\u6b21\u306b'' = ''\u6587\u5b57\u304c\u7d9a\u304b\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.quoteRequiredInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.quoteRequiredInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306f\u30af\u30aa\u30fc\u30c8\u3067\u56f2\u307e\u308c\u305f\u6587\u5b57\u5217\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.xml.invalidCharInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.xml.invalidCharInXMLDecl = XML\u5ba3\u8a00\u306e\u4e2d\u306b\u7121\u52b9\u306aXML\u6587\u5b57 (Unicode: 0x{0}) \u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.xml.closeQuoteMissingInTextDecl = \u30c6\u30ad\u30b9\u30c8\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.xml.closeQuoteMissingInXMLDecl = XML\u5ba3\u8a00\u4e2d\u306e\"{0}\"\u306b\u7d9a\u304f\u5024\u306e\u4e2d\u306e\u6700\u5f8c\u306e\u30af\u30aa\u30fc\u30c8\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.xml.invalidHighSurrogate = UTF-8\u30b7\u30fc\u30b1\u30f3\u30b9\u306e\u30cf\u30a4\u30b5\u30ed\u30b2\u30fc\u30c8\u30d3\u30c3\u30c8\u306f0x10\u3092\u8d8a\u3048\u3066\u306f\u3044\u3051\u307e\u305b\u3093\u304c\u30010x{0}\u304c\u898b\u3064\u304b\u308a\u307e\u3057\u305f +jsp.error.multiple.jsp = \u8907\u6570\u306e\u4ed5\u69d8\u3092\u6e80\u305f\u3059\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.jspoutput.conflict=<jsp:output>: \"{0}\"\u306b\u7570\u306a\u308b\u5024\u3092\u8907\u6570\u56de\u6307\u5b9a\u3059\u308b\u306e\u306f\u7121\u52b9\u3067\u3059 (\u65e7: {1}, \u65b0: {2}) +jsp.error.jspoutput.doctypenamesystem=<jsp:output>: 'doctype-root-element' \u53ca\u3073 'doctype-system' \u5c5e\u6027\u306f\u540c\u6642\u306b\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspoutput.doctypepulicsystem=<jsp:output>: 'doctype-public'\u5c5e\u6027\u3092\u6307\u5b9a\u3059\u308b\u5834\u5408\u306f\u3001'doctype-system' \u5c5e\u6027\u3082\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspoutput.nonemptybody=<jsp:output> \u30dc\u30c7\u30a3\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.jspoutput.invalidUse=<jsp:output> \u6a19\u6e96\u69cb\u6587\u306e\u4e2d\u3067\u4f7f\u7528\u3057\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.attributes.not.allowed = {0} \u306f\u5c5e\u6027\u3092\u6301\u3064\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.tagfile.badSuffix=\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9 {0} \u306e\u4e2d\u306b\".tag\" \u62e1\u5f35\u5b50\u304c\u3042\u308a\u307e\u305b\u3093 +jsp.error.tagfile.illegalPath=\u4e0d\u6b63\u306a\u30bf\u30b0\u30d5\u30a1\u30a4\u30eb\u30d1\u30b9\u3067\u3059: {0}\u3001\u3053\u308c\u306f\"/WEB-INF/tags\"\u53c8\u306f\"/META-INF/tags\"\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.plugin.wrongRootElement={0} \u306e\u4e2d\u306e\u30eb\u30fc\u30c8\u8981\u7d20\u306e\u540d\u524d\u306f {1} \u3067\u306f\u3042\u308a\u307e\u305b\u3093 +jsp.error.attribute.invalidPrefix=\u5c5e\u6027\u306e\u30d7\u30ec\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3069\u306e\u53d6\u308a\u8fbc\u307e\u308c\u305f\u30bf\u30b0\u30e9\u30a4\u30d6\u30e9\u30ea\u306b\u3082\u5bfe\u5fdc\u3057\u307e\u305b\u3093 +jsp.error.nested.jspattribute=jsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.nested.jspbody=jsp:body\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306f\u5225\u306ejsp:body\u53c8\u306fjsp:attribute\u6a19\u6e96\u30a2\u30af\u30b7\u30e7\u30f3\u306e\u7bc4\u56f2\u5185\u3067\u30cd\u30b9\u30c8\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.variable.either.name=name-given\u53c8\u306fname-from-attribute\u5c5e\u6027\u306e\u3069\u3061\u3089\u304b\u3092variable\u6307\u793a\u5b50\u306e\u4e2d\u3067\u6307\u5b9a\u3055\u308c\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.variable.both.name=variable\u6307\u793a\u5b50\u4e2d\u3067name-given\u3068name-from-attribute\u5c5e\u6027\u306e\u4e21\u65b9\u3092\u6307\u5b9a\u3059\u308b\u3053\u3068\u306f\u3067\u304d\u307e\u305b\u3093 +jsp.error.variable.alias=name-from-attribute\u304a\u3088\u3073alias\u5c5e\u6027\u306e\u4e21\u65b9\u3092variable\u6307\u793a\u5b50\u4e2d\u306b\u6307\u5b9a\u3059\u308b\u3001\u53c8\u306f\u3069\u3061\u3089\u3082\u6307\u5b9a\u3057\u306a\u3044\u3053\u3068\u304c\u3067\u304d\u307e\u3059 +jsp.error.attribute.null_name=\u7a7a\u306e\u5c5e\u6027\u540d\u3067\u3059 +jsp.error.jsptext.badcontent=\'<\'\u304c<jsp:text>\u306e\u30dc\u30c7\u30a3\u306e\u4e2d\u306b\u73fe\u308c\u308b\u6642\u306f\u3001CDATA\u306e\u4e2d\u306b\u96a0\u853d\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.jsproot.version.invalid=\u7121\u52b9\u306a\u30d0\u30fc\u30b8\u30e7\u30f3\u756a\u53f7\u3067\u3059: \"{0}\"\u3001\"1.2\" \u53c8\u306f \"2.0\"\u3000\u3067\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.noFunctionPrefix=\u30c7\u30d5\u30a9\u30eb\u30c8\u306e\u540d\u524d\u7a7a\u9593\u304c\u6307\u5b9a\u3055\u308c\u3066\u3044\u306a\u3044\u6642\u306b\u306f\u3001\u95a2\u6570 {0} \u306f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u4ed8\u304d\u3067\u4f7f\u7528\u3057\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +jsp.error.noFunction=\u95a2\u6570 {0} \u3092\u6307\u5b9a\u3055\u308c\u305f\u30d7\u30ea\u30d5\u30a3\u30af\u30b9\u3067\u914d\u7f6e\u3067\u304d\u307e\u305b\u3093 +jsp.error.noFunctionMethod=\u95a2\u6570 \"{1}\" \u306e\u30e1\u30bd\u30c3\u30c9 \"{0}\" \u304c \"{2}\" \u4e2d\u3067\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +jsp.error.function.classnotfound=TLD\u306e\u4e2d\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093: {2} +jsp.error.signature.classnotfound=TLD\u306e\u4e2d\u306e\u30e1\u30bd\u30c3\u30c9\u30b7\u30b0\u30cd\u30c1\u30e3\u3067\u95a2\u6570 {1} \u306b\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30af\u30e9\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3002 {2} +jsp.error.text.has_subelement=<jsp:text> \u306f\u526f\u8981\u7d20\u3092\u6301\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +jsp.error.data.file.read=\u30d5\u30a1\u30a4\u30eb \"{0}\" \u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f +jsp.error.prefix.refined=\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u304c\u73fe\u5728\u306e\u30b9\u30b3\u30fc\u30d7\u4e2d\u3067\u65e2\u306b {2} \u3068\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u308b\u306e\u3067 {1} \u306b\u518d\u5b9a\u7fa9\u3057\u307e\u3057\u305f +jsp.error.nested_jsproot=\u5165\u308c\u5b50\u306b\u306a\u3063\u305f <jsp:root> \u3067\u3059 +jsp.error.unbalanced.endtag=\u7d42\u4e86\u30bf\u30b0 \"</{0}\" \u306e\u5bfe\u5fdc\u304c\u53d6\u308c\u3066\u3044\u307e\u305b\u3093 +jsp.error.invalid.bean=useBean\u306e\u30af\u30e9\u30b9\u5c5e\u6027 {0} \u306e\u5024\u304c\u7121\u52b9\u3067\u3059 +jsp.error.prefix.use_before_dcl=\u3053\u306e\u30bf\u30b0\u6307\u793a\u5b50\u3067\u6307\u5b9a\u3055\u308c\u3066\u3044\u308b\u30d7\u30ea\u30d5\u30a3\u30c3\u30af\u30b9 {0} \u306f\u3001\u3059\u3067\u306b\u30d5\u30a1\u30a4\u30eb {1} \u306e {2} \u884c\u76ee\u306e\u30a2\u30af\u30b7\u30e7\u30f3\u3067\u4f7f\u7528\u3055\u308c\u3066\u3044\u307e\u3059 + diff --git a/java/org/apache/jasper/runtime/BodyContentImpl.java b/java/org/apache/jasper/runtime/BodyContentImpl.java index 06b44b88c..ee7633b6a 100644 --- a/java/org/apache/jasper/runtime/BodyContentImpl.java +++ b/java/org/apache/jasper/runtime/BodyContentImpl.java @@ -1,608 +1,608 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.CharArrayReader; -import java.io.IOException; -import java.io.Reader; -import java.io.Writer; - -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.tagext.BodyContent; - -import org.apache.jasper.Constants; - -/** - * Write text to a character-output stream, buffering characters so as - * to provide for the efficient writing of single characters, arrays, - * and strings. - * - * Provide support for discarding for the output that has been buffered. - * - * @author Rajiv Mordani - * @author Jan Luehe - */ -public class BodyContentImpl extends BodyContent { - - private static final String LINE_SEPARATOR = - System.getProperty("line.separator"); - private static final boolean LIMIT_BUFFER = - Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false")).booleanValue(); - - private char[] cb; - private int nextChar; - private boolean closed; - - // Enclosed writer to which any output is written - private Writer writer; - - // See comment in setWriter() - private int bufferSizeSave; - - /** - * Constructor. - */ - public BodyContentImpl(JspWriter enclosingWriter) { - super(enclosingWriter); - bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; - cb = new char[bufferSize]; - nextChar = 0; - closed = false; - } - - /** - * Write a single character. - */ - public void write(int c) throws IOException { - if (writer != null) { - writer.write(c); - } else { - ensureOpen(); - if (nextChar >= bufferSize) { - reAllocBuff (1); - } - cb[nextChar++] = (char) c; - } - } - - /** - * Write a portion of an array of characters. - * - *

        Ordinarily this method stores characters from the given array into - * this stream's buffer, flushing the buffer to the underlying stream as - * needed. If the requested length is at least as large as the buffer, - * however, then this method will flush the buffer and write the characters - * directly to the underlying stream. Thus redundant - * DiscardableBufferedWriters will not copy data - * unnecessarily. - * - * @param cbuf A character array - * @param off Offset from which to start reading characters - * @param len Number of characters to write - */ - public void write(char[] cbuf, int off, int len) throws IOException { - if (writer != null) { - writer.write(cbuf, off, len); - } else { - ensureOpen(); - - if ((off < 0) || (off > cbuf.length) || (len < 0) || - ((off + len) > cbuf.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - if (len >= bufferSize - nextChar) - reAllocBuff (len); - - System.arraycopy(cbuf, off, cb, nextChar, len); - nextChar+=len; - } - } - - /** - * Write an array of characters. This method cannot be inherited from the - * Writer class because it must suppress I/O exceptions. - */ - public void write(char[] buf) throws IOException { - if (writer != null) { - writer.write(buf); - } else { - write(buf, 0, buf.length); - } - } - - /** - * Write a portion of a String. - * - * @param s String to be written - * @param off Offset from which to start reading characters - * @param len Number of characters to be written - */ - public void write(String s, int off, int len) throws IOException { - if (writer != null) { - writer.write(s, off, len); - } else { - ensureOpen(); - if (len >= bufferSize - nextChar) - reAllocBuff(len); - - s.getChars(off, off + len, cb, nextChar); - nextChar += len; - } - } - - /** - * Write a string. This method cannot be inherited from the Writer class - * because it must suppress I/O exceptions. - */ - public void write(String s) throws IOException { - if (writer != null) { - writer.write(s); - } else { - write(s, 0, s.length()); - } - } - - /** - * Write a line separator. The line separator string is defined by the - * system property line.separator, and is not necessarily a single - * newline ('\n') character. - * - * @throws IOException If an I/O error occurs - */ - public void newLine() throws IOException { - if (writer != null) { - writer.write(LINE_SEPARATOR); - } else { - write(LINE_SEPARATOR); - } - } - - /** - * Print a boolean value. The string produced by {@link - * java.lang.String#valueOf(boolean)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param b The boolean to be printed - * @throws IOException - */ - public void print(boolean b) throws IOException { - if (writer != null) { - writer.write(b ? "true" : "false"); - } else { - write(b ? "true" : "false"); - } - } - - /** - * Print a character. The character is translated into one or more bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param c The char to be printed - * @throws IOException - */ - public void print(char c) throws IOException { - if (writer != null) { - writer.write(String.valueOf(c)); - } else { - write(String.valueOf(c)); - } - } - - /** - * Print an integer. The string produced by {@link - * java.lang.String#valueOf(int)} is translated into bytes according - * to the platform's default character encoding, and these bytes are - * written in exactly the manner of the {@link #write(int)} - * method. - * - * @param i The int to be printed - * @throws IOException - */ - public void print(int i) throws IOException { - if (writer != null) { - writer.write(String.valueOf(i)); - } else { - write(String.valueOf(i)); - } - } - - /** - * Print a long integer. The string produced by {@link - * java.lang.String#valueOf(long)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param l The long to be printed - * @throws IOException - */ - public void print(long l) throws IOException { - if (writer != null) { - writer.write(String.valueOf(l)); - } else { - write(String.valueOf(l)); - } - } - - /** - * Print a floating-point number. The string produced by {@link - * java.lang.String#valueOf(float)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param f The float to be printed - * @throws IOException - */ - public void print(float f) throws IOException { - if (writer != null) { - writer.write(String.valueOf(f)); - } else { - write(String.valueOf(f)); - } - } - - /** - * Print a double-precision floating-point number. The string produced by - * {@link java.lang.String#valueOf(double)} is translated into - * bytes according to the platform's default character encoding, and these - * bytes are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param d The double to be printed - * @throws IOException - */ - public void print(double d) throws IOException { - if (writer != null) { - writer.write(String.valueOf(d)); - } else { - write(String.valueOf(d)); - } - } - - /** - * Print an array of characters. The characters are converted into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param s The array of chars to be printed - * - * @throws NullPointerException If s is null - * @throws IOException - */ - public void print(char[] s) throws IOException { - if (writer != null) { - writer.write(s); - } else { - write(s); - } - } - - /** - * Print a string. If the argument is null then the string - * "null" is printed. Otherwise, the string's characters are - * converted into bytes according to the platform's default character - * encoding, and these bytes are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param s The String to be printed - * @throws IOException - */ - public void print(String s) throws IOException { - if (s == null) s = "null"; - if (writer != null) { - writer.write(s); - } else { - write(s); - } - } - - /** - * Print an object. The string produced by the {@link - * java.lang.String#valueOf(Object)} method is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param obj The Object to be printed - * @throws IOException - */ - public void print(Object obj) throws IOException { - if (writer != null) { - writer.write(String.valueOf(obj)); - } else { - write(String.valueOf(obj)); - } - } - - /** - * Terminate the current line by writing the line separator string. The - * line separator string is defined by the system property - * line.separator, and is not necessarily a single newline - * character ('\n'). - * - * @throws IOException - */ - public void println() throws IOException { - newLine(); - } - - /** - * Print a boolean value and then terminate the line. This method behaves - * as though it invokes {@link #print(boolean)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(boolean x) throws IOException { - print(x); - println(); - } - - /** - * Print a character and then terminate the line. This method behaves as - * though it invokes {@link #print(char)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(char x) throws IOException { - print(x); - println(); - } - - /** - * Print an integer and then terminate the line. This method behaves as - * though it invokes {@link #print(int)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(int x) throws IOException { - print(x); - println(); - } - - /** - * Print a long integer and then terminate the line. This method behaves - * as though it invokes {@link #print(long)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(long x) throws IOException { - print(x); - println(); - } - - /** - * Print a floating-point number and then terminate the line. This method - * behaves as though it invokes {@link #print(float)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(float x) throws IOException { - print(x); - println(); - } - - /** - * Print a double-precision floating-point number and then terminate the - * line. This method behaves as though it invokes {@link - * #print(double)} and then {@link #println()}. - * - * @throws IOException - */ - public void println(double x) throws IOException{ - print(x); - println(); - } - - /** - * Print an array of characters and then terminate the line. This method - * behaves as though it invokes {@link #print(char[])} and - * then {@link #println()}. - * - * @throws IOException - */ - public void println(char x[]) throws IOException { - print(x); - println(); - } - - /** - * Print a String and then terminate the line. This method behaves as - * though it invokes {@link #print(String)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(String x) throws IOException { - print(x); - println(); - } - - /** - * Print an Object and then terminate the line. This method behaves as - * though it invokes {@link #print(Object)} and then - * {@link #println()}. - * - * @throws IOException - */ - public void println(Object x) throws IOException { - print(x); - println(); - } - - /** - * Clear the contents of the buffer. If the buffer has been already - * been flushed then the clear operation shall throw an IOException - * to signal the fact that some data has already been irrevocably - * written to the client response stream. - * - * @throws IOException If an I/O error occurs - */ - public void clear() throws IOException { - if (writer != null) { - throw new IOException(); - } else { - nextChar = 0; - if (LIMIT_BUFFER && (cb.length > Constants.DEFAULT_TAG_BUFFER_SIZE)) { - bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; - cb = new char[bufferSize]; - } - } - } - - /** - * Clears the current contents of the buffer. Unlike clear(), this - * mehtod will not throw an IOException if the buffer has already been - * flushed. It merely clears the current content of the buffer and - * returns. - * - * @throws IOException If an I/O error occurs - */ - public void clearBuffer() throws IOException { - if (writer == null) { - this.clear(); - } - } - - /** - * Close the stream, flushing it first. Once a stream has been closed, - * further write() or flush() invocations will cause an IOException to be - * thrown. Closing a previously-closed stream, however, has no effect. - * - * @throws IOException If an I/O error occurs - */ - public void close() throws IOException { - if (writer != null) { - writer.close(); - } else { - closed = true; - } - } - - /** - * @return the number of bytes unused in the buffer - */ - public int getRemaining() { - return (writer == null) ? bufferSize-nextChar : 0; - } - - /** - * Return the value of this BodyJspWriter as a Reader. - * Note: this is after evaluation!! There are no scriptlets, - * etc in this stream. - * - * @return the value of this BodyJspWriter as a Reader - */ - public Reader getReader() { - return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null; - } - - /** - * Return the value of the BodyJspWriter as a String. - * Note: this is after evaluation!! There are no scriptlets, - * etc in this stream. - * - * @return the value of the BodyJspWriter as a String - */ - public String getString() { - return (writer == null) ? new String(cb, 0, nextChar) : null; - } - - /** - * Write the contents of this BodyJspWriter into a Writer. - * Subclasses are likely to do interesting things with the - * implementation so some things are extra efficient. - * - * @param out The writer into which to place the contents of this body - * evaluation - */ - public void writeOut(Writer out) throws IOException { - if (writer == null) { - out.write(cb, 0, nextChar); - // Flush not called as the writer passed could be a BodyContent and - // it doesn't allow to flush. - } - } - - /** - * Sets the writer to which all output is written. - */ - void setWriter(Writer writer) { - this.writer = writer; - closed = false; - if (writer != null) { - // According to the spec, the JspWriter returned by - // JspContext.pushBody(java.io.Writer writer) must behave as - // though it were unbuffered. This means that its getBufferSize() - // must always return 0. The implementation of - // JspWriter.getBufferSize() returns the value of JspWriter's - // 'bufferSize' field, which is inherited by this class. - // Therefore, we simply save the current 'bufferSize' (so we can - // later restore it should this BodyContentImpl ever be reused by - // a call to PageContext.pushBody()) before setting it to 0. - if (bufferSize != 0) { - bufferSizeSave = bufferSize; - bufferSize = 0; - } - } else { - bufferSize = bufferSizeSave; - clearBody(); - } - } - - private void ensureOpen() throws IOException { - if (closed) throw new IOException("Stream closed"); - } - - /** - * Reallocates buffer since the spec requires it to be unbounded. - */ - private void reAllocBuff(int len) { - - if (bufferSize + len <= cb.length) { - bufferSize = cb.length; - return; - } - - if (len < cb.length) { - len = cb.length; - } - - bufferSize = cb.length + len; - char[] tmp = new char[bufferSize]; - - System.arraycopy(cb, 0, tmp, 0, cb.length); - cb = tmp; - tmp = null; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.CharArrayReader; +import java.io.IOException; +import java.io.Reader; +import java.io.Writer; + +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.tagext.BodyContent; + +import org.apache.jasper.Constants; + +/** + * Write text to a character-output stream, buffering characters so as + * to provide for the efficient writing of single characters, arrays, + * and strings. + * + * Provide support for discarding for the output that has been buffered. + * + * @author Rajiv Mordani + * @author Jan Luehe + */ +public class BodyContentImpl extends BodyContent { + + private static final String LINE_SEPARATOR = + System.getProperty("line.separator"); + private static final boolean LIMIT_BUFFER = + Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.BodyContentImpl.LIMIT_BUFFER", "false")).booleanValue(); + + private char[] cb; + private int nextChar; + private boolean closed; + + // Enclosed writer to which any output is written + private Writer writer; + + // See comment in setWriter() + private int bufferSizeSave; + + /** + * Constructor. + */ + public BodyContentImpl(JspWriter enclosingWriter) { + super(enclosingWriter); + bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; + cb = new char[bufferSize]; + nextChar = 0; + closed = false; + } + + /** + * Write a single character. + */ + public void write(int c) throws IOException { + if (writer != null) { + writer.write(c); + } else { + ensureOpen(); + if (nextChar >= bufferSize) { + reAllocBuff (1); + } + cb[nextChar++] = (char) c; + } + } + + /** + * Write a portion of an array of characters. + * + *

        Ordinarily this method stores characters from the given array into + * this stream's buffer, flushing the buffer to the underlying stream as + * needed. If the requested length is at least as large as the buffer, + * however, then this method will flush the buffer and write the characters + * directly to the underlying stream. Thus redundant + * DiscardableBufferedWriters will not copy data + * unnecessarily. + * + * @param cbuf A character array + * @param off Offset from which to start reading characters + * @param len Number of characters to write + */ + public void write(char[] cbuf, int off, int len) throws IOException { + if (writer != null) { + writer.write(cbuf, off, len); + } else { + ensureOpen(); + + if ((off < 0) || (off > cbuf.length) || (len < 0) || + ((off + len) > cbuf.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + if (len >= bufferSize - nextChar) + reAllocBuff (len); + + System.arraycopy(cbuf, off, cb, nextChar, len); + nextChar+=len; + } + } + + /** + * Write an array of characters. This method cannot be inherited from the + * Writer class because it must suppress I/O exceptions. + */ + public void write(char[] buf) throws IOException { + if (writer != null) { + writer.write(buf); + } else { + write(buf, 0, buf.length); + } + } + + /** + * Write a portion of a String. + * + * @param s String to be written + * @param off Offset from which to start reading characters + * @param len Number of characters to be written + */ + public void write(String s, int off, int len) throws IOException { + if (writer != null) { + writer.write(s, off, len); + } else { + ensureOpen(); + if (len >= bufferSize - nextChar) + reAllocBuff(len); + + s.getChars(off, off + len, cb, nextChar); + nextChar += len; + } + } + + /** + * Write a string. This method cannot be inherited from the Writer class + * because it must suppress I/O exceptions. + */ + public void write(String s) throws IOException { + if (writer != null) { + writer.write(s); + } else { + write(s, 0, s.length()); + } + } + + /** + * Write a line separator. The line separator string is defined by the + * system property line.separator, and is not necessarily a single + * newline ('\n') character. + * + * @throws IOException If an I/O error occurs + */ + public void newLine() throws IOException { + if (writer != null) { + writer.write(LINE_SEPARATOR); + } else { + write(LINE_SEPARATOR); + } + } + + /** + * Print a boolean value. The string produced by {@link + * java.lang.String#valueOf(boolean)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param b The boolean to be printed + * @throws IOException + */ + public void print(boolean b) throws IOException { + if (writer != null) { + writer.write(b ? "true" : "false"); + } else { + write(b ? "true" : "false"); + } + } + + /** + * Print a character. The character is translated into one or more bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param c The char to be printed + * @throws IOException + */ + public void print(char c) throws IOException { + if (writer != null) { + writer.write(String.valueOf(c)); + } else { + write(String.valueOf(c)); + } + } + + /** + * Print an integer. The string produced by {@link + * java.lang.String#valueOf(int)} is translated into bytes according + * to the platform's default character encoding, and these bytes are + * written in exactly the manner of the {@link #write(int)} + * method. + * + * @param i The int to be printed + * @throws IOException + */ + public void print(int i) throws IOException { + if (writer != null) { + writer.write(String.valueOf(i)); + } else { + write(String.valueOf(i)); + } + } + + /** + * Print a long integer. The string produced by {@link + * java.lang.String#valueOf(long)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param l The long to be printed + * @throws IOException + */ + public void print(long l) throws IOException { + if (writer != null) { + writer.write(String.valueOf(l)); + } else { + write(String.valueOf(l)); + } + } + + /** + * Print a floating-point number. The string produced by {@link + * java.lang.String#valueOf(float)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param f The float to be printed + * @throws IOException + */ + public void print(float f) throws IOException { + if (writer != null) { + writer.write(String.valueOf(f)); + } else { + write(String.valueOf(f)); + } + } + + /** + * Print a double-precision floating-point number. The string produced by + * {@link java.lang.String#valueOf(double)} is translated into + * bytes according to the platform's default character encoding, and these + * bytes are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param d The double to be printed + * @throws IOException + */ + public void print(double d) throws IOException { + if (writer != null) { + writer.write(String.valueOf(d)); + } else { + write(String.valueOf(d)); + } + } + + /** + * Print an array of characters. The characters are converted into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param s The array of chars to be printed + * + * @throws NullPointerException If s is null + * @throws IOException + */ + public void print(char[] s) throws IOException { + if (writer != null) { + writer.write(s); + } else { + write(s); + } + } + + /** + * Print a string. If the argument is null then the string + * "null" is printed. Otherwise, the string's characters are + * converted into bytes according to the platform's default character + * encoding, and these bytes are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param s The String to be printed + * @throws IOException + */ + public void print(String s) throws IOException { + if (s == null) s = "null"; + if (writer != null) { + writer.write(s); + } else { + write(s); + } + } + + /** + * Print an object. The string produced by the {@link + * java.lang.String#valueOf(Object)} method is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param obj The Object to be printed + * @throws IOException + */ + public void print(Object obj) throws IOException { + if (writer != null) { + writer.write(String.valueOf(obj)); + } else { + write(String.valueOf(obj)); + } + } + + /** + * Terminate the current line by writing the line separator string. The + * line separator string is defined by the system property + * line.separator, and is not necessarily a single newline + * character ('\n'). + * + * @throws IOException + */ + public void println() throws IOException { + newLine(); + } + + /** + * Print a boolean value and then terminate the line. This method behaves + * as though it invokes {@link #print(boolean)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(boolean x) throws IOException { + print(x); + println(); + } + + /** + * Print a character and then terminate the line. This method behaves as + * though it invokes {@link #print(char)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(char x) throws IOException { + print(x); + println(); + } + + /** + * Print an integer and then terminate the line. This method behaves as + * though it invokes {@link #print(int)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(int x) throws IOException { + print(x); + println(); + } + + /** + * Print a long integer and then terminate the line. This method behaves + * as though it invokes {@link #print(long)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(long x) throws IOException { + print(x); + println(); + } + + /** + * Print a floating-point number and then terminate the line. This method + * behaves as though it invokes {@link #print(float)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(float x) throws IOException { + print(x); + println(); + } + + /** + * Print a double-precision floating-point number and then terminate the + * line. This method behaves as though it invokes {@link + * #print(double)} and then {@link #println()}. + * + * @throws IOException + */ + public void println(double x) throws IOException{ + print(x); + println(); + } + + /** + * Print an array of characters and then terminate the line. This method + * behaves as though it invokes {@link #print(char[])} and + * then {@link #println()}. + * + * @throws IOException + */ + public void println(char x[]) throws IOException { + print(x); + println(); + } + + /** + * Print a String and then terminate the line. This method behaves as + * though it invokes {@link #print(String)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(String x) throws IOException { + print(x); + println(); + } + + /** + * Print an Object and then terminate the line. This method behaves as + * though it invokes {@link #print(Object)} and then + * {@link #println()}. + * + * @throws IOException + */ + public void println(Object x) throws IOException { + print(x); + println(); + } + + /** + * Clear the contents of the buffer. If the buffer has been already + * been flushed then the clear operation shall throw an IOException + * to signal the fact that some data has already been irrevocably + * written to the client response stream. + * + * @throws IOException If an I/O error occurs + */ + public void clear() throws IOException { + if (writer != null) { + throw new IOException(); + } else { + nextChar = 0; + if (LIMIT_BUFFER && (cb.length > Constants.DEFAULT_TAG_BUFFER_SIZE)) { + bufferSize = Constants.DEFAULT_TAG_BUFFER_SIZE; + cb = new char[bufferSize]; + } + } + } + + /** + * Clears the current contents of the buffer. Unlike clear(), this + * mehtod will not throw an IOException if the buffer has already been + * flushed. It merely clears the current content of the buffer and + * returns. + * + * @throws IOException If an I/O error occurs + */ + public void clearBuffer() throws IOException { + if (writer == null) { + this.clear(); + } + } + + /** + * Close the stream, flushing it first. Once a stream has been closed, + * further write() or flush() invocations will cause an IOException to be + * thrown. Closing a previously-closed stream, however, has no effect. + * + * @throws IOException If an I/O error occurs + */ + public void close() throws IOException { + if (writer != null) { + writer.close(); + } else { + closed = true; + } + } + + /** + * @return the number of bytes unused in the buffer + */ + public int getRemaining() { + return (writer == null) ? bufferSize-nextChar : 0; + } + + /** + * Return the value of this BodyJspWriter as a Reader. + * Note: this is after evaluation!! There are no scriptlets, + * etc in this stream. + * + * @return the value of this BodyJspWriter as a Reader + */ + public Reader getReader() { + return (writer == null) ? new CharArrayReader (cb, 0, nextChar) : null; + } + + /** + * Return the value of the BodyJspWriter as a String. + * Note: this is after evaluation!! There are no scriptlets, + * etc in this stream. + * + * @return the value of the BodyJspWriter as a String + */ + public String getString() { + return (writer == null) ? new String(cb, 0, nextChar) : null; + } + + /** + * Write the contents of this BodyJspWriter into a Writer. + * Subclasses are likely to do interesting things with the + * implementation so some things are extra efficient. + * + * @param out The writer into which to place the contents of this body + * evaluation + */ + public void writeOut(Writer out) throws IOException { + if (writer == null) { + out.write(cb, 0, nextChar); + // Flush not called as the writer passed could be a BodyContent and + // it doesn't allow to flush. + } + } + + /** + * Sets the writer to which all output is written. + */ + void setWriter(Writer writer) { + this.writer = writer; + closed = false; + if (writer != null) { + // According to the spec, the JspWriter returned by + // JspContext.pushBody(java.io.Writer writer) must behave as + // though it were unbuffered. This means that its getBufferSize() + // must always return 0. The implementation of + // JspWriter.getBufferSize() returns the value of JspWriter's + // 'bufferSize' field, which is inherited by this class. + // Therefore, we simply save the current 'bufferSize' (so we can + // later restore it should this BodyContentImpl ever be reused by + // a call to PageContext.pushBody()) before setting it to 0. + if (bufferSize != 0) { + bufferSizeSave = bufferSize; + bufferSize = 0; + } + } else { + bufferSize = bufferSizeSave; + clearBody(); + } + } + + private void ensureOpen() throws IOException { + if (closed) throw new IOException("Stream closed"); + } + + /** + * Reallocates buffer since the spec requires it to be unbounded. + */ + private void reAllocBuff(int len) { + + if (bufferSize + len <= cb.length) { + bufferSize = cb.length; + return; + } + + if (len < cb.length) { + len = cb.length; + } + + bufferSize = cb.length + len; + char[] tmp = new char[bufferSize]; + + System.arraycopy(cb, 0, tmp, 0, cb.length); + cb = tmp; + tmp = null; + + } + + +} diff --git a/java/org/apache/jasper/runtime/HttpJspBase.java b/java/org/apache/jasper/runtime/HttpJspBase.java index 12936cc51..71efd1a55 100644 --- a/java/org/apache/jasper/runtime/HttpJspBase.java +++ b/java/org/apache/jasper/runtime/HttpJspBase.java @@ -1,115 +1,115 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.IOException; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.HttpJspPage; -import javax.servlet.jsp.JspFactory; - -import org.apache.jasper.compiler.Localizer; - -/** - * This is the super class of all JSP-generated servlets. - * - * @author Anil K. Vijendran - */ -public abstract class HttpJspBase - extends HttpServlet - implements HttpJspPage - - -{ - - static { - if( JspFactory.getDefaultFactory() == null ) { - JspFactoryImpl factory = new JspFactoryImpl(); - if( System.getSecurityManager() != null ) { - String basePackage = "org.apache.jasper."; - try { - factory.getClass().getClassLoader().loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedGetPageContext"); - factory.getClass().getClassLoader().loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); - factory.getClass().getClassLoader().loadClass( basePackage + - "runtime.JspRuntimeLibrary"); - factory.getClass().getClassLoader().loadClass( basePackage + - "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); - factory.getClass().getClassLoader().loadClass( basePackage + - "runtime.ServletResponseWrapperInclude"); - factory.getClass().getClassLoader().loadClass( basePackage + - "servlet.JspServletWrapper"); - } catch (ClassNotFoundException ex) { - org.apache.commons.logging.LogFactory.getLog( HttpJspBase.class ) - .error("Jasper JspRuntimeContext preload of class failed: " + - ex.getMessage(), ex); - } - } - JspFactory.setDefaultFactory(factory); - } - } - - protected HttpJspBase() { - } - - public final void init(ServletConfig config) - throws ServletException - { - super.init(config); - jspInit(); - _jspInit(); - } - - public String getServletInfo() { - return Localizer.getMessage("jsp.engine.info"); - } - - public final void destroy() { - jspDestroy(); - _jspDestroy(); - } - - /** - * Entry point into service. - */ - public final void service(HttpServletRequest request, HttpServletResponse response) - throws ServletException, IOException - { - _jspService(request, response); - } - - public void jspInit() { - } - - public void _jspInit() { - } - - public void jspDestroy() { - } - - protected void _jspDestroy() { - } - - public abstract void _jspService(HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException; -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.IOException; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.jsp.HttpJspPage; +import javax.servlet.jsp.JspFactory; + +import org.apache.jasper.compiler.Localizer; + +/** + * This is the super class of all JSP-generated servlets. + * + * @author Anil K. Vijendran + */ +public abstract class HttpJspBase + extends HttpServlet + implements HttpJspPage + + +{ + + static { + if( JspFactory.getDefaultFactory() == null ) { + JspFactoryImpl factory = new JspFactoryImpl(); + if( System.getSecurityManager() != null ) { + String basePackage = "org.apache.jasper."; + try { + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspFactoryImpl$PrivilegedGetPageContext"); + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspRuntimeLibrary"); + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); + factory.getClass().getClassLoader().loadClass( basePackage + + "servlet.JspServletWrapper"); + } catch (ClassNotFoundException ex) { + org.apache.commons.logging.LogFactory.getLog( HttpJspBase.class ) + .error("Jasper JspRuntimeContext preload of class failed: " + + ex.getMessage(), ex); + } + } + JspFactory.setDefaultFactory(factory); + } + } + + protected HttpJspBase() { + } + + public final void init(ServletConfig config) + throws ServletException + { + super.init(config); + jspInit(); + _jspInit(); + } + + public String getServletInfo() { + return Localizer.getMessage("jsp.engine.info"); + } + + public final void destroy() { + jspDestroy(); + _jspDestroy(); + } + + /** + * Entry point into service. + */ + public final void service(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException + { + _jspService(request, response); + } + + public void jspInit() { + } + + public void _jspInit() { + } + + public void jspDestroy() { + } + + protected void _jspDestroy() { + } + + public abstract void _jspService(HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException; +} diff --git a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java index db7eb819d..ec4e7e4df 100644 --- a/java/org/apache/jasper/runtime/JspApplicationContextImpl.java +++ b/java/org/apache/jasper/runtime/JspApplicationContextImpl.java @@ -1,137 +1,137 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.runtime; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import javax.el.ArrayELResolver; -import javax.el.BeanELResolver; -import javax.el.CompositeELResolver; -import javax.el.ELContextEvent; -import javax.el.ELContextListener; -import javax.el.ELResolver; -import javax.el.ExpressionFactory; -import javax.el.ListELResolver; -import javax.el.MapELResolver; -import javax.el.ResourceBundleELResolver; -import javax.servlet.ServletContext; -import javax.servlet.jsp.JspApplicationContext; -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.el.ImplicitObjectELResolver; -import javax.servlet.jsp.el.ScopedAttributeELResolver; - -import org.apache.el.ExpressionFactoryImpl; -import org.apache.jasper.el.ELContextImpl; - -/** - * Implementation of JspApplicationContext - * - * @author Jacob Hookom - */ -public class JspApplicationContextImpl implements JspApplicationContext { - - private final static String KEY = JspApplicationContext.class.getName(); - - private final static ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); - - private final List contextListeners = new ArrayList(); - - private final List resolvers = new ArrayList(); - - private boolean instantiated = false; - - private ELResolver resolver; - - public JspApplicationContextImpl() { - - } - - public void addELContextListener(ELContextListener listener) { - if (listener == null) { - throw new IllegalArgumentException("ELConextListener was null"); - } - this.contextListeners.add(listener); - } - - public static JspApplicationContextImpl getInstance(ServletContext context) { - if (context == null) { - throw new IllegalArgumentException("ServletContext was null"); - } - JspApplicationContextImpl impl = (JspApplicationContextImpl) context - .getAttribute(KEY); - if (impl == null) { - impl = new JspApplicationContextImpl(); - context.setAttribute(KEY, impl); - } - return impl; - } - - public ELContextImpl createELContext(JspContext context) { - if (context == null) { - throw new IllegalArgumentException("JspContext was null"); - } - - // create ELContext for JspContext - ELResolver r = this.createELResolver(); - ELContextImpl ctx = new ELContextImpl(r); - ctx.putContext(JspContext.class, context); - - // alert all ELContextListeners - ELContextEvent event = new ELContextEvent(ctx); - for (int i = 0; i < this.contextListeners.size(); i++) { - this.contextListeners.get(i).contextCreated(event); - } - - return ctx; - } - - private ELResolver createELResolver() { - this.instantiated = true; - if (this.resolver == null) { - CompositeELResolver r = new CompositeELResolver(); - r.add(new ImplicitObjectELResolver()); - for (Iterator itr = this.resolvers.iterator(); itr.hasNext();) { - r.add((ELResolver) itr.next()); - } - r.add(new MapELResolver()); - r.add(new ResourceBundleELResolver()); - r.add(new ListELResolver()); - r.add(new ArrayELResolver()); - r.add(new BeanELResolver()); - r.add(new ScopedAttributeELResolver()); - this.resolver = r; - } - return this.resolver; - } - - public void addELResolver(ELResolver resolver) throws IllegalStateException { - if (resolver == null) { - throw new IllegalArgumentException("ELResolver was null"); - } - if (this.instantiated) { - throw new IllegalStateException( - "cannot call addELResolver after the first request has been made"); - } - this.resolvers.add(resolver); - } - - public ExpressionFactory getExpressionFactory() { - return expressionFactory; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.runtime; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.el.ArrayELResolver; +import javax.el.BeanELResolver; +import javax.el.CompositeELResolver; +import javax.el.ELContextEvent; +import javax.el.ELContextListener; +import javax.el.ELResolver; +import javax.el.ExpressionFactory; +import javax.el.ListELResolver; +import javax.el.MapELResolver; +import javax.el.ResourceBundleELResolver; +import javax.servlet.ServletContext; +import javax.servlet.jsp.JspApplicationContext; +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.el.ImplicitObjectELResolver; +import javax.servlet.jsp.el.ScopedAttributeELResolver; + +import org.apache.el.ExpressionFactoryImpl; +import org.apache.jasper.el.ELContextImpl; + +/** + * Implementation of JspApplicationContext + * + * @author Jacob Hookom + */ +public class JspApplicationContextImpl implements JspApplicationContext { + + private final static String KEY = JspApplicationContext.class.getName(); + + private final static ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); + + private final List contextListeners = new ArrayList(); + + private final List resolvers = new ArrayList(); + + private boolean instantiated = false; + + private ELResolver resolver; + + public JspApplicationContextImpl() { + + } + + public void addELContextListener(ELContextListener listener) { + if (listener == null) { + throw new IllegalArgumentException("ELConextListener was null"); + } + this.contextListeners.add(listener); + } + + public static JspApplicationContextImpl getInstance(ServletContext context) { + if (context == null) { + throw new IllegalArgumentException("ServletContext was null"); + } + JspApplicationContextImpl impl = (JspApplicationContextImpl) context + .getAttribute(KEY); + if (impl == null) { + impl = new JspApplicationContextImpl(); + context.setAttribute(KEY, impl); + } + return impl; + } + + public ELContextImpl createELContext(JspContext context) { + if (context == null) { + throw new IllegalArgumentException("JspContext was null"); + } + + // create ELContext for JspContext + ELResolver r = this.createELResolver(); + ELContextImpl ctx = new ELContextImpl(r); + ctx.putContext(JspContext.class, context); + + // alert all ELContextListeners + ELContextEvent event = new ELContextEvent(ctx); + for (int i = 0; i < this.contextListeners.size(); i++) { + this.contextListeners.get(i).contextCreated(event); + } + + return ctx; + } + + private ELResolver createELResolver() { + this.instantiated = true; + if (this.resolver == null) { + CompositeELResolver r = new CompositeELResolver(); + r.add(new ImplicitObjectELResolver()); + for (Iterator itr = this.resolvers.iterator(); itr.hasNext();) { + r.add((ELResolver) itr.next()); + } + r.add(new MapELResolver()); + r.add(new ResourceBundleELResolver()); + r.add(new ListELResolver()); + r.add(new ArrayELResolver()); + r.add(new BeanELResolver()); + r.add(new ScopedAttributeELResolver()); + this.resolver = r; + } + return this.resolver; + } + + public void addELResolver(ELResolver resolver) throws IllegalStateException { + if (resolver == null) { + throw new IllegalArgumentException("ELResolver was null"); + } + if (this.instantiated) { + throw new IllegalStateException( + "cannot call addELResolver after the first request has been made"); + } + this.resolvers.add(resolver); + } + + public ExpressionFactory getExpressionFactory() { + return expressionFactory; + } + +} diff --git a/java/org/apache/jasper/runtime/JspContextWrapper.java b/java/org/apache/jasper/runtime/JspContextWrapper.java index caa97d037..ca0a4b918 100644 --- a/java/org/apache/jasper/runtime/JspContextWrapper.java +++ b/java/org/apache/jasper/runtime/JspContextWrapper.java @@ -1,462 +1,462 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.Map; - -import javax.el.ELContext; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.JspFactory; -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.ExpressionEvaluator; -import javax.servlet.jsp.el.VariableResolver; -import javax.servlet.jsp.tagext.BodyContent; -import javax.servlet.jsp.tagext.VariableInfo; - -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.el.ELContextImpl; - -/** - * Implementation of a JSP Context Wrapper. - * - * The JSP Context Wrapper is a JspContext created and maintained by a tag - * handler implementation. It wraps the Invoking JSP Context, that is, the - * JspContext instance passed to the tag handler by the invoking page via - * setJspContext(). - * - * @author Kin-man Chung - * @author Jan Luehe - * @author Jacob Hookom - */ -public class JspContextWrapper extends PageContext implements VariableResolver { - - // Invoking JSP context - private PageContext invokingJspCtxt; - - private transient Hashtable pageAttributes; - - // ArrayList of NESTED scripting variables - private ArrayList nestedVars; - - // ArrayList of AT_BEGIN scripting variables - private ArrayList atBeginVars; - - // ArrayList of AT_END scripting variables - private ArrayList atEndVars; - - private Map aliases; - - private Hashtable originalNestedVars; - - public JspContextWrapper(JspContext jspContext, ArrayList nestedVars, - ArrayList atBeginVars, ArrayList atEndVars, Map aliases) { - this.invokingJspCtxt = (PageContext) jspContext; - this.nestedVars = nestedVars; - this.atBeginVars = atBeginVars; - this.atEndVars = atEndVars; - this.pageAttributes = new Hashtable(16); - this.aliases = aliases; - - if (nestedVars != null) { - this.originalNestedVars = new Hashtable(nestedVars.size()); - } - syncBeginTagFile(); - } - - public void initialize(Servlet servlet, ServletRequest request, - ServletResponse response, String errorPageURL, - boolean needsSession, int bufferSize, boolean autoFlush) - throws IOException, IllegalStateException, IllegalArgumentException { - } - - public Object getAttribute(String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - return pageAttributes.get(name); - } - - public Object getAttribute(String name, int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (scope == PAGE_SCOPE) { - return pageAttributes.get(name); - } - - return invokingJspCtxt.getAttribute(name, scope); - } - - public void setAttribute(String name, Object value) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (value != null) { - pageAttributes.put(name, value); - } else { - removeAttribute(name, PAGE_SCOPE); - } - } - - public void setAttribute(String name, Object value, int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (scope == PAGE_SCOPE) { - if (value != null) { - pageAttributes.put(name, value); - } else { - removeAttribute(name, PAGE_SCOPE); - } - } else { - invokingJspCtxt.setAttribute(name, value, scope); - } - } - - public Object findAttribute(String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - Object o = pageAttributes.get(name); - if (o == null) { - o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE); - if (o == null) { - if (getSession() != null) { - o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE); - } - if (o == null) { - o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE); - } - } - } - - return o; - } - - public void removeAttribute(String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - pageAttributes.remove(name); - invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE); - if (getSession() != null) { - invokingJspCtxt.removeAttribute(name, SESSION_SCOPE); - } - invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE); - } - - public void removeAttribute(String name, int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (scope == PAGE_SCOPE) { - pageAttributes.remove(name); - } else { - invokingJspCtxt.removeAttribute(name, scope); - } - } - - public int getAttributesScope(String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (pageAttributes.get(name) != null) { - return PAGE_SCOPE; - } else { - return invokingJspCtxt.getAttributesScope(name); - } - } - - public Enumeration getAttributeNamesInScope(int scope) { - if (scope == PAGE_SCOPE) { - return pageAttributes.keys(); - } - - return invokingJspCtxt.getAttributeNamesInScope(scope); - } - - public void release() { - invokingJspCtxt.release(); - } - - public JspWriter getOut() { - return invokingJspCtxt.getOut(); - } - - public HttpSession getSession() { - return invokingJspCtxt.getSession(); - } - - public Object getPage() { - return invokingJspCtxt.getPage(); - } - - public ServletRequest getRequest() { - return invokingJspCtxt.getRequest(); - } - - public ServletResponse getResponse() { - return invokingJspCtxt.getResponse(); - } - - public Exception getException() { - return invokingJspCtxt.getException(); - } - - public ServletConfig getServletConfig() { - return invokingJspCtxt.getServletConfig(); - } - - public ServletContext getServletContext() { - return invokingJspCtxt.getServletContext(); - } - - public void forward(String relativeUrlPath) throws ServletException, - IOException { - invokingJspCtxt.forward(relativeUrlPath); - } - - public void include(String relativeUrlPath) throws ServletException, - IOException { - invokingJspCtxt.include(relativeUrlPath); - } - - public void include(String relativeUrlPath, boolean flush) - throws ServletException, IOException { - include(relativeUrlPath, false); // XXX - } - - public VariableResolver getVariableResolver() { - return this; - } - - public BodyContent pushBody() { - return invokingJspCtxt.pushBody(); - } - - public JspWriter pushBody(Writer writer) { - return invokingJspCtxt.pushBody(writer); - } - - public JspWriter popBody() { - return invokingJspCtxt.popBody(); - } - - public ExpressionEvaluator getExpressionEvaluator() { - return invokingJspCtxt.getExpressionEvaluator(); - } - - public void handlePageException(Exception ex) throws IOException, - ServletException { - // Should never be called since handleException() called with a - // Throwable in the generated servlet. - handlePageException((Throwable) ex); - } - - public void handlePageException(Throwable t) throws IOException, - ServletException { - invokingJspCtxt.handlePageException(t); - } - - /** - * VariableResolver interface - */ - public Object resolveVariable(String pName) throws ELException { - ELContext ctx = this.getELContext(); - return ctx.getELResolver().getValue(ctx, null, pName); - } - - /** - * Synchronize variables at begin of tag file - */ - public void syncBeginTagFile() { - saveNestedVariables(); - } - - /** - * Synchronize variables before fragment invokation - */ - public void syncBeforeInvoke() { - copyTagToPageScope(VariableInfo.NESTED); - copyTagToPageScope(VariableInfo.AT_BEGIN); - } - - /** - * Synchronize variables at end of tag file - */ - public void syncEndTagFile() { - copyTagToPageScope(VariableInfo.AT_BEGIN); - copyTagToPageScope(VariableInfo.AT_END); - restoreNestedVariables(); - } - - /** - * Copies the variables of the given scope from the virtual page scope of - * this JSP context wrapper to the page scope of the invoking JSP context. - * - * @param scope - * variable scope (one of NESTED, AT_BEGIN, or AT_END) - */ - private void copyTagToPageScope(int scope) { - Iterator iter = null; - - switch (scope) { - case VariableInfo.NESTED: - if (nestedVars != null) { - iter = nestedVars.iterator(); - } - break; - case VariableInfo.AT_BEGIN: - if (atBeginVars != null) { - iter = atBeginVars.iterator(); - } - break; - case VariableInfo.AT_END: - if (atEndVars != null) { - iter = atEndVars.iterator(); - } - break; - } - - while ((iter != null) && iter.hasNext()) { - String varName = (String) iter.next(); - Object obj = getAttribute(varName); - varName = findAlias(varName); - if (obj != null) { - invokingJspCtxt.setAttribute(varName, obj); - } else { - invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE); - } - } - } - - /** - * Saves the values of any NESTED variables that are present in the invoking - * JSP context, so they can later be restored. - */ - private void saveNestedVariables() { - if (nestedVars != null) { - Iterator iter = nestedVars.iterator(); - while (iter.hasNext()) { - String varName = (String) iter.next(); - varName = findAlias(varName); - Object obj = invokingJspCtxt.getAttribute(varName); - if (obj != null) { - originalNestedVars.put(varName, obj); - } - } - } - } - - /** - * Restores the values of any NESTED variables in the invoking JSP context. - */ - private void restoreNestedVariables() { - if (nestedVars != null) { - Iterator iter = nestedVars.iterator(); - while (iter.hasNext()) { - String varName = (String) iter.next(); - varName = findAlias(varName); - Object obj = originalNestedVars.get(varName); - if (obj != null) { - invokingJspCtxt.setAttribute(varName, obj); - } else { - invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE); - } - } - } - } - - /** - * Checks to see if the given variable name is used as an alias, and if so, - * returns the variable name for which it is used as an alias. - * - * @param varName - * The variable name to check - * @return The variable name for which varName is used as an alias, or - * varName if it is not being used as an alias - */ - private String findAlias(String varName) { - - if (aliases == null) - return varName; - - String alias = (String) aliases.get(varName); - if (alias == null) { - return varName; - } - return alias; - } - - //private ELContextImpl elContext; - - public ELContext getELContext() { - // instead decorate!!! - - return this.invokingJspCtxt.getELContext(); - - /* - if (this.elContext != null) { - JspFactory jspFact = JspFactory.getDefaultFactory(); - ServletContext servletContext = this.getServletContext(); - JspApplicationContextImpl jspCtx = (JspApplicationContextImpl) jspFact - .getJspApplicationContext(servletContext); - this.elContext = jspCtx.createELContext(this); - } - return this.elContext; - */ - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; + +import javax.el.ELContext; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.JspFactory; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.VariableResolver; +import javax.servlet.jsp.tagext.BodyContent; +import javax.servlet.jsp.tagext.VariableInfo; + +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.el.ELContextImpl; + +/** + * Implementation of a JSP Context Wrapper. + * + * The JSP Context Wrapper is a JspContext created and maintained by a tag + * handler implementation. It wraps the Invoking JSP Context, that is, the + * JspContext instance passed to the tag handler by the invoking page via + * setJspContext(). + * + * @author Kin-man Chung + * @author Jan Luehe + * @author Jacob Hookom + */ +public class JspContextWrapper extends PageContext implements VariableResolver { + + // Invoking JSP context + private PageContext invokingJspCtxt; + + private transient Hashtable pageAttributes; + + // ArrayList of NESTED scripting variables + private ArrayList nestedVars; + + // ArrayList of AT_BEGIN scripting variables + private ArrayList atBeginVars; + + // ArrayList of AT_END scripting variables + private ArrayList atEndVars; + + private Map aliases; + + private Hashtable originalNestedVars; + + public JspContextWrapper(JspContext jspContext, ArrayList nestedVars, + ArrayList atBeginVars, ArrayList atEndVars, Map aliases) { + this.invokingJspCtxt = (PageContext) jspContext; + this.nestedVars = nestedVars; + this.atBeginVars = atBeginVars; + this.atEndVars = atEndVars; + this.pageAttributes = new Hashtable(16); + this.aliases = aliases; + + if (nestedVars != null) { + this.originalNestedVars = new Hashtable(nestedVars.size()); + } + syncBeginTagFile(); + } + + public void initialize(Servlet servlet, ServletRequest request, + ServletResponse response, String errorPageURL, + boolean needsSession, int bufferSize, boolean autoFlush) + throws IOException, IllegalStateException, IllegalArgumentException { + } + + public Object getAttribute(String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + return pageAttributes.get(name); + } + + public Object getAttribute(String name, int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (scope == PAGE_SCOPE) { + return pageAttributes.get(name); + } + + return invokingJspCtxt.getAttribute(name, scope); + } + + public void setAttribute(String name, Object value) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (value != null) { + pageAttributes.put(name, value); + } else { + removeAttribute(name, PAGE_SCOPE); + } + } + + public void setAttribute(String name, Object value, int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (scope == PAGE_SCOPE) { + if (value != null) { + pageAttributes.put(name, value); + } else { + removeAttribute(name, PAGE_SCOPE); + } + } else { + invokingJspCtxt.setAttribute(name, value, scope); + } + } + + public Object findAttribute(String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + Object o = pageAttributes.get(name); + if (o == null) { + o = invokingJspCtxt.getAttribute(name, REQUEST_SCOPE); + if (o == null) { + if (getSession() != null) { + o = invokingJspCtxt.getAttribute(name, SESSION_SCOPE); + } + if (o == null) { + o = invokingJspCtxt.getAttribute(name, APPLICATION_SCOPE); + } + } + } + + return o; + } + + public void removeAttribute(String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + pageAttributes.remove(name); + invokingJspCtxt.removeAttribute(name, REQUEST_SCOPE); + if (getSession() != null) { + invokingJspCtxt.removeAttribute(name, SESSION_SCOPE); + } + invokingJspCtxt.removeAttribute(name, APPLICATION_SCOPE); + } + + public void removeAttribute(String name, int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (scope == PAGE_SCOPE) { + pageAttributes.remove(name); + } else { + invokingJspCtxt.removeAttribute(name, scope); + } + } + + public int getAttributesScope(String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (pageAttributes.get(name) != null) { + return PAGE_SCOPE; + } else { + return invokingJspCtxt.getAttributesScope(name); + } + } + + public Enumeration getAttributeNamesInScope(int scope) { + if (scope == PAGE_SCOPE) { + return pageAttributes.keys(); + } + + return invokingJspCtxt.getAttributeNamesInScope(scope); + } + + public void release() { + invokingJspCtxt.release(); + } + + public JspWriter getOut() { + return invokingJspCtxt.getOut(); + } + + public HttpSession getSession() { + return invokingJspCtxt.getSession(); + } + + public Object getPage() { + return invokingJspCtxt.getPage(); + } + + public ServletRequest getRequest() { + return invokingJspCtxt.getRequest(); + } + + public ServletResponse getResponse() { + return invokingJspCtxt.getResponse(); + } + + public Exception getException() { + return invokingJspCtxt.getException(); + } + + public ServletConfig getServletConfig() { + return invokingJspCtxt.getServletConfig(); + } + + public ServletContext getServletContext() { + return invokingJspCtxt.getServletContext(); + } + + public void forward(String relativeUrlPath) throws ServletException, + IOException { + invokingJspCtxt.forward(relativeUrlPath); + } + + public void include(String relativeUrlPath) throws ServletException, + IOException { + invokingJspCtxt.include(relativeUrlPath); + } + + public void include(String relativeUrlPath, boolean flush) + throws ServletException, IOException { + include(relativeUrlPath, false); // XXX + } + + public VariableResolver getVariableResolver() { + return this; + } + + public BodyContent pushBody() { + return invokingJspCtxt.pushBody(); + } + + public JspWriter pushBody(Writer writer) { + return invokingJspCtxt.pushBody(writer); + } + + public JspWriter popBody() { + return invokingJspCtxt.popBody(); + } + + public ExpressionEvaluator getExpressionEvaluator() { + return invokingJspCtxt.getExpressionEvaluator(); + } + + public void handlePageException(Exception ex) throws IOException, + ServletException { + // Should never be called since handleException() called with a + // Throwable in the generated servlet. + handlePageException((Throwable) ex); + } + + public void handlePageException(Throwable t) throws IOException, + ServletException { + invokingJspCtxt.handlePageException(t); + } + + /** + * VariableResolver interface + */ + public Object resolveVariable(String pName) throws ELException { + ELContext ctx = this.getELContext(); + return ctx.getELResolver().getValue(ctx, null, pName); + } + + /** + * Synchronize variables at begin of tag file + */ + public void syncBeginTagFile() { + saveNestedVariables(); + } + + /** + * Synchronize variables before fragment invokation + */ + public void syncBeforeInvoke() { + copyTagToPageScope(VariableInfo.NESTED); + copyTagToPageScope(VariableInfo.AT_BEGIN); + } + + /** + * Synchronize variables at end of tag file + */ + public void syncEndTagFile() { + copyTagToPageScope(VariableInfo.AT_BEGIN); + copyTagToPageScope(VariableInfo.AT_END); + restoreNestedVariables(); + } + + /** + * Copies the variables of the given scope from the virtual page scope of + * this JSP context wrapper to the page scope of the invoking JSP context. + * + * @param scope + * variable scope (one of NESTED, AT_BEGIN, or AT_END) + */ + private void copyTagToPageScope(int scope) { + Iterator iter = null; + + switch (scope) { + case VariableInfo.NESTED: + if (nestedVars != null) { + iter = nestedVars.iterator(); + } + break; + case VariableInfo.AT_BEGIN: + if (atBeginVars != null) { + iter = atBeginVars.iterator(); + } + break; + case VariableInfo.AT_END: + if (atEndVars != null) { + iter = atEndVars.iterator(); + } + break; + } + + while ((iter != null) && iter.hasNext()) { + String varName = (String) iter.next(); + Object obj = getAttribute(varName); + varName = findAlias(varName); + if (obj != null) { + invokingJspCtxt.setAttribute(varName, obj); + } else { + invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE); + } + } + } + + /** + * Saves the values of any NESTED variables that are present in the invoking + * JSP context, so they can later be restored. + */ + private void saveNestedVariables() { + if (nestedVars != null) { + Iterator iter = nestedVars.iterator(); + while (iter.hasNext()) { + String varName = (String) iter.next(); + varName = findAlias(varName); + Object obj = invokingJspCtxt.getAttribute(varName); + if (obj != null) { + originalNestedVars.put(varName, obj); + } + } + } + } + + /** + * Restores the values of any NESTED variables in the invoking JSP context. + */ + private void restoreNestedVariables() { + if (nestedVars != null) { + Iterator iter = nestedVars.iterator(); + while (iter.hasNext()) { + String varName = (String) iter.next(); + varName = findAlias(varName); + Object obj = originalNestedVars.get(varName); + if (obj != null) { + invokingJspCtxt.setAttribute(varName, obj); + } else { + invokingJspCtxt.removeAttribute(varName, PAGE_SCOPE); + } + } + } + } + + /** + * Checks to see if the given variable name is used as an alias, and if so, + * returns the variable name for which it is used as an alias. + * + * @param varName + * The variable name to check + * @return The variable name for which varName is used as an alias, or + * varName if it is not being used as an alias + */ + private String findAlias(String varName) { + + if (aliases == null) + return varName; + + String alias = (String) aliases.get(varName); + if (alias == null) { + return varName; + } + return alias; + } + + //private ELContextImpl elContext; + + public ELContext getELContext() { + // instead decorate!!! + + return this.invokingJspCtxt.getELContext(); + + /* + if (this.elContext != null) { + JspFactory jspFact = JspFactory.getDefaultFactory(); + ServletContext servletContext = this.getServletContext(); + JspApplicationContextImpl jspCtx = (JspApplicationContextImpl) jspFact + .getJspApplicationContext(servletContext); + this.elContext = jspCtx.createELContext(this); + } + return this.elContext; + */ + } +} diff --git a/java/org/apache/jasper/runtime/JspFactoryImpl.java b/java/org/apache/jasper/runtime/JspFactoryImpl.java index 0d6cc6881..9005f0d47 100644 --- a/java/org/apache/jasper/runtime/JspFactoryImpl.java +++ b/java/org/apache/jasper/runtime/JspFactoryImpl.java @@ -1,191 +1,191 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.runtime; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.jsp.JspApplicationContext; -import javax.servlet.jsp.JspFactory; -import javax.servlet.jsp.JspEngineInfo; -import javax.servlet.jsp.PageContext; - -import org.apache.jasper.util.SimplePool; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Implementation of JspFactory. - * - * @author Anil K. Vijendran - */ -public class JspFactoryImpl extends JspFactory { - - // Logger - private Log log = LogFactory.getLog(JspFactoryImpl.class); - - private static final String SPEC_VERSION = "2.0"; - private static final boolean USE_POOL = - Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.USE_POOL", "true")).booleanValue(); - - private SimplePool pool = new SimplePool( 100 ); - - public PageContext getPageContext(Servlet servlet, - ServletRequest request, - ServletResponse response, - String errorPageURL, - boolean needsSession, - int bufferSize, - boolean autoflush) { - - if( System.getSecurityManager() != null ) { - PrivilegedGetPageContext dp = new PrivilegedGetPageContext( - (JspFactoryImpl)this, servlet, request, response, errorPageURL, - needsSession, bufferSize, autoflush); - return (PageContext)AccessController.doPrivileged(dp); - } else { - return internalGetPageContext(servlet, request, response, - errorPageURL, needsSession, - bufferSize, autoflush); - } - } - - public void releasePageContext(PageContext pc) { - if( pc == null ) - return; - if( System.getSecurityManager() != null ) { - PrivilegedReleasePageContext dp = new PrivilegedReleasePageContext( - (JspFactoryImpl)this,pc); - AccessController.doPrivileged(dp); - } else { - internalReleasePageContext(pc); - } - } - - public JspEngineInfo getEngineInfo() { - return new JspEngineInfo() { - public String getSpecificationVersion() { - return SPEC_VERSION; - } - }; - } - - private PageContext internalGetPageContext(Servlet servlet, - ServletRequest request, - ServletResponse response, - String errorPageURL, - boolean needsSession, - int bufferSize, - boolean autoflush) { - try { - PageContext pc; - if( USE_POOL ) { - pc = (PageContext) pool.get(); - if( pc == null ) { - pc= new PageContextImpl(this); - } - } else { - pc = new PageContextImpl(this); - } - pc.initialize(servlet, request, response, errorPageURL, - needsSession, bufferSize, autoflush); - return pc; - } catch (Throwable ex) { - /* FIXME: need to do something reasonable here!! */ - log.fatal("Exception initializing page context", ex); - return null; - } - } - - private void internalReleasePageContext(PageContext pc) { - pc.release(); - if (USE_POOL && (pc instanceof PageContextImpl)) { - pool.put( pc ); - } - } - - private class PrivilegedGetPageContext implements PrivilegedAction { - - private JspFactoryImpl factory; - private Servlet servlet; - private ServletRequest request; - private ServletResponse response; - private String errorPageURL; - private boolean needsSession; - private int bufferSize; - private boolean autoflush; - - PrivilegedGetPageContext(JspFactoryImpl factory, - Servlet servlet, - ServletRequest request, - ServletResponse response, - String errorPageURL, - boolean needsSession, - int bufferSize, - boolean autoflush) { - this.factory = factory; - this.servlet = servlet; - this.request = request; - this.response = response; - this.errorPageURL = errorPageURL; - this.needsSession = needsSession; - this.bufferSize = bufferSize; - this.autoflush = autoflush; - } - - public Object run() { - return factory.internalGetPageContext(servlet, - request, - response, - errorPageURL, - needsSession, - bufferSize, - autoflush); - } - } - - private class PrivilegedReleasePageContext implements PrivilegedAction { - - private JspFactoryImpl factory; - private PageContext pageContext; - - PrivilegedReleasePageContext(JspFactoryImpl factory, - PageContext pageContext) { - this.factory = factory; - this.pageContext = pageContext; - } - - public Object run() { - factory.internalReleasePageContext(pageContext); - return null; - } - } - - private final static String APP_CONTEXT_VARIABLE = JspApplicationContextImpl.class.getName(); - - public JspApplicationContext getJspApplicationContext(ServletContext context) { - JspApplicationContext appContext = (JspApplicationContext) context.getAttribute(APP_CONTEXT_VARIABLE); - if (appContext == null) { - appContext = new JspApplicationContextImpl(); - context.setAttribute(APP_CONTEXT_VARIABLE, appContext); - } - return appContext; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.runtime; + +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.jsp.JspApplicationContext; +import javax.servlet.jsp.JspFactory; +import javax.servlet.jsp.JspEngineInfo; +import javax.servlet.jsp.PageContext; + +import org.apache.jasper.util.SimplePool; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Implementation of JspFactory. + * + * @author Anil K. Vijendran + */ +public class JspFactoryImpl extends JspFactory { + + // Logger + private Log log = LogFactory.getLog(JspFactoryImpl.class); + + private static final String SPEC_VERSION = "2.0"; + private static final boolean USE_POOL = + Boolean.valueOf(System.getProperty("org.apache.jasper.runtime.JspFactoryImpl.USE_POOL", "true")).booleanValue(); + + private SimplePool pool = new SimplePool( 100 ); + + public PageContext getPageContext(Servlet servlet, + ServletRequest request, + ServletResponse response, + String errorPageURL, + boolean needsSession, + int bufferSize, + boolean autoflush) { + + if( System.getSecurityManager() != null ) { + PrivilegedGetPageContext dp = new PrivilegedGetPageContext( + (JspFactoryImpl)this, servlet, request, response, errorPageURL, + needsSession, bufferSize, autoflush); + return (PageContext)AccessController.doPrivileged(dp); + } else { + return internalGetPageContext(servlet, request, response, + errorPageURL, needsSession, + bufferSize, autoflush); + } + } + + public void releasePageContext(PageContext pc) { + if( pc == null ) + return; + if( System.getSecurityManager() != null ) { + PrivilegedReleasePageContext dp = new PrivilegedReleasePageContext( + (JspFactoryImpl)this,pc); + AccessController.doPrivileged(dp); + } else { + internalReleasePageContext(pc); + } + } + + public JspEngineInfo getEngineInfo() { + return new JspEngineInfo() { + public String getSpecificationVersion() { + return SPEC_VERSION; + } + }; + } + + private PageContext internalGetPageContext(Servlet servlet, + ServletRequest request, + ServletResponse response, + String errorPageURL, + boolean needsSession, + int bufferSize, + boolean autoflush) { + try { + PageContext pc; + if( USE_POOL ) { + pc = (PageContext) pool.get(); + if( pc == null ) { + pc= new PageContextImpl(this); + } + } else { + pc = new PageContextImpl(this); + } + pc.initialize(servlet, request, response, errorPageURL, + needsSession, bufferSize, autoflush); + return pc; + } catch (Throwable ex) { + /* FIXME: need to do something reasonable here!! */ + log.fatal("Exception initializing page context", ex); + return null; + } + } + + private void internalReleasePageContext(PageContext pc) { + pc.release(); + if (USE_POOL && (pc instanceof PageContextImpl)) { + pool.put( pc ); + } + } + + private class PrivilegedGetPageContext implements PrivilegedAction { + + private JspFactoryImpl factory; + private Servlet servlet; + private ServletRequest request; + private ServletResponse response; + private String errorPageURL; + private boolean needsSession; + private int bufferSize; + private boolean autoflush; + + PrivilegedGetPageContext(JspFactoryImpl factory, + Servlet servlet, + ServletRequest request, + ServletResponse response, + String errorPageURL, + boolean needsSession, + int bufferSize, + boolean autoflush) { + this.factory = factory; + this.servlet = servlet; + this.request = request; + this.response = response; + this.errorPageURL = errorPageURL; + this.needsSession = needsSession; + this.bufferSize = bufferSize; + this.autoflush = autoflush; + } + + public Object run() { + return factory.internalGetPageContext(servlet, + request, + response, + errorPageURL, + needsSession, + bufferSize, + autoflush); + } + } + + private class PrivilegedReleasePageContext implements PrivilegedAction { + + private JspFactoryImpl factory; + private PageContext pageContext; + + PrivilegedReleasePageContext(JspFactoryImpl factory, + PageContext pageContext) { + this.factory = factory; + this.pageContext = pageContext; + } + + public Object run() { + factory.internalReleasePageContext(pageContext); + return null; + } + } + + private final static String APP_CONTEXT_VARIABLE = JspApplicationContextImpl.class.getName(); + + public JspApplicationContext getJspApplicationContext(ServletContext context) { + JspApplicationContext appContext = (JspApplicationContext) context.getAttribute(APP_CONTEXT_VARIABLE); + if (appContext == null) { + appContext = new JspApplicationContextImpl(); + context.setAttribute(APP_CONTEXT_VARIABLE, appContext); + } + return appContext; + } +} diff --git a/java/org/apache/jasper/runtime/JspFragmentHelper.java b/java/org/apache/jasper/runtime/JspFragmentHelper.java index bfef53f80..3e73f52c8 100644 --- a/java/org/apache/jasper/runtime/JspFragmentHelper.java +++ b/java/org/apache/jasper/runtime/JspFragmentHelper.java @@ -1,64 +1,64 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import javax.servlet.jsp.JspContext; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.tagext.JspFragment; -import javax.servlet.jsp.tagext.JspTag; - -/** - * Helper class from which all Jsp Fragment helper classes extend. - * This class allows for the emulation of numerous fragments within - * a single class, which in turn reduces the load on the class loader - * since there are potentially many JspFragments in a single page. - *

        - * The class also provides various utility methods for JspFragment - * implementations. - * - * @author Mark Roth - */ -public abstract class JspFragmentHelper - extends JspFragment -{ - - protected int discriminator; - protected JspContext jspContext; - protected PageContext _jspx_page_context; - protected JspTag parentTag; - - public JspFragmentHelper( int discriminator, JspContext jspContext, - JspTag parentTag ) - { - this.discriminator = discriminator; - this.jspContext = jspContext; - this._jspx_page_context = null; - if( jspContext instanceof PageContext ) { - _jspx_page_context = (PageContext)jspContext; - } - this.parentTag = parentTag; - } - - public JspContext getJspContext() { - return this.jspContext; - } - - public JspTag getParentTag() { - return this.parentTag; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import javax.servlet.jsp.JspContext; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.JspFragment; +import javax.servlet.jsp.tagext.JspTag; + +/** + * Helper class from which all Jsp Fragment helper classes extend. + * This class allows for the emulation of numerous fragments within + * a single class, which in turn reduces the load on the class loader + * since there are potentially many JspFragments in a single page. + *

        + * The class also provides various utility methods for JspFragment + * implementations. + * + * @author Mark Roth + */ +public abstract class JspFragmentHelper + extends JspFragment +{ + + protected int discriminator; + protected JspContext jspContext; + protected PageContext _jspx_page_context; + protected JspTag parentTag; + + public JspFragmentHelper( int discriminator, JspContext jspContext, + JspTag parentTag ) + { + this.discriminator = discriminator; + this.jspContext = jspContext; + this._jspx_page_context = null; + if( jspContext instanceof PageContext ) { + _jspx_page_context = (PageContext)jspContext; + } + this.parentTag = parentTag; + } + + public JspContext getJspContext() { + return this.jspContext; + } + + public JspTag getParentTag() { + return this.parentTag; + } + +} diff --git a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java index beccb15b2..9392204b4 100644 --- a/java/org/apache/jasper/runtime/JspRuntimeLibrary.java +++ b/java/org/apache/jasper/runtime/JspRuntimeLibrary.java @@ -1,1045 +1,1045 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.beans.PropertyEditor; -import java.beans.PropertyEditorManager; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.lang.reflect.Method; -import java.security.AccessController; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Enumeration; - -import javax.servlet.RequestDispatcher; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.tagext.BodyContent; - -import org.apache.jasper.JasperException; -import org.apache.jasper.compiler.Localizer; - -/** - * Bunch of util methods that are used by code generated for useBean, - * getProperty and setProperty. - * - * The __begin, __end stuff is there so that the JSP engine can - * actually parse this file and inline them if people don't want - * runtime dependencies on this class. However, I'm not sure if that - * works so well right now. It got forgotten at some point. -akv - * - * @author Mandar Raje - * @author Shawn Bayern - */ -public class JspRuntimeLibrary { - - private static final String SERVLET_EXCEPTION - = "javax.servlet.error.exception"; - private static final String JSP_EXCEPTION - = "javax.servlet.jsp.jspException"; - - protected static class PrivilegedIntrospectHelper - implements PrivilegedExceptionAction { - - private Object bean; - private String prop; - private String value; - private ServletRequest request; - private String param; - private boolean ignoreMethodNF; - - PrivilegedIntrospectHelper(Object bean, String prop, - String value, ServletRequest request, - String param, boolean ignoreMethodNF) - { - this.bean = bean; - this.prop = prop; - this.value = value; - this.request = request; - this.param = param; - this.ignoreMethodNF = ignoreMethodNF; - } - - public Object run() throws JasperException { - internalIntrospecthelper( - bean,prop,value,request,param,ignoreMethodNF); - return null; - } - } - - /** - * Returns the value of the javax.servlet.error.exception request - * attribute value, if present, otherwise the value of the - * javax.servlet.jsp.jspException request attribute value. - * - * This method is called at the beginning of the generated servlet code - * for a JSP error page, when the "exception" implicit scripting language - * variable is initialized. - */ - public static Throwable getThrowable(ServletRequest request) { - Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION); - if (error == null) { - error = (Throwable) request.getAttribute(JSP_EXCEPTION); - if (error != null) { - /* - * The only place that sets JSP_EXCEPTION is - * PageContextImpl.handlePageException(). It really should set - * SERVLET_EXCEPTION, but that would interfere with the - * ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we - * need to set SERVLET_EXCEPTION. - */ - request.setAttribute(SERVLET_EXCEPTION, error); - } - } - - return error; - } - - public static boolean coerceToBoolean(String s) { - if (s == null || s.length() == 0) - return false; - else - return Boolean.valueOf(s).booleanValue(); - } - - public static byte coerceToByte(String s) { - if (s == null || s.length() == 0) - return (byte) 0; - else - return Byte.valueOf(s).byteValue(); - } - - public static char coerceToChar(String s) { - if (s == null || s.length() == 0) { - return (char) 0; - } else { - // this trick avoids escaping issues - return (char)(int) s.charAt(0); - } - } - - public static double coerceToDouble(String s) { - if (s == null || s.length() == 0) - return (double) 0; - else - return Double.valueOf(s).doubleValue(); - } - - public static float coerceToFloat(String s) { - if (s == null || s.length() == 0) - return (float) 0; - else - return Float.valueOf(s).floatValue(); - } - - public static int coerceToInt(String s) { - if (s == null || s.length() == 0) - return 0; - else - return Integer.valueOf(s).intValue(); - } - - public static short coerceToShort(String s) { - if (s == null || s.length() == 0) - return (short) 0; - else - return Short.valueOf(s).shortValue(); - } - - public static long coerceToLong(String s) { - if (s == null || s.length() == 0) - return (long) 0; - else - return Long.valueOf(s).longValue(); - } - - public static Object coerce(String s, Class target) { - - boolean isNullOrEmpty = (s == null || s.length() == 0); - - if (target == Boolean.class) { - if (isNullOrEmpty) { - s = "false"; - } - return new Boolean(s); - } else if (target == Byte.class) { - if (isNullOrEmpty) - return new Byte((byte) 0); - else - return new Byte(s); - } else if (target == Character.class) { - if (isNullOrEmpty) - return new Character((char) 0); - else - return new Character(s.charAt(0)); - } else if (target == Double.class) { - if (isNullOrEmpty) - return new Double(0); - else - return new Double(s); - } else if (target == Float.class) { - if (isNullOrEmpty) - return new Float(0); - else - return new Float(s); - } else if (target == Integer.class) { - if (isNullOrEmpty) - return new Integer(0); - else - return new Integer(s); - } else if (target == Short.class) { - if (isNullOrEmpty) - return new Short((short) 0); - else - return new Short(s); - } else if (target == Long.class) { - if (isNullOrEmpty) - return new Long(0); - else - return new Long(s); - } else { - return null; - } - } - - // __begin convertMethod - public static Object convert(String propertyName, String s, Class t, - Class propertyEditorClass) - throws JasperException - { - try { - if (s == null) { - if (t.equals(Boolean.class) || t.equals(Boolean.TYPE)) - s = "false"; - else - return null; - } - if (propertyEditorClass != null) { - return getValueFromBeanInfoPropertyEditor( - t, propertyName, s, propertyEditorClass); - } else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) { - if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true")) - s = "true"; - else - s = "false"; - return new Boolean(s); - } else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) { - return new Byte(s); - } else if (t.equals(Character.class) || t.equals(Character.TYPE)) { - return s.length() > 0 ? new Character(s.charAt(0)) : null; - } else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) { - return new Short(s); - } else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) { - return new Integer(s); - } else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) { - return new Float(s); - } else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) { - return new Long(s); - } else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) { - return new Double(s); - } else if ( t.equals(String.class) ) { - return s; - } else if ( t.equals(java.io.File.class) ) { - return new java.io.File(s); - } else if (t.getName().equals("java.lang.Object")) { - return new Object[] {s}; - } else { - return getValueFromPropertyEditorManager( - t, propertyName, s); - } - } catch (Exception ex) { - throw new JasperException(ex); - } - } - // __end convertMethod - - // __begin introspectMethod - public static void introspect(Object bean, ServletRequest request) - throws JasperException - { - Enumeration e = request.getParameterNames(); - while ( e.hasMoreElements() ) { - String name = (String) e.nextElement(); - String value = request.getParameter(name); - introspecthelper(bean, name, value, request, name, true); - } - } - // __end introspectMethod - - // __begin introspecthelperMethod - public static void introspecthelper(Object bean, String prop, - String value, ServletRequest request, - String param, boolean ignoreMethodNF) - throws JasperException - { - if( System.getSecurityManager() != null ) { - try { - PrivilegedIntrospectHelper dp = - new PrivilegedIntrospectHelper( - bean,prop,value,request,param,ignoreMethodNF); - AccessController.doPrivileged(dp); - } catch( PrivilegedActionException pe) { - Exception e = pe.getException(); - throw (JasperException)e; - } - } else { - internalIntrospecthelper( - bean,prop,value,request,param,ignoreMethodNF); - } - } - - private static void internalIntrospecthelper(Object bean, String prop, - String value, ServletRequest request, - String param, boolean ignoreMethodNF) - throws JasperException - { - Method method = null; - Class type = null; - Class propertyEditorClass = null; - try { - java.beans.BeanInfo info - = java.beans.Introspector.getBeanInfo(bean.getClass()); - if ( info != null ) { - java.beans.PropertyDescriptor pd[] - = info.getPropertyDescriptors(); - for (int i = 0 ; i < pd.length ; i++) { - if ( pd[i].getName().equals(prop) ) { - method = pd[i].getWriteMethod(); - type = pd[i].getPropertyType(); - propertyEditorClass = pd[i].getPropertyEditorClass(); - break; - } - } - } - if ( method != null ) { - if (type.isArray()) { - if (request == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.setproperty.noindexset")); - } - Class t = type.getComponentType(); - String[] values = request.getParameterValues(param); - //XXX Please check. - if(values == null) return; - if(t.equals(String.class)) { - method.invoke(bean, new Object[] { values }); - } else { - Object tmpval = null; - createTypedArray (prop, bean, method, values, t, - propertyEditorClass); - } - } else { - if(value == null || (param != null && value.equals(""))) return; - Object oval = convert(prop, value, type, propertyEditorClass); - if ( oval != null ) - method.invoke(bean, new Object[] { oval }); - } - } - } catch (Exception ex) { - throw new JasperException(ex); - } - if (!ignoreMethodNF && (method == null)) { - if (type == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.noproperty", - prop, - bean.getClass().getName())); - } else { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nomethod.setproperty", - prop, - type.getName(), - bean.getClass().getName())); - } - } - } - // __end introspecthelperMethod - - //------------------------------------------------------------------- - // functions to convert builtin Java data types to string. - //------------------------------------------------------------------- - // __begin toStringMethod - public static String toString(Object o) { - return String.valueOf(o); - } - - public static String toString(byte b) { - return new Byte(b).toString(); - } - - public static String toString(boolean b) { - return new Boolean(b).toString(); - } - - public static String toString(short s) { - return new Short(s).toString(); - } - - public static String toString(int i) { - return new Integer(i).toString(); - } - - public static String toString(float f) { - return new Float(f).toString(); - } - - public static String toString(long l) { - return new Long(l).toString(); - } - - public static String toString(double d) { - return new Double(d).toString(); - } - - public static String toString(char c) { - return new Character(c).toString(); - } - // __end toStringMethod - - - /** - * Create a typed array. - * This is a special case where params are passed through - * the request and the property is indexed. - */ - public static void createTypedArray(String propertyName, - Object bean, - Method method, - String[] values, - Class t, - Class propertyEditorClass) - throws JasperException { - - try { - if (propertyEditorClass != null) { - Object[] tmpval = new Integer[values.length]; - for (int i=0; i^()[]{}$\\\n"; - - for(int index=0; index= encoded.length()) - count = encoded.length(); - else - count += 2; - } else if (cur == '+') { - holdbuffer[bufcount++] = (byte) ' '; - } else { - holdbuffer[bufcount++] = (byte) cur; - } - } - // REVISIT -- remedy for Deprecated warning. - //return new String(holdbuffer,0,0,bufcount); - return new String(holdbuffer,0,bufcount); - } - - // __begin lookupReadMethodMethod - public static Object handleGetProperty(Object o, String prop) - throws JasperException { - if (o == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nullbean")); - } - Object value = null; - try { - Method method = getReadMethod(o.getClass(), prop); - value = method.invoke(o, (Object[]) null); - } catch (Exception ex) { - throw new JasperException (ex); - } - return value; - } - // __end lookupReadMethodMethod - - // handles with EL expression for 'value' attribute -/** Use proprietaryEvaluate - public static void handleSetPropertyExpression(Object bean, - String prop, String expression, PageContext pageContext, - VariableResolver variableResolver, FunctionMapper functionMapper ) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { - pageContext.getExpressionEvaluator().evaluate( - expression, - method.getParameterTypes()[0], - variableResolver, - functionMapper, - null ) - }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } -**/ - public static void handleSetPropertyExpression(Object bean, - String prop, String expression, PageContext pageContext, - ProtectedFunctionMapper functionMapper ) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { - PageContextImpl.proprietaryEvaluate( - expression, - method.getParameterTypes()[0], - pageContext, - functionMapper, - false ) - }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - Object value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { value }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - int value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Integer(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - short value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Short(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - long value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Long(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - double value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Double(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - float value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Float(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - char value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Character(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - byte value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Byte(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static void handleSetProperty(Object bean, String prop, - boolean value) - throws JasperException - { - try { - Method method = getWriteMethod(bean.getClass(), prop); - method.invoke(bean, new Object[] { new Boolean(value) }); - } catch (Exception ex) { - throw new JasperException(ex); - } - } - - public static Method getWriteMethod(Class beanClass, String prop) - throws JasperException { - Method method = null; - Class type = null; - try { - java.beans.BeanInfo info - = java.beans.Introspector.getBeanInfo(beanClass); - if ( info != null ) { - java.beans.PropertyDescriptor pd[] - = info.getPropertyDescriptors(); - for (int i = 0 ; i < pd.length ; i++) { - if ( pd[i].getName().equals(prop) ) { - method = pd[i].getWriteMethod(); - type = pd[i].getPropertyType(); - break; - } - } - } else { - // just in case introspection silently fails. - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nobeaninfo", - beanClass.getName())); - } - } catch (Exception ex) { - throw new JasperException (ex); - } - if (method == null) { - if (type == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.noproperty", - prop, - beanClass.getName())); - } else { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nomethod.setproperty", - prop, - type.getName(), - beanClass.getName())); - } - } - return method; - } - - public static Method getReadMethod(Class beanClass, String prop) - throws JasperException { - - Method method = null; - Class type = null; - try { - java.beans.BeanInfo info - = java.beans.Introspector.getBeanInfo(beanClass); - if ( info != null ) { - java.beans.PropertyDescriptor pd[] - = info.getPropertyDescriptors(); - for (int i = 0 ; i < pd.length ; i++) { - if ( pd[i].getName().equals(prop) ) { - method = pd[i].getReadMethod(); - type = pd[i].getPropertyType(); - break; - } - } - } else { - // just in case introspection silently fails. - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nobeaninfo", - beanClass.getName())); - } - } catch (Exception ex) { - throw new JasperException (ex); - } - if (method == null) { - if (type == null) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.noproperty", prop, - beanClass.getName())); - } else { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.nomethod", prop, - beanClass.getName())); - } - } - - return method; - } - - //********************************************************************* - // PropertyEditor Support - - public static Object getValueFromBeanInfoPropertyEditor( - Class attrClass, String attrName, String attrValue, - Class propertyEditorClass) - throws JasperException - { - try { - PropertyEditor pe = (PropertyEditor)propertyEditorClass.newInstance(); - pe.setAsText(attrValue); - return pe.getValue(); - } catch (Exception ex) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.property.conversion", - attrValue, attrClass.getName(), attrName, - ex.getMessage())); - } - } - - public static Object getValueFromPropertyEditorManager( - Class attrClass, String attrName, String attrValue) - throws JasperException - { - try { - PropertyEditor propEditor = - PropertyEditorManager.findEditor(attrClass); - if (propEditor != null) { - propEditor.setAsText(attrValue); - return propEditor.getValue(); - } else { - throw new IllegalArgumentException( - Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered")); - } - } catch (IllegalArgumentException ex) { - throw new JasperException( - Localizer.getMessage("jsp.error.beans.property.conversion", - attrValue, attrClass.getName(), attrName, - ex.getMessage())); - } - } - - - // ************************************************************************ - // General Purpose Runtime Methods - // ************************************************************************ - - - /** - * Convert a possibly relative resource path into a context-relative - * resource path that starts with a '/'. - * - * @param request The servlet request we are processing - * @param relativePath The possibly relative resource path - */ - public static String getContextRelativePath(ServletRequest request, - String relativePath) { - - if (relativePath.startsWith("/")) - return (relativePath); - if (!(request instanceof HttpServletRequest)) - return (relativePath); - HttpServletRequest hrequest = (HttpServletRequest) request; - String uri = (String) - request.getAttribute("javax.servlet.include.servlet_path"); - if (uri != null) { - String pathInfo = (String) - request.getAttribute("javax.servlet.include.path_info"); - if (pathInfo == null) { - if (uri.lastIndexOf('/') >= 0) - uri = uri.substring(0, uri.lastIndexOf('/')); - } - } - else { - uri = hrequest.getServletPath(); - if (uri.lastIndexOf('/') >= 0) - uri = uri.substring(0, uri.lastIndexOf('/')); - } - return uri + '/' + relativePath; - - } - - - /** - * Perform a RequestDispatcher.include() operation, with optional flushing - * of the response beforehand. - * - * @param request The servlet request we are processing - * @param response The servlet response we are processing - * @param relativePath The relative path of the resource to be included - * @param out The Writer to whom we are currently writing - * @param flush Should we flush before the include is processed? - * - * @exception IOException if thrown by the included servlet - * @exception ServletException if thrown by the included servlet - */ - public static void include(ServletRequest request, - ServletResponse response, - String relativePath, - JspWriter out, - boolean flush) - throws IOException, ServletException { - - if (flush && !(out instanceof BodyContent)) - out.flush(); - - // FIXME - It is tempting to use request.getRequestDispatcher() to - // resolve a relative path directly, but Catalina currently does not - // take into account whether the caller is inside a RequestDispatcher - // include or not. Whether Catalina *should* take that into account - // is a spec issue currently under review. In the mean time, - // replicate Jasper's previous behavior - - String resourcePath = getContextRelativePath(request, relativePath); - RequestDispatcher rd = request.getRequestDispatcher(resourcePath); - - rd.include(request, - new ServletResponseWrapperInclude(response, out)); - - } - - /** - * URL encodes a string, based on the supplied character encoding. - * This performs the same function as java.next.URLEncode.encode - * in J2SDK1.4, and should be removed if the only platform supported - * is 1.4 or higher. - * @param s The String to be URL encoded. - * @param enc The character encoding - * @return The URL encoded String - */ - public static String URLEncode(String s, String enc) { - - if (s == null) { - return "null"; - } - - if (enc == null) { - enc = "ISO-8859-1"; // The default request encoding - } - - StringBuffer out = new StringBuffer(s.length()); - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - OutputStreamWriter writer = null; - try { - writer = new OutputStreamWriter(buf, enc); - } catch (java.io.UnsupportedEncodingException ex) { - // Use the default encoding? - writer = new OutputStreamWriter(buf); - } - - for (int i = 0; i < s.length(); i++) { - int c = s.charAt(i); - if (c == ' ') { - out.append('+'); - } else if (isSafeChar(c)) { - out.append((char)c); - } else { - // convert to external encoding before hex conversion - try { - writer.write(c); - writer.flush(); - } catch(IOException e) { - buf.reset(); - continue; - } - byte[] ba = buf.toByteArray(); - for (int j = 0; j < ba.length; j++) { - out.append('%'); - // Converting each byte in the buffer - out.append(Character.forDigit((ba[j]>>4) & 0xf, 16)); - out.append(Character.forDigit(ba[j] & 0xf, 16)); - } - buf.reset(); - } - } - return out.toString(); - } - - private static boolean isSafeChar(int c) { - if (c >= 'a' && c <= 'z') { - return true; - } - if (c >= 'A' && c <= 'Z') { - return true; - } - if (c >= '0' && c <= '9') { - return true; - } - if (c == '-' || c == '_' || c == '.' || c == '!' || - c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') { - return true; - } - return false; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.beans.PropertyEditor; +import java.beans.PropertyEditorManager; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.lang.reflect.Method; +import java.security.AccessController; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Enumeration; + +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.tagext.BodyContent; + +import org.apache.jasper.JasperException; +import org.apache.jasper.compiler.Localizer; + +/** + * Bunch of util methods that are used by code generated for useBean, + * getProperty and setProperty. + * + * The __begin, __end stuff is there so that the JSP engine can + * actually parse this file and inline them if people don't want + * runtime dependencies on this class. However, I'm not sure if that + * works so well right now. It got forgotten at some point. -akv + * + * @author Mandar Raje + * @author Shawn Bayern + */ +public class JspRuntimeLibrary { + + private static final String SERVLET_EXCEPTION + = "javax.servlet.error.exception"; + private static final String JSP_EXCEPTION + = "javax.servlet.jsp.jspException"; + + protected static class PrivilegedIntrospectHelper + implements PrivilegedExceptionAction { + + private Object bean; + private String prop; + private String value; + private ServletRequest request; + private String param; + private boolean ignoreMethodNF; + + PrivilegedIntrospectHelper(Object bean, String prop, + String value, ServletRequest request, + String param, boolean ignoreMethodNF) + { + this.bean = bean; + this.prop = prop; + this.value = value; + this.request = request; + this.param = param; + this.ignoreMethodNF = ignoreMethodNF; + } + + public Object run() throws JasperException { + internalIntrospecthelper( + bean,prop,value,request,param,ignoreMethodNF); + return null; + } + } + + /** + * Returns the value of the javax.servlet.error.exception request + * attribute value, if present, otherwise the value of the + * javax.servlet.jsp.jspException request attribute value. + * + * This method is called at the beginning of the generated servlet code + * for a JSP error page, when the "exception" implicit scripting language + * variable is initialized. + */ + public static Throwable getThrowable(ServletRequest request) { + Throwable error = (Throwable) request.getAttribute(SERVLET_EXCEPTION); + if (error == null) { + error = (Throwable) request.getAttribute(JSP_EXCEPTION); + if (error != null) { + /* + * The only place that sets JSP_EXCEPTION is + * PageContextImpl.handlePageException(). It really should set + * SERVLET_EXCEPTION, but that would interfere with the + * ErrorReportValve. Therefore, if JSP_EXCEPTION is set, we + * need to set SERVLET_EXCEPTION. + */ + request.setAttribute(SERVLET_EXCEPTION, error); + } + } + + return error; + } + + public static boolean coerceToBoolean(String s) { + if (s == null || s.length() == 0) + return false; + else + return Boolean.valueOf(s).booleanValue(); + } + + public static byte coerceToByte(String s) { + if (s == null || s.length() == 0) + return (byte) 0; + else + return Byte.valueOf(s).byteValue(); + } + + public static char coerceToChar(String s) { + if (s == null || s.length() == 0) { + return (char) 0; + } else { + // this trick avoids escaping issues + return (char)(int) s.charAt(0); + } + } + + public static double coerceToDouble(String s) { + if (s == null || s.length() == 0) + return (double) 0; + else + return Double.valueOf(s).doubleValue(); + } + + public static float coerceToFloat(String s) { + if (s == null || s.length() == 0) + return (float) 0; + else + return Float.valueOf(s).floatValue(); + } + + public static int coerceToInt(String s) { + if (s == null || s.length() == 0) + return 0; + else + return Integer.valueOf(s).intValue(); + } + + public static short coerceToShort(String s) { + if (s == null || s.length() == 0) + return (short) 0; + else + return Short.valueOf(s).shortValue(); + } + + public static long coerceToLong(String s) { + if (s == null || s.length() == 0) + return (long) 0; + else + return Long.valueOf(s).longValue(); + } + + public static Object coerce(String s, Class target) { + + boolean isNullOrEmpty = (s == null || s.length() == 0); + + if (target == Boolean.class) { + if (isNullOrEmpty) { + s = "false"; + } + return new Boolean(s); + } else if (target == Byte.class) { + if (isNullOrEmpty) + return new Byte((byte) 0); + else + return new Byte(s); + } else if (target == Character.class) { + if (isNullOrEmpty) + return new Character((char) 0); + else + return new Character(s.charAt(0)); + } else if (target == Double.class) { + if (isNullOrEmpty) + return new Double(0); + else + return new Double(s); + } else if (target == Float.class) { + if (isNullOrEmpty) + return new Float(0); + else + return new Float(s); + } else if (target == Integer.class) { + if (isNullOrEmpty) + return new Integer(0); + else + return new Integer(s); + } else if (target == Short.class) { + if (isNullOrEmpty) + return new Short((short) 0); + else + return new Short(s); + } else if (target == Long.class) { + if (isNullOrEmpty) + return new Long(0); + else + return new Long(s); + } else { + return null; + } + } + + // __begin convertMethod + public static Object convert(String propertyName, String s, Class t, + Class propertyEditorClass) + throws JasperException + { + try { + if (s == null) { + if (t.equals(Boolean.class) || t.equals(Boolean.TYPE)) + s = "false"; + else + return null; + } + if (propertyEditorClass != null) { + return getValueFromBeanInfoPropertyEditor( + t, propertyName, s, propertyEditorClass); + } else if ( t.equals(Boolean.class) || t.equals(Boolean.TYPE) ) { + if (s.equalsIgnoreCase("on") || s.equalsIgnoreCase("true")) + s = "true"; + else + s = "false"; + return new Boolean(s); + } else if ( t.equals(Byte.class) || t.equals(Byte.TYPE) ) { + return new Byte(s); + } else if (t.equals(Character.class) || t.equals(Character.TYPE)) { + return s.length() > 0 ? new Character(s.charAt(0)) : null; + } else if ( t.equals(Short.class) || t.equals(Short.TYPE) ) { + return new Short(s); + } else if ( t.equals(Integer.class) || t.equals(Integer.TYPE) ) { + return new Integer(s); + } else if ( t.equals(Float.class) || t.equals(Float.TYPE) ) { + return new Float(s); + } else if ( t.equals(Long.class) || t.equals(Long.TYPE) ) { + return new Long(s); + } else if ( t.equals(Double.class) || t.equals(Double.TYPE) ) { + return new Double(s); + } else if ( t.equals(String.class) ) { + return s; + } else if ( t.equals(java.io.File.class) ) { + return new java.io.File(s); + } else if (t.getName().equals("java.lang.Object")) { + return new Object[] {s}; + } else { + return getValueFromPropertyEditorManager( + t, propertyName, s); + } + } catch (Exception ex) { + throw new JasperException(ex); + } + } + // __end convertMethod + + // __begin introspectMethod + public static void introspect(Object bean, ServletRequest request) + throws JasperException + { + Enumeration e = request.getParameterNames(); + while ( e.hasMoreElements() ) { + String name = (String) e.nextElement(); + String value = request.getParameter(name); + introspecthelper(bean, name, value, request, name, true); + } + } + // __end introspectMethod + + // __begin introspecthelperMethod + public static void introspecthelper(Object bean, String prop, + String value, ServletRequest request, + String param, boolean ignoreMethodNF) + throws JasperException + { + if( System.getSecurityManager() != null ) { + try { + PrivilegedIntrospectHelper dp = + new PrivilegedIntrospectHelper( + bean,prop,value,request,param,ignoreMethodNF); + AccessController.doPrivileged(dp); + } catch( PrivilegedActionException pe) { + Exception e = pe.getException(); + throw (JasperException)e; + } + } else { + internalIntrospecthelper( + bean,prop,value,request,param,ignoreMethodNF); + } + } + + private static void internalIntrospecthelper(Object bean, String prop, + String value, ServletRequest request, + String param, boolean ignoreMethodNF) + throws JasperException + { + Method method = null; + Class type = null; + Class propertyEditorClass = null; + try { + java.beans.BeanInfo info + = java.beans.Introspector.getBeanInfo(bean.getClass()); + if ( info != null ) { + java.beans.PropertyDescriptor pd[] + = info.getPropertyDescriptors(); + for (int i = 0 ; i < pd.length ; i++) { + if ( pd[i].getName().equals(prop) ) { + method = pd[i].getWriteMethod(); + type = pd[i].getPropertyType(); + propertyEditorClass = pd[i].getPropertyEditorClass(); + break; + } + } + } + if ( method != null ) { + if (type.isArray()) { + if (request == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.setproperty.noindexset")); + } + Class t = type.getComponentType(); + String[] values = request.getParameterValues(param); + //XXX Please check. + if(values == null) return; + if(t.equals(String.class)) { + method.invoke(bean, new Object[] { values }); + } else { + Object tmpval = null; + createTypedArray (prop, bean, method, values, t, + propertyEditorClass); + } + } else { + if(value == null || (param != null && value.equals(""))) return; + Object oval = convert(prop, value, type, propertyEditorClass); + if ( oval != null ) + method.invoke(bean, new Object[] { oval }); + } + } + } catch (Exception ex) { + throw new JasperException(ex); + } + if (!ignoreMethodNF && (method == null)) { + if (type == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.noproperty", + prop, + bean.getClass().getName())); + } else { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nomethod.setproperty", + prop, + type.getName(), + bean.getClass().getName())); + } + } + } + // __end introspecthelperMethod + + //------------------------------------------------------------------- + // functions to convert builtin Java data types to string. + //------------------------------------------------------------------- + // __begin toStringMethod + public static String toString(Object o) { + return String.valueOf(o); + } + + public static String toString(byte b) { + return new Byte(b).toString(); + } + + public static String toString(boolean b) { + return new Boolean(b).toString(); + } + + public static String toString(short s) { + return new Short(s).toString(); + } + + public static String toString(int i) { + return new Integer(i).toString(); + } + + public static String toString(float f) { + return new Float(f).toString(); + } + + public static String toString(long l) { + return new Long(l).toString(); + } + + public static String toString(double d) { + return new Double(d).toString(); + } + + public static String toString(char c) { + return new Character(c).toString(); + } + // __end toStringMethod + + + /** + * Create a typed array. + * This is a special case where params are passed through + * the request and the property is indexed. + */ + public static void createTypedArray(String propertyName, + Object bean, + Method method, + String[] values, + Class t, + Class propertyEditorClass) + throws JasperException { + + try { + if (propertyEditorClass != null) { + Object[] tmpval = new Integer[values.length]; + for (int i=0; i^()[]{}$\\\n"; + + for(int index=0; index= encoded.length()) + count = encoded.length(); + else + count += 2; + } else if (cur == '+') { + holdbuffer[bufcount++] = (byte) ' '; + } else { + holdbuffer[bufcount++] = (byte) cur; + } + } + // REVISIT -- remedy for Deprecated warning. + //return new String(holdbuffer,0,0,bufcount); + return new String(holdbuffer,0,bufcount); + } + + // __begin lookupReadMethodMethod + public static Object handleGetProperty(Object o, String prop) + throws JasperException { + if (o == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nullbean")); + } + Object value = null; + try { + Method method = getReadMethod(o.getClass(), prop); + value = method.invoke(o, (Object[]) null); + } catch (Exception ex) { + throw new JasperException (ex); + } + return value; + } + // __end lookupReadMethodMethod + + // handles with EL expression for 'value' attribute +/** Use proprietaryEvaluate + public static void handleSetPropertyExpression(Object bean, + String prop, String expression, PageContext pageContext, + VariableResolver variableResolver, FunctionMapper functionMapper ) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { + pageContext.getExpressionEvaluator().evaluate( + expression, + method.getParameterTypes()[0], + variableResolver, + functionMapper, + null ) + }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } +**/ + public static void handleSetPropertyExpression(Object bean, + String prop, String expression, PageContext pageContext, + ProtectedFunctionMapper functionMapper ) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { + PageContextImpl.proprietaryEvaluate( + expression, + method.getParameterTypes()[0], + pageContext, + functionMapper, + false ) + }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + Object value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { value }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + int value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Integer(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + short value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Short(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + long value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Long(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + double value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Double(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + float value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Float(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + char value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Character(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + byte value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Byte(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static void handleSetProperty(Object bean, String prop, + boolean value) + throws JasperException + { + try { + Method method = getWriteMethod(bean.getClass(), prop); + method.invoke(bean, new Object[] { new Boolean(value) }); + } catch (Exception ex) { + throw new JasperException(ex); + } + } + + public static Method getWriteMethod(Class beanClass, String prop) + throws JasperException { + Method method = null; + Class type = null; + try { + java.beans.BeanInfo info + = java.beans.Introspector.getBeanInfo(beanClass); + if ( info != null ) { + java.beans.PropertyDescriptor pd[] + = info.getPropertyDescriptors(); + for (int i = 0 ; i < pd.length ; i++) { + if ( pd[i].getName().equals(prop) ) { + method = pd[i].getWriteMethod(); + type = pd[i].getPropertyType(); + break; + } + } + } else { + // just in case introspection silently fails. + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nobeaninfo", + beanClass.getName())); + } + } catch (Exception ex) { + throw new JasperException (ex); + } + if (method == null) { + if (type == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.noproperty", + prop, + beanClass.getName())); + } else { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nomethod.setproperty", + prop, + type.getName(), + beanClass.getName())); + } + } + return method; + } + + public static Method getReadMethod(Class beanClass, String prop) + throws JasperException { + + Method method = null; + Class type = null; + try { + java.beans.BeanInfo info + = java.beans.Introspector.getBeanInfo(beanClass); + if ( info != null ) { + java.beans.PropertyDescriptor pd[] + = info.getPropertyDescriptors(); + for (int i = 0 ; i < pd.length ; i++) { + if ( pd[i].getName().equals(prop) ) { + method = pd[i].getReadMethod(); + type = pd[i].getPropertyType(); + break; + } + } + } else { + // just in case introspection silently fails. + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nobeaninfo", + beanClass.getName())); + } + } catch (Exception ex) { + throw new JasperException (ex); + } + if (method == null) { + if (type == null) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.noproperty", prop, + beanClass.getName())); + } else { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.nomethod", prop, + beanClass.getName())); + } + } + + return method; + } + + //********************************************************************* + // PropertyEditor Support + + public static Object getValueFromBeanInfoPropertyEditor( + Class attrClass, String attrName, String attrValue, + Class propertyEditorClass) + throws JasperException + { + try { + PropertyEditor pe = (PropertyEditor)propertyEditorClass.newInstance(); + pe.setAsText(attrValue); + return pe.getValue(); + } catch (Exception ex) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.property.conversion", + attrValue, attrClass.getName(), attrName, + ex.getMessage())); + } + } + + public static Object getValueFromPropertyEditorManager( + Class attrClass, String attrName, String attrValue) + throws JasperException + { + try { + PropertyEditor propEditor = + PropertyEditorManager.findEditor(attrClass); + if (propEditor != null) { + propEditor.setAsText(attrValue); + return propEditor.getValue(); + } else { + throw new IllegalArgumentException( + Localizer.getMessage("jsp.error.beans.propertyeditor.notregistered")); + } + } catch (IllegalArgumentException ex) { + throw new JasperException( + Localizer.getMessage("jsp.error.beans.property.conversion", + attrValue, attrClass.getName(), attrName, + ex.getMessage())); + } + } + + + // ************************************************************************ + // General Purpose Runtime Methods + // ************************************************************************ + + + /** + * Convert a possibly relative resource path into a context-relative + * resource path that starts with a '/'. + * + * @param request The servlet request we are processing + * @param relativePath The possibly relative resource path + */ + public static String getContextRelativePath(ServletRequest request, + String relativePath) { + + if (relativePath.startsWith("/")) + return (relativePath); + if (!(request instanceof HttpServletRequest)) + return (relativePath); + HttpServletRequest hrequest = (HttpServletRequest) request; + String uri = (String) + request.getAttribute("javax.servlet.include.servlet_path"); + if (uri != null) { + String pathInfo = (String) + request.getAttribute("javax.servlet.include.path_info"); + if (pathInfo == null) { + if (uri.lastIndexOf('/') >= 0) + uri = uri.substring(0, uri.lastIndexOf('/')); + } + } + else { + uri = hrequest.getServletPath(); + if (uri.lastIndexOf('/') >= 0) + uri = uri.substring(0, uri.lastIndexOf('/')); + } + return uri + '/' + relativePath; + + } + + + /** + * Perform a RequestDispatcher.include() operation, with optional flushing + * of the response beforehand. + * + * @param request The servlet request we are processing + * @param response The servlet response we are processing + * @param relativePath The relative path of the resource to be included + * @param out The Writer to whom we are currently writing + * @param flush Should we flush before the include is processed? + * + * @exception IOException if thrown by the included servlet + * @exception ServletException if thrown by the included servlet + */ + public static void include(ServletRequest request, + ServletResponse response, + String relativePath, + JspWriter out, + boolean flush) + throws IOException, ServletException { + + if (flush && !(out instanceof BodyContent)) + out.flush(); + + // FIXME - It is tempting to use request.getRequestDispatcher() to + // resolve a relative path directly, but Catalina currently does not + // take into account whether the caller is inside a RequestDispatcher + // include or not. Whether Catalina *should* take that into account + // is a spec issue currently under review. In the mean time, + // replicate Jasper's previous behavior + + String resourcePath = getContextRelativePath(request, relativePath); + RequestDispatcher rd = request.getRequestDispatcher(resourcePath); + + rd.include(request, + new ServletResponseWrapperInclude(response, out)); + + } + + /** + * URL encodes a string, based on the supplied character encoding. + * This performs the same function as java.next.URLEncode.encode + * in J2SDK1.4, and should be removed if the only platform supported + * is 1.4 or higher. + * @param s The String to be URL encoded. + * @param enc The character encoding + * @return The URL encoded String + */ + public static String URLEncode(String s, String enc) { + + if (s == null) { + return "null"; + } + + if (enc == null) { + enc = "ISO-8859-1"; // The default request encoding + } + + StringBuffer out = new StringBuffer(s.length()); + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + OutputStreamWriter writer = null; + try { + writer = new OutputStreamWriter(buf, enc); + } catch (java.io.UnsupportedEncodingException ex) { + // Use the default encoding? + writer = new OutputStreamWriter(buf); + } + + for (int i = 0; i < s.length(); i++) { + int c = s.charAt(i); + if (c == ' ') { + out.append('+'); + } else if (isSafeChar(c)) { + out.append((char)c); + } else { + // convert to external encoding before hex conversion + try { + writer.write(c); + writer.flush(); + } catch(IOException e) { + buf.reset(); + continue; + } + byte[] ba = buf.toByteArray(); + for (int j = 0; j < ba.length; j++) { + out.append('%'); + // Converting each byte in the buffer + out.append(Character.forDigit((ba[j]>>4) & 0xf, 16)); + out.append(Character.forDigit(ba[j] & 0xf, 16)); + } + buf.reset(); + } + } + return out.toString(); + } + + private static boolean isSafeChar(int c) { + if (c >= 'a' && c <= 'z') { + return true; + } + if (c >= 'A' && c <= 'Z') { + return true; + } + if (c >= '0' && c <= '9') { + return true; + } + if (c == '-' || c == '_' || c == '.' || c == '!' || + c == '~' || c == '*' || c == '\'' || c == '(' || c == ')') { + return true; + } + return false; + } + +} diff --git a/java/org/apache/jasper/runtime/JspSourceDependent.java b/java/org/apache/jasper/runtime/JspSourceDependent.java index 91e7fd7ed..880cba16d 100644 --- a/java/org/apache/jasper/runtime/JspSourceDependent.java +++ b/java/org/apache/jasper/runtime/JspSourceDependent.java @@ -1,38 +1,38 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -/** - * Interface for tracking the source files dependencies, for the purpose - * of compiling out of date pages. This is used for - * 1) files that are included by page directives - * 2) files that are included by include-prelude and include-coda in jsp:config - * 3) files that are tag files and referenced - * 4) TLDs referenced - */ - -public interface JspSourceDependent { - - /** - * Returns a list of files names that the current page has a source - * dependency on. - */ - // FIXME: Type used is Object due to very weird behavior - // with Eclipse JDT 3.1 in Java 5 mode - public Object getDependants(); - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +/** + * Interface for tracking the source files dependencies, for the purpose + * of compiling out of date pages. This is used for + * 1) files that are included by page directives + * 2) files that are included by include-prelude and include-coda in jsp:config + * 3) files that are tag files and referenced + * 4) TLDs referenced + */ + +public interface JspSourceDependent { + + /** + * Returns a list of files names that the current page has a source + * dependency on. + */ + // FIXME: Type used is Object due to very weird behavior + // with Eclipse JDT 3.1 in Java 5 mode + public Object getDependants(); + +} diff --git a/java/org/apache/jasper/runtime/JspWriterImpl.java b/java/org/apache/jasper/runtime/JspWriterImpl.java index eba00ffcd..617b46b61 100644 --- a/java/org/apache/jasper/runtime/JspWriterImpl.java +++ b/java/org/apache/jasper/runtime/JspWriterImpl.java @@ -1,589 +1,589 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.IOException; -import java.io.Writer; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import javax.servlet.ServletResponse; -import javax.servlet.jsp.JspWriter; - -import org.apache.jasper.Constants; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.security.SecurityUtil; - -/** - * Write text to a character-output stream, buffering characters so as - * to provide for the efficient writing of single characters, arrays, - * and strings. - * - * Provide support for discarding for the output that has been - * buffered. - * - * This needs revisiting when the buffering problems in the JSP spec - * are fixed -akv - * - * @author Anil K. Vijendran - */ -public class JspWriterImpl extends JspWriter { - - private Writer out; - private ServletResponse response; - private char cb[]; - private int nextChar; - private boolean flushed = false; - private boolean closed = false; - - public JspWriterImpl() { - super( Constants.DEFAULT_BUFFER_SIZE, true ); - } - - /** - * Create a buffered character-output stream that uses a default-sized - * output buffer. - * - * @param response A Servlet Response - */ - public JspWriterImpl(ServletResponse response) { - this(response, Constants.DEFAULT_BUFFER_SIZE, true); - } - - /** - * Create a new buffered character-output stream that uses an output - * buffer of the given size. - * - * @param response A Servlet Response - * @param sz Output-buffer size, a positive integer - * - * @exception IllegalArgumentException If sz is <= 0 - */ - public JspWriterImpl(ServletResponse response, int sz, - boolean autoFlush) { - super(sz, autoFlush); - if (sz < 0) - throw new IllegalArgumentException("Buffer size <= 0"); - this.response = response; - cb = sz == 0 ? null : new char[sz]; - nextChar = 0; - } - - void init( ServletResponse response, int sz, boolean autoFlush ) { - this.response= response; - if( sz > 0 && ( cb == null || sz > cb.length ) ) - cb=new char[sz]; - nextChar = 0; - this.autoFlush=autoFlush; - this.bufferSize=sz; - } - - /** Package-level access - */ - void recycle() { - flushed = false; - closed = false; - out = null; - nextChar = 0; - response = null; - } - - /** - * Flush the output buffer to the underlying character stream, without - * flushing the stream itself. This method is non-private only so that it - * may be invoked by PrintStream. - */ - protected final void flushBuffer() throws IOException { - if (bufferSize == 0) - return; - flushed = true; - ensureOpen(); - if (nextChar == 0) - return; - initOut(); - out.write(cb, 0, nextChar); - nextChar = 0; - } - - private void initOut() throws IOException { - if (out == null) { - out = response.getWriter(); - } - } - - private String getLocalizeMessage(final String message){ - if (SecurityUtil.isPackageProtectionEnabled()){ - return (String)AccessController.doPrivileged(new PrivilegedAction(){ - public Object run(){ - return Localizer.getMessage(message); - } - }); - } else { - return Localizer.getMessage(message); - } - } - - /** - * Discard the output buffer. - */ - public final void clear() throws IOException { - if ((bufferSize == 0) && (out != null)) - // clear() is illegal after any unbuffered output (JSP.5.5) - throw new IllegalStateException( - getLocalizeMessage("jsp.error.ise_on_clear")); - if (flushed) - throw new IOException( - getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer")); - ensureOpen(); - nextChar = 0; - } - - public void clearBuffer() throws IOException { - if (bufferSize == 0) - throw new IllegalStateException( - getLocalizeMessage("jsp.error.ise_on_clear")); - ensureOpen(); - nextChar = 0; - } - - private final void bufferOverflow() throws IOException { - throw new IOException(getLocalizeMessage("jsp.error.overflow")); - } - - /** - * Flush the stream. - * - */ - public void flush() throws IOException { - flushBuffer(); - if (out != null) { - out.flush(); - } - } - - /** - * Close the stream. - * - */ - public void close() throws IOException { - if (response == null || closed) - // multiple calls to close is OK - return; - flush(); - if (out != null) - out.close(); - out = null; - closed = true; - } - - /** - * @return the number of bytes unused in the buffer - */ - public int getRemaining() { - return bufferSize - nextChar; - } - - /** check to make sure that the stream has not been closed */ - private void ensureOpen() throws IOException { - if (response == null || closed) - throw new IOException("Stream closed"); - } - - - /** - * Write a single character. - */ - public void write(int c) throws IOException { - ensureOpen(); - if (bufferSize == 0) { - initOut(); - out.write(c); - } - else { - if (nextChar >= bufferSize) - if (autoFlush) - flushBuffer(); - else - bufferOverflow(); - cb[nextChar++] = (char) c; - } - } - - /** - * Our own little min method, to avoid loading java.lang.Math if we've run - * out of file descriptors and we're trying to print a stack trace. - */ - private int min(int a, int b) { - if (a < b) return a; - return b; - } - - /** - * Write a portion of an array of characters. - * - *

        Ordinarily this method stores characters from the given array into - * this stream's buffer, flushing the buffer to the underlying stream as - * needed. If the requested length is at least as large as the buffer, - * however, then this method will flush the buffer and write the characters - * directly to the underlying stream. Thus redundant - * DiscardableBufferedWriters will not copy data unnecessarily. - * - * @param cbuf A character array - * @param off Offset from which to start reading characters - * @param len Number of characters to write - */ - public void write(char cbuf[], int off, int len) - throws IOException - { - ensureOpen(); - - if (bufferSize == 0) { - initOut(); - out.write(cbuf, off, len); - return; - } - - if ((off < 0) || (off > cbuf.length) || (len < 0) || - ((off + len) > cbuf.length) || ((off + len) < 0)) { - throw new IndexOutOfBoundsException(); - } else if (len == 0) { - return; - } - - if (len >= bufferSize) { - /* If the request length exceeds the size of the output buffer, - flush the buffer and then write the data directly. In this - way buffered streams will cascade harmlessly. */ - if (autoFlush) - flushBuffer(); - else - bufferOverflow(); - initOut(); - out.write(cbuf, off, len); - return; - } - - int b = off, t = off + len; - while (b < t) { - int d = min(bufferSize - nextChar, t - b); - System.arraycopy(cbuf, b, cb, nextChar, d); - b += d; - nextChar += d; - if (nextChar >= bufferSize) - if (autoFlush) - flushBuffer(); - else - bufferOverflow(); - } - - } - - /** - * Write an array of characters. This method cannot be inherited from the - * Writer class because it must suppress I/O exceptions. - */ - public void write(char buf[]) throws IOException { - write(buf, 0, buf.length); - } - - /** - * Write a portion of a String. - * - * @param s String to be written - * @param off Offset from which to start reading characters - * @param len Number of characters to be written - */ - public void write(String s, int off, int len) throws IOException { - ensureOpen(); - if (bufferSize == 0) { - initOut(); - out.write(s, off, len); - return; - } - int b = off, t = off + len; - while (b < t) { - int d = min(bufferSize - nextChar, t - b); - s.getChars(b, b + d, cb, nextChar); - b += d; - nextChar += d; - if (nextChar >= bufferSize) - if (autoFlush) - flushBuffer(); - else - bufferOverflow(); - } - } - - /** - * Write a string. This method cannot be inherited from the Writer class - * because it must suppress I/O exceptions. - */ - public void write(String s) throws IOException { - // Simple fix for Bugzilla 35410 - // Calling the other write function so as to init the buffer anyways - if(s == null) { - write(s, 0, 0); - } else { - write(s, 0, s.length()); - } - } - - - static String lineSeparator = System.getProperty("line.separator"); - - /** - * Write a line separator. The line separator string is defined by the - * system property line.separator, and is not necessarily a single - * newline ('\n') character. - * - * @exception IOException If an I/O error occurs - */ - - public void newLine() throws IOException { - write(lineSeparator); - } - - - /* Methods that do not terminate lines */ - - /** - * Print a boolean value. The string produced by {@link - * java.lang.String#valueOf(boolean)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param b The boolean to be printed - */ - public void print(boolean b) throws IOException { - write(b ? "true" : "false"); - } - - /** - * Print a character. The character is translated into one or more bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param c The char to be printed - */ - public void print(char c) throws IOException { - write(String.valueOf(c)); - } - - /** - * Print an integer. The string produced by {@link - * java.lang.String#valueOf(int)} is translated into bytes according - * to the platform's default character encoding, and these bytes are - * written in exactly the manner of the {@link #write(int)} - * method. - * - * @param i The int to be printed - */ - public void print(int i) throws IOException { - write(String.valueOf(i)); - } - - /** - * Print a long integer. The string produced by {@link - * java.lang.String#valueOf(long)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link #write(int)} - * method. - * - * @param l The long to be printed - */ - public void print(long l) throws IOException { - write(String.valueOf(l)); - } - - /** - * Print a floating-point number. The string produced by {@link - * java.lang.String#valueOf(float)} is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link #write(int)} - * method. - * - * @param f The float to be printed - */ - public void print(float f) throws IOException { - write(String.valueOf(f)); - } - - /** - * Print a double-precision floating-point number. The string produced by - * {@link java.lang.String#valueOf(double)} is translated into - * bytes according to the platform's default character encoding, and these - * bytes are written in exactly the manner of the {@link - * #write(int)} method. - * - * @param d The double to be printed - */ - public void print(double d) throws IOException { - write(String.valueOf(d)); - } - - /** - * Print an array of characters. The characters are converted into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link #write(int)} - * method. - * - * @param s The array of chars to be printed - * - * @throws NullPointerException If s is null - */ - public void print(char s[]) throws IOException { - write(s); - } - - /** - * Print a string. If the argument is null then the string - * "null" is printed. Otherwise, the string's characters are - * converted into bytes according to the platform's default character - * encoding, and these bytes are written in exactly the manner of the - * {@link #write(int)} method. - * - * @param s The String to be printed - */ - public void print(String s) throws IOException { - if (s == null) { - s = "null"; - } - write(s); - } - - /** - * Print an object. The string produced by the {@link - * java.lang.String#valueOf(Object)} method is translated into bytes - * according to the platform's default character encoding, and these bytes - * are written in exactly the manner of the {@link #write(int)} - * method. - * - * @param obj The Object to be printed - */ - public void print(Object obj) throws IOException { - write(String.valueOf(obj)); - } - - /* Methods that do terminate lines */ - - /** - * Terminate the current line by writing the line separator string. The - * line separator string is defined by the system property - * line.separator, and is not necessarily a single newline - * character ('\n'). - * - * Need to change this from PrintWriter because the default - * println() writes to the sink directly instead of through the - * write method... - */ - public void println() throws IOException { - newLine(); - } - - /** - * Print a boolean value and then terminate the line. This method behaves - * as though it invokes {@link #print(boolean)} and then - * {@link #println()}. - */ - public void println(boolean x) throws IOException { - print(x); - println(); - } - - /** - * Print a character and then terminate the line. This method behaves as - * though it invokes {@link #print(char)} and then {@link - * #println()}. - */ - public void println(char x) throws IOException { - print(x); - println(); - } - - /** - * Print an integer and then terminate the line. This method behaves as - * though it invokes {@link #print(int)} and then {@link - * #println()}. - */ - public void println(int x) throws IOException { - print(x); - println(); - } - - /** - * Print a long integer and then terminate the line. This method behaves - * as though it invokes {@link #print(long)} and then - * {@link #println()}. - */ - public void println(long x) throws IOException { - print(x); - println(); - } - - /** - * Print a floating-point number and then terminate the line. This method - * behaves as though it invokes {@link #print(float)} and then - * {@link #println()}. - */ - public void println(float x) throws IOException { - print(x); - println(); - } - - /** - * Print a double-precision floating-point number and then terminate the - * line. This method behaves as though it invokes {@link - * #print(double)} and then {@link #println()}. - */ - public void println(double x) throws IOException { - print(x); - println(); - } - - /** - * Print an array of characters and then terminate the line. This method - * behaves as though it invokes {@link #print(char[])} and then - * {@link #println()}. - */ - public void println(char x[]) throws IOException { - print(x); - println(); - } - - /** - * Print a String and then terminate the line. This method behaves as - * though it invokes {@link #print(String)} and then - * {@link #println()}. - */ - public void println(String x) throws IOException { - print(x); - println(); - } - - /** - * Print an Object and then terminate the line. This method behaves as - * though it invokes {@link #print(Object)} and then - * {@link #println()}. - */ - public void println(Object x) throws IOException { - print(x); - println(); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.IOException; +import java.io.Writer; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.servlet.ServletResponse; +import javax.servlet.jsp.JspWriter; + +import org.apache.jasper.Constants; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.security.SecurityUtil; + +/** + * Write text to a character-output stream, buffering characters so as + * to provide for the efficient writing of single characters, arrays, + * and strings. + * + * Provide support for discarding for the output that has been + * buffered. + * + * This needs revisiting when the buffering problems in the JSP spec + * are fixed -akv + * + * @author Anil K. Vijendran + */ +public class JspWriterImpl extends JspWriter { + + private Writer out; + private ServletResponse response; + private char cb[]; + private int nextChar; + private boolean flushed = false; + private boolean closed = false; + + public JspWriterImpl() { + super( Constants.DEFAULT_BUFFER_SIZE, true ); + } + + /** + * Create a buffered character-output stream that uses a default-sized + * output buffer. + * + * @param response A Servlet Response + */ + public JspWriterImpl(ServletResponse response) { + this(response, Constants.DEFAULT_BUFFER_SIZE, true); + } + + /** + * Create a new buffered character-output stream that uses an output + * buffer of the given size. + * + * @param response A Servlet Response + * @param sz Output-buffer size, a positive integer + * + * @exception IllegalArgumentException If sz is <= 0 + */ + public JspWriterImpl(ServletResponse response, int sz, + boolean autoFlush) { + super(sz, autoFlush); + if (sz < 0) + throw new IllegalArgumentException("Buffer size <= 0"); + this.response = response; + cb = sz == 0 ? null : new char[sz]; + nextChar = 0; + } + + void init( ServletResponse response, int sz, boolean autoFlush ) { + this.response= response; + if( sz > 0 && ( cb == null || sz > cb.length ) ) + cb=new char[sz]; + nextChar = 0; + this.autoFlush=autoFlush; + this.bufferSize=sz; + } + + /** Package-level access + */ + void recycle() { + flushed = false; + closed = false; + out = null; + nextChar = 0; + response = null; + } + + /** + * Flush the output buffer to the underlying character stream, without + * flushing the stream itself. This method is non-private only so that it + * may be invoked by PrintStream. + */ + protected final void flushBuffer() throws IOException { + if (bufferSize == 0) + return; + flushed = true; + ensureOpen(); + if (nextChar == 0) + return; + initOut(); + out.write(cb, 0, nextChar); + nextChar = 0; + } + + private void initOut() throws IOException { + if (out == null) { + out = response.getWriter(); + } + } + + private String getLocalizeMessage(final String message){ + if (SecurityUtil.isPackageProtectionEnabled()){ + return (String)AccessController.doPrivileged(new PrivilegedAction(){ + public Object run(){ + return Localizer.getMessage(message); + } + }); + } else { + return Localizer.getMessage(message); + } + } + + /** + * Discard the output buffer. + */ + public final void clear() throws IOException { + if ((bufferSize == 0) && (out != null)) + // clear() is illegal after any unbuffered output (JSP.5.5) + throw new IllegalStateException( + getLocalizeMessage("jsp.error.ise_on_clear")); + if (flushed) + throw new IOException( + getLocalizeMessage("jsp.error.attempt_to_clear_flushed_buffer")); + ensureOpen(); + nextChar = 0; + } + + public void clearBuffer() throws IOException { + if (bufferSize == 0) + throw new IllegalStateException( + getLocalizeMessage("jsp.error.ise_on_clear")); + ensureOpen(); + nextChar = 0; + } + + private final void bufferOverflow() throws IOException { + throw new IOException(getLocalizeMessage("jsp.error.overflow")); + } + + /** + * Flush the stream. + * + */ + public void flush() throws IOException { + flushBuffer(); + if (out != null) { + out.flush(); + } + } + + /** + * Close the stream. + * + */ + public void close() throws IOException { + if (response == null || closed) + // multiple calls to close is OK + return; + flush(); + if (out != null) + out.close(); + out = null; + closed = true; + } + + /** + * @return the number of bytes unused in the buffer + */ + public int getRemaining() { + return bufferSize - nextChar; + } + + /** check to make sure that the stream has not been closed */ + private void ensureOpen() throws IOException { + if (response == null || closed) + throw new IOException("Stream closed"); + } + + + /** + * Write a single character. + */ + public void write(int c) throws IOException { + ensureOpen(); + if (bufferSize == 0) { + initOut(); + out.write(c); + } + else { + if (nextChar >= bufferSize) + if (autoFlush) + flushBuffer(); + else + bufferOverflow(); + cb[nextChar++] = (char) c; + } + } + + /** + * Our own little min method, to avoid loading java.lang.Math if we've run + * out of file descriptors and we're trying to print a stack trace. + */ + private int min(int a, int b) { + if (a < b) return a; + return b; + } + + /** + * Write a portion of an array of characters. + * + *

        Ordinarily this method stores characters from the given array into + * this stream's buffer, flushing the buffer to the underlying stream as + * needed. If the requested length is at least as large as the buffer, + * however, then this method will flush the buffer and write the characters + * directly to the underlying stream. Thus redundant + * DiscardableBufferedWriters will not copy data unnecessarily. + * + * @param cbuf A character array + * @param off Offset from which to start reading characters + * @param len Number of characters to write + */ + public void write(char cbuf[], int off, int len) + throws IOException + { + ensureOpen(); + + if (bufferSize == 0) { + initOut(); + out.write(cbuf, off, len); + return; + } + + if ((off < 0) || (off > cbuf.length) || (len < 0) || + ((off + len) > cbuf.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } else if (len == 0) { + return; + } + + if (len >= bufferSize) { + /* If the request length exceeds the size of the output buffer, + flush the buffer and then write the data directly. In this + way buffered streams will cascade harmlessly. */ + if (autoFlush) + flushBuffer(); + else + bufferOverflow(); + initOut(); + out.write(cbuf, off, len); + return; + } + + int b = off, t = off + len; + while (b < t) { + int d = min(bufferSize - nextChar, t - b); + System.arraycopy(cbuf, b, cb, nextChar, d); + b += d; + nextChar += d; + if (nextChar >= bufferSize) + if (autoFlush) + flushBuffer(); + else + bufferOverflow(); + } + + } + + /** + * Write an array of characters. This method cannot be inherited from the + * Writer class because it must suppress I/O exceptions. + */ + public void write(char buf[]) throws IOException { + write(buf, 0, buf.length); + } + + /** + * Write a portion of a String. + * + * @param s String to be written + * @param off Offset from which to start reading characters + * @param len Number of characters to be written + */ + public void write(String s, int off, int len) throws IOException { + ensureOpen(); + if (bufferSize == 0) { + initOut(); + out.write(s, off, len); + return; + } + int b = off, t = off + len; + while (b < t) { + int d = min(bufferSize - nextChar, t - b); + s.getChars(b, b + d, cb, nextChar); + b += d; + nextChar += d; + if (nextChar >= bufferSize) + if (autoFlush) + flushBuffer(); + else + bufferOverflow(); + } + } + + /** + * Write a string. This method cannot be inherited from the Writer class + * because it must suppress I/O exceptions. + */ + public void write(String s) throws IOException { + // Simple fix for Bugzilla 35410 + // Calling the other write function so as to init the buffer anyways + if(s == null) { + write(s, 0, 0); + } else { + write(s, 0, s.length()); + } + } + + + static String lineSeparator = System.getProperty("line.separator"); + + /** + * Write a line separator. The line separator string is defined by the + * system property line.separator, and is not necessarily a single + * newline ('\n') character. + * + * @exception IOException If an I/O error occurs + */ + + public void newLine() throws IOException { + write(lineSeparator); + } + + + /* Methods that do not terminate lines */ + + /** + * Print a boolean value. The string produced by {@link + * java.lang.String#valueOf(boolean)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param b The boolean to be printed + */ + public void print(boolean b) throws IOException { + write(b ? "true" : "false"); + } + + /** + * Print a character. The character is translated into one or more bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param c The char to be printed + */ + public void print(char c) throws IOException { + write(String.valueOf(c)); + } + + /** + * Print an integer. The string produced by {@link + * java.lang.String#valueOf(int)} is translated into bytes according + * to the platform's default character encoding, and these bytes are + * written in exactly the manner of the {@link #write(int)} + * method. + * + * @param i The int to be printed + */ + public void print(int i) throws IOException { + write(String.valueOf(i)); + } + + /** + * Print a long integer. The string produced by {@link + * java.lang.String#valueOf(long)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link #write(int)} + * method. + * + * @param l The long to be printed + */ + public void print(long l) throws IOException { + write(String.valueOf(l)); + } + + /** + * Print a floating-point number. The string produced by {@link + * java.lang.String#valueOf(float)} is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link #write(int)} + * method. + * + * @param f The float to be printed + */ + public void print(float f) throws IOException { + write(String.valueOf(f)); + } + + /** + * Print a double-precision floating-point number. The string produced by + * {@link java.lang.String#valueOf(double)} is translated into + * bytes according to the platform's default character encoding, and these + * bytes are written in exactly the manner of the {@link + * #write(int)} method. + * + * @param d The double to be printed + */ + public void print(double d) throws IOException { + write(String.valueOf(d)); + } + + /** + * Print an array of characters. The characters are converted into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link #write(int)} + * method. + * + * @param s The array of chars to be printed + * + * @throws NullPointerException If s is null + */ + public void print(char s[]) throws IOException { + write(s); + } + + /** + * Print a string. If the argument is null then the string + * "null" is printed. Otherwise, the string's characters are + * converted into bytes according to the platform's default character + * encoding, and these bytes are written in exactly the manner of the + * {@link #write(int)} method. + * + * @param s The String to be printed + */ + public void print(String s) throws IOException { + if (s == null) { + s = "null"; + } + write(s); + } + + /** + * Print an object. The string produced by the {@link + * java.lang.String#valueOf(Object)} method is translated into bytes + * according to the platform's default character encoding, and these bytes + * are written in exactly the manner of the {@link #write(int)} + * method. + * + * @param obj The Object to be printed + */ + public void print(Object obj) throws IOException { + write(String.valueOf(obj)); + } + + /* Methods that do terminate lines */ + + /** + * Terminate the current line by writing the line separator string. The + * line separator string is defined by the system property + * line.separator, and is not necessarily a single newline + * character ('\n'). + * + * Need to change this from PrintWriter because the default + * println() writes to the sink directly instead of through the + * write method... + */ + public void println() throws IOException { + newLine(); + } + + /** + * Print a boolean value and then terminate the line. This method behaves + * as though it invokes {@link #print(boolean)} and then + * {@link #println()}. + */ + public void println(boolean x) throws IOException { + print(x); + println(); + } + + /** + * Print a character and then terminate the line. This method behaves as + * though it invokes {@link #print(char)} and then {@link + * #println()}. + */ + public void println(char x) throws IOException { + print(x); + println(); + } + + /** + * Print an integer and then terminate the line. This method behaves as + * though it invokes {@link #print(int)} and then {@link + * #println()}. + */ + public void println(int x) throws IOException { + print(x); + println(); + } + + /** + * Print a long integer and then terminate the line. This method behaves + * as though it invokes {@link #print(long)} and then + * {@link #println()}. + */ + public void println(long x) throws IOException { + print(x); + println(); + } + + /** + * Print a floating-point number and then terminate the line. This method + * behaves as though it invokes {@link #print(float)} and then + * {@link #println()}. + */ + public void println(float x) throws IOException { + print(x); + println(); + } + + /** + * Print a double-precision floating-point number and then terminate the + * line. This method behaves as though it invokes {@link + * #print(double)} and then {@link #println()}. + */ + public void println(double x) throws IOException { + print(x); + println(); + } + + /** + * Print an array of characters and then terminate the line. This method + * behaves as though it invokes {@link #print(char[])} and then + * {@link #println()}. + */ + public void println(char x[]) throws IOException { + print(x); + println(); + } + + /** + * Print a String and then terminate the line. This method behaves as + * though it invokes {@link #print(String)} and then + * {@link #println()}. + */ + public void println(String x) throws IOException { + print(x); + println(); + } + + /** + * Print an Object and then terminate the line. This method behaves as + * though it invokes {@link #print(Object)} and then + * {@link #println()}. + */ + public void println(Object x) throws IOException { + print(x); + println(); + } + +} diff --git a/java/org/apache/jasper/runtime/PageContextImpl.java b/java/org/apache/jasper/runtime/PageContextImpl.java index 459953596..0a3baa3eb 100644 --- a/java/org/apache/jasper/runtime/PageContextImpl.java +++ b/java/org/apache/jasper/runtime/PageContextImpl.java @@ -1,964 +1,964 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.IOException; -import java.io.Writer; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedActionException; -import java.security.PrivilegedExceptionAction; -import java.util.Enumeration; -import java.util.Hashtable; - -import javax.el.ELContext; -import javax.el.ELResolver; -import javax.el.ExpressionFactory; -import javax.el.ValueExpression; -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.JspFactory; -import javax.servlet.jsp.JspWriter; -import javax.servlet.jsp.PageContext; -import javax.servlet.jsp.el.ELException; -import javax.servlet.jsp.el.ExpressionEvaluator; -import javax.servlet.jsp.el.VariableResolver; -import javax.servlet.jsp.tagext.BodyContent; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.el.ELContextImpl; -import org.apache.jasper.el.ExpressionEvaluatorImpl; -import org.apache.jasper.el.FunctionMapperImpl; -import org.apache.jasper.el.VariableResolverImpl; -import org.apache.jasper.security.SecurityUtil; - -/** - * Implementation of the PageContext class from the JSP spec. Also doubles as a - * VariableResolver for the EL. - * - * @author Anil K. Vijendran - * @author Larry Cable - * @author Hans Bergsten - * @author Pierre Delisle - * @author Mark Roth - * @author Jan Luehe - * @author Jacob Hookom - */ -public class PageContextImpl extends PageContext { - - // Logger - private static Log log = LogFactory.getLog(PageContextImpl.class); - - private BodyContentImpl[] outs; - - private int depth; - - // per-servlet state - private Servlet servlet; - - private ServletConfig config; - - private ServletContext context; - - private JspFactory factory; - - private JspApplicationContextImpl applicationContext; - - private boolean needsSession; - - private String errorPageURL; - - private boolean autoFlush; - - private int bufferSize; - - // page-scope attributes - private transient Hashtable attributes; - - // per-request state - private transient ServletRequest request; - - private transient ServletResponse response; - - private transient Object page; - - private transient HttpSession session; - - private transient ELContextImpl elContext; - - private boolean isIncluded; - - - // - - // initial output stream - private transient JspWriter out; - - private transient JspWriterImpl baseOut; - - /* - * Constructor. - */ - PageContextImpl(JspFactory factory) { - this.factory = factory; - this.outs = new BodyContentImpl[0]; - this.attributes = new Hashtable(16); - this.depth = -1; - } - - public void initialize(Servlet servlet, ServletRequest request, - ServletResponse response, String errorPageURL, - boolean needsSession, int bufferSize, boolean autoFlush) - throws IOException { - - _initialize(servlet, request, response, errorPageURL, needsSession, - bufferSize, autoFlush); - } - - private void _initialize(Servlet servlet, ServletRequest request, - ServletResponse response, String errorPageURL, - boolean needsSession, int bufferSize, boolean autoFlush) - throws IOException { - - // initialize state - this.servlet = servlet; - this.config = servlet.getServletConfig(); - this.context = config.getServletContext(); - this.needsSession = needsSession; - this.errorPageURL = errorPageURL; - this.bufferSize = bufferSize; - this.autoFlush = autoFlush; - this.request = request; - this.response = response; - - // initialize application context - this.applicationContext = JspApplicationContextImpl.getInstance(context); - - // Setup session (if required) - if (request instanceof HttpServletRequest && needsSession) - this.session = ((HttpServletRequest) request).getSession(); - if (needsSession && session == null) - throw new IllegalStateException( - "Page needs a session and none is available"); - - // initialize the initial out ... - depth = -1; - if (this.baseOut == null) { - this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush); - } else { - this.baseOut.init(response, bufferSize, autoFlush); - } - this.out = baseOut; - - // register names/values as per spec - setAttribute(OUT, this.out); - setAttribute(REQUEST, request); - setAttribute(RESPONSE, response); - - if (session != null) - setAttribute(SESSION, session); - - setAttribute(PAGE, servlet); - setAttribute(CONFIG, config); - setAttribute(PAGECONTEXT, this); - setAttribute(APPLICATION, context); - - isIncluded = request.getAttribute("javax.servlet.include.servlet_path") != null; - } - - public void release() { - out = baseOut; - try { - if (isIncluded) { - ((JspWriterImpl) out).flushBuffer(); - // push it into the including jspWriter - } else { - // Old code: - // out.flush(); - // Do not flush the buffer even if we're not included (i.e. - // we are the main page. The servlet will flush it and close - // the stream. - ((JspWriterImpl) out).flushBuffer(); - } - } catch (IOException ex) { - log.warn("Internal error flushing the buffer in release()"); - } - - servlet = null; - config = null; - context = null; - needsSession = false; - errorPageURL = null; - bufferSize = JspWriter.DEFAULT_BUFFER; - autoFlush = true; - request = null; - response = null; - depth = -1; - baseOut.recycle(); - session = null; - - attributes.clear(); - } - - public Object getAttribute(final String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return doGetAttribute(name); - } - }); - } else { - return doGetAttribute(name); - } - - } - - private Object doGetAttribute(String name) { - return attributes.get(name); - } - - public Object getAttribute(final String name, final int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - return doGetAttribute(name, scope); - } - }); - } else { - return doGetAttribute(name, scope); - } - - } - - private Object doGetAttribute(String name, int scope) { - switch (scope) { - case PAGE_SCOPE: - return attributes.get(name); - - case REQUEST_SCOPE: - return request.getAttribute(name); - - case SESSION_SCOPE: - if (session == null) { - throw new IllegalStateException(Localizer - .getMessage("jsp.error.page.noSession")); - } - return session.getAttribute(name); - - case APPLICATION_SCOPE: - return context.getAttribute(name); - - default: - throw new IllegalArgumentException("Invalid scope"); - } - } - - public void setAttribute(final String name, final Object attribute) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - doSetAttribute(name, attribute); - return null; - } - }); - } else { - doSetAttribute(name, attribute); - } - } - - private void doSetAttribute(String name, Object attribute) { - if (attribute != null) { - attributes.put(name, attribute); - } else { - removeAttribute(name, PAGE_SCOPE); - } - } - - public void setAttribute(final String name, final Object o, final int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - doSetAttribute(name, o, scope); - return null; - } - }); - } else { - doSetAttribute(name, o, scope); - } - - } - - private void doSetAttribute(String name, Object o, int scope) { - if (o != null) { - switch (scope) { - case PAGE_SCOPE: - attributes.put(name, o); - break; - - case REQUEST_SCOPE: - request.setAttribute(name, o); - break; - - case SESSION_SCOPE: - if (session == null) { - throw new IllegalStateException(Localizer - .getMessage("jsp.error.page.noSession")); - } - session.setAttribute(name, o); - break; - - case APPLICATION_SCOPE: - context.setAttribute(name, o); - break; - - default: - throw new IllegalArgumentException("Invalid scope"); - } - } else { - removeAttribute(name, scope); - } - } - - public void removeAttribute(final String name, final int scope) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - if (SecurityUtil.isPackageProtectionEnabled()) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - doRemoveAttribute(name, scope); - return null; - } - }); - } else { - doRemoveAttribute(name, scope); - } - } - - private void doRemoveAttribute(String name, int scope) { - switch (scope) { - case PAGE_SCOPE: - attributes.remove(name); - break; - - case REQUEST_SCOPE: - request.removeAttribute(name); - break; - - case SESSION_SCOPE: - if (session == null) { - throw new IllegalStateException(Localizer - .getMessage("jsp.error.page.noSession")); - } - session.removeAttribute(name); - break; - - case APPLICATION_SCOPE: - context.removeAttribute(name); - break; - - default: - throw new IllegalArgumentException("Invalid scope"); - } - } - - public int getAttributesScope(final String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - return ((Integer) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return new Integer(doGetAttributeScope(name)); - } - })).intValue(); - } else { - return doGetAttributeScope(name); - } - } - - private int doGetAttributeScope(String name) { - if (attributes.get(name) != null) - return PAGE_SCOPE; - - if (request.getAttribute(name) != null) - return REQUEST_SCOPE; - - if (session != null) { - if (session.getAttribute(name) != null) - return SESSION_SCOPE; - } - - if (context.getAttribute(name) != null) - return APPLICATION_SCOPE; - - return 0; - } - - public Object findAttribute(final String name) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - return doFindAttribute(name); - } - }); - } else { - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - return doFindAttribute(name); - } - } - - private Object doFindAttribute(String name) { - - Object o = attributes.get(name); - if (o != null) - return o; - - o = request.getAttribute(name); - if (o != null) - return o; - - if (session != null) { - o = session.getAttribute(name); - if (o != null) - return o; - } - - return context.getAttribute(name); - } - - public Enumeration getAttributeNamesInScope(final int scope) { - if (SecurityUtil.isPackageProtectionEnabled()) { - return (Enumeration) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return doGetAttributeNamesInScope(scope); - } - }); - } else { - return doGetAttributeNamesInScope(scope); - } - } - - private Enumeration doGetAttributeNamesInScope(int scope) { - switch (scope) { - case PAGE_SCOPE: - return attributes.keys(); - - case REQUEST_SCOPE: - return request.getAttributeNames(); - - case SESSION_SCOPE: - if (session == null) { - throw new IllegalStateException(Localizer - .getMessage("jsp.error.page.noSession")); - } - return session.getAttributeNames(); - - case APPLICATION_SCOPE: - return context.getAttributeNames(); - - default: - throw new IllegalArgumentException("Invalid scope"); - } - } - - public void removeAttribute(final String name) { - - if (name == null) { - throw new NullPointerException(Localizer - .getMessage("jsp.error.attribute.null_name")); - } - - if (SecurityUtil.isPackageProtectionEnabled()) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - doRemoveAttribute(name); - return null; - } - }); - } else { - doRemoveAttribute(name); - } - } - - private void doRemoveAttribute(String name) { - try { - removeAttribute(name, PAGE_SCOPE); - removeAttribute(name, REQUEST_SCOPE); - if (session != null) { - removeAttribute(name, SESSION_SCOPE); - } - removeAttribute(name, APPLICATION_SCOPE); - } catch (Exception ex) { - // we remove as much as we can, and - // simply ignore possible exceptions - } - } - - public JspWriter getOut() { - return out; - } - - public HttpSession getSession() { - return session; - } - - public Servlet getServlet() { - return servlet; - } - - public ServletConfig getServletConfig() { - return config; - } - - public ServletContext getServletContext() { - return config.getServletContext(); - } - - public ServletRequest getRequest() { - return request; - } - - public ServletResponse getResponse() { - return response; - } - - /** - * Returns the exception associated with this page context, if any.

        - * Added wrapping for Throwables to avoid ClassCastException: see Bugzilla - * 31171 for details. - * - * @return The Exception associated with this page context, if any. - */ - public Exception getException() { - Throwable t = JspRuntimeLibrary.getThrowable(request); - - // Only wrap if needed - if ((t != null) && (!(t instanceof Exception))) { - t = new JspException(t); - } - - return (Exception) t; - } - - public Object getPage() { - return servlet; - } - - private final String getAbsolutePathRelativeToContext(String relativeUrlPath) { - String path = relativeUrlPath; - - if (!path.startsWith("/")) { - String uri = (String) request - .getAttribute("javax.servlet.include.servlet_path"); - if (uri == null) - uri = ((HttpServletRequest) request).getServletPath(); - String baseURI = uri.substring(0, uri.lastIndexOf('/')); - path = baseURI + '/' + path; - } - - return path; - } - - public void include(String relativeUrlPath) throws ServletException, - IOException { - JspRuntimeLibrary - .include(request, response, relativeUrlPath, out, true); - } - - public void include(final String relativeUrlPath, final boolean flush) - throws ServletException, IOException { - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - doInclude(relativeUrlPath, flush); - return null; - } - }); - } catch (PrivilegedActionException e) { - Exception ex = e.getException(); - if (ex instanceof IOException) { - throw (IOException) ex; - } else { - throw (ServletException) ex; - } - } - } else { - doInclude(relativeUrlPath, flush); - } - } - - private void doInclude(String relativeUrlPath, boolean flush) - throws ServletException, IOException { - JspRuntimeLibrary.include(request, response, relativeUrlPath, out, - flush); - } - - public VariableResolver getVariableResolver() { - return new VariableResolverImpl(this.getELContext()); - } - - public void forward(final String relativeUrlPath) throws ServletException, - IOException { - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - doForward(relativeUrlPath); - return null; - } - }); - } catch (PrivilegedActionException e) { - Exception ex = e.getException(); - if (ex instanceof IOException) { - throw (IOException) ex; - } else { - throw (ServletException) ex; - } - } - } else { - doForward(relativeUrlPath); - } - } - - private void doForward(String relativeUrlPath) throws ServletException, - IOException { - - // JSP.4.5 If the buffer was flushed, throw IllegalStateException - try { - out.clear(); - } catch (IOException ex) { - IllegalStateException ise = new IllegalStateException(Localizer - .getMessage("jsp.error.attempt_to_clear_flushed_buffer")); - ise.initCause(ex); - throw ise; - } - - // Make sure that the response object is not the wrapper for include - while (response instanceof ServletResponseWrapperInclude) { - response = ((ServletResponseWrapperInclude) response).getResponse(); - } - - final String path = getAbsolutePathRelativeToContext(relativeUrlPath); - String includeUri = (String) request - .getAttribute(Constants.INC_SERVLET_PATH); - - final ServletResponse fresponse = response; - final ServletRequest frequest = request; - - if (includeUri != null) - request.removeAttribute(Constants.INC_SERVLET_PATH); - try { - context.getRequestDispatcher(path).forward(request, response); - } finally { - if (includeUri != null) - request.setAttribute(Constants.INC_SERVLET_PATH, includeUri); - request.setAttribute(Constants.FORWARD_SEEN, "true"); - } - } - - public BodyContent pushBody() { - return (BodyContent) pushBody(null); - } - - public JspWriter pushBody(Writer writer) { - depth++; - if (depth >= outs.length) { - BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1]; - for (int i = 0; i < outs.length; i++) { - newOuts[i] = outs[i]; - } - newOuts[depth] = new BodyContentImpl(out); - outs = newOuts; - } - - outs[depth].setWriter(writer); - out = outs[depth]; - - // Update the value of the "out" attribute in the page scope - // attribute namespace of this PageContext - setAttribute(OUT, out); - - return outs[depth]; - } - - public JspWriter popBody() { - depth--; - if (depth >= 0) { - out = outs[depth]; - } else { - out = baseOut; - } - - // Update the value of the "out" attribute in the page scope - // attribute namespace of this PageContext - setAttribute(OUT, out); - - return out; - } - - /** - * Provides programmatic access to the ExpressionEvaluator. The JSP - * Container must return a valid instance of an ExpressionEvaluator that can - * parse EL expressions. - */ - public ExpressionEvaluator getExpressionEvaluator() { - return new ExpressionEvaluatorImpl(this.applicationContext.getExpressionFactory()); - } - - public void handlePageException(Exception ex) throws IOException, - ServletException { - // Should never be called since handleException() called with a - // Throwable in the generated servlet. - handlePageException((Throwable) ex); - } - - public void handlePageException(final Throwable t) throws IOException, - ServletException { - if (t == null) - throw new NullPointerException("null Throwable"); - - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - doHandlePageException(t); - return null; - } - }); - } catch (PrivilegedActionException e) { - Exception ex = e.getException(); - if (ex instanceof IOException) { - throw (IOException) ex; - } else { - throw (ServletException) ex; - } - } - } else { - doHandlePageException(t); - } - - } - - private void doHandlePageException(Throwable t) throws IOException, - ServletException { - - if (errorPageURL != null && !errorPageURL.equals("")) { - - /* - * Set request attributes. Do not set the - * javax.servlet.error.exception attribute here (instead, set in the - * generated servlet code for the error page) in order to prevent - * the ErrorReportValve, which is invoked as part of forwarding the - * request to the error page, from throwing it if the response has - * not been committed (the response will have been committed if the - * error page is a JSP page). - */ - request.setAttribute("javax.servlet.jsp.jspException", t); - request.setAttribute("javax.servlet.error.status_code", - new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); - request.setAttribute("javax.servlet.error.request_uri", - ((HttpServletRequest) request).getRequestURI()); - request.setAttribute("javax.servlet.error.servlet_name", config - .getServletName()); - try { - forward(errorPageURL); - } catch (IllegalStateException ise) { - include(errorPageURL); - } - - // The error page could be inside an include. - - Object newException = request - .getAttribute("javax.servlet.error.exception"); - - // t==null means the attribute was not set. - if ((newException != null) && (newException == t)) { - request.removeAttribute("javax.servlet.error.exception"); - } - - // now clear the error code - to prevent double handling. - request.removeAttribute("javax.servlet.error.status_code"); - request.removeAttribute("javax.servlet.error.request_uri"); - request.removeAttribute("javax.servlet.error.status_code"); - request.removeAttribute("javax.servlet.jsp.jspException"); - - } else { - // Otherwise throw the exception wrapped inside a ServletException. - // Set the exception as the root cause in the ServletException - // to get a stack trace for the real problem - if (t instanceof IOException) - throw (IOException) t; - if (t instanceof ServletException) - throw (ServletException) t; - if (t instanceof RuntimeException) - throw (RuntimeException) t; - - Throwable rootCause = null; - if (t instanceof JspException) { - rootCause = ((JspException) t).getRootCause(); - } else if (t instanceof ELException) { - rootCause = ((ELException) t).getRootCause(); - } - - if (rootCause != null) { - throw new ServletException(t.getClass().getName() + ": " - + t.getMessage(), rootCause); - } - - throw new ServletException(t); - } - } - - private static String XmlEscape(String s) { - if (s == null) - return null; - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '<') { - sb.append("<"); - } else if (c == '>') { - sb.append(">"); - } else if (c == '\'') { - sb.append("'"); // ' - } else if (c == '&') { - sb.append("&"); - } else if (c == '"') { - sb.append("""); // " - } else { - sb.append(c); - } - } - return sb.toString(); - } - - /** - * Proprietary method to evaluate EL expressions. XXX - This method should - * go away once the EL interpreter moves out of JSTL and into its own - * project. For now, this is necessary because the standard machinery is too - * slow. - * - * @param expression - * The expression to be evaluated - * @param expectedType - * The expected resulting type - * @param pageContext - * The page context - * @param functionMap - * Maps prefix and name to Method - * @return The result of the evaluation - */ - public static Object proprietaryEvaluate(final String expression, - final Class expectedType, final PageContext pageContext, - final ProtectedFunctionMapper functionMap, final boolean escape) - throws ELException { - Object retValue; - final ExpressionFactory exprFactory = JspFactory.getDefaultFactory().getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory(); - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - retValue = AccessController - .doPrivileged(new PrivilegedExceptionAction() { - - public Object run() throws Exception { - ELContextImpl ctx = (ELContextImpl) pageContext.getELContext(); - ctx.setFunctionMapper(new FunctionMapperImpl(functionMap)); - ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType); - return ve.getValue(ctx); - } - }); - } catch (PrivilegedActionException ex) { - Exception realEx = ex.getException(); - if (realEx instanceof ELException) { - throw (ELException) realEx; - } else { - throw new ELException(realEx); - } - } - } else { - ELContextImpl ctx = (ELContextImpl) pageContext.getELContext(); - ctx.setFunctionMapper(new FunctionMapperImpl(functionMap)); - ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType); - retValue = ve.getValue(ctx); - } - if (escape && retValue != null) { - retValue = XmlEscape(retValue.toString()); - } - - return retValue; - } - - public ELContext getELContext() { - if (this.elContext == null) { - this.elContext = this.applicationContext.createELContext(this); - } - return this.elContext; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.IOException; +import java.io.Writer; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.util.Enumeration; +import java.util.Hashtable; + +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.ExpressionFactory; +import javax.el.ValueExpression; +import javax.servlet.Servlet; +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspFactory; +import javax.servlet.jsp.JspWriter; +import javax.servlet.jsp.PageContext; +import javax.servlet.jsp.el.ELException; +import javax.servlet.jsp.el.ExpressionEvaluator; +import javax.servlet.jsp.el.VariableResolver; +import javax.servlet.jsp.tagext.BodyContent; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.compiler.Localizer; +import org.apache.jasper.el.ELContextImpl; +import org.apache.jasper.el.ExpressionEvaluatorImpl; +import org.apache.jasper.el.FunctionMapperImpl; +import org.apache.jasper.el.VariableResolverImpl; +import org.apache.jasper.security.SecurityUtil; + +/** + * Implementation of the PageContext class from the JSP spec. Also doubles as a + * VariableResolver for the EL. + * + * @author Anil K. Vijendran + * @author Larry Cable + * @author Hans Bergsten + * @author Pierre Delisle + * @author Mark Roth + * @author Jan Luehe + * @author Jacob Hookom + */ +public class PageContextImpl extends PageContext { + + // Logger + private static Log log = LogFactory.getLog(PageContextImpl.class); + + private BodyContentImpl[] outs; + + private int depth; + + // per-servlet state + private Servlet servlet; + + private ServletConfig config; + + private ServletContext context; + + private JspFactory factory; + + private JspApplicationContextImpl applicationContext; + + private boolean needsSession; + + private String errorPageURL; + + private boolean autoFlush; + + private int bufferSize; + + // page-scope attributes + private transient Hashtable attributes; + + // per-request state + private transient ServletRequest request; + + private transient ServletResponse response; + + private transient Object page; + + private transient HttpSession session; + + private transient ELContextImpl elContext; + + private boolean isIncluded; + + + // + + // initial output stream + private transient JspWriter out; + + private transient JspWriterImpl baseOut; + + /* + * Constructor. + */ + PageContextImpl(JspFactory factory) { + this.factory = factory; + this.outs = new BodyContentImpl[0]; + this.attributes = new Hashtable(16); + this.depth = -1; + } + + public void initialize(Servlet servlet, ServletRequest request, + ServletResponse response, String errorPageURL, + boolean needsSession, int bufferSize, boolean autoFlush) + throws IOException { + + _initialize(servlet, request, response, errorPageURL, needsSession, + bufferSize, autoFlush); + } + + private void _initialize(Servlet servlet, ServletRequest request, + ServletResponse response, String errorPageURL, + boolean needsSession, int bufferSize, boolean autoFlush) + throws IOException { + + // initialize state + this.servlet = servlet; + this.config = servlet.getServletConfig(); + this.context = config.getServletContext(); + this.needsSession = needsSession; + this.errorPageURL = errorPageURL; + this.bufferSize = bufferSize; + this.autoFlush = autoFlush; + this.request = request; + this.response = response; + + // initialize application context + this.applicationContext = JspApplicationContextImpl.getInstance(context); + + // Setup session (if required) + if (request instanceof HttpServletRequest && needsSession) + this.session = ((HttpServletRequest) request).getSession(); + if (needsSession && session == null) + throw new IllegalStateException( + "Page needs a session and none is available"); + + // initialize the initial out ... + depth = -1; + if (this.baseOut == null) { + this.baseOut = new JspWriterImpl(response, bufferSize, autoFlush); + } else { + this.baseOut.init(response, bufferSize, autoFlush); + } + this.out = baseOut; + + // register names/values as per spec + setAttribute(OUT, this.out); + setAttribute(REQUEST, request); + setAttribute(RESPONSE, response); + + if (session != null) + setAttribute(SESSION, session); + + setAttribute(PAGE, servlet); + setAttribute(CONFIG, config); + setAttribute(PAGECONTEXT, this); + setAttribute(APPLICATION, context); + + isIncluded = request.getAttribute("javax.servlet.include.servlet_path") != null; + } + + public void release() { + out = baseOut; + try { + if (isIncluded) { + ((JspWriterImpl) out).flushBuffer(); + // push it into the including jspWriter + } else { + // Old code: + // out.flush(); + // Do not flush the buffer even if we're not included (i.e. + // we are the main page. The servlet will flush it and close + // the stream. + ((JspWriterImpl) out).flushBuffer(); + } + } catch (IOException ex) { + log.warn("Internal error flushing the buffer in release()"); + } + + servlet = null; + config = null; + context = null; + needsSession = false; + errorPageURL = null; + bufferSize = JspWriter.DEFAULT_BUFFER; + autoFlush = true; + request = null; + response = null; + depth = -1; + baseOut.recycle(); + session = null; + + attributes.clear(); + } + + public Object getAttribute(final String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return doGetAttribute(name); + } + }); + } else { + return doGetAttribute(name); + } + + } + + private Object doGetAttribute(String name) { + return attributes.get(name); + } + + public Object getAttribute(final String name, final int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + return doGetAttribute(name, scope); + } + }); + } else { + return doGetAttribute(name, scope); + } + + } + + private Object doGetAttribute(String name, int scope) { + switch (scope) { + case PAGE_SCOPE: + return attributes.get(name); + + case REQUEST_SCOPE: + return request.getAttribute(name); + + case SESSION_SCOPE: + if (session == null) { + throw new IllegalStateException(Localizer + .getMessage("jsp.error.page.noSession")); + } + return session.getAttribute(name); + + case APPLICATION_SCOPE: + return context.getAttribute(name); + + default: + throw new IllegalArgumentException("Invalid scope"); + } + } + + public void setAttribute(final String name, final Object attribute) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + doSetAttribute(name, attribute); + return null; + } + }); + } else { + doSetAttribute(name, attribute); + } + } + + private void doSetAttribute(String name, Object attribute) { + if (attribute != null) { + attributes.put(name, attribute); + } else { + removeAttribute(name, PAGE_SCOPE); + } + } + + public void setAttribute(final String name, final Object o, final int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + doSetAttribute(name, o, scope); + return null; + } + }); + } else { + doSetAttribute(name, o, scope); + } + + } + + private void doSetAttribute(String name, Object o, int scope) { + if (o != null) { + switch (scope) { + case PAGE_SCOPE: + attributes.put(name, o); + break; + + case REQUEST_SCOPE: + request.setAttribute(name, o); + break; + + case SESSION_SCOPE: + if (session == null) { + throw new IllegalStateException(Localizer + .getMessage("jsp.error.page.noSession")); + } + session.setAttribute(name, o); + break; + + case APPLICATION_SCOPE: + context.setAttribute(name, o); + break; + + default: + throw new IllegalArgumentException("Invalid scope"); + } + } else { + removeAttribute(name, scope); + } + } + + public void removeAttribute(final String name, final int scope) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + if (SecurityUtil.isPackageProtectionEnabled()) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + doRemoveAttribute(name, scope); + return null; + } + }); + } else { + doRemoveAttribute(name, scope); + } + } + + private void doRemoveAttribute(String name, int scope) { + switch (scope) { + case PAGE_SCOPE: + attributes.remove(name); + break; + + case REQUEST_SCOPE: + request.removeAttribute(name); + break; + + case SESSION_SCOPE: + if (session == null) { + throw new IllegalStateException(Localizer + .getMessage("jsp.error.page.noSession")); + } + session.removeAttribute(name); + break; + + case APPLICATION_SCOPE: + context.removeAttribute(name); + break; + + default: + throw new IllegalArgumentException("Invalid scope"); + } + } + + public int getAttributesScope(final String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + return ((Integer) AccessController + .doPrivileged(new PrivilegedAction() { + public Object run() { + return new Integer(doGetAttributeScope(name)); + } + })).intValue(); + } else { + return doGetAttributeScope(name); + } + } + + private int doGetAttributeScope(String name) { + if (attributes.get(name) != null) + return PAGE_SCOPE; + + if (request.getAttribute(name) != null) + return REQUEST_SCOPE; + + if (session != null) { + if (session.getAttribute(name) != null) + return SESSION_SCOPE; + } + + if (context.getAttribute(name) != null) + return APPLICATION_SCOPE; + + return 0; + } + + public Object findAttribute(final String name) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + return doFindAttribute(name); + } + }); + } else { + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + return doFindAttribute(name); + } + } + + private Object doFindAttribute(String name) { + + Object o = attributes.get(name); + if (o != null) + return o; + + o = request.getAttribute(name); + if (o != null) + return o; + + if (session != null) { + o = session.getAttribute(name); + if (o != null) + return o; + } + + return context.getAttribute(name); + } + + public Enumeration getAttributeNamesInScope(final int scope) { + if (SecurityUtil.isPackageProtectionEnabled()) { + return (Enumeration) AccessController + .doPrivileged(new PrivilegedAction() { + public Object run() { + return doGetAttributeNamesInScope(scope); + } + }); + } else { + return doGetAttributeNamesInScope(scope); + } + } + + private Enumeration doGetAttributeNamesInScope(int scope) { + switch (scope) { + case PAGE_SCOPE: + return attributes.keys(); + + case REQUEST_SCOPE: + return request.getAttributeNames(); + + case SESSION_SCOPE: + if (session == null) { + throw new IllegalStateException(Localizer + .getMessage("jsp.error.page.noSession")); + } + return session.getAttributeNames(); + + case APPLICATION_SCOPE: + return context.getAttributeNames(); + + default: + throw new IllegalArgumentException("Invalid scope"); + } + } + + public void removeAttribute(final String name) { + + if (name == null) { + throw new NullPointerException(Localizer + .getMessage("jsp.error.attribute.null_name")); + } + + if (SecurityUtil.isPackageProtectionEnabled()) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + doRemoveAttribute(name); + return null; + } + }); + } else { + doRemoveAttribute(name); + } + } + + private void doRemoveAttribute(String name) { + try { + removeAttribute(name, PAGE_SCOPE); + removeAttribute(name, REQUEST_SCOPE); + if (session != null) { + removeAttribute(name, SESSION_SCOPE); + } + removeAttribute(name, APPLICATION_SCOPE); + } catch (Exception ex) { + // we remove as much as we can, and + // simply ignore possible exceptions + } + } + + public JspWriter getOut() { + return out; + } + + public HttpSession getSession() { + return session; + } + + public Servlet getServlet() { + return servlet; + } + + public ServletConfig getServletConfig() { + return config; + } + + public ServletContext getServletContext() { + return config.getServletContext(); + } + + public ServletRequest getRequest() { + return request; + } + + public ServletResponse getResponse() { + return response; + } + + /** + * Returns the exception associated with this page context, if any.

        + * Added wrapping for Throwables to avoid ClassCastException: see Bugzilla + * 31171 for details. + * + * @return The Exception associated with this page context, if any. + */ + public Exception getException() { + Throwable t = JspRuntimeLibrary.getThrowable(request); + + // Only wrap if needed + if ((t != null) && (!(t instanceof Exception))) { + t = new JspException(t); + } + + return (Exception) t; + } + + public Object getPage() { + return servlet; + } + + private final String getAbsolutePathRelativeToContext(String relativeUrlPath) { + String path = relativeUrlPath; + + if (!path.startsWith("/")) { + String uri = (String) request + .getAttribute("javax.servlet.include.servlet_path"); + if (uri == null) + uri = ((HttpServletRequest) request).getServletPath(); + String baseURI = uri.substring(0, uri.lastIndexOf('/')); + path = baseURI + '/' + path; + } + + return path; + } + + public void include(String relativeUrlPath) throws ServletException, + IOException { + JspRuntimeLibrary + .include(request, response, relativeUrlPath, out, true); + } + + public void include(final String relativeUrlPath, final boolean flush) + throws ServletException, IOException { + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + doInclude(relativeUrlPath, flush); + return null; + } + }); + } catch (PrivilegedActionException e) { + Exception ex = e.getException(); + if (ex instanceof IOException) { + throw (IOException) ex; + } else { + throw (ServletException) ex; + } + } + } else { + doInclude(relativeUrlPath, flush); + } + } + + private void doInclude(String relativeUrlPath, boolean flush) + throws ServletException, IOException { + JspRuntimeLibrary.include(request, response, relativeUrlPath, out, + flush); + } + + public VariableResolver getVariableResolver() { + return new VariableResolverImpl(this.getELContext()); + } + + public void forward(final String relativeUrlPath) throws ServletException, + IOException { + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + doForward(relativeUrlPath); + return null; + } + }); + } catch (PrivilegedActionException e) { + Exception ex = e.getException(); + if (ex instanceof IOException) { + throw (IOException) ex; + } else { + throw (ServletException) ex; + } + } + } else { + doForward(relativeUrlPath); + } + } + + private void doForward(String relativeUrlPath) throws ServletException, + IOException { + + // JSP.4.5 If the buffer was flushed, throw IllegalStateException + try { + out.clear(); + } catch (IOException ex) { + IllegalStateException ise = new IllegalStateException(Localizer + .getMessage("jsp.error.attempt_to_clear_flushed_buffer")); + ise.initCause(ex); + throw ise; + } + + // Make sure that the response object is not the wrapper for include + while (response instanceof ServletResponseWrapperInclude) { + response = ((ServletResponseWrapperInclude) response).getResponse(); + } + + final String path = getAbsolutePathRelativeToContext(relativeUrlPath); + String includeUri = (String) request + .getAttribute(Constants.INC_SERVLET_PATH); + + final ServletResponse fresponse = response; + final ServletRequest frequest = request; + + if (includeUri != null) + request.removeAttribute(Constants.INC_SERVLET_PATH); + try { + context.getRequestDispatcher(path).forward(request, response); + } finally { + if (includeUri != null) + request.setAttribute(Constants.INC_SERVLET_PATH, includeUri); + request.setAttribute(Constants.FORWARD_SEEN, "true"); + } + } + + public BodyContent pushBody() { + return (BodyContent) pushBody(null); + } + + public JspWriter pushBody(Writer writer) { + depth++; + if (depth >= outs.length) { + BodyContentImpl[] newOuts = new BodyContentImpl[depth + 1]; + for (int i = 0; i < outs.length; i++) { + newOuts[i] = outs[i]; + } + newOuts[depth] = new BodyContentImpl(out); + outs = newOuts; + } + + outs[depth].setWriter(writer); + out = outs[depth]; + + // Update the value of the "out" attribute in the page scope + // attribute namespace of this PageContext + setAttribute(OUT, out); + + return outs[depth]; + } + + public JspWriter popBody() { + depth--; + if (depth >= 0) { + out = outs[depth]; + } else { + out = baseOut; + } + + // Update the value of the "out" attribute in the page scope + // attribute namespace of this PageContext + setAttribute(OUT, out); + + return out; + } + + /** + * Provides programmatic access to the ExpressionEvaluator. The JSP + * Container must return a valid instance of an ExpressionEvaluator that can + * parse EL expressions. + */ + public ExpressionEvaluator getExpressionEvaluator() { + return new ExpressionEvaluatorImpl(this.applicationContext.getExpressionFactory()); + } + + public void handlePageException(Exception ex) throws IOException, + ServletException { + // Should never be called since handleException() called with a + // Throwable in the generated servlet. + handlePageException((Throwable) ex); + } + + public void handlePageException(final Throwable t) throws IOException, + ServletException { + if (t == null) + throw new NullPointerException("null Throwable"); + + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + AccessController.doPrivileged(new PrivilegedExceptionAction() { + public Object run() throws Exception { + doHandlePageException(t); + return null; + } + }); + } catch (PrivilegedActionException e) { + Exception ex = e.getException(); + if (ex instanceof IOException) { + throw (IOException) ex; + } else { + throw (ServletException) ex; + } + } + } else { + doHandlePageException(t); + } + + } + + private void doHandlePageException(Throwable t) throws IOException, + ServletException { + + if (errorPageURL != null && !errorPageURL.equals("")) { + + /* + * Set request attributes. Do not set the + * javax.servlet.error.exception attribute here (instead, set in the + * generated servlet code for the error page) in order to prevent + * the ErrorReportValve, which is invoked as part of forwarding the + * request to the error page, from throwing it if the response has + * not been committed (the response will have been committed if the + * error page is a JSP page). + */ + request.setAttribute("javax.servlet.jsp.jspException", t); + request.setAttribute("javax.servlet.error.status_code", + new Integer(HttpServletResponse.SC_INTERNAL_SERVER_ERROR)); + request.setAttribute("javax.servlet.error.request_uri", + ((HttpServletRequest) request).getRequestURI()); + request.setAttribute("javax.servlet.error.servlet_name", config + .getServletName()); + try { + forward(errorPageURL); + } catch (IllegalStateException ise) { + include(errorPageURL); + } + + // The error page could be inside an include. + + Object newException = request + .getAttribute("javax.servlet.error.exception"); + + // t==null means the attribute was not set. + if ((newException != null) && (newException == t)) { + request.removeAttribute("javax.servlet.error.exception"); + } + + // now clear the error code - to prevent double handling. + request.removeAttribute("javax.servlet.error.status_code"); + request.removeAttribute("javax.servlet.error.request_uri"); + request.removeAttribute("javax.servlet.error.status_code"); + request.removeAttribute("javax.servlet.jsp.jspException"); + + } else { + // Otherwise throw the exception wrapped inside a ServletException. + // Set the exception as the root cause in the ServletException + // to get a stack trace for the real problem + if (t instanceof IOException) + throw (IOException) t; + if (t instanceof ServletException) + throw (ServletException) t; + if (t instanceof RuntimeException) + throw (RuntimeException) t; + + Throwable rootCause = null; + if (t instanceof JspException) { + rootCause = ((JspException) t).getRootCause(); + } else if (t instanceof ELException) { + rootCause = ((ELException) t).getRootCause(); + } + + if (rootCause != null) { + throw new ServletException(t.getClass().getName() + ": " + + t.getMessage(), rootCause); + } + + throw new ServletException(t); + } + } + + private static String XmlEscape(String s) { + if (s == null) + return null; + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '<') { + sb.append("<"); + } else if (c == '>') { + sb.append(">"); + } else if (c == '\'') { + sb.append("'"); // ' + } else if (c == '&') { + sb.append("&"); + } else if (c == '"') { + sb.append("""); // " + } else { + sb.append(c); + } + } + return sb.toString(); + } + + /** + * Proprietary method to evaluate EL expressions. XXX - This method should + * go away once the EL interpreter moves out of JSTL and into its own + * project. For now, this is necessary because the standard machinery is too + * slow. + * + * @param expression + * The expression to be evaluated + * @param expectedType + * The expected resulting type + * @param pageContext + * The page context + * @param functionMap + * Maps prefix and name to Method + * @return The result of the evaluation + */ + public static Object proprietaryEvaluate(final String expression, + final Class expectedType, final PageContext pageContext, + final ProtectedFunctionMapper functionMap, final boolean escape) + throws ELException { + Object retValue; + final ExpressionFactory exprFactory = JspFactory.getDefaultFactory().getJspApplicationContext(pageContext.getServletContext()).getExpressionFactory(); + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + retValue = AccessController + .doPrivileged(new PrivilegedExceptionAction() { + + public Object run() throws Exception { + ELContextImpl ctx = (ELContextImpl) pageContext.getELContext(); + ctx.setFunctionMapper(new FunctionMapperImpl(functionMap)); + ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType); + return ve.getValue(ctx); + } + }); + } catch (PrivilegedActionException ex) { + Exception realEx = ex.getException(); + if (realEx instanceof ELException) { + throw (ELException) realEx; + } else { + throw new ELException(realEx); + } + } + } else { + ELContextImpl ctx = (ELContextImpl) pageContext.getELContext(); + ctx.setFunctionMapper(new FunctionMapperImpl(functionMap)); + ValueExpression ve = exprFactory.createValueExpression(ctx, expression, expectedType); + retValue = ve.getValue(ctx); + } + if (escape && retValue != null) { + retValue = XmlEscape(retValue.toString()); + } + + return retValue; + } + + public ELContext getELContext() { + if (this.elContext == null) { + this.elContext = this.applicationContext.createELContext(this); + } + return this.elContext; + } + +} diff --git a/java/org/apache/jasper/runtime/PerThreadTagHandlerPool.java b/java/org/apache/jasper/runtime/PerThreadTagHandlerPool.java index 616290297..94b7a5c3c 100644 --- a/java/org/apache/jasper/runtime/PerThreadTagHandlerPool.java +++ b/java/org/apache/jasper/runtime/PerThreadTagHandlerPool.java @@ -1,133 +1,133 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.util.Enumeration; -import java.util.Vector; - -import javax.servlet.ServletConfig; -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.tagext.Tag; - -import org.apache.jasper.Constants; - -/** - * Thread-local based pool of tag handlers that can be reused. - * - * @author Jan Luehe - * @author Costin Manolache - */ -public class PerThreadTagHandlerPool extends TagHandlerPool { - - private int maxSize; - - // For cleanup - private Vector perThreadDataVector; - - private ThreadLocal perThread; - - private static class PerThreadData { - Tag handlers[]; - int current; - } - - /** - * Constructs a tag handler pool with the default capacity. - */ - public PerThreadTagHandlerPool() { - super(); - perThreadDataVector = new Vector(); - } - - protected void init(ServletConfig config) { - maxSize = Constants.MAX_POOL_SIZE; - String maxSizeS = getOption(config, OPTION_MAXSIZE, null); - if (maxSizeS != null) { - maxSize = Integer.parseInt(maxSizeS); - if (maxSize < 0) { - maxSize = Constants.MAX_POOL_SIZE; - } - } - - perThread = new ThreadLocal() { - protected Object initialValue() { - PerThreadData ptd = new PerThreadData(); - ptd.handlers = new Tag[maxSize]; - ptd.current = -1; - perThreadDataVector.addElement(ptd); - return ptd; - } - }; - } - - /** - * Gets the next available tag handler from this tag handler pool, - * instantiating one if this tag handler pool is empty. - * - * @param handlerClass Tag handler class - * - * @return Reused or newly instantiated tag handler - * - * @throws JspException if a tag handler cannot be instantiated - */ - public Tag get(Class handlerClass) throws JspException { - PerThreadData ptd = (PerThreadData)perThread.get(); - if(ptd.current >=0 ) { - return ptd.handlers[ptd.current--]; - } else { - try { - return (Tag) handlerClass.newInstance(); - } catch (Exception e) { - throw new JspException(e.getMessage(), e); - } - } - } - - /** - * Adds the given tag handler to this tag handler pool, unless this tag - * handler pool has already reached its capacity, in which case the tag - * handler's release() method is called. - * - * @param handler Tag handler to add to this tag handler pool - */ - public void reuse(Tag handler) { - PerThreadData ptd=(PerThreadData)perThread.get(); - if (ptd.current < (ptd.handlers.length - 1)) { - ptd.handlers[++ptd.current] = handler; - } else { - handler.release(); - } - } - - /** - * Calls the release() method of all tag handlers in this tag handler pool. - */ - public void release() { - Enumeration enumeration = perThreadDataVector.elements(); - while (enumeration.hasMoreElements()) { - PerThreadData ptd = (PerThreadData)enumeration.nextElement(); - if (ptd.handlers != null) { - for (int i=ptd.current; i>=0; i--) { - if (ptd.handlers[i] != null) { - ptd.handlers[i].release(); - } - } - } - } - } -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.util.Enumeration; +import java.util.Vector; + +import javax.servlet.ServletConfig; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.tagext.Tag; + +import org.apache.jasper.Constants; + +/** + * Thread-local based pool of tag handlers that can be reused. + * + * @author Jan Luehe + * @author Costin Manolache + */ +public class PerThreadTagHandlerPool extends TagHandlerPool { + + private int maxSize; + + // For cleanup + private Vector perThreadDataVector; + + private ThreadLocal perThread; + + private static class PerThreadData { + Tag handlers[]; + int current; + } + + /** + * Constructs a tag handler pool with the default capacity. + */ + public PerThreadTagHandlerPool() { + super(); + perThreadDataVector = new Vector(); + } + + protected void init(ServletConfig config) { + maxSize = Constants.MAX_POOL_SIZE; + String maxSizeS = getOption(config, OPTION_MAXSIZE, null); + if (maxSizeS != null) { + maxSize = Integer.parseInt(maxSizeS); + if (maxSize < 0) { + maxSize = Constants.MAX_POOL_SIZE; + } + } + + perThread = new ThreadLocal() { + protected Object initialValue() { + PerThreadData ptd = new PerThreadData(); + ptd.handlers = new Tag[maxSize]; + ptd.current = -1; + perThreadDataVector.addElement(ptd); + return ptd; + } + }; + } + + /** + * Gets the next available tag handler from this tag handler pool, + * instantiating one if this tag handler pool is empty. + * + * @param handlerClass Tag handler class + * + * @return Reused or newly instantiated tag handler + * + * @throws JspException if a tag handler cannot be instantiated + */ + public Tag get(Class handlerClass) throws JspException { + PerThreadData ptd = (PerThreadData)perThread.get(); + if(ptd.current >=0 ) { + return ptd.handlers[ptd.current--]; + } else { + try { + return (Tag) handlerClass.newInstance(); + } catch (Exception e) { + throw new JspException(e.getMessage(), e); + } + } + } + + /** + * Adds the given tag handler to this tag handler pool, unless this tag + * handler pool has already reached its capacity, in which case the tag + * handler's release() method is called. + * + * @param handler Tag handler to add to this tag handler pool + */ + public void reuse(Tag handler) { + PerThreadData ptd=(PerThreadData)perThread.get(); + if (ptd.current < (ptd.handlers.length - 1)) { + ptd.handlers[++ptd.current] = handler; + } else { + handler.release(); + } + } + + /** + * Calls the release() method of all tag handlers in this tag handler pool. + */ + public void release() { + Enumeration enumeration = perThreadDataVector.elements(); + while (enumeration.hasMoreElements()) { + PerThreadData ptd = (PerThreadData)enumeration.nextElement(); + if (ptd.handlers != null) { + for (int i=ptd.current; i>=0; i--) { + if (ptd.handlers[i] != null) { + ptd.handlers[i].release(); + } + } + } + } + } +} + diff --git a/java/org/apache/jasper/runtime/ProtectedFunctionMapper.java b/java/org/apache/jasper/runtime/ProtectedFunctionMapper.java index d919201e0..515679c80 100644 --- a/java/org/apache/jasper/runtime/ProtectedFunctionMapper.java +++ b/java/org/apache/jasper/runtime/ProtectedFunctionMapper.java @@ -1,195 +1,195 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.util.HashMap; -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.security.PrivilegedExceptionAction; -import java.security.PrivilegedActionException; -import java.lang.reflect.Method; -import javax.servlet.jsp.el.FunctionMapper; - -import org.apache.jasper.security.SecurityUtil; - -/** - * Maps EL functions to their Java method counterparts. Keeps the actual Method - * objects protected so that JSP pages can't indirectly do reflection. - * - * @author Mark Roth - * @author Kin-man Chung - */ -public final class ProtectedFunctionMapper extends javax.el.FunctionMapper - implements FunctionMapper { - - /** - * Maps "prefix:name" to java.lang.Method objects. - */ - private HashMap fnmap = null; - - /** - * If there is only one function in the map, this is the Method for it. - */ - private Method theMethod = null; - - /** - * Constructor has protected access. - */ - private ProtectedFunctionMapper() { - } - - /** - * Generated Servlet and Tag Handler implementations call this method to - * retrieve an instance of the ProtectedFunctionMapper. This is necessary - * since generated code does not have access to create instances of classes - * in this package. - * - * @return A new protected function mapper. - */ - public static ProtectedFunctionMapper getInstance() { - ProtectedFunctionMapper funcMapper; - if (SecurityUtil.isPackageProtectionEnabled()) { - funcMapper = (ProtectedFunctionMapper) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return new ProtectedFunctionMapper(); - } - }); - } else { - funcMapper = new ProtectedFunctionMapper(); - } - funcMapper.fnmap = new java.util.HashMap(); - return funcMapper; - } - - /** - * Stores a mapping from the given EL function prefix and name to the given - * Java method. - * - * @param fnQName - * The EL function qualified name (including prefix) - * @param c - * The class containing the Java method - * @param methodName - * The name of the Java method - * @param args - * The arguments of the Java method - * @throws RuntimeException - * if no method with the given signature could be found. - */ - public void mapFunction(String fnQName, final Class c, - final String methodName, final Class[] args) { - java.lang.reflect.Method method; - if (SecurityUtil.isPackageProtectionEnabled()) { - try { - method = (java.lang.reflect.Method) AccessController - .doPrivileged(new PrivilegedExceptionAction() { - - public Object run() throws Exception { - return c.getDeclaredMethod(methodName, args); - } - }); - } catch (PrivilegedActionException ex) { - throw new RuntimeException( - "Invalid function mapping - no such method: " - + ex.getException().getMessage()); - } - } else { - try { - method = c.getDeclaredMethod(methodName, args); - } catch (NoSuchMethodException e) { - throw new RuntimeException( - "Invalid function mapping - no such method: " - + e.getMessage()); - } - } - - this.fnmap.put(fnQName, method); - } - - /** - * Creates an instance for this class, and stores the Method for the given - * EL function prefix and name. This method is used for the case when there - * is only one function in the EL expression. - * - * @param fnQName - * The EL function qualified name (including prefix) - * @param c - * The class containing the Java method - * @param methodName - * The name of the Java method - * @param args - * The arguments of the Java method - * @throws RuntimeException - * if no method with the given signature could be found. - */ - public static ProtectedFunctionMapper getMapForFunction(String fnQName, - final Class c, final String methodName, final Class[] args) { - java.lang.reflect.Method method; - ProtectedFunctionMapper funcMapper; - if (SecurityUtil.isPackageProtectionEnabled()) { - funcMapper = (ProtectedFunctionMapper) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return new ProtectedFunctionMapper(); - } - }); - - try { - method = (java.lang.reflect.Method) AccessController - .doPrivileged(new PrivilegedExceptionAction() { - - public Object run() throws Exception { - return c.getDeclaredMethod(methodName, args); - } - }); - } catch (PrivilegedActionException ex) { - throw new RuntimeException( - "Invalid function mapping - no such method: " - + ex.getException().getMessage()); - } - } else { - funcMapper = new ProtectedFunctionMapper(); - try { - method = c.getDeclaredMethod(methodName, args); - } catch (NoSuchMethodException e) { - throw new RuntimeException( - "Invalid function mapping - no such method: " - + e.getMessage()); - } - } - funcMapper.theMethod = method; - return funcMapper; - } - - /** - * Resolves the specified local name and prefix into a Java.lang.Method. - * Returns null if the prefix and local name are not found. - * - * @param prefix - * the prefix of the function - * @param localName - * the short name of the function - * @return the result of the method mapping. Null means no entry found. - */ - public Method resolveFunction(String prefix, String localName) { - if (this.fnmap != null) { - return (Method) this.fnmap.get(prefix + ":" + localName); - } - return theMethod; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.util.HashMap; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; +import java.lang.reflect.Method; +import javax.servlet.jsp.el.FunctionMapper; + +import org.apache.jasper.security.SecurityUtil; + +/** + * Maps EL functions to their Java method counterparts. Keeps the actual Method + * objects protected so that JSP pages can't indirectly do reflection. + * + * @author Mark Roth + * @author Kin-man Chung + */ +public final class ProtectedFunctionMapper extends javax.el.FunctionMapper + implements FunctionMapper { + + /** + * Maps "prefix:name" to java.lang.Method objects. + */ + private HashMap fnmap = null; + + /** + * If there is only one function in the map, this is the Method for it. + */ + private Method theMethod = null; + + /** + * Constructor has protected access. + */ + private ProtectedFunctionMapper() { + } + + /** + * Generated Servlet and Tag Handler implementations call this method to + * retrieve an instance of the ProtectedFunctionMapper. This is necessary + * since generated code does not have access to create instances of classes + * in this package. + * + * @return A new protected function mapper. + */ + public static ProtectedFunctionMapper getInstance() { + ProtectedFunctionMapper funcMapper; + if (SecurityUtil.isPackageProtectionEnabled()) { + funcMapper = (ProtectedFunctionMapper) AccessController + .doPrivileged(new PrivilegedAction() { + public Object run() { + return new ProtectedFunctionMapper(); + } + }); + } else { + funcMapper = new ProtectedFunctionMapper(); + } + funcMapper.fnmap = new java.util.HashMap(); + return funcMapper; + } + + /** + * Stores a mapping from the given EL function prefix and name to the given + * Java method. + * + * @param fnQName + * The EL function qualified name (including prefix) + * @param c + * The class containing the Java method + * @param methodName + * The name of the Java method + * @param args + * The arguments of the Java method + * @throws RuntimeException + * if no method with the given signature could be found. + */ + public void mapFunction(String fnQName, final Class c, + final String methodName, final Class[] args) { + java.lang.reflect.Method method; + if (SecurityUtil.isPackageProtectionEnabled()) { + try { + method = (java.lang.reflect.Method) AccessController + .doPrivileged(new PrivilegedExceptionAction() { + + public Object run() throws Exception { + return c.getDeclaredMethod(methodName, args); + } + }); + } catch (PrivilegedActionException ex) { + throw new RuntimeException( + "Invalid function mapping - no such method: " + + ex.getException().getMessage()); + } + } else { + try { + method = c.getDeclaredMethod(methodName, args); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "Invalid function mapping - no such method: " + + e.getMessage()); + } + } + + this.fnmap.put(fnQName, method); + } + + /** + * Creates an instance for this class, and stores the Method for the given + * EL function prefix and name. This method is used for the case when there + * is only one function in the EL expression. + * + * @param fnQName + * The EL function qualified name (including prefix) + * @param c + * The class containing the Java method + * @param methodName + * The name of the Java method + * @param args + * The arguments of the Java method + * @throws RuntimeException + * if no method with the given signature could be found. + */ + public static ProtectedFunctionMapper getMapForFunction(String fnQName, + final Class c, final String methodName, final Class[] args) { + java.lang.reflect.Method method; + ProtectedFunctionMapper funcMapper; + if (SecurityUtil.isPackageProtectionEnabled()) { + funcMapper = (ProtectedFunctionMapper) AccessController + .doPrivileged(new PrivilegedAction() { + public Object run() { + return new ProtectedFunctionMapper(); + } + }); + + try { + method = (java.lang.reflect.Method) AccessController + .doPrivileged(new PrivilegedExceptionAction() { + + public Object run() throws Exception { + return c.getDeclaredMethod(methodName, args); + } + }); + } catch (PrivilegedActionException ex) { + throw new RuntimeException( + "Invalid function mapping - no such method: " + + ex.getException().getMessage()); + } + } else { + funcMapper = new ProtectedFunctionMapper(); + try { + method = c.getDeclaredMethod(methodName, args); + } catch (NoSuchMethodException e) { + throw new RuntimeException( + "Invalid function mapping - no such method: " + + e.getMessage()); + } + } + funcMapper.theMethod = method; + return funcMapper; + } + + /** + * Resolves the specified local name and prefix into a Java.lang.Method. + * Returns null if the prefix and local name are not found. + * + * @param prefix + * the prefix of the function + * @param localName + * the short name of the function + * @return the result of the method mapping. Null means no entry found. + */ + public Method resolveFunction(String prefix, String localName) { + if (this.fnmap != null) { + return (Method) this.fnmap.get(prefix + ":" + localName); + } + return theMethod; + } +} diff --git a/java/org/apache/jasper/runtime/ServletResponseWrapperInclude.java b/java/org/apache/jasper/runtime/ServletResponseWrapperInclude.java index 28ecb86f4..25ad3ce75 100644 --- a/java/org/apache/jasper/runtime/ServletResponseWrapperInclude.java +++ b/java/org/apache/jasper/runtime/ServletResponseWrapperInclude.java @@ -1,75 +1,75 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.servlet.jsp.JspWriter; - -/** - * ServletResponseWrapper used by the JSP 'include' action. - * - * This wrapper response object is passed to RequestDispatcher.include(), so - * that the output of the included resource is appended to that of the - * including page. - * - * @author Pierre Delisle - */ - -public class ServletResponseWrapperInclude extends HttpServletResponseWrapper { - - /** - * PrintWriter which appends to the JspWriter of the including page. - */ - private PrintWriter printWriter; - - private JspWriter jspWriter; - - public ServletResponseWrapperInclude(ServletResponse response, - JspWriter jspWriter) { - super((HttpServletResponse)response); - this.printWriter = new PrintWriter(jspWriter); - this.jspWriter = jspWriter; - } - - /** - * Returns a wrapper around the JspWriter of the including page. - */ - public PrintWriter getWriter() throws IOException { - return printWriter; - } - - public ServletOutputStream getOutputStream() throws IOException { - throw new IllegalStateException(); - } - - /** - * Clears the output buffer of the JspWriter associated with the including - * page. - */ - public void resetBuffer() { - try { - jspWriter.clearBuffer(); - } catch (IOException ioe) { - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import java.io.IOException; +import java.io.PrintWriter; + +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import javax.servlet.jsp.JspWriter; + +/** + * ServletResponseWrapper used by the JSP 'include' action. + * + * This wrapper response object is passed to RequestDispatcher.include(), so + * that the output of the included resource is appended to that of the + * including page. + * + * @author Pierre Delisle + */ + +public class ServletResponseWrapperInclude extends HttpServletResponseWrapper { + + /** + * PrintWriter which appends to the JspWriter of the including page. + */ + private PrintWriter printWriter; + + private JspWriter jspWriter; + + public ServletResponseWrapperInclude(ServletResponse response, + JspWriter jspWriter) { + super((HttpServletResponse)response); + this.printWriter = new PrintWriter(jspWriter); + this.jspWriter = jspWriter; + } + + /** + * Returns a wrapper around the JspWriter of the including page. + */ + public PrintWriter getWriter() throws IOException { + return printWriter; + } + + public ServletOutputStream getOutputStream() throws IOException { + throw new IllegalStateException(); + } + + /** + * Clears the output buffer of the JspWriter associated with the including + * page. + */ + public void resetBuffer() { + try { + jspWriter.clearBuffer(); + } catch (IOException ioe) { + } + } +} diff --git a/java/org/apache/jasper/runtime/TagHandlerPool.java b/java/org/apache/jasper/runtime/TagHandlerPool.java index 8e2d341e4..5a2b86d72 100644 --- a/java/org/apache/jasper/runtime/TagHandlerPool.java +++ b/java/org/apache/jasper/runtime/TagHandlerPool.java @@ -1,193 +1,193 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.runtime; - -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.tagext.Tag; -import javax.servlet.ServletConfig; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; - -/** - * Pool of tag handlers that can be reused. - * - * @author Jan Luehe - */ -public class TagHandlerPool { - - private Tag[] handlers; - - public static String OPTION_TAGPOOL="tagpoolClassName"; - public static String OPTION_MAXSIZE="tagpoolMaxSize"; - - private Log log = LogFactory.getLog(TagHandlerPool.class); - - // index of next available tag handler - private int current; - private boolean ignoreAnnotations = false; - - public static TagHandlerPool getTagHandlerPool( ServletConfig config) { - TagHandlerPool result=null; - - String tpClassName=getOption( config, OPTION_TAGPOOL, null); - if( tpClassName != null ) { - try { - Class c=Class.forName( tpClassName ); - result=(TagHandlerPool)c.newInstance(); - } catch (Exception e) { - e.printStackTrace(); - result=null; - } - } - if( result==null ) result=new TagHandlerPool(); - result.init(config); - - return result; - } - - protected void init( ServletConfig config ) { - int maxSize=-1; - String maxSizeS=getOption(config, OPTION_MAXSIZE, null); - if( maxSizeS != null ) { - try { - maxSize=Integer.parseInt(maxSizeS); - } catch( Exception ex) { - maxSize=-1; - } - } - if( maxSize <0 ) { - maxSize=Constants.MAX_POOL_SIZE; - } - this.handlers = new Tag[maxSize]; - this.current = -1; - String annotations = getOption(config, "org.apache.jasper.IGNORE_ANNOTATIONS", null); - if ("true".equals(annotations)) { - ignoreAnnotations = true; - } - } - - /** - * Constructs a tag handler pool with the default capacity. - */ - public TagHandlerPool() { - // Nothing - jasper generated servlets call the other constructor, - // this should be used in future + init . - } - - /** - * Constructs a tag handler pool with the given capacity. - * - * @param capacity Tag handler pool capacity - * @deprecated Use static getTagHandlerPool - */ - public TagHandlerPool(int capacity) { - this.handlers = new Tag[capacity]; - this.current = -1; - } - - /** - * Gets the next available tag handler from this tag handler pool, - * instantiating one if this tag handler pool is empty. - * - * @param handlerClass Tag handler class - * - * @return Reused or newly instantiated tag handler - * - * @throws JspException if a tag handler cannot be instantiated - */ - public Tag get(Class handlerClass) throws JspException { - Tag handler = null; - synchronized( this ) { - if (current >= 0) { - handler = handlers[current--]; - return handler; - } - } - - // Out of sync block - there is no need for other threads to - // wait for us to construct a tag for this thread. - try { - Tag instance = (Tag) handlerClass.newInstance(); - if (!ignoreAnnotations) { - AnnotationProcessor.postConstruct(instance); - } - return instance; - } catch (Exception e) { - throw new JspException(e.getMessage(), e); - } - } - - /** - * Adds the given tag handler to this tag handler pool, unless this tag - * handler pool has already reached its capacity, in which case the tag - * handler's release() method is called. - * - * @param handler Tag handler to add to this tag handler pool - */ - public void reuse(Tag handler) { - synchronized( this ) { - if (current < (handlers.length - 1)) { - handlers[++current] = handler; - return; - } - } - // There is no need for other threads to wait for us to release - handler.release(); - if (!ignoreAnnotations) { - try { - AnnotationProcessor.preDestroy(handler); - } catch (Exception e) { - log.warn("Error processing preDestroy on tag instance of " - + handler.getClass().getName(), e); - } - } - } - - /** - * Calls the release() method of all available tag handlers in this tag - * handler pool. - */ - public synchronized void release() { - for (int i = current; i >= 0; i--) { - handlers[i].release(); - if (!ignoreAnnotations) { - try { - AnnotationProcessor.preDestroy(handlers[i]); - } catch (Exception e) { - log.warn("Error processing preDestroy on tag instance of " - + handlers[i].getClass().getName(), e); - } - } - } - } - - protected static String getOption( ServletConfig config, String name, String defaultV) { - if( config == null ) return defaultV; - - String value=config.getInitParameter(name); - if( value != null ) return value; - if( config.getServletContext() ==null ) - return defaultV; - value=config.getServletContext().getInitParameter(name); - if( value!=null ) return value; - return defaultV; - } - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.runtime; + +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.tagext.Tag; +import javax.servlet.ServletConfig; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; + +/** + * Pool of tag handlers that can be reused. + * + * @author Jan Luehe + */ +public class TagHandlerPool { + + private Tag[] handlers; + + public static String OPTION_TAGPOOL="tagpoolClassName"; + public static String OPTION_MAXSIZE="tagpoolMaxSize"; + + private Log log = LogFactory.getLog(TagHandlerPool.class); + + // index of next available tag handler + private int current; + private boolean ignoreAnnotations = false; + + public static TagHandlerPool getTagHandlerPool( ServletConfig config) { + TagHandlerPool result=null; + + String tpClassName=getOption( config, OPTION_TAGPOOL, null); + if( tpClassName != null ) { + try { + Class c=Class.forName( tpClassName ); + result=(TagHandlerPool)c.newInstance(); + } catch (Exception e) { + e.printStackTrace(); + result=null; + } + } + if( result==null ) result=new TagHandlerPool(); + result.init(config); + + return result; + } + + protected void init( ServletConfig config ) { + int maxSize=-1; + String maxSizeS=getOption(config, OPTION_MAXSIZE, null); + if( maxSizeS != null ) { + try { + maxSize=Integer.parseInt(maxSizeS); + } catch( Exception ex) { + maxSize=-1; + } + } + if( maxSize <0 ) { + maxSize=Constants.MAX_POOL_SIZE; + } + this.handlers = new Tag[maxSize]; + this.current = -1; + String annotations = getOption(config, "org.apache.jasper.IGNORE_ANNOTATIONS", null); + if ("true".equals(annotations)) { + ignoreAnnotations = true; + } + } + + /** + * Constructs a tag handler pool with the default capacity. + */ + public TagHandlerPool() { + // Nothing - jasper generated servlets call the other constructor, + // this should be used in future + init . + } + + /** + * Constructs a tag handler pool with the given capacity. + * + * @param capacity Tag handler pool capacity + * @deprecated Use static getTagHandlerPool + */ + public TagHandlerPool(int capacity) { + this.handlers = new Tag[capacity]; + this.current = -1; + } + + /** + * Gets the next available tag handler from this tag handler pool, + * instantiating one if this tag handler pool is empty. + * + * @param handlerClass Tag handler class + * + * @return Reused or newly instantiated tag handler + * + * @throws JspException if a tag handler cannot be instantiated + */ + public Tag get(Class handlerClass) throws JspException { + Tag handler = null; + synchronized( this ) { + if (current >= 0) { + handler = handlers[current--]; + return handler; + } + } + + // Out of sync block - there is no need for other threads to + // wait for us to construct a tag for this thread. + try { + Tag instance = (Tag) handlerClass.newInstance(); + if (!ignoreAnnotations) { + AnnotationProcessor.postConstruct(instance); + } + return instance; + } catch (Exception e) { + throw new JspException(e.getMessage(), e); + } + } + + /** + * Adds the given tag handler to this tag handler pool, unless this tag + * handler pool has already reached its capacity, in which case the tag + * handler's release() method is called. + * + * @param handler Tag handler to add to this tag handler pool + */ + public void reuse(Tag handler) { + synchronized( this ) { + if (current < (handlers.length - 1)) { + handlers[++current] = handler; + return; + } + } + // There is no need for other threads to wait for us to release + handler.release(); + if (!ignoreAnnotations) { + try { + AnnotationProcessor.preDestroy(handler); + } catch (Exception e) { + log.warn("Error processing preDestroy on tag instance of " + + handler.getClass().getName(), e); + } + } + } + + /** + * Calls the release() method of all available tag handlers in this tag + * handler pool. + */ + public synchronized void release() { + for (int i = current; i >= 0; i--) { + handlers[i].release(); + if (!ignoreAnnotations) { + try { + AnnotationProcessor.preDestroy(handlers[i]); + } catch (Exception e) { + log.warn("Error processing preDestroy on tag instance of " + + handlers[i].getClass().getName(), e); + } + } + } + } + + protected static String getOption( ServletConfig config, String name, String defaultV) { + if( config == null ) return defaultV; + + String value=config.getInitParameter(name); + if( value != null ) return value; + if( config.getServletContext() ==null ) + return defaultV; + value=config.getServletContext().getInitParameter(name); + if( value!=null ) return value; + return defaultV; + } + +} + diff --git a/java/org/apache/jasper/security/SecurityClassLoad.java b/java/org/apache/jasper/security/SecurityClassLoad.java index ea1bda540..fb48df59f 100644 --- a/java/org/apache/jasper/security/SecurityClassLoad.java +++ b/java/org/apache/jasper/security/SecurityClassLoad.java @@ -1,110 +1,110 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.security; - -/** - * Static class used to preload java classes when using the - * Java SecurityManager so that the defineClassInPackage - * RuntimePermission does not trigger an AccessControlException. - * - * @author Jean-Francois Arcand - */ - -public final class SecurityClassLoad { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SecurityClassLoad.class ); - - public static void securityClassLoad(ClassLoader loader){ - - if( System.getSecurityManager() == null ){ - return; - } - - String basePackage = "org.apache.jasper."; - try { - loader.loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedGetPageContext"); - loader.loadClass( basePackage + - "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); - - loader.loadClass( basePackage + - "runtime.JspRuntimeLibrary"); - loader.loadClass( basePackage + - "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); - - loader.loadClass( basePackage + - "runtime.ServletResponseWrapperInclude"); - loader.loadClass( basePackage + - "runtime.TagHandlerPool"); - loader.loadClass( basePackage + - "runtime.JspFragmentHelper"); - - loader.loadClass( basePackage + - "runtime.ProtectedFunctionMapper"); - loader.loadClass( basePackage + - "runtime.ProtectedFunctionMapper$1"); - loader.loadClass( basePackage + - "runtime.ProtectedFunctionMapper$2"); - loader.loadClass( basePackage + - "runtime.ProtectedFunctionMapper$3"); - loader.loadClass( basePackage + - "runtime.ProtectedFunctionMapper$4"); - - loader.loadClass( basePackage + - "runtime.PageContextImpl"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$1"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$2"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$3"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$4"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$5"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$6"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$7"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$8"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$9"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$10"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$11"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$12"); - loader.loadClass( basePackage + - "runtime.PageContextImpl$13"); - - loader.loadClass( basePackage + - "runtime.JspContextWrapper"); - - loader.loadClass( basePackage + - "servlet.JspServletWrapper"); - - loader.loadClass( basePackage + - "runtime.JspWriterImpl$1"); - } catch (ClassNotFoundException ex) { - log.error("SecurityClassLoad", ex); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.security; + +/** + * Static class used to preload java classes when using the + * Java SecurityManager so that the defineClassInPackage + * RuntimePermission does not trigger an AccessControlException. + * + * @author Jean-Francois Arcand + */ + +public final class SecurityClassLoad { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SecurityClassLoad.class ); + + public static void securityClassLoad(ClassLoader loader){ + + if( System.getSecurityManager() == null ){ + return; + } + + String basePackage = "org.apache.jasper."; + try { + loader.loadClass( basePackage + + "runtime.JspFactoryImpl$PrivilegedGetPageContext"); + loader.loadClass( basePackage + + "runtime.JspFactoryImpl$PrivilegedReleasePageContext"); + + loader.loadClass( basePackage + + "runtime.JspRuntimeLibrary"); + loader.loadClass( basePackage + + "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); + + loader.loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); + loader.loadClass( basePackage + + "runtime.TagHandlerPool"); + loader.loadClass( basePackage + + "runtime.JspFragmentHelper"); + + loader.loadClass( basePackage + + "runtime.ProtectedFunctionMapper"); + loader.loadClass( basePackage + + "runtime.ProtectedFunctionMapper$1"); + loader.loadClass( basePackage + + "runtime.ProtectedFunctionMapper$2"); + loader.loadClass( basePackage + + "runtime.ProtectedFunctionMapper$3"); + loader.loadClass( basePackage + + "runtime.ProtectedFunctionMapper$4"); + + loader.loadClass( basePackage + + "runtime.PageContextImpl"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$1"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$2"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$3"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$4"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$5"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$6"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$7"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$8"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$9"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$10"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$11"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$12"); + loader.loadClass( basePackage + + "runtime.PageContextImpl$13"); + + loader.loadClass( basePackage + + "runtime.JspContextWrapper"); + + loader.loadClass( basePackage + + "servlet.JspServletWrapper"); + + loader.loadClass( basePackage + + "runtime.JspWriterImpl$1"); + } catch (ClassNotFoundException ex) { + log.error("SecurityClassLoad", ex); + } + } +} diff --git a/java/org/apache/jasper/security/SecurityUtil.java b/java/org/apache/jasper/security/SecurityUtil.java index b924abeba..32ca26b5d 100644 --- a/java/org/apache/jasper/security/SecurityUtil.java +++ b/java/org/apache/jasper/security/SecurityUtil.java @@ -1,41 +1,41 @@ -/* - * Copyright 1999-2002,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.jasper.security; - -/** - * Util class for Security related operations. - * - * @author Jean-Francois Arcand - */ - -public final class SecurityUtil{ - - private static boolean packageDefinitionEnabled = - System.getProperty("package.definition") == null ? false : true; - - /** - * Return the SecurityManager only if Security is enabled AND - * package protection mechanism is enabled. - */ - public static boolean isPackageProtectionEnabled(){ - if (packageDefinitionEnabled && System.getSecurityManager() != null){ - return true; - } - return false; - } - - -} +/* + * Copyright 1999-2002,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.jasper.security; + +/** + * Util class for Security related operations. + * + * @author Jean-Francois Arcand + */ + +public final class SecurityUtil{ + + private static boolean packageDefinitionEnabled = + System.getProperty("package.definition") == null ? false : true; + + /** + * Return the SecurityManager only if Security is enabled AND + * package protection mechanism is enabled. + */ + public static boolean isPackageProtectionEnabled(){ + if (packageDefinitionEnabled && System.getSecurityManager() != null){ + return true; + } + return false; + } + + +} diff --git a/java/org/apache/jasper/servlet/JasperLoader.java b/java/org/apache/jasper/servlet/JasperLoader.java index cb97af0fe..1acfd10d3 100644 --- a/java/org/apache/jasper/servlet/JasperLoader.java +++ b/java/org/apache/jasper/servlet/JasperLoader.java @@ -1,171 +1,171 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.servlet; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.net.URLClassLoader; -import java.security.CodeSource; -import java.security.PermissionCollection; - -import org.apache.jasper.Constants; - -/** - * Class loader for loading servlet class files (corresponding to JSP files) - * and tag handler class files (corresponding to tag files). - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Jean-Francois Arcand - */ -public class JasperLoader extends URLClassLoader { - - private PermissionCollection permissionCollection; - private CodeSource codeSource; - private String className; - private ClassLoader parent; - private SecurityManager securityManager; - - public JasperLoader(URL[] urls, ClassLoader parent, - PermissionCollection permissionCollection, - CodeSource codeSource) { - super(urls, parent); - this.permissionCollection = permissionCollection; - this.codeSource = codeSource; - this.parent = parent; - this.securityManager = System.getSecurityManager(); - } - - /** - * Load the class with the specified name. This method searches for - * classes in the same manner as loadClass(String, boolean) - * with false as the second argument. - * - * @param name Name of the class to be loaded - * - * @exception ClassNotFoundException if the class was not found - */ - public Class loadClass(String name) throws ClassNotFoundException { - - return (loadClass(name, false)); - } - - /** - * Load the class with the specified name, searching using the following - * algorithm until it finds and returns the class. If the class cannot - * be found, returns ClassNotFoundException. - *

          - *
        • Call findLoadedClass(String) to check if the - * class has already been loaded. If it has, the same - * Class object is returned.
        • - *
        • If the delegate property is set to true, - * call the loadClass() method of the parent class - * loader, if any.
        • - *
        • Call findClass() to find this class in our locally - * defined repositories.
        • - *
        • Call the loadClass() method of our parent - * class loader, if any.
        • - *
        - * If the class was found using the above steps, and the - * resolve flag is true, this method will then - * call resolveClass(Class) on the resulting Class object. - * - * @param name Name of the class to be loaded - * @param resolve If true then resolve the class - * - * @exception ClassNotFoundException if the class was not found - */ - public Class loadClass(final String name, boolean resolve) - throws ClassNotFoundException { - - Class clazz = null; - - // (0) Check our previously loaded class cache - clazz = findLoadedClass(name); - if (clazz != null) { - if (resolve) - resolveClass(clazz); - return (clazz); - } - - // (.5) Permission to access this class when using a SecurityManager - if (securityManager != null) { - int dot = name.lastIndexOf('.'); - if (dot >= 0) { - try { - // Do not call the security manager since by default, we grant that package. - if (!"org.apache.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){ - securityManager.checkPackageAccess(name.substring(0,dot)); - } - } catch (SecurityException se) { - String error = "Security Violation, attempt to use " + - "Restricted Class: " + name; - se.printStackTrace(); - throw new ClassNotFoundException(error); - } - } - } - - if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) { - // Class is not in org.apache.jsp, therefore, have our - // parent load it - clazz = parent.loadClass(name); - if( resolve ) - resolveClass(clazz); - return clazz; - } - - return findClass(name); - } - - - /** - * Delegate to parent - * - * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String) - */ - public InputStream getResourceAsStream(String name) { - InputStream is = parent.getResourceAsStream(name); - if (is == null) { - URL url = findResource(name); - if (url != null) { - try { - is = url.openStream(); - } catch (IOException e) { - is = null; - } - } - } - return is; - } - - - /** - * Get the Permissions for a CodeSource. - * - * Since this ClassLoader is only used for a JSP page in - * a web application context, we just return our preset - * PermissionCollection for the web app context. - * - * @param codeSource Code source where the code was loaded from - * @return PermissionCollection for CodeSource - */ - public final PermissionCollection getPermissions(CodeSource codeSource) { - return permissionCollection; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.servlet; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.net.URLClassLoader; +import java.security.CodeSource; +import java.security.PermissionCollection; + +import org.apache.jasper.Constants; + +/** + * Class loader for loading servlet class files (corresponding to JSP files) + * and tag handler class files (corresponding to tag files). + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Jean-Francois Arcand + */ +public class JasperLoader extends URLClassLoader { + + private PermissionCollection permissionCollection; + private CodeSource codeSource; + private String className; + private ClassLoader parent; + private SecurityManager securityManager; + + public JasperLoader(URL[] urls, ClassLoader parent, + PermissionCollection permissionCollection, + CodeSource codeSource) { + super(urls, parent); + this.permissionCollection = permissionCollection; + this.codeSource = codeSource; + this.parent = parent; + this.securityManager = System.getSecurityManager(); + } + + /** + * Load the class with the specified name. This method searches for + * classes in the same manner as loadClass(String, boolean) + * with false as the second argument. + * + * @param name Name of the class to be loaded + * + * @exception ClassNotFoundException if the class was not found + */ + public Class loadClass(String name) throws ClassNotFoundException { + + return (loadClass(name, false)); + } + + /** + * Load the class with the specified name, searching using the following + * algorithm until it finds and returns the class. If the class cannot + * be found, returns ClassNotFoundException. + *
          + *
        • Call findLoadedClass(String) to check if the + * class has already been loaded. If it has, the same + * Class object is returned.
        • + *
        • If the delegate property is set to true, + * call the loadClass() method of the parent class + * loader, if any.
        • + *
        • Call findClass() to find this class in our locally + * defined repositories.
        • + *
        • Call the loadClass() method of our parent + * class loader, if any.
        • + *
        + * If the class was found using the above steps, and the + * resolve flag is true, this method will then + * call resolveClass(Class) on the resulting Class object. + * + * @param name Name of the class to be loaded + * @param resolve If true then resolve the class + * + * @exception ClassNotFoundException if the class was not found + */ + public Class loadClass(final String name, boolean resolve) + throws ClassNotFoundException { + + Class clazz = null; + + // (0) Check our previously loaded class cache + clazz = findLoadedClass(name); + if (clazz != null) { + if (resolve) + resolveClass(clazz); + return (clazz); + } + + // (.5) Permission to access this class when using a SecurityManager + if (securityManager != null) { + int dot = name.lastIndexOf('.'); + if (dot >= 0) { + try { + // Do not call the security manager since by default, we grant that package. + if (!"org.apache.jasper.runtime".equalsIgnoreCase(name.substring(0,dot))){ + securityManager.checkPackageAccess(name.substring(0,dot)); + } + } catch (SecurityException se) { + String error = "Security Violation, attempt to use " + + "Restricted Class: " + name; + se.printStackTrace(); + throw new ClassNotFoundException(error); + } + } + } + + if( !name.startsWith(Constants.JSP_PACKAGE_NAME) ) { + // Class is not in org.apache.jsp, therefore, have our + // parent load it + clazz = parent.loadClass(name); + if( resolve ) + resolveClass(clazz); + return clazz; + } + + return findClass(name); + } + + + /** + * Delegate to parent + * + * @see java.lang.ClassLoader#getResourceAsStream(java.lang.String) + */ + public InputStream getResourceAsStream(String name) { + InputStream is = parent.getResourceAsStream(name); + if (is == null) { + URL url = findResource(name); + if (url != null) { + try { + is = url.openStream(); + } catch (IOException e) { + is = null; + } + } + } + return is; + } + + + /** + * Get the Permissions for a CodeSource. + * + * Since this ClassLoader is only used for a JSP page in + * a web application context, we just return our preset + * PermissionCollection for the web app context. + * + * @param codeSource Code source where the code was loaded from + * @return PermissionCollection for CodeSource + */ + public final PermissionCollection getPermissions(CodeSource codeSource) { + return permissionCollection; + } +} diff --git a/java/org/apache/jasper/servlet/JspCServletContext.java b/java/org/apache/jasper/servlet/JspCServletContext.java index 2bffbbf60..d59b16543 100644 --- a/java/org/apache/jasper/servlet/JspCServletContext.java +++ b/java/org/apache/jasper/servlet/JspCServletContext.java @@ -1,440 +1,440 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.servlet; - - -import java.io.File; -import java.io.InputStream; -import java.io.PrintWriter; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Hashtable; -import java.util.Set; -import java.util.Vector; - -import javax.servlet.RequestDispatcher; -import javax.servlet.Servlet; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; - - -/** - * Simple ServletContext implementation without - * HTTP-specific methods. - * - * @author Peter Rossbach (pr@webapp.de) - */ - -public class JspCServletContext implements ServletContext { - - - // ----------------------------------------------------- Instance Variables - - - /** - * Servlet context attributes. - */ - protected Hashtable myAttributes; - - - /** - * The log writer we will write log messages to. - */ - protected PrintWriter myLogWriter; - - - /** - * The base URL (document root) for this context. - */ - protected URL myResourceBaseURL; - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a new instance of this ServletContext implementation. - * - * @param aLogWriter PrintWriter which is used for log() calls - * @param aResourceBaseURL Resource base URL - */ - public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL) { - - myAttributes = new Hashtable(); - myLogWriter = aLogWriter; - myResourceBaseURL = aResourceBaseURL; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return the specified context attribute, if any. - * - * @param name Name of the requested attribute - */ - public Object getAttribute(String name) { - - return (myAttributes.get(name)); - - } - - - /** - * Return an enumeration of context attribute names. - */ - public Enumeration getAttributeNames() { - - return (myAttributes.keys()); - - } - - - /** - * Return the servlet context for the specified path. - * - * @param uripath Server-relative path starting with '/' - */ - public ServletContext getContext(String uripath) { - - return (null); - - } - - - /** - * Return the context path. - */ - public String getContextPath() { - - return (null); - - } - - - /** - * Return the specified context initialization parameter. - * - * @param name Name of the requested parameter - */ - public String getInitParameter(String name) { - - return (null); - - } - - - /** - * Return an enumeration of the names of context initialization - * parameters. - */ - public Enumeration getInitParameterNames() { - - return (new Vector().elements()); - - } - - - /** - * Return the Servlet API major version number. - */ - public int getMajorVersion() { - - return (2); - - } - - - /** - * Return the MIME type for the specified filename. - * - * @param file Filename whose MIME type is requested - */ - public String getMimeType(String file) { - - return (null); - - } - - - /** - * Return the Servlet API minor version number. - */ - public int getMinorVersion() { - - return (3); - - } - - - /** - * Return a request dispatcher for the specified servlet name. - * - * @param name Name of the requested servlet - */ - public RequestDispatcher getNamedDispatcher(String name) { - - return (null); - - } - - - /** - * Return the real path for the specified context-relative - * virtual path. - * - * @param path The context-relative virtual path to resolve - */ - public String getRealPath(String path) { - - if (!myResourceBaseURL.getProtocol().equals("file")) - return (null); - if (!path.startsWith("/")) - return (null); - try { - return - (getResource(path).getFile().replace('/', File.separatorChar)); - } catch (Throwable t) { - return (null); - } - - } - - - /** - * Return a request dispatcher for the specified context-relative path. - * - * @param path Context-relative path for which to acquire a dispatcher - */ - public RequestDispatcher getRequestDispatcher(String path) { - - return (null); - - } - - - /** - * Return a URL object of a resource that is mapped to the - * specified context-relative path. - * - * @param path Context-relative path of the desired resource - * - * @exception MalformedURLException if the resource path is - * not properly formed - */ - public URL getResource(String path) throws MalformedURLException { - - if (!path.startsWith("/")) - throw new MalformedURLException("Path '" + path + - "' does not start with '/'"); - URL url = new URL(myResourceBaseURL, path.substring(1)); - InputStream is = null; - try { - is = url.openStream(); - } catch (Throwable t) { - url = null; - } finally { - if (is != null) { - try { - is.close(); - } catch (Throwable t2) { - // Ignore - } - } - } - return url; - - } - - - /** - * Return an InputStream allowing access to the resource at the - * specified context-relative path. - * - * @param path Context-relative path of the desired resource - */ - public InputStream getResourceAsStream(String path) { - - try { - return (getResource(path).openStream()); - } catch (Throwable t) { - return (null); - } - - } - - - /** - * Return the set of resource paths for the "directory" at the - * specified context path. - * - * @param path Context-relative base path - */ - public Set getResourcePaths(String path) { - - Set thePaths = new HashSet(); - if (!path.endsWith("/")) - path += "/"; - String basePath = getRealPath(path); - if (basePath == null) - return (thePaths); - File theBaseDir = new File(basePath); - if (!theBaseDir.exists() || !theBaseDir.isDirectory()) - return (thePaths); - String theFiles[] = theBaseDir.list(); - for (int i = 0; i < theFiles.length; i++) { - File testFile = new File(basePath + File.separator + theFiles[i]); - if (testFile.isFile()) - thePaths.add(path + theFiles[i]); - else if (testFile.isDirectory()) - thePaths.add(path + theFiles[i] + "/"); - } - return (thePaths); - - } - - - /** - * Return descriptive information about this server. - */ - public String getServerInfo() { - - return ("JspCServletContext/1.0"); - - } - - - /** - * Return a null reference for the specified servlet name. - * - * @param name Name of the requested servlet - * - * @deprecated This method has been deprecated with no replacement - */ - public Servlet getServlet(String name) throws ServletException { - - return (null); - - } - - - /** - * Return the name of this servlet context. - */ - public String getServletContextName() { - - return (getServerInfo()); - - } - - - /** - * Return an empty enumeration of servlet names. - * - * @deprecated This method has been deprecated with no replacement - */ - public Enumeration getServletNames() { - - return (new Vector().elements()); - - } - - - /** - * Return an empty enumeration of servlets. - * - * @deprecated This method has been deprecated with no replacement - */ - public Enumeration getServlets() { - - return (new Vector().elements()); - - } - - - /** - * Log the specified message. - * - * @param message The message to be logged - */ - public void log(String message) { - - myLogWriter.println(message); - - } - - - /** - * Log the specified message and exception. - * - * @param exception The exception to be logged - * @param message The message to be logged - * - * @deprecated Use log(String,Throwable) instead - */ - public void log(Exception exception, String message) { - - log(message, exception); - - } - - - /** - * Log the specified message and exception. - * - * @param message The message to be logged - * @param exception The exception to be logged - */ - public void log(String message, Throwable exception) { - - myLogWriter.println(message); - exception.printStackTrace(myLogWriter); - - } - - - /** - * Remove the specified context attribute. - * - * @param name Name of the attribute to remove - */ - public void removeAttribute(String name) { - - myAttributes.remove(name); - - } - - - /** - * Set or replace the specified context attribute. - * - * @param name Name of the context attribute to set - * @param value Corresponding attribute value - */ - public void setAttribute(String name, Object value) { - - myAttributes.put(name, value); - - } - - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.servlet; + + +import java.io.File; +import java.io.InputStream; +import java.io.PrintWriter; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; +import java.util.Vector; + +import javax.servlet.RequestDispatcher; +import javax.servlet.Servlet; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; + + +/** + * Simple ServletContext implementation without + * HTTP-specific methods. + * + * @author Peter Rossbach (pr@webapp.de) + */ + +public class JspCServletContext implements ServletContext { + + + // ----------------------------------------------------- Instance Variables + + + /** + * Servlet context attributes. + */ + protected Hashtable myAttributes; + + + /** + * The log writer we will write log messages to. + */ + protected PrintWriter myLogWriter; + + + /** + * The base URL (document root) for this context. + */ + protected URL myResourceBaseURL; + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a new instance of this ServletContext implementation. + * + * @param aLogWriter PrintWriter which is used for log() calls + * @param aResourceBaseURL Resource base URL + */ + public JspCServletContext(PrintWriter aLogWriter, URL aResourceBaseURL) { + + myAttributes = new Hashtable(); + myLogWriter = aLogWriter; + myResourceBaseURL = aResourceBaseURL; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return the specified context attribute, if any. + * + * @param name Name of the requested attribute + */ + public Object getAttribute(String name) { + + return (myAttributes.get(name)); + + } + + + /** + * Return an enumeration of context attribute names. + */ + public Enumeration getAttributeNames() { + + return (myAttributes.keys()); + + } + + + /** + * Return the servlet context for the specified path. + * + * @param uripath Server-relative path starting with '/' + */ + public ServletContext getContext(String uripath) { + + return (null); + + } + + + /** + * Return the context path. + */ + public String getContextPath() { + + return (null); + + } + + + /** + * Return the specified context initialization parameter. + * + * @param name Name of the requested parameter + */ + public String getInitParameter(String name) { + + return (null); + + } + + + /** + * Return an enumeration of the names of context initialization + * parameters. + */ + public Enumeration getInitParameterNames() { + + return (new Vector().elements()); + + } + + + /** + * Return the Servlet API major version number. + */ + public int getMajorVersion() { + + return (2); + + } + + + /** + * Return the MIME type for the specified filename. + * + * @param file Filename whose MIME type is requested + */ + public String getMimeType(String file) { + + return (null); + + } + + + /** + * Return the Servlet API minor version number. + */ + public int getMinorVersion() { + + return (3); + + } + + + /** + * Return a request dispatcher for the specified servlet name. + * + * @param name Name of the requested servlet + */ + public RequestDispatcher getNamedDispatcher(String name) { + + return (null); + + } + + + /** + * Return the real path for the specified context-relative + * virtual path. + * + * @param path The context-relative virtual path to resolve + */ + public String getRealPath(String path) { + + if (!myResourceBaseURL.getProtocol().equals("file")) + return (null); + if (!path.startsWith("/")) + return (null); + try { + return + (getResource(path).getFile().replace('/', File.separatorChar)); + } catch (Throwable t) { + return (null); + } + + } + + + /** + * Return a request dispatcher for the specified context-relative path. + * + * @param path Context-relative path for which to acquire a dispatcher + */ + public RequestDispatcher getRequestDispatcher(String path) { + + return (null); + + } + + + /** + * Return a URL object of a resource that is mapped to the + * specified context-relative path. + * + * @param path Context-relative path of the desired resource + * + * @exception MalformedURLException if the resource path is + * not properly formed + */ + public URL getResource(String path) throws MalformedURLException { + + if (!path.startsWith("/")) + throw new MalformedURLException("Path '" + path + + "' does not start with '/'"); + URL url = new URL(myResourceBaseURL, path.substring(1)); + InputStream is = null; + try { + is = url.openStream(); + } catch (Throwable t) { + url = null; + } finally { + if (is != null) { + try { + is.close(); + } catch (Throwable t2) { + // Ignore + } + } + } + return url; + + } + + + /** + * Return an InputStream allowing access to the resource at the + * specified context-relative path. + * + * @param path Context-relative path of the desired resource + */ + public InputStream getResourceAsStream(String path) { + + try { + return (getResource(path).openStream()); + } catch (Throwable t) { + return (null); + } + + } + + + /** + * Return the set of resource paths for the "directory" at the + * specified context path. + * + * @param path Context-relative base path + */ + public Set getResourcePaths(String path) { + + Set thePaths = new HashSet(); + if (!path.endsWith("/")) + path += "/"; + String basePath = getRealPath(path); + if (basePath == null) + return (thePaths); + File theBaseDir = new File(basePath); + if (!theBaseDir.exists() || !theBaseDir.isDirectory()) + return (thePaths); + String theFiles[] = theBaseDir.list(); + for (int i = 0; i < theFiles.length; i++) { + File testFile = new File(basePath + File.separator + theFiles[i]); + if (testFile.isFile()) + thePaths.add(path + theFiles[i]); + else if (testFile.isDirectory()) + thePaths.add(path + theFiles[i] + "/"); + } + return (thePaths); + + } + + + /** + * Return descriptive information about this server. + */ + public String getServerInfo() { + + return ("JspCServletContext/1.0"); + + } + + + /** + * Return a null reference for the specified servlet name. + * + * @param name Name of the requested servlet + * + * @deprecated This method has been deprecated with no replacement + */ + public Servlet getServlet(String name) throws ServletException { + + return (null); + + } + + + /** + * Return the name of this servlet context. + */ + public String getServletContextName() { + + return (getServerInfo()); + + } + + + /** + * Return an empty enumeration of servlet names. + * + * @deprecated This method has been deprecated with no replacement + */ + public Enumeration getServletNames() { + + return (new Vector().elements()); + + } + + + /** + * Return an empty enumeration of servlets. + * + * @deprecated This method has been deprecated with no replacement + */ + public Enumeration getServlets() { + + return (new Vector().elements()); + + } + + + /** + * Log the specified message. + * + * @param message The message to be logged + */ + public void log(String message) { + + myLogWriter.println(message); + + } + + + /** + * Log the specified message and exception. + * + * @param exception The exception to be logged + * @param message The message to be logged + * + * @deprecated Use log(String,Throwable) instead + */ + public void log(Exception exception, String message) { + + log(message, exception); + + } + + + /** + * Log the specified message and exception. + * + * @param message The message to be logged + * @param exception The exception to be logged + */ + public void log(String message, Throwable exception) { + + myLogWriter.println(message); + exception.printStackTrace(myLogWriter); + + } + + + /** + * Remove the specified context attribute. + * + * @param name Name of the attribute to remove + */ + public void removeAttribute(String name) { + + myAttributes.remove(name); + + } + + + /** + * Set or replace the specified context attribute. + * + * @param name Name of the context attribute to set + * @param value Corresponding attribute value + */ + public void setAttribute(String name, Object value) { + + myAttributes.put(name, value); + + } + + + +} diff --git a/java/org/apache/jasper/servlet/JspServlet.java b/java/org/apache/jasper/servlet/JspServlet.java index 74e7f5db1..82e5f5e9f 100644 --- a/java/org/apache/jasper/servlet/JspServlet.java +++ b/java/org/apache/jasper/servlet/JspServlet.java @@ -1,318 +1,318 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.servlet; - -import java.io.IOException; -import java.lang.reflect.Constructor; -import java.util.Enumeration; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.apache.jasper.Constants; -import org.apache.jasper.EmbeddedServletOptions; -import org.apache.jasper.Options; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; - -/** - * The JSP engine (a.k.a Jasper). - * - * The servlet container is responsible for providing a - * URLClassLoader for the web application context Jasper - * is being used in. Jasper will try get the Tomcat - * ServletContext attribute for its ServletContext class - * loader, if that fails, it uses the parent class loader. - * In either case, it must be a URLClassLoader. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Remy Maucherat - * @author Kin-man Chung - * @author Glenn Nielsen - */ -public class JspServlet extends HttpServlet { - - // Logger - private Log log = LogFactory.getLog(JspServlet.class); - - private ServletContext context; - private ServletConfig config; - private Options options; - private JspRuntimeContext rctxt; - - - /* - * Initializes this JspServlet. - */ - public void init(ServletConfig config) throws ServletException { - - super.init(config); - this.config = config; - this.context = config.getServletContext(); - - // Initialize the JSP Runtime Context - // Check for a custom Options implementation - String engineOptionsName = - config.getInitParameter("engineOptionsClass"); - if (engineOptionsName != null) { - // Instantiate the indicated Options implementation - try { - ClassLoader loader = Thread.currentThread() - .getContextClassLoader(); - Class engineOptionsClass = loader.loadClass(engineOptionsName); - Class[] ctorSig = { ServletConfig.class, ServletContext.class }; - Constructor ctor = engineOptionsClass.getConstructor(ctorSig); - Object[] args = { config, context }; - options = (Options) ctor.newInstance(args); - } catch (Throwable e) { - // Need to localize this. - log.warn("Failed to load engineOptionsClass", e); - // Use the default Options implementation - options = new EmbeddedServletOptions(config, context); - } - } else { - // Use the default Options implementation - options = new EmbeddedServletOptions(config, context); - } - rctxt = new JspRuntimeContext(context, options); - - if (log.isDebugEnabled()) { - log.debug(Localizer.getMessage("jsp.message.scratch.dir.is", - options.getScratchDir().toString())); - log.debug(Localizer.getMessage("jsp.message.dont.modify.servlets")); - } - } - - - /** - * Returns the number of JSPs for which JspServletWrappers exist, i.e., - * the number of JSPs that have been loaded into the webapp with which - * this JspServlet is associated. - * - *

        This info may be used for monitoring purposes. - * - * @return The number of JSPs that have been loaded into the webapp with - * which this JspServlet is associated - */ - public int getJspCount() { - return this.rctxt.getJspCount(); - } - - - /** - * Resets the JSP reload counter. - * - * @param count Value to which to reset the JSP reload counter - */ - public void setJspReloadCount(int count) { - this.rctxt.setJspReloadCount(count); - } - - - /** - * Gets the number of JSPs that have been reloaded. - * - *

        This info may be used for monitoring purposes. - * - * @return The number of JSPs (in the webapp with which this JspServlet is - * associated) that have been reloaded - */ - public int getJspReloadCount() { - return this.rctxt.getJspReloadCount(); - } - - - /** - *

        Look for a precompilation request as described in - * Section 8.4.2 of the JSP 1.2 Specification. WARNING - - * we cannot use request.getParameter() for this, because - * that will trigger parsing all of the request parameters, and not give - * a servlet the opportunity to call - * request.setCharacterEncoding() first.

        - * - * @param request The servlet requset we are processing - * - * @exception ServletException if an invalid parameter value for the - * jsp_precompile parameter name is specified - */ - boolean preCompile(HttpServletRequest request) throws ServletException { - - String queryString = request.getQueryString(); - if (queryString == null) { - return (false); - } - int start = queryString.indexOf(Constants.PRECOMPILE); - if (start < 0) { - return (false); - } - queryString = - queryString.substring(start + Constants.PRECOMPILE.length()); - if (queryString.length() == 0) { - return (true); // ?jsp_precompile - } - if (queryString.startsWith("&")) { - return (true); // ?jsp_precompile&foo=bar... - } - if (!queryString.startsWith("=")) { - return (false); // part of some other name or value - } - int limit = queryString.length(); - int ampersand = queryString.indexOf("&"); - if (ampersand > 0) { - limit = ampersand; - } - String value = queryString.substring(1, limit); - if (value.equals("true")) { - return (true); // ?jsp_precompile=true - } else if (value.equals("false")) { - // Spec says if jsp_precompile=false, the request should not - // be delivered to the JSP page; the easiest way to implement - // this is to set the flag to true, and precompile the page anyway. - // This still conforms to the spec, since it says the - // precompilation request can be ignored. - return (true); // ?jsp_precompile=false - } else { - throw new ServletException("Cannot have request parameter " + - Constants.PRECOMPILE + " set to " + - value); - } - - } - - - public void service (HttpServletRequest request, - HttpServletResponse response) - throws ServletException, IOException { - - String jspUri = null; - - String jspFile = (String) request.getAttribute(Constants.JSP_FILE); - if (jspFile != null) { - // JSP is specified via in declaration - jspUri = jspFile; - } else { - /* - * Check to see if the requested JSP has been the target of a - * RequestDispatcher.include() - */ - jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH); - if (jspUri != null) { - /* - * Requested JSP has been target of - * RequestDispatcher.include(). Its path is assembled from the - * relevant javax.servlet.include.* request attributes - */ - String pathInfo = (String) request.getAttribute( - "javax.servlet.include.path_info"); - if (pathInfo != null) { - jspUri += pathInfo; - } - } else { - /* - * Requested JSP has not been the target of a - * RequestDispatcher.include(). Reconstruct its path from the - * request's getServletPath() and getPathInfo() - */ - jspUri = request.getServletPath(); - String pathInfo = request.getPathInfo(); - if (pathInfo != null) { - jspUri += pathInfo; - } - } - } - - if (log.isDebugEnabled()) { - log.debug("JspEngine --> " + jspUri); - log.debug("\t ServletPath: " + request.getServletPath()); - log.debug("\t PathInfo: " + request.getPathInfo()); - log.debug("\t RealPath: " + context.getRealPath(jspUri)); - log.debug("\t RequestURI: " + request.getRequestURI()); - log.debug("\t QueryString: " + request.getQueryString()); - log.debug("\t Request Params: "); - Enumeration e = request.getParameterNames(); - while (e.hasMoreElements()) { - String name = (String) e.nextElement(); - log.debug("\t\t " + name + " = " - + request.getParameter(name)); - } - } - - try { - boolean precompile = preCompile(request); - serviceJspFile(request, response, jspUri, null, precompile); - } catch (RuntimeException e) { - throw e; - } catch (ServletException e) { - throw e; - } catch (IOException e) { - throw e; - } catch (Throwable e) { - throw new ServletException(e); - } - - } - - public void destroy() { - if (log.isDebugEnabled()) { - log.debug("JspServlet.destroy()"); - } - - rctxt.destroy(); - } - - - // -------------------------------------------------------- Private Methods - - private void serviceJspFile(HttpServletRequest request, - HttpServletResponse response, String jspUri, - Throwable exception, boolean precompile) - throws ServletException, IOException { - - JspServletWrapper wrapper = - (JspServletWrapper) rctxt.getWrapper(jspUri); - if (wrapper == null) { - synchronized(this) { - wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri); - if (wrapper == null) { - // Check if the requested JSP page exists, to avoid - // creating unnecessary directories and files. - if (null == context.getResource(jspUri)) { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - jspUri); - return; - } - boolean isErrorPage = exception != null; - wrapper = new JspServletWrapper(config, options, jspUri, - isErrorPage, rctxt); - rctxt.addWrapper(jspUri,wrapper); - } - } - } - - wrapper.service(request, response, precompile); - - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.servlet; + +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.util.Enumeration; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jasper.Constants; +import org.apache.jasper.EmbeddedServletOptions; +import org.apache.jasper.Options; +import org.apache.jasper.compiler.JspRuntimeContext; +import org.apache.jasper.compiler.Localizer; + +/** + * The JSP engine (a.k.a Jasper). + * + * The servlet container is responsible for providing a + * URLClassLoader for the web application context Jasper + * is being used in. Jasper will try get the Tomcat + * ServletContext attribute for its ServletContext class + * loader, if that fails, it uses the parent class loader. + * In either case, it must be a URLClassLoader. + * + * @author Anil K. Vijendran + * @author Harish Prabandham + * @author Remy Maucherat + * @author Kin-man Chung + * @author Glenn Nielsen + */ +public class JspServlet extends HttpServlet { + + // Logger + private Log log = LogFactory.getLog(JspServlet.class); + + private ServletContext context; + private ServletConfig config; + private Options options; + private JspRuntimeContext rctxt; + + + /* + * Initializes this JspServlet. + */ + public void init(ServletConfig config) throws ServletException { + + super.init(config); + this.config = config; + this.context = config.getServletContext(); + + // Initialize the JSP Runtime Context + // Check for a custom Options implementation + String engineOptionsName = + config.getInitParameter("engineOptionsClass"); + if (engineOptionsName != null) { + // Instantiate the indicated Options implementation + try { + ClassLoader loader = Thread.currentThread() + .getContextClassLoader(); + Class engineOptionsClass = loader.loadClass(engineOptionsName); + Class[] ctorSig = { ServletConfig.class, ServletContext.class }; + Constructor ctor = engineOptionsClass.getConstructor(ctorSig); + Object[] args = { config, context }; + options = (Options) ctor.newInstance(args); + } catch (Throwable e) { + // Need to localize this. + log.warn("Failed to load engineOptionsClass", e); + // Use the default Options implementation + options = new EmbeddedServletOptions(config, context); + } + } else { + // Use the default Options implementation + options = new EmbeddedServletOptions(config, context); + } + rctxt = new JspRuntimeContext(context, options); + + if (log.isDebugEnabled()) { + log.debug(Localizer.getMessage("jsp.message.scratch.dir.is", + options.getScratchDir().toString())); + log.debug(Localizer.getMessage("jsp.message.dont.modify.servlets")); + } + } + + + /** + * Returns the number of JSPs for which JspServletWrappers exist, i.e., + * the number of JSPs that have been loaded into the webapp with which + * this JspServlet is associated. + * + *

        This info may be used for monitoring purposes. + * + * @return The number of JSPs that have been loaded into the webapp with + * which this JspServlet is associated + */ + public int getJspCount() { + return this.rctxt.getJspCount(); + } + + + /** + * Resets the JSP reload counter. + * + * @param count Value to which to reset the JSP reload counter + */ + public void setJspReloadCount(int count) { + this.rctxt.setJspReloadCount(count); + } + + + /** + * Gets the number of JSPs that have been reloaded. + * + *

        This info may be used for monitoring purposes. + * + * @return The number of JSPs (in the webapp with which this JspServlet is + * associated) that have been reloaded + */ + public int getJspReloadCount() { + return this.rctxt.getJspReloadCount(); + } + + + /** + *

        Look for a precompilation request as described in + * Section 8.4.2 of the JSP 1.2 Specification. WARNING - + * we cannot use request.getParameter() for this, because + * that will trigger parsing all of the request parameters, and not give + * a servlet the opportunity to call + * request.setCharacterEncoding() first.

        + * + * @param request The servlet requset we are processing + * + * @exception ServletException if an invalid parameter value for the + * jsp_precompile parameter name is specified + */ + boolean preCompile(HttpServletRequest request) throws ServletException { + + String queryString = request.getQueryString(); + if (queryString == null) { + return (false); + } + int start = queryString.indexOf(Constants.PRECOMPILE); + if (start < 0) { + return (false); + } + queryString = + queryString.substring(start + Constants.PRECOMPILE.length()); + if (queryString.length() == 0) { + return (true); // ?jsp_precompile + } + if (queryString.startsWith("&")) { + return (true); // ?jsp_precompile&foo=bar... + } + if (!queryString.startsWith("=")) { + return (false); // part of some other name or value + } + int limit = queryString.length(); + int ampersand = queryString.indexOf("&"); + if (ampersand > 0) { + limit = ampersand; + } + String value = queryString.substring(1, limit); + if (value.equals("true")) { + return (true); // ?jsp_precompile=true + } else if (value.equals("false")) { + // Spec says if jsp_precompile=false, the request should not + // be delivered to the JSP page; the easiest way to implement + // this is to set the flag to true, and precompile the page anyway. + // This still conforms to the spec, since it says the + // precompilation request can be ignored. + return (true); // ?jsp_precompile=false + } else { + throw new ServletException("Cannot have request parameter " + + Constants.PRECOMPILE + " set to " + + value); + } + + } + + + public void service (HttpServletRequest request, + HttpServletResponse response) + throws ServletException, IOException { + + String jspUri = null; + + String jspFile = (String) request.getAttribute(Constants.JSP_FILE); + if (jspFile != null) { + // JSP is specified via in declaration + jspUri = jspFile; + } else { + /* + * Check to see if the requested JSP has been the target of a + * RequestDispatcher.include() + */ + jspUri = (String) request.getAttribute(Constants.INC_SERVLET_PATH); + if (jspUri != null) { + /* + * Requested JSP has been target of + * RequestDispatcher.include(). Its path is assembled from the + * relevant javax.servlet.include.* request attributes + */ + String pathInfo = (String) request.getAttribute( + "javax.servlet.include.path_info"); + if (pathInfo != null) { + jspUri += pathInfo; + } + } else { + /* + * Requested JSP has not been the target of a + * RequestDispatcher.include(). Reconstruct its path from the + * request's getServletPath() and getPathInfo() + */ + jspUri = request.getServletPath(); + String pathInfo = request.getPathInfo(); + if (pathInfo != null) { + jspUri += pathInfo; + } + } + } + + if (log.isDebugEnabled()) { + log.debug("JspEngine --> " + jspUri); + log.debug("\t ServletPath: " + request.getServletPath()); + log.debug("\t PathInfo: " + request.getPathInfo()); + log.debug("\t RealPath: " + context.getRealPath(jspUri)); + log.debug("\t RequestURI: " + request.getRequestURI()); + log.debug("\t QueryString: " + request.getQueryString()); + log.debug("\t Request Params: "); + Enumeration e = request.getParameterNames(); + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + log.debug("\t\t " + name + " = " + + request.getParameter(name)); + } + } + + try { + boolean precompile = preCompile(request); + serviceJspFile(request, response, jspUri, null, precompile); + } catch (RuntimeException e) { + throw e; + } catch (ServletException e) { + throw e; + } catch (IOException e) { + throw e; + } catch (Throwable e) { + throw new ServletException(e); + } + + } + + public void destroy() { + if (log.isDebugEnabled()) { + log.debug("JspServlet.destroy()"); + } + + rctxt.destroy(); + } + + + // -------------------------------------------------------- Private Methods + + private void serviceJspFile(HttpServletRequest request, + HttpServletResponse response, String jspUri, + Throwable exception, boolean precompile) + throws ServletException, IOException { + + JspServletWrapper wrapper = + (JspServletWrapper) rctxt.getWrapper(jspUri); + if (wrapper == null) { + synchronized(this) { + wrapper = (JspServletWrapper) rctxt.getWrapper(jspUri); + if (wrapper == null) { + // Check if the requested JSP page exists, to avoid + // creating unnecessary directories and files. + if (null == context.getResource(jspUri)) { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + jspUri); + return; + } + boolean isErrorPage = exception != null; + wrapper = new JspServletWrapper(config, options, jspUri, + isErrorPage, rctxt); + rctxt.addWrapper(jspUri,wrapper); + } + } + } + + wrapper.service(request, response, precompile); + + } + +} diff --git a/java/org/apache/jasper/servlet/JspServletWrapper.java b/java/org/apache/jasper/servlet/JspServletWrapper.java index 05f5efabb..45187b73c 100644 --- a/java/org/apache/jasper/servlet/JspServletWrapper.java +++ b/java/org/apache/jasper/servlet/JspServletWrapper.java @@ -1,530 +1,530 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.servlet; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import javax.servlet.Servlet; -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.SingleThreadModel; -import javax.servlet.UnavailableException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.jsp.tagext.TagInfo; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.Options; -import org.apache.jasper.compiler.ErrorDispatcher; -import org.apache.jasper.compiler.JavacErrorDetail; -import org.apache.jasper.compiler.JspRuntimeContext; -import org.apache.jasper.compiler.Localizer; -import org.apache.jasper.runtime.JspSourceDependent; - -/** - * The JSP engine (a.k.a Jasper). - * - * The servlet container is responsible for providing a - * URLClassLoader for the web application context Jasper - * is being used in. Jasper will try get the Tomcat - * ServletContext attribute for its ServletContext class - * loader, if that fails, it uses the parent class loader. - * In either case, it must be a URLClassLoader. - * - * @author Anil K. Vijendran - * @author Harish Prabandham - * @author Remy Maucherat - * @author Kin-man Chung - * @author Glenn Nielsen - * @author Tim Fennell - */ - -public class JspServletWrapper { - - // Logger - private Log log = LogFactory.getLog(JspServletWrapper.class); - - private Servlet theServlet; - private String jspUri; - private Class servletClass; - private Class tagHandlerClass; - private JspCompilationContext ctxt; - private long available = 0L; - private ServletConfig config; - private Options options; - private boolean firstTime = true; - private boolean reload = true; - private boolean isTagFile; - private int tripCount; - private JasperException compileException; - private long servletClassLastModifiedTime; - private long lastModificationTest = 0L; - - /* - * JspServletWrapper for JSP pages. - */ - JspServletWrapper(ServletConfig config, Options options, String jspUri, - boolean isErrorPage, JspRuntimeContext rctxt) - throws JasperException { - - this.isTagFile = false; - this.config = config; - this.options = options; - this.jspUri = jspUri; - ctxt = new JspCompilationContext(jspUri, isErrorPage, options, - config.getServletContext(), - this, rctxt); - } - - /* - * JspServletWrapper for tag files. - */ - public JspServletWrapper(ServletContext servletContext, - Options options, - String tagFilePath, - TagInfo tagInfo, - JspRuntimeContext rctxt, - URL tagFileJarUrl) - throws JasperException { - - this.isTagFile = true; - this.config = null; // not used - this.options = options; - this.jspUri = tagFilePath; - this.tripCount = 0; - ctxt = new JspCompilationContext(jspUri, tagInfo, options, - servletContext, this, rctxt, - tagFileJarUrl); - } - - public JspCompilationContext getJspEngineContext() { - return ctxt; - } - - public void setReload(boolean reload) { - this.reload = reload; - } - - public Servlet getServlet() - throws ServletException, IOException, FileNotFoundException - { - if (reload) { - synchronized (this) { - // Synchronizing on jsw enables simultaneous loading - // of different pages, but not the same page. - if (reload) { - // This is to maintain the original protocol. - destroy(); - - try { - servletClass = ctxt.load(); - theServlet = (Servlet) servletClass.newInstance(); - } catch( IllegalAccessException ex1 ) { - throw new JasperException( ex1 ); - } catch( InstantiationException ex ) { - throw new JasperException( ex ); - } - - theServlet.init(config); - - if (!firstTime) { - ctxt.getRuntimeContext().incrementJspReloadCount(); - } - - reload = false; - } - } - } - return theServlet; - } - - public ServletContext getServletContext() { - return config.getServletContext(); - } - - /** - * Sets the compilation exception for this JspServletWrapper. - * - * @param je The compilation exception - */ - public void setCompilationException(JasperException je) { - this.compileException = je; - } - - /** - * Sets the last-modified time of the servlet class file associated with - * this JspServletWrapper. - * - * @param lastModified Last-modified time of servlet class - */ - public void setServletClassLastModifiedTime(long lastModified) { - if (this.servletClassLastModifiedTime < lastModified) { - synchronized (this) { - if (this.servletClassLastModifiedTime < lastModified) { - this.servletClassLastModifiedTime = lastModified; - reload = true; - } - } - } - } - - /** - * Compile (if needed) and load a tag file - */ - public Class loadTagFile() throws JasperException { - - try { - if (ctxt.isRemoved()) { - throw new FileNotFoundException(jspUri); - } - if (options.getDevelopment() || firstTime ) { - synchronized (this) { - firstTime = false; - ctxt.compile(); - } - } else { - if (compileException != null) { - throw compileException; - } - } - - if (reload) { - tagHandlerClass = ctxt.load(); - } - } catch (FileNotFoundException ex) { - throw new JasperException(ex); - } - - return tagHandlerClass; - } - - /** - * Compile and load a prototype for the Tag file. This is needed - * when compiling tag files with circular dependencies. A prototpe - * (skeleton) with no dependencies on other other tag files is - * generated and compiled. - */ - public Class loadTagFilePrototype() throws JasperException { - - ctxt.setPrototypeMode(true); - try { - return loadTagFile(); - } finally { - ctxt.setPrototypeMode(false); - } - } - - /** - * Get a list of files that the current page has source dependency on. - */ - public java.util.List getDependants() { - try { - Object target; - if (isTagFile) { - if (reload) { - tagHandlerClass = ctxt.load(); - } - target = tagHandlerClass.newInstance(); - } else { - target = getServlet(); - } - if (target != null && target instanceof JspSourceDependent) { - return ((java.util.List) ((JspSourceDependent) target).getDependants()); - } - } catch (Throwable ex) { - } - return null; - } - - public boolean isTagFile() { - return this.isTagFile; - } - - public int incTripCount() { - return tripCount++; - } - - public int decTripCount() { - return tripCount--; - } - - public void service(HttpServletRequest request, - HttpServletResponse response, - boolean precompile) - throws ServletException, IOException, FileNotFoundException { - try { - - if (ctxt.isRemoved()) { - throw new FileNotFoundException(jspUri); - } - - if ((available > 0L) && (available < Long.MAX_VALUE)) { - response.setDateHeader("Retry-After", available); - response.sendError - (HttpServletResponse.SC_SERVICE_UNAVAILABLE, - Localizer.getMessage("jsp.error.unavailable")); - } - - /* - * (1) Compile - */ - if (options.getDevelopment() || firstTime ) { - synchronized (this) { - firstTime = false; - - // The following sets reload to true, if necessary - ctxt.compile(); - } - } else { - if (compileException != null) { - // Throw cached compilation exception - throw compileException; - } - } - - /* - * (2) (Re)load servlet class file - */ - getServlet(); - - // If a page is to be precompiled only, return. - if (precompile) { - return; - } - - /* - * (3) Service request - */ - if (theServlet instanceof SingleThreadModel) { - // sync on the wrapper so that the freshness - // of the page is determined right before servicing - synchronized (this) { - theServlet.service(request, response); - } - } else { - theServlet.service(request, response); - } - - } catch (UnavailableException ex) { - String includeRequestUri = (String) - request.getAttribute("javax.servlet.include.request_uri"); - if (includeRequestUri != null) { - // This file was included. Throw an exception as - // a response.sendError() will be ignored by the - // servlet engine. - throw ex; - } else { - int unavailableSeconds = ex.getUnavailableSeconds(); - if (unavailableSeconds <= 0) { - unavailableSeconds = 60; // Arbitrary default - } - available = System.currentTimeMillis() + - (unavailableSeconds * 1000L); - response.sendError - (HttpServletResponse.SC_SERVICE_UNAVAILABLE, - ex.getMessage()); - } - } catch (FileNotFoundException ex) { - ctxt.incrementRemoved(); - String includeRequestUri = (String) - request.getAttribute("javax.servlet.include.request_uri"); - if (includeRequestUri != null) { - // This file was included. Throw an exception as - // a response.sendError() will be ignored by the - // servlet engine. - throw new ServletException(ex); - } else { - try { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - ex.getMessage()); - } catch (IllegalStateException ise) { - log.error(Localizer.getMessage("jsp.error.file.not.found", - ex.getMessage()), - ex); - } - } - } catch (ServletException ex) { - if(options.getDevelopment()) { - throw handleJspException(ex); - } else { - throw ex; - } - } catch (IOException ex) { - if(options.getDevelopment()) { - throw handleJspException(ex); - } else { - throw ex; - } - } catch (IllegalStateException ex) { - if(options.getDevelopment()) { - throw handleJspException(ex); - } else { - throw ex; - } - } catch (Exception ex) { - if(options.getDevelopment()) { - throw handleJspException(ex); - } else { - throw new JasperException(ex); - } - } - } - - public void destroy() { - if (theServlet != null) { - theServlet.destroy(); - } - } - - /** - * @return Returns the lastModificationTest. - */ - public long getLastModificationTest() { - return lastModificationTest; - } - /** - * @param lastModificationTest The lastModificationTest to set. - */ - public void setLastModificationTest(long lastModificationTest) { - this.lastModificationTest = lastModificationTest; - } - - /** - *

        Attempts to construct a JasperException that contains helpful information - * about what went wrong. Uses the JSP compiler system to translate the line - * number in the generated servlet that originated the exception to a line - * number in the JSP. Then constructs an exception containing that - * information, and a snippet of the JSP to help debugging. - * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and - * http://www.tfenne.com/jasper/ for more details. - *

        - * - * @param ex the exception that was the cause of the problem. - * @return a JasperException with more detailed information - */ - protected JasperException handleJspException(Exception ex) { - try { - Throwable realException = ex; - if (ex instanceof ServletException) { - realException = ((ServletException) ex).getRootCause(); - } - - // First identify the stack frame in the trace that represents the JSP - StackTraceElement[] frames = realException.getStackTrace(); - StackTraceElement jspFrame = null; - - for (int i=0; i - jspLines[jspLineNumber-1].lastIndexOf("%>")) { - String javaLine = javaLines[javaLineNumber-1].trim(); - - for (int i=jspLineNumber-1; i 0L) && (available < Long.MAX_VALUE)) { + response.setDateHeader("Retry-After", available); + response.sendError + (HttpServletResponse.SC_SERVICE_UNAVAILABLE, + Localizer.getMessage("jsp.error.unavailable")); + } + + /* + * (1) Compile + */ + if (options.getDevelopment() || firstTime ) { + synchronized (this) { + firstTime = false; + + // The following sets reload to true, if necessary + ctxt.compile(); + } + } else { + if (compileException != null) { + // Throw cached compilation exception + throw compileException; + } + } + + /* + * (2) (Re)load servlet class file + */ + getServlet(); + + // If a page is to be precompiled only, return. + if (precompile) { + return; + } + + /* + * (3) Service request + */ + if (theServlet instanceof SingleThreadModel) { + // sync on the wrapper so that the freshness + // of the page is determined right before servicing + synchronized (this) { + theServlet.service(request, response); + } + } else { + theServlet.service(request, response); + } + + } catch (UnavailableException ex) { + String includeRequestUri = (String) + request.getAttribute("javax.servlet.include.request_uri"); + if (includeRequestUri != null) { + // This file was included. Throw an exception as + // a response.sendError() will be ignored by the + // servlet engine. + throw ex; + } else { + int unavailableSeconds = ex.getUnavailableSeconds(); + if (unavailableSeconds <= 0) { + unavailableSeconds = 60; // Arbitrary default + } + available = System.currentTimeMillis() + + (unavailableSeconds * 1000L); + response.sendError + (HttpServletResponse.SC_SERVICE_UNAVAILABLE, + ex.getMessage()); + } + } catch (FileNotFoundException ex) { + ctxt.incrementRemoved(); + String includeRequestUri = (String) + request.getAttribute("javax.servlet.include.request_uri"); + if (includeRequestUri != null) { + // This file was included. Throw an exception as + // a response.sendError() will be ignored by the + // servlet engine. + throw new ServletException(ex); + } else { + try { + response.sendError(HttpServletResponse.SC_NOT_FOUND, + ex.getMessage()); + } catch (IllegalStateException ise) { + log.error(Localizer.getMessage("jsp.error.file.not.found", + ex.getMessage()), + ex); + } + } + } catch (ServletException ex) { + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } + } catch (IOException ex) { + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } + } catch (IllegalStateException ex) { + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw ex; + } + } catch (Exception ex) { + if(options.getDevelopment()) { + throw handleJspException(ex); + } else { + throw new JasperException(ex); + } + } + } + + public void destroy() { + if (theServlet != null) { + theServlet.destroy(); + } + } + + /** + * @return Returns the lastModificationTest. + */ + public long getLastModificationTest() { + return lastModificationTest; + } + /** + * @param lastModificationTest The lastModificationTest to set. + */ + public void setLastModificationTest(long lastModificationTest) { + this.lastModificationTest = lastModificationTest; + } + + /** + *

        Attempts to construct a JasperException that contains helpful information + * about what went wrong. Uses the JSP compiler system to translate the line + * number in the generated servlet that originated the exception to a line + * number in the JSP. Then constructs an exception containing that + * information, and a snippet of the JSP to help debugging. + * Please see http://issues.apache.org/bugzilla/show_bug.cgi?id=37062 and + * http://www.tfenne.com/jasper/ for more details. + *

        + * + * @param ex the exception that was the cause of the problem. + * @return a JasperException with more detailed information + */ + protected JasperException handleJspException(Exception ex) { + try { + Throwable realException = ex; + if (ex instanceof ServletException) { + realException = ((ServletException) ex).getRootCause(); + } + + // First identify the stack frame in the trace that represents the JSP + StackTraceElement[] frames = realException.getStackTrace(); + StackTraceElement jspFrame = null; + + for (int i=0; i + jspLines[jspLineNumber-1].lastIndexOf("%>")) { + String javaLine = javaLines[javaLineNumber-1].trim(); + + for (int i=jspLineNumber-1; i - - - - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/java/org/apache/jasper/tagplugins/jstl/Util.java b/java/org/apache/jasper/tagplugins/jstl/Util.java index 410eb7640..99175f9ca 100644 --- a/java/org/apache/jasper/tagplugins/jstl/Util.java +++ b/java/org/apache/jasper/tagplugins/jstl/Util.java @@ -1,325 +1,325 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.io.UnsupportedEncodingException; -import java.util.Locale; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.servlet.jsp.JspException; -import javax.servlet.jsp.JspTagException; -import javax.servlet.jsp.PageContext; - -/** - * Util contains some often used consts, static methods and embedded class - * to support the JSTL tag plugin. - */ - -public class Util { - - public static final String VALID_SCHEME_CHAR = - "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"; - - public static final String DEFAULT_ENCODING = - "ISO-8859-1"; - - public static final int HIGHEST_SPECIAL = '>'; - - public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; - - static { - specialCharactersRepresentation['&'] = "&".toCharArray(); - specialCharactersRepresentation['<'] = "<".toCharArray(); - specialCharactersRepresentation['>'] = ">".toCharArray(); - specialCharactersRepresentation['"'] = """.toCharArray(); - specialCharactersRepresentation['\''] = "'".toCharArray(); - } - - /** - * Converts the given string description of a scope to the corresponding - * PageContext constant. - * - * The validity of the given scope has already been checked by the - * appropriate TLV. - * - * @param scope String description of scope - * - * @return PageContext constant corresponding to given scope description - * - * taken from org.apache.taglibs.standard.tag.common.core.Util - */ - public static int getScope(String scope){ - int ret = PageContext.PAGE_SCOPE; - - if("request".equalsIgnoreCase(scope)){ - ret = PageContext.REQUEST_SCOPE; - }else if("session".equalsIgnoreCase(scope)){ - ret = PageContext.SESSION_SCOPE; - }else if("application".equalsIgnoreCase(scope)){ - ret = PageContext.APPLICATION_SCOPE; - } - - return ret; - } - - /** - * Returns true if our current URL is absolute, - * false otherwise. - * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport - */ - public static boolean isAbsoluteUrl(String url){ - if(url == null){ - return false; - } - - int colonPos = url.indexOf(":"); - if(colonPos == -1){ - return false; - } - - for(int i=0;iurl. The session ID - * is encoded as a URL "path parameter" beginning with "jsessionid=". - * We thus remove anything we find between ";jsessionid=" (inclusive) - * and either EOS or a subsequent ';' (exclusive). - * - * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport - */ - public static String stripSession(String url) { - StringBuffer u = new StringBuffer(url); - int sessionStart; - while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) { - int sessionEnd = u.toString().indexOf(";", sessionStart + 1); - if (sessionEnd == -1) - sessionEnd = u.toString().indexOf("?", sessionStart + 1); - if (sessionEnd == -1) // still - sessionEnd = u.length(); - u.delete(sessionStart, sessionEnd); - } - return u.toString(); - } - - - /** - * Performs the following substring replacements - * (to facilitate output to XML/HTML pages): - * - * & -> & - * < -> < - * > -> > - * " -> " - * ' -> ' - * - * See also OutSupport.writeEscapedXml(). - * - * taken from org.apache.taglibs.standard.tag.common.core.Util - */ - public static String escapeXml(String buffer) { - int start = 0; - int length = buffer.length(); - char[] arrayBuffer = buffer.toCharArray(); - StringBuffer escapedBuffer = null; - - for (int i = 0; i < length; i++) { - char c = arrayBuffer[i]; - if (c <= HIGHEST_SPECIAL) { - char[] escaped = specialCharactersRepresentation[c]; - if (escaped != null) { - // create StringBuffer to hold escaped xml string - if (start == 0) { - escapedBuffer = new StringBuffer(length + 5); - } - // add unescaped portion - if (start < i) { - escapedBuffer.append(arrayBuffer,start,i-start); - } - start = i + 1; - // add escaped xml - escapedBuffer.append(escaped); - } - } - } - // no xml escaping was necessary - if (start == 0) { - return buffer; - } - // add rest of unescaped portion - if (start < length) { - escapedBuffer.append(arrayBuffer,start,length-start); - } - return escapedBuffer.toString(); - } - - /** Utility methods - * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport - */ - public static String resolveUrl( - String url, String context, PageContext pageContext) - throws JspException { - // don't touch absolute URLs - if (isAbsoluteUrl(url)) - return url; - - // normalize relative URLs against a context root - HttpServletRequest request = - (HttpServletRequest) pageContext.getRequest(); - if (context == null) { - if (url.startsWith("/")) - return (request.getContextPath() + url); - else - return url; - } else { - if (!context.startsWith("/") || !url.startsWith("/")) { - throw new JspTagException( - "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\"."); - } - if (context.equals("/")) { - // Don't produce string starting with '//', many - // browsers interpret this as host name, not as - // path on same host. - return url; - } else { - return (context + url); - } - } - } - - /** Wraps responses to allow us to retrieve results as Strings. - * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport - */ - public static class ImportResponseWrapper extends HttpServletResponseWrapper{ - - private StringWriter sw = new StringWriter(); - private ByteArrayOutputStream bos = new ByteArrayOutputStream(); - private ServletOutputStream sos = new ServletOutputStream() { - public void write(int b) throws IOException { - bos.write(b); - } - }; - private boolean isWriterUsed; - private boolean isStreamUsed; - private int status = 200; - private String charEncoding; - - public ImportResponseWrapper(HttpServletResponse arg0) { - super(arg0); - // TODO Auto-generated constructor stub - } - - public PrintWriter getWriter() { - if (isStreamUsed) - throw new IllegalStateException("Unexpected internal error during <import>: " + - "Target servlet called getWriter(), then getOutputStream()"); - isWriterUsed = true; - return new PrintWriter(sw); - } - - public ServletOutputStream getOutputStream() { - if (isWriterUsed) - throw new IllegalStateException("Unexpected internal error during <import>: " + - "Target servlet called getOutputStream(), then getWriter()"); - isStreamUsed = true; - return sos; - } - - /** Has no effect. */ - public void setContentType(String x) { - // ignore - } - - /** Has no effect. */ - public void setLocale(Locale x) { - // ignore - } - - public void setStatus(int status) { - this.status = status; - } - - public int getStatus() { - return status; - } - - public String getCharEncoding(){ - return this.charEncoding; - } - - public void setCharEncoding(String ce){ - this.charEncoding = ce; - } - - public String getString() throws UnsupportedEncodingException { - if (isWriterUsed) - return sw.toString(); - else if (isStreamUsed) { - if (this.charEncoding != null && !this.charEncoding.equals("")) - return bos.toString(charEncoding); - else - return bos.toString("ISO-8859-1"); - } else - return ""; // target didn't write anything - } - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.io.UnsupportedEncodingException; +import java.util.Locale; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; +import javax.servlet.jsp.JspException; +import javax.servlet.jsp.JspTagException; +import javax.servlet.jsp.PageContext; + +/** + * Util contains some often used consts, static methods and embedded class + * to support the JSTL tag plugin. + */ + +public class Util { + + public static final String VALID_SCHEME_CHAR = + "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"; + + public static final String DEFAULT_ENCODING = + "ISO-8859-1"; + + public static final int HIGHEST_SPECIAL = '>'; + + public static char[][] specialCharactersRepresentation = new char[HIGHEST_SPECIAL + 1][]; + + static { + specialCharactersRepresentation['&'] = "&".toCharArray(); + specialCharactersRepresentation['<'] = "<".toCharArray(); + specialCharactersRepresentation['>'] = ">".toCharArray(); + specialCharactersRepresentation['"'] = """.toCharArray(); + specialCharactersRepresentation['\''] = "'".toCharArray(); + } + + /** + * Converts the given string description of a scope to the corresponding + * PageContext constant. + * + * The validity of the given scope has already been checked by the + * appropriate TLV. + * + * @param scope String description of scope + * + * @return PageContext constant corresponding to given scope description + * + * taken from org.apache.taglibs.standard.tag.common.core.Util + */ + public static int getScope(String scope){ + int ret = PageContext.PAGE_SCOPE; + + if("request".equalsIgnoreCase(scope)){ + ret = PageContext.REQUEST_SCOPE; + }else if("session".equalsIgnoreCase(scope)){ + ret = PageContext.SESSION_SCOPE; + }else if("application".equalsIgnoreCase(scope)){ + ret = PageContext.APPLICATION_SCOPE; + } + + return ret; + } + + /** + * Returns true if our current URL is absolute, + * false otherwise. + * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport + */ + public static boolean isAbsoluteUrl(String url){ + if(url == null){ + return false; + } + + int colonPos = url.indexOf(":"); + if(colonPos == -1){ + return false; + } + + for(int i=0;iurl. The session ID + * is encoded as a URL "path parameter" beginning with "jsessionid=". + * We thus remove anything we find between ";jsessionid=" (inclusive) + * and either EOS or a subsequent ';' (exclusive). + * + * taken from org.apache.taglibs.standard.tag.common.core.ImportSupport + */ + public static String stripSession(String url) { + StringBuffer u = new StringBuffer(url); + int sessionStart; + while ((sessionStart = u.toString().indexOf(";jsessionid=")) != -1) { + int sessionEnd = u.toString().indexOf(";", sessionStart + 1); + if (sessionEnd == -1) + sessionEnd = u.toString().indexOf("?", sessionStart + 1); + if (sessionEnd == -1) // still + sessionEnd = u.length(); + u.delete(sessionStart, sessionEnd); + } + return u.toString(); + } + + + /** + * Performs the following substring replacements + * (to facilitate output to XML/HTML pages): + * + * & -> & + * < -> < + * > -> > + * " -> " + * ' -> ' + * + * See also OutSupport.writeEscapedXml(). + * + * taken from org.apache.taglibs.standard.tag.common.core.Util + */ + public static String escapeXml(String buffer) { + int start = 0; + int length = buffer.length(); + char[] arrayBuffer = buffer.toCharArray(); + StringBuffer escapedBuffer = null; + + for (int i = 0; i < length; i++) { + char c = arrayBuffer[i]; + if (c <= HIGHEST_SPECIAL) { + char[] escaped = specialCharactersRepresentation[c]; + if (escaped != null) { + // create StringBuffer to hold escaped xml string + if (start == 0) { + escapedBuffer = new StringBuffer(length + 5); + } + // add unescaped portion + if (start < i) { + escapedBuffer.append(arrayBuffer,start,i-start); + } + start = i + 1; + // add escaped xml + escapedBuffer.append(escaped); + } + } + } + // no xml escaping was necessary + if (start == 0) { + return buffer; + } + // add rest of unescaped portion + if (start < length) { + escapedBuffer.append(arrayBuffer,start,length-start); + } + return escapedBuffer.toString(); + } + + /** Utility methods + * taken from org.apache.taglibs.standard.tag.common.core.UrlSupport + */ + public static String resolveUrl( + String url, String context, PageContext pageContext) + throws JspException { + // don't touch absolute URLs + if (isAbsoluteUrl(url)) + return url; + + // normalize relative URLs against a context root + HttpServletRequest request = + (HttpServletRequest) pageContext.getRequest(); + if (context == null) { + if (url.startsWith("/")) + return (request.getContextPath() + url); + else + return url; + } else { + if (!context.startsWith("/") || !url.startsWith("/")) { + throw new JspTagException( + "In URL tags, when the \"context\" attribute is specified, values of both \"context\" and \"url\" must start with \"/\"."); + } + if (context.equals("/")) { + // Don't produce string starting with '//', many + // browsers interpret this as host name, not as + // path on same host. + return url; + } else { + return (context + url); + } + } + } + + /** Wraps responses to allow us to retrieve results as Strings. + * mainly taken from org.apache.taglibs.standard.tag.common.core.importSupport + */ + public static class ImportResponseWrapper extends HttpServletResponseWrapper{ + + private StringWriter sw = new StringWriter(); + private ByteArrayOutputStream bos = new ByteArrayOutputStream(); + private ServletOutputStream sos = new ServletOutputStream() { + public void write(int b) throws IOException { + bos.write(b); + } + }; + private boolean isWriterUsed; + private boolean isStreamUsed; + private int status = 200; + private String charEncoding; + + public ImportResponseWrapper(HttpServletResponse arg0) { + super(arg0); + // TODO Auto-generated constructor stub + } + + public PrintWriter getWriter() { + if (isStreamUsed) + throw new IllegalStateException("Unexpected internal error during <import>: " + + "Target servlet called getWriter(), then getOutputStream()"); + isWriterUsed = true; + return new PrintWriter(sw); + } + + public ServletOutputStream getOutputStream() { + if (isWriterUsed) + throw new IllegalStateException("Unexpected internal error during <import>: " + + "Target servlet called getOutputStream(), then getWriter()"); + isStreamUsed = true; + return sos; + } + + /** Has no effect. */ + public void setContentType(String x) { + // ignore + } + + /** Has no effect. */ + public void setLocale(Locale x) { + // ignore + } + + public void setStatus(int status) { + this.status = status; + } + + public int getStatus() { + return status; + } + + public String getCharEncoding(){ + return this.charEncoding; + } + + public void setCharEncoding(String ce){ + this.charEncoding = ce; + } + + public String getString() throws UnsupportedEncodingException { + if (isWriterUsed) + return sw.toString(); + else if (isStreamUsed) { + if (this.charEncoding != null && !this.charEncoding.equals("")) + return bos.toString(charEncoding); + else + return bos.toString("ISO-8859-1"); + } else + return ""; // target didn't write anything + } + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Catch.java b/java/org/apache/jasper/tagplugins/jstl/core/Catch.java index dd2c7aeb3..136fd2949 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Catch.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Catch.java @@ -1,71 +1,71 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - -public class Catch implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //flag for the existence of the var attribute - boolean hasVar = ctxt.isAttributeSpecified("var"); - - //temp name for exception and caught - String exceptionName = ctxt.getTemporaryVariableName(); - String caughtName = ctxt.getTemporaryVariableName(); - - //main part to generate code - ctxt.generateJavaSource("boolean " + caughtName + " = false;"); - ctxt.generateJavaSource("try{"); - ctxt.generateBody(); - ctxt.generateJavaSource("}"); - - //do catch - ctxt.generateJavaSource("catch(Throwable " + exceptionName + "){"); - - //if the var specified, the exception object should - //be set to the attribute "var" defines in page scope - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", " - + exceptionName + ", PageContext.PAGE_SCOPE);"); - } - - //whenever there's exception caught, - //the flag caught should be set true; - ctxt.generateJavaSource(" " + caughtName + " = true;"); - ctxt.generateJavaSource("}"); - - //do finally - ctxt.generateJavaSource("finally{"); - - //if var specified, the attribute it defines - //in page scope should be removed - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource(" if(!" + caughtName + "){"); - ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\", PageContext.PAGE_SCOPE);"); - ctxt.generateJavaSource(" }"); - } - - ctxt.generateJavaSource("}"); - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + +public class Catch implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //flag for the existence of the var attribute + boolean hasVar = ctxt.isAttributeSpecified("var"); + + //temp name for exception and caught + String exceptionName = ctxt.getTemporaryVariableName(); + String caughtName = ctxt.getTemporaryVariableName(); + + //main part to generate code + ctxt.generateJavaSource("boolean " + caughtName + " = false;"); + ctxt.generateJavaSource("try{"); + ctxt.generateBody(); + ctxt.generateJavaSource("}"); + + //do catch + ctxt.generateJavaSource("catch(Throwable " + exceptionName + "){"); + + //if the var specified, the exception object should + //be set to the attribute "var" defines in page scope + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", " + + exceptionName + ", PageContext.PAGE_SCOPE);"); + } + + //whenever there's exception caught, + //the flag caught should be set true; + ctxt.generateJavaSource(" " + caughtName + " = true;"); + ctxt.generateJavaSource("}"); + + //do finally + ctxt.generateJavaSource("finally{"); + + //if var specified, the attribute it defines + //in page scope should be removed + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource(" if(!" + caughtName + "){"); + ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\", PageContext.PAGE_SCOPE);"); + ctxt.generateJavaSource(" }"); + } + + ctxt.generateJavaSource("}"); + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Choose.java b/java/org/apache/jasper/tagplugins/jstl/core/Choose.java index 2810ee719..f65354d4a 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Choose.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Choose.java @@ -1,33 +1,33 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.*; - -public final class Choose implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - // Not much to do here, much of the work will be done in the - // containing tags, and . - - ctxt.generateBody(); - // See comments in When.java for the reason "}" is generated here. - ctxt.generateJavaSource("}"); - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.*; + +public final class Choose implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + // Not much to do here, much of the work will be done in the + // containing tags, and . + + ctxt.generateBody(); + // See comments in When.java for the reason "}" is generated here. + ctxt.generateJavaSource("}"); + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/ForEach.java b/java/org/apache/jasper/tagplugins/jstl/core/ForEach.java index 70dd301cc..4d58e845a 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/ForEach.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/ForEach.java @@ -1,343 +1,343 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.*; - -public final class ForEach implements TagPlugin { - - private boolean hasVar, hasBegin, hasEnd, hasStep; - - public void doTag(TagPluginContext ctxt) { - - String index = null; - - boolean hasVarStatus = ctxt.isAttributeSpecified("varStatus"); - if (hasVarStatus) { - ctxt.dontUseTagPlugin(); - return; - } - - hasVar = ctxt.isAttributeSpecified("var"); - hasBegin = ctxt.isAttributeSpecified("begin"); - hasEnd = ctxt.isAttributeSpecified("end"); - hasStep = ctxt.isAttributeSpecified("step"); - - boolean hasItems = ctxt.isAttributeSpecified("items"); - if (hasItems) { - doCollection(ctxt); - return; - } - - // We must have a begin and end attributes - index = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("for (int " + index + " = "); - ctxt.generateAttribute("begin"); - ctxt.generateJavaSource("; " + index + " <= "); - ctxt.generateAttribute("end"); - if (hasStep) { - ctxt.generateJavaSource("; " + index + "+="); - ctxt.generateAttribute("step"); - ctxt.generateJavaSource(") {"); - } - else { - ctxt.generateJavaSource("; " + index + "++) {"); - } - - // If var is specified and the body contains an EL, then sycn - // the var attribute - if (hasVar /* && ctxt.hasEL() */) { - ctxt.generateJavaSource("_jspx_page_context.setAttribute("); - ctxt.generateAttribute("var"); - ctxt.generateJavaSource(", String.valueOf(" + index + "));"); - } - ctxt.generateBody(); - ctxt.generateJavaSource("}"); - } - - /** - * Generate codes for Collections - * The pseudo code is: - */ - private void doCollection(TagPluginContext ctxt) { - - ctxt.generateImport("java.util.*"); - generateIterators(ctxt); - - String itemsV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("Object " + itemsV + "= "); - ctxt.generateAttribute("items"); - ctxt.generateJavaSource(";"); - - String indexV=null, beginV=null, endV=null, stepV=null; - if (hasBegin) { - beginV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("int " + beginV + " = "); - ctxt.generateAttribute("begin"); - ctxt.generateJavaSource(";"); - } - if (hasEnd) { - indexV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("int " + indexV + " = 0;"); - endV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("int " + endV + " = "); - ctxt.generateAttribute("end"); - ctxt.generateJavaSource(";"); - } - if (hasStep) { - stepV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("int " + stepV + " = "); - ctxt.generateAttribute("step"); - ctxt.generateJavaSource(";"); - } - - String iterV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("Iterator " + iterV + " = null;"); - // Object[] - ctxt.generateJavaSource("if (" + itemsV + " instanceof Object[])"); - ctxt.generateJavaSource(iterV + "=toIterator((Object[])" + itemsV + ");"); - // boolean[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof boolean[])"); - ctxt.generateJavaSource(iterV + "=toIterator((boolean[])" + itemsV + ");"); - // byte[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof byte[])"); - ctxt.generateJavaSource(iterV + "=toIterator((byte[])" + itemsV + ");"); - // char[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof char[])"); - ctxt.generateJavaSource(iterV + "=toIterator((char[])" + itemsV + ");"); - // short[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof short[])"); - ctxt.generateJavaSource(iterV + "=toIterator((short[])" + itemsV + ");"); - // int[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof int[])"); - ctxt.generateJavaSource(iterV + "=toIterator((int[])" + itemsV + ");"); - // long[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof long[])"); - ctxt.generateJavaSource(iterV + "=toIterator((long[])" + itemsV + ");"); - // float[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof float[])"); - ctxt.generateJavaSource(iterV + "=toIterator((float[])" + itemsV + ");"); - // double[] - ctxt.generateJavaSource("else if (" + itemsV + " instanceof double[])"); - ctxt.generateJavaSource(iterV + "=toIterator((double[])" + itemsV + ");"); - - // Collection - ctxt.generateJavaSource("else if (" + itemsV + " instanceof Collection)"); - ctxt.generateJavaSource(iterV + "=((Collection)" + itemsV + ").iterator();"); - - // Iterator - ctxt.generateJavaSource("else if (" + itemsV + " instanceof Iterator)"); - ctxt.generateJavaSource(iterV + "=(Iterator)" + itemsV + ";"); - - // Enumeration - ctxt.generateJavaSource("else if (" + itemsV + " instanceof Enumeration)"); - ctxt.generateJavaSource(iterV + "=toIterator((Enumeration)" + itemsV + ");"); - - // Map - ctxt.generateJavaSource("else if (" + itemsV + " instanceof Map)"); - ctxt.generateJavaSource(iterV + "=((Map)" + itemsV + ").entrySet().iterator();"); - - if (hasBegin) { - String tV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("for (int " + tV + "=" + beginV + ";" + - tV + ">0 && " + iterV + ".hasNext(); " + - tV + "--)"); - ctxt.generateJavaSource(iterV + ".next();"); - } - - ctxt.generateJavaSource("while (" + iterV + ".hasNext()){"); - if (hasVar) { - ctxt.generateJavaSource("_jspx_page_context.setAttribute("); - ctxt.generateAttribute("var"); - ctxt.generateJavaSource(", " + iterV + ".next());"); - } - - ctxt.generateBody(); - - if (hasStep) { - String tV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("for (int " + tV + "=" + stepV + "-1;" + - tV + ">0 && " + iterV + ".hasNext(); " + - tV + "--)"); - ctxt.generateJavaSource(iterV + ".next();"); - } - if (hasEnd) { - if (hasStep) { - ctxt.generateJavaSource(indexV + "+=" + stepV + ";"); - } - else { - ctxt.generateJavaSource(indexV + "++;"); - } - if (hasBegin) { - ctxt.generateJavaSource("if(" + beginV + "+" + indexV + - ">"+ endV + ")"); - } - else { - ctxt.generateJavaSource("if(" + indexV + ">" + endV + ")"); - } - ctxt.generateJavaSource("break;"); - } - ctxt.generateJavaSource("}"); // while - } - - /** - * Generate iterators for data types supported in items - */ - private void generateIterators(TagPluginContext ctxt) { - - // Object[] - ctxt.generateDeclaration("ObjectArrayIterator", - "private Iterator toIterator(final Object[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return a[index++];}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // boolean[] - ctxt.generateDeclaration("booleanArrayIterator", - "private Iterator toIterator(final boolean[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Boolean(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // byte[] - ctxt.generateDeclaration("byteArrayIterator", - "private Iterator toIterator(final byte[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Byte(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // char[] - ctxt.generateDeclaration("charArrayIterator", - "private Iterator toIterator(final char[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Character(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // short[] - ctxt.generateDeclaration("shortArrayIterator", - "private Iterator toIterator(final short[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Short(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // int[] - ctxt.generateDeclaration("intArrayIterator", - "private Iterator toIterator(final int[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Integer(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // long[] - ctxt.generateDeclaration("longArrayIterator", - "private Iterator toIterator(final long[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Long(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // float[] - ctxt.generateDeclaration("floatArrayIterator", - "private Iterator toIterator(final float[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Float(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // double[] - ctxt.generateDeclaration("doubleArrayIterator", - "private Iterator toIterator(final double[] a){\n" + - " return (new Iterator() {\n" + - " int index=0;\n" + - " public boolean hasNext() {\n" + - " return index < a.length;}\n" + - " public Object next() {\n" + - " return new Double(a[index++]);}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - // Enumeration - ctxt.generateDeclaration("enumIterator", - "private Iterator toIterator(final Enumeration e){\n" + - " return (new Iterator() {\n" + - " public boolean hasNext() {\n" + - " return e.hasMoreElements();}\n" + - " public Object next() {\n" + - " return e.nextElement();}\n" + - " public void remove() {}\n" + - " });\n" + - "}" - ); - - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.*; + +public final class ForEach implements TagPlugin { + + private boolean hasVar, hasBegin, hasEnd, hasStep; + + public void doTag(TagPluginContext ctxt) { + + String index = null; + + boolean hasVarStatus = ctxt.isAttributeSpecified("varStatus"); + if (hasVarStatus) { + ctxt.dontUseTagPlugin(); + return; + } + + hasVar = ctxt.isAttributeSpecified("var"); + hasBegin = ctxt.isAttributeSpecified("begin"); + hasEnd = ctxt.isAttributeSpecified("end"); + hasStep = ctxt.isAttributeSpecified("step"); + + boolean hasItems = ctxt.isAttributeSpecified("items"); + if (hasItems) { + doCollection(ctxt); + return; + } + + // We must have a begin and end attributes + index = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("for (int " + index + " = "); + ctxt.generateAttribute("begin"); + ctxt.generateJavaSource("; " + index + " <= "); + ctxt.generateAttribute("end"); + if (hasStep) { + ctxt.generateJavaSource("; " + index + "+="); + ctxt.generateAttribute("step"); + ctxt.generateJavaSource(") {"); + } + else { + ctxt.generateJavaSource("; " + index + "++) {"); + } + + // If var is specified and the body contains an EL, then sycn + // the var attribute + if (hasVar /* && ctxt.hasEL() */) { + ctxt.generateJavaSource("_jspx_page_context.setAttribute("); + ctxt.generateAttribute("var"); + ctxt.generateJavaSource(", String.valueOf(" + index + "));"); + } + ctxt.generateBody(); + ctxt.generateJavaSource("}"); + } + + /** + * Generate codes for Collections + * The pseudo code is: + */ + private void doCollection(TagPluginContext ctxt) { + + ctxt.generateImport("java.util.*"); + generateIterators(ctxt); + + String itemsV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("Object " + itemsV + "= "); + ctxt.generateAttribute("items"); + ctxt.generateJavaSource(";"); + + String indexV=null, beginV=null, endV=null, stepV=null; + if (hasBegin) { + beginV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("int " + beginV + " = "); + ctxt.generateAttribute("begin"); + ctxt.generateJavaSource(";"); + } + if (hasEnd) { + indexV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("int " + indexV + " = 0;"); + endV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("int " + endV + " = "); + ctxt.generateAttribute("end"); + ctxt.generateJavaSource(";"); + } + if (hasStep) { + stepV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("int " + stepV + " = "); + ctxt.generateAttribute("step"); + ctxt.generateJavaSource(";"); + } + + String iterV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("Iterator " + iterV + " = null;"); + // Object[] + ctxt.generateJavaSource("if (" + itemsV + " instanceof Object[])"); + ctxt.generateJavaSource(iterV + "=toIterator((Object[])" + itemsV + ");"); + // boolean[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof boolean[])"); + ctxt.generateJavaSource(iterV + "=toIterator((boolean[])" + itemsV + ");"); + // byte[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof byte[])"); + ctxt.generateJavaSource(iterV + "=toIterator((byte[])" + itemsV + ");"); + // char[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof char[])"); + ctxt.generateJavaSource(iterV + "=toIterator((char[])" + itemsV + ");"); + // short[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof short[])"); + ctxt.generateJavaSource(iterV + "=toIterator((short[])" + itemsV + ");"); + // int[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof int[])"); + ctxt.generateJavaSource(iterV + "=toIterator((int[])" + itemsV + ");"); + // long[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof long[])"); + ctxt.generateJavaSource(iterV + "=toIterator((long[])" + itemsV + ");"); + // float[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof float[])"); + ctxt.generateJavaSource(iterV + "=toIterator((float[])" + itemsV + ");"); + // double[] + ctxt.generateJavaSource("else if (" + itemsV + " instanceof double[])"); + ctxt.generateJavaSource(iterV + "=toIterator((double[])" + itemsV + ");"); + + // Collection + ctxt.generateJavaSource("else if (" + itemsV + " instanceof Collection)"); + ctxt.generateJavaSource(iterV + "=((Collection)" + itemsV + ").iterator();"); + + // Iterator + ctxt.generateJavaSource("else if (" + itemsV + " instanceof Iterator)"); + ctxt.generateJavaSource(iterV + "=(Iterator)" + itemsV + ";"); + + // Enumeration + ctxt.generateJavaSource("else if (" + itemsV + " instanceof Enumeration)"); + ctxt.generateJavaSource(iterV + "=toIterator((Enumeration)" + itemsV + ");"); + + // Map + ctxt.generateJavaSource("else if (" + itemsV + " instanceof Map)"); + ctxt.generateJavaSource(iterV + "=((Map)" + itemsV + ").entrySet().iterator();"); + + if (hasBegin) { + String tV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("for (int " + tV + "=" + beginV + ";" + + tV + ">0 && " + iterV + ".hasNext(); " + + tV + "--)"); + ctxt.generateJavaSource(iterV + ".next();"); + } + + ctxt.generateJavaSource("while (" + iterV + ".hasNext()){"); + if (hasVar) { + ctxt.generateJavaSource("_jspx_page_context.setAttribute("); + ctxt.generateAttribute("var"); + ctxt.generateJavaSource(", " + iterV + ".next());"); + } + + ctxt.generateBody(); + + if (hasStep) { + String tV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("for (int " + tV + "=" + stepV + "-1;" + + tV + ">0 && " + iterV + ".hasNext(); " + + tV + "--)"); + ctxt.generateJavaSource(iterV + ".next();"); + } + if (hasEnd) { + if (hasStep) { + ctxt.generateJavaSource(indexV + "+=" + stepV + ";"); + } + else { + ctxt.generateJavaSource(indexV + "++;"); + } + if (hasBegin) { + ctxt.generateJavaSource("if(" + beginV + "+" + indexV + + ">"+ endV + ")"); + } + else { + ctxt.generateJavaSource("if(" + indexV + ">" + endV + ")"); + } + ctxt.generateJavaSource("break;"); + } + ctxt.generateJavaSource("}"); // while + } + + /** + * Generate iterators for data types supported in items + */ + private void generateIterators(TagPluginContext ctxt) { + + // Object[] + ctxt.generateDeclaration("ObjectArrayIterator", + "private Iterator toIterator(final Object[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return a[index++];}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // boolean[] + ctxt.generateDeclaration("booleanArrayIterator", + "private Iterator toIterator(final boolean[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Boolean(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // byte[] + ctxt.generateDeclaration("byteArrayIterator", + "private Iterator toIterator(final byte[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Byte(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // char[] + ctxt.generateDeclaration("charArrayIterator", + "private Iterator toIterator(final char[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Character(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // short[] + ctxt.generateDeclaration("shortArrayIterator", + "private Iterator toIterator(final short[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Short(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // int[] + ctxt.generateDeclaration("intArrayIterator", + "private Iterator toIterator(final int[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Integer(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // long[] + ctxt.generateDeclaration("longArrayIterator", + "private Iterator toIterator(final long[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Long(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // float[] + ctxt.generateDeclaration("floatArrayIterator", + "private Iterator toIterator(final float[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Float(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // double[] + ctxt.generateDeclaration("doubleArrayIterator", + "private Iterator toIterator(final double[] a){\n" + + " return (new Iterator() {\n" + + " int index=0;\n" + + " public boolean hasNext() {\n" + + " return index < a.length;}\n" + + " public Object next() {\n" + + " return new Double(a[index++]);}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + // Enumeration + ctxt.generateDeclaration("enumIterator", + "private Iterator toIterator(final Enumeration e){\n" + + " return (new Iterator() {\n" + + " public boolean hasNext() {\n" + + " return e.hasMoreElements();}\n" + + " public Object next() {\n" + + " return e.nextElement();}\n" + + " public void remove() {}\n" + + " });\n" + + "}" + ); + + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/ForTokens.java b/java/org/apache/jasper/tagplugins/jstl/core/ForTokens.java index 602bc45df..e0ac2f6f9 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/ForTokens.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/ForTokens.java @@ -1,118 +1,118 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - -public class ForTokens implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - boolean hasVar, hasVarStatus, hasBegin, hasEnd, hasStep; - - //init the flags - hasVar = ctxt.isAttributeSpecified("var"); - hasVarStatus = ctxt.isAttributeSpecified("varStatus"); - hasBegin = ctxt.isAttributeSpecified("begin"); - hasEnd = ctxt.isAttributeSpecified("end"); - hasStep = ctxt.isAttributeSpecified("step"); - - if(hasVarStatus){ - ctxt.dontUseTagPlugin(); - return; - } - - //define all the temp variables' names - String itemsName = ctxt.getTemporaryVariableName(); - String delimsName = ctxt.getTemporaryVariableName(); - String stName = ctxt.getTemporaryVariableName(); - String beginName = ctxt.getTemporaryVariableName(); - String endName = ctxt.getTemporaryVariableName(); - String stepName = ctxt.getTemporaryVariableName(); - String index = ctxt.getTemporaryVariableName(); - String temp = ctxt.getTemporaryVariableName(); - String tokensCountName = ctxt.getTemporaryVariableName(); - - //get the value of the "items" attribute - ctxt.generateJavaSource("String " + itemsName + " = (String)"); - ctxt.generateAttribute("items"); - ctxt.generateJavaSource(";"); - - //get the value of the "delim" attribute - ctxt.generateJavaSource("String " + delimsName + " = (String)"); - ctxt.generateAttribute("delims"); - ctxt.generateJavaSource(";"); - - //new a StringTokenizer Object according to the "items" and the "delim" - ctxt.generateJavaSource("java.util.StringTokenizer " + stName + " = " + - "new java.util.StringTokenizer(" + itemsName + ", " + delimsName + ");"); - - //if "begin" specified, move the token to the "begin" place - //and record the begin index. default begin place is 0. - ctxt.generateJavaSource("int " + tokensCountName + " = " + stName + ".countTokens();"); - if(hasBegin){ - ctxt.generateJavaSource("int " + beginName + " = " ); - ctxt.generateAttribute("begin"); - ctxt.generateJavaSource(";"); - ctxt.generateJavaSource("for(int " + index + " = 0; " + index + " < " + beginName + " && " + stName + ".hasMoreTokens(); " + index + "++, " + stName + ".nextToken()){}"); - }else{ - ctxt.generateJavaSource("int " + beginName + " = 0;"); - } - - //when "end" is specified, if the "end" is more than the last index, - //record the end place as the last index, otherwise, record it as "end"; - //default end place is the last index - if(hasEnd){ - ctxt.generateJavaSource("int " + endName + " = 0;" ); - ctxt.generateJavaSource("if((" + tokensCountName + " - 1) < "); - ctxt.generateAttribute("end"); - ctxt.generateJavaSource("){"); - ctxt.generateJavaSource(" " + endName + " = " + tokensCountName + " - 1;"); - ctxt.generateJavaSource("}else{"); - ctxt.generateJavaSource(" " + endName + " = "); - ctxt.generateAttribute("end"); - ctxt.generateJavaSource(";}"); - }else{ - ctxt.generateJavaSource("int " + endName + " = " + tokensCountName + " - 1;"); - } - - //get the step value from "step" if specified. - //default step value is 1. - if(hasStep){ - ctxt.generateJavaSource("int " + stepName + " = " ); - ctxt.generateAttribute("step"); - ctxt.generateJavaSource(";"); - }else{ - ctxt.generateJavaSource("int " + stepName + " = 1;"); - } - - //the loop - ctxt.generateJavaSource("for(int " + index + " = " + beginName + "; " + index + " <= " + endName + "; " + index + "++){"); - ctxt.generateJavaSource(" String " + temp + " = " + stName + ".nextToken();"); - ctxt.generateJavaSource(" if(((" + index + " - " + beginName + ") % " + stepName + ") == 0){"); - //if var specified, put the current token into the attribute "var" defines. - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", " + temp + ");"); - } - ctxt.generateBody(); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource("}"); - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + +public class ForTokens implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + boolean hasVar, hasVarStatus, hasBegin, hasEnd, hasStep; + + //init the flags + hasVar = ctxt.isAttributeSpecified("var"); + hasVarStatus = ctxt.isAttributeSpecified("varStatus"); + hasBegin = ctxt.isAttributeSpecified("begin"); + hasEnd = ctxt.isAttributeSpecified("end"); + hasStep = ctxt.isAttributeSpecified("step"); + + if(hasVarStatus){ + ctxt.dontUseTagPlugin(); + return; + } + + //define all the temp variables' names + String itemsName = ctxt.getTemporaryVariableName(); + String delimsName = ctxt.getTemporaryVariableName(); + String stName = ctxt.getTemporaryVariableName(); + String beginName = ctxt.getTemporaryVariableName(); + String endName = ctxt.getTemporaryVariableName(); + String stepName = ctxt.getTemporaryVariableName(); + String index = ctxt.getTemporaryVariableName(); + String temp = ctxt.getTemporaryVariableName(); + String tokensCountName = ctxt.getTemporaryVariableName(); + + //get the value of the "items" attribute + ctxt.generateJavaSource("String " + itemsName + " = (String)"); + ctxt.generateAttribute("items"); + ctxt.generateJavaSource(";"); + + //get the value of the "delim" attribute + ctxt.generateJavaSource("String " + delimsName + " = (String)"); + ctxt.generateAttribute("delims"); + ctxt.generateJavaSource(";"); + + //new a StringTokenizer Object according to the "items" and the "delim" + ctxt.generateJavaSource("java.util.StringTokenizer " + stName + " = " + + "new java.util.StringTokenizer(" + itemsName + ", " + delimsName + ");"); + + //if "begin" specified, move the token to the "begin" place + //and record the begin index. default begin place is 0. + ctxt.generateJavaSource("int " + tokensCountName + " = " + stName + ".countTokens();"); + if(hasBegin){ + ctxt.generateJavaSource("int " + beginName + " = " ); + ctxt.generateAttribute("begin"); + ctxt.generateJavaSource(";"); + ctxt.generateJavaSource("for(int " + index + " = 0; " + index + " < " + beginName + " && " + stName + ".hasMoreTokens(); " + index + "++, " + stName + ".nextToken()){}"); + }else{ + ctxt.generateJavaSource("int " + beginName + " = 0;"); + } + + //when "end" is specified, if the "end" is more than the last index, + //record the end place as the last index, otherwise, record it as "end"; + //default end place is the last index + if(hasEnd){ + ctxt.generateJavaSource("int " + endName + " = 0;" ); + ctxt.generateJavaSource("if((" + tokensCountName + " - 1) < "); + ctxt.generateAttribute("end"); + ctxt.generateJavaSource("){"); + ctxt.generateJavaSource(" " + endName + " = " + tokensCountName + " - 1;"); + ctxt.generateJavaSource("}else{"); + ctxt.generateJavaSource(" " + endName + " = "); + ctxt.generateAttribute("end"); + ctxt.generateJavaSource(";}"); + }else{ + ctxt.generateJavaSource("int " + endName + " = " + tokensCountName + " - 1;"); + } + + //get the step value from "step" if specified. + //default step value is 1. + if(hasStep){ + ctxt.generateJavaSource("int " + stepName + " = " ); + ctxt.generateAttribute("step"); + ctxt.generateJavaSource(";"); + }else{ + ctxt.generateJavaSource("int " + stepName + " = 1;"); + } + + //the loop + ctxt.generateJavaSource("for(int " + index + " = " + beginName + "; " + index + " <= " + endName + "; " + index + "++){"); + ctxt.generateJavaSource(" String " + temp + " = " + stName + ".nextToken();"); + ctxt.generateJavaSource(" if(((" + index + " - " + beginName + ") % " + stepName + ") == 0){"); + //if var specified, put the current token into the attribute "var" defines. + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\", " + temp + ");"); + } + ctxt.generateBody(); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource("}"); + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/If.java b/java/org/apache/jasper/tagplugins/jstl/core/If.java index 2ba573b09..06dd61bda 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/If.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/If.java @@ -1,49 +1,49 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.*; - -public final class If implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - String condV = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource("boolean " + condV + "="); - ctxt.generateAttribute("test"); - ctxt.generateJavaSource(";"); - if (ctxt.isAttributeSpecified("var")) { - String scope = "PageContext.PAGE_SCOPE"; - if (ctxt.isAttributeSpecified("scope")) { - String scopeStr = ctxt.getConstantAttribute("scope"); - if ("request".equals(scopeStr)) { - scope = "PageContext.REQUEST_SCOPE"; - } else if ("session".equals(scopeStr)) { - scope = "PageContext.SESSION_SCOPE"; - } else if ("application".equals(scopeStr)) { - scope = "PageContext.APPLICATION_SCOPE"; - } - } - ctxt.generateJavaSource("_jspx_page_context.setAttribute("); - ctxt.generateAttribute("var"); - ctxt.generateJavaSource(", new Boolean(" + condV + ")," + scope + ");"); - } - ctxt.generateJavaSource("if (" + condV + "){"); - ctxt.generateBody(); - ctxt.generateJavaSource("}"); - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.*; + +public final class If implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + String condV = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource("boolean " + condV + "="); + ctxt.generateAttribute("test"); + ctxt.generateJavaSource(";"); + if (ctxt.isAttributeSpecified("var")) { + String scope = "PageContext.PAGE_SCOPE"; + if (ctxt.isAttributeSpecified("scope")) { + String scopeStr = ctxt.getConstantAttribute("scope"); + if ("request".equals(scopeStr)) { + scope = "PageContext.REQUEST_SCOPE"; + } else if ("session".equals(scopeStr)) { + scope = "PageContext.SESSION_SCOPE"; + } else if ("application".equals(scopeStr)) { + scope = "PageContext.APPLICATION_SCOPE"; + } + } + ctxt.generateJavaSource("_jspx_page_context.setAttribute("); + ctxt.generateAttribute("var"); + ctxt.generateJavaSource(", new Boolean(" + condV + ")," + scope + ");"); + } + ctxt.generateJavaSource("if (" + condV + "){"); + ctxt.generateBody(); + ctxt.generateJavaSource("}"); + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Import.java b/java/org/apache/jasper/tagplugins/jstl/core/Import.java index 991353921..88f155b4e 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Import.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Import.java @@ -1,381 +1,381 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; -import org.apache.jasper.tagplugins.jstl.Util; - -public class Import implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - boolean hasContext, hasVar, hasScope, hasVarReader, hasCharEncoding; - - //flags - hasContext = ctxt.isAttributeSpecified("context"); - hasVar = ctxt.isAttributeSpecified("var"); - hasScope = ctxt.isAttributeSpecified("scope"); - hasVarReader = ctxt.isAttributeSpecified("varReader"); - hasCharEncoding = ctxt.isAttributeSpecified("charEncoding"); - - //variables' names - String urlName = ctxt.getTemporaryVariableName(); - String contextName = ctxt.getTemporaryVariableName(); - String iauName = ctxt.getTemporaryVariableName(); // is absolute url - String urlObjName = ctxt.getTemporaryVariableName(); //URL object - String ucName = ctxt.getTemporaryVariableName(); //URLConnection - String inputStreamName = ctxt.getTemporaryVariableName(); - String tempReaderName = ctxt.getTemporaryVariableName(); - String tempReaderName2 = ctxt.getTemporaryVariableName(); - String charSetName = ctxt.getTemporaryVariableName(); - String charEncodingName = ctxt.getTemporaryVariableName(); - String contentTypeName = ctxt.getTemporaryVariableName(); - String varReaderName = ctxt.getTemporaryVariableName(); - String servletContextName = ctxt.getTemporaryVariableName(); - String servletPathName = ctxt.getTemporaryVariableName(); - String requestDispatcherName = ctxt.getTemporaryVariableName(); - String irwName = ctxt.getTemporaryVariableName(); //ImportResponseWrapper name - String brName = ctxt.getTemporaryVariableName(); //BufferedReader name - String sbName = ctxt.getTemporaryVariableName(); //StringBuffer name - String tempStringName = ctxt.getTemporaryVariableName(); - - //is absolute url - ctxt.generateJavaSource("boolean " + iauName + ";"); - - //get the url value - ctxt.generateJavaSource("String " + urlName + " = "); - ctxt.generateAttribute("url"); - ctxt.generateJavaSource(";"); - - //validate the url - ctxt.generateJavaSource("if(" + urlName + " == null || " + urlName + ".equals(\"\")){"); - ctxt.generateJavaSource(" throw new JspTagException(\"The \\\"url\\\" attribute " + - "illegally evaluated to \\\"null\\\" or \\\"\\\" in <import>\");"); - ctxt.generateJavaSource("}"); - - //initialize the is_absolute_url - ctxt.generateJavaSource(iauName + " = " + - "org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + urlName + ");"); - - //validate the context - if(hasContext){ - - ctxt.generateJavaSource("String " + contextName + " = "); - ctxt.generateAttribute("context"); - ctxt.generateJavaSource(";"); - - ctxt.generateJavaSource("if((!" + contextName + ".startsWith(\"/\")) " + - "|| (!" + urlName + ".startsWith(\"/\"))){"); - ctxt.generateJavaSource(" throw new JspTagException" + - "(\"In URL tags, when the \\\"context\\\" attribute is specified, " + - "values of both \\\"context\\\" and \\\"url\\\" must start with \\\"/\\\".\");"); - ctxt.generateJavaSource("}"); - - } - - //define charset - ctxt.generateJavaSource("String " + charSetName + " = null;"); - - //if the charEncoding attribute is specified - if(hasCharEncoding){ - - //initialize the charEncoding - ctxt.generateJavaSource("String " + charEncodingName + " = "); - ctxt.generateAttribute("charEncoding"); - ctxt.generateJavaSource(";"); - - //assign appropriate value tp the charset - ctxt.generateJavaSource("if(null != " + charEncodingName + " " + - "&& !" + charEncodingName + ".equals(\"\")){"); - ctxt.generateJavaSource(" " + charSetName + " = " - + charEncodingName + ";"); - ctxt.generateJavaSource("}"); - } - - //reshape the url string - ctxt.generateJavaSource("if(!"+iauName+"){"); - ctxt.generateJavaSource(" if(!" + urlName + ".startsWith(\"/\")){"); - ctxt.generateJavaSource(" String " + servletPathName + " = " + - "((HttpServletRequest)pageContext.getRequest()).getServletPath();"); - ctxt.generateJavaSource(" " + urlName + " = " - + servletPathName + ".substring(0," + servletPathName + ".lastIndexOf('/')) + '/' + " + urlName + ";"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource("}"); - - //if the varReader attribute specified - if(hasVarReader){ - - //get the String value of varReader - ctxt.generateJavaSource("String " + varReaderName + " = "); - ctxt.generateAttribute("varReader"); - ctxt.generateJavaSource(";"); - - //if the url is absolute url - ctxt.generateJavaSource("if(" + iauName + "){"); - - //get the content of the target - ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");"); - ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = " - + urlObjName + ".openConnection();"); - ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = " - + ucName + ".getInputStream();"); - - ctxt.generateJavaSource(" if(" + charSetName + " == null){"); - ctxt.generateJavaSource(" String " + contentTypeName + " = " - + ucName + ".getContentType();"); - ctxt.generateJavaSource(" if(null != " + contentTypeName + "){"); - ctxt.generateJavaSource(" " + charSetName + " = " + - "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");"); - ctxt.generateJavaSource(" if(" + charSetName + " == null) " - + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - - if(!hasCharEncoding){ - ctxt.generateJavaSource(" String " + contentTypeName + " = " + ucName + ".getContentType();"); - } - - //define the Reader - ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;"); - - //initialize the Reader object - ctxt.generateJavaSource(" try{"); - ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", " + charSetName + ");"); - ctxt.generateJavaSource(" }catch(Exception ex){"); - ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);"); - ctxt.generateJavaSource(" }"); - - //validate the response - ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){"); - ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();"); - ctxt.generateJavaSource(" if(status < 200 || status > 299){"); - ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - - //set attribute in the page context scope - ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");"); - - //if the url is relative - ctxt.generateJavaSource("}else{"); - - //if the url is relative, http request is needed - ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " + - "&& pageContext.getResponse() instanceof HttpServletResponse)){"); - ctxt.generateJavaSource(" throw new JspTagException(\"Relative <import> from non-HTTP request not allowed\");"); - ctxt.generateJavaSource(" }"); - - //get the servlet context of the context defined in the context attribute - ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;"); - if(hasContext){ - ctxt.generateJavaSource(" if(null != " + contextName + "){"); - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" ); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); - ctxt.generateJavaSource(" }"); - }else{ - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); - } - - // - ctxt.generateJavaSource(" if(" + servletContextName + " == null){"); - if(hasContext){ - ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \"+" + contextName + "+\" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); - }else{ - ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); - } - ctxt.generateJavaSource(" }"); - - //get the request dispatcher - ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); - ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); - - //initialize a ImportResponseWrapper to include the resource - ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());"); - ctxt.generateJavaSource(" if(" + charSetName + " == null){"); - ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");"); - ctxt.generateJavaSource(" try{"); - ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");"); - ctxt.generateJavaSource(" }catch(java.io.IOException ex){"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" }catch(RuntimeException ex){"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" }catch(ServletException ex){"); - ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();"); - ctxt.generateJavaSource(" if (rc == null)"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" else"); - ctxt.generateJavaSource(" throw new JspException(rc);"); - ctxt.generateJavaSource(" }"); - - //validate the response status - ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){"); - ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));"); - ctxt.generateJavaSource(" }"); - - //push in the page context - ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = new java.io.StringReader(" + irwName + ".getString());"); - ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");"); - - ctxt.generateJavaSource("}"); - - //execute the body action - ctxt.generateBody(); - - //close the reader - ctxt.generateJavaSource("java.io.Reader " + tempReaderName2 + " = (java.io.Reader)pageContext.getAttribute(" + varReaderName + ");"); - ctxt.generateJavaSource("if(" + tempReaderName2 + " != null) " + tempReaderName2 + ".close();"); - ctxt.generateJavaSource("pageContext.removeAttribute(" + varReaderName + ",1);"); - } - - //if the varReader is not specified - else{ - - ctxt.generateJavaSource("pageContext.setAttribute(\"url_without_param\"," + urlName + ");"); - ctxt.generateBody(); - ctxt.generateJavaSource(urlName + " = (String)pageContext.getAttribute(\"url_without_param\");"); - ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");"); - String strScope = "page"; - if(hasScope){ - strScope = ctxt.getConstantAttribute("scope"); - } - int iScope = Util.getScope(strScope); - - ctxt.generateJavaSource("String " + tempStringName + " = null;"); - - ctxt.generateJavaSource("if(" + iauName + "){"); - - //get the content of the target - ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");"); - ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = " + urlObjName + ".openConnection();"); - ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = " + ucName + ".getInputStream();"); - ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;"); - - ctxt.generateJavaSource(" if(" + charSetName + " == null){"); - ctxt.generateJavaSource(" String " + contentTypeName + " = " - + ucName + ".getContentType();"); - ctxt.generateJavaSource(" if(null != " + contentTypeName + "){"); - ctxt.generateJavaSource(" " + charSetName + " = " + - "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");"); - ctxt.generateJavaSource(" if(" + charSetName + " == null) " - + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - - ctxt.generateJavaSource(" try{"); - ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + "," + charSetName + ");"); - ctxt.generateJavaSource(" }catch(Exception ex){"); - //ctxt.generateJavaSource(" throw new JspTagException(ex.toString());"); - ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ",org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);"); - ctxt.generateJavaSource(" }"); - - //validate the response - ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){"); - ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();"); - ctxt.generateJavaSource(" if(status < 200 || status > 299){"); - ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - - ctxt.generateJavaSource(" java.io.BufferedReader " + brName + " = new java.io.BufferedReader(" + tempReaderName + ");"); - ctxt.generateJavaSource(" StringBuffer " + sbName + " = new StringBuffer();"); - String index = ctxt.getTemporaryVariableName(); - ctxt.generateJavaSource(" int " + index + ";"); - ctxt.generateJavaSource(" while(("+index+" = "+brName+".read()) != -1) "+sbName+".append((char)"+index+");"); - ctxt.generateJavaSource(" " + tempStringName + " = " +sbName + ".toString();"); - - ctxt.generateJavaSource("}else{"); - - //if the url is relative, http request is needed. - ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " + - "&& pageContext.getResponse() instanceof HttpServletResponse)){"); - ctxt.generateJavaSource(" throw new JspTagException(\"Relative <import> from non-HTTP request not allowed\");"); - ctxt.generateJavaSource(" }"); - - //get the servlet context of the context defined in the context attribute - ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;"); - if(hasContext){ - ctxt.generateJavaSource(" if(null != " + contextName + "){"); - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" ); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); - ctxt.generateJavaSource(" }"); - }else{ - ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); - } - - // - ctxt.generateJavaSource(" if(" + servletContextName + " == null){"); - if(hasContext){ - ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \" +" + contextName + "+ \" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); - }else{ - ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); - } - ctxt.generateJavaSource(" }"); - - //get the request dispatcher - ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); - ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); - - //initialize a ImportResponseWrapper to include the resource - ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());"); - ctxt.generateJavaSource(" if(" + charSetName + " == null){"); - ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");"); - ctxt.generateJavaSource(" try{"); - ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");"); - ctxt.generateJavaSource(" }catch(java.io.IOException ex){"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" }catch(RuntimeException ex){"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" }catch(ServletException ex){"); - ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();"); - ctxt.generateJavaSource(" if (rc == null)"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" else"); - ctxt.generateJavaSource(" throw new JspException(rc);"); - ctxt.generateJavaSource(" }"); - - //validate the response status - ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){"); - ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));"); - ctxt.generateJavaSource(" }"); - - ctxt.generateJavaSource(" " + tempStringName + " = " + irwName + ".getString();"); - - ctxt.generateJavaSource("}"); - - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource("pageContext.setAttribute(\""+strVar+"\"," + tempStringName + "," + iScope + ");"); - }else{ - ctxt.generateJavaSource("pageContext.getOut().print(" + tempStringName + ");"); - } - } - } - - - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; +import org.apache.jasper.tagplugins.jstl.Util; + +public class Import implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + boolean hasContext, hasVar, hasScope, hasVarReader, hasCharEncoding; + + //flags + hasContext = ctxt.isAttributeSpecified("context"); + hasVar = ctxt.isAttributeSpecified("var"); + hasScope = ctxt.isAttributeSpecified("scope"); + hasVarReader = ctxt.isAttributeSpecified("varReader"); + hasCharEncoding = ctxt.isAttributeSpecified("charEncoding"); + + //variables' names + String urlName = ctxt.getTemporaryVariableName(); + String contextName = ctxt.getTemporaryVariableName(); + String iauName = ctxt.getTemporaryVariableName(); // is absolute url + String urlObjName = ctxt.getTemporaryVariableName(); //URL object + String ucName = ctxt.getTemporaryVariableName(); //URLConnection + String inputStreamName = ctxt.getTemporaryVariableName(); + String tempReaderName = ctxt.getTemporaryVariableName(); + String tempReaderName2 = ctxt.getTemporaryVariableName(); + String charSetName = ctxt.getTemporaryVariableName(); + String charEncodingName = ctxt.getTemporaryVariableName(); + String contentTypeName = ctxt.getTemporaryVariableName(); + String varReaderName = ctxt.getTemporaryVariableName(); + String servletContextName = ctxt.getTemporaryVariableName(); + String servletPathName = ctxt.getTemporaryVariableName(); + String requestDispatcherName = ctxt.getTemporaryVariableName(); + String irwName = ctxt.getTemporaryVariableName(); //ImportResponseWrapper name + String brName = ctxt.getTemporaryVariableName(); //BufferedReader name + String sbName = ctxt.getTemporaryVariableName(); //StringBuffer name + String tempStringName = ctxt.getTemporaryVariableName(); + + //is absolute url + ctxt.generateJavaSource("boolean " + iauName + ";"); + + //get the url value + ctxt.generateJavaSource("String " + urlName + " = "); + ctxt.generateAttribute("url"); + ctxt.generateJavaSource(";"); + + //validate the url + ctxt.generateJavaSource("if(" + urlName + " == null || " + urlName + ".equals(\"\")){"); + ctxt.generateJavaSource(" throw new JspTagException(\"The \\\"url\\\" attribute " + + "illegally evaluated to \\\"null\\\" or \\\"\\\" in <import>\");"); + ctxt.generateJavaSource("}"); + + //initialize the is_absolute_url + ctxt.generateJavaSource(iauName + " = " + + "org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + urlName + ");"); + + //validate the context + if(hasContext){ + + ctxt.generateJavaSource("String " + contextName + " = "); + ctxt.generateAttribute("context"); + ctxt.generateJavaSource(";"); + + ctxt.generateJavaSource("if((!" + contextName + ".startsWith(\"/\")) " + + "|| (!" + urlName + ".startsWith(\"/\"))){"); + ctxt.generateJavaSource(" throw new JspTagException" + + "(\"In URL tags, when the \\\"context\\\" attribute is specified, " + + "values of both \\\"context\\\" and \\\"url\\\" must start with \\\"/\\\".\");"); + ctxt.generateJavaSource("}"); + + } + + //define charset + ctxt.generateJavaSource("String " + charSetName + " = null;"); + + //if the charEncoding attribute is specified + if(hasCharEncoding){ + + //initialize the charEncoding + ctxt.generateJavaSource("String " + charEncodingName + " = "); + ctxt.generateAttribute("charEncoding"); + ctxt.generateJavaSource(";"); + + //assign appropriate value tp the charset + ctxt.generateJavaSource("if(null != " + charEncodingName + " " + + "&& !" + charEncodingName + ".equals(\"\")){"); + ctxt.generateJavaSource(" " + charSetName + " = " + + charEncodingName + ";"); + ctxt.generateJavaSource("}"); + } + + //reshape the url string + ctxt.generateJavaSource("if(!"+iauName+"){"); + ctxt.generateJavaSource(" if(!" + urlName + ".startsWith(\"/\")){"); + ctxt.generateJavaSource(" String " + servletPathName + " = " + + "((HttpServletRequest)pageContext.getRequest()).getServletPath();"); + ctxt.generateJavaSource(" " + urlName + " = " + + servletPathName + ".substring(0," + servletPathName + ".lastIndexOf('/')) + '/' + " + urlName + ";"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource("}"); + + //if the varReader attribute specified + if(hasVarReader){ + + //get the String value of varReader + ctxt.generateJavaSource("String " + varReaderName + " = "); + ctxt.generateAttribute("varReader"); + ctxt.generateJavaSource(";"); + + //if the url is absolute url + ctxt.generateJavaSource("if(" + iauName + "){"); + + //get the content of the target + ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");"); + ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = " + + urlObjName + ".openConnection();"); + ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = " + + ucName + ".getInputStream();"); + + ctxt.generateJavaSource(" if(" + charSetName + " == null){"); + ctxt.generateJavaSource(" String " + contentTypeName + " = " + + ucName + ".getContentType();"); + ctxt.generateJavaSource(" if(null != " + contentTypeName + "){"); + ctxt.generateJavaSource(" " + charSetName + " = " + + "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");"); + ctxt.generateJavaSource(" if(" + charSetName + " == null) " + + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + + if(!hasCharEncoding){ + ctxt.generateJavaSource(" String " + contentTypeName + " = " + ucName + ".getContentType();"); + } + + //define the Reader + ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;"); + + //initialize the Reader object + ctxt.generateJavaSource(" try{"); + ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", " + charSetName + ");"); + ctxt.generateJavaSource(" }catch(Exception ex){"); + ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ", org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);"); + ctxt.generateJavaSource(" }"); + + //validate the response + ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){"); + ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();"); + ctxt.generateJavaSource(" if(status < 200 || status > 299){"); + ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + + //set attribute in the page context scope + ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");"); + + //if the url is relative + ctxt.generateJavaSource("}else{"); + + //if the url is relative, http request is needed + ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " + + "&& pageContext.getResponse() instanceof HttpServletResponse)){"); + ctxt.generateJavaSource(" throw new JspTagException(\"Relative <import> from non-HTTP request not allowed\");"); + ctxt.generateJavaSource(" }"); + + //get the servlet context of the context defined in the context attribute + ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;"); + if(hasContext){ + ctxt.generateJavaSource(" if(null != " + contextName + "){"); + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" ); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); + ctxt.generateJavaSource(" }"); + }else{ + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); + } + + // + ctxt.generateJavaSource(" if(" + servletContextName + " == null){"); + if(hasContext){ + ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \"+" + contextName + "+\" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); + }else{ + ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); + } + ctxt.generateJavaSource(" }"); + + //get the request dispatcher + ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); + ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); + + //initialize a ImportResponseWrapper to include the resource + ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());"); + ctxt.generateJavaSource(" if(" + charSetName + " == null){"); + ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");"); + ctxt.generateJavaSource(" try{"); + ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");"); + ctxt.generateJavaSource(" }catch(java.io.IOException ex){"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" }catch(RuntimeException ex){"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" }catch(ServletException ex){"); + ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();"); + ctxt.generateJavaSource(" if (rc == null)"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" else"); + ctxt.generateJavaSource(" throw new JspException(rc);"); + ctxt.generateJavaSource(" }"); + + //validate the response status + ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){"); + ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));"); + ctxt.generateJavaSource(" }"); + + //push in the page context + ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = new java.io.StringReader(" + irwName + ".getString());"); + ctxt.generateJavaSource(" pageContext.setAttribute(" + varReaderName + ", " + tempReaderName + ");"); + + ctxt.generateJavaSource("}"); + + //execute the body action + ctxt.generateBody(); + + //close the reader + ctxt.generateJavaSource("java.io.Reader " + tempReaderName2 + " = (java.io.Reader)pageContext.getAttribute(" + varReaderName + ");"); + ctxt.generateJavaSource("if(" + tempReaderName2 + " != null) " + tempReaderName2 + ".close();"); + ctxt.generateJavaSource("pageContext.removeAttribute(" + varReaderName + ",1);"); + } + + //if the varReader is not specified + else{ + + ctxt.generateJavaSource("pageContext.setAttribute(\"url_without_param\"," + urlName + ");"); + ctxt.generateBody(); + ctxt.generateJavaSource(urlName + " = (String)pageContext.getAttribute(\"url_without_param\");"); + ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");"); + String strScope = "page"; + if(hasScope){ + strScope = ctxt.getConstantAttribute("scope"); + } + int iScope = Util.getScope(strScope); + + ctxt.generateJavaSource("String " + tempStringName + " = null;"); + + ctxt.generateJavaSource("if(" + iauName + "){"); + + //get the content of the target + ctxt.generateJavaSource(" java.net.URL " + urlObjName + " = new java.net.URL(" + urlName + ");"); + ctxt.generateJavaSource(" java.net.URLConnection " + ucName + " = " + urlObjName + ".openConnection();"); + ctxt.generateJavaSource(" java.io.InputStream " + inputStreamName + " = " + ucName + ".getInputStream();"); + ctxt.generateJavaSource(" java.io.Reader " + tempReaderName + " = null;"); + + ctxt.generateJavaSource(" if(" + charSetName + " == null){"); + ctxt.generateJavaSource(" String " + contentTypeName + " = " + + ucName + ".getContentType();"); + ctxt.generateJavaSource(" if(null != " + contentTypeName + "){"); + ctxt.generateJavaSource(" " + charSetName + " = " + + "org.apache.jasper.tagplugins.jstl.Util.getContentTypeAttribute(" + contentTypeName + ", \"charset\");"); + ctxt.generateJavaSource(" if(" + charSetName + " == null) " + + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + + ctxt.generateJavaSource(" try{"); + ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + "," + charSetName + ");"); + ctxt.generateJavaSource(" }catch(Exception ex){"); + //ctxt.generateJavaSource(" throw new JspTagException(ex.toString());"); + ctxt.generateJavaSource(" " + tempReaderName + " = new java.io.InputStreamReader(" + inputStreamName + ",org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING);"); + ctxt.generateJavaSource(" }"); + + //validate the response + ctxt.generateJavaSource(" if(" + ucName + " instanceof java.net.HttpURLConnection){"); + ctxt.generateJavaSource(" int status = ((java.net.HttpURLConnection) " + ucName + ").getResponseCode();"); + ctxt.generateJavaSource(" if(status < 200 || status > 299){"); + ctxt.generateJavaSource(" throw new JspTagException(status + \" \" + " + urlName + ");"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + + ctxt.generateJavaSource(" java.io.BufferedReader " + brName + " = new java.io.BufferedReader(" + tempReaderName + ");"); + ctxt.generateJavaSource(" StringBuffer " + sbName + " = new StringBuffer();"); + String index = ctxt.getTemporaryVariableName(); + ctxt.generateJavaSource(" int " + index + ";"); + ctxt.generateJavaSource(" while(("+index+" = "+brName+".read()) != -1) "+sbName+".append((char)"+index+");"); + ctxt.generateJavaSource(" " + tempStringName + " = " +sbName + ".toString();"); + + ctxt.generateJavaSource("}else{"); + + //if the url is relative, http request is needed. + ctxt.generateJavaSource(" if (!(pageContext.getRequest() instanceof HttpServletRequest " + + "&& pageContext.getResponse() instanceof HttpServletResponse)){"); + ctxt.generateJavaSource(" throw new JspTagException(\"Relative <import> from non-HTTP request not allowed\");"); + ctxt.generateJavaSource(" }"); + + //get the servlet context of the context defined in the context attribute + ctxt.generateJavaSource(" ServletContext " + servletContextName + " = null;"); + if(hasContext){ + ctxt.generateJavaSource(" if(null != " + contextName + "){"); + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext().getContext(" + contextName + ");" ); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); + ctxt.generateJavaSource(" }"); + }else{ + ctxt.generateJavaSource(" " + servletContextName + " = pageContext.getServletContext();"); + } + + // + ctxt.generateJavaSource(" if(" + servletContextName + " == null){"); + if(hasContext){ + ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for Context: \\\" \" +" + contextName + "+ \" \\\" and URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); + }else{ + ctxt.generateJavaSource(" throw new JspTagException(\"Unable to get RequestDispatcher for URL: \\\" \" +" + urlName + "+ \" \\\". Verify values and/or enable cross context access.\");"); + } + ctxt.generateJavaSource(" }"); + + //get the request dispatcher + ctxt.generateJavaSource(" RequestDispatcher " + requestDispatcherName + " = " + servletContextName + ".getRequestDispatcher(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); + ctxt.generateJavaSource(" if(" + requestDispatcherName + " == null) throw new JspTagException(org.apache.jasper.tagplugins.jstl.Util.stripSession("+urlName+"));"); + + //initialize a ImportResponseWrapper to include the resource + ctxt.generateJavaSource(" org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper " + irwName + " = new org.apache.jasper.tagplugins.jstl.Util.ImportResponseWrapper((HttpServletResponse) pageContext.getResponse());"); + ctxt.generateJavaSource(" if(" + charSetName + " == null){"); + ctxt.generateJavaSource(" " + charSetName + " = org.apache.jasper.tagplugins.jstl.Util.DEFAULT_ENCODING;"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" " + irwName + ".setCharEncoding(" + charSetName + ");"); + ctxt.generateJavaSource(" try{"); + ctxt.generateJavaSource(" " + requestDispatcherName + ".include(pageContext.getRequest(), " + irwName + ");"); + ctxt.generateJavaSource(" }catch(java.io.IOException ex){"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" }catch(RuntimeException ex){"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" }catch(ServletException ex){"); + ctxt.generateJavaSource(" Throwable rc = ex.getRootCause();"); + ctxt.generateJavaSource(" if (rc == null)"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" else"); + ctxt.generateJavaSource(" throw new JspException(rc);"); + ctxt.generateJavaSource(" }"); + + //validate the response status + ctxt.generateJavaSource(" if(" + irwName + ".getStatus() < 200 || " + irwName + ".getStatus() > 299){"); + ctxt.generateJavaSource(" throw new JspTagException(" + irwName + ".getStatus()+\" \" + org.apache.jasper.tagplugins.jstl.Util.stripSession(" + urlName + "));"); + ctxt.generateJavaSource(" }"); + + ctxt.generateJavaSource(" " + tempStringName + " = " + irwName + ".getString();"); + + ctxt.generateJavaSource("}"); + + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource("pageContext.setAttribute(\""+strVar+"\"," + tempStringName + "," + iScope + ");"); + }else{ + ctxt.generateJavaSource("pageContext.getOut().print(" + tempStringName + ");"); + } + } + } + + + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Otherwise.java b/java/org/apache/jasper/tagplugins/jstl/core/Otherwise.java index 3542d0c57..bde0e5b8a 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Otherwise.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Otherwise.java @@ -1,31 +1,31 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.*; - -public final class Otherwise implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - // See When.java for the reason whey "}" is need at the beginng and - // not at the end. - ctxt.generateJavaSource("} else {"); - ctxt.generateBody(); - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.*; + +public final class Otherwise implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + // See When.java for the reason whey "}" is need at the beginng and + // not at the end. + ctxt.generateJavaSource("} else {"); + ctxt.generateBody(); + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Out.java b/java/org/apache/jasper/tagplugins/jstl/core/Out.java index 57b3b0263..134b4c2c6 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Out.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Out.java @@ -1,89 +1,89 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - - -public final class Out implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //these two data member are to indicate - //whether the corresponding attribute is specified - boolean hasDefault=false, hasEscapeXml=false; - hasDefault = ctxt.isAttributeSpecified("default"); - hasEscapeXml = ctxt.isAttributeSpecified("escapeXml"); - - //strValName, strEscapeXmlName & strDefName are two variables' name - //standing for value, escapeXml and default attribute - String strValName = ctxt.getTemporaryVariableName(); - String strDefName = ctxt.getTemporaryVariableName(); - String strEscapeXmlName = ctxt.getTemporaryVariableName(); - - //according to the tag file, the value attribute is mandatory. - ctxt.generateJavaSource("String " + strValName + " = null;"); - ctxt.generateJavaSource("if("); - ctxt.generateAttribute("value"); - ctxt.generateJavaSource("!=null){"); - ctxt.generateJavaSource(" " + strValName + " = ("); - ctxt.generateAttribute("value"); - ctxt.generateJavaSource(").toString();"); - ctxt.generateJavaSource("}"); - - //initiate the strDefName with null. - //if the default has been specified, then assign the value to it; - ctxt.generateJavaSource("String " + strDefName + " = null;\n"); - if(hasDefault){ - ctxt.generateJavaSource("if("); - ctxt.generateAttribute("default"); - ctxt.generateJavaSource(" != null){"); - ctxt.generateJavaSource(strDefName + " = ("); - ctxt.generateAttribute("default"); - ctxt.generateJavaSource(").toString();"); - ctxt.generateJavaSource("}"); - } - - //initiate the strEscapeXmlName with true; - //if the escapeXml is specified, assign the value to it; - ctxt.generateJavaSource("boolean " + strEscapeXmlName + " = true;"); - if(hasEscapeXml){ - ctxt.generateJavaSource(strEscapeXmlName + " = Boolean.parseBoolean(("); - ctxt.generateAttribute("default"); - ctxt.generateJavaSource(").toString());"); - } - - //main part. - ctxt.generateJavaSource("if(null != " + strValName +"){"); - ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){"); - ctxt.generateJavaSource(" " + strValName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strValName + ");"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" out.write(" + strValName + ");"); - ctxt.generateJavaSource("}else{"); - ctxt.generateJavaSource(" if(null != " + strDefName + "){"); - ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){"); - ctxt.generateJavaSource(" " + strDefName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strDefName + ");"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" out.write(" + strDefName + ");"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateBody(); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource("}"); - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + + +public final class Out implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //these two data member are to indicate + //whether the corresponding attribute is specified + boolean hasDefault=false, hasEscapeXml=false; + hasDefault = ctxt.isAttributeSpecified("default"); + hasEscapeXml = ctxt.isAttributeSpecified("escapeXml"); + + //strValName, strEscapeXmlName & strDefName are two variables' name + //standing for value, escapeXml and default attribute + String strValName = ctxt.getTemporaryVariableName(); + String strDefName = ctxt.getTemporaryVariableName(); + String strEscapeXmlName = ctxt.getTemporaryVariableName(); + + //according to the tag file, the value attribute is mandatory. + ctxt.generateJavaSource("String " + strValName + " = null;"); + ctxt.generateJavaSource("if("); + ctxt.generateAttribute("value"); + ctxt.generateJavaSource("!=null){"); + ctxt.generateJavaSource(" " + strValName + " = ("); + ctxt.generateAttribute("value"); + ctxt.generateJavaSource(").toString();"); + ctxt.generateJavaSource("}"); + + //initiate the strDefName with null. + //if the default has been specified, then assign the value to it; + ctxt.generateJavaSource("String " + strDefName + " = null;\n"); + if(hasDefault){ + ctxt.generateJavaSource("if("); + ctxt.generateAttribute("default"); + ctxt.generateJavaSource(" != null){"); + ctxt.generateJavaSource(strDefName + " = ("); + ctxt.generateAttribute("default"); + ctxt.generateJavaSource(").toString();"); + ctxt.generateJavaSource("}"); + } + + //initiate the strEscapeXmlName with true; + //if the escapeXml is specified, assign the value to it; + ctxt.generateJavaSource("boolean " + strEscapeXmlName + " = true;"); + if(hasEscapeXml){ + ctxt.generateJavaSource(strEscapeXmlName + " = Boolean.parseBoolean(("); + ctxt.generateAttribute("default"); + ctxt.generateJavaSource(").toString());"); + } + + //main part. + ctxt.generateJavaSource("if(null != " + strValName +"){"); + ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){"); + ctxt.generateJavaSource(" " + strValName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strValName + ");"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" out.write(" + strValName + ");"); + ctxt.generateJavaSource("}else{"); + ctxt.generateJavaSource(" if(null != " + strDefName + "){"); + ctxt.generateJavaSource(" if(" + strEscapeXmlName + "){"); + ctxt.generateJavaSource(" " + strDefName + " = org.apache.jasper.tagplugins.jstl.Util.escapeXml(" + strDefName + ");"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" out.write(" + strDefName + ");"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateBody(); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource("}"); + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Param.java b/java/org/apache/jasper/tagplugins/jstl/core/Param.java index 93bdf2dd0..3dfae3741 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Param.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Param.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - -public class Param implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //don't support the body content - - //define names of all the temp variables - String nameName = ctxt.getTemporaryVariableName(); - String valueName = ctxt.getTemporaryVariableName(); - String urlName = ctxt.getTemporaryVariableName(); - String encName = ctxt.getTemporaryVariableName(); - String index = ctxt.getTemporaryVariableName(); - - //if the param tag has no parents, throw a exception - TagPluginContext parent = ctxt.getParentContext(); - if(parent == null){ - ctxt.generateJavaSource(" throw new JspTagExcption" + - "(\"<param> outside <import> or <urlEncode>\");"); - return; - } - - //get the url string before adding this param - ctxt.generateJavaSource("String " + urlName + " = " + - "(String)pageContext.getAttribute(\"url_without_param\");"); - - //get the value of "name" - ctxt.generateJavaSource("String " + nameName + " = "); - ctxt.generateAttribute("name"); - ctxt.generateJavaSource(";"); - - //if the "name" is null then do nothing. - //else add such string "name=value" to the url. - //and the url should be encoded - ctxt.generateJavaSource("if(" + nameName + " != null && !" + nameName + ".equals(\"\")){"); - ctxt.generateJavaSource(" String " + valueName + " = "); - ctxt.generateAttribute("value"); - ctxt.generateJavaSource(";"); - ctxt.generateJavaSource(" if(" + valueName + " == null) " + valueName + " = \"\";"); - ctxt.generateJavaSource(" String " + encName + " = pageContext.getResponse().getCharacterEncoding();"); - ctxt.generateJavaSource(" " + nameName + " = java.net.URLEncoder.encode(" + nameName + ", " + encName + ");"); - ctxt.generateJavaSource(" " + valueName + " = java.net.URLEncoder.encode(" + valueName + ", " + encName + ");"); - ctxt.generateJavaSource(" int " + index + ";"); - ctxt.generateJavaSource(" " + index + " = " + urlName + ".indexOf(\'?\');"); - //if the current param is the first one, add a "?" ahead of it - //else add a "&" ahead of it - ctxt.generateJavaSource(" if(" + index + " == -1){"); - ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"?\" + " + nameName + " + \"=\" + " + valueName + ";"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"&\" + " + nameName + " + \"=\" + " + valueName + ";"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" pageContext.setAttribute(\"url_without_param\"," + urlName + ");"); - ctxt.generateJavaSource("}"); - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + +public class Param implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //don't support the body content + + //define names of all the temp variables + String nameName = ctxt.getTemporaryVariableName(); + String valueName = ctxt.getTemporaryVariableName(); + String urlName = ctxt.getTemporaryVariableName(); + String encName = ctxt.getTemporaryVariableName(); + String index = ctxt.getTemporaryVariableName(); + + //if the param tag has no parents, throw a exception + TagPluginContext parent = ctxt.getParentContext(); + if(parent == null){ + ctxt.generateJavaSource(" throw new JspTagExcption" + + "(\"<param> outside <import> or <urlEncode>\");"); + return; + } + + //get the url string before adding this param + ctxt.generateJavaSource("String " + urlName + " = " + + "(String)pageContext.getAttribute(\"url_without_param\");"); + + //get the value of "name" + ctxt.generateJavaSource("String " + nameName + " = "); + ctxt.generateAttribute("name"); + ctxt.generateJavaSource(";"); + + //if the "name" is null then do nothing. + //else add such string "name=value" to the url. + //and the url should be encoded + ctxt.generateJavaSource("if(" + nameName + " != null && !" + nameName + ".equals(\"\")){"); + ctxt.generateJavaSource(" String " + valueName + " = "); + ctxt.generateAttribute("value"); + ctxt.generateJavaSource(";"); + ctxt.generateJavaSource(" if(" + valueName + " == null) " + valueName + " = \"\";"); + ctxt.generateJavaSource(" String " + encName + " = pageContext.getResponse().getCharacterEncoding();"); + ctxt.generateJavaSource(" " + nameName + " = java.net.URLEncoder.encode(" + nameName + ", " + encName + ");"); + ctxt.generateJavaSource(" " + valueName + " = java.net.URLEncoder.encode(" + valueName + ", " + encName + ");"); + ctxt.generateJavaSource(" int " + index + ";"); + ctxt.generateJavaSource(" " + index + " = " + urlName + ".indexOf(\'?\');"); + //if the current param is the first one, add a "?" ahead of it + //else add a "&" ahead of it + ctxt.generateJavaSource(" if(" + index + " == -1){"); + ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"?\" + " + nameName + " + \"=\" + " + valueName + ";"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + urlName + " = " + urlName + " + \"&\" + " + nameName + " + \"=\" + " + valueName + ";"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" pageContext.setAttribute(\"url_without_param\"," + urlName + ");"); + ctxt.generateJavaSource("}"); + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Redirect.java b/java/org/apache/jasper/tagplugins/jstl/core/Redirect.java index 7174c07cf..641cff971 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Redirect.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Redirect.java @@ -1,82 +1,82 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; - -public class Redirect implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //flag for the existence of the "context" - boolean hasContext = ctxt.isAttributeSpecified("context"); - - //names of the temp variables - String urlName = ctxt.getTemporaryVariableName(); - String contextName = ctxt.getTemporaryVariableName(); - String baseUrlName = ctxt.getTemporaryVariableName(); - String resultName = ctxt.getTemporaryVariableName(); - String responseName = ctxt.getTemporaryVariableName(); - - //get context - ctxt.generateJavaSource("String " + contextName + " = null;"); - if(hasContext){ - ctxt.generateJavaSource(contextName + " = "); - ctxt.generateAttribute("context"); - ctxt.generateJavaSource(";"); - } - - //get the url - ctxt.generateJavaSource("String " + urlName + " = "); - ctxt.generateAttribute("url"); - ctxt.generateJavaSource(";"); - - //get the raw url according to "url" and "context" - ctxt.generateJavaSource("String " + baseUrlName + " = " + - "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + urlName + ", " + contextName + ", pageContext);"); - ctxt.generateJavaSource("pageContext.setAttribute" + - "(\"url_without_param\", " + baseUrlName + ");"); - - //add params - ctxt.generateBody(); - - ctxt.generateJavaSource("String " + resultName + " = " + - "(String)pageContext.getAttribute(\"url_without_param\");"); - ctxt.generateJavaSource("pageContext.removeAttribute" + - "(\"url_without_param\");"); - - //get the response object - ctxt.generateJavaSource("HttpServletResponse " + responseName + " = " + - "((HttpServletResponse) pageContext.getResponse());"); - - //if the url is relative, encode it - ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){"); - ctxt.generateJavaSource(" " + resultName + " = " - + responseName + ".encodeRedirectURL(" + resultName + ");"); - ctxt.generateJavaSource("}"); - - //do redirect - ctxt.generateJavaSource("try{"); - ctxt.generateJavaSource(" " + responseName + ".sendRedirect(" + resultName + ");"); - ctxt.generateJavaSource("}catch(java.io.IOException ex){"); - ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);"); - ctxt.generateJavaSource("}"); - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; + +public class Redirect implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //flag for the existence of the "context" + boolean hasContext = ctxt.isAttributeSpecified("context"); + + //names of the temp variables + String urlName = ctxt.getTemporaryVariableName(); + String contextName = ctxt.getTemporaryVariableName(); + String baseUrlName = ctxt.getTemporaryVariableName(); + String resultName = ctxt.getTemporaryVariableName(); + String responseName = ctxt.getTemporaryVariableName(); + + //get context + ctxt.generateJavaSource("String " + contextName + " = null;"); + if(hasContext){ + ctxt.generateJavaSource(contextName + " = "); + ctxt.generateAttribute("context"); + ctxt.generateJavaSource(";"); + } + + //get the url + ctxt.generateJavaSource("String " + urlName + " = "); + ctxt.generateAttribute("url"); + ctxt.generateJavaSource(";"); + + //get the raw url according to "url" and "context" + ctxt.generateJavaSource("String " + baseUrlName + " = " + + "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + urlName + ", " + contextName + ", pageContext);"); + ctxt.generateJavaSource("pageContext.setAttribute" + + "(\"url_without_param\", " + baseUrlName + ");"); + + //add params + ctxt.generateBody(); + + ctxt.generateJavaSource("String " + resultName + " = " + + "(String)pageContext.getAttribute(\"url_without_param\");"); + ctxt.generateJavaSource("pageContext.removeAttribute" + + "(\"url_without_param\");"); + + //get the response object + ctxt.generateJavaSource("HttpServletResponse " + responseName + " = " + + "((HttpServletResponse) pageContext.getResponse());"); + + //if the url is relative, encode it + ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){"); + ctxt.generateJavaSource(" " + resultName + " = " + + responseName + ".encodeRedirectURL(" + resultName + ");"); + ctxt.generateJavaSource("}"); + + //do redirect + ctxt.generateJavaSource("try{"); + ctxt.generateJavaSource(" " + responseName + ".sendRedirect(" + resultName + ");"); + ctxt.generateJavaSource("}catch(java.io.IOException ex){"); + ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);"); + ctxt.generateJavaSource("}"); + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Remove.java b/java/org/apache/jasper/tagplugins/jstl/core/Remove.java index 7bdafb60a..957aac313 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Remove.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Remove.java @@ -1,44 +1,44 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; -import org.apache.jasper.tagplugins.jstl.Util; - -public class Remove implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //scope flag - boolean hasScope = ctxt.isAttributeSpecified("scope"); - - //the value of the "var" - String strVar = ctxt.getConstantAttribute("var"); - - //remove attribute from certain scope. - //default scope is "page". - if(hasScope){ - int iScope = Util.getScope(ctxt.getConstantAttribute("scope")); - ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");"); - }else{ - ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\");"); - } - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; +import org.apache.jasper.tagplugins.jstl.Util; + +public class Remove implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //scope flag + boolean hasScope = ctxt.isAttributeSpecified("scope"); + + //the value of the "var" + String strVar = ctxt.getConstantAttribute("var"); + + //remove attribute from certain scope. + //default scope is "page". + if(hasScope){ + int iScope = Util.getScope(ctxt.getConstantAttribute("scope")); + ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");"); + }else{ + ctxt.generateJavaSource("pageContext.removeAttribute(\"" + strVar + "\");"); + } + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Set.java b/java/org/apache/jasper/tagplugins/jstl/core/Set.java index af3c71d17..c57b0ba74 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Set.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Set.java @@ -1,166 +1,166 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; -import org.apache.jasper.tagplugins.jstl.Util; - -public class Set implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //the flags to indicate whether the attributes have been specified - boolean hasValue = false, hasVar = false, hasScope = false, - hasTarget = false; - - //the scope name - String strScope; - //the id of the scope - int iScope; - - //initialize the flags - hasValue = ctxt.isAttributeSpecified("value"); - hasVar = ctxt.isAttributeSpecified("var"); - hasScope = ctxt.isAttributeSpecified("scope"); - hasTarget = ctxt.isAttributeSpecified("target"); - - //the temp variables name - String resultName = ctxt.getTemporaryVariableName(); - String targetName = ctxt.getTemporaryVariableName(); - String propertyName = ctxt.getTemporaryVariableName(); - - //initialize the "result" which will be assigned to the var or target.property - ctxt.generateJavaSource("Object " + resultName + " = null;"); - if(hasValue){ - ctxt.generateJavaSource(resultName + " = "); - ctxt.generateAttribute("value"); - ctxt.generateJavaSource(";"); - }else{ - ctxt.dontUseTagPlugin(); - return; - } - - //initialize the strScope - if(hasScope){ - strScope = ctxt.getConstantAttribute("scope"); - }else{ - strScope = "page"; - } - - //get the iScope according to the strScope - iScope = Util.getScope(strScope); - - //if the attribute var has been specified then assign the result to the var; - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource("if(null != " + resultName + "){"); - ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");"); - ctxt.generateJavaSource("} else {"); - if(hasScope){ - ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");"); - }else{ - ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\");"); - } - ctxt.generateJavaSource("}"); - - //else assign the result to the target.property - }else if(hasTarget){ - - //generate the temp variable name - String pdName = ctxt.getTemporaryVariableName(); - String successFlagName = ctxt.getTemporaryVariableName(); - String index = ctxt.getTemporaryVariableName(); - String methodName = ctxt.getTemporaryVariableName(); - - //initialize the property - ctxt.generateJavaSource("String " + propertyName + " = null;"); - ctxt.generateJavaSource("if("); - ctxt.generateAttribute("property"); - ctxt.generateJavaSource(" != null){"); - ctxt.generateJavaSource(" " + propertyName + " = ("); - ctxt.generateAttribute("property"); - ctxt.generateJavaSource(").toString();"); - ctxt.generateJavaSource("}"); - - //initialize the target - ctxt.generateJavaSource("Object " + targetName + " = "); - ctxt.generateAttribute("target"); - ctxt.generateJavaSource(";"); - - //the target is ok - ctxt.generateJavaSource("if(" + targetName + " != null){"); - - //if the target is a map, then put the result into the map with the key property - ctxt.generateJavaSource(" if(" + targetName + " instanceof java.util.Map){"); - ctxt.generateJavaSource(" if(null != " + resultName + "){"); - ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").put(" + propertyName + "," + resultName + ");"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").remove(" + propertyName + ");"); - ctxt.generateJavaSource(" }"); - - //else assign the result to the target.property - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" try{"); - - //get all the property of the target - ctxt.generateJavaSource(" java.beans.PropertyDescriptor " + pdName + "[] = java.beans.Introspector.getBeanInfo(" + targetName + ".getClass()).getPropertyDescriptors();"); - - //the success flag is to imply whether the assign is successful - ctxt.generateJavaSource(" boolean " + successFlagName + " = false;"); - - //find the right property - ctxt.generateJavaSource(" for(int " + index + "=0;" + index + "<" + pdName + ".length;" + index + "++){"); - ctxt.generateJavaSource(" if(" + pdName + "[" + index + "].getName().equals(" + propertyName + ")){"); - - //get the "set" method; - ctxt.generateJavaSource(" java.lang.reflect.Method " + methodName + " = " + pdName + "[" + index + "].getWriteMethod();"); - ctxt.generateJavaSource(" if(null == " + methodName + "){"); - ctxt.generateJavaSource(" throw new JspException(\"No setter method in <set> for property \"+" + propertyName + ");"); - ctxt.generateJavaSource(" }"); - - //invoke the method through the reflection - ctxt.generateJavaSource(" if(" + resultName + " != null){"); - ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{(" + methodName + ".getParameterTypes()[0]).cast(" + resultName + ")});"); - ctxt.generateJavaSource(" }else{"); - ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{null});"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" " + successFlagName + " = true;"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" if(!" + successFlagName + "){"); - ctxt.generateJavaSource(" throw new JspException(\"Invalid property in <set>:\"+" + propertyName + ");"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - - //catch the el exception and throw it as a JspException - ctxt.generateJavaSource(" catch (IllegalAccessException ex) {"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" } catch (java.beans.IntrospectionException ex) {"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" } catch (java.lang.reflect.InvocationTargetException ex) {"); - ctxt.generateJavaSource(" throw new JspException(ex);"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource(" }"); - ctxt.generateJavaSource("}else{"); - ctxt.generateJavaSource(" throw new JspException();"); - ctxt.generateJavaSource("}"); - } - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; +import org.apache.jasper.tagplugins.jstl.Util; + +public class Set implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //the flags to indicate whether the attributes have been specified + boolean hasValue = false, hasVar = false, hasScope = false, + hasTarget = false; + + //the scope name + String strScope; + //the id of the scope + int iScope; + + //initialize the flags + hasValue = ctxt.isAttributeSpecified("value"); + hasVar = ctxt.isAttributeSpecified("var"); + hasScope = ctxt.isAttributeSpecified("scope"); + hasTarget = ctxt.isAttributeSpecified("target"); + + //the temp variables name + String resultName = ctxt.getTemporaryVariableName(); + String targetName = ctxt.getTemporaryVariableName(); + String propertyName = ctxt.getTemporaryVariableName(); + + //initialize the "result" which will be assigned to the var or target.property + ctxt.generateJavaSource("Object " + resultName + " = null;"); + if(hasValue){ + ctxt.generateJavaSource(resultName + " = "); + ctxt.generateAttribute("value"); + ctxt.generateJavaSource(";"); + }else{ + ctxt.dontUseTagPlugin(); + return; + } + + //initialize the strScope + if(hasScope){ + strScope = ctxt.getConstantAttribute("scope"); + }else{ + strScope = "page"; + } + + //get the iScope according to the strScope + iScope = Util.getScope(strScope); + + //if the attribute var has been specified then assign the result to the var; + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource("if(null != " + resultName + "){"); + ctxt.generateJavaSource(" pageContext.setAttribute(\"" + strVar + "\"," + resultName + "," + iScope + ");"); + ctxt.generateJavaSource("} else {"); + if(hasScope){ + ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\"," + iScope + ");"); + }else{ + ctxt.generateJavaSource(" pageContext.removeAttribute(\"" + strVar + "\");"); + } + ctxt.generateJavaSource("}"); + + //else assign the result to the target.property + }else if(hasTarget){ + + //generate the temp variable name + String pdName = ctxt.getTemporaryVariableName(); + String successFlagName = ctxt.getTemporaryVariableName(); + String index = ctxt.getTemporaryVariableName(); + String methodName = ctxt.getTemporaryVariableName(); + + //initialize the property + ctxt.generateJavaSource("String " + propertyName + " = null;"); + ctxt.generateJavaSource("if("); + ctxt.generateAttribute("property"); + ctxt.generateJavaSource(" != null){"); + ctxt.generateJavaSource(" " + propertyName + " = ("); + ctxt.generateAttribute("property"); + ctxt.generateJavaSource(").toString();"); + ctxt.generateJavaSource("}"); + + //initialize the target + ctxt.generateJavaSource("Object " + targetName + " = "); + ctxt.generateAttribute("target"); + ctxt.generateJavaSource(";"); + + //the target is ok + ctxt.generateJavaSource("if(" + targetName + " != null){"); + + //if the target is a map, then put the result into the map with the key property + ctxt.generateJavaSource(" if(" + targetName + " instanceof java.util.Map){"); + ctxt.generateJavaSource(" if(null != " + resultName + "){"); + ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").put(" + propertyName + "," + resultName + ");"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" ((java.util.Map) " + targetName + ").remove(" + propertyName + ");"); + ctxt.generateJavaSource(" }"); + + //else assign the result to the target.property + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" try{"); + + //get all the property of the target + ctxt.generateJavaSource(" java.beans.PropertyDescriptor " + pdName + "[] = java.beans.Introspector.getBeanInfo(" + targetName + ".getClass()).getPropertyDescriptors();"); + + //the success flag is to imply whether the assign is successful + ctxt.generateJavaSource(" boolean " + successFlagName + " = false;"); + + //find the right property + ctxt.generateJavaSource(" for(int " + index + "=0;" + index + "<" + pdName + ".length;" + index + "++){"); + ctxt.generateJavaSource(" if(" + pdName + "[" + index + "].getName().equals(" + propertyName + ")){"); + + //get the "set" method; + ctxt.generateJavaSource(" java.lang.reflect.Method " + methodName + " = " + pdName + "[" + index + "].getWriteMethod();"); + ctxt.generateJavaSource(" if(null == " + methodName + "){"); + ctxt.generateJavaSource(" throw new JspException(\"No setter method in <set> for property \"+" + propertyName + ");"); + ctxt.generateJavaSource(" }"); + + //invoke the method through the reflection + ctxt.generateJavaSource(" if(" + resultName + " != null){"); + ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{(" + methodName + ".getParameterTypes()[0]).cast(" + resultName + ")});"); + ctxt.generateJavaSource(" }else{"); + ctxt.generateJavaSource(" " + methodName + ".invoke(" + targetName + ", new Object[]{null});"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" " + successFlagName + " = true;"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" if(!" + successFlagName + "){"); + ctxt.generateJavaSource(" throw new JspException(\"Invalid property in <set>:\"+" + propertyName + ");"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + + //catch the el exception and throw it as a JspException + ctxt.generateJavaSource(" catch (IllegalAccessException ex) {"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" } catch (java.beans.IntrospectionException ex) {"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" } catch (java.lang.reflect.InvocationTargetException ex) {"); + ctxt.generateJavaSource(" throw new JspException(ex);"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource(" }"); + ctxt.generateJavaSource("}else{"); + ctxt.generateJavaSource(" throw new JspException();"); + ctxt.generateJavaSource("}"); + } + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/Url.java b/java/org/apache/jasper/tagplugins/jstl/core/Url.java index 15a3cb52f..c848fe458 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/Url.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/Url.java @@ -1,100 +1,100 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.TagPlugin; -import org.apache.jasper.compiler.tagplugin.TagPluginContext; -import org.apache.jasper.tagplugins.jstl.Util; - -public class Url implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - - //flags - boolean hasVar, hasContext, hasScope; - - //init flags - hasVar = ctxt.isAttributeSpecified("var"); - hasContext = ctxt.isAttributeSpecified("context"); - hasScope = ctxt.isAttributeSpecified("scope"); - - //define name of the temp variables - String valueName = ctxt.getTemporaryVariableName(); - String contextName = ctxt.getTemporaryVariableName(); - String baseUrlName = ctxt.getTemporaryVariableName(); - String resultName = ctxt.getTemporaryVariableName(); - String responseName = ctxt.getTemporaryVariableName(); - - //get the scope - String strScope = "page"; - if(hasScope){ - strScope = ctxt.getConstantAttribute("scope"); - } - int iScope = Util.getScope(strScope); - - //get the value - ctxt.generateJavaSource("String " + valueName + " = "); - ctxt.generateAttribute("value"); - ctxt.generateJavaSource(";"); - - //get the context - ctxt.generateJavaSource("String " + contextName + " = null;"); - if(hasContext){ - ctxt.generateJavaSource(contextName + " = "); - ctxt.generateAttribute("context"); - ctxt.generateJavaSource(";"); - } - - //get the raw url - ctxt.generateJavaSource("String " + baseUrlName + " = " + - "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + valueName + ", " + contextName + ", pageContext);"); - ctxt.generateJavaSource("pageContext.setAttribute" + - "(\"url_without_param\", " + baseUrlName + ");"); - - //add params - ctxt.generateBody(); - - ctxt.generateJavaSource("String " + resultName + " = " + - "(String)pageContext.getAttribute(\"url_without_param\");"); - ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");"); - - //if the url is relative, encode it - ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){"); - ctxt.generateJavaSource(" HttpServletResponse " + responseName + " = " + - "((HttpServletResponse) pageContext.getResponse());"); - ctxt.generateJavaSource(" " + resultName + " = " - + responseName + ".encodeURL(" + resultName + ");"); - ctxt.generateJavaSource("}"); - - //if "var" is specified, the url string store in the attribute var defines - if(hasVar){ - String strVar = ctxt.getConstantAttribute("var"); - ctxt.generateJavaSource("pageContext.setAttribute" + - "(\"" + strVar + "\", " + resultName + ", " + iScope + ");"); - - //if var is not specified, just print out the url string - }else{ - ctxt.generateJavaSource("try{"); - ctxt.generateJavaSource(" pageContext.getOut().print(" + resultName + ");"); - ctxt.generateJavaSource("}catch(java.io.IOException ex){"); - ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);"); - ctxt.generateJavaSource("}"); - } - } - -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.TagPlugin; +import org.apache.jasper.compiler.tagplugin.TagPluginContext; +import org.apache.jasper.tagplugins.jstl.Util; + +public class Url implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + + //flags + boolean hasVar, hasContext, hasScope; + + //init flags + hasVar = ctxt.isAttributeSpecified("var"); + hasContext = ctxt.isAttributeSpecified("context"); + hasScope = ctxt.isAttributeSpecified("scope"); + + //define name of the temp variables + String valueName = ctxt.getTemporaryVariableName(); + String contextName = ctxt.getTemporaryVariableName(); + String baseUrlName = ctxt.getTemporaryVariableName(); + String resultName = ctxt.getTemporaryVariableName(); + String responseName = ctxt.getTemporaryVariableName(); + + //get the scope + String strScope = "page"; + if(hasScope){ + strScope = ctxt.getConstantAttribute("scope"); + } + int iScope = Util.getScope(strScope); + + //get the value + ctxt.generateJavaSource("String " + valueName + " = "); + ctxt.generateAttribute("value"); + ctxt.generateJavaSource(";"); + + //get the context + ctxt.generateJavaSource("String " + contextName + " = null;"); + if(hasContext){ + ctxt.generateJavaSource(contextName + " = "); + ctxt.generateAttribute("context"); + ctxt.generateJavaSource(";"); + } + + //get the raw url + ctxt.generateJavaSource("String " + baseUrlName + " = " + + "org.apache.jasper.tagplugins.jstl.Util.resolveUrl(" + valueName + ", " + contextName + ", pageContext);"); + ctxt.generateJavaSource("pageContext.setAttribute" + + "(\"url_without_param\", " + baseUrlName + ");"); + + //add params + ctxt.generateBody(); + + ctxt.generateJavaSource("String " + resultName + " = " + + "(String)pageContext.getAttribute(\"url_without_param\");"); + ctxt.generateJavaSource("pageContext.removeAttribute(\"url_without_param\");"); + + //if the url is relative, encode it + ctxt.generateJavaSource("if(!org.apache.jasper.tagplugins.jstl.Util.isAbsoluteUrl(" + resultName + ")){"); + ctxt.generateJavaSource(" HttpServletResponse " + responseName + " = " + + "((HttpServletResponse) pageContext.getResponse());"); + ctxt.generateJavaSource(" " + resultName + " = " + + responseName + ".encodeURL(" + resultName + ");"); + ctxt.generateJavaSource("}"); + + //if "var" is specified, the url string store in the attribute var defines + if(hasVar){ + String strVar = ctxt.getConstantAttribute("var"); + ctxt.generateJavaSource("pageContext.setAttribute" + + "(\"" + strVar + "\", " + resultName + ", " + iScope + ");"); + + //if var is not specified, just print out the url string + }else{ + ctxt.generateJavaSource("try{"); + ctxt.generateJavaSource(" pageContext.getOut().print(" + resultName + ");"); + ctxt.generateJavaSource("}catch(java.io.IOException ex){"); + ctxt.generateJavaSource(" throw new JspTagException(ex.toString(), ex);"); + ctxt.generateJavaSource("}"); + } + } + +} diff --git a/java/org/apache/jasper/tagplugins/jstl/core/When.java b/java/org/apache/jasper/tagplugins/jstl/core/When.java index ca6f15526..7c3bce3dd 100644 --- a/java/org/apache/jasper/tagplugins/jstl/core/When.java +++ b/java/org/apache/jasper/tagplugins/jstl/core/When.java @@ -1,49 +1,49 @@ -/* - * Copyright 1999,2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.jasper.tagplugins.jstl.core; - -import org.apache.jasper.compiler.tagplugin.*; - -public final class When implements TagPlugin { - - public void doTag(TagPluginContext ctxt) { - // Get the parent context to determine if this is the first - TagPluginContext parentContext = ctxt.getParentContext(); - if (parentContext == null) { - ctxt.dontUseTagPlugin(); - return; - } - - if ("true".equals(parentContext.getPluginAttribute("hasBeenHere"))) { - ctxt.generateJavaSource("} else if("); - // See comment below for the reason we generate the extra "}" here. - } - else { - ctxt.generateJavaSource("if("); - parentContext.setPluginAttribute("hasBeenHere", "true"); - } - ctxt.generateAttribute("test"); - ctxt.generateJavaSource("){"); - ctxt.generateBody(); - - // We don't generate the closing "}" for the "if" here because there - // may be whitespaces in between 's. Instead we delay - // generating it until the next or or - // - } -} +/* + * Copyright 1999,2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.jasper.tagplugins.jstl.core; + +import org.apache.jasper.compiler.tagplugin.*; + +public final class When implements TagPlugin { + + public void doTag(TagPluginContext ctxt) { + // Get the parent context to determine if this is the first + TagPluginContext parentContext = ctxt.getParentContext(); + if (parentContext == null) { + ctxt.dontUseTagPlugin(); + return; + } + + if ("true".equals(parentContext.getPluginAttribute("hasBeenHere"))) { + ctxt.generateJavaSource("} else if("); + // See comment below for the reason we generate the extra "}" here. + } + else { + ctxt.generateJavaSource("if("); + parentContext.setPluginAttribute("hasBeenHere", "true"); + } + ctxt.generateAttribute("test"); + ctxt.generateJavaSource("){"); + ctxt.generateBody(); + + // We don't generate the closing "}" for the "if" here because there + // may be whitespaces in between 's. Instead we delay + // generating it until the next or or + // + } +} diff --git a/java/org/apache/jasper/tagplugins/jstl/tagPlugins.xml b/java/org/apache/jasper/tagplugins/jstl/tagPlugins.xml index c18d33cd3..5d84dc6ce 100644 --- a/java/org/apache/jasper/tagplugins/jstl/tagPlugins.xml +++ b/java/org/apache/jasper/tagplugins/jstl/tagPlugins.xml @@ -1,46 +1,46 @@ - - - org.apache.taglibs.standard.tag.rt.core.IfTag - org.apache.jasper.tagplugins.jstl.core.If - - - org.apache.taglibs.standard.tag.common.core.ChooseTag - org.apache.jasper.tagplugins.jstl.core.Choose - - - org.apache.taglibs.standard.tag.rt.core.WhenTag - org.apache.jasper.tagplugins.jstl.core.When - - - org.apache.taglibs.standard.tag.common.core.OtherwiseTag - org.apache.jasper.tagplugins.jstl.core.Otherwise - - - org.apache.taglibs.standard.tag.rt.core.ForEachTag - org.apache.jasper.tagplugins.jstl.core.ForEach - - - org.apache.taglibs.standard.tag.rt.core.OutTag - org.apache.jasper.tagplugins.jstl.core.Out - - - org.apache.taglibs.standard.tag.rt.core.SetTag - org.apache.jasper.tagplugins.jstl.core.Set - - - org.apache.taglibs.standard.tag.common.core.RemoveTag - org.apache.jasper.tagplugins.jstl.core.Remove - - - org.apache.taglibs.standard.tag.common.core.CatchTag - org.apache.jasper.tagplugins.jstl.core.Catch - - - org.apache.taglibs.standard.tag.rt.core.ForTokensTag - org.apache.jasper.tagplugins.jstl.core.ForTokens - - - org.apache.taglibs.standard.tag.rt.core.ImportTag - org.apache.jasper.tagplugins.jstl.core.Import - - + + + org.apache.taglibs.standard.tag.rt.core.IfTag + org.apache.jasper.tagplugins.jstl.core.If + + + org.apache.taglibs.standard.tag.common.core.ChooseTag + org.apache.jasper.tagplugins.jstl.core.Choose + + + org.apache.taglibs.standard.tag.rt.core.WhenTag + org.apache.jasper.tagplugins.jstl.core.When + + + org.apache.taglibs.standard.tag.common.core.OtherwiseTag + org.apache.jasper.tagplugins.jstl.core.Otherwise + + + org.apache.taglibs.standard.tag.rt.core.ForEachTag + org.apache.jasper.tagplugins.jstl.core.ForEach + + + org.apache.taglibs.standard.tag.rt.core.OutTag + org.apache.jasper.tagplugins.jstl.core.Out + + + org.apache.taglibs.standard.tag.rt.core.SetTag + org.apache.jasper.tagplugins.jstl.core.Set + + + org.apache.taglibs.standard.tag.common.core.RemoveTag + org.apache.jasper.tagplugins.jstl.core.Remove + + + org.apache.taglibs.standard.tag.common.core.CatchTag + org.apache.jasper.tagplugins.jstl.core.Catch + + + org.apache.taglibs.standard.tag.rt.core.ForTokensTag + org.apache.jasper.tagplugins.jstl.core.ForTokens + + + org.apache.taglibs.standard.tag.rt.core.ImportTag + org.apache.jasper.tagplugins.jstl.core.Import + + diff --git a/java/org/apache/jasper/util/FastDateFormat.java b/java/org/apache/jasper/util/FastDateFormat.java index 578ef451d..95d1f2f83 100644 --- a/java/org/apache/jasper/util/FastDateFormat.java +++ b/java/org/apache/jasper/util/FastDateFormat.java @@ -1,133 +1,133 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.util; - -import java.util.Date; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParsePosition; -import java.text.SimpleDateFormat; - -/** - * Fast date formatter that caches recently formatted date information - * and uses it to avoid too-frequent calls to the underlying - * formatter. Note: breaks fieldPosition param of format(Date, - * StringBuffer, FieldPosition). If you care about the field - * position, call the underlying DateFormat directly. - * - * @author Stan Bailes - * @author Alex Chaffee - */ -public class FastDateFormat extends DateFormat { - - private DateFormat df; - private long lastSec = -1; - private StringBuffer sb = new StringBuffer(); - private FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD); - - public FastDateFormat(DateFormat df) { - this.df = df; - } - - public Date parse(String text, ParsePosition pos) { - return df.parse(text, pos); - } - - /** - * Note: breaks functionality of fieldPosition param. Also: - * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS" - * instead if you want a msec field. - */ - public StringBuffer format(Date date, StringBuffer toAppendTo, - FieldPosition fieldPosition) { - long dt = date.getTime(); - long ds = dt / 1000; - if (ds != lastSec) { - sb.setLength(0); - df.format(date, sb, fp); - lastSec = ds; - } else { - // munge current msec into existing string - int ms = (int)(dt % 1000); - int pos = fp.getEndIndex(); - int begin = fp.getBeginIndex(); - if (pos > 0) { - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - ms /= 10; - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - ms /= 10; - if (pos > begin) - sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); - } - } - toAppendTo.append(sb.toString()); - return toAppendTo; - } - - public static void main(String[] args) { - String format = "yyyy-MM-dd HH:mm:ss.SSS"; - if (args.length > 0) - format = args[0]; - SimpleDateFormat sdf = new SimpleDateFormat(format); - FastDateFormat fdf = new FastDateFormat(sdf); - Date d = new Date(); - - d.setTime(1); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(20); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(500); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(543); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(999); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(1050); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(2543); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(12345); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - d.setTime(12340); - System.out.println(fdf.format(d) + "\t" + sdf.format(d)); - - final int reps = 100000; - { - long start = System.currentTimeMillis(); - for (int i = 0; i < reps; i++) { - d.setTime(System.currentTimeMillis()); - fdf.format(d); - } - long elap = System.currentTimeMillis() - start; - System.out.println("fast: " + elap + " elapsed"); - System.out.println(fdf.format(d)); - } - { - long start = System.currentTimeMillis(); - for (int i = 0; i < reps; i++) { - d.setTime(System.currentTimeMillis()); - sdf.format(d); - } - long elap = System.currentTimeMillis() - start; - System.out.println("slow: " + elap + " elapsed"); - System.out.println(sdf.format(d)); - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.util; + +import java.util.Date; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParsePosition; +import java.text.SimpleDateFormat; + +/** + * Fast date formatter that caches recently formatted date information + * and uses it to avoid too-frequent calls to the underlying + * formatter. Note: breaks fieldPosition param of format(Date, + * StringBuffer, FieldPosition). If you care about the field + * position, call the underlying DateFormat directly. + * + * @author Stan Bailes + * @author Alex Chaffee + */ +public class FastDateFormat extends DateFormat { + + private DateFormat df; + private long lastSec = -1; + private StringBuffer sb = new StringBuffer(); + private FieldPosition fp = new FieldPosition(DateFormat.MILLISECOND_FIELD); + + public FastDateFormat(DateFormat df) { + this.df = df; + } + + public Date parse(String text, ParsePosition pos) { + return df.parse(text, pos); + } + + /** + * Note: breaks functionality of fieldPosition param. Also: + * there's a bug in SimpleDateFormat with "S" and "SS", use "SSS" + * instead if you want a msec field. + */ + public StringBuffer format(Date date, StringBuffer toAppendTo, + FieldPosition fieldPosition) { + long dt = date.getTime(); + long ds = dt / 1000; + if (ds != lastSec) { + sb.setLength(0); + df.format(date, sb, fp); + lastSec = ds; + } else { + // munge current msec into existing string + int ms = (int)(dt % 1000); + int pos = fp.getEndIndex(); + int begin = fp.getBeginIndex(); + if (pos > 0) { + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + ms /= 10; + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + ms /= 10; + if (pos > begin) + sb.setCharAt(--pos, Character.forDigit(ms % 10, 10)); + } + } + toAppendTo.append(sb.toString()); + return toAppendTo; + } + + public static void main(String[] args) { + String format = "yyyy-MM-dd HH:mm:ss.SSS"; + if (args.length > 0) + format = args[0]; + SimpleDateFormat sdf = new SimpleDateFormat(format); + FastDateFormat fdf = new FastDateFormat(sdf); + Date d = new Date(); + + d.setTime(1); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(20); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(500); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(543); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(999); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(1050); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(2543); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(12345); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + d.setTime(12340); + System.out.println(fdf.format(d) + "\t" + sdf.format(d)); + + final int reps = 100000; + { + long start = System.currentTimeMillis(); + for (int i = 0; i < reps; i++) { + d.setTime(System.currentTimeMillis()); + fdf.format(d); + } + long elap = System.currentTimeMillis() - start; + System.out.println("fast: " + elap + " elapsed"); + System.out.println(fdf.format(d)); + } + { + long start = System.currentTimeMillis(); + for (int i = 0; i < reps; i++) { + d.setTime(System.currentTimeMillis()); + sdf.format(d); + } + long elap = System.currentTimeMillis() - start; + System.out.println("slow: " + elap + " elapsed"); + System.out.println(sdf.format(d)); + } + } +} diff --git a/java/org/apache/jasper/util/Queue.java b/java/org/apache/jasper/util/Queue.java index f67a792f4..c17bc819d 100644 --- a/java/org/apache/jasper/util/Queue.java +++ b/java/org/apache/jasper/util/Queue.java @@ -1,88 +1,88 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.util; - -import java.util.Vector; - -/** - * A simple FIFO queue class which causes the calling thread to wait - * if the queue is empty and notifies threads that are waiting when it - * is not empty. - * - * @author Anil V (akv@eng.sun.com) - */ -public class Queue { - private Vector vector = new Vector(); - - /** - * Put the object into the queue. - * - * @param object the object to be appended to the - * queue. - */ - public synchronized void put(Object object) { - vector.addElement(object); - notify(); - } - - /** - * Pull the first object out of the queue. Wait if the queue is - * empty. - */ - public synchronized Object pull() { - while (isEmpty()) - try { - wait(); - } catch (InterruptedException ex) { - } - return get(); - } - - /** - * Get the first object out of the queue. Return null if the queue - * is empty. - */ - public synchronized Object get() { - Object object = peek(); - if (object != null) - vector.removeElementAt(0); - return object; - } - - /** - * Peek to see if something is available. - */ - public Object peek() { - if (isEmpty()) - return null; - return vector.elementAt(0); - } - - /** - * Is the queue empty? - */ - public boolean isEmpty() { - return vector.isEmpty(); - } - - /** - * How many elements are there in this queue? - */ - public int size() { - return vector.size(); - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.util; + +import java.util.Vector; + +/** + * A simple FIFO queue class which causes the calling thread to wait + * if the queue is empty and notifies threads that are waiting when it + * is not empty. + * + * @author Anil V (akv@eng.sun.com) + */ +public class Queue { + private Vector vector = new Vector(); + + /** + * Put the object into the queue. + * + * @param object the object to be appended to the + * queue. + */ + public synchronized void put(Object object) { + vector.addElement(object); + notify(); + } + + /** + * Pull the first object out of the queue. Wait if the queue is + * empty. + */ + public synchronized Object pull() { + while (isEmpty()) + try { + wait(); + } catch (InterruptedException ex) { + } + return get(); + } + + /** + * Get the first object out of the queue. Return null if the queue + * is empty. + */ + public synchronized Object get() { + Object object = peek(); + if (object != null) + vector.removeElementAt(0); + return object; + } + + /** + * Peek to see if something is available. + */ + public Object peek() { + if (isEmpty()) + return null; + return vector.elementAt(0); + } + + /** + * Is the queue empty? + */ + public boolean isEmpty() { + return vector.isEmpty(); + } + + /** + * How many elements are there in this queue? + */ + public int size() { + return vector.size(); + } +} diff --git a/java/org/apache/jasper/util/SimplePool.java b/java/org/apache/jasper/util/SimplePool.java index 2076c458d..22cd14fcd 100644 --- a/java/org/apache/jasper/util/SimplePool.java +++ b/java/org/apache/jasper/util/SimplePool.java @@ -1,85 +1,85 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.util; - -/** - * Simple object pool. Based on ThreadPool and few other classes - * - * The pool will ignore overflow and return null if empty. - * - * @author Gal Shachor - * @author Costin - */ -public final class SimplePool { - - private static final int DEFAULT_SIZE=16; - - /* - * Where the threads are held. - */ - private Object pool[]; - - private int max; - private int current=-1; - - private Object lock; - - public SimplePool() { - this.max=DEFAULT_SIZE; - this.pool=new Object[max]; - this.lock=new Object(); - } - - public SimplePool(int max) { - this.max=max; - this.pool=new Object[max]; - this.lock=new Object(); - } - - /** - * Adds the given object to the pool, and does nothing if the pool is full - */ - public void put(Object o) { - synchronized( lock ) { - if( current < (max-1) ) { - current += 1; - pool[current] = o; - } - } - } - - /** - * Get an object from the pool, null if the pool is empty. - */ - public Object get() { - Object item = null; - synchronized( lock ) { - if( current >= 0 ) { - item = pool[current]; - current -= 1; - } - } - return item; - } - - /** - * Return the size of the pool - */ - public int getMax() { - return max; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.util; + +/** + * Simple object pool. Based on ThreadPool and few other classes + * + * The pool will ignore overflow and return null if empty. + * + * @author Gal Shachor + * @author Costin + */ +public final class SimplePool { + + private static final int DEFAULT_SIZE=16; + + /* + * Where the threads are held. + */ + private Object pool[]; + + private int max; + private int current=-1; + + private Object lock; + + public SimplePool() { + this.max=DEFAULT_SIZE; + this.pool=new Object[max]; + this.lock=new Object(); + } + + public SimplePool(int max) { + this.max=max; + this.pool=new Object[max]; + this.lock=new Object(); + } + + /** + * Adds the given object to the pool, and does nothing if the pool is full + */ + public void put(Object o) { + synchronized( lock ) { + if( current < (max-1) ) { + current += 1; + pool[current] = o; + } + } + } + + /** + * Get an object from the pool, null if the pool is empty. + */ + public Object get() { + Object item = null; + synchronized( lock ) { + if( current >= 0 ) { + item = pool[current]; + current -= 1; + } + } + return item; + } + + /** + * Return the size of the pool + */ + public int getMax() { + return max; + } +} diff --git a/java/org/apache/jasper/util/SystemLogHandler.java b/java/org/apache/jasper/util/SystemLogHandler.java index 320e3a28b..19847ea09 100644 --- a/java/org/apache/jasper/util/SystemLogHandler.java +++ b/java/org/apache/jasper/util/SystemLogHandler.java @@ -1,221 +1,221 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.util; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; - - -/** - * This helper class may be used to do sophisticated redirection of - * System.out and System.err. - * - * @author Remy Maucherat - */ -public class SystemLogHandler extends PrintStream { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct the handler to capture the output of the given steam. - */ - public SystemLogHandler(PrintStream wrapped) { - super(wrapped); - this.wrapped = wrapped; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped PrintStream. - */ - protected PrintStream wrapped = null; - - - /** - * Thread <-> PrintStream associations. - */ - protected static ThreadLocal streams = new ThreadLocal(); - - - /** - * Thread <-> ByteArrayOutputStream associations. - */ - protected static ThreadLocal data = new ThreadLocal(); - - - // --------------------------------------------------------- Public Methods - - - public PrintStream getWrapped() { - return wrapped; - } - - /** - * Start capturing thread's output. - */ - public static void setThread() { - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - data.set(baos); - streams.set(new PrintStream(baos)); - } - - - /** - * Stop capturing thread's output and return captured data as a String. - */ - public static String unsetThread() { - ByteArrayOutputStream baos = - (ByteArrayOutputStream) data.get(); - if (baos == null) { - return null; - } - streams.set(null); - data.set(null); - return baos.toString(); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Find PrintStream to which the output must be written to. - */ - protected PrintStream findStream() { - PrintStream ps = (PrintStream) streams.get(); - if (ps == null) { - ps = wrapped; - } - return ps; - } - - - // ---------------------------------------------------- PrintStream Methods - - - public void flush() { - findStream().flush(); - } - - public void close() { - findStream().close(); - } - - public boolean checkError() { - return findStream().checkError(); - } - - protected void setError() { - //findStream().setError(); - } - - public void write(int b) { - findStream().write(b); - } - - public void write(byte[] b) - throws IOException { - findStream().write(b); - } - - public void write(byte[] buf, int off, int len) { - findStream().write(buf, off, len); - } - - public void print(boolean b) { - findStream().print(b); - } - - public void print(char c) { - findStream().print(c); - } - - public void print(int i) { - findStream().print(i); - } - - public void print(long l) { - findStream().print(l); - } - - public void print(float f) { - findStream().print(f); - } - - public void print(double d) { - findStream().print(d); - } - - public void print(char[] s) { - findStream().print(s); - } - - public void print(String s) { - findStream().print(s); - } - - public void print(Object obj) { - findStream().print(obj); - } - - public void println() { - findStream().println(); - } - - public void println(boolean x) { - findStream().println(x); - } - - public void println(char x) { - findStream().println(x); - } - - public void println(int x) { - findStream().println(x); - } - - public void println(long x) { - findStream().println(x); - } - - public void println(float x) { - findStream().println(x); - } - - public void println(double x) { - findStream().println(x); - } - - public void println(char[] x) { - findStream().println(x); - } - - public void println(String x) { - findStream().println(x); - } - - public void println(Object x) { - findStream().println(x); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + + +/** + * This helper class may be used to do sophisticated redirection of + * System.out and System.err. + * + * @author Remy Maucherat + */ +public class SystemLogHandler extends PrintStream { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct the handler to capture the output of the given steam. + */ + public SystemLogHandler(PrintStream wrapped) { + super(wrapped); + this.wrapped = wrapped; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Wrapped PrintStream. + */ + protected PrintStream wrapped = null; + + + /** + * Thread <-> PrintStream associations. + */ + protected static ThreadLocal streams = new ThreadLocal(); + + + /** + * Thread <-> ByteArrayOutputStream associations. + */ + protected static ThreadLocal data = new ThreadLocal(); + + + // --------------------------------------------------------- Public Methods + + + public PrintStream getWrapped() { + return wrapped; + } + + /** + * Start capturing thread's output. + */ + public static void setThread() { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + data.set(baos); + streams.set(new PrintStream(baos)); + } + + + /** + * Stop capturing thread's output and return captured data as a String. + */ + public static String unsetThread() { + ByteArrayOutputStream baos = + (ByteArrayOutputStream) data.get(); + if (baos == null) { + return null; + } + streams.set(null); + data.set(null); + return baos.toString(); + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Find PrintStream to which the output must be written to. + */ + protected PrintStream findStream() { + PrintStream ps = (PrintStream) streams.get(); + if (ps == null) { + ps = wrapped; + } + return ps; + } + + + // ---------------------------------------------------- PrintStream Methods + + + public void flush() { + findStream().flush(); + } + + public void close() { + findStream().close(); + } + + public boolean checkError() { + return findStream().checkError(); + } + + protected void setError() { + //findStream().setError(); + } + + public void write(int b) { + findStream().write(b); + } + + public void write(byte[] b) + throws IOException { + findStream().write(b); + } + + public void write(byte[] buf, int off, int len) { + findStream().write(buf, off, len); + } + + public void print(boolean b) { + findStream().print(b); + } + + public void print(char c) { + findStream().print(c); + } + + public void print(int i) { + findStream().print(i); + } + + public void print(long l) { + findStream().print(l); + } + + public void print(float f) { + findStream().print(f); + } + + public void print(double d) { + findStream().print(d); + } + + public void print(char[] s) { + findStream().print(s); + } + + public void print(String s) { + findStream().print(s); + } + + public void print(Object obj) { + findStream().print(obj); + } + + public void println() { + findStream().println(); + } + + public void println(boolean x) { + findStream().println(x); + } + + public void println(char x) { + findStream().println(x); + } + + public void println(int x) { + findStream().println(x); + } + + public void println(long x) { + findStream().println(x); + } + + public void println(float x) { + findStream().println(x); + } + + public void println(double x) { + findStream().println(x); + } + + public void println(char[] x) { + findStream().println(x); + } + + public void println(String x) { + findStream().println(x); + } + + public void println(Object x) { + findStream().println(x); + } + +} diff --git a/java/org/apache/jasper/xmlparser/ASCIIReader.java b/java/org/apache/jasper/xmlparser/ASCIIReader.java index bae17f449..c313e322a 100644 --- a/java/org/apache/jasper/xmlparser/ASCIIReader.java +++ b/java/org/apache/jasper/xmlparser/ASCIIReader.java @@ -1,203 +1,203 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.xmlparser; - -import java.io.InputStream; -import java.io.IOException; -import java.io.Reader; -import org.apache.jasper.compiler.Localizer; - -/** - * A simple ASCII byte reader. This is an optimized reader for reading - * byte streams that only contain 7-bit ASCII characters. - * - * @author Andy Clark, IBM - * - * @version $Id: ASCIIReader.java 305933 2004-03-17 19:23:05Z luehe $ - */ -public class ASCIIReader - extends Reader { - - // - // Constants - // - - /** Default byte buffer size (2048). */ - public static final int DEFAULT_BUFFER_SIZE = 2048; - - // - // Data - // - - /** Input stream. */ - protected InputStream fInputStream; - - /** Byte buffer. */ - protected byte[] fBuffer; - - // - // Constructors - // - - /** - * Constructs an ASCII reader from the specified input stream - * and buffer size. - * - * @param inputStream The input stream. - * @param size The initial buffer size. - */ - public ASCIIReader(InputStream inputStream, int size) { - fInputStream = inputStream; - fBuffer = new byte[size]; - } - - // - // Reader methods - // - - /** - * Read a single character. This method will block until a character is - * available, an I/O error occurs, or the end of the stream is reached. - * - *

        Subclasses that intend to support efficient single-character input - * should override this method. - * - * @return The character read, as an integer in the range 0 to 127 - * (0x00-0x7f), or -1 if the end of the stream has - * been reached - * - * @exception IOException If an I/O error occurs - */ - public int read() throws IOException { - int b0 = fInputStream.read(); - if (b0 > 0x80) { - throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII", - Integer.toString(b0))); - } - return b0; - } // read():int - - /** - * Read characters into a portion of an array. This method will block - * until some input is available, an I/O error occurs, or the end of the - * stream is reached. - * - * @param ch Destination buffer - * @param offset Offset at which to start storing characters - * @param length Maximum number of characters to read - * - * @return The number of characters read, or -1 if the end of the - * stream has been reached - * - * @exception IOException If an I/O error occurs - */ - public int read(char ch[], int offset, int length) throws IOException { - if (length > fBuffer.length) { - length = fBuffer.length; - } - int count = fInputStream.read(fBuffer, 0, length); - for (int i = 0; i < count; i++) { - int b0 = fBuffer[i]; - if (b0 > 0x80) { - throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII", - Integer.toString(b0))); - } - ch[offset + i] = (char)b0; - } - return count; - } // read(char[],int,int) - - /** - * Skip characters. This method will block until some characters are - * available, an I/O error occurs, or the end of the stream is reached. - * - * @param n The number of characters to skip - * - * @return The number of characters actually skipped - * - * @exception IOException If an I/O error occurs - */ - public long skip(long n) throws IOException { - return fInputStream.skip(n); - } // skip(long):long - - /** - * Tell whether this stream is ready to be read. - * - * @return True if the next read() is guaranteed not to block for input, - * false otherwise. Note that returning false does not guarantee that the - * next read will block. - * - * @exception IOException If an I/O error occurs - */ - public boolean ready() throws IOException { - return false; - } // ready() - - /** - * Tell whether this stream supports the mark() operation. - */ - public boolean markSupported() { - return fInputStream.markSupported(); - } // markSupported() - - /** - * Mark the present position in the stream. Subsequent calls to reset() - * will attempt to reposition the stream to this point. Not all - * character-input streams support the mark() operation. - * - * @param readAheadLimit Limit on the number of characters that may be - * read while still preserving the mark. After - * reading this many characters, attempting to - * reset the stream may fail. - * - * @exception IOException If the stream does not support mark(), - * or if some other I/O error occurs - */ - public void mark(int readAheadLimit) throws IOException { - fInputStream.mark(readAheadLimit); - } // mark(int) - - /** - * Reset the stream. If the stream has been marked, then attempt to - * reposition it at the mark. If the stream has not been marked, then - * attempt to reset it in some way appropriate to the particular stream, - * for example by repositioning it to its starting point. Not all - * character-input streams support the reset() operation, and some support - * reset() without supporting mark(). - * - * @exception IOException If the stream has not been marked, - * or if the mark has been invalidated, - * or if the stream does not support reset(), - * or if some other I/O error occurs - */ - public void reset() throws IOException { - fInputStream.reset(); - } // reset() - - /** - * Close the stream. Once a stream has been closed, further read(), - * ready(), mark(), or reset() invocations will throw an IOException. - * Closing a previously-closed stream, however, has no effect. - * - * @exception IOException If an I/O error occurs - */ - public void close() throws IOException { - fInputStream.close(); - } // close() - -} // class ASCIIReader +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.xmlparser; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import org.apache.jasper.compiler.Localizer; + +/** + * A simple ASCII byte reader. This is an optimized reader for reading + * byte streams that only contain 7-bit ASCII characters. + * + * @author Andy Clark, IBM + * + * @version $Id: ASCIIReader.java 305933 2004-03-17 19:23:05Z luehe $ + */ +public class ASCIIReader + extends Reader { + + // + // Constants + // + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + // + // Data + // + + /** Input stream. */ + protected InputStream fInputStream; + + /** Byte buffer. */ + protected byte[] fBuffer; + + // + // Constructors + // + + /** + * Constructs an ASCII reader from the specified input stream + * and buffer size. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + */ + public ASCIIReader(InputStream inputStream, int size) { + fInputStream = inputStream; + fBuffer = new byte[size]; + } + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

        Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 127 + * (0x00-0x7f), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + int b0 = fInputStream.read(); + if (b0 > 0x80) { + throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII", + Integer.toString(b0))); + } + return b0; + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + if (length > fBuffer.length) { + length = fBuffer.length; + } + int count = fInputStream.read(fBuffer, 0, length); + for (int i = 0; i < count; i++) { + int b0 = fBuffer[i]; + if (b0 > 0x80) { + throw new IOException(Localizer.getMessage("jsp.error.xml.invalidASCII", + Integer.toString(b0))); + } + ch[offset + i] = (char)b0; + } + return count; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + return fInputStream.skip(n); + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return fInputStream.markSupported(); + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fInputStream.reset(); + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + +} // class ASCIIReader diff --git a/java/org/apache/jasper/xmlparser/EncodingMap.java b/java/org/apache/jasper/xmlparser/EncodingMap.java index cc3e51c40..35e655947 100644 --- a/java/org/apache/jasper/xmlparser/EncodingMap.java +++ b/java/org/apache/jasper/xmlparser/EncodingMap.java @@ -1,1019 +1,1019 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -import java.util.Hashtable; - -/** - * EncodingMap is a convenience class which handles conversions between - * IANA encoding names and Java encoding names, and vice versa. The - * encoding names used in XML instance documents must - * be the IANA encoding names specified or one of the aliases for those names - * which IANA defines. - *

        - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - * - *
        - *

        Common Name - *

        - *

        Use this name in XML files - *

        - *

        Name Type - *

        - *

        Xerces converts to this Java Encoder Name - *

        8 bit Unicode - *

        UTF-8 - *

        - *

        IANA - *

        - *

        UTF8 - *

        ISO Latin 1 - *

        ISO-8859-1 - *

        - *

        MIME - *

        - *

        ISO-8859-1 - *

        ISO Latin 2 - *

        ISO-8859-2 - *

        - *

        MIME - *

        - *

        ISO-8859-2 - *

        ISO Latin 3 - *

        ISO-8859-3 - *

        - *

        MIME - *

        - *

        ISO-8859-3 - *

        ISO Latin 4 - *

        ISO-8859-4 - *

        - *

        MIME - *

        - *

        ISO-8859-4 - *

        ISO Latin Cyrillic - *

        ISO-8859-5 - *

        - *

        MIME - *

        - *

        ISO-8859-5 - *

        ISO Latin Arabic - *

        ISO-8859-6 - *

        - *

        MIME - *

        - *

        ISO-8859-6 - *

        ISO Latin Greek - *

        ISO-8859-7 - *

        - *

        MIME - *

        - *

        ISO-8859-7 - *

        ISO Latin Hebrew - *

        ISO-8859-8 - *

        - *

        MIME - *

        - *

        ISO-8859-8 - *

        ISO Latin 5 - *

        ISO-8859-9 - *

        - *

        MIME - *

        - *

        ISO-8859-9 - *

        EBCDIC: US - *

        ebcdic-cp-us - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Canada - *

        ebcdic-cp-ca - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Netherlands - *

        ebcdic-cp-nl - *

        - *

        IANA - *

        - *

        cp037 - *

        EBCDIC: Denmark - *

        ebcdic-cp-dk - *

        - *

        IANA - *

        - *

        cp277 - *

        EBCDIC: Norway - *

        ebcdic-cp-no - *

        - *

        IANA - *

        - *

        cp277 - *

        EBCDIC: Finland - *

        ebcdic-cp-fi - *

        - *

        IANA - *

        - *

        cp278 - *

        EBCDIC: Sweden - *

        ebcdic-cp-se - *

        - *

        IANA - *

        - *

        cp278 - *

        EBCDIC: Italy - *

        ebcdic-cp-it - *

        - *

        IANA - *

        - *

        cp280 - *

        EBCDIC: Spain, Latin America - *

        ebcdic-cp-es - *

        - *

        IANA - *

        - *

        cp284 - *

        EBCDIC: Great Britain - *

        ebcdic-cp-gb - *

        - *

        IANA - *

        - *

        cp285 - *

        EBCDIC: France - *

        ebcdic-cp-fr - *

        - *

        IANA - *

        - *

        cp297 - *

        EBCDIC: Arabic - *

        ebcdic-cp-ar1 - *

        - *

        IANA - *

        - *

        cp420 - *

        EBCDIC: Hebrew - *

        ebcdic-cp-he - *

        - *

        IANA - *

        - *

        cp424 - *

        EBCDIC: Switzerland - *

        ebcdic-cp-ch - *

        - *

        IANA - *

        - *

        cp500 - *

        EBCDIC: Roece - *

        ebcdic-cp-roece - *

        - *

        IANA - *

        - *

        cp870 - *

        EBCDIC: Yugoslavia - *

        ebcdic-cp-yu - *

        - *

        IANA - *

        - *

        cp870 - *

        EBCDIC: Iceland - *

        ebcdic-cp-is - *

        - *

        IANA - *

        - *

        cp871 - *

        EBCDIC: Urdu - *

        ebcdic-cp-ar2 - *

        - *

        IANA - *

        - *

        cp918 - *

        Chinese for PRC, mixed 1/2 byte - *

        gb2312 - *

        - *

        MIME - *

        - *

        GB2312 - *

        Extended Unix Code, packed for Japanese - *

        euc-jp - *

        - *

        MIME - *

        - *

        eucjis - *

        Japanese: iso-2022-jp - *

        iso-2020-jp - *

        - *

        MIME - *

        - *

        JIS - *

        Japanese: Shift JIS - *

        Shift_JIS - *

        - *

        MIME - *

        - *

        SJIS - *

        Chinese: Big5 - *

        Big5 - *

        - *

        MIME - *

        - *

        Big5 - *

        Extended Unix Code, packed for Korean - *

        euc-kr - *

        - *

        MIME - *

        - *

        iso2022kr - *

        Cyrillic - *

        koi8-r - *

        - *

        MIME - *

        - *

        koi8-r - *

        - * - * @author TAMURA Kent, IBM - * @author Andy Clark, IBM - * - * @version $Id: EncodingMap.java 306086 2004-10-01 19:24:35Z luehe $ - */ -public class EncodingMap { - - // - // Data - // - - /** fIANA2JavaMap */ - protected final static Hashtable fIANA2JavaMap = new Hashtable(); - - /** fJava2IANAMap */ - protected final static Hashtable fJava2IANAMap = new Hashtable(); - - // - // Static initialization - // - - static { - - // add IANA to Java encoding mappings. - fIANA2JavaMap.put("BIG5", "Big5"); - fIANA2JavaMap.put("CSBIG5", "Big5"); - fIANA2JavaMap.put("CP037", "CP037"); - fIANA2JavaMap.put("IBM037", "CP037"); - fIANA2JavaMap.put("CSIBM037", "CP037"); - fIANA2JavaMap.put("EBCDIC-CP-US", "CP037"); - fIANA2JavaMap.put("EBCDIC-CP-CA", "CP037"); - fIANA2JavaMap.put("EBCDIC-CP-NL", "CP037"); - fIANA2JavaMap.put("EBCDIC-CP-WT", "CP037"); - fIANA2JavaMap.put("IBM273", "CP273"); - fIANA2JavaMap.put("CP273", "CP273"); - fIANA2JavaMap.put("CSIBM273", "CP273"); - fIANA2JavaMap.put("IBM277", "CP277"); - fIANA2JavaMap.put("CP277", "CP277"); - fIANA2JavaMap.put("CSIBM277", "CP277"); - fIANA2JavaMap.put("EBCDIC-CP-DK", "CP277"); - fIANA2JavaMap.put("EBCDIC-CP-NO", "CP277"); - fIANA2JavaMap.put("IBM278", "CP278"); - fIANA2JavaMap.put("CP278", "CP278"); - fIANA2JavaMap.put("CSIBM278", "CP278"); - fIANA2JavaMap.put("EBCDIC-CP-FI", "CP278"); - fIANA2JavaMap.put("EBCDIC-CP-SE", "CP278"); - fIANA2JavaMap.put("IBM280", "CP280"); - fIANA2JavaMap.put("CP280", "CP280"); - fIANA2JavaMap.put("CSIBM280", "CP280"); - fIANA2JavaMap.put("EBCDIC-CP-IT", "CP280"); - fIANA2JavaMap.put("IBM284", "CP284"); - fIANA2JavaMap.put("CP284", "CP284"); - fIANA2JavaMap.put("CSIBM284", "CP284"); - fIANA2JavaMap.put("EBCDIC-CP-ES", "CP284"); - fIANA2JavaMap.put("EBCDIC-CP-GB", "CP285"); - fIANA2JavaMap.put("IBM285", "CP285"); - fIANA2JavaMap.put("CP285", "CP285"); - fIANA2JavaMap.put("CSIBM285", "CP285"); - fIANA2JavaMap.put("EBCDIC-JP-KANA", "CP290"); - fIANA2JavaMap.put("IBM290", "CP290"); - fIANA2JavaMap.put("CP290", "CP290"); - fIANA2JavaMap.put("CSIBM290", "CP290"); - fIANA2JavaMap.put("EBCDIC-CP-FR", "CP297"); - fIANA2JavaMap.put("IBM297", "CP297"); - fIANA2JavaMap.put("CP297", "CP297"); - fIANA2JavaMap.put("CSIBM297", "CP297"); - fIANA2JavaMap.put("EBCDIC-CP-AR1", "CP420"); - fIANA2JavaMap.put("IBM420", "CP420"); - fIANA2JavaMap.put("CP420", "CP420"); - fIANA2JavaMap.put("CSIBM420", "CP420"); - fIANA2JavaMap.put("EBCDIC-CP-HE", "CP424"); - fIANA2JavaMap.put("IBM424", "CP424"); - fIANA2JavaMap.put("CP424", "CP424"); - fIANA2JavaMap.put("CSIBM424", "CP424"); - fIANA2JavaMap.put("IBM437", "CP437"); - fIANA2JavaMap.put("437", "CP437"); - fIANA2JavaMap.put("CP437", "CP437"); - fIANA2JavaMap.put("CSPC8CODEPAGE437", "CP437"); - fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); - fIANA2JavaMap.put("IBM500", "CP500"); - fIANA2JavaMap.put("CP500", "CP500"); - fIANA2JavaMap.put("CSIBM500", "CP500"); - fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); - fIANA2JavaMap.put("EBCDIC-CP-BE", "CP500"); - fIANA2JavaMap.put("IBM775", "CP775"); - fIANA2JavaMap.put("CP775", "CP775"); - fIANA2JavaMap.put("CSPC775BALTIC", "CP775"); - fIANA2JavaMap.put("IBM850", "CP850"); - fIANA2JavaMap.put("850", "CP850"); - fIANA2JavaMap.put("CP850", "CP850"); - fIANA2JavaMap.put("CSPC850MULTILINGUAL", "CP850"); - fIANA2JavaMap.put("IBM852", "CP852"); - fIANA2JavaMap.put("852", "CP852"); - fIANA2JavaMap.put("CP852", "CP852"); - fIANA2JavaMap.put("CSPCP852", "CP852"); - fIANA2JavaMap.put("IBM855", "CP855"); - fIANA2JavaMap.put("855", "CP855"); - fIANA2JavaMap.put("CP855", "CP855"); - fIANA2JavaMap.put("CSIBM855", "CP855"); - fIANA2JavaMap.put("IBM857", "CP857"); - fIANA2JavaMap.put("857", "CP857"); - fIANA2JavaMap.put("CP857", "CP857"); - fIANA2JavaMap.put("CSIBM857", "CP857"); - fIANA2JavaMap.put("IBM00858", "CP858"); - fIANA2JavaMap.put("CP00858", "CP858"); - fIANA2JavaMap.put("CCSID00858", "CP858"); - fIANA2JavaMap.put("IBM860", "CP860"); - fIANA2JavaMap.put("860", "CP860"); - fIANA2JavaMap.put("CP860", "CP860"); - fIANA2JavaMap.put("CSIBM860", "CP860"); - fIANA2JavaMap.put("IBM861", "CP861"); - fIANA2JavaMap.put("861", "CP861"); - fIANA2JavaMap.put("CP861", "CP861"); - fIANA2JavaMap.put("CP-IS", "CP861"); - fIANA2JavaMap.put("CSIBM861", "CP861"); - fIANA2JavaMap.put("IBM862", "CP862"); - fIANA2JavaMap.put("862", "CP862"); - fIANA2JavaMap.put("CP862", "CP862"); - fIANA2JavaMap.put("CSPC862LATINHEBREW", "CP862"); - fIANA2JavaMap.put("IBM863", "CP863"); - fIANA2JavaMap.put("863", "CP863"); - fIANA2JavaMap.put("CP863", "CP863"); - fIANA2JavaMap.put("CSIBM863", "CP863"); - fIANA2JavaMap.put("IBM864", "CP864"); - fIANA2JavaMap.put("CP864", "CP864"); - fIANA2JavaMap.put("CSIBM864", "CP864"); - fIANA2JavaMap.put("IBM865", "CP865"); - fIANA2JavaMap.put("865", "CP865"); - fIANA2JavaMap.put("CP865", "CP865"); - fIANA2JavaMap.put("CSIBM865", "CP865"); - fIANA2JavaMap.put("IBM866", "CP866"); - fIANA2JavaMap.put("866", "CP866"); - fIANA2JavaMap.put("CP866", "CP866"); - fIANA2JavaMap.put("CSIBM866", "CP866"); - fIANA2JavaMap.put("IBM868", "CP868"); - fIANA2JavaMap.put("CP868", "CP868"); - fIANA2JavaMap.put("CSIBM868", "CP868"); - fIANA2JavaMap.put("CP-AR", "CP868"); - fIANA2JavaMap.put("IBM869", "CP869"); - fIANA2JavaMap.put("CP869", "CP869"); - fIANA2JavaMap.put("CSIBM869", "CP869"); - fIANA2JavaMap.put("CP-GR", "CP869"); - fIANA2JavaMap.put("IBM870", "CP870"); - fIANA2JavaMap.put("CP870", "CP870"); - fIANA2JavaMap.put("CSIBM870", "CP870"); - fIANA2JavaMap.put("EBCDIC-CP-ROECE", "CP870"); - fIANA2JavaMap.put("EBCDIC-CP-YU", "CP870"); - fIANA2JavaMap.put("IBM871", "CP871"); - fIANA2JavaMap.put("CP871", "CP871"); - fIANA2JavaMap.put("CSIBM871", "CP871"); - fIANA2JavaMap.put("EBCDIC-CP-IS", "CP871"); - fIANA2JavaMap.put("IBM918", "CP918"); - fIANA2JavaMap.put("CP918", "CP918"); - fIANA2JavaMap.put("CSIBM918", "CP918"); - fIANA2JavaMap.put("EBCDIC-CP-AR2", "CP918"); - fIANA2JavaMap.put("IBM00924", "CP924"); - fIANA2JavaMap.put("CP00924", "CP924"); - fIANA2JavaMap.put("CCSID00924", "CP924"); - // is this an error??? - fIANA2JavaMap.put("EBCDIC-LATIN9--EURO", "CP924"); - fIANA2JavaMap.put("IBM1026", "CP1026"); - fIANA2JavaMap.put("CP1026", "CP1026"); - fIANA2JavaMap.put("CSIBM1026", "CP1026"); - fIANA2JavaMap.put("IBM01140", "Cp1140"); - fIANA2JavaMap.put("CP01140", "Cp1140"); - fIANA2JavaMap.put("CCSID01140", "Cp1140"); - fIANA2JavaMap.put("IBM01141", "Cp1141"); - fIANA2JavaMap.put("CP01141", "Cp1141"); - fIANA2JavaMap.put("CCSID01141", "Cp1141"); - fIANA2JavaMap.put("IBM01142", "Cp1142"); - fIANA2JavaMap.put("CP01142", "Cp1142"); - fIANA2JavaMap.put("CCSID01142", "Cp1142"); - fIANA2JavaMap.put("IBM01143", "Cp1143"); - fIANA2JavaMap.put("CP01143", "Cp1143"); - fIANA2JavaMap.put("CCSID01143", "Cp1143"); - fIANA2JavaMap.put("IBM01144", "Cp1144"); - fIANA2JavaMap.put("CP01144", "Cp1144"); - fIANA2JavaMap.put("CCSID01144", "Cp1144"); - fIANA2JavaMap.put("IBM01145", "Cp1145"); - fIANA2JavaMap.put("CP01145", "Cp1145"); - fIANA2JavaMap.put("CCSID01145", "Cp1145"); - fIANA2JavaMap.put("IBM01146", "Cp1146"); - fIANA2JavaMap.put("CP01146", "Cp1146"); - fIANA2JavaMap.put("CCSID01146", "Cp1146"); - fIANA2JavaMap.put("IBM01147", "Cp1147"); - fIANA2JavaMap.put("CP01147", "Cp1147"); - fIANA2JavaMap.put("CCSID01147", "Cp1147"); - fIANA2JavaMap.put("IBM01148", "Cp1148"); - fIANA2JavaMap.put("CP01148", "Cp1148"); - fIANA2JavaMap.put("CCSID01148", "Cp1148"); - fIANA2JavaMap.put("IBM01149", "Cp1149"); - fIANA2JavaMap.put("CP01149", "Cp1149"); - fIANA2JavaMap.put("CCSID01149", "Cp1149"); - fIANA2JavaMap.put("EUC-JP", "EUCJIS"); - fIANA2JavaMap.put("CSEUCPKDFMTJAPANESE", "EUCJIS"); - fIANA2JavaMap.put("EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", "EUCJIS"); - fIANA2JavaMap.put("EUC-KR", "KSC5601"); - fIANA2JavaMap.put("CSEUCKR", "KSC5601"); - fIANA2JavaMap.put("KS_C_5601-1987", "KS_C_5601-1987"); - fIANA2JavaMap.put("ISO-IR-149", "KS_C_5601-1987"); - fIANA2JavaMap.put("KS_C_5601-1989", "KS_C_5601-1987"); - fIANA2JavaMap.put("KSC_5601", "KS_C_5601-1987"); - fIANA2JavaMap.put("KOREAN", "KS_C_5601-1987"); - fIANA2JavaMap.put("CSKSC56011987", "KS_C_5601-1987"); - fIANA2JavaMap.put("GB2312", "GB2312"); - fIANA2JavaMap.put("CSGB2312", "GB2312"); - fIANA2JavaMap.put("ISO-2022-JP", "JIS"); - fIANA2JavaMap.put("CSISO2022JP", "JIS"); - fIANA2JavaMap.put("ISO-2022-KR", "ISO2022KR"); - fIANA2JavaMap.put("CSISO2022KR", "ISO2022KR"); - fIANA2JavaMap.put("ISO-2022-CN", "ISO2022CN"); - - fIANA2JavaMap.put("X0201", "JIS0201"); - fIANA2JavaMap.put("CSISO13JISC6220JP", "JIS0201"); - fIANA2JavaMap.put("X0208", "JIS0208"); - fIANA2JavaMap.put("ISO-IR-87", "JIS0208"); - fIANA2JavaMap.put("X0208dbiJIS_X0208-1983", "JIS0208"); - fIANA2JavaMap.put("CSISO87JISX0208", "JIS0208"); - fIANA2JavaMap.put("X0212", "JIS0212"); - fIANA2JavaMap.put("ISO-IR-159", "JIS0212"); - fIANA2JavaMap.put("CSISO159JISX02121990", "JIS0212"); - fIANA2JavaMap.put("GB18030", "GB18030"); - fIANA2JavaMap.put("GBK", "GBK"); - fIANA2JavaMap.put("CP936", "GBK"); - fIANA2JavaMap.put("MS936", "GBK"); - fIANA2JavaMap.put("WINDOWS-936", "GBK"); - fIANA2JavaMap.put("SHIFT_JIS", "SJIS"); - fIANA2JavaMap.put("CSSHIFTJIS", "SJIS"); - fIANA2JavaMap.put("MS_KANJI", "SJIS"); - fIANA2JavaMap.put("WINDOWS-31J", "MS932"); - fIANA2JavaMap.put("CSWINDOWS31J", "MS932"); - - // Add support for Cp1252 and its friends - fIANA2JavaMap.put("WINDOWS-1250", "Cp1250"); - fIANA2JavaMap.put("WINDOWS-1251", "Cp1251"); - fIANA2JavaMap.put("WINDOWS-1252", "Cp1252"); - fIANA2JavaMap.put("WINDOWS-1253", "Cp1253"); - fIANA2JavaMap.put("WINDOWS-1254", "Cp1254"); - fIANA2JavaMap.put("WINDOWS-1255", "Cp1255"); - fIANA2JavaMap.put("WINDOWS-1256", "Cp1256"); - fIANA2JavaMap.put("WINDOWS-1257", "Cp1257"); - fIANA2JavaMap.put("WINDOWS-1258", "Cp1258"); - fIANA2JavaMap.put("TIS-620", "TIS620"); - - fIANA2JavaMap.put("ISO-8859-1", "ISO8859_1"); - fIANA2JavaMap.put("ISO-IR-100", "ISO8859_1"); - fIANA2JavaMap.put("ISO_8859-1", "ISO8859_1"); - fIANA2JavaMap.put("LATIN1", "ISO8859_1"); - fIANA2JavaMap.put("CSISOLATIN1", "ISO8859_1"); - fIANA2JavaMap.put("L1", "ISO8859_1"); - fIANA2JavaMap.put("IBM819", "ISO8859_1"); - fIANA2JavaMap.put("CP819", "ISO8859_1"); - - fIANA2JavaMap.put("ISO-8859-2", "ISO8859_2"); - fIANA2JavaMap.put("ISO-IR-101", "ISO8859_2"); - fIANA2JavaMap.put("ISO_8859-2", "ISO8859_2"); - fIANA2JavaMap.put("LATIN2", "ISO8859_2"); - fIANA2JavaMap.put("CSISOLATIN2", "ISO8859_2"); - fIANA2JavaMap.put("L2", "ISO8859_2"); - - fIANA2JavaMap.put("ISO-8859-3", "ISO8859_3"); - fIANA2JavaMap.put("ISO-IR-109", "ISO8859_3"); - fIANA2JavaMap.put("ISO_8859-3", "ISO8859_3"); - fIANA2JavaMap.put("LATIN3", "ISO8859_3"); - fIANA2JavaMap.put("CSISOLATIN3", "ISO8859_3"); - fIANA2JavaMap.put("L3", "ISO8859_3"); - - fIANA2JavaMap.put("ISO-8859-4", "ISO8859_4"); - fIANA2JavaMap.put("ISO-IR-110", "ISO8859_4"); - fIANA2JavaMap.put("ISO_8859-4", "ISO8859_4"); - fIANA2JavaMap.put("LATIN4", "ISO8859_4"); - fIANA2JavaMap.put("CSISOLATIN4", "ISO8859_4"); - fIANA2JavaMap.put("L4", "ISO8859_4"); - - fIANA2JavaMap.put("ISO-8859-5", "ISO8859_5"); - fIANA2JavaMap.put("ISO-IR-144", "ISO8859_5"); - fIANA2JavaMap.put("ISO_8859-5", "ISO8859_5"); - fIANA2JavaMap.put("CYRILLIC", "ISO8859_5"); - fIANA2JavaMap.put("CSISOLATINCYRILLIC", "ISO8859_5"); - - fIANA2JavaMap.put("ISO-8859-6", "ISO8859_6"); - fIANA2JavaMap.put("ISO-IR-127", "ISO8859_6"); - fIANA2JavaMap.put("ISO_8859-6", "ISO8859_6"); - fIANA2JavaMap.put("ECMA-114", "ISO8859_6"); - fIANA2JavaMap.put("ASMO-708", "ISO8859_6"); - fIANA2JavaMap.put("ARABIC", "ISO8859_6"); - fIANA2JavaMap.put("CSISOLATINARABIC", "ISO8859_6"); - - fIANA2JavaMap.put("ISO-8859-7", "ISO8859_7"); - fIANA2JavaMap.put("ISO-IR-126", "ISO8859_7"); - fIANA2JavaMap.put("ISO_8859-7", "ISO8859_7"); - fIANA2JavaMap.put("ELOT_928", "ISO8859_7"); - fIANA2JavaMap.put("ECMA-118", "ISO8859_7"); - fIANA2JavaMap.put("GREEK", "ISO8859_7"); - fIANA2JavaMap.put("CSISOLATINGREEK", "ISO8859_7"); - fIANA2JavaMap.put("GREEK8", "ISO8859_7"); - - fIANA2JavaMap.put("ISO-8859-8", "ISO8859_8"); - fIANA2JavaMap.put("ISO-8859-8-I", "ISO8859_8"); // added since this encoding only differs w.r.t. presentation - fIANA2JavaMap.put("ISO-IR-138", "ISO8859_8"); - fIANA2JavaMap.put("ISO_8859-8", "ISO8859_8"); - fIANA2JavaMap.put("HEBREW", "ISO8859_8"); - fIANA2JavaMap.put("CSISOLATINHEBREW", "ISO8859_8"); - - fIANA2JavaMap.put("ISO-8859-9", "ISO8859_9"); - fIANA2JavaMap.put("ISO-IR-148", "ISO8859_9"); - fIANA2JavaMap.put("ISO_8859-9", "ISO8859_9"); - fIANA2JavaMap.put("LATIN5", "ISO8859_9"); - fIANA2JavaMap.put("CSISOLATIN5", "ISO8859_9"); - fIANA2JavaMap.put("L5", "ISO8859_9"); - - fIANA2JavaMap.put("ISO-8859-13", "ISO8859_13"); - - fIANA2JavaMap.put("ISO-8859-15", "ISO8859_15_FDIS"); - fIANA2JavaMap.put("ISO_8859-15", "ISO8859_15_FDIS"); - fIANA2JavaMap.put("LATIN-9", "ISO8859_15_FDIS"); - - fIANA2JavaMap.put("KOI8-R", "KOI8_R"); - fIANA2JavaMap.put("CSKOI8R", "KOI8_R"); - fIANA2JavaMap.put("US-ASCII", "ASCII"); - fIANA2JavaMap.put("ISO-IR-6", "ASCII"); - fIANA2JavaMap.put("ANSI_X3.4-1968", "ASCII"); - fIANA2JavaMap.put("ANSI_X3.4-1986", "ASCII"); - fIANA2JavaMap.put("ISO_646.IRV:1991", "ASCII"); - fIANA2JavaMap.put("ASCII", "ASCII"); - fIANA2JavaMap.put("CSASCII", "ASCII"); - fIANA2JavaMap.put("ISO646-US", "ASCII"); - fIANA2JavaMap.put("US", "ASCII"); - fIANA2JavaMap.put("IBM367", "ASCII"); - fIANA2JavaMap.put("CP367", "ASCII"); - fIANA2JavaMap.put("UTF-8", "UTF8"); - fIANA2JavaMap.put("UTF-16", "UTF-16"); - fIANA2JavaMap.put("UTF-16BE", "UnicodeBig"); - fIANA2JavaMap.put("UTF-16LE", "UnicodeLittle"); - - // support for 1047, as proposed to be added to the - // IANA registry in - // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0049.html - fIANA2JavaMap.put("IBM-1047", "Cp1047"); - fIANA2JavaMap.put("IBM1047", "Cp1047"); - fIANA2JavaMap.put("CP1047", "Cp1047"); - - // Adding new aliases as proposed in - // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0058.html - fIANA2JavaMap.put("IBM-37", "CP037"); - fIANA2JavaMap.put("IBM-273", "CP273"); - fIANA2JavaMap.put("IBM-277", "CP277"); - fIANA2JavaMap.put("IBM-278", "CP278"); - fIANA2JavaMap.put("IBM-280", "CP280"); - fIANA2JavaMap.put("IBM-284", "CP284"); - fIANA2JavaMap.put("IBM-285", "CP285"); - fIANA2JavaMap.put("IBM-290", "CP290"); - fIANA2JavaMap.put("IBM-297", "CP297"); - fIANA2JavaMap.put("IBM-420", "CP420"); - fIANA2JavaMap.put("IBM-424", "CP424"); - fIANA2JavaMap.put("IBM-437", "CP437"); - fIANA2JavaMap.put("IBM-500", "CP500"); - fIANA2JavaMap.put("IBM-775", "CP775"); - fIANA2JavaMap.put("IBM-850", "CP850"); - fIANA2JavaMap.put("IBM-852", "CP852"); - fIANA2JavaMap.put("IBM-855", "CP855"); - fIANA2JavaMap.put("IBM-857", "CP857"); - fIANA2JavaMap.put("IBM-858", "CP858"); - fIANA2JavaMap.put("IBM-860", "CP860"); - fIANA2JavaMap.put("IBM-861", "CP861"); - fIANA2JavaMap.put("IBM-862", "CP862"); - fIANA2JavaMap.put("IBM-863", "CP863"); - fIANA2JavaMap.put("IBM-864", "CP864"); - fIANA2JavaMap.put("IBM-865", "CP865"); - fIANA2JavaMap.put("IBM-866", "CP866"); - fIANA2JavaMap.put("IBM-868", "CP868"); - fIANA2JavaMap.put("IBM-869", "CP869"); - fIANA2JavaMap.put("IBM-870", "CP870"); - fIANA2JavaMap.put("IBM-871", "CP871"); - fIANA2JavaMap.put("IBM-918", "CP918"); - fIANA2JavaMap.put("IBM-924", "CP924"); - fIANA2JavaMap.put("IBM-1026", "CP1026"); - fIANA2JavaMap.put("IBM-1140", "Cp1140"); - fIANA2JavaMap.put("IBM-1141", "Cp1141"); - fIANA2JavaMap.put("IBM-1142", "Cp1142"); - fIANA2JavaMap.put("IBM-1143", "Cp1143"); - fIANA2JavaMap.put("IBM-1144", "Cp1144"); - fIANA2JavaMap.put("IBM-1145", "Cp1145"); - fIANA2JavaMap.put("IBM-1146", "Cp1146"); - fIANA2JavaMap.put("IBM-1147", "Cp1147"); - fIANA2JavaMap.put("IBM-1148", "Cp1148"); - fIANA2JavaMap.put("IBM-1149", "Cp1149"); - fIANA2JavaMap.put("IBM-819", "ISO8859_1"); - fIANA2JavaMap.put("IBM-367", "ASCII"); - - // REVISIT: - // j:CNS11643 -> EUC-TW? - // ISO-2022-CN? ISO-2022-CN-EXT? - - // add Java to IANA encoding mappings - //fJava2IANAMap.put("8859_1", "US-ASCII"); // ? - fJava2IANAMap.put("ISO8859_1", "ISO-8859-1"); - fJava2IANAMap.put("ISO8859_2", "ISO-8859-2"); - fJava2IANAMap.put("ISO8859_3", "ISO-8859-3"); - fJava2IANAMap.put("ISO8859_4", "ISO-8859-4"); - fJava2IANAMap.put("ISO8859_5", "ISO-8859-5"); - fJava2IANAMap.put("ISO8859_6", "ISO-8859-6"); - fJava2IANAMap.put("ISO8859_7", "ISO-8859-7"); - fJava2IANAMap.put("ISO8859_8", "ISO-8859-8"); - fJava2IANAMap.put("ISO8859_9", "ISO-8859-9"); - fJava2IANAMap.put("ISO8859_13", "ISO-8859-13"); - fJava2IANAMap.put("ISO8859_15", "ISO-8859-15"); - fJava2IANAMap.put("ISO8859_15_FDIS", "ISO-8859-15"); - fJava2IANAMap.put("Big5", "BIG5"); - fJava2IANAMap.put("CP037", "EBCDIC-CP-US"); - fJava2IANAMap.put("CP273", "IBM273"); - fJava2IANAMap.put("CP277", "EBCDIC-CP-DK"); - fJava2IANAMap.put("CP278", "EBCDIC-CP-FI"); - fJava2IANAMap.put("CP280", "EBCDIC-CP-IT"); - fJava2IANAMap.put("CP284", "EBCDIC-CP-ES"); - fJava2IANAMap.put("CP285", "EBCDIC-CP-GB"); - fJava2IANAMap.put("CP290", "EBCDIC-JP-KANA"); - fJava2IANAMap.put("CP297", "EBCDIC-CP-FR"); - fJava2IANAMap.put("CP420", "EBCDIC-CP-AR1"); - fJava2IANAMap.put("CP424", "EBCDIC-CP-HE"); - fJava2IANAMap.put("CP437", "IBM437"); - fJava2IANAMap.put("CP500", "EBCDIC-CP-CH"); - fJava2IANAMap.put("CP775", "IBM775"); - fJava2IANAMap.put("CP850", "IBM850"); - fJava2IANAMap.put("CP852", "IBM852"); - fJava2IANAMap.put("CP855", "IBM855"); - fJava2IANAMap.put("CP857", "IBM857"); - fJava2IANAMap.put("CP858", "IBM00858"); - fJava2IANAMap.put("CP860", "IBM860"); - fJava2IANAMap.put("CP861", "IBM861"); - fJava2IANAMap.put("CP862", "IBM862"); - fJava2IANAMap.put("CP863", "IBM863"); - fJava2IANAMap.put("CP864", "IBM864"); - fJava2IANAMap.put("CP865", "IBM865"); - fJava2IANAMap.put("CP866", "IBM866"); - fJava2IANAMap.put("CP868", "IBM868"); - fJava2IANAMap.put("CP869", "IBM869"); - fJava2IANAMap.put("CP870", "EBCDIC-CP-ROECE"); - fJava2IANAMap.put("CP871", "EBCDIC-CP-IS"); - fJava2IANAMap.put("CP918", "EBCDIC-CP-AR2"); - fJava2IANAMap.put("CP924", "IBM00924"); - fJava2IANAMap.put("CP1026", "IBM1026"); - fJava2IANAMap.put("Cp01140", "IBM01140"); - fJava2IANAMap.put("Cp01141", "IBM01141"); - fJava2IANAMap.put("Cp01142", "IBM01142"); - fJava2IANAMap.put("Cp01143", "IBM01143"); - fJava2IANAMap.put("Cp01144", "IBM01144"); - fJava2IANAMap.put("Cp01145", "IBM01145"); - fJava2IANAMap.put("Cp01146", "IBM01146"); - fJava2IANAMap.put("Cp01147", "IBM01147"); - fJava2IANAMap.put("Cp01148", "IBM01148"); - fJava2IANAMap.put("Cp01149", "IBM01149"); - fJava2IANAMap.put("EUCJIS", "EUC-JP"); - fJava2IANAMap.put("KS_C_5601-1987", "KS_C_5601-1987"); - fJava2IANAMap.put("GB2312", "GB2312"); - fJava2IANAMap.put("ISO2022KR", "ISO-2022-KR"); - fJava2IANAMap.put("ISO2022CN", "ISO-2022-CN"); - fJava2IANAMap.put("JIS", "ISO-2022-JP"); - fJava2IANAMap.put("KOI8_R", "KOI8-R"); - fJava2IANAMap.put("KSC5601", "EUC-KR"); - fJava2IANAMap.put("GB18030", "GB18030"); - fJava2IANAMap.put("GBK", "GBK"); - fJava2IANAMap.put("SJIS", "SHIFT_JIS"); - fJava2IANAMap.put("MS932", "WINDOWS-31J"); - fJava2IANAMap.put("UTF8", "UTF-8"); - fJava2IANAMap.put("Unicode", "UTF-16"); - fJava2IANAMap.put("UnicodeBig", "UTF-16BE"); - fJava2IANAMap.put("UnicodeLittle", "UTF-16LE"); - fJava2IANAMap.put("JIS0201", "X0201"); - fJava2IANAMap.put("JIS0208", "X0208"); - fJava2IANAMap.put("JIS0212", "ISO-IR-159"); - - // proposed addition (see above for details): - fJava2IANAMap.put("CP1047", "IBM1047"); - - } // () - - // - // Constructors - // - - /** Default constructor. */ - public EncodingMap() {} - - // - // Public static methods - // - - /** - * Adds an IANA to Java encoding name mapping. - * - * @param ianaEncoding The IANA encoding name. - * @param javaEncoding The Java encoding name. - */ - public static void putIANA2JavaMapping(String ianaEncoding, - String javaEncoding) { - fIANA2JavaMap.put(ianaEncoding, javaEncoding); - } // putIANA2JavaMapping(String,String) - - /** - * Returns the Java encoding name for the specified IANA encoding name. - * - * @param ianaEncoding The IANA encoding name. - */ - public static String getIANA2JavaMapping(String ianaEncoding) { - return (String)fIANA2JavaMap.get(ianaEncoding); - } // getIANA2JavaMapping(String):String - - /** - * Removes an IANA to Java encoding name mapping. - * - * @param ianaEncoding The IANA encoding name. - */ - public static String removeIANA2JavaMapping(String ianaEncoding) { - return (String)fIANA2JavaMap.remove(ianaEncoding); - } // removeIANA2JavaMapping(String):String - - /** - * Adds a Java to IANA encoding name mapping. - * - * @param javaEncoding The Java encoding name. - * @param ianaEncoding The IANA encoding name. - */ - public static void putJava2IANAMapping(String javaEncoding, - String ianaEncoding) { - fJava2IANAMap.put(javaEncoding, ianaEncoding); - } // putJava2IANAMapping(String,String) - - /** - * Returns the IANA encoding name for the specified Java encoding name. - * - * @param javaEncoding The Java encoding name. - */ - public static String getJava2IANAMapping(String javaEncoding) { - return (String)fJava2IANAMap.get(javaEncoding); - } // getJava2IANAMapping(String):String - - /** - * Removes a Java to IANA encoding name mapping. - * - * @param javaEncoding The Java encoding name. - */ - public static String removeJava2IANAMapping(String javaEncoding) { - return (String)fJava2IANAMap.remove(javaEncoding); - } // removeJava2IANAMapping - -} // class EncodingMap +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +import java.util.Hashtable; + +/** + * EncodingMap is a convenience class which handles conversions between + * IANA encoding names and Java encoding names, and vice versa. The + * encoding names used in XML instance documents must + * be the IANA encoding names specified or one of the aliases for those names + * which IANA defines. + *

        + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
        + *

        Common Name + *

        + *

        Use this name in XML files + *

        + *

        Name Type + *

        + *

        Xerces converts to this Java Encoder Name + *

        8 bit Unicode + *

        UTF-8 + *

        + *

        IANA + *

        + *

        UTF8 + *

        ISO Latin 1 + *

        ISO-8859-1 + *

        + *

        MIME + *

        + *

        ISO-8859-1 + *

        ISO Latin 2 + *

        ISO-8859-2 + *

        + *

        MIME + *

        + *

        ISO-8859-2 + *

        ISO Latin 3 + *

        ISO-8859-3 + *

        + *

        MIME + *

        + *

        ISO-8859-3 + *

        ISO Latin 4 + *

        ISO-8859-4 + *

        + *

        MIME + *

        + *

        ISO-8859-4 + *

        ISO Latin Cyrillic + *

        ISO-8859-5 + *

        + *

        MIME + *

        + *

        ISO-8859-5 + *

        ISO Latin Arabic + *

        ISO-8859-6 + *

        + *

        MIME + *

        + *

        ISO-8859-6 + *

        ISO Latin Greek + *

        ISO-8859-7 + *

        + *

        MIME + *

        + *

        ISO-8859-7 + *

        ISO Latin Hebrew + *

        ISO-8859-8 + *

        + *

        MIME + *

        + *

        ISO-8859-8 + *

        ISO Latin 5 + *

        ISO-8859-9 + *

        + *

        MIME + *

        + *

        ISO-8859-9 + *

        EBCDIC: US + *

        ebcdic-cp-us + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Canada + *

        ebcdic-cp-ca + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Netherlands + *

        ebcdic-cp-nl + *

        + *

        IANA + *

        + *

        cp037 + *

        EBCDIC: Denmark + *

        ebcdic-cp-dk + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Norway + *

        ebcdic-cp-no + *

        + *

        IANA + *

        + *

        cp277 + *

        EBCDIC: Finland + *

        ebcdic-cp-fi + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Sweden + *

        ebcdic-cp-se + *

        + *

        IANA + *

        + *

        cp278 + *

        EBCDIC: Italy + *

        ebcdic-cp-it + *

        + *

        IANA + *

        + *

        cp280 + *

        EBCDIC: Spain, Latin America + *

        ebcdic-cp-es + *

        + *

        IANA + *

        + *

        cp284 + *

        EBCDIC: Great Britain + *

        ebcdic-cp-gb + *

        + *

        IANA + *

        + *

        cp285 + *

        EBCDIC: France + *

        ebcdic-cp-fr + *

        + *

        IANA + *

        + *

        cp297 + *

        EBCDIC: Arabic + *

        ebcdic-cp-ar1 + *

        + *

        IANA + *

        + *

        cp420 + *

        EBCDIC: Hebrew + *

        ebcdic-cp-he + *

        + *

        IANA + *

        + *

        cp424 + *

        EBCDIC: Switzerland + *

        ebcdic-cp-ch + *

        + *

        IANA + *

        + *

        cp500 + *

        EBCDIC: Roece + *

        ebcdic-cp-roece + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Yugoslavia + *

        ebcdic-cp-yu + *

        + *

        IANA + *

        + *

        cp870 + *

        EBCDIC: Iceland + *

        ebcdic-cp-is + *

        + *

        IANA + *

        + *

        cp871 + *

        EBCDIC: Urdu + *

        ebcdic-cp-ar2 + *

        + *

        IANA + *

        + *

        cp918 + *

        Chinese for PRC, mixed 1/2 byte + *

        gb2312 + *

        + *

        MIME + *

        + *

        GB2312 + *

        Extended Unix Code, packed for Japanese + *

        euc-jp + *

        + *

        MIME + *

        + *

        eucjis + *

        Japanese: iso-2022-jp + *

        iso-2020-jp + *

        + *

        MIME + *

        + *

        JIS + *

        Japanese: Shift JIS + *

        Shift_JIS + *

        + *

        MIME + *

        + *

        SJIS + *

        Chinese: Big5 + *

        Big5 + *

        + *

        MIME + *

        + *

        Big5 + *

        Extended Unix Code, packed for Korean + *

        euc-kr + *

        + *

        MIME + *

        + *

        iso2022kr + *

        Cyrillic + *

        koi8-r + *

        + *

        MIME + *

        + *

        koi8-r + *

        + * + * @author TAMURA Kent, IBM + * @author Andy Clark, IBM + * + * @version $Id: EncodingMap.java 306086 2004-10-01 19:24:35Z luehe $ + */ +public class EncodingMap { + + // + // Data + // + + /** fIANA2JavaMap */ + protected final static Hashtable fIANA2JavaMap = new Hashtable(); + + /** fJava2IANAMap */ + protected final static Hashtable fJava2IANAMap = new Hashtable(); + + // + // Static initialization + // + + static { + + // add IANA to Java encoding mappings. + fIANA2JavaMap.put("BIG5", "Big5"); + fIANA2JavaMap.put("CSBIG5", "Big5"); + fIANA2JavaMap.put("CP037", "CP037"); + fIANA2JavaMap.put("IBM037", "CP037"); + fIANA2JavaMap.put("CSIBM037", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-US", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-CA", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-NL", "CP037"); + fIANA2JavaMap.put("EBCDIC-CP-WT", "CP037"); + fIANA2JavaMap.put("IBM273", "CP273"); + fIANA2JavaMap.put("CP273", "CP273"); + fIANA2JavaMap.put("CSIBM273", "CP273"); + fIANA2JavaMap.put("IBM277", "CP277"); + fIANA2JavaMap.put("CP277", "CP277"); + fIANA2JavaMap.put("CSIBM277", "CP277"); + fIANA2JavaMap.put("EBCDIC-CP-DK", "CP277"); + fIANA2JavaMap.put("EBCDIC-CP-NO", "CP277"); + fIANA2JavaMap.put("IBM278", "CP278"); + fIANA2JavaMap.put("CP278", "CP278"); + fIANA2JavaMap.put("CSIBM278", "CP278"); + fIANA2JavaMap.put("EBCDIC-CP-FI", "CP278"); + fIANA2JavaMap.put("EBCDIC-CP-SE", "CP278"); + fIANA2JavaMap.put("IBM280", "CP280"); + fIANA2JavaMap.put("CP280", "CP280"); + fIANA2JavaMap.put("CSIBM280", "CP280"); + fIANA2JavaMap.put("EBCDIC-CP-IT", "CP280"); + fIANA2JavaMap.put("IBM284", "CP284"); + fIANA2JavaMap.put("CP284", "CP284"); + fIANA2JavaMap.put("CSIBM284", "CP284"); + fIANA2JavaMap.put("EBCDIC-CP-ES", "CP284"); + fIANA2JavaMap.put("EBCDIC-CP-GB", "CP285"); + fIANA2JavaMap.put("IBM285", "CP285"); + fIANA2JavaMap.put("CP285", "CP285"); + fIANA2JavaMap.put("CSIBM285", "CP285"); + fIANA2JavaMap.put("EBCDIC-JP-KANA", "CP290"); + fIANA2JavaMap.put("IBM290", "CP290"); + fIANA2JavaMap.put("CP290", "CP290"); + fIANA2JavaMap.put("CSIBM290", "CP290"); + fIANA2JavaMap.put("EBCDIC-CP-FR", "CP297"); + fIANA2JavaMap.put("IBM297", "CP297"); + fIANA2JavaMap.put("CP297", "CP297"); + fIANA2JavaMap.put("CSIBM297", "CP297"); + fIANA2JavaMap.put("EBCDIC-CP-AR1", "CP420"); + fIANA2JavaMap.put("IBM420", "CP420"); + fIANA2JavaMap.put("CP420", "CP420"); + fIANA2JavaMap.put("CSIBM420", "CP420"); + fIANA2JavaMap.put("EBCDIC-CP-HE", "CP424"); + fIANA2JavaMap.put("IBM424", "CP424"); + fIANA2JavaMap.put("CP424", "CP424"); + fIANA2JavaMap.put("CSIBM424", "CP424"); + fIANA2JavaMap.put("IBM437", "CP437"); + fIANA2JavaMap.put("437", "CP437"); + fIANA2JavaMap.put("CP437", "CP437"); + fIANA2JavaMap.put("CSPC8CODEPAGE437", "CP437"); + fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); + fIANA2JavaMap.put("IBM500", "CP500"); + fIANA2JavaMap.put("CP500", "CP500"); + fIANA2JavaMap.put("CSIBM500", "CP500"); + fIANA2JavaMap.put("EBCDIC-CP-CH", "CP500"); + fIANA2JavaMap.put("EBCDIC-CP-BE", "CP500"); + fIANA2JavaMap.put("IBM775", "CP775"); + fIANA2JavaMap.put("CP775", "CP775"); + fIANA2JavaMap.put("CSPC775BALTIC", "CP775"); + fIANA2JavaMap.put("IBM850", "CP850"); + fIANA2JavaMap.put("850", "CP850"); + fIANA2JavaMap.put("CP850", "CP850"); + fIANA2JavaMap.put("CSPC850MULTILINGUAL", "CP850"); + fIANA2JavaMap.put("IBM852", "CP852"); + fIANA2JavaMap.put("852", "CP852"); + fIANA2JavaMap.put("CP852", "CP852"); + fIANA2JavaMap.put("CSPCP852", "CP852"); + fIANA2JavaMap.put("IBM855", "CP855"); + fIANA2JavaMap.put("855", "CP855"); + fIANA2JavaMap.put("CP855", "CP855"); + fIANA2JavaMap.put("CSIBM855", "CP855"); + fIANA2JavaMap.put("IBM857", "CP857"); + fIANA2JavaMap.put("857", "CP857"); + fIANA2JavaMap.put("CP857", "CP857"); + fIANA2JavaMap.put("CSIBM857", "CP857"); + fIANA2JavaMap.put("IBM00858", "CP858"); + fIANA2JavaMap.put("CP00858", "CP858"); + fIANA2JavaMap.put("CCSID00858", "CP858"); + fIANA2JavaMap.put("IBM860", "CP860"); + fIANA2JavaMap.put("860", "CP860"); + fIANA2JavaMap.put("CP860", "CP860"); + fIANA2JavaMap.put("CSIBM860", "CP860"); + fIANA2JavaMap.put("IBM861", "CP861"); + fIANA2JavaMap.put("861", "CP861"); + fIANA2JavaMap.put("CP861", "CP861"); + fIANA2JavaMap.put("CP-IS", "CP861"); + fIANA2JavaMap.put("CSIBM861", "CP861"); + fIANA2JavaMap.put("IBM862", "CP862"); + fIANA2JavaMap.put("862", "CP862"); + fIANA2JavaMap.put("CP862", "CP862"); + fIANA2JavaMap.put("CSPC862LATINHEBREW", "CP862"); + fIANA2JavaMap.put("IBM863", "CP863"); + fIANA2JavaMap.put("863", "CP863"); + fIANA2JavaMap.put("CP863", "CP863"); + fIANA2JavaMap.put("CSIBM863", "CP863"); + fIANA2JavaMap.put("IBM864", "CP864"); + fIANA2JavaMap.put("CP864", "CP864"); + fIANA2JavaMap.put("CSIBM864", "CP864"); + fIANA2JavaMap.put("IBM865", "CP865"); + fIANA2JavaMap.put("865", "CP865"); + fIANA2JavaMap.put("CP865", "CP865"); + fIANA2JavaMap.put("CSIBM865", "CP865"); + fIANA2JavaMap.put("IBM866", "CP866"); + fIANA2JavaMap.put("866", "CP866"); + fIANA2JavaMap.put("CP866", "CP866"); + fIANA2JavaMap.put("CSIBM866", "CP866"); + fIANA2JavaMap.put("IBM868", "CP868"); + fIANA2JavaMap.put("CP868", "CP868"); + fIANA2JavaMap.put("CSIBM868", "CP868"); + fIANA2JavaMap.put("CP-AR", "CP868"); + fIANA2JavaMap.put("IBM869", "CP869"); + fIANA2JavaMap.put("CP869", "CP869"); + fIANA2JavaMap.put("CSIBM869", "CP869"); + fIANA2JavaMap.put("CP-GR", "CP869"); + fIANA2JavaMap.put("IBM870", "CP870"); + fIANA2JavaMap.put("CP870", "CP870"); + fIANA2JavaMap.put("CSIBM870", "CP870"); + fIANA2JavaMap.put("EBCDIC-CP-ROECE", "CP870"); + fIANA2JavaMap.put("EBCDIC-CP-YU", "CP870"); + fIANA2JavaMap.put("IBM871", "CP871"); + fIANA2JavaMap.put("CP871", "CP871"); + fIANA2JavaMap.put("CSIBM871", "CP871"); + fIANA2JavaMap.put("EBCDIC-CP-IS", "CP871"); + fIANA2JavaMap.put("IBM918", "CP918"); + fIANA2JavaMap.put("CP918", "CP918"); + fIANA2JavaMap.put("CSIBM918", "CP918"); + fIANA2JavaMap.put("EBCDIC-CP-AR2", "CP918"); + fIANA2JavaMap.put("IBM00924", "CP924"); + fIANA2JavaMap.put("CP00924", "CP924"); + fIANA2JavaMap.put("CCSID00924", "CP924"); + // is this an error??? + fIANA2JavaMap.put("EBCDIC-LATIN9--EURO", "CP924"); + fIANA2JavaMap.put("IBM1026", "CP1026"); + fIANA2JavaMap.put("CP1026", "CP1026"); + fIANA2JavaMap.put("CSIBM1026", "CP1026"); + fIANA2JavaMap.put("IBM01140", "Cp1140"); + fIANA2JavaMap.put("CP01140", "Cp1140"); + fIANA2JavaMap.put("CCSID01140", "Cp1140"); + fIANA2JavaMap.put("IBM01141", "Cp1141"); + fIANA2JavaMap.put("CP01141", "Cp1141"); + fIANA2JavaMap.put("CCSID01141", "Cp1141"); + fIANA2JavaMap.put("IBM01142", "Cp1142"); + fIANA2JavaMap.put("CP01142", "Cp1142"); + fIANA2JavaMap.put("CCSID01142", "Cp1142"); + fIANA2JavaMap.put("IBM01143", "Cp1143"); + fIANA2JavaMap.put("CP01143", "Cp1143"); + fIANA2JavaMap.put("CCSID01143", "Cp1143"); + fIANA2JavaMap.put("IBM01144", "Cp1144"); + fIANA2JavaMap.put("CP01144", "Cp1144"); + fIANA2JavaMap.put("CCSID01144", "Cp1144"); + fIANA2JavaMap.put("IBM01145", "Cp1145"); + fIANA2JavaMap.put("CP01145", "Cp1145"); + fIANA2JavaMap.put("CCSID01145", "Cp1145"); + fIANA2JavaMap.put("IBM01146", "Cp1146"); + fIANA2JavaMap.put("CP01146", "Cp1146"); + fIANA2JavaMap.put("CCSID01146", "Cp1146"); + fIANA2JavaMap.put("IBM01147", "Cp1147"); + fIANA2JavaMap.put("CP01147", "Cp1147"); + fIANA2JavaMap.put("CCSID01147", "Cp1147"); + fIANA2JavaMap.put("IBM01148", "Cp1148"); + fIANA2JavaMap.put("CP01148", "Cp1148"); + fIANA2JavaMap.put("CCSID01148", "Cp1148"); + fIANA2JavaMap.put("IBM01149", "Cp1149"); + fIANA2JavaMap.put("CP01149", "Cp1149"); + fIANA2JavaMap.put("CCSID01149", "Cp1149"); + fIANA2JavaMap.put("EUC-JP", "EUCJIS"); + fIANA2JavaMap.put("CSEUCPKDFMTJAPANESE", "EUCJIS"); + fIANA2JavaMap.put("EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", "EUCJIS"); + fIANA2JavaMap.put("EUC-KR", "KSC5601"); + fIANA2JavaMap.put("CSEUCKR", "KSC5601"); + fIANA2JavaMap.put("KS_C_5601-1987", "KS_C_5601-1987"); + fIANA2JavaMap.put("ISO-IR-149", "KS_C_5601-1987"); + fIANA2JavaMap.put("KS_C_5601-1989", "KS_C_5601-1987"); + fIANA2JavaMap.put("KSC_5601", "KS_C_5601-1987"); + fIANA2JavaMap.put("KOREAN", "KS_C_5601-1987"); + fIANA2JavaMap.put("CSKSC56011987", "KS_C_5601-1987"); + fIANA2JavaMap.put("GB2312", "GB2312"); + fIANA2JavaMap.put("CSGB2312", "GB2312"); + fIANA2JavaMap.put("ISO-2022-JP", "JIS"); + fIANA2JavaMap.put("CSISO2022JP", "JIS"); + fIANA2JavaMap.put("ISO-2022-KR", "ISO2022KR"); + fIANA2JavaMap.put("CSISO2022KR", "ISO2022KR"); + fIANA2JavaMap.put("ISO-2022-CN", "ISO2022CN"); + + fIANA2JavaMap.put("X0201", "JIS0201"); + fIANA2JavaMap.put("CSISO13JISC6220JP", "JIS0201"); + fIANA2JavaMap.put("X0208", "JIS0208"); + fIANA2JavaMap.put("ISO-IR-87", "JIS0208"); + fIANA2JavaMap.put("X0208dbiJIS_X0208-1983", "JIS0208"); + fIANA2JavaMap.put("CSISO87JISX0208", "JIS0208"); + fIANA2JavaMap.put("X0212", "JIS0212"); + fIANA2JavaMap.put("ISO-IR-159", "JIS0212"); + fIANA2JavaMap.put("CSISO159JISX02121990", "JIS0212"); + fIANA2JavaMap.put("GB18030", "GB18030"); + fIANA2JavaMap.put("GBK", "GBK"); + fIANA2JavaMap.put("CP936", "GBK"); + fIANA2JavaMap.put("MS936", "GBK"); + fIANA2JavaMap.put("WINDOWS-936", "GBK"); + fIANA2JavaMap.put("SHIFT_JIS", "SJIS"); + fIANA2JavaMap.put("CSSHIFTJIS", "SJIS"); + fIANA2JavaMap.put("MS_KANJI", "SJIS"); + fIANA2JavaMap.put("WINDOWS-31J", "MS932"); + fIANA2JavaMap.put("CSWINDOWS31J", "MS932"); + + // Add support for Cp1252 and its friends + fIANA2JavaMap.put("WINDOWS-1250", "Cp1250"); + fIANA2JavaMap.put("WINDOWS-1251", "Cp1251"); + fIANA2JavaMap.put("WINDOWS-1252", "Cp1252"); + fIANA2JavaMap.put("WINDOWS-1253", "Cp1253"); + fIANA2JavaMap.put("WINDOWS-1254", "Cp1254"); + fIANA2JavaMap.put("WINDOWS-1255", "Cp1255"); + fIANA2JavaMap.put("WINDOWS-1256", "Cp1256"); + fIANA2JavaMap.put("WINDOWS-1257", "Cp1257"); + fIANA2JavaMap.put("WINDOWS-1258", "Cp1258"); + fIANA2JavaMap.put("TIS-620", "TIS620"); + + fIANA2JavaMap.put("ISO-8859-1", "ISO8859_1"); + fIANA2JavaMap.put("ISO-IR-100", "ISO8859_1"); + fIANA2JavaMap.put("ISO_8859-1", "ISO8859_1"); + fIANA2JavaMap.put("LATIN1", "ISO8859_1"); + fIANA2JavaMap.put("CSISOLATIN1", "ISO8859_1"); + fIANA2JavaMap.put("L1", "ISO8859_1"); + fIANA2JavaMap.put("IBM819", "ISO8859_1"); + fIANA2JavaMap.put("CP819", "ISO8859_1"); + + fIANA2JavaMap.put("ISO-8859-2", "ISO8859_2"); + fIANA2JavaMap.put("ISO-IR-101", "ISO8859_2"); + fIANA2JavaMap.put("ISO_8859-2", "ISO8859_2"); + fIANA2JavaMap.put("LATIN2", "ISO8859_2"); + fIANA2JavaMap.put("CSISOLATIN2", "ISO8859_2"); + fIANA2JavaMap.put("L2", "ISO8859_2"); + + fIANA2JavaMap.put("ISO-8859-3", "ISO8859_3"); + fIANA2JavaMap.put("ISO-IR-109", "ISO8859_3"); + fIANA2JavaMap.put("ISO_8859-3", "ISO8859_3"); + fIANA2JavaMap.put("LATIN3", "ISO8859_3"); + fIANA2JavaMap.put("CSISOLATIN3", "ISO8859_3"); + fIANA2JavaMap.put("L3", "ISO8859_3"); + + fIANA2JavaMap.put("ISO-8859-4", "ISO8859_4"); + fIANA2JavaMap.put("ISO-IR-110", "ISO8859_4"); + fIANA2JavaMap.put("ISO_8859-4", "ISO8859_4"); + fIANA2JavaMap.put("LATIN4", "ISO8859_4"); + fIANA2JavaMap.put("CSISOLATIN4", "ISO8859_4"); + fIANA2JavaMap.put("L4", "ISO8859_4"); + + fIANA2JavaMap.put("ISO-8859-5", "ISO8859_5"); + fIANA2JavaMap.put("ISO-IR-144", "ISO8859_5"); + fIANA2JavaMap.put("ISO_8859-5", "ISO8859_5"); + fIANA2JavaMap.put("CYRILLIC", "ISO8859_5"); + fIANA2JavaMap.put("CSISOLATINCYRILLIC", "ISO8859_5"); + + fIANA2JavaMap.put("ISO-8859-6", "ISO8859_6"); + fIANA2JavaMap.put("ISO-IR-127", "ISO8859_6"); + fIANA2JavaMap.put("ISO_8859-6", "ISO8859_6"); + fIANA2JavaMap.put("ECMA-114", "ISO8859_6"); + fIANA2JavaMap.put("ASMO-708", "ISO8859_6"); + fIANA2JavaMap.put("ARABIC", "ISO8859_6"); + fIANA2JavaMap.put("CSISOLATINARABIC", "ISO8859_6"); + + fIANA2JavaMap.put("ISO-8859-7", "ISO8859_7"); + fIANA2JavaMap.put("ISO-IR-126", "ISO8859_7"); + fIANA2JavaMap.put("ISO_8859-7", "ISO8859_7"); + fIANA2JavaMap.put("ELOT_928", "ISO8859_7"); + fIANA2JavaMap.put("ECMA-118", "ISO8859_7"); + fIANA2JavaMap.put("GREEK", "ISO8859_7"); + fIANA2JavaMap.put("CSISOLATINGREEK", "ISO8859_7"); + fIANA2JavaMap.put("GREEK8", "ISO8859_7"); + + fIANA2JavaMap.put("ISO-8859-8", "ISO8859_8"); + fIANA2JavaMap.put("ISO-8859-8-I", "ISO8859_8"); // added since this encoding only differs w.r.t. presentation + fIANA2JavaMap.put("ISO-IR-138", "ISO8859_8"); + fIANA2JavaMap.put("ISO_8859-8", "ISO8859_8"); + fIANA2JavaMap.put("HEBREW", "ISO8859_8"); + fIANA2JavaMap.put("CSISOLATINHEBREW", "ISO8859_8"); + + fIANA2JavaMap.put("ISO-8859-9", "ISO8859_9"); + fIANA2JavaMap.put("ISO-IR-148", "ISO8859_9"); + fIANA2JavaMap.put("ISO_8859-9", "ISO8859_9"); + fIANA2JavaMap.put("LATIN5", "ISO8859_9"); + fIANA2JavaMap.put("CSISOLATIN5", "ISO8859_9"); + fIANA2JavaMap.put("L5", "ISO8859_9"); + + fIANA2JavaMap.put("ISO-8859-13", "ISO8859_13"); + + fIANA2JavaMap.put("ISO-8859-15", "ISO8859_15_FDIS"); + fIANA2JavaMap.put("ISO_8859-15", "ISO8859_15_FDIS"); + fIANA2JavaMap.put("LATIN-9", "ISO8859_15_FDIS"); + + fIANA2JavaMap.put("KOI8-R", "KOI8_R"); + fIANA2JavaMap.put("CSKOI8R", "KOI8_R"); + fIANA2JavaMap.put("US-ASCII", "ASCII"); + fIANA2JavaMap.put("ISO-IR-6", "ASCII"); + fIANA2JavaMap.put("ANSI_X3.4-1968", "ASCII"); + fIANA2JavaMap.put("ANSI_X3.4-1986", "ASCII"); + fIANA2JavaMap.put("ISO_646.IRV:1991", "ASCII"); + fIANA2JavaMap.put("ASCII", "ASCII"); + fIANA2JavaMap.put("CSASCII", "ASCII"); + fIANA2JavaMap.put("ISO646-US", "ASCII"); + fIANA2JavaMap.put("US", "ASCII"); + fIANA2JavaMap.put("IBM367", "ASCII"); + fIANA2JavaMap.put("CP367", "ASCII"); + fIANA2JavaMap.put("UTF-8", "UTF8"); + fIANA2JavaMap.put("UTF-16", "UTF-16"); + fIANA2JavaMap.put("UTF-16BE", "UnicodeBig"); + fIANA2JavaMap.put("UTF-16LE", "UnicodeLittle"); + + // support for 1047, as proposed to be added to the + // IANA registry in + // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0049.html + fIANA2JavaMap.put("IBM-1047", "Cp1047"); + fIANA2JavaMap.put("IBM1047", "Cp1047"); + fIANA2JavaMap.put("CP1047", "Cp1047"); + + // Adding new aliases as proposed in + // http://lists.w3.org/Archives/Public/ietf-charset/2002JulSep/0058.html + fIANA2JavaMap.put("IBM-37", "CP037"); + fIANA2JavaMap.put("IBM-273", "CP273"); + fIANA2JavaMap.put("IBM-277", "CP277"); + fIANA2JavaMap.put("IBM-278", "CP278"); + fIANA2JavaMap.put("IBM-280", "CP280"); + fIANA2JavaMap.put("IBM-284", "CP284"); + fIANA2JavaMap.put("IBM-285", "CP285"); + fIANA2JavaMap.put("IBM-290", "CP290"); + fIANA2JavaMap.put("IBM-297", "CP297"); + fIANA2JavaMap.put("IBM-420", "CP420"); + fIANA2JavaMap.put("IBM-424", "CP424"); + fIANA2JavaMap.put("IBM-437", "CP437"); + fIANA2JavaMap.put("IBM-500", "CP500"); + fIANA2JavaMap.put("IBM-775", "CP775"); + fIANA2JavaMap.put("IBM-850", "CP850"); + fIANA2JavaMap.put("IBM-852", "CP852"); + fIANA2JavaMap.put("IBM-855", "CP855"); + fIANA2JavaMap.put("IBM-857", "CP857"); + fIANA2JavaMap.put("IBM-858", "CP858"); + fIANA2JavaMap.put("IBM-860", "CP860"); + fIANA2JavaMap.put("IBM-861", "CP861"); + fIANA2JavaMap.put("IBM-862", "CP862"); + fIANA2JavaMap.put("IBM-863", "CP863"); + fIANA2JavaMap.put("IBM-864", "CP864"); + fIANA2JavaMap.put("IBM-865", "CP865"); + fIANA2JavaMap.put("IBM-866", "CP866"); + fIANA2JavaMap.put("IBM-868", "CP868"); + fIANA2JavaMap.put("IBM-869", "CP869"); + fIANA2JavaMap.put("IBM-870", "CP870"); + fIANA2JavaMap.put("IBM-871", "CP871"); + fIANA2JavaMap.put("IBM-918", "CP918"); + fIANA2JavaMap.put("IBM-924", "CP924"); + fIANA2JavaMap.put("IBM-1026", "CP1026"); + fIANA2JavaMap.put("IBM-1140", "Cp1140"); + fIANA2JavaMap.put("IBM-1141", "Cp1141"); + fIANA2JavaMap.put("IBM-1142", "Cp1142"); + fIANA2JavaMap.put("IBM-1143", "Cp1143"); + fIANA2JavaMap.put("IBM-1144", "Cp1144"); + fIANA2JavaMap.put("IBM-1145", "Cp1145"); + fIANA2JavaMap.put("IBM-1146", "Cp1146"); + fIANA2JavaMap.put("IBM-1147", "Cp1147"); + fIANA2JavaMap.put("IBM-1148", "Cp1148"); + fIANA2JavaMap.put("IBM-1149", "Cp1149"); + fIANA2JavaMap.put("IBM-819", "ISO8859_1"); + fIANA2JavaMap.put("IBM-367", "ASCII"); + + // REVISIT: + // j:CNS11643 -> EUC-TW? + // ISO-2022-CN? ISO-2022-CN-EXT? + + // add Java to IANA encoding mappings + //fJava2IANAMap.put("8859_1", "US-ASCII"); // ? + fJava2IANAMap.put("ISO8859_1", "ISO-8859-1"); + fJava2IANAMap.put("ISO8859_2", "ISO-8859-2"); + fJava2IANAMap.put("ISO8859_3", "ISO-8859-3"); + fJava2IANAMap.put("ISO8859_4", "ISO-8859-4"); + fJava2IANAMap.put("ISO8859_5", "ISO-8859-5"); + fJava2IANAMap.put("ISO8859_6", "ISO-8859-6"); + fJava2IANAMap.put("ISO8859_7", "ISO-8859-7"); + fJava2IANAMap.put("ISO8859_8", "ISO-8859-8"); + fJava2IANAMap.put("ISO8859_9", "ISO-8859-9"); + fJava2IANAMap.put("ISO8859_13", "ISO-8859-13"); + fJava2IANAMap.put("ISO8859_15", "ISO-8859-15"); + fJava2IANAMap.put("ISO8859_15_FDIS", "ISO-8859-15"); + fJava2IANAMap.put("Big5", "BIG5"); + fJava2IANAMap.put("CP037", "EBCDIC-CP-US"); + fJava2IANAMap.put("CP273", "IBM273"); + fJava2IANAMap.put("CP277", "EBCDIC-CP-DK"); + fJava2IANAMap.put("CP278", "EBCDIC-CP-FI"); + fJava2IANAMap.put("CP280", "EBCDIC-CP-IT"); + fJava2IANAMap.put("CP284", "EBCDIC-CP-ES"); + fJava2IANAMap.put("CP285", "EBCDIC-CP-GB"); + fJava2IANAMap.put("CP290", "EBCDIC-JP-KANA"); + fJava2IANAMap.put("CP297", "EBCDIC-CP-FR"); + fJava2IANAMap.put("CP420", "EBCDIC-CP-AR1"); + fJava2IANAMap.put("CP424", "EBCDIC-CP-HE"); + fJava2IANAMap.put("CP437", "IBM437"); + fJava2IANAMap.put("CP500", "EBCDIC-CP-CH"); + fJava2IANAMap.put("CP775", "IBM775"); + fJava2IANAMap.put("CP850", "IBM850"); + fJava2IANAMap.put("CP852", "IBM852"); + fJava2IANAMap.put("CP855", "IBM855"); + fJava2IANAMap.put("CP857", "IBM857"); + fJava2IANAMap.put("CP858", "IBM00858"); + fJava2IANAMap.put("CP860", "IBM860"); + fJava2IANAMap.put("CP861", "IBM861"); + fJava2IANAMap.put("CP862", "IBM862"); + fJava2IANAMap.put("CP863", "IBM863"); + fJava2IANAMap.put("CP864", "IBM864"); + fJava2IANAMap.put("CP865", "IBM865"); + fJava2IANAMap.put("CP866", "IBM866"); + fJava2IANAMap.put("CP868", "IBM868"); + fJava2IANAMap.put("CP869", "IBM869"); + fJava2IANAMap.put("CP870", "EBCDIC-CP-ROECE"); + fJava2IANAMap.put("CP871", "EBCDIC-CP-IS"); + fJava2IANAMap.put("CP918", "EBCDIC-CP-AR2"); + fJava2IANAMap.put("CP924", "IBM00924"); + fJava2IANAMap.put("CP1026", "IBM1026"); + fJava2IANAMap.put("Cp01140", "IBM01140"); + fJava2IANAMap.put("Cp01141", "IBM01141"); + fJava2IANAMap.put("Cp01142", "IBM01142"); + fJava2IANAMap.put("Cp01143", "IBM01143"); + fJava2IANAMap.put("Cp01144", "IBM01144"); + fJava2IANAMap.put("Cp01145", "IBM01145"); + fJava2IANAMap.put("Cp01146", "IBM01146"); + fJava2IANAMap.put("Cp01147", "IBM01147"); + fJava2IANAMap.put("Cp01148", "IBM01148"); + fJava2IANAMap.put("Cp01149", "IBM01149"); + fJava2IANAMap.put("EUCJIS", "EUC-JP"); + fJava2IANAMap.put("KS_C_5601-1987", "KS_C_5601-1987"); + fJava2IANAMap.put("GB2312", "GB2312"); + fJava2IANAMap.put("ISO2022KR", "ISO-2022-KR"); + fJava2IANAMap.put("ISO2022CN", "ISO-2022-CN"); + fJava2IANAMap.put("JIS", "ISO-2022-JP"); + fJava2IANAMap.put("KOI8_R", "KOI8-R"); + fJava2IANAMap.put("KSC5601", "EUC-KR"); + fJava2IANAMap.put("GB18030", "GB18030"); + fJava2IANAMap.put("GBK", "GBK"); + fJava2IANAMap.put("SJIS", "SHIFT_JIS"); + fJava2IANAMap.put("MS932", "WINDOWS-31J"); + fJava2IANAMap.put("UTF8", "UTF-8"); + fJava2IANAMap.put("Unicode", "UTF-16"); + fJava2IANAMap.put("UnicodeBig", "UTF-16BE"); + fJava2IANAMap.put("UnicodeLittle", "UTF-16LE"); + fJava2IANAMap.put("JIS0201", "X0201"); + fJava2IANAMap.put("JIS0208", "X0208"); + fJava2IANAMap.put("JIS0212", "ISO-IR-159"); + + // proposed addition (see above for details): + fJava2IANAMap.put("CP1047", "IBM1047"); + + } // () + + // + // Constructors + // + + /** Default constructor. */ + public EncodingMap() {} + + // + // Public static methods + // + + /** + * Adds an IANA to Java encoding name mapping. + * + * @param ianaEncoding The IANA encoding name. + * @param javaEncoding The Java encoding name. + */ + public static void putIANA2JavaMapping(String ianaEncoding, + String javaEncoding) { + fIANA2JavaMap.put(ianaEncoding, javaEncoding); + } // putIANA2JavaMapping(String,String) + + /** + * Returns the Java encoding name for the specified IANA encoding name. + * + * @param ianaEncoding The IANA encoding name. + */ + public static String getIANA2JavaMapping(String ianaEncoding) { + return (String)fIANA2JavaMap.get(ianaEncoding); + } // getIANA2JavaMapping(String):String + + /** + * Removes an IANA to Java encoding name mapping. + * + * @param ianaEncoding The IANA encoding name. + */ + public static String removeIANA2JavaMapping(String ianaEncoding) { + return (String)fIANA2JavaMap.remove(ianaEncoding); + } // removeIANA2JavaMapping(String):String + + /** + * Adds a Java to IANA encoding name mapping. + * + * @param javaEncoding The Java encoding name. + * @param ianaEncoding The IANA encoding name. + */ + public static void putJava2IANAMapping(String javaEncoding, + String ianaEncoding) { + fJava2IANAMap.put(javaEncoding, ianaEncoding); + } // putJava2IANAMapping(String,String) + + /** + * Returns the IANA encoding name for the specified Java encoding name. + * + * @param javaEncoding The Java encoding name. + */ + public static String getJava2IANAMapping(String javaEncoding) { + return (String)fJava2IANAMap.get(javaEncoding); + } // getJava2IANAMapping(String):String + + /** + * Removes a Java to IANA encoding name mapping. + * + * @param javaEncoding The Java encoding name. + */ + public static String removeJava2IANAMapping(String javaEncoding) { + return (String)fJava2IANAMap.remove(javaEncoding); + } // removeJava2IANAMapping + +} // class EncodingMap diff --git a/java/org/apache/jasper/xmlparser/ParserUtils.java b/java/org/apache/jasper/xmlparser/ParserUtils.java index e8995fe15..e897b2761 100644 --- a/java/org/apache/jasper/xmlparser/ParserUtils.java +++ b/java/org/apache/jasper/xmlparser/ParserUtils.java @@ -1,238 +1,238 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.xmlparser; - -import java.io.IOException; -import java.io.InputStream; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.jasper.Constants; -import org.apache.jasper.JasperException; -import org.apache.jasper.compiler.Localizer; -import org.w3c.dom.Comment; -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.w3c.dom.Text; -import org.xml.sax.EntityResolver; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; - - -/** - * XML parsing utilities for processing web application deployment - * descriptor and tag library descriptor files. FIXME - make these - * use a separate class loader for the parser to be used. - * - * @author Craig R. McClanahan - * @version $Revision: 306152 $ $Date: 2005-03-23 22:08:01 -0600 (Wed, 23 Mar 2005) $ - */ - -public class ParserUtils { - - /** - * An error handler for use when parsing XML documents. - */ - static ErrorHandler errorHandler = new MyErrorHandler(); - - /** - * An entity resolver for use when parsing XML documents. - */ - static EntityResolver entityResolver = new MyEntityResolver(); - - // Turn off for JSP 2.0 until switch over to using xschema. - public static boolean validating = false; - - - // --------------------------------------------------------- Public Methods - - /** - * Parse the specified XML document, and return a TreeNode - * that corresponds to the root node of the document tree. - * - * @param uri URI of the XML document being parsed - * @param is Input source containing the deployment descriptor - * - * @exception JasperException if an input/output error occurs - * @exception JasperException if a parsing error occurs - */ - public TreeNode parseXMLDocument(String uri, InputSource is) - throws JasperException { - - Document document = null; - - // Perform an XML parse of this document, via JAXP - try { - DocumentBuilderFactory factory = - DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); - factory.setValidating(validating); - DocumentBuilder builder = factory.newDocumentBuilder(); - builder.setEntityResolver(entityResolver); - builder.setErrorHandler(errorHandler); - document = builder.parse(is); - } catch (ParserConfigurationException ex) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml", uri), ex); - } catch (SAXParseException ex) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml.line", - uri, - Integer.toString(ex.getLineNumber()), - Integer.toString(ex.getColumnNumber())), - ex); - } catch (SAXException sx) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml", uri), sx); - } catch (IOException io) { - throw new JasperException - (Localizer.getMessage("jsp.error.parse.xml", uri), io); - } - - // Convert the resulting document to a graph of TreeNodes - return (convert(null, document.getDocumentElement())); - } - - - /** - * Parse the specified XML document, and return a TreeNode - * that corresponds to the root node of the document tree. - * - * @param uri URI of the XML document being parsed - * @param is Input stream containing the deployment descriptor - * - * @exception JasperException if an input/output error occurs - * @exception JasperException if a parsing error occurs - */ - public TreeNode parseXMLDocument(String uri, InputStream is) - throws JasperException { - - return (parseXMLDocument(uri, new InputSource(is))); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Create and return a TreeNode that corresponds to the specified Node, - * including processing all of the attributes and children nodes. - * - * @param parent The parent TreeNode (if any) for the new TreeNode - * @param node The XML document Node to be converted - */ - protected TreeNode convert(TreeNode parent, Node node) { - - // Construct a new TreeNode for this node - TreeNode treeNode = new TreeNode(node.getNodeName(), parent); - - // Convert all attributes of this node - NamedNodeMap attributes = node.getAttributes(); - if (attributes != null) { - int n = attributes.getLength(); - for (int i = 0; i < n; i++) { - Node attribute = attributes.item(i); - treeNode.addAttribute(attribute.getNodeName(), - attribute.getNodeValue()); - } - } - - // Create and attach all children of this node - NodeList children = node.getChildNodes(); - if (children != null) { - int n = children.getLength(); - for (int i = 0; i < n; i++) { - Node child = children.item(i); - if (child instanceof Comment) - continue; - if (child instanceof Text) { - String body = ((Text) child).getData(); - if (body != null) { - body = body.trim(); - if (body.length() > 0) - treeNode.setBody(body); - } - } else { - TreeNode treeChild = convert(treeNode, child); - } - } - } - - // Return the completed TreeNode graph - return (treeNode); - } -} - - -// ------------------------------------------------------------ Private Classes - -class MyEntityResolver implements EntityResolver { - - // Logger - private Log log = LogFactory.getLog(MyEntityResolver.class); - - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException { - for (int i = 0; i < Constants.CACHED_DTD_PUBLIC_IDS.length; i++) { - String cachedDtdPublicId = Constants.CACHED_DTD_PUBLIC_IDS[i]; - if (cachedDtdPublicId.equals(publicId)) { - String resourcePath = Constants.CACHED_DTD_RESOURCE_PATHS[i]; - InputStream input = this.getClass().getResourceAsStream( - resourcePath); - if (input == null) { - throw new SAXException(Localizer.getMessage( - "jsp.error.internal.filenotfound", resourcePath)); - } - InputSource isrc = new InputSource(input); - return isrc; - } - } - if (log.isDebugEnabled()) - log.debug("Resolve entity failed" + publicId + " " + systemId); - log.error(Localizer.getMessage("jsp.error.parse.xml.invalidPublicId", - publicId)); - return null; - } -} - -class MyErrorHandler implements ErrorHandler { - - // Logger - private Log log = LogFactory.getLog(MyErrorHandler.class); - - public void warning(SAXParseException ex) throws SAXException { - if (log.isDebugEnabled()) - log.debug("ParserUtils: warning ", ex); - // We ignore warnings - } - - public void error(SAXParseException ex) throws SAXException { - throw ex; - } - - public void fatalError(SAXParseException ex) throws SAXException { - throw ex; - } +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.xmlparser; + +import java.io.IOException; +import java.io.InputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.jasper.Constants; +import org.apache.jasper.JasperException; +import org.apache.jasper.compiler.Localizer; +import org.w3c.dom.Comment; +import org.w3c.dom.Document; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.w3c.dom.Text; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; + + +/** + * XML parsing utilities for processing web application deployment + * descriptor and tag library descriptor files. FIXME - make these + * use a separate class loader for the parser to be used. + * + * @author Craig R. McClanahan + * @version $Revision: 306152 $ $Date: 2005-03-23 22:08:01 -0600 (Wed, 23 Mar 2005) $ + */ + +public class ParserUtils { + + /** + * An error handler for use when parsing XML documents. + */ + static ErrorHandler errorHandler = new MyErrorHandler(); + + /** + * An entity resolver for use when parsing XML documents. + */ + static EntityResolver entityResolver = new MyEntityResolver(); + + // Turn off for JSP 2.0 until switch over to using xschema. + public static boolean validating = false; + + + // --------------------------------------------------------- Public Methods + + /** + * Parse the specified XML document, and return a TreeNode + * that corresponds to the root node of the document tree. + * + * @param uri URI of the XML document being parsed + * @param is Input source containing the deployment descriptor + * + * @exception JasperException if an input/output error occurs + * @exception JasperException if a parsing error occurs + */ + public TreeNode parseXMLDocument(String uri, InputSource is) + throws JasperException { + + Document document = null; + + // Perform an XML parse of this document, via JAXP + try { + DocumentBuilderFactory factory = + DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setValidating(validating); + DocumentBuilder builder = factory.newDocumentBuilder(); + builder.setEntityResolver(entityResolver); + builder.setErrorHandler(errorHandler); + document = builder.parse(is); + } catch (ParserConfigurationException ex) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml", uri), ex); + } catch (SAXParseException ex) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml.line", + uri, + Integer.toString(ex.getLineNumber()), + Integer.toString(ex.getColumnNumber())), + ex); + } catch (SAXException sx) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml", uri), sx); + } catch (IOException io) { + throw new JasperException + (Localizer.getMessage("jsp.error.parse.xml", uri), io); + } + + // Convert the resulting document to a graph of TreeNodes + return (convert(null, document.getDocumentElement())); + } + + + /** + * Parse the specified XML document, and return a TreeNode + * that corresponds to the root node of the document tree. + * + * @param uri URI of the XML document being parsed + * @param is Input stream containing the deployment descriptor + * + * @exception JasperException if an input/output error occurs + * @exception JasperException if a parsing error occurs + */ + public TreeNode parseXMLDocument(String uri, InputStream is) + throws JasperException { + + return (parseXMLDocument(uri, new InputSource(is))); + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Create and return a TreeNode that corresponds to the specified Node, + * including processing all of the attributes and children nodes. + * + * @param parent The parent TreeNode (if any) for the new TreeNode + * @param node The XML document Node to be converted + */ + protected TreeNode convert(TreeNode parent, Node node) { + + // Construct a new TreeNode for this node + TreeNode treeNode = new TreeNode(node.getNodeName(), parent); + + // Convert all attributes of this node + NamedNodeMap attributes = node.getAttributes(); + if (attributes != null) { + int n = attributes.getLength(); + for (int i = 0; i < n; i++) { + Node attribute = attributes.item(i); + treeNode.addAttribute(attribute.getNodeName(), + attribute.getNodeValue()); + } + } + + // Create and attach all children of this node + NodeList children = node.getChildNodes(); + if (children != null) { + int n = children.getLength(); + for (int i = 0; i < n; i++) { + Node child = children.item(i); + if (child instanceof Comment) + continue; + if (child instanceof Text) { + String body = ((Text) child).getData(); + if (body != null) { + body = body.trim(); + if (body.length() > 0) + treeNode.setBody(body); + } + } else { + TreeNode treeChild = convert(treeNode, child); + } + } + } + + // Return the completed TreeNode graph + return (treeNode); + } +} + + +// ------------------------------------------------------------ Private Classes + +class MyEntityResolver implements EntityResolver { + + // Logger + private Log log = LogFactory.getLog(MyEntityResolver.class); + + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException { + for (int i = 0; i < Constants.CACHED_DTD_PUBLIC_IDS.length; i++) { + String cachedDtdPublicId = Constants.CACHED_DTD_PUBLIC_IDS[i]; + if (cachedDtdPublicId.equals(publicId)) { + String resourcePath = Constants.CACHED_DTD_RESOURCE_PATHS[i]; + InputStream input = this.getClass().getResourceAsStream( + resourcePath); + if (input == null) { + throw new SAXException(Localizer.getMessage( + "jsp.error.internal.filenotfound", resourcePath)); + } + InputSource isrc = new InputSource(input); + return isrc; + } + } + if (log.isDebugEnabled()) + log.debug("Resolve entity failed" + publicId + " " + systemId); + log.error(Localizer.getMessage("jsp.error.parse.xml.invalidPublicId", + publicId)); + return null; + } +} + +class MyErrorHandler implements ErrorHandler { + + // Logger + private Log log = LogFactory.getLog(MyErrorHandler.class); + + public void warning(SAXParseException ex) throws SAXException { + if (log.isDebugEnabled()) + log.debug("ParserUtils: warning ", ex); + // We ignore warnings + } + + public void error(SAXParseException ex) throws SAXException { + throw ex; + } + + public void fatalError(SAXParseException ex) throws SAXException { + throw ex; + } } \ No newline at end of file diff --git a/java/org/apache/jasper/xmlparser/SymbolTable.java b/java/org/apache/jasper/xmlparser/SymbolTable.java index 3f60788b8..8537a9471 100644 --- a/java/org/apache/jasper/xmlparser/SymbolTable.java +++ b/java/org/apache/jasper/xmlparser/SymbolTable.java @@ -1,301 +1,301 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -/** - * This class is a symbol table implementation that guarantees that - * strings used as identifiers are unique references. Multiple calls - * to addSymbol will always return the same string - * reference. - *

        - * The symbol table performs the same task as String.intern() - * with the following differences: - *

          - *
        • - * A new string object does not need to be created in order to - * retrieve a unique reference. Symbols can be added by using - * a series of characters in a character array. - *
        • - *
        • - * Users of the symbol table can provide their own symbol hashing - * implementation. For example, a simple string hashing algorithm - * may fail to produce a balanced set of hashcodes for symbols - * that are mostly unique. Strings with similar leading - * characters are especially prone to this poor hashing behavior. - *
        • - *
        - * - * @author Andy Clark - * @version $Id: SymbolTable.java 306179 2005-07-27 15:12:04Z yoavs $ - */ -public class SymbolTable { - - // - // Constants - // - - /** Default table size. */ - protected static final int TABLE_SIZE = 101; - - // - // Data - // - - /** Buckets. */ - protected Entry[] fBuckets = null; - - // actual table size - protected int fTableSize; - - // - // Constructors - // - - /** Constructs a symbol table with a default number of buckets. */ - public SymbolTable() { - this(TABLE_SIZE); - } - - /** Constructs a symbol table with a specified number of buckets. */ - public SymbolTable(int tableSize) { - fTableSize = tableSize; - fBuckets = new Entry[fTableSize]; - } - - // - // Public methods - // - - /** - * Adds the specified symbol to the symbol table and returns a - * reference to the unique symbol. If the symbol already exists, - * the previous symbol reference is returned instead, in order - * guarantee that symbol references remain unique. - * - * @param symbol The new symbol. - */ - public String addSymbol(String symbol) { - - // search for identical symbol - int bucket = hash(symbol) % fTableSize; - int length = symbol.length(); - OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { - if (length == entry.characters.length) { - for (int i = 0; i < length; i++) { - if (symbol.charAt(i) != entry.characters[i]) { - continue OUTER; - } - } - return entry.symbol; - } - } - - // create new entry - Entry entry = new Entry(symbol, fBuckets[bucket]); - fBuckets[bucket] = entry; - return entry.symbol; - - } // addSymbol(String):String - - /** - * Adds the specified symbol to the symbol table and returns a - * reference to the unique symbol. If the symbol already exists, - * the previous symbol reference is returned instead, in order - * guarantee that symbol references remain unique. - * - * @param buffer The buffer containing the new symbol. - * @param offset The offset into the buffer of the new symbol. - * @param length The length of the new symbol in the buffer. - */ - public String addSymbol(char[] buffer, int offset, int length) { - - // search for identical symbol - int bucket = hash(buffer, offset, length) % fTableSize; - OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { - if (length == entry.characters.length) { - for (int i = 0; i < length; i++) { - if (buffer[offset + i] != entry.characters[i]) { - continue OUTER; - } - } - return entry.symbol; - } - } - - // add new entry - Entry entry = new Entry(buffer, offset, length, fBuckets[bucket]); - fBuckets[bucket] = entry; - return entry.symbol; - - } // addSymbol(char[],int,int):String - - /** - * Returns a hashcode value for the specified symbol. The value - * returned by this method must be identical to the value returned - * by the hash(char[],int,int) method when called - * with the character array that comprises the symbol string. - * - * @param symbol The symbol to hash. - */ - public int hash(String symbol) { - - int code = 0; - int length = symbol.length(); - for (int i = 0; i < length; i++) { - code = code * 37 + symbol.charAt(i); - } - return code & 0x7FFFFFF; - - } // hash(String):int - - /** - * Returns a hashcode value for the specified symbol information. - * The value returned by this method must be identical to the value - * returned by the hash(String) method when called - * with the string object created from the symbol information. - * - * @param buffer The character buffer containing the symbol. - * @param offset The offset into the character buffer of the start - * of the symbol. - * @param length The length of the symbol. - */ - public int hash(char[] buffer, int offset, int length) { - - int code = 0; - for (int i = 0; i < length; i++) { - code = code * 37 + buffer[offset + i]; - } - return code & 0x7FFFFFF; - - } // hash(char[],int,int):int - - /** - * Returns true if the symbol table already contains the specified - * symbol. - * - * @param symbol The symbol to look for. - */ - public boolean containsSymbol(String symbol) { - - // search for identical symbol - int bucket = hash(symbol) % fTableSize; - int length = symbol.length(); - OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { - if (length == entry.characters.length) { - for (int i = 0; i < length; i++) { - if (symbol.charAt(i) != entry.characters[i]) { - continue OUTER; - } - } - return true; - } - } - - return false; - - } // containsSymbol(String):boolean - - /** - * Returns true if the symbol table already contains the specified - * symbol. - * - * @param buffer The buffer containing the symbol to look for. - * @param offset The offset into the buffer. - * @param length The length of the symbol in the buffer. - */ - public boolean containsSymbol(char[] buffer, int offset, int length) { - - // search for identical symbol - int bucket = hash(buffer, offset, length) % fTableSize; - OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { - if (length == entry.characters.length) { - for (int i = 0; i < length; i++) { - if (buffer[offset + i] != entry.characters[i]) { - continue OUTER; - } - } - return true; - } - } - - return false; - - } // containsSymbol(char[],int,int):boolean - - // - // Classes - // - - /** - * This class is a symbol table entry. Each entry acts as a node - * in a linked list. - */ - protected static final class Entry { - - // - // Data - // - - /** Symbol. */ - public String symbol; - - /** - * Symbol characters. This information is duplicated here for - * comparison performance. - */ - public char[] characters; - - /** The next entry. */ - public Entry next; - - // - // Constructors - // - - /** - * Constructs a new entry from the specified symbol and next entry - * reference. - */ - public Entry(String symbol, Entry next) { - this.symbol = symbol.intern(); - characters = new char[symbol.length()]; - symbol.getChars(0, characters.length, characters, 0); - this.next = next; - } - - /** - * Constructs a new entry from the specified symbol information and - * next entry reference. - */ - public Entry(char[] ch, int offset, int length, Entry next) { - characters = new char[length]; - System.arraycopy(ch, offset, characters, 0, length); - symbol = new String(characters).intern(); - this.next = next; - } - - } // class Entry - -} // class SymbolTable +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +/** + * This class is a symbol table implementation that guarantees that + * strings used as identifiers are unique references. Multiple calls + * to addSymbol will always return the same string + * reference. + *

        + * The symbol table performs the same task as String.intern() + * with the following differences: + *

          + *
        • + * A new string object does not need to be created in order to + * retrieve a unique reference. Symbols can be added by using + * a series of characters in a character array. + *
        • + *
        • + * Users of the symbol table can provide their own symbol hashing + * implementation. For example, a simple string hashing algorithm + * may fail to produce a balanced set of hashcodes for symbols + * that are mostly unique. Strings with similar leading + * characters are especially prone to this poor hashing behavior. + *
        • + *
        + * + * @author Andy Clark + * @version $Id: SymbolTable.java 306179 2005-07-27 15:12:04Z yoavs $ + */ +public class SymbolTable { + + // + // Constants + // + + /** Default table size. */ + protected static final int TABLE_SIZE = 101; + + // + // Data + // + + /** Buckets. */ + protected Entry[] fBuckets = null; + + // actual table size + protected int fTableSize; + + // + // Constructors + // + + /** Constructs a symbol table with a default number of buckets. */ + public SymbolTable() { + this(TABLE_SIZE); + } + + /** Constructs a symbol table with a specified number of buckets. */ + public SymbolTable(int tableSize) { + fTableSize = tableSize; + fBuckets = new Entry[fTableSize]; + } + + // + // Public methods + // + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param symbol The new symbol. + */ + public String addSymbol(String symbol) { + + // search for identical symbol + int bucket = hash(symbol) % fTableSize; + int length = symbol.length(); + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (symbol.charAt(i) != entry.characters[i]) { + continue OUTER; + } + } + return entry.symbol; + } + } + + // create new entry + Entry entry = new Entry(symbol, fBuckets[bucket]); + fBuckets[bucket] = entry; + return entry.symbol; + + } // addSymbol(String):String + + /** + * Adds the specified symbol to the symbol table and returns a + * reference to the unique symbol. If the symbol already exists, + * the previous symbol reference is returned instead, in order + * guarantee that symbol references remain unique. + * + * @param buffer The buffer containing the new symbol. + * @param offset The offset into the buffer of the new symbol. + * @param length The length of the new symbol in the buffer. + */ + public String addSymbol(char[] buffer, int offset, int length) { + + // search for identical symbol + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != entry.characters[i]) { + continue OUTER; + } + } + return entry.symbol; + } + } + + // add new entry + Entry entry = new Entry(buffer, offset, length, fBuckets[bucket]); + fBuckets[bucket] = entry; + return entry.symbol; + + } // addSymbol(char[],int,int):String + + /** + * Returns a hashcode value for the specified symbol. The value + * returned by this method must be identical to the value returned + * by the hash(char[],int,int) method when called + * with the character array that comprises the symbol string. + * + * @param symbol The symbol to hash. + */ + public int hash(String symbol) { + + int code = 0; + int length = symbol.length(); + for (int i = 0; i < length; i++) { + code = code * 37 + symbol.charAt(i); + } + return code & 0x7FFFFFF; + + } // hash(String):int + + /** + * Returns a hashcode value for the specified symbol information. + * The value returned by this method must be identical to the value + * returned by the hash(String) method when called + * with the string object created from the symbol information. + * + * @param buffer The character buffer containing the symbol. + * @param offset The offset into the character buffer of the start + * of the symbol. + * @param length The length of the symbol. + */ + public int hash(char[] buffer, int offset, int length) { + + int code = 0; + for (int i = 0; i < length; i++) { + code = code * 37 + buffer[offset + i]; + } + return code & 0x7FFFFFF; + + } // hash(char[],int,int):int + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param symbol The symbol to look for. + */ + public boolean containsSymbol(String symbol) { + + // search for identical symbol + int bucket = hash(symbol) % fTableSize; + int length = symbol.length(); + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (symbol.charAt(i) != entry.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(String):boolean + + /** + * Returns true if the symbol table already contains the specified + * symbol. + * + * @param buffer The buffer containing the symbol to look for. + * @param offset The offset into the buffer. + * @param length The length of the symbol in the buffer. + */ + public boolean containsSymbol(char[] buffer, int offset, int length) { + + // search for identical symbol + int bucket = hash(buffer, offset, length) % fTableSize; + OUTER: for (Entry entry = fBuckets[bucket]; entry != null; entry = entry.next) { + if (length == entry.characters.length) { + for (int i = 0; i < length; i++) { + if (buffer[offset + i] != entry.characters[i]) { + continue OUTER; + } + } + return true; + } + } + + return false; + + } // containsSymbol(char[],int,int):boolean + + // + // Classes + // + + /** + * This class is a symbol table entry. Each entry acts as a node + * in a linked list. + */ + protected static final class Entry { + + // + // Data + // + + /** Symbol. */ + public String symbol; + + /** + * Symbol characters. This information is duplicated here for + * comparison performance. + */ + public char[] characters; + + /** The next entry. */ + public Entry next; + + // + // Constructors + // + + /** + * Constructs a new entry from the specified symbol and next entry + * reference. + */ + public Entry(String symbol, Entry next) { + this.symbol = symbol.intern(); + characters = new char[symbol.length()]; + symbol.getChars(0, characters.length, characters, 0); + this.next = next; + } + + /** + * Constructs a new entry from the specified symbol information and + * next entry reference. + */ + public Entry(char[] ch, int offset, int length, Entry next) { + characters = new char[length]; + System.arraycopy(ch, offset, characters, 0, length); + symbol = new String(characters).intern(); + this.next = next; + } + + } // class Entry + +} // class SymbolTable diff --git a/java/org/apache/jasper/xmlparser/TreeNode.java b/java/org/apache/jasper/xmlparser/TreeNode.java index 9da246bb9..d63d61725 100644 --- a/java/org/apache/jasper/xmlparser/TreeNode.java +++ b/java/org/apache/jasper/xmlparser/TreeNode.java @@ -1,359 +1,359 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.xmlparser; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; - - -/** - * Simplified implementation of a Node from a Document Object Model (DOM) - * parse of an XML document. This class is used to represent a DOM tree - * so that the XML parser's implementation of org.w3c.dom need - * not be visible to the remainder of Jasper. - *

        - * WARNING - Construction of a new tree, or modifications - * to an existing one, are not thread-safe and such accesses must be - * synchronized. - * - * @author Craig R. McClanahan - * @version $Revision: 305933 $ $Date: 2004-03-17 13:23:05 -0600 (Wed, 17 Mar 2004) $ - */ - -public class TreeNode { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new node with no parent. - * - * @param name The name of this node - */ - public TreeNode(String name) { - - this(name, null); - - } - - - /** - * Construct a new node with the specified parent. - * - * @param name The name of this node - * @param parent The node that is the parent of this node - */ - public TreeNode(String name, TreeNode parent) { - - super(); - this.name = name; - this.parent = parent; - if (this.parent != null) - this.parent.addChild(this); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The attributes of this node, keyed by attribute name, - * Instantiated only if required. - */ - protected HashMap attributes = null; - - - /** - * The body text associated with this node (if any). - */ - protected String body = null; - - - /** - * The children of this node, instantiated only if required. - */ - protected ArrayList children = null; - - - /** - * The name of this node. - */ - protected String name = null; - - - /** - * The parent node of this node. - */ - protected TreeNode parent = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Add an attribute to this node, replacing any existing attribute - * with the same name. - * - * @param name The attribute name to add - * @param value The new attribute value - */ - public void addAttribute(String name, String value) { - - if (attributes == null) - attributes = new HashMap(); - attributes.put(name, value); - - } - - - /** - * Add a new child node to this node. - * - * @param node The new child node - */ - public void addChild(TreeNode node) { - - if (children == null) - children = new ArrayList(); - children.add(node); - - } - - - /** - * Return the value of the specified node attribute if it exists, or - * null otherwise. - * - * @param name Name of the requested attribute - */ - public String findAttribute(String name) { - - if (attributes == null) - return (null); - else - return ((String) attributes.get(name)); - - } - - - /** - * Return an Iterator of the attribute names of this node. If there are - * no attributes, an empty Iterator is returned. - */ - public Iterator findAttributes() { - - if (attributes == null) - return (Collections.EMPTY_LIST.iterator()); - else - return (attributes.keySet().iterator()); - - } - - - /** - * Return the first child node of this node with the specified name, - * if there is one; otherwise, return null. - * - * @param name Name of the desired child element - */ - public TreeNode findChild(String name) { - - if (children == null) - return (null); - Iterator items = children.iterator(); - while (items.hasNext()) { - TreeNode item = (TreeNode) items.next(); - if (name.equals(item.getName())) - return (item); - } - return (null); - - } - - - /** - * Return an Iterator of all children of this node. If there are no - * children, an empty Iterator is returned. - */ - public Iterator findChildren() { - - if (children == null) - return (Collections.EMPTY_LIST.iterator()); - else - return (children.iterator()); - - } - - - /** - * Return an Iterator over all children of this node that have the - * specified name. If there are no such children, an empty Iterator - * is returned. - * - * @param name Name used to select children - */ - public Iterator findChildren(String name) { - - if (children == null) - return (Collections.EMPTY_LIST.iterator()); - - ArrayList results = new ArrayList(); - Iterator items = children.iterator(); - while (items.hasNext()) { - TreeNode item = (TreeNode) items.next(); - if (name.equals(item.getName())) - results.add(item); - } - return (results.iterator()); - - } - - - /** - * Return the body text associated with this node (if any). - */ - public String getBody() { - - return (this.body); - - } - - - /** - * Return the name of this node. - */ - public String getName() { - - return (this.name); - - } - - - /** - * Remove any existing value for the specified attribute name. - * - * @param name The attribute name to remove - */ - public void removeAttribute(String name) { - - if (attributes != null) - attributes.remove(name); - - } - - - /** - * Remove a child node from this node, if it is one. - * - * @param node The child node to remove - */ - public void removeNode(TreeNode node) { - - if (children != null) - children.remove(node); - - } - - - /** - * Set the body text associated with this node (if any). - * - * @param body The body text (if any) - */ - public void setBody(String body) { - - this.body = body; - - } - - - /** - * Return a String representation of this TreeNode. - */ - public String toString() { - - StringBuffer sb = new StringBuffer(); - toString(sb, 0, this); - return (sb.toString()); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Append to the specified StringBuffer a character representation of - * this node, with the specified amount of indentation. - * - * @param sb The StringBuffer to append to - * @param indent Number of characters of indentation - * @param node The TreeNode to be printed - */ - protected void toString(StringBuffer sb, int indent, - TreeNode node) { - - int indent2 = indent + 2; - - // Reconstruct an opening node - for (int i = 0; i < indent; i++) - sb.append(' '); - sb.append('<'); - sb.append(node.getName()); - Iterator names = node.findAttributes(); - while (names.hasNext()) { - sb.append(' '); - String name = (String) names.next(); - sb.append(name); - sb.append("=\""); - String value = node.findAttribute(name); - sb.append(value); - sb.append("\""); - } - sb.append(">\n"); - - // Reconstruct the body text of this node (if any) - String body = node.getBody(); - if ((body != null) && (body.length() > 0)) { - for (int i = 0; i < indent2; i++) - sb.append(' '); - sb.append(body); - sb.append("\n"); - } - - // Reconstruct child nodes with extra indentation - Iterator children = node.findChildren(); - while (children.hasNext()) { - TreeNode child = (TreeNode) children.next(); - toString(sb, indent2, child); - } - - // Reconstruct a closing node marker - for (int i = 0; i < indent; i++) - sb.append(' '); - sb.append("\n"); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.xmlparser; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; + + +/** + * Simplified implementation of a Node from a Document Object Model (DOM) + * parse of an XML document. This class is used to represent a DOM tree + * so that the XML parser's implementation of org.w3c.dom need + * not be visible to the remainder of Jasper. + *

        + * WARNING - Construction of a new tree, or modifications + * to an existing one, are not thread-safe and such accesses must be + * synchronized. + * + * @author Craig R. McClanahan + * @version $Revision: 305933 $ $Date: 2004-03-17 13:23:05 -0600 (Wed, 17 Mar 2004) $ + */ + +public class TreeNode { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new node with no parent. + * + * @param name The name of this node + */ + public TreeNode(String name) { + + this(name, null); + + } + + + /** + * Construct a new node with the specified parent. + * + * @param name The name of this node + * @param parent The node that is the parent of this node + */ + public TreeNode(String name, TreeNode parent) { + + super(); + this.name = name; + this.parent = parent; + if (this.parent != null) + this.parent.addChild(this); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The attributes of this node, keyed by attribute name, + * Instantiated only if required. + */ + protected HashMap attributes = null; + + + /** + * The body text associated with this node (if any). + */ + protected String body = null; + + + /** + * The children of this node, instantiated only if required. + */ + protected ArrayList children = null; + + + /** + * The name of this node. + */ + protected String name = null; + + + /** + * The parent node of this node. + */ + protected TreeNode parent = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Add an attribute to this node, replacing any existing attribute + * with the same name. + * + * @param name The attribute name to add + * @param value The new attribute value + */ + public void addAttribute(String name, String value) { + + if (attributes == null) + attributes = new HashMap(); + attributes.put(name, value); + + } + + + /** + * Add a new child node to this node. + * + * @param node The new child node + */ + public void addChild(TreeNode node) { + + if (children == null) + children = new ArrayList(); + children.add(node); + + } + + + /** + * Return the value of the specified node attribute if it exists, or + * null otherwise. + * + * @param name Name of the requested attribute + */ + public String findAttribute(String name) { + + if (attributes == null) + return (null); + else + return ((String) attributes.get(name)); + + } + + + /** + * Return an Iterator of the attribute names of this node. If there are + * no attributes, an empty Iterator is returned. + */ + public Iterator findAttributes() { + + if (attributes == null) + return (Collections.EMPTY_LIST.iterator()); + else + return (attributes.keySet().iterator()); + + } + + + /** + * Return the first child node of this node with the specified name, + * if there is one; otherwise, return null. + * + * @param name Name of the desired child element + */ + public TreeNode findChild(String name) { + + if (children == null) + return (null); + Iterator items = children.iterator(); + while (items.hasNext()) { + TreeNode item = (TreeNode) items.next(); + if (name.equals(item.getName())) + return (item); + } + return (null); + + } + + + /** + * Return an Iterator of all children of this node. If there are no + * children, an empty Iterator is returned. + */ + public Iterator findChildren() { + + if (children == null) + return (Collections.EMPTY_LIST.iterator()); + else + return (children.iterator()); + + } + + + /** + * Return an Iterator over all children of this node that have the + * specified name. If there are no such children, an empty Iterator + * is returned. + * + * @param name Name used to select children + */ + public Iterator findChildren(String name) { + + if (children == null) + return (Collections.EMPTY_LIST.iterator()); + + ArrayList results = new ArrayList(); + Iterator items = children.iterator(); + while (items.hasNext()) { + TreeNode item = (TreeNode) items.next(); + if (name.equals(item.getName())) + results.add(item); + } + return (results.iterator()); + + } + + + /** + * Return the body text associated with this node (if any). + */ + public String getBody() { + + return (this.body); + + } + + + /** + * Return the name of this node. + */ + public String getName() { + + return (this.name); + + } + + + /** + * Remove any existing value for the specified attribute name. + * + * @param name The attribute name to remove + */ + public void removeAttribute(String name) { + + if (attributes != null) + attributes.remove(name); + + } + + + /** + * Remove a child node from this node, if it is one. + * + * @param node The child node to remove + */ + public void removeNode(TreeNode node) { + + if (children != null) + children.remove(node); + + } + + + /** + * Set the body text associated with this node (if any). + * + * @param body The body text (if any) + */ + public void setBody(String body) { + + this.body = body; + + } + + + /** + * Return a String representation of this TreeNode. + */ + public String toString() { + + StringBuffer sb = new StringBuffer(); + toString(sb, 0, this); + return (sb.toString()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Append to the specified StringBuffer a character representation of + * this node, with the specified amount of indentation. + * + * @param sb The StringBuffer to append to + * @param indent Number of characters of indentation + * @param node The TreeNode to be printed + */ + protected void toString(StringBuffer sb, int indent, + TreeNode node) { + + int indent2 = indent + 2; + + // Reconstruct an opening node + for (int i = 0; i < indent; i++) + sb.append(' '); + sb.append('<'); + sb.append(node.getName()); + Iterator names = node.findAttributes(); + while (names.hasNext()) { + sb.append(' '); + String name = (String) names.next(); + sb.append(name); + sb.append("=\""); + String value = node.findAttribute(name); + sb.append(value); + sb.append("\""); + } + sb.append(">\n"); + + // Reconstruct the body text of this node (if any) + String body = node.getBody(); + if ((body != null) && (body.length() > 0)) { + for (int i = 0; i < indent2; i++) + sb.append(' '); + sb.append(body); + sb.append("\n"); + } + + // Reconstruct child nodes with extra indentation + Iterator children = node.findChildren(); + while (children.hasNext()) { + TreeNode child = (TreeNode) children.next(); + toString(sb, indent2, child); + } + + // Reconstruct a closing node marker + for (int i = 0; i < indent; i++) + sb.append(' '); + sb.append("\n"); + + } + + +} diff --git a/java/org/apache/jasper/xmlparser/UCSReader.java b/java/org/apache/jasper/xmlparser/UCSReader.java index 603e3652d..192545040 100644 --- a/java/org/apache/jasper/xmlparser/UCSReader.java +++ b/java/org/apache/jasper/xmlparser/UCSReader.java @@ -1,300 +1,300 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.xmlparser; - -import java.io.InputStream; -import java.io.IOException; -import java.io.Reader; - -/** - * Reader for UCS-2 and UCS-4 encodings. - * (i.e., encodings from ISO-10646-UCS-(2|4)). - * - * @author Neil Graham, IBM - * - * @version $Id: UCSReader.java 306148 2005-03-21 15:38:13Z remm $ - */ -public class UCSReader extends Reader { - - private org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( UCSReader.class ); - - // - // Constants - // - - /** Default byte buffer size (8192, larger than that of ASCIIReader - * since it's reasonable to surmise that the average UCS-4-encoded - * file should be 4 times as large as the average ASCII-encoded file). - */ - public static final int DEFAULT_BUFFER_SIZE = 8192; - - public static final short UCS2LE = 1; - public static final short UCS2BE = 2; - public static final short UCS4LE = 4; - public static final short UCS4BE = 8; - - // - // Data - // - - /** Input stream. */ - protected InputStream fInputStream; - - /** Byte buffer. */ - protected byte[] fBuffer; - - // what kind of data we're dealing with - protected short fEncoding; - - // - // Constructors - // - - /** - * Constructs an ASCII reader from the specified input stream - * using the default buffer size. The Endian-ness and whether this is - * UCS-2 or UCS-4 needs also to be known in advance. - * - * @param inputStream The input stream. - * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. - */ - public UCSReader(InputStream inputStream, short encoding) { - this(inputStream, DEFAULT_BUFFER_SIZE, encoding); - } // (InputStream, short) - - /** - * Constructs an ASCII reader from the specified input stream - * and buffer size. The Endian-ness and whether this is - * UCS-2 or UCS-4 needs also to be known in advance. - * - * @param inputStream The input stream. - * @param size The initial buffer size. - * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. - */ - public UCSReader(InputStream inputStream, int size, short encoding) { - fInputStream = inputStream; - fBuffer = new byte[size]; - fEncoding = encoding; - } // (InputStream,int,short) - - // - // Reader methods - // - - /** - * Read a single character. This method will block until a character is - * available, an I/O error occurs, or the end of the stream is reached. - * - *

        Subclasses that intend to support efficient single-character input - * should override this method. - * - * @return The character read, as an integer in the range 0 to 127 - * (0x00-0x7f), or -1 if the end of the stream has - * been reached - * - * @exception IOException If an I/O error occurs - */ - public int read() throws IOException { - int b0 = fInputStream.read() & 0xff; - if (b0 == 0xff) - return -1; - int b1 = fInputStream.read() & 0xff; - if (b1 == 0xff) - return -1; - if(fEncoding >=4) { - int b2 = fInputStream.read() & 0xff; - if (b2 == 0xff) - return -1; - int b3 = fInputStream.read() & 0xff; - if (b3 == 0xff) - return -1; - if (log.isDebugEnabled()) - log.debug("b0 is " + (b0 & 0xff) + " b1 " + (b1 & 0xff) + " b2 " + (b2 & 0xff) + " b3 " + (b3 & 0xff)); - if (fEncoding == UCS4BE) - return (b0<<24)+(b1<<16)+(b2<<8)+b3; - else - return (b3<<24)+(b2<<16)+(b1<<8)+b0; - } else { // UCS-2 - if (fEncoding == UCS2BE) - return (b0<<8)+b1; - else - return (b1<<8)+b0; - } - } // read():int - - /** - * Read characters into a portion of an array. This method will block - * until some input is available, an I/O error occurs, or the end of the - * stream is reached. - * - * @param ch Destination buffer - * @param offset Offset at which to start storing characters - * @param length Maximum number of characters to read - * - * @return The number of characters read, or -1 if the end of the - * stream has been reached - * - * @exception IOException If an I/O error occurs - */ - public int read(char ch[], int offset, int length) throws IOException { - int byteLength = length << ((fEncoding >= 4)?2:1); - if (byteLength > fBuffer.length) { - byteLength = fBuffer.length; - } - int count = fInputStream.read(fBuffer, 0, byteLength); - if(count == -1) return -1; - // try and make count be a multiple of the number of bytes we're looking for - if(fEncoding >= 4) { // BigEndian - // this looks ugly, but it avoids an if at any rate... - int numToRead = (4 - (count & 3) & 3); - for(int i=0; i> ((fEncoding >= 4)?2:1); - int curPos = 0; - for (int i = 0; i < numChars; i++) { - int b0 = fBuffer[curPos++] & 0xff; - int b1 = fBuffer[curPos++] & 0xff; - if(fEncoding >=4) { - int b2 = fBuffer[curPos++] & 0xff; - int b3 = fBuffer[curPos++] & 0xff; - if (fEncoding == UCS4BE) - ch[offset+i] = (char)((b0<<24)+(b1<<16)+(b2<<8)+b3); - else - ch[offset+i] = (char)((b3<<24)+(b2<<16)+(b1<<8)+b0); - } else { // UCS-2 - if (fEncoding == UCS2BE) - ch[offset+i] = (char)((b0<<8)+b1); - else - ch[offset+i] = (char)((b1<<8)+b0); - } - } - return numChars; - } // read(char[],int,int) - - /** - * Skip characters. This method will block until some characters are - * available, an I/O error occurs, or the end of the stream is reached. - * - * @param n The number of characters to skip - * - * @return The number of characters actually skipped - * - * @exception IOException If an I/O error occurs - */ - public long skip(long n) throws IOException { - // charWidth will represent the number of bits to move - // n leftward to get num of bytes to skip, and then move the result rightward - // to get num of chars effectively skipped. - // The trick with &'ing, as with elsewhere in this dcode, is - // intended to avoid an expensive use of / that might not be optimized - // away. - int charWidth = (fEncoding >=4)?2:1; - long bytesSkipped = fInputStream.skip(n<> charWidth; - return (bytesSkipped >> charWidth) + 1; - } // skip(long):long - - /** - * Tell whether this stream is ready to be read. - * - * @return True if the next read() is guaranteed not to block for input, - * false otherwise. Note that returning false does not guarantee that the - * next read will block. - * - * @exception IOException If an I/O error occurs - */ - public boolean ready() throws IOException { - return false; - } // ready() - - /** - * Tell whether this stream supports the mark() operation. - */ - public boolean markSupported() { - return fInputStream.markSupported(); - } // markSupported() - - /** - * Mark the present position in the stream. Subsequent calls to reset() - * will attempt to reposition the stream to this point. Not all - * character-input streams support the mark() operation. - * - * @param readAheadLimit Limit on the number of characters that may be - * read while still preserving the mark. After - * reading this many characters, attempting to - * reset the stream may fail. - * - * @exception IOException If the stream does not support mark(), - * or if some other I/O error occurs - */ - public void mark(int readAheadLimit) throws IOException { - fInputStream.mark(readAheadLimit); - } // mark(int) - - /** - * Reset the stream. If the stream has been marked, then attempt to - * reposition it at the mark. If the stream has not been marked, then - * attempt to reset it in some way appropriate to the particular stream, - * for example by repositioning it to its starting point. Not all - * character-input streams support the reset() operation, and some support - * reset() without supporting mark(). - * - * @exception IOException If the stream has not been marked, - * or if the mark has been invalidated, - * or if the stream does not support reset(), - * or if some other I/O error occurs - */ - public void reset() throws IOException { - fInputStream.reset(); - } // reset() - - /** - * Close the stream. Once a stream has been closed, further read(), - * ready(), mark(), or reset() invocations will throw an IOException. - * Closing a previously-closed stream, however, has no effect. - * - * @exception IOException If an I/O error occurs - */ - public void close() throws IOException { - fInputStream.close(); - } // close() - -} // class UCSReader +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.xmlparser; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; + +/** + * Reader for UCS-2 and UCS-4 encodings. + * (i.e., encodings from ISO-10646-UCS-(2|4)). + * + * @author Neil Graham, IBM + * + * @version $Id: UCSReader.java 306148 2005-03-21 15:38:13Z remm $ + */ +public class UCSReader extends Reader { + + private org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( UCSReader.class ); + + // + // Constants + // + + /** Default byte buffer size (8192, larger than that of ASCIIReader + * since it's reasonable to surmise that the average UCS-4-encoded + * file should be 4 times as large as the average ASCII-encoded file). + */ + public static final int DEFAULT_BUFFER_SIZE = 8192; + + public static final short UCS2LE = 1; + public static final short UCS2BE = 2; + public static final short UCS4LE = 4; + public static final short UCS4BE = 8; + + // + // Data + // + + /** Input stream. */ + protected InputStream fInputStream; + + /** Byte buffer. */ + protected byte[] fBuffer; + + // what kind of data we're dealing with + protected short fEncoding; + + // + // Constructors + // + + /** + * Constructs an ASCII reader from the specified input stream + * using the default buffer size. The Endian-ness and whether this is + * UCS-2 or UCS-4 needs also to be known in advance. + * + * @param inputStream The input stream. + * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. + */ + public UCSReader(InputStream inputStream, short encoding) { + this(inputStream, DEFAULT_BUFFER_SIZE, encoding); + } // (InputStream, short) + + /** + * Constructs an ASCII reader from the specified input stream + * and buffer size. The Endian-ness and whether this is + * UCS-2 or UCS-4 needs also to be known in advance. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + * @param encoding One of UCS2LE, UCS2BE, UCS4LE or UCS4BE. + */ + public UCSReader(InputStream inputStream, int size, short encoding) { + fInputStream = inputStream; + fBuffer = new byte[size]; + fEncoding = encoding; + } // (InputStream,int,short) + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

        Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 127 + * (0x00-0x7f), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + int b0 = fInputStream.read() & 0xff; + if (b0 == 0xff) + return -1; + int b1 = fInputStream.read() & 0xff; + if (b1 == 0xff) + return -1; + if(fEncoding >=4) { + int b2 = fInputStream.read() & 0xff; + if (b2 == 0xff) + return -1; + int b3 = fInputStream.read() & 0xff; + if (b3 == 0xff) + return -1; + if (log.isDebugEnabled()) + log.debug("b0 is " + (b0 & 0xff) + " b1 " + (b1 & 0xff) + " b2 " + (b2 & 0xff) + " b3 " + (b3 & 0xff)); + if (fEncoding == UCS4BE) + return (b0<<24)+(b1<<16)+(b2<<8)+b3; + else + return (b3<<24)+(b2<<16)+(b1<<8)+b0; + } else { // UCS-2 + if (fEncoding == UCS2BE) + return (b0<<8)+b1; + else + return (b1<<8)+b0; + } + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + int byteLength = length << ((fEncoding >= 4)?2:1); + if (byteLength > fBuffer.length) { + byteLength = fBuffer.length; + } + int count = fInputStream.read(fBuffer, 0, byteLength); + if(count == -1) return -1; + // try and make count be a multiple of the number of bytes we're looking for + if(fEncoding >= 4) { // BigEndian + // this looks ugly, but it avoids an if at any rate... + int numToRead = (4 - (count & 3) & 3); + for(int i=0; i> ((fEncoding >= 4)?2:1); + int curPos = 0; + for (int i = 0; i < numChars; i++) { + int b0 = fBuffer[curPos++] & 0xff; + int b1 = fBuffer[curPos++] & 0xff; + if(fEncoding >=4) { + int b2 = fBuffer[curPos++] & 0xff; + int b3 = fBuffer[curPos++] & 0xff; + if (fEncoding == UCS4BE) + ch[offset+i] = (char)((b0<<24)+(b1<<16)+(b2<<8)+b3); + else + ch[offset+i] = (char)((b3<<24)+(b2<<16)+(b1<<8)+b0); + } else { // UCS-2 + if (fEncoding == UCS2BE) + ch[offset+i] = (char)((b0<<8)+b1); + else + ch[offset+i] = (char)((b1<<8)+b0); + } + } + return numChars; + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + // charWidth will represent the number of bits to move + // n leftward to get num of bytes to skip, and then move the result rightward + // to get num of chars effectively skipped. + // The trick with &'ing, as with elsewhere in this dcode, is + // intended to avoid an expensive use of / that might not be optimized + // away. + int charWidth = (fEncoding >=4)?2:1; + long bytesSkipped = fInputStream.skip(n<> charWidth; + return (bytesSkipped >> charWidth) + 1; + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return fInputStream.markSupported(); + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + fInputStream.mark(readAheadLimit); + } // mark(int) + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fInputStream.reset(); + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + +} // class UCSReader diff --git a/java/org/apache/jasper/xmlparser/UTF8Reader.java b/java/org/apache/jasper/xmlparser/UTF8Reader.java index cd360eabd..5a9f6e6b1 100644 --- a/java/org/apache/jasper/xmlparser/UTF8Reader.java +++ b/java/org/apache/jasper/xmlparser/UTF8Reader.java @@ -1,634 +1,634 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jasper.xmlparser; - -import java.io.InputStream; -import java.io.IOException; -import java.io.Reader; -import java.io.UTFDataFormatException; -import org.apache.jasper.compiler.Localizer; - -/** - * @author Andy Clark, IBM - * - * @version $Id: UTF8Reader.java 306148 2005-03-21 15:38:13Z remm $ - */ -public class UTF8Reader - extends Reader { - - private org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( UTF8Reader.class ); - - // - // Constants - // - - /** Default byte buffer size (2048). */ - public static final int DEFAULT_BUFFER_SIZE = 2048; - - // debugging - - /** Debug read. */ - private static final boolean DEBUG_READ = false; - - // - // Data - // - - /** Input stream. */ - protected InputStream fInputStream; - - /** Byte buffer. */ - protected byte[] fBuffer; - - /** Offset into buffer. */ - protected int fOffset; - - /** Surrogate character. */ - private int fSurrogate = -1; - - // - // Constructors - // - - /** - * Constructs a UTF-8 reader from the specified input stream, - * buffer size and MessageFormatter. - * - * @param inputStream The input stream. - * @param size The initial buffer size. - */ - public UTF8Reader(InputStream inputStream, int size) { - fInputStream = inputStream; - fBuffer = new byte[size]; - } - - // - // Reader methods - // - - /** - * Read a single character. This method will block until a character is - * available, an I/O error occurs, or the end of the stream is reached. - * - *

        Subclasses that intend to support efficient single-character input - * should override this method. - * - * @return The character read, as an integer in the range 0 to 16383 - * (0x00-0xffff), or -1 if the end of the stream has - * been reached - * - * @exception IOException If an I/O error occurs - */ - public int read() throws IOException { - - // decode character - int c = fSurrogate; - if (fSurrogate == -1) { - // NOTE: We use the index into the buffer if there are remaining - // bytes from the last block read. -Ac - int index = 0; - - // get first byte - int b0 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b0 == -1) { - return -1; - } - - // UTF-8: [0xxx xxxx] - // Unicode: [0000 0000] [0xxx xxxx] - if (b0 < 0x80) { - c = (char)b0; - } - - // UTF-8: [110y yyyy] [10xx xxxx] - // Unicode: [0000 0yyy] [yyxx xxxx] - else if ((b0 & 0xE0) == 0xC0) { - int b1 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b1 == -1) { - expectedByte(2, 2); - } - if ((b1 & 0xC0) != 0x80) { - invalidByte(2, 2, b1); - } - c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); - } - - // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] - // Unicode: [zzzz yyyy] [yyxx xxxx] - else if ((b0 & 0xF0) == 0xE0) { - int b1 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b1 == -1) { - expectedByte(2, 3); - } - if ((b1 & 0xC0) != 0x80) { - invalidByte(2, 3, b1); - } - int b2 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b2 == -1) { - expectedByte(3, 3); - } - if ((b2 & 0xC0) != 0x80) { - invalidByte(3, 3, b2); - } - c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | - (b2 & 0x003F); - } - - // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* - // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) - // [1101 11yy] [yyxx xxxx] (low surrogate) - // * uuuuu = wwww + 1 - else if ((b0 & 0xF8) == 0xF0) { - int b1 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b1 == -1) { - expectedByte(2, 4); - } - if ((b1 & 0xC0) != 0x80) { - invalidByte(2, 3, b1); - } - int b2 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b2 == -1) { - expectedByte(3, 4); - } - if ((b2 & 0xC0) != 0x80) { - invalidByte(3, 3, b2); - } - int b3 = index == fOffset - ? fInputStream.read() : fBuffer[index++] & 0x00FF; - if (b3 == -1) { - expectedByte(4, 4); - } - if ((b3 & 0xC0) != 0x80) { - invalidByte(4, 4, b3); - } - int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); - if (uuuuu > 0x10) { - invalidSurrogate(uuuuu); - } - int wwww = uuuuu - 1; - int hs = 0xD800 | - ((wwww << 6) & 0x03C0) | ((b1 << 2) & 0x003C) | - ((b2 >> 4) & 0x0003); - int ls = 0xDC00 | ((b2 << 6) & 0x03C0) | (b3 & 0x003F); - c = hs; - fSurrogate = ls; - } - - // error - else { - invalidByte(1, 1, b0); - } - } - - // use surrogate - else { - fSurrogate = -1; - } - - // return character - if (DEBUG_READ) { - if (log.isDebugEnabled()) - log.debug("read(): 0x"+Integer.toHexString(c)); - } - return c; - - } // read():int - - /** - * Read characters into a portion of an array. This method will block - * until some input is available, an I/O error occurs, or the end of the - * stream is reached. - * - * @param ch Destination buffer - * @param offset Offset at which to start storing characters - * @param length Maximum number of characters to read - * - * @return The number of characters read, or -1 if the end of the - * stream has been reached - * - * @exception IOException If an I/O error occurs - */ - public int read(char ch[], int offset, int length) throws IOException { - - // handle surrogate - int out = offset; - if (fSurrogate != -1) { - ch[offset + 1] = (char)fSurrogate; - fSurrogate = -1; - length--; - out++; - } - - // read bytes - int count = 0; - if (fOffset == 0) { - // adjust length to read - if (length > fBuffer.length) { - length = fBuffer.length; - } - - // perform read operation - count = fInputStream.read(fBuffer, 0, length); - if (count == -1) { - return -1; - } - count += out - offset; - } - - // skip read; last character was in error - // NOTE: Having an offset value other than zero means that there was - // an error in the last character read. In this case, we have - // skipped the read so we don't consume any bytes past the - // error. By signalling the error on the next block read we - // allow the method to return the most valid characters that - // it can on the previous block read. -Ac - else { - count = fOffset; - fOffset = 0; - } - - // convert bytes to characters - final int total = count; - for (int in = 0; in < total; in++) { - int b0 = fBuffer[in] & 0x00FF; - - // UTF-8: [0xxx xxxx] - // Unicode: [0000 0000] [0xxx xxxx] - if (b0 < 0x80) { - ch[out++] = (char)b0; - continue; - } - - // UTF-8: [110y yyyy] [10xx xxxx] - // Unicode: [0000 0yyy] [yyxx xxxx] - if ((b0 & 0xE0) == 0xC0) { - int b1 = -1; - if (++in < total) { - b1 = fBuffer[in] & 0x00FF; - } - else { - b1 = fInputStream.read(); - if (b1 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fOffset = 1; - return out - offset; - } - expectedByte(2, 2); - } - count++; - } - if ((b1 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fOffset = 2; - return out - offset; - } - invalidByte(2, 2, b1); - } - int c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); - ch[out++] = (char)c; - count -= 1; - continue; - } - - // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] - // Unicode: [zzzz yyyy] [yyxx xxxx] - if ((b0 & 0xF0) == 0xE0) { - int b1 = -1; - if (++in < total) { - b1 = fBuffer[in] & 0x00FF; - } - else { - b1 = fInputStream.read(); - if (b1 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fOffset = 1; - return out - offset; - } - expectedByte(2, 3); - } - count++; - } - if ((b1 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fOffset = 2; - return out - offset; - } - invalidByte(2, 3, b1); - } - int b2 = -1; - if (++in < total) { - b2 = fBuffer[in] & 0x00FF; - } - else { - b2 = fInputStream.read(); - if (b2 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fOffset = 2; - return out - offset; - } - expectedByte(3, 3); - } - count++; - } - if ((b2 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fBuffer[2] = (byte)b2; - fOffset = 3; - return out - offset; - } - invalidByte(3, 3, b2); - } - int c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | - (b2 & 0x003F); - ch[out++] = (char)c; - count -= 2; - continue; - } - - // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* - // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) - // [1101 11yy] [yyxx xxxx] (low surrogate) - // * uuuuu = wwww + 1 - if ((b0 & 0xF8) == 0xF0) { - int b1 = -1; - if (++in < total) { - b1 = fBuffer[in] & 0x00FF; - } - else { - b1 = fInputStream.read(); - if (b1 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fOffset = 1; - return out - offset; - } - expectedByte(2, 4); - } - count++; - } - if ((b1 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fOffset = 2; - return out - offset; - } - invalidByte(2, 4, b1); - } - int b2 = -1; - if (++in < total) { - b2 = fBuffer[in] & 0x00FF; - } - else { - b2 = fInputStream.read(); - if (b2 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fOffset = 2; - return out - offset; - } - expectedByte(3, 4); - } - count++; - } - if ((b2 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fBuffer[2] = (byte)b2; - fOffset = 3; - return out - offset; - } - invalidByte(3, 4, b2); - } - int b3 = -1; - if (++in < total) { - b3 = fBuffer[in] & 0x00FF; - } - else { - b3 = fInputStream.read(); - if (b3 == -1) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fBuffer[2] = (byte)b2; - fOffset = 3; - return out - offset; - } - expectedByte(4, 4); - } - count++; - } - if ((b3 & 0xC0) != 0x80) { - if (out > offset) { - fBuffer[0] = (byte)b0; - fBuffer[1] = (byte)b1; - fBuffer[2] = (byte)b2; - fBuffer[3] = (byte)b3; - fOffset = 4; - return out - offset; - } - invalidByte(4, 4, b2); - } - - // decode bytes into surrogate characters - int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); - if (uuuuu > 0x10) { - invalidSurrogate(uuuuu); - } - int wwww = uuuuu - 1; - int zzzz = b1 & 0x000F; - int yyyyyy = b2 & 0x003F; - int xxxxxx = b3 & 0x003F; - int hs = 0xD800 | ((wwww << 6) & 0x03C0) | (zzzz << 2) | (yyyyyy >> 4); - int ls = 0xDC00 | ((yyyyyy << 6) & 0x03C0) | xxxxxx; - - // set characters - ch[out++] = (char)hs; - ch[out++] = (char)ls; - count -= 2; - continue; - } - - // error - if (out > offset) { - fBuffer[0] = (byte)b0; - fOffset = 1; - return out - offset; - } - invalidByte(1, 1, b0); - } - - // return number of characters converted - if (DEBUG_READ) { - if (log.isDebugEnabled()) - log.debug("read(char[],"+offset+','+length+"): count="+count); - } - return count; - - } // read(char[],int,int) - - /** - * Skip characters. This method will block until some characters are - * available, an I/O error occurs, or the end of the stream is reached. - * - * @param n The number of characters to skip - * - * @return The number of characters actually skipped - * - * @exception IOException If an I/O error occurs - */ - public long skip(long n) throws IOException { - - long remaining = n; - final char[] ch = new char[fBuffer.length]; - do { - int length = ch.length < remaining ? ch.length : (int)remaining; - int count = read(ch, 0, length); - if (count > 0) { - remaining -= count; - } - else { - break; - } - } while (remaining > 0); - - long skipped = n - remaining; - return skipped; - - } // skip(long):long - - /** - * Tell whether this stream is ready to be read. - * - * @return True if the next read() is guaranteed not to block for input, - * false otherwise. Note that returning false does not guarantee that the - * next read will block. - * - * @exception IOException If an I/O error occurs - */ - public boolean ready() throws IOException { - return false; - } // ready() - - /** - * Tell whether this stream supports the mark() operation. - */ - public boolean markSupported() { - return false; - } // markSupported() - - /** - * Mark the present position in the stream. Subsequent calls to reset() - * will attempt to reposition the stream to this point. Not all - * character-input streams support the mark() operation. - * - * @param readAheadLimit Limit on the number of characters that may be - * read while still preserving the mark. After - * reading this many characters, attempting to - * reset the stream may fail. - * - * @exception IOException If the stream does not support mark(), - * or if some other I/O error occurs - */ - public void mark(int readAheadLimit) throws IOException { - throw new IOException( - Localizer.getMessage("jsp.error.xml.operationNotSupported", - "mark()", "UTF-8")); - } - - /** - * Reset the stream. If the stream has been marked, then attempt to - * reposition it at the mark. If the stream has not been marked, then - * attempt to reset it in some way appropriate to the particular stream, - * for example by repositioning it to its starting point. Not all - * character-input streams support the reset() operation, and some support - * reset() without supporting mark(). - * - * @exception IOException If the stream has not been marked, - * or if the mark has been invalidated, - * or if the stream does not support reset(), - * or if some other I/O error occurs - */ - public void reset() throws IOException { - fOffset = 0; - fSurrogate = -1; - } // reset() - - /** - * Close the stream. Once a stream has been closed, further read(), - * ready(), mark(), or reset() invocations will throw an IOException. - * Closing a previously-closed stream, however, has no effect. - * - * @exception IOException If an I/O error occurs - */ - public void close() throws IOException { - fInputStream.close(); - } // close() - - // - // Private methods - // - - /** Throws an exception for expected byte. */ - private void expectedByte(int position, int count) - throws UTFDataFormatException { - - throw new UTFDataFormatException( - Localizer.getMessage("jsp.error.xml.expectedByte", - Integer.toString(position), - Integer.toString(count))); - - } // expectedByte(int,int,int) - - /** Throws an exception for invalid byte. */ - private void invalidByte(int position, int count, int c) - throws UTFDataFormatException { - - throw new UTFDataFormatException( - Localizer.getMessage("jsp.error.xml.invalidByte", - Integer.toString(position), - Integer.toString(count))); - } // invalidByte(int,int,int,int) - - /** Throws an exception for invalid surrogate bits. */ - private void invalidSurrogate(int uuuuu) throws UTFDataFormatException { - - throw new UTFDataFormatException( - Localizer.getMessage("jsp.error.xml.invalidHighSurrogate", - Integer.toHexString(uuuuu))); - } // invalidSurrogate(int) - -} // class UTF8Reader +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.xmlparser; + +import java.io.InputStream; +import java.io.IOException; +import java.io.Reader; +import java.io.UTFDataFormatException; +import org.apache.jasper.compiler.Localizer; + +/** + * @author Andy Clark, IBM + * + * @version $Id: UTF8Reader.java 306148 2005-03-21 15:38:13Z remm $ + */ +public class UTF8Reader + extends Reader { + + private org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( UTF8Reader.class ); + + // + // Constants + // + + /** Default byte buffer size (2048). */ + public static final int DEFAULT_BUFFER_SIZE = 2048; + + // debugging + + /** Debug read. */ + private static final boolean DEBUG_READ = false; + + // + // Data + // + + /** Input stream. */ + protected InputStream fInputStream; + + /** Byte buffer. */ + protected byte[] fBuffer; + + /** Offset into buffer. */ + protected int fOffset; + + /** Surrogate character. */ + private int fSurrogate = -1; + + // + // Constructors + // + + /** + * Constructs a UTF-8 reader from the specified input stream, + * buffer size and MessageFormatter. + * + * @param inputStream The input stream. + * @param size The initial buffer size. + */ + public UTF8Reader(InputStream inputStream, int size) { + fInputStream = inputStream; + fBuffer = new byte[size]; + } + + // + // Reader methods + // + + /** + * Read a single character. This method will block until a character is + * available, an I/O error occurs, or the end of the stream is reached. + * + *

        Subclasses that intend to support efficient single-character input + * should override this method. + * + * @return The character read, as an integer in the range 0 to 16383 + * (0x00-0xffff), or -1 if the end of the stream has + * been reached + * + * @exception IOException If an I/O error occurs + */ + public int read() throws IOException { + + // decode character + int c = fSurrogate; + if (fSurrogate == -1) { + // NOTE: We use the index into the buffer if there are remaining + // bytes from the last block read. -Ac + int index = 0; + + // get first byte + int b0 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b0 == -1) { + return -1; + } + + // UTF-8: [0xxx xxxx] + // Unicode: [0000 0000] [0xxx xxxx] + if (b0 < 0x80) { + c = (char)b0; + } + + // UTF-8: [110y yyyy] [10xx xxxx] + // Unicode: [0000 0yyy] [yyxx xxxx] + else if ((b0 & 0xE0) == 0xC0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 2); + } + if ((b1 & 0xC0) != 0x80) { + invalidByte(2, 2, b1); + } + c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); + } + + // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] + // Unicode: [zzzz yyyy] [yyxx xxxx] + else if ((b0 & 0xF0) == 0xE0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 3); + } + if ((b1 & 0xC0) != 0x80) { + invalidByte(2, 3, b1); + } + int b2 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b2 == -1) { + expectedByte(3, 3); + } + if ((b2 & 0xC0) != 0x80) { + invalidByte(3, 3, b2); + } + c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | + (b2 & 0x003F); + } + + // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* + // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) + // [1101 11yy] [yyxx xxxx] (low surrogate) + // * uuuuu = wwww + 1 + else if ((b0 & 0xF8) == 0xF0) { + int b1 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b1 == -1) { + expectedByte(2, 4); + } + if ((b1 & 0xC0) != 0x80) { + invalidByte(2, 3, b1); + } + int b2 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b2 == -1) { + expectedByte(3, 4); + } + if ((b2 & 0xC0) != 0x80) { + invalidByte(3, 3, b2); + } + int b3 = index == fOffset + ? fInputStream.read() : fBuffer[index++] & 0x00FF; + if (b3 == -1) { + expectedByte(4, 4); + } + if ((b3 & 0xC0) != 0x80) { + invalidByte(4, 4, b3); + } + int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); + if (uuuuu > 0x10) { + invalidSurrogate(uuuuu); + } + int wwww = uuuuu - 1; + int hs = 0xD800 | + ((wwww << 6) & 0x03C0) | ((b1 << 2) & 0x003C) | + ((b2 >> 4) & 0x0003); + int ls = 0xDC00 | ((b2 << 6) & 0x03C0) | (b3 & 0x003F); + c = hs; + fSurrogate = ls; + } + + // error + else { + invalidByte(1, 1, b0); + } + } + + // use surrogate + else { + fSurrogate = -1; + } + + // return character + if (DEBUG_READ) { + if (log.isDebugEnabled()) + log.debug("read(): 0x"+Integer.toHexString(c)); + } + return c; + + } // read():int + + /** + * Read characters into a portion of an array. This method will block + * until some input is available, an I/O error occurs, or the end of the + * stream is reached. + * + * @param ch Destination buffer + * @param offset Offset at which to start storing characters + * @param length Maximum number of characters to read + * + * @return The number of characters read, or -1 if the end of the + * stream has been reached + * + * @exception IOException If an I/O error occurs + */ + public int read(char ch[], int offset, int length) throws IOException { + + // handle surrogate + int out = offset; + if (fSurrogate != -1) { + ch[offset + 1] = (char)fSurrogate; + fSurrogate = -1; + length--; + out++; + } + + // read bytes + int count = 0; + if (fOffset == 0) { + // adjust length to read + if (length > fBuffer.length) { + length = fBuffer.length; + } + + // perform read operation + count = fInputStream.read(fBuffer, 0, length); + if (count == -1) { + return -1; + } + count += out - offset; + } + + // skip read; last character was in error + // NOTE: Having an offset value other than zero means that there was + // an error in the last character read. In this case, we have + // skipped the read so we don't consume any bytes past the + // error. By signalling the error on the next block read we + // allow the method to return the most valid characters that + // it can on the previous block read. -Ac + else { + count = fOffset; + fOffset = 0; + } + + // convert bytes to characters + final int total = count; + for (int in = 0; in < total; in++) { + int b0 = fBuffer[in] & 0x00FF; + + // UTF-8: [0xxx xxxx] + // Unicode: [0000 0000] [0xxx xxxx] + if (b0 < 0x80) { + ch[out++] = (char)b0; + continue; + } + + // UTF-8: [110y yyyy] [10xx xxxx] + // Unicode: [0000 0yyy] [yyxx xxxx] + if ((b0 & 0xE0) == 0xC0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 2); + } + count++; + } + if ((b1 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 2, b1); + } + int c = ((b0 << 6) & 0x07C0) | (b1 & 0x003F); + ch[out++] = (char)c; + count -= 1; + continue; + } + + // UTF-8: [1110 zzzz] [10yy yyyy] [10xx xxxx] + // Unicode: [zzzz yyyy] [yyxx xxxx] + if ((b0 & 0xF0) == 0xE0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 3); + } + count++; + } + if ((b1 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 3, b1); + } + int b2 = -1; + if (++in < total) { + b2 = fBuffer[in] & 0x00FF; + } + else { + b2 = fInputStream.read(); + if (b2 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + expectedByte(3, 3); + } + count++; + } + if ((b2 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + invalidByte(3, 3, b2); + } + int c = ((b0 << 12) & 0xF000) | ((b1 << 6) & 0x0FC0) | + (b2 & 0x003F); + ch[out++] = (char)c; + count -= 2; + continue; + } + + // UTF-8: [1111 0uuu] [10uu zzzz] [10yy yyyy] [10xx xxxx]* + // Unicode: [1101 10ww] [wwzz zzyy] (high surrogate) + // [1101 11yy] [yyxx xxxx] (low surrogate) + // * uuuuu = wwww + 1 + if ((b0 & 0xF8) == 0xF0) { + int b1 = -1; + if (++in < total) { + b1 = fBuffer[in] & 0x00FF; + } + else { + b1 = fInputStream.read(); + if (b1 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + expectedByte(2, 4); + } + count++; + } + if ((b1 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + invalidByte(2, 4, b1); + } + int b2 = -1; + if (++in < total) { + b2 = fBuffer[in] & 0x00FF; + } + else { + b2 = fInputStream.read(); + if (b2 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fOffset = 2; + return out - offset; + } + expectedByte(3, 4); + } + count++; + } + if ((b2 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + invalidByte(3, 4, b2); + } + int b3 = -1; + if (++in < total) { + b3 = fBuffer[in] & 0x00FF; + } + else { + b3 = fInputStream.read(); + if (b3 == -1) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fOffset = 3; + return out - offset; + } + expectedByte(4, 4); + } + count++; + } + if ((b3 & 0xC0) != 0x80) { + if (out > offset) { + fBuffer[0] = (byte)b0; + fBuffer[1] = (byte)b1; + fBuffer[2] = (byte)b2; + fBuffer[3] = (byte)b3; + fOffset = 4; + return out - offset; + } + invalidByte(4, 4, b2); + } + + // decode bytes into surrogate characters + int uuuuu = ((b0 << 2) & 0x001C) | ((b1 >> 4) & 0x0003); + if (uuuuu > 0x10) { + invalidSurrogate(uuuuu); + } + int wwww = uuuuu - 1; + int zzzz = b1 & 0x000F; + int yyyyyy = b2 & 0x003F; + int xxxxxx = b3 & 0x003F; + int hs = 0xD800 | ((wwww << 6) & 0x03C0) | (zzzz << 2) | (yyyyyy >> 4); + int ls = 0xDC00 | ((yyyyyy << 6) & 0x03C0) | xxxxxx; + + // set characters + ch[out++] = (char)hs; + ch[out++] = (char)ls; + count -= 2; + continue; + } + + // error + if (out > offset) { + fBuffer[0] = (byte)b0; + fOffset = 1; + return out - offset; + } + invalidByte(1, 1, b0); + } + + // return number of characters converted + if (DEBUG_READ) { + if (log.isDebugEnabled()) + log.debug("read(char[],"+offset+','+length+"): count="+count); + } + return count; + + } // read(char[],int,int) + + /** + * Skip characters. This method will block until some characters are + * available, an I/O error occurs, or the end of the stream is reached. + * + * @param n The number of characters to skip + * + * @return The number of characters actually skipped + * + * @exception IOException If an I/O error occurs + */ + public long skip(long n) throws IOException { + + long remaining = n; + final char[] ch = new char[fBuffer.length]; + do { + int length = ch.length < remaining ? ch.length : (int)remaining; + int count = read(ch, 0, length); + if (count > 0) { + remaining -= count; + } + else { + break; + } + } while (remaining > 0); + + long skipped = n - remaining; + return skipped; + + } // skip(long):long + + /** + * Tell whether this stream is ready to be read. + * + * @return True if the next read() is guaranteed not to block for input, + * false otherwise. Note that returning false does not guarantee that the + * next read will block. + * + * @exception IOException If an I/O error occurs + */ + public boolean ready() throws IOException { + return false; + } // ready() + + /** + * Tell whether this stream supports the mark() operation. + */ + public boolean markSupported() { + return false; + } // markSupported() + + /** + * Mark the present position in the stream. Subsequent calls to reset() + * will attempt to reposition the stream to this point. Not all + * character-input streams support the mark() operation. + * + * @param readAheadLimit Limit on the number of characters that may be + * read while still preserving the mark. After + * reading this many characters, attempting to + * reset the stream may fail. + * + * @exception IOException If the stream does not support mark(), + * or if some other I/O error occurs + */ + public void mark(int readAheadLimit) throws IOException { + throw new IOException( + Localizer.getMessage("jsp.error.xml.operationNotSupported", + "mark()", "UTF-8")); + } + + /** + * Reset the stream. If the stream has been marked, then attempt to + * reposition it at the mark. If the stream has not been marked, then + * attempt to reset it in some way appropriate to the particular stream, + * for example by repositioning it to its starting point. Not all + * character-input streams support the reset() operation, and some support + * reset() without supporting mark(). + * + * @exception IOException If the stream has not been marked, + * or if the mark has been invalidated, + * or if the stream does not support reset(), + * or if some other I/O error occurs + */ + public void reset() throws IOException { + fOffset = 0; + fSurrogate = -1; + } // reset() + + /** + * Close the stream. Once a stream has been closed, further read(), + * ready(), mark(), or reset() invocations will throw an IOException. + * Closing a previously-closed stream, however, has no effect. + * + * @exception IOException If an I/O error occurs + */ + public void close() throws IOException { + fInputStream.close(); + } // close() + + // + // Private methods + // + + /** Throws an exception for expected byte. */ + private void expectedByte(int position, int count) + throws UTFDataFormatException { + + throw new UTFDataFormatException( + Localizer.getMessage("jsp.error.xml.expectedByte", + Integer.toString(position), + Integer.toString(count))); + + } // expectedByte(int,int,int) + + /** Throws an exception for invalid byte. */ + private void invalidByte(int position, int count, int c) + throws UTFDataFormatException { + + throw new UTFDataFormatException( + Localizer.getMessage("jsp.error.xml.invalidByte", + Integer.toString(position), + Integer.toString(count))); + } // invalidByte(int,int,int,int) + + /** Throws an exception for invalid surrogate bits. */ + private void invalidSurrogate(int uuuuu) throws UTFDataFormatException { + + throw new UTFDataFormatException( + Localizer.getMessage("jsp.error.xml.invalidHighSurrogate", + Integer.toHexString(uuuuu))); + } // invalidSurrogate(int) + +} // class UTF8Reader diff --git a/java/org/apache/jasper/xmlparser/XMLChar.java b/java/org/apache/jasper/xmlparser/XMLChar.java index bad99e1f3..121117fdc 100644 --- a/java/org/apache/jasper/xmlparser/XMLChar.java +++ b/java/org/apache/jasper/xmlparser/XMLChar.java @@ -1,1030 +1,1030 @@ -/* - * Copyright 1999,2004-2005 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -import java.util.Arrays; - -/** - * This class defines the basic XML character properties. The data - * in this class can be used to verify that a character is a valid - * XML character or if the character is a space, name start, or name - * character. - *

        - * A series of convenience methods are supplied to ease the burden - * of the developer. Because inlining the checks can improve per - * character performance, the tables of character properties are - * public. Using the character as an index into the CHARS - * array and applying the appropriate mask flag (e.g. - * MASK_VALID), yields the same results as calling the - * convenience methods. There is one exception: check the comments - * for the isValid method for details. - * - * @author Glenn Marcy, IBM - * @author Andy Clark, IBM - * @author Eric Ye, IBM - * @author Arnaud Le Hors, IBM - * @author Michael Glavassevich, IBM - * @author Rahul Srivastava, Sun Microsystems Inc. - * - * @version $Id: XMLChar.java 306179 2005-07-27 15:12:04Z yoavs $ - */ -public class XMLChar { - - // - // Constants - // - - /** Character flags. */ - private static final byte[] CHARS = new byte[1 << 16]; - - /** Valid character mask. */ - public static final int MASK_VALID = 0x01; - - /** Space character mask. */ - public static final int MASK_SPACE = 0x02; - - /** Name start character mask. */ - public static final int MASK_NAME_START = 0x04; - - /** Name character mask. */ - public static final int MASK_NAME = 0x08; - - /** Pubid character mask. */ - public static final int MASK_PUBID = 0x10; - - /** - * Content character mask. Special characters are those that can - * be considered the start of markup, such as '<' and '&'. - * The various newline characters are considered special as well. - * All other valid XML characters can be considered content. - *

        - * This is an optimization for the inner loop of character scanning. - */ - public static final int MASK_CONTENT = 0x20; - - /** NCName start character mask. */ - public static final int MASK_NCNAME_START = 0x40; - - /** NCName character mask. */ - public static final int MASK_NCNAME = 0x80; - - // - // Static initialization - // - - static { - - // Initializing the Character Flag Array - // Code generated by: XMLCharGenerator. - - CHARS[9] = 35; - CHARS[10] = 19; - CHARS[13] = 19; - CHARS[32] = 51; - CHARS[33] = 49; - CHARS[34] = 33; - Arrays.fill(CHARS, 35, 38, (byte) 49 ); // Fill 3 of value (byte) 49 - CHARS[38] = 1; - Arrays.fill(CHARS, 39, 45, (byte) 49 ); // Fill 6 of value (byte) 49 - Arrays.fill(CHARS, 45, 47, (byte) -71 ); // Fill 2 of value (byte) -71 - CHARS[47] = 49; - Arrays.fill(CHARS, 48, 58, (byte) -71 ); // Fill 10 of value (byte) -71 - CHARS[58] = 61; - CHARS[59] = 49; - CHARS[60] = 1; - CHARS[61] = 49; - CHARS[62] = 33; - Arrays.fill(CHARS, 63, 65, (byte) 49 ); // Fill 2 of value (byte) 49 - Arrays.fill(CHARS, 65, 91, (byte) -3 ); // Fill 26 of value (byte) -3 - Arrays.fill(CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[93] = 1; - CHARS[94] = 33; - CHARS[95] = -3; - CHARS[96] = 33; - Arrays.fill(CHARS, 97, 123, (byte) -3 ); // Fill 26 of value (byte) -3 - Arrays.fill(CHARS, 123, 183, (byte) 33 ); // Fill 60 of value (byte) 33 - CHARS[183] = -87; - Arrays.fill(CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33 - Arrays.fill(CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19 - CHARS[215] = 33; - Arrays.fill(CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19 - CHARS[247] = 33; - Arrays.fill(CHARS, 248, 306, (byte) -19 ); // Fill 58 of value (byte) -19 - Arrays.fill(CHARS, 306, 308, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 308, 319, (byte) -19 ); // Fill 11 of value (byte) -19 - Arrays.fill(CHARS, 319, 321, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 321, 329, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[329] = 33; - Arrays.fill(CHARS, 330, 383, (byte) -19 ); // Fill 53 of value (byte) -19 - CHARS[383] = 33; - Arrays.fill(CHARS, 384, 452, (byte) -19 ); // Fill 68 of value (byte) -19 - Arrays.fill(CHARS, 452, 461, (byte) 33 ); // Fill 9 of value (byte) 33 - Arrays.fill(CHARS, 461, 497, (byte) -19 ); // Fill 36 of value (byte) -19 - Arrays.fill(CHARS, 497, 500, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 500, 502, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 502, 506, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 506, 536, (byte) -19 ); // Fill 30 of value (byte) -19 - Arrays.fill(CHARS, 536, 592, (byte) 33 ); // Fill 56 of value (byte) 33 - Arrays.fill(CHARS, 592, 681, (byte) -19 ); // Fill 89 of value (byte) -19 - Arrays.fill(CHARS, 681, 699, (byte) 33 ); // Fill 18 of value (byte) 33 - Arrays.fill(CHARS, 699, 706, (byte) -19 ); // Fill 7 of value (byte) -19 - Arrays.fill(CHARS, 706, 720, (byte) 33 ); // Fill 14 of value (byte) 33 - Arrays.fill(CHARS, 720, 722, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 722, 768, (byte) 33 ); // Fill 46 of value (byte) 33 - Arrays.fill(CHARS, 768, 838, (byte) -87 ); // Fill 70 of value (byte) -87 - Arrays.fill(CHARS, 838, 864, (byte) 33 ); // Fill 26 of value (byte) 33 - Arrays.fill(CHARS, 864, 866, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 866, 902, (byte) 33 ); // Fill 36 of value (byte) 33 - CHARS[902] = -19; - CHARS[903] = -87; - Arrays.fill(CHARS, 904, 907, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[907] = 33; - CHARS[908] = -19; - CHARS[909] = 33; - Arrays.fill(CHARS, 910, 930, (byte) -19 ); // Fill 20 of value (byte) -19 - CHARS[930] = 33; - Arrays.fill(CHARS, 931, 975, (byte) -19 ); // Fill 44 of value (byte) -19 - CHARS[975] = 33; - Arrays.fill(CHARS, 976, 983, (byte) -19 ); // Fill 7 of value (byte) -19 - Arrays.fill(CHARS, 983, 986, (byte) 33 ); // Fill 3 of value (byte) 33 - CHARS[986] = -19; - CHARS[987] = 33; - CHARS[988] = -19; - CHARS[989] = 33; - CHARS[990] = -19; - CHARS[991] = 33; - CHARS[992] = -19; - CHARS[993] = 33; - Arrays.fill(CHARS, 994, 1012, (byte) -19 ); // Fill 18 of value (byte) -19 - Arrays.fill(CHARS, 1012, 1025, (byte) 33 ); // Fill 13 of value (byte) 33 - Arrays.fill(CHARS, 1025, 1037, (byte) -19 ); // Fill 12 of value (byte) -19 - CHARS[1037] = 33; - Arrays.fill(CHARS, 1038, 1104, (byte) -19 ); // Fill 66 of value (byte) -19 - CHARS[1104] = 33; - Arrays.fill(CHARS, 1105, 1117, (byte) -19 ); // Fill 12 of value (byte) -19 - CHARS[1117] = 33; - Arrays.fill(CHARS, 1118, 1154, (byte) -19 ); // Fill 36 of value (byte) -19 - CHARS[1154] = 33; - Arrays.fill(CHARS, 1155, 1159, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 1159, 1168, (byte) 33 ); // Fill 9 of value (byte) 33 - Arrays.fill(CHARS, 1168, 1221, (byte) -19 ); // Fill 53 of value (byte) -19 - Arrays.fill(CHARS, 1221, 1223, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1223, 1225, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 1225, 1227, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1227, 1229, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 1229, 1232, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 1232, 1260, (byte) -19 ); // Fill 28 of value (byte) -19 - Arrays.fill(CHARS, 1260, 1262, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1262, 1270, (byte) -19 ); // Fill 8 of value (byte) -19 - Arrays.fill(CHARS, 1270, 1272, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1272, 1274, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 1274, 1329, (byte) 33 ); // Fill 55 of value (byte) 33 - Arrays.fill(CHARS, 1329, 1367, (byte) -19 ); // Fill 38 of value (byte) -19 - Arrays.fill(CHARS, 1367, 1369, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[1369] = -19; - Arrays.fill(CHARS, 1370, 1377, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 1377, 1415, (byte) -19 ); // Fill 38 of value (byte) -19 - Arrays.fill(CHARS, 1415, 1425, (byte) 33 ); // Fill 10 of value (byte) 33 - Arrays.fill(CHARS, 1425, 1442, (byte) -87 ); // Fill 17 of value (byte) -87 - CHARS[1442] = 33; - Arrays.fill(CHARS, 1443, 1466, (byte) -87 ); // Fill 23 of value (byte) -87 - CHARS[1466] = 33; - Arrays.fill(CHARS, 1467, 1470, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[1470] = 33; - CHARS[1471] = -87; - CHARS[1472] = 33; - Arrays.fill(CHARS, 1473, 1475, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[1475] = 33; - CHARS[1476] = -87; - Arrays.fill(CHARS, 1477, 1488, (byte) 33 ); // Fill 11 of value (byte) 33 - Arrays.fill(CHARS, 1488, 1515, (byte) -19 ); // Fill 27 of value (byte) -19 - Arrays.fill(CHARS, 1515, 1520, (byte) 33 ); // Fill 5 of value (byte) 33 - Arrays.fill(CHARS, 1520, 1523, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 1523, 1569, (byte) 33 ); // Fill 46 of value (byte) 33 - Arrays.fill(CHARS, 1569, 1595, (byte) -19 ); // Fill 26 of value (byte) -19 - Arrays.fill(CHARS, 1595, 1600, (byte) 33 ); // Fill 5 of value (byte) 33 - CHARS[1600] = -87; - Arrays.fill(CHARS, 1601, 1611, (byte) -19 ); // Fill 10 of value (byte) -19 - Arrays.fill(CHARS, 1611, 1619, (byte) -87 ); // Fill 8 of value (byte) -87 - Arrays.fill(CHARS, 1619, 1632, (byte) 33 ); // Fill 13 of value (byte) 33 - Arrays.fill(CHARS, 1632, 1642, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 1642, 1648, (byte) 33 ); // Fill 6 of value (byte) 33 - CHARS[1648] = -87; - Arrays.fill(CHARS, 1649, 1720, (byte) -19 ); // Fill 71 of value (byte) -19 - Arrays.fill(CHARS, 1720, 1722, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1722, 1727, (byte) -19 ); // Fill 5 of value (byte) -19 - CHARS[1727] = 33; - Arrays.fill(CHARS, 1728, 1743, (byte) -19 ); // Fill 15 of value (byte) -19 - CHARS[1743] = 33; - Arrays.fill(CHARS, 1744, 1748, (byte) -19 ); // Fill 4 of value (byte) -19 - CHARS[1748] = 33; - CHARS[1749] = -19; - Arrays.fill(CHARS, 1750, 1765, (byte) -87 ); // Fill 15 of value (byte) -87 - Arrays.fill(CHARS, 1765, 1767, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 1767, 1769, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[1769] = 33; - Arrays.fill(CHARS, 1770, 1774, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 1774, 1776, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 1776, 1786, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 1786, 2305, (byte) 33 ); // Fill 519 of value (byte) 33 - Arrays.fill(CHARS, 2305, 2308, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[2308] = 33; - Arrays.fill(CHARS, 2309, 2362, (byte) -19 ); // Fill 53 of value (byte) -19 - Arrays.fill(CHARS, 2362, 2364, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[2364] = -87; - CHARS[2365] = -19; - Arrays.fill(CHARS, 2366, 2382, (byte) -87 ); // Fill 16 of value (byte) -87 - Arrays.fill(CHARS, 2382, 2385, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2385, 2389, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 2389, 2392, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2392, 2402, (byte) -19 ); // Fill 10 of value (byte) -19 - Arrays.fill(CHARS, 2402, 2404, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2404, 2406, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2406, 2416, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 2416, 2433, (byte) 33 ); // Fill 17 of value (byte) 33 - Arrays.fill(CHARS, 2433, 2436, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[2436] = 33; - Arrays.fill(CHARS, 2437, 2445, (byte) -19 ); // Fill 8 of value (byte) -19 - Arrays.fill(CHARS, 2445, 2447, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2447, 2449, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2449, 2451, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2451, 2473, (byte) -19 ); // Fill 22 of value (byte) -19 - CHARS[2473] = 33; - Arrays.fill(CHARS, 2474, 2481, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[2481] = 33; - CHARS[2482] = -19; - Arrays.fill(CHARS, 2483, 2486, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2486, 2490, (byte) -19 ); // Fill 4 of value (byte) -19 - Arrays.fill(CHARS, 2490, 2492, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[2492] = -87; - CHARS[2493] = 33; - Arrays.fill(CHARS, 2494, 2501, (byte) -87 ); // Fill 7 of value (byte) -87 - Arrays.fill(CHARS, 2501, 2503, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2503, 2505, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2505, 2507, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2507, 2510, (byte) -87 ); // Fill 3 of value (byte) -87 - Arrays.fill(CHARS, 2510, 2519, (byte) 33 ); // Fill 9 of value (byte) 33 - CHARS[2519] = -87; - Arrays.fill(CHARS, 2520, 2524, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 2524, 2526, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2526] = 33; - Arrays.fill(CHARS, 2527, 2530, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 2530, 2532, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2532, 2534, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2534, 2544, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 2544, 2546, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2546, 2562, (byte) 33 ); // Fill 16 of value (byte) 33 - CHARS[2562] = -87; - Arrays.fill(CHARS, 2563, 2565, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2565, 2571, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 2571, 2575, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 2575, 2577, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2577, 2579, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2579, 2601, (byte) -19 ); // Fill 22 of value (byte) -19 - CHARS[2601] = 33; - Arrays.fill(CHARS, 2602, 2609, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[2609] = 33; - Arrays.fill(CHARS, 2610, 2612, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2612] = 33; - Arrays.fill(CHARS, 2613, 2615, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2615] = 33; - Arrays.fill(CHARS, 2616, 2618, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2618, 2620, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[2620] = -87; - CHARS[2621] = 33; - Arrays.fill(CHARS, 2622, 2627, (byte) -87 ); // Fill 5 of value (byte) -87 - Arrays.fill(CHARS, 2627, 2631, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 2631, 2633, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2633, 2635, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2635, 2638, (byte) -87 ); // Fill 3 of value (byte) -87 - Arrays.fill(CHARS, 2638, 2649, (byte) 33 ); // Fill 11 of value (byte) 33 - Arrays.fill(CHARS, 2649, 2653, (byte) -19 ); // Fill 4 of value (byte) -19 - CHARS[2653] = 33; - CHARS[2654] = -19; - Arrays.fill(CHARS, 2655, 2662, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 2662, 2674, (byte) -87 ); // Fill 12 of value (byte) -87 - Arrays.fill(CHARS, 2674, 2677, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 2677, 2689, (byte) 33 ); // Fill 12 of value (byte) 33 - Arrays.fill(CHARS, 2689, 2692, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[2692] = 33; - Arrays.fill(CHARS, 2693, 2700, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[2700] = 33; - CHARS[2701] = -19; - CHARS[2702] = 33; - Arrays.fill(CHARS, 2703, 2706, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[2706] = 33; - Arrays.fill(CHARS, 2707, 2729, (byte) -19 ); // Fill 22 of value (byte) -19 - CHARS[2729] = 33; - Arrays.fill(CHARS, 2730, 2737, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[2737] = 33; - Arrays.fill(CHARS, 2738, 2740, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2740] = 33; - Arrays.fill(CHARS, 2741, 2746, (byte) -19 ); // Fill 5 of value (byte) -19 - Arrays.fill(CHARS, 2746, 2748, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[2748] = -87; - CHARS[2749] = -19; - Arrays.fill(CHARS, 2750, 2758, (byte) -87 ); // Fill 8 of value (byte) -87 - CHARS[2758] = 33; - Arrays.fill(CHARS, 2759, 2762, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[2762] = 33; - Arrays.fill(CHARS, 2763, 2766, (byte) -87 ); // Fill 3 of value (byte) -87 - Arrays.fill(CHARS, 2766, 2784, (byte) 33 ); // Fill 18 of value (byte) 33 - CHARS[2784] = -19; - Arrays.fill(CHARS, 2785, 2790, (byte) 33 ); // Fill 5 of value (byte) 33 - Arrays.fill(CHARS, 2790, 2800, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 2800, 2817, (byte) 33 ); // Fill 17 of value (byte) 33 - Arrays.fill(CHARS, 2817, 2820, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[2820] = 33; - Arrays.fill(CHARS, 2821, 2829, (byte) -19 ); // Fill 8 of value (byte) -19 - Arrays.fill(CHARS, 2829, 2831, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2831, 2833, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2833, 2835, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2835, 2857, (byte) -19 ); // Fill 22 of value (byte) -19 - CHARS[2857] = 33; - Arrays.fill(CHARS, 2858, 2865, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[2865] = 33; - Arrays.fill(CHARS, 2866, 2868, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2868, 2870, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2870, 2874, (byte) -19 ); // Fill 4 of value (byte) -19 - Arrays.fill(CHARS, 2874, 2876, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[2876] = -87; - CHARS[2877] = -19; - Arrays.fill(CHARS, 2878, 2884, (byte) -87 ); // Fill 6 of value (byte) -87 - Arrays.fill(CHARS, 2884, 2887, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2887, 2889, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2889, 2891, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 2891, 2894, (byte) -87 ); // Fill 3 of value (byte) -87 - Arrays.fill(CHARS, 2894, 2902, (byte) 33 ); // Fill 8 of value (byte) 33 - Arrays.fill(CHARS, 2902, 2904, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 2904, 2908, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 2908, 2910, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2910] = 33; - Arrays.fill(CHARS, 2911, 2914, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 2914, 2918, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 2918, 2928, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 2928, 2946, (byte) 33 ); // Fill 18 of value (byte) 33 - Arrays.fill(CHARS, 2946, 2948, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[2948] = 33; - Arrays.fill(CHARS, 2949, 2955, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 2955, 2958, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2958, 2961, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[2961] = 33; - Arrays.fill(CHARS, 2962, 2966, (byte) -19 ); // Fill 4 of value (byte) -19 - Arrays.fill(CHARS, 2966, 2969, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2969, 2971, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[2971] = 33; - CHARS[2972] = -19; - CHARS[2973] = 33; - Arrays.fill(CHARS, 2974, 2976, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2976, 2979, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2979, 2981, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 2981, 2984, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2984, 2987, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 2987, 2990, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 2990, 2998, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[2998] = 33; - Arrays.fill(CHARS, 2999, 3002, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 3002, 3006, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3006, 3011, (byte) -87 ); // Fill 5 of value (byte) -87 - Arrays.fill(CHARS, 3011, 3014, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 3014, 3017, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[3017] = 33; - Arrays.fill(CHARS, 3018, 3022, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 3022, 3031, (byte) 33 ); // Fill 9 of value (byte) 33 - CHARS[3031] = -87; - Arrays.fill(CHARS, 3032, 3047, (byte) 33 ); // Fill 15 of value (byte) 33 - Arrays.fill(CHARS, 3047, 3056, (byte) -87 ); // Fill 9 of value (byte) -87 - Arrays.fill(CHARS, 3056, 3073, (byte) 33 ); // Fill 17 of value (byte) 33 - Arrays.fill(CHARS, 3073, 3076, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[3076] = 33; - Arrays.fill(CHARS, 3077, 3085, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[3085] = 33; - Arrays.fill(CHARS, 3086, 3089, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[3089] = 33; - Arrays.fill(CHARS, 3090, 3113, (byte) -19 ); // Fill 23 of value (byte) -19 - CHARS[3113] = 33; - Arrays.fill(CHARS, 3114, 3124, (byte) -19 ); // Fill 10 of value (byte) -19 - CHARS[3124] = 33; - Arrays.fill(CHARS, 3125, 3130, (byte) -19 ); // Fill 5 of value (byte) -19 - Arrays.fill(CHARS, 3130, 3134, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3134, 3141, (byte) -87 ); // Fill 7 of value (byte) -87 - CHARS[3141] = 33; - Arrays.fill(CHARS, 3142, 3145, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[3145] = 33; - Arrays.fill(CHARS, 3146, 3150, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 3150, 3157, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 3157, 3159, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 3159, 3168, (byte) 33 ); // Fill 9 of value (byte) 33 - Arrays.fill(CHARS, 3168, 3170, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 3170, 3174, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3174, 3184, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3184, 3202, (byte) 33 ); // Fill 18 of value (byte) 33 - Arrays.fill(CHARS, 3202, 3204, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[3204] = 33; - Arrays.fill(CHARS, 3205, 3213, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[3213] = 33; - Arrays.fill(CHARS, 3214, 3217, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[3217] = 33; - Arrays.fill(CHARS, 3218, 3241, (byte) -19 ); // Fill 23 of value (byte) -19 - CHARS[3241] = 33; - Arrays.fill(CHARS, 3242, 3252, (byte) -19 ); // Fill 10 of value (byte) -19 - CHARS[3252] = 33; - Arrays.fill(CHARS, 3253, 3258, (byte) -19 ); // Fill 5 of value (byte) -19 - Arrays.fill(CHARS, 3258, 3262, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3262, 3269, (byte) -87 ); // Fill 7 of value (byte) -87 - CHARS[3269] = 33; - Arrays.fill(CHARS, 3270, 3273, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[3273] = 33; - Arrays.fill(CHARS, 3274, 3278, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 3278, 3285, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 3285, 3287, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 3287, 3294, (byte) 33 ); // Fill 7 of value (byte) 33 - CHARS[3294] = -19; - CHARS[3295] = 33; - Arrays.fill(CHARS, 3296, 3298, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 3298, 3302, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3302, 3312, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3312, 3330, (byte) 33 ); // Fill 18 of value (byte) 33 - Arrays.fill(CHARS, 3330, 3332, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[3332] = 33; - Arrays.fill(CHARS, 3333, 3341, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[3341] = 33; - Arrays.fill(CHARS, 3342, 3345, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[3345] = 33; - Arrays.fill(CHARS, 3346, 3369, (byte) -19 ); // Fill 23 of value (byte) -19 - CHARS[3369] = 33; - Arrays.fill(CHARS, 3370, 3386, (byte) -19 ); // Fill 16 of value (byte) -19 - Arrays.fill(CHARS, 3386, 3390, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3390, 3396, (byte) -87 ); // Fill 6 of value (byte) -87 - Arrays.fill(CHARS, 3396, 3398, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 3398, 3401, (byte) -87 ); // Fill 3 of value (byte) -87 - CHARS[3401] = 33; - Arrays.fill(CHARS, 3402, 3406, (byte) -87 ); // Fill 4 of value (byte) -87 - Arrays.fill(CHARS, 3406, 3415, (byte) 33 ); // Fill 9 of value (byte) 33 - CHARS[3415] = -87; - Arrays.fill(CHARS, 3416, 3424, (byte) 33 ); // Fill 8 of value (byte) 33 - Arrays.fill(CHARS, 3424, 3426, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 3426, 3430, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3430, 3440, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3440, 3585, (byte) 33 ); // Fill 145 of value (byte) 33 - Arrays.fill(CHARS, 3585, 3631, (byte) -19 ); // Fill 46 of value (byte) -19 - CHARS[3631] = 33; - CHARS[3632] = -19; - CHARS[3633] = -87; - Arrays.fill(CHARS, 3634, 3636, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 3636, 3643, (byte) -87 ); // Fill 7 of value (byte) -87 - Arrays.fill(CHARS, 3643, 3648, (byte) 33 ); // Fill 5 of value (byte) 33 - Arrays.fill(CHARS, 3648, 3654, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 3654, 3663, (byte) -87 ); // Fill 9 of value (byte) -87 - CHARS[3663] = 33; - Arrays.fill(CHARS, 3664, 3674, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3674, 3713, (byte) 33 ); // Fill 39 of value (byte) 33 - Arrays.fill(CHARS, 3713, 3715, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[3715] = 33; - CHARS[3716] = -19; - Arrays.fill(CHARS, 3717, 3719, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 3719, 3721, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[3721] = 33; - CHARS[3722] = -19; - Arrays.fill(CHARS, 3723, 3725, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[3725] = -19; - Arrays.fill(CHARS, 3726, 3732, (byte) 33 ); // Fill 6 of value (byte) 33 - Arrays.fill(CHARS, 3732, 3736, (byte) -19 ); // Fill 4 of value (byte) -19 - CHARS[3736] = 33; - Arrays.fill(CHARS, 3737, 3744, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[3744] = 33; - Arrays.fill(CHARS, 3745, 3748, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[3748] = 33; - CHARS[3749] = -19; - CHARS[3750] = 33; - CHARS[3751] = -19; - Arrays.fill(CHARS, 3752, 3754, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 3754, 3756, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[3756] = 33; - Arrays.fill(CHARS, 3757, 3759, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[3759] = 33; - CHARS[3760] = -19; - CHARS[3761] = -87; - Arrays.fill(CHARS, 3762, 3764, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 3764, 3770, (byte) -87 ); // Fill 6 of value (byte) -87 - CHARS[3770] = 33; - Arrays.fill(CHARS, 3771, 3773, (byte) -87 ); // Fill 2 of value (byte) -87 - CHARS[3773] = -19; - Arrays.fill(CHARS, 3774, 3776, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 3776, 3781, (byte) -19 ); // Fill 5 of value (byte) -19 - CHARS[3781] = 33; - CHARS[3782] = -87; - CHARS[3783] = 33; - Arrays.fill(CHARS, 3784, 3790, (byte) -87 ); // Fill 6 of value (byte) -87 - Arrays.fill(CHARS, 3790, 3792, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 3792, 3802, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3802, 3864, (byte) 33 ); // Fill 62 of value (byte) 33 - Arrays.fill(CHARS, 3864, 3866, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 3866, 3872, (byte) 33 ); // Fill 6 of value (byte) 33 - Arrays.fill(CHARS, 3872, 3882, (byte) -87 ); // Fill 10 of value (byte) -87 - Arrays.fill(CHARS, 3882, 3893, (byte) 33 ); // Fill 11 of value (byte) 33 - CHARS[3893] = -87; - CHARS[3894] = 33; - CHARS[3895] = -87; - CHARS[3896] = 33; - CHARS[3897] = -87; - Arrays.fill(CHARS, 3898, 3902, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3902, 3904, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 3904, 3912, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[3912] = 33; - Arrays.fill(CHARS, 3913, 3946, (byte) -19 ); // Fill 33 of value (byte) -19 - Arrays.fill(CHARS, 3946, 3953, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 3953, 3973, (byte) -87 ); // Fill 20 of value (byte) -87 - CHARS[3973] = 33; - Arrays.fill(CHARS, 3974, 3980, (byte) -87 ); // Fill 6 of value (byte) -87 - Arrays.fill(CHARS, 3980, 3984, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 3984, 3990, (byte) -87 ); // Fill 6 of value (byte) -87 - CHARS[3990] = 33; - CHARS[3991] = -87; - CHARS[3992] = 33; - Arrays.fill(CHARS, 3993, 4014, (byte) -87 ); // Fill 21 of value (byte) -87 - Arrays.fill(CHARS, 4014, 4017, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 4017, 4024, (byte) -87 ); // Fill 7 of value (byte) -87 - CHARS[4024] = 33; - CHARS[4025] = -87; - Arrays.fill(CHARS, 4026, 4256, (byte) 33 ); // Fill 230 of value (byte) 33 - Arrays.fill(CHARS, 4256, 4294, (byte) -19 ); // Fill 38 of value (byte) -19 - Arrays.fill(CHARS, 4294, 4304, (byte) 33 ); // Fill 10 of value (byte) 33 - Arrays.fill(CHARS, 4304, 4343, (byte) -19 ); // Fill 39 of value (byte) -19 - Arrays.fill(CHARS, 4343, 4352, (byte) 33 ); // Fill 9 of value (byte) 33 - CHARS[4352] = -19; - CHARS[4353] = 33; - Arrays.fill(CHARS, 4354, 4356, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[4356] = 33; - Arrays.fill(CHARS, 4357, 4360, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[4360] = 33; - CHARS[4361] = -19; - CHARS[4362] = 33; - Arrays.fill(CHARS, 4363, 4365, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[4365] = 33; - Arrays.fill(CHARS, 4366, 4371, (byte) -19 ); // Fill 5 of value (byte) -19 - Arrays.fill(CHARS, 4371, 4412, (byte) 33 ); // Fill 41 of value (byte) 33 - CHARS[4412] = -19; - CHARS[4413] = 33; - CHARS[4414] = -19; - CHARS[4415] = 33; - CHARS[4416] = -19; - Arrays.fill(CHARS, 4417, 4428, (byte) 33 ); // Fill 11 of value (byte) 33 - CHARS[4428] = -19; - CHARS[4429] = 33; - CHARS[4430] = -19; - CHARS[4431] = 33; - CHARS[4432] = -19; - Arrays.fill(CHARS, 4433, 4436, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 4436, 4438, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 4438, 4441, (byte) 33 ); // Fill 3 of value (byte) 33 - CHARS[4441] = -19; - Arrays.fill(CHARS, 4442, 4447, (byte) 33 ); // Fill 5 of value (byte) 33 - Arrays.fill(CHARS, 4447, 4450, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[4450] = 33; - CHARS[4451] = -19; - CHARS[4452] = 33; - CHARS[4453] = -19; - CHARS[4454] = 33; - CHARS[4455] = -19; - CHARS[4456] = 33; - CHARS[4457] = -19; - Arrays.fill(CHARS, 4458, 4461, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 4461, 4463, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 4463, 4466, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 4466, 4468, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[4468] = 33; - CHARS[4469] = -19; - Arrays.fill(CHARS, 4470, 4510, (byte) 33 ); // Fill 40 of value (byte) 33 - CHARS[4510] = -19; - Arrays.fill(CHARS, 4511, 4520, (byte) 33 ); // Fill 9 of value (byte) 33 - CHARS[4520] = -19; - Arrays.fill(CHARS, 4521, 4523, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[4523] = -19; - Arrays.fill(CHARS, 4524, 4526, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 4526, 4528, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 4528, 4535, (byte) 33 ); // Fill 7 of value (byte) 33 - Arrays.fill(CHARS, 4535, 4537, (byte) -19 ); // Fill 2 of value (byte) -19 - CHARS[4537] = 33; - CHARS[4538] = -19; - CHARS[4539] = 33; - Arrays.fill(CHARS, 4540, 4547, (byte) -19 ); // Fill 7 of value (byte) -19 - Arrays.fill(CHARS, 4547, 4587, (byte) 33 ); // Fill 40 of value (byte) 33 - CHARS[4587] = -19; - Arrays.fill(CHARS, 4588, 4592, (byte) 33 ); // Fill 4 of value (byte) 33 - CHARS[4592] = -19; - Arrays.fill(CHARS, 4593, 4601, (byte) 33 ); // Fill 8 of value (byte) 33 - CHARS[4601] = -19; - Arrays.fill(CHARS, 4602, 7680, (byte) 33 ); // Fill 3078 of value (byte) 33 - Arrays.fill(CHARS, 7680, 7836, (byte) -19 ); // Fill 156 of value (byte) -19 - Arrays.fill(CHARS, 7836, 7840, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 7840, 7930, (byte) -19 ); // Fill 90 of value (byte) -19 - Arrays.fill(CHARS, 7930, 7936, (byte) 33 ); // Fill 6 of value (byte) 33 - Arrays.fill(CHARS, 7936, 7958, (byte) -19 ); // Fill 22 of value (byte) -19 - Arrays.fill(CHARS, 7958, 7960, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 7960, 7966, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 7966, 7968, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 7968, 8006, (byte) -19 ); // Fill 38 of value (byte) -19 - Arrays.fill(CHARS, 8006, 8008, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 8008, 8014, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 8014, 8016, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 8016, 8024, (byte) -19 ); // Fill 8 of value (byte) -19 - CHARS[8024] = 33; - CHARS[8025] = -19; - CHARS[8026] = 33; - CHARS[8027] = -19; - CHARS[8028] = 33; - CHARS[8029] = -19; - CHARS[8030] = 33; - Arrays.fill(CHARS, 8031, 8062, (byte) -19 ); // Fill 31 of value (byte) -19 - Arrays.fill(CHARS, 8062, 8064, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 8064, 8117, (byte) -19 ); // Fill 53 of value (byte) -19 - CHARS[8117] = 33; - Arrays.fill(CHARS, 8118, 8125, (byte) -19 ); // Fill 7 of value (byte) -19 - CHARS[8125] = 33; - CHARS[8126] = -19; - Arrays.fill(CHARS, 8127, 8130, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 8130, 8133, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[8133] = 33; - Arrays.fill(CHARS, 8134, 8141, (byte) -19 ); // Fill 7 of value (byte) -19 - Arrays.fill(CHARS, 8141, 8144, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 8144, 8148, (byte) -19 ); // Fill 4 of value (byte) -19 - Arrays.fill(CHARS, 8148, 8150, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 8150, 8156, (byte) -19 ); // Fill 6 of value (byte) -19 - Arrays.fill(CHARS, 8156, 8160, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 8160, 8173, (byte) -19 ); // Fill 13 of value (byte) -19 - Arrays.fill(CHARS, 8173, 8178, (byte) 33 ); // Fill 5 of value (byte) 33 - Arrays.fill(CHARS, 8178, 8181, (byte) -19 ); // Fill 3 of value (byte) -19 - CHARS[8181] = 33; - Arrays.fill(CHARS, 8182, 8189, (byte) -19 ); // Fill 7 of value (byte) -19 - Arrays.fill(CHARS, 8189, 8400, (byte) 33 ); // Fill 211 of value (byte) 33 - Arrays.fill(CHARS, 8400, 8413, (byte) -87 ); // Fill 13 of value (byte) -87 - Arrays.fill(CHARS, 8413, 8417, (byte) 33 ); // Fill 4 of value (byte) 33 - CHARS[8417] = -87; - Arrays.fill(CHARS, 8418, 8486, (byte) 33 ); // Fill 68 of value (byte) 33 - CHARS[8486] = -19; - Arrays.fill(CHARS, 8487, 8490, (byte) 33 ); // Fill 3 of value (byte) 33 - Arrays.fill(CHARS, 8490, 8492, (byte) -19 ); // Fill 2 of value (byte) -19 - Arrays.fill(CHARS, 8492, 8494, (byte) 33 ); // Fill 2 of value (byte) 33 - CHARS[8494] = -19; - Arrays.fill(CHARS, 8495, 8576, (byte) 33 ); // Fill 81 of value (byte) 33 - Arrays.fill(CHARS, 8576, 8579, (byte) -19 ); // Fill 3 of value (byte) -19 - Arrays.fill(CHARS, 8579, 12293, (byte) 33 ); // Fill 3714 of value (byte) 33 - CHARS[12293] = -87; - CHARS[12294] = 33; - CHARS[12295] = -19; - Arrays.fill(CHARS, 12296, 12321, (byte) 33 ); // Fill 25 of value (byte) 33 - Arrays.fill(CHARS, 12321, 12330, (byte) -19 ); // Fill 9 of value (byte) -19 - Arrays.fill(CHARS, 12330, 12336, (byte) -87 ); // Fill 6 of value (byte) -87 - CHARS[12336] = 33; - Arrays.fill(CHARS, 12337, 12342, (byte) -87 ); // Fill 5 of value (byte) -87 - Arrays.fill(CHARS, 12342, 12353, (byte) 33 ); // Fill 11 of value (byte) 33 - Arrays.fill(CHARS, 12353, 12437, (byte) -19 ); // Fill 84 of value (byte) -19 - Arrays.fill(CHARS, 12437, 12441, (byte) 33 ); // Fill 4 of value (byte) 33 - Arrays.fill(CHARS, 12441, 12443, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 12443, 12445, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 12445, 12447, (byte) -87 ); // Fill 2 of value (byte) -87 - Arrays.fill(CHARS, 12447, 12449, (byte) 33 ); // Fill 2 of value (byte) 33 - Arrays.fill(CHARS, 12449, 12539, (byte) -19 ); // Fill 90 of value (byte) -19 - CHARS[12539] = 33; - Arrays.fill(CHARS, 12540, 12543, (byte) -87 ); // Fill 3 of value (byte) -87 - Arrays.fill(CHARS, 12543, 12549, (byte) 33 ); // Fill 6 of value (byte) 33 - Arrays.fill(CHARS, 12549, 12589, (byte) -19 ); // Fill 40 of value (byte) -19 - Arrays.fill(CHARS, 12589, 19968, (byte) 33 ); // Fill 7379 of value (byte) 33 - Arrays.fill(CHARS, 19968, 40870, (byte) -19 ); // Fill 20902 of value (byte) -19 - Arrays.fill(CHARS, 40870, 44032, (byte) 33 ); // Fill 3162 of value (byte) 33 - Arrays.fill(CHARS, 44032, 55204, (byte) -19 ); // Fill 11172 of value (byte) -19 - Arrays.fill(CHARS, 55204, 55296, (byte) 33 ); // Fill 92 of value (byte) 33 - Arrays.fill(CHARS, 57344, 65534, (byte) 33 ); // Fill 8190 of value (byte) 33 - - } // () - - // - // Public static methods - // - - /** - * Returns true if the specified character is a supplemental character. - * - * @param c The character to check. - */ - public static boolean isSupplemental(int c) { - return (c >= 0x10000 && c <= 0x10FFFF); - } - - /** - * Returns true the supplemental character corresponding to the given - * surrogates. - * - * @param h The high surrogate. - * @param l The low surrogate. - */ - public static int supplemental(char h, char l) { - return (h - 0xD800) * 0x400 + (l - 0xDC00) + 0x10000; - } - - /** - * Returns the high surrogate of a supplemental character - * - * @param c The supplemental character to "split". - */ - public static char highSurrogate(int c) { - return (char) (((c - 0x00010000) >> 10) + 0xD800); - } - - /** - * Returns the low surrogate of a supplemental character - * - * @param c The supplemental character to "split". - */ - public static char lowSurrogate(int c) { - return (char) (((c - 0x00010000) & 0x3FF) + 0xDC00); - } - - /** - * Returns whether the given character is a high surrogate - * - * @param c The character to check. - */ - public static boolean isHighSurrogate(int c) { - return (0xD800 <= c && c <= 0xDBFF); - } - - /** - * Returns whether the given character is a low surrogate - * - * @param c The character to check. - */ - public static boolean isLowSurrogate(int c) { - return (0xDC00 <= c && c <= 0xDFFF); - } - - - /** - * Returns true if the specified character is valid. This method - * also checks the surrogate character range from 0x10000 to 0x10FFFF. - *

        - * If the program chooses to apply the mask directly to the - * CHARS array, then they are responsible for checking - * the surrogate character range. - * - * @param c The character to check. - */ - public static boolean isValid(int c) { - return (c < 0x10000 && (CHARS[c] & MASK_VALID) != 0) || - (0x10000 <= c && c <= 0x10FFFF); - } // isValid(int):boolean - - /** - * Returns true if the specified character is invalid. - * - * @param c The character to check. - */ - public static boolean isInvalid(int c) { - return !isValid(c); - } // isInvalid(int):boolean - - /** - * Returns true if the specified character can be considered content. - * - * @param c The character to check. - */ - public static boolean isContent(int c) { - return (c < 0x10000 && (CHARS[c] & MASK_CONTENT) != 0) || - (0x10000 <= c && c <= 0x10FFFF); - } // isContent(int):boolean - - /** - * Returns true if the specified character can be considered markup. - * Markup characters include '<', '&', and '%'. - * - * @param c The character to check. - */ - public static boolean isMarkup(int c) { - return c == '<' || c == '&' || c == '%'; - } // isMarkup(int):boolean - - /** - * Returns true if the specified character is a space character - * as defined by production [3] in the XML 1.0 specification. - * - * @param c The character to check. - */ - public static boolean isSpace(int c) { - return c <= 0x20 && (CHARS[c] & MASK_SPACE) != 0; - } // isSpace(int):boolean - - /** - * Returns true if the specified character is a valid name start - * character as defined by production [5] in the XML 1.0 - * specification. - * - * @param c The character to check. - */ - public static boolean isNameStart(int c) { - return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0; - } // isNameStart(int):boolean - - /** - * Returns true if the specified character is a valid name - * character as defined by production [4] in the XML 1.0 - * specification. - * - * @param c The character to check. - */ - public static boolean isName(int c) { - return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0; - } // isName(int):boolean - - /** - * Returns true if the specified character is a valid NCName start - * character as defined by production [4] in Namespaces in XML - * recommendation. - * - * @param c The character to check. - */ - public static boolean isNCNameStart(int c) { - return c < 0x10000 && (CHARS[c] & MASK_NCNAME_START) != 0; - } // isNCNameStart(int):boolean - - /** - * Returns true if the specified character is a valid NCName - * character as defined by production [5] in Namespaces in XML - * recommendation. - * - * @param c The character to check. - */ - public static boolean isNCName(int c) { - return c < 0x10000 && (CHARS[c] & MASK_NCNAME) != 0; - } // isNCName(int):boolean - - /** - * Returns true if the specified character is a valid Pubid - * character as defined by production [13] in the XML 1.0 - * specification. - * - * @param c The character to check. - */ - public static boolean isPubid(int c) { - return c < 0x10000 && (CHARS[c] & MASK_PUBID) != 0; - } // isPubid(int):boolean - - /* - * [5] Name ::= (Letter | '_' | ':') (NameChar)* - */ - /** - * Check to see if a string is a valid Name according to [5] - * in the XML 1.0 Recommendation - * - * @param name string to check - * @return true if name is a valid Name - */ - public static boolean isValidName(String name) { - if (name.length() == 0) - return false; - char ch = name.charAt(0); - if( isNameStart(ch) == false) - return false; - for (int i = 1; i < name.length(); i++ ) { - ch = name.charAt(i); - if( isName( ch ) == false ){ - return false; - } - } - return true; - } // isValidName(String):boolean - - - /* - * from the namespace rec - * [4] NCName ::= (Letter | '_') (NCNameChar)* - */ - /** - * Check to see if a string is a valid NCName according to [4] - * from the XML Namespaces 1.0 Recommendation - * - * @param ncName string to check - * @return true if name is a valid NCName - */ - public static boolean isValidNCName(String ncName) { - if (ncName.length() == 0) - return false; - char ch = ncName.charAt(0); - if( isNCNameStart(ch) == false) - return false; - for (int i = 1; i < ncName.length(); i++ ) { - ch = ncName.charAt(i); - if( isNCName( ch ) == false ){ - return false; - } - } - return true; - } // isValidNCName(String):boolean - - /* - * [7] Nmtoken ::= (NameChar)+ - */ - /** - * Check to see if a string is a valid Nmtoken according to [7] - * in the XML 1.0 Recommendation - * - * @param nmtoken string to check - * @return true if nmtoken is a valid Nmtoken - */ - public static boolean isValidNmtoken(String nmtoken) { - if (nmtoken.length() == 0) - return false; - for (int i = 0; i < nmtoken.length(); i++ ) { - char ch = nmtoken.charAt(i); - if( ! isName( ch ) ){ - return false; - } - } - return true; - } // isValidName(String):boolean - - - - - - // encodings - - /** - * Returns true if the encoding name is a valid IANA encoding. - * This method does not verify that there is a decoder available - * for this encoding, only that the characters are valid for an - * IANA encoding name. - * - * @param ianaEncoding The IANA encoding name. - */ - public static boolean isValidIANAEncoding(String ianaEncoding) { - if (ianaEncoding != null) { - int length = ianaEncoding.length(); - if (length > 0) { - char c = ianaEncoding.charAt(0); - if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { - for (int i = 1; i < length; i++) { - c = ianaEncoding.charAt(i); - if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && - (c < '0' || c > '9') && c != '.' && c != '_' && - c != '-') { - return false; - } - } - return true; - } - } - } - return false; - } // isValidIANAEncoding(String):boolean - - /** - * Returns true if the encoding name is a valid Java encoding. - * This method does not verify that there is a decoder available - * for this encoding, only that the characters are valid for an - * Java encoding name. - * - * @param javaEncoding The Java encoding name. - */ - public static boolean isValidJavaEncoding(String javaEncoding) { - if (javaEncoding != null) { - int length = javaEncoding.length(); - if (length > 0) { - for (int i = 1; i < length; i++) { - char c = javaEncoding.charAt(i); - if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && - (c < '0' || c > '9') && c != '.' && c != '_' && - c != '-') { - return false; - } - } - return true; - } - } - return false; - } // isValidIANAEncoding(String):boolean - - -} // class XMLChar +/* + * Copyright 1999,2004-2005 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +import java.util.Arrays; + +/** + * This class defines the basic XML character properties. The data + * in this class can be used to verify that a character is a valid + * XML character or if the character is a space, name start, or name + * character. + *

        + * A series of convenience methods are supplied to ease the burden + * of the developer. Because inlining the checks can improve per + * character performance, the tables of character properties are + * public. Using the character as an index into the CHARS + * array and applying the appropriate mask flag (e.g. + * MASK_VALID), yields the same results as calling the + * convenience methods. There is one exception: check the comments + * for the isValid method for details. + * + * @author Glenn Marcy, IBM + * @author Andy Clark, IBM + * @author Eric Ye, IBM + * @author Arnaud Le Hors, IBM + * @author Michael Glavassevich, IBM + * @author Rahul Srivastava, Sun Microsystems Inc. + * + * @version $Id: XMLChar.java 306179 2005-07-27 15:12:04Z yoavs $ + */ +public class XMLChar { + + // + // Constants + // + + /** Character flags. */ + private static final byte[] CHARS = new byte[1 << 16]; + + /** Valid character mask. */ + public static final int MASK_VALID = 0x01; + + /** Space character mask. */ + public static final int MASK_SPACE = 0x02; + + /** Name start character mask. */ + public static final int MASK_NAME_START = 0x04; + + /** Name character mask. */ + public static final int MASK_NAME = 0x08; + + /** Pubid character mask. */ + public static final int MASK_PUBID = 0x10; + + /** + * Content character mask. Special characters are those that can + * be considered the start of markup, such as '<' and '&'. + * The various newline characters are considered special as well. + * All other valid XML characters can be considered content. + *

        + * This is an optimization for the inner loop of character scanning. + */ + public static final int MASK_CONTENT = 0x20; + + /** NCName start character mask. */ + public static final int MASK_NCNAME_START = 0x40; + + /** NCName character mask. */ + public static final int MASK_NCNAME = 0x80; + + // + // Static initialization + // + + static { + + // Initializing the Character Flag Array + // Code generated by: XMLCharGenerator. + + CHARS[9] = 35; + CHARS[10] = 19; + CHARS[13] = 19; + CHARS[32] = 51; + CHARS[33] = 49; + CHARS[34] = 33; + Arrays.fill(CHARS, 35, 38, (byte) 49 ); // Fill 3 of value (byte) 49 + CHARS[38] = 1; + Arrays.fill(CHARS, 39, 45, (byte) 49 ); // Fill 6 of value (byte) 49 + Arrays.fill(CHARS, 45, 47, (byte) -71 ); // Fill 2 of value (byte) -71 + CHARS[47] = 49; + Arrays.fill(CHARS, 48, 58, (byte) -71 ); // Fill 10 of value (byte) -71 + CHARS[58] = 61; + CHARS[59] = 49; + CHARS[60] = 1; + CHARS[61] = 49; + CHARS[62] = 33; + Arrays.fill(CHARS, 63, 65, (byte) 49 ); // Fill 2 of value (byte) 49 + Arrays.fill(CHARS, 65, 91, (byte) -3 ); // Fill 26 of value (byte) -3 + Arrays.fill(CHARS, 91, 93, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[93] = 1; + CHARS[94] = 33; + CHARS[95] = -3; + CHARS[96] = 33; + Arrays.fill(CHARS, 97, 123, (byte) -3 ); // Fill 26 of value (byte) -3 + Arrays.fill(CHARS, 123, 183, (byte) 33 ); // Fill 60 of value (byte) 33 + CHARS[183] = -87; + Arrays.fill(CHARS, 184, 192, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 192, 215, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[215] = 33; + Arrays.fill(CHARS, 216, 247, (byte) -19 ); // Fill 31 of value (byte) -19 + CHARS[247] = 33; + Arrays.fill(CHARS, 248, 306, (byte) -19 ); // Fill 58 of value (byte) -19 + Arrays.fill(CHARS, 306, 308, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 308, 319, (byte) -19 ); // Fill 11 of value (byte) -19 + Arrays.fill(CHARS, 319, 321, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 321, 329, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[329] = 33; + Arrays.fill(CHARS, 330, 383, (byte) -19 ); // Fill 53 of value (byte) -19 + CHARS[383] = 33; + Arrays.fill(CHARS, 384, 452, (byte) -19 ); // Fill 68 of value (byte) -19 + Arrays.fill(CHARS, 452, 461, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 461, 497, (byte) -19 ); // Fill 36 of value (byte) -19 + Arrays.fill(CHARS, 497, 500, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 500, 502, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 502, 506, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 506, 536, (byte) -19 ); // Fill 30 of value (byte) -19 + Arrays.fill(CHARS, 536, 592, (byte) 33 ); // Fill 56 of value (byte) 33 + Arrays.fill(CHARS, 592, 681, (byte) -19 ); // Fill 89 of value (byte) -19 + Arrays.fill(CHARS, 681, 699, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 699, 706, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 706, 720, (byte) 33 ); // Fill 14 of value (byte) 33 + Arrays.fill(CHARS, 720, 722, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 722, 768, (byte) 33 ); // Fill 46 of value (byte) 33 + Arrays.fill(CHARS, 768, 838, (byte) -87 ); // Fill 70 of value (byte) -87 + Arrays.fill(CHARS, 838, 864, (byte) 33 ); // Fill 26 of value (byte) 33 + Arrays.fill(CHARS, 864, 866, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 866, 902, (byte) 33 ); // Fill 36 of value (byte) 33 + CHARS[902] = -19; + CHARS[903] = -87; + Arrays.fill(CHARS, 904, 907, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[907] = 33; + CHARS[908] = -19; + CHARS[909] = 33; + Arrays.fill(CHARS, 910, 930, (byte) -19 ); // Fill 20 of value (byte) -19 + CHARS[930] = 33; + Arrays.fill(CHARS, 931, 975, (byte) -19 ); // Fill 44 of value (byte) -19 + CHARS[975] = 33; + Arrays.fill(CHARS, 976, 983, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 983, 986, (byte) 33 ); // Fill 3 of value (byte) 33 + CHARS[986] = -19; + CHARS[987] = 33; + CHARS[988] = -19; + CHARS[989] = 33; + CHARS[990] = -19; + CHARS[991] = 33; + CHARS[992] = -19; + CHARS[993] = 33; + Arrays.fill(CHARS, 994, 1012, (byte) -19 ); // Fill 18 of value (byte) -19 + Arrays.fill(CHARS, 1012, 1025, (byte) 33 ); // Fill 13 of value (byte) 33 + Arrays.fill(CHARS, 1025, 1037, (byte) -19 ); // Fill 12 of value (byte) -19 + CHARS[1037] = 33; + Arrays.fill(CHARS, 1038, 1104, (byte) -19 ); // Fill 66 of value (byte) -19 + CHARS[1104] = 33; + Arrays.fill(CHARS, 1105, 1117, (byte) -19 ); // Fill 12 of value (byte) -19 + CHARS[1117] = 33; + Arrays.fill(CHARS, 1118, 1154, (byte) -19 ); // Fill 36 of value (byte) -19 + CHARS[1154] = 33; + Arrays.fill(CHARS, 1155, 1159, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 1159, 1168, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 1168, 1221, (byte) -19 ); // Fill 53 of value (byte) -19 + Arrays.fill(CHARS, 1221, 1223, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1223, 1225, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1225, 1227, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1227, 1229, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1229, 1232, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 1232, 1260, (byte) -19 ); // Fill 28 of value (byte) -19 + Arrays.fill(CHARS, 1260, 1262, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1262, 1270, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 1270, 1272, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1272, 1274, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1274, 1329, (byte) 33 ); // Fill 55 of value (byte) 33 + Arrays.fill(CHARS, 1329, 1367, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 1367, 1369, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[1369] = -19; + Arrays.fill(CHARS, 1370, 1377, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 1377, 1415, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 1415, 1425, (byte) 33 ); // Fill 10 of value (byte) 33 + Arrays.fill(CHARS, 1425, 1442, (byte) -87 ); // Fill 17 of value (byte) -87 + CHARS[1442] = 33; + Arrays.fill(CHARS, 1443, 1466, (byte) -87 ); // Fill 23 of value (byte) -87 + CHARS[1466] = 33; + Arrays.fill(CHARS, 1467, 1470, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[1470] = 33; + CHARS[1471] = -87; + CHARS[1472] = 33; + Arrays.fill(CHARS, 1473, 1475, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[1475] = 33; + CHARS[1476] = -87; + Arrays.fill(CHARS, 1477, 1488, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 1488, 1515, (byte) -19 ); // Fill 27 of value (byte) -19 + Arrays.fill(CHARS, 1515, 1520, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 1520, 1523, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 1523, 1569, (byte) 33 ); // Fill 46 of value (byte) 33 + Arrays.fill(CHARS, 1569, 1595, (byte) -19 ); // Fill 26 of value (byte) -19 + Arrays.fill(CHARS, 1595, 1600, (byte) 33 ); // Fill 5 of value (byte) 33 + CHARS[1600] = -87; + Arrays.fill(CHARS, 1601, 1611, (byte) -19 ); // Fill 10 of value (byte) -19 + Arrays.fill(CHARS, 1611, 1619, (byte) -87 ); // Fill 8 of value (byte) -87 + Arrays.fill(CHARS, 1619, 1632, (byte) 33 ); // Fill 13 of value (byte) 33 + Arrays.fill(CHARS, 1632, 1642, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 1642, 1648, (byte) 33 ); // Fill 6 of value (byte) 33 + CHARS[1648] = -87; + Arrays.fill(CHARS, 1649, 1720, (byte) -19 ); // Fill 71 of value (byte) -19 + Arrays.fill(CHARS, 1720, 1722, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1722, 1727, (byte) -19 ); // Fill 5 of value (byte) -19 + CHARS[1727] = 33; + Arrays.fill(CHARS, 1728, 1743, (byte) -19 ); // Fill 15 of value (byte) -19 + CHARS[1743] = 33; + Arrays.fill(CHARS, 1744, 1748, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[1748] = 33; + CHARS[1749] = -19; + Arrays.fill(CHARS, 1750, 1765, (byte) -87 ); // Fill 15 of value (byte) -87 + Arrays.fill(CHARS, 1765, 1767, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 1767, 1769, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[1769] = 33; + Arrays.fill(CHARS, 1770, 1774, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 1774, 1776, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 1776, 1786, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 1786, 2305, (byte) 33 ); // Fill 519 of value (byte) 33 + Arrays.fill(CHARS, 2305, 2308, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2308] = 33; + Arrays.fill(CHARS, 2309, 2362, (byte) -19 ); // Fill 53 of value (byte) -19 + Arrays.fill(CHARS, 2362, 2364, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2364] = -87; + CHARS[2365] = -19; + Arrays.fill(CHARS, 2366, 2382, (byte) -87 ); // Fill 16 of value (byte) -87 + Arrays.fill(CHARS, 2382, 2385, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2385, 2389, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 2389, 2392, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2392, 2402, (byte) -19 ); // Fill 10 of value (byte) -19 + Arrays.fill(CHARS, 2402, 2404, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2404, 2406, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2406, 2416, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2416, 2433, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 2433, 2436, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2436] = 33; + Arrays.fill(CHARS, 2437, 2445, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 2445, 2447, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2447, 2449, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2449, 2451, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2451, 2473, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2473] = 33; + Arrays.fill(CHARS, 2474, 2481, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2481] = 33; + CHARS[2482] = -19; + Arrays.fill(CHARS, 2483, 2486, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2486, 2490, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2490, 2492, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2492] = -87; + CHARS[2493] = 33; + Arrays.fill(CHARS, 2494, 2501, (byte) -87 ); // Fill 7 of value (byte) -87 + Arrays.fill(CHARS, 2501, 2503, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2503, 2505, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2505, 2507, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2507, 2510, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2510, 2519, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[2519] = -87; + Arrays.fill(CHARS, 2520, 2524, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2524, 2526, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2526] = 33; + Arrays.fill(CHARS, 2527, 2530, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2530, 2532, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2532, 2534, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2534, 2544, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2544, 2546, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2546, 2562, (byte) 33 ); // Fill 16 of value (byte) 33 + CHARS[2562] = -87; + Arrays.fill(CHARS, 2563, 2565, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2565, 2571, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 2571, 2575, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2575, 2577, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2577, 2579, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2579, 2601, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2601] = 33; + Arrays.fill(CHARS, 2602, 2609, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2609] = 33; + Arrays.fill(CHARS, 2610, 2612, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2612] = 33; + Arrays.fill(CHARS, 2613, 2615, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2615] = 33; + Arrays.fill(CHARS, 2616, 2618, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2618, 2620, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2620] = -87; + CHARS[2621] = 33; + Arrays.fill(CHARS, 2622, 2627, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 2627, 2631, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2631, 2633, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2633, 2635, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2635, 2638, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2638, 2649, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 2649, 2653, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[2653] = 33; + CHARS[2654] = -19; + Arrays.fill(CHARS, 2655, 2662, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 2662, 2674, (byte) -87 ); // Fill 12 of value (byte) -87 + Arrays.fill(CHARS, 2674, 2677, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2677, 2689, (byte) 33 ); // Fill 12 of value (byte) 33 + Arrays.fill(CHARS, 2689, 2692, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2692] = 33; + Arrays.fill(CHARS, 2693, 2700, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2700] = 33; + CHARS[2701] = -19; + CHARS[2702] = 33; + Arrays.fill(CHARS, 2703, 2706, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[2706] = 33; + Arrays.fill(CHARS, 2707, 2729, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2729] = 33; + Arrays.fill(CHARS, 2730, 2737, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2737] = 33; + Arrays.fill(CHARS, 2738, 2740, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2740] = 33; + Arrays.fill(CHARS, 2741, 2746, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 2746, 2748, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2748] = -87; + CHARS[2749] = -19; + Arrays.fill(CHARS, 2750, 2758, (byte) -87 ); // Fill 8 of value (byte) -87 + CHARS[2758] = 33; + Arrays.fill(CHARS, 2759, 2762, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2762] = 33; + Arrays.fill(CHARS, 2763, 2766, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2766, 2784, (byte) 33 ); // Fill 18 of value (byte) 33 + CHARS[2784] = -19; + Arrays.fill(CHARS, 2785, 2790, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 2790, 2800, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2800, 2817, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 2817, 2820, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[2820] = 33; + Arrays.fill(CHARS, 2821, 2829, (byte) -19 ); // Fill 8 of value (byte) -19 + Arrays.fill(CHARS, 2829, 2831, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2831, 2833, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2833, 2835, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2835, 2857, (byte) -19 ); // Fill 22 of value (byte) -19 + CHARS[2857] = 33; + Arrays.fill(CHARS, 2858, 2865, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[2865] = 33; + Arrays.fill(CHARS, 2866, 2868, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2868, 2870, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2870, 2874, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2874, 2876, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[2876] = -87; + CHARS[2877] = -19; + Arrays.fill(CHARS, 2878, 2884, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 2884, 2887, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2887, 2889, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2889, 2891, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 2891, 2894, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 2894, 2902, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 2902, 2904, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 2904, 2908, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2908, 2910, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2910] = 33; + Arrays.fill(CHARS, 2911, 2914, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2914, 2918, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 2918, 2928, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 2928, 2946, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 2946, 2948, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[2948] = 33; + Arrays.fill(CHARS, 2949, 2955, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 2955, 2958, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2958, 2961, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[2961] = 33; + Arrays.fill(CHARS, 2962, 2966, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 2966, 2969, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2969, 2971, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[2971] = 33; + CHARS[2972] = -19; + CHARS[2973] = 33; + Arrays.fill(CHARS, 2974, 2976, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2976, 2979, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2979, 2981, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 2981, 2984, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2984, 2987, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 2987, 2990, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 2990, 2998, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[2998] = 33; + Arrays.fill(CHARS, 2999, 3002, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 3002, 3006, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3006, 3011, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 3011, 3014, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 3014, 3017, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3017] = 33; + Arrays.fill(CHARS, 3018, 3022, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3022, 3031, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[3031] = -87; + Arrays.fill(CHARS, 3032, 3047, (byte) 33 ); // Fill 15 of value (byte) 33 + Arrays.fill(CHARS, 3047, 3056, (byte) -87 ); // Fill 9 of value (byte) -87 + Arrays.fill(CHARS, 3056, 3073, (byte) 33 ); // Fill 17 of value (byte) 33 + Arrays.fill(CHARS, 3073, 3076, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3076] = 33; + Arrays.fill(CHARS, 3077, 3085, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3085] = 33; + Arrays.fill(CHARS, 3086, 3089, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3089] = 33; + Arrays.fill(CHARS, 3090, 3113, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3113] = 33; + Arrays.fill(CHARS, 3114, 3124, (byte) -19 ); // Fill 10 of value (byte) -19 + CHARS[3124] = 33; + Arrays.fill(CHARS, 3125, 3130, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 3130, 3134, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3134, 3141, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[3141] = 33; + Arrays.fill(CHARS, 3142, 3145, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3145] = 33; + Arrays.fill(CHARS, 3146, 3150, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3150, 3157, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3157, 3159, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3159, 3168, (byte) 33 ); // Fill 9 of value (byte) 33 + Arrays.fill(CHARS, 3168, 3170, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3170, 3174, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3174, 3184, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3184, 3202, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 3202, 3204, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3204] = 33; + Arrays.fill(CHARS, 3205, 3213, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3213] = 33; + Arrays.fill(CHARS, 3214, 3217, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3217] = 33; + Arrays.fill(CHARS, 3218, 3241, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3241] = 33; + Arrays.fill(CHARS, 3242, 3252, (byte) -19 ); // Fill 10 of value (byte) -19 + CHARS[3252] = 33; + Arrays.fill(CHARS, 3253, 3258, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 3258, 3262, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3262, 3269, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[3269] = 33; + Arrays.fill(CHARS, 3270, 3273, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3273] = 33; + Arrays.fill(CHARS, 3274, 3278, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3278, 3285, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3285, 3287, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3287, 3294, (byte) 33 ); // Fill 7 of value (byte) 33 + CHARS[3294] = -19; + CHARS[3295] = 33; + Arrays.fill(CHARS, 3296, 3298, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3298, 3302, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3302, 3312, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3312, 3330, (byte) 33 ); // Fill 18 of value (byte) 33 + Arrays.fill(CHARS, 3330, 3332, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3332] = 33; + Arrays.fill(CHARS, 3333, 3341, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3341] = 33; + Arrays.fill(CHARS, 3342, 3345, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3345] = 33; + Arrays.fill(CHARS, 3346, 3369, (byte) -19 ); // Fill 23 of value (byte) -19 + CHARS[3369] = 33; + Arrays.fill(CHARS, 3370, 3386, (byte) -19 ); // Fill 16 of value (byte) -19 + Arrays.fill(CHARS, 3386, 3390, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3390, 3396, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3396, 3398, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3398, 3401, (byte) -87 ); // Fill 3 of value (byte) -87 + CHARS[3401] = 33; + Arrays.fill(CHARS, 3402, 3406, (byte) -87 ); // Fill 4 of value (byte) -87 + Arrays.fill(CHARS, 3406, 3415, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[3415] = -87; + Arrays.fill(CHARS, 3416, 3424, (byte) 33 ); // Fill 8 of value (byte) 33 + Arrays.fill(CHARS, 3424, 3426, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3426, 3430, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3430, 3440, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3440, 3585, (byte) 33 ); // Fill 145 of value (byte) 33 + Arrays.fill(CHARS, 3585, 3631, (byte) -19 ); // Fill 46 of value (byte) -19 + CHARS[3631] = 33; + CHARS[3632] = -19; + CHARS[3633] = -87; + Arrays.fill(CHARS, 3634, 3636, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3636, 3643, (byte) -87 ); // Fill 7 of value (byte) -87 + Arrays.fill(CHARS, 3643, 3648, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 3648, 3654, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 3654, 3663, (byte) -87 ); // Fill 9 of value (byte) -87 + CHARS[3663] = 33; + Arrays.fill(CHARS, 3664, 3674, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3674, 3713, (byte) 33 ); // Fill 39 of value (byte) 33 + Arrays.fill(CHARS, 3713, 3715, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3715] = 33; + CHARS[3716] = -19; + Arrays.fill(CHARS, 3717, 3719, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3719, 3721, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3721] = 33; + CHARS[3722] = -19; + Arrays.fill(CHARS, 3723, 3725, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[3725] = -19; + Arrays.fill(CHARS, 3726, 3732, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 3732, 3736, (byte) -19 ); // Fill 4 of value (byte) -19 + CHARS[3736] = 33; + Arrays.fill(CHARS, 3737, 3744, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[3744] = 33; + Arrays.fill(CHARS, 3745, 3748, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[3748] = 33; + CHARS[3749] = -19; + CHARS[3750] = 33; + CHARS[3751] = -19; + Arrays.fill(CHARS, 3752, 3754, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3754, 3756, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3756] = 33; + Arrays.fill(CHARS, 3757, 3759, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[3759] = 33; + CHARS[3760] = -19; + CHARS[3761] = -87; + Arrays.fill(CHARS, 3762, 3764, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 3764, 3770, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[3770] = 33; + Arrays.fill(CHARS, 3771, 3773, (byte) -87 ); // Fill 2 of value (byte) -87 + CHARS[3773] = -19; + Arrays.fill(CHARS, 3774, 3776, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3776, 3781, (byte) -19 ); // Fill 5 of value (byte) -19 + CHARS[3781] = 33; + CHARS[3782] = -87; + CHARS[3783] = 33; + Arrays.fill(CHARS, 3784, 3790, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3790, 3792, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 3792, 3802, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3802, 3864, (byte) 33 ); // Fill 62 of value (byte) 33 + Arrays.fill(CHARS, 3864, 3866, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3866, 3872, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 3872, 3882, (byte) -87 ); // Fill 10 of value (byte) -87 + Arrays.fill(CHARS, 3882, 3893, (byte) 33 ); // Fill 11 of value (byte) 33 + CHARS[3893] = -87; + CHARS[3894] = 33; + CHARS[3895] = -87; + CHARS[3896] = 33; + CHARS[3897] = -87; + Arrays.fill(CHARS, 3898, 3902, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3902, 3904, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 3904, 3912, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[3912] = 33; + Arrays.fill(CHARS, 3913, 3946, (byte) -19 ); // Fill 33 of value (byte) -19 + Arrays.fill(CHARS, 3946, 3953, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 3953, 3973, (byte) -87 ); // Fill 20 of value (byte) -87 + CHARS[3973] = 33; + Arrays.fill(CHARS, 3974, 3980, (byte) -87 ); // Fill 6 of value (byte) -87 + Arrays.fill(CHARS, 3980, 3984, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 3984, 3990, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[3990] = 33; + CHARS[3991] = -87; + CHARS[3992] = 33; + Arrays.fill(CHARS, 3993, 4014, (byte) -87 ); // Fill 21 of value (byte) -87 + Arrays.fill(CHARS, 4014, 4017, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4017, 4024, (byte) -87 ); // Fill 7 of value (byte) -87 + CHARS[4024] = 33; + CHARS[4025] = -87; + Arrays.fill(CHARS, 4026, 4256, (byte) 33 ); // Fill 230 of value (byte) 33 + Arrays.fill(CHARS, 4256, 4294, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 4294, 4304, (byte) 33 ); // Fill 10 of value (byte) 33 + Arrays.fill(CHARS, 4304, 4343, (byte) -19 ); // Fill 39 of value (byte) -19 + Arrays.fill(CHARS, 4343, 4352, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[4352] = -19; + CHARS[4353] = 33; + Arrays.fill(CHARS, 4354, 4356, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4356] = 33; + Arrays.fill(CHARS, 4357, 4360, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[4360] = 33; + CHARS[4361] = -19; + CHARS[4362] = 33; + Arrays.fill(CHARS, 4363, 4365, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4365] = 33; + Arrays.fill(CHARS, 4366, 4371, (byte) -19 ); // Fill 5 of value (byte) -19 + Arrays.fill(CHARS, 4371, 4412, (byte) 33 ); // Fill 41 of value (byte) 33 + CHARS[4412] = -19; + CHARS[4413] = 33; + CHARS[4414] = -19; + CHARS[4415] = 33; + CHARS[4416] = -19; + Arrays.fill(CHARS, 4417, 4428, (byte) 33 ); // Fill 11 of value (byte) 33 + CHARS[4428] = -19; + CHARS[4429] = 33; + CHARS[4430] = -19; + CHARS[4431] = 33; + CHARS[4432] = -19; + Arrays.fill(CHARS, 4433, 4436, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4436, 4438, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4438, 4441, (byte) 33 ); // Fill 3 of value (byte) 33 + CHARS[4441] = -19; + Arrays.fill(CHARS, 4442, 4447, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 4447, 4450, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[4450] = 33; + CHARS[4451] = -19; + CHARS[4452] = 33; + CHARS[4453] = -19; + CHARS[4454] = 33; + CHARS[4455] = -19; + CHARS[4456] = 33; + CHARS[4457] = -19; + Arrays.fill(CHARS, 4458, 4461, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4461, 4463, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4463, 4466, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 4466, 4468, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4468] = 33; + CHARS[4469] = -19; + Arrays.fill(CHARS, 4470, 4510, (byte) 33 ); // Fill 40 of value (byte) 33 + CHARS[4510] = -19; + Arrays.fill(CHARS, 4511, 4520, (byte) 33 ); // Fill 9 of value (byte) 33 + CHARS[4520] = -19; + Arrays.fill(CHARS, 4521, 4523, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[4523] = -19; + Arrays.fill(CHARS, 4524, 4526, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 4526, 4528, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 4528, 4535, (byte) 33 ); // Fill 7 of value (byte) 33 + Arrays.fill(CHARS, 4535, 4537, (byte) -19 ); // Fill 2 of value (byte) -19 + CHARS[4537] = 33; + CHARS[4538] = -19; + CHARS[4539] = 33; + Arrays.fill(CHARS, 4540, 4547, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 4547, 4587, (byte) 33 ); // Fill 40 of value (byte) 33 + CHARS[4587] = -19; + Arrays.fill(CHARS, 4588, 4592, (byte) 33 ); // Fill 4 of value (byte) 33 + CHARS[4592] = -19; + Arrays.fill(CHARS, 4593, 4601, (byte) 33 ); // Fill 8 of value (byte) 33 + CHARS[4601] = -19; + Arrays.fill(CHARS, 4602, 7680, (byte) 33 ); // Fill 3078 of value (byte) 33 + Arrays.fill(CHARS, 7680, 7836, (byte) -19 ); // Fill 156 of value (byte) -19 + Arrays.fill(CHARS, 7836, 7840, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 7840, 7930, (byte) -19 ); // Fill 90 of value (byte) -19 + Arrays.fill(CHARS, 7930, 7936, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 7936, 7958, (byte) -19 ); // Fill 22 of value (byte) -19 + Arrays.fill(CHARS, 7958, 7960, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 7960, 7966, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 7966, 7968, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 7968, 8006, (byte) -19 ); // Fill 38 of value (byte) -19 + Arrays.fill(CHARS, 8006, 8008, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8008, 8014, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 8014, 8016, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8016, 8024, (byte) -19 ); // Fill 8 of value (byte) -19 + CHARS[8024] = 33; + CHARS[8025] = -19; + CHARS[8026] = 33; + CHARS[8027] = -19; + CHARS[8028] = 33; + CHARS[8029] = -19; + CHARS[8030] = 33; + Arrays.fill(CHARS, 8031, 8062, (byte) -19 ); // Fill 31 of value (byte) -19 + Arrays.fill(CHARS, 8062, 8064, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8064, 8117, (byte) -19 ); // Fill 53 of value (byte) -19 + CHARS[8117] = 33; + Arrays.fill(CHARS, 8118, 8125, (byte) -19 ); // Fill 7 of value (byte) -19 + CHARS[8125] = 33; + CHARS[8126] = -19; + Arrays.fill(CHARS, 8127, 8130, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8130, 8133, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[8133] = 33; + Arrays.fill(CHARS, 8134, 8141, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 8141, 8144, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8144, 8148, (byte) -19 ); // Fill 4 of value (byte) -19 + Arrays.fill(CHARS, 8148, 8150, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 8150, 8156, (byte) -19 ); // Fill 6 of value (byte) -19 + Arrays.fill(CHARS, 8156, 8160, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 8160, 8173, (byte) -19 ); // Fill 13 of value (byte) -19 + Arrays.fill(CHARS, 8173, 8178, (byte) 33 ); // Fill 5 of value (byte) 33 + Arrays.fill(CHARS, 8178, 8181, (byte) -19 ); // Fill 3 of value (byte) -19 + CHARS[8181] = 33; + Arrays.fill(CHARS, 8182, 8189, (byte) -19 ); // Fill 7 of value (byte) -19 + Arrays.fill(CHARS, 8189, 8400, (byte) 33 ); // Fill 211 of value (byte) 33 + Arrays.fill(CHARS, 8400, 8413, (byte) -87 ); // Fill 13 of value (byte) -87 + Arrays.fill(CHARS, 8413, 8417, (byte) 33 ); // Fill 4 of value (byte) 33 + CHARS[8417] = -87; + Arrays.fill(CHARS, 8418, 8486, (byte) 33 ); // Fill 68 of value (byte) 33 + CHARS[8486] = -19; + Arrays.fill(CHARS, 8487, 8490, (byte) 33 ); // Fill 3 of value (byte) 33 + Arrays.fill(CHARS, 8490, 8492, (byte) -19 ); // Fill 2 of value (byte) -19 + Arrays.fill(CHARS, 8492, 8494, (byte) 33 ); // Fill 2 of value (byte) 33 + CHARS[8494] = -19; + Arrays.fill(CHARS, 8495, 8576, (byte) 33 ); // Fill 81 of value (byte) 33 + Arrays.fill(CHARS, 8576, 8579, (byte) -19 ); // Fill 3 of value (byte) -19 + Arrays.fill(CHARS, 8579, 12293, (byte) 33 ); // Fill 3714 of value (byte) 33 + CHARS[12293] = -87; + CHARS[12294] = 33; + CHARS[12295] = -19; + Arrays.fill(CHARS, 12296, 12321, (byte) 33 ); // Fill 25 of value (byte) 33 + Arrays.fill(CHARS, 12321, 12330, (byte) -19 ); // Fill 9 of value (byte) -19 + Arrays.fill(CHARS, 12330, 12336, (byte) -87 ); // Fill 6 of value (byte) -87 + CHARS[12336] = 33; + Arrays.fill(CHARS, 12337, 12342, (byte) -87 ); // Fill 5 of value (byte) -87 + Arrays.fill(CHARS, 12342, 12353, (byte) 33 ); // Fill 11 of value (byte) 33 + Arrays.fill(CHARS, 12353, 12437, (byte) -19 ); // Fill 84 of value (byte) -19 + Arrays.fill(CHARS, 12437, 12441, (byte) 33 ); // Fill 4 of value (byte) 33 + Arrays.fill(CHARS, 12441, 12443, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 12443, 12445, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 12445, 12447, (byte) -87 ); // Fill 2 of value (byte) -87 + Arrays.fill(CHARS, 12447, 12449, (byte) 33 ); // Fill 2 of value (byte) 33 + Arrays.fill(CHARS, 12449, 12539, (byte) -19 ); // Fill 90 of value (byte) -19 + CHARS[12539] = 33; + Arrays.fill(CHARS, 12540, 12543, (byte) -87 ); // Fill 3 of value (byte) -87 + Arrays.fill(CHARS, 12543, 12549, (byte) 33 ); // Fill 6 of value (byte) 33 + Arrays.fill(CHARS, 12549, 12589, (byte) -19 ); // Fill 40 of value (byte) -19 + Arrays.fill(CHARS, 12589, 19968, (byte) 33 ); // Fill 7379 of value (byte) 33 + Arrays.fill(CHARS, 19968, 40870, (byte) -19 ); // Fill 20902 of value (byte) -19 + Arrays.fill(CHARS, 40870, 44032, (byte) 33 ); // Fill 3162 of value (byte) 33 + Arrays.fill(CHARS, 44032, 55204, (byte) -19 ); // Fill 11172 of value (byte) -19 + Arrays.fill(CHARS, 55204, 55296, (byte) 33 ); // Fill 92 of value (byte) 33 + Arrays.fill(CHARS, 57344, 65534, (byte) 33 ); // Fill 8190 of value (byte) 33 + + } // () + + // + // Public static methods + // + + /** + * Returns true if the specified character is a supplemental character. + * + * @param c The character to check. + */ + public static boolean isSupplemental(int c) { + return (c >= 0x10000 && c <= 0x10FFFF); + } + + /** + * Returns true the supplemental character corresponding to the given + * surrogates. + * + * @param h The high surrogate. + * @param l The low surrogate. + */ + public static int supplemental(char h, char l) { + return (h - 0xD800) * 0x400 + (l - 0xDC00) + 0x10000; + } + + /** + * Returns the high surrogate of a supplemental character + * + * @param c The supplemental character to "split". + */ + public static char highSurrogate(int c) { + return (char) (((c - 0x00010000) >> 10) + 0xD800); + } + + /** + * Returns the low surrogate of a supplemental character + * + * @param c The supplemental character to "split". + */ + public static char lowSurrogate(int c) { + return (char) (((c - 0x00010000) & 0x3FF) + 0xDC00); + } + + /** + * Returns whether the given character is a high surrogate + * + * @param c The character to check. + */ + public static boolean isHighSurrogate(int c) { + return (0xD800 <= c && c <= 0xDBFF); + } + + /** + * Returns whether the given character is a low surrogate + * + * @param c The character to check. + */ + public static boolean isLowSurrogate(int c) { + return (0xDC00 <= c && c <= 0xDFFF); + } + + + /** + * Returns true if the specified character is valid. This method + * also checks the surrogate character range from 0x10000 to 0x10FFFF. + *

        + * If the program chooses to apply the mask directly to the + * CHARS array, then they are responsible for checking + * the surrogate character range. + * + * @param c The character to check. + */ + public static boolean isValid(int c) { + return (c < 0x10000 && (CHARS[c] & MASK_VALID) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isValid(int):boolean + + /** + * Returns true if the specified character is invalid. + * + * @param c The character to check. + */ + public static boolean isInvalid(int c) { + return !isValid(c); + } // isInvalid(int):boolean + + /** + * Returns true if the specified character can be considered content. + * + * @param c The character to check. + */ + public static boolean isContent(int c) { + return (c < 0x10000 && (CHARS[c] & MASK_CONTENT) != 0) || + (0x10000 <= c && c <= 0x10FFFF); + } // isContent(int):boolean + + /** + * Returns true if the specified character can be considered markup. + * Markup characters include '<', '&', and '%'. + * + * @param c The character to check. + */ + public static boolean isMarkup(int c) { + return c == '<' || c == '&' || c == '%'; + } // isMarkup(int):boolean + + /** + * Returns true if the specified character is a space character + * as defined by production [3] in the XML 1.0 specification. + * + * @param c The character to check. + */ + public static boolean isSpace(int c) { + return c <= 0x20 && (CHARS[c] & MASK_SPACE) != 0; + } // isSpace(int):boolean + + /** + * Returns true if the specified character is a valid name start + * character as defined by production [5] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isNameStart(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NAME_START) != 0; + } // isNameStart(int):boolean + + /** + * Returns true if the specified character is a valid name + * character as defined by production [4] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isName(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NAME) != 0; + } // isName(int):boolean + + /** + * Returns true if the specified character is a valid NCName start + * character as defined by production [4] in Namespaces in XML + * recommendation. + * + * @param c The character to check. + */ + public static boolean isNCNameStart(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NCNAME_START) != 0; + } // isNCNameStart(int):boolean + + /** + * Returns true if the specified character is a valid NCName + * character as defined by production [5] in Namespaces in XML + * recommendation. + * + * @param c The character to check. + */ + public static boolean isNCName(int c) { + return c < 0x10000 && (CHARS[c] & MASK_NCNAME) != 0; + } // isNCName(int):boolean + + /** + * Returns true if the specified character is a valid Pubid + * character as defined by production [13] in the XML 1.0 + * specification. + * + * @param c The character to check. + */ + public static boolean isPubid(int c) { + return c < 0x10000 && (CHARS[c] & MASK_PUBID) != 0; + } // isPubid(int):boolean + + /* + * [5] Name ::= (Letter | '_' | ':') (NameChar)* + */ + /** + * Check to see if a string is a valid Name according to [5] + * in the XML 1.0 Recommendation + * + * @param name string to check + * @return true if name is a valid Name + */ + public static boolean isValidName(String name) { + if (name.length() == 0) + return false; + char ch = name.charAt(0); + if( isNameStart(ch) == false) + return false; + for (int i = 1; i < name.length(); i++ ) { + ch = name.charAt(i); + if( isName( ch ) == false ){ + return false; + } + } + return true; + } // isValidName(String):boolean + + + /* + * from the namespace rec + * [4] NCName ::= (Letter | '_') (NCNameChar)* + */ + /** + * Check to see if a string is a valid NCName according to [4] + * from the XML Namespaces 1.0 Recommendation + * + * @param ncName string to check + * @return true if name is a valid NCName + */ + public static boolean isValidNCName(String ncName) { + if (ncName.length() == 0) + return false; + char ch = ncName.charAt(0); + if( isNCNameStart(ch) == false) + return false; + for (int i = 1; i < ncName.length(); i++ ) { + ch = ncName.charAt(i); + if( isNCName( ch ) == false ){ + return false; + } + } + return true; + } // isValidNCName(String):boolean + + /* + * [7] Nmtoken ::= (NameChar)+ + */ + /** + * Check to see if a string is a valid Nmtoken according to [7] + * in the XML 1.0 Recommendation + * + * @param nmtoken string to check + * @return true if nmtoken is a valid Nmtoken + */ + public static boolean isValidNmtoken(String nmtoken) { + if (nmtoken.length() == 0) + return false; + for (int i = 0; i < nmtoken.length(); i++ ) { + char ch = nmtoken.charAt(i); + if( ! isName( ch ) ){ + return false; + } + } + return true; + } // isValidName(String):boolean + + + + + + // encodings + + /** + * Returns true if the encoding name is a valid IANA encoding. + * This method does not verify that there is a decoder available + * for this encoding, only that the characters are valid for an + * IANA encoding name. + * + * @param ianaEncoding The IANA encoding name. + */ + public static boolean isValidIANAEncoding(String ianaEncoding) { + if (ianaEncoding != null) { + int length = ianaEncoding.length(); + if (length > 0) { + char c = ianaEncoding.charAt(0); + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { + for (int i = 1; i < length; i++) { + c = ianaEncoding.charAt(i); + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && + (c < '0' || c > '9') && c != '.' && c != '_' && + c != '-') { + return false; + } + } + return true; + } + } + } + return false; + } // isValidIANAEncoding(String):boolean + + /** + * Returns true if the encoding name is a valid Java encoding. + * This method does not verify that there is a decoder available + * for this encoding, only that the characters are valid for an + * Java encoding name. + * + * @param javaEncoding The Java encoding name. + */ + public static boolean isValidJavaEncoding(String javaEncoding) { + if (javaEncoding != null) { + int length = javaEncoding.length(); + if (length > 0) { + for (int i = 1; i < length; i++) { + char c = javaEncoding.charAt(i); + if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && + (c < '0' || c > '9') && c != '.' && c != '_' && + c != '-') { + return false; + } + } + return true; + } + } + return false; + } // isValidIANAEncoding(String):boolean + + +} // class XMLChar diff --git a/java/org/apache/jasper/xmlparser/XMLEncodingDetector.java b/java/org/apache/jasper/xmlparser/XMLEncodingDetector.java index 1ef4859e6..a0f050c82 100644 --- a/java/org/apache/jasper/xmlparser/XMLEncodingDetector.java +++ b/java/org/apache/jasper/xmlparser/XMLEncodingDetector.java @@ -1,1624 +1,1624 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -import java.io.EOFException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.IOException; -import java.io.Reader; -import java.util.Locale; -import java.util.jar.JarFile; - -import org.apache.jasper.JasperException; -import org.apache.jasper.JspCompilationContext; -import org.apache.jasper.compiler.ErrorDispatcher; -import org.apache.jasper.compiler.JspUtil; - -public class XMLEncodingDetector { - - private InputStream stream; - private String encoding; - private boolean isEncodingSetInProlog; - private Boolean isBigEndian; - private Reader reader; - - // org.apache.xerces.impl.XMLEntityManager fields - public static final int DEFAULT_BUFFER_SIZE = 2048; - public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64; - private boolean fAllowJavaEncodings; - private SymbolTable fSymbolTable; - private XMLEncodingDetector fCurrentEntity; - private int fBufferSize = DEFAULT_BUFFER_SIZE; - - // org.apache.xerces.impl.XMLEntityManager.ScannedEntity fields - private int lineNumber = 1; - private int columnNumber = 1; - private boolean literal; - private char[] ch = new char[DEFAULT_BUFFER_SIZE]; - private int position; - private int count; - private boolean mayReadChunks = false; - - // org.apache.xerces.impl.XMLScanner fields - private XMLString fString = new XMLString(); - private XMLStringBuffer fStringBuffer = new XMLStringBuffer(); - private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); - private final static String fVersionSymbol = "version"; - private final static String fEncodingSymbol = "encoding"; - private final static String fStandaloneSymbol = "standalone"; - - // org.apache.xerces.impl.XMLDocumentFragmentScannerImpl fields - private int fMarkupDepth = 0; - private String[] fStrings = new String[3]; - - private ErrorDispatcher err; - - /** - * Constructor - */ - public XMLEncodingDetector() { - fSymbolTable = new SymbolTable(); - fCurrentEntity = this; - } - - /** - * Autodetects the encoding of the XML document supplied by the given - * input stream. - * - * Encoding autodetection is done according to the XML 1.0 specification, - * Appendix F.1: Detection Without External Encoding Information. - * - * @return Two-element array, where the first element (of type - * java.lang.String) contains the name of the (auto)detected encoding, and - * the second element (of type java.lang.Boolean) specifies whether the - * encoding was specified using the 'encoding' attribute of an XML prolog - * (TRUE) or autodetected (FALSE). - */ - public static Object[] getEncoding(String fname, JarFile jarFile, - JspCompilationContext ctxt, - ErrorDispatcher err) - throws IOException, JasperException - { - InputStream inStream = JspUtil.getInputStream(fname, jarFile, ctxt, - err); - XMLEncodingDetector detector = new XMLEncodingDetector(); - Object[] ret = detector.getEncoding(inStream, err); - inStream.close(); - - return ret; - } - - private Object[] getEncoding(InputStream in, ErrorDispatcher err) - throws IOException, JasperException - { - this.stream = in; - this.err=err; - createInitialReader(); - scanXMLDecl(); - - return new Object[] { this.encoding, - new Boolean(this.isEncodingSetInProlog) }; - } - - // stub method - void endEntity() { - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.startEntity() - private void createInitialReader() throws IOException, JasperException { - - // wrap this stream in RewindableInputStream - stream = new RewindableInputStream(stream); - - // perform auto-detect of encoding if necessary - if (encoding == null) { - // read first four bytes and determine encoding - final byte[] b4 = new byte[4]; - int count = 0; - for (; count<4; count++ ) { - b4[count] = (byte)stream.read(); - } - if (count == 4) { - Object [] encodingDesc = getEncodingName(b4, count); - encoding = (String)(encodingDesc[0]); - isBigEndian = (Boolean)(encodingDesc[1]); - - stream.reset(); - // Special case UTF-8 files with BOM created by Microsoft - // tools. It's more efficient to consume the BOM than make - // the reader perform extra checks. -Ac - if (count > 2 && encoding.equals("UTF-8")) { - int b0 = b4[0] & 0xFF; - int b1 = b4[1] & 0xFF; - int b2 = b4[2] & 0xFF; - if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { - // ignore first three bytes... - stream.skip(3); - } - } - reader = createReader(stream, encoding, isBigEndian); - } else { - reader = createReader(stream, encoding, isBigEndian); - } - } - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.createReader - /** - * Creates a reader capable of reading the given input stream in - * the specified encoding. - * - * @param inputStream The input stream. - * @param encoding The encoding name that the input stream is - * encoded using. If the user has specified that - * Java encoding names are allowed, then the - * encoding name may be a Java encoding name; - * otherwise, it is an ianaEncoding name. - * @param isBigEndian For encodings (like uCS-4), whose names cannot - * specify a byte order, this tells whether the order - * is bigEndian. null means unknown or not relevant. - * - * @return Returns a reader. - */ - private Reader createReader(InputStream inputStream, String encoding, - Boolean isBigEndian) - throws IOException, JasperException { - - // normalize encoding name - if (encoding == null) { - encoding = "UTF-8"; - } - - // try to use an optimized reader - String ENCODING = encoding.toUpperCase(Locale.ENGLISH); - if (ENCODING.equals("UTF-8")) { - return new UTF8Reader(inputStream, fBufferSize); - } - if (ENCODING.equals("US-ASCII")) { - return new ASCIIReader(inputStream, fBufferSize); - } - if (ENCODING.equals("ISO-10646-UCS-4")) { - if (isBigEndian != null) { - boolean isBE = isBigEndian.booleanValue(); - if (isBE) { - return new UCSReader(inputStream, UCSReader.UCS4BE); - } else { - return new UCSReader(inputStream, UCSReader.UCS4LE); - } - } else { - err.jspError("jsp.error.xml.encodingByteOrderUnsupported", - encoding); - } - } - if (ENCODING.equals("ISO-10646-UCS-2")) { - if (isBigEndian != null) { // sould never happen with this encoding... - boolean isBE = isBigEndian.booleanValue(); - if (isBE) { - return new UCSReader(inputStream, UCSReader.UCS2BE); - } else { - return new UCSReader(inputStream, UCSReader.UCS2LE); - } - } else { - err.jspError("jsp.error.xml.encodingByteOrderUnsupported", - encoding); - } - } - - // check for valid name - boolean validIANA = XMLChar.isValidIANAEncoding(encoding); - boolean validJava = XMLChar.isValidJavaEncoding(encoding); - if (!validIANA || (fAllowJavaEncodings && !validJava)) { - err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); - // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 - // because every byte is a valid ISO Latin 1 character. - // It may not translate correctly but if we failed on - // the encoding anyway, then we're expecting the content - // of the document to be bad. This will just prevent an - // invalid UTF-8 sequence to be detected. This is only - // important when continue-after-fatal-error is turned - // on. -Ac - encoding = "ISO-8859-1"; - } - - // try to use a Java reader - String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); - if (javaEncoding == null) { - if (fAllowJavaEncodings) { - javaEncoding = encoding; - } else { - err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); - // see comment above. - javaEncoding = "ISO8859_1"; - } - } - return new InputStreamReader(inputStream, javaEncoding); - - } // createReader(InputStream,String, Boolean): Reader - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.getEncodingName - /** - * Returns the IANA encoding name that is auto-detected from - * the bytes specified, with the endian-ness of that encoding where - * appropriate. - * - * @param b4 The first four bytes of the input. - * @param count The number of bytes actually read. - * @return a 2-element array: the first element, an IANA-encoding string, - * the second element a Boolean which is true iff the document is big - * endian, false if it's little-endian, and null if the distinction isn't - * relevant. - */ - private Object[] getEncodingName(byte[] b4, int count) { - - if (count < 2) { - return new Object[]{"UTF-8", null}; - } - - // UTF-16, with BOM - int b0 = b4[0] & 0xFF; - int b1 = b4[1] & 0xFF; - if (b0 == 0xFE && b1 == 0xFF) { - // UTF-16, big-endian - return new Object [] {"UTF-16BE", new Boolean(true)}; - } - if (b0 == 0xFF && b1 == 0xFE) { - // UTF-16, little-endian - return new Object [] {"UTF-16LE", new Boolean(false)}; - } - - // default to UTF-8 if we don't have enough bytes to make a - // good determination of the encoding - if (count < 3) { - return new Object [] {"UTF-8", null}; - } - - // UTF-8 with a BOM - int b2 = b4[2] & 0xFF; - if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { - return new Object [] {"UTF-8", null}; - } - - // default to UTF-8 if we don't have enough bytes to make a - // good determination of the encoding - if (count < 4) { - return new Object [] {"UTF-8", null}; - } - - // other encodings - int b3 = b4[3] & 0xFF; - if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { - // UCS-4, big endian (1234) - return new Object [] {"ISO-10646-UCS-4", new Boolean(true)}; - } - if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { - // UCS-4, little endian (4321) - return new Object [] {"ISO-10646-UCS-4", new Boolean(false)}; - } - if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { - // UCS-4, unusual octet order (2143) - // REVISIT: What should this be? - return new Object [] {"ISO-10646-UCS-4", null}; - } - if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { - // UCS-4, unusual octect order (3412) - // REVISIT: What should this be? - return new Object [] {"ISO-10646-UCS-4", null}; - } - if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { - // UTF-16, big-endian, no BOM - // (or could turn out to be UCS-2... - // REVISIT: What should this be? - return new Object [] {"UTF-16BE", new Boolean(true)}; - } - if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { - // UTF-16, little-endian, no BOM - // (or could turn out to be UCS-2... - return new Object [] {"UTF-16LE", new Boolean(false)}; - } - if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { - // EBCDIC - // a la xerces1, return CP037 instead of EBCDIC here - return new Object [] {"CP037", null}; - } - - // default encoding - return new Object [] {"UTF-8", null}; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.isExternal - /** Returns true if the current entity being scanned is external. */ - public boolean isExternal() { - return true; - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.peekChar - /** - * Returns the next character on the input. - *

        - * Note: The character is not consumed. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public int peekChar() throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // peek at character - int c = fCurrentEntity.ch[fCurrentEntity.position]; - - // return peeked character - if (fCurrentEntity.isExternal()) { - return c != '\r' ? c : '\n'; - } - else { - return c; - } - - } // peekChar():int - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanChar - /** - * Returns the next character on the input. - *

        - * Note: The character is consumed. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public int scanChar() throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // scan character - int c = fCurrentEntity.ch[fCurrentEntity.position++]; - boolean external = false; - if (c == '\n' || - (c == '\r' && (external = fCurrentEntity.isExternal()))) { - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count) { - fCurrentEntity.ch[0] = (char)c; - load(1, false); - } - if (c == '\r' && external) { - if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') { - fCurrentEntity.position--; - } - c = '\n'; - } - } - - // return character that was scanned - fCurrentEntity.columnNumber++; - return c; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanName - /** - * Returns a string matching the Name production appearing immediately - * on the input as a symbol, or null if no Name string is present. - *

        - * Note: The Name characters are consumed. - *

        - * Note: The string returned must be a symbol. The - * SymbolTable can be used for this purpose. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - * - * @see SymbolTable - * @see XMLChar#isName - * @see XMLChar#isNameStart - */ - public String scanName() throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // scan name - int offset = fCurrentEntity.position; - if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { - if (++fCurrentEntity.position == fCurrentEntity.count) { - fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; - offset = 0; - if (load(1, false)) { - fCurrentEntity.columnNumber++; - String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, - 0, 1); - return symbol; - } - } - while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { - if (++fCurrentEntity.position == fCurrentEntity.count) { - int length = fCurrentEntity.position - offset; - if (length == fBufferSize) { - // bad luck we have to resize our buffer - char[] tmp = new char[fBufferSize * 2]; - System.arraycopy(fCurrentEntity.ch, offset, - tmp, 0, length); - fCurrentEntity.ch = tmp; - fBufferSize *= 2; - } else { - System.arraycopy(fCurrentEntity.ch, offset, - fCurrentEntity.ch, 0, length); - } - offset = 0; - if (load(length, false)) { - break; - } - } - } - } - int length = fCurrentEntity.position - offset; - fCurrentEntity.columnNumber += length; - - // return name - String symbol = null; - if (length > 0) { - symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); - } - return symbol; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanLiteral - /** - * Scans a range of attribute value data, setting the fields of the - * XMLString structure, appropriately. - *

        - * Note: The characters are consumed. - *

        - * Note: This method does not guarantee to return - * the longest run of attribute value data. This method may return - * before the quote character due to reaching the end of the input - * buffer or any other reason. - *

        - * Note: The fields contained in the XMLString - * structure are not guaranteed to remain valid upon subsequent calls - * to the entity scanner. Therefore, the caller is responsible for - * immediately using the returned character data or making a copy of - * the character data. - * - * @param quote The quote character that signifies the end of the - * attribute value data. - * @param content The content structure to fill. - * - * @return Returns the next character on the input, if known. This - * value may be -1 but this does note designate - * end of file. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public int scanLiteral(int quote, XMLString content) - throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { - fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; - load(1, false); - fCurrentEntity.position = 0; - } - - // normalize newlines - int offset = fCurrentEntity.position; - int c = fCurrentEntity.ch[offset]; - int newlines = 0; - boolean external = fCurrentEntity.isExternal(); - if (c == '\n' || (c == '\r' && external)) { - do { - c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (c == '\r' && external) { - newlines++; - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count) { - offset = 0; - fCurrentEntity.position = newlines; - if (load(newlines, false)) { - break; - } - } - if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { - fCurrentEntity.position++; - offset++; - } - /*** NEWLINE NORMALIZATION ***/ - else { - newlines++; - } - /***/ - } - else if (c == '\n') { - newlines++; - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count) { - offset = 0; - fCurrentEntity.position = newlines; - if (load(newlines, false)) { - break; - } - } - /*** NEWLINE NORMALIZATION *** - if (fCurrentEntity.ch[fCurrentEntity.position] == '\r' - && external) { - fCurrentEntity.position++; - offset++; - } - /***/ - } - else { - fCurrentEntity.position--; - break; - } - } while (fCurrentEntity.position < fCurrentEntity.count - 1); - for (int i = offset; i < fCurrentEntity.position; i++) { - fCurrentEntity.ch[i] = '\n'; - } - int length = fCurrentEntity.position - offset; - if (fCurrentEntity.position == fCurrentEntity.count - 1) { - content.setValues(fCurrentEntity.ch, offset, length); - return -1; - } - } - - // scan literal value - while (fCurrentEntity.position < fCurrentEntity.count) { - c = fCurrentEntity.ch[fCurrentEntity.position++]; - if ((c == quote && - (!fCurrentEntity.literal || external)) - || c == '%' || !XMLChar.isContent(c)) { - fCurrentEntity.position--; - break; - } - } - int length = fCurrentEntity.position - offset; - fCurrentEntity.columnNumber += length - newlines; - content.setValues(fCurrentEntity.ch, offset, length); - - // return next character - if (fCurrentEntity.position != fCurrentEntity.count) { - c = fCurrentEntity.ch[fCurrentEntity.position]; - // NOTE: We don't want to accidentally signal the - // end of the literal if we're expanding an - // entity appearing in the literal. -Ac - if (c == quote && fCurrentEntity.literal) { - c = -1; - } - } - else { - c = -1; - } - return c; - - } - - /** - * Scans a range of character data up to the specified delimiter, - * setting the fields of the XMLString structure, appropriately. - *

        - * Note: The characters are consumed. - *

        - * Note: This assumes that the internal buffer is - * at least the same size, or bigger, than the length of the delimiter - * and that the delimiter contains at least one character. - *

        - * Note: This method does not guarantee to return - * the longest run of character data. This method may return before - * the delimiter due to reaching the end of the input buffer or any - * other reason. - *

        - * Note: The fields contained in the XMLString - * structure are not guaranteed to remain valid upon subsequent calls - * to the entity scanner. Therefore, the caller is responsible for - * immediately using the returned character data or making a copy of - * the character data. - * - * @param delimiter The string that signifies the end of the character - * data to be scanned. - * @param buffer The data structure to fill. - * - * @return Returns true if there is more data to scan, false otherwise. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public boolean scanData(String delimiter, XMLStringBuffer buffer) - throws IOException { - - boolean done = false; - int delimLen = delimiter.length(); - char charAt0 = delimiter.charAt(0); - boolean external = fCurrentEntity.isExternal(); - do { - - // load more characters, if needed - - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - else if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { - System.arraycopy(fCurrentEntity.ch, fCurrentEntity.position, - fCurrentEntity.ch, 0, fCurrentEntity.count - fCurrentEntity.position); - load(fCurrentEntity.count - fCurrentEntity.position, false); - fCurrentEntity.position = 0; - } - if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { - // something must be wrong with the input: e.g., file ends an - // unterminated comment - int length = fCurrentEntity.count - fCurrentEntity.position; - buffer.append (fCurrentEntity.ch, fCurrentEntity.position, - length); - fCurrentEntity.columnNumber += fCurrentEntity.count; - fCurrentEntity.position = fCurrentEntity.count; - load(0,true); - return false; - } - - // normalize newlines - int offset = fCurrentEntity.position; - int c = fCurrentEntity.ch[offset]; - int newlines = 0; - if (c == '\n' || (c == '\r' && external)) { - do { - c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (c == '\r' && external) { - newlines++; - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count) { - offset = 0; - fCurrentEntity.position = newlines; - if (load(newlines, false)) { - break; - } - } - if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { - fCurrentEntity.position++; - offset++; - } - /*** NEWLINE NORMALIZATION ***/ - else { - newlines++; - } - } - else if (c == '\n') { - newlines++; - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count) { - offset = 0; - fCurrentEntity.position = newlines; - fCurrentEntity.count = newlines; - if (load(newlines, false)) { - break; - } - } - } - else { - fCurrentEntity.position--; - break; - } - } while (fCurrentEntity.position < fCurrentEntity.count - 1); - for (int i = offset; i < fCurrentEntity.position; i++) { - fCurrentEntity.ch[i] = '\n'; - } - int length = fCurrentEntity.position - offset; - if (fCurrentEntity.position == fCurrentEntity.count - 1) { - buffer.append(fCurrentEntity.ch, offset, length); - return true; - } - } - - // iterate over buffer looking for delimiter - OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { - c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (c == charAt0) { - // looks like we just hit the delimiter - int delimOffset = fCurrentEntity.position - 1; - for (int i = 1; i < delimLen; i++) { - if (fCurrentEntity.position == fCurrentEntity.count) { - fCurrentEntity.position -= i; - break OUTER; - } - c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (delimiter.charAt(i) != c) { - fCurrentEntity.position--; - break; - } - } - if (fCurrentEntity.position == delimOffset + delimLen) { - done = true; - break; - } - } - else if (c == '\n' || (external && c == '\r')) { - fCurrentEntity.position--; - break; - } - else if (XMLChar.isInvalid(c)) { - fCurrentEntity.position--; - int length = fCurrentEntity.position - offset; - fCurrentEntity.columnNumber += length - newlines; - buffer.append(fCurrentEntity.ch, offset, length); - return true; - } - } - int length = fCurrentEntity.position - offset; - fCurrentEntity.columnNumber += length - newlines; - if (done) { - length -= delimLen; - } - buffer.append (fCurrentEntity.ch, offset, length); - - // return true if string was skipped - } while (!done); - return !done; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipChar - /** - * Skips a character appearing immediately on the input. - *

        - * Note: The character is consumed only if it matches - * the specified character. - * - * @param c The character to skip. - * - * @return Returns true if the character was skipped. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public boolean skipChar(int c) throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // skip character - int cc = fCurrentEntity.ch[fCurrentEntity.position]; - if (cc == c) { - fCurrentEntity.position++; - if (c == '\n') { - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - } - else { - fCurrentEntity.columnNumber++; - } - return true; - } else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) { - // handle newlines - if (fCurrentEntity.position == fCurrentEntity.count) { - fCurrentEntity.ch[0] = (char)cc; - load(1, false); - } - fCurrentEntity.position++; - if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { - fCurrentEntity.position++; - } - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - return true; - } - - // character was not skipped - return false; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipSpaces - /** - * Skips space characters appearing immediately on the input. - *

        - * Note: The characters are consumed only if they are - * space characters. - * - * @return Returns true if at least one space character was skipped. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - * - * @see XMLChar#isSpace - */ - public boolean skipSpaces() throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // skip spaces - int c = fCurrentEntity.ch[fCurrentEntity.position]; - if (XMLChar.isSpace(c)) { - boolean external = fCurrentEntity.isExternal(); - do { - boolean entityChanged = false; - // handle newlines - if (c == '\n' || (external && c == '\r')) { - fCurrentEntity.lineNumber++; - fCurrentEntity.columnNumber = 1; - if (fCurrentEntity.position == fCurrentEntity.count - 1) { - fCurrentEntity.ch[0] = (char)c; - entityChanged = load(1, true); - if (!entityChanged) - // the load change the position to be 1, - // need to restore it when entity not changed - fCurrentEntity.position = 0; - } - if (c == '\r' && external) { - // REVISIT: Does this need to be updated to fix the - // #x0D ^#x0A newline normalization problem? -Ac - if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') { - fCurrentEntity.position--; - } - } - /*** NEWLINE NORMALIZATION *** - else { - if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r' - && external) { - fCurrentEntity.position++; - } - } - /***/ - } - else { - fCurrentEntity.columnNumber++; - } - // load more characters, if needed - if (!entityChanged) - fCurrentEntity.position++; - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); - return true; - } - - // no spaces were found - return false; - - } - - /** - * Skips the specified string appearing immediately on the input. - *

        - * Note: The characters are consumed only if they are - * space characters. - * - * @param s The string to skip. - * - * @return Returns true if the string was skipped. - * - * @throws IOException Thrown if i/o error occurs. - * @throws EOFException Thrown on end of file. - */ - public boolean skipString(String s) throws IOException { - - // load more characters, if needed - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, true); - } - - // skip string - final int length = s.length(); - for (int i = 0; i < length; i++) { - char c = fCurrentEntity.ch[fCurrentEntity.position++]; - if (c != s.charAt(i)) { - fCurrentEntity.position -= i + 1; - return false; - } - if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { - System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); - // REVISIT: Can a string to be skipped cross an - // entity boundary? -Ac - if (load(i + 1, false)) { - fCurrentEntity.position -= i + 1; - return false; - } - } - } - fCurrentEntity.columnNumber += length; - return true; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.EntityScanner.load - /** - * Loads a chunk of text. - * - * @param offset The offset into the character buffer to - * read the next batch of characters. - * @param changeEntity True if the load should change entities - * at the end of the entity, otherwise leave - * the current entity in place and the entity - * boundary will be signaled by the return - * value. - * - * @returns Returns true if the entity changed as a result of this - * load operation. - */ - final boolean load(int offset, boolean changeEntity) - throws IOException { - - // read characters - int length = fCurrentEntity.mayReadChunks? - (fCurrentEntity.ch.length - offset): - (DEFAULT_XMLDECL_BUFFER_SIZE); - int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset, - length); - - // reset count and position - boolean entityChanged = false; - if (count != -1) { - if (count != 0) { - fCurrentEntity.count = count + offset; - fCurrentEntity.position = offset; - } - } - - // end of this entity - else { - fCurrentEntity.count = offset; - fCurrentEntity.position = offset; - entityChanged = true; - if (changeEntity) { - endEntity(); - if (fCurrentEntity == null) { - throw new EOFException(); - } - // handle the trailing edges - if (fCurrentEntity.position == fCurrentEntity.count) { - load(0, false); - } - } - } - - return entityChanged; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLEntityManager.RewindableInputStream - /** - * This class wraps the byte inputstreams we're presented with. - * We need it because java.io.InputStreams don't provide - * functionality to reread processed bytes, and they have a habit - * of reading more than one character when you call their read() - * methods. This means that, once we discover the true (declared) - * encoding of a document, we can neither backtrack to read the - * whole doc again nor start reading where we are with a new - * reader. - * - * This class allows rewinding an inputStream by allowing a mark - * to be set, and the stream reset to that position. The - * class assumes that it needs to read one character per - * invocation when it's read() method is inovked, but uses the - * underlying InputStream's read(char[], offset length) method--it - * won't buffer data read this way! - * - * @author Neil Graham, IBM - * @author Glenn Marcy, IBM - */ - private final class RewindableInputStream extends InputStream { - - private InputStream fInputStream; - private byte[] fData; - private int fStartOffset; - private int fEndOffset; - private int fOffset; - private int fLength; - private int fMark; - - public RewindableInputStream(InputStream is) { - fData = new byte[DEFAULT_XMLDECL_BUFFER_SIZE]; - fInputStream = is; - fStartOffset = 0; - fEndOffset = -1; - fOffset = 0; - fLength = 0; - fMark = 0; - } - - public void setStartOffset(int offset) { - fStartOffset = offset; - } - - public void rewind() { - fOffset = fStartOffset; - } - - public int read() throws IOException { - int b = 0; - if (fOffset < fLength) { - return fData[fOffset++] & 0xff; - } - if (fOffset == fEndOffset) { - return -1; - } - if (fOffset == fData.length) { - byte[] newData = new byte[fOffset << 1]; - System.arraycopy(fData, 0, newData, 0, fOffset); - fData = newData; - } - b = fInputStream.read(); - if (b == -1) { - fEndOffset = fOffset; - return -1; - } - fData[fLength++] = (byte)b; - fOffset++; - return b & 0xff; - } - - public int read(byte[] b, int off, int len) throws IOException { - int bytesLeft = fLength - fOffset; - if (bytesLeft == 0) { - if (fOffset == fEndOffset) { - return -1; - } - // better get some more for the voracious reader... - if (fCurrentEntity.mayReadChunks) { - return fInputStream.read(b, off, len); - } - int returnedVal = read(); - if (returnedVal == -1) { - fEndOffset = fOffset; - return -1; - } - b[off] = (byte)returnedVal; - return 1; - } - if (len < bytesLeft) { - if (len <= 0) { - return 0; - } - } - else { - len = bytesLeft; - } - if (b != null) { - System.arraycopy(fData, fOffset, b, off, len); - } - fOffset += len; - return len; - } - - public long skip(long n) - throws IOException - { - int bytesLeft; - if (n <= 0) { - return 0; - } - bytesLeft = fLength - fOffset; - if (bytesLeft == 0) { - if (fOffset == fEndOffset) { - return 0; - } - return fInputStream.skip(n); - } - if (n <= bytesLeft) { - fOffset += n; - return n; - } - fOffset += bytesLeft; - if (fOffset == fEndOffset) { - return bytesLeft; - } - n -= bytesLeft; - /* - * In a manner of speaking, when this class isn't permitting more - * than one byte at a time to be read, it is "blocking". The - * available() method should indicate how much can be read without - * blocking, so while we're in this mode, it should only indicate - * that bytes in its buffer are available; otherwise, the result of - * available() on the underlying InputStream is appropriate. - */ - return fInputStream.skip(n) + bytesLeft; - } - - public int available() throws IOException { - int bytesLeft = fLength - fOffset; - if (bytesLeft == 0) { - if (fOffset == fEndOffset) { - return -1; - } - return fCurrentEntity.mayReadChunks ? fInputStream.available() - : 0; - } - return bytesLeft; - } - - public void mark(int howMuch) { - fMark = fOffset; - } - - public void reset() { - fOffset = fMark; - } - - public boolean markSupported() { - return true; - } - - public void close() throws IOException { - if (fInputStream != null) { - fInputStream.close(); - fInputStream = null; - } - } - } // end of RewindableInputStream class - - // Adapted from: - // org.apache.xerces.impl.XMLDocumentScannerImpl.dispatch - private void scanXMLDecl() throws IOException, JasperException { - - if (skipString(" - *

        -     * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
        -     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
        -     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
        -     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
        -     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
        -     *                 | ('"' ('yes' | 'no') '"'))
        -     *
        -     * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
        -     * 
        - * - * @param scanningTextDecl True if a text declaration is to - * be scanned instead of an XML - * declaration. - */ - private void scanXMLDeclOrTextDecl(boolean scanningTextDecl) - throws IOException, JasperException { - - // scan decl - scanXMLDeclOrTextDecl(scanningTextDecl, fStrings); - fMarkupDepth--; - - // pseudo-attribute values - String encodingPseudoAttr = fStrings[1]; - - // set encoding on reader - if (encodingPseudoAttr != null) { - isEncodingSetInProlog = true; - encoding = encodingPseudoAttr; - } - } - - // Adapted from: - // org.apache.xerces.impl.XMLScanner.scanXMLDeclOrTextDecl - /** - * Scans an XML or text declaration. - *

        - *

        -     * [23] XMLDecl ::= ''
        -     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
        -     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
        -     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
        -     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
        -     *                 | ('"' ('yes' | 'no') '"'))
        -     *
        -     * [77] TextDecl ::= ''
        -     * 
        - * - * @param scanningTextDecl True if a text declaration is to - * be scanned instead of an XML - * declaration. - * @param pseudoAttributeValues An array of size 3 to return the version, - * encoding and standalone pseudo attribute values - * (in that order). - * - * Note: This method uses fString, anything in it - * at the time of calling is lost. - */ - private void scanXMLDeclOrTextDecl(boolean scanningTextDecl, - String[] pseudoAttributeValues) - throws IOException, JasperException { - - // pseudo-attribute values - String version = null; - String encoding = null; - String standalone = null; - - // scan pseudo-attributes - final int STATE_VERSION = 0; - final int STATE_ENCODING = 1; - final int STATE_STANDALONE = 2; - final int STATE_DONE = 3; - int state = STATE_VERSION; - - boolean dataFoundForTarget = false; - boolean sawSpace = skipSpaces(); - while (peekChar() != '?') { - dataFoundForTarget = true; - String name = scanPseudoAttribute(scanningTextDecl, fString); - switch (state) { - case STATE_VERSION: { - if (name == fVersionSymbol) { - if (!sawSpace) { - reportFatalError(scanningTextDecl - ? "jsp.error.xml.spaceRequiredBeforeVersionInTextDecl" - : "jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl", - null); - } - version = fString.toString(); - state = STATE_ENCODING; - if (!version.equals("1.0")) { - // REVISIT: XML REC says we should throw an error - // in such cases. - // some may object the throwing of fatalError. - err.jspError("jsp.error.xml.versionNotSupported", - version); - } - } else if (name == fEncodingSymbol) { - if (!scanningTextDecl) { - err.jspError("jsp.error.xml.versionInfoRequired"); - } - if (!sawSpace) { - reportFatalError(scanningTextDecl - ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" - : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", - null); - } - encoding = fString.toString(); - state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; - } else { - if (scanningTextDecl) { - err.jspError("jsp.error.xml.encodingDeclRequired"); - } - else { - err.jspError("jsp.error.xml.versionInfoRequired"); - } - } - break; - } - case STATE_ENCODING: { - if (name == fEncodingSymbol) { - if (!sawSpace) { - reportFatalError(scanningTextDecl - ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" - : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", - null); - } - encoding = fString.toString(); - state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; - // TODO: check encoding name; set encoding on - // entity scanner - } else if (!scanningTextDecl && name == fStandaloneSymbol) { - if (!sawSpace) { - err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); - } - standalone = fString.toString(); - state = STATE_DONE; - if (!standalone.equals("yes") && !standalone.equals("no")) { - err.jspError("jsp.error.xml.sdDeclInvalid"); - } - } else { - err.jspError("jsp.error.xml.encodingDeclRequired"); - } - break; - } - case STATE_STANDALONE: { - if (name == fStandaloneSymbol) { - if (!sawSpace) { - err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); - } - standalone = fString.toString(); - state = STATE_DONE; - if (!standalone.equals("yes") && !standalone.equals("no")) { - err.jspError("jsp.error.xml.sdDeclInvalid"); - } - } else { - err.jspError("jsp.error.xml.encodingDeclRequired"); - } - break; - } - default: { - err.jspError("jsp.error.xml.noMorePseudoAttributes"); - } - } - sawSpace = skipSpaces(); - } - // REVISIT: should we remove this error reporting? - if (scanningTextDecl && state != STATE_DONE) { - err.jspError("jsp.error.xml.morePseudoAttributes"); - } - - // If there is no data in the xml or text decl then we fail to report - // error for version or encoding info above. - if (scanningTextDecl) { - if (!dataFoundForTarget && encoding == null) { - err.jspError("jsp.error.xml.encodingDeclRequired"); - } - } else { - if (!dataFoundForTarget && version == null) { - err.jspError("jsp.error.xml.versionInfoRequired"); - } - } - - // end - if (!skipChar('?')) { - err.jspError("jsp.error.xml.xmlDeclUnterminated"); - } - if (!skipChar('>')) { - err.jspError("jsp.error.xml.xmlDeclUnterminated"); - - } - - // fill in return array - pseudoAttributeValues[0] = version; - pseudoAttributeValues[1] = encoding; - pseudoAttributeValues[2] = standalone; - } - - // Adapted from: - // org.apache.xerces.impl.XMLScanner.scanPseudoAttribute - /** - * Scans a pseudo attribute. - * - * @param scanningTextDecl True if scanning this pseudo-attribute for a - * TextDecl; false if scanning XMLDecl. This - * flag is needed to report the correct type of - * error. - * @param value The string to fill in with the attribute - * value. - * - * @return The name of the attribute - * - * Note: This method uses fStringBuffer2, anything in it - * at the time of calling is lost. - */ - public String scanPseudoAttribute(boolean scanningTextDecl, - XMLString value) - throws IOException, JasperException { - - String name = scanName(); - if (name == null) { - err.jspError("jsp.error.xml.pseudoAttrNameExpected"); - } - skipSpaces(); - if (!skipChar('=')) { - reportFatalError(scanningTextDecl ? - "jsp.error.xml.eqRequiredInTextDecl" - : "jsp.error.xml.eqRequiredInXMLDecl", - name); - } - skipSpaces(); - int quote = peekChar(); - if (quote != '\'' && quote != '"') { - reportFatalError(scanningTextDecl ? - "jsp.error.xml.quoteRequiredInTextDecl" - : "jsp.error.xml.quoteRequiredInXMLDecl" , - name); - } - scanChar(); - int c = scanLiteral(quote, value); - if (c != quote) { - fStringBuffer2.clear(); - do { - fStringBuffer2.append(value); - if (c != -1) { - if (c == '&' || c == '%' || c == '<' || c == ']') { - fStringBuffer2.append((char)scanChar()); - } - else if (XMLChar.isHighSurrogate(c)) { - scanSurrogates(fStringBuffer2); - } - else if (XMLChar.isInvalid(c)) { - String key = scanningTextDecl - ? "jsp.error.xml.invalidCharInTextDecl" - : "jsp.error.xml.invalidCharInXMLDecl"; - reportFatalError(key, Integer.toString(c, 16)); - scanChar(); - } - } - c = scanLiteral(quote, value); - } while (c != quote); - fStringBuffer2.append(value); - value.setValues(fStringBuffer2); - } - if (!skipChar(quote)) { - reportFatalError(scanningTextDecl ? - "jsp.error.xml.closeQuoteMissingInTextDecl" - : "jsp.error.xml.closeQuoteMissingInXMLDecl", - name); - } - - // return - return name; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLScanner.scanPIData - /** - * Scans a processing data. This is needed to handle the situation - * where a document starts with a processing instruction whose - * target name starts with "xml". (e.g. xmlfoo) - * - * Note: This method uses fStringBuffer, anything in it - * at the time of calling is lost. - * - * @param target The PI target - * @param data The string to fill in with the data - */ - private void scanPIData(String target, XMLString data) - throws IOException, JasperException { - - // check target - if (target.length() == 3) { - char c0 = Character.toLowerCase(target.charAt(0)); - char c1 = Character.toLowerCase(target.charAt(1)); - char c2 = Character.toLowerCase(target.charAt(2)); - if (c0 == 'x' && c1 == 'm' && c2 == 'l') { - err.jspError("jsp.error.xml.reservedPITarget"); - } - } - - // spaces - if (!skipSpaces()) { - if (skipString("?>")) { - // we found the end, there is no data - data.clear(); - return; - } - else { - // if there is data there should be some space - err.jspError("jsp.error.xml.spaceRequiredInPI"); - } - } - - fStringBuffer.clear(); - // data - if (scanData("?>", fStringBuffer)) { - do { - int c = peekChar(); - if (c != -1) { - if (XMLChar.isHighSurrogate(c)) { - scanSurrogates(fStringBuffer); - } else if (XMLChar.isInvalid(c)) { - err.jspError("jsp.error.xml.invalidCharInPI", - Integer.toHexString(c)); - scanChar(); - } - } - } while (scanData("?>", fStringBuffer)); - } - data.setValues(fStringBuffer); - - } - - // Adapted from: - // org.apache.xerces.impl.XMLScanner.scanSurrogates - /** - * Scans surrogates and append them to the specified buffer. - *

        - * Note: This assumes the current char has already been - * identified as a high surrogate. - * - * @param buf The StringBuffer to append the read surrogates to. - * @returns True if it succeeded. - */ - private boolean scanSurrogates(XMLStringBuffer buf) - throws IOException, JasperException { - - int high = scanChar(); - int low = peekChar(); - if (!XMLChar.isLowSurrogate(low)) { - err.jspError("jsp.error.xml.invalidCharInContent", - Integer.toString(high, 16)); - return false; - } - scanChar(); - - // convert surrogates to supplemental character - int c = XMLChar.supplemental((char)high, (char)low); - - // supplemental character must be a valid XML character - if (!XMLChar.isValid(c)) { - err.jspError("jsp.error.xml.invalidCharInContent", - Integer.toString(c, 16)); - return false; - } - - // fill in the buffer - buf.append((char)high); - buf.append((char)low); - - return true; - - } - - // Adapted from: - // org.apache.xerces.impl.XMLScanner.reportFatalError - /** - * Convenience function used in all XML scanners. - */ - private void reportFatalError(String msgId, String arg) - throws JasperException { - err.jspError(msgId, arg); - } - -} - - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +import java.io.EOFException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Locale; +import java.util.jar.JarFile; + +import org.apache.jasper.JasperException; +import org.apache.jasper.JspCompilationContext; +import org.apache.jasper.compiler.ErrorDispatcher; +import org.apache.jasper.compiler.JspUtil; + +public class XMLEncodingDetector { + + private InputStream stream; + private String encoding; + private boolean isEncodingSetInProlog; + private Boolean isBigEndian; + private Reader reader; + + // org.apache.xerces.impl.XMLEntityManager fields + public static final int DEFAULT_BUFFER_SIZE = 2048; + public static final int DEFAULT_XMLDECL_BUFFER_SIZE = 64; + private boolean fAllowJavaEncodings; + private SymbolTable fSymbolTable; + private XMLEncodingDetector fCurrentEntity; + private int fBufferSize = DEFAULT_BUFFER_SIZE; + + // org.apache.xerces.impl.XMLEntityManager.ScannedEntity fields + private int lineNumber = 1; + private int columnNumber = 1; + private boolean literal; + private char[] ch = new char[DEFAULT_BUFFER_SIZE]; + private int position; + private int count; + private boolean mayReadChunks = false; + + // org.apache.xerces.impl.XMLScanner fields + private XMLString fString = new XMLString(); + private XMLStringBuffer fStringBuffer = new XMLStringBuffer(); + private XMLStringBuffer fStringBuffer2 = new XMLStringBuffer(); + private final static String fVersionSymbol = "version"; + private final static String fEncodingSymbol = "encoding"; + private final static String fStandaloneSymbol = "standalone"; + + // org.apache.xerces.impl.XMLDocumentFragmentScannerImpl fields + private int fMarkupDepth = 0; + private String[] fStrings = new String[3]; + + private ErrorDispatcher err; + + /** + * Constructor + */ + public XMLEncodingDetector() { + fSymbolTable = new SymbolTable(); + fCurrentEntity = this; + } + + /** + * Autodetects the encoding of the XML document supplied by the given + * input stream. + * + * Encoding autodetection is done according to the XML 1.0 specification, + * Appendix F.1: Detection Without External Encoding Information. + * + * @return Two-element array, where the first element (of type + * java.lang.String) contains the name of the (auto)detected encoding, and + * the second element (of type java.lang.Boolean) specifies whether the + * encoding was specified using the 'encoding' attribute of an XML prolog + * (TRUE) or autodetected (FALSE). + */ + public static Object[] getEncoding(String fname, JarFile jarFile, + JspCompilationContext ctxt, + ErrorDispatcher err) + throws IOException, JasperException + { + InputStream inStream = JspUtil.getInputStream(fname, jarFile, ctxt, + err); + XMLEncodingDetector detector = new XMLEncodingDetector(); + Object[] ret = detector.getEncoding(inStream, err); + inStream.close(); + + return ret; + } + + private Object[] getEncoding(InputStream in, ErrorDispatcher err) + throws IOException, JasperException + { + this.stream = in; + this.err=err; + createInitialReader(); + scanXMLDecl(); + + return new Object[] { this.encoding, + new Boolean(this.isEncodingSetInProlog) }; + } + + // stub method + void endEntity() { + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.startEntity() + private void createInitialReader() throws IOException, JasperException { + + // wrap this stream in RewindableInputStream + stream = new RewindableInputStream(stream); + + // perform auto-detect of encoding if necessary + if (encoding == null) { + // read first four bytes and determine encoding + final byte[] b4 = new byte[4]; + int count = 0; + for (; count<4; count++ ) { + b4[count] = (byte)stream.read(); + } + if (count == 4) { + Object [] encodingDesc = getEncodingName(b4, count); + encoding = (String)(encodingDesc[0]); + isBigEndian = (Boolean)(encodingDesc[1]); + + stream.reset(); + // Special case UTF-8 files with BOM created by Microsoft + // tools. It's more efficient to consume the BOM than make + // the reader perform extra checks. -Ac + if (count > 2 && encoding.equals("UTF-8")) { + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + // ignore first three bytes... + stream.skip(3); + } + } + reader = createReader(stream, encoding, isBigEndian); + } else { + reader = createReader(stream, encoding, isBigEndian); + } + } + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.createReader + /** + * Creates a reader capable of reading the given input stream in + * the specified encoding. + * + * @param inputStream The input stream. + * @param encoding The encoding name that the input stream is + * encoded using. If the user has specified that + * Java encoding names are allowed, then the + * encoding name may be a Java encoding name; + * otherwise, it is an ianaEncoding name. + * @param isBigEndian For encodings (like uCS-4), whose names cannot + * specify a byte order, this tells whether the order + * is bigEndian. null means unknown or not relevant. + * + * @return Returns a reader. + */ + private Reader createReader(InputStream inputStream, String encoding, + Boolean isBigEndian) + throws IOException, JasperException { + + // normalize encoding name + if (encoding == null) { + encoding = "UTF-8"; + } + + // try to use an optimized reader + String ENCODING = encoding.toUpperCase(Locale.ENGLISH); + if (ENCODING.equals("UTF-8")) { + return new UTF8Reader(inputStream, fBufferSize); + } + if (ENCODING.equals("US-ASCII")) { + return new ASCIIReader(inputStream, fBufferSize); + } + if (ENCODING.equals("ISO-10646-UCS-4")) { + if (isBigEndian != null) { + boolean isBE = isBigEndian.booleanValue(); + if (isBE) { + return new UCSReader(inputStream, UCSReader.UCS4BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS4LE); + } + } else { + err.jspError("jsp.error.xml.encodingByteOrderUnsupported", + encoding); + } + } + if (ENCODING.equals("ISO-10646-UCS-2")) { + if (isBigEndian != null) { // sould never happen with this encoding... + boolean isBE = isBigEndian.booleanValue(); + if (isBE) { + return new UCSReader(inputStream, UCSReader.UCS2BE); + } else { + return new UCSReader(inputStream, UCSReader.UCS2LE); + } + } else { + err.jspError("jsp.error.xml.encodingByteOrderUnsupported", + encoding); + } + } + + // check for valid name + boolean validIANA = XMLChar.isValidIANAEncoding(encoding); + boolean validJava = XMLChar.isValidJavaEncoding(encoding); + if (!validIANA || (fAllowJavaEncodings && !validJava)) { + err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); + // NOTE: AndyH suggested that, on failure, we use ISO Latin 1 + // because every byte is a valid ISO Latin 1 character. + // It may not translate correctly but if we failed on + // the encoding anyway, then we're expecting the content + // of the document to be bad. This will just prevent an + // invalid UTF-8 sequence to be detected. This is only + // important when continue-after-fatal-error is turned + // on. -Ac + encoding = "ISO-8859-1"; + } + + // try to use a Java reader + String javaEncoding = EncodingMap.getIANA2JavaMapping(ENCODING); + if (javaEncoding == null) { + if (fAllowJavaEncodings) { + javaEncoding = encoding; + } else { + err.jspError("jsp.error.xml.encodingDeclInvalid", encoding); + // see comment above. + javaEncoding = "ISO8859_1"; + } + } + return new InputStreamReader(inputStream, javaEncoding); + + } // createReader(InputStream,String, Boolean): Reader + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.getEncodingName + /** + * Returns the IANA encoding name that is auto-detected from + * the bytes specified, with the endian-ness of that encoding where + * appropriate. + * + * @param b4 The first four bytes of the input. + * @param count The number of bytes actually read. + * @return a 2-element array: the first element, an IANA-encoding string, + * the second element a Boolean which is true iff the document is big + * endian, false if it's little-endian, and null if the distinction isn't + * relevant. + */ + private Object[] getEncodingName(byte[] b4, int count) { + + if (count < 2) { + return new Object[]{"UTF-8", null}; + } + + // UTF-16, with BOM + int b0 = b4[0] & 0xFF; + int b1 = b4[1] & 0xFF; + if (b0 == 0xFE && b1 == 0xFF) { + // UTF-16, big-endian + return new Object [] {"UTF-16BE", new Boolean(true)}; + } + if (b0 == 0xFF && b1 == 0xFE) { + // UTF-16, little-endian + return new Object [] {"UTF-16LE", new Boolean(false)}; + } + + // default to UTF-8 if we don't have enough bytes to make a + // good determination of the encoding + if (count < 3) { + return new Object [] {"UTF-8", null}; + } + + // UTF-8 with a BOM + int b2 = b4[2] & 0xFF; + if (b0 == 0xEF && b1 == 0xBB && b2 == 0xBF) { + return new Object [] {"UTF-8", null}; + } + + // default to UTF-8 if we don't have enough bytes to make a + // good determination of the encoding + if (count < 4) { + return new Object [] {"UTF-8", null}; + } + + // other encodings + int b3 = b4[3] & 0xFF; + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x00 && b3 == 0x3C) { + // UCS-4, big endian (1234) + return new Object [] {"ISO-10646-UCS-4", new Boolean(true)}; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x00 && b3 == 0x00) { + // UCS-4, little endian (4321) + return new Object [] {"ISO-10646-UCS-4", new Boolean(false)}; + } + if (b0 == 0x00 && b1 == 0x00 && b2 == 0x3C && b3 == 0x00) { + // UCS-4, unusual octet order (2143) + // REVISIT: What should this be? + return new Object [] {"ISO-10646-UCS-4", null}; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x00) { + // UCS-4, unusual octect order (3412) + // REVISIT: What should this be? + return new Object [] {"ISO-10646-UCS-4", null}; + } + if (b0 == 0x00 && b1 == 0x3C && b2 == 0x00 && b3 == 0x3F) { + // UTF-16, big-endian, no BOM + // (or could turn out to be UCS-2... + // REVISIT: What should this be? + return new Object [] {"UTF-16BE", new Boolean(true)}; + } + if (b0 == 0x3C && b1 == 0x00 && b2 == 0x3F && b3 == 0x00) { + // UTF-16, little-endian, no BOM + // (or could turn out to be UCS-2... + return new Object [] {"UTF-16LE", new Boolean(false)}; + } + if (b0 == 0x4C && b1 == 0x6F && b2 == 0xA7 && b3 == 0x94) { + // EBCDIC + // a la xerces1, return CP037 instead of EBCDIC here + return new Object [] {"CP037", null}; + } + + // default encoding + return new Object [] {"UTF-8", null}; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.isExternal + /** Returns true if the current entity being scanned is external. */ + public boolean isExternal() { + return true; + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.peekChar + /** + * Returns the next character on the input. + *

        + * Note: The character is not consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int peekChar() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // peek at character + int c = fCurrentEntity.ch[fCurrentEntity.position]; + + // return peeked character + if (fCurrentEntity.isExternal()) { + return c != '\r' ? c : '\n'; + } + else { + return c; + } + + } // peekChar():int + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanChar + /** + * Returns the next character on the input. + *

        + * Note: The character is consumed. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanChar() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan character + int c = fCurrentEntity.ch[fCurrentEntity.position++]; + boolean external = false; + if (c == '\n' || + (c == '\r' && (external = fCurrentEntity.isExternal()))) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)c; + load(1, false); + } + if (c == '\r' && external) { + if (fCurrentEntity.ch[fCurrentEntity.position++] != '\n') { + fCurrentEntity.position--; + } + c = '\n'; + } + } + + // return character that was scanned + fCurrentEntity.columnNumber++; + return c; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanName + /** + * Returns a string matching the Name production appearing immediately + * on the input as a symbol, or null if no Name string is present. + *

        + * Note: The Name characters are consumed. + *

        + * Note: The string returned must be a symbol. The + * SymbolTable can be used for this purpose. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see SymbolTable + * @see XMLChar#isName + * @see XMLChar#isNameStart + */ + public String scanName() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // scan name + int offset = fCurrentEntity.position; + if (XMLChar.isNameStart(fCurrentEntity.ch[offset])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[offset]; + offset = 0; + if (load(1, false)) { + fCurrentEntity.columnNumber++; + String symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, + 0, 1); + return symbol; + } + } + while (XMLChar.isName(fCurrentEntity.ch[fCurrentEntity.position])) { + if (++fCurrentEntity.position == fCurrentEntity.count) { + int length = fCurrentEntity.position - offset; + if (length == fBufferSize) { + // bad luck we have to resize our buffer + char[] tmp = new char[fBufferSize * 2]; + System.arraycopy(fCurrentEntity.ch, offset, + tmp, 0, length); + fCurrentEntity.ch = tmp; + fBufferSize *= 2; + } else { + System.arraycopy(fCurrentEntity.ch, offset, + fCurrentEntity.ch, 0, length); + } + offset = 0; + if (load(length, false)) { + break; + } + } + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length; + + // return name + String symbol = null; + if (length > 0) { + symbol = fSymbolTable.addSymbol(fCurrentEntity.ch, offset, length); + } + return symbol; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.scanLiteral + /** + * Scans a range of attribute value data, setting the fields of the + * XMLString structure, appropriately. + *

        + * Note: The characters are consumed. + *

        + * Note: This method does not guarantee to return + * the longest run of attribute value data. This method may return + * before the quote character due to reaching the end of the input + * buffer or any other reason. + *

        + * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param quote The quote character that signifies the end of the + * attribute value data. + * @param content The content structure to fill. + * + * @return Returns the next character on the input, if known. This + * value may be -1 but this does note designate + * end of file. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public int scanLiteral(int quote, XMLString content) + throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } else if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = fCurrentEntity.ch[fCurrentEntity.count - 1]; + load(1, false); + fCurrentEntity.position = 0; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + boolean external = fCurrentEntity.isExternal(); + if (c == '\n' || (c == '\r' && external)) { + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == '\r' && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.position = newlines; + if (load(newlines, false)) { + break; + } + } + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + /***/ + } + else if (c == '\n') { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.position = newlines; + if (load(newlines, false)) { + break; + } + } + /*** NEWLINE NORMALIZATION *** + if (fCurrentEntity.ch[fCurrentEntity.position] == '\r' + && external) { + fCurrentEntity.position++; + offset++; + } + /***/ + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + content.setValues(fCurrentEntity.ch, offset, length); + return -1; + } + } + + // scan literal value + while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if ((c == quote && + (!fCurrentEntity.literal || external)) + || c == '%' || !XMLChar.isContent(c)) { + fCurrentEntity.position--; + break; + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + content.setValues(fCurrentEntity.ch, offset, length); + + // return next character + if (fCurrentEntity.position != fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position]; + // NOTE: We don't want to accidentally signal the + // end of the literal if we're expanding an + // entity appearing in the literal. -Ac + if (c == quote && fCurrentEntity.literal) { + c = -1; + } + } + else { + c = -1; + } + return c; + + } + + /** + * Scans a range of character data up to the specified delimiter, + * setting the fields of the XMLString structure, appropriately. + *

        + * Note: The characters are consumed. + *

        + * Note: This assumes that the internal buffer is + * at least the same size, or bigger, than the length of the delimiter + * and that the delimiter contains at least one character. + *

        + * Note: This method does not guarantee to return + * the longest run of character data. This method may return before + * the delimiter due to reaching the end of the input buffer or any + * other reason. + *

        + * Note: The fields contained in the XMLString + * structure are not guaranteed to remain valid upon subsequent calls + * to the entity scanner. Therefore, the caller is responsible for + * immediately using the returned character data or making a copy of + * the character data. + * + * @param delimiter The string that signifies the end of the character + * data to be scanned. + * @param buffer The data structure to fill. + * + * @return Returns true if there is more data to scan, false otherwise. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean scanData(String delimiter, XMLStringBuffer buffer) + throws IOException { + + boolean done = false; + int delimLen = delimiter.length(); + char charAt0 = delimiter.charAt(0); + boolean external = fCurrentEntity.isExternal(); + do { + + // load more characters, if needed + + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + else if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { + System.arraycopy(fCurrentEntity.ch, fCurrentEntity.position, + fCurrentEntity.ch, 0, fCurrentEntity.count - fCurrentEntity.position); + load(fCurrentEntity.count - fCurrentEntity.position, false); + fCurrentEntity.position = 0; + } + if (fCurrentEntity.position >= fCurrentEntity.count - delimLen) { + // something must be wrong with the input: e.g., file ends an + // unterminated comment + int length = fCurrentEntity.count - fCurrentEntity.position; + buffer.append (fCurrentEntity.ch, fCurrentEntity.position, + length); + fCurrentEntity.columnNumber += fCurrentEntity.count; + fCurrentEntity.position = fCurrentEntity.count; + load(0,true); + return false; + } + + // normalize newlines + int offset = fCurrentEntity.position; + int c = fCurrentEntity.ch[offset]; + int newlines = 0; + if (c == '\n' || (c == '\r' && external)) { + do { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == '\r' && external) { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.position = newlines; + if (load(newlines, false)) { + break; + } + } + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + offset++; + } + /*** NEWLINE NORMALIZATION ***/ + else { + newlines++; + } + } + else if (c == '\n') { + newlines++; + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count) { + offset = 0; + fCurrentEntity.position = newlines; + fCurrentEntity.count = newlines; + if (load(newlines, false)) { + break; + } + } + } + else { + fCurrentEntity.position--; + break; + } + } while (fCurrentEntity.position < fCurrentEntity.count - 1); + for (int i = offset; i < fCurrentEntity.position; i++) { + fCurrentEntity.ch[i] = '\n'; + } + int length = fCurrentEntity.position - offset; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + + // iterate over buffer looking for delimiter + OUTER: while (fCurrentEntity.position < fCurrentEntity.count) { + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c == charAt0) { + // looks like we just hit the delimiter + int delimOffset = fCurrentEntity.position - 1; + for (int i = 1; i < delimLen; i++) { + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.position -= i; + break OUTER; + } + c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (delimiter.charAt(i) != c) { + fCurrentEntity.position--; + break; + } + } + if (fCurrentEntity.position == delimOffset + delimLen) { + done = true; + break; + } + } + else if (c == '\n' || (external && c == '\r')) { + fCurrentEntity.position--; + break; + } + else if (XMLChar.isInvalid(c)) { + fCurrentEntity.position--; + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + buffer.append(fCurrentEntity.ch, offset, length); + return true; + } + } + int length = fCurrentEntity.position - offset; + fCurrentEntity.columnNumber += length - newlines; + if (done) { + length -= delimLen; + } + buffer.append (fCurrentEntity.ch, offset, length); + + // return true if string was skipped + } while (!done); + return !done; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipChar + /** + * Skips a character appearing immediately on the input. + *

        + * Note: The character is consumed only if it matches + * the specified character. + * + * @param c The character to skip. + * + * @return Returns true if the character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipChar(int c) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip character + int cc = fCurrentEntity.ch[fCurrentEntity.position]; + if (cc == c) { + fCurrentEntity.position++; + if (c == '\n') { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + } + else { + fCurrentEntity.columnNumber++; + } + return true; + } else if (c == '\n' && cc == '\r' && fCurrentEntity.isExternal()) { + // handle newlines + if (fCurrentEntity.position == fCurrentEntity.count) { + fCurrentEntity.ch[0] = (char)cc; + load(1, false); + } + fCurrentEntity.position++; + if (fCurrentEntity.ch[fCurrentEntity.position] == '\n') { + fCurrentEntity.position++; + } + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + return true; + } + + // character was not skipped + return false; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.skipSpaces + /** + * Skips space characters appearing immediately on the input. + *

        + * Note: The characters are consumed only if they are + * space characters. + * + * @return Returns true if at least one space character was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + * + * @see XMLChar#isSpace + */ + public boolean skipSpaces() throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip spaces + int c = fCurrentEntity.ch[fCurrentEntity.position]; + if (XMLChar.isSpace(c)) { + boolean external = fCurrentEntity.isExternal(); + do { + boolean entityChanged = false; + // handle newlines + if (c == '\n' || (external && c == '\r')) { + fCurrentEntity.lineNumber++; + fCurrentEntity.columnNumber = 1; + if (fCurrentEntity.position == fCurrentEntity.count - 1) { + fCurrentEntity.ch[0] = (char)c; + entityChanged = load(1, true); + if (!entityChanged) + // the load change the position to be 1, + // need to restore it when entity not changed + fCurrentEntity.position = 0; + } + if (c == '\r' && external) { + // REVISIT: Does this need to be updated to fix the + // #x0D ^#x0A newline normalization problem? -Ac + if (fCurrentEntity.ch[++fCurrentEntity.position] != '\n') { + fCurrentEntity.position--; + } + } + /*** NEWLINE NORMALIZATION *** + else { + if (fCurrentEntity.ch[fCurrentEntity.position + 1] == '\r' + && external) { + fCurrentEntity.position++; + } + } + /***/ + } + else { + fCurrentEntity.columnNumber++; + } + // load more characters, if needed + if (!entityChanged) + fCurrentEntity.position++; + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + } while (XMLChar.isSpace(c = fCurrentEntity.ch[fCurrentEntity.position])); + return true; + } + + // no spaces were found + return false; + + } + + /** + * Skips the specified string appearing immediately on the input. + *

        + * Note: The characters are consumed only if they are + * space characters. + * + * @param s The string to skip. + * + * @return Returns true if the string was skipped. + * + * @throws IOException Thrown if i/o error occurs. + * @throws EOFException Thrown on end of file. + */ + public boolean skipString(String s) throws IOException { + + // load more characters, if needed + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, true); + } + + // skip string + final int length = s.length(); + for (int i = 0; i < length; i++) { + char c = fCurrentEntity.ch[fCurrentEntity.position++]; + if (c != s.charAt(i)) { + fCurrentEntity.position -= i + 1; + return false; + } + if (i < length - 1 && fCurrentEntity.position == fCurrentEntity.count) { + System.arraycopy(fCurrentEntity.ch, fCurrentEntity.count - i - 1, fCurrentEntity.ch, 0, i + 1); + // REVISIT: Can a string to be skipped cross an + // entity boundary? -Ac + if (load(i + 1, false)) { + fCurrentEntity.position -= i + 1; + return false; + } + } + } + fCurrentEntity.columnNumber += length; + return true; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.EntityScanner.load + /** + * Loads a chunk of text. + * + * @param offset The offset into the character buffer to + * read the next batch of characters. + * @param changeEntity True if the load should change entities + * at the end of the entity, otherwise leave + * the current entity in place and the entity + * boundary will be signaled by the return + * value. + * + * @returns Returns true if the entity changed as a result of this + * load operation. + */ + final boolean load(int offset, boolean changeEntity) + throws IOException { + + // read characters + int length = fCurrentEntity.mayReadChunks? + (fCurrentEntity.ch.length - offset): + (DEFAULT_XMLDECL_BUFFER_SIZE); + int count = fCurrentEntity.reader.read(fCurrentEntity.ch, offset, + length); + + // reset count and position + boolean entityChanged = false; + if (count != -1) { + if (count != 0) { + fCurrentEntity.count = count + offset; + fCurrentEntity.position = offset; + } + } + + // end of this entity + else { + fCurrentEntity.count = offset; + fCurrentEntity.position = offset; + entityChanged = true; + if (changeEntity) { + endEntity(); + if (fCurrentEntity == null) { + throw new EOFException(); + } + // handle the trailing edges + if (fCurrentEntity.position == fCurrentEntity.count) { + load(0, false); + } + } + } + + return entityChanged; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLEntityManager.RewindableInputStream + /** + * This class wraps the byte inputstreams we're presented with. + * We need it because java.io.InputStreams don't provide + * functionality to reread processed bytes, and they have a habit + * of reading more than one character when you call their read() + * methods. This means that, once we discover the true (declared) + * encoding of a document, we can neither backtrack to read the + * whole doc again nor start reading where we are with a new + * reader. + * + * This class allows rewinding an inputStream by allowing a mark + * to be set, and the stream reset to that position. The + * class assumes that it needs to read one character per + * invocation when it's read() method is inovked, but uses the + * underlying InputStream's read(char[], offset length) method--it + * won't buffer data read this way! + * + * @author Neil Graham, IBM + * @author Glenn Marcy, IBM + */ + private final class RewindableInputStream extends InputStream { + + private InputStream fInputStream; + private byte[] fData; + private int fStartOffset; + private int fEndOffset; + private int fOffset; + private int fLength; + private int fMark; + + public RewindableInputStream(InputStream is) { + fData = new byte[DEFAULT_XMLDECL_BUFFER_SIZE]; + fInputStream = is; + fStartOffset = 0; + fEndOffset = -1; + fOffset = 0; + fLength = 0; + fMark = 0; + } + + public void setStartOffset(int offset) { + fStartOffset = offset; + } + + public void rewind() { + fOffset = fStartOffset; + } + + public int read() throws IOException { + int b = 0; + if (fOffset < fLength) { + return fData[fOffset++] & 0xff; + } + if (fOffset == fEndOffset) { + return -1; + } + if (fOffset == fData.length) { + byte[] newData = new byte[fOffset << 1]; + System.arraycopy(fData, 0, newData, 0, fOffset); + fData = newData; + } + b = fInputStream.read(); + if (b == -1) { + fEndOffset = fOffset; + return -1; + } + fData[fLength++] = (byte)b; + fOffset++; + return b & 0xff; + } + + public int read(byte[] b, int off, int len) throws IOException { + int bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return -1; + } + // better get some more for the voracious reader... + if (fCurrentEntity.mayReadChunks) { + return fInputStream.read(b, off, len); + } + int returnedVal = read(); + if (returnedVal == -1) { + fEndOffset = fOffset; + return -1; + } + b[off] = (byte)returnedVal; + return 1; + } + if (len < bytesLeft) { + if (len <= 0) { + return 0; + } + } + else { + len = bytesLeft; + } + if (b != null) { + System.arraycopy(fData, fOffset, b, off, len); + } + fOffset += len; + return len; + } + + public long skip(long n) + throws IOException + { + int bytesLeft; + if (n <= 0) { + return 0; + } + bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return 0; + } + return fInputStream.skip(n); + } + if (n <= bytesLeft) { + fOffset += n; + return n; + } + fOffset += bytesLeft; + if (fOffset == fEndOffset) { + return bytesLeft; + } + n -= bytesLeft; + /* + * In a manner of speaking, when this class isn't permitting more + * than one byte at a time to be read, it is "blocking". The + * available() method should indicate how much can be read without + * blocking, so while we're in this mode, it should only indicate + * that bytes in its buffer are available; otherwise, the result of + * available() on the underlying InputStream is appropriate. + */ + return fInputStream.skip(n) + bytesLeft; + } + + public int available() throws IOException { + int bytesLeft = fLength - fOffset; + if (bytesLeft == 0) { + if (fOffset == fEndOffset) { + return -1; + } + return fCurrentEntity.mayReadChunks ? fInputStream.available() + : 0; + } + return bytesLeft; + } + + public void mark(int howMuch) { + fMark = fOffset; + } + + public void reset() { + fOffset = fMark; + } + + public boolean markSupported() { + return true; + } + + public void close() throws IOException { + if (fInputStream != null) { + fInputStream.close(); + fInputStream = null; + } + } + } // end of RewindableInputStream class + + // Adapted from: + // org.apache.xerces.impl.XMLDocumentScannerImpl.dispatch + private void scanXMLDecl() throws IOException, JasperException { + + if (skipString(" + *

        +     * [23] XMLDecl ::= '<?xml' VersionInfo EncodingDecl? SDDecl? S? '?>'
        +     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
        +     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
        +     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
        +     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
        +     *                 | ('"' ('yes' | 'no') '"'))
        +     *
        +     * [77] TextDecl ::= '<?xml' VersionInfo? EncodingDecl S? '?>'
        +     * 
        + * + * @param scanningTextDecl True if a text declaration is to + * be scanned instead of an XML + * declaration. + */ + private void scanXMLDeclOrTextDecl(boolean scanningTextDecl) + throws IOException, JasperException { + + // scan decl + scanXMLDeclOrTextDecl(scanningTextDecl, fStrings); + fMarkupDepth--; + + // pseudo-attribute values + String encodingPseudoAttr = fStrings[1]; + + // set encoding on reader + if (encodingPseudoAttr != null) { + isEncodingSetInProlog = true; + encoding = encodingPseudoAttr; + } + } + + // Adapted from: + // org.apache.xerces.impl.XMLScanner.scanXMLDeclOrTextDecl + /** + * Scans an XML or text declaration. + *

        + *

        +     * [23] XMLDecl ::= ''
        +     * [24] VersionInfo ::= S 'version' Eq (' VersionNum ' | " VersionNum ")
        +     * [80] EncodingDecl ::= S 'encoding' Eq ('"' EncName '"' |  "'" EncName "'" )
        +     * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
        +     * [32] SDDecl ::= S 'standalone' Eq (("'" ('yes' | 'no') "'")
        +     *                 | ('"' ('yes' | 'no') '"'))
        +     *
        +     * [77] TextDecl ::= ''
        +     * 
        + * + * @param scanningTextDecl True if a text declaration is to + * be scanned instead of an XML + * declaration. + * @param pseudoAttributeValues An array of size 3 to return the version, + * encoding and standalone pseudo attribute values + * (in that order). + * + * Note: This method uses fString, anything in it + * at the time of calling is lost. + */ + private void scanXMLDeclOrTextDecl(boolean scanningTextDecl, + String[] pseudoAttributeValues) + throws IOException, JasperException { + + // pseudo-attribute values + String version = null; + String encoding = null; + String standalone = null; + + // scan pseudo-attributes + final int STATE_VERSION = 0; + final int STATE_ENCODING = 1; + final int STATE_STANDALONE = 2; + final int STATE_DONE = 3; + int state = STATE_VERSION; + + boolean dataFoundForTarget = false; + boolean sawSpace = skipSpaces(); + while (peekChar() != '?') { + dataFoundForTarget = true; + String name = scanPseudoAttribute(scanningTextDecl, fString); + switch (state) { + case STATE_VERSION: { + if (name == fVersionSymbol) { + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "jsp.error.xml.spaceRequiredBeforeVersionInTextDecl" + : "jsp.error.xml.spaceRequiredBeforeVersionInXMLDecl", + null); + } + version = fString.toString(); + state = STATE_ENCODING; + if (!version.equals("1.0")) { + // REVISIT: XML REC says we should throw an error + // in such cases. + // some may object the throwing of fatalError. + err.jspError("jsp.error.xml.versionNotSupported", + version); + } + } else if (name == fEncodingSymbol) { + if (!scanningTextDecl) { + err.jspError("jsp.error.xml.versionInfoRequired"); + } + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" + : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", + null); + } + encoding = fString.toString(); + state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; + } else { + if (scanningTextDecl) { + err.jspError("jsp.error.xml.encodingDeclRequired"); + } + else { + err.jspError("jsp.error.xml.versionInfoRequired"); + } + } + break; + } + case STATE_ENCODING: { + if (name == fEncodingSymbol) { + if (!sawSpace) { + reportFatalError(scanningTextDecl + ? "jsp.error.xml.spaceRequiredBeforeEncodingInTextDecl" + : "jsp.error.xml.spaceRequiredBeforeEncodingInXMLDecl", + null); + } + encoding = fString.toString(); + state = scanningTextDecl ? STATE_DONE : STATE_STANDALONE; + // TODO: check encoding name; set encoding on + // entity scanner + } else if (!scanningTextDecl && name == fStandaloneSymbol) { + if (!sawSpace) { + err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); + } + standalone = fString.toString(); + state = STATE_DONE; + if (!standalone.equals("yes") && !standalone.equals("no")) { + err.jspError("jsp.error.xml.sdDeclInvalid"); + } + } else { + err.jspError("jsp.error.xml.encodingDeclRequired"); + } + break; + } + case STATE_STANDALONE: { + if (name == fStandaloneSymbol) { + if (!sawSpace) { + err.jspError("jsp.error.xml.spaceRequiredBeforeStandalone"); + } + standalone = fString.toString(); + state = STATE_DONE; + if (!standalone.equals("yes") && !standalone.equals("no")) { + err.jspError("jsp.error.xml.sdDeclInvalid"); + } + } else { + err.jspError("jsp.error.xml.encodingDeclRequired"); + } + break; + } + default: { + err.jspError("jsp.error.xml.noMorePseudoAttributes"); + } + } + sawSpace = skipSpaces(); + } + // REVISIT: should we remove this error reporting? + if (scanningTextDecl && state != STATE_DONE) { + err.jspError("jsp.error.xml.morePseudoAttributes"); + } + + // If there is no data in the xml or text decl then we fail to report + // error for version or encoding info above. + if (scanningTextDecl) { + if (!dataFoundForTarget && encoding == null) { + err.jspError("jsp.error.xml.encodingDeclRequired"); + } + } else { + if (!dataFoundForTarget && version == null) { + err.jspError("jsp.error.xml.versionInfoRequired"); + } + } + + // end + if (!skipChar('?')) { + err.jspError("jsp.error.xml.xmlDeclUnterminated"); + } + if (!skipChar('>')) { + err.jspError("jsp.error.xml.xmlDeclUnterminated"); + + } + + // fill in return array + pseudoAttributeValues[0] = version; + pseudoAttributeValues[1] = encoding; + pseudoAttributeValues[2] = standalone; + } + + // Adapted from: + // org.apache.xerces.impl.XMLScanner.scanPseudoAttribute + /** + * Scans a pseudo attribute. + * + * @param scanningTextDecl True if scanning this pseudo-attribute for a + * TextDecl; false if scanning XMLDecl. This + * flag is needed to report the correct type of + * error. + * @param value The string to fill in with the attribute + * value. + * + * @return The name of the attribute + * + * Note: This method uses fStringBuffer2, anything in it + * at the time of calling is lost. + */ + public String scanPseudoAttribute(boolean scanningTextDecl, + XMLString value) + throws IOException, JasperException { + + String name = scanName(); + if (name == null) { + err.jspError("jsp.error.xml.pseudoAttrNameExpected"); + } + skipSpaces(); + if (!skipChar('=')) { + reportFatalError(scanningTextDecl ? + "jsp.error.xml.eqRequiredInTextDecl" + : "jsp.error.xml.eqRequiredInXMLDecl", + name); + } + skipSpaces(); + int quote = peekChar(); + if (quote != '\'' && quote != '"') { + reportFatalError(scanningTextDecl ? + "jsp.error.xml.quoteRequiredInTextDecl" + : "jsp.error.xml.quoteRequiredInXMLDecl" , + name); + } + scanChar(); + int c = scanLiteral(quote, value); + if (c != quote) { + fStringBuffer2.clear(); + do { + fStringBuffer2.append(value); + if (c != -1) { + if (c == '&' || c == '%' || c == '<' || c == ']') { + fStringBuffer2.append((char)scanChar()); + } + else if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer2); + } + else if (XMLChar.isInvalid(c)) { + String key = scanningTextDecl + ? "jsp.error.xml.invalidCharInTextDecl" + : "jsp.error.xml.invalidCharInXMLDecl"; + reportFatalError(key, Integer.toString(c, 16)); + scanChar(); + } + } + c = scanLiteral(quote, value); + } while (c != quote); + fStringBuffer2.append(value); + value.setValues(fStringBuffer2); + } + if (!skipChar(quote)) { + reportFatalError(scanningTextDecl ? + "jsp.error.xml.closeQuoteMissingInTextDecl" + : "jsp.error.xml.closeQuoteMissingInXMLDecl", + name); + } + + // return + return name; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLScanner.scanPIData + /** + * Scans a processing data. This is needed to handle the situation + * where a document starts with a processing instruction whose + * target name starts with "xml". (e.g. xmlfoo) + * + * Note: This method uses fStringBuffer, anything in it + * at the time of calling is lost. + * + * @param target The PI target + * @param data The string to fill in with the data + */ + private void scanPIData(String target, XMLString data) + throws IOException, JasperException { + + // check target + if (target.length() == 3) { + char c0 = Character.toLowerCase(target.charAt(0)); + char c1 = Character.toLowerCase(target.charAt(1)); + char c2 = Character.toLowerCase(target.charAt(2)); + if (c0 == 'x' && c1 == 'm' && c2 == 'l') { + err.jspError("jsp.error.xml.reservedPITarget"); + } + } + + // spaces + if (!skipSpaces()) { + if (skipString("?>")) { + // we found the end, there is no data + data.clear(); + return; + } + else { + // if there is data there should be some space + err.jspError("jsp.error.xml.spaceRequiredInPI"); + } + } + + fStringBuffer.clear(); + // data + if (scanData("?>", fStringBuffer)) { + do { + int c = peekChar(); + if (c != -1) { + if (XMLChar.isHighSurrogate(c)) { + scanSurrogates(fStringBuffer); + } else if (XMLChar.isInvalid(c)) { + err.jspError("jsp.error.xml.invalidCharInPI", + Integer.toHexString(c)); + scanChar(); + } + } + } while (scanData("?>", fStringBuffer)); + } + data.setValues(fStringBuffer); + + } + + // Adapted from: + // org.apache.xerces.impl.XMLScanner.scanSurrogates + /** + * Scans surrogates and append them to the specified buffer. + *

        + * Note: This assumes the current char has already been + * identified as a high surrogate. + * + * @param buf The StringBuffer to append the read surrogates to. + * @returns True if it succeeded. + */ + private boolean scanSurrogates(XMLStringBuffer buf) + throws IOException, JasperException { + + int high = scanChar(); + int low = peekChar(); + if (!XMLChar.isLowSurrogate(low)) { + err.jspError("jsp.error.xml.invalidCharInContent", + Integer.toString(high, 16)); + return false; + } + scanChar(); + + // convert surrogates to supplemental character + int c = XMLChar.supplemental((char)high, (char)low); + + // supplemental character must be a valid XML character + if (!XMLChar.isValid(c)) { + err.jspError("jsp.error.xml.invalidCharInContent", + Integer.toString(c, 16)); + return false; + } + + // fill in the buffer + buf.append((char)high); + buf.append((char)low); + + return true; + + } + + // Adapted from: + // org.apache.xerces.impl.XMLScanner.reportFatalError + /** + * Convenience function used in all XML scanners. + */ + private void reportFatalError(String msgId, String arg) + throws JasperException { + err.jspError(msgId, arg); + } + +} + + diff --git a/java/org/apache/jasper/xmlparser/XMLString.java b/java/org/apache/jasper/xmlparser/XMLString.java index 98e083aac..54ee60e71 100644 --- a/java/org/apache/jasper/xmlparser/XMLString.java +++ b/java/org/apache/jasper/xmlparser/XMLString.java @@ -1,196 +1,196 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -/** - * This class is used as a structure to pass text contained in the underlying - * character buffer of the scanner. The offset and length fields allow the - * buffer to be re-used without creating new character arrays. - *

        - * Note: Methods that are passed an XMLString structure - * should consider the contents read-only and not make any modifications - * to the contents of the buffer. The method receiving this structure - * should also not modify the offset and length if this structure (or - * the values of this structure) are passed to another method. - *

        - * Note: Methods that are passed an XMLString structure - * are required to copy the information out of the buffer if it is to be - * saved for use beyond the scope of the method. The contents of the - * structure are volatile and the contents of the character buffer cannot - * be assured once the method that is passed this structure returns. - * Therefore, methods passed this structure should not save any reference - * to the structure or the character array contained in the structure. - * - * @author Eric Ye, IBM - * @author Andy Clark, IBM - * - * @version $Id: XMLString.java 306086 2004-10-01 19:24:35Z luehe $ - */ -public class XMLString { - - // - // Data - // - - /** The character array. */ - public char[] ch; - - /** The offset into the character array. */ - public int offset; - - /** The length of characters from the offset. */ - public int length; - - // - // Constructors - // - - /** Default constructor. */ - public XMLString() { - } // () - - /** - * Constructs an XMLString structure preset with the specified - * values. - * - * @param ch The character array. - * @param offset The offset into the character array. - * @param length The length of characters from the offset. - */ - public XMLString(char[] ch, int offset, int length) { - setValues(ch, offset, length); - } // (char[],int,int) - - /** - * Constructs an XMLString structure with copies of the values in - * the given structure. - *

        - * Note: This does not copy the character array; - * only the reference to the array is copied. - * - * @param string The XMLString to copy. - */ - public XMLString(XMLString string) { - setValues(string); - } // (XMLString) - - // - // Public methods - // - - /** - * Initializes the contents of the XMLString structure with the - * specified values. - * - * @param ch The character array. - * @param offset The offset into the character array. - * @param length The length of characters from the offset. - */ - public void setValues(char[] ch, int offset, int length) { - this.ch = ch; - this.offset = offset; - this.length = length; - } // setValues(char[],int,int) - - /** - * Initializes the contents of the XMLString structure with copies - * of the given string structure. - *

        - * Note: This does not copy the character array; - * only the reference to the array is copied. - * - * @param s - */ - public void setValues(XMLString s) { - setValues(s.ch, s.offset, s.length); - } // setValues(XMLString) - - /** Resets all of the values to their defaults. */ - public void clear() { - this.ch = null; - this.offset = 0; - this.length = -1; - } // clear() - - /** - * Returns true if the contents of this XMLString structure and - * the specified array are equal. - * - * @param ch The character array. - * @param offset The offset into the character array. - * @param length The length of characters from the offset. - */ - public boolean equals(char[] ch, int offset, int length) { - if (ch == null) { - return false; - } - if (this.length != length) { - return false; - } - - for (int i=0; i 0 ? new String(ch, offset, length) : ""; - } // toString():String - -} // class XMLString +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +/** + * This class is used as a structure to pass text contained in the underlying + * character buffer of the scanner. The offset and length fields allow the + * buffer to be re-used without creating new character arrays. + *

        + * Note: Methods that are passed an XMLString structure + * should consider the contents read-only and not make any modifications + * to the contents of the buffer. The method receiving this structure + * should also not modify the offset and length if this structure (or + * the values of this structure) are passed to another method. + *

        + * Note: Methods that are passed an XMLString structure + * are required to copy the information out of the buffer if it is to be + * saved for use beyond the scope of the method. The contents of the + * structure are volatile and the contents of the character buffer cannot + * be assured once the method that is passed this structure returns. + * Therefore, methods passed this structure should not save any reference + * to the structure or the character array contained in the structure. + * + * @author Eric Ye, IBM + * @author Andy Clark, IBM + * + * @version $Id: XMLString.java 306086 2004-10-01 19:24:35Z luehe $ + */ +public class XMLString { + + // + // Data + // + + /** The character array. */ + public char[] ch; + + /** The offset into the character array. */ + public int offset; + + /** The length of characters from the offset. */ + public int length; + + // + // Constructors + // + + /** Default constructor. */ + public XMLString() { + } // () + + /** + * Constructs an XMLString structure preset with the specified + * values. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public XMLString(char[] ch, int offset, int length) { + setValues(ch, offset, length); + } // (char[],int,int) + + /** + * Constructs an XMLString structure with copies of the values in + * the given structure. + *

        + * Note: This does not copy the character array; + * only the reference to the array is copied. + * + * @param string The XMLString to copy. + */ + public XMLString(XMLString string) { + setValues(string); + } // (XMLString) + + // + // Public methods + // + + /** + * Initializes the contents of the XMLString structure with the + * specified values. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public void setValues(char[] ch, int offset, int length) { + this.ch = ch; + this.offset = offset; + this.length = length; + } // setValues(char[],int,int) + + /** + * Initializes the contents of the XMLString structure with copies + * of the given string structure. + *

        + * Note: This does not copy the character array; + * only the reference to the array is copied. + * + * @param s + */ + public void setValues(XMLString s) { + setValues(s.ch, s.offset, s.length); + } // setValues(XMLString) + + /** Resets all of the values to their defaults. */ + public void clear() { + this.ch = null; + this.offset = 0; + this.length = -1; + } // clear() + + /** + * Returns true if the contents of this XMLString structure and + * the specified array are equal. + * + * @param ch The character array. + * @param offset The offset into the character array. + * @param length The length of characters from the offset. + */ + public boolean equals(char[] ch, int offset, int length) { + if (ch == null) { + return false; + } + if (this.length != length) { + return false; + } + + for (int i=0; i 0 ? new String(ch, offset, length) : ""; + } // toString():String + +} // class XMLString diff --git a/java/org/apache/jasper/xmlparser/XMLStringBuffer.java b/java/org/apache/jasper/xmlparser/XMLStringBuffer.java index b9124780b..c51aff800 100644 --- a/java/org/apache/jasper/xmlparser/XMLStringBuffer.java +++ b/java/org/apache/jasper/xmlparser/XMLStringBuffer.java @@ -1,175 +1,175 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation and was - * originally based on software copyright (c) 1999, International - * Business Machines, Inc., http://www.apache.org. For more - * information on the Apache Software Foundation, please see - * . - */ - -package org.apache.jasper.xmlparser; - -/** - * XMLString is a structure used to pass character arrays. However, - * XMLStringBuffer is a buffer in which characters can be appended - * and extends XMLString so that it can be passed to methods - * expecting an XMLString object. This is a safe operation because - * it is assumed that any callee will not modify - * the contents of the XMLString structure. - *

        - * The contents of the string are managed by the string buffer. As - * characters are appended, the string buffer will grow as needed. - *

        - * Note: Never set the ch, - * offset, and length fields directly. - * These fields are managed by the string buffer. In order to reset - * the buffer, call clear(). - * - * @author Andy Clark, IBM - * @author Eric Ye, IBM - * - * @version $Id: XMLStringBuffer.java 306086 2004-10-01 19:24:35Z luehe $ - */ -public class XMLStringBuffer - extends XMLString { - - // - // Constants - // - - /** Default buffer size (32). */ - public static final int DEFAULT_SIZE = 32; - - // - // Constructors - // - - /** - * - */ - public XMLStringBuffer() { - this(DEFAULT_SIZE); - } // () - - /** - * - * - * @param size - */ - public XMLStringBuffer(int size) { - ch = new char[size]; - } // (int) - - /** Constructs a string buffer from a char. */ - public XMLStringBuffer(char c) { - this(1); - append(c); - } // (char) - - /** Constructs a string buffer from a String. */ - public XMLStringBuffer(String s) { - this(s.length()); - append(s); - } // (String) - - /** Constructs a string buffer from the specified character array. */ - public XMLStringBuffer(char[] ch, int offset, int length) { - this(length); - append(ch, offset, length); - } // (char[],int,int) - - /** Constructs a string buffer from the specified XMLString. */ - public XMLStringBuffer(XMLString s) { - this(s.length); - append(s); - } // (XMLString) - - // - // Public methods - // - - /** Clears the string buffer. */ - public void clear() { - offset = 0; - length = 0; - } - - /** - * append - * - * @param c - */ - public void append(char c) { - if (this.length + 1 > this.ch.length) { - int newLength = this.ch.length*2; - if (newLength < this.ch.length + DEFAULT_SIZE) - newLength = this.ch.length + DEFAULT_SIZE; - char[] newch = new char[newLength]; - System.arraycopy(this.ch, 0, newch, 0, this.length); - this.ch = newch; - } - this.ch[this.length] = c; - this.length++; - } // append(char) - - /** - * append - * - * @param s - */ - public void append(String s) { - int length = s.length(); - if (this.length + length > this.ch.length) { - int newLength = this.ch.length*2; - if (newLength < this.length + length + DEFAULT_SIZE) - newLength = this.ch.length + length + DEFAULT_SIZE; - char[] newch = new char[newLength]; - System.arraycopy(this.ch, 0, newch, 0, this.length); - this.ch = newch; - } - s.getChars(0, length, this.ch, this.length); - this.length += length; - } // append(String) - - /** - * append - * - * @param ch - * @param offset - * @param length - */ - public void append(char[] ch, int offset, int length) { - if (this.length + length > this.ch.length) { - char[] newch = new char[this.ch.length + length + DEFAULT_SIZE]; - System.arraycopy(this.ch, 0, newch, 0, this.length); - this.ch = newch; - } - System.arraycopy(ch, offset, this.ch, this.length, length); - this.length += length; - } // append(char[],int,int) - - /** - * append - * - * @param s - */ - public void append(XMLString s) { - append(s.ch, s.offset, s.length); - } // append(XMLString) - -} // class XMLStringBuffer +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation and was + * originally based on software copyright (c) 1999, International + * Business Machines, Inc., http://www.apache.org. For more + * information on the Apache Software Foundation, please see + * . + */ + +package org.apache.jasper.xmlparser; + +/** + * XMLString is a structure used to pass character arrays. However, + * XMLStringBuffer is a buffer in which characters can be appended + * and extends XMLString so that it can be passed to methods + * expecting an XMLString object. This is a safe operation because + * it is assumed that any callee will not modify + * the contents of the XMLString structure. + *

        + * The contents of the string are managed by the string buffer. As + * characters are appended, the string buffer will grow as needed. + *

        + * Note: Never set the ch, + * offset, and length fields directly. + * These fields are managed by the string buffer. In order to reset + * the buffer, call clear(). + * + * @author Andy Clark, IBM + * @author Eric Ye, IBM + * + * @version $Id: XMLStringBuffer.java 306086 2004-10-01 19:24:35Z luehe $ + */ +public class XMLStringBuffer + extends XMLString { + + // + // Constants + // + + /** Default buffer size (32). */ + public static final int DEFAULT_SIZE = 32; + + // + // Constructors + // + + /** + * + */ + public XMLStringBuffer() { + this(DEFAULT_SIZE); + } // () + + /** + * + * + * @param size + */ + public XMLStringBuffer(int size) { + ch = new char[size]; + } // (int) + + /** Constructs a string buffer from a char. */ + public XMLStringBuffer(char c) { + this(1); + append(c); + } // (char) + + /** Constructs a string buffer from a String. */ + public XMLStringBuffer(String s) { + this(s.length()); + append(s); + } // (String) + + /** Constructs a string buffer from the specified character array. */ + public XMLStringBuffer(char[] ch, int offset, int length) { + this(length); + append(ch, offset, length); + } // (char[],int,int) + + /** Constructs a string buffer from the specified XMLString. */ + public XMLStringBuffer(XMLString s) { + this(s.length); + append(s); + } // (XMLString) + + // + // Public methods + // + + /** Clears the string buffer. */ + public void clear() { + offset = 0; + length = 0; + } + + /** + * append + * + * @param c + */ + public void append(char c) { + if (this.length + 1 > this.ch.length) { + int newLength = this.ch.length*2; + if (newLength < this.ch.length + DEFAULT_SIZE) + newLength = this.ch.length + DEFAULT_SIZE; + char[] newch = new char[newLength]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + this.ch[this.length] = c; + this.length++; + } // append(char) + + /** + * append + * + * @param s + */ + public void append(String s) { + int length = s.length(); + if (this.length + length > this.ch.length) { + int newLength = this.ch.length*2; + if (newLength < this.length + length + DEFAULT_SIZE) + newLength = this.ch.length + length + DEFAULT_SIZE; + char[] newch = new char[newLength]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + s.getChars(0, length, this.ch, this.length); + this.length += length; + } // append(String) + + /** + * append + * + * @param ch + * @param offset + * @param length + */ + public void append(char[] ch, int offset, int length) { + if (this.length + length > this.ch.length) { + char[] newch = new char[this.ch.length + length + DEFAULT_SIZE]; + System.arraycopy(this.ch, 0, newch, 0, this.length); + this.ch = newch; + } + System.arraycopy(ch, offset, this.ch, this.length, length); + this.length += length; + } // append(char[],int,int) + + /** + * append + * + * @param s + */ + public void append(XMLString s) { + append(s.ch, s.offset, s.length); + } // append(XMLString) + +} // class XMLStringBuffer diff --git a/java/org/apache/jk/apr/AprImpl.java b/java/org/apache/jk/apr/AprImpl.java index 4c2c4c371..f6294811c 100644 --- a/java/org/apache/jk/apr/AprImpl.java +++ b/java/org/apache/jk/apr/AprImpl.java @@ -1,316 +1,316 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.apr; - -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Hashtable; -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.JkChannel; - -/** Implements the interface with the APR library. This is for internal-use - * only. The goal is to use 'natural' mappings for user code - for example - * java.net.Socket for unix-domain sockets, etc. - * - */ -public class AprImpl extends JkHandler { // This will be o.a.t.util.handler.TcHandler - lifecycle and config - static AprImpl aprSingleton=null; - - String baseDir; - String aprHome; - String soExt="so"; - - static boolean ok=true; - boolean initialized=false; - // Handlers for native callbacks - Hashtable jkHandlers=new Hashtable(); - - // Name of the so used in inprocess mode - String jniModeSo="inprocess"; - // name of the so used by java. If not set we'll loadLibrary("jkjni" ), - // if set we load( nativeSo ) - String nativeSo; - - public AprImpl() { - aprSingleton=this; - } - - // -------------------- Properties -------------------- - - /** Native libraries are located based on base dir. - * XXX Add platform, version, etc - */ - public void setBaseDir(String s) { - baseDir=s; - } - - public void setSoExt(String s ) { - soExt=s; - } - - // XXX maybe install the jni lib in apr-home ? - public void setAprHome( String s ) { - aprHome=s; - } - - /** Add a Handler for jni callbacks. - */ - public void addJkHandler(String type, JkHandler cb) { - jkHandlers.put( type, cb ); - } - - /** Name of the so used in inprocess mode - */ - public void setJniModeSo(String jniModeSo ) { - this.jniModeSo=jniModeSo; - } - - /** name of the so used by java. If not set we'll loadLibrary("jkjni" ), - if set we load( nativeSo ) - */ - public void setNativeSo( String nativeSo ) { - this.nativeSo=nativeSo; - } - - /** Sets the System.out stream */ - - public static void setOut( String filename ) { - try{ - if( filename !=null ){ - System.setOut( new PrintStream(new FileOutputStream(filename ))); - } - }catch (Throwable th){ - } - } - /** Sets the System.err stream */ - - public static void setErr( String filename ) { - try{ - if( filename !=null ){ - System.setErr( new PrintStream(new FileOutputStream(filename ))); - } - }catch (Throwable th){ - } - } - - // -------------------- Apr generic utils -------------------- - /** Initialize APR - */ - public native int initialize(); - - public native int terminate(); - - /* -------------------- Access to the jk_env_t -------------------- */ - - /* The jk_env_t provide temporary storage ( pool ), logging, common services - */ - - /* Return a jk_env_t, used to keep the execution context ( temp pool, etc ) - */ - public native long getJkEnv(); - - /** Clean the temp pool, put back the env in the pool - */ - public native void releaseJkEnv(long xEnv); - - /* -------------------- Interface to the jk_bean object -------------------- */ - /* Each jk component is 'wrapped' as a bean, with a specified lifecycle - * - */ - - /** Get a native component - * @return 0 if the component is not found. - */ - public native long getJkHandler(long xEnv, String compName ); - - public native long createJkHandler(long xEnv, String compName ); - - public native int jkSetAttribute( long xEnv, long componentP, String name, String val ); - - public native String jkGetAttribute( long xEnv, long componentP, String name ); - - public native int jkInit( long xEnv, long componentP ); - - public native int jkDestroy( long xEnv, long componentP ); - - /** Send the packet to the C side. On return it contains the response - * or indication there is no response. Asymetrical because we can't - * do things like continuations. - */ - public static native int jkInvoke(long xEnv, long componentP, long endpointP, - int code, byte data[], int off, int len, int raw); - - /** Recycle an endpoint after use. - */ - public native void jkRecycle(long xEnv, long endpointP); - - // -------------------- Called from C -------------------- - // XXX Check security, add guard or other protection - // It's better to do it the other way - on init 'push' AprImpl into - // the native library, and have native code call instance methods. - - public static Object createJavaContext(String type, long cContext) { - // XXX will be an instance method, fields accessible directly - AprImpl apr=aprSingleton; - JkChannel jkH=(JkChannel)apr.jkHandlers.get( type ); - if( jkH==null ) return null; - - MsgContext ep=jkH.createMsgContext(); - - ep.setSource( jkH ); - - ep.setJniContext( cContext ); - return ep; - } - - /** Return a buffer associated with the ctx. - */ - public static byte[] getBuffer( Object ctx, int id ) { - return ((MsgContext)ctx).getBuffer( id ); - } - - public static int jniInvoke( long jContext, Object ctx ) { - try { - MsgContext ep=(MsgContext)ctx; - ep.setJniEnv( jContext ); - ep.setType( 0 ); - return ((MsgContext)ctx).execute(); - } catch( Throwable ex ) { - ex.printStackTrace(); - return -1; - } - } - - // -------------------- Initialization -------------------- - - public void init() throws IOException { - try { - initialized=true; - loadNative(); - - initialize(); - jkSetAttribute(0, 0, "channel:jni", "starting"); - - log.info("JK: Initialized apr" ); - - } catch( Throwable t ) { - throw new IOException( t.toString() ); - } - ok=true; - } - - public boolean isLoaded() { - if( ! initialized ) { - try { - init(); - } catch( Throwable t ) { - log.info("Apr not loaded: " + t); - } - } - return ok; - } - - static boolean jniMode=false; - - - public static void jniMode() { - jniMode=true; - } - - /** This method of loading the libs doesn't require setting - * LD_LIBRARY_PATH. Assuming a 'right' binary distribution, - * or a correct build all files will be in their right place. - * - * The burden is on our code to deal with platform specific - * extensions and to keep the paths consistent - not easy, but - * worth it if it avoids one extra step for the user. - * - * Of course, this can change to System.load() and putting the - * libs in LD_LIBRARY_PATH. - */ - public void loadNative() throws Throwable { - if( aprHome==null ) - aprHome=baseDir; - - // XXX Update for windows - if( jniMode ) { - /* In JNI mode we use mod_jk for the native functions. - This seems the cleanest solution that works with multiple - VMs. - */ - if (jniModeSo.equals("inprocess")) { - ok=true; - return; - } - try { - log.info("Loading " + jniModeSo); - if( jniModeSo!= null ) System.load( jniModeSo ); - } catch( Throwable ex ) { - // ignore - //ex.printStackTrace(); - return; - } - ok=true; - return; - } - - /* - jkjni _must_ be linked with apr and crypt - - this seem the only ( decent ) way to support JDK1.4 and - JDK1.3 at the same time - try { - System.loadLibrary( "crypt" ); - } catch( Throwable ex ) { - // ignore - ex.printStackTrace(); - } - try { - System.loadLibrary( "apr" ); - } catch( Throwable ex ) { - System.out.println("can't load apr, that's fine"); - ex.printStackTrace(); - } - */ - try { - if( nativeSo == null ) { - // This will load libjkjni.so or jkjni.dll in LD_LIBRARY_PATH - log.debug("Loading jkjni from " + System.getProperty("java.library.path")); - System.loadLibrary( "jkjni" ); - } else { - System.load( nativeSo ); - } - } catch( Throwable ex ) { - ok=false; - //ex.printStackTrace(); - throw ex; - } - } - - public void loadNative(String libPath) { - try { - System.load( libPath ); - } catch( Throwable ex ) { - ok=false; - if( log.isDebugEnabled() ) - log.debug( "Error loading native library ", ex); - } - } - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( AprImpl.class ); -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.apr; + +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.JkChannel; + +/** Implements the interface with the APR library. This is for internal-use + * only. The goal is to use 'natural' mappings for user code - for example + * java.net.Socket for unix-domain sockets, etc. + * + */ +public class AprImpl extends JkHandler { // This will be o.a.t.util.handler.TcHandler - lifecycle and config + static AprImpl aprSingleton=null; + + String baseDir; + String aprHome; + String soExt="so"; + + static boolean ok=true; + boolean initialized=false; + // Handlers for native callbacks + Hashtable jkHandlers=new Hashtable(); + + // Name of the so used in inprocess mode + String jniModeSo="inprocess"; + // name of the so used by java. If not set we'll loadLibrary("jkjni" ), + // if set we load( nativeSo ) + String nativeSo; + + public AprImpl() { + aprSingleton=this; + } + + // -------------------- Properties -------------------- + + /** Native libraries are located based on base dir. + * XXX Add platform, version, etc + */ + public void setBaseDir(String s) { + baseDir=s; + } + + public void setSoExt(String s ) { + soExt=s; + } + + // XXX maybe install the jni lib in apr-home ? + public void setAprHome( String s ) { + aprHome=s; + } + + /** Add a Handler for jni callbacks. + */ + public void addJkHandler(String type, JkHandler cb) { + jkHandlers.put( type, cb ); + } + + /** Name of the so used in inprocess mode + */ + public void setJniModeSo(String jniModeSo ) { + this.jniModeSo=jniModeSo; + } + + /** name of the so used by java. If not set we'll loadLibrary("jkjni" ), + if set we load( nativeSo ) + */ + public void setNativeSo( String nativeSo ) { + this.nativeSo=nativeSo; + } + + /** Sets the System.out stream */ + + public static void setOut( String filename ) { + try{ + if( filename !=null ){ + System.setOut( new PrintStream(new FileOutputStream(filename ))); + } + }catch (Throwable th){ + } + } + /** Sets the System.err stream */ + + public static void setErr( String filename ) { + try{ + if( filename !=null ){ + System.setErr( new PrintStream(new FileOutputStream(filename ))); + } + }catch (Throwable th){ + } + } + + // -------------------- Apr generic utils -------------------- + /** Initialize APR + */ + public native int initialize(); + + public native int terminate(); + + /* -------------------- Access to the jk_env_t -------------------- */ + + /* The jk_env_t provide temporary storage ( pool ), logging, common services + */ + + /* Return a jk_env_t, used to keep the execution context ( temp pool, etc ) + */ + public native long getJkEnv(); + + /** Clean the temp pool, put back the env in the pool + */ + public native void releaseJkEnv(long xEnv); + + /* -------------------- Interface to the jk_bean object -------------------- */ + /* Each jk component is 'wrapped' as a bean, with a specified lifecycle + * + */ + + /** Get a native component + * @return 0 if the component is not found. + */ + public native long getJkHandler(long xEnv, String compName ); + + public native long createJkHandler(long xEnv, String compName ); + + public native int jkSetAttribute( long xEnv, long componentP, String name, String val ); + + public native String jkGetAttribute( long xEnv, long componentP, String name ); + + public native int jkInit( long xEnv, long componentP ); + + public native int jkDestroy( long xEnv, long componentP ); + + /** Send the packet to the C side. On return it contains the response + * or indication there is no response. Asymetrical because we can't + * do things like continuations. + */ + public static native int jkInvoke(long xEnv, long componentP, long endpointP, + int code, byte data[], int off, int len, int raw); + + /** Recycle an endpoint after use. + */ + public native void jkRecycle(long xEnv, long endpointP); + + // -------------------- Called from C -------------------- + // XXX Check security, add guard or other protection + // It's better to do it the other way - on init 'push' AprImpl into + // the native library, and have native code call instance methods. + + public static Object createJavaContext(String type, long cContext) { + // XXX will be an instance method, fields accessible directly + AprImpl apr=aprSingleton; + JkChannel jkH=(JkChannel)apr.jkHandlers.get( type ); + if( jkH==null ) return null; + + MsgContext ep=jkH.createMsgContext(); + + ep.setSource( jkH ); + + ep.setJniContext( cContext ); + return ep; + } + + /** Return a buffer associated with the ctx. + */ + public static byte[] getBuffer( Object ctx, int id ) { + return ((MsgContext)ctx).getBuffer( id ); + } + + public static int jniInvoke( long jContext, Object ctx ) { + try { + MsgContext ep=(MsgContext)ctx; + ep.setJniEnv( jContext ); + ep.setType( 0 ); + return ((MsgContext)ctx).execute(); + } catch( Throwable ex ) { + ex.printStackTrace(); + return -1; + } + } + + // -------------------- Initialization -------------------- + + public void init() throws IOException { + try { + initialized=true; + loadNative(); + + initialize(); + jkSetAttribute(0, 0, "channel:jni", "starting"); + + log.info("JK: Initialized apr" ); + + } catch( Throwable t ) { + throw new IOException( t.toString() ); + } + ok=true; + } + + public boolean isLoaded() { + if( ! initialized ) { + try { + init(); + } catch( Throwable t ) { + log.info("Apr not loaded: " + t); + } + } + return ok; + } + + static boolean jniMode=false; + + + public static void jniMode() { + jniMode=true; + } + + /** This method of loading the libs doesn't require setting + * LD_LIBRARY_PATH. Assuming a 'right' binary distribution, + * or a correct build all files will be in their right place. + * + * The burden is on our code to deal with platform specific + * extensions and to keep the paths consistent - not easy, but + * worth it if it avoids one extra step for the user. + * + * Of course, this can change to System.load() and putting the + * libs in LD_LIBRARY_PATH. + */ + public void loadNative() throws Throwable { + if( aprHome==null ) + aprHome=baseDir; + + // XXX Update for windows + if( jniMode ) { + /* In JNI mode we use mod_jk for the native functions. + This seems the cleanest solution that works with multiple + VMs. + */ + if (jniModeSo.equals("inprocess")) { + ok=true; + return; + } + try { + log.info("Loading " + jniModeSo); + if( jniModeSo!= null ) System.load( jniModeSo ); + } catch( Throwable ex ) { + // ignore + //ex.printStackTrace(); + return; + } + ok=true; + return; + } + + /* + jkjni _must_ be linked with apr and crypt - + this seem the only ( decent ) way to support JDK1.4 and + JDK1.3 at the same time + try { + System.loadLibrary( "crypt" ); + } catch( Throwable ex ) { + // ignore + ex.printStackTrace(); + } + try { + System.loadLibrary( "apr" ); + } catch( Throwable ex ) { + System.out.println("can't load apr, that's fine"); + ex.printStackTrace(); + } + */ + try { + if( nativeSo == null ) { + // This will load libjkjni.so or jkjni.dll in LD_LIBRARY_PATH + log.debug("Loading jkjni from " + System.getProperty("java.library.path")); + System.loadLibrary( "jkjni" ); + } else { + System.load( nativeSo ); + } + } catch( Throwable ex ) { + ok=false; + //ex.printStackTrace(); + throw ex; + } + } + + public void loadNative(String libPath) { + try { + System.load( libPath ); + } catch( Throwable ex ) { + ok=false; + if( log.isDebugEnabled() ) + log.debug( "Error loading native library ", ex); + } + } + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( AprImpl.class ); +} diff --git a/java/org/apache/jk/apr/TomcatStarter.java b/java/org/apache/jk/apr/TomcatStarter.java index 42782e906..c9e2a6bab 100644 --- a/java/org/apache/jk/apr/TomcatStarter.java +++ b/java/org/apache/jk/apr/TomcatStarter.java @@ -1,93 +1,93 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.apr; - -import java.lang.reflect.Method; - -// Hack for Catalina 4.1 who hungs the calling thread. -// Also avoids delays in apache initialization ( tomcat can take a while ) - -/** - * Start some tomcat. - * - */ -public class TomcatStarter implements Runnable { - Class c; - String args[]; - AprImpl apr = new AprImpl(); - - public static String mainClasses[]={ "org.apache.tomcat.startup.Main", - "org.apache.catalina.startup.BootstrapService", - "org.apache.catalina.startup.Bootstrap"}; - - // If someone has time - we can also guess the classpath and do other - // fancy guessings. - - public static void main( String args[] ) { - System.err.println("TomcatStarter: main()"); - int nClasses = 0; - - try { - AprImpl.jniMode(); - // Find the class - Class c=null; - for( int i=0; i433 RPS and - 52->35ms average time with a simple servlet ) - */ - - ThreadPool tp=ThreadPool.createThreadPool(true); - - /* ==================== Tcp socket options ==================== */ - - /** - * jmx:managed-constructor description="default constructor" - */ - public ChannelNioSocket() { - // This should be integrated with the domain setup - } - - public ThreadPool getThreadPool() { - return tp; - } - - public long getRequestCount() { - return requestCount; - } - - /** Set the port for the ajp13 channel. - * To support seemless load balancing and jni, we treat this - * as the 'base' port - we'll try up until we find one that is not - * used. We'll also provide the 'difference' to the main coyote - * handler - that will be our 'sessionID' and the position in - * the scoreboard and the suffix for the unix domain socket. - * - * jmx:managed-attribute description="Port to listen" access="READ_WRITE" - */ - public void setPort( int port ) { - this.startPort=port; - this.port=port; - this.maxPort=port+10; - } - - public int getPort() { - return port; - } - - public void setAddress(InetAddress inet) { - this.inet=inet; - } - - public void setBufferSize(int bs) { - if(bs > 8*1024) { - bufferSize = bs; - } - } - - public int getBufferSize() { - return bufferSize; - } - - - /** - * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE" - */ - public void setAddress(String inet) { - try { - this.inet= InetAddress.getByName( inet ); - } catch( Exception ex ) { - log.error("Error parsing "+inet,ex); - } - } - - public String getAddress() { - if( inet!=null) - return inet.toString(); - return "/0.0.0.0"; - } - - /** - * Sets the timeout in ms of the server sockets created by this - * server. This method allows the developer to make servers - * more or less responsive to having their server sockets - * shut down. - * - *

        By default this value is 1000ms. - */ - public void setServerTimeout(int timeout) { - this.serverTimeout = timeout; - } - public int getServerTimeout() { - return serverTimeout; - } - - public void setTcpNoDelay( boolean b ) { - tcpNoDelay=b; - } - - public boolean getTcpNoDelay() { - return tcpNoDelay; - } - - public void setSoLinger( int i ) { - linger=i; - } - - public int getSoLinger() { - return linger; - } - - public void setSoTimeout( int i ) { - socketTimeout=i; - } - - public int getSoTimeout() { - return socketTimeout; - } - - public void setMaxPort( int i ) { - maxPort=i; - } - - public int getMaxPort() { - return maxPort; - } - - /** At startup we'll look for the first free port in the range. - The difference between this port and the beggining of the range - is the 'id'. - This is usefull for lb cases ( less config ). - */ - public int getInstanceId() { - return port-startPort; - } - - /** If set to false, the thread pool will be created in - * non-daemon mode, and will prevent main from exiting - */ - public void setDaemon( boolean b ) { - tp.setDaemon( b ); - } - - public boolean getDaemon() { - return tp.getDaemon(); - } - - - public void setMaxThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i); - tp.setMaxThreads(i); - } - - public void setMinSpareThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i); - tp.setMinSpareThreads(i); - } - - public void setMaxSpareThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i); - tp.setMaxSpareThreads(i); - } - - public int getMaxThreads() { - return tp.getMaxThreads(); - } - - public int getMinSpareThreads() { - return tp.getMinSpareThreads(); - } - - public int getMaxSpareThreads() { - return tp.getMaxSpareThreads(); - } - - public void setBacklog(int i) { - } - - public void setNioIsBroken(boolean nib) { - nioIsBroken = nib; - } - - public boolean getNioIsBroken() { - return nioIsBroken; - } - - /* ==================== ==================== */ - ServerSocket sSocket; - final int socketNote=1; - final int isNote=2; - final int osNote=3; - final int notifNote=4; - boolean paused = false; - - public void pause() throws Exception { - synchronized(this) { - paused = true; - } - } - - public void resume() { - synchronized(this) { - paused = false; - notify(); - } - } - - - public void accept( MsgContext ep ) throws IOException { - if( sSocket==null ) return; - synchronized(this) { - while(paused) { - try{ - wait(); - } catch(InterruptedException ie) { - //Ignore, since can't happen - } - } - } - SocketChannel sc=sSocket.getChannel().accept(); - Socket s = sc.socket(); - ep.setNote( socketNote, s ); - if(log.isDebugEnabled() ) - log.debug("Accepted socket " + s +" channel " + sc.isBlocking()); - - try { - setSocketOptions(s); - } catch(SocketException sex) { - log.debug("Error initializing Socket Options", sex); - } - - requestCount++; - - sc.configureBlocking(false); - InputStream is=new SocketInputStream(sc); - OutputStream os = new SocketOutputStream(sc); - ep.setNote( isNote, is ); - ep.setNote( osNote, os ); - ep.setControl( tp ); - } - - private void setSocketOptions(Socket s) throws SocketException { - if( socketTimeout > 0 ) - s.setSoTimeout( socketTimeout ); - - s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state - - if( linger > 0 ) - s.setSoLinger( true, linger); - } - - public void resetCounters() { - requestCount=0; - } - - /** Called after you change some fields at runtime using jmx. - Experimental for now. - */ - public void reinit() throws IOException { - destroy(); - init(); - } - - /** - * jmx:managed-operation - */ - public void init() throws IOException { - // Find a port. - if (startPort == 0) { - port = 0; - if(log.isInfoEnabled()) - log.info("JK: ajp13 disabling channelNioSocket"); - running = true; - return; - } - if (maxPort < startPort) - maxPort = startPort; - ServerSocketChannel ssc = ServerSocketChannel.open(); - ssc.configureBlocking(false); - for( int i=startPort; i<=maxPort; i++ ) { - try { - InetSocketAddress iddr = null; - if( inet == null ) { - iddr = new InetSocketAddress( i); - } else { - iddr=new InetSocketAddress( inet, i); - } - sSocket = ssc.socket(); - sSocket.bind(iddr); - port=i; - break; - } catch( IOException ex ) { - if(log.isInfoEnabled()) - log.info("Port busy " + i + " " + ex.toString()); - sSocket = null; - } - } - - if( sSocket==null ) { - log.error("Can't find free port " + startPort + " " + maxPort ); - return; - } - if(log.isInfoEnabled()) - log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); - - selector = Selector.open(); - ssc.register(selector, SelectionKey.OP_ACCEPT); - // If this is not the base port and we are the 'main' channleSocket and - // SHM didn't already set the localId - we'll set the instance id - if( "channelNioSocket".equals( name ) && - port != startPort && - (wEnv.getLocalId()==0) ) { - wEnv.setLocalId( port - startPort ); - } - - // XXX Reverse it -> this is a notification generator !! - if( next==null && wEnv!=null ) { - if( nextName!=null ) - setNext( wEnv.getHandler( nextName ) ); - if( next==null ) - next=wEnv.getHandler( "dispatch" ); - if( next==null ) - next=wEnv.getHandler( "request" ); - } - JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); - running = true; - - // Run a thread that will accept connections. - // XXX Try to find a thread first - not sure how... - if( this.domain != null ) { - try { - tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + - getChannelName()); - - Registry.getRegistry(null, null) - .registerComponent(tp, tpOName, null); - - rgOName = new ObjectName - (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); - Registry.getRegistry(null, null) - .registerComponent(global, rgOName, null); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - } - - tp.start(); - Poller pollAjp = new Poller(); - tp.runIt(pollAjp); - } - - ObjectName tpOName; - ObjectName rgOName; - RequestGroupInfo global=new RequestGroupInfo(); - int JMXRequestNote; - - public void start() throws IOException{ - if( sSocket==null ) - init(); - resume(); - } - - public void stop() throws IOException { - destroy(); - } - - public void registerRequest(Request req, MsgContext ep, int count) { - if(this.domain != null) { - try { - RequestInfo rp=req.getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName roname = new ObjectName - (getDomain() + ":type=RequestProcessor,worker="+ - getChannelName()+",name=JkRequest" +count); - ep.setNote(JMXRequestNote, roname); - - Registry.getRegistry(null, null).registerComponent( rp, roname, null); - } catch( Exception ex ) { - log.warn("Error registering request"); - } - } - } - - public void open(MsgContext ep) throws IOException { - } - - - public void close(MsgContext ep) throws IOException { - Socket s=(Socket)ep.getNote( socketNote ); - SelectionKey key = s.getChannel().keyFor(selector); - if(key != null) { - key.cancel(); - } - s.close(); - } - - public void destroy() throws IOException { - running = false; - try { - /* If we disabled the channel return */ - if (port == 0) - return; - tp.shutdown(); - - selector.wakeup().close(); - sSocket.close(); // XXX? - - if( tpOName != null ) { - Registry.getRegistry(null, null).unregisterComponent(tpOName); - } - if( rgOName != null ) { - Registry.getRegistry(null, null).unregisterComponent(rgOName); - } - } catch(Exception e) { - log.info("Error shutting down the channel " + port + " " + - e.toString()); - if( log.isDebugEnabled() ) log.debug("Trace", e); - } - } - - public int send( Msg msg, MsgContext ep) - throws IOException { - msg.end(); // Write the packet header - byte buf[]=msg.getBuffer(); - int len=msg.getLen(); - - if(log.isTraceEnabled() ) - log.trace("send() " + len + " " + buf[4] ); - - OutputStream os=(OutputStream)ep.getNote( osNote ); - os.write( buf, 0, len ); - return len; - } - - public int flush( Msg msg, MsgContext ep) - throws IOException { - OutputStream os=(OutputStream)ep.getNote( osNote ); - os.flush(); - return 0; - } - - public int receive( Msg msg, MsgContext ep ) - throws IOException { - if (log.isTraceEnabled()) { - log.trace("receive() "); - } - - byte buf[]=msg.getBuffer(); - int hlen=msg.getHeaderLength(); - - // XXX If the length in the packet header doesn't agree with the - // actual number of bytes read, it should probably return an error - // value. Also, callers of this method never use the length - // returned -- should probably return true/false instead. - - int rd = this.read(ep, buf, 0, hlen ); - - if(rd < 0) { - // Most likely normal apache restart. - // log.warn("Wrong message " + rd ); - return rd; - } - - msg.processHeader(); - - /* After processing the header we know the body - length - */ - int blen=msg.getLen(); - - // XXX check if enough space - it's assert()-ed !!! - - int total_read = 0; - - total_read = this.read(ep, buf, hlen, blen); - - if ((total_read <= 0) && (blen > 0)) { - log.warn("can't read body, waited #" + blen); - return -1; - } - - if (total_read != blen) { - log.warn( "incomplete read, waited #" + blen + - " got only " + total_read); - return -2; - } - - return total_read; - } - - /** - * Read N bytes from the InputStream, and ensure we got them all - * Under heavy load we could experience many fragmented packets - * just read Unix Network Programming to recall that a call to - * read didn't ensure you got all the data you want - * - * from read() Linux manual - * - * On success, the number of bytes read is returned (zero indicates end - * of file),and the file position is advanced by this number. - * It is not an error if this number is smaller than the number of bytes - * requested; this may happen for example because fewer bytes - * are actually available right now (maybe because we were close to - * end-of-file, or because we are reading from a pipe, or from a - * terminal), or because read() was interrupted by a signal. - * On error, -1 is returned, and errno is set appropriately. In this - * case it is left unspecified whether the file position (if any) changes. - * - **/ - public int read( MsgContext ep, byte[] b, int offset, int len) - throws IOException - { - InputStream is=(InputStream)ep.getNote( isNote ); - int pos = 0; - int got; - - while(pos < len) { - try { - got = is.read(b, pos + offset, len - pos); - } catch(ClosedChannelException sex) { - if(pos > 0) { - log.info("Error reading data after "+pos+"bytes",sex); - } else { - log.debug("Error reading data", sex); - } - got = -1; - } - if (log.isTraceEnabled()) { - log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " + - offset + " " + len + " = " + got ); - } - - // connection just closed by remote. - if (got <= 0) { - // This happens periodically, as apache restarts - // periodically. - // It should be more gracefull ! - another feature for Ajp14 - // log.warn( "server has closed the current connection (-1)" ); - return -3; - } - - pos += got; - } - return pos; - } - - protected boolean running=true; - - /** Accept incoming connections, dispatch to the thread pool - */ - void acceptConnections() { - if( running ) { - try{ - MsgContext ep=createMsgContext(); - ep.setSource(this); - ep.setWorkerEnv( wEnv ); - this.accept(ep); - - if( !running ) return; - - // Since this is a long-running connection, we don't care - // about the small GC - SocketConnection ajpConn= - new SocketConnection( ep); - ajpConn.register(ep); - }catch(Exception ex) { - if (running) - log.warn("Exception executing accept" ,ex); - } - } - } - - - // XXX This should become handleNotification - public int invoke( Msg msg, MsgContext ep ) throws IOException { - int type=ep.getType(); - - switch( type ) { - case JkHandler.HANDLE_RECEIVE_PACKET: - if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? "); - return receive( msg, ep ); - case JkHandler.HANDLE_SEND_PACKET: - return send( msg, ep ); - case JkHandler.HANDLE_FLUSH: - return flush( msg, ep ); - } - - if( log.isTraceEnabled() ) - log.trace("Call next " + type + " " + next); - - // Send notification - if( nSupport!=null ) { - Notification notif=(Notification)ep.getNote(notifNote); - if( notif==null ) { - notif=new Notification("channelNioSocket.message", ep, requestCount ); - ep.setNote( notifNote, notif); - } - nSupport.sendNotification(notif); - } - - if( next != null ) { - return next.invoke( msg, ep ); - } else { - log.info("No next "); - } - - return OK; - } - - public boolean isSameAddress(MsgContext ep) { - Socket s=(Socket)ep.getNote( socketNote ); - return isSameAddress( s.getLocalAddress(), s.getInetAddress()); - } - - public String getChannelName() { - String encodedAddr = ""; - if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) { - encodedAddr = getAddress(); - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) + "-"; - } - return ("jk-" + encodedAddr + port); - } - - /** - * Return true if the specified client and server addresses - * are the same. This method works around a bug in the IBM 1.1.8 JVM on - * Linux, where the address bytes are returned reversed in some - * circumstances. - * - * @param server The server's InetAddress - * @param client The client's InetAddress - */ - public static boolean isSameAddress(InetAddress server, InetAddress client) - { - // Compare the byte array versions of the two addresses - byte serverAddr[] = server.getAddress(); - byte clientAddr[] = client.getAddress(); - if (serverAddr.length != clientAddr.length) - return (false); - boolean match = true; - for (int i = 0; i < serverAddr.length; i++) { - if (serverAddr[i] != clientAddr[i]) { - match = false; - break; - } - } - if (match) - return (true); - - // Compare the reversed form of the two addresses - for (int i = 0; i < serverAddr.length; i++) { - if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i]) - return (false); - } - return (true); - } - - public void sendNewMessageNotification(Notification notification) { - if( nSupport!= null ) - nSupport.sendNotification(notification); - } - - private NotificationBroadcasterSupport nSupport= null; - - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws IllegalArgumentException - { - if( nSupport==null ) nSupport=new NotificationBroadcasterSupport(); - nSupport.addNotificationListener(listener, filter, handback); - } - - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException - { - if( nSupport!=null) - nSupport.removeNotificationListener(listener); - } - - MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0]; - - public void setNotificationInfo( MBeanNotificationInfo info[]) { - this.notifInfo=info; - } - - public MBeanNotificationInfo[] getNotificationInfo() { - return notifInfo; - } - - protected class SocketConnection implements ThreadPoolRunnable { - MsgContext ep; - MsgAjp recv = new MsgAjp(); - boolean inProgress = false; - - SocketConnection(MsgContext ep) { - this.ep=ep; - } - - public Object[] getInitData() { - return null; - } - - public void runIt(Object perTh[]) { - if(!processConnection(ep)) { - unregister(ep); - } - } - - public boolean isRunning() { - return inProgress; - } - - public void setFinished() { - inProgress = false; - } - - /** Process a single ajp connection. - */ - boolean processConnection(MsgContext ep) { - try { - InputStream sis = (InputStream)ep.getNote(isNote); - boolean haveInput = true; - while(haveInput) { - if( !running || paused ) { - return false; - } - int status= receive( recv, ep ); - if( status <= 0 ) { - if( status==-3) - log.debug( "server has been restarted or reset this connection" ); - else - log.warn("Closing ajp connection " + status ); - return false; - } - ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis()); - - ep.setType( 0 ); - // Will call next - status= invoke( recv, ep ); - if( status != JkHandler.OK ) { - log.warn("processCallbacks status " + status ); - return false; - } - synchronized(this) { - synchronized(sis) { - haveInput = sis.available() > 0; - } - if(!haveInput) { - setFinished(); - } else { - if(log.isDebugEnabled()) - log.debug("KeepAlive: "+sis.available()); - } - } - } - } catch( Exception ex ) { - String msg = ex.getMessage(); - if( msg != null && msg.indexOf( "Connection reset" ) >= 0) - log.debug( "Server has been restarted or reset this connection"); - else if (msg != null && msg.indexOf( "Read timed out" ) >=0 ) - log.debug( "connection timeout reached"); - else - log.error( "Error, processing connection", ex); - return false; - } - return true; - } - - synchronized void process(SelectionKey sk) { - if(!sk.isValid()) { - return; - } - if(sk.isReadable()) { - SocketInputStream sis = (SocketInputStream)ep.getNote(isNote); - boolean isok = sis.readAvailable(); - if(!inProgress) { - if(isok) { - if(sis.available() > 0 || !nioIsBroken){ - inProgress = true; - tp.runIt(this); - } - } else { - unregister(ep); - return; - } - } - } - if(sk.isWritable()) { - Object os = ep.getNote(osNote); - synchronized(os) { - os.notify(); - } - } - } - - synchronized void unregister(MsgContext ep) { - try{ - close(ep); - } catch(Exception e) { - log.error("Error closing connection", e); - } - try{ - Request req = (Request)ep.getRequest(); - if( req != null ) { - ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); - if( roname != null ) { - Registry.getRegistry(null, null).unregisterComponent(roname); - } - req.getRequestProcessor().setGlobalProcessor(null); - } - } catch( Exception ee) { - log.error( "Error, releasing connection",ee); - } - } - - void register(MsgContext ep) { - Socket s = (Socket)ep.getNote(socketNote); - try { - s.getChannel().register(selector, SelectionKey.OP_READ, this); - } catch(IOException iex) { - log.error("Unable to register connection",iex); - unregister(ep); - } - } - - } - - protected class Poller implements ThreadPoolRunnable { - - Poller() { - } - - public Object[] getInitData() { - return null; - } - - public void runIt(Object perTh[]) { - while(running) { - try { - int ns = selector.select(serverTimeout); - if(log.isDebugEnabled()) - log.debug("Selecting "+ns+" channels"); - if(ns > 0) { - Set sels = selector.selectedKeys(); - Iterator it = sels.iterator(); - while(it.hasNext()) { - SelectionKey sk = (SelectionKey)it.next(); - if(sk.isValid()) { - if(sk.isAcceptable()) { - acceptConnections(); - } else { - SocketConnection sc = (SocketConnection)sk.attachment(); - sc.process(sk); - } - } else { - sk.cancel(); - } - it.remove(); - } - } - } catch(ClosedSelectorException cse) { - log.debug("Selector is closed"); - return; - } catch(CancelledKeyException cke) { - log.debug("Key Cancelled", cke); - } catch(IOException iex) { - log.warn("IO Error in select",iex); - } catch(Exception ex) { - log.warn("Error processing select",ex); - } - } - } - } - - protected class SocketInputStream extends InputStream { - final int BUFFER_SIZE = 8200; - private ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); - private SocketChannel channel; - private boolean blocking = false; - private boolean isClosed = false; - private volatile boolean dataAvailable = false; - - SocketInputStream(SocketChannel channel) { - this.channel = channel; - buffer.limit(0); - } - - public int available() { - return buffer.remaining(); - } - - public void mark(int readlimit) { - buffer.mark(); - } - - public boolean markSupported() { - return true; - } - - public void reset() { - buffer.reset(); - } - - public synchronized int read() throws IOException { - if(!checkAvailable(1)) { - block(1); - } - return buffer.get(); - } - - private boolean checkAvailable(int nbyte) throws IOException { - if(isClosed) { - throw new ClosedChannelException(); - } - return buffer.remaining() >= nbyte; - } - - private int fill(int nbyte) throws IOException { - int rem = nbyte; - int read = 0; - boolean eof = false; - byte [] oldData = null; - if(buffer.remaining() > 0) { - // should rarely happen, so short-lived GC shouldn't hurt - // as much as allocating a long-lived buffer for this - if(log.isDebugEnabled()) - log.debug("Saving old buffer: "+buffer.remaining()); - oldData = new byte[buffer.remaining()]; - buffer.get(oldData); - } - buffer.clear(); - if(oldData != null) { - buffer.put(oldData); - } - while(rem > 0) { - int count = channel.read(buffer); - if(count < 0) { - eof = true; - break; - } else if(count == 0) { - log.debug("Failed to recieve signaled read: "); - break; - } - read += count; - rem -= count; - } - buffer.flip(); - return eof ? -1 : read; - } - - synchronized boolean readAvailable() { - if(blocking) { - dataAvailable = true; - notify(); - } else if(dataAvailable) { - log.debug("Race Condition"); - } else { - int nr=0; - - try { - nr = fill(1); - } catch(ClosedChannelException cce) { - log.debug("Channel is closed",cce); - nr = -1; - } catch(IOException iex) { - log.warn("Exception processing read",iex); - nr = -1; // Can't handle this yet - } - if(nr < 0) { - isClosed = true; - notify(); - return false; - } else if(nr == 0) { - if(!nioIsBroken) { - dataAvailable = (buffer.remaining() <= 0); - } - } - } - return true; - } - - public int read(byte [] data) throws IOException { - return read(data, 0, data.length); - } - - public synchronized int read(byte [] data, int offset, int len) throws IOException { - int olen = len; - while(!checkAvailable(len)) { - int avail = buffer.remaining(); - if(avail > 0) { - buffer.get(data, offset, avail); - } - len -= avail; - offset += avail; - block(len); - } - buffer.get(data, offset, len); - return olen; - } - - private void block(int len) throws IOException { - if(len <= 0) { - return; - } - if(!dataAvailable) { - blocking = true; - if(log.isDebugEnabled()) - log.debug("Waiting for "+len+" bytes to be available"); - try{ - wait(socketTimeout); - }catch(InterruptedException iex) { - log.debug("Interrupted",iex); - } - blocking = false; - } - if(dataAvailable) { - dataAvailable = false; - if(fill(len) < 0) { - isClosed = true; - } - } - } - } - - protected class SocketOutputStream extends OutputStream { - ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize); - SocketChannel channel; - - SocketOutputStream(SocketChannel channel) { - this.channel = channel; - } - - public void write(int b) throws IOException { - if(!checkAvailable(1)) { - flush(); - } - buffer.put((byte)b); - } - - public void write(byte [] data) throws IOException { - write(data, 0, data.length); - } - - public void write(byte [] data, int offset, int len) throws IOException { - if(!checkAvailable(len)) { - flush(); - } - buffer.put(data, offset, len); - } - - public void flush() throws IOException { - buffer.flip(); - while(buffer.hasRemaining()) { - int count = channel.write(buffer); - if(count == 0) { - synchronized(this) { - SelectionKey key = channel.keyFor(selector); - key.interestOps(SelectionKey.OP_WRITE); - if(log.isDebugEnabled()) - log.debug("Blocking for channel write: "+buffer.remaining()); - try { - wait(); - } catch(InterruptedException iex) { - // ignore, since can't happen - } - key.interestOps(SelectionKey.OP_READ); - } - } - } - buffer.clear(); - } - - private boolean checkAvailable(int len) { - return buffer.remaining() >= len; - } - } - -} - +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.util.Set; +import java.util.Iterator; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.Selector; +import java.nio.channels.SelectionKey; +import java.nio.channels.SocketChannel; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.ClosedChannelException; +import java.net.URLEncoder; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.JkChannel; +import org.apache.jk.core.WorkerEnv; +import org.apache.coyote.Request; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.threads.ThreadPool; +import org.apache.tomcat.util.threads.ThreadPoolRunnable; + +/** + * Accept ( and send ) TCP messages. + * + * @author Costin Manolache + * @author Bill Barker + * jmx:mbean name="jk:service=ChannelNioSocket" + * description="Accept socket connections" + * jmx:notification name="org.apache.coyote.INVOKE + * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET + * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET + * jmx:notification-handler name="org.apache.jk.JK_FLUSH + * + * Jk can use multiple protocols/transports. + * Various container adapters should load this object ( as a bean ), + * set configurations and use it. Note that the connector will handle + * all incoming protocols - it's not specific to ajp1x. The protocol + * is abstracted by MsgContext/Message/Channel. + * + * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol, + * TCP, Ajp14 API etc. + * As we add other protocols/transports/APIs this will change, the current goal + * is to get the same level of functionality as in the original jk connector. + * + * XXX Make the 'message type' pluggable + */ +public class ChannelNioSocket extends JkHandler + implements NotificationBroadcaster, JkChannel { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog( ChannelNioSocket.class ); + + private int startPort=8009; + private int maxPort=8019; // 0 for backward compat. + private int port=startPort; + private InetAddress inet; + private int serverTimeout = 0; + private boolean tcpNoDelay=true; // nodelay to true by default + private int linger=100; + private int socketTimeout = 0; + private boolean nioIsBroken = false; + private Selector selector = null; + private int bufferSize = 8*1024; + + private long requestCount=0; + + /* Turning this to true will reduce the latency with about 20%. + But it requires changes in tomcat to make sure client-requested + flush() is honored ( on my test, I got 367->433 RPS and + 52->35ms average time with a simple servlet ) + */ + + ThreadPool tp=ThreadPool.createThreadPool(true); + + /* ==================== Tcp socket options ==================== */ + + /** + * jmx:managed-constructor description="default constructor" + */ + public ChannelNioSocket() { + // This should be integrated with the domain setup + } + + public ThreadPool getThreadPool() { + return tp; + } + + public long getRequestCount() { + return requestCount; + } + + /** Set the port for the ajp13 channel. + * To support seemless load balancing and jni, we treat this + * as the 'base' port - we'll try up until we find one that is not + * used. We'll also provide the 'difference' to the main coyote + * handler - that will be our 'sessionID' and the position in + * the scoreboard and the suffix for the unix domain socket. + * + * jmx:managed-attribute description="Port to listen" access="READ_WRITE" + */ + public void setPort( int port ) { + this.startPort=port; + this.port=port; + this.maxPort=port+10; + } + + public int getPort() { + return port; + } + + public void setAddress(InetAddress inet) { + this.inet=inet; + } + + public void setBufferSize(int bs) { + if(bs > 8*1024) { + bufferSize = bs; + } + } + + public int getBufferSize() { + return bufferSize; + } + + + /** + * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE" + */ + public void setAddress(String inet) { + try { + this.inet= InetAddress.getByName( inet ); + } catch( Exception ex ) { + log.error("Error parsing "+inet,ex); + } + } + + public String getAddress() { + if( inet!=null) + return inet.toString(); + return "/0.0.0.0"; + } + + /** + * Sets the timeout in ms of the server sockets created by this + * server. This method allows the developer to make servers + * more or less responsive to having their server sockets + * shut down. + * + *

        By default this value is 1000ms. + */ + public void setServerTimeout(int timeout) { + this.serverTimeout = timeout; + } + public int getServerTimeout() { + return serverTimeout; + } + + public void setTcpNoDelay( boolean b ) { + tcpNoDelay=b; + } + + public boolean getTcpNoDelay() { + return tcpNoDelay; + } + + public void setSoLinger( int i ) { + linger=i; + } + + public int getSoLinger() { + return linger; + } + + public void setSoTimeout( int i ) { + socketTimeout=i; + } + + public int getSoTimeout() { + return socketTimeout; + } + + public void setMaxPort( int i ) { + maxPort=i; + } + + public int getMaxPort() { + return maxPort; + } + + /** At startup we'll look for the first free port in the range. + The difference between this port and the beggining of the range + is the 'id'. + This is usefull for lb cases ( less config ). + */ + public int getInstanceId() { + return port-startPort; + } + + /** If set to false, the thread pool will be created in + * non-daemon mode, and will prevent main from exiting + */ + public void setDaemon( boolean b ) { + tp.setDaemon( b ); + } + + public boolean getDaemon() { + return tp.getDaemon(); + } + + + public void setMaxThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i); + tp.setMaxThreads(i); + } + + public void setMinSpareThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i); + tp.setMinSpareThreads(i); + } + + public void setMaxSpareThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i); + tp.setMaxSpareThreads(i); + } + + public int getMaxThreads() { + return tp.getMaxThreads(); + } + + public int getMinSpareThreads() { + return tp.getMinSpareThreads(); + } + + public int getMaxSpareThreads() { + return tp.getMaxSpareThreads(); + } + + public void setBacklog(int i) { + } + + public void setNioIsBroken(boolean nib) { + nioIsBroken = nib; + } + + public boolean getNioIsBroken() { + return nioIsBroken; + } + + /* ==================== ==================== */ + ServerSocket sSocket; + final int socketNote=1; + final int isNote=2; + final int osNote=3; + final int notifNote=4; + boolean paused = false; + + public void pause() throws Exception { + synchronized(this) { + paused = true; + } + } + + public void resume() { + synchronized(this) { + paused = false; + notify(); + } + } + + + public void accept( MsgContext ep ) throws IOException { + if( sSocket==null ) return; + synchronized(this) { + while(paused) { + try{ + wait(); + } catch(InterruptedException ie) { + //Ignore, since can't happen + } + } + } + SocketChannel sc=sSocket.getChannel().accept(); + Socket s = sc.socket(); + ep.setNote( socketNote, s ); + if(log.isDebugEnabled() ) + log.debug("Accepted socket " + s +" channel " + sc.isBlocking()); + + try { + setSocketOptions(s); + } catch(SocketException sex) { + log.debug("Error initializing Socket Options", sex); + } + + requestCount++; + + sc.configureBlocking(false); + InputStream is=new SocketInputStream(sc); + OutputStream os = new SocketOutputStream(sc); + ep.setNote( isNote, is ); + ep.setNote( osNote, os ); + ep.setControl( tp ); + } + + private void setSocketOptions(Socket s) throws SocketException { + if( socketTimeout > 0 ) + s.setSoTimeout( socketTimeout ); + + s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state + + if( linger > 0 ) + s.setSoLinger( true, linger); + } + + public void resetCounters() { + requestCount=0; + } + + /** Called after you change some fields at runtime using jmx. + Experimental for now. + */ + public void reinit() throws IOException { + destroy(); + init(); + } + + /** + * jmx:managed-operation + */ + public void init() throws IOException { + // Find a port. + if (startPort == 0) { + port = 0; + if(log.isInfoEnabled()) + log.info("JK: ajp13 disabling channelNioSocket"); + running = true; + return; + } + if (maxPort < startPort) + maxPort = startPort; + ServerSocketChannel ssc = ServerSocketChannel.open(); + ssc.configureBlocking(false); + for( int i=startPort; i<=maxPort; i++ ) { + try { + InetSocketAddress iddr = null; + if( inet == null ) { + iddr = new InetSocketAddress( i); + } else { + iddr=new InetSocketAddress( inet, i); + } + sSocket = ssc.socket(); + sSocket.bind(iddr); + port=i; + break; + } catch( IOException ex ) { + if(log.isInfoEnabled()) + log.info("Port busy " + i + " " + ex.toString()); + sSocket = null; + } + } + + if( sSocket==null ) { + log.error("Can't find free port " + startPort + " " + maxPort ); + return; + } + if(log.isInfoEnabled()) + log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); + + selector = Selector.open(); + ssc.register(selector, SelectionKey.OP_ACCEPT); + // If this is not the base port and we are the 'main' channleSocket and + // SHM didn't already set the localId - we'll set the instance id + if( "channelNioSocket".equals( name ) && + port != startPort && + (wEnv.getLocalId()==0) ) { + wEnv.setLocalId( port - startPort ); + } + + // XXX Reverse it -> this is a notification generator !! + if( next==null && wEnv!=null ) { + if( nextName!=null ) + setNext( wEnv.getHandler( nextName ) ); + if( next==null ) + next=wEnv.getHandler( "dispatch" ); + if( next==null ) + next=wEnv.getHandler( "request" ); + } + JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); + running = true; + + // Run a thread that will accept connections. + // XXX Try to find a thread first - not sure how... + if( this.domain != null ) { + try { + tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + + getChannelName()); + + Registry.getRegistry(null, null) + .registerComponent(tp, tpOName, null); + + rgOName = new ObjectName + (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); + Registry.getRegistry(null, null) + .registerComponent(global, rgOName, null); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + } + + tp.start(); + Poller pollAjp = new Poller(); + tp.runIt(pollAjp); + } + + ObjectName tpOName; + ObjectName rgOName; + RequestGroupInfo global=new RequestGroupInfo(); + int JMXRequestNote; + + public void start() throws IOException{ + if( sSocket==null ) + init(); + resume(); + } + + public void stop() throws IOException { + destroy(); + } + + public void registerRequest(Request req, MsgContext ep, int count) { + if(this.domain != null) { + try { + RequestInfo rp=req.getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName roname = new ObjectName + (getDomain() + ":type=RequestProcessor,worker="+ + getChannelName()+",name=JkRequest" +count); + ep.setNote(JMXRequestNote, roname); + + Registry.getRegistry(null, null).registerComponent( rp, roname, null); + } catch( Exception ex ) { + log.warn("Error registering request"); + } + } + } + + public void open(MsgContext ep) throws IOException { + } + + + public void close(MsgContext ep) throws IOException { + Socket s=(Socket)ep.getNote( socketNote ); + SelectionKey key = s.getChannel().keyFor(selector); + if(key != null) { + key.cancel(); + } + s.close(); + } + + public void destroy() throws IOException { + running = false; + try { + /* If we disabled the channel return */ + if (port == 0) + return; + tp.shutdown(); + + selector.wakeup().close(); + sSocket.close(); // XXX? + + if( tpOName != null ) { + Registry.getRegistry(null, null).unregisterComponent(tpOName); + } + if( rgOName != null ) { + Registry.getRegistry(null, null).unregisterComponent(rgOName); + } + } catch(Exception e) { + log.info("Error shutting down the channel " + port + " " + + e.toString()); + if( log.isDebugEnabled() ) log.debug("Trace", e); + } + } + + public int send( Msg msg, MsgContext ep) + throws IOException { + msg.end(); // Write the packet header + byte buf[]=msg.getBuffer(); + int len=msg.getLen(); + + if(log.isTraceEnabled() ) + log.trace("send() " + len + " " + buf[4] ); + + OutputStream os=(OutputStream)ep.getNote( osNote ); + os.write( buf, 0, len ); + return len; + } + + public int flush( Msg msg, MsgContext ep) + throws IOException { + OutputStream os=(OutputStream)ep.getNote( osNote ); + os.flush(); + return 0; + } + + public int receive( Msg msg, MsgContext ep ) + throws IOException { + if (log.isTraceEnabled()) { + log.trace("receive() "); + } + + byte buf[]=msg.getBuffer(); + int hlen=msg.getHeaderLength(); + + // XXX If the length in the packet header doesn't agree with the + // actual number of bytes read, it should probably return an error + // value. Also, callers of this method never use the length + // returned -- should probably return true/false instead. + + int rd = this.read(ep, buf, 0, hlen ); + + if(rd < 0) { + // Most likely normal apache restart. + // log.warn("Wrong message " + rd ); + return rd; + } + + msg.processHeader(); + + /* After processing the header we know the body + length + */ + int blen=msg.getLen(); + + // XXX check if enough space - it's assert()-ed !!! + + int total_read = 0; + + total_read = this.read(ep, buf, hlen, blen); + + if ((total_read <= 0) && (blen > 0)) { + log.warn("can't read body, waited #" + blen); + return -1; + } + + if (total_read != blen) { + log.warn( "incomplete read, waited #" + blen + + " got only " + total_read); + return -2; + } + + return total_read; + } + + /** + * Read N bytes from the InputStream, and ensure we got them all + * Under heavy load we could experience many fragmented packets + * just read Unix Network Programming to recall that a call to + * read didn't ensure you got all the data you want + * + * from read() Linux manual + * + * On success, the number of bytes read is returned (zero indicates end + * of file),and the file position is advanced by this number. + * It is not an error if this number is smaller than the number of bytes + * requested; this may happen for example because fewer bytes + * are actually available right now (maybe because we were close to + * end-of-file, or because we are reading from a pipe, or from a + * terminal), or because read() was interrupted by a signal. + * On error, -1 is returned, and errno is set appropriately. In this + * case it is left unspecified whether the file position (if any) changes. + * + **/ + public int read( MsgContext ep, byte[] b, int offset, int len) + throws IOException + { + InputStream is=(InputStream)ep.getNote( isNote ); + int pos = 0; + int got; + + while(pos < len) { + try { + got = is.read(b, pos + offset, len - pos); + } catch(ClosedChannelException sex) { + if(pos > 0) { + log.info("Error reading data after "+pos+"bytes",sex); + } else { + log.debug("Error reading data", sex); + } + got = -1; + } + if (log.isTraceEnabled()) { + log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " + + offset + " " + len + " = " + got ); + } + + // connection just closed by remote. + if (got <= 0) { + // This happens periodically, as apache restarts + // periodically. + // It should be more gracefull ! - another feature for Ajp14 + // log.warn( "server has closed the current connection (-1)" ); + return -3; + } + + pos += got; + } + return pos; + } + + protected boolean running=true; + + /** Accept incoming connections, dispatch to the thread pool + */ + void acceptConnections() { + if( running ) { + try{ + MsgContext ep=createMsgContext(); + ep.setSource(this); + ep.setWorkerEnv( wEnv ); + this.accept(ep); + + if( !running ) return; + + // Since this is a long-running connection, we don't care + // about the small GC + SocketConnection ajpConn= + new SocketConnection( ep); + ajpConn.register(ep); + }catch(Exception ex) { + if (running) + log.warn("Exception executing accept" ,ex); + } + } + } + + + // XXX This should become handleNotification + public int invoke( Msg msg, MsgContext ep ) throws IOException { + int type=ep.getType(); + + switch( type ) { + case JkHandler.HANDLE_RECEIVE_PACKET: + if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? "); + return receive( msg, ep ); + case JkHandler.HANDLE_SEND_PACKET: + return send( msg, ep ); + case JkHandler.HANDLE_FLUSH: + return flush( msg, ep ); + } + + if( log.isTraceEnabled() ) + log.trace("Call next " + type + " " + next); + + // Send notification + if( nSupport!=null ) { + Notification notif=(Notification)ep.getNote(notifNote); + if( notif==null ) { + notif=new Notification("channelNioSocket.message", ep, requestCount ); + ep.setNote( notifNote, notif); + } + nSupport.sendNotification(notif); + } + + if( next != null ) { + return next.invoke( msg, ep ); + } else { + log.info("No next "); + } + + return OK; + } + + public boolean isSameAddress(MsgContext ep) { + Socket s=(Socket)ep.getNote( socketNote ); + return isSameAddress( s.getLocalAddress(), s.getInetAddress()); + } + + public String getChannelName() { + String encodedAddr = ""; + if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) { + encodedAddr = getAddress(); + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) + "-"; + } + return ("jk-" + encodedAddr + port); + } + + /** + * Return true if the specified client and server addresses + * are the same. This method works around a bug in the IBM 1.1.8 JVM on + * Linux, where the address bytes are returned reversed in some + * circumstances. + * + * @param server The server's InetAddress + * @param client The client's InetAddress + */ + public static boolean isSameAddress(InetAddress server, InetAddress client) + { + // Compare the byte array versions of the two addresses + byte serverAddr[] = server.getAddress(); + byte clientAddr[] = client.getAddress(); + if (serverAddr.length != clientAddr.length) + return (false); + boolean match = true; + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[i]) { + match = false; + break; + } + } + if (match) + return (true); + + // Compare the reversed form of the two addresses + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i]) + return (false); + } + return (true); + } + + public void sendNewMessageNotification(Notification notification) { + if( nSupport!= null ) + nSupport.sendNotification(notification); + } + + private NotificationBroadcasterSupport nSupport= null; + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IllegalArgumentException + { + if( nSupport==null ) nSupport=new NotificationBroadcasterSupport(); + nSupport.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + if( nSupport!=null) + nSupport.removeNotificationListener(listener); + } + + MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0]; + + public void setNotificationInfo( MBeanNotificationInfo info[]) { + this.notifInfo=info; + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return notifInfo; + } + + protected class SocketConnection implements ThreadPoolRunnable { + MsgContext ep; + MsgAjp recv = new MsgAjp(); + boolean inProgress = false; + + SocketConnection(MsgContext ep) { + this.ep=ep; + } + + public Object[] getInitData() { + return null; + } + + public void runIt(Object perTh[]) { + if(!processConnection(ep)) { + unregister(ep); + } + } + + public boolean isRunning() { + return inProgress; + } + + public void setFinished() { + inProgress = false; + } + + /** Process a single ajp connection. + */ + boolean processConnection(MsgContext ep) { + try { + InputStream sis = (InputStream)ep.getNote(isNote); + boolean haveInput = true; + while(haveInput) { + if( !running || paused ) { + return false; + } + int status= receive( recv, ep ); + if( status <= 0 ) { + if( status==-3) + log.debug( "server has been restarted or reset this connection" ); + else + log.warn("Closing ajp connection " + status ); + return false; + } + ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis()); + + ep.setType( 0 ); + // Will call next + status= invoke( recv, ep ); + if( status != JkHandler.OK ) { + log.warn("processCallbacks status " + status ); + return false; + } + synchronized(this) { + synchronized(sis) { + haveInput = sis.available() > 0; + } + if(!haveInput) { + setFinished(); + } else { + if(log.isDebugEnabled()) + log.debug("KeepAlive: "+sis.available()); + } + } + } + } catch( Exception ex ) { + String msg = ex.getMessage(); + if( msg != null && msg.indexOf( "Connection reset" ) >= 0) + log.debug( "Server has been restarted or reset this connection"); + else if (msg != null && msg.indexOf( "Read timed out" ) >=0 ) + log.debug( "connection timeout reached"); + else + log.error( "Error, processing connection", ex); + return false; + } + return true; + } + + synchronized void process(SelectionKey sk) { + if(!sk.isValid()) { + return; + } + if(sk.isReadable()) { + SocketInputStream sis = (SocketInputStream)ep.getNote(isNote); + boolean isok = sis.readAvailable(); + if(!inProgress) { + if(isok) { + if(sis.available() > 0 || !nioIsBroken){ + inProgress = true; + tp.runIt(this); + } + } else { + unregister(ep); + return; + } + } + } + if(sk.isWritable()) { + Object os = ep.getNote(osNote); + synchronized(os) { + os.notify(); + } + } + } + + synchronized void unregister(MsgContext ep) { + try{ + close(ep); + } catch(Exception e) { + log.error("Error closing connection", e); + } + try{ + Request req = (Request)ep.getRequest(); + if( req != null ) { + ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); + if( roname != null ) { + Registry.getRegistry(null, null).unregisterComponent(roname); + } + req.getRequestProcessor().setGlobalProcessor(null); + } + } catch( Exception ee) { + log.error( "Error, releasing connection",ee); + } + } + + void register(MsgContext ep) { + Socket s = (Socket)ep.getNote(socketNote); + try { + s.getChannel().register(selector, SelectionKey.OP_READ, this); + } catch(IOException iex) { + log.error("Unable to register connection",iex); + unregister(ep); + } + } + + } + + protected class Poller implements ThreadPoolRunnable { + + Poller() { + } + + public Object[] getInitData() { + return null; + } + + public void runIt(Object perTh[]) { + while(running) { + try { + int ns = selector.select(serverTimeout); + if(log.isDebugEnabled()) + log.debug("Selecting "+ns+" channels"); + if(ns > 0) { + Set sels = selector.selectedKeys(); + Iterator it = sels.iterator(); + while(it.hasNext()) { + SelectionKey sk = (SelectionKey)it.next(); + if(sk.isValid()) { + if(sk.isAcceptable()) { + acceptConnections(); + } else { + SocketConnection sc = (SocketConnection)sk.attachment(); + sc.process(sk); + } + } else { + sk.cancel(); + } + it.remove(); + } + } + } catch(ClosedSelectorException cse) { + log.debug("Selector is closed"); + return; + } catch(CancelledKeyException cke) { + log.debug("Key Cancelled", cke); + } catch(IOException iex) { + log.warn("IO Error in select",iex); + } catch(Exception ex) { + log.warn("Error processing select",ex); + } + } + } + } + + protected class SocketInputStream extends InputStream { + final int BUFFER_SIZE = 8200; + private ByteBuffer buffer = ByteBuffer.allocateDirect(BUFFER_SIZE); + private SocketChannel channel; + private boolean blocking = false; + private boolean isClosed = false; + private volatile boolean dataAvailable = false; + + SocketInputStream(SocketChannel channel) { + this.channel = channel; + buffer.limit(0); + } + + public int available() { + return buffer.remaining(); + } + + public void mark(int readlimit) { + buffer.mark(); + } + + public boolean markSupported() { + return true; + } + + public void reset() { + buffer.reset(); + } + + public synchronized int read() throws IOException { + if(!checkAvailable(1)) { + block(1); + } + return buffer.get(); + } + + private boolean checkAvailable(int nbyte) throws IOException { + if(isClosed) { + throw new ClosedChannelException(); + } + return buffer.remaining() >= nbyte; + } + + private int fill(int nbyte) throws IOException { + int rem = nbyte; + int read = 0; + boolean eof = false; + byte [] oldData = null; + if(buffer.remaining() > 0) { + // should rarely happen, so short-lived GC shouldn't hurt + // as much as allocating a long-lived buffer for this + if(log.isDebugEnabled()) + log.debug("Saving old buffer: "+buffer.remaining()); + oldData = new byte[buffer.remaining()]; + buffer.get(oldData); + } + buffer.clear(); + if(oldData != null) { + buffer.put(oldData); + } + while(rem > 0) { + int count = channel.read(buffer); + if(count < 0) { + eof = true; + break; + } else if(count == 0) { + log.debug("Failed to recieve signaled read: "); + break; + } + read += count; + rem -= count; + } + buffer.flip(); + return eof ? -1 : read; + } + + synchronized boolean readAvailable() { + if(blocking) { + dataAvailable = true; + notify(); + } else if(dataAvailable) { + log.debug("Race Condition"); + } else { + int nr=0; + + try { + nr = fill(1); + } catch(ClosedChannelException cce) { + log.debug("Channel is closed",cce); + nr = -1; + } catch(IOException iex) { + log.warn("Exception processing read",iex); + nr = -1; // Can't handle this yet + } + if(nr < 0) { + isClosed = true; + notify(); + return false; + } else if(nr == 0) { + if(!nioIsBroken) { + dataAvailable = (buffer.remaining() <= 0); + } + } + } + return true; + } + + public int read(byte [] data) throws IOException { + return read(data, 0, data.length); + } + + public synchronized int read(byte [] data, int offset, int len) throws IOException { + int olen = len; + while(!checkAvailable(len)) { + int avail = buffer.remaining(); + if(avail > 0) { + buffer.get(data, offset, avail); + } + len -= avail; + offset += avail; + block(len); + } + buffer.get(data, offset, len); + return olen; + } + + private void block(int len) throws IOException { + if(len <= 0) { + return; + } + if(!dataAvailable) { + blocking = true; + if(log.isDebugEnabled()) + log.debug("Waiting for "+len+" bytes to be available"); + try{ + wait(socketTimeout); + }catch(InterruptedException iex) { + log.debug("Interrupted",iex); + } + blocking = false; + } + if(dataAvailable) { + dataAvailable = false; + if(fill(len) < 0) { + isClosed = true; + } + } + } + } + + protected class SocketOutputStream extends OutputStream { + ByteBuffer buffer = ByteBuffer.allocateDirect(bufferSize); + SocketChannel channel; + + SocketOutputStream(SocketChannel channel) { + this.channel = channel; + } + + public void write(int b) throws IOException { + if(!checkAvailable(1)) { + flush(); + } + buffer.put((byte)b); + } + + public void write(byte [] data) throws IOException { + write(data, 0, data.length); + } + + public void write(byte [] data, int offset, int len) throws IOException { + if(!checkAvailable(len)) { + flush(); + } + buffer.put(data, offset, len); + } + + public void flush() throws IOException { + buffer.flip(); + while(buffer.hasRemaining()) { + int count = channel.write(buffer); + if(count == 0) { + synchronized(this) { + SelectionKey key = channel.keyFor(selector); + key.interestOps(SelectionKey.OP_WRITE); + if(log.isDebugEnabled()) + log.debug("Blocking for channel write: "+buffer.remaining()); + try { + wait(); + } catch(InterruptedException iex) { + // ignore, since can't happen + } + key.interestOps(SelectionKey.OP_READ); + } + } + } + buffer.clear(); + } + + private boolean checkAvailable(int len) { + return buffer.remaining() >= len; + } + } + +} + diff --git a/java/org/apache/jk/common/ChannelShm.java b/java/org/apache/jk/common/ChannelShm.java index 97dd22458..ceaaf9a6a 100644 --- a/java/org/apache/jk/common/ChannelShm.java +++ b/java/org/apache/jk/common/ChannelShm.java @@ -1,32 +1,32 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import org.apache.jk.core.JkHandler; - - - -/** Channel using shm. - * - * @author Costin Manolache - */ -public class ChannelShm extends JkHandler { - - // Not implemented yet. - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import org.apache.jk.core.JkHandler; + + + +/** Channel using shm. + * + * @author Costin Manolache + */ +public class ChannelShm extends JkHandler { + + // Not implemented yet. + + +} diff --git a/java/org/apache/jk/common/ChannelSocket.java b/java/org/apache/jk/common/ChannelSocket.java index c49833d7d..184abd337 100644 --- a/java/org/apache/jk/common/ChannelSocket.java +++ b/java/org/apache/jk/common/ChannelSocket.java @@ -1,882 +1,882 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.BufferedInputStream; -import java.io.BufferedOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.URLEncoder; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; - -import javax.management.ListenerNotFoundException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationBroadcasterSupport; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; -import javax.management.ObjectName; - -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.JkChannel; -import org.apache.jk.core.WorkerEnv; -import org.apache.coyote.Request; -import org.apache.coyote.RequestGroupInfo; -import org.apache.coyote.RequestInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.threads.ThreadPool; -import org.apache.tomcat.util.threads.ThreadPoolRunnable; - -/** - * Accept ( and send ) TCP messages. - * - * @author Costin Manolache - * @author Bill Barker - * jmx:mbean name="jk:service=ChannelNioSocket" - * description="Accept socket connections" - * jmx:notification name="org.apache.coyote.INVOKE - * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET - * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET - * jmx:notification-handler name="org.apache.jk.JK_FLUSH - * - * Jk can use multiple protocols/transports. - * Various container adapters should load this object ( as a bean ), - * set configurations and use it. Note that the connector will handle - * all incoming protocols - it's not specific to ajp1x. The protocol - * is abstracted by MsgContext/Message/Channel. - * - * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol, - * TCP, Ajp14 API etc. - * As we add other protocols/transports/APIs this will change, the current goal - * is to get the same level of functionality as in the original jk connector. - * - * XXX Make the 'message type' pluggable - */ -public class ChannelSocket extends JkHandler - implements NotificationBroadcaster, JkChannel { - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog( ChannelSocket.class ); - - private int startPort=8009; - private int maxPort=8019; // 0 for backward compat. - private int port=startPort; - private InetAddress inet; - private int serverTimeout; - private boolean tcpNoDelay=true; // nodelay to true by default - private int linger=100; - private int socketTimeout; - private int bufferSize = -1; - - private long requestCount=0; - - ThreadPool tp=ThreadPool.createThreadPool(true); - - /* ==================== Tcp socket options ==================== */ - - /** - * jmx:managed-constructor description="default constructor" - */ - public ChannelSocket() { - // This should be integrated with the domain setup - } - - public ThreadPool getThreadPool() { - return tp; - } - - public long getRequestCount() { - return requestCount; - } - - /** Set the port for the ajp13 channel. - * To support seemless load balancing and jni, we treat this - * as the 'base' port - we'll try up until we find one that is not - * used. We'll also provide the 'difference' to the main coyote - * handler - that will be our 'sessionID' and the position in - * the scoreboard and the suffix for the unix domain socket. - * - * jmx:managed-attribute description="Port to listen" access="READ_WRITE" - */ - public void setPort( int port ) { - this.startPort=port; - this.port=port; - this.maxPort=port+10; - } - - public int getPort() { - return port; - } - - public void setAddress(InetAddress inet) { - this.inet=inet; - } - - /** - * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE" - */ - public void setAddress(String inet) { - try { - this.inet= InetAddress.getByName( inet ); - } catch( Exception ex ) { - log.error("Error parsing "+inet,ex); - } - } - - public String getAddress() { - if( inet!=null) - return inet.toString(); - return "/0.0.0.0"; - } - - /** - * Sets the timeout in ms of the server sockets created by this - * server. This method allows the developer to make servers - * more or less responsive to having their server sockets - * shut down. - * - *

        By default this value is 1000ms. - */ - public void setServerTimeout(int timeout) { - this.serverTimeout = timeout; - } - public int getServerTimeout() { - return serverTimeout; - } - - public void setTcpNoDelay( boolean b ) { - tcpNoDelay=b; - } - - public boolean getTcpNoDelay() { - return tcpNoDelay; - } - - public void setSoLinger( int i ) { - linger=i; - } - - public int getSoLinger() { - return linger; - } - - public void setSoTimeout( int i ) { - socketTimeout=i; - } - - public int getSoTimeout() { - return socketTimeout; - } - - public void setMaxPort( int i ) { - maxPort=i; - } - - public int getMaxPort() { - return maxPort; - } - - public void setBufferSize(int bs) { - bufferSize = bs; - } - - public int getBufferSize() { - return bufferSize; - } - - /** At startup we'll look for the first free port in the range. - The difference between this port and the beggining of the range - is the 'id'. - This is usefull for lb cases ( less config ). - */ - public int getInstanceId() { - return port-startPort; - } - - /** If set to false, the thread pool will be created in - * non-daemon mode, and will prevent main from exiting - */ - public void setDaemon( boolean b ) { - tp.setDaemon( b ); - } - - public boolean getDaemon() { - return tp.getDaemon(); - } - - - public void setMaxThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i); - tp.setMaxThreads(i); - } - - public void setMinSpareThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i); - tp.setMinSpareThreads(i); - } - - public void setMaxSpareThreads( int i ) { - if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i); - tp.setMaxSpareThreads(i); - } - - public int getMaxThreads() { - return tp.getMaxThreads(); - } - - public int getMinSpareThreads() { - return tp.getMinSpareThreads(); - } - - public int getMaxSpareThreads() { - return tp.getMaxSpareThreads(); - } - - public void setBacklog(int i) { - } - - - /* ==================== ==================== */ - ServerSocket sSocket; - final int socketNote=1; - final int isNote=2; - final int osNote=3; - final int notifNote=4; - boolean paused = false; - - public void pause() throws Exception { - synchronized(this) { - paused = true; - unLockSocket(); - } - } - - public void resume() throws Exception { - synchronized(this) { - paused = false; - notify(); - } - } - - - public void accept( MsgContext ep ) throws IOException { - if( sSocket==null ) return; - synchronized(this) { - while(paused) { - try{ - wait(); - } catch(InterruptedException ie) { - //Ignore, since can't happen - } - } - } - Socket s=sSocket.accept(); - ep.setNote( socketNote, s ); - if(log.isDebugEnabled() ) - log.debug("Accepted socket " + s ); - - try { - setSocketOptions(s); - } catch(SocketException sex) { - log.debug("Error initializing Socket Options", sex); - } - - requestCount++; - - InputStream is=new BufferedInputStream(s.getInputStream()); - OutputStream os; - if( bufferSize > 0 ) - os = new BufferedOutputStream( s.getOutputStream(), bufferSize); - else - os = s.getOutputStream(); - ep.setNote( isNote, is ); - ep.setNote( osNote, os ); - ep.setControl( tp ); - } - - private void setSocketOptions(Socket s) throws SocketException { - if( socketTimeout > 0 ) - s.setSoTimeout( socketTimeout ); - - s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state - - if( linger > 0 ) - s.setSoLinger( true, linger); - } - - public void resetCounters() { - requestCount=0; - } - - /** Called after you change some fields at runtime using jmx. - Experimental for now. - */ - public void reinit() throws IOException { - destroy(); - init(); - } - - /** - * jmx:managed-operation - */ - public void init() throws IOException { - // Find a port. - if (startPort == 0) { - port = 0; - if(log.isInfoEnabled()) - log.info("JK: ajp13 disabling channelSocket"); - running = true; - return; - } - if (maxPort < startPort) - maxPort = startPort; - for( int i=startPort; i<=maxPort; i++ ) { - try { - if( inet == null ) { - sSocket = new ServerSocket( i, 0 ); - } else { - sSocket=new ServerSocket( i, 0, inet ); - } - port=i; - break; - } catch( IOException ex ) { - if(log.isInfoEnabled()) - log.info("Port busy " + i + " " + ex.toString()); - continue; - } - } - - if( sSocket==null ) { - log.error("Can't find free port " + startPort + " " + maxPort ); - return; - } - if(log.isInfoEnabled()) - log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); - - // If this is not the base port and we are the 'main' channleSocket and - // SHM didn't already set the localId - we'll set the instance id - if( "channelSocket".equals( name ) && - port != startPort && - (wEnv.getLocalId()==0) ) { - wEnv.setLocalId( port - startPort ); - } - if( serverTimeout > 0 ) - sSocket.setSoTimeout( serverTimeout ); - - // XXX Reverse it -> this is a notification generator !! - if( next==null && wEnv!=null ) { - if( nextName!=null ) - setNext( wEnv.getHandler( nextName ) ); - if( next==null ) - next=wEnv.getHandler( "dispatch" ); - if( next==null ) - next=wEnv.getHandler( "request" ); - } - JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); - running = true; - - // Run a thread that will accept connections. - // XXX Try to find a thread first - not sure how... - if( this.domain != null ) { - try { - tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + - getChannelName()); - - Registry.getRegistry(null, null) - .registerComponent(tp, tpOName, null); - - rgOName = new ObjectName - (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); - Registry.getRegistry(null, null) - .registerComponent(global, rgOName, null); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - } - - tp.start(); - SocketAcceptor acceptAjp=new SocketAcceptor( this ); - tp.runIt( acceptAjp); - - } - - ObjectName tpOName; - ObjectName rgOName; - RequestGroupInfo global=new RequestGroupInfo(); - int JMXRequestNote; - - public void start() throws IOException{ - if( sSocket==null ) - init(); - } - - public void stop() throws IOException { - destroy(); - } - - public void registerRequest(Request req, MsgContext ep, int count) { - if(this.domain != null) { - try { - RequestInfo rp=req.getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName roname = new ObjectName - (getDomain() + ":type=RequestProcessor,worker="+ - getChannelName()+",name=JkRequest" +count); - ep.setNote(JMXRequestNote, roname); - - Registry.getRegistry(null, null).registerComponent( rp, roname, null); - } catch( Exception ex ) { - log.warn("Error registering request"); - } - } - } - - public void open(MsgContext ep) throws IOException { - } - - - public void close(MsgContext ep) throws IOException { - Socket s=(Socket)ep.getNote( socketNote ); - s.close(); - } - - private void unLockSocket() throws IOException { - // Need to create a connection to unlock the accept(); - Socket s; - InetAddress ladr = inet; - - if(port == 0) - return; - if (ladr == null || "0.0.0.0".equals(ladr.getHostAddress())) { - ladr = InetAddress.getLocalHost(); - } - s=new Socket(ladr, port ); - // setting soLinger to a small value will help shutdown the - // connection quicker - s.setSoLinger(true, 0); - - s.close(); - } - - public void destroy() throws IOException { - running = false; - try { - /* If we disabled the channel return */ - if (port == 0) - return; - tp.shutdown(); - - if(!paused) { - unLockSocket(); - } - - sSocket.close(); // XXX? - - if( tpOName != null ) { - Registry.getRegistry(null, null).unregisterComponent(tpOName); - } - if( rgOName != null ) { - Registry.getRegistry(null, null).unregisterComponent(rgOName); - } - } catch(Exception e) { - log.info("Error shutting down the channel " + port + " " + - e.toString()); - if( log.isDebugEnabled() ) log.debug("Trace", e); - } - } - - public int send( Msg msg, MsgContext ep) - throws IOException { - msg.end(); // Write the packet header - byte buf[]=msg.getBuffer(); - int len=msg.getLen(); - - if(log.isTraceEnabled() ) - log.trace("send() " + len + " " + buf[4] ); - - OutputStream os=(OutputStream)ep.getNote( osNote ); - os.write( buf, 0, len ); - return len; - } - - public int flush( Msg msg, MsgContext ep) - throws IOException { - if( bufferSize > 0 ) { - OutputStream os=(OutputStream)ep.getNote( osNote ); - os.flush(); - } - return 0; - } - - public int receive( Msg msg, MsgContext ep ) - throws IOException { - if (log.isDebugEnabled()) { - log.debug("receive() "); - } - - byte buf[]=msg.getBuffer(); - int hlen=msg.getHeaderLength(); - - // XXX If the length in the packet header doesn't agree with the - // actual number of bytes read, it should probably return an error - // value. Also, callers of this method never use the length - // returned -- should probably return true/false instead. - - int rd = this.read(ep, buf, 0, hlen ); - - if(rd < 0) { - // Most likely normal apache restart. - // log.warn("Wrong message " + rd ); - return rd; - } - - msg.processHeader(); - - /* After processing the header we know the body - length - */ - int blen=msg.getLen(); - - // XXX check if enough space - it's assert()-ed !!! - - int total_read = 0; - - total_read = this.read(ep, buf, hlen, blen); - - if ((total_read <= 0) && (blen > 0)) { - log.warn("can't read body, waited #" + blen); - return -1; - } - - if (total_read != blen) { - log.warn( "incomplete read, waited #" + blen + - " got only " + total_read); - return -2; - } - - return total_read; - } - - /** - * Read N bytes from the InputStream, and ensure we got them all - * Under heavy load we could experience many fragmented packets - * just read Unix Network Programming to recall that a call to - * read didn't ensure you got all the data you want - * - * from read() Linux manual - * - * On success, the number of bytes read is returned (zero indicates end - * of file),and the file position is advanced by this number. - * It is not an error if this number is smaller than the number of bytes - * requested; this may happen for example because fewer bytes - * are actually available right now (maybe because we were close to - * end-of-file, or because we are reading from a pipe, or from a - * terminal), or because read() was interrupted by a signal. - * On error, -1 is returned, and errno is set appropriately. In this - * case it is left unspecified whether the file position (if any) changes. - * - **/ - public int read( MsgContext ep, byte[] b, int offset, int len) - throws IOException { - InputStream is=(InputStream)ep.getNote( isNote ); - int pos = 0; - int got; - - while(pos < len) { - try { - got = is.read(b, pos + offset, len - pos); - } catch(SocketException sex) { - if(pos > 0) { - log.info("Error reading data after "+pos+"bytes",sex); - } else { - log.debug("Error reading data", sex); - } - got = -1; - } - if (log.isTraceEnabled()) { - log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " + - offset + " " + len + " = " + got ); - } - - // connection just closed by remote. - if (got <= 0) { - // This happens periodically, as apache restarts - // periodically. - // It should be more gracefull ! - another feature for Ajp14 - // log.warn( "server has closed the current connection (-1)" ); - return -3; - } - - pos += got; - } - return pos; - } - - protected boolean running=true; - - /** Accept incoming connections, dispatch to the thread pool - */ - void acceptConnections() { - if( log.isDebugEnabled() ) - log.debug("Accepting ajp connections on " + port); - while( running ) { - try{ - MsgContext ep=createMsgContext(); - ep.setSource(this); - ep.setWorkerEnv( wEnv ); - this.accept(ep); - - if( !running ) break; - - // Since this is a long-running connection, we don't care - // about the small GC - SocketConnection ajpConn= - new SocketConnection(this, ep); - tp.runIt( ajpConn ); - }catch(Exception ex) { - if (running) - log.warn("Exception executing accept" ,ex); - } - } - } - - /** Process a single ajp connection. - */ - void processConnection(MsgContext ep) { - try { - MsgAjp recv=new MsgAjp(); - while( running ) { - if(paused) { // Drop the connection on pause - break; - } - int status= this.receive( recv, ep ); - if( status <= 0 ) { - if( status==-3) - log.debug( "server has been restarted or reset this connection" ); - else - log.warn("Closing ajp connection " + status ); - break; - } - ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis()); - - ep.setType( 0 ); - // Will call next - status= this.invoke( recv, ep ); - if( status!= JkHandler.OK ) { - log.warn("processCallbacks status " + status ); - break; - } - } - } catch( Exception ex ) { - String msg = ex.getMessage(); - if( msg != null && msg.indexOf( "Connection reset" ) >= 0) - log.debug( "Server has been restarted or reset this connection"); - else if (msg != null && msg.indexOf( "Read timed out" ) >=0 ) - log.debug( "connection timeout reached"); - else - log.error( "Error, processing connection", ex); - } finally { - /* - * Whatever happened to this connection (remote closed it, timeout, read error) - * the socket SHOULD be closed, or we may be in situation where the webserver - * will continue to think the socket is still open and will forward request - * to tomcat without receiving ever a reply - */ - try { - this.close( ep ); - } - catch( Exception e) { - log.error( "Error, closing connection", e); - } - try{ - Request req = (Request)ep.getRequest(); - if( req != null ) { - ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); - if( roname != null ) { - Registry.getRegistry(null, null).unregisterComponent(roname); - } - req.getRequestProcessor().setGlobalProcessor(null); - } - } catch( Exception ee) { - log.error( "Error, releasing connection",ee); - } - } - } - - // XXX This should become handleNotification - public int invoke( Msg msg, MsgContext ep ) throws IOException { - int type=ep.getType(); - - switch( type ) { - case JkHandler.HANDLE_RECEIVE_PACKET: - if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? "); - return receive( msg, ep ); - case JkHandler.HANDLE_SEND_PACKET: - return send( msg, ep ); - case JkHandler.HANDLE_FLUSH: - return flush( msg, ep ); - } - - if( log.isDebugEnabled() ) - log.debug("Call next " + type + " " + next); - - // Send notification - if( nSupport!=null ) { - Notification notif=(Notification)ep.getNote(notifNote); - if( notif==null ) { - notif=new Notification("channelSocket.message", ep, requestCount ); - ep.setNote( notifNote, notif); - } - nSupport.sendNotification(notif); - } - - if( next != null ) { - return next.invoke( msg, ep ); - } else { - log.info("No next "); - } - - return OK; - } - - public boolean isSameAddress(MsgContext ep) { - Socket s=(Socket)ep.getNote( socketNote ); - return isSameAddress( s.getLocalAddress(), s.getInetAddress()); - } - - public String getChannelName() { - String encodedAddr = ""; - if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) { - encodedAddr = getAddress(); - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) + "-"; - } - return ("jk-" + encodedAddr + port); - } - - /** - * Return true if the specified client and server addresses - * are the same. This method works around a bug in the IBM 1.1.8 JVM on - * Linux, where the address bytes are returned reversed in some - * circumstances. - * - * @param server The server's InetAddress - * @param client The client's InetAddress - */ - public static boolean isSameAddress(InetAddress server, InetAddress client) - { - // Compare the byte array versions of the two addresses - byte serverAddr[] = server.getAddress(); - byte clientAddr[] = client.getAddress(); - if (serverAddr.length != clientAddr.length) - return (false); - boolean match = true; - for (int i = 0; i < serverAddr.length; i++) { - if (serverAddr[i] != clientAddr[i]) { - match = false; - break; - } - } - if (match) - return (true); - - // Compare the reversed form of the two addresses - for (int i = 0; i < serverAddr.length; i++) { - if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i]) - return (false); - } - return (true); - } - - public void sendNewMessageNotification(Notification notification) { - if( nSupport!= null ) - nSupport.sendNotification(notification); - } - - private NotificationBroadcasterSupport nSupport= null; - - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws IllegalArgumentException - { - if( nSupport==null ) nSupport=new NotificationBroadcasterSupport(); - nSupport.addNotificationListener(listener, filter, handback); - } - - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException - { - if( nSupport!=null) - nSupport.removeNotificationListener(listener); - } - - MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0]; - - public void setNotificationInfo( MBeanNotificationInfo info[]) { - this.notifInfo=info; - } - - public MBeanNotificationInfo[] getNotificationInfo() { - return notifInfo; - } - - static class SocketAcceptor implements ThreadPoolRunnable { - ChannelSocket wajp; - - SocketAcceptor(ChannelSocket wajp ) { - this.wajp=wajp; - } - - public Object[] getInitData() { - return null; - } - - public void runIt(Object thD[]) { - wajp.acceptConnections(); - } - } - - static class SocketConnection implements ThreadPoolRunnable { - ChannelSocket wajp; - MsgContext ep; - - SocketConnection(ChannelSocket wajp, MsgContext ep) { - this.wajp=wajp; - this.ep=ep; - } - - - public Object[] getInitData() { - return null; - } - - public void runIt(Object perTh[]) { - wajp.processConnection(ep); - ep = null; - } - } - -} - +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationBroadcasterSupport; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.JkChannel; +import org.apache.jk.core.WorkerEnv; +import org.apache.coyote.Request; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.threads.ThreadPool; +import org.apache.tomcat.util.threads.ThreadPoolRunnable; + +/** + * Accept ( and send ) TCP messages. + * + * @author Costin Manolache + * @author Bill Barker + * jmx:mbean name="jk:service=ChannelNioSocket" + * description="Accept socket connections" + * jmx:notification name="org.apache.coyote.INVOKE + * jmx:notification-handler name="org.apache.jk.JK_SEND_PACKET + * jmx:notification-handler name="org.apache.jk.JK_RECEIVE_PACKET + * jmx:notification-handler name="org.apache.jk.JK_FLUSH + * + * Jk can use multiple protocols/transports. + * Various container adapters should load this object ( as a bean ), + * set configurations and use it. Note that the connector will handle + * all incoming protocols - it's not specific to ajp1x. The protocol + * is abstracted by MsgContext/Message/Channel. + * + * A lot of the 'original' behavior is hardcoded - this uses Ajp13 wire protocol, + * TCP, Ajp14 API etc. + * As we add other protocols/transports/APIs this will change, the current goal + * is to get the same level of functionality as in the original jk connector. + * + * XXX Make the 'message type' pluggable + */ +public class ChannelSocket extends JkHandler + implements NotificationBroadcaster, JkChannel { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog( ChannelSocket.class ); + + private int startPort=8009; + private int maxPort=8019; // 0 for backward compat. + private int port=startPort; + private InetAddress inet; + private int serverTimeout; + private boolean tcpNoDelay=true; // nodelay to true by default + private int linger=100; + private int socketTimeout; + private int bufferSize = -1; + + private long requestCount=0; + + ThreadPool tp=ThreadPool.createThreadPool(true); + + /* ==================== Tcp socket options ==================== */ + + /** + * jmx:managed-constructor description="default constructor" + */ + public ChannelSocket() { + // This should be integrated with the domain setup + } + + public ThreadPool getThreadPool() { + return tp; + } + + public long getRequestCount() { + return requestCount; + } + + /** Set the port for the ajp13 channel. + * To support seemless load balancing and jni, we treat this + * as the 'base' port - we'll try up until we find one that is not + * used. We'll also provide the 'difference' to the main coyote + * handler - that will be our 'sessionID' and the position in + * the scoreboard and the suffix for the unix domain socket. + * + * jmx:managed-attribute description="Port to listen" access="READ_WRITE" + */ + public void setPort( int port ) { + this.startPort=port; + this.port=port; + this.maxPort=port+10; + } + + public int getPort() { + return port; + } + + public void setAddress(InetAddress inet) { + this.inet=inet; + } + + /** + * jmx:managed-attribute description="Bind on a specified address" access="READ_WRITE" + */ + public void setAddress(String inet) { + try { + this.inet= InetAddress.getByName( inet ); + } catch( Exception ex ) { + log.error("Error parsing "+inet,ex); + } + } + + public String getAddress() { + if( inet!=null) + return inet.toString(); + return "/0.0.0.0"; + } + + /** + * Sets the timeout in ms of the server sockets created by this + * server. This method allows the developer to make servers + * more or less responsive to having their server sockets + * shut down. + * + *

        By default this value is 1000ms. + */ + public void setServerTimeout(int timeout) { + this.serverTimeout = timeout; + } + public int getServerTimeout() { + return serverTimeout; + } + + public void setTcpNoDelay( boolean b ) { + tcpNoDelay=b; + } + + public boolean getTcpNoDelay() { + return tcpNoDelay; + } + + public void setSoLinger( int i ) { + linger=i; + } + + public int getSoLinger() { + return linger; + } + + public void setSoTimeout( int i ) { + socketTimeout=i; + } + + public int getSoTimeout() { + return socketTimeout; + } + + public void setMaxPort( int i ) { + maxPort=i; + } + + public int getMaxPort() { + return maxPort; + } + + public void setBufferSize(int bs) { + bufferSize = bs; + } + + public int getBufferSize() { + return bufferSize; + } + + /** At startup we'll look for the first free port in the range. + The difference between this port and the beggining of the range + is the 'id'. + This is usefull for lb cases ( less config ). + */ + public int getInstanceId() { + return port-startPort; + } + + /** If set to false, the thread pool will be created in + * non-daemon mode, and will prevent main from exiting + */ + public void setDaemon( boolean b ) { + tp.setDaemon( b ); + } + + public boolean getDaemon() { + return tp.getDaemon(); + } + + + public void setMaxThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting maxThreads " + i); + tp.setMaxThreads(i); + } + + public void setMinSpareThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting minSpareThreads " + i); + tp.setMinSpareThreads(i); + } + + public void setMaxSpareThreads( int i ) { + if( log.isDebugEnabled()) log.debug("Setting maxSpareThreads " + i); + tp.setMaxSpareThreads(i); + } + + public int getMaxThreads() { + return tp.getMaxThreads(); + } + + public int getMinSpareThreads() { + return tp.getMinSpareThreads(); + } + + public int getMaxSpareThreads() { + return tp.getMaxSpareThreads(); + } + + public void setBacklog(int i) { + } + + + /* ==================== ==================== */ + ServerSocket sSocket; + final int socketNote=1; + final int isNote=2; + final int osNote=3; + final int notifNote=4; + boolean paused = false; + + public void pause() throws Exception { + synchronized(this) { + paused = true; + unLockSocket(); + } + } + + public void resume() throws Exception { + synchronized(this) { + paused = false; + notify(); + } + } + + + public void accept( MsgContext ep ) throws IOException { + if( sSocket==null ) return; + synchronized(this) { + while(paused) { + try{ + wait(); + } catch(InterruptedException ie) { + //Ignore, since can't happen + } + } + } + Socket s=sSocket.accept(); + ep.setNote( socketNote, s ); + if(log.isDebugEnabled() ) + log.debug("Accepted socket " + s ); + + try { + setSocketOptions(s); + } catch(SocketException sex) { + log.debug("Error initializing Socket Options", sex); + } + + requestCount++; + + InputStream is=new BufferedInputStream(s.getInputStream()); + OutputStream os; + if( bufferSize > 0 ) + os = new BufferedOutputStream( s.getOutputStream(), bufferSize); + else + os = s.getOutputStream(); + ep.setNote( isNote, is ); + ep.setNote( osNote, os ); + ep.setControl( tp ); + } + + private void setSocketOptions(Socket s) throws SocketException { + if( socketTimeout > 0 ) + s.setSoTimeout( socketTimeout ); + + s.setTcpNoDelay( tcpNoDelay ); // set socket tcpnodelay state + + if( linger > 0 ) + s.setSoLinger( true, linger); + } + + public void resetCounters() { + requestCount=0; + } + + /** Called after you change some fields at runtime using jmx. + Experimental for now. + */ + public void reinit() throws IOException { + destroy(); + init(); + } + + /** + * jmx:managed-operation + */ + public void init() throws IOException { + // Find a port. + if (startPort == 0) { + port = 0; + if(log.isInfoEnabled()) + log.info("JK: ajp13 disabling channelSocket"); + running = true; + return; + } + if (maxPort < startPort) + maxPort = startPort; + for( int i=startPort; i<=maxPort; i++ ) { + try { + if( inet == null ) { + sSocket = new ServerSocket( i, 0 ); + } else { + sSocket=new ServerSocket( i, 0, inet ); + } + port=i; + break; + } catch( IOException ex ) { + if(log.isInfoEnabled()) + log.info("Port busy " + i + " " + ex.toString()); + continue; + } + } + + if( sSocket==null ) { + log.error("Can't find free port " + startPort + " " + maxPort ); + return; + } + if(log.isInfoEnabled()) + log.info("JK: ajp13 listening on " + getAddress() + ":" + port ); + + // If this is not the base port and we are the 'main' channleSocket and + // SHM didn't already set the localId - we'll set the instance id + if( "channelSocket".equals( name ) && + port != startPort && + (wEnv.getLocalId()==0) ) { + wEnv.setLocalId( port - startPort ); + } + if( serverTimeout > 0 ) + sSocket.setSoTimeout( serverTimeout ); + + // XXX Reverse it -> this is a notification generator !! + if( next==null && wEnv!=null ) { + if( nextName!=null ) + setNext( wEnv.getHandler( nextName ) ); + if( next==null ) + next=wEnv.getHandler( "dispatch" ); + if( next==null ) + next=wEnv.getHandler( "request" ); + } + JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); + running = true; + + // Run a thread that will accept connections. + // XXX Try to find a thread first - not sure how... + if( this.domain != null ) { + try { + tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + + getChannelName()); + + Registry.getRegistry(null, null) + .registerComponent(tp, tpOName, null); + + rgOName = new ObjectName + (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); + Registry.getRegistry(null, null) + .registerComponent(global, rgOName, null); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + } + + tp.start(); + SocketAcceptor acceptAjp=new SocketAcceptor( this ); + tp.runIt( acceptAjp); + + } + + ObjectName tpOName; + ObjectName rgOName; + RequestGroupInfo global=new RequestGroupInfo(); + int JMXRequestNote; + + public void start() throws IOException{ + if( sSocket==null ) + init(); + } + + public void stop() throws IOException { + destroy(); + } + + public void registerRequest(Request req, MsgContext ep, int count) { + if(this.domain != null) { + try { + RequestInfo rp=req.getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName roname = new ObjectName + (getDomain() + ":type=RequestProcessor,worker="+ + getChannelName()+",name=JkRequest" +count); + ep.setNote(JMXRequestNote, roname); + + Registry.getRegistry(null, null).registerComponent( rp, roname, null); + } catch( Exception ex ) { + log.warn("Error registering request"); + } + } + } + + public void open(MsgContext ep) throws IOException { + } + + + public void close(MsgContext ep) throws IOException { + Socket s=(Socket)ep.getNote( socketNote ); + s.close(); + } + + private void unLockSocket() throws IOException { + // Need to create a connection to unlock the accept(); + Socket s; + InetAddress ladr = inet; + + if(port == 0) + return; + if (ladr == null || "0.0.0.0".equals(ladr.getHostAddress())) { + ladr = InetAddress.getLocalHost(); + } + s=new Socket(ladr, port ); + // setting soLinger to a small value will help shutdown the + // connection quicker + s.setSoLinger(true, 0); + + s.close(); + } + + public void destroy() throws IOException { + running = false; + try { + /* If we disabled the channel return */ + if (port == 0) + return; + tp.shutdown(); + + if(!paused) { + unLockSocket(); + } + + sSocket.close(); // XXX? + + if( tpOName != null ) { + Registry.getRegistry(null, null).unregisterComponent(tpOName); + } + if( rgOName != null ) { + Registry.getRegistry(null, null).unregisterComponent(rgOName); + } + } catch(Exception e) { + log.info("Error shutting down the channel " + port + " " + + e.toString()); + if( log.isDebugEnabled() ) log.debug("Trace", e); + } + } + + public int send( Msg msg, MsgContext ep) + throws IOException { + msg.end(); // Write the packet header + byte buf[]=msg.getBuffer(); + int len=msg.getLen(); + + if(log.isTraceEnabled() ) + log.trace("send() " + len + " " + buf[4] ); + + OutputStream os=(OutputStream)ep.getNote( osNote ); + os.write( buf, 0, len ); + return len; + } + + public int flush( Msg msg, MsgContext ep) + throws IOException { + if( bufferSize > 0 ) { + OutputStream os=(OutputStream)ep.getNote( osNote ); + os.flush(); + } + return 0; + } + + public int receive( Msg msg, MsgContext ep ) + throws IOException { + if (log.isDebugEnabled()) { + log.debug("receive() "); + } + + byte buf[]=msg.getBuffer(); + int hlen=msg.getHeaderLength(); + + // XXX If the length in the packet header doesn't agree with the + // actual number of bytes read, it should probably return an error + // value. Also, callers of this method never use the length + // returned -- should probably return true/false instead. + + int rd = this.read(ep, buf, 0, hlen ); + + if(rd < 0) { + // Most likely normal apache restart. + // log.warn("Wrong message " + rd ); + return rd; + } + + msg.processHeader(); + + /* After processing the header we know the body + length + */ + int blen=msg.getLen(); + + // XXX check if enough space - it's assert()-ed !!! + + int total_read = 0; + + total_read = this.read(ep, buf, hlen, blen); + + if ((total_read <= 0) && (blen > 0)) { + log.warn("can't read body, waited #" + blen); + return -1; + } + + if (total_read != blen) { + log.warn( "incomplete read, waited #" + blen + + " got only " + total_read); + return -2; + } + + return total_read; + } + + /** + * Read N bytes from the InputStream, and ensure we got them all + * Under heavy load we could experience many fragmented packets + * just read Unix Network Programming to recall that a call to + * read didn't ensure you got all the data you want + * + * from read() Linux manual + * + * On success, the number of bytes read is returned (zero indicates end + * of file),and the file position is advanced by this number. + * It is not an error if this number is smaller than the number of bytes + * requested; this may happen for example because fewer bytes + * are actually available right now (maybe because we were close to + * end-of-file, or because we are reading from a pipe, or from a + * terminal), or because read() was interrupted by a signal. + * On error, -1 is returned, and errno is set appropriately. In this + * case it is left unspecified whether the file position (if any) changes. + * + **/ + public int read( MsgContext ep, byte[] b, int offset, int len) + throws IOException { + InputStream is=(InputStream)ep.getNote( isNote ); + int pos = 0; + int got; + + while(pos < len) { + try { + got = is.read(b, pos + offset, len - pos); + } catch(SocketException sex) { + if(pos > 0) { + log.info("Error reading data after "+pos+"bytes",sex); + } else { + log.debug("Error reading data", sex); + } + got = -1; + } + if (log.isTraceEnabled()) { + log.trace("read() " + b + " " + (b==null ? 0: b.length) + " " + + offset + " " + len + " = " + got ); + } + + // connection just closed by remote. + if (got <= 0) { + // This happens periodically, as apache restarts + // periodically. + // It should be more gracefull ! - another feature for Ajp14 + // log.warn( "server has closed the current connection (-1)" ); + return -3; + } + + pos += got; + } + return pos; + } + + protected boolean running=true; + + /** Accept incoming connections, dispatch to the thread pool + */ + void acceptConnections() { + if( log.isDebugEnabled() ) + log.debug("Accepting ajp connections on " + port); + while( running ) { + try{ + MsgContext ep=createMsgContext(); + ep.setSource(this); + ep.setWorkerEnv( wEnv ); + this.accept(ep); + + if( !running ) break; + + // Since this is a long-running connection, we don't care + // about the small GC + SocketConnection ajpConn= + new SocketConnection(this, ep); + tp.runIt( ajpConn ); + }catch(Exception ex) { + if (running) + log.warn("Exception executing accept" ,ex); + } + } + } + + /** Process a single ajp connection. + */ + void processConnection(MsgContext ep) { + try { + MsgAjp recv=new MsgAjp(); + while( running ) { + if(paused) { // Drop the connection on pause + break; + } + int status= this.receive( recv, ep ); + if( status <= 0 ) { + if( status==-3) + log.debug( "server has been restarted or reset this connection" ); + else + log.warn("Closing ajp connection " + status ); + break; + } + ep.setLong( MsgContext.TIMER_RECEIVED, System.currentTimeMillis()); + + ep.setType( 0 ); + // Will call next + status= this.invoke( recv, ep ); + if( status!= JkHandler.OK ) { + log.warn("processCallbacks status " + status ); + break; + } + } + } catch( Exception ex ) { + String msg = ex.getMessage(); + if( msg != null && msg.indexOf( "Connection reset" ) >= 0) + log.debug( "Server has been restarted or reset this connection"); + else if (msg != null && msg.indexOf( "Read timed out" ) >=0 ) + log.debug( "connection timeout reached"); + else + log.error( "Error, processing connection", ex); + } finally { + /* + * Whatever happened to this connection (remote closed it, timeout, read error) + * the socket SHOULD be closed, or we may be in situation where the webserver + * will continue to think the socket is still open and will forward request + * to tomcat without receiving ever a reply + */ + try { + this.close( ep ); + } + catch( Exception e) { + log.error( "Error, closing connection", e); + } + try{ + Request req = (Request)ep.getRequest(); + if( req != null ) { + ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); + if( roname != null ) { + Registry.getRegistry(null, null).unregisterComponent(roname); + } + req.getRequestProcessor().setGlobalProcessor(null); + } + } catch( Exception ee) { + log.error( "Error, releasing connection",ee); + } + } + } + + // XXX This should become handleNotification + public int invoke( Msg msg, MsgContext ep ) throws IOException { + int type=ep.getType(); + + switch( type ) { + case JkHandler.HANDLE_RECEIVE_PACKET: + if( log.isDebugEnabled()) log.debug("RECEIVE_PACKET ?? "); + return receive( msg, ep ); + case JkHandler.HANDLE_SEND_PACKET: + return send( msg, ep ); + case JkHandler.HANDLE_FLUSH: + return flush( msg, ep ); + } + + if( log.isDebugEnabled() ) + log.debug("Call next " + type + " " + next); + + // Send notification + if( nSupport!=null ) { + Notification notif=(Notification)ep.getNote(notifNote); + if( notif==null ) { + notif=new Notification("channelSocket.message", ep, requestCount ); + ep.setNote( notifNote, notif); + } + nSupport.sendNotification(notif); + } + + if( next != null ) { + return next.invoke( msg, ep ); + } else { + log.info("No next "); + } + + return OK; + } + + public boolean isSameAddress(MsgContext ep) { + Socket s=(Socket)ep.getNote( socketNote ); + return isSameAddress( s.getLocalAddress(), s.getInetAddress()); + } + + public String getChannelName() { + String encodedAddr = ""; + if (inet != null && !"0.0.0.0".equals(inet.getHostAddress())) { + encodedAddr = getAddress(); + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) + "-"; + } + return ("jk-" + encodedAddr + port); + } + + /** + * Return true if the specified client and server addresses + * are the same. This method works around a bug in the IBM 1.1.8 JVM on + * Linux, where the address bytes are returned reversed in some + * circumstances. + * + * @param server The server's InetAddress + * @param client The client's InetAddress + */ + public static boolean isSameAddress(InetAddress server, InetAddress client) + { + // Compare the byte array versions of the two addresses + byte serverAddr[] = server.getAddress(); + byte clientAddr[] = client.getAddress(); + if (serverAddr.length != clientAddr.length) + return (false); + boolean match = true; + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[i]) { + match = false; + break; + } + } + if (match) + return (true); + + // Compare the reversed form of the two addresses + for (int i = 0; i < serverAddr.length; i++) { + if (serverAddr[i] != clientAddr[(serverAddr.length-1)-i]) + return (false); + } + return (true); + } + + public void sendNewMessageNotification(Notification notification) { + if( nSupport!= null ) + nSupport.sendNotification(notification); + } + + private NotificationBroadcasterSupport nSupport= null; + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IllegalArgumentException + { + if( nSupport==null ) nSupport=new NotificationBroadcasterSupport(); + nSupport.addNotificationListener(listener, filter, handback); + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + if( nSupport!=null) + nSupport.removeNotificationListener(listener); + } + + MBeanNotificationInfo notifInfo[]=new MBeanNotificationInfo[0]; + + public void setNotificationInfo( MBeanNotificationInfo info[]) { + this.notifInfo=info; + } + + public MBeanNotificationInfo[] getNotificationInfo() { + return notifInfo; + } + + static class SocketAcceptor implements ThreadPoolRunnable { + ChannelSocket wajp; + + SocketAcceptor(ChannelSocket wajp ) { + this.wajp=wajp; + } + + public Object[] getInitData() { + return null; + } + + public void runIt(Object thD[]) { + wajp.acceptConnections(); + } + } + + static class SocketConnection implements ThreadPoolRunnable { + ChannelSocket wajp; + MsgContext ep; + + SocketConnection(ChannelSocket wajp, MsgContext ep) { + this.wajp=wajp; + this.ep=ep; + } + + + public Object[] getInitData() { + return null; + } + + public void runIt(Object perTh[]) { + wajp.processConnection(ep); + ep = null; + } + } + +} + diff --git a/java/org/apache/jk/common/ChannelUn.java b/java/org/apache/jk/common/ChannelUn.java index 1253db91d..3248f8437 100644 --- a/java/org/apache/jk/common/ChannelUn.java +++ b/java/org/apache/jk/common/ChannelUn.java @@ -1,394 +1,394 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.net.URLEncoder; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import javax.management.ObjectName; - -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.JkChannel; -import org.apache.jk.core.WorkerEnv; -import org.apache.coyote.Request; -import org.apache.coyote.RequestGroupInfo; -import org.apache.coyote.RequestInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.threads.ThreadPool; -import org.apache.tomcat.util.threads.ThreadPoolRunnable; - - -/** Pass messages using unix domain sockets. - * - * @author Costin Manolache - */ -public class ChannelUn extends JniHandler implements JkChannel { - static final int CH_OPEN=4; - static final int CH_CLOSE=5; - static final int CH_READ=6; - static final int CH_WRITE=7; - - String file; - ThreadPool tp = ThreadPool.createThreadPool(true); - - /* ==================== Tcp socket options ==================== */ - - public ThreadPool getThreadPool() { - return tp; - } - - public void setFile( String f ) { - file=f; - } - - public String getFile() { - return file; - } - - /* ==================== ==================== */ - int socketNote=1; - int isNote=2; - int osNote=3; - - int localId=0; - - public void init() throws IOException { - if( file==null ) { - log.debug("No file, disabling unix channel"); - return; - //throw new IOException( "No file for the unix socket channel"); - } - if( wEnv!=null && wEnv.getLocalId() != 0 ) { - localId=wEnv.getLocalId(); - } - - if( localId != 0 ) { - file=file+ localId; - } - File socketFile=new File( file ); - if( !socketFile.isAbsolute() ) { - String home=wEnv.getJkHome(); - if( home==null ) { - log.debug("No jkhome"); - } else { - File homef=new File( home ); - socketFile=new File( homef, file ); - log.debug( "Making the file absolute " +socketFile); - } - } - - if( ! socketFile.exists() ) { - try { - FileOutputStream fos=new FileOutputStream(socketFile); - fos.write( 1 ); - fos.close(); - } catch( Throwable t ) { - log.error("Attempting to create the file failed, disabling channel" - + socketFile); - return; - } - } - // The socket file cannot be removed ... - if (!socketFile.delete()) { - log.error( "Can't remove socket file " + socketFile); - return; - } - - - super.initNative( "channel.un:" + file ); - - if( apr==null || ! apr.isLoaded() ) { - log.debug("Apr is not available, disabling unix channel "); - apr=null; - return; - } - - // Set properties and call init. - setNativeAttribute( "file", file ); - // unixListenSocket=apr.unSocketListen( file, 10 ); - - setNativeAttribute( "listen", "10" ); - // setNativeAttribute( "debug", "10" ); - - // Initialize the thread pool and execution chain - if( next==null && wEnv!=null ) { - if( nextName!=null ) - setNext( wEnv.getHandler( nextName ) ); - if( next==null ) - next=wEnv.getHandler( "dispatch" ); - if( next==null ) - next=wEnv.getHandler( "request" ); - } - - super.initJkComponent(); - JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); - // Run a thread that will accept connections. - if( this.domain != null ) { - try { - tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + - getChannelName()); - - Registry.getRegistry(null, null) - .registerComponent(tp, tpOName, null); - - rgOName = new ObjectName - (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); - Registry.getRegistry(null, null) - .registerComponent(global, rgOName, null); - } catch (Exception e) { - log.error("Can't register threadpool" ); - } - } - tp.start(); - AprAcceptor acceptAjp=new AprAcceptor( this ); - tp.runIt( acceptAjp); - log.info("JK: listening on unix socket: " + file ); - - } - - ObjectName tpOName; - ObjectName rgOName; - RequestGroupInfo global=new RequestGroupInfo(); - int count = 0; - int JMXRequestNote; - - public void start() throws IOException { - } - - public void destroy() throws IOException { - if( apr==null ) return; - try { - if( tp != null ) - tp.shutdown(); - - //apr.unSocketClose( unixListenSocket,3); - super.destroyJkComponent(); - - if(tpOName != null) { - Registry.getRegistry(null, null).unregisterComponent(tpOName); - } - if(rgOName != null) { - Registry.getRegistry(null, null).unregisterComponent(rgOName); - } - } catch(Exception e) { - log.error("Error in destroy",e); - } - } - - public void registerRequest(Request req, MsgContext ep, int count) { - if(this.domain != null) { - try { - - RequestInfo rp=req.getRequestProcessor(); - rp.setGlobalProcessor(global); - ObjectName roname = new ObjectName - (getDomain() + ":type=RequestProcessor,worker="+ - getChannelName()+",name=JkRequest" +count); - ep.setNote(JMXRequestNote, roname); - - Registry.getRegistry(null, null).registerComponent( rp, roname, null); - } catch( Exception ex ) { - log.warn("Error registering request"); - } - } - } - - - /** Open a connection - since we're listening that will block in - accept - */ - public int open(MsgContext ep) throws IOException { - // Will associate a jk_endpoint with ep and call open() on it. - // jk_channel_un will accept a connection and set the socket info - // in the endpoint. MsgContext will represent an active connection. - return super.nativeDispatch( ep.getMsg(0), ep, CH_OPEN, 1 ); - } - - public void close(MsgContext ep) throws IOException { - super.nativeDispatch( ep.getMsg(0), ep, CH_CLOSE, 1 ); - } - - public int send( Msg msg, MsgContext ep) - throws IOException - { - return super.nativeDispatch( msg, ep, CH_WRITE, 0 ); - } - - public int receive( Msg msg, MsgContext ep ) - throws IOException - { - int rc=super.nativeDispatch( msg, ep, CH_READ, 1 ); - - if( rc!=0 ) { - log.error("receive error: " + rc, new Throwable()); - return -1; - } - - msg.processHeader(); - - if (log.isDebugEnabled()) - log.debug("receive: total read = " + msg.getLen()); - - return msg.getLen(); - } - - public int flush( Msg msg, MsgContext ep) throws IOException { - return OK; - } - - public boolean isSameAddress( MsgContext ep ) { - return false; // Not supporting shutdown on this channel. - } - - boolean running=true; - - /** Accept incoming connections, dispatch to the thread pool - */ - void acceptConnections() { - if( apr==null ) return; - - if( log.isDebugEnabled() ) - log.debug("Accepting ajp connections on " + file); - - while( running ) { - try { - MsgContext ep=this.createMsgContext(); - - // blocking - opening a server connection. - int status=this.open(ep); - if( status != 0 && status != 2 ) { - log.error( "Error acceptin connection on " + file ); - break; - } - - // if( log.isDebugEnabled() ) - // log.debug("Accepted ajp connections "); - - AprConnection ajpConn= new AprConnection(this, ep); - tp.runIt( ajpConn ); - } catch( Exception ex ) { - ex.printStackTrace(); - } - } - } - - /** Process a single ajp connection. - */ - void processConnection(MsgContext ep) { - if( log.isDebugEnabled() ) - log.debug( "New ajp connection "); - try { - MsgAjp recv=new MsgAjp(); - while( running ) { - int res=this.receive( recv, ep ); - if( res<0 ) { - // EOS - break; - } - ep.setType(0); - log.debug( "Process msg "); - int status=next.invoke( recv, ep ); - } - if( log.isDebugEnabled() ) - log.debug( "Closing un channel"); - try{ - Request req = (Request)ep.getRequest(); - if( req != null ) { - ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); - if( roname != null ) { - Registry.getRegistry(null, null).unregisterComponent(roname); - } - req.getRequestProcessor().setGlobalProcessor(null); - } - } catch( Exception ee) { - log.error( "Error, releasing connection",ee); - } - this.close( ep ); - } catch( Exception ex ) { - ex.printStackTrace(); - } - } - - public int invoke( Msg msg, MsgContext ep ) throws IOException { - int type=ep.getType(); - - switch( type ) { - case JkHandler.HANDLE_RECEIVE_PACKET: - return receive( msg, ep ); - case JkHandler.HANDLE_SEND_PACKET: - return send( msg, ep ); - case JkHandler.HANDLE_FLUSH: - return flush( msg, ep ); - } - - // return next.invoke( msg, ep ); - return OK; - } - - public String getChannelName() { - String encodedAddr = ""; - String address = file; - if (address != null) { - encodedAddr = "" + address; - if (encodedAddr.startsWith("/")) - encodedAddr = encodedAddr.substring(1); - encodedAddr = URLEncoder.encode(encodedAddr) ; - } - return ("jk-" + encodedAddr); - } - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( ChannelUn.class ); -} - -class AprAcceptor implements ThreadPoolRunnable { - ChannelUn wajp; - - AprAcceptor(ChannelUn wajp ) { - this.wajp=wajp; - } - - public Object[] getInitData() { - return null; - } - - public void runIt(Object thD[]) { - wajp.acceptConnections(); - } -} - -class AprConnection implements ThreadPoolRunnable { - ChannelUn wajp; - MsgContext ep; - - AprConnection(ChannelUn wajp, MsgContext ep) { - this.wajp=wajp; - this.ep=ep; - } - - - public Object[] getInitData() { - return null; - } - - public void runIt(Object perTh[]) { - wajp.processConnection(ep); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.net.URLEncoder; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import javax.management.ObjectName; + +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.JkChannel; +import org.apache.jk.core.WorkerEnv; +import org.apache.coyote.Request; +import org.apache.coyote.RequestGroupInfo; +import org.apache.coyote.RequestInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.threads.ThreadPool; +import org.apache.tomcat.util.threads.ThreadPoolRunnable; + + +/** Pass messages using unix domain sockets. + * + * @author Costin Manolache + */ +public class ChannelUn extends JniHandler implements JkChannel { + static final int CH_OPEN=4; + static final int CH_CLOSE=5; + static final int CH_READ=6; + static final int CH_WRITE=7; + + String file; + ThreadPool tp = ThreadPool.createThreadPool(true); + + /* ==================== Tcp socket options ==================== */ + + public ThreadPool getThreadPool() { + return tp; + } + + public void setFile( String f ) { + file=f; + } + + public String getFile() { + return file; + } + + /* ==================== ==================== */ + int socketNote=1; + int isNote=2; + int osNote=3; + + int localId=0; + + public void init() throws IOException { + if( file==null ) { + log.debug("No file, disabling unix channel"); + return; + //throw new IOException( "No file for the unix socket channel"); + } + if( wEnv!=null && wEnv.getLocalId() != 0 ) { + localId=wEnv.getLocalId(); + } + + if( localId != 0 ) { + file=file+ localId; + } + File socketFile=new File( file ); + if( !socketFile.isAbsolute() ) { + String home=wEnv.getJkHome(); + if( home==null ) { + log.debug("No jkhome"); + } else { + File homef=new File( home ); + socketFile=new File( homef, file ); + log.debug( "Making the file absolute " +socketFile); + } + } + + if( ! socketFile.exists() ) { + try { + FileOutputStream fos=new FileOutputStream(socketFile); + fos.write( 1 ); + fos.close(); + } catch( Throwable t ) { + log.error("Attempting to create the file failed, disabling channel" + + socketFile); + return; + } + } + // The socket file cannot be removed ... + if (!socketFile.delete()) { + log.error( "Can't remove socket file " + socketFile); + return; + } + + + super.initNative( "channel.un:" + file ); + + if( apr==null || ! apr.isLoaded() ) { + log.debug("Apr is not available, disabling unix channel "); + apr=null; + return; + } + + // Set properties and call init. + setNativeAttribute( "file", file ); + // unixListenSocket=apr.unSocketListen( file, 10 ); + + setNativeAttribute( "listen", "10" ); + // setNativeAttribute( "debug", "10" ); + + // Initialize the thread pool and execution chain + if( next==null && wEnv!=null ) { + if( nextName!=null ) + setNext( wEnv.getHandler( nextName ) ); + if( next==null ) + next=wEnv.getHandler( "dispatch" ); + if( next==null ) + next=wEnv.getHandler( "request" ); + } + + super.initJkComponent(); + JMXRequestNote =wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "requestNote"); + // Run a thread that will accept connections. + if( this.domain != null ) { + try { + tpOName=new ObjectName(domain + ":type=ThreadPool,name=" + + getChannelName()); + + Registry.getRegistry(null, null) + .registerComponent(tp, tpOName, null); + + rgOName = new ObjectName + (domain+":type=GlobalRequestProcessor,name=" + getChannelName()); + Registry.getRegistry(null, null) + .registerComponent(global, rgOName, null); + } catch (Exception e) { + log.error("Can't register threadpool" ); + } + } + tp.start(); + AprAcceptor acceptAjp=new AprAcceptor( this ); + tp.runIt( acceptAjp); + log.info("JK: listening on unix socket: " + file ); + + } + + ObjectName tpOName; + ObjectName rgOName; + RequestGroupInfo global=new RequestGroupInfo(); + int count = 0; + int JMXRequestNote; + + public void start() throws IOException { + } + + public void destroy() throws IOException { + if( apr==null ) return; + try { + if( tp != null ) + tp.shutdown(); + + //apr.unSocketClose( unixListenSocket,3); + super.destroyJkComponent(); + + if(tpOName != null) { + Registry.getRegistry(null, null).unregisterComponent(tpOName); + } + if(rgOName != null) { + Registry.getRegistry(null, null).unregisterComponent(rgOName); + } + } catch(Exception e) { + log.error("Error in destroy",e); + } + } + + public void registerRequest(Request req, MsgContext ep, int count) { + if(this.domain != null) { + try { + + RequestInfo rp=req.getRequestProcessor(); + rp.setGlobalProcessor(global); + ObjectName roname = new ObjectName + (getDomain() + ":type=RequestProcessor,worker="+ + getChannelName()+",name=JkRequest" +count); + ep.setNote(JMXRequestNote, roname); + + Registry.getRegistry(null, null).registerComponent( rp, roname, null); + } catch( Exception ex ) { + log.warn("Error registering request"); + } + } + } + + + /** Open a connection - since we're listening that will block in + accept + */ + public int open(MsgContext ep) throws IOException { + // Will associate a jk_endpoint with ep and call open() on it. + // jk_channel_un will accept a connection and set the socket info + // in the endpoint. MsgContext will represent an active connection. + return super.nativeDispatch( ep.getMsg(0), ep, CH_OPEN, 1 ); + } + + public void close(MsgContext ep) throws IOException { + super.nativeDispatch( ep.getMsg(0), ep, CH_CLOSE, 1 ); + } + + public int send( Msg msg, MsgContext ep) + throws IOException + { + return super.nativeDispatch( msg, ep, CH_WRITE, 0 ); + } + + public int receive( Msg msg, MsgContext ep ) + throws IOException + { + int rc=super.nativeDispatch( msg, ep, CH_READ, 1 ); + + if( rc!=0 ) { + log.error("receive error: " + rc, new Throwable()); + return -1; + } + + msg.processHeader(); + + if (log.isDebugEnabled()) + log.debug("receive: total read = " + msg.getLen()); + + return msg.getLen(); + } + + public int flush( Msg msg, MsgContext ep) throws IOException { + return OK; + } + + public boolean isSameAddress( MsgContext ep ) { + return false; // Not supporting shutdown on this channel. + } + + boolean running=true; + + /** Accept incoming connections, dispatch to the thread pool + */ + void acceptConnections() { + if( apr==null ) return; + + if( log.isDebugEnabled() ) + log.debug("Accepting ajp connections on " + file); + + while( running ) { + try { + MsgContext ep=this.createMsgContext(); + + // blocking - opening a server connection. + int status=this.open(ep); + if( status != 0 && status != 2 ) { + log.error( "Error acceptin connection on " + file ); + break; + } + + // if( log.isDebugEnabled() ) + // log.debug("Accepted ajp connections "); + + AprConnection ajpConn= new AprConnection(this, ep); + tp.runIt( ajpConn ); + } catch( Exception ex ) { + ex.printStackTrace(); + } + } + } + + /** Process a single ajp connection. + */ + void processConnection(MsgContext ep) { + if( log.isDebugEnabled() ) + log.debug( "New ajp connection "); + try { + MsgAjp recv=new MsgAjp(); + while( running ) { + int res=this.receive( recv, ep ); + if( res<0 ) { + // EOS + break; + } + ep.setType(0); + log.debug( "Process msg "); + int status=next.invoke( recv, ep ); + } + if( log.isDebugEnabled() ) + log.debug( "Closing un channel"); + try{ + Request req = (Request)ep.getRequest(); + if( req != null ) { + ObjectName roname = (ObjectName)ep.getNote(JMXRequestNote); + if( roname != null ) { + Registry.getRegistry(null, null).unregisterComponent(roname); + } + req.getRequestProcessor().setGlobalProcessor(null); + } + } catch( Exception ee) { + log.error( "Error, releasing connection",ee); + } + this.close( ep ); + } catch( Exception ex ) { + ex.printStackTrace(); + } + } + + public int invoke( Msg msg, MsgContext ep ) throws IOException { + int type=ep.getType(); + + switch( type ) { + case JkHandler.HANDLE_RECEIVE_PACKET: + return receive( msg, ep ); + case JkHandler.HANDLE_SEND_PACKET: + return send( msg, ep ); + case JkHandler.HANDLE_FLUSH: + return flush( msg, ep ); + } + + // return next.invoke( msg, ep ); + return OK; + } + + public String getChannelName() { + String encodedAddr = ""; + String address = file; + if (address != null) { + encodedAddr = "" + address; + if (encodedAddr.startsWith("/")) + encodedAddr = encodedAddr.substring(1); + encodedAddr = URLEncoder.encode(encodedAddr) ; + } + return ("jk-" + encodedAddr); + } + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( ChannelUn.class ); +} + +class AprAcceptor implements ThreadPoolRunnable { + ChannelUn wajp; + + AprAcceptor(ChannelUn wajp ) { + this.wajp=wajp; + } + + public Object[] getInitData() { + return null; + } + + public void runIt(Object thD[]) { + wajp.acceptConnections(); + } +} + +class AprConnection implements ThreadPoolRunnable { + ChannelUn wajp; + MsgContext ep; + + AprConnection(ChannelUn wajp, MsgContext ep) { + this.wajp=wajp; + this.ep=ep; + } + + + public Object[] getInitData() { + return null; + } + + public void runIt(Object perTh[]) { + wajp.processConnection(ep); + } +} diff --git a/java/org/apache/jk/common/HandlerDispatch.java b/java/org/apache/jk/common/HandlerDispatch.java index fbd3d42c7..d40b14c15 100644 --- a/java/org/apache/jk/common/HandlerDispatch.java +++ b/java/org/apache/jk/common/HandlerDispatch.java @@ -1,100 +1,100 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.IOException; - -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; - - - - -/** - * Dispatch based on the message type. ( XXX make it more generic, - * now it's specific to ajp13 ). - * - * @author Costin Manolache - */ -public class HandlerDispatch extends JkHandler -{ - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( HandlerDispatch.class ); - - public HandlerDispatch() - { - } - - public void init() { - } - - JkHandler handlers[]=new JkHandler[MAX_HANDLERS]; - String handlerNames[]=new String[MAX_HANDLERS]; - - static final int MAX_HANDLERS=32; - static final int RESERVED=16; // reserved names, backward compat - int currentId=RESERVED; - - public int registerMessageType( int id, String name, JkHandler h, - String sig[] ) - { - if( log.isDebugEnabled() ) - log.debug( "Register message " + id + " " + h.getName() + - " " + h.getClass().getName()); - if( id < 0 ) { - // try to find it by name - for( int i=0; i< handlerNames.length; i++ ) { - if( handlerNames[i]==null ) continue; - if( name.equals( handlerNames[i] ) ) - return i; - } - handlers[currentId]=h; - handlerNames[currentId]=name; - currentId++; - return currentId; - } - handlers[id]=h; - handlerNames[currentId]=name; - return id; - } - - - // -------------------- Incoming message -------------------- - - public int invoke(Msg msg, MsgContext ep ) - throws IOException - { - int type=msg.peekByte(); - ep.setType( type ); - - if( type > handlers.length || - handlers[type]==null ) { - if( log.isDebugEnabled() ) - log.debug( "Invalid handler " + type ); - return ERROR; - } - - if( log.isDebugEnabled() ) - log.debug( "Received " + type + " " + handlers[type].getName()); - - JkHandler handler=handlers[type]; - - return handler.invoke( msg, ep ); - } - - } +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.io.IOException; + +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; + + + + +/** + * Dispatch based on the message type. ( XXX make it more generic, + * now it's specific to ajp13 ). + * + * @author Costin Manolache + */ +public class HandlerDispatch extends JkHandler +{ + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( HandlerDispatch.class ); + + public HandlerDispatch() + { + } + + public void init() { + } + + JkHandler handlers[]=new JkHandler[MAX_HANDLERS]; + String handlerNames[]=new String[MAX_HANDLERS]; + + static final int MAX_HANDLERS=32; + static final int RESERVED=16; // reserved names, backward compat + int currentId=RESERVED; + + public int registerMessageType( int id, String name, JkHandler h, + String sig[] ) + { + if( log.isDebugEnabled() ) + log.debug( "Register message " + id + " " + h.getName() + + " " + h.getClass().getName()); + if( id < 0 ) { + // try to find it by name + for( int i=0; i< handlerNames.length; i++ ) { + if( handlerNames[i]==null ) continue; + if( name.equals( handlerNames[i] ) ) + return i; + } + handlers[currentId]=h; + handlerNames[currentId]=name; + currentId++; + return currentId; + } + handlers[id]=h; + handlerNames[currentId]=name; + return id; + } + + + // -------------------- Incoming message -------------------- + + public int invoke(Msg msg, MsgContext ep ) + throws IOException + { + int type=msg.peekByte(); + ep.setType( type ); + + if( type > handlers.length || + handlers[type]==null ) { + if( log.isDebugEnabled() ) + log.debug( "Invalid handler " + type ); + return ERROR; + } + + if( log.isDebugEnabled() ) + log.debug( "Received " + type + " " + handlers[type].getName()); + + JkHandler handler=handlers[type]; + + return handler.invoke( msg, ep ); + } + + } diff --git a/java/org/apache/jk/common/HandlerRequest.java b/java/org/apache/jk/common/HandlerRequest.java index be7e0afbd..482a868c0 100644 --- a/java/org/apache/jk/common/HandlerRequest.java +++ b/java/org/apache/jk/common/HandlerRequest.java @@ -1,666 +1,666 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.CharConversionException; -import java.net.InetAddress; -import java.util.Properties; - -import org.apache.coyote.Request; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Response; -import org.apache.coyote.Constants; -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.WorkerEnv; -import org.apache.jk.core.JkChannel; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.HexUtils; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.threads.ThreadWithAttributes; - -/** - * Handle messages related with basic request information. - * - * This object can handle the following incoming messages: - * - "FORWARD_REQUEST" input message ( sent when a request is passed from the - * web server ) - * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in - * response to GET_BODY_CHUNK ) - * - * It can handle the following outgoing messages: - * - SEND_HEADERS. Pass the status code and headers. - * - SEND_BODY_CHUNK. Send a chunk of body - * - GET_BODY_CHUNK. Request a chunk of body data - * - END_RESPONSE. Notify the end of a request processing. - * - * @author Henri Gomez [hgomez@apache.org] - * @author Dan Milstein [danmil@shore.net] - * @author Keith Wannamaker [Keith@Wannamaker.org] - * @author Costin Manolache - */ -public class HandlerRequest extends JkHandler -{ - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( HandlerRequest.class ); - - /* - * Note for Host parsing. - */ - public static final int HOSTBUFFER = 10; - - /** - * Thread lock. - */ - private static Object lock = new Object(); - - private HandlerDispatch dispatch; - private String ajpidDir="conf"; - - - public HandlerRequest() { - } - - public void init() { - dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" ); - if( dispatch != null ) { - // register incoming message handlers - dispatch.registerMessageType( AjpConstants.JK_AJP13_FORWARD_REQUEST, - "JK_AJP13_FORWARD_REQUEST", - this, null); // 2 - - dispatch.registerMessageType( AjpConstants.JK_AJP13_SHUTDOWN, - "JK_AJP13_SHUTDOWN", - this, null); // 7 - - dispatch.registerMessageType( AjpConstants.JK_AJP13_CPING_REQUEST, - "JK_AJP13_CPING_REQUEST", - this, null); // 10 - dispatch.registerMessageType( HANDLE_THREAD_END, - "HANDLE_THREAD_END", - this, null); - // register outgoing messages handler - dispatch.registerMessageType( AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3 - "JK_AJP13_SEND_BODY_CHUNK", - this,null ); - } - - tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" ); - secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" ); - - if( next==null ) - next=wEnv.getHandler( "container" ); - if( log.isDebugEnabled() ) - log.debug( "Container handler " + next + " " + next.getName() + - " " + next.getClass().getName()); - - // should happen on start() - generateAjp13Id(); - } - - public void setSecret( String s ) { - requiredSecret=s; - } - - public void setUseSecret( boolean b ) { - if(b) { - requiredSecret=Double.toString(Math.random()); - } - } - - public void setDecodedUri( boolean b ) { - decoded=b; - } - - public boolean isTomcatAuthentication() { - return tomcatAuthentication; - } - - public void setShutdownEnabled(boolean se) { - shutdownEnabled = se; - } - - public boolean getShutdownEnabled() { - return shutdownEnabled; - } - - public void setTomcatAuthentication(boolean newTomcatAuthentication) { - tomcatAuthentication = newTomcatAuthentication; - } - - public void setAjpidDir( String path ) { - if( "".equals( path ) ) path=null; - ajpidDir=path; - } - - /** - * Set the flag to tell if we JMX register requests. - */ - public void setRegisterRequests(boolean srr) { - registerRequests = srr; - } - - /** - * Get the flag to tell if we JMX register requests. - */ - public boolean getRegisterRequests() { - return registerRequests; - } - - /** - * Set the flag to delay the initial body read - */ - public void setDelayInitialRead(boolean dir) { - delayInitialRead = dir; - } - - /** - * Get the flag to tell if we delay the initial body read - */ - public boolean getDelayInitialRead() { - return delayInitialRead; - } - - // -------------------- Ajp13.id -------------------- - - private void generateAjp13Id() { - int portInt=8009; // tcpCon.getPort(); - InetAddress address=null; // tcpCon.getAddress(); - - if( requiredSecret == null || !shutdownEnabled ) - return; - - File f1=new File( wEnv.getJkHome() ); - File f2=new File( f1, "conf" ); - - if( ! f2.exists() ) { - log.error( "No conf dir for ajp13.id " + f2 ); - return; - } - - File sf=new File( f2, "ajp13.id"); - - if( log.isDebugEnabled()) - log.debug( "Using stop file: "+sf); - - try { - Properties props=new Properties(); - - props.put( "port", Integer.toString( portInt )); - if( address!=null ) { - props.put( "address", address.getHostAddress() ); - } - if( requiredSecret !=null ) { - props.put( "secret", requiredSecret ); - } - - FileOutputStream stopF=new FileOutputStream( sf ); - props.store( stopF, "Automatically generated, don't edit" ); - } catch( IOException ex ) { - if(log.isDebugEnabled()) - log.debug( "Can't create stop file: "+sf,ex ); - } - } - - // -------------------- Incoming message -------------------- - private String requiredSecret=null; - private int secretNote; - private int tmpBufNote; - - private boolean decoded=true; - private boolean tomcatAuthentication=true; - private boolean registerRequests=true; - private boolean shutdownEnabled=false; - private boolean delayInitialRead = true; - - public int invoke(Msg msg, MsgContext ep ) - throws IOException { - int type=msg.getByte(); - ThreadWithAttributes twa = null; - if (Thread.currentThread() instanceof ThreadWithAttributes) { - twa = (ThreadWithAttributes) Thread.currentThread(); - } - Object control=ep.getControl(); - MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote ); - if( tmpMB==null ) { - tmpMB= MessageBytes.newInstance(); - ep.setNote( tmpBufNote, tmpMB); - } - - if( log.isDebugEnabled() ) - log.debug( "Handling " + type ); - - switch( type ) { - case AjpConstants.JK_AJP13_FORWARD_REQUEST: - try { - if (twa != null) { - twa.setCurrentStage(control, "JkDecode"); - } - decodeRequest( msg, ep, tmpMB ); - if (twa != null) { - twa.setCurrentStage(control, "JkService"); - twa.setParam(control, - ((Request)ep.getRequest()).unparsedURI()); - } - } catch( Exception ex ) { - log.error( "Error decoding request ", ex ); - msg.dump( "Incomming message"); - return ERROR; - } - - if( requiredSecret != null ) { - String epSecret=(String)ep.getNote( secretNote ); - if( epSecret==null || ! requiredSecret.equals( epSecret ) ) - return ERROR; - } - /* XXX it should be computed from request, by workerEnv */ - if(log.isDebugEnabled() ) - log.debug("Calling next " + next.getName() + " " + - next.getClass().getName()); - - int err= next.invoke( msg, ep ); - if (twa != null) { - twa.setCurrentStage(control, "JkDone"); - } - - if( log.isDebugEnabled() ) - log.debug( "Invoke returned " + err ); - return err; - case AjpConstants.JK_AJP13_SHUTDOWN: - String epSecret=null; - if( msg.getLen() > 3 ) { - // we have a secret - msg.getBytes( tmpMB ); - epSecret=tmpMB.toString(); - } - - if( requiredSecret != null && - requiredSecret.equals( epSecret ) ) { - if( log.isDebugEnabled() ) - log.debug("Received wrong secret, no shutdown "); - return ERROR; - } - - // XXX add isSameAddress check - JkChannel ch=ep.getSource(); - if( !ch.isSameAddress(ep) ) { - log.error("Shutdown request not from 'same address' "); - return ERROR; - } - - if( !shutdownEnabled ) { - log.warn("Ignoring shutdown request: shutdown not enabled"); - return ERROR; - } - // forward to the default handler - it'll do the shutdown - checkRequest(ep); - next.invoke( msg, ep ); - - if(log.isInfoEnabled()) - log.info("Exiting"); - System.exit(0); - - return OK; - - // We got a PING REQUEST, quickly respond with a PONG - case AjpConstants.JK_AJP13_CPING_REQUEST: - msg.reset(); - msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY); - ep.getSource().send( msg, ep ); - ep.getSource().flush( msg, ep ); // Server needs to get it - return OK; - - case HANDLE_THREAD_END: - return OK; - - default: - if(log.isInfoEnabled()) - log.info("Unknown message " + type); - } - - return OK; - } - - static int count = 0; - - private Request checkRequest(MsgContext ep) { - Request req=ep.getRequest(); - if( req==null ) { - req=new Request(); - Response res=new Response(); - req.setResponse(res); - ep.setRequest( req ); - if( registerRequests ) { - synchronized(lock) { - ep.getSource().registerRequest(req, ep, count++); - } - } - } - return req; - } - - private int decodeRequest( Msg msg, MsgContext ep, MessageBytes tmpMB ) - throws IOException { - // FORWARD_REQUEST handler - Request req = checkRequest(ep); - - RequestInfo rp = req.getRequestProcessor(); - rp.setStage(Constants.STAGE_PARSE); - MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); - if(tmpMB2 != null) { - tmpMB2.recycle(); - } - req.setStartTime(System.currentTimeMillis()); - - // Translate the HTTP method code to a String. - byte methodCode = msg.getByte(); - if (methodCode != AjpConstants.SC_M_JK_STORED) { - String mName=AjpConstants.methodTransArray[(int)methodCode - 1]; - req.method().setString(mName); - } - - msg.getBytes(req.protocol()); - msg.getBytes(req.requestURI()); - - msg.getBytes(req.remoteAddr()); - msg.getBytes(req.remoteHost()); - msg.getBytes(req.localName()); - req.setLocalPort(msg.getInt()); - - boolean isSSL = msg.getByte() != 0; - if( isSSL ) { - // XXX req.setSecure( true ); - req.scheme().setString("https"); - } - - decodeHeaders( ep, msg, req, tmpMB ); - - decodeAttributes( ep, msg, req, tmpMB ); - - rp.setStage(Constants.STAGE_PREPARE); - MessageBytes valueMB = req.getMimeHeaders().getValue("host"); - parseHost(valueMB, req); - // set cookies on request now that we have all headers - req.getCookies().setHeaders(req.getMimeHeaders()); - - // Check to see if there should be a body packet coming along - // immediately after - int cl=req.getContentLength(); - if(cl > 0) { - JkInputStream jkIS = ep.getInputStream(); - jkIS.setIsReadRequired(true); - if(!delayInitialRead) { - jkIS.receive(); - } - } - - if (log.isTraceEnabled()) { - log.trace(req.toString()); - } - - return OK; - } - - private int decodeAttributes( MsgContext ep, Msg msg, Request req, - MessageBytes tmpMB) { - boolean moreAttr=true; - - while( moreAttr ) { - byte attributeCode=msg.getByte(); - if( attributeCode == AjpConstants.SC_A_ARE_DONE ) - return 200; - - /* Special case ( XXX in future API make it separate type !) - */ - if( attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE ) { - // Bug 1326: it's an Integer. - req.setAttribute(SSLSupport.KEY_SIZE_KEY, - new Integer( msg.getInt())); - //Integer.toString(msg.getInt())); - } - - if( attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE ) { - // 2 strings ???... - msg.getBytes( tmpMB ); - String n=tmpMB.toString(); - msg.getBytes( tmpMB ); - String v=tmpMB.toString(); - req.setAttribute(n, v ); - if(log.isTraceEnabled()) - log.trace("jk Attribute set " + n + "=" + v); - } - - - // 1 string attributes - switch(attributeCode) { - case AjpConstants.SC_A_CONTEXT : - msg.getBytes( tmpMB ); - // nothing - break; - - case AjpConstants.SC_A_SERVLET_PATH : - msg.getBytes( tmpMB ); - // nothing - break; - - case AjpConstants.SC_A_REMOTE_USER : - if( tomcatAuthentication ) { - // ignore server - msg.getBytes( tmpMB ); - } else { - msg.getBytes(req.getRemoteUser()); - } - break; - - case AjpConstants.SC_A_AUTH_TYPE : - if( tomcatAuthentication ) { - // ignore server - msg.getBytes( tmpMB ); - } else { - msg.getBytes(req.getAuthType()); - } - break; - - case AjpConstants.SC_A_QUERY_STRING : - msg.getBytes(req.queryString()); - break; - - case AjpConstants.SC_A_JVM_ROUTE : - msg.getBytes(req.instanceId()); - break; - - case AjpConstants.SC_A_SSL_CERT : - req.scheme().setString( "https" ); - // Transform the string into certificate. - MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); - if(tmpMB2 == null) { - tmpMB2 = MessageBytes.newInstance(); - req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2); - } - // SSL certificate extraction is costy, moved to JkCoyoteHandler - msg.getBytes(tmpMB2); - break; - - case AjpConstants.SC_A_SSL_CIPHER : - req.scheme().setString( "https" ); - msg.getBytes(tmpMB); - req.setAttribute(SSLSupport.CIPHER_SUITE_KEY, - tmpMB.toString()); - break; - - case AjpConstants.SC_A_SSL_SESSION : - req.scheme().setString( "https" ); - msg.getBytes(tmpMB); - req.setAttribute(SSLSupport.SESSION_ID_KEY, - tmpMB.toString()); - break; - - case AjpConstants.SC_A_SECRET : - msg.getBytes(tmpMB); - String secret=tmpMB.toString(); - if(log.isTraceEnabled()) - log.trace("Secret: " + secret ); - // endpoint note - ep.setNote( secretNote, secret ); - break; - - case AjpConstants.SC_A_STORED_METHOD: - msg.getBytes(req.method()); - break; - - default: - break; // ignore, we don't know about it - backward compat - } - } - return 200; - } - - private void decodeHeaders( MsgContext ep, Msg msg, Request req, - MessageBytes tmpMB ) { - // Decode headers - MimeHeaders headers = req.getMimeHeaders(); - - int hCount = msg.getInt(); - for(int i = 0 ; i < hCount ; i++) { - String hName = null; - - // Header names are encoded as either an integer code starting - // with 0xA0, or as a normal string (in which case the first - // two bytes are the length). - int isc = msg.peekInt(); - int hId = isc & 0xFF; - - MessageBytes vMB=null; - isc &= 0xFF00; - if(0xA000 == isc) { - msg.getInt(); // To advance the read position - hName = AjpConstants.headerTransArray[hId - 1]; - vMB=headers.addValue( hName ); - } else { - // reset hId -- if the header currently being read - // happens to be 7 or 8 bytes long, the code below - // will think it's the content-type header or the - // content-length header - SC_REQ_CONTENT_TYPE=7, - // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected - // behaviour. see bug 5861 for more information. - hId = -1; - msg.getBytes( tmpMB ); - ByteChunk bc=tmpMB.getByteChunk(); - vMB=headers.addValue( bc.getBuffer(), - bc.getStart(), bc.getLength() ); - } - - msg.getBytes(vMB); - - if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { - // just read the content-length header, so set it - req.setContentLength( vMB.getInt() ); - } else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { - // just read the content-type header, so set it - ByteChunk bchunk = vMB.getByteChunk(); - req.contentType().setBytes(bchunk.getBytes(), - bchunk.getOffset(), - bchunk.getLength()); - } - } - } - - /** - * Parse host. - */ - private void parseHost(MessageBytes valueMB, Request request) - throws IOException { - - if (valueMB == null || valueMB.isNull()) { - // HTTP/1.0 - // Default is what the socket tells us. Overriden if a host is - // found/parsed - request.setServerPort(request.getLocalPort()); - request.serverName().duplicate(request.localName()); - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - CharChunk hostNameC = (CharChunk)request.getNote(HOSTBUFFER); - if(hostNameC == null) { - hostNameC = new CharChunk(valueL); - request.setNote(HOSTBUFFER, hostNameC); - } - hostNameC.recycle(); - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC.append(b); - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (request.scheme().equalsIgnoreCase("https")) { - // 80 - Default HTTTP port - request.setServerPort(443); - } else { - // 443 - Default HTTPS port - request.setServerPort(80); - } - request.serverName().setChars(hostNameC.getChars(), - hostNameC.getStart(), - hostNameC.getLength()); - } else { - - request.serverName().setChars(hostNameC.getChars(), - hostNameC.getStart(), colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; - if (charValue == -1) { - // Invalid character - throw new CharConversionException("Invalid char in port: " + valueB[i + valueS]); - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - - } - - } - -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.CharConversionException; +import java.net.InetAddress; +import java.util.Properties; + +import org.apache.coyote.Request; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Response; +import org.apache.coyote.Constants; +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.WorkerEnv; +import org.apache.jk.core.JkChannel; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.threads.ThreadWithAttributes; + +/** + * Handle messages related with basic request information. + * + * This object can handle the following incoming messages: + * - "FORWARD_REQUEST" input message ( sent when a request is passed from the + * web server ) + * - "RECEIVE_BODY_CHUNK" input ( sent by container to pass more body, in + * response to GET_BODY_CHUNK ) + * + * It can handle the following outgoing messages: + * - SEND_HEADERS. Pass the status code and headers. + * - SEND_BODY_CHUNK. Send a chunk of body + * - GET_BODY_CHUNK. Request a chunk of body data + * - END_RESPONSE. Notify the end of a request processing. + * + * @author Henri Gomez [hgomez@apache.org] + * @author Dan Milstein [danmil@shore.net] + * @author Keith Wannamaker [Keith@Wannamaker.org] + * @author Costin Manolache + */ +public class HandlerRequest extends JkHandler +{ + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( HandlerRequest.class ); + + /* + * Note for Host parsing. + */ + public static final int HOSTBUFFER = 10; + + /** + * Thread lock. + */ + private static Object lock = new Object(); + + private HandlerDispatch dispatch; + private String ajpidDir="conf"; + + + public HandlerRequest() { + } + + public void init() { + dispatch=(HandlerDispatch)wEnv.getHandler( "dispatch" ); + if( dispatch != null ) { + // register incoming message handlers + dispatch.registerMessageType( AjpConstants.JK_AJP13_FORWARD_REQUEST, + "JK_AJP13_FORWARD_REQUEST", + this, null); // 2 + + dispatch.registerMessageType( AjpConstants.JK_AJP13_SHUTDOWN, + "JK_AJP13_SHUTDOWN", + this, null); // 7 + + dispatch.registerMessageType( AjpConstants.JK_AJP13_CPING_REQUEST, + "JK_AJP13_CPING_REQUEST", + this, null); // 10 + dispatch.registerMessageType( HANDLE_THREAD_END, + "HANDLE_THREAD_END", + this, null); + // register outgoing messages handler + dispatch.registerMessageType( AjpConstants.JK_AJP13_SEND_BODY_CHUNK, // 3 + "JK_AJP13_SEND_BODY_CHUNK", + this,null ); + } + + tmpBufNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "tmpBuf" ); + secretNote=wEnv.getNoteId( WorkerEnv.ENDPOINT_NOTE, "secret" ); + + if( next==null ) + next=wEnv.getHandler( "container" ); + if( log.isDebugEnabled() ) + log.debug( "Container handler " + next + " " + next.getName() + + " " + next.getClass().getName()); + + // should happen on start() + generateAjp13Id(); + } + + public void setSecret( String s ) { + requiredSecret=s; + } + + public void setUseSecret( boolean b ) { + if(b) { + requiredSecret=Double.toString(Math.random()); + } + } + + public void setDecodedUri( boolean b ) { + decoded=b; + } + + public boolean isTomcatAuthentication() { + return tomcatAuthentication; + } + + public void setShutdownEnabled(boolean se) { + shutdownEnabled = se; + } + + public boolean getShutdownEnabled() { + return shutdownEnabled; + } + + public void setTomcatAuthentication(boolean newTomcatAuthentication) { + tomcatAuthentication = newTomcatAuthentication; + } + + public void setAjpidDir( String path ) { + if( "".equals( path ) ) path=null; + ajpidDir=path; + } + + /** + * Set the flag to tell if we JMX register requests. + */ + public void setRegisterRequests(boolean srr) { + registerRequests = srr; + } + + /** + * Get the flag to tell if we JMX register requests. + */ + public boolean getRegisterRequests() { + return registerRequests; + } + + /** + * Set the flag to delay the initial body read + */ + public void setDelayInitialRead(boolean dir) { + delayInitialRead = dir; + } + + /** + * Get the flag to tell if we delay the initial body read + */ + public boolean getDelayInitialRead() { + return delayInitialRead; + } + + // -------------------- Ajp13.id -------------------- + + private void generateAjp13Id() { + int portInt=8009; // tcpCon.getPort(); + InetAddress address=null; // tcpCon.getAddress(); + + if( requiredSecret == null || !shutdownEnabled ) + return; + + File f1=new File( wEnv.getJkHome() ); + File f2=new File( f1, "conf" ); + + if( ! f2.exists() ) { + log.error( "No conf dir for ajp13.id " + f2 ); + return; + } + + File sf=new File( f2, "ajp13.id"); + + if( log.isDebugEnabled()) + log.debug( "Using stop file: "+sf); + + try { + Properties props=new Properties(); + + props.put( "port", Integer.toString( portInt )); + if( address!=null ) { + props.put( "address", address.getHostAddress() ); + } + if( requiredSecret !=null ) { + props.put( "secret", requiredSecret ); + } + + FileOutputStream stopF=new FileOutputStream( sf ); + props.store( stopF, "Automatically generated, don't edit" ); + } catch( IOException ex ) { + if(log.isDebugEnabled()) + log.debug( "Can't create stop file: "+sf,ex ); + } + } + + // -------------------- Incoming message -------------------- + private String requiredSecret=null; + private int secretNote; + private int tmpBufNote; + + private boolean decoded=true; + private boolean tomcatAuthentication=true; + private boolean registerRequests=true; + private boolean shutdownEnabled=false; + private boolean delayInitialRead = true; + + public int invoke(Msg msg, MsgContext ep ) + throws IOException { + int type=msg.getByte(); + ThreadWithAttributes twa = null; + if (Thread.currentThread() instanceof ThreadWithAttributes) { + twa = (ThreadWithAttributes) Thread.currentThread(); + } + Object control=ep.getControl(); + MessageBytes tmpMB=(MessageBytes)ep.getNote( tmpBufNote ); + if( tmpMB==null ) { + tmpMB= MessageBytes.newInstance(); + ep.setNote( tmpBufNote, tmpMB); + } + + if( log.isDebugEnabled() ) + log.debug( "Handling " + type ); + + switch( type ) { + case AjpConstants.JK_AJP13_FORWARD_REQUEST: + try { + if (twa != null) { + twa.setCurrentStage(control, "JkDecode"); + } + decodeRequest( msg, ep, tmpMB ); + if (twa != null) { + twa.setCurrentStage(control, "JkService"); + twa.setParam(control, + ((Request)ep.getRequest()).unparsedURI()); + } + } catch( Exception ex ) { + log.error( "Error decoding request ", ex ); + msg.dump( "Incomming message"); + return ERROR; + } + + if( requiredSecret != null ) { + String epSecret=(String)ep.getNote( secretNote ); + if( epSecret==null || ! requiredSecret.equals( epSecret ) ) + return ERROR; + } + /* XXX it should be computed from request, by workerEnv */ + if(log.isDebugEnabled() ) + log.debug("Calling next " + next.getName() + " " + + next.getClass().getName()); + + int err= next.invoke( msg, ep ); + if (twa != null) { + twa.setCurrentStage(control, "JkDone"); + } + + if( log.isDebugEnabled() ) + log.debug( "Invoke returned " + err ); + return err; + case AjpConstants.JK_AJP13_SHUTDOWN: + String epSecret=null; + if( msg.getLen() > 3 ) { + // we have a secret + msg.getBytes( tmpMB ); + epSecret=tmpMB.toString(); + } + + if( requiredSecret != null && + requiredSecret.equals( epSecret ) ) { + if( log.isDebugEnabled() ) + log.debug("Received wrong secret, no shutdown "); + return ERROR; + } + + // XXX add isSameAddress check + JkChannel ch=ep.getSource(); + if( !ch.isSameAddress(ep) ) { + log.error("Shutdown request not from 'same address' "); + return ERROR; + } + + if( !shutdownEnabled ) { + log.warn("Ignoring shutdown request: shutdown not enabled"); + return ERROR; + } + // forward to the default handler - it'll do the shutdown + checkRequest(ep); + next.invoke( msg, ep ); + + if(log.isInfoEnabled()) + log.info("Exiting"); + System.exit(0); + + return OK; + + // We got a PING REQUEST, quickly respond with a PONG + case AjpConstants.JK_AJP13_CPING_REQUEST: + msg.reset(); + msg.appendByte(AjpConstants.JK_AJP13_CPONG_REPLY); + ep.getSource().send( msg, ep ); + ep.getSource().flush( msg, ep ); // Server needs to get it + return OK; + + case HANDLE_THREAD_END: + return OK; + + default: + if(log.isInfoEnabled()) + log.info("Unknown message " + type); + } + + return OK; + } + + static int count = 0; + + private Request checkRequest(MsgContext ep) { + Request req=ep.getRequest(); + if( req==null ) { + req=new Request(); + Response res=new Response(); + req.setResponse(res); + ep.setRequest( req ); + if( registerRequests ) { + synchronized(lock) { + ep.getSource().registerRequest(req, ep, count++); + } + } + } + return req; + } + + private int decodeRequest( Msg msg, MsgContext ep, MessageBytes tmpMB ) + throws IOException { + // FORWARD_REQUEST handler + Request req = checkRequest(ep); + + RequestInfo rp = req.getRequestProcessor(); + rp.setStage(Constants.STAGE_PARSE); + MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); + if(tmpMB2 != null) { + tmpMB2.recycle(); + } + req.setStartTime(System.currentTimeMillis()); + + // Translate the HTTP method code to a String. + byte methodCode = msg.getByte(); + if (methodCode != AjpConstants.SC_M_JK_STORED) { + String mName=AjpConstants.methodTransArray[(int)methodCode - 1]; + req.method().setString(mName); + } + + msg.getBytes(req.protocol()); + msg.getBytes(req.requestURI()); + + msg.getBytes(req.remoteAddr()); + msg.getBytes(req.remoteHost()); + msg.getBytes(req.localName()); + req.setLocalPort(msg.getInt()); + + boolean isSSL = msg.getByte() != 0; + if( isSSL ) { + // XXX req.setSecure( true ); + req.scheme().setString("https"); + } + + decodeHeaders( ep, msg, req, tmpMB ); + + decodeAttributes( ep, msg, req, tmpMB ); + + rp.setStage(Constants.STAGE_PREPARE); + MessageBytes valueMB = req.getMimeHeaders().getValue("host"); + parseHost(valueMB, req); + // set cookies on request now that we have all headers + req.getCookies().setHeaders(req.getMimeHeaders()); + + // Check to see if there should be a body packet coming along + // immediately after + int cl=req.getContentLength(); + if(cl > 0) { + JkInputStream jkIS = ep.getInputStream(); + jkIS.setIsReadRequired(true); + if(!delayInitialRead) { + jkIS.receive(); + } + } + + if (log.isTraceEnabled()) { + log.trace(req.toString()); + } + + return OK; + } + + private int decodeAttributes( MsgContext ep, Msg msg, Request req, + MessageBytes tmpMB) { + boolean moreAttr=true; + + while( moreAttr ) { + byte attributeCode=msg.getByte(); + if( attributeCode == AjpConstants.SC_A_ARE_DONE ) + return 200; + + /* Special case ( XXX in future API make it separate type !) + */ + if( attributeCode == AjpConstants.SC_A_SSL_KEY_SIZE ) { + // Bug 1326: it's an Integer. + req.setAttribute(SSLSupport.KEY_SIZE_KEY, + new Integer( msg.getInt())); + //Integer.toString(msg.getInt())); + } + + if( attributeCode == AjpConstants.SC_A_REQ_ATTRIBUTE ) { + // 2 strings ???... + msg.getBytes( tmpMB ); + String n=tmpMB.toString(); + msg.getBytes( tmpMB ); + String v=tmpMB.toString(); + req.setAttribute(n, v ); + if(log.isTraceEnabled()) + log.trace("jk Attribute set " + n + "=" + v); + } + + + // 1 string attributes + switch(attributeCode) { + case AjpConstants.SC_A_CONTEXT : + msg.getBytes( tmpMB ); + // nothing + break; + + case AjpConstants.SC_A_SERVLET_PATH : + msg.getBytes( tmpMB ); + // nothing + break; + + case AjpConstants.SC_A_REMOTE_USER : + if( tomcatAuthentication ) { + // ignore server + msg.getBytes( tmpMB ); + } else { + msg.getBytes(req.getRemoteUser()); + } + break; + + case AjpConstants.SC_A_AUTH_TYPE : + if( tomcatAuthentication ) { + // ignore server + msg.getBytes( tmpMB ); + } else { + msg.getBytes(req.getAuthType()); + } + break; + + case AjpConstants.SC_A_QUERY_STRING : + msg.getBytes(req.queryString()); + break; + + case AjpConstants.SC_A_JVM_ROUTE : + msg.getBytes(req.instanceId()); + break; + + case AjpConstants.SC_A_SSL_CERT : + req.scheme().setString( "https" ); + // Transform the string into certificate. + MessageBytes tmpMB2 = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); + if(tmpMB2 == null) { + tmpMB2 = MessageBytes.newInstance(); + req.setNote(WorkerEnv.SSL_CERT_NOTE, tmpMB2); + } + // SSL certificate extraction is costy, moved to JkCoyoteHandler + msg.getBytes(tmpMB2); + break; + + case AjpConstants.SC_A_SSL_CIPHER : + req.scheme().setString( "https" ); + msg.getBytes(tmpMB); + req.setAttribute(SSLSupport.CIPHER_SUITE_KEY, + tmpMB.toString()); + break; + + case AjpConstants.SC_A_SSL_SESSION : + req.scheme().setString( "https" ); + msg.getBytes(tmpMB); + req.setAttribute(SSLSupport.SESSION_ID_KEY, + tmpMB.toString()); + break; + + case AjpConstants.SC_A_SECRET : + msg.getBytes(tmpMB); + String secret=tmpMB.toString(); + if(log.isTraceEnabled()) + log.trace("Secret: " + secret ); + // endpoint note + ep.setNote( secretNote, secret ); + break; + + case AjpConstants.SC_A_STORED_METHOD: + msg.getBytes(req.method()); + break; + + default: + break; // ignore, we don't know about it - backward compat + } + } + return 200; + } + + private void decodeHeaders( MsgContext ep, Msg msg, Request req, + MessageBytes tmpMB ) { + // Decode headers + MimeHeaders headers = req.getMimeHeaders(); + + int hCount = msg.getInt(); + for(int i = 0 ; i < hCount ; i++) { + String hName = null; + + // Header names are encoded as either an integer code starting + // with 0xA0, or as a normal string (in which case the first + // two bytes are the length). + int isc = msg.peekInt(); + int hId = isc & 0xFF; + + MessageBytes vMB=null; + isc &= 0xFF00; + if(0xA000 == isc) { + msg.getInt(); // To advance the read position + hName = AjpConstants.headerTransArray[hId - 1]; + vMB=headers.addValue( hName ); + } else { + // reset hId -- if the header currently being read + // happens to be 7 or 8 bytes long, the code below + // will think it's the content-type header or the + // content-length header - SC_REQ_CONTENT_TYPE=7, + // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected + // behaviour. see bug 5861 for more information. + hId = -1; + msg.getBytes( tmpMB ); + ByteChunk bc=tmpMB.getByteChunk(); + vMB=headers.addValue( bc.getBuffer(), + bc.getStart(), bc.getLength() ); + } + + msg.getBytes(vMB); + + if (hId == AjpConstants.SC_REQ_CONTENT_LENGTH || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { + // just read the content-length header, so set it + req.setContentLength( vMB.getInt() ); + } else if (hId == AjpConstants.SC_REQ_CONTENT_TYPE || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { + // just read the content-type header, so set it + ByteChunk bchunk = vMB.getByteChunk(); + req.contentType().setBytes(bchunk.getBytes(), + bchunk.getOffset(), + bchunk.getLength()); + } + } + } + + /** + * Parse host. + */ + private void parseHost(MessageBytes valueMB, Request request) + throws IOException { + + if (valueMB == null || valueMB.isNull()) { + // HTTP/1.0 + // Default is what the socket tells us. Overriden if a host is + // found/parsed + request.setServerPort(request.getLocalPort()); + request.serverName().duplicate(request.localName()); + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + CharChunk hostNameC = (CharChunk)request.getNote(HOSTBUFFER); + if(hostNameC == null) { + hostNameC = new CharChunk(valueL); + request.setNote(HOSTBUFFER, hostNameC); + } + hostNameC.recycle(); + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC.append(b); + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (request.scheme().equalsIgnoreCase("https")) { + // 80 - Default HTTTP port + request.setServerPort(443); + } else { + // 443 - Default HTTPS port + request.setServerPort(80); + } + request.serverName().setChars(hostNameC.getChars(), + hostNameC.getStart(), + hostNameC.getLength()); + } else { + + request.serverName().setChars(hostNameC.getChars(), + hostNameC.getStart(), colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.DEC[(int) valueB[i + valueS]]; + if (charValue == -1) { + // Invalid character + throw new CharConversionException("Invalid char in port: " + valueB[i + valueS]); + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + + } + + } + +} diff --git a/java/org/apache/jk/common/JkInputStream.java b/java/org/apache/jk/common/JkInputStream.java index 3947f5850..7d59a4ff0 100644 --- a/java/org/apache/jk/common/JkInputStream.java +++ b/java/org/apache/jk/common/JkInputStream.java @@ -1,318 +1,318 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.IOException; - -import org.apache.coyote.OutputBuffer; -import org.apache.coyote.InputBuffer; -import org.apache.coyote.Request; -import org.apache.coyote.Response; - -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.C2BConverter; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; - -/** Generic input stream impl on top of ajp - */ -public class JkInputStream implements InputBuffer, OutputBuffer { - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( JkInputStream.class ); - - private Msg bodyMsg = new MsgAjp(); - private Msg outputMsg = new MsgAjp(); - private MsgContext mc; - - - // Holds incoming chunks of request body data - private MessageBytes bodyBuff = MessageBytes.newInstance(); - private MessageBytes tempMB = MessageBytes.newInstance(); - private boolean end_of_stream=false; - private boolean isEmpty = true; - private boolean isFirst = true; - private boolean isReplay = false; - private boolean isReadRequired = false; - - static { - // Make certain HttpMessages is loaded for SecurityManager - try { - Class.forName("org.apache.tomcat.util.http.HttpMessages"); - } catch(Exception ex) { - // ignore - } - } - - public JkInputStream(MsgContext context) { - mc = context; - } - - // -------------------- Jk specific methods -------------------- - - - /** - * Set the flag saying that the server is sending a body - */ - public void setIsReadRequired(boolean irr) { - isReadRequired = irr; - } - - /** - * Return the flag saying that the server is sending a body - */ - public boolean isReadRequired() { - return isReadRequired; - } - - - /** Must be called before or after each request - */ - public void recycle() { - if(isReadRequired && isFirst) { - // The Servlet never read the request body, so we need to junk it - try { - receive(); - } catch(IOException iex) { - log.debug("Error consuming request body",iex); - } - } - - end_of_stream = false; - isEmpty = true; - isFirst = true; - isReplay = false; - isReadRequired = false; - bodyBuff.recycle(); - tempMB.recycle(); - } - - - public void endMessage() throws IOException { - outputMsg.reset(); - outputMsg.appendByte(AjpConstants.JK_AJP13_END_RESPONSE); - outputMsg.appendByte(1); - mc.getSource().send(outputMsg, mc); - mc.getSource().flush(outputMsg, mc); - } - - - // -------------------- OutputBuffer implementation -------------------- - - - public int doWrite(ByteChunk chunk, Response res) - throws IOException { - if (!res.isCommitted()) { - // Send the connector a request for commit. The connector should - // then validate the headers, send them (using sendHeader) and - // set the filters accordingly. - res.sendHeaders(); - } - - int len=chunk.getLength(); - byte buf[]=outputMsg.getBuffer(); - // 4 - hardcoded, byte[] marshalling overhead - int chunkSize=buf.length - outputMsg.getHeaderLength() - 4; - int off=0; - while( len > 0 ) { - int thisTime=len; - if( thisTime > chunkSize ) { - thisTime=chunkSize; - } - len-=thisTime; - - outputMsg.reset(); - outputMsg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK); - if( log.isTraceEnabled() ) - log.trace("doWrite " + off + " " + thisTime + " " + len ); - outputMsg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime ); - off+=thisTime; - mc.getSource().send( outputMsg, mc ); - } - return 0; - } - - public int doRead(ByteChunk responseChunk, Request req) - throws IOException { - - if( log.isDebugEnabled()) - log.debug( "doRead " + end_of_stream+ - " " + responseChunk.getOffset()+ " " + responseChunk.getLength()); - if( end_of_stream ) { - return -1; - } - - if( isFirst && isReadRequired ) { - // Handle special first-body-chunk, but only if httpd expects it. - if( !receive() ) { - return 0; - } - } else if(isEmpty) { - if ( !refillReadBuffer() ){ - return -1; - } - } - ByteChunk bc = bodyBuff.getByteChunk(); - responseChunk.setBytes( bc.getBuffer(), bc.getStart(), bc.getLength() ); - isEmpty = true; - return responseChunk.getLength(); - } - - /** Receive a chunk of data. Called to implement the - * 'special' packet in ajp13 and to receive the data - * after we send a GET_BODY packet - */ - public boolean receive() throws IOException { - isFirst = false; - bodyMsg.reset(); - int err = mc.getSource().receive(bodyMsg, mc); - if( log.isDebugEnabled() ) - log.info( "Receiving: getting request body chunk " + err + " " + bodyMsg.getLen() ); - - if(err < 0) { - throw new IOException(); - } - - // No data received. - if( bodyMsg.getLen() == 0 ) { // just the header - // Don't mark 'end of stream' for the first chunk. - // end_of_stream = true; - return false; - } - int blen = bodyMsg.peekInt(); - - if( blen == 0 ) { - return false; - } - - if( log.isTraceEnabled() ) { - bodyMsg.dump("Body buffer"); - } - - bodyMsg.getBytes(bodyBuff); - if( log.isTraceEnabled() ) - log.trace( "Data:\n" + bodyBuff); - isEmpty = false; - return true; - } - - /** - * Get more request body data from the web server and store it in the - * internal buffer. - * - * @return true if there is more data, false if not. - */ - private boolean refillReadBuffer() throws IOException - { - // If the server returns an empty packet, assume that that end of - // the stream has been reached (yuck -- fix protocol??). - if(isReplay) { - end_of_stream = true; // we've read everything there is - } - if (end_of_stream) { - if( log.isDebugEnabled() ) - log.debug("refillReadBuffer: end of stream " ); - return false; - } - - // Why not use outBuf?? - bodyMsg.reset(); - bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK); - bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE); - - if( log.isDebugEnabled() ) - log.debug("refillReadBuffer " + Thread.currentThread()); - - mc.getSource().send(bodyMsg, mc); - mc.getSource().flush(bodyMsg, mc); // Server needs to get it - - // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be - // read - - boolean moreData=receive(); - if( !moreData ) { - end_of_stream=true; - } - return moreData; - } - - public void appendHead(Response res) throws IOException { - if( log.isDebugEnabled() ) - log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() ); - - C2BConverter c2b=mc.getConverter(); - - outputMsg.reset(); - outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS); - outputMsg.appendInt( res.getStatus() ); - - String message=res.getMessage(); - if( message==null ){ - message= HttpMessages.getMessage(res.getStatus()); - } else { - message = message.replace('\n', ' ').replace('\r', ' '); - } - tempMB.setString( message ); - c2b.convert( tempMB ); - outputMsg.appendBytes(tempMB); - - // XXX add headers - - MimeHeaders headers=res.getMimeHeaders(); - String contentType = res.getContentType(); - if( contentType != null ) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = res.getContentLanguage(); - if( contentLanguage != null ) { - headers.setValue("Content-Language").setString(contentLanguage); - } - int contentLength = res.getContentLength(); - if( contentLength >= 0 ) { - headers.setValue("Content-Length").setInt(contentLength); - } - int numHeaders = headers.size(); - outputMsg.appendInt(numHeaders); - for( int i=0; i 0 ) { + int thisTime=len; + if( thisTime > chunkSize ) { + thisTime=chunkSize; + } + len-=thisTime; + + outputMsg.reset(); + outputMsg.appendByte( AjpConstants.JK_AJP13_SEND_BODY_CHUNK); + if( log.isTraceEnabled() ) + log.trace("doWrite " + off + " " + thisTime + " " + len ); + outputMsg.appendBytes( chunk.getBytes(), chunk.getOffset() + off, thisTime ); + off+=thisTime; + mc.getSource().send( outputMsg, mc ); + } + return 0; + } + + public int doRead(ByteChunk responseChunk, Request req) + throws IOException { + + if( log.isDebugEnabled()) + log.debug( "doRead " + end_of_stream+ + " " + responseChunk.getOffset()+ " " + responseChunk.getLength()); + if( end_of_stream ) { + return -1; + } + + if( isFirst && isReadRequired ) { + // Handle special first-body-chunk, but only if httpd expects it. + if( !receive() ) { + return 0; + } + } else if(isEmpty) { + if ( !refillReadBuffer() ){ + return -1; + } + } + ByteChunk bc = bodyBuff.getByteChunk(); + responseChunk.setBytes( bc.getBuffer(), bc.getStart(), bc.getLength() ); + isEmpty = true; + return responseChunk.getLength(); + } + + /** Receive a chunk of data. Called to implement the + * 'special' packet in ajp13 and to receive the data + * after we send a GET_BODY packet + */ + public boolean receive() throws IOException { + isFirst = false; + bodyMsg.reset(); + int err = mc.getSource().receive(bodyMsg, mc); + if( log.isDebugEnabled() ) + log.info( "Receiving: getting request body chunk " + err + " " + bodyMsg.getLen() ); + + if(err < 0) { + throw new IOException(); + } + + // No data received. + if( bodyMsg.getLen() == 0 ) { // just the header + // Don't mark 'end of stream' for the first chunk. + // end_of_stream = true; + return false; + } + int blen = bodyMsg.peekInt(); + + if( blen == 0 ) { + return false; + } + + if( log.isTraceEnabled() ) { + bodyMsg.dump("Body buffer"); + } + + bodyMsg.getBytes(bodyBuff); + if( log.isTraceEnabled() ) + log.trace( "Data:\n" + bodyBuff); + isEmpty = false; + return true; + } + + /** + * Get more request body data from the web server and store it in the + * internal buffer. + * + * @return true if there is more data, false if not. + */ + private boolean refillReadBuffer() throws IOException + { + // If the server returns an empty packet, assume that that end of + // the stream has been reached (yuck -- fix protocol??). + if(isReplay) { + end_of_stream = true; // we've read everything there is + } + if (end_of_stream) { + if( log.isDebugEnabled() ) + log.debug("refillReadBuffer: end of stream " ); + return false; + } + + // Why not use outBuf?? + bodyMsg.reset(); + bodyMsg.appendByte(AjpConstants.JK_AJP13_GET_BODY_CHUNK); + bodyMsg.appendInt(AjpConstants.MAX_READ_SIZE); + + if( log.isDebugEnabled() ) + log.debug("refillReadBuffer " + Thread.currentThread()); + + mc.getSource().send(bodyMsg, mc); + mc.getSource().flush(bodyMsg, mc); // Server needs to get it + + // In JNI mode, response will be in bodyMsg. In TCP mode, response need to be + // read + + boolean moreData=receive(); + if( !moreData ) { + end_of_stream=true; + } + return moreData; + } + + public void appendHead(Response res) throws IOException { + if( log.isDebugEnabled() ) + log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders() ); + + C2BConverter c2b=mc.getConverter(); + + outputMsg.reset(); + outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS); + outputMsg.appendInt( res.getStatus() ); + + String message=res.getMessage(); + if( message==null ){ + message= HttpMessages.getMessage(res.getStatus()); + } else { + message = message.replace('\n', ' ').replace('\r', ' '); + } + tempMB.setString( message ); + c2b.convert( tempMB ); + outputMsg.appendBytes(tempMB); + + // XXX add headers + + MimeHeaders headers=res.getMimeHeaders(); + String contentType = res.getContentType(); + if( contentType != null ) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = res.getContentLanguage(); + if( contentLanguage != null ) { + headers.setValue("Content-Language").setString(contentLanguage); + } + int contentLength = res.getContentLength(); + if( contentLength >= 0 ) { + headers.setValue("Content-Length").setInt(contentLength); + } + int numHeaders = headers.size(); + outputMsg.appendInt(numHeaders); + for( int i=0; i - * If you run into an error message like - * "SystemId Unknown; Line #12; Column #81; Cannot add attribute name after - * child nodes or before an element is produced. Attribute will be ignored." - * after setting mx.enabled to true, you probably need a newer version - * of Xalan. See the RELEASE-NOTES document section on XML Parsers for - * more information. - * - */ -public class JkMX extends JkHandler -{ - MBeanServer mserver; - private boolean enabled=false; - private boolean log4jEnabled=true; - private int httpport=-1; - private String httphost="localhost"; - private String authmode="none"; - private String authuser=null; - private String authpassword=null; - private int jrmpport=-1; - private String jrmphost="localhost"; - private boolean useXSLTProcessor = true; - - public JkMX() { - } - - /* -------------------- Public methods -------------------- */ - - /** Enable the MX4J adapters (new way) - */ - public void setEnabled(boolean b) { - enabled=b; - } - - public boolean getEnabled() { - return enabled; - } - - /** Enable the Log4j MBean) - */ - public void setLog4jEnabled(boolean b) { - log4jEnabled=b; - } - - public boolean getLog4jEnabled() { - return log4jEnabled; - } - - /** Enable the MX4J adapters (old way, compatible) - */ - public void setPort(int i) { - enabled=(i != -1); - } - - public int getPort() { - return ((httpport != -1) ? httpport : jrmpport); - } - - /** Enable the MX4J HTTP internal adapter - */ - public void setHttpPort( int i ) { - httpport=i; - } - - public int getHttpPort() { - return httpport; - } - - public void setHttpHost(String host ) { - this.httphost=host; - } - - public String getHttpHost() { - return httphost; - } - - public void setAuthMode(String mode) { - authmode=mode; - } - - public String getAuthMode() { - return authmode; - } - - public void setAuthUser(String user) { - authuser=user; - } - - public String getAuthUser() { - return authuser; - } - - public void setAuthPassword(String password) { - authpassword=password; - } - - public String getAuthPassword() { - return authpassword; - } - - /** Enable the MX4J JRMP internal adapter - */ - public void setJrmpPort( int i ) { - jrmpport=i; - } - - public int getJrmpPort() { - return jrmpport; - } - - public void setJrmpHost(String host ) { - this.jrmphost=host; - } - - public String getJrmpHost() { - return jrmphost; - } - - public boolean getUseXSLTProcessor() { - return useXSLTProcessor; - } - - public void setUseXSLTProcessor(boolean uxsltp) { - useXSLTProcessor = uxsltp; - } - - /* ==================== Start/stop ==================== */ - ObjectName httpServerName=null; - ObjectName jrmpServerName=null; - - /** Initialize the worker. After this call the worker will be - * ready to accept new requests. - */ - public void loadAdapter() throws IOException { - boolean httpAdapterLoaded = false; - boolean jrmpAdapterLoaded = false; - - if ((httpport != -1) && classExists("mx4j.adaptor.http.HttpAdaptor")) { - try { - httpServerName = registerObject("mx4j.adaptor.http.HttpAdaptor", - "Http:name=HttpAdaptor"); - - - if( httphost!=null ) - mserver.setAttribute(httpServerName, new Attribute("Host", httphost)); - mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport))); - - if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) ) - mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode)); - - if( authuser!=null && authpassword!=null ) - mserver.invoke(httpServerName, "addAuthorization", - new Object[] { - authuser, - authpassword}, - new String[] { "java.lang.String", "java.lang.String" }); - - if(useXSLTProcessor) { - ObjectName processorName = registerObject("mx4j.adaptor.http.XSLTProcessor", - "Http:name=XSLTProcessor"); - mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName)); - } - - // starts the server - mserver.invoke(httpServerName, "start", null, null); - - log.info( "Started MX4J console on host " + httphost + " at port " + httpport); - - httpAdapterLoaded = true; - - } catch( Throwable t ) { - httpServerName=null; - log.error( "Can't load the MX4J http adapter ", t ); - } - } - - if ((httpport != -1) && (!httpAdapterLoaded) && classExists("mx4j.tools.adaptor.http.HttpAdaptor")) { - try { - httpServerName = registerObject("mx4j.tools.adaptor.http.HttpAdaptor", - "Http:name=HttpAdaptor"); - - - if( httphost!=null ) - mserver.setAttribute(httpServerName, new Attribute("Host", httphost)); - mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport))); - - if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) ) - mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode)); - - if( authuser!=null && authpassword!=null ) - mserver.invoke(httpServerName, "addAuthorization", - new Object[] { - authuser, - authpassword}, - new String[] { "java.lang.String", "java.lang.String" }); - - if(useXSLTProcessor) { - ObjectName processorName = registerObject("mx4j.tools.adaptor.http.XSLTProcessor", - "Http:name=XSLTProcessor"); - mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName)); - } - // starts the server - mserver.invoke(httpServerName, "start", null, null); - if(log.isInfoEnabled()) - log.info( "Started MX4J console on host " + httphost + " at port " + httpport); - - httpAdapterLoaded = true; - - } catch( Throwable t ) { - httpServerName=null; - log.error( "Can't load the MX4J http adapter ", t ); - } - } - - if ((jrmpport != -1) && classExists("mx4j.tools.naming.NamingService")) { - try { - jrmpServerName = registerObject("mx4j.tools.naming.NamingService", - "Naming:name=rmiregistry"); - mserver.setAttribute(jrmpServerName, new Attribute("Port", - new Integer(jrmpport))); - mserver.invoke(jrmpServerName, "start", null, null); - if(log.isInfoEnabled()) - log.info( "Creating " + jrmpServerName ); - - // Create the JRMP adaptor - ObjectName adaptor = registerObject("mx4j.adaptor.rmi.jrmp.JRMPAdaptor", - "Adaptor:protocol=jrmp"); - - - mserver.setAttribute(adaptor, new Attribute("JNDIName", "jrmp")); - - mserver.invoke( adaptor, "putNamingProperty", - new Object[] { - javax.naming.Context.INITIAL_CONTEXT_FACTORY, - "com.sun.jndi.rmi.registry.RegistryContextFactory"}, - new String[] { "java.lang.Object", "java.lang.Object" }); - - String jrpmurl = "rmi://" + jrmphost + ":" + Integer.toString(jrmpport) ; - - mserver.invoke( adaptor, "putNamingProperty", - new Object[] { - javax.naming.Context.PROVIDER_URL, - jrpmurl}, - new String[] { "java.lang.Object", "java.lang.Object" }); - - // Registers the JRMP adaptor in JNDI and starts it - mserver.invoke(adaptor, "start", null, null); - if(log.isInfoEnabled()) - log.info( "Creating " + adaptor + " on host " + jrmphost + " at port " + jrmpport); - - jrmpAdapterLoaded = true; - - } catch( Exception ex ) { - jrmpServerName = null; - log.error( "MX4j RMI adapter not loaded: " + ex.toString()); - } - } - - if ((httpport != -1) && (! httpAdapterLoaded) && classExists("com.sun.jdmk.comm.HtmlAdaptorServer")) { - try { - httpServerName=registerObject("com.sun.jdmk.comm.HtmlAdaptorServer", - "Adaptor:name=html,port=" + httpport); - if(log.isInfoEnabled()) - log.info("Registering the JMX_RI html adapter " + httpServerName + " at port " + httpport); - - mserver.setAttribute(httpServerName, - new Attribute("Port", new Integer(httpport))); - - mserver.invoke(httpServerName, "start", null, null); - - httpAdapterLoaded = true; - } catch( Throwable t ) { - httpServerName = null; - log.error( "Can't load the JMX_RI http adapter " + t.toString() ); - } - } - - if ((!httpAdapterLoaded) && (!jrmpAdapterLoaded)) - log.warn( "No adaptors were loaded but mx.enabled was defined."); - - } - - public void destroy() { - try { - if(log.isInfoEnabled()) - log.info("Stoping JMX "); - - if( httpServerName!=null ) { - mserver.invoke(httpServerName, "stop", null, null); - } - if( jrmpServerName!=null ) { - mserver.invoke(jrmpServerName, "stop", null, null); - } - } catch( Throwable t ) { - log.error( "Destroy error" + t ); - } - } - - public void init() throws IOException { - try { - mserver = getMBeanServer(); - - if( enabled ) { - loadAdapter(); - } - if( log4jEnabled) { - try { - registerObject("org.apache.log4j.jmx.HierarchyDynamicMBean" , - "log4j:hierarchy=default"); - if(log.isInfoEnabled()) - log.info("Registering the JMX hierarchy for Log4J "); - } catch( Throwable t ) { - if(log.isInfoEnabled()) - log.info("Can't enable log4j mx: ",t); - } - } - } catch( Throwable t ) { - log.error( "Init error", t ); - } - } - - public void addHandlerCallback( JkHandler w ) { - } - - MBeanServer getMBeanServer() { - MBeanServer server; - if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { - server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); - } else { - server=MBeanServerFactory.createMBeanServer(); - } - return (server); - } - - - private static boolean classExists(String className) { - try { - Thread.currentThread().getContextClassLoader().loadClass(className); - return true; - } catch(Throwable e) { - if (log.isInfoEnabled()) - log.info( "className [" + className + "] does not exist"); - return false; - } - } - - private ObjectName registerObject(String className, String oName) - throws Exception { - Class c = Class.forName(className); - Object o = c.newInstance(); - ObjectName objN = new ObjectName(oName); - mserver.registerMBean(o, objN); - return objN; - } - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( JkMX.class ); - - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + + +import org.apache.jk.core.JkHandler; + +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.Attribute; +import javax.management.MBeanServerFactory; +import java.io.IOException; + +/** + * Load the HTTP or RMI adapters for MX4J and JMXRI. + * + * Add "mx.enabled=true" in jk2.properties to enable it. + * You could also select http and/or jrmp protocol, + * with mx.httpPort, mx.httpHost, mxjrmpPort and mx.jrmpPort. + *

        + * If you run into an error message like + * "SystemId Unknown; Line #12; Column #81; Cannot add attribute name after + * child nodes or before an element is produced. Attribute will be ignored." + * after setting mx.enabled to true, you probably need a newer version + * of Xalan. See the RELEASE-NOTES document section on XML Parsers for + * more information. + * + */ +public class JkMX extends JkHandler +{ + MBeanServer mserver; + private boolean enabled=false; + private boolean log4jEnabled=true; + private int httpport=-1; + private String httphost="localhost"; + private String authmode="none"; + private String authuser=null; + private String authpassword=null; + private int jrmpport=-1; + private String jrmphost="localhost"; + private boolean useXSLTProcessor = true; + + public JkMX() { + } + + /* -------------------- Public methods -------------------- */ + + /** Enable the MX4J adapters (new way) + */ + public void setEnabled(boolean b) { + enabled=b; + } + + public boolean getEnabled() { + return enabled; + } + + /** Enable the Log4j MBean) + */ + public void setLog4jEnabled(boolean b) { + log4jEnabled=b; + } + + public boolean getLog4jEnabled() { + return log4jEnabled; + } + + /** Enable the MX4J adapters (old way, compatible) + */ + public void setPort(int i) { + enabled=(i != -1); + } + + public int getPort() { + return ((httpport != -1) ? httpport : jrmpport); + } + + /** Enable the MX4J HTTP internal adapter + */ + public void setHttpPort( int i ) { + httpport=i; + } + + public int getHttpPort() { + return httpport; + } + + public void setHttpHost(String host ) { + this.httphost=host; + } + + public String getHttpHost() { + return httphost; + } + + public void setAuthMode(String mode) { + authmode=mode; + } + + public String getAuthMode() { + return authmode; + } + + public void setAuthUser(String user) { + authuser=user; + } + + public String getAuthUser() { + return authuser; + } + + public void setAuthPassword(String password) { + authpassword=password; + } + + public String getAuthPassword() { + return authpassword; + } + + /** Enable the MX4J JRMP internal adapter + */ + public void setJrmpPort( int i ) { + jrmpport=i; + } + + public int getJrmpPort() { + return jrmpport; + } + + public void setJrmpHost(String host ) { + this.jrmphost=host; + } + + public String getJrmpHost() { + return jrmphost; + } + + public boolean getUseXSLTProcessor() { + return useXSLTProcessor; + } + + public void setUseXSLTProcessor(boolean uxsltp) { + useXSLTProcessor = uxsltp; + } + + /* ==================== Start/stop ==================== */ + ObjectName httpServerName=null; + ObjectName jrmpServerName=null; + + /** Initialize the worker. After this call the worker will be + * ready to accept new requests. + */ + public void loadAdapter() throws IOException { + boolean httpAdapterLoaded = false; + boolean jrmpAdapterLoaded = false; + + if ((httpport != -1) && classExists("mx4j.adaptor.http.HttpAdaptor")) { + try { + httpServerName = registerObject("mx4j.adaptor.http.HttpAdaptor", + "Http:name=HttpAdaptor"); + + + if( httphost!=null ) + mserver.setAttribute(httpServerName, new Attribute("Host", httphost)); + mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport))); + + if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) ) + mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode)); + + if( authuser!=null && authpassword!=null ) + mserver.invoke(httpServerName, "addAuthorization", + new Object[] { + authuser, + authpassword}, + new String[] { "java.lang.String", "java.lang.String" }); + + if(useXSLTProcessor) { + ObjectName processorName = registerObject("mx4j.adaptor.http.XSLTProcessor", + "Http:name=XSLTProcessor"); + mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName)); + } + + // starts the server + mserver.invoke(httpServerName, "start", null, null); + + log.info( "Started MX4J console on host " + httphost + " at port " + httpport); + + httpAdapterLoaded = true; + + } catch( Throwable t ) { + httpServerName=null; + log.error( "Can't load the MX4J http adapter ", t ); + } + } + + if ((httpport != -1) && (!httpAdapterLoaded) && classExists("mx4j.tools.adaptor.http.HttpAdaptor")) { + try { + httpServerName = registerObject("mx4j.tools.adaptor.http.HttpAdaptor", + "Http:name=HttpAdaptor"); + + + if( httphost!=null ) + mserver.setAttribute(httpServerName, new Attribute("Host", httphost)); + mserver.setAttribute(httpServerName, new Attribute("Port", new Integer(httpport))); + + if( "none".equals(authmode) || "basic".equals(authmode) || "digest".equals(authmode) ) + mserver.setAttribute(httpServerName, new Attribute("AuthenticationMethod", authmode)); + + if( authuser!=null && authpassword!=null ) + mserver.invoke(httpServerName, "addAuthorization", + new Object[] { + authuser, + authpassword}, + new String[] { "java.lang.String", "java.lang.String" }); + + if(useXSLTProcessor) { + ObjectName processorName = registerObject("mx4j.tools.adaptor.http.XSLTProcessor", + "Http:name=XSLTProcessor"); + mserver.setAttribute(httpServerName, new Attribute("ProcessorName", processorName)); + } + // starts the server + mserver.invoke(httpServerName, "start", null, null); + if(log.isInfoEnabled()) + log.info( "Started MX4J console on host " + httphost + " at port " + httpport); + + httpAdapterLoaded = true; + + } catch( Throwable t ) { + httpServerName=null; + log.error( "Can't load the MX4J http adapter ", t ); + } + } + + if ((jrmpport != -1) && classExists("mx4j.tools.naming.NamingService")) { + try { + jrmpServerName = registerObject("mx4j.tools.naming.NamingService", + "Naming:name=rmiregistry"); + mserver.setAttribute(jrmpServerName, new Attribute("Port", + new Integer(jrmpport))); + mserver.invoke(jrmpServerName, "start", null, null); + if(log.isInfoEnabled()) + log.info( "Creating " + jrmpServerName ); + + // Create the JRMP adaptor + ObjectName adaptor = registerObject("mx4j.adaptor.rmi.jrmp.JRMPAdaptor", + "Adaptor:protocol=jrmp"); + + + mserver.setAttribute(adaptor, new Attribute("JNDIName", "jrmp")); + + mserver.invoke( adaptor, "putNamingProperty", + new Object[] { + javax.naming.Context.INITIAL_CONTEXT_FACTORY, + "com.sun.jndi.rmi.registry.RegistryContextFactory"}, + new String[] { "java.lang.Object", "java.lang.Object" }); + + String jrpmurl = "rmi://" + jrmphost + ":" + Integer.toString(jrmpport) ; + + mserver.invoke( adaptor, "putNamingProperty", + new Object[] { + javax.naming.Context.PROVIDER_URL, + jrpmurl}, + new String[] { "java.lang.Object", "java.lang.Object" }); + + // Registers the JRMP adaptor in JNDI and starts it + mserver.invoke(adaptor, "start", null, null); + if(log.isInfoEnabled()) + log.info( "Creating " + adaptor + " on host " + jrmphost + " at port " + jrmpport); + + jrmpAdapterLoaded = true; + + } catch( Exception ex ) { + jrmpServerName = null; + log.error( "MX4j RMI adapter not loaded: " + ex.toString()); + } + } + + if ((httpport != -1) && (! httpAdapterLoaded) && classExists("com.sun.jdmk.comm.HtmlAdaptorServer")) { + try { + httpServerName=registerObject("com.sun.jdmk.comm.HtmlAdaptorServer", + "Adaptor:name=html,port=" + httpport); + if(log.isInfoEnabled()) + log.info("Registering the JMX_RI html adapter " + httpServerName + " at port " + httpport); + + mserver.setAttribute(httpServerName, + new Attribute("Port", new Integer(httpport))); + + mserver.invoke(httpServerName, "start", null, null); + + httpAdapterLoaded = true; + } catch( Throwable t ) { + httpServerName = null; + log.error( "Can't load the JMX_RI http adapter " + t.toString() ); + } + } + + if ((!httpAdapterLoaded) && (!jrmpAdapterLoaded)) + log.warn( "No adaptors were loaded but mx.enabled was defined."); + + } + + public void destroy() { + try { + if(log.isInfoEnabled()) + log.info("Stoping JMX "); + + if( httpServerName!=null ) { + mserver.invoke(httpServerName, "stop", null, null); + } + if( jrmpServerName!=null ) { + mserver.invoke(jrmpServerName, "stop", null, null); + } + } catch( Throwable t ) { + log.error( "Destroy error" + t ); + } + } + + public void init() throws IOException { + try { + mserver = getMBeanServer(); + + if( enabled ) { + loadAdapter(); + } + if( log4jEnabled) { + try { + registerObject("org.apache.log4j.jmx.HierarchyDynamicMBean" , + "log4j:hierarchy=default"); + if(log.isInfoEnabled()) + log.info("Registering the JMX hierarchy for Log4J "); + } catch( Throwable t ) { + if(log.isInfoEnabled()) + log.info("Can't enable log4j mx: ",t); + } + } + } catch( Throwable t ) { + log.error( "Init error", t ); + } + } + + public void addHandlerCallback( JkHandler w ) { + } + + MBeanServer getMBeanServer() { + MBeanServer server; + if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { + server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); + } else { + server=MBeanServerFactory.createMBeanServer(); + } + return (server); + } + + + private static boolean classExists(String className) { + try { + Thread.currentThread().getContextClassLoader().loadClass(className); + return true; + } catch(Throwable e) { + if (log.isInfoEnabled()) + log.info( "className [" + className + "] does not exist"); + return false; + } + } + + private ObjectName registerObject(String className, String oName) + throws Exception { + Class c = Class.forName(className); + Object o = c.newInstance(); + ObjectName objN = new ObjectName(oName); + mserver.registerMBean(o, objN); + return objN; + } + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( JkMX.class ); + + +} + diff --git a/java/org/apache/jk/common/JniHandler.java b/java/org/apache/jk/common/JniHandler.java index 46e176a9a..28120164f 100644 --- a/java/org/apache/jk/common/JniHandler.java +++ b/java/org/apache/jk/common/JniHandler.java @@ -1,317 +1,317 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.IOException; - -import javax.management.ObjectName; - -import org.apache.jk.apr.AprImpl; -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.JkChannel; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.C2BConverter; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.modeler.Registry; - - -/** - * Base class for components using native code ( libjkjni.so ). - * It allows to access the jk_env and wrap ( 'box' ? ) a native - * jk component, and call it's methods. - * - * Note that get/setAttribute are expensive ( Strings, etc ), - * invoke() is were all optimizations are done. We do recycle - * all memory on both C and java sides ( the only exception is - * when we attempt pinning but the VM doesn't support it ). The - * low level optimizations from ByteBuffer, etc are used to - * reduce the overhead of passing strings. - * - * @author Costin Manolache - */ -public class JniHandler extends JkHandler { - protected AprImpl apr; - - // The native side handler - protected long nativeJkHandlerP; - - protected String jkHome; - - // Dispatch table codes. Hardcoded for now, will change when we have more handlers. - public static final int JK_HANDLE_JNI_DISPATCH=0x15; - public static final int JK_HANDLE_SHM_DISPATCH=0x16; - - - public static final int MSG_NOTE=0; - public static final int MB_NOTE=2; - private boolean paused = false; - - - public JniHandler() { - } - - /** - */ - public void setJkHome( String s ) { - jkHome=s; - } - - public String getJkHome() { - return jkHome; - } - - /** You must call initNative() inside the component init() - */ - public void init() throws IOException { - // static field init, temp - } - - protected void initNative(String nativeComponentName) { - apr=(AprImpl)wEnv.getHandler("apr"); - if( apr==null ) { - // In most cases we can just load it automatically. - // that requires all libs to be installed in standard places - // ( LD_LIBRARY_PATH, /usr/lib - try { - apr=new AprImpl(); - wEnv.addHandler("apr", apr); - apr.init(); - if( oname != null ) { - ObjectName aprname=new ObjectName(oname.getDomain() + - ":type=JkHandler, name=apr"); - Registry.getRegistry(null, null).registerComponent(apr, aprname, null); - } - } catch( Throwable t ) { - log.debug("Can't load apr", t); - apr=null; - } - } - if( apr==null || ! apr.isLoaded() ) { - if( log.isDebugEnabled() ) - log.debug("No apr, disabling jni proxy "); - apr=null; - return; - } - - try { - long xEnv=apr.getJkEnv(); - nativeJkHandlerP=apr.getJkHandler(xEnv, nativeComponentName ); - - if( nativeJkHandlerP==0 ) { - log.debug("Component not found, creating it " + nativeComponentName ); - nativeJkHandlerP=apr.createJkHandler(xEnv, nativeComponentName); - } - log.debug("Native proxy " + nativeJkHandlerP ); - apr.releaseJkEnv(xEnv); - } catch( Throwable t ) { - apr=null; - log.info("Error calling apr ", t); - } - } - - public void appendString( Msg msg, String s, C2BConverter charsetDecoder) - throws IOException - { - ByteChunk bc=charsetDecoder.getByteChunk(); - charsetDecoder.recycle(); - charsetDecoder.convert( s ); - charsetDecoder.flushBuffer(); - msg.appendByteChunk( bc ); - } - - public void pause() throws Exception { - synchronized(this) { - paused = true; - } - } - - public void resume() throws Exception { - synchronized(this) { - paused = false; - notifyAll(); - } - } - - - /** Create a msg context to be used with the shm channel - */ - public MsgContext createMsgContext() { - if( nativeJkHandlerP==0 || apr==null ) - return null; - - synchronized(this) { - try{ - while(paused) { - wait(); - } - }catch(InterruptedException ie) { - // Ignore, since it can't happen - } - } - - try { - MsgContext msgCtx=new MsgContext(); - MsgAjp msg=new MsgAjp(); - - msgCtx.setSource( (JkChannel)this ); - msgCtx.setWorkerEnv( wEnv ); - - msgCtx.setNext( this ); - - msgCtx.setMsg( MSG_NOTE, msg); // XXX Use noteId - - C2BConverter c2b=new C2BConverter( "iso-8859-1" ); - msgCtx.setConverter( c2b ); - - MessageBytes tmpMB= MessageBytes.newInstance(); - msgCtx.setNote( MB_NOTE, tmpMB ); - return msgCtx; - } catch( Exception ex ) { - log.error("Can't create endpoint", ex); - return null; - } - } - - public void setNativeAttribute(String name, String val) throws IOException { - if( apr==null ) return; - - if( nativeJkHandlerP == 0 ) { - log.error( "Unitialized component " + name+ " " + val ); - return; - } - - long xEnv=apr.getJkEnv(); - - apr.jkSetAttribute( xEnv, nativeJkHandlerP, name, val ); - - apr.releaseJkEnv( xEnv ); - } - - public void initJkComponent() throws IOException { - if( apr==null ) return; - - if( nativeJkHandlerP == 0 ) { - log.error( "Unitialized component " ); - return; - } - - long xEnv=apr.getJkEnv(); - - apr.jkInit( xEnv, nativeJkHandlerP ); - - apr.releaseJkEnv( xEnv ); - } - - public void destroyJkComponent() throws IOException { - if( apr==null ) return; - - if( nativeJkHandlerP == 0 ) { - log.error( "Unitialized component " ); - return; - } - - long xEnv=apr.getJkEnv(); - - apr.jkDestroy( xEnv, nativeJkHandlerP ); - - apr.releaseJkEnv( xEnv ); - } - - - - protected void setNativeEndpoint(MsgContext msgCtx) { - long xEnv=apr.getJkEnv(); - msgCtx.setJniEnv( xEnv ); - - long epP=apr.createJkHandler(xEnv, "endpoint"); - log.debug("create ep " + epP ); - if( epP == 0 ) return; - apr.jkInit( xEnv, epP ); - msgCtx.setJniContext( epP ); - - } - - protected void recycleNative(MsgContext ep) { - apr.jkRecycle(ep.getJniEnv(), ep.getJniContext()); - } - - /** send and get the response in the same buffer. This calls the - * method on the wrapped jk_bean object. - */ - protected int nativeDispatch( Msg msg, MsgContext ep, int code, int raw ) - throws IOException - { - if( log.isDebugEnabled() ) - log.debug( "Sending packet " + code + " " + raw); - - if( raw == 0 ) { - msg.end(); - - if( log.isTraceEnabled() ) msg.dump("OUT:" ); - } - - // Create ( or reuse ) the jk_endpoint ( the native pair of - // MsgContext ) - long xEnv=ep.getJniEnv(); - long nativeContext=ep.getJniContext(); - if( nativeContext==0 || xEnv==0 ) { - setNativeEndpoint( ep ); - xEnv=ep.getJniEnv(); - nativeContext=ep.getJniContext(); - } - - if( xEnv==0 || nativeContext==0 || nativeJkHandlerP==0 ) { - log.error("invokeNative: Null pointer "); - return -1; - } - - // Will process the message in the current thread. - // No wait needed to receive the response, if any - int status=AprImpl.jkInvoke( xEnv, - nativeJkHandlerP, - nativeContext, - code, msg.getBuffer(), 0, msg.getLen(), raw ); - - if( status != 0 && status != 2 ) { - log.error( "nativeDispatch: error " + status, new Throwable() ); - } - - if( log.isDebugEnabled() ) log.debug( "Sending packet - done " + status); - return status; - } - - /** Base implementation for invoke. Dispatch the action to the native - * code, where invoke() is called on the wrapped jk_bean. - */ - public int invoke(Msg msg, MsgContext ep ) - throws IOException - { - long xEnv=ep.getJniEnv(); - int type=ep.getType(); - - int status=nativeDispatch(msg, ep, type, 0 ); - - apr.jkRecycle(xEnv, ep.getJniContext()); - apr.releaseJkEnv( xEnv ); - return status; - } - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( JniHandler.class ); -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.io.IOException; + +import javax.management.ObjectName; + +import org.apache.jk.apr.AprImpl; +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.JkChannel; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.C2BConverter; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.modeler.Registry; + + +/** + * Base class for components using native code ( libjkjni.so ). + * It allows to access the jk_env and wrap ( 'box' ? ) a native + * jk component, and call it's methods. + * + * Note that get/setAttribute are expensive ( Strings, etc ), + * invoke() is were all optimizations are done. We do recycle + * all memory on both C and java sides ( the only exception is + * when we attempt pinning but the VM doesn't support it ). The + * low level optimizations from ByteBuffer, etc are used to + * reduce the overhead of passing strings. + * + * @author Costin Manolache + */ +public class JniHandler extends JkHandler { + protected AprImpl apr; + + // The native side handler + protected long nativeJkHandlerP; + + protected String jkHome; + + // Dispatch table codes. Hardcoded for now, will change when we have more handlers. + public static final int JK_HANDLE_JNI_DISPATCH=0x15; + public static final int JK_HANDLE_SHM_DISPATCH=0x16; + + + public static final int MSG_NOTE=0; + public static final int MB_NOTE=2; + private boolean paused = false; + + + public JniHandler() { + } + + /** + */ + public void setJkHome( String s ) { + jkHome=s; + } + + public String getJkHome() { + return jkHome; + } + + /** You must call initNative() inside the component init() + */ + public void init() throws IOException { + // static field init, temp + } + + protected void initNative(String nativeComponentName) { + apr=(AprImpl)wEnv.getHandler("apr"); + if( apr==null ) { + // In most cases we can just load it automatically. + // that requires all libs to be installed in standard places + // ( LD_LIBRARY_PATH, /usr/lib + try { + apr=new AprImpl(); + wEnv.addHandler("apr", apr); + apr.init(); + if( oname != null ) { + ObjectName aprname=new ObjectName(oname.getDomain() + + ":type=JkHandler, name=apr"); + Registry.getRegistry(null, null).registerComponent(apr, aprname, null); + } + } catch( Throwable t ) { + log.debug("Can't load apr", t); + apr=null; + } + } + if( apr==null || ! apr.isLoaded() ) { + if( log.isDebugEnabled() ) + log.debug("No apr, disabling jni proxy "); + apr=null; + return; + } + + try { + long xEnv=apr.getJkEnv(); + nativeJkHandlerP=apr.getJkHandler(xEnv, nativeComponentName ); + + if( nativeJkHandlerP==0 ) { + log.debug("Component not found, creating it " + nativeComponentName ); + nativeJkHandlerP=apr.createJkHandler(xEnv, nativeComponentName); + } + log.debug("Native proxy " + nativeJkHandlerP ); + apr.releaseJkEnv(xEnv); + } catch( Throwable t ) { + apr=null; + log.info("Error calling apr ", t); + } + } + + public void appendString( Msg msg, String s, C2BConverter charsetDecoder) + throws IOException + { + ByteChunk bc=charsetDecoder.getByteChunk(); + charsetDecoder.recycle(); + charsetDecoder.convert( s ); + charsetDecoder.flushBuffer(); + msg.appendByteChunk( bc ); + } + + public void pause() throws Exception { + synchronized(this) { + paused = true; + } + } + + public void resume() throws Exception { + synchronized(this) { + paused = false; + notifyAll(); + } + } + + + /** Create a msg context to be used with the shm channel + */ + public MsgContext createMsgContext() { + if( nativeJkHandlerP==0 || apr==null ) + return null; + + synchronized(this) { + try{ + while(paused) { + wait(); + } + }catch(InterruptedException ie) { + // Ignore, since it can't happen + } + } + + try { + MsgContext msgCtx=new MsgContext(); + MsgAjp msg=new MsgAjp(); + + msgCtx.setSource( (JkChannel)this ); + msgCtx.setWorkerEnv( wEnv ); + + msgCtx.setNext( this ); + + msgCtx.setMsg( MSG_NOTE, msg); // XXX Use noteId + + C2BConverter c2b=new C2BConverter( "iso-8859-1" ); + msgCtx.setConverter( c2b ); + + MessageBytes tmpMB= MessageBytes.newInstance(); + msgCtx.setNote( MB_NOTE, tmpMB ); + return msgCtx; + } catch( Exception ex ) { + log.error("Can't create endpoint", ex); + return null; + } + } + + public void setNativeAttribute(String name, String val) throws IOException { + if( apr==null ) return; + + if( nativeJkHandlerP == 0 ) { + log.error( "Unitialized component " + name+ " " + val ); + return; + } + + long xEnv=apr.getJkEnv(); + + apr.jkSetAttribute( xEnv, nativeJkHandlerP, name, val ); + + apr.releaseJkEnv( xEnv ); + } + + public void initJkComponent() throws IOException { + if( apr==null ) return; + + if( nativeJkHandlerP == 0 ) { + log.error( "Unitialized component " ); + return; + } + + long xEnv=apr.getJkEnv(); + + apr.jkInit( xEnv, nativeJkHandlerP ); + + apr.releaseJkEnv( xEnv ); + } + + public void destroyJkComponent() throws IOException { + if( apr==null ) return; + + if( nativeJkHandlerP == 0 ) { + log.error( "Unitialized component " ); + return; + } + + long xEnv=apr.getJkEnv(); + + apr.jkDestroy( xEnv, nativeJkHandlerP ); + + apr.releaseJkEnv( xEnv ); + } + + + + protected void setNativeEndpoint(MsgContext msgCtx) { + long xEnv=apr.getJkEnv(); + msgCtx.setJniEnv( xEnv ); + + long epP=apr.createJkHandler(xEnv, "endpoint"); + log.debug("create ep " + epP ); + if( epP == 0 ) return; + apr.jkInit( xEnv, epP ); + msgCtx.setJniContext( epP ); + + } + + protected void recycleNative(MsgContext ep) { + apr.jkRecycle(ep.getJniEnv(), ep.getJniContext()); + } + + /** send and get the response in the same buffer. This calls the + * method on the wrapped jk_bean object. + */ + protected int nativeDispatch( Msg msg, MsgContext ep, int code, int raw ) + throws IOException + { + if( log.isDebugEnabled() ) + log.debug( "Sending packet " + code + " " + raw); + + if( raw == 0 ) { + msg.end(); + + if( log.isTraceEnabled() ) msg.dump("OUT:" ); + } + + // Create ( or reuse ) the jk_endpoint ( the native pair of + // MsgContext ) + long xEnv=ep.getJniEnv(); + long nativeContext=ep.getJniContext(); + if( nativeContext==0 || xEnv==0 ) { + setNativeEndpoint( ep ); + xEnv=ep.getJniEnv(); + nativeContext=ep.getJniContext(); + } + + if( xEnv==0 || nativeContext==0 || nativeJkHandlerP==0 ) { + log.error("invokeNative: Null pointer "); + return -1; + } + + // Will process the message in the current thread. + // No wait needed to receive the response, if any + int status=AprImpl.jkInvoke( xEnv, + nativeJkHandlerP, + nativeContext, + code, msg.getBuffer(), 0, msg.getLen(), raw ); + + if( status != 0 && status != 2 ) { + log.error( "nativeDispatch: error " + status, new Throwable() ); + } + + if( log.isDebugEnabled() ) log.debug( "Sending packet - done " + status); + return status; + } + + /** Base implementation for invoke. Dispatch the action to the native + * code, where invoke() is called on the wrapped jk_bean. + */ + public int invoke(Msg msg, MsgContext ep ) + throws IOException + { + long xEnv=ep.getJniEnv(); + int type=ep.getType(); + + int status=nativeDispatch(msg, ep, type, 0 ); + + apr.jkRecycle(xEnv, ep.getJniContext()); + apr.releaseJkEnv( xEnv ); + return status; + } + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( JniHandler.class ); +} diff --git a/java/org/apache/jk/common/MsgAjp.java b/java/org/apache/jk/common/MsgAjp.java index aa3eb9fbb..b1436a380 100644 --- a/java/org/apache/jk/common/MsgAjp.java +++ b/java/org/apache/jk/common/MsgAjp.java @@ -1,329 +1,329 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.IOException; - -import org.apache.jk.core.Msg; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; - -/** - * A single packet for communication between the web server and the - * container. Designed to be reused many times with no creation of - * garbage. Understands the format of data types for these packets. - * Can be used (somewhat confusingly) for both incoming and outgoing - * packets. - * - * See Ajp14/Ajp13Packet.java. - * - * @author Henri Gomez [hgomez@apache.org] - * @author Dan Milstein [danmil@shore.net] - * @author Keith Wannamaker [Keith@Wannamaker.org] - * @author Kevin Seguin - * @author Costin Manolache - */ -public class MsgAjp extends Msg { - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( MsgAjp.class ); - - // that's the original buffer size in ajp13 - otherwise we'll get interoperability problems. - private byte buf[]=new byte[8*1024]; - // The current read or write position in the buffer - private int pos; - /** - * This actually means different things depending on whether the - * packet is read or write. For read, it's the length of the - * payload (excluding the header). For write, it's the length of - * the packet as a whole (counting the header). Oh, well. - */ - private int len; - - - - - /** - * Prepare this packet for accumulating a message from the container to - * the web server. Set the write position to just after the header - * (but leave the length unwritten, because it is as yet unknown). - */ - public void reset() { - len = 4; - pos = 4; - } - - /** - * For a packet to be sent to the web server, finish the process of - * accumulating data and write the length of the data payload into - * the header. - */ - public void end() { - len=pos; - int dLen=len-4; - - buf[0] = (byte)0x41; - buf[1] = (byte)0x42; - buf[2]= (byte)((dLen>>>8 ) & 0xFF ); - buf[3] = (byte)(dLen & 0xFF); - } - - public byte[] getBuffer() { - return buf; - } - - public int getLen() { - return len; - } - - // ============ Data Writing Methods =================== - - /** - * Add an int. - * - * @param val The integer to write. - */ - public void appendInt( int val ) { - buf[pos++] = (byte) ((val >>> 8) & 0xFF); - buf[pos++] = (byte) (val & 0xFF); - } - - public void appendByte( int val ) { - buf[pos++] = (byte)val; - } - - public void appendLongInt( int val ) { - buf[pos++] = (byte) ((val >>> 24) & 0xFF); - buf[pos++] = (byte) ((val >>> 16) & 0xFF); - buf[pos++] = (byte) ((val >>> 8) & 0xFF); - buf[pos++] = (byte) (val & 0xFF); - } - - /** - * Write a String out at the current write position. Strings are - * encoded with the length in two bytes first, then the string, and - * then a terminating \0 (which is not included in the - * encoded length). The terminator is for the convenience of the C - * code, where it saves a round of copying. A null string is - * encoded as a string with length 0. - */ - public void appendBytes(MessageBytes mb) throws IOException { - if(mb==null || mb.isNull() ) { - appendInt( 0); - appendByte(0); - return; - } - - // XXX Convert !! - ByteChunk bc= mb.getByteChunk(); - appendByteChunk(bc); - } - - public void appendByteChunk(ByteChunk bc) throws IOException { - if(bc==null) { - log.error("appendByteChunk() null"); - appendInt( 0); - appendByte(0); - return; - } - - byte[] bytes = bc.getBytes(); - int start=bc.getStart(); - appendInt( bc.getLength() ); - cpBytes(bytes, start, bc.getLength()); - appendByte(0); - } - - /** - * Copy a chunk of bytes into the packet, starting at the current - * write position. The chunk of bytes is encoded with the length - * in two bytes first, then the data itself, and finally a - * terminating \0 (which is not included in the encoded - * length). - * - * @param b The array from which to copy bytes. - * @param off The offset into the array at which to start copying - * @param numBytes The number of bytes to copy. - */ - public void appendBytes( byte b[], int off, int numBytes ) { - appendInt( numBytes ); - cpBytes( b, off, numBytes ); - appendByte(0); - } - - private void cpBytes( byte b[], int off, int numBytes ) { - if( pos + numBytes >= buf.length ) { - log.error("Buffer overflow: buffer.len=" + buf.length + " pos=" + - pos + " data=" + numBytes ); - dump("Overflow/coBytes"); - log.error( "Overflow ", new Throwable()); - return; - } - System.arraycopy( b, off, buf, pos, numBytes); - pos += numBytes; - // buf[pos + numBytes] = 0; // Terminating \0 - } - - - - // ============ Data Reading Methods =================== - - /** - * Read an integer from packet, and advance the read position past - * it. Integers are encoded as two unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public int getInt() { - int b1 = buf[pos++] & 0xFF; // No swap, Java order - int b2 = buf[pos++] & 0xFF; - - return (b1<<8) + b2; - } - - public int peekInt() { - int b1 = buf[pos] & 0xFF; // No swap, Java order - int b2 = buf[pos+1] & 0xFF; - - return (b1<<8) + b2; - } - - public byte getByte() { - byte res = buf[pos++]; - return res; - } - - public byte peekByte() { - byte res = buf[pos]; - return res; - } - - public void getBytes(MessageBytes mb) { - int length = getInt(); - if( (length == 0xFFFF) || (length == -1) ) { - mb.recycle(); - return; - } - mb.setBytes( buf, pos, length ); - pos += length; - pos++; // Skip the terminating \0 - } - - /** - * Copy a chunk of bytes from the packet into an array and advance - * the read position past the chunk. See appendBytes() for details - * on the encoding. - * - * @return The number of bytes copied. - */ - public int getBytes(byte dest[]) { - int length = getInt(); - if( length > buf.length ) { - // XXX Should be if(pos + length > buff.legth)? - log.error("getBytes() buffer overflow " + length + " " + buf.length ); - } - - if( (length == 0xFFFF) || (length == -1) ) { - log.info("Null string " + length); - return 0; - } - - System.arraycopy( buf, pos, dest, 0, length ); - pos += length; - pos++; // Skip terminating \0 XXX I believe this is wrong but harmless - return length; - } - - /** - * Read a 32 bits integer from packet, and advance the read position past - * it. Integers are encoded as four unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public int getLongInt() { - int b1 = buf[pos++] & 0xFF; // No swap, Java order - b1 <<= 8; - b1 |= (buf[pos++] & 0xFF); - b1 <<= 8; - b1 |= (buf[pos++] & 0xFF); - b1 <<=8; - b1 |= (buf[pos++] & 0xFF); - return b1; - } - - public int getHeaderLength() { - return 4; - } - - public int processHeader() { - pos = 0; - int mark = getInt(); - len = getInt(); - - if( mark != 0x1234 && mark != 0x4142 ) { - // XXX Logging - log.error("BAD packet signature " + mark); - dump( "In: " ); - return -1; - } - - if( log.isDebugEnabled() ) - log.debug( "Received " + len + " " + buf[0] ); - return len; - } - - public void dump(String msg) { - if( log.isDebugEnabled() ) - log.debug( msg + ": " + buf + " " + pos +"/" + (len + 4)); - int max=pos; - if( len + 4 > pos ) - max=len+4; - if( max >1000 ) max=1000; - if( log.isDebugEnabled() ) - for( int j=0; j < max; j+=16 ) - log.debug( hexLine( buf, j, len )); - - } - - /* -------------------- Utilities -------------------- */ - // XXX Move to util package - - public static String hexLine( byte buf[], int start, int len ) { - StringBuffer sb=new StringBuffer(); - for( int i=start; i< start+16 ; i++ ) { - if( i < len + 4) - sb.append( hex( buf[i] ) + " "); - else - sb.append( " " ); - } - sb.append(" | "); - for( int i=start; i < start+16 && i < len + 4; i++ ) { - if( ! Character.isISOControl( (char)buf[i] )) - sb.append( new Character((char)buf[i]) ); - else - sb.append( "." ); - } - return sb.toString(); - } - - private static String hex( int x ) { - // if( x < 0) x=256 + x; - String h=Integer.toHexString( x ); - if( h.length() == 1 ) h = "0" + h; - return h.substring( h.length() - 2 ); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.common; + +import java.io.IOException; + +import org.apache.jk.core.Msg; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * A single packet for communication between the web server and the + * container. Designed to be reused many times with no creation of + * garbage. Understands the format of data types for these packets. + * Can be used (somewhat confusingly) for both incoming and outgoing + * packets. + * + * See Ajp14/Ajp13Packet.java. + * + * @author Henri Gomez [hgomez@apache.org] + * @author Dan Milstein [danmil@shore.net] + * @author Keith Wannamaker [Keith@Wannamaker.org] + * @author Kevin Seguin + * @author Costin Manolache + */ +public class MsgAjp extends Msg { + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( MsgAjp.class ); + + // that's the original buffer size in ajp13 - otherwise we'll get interoperability problems. + private byte buf[]=new byte[8*1024]; + // The current read or write position in the buffer + private int pos; + /** + * This actually means different things depending on whether the + * packet is read or write. For read, it's the length of the + * payload (excluding the header). For write, it's the length of + * the packet as a whole (counting the header). Oh, well. + */ + private int len; + + + + + /** + * Prepare this packet for accumulating a message from the container to + * the web server. Set the write position to just after the header + * (but leave the length unwritten, because it is as yet unknown). + */ + public void reset() { + len = 4; + pos = 4; + } + + /** + * For a packet to be sent to the web server, finish the process of + * accumulating data and write the length of the data payload into + * the header. + */ + public void end() { + len=pos; + int dLen=len-4; + + buf[0] = (byte)0x41; + buf[1] = (byte)0x42; + buf[2]= (byte)((dLen>>>8 ) & 0xFF ); + buf[3] = (byte)(dLen & 0xFF); + } + + public byte[] getBuffer() { + return buf; + } + + public int getLen() { + return len; + } + + // ============ Data Writing Methods =================== + + /** + * Add an int. + * + * @param val The integer to write. + */ + public void appendInt( int val ) { + buf[pos++] = (byte) ((val >>> 8) & 0xFF); + buf[pos++] = (byte) (val & 0xFF); + } + + public void appendByte( int val ) { + buf[pos++] = (byte)val; + } + + public void appendLongInt( int val ) { + buf[pos++] = (byte) ((val >>> 24) & 0xFF); + buf[pos++] = (byte) ((val >>> 16) & 0xFF); + buf[pos++] = (byte) ((val >>> 8) & 0xFF); + buf[pos++] = (byte) (val & 0xFF); + } + + /** + * Write a String out at the current write position. Strings are + * encoded with the length in two bytes first, then the string, and + * then a terminating \0 (which is not included in the + * encoded length). The terminator is for the convenience of the C + * code, where it saves a round of copying. A null string is + * encoded as a string with length 0. + */ + public void appendBytes(MessageBytes mb) throws IOException { + if(mb==null || mb.isNull() ) { + appendInt( 0); + appendByte(0); + return; + } + + // XXX Convert !! + ByteChunk bc= mb.getByteChunk(); + appendByteChunk(bc); + } + + public void appendByteChunk(ByteChunk bc) throws IOException { + if(bc==null) { + log.error("appendByteChunk() null"); + appendInt( 0); + appendByte(0); + return; + } + + byte[] bytes = bc.getBytes(); + int start=bc.getStart(); + appendInt( bc.getLength() ); + cpBytes(bytes, start, bc.getLength()); + appendByte(0); + } + + /** + * Copy a chunk of bytes into the packet, starting at the current + * write position. The chunk of bytes is encoded with the length + * in two bytes first, then the data itself, and finally a + * terminating \0 (which is not included in the encoded + * length). + * + * @param b The array from which to copy bytes. + * @param off The offset into the array at which to start copying + * @param numBytes The number of bytes to copy. + */ + public void appendBytes( byte b[], int off, int numBytes ) { + appendInt( numBytes ); + cpBytes( b, off, numBytes ); + appendByte(0); + } + + private void cpBytes( byte b[], int off, int numBytes ) { + if( pos + numBytes >= buf.length ) { + log.error("Buffer overflow: buffer.len=" + buf.length + " pos=" + + pos + " data=" + numBytes ); + dump("Overflow/coBytes"); + log.error( "Overflow ", new Throwable()); + return; + } + System.arraycopy( b, off, buf, pos, numBytes); + pos += numBytes; + // buf[pos + numBytes] = 0; // Terminating \0 + } + + + + // ============ Data Reading Methods =================== + + /** + * Read an integer from packet, and advance the read position past + * it. Integers are encoded as two unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public int getInt() { + int b1 = buf[pos++] & 0xFF; // No swap, Java order + int b2 = buf[pos++] & 0xFF; + + return (b1<<8) + b2; + } + + public int peekInt() { + int b1 = buf[pos] & 0xFF; // No swap, Java order + int b2 = buf[pos+1] & 0xFF; + + return (b1<<8) + b2; + } + + public byte getByte() { + byte res = buf[pos++]; + return res; + } + + public byte peekByte() { + byte res = buf[pos]; + return res; + } + + public void getBytes(MessageBytes mb) { + int length = getInt(); + if( (length == 0xFFFF) || (length == -1) ) { + mb.recycle(); + return; + } + mb.setBytes( buf, pos, length ); + pos += length; + pos++; // Skip the terminating \0 + } + + /** + * Copy a chunk of bytes from the packet into an array and advance + * the read position past the chunk. See appendBytes() for details + * on the encoding. + * + * @return The number of bytes copied. + */ + public int getBytes(byte dest[]) { + int length = getInt(); + if( length > buf.length ) { + // XXX Should be if(pos + length > buff.legth)? + log.error("getBytes() buffer overflow " + length + " " + buf.length ); + } + + if( (length == 0xFFFF) || (length == -1) ) { + log.info("Null string " + length); + return 0; + } + + System.arraycopy( buf, pos, dest, 0, length ); + pos += length; + pos++; // Skip terminating \0 XXX I believe this is wrong but harmless + return length; + } + + /** + * Read a 32 bits integer from packet, and advance the read position past + * it. Integers are encoded as four unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public int getLongInt() { + int b1 = buf[pos++] & 0xFF; // No swap, Java order + b1 <<= 8; + b1 |= (buf[pos++] & 0xFF); + b1 <<= 8; + b1 |= (buf[pos++] & 0xFF); + b1 <<=8; + b1 |= (buf[pos++] & 0xFF); + return b1; + } + + public int getHeaderLength() { + return 4; + } + + public int processHeader() { + pos = 0; + int mark = getInt(); + len = getInt(); + + if( mark != 0x1234 && mark != 0x4142 ) { + // XXX Logging + log.error("BAD packet signature " + mark); + dump( "In: " ); + return -1; + } + + if( log.isDebugEnabled() ) + log.debug( "Received " + len + " " + buf[0] ); + return len; + } + + public void dump(String msg) { + if( log.isDebugEnabled() ) + log.debug( msg + ": " + buf + " " + pos +"/" + (len + 4)); + int max=pos; + if( len + 4 > pos ) + max=len+4; + if( max >1000 ) max=1000; + if( log.isDebugEnabled() ) + for( int j=0; j < max; j+=16 ) + log.debug( hexLine( buf, j, len )); + + } + + /* -------------------- Utilities -------------------- */ + // XXX Move to util package + + public static String hexLine( byte buf[], int start, int len ) { + StringBuffer sb=new StringBuffer(); + for( int i=start; i< start+16 ; i++ ) { + if( i < len + 4) + sb.append( hex( buf[i] ) + " "); + else + sb.append( " " ); + } + sb.append(" | "); + for( int i=start; i < start+16 && i < len + 4; i++ ) { + if( ! Character.isISOControl( (char)buf[i] )) + sb.append( new Character((char)buf[i]) ); + else + sb.append( "." ); + } + return sb.toString(); + } + + private static String hex( int x ) { + // if( x < 0) x=256 + x; + String h=Integer.toHexString( x ); + if( h.length() == 1 ) h = "0" + h; + return h.substring( h.length() - 2 ); + } + +} diff --git a/java/org/apache/jk/common/Shm.java b/java/org/apache/jk/common/Shm.java index 2cb8d0fdc..7571b9647 100644 --- a/java/org/apache/jk/common/Shm.java +++ b/java/org/apache/jk/common/Shm.java @@ -1,330 +1,330 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.common; - -import java.io.IOException; -import java.util.Vector; - -import org.apache.jk.apr.AprImpl; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.WorkerEnv; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.buf.C2BConverter; - -/* The code is a bit confusing at this moment - the class is used as - a Bean, or ant Task, or CLI - i.e. you set properties and call execute. - - That's different from the rest of jk handlers wich are stateless ( but - similar with Coyote-http ). -*/ - - -/** Handle the shared memory objects. - * - * @author Costin Manolache - */ -public class Shm extends JniHandler { - String file="/tmp/shm.file"; - int size; - String host="localhost"; - int port=8009; - String unixSocket; - - boolean help=false; - boolean unregister=false; - boolean reset=false; - String dumpFile=null; - - Vector groups=new Vector(); - - // Will be dynamic ( getMethodId() ) after things are stable - static final int SHM_WRITE_SLOT=2; - static final int SHM_RESET=5; - static final int SHM_DUMP=6; - - public Shm() { - } - - /** Scoreboard location - */ - public void setFile( String f ) { - file=f; - } - - /** Copy the scoreboard in a file for debugging - * Will also log a lot of information about what's in the scoreboard. - */ - public void setDump( String dumpFile ) { - this.dumpFile=dumpFile; - } - - /** Size. Used only if the scoreboard is to be created. - */ - public void setSize( int size ) { - this.size=size; - } - - /** Set this to get the scoreboard reset. - * The shm segment will be destroyed and a new one created, - * with the provided size. - * - * Requires "file" and "size". - */ - public void setReset(boolean b) { - reset=true; - } - - /** Ajp13 host - */ - public void setHost( String host ) { - this.host=host; - } - - /** Mark this instance as belonging to a group - */ - public void setGroup( String grp ) { - groups.addElement( grp ); - } - - /** Ajp13 port - */ - public void setPort( int port ) { - this.port=port; - } - - /** Unix socket where tomcat is listening. - * Use it only if tomcat is on the same host, of course - */ - public void setUnixSocket( String unixSocket ) { - this.unixSocket=unixSocket; - } - - /** Set this option to mark the tomcat instance as - 'down', so apache will no longer forward messages to it. - Note that requests with a session will still try this - host first. - - This can be used to implement gracefull shutdown. - - Host and port are still required, since they are used - to identify tomcat. - */ - public void setUnregister( boolean unregister ) { - this.unregister=true; - } - - public void init() throws IOException { - super.initNative( "shm" ); - if( apr==null ) return; - if( file==null ) { - log.error("No shm file, disabling shared memory"); - apr=null; - return; - } - - // Set properties and call init. - setNativeAttribute( "file", file ); - if( size > 0 ) - setNativeAttribute( "size", Integer.toString( size ) ); - - initJkComponent(); - } - - public void resetScoreboard() throws IOException { - if( apr==null ) return; - MsgContext mCtx=createMsgContext(); - Msg msg=(Msg)mCtx.getMsg(0); - msg.reset(); - - msg.appendByte( SHM_RESET ); - - this.invoke( msg, mCtx ); - } - - public void dumpScoreboard(String fname) throws IOException { - if( apr==null ) return; - MsgContext mCtx=createMsgContext(); - Msg msg=(Msg)mCtx.getMsg(0); - C2BConverter c2b=mCtx.getConverter(); - msg.reset(); - - msg.appendByte( SHM_DUMP ); - - appendString( msg, fname, c2b); - - this.invoke( msg, mCtx ); - } - - /** Register a tomcat instance - * XXX make it more flexible - */ - public void registerTomcat(String host, int port, String unixDomain) - throws IOException - { - String instanceId=host+":" + port; - - String slotName="TOMCAT:" + instanceId; - MsgContext mCtx=createMsgContext(); - Msg msg=(Msg)mCtx.getMsg(0); - msg.reset(); - C2BConverter c2b=mCtx.getConverter(); - - msg.appendByte( SHM_WRITE_SLOT ); - appendString( msg, slotName, c2b ); - - int channelCnt=1; - if( unixDomain != null ) channelCnt++; - - // number of groups. 0 means the default lb. - msg.appendInt( groups.size() ); - for( int i=0; i 0 ) + setNativeAttribute( "size", Integer.toString( size ) ); + + initJkComponent(); + } + + public void resetScoreboard() throws IOException { + if( apr==null ) return; + MsgContext mCtx=createMsgContext(); + Msg msg=(Msg)mCtx.getMsg(0); + msg.reset(); + + msg.appendByte( SHM_RESET ); + + this.invoke( msg, mCtx ); + } + + public void dumpScoreboard(String fname) throws IOException { + if( apr==null ) return; + MsgContext mCtx=createMsgContext(); + Msg msg=(Msg)mCtx.getMsg(0); + C2BConverter c2b=mCtx.getConverter(); + msg.reset(); + + msg.appendByte( SHM_DUMP ); + + appendString( msg, fname, c2b); + + this.invoke( msg, mCtx ); + } + + /** Register a tomcat instance + * XXX make it more flexible + */ + public void registerTomcat(String host, int port, String unixDomain) + throws IOException + { + String instanceId=host+":" + port; + + String slotName="TOMCAT:" + instanceId; + MsgContext mCtx=createMsgContext(); + Msg msg=(Msg)mCtx.getMsg(0); + msg.reset(); + C2BConverter c2b=mCtx.getConverter(); + + msg.appendByte( SHM_WRITE_SLOT ); + appendString( msg, slotName, c2b ); + + int channelCnt=1; + if( unixDomain != null ) channelCnt++; + + // number of groups. 0 means the default lb. + msg.appendInt( groups.size() ); + for( int i=0; i - This config interceptor is enabled by inserting an ApacheConfig - Listener in - the server.xml file like so: -

        -    * < Server ... >
        -    *   ...
        -    *   org.apache.ajp.tomcat4.config.ApacheConfig 
        -    *       options />
        -    *   ...
        -    * < /Server >
        -    
        - where options can include any of the following attributes: -
          -
        • configHome - default parent directory for the following paths. - If not set, this defaults to TOMCAT_HOME. Ignored - whenever any of the following paths is absolute. -
        • -
        • jkConfig - path to use for writing Apache mod_jk conf file. If - not set, defaults to - "conf/auto/mod_jk.conf".
        • -
        • workersConfig - path to workers.properties file used by - mod_jk. If not set, defaults to - "conf/jk/workers.properties".
        • -
        • modJk - path to Apache mod_jk plugin file. If not set, - defaults to "modules/mod_jk.dll" on windows, - "modules/mod_jk.nlm" on netware, and - "libexec/mod_jk.so" everywhere else.
        • -
        • jkLog - path to log file to be used by mod_jk.
        • -
        • jkDebug - JK Loglevel setting. May be debug, info, error, or emerg. - If not set, defaults to emerg.
        • -
        • jkWorker The desired worker. Must be set to one of the workers - defined in the workers.properties file. "ajp12", "ajp13" - or "inprocess" are the workers found in the default - workers.properties file. If not specified, defaults - to "ajp13" if an Ajp13Interceptor is in use, otherwise - it defaults to "ajp12".
        • -
        • forwardAll - If true, forward all requests to Tomcat. This helps - insure that all the behavior configured in the web.xml - file functions correctly. If false, let Apache serve - static resources. The default is true. - Warning: When false, some configuration in - the web.xml may not be duplicated in Apache. - Review the mod_jk conf file to see what - configuration is actually being set in Apache.
        • -
        • noRoot - If true, the root context is not mapped to - Tomcat. If false and forwardAll is true, all requests - to the root context are mapped to Tomcat. If false and - forwardAll is false, only JSP and servlets requests to - the root context are mapped to Tomcat. When false, - to correctly serve Tomcat's root context you must also - modify the DocumentRoot setting in Apache's httpd.conf - file to point to Tomcat's root context directory. - Otherwise some content, such as Apache's index.html, - will be served by Apache before mod_jk gets a chance - to claim the request and pass it to Tomcat. - The default is true.
        • -
        -

        - @author Costin Manolache - @author Larry Isaacs - @author Mel Martinez - @author Bill Barker - */ -public class ApacheConfig extends BaseJkConfig { - - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(ApacheConfig.class); - - /** default path to mod_jk .conf location */ - public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf"; - /** default path to workers.properties file - This should be also auto-generated from server.xml. - */ - public static final String WORKERS_CONFIG = "conf/jk/workers.properties"; - /** default mod_jk log file location */ - public static final String JK_LOG_LOCATION = "logs/mod_jk.log"; - /** default location of mod_jk Apache plug-in. */ - public static final String MOD_JK; - - //set up some defaults based on OS type - static{ - String os = System.getProperty("os.name").toLowerCase(); - if(os.indexOf("windows")>=0){ - MOD_JK = "modules/mod_jk.dll"; - }else if(os.indexOf("netware")>=0){ - MOD_JK = "modules/mod_jk.nlm"; - }else{ - MOD_JK = "libexec/mod_jk.so"; - } - } - - private File jkConfig = null; - private File modJk = null; - - // ssl settings - private boolean sslExtract=true; - private String sslHttpsIndicator="HTTPS"; - private String sslSessionIndicator="SSL_SESSION_ID"; - private String sslCipherIndicator="SSL_CIPHER"; - private String sslCertsIndicator="SSL_CLIENT_CERT"; - - Hashtable NamedVirtualHosts=null; - - public ApacheConfig() { - } - - //-------------------- Properties -------------------- - - /** - set the path to the output file for the auto-generated - mod_jk configuration file. If this path is relative - then it will be resolved absolutely against - the getConfigHome() path. -

        - @param path String path to a file - */ - public void setJkConfig(String path){ - jkConfig= (path==null)?null:new File(path); - } - - /** - set the path to the mod_jk Apache Module - @param path String path to a file - */ - public void setModJk(String path){ - modJk=( path==null?null:new File(path)); - } - - /** By default mod_jk is configured to collect SSL information from - the apache environment and send it to the Tomcat workers. The - problem is that there are many SSL solutions for Apache and as - a result the environment variable names may change. - - The following JK related SSL configureation - can be used to customize mod_jk's SSL behaviour. - - Should mod_jk send SSL information to Tomact (default is On) - */ - public void setExtractSSL( boolean sslMode ) { - this.sslExtract=sslMode; - } - - /** What is the indicator for SSL (default is HTTPS) - */ - public void setHttpsIndicator( String s ) { - sslHttpsIndicator=s; - } - - /**What is the indicator for SSL session (default is SSL_SESSION_ID) - */ - public void setSessionIndicator( String s ) { - sslSessionIndicator=s; - } - - /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER) - */ - public void setCipherIndicator( String s ) { - sslCipherIndicator=s; - } - - /** What is the indicator for the client SSL certificated(default - is SSL_CLIENT_CERT - */ - public void setCertsIndicator( String s ) { - sslCertsIndicator=s; - } - - // -------------------- Initialize/guess defaults -------------------- - - /** Initialize defaults for properties that are not set - explicitely - */ - protected void initProperties() { - super.initProperties(); - - jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG); - workersConfig=getConfigFile( workersConfig, configHome, - WORKERS_CONFIG); - if( modJk == null ) - modJk=new File(MOD_JK); - else - modJk=getConfigFile( modJk, configHome, MOD_JK ); - jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION); - } - // -------------------- Generate config -------------------- - - protected PrintWriter getWriter() throws IOException { - String abJkConfig = jkConfig.getAbsolutePath(); - return new PrintWriter(new FileWriter(abJkConfig, append)); - } - - - // -------------------- Config sections -------------------- - - /** Generate the loadModule and general options - */ - protected boolean generateJkHead(PrintWriter mod_jk) - { - - mod_jk.println("########## Auto generated on " + new Date() + - "##########" ); - mod_jk.println(); - - // Fail if mod_jk not found, let the user know the problem - // instead of running into problems later. - if( ! modJk.exists() ) { - log.info( "mod_jk location: " + modJk ); - log.info( "Make sure it is installed corectly or " + - " set the config location" ); - log.info( "Using " ); - } - - // Verify the file exists !! - mod_jk.println(""); - mod_jk.println(" LoadModule jk_module \""+ - modJk.toString().replace('\\','/') + - "\""); - mod_jk.println(""); - mod_jk.println(); - - - // Fail if workers file not found, let the user know the problem - // instead of running into problems later. - if( ! workersConfig.exists() ) { - log.warn( "Can't find workers.properties at " + workersConfig ); - log.warn( "Please install it in the default location or " + - " set the config location" ); - log.warn( "Using " ); - return false; - } - - mod_jk.println("JkWorkersFile \"" - + workersConfig.toString().replace('\\', '/') - + "\""); - - mod_jk.println("JkLogFile \"" - + jkLog.toString().replace('\\', '/') - + "\""); - mod_jk.println(); - - if( jkDebug != null ) { - mod_jk.println("JkLogLevel " + jkDebug); - mod_jk.println(); - } - return true; - } - - protected void generateVhostHead(Host host, PrintWriter mod_jk) { - - mod_jk.println(); - String vhostip = host.getName(); - String vhost = vhostip; - int ppos = vhost.indexOf(":"); - if(ppos >= 0) - vhost = vhost.substring(0,ppos); - - mod_jk.println(""); - mod_jk.println(" ServerName " + vhost ); - String [] aliases=host.findAliases(); - if( aliases.length > 0 ) { - mod_jk.print(" ServerAlias " ); - for( int ii=0; ii < aliases.length ; ii++) { - mod_jk.print( aliases[ii] + " " ); - } - mod_jk.println(); - } - indent=" "; - } - - protected void generateVhostTail(Host host, PrintWriter mod_jk) { - mod_jk.println(""); - indent=""; - } - - protected void generateSSLConfig(PrintWriter mod_jk) { - if( ! sslExtract ) { - mod_jk.println("JkExtractSSL Off"); - } - if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) { - mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator); - } - if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) { - mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator); - } - if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) { - mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator); - } - if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) { - mod_jk.println("JkCERTSIndicator " + sslCertsIndicator); - } - - mod_jk.println(); - } - - // -------------------- Forward all mode -------------------- - String indent=""; - - /** Forward all requests for a context to tomcat. - The default. - */ - protected void generateStupidMappings(Context context, - PrintWriter mod_jk ) - { - String ctxPath = context.getPath(); - if(ctxPath == null) - return; - - String nPath=("".equals(ctxPath)) ? "/" : ctxPath; - - mod_jk.println(); - mod_jk.println(indent + "JkMount " + nPath + " " + jkWorker ); - if( "".equals(ctxPath) ) { - mod_jk.println(indent + "JkMount " + nPath + "* " + jkWorker ); - if ( context.getParent() instanceof Host ) { - mod_jk.println(indent + "DocumentRoot \"" + - getApacheDocBase(context) + "\""); - } else { - mod_jk.println(indent + - "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot"); - mod_jk.println(indent + - "# to point to: \"" + getApacheDocBase(context) + "\""); - } - - } else { - mod_jk.println(indent + "JkMount " + nPath + "/* " + jkWorker ); - } - } - - - private void generateNameVirtualHost( PrintWriter mod_jk, String ip ) { - if( !NamedVirtualHosts.containsKey(ip) ) { - mod_jk.println("NameVirtualHost " + ip + ""); - NamedVirtualHosts.put(ip,ip); - } - } - - // -------------------- Apache serves static mode -------------------- - // This is not going to work for all apps. We fall back to stupid mode. - - protected void generateContextMappings(Context context, PrintWriter mod_jk ) - { - String ctxPath = context.getPath(); - Host vhost = getHost(context); - - if( noRoot && "".equals(ctxPath) ) { - log.debug("Ignoring root context in non-forward-all mode "); - return; - } - - mod_jk.println(); - mod_jk.println(indent + "#################### " + - ((vhost!=null ) ? vhost.getName() + ":" : "" ) + - (("".equals(ctxPath)) ? "/" : ctxPath ) + - " ####################" ); - mod_jk.println(); - // Dynamic /servet pages go to Tomcat - - generateStaticMappings( context, mod_jk ); - - // InvokerInterceptor - it doesn't have a container, - // but it's implemented using a special module. - - // XXX we need to better collect all mappings - - if(context.getLoginConfig() != null) { - String loginPage = context.getLoginConfig().getLoginPage(); - if(loginPage != null) { - int lpos = loginPage.lastIndexOf("/"); - String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; - addMapping( ctxPath, jscurl, mod_jk); - } - } - String [] servletMaps = context.findServletMappings(); - for(int ii=0; ii < servletMaps.length; ii++) { - addMapping( ctxPath, servletMaps[ii] , mod_jk ); - } - } - - /** Add an Apache extension mapping. - */ - protected boolean addExtensionMapping( String ctxPath, String ext, - PrintWriter mod_jk ) - { - if( log.isDebugEnabled() ) - log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); - mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext - + " " + jkWorker); - return true; - } - - - /** Add a fulling specified Appache mapping. - */ - protected boolean addMapping( String fullPath, PrintWriter mod_jk ) { - if( log.isDebugEnabled() ) - log.debug( "Adding map for " + fullPath ); - mod_jk.println(indent + "JkMount " + fullPath + " " + jkWorker ); - return true; - } - /** Add a partially specified Appache mapping. - */ - protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) { - if( log.isDebugEnabled() ) - log.debug( "Adding map for " + ext ); - if(! ext.startsWith("/") ) - ext = "/" + ext; - if(ext.length() > 1) - mod_jk.println(indent + "JkMount " + ctxP + ext+ " " + jkWorker ); - return true; - } - - private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) { - String wf[]=context.findWelcomeFiles(); - if( wf==null || wf.length == 0 ) - return; - mod_jk.print(indent + " DirectoryIndex "); - for( int i=0; i"); - mod_jk.println(indent + " Options Indexes FollowSymLinks"); - - generateWelcomeFiles(context, mod_jk); - - // XXX XXX Here goes the Mime types and welcome files !!!!!!!! - mod_jk.println(indent + ""); - mod_jk.println(); - - - // Deny serving any files from WEB-INF - mod_jk.println(); - mod_jk.println(indent + - "# Deny direct access to WEB-INF and META-INF"); - mod_jk.println(indent + "#"); - mod_jk.println(indent + ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - // Deny serving any files from META-INF - mod_jk.println(); - mod_jk.println(indent + ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - if (File.separatorChar == '\\') { - mod_jk.println(indent + "#"); - mod_jk.println(indent + - "# Use Directory too. On Windows, Location doesn't" - + " work unless case matches"); - mod_jk.println(indent + "#"); - mod_jk.println(indent + - ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - mod_jk.println(); - mod_jk.println(indent + - ""); - mod_jk.println(indent + " AllowOverride None"); - mod_jk.println(indent + " deny from all"); - mod_jk.println(indent + ""); - } - mod_jk.println(); - } - - // -------------------- Utils -------------------- - - private String getApacheDocBase(Context context) - { - // Calculate the absolute path of the document base - String docBase = getAbsoluteDocBase(context); - if (File.separatorChar == '\\') { - // use separator preferred by Apache - docBase = docBase.replace('\\','/'); - } - return docBase; - } - - private String getVirtualHostAddress(String vhost, String vhostip) { - if( vhostip == null ) { - if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) ) - vhostip=vhost; - else - vhostip="*"; - } - return vhostip; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; +import java.util.Hashtable; + +import org.apache.catalina.Context; +import org.apache.catalina.Host; + +/* The idea is to keep all configuration in server.xml and + the normal apache config files. We don't want people to + touch apache ( or IIS, NES ) config files unless they + want to and know what they're doing ( better than we do :-). + + One nice feature ( if someone sends it ) would be to + also edit httpd.conf to add the include. + + We'll generate a number of configuration files - this one + is trying to generate a native apache config file. + + Some web.xml mappings do not "map" to server configuration - in + this case we need to fallback to forward all requests to tomcat. + + Ajp14 will add to that the posibility to have tomcat and + apache on different machines, and many other improvements - + but this should also work for Ajp12, Ajp13 and Jni. + +*/ + +/** + Generates automatic apache mod_jk configurations based on + the Tomcat server.xml settings and the war contexts + initialized during startup. +

        + This config interceptor is enabled by inserting an ApacheConfig + Listener in + the server.xml file like so: +

        +    * < Server ... >
        +    *   ...
        +    *   org.apache.ajp.tomcat4.config.ApacheConfig 
        +    *       options />
        +    *   ...
        +    * < /Server >
        +    
        + where options can include any of the following attributes: +
          +
        • configHome - default parent directory for the following paths. + If not set, this defaults to TOMCAT_HOME. Ignored + whenever any of the following paths is absolute. +
        • +
        • jkConfig - path to use for writing Apache mod_jk conf file. If + not set, defaults to + "conf/auto/mod_jk.conf".
        • +
        • workersConfig - path to workers.properties file used by + mod_jk. If not set, defaults to + "conf/jk/workers.properties".
        • +
        • modJk - path to Apache mod_jk plugin file. If not set, + defaults to "modules/mod_jk.dll" on windows, + "modules/mod_jk.nlm" on netware, and + "libexec/mod_jk.so" everywhere else.
        • +
        • jkLog - path to log file to be used by mod_jk.
        • +
        • jkDebug - JK Loglevel setting. May be debug, info, error, or emerg. + If not set, defaults to emerg.
        • +
        • jkWorker The desired worker. Must be set to one of the workers + defined in the workers.properties file. "ajp12", "ajp13" + or "inprocess" are the workers found in the default + workers.properties file. If not specified, defaults + to "ajp13" if an Ajp13Interceptor is in use, otherwise + it defaults to "ajp12".
        • +
        • forwardAll - If true, forward all requests to Tomcat. This helps + insure that all the behavior configured in the web.xml + file functions correctly. If false, let Apache serve + static resources. The default is true. + Warning: When false, some configuration in + the web.xml may not be duplicated in Apache. + Review the mod_jk conf file to see what + configuration is actually being set in Apache.
        • +
        • noRoot - If true, the root context is not mapped to + Tomcat. If false and forwardAll is true, all requests + to the root context are mapped to Tomcat. If false and + forwardAll is false, only JSP and servlets requests to + the root context are mapped to Tomcat. When false, + to correctly serve Tomcat's root context you must also + modify the DocumentRoot setting in Apache's httpd.conf + file to point to Tomcat's root context directory. + Otherwise some content, such as Apache's index.html, + will be served by Apache before mod_jk gets a chance + to claim the request and pass it to Tomcat. + The default is true.
        • +
        +

        + @author Costin Manolache + @author Larry Isaacs + @author Mel Martinez + @author Bill Barker + */ +public class ApacheConfig extends BaseJkConfig { + + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(ApacheConfig.class); + + /** default path to mod_jk .conf location */ + public static final String MOD_JK_CONFIG = "conf/auto/mod_jk.conf"; + /** default path to workers.properties file + This should be also auto-generated from server.xml. + */ + public static final String WORKERS_CONFIG = "conf/jk/workers.properties"; + /** default mod_jk log file location */ + public static final String JK_LOG_LOCATION = "logs/mod_jk.log"; + /** default location of mod_jk Apache plug-in. */ + public static final String MOD_JK; + + //set up some defaults based on OS type + static{ + String os = System.getProperty("os.name").toLowerCase(); + if(os.indexOf("windows")>=0){ + MOD_JK = "modules/mod_jk.dll"; + }else if(os.indexOf("netware")>=0){ + MOD_JK = "modules/mod_jk.nlm"; + }else{ + MOD_JK = "libexec/mod_jk.so"; + } + } + + private File jkConfig = null; + private File modJk = null; + + // ssl settings + private boolean sslExtract=true; + private String sslHttpsIndicator="HTTPS"; + private String sslSessionIndicator="SSL_SESSION_ID"; + private String sslCipherIndicator="SSL_CIPHER"; + private String sslCertsIndicator="SSL_CLIENT_CERT"; + + Hashtable NamedVirtualHosts=null; + + public ApacheConfig() { + } + + //-------------------- Properties -------------------- + + /** + set the path to the output file for the auto-generated + mod_jk configuration file. If this path is relative + then it will be resolved absolutely against + the getConfigHome() path. +

        + @param path String path to a file + */ + public void setJkConfig(String path){ + jkConfig= (path==null)?null:new File(path); + } + + /** + set the path to the mod_jk Apache Module + @param path String path to a file + */ + public void setModJk(String path){ + modJk=( path==null?null:new File(path)); + } + + /** By default mod_jk is configured to collect SSL information from + the apache environment and send it to the Tomcat workers. The + problem is that there are many SSL solutions for Apache and as + a result the environment variable names may change. + + The following JK related SSL configureation + can be used to customize mod_jk's SSL behaviour. + + Should mod_jk send SSL information to Tomact (default is On) + */ + public void setExtractSSL( boolean sslMode ) { + this.sslExtract=sslMode; + } + + /** What is the indicator for SSL (default is HTTPS) + */ + public void setHttpsIndicator( String s ) { + sslHttpsIndicator=s; + } + + /**What is the indicator for SSL session (default is SSL_SESSION_ID) + */ + public void setSessionIndicator( String s ) { + sslSessionIndicator=s; + } + + /**What is the indicator for client SSL cipher suit (default is SSL_CIPHER) + */ + public void setCipherIndicator( String s ) { + sslCipherIndicator=s; + } + + /** What is the indicator for the client SSL certificated(default + is SSL_CLIENT_CERT + */ + public void setCertsIndicator( String s ) { + sslCertsIndicator=s; + } + + // -------------------- Initialize/guess defaults -------------------- + + /** Initialize defaults for properties that are not set + explicitely + */ + protected void initProperties() { + super.initProperties(); + + jkConfig= getConfigFile( jkConfig, configHome, MOD_JK_CONFIG); + workersConfig=getConfigFile( workersConfig, configHome, + WORKERS_CONFIG); + if( modJk == null ) + modJk=new File(MOD_JK); + else + modJk=getConfigFile( modJk, configHome, MOD_JK ); + jkLog=getConfigFile( jkLog, configHome, JK_LOG_LOCATION); + } + // -------------------- Generate config -------------------- + + protected PrintWriter getWriter() throws IOException { + String abJkConfig = jkConfig.getAbsolutePath(); + return new PrintWriter(new FileWriter(abJkConfig, append)); + } + + + // -------------------- Config sections -------------------- + + /** Generate the loadModule and general options + */ + protected boolean generateJkHead(PrintWriter mod_jk) + { + + mod_jk.println("########## Auto generated on " + new Date() + + "##########" ); + mod_jk.println(); + + // Fail if mod_jk not found, let the user know the problem + // instead of running into problems later. + if( ! modJk.exists() ) { + log.info( "mod_jk location: " + modJk ); + log.info( "Make sure it is installed corectly or " + + " set the config location" ); + log.info( "Using " ); + } + + // Verify the file exists !! + mod_jk.println(""); + mod_jk.println(" LoadModule jk_module \""+ + modJk.toString().replace('\\','/') + + "\""); + mod_jk.println(""); + mod_jk.println(); + + + // Fail if workers file not found, let the user know the problem + // instead of running into problems later. + if( ! workersConfig.exists() ) { + log.warn( "Can't find workers.properties at " + workersConfig ); + log.warn( "Please install it in the default location or " + + " set the config location" ); + log.warn( "Using " ); + return false; + } + + mod_jk.println("JkWorkersFile \"" + + workersConfig.toString().replace('\\', '/') + + "\""); + + mod_jk.println("JkLogFile \"" + + jkLog.toString().replace('\\', '/') + + "\""); + mod_jk.println(); + + if( jkDebug != null ) { + mod_jk.println("JkLogLevel " + jkDebug); + mod_jk.println(); + } + return true; + } + + protected void generateVhostHead(Host host, PrintWriter mod_jk) { + + mod_jk.println(); + String vhostip = host.getName(); + String vhost = vhostip; + int ppos = vhost.indexOf(":"); + if(ppos >= 0) + vhost = vhost.substring(0,ppos); + + mod_jk.println(""); + mod_jk.println(" ServerName " + vhost ); + String [] aliases=host.findAliases(); + if( aliases.length > 0 ) { + mod_jk.print(" ServerAlias " ); + for( int ii=0; ii < aliases.length ; ii++) { + mod_jk.print( aliases[ii] + " " ); + } + mod_jk.println(); + } + indent=" "; + } + + protected void generateVhostTail(Host host, PrintWriter mod_jk) { + mod_jk.println(""); + indent=""; + } + + protected void generateSSLConfig(PrintWriter mod_jk) { + if( ! sslExtract ) { + mod_jk.println("JkExtractSSL Off"); + } + if( ! "HTTPS".equalsIgnoreCase( sslHttpsIndicator ) ) { + mod_jk.println("JkHTTPSIndicator " + sslHttpsIndicator); + } + if( ! "SSL_SESSION_ID".equalsIgnoreCase( sslSessionIndicator )) { + mod_jk.println("JkSESSIONIndicator " + sslSessionIndicator); + } + if( ! "SSL_CIPHER".equalsIgnoreCase( sslCipherIndicator )) { + mod_jk.println("JkCIPHERIndicator " + sslCipherIndicator); + } + if( ! "SSL_CLIENT_CERT".equalsIgnoreCase( sslCertsIndicator )) { + mod_jk.println("JkCERTSIndicator " + sslCertsIndicator); + } + + mod_jk.println(); + } + + // -------------------- Forward all mode -------------------- + String indent=""; + + /** Forward all requests for a context to tomcat. + The default. + */ + protected void generateStupidMappings(Context context, + PrintWriter mod_jk ) + { + String ctxPath = context.getPath(); + if(ctxPath == null) + return; + + String nPath=("".equals(ctxPath)) ? "/" : ctxPath; + + mod_jk.println(); + mod_jk.println(indent + "JkMount " + nPath + " " + jkWorker ); + if( "".equals(ctxPath) ) { + mod_jk.println(indent + "JkMount " + nPath + "* " + jkWorker ); + if ( context.getParent() instanceof Host ) { + mod_jk.println(indent + "DocumentRoot \"" + + getApacheDocBase(context) + "\""); + } else { + mod_jk.println(indent + + "# To avoid Apache serving root welcome files from htdocs, update DocumentRoot"); + mod_jk.println(indent + + "# to point to: \"" + getApacheDocBase(context) + "\""); + } + + } else { + mod_jk.println(indent + "JkMount " + nPath + "/* " + jkWorker ); + } + } + + + private void generateNameVirtualHost( PrintWriter mod_jk, String ip ) { + if( !NamedVirtualHosts.containsKey(ip) ) { + mod_jk.println("NameVirtualHost " + ip + ""); + NamedVirtualHosts.put(ip,ip); + } + } + + // -------------------- Apache serves static mode -------------------- + // This is not going to work for all apps. We fall back to stupid mode. + + protected void generateContextMappings(Context context, PrintWriter mod_jk ) + { + String ctxPath = context.getPath(); + Host vhost = getHost(context); + + if( noRoot && "".equals(ctxPath) ) { + log.debug("Ignoring root context in non-forward-all mode "); + return; + } + + mod_jk.println(); + mod_jk.println(indent + "#################### " + + ((vhost!=null ) ? vhost.getName() + ":" : "" ) + + (("".equals(ctxPath)) ? "/" : ctxPath ) + + " ####################" ); + mod_jk.println(); + // Dynamic /servet pages go to Tomcat + + generateStaticMappings( context, mod_jk ); + + // InvokerInterceptor - it doesn't have a container, + // but it's implemented using a special module. + + // XXX we need to better collect all mappings + + if(context.getLoginConfig() != null) { + String loginPage = context.getLoginConfig().getLoginPage(); + if(loginPage != null) { + int lpos = loginPage.lastIndexOf("/"); + String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; + addMapping( ctxPath, jscurl, mod_jk); + } + } + String [] servletMaps = context.findServletMappings(); + for(int ii=0; ii < servletMaps.length; ii++) { + addMapping( ctxPath, servletMaps[ii] , mod_jk ); + } + } + + /** Add an Apache extension mapping. + */ + protected boolean addExtensionMapping( String ctxPath, String ext, + PrintWriter mod_jk ) + { + if( log.isDebugEnabled() ) + log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); + mod_jk.println(indent + "JkMount " + ctxPath + "/*." + ext + + " " + jkWorker); + return true; + } + + + /** Add a fulling specified Appache mapping. + */ + protected boolean addMapping( String fullPath, PrintWriter mod_jk ) { + if( log.isDebugEnabled() ) + log.debug( "Adding map for " + fullPath ); + mod_jk.println(indent + "JkMount " + fullPath + " " + jkWorker ); + return true; + } + /** Add a partially specified Appache mapping. + */ + protected boolean addMapping( String ctxP, String ext, PrintWriter mod_jk ) { + if( log.isDebugEnabled() ) + log.debug( "Adding map for " + ext ); + if(! ext.startsWith("/") ) + ext = "/" + ext; + if(ext.length() > 1) + mod_jk.println(indent + "JkMount " + ctxP + ext+ " " + jkWorker ); + return true; + } + + private void generateWelcomeFiles(Context context, PrintWriter mod_jk ) { + String wf[]=context.findWelcomeFiles(); + if( wf==null || wf.length == 0 ) + return; + mod_jk.print(indent + " DirectoryIndex "); + for( int i=0; i"); + mod_jk.println(indent + " Options Indexes FollowSymLinks"); + + generateWelcomeFiles(context, mod_jk); + + // XXX XXX Here goes the Mime types and welcome files !!!!!!!! + mod_jk.println(indent + ""); + mod_jk.println(); + + + // Deny serving any files from WEB-INF + mod_jk.println(); + mod_jk.println(indent + + "# Deny direct access to WEB-INF and META-INF"); + mod_jk.println(indent + "#"); + mod_jk.println(indent + ""); + mod_jk.println(indent + " AllowOverride None"); + mod_jk.println(indent + " deny from all"); + mod_jk.println(indent + ""); + // Deny serving any files from META-INF + mod_jk.println(); + mod_jk.println(indent + ""); + mod_jk.println(indent + " AllowOverride None"); + mod_jk.println(indent + " deny from all"); + mod_jk.println(indent + ""); + if (File.separatorChar == '\\') { + mod_jk.println(indent + "#"); + mod_jk.println(indent + + "# Use Directory too. On Windows, Location doesn't" + + " work unless case matches"); + mod_jk.println(indent + "#"); + mod_jk.println(indent + + ""); + mod_jk.println(indent + " AllowOverride None"); + mod_jk.println(indent + " deny from all"); + mod_jk.println(indent + ""); + mod_jk.println(); + mod_jk.println(indent + + ""); + mod_jk.println(indent + " AllowOverride None"); + mod_jk.println(indent + " deny from all"); + mod_jk.println(indent + ""); + } + mod_jk.println(); + } + + // -------------------- Utils -------------------- + + private String getApacheDocBase(Context context) + { + // Calculate the absolute path of the document base + String docBase = getAbsoluteDocBase(context); + if (File.separatorChar == '\\') { + // use separator preferred by Apache + docBase = docBase.replace('\\','/'); + } + return docBase; + } + + private String getVirtualHostAddress(String vhost, String vhostip) { + if( vhostip == null ) { + if ( vhost != null && vhost.length() > 0 && Character.isDigit(vhost.charAt(0)) ) + vhostip=vhost; + else + vhostip="*"; + } + return vhostip; + } + +} diff --git a/java/org/apache/jk/config/BaseJkConfig.java b/java/org/apache/jk/config/BaseJkConfig.java index eda2ddadf..8cefe21e4 100644 --- a/java/org/apache/jk/config/BaseJkConfig.java +++ b/java/org/apache/jk/config/BaseJkConfig.java @@ -1,515 +1,515 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.config; - -import java.io.File; -import java.io.IOException; -import java.io.PrintWriter; - -import org.apache.catalina.Container; -import org.apache.catalina.Context; -import org.apache.catalina.Engine; -import org.apache.catalina.Host; -import org.apache.catalina.Lifecycle; -import org.apache.catalina.LifecycleEvent; -import org.apache.catalina.LifecycleListener; -import org.apache.catalina.Server; - - -/** - Base class for automatic jk based configurations based on - the Tomcat server.xml settings and the war contexts - initialized during startup. -

        - This config interceptor is enabled by inserting a Config - element in the <ContextManager> tag body inside - the server.xml file like so: -

        -    * < ContextManager ... >
        -    *   ...
        -    *   <???Config options />
        -    *   ...
        -    * < /ContextManager >
        -    
        - where options can include any of the following attributes: -
          -
        • configHome - default parent directory for the following paths. - If not set, this defaults to TOMCAT_HOME. Ignored - whenever any of the following paths is absolute. -
        • -
        • workersConfig - path to workers.properties file used by - jk connector. If not set, defaults to - "conf/jk/workers.properties".
        • -
        • jkLog - path to log file to be used by jk connector.
        • -
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. - If not set, defaults to emerg.
        • -
        • jkWorker The desired worker. Must be set to one of the workers - defined in the workers.properties file. "ajp12", "ajp13" - or "inprocess" are the workers found in the default - workers.properties file. If not specified, defaults - to "ajp13" if an Ajp13Interceptor is in use, otherwise - it defaults to "ajp12".
        • -
        • forwardAll - If true, forward all requests to Tomcat. This helps - insure that all the behavior configured in the web.xml - file functions correctly. If false, let Apache serve - static resources. The default is true. - Warning: When false, some configuration in - the web.xml may not be duplicated in Apache. - Review the mod_jk conf file to see what - configuration is actually being set in Apache.
        • -
        • noRoot - If true, the root context is not mapped to - Tomcat. If false and forwardAll is true, all requests - to the root context are mapped to Tomcat. If false and - forwardAll is false, only JSP and servlets requests to - the root context are mapped to Tomcat. When false, - to correctly serve Tomcat's root context you may also - need to modify the web server to point it's home - directory to Tomcat's root context directory. - Otherwise some content, such as the root index.html, - may be served by the web server before the connector - gets a chance to claim the request and pass it to Tomcat. - The default is true.
        • -
        -

        - @author Costin Manolache - @author Larry Isaacs - @author Bill Barker - @version $Revision: 299988 $ - */ -public class BaseJkConfig implements LifecycleListener { - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(BaseJkConfig.class); - - protected File configHome = null; - protected File workersConfig = null; - - protected File jkLog = null; - protected String jkDebug="emerg"; - protected String jkWorker = "ajp13"; - - protected boolean noRoot=true; - protected boolean forwardAll=true; - - protected String tomcatHome; - protected boolean regenerate=false; - protected boolean append=false; - protected boolean legacy=true; - - // -------------------- Tomcat callbacks -------------------- - - - // Auto-config should be able to react to dynamic config changes, - // and regenerate the config. - - /** - * Generate the configuration - only when the server is - * completely initialized ( before starting ) - */ - public void lifecycleEvent(LifecycleEvent evt) { - if(Lifecycle.START_EVENT.equals(evt.getType())) { - execute( evt ); - } - } - - /** - * Generate configuration files. Override with method to generate - * web server specific configuration. - */ - public void execute(LifecycleEvent evt) { - initProperties(); - PrintWriter mod_jk = null; - try { - mod_jk = getWriter(); - } catch(IOException iex) { - log.warn("Unable to open config file"); - return; - } - Lifecycle who = evt.getLifecycle(); - if( who instanceof Server ) { - executeServer((Server)who, mod_jk); - } else if(who instanceof Engine) { - executeEngine((Engine)who, mod_jk); - } else if ( who instanceof Host ) { - executeHost((Host)who, mod_jk); - } else if( who instanceof Context ) { - executeContext((Context)who, mod_jk); - } - mod_jk.close(); - } - /** - * Generate configuration files. Override with method to generate - * web server specific configuration. - */ - public void executeServer(Server svr, PrintWriter mod_jk) { - if(! append ) { - if( ! generateJkHead(mod_jk) ) - return; - generateSSLConfig(mod_jk); - generateJkTail(mod_jk); - } - } - - /** - * Generate SSL options - */ - protected void generateSSLConfig(PrintWriter mod_jk) { - } - - /** - * Generate general options - */ - protected boolean generateJkHead(PrintWriter mod_jk) { - return true; - } - - /** - * Generate general options - */ - protected void generateJkTail(PrintWriter mod_jk) { - } - - /** - * Generate Virtual Host start - */ - protected void generateVhostHead(Host host, PrintWriter mod_jk) { - } - - /** - * Generate Virtual Host end - */ - protected void generateVhostTail(Host host, PrintWriter mod_jk) { - } - - /** - * Generate configuration files. Override with method to generate - * web server specific configuration. - */ - protected void executeEngine(Engine egn, PrintWriter mod_jk) { - if(egn.getJvmRoute() != null) { - jkWorker = egn.getJvmRoute(); - } - executeServer(egn.getService().getServer(), mod_jk); - Container [] children = egn.findChildren(); - for(int ii=0; ii < children.length; ii++) { - if( children[ii] instanceof Host ) { - executeHost((Host)children[ii], mod_jk); - } else if( children[ii] instanceof Context ) { - executeContext((Context)children[ii], mod_jk); - } - } - } - /** - * Generate configuration files. Override with method to generate - * web server specific configuration. - */ - protected void executeHost(Host hst, PrintWriter mod_jk) { - generateVhostHead(hst, mod_jk); - Container [] children = hst.findChildren(); - for(int ii=0; ii < children.length; ii++) { - if(children[ii] instanceof Context) { - executeContext((Context)children[ii],mod_jk); - } - } - generateVhostTail(hst, mod_jk); - } - /** - * executes the ApacheConfig interceptor. This method generates apache - * configuration files for use with mod_jk. - * @param context a Context object. - * @param mod_jk Writer for output. - */ - public void executeContext(Context context, PrintWriter mod_jk){ - - if(context.getPath().length() > 0 || ! noRoot ) { - String docRoot = context.getServletContext().getRealPath("/"); - if( forwardAll || docRoot == null) - generateStupidMappings( context, mod_jk ); - else - generateContextMappings( context, mod_jk); - } - } - - protected void generateStupidMappings(Context context, PrintWriter mod_jk){ - } - protected void generateContextMappings(Context context, PrintWriter mod_jk){ - } - - /** - * Get the output Writer. Override with method to generate - * web server specific configuration. - */ - protected PrintWriter getWriter() throws IOException { - return null; - } - - /** - * Get the host associated with this Container (if any). - */ - protected Host getHost(Container child) { - while(child != null && ! (child instanceof Host) ) { - child = child.getParent(); - } - return (Host)child; - } - - //-------------------- Properties -------------------- - - /** - * Append to config file. - * Set to true if the config information should be - * appended. - */ - public void setAppend(boolean apnd) { - append = apnd; - } - - /** - * If false, we'll try to generate a config that will - * let apache serve static files. - * The default is true, forward all requests in a context - * to tomcat. - */ - public void setForwardAll( boolean b ) { - forwardAll=b; - } - - /** - * Special option - do not generate mappings for the ROOT - * context. The default is true, and will not generate the mappings, - * not redirecting all pages to tomcat (since /* matches everything). - * This means that the web server's root remains intact but isn't - * completely servlet/JSP enabled. If the ROOT webapp can be configured - * with the web server serving static files, there's no problem setting - * this option to false. If not, then setting it true means the web - * server will be out of picture for all requests. - */ - public void setNoRoot( boolean b ) { - noRoot=b; - } - - /** - * set a path to the parent directory of the - * conf folder. That is, the parent directory - * within which path setters would be resolved against, - * if relative. For example if ConfigHome is set to "/home/tomcat" - * and regConfig is set to "conf/mod_jk.conf" then the resulting - * path used would be: - * "/home/tomcat/conf/mod_jk.conf".

        - *

        - * However, if the path is set to an absolute path, - * this attribute is ignored. - *

        - * If not set, execute() will set this to TOMCAT_HOME. - * @param dir - path to a directory - */ - public void setConfigHome(String dir){ - if( dir==null ) return; - File f=new File(dir); - if(!f.isDirectory()){ - throw new IllegalArgumentException( - "BaseConfig.setConfigHome(): "+ - "Configuration Home must be a directory! : "+dir); - } - configHome = f; - } - - /** - * set a path to the workers.properties file. - * @param path String path to workers.properties file - */ - public void setWorkersConfig(String path){ - workersConfig= (path==null?null:new File(path)); - } - - /** - * set the path to the log file - * @param path String path to a file - */ - public void setJkLog(String path){ - jkLog = ( path==null ? null : new File(path)); - } - - /** - * Set the verbosity level - * ( use debug, error, etc. ) If not set, no log is written. - */ - public void setJkDebug( String level ) { - jkDebug=level; - } - - /** - * Sets the JK worker. - * @param worker The worker - */ - public void setJkWorker(String worker){ - jkWorker = worker; - } - - public void setLegacy(boolean legacy) { - this.legacy = legacy; - } - - // -------------------- Initialize/guess defaults -------------------- - - /** - * Initialize defaults for properties that are not set - * explicitely - */ - protected void initProperties() { - tomcatHome = System.getProperty("catalina.home"); - File tomcatDir = new File(tomcatHome); - if(configHome==null){ - configHome=tomcatDir; - } - } - - // -------------------- Config Utils -------------------- - - - /** - * Add an extension mapping. Override with method to generate - * web server specific configuration - */ - protected boolean addExtensionMapping( String ctxPath, String ext, - PrintWriter pw ) { - return true; - } - - - /** - * Add a fulling specified mapping. Override with method to generate - * web server specific configuration - */ - protected boolean addMapping( String fullPath, PrintWriter pw ) { - return true; - } - - // -------------------- General Utils -------------------- - - protected String getAbsoluteDocBase(Context context) { - // Calculate the absolute path of the document base - String docBase = context.getServletContext().getRealPath("/"); - docBase = docBase.substring(0,docBase.length()-1); - if (!isAbsolute(docBase)){ - docBase = tomcatHome + "/" + docBase; - } - docBase = patch(docBase); - return docBase; - } - - // ------------------ Grabbed from FileUtil ----------------- - public static File getConfigFile( File base, File configDir, String defaultF ) - { - if( base==null ) - base=new File( defaultF ); - if( ! base.isAbsolute() ) { - if( configDir != null ) - base=new File( configDir, base.getPath()); - else - base=new File( base.getAbsolutePath()); //?? - } - File parent=new File(base.getParent()); - if(!parent.exists()){ - if(!parent.mkdirs()){ - throw new RuntimeException( - "Unable to create path to config file :"+ - base.getAbsolutePath()); - } - } - return base; - } - - public static String patch(String path) { - String patchPath = path; - - // Move drive spec to the front of the path - if (patchPath.length() >= 3 && - patchPath.charAt(0) == '/' && - Character.isLetter(patchPath.charAt(1)) && - patchPath.charAt(2) == ':') { - patchPath=patchPath.substring(1,3)+"/"+patchPath.substring(3); - } - - // Eliminate consecutive slashes after the drive spec - if (patchPath.length() >= 2 && - Character.isLetter(patchPath.charAt(0)) && - patchPath.charAt(1) == ':') { - char[] ca = patchPath.replace('/', '\\').toCharArray(); - char c; - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < ca.length; i++) { - if ((ca[i] != '\\') || - (ca[i] == '\\' && - i > 0 && - ca[i - 1] != '\\')) { - if (i == 0 && - Character.isLetter(ca[i]) && - i < ca.length - 1 && - ca[i + 1] == ':') { - c = Character.toUpperCase(ca[i]); - } else { - c = ca[i]; - } - - sb.append(c); - } - } - - patchPath = sb.toString(); - } - - // fix path on NetWare - all '/' become '\\' and remove duplicate '\\' - if (System.getProperty("os.name").startsWith("NetWare") && - path.length() >=3 && - path.indexOf(':') > 0) { - char[] ca = patchPath.replace('/', '\\').toCharArray(); - StringBuffer sb = new StringBuffer(); - - for (int i = 0; i < ca.length; i++) { - if ((ca[i] != '\\') || - (ca[i] == '\\' && i > 0 && ca[i - 1] != '\\')) { - sb.append(ca[i]); - } - } - patchPath = sb.toString(); - } - - return patchPath; - } - - public static boolean isAbsolute( String path ) { - // normal file - if( path.startsWith("/" ) ) return true; - - if( path.startsWith(File.separator ) ) return true; - - // win c: - if (path.length() >= 3 && - Character.isLetter(path.charAt(0)) && - path.charAt(1) == ':') - return true; - - // NetWare volume: - if (System.getProperty("os.name").startsWith("NetWare") && - path.length() >=3 && - path.indexOf(':') > 0) - return true; - - return false; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; + +import org.apache.catalina.Container; +import org.apache.catalina.Context; +import org.apache.catalina.Engine; +import org.apache.catalina.Host; +import org.apache.catalina.Lifecycle; +import org.apache.catalina.LifecycleEvent; +import org.apache.catalina.LifecycleListener; +import org.apache.catalina.Server; + + +/** + Base class for automatic jk based configurations based on + the Tomcat server.xml settings and the war contexts + initialized during startup. +

        + This config interceptor is enabled by inserting a Config + element in the <ContextManager> tag body inside + the server.xml file like so: +

        +    * < ContextManager ... >
        +    *   ...
        +    *   <???Config options />
        +    *   ...
        +    * < /ContextManager >
        +    
        + where options can include any of the following attributes: +
          +
        • configHome - default parent directory for the following paths. + If not set, this defaults to TOMCAT_HOME. Ignored + whenever any of the following paths is absolute. +
        • +
        • workersConfig - path to workers.properties file used by + jk connector. If not set, defaults to + "conf/jk/workers.properties".
        • +
        • jkLog - path to log file to be used by jk connector.
        • +
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. + If not set, defaults to emerg.
        • +
        • jkWorker The desired worker. Must be set to one of the workers + defined in the workers.properties file. "ajp12", "ajp13" + or "inprocess" are the workers found in the default + workers.properties file. If not specified, defaults + to "ajp13" if an Ajp13Interceptor is in use, otherwise + it defaults to "ajp12".
        • +
        • forwardAll - If true, forward all requests to Tomcat. This helps + insure that all the behavior configured in the web.xml + file functions correctly. If false, let Apache serve + static resources. The default is true. + Warning: When false, some configuration in + the web.xml may not be duplicated in Apache. + Review the mod_jk conf file to see what + configuration is actually being set in Apache.
        • +
        • noRoot - If true, the root context is not mapped to + Tomcat. If false and forwardAll is true, all requests + to the root context are mapped to Tomcat. If false and + forwardAll is false, only JSP and servlets requests to + the root context are mapped to Tomcat. When false, + to correctly serve Tomcat's root context you may also + need to modify the web server to point it's home + directory to Tomcat's root context directory. + Otherwise some content, such as the root index.html, + may be served by the web server before the connector + gets a chance to claim the request and pass it to Tomcat. + The default is true.
        • +
        +

        + @author Costin Manolache + @author Larry Isaacs + @author Bill Barker + @version $Revision: 299988 $ + */ +public class BaseJkConfig implements LifecycleListener { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(BaseJkConfig.class); + + protected File configHome = null; + protected File workersConfig = null; + + protected File jkLog = null; + protected String jkDebug="emerg"; + protected String jkWorker = "ajp13"; + + protected boolean noRoot=true; + protected boolean forwardAll=true; + + protected String tomcatHome; + protected boolean regenerate=false; + protected boolean append=false; + protected boolean legacy=true; + + // -------------------- Tomcat callbacks -------------------- + + + // Auto-config should be able to react to dynamic config changes, + // and regenerate the config. + + /** + * Generate the configuration - only when the server is + * completely initialized ( before starting ) + */ + public void lifecycleEvent(LifecycleEvent evt) { + if(Lifecycle.START_EVENT.equals(evt.getType())) { + execute( evt ); + } + } + + /** + * Generate configuration files. Override with method to generate + * web server specific configuration. + */ + public void execute(LifecycleEvent evt) { + initProperties(); + PrintWriter mod_jk = null; + try { + mod_jk = getWriter(); + } catch(IOException iex) { + log.warn("Unable to open config file"); + return; + } + Lifecycle who = evt.getLifecycle(); + if( who instanceof Server ) { + executeServer((Server)who, mod_jk); + } else if(who instanceof Engine) { + executeEngine((Engine)who, mod_jk); + } else if ( who instanceof Host ) { + executeHost((Host)who, mod_jk); + } else if( who instanceof Context ) { + executeContext((Context)who, mod_jk); + } + mod_jk.close(); + } + /** + * Generate configuration files. Override with method to generate + * web server specific configuration. + */ + public void executeServer(Server svr, PrintWriter mod_jk) { + if(! append ) { + if( ! generateJkHead(mod_jk) ) + return; + generateSSLConfig(mod_jk); + generateJkTail(mod_jk); + } + } + + /** + * Generate SSL options + */ + protected void generateSSLConfig(PrintWriter mod_jk) { + } + + /** + * Generate general options + */ + protected boolean generateJkHead(PrintWriter mod_jk) { + return true; + } + + /** + * Generate general options + */ + protected void generateJkTail(PrintWriter mod_jk) { + } + + /** + * Generate Virtual Host start + */ + protected void generateVhostHead(Host host, PrintWriter mod_jk) { + } + + /** + * Generate Virtual Host end + */ + protected void generateVhostTail(Host host, PrintWriter mod_jk) { + } + + /** + * Generate configuration files. Override with method to generate + * web server specific configuration. + */ + protected void executeEngine(Engine egn, PrintWriter mod_jk) { + if(egn.getJvmRoute() != null) { + jkWorker = egn.getJvmRoute(); + } + executeServer(egn.getService().getServer(), mod_jk); + Container [] children = egn.findChildren(); + for(int ii=0; ii < children.length; ii++) { + if( children[ii] instanceof Host ) { + executeHost((Host)children[ii], mod_jk); + } else if( children[ii] instanceof Context ) { + executeContext((Context)children[ii], mod_jk); + } + } + } + /** + * Generate configuration files. Override with method to generate + * web server specific configuration. + */ + protected void executeHost(Host hst, PrintWriter mod_jk) { + generateVhostHead(hst, mod_jk); + Container [] children = hst.findChildren(); + for(int ii=0; ii < children.length; ii++) { + if(children[ii] instanceof Context) { + executeContext((Context)children[ii],mod_jk); + } + } + generateVhostTail(hst, mod_jk); + } + /** + * executes the ApacheConfig interceptor. This method generates apache + * configuration files for use with mod_jk. + * @param context a Context object. + * @param mod_jk Writer for output. + */ + public void executeContext(Context context, PrintWriter mod_jk){ + + if(context.getPath().length() > 0 || ! noRoot ) { + String docRoot = context.getServletContext().getRealPath("/"); + if( forwardAll || docRoot == null) + generateStupidMappings( context, mod_jk ); + else + generateContextMappings( context, mod_jk); + } + } + + protected void generateStupidMappings(Context context, PrintWriter mod_jk){ + } + protected void generateContextMappings(Context context, PrintWriter mod_jk){ + } + + /** + * Get the output Writer. Override with method to generate + * web server specific configuration. + */ + protected PrintWriter getWriter() throws IOException { + return null; + } + + /** + * Get the host associated with this Container (if any). + */ + protected Host getHost(Container child) { + while(child != null && ! (child instanceof Host) ) { + child = child.getParent(); + } + return (Host)child; + } + + //-------------------- Properties -------------------- + + /** + * Append to config file. + * Set to true if the config information should be + * appended. + */ + public void setAppend(boolean apnd) { + append = apnd; + } + + /** + * If false, we'll try to generate a config that will + * let apache serve static files. + * The default is true, forward all requests in a context + * to tomcat. + */ + public void setForwardAll( boolean b ) { + forwardAll=b; + } + + /** + * Special option - do not generate mappings for the ROOT + * context. The default is true, and will not generate the mappings, + * not redirecting all pages to tomcat (since /* matches everything). + * This means that the web server's root remains intact but isn't + * completely servlet/JSP enabled. If the ROOT webapp can be configured + * with the web server serving static files, there's no problem setting + * this option to false. If not, then setting it true means the web + * server will be out of picture for all requests. + */ + public void setNoRoot( boolean b ) { + noRoot=b; + } + + /** + * set a path to the parent directory of the + * conf folder. That is, the parent directory + * within which path setters would be resolved against, + * if relative. For example if ConfigHome is set to "/home/tomcat" + * and regConfig is set to "conf/mod_jk.conf" then the resulting + * path used would be: + * "/home/tomcat/conf/mod_jk.conf".

        + *

        + * However, if the path is set to an absolute path, + * this attribute is ignored. + *

        + * If not set, execute() will set this to TOMCAT_HOME. + * @param dir - path to a directory + */ + public void setConfigHome(String dir){ + if( dir==null ) return; + File f=new File(dir); + if(!f.isDirectory()){ + throw new IllegalArgumentException( + "BaseConfig.setConfigHome(): "+ + "Configuration Home must be a directory! : "+dir); + } + configHome = f; + } + + /** + * set a path to the workers.properties file. + * @param path String path to workers.properties file + */ + public void setWorkersConfig(String path){ + workersConfig= (path==null?null:new File(path)); + } + + /** + * set the path to the log file + * @param path String path to a file + */ + public void setJkLog(String path){ + jkLog = ( path==null ? null : new File(path)); + } + + /** + * Set the verbosity level + * ( use debug, error, etc. ) If not set, no log is written. + */ + public void setJkDebug( String level ) { + jkDebug=level; + } + + /** + * Sets the JK worker. + * @param worker The worker + */ + public void setJkWorker(String worker){ + jkWorker = worker; + } + + public void setLegacy(boolean legacy) { + this.legacy = legacy; + } + + // -------------------- Initialize/guess defaults -------------------- + + /** + * Initialize defaults for properties that are not set + * explicitely + */ + protected void initProperties() { + tomcatHome = System.getProperty("catalina.home"); + File tomcatDir = new File(tomcatHome); + if(configHome==null){ + configHome=tomcatDir; + } + } + + // -------------------- Config Utils -------------------- + + + /** + * Add an extension mapping. Override with method to generate + * web server specific configuration + */ + protected boolean addExtensionMapping( String ctxPath, String ext, + PrintWriter pw ) { + return true; + } + + + /** + * Add a fulling specified mapping. Override with method to generate + * web server specific configuration + */ + protected boolean addMapping( String fullPath, PrintWriter pw ) { + return true; + } + + // -------------------- General Utils -------------------- + + protected String getAbsoluteDocBase(Context context) { + // Calculate the absolute path of the document base + String docBase = context.getServletContext().getRealPath("/"); + docBase = docBase.substring(0,docBase.length()-1); + if (!isAbsolute(docBase)){ + docBase = tomcatHome + "/" + docBase; + } + docBase = patch(docBase); + return docBase; + } + + // ------------------ Grabbed from FileUtil ----------------- + public static File getConfigFile( File base, File configDir, String defaultF ) + { + if( base==null ) + base=new File( defaultF ); + if( ! base.isAbsolute() ) { + if( configDir != null ) + base=new File( configDir, base.getPath()); + else + base=new File( base.getAbsolutePath()); //?? + } + File parent=new File(base.getParent()); + if(!parent.exists()){ + if(!parent.mkdirs()){ + throw new RuntimeException( + "Unable to create path to config file :"+ + base.getAbsolutePath()); + } + } + return base; + } + + public static String patch(String path) { + String patchPath = path; + + // Move drive spec to the front of the path + if (patchPath.length() >= 3 && + patchPath.charAt(0) == '/' && + Character.isLetter(patchPath.charAt(1)) && + patchPath.charAt(2) == ':') { + patchPath=patchPath.substring(1,3)+"/"+patchPath.substring(3); + } + + // Eliminate consecutive slashes after the drive spec + if (patchPath.length() >= 2 && + Character.isLetter(patchPath.charAt(0)) && + patchPath.charAt(1) == ':') { + char[] ca = patchPath.replace('/', '\\').toCharArray(); + char c; + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < ca.length; i++) { + if ((ca[i] != '\\') || + (ca[i] == '\\' && + i > 0 && + ca[i - 1] != '\\')) { + if (i == 0 && + Character.isLetter(ca[i]) && + i < ca.length - 1 && + ca[i + 1] == ':') { + c = Character.toUpperCase(ca[i]); + } else { + c = ca[i]; + } + + sb.append(c); + } + } + + patchPath = sb.toString(); + } + + // fix path on NetWare - all '/' become '\\' and remove duplicate '\\' + if (System.getProperty("os.name").startsWith("NetWare") && + path.length() >=3 && + path.indexOf(':') > 0) { + char[] ca = patchPath.replace('/', '\\').toCharArray(); + StringBuffer sb = new StringBuffer(); + + for (int i = 0; i < ca.length; i++) { + if ((ca[i] != '\\') || + (ca[i] == '\\' && i > 0 && ca[i - 1] != '\\')) { + sb.append(ca[i]); + } + } + patchPath = sb.toString(); + } + + return patchPath; + } + + public static boolean isAbsolute( String path ) { + // normal file + if( path.startsWith("/" ) ) return true; + + if( path.startsWith(File.separator ) ) return true; + + // win c: + if (path.length() >= 3 && + Character.isLetter(path.charAt(0)) && + path.charAt(1) == ':') + return true; + + // NetWare volume: + if (System.getProperty("os.name").startsWith("NetWare") && + path.length() >=3 && + path.indexOf(':') > 0) + return true; + + return false; + } +} diff --git a/java/org/apache/jk/config/GeneratorApache2.java b/java/org/apache/jk/config/GeneratorApache2.java index f9480c2ea..c2b2f4c87 100644 --- a/java/org/apache/jk/config/GeneratorApache2.java +++ b/java/org/apache/jk/config/GeneratorApache2.java @@ -1,193 +1,193 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.config; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Vector; - -import org.w3c.dom.Node; - - -/* Naming conventions: - -JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? ) - -- Each vhost has a sub-dir named after the canonycal name - -- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap - -- In httpd.conf ( or equivalent servers ), in each virtual host you -should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config -file will contain the Alias declarations and other rules required -for apache operation. Same for other servers. - -- WebXml2Jk will be invoked by a config tool or automatically for each -webapp - it'll generate the WEBAPP.jkmap files and config fragments. - -WebXml2Jk will _not_ generate anything else but mappings. -It should _not_ try to guess locations or anything else - that's -another components' job. - -*/ - -/** - * - * @author Costin Manolache - */ -public class GeneratorApache2 implements WebXml2Jk.MappingGenerator { - WebXml2Jk wxml; - String vhost; - String cpath; - String worker; - PrintWriter out; - - public void setWebXmlReader(WebXml2Jk wxml ) { - this.wxml=wxml; - vhost=wxml.vhost; - cpath=wxml.cpath; - worker=wxml.worker; - } - - public void generateStart() throws IOException { - File base=wxml.getJkDir(); - File outF=new File(base, "jk2.conf"); - out=new PrintWriter( new FileWriter( outF )); - - out.println("# Must be included in a virtual host context for " + vhost ); - - out.println("Alias " + cpath + " \"" + wxml.docBase + "\""); - out.println(""); - out.println(" Options Indexes FollowSymLinks"); - generateMimeMapping( out ); - generateWelcomeFiles( out); - - // If we use this instead of extension mapping for jsp we can avoid most - // jsp security problems. - out.println(" AddHandler jakarta-servlet2 .jsp"); - out.println(""); - out.println(); - - out.println(""); - out.println(" AllowOverride None"); - out.println(" Deny from all"); - out.println(""); - out.println(); - out.println(""); - out.println(" AllowOverride None"); - out.println(" Deny from all"); - out.println(""); - out.println(); - } - - private void generateWelcomeFiles( PrintWriter out ) { - Vector wf= wxml.getWellcomeFiles(); - out.print(" DirectoryIndex "); - for( int i=0; i"); - out.println( " SetHandler jakarta-servlet2" ); - out.println( " JkUriSet group " + worker ); - out.println( " JkUriSet servlet " + servlet); - out.println( " JkUriSet host " + vhost ); - out.println( " JkUriSet context " + cpath ); - out.println( ""); - out.println(); - } - - public void generateFilterMapping( String servlet, String url ) { - out.println( ""); - out.println( " SetHandler jakarta-servlet2" ); - out.println( " JkUriSet group " + worker ); - out.println( " JkUriSet servlet " + servlet); - out.println( " JkUriSet host " + vhost ); - out.println( " JkUriSet context " + cpath ); - out.println( ""); - out.println(); - } - - public void generateLoginConfig( String loginPage, - String errPage, String authM ) { - out.println( ""); - out.println( " SetHandler jakarta-servlet2" ); - out.println( " JkUriSet group " + worker ); - out.println( " JkUriSet host " + vhost ); - out.println( " JkUriSet context " + cpath ); - out.println( ""); - out.println(); - } - - public void generateErrorPage( int err, String location ) { - - } - - // XXX Only if BASIC/DIGEST and 'integrated auth' - public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) { - for( int i=0; i"); - - if( methods.size() > 0 ) { - out.print(" " ); - } - - out.println( " AuthType basic" ); - out.print( " Require group " ); - for( int j=0; j 0 ) { - out.println(" "); - } - - out.println( ""); - } - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Vector; + +import org.w3c.dom.Node; + + +/* Naming conventions: + +JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? ) + +- Each vhost has a sub-dir named after the canonycal name + +- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap + +- In httpd.conf ( or equivalent servers ), in each virtual host you +should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config +file will contain the Alias declarations and other rules required +for apache operation. Same for other servers. + +- WebXml2Jk will be invoked by a config tool or automatically for each +webapp - it'll generate the WEBAPP.jkmap files and config fragments. + +WebXml2Jk will _not_ generate anything else but mappings. +It should _not_ try to guess locations or anything else - that's +another components' job. + +*/ + +/** + * + * @author Costin Manolache + */ +public class GeneratorApache2 implements WebXml2Jk.MappingGenerator { + WebXml2Jk wxml; + String vhost; + String cpath; + String worker; + PrintWriter out; + + public void setWebXmlReader(WebXml2Jk wxml ) { + this.wxml=wxml; + vhost=wxml.vhost; + cpath=wxml.cpath; + worker=wxml.worker; + } + + public void generateStart() throws IOException { + File base=wxml.getJkDir(); + File outF=new File(base, "jk2.conf"); + out=new PrintWriter( new FileWriter( outF )); + + out.println("# Must be included in a virtual host context for " + vhost ); + + out.println("Alias " + cpath + " \"" + wxml.docBase + "\""); + out.println(""); + out.println(" Options Indexes FollowSymLinks"); + generateMimeMapping( out ); + generateWelcomeFiles( out); + + // If we use this instead of extension mapping for jsp we can avoid most + // jsp security problems. + out.println(" AddHandler jakarta-servlet2 .jsp"); + out.println(""); + out.println(); + + out.println(""); + out.println(" AllowOverride None"); + out.println(" Deny from all"); + out.println(""); + out.println(); + out.println(""); + out.println(" AllowOverride None"); + out.println(" Deny from all"); + out.println(""); + out.println(); + } + + private void generateWelcomeFiles( PrintWriter out ) { + Vector wf= wxml.getWellcomeFiles(); + out.print(" DirectoryIndex "); + for( int i=0; i"); + out.println( " SetHandler jakarta-servlet2" ); + out.println( " JkUriSet group " + worker ); + out.println( " JkUriSet servlet " + servlet); + out.println( " JkUriSet host " + vhost ); + out.println( " JkUriSet context " + cpath ); + out.println( ""); + out.println(); + } + + public void generateFilterMapping( String servlet, String url ) { + out.println( ""); + out.println( " SetHandler jakarta-servlet2" ); + out.println( " JkUriSet group " + worker ); + out.println( " JkUriSet servlet " + servlet); + out.println( " JkUriSet host " + vhost ); + out.println( " JkUriSet context " + cpath ); + out.println( ""); + out.println(); + } + + public void generateLoginConfig( String loginPage, + String errPage, String authM ) { + out.println( ""); + out.println( " SetHandler jakarta-servlet2" ); + out.println( " JkUriSet group " + worker ); + out.println( " JkUriSet host " + vhost ); + out.println( " JkUriSet context " + cpath ); + out.println( ""); + out.println(); + } + + public void generateErrorPage( int err, String location ) { + + } + + // XXX Only if BASIC/DIGEST and 'integrated auth' + public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) { + for( int i=0; i"); + + if( methods.size() > 0 ) { + out.print(" " ); + } + + out.println( " AuthType basic" ); + out.print( " Require group " ); + for( int j=0; j 0 ) { + out.println(" "); + } + + out.println( ""); + } + } +} diff --git a/java/org/apache/jk/config/GeneratorJk1.java b/java/org/apache/jk/config/GeneratorJk1.java index 2003a25ac..ade15efed 100644 --- a/java/org/apache/jk/config/GeneratorJk1.java +++ b/java/org/apache/jk/config/GeneratorJk1.java @@ -1,112 +1,112 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.config; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Vector; - - -/* Naming conventions: - -JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? ) - -- Each vhost has a sub-dir named after the canonycal name - -- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap - -- In httpd.conf ( or equivalent servers ), in each virtual host you -should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config -file will contain the Alias declarations and other rules required -for apache operation. Same for other servers. - -- WebXml2Jk will be invoked by a config tool or automatically for each -webapp - it'll generate the WEBAPP.jkmap files and config fragments. - -WebXml2Jk will _not_ generate anything else but mappings. -It should _not_ try to guess locations or anything else - that's -another components' job. - -*/ - -/** - * - * @author Costin Manolache - */ -public class GeneratorJk1 implements WebXml2Jk.MappingGenerator { - WebXml2Jk wxml; - String vhost; - String cpath; - String worker; - PrintWriter out; - - public void setWebXmlReader(WebXml2Jk wxml ) { - this.wxml=wxml; - vhost=wxml.vhost; - cpath=wxml.cpath; - worker=wxml.worker; - } - - public void generateStart( ) throws IOException { - File base=wxml.getJkDir(); - File outF=new File(base, "jk.conf"); - out=new PrintWriter( new FileWriter( outF )); - - out.println("# This must be included in the virtual host section for " + vhost ); - } - - public void generateEnd() { - out.close(); - } - - - public void generateServletMapping( String servlet, String url ) { - out.println( "JkMount " + cpath + url + " " + worker); - } - - public void generateFilterMapping( String servlet, String url ) { - out.println( "JkMount " + cpath + url + " " + worker); - } - - public void generateLoginConfig( String loginPage, - String errPage, String authM ) { - out.println( "JkMount " + cpath + loginPage + " " + worker); - } - - public void generateErrorPage( int err, String location ) { - - } - - public void generateMimeMapping( String ext, String type ) { - - } - - public void generateWelcomeFiles( Vector wf ) { - - } - - - public void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) { - for( int i=0; i - This config interceptor is enabled by inserting an IISConfig - element in the <ContextManager> tag body inside - the server.xml file like so: -

        -    * < ContextManager ... >
        -    *   ...
        -    *   <IISConfig options />
        -    *   ...
        -    * < /ContextManager >
        -    
        - where options can include any of the following attributes: -
          -
        • configHome - default parent directory for the following paths. - If not set, this defaults to TOMCAT_HOME. Ignored - whenever any of the following paths is absolute. -
        • -
        • regConfig - path to use for writing IIS isapi_redirect registry - file. If not set, defaults to - "conf/auto/iis_redirect.reg".
        • -
        • workersConfig - path to workers.properties file used by - isapi_redirect. If not set, defaults to - "conf/jk/workers.properties".
        • -
        • uriConfig - path to use for writing IIS isapi_redirect uriworkermap - file. If not set, defaults to - "conf/auto/uriworkermap.properties".
        • -
        • jkLog - path to log file to be used by isapi_redirect.
        • -
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. - If not set, defaults to emerg.
        • -
        • jkWorker The desired worker. Must be set to one of the workers - defined in the workers.properties file. "ajp12", "ajp13" - or "inprocess" are the workers found in the default - workers.properties file. If not specified, defaults - to "ajp13" if an Ajp13Interceptor is in use, otherwise - it defaults to "ajp12".
        • -
        • forwardAll - If true, forward all requests to Tomcat. This helps - insure that all the behavior configured in the web.xml - file functions correctly. If false, let IIS serve - static resources assuming it has been configured - to do so. The default is true. - Warning: When false, some configuration in - the web.xml may not be duplicated in IIS. - Review the uriworkermap file to see what - configuration is actually being set in IIS.
        • -
        • noRoot - If true, the root context is not mapped to - Tomcat. If false and forwardAll is true, all requests - to the root context are mapped to Tomcat. If false and - forwardAll is false, only JSP and servlets requests to - the root context are mapped to Tomcat. When false, - to correctly serve Tomcat's root context you must also - modify the Home Directory setting in IIS - to point to Tomcat's root context directory. - Otherwise some content, such as the root index.html, - will be served by IIS before isapi_redirect gets a chance - to claim the request and pass it to Tomcat. - The default is true.
        • -
        -

        - @author Costin Manolache - @author Larry Isaacs - @author Gal Shachor - @author Bill Barker - */ -public class IISConfig extends BaseJkConfig { - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(IISConfig.class); - - public static final String WORKERS_CONFIG = "/conf/jk/workers.properties"; - public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties"; - public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log"; - public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg"; - - private File regConfig = null; - private File uriConfig = null; - - public IISConfig() - { - } - - //-------------------- Properties -------------------- - - /** - set the path to the output file for the auto-generated - isapi_redirect registry file. If this path is relative - then getRegConfig() will resolve it absolutely against - the getConfigHome() path. -

        - @param path String path to a file - */ - public void setRegConfig(String path){ - regConfig= (path==null)?null:new File(path); - } - - /** - set a path to the uriworkermap.properties file. - @param path String path to uriworkermap.properties file - */ - public void setUriConfig(String path){ - uriConfig= (path==null?null:new File(path)); - } - - // -------------------- Initialize/guess defaults -------------------- - - /** Initialize defaults for properties that are not set - explicitely - */ - protected void initProperties() { - super.initProperties(); - - regConfig=getConfigFile( regConfig, configHome, ISAPI_REG_FILE); - workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG); - uriConfig=getConfigFile( uriConfig, configHome, URI_WORKERS_MAP_CONFIG); - jkLog=getConfigFile( jkLog, configHome, ISAPI_LOG_LOCATION); - } - - // -------------------- Generate config -------------------- - - protected PrintWriter getWriter() throws IOException { - String abUriConfig = uriConfig.getAbsolutePath(); - return new PrintWriter(new FileWriter(abUriConfig,append)); - } - protected boolean generateJkHead(PrintWriter mod_jk) { - try { - PrintWriter regfile = new PrintWriter(new FileWriter(regConfig)); - log.info("Generating IIS registry file = "+regConfig ); - generateRegistrySettings(regfile); - regfile.close(); - } catch(IOException iex) { - log.warn("Unable to generate registry file " +regConfig); - return false; - } - log.info("Generating IIS URI worker map file = "+uriConfig ); - generateUriWorkerHeader(mod_jk); - return true; - } - - // -------------------- Config sections -------------------- - - /** Writes the registry settings required by the IIS connector - */ - private void generateRegistrySettings(PrintWriter regfile) - { - regfile.println("REGEDIT4"); - regfile.println(); - regfile.println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]"); - regfile.println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\""); - regfile.println("\"log_file\"=\"" + dubleSlash(jkLog.toString()) +"\""); - regfile.println("\"log_level\"=\"" + jkDebug + "\""); - regfile.println("\"worker_file\"=\"" + dubleSlash(workersConfig.toString()) +"\""); - regfile.println("\"worker_mount_file\"=\"" + dubleSlash(uriConfig.toString()) +"\""); - } - - /** Writes the header information to the uriworkermap file - */ - private void generateUriWorkerHeader(PrintWriter uri_worker) - { - uri_worker.println("###################################################################"); - uri_worker.println("# Auto generated configuration. Dated: " + new Date()); - uri_worker.println("###################################################################"); - uri_worker.println(); - - uri_worker.println("#"); - uri_worker.println("# Default worker to be used through our mappings"); - uri_worker.println("#"); - uri_worker.println("default.worker=" + jkWorker); - uri_worker.println(); - } - - /** Forward all requests for a context to tomcat. - The default. - */ - protected void generateStupidMappings(Context context, PrintWriter uri_worker ) - { - String ctxPath = context.getPath(); - String nPath=("".equals(ctxPath)) ? "/" : ctxPath; - - if( noRoot && "".equals(ctxPath) ) { - log.debug("Ignoring root context in forward-all mode "); - return; - } - - // map all requests for this context to Tomcat - uri_worker.println(nPath +"=$(default.worker)"); - if( "".equals(ctxPath) ) { - uri_worker.println(nPath +"*=$(default.worker)"); - uri_worker.println( - "# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must"); - uri_worker.println( - "# must be set to: \"" + getAbsoluteDocBase(context) + "\""); - } - else - uri_worker.println(nPath +"/*=$(default.worker)"); - } - - protected void generateContextMappings(Context context, PrintWriter uri_worker ) - { - String ctxPath = context.getPath(); - String nPath=("".equals(ctxPath)) ? "/" : ctxPath; - - if( noRoot && "".equals(ctxPath) ) { - log.debug("Ignoring root context in forward-all mode "); - return; - } - - // Static files will be served by IIS - uri_worker.println(); - uri_worker.println("#########################################################"); - uri_worker.println("# Auto configuration for the " + nPath + " context."); - uri_worker.println("#########################################################"); - uri_worker.println(); - - // Static mappings are not set in uriworkermap, but must be set with IIS admin. - - // InvokerInterceptor - it doesn't have a container, - // but it's implemented using a special module. - - // XXX we need to better collect all mappings - - if(context.getLoginConfig() != null) { - String loginPage = context.getLoginConfig().getLoginPage(); - if(loginPage != null) { - int lpos = loginPage.lastIndexOf("/"); - String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; - addMapping( ctxPath, jscurl, uri_worker); - } - } - String [] servletMaps=context.findServletMappings(); - for( int ii=0; ii < servletMaps.length ; ii++) { - addMapping( ctxPath , servletMaps[ii] , uri_worker ); - } - } - - /** Add an IIS extension mapping. - */ - protected boolean addMapping( String ctxPath, String ext, - PrintWriter uri_worker ) - { - if( log.isDebugEnabled() ) - log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); - if(! ext.startsWith("/") ) - ext = "/" + ext; - if(ext.length() > 1) - uri_worker.println(ctxPath + "/*." + ext + "=$(default.worker)"); - return true; - } - - /** Add a fulling specified IIS mapping. - */ - protected boolean addMapping( String fullPath, PrintWriter uri_worker ) { - if( log.isDebugEnabled() ) - log.debug( "Adding map for " + fullPath ); - uri_worker.println(fullPath + "=$(default.worker)" ); - return true; - } - - // -------------------- Utils -------------------- - - private String dubleSlash(String in) - { - StringBuffer sb = new StringBuffer(); - - for(int i = 0 ; i < in.length() ; i++) { - char ch = in.charAt(i); - if('\\' == ch) { - sb.append("\\\\"); - } else { - sb.append(ch); - } - } - - return sb.toString(); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; + +import org.apache.catalina.Context; + + +/** + Generates automatic IIS isapi_redirect configurations based on + the Tomcat server.xml settings and the war contexts + initialized during startup. +

        + This config interceptor is enabled by inserting an IISConfig + element in the <ContextManager> tag body inside + the server.xml file like so: +

        +    * < ContextManager ... >
        +    *   ...
        +    *   <IISConfig options />
        +    *   ...
        +    * < /ContextManager >
        +    
        + where options can include any of the following attributes: +
          +
        • configHome - default parent directory for the following paths. + If not set, this defaults to TOMCAT_HOME. Ignored + whenever any of the following paths is absolute. +
        • +
        • regConfig - path to use for writing IIS isapi_redirect registry + file. If not set, defaults to + "conf/auto/iis_redirect.reg".
        • +
        • workersConfig - path to workers.properties file used by + isapi_redirect. If not set, defaults to + "conf/jk/workers.properties".
        • +
        • uriConfig - path to use for writing IIS isapi_redirect uriworkermap + file. If not set, defaults to + "conf/auto/uriworkermap.properties".
        • +
        • jkLog - path to log file to be used by isapi_redirect.
        • +
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. + If not set, defaults to emerg.
        • +
        • jkWorker The desired worker. Must be set to one of the workers + defined in the workers.properties file. "ajp12", "ajp13" + or "inprocess" are the workers found in the default + workers.properties file. If not specified, defaults + to "ajp13" if an Ajp13Interceptor is in use, otherwise + it defaults to "ajp12".
        • +
        • forwardAll - If true, forward all requests to Tomcat. This helps + insure that all the behavior configured in the web.xml + file functions correctly. If false, let IIS serve + static resources assuming it has been configured + to do so. The default is true. + Warning: When false, some configuration in + the web.xml may not be duplicated in IIS. + Review the uriworkermap file to see what + configuration is actually being set in IIS.
        • +
        • noRoot - If true, the root context is not mapped to + Tomcat. If false and forwardAll is true, all requests + to the root context are mapped to Tomcat. If false and + forwardAll is false, only JSP and servlets requests to + the root context are mapped to Tomcat. When false, + to correctly serve Tomcat's root context you must also + modify the Home Directory setting in IIS + to point to Tomcat's root context directory. + Otherwise some content, such as the root index.html, + will be served by IIS before isapi_redirect gets a chance + to claim the request and pass it to Tomcat. + The default is true.
        • +
        +

        + @author Costin Manolache + @author Larry Isaacs + @author Gal Shachor + @author Bill Barker + */ +public class IISConfig extends BaseJkConfig { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(IISConfig.class); + + public static final String WORKERS_CONFIG = "/conf/jk/workers.properties"; + public static final String URI_WORKERS_MAP_CONFIG = "/conf/auto/uriworkermap.properties"; + public static final String ISAPI_LOG_LOCATION = "/logs/iis_redirect.log"; + public static final String ISAPI_REG_FILE = "/conf/auto/iis_redirect.reg"; + + private File regConfig = null; + private File uriConfig = null; + + public IISConfig() + { + } + + //-------------------- Properties -------------------- + + /** + set the path to the output file for the auto-generated + isapi_redirect registry file. If this path is relative + then getRegConfig() will resolve it absolutely against + the getConfigHome() path. +

        + @param path String path to a file + */ + public void setRegConfig(String path){ + regConfig= (path==null)?null:new File(path); + } + + /** + set a path to the uriworkermap.properties file. + @param path String path to uriworkermap.properties file + */ + public void setUriConfig(String path){ + uriConfig= (path==null?null:new File(path)); + } + + // -------------------- Initialize/guess defaults -------------------- + + /** Initialize defaults for properties that are not set + explicitely + */ + protected void initProperties() { + super.initProperties(); + + regConfig=getConfigFile( regConfig, configHome, ISAPI_REG_FILE); + workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG); + uriConfig=getConfigFile( uriConfig, configHome, URI_WORKERS_MAP_CONFIG); + jkLog=getConfigFile( jkLog, configHome, ISAPI_LOG_LOCATION); + } + + // -------------------- Generate config -------------------- + + protected PrintWriter getWriter() throws IOException { + String abUriConfig = uriConfig.getAbsolutePath(); + return new PrintWriter(new FileWriter(abUriConfig,append)); + } + protected boolean generateJkHead(PrintWriter mod_jk) { + try { + PrintWriter regfile = new PrintWriter(new FileWriter(regConfig)); + log.info("Generating IIS registry file = "+regConfig ); + generateRegistrySettings(regfile); + regfile.close(); + } catch(IOException iex) { + log.warn("Unable to generate registry file " +regConfig); + return false; + } + log.info("Generating IIS URI worker map file = "+uriConfig ); + generateUriWorkerHeader(mod_jk); + return true; + } + + // -------------------- Config sections -------------------- + + /** Writes the registry settings required by the IIS connector + */ + private void generateRegistrySettings(PrintWriter regfile) + { + regfile.println("REGEDIT4"); + regfile.println(); + regfile.println("[HKEY_LOCAL_MACHINE\\SOFTWARE\\Apache Software Foundation\\Jakarta Isapi Redirector\\1.0]"); + regfile.println("\"extension_uri\"=\"/jakarta/isapi_redirect.dll\""); + regfile.println("\"log_file\"=\"" + dubleSlash(jkLog.toString()) +"\""); + regfile.println("\"log_level\"=\"" + jkDebug + "\""); + regfile.println("\"worker_file\"=\"" + dubleSlash(workersConfig.toString()) +"\""); + regfile.println("\"worker_mount_file\"=\"" + dubleSlash(uriConfig.toString()) +"\""); + } + + /** Writes the header information to the uriworkermap file + */ + private void generateUriWorkerHeader(PrintWriter uri_worker) + { + uri_worker.println("###################################################################"); + uri_worker.println("# Auto generated configuration. Dated: " + new Date()); + uri_worker.println("###################################################################"); + uri_worker.println(); + + uri_worker.println("#"); + uri_worker.println("# Default worker to be used through our mappings"); + uri_worker.println("#"); + uri_worker.println("default.worker=" + jkWorker); + uri_worker.println(); + } + + /** Forward all requests for a context to tomcat. + The default. + */ + protected void generateStupidMappings(Context context, PrintWriter uri_worker ) + { + String ctxPath = context.getPath(); + String nPath=("".equals(ctxPath)) ? "/" : ctxPath; + + if( noRoot && "".equals(ctxPath) ) { + log.debug("Ignoring root context in forward-all mode "); + return; + } + + // map all requests for this context to Tomcat + uri_worker.println(nPath +"=$(default.worker)"); + if( "".equals(ctxPath) ) { + uri_worker.println(nPath +"*=$(default.worker)"); + uri_worker.println( + "# Note: To correctly serve the Tomcat's root context, IIS's Home Directory must"); + uri_worker.println( + "# must be set to: \"" + getAbsoluteDocBase(context) + "\""); + } + else + uri_worker.println(nPath +"/*=$(default.worker)"); + } + + protected void generateContextMappings(Context context, PrintWriter uri_worker ) + { + String ctxPath = context.getPath(); + String nPath=("".equals(ctxPath)) ? "/" : ctxPath; + + if( noRoot && "".equals(ctxPath) ) { + log.debug("Ignoring root context in forward-all mode "); + return; + } + + // Static files will be served by IIS + uri_worker.println(); + uri_worker.println("#########################################################"); + uri_worker.println("# Auto configuration for the " + nPath + " context."); + uri_worker.println("#########################################################"); + uri_worker.println(); + + // Static mappings are not set in uriworkermap, but must be set with IIS admin. + + // InvokerInterceptor - it doesn't have a container, + // but it's implemented using a special module. + + // XXX we need to better collect all mappings + + if(context.getLoginConfig() != null) { + String loginPage = context.getLoginConfig().getLoginPage(); + if(loginPage != null) { + int lpos = loginPage.lastIndexOf("/"); + String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; + addMapping( ctxPath, jscurl, uri_worker); + } + } + String [] servletMaps=context.findServletMappings(); + for( int ii=0; ii < servletMaps.length ; ii++) { + addMapping( ctxPath , servletMaps[ii] , uri_worker ); + } + } + + /** Add an IIS extension mapping. + */ + protected boolean addMapping( String ctxPath, String ext, + PrintWriter uri_worker ) + { + if( log.isDebugEnabled() ) + log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); + if(! ext.startsWith("/") ) + ext = "/" + ext; + if(ext.length() > 1) + uri_worker.println(ctxPath + "/*." + ext + "=$(default.worker)"); + return true; + } + + /** Add a fulling specified IIS mapping. + */ + protected boolean addMapping( String fullPath, PrintWriter uri_worker ) { + if( log.isDebugEnabled() ) + log.debug( "Adding map for " + fullPath ); + uri_worker.println(fullPath + "=$(default.worker)" ); + return true; + } + + // -------------------- Utils -------------------- + + private String dubleSlash(String in) + { + StringBuffer sb = new StringBuffer(); + + for(int i = 0 ; i < in.length() ; i++) { + char ch = in.charAt(i); + if('\\' == ch) { + sb.append("\\\\"); + } else { + sb.append(ch); + } + } + + return sb.toString(); + } + +} diff --git a/java/org/apache/jk/config/NSConfig.java b/java/org/apache/jk/config/NSConfig.java index 4b538d91f..885de8bd6 100644 --- a/java/org/apache/jk/config/NSConfig.java +++ b/java/org/apache/jk/config/NSConfig.java @@ -1,328 +1,328 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.config; - -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.PrintWriter; -import java.util.Date; - -import org.apache.catalina.Context; - - -/** - Generates automatic Netscape nsapi_redirect configurations based on - the Tomcat server.xml settings and the war contexts - initialized during startup. -

        - This config interceptor is enabled by inserting an NSConfig - element in the <ContextManager> tag body inside - the server.xml file like so: -

        -    * < ContextManager ... >
        -    *   ...
        -    *   <NSConfig options />
        -    *   ...
        -    * < /ContextManager >
        -    
        - where options can include any of the following attributes: -
          -
        • configHome - default parent directory for the following paths. - If not set, this defaults to TOMCAT_HOME. Ignored - whenever any of the following paths is absolute. -
        • -
        • objConfig - path to use for writing Netscape obj.conf - file. If not set, defaults to - "conf/auto/obj.conf".
        • -
        • objectName - Name of the Object to execute the requests. - Defaults to "servlet".
        • -
        • workersConfig - path to workers.properties file used by - nsapi_redirect. If not set, defaults to - "conf/jk/workers.properties".
        • -
        • nsapiJk - path to Netscape mod_jk plugin file. If not set, - defaults to "bin/nsapi_redirect.dll" on windows, - "bin/nsapi_rd.nlm" on netware, and - "bin/nsapi_redirector.so" everywhere else.
        • -
        • jkLog - path to log file to be used by nsapi_redirect.
        • -
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. - If not set, defaults to emerg.
        • -
        • jkWorker The desired worker. Must be set to one of the workers - defined in the workers.properties file. "ajp12", "ajp13" - or "inprocess" are the workers found in the default - workers.properties file. If not specified, defaults - to "ajp13" if an Ajp13Interceptor is in use, otherwise - it defaults to "ajp12".
        • -
        • forwardAll - If true, forward all requests to Tomcat. This helps - insure that all the behavior configured in the web.xml - file functions correctly. If false, let Netscape serve - static resources assuming it has been configured - to do so. The default is true. - Warning: When false, some configuration in - the web.xml may not be duplicated in Netscape. - Review the uriworkermap file to see what - configuration is actually being set in Netscape.
        • -
        • noRoot - If true, the root context is not mapped to - Tomcat. If false and forwardAll is true, all requests - to the root context are mapped to Tomcat. If false and - forwardAll is false, only JSP and servlets requests to - the root context are mapped to Tomcat. When false, - to correctly serve Tomcat's root context you must also - modify the Home Directory setting in Netscape - to point to Tomcat's root context directory. - Otherwise some content, such as the root index.html, - will be served by Netscape before nsapi_redirect gets a chance - to claim the request and pass it to Tomcat. - The default is true.
        • -
        -

        - @author Costin Manolache - @author Larry Isaacs - @author Gal Shachor - @author Bill Barker - */ -public class NSConfig extends BaseJkConfig { - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(NSConfig.class); - - public static final String WORKERS_CONFIG = "/conf/jk/workers.properties"; - public static final String NS_CONFIG = "/conf/auto/obj.conf"; - public static final String NSAPI_LOG_LOCATION = "/logs/nsapi_redirect.log"; - /** default location of nsapi plug-in. */ - public static final String NSAPI_REDIRECTOR; - - //set up some defaults based on OS type - static{ - String os = System.getProperty("os.name").toLowerCase(); - if(os.indexOf("windows")>=0){ - NSAPI_REDIRECTOR = "bin/nsapi_redirect.dll"; - }else if(os.indexOf("netware")>=0){ - NSAPI_REDIRECTOR = "bin/nsapi_rd.nlm"; - }else{ - NSAPI_REDIRECTOR = "bin/nsapi_redirector.so"; - } - } - - private File objConfig = null; - private File nsapiJk = null; - private String objectName = "servlet"; - - public NSConfig() - { - } - - //-------------------- Properties -------------------- - - /** - set the path to the output file for the auto-generated - isapi_redirect registry file. If this path is relative - then getRegConfig() will resolve it absolutely against - the getConfigHome() path. -

        - @param path String path to a file - */ - public void setObjConfig(String path) { - objConfig= (path==null)?null:new File(path); - } - - /** - set the path to the nsapi plugin module - @param path String path to a file - */ - public void setNsapiJk(String path) { - nsapiJk=( path==null?null:new File(path)); - } - - /** - Set the name for the Object that implements the - jk_service call. - @param name Name of the obj.conf Object - */ - public void setObjectName(String name) { - objectName = name; - } - - // -------------------- Initialize/guess defaults -------------------- - - /** Initialize defaults for properties that are not set - explicitely - */ - protected void initProperties() { - super.initProperties(); - - objConfig=getConfigFile( objConfig, configHome, NS_CONFIG); - workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG); - - if( nsapiJk == null ) - nsapiJk=new File(NSAPI_REDIRECTOR); - else - nsapiJk =getConfigFile( nsapiJk, configHome, NSAPI_REDIRECTOR ); - jkLog=getConfigFile( jkLog, configHome, NSAPI_LOG_LOCATION); - } - - // -------------------- Generate config -------------------- - protected PrintWriter getWriter() throws IOException { - String abObjConfig = objConfig.getAbsolutePath(); - return new PrintWriter(new FileWriter(abObjConfig,append)); - } - protected boolean generateJkHead(PrintWriter mod_jk) { - log.info("Generating netscape web server config = "+objConfig ); - - generateNsapiHead( mod_jk ); - - mod_jk.println(""); - return true; - } - - private void generateNsapiHead(PrintWriter objfile) - { - objfile.println("###################################################################"); - objfile.println("# Auto generated configuration. Dated: " + new Date()); - objfile.println("###################################################################"); - objfile.println(); - - objfile.println("#"); - objfile.println("# You will need to merge the content of this file with your "); - objfile.println("# regular obj.conf and then restart (=stop + start) your Netscape server. "); - objfile.println("#"); - objfile.println(); - - objfile.println("#"); - objfile.println("# Loading the redirector into your server"); - objfile.println("#"); - objfile.println(); - objfile.println("Init fn=\"load-modules\" funcs=\"jk_init,jk_service\" shlib=\"\""); - objfile.println("Init fn=\"jk_init\" worker_file=\"" + - workersConfig.toString().replace('\\', '/') + - "\" log_level=\"" + jkDebug + "\" log_file=\"" + - jkLog.toString().replace('\\', '/') + - "\""); - objfile.println(); - } - - protected void generateJkTail(PrintWriter objfile) - { - objfile.println(); - objfile.println("#######################################################"); - objfile.println("# Protecting the WEB-INF and META-INF directories."); - objfile.println("#######################################################"); - objfile.println("PathCheck fn=\"deny-existence\" path=\"*/WEB-INF/*\""); - objfile.println("PathCheck fn=\"deny-existence\" path=\"*/META-INF/*\""); - objfile.println(); - - objfile.println(""); - objfile.println(); - - objfile.println("#######################################################"); - objfile.println("# New object to execute your servlet requests."); - objfile.println("#######################################################"); - objfile.println(""); - objfile.println("ObjectType fn=force-type type=text/html"); - objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\""); - objfile.println(""); - objfile.println(); - } - - // -------------------- Forward all mode -------------------- - - /** Forward all requests for a context to tomcat. - The default. - */ - protected void generateStupidMappings(Context context, PrintWriter objfile ) - { - String ctxPath = context.getPath(); - String nPath=("".equals(ctxPath)) ? "/" : ctxPath; - - if( noRoot && "".equals(ctxPath) ) { - log.debug("Ignoring root context in forward-all mode "); - return; - } - objfile.println(""); - - objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\""); - objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\""); - objfile.println(""); - } - - - // -------------------- Netscape serves static mode -------------------- - // This is not going to work for all apps. We fall back to stupid mode. - - protected void generateContextMappings(Context context, PrintWriter objfile ) - { - String ctxPath = context.getPath(); - String nPath=("".equals(ctxPath)) ? "/" : ctxPath; - - if( noRoot && "".equals(ctxPath) ) { - log.debug("Ignoring root context in non-forward-all mode "); - return; - } - objfile.println(""); - // Static files will be served by Netscape - objfile.println("#########################################################"); - objfile.println("# Auto configuration for the " + nPath + " context starts."); - objfile.println("#########################################################"); - objfile.println(); - - // XXX Need to determine what if/how static mappings are done - - // InvokerInterceptor - it doesn't have a container, - // but it's implemented using a special module. - - // XXX we need to better collect all mappings - if(context.getLoginConfig() != null) { - String loginPage = context.getLoginConfig().getLoginPage(); - if(loginPage != null) { - int lpos = loginPage.lastIndexOf("/"); - String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; - addMapping( ctxPath, jscurl, objfile); - } - } - - String [] servletMaps=context.findServletMappings(); - for(int ii=0; ii < servletMaps.length; ii++) { - addMapping( ctxPath , servletMaps[ii] , objfile ); - } - objfile.println(""); - } - - /** Add a Netscape extension mapping. - */ - protected boolean addMapping( String ctxPath, String ext, - PrintWriter objfile ) - { - if( log.isDebugEnabled() ) - log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); - if(! ext.startsWith("/") ) - ext = "/" + ext; - if(ext.length() > 1) - objfile.println("NameTrans fn=\"assign-name\" from=\"" + - ctxPath + ext + "\" name=\"" + objectName + "\""); - return true; - } - - /** Add a fulling specified Netscape mapping. - */ - protected boolean addMapping( String fullPath, PrintWriter objfile ) { - if( log.isDebugEnabled() ) - log.debug( "Adding map for " + fullPath ); - objfile.println("NameTrans fn=\"assign-name\" from=\"" + - fullPath + "\" name=\"" + objectName + "\""); - return true; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Date; + +import org.apache.catalina.Context; + + +/** + Generates automatic Netscape nsapi_redirect configurations based on + the Tomcat server.xml settings and the war contexts + initialized during startup. +

        + This config interceptor is enabled by inserting an NSConfig + element in the <ContextManager> tag body inside + the server.xml file like so: +

        +    * < ContextManager ... >
        +    *   ...
        +    *   <NSConfig options />
        +    *   ...
        +    * < /ContextManager >
        +    
        + where options can include any of the following attributes: +
          +
        • configHome - default parent directory for the following paths. + If not set, this defaults to TOMCAT_HOME. Ignored + whenever any of the following paths is absolute. +
        • +
        • objConfig - path to use for writing Netscape obj.conf + file. If not set, defaults to + "conf/auto/obj.conf".
        • +
        • objectName - Name of the Object to execute the requests. + Defaults to "servlet".
        • +
        • workersConfig - path to workers.properties file used by + nsapi_redirect. If not set, defaults to + "conf/jk/workers.properties".
        • +
        • nsapiJk - path to Netscape mod_jk plugin file. If not set, + defaults to "bin/nsapi_redirect.dll" on windows, + "bin/nsapi_rd.nlm" on netware, and + "bin/nsapi_redirector.so" everywhere else.
        • +
        • jkLog - path to log file to be used by nsapi_redirect.
        • +
        • jkDebug - Loglevel setting. May be debug, info, error, or emerg. + If not set, defaults to emerg.
        • +
        • jkWorker The desired worker. Must be set to one of the workers + defined in the workers.properties file. "ajp12", "ajp13" + or "inprocess" are the workers found in the default + workers.properties file. If not specified, defaults + to "ajp13" if an Ajp13Interceptor is in use, otherwise + it defaults to "ajp12".
        • +
        • forwardAll - If true, forward all requests to Tomcat. This helps + insure that all the behavior configured in the web.xml + file functions correctly. If false, let Netscape serve + static resources assuming it has been configured + to do so. The default is true. + Warning: When false, some configuration in + the web.xml may not be duplicated in Netscape. + Review the uriworkermap file to see what + configuration is actually being set in Netscape.
        • +
        • noRoot - If true, the root context is not mapped to + Tomcat. If false and forwardAll is true, all requests + to the root context are mapped to Tomcat. If false and + forwardAll is false, only JSP and servlets requests to + the root context are mapped to Tomcat. When false, + to correctly serve Tomcat's root context you must also + modify the Home Directory setting in Netscape + to point to Tomcat's root context directory. + Otherwise some content, such as the root index.html, + will be served by Netscape before nsapi_redirect gets a chance + to claim the request and pass it to Tomcat. + The default is true.
        • +
        +

        + @author Costin Manolache + @author Larry Isaacs + @author Gal Shachor + @author Bill Barker + */ +public class NSConfig extends BaseJkConfig { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(NSConfig.class); + + public static final String WORKERS_CONFIG = "/conf/jk/workers.properties"; + public static final String NS_CONFIG = "/conf/auto/obj.conf"; + public static final String NSAPI_LOG_LOCATION = "/logs/nsapi_redirect.log"; + /** default location of nsapi plug-in. */ + public static final String NSAPI_REDIRECTOR; + + //set up some defaults based on OS type + static{ + String os = System.getProperty("os.name").toLowerCase(); + if(os.indexOf("windows")>=0){ + NSAPI_REDIRECTOR = "bin/nsapi_redirect.dll"; + }else if(os.indexOf("netware")>=0){ + NSAPI_REDIRECTOR = "bin/nsapi_rd.nlm"; + }else{ + NSAPI_REDIRECTOR = "bin/nsapi_redirector.so"; + } + } + + private File objConfig = null; + private File nsapiJk = null; + private String objectName = "servlet"; + + public NSConfig() + { + } + + //-------------------- Properties -------------------- + + /** + set the path to the output file for the auto-generated + isapi_redirect registry file. If this path is relative + then getRegConfig() will resolve it absolutely against + the getConfigHome() path. +

        + @param path String path to a file + */ + public void setObjConfig(String path) { + objConfig= (path==null)?null:new File(path); + } + + /** + set the path to the nsapi plugin module + @param path String path to a file + */ + public void setNsapiJk(String path) { + nsapiJk=( path==null?null:new File(path)); + } + + /** + Set the name for the Object that implements the + jk_service call. + @param name Name of the obj.conf Object + */ + public void setObjectName(String name) { + objectName = name; + } + + // -------------------- Initialize/guess defaults -------------------- + + /** Initialize defaults for properties that are not set + explicitely + */ + protected void initProperties() { + super.initProperties(); + + objConfig=getConfigFile( objConfig, configHome, NS_CONFIG); + workersConfig=getConfigFile( workersConfig, configHome, WORKERS_CONFIG); + + if( nsapiJk == null ) + nsapiJk=new File(NSAPI_REDIRECTOR); + else + nsapiJk =getConfigFile( nsapiJk, configHome, NSAPI_REDIRECTOR ); + jkLog=getConfigFile( jkLog, configHome, NSAPI_LOG_LOCATION); + } + + // -------------------- Generate config -------------------- + protected PrintWriter getWriter() throws IOException { + String abObjConfig = objConfig.getAbsolutePath(); + return new PrintWriter(new FileWriter(abObjConfig,append)); + } + protected boolean generateJkHead(PrintWriter mod_jk) { + log.info("Generating netscape web server config = "+objConfig ); + + generateNsapiHead( mod_jk ); + + mod_jk.println(""); + return true; + } + + private void generateNsapiHead(PrintWriter objfile) + { + objfile.println("###################################################################"); + objfile.println("# Auto generated configuration. Dated: " + new Date()); + objfile.println("###################################################################"); + objfile.println(); + + objfile.println("#"); + objfile.println("# You will need to merge the content of this file with your "); + objfile.println("# regular obj.conf and then restart (=stop + start) your Netscape server. "); + objfile.println("#"); + objfile.println(); + + objfile.println("#"); + objfile.println("# Loading the redirector into your server"); + objfile.println("#"); + objfile.println(); + objfile.println("Init fn=\"load-modules\" funcs=\"jk_init,jk_service\" shlib=\"\""); + objfile.println("Init fn=\"jk_init\" worker_file=\"" + + workersConfig.toString().replace('\\', '/') + + "\" log_level=\"" + jkDebug + "\" log_file=\"" + + jkLog.toString().replace('\\', '/') + + "\""); + objfile.println(); + } + + protected void generateJkTail(PrintWriter objfile) + { + objfile.println(); + objfile.println("#######################################################"); + objfile.println("# Protecting the WEB-INF and META-INF directories."); + objfile.println("#######################################################"); + objfile.println("PathCheck fn=\"deny-existence\" path=\"*/WEB-INF/*\""); + objfile.println("PathCheck fn=\"deny-existence\" path=\"*/META-INF/*\""); + objfile.println(); + + objfile.println(""); + objfile.println(); + + objfile.println("#######################################################"); + objfile.println("# New object to execute your servlet requests."); + objfile.println("#######################################################"); + objfile.println(""); + objfile.println("ObjectType fn=force-type type=text/html"); + objfile.println("Service fn=\"jk_service\" worker=\""+ jkWorker + "\" path=\"/*\""); + objfile.println(""); + objfile.println(); + } + + // -------------------- Forward all mode -------------------- + + /** Forward all requests for a context to tomcat. + The default. + */ + protected void generateStupidMappings(Context context, PrintWriter objfile ) + { + String ctxPath = context.getPath(); + String nPath=("".equals(ctxPath)) ? "/" : ctxPath; + + if( noRoot && "".equals(ctxPath) ) { + log.debug("Ignoring root context in forward-all mode "); + return; + } + objfile.println(""); + + objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "\" name=\"" + objectName + "\""); + objfile.println("NameTrans fn=\"assign-name\" from=\"" + ctxPath + "/*\" name=\"" + objectName + "\""); + objfile.println(""); + } + + + // -------------------- Netscape serves static mode -------------------- + // This is not going to work for all apps. We fall back to stupid mode. + + protected void generateContextMappings(Context context, PrintWriter objfile ) + { + String ctxPath = context.getPath(); + String nPath=("".equals(ctxPath)) ? "/" : ctxPath; + + if( noRoot && "".equals(ctxPath) ) { + log.debug("Ignoring root context in non-forward-all mode "); + return; + } + objfile.println(""); + // Static files will be served by Netscape + objfile.println("#########################################################"); + objfile.println("# Auto configuration for the " + nPath + " context starts."); + objfile.println("#########################################################"); + objfile.println(); + + // XXX Need to determine what if/how static mappings are done + + // InvokerInterceptor - it doesn't have a container, + // but it's implemented using a special module. + + // XXX we need to better collect all mappings + if(context.getLoginConfig() != null) { + String loginPage = context.getLoginConfig().getLoginPage(); + if(loginPage != null) { + int lpos = loginPage.lastIndexOf("/"); + String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; + addMapping( ctxPath, jscurl, objfile); + } + } + + String [] servletMaps=context.findServletMappings(); + for(int ii=0; ii < servletMaps.length; ii++) { + addMapping( ctxPath , servletMaps[ii] , objfile ); + } + objfile.println(""); + } + + /** Add a Netscape extension mapping. + */ + protected boolean addMapping( String ctxPath, String ext, + PrintWriter objfile ) + { + if( log.isDebugEnabled() ) + log.debug( "Adding extension map for " + ctxPath + "/*." + ext ); + if(! ext.startsWith("/") ) + ext = "/" + ext; + if(ext.length() > 1) + objfile.println("NameTrans fn=\"assign-name\" from=\"" + + ctxPath + ext + "\" name=\"" + objectName + "\""); + return true; + } + + /** Add a fulling specified Netscape mapping. + */ + protected boolean addMapping( String fullPath, PrintWriter objfile ) { + if( log.isDebugEnabled() ) + log.debug( "Adding map for " + fullPath ); + objfile.println("NameTrans fn=\"assign-name\" from=\"" + + fullPath + "\" name=\"" + objectName + "\""); + return true; + } + +} diff --git a/java/org/apache/jk/config/WebXml2Jk.java b/java/org/apache/jk/config/WebXml2Jk.java index aedeaf625..1ab15772a 100644 --- a/java/org/apache/jk/config/WebXml2Jk.java +++ b/java/org/apache/jk/config/WebXml2Jk.java @@ -1,451 +1,451 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.config; - -import java.io.File; -import java.io.IOException; -import java.io.StringReader; -import java.util.Hashtable; -import java.util.Vector; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.apache.tomcat.util.IntrospectionUtils; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - - -/* Naming conventions: - -JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? ) - -- Each vhost has a sub-dir named after the canonycal name - -- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap - -- In httpd.conf ( or equivalent servers ), in each virtual host you -should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config -file will contain the Alias declarations and other rules required -for apache operation. Same for other servers. - -- WebXml2Jk will be invoked by a config tool or automatically for each -webapp - it'll generate the WEBAPP.jkmap files and config fragments. - -WebXml2Jk will _not_ generate anything else but mappings. -It should _not_ try to guess locations or anything else - that's -another components' job. - -*/ - -/** - * Read a web.xml file and generate the mappings for jk2. - * It can be used from the command line or ant. - * - * In order for the web server to serve static pages, all webapps - * must be deployed on the computer that runs Apache, IIS, etc. - * - * Dynamic pages can be executed on that computer or other servers - * in a pool, but even if the main server doesn't run tomcat, - * it must have all the static files and WEB-INF/web.xml. - * ( you could have a script remove everything else, including jsps - if - * security paranoia is present ). - * - * XXX We could have this in WEB-INF/urimap.properties. - * - * @author Costin Manolache - */ -public class WebXml2Jk { - String vhost=""; - String cpath=""; - String docBase; - String file; - String worker="lb"; - - // -------------------- Settings -------------------- - - // XXX We can also generate location-independent mappings. - - /** Set the canonycal name of the virtual host. - */ - public void setHost( String vhost ) { - this.vhost=vhost; - } - - /** Set the canonical name of the virtual host. - */ - public void setContext( String contextPath ) { - this.cpath=contextPath; - } - - - /** Set the base directory where the application is - * deployed ( on the web server ). - */ - public void setDocBase(String docBase ) { - this.docBase=docBase; - } - - // Automatically generated. -// /** The file where the jk2 mapping will be generated -// */ -// public void setJk2Conf( String outFile ) { -// file=outFile; -// type=CONFIG_JK2_URIMAP; -// } - -// /** Backward compat: generate JkMounts for mod_jk1 -// */ -// public void setJkmountFile( String outFile ) { -// file=outFile; -// type=CONFIG_JK_MOUNT; -// } - - /* By default we map to the lb - in jk2 this is automatically - * created and includes all tomcat instances. - * - * This is equivalent to the worker in jk1. - */ - public void setGroup(String route ) { - worker=route; - } - - // -------------------- Generators -------------------- - public static interface MappingGenerator { - void setWebXmlReader(WebXml2Jk wxml ); - - /** Start section( vhost declarations, etc ) - */ - void generateStart() throws IOException ; - - void generateEnd() throws IOException ; - - void generateServletMapping( String servlet, String url )throws IOException ; - void generateFilterMapping( String servlet, String url ) throws IOException ; - - void generateLoginConfig( String loginPage, - String errPage, String authM ) throws IOException ; - - void generateErrorPage( int err, String location ) throws IOException ; - - void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) throws IOException ; - } - - // -------------------- Implementation -------------------- - Node webN; - File jkDir; - - /** Return the top level node - */ - public Node getWebXmlNode() { - return webN; - } - - public File getJkDir() { - return jkDir; - } - - /** Extract the wellcome files from the web.xml - */ - public Vector getWellcomeFiles() { - Node n0=getChild( webN, "welcome-file-list" ); - Vector wF=new Vector(); - if( n0!=null ) { - for( Node mapN=getChild( webN, "welcome-file" ); - mapN != null; mapN = getNext( mapN ) ) { - wF.addElement( getContent(mapN)); - } - } - // XXX Add index.html, index.jsp - return wF; - } - - - void generate(MappingGenerator gen ) throws IOException { - gen.generateStart(); - log.info("Generating mappings for servlets " ); - for( Node mapN=getChild( webN, "servlet-mapping" ); - mapN != null; mapN = getNext( mapN ) ) { - - String serv=getChildContent( mapN, "servlet-name"); - String url=getChildContent( mapN, "url-pattern"); - - gen.generateServletMapping( serv, url ); - } - - log.info("Generating mappings for filters " ); - for( Node mapN=getChild( webN, "filter-mapping" ); - mapN != null; mapN = getNext( mapN ) ) { - - String filter=getChildContent( mapN, "filter-name"); - String url=getChildContent( mapN, "url-pattern"); - - gen.generateFilterMapping( filter, url ); - } - - - for( Node mapN=getChild( webN, "error-page" ); - mapN != null; mapN = getNext( mapN ) ) { - String errorCode= getChildContent( mapN, "error-code" ); - String location= getChildContent( mapN, "location" ); - - if( errorCode!=null && ! "".equals( errorCode ) ) { - try { - int err=new Integer( errorCode ).intValue(); - gen.generateErrorPage( err, location ); - } catch( Exception ex ) { - log.error( "Format error " + location, ex); - } - } - } - - Node lcN=getChild( webN, "login-config" ); - if( lcN!=null ) { - log.info("Generating mapping for login-config " ); - - String authMeth=getContent( getChild( lcN, "auth-method")); - if( authMeth == null ) authMeth="BASIC"; - - Node n1=getChild( lcN, "form-login-config"); - String loginPage= getChildContent( n1, "form-login-page"); - String errPage= getChildContent( n1, "form-error-page"); - - if(loginPage != null) { - int lpos = loginPage.lastIndexOf("/"); - String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; - gen.generateLoginConfig( jscurl, errPage, authMeth ); - } - } - - log.info("Generating mappings for security constraints " ); - for( Node mapN=getChild( webN, "security-constraint" ); - mapN != null; mapN = getNext( mapN )) { - - Vector methods=new Vector(); - Vector urls=new Vector(); - Vector roles=new Vector(); - boolean isSSL=false; - - Node wrcN=getChild( mapN, "web-resource-collection"); - for( Node uN=getChild(wrcN, "http-method"); - uN!=null; uN=getNext( uN )) { - methods.addElement( getContent( uN )); - } - for( Node uN=getChild(wrcN, "url-pattern"); - uN!=null; uN=getNext( uN )) { - urls.addElement( getContent( uN )); - } - - // Not used at the moment - Node acN=getChild( mapN, "auth-constraint"); - for( Node rN=getChild(acN, "role-name"); - rN!=null; rN=getNext( rN )) { - roles.addElement(getContent( rN )); - } - - Node ucN=getChild( mapN, "user-data-constraint"); - String transp=getContent(getChild( ucN, "transport-guarantee")); - if( transp!=null ) { - if( "INTEGRAL".equalsIgnoreCase( transp ) || - "CONFIDENTIAL".equalsIgnoreCase( transp ) ) { - isSSL=true; - } - } - - gen.generateConstraints( urls, methods, roles, isSSL ); - } - gen.generateEnd(); - } - - // -------------------- Main and ant wrapper -------------------- - - public void execute() { - try { - if( docBase== null) { - log.error("No docbase - please specify the base directory of you web application ( -docBase PATH )"); - return; - } - if( cpath== null) { - log.error("No context - please specify the mount ( -context PATH )"); - return; - } - File docbF=new File(docBase); - File wXmlF=new File( docBase, "WEB-INF/web.xml"); - - Document wXmlN=readXml(wXmlF); - if( wXmlN == null ) return; - - webN = wXmlN.getDocumentElement(); - if( webN==null ) { - log.error("Can't find web-app"); - return; - } - - jkDir=new File( docbF, "WEB-INF/jk2" ); - jkDir.mkdirs(); - - MappingGenerator generator=new GeneratorJk2(); - generator.setWebXmlReader( this ); - generate( generator ); - - generator=new GeneratorJk1(); - generator.setWebXmlReader( this ); - generate( generator ); - - generator=new GeneratorApache2(); - generator.setWebXmlReader( this ); - generate( generator ); - - } catch( Exception ex ) { - ex.printStackTrace(); - } - } - - - public static void main(String args[] ) { - try { - if( args.length == 1 && - ( "-?".equals(args[0]) || "-h".equals( args[0])) ) { - System.out.println("Usage: "); - System.out.println(" WebXml2Jk [OPTIONS]"); - System.out.println(); - System.out.println(" -docBase DIR The location of the webapp. Required"); - System.out.println(" -group GROUP Group, if you have multiple tomcats with diffrent content. " ); - System.out.println(" The default is 'lb', and should be used in most cases"); - System.out.println(" -host HOSTNAME Canonical hostname - for virtual hosts"); - System.out.println(" -context /CPATH Context path where the app will be mounted"); - return; - } - - WebXml2Jk w2jk=new WebXml2Jk(); - - /* do ant-style property setting */ - IntrospectionUtils.processArgs( w2jk, args, new String[] {}, - null, new Hashtable()); - w2jk.execute(); - } catch( Exception ex ) { - ex.printStackTrace(); - } - - } - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( WebXml2Jk.class ); - - - // -------------------- DOM utils -------------------- - - /** Get the content of a node - */ - public static String getContent(Node n ) { - if( n==null ) return null; - Node n1=n.getFirstChild(); - // XXX Check if it's a text node - - String s1=n1.getNodeValue(); - return s1.trim(); - } - - /** Get the first child - */ - public static Node getChild( Node parent, String name ) { - if( parent==null ) return null; - Node first=parent.getFirstChild(); - if( first==null ) return null; - for (Node node = first; node != null; - node = node.getNextSibling()) { - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( name.equals( node.getNodeName() ) ) { - return node; - } - } - return null; - } - - /** Get the first child's content ( i.e. it's included TEXT node ) - */ - public static String getChildContent( Node parent, String name ) { - Node first=parent.getFirstChild(); - if( first==null ) return null; - for (Node node = first; node != null; - node = node.getNextSibling()) { - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( name.equals( node.getNodeName() ) ) { - return getContent( node ); - } - } - return null; - } - - /** Get the node in the list of siblings - */ - public static Node getNext( Node current ) { - Node first=current.getNextSibling(); - String name=current.getNodeName(); - if( first==null ) return null; - for (Node node = first; node != null; - node = node.getNextSibling()) { - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( name.equals( node.getNodeName() ) ) { - return node; - } - } - return null; - } - - public static class NullResolver implements EntityResolver { - public InputSource resolveEntity (String publicId, - String systemId) - throws SAXException, IOException - { - if (log.isDebugEnabled()) - log.debug("ResolveEntity: " + publicId + " " + systemId); - return new InputSource(new StringReader("")); - } - } - - public static Document readXml(File xmlF) - throws SAXException, IOException, ParserConfigurationException - { - if( ! xmlF.exists() ) { - log.error("No xml file " + xmlF ); - return null; - } - DocumentBuilderFactory dbf = - DocumentBuilderFactory.newInstance(); - - dbf.setValidating(false); - dbf.setIgnoringComments(false); - dbf.setIgnoringElementContentWhitespace(true); - //dbf.setCoalescing(true); - //dbf.setExpandEntityReferences(true); - - DocumentBuilder db = null; - db = dbf.newDocumentBuilder(); - db.setEntityResolver( new NullResolver() ); - - // db.setErrorHandler( new MyErrorHandler()); - - Document doc = db.parse(xmlF); - return doc; - } - -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.config; + +import java.io.File; +import java.io.IOException; +import java.io.StringReader; +import java.util.Hashtable; +import java.util.Vector; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.apache.tomcat.util.IntrospectionUtils; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.xml.sax.EntityResolver; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + + +/* Naming conventions: + +JK_CONF_DIR == serverRoot/work ( XXX /jkConfig ? ) + +- Each vhost has a sub-dir named after the canonycal name + +- For each webapp in a vhost, there is a separate WEBAPP_NAME.jkmap + +- In httpd.conf ( or equivalent servers ), in each virtual host you +should "Include JK_CONF_DIR/VHOST/jk_apache.conf". The config +file will contain the Alias declarations and other rules required +for apache operation. Same for other servers. + +- WebXml2Jk will be invoked by a config tool or automatically for each +webapp - it'll generate the WEBAPP.jkmap files and config fragments. + +WebXml2Jk will _not_ generate anything else but mappings. +It should _not_ try to guess locations or anything else - that's +another components' job. + +*/ + +/** + * Read a web.xml file and generate the mappings for jk2. + * It can be used from the command line or ant. + * + * In order for the web server to serve static pages, all webapps + * must be deployed on the computer that runs Apache, IIS, etc. + * + * Dynamic pages can be executed on that computer or other servers + * in a pool, but even if the main server doesn't run tomcat, + * it must have all the static files and WEB-INF/web.xml. + * ( you could have a script remove everything else, including jsps - if + * security paranoia is present ). + * + * XXX We could have this in WEB-INF/urimap.properties. + * + * @author Costin Manolache + */ +public class WebXml2Jk { + String vhost=""; + String cpath=""; + String docBase; + String file; + String worker="lb"; + + // -------------------- Settings -------------------- + + // XXX We can also generate location-independent mappings. + + /** Set the canonycal name of the virtual host. + */ + public void setHost( String vhost ) { + this.vhost=vhost; + } + + /** Set the canonical name of the virtual host. + */ + public void setContext( String contextPath ) { + this.cpath=contextPath; + } + + + /** Set the base directory where the application is + * deployed ( on the web server ). + */ + public void setDocBase(String docBase ) { + this.docBase=docBase; + } + + // Automatically generated. +// /** The file where the jk2 mapping will be generated +// */ +// public void setJk2Conf( String outFile ) { +// file=outFile; +// type=CONFIG_JK2_URIMAP; +// } + +// /** Backward compat: generate JkMounts for mod_jk1 +// */ +// public void setJkmountFile( String outFile ) { +// file=outFile; +// type=CONFIG_JK_MOUNT; +// } + + /* By default we map to the lb - in jk2 this is automatically + * created and includes all tomcat instances. + * + * This is equivalent to the worker in jk1. + */ + public void setGroup(String route ) { + worker=route; + } + + // -------------------- Generators -------------------- + public static interface MappingGenerator { + void setWebXmlReader(WebXml2Jk wxml ); + + /** Start section( vhost declarations, etc ) + */ + void generateStart() throws IOException ; + + void generateEnd() throws IOException ; + + void generateServletMapping( String servlet, String url )throws IOException ; + void generateFilterMapping( String servlet, String url ) throws IOException ; + + void generateLoginConfig( String loginPage, + String errPage, String authM ) throws IOException ; + + void generateErrorPage( int err, String location ) throws IOException ; + + void generateConstraints( Vector urls, Vector methods, Vector roles, boolean isSSL ) throws IOException ; + } + + // -------------------- Implementation -------------------- + Node webN; + File jkDir; + + /** Return the top level node + */ + public Node getWebXmlNode() { + return webN; + } + + public File getJkDir() { + return jkDir; + } + + /** Extract the wellcome files from the web.xml + */ + public Vector getWellcomeFiles() { + Node n0=getChild( webN, "welcome-file-list" ); + Vector wF=new Vector(); + if( n0!=null ) { + for( Node mapN=getChild( webN, "welcome-file" ); + mapN != null; mapN = getNext( mapN ) ) { + wF.addElement( getContent(mapN)); + } + } + // XXX Add index.html, index.jsp + return wF; + } + + + void generate(MappingGenerator gen ) throws IOException { + gen.generateStart(); + log.info("Generating mappings for servlets " ); + for( Node mapN=getChild( webN, "servlet-mapping" ); + mapN != null; mapN = getNext( mapN ) ) { + + String serv=getChildContent( mapN, "servlet-name"); + String url=getChildContent( mapN, "url-pattern"); + + gen.generateServletMapping( serv, url ); + } + + log.info("Generating mappings for filters " ); + for( Node mapN=getChild( webN, "filter-mapping" ); + mapN != null; mapN = getNext( mapN ) ) { + + String filter=getChildContent( mapN, "filter-name"); + String url=getChildContent( mapN, "url-pattern"); + + gen.generateFilterMapping( filter, url ); + } + + + for( Node mapN=getChild( webN, "error-page" ); + mapN != null; mapN = getNext( mapN ) ) { + String errorCode= getChildContent( mapN, "error-code" ); + String location= getChildContent( mapN, "location" ); + + if( errorCode!=null && ! "".equals( errorCode ) ) { + try { + int err=new Integer( errorCode ).intValue(); + gen.generateErrorPage( err, location ); + } catch( Exception ex ) { + log.error( "Format error " + location, ex); + } + } + } + + Node lcN=getChild( webN, "login-config" ); + if( lcN!=null ) { + log.info("Generating mapping for login-config " ); + + String authMeth=getContent( getChild( lcN, "auth-method")); + if( authMeth == null ) authMeth="BASIC"; + + Node n1=getChild( lcN, "form-login-config"); + String loginPage= getChildContent( n1, "form-login-page"); + String errPage= getChildContent( n1, "form-error-page"); + + if(loginPage != null) { + int lpos = loginPage.lastIndexOf("/"); + String jscurl = loginPage.substring(0,lpos+1) + "j_security_check"; + gen.generateLoginConfig( jscurl, errPage, authMeth ); + } + } + + log.info("Generating mappings for security constraints " ); + for( Node mapN=getChild( webN, "security-constraint" ); + mapN != null; mapN = getNext( mapN )) { + + Vector methods=new Vector(); + Vector urls=new Vector(); + Vector roles=new Vector(); + boolean isSSL=false; + + Node wrcN=getChild( mapN, "web-resource-collection"); + for( Node uN=getChild(wrcN, "http-method"); + uN!=null; uN=getNext( uN )) { + methods.addElement( getContent( uN )); + } + for( Node uN=getChild(wrcN, "url-pattern"); + uN!=null; uN=getNext( uN )) { + urls.addElement( getContent( uN )); + } + + // Not used at the moment + Node acN=getChild( mapN, "auth-constraint"); + for( Node rN=getChild(acN, "role-name"); + rN!=null; rN=getNext( rN )) { + roles.addElement(getContent( rN )); + } + + Node ucN=getChild( mapN, "user-data-constraint"); + String transp=getContent(getChild( ucN, "transport-guarantee")); + if( transp!=null ) { + if( "INTEGRAL".equalsIgnoreCase( transp ) || + "CONFIDENTIAL".equalsIgnoreCase( transp ) ) { + isSSL=true; + } + } + + gen.generateConstraints( urls, methods, roles, isSSL ); + } + gen.generateEnd(); + } + + // -------------------- Main and ant wrapper -------------------- + + public void execute() { + try { + if( docBase== null) { + log.error("No docbase - please specify the base directory of you web application ( -docBase PATH )"); + return; + } + if( cpath== null) { + log.error("No context - please specify the mount ( -context PATH )"); + return; + } + File docbF=new File(docBase); + File wXmlF=new File( docBase, "WEB-INF/web.xml"); + + Document wXmlN=readXml(wXmlF); + if( wXmlN == null ) return; + + webN = wXmlN.getDocumentElement(); + if( webN==null ) { + log.error("Can't find web-app"); + return; + } + + jkDir=new File( docbF, "WEB-INF/jk2" ); + jkDir.mkdirs(); + + MappingGenerator generator=new GeneratorJk2(); + generator.setWebXmlReader( this ); + generate( generator ); + + generator=new GeneratorJk1(); + generator.setWebXmlReader( this ); + generate( generator ); + + generator=new GeneratorApache2(); + generator.setWebXmlReader( this ); + generate( generator ); + + } catch( Exception ex ) { + ex.printStackTrace(); + } + } + + + public static void main(String args[] ) { + try { + if( args.length == 1 && + ( "-?".equals(args[0]) || "-h".equals( args[0])) ) { + System.out.println("Usage: "); + System.out.println(" WebXml2Jk [OPTIONS]"); + System.out.println(); + System.out.println(" -docBase DIR The location of the webapp. Required"); + System.out.println(" -group GROUP Group, if you have multiple tomcats with diffrent content. " ); + System.out.println(" The default is 'lb', and should be used in most cases"); + System.out.println(" -host HOSTNAME Canonical hostname - for virtual hosts"); + System.out.println(" -context /CPATH Context path where the app will be mounted"); + return; + } + + WebXml2Jk w2jk=new WebXml2Jk(); + + /* do ant-style property setting */ + IntrospectionUtils.processArgs( w2jk, args, new String[] {}, + null, new Hashtable()); + w2jk.execute(); + } catch( Exception ex ) { + ex.printStackTrace(); + } + + } + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( WebXml2Jk.class ); + + + // -------------------- DOM utils -------------------- + + /** Get the content of a node + */ + public static String getContent(Node n ) { + if( n==null ) return null; + Node n1=n.getFirstChild(); + // XXX Check if it's a text node + + String s1=n1.getNodeValue(); + return s1.trim(); + } + + /** Get the first child + */ + public static Node getChild( Node parent, String name ) { + if( parent==null ) return null; + Node first=parent.getFirstChild(); + if( first==null ) return null; + for (Node node = first; node != null; + node = node.getNextSibling()) { + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name.equals( node.getNodeName() ) ) { + return node; + } + } + return null; + } + + /** Get the first child's content ( i.e. it's included TEXT node ) + */ + public static String getChildContent( Node parent, String name ) { + Node first=parent.getFirstChild(); + if( first==null ) return null; + for (Node node = first; node != null; + node = node.getNextSibling()) { + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name.equals( node.getNodeName() ) ) { + return getContent( node ); + } + } + return null; + } + + /** Get the node in the list of siblings + */ + public static Node getNext( Node current ) { + Node first=current.getNextSibling(); + String name=current.getNodeName(); + if( first==null ) return null; + for (Node node = first; node != null; + node = node.getNextSibling()) { + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name.equals( node.getNodeName() ) ) { + return node; + } + } + return null; + } + + public static class NullResolver implements EntityResolver { + public InputSource resolveEntity (String publicId, + String systemId) + throws SAXException, IOException + { + if (log.isDebugEnabled()) + log.debug("ResolveEntity: " + publicId + " " + systemId); + return new InputSource(new StringReader("")); + } + } + + public static Document readXml(File xmlF) + throws SAXException, IOException, ParserConfigurationException + { + if( ! xmlF.exists() ) { + log.error("No xml file " + xmlF ); + return null; + } + DocumentBuilderFactory dbf = + DocumentBuilderFactory.newInstance(); + + dbf.setValidating(false); + dbf.setIgnoringComments(false); + dbf.setIgnoringElementContentWhitespace(true); + //dbf.setCoalescing(true); + //dbf.setExpandEntityReferences(true); + + DocumentBuilder db = null; + db = dbf.newDocumentBuilder(); + db.setEntityResolver( new NullResolver() ); + + // db.setErrorHandler( new MyErrorHandler()); + + Document doc = db.parse(xmlF); + return doc; + } + +} diff --git a/java/org/apache/jk/core/JkChannel.java b/java/org/apache/jk/core/JkChannel.java index a2c8d0b76..d69510662 100644 --- a/java/org/apache/jk/core/JkChannel.java +++ b/java/org/apache/jk/core/JkChannel.java @@ -1,76 +1,76 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.core; - -import java.io.IOException; - -import org.apache.coyote.Request; - -/** - * A Channel represents a connection point to the outside world. - * - * @author Bill Barker - */ - -public interface JkChannel { - - - /** - * Return the identifying name of this Channel. - */ - public String getChannelName(); - - /** - * Send a message back to the client. - * @param msg The message to send. - * @param ep The connection point for this request. - */ - public int send(Msg msg, MsgContext ep) throws IOException; - - /** - * Recieve a message from the client. - * @param msg The place to recieve the data into. - * @param ep The connection point for this request. - */ - public int receive(Msg msg, MsgContext ep) throws IOException; - - /** - * Flush the data to the client. - */ - public int flush(Msg msg, MsgContext ep) throws IOException; - - /** - * Invoke the request chain. - */ - public int invoke(Msg msg, MsgContext ep) throws IOException; - - /** - * Confirm that a shutdown request was recieved form us. - */ - public boolean isSameAddress(MsgContext ep); - - /** - * Register a new Request in the Request pool. - */ - public void registerRequest(Request req, MsgContext ep, int count); - - /** - * Create a new request endpoint. - */ - public MsgContext createMsgContext(); - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.core; + +import java.io.IOException; + +import org.apache.coyote.Request; + +/** + * A Channel represents a connection point to the outside world. + * + * @author Bill Barker + */ + +public interface JkChannel { + + + /** + * Return the identifying name of this Channel. + */ + public String getChannelName(); + + /** + * Send a message back to the client. + * @param msg The message to send. + * @param ep The connection point for this request. + */ + public int send(Msg msg, MsgContext ep) throws IOException; + + /** + * Recieve a message from the client. + * @param msg The place to recieve the data into. + * @param ep The connection point for this request. + */ + public int receive(Msg msg, MsgContext ep) throws IOException; + + /** + * Flush the data to the client. + */ + public int flush(Msg msg, MsgContext ep) throws IOException; + + /** + * Invoke the request chain. + */ + public int invoke(Msg msg, MsgContext ep) throws IOException; + + /** + * Confirm that a shutdown request was recieved form us. + */ + public boolean isSameAddress(MsgContext ep); + + /** + * Register a new Request in the Request pool. + */ + public void registerRequest(Request req, MsgContext ep, int count); + + /** + * Create a new request endpoint. + */ + public MsgContext createMsgContext(); + +} diff --git a/java/org/apache/jk/core/JkHandler.java b/java/org/apache/jk/core/JkHandler.java index db089315e..3fbdaad52 100644 --- a/java/org/apache/jk/core/JkHandler.java +++ b/java/org/apache/jk/core/JkHandler.java @@ -1,196 +1,196 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.core; - -import java.io.IOException; -import java.util.Properties; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; - -import org.apache.tomcat.util.modeler.Registry; - -/** - * - * @author Costin Manolache - */ -public class JkHandler implements MBeanRegistration, NotificationListener { - public static final int OK=0; - public static final int LAST=1; - public static final int ERROR=2; - - protected Properties properties=new Properties(); - protected WorkerEnv wEnv; - protected JkHandler next; - protected String nextName=null; - protected String name; - protected int id; - - // XXX Will be replaced with notes and (configurable) ids - // Each represents a 'chain' - similar with ActionCode in Coyote ( the concepts - // will be merged ). - public static final int HANDLE_RECEIVE_PACKET = 10; - public static final int HANDLE_SEND_PACKET = 11; - public static final int HANDLE_FLUSH = 12; - public static final int HANDLE_THREAD_END = 13; - - public void setWorkerEnv( WorkerEnv we ) { - this.wEnv=we; - } - - /** Set the name of the handler. Will allways be called by - * worker env after creating the worker. - */ - public void setName(String s ) { - name=s; - } - - public String getName() { - return name; - } - - /** Set the id of the worker. We use an id for faster dispatch. - * Since we expect a decent number of handler in system, the - * id is unique - that means we may have to allocate bigger - * dispatch tables. ( easy to fix if needed ) - */ - public void setId( int id ) { - this.id=id; - } - - public int getId() { - return id; - } - - /** Catalina-style "recursive" invocation. - * A chain is used for Apache/3.3 style iterative invocation. - */ - public void setNext( JkHandler h ) { - next=h; - } - - public void setNext( String s ) { - nextName=s; - } - - public String getNext() { - if( nextName==null ) { - if( next!=null) - nextName=next.getName(); - } - return nextName; - } - - /** Should register the request types it can handle, - * same style as apache2. - */ - public void init() throws IOException { - } - - /** Clean up and stop the handler - */ - public void destroy() throws IOException { - } - - public MsgContext createMsgContext() { - return new MsgContext(); - } - - public int invoke(Msg msg, MsgContext mc ) throws IOException { - return OK; - } - - public void setProperty( String name, String value ) { - properties.put( name, value ); - } - - public String getProperty( String name ) { - return properties.getProperty(name) ; - } - - /** Experimental, will be replaced. This allows handlers to be - * notified when other handlers are added. - */ - public void addHandlerCallback( JkHandler w ) { - - } - - public void handleNotification(Notification notification, Object handback) - { -// BaseNotification bNot=(BaseNotification)notification; -// int code=bNot.getCode(); -// -// MsgContext ctx=(MsgContext)bNot.getSource(); - - - } - - protected String domain; - protected ObjectName oname; - protected MBeanServer mserver; - - public ObjectName getObjectName() { - return oname; - } - - public String getDomain() { - return domain; - } - - public ObjectName preRegister(MBeanServer server, - ObjectName oname) throws Exception { - this.oname=oname; - mserver=server; - domain=oname.getDomain(); - if( name==null ) { - name=oname.getKeyProperty("name"); - } - - // we need to create a workerEnv or set one. - ObjectName wEnvName=new ObjectName(domain + ":type=JkWorkerEnv"); - if ( wEnv == null ) { - wEnv=new WorkerEnv(); - } - if( ! mserver.isRegistered(wEnvName )) { - Registry.getRegistry(null, null).registerComponent(wEnv, wEnvName, null); - } - mserver.invoke( wEnvName, "addHandler", - new Object[] {name, this}, - new String[] {"java.lang.String", - "org.apache.jk.core.JkHandler"}); - return oname; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - public void pause() throws Exception { - } - - public void resume() throws Exception { - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.core; + +import java.io.IOException; +import java.util.Properties; + +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; + +import org.apache.tomcat.util.modeler.Registry; + +/** + * + * @author Costin Manolache + */ +public class JkHandler implements MBeanRegistration, NotificationListener { + public static final int OK=0; + public static final int LAST=1; + public static final int ERROR=2; + + protected Properties properties=new Properties(); + protected WorkerEnv wEnv; + protected JkHandler next; + protected String nextName=null; + protected String name; + protected int id; + + // XXX Will be replaced with notes and (configurable) ids + // Each represents a 'chain' - similar with ActionCode in Coyote ( the concepts + // will be merged ). + public static final int HANDLE_RECEIVE_PACKET = 10; + public static final int HANDLE_SEND_PACKET = 11; + public static final int HANDLE_FLUSH = 12; + public static final int HANDLE_THREAD_END = 13; + + public void setWorkerEnv( WorkerEnv we ) { + this.wEnv=we; + } + + /** Set the name of the handler. Will allways be called by + * worker env after creating the worker. + */ + public void setName(String s ) { + name=s; + } + + public String getName() { + return name; + } + + /** Set the id of the worker. We use an id for faster dispatch. + * Since we expect a decent number of handler in system, the + * id is unique - that means we may have to allocate bigger + * dispatch tables. ( easy to fix if needed ) + */ + public void setId( int id ) { + this.id=id; + } + + public int getId() { + return id; + } + + /** Catalina-style "recursive" invocation. + * A chain is used for Apache/3.3 style iterative invocation. + */ + public void setNext( JkHandler h ) { + next=h; + } + + public void setNext( String s ) { + nextName=s; + } + + public String getNext() { + if( nextName==null ) { + if( next!=null) + nextName=next.getName(); + } + return nextName; + } + + /** Should register the request types it can handle, + * same style as apache2. + */ + public void init() throws IOException { + } + + /** Clean up and stop the handler + */ + public void destroy() throws IOException { + } + + public MsgContext createMsgContext() { + return new MsgContext(); + } + + public int invoke(Msg msg, MsgContext mc ) throws IOException { + return OK; + } + + public void setProperty( String name, String value ) { + properties.put( name, value ); + } + + public String getProperty( String name ) { + return properties.getProperty(name) ; + } + + /** Experimental, will be replaced. This allows handlers to be + * notified when other handlers are added. + */ + public void addHandlerCallback( JkHandler w ) { + + } + + public void handleNotification(Notification notification, Object handback) + { +// BaseNotification bNot=(BaseNotification)notification; +// int code=bNot.getCode(); +// +// MsgContext ctx=(MsgContext)bNot.getSource(); + + + } + + protected String domain; + protected ObjectName oname; + protected MBeanServer mserver; + + public ObjectName getObjectName() { + return oname; + } + + public String getDomain() { + return domain; + } + + public ObjectName preRegister(MBeanServer server, + ObjectName oname) throws Exception { + this.oname=oname; + mserver=server; + domain=oname.getDomain(); + if( name==null ) { + name=oname.getKeyProperty("name"); + } + + // we need to create a workerEnv or set one. + ObjectName wEnvName=new ObjectName(domain + ":type=JkWorkerEnv"); + if ( wEnv == null ) { + wEnv=new WorkerEnv(); + } + if( ! mserver.isRegistered(wEnvName )) { + Registry.getRegistry(null, null).registerComponent(wEnv, wEnvName, null); + } + mserver.invoke( wEnvName, "addHandler", + new Object[] {name, this}, + new String[] {"java.lang.String", + "org.apache.jk.core.JkHandler"}); + return oname; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + public void pause() throws Exception { + } + + public void resume() throws Exception { + } + +} diff --git a/java/org/apache/jk/core/Msg.java b/java/org/apache/jk/core/Msg.java index 0a63a967d..8176dc014 100644 --- a/java/org/apache/jk/core/Msg.java +++ b/java/org/apache/jk/core/Msg.java @@ -1,153 +1,153 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.core; - -import java.io.IOException; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; - - -/** - * A single packet for communication between the web server and the - * container. - * - * In a more generic sense, it's the event that drives the processing chain. - * XXX Use Event, make Msg a particular case. - * - * @author Henri Gomez [hgomez@apache.org] - * @author Dan Milstein [danmil@shore.net] - * @author Keith Wannamaker [Keith@Wannamaker.org] - * @author Kevin Seguin - * @author Costin Manolache - */ -public abstract class Msg { - - - - /** - * Prepare this packet for accumulating a message from the container to - * the web server. Set the write position to just after the header - * (but leave the length unwritten, because it is as yet unknown). - */ - public abstract void reset(); - - /** - * For a packet to be sent to the web server, finish the process of - * accumulating data and write the length of the data payload into - * the header. - */ - public abstract void end(); - - public abstract void appendInt( int val ); - - public abstract void appendByte( int val ); - - public abstract void appendLongInt( int val ); - - /** - */ - public abstract void appendBytes(MessageBytes mb) throws IOException; - - public abstract void appendByteChunk(ByteChunk bc) throws IOException; - - /** - * Copy a chunk of bytes into the packet, starting at the current - * write position. The chunk of bytes is encoded with the length - * in two bytes first, then the data itself, and finally a - * terminating \0 (which is not included in the encoded - * length). - * - * @param b The array from which to copy bytes. - * @param off The offset into the array at which to start copying - * @param numBytes The number of bytes to copy. - */ - public abstract void appendBytes( byte b[], int off, int numBytes ); - - /** - * Read an integer from packet, and advance the read position past - * it. Integers are encoded as two unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public abstract int getInt(); - - public abstract int peekInt(); - - public abstract byte getByte(); - - public abstract byte peekByte(); - - public abstract void getBytes(MessageBytes mb); - - /** - * Copy a chunk of bytes from the packet into an array and advance - * the read position past the chunk. See appendBytes() for details - * on the encoding. - * - * @return The number of bytes copied. - */ - public abstract int getBytes(byte dest[]); - - /** - * Read a 32 bits integer from packet, and advance the read position past - * it. Integers are encoded as four unsigned bytes with the - * high-order byte first, and, as far as I can tell, in - * little-endian order within each byte. - */ - public abstract int getLongInt(); - - public abstract int getHeaderLength(); - - public abstract int processHeader(); - - public abstract byte[] getBuffer(); - - public abstract int getLen(); - - public abstract void dump(String msg); - - /* -------------------- Utilities -------------------- */ - // XXX Move to util package - - public static String hexLine( byte buf[], int start, int len ) { - StringBuffer sb=new StringBuffer(); - for( int i=start; i< start+16 ; i++ ) { - if( i < len + 4) - sb.append( hex( buf[i] ) + " "); - else - sb.append( " " ); - } - sb.append(" | "); - for( int i=start; i < start+16 && i < len + 4; i++ ) { - if( ! Character.isISOControl( (char)buf[i] )) - sb.append( new Character((char)buf[i]) ); - else - sb.append( "." ); - } - return sb.toString(); - } - - private static String hex( int x ) { - // if( x < 0) x=256 + x; - String h=Integer.toHexString( x ); - if( h.length() == 1 ) h = "0" + h; - return h.substring( h.length() - 2 ); - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.core; + +import java.io.IOException; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; + + +/** + * A single packet for communication between the web server and the + * container. + * + * In a more generic sense, it's the event that drives the processing chain. + * XXX Use Event, make Msg a particular case. + * + * @author Henri Gomez [hgomez@apache.org] + * @author Dan Milstein [danmil@shore.net] + * @author Keith Wannamaker [Keith@Wannamaker.org] + * @author Kevin Seguin + * @author Costin Manolache + */ +public abstract class Msg { + + + + /** + * Prepare this packet for accumulating a message from the container to + * the web server. Set the write position to just after the header + * (but leave the length unwritten, because it is as yet unknown). + */ + public abstract void reset(); + + /** + * For a packet to be sent to the web server, finish the process of + * accumulating data and write the length of the data payload into + * the header. + */ + public abstract void end(); + + public abstract void appendInt( int val ); + + public abstract void appendByte( int val ); + + public abstract void appendLongInt( int val ); + + /** + */ + public abstract void appendBytes(MessageBytes mb) throws IOException; + + public abstract void appendByteChunk(ByteChunk bc) throws IOException; + + /** + * Copy a chunk of bytes into the packet, starting at the current + * write position. The chunk of bytes is encoded with the length + * in two bytes first, then the data itself, and finally a + * terminating \0 (which is not included in the encoded + * length). + * + * @param b The array from which to copy bytes. + * @param off The offset into the array at which to start copying + * @param numBytes The number of bytes to copy. + */ + public abstract void appendBytes( byte b[], int off, int numBytes ); + + /** + * Read an integer from packet, and advance the read position past + * it. Integers are encoded as two unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public abstract int getInt(); + + public abstract int peekInt(); + + public abstract byte getByte(); + + public abstract byte peekByte(); + + public abstract void getBytes(MessageBytes mb); + + /** + * Copy a chunk of bytes from the packet into an array and advance + * the read position past the chunk. See appendBytes() for details + * on the encoding. + * + * @return The number of bytes copied. + */ + public abstract int getBytes(byte dest[]); + + /** + * Read a 32 bits integer from packet, and advance the read position past + * it. Integers are encoded as four unsigned bytes with the + * high-order byte first, and, as far as I can tell, in + * little-endian order within each byte. + */ + public abstract int getLongInt(); + + public abstract int getHeaderLength(); + + public abstract int processHeader(); + + public abstract byte[] getBuffer(); + + public abstract int getLen(); + + public abstract void dump(String msg); + + /* -------------------- Utilities -------------------- */ + // XXX Move to util package + + public static String hexLine( byte buf[], int start, int len ) { + StringBuffer sb=new StringBuffer(); + for( int i=start; i< start+16 ; i++ ) { + if( i < len + 4) + sb.append( hex( buf[i] ) + " "); + else + sb.append( " " ); + } + sb.append(" | "); + for( int i=start; i < start+16 && i < len + 4; i++ ) { + if( ! Character.isISOControl( (char)buf[i] )) + sb.append( new Character((char)buf[i]) ); + else + sb.append( "." ); + } + return sb.toString(); + } + + private static String hex( int x ) { + // if( x < 0) x=256 + x; + String h=Integer.toHexString( x ); + if( h.length() == 1 ) h = "0" + h; + return h.substring( h.length() - 2 ); + } + + +} diff --git a/java/org/apache/jk/core/MsgContext.java b/java/org/apache/jk/core/MsgContext.java index daa74ab03..10963ce61 100644 --- a/java/org/apache/jk/core/MsgContext.java +++ b/java/org/apache/jk/core/MsgContext.java @@ -1,381 +1,381 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.core; - -import java.io.IOException; -import java.io.ByteArrayInputStream; -import java.net.InetAddress; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; - -import org.apache.coyote.ActionCode; -import org.apache.coyote.ActionHook; -import org.apache.coyote.Request; -import org.apache.coyote.Response; - -import org.apache.tomcat.util.buf.C2BConverter; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.jk.common.JkInputStream; - - -/** - * - * @author Henri Gomez [hgomez@apache.org] - * @author Dan Milstein [danmil@shore.net] - * @author Keith Wannamaker [Keith@Wannamaker.org] - * @author Kevin Seguin - * @author Costin Manolache - */ -public class MsgContext implements ActionHook { - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(MsgContext.class); - private static org.apache.commons.logging.Log logTime= - org.apache.commons.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" ); - - private int type; - private Object notes[]=new Object[32]; - private JkHandler next; - private JkChannel source; - private JkInputStream jkIS = new JkInputStream(this); - private C2BConverter c2b; - private Request req; - private WorkerEnv wEnv; - private Msg msgs[]=new Msg[10]; - private int status=0; - // Control object - private Object control; - - // Application managed, like notes - private long timers[]=new long[20]; - - // The context can be used by JNI components as well - private long jkEndpointP; - private long xEnvP; - - // Temp: use notes and dynamic strings - public static final int TIMER_RECEIVED=0; - public static final int TIMER_PRE_REQUEST=1; - public static final int TIMER_POST_REQUEST=2; - - // Status codes - public static final int JK_STATUS_NEW=0; - public static final int JK_STATUS_HEAD=1; - public static final int JK_STATUS_CLOSED=2; - public static final int JK_STATUS_ERROR=3; - - public MsgContext() { - try { - c2b = new C2BConverter("iso-8859-1"); - } catch(IOException iex) { - log.warn("Can't happen", iex); - } - } - - public final Object getNote( int id ) { - return notes[id]; - } - - public final void setNote( int id, Object o ) { - notes[id]=o; - } - - /** The id of the chain */ - public final int getType() { - return type; - } - - public final void setType(int i) { - type=i; - } - - public final void setLong( int i, long l) { - timers[i]=l; - } - - public final long getLong( int i) { - return timers[i]; - } - - // Common attributes ( XXX should be notes for flexibility ? ) - - public final WorkerEnv getWorkerEnv() { - return wEnv; - } - - public final void setWorkerEnv( WorkerEnv we ) { - this.wEnv=we; - } - - public final JkChannel getSource() { - return source; - } - - public final void setSource(JkChannel ch) { - this.source=ch; - } - - public final int getStatus() { - return status; - } - - public final void setStatus( int s ) { - status=s; - } - - public final JkHandler getNext() { - return next; - } - - public final void setNext(JkHandler ch) { - this.next=ch; - } - - /** The high level request object associated with this context - */ - public final void setRequest( Request req ) { - this.req=req; - req.setInputBuffer(jkIS); - Response res = req.getResponse(); - res.setOutputBuffer(jkIS); - res.setHook(this); - } - - public final Request getRequest() { - return req; - } - - /** The context may store a number of messages ( buffers + marshalling ) - */ - public final Msg getMsg(int i) { - return msgs[i]; - } - - public final void setMsg(int i, Msg msg) { - this.msgs[i]=msg; - } - - public final C2BConverter getConverter() { - return c2b; - } - - public final void setConverter(C2BConverter c2b) { - this.c2b = c2b; - } - - public final boolean isLogTimeEnabled() { - return logTime.isDebugEnabled(); - } - - public JkInputStream getInputStream() { - return jkIS; - } - - /** Each context contains a number of byte[] buffers used for communication. - * The C side will contain a char * equivalent - both buffers are long-lived - * and recycled. - * - * This will be called at init time. A long-lived global reference to the byte[] - * will be stored in the C context. - */ - public byte[] getBuffer( int id ) { - // We use a single buffer right now. - if( msgs[id]==null ) { - return null; - } - return msgs[id].getBuffer(); - } - - /** Invoke a java hook. The xEnv is the representation of the current execution - * environment ( the jni_env_t * ) - */ - public int execute() throws IOException { - int status=next.invoke(msgs[0], this); - return status; - } - - // -------------------- Jni support -------------------- - - /** Store native execution context data when this handler is called - * from JNI. This will change on each call, represent temproary - * call data. - */ - public void setJniEnv( long xEnvP ) { - this.xEnvP=xEnvP; - } - - public long getJniEnv() { - return xEnvP; - } - - /** The long-lived JNI context associated with this java context. - * The 2 share pointers to buffers and cache data to avoid expensive - * jni calls. - */ - public void setJniContext( long cContext ) { - this.jkEndpointP=cContext; - } - - public long getJniContext() { - return jkEndpointP; - } - - public Object getControl() { - return control; - } - - public void setControl(Object control) { - this.control = control; - } - - // -------------------- Coyote Action implementation -------------------- - - public void action(ActionCode actionCode, Object param) { - if( actionCode==ActionCode.ACTION_COMMIT ) { - if( log.isDebugEnabled() ) log.debug("COMMIT " ); - Response res=(Response)param; - - if( res.isCommitted() ) { - if( log.isDebugEnabled() ) - log.debug("Response already committed " ); - } else { - try { - jkIS.appendHead( res ); - } catch(IOException iex) { - log.warn("Unable to send headers",iex); - setStatus(JK_STATUS_ERROR); - } - } - } else if( actionCode==ActionCode.ACTION_RESET ) { - if( log.isDebugEnabled() ) - log.debug("RESET " ); - - } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) { - if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " ); - try { - source.flush( null, this ); - } catch(IOException iex) { - // This is logged elsewhere, so debug only here - log.debug("Error during flush",iex); - Response res = (Response)param; - res.setErrorException(iex); - setStatus(JK_STATUS_ERROR); - } - - } else if( actionCode==ActionCode.ACTION_CLOSE ) { - if( log.isDebugEnabled() ) log.debug("CLOSE " ); - - Response res=(Response)param; - if( getStatus()== JK_STATUS_CLOSED || getStatus() == JK_STATUS_ERROR) { - // Double close - it may happen with forward - if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() ); - return; - } - - if( !res.isCommitted() ) - this.action( ActionCode.ACTION_COMMIT, param ); - try { - jkIS.endMessage(); - } catch(IOException iex) { - log.warn("Error sending end packet",iex); - setStatus(JK_STATUS_ERROR); - } - if(getStatus() != JK_STATUS_ERROR) { - setStatus(JK_STATUS_CLOSED ); - } - - if( logTime.isDebugEnabled() ) - logTime(res.getRequest(), res); - } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { - Request req=(Request)param; - - // Extract SSL certificate information (if requested) - MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); - if( certString != null && !certString.isNull() ) { - ByteChunk certData = certString.getByteChunk(); - ByteArrayInputStream bais = - new ByteArrayInputStream(certData.getBytes(), - certData.getStart(), - certData.getLength()); - - // Fill the first element. - X509Certificate jsseCerts[] = null; - try { - CertificateFactory cf = - CertificateFactory.getInstance("X.509"); - X509Certificate cert = (X509Certificate) - cf.generateCertificate(bais); - jsseCerts = new X509Certificate[1]; - jsseCerts[0] = cert; - } catch(java.security.cert.CertificateException e) { - log.error("Certificate convertion failed" , e ); - return; - } - - req.setAttribute(SSLSupport.CERTIFICATE_KEY, - jsseCerts); - } - - } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) { - Request req=(Request)param; - - // If remoteHost not set by JK, get it's name from it's remoteAddr - if( req.remoteHost().isNull()) { - try { - req.remoteHost().setString(InetAddress.getByName( - req.remoteAddr().toString()). - getHostName()); - } catch(IOException iex) { - if(log.isDebugEnabled()) - log.debug("Unable to resolve "+req.remoteAddr()); - } - } - } else if( actionCode==ActionCode.ACTION_ACK ) { - if( log.isTraceEnabled() ) - log.trace("ACK " ); - } else if ( actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY ) { - if( log.isTraceEnabled() ) - log.trace("Replay "); - ByteChunk bc = (ByteChunk)param; - jkIS.setReplay(bc); - } - } - - - private void logTime(Request req, Response res ) { - // called after the request - // org.apache.coyote.Request req=(org.apache.coyote.Request)param; - // Response res=req.getResponse(); - String uri=req.requestURI().toString(); - if( uri.indexOf( ".gif" ) >0 ) return; - - setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis()); - long t1= getLong( MsgContext.TIMER_PRE_REQUEST ) - - getLong( MsgContext.TIMER_RECEIVED ); - long t2= getLong( MsgContext.TIMER_POST_REQUEST ) - - getLong( MsgContext.TIMER_PRE_REQUEST ); - - logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " + - res.getContentLength() + " " + - uri ); - } - - public void recycle() { - jkIS.recycle(); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.core; + +import java.io.IOException; +import java.io.ByteArrayInputStream; +import java.net.InetAddress; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +import org.apache.coyote.ActionCode; +import org.apache.coyote.ActionHook; +import org.apache.coyote.Request; +import org.apache.coyote.Response; + +import org.apache.tomcat.util.buf.C2BConverter; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.jk.common.JkInputStream; + + +/** + * + * @author Henri Gomez [hgomez@apache.org] + * @author Dan Milstein [danmil@shore.net] + * @author Keith Wannamaker [Keith@Wannamaker.org] + * @author Kevin Seguin + * @author Costin Manolache + */ +public class MsgContext implements ActionHook { + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(MsgContext.class); + private static org.apache.commons.logging.Log logTime= + org.apache.commons.logging.LogFactory.getLog( "org.apache.jk.REQ_TIME" ); + + private int type; + private Object notes[]=new Object[32]; + private JkHandler next; + private JkChannel source; + private JkInputStream jkIS = new JkInputStream(this); + private C2BConverter c2b; + private Request req; + private WorkerEnv wEnv; + private Msg msgs[]=new Msg[10]; + private int status=0; + // Control object + private Object control; + + // Application managed, like notes + private long timers[]=new long[20]; + + // The context can be used by JNI components as well + private long jkEndpointP; + private long xEnvP; + + // Temp: use notes and dynamic strings + public static final int TIMER_RECEIVED=0; + public static final int TIMER_PRE_REQUEST=1; + public static final int TIMER_POST_REQUEST=2; + + // Status codes + public static final int JK_STATUS_NEW=0; + public static final int JK_STATUS_HEAD=1; + public static final int JK_STATUS_CLOSED=2; + public static final int JK_STATUS_ERROR=3; + + public MsgContext() { + try { + c2b = new C2BConverter("iso-8859-1"); + } catch(IOException iex) { + log.warn("Can't happen", iex); + } + } + + public final Object getNote( int id ) { + return notes[id]; + } + + public final void setNote( int id, Object o ) { + notes[id]=o; + } + + /** The id of the chain */ + public final int getType() { + return type; + } + + public final void setType(int i) { + type=i; + } + + public final void setLong( int i, long l) { + timers[i]=l; + } + + public final long getLong( int i) { + return timers[i]; + } + + // Common attributes ( XXX should be notes for flexibility ? ) + + public final WorkerEnv getWorkerEnv() { + return wEnv; + } + + public final void setWorkerEnv( WorkerEnv we ) { + this.wEnv=we; + } + + public final JkChannel getSource() { + return source; + } + + public final void setSource(JkChannel ch) { + this.source=ch; + } + + public final int getStatus() { + return status; + } + + public final void setStatus( int s ) { + status=s; + } + + public final JkHandler getNext() { + return next; + } + + public final void setNext(JkHandler ch) { + this.next=ch; + } + + /** The high level request object associated with this context + */ + public final void setRequest( Request req ) { + this.req=req; + req.setInputBuffer(jkIS); + Response res = req.getResponse(); + res.setOutputBuffer(jkIS); + res.setHook(this); + } + + public final Request getRequest() { + return req; + } + + /** The context may store a number of messages ( buffers + marshalling ) + */ + public final Msg getMsg(int i) { + return msgs[i]; + } + + public final void setMsg(int i, Msg msg) { + this.msgs[i]=msg; + } + + public final C2BConverter getConverter() { + return c2b; + } + + public final void setConverter(C2BConverter c2b) { + this.c2b = c2b; + } + + public final boolean isLogTimeEnabled() { + return logTime.isDebugEnabled(); + } + + public JkInputStream getInputStream() { + return jkIS; + } + + /** Each context contains a number of byte[] buffers used for communication. + * The C side will contain a char * equivalent - both buffers are long-lived + * and recycled. + * + * This will be called at init time. A long-lived global reference to the byte[] + * will be stored in the C context. + */ + public byte[] getBuffer( int id ) { + // We use a single buffer right now. + if( msgs[id]==null ) { + return null; + } + return msgs[id].getBuffer(); + } + + /** Invoke a java hook. The xEnv is the representation of the current execution + * environment ( the jni_env_t * ) + */ + public int execute() throws IOException { + int status=next.invoke(msgs[0], this); + return status; + } + + // -------------------- Jni support -------------------- + + /** Store native execution context data when this handler is called + * from JNI. This will change on each call, represent temproary + * call data. + */ + public void setJniEnv( long xEnvP ) { + this.xEnvP=xEnvP; + } + + public long getJniEnv() { + return xEnvP; + } + + /** The long-lived JNI context associated with this java context. + * The 2 share pointers to buffers and cache data to avoid expensive + * jni calls. + */ + public void setJniContext( long cContext ) { + this.jkEndpointP=cContext; + } + + public long getJniContext() { + return jkEndpointP; + } + + public Object getControl() { + return control; + } + + public void setControl(Object control) { + this.control = control; + } + + // -------------------- Coyote Action implementation -------------------- + + public void action(ActionCode actionCode, Object param) { + if( actionCode==ActionCode.ACTION_COMMIT ) { + if( log.isDebugEnabled() ) log.debug("COMMIT " ); + Response res=(Response)param; + + if( res.isCommitted() ) { + if( log.isDebugEnabled() ) + log.debug("Response already committed " ); + } else { + try { + jkIS.appendHead( res ); + } catch(IOException iex) { + log.warn("Unable to send headers",iex); + setStatus(JK_STATUS_ERROR); + } + } + } else if( actionCode==ActionCode.ACTION_RESET ) { + if( log.isDebugEnabled() ) + log.debug("RESET " ); + + } else if( actionCode==ActionCode.ACTION_CLIENT_FLUSH ) { + if( log.isDebugEnabled() ) log.debug("CLIENT_FLUSH " ); + try { + source.flush( null, this ); + } catch(IOException iex) { + // This is logged elsewhere, so debug only here + log.debug("Error during flush",iex); + Response res = (Response)param; + res.setErrorException(iex); + setStatus(JK_STATUS_ERROR); + } + + } else if( actionCode==ActionCode.ACTION_CLOSE ) { + if( log.isDebugEnabled() ) log.debug("CLOSE " ); + + Response res=(Response)param; + if( getStatus()== JK_STATUS_CLOSED || getStatus() == JK_STATUS_ERROR) { + // Double close - it may happen with forward + if( log.isDebugEnabled() ) log.debug("Double CLOSE - forward ? " + res.getRequest().requestURI() ); + return; + } + + if( !res.isCommitted() ) + this.action( ActionCode.ACTION_COMMIT, param ); + try { + jkIS.endMessage(); + } catch(IOException iex) { + log.warn("Error sending end packet",iex); + setStatus(JK_STATUS_ERROR); + } + if(getStatus() != JK_STATUS_ERROR) { + setStatus(JK_STATUS_CLOSED ); + } + + if( logTime.isDebugEnabled() ) + logTime(res.getRequest(), res); + } else if( actionCode==ActionCode.ACTION_REQ_SSL_ATTRIBUTE ) { + Request req=(Request)param; + + // Extract SSL certificate information (if requested) + MessageBytes certString = (MessageBytes)req.getNote(WorkerEnv.SSL_CERT_NOTE); + if( certString != null && !certString.isNull() ) { + ByteChunk certData = certString.getByteChunk(); + ByteArrayInputStream bais = + new ByteArrayInputStream(certData.getBytes(), + certData.getStart(), + certData.getLength()); + + // Fill the first element. + X509Certificate jsseCerts[] = null; + try { + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + X509Certificate cert = (X509Certificate) + cf.generateCertificate(bais); + jsseCerts = new X509Certificate[1]; + jsseCerts[0] = cert; + } catch(java.security.cert.CertificateException e) { + log.error("Certificate convertion failed" , e ); + return; + } + + req.setAttribute(SSLSupport.CERTIFICATE_KEY, + jsseCerts); + } + + } else if( actionCode==ActionCode.ACTION_REQ_HOST_ATTRIBUTE ) { + Request req=(Request)param; + + // If remoteHost not set by JK, get it's name from it's remoteAddr + if( req.remoteHost().isNull()) { + try { + req.remoteHost().setString(InetAddress.getByName( + req.remoteAddr().toString()). + getHostName()); + } catch(IOException iex) { + if(log.isDebugEnabled()) + log.debug("Unable to resolve "+req.remoteAddr()); + } + } + } else if( actionCode==ActionCode.ACTION_ACK ) { + if( log.isTraceEnabled() ) + log.trace("ACK " ); + } else if ( actionCode == ActionCode.ACTION_REQ_SET_BODY_REPLAY ) { + if( log.isTraceEnabled() ) + log.trace("Replay "); + ByteChunk bc = (ByteChunk)param; + jkIS.setReplay(bc); + } + } + + + private void logTime(Request req, Response res ) { + // called after the request + // org.apache.coyote.Request req=(org.apache.coyote.Request)param; + // Response res=req.getResponse(); + String uri=req.requestURI().toString(); + if( uri.indexOf( ".gif" ) >0 ) return; + + setLong( MsgContext.TIMER_POST_REQUEST, System.currentTimeMillis()); + long t1= getLong( MsgContext.TIMER_PRE_REQUEST ) - + getLong( MsgContext.TIMER_RECEIVED ); + long t2= getLong( MsgContext.TIMER_POST_REQUEST ) - + getLong( MsgContext.TIMER_PRE_REQUEST ); + + logTime.debug("Time pre=" + t1 + "/ service=" + t2 + " " + + res.getContentLength() + " " + + uri ); + } + + public void recycle() { + jkIS.recycle(); + } +} diff --git a/java/org/apache/jk/core/WorkerEnv.java b/java/org/apache/jk/core/WorkerEnv.java index 2ff0a285d..5392460e5 100644 --- a/java/org/apache/jk/core/WorkerEnv.java +++ b/java/org/apache/jk/core/WorkerEnv.java @@ -1,144 +1,144 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.core; - -import java.util.Hashtable; -import javax.management.ObjectName; - -/** - * The controller object. It manages all other jk objects, acting as the root of - * the jk object model. - * - * @author Gal Shachor - * @author Henri Gomez [hgomez@apache.org] - * @author Dan Milstein [danmil@shore.net] - * @author Keith Wannamaker [Keith@Wannamaker.org] - * @author Kevin Seguin - * @author Costin Manolache - */ -public class WorkerEnv { - - Hashtable properties; - - public static final int ENDPOINT_NOTE=0; - public static final int REQUEST_NOTE=1; - public static final int SSL_CERT_NOTE=16; - int noteId[]=new int[4]; - String noteName[][]=new String[4][]; - private Object notes[]=new Object[32]; - - Hashtable handlersMap=new Hashtable(); - JkHandler handlersTable[]=new JkHandler[20]; - int handlerCount=0; - - // base dir for the jk webapp - String home; - int localId=0; - - public WorkerEnv() { - for( int i=0; i handlersTable.length ) { - JkHandler newT[]=new JkHandler[ 2 * handlersTable.length ]; - System.arraycopy( handlersTable, 0, newT, 0, handlersTable.length ); - handlersTable=newT; - } - if(oldH == null) { - handlersTable[handlerCount]=w; - w.setId( handlerCount ); - handlerCount++; - } else { - handlersTable[oldH.getId()]=w; - w.setId(oldH.getId()); - } - - // Notify all other handlers of the new one - // XXX Could be a Coyote action ? - for( int i=0; i< handlerCount ; i++ ) { - handlersTable[i].addHandlerCallback( w ); - } - } - - public final JkHandler getHandler( String name ) { - return (JkHandler)handlersMap.get(name); - } - - public final JkHandler getHandler( int id ) { - return handlersTable[id]; - } - - public final int getHandlerCount() { - return handlerCount; - } - - public ObjectName[] getHandlersObjectName() { - - ObjectName onames[]=new ObjectName[ handlerCount ]; - for( int i=0; i handlersTable.length ) { + JkHandler newT[]=new JkHandler[ 2 * handlersTable.length ]; + System.arraycopy( handlersTable, 0, newT, 0, handlersTable.length ); + handlersTable=newT; + } + if(oldH == null) { + handlersTable[handlerCount]=w; + w.setId( handlerCount ); + handlerCount++; + } else { + handlersTable[oldH.getId()]=w; + w.setId(oldH.getId()); + } + + // Notify all other handlers of the new one + // XXX Could be a Coyote action ? + for( int i=0; i< handlerCount ; i++ ) { + handlersTable[i].addHandlerCallback( w ); + } + } + + public final JkHandler getHandler( String name ) { + return (JkHandler)handlersMap.get(name); + } + + public final JkHandler getHandler( int id ) { + return handlersTable[id]; + } + + public final int getHandlerCount() { + return handlerCount; + } + + public ObjectName[] getHandlersObjectName() { + + ObjectName onames[]=new ObjectName[ handlerCount ]; + for( int i=0; i - - - - - -

        Jk2 interfaces

        -

        Core interfaces for jk2, similar with the interfaces defined in the C -side ( jk2/include ).
        -

        -

        The implementations are in common/ and server/.
        -

        -


        -

        - - + + + + + + +

        Jk2 interfaces

        +

        Core interfaces for jk2, similar with the interfaces defined in the C +side ( jk2/include ).
        +

        +

        The implementations are in common/ and server/.
        +

        +


        +

        + + diff --git a/java/org/apache/jk/mbeans-descriptors.xml b/java/org/apache/jk/mbeans-descriptors.xml index 2b9345d06..b43af8576 100644 --- a/java/org/apache/jk/mbeans-descriptors.xml +++ b/java/org/apache/jk/mbeans-descriptors.xml @@ -1,538 +1,538 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/jk/server/JkCoyoteHandler.java b/java/org/apache/jk/server/JkCoyoteHandler.java index 91a1cda84..684b4d6a6 100644 --- a/java/org/apache/jk/server/JkCoyoteHandler.java +++ b/java/org/apache/jk/server/JkCoyoteHandler.java @@ -1,227 +1,227 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.server; - -import java.io.IOException; -import java.util.Iterator; - -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.coyote.Adapter; -import org.apache.coyote.ProtocolHandler; -import org.apache.coyote.Request; -import org.apache.coyote.Response; -import org.apache.coyote.RequestInfo; -import org.apache.coyote.Constants; -import org.apache.jk.common.HandlerRequest; -import org.apache.jk.common.JkInputStream; -import org.apache.jk.common.MsgAjp; -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.Msg; -import org.apache.jk.core.MsgContext; -import org.apache.jk.core.WorkerEnv; -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.C2BConverter; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.http.HttpMessages; -import org.apache.tomcat.util.http.MimeHeaders; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.tomcat.util.net.SSLSupport; - -/** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container" - * - * jmx:notification-handler name="org.apache.jk.SEND_PACKET - * jmx:notification-handler name="org.apache.coyote.ACTION_COMMIT - */ -public class JkCoyoteHandler extends JkHandler implements ProtocolHandler { - protected static org.apache.commons.logging.Log log - = org.apache.commons.logging.LogFactory.getLog(JkCoyoteHandler.class); - // Set debug on this logger to see the container request time - - // ----------------------------------------------------------- DoPrivileged - private boolean paused = false; - int epNote; - Adapter adapter; - protected JkMain jkMain=null; - - /** Set a property. Name is a "component.property". JMX should - * be used instead. - */ - public void setProperty( String name, String value ) { - if( log.isTraceEnabled()) - log.trace("setProperty " + name + " " + value ); - getJkMain().setProperty( name, value ); - properties.put( name, value ); - } - - public String getProperty( String name ) { - return properties.getProperty(name) ; - } - - public Iterator getAttributeNames() { - return properties.keySet().iterator(); - } - - /** Pass config info - */ - public void setAttribute( String name, Object value ) { - if( log.isDebugEnabled()) - log.debug("setAttribute " + name + " " + value ); - if( value instanceof String ) - this.setProperty( name, (String)value ); - } - - /** - * Retrieve config info. - * Primarily for use with the admin webapp. - */ - public Object getAttribute( String name ) { - return getJkMain().getProperty(name); - } - - /** The adapter, used to call the connector - */ - public void setAdapter(Adapter adapter) { - this.adapter=adapter; - } - - public Adapter getAdapter() { - return adapter; - } - - public JkMain getJkMain() { - if( jkMain == null ) { - jkMain=new JkMain(); - jkMain.setWorkerEnv(wEnv); - - } - return jkMain; - } - - boolean started=false; - - /** Start the protocol - */ - public void init() { - if( started ) return; - - started=true; - - if( wEnv==null ) { - // we are probably not registered - not very good. - wEnv=getJkMain().getWorkerEnv(); - wEnv.addHandler("container", this ); - } - - try { - // jkMain.setJkHome() XXX; - - getJkMain().init(); - - } catch( Exception ex ) { - log.error("Error during init",ex); - } - } - - public void start() { - try { - if( oname != null && getJkMain().getDomain() == null) { - try { - ObjectName jkmainOname = - new ObjectName(oname.getDomain() + ":type=JkMain"); - Registry.getRegistry(null, null) - .registerComponent(getJkMain(), jkmainOname, "JkMain"); - } catch (Exception e) { - log.error( "Error registering jkmain " + e ); - } - } - getJkMain().start(); - } catch( Exception ex ) { - log.error("Error during startup",ex); - } - } - - public void pause() throws Exception { - if(!paused) { - paused = true; - getJkMain().pause(); - } - } - - public void resume() throws Exception { - if(paused) { - paused = false; - getJkMain().resume(); - } - } - - public void destroy() { - if( !started ) return; - - started = false; - getJkMain().stop(); - } - - - // -------------------- Jk handler implementation -------------------- - // Jk Handler mehod - public int invoke( Msg msg, MsgContext ep ) - throws IOException { - if( ep.isLogTimeEnabled() ) - ep.setLong( MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis()); - - Request req=ep.getRequest(); - Response res=req.getResponse(); - - if( log.isDebugEnabled() ) - log.debug( "Invoke " + req + " " + res + " " + req.requestURI().toString()); - - res.setNote( epNote, ep ); - ep.setStatus( MsgContext.JK_STATUS_HEAD ); - RequestInfo rp = req.getRequestProcessor(); - rp.setStage(Constants.STAGE_SERVICE); - try { - adapter.service( req, res ); - } catch( Exception ex ) { - log.info("Error servicing request " + req,ex); - } - if(ep.getStatus() != MsgContext.JK_STATUS_CLOSED) { - res.finish(); - } - - req.recycle(); - req.updateCounters(); - res.recycle(); - ep.recycle(); - if( ep.getStatus() == MsgContext.JK_STATUS_ERROR ) { - return ERROR; - } - ep.setStatus( MsgContext.JK_STATUS_NEW ); - rp.setStage(Constants.STAGE_KEEPALIVE); - return OK; - } - - - public ObjectName preRegister(MBeanServer server, - ObjectName oname) throws Exception - { - // override - we must be registered as "container" - this.name="container"; - return super.preRegister(server, oname); - } -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jk.server; + +import java.io.IOException; +import java.util.Iterator; + +import javax.management.MBeanServer; +import javax.management.ObjectName; + +import org.apache.coyote.Adapter; +import org.apache.coyote.ProtocolHandler; +import org.apache.coyote.Request; +import org.apache.coyote.Response; +import org.apache.coyote.RequestInfo; +import org.apache.coyote.Constants; +import org.apache.jk.common.HandlerRequest; +import org.apache.jk.common.JkInputStream; +import org.apache.jk.common.MsgAjp; +import org.apache.jk.core.JkHandler; +import org.apache.jk.core.Msg; +import org.apache.jk.core.MsgContext; +import org.apache.jk.core.WorkerEnv; +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.C2BConverter; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.http.HttpMessages; +import org.apache.tomcat.util.http.MimeHeaders; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.tomcat.util.net.SSLSupport; + +/** Plugs Jk into Coyote. Must be named "type=JkHandler,name=container" + * + * jmx:notification-handler name="org.apache.jk.SEND_PACKET + * jmx:notification-handler name="org.apache.coyote.ACTION_COMMIT + */ +public class JkCoyoteHandler extends JkHandler implements ProtocolHandler { + protected static org.apache.commons.logging.Log log + = org.apache.commons.logging.LogFactory.getLog(JkCoyoteHandler.class); + // Set debug on this logger to see the container request time + + // ----------------------------------------------------------- DoPrivileged + private boolean paused = false; + int epNote; + Adapter adapter; + protected JkMain jkMain=null; + + /** Set a property. Name is a "component.property". JMX should + * be used instead. + */ + public void setProperty( String name, String value ) { + if( log.isTraceEnabled()) + log.trace("setProperty " + name + " " + value ); + getJkMain().setProperty( name, value ); + properties.put( name, value ); + } + + public String getProperty( String name ) { + return properties.getProperty(name) ; + } + + public Iterator getAttributeNames() { + return properties.keySet().iterator(); + } + + /** Pass config info + */ + public void setAttribute( String name, Object value ) { + if( log.isDebugEnabled()) + log.debug("setAttribute " + name + " " + value ); + if( value instanceof String ) + this.setProperty( name, (String)value ); + } + + /** + * Retrieve config info. + * Primarily for use with the admin webapp. + */ + public Object getAttribute( String name ) { + return getJkMain().getProperty(name); + } + + /** The adapter, used to call the connector + */ + public void setAdapter(Adapter adapter) { + this.adapter=adapter; + } + + public Adapter getAdapter() { + return adapter; + } + + public JkMain getJkMain() { + if( jkMain == null ) { + jkMain=new JkMain(); + jkMain.setWorkerEnv(wEnv); + + } + return jkMain; + } + + boolean started=false; + + /** Start the protocol + */ + public void init() { + if( started ) return; + + started=true; + + if( wEnv==null ) { + // we are probably not registered - not very good. + wEnv=getJkMain().getWorkerEnv(); + wEnv.addHandler("container", this ); + } + + try { + // jkMain.setJkHome() XXX; + + getJkMain().init(); + + } catch( Exception ex ) { + log.error("Error during init",ex); + } + } + + public void start() { + try { + if( oname != null && getJkMain().getDomain() == null) { + try { + ObjectName jkmainOname = + new ObjectName(oname.getDomain() + ":type=JkMain"); + Registry.getRegistry(null, null) + .registerComponent(getJkMain(), jkmainOname, "JkMain"); + } catch (Exception e) { + log.error( "Error registering jkmain " + e ); + } + } + getJkMain().start(); + } catch( Exception ex ) { + log.error("Error during startup",ex); + } + } + + public void pause() throws Exception { + if(!paused) { + paused = true; + getJkMain().pause(); + } + } + + public void resume() throws Exception { + if(paused) { + paused = false; + getJkMain().resume(); + } + } + + public void destroy() { + if( !started ) return; + + started = false; + getJkMain().stop(); + } + + + // -------------------- Jk handler implementation -------------------- + // Jk Handler mehod + public int invoke( Msg msg, MsgContext ep ) + throws IOException { + if( ep.isLogTimeEnabled() ) + ep.setLong( MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis()); + + Request req=ep.getRequest(); + Response res=req.getResponse(); + + if( log.isDebugEnabled() ) + log.debug( "Invoke " + req + " " + res + " " + req.requestURI().toString()); + + res.setNote( epNote, ep ); + ep.setStatus( MsgContext.JK_STATUS_HEAD ); + RequestInfo rp = req.getRequestProcessor(); + rp.setStage(Constants.STAGE_SERVICE); + try { + adapter.service( req, res ); + } catch( Exception ex ) { + log.info("Error servicing request " + req,ex); + } + if(ep.getStatus() != MsgContext.JK_STATUS_CLOSED) { + res.finish(); + } + + req.recycle(); + req.updateCounters(); + res.recycle(); + ep.recycle(); + if( ep.getStatus() == MsgContext.JK_STATUS_ERROR ) { + return ERROR; + } + ep.setStatus( MsgContext.JK_STATUS_NEW ); + rp.setStage(Constants.STAGE_KEEPALIVE); + return OK; + } + + + public ObjectName preRegister(MBeanServer server, + ObjectName oname) throws Exception + { + // override - we must be registered as "container" + this.name="container"; + return super.preRegister(server, oname); + } +} diff --git a/java/org/apache/jk/server/JkMain.java b/java/org/apache/jk/server/JkMain.java index bd4478259..1f80e5151 100644 --- a/java/org/apache/jk/server/JkMain.java +++ b/java/org/apache/jk/server/JkMain.java @@ -1,693 +1,693 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.jk.server; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.PrintStream; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Properties; -import java.util.StringTokenizer; -import java.util.Vector; - -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.ObjectName; - -import org.apache.jk.core.JkHandler; -import org.apache.jk.core.WorkerEnv; -import org.apache.tomcat.util.IntrospectionUtils; -import org.apache.tomcat.util.modeler.Registry; - -/** Main class used to startup and configure jk. It manages the conf/jk2.properties file - * and is the target of JMX proxy. - * - * It implements a policy of save-on-change - whenever a property is changed at - * runtime the jk2.properties file will be overriden. - * - * You can edit the config file when tomcat is stoped ( or if you don't use JMX or - * other admin tools ). - * - * The format of jk2.properties: - *
        - *
        TYPE[.LOCALNAME].PROPERTY_NAME=VALUE - *
        Set a property on the associated component. TYPE will be used to - * find the class name and instantiate the component. LOCALNAME allows - * multiple instances. In JMX mode, TYPE and LOCALNAME will form the - * JMX name ( eventually combined with a 'jk2' component ) - * - *
        NAME=VALUE - *
        Define global properties to be used in ${} substitutions - * - *
        class.COMPONENT_TYPE=JAVA_CLASS_NAME - *
        Adds a new 'type' of component. We predefine all known types. - *
        - * - * Instances are created the first time a component name is found. In addition, - * 'handler.list' property will override the list of 'default' components that are - * loaded automatically. - * - * Note that the properties file is just one (simplistic) way to configure jk. We hope - * to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better ) - * - * @author Costin Manolache - */ -public class JkMain implements MBeanRegistration -{ - WorkerEnv wEnv; - String propFile; - Properties props=new Properties(); - - Properties modules=new Properties(); - boolean modified=false; - boolean started=false; - boolean saveProperties=false; - - public JkMain() - { - JkMain.jkMain=this; - modules.put("channelSocket", "org.apache.jk.common.ChannelSocket"); - modules.put("channelNioSocket", "org.apache.jk.common.ChannelNioSocket"); - modules.put("channelUnix", "org.apache.jk.common.ChannelUn"); - modules.put("channelJni", "org.apache.jk.common.ChannelJni"); - modules.put("apr", "org.apache.jk.apr.AprImpl"); - modules.put("mx", "org.apache.jk.common.JkMX"); - modules.put("modeler", "org.apache.jk.common.JkModeler"); - modules.put("shm", "org.apache.jk.common.Shm"); - modules.put("request","org.apache.jk.common.HandlerRequest"); - modules.put("container","org.apache.jk.common.HandlerRequest"); - modules.put("modjk","org.apache.jk.common.ModJkMX"); - - } - - public static JkMain getJkMain() { - return jkMain; - } - - private static String DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol"; - private void initHTTPSUrls() { - try { - // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+) - String value = System.getProperty("java.protocol.handler.pkgs"); - if (value == null) { - value = DEFAULT_HTTPS; - } else if (value.indexOf(DEFAULT_HTTPS) >= 0 ) { - return; // already set - } else { - value += "|" + DEFAULT_HTTPS; - } - System.setProperty("java.protocol.handler.pkgs", value); - } catch(Exception ex ) { - log.info("Error adding SSL Protocol Handler",ex); - } - } - - // -------------------- Setting -------------------- - - /** Load a .properties file into and set the values - * into jk2 configuration. - */ - public void setPropertiesFile( String p ) { - propFile=p; - if( started ) { - loadPropertiesFile(); - } - } - - public String getPropertiesFile() { - return propFile; - } - - public void setSaveProperties( boolean b ) { - saveProperties=b; - } - - /** Set a name/value as a jk2 property - */ - public void setProperty( String n, String v ) { - if( "jkHome".equals( n ) ) { - setJkHome( v ); - } - if( "propertiesFile".equals( n ) ) { - setPropertiesFile( v ); - } - props.put( n, v ); - if( started ) { - processProperty( n, v ); - saveProperties(); - } - } - /** - * Retrieve a property. - */ - public Object getProperty(String name) { - String alias = (String)replacements.get(name); - Object result = null; - if(alias != null) { - result = props.get(alias); - } - if(result == null) { - result = props.get(name); - } - return result; - } - /** - * Set the channelClassName that will used to connect to - * httpd. - */ - public void setChannelClassName(String name) { - props.put( "handler.channel.className",name); - } - - public String getChannelClassName() { - return (String)props.get( "handler.channel.className"); - } - - /** - * Set the workerClassName that will handle the request. - * ( sort of 'pivot' in axis :-) - */ - public void setWorkerClassName(String name) { - props.put( "handler.container.className",name); - } - - public String getWorkerClassName() { - return (String)props.get( "handler.container.className"); - } - - /** Set the base dir of jk2. ( including WEB-INF if in a webapp ). - * We'll try to guess it from classpath if none is set ( for - * example on command line ), but if in a servlet environment - * you need to use Context.getRealPath or a system property or - * set it expliciltey. - */ - public void setJkHome( String s ) { - getWorkerEnv().setJkHome(s); - } - - public String getJkHome() { - return getWorkerEnv().getJkHome(); - } - - String out; - String err; - File propsF; - - public void setOut( String s ) { - this.out=s; - } - - public String getOut() { - return this.out; - } - - public void setErr( String s ) { - this.err=s; - } - - public String getErr() { - return this.err; - } - - // -------------------- Initialization -------------------- - - public void init() throws IOException - { - long t1=System.currentTimeMillis(); - if(null != out) { - PrintStream outS=new PrintStream(new FileOutputStream(out)); - System.setOut(outS); - } - if(null != err) { - PrintStream errS=new PrintStream(new FileOutputStream(err)); - System.setErr(errS); - } - - String home=getWorkerEnv().getJkHome(); - if( home==null ) { - // XXX use IntrospectionUtil to find myself - this.guessHome(); - } - home=getWorkerEnv().getJkHome(); - if( home==null ) { - log.info( "Can't find home, jk2.properties not loaded"); - } - if(log.isDebugEnabled()) - log.debug("Starting Jk2, base dir= " + home ); - loadPropertiesFile(); - - String initHTTPS = (String)props.get("class.initHTTPS"); - if("true".equalsIgnoreCase(initHTTPS)) { - initHTTPSUrls(); - } - - long t2=System.currentTimeMillis(); - initTime=t2-t1; - } - - static String defaultHandlers[]= { "request", - "container", - "channelSocket"}; - /* - static String defaultHandlers[]= { "apr", - "shm", - "request", - "container", - "channelSocket", - "channelJni", - "channelUnix"}; - */ - - public void stop() - { - for( int i=0; i 0 ) { - type=name.substring(0, dot ); - if( dot != lastDot ) { - localName=name.substring( dot + 1, lastDot ); - fullName=type + "." + localName; - } else { - fullName=type; - } - propName=name.substring( lastDot+1); - } else { - return; - } - - if( log.isDebugEnabled() ) - log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName ); - if( "class".equals( type ) || "handler".equals( type ) ) { - return; - } - - JkHandler comp=getWorkerEnv().getHandler( fullName ); - if( comp==null ) { - comp=newHandler( type, localName, fullName ); - } - if( comp==null ) - return; - - if( log.isDebugEnabled() ) - log.debug("Setting " + propName + " on " + fullName + " " + comp); - this.setBeanProperty( comp, propName, propValue ); - } - - private JkHandler newHandler( String type, String localName, String fullName ) - { - JkHandler handler; - String classN=modules.getProperty(type); - if( classN == null ) { - log.error("No class name for " + fullName + " " + type ); - return null; - } - try { - Class channelclass = Class.forName(classN); - handler=(JkHandler)channelclass.newInstance(); - } catch (Throwable ex) { - handler=null; - log.error( "Can't create " + fullName, ex ); - return null; - } - if( this.domain != null ) { - try { - ObjectName handlerOname = new ObjectName - (this.domain + ":" + "type=JkHandler,name=" + fullName); - Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN); - } catch (Exception e) { - log.error( "Error registering " + fullName, e ); - } - - } - wEnv.addHandler( fullName, handler ); - return handler; - } - - private void processModules() { - Enumeration keys=props.keys(); - int plen=6; - - while( keys.hasMoreElements() ) { - String k=(String)keys.nextElement(); - if( ! k.startsWith( "class." ) ) - continue; - - String name= k.substring( plen ); - String propValue=props.getProperty( k ); - - if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue ); - modules.put( name, propValue ); - } - } - - private String[] split(String s, String delim ) { - Vector v=new Vector(); - StringTokenizer st=new StringTokenizer(s, delim ); - while( st.hasMoreTokens() ) { - v.addElement( st.nextToken()); - } - String res[]=new String[ v.size() ]; - for( int i=0; i + *
        TYPE[.LOCALNAME].PROPERTY_NAME=VALUE + *
        Set a property on the associated component. TYPE will be used to + * find the class name and instantiate the component. LOCALNAME allows + * multiple instances. In JMX mode, TYPE and LOCALNAME will form the + * JMX name ( eventually combined with a 'jk2' component ) + * + *
        NAME=VALUE + *
        Define global properties to be used in ${} substitutions + * + *
        class.COMPONENT_TYPE=JAVA_CLASS_NAME + *
        Adds a new 'type' of component. We predefine all known types. + * + * + * Instances are created the first time a component name is found. In addition, + * 'handler.list' property will override the list of 'default' components that are + * loaded automatically. + * + * Note that the properties file is just one (simplistic) way to configure jk. We hope + * to see configs based on registry, LDAP, db, etc. ( XML is not necesarily better ) + * + * @author Costin Manolache + */ +public class JkMain implements MBeanRegistration +{ + WorkerEnv wEnv; + String propFile; + Properties props=new Properties(); + + Properties modules=new Properties(); + boolean modified=false; + boolean started=false; + boolean saveProperties=false; + + public JkMain() + { + JkMain.jkMain=this; + modules.put("channelSocket", "org.apache.jk.common.ChannelSocket"); + modules.put("channelNioSocket", "org.apache.jk.common.ChannelNioSocket"); + modules.put("channelUnix", "org.apache.jk.common.ChannelUn"); + modules.put("channelJni", "org.apache.jk.common.ChannelJni"); + modules.put("apr", "org.apache.jk.apr.AprImpl"); + modules.put("mx", "org.apache.jk.common.JkMX"); + modules.put("modeler", "org.apache.jk.common.JkModeler"); + modules.put("shm", "org.apache.jk.common.Shm"); + modules.put("request","org.apache.jk.common.HandlerRequest"); + modules.put("container","org.apache.jk.common.HandlerRequest"); + modules.put("modjk","org.apache.jk.common.ModJkMX"); + + } + + public static JkMain getJkMain() { + return jkMain; + } + + private static String DEFAULT_HTTPS="com.sun.net.ssl.internal.www.protocol"; + private void initHTTPSUrls() { + try { + // 11657: if only ajp is used, https: redirects need to work ( at least for 1.3+) + String value = System.getProperty("java.protocol.handler.pkgs"); + if (value == null) { + value = DEFAULT_HTTPS; + } else if (value.indexOf(DEFAULT_HTTPS) >= 0 ) { + return; // already set + } else { + value += "|" + DEFAULT_HTTPS; + } + System.setProperty("java.protocol.handler.pkgs", value); + } catch(Exception ex ) { + log.info("Error adding SSL Protocol Handler",ex); + } + } + + // -------------------- Setting -------------------- + + /** Load a .properties file into and set the values + * into jk2 configuration. + */ + public void setPropertiesFile( String p ) { + propFile=p; + if( started ) { + loadPropertiesFile(); + } + } + + public String getPropertiesFile() { + return propFile; + } + + public void setSaveProperties( boolean b ) { + saveProperties=b; + } + + /** Set a name/value as a jk2 property + */ + public void setProperty( String n, String v ) { + if( "jkHome".equals( n ) ) { + setJkHome( v ); + } + if( "propertiesFile".equals( n ) ) { + setPropertiesFile( v ); + } + props.put( n, v ); + if( started ) { + processProperty( n, v ); + saveProperties(); + } + } + /** + * Retrieve a property. + */ + public Object getProperty(String name) { + String alias = (String)replacements.get(name); + Object result = null; + if(alias != null) { + result = props.get(alias); + } + if(result == null) { + result = props.get(name); + } + return result; + } + /** + * Set the channelClassName that will used to connect to + * httpd. + */ + public void setChannelClassName(String name) { + props.put( "handler.channel.className",name); + } + + public String getChannelClassName() { + return (String)props.get( "handler.channel.className"); + } + + /** + * Set the workerClassName that will handle the request. + * ( sort of 'pivot' in axis :-) + */ + public void setWorkerClassName(String name) { + props.put( "handler.container.className",name); + } + + public String getWorkerClassName() { + return (String)props.get( "handler.container.className"); + } + + /** Set the base dir of jk2. ( including WEB-INF if in a webapp ). + * We'll try to guess it from classpath if none is set ( for + * example on command line ), but if in a servlet environment + * you need to use Context.getRealPath or a system property or + * set it expliciltey. + */ + public void setJkHome( String s ) { + getWorkerEnv().setJkHome(s); + } + + public String getJkHome() { + return getWorkerEnv().getJkHome(); + } + + String out; + String err; + File propsF; + + public void setOut( String s ) { + this.out=s; + } + + public String getOut() { + return this.out; + } + + public void setErr( String s ) { + this.err=s; + } + + public String getErr() { + return this.err; + } + + // -------------------- Initialization -------------------- + + public void init() throws IOException + { + long t1=System.currentTimeMillis(); + if(null != out) { + PrintStream outS=new PrintStream(new FileOutputStream(out)); + System.setOut(outS); + } + if(null != err) { + PrintStream errS=new PrintStream(new FileOutputStream(err)); + System.setErr(errS); + } + + String home=getWorkerEnv().getJkHome(); + if( home==null ) { + // XXX use IntrospectionUtil to find myself + this.guessHome(); + } + home=getWorkerEnv().getJkHome(); + if( home==null ) { + log.info( "Can't find home, jk2.properties not loaded"); + } + if(log.isDebugEnabled()) + log.debug("Starting Jk2, base dir= " + home ); + loadPropertiesFile(); + + String initHTTPS = (String)props.get("class.initHTTPS"); + if("true".equalsIgnoreCase(initHTTPS)) { + initHTTPSUrls(); + } + + long t2=System.currentTimeMillis(); + initTime=t2-t1; + } + + static String defaultHandlers[]= { "request", + "container", + "channelSocket"}; + /* + static String defaultHandlers[]= { "apr", + "shm", + "request", + "container", + "channelSocket", + "channelJni", + "channelUnix"}; + */ + + public void stop() + { + for( int i=0; i 0 ) { + type=name.substring(0, dot ); + if( dot != lastDot ) { + localName=name.substring( dot + 1, lastDot ); + fullName=type + "." + localName; + } else { + fullName=type; + } + propName=name.substring( lastDot+1); + } else { + return; + } + + if( log.isDebugEnabled() ) + log.debug( "Processing " + type + ":" + localName + ":" + fullName + " " + propName ); + if( "class".equals( type ) || "handler".equals( type ) ) { + return; + } + + JkHandler comp=getWorkerEnv().getHandler( fullName ); + if( comp==null ) { + comp=newHandler( type, localName, fullName ); + } + if( comp==null ) + return; + + if( log.isDebugEnabled() ) + log.debug("Setting " + propName + " on " + fullName + " " + comp); + this.setBeanProperty( comp, propName, propValue ); + } + + private JkHandler newHandler( String type, String localName, String fullName ) + { + JkHandler handler; + String classN=modules.getProperty(type); + if( classN == null ) { + log.error("No class name for " + fullName + " " + type ); + return null; + } + try { + Class channelclass = Class.forName(classN); + handler=(JkHandler)channelclass.newInstance(); + } catch (Throwable ex) { + handler=null; + log.error( "Can't create " + fullName, ex ); + return null; + } + if( this.domain != null ) { + try { + ObjectName handlerOname = new ObjectName + (this.domain + ":" + "type=JkHandler,name=" + fullName); + Registry.getRegistry(null, null).registerComponent(handler, handlerOname, classN); + } catch (Exception e) { + log.error( "Error registering " + fullName, e ); + } + + } + wEnv.addHandler( fullName, handler ); + return handler; + } + + private void processModules() { + Enumeration keys=props.keys(); + int plen=6; + + while( keys.hasMoreElements() ) { + String k=(String)keys.nextElement(); + if( ! k.startsWith( "class." ) ) + continue; + + String name= k.substring( plen ); + String propValue=props.getProperty( k ); + + if( log.isDebugEnabled()) log.debug("Register " + name + " " + propValue ); + modules.put( name, propValue ); + } + } + + private String[] split(String s, String delim ) { + Vector v=new Vector(); + StringTokenizer st=new StringTokenizer(s, delim ); + while( st.hasMoreTokens() ) { + v.addElement( st.nextToken()); + } + String res[]=new String[ v.size() ]; + for( int i=0; i classLoaderLoggers = - new WeakHashMap(); - - - /** - * This prefix is used to allow using prefixes for the properties names - * of handlers and their subcomponents. - */ - protected ThreadLocal prefix = new ThreadLocal(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add the specified logger to the classloader local configuration. - * - * @param logger The logger to be added - */ - public synchronized boolean addLogger(final Logger logger) { - - final String loggerName = logger.getName(); - - ClassLoader classLoader = - Thread.currentThread().getContextClassLoader(); - ClassLoaderLogInfo info = getClassLoaderInfo(classLoader); - if (info.loggers.containsKey(loggerName)) { - return false; - } - info.loggers.put(loggerName, logger); - - // Apply initial level for new logger - final String levelString = getProperty(loggerName + ".level"); - if (levelString != null) { - try { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - logger.setLevel(Level.parse(levelString.trim())); - return null; - } - }); - } catch (IllegalArgumentException e) { - // Leave level set to null - } - } - - // If any parent loggers have levels definied, make sure they are - // instantiated - int dotIndex = loggerName.lastIndexOf('.'); - while (dotIndex >= 0) { - final String parentName = loggerName.substring(0, dotIndex); - if (getProperty(parentName + ".level") != null) { - Logger.getLogger(parentName); - break; - } - dotIndex = loggerName.lastIndexOf('.', dotIndex - 1); - } - - // Find associated node - LogNode node = info.rootNode.findNode(loggerName); - node.logger = logger; - - // Set parent logger - Logger parentLogger = node.findParentLogger(); - if (parentLogger != null) { - doSetParentLogger(logger, parentLogger); - } - - // Tell children we are their new parent - node.setParentLogger(logger); - - // Add associated handlers, if any are defined using the .handlers property. - // In this case, handlers of the parent logger(s) will not be used - String handlers = getProperty(loggerName + ".handlers"); - if (handlers != null) { - logger.setUseParentHandlers(false); - StringTokenizer tok = new StringTokenizer(handlers, ","); - while (tok.hasMoreTokens()) { - String handlerName = (tok.nextToken().trim()); - Handler handler = null; - ClassLoader current = classLoader; - while (current != null) { - info = (ClassLoaderLogInfo) classLoaderLoggers.get(current); - if (info != null) { - handler = (Handler) info.handlers.get(handlerName); - if (handler != null) { - break; - } - } - current = current.getParent(); - } - if (handler != null) { - logger.addHandler(handler); - } - } - } - - // Parse useParentHandlers to set if the logger should delegate to its parent. - // Unlike java.util.logging, the default is to not delegate if a list of handlers - // has been specified for the logger. - String useParentHandlersString = getProperty(loggerName + ".useParentHandlers"); - if (Boolean.valueOf(useParentHandlersString).booleanValue()) { - logger.setUseParentHandlers(true); - } - - return true; - } - - - /** - * Get the logger associated with the specified name inside - * the classloader local configuration. If this returns null, - * and the call originated for Logger.getLogger, a new - * logger with the specified name will be instantiated and - * added using addLogger. - * - * @param name The name of the logger to retrieve - */ - public synchronized Logger getLogger(final String name) { - ClassLoader classLoader = Thread.currentThread() - .getContextClassLoader(); - return (Logger) getClassLoaderInfo(classLoader).loggers.get(name); - } - - - /** - * Get an enumeration of the logger names currently defined in the - * classloader local configuration. - */ - public synchronized Enumeration getLoggerNames() { - ClassLoader classLoader = Thread.currentThread() - .getContextClassLoader(); - return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet()); - } - - - /** - * Get the value of the specified property in the classloader local - * configuration. - * - * @param name The property name - */ - public String getProperty(String name) { - ClassLoader classLoader = Thread.currentThread() - .getContextClassLoader(); - String prefix = (String) this.prefix.get(); - if (prefix != null) { - name = prefix + name; - } - ClassLoaderLogInfo info = getClassLoaderInfo(classLoader); - String result = info.props.getProperty(name); - // If the property was not found, and the current classloader had no - // configuration (property list is empty), look for the parent classloader - // properties. - if ((result == null) && (info.props.isEmpty())) { - ClassLoader current = classLoader.getParent(); - while (current != null) { - info = (ClassLoaderLogInfo) classLoaderLoggers.get(current); - if (info != null) { - result = info.props.getProperty(name); - if ((result != null) || (!info.props.isEmpty())) { - break; - } - } - current = current.getParent(); - } - if (result == null) { - result = super.getProperty(name); - } - } - // Simple property replacement (mostly for folder names) - if (result != null) { - result = replace(result); - } - return result; - } - - - public void readConfiguration() - throws IOException, SecurityException { - - checkAccess(); - - readConfiguration(Thread.currentThread().getContextClassLoader()); - - } - - public void readConfiguration(InputStream is) - throws IOException, SecurityException { - - checkAccess(); - reset(); - - readConfiguration(is, Thread.currentThread().getContextClassLoader()); - - } - - // ------------------------------------------------------ Protected Methods - - - /** - * Retrieve the configuration associated with the specified classloader. If - * it does not exist, it will be created. - * - * @param classLoader The classloader for which we will retrieve or build the - * configuration - */ - protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader classLoader) { - - if (classLoader == null) { - classLoader = ClassLoader.getSystemClassLoader(); - } - ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers - .get(classLoader); - if (info == null) { - final ClassLoader classLoaderParam = classLoader; - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - try { - readConfiguration(classLoaderParam); - } catch (IOException e) { - // Ignore - } - return null; - } - }); - info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader); - } - return info; - } - - - /** - * Read configuration for the specified classloader. - * - * @param classLoader - * @throws IOException Errot - */ - protected void readConfiguration(ClassLoader classLoader) - throws IOException { - - InputStream is = null; - // Special case for URL classloaders which are used in containers: - // only look in the local repositories to avoid redefining loggers 20 times - if ((classLoader instanceof URLClassLoader) - && (((URLClassLoader) classLoader).findResource("logging.properties") != null)) { - is = classLoader.getResourceAsStream("logging.properties"); - } - if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) { - String configFileStr = System.getProperty("java.util.logging.config.file"); - if (configFileStr != null) { - try { - is = new FileInputStream(replace(configFileStr)); - } catch (IOException e) { - // Ignore - } - } - // Try the default JVM configuration - if (is == null) { - File defaultFile = new File(new File(System.getProperty("java.home"), "lib"), - "logging.properties"); - try { - is = new FileInputStream(defaultFile); - } catch (IOException e) { - // Critical problem, do something ... - } - } - } - - Logger localRootLogger = new RootLogger(); - if (is == null) { - // Retrieve the root logger of the parent classloader instead - ClassLoader current = classLoader.getParent(); - ClassLoaderLogInfo info = null; - while (current != null && info == null) { - info = getClassLoaderInfo(current); - current = current.getParent(); - } - if (info != null) { - localRootLogger.setParent(info.rootNode.logger); - } - } - ClassLoaderLogInfo info = - new ClassLoaderLogInfo(new LogNode(null, localRootLogger)); - classLoaderLoggers.put(classLoader, info); - - if (is != null) { - readConfiguration(is, classLoader); - } - addLogger(localRootLogger); - - } - - - /** - * Load specified configuration. - * - * @param is InputStream to the properties file - * @param classLoader for which the configuration will be loaded - * @throws IOException If something wrong happens during loading - */ - protected void readConfiguration(InputStream is, ClassLoader classLoader) - throws IOException { - - ClassLoaderLogInfo info = - (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader); - - try { - info.props.load(is); - } catch (IOException e) { - // Report error - System.err.println("Configuration error"); - e.printStackTrace(); - } finally { - try { - is.close(); - } catch (Throwable t) {} - } - - // Create handlers for the root logger of this classloader - String rootHandlers = info.props.getProperty(".handlers"); - String handlers = info.props.getProperty("handlers"); - Logger localRootLogger = info.rootNode.logger; - if (handlers != null) { - StringTokenizer tok = new StringTokenizer(handlers, ","); - while (tok.hasMoreTokens()) { - String handlerName = (tok.nextToken().trim()); - String handlerClassName = handlerName; - String prefix = ""; - if (handlerClassName.length() <= 0) { - continue; - } - // Parse and remove a prefix (prefix start with a digit, such as - // "10WebappFooHanlder.") - if (Character.isDigit(handlerClassName.charAt(0))) { - int pos = handlerClassName.indexOf('.'); - if (pos >= 0) { - prefix = handlerClassName.substring(0, pos + 1); - handlerClassName = handlerClassName.substring(pos + 1); - } - } - try { - this.prefix.set(prefix); - Handler handler = - (Handler) classLoader.loadClass(handlerClassName).newInstance(); - // The specification strongly implies all configuration should be done - // during the creation of the handler object. - // This includes setting level, filter, formatter and encoding. - this.prefix.set(null); - info.handlers.put(handlerName, handler); - if (rootHandlers == null) { - localRootLogger.addHandler(handler); - } - } catch (Exception e) { - // Report error - System.err.println("Handler error"); - e.printStackTrace(); - } - } - - // Add handlers to the root logger, if any are defined using the .handlers property. - if (rootHandlers != null) { - StringTokenizer tok2 = new StringTokenizer(rootHandlers, ","); - while (tok2.hasMoreTokens()) { - String handlerName = (tok2.nextToken().trim()); - Handler handler = (Handler) info.handlers.get(handlerName); - if (handler != null) { - localRootLogger.addHandler(handler); - } - } - } - - } - - } - - - /** - * Set parent child relationship between the two specified loggers. - * - * @param logger - * @param parent - */ - protected static void doSetParentLogger(final Logger logger, - final Logger parent) { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { - logger.setParent(parent); - return null; - } - }); - } - - - /** - * System property replacement in the given string. - * - * @param str The original string - * @return the modified string - */ - protected String replace(String str) { - String result = str.trim(); - if (result.startsWith("${")) { - int pos = result.indexOf('}'); - if (pos != -1) { - String propName = result.substring(2, pos); - String replacement = System.getProperty(propName); - if (replacement != null) { - result = replacement + result.substring(pos + 1); - } - } - } - return result; - } - - - // ---------------------------------------------------- LogNode Inner Class - - - protected static final class LogNode { - Logger logger; - - protected final Map children = - new HashMap(); - - protected final LogNode parent; - - LogNode(final LogNode parent, final Logger logger) { - this.parent = parent; - this.logger = logger; - } - - LogNode(final LogNode parent) { - this(parent, null); - } - - LogNode findNode(String name) { - LogNode currentNode = this; - if (logger.getName().equals(name)) { - return this; - } - while (name != null) { - final int dotIndex = name.indexOf('.'); - final String nextName; - if (dotIndex < 0) { - nextName = name; - name = null; - } else { - nextName = name.substring(0, dotIndex); - name = name.substring(dotIndex + 1); - } - LogNode childNode = (LogNode) currentNode.children - .get(nextName); - if (childNode == null) { - childNode = new LogNode(currentNode); - currentNode.children.put(nextName, childNode); - } - currentNode = childNode; - } - return currentNode; - } - - Logger findParentLogger() { - Logger logger = null; - LogNode node = parent; - while (node != null && logger == null) { - logger = node.logger; - node = node.parent; - } - return logger; - } - - void setParentLogger(final Logger parent) { - for (final Iterator iter = children.values().iterator(); iter - .hasNext();) { - final LogNode childNode = (LogNode) iter.next(); - if (childNode.logger == null) { - childNode.setParentLogger(parent); - } else { - doSetParentLogger(childNode.logger, parent); - } - } - } - - } - - - // -------------------------------------------- ClassLoaderInfo Inner Class - - - protected static final class ClassLoaderLogInfo { - final LogNode rootNode; - final Map loggers = new HashMap(); - final Map handlers = new HashMap(); - final Properties props = new Properties(); - - ClassLoaderLogInfo(final LogNode rootNode) { - this.rootNode = rootNode; - } - - } - - - // ------------------------------------------------- RootLogger Inner Class - - - /** - * This class is needed to instantiate the root of each per classloader - * hierarchy. - */ - protected class RootLogger extends Logger { - public RootLogger() { - super("", null); - } - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.juli; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLClassLoader; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.StringTokenizer; +import java.util.WeakHashMap; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.Logger; + + +/** + * Per classloader LogManager implementation. + */ +public class ClassLoaderLogManager extends LogManager { + + + // -------------------------------------------------------------- Variables + + + /** + * Map containing the classloader information, keyed per classloader. A + * weak hashmap is used to ensure no classloader reference is leaked from + * application redeployment. + */ + protected final Map classLoaderLoggers = + new WeakHashMap(); + + + /** + * This prefix is used to allow using prefixes for the properties names + * of handlers and their subcomponents. + */ + protected ThreadLocal prefix = new ThreadLocal(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the specified logger to the classloader local configuration. + * + * @param logger The logger to be added + */ + public synchronized boolean addLogger(final Logger logger) { + + final String loggerName = logger.getName(); + + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader(); + ClassLoaderLogInfo info = getClassLoaderInfo(classLoader); + if (info.loggers.containsKey(loggerName)) { + return false; + } + info.loggers.put(loggerName, logger); + + // Apply initial level for new logger + final String levelString = getProperty(loggerName + ".level"); + if (levelString != null) { + try { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + logger.setLevel(Level.parse(levelString.trim())); + return null; + } + }); + } catch (IllegalArgumentException e) { + // Leave level set to null + } + } + + // If any parent loggers have levels definied, make sure they are + // instantiated + int dotIndex = loggerName.lastIndexOf('.'); + while (dotIndex >= 0) { + final String parentName = loggerName.substring(0, dotIndex); + if (getProperty(parentName + ".level") != null) { + Logger.getLogger(parentName); + break; + } + dotIndex = loggerName.lastIndexOf('.', dotIndex - 1); + } + + // Find associated node + LogNode node = info.rootNode.findNode(loggerName); + node.logger = logger; + + // Set parent logger + Logger parentLogger = node.findParentLogger(); + if (parentLogger != null) { + doSetParentLogger(logger, parentLogger); + } + + // Tell children we are their new parent + node.setParentLogger(logger); + + // Add associated handlers, if any are defined using the .handlers property. + // In this case, handlers of the parent logger(s) will not be used + String handlers = getProperty(loggerName + ".handlers"); + if (handlers != null) { + logger.setUseParentHandlers(false); + StringTokenizer tok = new StringTokenizer(handlers, ","); + while (tok.hasMoreTokens()) { + String handlerName = (tok.nextToken().trim()); + Handler handler = null; + ClassLoader current = classLoader; + while (current != null) { + info = (ClassLoaderLogInfo) classLoaderLoggers.get(current); + if (info != null) { + handler = (Handler) info.handlers.get(handlerName); + if (handler != null) { + break; + } + } + current = current.getParent(); + } + if (handler != null) { + logger.addHandler(handler); + } + } + } + + // Parse useParentHandlers to set if the logger should delegate to its parent. + // Unlike java.util.logging, the default is to not delegate if a list of handlers + // has been specified for the logger. + String useParentHandlersString = getProperty(loggerName + ".useParentHandlers"); + if (Boolean.valueOf(useParentHandlersString).booleanValue()) { + logger.setUseParentHandlers(true); + } + + return true; + } + + + /** + * Get the logger associated with the specified name inside + * the classloader local configuration. If this returns null, + * and the call originated for Logger.getLogger, a new + * logger with the specified name will be instantiated and + * added using addLogger. + * + * @param name The name of the logger to retrieve + */ + public synchronized Logger getLogger(final String name) { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + return (Logger) getClassLoaderInfo(classLoader).loggers.get(name); + } + + + /** + * Get an enumeration of the logger names currently defined in the + * classloader local configuration. + */ + public synchronized Enumeration getLoggerNames() { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + return Collections.enumeration(getClassLoaderInfo(classLoader).loggers.keySet()); + } + + + /** + * Get the value of the specified property in the classloader local + * configuration. + * + * @param name The property name + */ + public String getProperty(String name) { + ClassLoader classLoader = Thread.currentThread() + .getContextClassLoader(); + String prefix = (String) this.prefix.get(); + if (prefix != null) { + name = prefix + name; + } + ClassLoaderLogInfo info = getClassLoaderInfo(classLoader); + String result = info.props.getProperty(name); + // If the property was not found, and the current classloader had no + // configuration (property list is empty), look for the parent classloader + // properties. + if ((result == null) && (info.props.isEmpty())) { + ClassLoader current = classLoader.getParent(); + while (current != null) { + info = (ClassLoaderLogInfo) classLoaderLoggers.get(current); + if (info != null) { + result = info.props.getProperty(name); + if ((result != null) || (!info.props.isEmpty())) { + break; + } + } + current = current.getParent(); + } + if (result == null) { + result = super.getProperty(name); + } + } + // Simple property replacement (mostly for folder names) + if (result != null) { + result = replace(result); + } + return result; + } + + + public void readConfiguration() + throws IOException, SecurityException { + + checkAccess(); + + readConfiguration(Thread.currentThread().getContextClassLoader()); + + } + + public void readConfiguration(InputStream is) + throws IOException, SecurityException { + + checkAccess(); + reset(); + + readConfiguration(is, Thread.currentThread().getContextClassLoader()); + + } + + // ------------------------------------------------------ Protected Methods + + + /** + * Retrieve the configuration associated with the specified classloader. If + * it does not exist, it will be created. + * + * @param classLoader The classloader for which we will retrieve or build the + * configuration + */ + protected ClassLoaderLogInfo getClassLoaderInfo(ClassLoader classLoader) { + + if (classLoader == null) { + classLoader = ClassLoader.getSystemClassLoader(); + } + ClassLoaderLogInfo info = (ClassLoaderLogInfo) classLoaderLoggers + .get(classLoader); + if (info == null) { + final ClassLoader classLoaderParam = classLoader; + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + try { + readConfiguration(classLoaderParam); + } catch (IOException e) { + // Ignore + } + return null; + } + }); + info = (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader); + } + return info; + } + + + /** + * Read configuration for the specified classloader. + * + * @param classLoader + * @throws IOException Errot + */ + protected void readConfiguration(ClassLoader classLoader) + throws IOException { + + InputStream is = null; + // Special case for URL classloaders which are used in containers: + // only look in the local repositories to avoid redefining loggers 20 times + if ((classLoader instanceof URLClassLoader) + && (((URLClassLoader) classLoader).findResource("logging.properties") != null)) { + is = classLoader.getResourceAsStream("logging.properties"); + } + if ((is == null) && (classLoader == ClassLoader.getSystemClassLoader())) { + String configFileStr = System.getProperty("java.util.logging.config.file"); + if (configFileStr != null) { + try { + is = new FileInputStream(replace(configFileStr)); + } catch (IOException e) { + // Ignore + } + } + // Try the default JVM configuration + if (is == null) { + File defaultFile = new File(new File(System.getProperty("java.home"), "lib"), + "logging.properties"); + try { + is = new FileInputStream(defaultFile); + } catch (IOException e) { + // Critical problem, do something ... + } + } + } + + Logger localRootLogger = new RootLogger(); + if (is == null) { + // Retrieve the root logger of the parent classloader instead + ClassLoader current = classLoader.getParent(); + ClassLoaderLogInfo info = null; + while (current != null && info == null) { + info = getClassLoaderInfo(current); + current = current.getParent(); + } + if (info != null) { + localRootLogger.setParent(info.rootNode.logger); + } + } + ClassLoaderLogInfo info = + new ClassLoaderLogInfo(new LogNode(null, localRootLogger)); + classLoaderLoggers.put(classLoader, info); + + if (is != null) { + readConfiguration(is, classLoader); + } + addLogger(localRootLogger); + + } + + + /** + * Load specified configuration. + * + * @param is InputStream to the properties file + * @param classLoader for which the configuration will be loaded + * @throws IOException If something wrong happens during loading + */ + protected void readConfiguration(InputStream is, ClassLoader classLoader) + throws IOException { + + ClassLoaderLogInfo info = + (ClassLoaderLogInfo) classLoaderLoggers.get(classLoader); + + try { + info.props.load(is); + } catch (IOException e) { + // Report error + System.err.println("Configuration error"); + e.printStackTrace(); + } finally { + try { + is.close(); + } catch (Throwable t) {} + } + + // Create handlers for the root logger of this classloader + String rootHandlers = info.props.getProperty(".handlers"); + String handlers = info.props.getProperty("handlers"); + Logger localRootLogger = info.rootNode.logger; + if (handlers != null) { + StringTokenizer tok = new StringTokenizer(handlers, ","); + while (tok.hasMoreTokens()) { + String handlerName = (tok.nextToken().trim()); + String handlerClassName = handlerName; + String prefix = ""; + if (handlerClassName.length() <= 0) { + continue; + } + // Parse and remove a prefix (prefix start with a digit, such as + // "10WebappFooHanlder.") + if (Character.isDigit(handlerClassName.charAt(0))) { + int pos = handlerClassName.indexOf('.'); + if (pos >= 0) { + prefix = handlerClassName.substring(0, pos + 1); + handlerClassName = handlerClassName.substring(pos + 1); + } + } + try { + this.prefix.set(prefix); + Handler handler = + (Handler) classLoader.loadClass(handlerClassName).newInstance(); + // The specification strongly implies all configuration should be done + // during the creation of the handler object. + // This includes setting level, filter, formatter and encoding. + this.prefix.set(null); + info.handlers.put(handlerName, handler); + if (rootHandlers == null) { + localRootLogger.addHandler(handler); + } + } catch (Exception e) { + // Report error + System.err.println("Handler error"); + e.printStackTrace(); + } + } + + // Add handlers to the root logger, if any are defined using the .handlers property. + if (rootHandlers != null) { + StringTokenizer tok2 = new StringTokenizer(rootHandlers, ","); + while (tok2.hasMoreTokens()) { + String handlerName = (tok2.nextToken().trim()); + Handler handler = (Handler) info.handlers.get(handlerName); + if (handler != null) { + localRootLogger.addHandler(handler); + } + } + } + + } + + } + + + /** + * Set parent child relationship between the two specified loggers. + * + * @param logger + * @param parent + */ + protected static void doSetParentLogger(final Logger logger, + final Logger parent) { + AccessController.doPrivileged(new PrivilegedAction() { + public Object run() { + logger.setParent(parent); + return null; + } + }); + } + + + /** + * System property replacement in the given string. + * + * @param str The original string + * @return the modified string + */ + protected String replace(String str) { + String result = str.trim(); + if (result.startsWith("${")) { + int pos = result.indexOf('}'); + if (pos != -1) { + String propName = result.substring(2, pos); + String replacement = System.getProperty(propName); + if (replacement != null) { + result = replacement + result.substring(pos + 1); + } + } + } + return result; + } + + + // ---------------------------------------------------- LogNode Inner Class + + + protected static final class LogNode { + Logger logger; + + protected final Map children = + new HashMap(); + + protected final LogNode parent; + + LogNode(final LogNode parent, final Logger logger) { + this.parent = parent; + this.logger = logger; + } + + LogNode(final LogNode parent) { + this(parent, null); + } + + LogNode findNode(String name) { + LogNode currentNode = this; + if (logger.getName().equals(name)) { + return this; + } + while (name != null) { + final int dotIndex = name.indexOf('.'); + final String nextName; + if (dotIndex < 0) { + nextName = name; + name = null; + } else { + nextName = name.substring(0, dotIndex); + name = name.substring(dotIndex + 1); + } + LogNode childNode = (LogNode) currentNode.children + .get(nextName); + if (childNode == null) { + childNode = new LogNode(currentNode); + currentNode.children.put(nextName, childNode); + } + currentNode = childNode; + } + return currentNode; + } + + Logger findParentLogger() { + Logger logger = null; + LogNode node = parent; + while (node != null && logger == null) { + logger = node.logger; + node = node.parent; + } + return logger; + } + + void setParentLogger(final Logger parent) { + for (final Iterator iter = children.values().iterator(); iter + .hasNext();) { + final LogNode childNode = (LogNode) iter.next(); + if (childNode.logger == null) { + childNode.setParentLogger(parent); + } else { + doSetParentLogger(childNode.logger, parent); + } + } + } + + } + + + // -------------------------------------------- ClassLoaderInfo Inner Class + + + protected static final class ClassLoaderLogInfo { + final LogNode rootNode; + final Map loggers = new HashMap(); + final Map handlers = new HashMap(); + final Properties props = new Properties(); + + ClassLoaderLogInfo(final LogNode rootNode) { + this.rootNode = rootNode; + } + + } + + + // ------------------------------------------------- RootLogger Inner Class + + + /** + * This class is needed to instantiate the root of each per classloader + * hierarchy. + */ + protected class RootLogger extends Logger { + public RootLogger() { + super("", null); + } + } + + +} diff --git a/java/org/apache/juli/FileHandler.java b/java/org/apache/juli/FileHandler.java index 73de56a75..a058f99d6 100644 --- a/java/org/apache/juli/FileHandler.java +++ b/java/org/apache/juli/FileHandler.java @@ -1,266 +1,266 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.juli; - -import java.io.File; -import java.io.FileWriter; -import java.io.PrintWriter; -import java.sql.Timestamp; -import java.util.logging.ErrorManager; -import java.util.logging.Filter; -import java.util.logging.Formatter; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.LogManager; -import java.util.logging.LogRecord; -import java.util.logging.SimpleFormatter; - -/** - * Implementation of Handler that appends log messages to a file - * named {prefix}.{date}.{suffix} in a configured directory, with an - * optional preceding timestamp. - * - * @version $Revision: 300331 $ $Date: 2005-03-03 19:29:45 +0100 (jeu., 03 mars 2005) $ - */ - -public class FileHandler - extends Handler { - - - // ------------------------------------------------------------ Constructor - - - public FileHandler() { - configure(); - open(); - } - - - public FileHandler(String directory, String prefix, String suffix) { - this(); - this.directory = directory; - this.prefix = prefix; - this.suffix = suffix; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The as-of date for the currently open log file, or a zero-length - * string if there is no open log file. - */ - private String date = ""; - - - /** - * The directory in which log files are created. - */ - private String directory = null; - - - /** - * The prefix that is added to log file filenames. - */ - private String prefix = null; - - - /** - * The suffix that is added to log file filenames. - */ - private String suffix = null; - - - /** - * The PrintWriter to which we are currently logging, if any. - */ - private PrintWriter writer = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Format and publish a LogRecord. - * - * @param record description of the log event - */ - public void publish(LogRecord record) { - - if (!isLoggable(record)) { - return; - } - - // Construct the timestamp we will use, if requested - Timestamp ts = new Timestamp(System.currentTimeMillis()); - String tsString = ts.toString().substring(0, 19); - String tsDate = tsString.substring(0, 10); - - // If the date has changed, switch log files - if (!date.equals(tsDate)) { - synchronized (this) { - if (!date.equals(tsDate)) { - close(); - date = tsDate; - open(); - } - } - } - - String result = null; - try { - result = getFormatter().format(record); - } catch (Exception e) { - reportError(null, e, ErrorManager.FORMAT_FAILURE); - return; - } - - try { - writer.write(result); - writer.flush(); - } catch (Exception e) { - reportError(null, e, ErrorManager.WRITE_FAILURE); - return; - } - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Close the currently open log file (if any). - */ - public void close() { - - try { - if (writer == null) - return; - writer.write(getFormatter().getTail(this)); - writer.flush(); - writer.close(); - writer = null; - date = ""; - } catch (Exception e) { - reportError(null, e, ErrorManager.CLOSE_FAILURE); - } - - } - - - /** - * Flush the writer. - */ - public void flush() { - - try { - writer.flush(); - } catch (Exception e) { - reportError(null, e, ErrorManager.FLUSH_FAILURE); - } - - } - - - /** - * Configure from LogManager properties. - */ - private void configure() { - - Timestamp ts = new Timestamp(System.currentTimeMillis()); - String tsString = ts.toString().substring(0, 19); - date = tsString.substring(0, 10); - - LogManager manager = LogManager.getLogManager(); - String className = FileHandler.class.getName(); - - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - - // Retrieve configuration of logging file name - directory = getProperty(className + ".directory", "logs"); - prefix = getProperty(className + ".prefix", "juli."); - suffix = getProperty(className + ".suffix", ".log"); - - // Get logging level for the handler - setLevel(Level.parse(getProperty(className + ".level", "" + Level.ALL))); - - // Get filter configuration - String filterName = getProperty(className + ".filter", null); - if (filterName != null) { - try { - setFilter((Filter) cl.loadClass(filterName).newInstance()); - } catch (Exception e) { - // Ignore - } - } - - // Set formatter - String formatterName = getProperty(className + ".formatter", null); - if (formatterName != null) { - try { - setFormatter((Formatter) cl.loadClass(formatterName).newInstance()); - } catch (Exception e) { - // Ignore - } - } else { - setFormatter(new SimpleFormatter()); - } - - // Set error manager - setErrorManager(new ErrorManager()); - - } - - - private String getProperty(String name, String defaultValue) { - String value = LogManager.getLogManager().getProperty(name); - if (value == null) { - value = defaultValue; - } else { - value = value.trim(); - } - return value; - } - - - /** - * Open the new log file for the date specified by date. - */ - private void open() { - - // Create the directory if necessary - File dir = new File(directory); - dir.mkdirs(); - - // Open the current log file - try { - String pathname = dir.getAbsolutePath() + File.separator + - prefix + date + suffix; - writer = new PrintWriter(new FileWriter(pathname, true), true); - writer.write(getFormatter().getHead(this)); - } catch (Exception e) { - reportError(null, e, ErrorManager.OPEN_FAILURE); - writer = null; - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.juli; + +import java.io.File; +import java.io.FileWriter; +import java.io.PrintWriter; +import java.sql.Timestamp; +import java.util.logging.ErrorManager; +import java.util.logging.Filter; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogManager; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; + +/** + * Implementation of Handler that appends log messages to a file + * named {prefix}.{date}.{suffix} in a configured directory, with an + * optional preceding timestamp. + * + * @version $Revision: 300331 $ $Date: 2005-03-03 19:29:45 +0100 (jeu., 03 mars 2005) $ + */ + +public class FileHandler + extends Handler { + + + // ------------------------------------------------------------ Constructor + + + public FileHandler() { + configure(); + open(); + } + + + public FileHandler(String directory, String prefix, String suffix) { + this(); + this.directory = directory; + this.prefix = prefix; + this.suffix = suffix; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The as-of date for the currently open log file, or a zero-length + * string if there is no open log file. + */ + private String date = ""; + + + /** + * The directory in which log files are created. + */ + private String directory = null; + + + /** + * The prefix that is added to log file filenames. + */ + private String prefix = null; + + + /** + * The suffix that is added to log file filenames. + */ + private String suffix = null; + + + /** + * The PrintWriter to which we are currently logging, if any. + */ + private PrintWriter writer = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Format and publish a LogRecord. + * + * @param record description of the log event + */ + public void publish(LogRecord record) { + + if (!isLoggable(record)) { + return; + } + + // Construct the timestamp we will use, if requested + Timestamp ts = new Timestamp(System.currentTimeMillis()); + String tsString = ts.toString().substring(0, 19); + String tsDate = tsString.substring(0, 10); + + // If the date has changed, switch log files + if (!date.equals(tsDate)) { + synchronized (this) { + if (!date.equals(tsDate)) { + close(); + date = tsDate; + open(); + } + } + } + + String result = null; + try { + result = getFormatter().format(record); + } catch (Exception e) { + reportError(null, e, ErrorManager.FORMAT_FAILURE); + return; + } + + try { + writer.write(result); + writer.flush(); + } catch (Exception e) { + reportError(null, e, ErrorManager.WRITE_FAILURE); + return; + } + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Close the currently open log file (if any). + */ + public void close() { + + try { + if (writer == null) + return; + writer.write(getFormatter().getTail(this)); + writer.flush(); + writer.close(); + writer = null; + date = ""; + } catch (Exception e) { + reportError(null, e, ErrorManager.CLOSE_FAILURE); + } + + } + + + /** + * Flush the writer. + */ + public void flush() { + + try { + writer.flush(); + } catch (Exception e) { + reportError(null, e, ErrorManager.FLUSH_FAILURE); + } + + } + + + /** + * Configure from LogManager properties. + */ + private void configure() { + + Timestamp ts = new Timestamp(System.currentTimeMillis()); + String tsString = ts.toString().substring(0, 19); + date = tsString.substring(0, 10); + + LogManager manager = LogManager.getLogManager(); + String className = FileHandler.class.getName(); + + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + + // Retrieve configuration of logging file name + directory = getProperty(className + ".directory", "logs"); + prefix = getProperty(className + ".prefix", "juli."); + suffix = getProperty(className + ".suffix", ".log"); + + // Get logging level for the handler + setLevel(Level.parse(getProperty(className + ".level", "" + Level.ALL))); + + // Get filter configuration + String filterName = getProperty(className + ".filter", null); + if (filterName != null) { + try { + setFilter((Filter) cl.loadClass(filterName).newInstance()); + } catch (Exception e) { + // Ignore + } + } + + // Set formatter + String formatterName = getProperty(className + ".formatter", null); + if (formatterName != null) { + try { + setFormatter((Formatter) cl.loadClass(formatterName).newInstance()); + } catch (Exception e) { + // Ignore + } + } else { + setFormatter(new SimpleFormatter()); + } + + // Set error manager + setErrorManager(new ErrorManager()); + + } + + + private String getProperty(String name, String defaultValue) { + String value = LogManager.getLogManager().getProperty(name); + if (value == null) { + value = defaultValue; + } else { + value = value.trim(); + } + return value; + } + + + /** + * Open the new log file for the date specified by date. + */ + private void open() { + + // Create the directory if necessary + File dir = new File(directory); + dir.mkdirs(); + + // Open the current log file + try { + String pathname = dir.getAbsolutePath() + File.separator + + prefix + date + suffix; + writer = new PrintWriter(new FileWriter(pathname, true), true); + writer.write(getFormatter().getHead(this)); + } catch (Exception e) { + reportError(null, e, ErrorManager.OPEN_FAILURE); + writer = null; + } + + } + + +} diff --git a/java/org/apache/naming/Constants.java b/java/org/apache/naming/Constants.java index 5dffbdadf..127c8e6f6 100644 --- a/java/org/apache/naming/Constants.java +++ b/java/org/apache/naming/Constants.java @@ -1,29 +1,29 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - - -/** - * Static constants for this package. - */ - -public final class Constants { - - public static final String Package = "org.apache.naming"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + + +/** + * Static constants for this package. + */ + +public final class Constants { + + public static final String Package = "org.apache.naming"; + +} diff --git a/java/org/apache/naming/ContextAccessController.java b/java/org/apache/naming/ContextAccessController.java index e9e8fde25..fa47e5d73 100644 --- a/java/org/apache/naming/ContextAccessController.java +++ b/java/org/apache/naming/ContextAccessController.java @@ -1,128 +1,128 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Hashtable; - -/** - * Handles the access control on the JNDI contexts. - * - * @author Remy Maucherat - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class ContextAccessController { - - - // -------------------------------------------------------------- Variables - - - /** - * Catalina context names on which writing is not allowed. - */ - private static Hashtable readOnlyContexts = new Hashtable(); - - - /** - * Security tokens repository. - */ - private static Hashtable securityTokens = new Hashtable(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Set a security token for a context. Can be set only once. - * - * @param name Name of the context - * @param token Security token - */ - public static void setSecurityToken(Object name, Object token) { - if ((!securityTokens.containsKey(name)) && (token != null)) { - securityTokens.put(name, token); - } - } - - - /** - * Remove a security token for a context. - * - * @param name Name of the context - * @param token Security token - */ - public static void unsetSecurityToken(Object name, Object token) { - if (checkSecurityToken(name, token)) { - securityTokens.remove(name); - } - } - - - /** - * Check a submitted security token. The submitted token must be equal to - * the token present in the repository. If no token is present for the - * context, then returns true. - * - * @param name Name of the context - * @param token Submitted security token - */ - public static boolean checkSecurityToken - (Object name, Object token) { - Object refToken = securityTokens.get(name); - if (refToken == null) - return (true); - if ((refToken != null) && (refToken.equals(token))) - return (true); - return (false); - } - - - /** - * Allow writing to a context. - * - * @param name Name of the context - * @param token Security token - */ - public static void setWritable(Object name, Object token) { - if (checkSecurityToken(name, token)) - readOnlyContexts.remove(name); - } - - - /** - * Set whether or not a context is writable. - * - * @param name Name of the context - */ - public static void setReadOnly(Object name) { - readOnlyContexts.put(name, name); - } - - - /** - * Returns if a context is writable. - * - * @param name Name of the context - */ - public static boolean isWritable(Object name) { - return !(readOnlyContexts.containsKey(name)); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Hashtable; + +/** + * Handles the access control on the JNDI contexts. + * + * @author Remy Maucherat + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class ContextAccessController { + + + // -------------------------------------------------------------- Variables + + + /** + * Catalina context names on which writing is not allowed. + */ + private static Hashtable readOnlyContexts = new Hashtable(); + + + /** + * Security tokens repository. + */ + private static Hashtable securityTokens = new Hashtable(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Set a security token for a context. Can be set only once. + * + * @param name Name of the context + * @param token Security token + */ + public static void setSecurityToken(Object name, Object token) { + if ((!securityTokens.containsKey(name)) && (token != null)) { + securityTokens.put(name, token); + } + } + + + /** + * Remove a security token for a context. + * + * @param name Name of the context + * @param token Security token + */ + public static void unsetSecurityToken(Object name, Object token) { + if (checkSecurityToken(name, token)) { + securityTokens.remove(name); + } + } + + + /** + * Check a submitted security token. The submitted token must be equal to + * the token present in the repository. If no token is present for the + * context, then returns true. + * + * @param name Name of the context + * @param token Submitted security token + */ + public static boolean checkSecurityToken + (Object name, Object token) { + Object refToken = securityTokens.get(name); + if (refToken == null) + return (true); + if ((refToken != null) && (refToken.equals(token))) + return (true); + return (false); + } + + + /** + * Allow writing to a context. + * + * @param name Name of the context + * @param token Security token + */ + public static void setWritable(Object name, Object token) { + if (checkSecurityToken(name, token)) + readOnlyContexts.remove(name); + } + + + /** + * Set whether or not a context is writable. + * + * @param name Name of the context + */ + public static void setReadOnly(Object name) { + readOnlyContexts.put(name, name); + } + + + /** + * Returns if a context is writable. + * + * @param name Name of the context + */ + public static boolean isWritable(Object name) { + return !(readOnlyContexts.containsKey(name)); + } + + +} + diff --git a/java/org/apache/naming/ContextBindings.java b/java/org/apache/naming/ContextBindings.java index 2cc848b1f..90ba59c11 100644 --- a/java/org/apache/naming/ContextBindings.java +++ b/java/org/apache/naming/ContextBindings.java @@ -1,362 +1,362 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Hashtable; -import javax.naming.NamingException; -import javax.naming.Context; - -/** - * Handles the associations : - *
          - *
        • Catalina context name with the NamingContext
        • - *
        • Calling thread with the NamingContext
        • - *
        - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ContextBindings { - - - // -------------------------------------------------------------- Variables - - - /** - * Bindings name - naming context. Keyed by name. - */ - private static Hashtable contextNameBindings = new Hashtable(); - - - /** - * Bindings thread - naming context. Keyed by thread id. - */ - private static Hashtable threadBindings = new Hashtable(); - - - /** - * Bindings thread - name. Keyed by thread id. - */ - private static Hashtable threadNameBindings = new Hashtable(); - - - /** - * Bindings class loader - naming context. Keyed by CL id. - */ - private static Hashtable clBindings = new Hashtable(); - - - /** - * Bindings class loader - name. Keyed by CL id. - */ - private static Hashtable clNameBindings = new Hashtable(); - - - /** - * The string manager for this package. - */ - protected static StringManager sm = - StringManager.getManager(Constants.Package); - - - // --------------------------------------------------------- Public Methods - - - /** - * Binds a context name. - * - * @param name Name of the context - * @param context Associated naming context instance - */ - public static void bindContext(Object name, Context context) { - bindContext(name, context, null); - } - - - /** - * Binds a context name. - * - * @param name Name of the context - * @param context Associated naming context instance - * @param token Security token - */ - public static void bindContext(Object name, Context context, - Object token) { - if (ContextAccessController.checkSecurityToken(name, token)) - contextNameBindings.put(name, context); - } - - - /** - * Unbind context name. - * - * @param name Name of the context - */ - public static void unbindContext(Object name) { - unbindContext(name, null); - } - - - /** - * Unbind context name. - * - * @param name Name of the context - * @param token Security token - */ - public static void unbindContext(Object name, Object token) { - if (ContextAccessController.checkSecurityToken(name, token)) - contextNameBindings.remove(name); - } - - - /** - * Retrieve a naming context. - * - * @param name Name of the context - */ - static Context getContext(Object name) { - return (Context) contextNameBindings.get(name); - } - - - /** - * Binds a naming context to a thread. - * - * @param name Name of the context - */ - public static void bindThread(Object name) - throws NamingException { - bindThread(name, null); - } - - - /** - * Binds a naming context to a thread. - * - * @param name Name of the context - * @param token Security token - */ - public static void bindThread(Object name, Object token) - throws NamingException { - if (ContextAccessController.checkSecurityToken(name, token)) { - Context context = (Context) contextNameBindings.get(name); - if (context == null) - throw new NamingException - (sm.getString("contextBindings.unknownContext", name)); - threadBindings.put(Thread.currentThread(), context); - threadNameBindings.put(Thread.currentThread(), name); - } - } - - - /** - * Unbinds a naming context to a thread. - * - * @param name Name of the context - */ - public static void unbindThread(Object name) { - unbindThread(name, null); - } - - - /** - * Unbinds a naming context to a thread. - * - * @param name Name of the context - * @param token Security token - */ - public static void unbindThread(Object name, Object token) { - if (ContextAccessController.checkSecurityToken(name, token)) { - threadBindings.remove(Thread.currentThread()); - threadNameBindings.remove(Thread.currentThread()); - } - } - - - /** - * Retrieves the naming context bound to a thread. - */ - public static Context getThread() - throws NamingException { - Context context = - (Context) threadBindings.get(Thread.currentThread()); - if (context == null) - throw new NamingException - (sm.getString("contextBindings.noContextBoundToThread")); - return context; - } - - - /** - * Retrieves the naming context name bound to a thread. - */ - static Object getThreadName() - throws NamingException { - Object name = threadNameBindings.get(Thread.currentThread()); - if (name == null) - throw new NamingException - (sm.getString("contextBindings.noContextBoundToThread")); - return name; - } - - - /** - * Tests if current thread is bound to a context. - */ - public static boolean isThreadBound() { - return (threadBindings.containsKey(Thread.currentThread())); - } - - - /** - * Binds a naming context to a class loader. - * - * @param name Name of the context - */ - public static void bindClassLoader(Object name) - throws NamingException { - bindClassLoader(name, null); - } - - - /** - * Binds a naming context to a thread. - * - * @param name Name of the context - * @param token Security token - */ - public static void bindClassLoader(Object name, Object token) - throws NamingException { - bindClassLoader - (name, token, Thread.currentThread().getContextClassLoader()); - } - - - /** - * Binds a naming context to a thread. - * - * @param name Name of the context - * @param token Security token - */ - public static void bindClassLoader(Object name, Object token, - ClassLoader classLoader) - throws NamingException { - if (ContextAccessController.checkSecurityToken(name, token)) { - Context context = (Context) contextNameBindings.get(name); - if (context == null) - throw new NamingException - (sm.getString("contextBindings.unknownContext", name)); - clBindings.put(classLoader, context); - clNameBindings.put(classLoader, name); - } - } - - - /** - * Unbinds a naming context to a class loader. - * - * @param name Name of the context - */ - public static void unbindClassLoader(Object name) { - unbindClassLoader(name, null); - } - - - /** - * Unbinds a naming context to a class loader. - * - * @param name Name of the context - * @param token Security token - */ - public static void unbindClassLoader(Object name, Object token) { - unbindClassLoader(name, token, - Thread.currentThread().getContextClassLoader()); - } - - - /** - * Unbinds a naming context to a class loader. - * - * @param name Name of the context - * @param token Security token - */ - public static void unbindClassLoader(Object name, Object token, - ClassLoader classLoader) { - if (ContextAccessController.checkSecurityToken(name, token)) { - Object n = clNameBindings.get(classLoader); - if ((n==null) || !(n.equals(name))) { - return; - } - clBindings.remove(classLoader); - clNameBindings.remove(classLoader); - } - } - - - /** - * Retrieves the naming context bound to a class loader. - */ - public static Context getClassLoader() - throws NamingException { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Context context = null; - do { - context = (Context) clBindings.get(cl); - if (context != null) { - return context; - } - } while ((cl = cl.getParent()) != null); - throw new NamingException - (sm.getString("contextBindings.noContextBoundToCL")); - } - - - /** - * Retrieves the naming context name bound to a class loader. - */ - static Object getClassLoaderName() - throws NamingException { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - Object name = null; - do { - name = clNameBindings.get(cl); - if (name != null) { - return name; - } - } while ((cl = cl.getParent()) != null); - throw new NamingException - (sm.getString("contextBindings.noContextBoundToCL")); - } - - - /** - * Tests if current class loader is bound to a context. - */ - public static boolean isClassLoaderBound() { - ClassLoader cl = Thread.currentThread().getContextClassLoader(); - do { - if (clBindings.containsKey(cl)) { - return true; - } - } while ((cl = cl.getParent()) != null); - return false; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Hashtable; +import javax.naming.NamingException; +import javax.naming.Context; + +/** + * Handles the associations : + *
          + *
        • Catalina context name with the NamingContext
        • + *
        • Calling thread with the NamingContext
        • + *
        + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ContextBindings { + + + // -------------------------------------------------------------- Variables + + + /** + * Bindings name - naming context. Keyed by name. + */ + private static Hashtable contextNameBindings = new Hashtable(); + + + /** + * Bindings thread - naming context. Keyed by thread id. + */ + private static Hashtable threadBindings = new Hashtable(); + + + /** + * Bindings thread - name. Keyed by thread id. + */ + private static Hashtable threadNameBindings = new Hashtable(); + + + /** + * Bindings class loader - naming context. Keyed by CL id. + */ + private static Hashtable clBindings = new Hashtable(); + + + /** + * Bindings class loader - name. Keyed by CL id. + */ + private static Hashtable clNameBindings = new Hashtable(); + + + /** + * The string manager for this package. + */ + protected static StringManager sm = + StringManager.getManager(Constants.Package); + + + // --------------------------------------------------------- Public Methods + + + /** + * Binds a context name. + * + * @param name Name of the context + * @param context Associated naming context instance + */ + public static void bindContext(Object name, Context context) { + bindContext(name, context, null); + } + + + /** + * Binds a context name. + * + * @param name Name of the context + * @param context Associated naming context instance + * @param token Security token + */ + public static void bindContext(Object name, Context context, + Object token) { + if (ContextAccessController.checkSecurityToken(name, token)) + contextNameBindings.put(name, context); + } + + + /** + * Unbind context name. + * + * @param name Name of the context + */ + public static void unbindContext(Object name) { + unbindContext(name, null); + } + + + /** + * Unbind context name. + * + * @param name Name of the context + * @param token Security token + */ + public static void unbindContext(Object name, Object token) { + if (ContextAccessController.checkSecurityToken(name, token)) + contextNameBindings.remove(name); + } + + + /** + * Retrieve a naming context. + * + * @param name Name of the context + */ + static Context getContext(Object name) { + return (Context) contextNameBindings.get(name); + } + + + /** + * Binds a naming context to a thread. + * + * @param name Name of the context + */ + public static void bindThread(Object name) + throws NamingException { + bindThread(name, null); + } + + + /** + * Binds a naming context to a thread. + * + * @param name Name of the context + * @param token Security token + */ + public static void bindThread(Object name, Object token) + throws NamingException { + if (ContextAccessController.checkSecurityToken(name, token)) { + Context context = (Context) contextNameBindings.get(name); + if (context == null) + throw new NamingException + (sm.getString("contextBindings.unknownContext", name)); + threadBindings.put(Thread.currentThread(), context); + threadNameBindings.put(Thread.currentThread(), name); + } + } + + + /** + * Unbinds a naming context to a thread. + * + * @param name Name of the context + */ + public static void unbindThread(Object name) { + unbindThread(name, null); + } + + + /** + * Unbinds a naming context to a thread. + * + * @param name Name of the context + * @param token Security token + */ + public static void unbindThread(Object name, Object token) { + if (ContextAccessController.checkSecurityToken(name, token)) { + threadBindings.remove(Thread.currentThread()); + threadNameBindings.remove(Thread.currentThread()); + } + } + + + /** + * Retrieves the naming context bound to a thread. + */ + public static Context getThread() + throws NamingException { + Context context = + (Context) threadBindings.get(Thread.currentThread()); + if (context == null) + throw new NamingException + (sm.getString("contextBindings.noContextBoundToThread")); + return context; + } + + + /** + * Retrieves the naming context name bound to a thread. + */ + static Object getThreadName() + throws NamingException { + Object name = threadNameBindings.get(Thread.currentThread()); + if (name == null) + throw new NamingException + (sm.getString("contextBindings.noContextBoundToThread")); + return name; + } + + + /** + * Tests if current thread is bound to a context. + */ + public static boolean isThreadBound() { + return (threadBindings.containsKey(Thread.currentThread())); + } + + + /** + * Binds a naming context to a class loader. + * + * @param name Name of the context + */ + public static void bindClassLoader(Object name) + throws NamingException { + bindClassLoader(name, null); + } + + + /** + * Binds a naming context to a thread. + * + * @param name Name of the context + * @param token Security token + */ + public static void bindClassLoader(Object name, Object token) + throws NamingException { + bindClassLoader + (name, token, Thread.currentThread().getContextClassLoader()); + } + + + /** + * Binds a naming context to a thread. + * + * @param name Name of the context + * @param token Security token + */ + public static void bindClassLoader(Object name, Object token, + ClassLoader classLoader) + throws NamingException { + if (ContextAccessController.checkSecurityToken(name, token)) { + Context context = (Context) contextNameBindings.get(name); + if (context == null) + throw new NamingException + (sm.getString("contextBindings.unknownContext", name)); + clBindings.put(classLoader, context); + clNameBindings.put(classLoader, name); + } + } + + + /** + * Unbinds a naming context to a class loader. + * + * @param name Name of the context + */ + public static void unbindClassLoader(Object name) { + unbindClassLoader(name, null); + } + + + /** + * Unbinds a naming context to a class loader. + * + * @param name Name of the context + * @param token Security token + */ + public static void unbindClassLoader(Object name, Object token) { + unbindClassLoader(name, token, + Thread.currentThread().getContextClassLoader()); + } + + + /** + * Unbinds a naming context to a class loader. + * + * @param name Name of the context + * @param token Security token + */ + public static void unbindClassLoader(Object name, Object token, + ClassLoader classLoader) { + if (ContextAccessController.checkSecurityToken(name, token)) { + Object n = clNameBindings.get(classLoader); + if ((n==null) || !(n.equals(name))) { + return; + } + clBindings.remove(classLoader); + clNameBindings.remove(classLoader); + } + } + + + /** + * Retrieves the naming context bound to a class loader. + */ + public static Context getClassLoader() + throws NamingException { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Context context = null; + do { + context = (Context) clBindings.get(cl); + if (context != null) { + return context; + } + } while ((cl = cl.getParent()) != null); + throw new NamingException + (sm.getString("contextBindings.noContextBoundToCL")); + } + + + /** + * Retrieves the naming context name bound to a class loader. + */ + static Object getClassLoaderName() + throws NamingException { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + Object name = null; + do { + name = clNameBindings.get(cl); + if (name != null) { + return name; + } + } while ((cl = cl.getParent()) != null); + throw new NamingException + (sm.getString("contextBindings.noContextBoundToCL")); + } + + + /** + * Tests if current class loader is bound to a context. + */ + public static boolean isClassLoaderBound() { + ClassLoader cl = Thread.currentThread().getContextClassLoader(); + do { + if (clBindings.containsKey(cl)) { + return true; + } + } while ((cl = cl.getParent()) != null); + return false; + } + + +} diff --git a/java/org/apache/naming/EjbRef.java b/java/org/apache/naming/EjbRef.java index 35c89ee79..c42f5b75d 100644 --- a/java/org/apache/naming/EjbRef.java +++ b/java/org/apache/naming/EjbRef.java @@ -1,137 +1,137 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import javax.naming.Context; -import javax.naming.Reference; -import javax.naming.StringRefAddr; - -/** - * Represents a reference address to an EJB. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class EjbRef - extends Reference { - - - // -------------------------------------------------------------- Constants - - - /** - * Default factory for this reference. - */ - public static final String DEFAULT_FACTORY = - org.apache.naming.factory.Constants.DEFAULT_EJB_FACTORY; - - - /** - * EJB type address type. - */ - public static final String TYPE = "type"; - - - /** - * Remote interface classname address type. - */ - public static final String REMOTE = "remote"; - - - /** - * Link address type. - */ - public static final String LINK = "link"; - - - // ----------------------------------------------------------- Constructors - - - /** - * EJB Reference. - * - * @param ejbType EJB type - * @param home Home interface classname - * @param remote Remote interface classname - * @param link EJB link - */ - public EjbRef(String ejbType, String home, String remote, String link) { - this(ejbType, home, remote, link, null, null); - } - - - /** - * EJB Reference. - * - * @param ejbType EJB type - * @param home Home interface classname - * @param remote Remote interface classname - * @param link EJB link - */ - public EjbRef(String ejbType, String home, String remote, String link, - String factory, String factoryLocation) { - super(home, factory, factoryLocation); - StringRefAddr refAddr = null; - if (ejbType != null) { - refAddr = new StringRefAddr(TYPE, ejbType); - add(refAddr); - } - if (remote != null) { - refAddr = new StringRefAddr(REMOTE, remote); - add(refAddr); - } - if (link != null) { - refAddr = new StringRefAddr(LINK, link); - add(refAddr); - } - } - - - // ----------------------------------------------------- Instance Variables - - - // -------------------------------------------------------- RefAddr Methods - - - // ------------------------------------------------------ Reference Methods - - - /** - * Retrieves the class name of the factory of the object to which this - * reference refers. - */ - public String getFactoryClassName() { - String factory = super.getFactoryClassName(); - if (factory != null) { - return factory; - } else { - factory = System.getProperty(Context.OBJECT_FACTORIES); - if (factory != null) { - return null; - } else { - return DEFAULT_FACTORY; - } - } - } - - - // ------------------------------------------------------------- Properties - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import javax.naming.Context; +import javax.naming.Reference; +import javax.naming.StringRefAddr; + +/** + * Represents a reference address to an EJB. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class EjbRef + extends Reference { + + + // -------------------------------------------------------------- Constants + + + /** + * Default factory for this reference. + */ + public static final String DEFAULT_FACTORY = + org.apache.naming.factory.Constants.DEFAULT_EJB_FACTORY; + + + /** + * EJB type address type. + */ + public static final String TYPE = "type"; + + + /** + * Remote interface classname address type. + */ + public static final String REMOTE = "remote"; + + + /** + * Link address type. + */ + public static final String LINK = "link"; + + + // ----------------------------------------------------------- Constructors + + + /** + * EJB Reference. + * + * @param ejbType EJB type + * @param home Home interface classname + * @param remote Remote interface classname + * @param link EJB link + */ + public EjbRef(String ejbType, String home, String remote, String link) { + this(ejbType, home, remote, link, null, null); + } + + + /** + * EJB Reference. + * + * @param ejbType EJB type + * @param home Home interface classname + * @param remote Remote interface classname + * @param link EJB link + */ + public EjbRef(String ejbType, String home, String remote, String link, + String factory, String factoryLocation) { + super(home, factory, factoryLocation); + StringRefAddr refAddr = null; + if (ejbType != null) { + refAddr = new StringRefAddr(TYPE, ejbType); + add(refAddr); + } + if (remote != null) { + refAddr = new StringRefAddr(REMOTE, remote); + add(refAddr); + } + if (link != null) { + refAddr = new StringRefAddr(LINK, link); + add(refAddr); + } + } + + + // ----------------------------------------------------- Instance Variables + + + // -------------------------------------------------------- RefAddr Methods + + + // ------------------------------------------------------ Reference Methods + + + /** + * Retrieves the class name of the factory of the object to which this + * reference refers. + */ + public String getFactoryClassName() { + String factory = super.getFactoryClassName(); + if (factory != null) { + return factory; + } else { + factory = System.getProperty(Context.OBJECT_FACTORIES); + if (factory != null) { + return null; + } else { + return DEFAULT_FACTORY; + } + } + } + + + // ------------------------------------------------------------- Properties + + +} diff --git a/java/org/apache/naming/JndiPermission.java b/java/org/apache/naming/JndiPermission.java index 71b875a0c..b36cb31e6 100644 --- a/java/org/apache/naming/JndiPermission.java +++ b/java/org/apache/naming/JndiPermission.java @@ -1,61 +1,61 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.security.BasicPermission; - -/** - * Java SecurityManager Permission class for JNDI name based file resources - *

        - * The JndiPermission extends the BasicPermission. - * The permission name is a full or partial jndi resource name. - * An * can be used at the end of the name to match all named - * resources that start with name. There are no actions.

        - *

        - * Example that grants permission to read all JNDI file based resources: - *

      • permission org.apache.naming.JndiPermission "*";
      • - *

        - * - * @author Glenn Nielsen - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public final class JndiPermission extends BasicPermission { - - // ----------------------------------------------------------- Constructors - - /** - * Creates a new JndiPermission with no actions - * - * @param name - JNDI resource path name - */ - public JndiPermission(String name) { - super(name); - } - - /** - * Creates a new JndiPermission with actions - * - * @param name - JNDI resource path name - * @param actions - JNDI actions (none defined) - */ - public JndiPermission(String name, String actions) { - super(name,actions); - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.security.BasicPermission; + +/** + * Java SecurityManager Permission class for JNDI name based file resources + *

        + * The JndiPermission extends the BasicPermission. + * The permission name is a full or partial jndi resource name. + * An * can be used at the end of the name to match all named + * resources that start with name. There are no actions.

        + *

        + * Example that grants permission to read all JNDI file based resources: + *

      • permission org.apache.naming.JndiPermission "*";
      • + *

        + * + * @author Glenn Nielsen + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public final class JndiPermission extends BasicPermission { + + // ----------------------------------------------------------- Constructors + + /** + * Creates a new JndiPermission with no actions + * + * @param name - JNDI resource path name + */ + public JndiPermission(String name) { + super(name); + } + + /** + * Creates a new JndiPermission with actions + * + * @param name - JNDI resource path name + * @param actions - JNDI actions (none defined) + */ + public JndiPermission(String name, String actions) { + super(name,actions); + } + +} diff --git a/java/org/apache/naming/LocalStrings.properties b/java/org/apache/naming/LocalStrings.properties index e466ed415..254f57254 100644 --- a/java/org/apache/naming/LocalStrings.properties +++ b/java/org/apache/naming/LocalStrings.properties @@ -1,11 +1,11 @@ -contextBindings.unknownContext=Unknown context name : {0} -contextBindings.noContextBoundToThread=No naming context bound to this thread -contextBindings.noContextBoundToCL=No naming context bound to this class loader -selectorContext.noJavaUrl=This context must be accessed throught a java: URL -namingContext.contextExpected=Name is not bound to a Context -namingContext.failResolvingReference=Unexpected exception resolving reference -namingContext.nameNotBound=Name {0} is not bound in this Context -namingContext.readOnly=Context is read only -namingContext.invalidName=Name is not valid -namingContext.alreadyBound=Name {0} is already bound in this Context +contextBindings.unknownContext=Unknown context name : {0} +contextBindings.noContextBoundToThread=No naming context bound to this thread +contextBindings.noContextBoundToCL=No naming context bound to this class loader +selectorContext.noJavaUrl=This context must be accessed throught a java: URL +namingContext.contextExpected=Name is not bound to a Context +namingContext.failResolvingReference=Unexpected exception resolving reference +namingContext.nameNotBound=Name {0} is not bound in this Context +namingContext.readOnly=Context is read only +namingContext.invalidName=Name is not valid +namingContext.alreadyBound=Name {0} is already bound in this Context namingContext.noAbsoluteName=Can''t generate an absolute name for this namespace \ No newline at end of file diff --git a/java/org/apache/naming/LocalStrings_es.properties b/java/org/apache/naming/LocalStrings_es.properties index 1c4bb9ac5..2cfe4bba7 100644 --- a/java/org/apache/naming/LocalStrings_es.properties +++ b/java/org/apache/naming/LocalStrings_es.properties @@ -1,16 +1,16 @@ -# $Id: LocalStrings_es.properties 301082 2002-07-18 16:47:23Z remm $ - -# language es - -# package org.apache.naming - - -contextBindings.unknownContext=Contexto {0} desconocido -contextBindings.noContextBoundToThread=No hay contexto de nombres asociado a este hilo -selectorContext.noJavaUrl=Este contexto debe de ser accedido a traves de una URL de tipo java: -namingContext.contextExpected=El nombre no esta asociado a ningun Contexto -namingContext.nameNotBound=El nombre {0} no este asociado a este contexto -namingContext.readOnly=El contexto es de solo lectura -namingContext.invalidName=Nombre no valido -namingContext.noAbsoluteName=No se puede generar un nombre absoluto para este espacio de nombres -namingContext.alreadyBound=El nombre {0} este ya asociado en este Contexto +# $Id: LocalStrings_es.properties 301082 2002-07-18 16:47:23Z remm $ + +# language es + +# package org.apache.naming + + +contextBindings.unknownContext=Contexto {0} desconocido +contextBindings.noContextBoundToThread=No hay contexto de nombres asociado a este hilo +selectorContext.noJavaUrl=Este contexto debe de ser accedido a traves de una URL de tipo java: +namingContext.contextExpected=El nombre no esta asociado a ningun Contexto +namingContext.nameNotBound=El nombre {0} no este asociado a este contexto +namingContext.readOnly=El contexto es de solo lectura +namingContext.invalidName=Nombre no valido +namingContext.noAbsoluteName=No se puede generar un nombre absoluto para este espacio de nombres +namingContext.alreadyBound=El nombre {0} este ya asociado en este Contexto diff --git a/java/org/apache/naming/LocalStrings_fr.properties b/java/org/apache/naming/LocalStrings_fr.properties index 444745244..911a60217 100644 --- a/java/org/apache/naming/LocalStrings_fr.properties +++ b/java/org/apache/naming/LocalStrings_fr.properties @@ -1,11 +1,11 @@ -contextBindings.unknownContext=Nom de Contexte inconnu : {0} -contextBindings.noContextBoundToThread=Aucun Contexte de nommage lié à ce thread -contextBindings.noContextBoundToCL=Aucun Contexte de nommage lié à ce chargeur de classes -selectorContext.noJavaUrl=Ce Contexte doit être accédé par une java: URL -namingContext.contextExpected=Le Nom n''est pas lié à un Contexte -namingContext.failResolvingReference=Une erreur s est produite durant la résolution de la référence -namingContext.nameNotBound=Le Nom {0} n''est pas lié à ce Contexte -namingContext.readOnly=Le Contexte est en lecture seule -namingContext.invalidName=Le Nom est invalide -namingContext.alreadyBound=Le Nom {0} est déjà lié à ce Contexte +contextBindings.unknownContext=Nom de Contexte inconnu : {0} +contextBindings.noContextBoundToThread=Aucun Contexte de nommage lié à ce thread +contextBindings.noContextBoundToCL=Aucun Contexte de nommage lié à ce chargeur de classes +selectorContext.noJavaUrl=Ce Contexte doit être accédé par une java: URL +namingContext.contextExpected=Le Nom n''est pas lié à un Contexte +namingContext.failResolvingReference=Une erreur s est produite durant la résolution de la référence +namingContext.nameNotBound=Le Nom {0} n''est pas lié à ce Contexte +namingContext.readOnly=Le Contexte est en lecture seule +namingContext.invalidName=Le Nom est invalide +namingContext.alreadyBound=Le Nom {0} est déjà lié à ce Contexte namingContext.noAbsoluteName=Impossible de générer un nom absolu pour cet espace de nommage (namespace) \ No newline at end of file diff --git a/java/org/apache/naming/LocalStrings_ja.properties b/java/org/apache/naming/LocalStrings_ja.properties index e4d67d1e6..7d07efd35 100644 --- a/java/org/apache/naming/LocalStrings_ja.properties +++ b/java/org/apache/naming/LocalStrings_ja.properties @@ -1,11 +1,11 @@ -contextBindings.unknownContext=\u672a\u77e5\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u540d\u3067\u3059: {0} -contextBindings.noContextBoundToThread=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -contextBindings.noContextBoundToCL=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -selectorContext.noJavaUrl=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u306fjava: URL\u3092\u7528\u3044\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u306d\u3070\u3044\u3051\u307e\u305b\u3093 -namingContext.contextExpected=\u540d\u524d\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -namingContext.failResolvingReference=\u53c2\u7167\u306e\u89e3\u6c7a\u4e2d\u306b\u4e88\u6e2c\u3057\u306a\u3044\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f -namingContext.nameNotBound=\u540d\u524d {0} \u306f\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -namingContext.readOnly=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u30ea\u30fc\u30c9\u30aa\u30f3\u30ea\u30fc\u3067\u3059 -namingContext.invalidName=\u540d\u524d\u306f\u7121\u52b9\u3067\u3059 -namingContext.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 -namingContext.noAbsoluteName=\u3053\u306e\u540d\u524d\u7a7a\u9593\u306b\u7d76\u5bfe\u540d\u3092\u751f\u6210\u3067\u304d\u307e\u305b\u3093 +contextBindings.unknownContext=\u672a\u77e5\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u540d\u3067\u3059: {0} +contextBindings.noContextBoundToThread=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30b9\u30ec\u30c3\u30c9\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +contextBindings.noContextBoundToCL=\u540d\u524d\u4ed8\u3051\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u3053\u306e\u30af\u30e9\u30b9\u30ed\u30fc\u30c0\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +selectorContext.noJavaUrl=\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u306fjava: URL\u3092\u7528\u3044\u3066\u30a2\u30af\u30bb\u30b9\u3055\u308c\u306d\u3070\u3044\u3051\u307e\u305b\u3093 +namingContext.contextExpected=\u540d\u524d\u304c\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +namingContext.failResolvingReference=\u53c2\u7167\u306e\u89e3\u6c7a\u4e2d\u306b\u4e88\u6e2c\u3057\u306a\u3044\u4f8b\u5916\u304c\u767a\u751f\u3057\u307e\u3057\u305f +namingContext.nameNotBound=\u540d\u524d {0} \u306f\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +namingContext.readOnly=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306f\u30ea\u30fc\u30c9\u30aa\u30f3\u30ea\u30fc\u3067\u3059 +namingContext.invalidName=\u540d\u524d\u306f\u7121\u52b9\u3067\u3059 +namingContext.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 +namingContext.noAbsoluteName=\u3053\u306e\u540d\u524d\u7a7a\u9593\u306b\u7d76\u5bfe\u540d\u3092\u751f\u6210\u3067\u304d\u307e\u305b\u3093 diff --git a/java/org/apache/naming/NameParserImpl.java b/java/org/apache/naming/NameParserImpl.java index c2a062fd9..53f5a1c1e 100644 --- a/java/org/apache/naming/NameParserImpl.java +++ b/java/org/apache/naming/NameParserImpl.java @@ -1,56 +1,56 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import javax.naming.NameParser; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.CompositeName; - -/** - * Parses names. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class NameParserImpl - implements NameParser { - - - // ----------------------------------------------------- Instance Variables - - - // ----------------------------------------------------- NameParser Methods - - - /** - * Parses a name into its components. - * - * @param name The non-null string name to parse - * @return A non-null parsed form of the name using the naming convention - * of this parser. - */ - public Name parse(String name) - throws NamingException { - return new CompositeName(name); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import javax.naming.NameParser; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.CompositeName; + +/** + * Parses names. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class NameParserImpl + implements NameParser { + + + // ----------------------------------------------------- Instance Variables + + + // ----------------------------------------------------- NameParser Methods + + + /** + * Parses a name into its components. + * + * @param name The non-null string name to parse + * @return A non-null parsed form of the name using the naming convention + * of this parser. + */ + public Name parse(String name) + throws NamingException { + return new CompositeName(name); + } + + +} + diff --git a/java/org/apache/naming/NamingContext.java b/java/org/apache/naming/NamingContext.java index b330f337a..f7a47e3db 100644 --- a/java/org/apache/naming/NamingContext.java +++ b/java/org/apache/naming/NamingContext.java @@ -1,907 +1,907 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Enumeration; -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.LinkRef; -import javax.naming.CompositeName; -import javax.naming.NameParser; -import javax.naming.Referenceable; -import javax.naming.Reference; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.NameAlreadyBoundException; -import javax.naming.NameNotFoundException; -import javax.naming.NotContextException; -import javax.naming.InitialContext; -import javax.naming.OperationNotSupportedException; -import javax.naming.spi.NamingManager; - -/** - * Catalina JNDI Context implementation. - * - * @author Remy Maucherat - * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ - */ -public class NamingContext implements Context { - - - // -------------------------------------------------------------- Constants - - - /** - * Name parser for this context. - */ - protected static final NameParser nameParser = new NameParserImpl(); - - - private static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(NamingContext.class); - - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a naming context using the given environment. - */ - public NamingContext(Hashtable env, String name) - throws NamingException { - this.bindings = new HashMap(); - this.env = new Hashtable(); - // FIXME ? Could be put in the environment ? - this.name = name; - // Populating the environment hashtable - if (env != null ) { - Enumeration envEntries = env.keys(); - while (envEntries.hasMoreElements()) { - String entryName = (String) envEntries.nextElement(); - addToEnvironment(entryName, env.get(entryName)); - } - } - } - - - /** - * Builds a naming context using the given environment. - */ - public NamingContext(Hashtable env, String name, HashMap bindings) - throws NamingException { - this(env, name); - this.bindings = bindings; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Environment. - */ - protected Hashtable env; - - - /** - * The string manager for this package. - */ - protected StringManager sm = StringManager.getManager(Constants.Package); - - - /** - * Bindings in this Context. - */ - protected HashMap bindings; - - - /** - * Name of the associated Catalina Context. - */ - protected String name; - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. If name is empty, returns a new instance - * of this context (which represents the same naming context as this - * context, but its environment may be modified independently and it may - * be accessed concurrently). - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(Name name) - throws NamingException { - return lookup(name, true); - } - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(String name) - throws NamingException { - return lookup(new CompositeName(name), true); - } - - - /** - * Binds a name to an object. All intermediate contexts and the target - * context (that named by all but terminal atomic component of the name) - * must already exist. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj) - throws NamingException { - bind(name, obj, false); - } - - - /** - * Binds a name to an object. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj) - throws NamingException { - bind(new CompositeName(name), obj); - } - - - /** - * Binds a name to an object, overwriting any existing binding. All - * intermediate contexts and the target context (that named by all but - * terminal atomic component of the name) must already exist. - *

        - * If the object is a DirContext, any existing attributes associated with - * the name are replaced with those of the object. Otherwise, any - * existing attributes associated with the name remain unchanged. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj) - throws NamingException { - bind(name, obj, true); - } - - - /** - * Binds a name to an object, overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj) - throws NamingException { - rebind(new CompositeName(name), obj); - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(Name name) - throws NamingException { - checkWritable(); - - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) - throw new NamingException - (sm.getString("namingContext.invalidName")); - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - - if (name.size() > 1) { - if (entry.type == NamingEntry.CONTEXT) { - ((Context) entry.value).unbind(name.getSuffix(1)); - } else { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - } else { - bindings.remove(name.get(0)); - } - - } - - - /** - * Unbinds the named object. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(String name) - throws NamingException { - unbind(new CompositeName(name)); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(Name oldName, Name newName) - throws NamingException { - Object value = lookup(oldName); - bind(newName, value); - unbind(oldName); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(String oldName, String newName) - throws NamingException { - rename(new CompositeName(oldName), new CompositeName(newName)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(Name name) - throws NamingException { - // Removing empty parts - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) { - return new NamingContextEnumeration(bindings.values().iterator()); - } - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - - if (entry.type != NamingEntry.CONTEXT) { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - return ((Context) entry.value).list(name.getSuffix(1)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(String name) - throws NamingException { - return list(new CompositeName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(Name name) - throws NamingException { - // Removing empty parts - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) { - return new NamingContextBindingsEnumeration(bindings.values().iterator(), this); - } - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - - if (entry.type != NamingEntry.CONTEXT) { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - return ((Context) entry.value).listBindings(name.getSuffix(1)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(String name) - throws NamingException { - return listBindings(new CompositeName(name)); - } - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(Name name) - throws NamingException { - - checkWritable(); - - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) - throw new NamingException - (sm.getString("namingContext.invalidName")); - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - - if (name.size() > 1) { - if (entry.type == NamingEntry.CONTEXT) { - ((Context) entry.value).unbind(name.getSuffix(1)); - } else { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - } else { - if (entry.type == NamingEntry.CONTEXT) { - ((Context) entry.value).close(); - bindings.remove(name.get(0)); - } else { - throw new NotContextException - (sm.getString("namingContext.contextExpected")); - } - } - - } - - - /** - * Destroys the named context and removes it from the namespace. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(String name) - throws NamingException { - destroySubcontext(new CompositeName(name)); - } - - - /** - * Creates and binds a new context. Creates a new context with the given - * name and binds it in the target context (that named by all but - * terminal atomic component of the name). All intermediate contexts and - * the target context must already exist. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(Name name) - throws NamingException { - checkWritable(); - - Context newContext = new NamingContext(env, this.name); - bind(name, newContext); - - return newContext; - } - - - /** - * Creates and binds a new context. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(String name) - throws NamingException { - return createSubcontext(new CompositeName(name)); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(Name name) - throws NamingException { - return lookup(name, false); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(String name) - throws NamingException { - return lookup(new CompositeName(name), false); - } - - - /** - * Retrieves the parser associated with the named context. In a - * federation of namespaces, different naming systems will parse names - * differently. This method allows an application to get a parser for - * parsing names into their atomic components using the naming convention - * of a particular naming system. Within any single naming system, - * NameParser objects returned by this method must be equal (using the - * equals() test). - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(Name name) - throws NamingException { - - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) - return nameParser; - - if (name.size() > 1) { - Object obj = bindings.get(name.get(0)); - if (obj instanceof Context) { - return ((Context) obj).getNameParser(name.getSuffix(1)); - } else { - throw new NotContextException - (sm.getString("namingContext.contextExpected")); - } - } - - return nameParser; - - } - - - /** - * Retrieves the parser associated with the named context. - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(String name) - throws NamingException { - return getNameParser(new CompositeName(name)); - } - - - /** - * Composes the name of this context with a name relative to this context. - *

        - * Given a name (name) relative to this context, and the name (prefix) - * of this context relative to one of its ancestors, this method returns - * the composition of the two names using the syntax appropriate for the - * naming system(s) involved. That is, if name names an object relative - * to this context, the result is the name of the same object, but - * relative to the ancestor context. None of the names may be null. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public Name composeName(Name name, Name prefix) - throws NamingException { - prefix = (Name) prefix.clone(); - return prefix.addAll(name); - } - - - /** - * Composes the name of this context with a name relative to this context. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public String composeName(String name, String prefix) - throws NamingException { - return prefix + "/" + name; - } - - - /** - * Adds a new environment property to the environment of this context. If - * the property already exists, its value is overwritten. - * - * @param propName the name of the environment property to add; may not - * be null - * @param propVal the value of the property to add; may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object addToEnvironment(String propName, Object propVal) - throws NamingException { - return env.put(propName, propVal); - } - - - /** - * Removes an environment property from the environment of this context. - * - * @param propName the name of the environment property to remove; - * may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object removeFromEnvironment(String propName) - throws NamingException { - return env.remove(propName); - } - - - /** - * Retrieves the environment in effect for this context. See class - * description for more details on environment properties. - * The caller should not make any changes to the object returned: their - * effect on the context is undefined. The environment of this context - * may be changed using addToEnvironment() and removeFromEnvironment(). - * - * @return the environment of this context; never null - * @exception NamingException if a naming exception is encountered - */ - public Hashtable getEnvironment() - throws NamingException { - return env; - } - - - /** - * Closes this context. This method releases this context's resources - * immediately, instead of waiting for them to be released automatically - * by the garbage collector. - * This method is idempotent: invoking it on a context that has already - * been closed has no effect. Invoking any other method on a closed - * context is not allowed, and results in undefined behaviour. - * - * @exception NamingException if a naming exception is encountered - */ - public void close() - throws NamingException { - env.clear(); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public String getNameInNamespace() - throws NamingException { - throw new OperationNotSupportedException - (sm.getString("namingContext.noAbsoluteName")); - //FIXME ? - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @param resolveLinks If true, the links will be resolved - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - protected Object lookup(Name name, boolean resolveLinks) - throws NamingException { - - // Removing empty parts - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) { - // If name is empty, a newly allocated naming context is returned - return new NamingContext(env, this.name, bindings); - } - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - - if (name.size() > 1) { - // If the size of the name is greater that 1, then we go through a - // number of subcontexts. - if (entry.type != NamingEntry.CONTEXT) { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - return ((Context) entry.value).lookup(name.getSuffix(1)); - } else { - if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) { - String link = ((LinkRef) entry.value).getLinkName(); - if (link.startsWith(".")) { - // Link relative to this context - return lookup(link.substring(1)); - } else { - return (new InitialContext(env)).lookup(link); - } - } else if (entry.type == NamingEntry.REFERENCE) { - try { - Object obj = NamingManager.getObjectInstance - (entry.value, name, this, env); - if (obj != null) { - entry.value = obj; - entry.type = NamingEntry.ENTRY; - } - return obj; - } catch (NamingException e) { - throw e; - } catch (Exception e) { - log.warn(sm.getString - ("namingContext.failResolvingReference"), e); - throw new NamingException(e.getMessage()); - } - } else { - return entry.value; - } - } - - } - - - /** - * Binds a name to an object. All intermediate contexts and the target - * context (that named by all but terminal atomic component of the name) - * must already exist. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param rebind if true, then perform a rebind (ie, overwrite) - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - protected void bind(Name name, Object obj, boolean rebind) - throws NamingException { - - checkWritable(); - - while ((!name.isEmpty()) && (name.get(0).length() == 0)) - name = name.getSuffix(1); - if (name.isEmpty()) - throw new NamingException - (sm.getString("namingContext.invalidName")); - - NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); - - if (name.size() > 1) { - if (entry == null) { - throw new NameNotFoundException - (sm.getString("namingContext.nameNotBound", name.get(0))); - } - if (entry.type == NamingEntry.CONTEXT) { - if (rebind) { - ((Context) entry.value).rebind(name.getSuffix(1), obj); - } else { - ((Context) entry.value).bind(name.getSuffix(1), obj); - } - } else { - throw new NamingException - (sm.getString("namingContext.contextExpected")); - } - } else { - if ((!rebind) && (entry != null)) { - throw new NameAlreadyBoundException - (sm.getString("namingContext.alreadyBound", name.get(0))); - } else { - // Getting the type of the object and wrapping it within a new - // NamingEntry - Object toBind = - NamingManager.getStateToBind(obj, name, this, env); - if (toBind instanceof Context) { - entry = new NamingEntry(name.get(0), toBind, - NamingEntry.CONTEXT); - } else if (toBind instanceof LinkRef) { - entry = new NamingEntry(name.get(0), toBind, - NamingEntry.LINK_REF); - } else if (toBind instanceof Reference) { - entry = new NamingEntry(name.get(0), toBind, - NamingEntry.REFERENCE); - } else if (toBind instanceof Referenceable) { - toBind = ((Referenceable) toBind).getReference(); - entry = new NamingEntry(name.get(0), toBind, - NamingEntry.REFERENCE); - } else { - entry = new NamingEntry(name.get(0), toBind, - NamingEntry.ENTRY); - } - bindings.put(name.get(0), entry); - } - } - - } - - - /** - * Returns true if writing is allowed on this context. - */ - protected boolean isWritable() { - return ContextAccessController.isWritable(name); - } - - - /** - * Throws a naming exception is Context is not writable. - */ - protected void checkWritable() - throws NamingException { - if (!isWritable()) - throw new NamingException(sm.getString("namingContext.readOnly")); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Enumeration; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.LinkRef; +import javax.naming.CompositeName; +import javax.naming.NameParser; +import javax.naming.Referenceable; +import javax.naming.Reference; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.NameAlreadyBoundException; +import javax.naming.NameNotFoundException; +import javax.naming.NotContextException; +import javax.naming.InitialContext; +import javax.naming.OperationNotSupportedException; +import javax.naming.spi.NamingManager; + +/** + * Catalina JNDI Context implementation. + * + * @author Remy Maucherat + * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ + */ +public class NamingContext implements Context { + + + // -------------------------------------------------------------- Constants + + + /** + * Name parser for this context. + */ + protected static final NameParser nameParser = new NameParserImpl(); + + + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(NamingContext.class); + + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a naming context using the given environment. + */ + public NamingContext(Hashtable env, String name) + throws NamingException { + this.bindings = new HashMap(); + this.env = new Hashtable(); + // FIXME ? Could be put in the environment ? + this.name = name; + // Populating the environment hashtable + if (env != null ) { + Enumeration envEntries = env.keys(); + while (envEntries.hasMoreElements()) { + String entryName = (String) envEntries.nextElement(); + addToEnvironment(entryName, env.get(entryName)); + } + } + } + + + /** + * Builds a naming context using the given environment. + */ + public NamingContext(Hashtable env, String name, HashMap bindings) + throws NamingException { + this(env, name); + this.bindings = bindings; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Environment. + */ + protected Hashtable env; + + + /** + * The string manager for this package. + */ + protected StringManager sm = StringManager.getManager(Constants.Package); + + + /** + * Bindings in this Context. + */ + protected HashMap bindings; + + + /** + * Name of the associated Catalina Context. + */ + protected String name; + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. If name is empty, returns a new instance + * of this context (which represents the same naming context as this + * context, but its environment may be modified independently and it may + * be accessed concurrently). + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(Name name) + throws NamingException { + return lookup(name, true); + } + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(String name) + throws NamingException { + return lookup(new CompositeName(name), true); + } + + + /** + * Binds a name to an object. All intermediate contexts and the target + * context (that named by all but terminal atomic component of the name) + * must already exist. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj) + throws NamingException { + bind(name, obj, false); + } + + + /** + * Binds a name to an object. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj) + throws NamingException { + bind(new CompositeName(name), obj); + } + + + /** + * Binds a name to an object, overwriting any existing binding. All + * intermediate contexts and the target context (that named by all but + * terminal atomic component of the name) must already exist. + *

        + * If the object is a DirContext, any existing attributes associated with + * the name are replaced with those of the object. Otherwise, any + * existing attributes associated with the name remain unchanged. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj) + throws NamingException { + bind(name, obj, true); + } + + + /** + * Binds a name to an object, overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj) + throws NamingException { + rebind(new CompositeName(name), obj); + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(Name name) + throws NamingException { + checkWritable(); + + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) + throw new NamingException + (sm.getString("namingContext.invalidName")); + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + + if (name.size() > 1) { + if (entry.type == NamingEntry.CONTEXT) { + ((Context) entry.value).unbind(name.getSuffix(1)); + } else { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + } else { + bindings.remove(name.get(0)); + } + + } + + + /** + * Unbinds the named object. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(String name) + throws NamingException { + unbind(new CompositeName(name)); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(Name oldName, Name newName) + throws NamingException { + Object value = lookup(oldName); + bind(newName, value); + unbind(oldName); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(String oldName, String newName) + throws NamingException { + rename(new CompositeName(oldName), new CompositeName(newName)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(Name name) + throws NamingException { + // Removing empty parts + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) { + return new NamingContextEnumeration(bindings.values().iterator()); + } + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + + if (entry.type != NamingEntry.CONTEXT) { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + return ((Context) entry.value).list(name.getSuffix(1)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(String name) + throws NamingException { + return list(new CompositeName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(Name name) + throws NamingException { + // Removing empty parts + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) { + return new NamingContextBindingsEnumeration(bindings.values().iterator(), this); + } + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + + if (entry.type != NamingEntry.CONTEXT) { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + return ((Context) entry.value).listBindings(name.getSuffix(1)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(String name) + throws NamingException { + return listBindings(new CompositeName(name)); + } + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(Name name) + throws NamingException { + + checkWritable(); + + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) + throw new NamingException + (sm.getString("namingContext.invalidName")); + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + + if (name.size() > 1) { + if (entry.type == NamingEntry.CONTEXT) { + ((Context) entry.value).unbind(name.getSuffix(1)); + } else { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + } else { + if (entry.type == NamingEntry.CONTEXT) { + ((Context) entry.value).close(); + bindings.remove(name.get(0)); + } else { + throw new NotContextException + (sm.getString("namingContext.contextExpected")); + } + } + + } + + + /** + * Destroys the named context and removes it from the namespace. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(String name) + throws NamingException { + destroySubcontext(new CompositeName(name)); + } + + + /** + * Creates and binds a new context. Creates a new context with the given + * name and binds it in the target context (that named by all but + * terminal atomic component of the name). All intermediate contexts and + * the target context must already exist. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(Name name) + throws NamingException { + checkWritable(); + + Context newContext = new NamingContext(env, this.name); + bind(name, newContext); + + return newContext; + } + + + /** + * Creates and binds a new context. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(String name) + throws NamingException { + return createSubcontext(new CompositeName(name)); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(Name name) + throws NamingException { + return lookup(name, false); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(String name) + throws NamingException { + return lookup(new CompositeName(name), false); + } + + + /** + * Retrieves the parser associated with the named context. In a + * federation of namespaces, different naming systems will parse names + * differently. This method allows an application to get a parser for + * parsing names into their atomic components using the naming convention + * of a particular naming system. Within any single naming system, + * NameParser objects returned by this method must be equal (using the + * equals() test). + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(Name name) + throws NamingException { + + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) + return nameParser; + + if (name.size() > 1) { + Object obj = bindings.get(name.get(0)); + if (obj instanceof Context) { + return ((Context) obj).getNameParser(name.getSuffix(1)); + } else { + throw new NotContextException + (sm.getString("namingContext.contextExpected")); + } + } + + return nameParser; + + } + + + /** + * Retrieves the parser associated with the named context. + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(String name) + throws NamingException { + return getNameParser(new CompositeName(name)); + } + + + /** + * Composes the name of this context with a name relative to this context. + *

        + * Given a name (name) relative to this context, and the name (prefix) + * of this context relative to one of its ancestors, this method returns + * the composition of the two names using the syntax appropriate for the + * naming system(s) involved. That is, if name names an object relative + * to this context, the result is the name of the same object, but + * relative to the ancestor context. None of the names may be null. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public Name composeName(Name name, Name prefix) + throws NamingException { + prefix = (Name) prefix.clone(); + return prefix.addAll(name); + } + + + /** + * Composes the name of this context with a name relative to this context. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public String composeName(String name, String prefix) + throws NamingException { + return prefix + "/" + name; + } + + + /** + * Adds a new environment property to the environment of this context. If + * the property already exists, its value is overwritten. + * + * @param propName the name of the environment property to add; may not + * be null + * @param propVal the value of the property to add; may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + return env.put(propName, propVal); + } + + + /** + * Removes an environment property from the environment of this context. + * + * @param propName the name of the environment property to remove; + * may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object removeFromEnvironment(String propName) + throws NamingException { + return env.remove(propName); + } + + + /** + * Retrieves the environment in effect for this context. See class + * description for more details on environment properties. + * The caller should not make any changes to the object returned: their + * effect on the context is undefined. The environment of this context + * may be changed using addToEnvironment() and removeFromEnvironment(). + * + * @return the environment of this context; never null + * @exception NamingException if a naming exception is encountered + */ + public Hashtable getEnvironment() + throws NamingException { + return env; + } + + + /** + * Closes this context. This method releases this context's resources + * immediately, instead of waiting for them to be released automatically + * by the garbage collector. + * This method is idempotent: invoking it on a context that has already + * been closed has no effect. Invoking any other method on a closed + * context is not allowed, and results in undefined behaviour. + * + * @exception NamingException if a naming exception is encountered + */ + public void close() + throws NamingException { + env.clear(); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public String getNameInNamespace() + throws NamingException { + throw new OperationNotSupportedException + (sm.getString("namingContext.noAbsoluteName")); + //FIXME ? + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @param resolveLinks If true, the links will be resolved + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + protected Object lookup(Name name, boolean resolveLinks) + throws NamingException { + + // Removing empty parts + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) { + // If name is empty, a newly allocated naming context is returned + return new NamingContext(env, this.name, bindings); + } + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + + if (name.size() > 1) { + // If the size of the name is greater that 1, then we go through a + // number of subcontexts. + if (entry.type != NamingEntry.CONTEXT) { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + return ((Context) entry.value).lookup(name.getSuffix(1)); + } else { + if ((resolveLinks) && (entry.type == NamingEntry.LINK_REF)) { + String link = ((LinkRef) entry.value).getLinkName(); + if (link.startsWith(".")) { + // Link relative to this context + return lookup(link.substring(1)); + } else { + return (new InitialContext(env)).lookup(link); + } + } else if (entry.type == NamingEntry.REFERENCE) { + try { + Object obj = NamingManager.getObjectInstance + (entry.value, name, this, env); + if (obj != null) { + entry.value = obj; + entry.type = NamingEntry.ENTRY; + } + return obj; + } catch (NamingException e) { + throw e; + } catch (Exception e) { + log.warn(sm.getString + ("namingContext.failResolvingReference"), e); + throw new NamingException(e.getMessage()); + } + } else { + return entry.value; + } + } + + } + + + /** + * Binds a name to an object. All intermediate contexts and the target + * context (that named by all but terminal atomic component of the name) + * must already exist. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param rebind if true, then perform a rebind (ie, overwrite) + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + protected void bind(Name name, Object obj, boolean rebind) + throws NamingException { + + checkWritable(); + + while ((!name.isEmpty()) && (name.get(0).length() == 0)) + name = name.getSuffix(1); + if (name.isEmpty()) + throw new NamingException + (sm.getString("namingContext.invalidName")); + + NamingEntry entry = (NamingEntry) bindings.get(name.get(0)); + + if (name.size() > 1) { + if (entry == null) { + throw new NameNotFoundException + (sm.getString("namingContext.nameNotBound", name.get(0))); + } + if (entry.type == NamingEntry.CONTEXT) { + if (rebind) { + ((Context) entry.value).rebind(name.getSuffix(1), obj); + } else { + ((Context) entry.value).bind(name.getSuffix(1), obj); + } + } else { + throw new NamingException + (sm.getString("namingContext.contextExpected")); + } + } else { + if ((!rebind) && (entry != null)) { + throw new NameAlreadyBoundException + (sm.getString("namingContext.alreadyBound", name.get(0))); + } else { + // Getting the type of the object and wrapping it within a new + // NamingEntry + Object toBind = + NamingManager.getStateToBind(obj, name, this, env); + if (toBind instanceof Context) { + entry = new NamingEntry(name.get(0), toBind, + NamingEntry.CONTEXT); + } else if (toBind instanceof LinkRef) { + entry = new NamingEntry(name.get(0), toBind, + NamingEntry.LINK_REF); + } else if (toBind instanceof Reference) { + entry = new NamingEntry(name.get(0), toBind, + NamingEntry.REFERENCE); + } else if (toBind instanceof Referenceable) { + toBind = ((Referenceable) toBind).getReference(); + entry = new NamingEntry(name.get(0), toBind, + NamingEntry.REFERENCE); + } else { + entry = new NamingEntry(name.get(0), toBind, + NamingEntry.ENTRY); + } + bindings.put(name.get(0), entry); + } + } + + } + + + /** + * Returns true if writing is allowed on this context. + */ + protected boolean isWritable() { + return ContextAccessController.isWritable(name); + } + + + /** + * Throws a naming exception is Context is not writable. + */ + protected void checkWritable() + throws NamingException { + if (!isWritable()) + throw new NamingException(sm.getString("namingContext.readOnly")); + } + + +} + diff --git a/java/org/apache/naming/NamingContextBindingsEnumeration.java b/java/org/apache/naming/NamingContextBindingsEnumeration.java index e33a80040..459930bb6 100644 --- a/java/org/apache/naming/NamingContextBindingsEnumeration.java +++ b/java/org/apache/naming/NamingContextBindingsEnumeration.java @@ -1,128 +1,128 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Iterator; - -import javax.naming.Binding; -import javax.naming.CompositeName; -import javax.naming.Context; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; - -/** - * Naming enumeration implementation. - * - * @author Remy Maucherat - * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ - */ - -public class NamingContextBindingsEnumeration - implements NamingEnumeration { - - - // ----------------------------------------------------------- Constructors - - - public NamingContextBindingsEnumeration(Iterator entries, Context ctx) { - iterator = entries; - this.ctx = ctx; - } - - // -------------------------------------------------------------- Variables - - - /** - * Underlying enumeration. - */ - protected Iterator iterator; - - - /** - * The context for which this enumeration is being generated. - */ - private Context ctx; - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieves the next element in the enumeration. - */ - public Object next() - throws NamingException { - return nextElementInternal(); - } - - - /** - * Determines whether there are any more elements in the enumeration. - */ - public boolean hasMore() - throws NamingException { - return iterator.hasNext(); - } - - - /** - * Closes this enumeration. - */ - public void close() - throws NamingException { - } - - - public boolean hasMoreElements() { - return iterator.hasNext(); - } - - - public Object nextElement() { - try { - return nextElementInternal(); - } catch (NamingException e) { - throw new RuntimeException(e.getMessage(), e); - } - } - - private Object nextElementInternal() throws NamingException { - NamingEntry entry = (NamingEntry) iterator.next(); - - // If the entry is a reference, resolve it - if (entry.type == NamingEntry.REFERENCE - || entry.type == NamingEntry.LINK_REF) { - try { - // A lookup will resolve the entry - ctx.lookup(new CompositeName(entry.name)); - } catch (NamingException e) { - throw e; - } catch (Exception e) { - NamingException ne = new NamingException(e.getMessage()); - ne.initCause(e); - throw ne; - } - } - - return new Binding(entry.name, entry.value.getClass().getName(), - entry.value, true); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Iterator; + +import javax.naming.Binding; +import javax.naming.CompositeName; +import javax.naming.Context; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Naming enumeration implementation. + * + * @author Remy Maucherat + * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ + */ + +public class NamingContextBindingsEnumeration + implements NamingEnumeration { + + + // ----------------------------------------------------------- Constructors + + + public NamingContextBindingsEnumeration(Iterator entries, Context ctx) { + iterator = entries; + this.ctx = ctx; + } + + // -------------------------------------------------------------- Variables + + + /** + * Underlying enumeration. + */ + protected Iterator iterator; + + + /** + * The context for which this enumeration is being generated. + */ + private Context ctx; + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieves the next element in the enumeration. + */ + public Object next() + throws NamingException { + return nextElementInternal(); + } + + + /** + * Determines whether there are any more elements in the enumeration. + */ + public boolean hasMore() + throws NamingException { + return iterator.hasNext(); + } + + + /** + * Closes this enumeration. + */ + public void close() + throws NamingException { + } + + + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + + public Object nextElement() { + try { + return nextElementInternal(); + } catch (NamingException e) { + throw new RuntimeException(e.getMessage(), e); + } + } + + private Object nextElementInternal() throws NamingException { + NamingEntry entry = (NamingEntry) iterator.next(); + + // If the entry is a reference, resolve it + if (entry.type == NamingEntry.REFERENCE + || entry.type == NamingEntry.LINK_REF) { + try { + // A lookup will resolve the entry + ctx.lookup(new CompositeName(entry.name)); + } catch (NamingException e) { + throw e; + } catch (Exception e) { + NamingException ne = new NamingException(e.getMessage()); + ne.initCause(e); + throw ne; + } + } + + return new Binding(entry.name, entry.value.getClass().getName(), + entry.value, true); + } + + +} + diff --git a/java/org/apache/naming/NamingContextEnumeration.java b/java/org/apache/naming/NamingContextEnumeration.java index 341983fdd..80f591bc2 100644 --- a/java/org/apache/naming/NamingContextEnumeration.java +++ b/java/org/apache/naming/NamingContextEnumeration.java @@ -1,95 +1,95 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Iterator; - -import javax.naming.NameClassPair; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; - -/** - * Naming enumeration implementation. - * - * @author Remy Maucherat - * @version $Revision: 303022 $ $Date: 2004-07-24 00:46:08 +0200 (sam., 24 juil. 2004) $ - */ - -public class NamingContextEnumeration - implements NamingEnumeration { - - - // ----------------------------------------------------------- Constructors - - - public NamingContextEnumeration(Iterator entries) { - iterator = entries; - } - - - // -------------------------------------------------------------- Variables - - - /** - * Underlying enumeration. - */ - protected Iterator iterator; - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieves the next element in the enumeration. - */ - public Object next() - throws NamingException { - return nextElement(); - } - - - /** - * Determines whether there are any more elements in the enumeration. - */ - public boolean hasMore() - throws NamingException { - return iterator.hasNext(); - } - - - /** - * Closes this enumeration. - */ - public void close() - throws NamingException { - } - - - public boolean hasMoreElements() { - return iterator.hasNext(); - } - - - public Object nextElement() { - NamingEntry entry = (NamingEntry) iterator.next(); - return new NameClassPair(entry.name, entry.value.getClass().getName()); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Iterator; + +import javax.naming.NameClassPair; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Naming enumeration implementation. + * + * @author Remy Maucherat + * @version $Revision: 303022 $ $Date: 2004-07-24 00:46:08 +0200 (sam., 24 juil. 2004) $ + */ + +public class NamingContextEnumeration + implements NamingEnumeration { + + + // ----------------------------------------------------------- Constructors + + + public NamingContextEnumeration(Iterator entries) { + iterator = entries; + } + + + // -------------------------------------------------------------- Variables + + + /** + * Underlying enumeration. + */ + protected Iterator iterator; + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieves the next element in the enumeration. + */ + public Object next() + throws NamingException { + return nextElement(); + } + + + /** + * Determines whether there are any more elements in the enumeration. + */ + public boolean hasMore() + throws NamingException { + return iterator.hasNext(); + } + + + /** + * Closes this enumeration. + */ + public void close() + throws NamingException { + } + + + public boolean hasMoreElements() { + return iterator.hasNext(); + } + + + public Object nextElement() { + NamingEntry entry = (NamingEntry) iterator.next(); + return new NameClassPair(entry.name, entry.value.getClass().getName()); + } + + +} + diff --git a/java/org/apache/naming/NamingEntry.java b/java/org/apache/naming/NamingEntry.java index a20e8d801..1aecca768 100644 --- a/java/org/apache/naming/NamingEntry.java +++ b/java/org/apache/naming/NamingEntry.java @@ -1,80 +1,80 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - - -/** - * Represents a binding in a NamingContext. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class NamingEntry { - - - // -------------------------------------------------------------- Constants - - - public static final int ENTRY = 0; - public static final int LINK_REF = 1; - public static final int REFERENCE = 2; - - public static final int CONTEXT = 10; - - - // ----------------------------------------------------------- Constructors - - - public NamingEntry(String name, Object value, int type) { - this.name = name; - this.value = value; - this.type = type; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The type instance variable is used to avoid unsing RTTI when doing - * lookups. - */ - public int type; - public String name; - public Object value; - - - // --------------------------------------------------------- Object Methods - - - public boolean equals(Object obj) { - if ((obj != null) && (obj instanceof NamingEntry)) { - return name.equals(((NamingEntry) obj).name); - } else { - return false; - } - } - - - public int hashCode() { - return name.hashCode(); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + + +/** + * Represents a binding in a NamingContext. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class NamingEntry { + + + // -------------------------------------------------------------- Constants + + + public static final int ENTRY = 0; + public static final int LINK_REF = 1; + public static final int REFERENCE = 2; + + public static final int CONTEXT = 10; + + + // ----------------------------------------------------------- Constructors + + + public NamingEntry(String name, Object value, int type) { + this.name = name; + this.value = value; + this.type = type; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The type instance variable is used to avoid unsing RTTI when doing + * lookups. + */ + public int type; + public String name; + public Object value; + + + // --------------------------------------------------------- Object Methods + + + public boolean equals(Object obj) { + if ((obj != null) && (obj instanceof NamingEntry)) { + return name.equals(((NamingEntry) obj).name); + } else { + return false; + } + } + + + public int hashCode() { + return name.hashCode(); + } + + +} diff --git a/java/org/apache/naming/NamingService.java b/java/org/apache/naming/NamingService.java index 16b84bc86..a880d6fa8 100644 --- a/java/org/apache/naming/NamingService.java +++ b/java/org/apache/naming/NamingService.java @@ -1,229 +1,229 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming; - -import javax.naming.Context; -import javax.management.NotificationBroadcasterSupport; -import javax.management.ObjectName; -import javax.management.MBeanServer; -import javax.management.MBeanRegistration; -import javax.management.AttributeChangeNotification; -import javax.management.Notification; - -/** - * Implementation of the NamingService JMX MBean. - * - * @author Remy Maucherat - * @version $Revision: 303104 $ - */ - -public final class NamingService - extends NotificationBroadcasterSupport - implements NamingServiceMBean, MBeanRegistration { - - - // ----------------------------------------------------- Instance Variables - - - /** - * Status of the Slide domain. - */ - private int state = STOPPED; - - - /** - * Notification sequence number. - */ - private long sequenceNumber = 0; - - - /** - * Old URL packages value. - */ - private String oldUrlValue = ""; - - - /** - * Old initial context value. - */ - private String oldIcValue = ""; - - - // ---------------------------------------------- MBeanRegistration Methods - - - public ObjectName preRegister(MBeanServer server, ObjectName name) - throws Exception { - return new ObjectName(OBJECT_NAME); - } - - - public void postRegister(Boolean registrationDone) { - if (!registrationDone.booleanValue()) - destroy(); - } - - - public void preDeregister() - throws Exception { - } - - - public void postDeregister() { - destroy(); - } - - - // ----------------------------------------------------- SlideMBean Methods - - - /** - * Retruns the Catalina component name. - */ - public String getName() { - return NAME; - } - - - /** - * Returns the state. - */ - public int getState() { - return state; - } - - - /** - * Returns a String representation of the state. - */ - public String getStateString() { - return states[state]; - } - - - /** - * Start the servlet container. - */ - public void start() - throws Exception { - - Notification notification = null; - - if (state != STOPPED) - return; - - state = STARTING; - - // Notifying the MBEan server that we're starting - - notification = new AttributeChangeNotification - (this, sequenceNumber++, System.currentTimeMillis(), - "Starting " + NAME, "State", "java.lang.Integer", - new Integer(STOPPED), new Integer(STARTING)); - sendNotification(notification); - - try { - - String value = "org.apache.naming"; - String oldValue = System.getProperty(Context.URL_PKG_PREFIXES); - if (oldValue != null) { - oldUrlValue = oldValue; - value = oldValue + ":" + value; - } - System.setProperty(Context.URL_PKG_PREFIXES, value); - - oldValue = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); - if ((oldValue != null) && (oldValue.length() > 0)) { - oldIcValue = oldValue; - } else { - System.setProperty(Context.INITIAL_CONTEXT_FACTORY, - Constants.Package - + ".java.javaURLContextFactory"); - } - - } catch (Throwable t) { - state = STOPPED; - notification = new AttributeChangeNotification - (this, sequenceNumber++, System.currentTimeMillis(), - "Stopped " + NAME, "State", "java.lang.Integer", - new Integer(STARTING), new Integer(STOPPED)); - sendNotification(notification); - } - - state = STARTED; - notification = new AttributeChangeNotification - (this, sequenceNumber++, System.currentTimeMillis(), - "Started " + NAME, "State", "java.lang.Integer", - new Integer(STARTING), new Integer(STARTED)); - sendNotification(notification); - - } - - - /** - * Stop the servlet container. - */ - public void stop() { - - Notification notification = null; - - if (state != STARTED) - return; - - state = STOPPING; - - notification = new AttributeChangeNotification - (this, sequenceNumber++, System.currentTimeMillis(), - "Stopping " + NAME, "State", "java.lang.Integer", - new Integer(STARTED), new Integer(STOPPING)); - sendNotification(notification); - - try { - - System.setProperty(Context.URL_PKG_PREFIXES, oldUrlValue); - System.setProperty(Context.INITIAL_CONTEXT_FACTORY, oldIcValue); - - } catch (Throwable t) { - - // FIXME - t.printStackTrace(); - - } - - state = STOPPED; - - notification = new AttributeChangeNotification - (this, sequenceNumber++, System.currentTimeMillis(), - "Stopped " + NAME, "State", "java.lang.Integer", - new Integer(STOPPING), new Integer(STOPPED)); - sendNotification(notification); - - } - - - /** - * Destroy servlet container (if any is running). - */ - public void destroy() { - - if (getState() != STOPPED) - stop(); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming; + +import javax.naming.Context; +import javax.management.NotificationBroadcasterSupport; +import javax.management.ObjectName; +import javax.management.MBeanServer; +import javax.management.MBeanRegistration; +import javax.management.AttributeChangeNotification; +import javax.management.Notification; + +/** + * Implementation of the NamingService JMX MBean. + * + * @author Remy Maucherat + * @version $Revision: 303104 $ + */ + +public final class NamingService + extends NotificationBroadcasterSupport + implements NamingServiceMBean, MBeanRegistration { + + + // ----------------------------------------------------- Instance Variables + + + /** + * Status of the Slide domain. + */ + private int state = STOPPED; + + + /** + * Notification sequence number. + */ + private long sequenceNumber = 0; + + + /** + * Old URL packages value. + */ + private String oldUrlValue = ""; + + + /** + * Old initial context value. + */ + private String oldIcValue = ""; + + + // ---------------------------------------------- MBeanRegistration Methods + + + public ObjectName preRegister(MBeanServer server, ObjectName name) + throws Exception { + return new ObjectName(OBJECT_NAME); + } + + + public void postRegister(Boolean registrationDone) { + if (!registrationDone.booleanValue()) + destroy(); + } + + + public void preDeregister() + throws Exception { + } + + + public void postDeregister() { + destroy(); + } + + + // ----------------------------------------------------- SlideMBean Methods + + + /** + * Retruns the Catalina component name. + */ + public String getName() { + return NAME; + } + + + /** + * Returns the state. + */ + public int getState() { + return state; + } + + + /** + * Returns a String representation of the state. + */ + public String getStateString() { + return states[state]; + } + + + /** + * Start the servlet container. + */ + public void start() + throws Exception { + + Notification notification = null; + + if (state != STOPPED) + return; + + state = STARTING; + + // Notifying the MBEan server that we're starting + + notification = new AttributeChangeNotification + (this, sequenceNumber++, System.currentTimeMillis(), + "Starting " + NAME, "State", "java.lang.Integer", + new Integer(STOPPED), new Integer(STARTING)); + sendNotification(notification); + + try { + + String value = "org.apache.naming"; + String oldValue = System.getProperty(Context.URL_PKG_PREFIXES); + if (oldValue != null) { + oldUrlValue = oldValue; + value = oldValue + ":" + value; + } + System.setProperty(Context.URL_PKG_PREFIXES, value); + + oldValue = System.getProperty(Context.INITIAL_CONTEXT_FACTORY); + if ((oldValue != null) && (oldValue.length() > 0)) { + oldIcValue = oldValue; + } else { + System.setProperty(Context.INITIAL_CONTEXT_FACTORY, + Constants.Package + + ".java.javaURLContextFactory"); + } + + } catch (Throwable t) { + state = STOPPED; + notification = new AttributeChangeNotification + (this, sequenceNumber++, System.currentTimeMillis(), + "Stopped " + NAME, "State", "java.lang.Integer", + new Integer(STARTING), new Integer(STOPPED)); + sendNotification(notification); + } + + state = STARTED; + notification = new AttributeChangeNotification + (this, sequenceNumber++, System.currentTimeMillis(), + "Started " + NAME, "State", "java.lang.Integer", + new Integer(STARTING), new Integer(STARTED)); + sendNotification(notification); + + } + + + /** + * Stop the servlet container. + */ + public void stop() { + + Notification notification = null; + + if (state != STARTED) + return; + + state = STOPPING; + + notification = new AttributeChangeNotification + (this, sequenceNumber++, System.currentTimeMillis(), + "Stopping " + NAME, "State", "java.lang.Integer", + new Integer(STARTED), new Integer(STOPPING)); + sendNotification(notification); + + try { + + System.setProperty(Context.URL_PKG_PREFIXES, oldUrlValue); + System.setProperty(Context.INITIAL_CONTEXT_FACTORY, oldIcValue); + + } catch (Throwable t) { + + // FIXME + t.printStackTrace(); + + } + + state = STOPPED; + + notification = new AttributeChangeNotification + (this, sequenceNumber++, System.currentTimeMillis(), + "Stopped " + NAME, "State", "java.lang.Integer", + new Integer(STOPPING), new Integer(STOPPED)); + sendNotification(notification); + + } + + + /** + * Destroy servlet container (if any is running). + */ + public void destroy() { + + if (getState() != STOPPED) + stop(); + + } + + +} diff --git a/java/org/apache/naming/NamingServiceMBean.java b/java/org/apache/naming/NamingServiceMBean.java index bb5f4b9ea..68e1eb94a 100644 --- a/java/org/apache/naming/NamingServiceMBean.java +++ b/java/org/apache/naming/NamingServiceMBean.java @@ -1,97 +1,97 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming; - -/** - * Naming MBean interface. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ - -public interface NamingServiceMBean { - - - // -------------------------------------------------------------- Constants - - - /** - * Status constants. - */ - public static final String[] states = - {"Stopped", "Stopping", "Starting", "Started"}; - - - public static final int STOPPED = 0; - public static final int STOPPING = 1; - public static final int STARTING = 2; - public static final int STARTED = 3; - - - /** - * Component name. - */ - public static final String NAME = "Apache JNDI Naming Service"; - - - /** - * Object name. - */ - public static final String OBJECT_NAME = ":service=Naming"; - - - // ------------------------------------------------------ Interface Methods - - - /** - * Retruns the JNDI component name. - */ - public String getName(); - - - /** - * Returns the state. - */ - public int getState(); - - - /** - * Returns a String representation of the state. - */ - public String getStateString(); - - - /** - * Start the servlet container. - */ - public void start() - throws Exception; - - - /** - * Stop the servlet container. - */ - public void stop(); - - - /** - * Destroy servlet container (if any is running). - */ - public void destroy(); - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming; + +/** + * Naming MBean interface. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ + +public interface NamingServiceMBean { + + + // -------------------------------------------------------------- Constants + + + /** + * Status constants. + */ + public static final String[] states = + {"Stopped", "Stopping", "Starting", "Started"}; + + + public static final int STOPPED = 0; + public static final int STOPPING = 1; + public static final int STARTING = 2; + public static final int STARTED = 3; + + + /** + * Component name. + */ + public static final String NAME = "Apache JNDI Naming Service"; + + + /** + * Object name. + */ + public static final String OBJECT_NAME = ":service=Naming"; + + + // ------------------------------------------------------ Interface Methods + + + /** + * Retruns the JNDI component name. + */ + public String getName(); + + + /** + * Returns the state. + */ + public int getState(); + + + /** + * Returns a String representation of the state. + */ + public String getStateString(); + + + /** + * Start the servlet container. + */ + public void start() + throws Exception; + + + /** + * Stop the servlet container. + */ + public void stop(); + + + /** + * Destroy servlet container (if any is running). + */ + public void destroy(); + + +} diff --git a/java/org/apache/naming/ResourceEnvRef.java b/java/org/apache/naming/ResourceEnvRef.java index 1d1a09375..541c8fb90 100644 --- a/java/org/apache/naming/ResourceEnvRef.java +++ b/java/org/apache/naming/ResourceEnvRef.java @@ -1,98 +1,98 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import javax.naming.Context; -import javax.naming.Reference; - -/** - * Represents a reference address to a resource environment. - * - * @author Remy Maucherat - * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ - */ - -public class ResourceEnvRef - extends Reference { - - - // -------------------------------------------------------------- Constants - - - /** - * Default factory for this reference. - */ - public static final String DEFAULT_FACTORY = - org.apache.naming.factory.Constants.DEFAULT_RESOURCE_ENV_FACTORY; - - - // ----------------------------------------------------------- Constructors - - - /** - * Resource env reference. - * - * @param resourceType Type - */ - public ResourceEnvRef(String resourceType) { - super(resourceType); - } - - - /** - * Resource env reference. - * - * @param resourceType Type - * @param factory The factory class - * @param factoryLocation The factory location - */ - public ResourceEnvRef(String resourceType, String factory, - String factoryLocation) { - super(resourceType, factory, factoryLocation); - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------ Reference Methods - - - /** - * Retrieves the class name of the factory of the object to which this - * reference refers. - */ - public String getFactoryClassName() { - String factory = super.getFactoryClassName(); - if (factory != null) { - return factory; - } else { - factory = System.getProperty(Context.OBJECT_FACTORIES); - if (factory != null) { - return null; - } else { - return DEFAULT_FACTORY; - } - } - } - - - // ------------------------------------------------------------- Properties - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import javax.naming.Context; +import javax.naming.Reference; + +/** + * Represents a reference address to a resource environment. + * + * @author Remy Maucherat + * @version $Revision: 303133 $ $Date: 2004-08-29 18:46:15 +0200 (dim., 29 août 2004) $ + */ + +public class ResourceEnvRef + extends Reference { + + + // -------------------------------------------------------------- Constants + + + /** + * Default factory for this reference. + */ + public static final String DEFAULT_FACTORY = + org.apache.naming.factory.Constants.DEFAULT_RESOURCE_ENV_FACTORY; + + + // ----------------------------------------------------------- Constructors + + + /** + * Resource env reference. + * + * @param resourceType Type + */ + public ResourceEnvRef(String resourceType) { + super(resourceType); + } + + + /** + * Resource env reference. + * + * @param resourceType Type + * @param factory The factory class + * @param factoryLocation The factory location + */ + public ResourceEnvRef(String resourceType, String factory, + String factoryLocation) { + super(resourceType, factory, factoryLocation); + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------ Reference Methods + + + /** + * Retrieves the class name of the factory of the object to which this + * reference refers. + */ + public String getFactoryClassName() { + String factory = super.getFactoryClassName(); + if (factory != null) { + return factory; + } else { + factory = System.getProperty(Context.OBJECT_FACTORIES); + if (factory != null) { + return null; + } else { + return DEFAULT_FACTORY; + } + } + } + + + // ------------------------------------------------------------- Properties + + +} diff --git a/java/org/apache/naming/ResourceLinkRef.java b/java/org/apache/naming/ResourceLinkRef.java index 33923400f..1d3eaab9a 100644 --- a/java/org/apache/naming/ResourceLinkRef.java +++ b/java/org/apache/naming/ResourceLinkRef.java @@ -1,110 +1,110 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import javax.naming.Context; -import javax.naming.Reference; -import javax.naming.StringRefAddr; - -/** - * Represents a reference address to a resource. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ResourceLinkRef - extends Reference { - - - // -------------------------------------------------------------- Constants - - - /** - * Default factory for this reference. - */ - public static final String DEFAULT_FACTORY = - org.apache.naming.factory.Constants.DEFAULT_RESOURCE_LINK_FACTORY; - - - /** - * Description address type. - */ - public static final String GLOBALNAME = "globalName"; - - - // ----------------------------------------------------------- Constructors - - - /** - * ResourceLink Reference. - * - * @param resourceClass Resource class - * @param globalName Global name - */ - public ResourceLinkRef(String resourceClass, String globalName) { - this(resourceClass, globalName, null, null); - } - - - /** - * ResourceLink Reference. - * - * @param resourceClass Resource class - * @param globalName Global name - */ - public ResourceLinkRef(String resourceClass, String globalName, - String factory, String factoryLocation) { - super(resourceClass, factory, factoryLocation); - StringRefAddr refAddr = null; - if (globalName != null) { - refAddr = new StringRefAddr(GLOBALNAME, globalName); - add(refAddr); - } - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------ Reference Methods - - - /** - * Retrieves the class name of the factory of the object to which this - * reference refers. - */ - public String getFactoryClassName() { - String factory = super.getFactoryClassName(); - if (factory != null) { - return factory; - } else { - factory = System.getProperty(Context.OBJECT_FACTORIES); - if (factory != null) { - return null; - } else { - return DEFAULT_FACTORY; - } - } - } - - - // ------------------------------------------------------------- Properties - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import javax.naming.Context; +import javax.naming.Reference; +import javax.naming.StringRefAddr; + +/** + * Represents a reference address to a resource. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ResourceLinkRef + extends Reference { + + + // -------------------------------------------------------------- Constants + + + /** + * Default factory for this reference. + */ + public static final String DEFAULT_FACTORY = + org.apache.naming.factory.Constants.DEFAULT_RESOURCE_LINK_FACTORY; + + + /** + * Description address type. + */ + public static final String GLOBALNAME = "globalName"; + + + // ----------------------------------------------------------- Constructors + + + /** + * ResourceLink Reference. + * + * @param resourceClass Resource class + * @param globalName Global name + */ + public ResourceLinkRef(String resourceClass, String globalName) { + this(resourceClass, globalName, null, null); + } + + + /** + * ResourceLink Reference. + * + * @param resourceClass Resource class + * @param globalName Global name + */ + public ResourceLinkRef(String resourceClass, String globalName, + String factory, String factoryLocation) { + super(resourceClass, factory, factoryLocation); + StringRefAddr refAddr = null; + if (globalName != null) { + refAddr = new StringRefAddr(GLOBALNAME, globalName); + add(refAddr); + } + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------ Reference Methods + + + /** + * Retrieves the class name of the factory of the object to which this + * reference refers. + */ + public String getFactoryClassName() { + String factory = super.getFactoryClassName(); + if (factory != null) { + return factory; + } else { + factory = System.getProperty(Context.OBJECT_FACTORIES); + if (factory != null) { + return null; + } else { + return DEFAULT_FACTORY; + } + } + } + + + // ------------------------------------------------------------- Properties + + +} diff --git a/java/org/apache/naming/ResourceRef.java b/java/org/apache/naming/ResourceRef.java index d7f7d44d4..cbf7c08dd 100644 --- a/java/org/apache/naming/ResourceRef.java +++ b/java/org/apache/naming/ResourceRef.java @@ -1,167 +1,167 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Enumeration; - -import javax.naming.Context; -import javax.naming.RefAddr; -import javax.naming.Reference; -import javax.naming.StringRefAddr; - -/** - * Represents a reference address to a resource. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ResourceRef - extends Reference { - - - // -------------------------------------------------------------- Constants - - - /** - * Default factory for this reference. - */ - public static final String DEFAULT_FACTORY = - org.apache.naming.factory.Constants.DEFAULT_RESOURCE_FACTORY; - - - /** - * Description address type. - */ - public static final String DESCRIPTION = "description"; - - - /** - * Scope address type. - */ - public static final String SCOPE = "scope"; - - - /** - * Auth address type. - */ - public static final String AUTH = "auth"; - - - // ----------------------------------------------------------- Constructors - - - /** - * Resource Reference. - * - * @param resourceClass Resource class - * @param scope Resource scope - * @param auth Resource authetication - */ - public ResourceRef(String resourceClass, String description, - String scope, String auth) { - this(resourceClass, description, scope, auth, null, null); - } - - - /** - * Resource Reference. - * - * @param resourceClass Resource class - * @param scope Resource scope - * @param auth Resource authetication - */ - public ResourceRef(String resourceClass, String description, - String scope, String auth, String factory, - String factoryLocation) { - super(resourceClass, factory, factoryLocation); - StringRefAddr refAddr = null; - if (description != null) { - refAddr = new StringRefAddr(DESCRIPTION, description); - add(refAddr); - } - if (scope != null) { - refAddr = new StringRefAddr(SCOPE, scope); - add(refAddr); - } - if (auth != null) { - refAddr = new StringRefAddr(AUTH, auth); - add(refAddr); - } - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------ Reference Methods - - - /** - * Retrieves the class name of the factory of the object to which this - * reference refers. - */ - public String getFactoryClassName() { - String factory = super.getFactoryClassName(); - if (factory != null) { - return factory; - } else { - factory = System.getProperty(Context.OBJECT_FACTORIES); - if (factory != null) { - return null; - } else { - return DEFAULT_FACTORY; - } - } - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Return a String rendering of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ResourceRef["); - sb.append("className="); - sb.append(getClassName()); - sb.append(",factoryClassLocation="); - sb.append(getFactoryClassLocation()); - sb.append(",factoryClassName="); - sb.append(getFactoryClassName()); - Enumeration refAddrs = getAll(); - while (refAddrs.hasMoreElements()) { - RefAddr refAddr = (RefAddr) refAddrs.nextElement(); - sb.append(",{type="); - sb.append(refAddr.getType()); - sb.append(",content="); - sb.append(refAddr.getContent()); - sb.append("}"); - } - sb.append("]"); - return (sb.toString()); - - } - - - // ------------------------------------------------------------- Properties - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Enumeration; + +import javax.naming.Context; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.StringRefAddr; + +/** + * Represents a reference address to a resource. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ResourceRef + extends Reference { + + + // -------------------------------------------------------------- Constants + + + /** + * Default factory for this reference. + */ + public static final String DEFAULT_FACTORY = + org.apache.naming.factory.Constants.DEFAULT_RESOURCE_FACTORY; + + + /** + * Description address type. + */ + public static final String DESCRIPTION = "description"; + + + /** + * Scope address type. + */ + public static final String SCOPE = "scope"; + + + /** + * Auth address type. + */ + public static final String AUTH = "auth"; + + + // ----------------------------------------------------------- Constructors + + + /** + * Resource Reference. + * + * @param resourceClass Resource class + * @param scope Resource scope + * @param auth Resource authetication + */ + public ResourceRef(String resourceClass, String description, + String scope, String auth) { + this(resourceClass, description, scope, auth, null, null); + } + + + /** + * Resource Reference. + * + * @param resourceClass Resource class + * @param scope Resource scope + * @param auth Resource authetication + */ + public ResourceRef(String resourceClass, String description, + String scope, String auth, String factory, + String factoryLocation) { + super(resourceClass, factory, factoryLocation); + StringRefAddr refAddr = null; + if (description != null) { + refAddr = new StringRefAddr(DESCRIPTION, description); + add(refAddr); + } + if (scope != null) { + refAddr = new StringRefAddr(SCOPE, scope); + add(refAddr); + } + if (auth != null) { + refAddr = new StringRefAddr(AUTH, auth); + add(refAddr); + } + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------ Reference Methods + + + /** + * Retrieves the class name of the factory of the object to which this + * reference refers. + */ + public String getFactoryClassName() { + String factory = super.getFactoryClassName(); + if (factory != null) { + return factory; + } else { + factory = System.getProperty(Context.OBJECT_FACTORIES); + if (factory != null) { + return null; + } else { + return DEFAULT_FACTORY; + } + } + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Return a String rendering of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ResourceRef["); + sb.append("className="); + sb.append(getClassName()); + sb.append(",factoryClassLocation="); + sb.append(getFactoryClassLocation()); + sb.append(",factoryClassName="); + sb.append(getFactoryClassName()); + Enumeration refAddrs = getAll(); + while (refAddrs.hasMoreElements()) { + RefAddr refAddr = (RefAddr) refAddrs.nextElement(); + sb.append(",{type="); + sb.append(refAddr.getType()); + sb.append(",content="); + sb.append(refAddr.getContent()); + sb.append("}"); + } + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------------------- Properties + + +} diff --git a/java/org/apache/naming/SelectorContext.java b/java/org/apache/naming/SelectorContext.java index 6307452c6..a417c875d 100644 --- a/java/org/apache/naming/SelectorContext.java +++ b/java/org/apache/naming/SelectorContext.java @@ -1,694 +1,694 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.util.Hashtable; -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.NameParser; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; - -/** - * Catalina JNDI Context implementation. - * - * @author Remy Maucherat - * @version $Revision: 303999 $ $Date: 2005-07-20 23:25:18 +0200 (mer., 20 juil. 2005) $ - */ - -public class SelectorContext implements Context { - - - // -------------------------------------------------------------- Constants - - - /** - * Namespace URL. - */ - public static final String prefix = "java:"; - - - /** - * Namespace URL length. - */ - public static final int prefixLength = prefix.length(); - - - /** - * Initial context prefix. - */ - public static final String IC_PREFIX = "IC_"; - - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a Catalina selector context using the given environment. - */ - public SelectorContext(Hashtable env) { - this.env = env; - } - - - /** - * Builds a Catalina selector context using the given environment. - */ - public SelectorContext(Hashtable env, boolean initialContext) { - this(env); - this.initialContext = initialContext; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Environment. - */ - protected Hashtable env; - - - /** - * The string manager for this package. - */ - protected StringManager sm = StringManager.getManager(Constants.Package); - - - /** - * Request for an initial context. - */ - protected boolean initialContext = false; - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. If name is empty, returns a new instance - * of this context (which represents the same naming context as this - * context, but its environment may be modified independently and it may - * be accessed concurrently). - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(Name name) - throws NamingException { - // Strip the URL header - // Find the appropriate NamingContext according to the current bindings - // Execute the lookup on that context - return getBoundContext().lookup(parseName(name)); - } - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(String name) - throws NamingException { - // Strip the URL header - // Find the appropriate NamingContext according to the current bindings - // Execute the lookup on that context - return getBoundContext().lookup(parseName(name)); - } - - - /** - * Binds a name to an object. All intermediate contexts and the target - * context (that named by all but terminal atomic component of the name) - * must already exist. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj) - throws NamingException { - getBoundContext().bind(parseName(name), obj); - } - - - /** - * Binds a name to an object. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj) - throws NamingException { - getBoundContext().bind(parseName(name), obj); - } - - - /** - * Binds a name to an object, overwriting any existing binding. All - * intermediate contexts and the target context (that named by all but - * terminal atomic component of the name) must already exist. - *

        - * If the object is a DirContext, any existing attributes associated with - * the name are replaced with those of the object. Otherwise, any - * existing attributes associated with the name remain unchanged. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj) - throws NamingException { - getBoundContext().rebind(parseName(name), obj); - } - - - /** - * Binds a name to an object, overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj) - throws NamingException { - getBoundContext().rebind(parseName(name), obj); - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(Name name) - throws NamingException { - getBoundContext().unbind(parseName(name)); - } - - - /** - * Unbinds the named object. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(String name) - throws NamingException { - getBoundContext().unbind(parseName(name)); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(Name oldName, Name newName) - throws NamingException { - getBoundContext().rename(parseName(oldName), parseName(newName)); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(String oldName, String newName) - throws NamingException { - getBoundContext().rename(parseName(oldName), parseName(newName)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(Name name) - throws NamingException { - return getBoundContext().list(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(String name) - throws NamingException { - return getBoundContext().list(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(Name name) - throws NamingException { - return getBoundContext().listBindings(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(String name) - throws NamingException { - return getBoundContext().listBindings(parseName(name)); - } - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(Name name) - throws NamingException { - getBoundContext().destroySubcontext(parseName(name)); - } - - - /** - * Destroys the named context and removes it from the namespace. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(String name) - throws NamingException { - getBoundContext().destroySubcontext(parseName(name)); - } - - - /** - * Creates and binds a new context. Creates a new context with the given - * name and binds it in the target context (that named by all but - * terminal atomic component of the name). All intermediate contexts and - * the target context must already exist. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(Name name) - throws NamingException { - return getBoundContext().createSubcontext(parseName(name)); - } - - - /** - * Creates and binds a new context. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(String name) - throws NamingException { - return getBoundContext().createSubcontext(parseName(name)); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(Name name) - throws NamingException { - return getBoundContext().lookupLink(parseName(name)); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(String name) - throws NamingException { - return getBoundContext().lookupLink(parseName(name)); - } - - - /** - * Retrieves the parser associated with the named context. In a - * federation of namespaces, different naming systems will parse names - * differently. This method allows an application to get a parser for - * parsing names into their atomic components using the naming convention - * of a particular naming system. Within any single naming system, - * NameParser objects returned by this method must be equal (using the - * equals() test). - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(Name name) - throws NamingException { - return getBoundContext().getNameParser(parseName(name)); - } - - - /** - * Retrieves the parser associated with the named context. - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(String name) - throws NamingException { - return getBoundContext().getNameParser(parseName(name)); - } - - - /** - * Composes the name of this context with a name relative to this context. - *

        - * Given a name (name) relative to this context, and the name (prefix) - * of this context relative to one of its ancestors, this method returns - * the composition of the two names using the syntax appropriate for the - * naming system(s) involved. That is, if name names an object relative - * to this context, the result is the name of the same object, but - * relative to the ancestor context. None of the names may be null. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public Name composeName(Name name, Name prefix) - throws NamingException { - prefix = (Name) prefix.clone(); - return prefix.addAll(name); - } - - - /** - * Composes the name of this context with a name relative to this context. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public String composeName(String name, String prefix) - throws NamingException { - return prefix + "/" + name; - } - - - /** - * Adds a new environment property to the environment of this context. If - * the property already exists, its value is overwritten. - * - * @param propName the name of the environment property to add; may not - * be null - * @param propVal the value of the property to add; may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object addToEnvironment(String propName, Object propVal) - throws NamingException { - return getBoundContext().addToEnvironment(propName, propVal); - } - - - /** - * Removes an environment property from the environment of this context. - * - * @param propName the name of the environment property to remove; - * may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object removeFromEnvironment(String propName) - throws NamingException { - return getBoundContext().removeFromEnvironment(propName); - } - - - /** - * Retrieves the environment in effect for this context. See class - * description for more details on environment properties. - * The caller should not make any changes to the object returned: their - * effect on the context is undefined. The environment of this context - * may be changed using addToEnvironment() and removeFromEnvironment(). - * - * @return the environment of this context; never null - * @exception NamingException if a naming exception is encountered - */ - public Hashtable getEnvironment() - throws NamingException { - return getBoundContext().getEnvironment(); - } - - - /** - * Closes this context. This method releases this context's resources - * immediately, instead of waiting for them to be released automatically - * by the garbage collector. - * This method is idempotent: invoking it on a context that has already - * been closed has no effect. Invoking any other method on a closed - * context is not allowed, and results in undefined behaviour. - * - * @exception NamingException if a naming exception is encountered - */ - public void close() - throws NamingException { - getBoundContext().close(); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public String getNameInNamespace() - throws NamingException { - return prefix; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Get the bound context. - */ - protected Context getBoundContext() - throws NamingException { - - if (initialContext) { - String ICName = IC_PREFIX; - if (ContextBindings.isThreadBound()) { - ICName += ContextBindings.getThreadName(); - } else if (ContextBindings.isClassLoaderBound()) { - ICName += ContextBindings.getClassLoaderName(); - } - Context initialContext = ContextBindings.getContext(ICName); - if (initialContext == null) { - // Allocating a new context and binding it to the appropriate - // name - initialContext = new NamingContext(env, ICName); - ContextBindings.bindContext(ICName, initialContext); - } - return initialContext; - } else { - if (ContextBindings.isThreadBound()) { - return ContextBindings.getThread(); - } else { - return ContextBindings.getClassLoader(); - } - } - - } - - - /** - * Strips the URL header. - * - * @return the parsed name - * @exception NamingException if there is no "java:" header or if no - * naming context has been bound to this thread - */ - protected String parseName(String name) - throws NamingException { - - if ((!initialContext) && (name.startsWith(prefix))) { - return (name.substring(prefixLength)); - } else { - if (initialContext) { - return (name); - } else { - throw new NamingException - (sm.getString("selectorContext.noJavaUrl")); - } - } - - } - - - /** - * Strips the URL header. - * - * @return the parsed name - * @exception NamingException if there is no "java:" header or if no - * naming context has been bound to this thread - */ - protected Name parseName(Name name) - throws NamingException { - - if ((!initialContext) && (!name.isEmpty()) - && (name.get(0).equals(prefix))) { - return (name.getSuffix(1)); - } else { - if (initialContext) { - return (name); - } else { - throw new NamingException - (sm.getString("selectorContext.noJavaUrl")); - } - } - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming; + +import java.util.Hashtable; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Catalina JNDI Context implementation. + * + * @author Remy Maucherat + * @version $Revision: 303999 $ $Date: 2005-07-20 23:25:18 +0200 (mer., 20 juil. 2005) $ + */ + +public class SelectorContext implements Context { + + + // -------------------------------------------------------------- Constants + + + /** + * Namespace URL. + */ + public static final String prefix = "java:"; + + + /** + * Namespace URL length. + */ + public static final int prefixLength = prefix.length(); + + + /** + * Initial context prefix. + */ + public static final String IC_PREFIX = "IC_"; + + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a Catalina selector context using the given environment. + */ + public SelectorContext(Hashtable env) { + this.env = env; + } + + + /** + * Builds a Catalina selector context using the given environment. + */ + public SelectorContext(Hashtable env, boolean initialContext) { + this(env); + this.initialContext = initialContext; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Environment. + */ + protected Hashtable env; + + + /** + * The string manager for this package. + */ + protected StringManager sm = StringManager.getManager(Constants.Package); + + + /** + * Request for an initial context. + */ + protected boolean initialContext = false; + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. If name is empty, returns a new instance + * of this context (which represents the same naming context as this + * context, but its environment may be modified independently and it may + * be accessed concurrently). + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(Name name) + throws NamingException { + // Strip the URL header + // Find the appropriate NamingContext according to the current bindings + // Execute the lookup on that context + return getBoundContext().lookup(parseName(name)); + } + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(String name) + throws NamingException { + // Strip the URL header + // Find the appropriate NamingContext according to the current bindings + // Execute the lookup on that context + return getBoundContext().lookup(parseName(name)); + } + + + /** + * Binds a name to an object. All intermediate contexts and the target + * context (that named by all but terminal atomic component of the name) + * must already exist. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj) + throws NamingException { + getBoundContext().bind(parseName(name), obj); + } + + + /** + * Binds a name to an object. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj) + throws NamingException { + getBoundContext().bind(parseName(name), obj); + } + + + /** + * Binds a name to an object, overwriting any existing binding. All + * intermediate contexts and the target context (that named by all but + * terminal atomic component of the name) must already exist. + *

        + * If the object is a DirContext, any existing attributes associated with + * the name are replaced with those of the object. Otherwise, any + * existing attributes associated with the name remain unchanged. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj) + throws NamingException { + getBoundContext().rebind(parseName(name), obj); + } + + + /** + * Binds a name to an object, overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj) + throws NamingException { + getBoundContext().rebind(parseName(name), obj); + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(Name name) + throws NamingException { + getBoundContext().unbind(parseName(name)); + } + + + /** + * Unbinds the named object. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(String name) + throws NamingException { + getBoundContext().unbind(parseName(name)); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(Name oldName, Name newName) + throws NamingException { + getBoundContext().rename(parseName(oldName), parseName(newName)); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(String oldName, String newName) + throws NamingException { + getBoundContext().rename(parseName(oldName), parseName(newName)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(Name name) + throws NamingException { + return getBoundContext().list(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(String name) + throws NamingException { + return getBoundContext().list(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(Name name) + throws NamingException { + return getBoundContext().listBindings(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(String name) + throws NamingException { + return getBoundContext().listBindings(parseName(name)); + } + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(Name name) + throws NamingException { + getBoundContext().destroySubcontext(parseName(name)); + } + + + /** + * Destroys the named context and removes it from the namespace. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(String name) + throws NamingException { + getBoundContext().destroySubcontext(parseName(name)); + } + + + /** + * Creates and binds a new context. Creates a new context with the given + * name and binds it in the target context (that named by all but + * terminal atomic component of the name). All intermediate contexts and + * the target context must already exist. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(Name name) + throws NamingException { + return getBoundContext().createSubcontext(parseName(name)); + } + + + /** + * Creates and binds a new context. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(String name) + throws NamingException { + return getBoundContext().createSubcontext(parseName(name)); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(Name name) + throws NamingException { + return getBoundContext().lookupLink(parseName(name)); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(String name) + throws NamingException { + return getBoundContext().lookupLink(parseName(name)); + } + + + /** + * Retrieves the parser associated with the named context. In a + * federation of namespaces, different naming systems will parse names + * differently. This method allows an application to get a parser for + * parsing names into their atomic components using the naming convention + * of a particular naming system. Within any single naming system, + * NameParser objects returned by this method must be equal (using the + * equals() test). + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(Name name) + throws NamingException { + return getBoundContext().getNameParser(parseName(name)); + } + + + /** + * Retrieves the parser associated with the named context. + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(String name) + throws NamingException { + return getBoundContext().getNameParser(parseName(name)); + } + + + /** + * Composes the name of this context with a name relative to this context. + *

        + * Given a name (name) relative to this context, and the name (prefix) + * of this context relative to one of its ancestors, this method returns + * the composition of the two names using the syntax appropriate for the + * naming system(s) involved. That is, if name names an object relative + * to this context, the result is the name of the same object, but + * relative to the ancestor context. None of the names may be null. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public Name composeName(Name name, Name prefix) + throws NamingException { + prefix = (Name) prefix.clone(); + return prefix.addAll(name); + } + + + /** + * Composes the name of this context with a name relative to this context. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public String composeName(String name, String prefix) + throws NamingException { + return prefix + "/" + name; + } + + + /** + * Adds a new environment property to the environment of this context. If + * the property already exists, its value is overwritten. + * + * @param propName the name of the environment property to add; may not + * be null + * @param propVal the value of the property to add; may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + return getBoundContext().addToEnvironment(propName, propVal); + } + + + /** + * Removes an environment property from the environment of this context. + * + * @param propName the name of the environment property to remove; + * may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object removeFromEnvironment(String propName) + throws NamingException { + return getBoundContext().removeFromEnvironment(propName); + } + + + /** + * Retrieves the environment in effect for this context. See class + * description for more details on environment properties. + * The caller should not make any changes to the object returned: their + * effect on the context is undefined. The environment of this context + * may be changed using addToEnvironment() and removeFromEnvironment(). + * + * @return the environment of this context; never null + * @exception NamingException if a naming exception is encountered + */ + public Hashtable getEnvironment() + throws NamingException { + return getBoundContext().getEnvironment(); + } + + + /** + * Closes this context. This method releases this context's resources + * immediately, instead of waiting for them to be released automatically + * by the garbage collector. + * This method is idempotent: invoking it on a context that has already + * been closed has no effect. Invoking any other method on a closed + * context is not allowed, and results in undefined behaviour. + * + * @exception NamingException if a naming exception is encountered + */ + public void close() + throws NamingException { + getBoundContext().close(); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public String getNameInNamespace() + throws NamingException { + return prefix; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Get the bound context. + */ + protected Context getBoundContext() + throws NamingException { + + if (initialContext) { + String ICName = IC_PREFIX; + if (ContextBindings.isThreadBound()) { + ICName += ContextBindings.getThreadName(); + } else if (ContextBindings.isClassLoaderBound()) { + ICName += ContextBindings.getClassLoaderName(); + } + Context initialContext = ContextBindings.getContext(ICName); + if (initialContext == null) { + // Allocating a new context and binding it to the appropriate + // name + initialContext = new NamingContext(env, ICName); + ContextBindings.bindContext(ICName, initialContext); + } + return initialContext; + } else { + if (ContextBindings.isThreadBound()) { + return ContextBindings.getThread(); + } else { + return ContextBindings.getClassLoader(); + } + } + + } + + + /** + * Strips the URL header. + * + * @return the parsed name + * @exception NamingException if there is no "java:" header or if no + * naming context has been bound to this thread + */ + protected String parseName(String name) + throws NamingException { + + if ((!initialContext) && (name.startsWith(prefix))) { + return (name.substring(prefixLength)); + } else { + if (initialContext) { + return (name); + } else { + throw new NamingException + (sm.getString("selectorContext.noJavaUrl")); + } + } + + } + + + /** + * Strips the URL header. + * + * @return the parsed name + * @exception NamingException if there is no "java:" header or if no + * naming context has been bound to this thread + */ + protected Name parseName(Name name) + throws NamingException { + + if ((!initialContext) && (!name.isEmpty()) + && (name.get(0).equals(prefix))) { + return (name.getSuffix(1)); + } else { + if (initialContext) { + return (name); + } else { + throw new NamingException + (sm.getString("selectorContext.noJavaUrl")); + } + } + + } + + +} + diff --git a/java/org/apache/naming/StringManager.java b/java/org/apache/naming/StringManager.java index 0b42e4b11..82da0b308 100644 --- a/java/org/apache/naming/StringManager.java +++ b/java/org/apache/naming/StringManager.java @@ -1,217 +1,217 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming; - -import java.text.MessageFormat; -import java.util.Hashtable; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -/** - * An internationalization / localization helper class which reduces - * the bother of handling ResourceBundles and takes care of the - * common cases of message formating which otherwise require the - * creation of Object arrays and such. - * - *

        The StringManager operates on a package basis. One StringManager - * per package can be created and accessed via the getManager method - * call. - * - *

        The StringManager will look for a ResourceBundle named by - * the package name given plus the suffix of "LocalStrings". In - * practice, this means that the localized information will be contained - * in a LocalStrings.properties file located in the package - * directory of the classpath. - * - *

        Please see the documentation for java.util.ResourceBundle for - * more information. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - */ - -public class StringManager { - - /** - * The ResourceBundle for this StringManager. - */ - - private ResourceBundle bundle; - - /** - * Creates a new StringManager for a given package. This is a - * private method and all access to it is arbitrated by the - * static getManager method call so that only one StringManager - * per package will be created. - * - * @param packageName Name of package to create StringManager for. - */ - - private StringManager(String packageName) { - String bundleName = packageName + ".LocalStrings"; - bundle = ResourceBundle.getBundle(bundleName); - } - - /** - * Get a string from the underlying resource bundle. - * - * @param key - */ - - public String getString(String key) { - if (key == null) { - String msg = "key is null"; - - throw new NullPointerException(msg); - } - - String str = null; - - try { - str = bundle.getString(key); - } catch (MissingResourceException mre) { - str = "Cannot find message associated with key '" + key + "'"; - } - - return str; - } - - /** - * Get a string from the underlying resource bundle and format - * it with the given set of arguments. - * - * @param key - * @param args - */ - - public String getString(String key, Object[] args) { - String iString = null; - String value = getString(key); - - // this check for the runtime exception is some pre 1.1.6 - // VM's don't do an automatic toString() on the passed in - // objects and barf out - - try { - // ensure the arguments are not null so pre 1.2 VM's don't barf - Object nonNullArgs[] = args; - for (int i=0; iThe StringManager operates on a package basis. One StringManager + * per package can be created and accessed via the getManager method + * call. + * + *

        The StringManager will look for a ResourceBundle named by + * the package name given plus the suffix of "LocalStrings". In + * practice, this means that the localized information will be contained + * in a LocalStrings.properties file located in the package + * directory of the classpath. + * + *

        Please see the documentation for java.util.ResourceBundle for + * more information. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + */ + +public class StringManager { + + /** + * The ResourceBundle for this StringManager. + */ + + private ResourceBundle bundle; + + /** + * Creates a new StringManager for a given package. This is a + * private method and all access to it is arbitrated by the + * static getManager method call so that only one StringManager + * per package will be created. + * + * @param packageName Name of package to create StringManager for. + */ + + private StringManager(String packageName) { + String bundleName = packageName + ".LocalStrings"; + bundle = ResourceBundle.getBundle(bundleName); + } + + /** + * Get a string from the underlying resource bundle. + * + * @param key + */ + + public String getString(String key) { + if (key == null) { + String msg = "key is null"; + + throw new NullPointerException(msg); + } + + String str = null; + + try { + str = bundle.getString(key); + } catch (MissingResourceException mre) { + str = "Cannot find message associated with key '" + key + "'"; + } + + return str; + } + + /** + * Get a string from the underlying resource bundle and format + * it with the given set of arguments. + * + * @param key + * @param args + */ + + public String getString(String key, Object[] args) { + String iString = null; + String value = getString(key); + + // this check for the runtime exception is some pre 1.1.6 + // VM's don't do an automatic toString() on the passed in + // objects and barf out + + try { + // ensure the arguments are not null so pre 1.2 VM's don't barf + Object nonNullArgs[] = args; + for (int i=0; iThis factory can be configured in a <DefaultContext> - * or <Context> element in your conf/server.xml - * configuration file. An example of factory configuration is:

        - *
        - * <Resource name="jdbc/myDataSource" auth="SERVLET"
        - *   type="oracle.jdbc.pool.OracleConnectionCacheImpl"/>
        - * <ResourceParams name="jdbc/myDataSource">
        - *   <parameter>
        - *     <name>factory</name>
        - *     <value>org.apache.naming.factory.BeanFactory</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>driverType</name>
        - *     <value>thin</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>serverName</name>
        - *     <value>hue</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>networkProtocol</name>
        - *     <value>tcp</value>
        - *   </parameter> 
        - *   <parameter>
        - *     <name>databaseName</name>
        - *     <value>XXXX</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>portNumber</name>
        - *     <value>NNNN</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>user</name>
        - *     <value>XXXX</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>password</name>
        - *     <value>XXXX</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>maxLimit</name>
        - *     <value>5</value>
        - *   </parameter>
        - * </ResourceParams>
        - * 
        - * - * @author Aner Perez - */ -public class BeanFactory - implements ObjectFactory { - - // ----------------------------------------------------------- Constructors - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Create a new Bean instance. - * - * @param obj The reference object describing the Bean - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws NamingException { - - if (obj instanceof ResourceRef) { - - try { - - Reference ref = (Reference) obj; - String beanClassName = ref.getClassName(); - Class beanClass = null; - ClassLoader tcl = - Thread.currentThread().getContextClassLoader(); - if (tcl != null) { - try { - beanClass = tcl.loadClass(beanClassName); - } catch(ClassNotFoundException e) { - } - } else { - try { - beanClass = Class.forName(beanClassName); - } catch(ClassNotFoundException e) { - e.printStackTrace(); - } - } - if (beanClass == null) { - throw new NamingException - ("Class not found: " + beanClassName); - } - - BeanInfo bi = Introspector.getBeanInfo(beanClass); - PropertyDescriptor[] pda = bi.getPropertyDescriptors(); - - Object bean = beanClass.newInstance(); - - Enumeration e = ref.getAll(); - while (e.hasMoreElements()) { - - RefAddr ra = (RefAddr) e.nextElement(); - String propName = ra.getType(); - - if (propName.equals(Constants.FACTORY) || - propName.equals("scope") || propName.equals("auth")) { - continue; - } - - String value = (String)ra.getContent(); - - Object[] valueArray = new Object[1]; - - int i = 0; - for (i = 0; iThis factory can be configured in a <DefaultContext> + * or <Context> element in your conf/server.xml + * configuration file. An example of factory configuration is:

        + *
        + * <Resource name="jdbc/myDataSource" auth="SERVLET"
        + *   type="oracle.jdbc.pool.OracleConnectionCacheImpl"/>
        + * <ResourceParams name="jdbc/myDataSource">
        + *   <parameter>
        + *     <name>factory</name>
        + *     <value>org.apache.naming.factory.BeanFactory</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>driverType</name>
        + *     <value>thin</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>serverName</name>
        + *     <value>hue</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>networkProtocol</name>
        + *     <value>tcp</value>
        + *   </parameter> 
        + *   <parameter>
        + *     <name>databaseName</name>
        + *     <value>XXXX</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>portNumber</name>
        + *     <value>NNNN</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>user</name>
        + *     <value>XXXX</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>password</name>
        + *     <value>XXXX</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>maxLimit</name>
        + *     <value>5</value>
        + *   </parameter>
        + * </ResourceParams>
        + * 
        + * + * @author Aner Perez + */ +public class BeanFactory + implements ObjectFactory { + + // ----------------------------------------------------------- Constructors + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Create a new Bean instance. + * + * @param obj The reference object describing the Bean + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws NamingException { + + if (obj instanceof ResourceRef) { + + try { + + Reference ref = (Reference) obj; + String beanClassName = ref.getClassName(); + Class beanClass = null; + ClassLoader tcl = + Thread.currentThread().getContextClassLoader(); + if (tcl != null) { + try { + beanClass = tcl.loadClass(beanClassName); + } catch(ClassNotFoundException e) { + } + } else { + try { + beanClass = Class.forName(beanClassName); + } catch(ClassNotFoundException e) { + e.printStackTrace(); + } + } + if (beanClass == null) { + throw new NamingException + ("Class not found: " + beanClassName); + } + + BeanInfo bi = Introspector.getBeanInfo(beanClass); + PropertyDescriptor[] pda = bi.getPropertyDescriptors(); + + Object bean = beanClass.newInstance(); + + Enumeration e = ref.getAll(); + while (e.hasMoreElements()) { + + RefAddr ra = (RefAddr) e.nextElement(); + String propName = ra.getType(); + + if (propName.equals(Constants.FACTORY) || + propName.equals("scope") || propName.equals("auth")) { + continue; + } + + String value = (String)ra.getContent(); + + Object[] valueArray = new Object[1]; + + int i = 0; + for (i = 0; iFactory class that creates a JNDI named JavaMail Session factory, - * which can be used for managing inbound and outbound electronic mail - * messages via JavaMail APIs. All messaging environment properties - * described in the JavaMail Specification may be passed to the Session - * factory; however the following properties are the most commonly used:

        - *
          - *
        • - *
        • mail.smtp.host - Hostname for outbound transport - * connections. Defaults to localhost if not specified.
        • - *
        - * - *

        This factory can be configured in a <DefaultContext> - * or <Context> element in your conf/server.xml - * configuration file. An example of factory configuration is:

        - *
        - * <Resource name="mail/smtp" auth="CONTAINER"
        - *           type="javax.mail.Session"/>
        - * <ResourceParams name="mail/smtp">
        - *   <parameter>
        - *     <name>factory</name>
        - *     <value>org.apache.naming.factory.MailSessionFactory</value>
        - *   </parameter>
        - *   <parameter>
        - *     <name>mail.smtp.host</name>
        - *     <value>mail.mycompany.com</value>
        - *   </parameter>
        - * </ResourceParams>
        - * 
        - * - * @author Craig R. McClanahan - * @version $Revision: 303771 $ $Date: 2005-03-23 16:30:56 +0100 (mer., 23 mars 2005) $ - */ - -public class MailSessionFactory implements ObjectFactory { - - - /** - * The Java type for which this factory knows how to create objects. - */ - protected static final String factoryType = "javax.mail.Session"; - - - /** - * Create and return an object instance based on the specified - * characteristics. - * - * @param refObj Reference information containing our parameters, or null - * if there are no parameters - * @param name The name of this object, relative to context, or null - * if there is no name - * @param context The context to which name is relative, or null if name - * is relative to the default initial context - * @param env Environment variables, or null if there are none - * - * @exception Exception if an error occurs during object creation - */ - public Object getObjectInstance(Object refObj, Name name, Context context, - Hashtable env) throws Exception - { - - // Return null if we cannot create an object of the requested type - final Reference ref = (Reference) refObj; - if (!ref.getClassName().equals(factoryType)) - return (null); - - // Create a new Session inside a doPrivileged block, so that JavaMail - // can read its default properties without throwing Security - // exceptions. - // - // Bugzilla 31288, 33077: add support for authentication. - return AccessController.doPrivileged( new PrivilegedAction() { - public Object run() { - - // Create the JavaMail properties we will use - Properties props = new Properties(); - props.put("mail.transport.protocol", "smtp"); - props.put("mail.smtp.host", "localhost"); - - String password = null; - - Enumeration attrs = ref.getAll(); - while (attrs.hasMoreElements()) { - RefAddr attr = (RefAddr) attrs.nextElement(); - if ("factory".equals(attr.getType())) { - continue; - } - - if ("password".equals(attr.getType())) { - password = (String) attr.getContent(); - continue; - } - - props.put(attr.getType(), (String) attr.getContent()); - } - - Authenticator auth = null; - if (password != null) { - String user = props.getProperty("mail.smtp.user"); - if(user == null) { - user = props.getProperty("mail.user"); - } - - if(user != null) { - final PasswordAuthentication pa = new PasswordAuthentication(user, password); - auth = new Authenticator() { - protected PasswordAuthentication getPasswordAuthentication() { - return pa; - } - }; - } - } - - // Create and return the new Session object - Session session = Session.getInstance(props, auth); - return (session); - - } - } ); - - } - - -} +/* + * Copyright 1999-2001,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.factory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Properties; +import javax.mail.Authenticator; +import javax.mail.PasswordAuthentication; +import javax.mail.Session; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; + +/** + *

        Factory class that creates a JNDI named JavaMail Session factory, + * which can be used for managing inbound and outbound electronic mail + * messages via JavaMail APIs. All messaging environment properties + * described in the JavaMail Specification may be passed to the Session + * factory; however the following properties are the most commonly used:

        + *
          + *
        • + *
        • mail.smtp.host - Hostname for outbound transport + * connections. Defaults to localhost if not specified.
        • + *
        + * + *

        This factory can be configured in a <DefaultContext> + * or <Context> element in your conf/server.xml + * configuration file. An example of factory configuration is:

        + *
        + * <Resource name="mail/smtp" auth="CONTAINER"
        + *           type="javax.mail.Session"/>
        + * <ResourceParams name="mail/smtp">
        + *   <parameter>
        + *     <name>factory</name>
        + *     <value>org.apache.naming.factory.MailSessionFactory</value>
        + *   </parameter>
        + *   <parameter>
        + *     <name>mail.smtp.host</name>
        + *     <value>mail.mycompany.com</value>
        + *   </parameter>
        + * </ResourceParams>
        + * 
        + * + * @author Craig R. McClanahan + * @version $Revision: 303771 $ $Date: 2005-03-23 16:30:56 +0100 (mer., 23 mars 2005) $ + */ + +public class MailSessionFactory implements ObjectFactory { + + + /** + * The Java type for which this factory knows how to create objects. + */ + protected static final String factoryType = "javax.mail.Session"; + + + /** + * Create and return an object instance based on the specified + * characteristics. + * + * @param refObj Reference information containing our parameters, or null + * if there are no parameters + * @param name The name of this object, relative to context, or null + * if there is no name + * @param context The context to which name is relative, or null if name + * is relative to the default initial context + * @param env Environment variables, or null if there are none + * + * @exception Exception if an error occurs during object creation + */ + public Object getObjectInstance(Object refObj, Name name, Context context, + Hashtable env) throws Exception + { + + // Return null if we cannot create an object of the requested type + final Reference ref = (Reference) refObj; + if (!ref.getClassName().equals(factoryType)) + return (null); + + // Create a new Session inside a doPrivileged block, so that JavaMail + // can read its default properties without throwing Security + // exceptions. + // + // Bugzilla 31288, 33077: add support for authentication. + return AccessController.doPrivileged( new PrivilegedAction() { + public Object run() { + + // Create the JavaMail properties we will use + Properties props = new Properties(); + props.put("mail.transport.protocol", "smtp"); + props.put("mail.smtp.host", "localhost"); + + String password = null; + + Enumeration attrs = ref.getAll(); + while (attrs.hasMoreElements()) { + RefAddr attr = (RefAddr) attrs.nextElement(); + if ("factory".equals(attr.getType())) { + continue; + } + + if ("password".equals(attr.getType())) { + password = (String) attr.getContent(); + continue; + } + + props.put(attr.getType(), (String) attr.getContent()); + } + + Authenticator auth = null; + if (password != null) { + String user = props.getProperty("mail.smtp.user"); + if(user == null) { + user = props.getProperty("mail.user"); + } + + if(user != null) { + final PasswordAuthentication pa = new PasswordAuthentication(user, password); + auth = new Authenticator() { + protected PasswordAuthentication getPasswordAuthentication() { + return pa; + } + }; + } + } + + // Create and return the new Session object + Session session = Session.getInstance(props, auth); + return (session); + + } + } ); + + } + + +} diff --git a/java/org/apache/naming/factory/OpenEjbFactory.java b/java/org/apache/naming/factory/OpenEjbFactory.java index a1a04dfc7..7eface6cc 100644 --- a/java/org/apache/naming/factory/OpenEjbFactory.java +++ b/java/org/apache/naming/factory/OpenEjbFactory.java @@ -1,89 +1,89 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.factory; - -import org.apache.naming.EjbRef; - -import javax.naming.Context; -import javax.naming.InitialContext; -import javax.naming.Name; -import javax.naming.Reference; -import javax.naming.RefAddr; -import javax.naming.spi.ObjectFactory; -import java.util.Hashtable; -import java.util.Properties; - -/** - * Object factory for EJBs. - * - * @author Jacek Laskowski - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ -public class OpenEjbFactory implements ObjectFactory { - - - // -------------------------------------------------------------- Constants - - - protected static final String DEFAULT_OPENEJB_FACTORY = - "org.openejb.client.LocalInitialContextFactory"; - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Crete a new EJB instance using OpenEJB. - * - * @param obj The reference object describing the DataSource - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws Exception { - - Object beanObj = null; - - if (obj instanceof EjbRef) { - - Reference ref = (Reference) obj; - - String factory = DEFAULT_OPENEJB_FACTORY; - RefAddr factoryRefAddr = ref.get("openejb.factory"); - if (factoryRefAddr != null) { - // Retrieving the OpenEJB factory - factory = factoryRefAddr.getContent().toString(); - } - - Properties env = new Properties(); - env.put(Context.INITIAL_CONTEXT_FACTORY, factory); - - RefAddr linkRefAddr = ref.get("openejb.link"); - if (linkRefAddr != null) { - String ejbLink = linkRefAddr.getContent().toString(); - beanObj = (new InitialContext(env)).lookup(ejbLink); - } - - } - - return beanObj; - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.factory; + +import org.apache.naming.EjbRef; + +import javax.naming.Context; +import javax.naming.InitialContext; +import javax.naming.Name; +import javax.naming.Reference; +import javax.naming.RefAddr; +import javax.naming.spi.ObjectFactory; +import java.util.Hashtable; +import java.util.Properties; + +/** + * Object factory for EJBs. + * + * @author Jacek Laskowski + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ +public class OpenEjbFactory implements ObjectFactory { + + + // -------------------------------------------------------------- Constants + + + protected static final String DEFAULT_OPENEJB_FACTORY = + "org.openejb.client.LocalInitialContextFactory"; + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Crete a new EJB instance using OpenEJB. + * + * @param obj The reference object describing the DataSource + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws Exception { + + Object beanObj = null; + + if (obj instanceof EjbRef) { + + Reference ref = (Reference) obj; + + String factory = DEFAULT_OPENEJB_FACTORY; + RefAddr factoryRefAddr = ref.get("openejb.factory"); + if (factoryRefAddr != null) { + // Retrieving the OpenEJB factory + factory = factoryRefAddr.getContent().toString(); + } + + Properties env = new Properties(); + env.put(Context.INITIAL_CONTEXT_FACTORY, factory); + + RefAddr linkRefAddr = ref.get("openejb.link"); + if (linkRefAddr != null) { + String ejbLink = linkRefAddr.getContent().toString(); + beanObj = (new InitialContext(env)).lookup(ejbLink); + } + + } + + return beanObj; + + } + + +} diff --git a/java/org/apache/naming/factory/ResourceEnvFactory.java b/java/org/apache/naming/factory/ResourceEnvFactory.java index ffb504c65..a42bc343a 100644 --- a/java/org/apache/naming/factory/ResourceEnvFactory.java +++ b/java/org/apache/naming/factory/ResourceEnvFactory.java @@ -1,124 +1,124 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.factory; - -import java.util.Hashtable; -import javax.naming.Name; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.RefAddr; -import javax.naming.spi.ObjectFactory; -import org.apache.naming.ResourceEnvRef; - -/** - * Object factory for Resources env. - * - * @author Remy Maucherat - * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ - */ - -public class ResourceEnvFactory - implements ObjectFactory { - - - // ----------------------------------------------------------- Constructors - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Crete a new Resource env instance. - * - * @param obj The reference object describing the DataSource - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws Exception { - - if (obj instanceof ResourceEnvRef) { - Reference ref = (Reference) obj; - ObjectFactory factory = null; - RefAddr factoryRefAddr = ref.get(Constants.FACTORY); - if (factoryRefAddr != null) { - // Using the specified factory - String factoryClassName = - factoryRefAddr.getContent().toString(); - // Loading factory - ClassLoader tcl = - Thread.currentThread().getContextClassLoader(); - Class factoryClass = null; - if (tcl != null) { - try { - factoryClass = tcl.loadClass(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } else { - try { - factoryClass = Class.forName(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } - if (factoryClass != null) { - try { - factory = (ObjectFactory) factoryClass.newInstance(); - } catch(Throwable t) { - if (t instanceof NamingException) - throw (NamingException) t; - NamingException ex = new NamingException - ("Could not create resource factory instance"); - ex.initCause(t); - throw ex; - } - } - } - // Note: No defaults here - if (factory != null) { - return factory.getObjectInstance - (obj, name, nameCtx, environment); - } else { - throw new NamingException - ("Cannot create resource instance"); - } - } - - return null; - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.factory; + +import java.util.Hashtable; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.RefAddr; +import javax.naming.spi.ObjectFactory; +import org.apache.naming.ResourceEnvRef; + +/** + * Object factory for Resources env. + * + * @author Remy Maucherat + * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ + */ + +public class ResourceEnvFactory + implements ObjectFactory { + + + // ----------------------------------------------------------- Constructors + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Crete a new Resource env instance. + * + * @param obj The reference object describing the DataSource + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws Exception { + + if (obj instanceof ResourceEnvRef) { + Reference ref = (Reference) obj; + ObjectFactory factory = null; + RefAddr factoryRefAddr = ref.get(Constants.FACTORY); + if (factoryRefAddr != null) { + // Using the specified factory + String factoryClassName = + factoryRefAddr.getContent().toString(); + // Loading factory + ClassLoader tcl = + Thread.currentThread().getContextClassLoader(); + Class factoryClass = null; + if (tcl != null) { + try { + factoryClass = tcl.loadClass(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } else { + try { + factoryClass = Class.forName(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } + if (factoryClass != null) { + try { + factory = (ObjectFactory) factoryClass.newInstance(); + } catch(Throwable t) { + if (t instanceof NamingException) + throw (NamingException) t; + NamingException ex = new NamingException + ("Could not create resource factory instance"); + ex.initCause(t); + throw ex; + } + } + } + // Note: No defaults here + if (factory != null) { + return factory.getObjectInstance + (obj, name, nameCtx, environment); + } else { + throw new NamingException + ("Cannot create resource instance"); + } + } + + return null; + + } + + +} + diff --git a/java/org/apache/naming/factory/ResourceFactory.java b/java/org/apache/naming/factory/ResourceFactory.java index 66a005fa3..3c1ea8660 100644 --- a/java/org/apache/naming/factory/ResourceFactory.java +++ b/java/org/apache/naming/factory/ResourceFactory.java @@ -1,153 +1,153 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.factory; - -import java.util.Hashtable; -import javax.naming.Name; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.RefAddr; -import javax.naming.spi.ObjectFactory; -import org.apache.naming.ResourceRef; - -/** - * Object factory for Resources. - * - * @author Remy Maucherat - * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ - */ - -public class ResourceFactory - implements ObjectFactory { - - - // ----------------------------------------------------------- Constructors - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Crete a new DataSource instance. - * - * @param obj The reference object describing the DataSource - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws Exception { - - if (obj instanceof ResourceRef) { - Reference ref = (Reference) obj; - ObjectFactory factory = null; - RefAddr factoryRefAddr = ref.get(Constants.FACTORY); - if (factoryRefAddr != null) { - // Using the specified factory - String factoryClassName = - factoryRefAddr.getContent().toString(); - // Loading factory - ClassLoader tcl = - Thread.currentThread().getContextClassLoader(); - Class factoryClass = null; - if (tcl != null) { - try { - factoryClass = tcl.loadClass(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } else { - try { - factoryClass = Class.forName(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } - if (factoryClass != null) { - try { - factory = (ObjectFactory) factoryClass.newInstance(); - } catch (Throwable t) { - if (t instanceof NamingException) - throw (NamingException) t; - NamingException ex = new NamingException - ("Could not create resource factory instance"); - ex.initCause(t); - throw ex; - } - } - } else { - if (ref.getClassName().equals("javax.sql.DataSource")) { - String javaxSqlDataSourceFactoryClassName = - System.getProperty("javax.sql.DataSource.Factory", - Constants.DBCP_DATASOURCE_FACTORY); - try { - factory = (ObjectFactory) - Class.forName(javaxSqlDataSourceFactoryClassName) - .newInstance(); - } catch (Throwable t) { - NamingException ex = new NamingException - ("Could not create resource factory instance"); - ex.initCause(t); - throw ex; - } - } else if (ref.getClassName().equals("javax.mail.Session")) { - String javaxMailSessionFactoryClassName = - System.getProperty("javax.mail.Session.Factory", - "org.apache.naming.factory.MailSessionFactory"); - try { - factory = (ObjectFactory) - Class.forName(javaxMailSessionFactoryClassName) - .newInstance(); - } catch(Throwable t) { - NamingException ex = new NamingException - ("Could not create resource factory instance"); - ex.initCause(t); - throw ex; - } - } - } - if (factory != null) { - return factory.getObjectInstance - (obj, name, nameCtx, environment); - } else { - throw new NamingException - ("Cannot create resource instance"); - } - } - - return null; - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.factory; + +import java.util.Hashtable; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.RefAddr; +import javax.naming.spi.ObjectFactory; +import org.apache.naming.ResourceRef; + +/** + * Object factory for Resources. + * + * @author Remy Maucherat + * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ + */ + +public class ResourceFactory + implements ObjectFactory { + + + // ----------------------------------------------------------- Constructors + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Crete a new DataSource instance. + * + * @param obj The reference object describing the DataSource + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws Exception { + + if (obj instanceof ResourceRef) { + Reference ref = (Reference) obj; + ObjectFactory factory = null; + RefAddr factoryRefAddr = ref.get(Constants.FACTORY); + if (factoryRefAddr != null) { + // Using the specified factory + String factoryClassName = + factoryRefAddr.getContent().toString(); + // Loading factory + ClassLoader tcl = + Thread.currentThread().getContextClassLoader(); + Class factoryClass = null; + if (tcl != null) { + try { + factoryClass = tcl.loadClass(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } else { + try { + factoryClass = Class.forName(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } + if (factoryClass != null) { + try { + factory = (ObjectFactory) factoryClass.newInstance(); + } catch (Throwable t) { + if (t instanceof NamingException) + throw (NamingException) t; + NamingException ex = new NamingException + ("Could not create resource factory instance"); + ex.initCause(t); + throw ex; + } + } + } else { + if (ref.getClassName().equals("javax.sql.DataSource")) { + String javaxSqlDataSourceFactoryClassName = + System.getProperty("javax.sql.DataSource.Factory", + Constants.DBCP_DATASOURCE_FACTORY); + try { + factory = (ObjectFactory) + Class.forName(javaxSqlDataSourceFactoryClassName) + .newInstance(); + } catch (Throwable t) { + NamingException ex = new NamingException + ("Could not create resource factory instance"); + ex.initCause(t); + throw ex; + } + } else if (ref.getClassName().equals("javax.mail.Session")) { + String javaxMailSessionFactoryClassName = + System.getProperty("javax.mail.Session.Factory", + "org.apache.naming.factory.MailSessionFactory"); + try { + factory = (ObjectFactory) + Class.forName(javaxMailSessionFactoryClassName) + .newInstance(); + } catch(Throwable t) { + NamingException ex = new NamingException + ("Could not create resource factory instance"); + ex.initCause(t); + throw ex; + } + } + } + if (factory != null) { + return factory.getObjectInstance + (obj, name, nameCtx, environment); + } else { + throw new NamingException + ("Cannot create resource instance"); + } + } + + return null; + + } + + +} + diff --git a/java/org/apache/naming/factory/ResourceLinkFactory.java b/java/org/apache/naming/factory/ResourceLinkFactory.java index 3fa6ed9c8..cc3542e87 100644 --- a/java/org/apache/naming/factory/ResourceLinkFactory.java +++ b/java/org/apache/naming/factory/ResourceLinkFactory.java @@ -1,107 +1,107 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.factory; - -import java.util.Hashtable; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.NamingException; -import javax.naming.RefAddr; -import javax.naming.Reference; -import javax.naming.spi.ObjectFactory; - -import org.apache.naming.ResourceLinkRef; - - -/** - *

        Object factory for resource links.

        - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class ResourceLinkFactory - implements ObjectFactory { - - - // ----------------------------------------------------------- Constructors - - - // ------------------------------------------------------- Static Variables - - - /** - * Global naming context. - */ - private static Context globalContext = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Set the global context (note: can only be used once). - * - * @param newGlobalContext new global context value - */ - public static void setGlobalContext(Context newGlobalContext) { - if (globalContext != null) - return; - globalContext = newGlobalContext; - } - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Create a new DataSource instance. - * - * @param obj The reference object describing the DataSource - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws NamingException { - - if (!(obj instanceof ResourceLinkRef)) - return null; - - // Can we process this request? - Reference ref = (Reference) obj; - - String type = ref.getClassName(); - - // Read the global ref addr - String globalName = null; - RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME); - if (refAddr != null) { - globalName = refAddr.getContent().toString(); - Object result = null; - result = globalContext.lookup(globalName); - // FIXME: Check type - return result; - } - - return (null); - - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.factory; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.RefAddr; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; + +import org.apache.naming.ResourceLinkRef; + + +/** + *

        Object factory for resource links.

        + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class ResourceLinkFactory + implements ObjectFactory { + + + // ----------------------------------------------------------- Constructors + + + // ------------------------------------------------------- Static Variables + + + /** + * Global naming context. + */ + private static Context globalContext = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Set the global context (note: can only be used once). + * + * @param newGlobalContext new global context value + */ + public static void setGlobalContext(Context newGlobalContext) { + if (globalContext != null) + return; + globalContext = newGlobalContext; + } + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Create a new DataSource instance. + * + * @param obj The reference object describing the DataSource + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws NamingException { + + if (!(obj instanceof ResourceLinkRef)) + return null; + + // Can we process this request? + Reference ref = (Reference) obj; + + String type = ref.getClassName(); + + // Read the global ref addr + String globalName = null; + RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME); + if (refAddr != null) { + globalName = refAddr.getContent().toString(); + Object result = null; + result = globalContext.lookup(globalName); + // FIXME: Check type + return result; + } + + return (null); + + + } + + +} diff --git a/java/org/apache/naming/factory/SendMailFactory.java b/java/org/apache/naming/factory/SendMailFactory.java index 55005b61b..b0fec4828 100644 --- a/java/org/apache/naming/factory/SendMailFactory.java +++ b/java/org/apache/naming/factory/SendMailFactory.java @@ -1,125 +1,125 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.factory; - -import java.security.AccessController; -import java.security.PrivilegedAction; -import java.util.Hashtable; -import java.util.Properties; -import java.util.Enumeration; -import javax.mail.Session; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimePart; -import javax.mail.internet.MimePartDataSource; -import javax.naming.Name; -import javax.naming.Context; -import javax.naming.Reference; -import javax.naming.RefAddr; -import javax.naming.spi.ObjectFactory; - -/** - * Factory class that creates a JNDI named javamail MimePartDataSource - * object which can be used for sending email using SMTP. - *

        - * Can be configured in the DefaultContext or Context scope - * of your server.xml configuration file. - *

        - * Example: - *

        - *

        - * <Resource name="mail/send" auth="CONTAINER"
        - *           type="javax.mail.internet.MimePartDataSource"/>
        - * <ResourceParams name="mail/send">
        - *   <parameter><name>factory</name>
        - *     <value>org.apache.naming.factory.SendMailFactory</value>
        - *   </parameter>
        - *   <parameter><name>mail.smtp.host</name>
        - *     <value>your.smtp.host</value>
        - *   </parameter>
        - *   <parameter><name>mail.smtp.user</name>
        - *     <value>someuser</value>
        - *   </parameter>
        - *   <parameter><name>mail.from</name>
        - *     <value>someuser@some.host</value>
        - *   </parameter>
        - *   <parameter><name>mail.smtp.sendpartial</name>
        - *     <value>true</value>
        - *   </parameter>
        - *  <parameter><name>mail.smtp.dsn.notify</name>
        - *     <value>FAILURE</value>
        - *   </parameter>
        - *   <parameter><name>mail.smtp.dsn.ret</name>
        - *     <value>FULL</value>
        - *   </parameter>
        - * </ResourceParams>
        - * 
        - * - * @author Glenn Nielsen Rich Catlett - */ - -public class SendMailFactory implements ObjectFactory -{ - // The class name for the javamail MimeMessageDataSource - protected final String DataSourceClassName = - "javax.mail.internet.MimePartDataSource"; - - public Object getObjectInstance(Object RefObj, Name Nm, Context Ctx, - Hashtable Env) throws Exception - { - final Reference Ref = (Reference)RefObj; - - // Creation of the DataSource is wrapped inside a doPrivileged - // so that javamail can read its default properties without - // throwing Security Exceptions - if (Ref.getClassName().equals(DataSourceClassName)) { - return AccessController.doPrivileged( new PrivilegedAction() - { - public Object run() { - // set up the smtp session that will send the message - Properties props = new Properties(); - // enumeration of all refaddr - Enumeration list = Ref.getAll(); - // current refaddr to be set - RefAddr refaddr; - // set transport to smtp - props.put("mail.transport.protocol", "smtp"); - - while (list.hasMoreElements()) { - refaddr = (RefAddr)list.nextElement(); - - // set property - props.put(refaddr.getType(), (String)refaddr.getContent()); - } - MimeMessage message = new MimeMessage( - Session.getInstance(props)); - try { - String from = (String)Ref.get("mail.from").getContent(); - message.setFrom(new InternetAddress(from)); - message.setSubject(""); - } catch (Exception e) {} - MimePartDataSource mds = new MimePartDataSource( - (MimePart)message); - return mds; - } - } ); - } - else { // We can't create an instance of the DataSource - return null; - } - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.factory; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.Hashtable; +import java.util.Properties; +import java.util.Enumeration; +import javax.mail.Session; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import javax.mail.internet.MimePart; +import javax.mail.internet.MimePartDataSource; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.Reference; +import javax.naming.RefAddr; +import javax.naming.spi.ObjectFactory; + +/** + * Factory class that creates a JNDI named javamail MimePartDataSource + * object which can be used for sending email using SMTP. + *

        + * Can be configured in the DefaultContext or Context scope + * of your server.xml configuration file. + *

        + * Example: + *

        + *

        + * <Resource name="mail/send" auth="CONTAINER"
        + *           type="javax.mail.internet.MimePartDataSource"/>
        + * <ResourceParams name="mail/send">
        + *   <parameter><name>factory</name>
        + *     <value>org.apache.naming.factory.SendMailFactory</value>
        + *   </parameter>
        + *   <parameter><name>mail.smtp.host</name>
        + *     <value>your.smtp.host</value>
        + *   </parameter>
        + *   <parameter><name>mail.smtp.user</name>
        + *     <value>someuser</value>
        + *   </parameter>
        + *   <parameter><name>mail.from</name>
        + *     <value>someuser@some.host</value>
        + *   </parameter>
        + *   <parameter><name>mail.smtp.sendpartial</name>
        + *     <value>true</value>
        + *   </parameter>
        + *  <parameter><name>mail.smtp.dsn.notify</name>
        + *     <value>FAILURE</value>
        + *   </parameter>
        + *   <parameter><name>mail.smtp.dsn.ret</name>
        + *     <value>FULL</value>
        + *   </parameter>
        + * </ResourceParams>
        + * 
        + * + * @author Glenn Nielsen Rich Catlett + */ + +public class SendMailFactory implements ObjectFactory +{ + // The class name for the javamail MimeMessageDataSource + protected final String DataSourceClassName = + "javax.mail.internet.MimePartDataSource"; + + public Object getObjectInstance(Object RefObj, Name Nm, Context Ctx, + Hashtable Env) throws Exception + { + final Reference Ref = (Reference)RefObj; + + // Creation of the DataSource is wrapped inside a doPrivileged + // so that javamail can read its default properties without + // throwing Security Exceptions + if (Ref.getClassName().equals(DataSourceClassName)) { + return AccessController.doPrivileged( new PrivilegedAction() + { + public Object run() { + // set up the smtp session that will send the message + Properties props = new Properties(); + // enumeration of all refaddr + Enumeration list = Ref.getAll(); + // current refaddr to be set + RefAddr refaddr; + // set transport to smtp + props.put("mail.transport.protocol", "smtp"); + + while (list.hasMoreElements()) { + refaddr = (RefAddr)list.nextElement(); + + // set property + props.put(refaddr.getType(), (String)refaddr.getContent()); + } + MimeMessage message = new MimeMessage( + Session.getInstance(props)); + try { + String from = (String)Ref.get("mail.from").getContent(); + message.setFrom(new InternetAddress(from)); + message.setSubject(""); + } catch (Exception e) {} + MimePartDataSource mds = new MimePartDataSource( + (MimePart)message); + return mds; + } + } ); + } + else { // We can't create an instance of the DataSource + return null; + } + } +} diff --git a/java/org/apache/naming/factory/TransactionFactory.java b/java/org/apache/naming/factory/TransactionFactory.java index d4fc8414e..2e0b3c9b1 100644 --- a/java/org/apache/naming/factory/TransactionFactory.java +++ b/java/org/apache/naming/factory/TransactionFactory.java @@ -1,124 +1,124 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.factory; - -import java.util.Hashtable; -import javax.naming.Name; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.Reference; -import javax.naming.RefAddr; -import javax.naming.spi.ObjectFactory; -import org.apache.naming.TransactionRef; - -/** - * Object factory for User trasactions. - * - * @author Remy Maucherat - * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ - */ - -public class TransactionFactory - implements ObjectFactory { - - - // ----------------------------------------------------------- Constructors - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------- Instance Variables - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Crete a new User transaction instance. - * - * @param obj The reference object describing the DataSource - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws Exception { - - if (obj instanceof TransactionRef) { - Reference ref = (Reference) obj; - ObjectFactory factory = null; - RefAddr factoryRefAddr = ref.get(Constants.FACTORY); - if (factoryRefAddr != null) { - // Using the specified factory - String factoryClassName = - factoryRefAddr.getContent().toString(); - // Loading factory - ClassLoader tcl = - Thread.currentThread().getContextClassLoader(); - Class factoryClass = null; - if (tcl != null) { - try { - factoryClass = tcl.loadClass(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } else { - try { - factoryClass = Class.forName(factoryClassName); - } catch(ClassNotFoundException e) { - NamingException ex = new NamingException - ("Could not load resource factory class"); - ex.initCause(e); - throw ex; - } - } - if (factoryClass != null) { - try { - factory = (ObjectFactory) factoryClass.newInstance(); - } catch(Throwable t) { - if (t instanceof NamingException) - throw (NamingException) t; - NamingException ex = new NamingException - ("Could not create resource factory instance"); - ex.initCause(t); - throw ex; - } - } - } - if (factory != null) { - return factory.getObjectInstance - (obj, name, nameCtx, environment); - } else { - throw new NamingException - ("Cannot create resource instance"); - } - - } - - return null; - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.factory; + +import java.util.Hashtable; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.RefAddr; +import javax.naming.spi.ObjectFactory; +import org.apache.naming.TransactionRef; + +/** + * Object factory for User trasactions. + * + * @author Remy Maucherat + * @version $Revision: 375650 $ $Date: 2006-02-07 18:55:11 +0100 (mar., 07 févr. 2006) $ + */ + +public class TransactionFactory + implements ObjectFactory { + + + // ----------------------------------------------------------- Constructors + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------- Instance Variables + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Crete a new User transaction instance. + * + * @param obj The reference object describing the DataSource + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws Exception { + + if (obj instanceof TransactionRef) { + Reference ref = (Reference) obj; + ObjectFactory factory = null; + RefAddr factoryRefAddr = ref.get(Constants.FACTORY); + if (factoryRefAddr != null) { + // Using the specified factory + String factoryClassName = + factoryRefAddr.getContent().toString(); + // Loading factory + ClassLoader tcl = + Thread.currentThread().getContextClassLoader(); + Class factoryClass = null; + if (tcl != null) { + try { + factoryClass = tcl.loadClass(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } else { + try { + factoryClass = Class.forName(factoryClassName); + } catch(ClassNotFoundException e) { + NamingException ex = new NamingException + ("Could not load resource factory class"); + ex.initCause(e); + throw ex; + } + } + if (factoryClass != null) { + try { + factory = (ObjectFactory) factoryClass.newInstance(); + } catch(Throwable t) { + if (t instanceof NamingException) + throw (NamingException) t; + NamingException ex = new NamingException + ("Could not create resource factory instance"); + ex.initCause(t); + throw ex; + } + } + } + if (factory != null) { + return factory.getObjectInstance + (obj, name, nameCtx, environment); + } else { + throw new NamingException + ("Cannot create resource instance"); + } + + } + + return null; + + } + + +} + diff --git a/java/org/apache/naming/factory/package.html b/java/org/apache/naming/factory/package.html index b64277bad..b18cb0745 100644 --- a/java/org/apache/naming/factory/package.html +++ b/java/org/apache/naming/factory/package.html @@ -1,7 +1,7 @@ - - -

        This package contains object factories used by the naming service.

        - -

        - - + + +

        This package contains object factories used by the naming service.

        + +

        + + diff --git a/java/org/apache/naming/java/javaURLContextFactory.java b/java/org/apache/naming/java/javaURLContextFactory.java index fe9cac364..b653c9cf7 100644 --- a/java/org/apache/naming/java/javaURLContextFactory.java +++ b/java/org/apache/naming/java/javaURLContextFactory.java @@ -1,111 +1,111 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.java; - -import java.util.Hashtable; -import javax.naming.Name; -import javax.naming.Context; -import javax.naming.NamingException; -import javax.naming.spi.ObjectFactory; -import javax.naming.spi.InitialContextFactory; -import org.apache.naming.SelectorContext; -import org.apache.naming.NamingContext; -import org.apache.naming.ContextBindings; - -/** - * Context factory for the "java:" namespace. - *

        - * Important note : This factory MUST be associated with the "java" URL - * prefix, which can be done by either : - *

          - *
        • Adding a - * java.naming.factory.url.pkgs=org.apache.catalina.util.naming property - * to the JNDI properties file
        • - *
        • Setting an environment variable named Context.URL_PKG_PREFIXES with - * its value including the org.apache.catalina.util.naming package name. - * More detail about this can be found in the JNDI documentation : - * {@link javax.naming.spi.NamingManager#getURLContext(java.lang.String, java.util.Hashtable)}.
        • - *
        - * - * @author Remy Maucherat - * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ - */ - -public class javaURLContextFactory - implements ObjectFactory, InitialContextFactory { - - - // ----------------------------------------------------------- Constructors - - - // -------------------------------------------------------------- Constants - - - public static final String MAIN = "initialContext"; - - - // ----------------------------------------------------- Instance Variables - - - /** - * Initial context. - */ - protected static Context initialContext = null; - - - // --------------------------------------------------------- Public Methods - - - // -------------------------------------------------- ObjectFactory Methods - - - /** - * Crete a new Context's instance. - */ - public Object getObjectInstance(Object obj, Name name, Context nameCtx, - Hashtable environment) - throws NamingException { - if ((ContextBindings.isThreadBound()) || - (ContextBindings.isClassLoaderBound())) { - return new SelectorContext(environment); - } else { - return null; - } - } - - - /** - * Get a new (writable) initial context. - */ - public Context getInitialContext(Hashtable environment) - throws NamingException { - if (ContextBindings.isThreadBound() || - (ContextBindings.isClassLoaderBound())) { - // Redirect the request to the bound initial context - return new SelectorContext(environment, true); - } else { - // If the thread is not bound, return a shared writable context - if (initialContext == null) - initialContext = new NamingContext(environment, MAIN); - return initialContext; - } - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.java; + +import java.util.Hashtable; +import javax.naming.Name; +import javax.naming.Context; +import javax.naming.NamingException; +import javax.naming.spi.ObjectFactory; +import javax.naming.spi.InitialContextFactory; +import org.apache.naming.SelectorContext; +import org.apache.naming.NamingContext; +import org.apache.naming.ContextBindings; + +/** + * Context factory for the "java:" namespace. + *

        + * Important note : This factory MUST be associated with the "java" URL + * prefix, which can be done by either : + *

          + *
        • Adding a + * java.naming.factory.url.pkgs=org.apache.catalina.util.naming property + * to the JNDI properties file
        • + *
        • Setting an environment variable named Context.URL_PKG_PREFIXES with + * its value including the org.apache.catalina.util.naming package name. + * More detail about this can be found in the JNDI documentation : + * {@link javax.naming.spi.NamingManager#getURLContext(java.lang.String, java.util.Hashtable)}.
        • + *
        + * + * @author Remy Maucherat + * @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 févr. 2004) $ + */ + +public class javaURLContextFactory + implements ObjectFactory, InitialContextFactory { + + + // ----------------------------------------------------------- Constructors + + + // -------------------------------------------------------------- Constants + + + public static final String MAIN = "initialContext"; + + + // ----------------------------------------------------- Instance Variables + + + /** + * Initial context. + */ + protected static Context initialContext = null; + + + // --------------------------------------------------------- Public Methods + + + // -------------------------------------------------- ObjectFactory Methods + + + /** + * Crete a new Context's instance. + */ + public Object getObjectInstance(Object obj, Name name, Context nameCtx, + Hashtable environment) + throws NamingException { + if ((ContextBindings.isThreadBound()) || + (ContextBindings.isClassLoaderBound())) { + return new SelectorContext(environment); + } else { + return null; + } + } + + + /** + * Get a new (writable) initial context. + */ + public Context getInitialContext(Hashtable environment) + throws NamingException { + if (ContextBindings.isThreadBound() || + (ContextBindings.isClassLoaderBound())) { + // Redirect the request to the bound initial context + return new SelectorContext(environment, true); + } else { + // If the thread is not bound, return a shared writable context + if (initialContext == null) + initialContext = new NamingContext(environment, MAIN); + return initialContext; + } + } + + +} + diff --git a/java/org/apache/naming/java/package.html b/java/org/apache/naming/java/package.html index 489f8bb10..900f764e6 100644 --- a/java/org/apache/naming/java/package.html +++ b/java/org/apache/naming/java/package.html @@ -1,7 +1,7 @@ - - -

        This package contains the URL context factory for the "java" namespace.

        - -

        - - + + +

        This package contains the URL context factory for the "java" namespace.

        + +

        + + diff --git a/java/org/apache/naming/package.html b/java/org/apache/naming/package.html index 83ad2b797..7d5f9eb3b 100644 --- a/java/org/apache/naming/package.html +++ b/java/org/apache/naming/package.html @@ -1,7 +1,7 @@ - - -

        This package contains a memory based naming service provider.

        - -

        - - + + +

        This package contains a memory based naming service provider.

        + +

        + + diff --git a/java/org/apache/naming/resources/BaseDirContext.java b/java/org/apache/naming/resources/BaseDirContext.java index 6db2dc380..8f1321e37 100644 --- a/java/org/apache/naming/resources/BaseDirContext.java +++ b/java/org/apache/naming/resources/BaseDirContext.java @@ -1,1208 +1,1208 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - -import java.util.Hashtable; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.NameParser; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; - -import org.apache.naming.NameParserImpl; -import org.apache.naming.StringManager; - -/** - * Directory Context implementation helper class. - * - * @author Remy Maucherat - * @version $Revision: 303999 $ $Date: 2005-07-20 23:25:18 +0200 (mer., 20 juil. 2005) $ - */ - -public abstract class BaseDirContext implements DirContext { - - - // -------------------------------------------------------------- Constants - - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a base directory context. - */ - public BaseDirContext() { - this.env = new Hashtable(); - } - - - /** - * Builds a base directory context using the given environment. - */ - public BaseDirContext(Hashtable env) { - this.env = env; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The document base path. - */ - protected String docBase = null; - - - /** - * Environment. - */ - protected Hashtable env; - - - /** - * The string manager for this package. - */ - protected StringManager sm = StringManager.getManager(Constants.Package); - - - /** - * Name parser for this context. - */ - protected final NameParser nameParser = new NameParserImpl(); - - - /** - * Cached. - */ - protected boolean cached = true; - - - /** - * Cache TTL. - */ - protected int cacheTTL = 5000; // 5s - - - /** - * Max size of resources which will have their content cached. - */ - protected int cacheMaxSize = 10240; // 10 MB - - - // ------------------------------------------------------------- Properties - - - /** - * Return the document root for this component. - */ - public String getDocBase() { - return (this.docBase); - } - - - /** - * Set the document root for this component. - * - * @param docBase The new document root - * - * @exception IllegalArgumentException if the specified value is not - * supported by this implementation - * @exception IllegalArgumentException if this would create a - * malformed URL - */ - public void setDocBase(String docBase) { - - // Validate the format of the proposed document root - if (docBase == null) - throw new IllegalArgumentException - (sm.getString("resources.null")); - - // Change the document root property - this.docBase = docBase; - - } - - - /** - * Set cached. - */ - public void setCached(boolean cached) { - this.cached = cached; - } - - - /** - * Is cached ? - */ - public boolean isCached() { - return cached; - } - - - /** - * Set cache TTL. - */ - public void setCacheTTL(int cacheTTL) { - this.cacheTTL = cacheTTL; - } - - - /** - * Get cache TTL. - */ - public int getCacheTTL() { - return cacheTTL; - } - - - /** - * Return the maximum size of the cache in KB. - */ - public int getCacheMaxSize() { - return cacheMaxSize; - } - - - /** - * Set the maximum size of the cache in KB. - */ - public void setCacheMaxSize(int cacheMaxSize) { - this.cacheMaxSize = cacheMaxSize; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Allocate resources for this directory context. - */ - public void allocate() { - ; // No action taken by the default implementation - } - - - /** - * Release any resources allocated for this directory context. - */ - public void release() { - ; // No action taken by the default implementation - } - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. If name is empty, returns a new instance - * of this context (which represents the same naming context as this - * context, but its environment may be modified independently and it may - * be accessed concurrently). - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(Name name) - throws NamingException { - return lookup(name.toString()); - } - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public abstract Object lookup(String name) - throws NamingException; - - - /** - * Binds a name to an object. All intermediate contexts and the target - * context (that named by all but terminal atomic component of the name) - * must already exist. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj) - throws NamingException { - bind(name.toString(), obj); - } - - - /** - * Binds a name to an object. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj) - throws NamingException { - bind(name, obj, null); - } - - - /** - * Binds a name to an object, overwriting any existing binding. All - * intermediate contexts and the target context (that named by all but - * terminal atomic component of the name) must already exist. - *

        - * If the object is a DirContext, any existing attributes associated with - * the name are replaced with those of the object. Otherwise, any - * existing attributes associated with the name remain unchanged. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj) - throws NamingException { - rebind(name.toString(), obj); - } - - - /** - * Binds a name to an object, overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj) - throws NamingException { - rebind(name, obj, null); - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(Name name) - throws NamingException { - unbind(name.toString()); - } - - - /** - * Unbinds the named object. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public abstract void unbind(String name) - throws NamingException; - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(Name oldName, Name newName) - throws NamingException { - rename(oldName.toString(), newName.toString()); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public abstract void rename(String oldName, String newName) - throws NamingException; - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(Name name) - throws NamingException { - return list(name.toString()); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration list(String name) - throws NamingException; - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(Name name) - throws NamingException { - return listBindings(name.toString()); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration listBindings(String name) - throws NamingException; - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(Name name) - throws NamingException { - destroySubcontext(name.toString()); - } - - - /** - * Destroys the named context and removes it from the namespace. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public abstract void destroySubcontext(String name) - throws NamingException; - - - /** - * Creates and binds a new context. Creates a new context with the given - * name and binds it in the target context (that named by all but - * terminal atomic component of the name). All intermediate contexts and - * the target context must already exist. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(Name name) - throws NamingException { - return createSubcontext(name.toString()); - } - - - /** - * Creates and binds a new context. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(String name) - throws NamingException { - return createSubcontext(name, null); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(Name name) - throws NamingException { - return lookupLink(name.toString()); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public abstract Object lookupLink(String name) - throws NamingException; - - - /** - * Retrieves the parser associated with the named context. In a - * federation of namespaces, different naming systems will parse names - * differently. This method allows an application to get a parser for - * parsing names into their atomic components using the naming convention - * of a particular naming system. Within any single naming system, - * NameParser objects returned by this method must be equal (using the - * equals() test). - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(Name name) - throws NamingException { - return new NameParserImpl(); - } - - - /** - * Retrieves the parser associated with the named context. - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(String name) - throws NamingException { - return new NameParserImpl(); - } - - - /** - * Composes the name of this context with a name relative to this context. - *

        - * Given a name (name) relative to this context, and the name (prefix) - * of this context relative to one of its ancestors, this method returns - * the composition of the two names using the syntax appropriate for the - * naming system(s) involved. That is, if name names an object relative - * to this context, the result is the name of the same object, but - * relative to the ancestor context. None of the names may be null. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public Name composeName(Name name, Name prefix) - throws NamingException { - prefix = (Name) prefix.clone(); - return prefix.addAll(name); - } - - - /** - * Composes the name of this context with a name relative to this context. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public String composeName(String name, String prefix) - throws NamingException { - return prefix + "/" + name; - } - - - /** - * Adds a new environment property to the environment of this context. If - * the property already exists, its value is overwritten. - * - * @param propName the name of the environment property to add; may not - * be null - * @param propVal the value of the property to add; may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object addToEnvironment(String propName, Object propVal) - throws NamingException { - return env.put(propName, propVal); - } - - - /** - * Removes an environment property from the environment of this context. - * - * @param propName the name of the environment property to remove; - * may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object removeFromEnvironment(String propName) - throws NamingException { - return env.remove(propName); - } - - - /** - * Retrieves the environment in effect for this context. See class - * description for more details on environment properties. - * The caller should not make any changes to the object returned: their - * effect on the context is undefined. The environment of this context - * may be changed using addToEnvironment() and removeFromEnvironment(). - * - * @return the environment of this context; never null - * @exception NamingException if a naming exception is encountered - */ - public Hashtable getEnvironment() - throws NamingException { - return env; - } - - - /** - * Closes this context. This method releases this context's resources - * immediately, instead of waiting for them to be released automatically - * by the garbage collector. - * This method is idempotent: invoking it on a context that has already - * been closed has no effect. Invoking any other method on a closed - * context is not allowed, and results in undefined behaviour. - * - * @exception NamingException if a naming exception is encountered - */ - public void close() - throws NamingException { - env.clear(); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public abstract String getNameInNamespace() - throws NamingException; - - - // ----------------------------------------------------- DirContext Methods - - - /** - * Retrieves all of the attributes associated with a named object. - * - * @return the set of attributes associated with name. - * Returns an empty attribute set if name has no attributes; never null. - * @param name the name of the object from which to retrieve attributes - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(Name name) - throws NamingException { - return getAttributes(name.toString()); - } - - - /** - * Retrieves all of the attributes associated with a named object. - * - * @return the set of attributes associated with name - * @param name the name of the object from which to retrieve attributes - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(String name) - throws NamingException { - return getAttributes(name, null); - } - - - /** - * Retrieves selected attributes associated with a named object. - * See the class description regarding attribute models, attribute type - * names, and operational attributes. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(Name name, String[] attrIds) - throws NamingException { - return getAttributes(name.toString(), attrIds); - } - - - /** - * Retrieves selected attributes associated with a named object. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public abstract Attributes getAttributes(String name, String[] attrIds) - throws NamingException; - - - /** - * Modifies the attributes associated with a named object. The order of - * the modifications is not specified. Where possible, the modifications - * are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(Name name, int mod_op, Attributes attrs) - throws NamingException { - modifyAttributes(name.toString(), mod_op, attrs); - } - - - /** - * Modifies the attributes associated with a named object. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public abstract void modifyAttributes - (String name, int mod_op, Attributes attrs) - throws NamingException; - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. The modifications are performed in the - * order specified. Each modification specifies a modification operation - * code and an attribute on which to operate. Where possible, the - * modifications are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(Name name, ModificationItem[] mods) - throws NamingException { - modifyAttributes(name.toString(), mods); - } - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public abstract void modifyAttributes(String name, ModificationItem[] mods) - throws NamingException; - - - /** - * Binds a name to an object, along with associated attributes. If attrs - * is null, the resulting binding will have the attributes associated - * with obj if obj is a DirContext, and no attributes otherwise. If attrs - * is non-null, the resulting binding will have attrs as its attributes; - * any attributes associated with obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj, Attributes attrs) - throws NamingException { - bind(name.toString(), obj, attrs); - } - - - /** - * Binds a name to an object, along with associated attributes. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public abstract void bind(String name, Object obj, Attributes attrs) - throws NamingException; - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. If attrs is null and obj is a - * DirContext, the attributes from obj are used. If attrs is null and obj - * is not a DirContext, any existing attributes associated with the object - * already bound in the directory remain unchanged. If attrs is non-null, - * any existing attributes associated with the object already bound in - * the directory are removed and attrs is associated with the named - * object. If obj is a DirContext and attrs is non-null, the attributes - * of obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj, Attributes attrs) - throws NamingException { - rebind(name.toString(), obj, attrs); - } - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public abstract void rebind(String name, Object obj, Attributes attrs) - throws NamingException; - - - /** - * Creates and binds a new context, along with associated attributes. - * This method creates a new subcontext with the given name, binds it in - * the target context (that named by all but terminal atomic component of - * the name), and associates the supplied attributes with the newly - * created object. All intermediate and target contexts must already - * exist. If attrs is null, this method is equivalent to - * Context.createSubcontext(). - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public DirContext createSubcontext(Name name, Attributes attrs) - throws NamingException { - return createSubcontext(name.toString(), attrs); - } - - - /** - * Creates and binds a new context, along with associated attributes. - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public abstract DirContext createSubcontext(String name, Attributes attrs) - throws NamingException; - - - /** - * Retrieves the schema associated with the named object. The schema - * describes rules regarding the structure of the namespace and the - * attributes stored within it. The schema specifies what types of - * objects can be added to the directory and where they can be added; - * what mandatory and optional attributes an object can have. The range - * of support for schemas is directory-specific. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchema(Name name) - throws NamingException { - return getSchema(name.toString()); - } - - - /** - * Retrieves the schema associated with the named object. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public abstract DirContext getSchema(String name) - throws NamingException; - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchemaClassDefinition(Name name) - throws NamingException { - return getSchemaClassDefinition(name.toString()); - } - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public abstract DirContext getSchemaClassDefinition(String name) - throws NamingException; - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. The search is - * performed using the default SearchControls settings. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException { - return search(name.toString(), matchingAttributes, attributesToReturn); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration search - (String name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException; - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. This method returns all the attributes of such objects. - * It is equivalent to supplying null as the atributesToReturn parameter - * to the method search(Name, Attributes, String[]). - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes) - throws NamingException { - return search(name.toString(), matchingAttributes); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration search - (String name, Attributes matchingAttributes) - throws NamingException; - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter specified - * is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search - (Name name, String filter, SearchControls cons) - throws NamingException { - return search(name.toString(), filter, cons); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter - * specified is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration search(String name, String filter, - SearchControls cons) - throws NamingException; - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException { - return search(name.toString(), filterExpr, filterArgs, cons); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public abstract NamingEnumeration search - (String name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException; - - - // ------------------------------------------------------ Protected Methods - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; + +import org.apache.naming.NameParserImpl; +import org.apache.naming.StringManager; + +/** + * Directory Context implementation helper class. + * + * @author Remy Maucherat + * @version $Revision: 303999 $ $Date: 2005-07-20 23:25:18 +0200 (mer., 20 juil. 2005) $ + */ + +public abstract class BaseDirContext implements DirContext { + + + // -------------------------------------------------------------- Constants + + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a base directory context. + */ + public BaseDirContext() { + this.env = new Hashtable(); + } + + + /** + * Builds a base directory context using the given environment. + */ + public BaseDirContext(Hashtable env) { + this.env = env; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The document base path. + */ + protected String docBase = null; + + + /** + * Environment. + */ + protected Hashtable env; + + + /** + * The string manager for this package. + */ + protected StringManager sm = StringManager.getManager(Constants.Package); + + + /** + * Name parser for this context. + */ + protected final NameParser nameParser = new NameParserImpl(); + + + /** + * Cached. + */ + protected boolean cached = true; + + + /** + * Cache TTL. + */ + protected int cacheTTL = 5000; // 5s + + + /** + * Max size of resources which will have their content cached. + */ + protected int cacheMaxSize = 10240; // 10 MB + + + // ------------------------------------------------------------- Properties + + + /** + * Return the document root for this component. + */ + public String getDocBase() { + return (this.docBase); + } + + + /** + * Set the document root for this component. + * + * @param docBase The new document root + * + * @exception IllegalArgumentException if the specified value is not + * supported by this implementation + * @exception IllegalArgumentException if this would create a + * malformed URL + */ + public void setDocBase(String docBase) { + + // Validate the format of the proposed document root + if (docBase == null) + throw new IllegalArgumentException + (sm.getString("resources.null")); + + // Change the document root property + this.docBase = docBase; + + } + + + /** + * Set cached. + */ + public void setCached(boolean cached) { + this.cached = cached; + } + + + /** + * Is cached ? + */ + public boolean isCached() { + return cached; + } + + + /** + * Set cache TTL. + */ + public void setCacheTTL(int cacheTTL) { + this.cacheTTL = cacheTTL; + } + + + /** + * Get cache TTL. + */ + public int getCacheTTL() { + return cacheTTL; + } + + + /** + * Return the maximum size of the cache in KB. + */ + public int getCacheMaxSize() { + return cacheMaxSize; + } + + + /** + * Set the maximum size of the cache in KB. + */ + public void setCacheMaxSize(int cacheMaxSize) { + this.cacheMaxSize = cacheMaxSize; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Allocate resources for this directory context. + */ + public void allocate() { + ; // No action taken by the default implementation + } + + + /** + * Release any resources allocated for this directory context. + */ + public void release() { + ; // No action taken by the default implementation + } + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. If name is empty, returns a new instance + * of this context (which represents the same naming context as this + * context, but its environment may be modified independently and it may + * be accessed concurrently). + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(Name name) + throws NamingException { + return lookup(name.toString()); + } + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public abstract Object lookup(String name) + throws NamingException; + + + /** + * Binds a name to an object. All intermediate contexts and the target + * context (that named by all but terminal atomic component of the name) + * must already exist. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj) + throws NamingException { + bind(name.toString(), obj); + } + + + /** + * Binds a name to an object. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj) + throws NamingException { + bind(name, obj, null); + } + + + /** + * Binds a name to an object, overwriting any existing binding. All + * intermediate contexts and the target context (that named by all but + * terminal atomic component of the name) must already exist. + *

        + * If the object is a DirContext, any existing attributes associated with + * the name are replaced with those of the object. Otherwise, any + * existing attributes associated with the name remain unchanged. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj) + throws NamingException { + rebind(name.toString(), obj); + } + + + /** + * Binds a name to an object, overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj) + throws NamingException { + rebind(name, obj, null); + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(Name name) + throws NamingException { + unbind(name.toString()); + } + + + /** + * Unbinds the named object. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public abstract void unbind(String name) + throws NamingException; + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(Name oldName, Name newName) + throws NamingException { + rename(oldName.toString(), newName.toString()); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public abstract void rename(String oldName, String newName) + throws NamingException; + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(Name name) + throws NamingException { + return list(name.toString()); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration list(String name) + throws NamingException; + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(Name name) + throws NamingException { + return listBindings(name.toString()); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration listBindings(String name) + throws NamingException; + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(Name name) + throws NamingException { + destroySubcontext(name.toString()); + } + + + /** + * Destroys the named context and removes it from the namespace. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public abstract void destroySubcontext(String name) + throws NamingException; + + + /** + * Creates and binds a new context. Creates a new context with the given + * name and binds it in the target context (that named by all but + * terminal atomic component of the name). All intermediate contexts and + * the target context must already exist. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(Name name) + throws NamingException { + return createSubcontext(name.toString()); + } + + + /** + * Creates and binds a new context. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(String name) + throws NamingException { + return createSubcontext(name, null); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(Name name) + throws NamingException { + return lookupLink(name.toString()); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public abstract Object lookupLink(String name) + throws NamingException; + + + /** + * Retrieves the parser associated with the named context. In a + * federation of namespaces, different naming systems will parse names + * differently. This method allows an application to get a parser for + * parsing names into their atomic components using the naming convention + * of a particular naming system. Within any single naming system, + * NameParser objects returned by this method must be equal (using the + * equals() test). + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(Name name) + throws NamingException { + return new NameParserImpl(); + } + + + /** + * Retrieves the parser associated with the named context. + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(String name) + throws NamingException { + return new NameParserImpl(); + } + + + /** + * Composes the name of this context with a name relative to this context. + *

        + * Given a name (name) relative to this context, and the name (prefix) + * of this context relative to one of its ancestors, this method returns + * the composition of the two names using the syntax appropriate for the + * naming system(s) involved. That is, if name names an object relative + * to this context, the result is the name of the same object, but + * relative to the ancestor context. None of the names may be null. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public Name composeName(Name name, Name prefix) + throws NamingException { + prefix = (Name) prefix.clone(); + return prefix.addAll(name); + } + + + /** + * Composes the name of this context with a name relative to this context. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public String composeName(String name, String prefix) + throws NamingException { + return prefix + "/" + name; + } + + + /** + * Adds a new environment property to the environment of this context. If + * the property already exists, its value is overwritten. + * + * @param propName the name of the environment property to add; may not + * be null + * @param propVal the value of the property to add; may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + return env.put(propName, propVal); + } + + + /** + * Removes an environment property from the environment of this context. + * + * @param propName the name of the environment property to remove; + * may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object removeFromEnvironment(String propName) + throws NamingException { + return env.remove(propName); + } + + + /** + * Retrieves the environment in effect for this context. See class + * description for more details on environment properties. + * The caller should not make any changes to the object returned: their + * effect on the context is undefined. The environment of this context + * may be changed using addToEnvironment() and removeFromEnvironment(). + * + * @return the environment of this context; never null + * @exception NamingException if a naming exception is encountered + */ + public Hashtable getEnvironment() + throws NamingException { + return env; + } + + + /** + * Closes this context. This method releases this context's resources + * immediately, instead of waiting for them to be released automatically + * by the garbage collector. + * This method is idempotent: invoking it on a context that has already + * been closed has no effect. Invoking any other method on a closed + * context is not allowed, and results in undefined behaviour. + * + * @exception NamingException if a naming exception is encountered + */ + public void close() + throws NamingException { + env.clear(); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public abstract String getNameInNamespace() + throws NamingException; + + + // ----------------------------------------------------- DirContext Methods + + + /** + * Retrieves all of the attributes associated with a named object. + * + * @return the set of attributes associated with name. + * Returns an empty attribute set if name has no attributes; never null. + * @param name the name of the object from which to retrieve attributes + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(Name name) + throws NamingException { + return getAttributes(name.toString()); + } + + + /** + * Retrieves all of the attributes associated with a named object. + * + * @return the set of attributes associated with name + * @param name the name of the object from which to retrieve attributes + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(String name) + throws NamingException { + return getAttributes(name, null); + } + + + /** + * Retrieves selected attributes associated with a named object. + * See the class description regarding attribute models, attribute type + * names, and operational attributes. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(Name name, String[] attrIds) + throws NamingException { + return getAttributes(name.toString(), attrIds); + } + + + /** + * Retrieves selected attributes associated with a named object. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public abstract Attributes getAttributes(String name, String[] attrIds) + throws NamingException; + + + /** + * Modifies the attributes associated with a named object. The order of + * the modifications is not specified. Where possible, the modifications + * are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(Name name, int mod_op, Attributes attrs) + throws NamingException { + modifyAttributes(name.toString(), mod_op, attrs); + } + + + /** + * Modifies the attributes associated with a named object. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public abstract void modifyAttributes + (String name, int mod_op, Attributes attrs) + throws NamingException; + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. The modifications are performed in the + * order specified. Each modification specifies a modification operation + * code and an attribute on which to operate. Where possible, the + * modifications are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(Name name, ModificationItem[] mods) + throws NamingException { + modifyAttributes(name.toString(), mods); + } + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public abstract void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException; + + + /** + * Binds a name to an object, along with associated attributes. If attrs + * is null, the resulting binding will have the attributes associated + * with obj if obj is a DirContext, and no attributes otherwise. If attrs + * is non-null, the resulting binding will have attrs as its attributes; + * any attributes associated with obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj, Attributes attrs) + throws NamingException { + bind(name.toString(), obj, attrs); + } + + + /** + * Binds a name to an object, along with associated attributes. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public abstract void bind(String name, Object obj, Attributes attrs) + throws NamingException; + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. If attrs is null and obj is a + * DirContext, the attributes from obj are used. If attrs is null and obj + * is not a DirContext, any existing attributes associated with the object + * already bound in the directory remain unchanged. If attrs is non-null, + * any existing attributes associated with the object already bound in + * the directory are removed and attrs is associated with the named + * object. If obj is a DirContext and attrs is non-null, the attributes + * of obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj, Attributes attrs) + throws NamingException { + rebind(name.toString(), obj, attrs); + } + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public abstract void rebind(String name, Object obj, Attributes attrs) + throws NamingException; + + + /** + * Creates and binds a new context, along with associated attributes. + * This method creates a new subcontext with the given name, binds it in + * the target context (that named by all but terminal atomic component of + * the name), and associates the supplied attributes with the newly + * created object. All intermediate and target contexts must already + * exist. If attrs is null, this method is equivalent to + * Context.createSubcontext(). + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public DirContext createSubcontext(Name name, Attributes attrs) + throws NamingException { + return createSubcontext(name.toString(), attrs); + } + + + /** + * Creates and binds a new context, along with associated attributes. + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public abstract DirContext createSubcontext(String name, Attributes attrs) + throws NamingException; + + + /** + * Retrieves the schema associated with the named object. The schema + * describes rules regarding the structure of the namespace and the + * attributes stored within it. The schema specifies what types of + * objects can be added to the directory and where they can be added; + * what mandatory and optional attributes an object can have. The range + * of support for schemas is directory-specific. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchema(Name name) + throws NamingException { + return getSchema(name.toString()); + } + + + /** + * Retrieves the schema associated with the named object. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public abstract DirContext getSchema(String name) + throws NamingException; + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchemaClassDefinition(Name name) + throws NamingException { + return getSchemaClassDefinition(name.toString()); + } + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public abstract DirContext getSchemaClassDefinition(String name) + throws NamingException; + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. The search is + * performed using the default SearchControls settings. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + return search(name.toString(), matchingAttributes, attributesToReturn); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration search + (String name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException; + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. This method returns all the attributes of such objects. + * It is equivalent to supplying null as the atributesToReturn parameter + * to the method search(Name, Attributes, String[]). + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes) + throws NamingException { + return search(name.toString(), matchingAttributes); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration search + (String name, Attributes matchingAttributes) + throws NamingException; + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter specified + * is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search + (Name name, String filter, SearchControls cons) + throws NamingException { + return search(name.toString(), filter, cons); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter + * specified is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration search(String name, String filter, + SearchControls cons) + throws NamingException; + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException { + return search(name.toString(), filterExpr, filterArgs, cons); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public abstract NamingEnumeration search + (String name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException; + + + // ------------------------------------------------------ Protected Methods + + +} + diff --git a/java/org/apache/naming/resources/CacheEntry.java b/java/org/apache/naming/resources/CacheEntry.java index 429f9b3fd..5c4ad9c3b 100644 --- a/java/org/apache/naming/resources/CacheEntry.java +++ b/java/org/apache/naming/resources/CacheEntry.java @@ -1,67 +1,67 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import javax.naming.directory.DirContext; - -/** - * Implements a cache entry. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ -public class CacheEntry { - - - // ------------------------------------------------- Instance Variables - - - public long timestamp = -1; - public String name = null; - public ResourceAttributes attributes = null; - public Resource resource = null; - public DirContext context = null; - public boolean exists = true; - public long accessCount = 0; - public int size = 1; - - - // ----------------------------------------------------- Public Methods - - - public void recycle() { - timestamp = -1; - name = null; - attributes = null; - resource = null; - context = null; - exists = true; - accessCount = 0; - size = 1; - } - - - public String toString() { - return ("Cache entry: " + name + "\n" - + "Exists: " + exists + "\n" - + "Attributes: " + attributes + "\n" - + "Resource: " + resource + "\n" - + "Context: " + context); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import javax.naming.directory.DirContext; + +/** + * Implements a cache entry. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ +public class CacheEntry { + + + // ------------------------------------------------- Instance Variables + + + public long timestamp = -1; + public String name = null; + public ResourceAttributes attributes = null; + public Resource resource = null; + public DirContext context = null; + public boolean exists = true; + public long accessCount = 0; + public int size = 1; + + + // ----------------------------------------------------- Public Methods + + + public void recycle() { + timestamp = -1; + name = null; + attributes = null; + resource = null; + context = null; + exists = true; + accessCount = 0; + size = 1; + } + + + public String toString() { + return ("Cache entry: " + name + "\n" + + "Exists: " + exists + "\n" + + "Attributes: " + attributes + "\n" + + "Resource: " + resource + "\n" + + "Context: " + context); + } + + +} diff --git a/java/org/apache/naming/resources/Constants.java b/java/org/apache/naming/resources/Constants.java index 07e13f957..a505a2200 100644 --- a/java/org/apache/naming/resources/Constants.java +++ b/java/org/apache/naming/resources/Constants.java @@ -1,35 +1,35 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - - -/** - * Static constants for this package. - */ - -public final class Constants { - - public static final String PROTOCOL_HANDLER_VARIABLE = - "java.protocol.handler.pkgs"; - - public static final String Package = "org.apache.naming.resources"; - - // Default namespace name - public static final String DEFAULT_NAMESPACE = "DAV:"; - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + + +/** + * Static constants for this package. + */ + +public final class Constants { + + public static final String PROTOCOL_HANDLER_VARIABLE = + "java.protocol.handler.pkgs"; + + public static final String Package = "org.apache.naming.resources"; + + // Default namespace name + public static final String DEFAULT_NAMESPACE = "DAV:"; + +} diff --git a/java/org/apache/naming/resources/DirContextURLConnection.java b/java/org/apache/naming/resources/DirContextURLConnection.java index 698112f9d..773dc6b09 100644 --- a/java/org/apache/naming/resources/DirContextURLConnection.java +++ b/java/org/apache/naming/resources/DirContextURLConnection.java @@ -1,358 +1,358 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.net.URL; -import java.net.URLConnection; -import java.io.IOException; -import java.io.InputStream; -import java.io.FileNotFoundException; -import java.security.Permission; -import java.util.Date; -import java.util.Enumeration; -import java.util.Vector; -import javax.naming.NamingException; -import javax.naming.NamingEnumeration; -import javax.naming.NameClassPair; -import javax.naming.directory.DirContext; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import org.apache.naming.JndiPermission; -import org.apache.naming.resources.Resource; -import org.apache.naming.resources.ResourceAttributes; - -/** - * Connection to a JNDI directory context. - *

        - * Note: All the object attribute names are the WebDAV names, not the HTTP - * names, so this class overrides some methods from URLConnection to do the - * queries using the right names. Content handler is also not used; the - * content is directly returned. - * - * @author Remy Maucherat - * @version $Revision: 303022 $ - */ -public class DirContextURLConnection - extends URLConnection { - - - // ----------------------------------------------------------- Constructors - - - public DirContextURLConnection(DirContext context, URL url) { - super(url); - if (context == null) - throw new IllegalArgumentException - ("Directory context can't be null"); - if (System.getSecurityManager() != null) { - this.permission = new JndiPermission(url.toString()); - } - this.context = context; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Directory context. - */ - protected DirContext context; - - - /** - * Associated resource. - */ - protected Resource resource; - - - /** - * Associated DirContext. - */ - protected DirContext collection; - - - /** - * Other unknown object. - */ - protected Object object; - - - /** - * Attributes. - */ - protected Attributes attributes; - - - /** - * Date. - */ - protected long date; - - - /** - * Permission - */ - protected Permission permission; - - - // ------------------------------------------------------------- Properties - - - /** - * Connect to the DirContext, and retrive the bound object, as well as - * its attributes. If no object is bound with the name specified in the - * URL, then an IOException is thrown. - * - * @throws IOException Object not found - */ - public void connect() - throws IOException { - - if (!connected) { - - try { - date = System.currentTimeMillis(); - String path = getURL().getFile(); - if (context instanceof ProxyDirContext) { - ProxyDirContext proxyDirContext = - (ProxyDirContext) context; - String hostName = proxyDirContext.getHostName(); - String contextName = proxyDirContext.getContextName(); - if (hostName != null) { - if (!path.startsWith("/" + hostName + "/")) - return; - path = path.substring(hostName.length()+ 1); - } - if (contextName != null) { - if (!path.startsWith(contextName + "/")) { - return; - } else { - path = path.substring(contextName.length()); - } - } - } - object = context.lookup(path); - attributes = context.getAttributes(path); - if (object instanceof Resource) - resource = (Resource) object; - if (object instanceof DirContext) - collection = (DirContext) object; - } catch (NamingException e) { - // Object not found - } - - connected = true; - - } - - } - - - /** - * Return the content length value. - */ - public int getContentLength() { - return getHeaderFieldInt(ResourceAttributes.CONTENT_LENGTH, -1); - } - - - /** - * Return the content type value. - */ - public String getContentType() { - return getHeaderField(ResourceAttributes.CONTENT_TYPE); - } - - - /** - * Return the last modified date. - */ - public long getDate() { - return date; - } - - - /** - * Return the last modified date. - */ - public long getLastModified() { - - if (!connected) { - // Try to connect (silently) - try { - connect(); - } catch (IOException e) { - } - } - - if (attributes == null) - return 0; - - Attribute lastModified = - attributes.get(ResourceAttributes.LAST_MODIFIED); - if (lastModified != null) { - try { - Date lmDate = (Date) lastModified.get(); - return lmDate.getTime(); - } catch (Exception e) { - } - } - - return 0; - } - - - /** - * Returns the name of the specified header field. - */ - public String getHeaderField(String name) { - - if (!connected) { - // Try to connect (silently) - try { - connect(); - } catch (IOException e) { - } - } - - if (attributes == null) - return (null); - - Attribute attribute = attributes.get(name); - try { - return attribute.get().toString(); - } catch (Exception e) { - // Shouldn't happen, unless the attribute has no value - } - - return (null); - - } - - - /** - * Get object content. - */ - public Object getContent() - throws IOException { - - if (!connected) - connect(); - - if (resource != null) - return getInputStream(); - if (collection != null) - return collection; - if (object != null) - return object; - - throw new FileNotFoundException(); - - } - - - /** - * Get object content. - */ - public Object getContent(Class[] classes) - throws IOException { - - Object object = getContent(); - - for (int i = 0; i < classes.length; i++) { - if (classes[i].isInstance(object)) - return object; - } - - return null; - - } - - - /** - * Get input stream. - */ - public InputStream getInputStream() - throws IOException { - - if (!connected) - connect(); - - if (resource == null) { - throw new FileNotFoundException(); - } else { - // Reopen resource - try { - resource = (Resource) context.lookup(getURL().getFile()); - } catch (NamingException e) { - } - } - - return (resource.streamContent()); - - } - - - /** - * Get the Permission for this URL - */ - public Permission getPermission() { - - return permission; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * List children of this collection. The names given are relative to this - * URI's path. The full uri of the children is then : path + "/" + name. - */ - public Enumeration list() - throws IOException { - - if (!connected) { - connect(); - } - - if ((resource == null) && (collection == null)) { - throw new FileNotFoundException(); - } - - Vector result = new Vector(); - - if (collection != null) { - try { - NamingEnumeration enumeration = context.list(getURL().getFile()); - while (enumeration.hasMoreElements()) { - NameClassPair ncp = (NameClassPair) enumeration.nextElement(); - result.addElement(ncp.getName()); - } - } catch (NamingException e) { - // Unexpected exception - throw new FileNotFoundException(); - } - } - - return result.elements(); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.net.URL; +import java.net.URLConnection; +import java.io.IOException; +import java.io.InputStream; +import java.io.FileNotFoundException; +import java.security.Permission; +import java.util.Date; +import java.util.Enumeration; +import java.util.Vector; +import javax.naming.NamingException; +import javax.naming.NamingEnumeration; +import javax.naming.NameClassPair; +import javax.naming.directory.DirContext; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import org.apache.naming.JndiPermission; +import org.apache.naming.resources.Resource; +import org.apache.naming.resources.ResourceAttributes; + +/** + * Connection to a JNDI directory context. + *

        + * Note: All the object attribute names are the WebDAV names, not the HTTP + * names, so this class overrides some methods from URLConnection to do the + * queries using the right names. Content handler is also not used; the + * content is directly returned. + * + * @author Remy Maucherat + * @version $Revision: 303022 $ + */ +public class DirContextURLConnection + extends URLConnection { + + + // ----------------------------------------------------------- Constructors + + + public DirContextURLConnection(DirContext context, URL url) { + super(url); + if (context == null) + throw new IllegalArgumentException + ("Directory context can't be null"); + if (System.getSecurityManager() != null) { + this.permission = new JndiPermission(url.toString()); + } + this.context = context; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Directory context. + */ + protected DirContext context; + + + /** + * Associated resource. + */ + protected Resource resource; + + + /** + * Associated DirContext. + */ + protected DirContext collection; + + + /** + * Other unknown object. + */ + protected Object object; + + + /** + * Attributes. + */ + protected Attributes attributes; + + + /** + * Date. + */ + protected long date; + + + /** + * Permission + */ + protected Permission permission; + + + // ------------------------------------------------------------- Properties + + + /** + * Connect to the DirContext, and retrive the bound object, as well as + * its attributes. If no object is bound with the name specified in the + * URL, then an IOException is thrown. + * + * @throws IOException Object not found + */ + public void connect() + throws IOException { + + if (!connected) { + + try { + date = System.currentTimeMillis(); + String path = getURL().getFile(); + if (context instanceof ProxyDirContext) { + ProxyDirContext proxyDirContext = + (ProxyDirContext) context; + String hostName = proxyDirContext.getHostName(); + String contextName = proxyDirContext.getContextName(); + if (hostName != null) { + if (!path.startsWith("/" + hostName + "/")) + return; + path = path.substring(hostName.length()+ 1); + } + if (contextName != null) { + if (!path.startsWith(contextName + "/")) { + return; + } else { + path = path.substring(contextName.length()); + } + } + } + object = context.lookup(path); + attributes = context.getAttributes(path); + if (object instanceof Resource) + resource = (Resource) object; + if (object instanceof DirContext) + collection = (DirContext) object; + } catch (NamingException e) { + // Object not found + } + + connected = true; + + } + + } + + + /** + * Return the content length value. + */ + public int getContentLength() { + return getHeaderFieldInt(ResourceAttributes.CONTENT_LENGTH, -1); + } + + + /** + * Return the content type value. + */ + public String getContentType() { + return getHeaderField(ResourceAttributes.CONTENT_TYPE); + } + + + /** + * Return the last modified date. + */ + public long getDate() { + return date; + } + + + /** + * Return the last modified date. + */ + public long getLastModified() { + + if (!connected) { + // Try to connect (silently) + try { + connect(); + } catch (IOException e) { + } + } + + if (attributes == null) + return 0; + + Attribute lastModified = + attributes.get(ResourceAttributes.LAST_MODIFIED); + if (lastModified != null) { + try { + Date lmDate = (Date) lastModified.get(); + return lmDate.getTime(); + } catch (Exception e) { + } + } + + return 0; + } + + + /** + * Returns the name of the specified header field. + */ + public String getHeaderField(String name) { + + if (!connected) { + // Try to connect (silently) + try { + connect(); + } catch (IOException e) { + } + } + + if (attributes == null) + return (null); + + Attribute attribute = attributes.get(name); + try { + return attribute.get().toString(); + } catch (Exception e) { + // Shouldn't happen, unless the attribute has no value + } + + return (null); + + } + + + /** + * Get object content. + */ + public Object getContent() + throws IOException { + + if (!connected) + connect(); + + if (resource != null) + return getInputStream(); + if (collection != null) + return collection; + if (object != null) + return object; + + throw new FileNotFoundException(); + + } + + + /** + * Get object content. + */ + public Object getContent(Class[] classes) + throws IOException { + + Object object = getContent(); + + for (int i = 0; i < classes.length; i++) { + if (classes[i].isInstance(object)) + return object; + } + + return null; + + } + + + /** + * Get input stream. + */ + public InputStream getInputStream() + throws IOException { + + if (!connected) + connect(); + + if (resource == null) { + throw new FileNotFoundException(); + } else { + // Reopen resource + try { + resource = (Resource) context.lookup(getURL().getFile()); + } catch (NamingException e) { + } + } + + return (resource.streamContent()); + + } + + + /** + * Get the Permission for this URL + */ + public Permission getPermission() { + + return permission; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * List children of this collection. The names given are relative to this + * URI's path. The full uri of the children is then : path + "/" + name. + */ + public Enumeration list() + throws IOException { + + if (!connected) { + connect(); + } + + if ((resource == null) && (collection == null)) { + throw new FileNotFoundException(); + } + + Vector result = new Vector(); + + if (collection != null) { + try { + NamingEnumeration enumeration = context.list(getURL().getFile()); + while (enumeration.hasMoreElements()) { + NameClassPair ncp = (NameClassPair) enumeration.nextElement(); + result.addElement(ncp.getName()); + } + } catch (NamingException e) { + // Unexpected exception + throw new FileNotFoundException(); + } + } + + return result.elements(); + + } + + +} diff --git a/java/org/apache/naming/resources/DirContextURLStreamHandler.java b/java/org/apache/naming/resources/DirContextURLStreamHandler.java index 8a5117809..b5e8a00c5 100644 --- a/java/org/apache/naming/resources/DirContextURLStreamHandler.java +++ b/java/org/apache/naming/resources/DirContextURLStreamHandler.java @@ -1,261 +1,261 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.io.IOException; -import java.net.URL; -import java.net.URLConnection; -import java.net.URLStreamHandler; -import java.util.Hashtable; - -import javax.naming.directory.DirContext; - -/** - * Stream handler to a JNDI directory context. - * - * @author Remy Maucherat - * @version $Revision: 304080 $ - */ -public class DirContextURLStreamHandler - extends URLStreamHandler { - - - // ----------------------------------------------------------- Constructors - - - public DirContextURLStreamHandler() { - } - - - public DirContextURLStreamHandler(DirContext context) { - this.context = context; - } - - - // -------------------------------------------------------------- Variables - - - /** - * Bindings class loader - directory context. Keyed by CL id. - */ - private static Hashtable clBindings = new Hashtable(); - - - /** - * Bindings thread - directory context. Keyed by thread id. - */ - private static Hashtable threadBindings = new Hashtable(); - - - // ----------------------------------------------------- Instance Variables - - - /** - * Directory context. - */ - protected DirContext context = null; - - - // ------------------------------------------------------------- Properties - - - // ----------------------------------------------- URLStreamHandler Methods - - - /** - * Opens a connection to the object referenced by the URL - * argument. - */ - protected URLConnection openConnection(URL u) - throws IOException { - DirContext currentContext = this.context; - if (currentContext == null) - currentContext = get(); - return new DirContextURLConnection(currentContext, u); - } - - - // ------------------------------------------------------------ URL Methods - - - /** - * Override as part of the fix for 36534, to ensure toString is correct. - */ - protected String toExternalForm(URL u) { - // pre-compute length of StringBuffer - int len = u.getProtocol().length() + 1; - if (u.getPath() != null) { - len += u.getPath().length(); - } - if (u.getQuery() != null) { - len += 1 + u.getQuery().length(); - } - if (u.getRef() != null) - len += 1 + u.getRef().length(); - StringBuffer result = new StringBuffer(len); - result.append(u.getProtocol()); - result.append(":"); - if (u.getPath() != null) { - result.append(u.getPath()); - } - if (u.getQuery() != null) { - result.append('?'); - result.append(u.getQuery()); - } - if (u.getRef() != null) { - result.append("#"); - result.append(u.getRef()); - } - return result.toString(); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Set the java.protocol.handler.pkgs system property. - */ - public static void setProtocolHandler() { - String value = System.getProperty(Constants.PROTOCOL_HANDLER_VARIABLE); - if (value == null) { - value = Constants.Package; - System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); - } else if (value.indexOf(Constants.Package) == -1) { - value += "|" + Constants.Package; - System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); - } - } - - - /** - * Returns true if the thread or the context class loader of the current - * thread is bound. - */ - public static boolean isBound() { - return (clBindings.containsKey - (Thread.currentThread().getContextClassLoader())) - || (threadBindings.containsKey(Thread.currentThread())); - } - - - /** - * Binds a directory context to a class loader. - */ - public static void bind(DirContext dirContext) { - ClassLoader currentCL = - Thread.currentThread().getContextClassLoader(); - if (currentCL != null) - clBindings.put(currentCL, dirContext); - } - - - /** - * Unbinds a directory context to a class loader. - */ - public static void unbind() { - ClassLoader currentCL = - Thread.currentThread().getContextClassLoader(); - if (currentCL != null) - clBindings.remove(currentCL); - } - - - /** - * Binds a directory context to a thread. - */ - public static void bindThread(DirContext dirContext) { - threadBindings.put(Thread.currentThread(), dirContext); - } - - - /** - * Unbinds a directory context to a thread. - */ - public static void unbindThread() { - threadBindings.remove(Thread.currentThread()); - } - - - /** - * Get the bound context. - */ - public static DirContext get() { - - DirContext result = null; - - Thread currentThread = Thread.currentThread(); - ClassLoader currentCL = currentThread.getContextClassLoader(); - - // Checking CL binding - result = (DirContext) clBindings.get(currentCL); - if (result != null) - return result; - - // Checking thread biding - result = (DirContext) threadBindings.get(currentThread); - - // Checking parent CL binding - currentCL = currentCL.getParent(); - while (currentCL != null) { - result = (DirContext) clBindings.get(currentCL); - if (result != null) - return result; - currentCL = currentCL.getParent(); - } - - if (result == null) - throw new IllegalStateException("Illegal class loader binding"); - - return result; - - } - - - /** - * Binds a directory context to a class loader. - */ - public static void bind(ClassLoader cl, DirContext dirContext) { - clBindings.put(cl, dirContext); - } - - - /** - * Unbinds a directory context to a class loader. - */ - public static void unbind(ClassLoader cl) { - clBindings.remove(cl); - } - - - /** - * Get the bound context. - */ - public static DirContext get(ClassLoader cl) { - return (DirContext) clBindings.get(cl); - } - - - /** - * Get the bound context. - */ - public static DirContext get(Thread thread) { - return (DirContext) threadBindings.get(thread); - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.Hashtable; + +import javax.naming.directory.DirContext; + +/** + * Stream handler to a JNDI directory context. + * + * @author Remy Maucherat + * @version $Revision: 304080 $ + */ +public class DirContextURLStreamHandler + extends URLStreamHandler { + + + // ----------------------------------------------------------- Constructors + + + public DirContextURLStreamHandler() { + } + + + public DirContextURLStreamHandler(DirContext context) { + this.context = context; + } + + + // -------------------------------------------------------------- Variables + + + /** + * Bindings class loader - directory context. Keyed by CL id. + */ + private static Hashtable clBindings = new Hashtable(); + + + /** + * Bindings thread - directory context. Keyed by thread id. + */ + private static Hashtable threadBindings = new Hashtable(); + + + // ----------------------------------------------------- Instance Variables + + + /** + * Directory context. + */ + protected DirContext context = null; + + + // ------------------------------------------------------------- Properties + + + // ----------------------------------------------- URLStreamHandler Methods + + + /** + * Opens a connection to the object referenced by the URL + * argument. + */ + protected URLConnection openConnection(URL u) + throws IOException { + DirContext currentContext = this.context; + if (currentContext == null) + currentContext = get(); + return new DirContextURLConnection(currentContext, u); + } + + + // ------------------------------------------------------------ URL Methods + + + /** + * Override as part of the fix for 36534, to ensure toString is correct. + */ + protected String toExternalForm(URL u) { + // pre-compute length of StringBuffer + int len = u.getProtocol().length() + 1; + if (u.getPath() != null) { + len += u.getPath().length(); + } + if (u.getQuery() != null) { + len += 1 + u.getQuery().length(); + } + if (u.getRef() != null) + len += 1 + u.getRef().length(); + StringBuffer result = new StringBuffer(len); + result.append(u.getProtocol()); + result.append(":"); + if (u.getPath() != null) { + result.append(u.getPath()); + } + if (u.getQuery() != null) { + result.append('?'); + result.append(u.getQuery()); + } + if (u.getRef() != null) { + result.append("#"); + result.append(u.getRef()); + } + return result.toString(); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Set the java.protocol.handler.pkgs system property. + */ + public static void setProtocolHandler() { + String value = System.getProperty(Constants.PROTOCOL_HANDLER_VARIABLE); + if (value == null) { + value = Constants.Package; + System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); + } else if (value.indexOf(Constants.Package) == -1) { + value += "|" + Constants.Package; + System.setProperty(Constants.PROTOCOL_HANDLER_VARIABLE, value); + } + } + + + /** + * Returns true if the thread or the context class loader of the current + * thread is bound. + */ + public static boolean isBound() { + return (clBindings.containsKey + (Thread.currentThread().getContextClassLoader())) + || (threadBindings.containsKey(Thread.currentThread())); + } + + + /** + * Binds a directory context to a class loader. + */ + public static void bind(DirContext dirContext) { + ClassLoader currentCL = + Thread.currentThread().getContextClassLoader(); + if (currentCL != null) + clBindings.put(currentCL, dirContext); + } + + + /** + * Unbinds a directory context to a class loader. + */ + public static void unbind() { + ClassLoader currentCL = + Thread.currentThread().getContextClassLoader(); + if (currentCL != null) + clBindings.remove(currentCL); + } + + + /** + * Binds a directory context to a thread. + */ + public static void bindThread(DirContext dirContext) { + threadBindings.put(Thread.currentThread(), dirContext); + } + + + /** + * Unbinds a directory context to a thread. + */ + public static void unbindThread() { + threadBindings.remove(Thread.currentThread()); + } + + + /** + * Get the bound context. + */ + public static DirContext get() { + + DirContext result = null; + + Thread currentThread = Thread.currentThread(); + ClassLoader currentCL = currentThread.getContextClassLoader(); + + // Checking CL binding + result = (DirContext) clBindings.get(currentCL); + if (result != null) + return result; + + // Checking thread biding + result = (DirContext) threadBindings.get(currentThread); + + // Checking parent CL binding + currentCL = currentCL.getParent(); + while (currentCL != null) { + result = (DirContext) clBindings.get(currentCL); + if (result != null) + return result; + currentCL = currentCL.getParent(); + } + + if (result == null) + throw new IllegalStateException("Illegal class loader binding"); + + return result; + + } + + + /** + * Binds a directory context to a class loader. + */ + public static void bind(ClassLoader cl, DirContext dirContext) { + clBindings.put(cl, dirContext); + } + + + /** + * Unbinds a directory context to a class loader. + */ + public static void unbind(ClassLoader cl) { + clBindings.remove(cl); + } + + + /** + * Get the bound context. + */ + public static DirContext get(ClassLoader cl) { + return (DirContext) clBindings.get(cl); + } + + + /** + * Get the bound context. + */ + public static DirContext get(Thread thread) { + return (DirContext) threadBindings.get(thread); + } + + +} diff --git a/java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java b/java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java index 8095195d5..a7d8f8921 100644 --- a/java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java +++ b/java/org/apache/naming/resources/DirContextURLStreamHandlerFactory.java @@ -1,65 +1,65 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.net.URLStreamHandler; -import java.net.URLStreamHandlerFactory; - -/** - * Factory for Stream handlers to a JNDI directory context. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ -public class DirContextURLStreamHandlerFactory - implements URLStreamHandlerFactory { - - - // ----------------------------------------------------------- Constructors - - - public DirContextURLStreamHandlerFactory() { - } - - - // ----------------------------------------------------- Instance Variables - - - // ------------------------------------------------------------- Properties - - - // ---------------------------------------- URLStreamHandlerFactory Methods - - - /** - * Creates a new URLStreamHandler instance with the specified protocol. - * Will return null if the protocol is not jndi. - * - * @param protocol the protocol (must be "jndi" here) - * @return a URLStreamHandler for the jndi protocol, or null if the - * protocol is not JNDI - */ - public URLStreamHandler createURLStreamHandler(String protocol) { - if (protocol.equals("jndi")) { - return new DirContextURLStreamHandler(); - } else { - return null; - } - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.net.URLStreamHandler; +import java.net.URLStreamHandlerFactory; + +/** + * Factory for Stream handlers to a JNDI directory context. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ +public class DirContextURLStreamHandlerFactory + implements URLStreamHandlerFactory { + + + // ----------------------------------------------------------- Constructors + + + public DirContextURLStreamHandlerFactory() { + } + + + // ----------------------------------------------------- Instance Variables + + + // ------------------------------------------------------------- Properties + + + // ---------------------------------------- URLStreamHandlerFactory Methods + + + /** + * Creates a new URLStreamHandler instance with the specified protocol. + * Will return null if the protocol is not jndi. + * + * @param protocol the protocol (must be "jndi" here) + * @return a URLStreamHandler for the jndi protocol, or null if the + * protocol is not JNDI + */ + public URLStreamHandler createURLStreamHandler(String protocol) { + if (protocol.equals("jndi")) { + return new DirContextURLStreamHandler(); + } else { + return null; + } + } + + +} diff --git a/java/org/apache/naming/resources/FileDirContext.java b/java/org/apache/naming/resources/FileDirContext.java index de3ace950..4dd80ee9a 100644 --- a/java/org/apache/naming/resources/FileDirContext.java +++ b/java/org/apache/naming/resources/FileDirContext.java @@ -1,1129 +1,1129 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.Hashtable; - -import javax.naming.NameAlreadyBoundException; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.OperationNotSupportedException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; - -import org.apache.naming.NamingContextBindingsEnumeration; -import org.apache.naming.NamingContextEnumeration; -import org.apache.naming.NamingEntry; - -/** - * Filesystem Directory Context implementation helper class. - * - * @author Remy Maucherat - * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ - */ - -public class FileDirContext extends BaseDirContext { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( FileDirContext.class ); - - // -------------------------------------------------------------- Constants - - - /** - * The descriptive information string for this implementation. - */ - protected static final int BUFFER_SIZE = 2048; - - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a file directory context using the given environment. - */ - public FileDirContext() { - super(); - } - - - /** - * Builds a file directory context using the given environment. - */ - public FileDirContext(Hashtable env) { - super(env); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The document base directory. - */ - protected File base = null; - - - /** - * Absolute normalized filename of the base. - */ - protected String absoluteBase = null; - - - /** - * Case sensitivity. - */ - protected boolean caseSensitive = true; - - - /** - * Allow linking. - */ - protected boolean allowLinking = false; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the document root. - * - * @param docBase The new document root - * - * @exception IllegalArgumentException if the specified value is not - * supported by this implementation - * @exception IllegalArgumentException if this would create a - * malformed URL - */ - public void setDocBase(String docBase) { - - // Validate the format of the proposed document root - if (docBase == null) - throw new IllegalArgumentException - (sm.getString("resources.null")); - - // Calculate a File object referencing this document base directory - base = new File(docBase); - try { - base = base.getCanonicalFile(); - } catch (IOException e) { - // Ignore - } - - // Validate that the document base is an existing directory - if (!base.exists() || !base.isDirectory() || !base.canRead()) - throw new IllegalArgumentException - (sm.getString("fileResources.base", docBase)); - this.absoluteBase = base.getAbsolutePath(); - super.setDocBase(docBase); - - } - - - /** - * Set case sensitivity. - */ - public void setCaseSensitive(boolean caseSensitive) { - this.caseSensitive = caseSensitive; - } - - - /** - * Is case sensitive ? - */ - public boolean isCaseSensitive() { - return caseSensitive; - } - - - /** - * Set allow linking. - */ - public void setAllowLinking(boolean allowLinking) { - this.allowLinking = allowLinking; - } - - - /** - * Is linking allowed. - */ - public boolean getAllowLinking() { - return allowLinking; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Release any resources allocated for this directory context. - */ - public void release() { - super.release(); - } - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(String name) - throws NamingException { - Object result = null; - File file = file(name); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - if (file.isDirectory()) { - FileDirContext tempContext = new FileDirContext(env); - tempContext.setDocBase(file.getPath()); - tempContext.setAllowLinking(getAllowLinking()); - tempContext.setCaseSensitive(isCaseSensitive()); - result = tempContext; - } else { - result = new FileResource(file); - } - - return result; - - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(String name) - throws NamingException { - - File file = file(name); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - if (!file.delete()) - throw new NamingException - (sm.getString("resources.unbindFailed", name)); - - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(String oldName, String newName) - throws NamingException { - - File file = file(oldName); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", oldName)); - - File newFile = new File(base, newName); - - file.renameTo(newFile); - - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(String name) - throws NamingException { - - File file = file(name); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - return new NamingContextEnumeration(list(file).iterator()); - - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(String name) - throws NamingException { - - File file = file(name); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - return new NamingContextBindingsEnumeration(list(file).iterator(), - this); - - } - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(String name) - throws NamingException { - unbind(name); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(String name) - throws NamingException { - // Note : Links are not supported - return lookup(name); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public String getNameInNamespace() - throws NamingException { - return docBase; - } - - - // ----------------------------------------------------- DirContext Methods - - - /** - * Retrieves selected attributes associated with a named object. - * See the class description regarding attribute models, attribute type - * names, and operational attributes. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(String name, String[] attrIds) - throws NamingException { - - // Building attribute list - File file = file(name); - - if (file == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - return new FileResourceAttributes(file); - - } - - - /** - * Modifies the attributes associated with a named object. The order of - * the modifications is not specified. Where possible, the modifications - * are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, int mod_op, Attributes attrs) - throws NamingException { - - } - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. The modifications are performed in the - * order specified. Each modification specifies a modification operation - * code and an attribute on which to operate. Where possible, the - * modifications are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, ModificationItem[] mods) - throws NamingException { - - } - - - /** - * Binds a name to an object, along with associated attributes. If attrs - * is null, the resulting binding will have the attributes associated - * with obj if obj is a DirContext, and no attributes otherwise. If attrs - * is non-null, the resulting binding will have attrs as its attributes; - * any attributes associated with obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj, Attributes attrs) - throws NamingException { - - // Note: No custom attributes allowed - - File file = new File(base, name); - if (file.exists()) - throw new NameAlreadyBoundException - (sm.getString("resources.alreadyBound", name)); - - rebind(name, obj, attrs); - - } - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. If attrs is null and obj is a - * DirContext, the attributes from obj are used. If attrs is null and obj - * is not a DirContext, any existing attributes associated with the object - * already bound in the directory remain unchanged. If attrs is non-null, - * any existing attributes associated with the object already bound in - * the directory are removed and attrs is associated with the named - * object. If obj is a DirContext and attrs is non-null, the attributes - * of obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj, Attributes attrs) - throws NamingException { - - // Note: No custom attributes allowed - // Check obj type - - File file = new File(base, name); - - InputStream is = null; - if (obj instanceof Resource) { - try { - is = ((Resource) obj).streamContent(); - } catch (IOException e) { - } - } else if (obj instanceof InputStream) { - is = (InputStream) obj; - } else if (obj instanceof DirContext) { - if (file.exists()) { - if (!file.delete()) - throw new NamingException - (sm.getString("resources.bindFailed", name)); - } - if (!file.mkdir()) - throw new NamingException - (sm.getString("resources.bindFailed", name)); - } - if (is == null) - throw new NamingException - (sm.getString("resources.bindFailed", name)); - - // Open os - - try { - FileOutputStream os = null; - byte buffer[] = new byte[BUFFER_SIZE]; - int len = -1; - try { - os = new FileOutputStream(file); - while (true) { - len = is.read(buffer); - if (len == -1) - break; - os.write(buffer, 0, len); - } - } finally { - if (os != null) - os.close(); - is.close(); - } - } catch (IOException e) { - throw new NamingException - (sm.getString("resources.bindFailed", e)); - } - - } - - - /** - * Creates and binds a new context, along with associated attributes. - * This method creates a new subcontext with the given name, binds it in - * the target context (that named by all but terminal atomic component of - * the name), and associates the supplied attributes with the newly - * created object. All intermediate and target contexts must already - * exist. If attrs is null, this method is equivalent to - * Context.createSubcontext(). - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public DirContext createSubcontext(String name, Attributes attrs) - throws NamingException { - - File file = new File(base, name); - if (file.exists()) - throw new NameAlreadyBoundException - (sm.getString("resources.alreadyBound", name)); - if (!file.mkdir()) - throw new NamingException - (sm.getString("resources.bindFailed", name)); - return (DirContext) lookup(name); - - } - - - /** - * Retrieves the schema associated with the named object. The schema - * describes rules regarding the structure of the namespace and the - * attributes stored within it. The schema specifies what types of - * objects can be added to the directory and where they can be added; - * what mandatory and optional attributes an object can have. The range - * of support for schemas is directory-specific. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchema(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchemaClassDefinition(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. The search is - * performed using the default SearchControls settings. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException { - return null; - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. This method returns all the attributes of such objects. - * It is equivalent to supplying null as the atributesToReturn parameter - * to the method search(Name, Attributes, String[]). - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes) - throws NamingException { - return null; - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter specified - * is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filter, - SearchControls cons) - throws NamingException { - return null; - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException { - return null; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a context-relative path, beginning with a "/", that represents - * the canonical version of the specified path after ".." and "." elements - * are resolved out. If the specified path attempts to go outside the - * boundaries of the current context (i.e. too many ".." path elements - * are present), return null instead. - * - * @param path Path to be normalized - */ - protected String normalize(String path) { - - String normalized = path; - - // Normalize the slashes and add leading slash if necessary - if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - if (!normalized.startsWith("/")) - normalized = "/" + normalized; - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - return (null); // Trying to go outside our context - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Return the normalized path that we have completed - return (normalized); - - } - - - /** - * Return a File object representing the specified normalized - * context-relative path if it exists and is readable. Otherwise, - * return null. - * - * @param name Normalized context-relative path (with leading '/') - */ - protected File file(String name) { - - File file = new File(base, name); - if (file.exists() && file.canRead()) { - - if (allowLinking) - return file; - - // Check that this file belongs to our root path - String canPath = null; - try { - canPath = file.getCanonicalPath(); - } catch (IOException e) { - } - if (canPath == null) - return null; - - // Check to see if going outside of the web application root - if (!canPath.startsWith(absoluteBase)) { - return null; - } - - // Case sensitivity check - if (caseSensitive) { - String fileAbsPath = file.getAbsolutePath(); - if (fileAbsPath.endsWith(".")) - fileAbsPath = fileAbsPath + "/"; - String absPath = normalize(fileAbsPath); - if (canPath != null) - canPath = normalize(canPath); - if ((absoluteBase.length() < absPath.length()) - && (absoluteBase.length() < canPath.length())) { - absPath = absPath.substring(absoluteBase.length() + 1); - if ((canPath == null) || (absPath == null)) - return null; - if (absPath.equals("")) - absPath = "/"; - canPath = canPath.substring(absoluteBase.length() + 1); - if (canPath.equals("")) - canPath = "/"; - if (!canPath.equals(absPath)) - return null; - } - } - - } else { - return null; - } - return file; - - } - - - /** - * List the resources which are members of a collection. - * - * @param file Collection - * @return Vector containg NamingEntry objects - */ - protected ArrayList list(File file) { - - ArrayList entries = new ArrayList(); - if (!file.isDirectory()) - return entries; - String[] names = file.list(); - if (names==null) { - /* Some IO error occurred such as bad file permissions. - Prevent a NPE with Arrays.sort(names) */ - log.warn(sm.getString("fileResources.listingNull", - file.getAbsolutePath())); - return entries; - } - - Arrays.sort(names); // Sort alphabetically - if (names == null) - return entries; - NamingEntry entry = null; - - for (int i = 0; i < names.length; i++) { - - File currentFile = new File(file, names[i]); - Object object = null; - if (currentFile.isDirectory()) { - FileDirContext tempContext = new FileDirContext(env); - tempContext.setDocBase(file.getPath()); - tempContext.setAllowLinking(getAllowLinking()); - tempContext.setCaseSensitive(isCaseSensitive()); - object = tempContext; - } else { - object = new FileResource(currentFile); - } - entry = new NamingEntry(names[i], object, NamingEntry.ENTRY); - entries.add(entry); - - } - - return entries; - - } - - - // ----------------------------------------------- FileResource Inner Class - - - /** - * This specialized resource implementation avoids opening the IputStream - * to the file right away (which would put a lock on the file). - */ - protected class FileResource extends Resource { - - - // -------------------------------------------------------- Constructor - - - public FileResource(File file) { - this.file = file; - } - - - // --------------------------------------------------- Member Variables - - - /** - * Associated file object. - */ - protected File file; - - - /** - * File length. - */ - protected long length = -1L; - - - // --------------------------------------------------- Resource Methods - - - /** - * Content accessor. - * - * @return InputStream - */ - public InputStream streamContent() - throws IOException { - if (binaryContent == null) { - inputStream = new FileInputStream(file); - } - return super.streamContent(); - } - - - } - - - // ------------------------------------- FileResourceAttributes Inner Class - - - /** - * This specialized resource attribute implementation does some lazy - * reading (to speed up simple checks, like checking the last modified - * date). - */ - protected class FileResourceAttributes extends ResourceAttributes { - - - // -------------------------------------------------------- Constructor - - - public FileResourceAttributes(File file) { - this.file = file; - } - - // --------------------------------------------------- Member Variables - - - protected File file; - - - protected boolean accessed = false; - - - protected String canonicalPath = null; - - - // ----------------------------------------- ResourceAttributes Methods - - - /** - * Is collection. - */ - public boolean isCollection() { - if (!accessed) { - collection = file.isDirectory(); - accessed = true; - } - return super.isCollection(); - } - - - /** - * Get content length. - * - * @return content length value - */ - public long getContentLength() { - if (contentLength != -1L) - return contentLength; - contentLength = file.length(); - return contentLength; - } - - - /** - * Get creation time. - * - * @return creation time value - */ - public long getCreation() { - if (creation != -1L) - return creation; - creation = file.lastModified(); - return creation; - } - - - /** - * Get creation date. - * - * @return Creation date value - */ - public Date getCreationDate() { - if (creation == -1L) { - creation = file.lastModified(); - } - return super.getCreationDate(); - } - - - /** - * Get last modified time. - * - * @return lastModified time value - */ - public long getLastModified() { - if (lastModified != -1L) - return lastModified; - lastModified = file.lastModified(); - return lastModified; - } - - - /** - * Get lastModified date. - * - * @return LastModified date value - */ - public Date getLastModifiedDate() { - if (lastModified == -1L) { - lastModified = file.lastModified(); - } - return super.getLastModifiedDate(); - } - - - /** - * Get name. - * - * @return Name value - */ - public String getName() { - if (name == null) - name = file.getName(); - return name; - } - - - /** - * Get resource type. - * - * @return String resource type - */ - public String getResourceType() { - if (!accessed) { - collection = file.isDirectory(); - accessed = true; - } - return super.getResourceType(); - } - - - /** - * Get canonical path. - * - * @return String the file's canonical path - */ - public String getCanonicalPath() { - if (canonicalPath == null) { - try { - canonicalPath = file.getCanonicalPath(); - } catch (IOException e) { - // Ignore - } - } - return canonicalPath; - } - - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Hashtable; + +import javax.naming.NameAlreadyBoundException; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; + +import org.apache.naming.NamingContextBindingsEnumeration; +import org.apache.naming.NamingContextEnumeration; +import org.apache.naming.NamingEntry; + +/** + * Filesystem Directory Context implementation helper class. + * + * @author Remy Maucherat + * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ + */ + +public class FileDirContext extends BaseDirContext { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( FileDirContext.class ); + + // -------------------------------------------------------------- Constants + + + /** + * The descriptive information string for this implementation. + */ + protected static final int BUFFER_SIZE = 2048; + + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a file directory context using the given environment. + */ + public FileDirContext() { + super(); + } + + + /** + * Builds a file directory context using the given environment. + */ + public FileDirContext(Hashtable env) { + super(env); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The document base directory. + */ + protected File base = null; + + + /** + * Absolute normalized filename of the base. + */ + protected String absoluteBase = null; + + + /** + * Case sensitivity. + */ + protected boolean caseSensitive = true; + + + /** + * Allow linking. + */ + protected boolean allowLinking = false; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the document root. + * + * @param docBase The new document root + * + * @exception IllegalArgumentException if the specified value is not + * supported by this implementation + * @exception IllegalArgumentException if this would create a + * malformed URL + */ + public void setDocBase(String docBase) { + + // Validate the format of the proposed document root + if (docBase == null) + throw new IllegalArgumentException + (sm.getString("resources.null")); + + // Calculate a File object referencing this document base directory + base = new File(docBase); + try { + base = base.getCanonicalFile(); + } catch (IOException e) { + // Ignore + } + + // Validate that the document base is an existing directory + if (!base.exists() || !base.isDirectory() || !base.canRead()) + throw new IllegalArgumentException + (sm.getString("fileResources.base", docBase)); + this.absoluteBase = base.getAbsolutePath(); + super.setDocBase(docBase); + + } + + + /** + * Set case sensitivity. + */ + public void setCaseSensitive(boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + + /** + * Is case sensitive ? + */ + public boolean isCaseSensitive() { + return caseSensitive; + } + + + /** + * Set allow linking. + */ + public void setAllowLinking(boolean allowLinking) { + this.allowLinking = allowLinking; + } + + + /** + * Is linking allowed. + */ + public boolean getAllowLinking() { + return allowLinking; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Release any resources allocated for this directory context. + */ + public void release() { + super.release(); + } + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(String name) + throws NamingException { + Object result = null; + File file = file(name); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + if (file.isDirectory()) { + FileDirContext tempContext = new FileDirContext(env); + tempContext.setDocBase(file.getPath()); + tempContext.setAllowLinking(getAllowLinking()); + tempContext.setCaseSensitive(isCaseSensitive()); + result = tempContext; + } else { + result = new FileResource(file); + } + + return result; + + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(String name) + throws NamingException { + + File file = file(name); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + if (!file.delete()) + throw new NamingException + (sm.getString("resources.unbindFailed", name)); + + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(String oldName, String newName) + throws NamingException { + + File file = file(oldName); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", oldName)); + + File newFile = new File(base, newName); + + file.renameTo(newFile); + + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(String name) + throws NamingException { + + File file = file(name); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + return new NamingContextEnumeration(list(file).iterator()); + + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(String name) + throws NamingException { + + File file = file(name); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + return new NamingContextBindingsEnumeration(list(file).iterator(), + this); + + } + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(String name) + throws NamingException { + unbind(name); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(String name) + throws NamingException { + // Note : Links are not supported + return lookup(name); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public String getNameInNamespace() + throws NamingException { + return docBase; + } + + + // ----------------------------------------------------- DirContext Methods + + + /** + * Retrieves selected attributes associated with a named object. + * See the class description regarding attribute models, attribute type + * names, and operational attributes. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + + // Building attribute list + File file = file(name); + + if (file == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + return new FileResourceAttributes(file); + + } + + + /** + * Modifies the attributes associated with a named object. The order of + * the modifications is not specified. Where possible, the modifications + * are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, int mod_op, Attributes attrs) + throws NamingException { + + } + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. The modifications are performed in the + * order specified. Each modification specifies a modification operation + * code and an attribute on which to operate. Where possible, the + * modifications are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException { + + } + + + /** + * Binds a name to an object, along with associated attributes. If attrs + * is null, the resulting binding will have the attributes associated + * with obj if obj is a DirContext, and no attributes otherwise. If attrs + * is non-null, the resulting binding will have attrs as its attributes; + * any attributes associated with obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj, Attributes attrs) + throws NamingException { + + // Note: No custom attributes allowed + + File file = new File(base, name); + if (file.exists()) + throw new NameAlreadyBoundException + (sm.getString("resources.alreadyBound", name)); + + rebind(name, obj, attrs); + + } + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. If attrs is null and obj is a + * DirContext, the attributes from obj are used. If attrs is null and obj + * is not a DirContext, any existing attributes associated with the object + * already bound in the directory remain unchanged. If attrs is non-null, + * any existing attributes associated with the object already bound in + * the directory are removed and attrs is associated with the named + * object. If obj is a DirContext and attrs is non-null, the attributes + * of obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj, Attributes attrs) + throws NamingException { + + // Note: No custom attributes allowed + // Check obj type + + File file = new File(base, name); + + InputStream is = null; + if (obj instanceof Resource) { + try { + is = ((Resource) obj).streamContent(); + } catch (IOException e) { + } + } else if (obj instanceof InputStream) { + is = (InputStream) obj; + } else if (obj instanceof DirContext) { + if (file.exists()) { + if (!file.delete()) + throw new NamingException + (sm.getString("resources.bindFailed", name)); + } + if (!file.mkdir()) + throw new NamingException + (sm.getString("resources.bindFailed", name)); + } + if (is == null) + throw new NamingException + (sm.getString("resources.bindFailed", name)); + + // Open os + + try { + FileOutputStream os = null; + byte buffer[] = new byte[BUFFER_SIZE]; + int len = -1; + try { + os = new FileOutputStream(file); + while (true) { + len = is.read(buffer); + if (len == -1) + break; + os.write(buffer, 0, len); + } + } finally { + if (os != null) + os.close(); + is.close(); + } + } catch (IOException e) { + throw new NamingException + (sm.getString("resources.bindFailed", e)); + } + + } + + + /** + * Creates and binds a new context, along with associated attributes. + * This method creates a new subcontext with the given name, binds it in + * the target context (that named by all but terminal atomic component of + * the name), and associates the supplied attributes with the newly + * created object. All intermediate and target contexts must already + * exist. If attrs is null, this method is equivalent to + * Context.createSubcontext(). + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public DirContext createSubcontext(String name, Attributes attrs) + throws NamingException { + + File file = new File(base, name); + if (file.exists()) + throw new NameAlreadyBoundException + (sm.getString("resources.alreadyBound", name)); + if (!file.mkdir()) + throw new NamingException + (sm.getString("resources.bindFailed", name)); + return (DirContext) lookup(name); + + } + + + /** + * Retrieves the schema associated with the named object. The schema + * describes rules regarding the structure of the namespace and the + * attributes stored within it. The schema specifies what types of + * objects can be added to the directory and where they can be added; + * what mandatory and optional attributes an object can have. The range + * of support for schemas is directory-specific. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchema(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchemaClassDefinition(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. The search is + * performed using the default SearchControls settings. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + return null; + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. This method returns all the attributes of such objects. + * It is equivalent to supplying null as the atributesToReturn parameter + * to the method search(Name, Attributes, String[]). + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes) + throws NamingException { + return null; + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter specified + * is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filter, + SearchControls cons) + throws NamingException { + return null; + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException { + return null; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a context-relative path, beginning with a "/", that represents + * the canonical version of the specified path after ".." and "." elements + * are resolved out. If the specified path attempts to go outside the + * boundaries of the current context (i.e. too many ".." path elements + * are present), return null instead. + * + * @param path Path to be normalized + */ + protected String normalize(String path) { + + String normalized = path; + + // Normalize the slashes and add leading slash if necessary + if (File.separatorChar == '\\' && normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + return (null); // Trying to go outside our context + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Return the normalized path that we have completed + return (normalized); + + } + + + /** + * Return a File object representing the specified normalized + * context-relative path if it exists and is readable. Otherwise, + * return null. + * + * @param name Normalized context-relative path (with leading '/') + */ + protected File file(String name) { + + File file = new File(base, name); + if (file.exists() && file.canRead()) { + + if (allowLinking) + return file; + + // Check that this file belongs to our root path + String canPath = null; + try { + canPath = file.getCanonicalPath(); + } catch (IOException e) { + } + if (canPath == null) + return null; + + // Check to see if going outside of the web application root + if (!canPath.startsWith(absoluteBase)) { + return null; + } + + // Case sensitivity check + if (caseSensitive) { + String fileAbsPath = file.getAbsolutePath(); + if (fileAbsPath.endsWith(".")) + fileAbsPath = fileAbsPath + "/"; + String absPath = normalize(fileAbsPath); + if (canPath != null) + canPath = normalize(canPath); + if ((absoluteBase.length() < absPath.length()) + && (absoluteBase.length() < canPath.length())) { + absPath = absPath.substring(absoluteBase.length() + 1); + if ((canPath == null) || (absPath == null)) + return null; + if (absPath.equals("")) + absPath = "/"; + canPath = canPath.substring(absoluteBase.length() + 1); + if (canPath.equals("")) + canPath = "/"; + if (!canPath.equals(absPath)) + return null; + } + } + + } else { + return null; + } + return file; + + } + + + /** + * List the resources which are members of a collection. + * + * @param file Collection + * @return Vector containg NamingEntry objects + */ + protected ArrayList list(File file) { + + ArrayList entries = new ArrayList(); + if (!file.isDirectory()) + return entries; + String[] names = file.list(); + if (names==null) { + /* Some IO error occurred such as bad file permissions. + Prevent a NPE with Arrays.sort(names) */ + log.warn(sm.getString("fileResources.listingNull", + file.getAbsolutePath())); + return entries; + } + + Arrays.sort(names); // Sort alphabetically + if (names == null) + return entries; + NamingEntry entry = null; + + for (int i = 0; i < names.length; i++) { + + File currentFile = new File(file, names[i]); + Object object = null; + if (currentFile.isDirectory()) { + FileDirContext tempContext = new FileDirContext(env); + tempContext.setDocBase(file.getPath()); + tempContext.setAllowLinking(getAllowLinking()); + tempContext.setCaseSensitive(isCaseSensitive()); + object = tempContext; + } else { + object = new FileResource(currentFile); + } + entry = new NamingEntry(names[i], object, NamingEntry.ENTRY); + entries.add(entry); + + } + + return entries; + + } + + + // ----------------------------------------------- FileResource Inner Class + + + /** + * This specialized resource implementation avoids opening the IputStream + * to the file right away (which would put a lock on the file). + */ + protected class FileResource extends Resource { + + + // -------------------------------------------------------- Constructor + + + public FileResource(File file) { + this.file = file; + } + + + // --------------------------------------------------- Member Variables + + + /** + * Associated file object. + */ + protected File file; + + + /** + * File length. + */ + protected long length = -1L; + + + // --------------------------------------------------- Resource Methods + + + /** + * Content accessor. + * + * @return InputStream + */ + public InputStream streamContent() + throws IOException { + if (binaryContent == null) { + inputStream = new FileInputStream(file); + } + return super.streamContent(); + } + + + } + + + // ------------------------------------- FileResourceAttributes Inner Class + + + /** + * This specialized resource attribute implementation does some lazy + * reading (to speed up simple checks, like checking the last modified + * date). + */ + protected class FileResourceAttributes extends ResourceAttributes { + + + // -------------------------------------------------------- Constructor + + + public FileResourceAttributes(File file) { + this.file = file; + } + + // --------------------------------------------------- Member Variables + + + protected File file; + + + protected boolean accessed = false; + + + protected String canonicalPath = null; + + + // ----------------------------------------- ResourceAttributes Methods + + + /** + * Is collection. + */ + public boolean isCollection() { + if (!accessed) { + collection = file.isDirectory(); + accessed = true; + } + return super.isCollection(); + } + + + /** + * Get content length. + * + * @return content length value + */ + public long getContentLength() { + if (contentLength != -1L) + return contentLength; + contentLength = file.length(); + return contentLength; + } + + + /** + * Get creation time. + * + * @return creation time value + */ + public long getCreation() { + if (creation != -1L) + return creation; + creation = file.lastModified(); + return creation; + } + + + /** + * Get creation date. + * + * @return Creation date value + */ + public Date getCreationDate() { + if (creation == -1L) { + creation = file.lastModified(); + } + return super.getCreationDate(); + } + + + /** + * Get last modified time. + * + * @return lastModified time value + */ + public long getLastModified() { + if (lastModified != -1L) + return lastModified; + lastModified = file.lastModified(); + return lastModified; + } + + + /** + * Get lastModified date. + * + * @return LastModified date value + */ + public Date getLastModifiedDate() { + if (lastModified == -1L) { + lastModified = file.lastModified(); + } + return super.getLastModifiedDate(); + } + + + /** + * Get name. + * + * @return Name value + */ + public String getName() { + if (name == null) + name = file.getName(); + return name; + } + + + /** + * Get resource type. + * + * @return String resource type + */ + public String getResourceType() { + if (!accessed) { + collection = file.isDirectory(); + accessed = true; + } + return super.getResourceType(); + } + + + /** + * Get canonical path. + * + * @return String the file's canonical path + */ + public String getCanonicalPath() { + if (canonicalPath == null) { + try { + canonicalPath = file.getCanonicalPath(); + } catch (IOException e) { + // Ignore + } + } + return canonicalPath; + } + + + } + + +} + diff --git a/java/org/apache/naming/resources/ImmutableNameNotFoundException.java b/java/org/apache/naming/resources/ImmutableNameNotFoundException.java index 8092f9ba3..6d66f36c5 100644 --- a/java/org/apache/naming/resources/ImmutableNameNotFoundException.java +++ b/java/org/apache/naming/resources/ImmutableNameNotFoundException.java @@ -1,39 +1,39 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import javax.naming.Name; -import javax.naming.NameNotFoundException; - -/** - * Immutable exception to avoid useless object creation by the proxy context. - * This should be used only by the proxy context. Actual contexts should return - * properly populated exceptions. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ -public class ImmutableNameNotFoundException - extends NameNotFoundException { - - public void appendRemainingComponent(String name) {} - public void appendRemainingName(Name name) {} - public void setRemainingName(Name name) {} - public void setResolverName(Name name) {} - public void setRootCause(Throwable e) {} - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import javax.naming.Name; +import javax.naming.NameNotFoundException; + +/** + * Immutable exception to avoid useless object creation by the proxy context. + * This should be used only by the proxy context. Actual contexts should return + * properly populated exceptions. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ +public class ImmutableNameNotFoundException + extends NameNotFoundException { + + public void appendRemainingComponent(String name) {} + public void appendRemainingName(Name name) {} + public void setRemainingName(Name name) {} + public void setResolverName(Name name) {} + public void setRootCause(Throwable e) {} + +} diff --git a/java/org/apache/naming/resources/LocalStrings.properties b/java/org/apache/naming/resources/LocalStrings.properties index b4eaa0150..36aa5f8f6 100644 --- a/java/org/apache/naming/resources/LocalStrings.properties +++ b/java/org/apache/naming/resources/LocalStrings.properties @@ -1,21 +1,21 @@ -fileResources.base=Document base {0} does not exist or is not a readable directory -fileResources.listingNull=Could not get dir listing for {0} -warResources.notWar=Doc base must point to a WAR file -warResources.invalidWar=Invalid or unreadable WAR file : {0} -jarResources.syntax=Document base {0} must start with ''jar:'' and end with ''!/'' -resources.alreadyStarted=Resources has already been started -resources.connect=Cannot connect to document base {0} -resources.input=Cannot create input stream for resource {0} -resources.notStarted=Resources has not yet been started -resources.null=Document base cannot be null -resources.notFound=Resource {0} not found -resources.path=Context relative path {0} must start with ''/'' -resources.alreadyBound=Name {0} is already bound in this Context -resources.bindFailed=Bind failed: {0} -resources.unbindFailed=Unbind failed: {0} -standardResources.alreadyStarted=Resources has already been started -standardResources.directory=File base {0} is not a directory -standardResources.exists=File base {0} does not exist -standardResources.notStarted=Resources has not yet been started -standardResources.null=Document base cannot be null -standardResources.slash=Document base {0} must not end with a slash +fileResources.base=Document base {0} does not exist or is not a readable directory +fileResources.listingNull=Could not get dir listing for {0} +warResources.notWar=Doc base must point to a WAR file +warResources.invalidWar=Invalid or unreadable WAR file : {0} +jarResources.syntax=Document base {0} must start with ''jar:'' and end with ''!/'' +resources.alreadyStarted=Resources has already been started +resources.connect=Cannot connect to document base {0} +resources.input=Cannot create input stream for resource {0} +resources.notStarted=Resources has not yet been started +resources.null=Document base cannot be null +resources.notFound=Resource {0} not found +resources.path=Context relative path {0} must start with ''/'' +resources.alreadyBound=Name {0} is already bound in this Context +resources.bindFailed=Bind failed: {0} +resources.unbindFailed=Unbind failed: {0} +standardResources.alreadyStarted=Resources has already been started +standardResources.directory=File base {0} is not a directory +standardResources.exists=File base {0} does not exist +standardResources.notStarted=Resources has not yet been started +standardResources.null=Document base cannot be null +standardResources.slash=Document base {0} must not end with a slash diff --git a/java/org/apache/naming/resources/LocalStrings_es.properties b/java/org/apache/naming/resources/LocalStrings_es.properties index df1c691f9..4e4aa3c78 100644 --- a/java/org/apache/naming/resources/LocalStrings_es.properties +++ b/java/org/apache/naming/resources/LocalStrings_es.properties @@ -1,20 +1,20 @@ -fileResources.base=El Documento base {0} no existe o no es un directorio legible -warResources.notWar=Doc base debe de apuntar a un archivo WAR -warResources.invalidWar=Archivo WAR inválido o ilegible: {0} -jarResources.syntax=Documento base {0} debe de empezar con ''jar:'' y acabar con ''!/'' -resources.alreadyStarted=Ya han sido arrancados los Recursos -resources.connect=No puedo conectar a documento base {0} -resources.input=No puedo crear flujo (stream) de entrada para recurso {0} -resources.notStarted=Aún no han sido arrancados los Recursos -resources.null=El Documento base no puede ser nulo -resources.notFound=Recurso {0} no hallado -resources.path=Trayectoria relativa a contexto {0} debe de comenzar con ''/'' -resources.alreadyBound=El Nombre {0} ya ha sido cambiado (bound) en este Contexto -resources.bindFailed=Falló el Cambio (Bind): {0} -resources.unbindFailed=Falló el Descambio (Unbind): {0} -standardResources.alreadyStarted=Ya han sido arrancados los Recursos -standardResources.directory=El archivo base {0} no es un directorio -standardResources.exists=El archivo base {0} no existe -standardResources.notStarted=Aún no han sido arrancados los Recursos -standardResources.null=El Documento base no puede ser nulo -standardResources.slash=El Documento base {0} no debe de terminar con una barra +fileResources.base=El Documento base {0} no existe o no es un directorio legible +warResources.notWar=Doc base debe de apuntar a un archivo WAR +warResources.invalidWar=Archivo WAR inválido o ilegible: {0} +jarResources.syntax=Documento base {0} debe de empezar con ''jar:'' y acabar con ''!/'' +resources.alreadyStarted=Ya han sido arrancados los Recursos +resources.connect=No puedo conectar a documento base {0} +resources.input=No puedo crear flujo (stream) de entrada para recurso {0} +resources.notStarted=Aún no han sido arrancados los Recursos +resources.null=El Documento base no puede ser nulo +resources.notFound=Recurso {0} no hallado +resources.path=Trayectoria relativa a contexto {0} debe de comenzar con ''/'' +resources.alreadyBound=El Nombre {0} ya ha sido cambiado (bound) en este Contexto +resources.bindFailed=Falló el Cambio (Bind): {0} +resources.unbindFailed=Falló el Descambio (Unbind): {0} +standardResources.alreadyStarted=Ya han sido arrancados los Recursos +standardResources.directory=El archivo base {0} no es un directorio +standardResources.exists=El archivo base {0} no existe +standardResources.notStarted=Aún no han sido arrancados los Recursos +standardResources.null=El Documento base no puede ser nulo +standardResources.slash=El Documento base {0} no debe de terminar con una barra diff --git a/java/org/apache/naming/resources/LocalStrings_fr.properties b/java/org/apache/naming/resources/LocalStrings_fr.properties index 7c49cd228..06ee0646e 100644 --- a/java/org/apache/naming/resources/LocalStrings_fr.properties +++ b/java/org/apache/naming/resources/LocalStrings_fr.properties @@ -1,20 +1,20 @@ -fileResources.base=Le document base {0} n''existe pas ou n''est pas un répertoire lisible -warResources.notWar=Doc base doit pointé vers un fichier WAR -warResources.invalidWar=Fichier WAR invalide ou illisible : {0} -jarResources.syntax=Le document base {0} doit commencé par ''jar:'' et finir avec ''!/'' -resources.alreadyStarted=Les Ressources ont déjà été démarrées -resources.connect=Impossible de se connecter au document base {0} -resources.input=Impossible de créer l''input stream pour la ressource {0} -resources.notStarted=Les ressources n''ont pas encore été démarrées -resources.null=Le document base ne peut être nul -resources.notFound=La ressource {0} est introuvable -resources.path=Le chemin relatif de context {0} doit commencé par ''/'' -resources.alreadyBound=Le nom {0} est déjà référencé par ce contexte -resources.bindFailed=Le liage a échoué: {0} -resources.unbindFailed=Le déliage a échoué: {0} -standardResources.alreadyStarted=Les ressources ont déja été démarrées -standardResources.directory=Le file base {0} n''est pas un répertoire -standardResources.exists=Le file base {0} n''existe pas -standardResources.notStarted=Les ressources n''ont pas encore été démarrées -standardResources.null=Le document base ne peut être nul -standardResources.slash=Le document base {0} ne doit pas se terminer par un ''/'' +fileResources.base=Le document base {0} n''existe pas ou n''est pas un répertoire lisible +warResources.notWar=Doc base doit pointé vers un fichier WAR +warResources.invalidWar=Fichier WAR invalide ou illisible : {0} +jarResources.syntax=Le document base {0} doit commencé par ''jar:'' et finir avec ''!/'' +resources.alreadyStarted=Les Ressources ont déjà été démarrées +resources.connect=Impossible de se connecter au document base {0} +resources.input=Impossible de créer l''input stream pour la ressource {0} +resources.notStarted=Les ressources n''ont pas encore été démarrées +resources.null=Le document base ne peut être nul +resources.notFound=La ressource {0} est introuvable +resources.path=Le chemin relatif de context {0} doit commencé par ''/'' +resources.alreadyBound=Le nom {0} est déjà référencé par ce contexte +resources.bindFailed=Le liage a échoué: {0} +resources.unbindFailed=Le déliage a échoué: {0} +standardResources.alreadyStarted=Les ressources ont déja été démarrées +standardResources.directory=Le file base {0} n''est pas un répertoire +standardResources.exists=Le file base {0} n''existe pas +standardResources.notStarted=Les ressources n''ont pas encore été démarrées +standardResources.null=Le document base ne peut être nul +standardResources.slash=Le document base {0} ne doit pas se terminer par un ''/'' diff --git a/java/org/apache/naming/resources/LocalStrings_ja.properties b/java/org/apache/naming/resources/LocalStrings_ja.properties index f5496286e..a9914553a 100644 --- a/java/org/apache/naming/resources/LocalStrings_ja.properties +++ b/java/org/apache/naming/resources/LocalStrings_ja.properties @@ -1,21 +1,21 @@ -fileResources.base=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u304c\u5b58\u5728\u3057\u306a\u3044\u3001\u53c8\u306f\u8aad\u3081\u306a\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u3059 -fileResources.listingNull={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 -warResources.notWar=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u793a\u3055\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -warResources.invalidWar=\u7121\u52b9\u53c8\u306f\u8aad\u3081\u306a\u3044WAR\u30d5\u30a1\u30a4\u30eb\u3067\u3059 : {0} -jarResources.syntax=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f''jar:''\u3067\u59cb\u307e\u308a\u3001''!/''\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -resources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -resources.connect=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093 -resources.input=\u30ea\u30bd\u30fc\u30b9 {0} \u306b\u5165\u529b\u30b9\u30c8\u30ea\u30fc\u30e0\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 -resources.notStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -resources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -resources.notFound=\u30ea\u30bd\u30fc\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 -resources.path=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u76f8\u5bfe\u30d1\u30b9 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 -resources.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 -resources.bindFailed=\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} -resources.unbindFailed=\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} -standardResources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 -standardResources.directory=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u306f\u3042\u308a\u307e\u305b\u3093 -standardResources.exists=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 -standardResources.notStarted=\u30ea\u30bd\u30fc\u30b9\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 -standardResources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 -standardResources.slash=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f\u30b9\u30e9\u30c3\u30b7\u30e5\u3067\u7d42\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +fileResources.base=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u304c\u5b58\u5728\u3057\u306a\u3044\u3001\u53c8\u306f\u8aad\u3081\u306a\u3044\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u3059 +fileResources.listingNull={0} \u306e\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u306e\u30ea\u30b9\u30c8\u3092\u53d6\u5f97\u3067\u304d\u307e\u305b\u3093 +warResources.notWar=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fWAR\u30d5\u30a1\u30a4\u30eb\u3092\u793a\u3055\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +warResources.invalidWar=\u7121\u52b9\u53c8\u306f\u8aad\u3081\u306a\u3044WAR\u30d5\u30a1\u30a4\u30eb\u3067\u3059 : {0} +jarResources.syntax=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f''jar:''\u3067\u59cb\u307e\u308a\u3001''!/''\u3067\u7d42\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +resources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +resources.connect=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306b\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093 +resources.input=\u30ea\u30bd\u30fc\u30b9 {0} \u306b\u5165\u529b\u30b9\u30c8\u30ea\u30fc\u30e0\u3092\u4f5c\u6210\u3067\u304d\u307e\u305b\u3093 +resources.notStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +resources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +resources.notFound=\u30ea\u30bd\u30fc\u30b9 {0} \u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093 +resources.path=\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u76f8\u5bfe\u30d1\u30b9 {0} \u306f''/''\u3067\u59cb\u307e\u3089\u306a\u3051\u308c\u3070\u3044\u3051\u307e\u305b\u3093 +resources.alreadyBound=\u540d\u524d {0} \u306f\u65e2\u306b\u3053\u306e\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306b\u30d0\u30a4\u30f3\u30c9\u3055\u308c\u3066\u3044\u307e\u3059 +resources.bindFailed=\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} +resources.unbindFailed=\u30a2\u30f3\u30d0\u30a4\u30f3\u30c9\u304c\u5931\u6557\u3057\u307e\u3057\u305f: {0} +standardResources.alreadyStarted=\u30ea\u30bd\u30fc\u30b9\u306f\u65e2\u306b\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u3059 +standardResources.directory=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u3067\u306f\u3042\u308a\u307e\u305b\u3093 +standardResources.exists=\u30d5\u30a1\u30a4\u30eb\u30d9\u30fc\u30b9 {0} \u306f\u5b58\u5728\u3057\u307e\u305b\u3093 +standardResources.notStarted=\u30ea\u30bd\u30fc\u30b9\u304c\u307e\u3060\u8d77\u52d5\u3055\u308c\u3066\u3044\u307e\u305b\u3093 +standardResources.null=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9\u306fnull\u3067\u3042\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 +standardResources.slash=\u30c9\u30ad\u30e5\u30e1\u30f3\u30c8\u30d9\u30fc\u30b9 {0} \u306f\u30b9\u30e9\u30c3\u30b7\u30e5\u3067\u7d42\u3063\u3066\u306f\u3044\u3051\u307e\u305b\u3093 diff --git a/java/org/apache/naming/resources/ProxyDirContext.java b/java/org/apache/naming/resources/ProxyDirContext.java index 1a2ecdff4..d501afbfa 100644 --- a/java/org/apache/naming/resources/ProxyDirContext.java +++ b/java/org/apache/naming/resources/ProxyDirContext.java @@ -1,1620 +1,1620 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - -import java.io.ByteArrayInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Hashtable; - -import javax.naming.Context; -import javax.naming.Name; -import javax.naming.NameNotFoundException; -import javax.naming.NameParser; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; - -import org.apache.naming.StringManager; - -/** - * Proxy Directory Context implementation. - * - * @author Remy Maucherat - * @version $Revision: 304085 $ $Date: 2005-09-12 12:57:46 +0200 (lun., 12 sept. 2005) $ - */ - -public class ProxyDirContext implements DirContext { - - - // -------------------------------------------------------------- Constants - - - public static final String CONTEXT = "context"; - public static final String HOST = "host"; - - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a proxy directory context using the given environment. - */ - public ProxyDirContext(Hashtable env, DirContext dirContext) { - this.env = env; - this.dirContext = dirContext; - if (dirContext instanceof BaseDirContext) { - // Initialize parameters based on the associated dir context, like - // the caching policy. - BaseDirContext baseDirContext = (BaseDirContext) dirContext; - if (baseDirContext.isCached()) { - try { - cache = (ResourceCache) - Class.forName(cacheClassName).newInstance(); - } catch (Exception e) { - //FIXME - e.printStackTrace(); - } - cache.setCacheMaxSize(baseDirContext.getCacheMaxSize()); - cacheTTL = baseDirContext.getCacheTTL(); - cacheObjectMaxSize = baseDirContext.getCacheMaxSize() / 20; - } - } - hostName = (String) env.get(HOST); - contextName = (String) env.get(CONTEXT); - } - - - /** - * Builds a clone of this proxy dir context, wrapping the given directory - * context, and sharing the same cache. - */ - // TODO: Refactor using the proxy field - /* - protected ProxyDirContext(ProxyDirContext proxyDirContext, - DirContext dirContext, String vPath) { - this.env = proxyDirContext.env; - this.dirContext = dirContext; - this.vPath = vPath; - this.cache = proxyDirContext.cache; - this.cacheMaxSize = proxyDirContext.cacheMaxSize; - this.cacheSize = proxyDirContext.cacheSize; - this.cacheTTL = proxyDirContext.cacheTTL; - this.cacheObjectMaxSize = proxyDirContext.cacheObjectMaxSize; - this.notFoundCache = proxyDirContext.notFoundCache; - this.hostName = proxyDirContext.hostName; - this.contextName = proxyDirContext.contextName; - } - */ - - - // ----------------------------------------------------- Instance Variables - - - /** - * Proxy DirContext (either this or the real proxy). - */ - protected ProxyDirContext proxy = this; - - - /** - * Environment. - */ - protected Hashtable env; - - - /** - * The string manager for this package. - */ - protected StringManager sm = StringManager.getManager(Constants.Package); - - - /** - * Associated DirContext. - */ - protected DirContext dirContext; - - - /** - * Virtual path. - */ - protected String vPath = null; - - - /** - * Host name. - */ - protected String hostName; - - - /** - * Context name. - */ - protected String contextName; - - - /** - * Cache class. - */ - protected String cacheClassName = - "org.apache.naming.resources.ResourceCache"; - - - /** - * Cache. - */ - protected ResourceCache cache = null; - - - /** - * Cache TTL. - */ - protected int cacheTTL = 5000; // 5s - - - /** - * Max size of resources which will have their content cached. - */ - protected int cacheObjectMaxSize = 512; // 512 KB - - - /** - * Immutable name not found exception. - */ - protected NameNotFoundException notFoundException = - new ImmutableNameNotFoundException(); - - - /** - * Non cacheable resources. - */ - protected String[] nonCacheable = { "/WEB-INF/lib/", "/WEB-INF/classes/" }; - - - // --------------------------------------------------------- Public Methods - - - /** - * Get the cache used for this context. - */ - public ResourceCache getCache() { - return cache; - } - - - /** - * Return the actual directory context we are wrapping. - */ - public DirContext getDirContext() { - return this.dirContext; - } - - - /** - * Return the document root for this component. - */ - public String getDocBase() { - if (dirContext instanceof BaseDirContext) - return ((BaseDirContext) dirContext).getDocBase(); - else - return ""; - } - - - /** - * Return the host name. - */ - public String getHostName() { - return this.hostName; - } - - - /** - * Return the context name. - */ - public String getContextName() { - return this.contextName; - } - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. If name is empty, returns a new instance - * of this context (which represents the same naming context as this - * context, but its environment may be modified independently and it may - * be accessed concurrently). - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(Name name) - throws NamingException { - CacheEntry entry = cacheLookup(name.toString()); - if (entry != null) { - if (!entry.exists) { - throw notFoundException; - } - if (entry.resource != null) { - // Check content caching. - return entry.resource; - } else { - return entry.context; - } - } - Object object = dirContext.lookup(parseName(name)); - if (object instanceof InputStream) - return new Resource((InputStream) object); - else - return object; - } - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(String name) - throws NamingException { - CacheEntry entry = cacheLookup(name); - if (entry != null) { - if (!entry.exists) { - throw notFoundException; - } - if (entry.resource != null) { - return entry.resource; - } else { - return entry.context; - } - } - Object object = dirContext.lookup(parseName(name)); - if (object instanceof InputStream) { - return new Resource((InputStream) object); - } else if (object instanceof DirContext) { - return object; - } else if (object instanceof Resource) { - return object; - } else { - return new Resource(new ByteArrayInputStream - (object.toString().getBytes())); - } - } - - - /** - * Binds a name to an object. All intermediate contexts and the target - * context (that named by all but terminal atomic component of the name) - * must already exist. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj) - throws NamingException { - dirContext.bind(parseName(name), obj); - cacheUnload(name.toString()); - } - - - /** - * Binds a name to an object. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj) - throws NamingException { - dirContext.bind(parseName(name), obj); - cacheUnload(name); - } - - - /** - * Binds a name to an object, overwriting any existing binding. All - * intermediate contexts and the target context (that named by all but - * terminal atomic component of the name) must already exist. - *

        - * If the object is a DirContext, any existing attributes associated with - * the name are replaced with those of the object. Otherwise, any - * existing attributes associated with the name remain unchanged. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj) - throws NamingException { - dirContext.rebind(parseName(name), obj); - cacheUnload(name.toString()); - } - - - /** - * Binds a name to an object, overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @exception InvalidAttributesException if object did not supply all - * mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj) - throws NamingException { - dirContext.rebind(parseName(name), obj); - cacheUnload(name); - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(Name name) - throws NamingException { - dirContext.unbind(parseName(name)); - cacheUnload(name.toString()); - } - - - /** - * Unbinds the named object. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(String name) - throws NamingException { - dirContext.unbind(parseName(name)); - cacheUnload(name); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(Name oldName, Name newName) - throws NamingException { - dirContext.rename(parseName(oldName), parseName(newName)); - cacheUnload(oldName.toString()); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(String oldName, String newName) - throws NamingException { - dirContext.rename(parseName(oldName), parseName(newName)); - cacheUnload(oldName); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(Name name) - throws NamingException { - return dirContext.list(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(String name) - throws NamingException { - return dirContext.list(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(Name name) - throws NamingException { - return dirContext.listBindings(parseName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(String name) - throws NamingException { - return dirContext.listBindings(parseName(name)); - } - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(Name name) - throws NamingException { - dirContext.destroySubcontext(parseName(name)); - cacheUnload(name.toString()); - } - - - /** - * Destroys the named context and removes it from the namespace. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(String name) - throws NamingException { - dirContext.destroySubcontext(parseName(name)); - cacheUnload(name); - } - - - /** - * Creates and binds a new context. Creates a new context with the given - * name and binds it in the target context (that named by all but - * terminal atomic component of the name). All intermediate contexts and - * the target context must already exist. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(Name name) - throws NamingException { - Context context = dirContext.createSubcontext(parseName(name)); - cacheUnload(name.toString()); - return context; - } - - - /** - * Creates and binds a new context. - * - * @param name the name of the context to create; may not be empty - * @return the newly created context - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if creation of the subcontext - * requires specification of mandatory attributes - * @exception NamingException if a naming exception is encountered - */ - public Context createSubcontext(String name) - throws NamingException { - Context context = dirContext.createSubcontext(parseName(name)); - cacheUnload(name); - return context; - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(Name name) - throws NamingException { - return dirContext.lookupLink(parseName(name)); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(String name) - throws NamingException { - return dirContext.lookupLink(parseName(name)); - } - - - /** - * Retrieves the parser associated with the named context. In a - * federation of namespaces, different naming systems will parse names - * differently. This method allows an application to get a parser for - * parsing names into their atomic components using the naming convention - * of a particular naming system. Within any single naming system, - * NameParser objects returned by this method must be equal (using the - * equals() test). - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(Name name) - throws NamingException { - return dirContext.getNameParser(parseName(name)); - } - - - /** - * Retrieves the parser associated with the named context. - * - * @param name the name of the context from which to get the parser - * @return a name parser that can parse compound names into their atomic - * components - * @exception NamingException if a naming exception is encountered - */ - public NameParser getNameParser(String name) - throws NamingException { - return dirContext.getNameParser(parseName(name)); - } - - - /** - * Composes the name of this context with a name relative to this context. - *

        - * Given a name (name) relative to this context, and the name (prefix) - * of this context relative to one of its ancestors, this method returns - * the composition of the two names using the syntax appropriate for the - * naming system(s) involved. That is, if name names an object relative - * to this context, the result is the name of the same object, but - * relative to the ancestor context. None of the names may be null. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public Name composeName(Name name, Name prefix) - throws NamingException { - prefix = (Name) prefix.clone(); - return prefix.addAll(name); - } - - - /** - * Composes the name of this context with a name relative to this context. - * - * @param name a name relative to this context - * @param prefix the name of this context relative to one of its ancestors - * @return the composition of prefix and name - * @exception NamingException if a naming exception is encountered - */ - public String composeName(String name, String prefix) - throws NamingException { - return prefix + "/" + name; - } - - - /** - * Adds a new environment property to the environment of this context. If - * the property already exists, its value is overwritten. - * - * @param propName the name of the environment property to add; may not - * be null - * @param propVal the value of the property to add; may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object addToEnvironment(String propName, Object propVal) - throws NamingException { - return dirContext.addToEnvironment(propName, propVal); - } - - - /** - * Removes an environment property from the environment of this context. - * - * @param propName the name of the environment property to remove; - * may not be null - * @exception NamingException if a naming exception is encountered - */ - public Object removeFromEnvironment(String propName) - throws NamingException { - return dirContext.removeFromEnvironment(propName); - } - - - /** - * Retrieves the environment in effect for this context. See class - * description for more details on environment properties. - * The caller should not make any changes to the object returned: their - * effect on the context is undefined. The environment of this context - * may be changed using addToEnvironment() and removeFromEnvironment(). - * - * @return the environment of this context; never null - * @exception NamingException if a naming exception is encountered - */ - public Hashtable getEnvironment() - throws NamingException { - return dirContext.getEnvironment(); - } - - - /** - * Closes this context. This method releases this context's resources - * immediately, instead of waiting for them to be released automatically - * by the garbage collector. - * This method is idempotent: invoking it on a context that has already - * been closed has no effect. Invoking any other method on a closed - * context is not allowed, and results in undefined behaviour. - * - * @exception NamingException if a naming exception is encountered - */ - public void close() - throws NamingException { - dirContext.close(); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public String getNameInNamespace() - throws NamingException { - return dirContext.getNameInNamespace(); - } - - - // ----------------------------------------------------- DirContext Methods - - - /** - * Retrieves all of the attributes associated with a named object. - * - * @return the set of attributes associated with name. - * Returns an empty attribute set if name has no attributes; never null. - * @param name the name of the object from which to retrieve attributes - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(Name name) - throws NamingException { - CacheEntry entry = cacheLookup(name.toString()); - if (entry != null) { - if (!entry.exists) { - throw notFoundException; - } - return entry.attributes; - } - Attributes attributes = dirContext.getAttributes(parseName(name)); - if (!(attributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(attributes); - } - return attributes; - } - - - /** - * Retrieves all of the attributes associated with a named object. - * - * @return the set of attributes associated with name - * @param name the name of the object from which to retrieve attributes - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(String name) - throws NamingException { - CacheEntry entry = cacheLookup(name); - if (entry != null) { - if (!entry.exists) { - throw notFoundException; - } - return entry.attributes; - } - Attributes attributes = dirContext.getAttributes(parseName(name)); - if (!(attributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(attributes); - } - return attributes; - } - - - /** - * Retrieves selected attributes associated with a named object. - * See the class description regarding attribute models, attribute type - * names, and operational attributes. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(Name name, String[] attrIds) - throws NamingException { - Attributes attributes = - dirContext.getAttributes(parseName(name), attrIds); - if (!(attributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(attributes); - } - return attributes; - } - - - /** - * Retrieves selected attributes associated with a named object. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(String name, String[] attrIds) - throws NamingException { - Attributes attributes = - dirContext.getAttributes(parseName(name), attrIds); - if (!(attributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(attributes); - } - return attributes; - } - - - /** - * Modifies the attributes associated with a named object. The order of - * the modifications is not specified. Where possible, the modifications - * are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(Name name, int mod_op, Attributes attrs) - throws NamingException { - dirContext.modifyAttributes(parseName(name), mod_op, attrs); - cacheUnload(name.toString()); - } - - - /** - * Modifies the attributes associated with a named object. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, int mod_op, Attributes attrs) - throws NamingException { - dirContext.modifyAttributes(parseName(name), mod_op, attrs); - cacheUnload(name); - } - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. The modifications are performed in the - * order specified. Each modification specifies a modification operation - * code and an attribute on which to operate. Where possible, the - * modifications are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(Name name, ModificationItem[] mods) - throws NamingException { - dirContext.modifyAttributes(parseName(name), mods); - cacheUnload(name.toString()); - } - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, ModificationItem[] mods) - throws NamingException { - dirContext.modifyAttributes(parseName(name), mods); - cacheUnload(name); - } - - - /** - * Binds a name to an object, along with associated attributes. If attrs - * is null, the resulting binding will have the attributes associated - * with obj if obj is a DirContext, and no attributes otherwise. If attrs - * is non-null, the resulting binding will have attrs as its attributes; - * any attributes associated with obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void bind(Name name, Object obj, Attributes attrs) - throws NamingException { - dirContext.bind(parseName(name), obj, attrs); - cacheUnload(name.toString()); - } - - - /** - * Binds a name to an object, along with associated attributes. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj, Attributes attrs) - throws NamingException { - dirContext.bind(parseName(name), obj, attrs); - cacheUnload(name); - } - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. If attrs is null and obj is a - * DirContext, the attributes from obj are used. If attrs is null and obj - * is not a DirContext, any existing attributes associated with the object - * already bound in the directory remain unchanged. If attrs is non-null, - * any existing attributes associated with the object already bound in - * the directory are removed and attrs is associated with the named - * object. If obj is a DirContext and attrs is non-null, the attributes - * of obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void rebind(Name name, Object obj, Attributes attrs) - throws NamingException { - dirContext.rebind(parseName(name), obj, attrs); - cacheUnload(name.toString()); - } - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj, Attributes attrs) - throws NamingException { - dirContext.rebind(parseName(name), obj, attrs); - cacheUnload(name); - } - - - /** - * Creates and binds a new context, along with associated attributes. - * This method creates a new subcontext with the given name, binds it in - * the target context (that named by all but terminal atomic component of - * the name), and associates the supplied attributes with the newly - * created object. All intermediate and target contexts must already - * exist. If attrs is null, this method is equivalent to - * Context.createSubcontext(). - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public DirContext createSubcontext(Name name, Attributes attrs) - throws NamingException { - DirContext context = - dirContext.createSubcontext(parseName(name), attrs); - cacheUnload(name.toString()); - return context; - } - - - /** - * Creates and binds a new context, along with associated attributes. - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public DirContext createSubcontext(String name, Attributes attrs) - throws NamingException { - DirContext context = - dirContext.createSubcontext(parseName(name), attrs); - cacheUnload(name); - return context; - } - - - /** - * Retrieves the schema associated with the named object. The schema - * describes rules regarding the structure of the namespace and the - * attributes stored within it. The schema specifies what types of - * objects can be added to the directory and where they can be added; - * what mandatory and optional attributes an object can have. The range - * of support for schemas is directory-specific. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchema(Name name) - throws NamingException { - return dirContext.getSchema(parseName(name)); - } - - - /** - * Retrieves the schema associated with the named object. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchema(String name) - throws NamingException { - return dirContext.getSchema(parseName(name)); - } - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchemaClassDefinition(Name name) - throws NamingException { - return dirContext.getSchemaClassDefinition(parseName(name)); - } - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchemaClassDefinition(String name) - throws NamingException { - return dirContext.getSchemaClassDefinition(parseName(name)); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. The search is - * performed using the default SearchControls settings. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException { - return dirContext.search(parseName(name), matchingAttributes, - attributesToReturn); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException { - return dirContext.search(parseName(name), matchingAttributes, - attributesToReturn); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. This method returns all the attributes of such objects. - * It is equivalent to supplying null as the atributesToReturn parameter - * to the method search(Name, Attributes, String[]). - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, Attributes matchingAttributes) - throws NamingException { - return dirContext.search(parseName(name), matchingAttributes); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes) - throws NamingException { - return dirContext.search(parseName(name), matchingAttributes); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter specified - * is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, String filter, - SearchControls cons) - throws NamingException { - return dirContext.search(parseName(name), filter, cons); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter - * specified is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filter, - SearchControls cons) - throws NamingException { - return dirContext.search(parseName(name), filter, cons); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(Name name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException { - return dirContext.search(parseName(name), filterExpr, filterArgs, - cons); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException { - return dirContext.search(parseName(name), filterExpr, filterArgs, - cons); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieves the named object as a cache entry, without any exception. - * - * @param name the name of the object to look up - * @return the cache entry bound to name - */ - public CacheEntry lookupCache(String name) { - CacheEntry entry = cacheLookup(name); - if (entry == null) { - entry = new CacheEntry(); - entry.name = name; - try { - Object object = dirContext.lookup(parseName(name)); - if (object instanceof InputStream) { - entry.resource = new Resource((InputStream) object); - } else if (object instanceof DirContext) { - entry.context = (DirContext) object; - } else if (object instanceof Resource) { - entry.resource = (Resource) object; - } else { - entry.resource = new Resource(new ByteArrayInputStream - (object.toString().getBytes())); - } - Attributes attributes = dirContext.getAttributes(parseName(name)); - if (!(attributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(attributes); - } - entry.attributes = (ResourceAttributes) attributes; - } catch (NamingException e) { - entry.exists = false; - } - } - return entry; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Parses a name. - * - * @return the parsed name - */ - protected String parseName(String name) - throws NamingException { - return name; - } - - - /** - * Parses a name. - * - * @return the parsed name - */ - protected Name parseName(Name name) - throws NamingException { - return name; - } - - - /** - * Lookup in cache. - */ - protected CacheEntry cacheLookup(String name) { - if (cache == null) - return (null); - if (name == null) - name = ""; - for (int i = 0; i < nonCacheable.length; i++) { - if (name.startsWith(nonCacheable[i])) { - return (null); - } - } - CacheEntry cacheEntry = cache.lookup(name); - if (cacheEntry == null) { - cacheEntry = new CacheEntry(); - cacheEntry.name = name; - // Load entry - cacheLoad(cacheEntry); - } else { - if (!validate(cacheEntry)) { - if (!revalidate(cacheEntry)) { - cacheUnload(cacheEntry.name); - return (null); - } else { - cacheEntry.timestamp = - System.currentTimeMillis() + cacheTTL; - } - } - cacheEntry.accessCount++; - } - return (cacheEntry); - } - - - /** - * Validate entry. - */ - protected boolean validate(CacheEntry entry) { - if (((!entry.exists) - || (entry.context != null) - || ((entry.resource != null) - && (entry.resource.getContent() != null))) - && (System.currentTimeMillis() < entry.timestamp)) { - return true; - } - return false; - } - - - /** - * Revalidate entry. - */ - protected boolean revalidate(CacheEntry entry) { - // Get the attributes at the given path, and check the last - // modification date - if (!entry.exists) - return false; - if (entry.attributes == null) - return false; - long lastModified = entry.attributes.getLastModified(); - long contentLength = entry.attributes.getContentLength(); - if (lastModified <= 0) - return false; - try { - Attributes tempAttributes = dirContext.getAttributes(entry.name); - ResourceAttributes attributes = null; - if (!(tempAttributes instanceof ResourceAttributes)) { - attributes = new ResourceAttributes(tempAttributes); - } else { - attributes = (ResourceAttributes) tempAttributes; - } - long lastModified2 = attributes.getLastModified(); - long contentLength2 = attributes.getContentLength(); - return (lastModified == lastModified2) - && (contentLength == contentLength2); - } catch (NamingException e) { - return false; - } - } - - - /** - * Load entry into cache. - */ - protected void cacheLoad(CacheEntry entry) { - - String name = entry.name; - - // Retrieve missing info - boolean exists = true; - - // Retrieving attributes - if (entry.attributes == null) { - try { - Attributes attributes = dirContext.getAttributes(entry.name); - if (!(attributes instanceof ResourceAttributes)) { - entry.attributes = - new ResourceAttributes(attributes); - } else { - entry.attributes = (ResourceAttributes) attributes; - } - } catch (NamingException e) { - exists = false; - } - } - - // Retriving object - if ((exists) && (entry.resource == null) && (entry.context == null)) { - try { - Object object = dirContext.lookup(name); - if (object instanceof InputStream) { - entry.resource = new Resource((InputStream) object); - } else if (object instanceof DirContext) { - entry.context = (DirContext) object; - } else if (object instanceof Resource) { - entry.resource = (Resource) object; - } else { - entry.resource = new Resource(new ByteArrayInputStream - (object.toString().getBytes())); - } - } catch (NamingException e) { - exists = false; - } - } - - // Load object content - if ((exists) && (entry.resource != null) - && (entry.resource.getContent() == null) - && (entry.attributes.getContentLength() >= 0) - && (entry.attributes.getContentLength() < - (cacheObjectMaxSize * 1024))) { - int length = (int) entry.attributes.getContentLength(); - // The entry size is 1 + the resource size in KB, if it will be - // cached - entry.size += (entry.attributes.getContentLength() / 1024); - InputStream is = null; - try { - is = entry.resource.streamContent(); - int pos = 0; - byte[] b = new byte[length]; - while (pos < length) { - int n = is.read(b, pos, length - pos); - if (n < 0) - break; - pos = pos + n; - } - entry.resource.setContent(b); - } catch (IOException e) { - ; // Ignore - } finally { - try { - if (is != null) - is.close(); - } catch (IOException e) { - ; // Ignore - } - } - } - - // Set existence flag - entry.exists = exists; - - // Set timestamp - entry.timestamp = System.currentTimeMillis() + cacheTTL; - - // Add new entry to cache - synchronized (cache) { - // Check cache size, and remove elements if too big - if ((cache.lookup(name) == null) && cache.allocate(entry.size)) { - cache.load(entry); - } - } - - } - - - /** - * Remove entry from cache. - */ - protected boolean cacheUnload(String name) { - if (cache == null) - return false; - synchronized (cache) { - return cache.unload(name); - } - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.Hashtable; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NameNotFoundException; +import javax.naming.NameParser; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; + +import org.apache.naming.StringManager; + +/** + * Proxy Directory Context implementation. + * + * @author Remy Maucherat + * @version $Revision: 304085 $ $Date: 2005-09-12 12:57:46 +0200 (lun., 12 sept. 2005) $ + */ + +public class ProxyDirContext implements DirContext { + + + // -------------------------------------------------------------- Constants + + + public static final String CONTEXT = "context"; + public static final String HOST = "host"; + + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a proxy directory context using the given environment. + */ + public ProxyDirContext(Hashtable env, DirContext dirContext) { + this.env = env; + this.dirContext = dirContext; + if (dirContext instanceof BaseDirContext) { + // Initialize parameters based on the associated dir context, like + // the caching policy. + BaseDirContext baseDirContext = (BaseDirContext) dirContext; + if (baseDirContext.isCached()) { + try { + cache = (ResourceCache) + Class.forName(cacheClassName).newInstance(); + } catch (Exception e) { + //FIXME + e.printStackTrace(); + } + cache.setCacheMaxSize(baseDirContext.getCacheMaxSize()); + cacheTTL = baseDirContext.getCacheTTL(); + cacheObjectMaxSize = baseDirContext.getCacheMaxSize() / 20; + } + } + hostName = (String) env.get(HOST); + contextName = (String) env.get(CONTEXT); + } + + + /** + * Builds a clone of this proxy dir context, wrapping the given directory + * context, and sharing the same cache. + */ + // TODO: Refactor using the proxy field + /* + protected ProxyDirContext(ProxyDirContext proxyDirContext, + DirContext dirContext, String vPath) { + this.env = proxyDirContext.env; + this.dirContext = dirContext; + this.vPath = vPath; + this.cache = proxyDirContext.cache; + this.cacheMaxSize = proxyDirContext.cacheMaxSize; + this.cacheSize = proxyDirContext.cacheSize; + this.cacheTTL = proxyDirContext.cacheTTL; + this.cacheObjectMaxSize = proxyDirContext.cacheObjectMaxSize; + this.notFoundCache = proxyDirContext.notFoundCache; + this.hostName = proxyDirContext.hostName; + this.contextName = proxyDirContext.contextName; + } + */ + + + // ----------------------------------------------------- Instance Variables + + + /** + * Proxy DirContext (either this or the real proxy). + */ + protected ProxyDirContext proxy = this; + + + /** + * Environment. + */ + protected Hashtable env; + + + /** + * The string manager for this package. + */ + protected StringManager sm = StringManager.getManager(Constants.Package); + + + /** + * Associated DirContext. + */ + protected DirContext dirContext; + + + /** + * Virtual path. + */ + protected String vPath = null; + + + /** + * Host name. + */ + protected String hostName; + + + /** + * Context name. + */ + protected String contextName; + + + /** + * Cache class. + */ + protected String cacheClassName = + "org.apache.naming.resources.ResourceCache"; + + + /** + * Cache. + */ + protected ResourceCache cache = null; + + + /** + * Cache TTL. + */ + protected int cacheTTL = 5000; // 5s + + + /** + * Max size of resources which will have their content cached. + */ + protected int cacheObjectMaxSize = 512; // 512 KB + + + /** + * Immutable name not found exception. + */ + protected NameNotFoundException notFoundException = + new ImmutableNameNotFoundException(); + + + /** + * Non cacheable resources. + */ + protected String[] nonCacheable = { "/WEB-INF/lib/", "/WEB-INF/classes/" }; + + + // --------------------------------------------------------- Public Methods + + + /** + * Get the cache used for this context. + */ + public ResourceCache getCache() { + return cache; + } + + + /** + * Return the actual directory context we are wrapping. + */ + public DirContext getDirContext() { + return this.dirContext; + } + + + /** + * Return the document root for this component. + */ + public String getDocBase() { + if (dirContext instanceof BaseDirContext) + return ((BaseDirContext) dirContext).getDocBase(); + else + return ""; + } + + + /** + * Return the host name. + */ + public String getHostName() { + return this.hostName; + } + + + /** + * Return the context name. + */ + public String getContextName() { + return this.contextName; + } + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. If name is empty, returns a new instance + * of this context (which represents the same naming context as this + * context, but its environment may be modified independently and it may + * be accessed concurrently). + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(Name name) + throws NamingException { + CacheEntry entry = cacheLookup(name.toString()); + if (entry != null) { + if (!entry.exists) { + throw notFoundException; + } + if (entry.resource != null) { + // Check content caching. + return entry.resource; + } else { + return entry.context; + } + } + Object object = dirContext.lookup(parseName(name)); + if (object instanceof InputStream) + return new Resource((InputStream) object); + else + return object; + } + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(String name) + throws NamingException { + CacheEntry entry = cacheLookup(name); + if (entry != null) { + if (!entry.exists) { + throw notFoundException; + } + if (entry.resource != null) { + return entry.resource; + } else { + return entry.context; + } + } + Object object = dirContext.lookup(parseName(name)); + if (object instanceof InputStream) { + return new Resource((InputStream) object); + } else if (object instanceof DirContext) { + return object; + } else if (object instanceof Resource) { + return object; + } else { + return new Resource(new ByteArrayInputStream + (object.toString().getBytes())); + } + } + + + /** + * Binds a name to an object. All intermediate contexts and the target + * context (that named by all but terminal atomic component of the name) + * must already exist. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj) + throws NamingException { + dirContext.bind(parseName(name), obj); + cacheUnload(name.toString()); + } + + + /** + * Binds a name to an object. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj) + throws NamingException { + dirContext.bind(parseName(name), obj); + cacheUnload(name); + } + + + /** + * Binds a name to an object, overwriting any existing binding. All + * intermediate contexts and the target context (that named by all but + * terminal atomic component of the name) must already exist. + *

        + * If the object is a DirContext, any existing attributes associated with + * the name are replaced with those of the object. Otherwise, any + * existing attributes associated with the name remain unchanged. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj) + throws NamingException { + dirContext.rebind(parseName(name), obj); + cacheUnload(name.toString()); + } + + + /** + * Binds a name to an object, overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @exception InvalidAttributesException if object did not supply all + * mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj) + throws NamingException { + dirContext.rebind(parseName(name), obj); + cacheUnload(name); + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(Name name) + throws NamingException { + dirContext.unbind(parseName(name)); + cacheUnload(name.toString()); + } + + + /** + * Unbinds the named object. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(String name) + throws NamingException { + dirContext.unbind(parseName(name)); + cacheUnload(name); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(Name oldName, Name newName) + throws NamingException { + dirContext.rename(parseName(oldName), parseName(newName)); + cacheUnload(oldName.toString()); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(String oldName, String newName) + throws NamingException { + dirContext.rename(parseName(oldName), parseName(newName)); + cacheUnload(oldName); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(Name name) + throws NamingException { + return dirContext.list(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(String name) + throws NamingException { + return dirContext.list(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(Name name) + throws NamingException { + return dirContext.listBindings(parseName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(String name) + throws NamingException { + return dirContext.listBindings(parseName(name)); + } + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(Name name) + throws NamingException { + dirContext.destroySubcontext(parseName(name)); + cacheUnload(name.toString()); + } + + + /** + * Destroys the named context and removes it from the namespace. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(String name) + throws NamingException { + dirContext.destroySubcontext(parseName(name)); + cacheUnload(name); + } + + + /** + * Creates and binds a new context. Creates a new context with the given + * name and binds it in the target context (that named by all but + * terminal atomic component of the name). All intermediate contexts and + * the target context must already exist. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(Name name) + throws NamingException { + Context context = dirContext.createSubcontext(parseName(name)); + cacheUnload(name.toString()); + return context; + } + + + /** + * Creates and binds a new context. + * + * @param name the name of the context to create; may not be empty + * @return the newly created context + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if creation of the subcontext + * requires specification of mandatory attributes + * @exception NamingException if a naming exception is encountered + */ + public Context createSubcontext(String name) + throws NamingException { + Context context = dirContext.createSubcontext(parseName(name)); + cacheUnload(name); + return context; + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(Name name) + throws NamingException { + return dirContext.lookupLink(parseName(name)); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(String name) + throws NamingException { + return dirContext.lookupLink(parseName(name)); + } + + + /** + * Retrieves the parser associated with the named context. In a + * federation of namespaces, different naming systems will parse names + * differently. This method allows an application to get a parser for + * parsing names into their atomic components using the naming convention + * of a particular naming system. Within any single naming system, + * NameParser objects returned by this method must be equal (using the + * equals() test). + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(Name name) + throws NamingException { + return dirContext.getNameParser(parseName(name)); + } + + + /** + * Retrieves the parser associated with the named context. + * + * @param name the name of the context from which to get the parser + * @return a name parser that can parse compound names into their atomic + * components + * @exception NamingException if a naming exception is encountered + */ + public NameParser getNameParser(String name) + throws NamingException { + return dirContext.getNameParser(parseName(name)); + } + + + /** + * Composes the name of this context with a name relative to this context. + *

        + * Given a name (name) relative to this context, and the name (prefix) + * of this context relative to one of its ancestors, this method returns + * the composition of the two names using the syntax appropriate for the + * naming system(s) involved. That is, if name names an object relative + * to this context, the result is the name of the same object, but + * relative to the ancestor context. None of the names may be null. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public Name composeName(Name name, Name prefix) + throws NamingException { + prefix = (Name) prefix.clone(); + return prefix.addAll(name); + } + + + /** + * Composes the name of this context with a name relative to this context. + * + * @param name a name relative to this context + * @param prefix the name of this context relative to one of its ancestors + * @return the composition of prefix and name + * @exception NamingException if a naming exception is encountered + */ + public String composeName(String name, String prefix) + throws NamingException { + return prefix + "/" + name; + } + + + /** + * Adds a new environment property to the environment of this context. If + * the property already exists, its value is overwritten. + * + * @param propName the name of the environment property to add; may not + * be null + * @param propVal the value of the property to add; may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object addToEnvironment(String propName, Object propVal) + throws NamingException { + return dirContext.addToEnvironment(propName, propVal); + } + + + /** + * Removes an environment property from the environment of this context. + * + * @param propName the name of the environment property to remove; + * may not be null + * @exception NamingException if a naming exception is encountered + */ + public Object removeFromEnvironment(String propName) + throws NamingException { + return dirContext.removeFromEnvironment(propName); + } + + + /** + * Retrieves the environment in effect for this context. See class + * description for more details on environment properties. + * The caller should not make any changes to the object returned: their + * effect on the context is undefined. The environment of this context + * may be changed using addToEnvironment() and removeFromEnvironment(). + * + * @return the environment of this context; never null + * @exception NamingException if a naming exception is encountered + */ + public Hashtable getEnvironment() + throws NamingException { + return dirContext.getEnvironment(); + } + + + /** + * Closes this context. This method releases this context's resources + * immediately, instead of waiting for them to be released automatically + * by the garbage collector. + * This method is idempotent: invoking it on a context that has already + * been closed has no effect. Invoking any other method on a closed + * context is not allowed, and results in undefined behaviour. + * + * @exception NamingException if a naming exception is encountered + */ + public void close() + throws NamingException { + dirContext.close(); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public String getNameInNamespace() + throws NamingException { + return dirContext.getNameInNamespace(); + } + + + // ----------------------------------------------------- DirContext Methods + + + /** + * Retrieves all of the attributes associated with a named object. + * + * @return the set of attributes associated with name. + * Returns an empty attribute set if name has no attributes; never null. + * @param name the name of the object from which to retrieve attributes + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(Name name) + throws NamingException { + CacheEntry entry = cacheLookup(name.toString()); + if (entry != null) { + if (!entry.exists) { + throw notFoundException; + } + return entry.attributes; + } + Attributes attributes = dirContext.getAttributes(parseName(name)); + if (!(attributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(attributes); + } + return attributes; + } + + + /** + * Retrieves all of the attributes associated with a named object. + * + * @return the set of attributes associated with name + * @param name the name of the object from which to retrieve attributes + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(String name) + throws NamingException { + CacheEntry entry = cacheLookup(name); + if (entry != null) { + if (!entry.exists) { + throw notFoundException; + } + return entry.attributes; + } + Attributes attributes = dirContext.getAttributes(parseName(name)); + if (!(attributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(attributes); + } + return attributes; + } + + + /** + * Retrieves selected attributes associated with a named object. + * See the class description regarding attribute models, attribute type + * names, and operational attributes. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(Name name, String[] attrIds) + throws NamingException { + Attributes attributes = + dirContext.getAttributes(parseName(name), attrIds); + if (!(attributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(attributes); + } + return attributes; + } + + + /** + * Retrieves selected attributes associated with a named object. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + Attributes attributes = + dirContext.getAttributes(parseName(name), attrIds); + if (!(attributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(attributes); + } + return attributes; + } + + + /** + * Modifies the attributes associated with a named object. The order of + * the modifications is not specified. Where possible, the modifications + * are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(Name name, int mod_op, Attributes attrs) + throws NamingException { + dirContext.modifyAttributes(parseName(name), mod_op, attrs); + cacheUnload(name.toString()); + } + + + /** + * Modifies the attributes associated with a named object. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, int mod_op, Attributes attrs) + throws NamingException { + dirContext.modifyAttributes(parseName(name), mod_op, attrs); + cacheUnload(name); + } + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. The modifications are performed in the + * order specified. Each modification specifies a modification operation + * code and an attribute on which to operate. Where possible, the + * modifications are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(Name name, ModificationItem[] mods) + throws NamingException { + dirContext.modifyAttributes(parseName(name), mods); + cacheUnload(name.toString()); + } + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException { + dirContext.modifyAttributes(parseName(name), mods); + cacheUnload(name); + } + + + /** + * Binds a name to an object, along with associated attributes. If attrs + * is null, the resulting binding will have the attributes associated + * with obj if obj is a DirContext, and no attributes otherwise. If attrs + * is non-null, the resulting binding will have attrs as its attributes; + * any attributes associated with obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void bind(Name name, Object obj, Attributes attrs) + throws NamingException { + dirContext.bind(parseName(name), obj, attrs); + cacheUnload(name.toString()); + } + + + /** + * Binds a name to an object, along with associated attributes. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj, Attributes attrs) + throws NamingException { + dirContext.bind(parseName(name), obj, attrs); + cacheUnload(name); + } + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. If attrs is null and obj is a + * DirContext, the attributes from obj are used. If attrs is null and obj + * is not a DirContext, any existing attributes associated with the object + * already bound in the directory remain unchanged. If attrs is non-null, + * any existing attributes associated with the object already bound in + * the directory are removed and attrs is associated with the named + * object. If obj is a DirContext and attrs is non-null, the attributes + * of obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void rebind(Name name, Object obj, Attributes attrs) + throws NamingException { + dirContext.rebind(parseName(name), obj, attrs); + cacheUnload(name.toString()); + } + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj, Attributes attrs) + throws NamingException { + dirContext.rebind(parseName(name), obj, attrs); + cacheUnload(name); + } + + + /** + * Creates and binds a new context, along with associated attributes. + * This method creates a new subcontext with the given name, binds it in + * the target context (that named by all but terminal atomic component of + * the name), and associates the supplied attributes with the newly + * created object. All intermediate and target contexts must already + * exist. If attrs is null, this method is equivalent to + * Context.createSubcontext(). + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public DirContext createSubcontext(Name name, Attributes attrs) + throws NamingException { + DirContext context = + dirContext.createSubcontext(parseName(name), attrs); + cacheUnload(name.toString()); + return context; + } + + + /** + * Creates and binds a new context, along with associated attributes. + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public DirContext createSubcontext(String name, Attributes attrs) + throws NamingException { + DirContext context = + dirContext.createSubcontext(parseName(name), attrs); + cacheUnload(name); + return context; + } + + + /** + * Retrieves the schema associated with the named object. The schema + * describes rules regarding the structure of the namespace and the + * attributes stored within it. The schema specifies what types of + * objects can be added to the directory and where they can be added; + * what mandatory and optional attributes an object can have. The range + * of support for schemas is directory-specific. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchema(Name name) + throws NamingException { + return dirContext.getSchema(parseName(name)); + } + + + /** + * Retrieves the schema associated with the named object. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchema(String name) + throws NamingException { + return dirContext.getSchema(parseName(name)); + } + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchemaClassDefinition(Name name) + throws NamingException { + return dirContext.getSchemaClassDefinition(parseName(name)); + } + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchemaClassDefinition(String name) + throws NamingException { + return dirContext.getSchemaClassDefinition(parseName(name)); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. The search is + * performed using the default SearchControls settings. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + return dirContext.search(parseName(name), matchingAttributes, + attributesToReturn); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + return dirContext.search(parseName(name), matchingAttributes, + attributesToReturn); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. This method returns all the attributes of such objects. + * It is equivalent to supplying null as the atributesToReturn parameter + * to the method search(Name, Attributes, String[]). + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, Attributes matchingAttributes) + throws NamingException { + return dirContext.search(parseName(name), matchingAttributes); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes) + throws NamingException { + return dirContext.search(parseName(name), matchingAttributes); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter specified + * is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, String filter, + SearchControls cons) + throws NamingException { + return dirContext.search(parseName(name), filter, cons); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter + * specified is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filter, + SearchControls cons) + throws NamingException { + return dirContext.search(parseName(name), filter, cons); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(Name name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException { + return dirContext.search(parseName(name), filterExpr, filterArgs, + cons); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException { + return dirContext.search(parseName(name), filterExpr, filterArgs, + cons); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieves the named object as a cache entry, without any exception. + * + * @param name the name of the object to look up + * @return the cache entry bound to name + */ + public CacheEntry lookupCache(String name) { + CacheEntry entry = cacheLookup(name); + if (entry == null) { + entry = new CacheEntry(); + entry.name = name; + try { + Object object = dirContext.lookup(parseName(name)); + if (object instanceof InputStream) { + entry.resource = new Resource((InputStream) object); + } else if (object instanceof DirContext) { + entry.context = (DirContext) object; + } else if (object instanceof Resource) { + entry.resource = (Resource) object; + } else { + entry.resource = new Resource(new ByteArrayInputStream + (object.toString().getBytes())); + } + Attributes attributes = dirContext.getAttributes(parseName(name)); + if (!(attributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(attributes); + } + entry.attributes = (ResourceAttributes) attributes; + } catch (NamingException e) { + entry.exists = false; + } + } + return entry; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Parses a name. + * + * @return the parsed name + */ + protected String parseName(String name) + throws NamingException { + return name; + } + + + /** + * Parses a name. + * + * @return the parsed name + */ + protected Name parseName(Name name) + throws NamingException { + return name; + } + + + /** + * Lookup in cache. + */ + protected CacheEntry cacheLookup(String name) { + if (cache == null) + return (null); + if (name == null) + name = ""; + for (int i = 0; i < nonCacheable.length; i++) { + if (name.startsWith(nonCacheable[i])) { + return (null); + } + } + CacheEntry cacheEntry = cache.lookup(name); + if (cacheEntry == null) { + cacheEntry = new CacheEntry(); + cacheEntry.name = name; + // Load entry + cacheLoad(cacheEntry); + } else { + if (!validate(cacheEntry)) { + if (!revalidate(cacheEntry)) { + cacheUnload(cacheEntry.name); + return (null); + } else { + cacheEntry.timestamp = + System.currentTimeMillis() + cacheTTL; + } + } + cacheEntry.accessCount++; + } + return (cacheEntry); + } + + + /** + * Validate entry. + */ + protected boolean validate(CacheEntry entry) { + if (((!entry.exists) + || (entry.context != null) + || ((entry.resource != null) + && (entry.resource.getContent() != null))) + && (System.currentTimeMillis() < entry.timestamp)) { + return true; + } + return false; + } + + + /** + * Revalidate entry. + */ + protected boolean revalidate(CacheEntry entry) { + // Get the attributes at the given path, and check the last + // modification date + if (!entry.exists) + return false; + if (entry.attributes == null) + return false; + long lastModified = entry.attributes.getLastModified(); + long contentLength = entry.attributes.getContentLength(); + if (lastModified <= 0) + return false; + try { + Attributes tempAttributes = dirContext.getAttributes(entry.name); + ResourceAttributes attributes = null; + if (!(tempAttributes instanceof ResourceAttributes)) { + attributes = new ResourceAttributes(tempAttributes); + } else { + attributes = (ResourceAttributes) tempAttributes; + } + long lastModified2 = attributes.getLastModified(); + long contentLength2 = attributes.getContentLength(); + return (lastModified == lastModified2) + && (contentLength == contentLength2); + } catch (NamingException e) { + return false; + } + } + + + /** + * Load entry into cache. + */ + protected void cacheLoad(CacheEntry entry) { + + String name = entry.name; + + // Retrieve missing info + boolean exists = true; + + // Retrieving attributes + if (entry.attributes == null) { + try { + Attributes attributes = dirContext.getAttributes(entry.name); + if (!(attributes instanceof ResourceAttributes)) { + entry.attributes = + new ResourceAttributes(attributes); + } else { + entry.attributes = (ResourceAttributes) attributes; + } + } catch (NamingException e) { + exists = false; + } + } + + // Retriving object + if ((exists) && (entry.resource == null) && (entry.context == null)) { + try { + Object object = dirContext.lookup(name); + if (object instanceof InputStream) { + entry.resource = new Resource((InputStream) object); + } else if (object instanceof DirContext) { + entry.context = (DirContext) object; + } else if (object instanceof Resource) { + entry.resource = (Resource) object; + } else { + entry.resource = new Resource(new ByteArrayInputStream + (object.toString().getBytes())); + } + } catch (NamingException e) { + exists = false; + } + } + + // Load object content + if ((exists) && (entry.resource != null) + && (entry.resource.getContent() == null) + && (entry.attributes.getContentLength() >= 0) + && (entry.attributes.getContentLength() < + (cacheObjectMaxSize * 1024))) { + int length = (int) entry.attributes.getContentLength(); + // The entry size is 1 + the resource size in KB, if it will be + // cached + entry.size += (entry.attributes.getContentLength() / 1024); + InputStream is = null; + try { + is = entry.resource.streamContent(); + int pos = 0; + byte[] b = new byte[length]; + while (pos < length) { + int n = is.read(b, pos, length - pos); + if (n < 0) + break; + pos = pos + n; + } + entry.resource.setContent(b); + } catch (IOException e) { + ; // Ignore + } finally { + try { + if (is != null) + is.close(); + } catch (IOException e) { + ; // Ignore + } + } + } + + // Set existence flag + entry.exists = exists; + + // Set timestamp + entry.timestamp = System.currentTimeMillis() + cacheTTL; + + // Add new entry to cache + synchronized (cache) { + // Check cache size, and remove elements if too big + if ((cache.lookup(name) == null) && cache.allocate(entry.size)) { + cache.load(entry); + } + } + + } + + + /** + * Remove entry from cache. + */ + protected boolean cacheUnload(String name) { + if (cache == null) + return false; + synchronized (cache) { + return cache.unload(name); + } + } + + +} + diff --git a/java/org/apache/naming/resources/RecyclableNamingEnumeration.java b/java/org/apache/naming/resources/RecyclableNamingEnumeration.java index 9cc31412c..3ff22255b 100644 --- a/java/org/apache/naming/resources/RecyclableNamingEnumeration.java +++ b/java/org/apache/naming/resources/RecyclableNamingEnumeration.java @@ -1,112 +1,112 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - -import java.util.Enumeration; -import java.util.Vector; - -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; - -/** - * Naming enumeration implementation. - * - * @author Remy Maucherat - * @version $Revision: 303022 $ $Date: 2004-07-24 00:46:08 +0200 (sam., 24 juil. 2004) $ - */ - -public class RecyclableNamingEnumeration - implements NamingEnumeration { - - - // ----------------------------------------------------------- Constructors - - - public RecyclableNamingEnumeration(Vector entries) { - this.entries = entries; - recycle(); - } - - - // -------------------------------------------------------------- Variables - - - /** - * Entries. - */ - protected Vector entries; - - - /** - * Underlying enumeration. - */ - protected Enumeration enumeration; - - - // --------------------------------------------------------- Public Methods - - - /** - * Retrieves the next element in the enumeration. - */ - public Object next() - throws NamingException { - return nextElement(); - } - - - /** - * Determines whether there are any more elements in the enumeration. - */ - public boolean hasMore() - throws NamingException { - return enumeration.hasMoreElements(); - } - - - /** - * Closes this enumeration. - */ - public void close() - throws NamingException { - } - - - public boolean hasMoreElements() { - return enumeration.hasMoreElements(); - } - - - public Object nextElement() { - return enumeration.nextElement(); - } - - - // -------------------------------------------------------- Package Methods - - - /** - * Recycle. - */ - void recycle() { - enumeration = entries.elements(); - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + +import java.util.Enumeration; +import java.util.Vector; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; + +/** + * Naming enumeration implementation. + * + * @author Remy Maucherat + * @version $Revision: 303022 $ $Date: 2004-07-24 00:46:08 +0200 (sam., 24 juil. 2004) $ + */ + +public class RecyclableNamingEnumeration + implements NamingEnumeration { + + + // ----------------------------------------------------------- Constructors + + + public RecyclableNamingEnumeration(Vector entries) { + this.entries = entries; + recycle(); + } + + + // -------------------------------------------------------------- Variables + + + /** + * Entries. + */ + protected Vector entries; + + + /** + * Underlying enumeration. + */ + protected Enumeration enumeration; + + + // --------------------------------------------------------- Public Methods + + + /** + * Retrieves the next element in the enumeration. + */ + public Object next() + throws NamingException { + return nextElement(); + } + + + /** + * Determines whether there are any more elements in the enumeration. + */ + public boolean hasMore() + throws NamingException { + return enumeration.hasMoreElements(); + } + + + /** + * Closes this enumeration. + */ + public void close() + throws NamingException { + } + + + public boolean hasMoreElements() { + return enumeration.hasMoreElements(); + } + + + public Object nextElement() { + return enumeration.nextElement(); + } + + + // -------------------------------------------------------- Package Methods + + + /** + * Recycle. + */ + void recycle() { + enumeration = entries.elements(); + } + + +} + diff --git a/java/org/apache/naming/resources/Resource.java b/java/org/apache/naming/resources/Resource.java index 73a7f9805..a4e923fcd 100644 --- a/java/org/apache/naming/resources/Resource.java +++ b/java/org/apache/naming/resources/Resource.java @@ -1,111 +1,111 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.io.InputStream; -import java.io.ByteArrayInputStream; -import java.io.IOException; - -/** - * Encapsultes the contents of a resource. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ -public class Resource { - - - // ----------------------------------------------------------- Constructors - - - public Resource() { - } - - - public Resource(InputStream inputStream) { - setContent(inputStream); - } - - - public Resource(byte[] binaryContent) { - setContent(binaryContent); - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Binary content. - */ - protected byte[] binaryContent = null; - - - /** - * Input stream. - */ - protected InputStream inputStream = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Content accessor. - * - * @return InputStream - */ - public InputStream streamContent() - throws IOException { - if (binaryContent != null) { - return new ByteArrayInputStream(binaryContent); - } - return inputStream; - } - - - /** - * Content accessor. - * - * @return binary content - */ - public byte[] getContent() { - return binaryContent; - } - - - /** - * Content mutator. - * - * @param inputStream New input stream - */ - public void setContent(InputStream inputStream) { - this.inputStream = inputStream; - } - - - /** - * Content mutator. - * - * @param binaryContent New bin content - */ - public void setContent(byte[] binaryContent) { - this.binaryContent = binaryContent; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.io.InputStream; +import java.io.ByteArrayInputStream; +import java.io.IOException; + +/** + * Encapsultes the contents of a resource. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ +public class Resource { + + + // ----------------------------------------------------------- Constructors + + + public Resource() { + } + + + public Resource(InputStream inputStream) { + setContent(inputStream); + } + + + public Resource(byte[] binaryContent) { + setContent(binaryContent); + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Binary content. + */ + protected byte[] binaryContent = null; + + + /** + * Input stream. + */ + protected InputStream inputStream = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Content accessor. + * + * @return InputStream + */ + public InputStream streamContent() + throws IOException { + if (binaryContent != null) { + return new ByteArrayInputStream(binaryContent); + } + return inputStream; + } + + + /** + * Content accessor. + * + * @return binary content + */ + public byte[] getContent() { + return binaryContent; + } + + + /** + * Content mutator. + * + * @param inputStream New input stream + */ + public void setContent(InputStream inputStream) { + this.inputStream = inputStream; + } + + + /** + * Content mutator. + * + * @param binaryContent New bin content + */ + public void setContent(byte[] binaryContent) { + this.binaryContent = binaryContent; + } + + +} diff --git a/java/org/apache/naming/resources/ResourceAttributes.java b/java/org/apache/naming/resources/ResourceAttributes.java index 744721b99..66b24e308 100644 --- a/java/org/apache/naming/resources/ResourceAttributes.java +++ b/java/org/apache/naming/resources/ResourceAttributes.java @@ -1,915 +1,915 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; -import java.util.Vector; - -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.directory.Attribute; -import javax.naming.directory.Attributes; -import javax.naming.directory.BasicAttribute; - -/** - * Attributes implementation. - * - * @author Remy Maucherat - * @version $Revision: 303877 $ - */ -public class ResourceAttributes implements Attributes { - - - // -------------------------------------------------------------- Constants - - - // Default attribute names - - /** - * Creation date. - */ - public static final String CREATION_DATE = "creationdate"; - - - /** - * Creation date. - */ - public static final String ALTERNATE_CREATION_DATE = "creation-date"; - - - /** - * Last modification date. - */ - public static final String LAST_MODIFIED = "getlastmodified"; - - - /** - * Last modification date. - */ - public static final String ALTERNATE_LAST_MODIFIED = "last-modified"; - - - /** - * Name. - */ - public static final String NAME = "displayname"; - - - /** - * Type. - */ - public static final String TYPE = "resourcetype"; - - - /** - * Type. - */ - public static final String ALTERNATE_TYPE = "content-type"; - - - /** - * Source. - */ - public static final String SOURCE = "source"; - - - /** - * MIME type of the content. - */ - public static final String CONTENT_TYPE = "getcontenttype"; - - - /** - * Content language. - */ - public static final String CONTENT_LANGUAGE = "getcontentlanguage"; - - - /** - * Content length. - */ - public static final String CONTENT_LENGTH = "getcontentlength"; - - - /** - * Content length. - */ - public static final String ALTERNATE_CONTENT_LENGTH = "content-length"; - - - /** - * ETag. - */ - public static final String ETAG = "getetag"; - - - /** - * Collection type. - */ - public static final String COLLECTION_TYPE = ""; - - - /** - * HTTP date format. - */ - protected static final SimpleDateFormat format = - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - - - /** - * Date formats using for Date parsing. - */ - protected static final SimpleDateFormat formats[] = { - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - - - protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); - - - /** - * GMT timezone - all HTTP dates are on GMT - */ - static { - - format.setTimeZone(gmtZone); - - formats[0].setTimeZone(gmtZone); - formats[1].setTimeZone(gmtZone); - formats[2].setTimeZone(gmtZone); - - } - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. - */ - public ResourceAttributes() { - } - - - /** - * Merges with another attribute set. - */ - public ResourceAttributes(Attributes attributes) { - this.attributes = attributes; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Collection flag. - */ - protected boolean collection = false; - - - /** - * Content length. - */ - protected long contentLength = -1; - - - /** - * Creation time. - */ - protected long creation = -1; - - - /** - * Creation date. - */ - protected Date creationDate = null; - - - /** - * Last modified time. - */ - protected long lastModified = -1; - - - /** - * Last modified date. - */ - protected Date lastModifiedDate = null; - - - /** - * Last modified date in HTTP format. - */ - protected String lastModifiedHttp = null; - - - /** - * MIME type. - */ - protected String mimeType = null; - - - /** - * Name. - */ - protected String name = null; - - - /** - * Weak ETag. - */ - protected String weakETag = null; - - - /** - * Strong ETag. - */ - protected String strongETag = null; - - - /** - * External attributes. - */ - protected Attributes attributes = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Is collection. - */ - public boolean isCollection() { - if (attributes != null) { - return (getResourceType().equals(COLLECTION_TYPE)); - } else { - return (collection); - } - } - - - /** - * Set collection flag. - * - * @param collection New flag value - */ - public void setCollection(boolean collection) { - this.collection = collection; - if (attributes != null) { - String value = ""; - if (collection) - value = COLLECTION_TYPE; - attributes.put(TYPE, value); - } - } - - - /** - * Get content length. - * - * @return content length value - */ - public long getContentLength() { - if (contentLength != -1L) - return contentLength; - if (attributes != null) { - Attribute attribute = attributes.get(CONTENT_LENGTH); - if (attribute != null) { - try { - Object value = attribute.get(); - if (value instanceof Long) { - contentLength = ((Long) value).longValue(); - } else { - try { - contentLength = Long.parseLong(value.toString()); - } catch (NumberFormatException e) { - ; // Ignore - } - } - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return contentLength; - } - - - /** - * Set content length. - * - * @param contentLength New content length value - */ - public void setContentLength(long contentLength) { - this.contentLength = contentLength; - if (attributes != null) - attributes.put(CONTENT_LENGTH, new Long(contentLength)); - } - - - /** - * Get creation time. - * - * @return creation time value - */ - public long getCreation() { - if (creation != -1L) - return creation; - if (creationDate != null) - return creationDate.getTime(); - if (attributes != null) { - Attribute attribute = attributes.get(CREATION_DATE); - if (attribute != null) { - try { - Object value = attribute.get(); - if (value instanceof Long) { - creation = ((Long) value).longValue(); - } else if (value instanceof Date) { - creation = ((Date) value).getTime(); - creationDate = (Date) value; - } else { - String creationDateValue = value.toString(); - Date result = null; - // Parsing the HTTP Date - for (int i = 0; (result == null) && - (i < formats.length); i++) { - try { - result = formats[i].parse(creationDateValue); - } catch (ParseException e) { - ; - } - } - if (result != null) { - creation = result.getTime(); - creationDate = result; - } - } - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return creation; - } - - - /** - * Set creation. - * - * @param creation New creation value - */ - public void setCreation(long creation) { - this.creation = creation; - this.creationDate = null; - if (attributes != null) - attributes.put(CREATION_DATE, new Date(creation)); - } - - - /** - * Get creation date. - * - * @return Creation date value - */ - public Date getCreationDate() { - if (creationDate != null) - return creationDate; - if (creation != -1L) { - creationDate = new Date(creation); - return creationDate; - } - if (attributes != null) { - Attribute attribute = attributes.get(CREATION_DATE); - if (attribute != null) { - try { - Object value = attribute.get(); - if (value instanceof Long) { - creation = ((Long) value).longValue(); - creationDate = new Date(creation); - } else if (value instanceof Date) { - creation = ((Date) value).getTime(); - creationDate = (Date) value; - } else { - String creationDateValue = value.toString(); - Date result = null; - // Parsing the HTTP Date - for (int i = 0; (result == null) && - (i < formats.length); i++) { - try { - result = formats[i].parse(creationDateValue); - } catch (ParseException e) { - ; - } - } - if (result != null) { - creation = result.getTime(); - creationDate = result; - } - } - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return creationDate; - } - - - /** - * Creation date mutator. - * - * @param creationDate New creation date - */ - public void setCreationDate(Date creationDate) { - this.creation = creationDate.getTime(); - this.creationDate = creationDate; - if (attributes != null) - attributes.put(CREATION_DATE, creationDate); - } - - - /** - * Get last modified time. - * - * @return lastModified time value - */ - public long getLastModified() { - if (lastModified != -1L) - return lastModified; - if (lastModifiedDate != null) - return lastModifiedDate.getTime(); - if (attributes != null) { - Attribute attribute = attributes.get(LAST_MODIFIED); - if (attribute != null) { - try { - Object value = attribute.get(); - if (value instanceof Long) { - lastModified = ((Long) value).longValue(); - } else if (value instanceof Date) { - lastModified = ((Date) value).getTime(); - lastModifiedDate = (Date) value; - } else { - String lastModifiedDateValue = value.toString(); - Date result = null; - // Parsing the HTTP Date - for (int i = 0; (result == null) && - (i < formats.length); i++) { - try { - result = - formats[i].parse(lastModifiedDateValue); - } catch (ParseException e) { - ; - } - } - if (result != null) { - lastModified = result.getTime(); - lastModifiedDate = result; - } - } - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return lastModified; - } - - - /** - * Set last modified. - * - * @param lastModified New last modified value - */ - public void setLastModified(long lastModified) { - this.lastModified = lastModified; - this.lastModifiedDate = null; - if (attributes != null) - attributes.put(LAST_MODIFIED, new Date(lastModified)); - } - - - /** - * Set last modified date. - * - * @param lastModified New last modified date value - * @deprecated - */ - public void setLastModified(Date lastModified) { - setLastModifiedDate(lastModified); - } - - - /** - * Get lastModified date. - * - * @return LastModified date value - */ - public Date getLastModifiedDate() { - if (lastModifiedDate != null) - return lastModifiedDate; - if (lastModified != -1L) { - lastModifiedDate = new Date(lastModified); - return lastModifiedDate; - } - if (attributes != null) { - Attribute attribute = attributes.get(LAST_MODIFIED); - if (attribute != null) { - try { - Object value = attribute.get(); - if (value instanceof Long) { - lastModified = ((Long) value).longValue(); - lastModifiedDate = new Date(lastModified); - } else if (value instanceof Date) { - lastModified = ((Date) value).getTime(); - lastModifiedDate = (Date) value; - } else { - String lastModifiedDateValue = value.toString(); - Date result = null; - // Parsing the HTTP Date - for (int i = 0; (result == null) && - (i < formats.length); i++) { - try { - result = - formats[i].parse(lastModifiedDateValue); - } catch (ParseException e) { - ; - } - } - if (result != null) { - lastModified = result.getTime(); - lastModifiedDate = result; - } - } - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return lastModifiedDate; - } - - - /** - * Last modified date mutator. - * - * @param lastModifiedDate New last modified date - */ - public void setLastModifiedDate(Date lastModifiedDate) { - this.lastModified = lastModifiedDate.getTime(); - this.lastModifiedDate = lastModifiedDate; - if (attributes != null) - attributes.put(LAST_MODIFIED, lastModifiedDate); - } - - - /** - * @return Returns the lastModifiedHttp. - */ - public String getLastModifiedHttp() { - if (lastModifiedHttp != null) - return lastModifiedHttp; - Date modifiedDate = getLastModifiedDate(); - if (modifiedDate == null) { - modifiedDate = getCreationDate(); - } - if (modifiedDate == null) { - modifiedDate = new Date(); - } - synchronized (format) { - lastModifiedHttp = format.format(modifiedDate); - } - return lastModifiedHttp; - } - - - /** - * @param lastModifiedHttp The lastModifiedHttp to set. - */ - public void setLastModifiedHttp(String lastModifiedHttp) { - this.lastModifiedHttp = lastModifiedHttp; - } - - - /** - * @return Returns the mimeType. - */ - public String getMimeType() { - return mimeType; - } - - - /** - * @param mimeType The mimeType to set. - */ - public void setMimeType(String mimeType) { - this.mimeType = mimeType; - } - - - /** - * Get name. - * - * @return Name value - */ - public String getName() { - if (name != null) - return name; - if (attributes != null) { - Attribute attribute = attributes.get(NAME); - if (attribute != null) { - try { - name = attribute.get().toString(); - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - return name; - } - - - /** - * Set name. - * - * @param name New name value - */ - public void setName(String name) { - this.name = name; - if (attributes != null) - attributes.put(NAME, name); - } - - - /** - * Get resource type. - * - * @return String resource type - */ - public String getResourceType() { - String result = null; - if (attributes != null) { - Attribute attribute = attributes.get(TYPE); - if (attribute != null) { - try { - result = attribute.get().toString(); - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - if (result == null) { - if (collection) - result = COLLECTION_TYPE; - else - result = ""; - } - return result; - } - - - /** - * Type mutator. - * - * @param resourceType New resource type - */ - public void setResourceType(String resourceType) { - collection = resourceType.equals(COLLECTION_TYPE); - if (attributes != null) - attributes.put(TYPE, resourceType); - } - - - /** - * Get ETag. - * - * @return Weak ETag - */ - public String getETag() { - return getETag(false); - } - - - /** - * Get ETag. - * - * @param strong If true, the strong ETag will be returned - * @return ETag - */ - public String getETag(boolean strong) { - String result = null; - if (attributes != null) { - Attribute attribute = attributes.get(ETAG); - if (attribute != null) { - try { - result = attribute.get().toString(); - } catch (NamingException e) { - ; // No value for the attribute - } - } - } - if (strong) { - // The strong ETag must always be calculated by the resources - result = strongETag; - } else { - // The weakETag is contentLenght + lastModified - if (weakETag == null) { - weakETag = "W/\"" + getContentLength() + "-" - + getLastModified() + "\""; - } - result = weakETag; - } - return result; - } - - - /** - * Set strong ETag. - */ - public void setETag(String eTag) { - this.strongETag = eTag; - if (attributes != null) - attributes.put(ETAG, eTag); - } - - - /** - * Return the canonical path of the resource, to possibly be used for - * direct file serving. Implementations which support this should override - * it to return the file path. - * - * @return The canonical path of the resource - */ - public String getCanonicalPath() { - return null; - } - - - // ----------------------------------------------------- Attributes Methods - - - /** - * Get attribute. - */ - public Attribute get(String attrID) { - if (attributes == null) { - if (attrID.equals(CREATION_DATE)) { - return new BasicAttribute(CREATION_DATE, getCreationDate()); - } else if (attrID.equals(ALTERNATE_CREATION_DATE)) { - return new BasicAttribute(ALTERNATE_CREATION_DATE, - getCreationDate()); - } else if (attrID.equals(LAST_MODIFIED)) { - return new BasicAttribute(LAST_MODIFIED, - getLastModifiedDate()); - } else if (attrID.equals(ALTERNATE_LAST_MODIFIED)) { - return new BasicAttribute(ALTERNATE_LAST_MODIFIED, - getLastModifiedDate()); - } else if (attrID.equals(NAME)) { - return new BasicAttribute(NAME, getName()); - } else if (attrID.equals(TYPE)) { - return new BasicAttribute(TYPE, getResourceType()); - } else if (attrID.equals(ALTERNATE_TYPE)) { - return new BasicAttribute(ALTERNATE_TYPE, getResourceType()); - } else if (attrID.equals(CONTENT_LENGTH)) { - return new BasicAttribute(CONTENT_LENGTH, - new Long(getContentLength())); - } else if (attrID.equals(ALTERNATE_CONTENT_LENGTH)) { - return new BasicAttribute(ALTERNATE_CONTENT_LENGTH, - new Long(getContentLength())); - } - } else { - return attributes.get(attrID); - } - return null; - } - - - /** - * Put attribute. - */ - public Attribute put(Attribute attribute) { - if (attributes == null) { - try { - return put(attribute.getID(), attribute.get()); - } catch (NamingException e) { - return null; - } - } else { - return attributes.put(attribute); - } - } - - - /** - * Put attribute. - */ - public Attribute put(String attrID, Object val) { - if (attributes == null) { - return null; // No reason to implement this - } else { - return attributes.put(attrID, val); - } - } - - - /** - * Remove attribute. - */ - public Attribute remove(String attrID) { - if (attributes == null) { - return null; // No reason to implement this - } else { - return attributes.remove(attrID); - } - } - - - /** - * Get all attributes. - */ - public NamingEnumeration getAll() { - if (attributes == null) { - Vector attributes = new Vector(); - attributes.addElement(new BasicAttribute - (CREATION_DATE, getCreationDate())); - attributes.addElement(new BasicAttribute - (LAST_MODIFIED, getLastModifiedDate())); - attributes.addElement(new BasicAttribute(NAME, getName())); - attributes.addElement(new BasicAttribute(TYPE, getResourceType())); - attributes.addElement - (new BasicAttribute(CONTENT_LENGTH, - new Long(getContentLength()))); - return new RecyclableNamingEnumeration(attributes); - } else { - return attributes.getAll(); - } - } - - - /** - * Get all attribute IDs. - */ - public NamingEnumeration getIDs() { - if (attributes == null) { - Vector attributeIDs = new Vector(); - attributeIDs.addElement(CREATION_DATE); - attributeIDs.addElement(LAST_MODIFIED); - attributeIDs.addElement(NAME); - attributeIDs.addElement(TYPE); - attributeIDs.addElement(CONTENT_LENGTH); - return new RecyclableNamingEnumeration(attributeIDs); - } else { - return attributes.getIDs(); - } - } - - - /** - * Retrieves the number of attributes in the attribute set. - */ - public int size() { - if (attributes == null) { - return 5; - } else { - return attributes.size(); - } - } - - - /** - * Clone the attributes object (WARNING: fake cloning). - */ - public Object clone() { - return this; - } - - - /** - * Case sensitivity. - */ - public boolean isCaseIgnored() { - return false; - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; +import java.util.Vector; + +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.directory.Attribute; +import javax.naming.directory.Attributes; +import javax.naming.directory.BasicAttribute; + +/** + * Attributes implementation. + * + * @author Remy Maucherat + * @version $Revision: 303877 $ + */ +public class ResourceAttributes implements Attributes { + + + // -------------------------------------------------------------- Constants + + + // Default attribute names + + /** + * Creation date. + */ + public static final String CREATION_DATE = "creationdate"; + + + /** + * Creation date. + */ + public static final String ALTERNATE_CREATION_DATE = "creation-date"; + + + /** + * Last modification date. + */ + public static final String LAST_MODIFIED = "getlastmodified"; + + + /** + * Last modification date. + */ + public static final String ALTERNATE_LAST_MODIFIED = "last-modified"; + + + /** + * Name. + */ + public static final String NAME = "displayname"; + + + /** + * Type. + */ + public static final String TYPE = "resourcetype"; + + + /** + * Type. + */ + public static final String ALTERNATE_TYPE = "content-type"; + + + /** + * Source. + */ + public static final String SOURCE = "source"; + + + /** + * MIME type of the content. + */ + public static final String CONTENT_TYPE = "getcontenttype"; + + + /** + * Content language. + */ + public static final String CONTENT_LANGUAGE = "getcontentlanguage"; + + + /** + * Content length. + */ + public static final String CONTENT_LENGTH = "getcontentlength"; + + + /** + * Content length. + */ + public static final String ALTERNATE_CONTENT_LENGTH = "content-length"; + + + /** + * ETag. + */ + public static final String ETAG = "getetag"; + + + /** + * Collection type. + */ + public static final String COLLECTION_TYPE = ""; + + + /** + * HTTP date format. + */ + protected static final SimpleDateFormat format = + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + + + /** + * Date formats using for Date parsing. + */ + protected static final SimpleDateFormat formats[] = { + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) + }; + + + protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); + + + /** + * GMT timezone - all HTTP dates are on GMT + */ + static { + + format.setTimeZone(gmtZone); + + formats[0].setTimeZone(gmtZone); + formats[1].setTimeZone(gmtZone); + formats[2].setTimeZone(gmtZone); + + } + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. + */ + public ResourceAttributes() { + } + + + /** + * Merges with another attribute set. + */ + public ResourceAttributes(Attributes attributes) { + this.attributes = attributes; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Collection flag. + */ + protected boolean collection = false; + + + /** + * Content length. + */ + protected long contentLength = -1; + + + /** + * Creation time. + */ + protected long creation = -1; + + + /** + * Creation date. + */ + protected Date creationDate = null; + + + /** + * Last modified time. + */ + protected long lastModified = -1; + + + /** + * Last modified date. + */ + protected Date lastModifiedDate = null; + + + /** + * Last modified date in HTTP format. + */ + protected String lastModifiedHttp = null; + + + /** + * MIME type. + */ + protected String mimeType = null; + + + /** + * Name. + */ + protected String name = null; + + + /** + * Weak ETag. + */ + protected String weakETag = null; + + + /** + * Strong ETag. + */ + protected String strongETag = null; + + + /** + * External attributes. + */ + protected Attributes attributes = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Is collection. + */ + public boolean isCollection() { + if (attributes != null) { + return (getResourceType().equals(COLLECTION_TYPE)); + } else { + return (collection); + } + } + + + /** + * Set collection flag. + * + * @param collection New flag value + */ + public void setCollection(boolean collection) { + this.collection = collection; + if (attributes != null) { + String value = ""; + if (collection) + value = COLLECTION_TYPE; + attributes.put(TYPE, value); + } + } + + + /** + * Get content length. + * + * @return content length value + */ + public long getContentLength() { + if (contentLength != -1L) + return contentLength; + if (attributes != null) { + Attribute attribute = attributes.get(CONTENT_LENGTH); + if (attribute != null) { + try { + Object value = attribute.get(); + if (value instanceof Long) { + contentLength = ((Long) value).longValue(); + } else { + try { + contentLength = Long.parseLong(value.toString()); + } catch (NumberFormatException e) { + ; // Ignore + } + } + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return contentLength; + } + + + /** + * Set content length. + * + * @param contentLength New content length value + */ + public void setContentLength(long contentLength) { + this.contentLength = contentLength; + if (attributes != null) + attributes.put(CONTENT_LENGTH, new Long(contentLength)); + } + + + /** + * Get creation time. + * + * @return creation time value + */ + public long getCreation() { + if (creation != -1L) + return creation; + if (creationDate != null) + return creationDate.getTime(); + if (attributes != null) { + Attribute attribute = attributes.get(CREATION_DATE); + if (attribute != null) { + try { + Object value = attribute.get(); + if (value instanceof Long) { + creation = ((Long) value).longValue(); + } else if (value instanceof Date) { + creation = ((Date) value).getTime(); + creationDate = (Date) value; + } else { + String creationDateValue = value.toString(); + Date result = null; + // Parsing the HTTP Date + for (int i = 0; (result == null) && + (i < formats.length); i++) { + try { + result = formats[i].parse(creationDateValue); + } catch (ParseException e) { + ; + } + } + if (result != null) { + creation = result.getTime(); + creationDate = result; + } + } + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return creation; + } + + + /** + * Set creation. + * + * @param creation New creation value + */ + public void setCreation(long creation) { + this.creation = creation; + this.creationDate = null; + if (attributes != null) + attributes.put(CREATION_DATE, new Date(creation)); + } + + + /** + * Get creation date. + * + * @return Creation date value + */ + public Date getCreationDate() { + if (creationDate != null) + return creationDate; + if (creation != -1L) { + creationDate = new Date(creation); + return creationDate; + } + if (attributes != null) { + Attribute attribute = attributes.get(CREATION_DATE); + if (attribute != null) { + try { + Object value = attribute.get(); + if (value instanceof Long) { + creation = ((Long) value).longValue(); + creationDate = new Date(creation); + } else if (value instanceof Date) { + creation = ((Date) value).getTime(); + creationDate = (Date) value; + } else { + String creationDateValue = value.toString(); + Date result = null; + // Parsing the HTTP Date + for (int i = 0; (result == null) && + (i < formats.length); i++) { + try { + result = formats[i].parse(creationDateValue); + } catch (ParseException e) { + ; + } + } + if (result != null) { + creation = result.getTime(); + creationDate = result; + } + } + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return creationDate; + } + + + /** + * Creation date mutator. + * + * @param creationDate New creation date + */ + public void setCreationDate(Date creationDate) { + this.creation = creationDate.getTime(); + this.creationDate = creationDate; + if (attributes != null) + attributes.put(CREATION_DATE, creationDate); + } + + + /** + * Get last modified time. + * + * @return lastModified time value + */ + public long getLastModified() { + if (lastModified != -1L) + return lastModified; + if (lastModifiedDate != null) + return lastModifiedDate.getTime(); + if (attributes != null) { + Attribute attribute = attributes.get(LAST_MODIFIED); + if (attribute != null) { + try { + Object value = attribute.get(); + if (value instanceof Long) { + lastModified = ((Long) value).longValue(); + } else if (value instanceof Date) { + lastModified = ((Date) value).getTime(); + lastModifiedDate = (Date) value; + } else { + String lastModifiedDateValue = value.toString(); + Date result = null; + // Parsing the HTTP Date + for (int i = 0; (result == null) && + (i < formats.length); i++) { + try { + result = + formats[i].parse(lastModifiedDateValue); + } catch (ParseException e) { + ; + } + } + if (result != null) { + lastModified = result.getTime(); + lastModifiedDate = result; + } + } + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return lastModified; + } + + + /** + * Set last modified. + * + * @param lastModified New last modified value + */ + public void setLastModified(long lastModified) { + this.lastModified = lastModified; + this.lastModifiedDate = null; + if (attributes != null) + attributes.put(LAST_MODIFIED, new Date(lastModified)); + } + + + /** + * Set last modified date. + * + * @param lastModified New last modified date value + * @deprecated + */ + public void setLastModified(Date lastModified) { + setLastModifiedDate(lastModified); + } + + + /** + * Get lastModified date. + * + * @return LastModified date value + */ + public Date getLastModifiedDate() { + if (lastModifiedDate != null) + return lastModifiedDate; + if (lastModified != -1L) { + lastModifiedDate = new Date(lastModified); + return lastModifiedDate; + } + if (attributes != null) { + Attribute attribute = attributes.get(LAST_MODIFIED); + if (attribute != null) { + try { + Object value = attribute.get(); + if (value instanceof Long) { + lastModified = ((Long) value).longValue(); + lastModifiedDate = new Date(lastModified); + } else if (value instanceof Date) { + lastModified = ((Date) value).getTime(); + lastModifiedDate = (Date) value; + } else { + String lastModifiedDateValue = value.toString(); + Date result = null; + // Parsing the HTTP Date + for (int i = 0; (result == null) && + (i < formats.length); i++) { + try { + result = + formats[i].parse(lastModifiedDateValue); + } catch (ParseException e) { + ; + } + } + if (result != null) { + lastModified = result.getTime(); + lastModifiedDate = result; + } + } + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return lastModifiedDate; + } + + + /** + * Last modified date mutator. + * + * @param lastModifiedDate New last modified date + */ + public void setLastModifiedDate(Date lastModifiedDate) { + this.lastModified = lastModifiedDate.getTime(); + this.lastModifiedDate = lastModifiedDate; + if (attributes != null) + attributes.put(LAST_MODIFIED, lastModifiedDate); + } + + + /** + * @return Returns the lastModifiedHttp. + */ + public String getLastModifiedHttp() { + if (lastModifiedHttp != null) + return lastModifiedHttp; + Date modifiedDate = getLastModifiedDate(); + if (modifiedDate == null) { + modifiedDate = getCreationDate(); + } + if (modifiedDate == null) { + modifiedDate = new Date(); + } + synchronized (format) { + lastModifiedHttp = format.format(modifiedDate); + } + return lastModifiedHttp; + } + + + /** + * @param lastModifiedHttp The lastModifiedHttp to set. + */ + public void setLastModifiedHttp(String lastModifiedHttp) { + this.lastModifiedHttp = lastModifiedHttp; + } + + + /** + * @return Returns the mimeType. + */ + public String getMimeType() { + return mimeType; + } + + + /** + * @param mimeType The mimeType to set. + */ + public void setMimeType(String mimeType) { + this.mimeType = mimeType; + } + + + /** + * Get name. + * + * @return Name value + */ + public String getName() { + if (name != null) + return name; + if (attributes != null) { + Attribute attribute = attributes.get(NAME); + if (attribute != null) { + try { + name = attribute.get().toString(); + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + return name; + } + + + /** + * Set name. + * + * @param name New name value + */ + public void setName(String name) { + this.name = name; + if (attributes != null) + attributes.put(NAME, name); + } + + + /** + * Get resource type. + * + * @return String resource type + */ + public String getResourceType() { + String result = null; + if (attributes != null) { + Attribute attribute = attributes.get(TYPE); + if (attribute != null) { + try { + result = attribute.get().toString(); + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + if (result == null) { + if (collection) + result = COLLECTION_TYPE; + else + result = ""; + } + return result; + } + + + /** + * Type mutator. + * + * @param resourceType New resource type + */ + public void setResourceType(String resourceType) { + collection = resourceType.equals(COLLECTION_TYPE); + if (attributes != null) + attributes.put(TYPE, resourceType); + } + + + /** + * Get ETag. + * + * @return Weak ETag + */ + public String getETag() { + return getETag(false); + } + + + /** + * Get ETag. + * + * @param strong If true, the strong ETag will be returned + * @return ETag + */ + public String getETag(boolean strong) { + String result = null; + if (attributes != null) { + Attribute attribute = attributes.get(ETAG); + if (attribute != null) { + try { + result = attribute.get().toString(); + } catch (NamingException e) { + ; // No value for the attribute + } + } + } + if (strong) { + // The strong ETag must always be calculated by the resources + result = strongETag; + } else { + // The weakETag is contentLenght + lastModified + if (weakETag == null) { + weakETag = "W/\"" + getContentLength() + "-" + + getLastModified() + "\""; + } + result = weakETag; + } + return result; + } + + + /** + * Set strong ETag. + */ + public void setETag(String eTag) { + this.strongETag = eTag; + if (attributes != null) + attributes.put(ETAG, eTag); + } + + + /** + * Return the canonical path of the resource, to possibly be used for + * direct file serving. Implementations which support this should override + * it to return the file path. + * + * @return The canonical path of the resource + */ + public String getCanonicalPath() { + return null; + } + + + // ----------------------------------------------------- Attributes Methods + + + /** + * Get attribute. + */ + public Attribute get(String attrID) { + if (attributes == null) { + if (attrID.equals(CREATION_DATE)) { + return new BasicAttribute(CREATION_DATE, getCreationDate()); + } else if (attrID.equals(ALTERNATE_CREATION_DATE)) { + return new BasicAttribute(ALTERNATE_CREATION_DATE, + getCreationDate()); + } else if (attrID.equals(LAST_MODIFIED)) { + return new BasicAttribute(LAST_MODIFIED, + getLastModifiedDate()); + } else if (attrID.equals(ALTERNATE_LAST_MODIFIED)) { + return new BasicAttribute(ALTERNATE_LAST_MODIFIED, + getLastModifiedDate()); + } else if (attrID.equals(NAME)) { + return new BasicAttribute(NAME, getName()); + } else if (attrID.equals(TYPE)) { + return new BasicAttribute(TYPE, getResourceType()); + } else if (attrID.equals(ALTERNATE_TYPE)) { + return new BasicAttribute(ALTERNATE_TYPE, getResourceType()); + } else if (attrID.equals(CONTENT_LENGTH)) { + return new BasicAttribute(CONTENT_LENGTH, + new Long(getContentLength())); + } else if (attrID.equals(ALTERNATE_CONTENT_LENGTH)) { + return new BasicAttribute(ALTERNATE_CONTENT_LENGTH, + new Long(getContentLength())); + } + } else { + return attributes.get(attrID); + } + return null; + } + + + /** + * Put attribute. + */ + public Attribute put(Attribute attribute) { + if (attributes == null) { + try { + return put(attribute.getID(), attribute.get()); + } catch (NamingException e) { + return null; + } + } else { + return attributes.put(attribute); + } + } + + + /** + * Put attribute. + */ + public Attribute put(String attrID, Object val) { + if (attributes == null) { + return null; // No reason to implement this + } else { + return attributes.put(attrID, val); + } + } + + + /** + * Remove attribute. + */ + public Attribute remove(String attrID) { + if (attributes == null) { + return null; // No reason to implement this + } else { + return attributes.remove(attrID); + } + } + + + /** + * Get all attributes. + */ + public NamingEnumeration getAll() { + if (attributes == null) { + Vector attributes = new Vector(); + attributes.addElement(new BasicAttribute + (CREATION_DATE, getCreationDate())); + attributes.addElement(new BasicAttribute + (LAST_MODIFIED, getLastModifiedDate())); + attributes.addElement(new BasicAttribute(NAME, getName())); + attributes.addElement(new BasicAttribute(TYPE, getResourceType())); + attributes.addElement + (new BasicAttribute(CONTENT_LENGTH, + new Long(getContentLength()))); + return new RecyclableNamingEnumeration(attributes); + } else { + return attributes.getAll(); + } + } + + + /** + * Get all attribute IDs. + */ + public NamingEnumeration getIDs() { + if (attributes == null) { + Vector attributeIDs = new Vector(); + attributeIDs.addElement(CREATION_DATE); + attributeIDs.addElement(LAST_MODIFIED); + attributeIDs.addElement(NAME); + attributeIDs.addElement(TYPE); + attributeIDs.addElement(CONTENT_LENGTH); + return new RecyclableNamingEnumeration(attributeIDs); + } else { + return attributes.getIDs(); + } + } + + + /** + * Retrieves the number of attributes in the attribute set. + */ + public int size() { + if (attributes == null) { + return 5; + } else { + return attributes.size(); + } + } + + + /** + * Clone the attributes object (WARNING: fake cloning). + */ + public Object clone() { + return this; + } + + + /** + * Case sensitivity. + */ + public boolean isCaseIgnored() { + return false; + } + + +} diff --git a/java/org/apache/naming/resources/ResourceCache.java b/java/org/apache/naming/resources/ResourceCache.java index 9c763dbf6..a82fe0ef7 100644 --- a/java/org/apache/naming/resources/ResourceCache.java +++ b/java/org/apache/naming/resources/ResourceCache.java @@ -1,420 +1,420 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources; - -import java.util.HashMap; -import java.util.Random; - - -/** - * Implements a special purpose cache. - * - * @author Remy Maucherat - * @version $Revision: 304084 $ - */ -public class ResourceCache { - - - // ----------------------------------------------------------- Constructors - - - public ResourceCache() { - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Random generator used to determine elements to free. - */ - protected Random random = new Random(); - - - /** - * Cache. - * Path -> Cache entry. - */ - protected CacheEntry[] cache = new CacheEntry[0]; - - - /** - * Not found cache. - */ - protected HashMap notFoundCache = new HashMap(); - - - /** - * Max size of resources which will have their content cached. - */ - protected int cacheMaxSize = 10240; // 10 MB - - - /** - * Max amount of removals during a make space. - */ - protected int maxAllocateIterations = 20; - - - /** - * Entry hit ratio at which an entry will never be removed from the cache. - * Compared with entry.access / hitsCount - */ - protected long desiredEntryAccessRatio = 3; - - - /** - * Spare amount of not found entries. - */ - protected int spareNotFoundEntries = 500; - - - /** - * Current cache size in KB. - */ - protected int cacheSize = 0; - - - /** - * Number of accesses to the cache. - */ - protected long accessCount = 0; - - - /** - * Number of cache hits. - */ - protected long hitsCount = 0; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the access count. - * Note: Update is not synced, so the number may not be completely - * accurate. - */ - public long getAccessCount() { - return accessCount; - } - - - /** - * Return the maximum size of the cache in KB. - */ - public int getCacheMaxSize() { - return cacheMaxSize; - } - - - /** - * Set the maximum size of the cache in KB. - */ - public void setCacheMaxSize(int cacheMaxSize) { - this.cacheMaxSize = cacheMaxSize; - } - - - /** - * Return the current cache size in KB. - */ - public int getCacheSize() { - return cacheSize; - } - - - /** - * Return desired entry access ratio. - */ - public long getDesiredEntryAccessRatio() { - return desiredEntryAccessRatio; - } - - - /** - * Set the desired entry access ratio. - */ - public void setDesiredEntryAccessRatio(long desiredEntryAccessRatio) { - this.desiredEntryAccessRatio = desiredEntryAccessRatio; - } - - - /** - * Return the number of cache hits. - * Note: Update is not synced, so the number may not be completely - * accurate. - */ - public long getHitsCount() { - return hitsCount; - } - - - /** - * Return the maximum amount of iterations during a space allocation. - */ - public int getMaxAllocateIterations() { - return maxAllocateIterations; - } - - - /** - * Set the maximum amount of iterations during a space allocation. - */ - public void setMaxAllocateIterations(int maxAllocateIterations) { - this.maxAllocateIterations = maxAllocateIterations; - } - - - /** - * Return the amount of spare not found entries. - */ - public int getSpareNotFoundEntries() { - return spareNotFoundEntries; - } - - - /** - * Set the amount of spare not found entries. - */ - public void setSpareNotFoundEntries(int spareNotFoundEntries) { - this.spareNotFoundEntries = spareNotFoundEntries; - } - - - // --------------------------------------------------------- Public Methods - - - public boolean allocate(int space) { - - int toFree = space - (cacheMaxSize - cacheSize); - - if (toFree <= 0) { - return true; - } - - // Increase the amount to free so that allocate won't have to run right - // away again - toFree += (cacheMaxSize / 20); - - int size = notFoundCache.size(); - if (size > spareNotFoundEntries) { - notFoundCache.clear(); - cacheSize -= size; - toFree -= size; - } - - if (toFree <= 0) { - return true; - } - - int attempts = 0; - int entriesFound = 0; - long totalSpace = 0; - int[] toRemove = new int[maxAllocateIterations]; - while (toFree > 0) { - if (attempts == maxAllocateIterations) { - // Give up, no changes are made to the current cache - return false; - } - if (toFree > 0) { - // Randomly select an entry in the array - int entryPos = -1; - boolean unique = false; - while (!unique) { - unique = true; - entryPos = random.nextInt(cache.length) ; - // Guarantee uniqueness - for (int i = 0; i < entriesFound; i++) { - if (toRemove[i] == entryPos) { - unique = false; - } - } - } - long entryAccessRatio = - ((cache[entryPos].accessCount * 100) / accessCount); - if (entryAccessRatio < desiredEntryAccessRatio) { - toRemove[entriesFound] = entryPos; - totalSpace += cache[entryPos].size; - toFree -= cache[entryPos].size; - entriesFound++; - } - } - attempts++; - } - - // Now remove the selected entries - java.util.Arrays.sort(toRemove, 0, entriesFound); - CacheEntry[] newCache = new CacheEntry[cache.length - entriesFound]; - int pos = 0; - int n = -1; - if (entriesFound > 0) { - n = toRemove[0]; - for (int i = 0; i < cache.length; i++) { - if (i == n) { - if ((pos + 1) < entriesFound) { - n = toRemove[pos + 1]; - pos++; - } else { - pos++; - n = -1; - } - } else { - newCache[i - pos] = cache[i]; - } - } - } - cache = newCache; - cacheSize -= totalSpace; - - return true; - - } - - - public CacheEntry lookup(String name) { - - CacheEntry cacheEntry = null; - accessCount++; - int pos = find(cache, name); - if ((pos != -1) && (name.equals(cache[pos].name))) { - cacheEntry = cache[pos]; - } - if (cacheEntry == null) { - try { - cacheEntry = (CacheEntry) notFoundCache.get(name); - } catch (Exception e) { - // Ignore: the reliability of this lookup is not critical - } - } - if (cacheEntry != null) { - hitsCount++; - } - return cacheEntry; - - } - - - public void load(CacheEntry entry) { - if (entry.exists) { - if (insertCache(entry)) { - cacheSize += entry.size; - } - } else { - int sizeIncrement = (notFoundCache.get(entry.name) == null) ? 1 : 0; - notFoundCache.put(entry.name, entry); - cacheSize += sizeIncrement; - } - } - - - public boolean unload(String name) { - CacheEntry removedEntry = removeCache(name); - if (removedEntry != null) { - cacheSize -= removedEntry.size; - return true; - } else if (notFoundCache.remove(name) != null) { - cacheSize--; - return true; - } - return false; - } - - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int find(CacheEntry[] map, String name) { - - int a = 0; - int b = map.length - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - if (name.compareTo(map[0].name) < 0) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = name.compareTo(map[i].name); - if (result > 0) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = name.compareTo(map[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - - /** - * Insert into the right place in a sorted MapElement array, and prevent - * duplicates. - */ - private final boolean insertCache(CacheEntry newElement) { - CacheEntry[] oldCache = cache; - int pos = find(oldCache, newElement.name); - if ((pos != -1) && (newElement.name.equals(oldCache[pos].name))) { - return false; - } - CacheEntry[] newCache = new CacheEntry[cache.length + 1]; - System.arraycopy(oldCache, 0, newCache, 0, pos + 1); - newCache[pos + 1] = newElement; - System.arraycopy - (oldCache, pos + 1, newCache, pos + 2, oldCache.length - pos - 1); - cache = newCache; - return true; - } - - - /** - * Insert into the right place in a sorted MapElement array. - */ - private final CacheEntry removeCache(String name) { - CacheEntry[] oldCache = cache; - int pos = find(oldCache, name); - if ((pos != -1) && (name.equals(oldCache[pos].name))) { - CacheEntry[] newCache = new CacheEntry[cache.length - 1]; - System.arraycopy(oldCache, 0, newCache, 0, pos); - System.arraycopy(oldCache, pos + 1, newCache, pos, - oldCache.length - pos - 1); - cache = newCache; - return oldCache[pos]; - } - return null; - } - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources; + +import java.util.HashMap; +import java.util.Random; + + +/** + * Implements a special purpose cache. + * + * @author Remy Maucherat + * @version $Revision: 304084 $ + */ +public class ResourceCache { + + + // ----------------------------------------------------------- Constructors + + + public ResourceCache() { + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Random generator used to determine elements to free. + */ + protected Random random = new Random(); + + + /** + * Cache. + * Path -> Cache entry. + */ + protected CacheEntry[] cache = new CacheEntry[0]; + + + /** + * Not found cache. + */ + protected HashMap notFoundCache = new HashMap(); + + + /** + * Max size of resources which will have their content cached. + */ + protected int cacheMaxSize = 10240; // 10 MB + + + /** + * Max amount of removals during a make space. + */ + protected int maxAllocateIterations = 20; + + + /** + * Entry hit ratio at which an entry will never be removed from the cache. + * Compared with entry.access / hitsCount + */ + protected long desiredEntryAccessRatio = 3; + + + /** + * Spare amount of not found entries. + */ + protected int spareNotFoundEntries = 500; + + + /** + * Current cache size in KB. + */ + protected int cacheSize = 0; + + + /** + * Number of accesses to the cache. + */ + protected long accessCount = 0; + + + /** + * Number of cache hits. + */ + protected long hitsCount = 0; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the access count. + * Note: Update is not synced, so the number may not be completely + * accurate. + */ + public long getAccessCount() { + return accessCount; + } + + + /** + * Return the maximum size of the cache in KB. + */ + public int getCacheMaxSize() { + return cacheMaxSize; + } + + + /** + * Set the maximum size of the cache in KB. + */ + public void setCacheMaxSize(int cacheMaxSize) { + this.cacheMaxSize = cacheMaxSize; + } + + + /** + * Return the current cache size in KB. + */ + public int getCacheSize() { + return cacheSize; + } + + + /** + * Return desired entry access ratio. + */ + public long getDesiredEntryAccessRatio() { + return desiredEntryAccessRatio; + } + + + /** + * Set the desired entry access ratio. + */ + public void setDesiredEntryAccessRatio(long desiredEntryAccessRatio) { + this.desiredEntryAccessRatio = desiredEntryAccessRatio; + } + + + /** + * Return the number of cache hits. + * Note: Update is not synced, so the number may not be completely + * accurate. + */ + public long getHitsCount() { + return hitsCount; + } + + + /** + * Return the maximum amount of iterations during a space allocation. + */ + public int getMaxAllocateIterations() { + return maxAllocateIterations; + } + + + /** + * Set the maximum amount of iterations during a space allocation. + */ + public void setMaxAllocateIterations(int maxAllocateIterations) { + this.maxAllocateIterations = maxAllocateIterations; + } + + + /** + * Return the amount of spare not found entries. + */ + public int getSpareNotFoundEntries() { + return spareNotFoundEntries; + } + + + /** + * Set the amount of spare not found entries. + */ + public void setSpareNotFoundEntries(int spareNotFoundEntries) { + this.spareNotFoundEntries = spareNotFoundEntries; + } + + + // --------------------------------------------------------- Public Methods + + + public boolean allocate(int space) { + + int toFree = space - (cacheMaxSize - cacheSize); + + if (toFree <= 0) { + return true; + } + + // Increase the amount to free so that allocate won't have to run right + // away again + toFree += (cacheMaxSize / 20); + + int size = notFoundCache.size(); + if (size > spareNotFoundEntries) { + notFoundCache.clear(); + cacheSize -= size; + toFree -= size; + } + + if (toFree <= 0) { + return true; + } + + int attempts = 0; + int entriesFound = 0; + long totalSpace = 0; + int[] toRemove = new int[maxAllocateIterations]; + while (toFree > 0) { + if (attempts == maxAllocateIterations) { + // Give up, no changes are made to the current cache + return false; + } + if (toFree > 0) { + // Randomly select an entry in the array + int entryPos = -1; + boolean unique = false; + while (!unique) { + unique = true; + entryPos = random.nextInt(cache.length) ; + // Guarantee uniqueness + for (int i = 0; i < entriesFound; i++) { + if (toRemove[i] == entryPos) { + unique = false; + } + } + } + long entryAccessRatio = + ((cache[entryPos].accessCount * 100) / accessCount); + if (entryAccessRatio < desiredEntryAccessRatio) { + toRemove[entriesFound] = entryPos; + totalSpace += cache[entryPos].size; + toFree -= cache[entryPos].size; + entriesFound++; + } + } + attempts++; + } + + // Now remove the selected entries + java.util.Arrays.sort(toRemove, 0, entriesFound); + CacheEntry[] newCache = new CacheEntry[cache.length - entriesFound]; + int pos = 0; + int n = -1; + if (entriesFound > 0) { + n = toRemove[0]; + for (int i = 0; i < cache.length; i++) { + if (i == n) { + if ((pos + 1) < entriesFound) { + n = toRemove[pos + 1]; + pos++; + } else { + pos++; + n = -1; + } + } else { + newCache[i - pos] = cache[i]; + } + } + } + cache = newCache; + cacheSize -= totalSpace; + + return true; + + } + + + public CacheEntry lookup(String name) { + + CacheEntry cacheEntry = null; + accessCount++; + int pos = find(cache, name); + if ((pos != -1) && (name.equals(cache[pos].name))) { + cacheEntry = cache[pos]; + } + if (cacheEntry == null) { + try { + cacheEntry = (CacheEntry) notFoundCache.get(name); + } catch (Exception e) { + // Ignore: the reliability of this lookup is not critical + } + } + if (cacheEntry != null) { + hitsCount++; + } + return cacheEntry; + + } + + + public void load(CacheEntry entry) { + if (entry.exists) { + if (insertCache(entry)) { + cacheSize += entry.size; + } + } else { + int sizeIncrement = (notFoundCache.get(entry.name) == null) ? 1 : 0; + notFoundCache.put(entry.name, entry); + cacheSize += sizeIncrement; + } + } + + + public boolean unload(String name) { + CacheEntry removedEntry = removeCache(name); + if (removedEntry != null) { + cacheSize -= removedEntry.size; + return true; + } else if (notFoundCache.remove(name) != null) { + cacheSize--; + return true; + } + return false; + } + + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int find(CacheEntry[] map, String name) { + + int a = 0; + int b = map.length - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + if (name.compareTo(map[0].name) < 0) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = name.compareTo(map[i].name); + if (result > 0) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = name.compareTo(map[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + + /** + * Insert into the right place in a sorted MapElement array, and prevent + * duplicates. + */ + private final boolean insertCache(CacheEntry newElement) { + CacheEntry[] oldCache = cache; + int pos = find(oldCache, newElement.name); + if ((pos != -1) && (newElement.name.equals(oldCache[pos].name))) { + return false; + } + CacheEntry[] newCache = new CacheEntry[cache.length + 1]; + System.arraycopy(oldCache, 0, newCache, 0, pos + 1); + newCache[pos + 1] = newElement; + System.arraycopy + (oldCache, pos + 1, newCache, pos + 2, oldCache.length - pos - 1); + cache = newCache; + return true; + } + + + /** + * Insert into the right place in a sorted MapElement array. + */ + private final CacheEntry removeCache(String name) { + CacheEntry[] oldCache = cache; + int pos = find(oldCache, name); + if ((pos != -1) && (name.equals(oldCache[pos].name))) { + CacheEntry[] newCache = new CacheEntry[cache.length - 1]; + System.arraycopy(oldCache, 0, newCache, 0, pos); + System.arraycopy(oldCache, pos + 1, newCache, pos, + oldCache.length - pos - 1); + cache = newCache; + return oldCache[pos]; + } + return null; + } + +} diff --git a/java/org/apache/naming/resources/WARDirContext.java b/java/org/apache/naming/resources/WARDirContext.java index 3414b65d6..20ccd87bf 100644 --- a/java/org/apache/naming/resources/WARDirContext.java +++ b/java/org/apache/naming/resources/WARDirContext.java @@ -1,953 +1,953 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.naming.resources; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.zip.ZipEntry; -import java.util.zip.ZipException; -import java.util.zip.ZipFile; - -import javax.naming.CompositeName; -import javax.naming.Name; -import javax.naming.NamingEnumeration; -import javax.naming.NamingException; -import javax.naming.OperationNotSupportedException; -import javax.naming.directory.Attributes; -import javax.naming.directory.DirContext; -import javax.naming.directory.ModificationItem; -import javax.naming.directory.SearchControls; - -import org.apache.naming.NamingContextBindingsEnumeration; -import org.apache.naming.NamingContextEnumeration; -import org.apache.naming.NamingEntry; - -/** - * WAR Directory Context implementation. - * - * @author Remy Maucherat - * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ - */ - -public class WARDirContext extends BaseDirContext { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( WARDirContext.class ); - - // ----------------------------------------------------------- Constructors - - - /** - * Builds a WAR directory context using the given environment. - */ - public WARDirContext() { - super(); - } - - - /** - * Builds a WAR directory context using the given environment. - */ - public WARDirContext(Hashtable env) { - super(env); - } - - - /** - * Constructor used for returning fake subcontexts. - */ - protected WARDirContext(ZipFile base, Entry entries) { - this.base = base; - this.entries = entries; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The WAR file. - */ - protected ZipFile base = null; - - - /** - * WAR entries. - */ - protected Entry entries = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Set the document root. - * - * @param docBase The new document root - * - * @exception IllegalArgumentException if the specified value is not - * supported by this implementation - * @exception IllegalArgumentException if this would create a - * malformed URL - */ - public void setDocBase(String docBase) { - - // Validate the format of the proposed document root - if (docBase == null) - throw new IllegalArgumentException - (sm.getString("resources.null")); - if (!(docBase.endsWith(".war"))) - throw new IllegalArgumentException - (sm.getString("warResources.notWar")); - - // Calculate a File object referencing this document base directory - File base = new File(docBase); - - // Validate that the document base is an existing directory - if (!base.exists() || !base.canRead() || base.isDirectory()) - throw new IllegalArgumentException - (sm.getString("warResources.invalidWar", docBase)); - try { - this.base = new ZipFile(base); - } catch (Exception e) { - throw new IllegalArgumentException - (sm.getString("warResources.invalidWar", e.getMessage())); - } - super.setDocBase(docBase); - - loadEntries(); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Release any resources allocated for this directory context. - */ - public void release() { - - entries = null; - if (base != null) { - try { - base.close(); - } catch (IOException e) { - log.warn - ("Exception closing WAR File " + base.getName(), e); - } - } - base = null; - super.release(); - - } - - - // -------------------------------------------------------- Context Methods - - - /** - * Retrieves the named object. - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(String name) - throws NamingException { - return lookup(new CompositeName(name)); - } - - - /** - * Retrieves the named object. If name is empty, returns a new instance - * of this context (which represents the same naming context as this - * context, but its environment may be modified independently and it may - * be accessed concurrently). - * - * @param name the name of the object to look up - * @return the object bound to name - * @exception NamingException if a naming exception is encountered - */ - public Object lookup(Name name) - throws NamingException { - if (name.isEmpty()) - return this; - Entry entry = treeLookup(name); - if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - ZipEntry zipEntry = entry.getEntry(); - if (zipEntry.isDirectory()) - return new WARDirContext(base, entry); - else - return new WARResource(entry.getEntry()); - } - - - /** - * Unbinds the named object. Removes the terminal atomic name in name - * from the target context--that named by all but the terminal atomic - * part of name. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * @param name the name to bind; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NamingException if a naming exception is encountered - */ - public void unbind(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Binds a new name to the object bound to an old name, and unbinds the - * old name. Both names are relative to this context. Any attributes - * associated with the old name become associated with the new name. - * Intermediate contexts of the old name are not changed. - * - * @param oldName the name of the existing binding; may not be empty - * @param newName the name of the new binding; may not be empty - * @exception NameAlreadyBoundException if newName is already bound - * @exception NamingException if a naming exception is encountered - */ - public void rename(String oldName, String newName) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(String name) - throws NamingException { - return list(new CompositeName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the class - * names of objects bound to them. The contents of any subcontexts are - * not included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the names and class names of the bindings in - * this context. Each element of the enumeration is of type NameClassPair. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration list(Name name) - throws NamingException { - if (name.isEmpty()) - return new NamingContextEnumeration(list(entries).iterator()); - Entry entry = treeLookup(name); - if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - return new NamingContextEnumeration(list(entry).iterator()); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(String name) - throws NamingException { - return listBindings(new CompositeName(name)); - } - - - /** - * Enumerates the names bound in the named context, along with the - * objects bound to them. The contents of any subcontexts are not - * included. - *

        - * If a binding is added to or removed from this context, its effect on - * an enumeration previously returned is undefined. - * - * @param name the name of the context to list - * @return an enumeration of the bindings in this context. - * Each element of the enumeration is of type Binding. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration listBindings(Name name) - throws NamingException { - if (name.isEmpty()) - return new NamingContextBindingsEnumeration(list(entries).iterator(), - this); - Entry entry = treeLookup(name); - if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - return new NamingContextBindingsEnumeration(list(entry).iterator(), - this); - } - - - /** - * Destroys the named context and removes it from the namespace. Any - * attributes associated with the name are also removed. Intermediate - * contexts are not destroyed. - *

        - * This method is idempotent. It succeeds even if the terminal atomic - * name is not bound in the target context, but throws - * NameNotFoundException if any of the intermediate contexts do not exist. - * - * In a federated naming system, a context from one naming system may be - * bound to a name in another. One can subsequently look up and perform - * operations on the foreign context using a composite name. However, an - * attempt destroy the context using this composite name will fail with - * NotContextException, because the foreign context is not a "subcontext" - * of the context in which it is bound. Instead, use unbind() to remove - * the binding of the foreign context. Destroying the foreign context - * requires that the destroySubcontext() be performed on a context from - * the foreign context's "native" naming system. - * - * @param name the name of the context to be destroyed; may not be empty - * @exception NameNotFoundException if an intermediate context does not - * exist - * @exception NotContextException if the name is bound but does not name - * a context, or does not name a context of the appropriate type - */ - public void destroySubcontext(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Retrieves the named object, following links except for the terminal - * atomic component of the name. If the object bound to name is not a - * link, returns the object itself. - * - * @param name the name of the object to look up - * @return the object bound to name, not following the terminal link - * (if any). - * @exception NamingException if a naming exception is encountered - */ - public Object lookupLink(String name) - throws NamingException { - // Note : Links are not supported - return lookup(name); - } - - - /** - * Retrieves the full name of this context within its own namespace. - *

        - * Many naming services have a notion of a "full name" for objects in - * their respective namespaces. For example, an LDAP entry has a - * distinguished name, and a DNS record has a fully qualified name. This - * method allows the client application to retrieve this name. The string - * returned by this method is not a JNDI composite name and should not be - * passed directly to context methods. In naming systems for which the - * notion of full name does not make sense, - * OperationNotSupportedException is thrown. - * - * @return this context's name in its own namespace; never null - * @exception OperationNotSupportedException if the naming system does - * not have the notion of a full name - * @exception NamingException if a naming exception is encountered - */ - public String getNameInNamespace() - throws NamingException { - return docBase; - } - - - // ----------------------------------------------------- DirContext Methods - - - /** - * Retrieves selected attributes associated with a named object. - * See the class description regarding attribute models, attribute type - * names, and operational attributes. - * - * @return the requested attributes; never null - * @param name the name of the object from which to retrieve attributes - * @param attrIds the identifiers of the attributes to retrieve. null - * indicates that all attributes should be retrieved; an empty array - * indicates that none should be retrieved - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(String name, String[] attrIds) - throws NamingException { - return getAttributes(new CompositeName(name), attrIds); - } - - - /** - * Retrieves all of the attributes associated with a named object. - * - * @return the set of attributes associated with name. - * Returns an empty attribute set if name has no attributes; never null. - * @param name the name of the object from which to retrieve attributes - * @exception NamingException if a naming exception is encountered - */ - public Attributes getAttributes(Name name, String[] attrIds) - throws NamingException { - - Entry entry = null; - if (name.isEmpty()) - entry = entries; - else - entry = treeLookup(name); - if (entry == null) - throw new NamingException - (sm.getString("resources.notFound", name)); - - ZipEntry zipEntry = entry.getEntry(); - - ResourceAttributes attrs = new ResourceAttributes(); - attrs.setCreationDate(new Date(zipEntry.getTime())); - attrs.setName(entry.getName()); - if (!zipEntry.isDirectory()) - attrs.setResourceType(""); - attrs.setContentLength(zipEntry.getSize()); - attrs.setLastModified(zipEntry.getTime()); - - return attrs; - - } - - - /** - * Modifies the attributes associated with a named object. The order of - * the modifications is not specified. Where possible, the modifications - * are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, - * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE - * @param attrs the attributes to be used for the modification; may not - * be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, int mod_op, Attributes attrs) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Modifies the attributes associated with a named object using an an - * ordered list of modifications. The modifications are performed in the - * order specified. Each modification specifies a modification operation - * code and an attribute on which to operate. Where possible, the - * modifications are performed atomically. - * - * @param name the name of the object whose attributes will be updated - * @param mods an ordered sequence of modifications to be performed; may - * not be null - * @exception AttributeModificationException if the modification cannot be - * completed successfully - * @exception NamingException if a naming exception is encountered - */ - public void modifyAttributes(String name, ModificationItem[] mods) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Binds a name to an object, along with associated attributes. If attrs - * is null, the resulting binding will have the attributes associated - * with obj if obj is a DirContext, and no attributes otherwise. If attrs - * is non-null, the resulting binding will have attrs as its attributes; - * any attributes associated with obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception NameAlreadyBoundException if name is already bound - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void bind(String name, Object obj, Attributes attrs) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Binds a name to an object, along with associated attributes, - * overwriting any existing binding. If attrs is null and obj is a - * DirContext, the attributes from obj are used. If attrs is null and obj - * is not a DirContext, any existing attributes associated with the object - * already bound in the directory remain unchanged. If attrs is non-null, - * any existing attributes associated with the object already bound in - * the directory are removed and attrs is associated with the named - * object. If obj is a DirContext and attrs is non-null, the attributes - * of obj are ignored. - * - * @param name the name to bind; may not be empty - * @param obj the object to bind; possibly null - * @param attrs the attributes to associate with the binding - * @exception InvalidAttributesException if some "mandatory" attributes - * of the binding are not supplied - * @exception NamingException if a naming exception is encountered - */ - public void rebind(String name, Object obj, Attributes attrs) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Creates and binds a new context, along with associated attributes. - * This method creates a new subcontext with the given name, binds it in - * the target context (that named by all but terminal atomic component of - * the name), and associates the supplied attributes with the newly - * created object. All intermediate and target contexts must already - * exist. If attrs is null, this method is equivalent to - * Context.createSubcontext(). - * - * @param name the name of the context to create; may not be empty - * @param attrs the attributes to associate with the newly created context - * @return the newly created context - * @exception NameAlreadyBoundException if the name is already bound - * @exception InvalidAttributesException if attrs does not contain all - * the mandatory attributes required for creation - * @exception NamingException if a naming exception is encountered - */ - public DirContext createSubcontext(String name, Attributes attrs) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Retrieves the schema associated with the named object. The schema - * describes rules regarding the structure of the namespace and the - * attributes stored within it. The schema specifies what types of - * objects can be added to the directory and where they can be added; - * what mandatory and optional attributes an object can have. The range - * of support for schemas is directory-specific. - * - * @param name the name of the object whose schema is to be retrieved - * @return the schema associated with the context; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchema(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Retrieves a context containing the schema objects of the named - * object's class definitions. - * - * @param name the name of the object whose object class definition is to - * be retrieved - * @return the DirContext containing the named object's class - * definitions; never null - * @exception OperationNotSupportedException if schema not supported - * @exception NamingException if a naming exception is encountered - */ - public DirContext getSchemaClassDefinition(String name) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes, and retrieves selected attributes. The search is - * performed using the default SearchControls settings. - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @param attributesToReturn the attributes to return. null indicates - * that all attributes are to be returned; an empty array indicates that - * none are to be returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes, - String[] attributesToReturn) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Searches in a single context for objects that contain a specified set - * of attributes. This method returns all the attributes of such objects. - * It is equivalent to supplying null as the atributesToReturn parameter - * to the method search(Name, Attributes, String[]). - * - * @param name the name of the context to search - * @param matchingAttributes the attributes to search for. If empty or - * null, all objects in the target context are returned. - * @return a non-null enumeration of SearchResult objects. Each - * SearchResult contains the attributes identified by attributesToReturn - * and the name of the corresponding object, named relative to the - * context named by name. - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, Attributes matchingAttributes) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filter the filter expression to use for the search; may not be - * null - * @param cons the search controls that control the search. If null, - * the default search controls are used (equivalent to - * (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisfy - * the filter; never null - * @exception InvalidSearchFilterException if the search filter specified - * is not supported or understood by the underlying directory - * @exception InvalidSearchControlsException if the search controls - * contain invalid settings - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filter, - SearchControls cons) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - /** - * Searches in the named context or object for entries that satisfy the - * given search filter. Performs the search as specified by the search - * controls. - * - * @param name the name of the context or object to search - * @param filterExpr the filter expression to use for the search. - * The expression may contain variables of the form "{i}" where i is a - * nonnegative integer. May not be null. - * @param filterArgs the array of arguments to substitute for the - * variables in filterExpr. The value of filterArgs[i] will replace each - * occurrence of "{i}". If null, equivalent to an empty array. - * @param cons the search controls that control the search. If null, the - * default search controls are used (equivalent to (new SearchControls())). - * @return an enumeration of SearchResults of the objects that satisy the - * filter; never null - * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} - * expressions where i is outside the bounds of the array filterArgs - * @exception InvalidSearchControlsException if cons contains invalid - * settings - * @exception InvalidSearchFilterException if filterExpr with filterArgs - * represents an invalid search filter - * @exception NamingException if a naming exception is encountered - */ - public NamingEnumeration search(String name, String filterExpr, - Object[] filterArgs, SearchControls cons) - throws NamingException { - throw new OperationNotSupportedException(); - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Normalize the name of an entry read from the Zip. - */ - protected String normalize(ZipEntry entry) { - - String result = "/" + entry.getName(); - if (entry.isDirectory()) { - result = result.substring(0, result.length() - 1); - } - return result; - - } - - - /** - * Constructs a tree of the entries contained in a WAR file. - */ - protected void loadEntries() { - - try { - - Enumeration entryList = base.entries(); - entries = new Entry("/", new ZipEntry("/")); - - while (entryList.hasMoreElements()) { - - ZipEntry entry = (ZipEntry) entryList.nextElement(); - String name = normalize(entry); - int pos = name.lastIndexOf('/'); - // Check that parent entries exist and, if not, create them. - // This fixes a bug for war files that don't record separate - // zip entries for the directories. - int currentPos = -1; - int lastPos = 0; - while ((currentPos = name.indexOf('/', lastPos)) != -1) { - Name parentName = new CompositeName(name.substring(0, lastPos)); - Name childName = new CompositeName(name.substring(0, currentPos)); - String entryName = name.substring(lastPos, currentPos); - // Parent should have been created in last cycle through - // this loop - Entry parent = treeLookup(parentName); - Entry child = treeLookup(childName); - if (child == null) { - // Create a new entry for missing entry and strip off - // the leading '/' character and appended on by the - // normalize method and add '/' character to end to - // signify that it is a directory entry - String zipName = name.substring(1, currentPos) + "/"; - child = new Entry(entryName, new ZipEntry(zipName)); - if (parent != null) - parent.addChild(child); - } - // Increment lastPos - lastPos = currentPos + 1; - } - String entryName = name.substring(pos + 1, name.length()); - Name compositeName = new CompositeName(name.substring(0, pos)); - Entry parent = treeLookup(compositeName); - Entry child = new Entry(entryName, entry); - if (parent != null) - parent.addChild(child); - - } - - } catch (Exception e) { - } - - } - - - /** - * Entry tree lookup. - */ - protected Entry treeLookup(Name name) { - if (name.isEmpty()) - return entries; - Entry currentEntry = entries; - for (int i = 0; i < name.size(); i++) { - if (name.get(i).length() == 0) - continue; - currentEntry = currentEntry.getChild(name.get(i)); - if (currentEntry == null) - return null; - } - return currentEntry; - } - - - /** - * List children as objects. - */ - protected ArrayList list(Entry entry) { - - ArrayList entries = new ArrayList(); - Entry[] children = entry.getChildren(); - Arrays.sort(children); - NamingEntry namingEntry = null; - - for (int i = 0; i < children.length; i++) { - ZipEntry current = children[i].getEntry(); - Object object = null; - if (current.isDirectory()) { - object = new WARDirContext(base, children[i]); - } else { - object = new WARResource(current); - } - namingEntry = new NamingEntry - (children[i].getName(), object, NamingEntry.ENTRY); - entries.add(namingEntry); - } - - return entries; - - } - - - // ---------------------------------------------------- Entries Inner Class - - - /** - * Entries structure. - */ - protected class Entry implements Comparable { - - - // -------------------------------------------------------- Constructor - - - public Entry(String name, ZipEntry entry) { - this.name = name; - this.entry = entry; - } - - - // --------------------------------------------------- Member Variables - - - protected String name = null; - - - protected ZipEntry entry = null; - - - protected Entry children[] = new Entry[0]; - - - // ----------------------------------------------------- Public Methods - - - public int compareTo(Object o) { - if (!(o instanceof Entry)) - return (+1); - return (name.compareTo(((Entry) o).getName())); - } - - public ZipEntry getEntry() { - return entry; - } - - - public String getName() { - return name; - } - - - public void addChild(Entry entry) { - Entry[] newChildren = new Entry[children.length + 1]; - for (int i = 0; i < children.length; i++) - newChildren[i] = children[i]; - newChildren[children.length] = entry; - children = newChildren; - } - - - public Entry[] getChildren() { - return children; - } - - - public Entry getChild(String name) { - for (int i = 0; i < children.length; i++) { - if (children[i].name.equals(name)) { - return children[i]; - } - } - return null; - } - - - } - - - // ------------------------------------------------ WARResource Inner Class - - - /** - * This specialized resource implementation avoids opening the IputStream - * to the WAR right away. - */ - protected class WARResource extends Resource { - - - // -------------------------------------------------------- Constructor - - - public WARResource(ZipEntry entry) { - this.entry = entry; - } - - - // --------------------------------------------------- Member Variables - - - protected ZipEntry entry; - - - // ----------------------------------------------------- Public Methods - - - /** - * Content accessor. - * - * @return InputStream - */ - public InputStream streamContent() - throws IOException { - try { - if (binaryContent == null) { - inputStream = base.getInputStream(entry); - } - } catch (ZipException e) { - throw new IOException(e.getMessage()); - } - return super.streamContent(); - } - - - } - - -} - +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.naming.resources; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.zip.ZipEntry; +import java.util.zip.ZipException; +import java.util.zip.ZipFile; + +import javax.naming.CompositeName; +import javax.naming.Name; +import javax.naming.NamingEnumeration; +import javax.naming.NamingException; +import javax.naming.OperationNotSupportedException; +import javax.naming.directory.Attributes; +import javax.naming.directory.DirContext; +import javax.naming.directory.ModificationItem; +import javax.naming.directory.SearchControls; + +import org.apache.naming.NamingContextBindingsEnumeration; +import org.apache.naming.NamingContextEnumeration; +import org.apache.naming.NamingEntry; + +/** + * WAR Directory Context implementation. + * + * @author Remy Maucherat + * @version $Revision: 366304 $ $Date: 2006-01-05 22:42:29 +0100 (jeu., 05 janv. 2006) $ + */ + +public class WARDirContext extends BaseDirContext { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( WARDirContext.class ); + + // ----------------------------------------------------------- Constructors + + + /** + * Builds a WAR directory context using the given environment. + */ + public WARDirContext() { + super(); + } + + + /** + * Builds a WAR directory context using the given environment. + */ + public WARDirContext(Hashtable env) { + super(env); + } + + + /** + * Constructor used for returning fake subcontexts. + */ + protected WARDirContext(ZipFile base, Entry entries) { + this.base = base; + this.entries = entries; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The WAR file. + */ + protected ZipFile base = null; + + + /** + * WAR entries. + */ + protected Entry entries = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Set the document root. + * + * @param docBase The new document root + * + * @exception IllegalArgumentException if the specified value is not + * supported by this implementation + * @exception IllegalArgumentException if this would create a + * malformed URL + */ + public void setDocBase(String docBase) { + + // Validate the format of the proposed document root + if (docBase == null) + throw new IllegalArgumentException + (sm.getString("resources.null")); + if (!(docBase.endsWith(".war"))) + throw new IllegalArgumentException + (sm.getString("warResources.notWar")); + + // Calculate a File object referencing this document base directory + File base = new File(docBase); + + // Validate that the document base is an existing directory + if (!base.exists() || !base.canRead() || base.isDirectory()) + throw new IllegalArgumentException + (sm.getString("warResources.invalidWar", docBase)); + try { + this.base = new ZipFile(base); + } catch (Exception e) { + throw new IllegalArgumentException + (sm.getString("warResources.invalidWar", e.getMessage())); + } + super.setDocBase(docBase); + + loadEntries(); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Release any resources allocated for this directory context. + */ + public void release() { + + entries = null; + if (base != null) { + try { + base.close(); + } catch (IOException e) { + log.warn + ("Exception closing WAR File " + base.getName(), e); + } + } + base = null; + super.release(); + + } + + + // -------------------------------------------------------- Context Methods + + + /** + * Retrieves the named object. + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(String name) + throws NamingException { + return lookup(new CompositeName(name)); + } + + + /** + * Retrieves the named object. If name is empty, returns a new instance + * of this context (which represents the same naming context as this + * context, but its environment may be modified independently and it may + * be accessed concurrently). + * + * @param name the name of the object to look up + * @return the object bound to name + * @exception NamingException if a naming exception is encountered + */ + public Object lookup(Name name) + throws NamingException { + if (name.isEmpty()) + return this; + Entry entry = treeLookup(name); + if (entry == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + ZipEntry zipEntry = entry.getEntry(); + if (zipEntry.isDirectory()) + return new WARDirContext(base, entry); + else + return new WARResource(entry.getEntry()); + } + + + /** + * Unbinds the named object. Removes the terminal atomic name in name + * from the target context--that named by all but the terminal atomic + * part of name. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * @param name the name to bind; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NamingException if a naming exception is encountered + */ + public void unbind(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Binds a new name to the object bound to an old name, and unbinds the + * old name. Both names are relative to this context. Any attributes + * associated with the old name become associated with the new name. + * Intermediate contexts of the old name are not changed. + * + * @param oldName the name of the existing binding; may not be empty + * @param newName the name of the new binding; may not be empty + * @exception NameAlreadyBoundException if newName is already bound + * @exception NamingException if a naming exception is encountered + */ + public void rename(String oldName, String newName) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(String name) + throws NamingException { + return list(new CompositeName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the class + * names of objects bound to them. The contents of any subcontexts are + * not included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the names and class names of the bindings in + * this context. Each element of the enumeration is of type NameClassPair. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration list(Name name) + throws NamingException { + if (name.isEmpty()) + return new NamingContextEnumeration(list(entries).iterator()); + Entry entry = treeLookup(name); + if (entry == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + return new NamingContextEnumeration(list(entry).iterator()); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(String name) + throws NamingException { + return listBindings(new CompositeName(name)); + } + + + /** + * Enumerates the names bound in the named context, along with the + * objects bound to them. The contents of any subcontexts are not + * included. + *

        + * If a binding is added to or removed from this context, its effect on + * an enumeration previously returned is undefined. + * + * @param name the name of the context to list + * @return an enumeration of the bindings in this context. + * Each element of the enumeration is of type Binding. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration listBindings(Name name) + throws NamingException { + if (name.isEmpty()) + return new NamingContextBindingsEnumeration(list(entries).iterator(), + this); + Entry entry = treeLookup(name); + if (entry == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + return new NamingContextBindingsEnumeration(list(entry).iterator(), + this); + } + + + /** + * Destroys the named context and removes it from the namespace. Any + * attributes associated with the name are also removed. Intermediate + * contexts are not destroyed. + *

        + * This method is idempotent. It succeeds even if the terminal atomic + * name is not bound in the target context, but throws + * NameNotFoundException if any of the intermediate contexts do not exist. + * + * In a federated naming system, a context from one naming system may be + * bound to a name in another. One can subsequently look up and perform + * operations on the foreign context using a composite name. However, an + * attempt destroy the context using this composite name will fail with + * NotContextException, because the foreign context is not a "subcontext" + * of the context in which it is bound. Instead, use unbind() to remove + * the binding of the foreign context. Destroying the foreign context + * requires that the destroySubcontext() be performed on a context from + * the foreign context's "native" naming system. + * + * @param name the name of the context to be destroyed; may not be empty + * @exception NameNotFoundException if an intermediate context does not + * exist + * @exception NotContextException if the name is bound but does not name + * a context, or does not name a context of the appropriate type + */ + public void destroySubcontext(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Retrieves the named object, following links except for the terminal + * atomic component of the name. If the object bound to name is not a + * link, returns the object itself. + * + * @param name the name of the object to look up + * @return the object bound to name, not following the terminal link + * (if any). + * @exception NamingException if a naming exception is encountered + */ + public Object lookupLink(String name) + throws NamingException { + // Note : Links are not supported + return lookup(name); + } + + + /** + * Retrieves the full name of this context within its own namespace. + *

        + * Many naming services have a notion of a "full name" for objects in + * their respective namespaces. For example, an LDAP entry has a + * distinguished name, and a DNS record has a fully qualified name. This + * method allows the client application to retrieve this name. The string + * returned by this method is not a JNDI composite name and should not be + * passed directly to context methods. In naming systems for which the + * notion of full name does not make sense, + * OperationNotSupportedException is thrown. + * + * @return this context's name in its own namespace; never null + * @exception OperationNotSupportedException if the naming system does + * not have the notion of a full name + * @exception NamingException if a naming exception is encountered + */ + public String getNameInNamespace() + throws NamingException { + return docBase; + } + + + // ----------------------------------------------------- DirContext Methods + + + /** + * Retrieves selected attributes associated with a named object. + * See the class description regarding attribute models, attribute type + * names, and operational attributes. + * + * @return the requested attributes; never null + * @param name the name of the object from which to retrieve attributes + * @param attrIds the identifiers of the attributes to retrieve. null + * indicates that all attributes should be retrieved; an empty array + * indicates that none should be retrieved + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(String name, String[] attrIds) + throws NamingException { + return getAttributes(new CompositeName(name), attrIds); + } + + + /** + * Retrieves all of the attributes associated with a named object. + * + * @return the set of attributes associated with name. + * Returns an empty attribute set if name has no attributes; never null. + * @param name the name of the object from which to retrieve attributes + * @exception NamingException if a naming exception is encountered + */ + public Attributes getAttributes(Name name, String[] attrIds) + throws NamingException { + + Entry entry = null; + if (name.isEmpty()) + entry = entries; + else + entry = treeLookup(name); + if (entry == null) + throw new NamingException + (sm.getString("resources.notFound", name)); + + ZipEntry zipEntry = entry.getEntry(); + + ResourceAttributes attrs = new ResourceAttributes(); + attrs.setCreationDate(new Date(zipEntry.getTime())); + attrs.setName(entry.getName()); + if (!zipEntry.isDirectory()) + attrs.setResourceType(""); + attrs.setContentLength(zipEntry.getSize()); + attrs.setLastModified(zipEntry.getTime()); + + return attrs; + + } + + + /** + * Modifies the attributes associated with a named object. The order of + * the modifications is not specified. Where possible, the modifications + * are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mod_op the modification operation, one of: ADD_ATTRIBUTE, + * REPLACE_ATTRIBUTE, REMOVE_ATTRIBUTE + * @param attrs the attributes to be used for the modification; may not + * be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, int mod_op, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Modifies the attributes associated with a named object using an an + * ordered list of modifications. The modifications are performed in the + * order specified. Each modification specifies a modification operation + * code and an attribute on which to operate. Where possible, the + * modifications are performed atomically. + * + * @param name the name of the object whose attributes will be updated + * @param mods an ordered sequence of modifications to be performed; may + * not be null + * @exception AttributeModificationException if the modification cannot be + * completed successfully + * @exception NamingException if a naming exception is encountered + */ + public void modifyAttributes(String name, ModificationItem[] mods) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Binds a name to an object, along with associated attributes. If attrs + * is null, the resulting binding will have the attributes associated + * with obj if obj is a DirContext, and no attributes otherwise. If attrs + * is non-null, the resulting binding will have attrs as its attributes; + * any attributes associated with obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception NameAlreadyBoundException if name is already bound + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void bind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Binds a name to an object, along with associated attributes, + * overwriting any existing binding. If attrs is null and obj is a + * DirContext, the attributes from obj are used. If attrs is null and obj + * is not a DirContext, any existing attributes associated with the object + * already bound in the directory remain unchanged. If attrs is non-null, + * any existing attributes associated with the object already bound in + * the directory are removed and attrs is associated with the named + * object. If obj is a DirContext and attrs is non-null, the attributes + * of obj are ignored. + * + * @param name the name to bind; may not be empty + * @param obj the object to bind; possibly null + * @param attrs the attributes to associate with the binding + * @exception InvalidAttributesException if some "mandatory" attributes + * of the binding are not supplied + * @exception NamingException if a naming exception is encountered + */ + public void rebind(String name, Object obj, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Creates and binds a new context, along with associated attributes. + * This method creates a new subcontext with the given name, binds it in + * the target context (that named by all but terminal atomic component of + * the name), and associates the supplied attributes with the newly + * created object. All intermediate and target contexts must already + * exist. If attrs is null, this method is equivalent to + * Context.createSubcontext(). + * + * @param name the name of the context to create; may not be empty + * @param attrs the attributes to associate with the newly created context + * @return the newly created context + * @exception NameAlreadyBoundException if the name is already bound + * @exception InvalidAttributesException if attrs does not contain all + * the mandatory attributes required for creation + * @exception NamingException if a naming exception is encountered + */ + public DirContext createSubcontext(String name, Attributes attrs) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Retrieves the schema associated with the named object. The schema + * describes rules regarding the structure of the namespace and the + * attributes stored within it. The schema specifies what types of + * objects can be added to the directory and where they can be added; + * what mandatory and optional attributes an object can have. The range + * of support for schemas is directory-specific. + * + * @param name the name of the object whose schema is to be retrieved + * @return the schema associated with the context; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchema(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Retrieves a context containing the schema objects of the named + * object's class definitions. + * + * @param name the name of the object whose object class definition is to + * be retrieved + * @return the DirContext containing the named object's class + * definitions; never null + * @exception OperationNotSupportedException if schema not supported + * @exception NamingException if a naming exception is encountered + */ + public DirContext getSchemaClassDefinition(String name) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes, and retrieves selected attributes. The search is + * performed using the default SearchControls settings. + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @param attributesToReturn the attributes to return. null indicates + * that all attributes are to be returned; an empty array indicates that + * none are to be returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes, + String[] attributesToReturn) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Searches in a single context for objects that contain a specified set + * of attributes. This method returns all the attributes of such objects. + * It is equivalent to supplying null as the atributesToReturn parameter + * to the method search(Name, Attributes, String[]). + * + * @param name the name of the context to search + * @param matchingAttributes the attributes to search for. If empty or + * null, all objects in the target context are returned. + * @return a non-null enumeration of SearchResult objects. Each + * SearchResult contains the attributes identified by attributesToReturn + * and the name of the corresponding object, named relative to the + * context named by name. + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, Attributes matchingAttributes) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filter the filter expression to use for the search; may not be + * null + * @param cons the search controls that control the search. If null, + * the default search controls are used (equivalent to + * (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisfy + * the filter; never null + * @exception InvalidSearchFilterException if the search filter specified + * is not supported or understood by the underlying directory + * @exception InvalidSearchControlsException if the search controls + * contain invalid settings + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filter, + SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + /** + * Searches in the named context or object for entries that satisfy the + * given search filter. Performs the search as specified by the search + * controls. + * + * @param name the name of the context or object to search + * @param filterExpr the filter expression to use for the search. + * The expression may contain variables of the form "{i}" where i is a + * nonnegative integer. May not be null. + * @param filterArgs the array of arguments to substitute for the + * variables in filterExpr. The value of filterArgs[i] will replace each + * occurrence of "{i}". If null, equivalent to an empty array. + * @param cons the search controls that control the search. If null, the + * default search controls are used (equivalent to (new SearchControls())). + * @return an enumeration of SearchResults of the objects that satisy the + * filter; never null + * @exception ArrayIndexOutOfBoundsException if filterExpr contains {i} + * expressions where i is outside the bounds of the array filterArgs + * @exception InvalidSearchControlsException if cons contains invalid + * settings + * @exception InvalidSearchFilterException if filterExpr with filterArgs + * represents an invalid search filter + * @exception NamingException if a naming exception is encountered + */ + public NamingEnumeration search(String name, String filterExpr, + Object[] filterArgs, SearchControls cons) + throws NamingException { + throw new OperationNotSupportedException(); + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Normalize the name of an entry read from the Zip. + */ + protected String normalize(ZipEntry entry) { + + String result = "/" + entry.getName(); + if (entry.isDirectory()) { + result = result.substring(0, result.length() - 1); + } + return result; + + } + + + /** + * Constructs a tree of the entries contained in a WAR file. + */ + protected void loadEntries() { + + try { + + Enumeration entryList = base.entries(); + entries = new Entry("/", new ZipEntry("/")); + + while (entryList.hasMoreElements()) { + + ZipEntry entry = (ZipEntry) entryList.nextElement(); + String name = normalize(entry); + int pos = name.lastIndexOf('/'); + // Check that parent entries exist and, if not, create them. + // This fixes a bug for war files that don't record separate + // zip entries for the directories. + int currentPos = -1; + int lastPos = 0; + while ((currentPos = name.indexOf('/', lastPos)) != -1) { + Name parentName = new CompositeName(name.substring(0, lastPos)); + Name childName = new CompositeName(name.substring(0, currentPos)); + String entryName = name.substring(lastPos, currentPos); + // Parent should have been created in last cycle through + // this loop + Entry parent = treeLookup(parentName); + Entry child = treeLookup(childName); + if (child == null) { + // Create a new entry for missing entry and strip off + // the leading '/' character and appended on by the + // normalize method and add '/' character to end to + // signify that it is a directory entry + String zipName = name.substring(1, currentPos) + "/"; + child = new Entry(entryName, new ZipEntry(zipName)); + if (parent != null) + parent.addChild(child); + } + // Increment lastPos + lastPos = currentPos + 1; + } + String entryName = name.substring(pos + 1, name.length()); + Name compositeName = new CompositeName(name.substring(0, pos)); + Entry parent = treeLookup(compositeName); + Entry child = new Entry(entryName, entry); + if (parent != null) + parent.addChild(child); + + } + + } catch (Exception e) { + } + + } + + + /** + * Entry tree lookup. + */ + protected Entry treeLookup(Name name) { + if (name.isEmpty()) + return entries; + Entry currentEntry = entries; + for (int i = 0; i < name.size(); i++) { + if (name.get(i).length() == 0) + continue; + currentEntry = currentEntry.getChild(name.get(i)); + if (currentEntry == null) + return null; + } + return currentEntry; + } + + + /** + * List children as objects. + */ + protected ArrayList list(Entry entry) { + + ArrayList entries = new ArrayList(); + Entry[] children = entry.getChildren(); + Arrays.sort(children); + NamingEntry namingEntry = null; + + for (int i = 0; i < children.length; i++) { + ZipEntry current = children[i].getEntry(); + Object object = null; + if (current.isDirectory()) { + object = new WARDirContext(base, children[i]); + } else { + object = new WARResource(current); + } + namingEntry = new NamingEntry + (children[i].getName(), object, NamingEntry.ENTRY); + entries.add(namingEntry); + } + + return entries; + + } + + + // ---------------------------------------------------- Entries Inner Class + + + /** + * Entries structure. + */ + protected class Entry implements Comparable { + + + // -------------------------------------------------------- Constructor + + + public Entry(String name, ZipEntry entry) { + this.name = name; + this.entry = entry; + } + + + // --------------------------------------------------- Member Variables + + + protected String name = null; + + + protected ZipEntry entry = null; + + + protected Entry children[] = new Entry[0]; + + + // ----------------------------------------------------- Public Methods + + + public int compareTo(Object o) { + if (!(o instanceof Entry)) + return (+1); + return (name.compareTo(((Entry) o).getName())); + } + + public ZipEntry getEntry() { + return entry; + } + + + public String getName() { + return name; + } + + + public void addChild(Entry entry) { + Entry[] newChildren = new Entry[children.length + 1]; + for (int i = 0; i < children.length; i++) + newChildren[i] = children[i]; + newChildren[children.length] = entry; + children = newChildren; + } + + + public Entry[] getChildren() { + return children; + } + + + public Entry getChild(String name) { + for (int i = 0; i < children.length; i++) { + if (children[i].name.equals(name)) { + return children[i]; + } + } + return null; + } + + + } + + + // ------------------------------------------------ WARResource Inner Class + + + /** + * This specialized resource implementation avoids opening the IputStream + * to the WAR right away. + */ + protected class WARResource extends Resource { + + + // -------------------------------------------------------- Constructor + + + public WARResource(ZipEntry entry) { + this.entry = entry; + } + + + // --------------------------------------------------- Member Variables + + + protected ZipEntry entry; + + + // ----------------------------------------------------- Public Methods + + + /** + * Content accessor. + * + * @return InputStream + */ + public InputStream streamContent() + throws IOException { + try { + if (binaryContent == null) { + inputStream = base.getInputStream(entry); + } + } catch (ZipException e) { + throw new IOException(e.getMessage()); + } + return super.streamContent(); + } + + + } + + +} + diff --git a/java/org/apache/naming/resources/jndi/Handler.java b/java/org/apache/naming/resources/jndi/Handler.java index d90033c30..4a0e6bc4b 100644 --- a/java/org/apache/naming/resources/jndi/Handler.java +++ b/java/org/apache/naming/resources/jndi/Handler.java @@ -1,38 +1,38 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.naming.resources.jndi; - -import org.apache.naming.resources.DirContextURLStreamHandler; - -/** - * Stream handler to a JNDI directory context. - * - * @author Remy Maucherat - * @version $Revision: 302726 $ - */ -public class Handler - extends DirContextURLStreamHandler { - - - // ----------------------------------------------------------- Constructors - - - public Handler() { - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.naming.resources.jndi; + +import org.apache.naming.resources.DirContextURLStreamHandler; + +/** + * Stream handler to a JNDI directory context. + * + * @author Remy Maucherat + * @version $Revision: 302726 $ + */ +public class Handler + extends DirContextURLStreamHandler { + + + // ----------------------------------------------------------- Constructors + + + public Handler() { + } + + +} diff --git a/java/org/apache/naming/resources/package.html b/java/org/apache/naming/resources/package.html index 4e283b7d9..02dc56a49 100644 --- a/java/org/apache/naming/resources/package.html +++ b/java/org/apache/naming/resources/package.html @@ -1,15 +1,15 @@ - - -

        This package contains the resources directory context implemetation. -This includes : -

          -
        • A CacheDirContext which handles caching and acts as a proxy for the real -resources context
        • -
        • A FileDirContext, an implementation of DirContext to access the -filesystem
        • -
        -

        - -

        - - + + +

        This package contains the resources directory context implemetation. +This includes : +

          +
        • A CacheDirContext which handles caching and acts as a proxy for the real +resources context
        • +
        • A FileDirContext, an implementation of DirContext to access the +filesystem
        • +
        +

        + +

        + + diff --git a/java/org/apache/tomcat/Apr.java b/java/org/apache/tomcat/Apr.java index 1e7c4df61..9c2480c4a 100644 --- a/java/org/apache/tomcat/Apr.java +++ b/java/org/apache/tomcat/Apr.java @@ -1,40 +1,40 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat; - -import java.io.InputStream; -import java.util.Properties; - -public class Apr { - private static String aprInfo = null; - - static { - - try { - InputStream is = Apr.class.getResourceAsStream - ("/org/apache/tomcat/apr.properties"); - Properties props = new Properties(); - props.load(is); - is.close(); - aprInfo = props.getProperty("tcn.info"); - } - catch (Throwable t) { - ; // Nothing - } - } -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat; + +import java.io.InputStream; +import java.util.Properties; + +public class Apr { + private static String aprInfo = null; + + static { + + try { + InputStream is = Apr.class.getResourceAsStream + ("/org/apache/tomcat/apr.properties"); + Properties props = new Properties(); + props.load(is); + is.close(); + aprInfo = props.getProperty("tcn.info"); + } + catch (Throwable t) { + ; // Nothing + } + } +} diff --git a/java/org/apache/tomcat/apr.properties b/java/org/apache/tomcat/apr.properties index fe12c3a7a..9dfb03d23 100644 --- a/java/org/apache/tomcat/apr.properties +++ b/java/org/apache/tomcat/apr.properties @@ -1 +1 @@ -tcn.info=Tomcat Native/@VERSION@ +tcn.info=Tomcat Native/@VERSION@ diff --git a/java/org/apache/tomcat/jni/Address.java b/java/org/apache/tomcat/jni/Address.java index f20247026..9d9f742c3 100644 --- a/java/org/apache/tomcat/jni/Address.java +++ b/java/org/apache/tomcat/jni/Address.java @@ -1,113 +1,113 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Address - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Address { - - static public String APR_ANYADDR = "0.0.0.0"; - /** - * Fill the Sockaddr class from apr_sockaddr_t - * @param info Sockaddr class to fill - * @param sa Structure pointer - */ - public static native boolean fill(Sockaddr info, long sa); - - /** - * Create the Sockaddr object from apr_sockaddr_t - * @param sa Structure pointer - */ - public static native Sockaddr getInfo(long sa); - - /** - * Create apr_sockaddr_t from hostname, address family, and port. - * @param hostname The hostname or numeric address string to resolve/parse, or - * NULL to build an address that corresponds to 0.0.0.0 or :: - * @param family The address family to use, or APR_UNSPEC if the system should - * decide. - * @param port The port number. - * @param flags Special processing flags: - *
        -     *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
        -     *                                 for IPv6 addresses if the first query failed;
        -     *                                 only valid if family is APR_UNSPEC and hostname
        -     *                                 isn't NULL; mutually exclusive with
        -     *                                 APR_IPV6_ADDR_OK
        -     *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
        -     *                                 for IPv4 addresses if the first query failed;
        -     *                                 only valid if family is APR_UNSPEC and hostname
        -     *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
        -     *                                 with APR_IPV4_ADDR_OK
        -     * 
        - * @param p The pool for the apr_sockaddr_t and associated storage. - * @return The new apr_sockaddr_t. - */ - public static native long info(String hostname, int family, - int port, int flags, long p) - throws Exception; - /** - * Look up the host name from an apr_sockaddr_t. - * @param sa The apr_sockaddr_t. - * @param flags Special processing flags. - * @return The hostname. - */ - public static native String getnameinfo(long sa, int flags); - - /** - * Return the IP address (in numeric address string format) in - * an APR socket address. APR will allocate storage for the IP address - * string from the pool of the apr_sockaddr_t. - * @param sa The socket address to reference. - * @return The IP address. - */ - public static native String getip(long sa); - - /** - * Given an apr_sockaddr_t and a service name, set the port for the service - * @param sockaddr The apr_sockaddr_t that will have its port set - * @param servname The name of the service you wish to use - * @return APR status code. - */ - public static native int getservbyname(long sockaddr, String servname); - - /** - * Return an apr_sockaddr_t from an apr_socket_t - * @param which Which interface do we want the apr_sockaddr_t for? - * @param sock The socket to use - * @return The returned apr_sockaddr_t. - */ - public static native long get(int which, long sock) - throws Exception; - - /** - * See if the IP addresses in two APR socket addresses are - * equivalent. Appropriate logic is present for comparing - * IPv4-mapped IPv6 addresses with IPv4 addresses. - * - * @param a One of the APR socket addresses. - * @param b The other APR socket address. - * The return value will be True if the addresses - * are equivalent. - */ - public static native boolean equal(long a, long b); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Address + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Address { + + static public String APR_ANYADDR = "0.0.0.0"; + /** + * Fill the Sockaddr class from apr_sockaddr_t + * @param info Sockaddr class to fill + * @param sa Structure pointer + */ + public static native boolean fill(Sockaddr info, long sa); + + /** + * Create the Sockaddr object from apr_sockaddr_t + * @param sa Structure pointer + */ + public static native Sockaddr getInfo(long sa); + + /** + * Create apr_sockaddr_t from hostname, address family, and port. + * @param hostname The hostname or numeric address string to resolve/parse, or + * NULL to build an address that corresponds to 0.0.0.0 or :: + * @param family The address family to use, or APR_UNSPEC if the system should + * decide. + * @param port The port number. + * @param flags Special processing flags: + *
        +     *       APR_IPV4_ADDR_OK          first query for IPv4 addresses; only look
        +     *                                 for IPv6 addresses if the first query failed;
        +     *                                 only valid if family is APR_UNSPEC and hostname
        +     *                                 isn't NULL; mutually exclusive with
        +     *                                 APR_IPV6_ADDR_OK
        +     *       APR_IPV6_ADDR_OK          first query for IPv6 addresses; only look
        +     *                                 for IPv4 addresses if the first query failed;
        +     *                                 only valid if family is APR_UNSPEC and hostname
        +     *                                 isn't NULL and APR_HAVE_IPV6; mutually exclusive
        +     *                                 with APR_IPV4_ADDR_OK
        +     * 
        + * @param p The pool for the apr_sockaddr_t and associated storage. + * @return The new apr_sockaddr_t. + */ + public static native long info(String hostname, int family, + int port, int flags, long p) + throws Exception; + /** + * Look up the host name from an apr_sockaddr_t. + * @param sa The apr_sockaddr_t. + * @param flags Special processing flags. + * @return The hostname. + */ + public static native String getnameinfo(long sa, int flags); + + /** + * Return the IP address (in numeric address string format) in + * an APR socket address. APR will allocate storage for the IP address + * string from the pool of the apr_sockaddr_t. + * @param sa The socket address to reference. + * @return The IP address. + */ + public static native String getip(long sa); + + /** + * Given an apr_sockaddr_t and a service name, set the port for the service + * @param sockaddr The apr_sockaddr_t that will have its port set + * @param servname The name of the service you wish to use + * @return APR status code. + */ + public static native int getservbyname(long sockaddr, String servname); + + /** + * Return an apr_sockaddr_t from an apr_socket_t + * @param which Which interface do we want the apr_sockaddr_t for? + * @param sock The socket to use + * @return The returned apr_sockaddr_t. + */ + public static native long get(int which, long sock) + throws Exception; + + /** + * See if the IP addresses in two APR socket addresses are + * equivalent. Appropriate logic is present for comparing + * IPv4-mapped IPv6 addresses with IPv4 addresses. + * + * @param a One of the APR socket addresses. + * @param b The other APR socket address. + * The return value will be True if the addresses + * are equivalent. + */ + public static native boolean equal(long a, long b); + +} diff --git a/java/org/apache/tomcat/jni/BIOCallback.java b/java/org/apache/tomcat/jni/BIOCallback.java index 36181a7ea..6928d331b 100644 --- a/java/org/apache/tomcat/jni/BIOCallback.java +++ b/java/org/apache/tomcat/jni/BIOCallback.java @@ -1,55 +1,55 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Open SSL BIO Callback Interface - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public interface BIOCallback { - - /** - * Write data - * @param buf containg the bytes to write. - * @return Number of characters written. - */ - public int write(byte [] buf); - - /** - * Read data - * @param buf buffer to store the read bytes. - * @return number of bytes read. - */ - public int read(byte [] buf); - - /** - * Puts string - * @param data String to write - * @return Number of characters written - */ - public int puts(String data); - - /** - * Read string up to the len or CLRLF - * @param len Maximum number of characters to read - * @return String with up to len bytes readed - */ - public String gets(int len); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Open SSL BIO Callback Interface + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public interface BIOCallback { + + /** + * Write data + * @param buf containg the bytes to write. + * @return Number of characters written. + */ + public int write(byte [] buf); + + /** + * Read data + * @param buf buffer to store the read bytes. + * @return number of bytes read. + */ + public int read(byte [] buf); + + /** + * Puts string + * @param data String to write + * @return Number of characters written + */ + public int puts(String data); + + /** + * Read string up to the len or CLRLF + * @param len Maximum number of characters to read + * @return String with up to len bytes readed + */ + public String gets(int len); + +} diff --git a/java/org/apache/tomcat/jni/Directory.java b/java/org/apache/tomcat/jni/Directory.java index 5726ae885..a6a019809 100644 --- a/java/org/apache/tomcat/jni/Directory.java +++ b/java/org/apache/tomcat/jni/Directory.java @@ -1,96 +1,96 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Directory - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Directory { - - /** - * Create a new directory on the file system. - * @param path the path for the directory to be created. (use / on all systems) - * @param perm Permissions for the new direcoty. - * @param pool the pool to use. - */ - public static native int make(String path, int perm, long pool); - - /** Creates a new directory on the file system, but behaves like - * 'mkdir -p'. Creates intermediate directories as required. No error - * will be reported if PATH already exists. - * @param path the path for the directory to be created. (use / on all systems) - * @param perm Permissions for the new direcoty. - * @param pool the pool to use. - */ - public static native int makeRecursive(String path, int perm, long pool); - - /** - * Remove directory from the file system. - * @param path the path for the directory to be removed. (use / on all systems) - * @param pool the pool to use. - */ - public static native int remove(String path, long pool); - - /** - * Find an existing directory suitable as a temporary storage location. - * @param pool The pool to use for any necessary allocations. - * @return The temp directory. - * - * This function uses an algorithm to search for a directory that an - * an application can use for temporary storage. Once such a - * directory is found, that location is cached by the library. Thus, - * callers only pay the cost of this algorithm once if that one time - * is successful. - * - */ - public static native String tempGet(long pool); - - /** - * Open the specified directory. - * @param dirname The full path to the directory (use / on all systems) - * @param pool The pool to use. - * @return The opened directory descriptor. - */ - public static native long open(String dirname, long pool) - throws Error; - - /** - * close the specified directory. - * @param thedir the directory descriptor to close. - */ - public static native int close(long thedir); - - /** - * Rewind the directory to the first entry. - * @param thedir the directory descriptor to rewind. - */ - public static native int rewind(long thedir); - - - /** - * Read the next entry from the specified directory. - * @param finfo the file info structure and filled in by apr_dir_read - * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values - * @param thedir the directory descriptor returned from apr_dir_open - * No ordering is guaranteed for the entries read. - */ - public static native int read(FileInfo finfo, int wanted, long thedir); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Directory + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Directory { + + /** + * Create a new directory on the file system. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ + public static native int make(String path, int perm, long pool); + + /** Creates a new directory on the file system, but behaves like + * 'mkdir -p'. Creates intermediate directories as required. No error + * will be reported if PATH already exists. + * @param path the path for the directory to be created. (use / on all systems) + * @param perm Permissions for the new direcoty. + * @param pool the pool to use. + */ + public static native int makeRecursive(String path, int perm, long pool); + + /** + * Remove directory from the file system. + * @param path the path for the directory to be removed. (use / on all systems) + * @param pool the pool to use. + */ + public static native int remove(String path, long pool); + + /** + * Find an existing directory suitable as a temporary storage location. + * @param pool The pool to use for any necessary allocations. + * @return The temp directory. + * + * This function uses an algorithm to search for a directory that an + * an application can use for temporary storage. Once such a + * directory is found, that location is cached by the library. Thus, + * callers only pay the cost of this algorithm once if that one time + * is successful. + * + */ + public static native String tempGet(long pool); + + /** + * Open the specified directory. + * @param dirname The full path to the directory (use / on all systems) + * @param pool The pool to use. + * @return The opened directory descriptor. + */ + public static native long open(String dirname, long pool) + throws Error; + + /** + * close the specified directory. + * @param thedir the directory descriptor to close. + */ + public static native int close(long thedir); + + /** + * Rewind the directory to the first entry. + * @param thedir the directory descriptor to rewind. + */ + public static native int rewind(long thedir); + + + /** + * Read the next entry from the specified directory. + * @param finfo the file info structure and filled in by apr_dir_read + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param thedir the directory descriptor returned from apr_dir_open + * No ordering is guaranteed for the entries read. + */ + public static native int read(FileInfo finfo, int wanted, long thedir); + +} diff --git a/java/org/apache/tomcat/jni/Error.java b/java/org/apache/tomcat/jni/Error.java index 181757dc4..97683291e 100644 --- a/java/org/apache/tomcat/jni/Error.java +++ b/java/org/apache/tomcat/jni/Error.java @@ -1,95 +1,95 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Error - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Error extends Exception { - - /** - * APR error type. - */ - private int error; - - /** - * A description of the problem. - */ - private String description; - - /** - * Construct an APRException. - * - * @param error one of the value in Error - * @param description error message - */ - private Error(int error, String description) - { - super(description); - this.error = error; - this.description = description; - } - - /** - * Get the APR error code of the exception. - * - * @return error of the Exception - */ - public int getError() - { - return error; - } - - /** - * Get the APR description of the exception. - * - * @return description of the Exception - */ - public String getDescription() - { - return description; - } - - /** - * Get the last platform error. - * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms - * This retrieves errno, or calls a GetLastError() style function, and - * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no - * such mechanism, so this call may be unsupported. Do NOT use this - * call for socket errors from socket, send, recv etc! - */ - public static native int osError(); - - /** - * Get the last platform socket error. - * @return the last socket error, folded into apr_status_t, on all platforms - * This retrieves errno or calls a GetLastSocketError() style function, - * and folds it with APR_FROM_OS_ERROR. - */ - public static native int netosError(); - - /** - * Return a human readable string describing the specified error. - * @param statcode The error code the get a string for. - * @return The error string. - */ - public static native String strerror(int statcode); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Error + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Error extends Exception { + + /** + * APR error type. + */ + private int error; + + /** + * A description of the problem. + */ + private String description; + + /** + * Construct an APRException. + * + * @param error one of the value in Error + * @param description error message + */ + private Error(int error, String description) + { + super(description); + this.error = error; + this.description = description; + } + + /** + * Get the APR error code of the exception. + * + * @return error of the Exception + */ + public int getError() + { + return error; + } + + /** + * Get the APR description of the exception. + * + * @return description of the Exception + */ + public String getDescription() + { + return description; + } + + /** + * Get the last platform error. + * @return apr_status_t the last platform error, folded into apr_status_t, on most platforms + * This retrieves errno, or calls a GetLastError() style function, and + * folds it with APR_FROM_OS_ERROR. Some platforms (such as OS2) have no + * such mechanism, so this call may be unsupported. Do NOT use this + * call for socket errors from socket, send, recv etc! + */ + public static native int osError(); + + /** + * Get the last platform socket error. + * @return the last socket error, folded into apr_status_t, on all platforms + * This retrieves errno or calls a GetLastSocketError() style function, + * and folds it with APR_FROM_OS_ERROR. + */ + public static native int netosError(); + + /** + * Return a human readable string describing the specified error. + * @param statcode The error code the get a string for. + * @return The error string. + */ + public static native String strerror(int statcode); + +} diff --git a/java/org/apache/tomcat/jni/File.java b/java/org/apache/tomcat/jni/File.java index 53f4ac527..1e4213da4 100644 --- a/java/org/apache/tomcat/jni/File.java +++ b/java/org/apache/tomcat/jni/File.java @@ -1,702 +1,702 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; -/* Import needed classes */ -import java.nio.ByteBuffer; -/** File - * - * @author Mladen Turk - * @version $Revision: 369000 $, $Date: 2006-01-14 09:08:44 +0100 (sam., 14 janv. 2006) $ - */ - -public class File { - - /** Open the file for reading */ - public static final int APR_FOPEN_READ = 0x00001; - /** Open the file for writing */ - public static final int APR_FOPEN_WRITE = 0x00002; - /** Create the file if not there */ - public static final int APR_FOPEN_CREATE = 0x00004; - /** Append to the end of the file */ - public static final int APR_FOPEN_APPEND = 0x00008; - /** Open the file and truncate to 0 length */ - public static final int APR_FOPEN_TRUNCATE = 0x00010; - /** Open the file in binary mode */ - public static final int APR_FOPEN_BINARY = 0x00020; - /** Open should fail if APR_CREATE and file exists. */ - public static final int APR_FOPEN_EXCL = 0x00040; - /** Open the file for buffered I/O */ - public static final int APR_FOPEN_BUFFERED = 0x00080; - /** Delete the file after close */ - public static final int APR_FOPEN_DELONCLOSE = 0x00100; - /** Platform dependent tag to open the file for - * use across multiple threads - */ - public static final int APR_FOPEN_XTHREAD = 0x00200; - /** Platform dependent support for higher level locked read/write - * access to support writes across process/machines - */ - public static final int APR_FOPEN_SHARELOCK = 0x00400; - /** Do not register a cleanup when the file is opened */ - public static final int APR_FOPEN_NOCLEANUP = 0x00800; - /** Advisory flag that this file should support - * apr_socket_sendfile operation - */ - public static final int APR_FOPEN_SENDFILE_ENABLED = 0x01000; - /** Platform dependent flag to enable large file support; - *
        Warning : The APR_LARGEFILE flag only has effect on some platforms - * where sizeof(apr_off_t) == 4. Where implemented, it allows opening - * and writing to a file which exceeds the size which can be - * represented by apr_off_t (2 gigabytes). When a file's size does - * exceed 2Gb, apr_file_info_get() will fail with an error on the - * descriptor, likewise apr_stat()/apr_lstat() will fail on the - * filename. apr_dir_read() will fail with APR_INCOMPLETE on a - * directory entry for a large file depending on the particular - * APR_FINFO_* flags. Generally, it is not recommended to use this - * flag. - */ - public static final int APR_FOPEN_LARGEFILE = 0x04000; - - /** Set the file position */ - public static final int APR_SET = 0; - /** Current */ - public static final int APR_CUR = 1; - /** Go to end of file */ - public static final int APR_END = 2; - - /* flags for apr_file_attrs_set */ - - /** File is read-only */ - public static final int APR_FILE_ATTR_READONLY = 0x01; - /** File is executable */ - public static final int APR_FILE_ATTR_EXECUTABLE = 0x02; - /** File is hidden */ - public static final int APR_FILE_ATTR_HIDDEN = 0x04; - - - /* File lock types/flags */ - - /** Shared lock. More than one process or thread can hold a shared lock - * at any given time. Essentially, this is a "read lock", preventing - * writers from establishing an exclusive lock. - */ - public static final int APR_FLOCK_SHARED = 1; - - /** Exclusive lock. Only one process may hold an exclusive lock at any - * given time. This is analogous to a "write lock". - */ - public static final int APR_FLOCK_EXCLUSIVE = 2; - /** mask to extract lock type */ - public static final int APR_FLOCK_TYPEMASK = 0x000F; - /** do not block while acquiring the file lock */ - public static final int APR_FLOCK_NONBLOCK = 0x0010; - - /* apr_filetype_e values for the filetype member of the - * apr_file_info_t structure - *
        Warning :: Not all of the filetypes below can be determined. - * For example, a given platform might not correctly report - * a socket descriptor as APR_SOCK if that type isn't - * well-identified on that platform. In such cases where - * a filetype exists but cannot be described by the recognized - * flags below, the filetype will be APR_UNKFILE. If the - * filetype member is not determined, the type will be APR_NOFILE. - */ - - /** no file type determined */ - public static final int APR_NOFILE = 0; - /** a regular file */ - public static final int APR_REG = 1; - /** a directory */ - public static final int APR_DIR = 2; - /** a character device */ - public static final int APR_CHR = 3; - /** a block device */ - public static final int APR_BLK = 4; - /** a FIFO / pipe */ - public static final int APR_PIPE = 5; - /** a symbolic link */ - public static final int APR_LNK = 6; - /** a [unix domain] socket */ - public static final int APR_SOCK = 7; - /** a file of some other unknown type */ - public static final int APR_UNKFILE = 127; - - - /* - * apr_file_permissions File Permissions flags - */ - - public static final int APR_FPROT_USETID = 0x8000; /** Set user id */ - public static final int APR_FPROT_UREAD = 0x0400; /** Read by user */ - public static final int APR_FPROT_UWRITE = 0x0200; /** Write by user */ - public static final int APR_FPROT_UEXECUTE = 0x0100; /** Execute by user */ - - public static final int APR_FPROT_GSETID = 0x4000; /** Set group id */ - public static final int APR_FPROT_GREAD = 0x0040; /** Read by group */ - public static final int APR_FPROT_GWRITE = 0x0020; /** Write by group */ - public static final int APR_FPROT_GEXECUTE = 0x0010; /** Execute by group */ - - public static final int APR_FPROT_WSTICKY = 0x2000; /** Sticky bit */ - public static final int APR_FPROT_WREAD = 0x0004; /** Read by others */ - public static final int APR_FPROT_WWRITE = 0x0002; /** Write by others */ - public static final int APR_FPROT_WEXECUTE = 0x0001; /** Execute by others */ - public static final int APR_FPROT_OS_DEFAULT = 0x0FFF; /** use OS's default permissions */ - - - public static final int APR_FINFO_LINK = 0x00000001; /** Stat the link not the file itself if it is a link */ - public static final int APR_FINFO_MTIME = 0x00000010; /** Modification Time */ - public static final int APR_FINFO_CTIME = 0x00000020; /** Creation or inode-changed time */ - public static final int APR_FINFO_ATIME = 0x00000040; /** Access Time */ - public static final int APR_FINFO_SIZE = 0x00000100; /** Size of the file */ - public static final int APR_FINFO_CSIZE = 0x00000200; /** Storage size consumed by the file */ - public static final int APR_FINFO_DEV = 0x00001000; /** Device */ - public static final int APR_FINFO_INODE = 0x00002000; /** Inode */ - public static final int APR_FINFO_NLINK = 0x00004000; /** Number of links */ - public static final int APR_FINFO_TYPE = 0x00008000; /** Type */ - public static final int APR_FINFO_USER = 0x00010000; /** User */ - public static final int APR_FINFO_GROUP = 0x00020000; /** Group */ - public static final int APR_FINFO_UPROT = 0x00100000; /** User protection bits */ - public static final int APR_FINFO_GPROT = 0x00200000; /** Group protection bits */ - public static final int APR_FINFO_WPROT = 0x00400000; /** World protection bits */ - public static final int APR_FINFO_ICASE = 0x01000000; /** if dev is case insensitive */ - public static final int APR_FINFO_NAME = 0x02000000; /** ->name in proper case */ - - public static final int APR_FINFO_MIN = 0x00008170; /** type, mtime, ctime, atime, size */ - public static final int APR_FINFO_IDENT = 0x00003000; /** dev and inode */ - public static final int APR_FINFO_OWNER = 0x00030000; /** user and group */ - public static final int APR_FINFO_PROT = 0x00700000; /** all protections */ - public static final int APR_FINFO_NORM = 0x0073b170; /** an atomic unix apr_stat() */ - public static final int APR_FINFO_DIRENT = 0x02000000; /** an atomic unix apr_dir_read() */ - - - - /** - * Open the specified file. - * @param fname The full path to the file (using / on all systems) - * @param flag Or'ed value of: - *
        -     * APR_FOPEN_READ              open for reading
        -     * APR_FOPEN_WRITE             open for writing
        -     * APR_FOPEN_CREATE            create the file if not there
        -     * APR_FOPEN_APPEND            file ptr is set to end prior to all writes
        -     * APR_FOPEN_TRUNCATE          set length to zero if file exists
        -     * APR_FOPEN_BINARY            not a text file (This flag is ignored on
        -     *                             UNIX because it has no meaning)
        -     * APR_FOPEN_BUFFERED          buffer the data.  Default is non-buffered
        -     * APR_FOPEN_EXCL              return error if APR_CREATE and file exists
        -     * APR_FOPEN_DELONCLOSE        delete the file after closing.
        -     * APR_FOPEN_XTHREAD           Platform dependent tag to open the file
        -     *                             for use across multiple threads
        -     * APR_FOPEN_SHARELOCK         Platform dependent support for higher
        -     *                             level locked read/write access to support
        -     *                             writes across process/machines
        -     * APR_FOPEN_NOCLEANUP         Do not register a cleanup with the pool
        -     *                             passed in on the pool argument (see below).
        -     *                             The apr_os_file_t handle in apr_file_t will not
        -     *                             be closed when the pool is destroyed.
        -     * APR_FOPEN_SENDFILE_ENABLED  Open with appropriate platform semantics
        -     *                             for sendfile operations.  Advisory only,
        -     *                             apr_socket_sendfile does not check this flag.
        -     * 
        - * @param perm Access permissions for file. - * @param pool The pool to use. - * If perm is APR_OS_DEFAULT and the file is being created, - * appropriate default permissions will be used. - * @return The opened file descriptor. - */ - public static native long open(String fname, int flag, int perm, long pool) - throws Error; - - /** - * Close the specified file. - * @param file The file descriptor to close. - */ - public static native int close(long file); - - /** - * Flush the file's buffer. - * @param thefile The file descriptor to flush - */ - public static native int flush(long thefile); - - /** - * Open a temporary file - * @param templ The template to use when creating a temp file. - * @param flags The flags to open the file with. If this is zero, - * the file is opened with - * APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE - * @param pool The pool to allocate the file out of. - * @return The apr file to use as a temporary file. - * - * This function generates a unique temporary file name from template. - * The last six characters of template must be XXXXXX and these are replaced - * with a string that makes the filename unique. Since it will be modified, - * template must not be a string constant, but should be declared as a character - * array. - * - */ - public static native long mktemp(String templ, int flags, long pool) - throws Error; - - /** - * Delete the specified file. - * @param path The full path to the file (using / on all systems) - * @param pool The pool to use. - * If the file is open, it won't be removed until all - * instances are closed. - */ - public static native int remove(String path, long pool); - - /** - * Rename the specified file. - *
        Warning : If a file exists at the new location, then it will be - * overwritten. Moving files or directories across devices may not be - * possible. - * @param fromPath The full path to the original file (using / on all systems) - * @param toPath The full path to the new file (using / on all systems) - * @param pool The pool to use. - */ - public static native int rename(String fromPath, String toPath, long pool); - - /** - * Copy the specified file to another file. - * The new file does not need to exist, it will be created if required. - *
        Warning : If the new file already exists, its contents will be overwritten. - * @param fromPath The full path to the original file (using / on all systems) - * @param toPath The full path to the new file (using / on all systems) - * @param perms Access permissions for the new file if it is created. - * In place of the usual or'd combination of file permissions, the - * value APR_FILE_SOURCE_PERMS may be given, in which case the source - * file's permissions are copied. - * @param pool The pool to use. - */ - public static native int copy(String fromPath, String toPath, int perms, long pool); - - /** - * Append the specified file to another file. - * The new file does not need to exist, it will be created if required. - * @param fromPath The full path to the source file (use / on all systems) - * @param toPath The full path to the destination file (use / on all systems) - * @param perms Access permissions for the destination file if it is created. - * In place of the usual or'd combination of file permissions, the - * value APR_FILE_SOURCE_PERMS may be given, in which case the source - * file's permissions are copied. - * @param pool The pool to use. - */ - public static native int append(String fromPath, String toPath, int perms, long pool); - - /** - * Write the string into the specified file. - * @param str The string to write. Must be NUL terminated! - * @param thefile The file descriptor to write to - */ - public static native int puts(byte [] str, long thefile); - - /** - * Move the read/write file offset to a specified byte within a file. - * @param thefile The file descriptor - * @param where How to move the pointer, one of: - *
        -     * APR_SET  --  set the offset to offset
        -     * APR_CUR  --  add the offset to the current position
        -     * APR_END  --  add the offset to the current file size
        -     * 
        - * @param offset The offset to move the pointer to. - * @return Offset the pointer was actually moved to. - */ - public static native long seek(long thefile, int where, long offset) - throws Error; - - /** - * Write a character into the specified file. - * @param ch The character to write. - * @param thefile The file descriptor to write to - */ - public static native int putc(byte ch, long thefile); - - /** - * Put a character back onto a specified stream. - * @param ch The character to write. - * @param thefile The file descriptor to write to - */ - public static native int ungetc(byte ch, long thefile); - - /** - * Write data to the specified file. - * - * Write will write up to the specified number of - * bytes, but never more. If the OS cannot write that many bytes, it - * will write as many as it can. The third argument is modified to - * reflect the * number of bytes written. - * - * It is possible for both bytes to be written and an error to - * be returned. APR_EINTR is never returned. - * @param thefile The file descriptor to write to. - * @param buf The buffer which contains the data. - * @param offset Start offset in buf - * @param nbytes The number of bytes to write; (-1) for full array. - * @return The number of bytes written. - */ - public static native int write(long thefile, byte[] buf, int offset, int nbytes); - - /** - * Write data to the specified file. - * - * Write will write up to the specified number of - * bytes, but never more. If the OS cannot write that many bytes, it - * will write as many as it can. The third argument is modified to - * reflect the * number of bytes written. - * - * It is possible for both bytes to be written and an error to - * be returned. APR_EINTR is never returned. - * @param thefile The file descriptor to write to. - * @param buf The direct Byte buffer which contains the data. - * @param offset Start offset in buf - * @param nbytes The number of bytes to write - * @return The number of bytes written. - */ - public static native int writeb(long thefile, ByteBuffer buf, int offset, int nbytes); - - /** - * Write data to the specified file, ensuring that all of the data is - * written before returning. - * - * Write will write up to the specified number of - * bytes, but never more. If the OS cannot write that many bytes, the - * process/thread will block until they can be written. Exceptional - * error such as "out of space" or "pipe closed" will terminate with - * an error. - * - * It is possible for both bytes to be written and an error to - * be returned. And if *bytes_written is less than nbytes, an - * accompanying error is _always_ returned. - * - * APR_EINTR is never returned. - * @param thefile The file descriptor to write to. - * @param buf The buffer which contains the data. - * @param offset Start offset in buf - * @param nbytes The number of bytes to write; (-1) for full array. - * @return The number of bytes written. - */ - public static native int writeFull(long thefile, byte[] buf, int offset, int nbytes); - - /** - * Write data to the specified file, ensuring that all of the data is - * written before returning. - * - * Write will write up to the specified number of - * bytes, but never more. If the OS cannot write that many bytes, the - * process/thread will block until they can be written. Exceptional - * error such as "out of space" or "pipe closed" will terminate with - * an error. - * - * It is possible for both bytes to be written and an error to - * be returned. And if *bytes_written is less than nbytes, an - * accompanying error is _always_ returned. - * - * APR_EINTR is never returned. - * @param thefile The file descriptor to write to. - * @param buf The direct ByteBuffer which contains the data. - * @param offset Start offset in buf - * @param nbytes The number of bytes to write. - * @return The number of bytes written. - */ - public static native int writeFullb(long thefile, ByteBuffer buf, int offset, int nbytes); - - /** - * Write data from aray of byte arrays to the specified file. - * - * It is possible for both bytes to be written and an error to - * be returned. APR_EINTR is never returned. - * - * apr_file_writev is available even if the underlying - * operating system doesn't provide writev(). - * @param thefile The file descriptor to write to. - * @param vec The array from which to get the data to write to the file. - * @return The number of bytes written. - */ - public static native int writev(long thefile, byte[][] vec); - - /** - * Write data from aray of byte arrays to the specified file, - * ensuring that all of the data is written before returning. - * - * writevFull is available even if the underlying - * operating system doesn't provide writev(). - * @param thefile The file descriptor to write to. - * @param vec The array from which to get the data to write to the file. - * @return The number of bytes written. - */ - public static native int writevFull(long thefile, byte[][] vec); - - /** - * Read data from the specified file. - * - * apr_file_read will read up to the specified number of - * bytes, but never more. If there isn't enough data to fill that - * number of bytes, all of the available data is read. The third - * argument is modified to reflect the number of bytes read. If a - * char was put back into the stream via ungetc, it will be the first - * character returned. - * - * It is not possible for both bytes to be read and an APR_EOF - * or other error to be returned. APR_EINTR is never returned. - * @param thefile The file descriptor to read from. - * @param buf The buffer to store the data to. - * @param offset Start offset in buf - * @param nbytes The number of bytes to read (-1) for full array. - * @return the number of bytes read. - */ - public static native int read(long thefile, byte[] buf, int offset, int nbytes); - - /** - * Read data from the specified file. - * - * apr_file_read will read up to the specified number of - * bytes, but never more. If there isn't enough data to fill that - * number of bytes, all of the available data is read. The third - * argument is modified to reflect the number of bytes read. If a - * char was put back into the stream via ungetc, it will be the first - * character returned. - * - * It is not possible for both bytes to be read and an APR_EOF - * or other error to be returned. APR_EINTR is never returned. - * @param thefile The file descriptor to read from. - * @param buf The direct Byte buffer to store the data to. - * @param offset Start offset in buf - * @param nbytes The number of bytes to read. - * @return the number of bytes read. - */ - public static native int readb(long thefile, ByteBuffer buf, int offset, int nbytes); - - /** - * Read data from the specified file, ensuring that the buffer is filled - * before returning. - * - * Read will read up to the specified number of - * bytes, but never more. If there isn't enough data to fill that - * number of bytes, then the process/thread will block until it is - * available or EOF is reached. If a char was put back into the - * stream via ungetc, it will be the first character returned. - * - * It is possible for both bytes to be read and an error to be - * returned. And if *bytes_read is less than nbytes, an accompanying - * error is _always_ returned. - * - * APR_EINTR is never returned. - * @param thefile The file descriptor to read from. - * @param buf The buffer to store the data to. - * @param offset Start offset in buf - * @param nbytes The number of bytes to read (-1) for full array. - * @return the number of bytes read. - */ - public static native int readFull(long thefile, byte[] buf, int offset, int nbytes); - - /** - * Read data from the specified file, ensuring that the buffer is filled - * before returning. - * - * Read will read up to the specified number of - * bytes, but never more. If there isn't enough data to fill that - * number of bytes, then the process/thread will block until it is - * available or EOF is reached. If a char was put back into the - * stream via ungetc, it will be the first character returned. - * - * It is possible for both bytes to be read and an error to be - * returned. And if *bytes_read is less than nbytes, an accompanying - * error is _always_ returned. - * - * APR_EINTR is never returned. - * @param thefile The file descriptor to read from. - * @param buf The direct ByteBuffer to store the data to. - * @param offset Start offset in buf - * @param nbytes The number of bytes to read. - * @return the number of bytes read. - */ - public static native int readFullb(long thefile, ByteBuffer buf, int offset, int nbytes); - - /** - * Read a string from the specified file. - * The buffer will be NUL-terminated if any characters are stored. - * @param buf The buffer to store the string in. - * @param offset Start offset in buf - * @param thefile The file descriptor to read from - */ - public static native int gets(byte[] buf, int offset, long thefile); - - - /** - * Read a character from the specified file. - * @param thefile The file descriptor to read from - * @return The readed character - */ - public static native int getc(long thefile) - throws Error; - - /** - * Are we at the end of the file - * @param fptr The apr file we are testing. - * @return Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. - */ - public static native int eof(long fptr); - - /** - * return the file name of the current file. - * @param thefile The currently open file. - */ - public static native String nameGet(long thefile); - - /** - * Set the specified file's permission bits. - *
        Warning : Some platforms may not be able to apply all of the - * available permission bits; APR_INCOMPLETE will be returned if some - * permissions are specified which could not be set. - *
        Warning : Platforms which do not implement this feature will return - * APR_ENOTIMPL. - * @param fname The file (name) to apply the permissions to. - * @param perms The permission bits to apply to the file. - * - */ - public static native int permsSet(String fname, int perms); - - /** - * Set attributes of the specified file. - * This function should be used in preference to explict manipulation - * of the file permissions, because the operations to provide these - * attributes are platform specific and may involve more than simply - * setting permission bits. - *
        Warning : Platforms which do not implement this feature will return - * APR_ENOTIMPL. - * @param fname The full path to the file (using / on all systems) - * @param attributes Or'd combination of - *
        -     *            APR_FILE_ATTR_READONLY   - make the file readonly
        -     *            APR_FILE_ATTR_EXECUTABLE - make the file executable
        -     *            APR_FILE_ATTR_HIDDEN     - make the file hidden
        -     * 
        - * @param mask Mask of valid bits in attributes. - * @param pool the pool to use. - */ - public static native int attrsSet(String fname, int attributes, int mask, long pool); - - /** - * Set the mtime of the specified file. - *
        Warning : Platforms which do not implement this feature will return - * APR_ENOTIMPL. - * @param fname The full path to the file (using / on all systems) - * @param mtime The mtime to apply to the file in microseconds - * @param pool The pool to use. - */ - public static native int mtimeSet(String fname, long mtime, long pool); - - /** - * Establish a lock on the specified, open file. The lock may be advisory - * or mandatory, at the discretion of the platform. The lock applies to - * the file as a whole, rather than a specific range. Locks are established - * on a per-thread/process basis; a second lock by the same thread will not - * block. - * @param thefile The file to lock. - * @param type The type of lock to establish on the file. - */ - public static native int lock(long thefile, int type); - - /** - * Remove any outstanding locks on the file. - * @param thefile The file to unlock. - */ - public static native int unlock(long thefile); - - /** - * Retrieve the flags that were passed into apr_file_open() - * when the file was opened. - * @param file The file to retrive flags. - * @return the flags - */ - public static native int flagsGet(long file); - - /** - * Truncate the file's length to the specified offset - * @param fp The file to truncate - * @param offset The offset to truncate to. - */ - public static native int trunc(long fp, long offset); - - /** - * Create an anonymous pipe. - * @param io io[0] The file descriptors to use as input to the pipe. - * io[1] The file descriptor to use as output from the pipe. - * @param pool The pool to operate on. - */ - public static native int pipeCreate(long [] io, long pool); - - /** - * Get the timeout value for a pipe or manipulate the blocking state. - * @param thepipe The pipe we are getting a timeout for. - * @return The current timeout value in microseconds. - */ - public static native long pipeTimeoutGet(long thepipe) - throws Error; - - /** - * Set the timeout value for a pipe or manipulate the blocking state. - * @param thepipe The pipe we are setting a timeout on. - * @param timeout The timeout value in microseconds. Values < 0 mean wait - * forever, 0 means do not wait at all. - */ - public static native int pipeTimeoutSet(long thepipe, long timeout); - - /** - * Duplicate the specified file descriptor. - * @param newFile The file to duplicate. - * newFile must point to a valid apr_file_t, or point to NULL. - * @param oldFile The file to duplicate. - * @param pool The pool to use for the new file. - * @return Duplicated file structure. - */ - public static native long dup(long newFile, long oldFile, long pool) - throws Error; - - /** - * Duplicate the specified file descriptor and close the original. - * @param newFile The old file that is to be closed and reused. - * newFile MUST point at a valid apr_file_t. It cannot be NULL. - * @param oldFile The file to duplicate. - * @param pool The pool to use for the new file. - * @return Status code. - */ - public static native int dup2(long newFile, long oldFile, long pool); - - /** - * Get the specified file's stats. The file is specified by filename, - * instead of using a pre-opened file. - * @param finfo Where to store the information about the file, which is - * never touched if the call fails. - * @param fname The name of the file to stat. - * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values - * @param pool the pool to use to allocate the new file. - */ - public static native int stat(FileInfo finfo, String fname, int wanted, long pool); - - /** - * Get the specified file's stats. - * @param finfo Where to store the information about the file. - * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values - * @param thefile The file to get information about. - */ - public static native int infoGet(FileInfo finfo, int wanted, long thefile); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; +/* Import needed classes */ +import java.nio.ByteBuffer; +/** File + * + * @author Mladen Turk + * @version $Revision: 369000 $, $Date: 2006-01-14 09:08:44 +0100 (sam., 14 janv. 2006) $ + */ + +public class File { + + /** Open the file for reading */ + public static final int APR_FOPEN_READ = 0x00001; + /** Open the file for writing */ + public static final int APR_FOPEN_WRITE = 0x00002; + /** Create the file if not there */ + public static final int APR_FOPEN_CREATE = 0x00004; + /** Append to the end of the file */ + public static final int APR_FOPEN_APPEND = 0x00008; + /** Open the file and truncate to 0 length */ + public static final int APR_FOPEN_TRUNCATE = 0x00010; + /** Open the file in binary mode */ + public static final int APR_FOPEN_BINARY = 0x00020; + /** Open should fail if APR_CREATE and file exists. */ + public static final int APR_FOPEN_EXCL = 0x00040; + /** Open the file for buffered I/O */ + public static final int APR_FOPEN_BUFFERED = 0x00080; + /** Delete the file after close */ + public static final int APR_FOPEN_DELONCLOSE = 0x00100; + /** Platform dependent tag to open the file for + * use across multiple threads + */ + public static final int APR_FOPEN_XTHREAD = 0x00200; + /** Platform dependent support for higher level locked read/write + * access to support writes across process/machines + */ + public static final int APR_FOPEN_SHARELOCK = 0x00400; + /** Do not register a cleanup when the file is opened */ + public static final int APR_FOPEN_NOCLEANUP = 0x00800; + /** Advisory flag that this file should support + * apr_socket_sendfile operation + */ + public static final int APR_FOPEN_SENDFILE_ENABLED = 0x01000; + /** Platform dependent flag to enable large file support; + *
        Warning : The APR_LARGEFILE flag only has effect on some platforms + * where sizeof(apr_off_t) == 4. Where implemented, it allows opening + * and writing to a file which exceeds the size which can be + * represented by apr_off_t (2 gigabytes). When a file's size does + * exceed 2Gb, apr_file_info_get() will fail with an error on the + * descriptor, likewise apr_stat()/apr_lstat() will fail on the + * filename. apr_dir_read() will fail with APR_INCOMPLETE on a + * directory entry for a large file depending on the particular + * APR_FINFO_* flags. Generally, it is not recommended to use this + * flag. + */ + public static final int APR_FOPEN_LARGEFILE = 0x04000; + + /** Set the file position */ + public static final int APR_SET = 0; + /** Current */ + public static final int APR_CUR = 1; + /** Go to end of file */ + public static final int APR_END = 2; + + /* flags for apr_file_attrs_set */ + + /** File is read-only */ + public static final int APR_FILE_ATTR_READONLY = 0x01; + /** File is executable */ + public static final int APR_FILE_ATTR_EXECUTABLE = 0x02; + /** File is hidden */ + public static final int APR_FILE_ATTR_HIDDEN = 0x04; + + + /* File lock types/flags */ + + /** Shared lock. More than one process or thread can hold a shared lock + * at any given time. Essentially, this is a "read lock", preventing + * writers from establishing an exclusive lock. + */ + public static final int APR_FLOCK_SHARED = 1; + + /** Exclusive lock. Only one process may hold an exclusive lock at any + * given time. This is analogous to a "write lock". + */ + public static final int APR_FLOCK_EXCLUSIVE = 2; + /** mask to extract lock type */ + public static final int APR_FLOCK_TYPEMASK = 0x000F; + /** do not block while acquiring the file lock */ + public static final int APR_FLOCK_NONBLOCK = 0x0010; + + /* apr_filetype_e values for the filetype member of the + * apr_file_info_t structure + *
        Warning :: Not all of the filetypes below can be determined. + * For example, a given platform might not correctly report + * a socket descriptor as APR_SOCK if that type isn't + * well-identified on that platform. In such cases where + * a filetype exists but cannot be described by the recognized + * flags below, the filetype will be APR_UNKFILE. If the + * filetype member is not determined, the type will be APR_NOFILE. + */ + + /** no file type determined */ + public static final int APR_NOFILE = 0; + /** a regular file */ + public static final int APR_REG = 1; + /** a directory */ + public static final int APR_DIR = 2; + /** a character device */ + public static final int APR_CHR = 3; + /** a block device */ + public static final int APR_BLK = 4; + /** a FIFO / pipe */ + public static final int APR_PIPE = 5; + /** a symbolic link */ + public static final int APR_LNK = 6; + /** a [unix domain] socket */ + public static final int APR_SOCK = 7; + /** a file of some other unknown type */ + public static final int APR_UNKFILE = 127; + + + /* + * apr_file_permissions File Permissions flags + */ + + public static final int APR_FPROT_USETID = 0x8000; /** Set user id */ + public static final int APR_FPROT_UREAD = 0x0400; /** Read by user */ + public static final int APR_FPROT_UWRITE = 0x0200; /** Write by user */ + public static final int APR_FPROT_UEXECUTE = 0x0100; /** Execute by user */ + + public static final int APR_FPROT_GSETID = 0x4000; /** Set group id */ + public static final int APR_FPROT_GREAD = 0x0040; /** Read by group */ + public static final int APR_FPROT_GWRITE = 0x0020; /** Write by group */ + public static final int APR_FPROT_GEXECUTE = 0x0010; /** Execute by group */ + + public static final int APR_FPROT_WSTICKY = 0x2000; /** Sticky bit */ + public static final int APR_FPROT_WREAD = 0x0004; /** Read by others */ + public static final int APR_FPROT_WWRITE = 0x0002; /** Write by others */ + public static final int APR_FPROT_WEXECUTE = 0x0001; /** Execute by others */ + public static final int APR_FPROT_OS_DEFAULT = 0x0FFF; /** use OS's default permissions */ + + + public static final int APR_FINFO_LINK = 0x00000001; /** Stat the link not the file itself if it is a link */ + public static final int APR_FINFO_MTIME = 0x00000010; /** Modification Time */ + public static final int APR_FINFO_CTIME = 0x00000020; /** Creation or inode-changed time */ + public static final int APR_FINFO_ATIME = 0x00000040; /** Access Time */ + public static final int APR_FINFO_SIZE = 0x00000100; /** Size of the file */ + public static final int APR_FINFO_CSIZE = 0x00000200; /** Storage size consumed by the file */ + public static final int APR_FINFO_DEV = 0x00001000; /** Device */ + public static final int APR_FINFO_INODE = 0x00002000; /** Inode */ + public static final int APR_FINFO_NLINK = 0x00004000; /** Number of links */ + public static final int APR_FINFO_TYPE = 0x00008000; /** Type */ + public static final int APR_FINFO_USER = 0x00010000; /** User */ + public static final int APR_FINFO_GROUP = 0x00020000; /** Group */ + public static final int APR_FINFO_UPROT = 0x00100000; /** User protection bits */ + public static final int APR_FINFO_GPROT = 0x00200000; /** Group protection bits */ + public static final int APR_FINFO_WPROT = 0x00400000; /** World protection bits */ + public static final int APR_FINFO_ICASE = 0x01000000; /** if dev is case insensitive */ + public static final int APR_FINFO_NAME = 0x02000000; /** ->name in proper case */ + + public static final int APR_FINFO_MIN = 0x00008170; /** type, mtime, ctime, atime, size */ + public static final int APR_FINFO_IDENT = 0x00003000; /** dev and inode */ + public static final int APR_FINFO_OWNER = 0x00030000; /** user and group */ + public static final int APR_FINFO_PROT = 0x00700000; /** all protections */ + public static final int APR_FINFO_NORM = 0x0073b170; /** an atomic unix apr_stat() */ + public static final int APR_FINFO_DIRENT = 0x02000000; /** an atomic unix apr_dir_read() */ + + + + /** + * Open the specified file. + * @param fname The full path to the file (using / on all systems) + * @param flag Or'ed value of: + *
        +     * APR_FOPEN_READ              open for reading
        +     * APR_FOPEN_WRITE             open for writing
        +     * APR_FOPEN_CREATE            create the file if not there
        +     * APR_FOPEN_APPEND            file ptr is set to end prior to all writes
        +     * APR_FOPEN_TRUNCATE          set length to zero if file exists
        +     * APR_FOPEN_BINARY            not a text file (This flag is ignored on
        +     *                             UNIX because it has no meaning)
        +     * APR_FOPEN_BUFFERED          buffer the data.  Default is non-buffered
        +     * APR_FOPEN_EXCL              return error if APR_CREATE and file exists
        +     * APR_FOPEN_DELONCLOSE        delete the file after closing.
        +     * APR_FOPEN_XTHREAD           Platform dependent tag to open the file
        +     *                             for use across multiple threads
        +     * APR_FOPEN_SHARELOCK         Platform dependent support for higher
        +     *                             level locked read/write access to support
        +     *                             writes across process/machines
        +     * APR_FOPEN_NOCLEANUP         Do not register a cleanup with the pool
        +     *                             passed in on the pool argument (see below).
        +     *                             The apr_os_file_t handle in apr_file_t will not
        +     *                             be closed when the pool is destroyed.
        +     * APR_FOPEN_SENDFILE_ENABLED  Open with appropriate platform semantics
        +     *                             for sendfile operations.  Advisory only,
        +     *                             apr_socket_sendfile does not check this flag.
        +     * 
        + * @param perm Access permissions for file. + * @param pool The pool to use. + * If perm is APR_OS_DEFAULT and the file is being created, + * appropriate default permissions will be used. + * @return The opened file descriptor. + */ + public static native long open(String fname, int flag, int perm, long pool) + throws Error; + + /** + * Close the specified file. + * @param file The file descriptor to close. + */ + public static native int close(long file); + + /** + * Flush the file's buffer. + * @param thefile The file descriptor to flush + */ + public static native int flush(long thefile); + + /** + * Open a temporary file + * @param templ The template to use when creating a temp file. + * @param flags The flags to open the file with. If this is zero, + * the file is opened with + * APR_CREATE | APR_READ | APR_WRITE | APR_EXCL | APR_DELONCLOSE + * @param pool The pool to allocate the file out of. + * @return The apr file to use as a temporary file. + * + * This function generates a unique temporary file name from template. + * The last six characters of template must be XXXXXX and these are replaced + * with a string that makes the filename unique. Since it will be modified, + * template must not be a string constant, but should be declared as a character + * array. + * + */ + public static native long mktemp(String templ, int flags, long pool) + throws Error; + + /** + * Delete the specified file. + * @param path The full path to the file (using / on all systems) + * @param pool The pool to use. + * If the file is open, it won't be removed until all + * instances are closed. + */ + public static native int remove(String path, long pool); + + /** + * Rename the specified file. + *
        Warning : If a file exists at the new location, then it will be + * overwritten. Moving files or directories across devices may not be + * possible. + * @param fromPath The full path to the original file (using / on all systems) + * @param toPath The full path to the new file (using / on all systems) + * @param pool The pool to use. + */ + public static native int rename(String fromPath, String toPath, long pool); + + /** + * Copy the specified file to another file. + * The new file does not need to exist, it will be created if required. + *
        Warning : If the new file already exists, its contents will be overwritten. + * @param fromPath The full path to the original file (using / on all systems) + * @param toPath The full path to the new file (using / on all systems) + * @param perms Access permissions for the new file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + */ + public static native int copy(String fromPath, String toPath, int perms, long pool); + + /** + * Append the specified file to another file. + * The new file does not need to exist, it will be created if required. + * @param fromPath The full path to the source file (use / on all systems) + * @param toPath The full path to the destination file (use / on all systems) + * @param perms Access permissions for the destination file if it is created. + * In place of the usual or'd combination of file permissions, the + * value APR_FILE_SOURCE_PERMS may be given, in which case the source + * file's permissions are copied. + * @param pool The pool to use. + */ + public static native int append(String fromPath, String toPath, int perms, long pool); + + /** + * Write the string into the specified file. + * @param str The string to write. Must be NUL terminated! + * @param thefile The file descriptor to write to + */ + public static native int puts(byte [] str, long thefile); + + /** + * Move the read/write file offset to a specified byte within a file. + * @param thefile The file descriptor + * @param where How to move the pointer, one of: + *
        +     * APR_SET  --  set the offset to offset
        +     * APR_CUR  --  add the offset to the current position
        +     * APR_END  --  add the offset to the current file size
        +     * 
        + * @param offset The offset to move the pointer to. + * @return Offset the pointer was actually moved to. + */ + public static native long seek(long thefile, int where, long offset) + throws Error; + + /** + * Write a character into the specified file. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ + public static native int putc(byte ch, long thefile); + + /** + * Put a character back onto a specified stream. + * @param ch The character to write. + * @param thefile The file descriptor to write to + */ + public static native int ungetc(byte ch, long thefile); + + /** + * Write data to the specified file. + * + * Write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param offset Start offset in buf + * @param nbytes The number of bytes to write; (-1) for full array. + * @return The number of bytes written. + */ + public static native int write(long thefile, byte[] buf, int offset, int nbytes); + + /** + * Write data to the specified file. + * + * Write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, it + * will write as many as it can. The third argument is modified to + * reflect the * number of bytes written. + * + * It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + * @param thefile The file descriptor to write to. + * @param buf The direct Byte buffer which contains the data. + * @param offset Start offset in buf + * @param nbytes The number of bytes to write + * @return The number of bytes written. + */ + public static native int writeb(long thefile, ByteBuffer buf, int offset, int nbytes); + + /** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * + * Write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * APR_EINTR is never returned. + * @param thefile The file descriptor to write to. + * @param buf The buffer which contains the data. + * @param offset Start offset in buf + * @param nbytes The number of bytes to write; (-1) for full array. + * @return The number of bytes written. + */ + public static native int writeFull(long thefile, byte[] buf, int offset, int nbytes); + + /** + * Write data to the specified file, ensuring that all of the data is + * written before returning. + * + * Write will write up to the specified number of + * bytes, but never more. If the OS cannot write that many bytes, the + * process/thread will block until they can be written. Exceptional + * error such as "out of space" or "pipe closed" will terminate with + * an error. + * + * It is possible for both bytes to be written and an error to + * be returned. And if *bytes_written is less than nbytes, an + * accompanying error is _always_ returned. + * + * APR_EINTR is never returned. + * @param thefile The file descriptor to write to. + * @param buf The direct ByteBuffer which contains the data. + * @param offset Start offset in buf + * @param nbytes The number of bytes to write. + * @return The number of bytes written. + */ + public static native int writeFullb(long thefile, ByteBuffer buf, int offset, int nbytes); + + /** + * Write data from aray of byte arrays to the specified file. + * + * It is possible for both bytes to be written and an error to + * be returned. APR_EINTR is never returned. + * + * apr_file_writev is available even if the underlying + * operating system doesn't provide writev(). + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @return The number of bytes written. + */ + public static native int writev(long thefile, byte[][] vec); + + /** + * Write data from aray of byte arrays to the specified file, + * ensuring that all of the data is written before returning. + * + * writevFull is available even if the underlying + * operating system doesn't provide writev(). + * @param thefile The file descriptor to write to. + * @param vec The array from which to get the data to write to the file. + * @return The number of bytes written. + */ + public static native int writevFull(long thefile, byte[][] vec); + + /** + * Read data from the specified file. + * + * apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * It is not possible for both bytes to be read and an APR_EOF + * or other error to be returned. APR_EINTR is never returned. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param offset Start offset in buf + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes read. + */ + public static native int read(long thefile, byte[] buf, int offset, int nbytes); + + /** + * Read data from the specified file. + * + * apr_file_read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, all of the available data is read. The third + * argument is modified to reflect the number of bytes read. If a + * char was put back into the stream via ungetc, it will be the first + * character returned. + * + * It is not possible for both bytes to be read and an APR_EOF + * or other error to be returned. APR_EINTR is never returned. + * @param thefile The file descriptor to read from. + * @param buf The direct Byte buffer to store the data to. + * @param offset Start offset in buf + * @param nbytes The number of bytes to read. + * @return the number of bytes read. + */ + public static native int readb(long thefile, ByteBuffer buf, int offset, int nbytes); + + /** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * + * Read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * APR_EINTR is never returned. + * @param thefile The file descriptor to read from. + * @param buf The buffer to store the data to. + * @param offset Start offset in buf + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes read. + */ + public static native int readFull(long thefile, byte[] buf, int offset, int nbytes); + + /** + * Read data from the specified file, ensuring that the buffer is filled + * before returning. + * + * Read will read up to the specified number of + * bytes, but never more. If there isn't enough data to fill that + * number of bytes, then the process/thread will block until it is + * available or EOF is reached. If a char was put back into the + * stream via ungetc, it will be the first character returned. + * + * It is possible for both bytes to be read and an error to be + * returned. And if *bytes_read is less than nbytes, an accompanying + * error is _always_ returned. + * + * APR_EINTR is never returned. + * @param thefile The file descriptor to read from. + * @param buf The direct ByteBuffer to store the data to. + * @param offset Start offset in buf + * @param nbytes The number of bytes to read. + * @return the number of bytes read. + */ + public static native int readFullb(long thefile, ByteBuffer buf, int offset, int nbytes); + + /** + * Read a string from the specified file. + * The buffer will be NUL-terminated if any characters are stored. + * @param buf The buffer to store the string in. + * @param offset Start offset in buf + * @param thefile The file descriptor to read from + */ + public static native int gets(byte[] buf, int offset, long thefile); + + + /** + * Read a character from the specified file. + * @param thefile The file descriptor to read from + * @return The readed character + */ + public static native int getc(long thefile) + throws Error; + + /** + * Are we at the end of the file + * @param fptr The apr file we are testing. + * @return Returns APR_EOF if we are at the end of file, APR_SUCCESS otherwise. + */ + public static native int eof(long fptr); + + /** + * return the file name of the current file. + * @param thefile The currently open file. + */ + public static native String nameGet(long thefile); + + /** + * Set the specified file's permission bits. + *
        Warning : Some platforms may not be able to apply all of the + * available permission bits; APR_INCOMPLETE will be returned if some + * permissions are specified which could not be set. + *
        Warning : Platforms which do not implement this feature will return + * APR_ENOTIMPL. + * @param fname The file (name) to apply the permissions to. + * @param perms The permission bits to apply to the file. + * + */ + public static native int permsSet(String fname, int perms); + + /** + * Set attributes of the specified file. + * This function should be used in preference to explict manipulation + * of the file permissions, because the operations to provide these + * attributes are platform specific and may involve more than simply + * setting permission bits. + *
        Warning : Platforms which do not implement this feature will return + * APR_ENOTIMPL. + * @param fname The full path to the file (using / on all systems) + * @param attributes Or'd combination of + *
        +     *            APR_FILE_ATTR_READONLY   - make the file readonly
        +     *            APR_FILE_ATTR_EXECUTABLE - make the file executable
        +     *            APR_FILE_ATTR_HIDDEN     - make the file hidden
        +     * 
        + * @param mask Mask of valid bits in attributes. + * @param pool the pool to use. + */ + public static native int attrsSet(String fname, int attributes, int mask, long pool); + + /** + * Set the mtime of the specified file. + *
        Warning : Platforms which do not implement this feature will return + * APR_ENOTIMPL. + * @param fname The full path to the file (using / on all systems) + * @param mtime The mtime to apply to the file in microseconds + * @param pool The pool to use. + */ + public static native int mtimeSet(String fname, long mtime, long pool); + + /** + * Establish a lock on the specified, open file. The lock may be advisory + * or mandatory, at the discretion of the platform. The lock applies to + * the file as a whole, rather than a specific range. Locks are established + * on a per-thread/process basis; a second lock by the same thread will not + * block. + * @param thefile The file to lock. + * @param type The type of lock to establish on the file. + */ + public static native int lock(long thefile, int type); + + /** + * Remove any outstanding locks on the file. + * @param thefile The file to unlock. + */ + public static native int unlock(long thefile); + + /** + * Retrieve the flags that were passed into apr_file_open() + * when the file was opened. + * @param file The file to retrive flags. + * @return the flags + */ + public static native int flagsGet(long file); + + /** + * Truncate the file's length to the specified offset + * @param fp The file to truncate + * @param offset The offset to truncate to. + */ + public static native int trunc(long fp, long offset); + + /** + * Create an anonymous pipe. + * @param io io[0] The file descriptors to use as input to the pipe. + * io[1] The file descriptor to use as output from the pipe. + * @param pool The pool to operate on. + */ + public static native int pipeCreate(long [] io, long pool); + + /** + * Get the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are getting a timeout for. + * @return The current timeout value in microseconds. + */ + public static native long pipeTimeoutGet(long thepipe) + throws Error; + + /** + * Set the timeout value for a pipe or manipulate the blocking state. + * @param thepipe The pipe we are setting a timeout on. + * @param timeout The timeout value in microseconds. Values < 0 mean wait + * forever, 0 means do not wait at all. + */ + public static native int pipeTimeoutSet(long thepipe, long timeout); + + /** + * Duplicate the specified file descriptor. + * @param newFile The file to duplicate. + * newFile must point to a valid apr_file_t, or point to NULL. + * @param oldFile The file to duplicate. + * @param pool The pool to use for the new file. + * @return Duplicated file structure. + */ + public static native long dup(long newFile, long oldFile, long pool) + throws Error; + + /** + * Duplicate the specified file descriptor and close the original. + * @param newFile The old file that is to be closed and reused. + * newFile MUST point at a valid apr_file_t. It cannot be NULL. + * @param oldFile The file to duplicate. + * @param pool The pool to use for the new file. + * @return Status code. + */ + public static native int dup2(long newFile, long oldFile, long pool); + + /** + * Get the specified file's stats. The file is specified by filename, + * instead of using a pre-opened file. + * @param finfo Where to store the information about the file, which is + * never touched if the call fails. + * @param fname The name of the file to stat. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param pool the pool to use to allocate the new file. + */ + public static native int stat(FileInfo finfo, String fname, int wanted, long pool); + + /** + * Get the specified file's stats. + * @param finfo Where to store the information about the file. + * @param wanted The desired apr_finfo_t fields, as a bit flag of APR_FINFO_ values + * @param thefile The file to get information about. + */ + public static native int infoGet(FileInfo finfo, int wanted, long thefile); + +} diff --git a/java/org/apache/tomcat/jni/FileInfo.java b/java/org/apache/tomcat/jni/FileInfo.java index 25cad5b2e..a4b1f32f7 100644 --- a/java/org/apache/tomcat/jni/FileInfo.java +++ b/java/org/apache/tomcat/jni/FileInfo.java @@ -1,66 +1,66 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Fileinfo - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class FileInfo { - - /** Allocates memory and closes lingering handles in the specified pool */ - public long pool; - /** The bitmask describing valid fields of this apr_finfo_t structure - * including all available 'wanted' fields and potentially more */ - public int valid; - /** The access permissions of the file. Mimics Unix access rights. */ - public int protection; - /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, - * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. - * If the type cannot be determined, the value is APR_UNKFILE. - */ - public int filetype; - /** The user id that owns the file */ - public int user; - /** The group id that owns the file */ - public int group; - /** The inode of the file. */ - public int inode; - /** The id of the device the file is on. */ - public int device; - /** The number of hard links to the file. */ - public int nlink; - /** The size of the file */ - public long size; - /** The storage size consumed by the file */ - public long csize; - /** The time the file was last accessed */ - public long atime; - /** The time the file was last modified */ - public long mtime; - /** The time the file was created, or the inode was last changed */ - public long ctime; - /** The pathname of the file (possibly unrooted) */ - public String fname; - /** The file's name (no path) in filesystem case */ - public String name; - /** The file's handle, if accessed (can be submitted to apr_duphandle) */ - public long filehand; - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Fileinfo + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class FileInfo { + + /** Allocates memory and closes lingering handles in the specified pool */ + public long pool; + /** The bitmask describing valid fields of this apr_finfo_t structure + * including all available 'wanted' fields and potentially more */ + public int valid; + /** The access permissions of the file. Mimics Unix access rights. */ + public int protection; + /** The type of file. One of APR_REG, APR_DIR, APR_CHR, APR_BLK, APR_PIPE, + * APR_LNK or APR_SOCK. If the type is undetermined, the value is APR_NOFILE. + * If the type cannot be determined, the value is APR_UNKFILE. + */ + public int filetype; + /** The user id that owns the file */ + public int user; + /** The group id that owns the file */ + public int group; + /** The inode of the file. */ + public int inode; + /** The id of the device the file is on. */ + public int device; + /** The number of hard links to the file. */ + public int nlink; + /** The size of the file */ + public long size; + /** The storage size consumed by the file */ + public long csize; + /** The time the file was last accessed */ + public long atime; + /** The time the file was last modified */ + public long mtime; + /** The time the file was created, or the inode was last changed */ + public long ctime; + /** The pathname of the file (possibly unrooted) */ + public String fname; + /** The file's name (no path) in filesystem case */ + public String name; + /** The file's handle, if accessed (can be submitted to apr_duphandle) */ + public long filehand; + +} diff --git a/java/org/apache/tomcat/jni/Global.java b/java/org/apache/tomcat/jni/Global.java index 8368508cb..a15b6e42d 100644 --- a/java/org/apache/tomcat/jni/Global.java +++ b/java/org/apache/tomcat/jni/Global.java @@ -1,95 +1,95 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Global - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Global { - - /** - * Create and initialize a mutex that can be used to synchronize both - * processes and threads. Note: There is considerable overhead in using - * this API if only cross-process or cross-thread mutual exclusion is - * required. See apr_proc_mutex.h and apr_thread_mutex.h for more - * specialized lock routines. - *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports - * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. - * @param fname A file name to use if the lock mechanism requires one. This - * argument should always be provided. The lock code itself will - * determine if it should be used. - * @param mech The mechanism to use for the interprocess lock, if any; one of - *
        -     *            APR_LOCK_FCNTL
        -     *            APR_LOCK_FLOCK
        -     *            APR_LOCK_SYSVSEM
        -     *            APR_LOCK_POSIXSEM
        -     *            APR_LOCK_PROC_PTHREAD
        -     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
        -     * 
        - * @param pool the pool from which to allocate the mutex. - * @return Newly created mutex. - */ - public static native long create(String fname, int mech, long pool) - throws Error; - - /** - * Re-open a mutex in a child process. - * @param fname A file name to use if the mutex mechanism requires one. This - * argument should always be provided. The mutex code itself will - * determine if it should be used. This filename should be the - * same one that was passed to apr_proc_mutex_create(). - * @param pool The pool to operate on. - * This function must be called to maintain portability, even - * if the underlying lock mechanism does not require it. - * @return Newly opened mutex. - */ - public static native long childInit(String fname, long pool) - throws Error; - - /** - * Acquire the lock for the given mutex. If the mutex is already locked, - * the current thread will be put to sleep until the lock becomes available. - * @param mutex the mutex on which to acquire the lock. - */ - public static native int lock(long mutex); - - /** - * Attempt to acquire the lock for the given mutex. If the mutex has already - * been acquired, the call returns immediately with APR_EBUSY. Note: it - * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine - * if the return value was APR_EBUSY, for portability reasons. - * @param mutex the mutex on which to attempt the lock acquiring. - */ - public static native int trylock(long mutex); - - /** - * Release the lock for the given mutex. - * @param mutex the mutex from which to release the lock. - */ - public static native int unlock(long mutex); - - /** - * Destroy the mutex and free the memory associated with the lock. - * @param mutex the mutex to destroy. - */ - public static native int destroy(long mutex); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Global + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Global { + + /** + * Create and initialize a mutex that can be used to synchronize both + * processes and threads. Note: There is considerable overhead in using + * this API if only cross-process or cross-thread mutual exclusion is + * required. See apr_proc_mutex.h and apr_thread_mutex.h for more + * specialized lock routines. + *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
        +     *            APR_LOCK_FCNTL
        +     *            APR_LOCK_FLOCK
        +     *            APR_LOCK_SYSVSEM
        +     *            APR_LOCK_POSIXSEM
        +     *            APR_LOCK_PROC_PTHREAD
        +     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
        +     * 
        + * @param pool the pool from which to allocate the mutex. + * @return Newly created mutex. + */ + public static native long create(String fname, int mech, long pool) + throws Error; + + /** + * Re-open a mutex in a child process. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_proc_mutex_create(). + * @param pool The pool to operate on. + * This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + * @return Newly opened mutex. + */ + public static native long childInit(String fname, long pool) + throws Error; + + /** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ + public static native int lock(long mutex); + + /** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ + public static native int trylock(long mutex); + + /** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ + public static native int unlock(long mutex); + + /** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ + public static native int destroy(long mutex); + +} diff --git a/java/org/apache/tomcat/jni/Library.java b/java/org/apache/tomcat/jni/Library.java index 242165a42..1cd0aacc0 100644 --- a/java/org/apache/tomcat/jni/Library.java +++ b/java/org/apache/tomcat/jni/Library.java @@ -1,207 +1,207 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Library - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public final class Library { - - /* Default library names */ - private static String [] NAMES = {"tcnative-1", "libtcnative-1"}; - /* - * A handle to the unique Library singleton instance. - */ - static private Library _instance = null; - - private Library() - { - boolean loaded = false; - String err = ""; - for (int i = 0; i < NAMES.length; i++) { - try { - System.loadLibrary(NAMES[i]); - loaded = true; - } - catch (Throwable e) { - if ( i > 0) - err += ", "; - err += e.getMessage(); - } - if (loaded) - break; - } - if (!loaded) { - err += "("; - err += System.getProperty("java.library.path"); - err += ")"; - throw new UnsatisfiedLinkError(err); - } - } - - private Library(String libraryName) - { - System.loadLibrary(libraryName); - } - - /* create global TCN's APR pool - * This has to be the first call to TCN library. - */ - private static native boolean initialize(); - /* destroy global TCN's APR pool - * This has to be the last call to TCN library. - */ - public static native void terminate(); - /* Internal function for loading APR Features */ - private static native boolean has(int what); - /* Internal function for loading APR Features */ - private static native int version(int what); - /* Internal function for loading APR sizes */ - private static native int size(int what); - - /* TCN_MAJOR_VERSION */ - public static int TCN_MAJOR_VERSION = 0; - /* TCN_MINOR_VERSION */ - public static int TCN_MINOR_VERSION = 0; - /* TCN_PATCH_VERSION */ - public static int TCN_PATCH_VERSION = 0; - /* TCN_IS_DEV_VERSION */ - public static int TCN_IS_DEV_VERSION = 0; - /* APR_MAJOR_VERSION */ - public static int APR_MAJOR_VERSION = 0; - /* APR_MINOR_VERSION */ - public static int APR_MINOR_VERSION = 0; - /* APR_PATCH_VERSION */ - public static int APR_PATCH_VERSION = 0; - /* APR_IS_DEV_VERSION */ - public static int APR_IS_DEV_VERSION = 0; - - /* TCN_VERSION_STRING */ - public static native String versionString(); - /* APR_VERSION_STRING */ - public static native String aprVersionString(); - - /* APR Feature Macros */ - public static boolean APR_HAVE_IPV6 = false; - public static boolean APR_HAS_SHARED_MEMORY = false; - public static boolean APR_HAS_THREADS = false; - public static boolean APR_HAS_SENDFILE = false; - public static boolean APR_HAS_MMAP = false; - public static boolean APR_HAS_FORK = false; - public static boolean APR_HAS_RANDOM = false; - public static boolean APR_HAS_OTHER_CHILD = false; - public static boolean APR_HAS_DSO = false; - public static boolean APR_HAS_SO_ACCEPTFILTER = false; - public static boolean APR_HAS_UNICODE_FS = false; - public static boolean APR_HAS_PROC_INVOKED = false; - public static boolean APR_HAS_USER = false; - public static boolean APR_HAS_LARGE_FILES = false; - public static boolean APR_HAS_XTHREAD_FILES = false; - public static boolean APR_HAS_OS_UUID = false; - /* Are we big endian? */ - public static boolean APR_IS_BIGENDIAN = false; - /* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible - * to poll on files/pipes. - */ - public static boolean APR_FILES_AS_SOCKETS = false; - /* This macro indicates whether or not EBCDIC is the native character set. - */ - public static boolean APR_CHARSET_EBCDIC = false; - /* Is the TCP_NODELAY socket option inherited from listening sockets? - */ - public static boolean APR_TCP_NODELAY_INHERITED = false; - /* Is the O_NONBLOCK flag inherited from listening sockets? - */ - public static boolean APR_O_NONBLOCK_INHERITED = false; - - - public static int APR_SIZEOF_VOIDP; - public static int APR_PATH_MAX; - public static int APRMAXHOSTLEN; - public static int APR_MAX_IOVEC_SIZE; - public static int APR_MAX_SECS_TO_LINGER; - public static int APR_MMAP_THRESHOLD; - public static int APR_MMAP_LIMIT; - - /* return global TCN's APR pool */ - public static native long globalPool(); - - /** - * Setup any APR internal data structures. This MUST be the first function - * called for any APR library. - * @param libraryName the name of the library to load - */ - static public boolean initialize(String libraryName) - throws Exception - { - if (_instance == null) { - if (libraryName == null) - _instance = new Library(); - else - _instance = new Library(libraryName); - TCN_MAJOR_VERSION = version(0x01); - TCN_MINOR_VERSION = version(0x02); - TCN_PATCH_VERSION = version(0x03); - TCN_IS_DEV_VERSION = version(0x04); - APR_MAJOR_VERSION = version(0x11); - APR_MINOR_VERSION = version(0x12); - APR_PATCH_VERSION = version(0x13); - APR_IS_DEV_VERSION = version(0x14); - - APR_SIZEOF_VOIDP = size(1); - APR_PATH_MAX = size(2); - APRMAXHOSTLEN = size(3); - APR_MAX_IOVEC_SIZE = size(4); - APR_MAX_SECS_TO_LINGER = size(5); - APR_MMAP_THRESHOLD = size(6); - APR_MMAP_LIMIT = size(7); - - APR_HAVE_IPV6 = has(0); - APR_HAS_SHARED_MEMORY = has(1); - APR_HAS_THREADS = has(2); - APR_HAS_SENDFILE = has(3); - APR_HAS_MMAP = has(4); - APR_HAS_FORK = has(5); - APR_HAS_RANDOM = has(6); - APR_HAS_OTHER_CHILD = has(7); - APR_HAS_DSO = has(8); - APR_HAS_SO_ACCEPTFILTER = has(9); - APR_HAS_UNICODE_FS = has(10); - APR_HAS_PROC_INVOKED = has(11); - APR_HAS_USER = has(12); - APR_HAS_LARGE_FILES = has(13); - APR_HAS_XTHREAD_FILES = has(14); - APR_HAS_OS_UUID = has(15); - APR_IS_BIGENDIAN = has(16); - APR_FILES_AS_SOCKETS = has(17); - APR_CHARSET_EBCDIC = has(18); - APR_TCP_NODELAY_INHERITED = has(19); - APR_O_NONBLOCK_INHERITED = has(20); - if (APR_MAJOR_VERSION < 1) { - throw new UnsatisfiedLinkError("Unsupported APR Version (" + - aprVersionString() + ")"); - } - if (!APR_HAS_THREADS) { - throw new UnsatisfiedLinkError("Missing APR_HAS_THREADS"); - } - } - return initialize(); - } -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Library + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public final class Library { + + /* Default library names */ + private static String [] NAMES = {"tcnative-1", "libtcnative-1"}; + /* + * A handle to the unique Library singleton instance. + */ + static private Library _instance = null; + + private Library() + { + boolean loaded = false; + String err = ""; + for (int i = 0; i < NAMES.length; i++) { + try { + System.loadLibrary(NAMES[i]); + loaded = true; + } + catch (Throwable e) { + if ( i > 0) + err += ", "; + err += e.getMessage(); + } + if (loaded) + break; + } + if (!loaded) { + err += "("; + err += System.getProperty("java.library.path"); + err += ")"; + throw new UnsatisfiedLinkError(err); + } + } + + private Library(String libraryName) + { + System.loadLibrary(libraryName); + } + + /* create global TCN's APR pool + * This has to be the first call to TCN library. + */ + private static native boolean initialize(); + /* destroy global TCN's APR pool + * This has to be the last call to TCN library. + */ + public static native void terminate(); + /* Internal function for loading APR Features */ + private static native boolean has(int what); + /* Internal function for loading APR Features */ + private static native int version(int what); + /* Internal function for loading APR sizes */ + private static native int size(int what); + + /* TCN_MAJOR_VERSION */ + public static int TCN_MAJOR_VERSION = 0; + /* TCN_MINOR_VERSION */ + public static int TCN_MINOR_VERSION = 0; + /* TCN_PATCH_VERSION */ + public static int TCN_PATCH_VERSION = 0; + /* TCN_IS_DEV_VERSION */ + public static int TCN_IS_DEV_VERSION = 0; + /* APR_MAJOR_VERSION */ + public static int APR_MAJOR_VERSION = 0; + /* APR_MINOR_VERSION */ + public static int APR_MINOR_VERSION = 0; + /* APR_PATCH_VERSION */ + public static int APR_PATCH_VERSION = 0; + /* APR_IS_DEV_VERSION */ + public static int APR_IS_DEV_VERSION = 0; + + /* TCN_VERSION_STRING */ + public static native String versionString(); + /* APR_VERSION_STRING */ + public static native String aprVersionString(); + + /* APR Feature Macros */ + public static boolean APR_HAVE_IPV6 = false; + public static boolean APR_HAS_SHARED_MEMORY = false; + public static boolean APR_HAS_THREADS = false; + public static boolean APR_HAS_SENDFILE = false; + public static boolean APR_HAS_MMAP = false; + public static boolean APR_HAS_FORK = false; + public static boolean APR_HAS_RANDOM = false; + public static boolean APR_HAS_OTHER_CHILD = false; + public static boolean APR_HAS_DSO = false; + public static boolean APR_HAS_SO_ACCEPTFILTER = false; + public static boolean APR_HAS_UNICODE_FS = false; + public static boolean APR_HAS_PROC_INVOKED = false; + public static boolean APR_HAS_USER = false; + public static boolean APR_HAS_LARGE_FILES = false; + public static boolean APR_HAS_XTHREAD_FILES = false; + public static boolean APR_HAS_OS_UUID = false; + /* Are we big endian? */ + public static boolean APR_IS_BIGENDIAN = false; + /* APR sets APR_FILES_AS_SOCKETS to 1 on systems where it is possible + * to poll on files/pipes. + */ + public static boolean APR_FILES_AS_SOCKETS = false; + /* This macro indicates whether or not EBCDIC is the native character set. + */ + public static boolean APR_CHARSET_EBCDIC = false; + /* Is the TCP_NODELAY socket option inherited from listening sockets? + */ + public static boolean APR_TCP_NODELAY_INHERITED = false; + /* Is the O_NONBLOCK flag inherited from listening sockets? + */ + public static boolean APR_O_NONBLOCK_INHERITED = false; + + + public static int APR_SIZEOF_VOIDP; + public static int APR_PATH_MAX; + public static int APRMAXHOSTLEN; + public static int APR_MAX_IOVEC_SIZE; + public static int APR_MAX_SECS_TO_LINGER; + public static int APR_MMAP_THRESHOLD; + public static int APR_MMAP_LIMIT; + + /* return global TCN's APR pool */ + public static native long globalPool(); + + /** + * Setup any APR internal data structures. This MUST be the first function + * called for any APR library. + * @param libraryName the name of the library to load + */ + static public boolean initialize(String libraryName) + throws Exception + { + if (_instance == null) { + if (libraryName == null) + _instance = new Library(); + else + _instance = new Library(libraryName); + TCN_MAJOR_VERSION = version(0x01); + TCN_MINOR_VERSION = version(0x02); + TCN_PATCH_VERSION = version(0x03); + TCN_IS_DEV_VERSION = version(0x04); + APR_MAJOR_VERSION = version(0x11); + APR_MINOR_VERSION = version(0x12); + APR_PATCH_VERSION = version(0x13); + APR_IS_DEV_VERSION = version(0x14); + + APR_SIZEOF_VOIDP = size(1); + APR_PATH_MAX = size(2); + APRMAXHOSTLEN = size(3); + APR_MAX_IOVEC_SIZE = size(4); + APR_MAX_SECS_TO_LINGER = size(5); + APR_MMAP_THRESHOLD = size(6); + APR_MMAP_LIMIT = size(7); + + APR_HAVE_IPV6 = has(0); + APR_HAS_SHARED_MEMORY = has(1); + APR_HAS_THREADS = has(2); + APR_HAS_SENDFILE = has(3); + APR_HAS_MMAP = has(4); + APR_HAS_FORK = has(5); + APR_HAS_RANDOM = has(6); + APR_HAS_OTHER_CHILD = has(7); + APR_HAS_DSO = has(8); + APR_HAS_SO_ACCEPTFILTER = has(9); + APR_HAS_UNICODE_FS = has(10); + APR_HAS_PROC_INVOKED = has(11); + APR_HAS_USER = has(12); + APR_HAS_LARGE_FILES = has(13); + APR_HAS_XTHREAD_FILES = has(14); + APR_HAS_OS_UUID = has(15); + APR_IS_BIGENDIAN = has(16); + APR_FILES_AS_SOCKETS = has(17); + APR_CHARSET_EBCDIC = has(18); + APR_TCP_NODELAY_INHERITED = has(19); + APR_O_NONBLOCK_INHERITED = has(20); + if (APR_MAJOR_VERSION < 1) { + throw new UnsatisfiedLinkError("Unsupported APR Version (" + + aprVersionString() + ")"); + } + if (!APR_HAS_THREADS) { + throw new UnsatisfiedLinkError("Missing APR_HAS_THREADS"); + } + } + return initialize(); + } +} diff --git a/java/org/apache/tomcat/jni/Local.java b/java/org/apache/tomcat/jni/Local.java index 5c214ff5d..ce7bbdeb0 100644 --- a/java/org/apache/tomcat/jni/Local.java +++ b/java/org/apache/tomcat/jni/Local.java @@ -1,75 +1,75 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Local socket - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Local { - - /** - * Create a socket. - * @param path The address of the new socket. - * @param cont The parent pool to use - * @return The new socket that has been set up. - */ - public static native long create(String path, long cont) - throws Exception; - - /** - * Bind the socket to its associated port - * @param sock The socket to bind - * @param sa The socket address to bind to - * This may be where we will find out if there is any other process - * using the selected port. - */ - public static native int bind(long sock, long sa); - - /** - * Listen to a bound socket for connections. - * @param sock The socket to listen on - * @param backlog The number of outstanding connections allowed in the sockets - * listen queue. If this value is less than zero, for NT pipes - * the number of instances is unlimite. - * - */ - public static native int listen(long sock, int backlog); - - /** - * Accept a new connection request - * @param sock The socket we are listening on. - * @param pool The pool for the new socket. - * @return A copy of the socket that is connected to the socket that - * made the connection request. This is the socket which should - * be used for all future communication. - */ - public static native long accept(long sock) - throws Exception; - - /** - * Issue a connection request to a socket either on the same machine - * or a different one. - * @param sock The socket we wish to use for our side of the connection - * @param sa The address of the machine we wish to connect to. - * Unused for NT Pipes. - */ - public static native int connect(long sock, long sa); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Local socket + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Local { + + /** + * Create a socket. + * @param path The address of the new socket. + * @param cont The parent pool to use + * @return The new socket that has been set up. + */ + public static native long create(String path, long cont) + throws Exception; + + /** + * Bind the socket to its associated port + * @param sock The socket to bind + * @param sa The socket address to bind to + * This may be where we will find out if there is any other process + * using the selected port. + */ + public static native int bind(long sock, long sa); + + /** + * Listen to a bound socket for connections. + * @param sock The socket to listen on + * @param backlog The number of outstanding connections allowed in the sockets + * listen queue. If this value is less than zero, for NT pipes + * the number of instances is unlimite. + * + */ + public static native int listen(long sock, int backlog); + + /** + * Accept a new connection request + * @param sock The socket we are listening on. + * @param pool The pool for the new socket. + * @return A copy of the socket that is connected to the socket that + * made the connection request. This is the socket which should + * be used for all future communication. + */ + public static native long accept(long sock) + throws Exception; + + /** + * Issue a connection request to a socket either on the same machine + * or a different one. + * @param sock The socket we wish to use for our side of the connection + * @param sa The address of the machine we wish to connect to. + * Unused for NT Pipes. + */ + public static native int connect(long sock, long sa); + +} diff --git a/java/org/apache/tomcat/jni/Lock.java b/java/org/apache/tomcat/jni/Lock.java index 05ac7fa98..a74b0dcc6 100644 --- a/java/org/apache/tomcat/jni/Lock.java +++ b/java/org/apache/tomcat/jni/Lock.java @@ -1,122 +1,122 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Lock - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Lock { - - /** - * Enumerated potential types for APR process locking methods - *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports - * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. - */ - - public static final int APR_LOCK_FCNTL = 0; /** fcntl() */ - public static final int APR_LOCK_FLOCK = 1; /** flock() */ - public static final int APR_LOCK_SYSVSEM = 2; /** System V Semaphores */ - public static final int APR_LOCK_PROC_PTHREAD = 3; /** POSIX pthread process-based locking */ - public static final int APR_LOCK_POSIXSEM = 4; /** POSIX semaphore process-based locking */ - public static final int APR_LOCK_DEFAULT = 5; /** Use the default process lock */ - - /** - * Create and initialize a mutex that can be used to synchronize processes. - *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports - * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. - * @param fname A file name to use if the lock mechanism requires one. This - * argument should always be provided. The lock code itself will - * determine if it should be used. - * @param mech The mechanism to use for the interprocess lock, if any; one of - *
        -     *            APR_LOCK_FCNTL
        -     *            APR_LOCK_FLOCK
        -     *            APR_LOCK_SYSVSEM
        -     *            APR_LOCK_POSIXSEM
        -     *            APR_LOCK_PROC_PTHREAD
        -     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
        -     * 
        - * @param pool the pool from which to allocate the mutex. - * @return Newly created mutex. - */ - public static native long create(String fname, int mech, long pool) - throws Error; - - /** - * Re-open a mutex in a child process. - * This function must be called to maintain portability, even - * if the underlying lock mechanism does not require it. - * @param fname A file name to use if the mutex mechanism requires one. This - * argument should always be provided. The mutex code itself will - * determine if it should be used. This filename should be the - * same one that was passed to apr_proc_mutex_create(). - * @param pool The pool to operate on. - * @return Newly opened mutex. - */ - public static native long childInit(String fname, long pool) - throws Error; - - /** - * Acquire the lock for the given mutex. If the mutex is already locked, - * the current thread will be put to sleep until the lock becomes available. - * @param mutex the mutex on which to acquire the lock. - */ - public static native int lock(long mutex); - - /** - * Attempt to acquire the lock for the given mutex. If the mutex has already - * been acquired, the call returns immediately with APR_EBUSY. Note: it - * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine - * if the return value was APR_EBUSY, for portability reasons. - * @param mutex the mutex on which to attempt the lock acquiring. - */ - public static native int trylock(long mutex); - - /** - * Release the lock for the given mutex. - * @param mutex the mutex from which to release the lock. - */ - public static native int unlock(long mutex); - - /** - * Destroy the mutex and free the memory associated with the lock. - * @param mutex the mutex to destroy. - */ - public static native int destroy(long mutex); - - /** - * Return the name of the lockfile for the mutex, or NULL - * if the mutex doesn't use a lock file - */ - public static native String lockfile(long mutex); - - /** - * Display the name of the mutex, as it relates to the actual method used. - * This matches the valid options for Apache's AcceptMutex directive - * @param mutex the name of the mutex - */ - public static native String name(long mutex); - - /** - * Display the name of the default mutex: APR_LOCK_DEFAULT - */ - public static native String defname(); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Lock + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Lock { + + /** + * Enumerated potential types for APR process locking methods + *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + */ + + public static final int APR_LOCK_FCNTL = 0; /** fcntl() */ + public static final int APR_LOCK_FLOCK = 1; /** flock() */ + public static final int APR_LOCK_SYSVSEM = 2; /** System V Semaphores */ + public static final int APR_LOCK_PROC_PTHREAD = 3; /** POSIX pthread process-based locking */ + public static final int APR_LOCK_POSIXSEM = 4; /** POSIX semaphore process-based locking */ + public static final int APR_LOCK_DEFAULT = 5; /** Use the default process lock */ + + /** + * Create and initialize a mutex that can be used to synchronize processes. + *
        Warning : Check APR_HAS_foo_SERIALIZE defines to see if the platform supports + * APR_LOCK_foo. Only APR_LOCK_DEFAULT is portable. + * @param fname A file name to use if the lock mechanism requires one. This + * argument should always be provided. The lock code itself will + * determine if it should be used. + * @param mech The mechanism to use for the interprocess lock, if any; one of + *
        +     *            APR_LOCK_FCNTL
        +     *            APR_LOCK_FLOCK
        +     *            APR_LOCK_SYSVSEM
        +     *            APR_LOCK_POSIXSEM
        +     *            APR_LOCK_PROC_PTHREAD
        +     *            APR_LOCK_DEFAULT     pick the default mechanism for the platform
        +     * 
        + * @param pool the pool from which to allocate the mutex. + * @return Newly created mutex. + */ + public static native long create(String fname, int mech, long pool) + throws Error; + + /** + * Re-open a mutex in a child process. + * This function must be called to maintain portability, even + * if the underlying lock mechanism does not require it. + * @param fname A file name to use if the mutex mechanism requires one. This + * argument should always be provided. The mutex code itself will + * determine if it should be used. This filename should be the + * same one that was passed to apr_proc_mutex_create(). + * @param pool The pool to operate on. + * @return Newly opened mutex. + */ + public static native long childInit(String fname, long pool) + throws Error; + + /** + * Acquire the lock for the given mutex. If the mutex is already locked, + * the current thread will be put to sleep until the lock becomes available. + * @param mutex the mutex on which to acquire the lock. + */ + public static native int lock(long mutex); + + /** + * Attempt to acquire the lock for the given mutex. If the mutex has already + * been acquired, the call returns immediately with APR_EBUSY. Note: it + * is important that the APR_STATUS_IS_EBUSY(s) macro be used to determine + * if the return value was APR_EBUSY, for portability reasons. + * @param mutex the mutex on which to attempt the lock acquiring. + */ + public static native int trylock(long mutex); + + /** + * Release the lock for the given mutex. + * @param mutex the mutex from which to release the lock. + */ + public static native int unlock(long mutex); + + /** + * Destroy the mutex and free the memory associated with the lock. + * @param mutex the mutex to destroy. + */ + public static native int destroy(long mutex); + + /** + * Return the name of the lockfile for the mutex, or NULL + * if the mutex doesn't use a lock file + */ + public static native String lockfile(long mutex); + + /** + * Display the name of the mutex, as it relates to the actual method used. + * This matches the valid options for Apache's AcceptMutex directive + * @param mutex the name of the mutex + */ + public static native String name(long mutex); + + /** + * Display the name of the default mutex: APR_LOCK_DEFAULT + */ + public static native String defname(); + +} diff --git a/java/org/apache/tomcat/jni/Mmap.java b/java/org/apache/tomcat/jni/Mmap.java index 42521bc12..d4211f0af 100644 --- a/java/org/apache/tomcat/jni/Mmap.java +++ b/java/org/apache/tomcat/jni/Mmap.java @@ -1,72 +1,72 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Mmap - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Mmap { - /** MMap opened for reading */ - public static final int APR_MMAP_READ = 1; - /** MMap opened for writing */ - public static final int APR_MMAP_WRITE = 2; - - - /** - * Create a new mmap'ed file out of an existing APR file. - * @param file The file turn into an mmap. - * @param offset The offset into the file to start the data pointer at. - * @param size The size of the file - * @param flag bit-wise or of: - *
        -     * APR_MMAP_READ       MMap opened for reading
        -     * APR_MMAP_WRITE      MMap opened for writing
        -     * 
        - * @param pool The pool to use when creating the mmap. - * @return The newly created mmap'ed file. - */ - public static native long create(long file, long offset, long size, int flag, long pool) - throws Error; - - /** - * Duplicate the specified MMAP. - * @param mmap The mmap to duplicate. - * @param pool The pool to use for new_mmap. - * @return Duplicated mmap'ed file. - */ - public static native long dup(long mmap, long pool) - throws Error; - - /** - * Remove a mmap'ed. - * @param mm The mmap'ed file. - */ - public static native int delete(long mm); - - /** - * Move the pointer into the mmap'ed file to the specified offset. - * @param mm The mmap'ed file. - * @param offset The offset to move to. - * @return The pointer to the offset specified. - */ - public static native long offset(long mm, long offset) - throws Error; - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Mmap + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Mmap { + /** MMap opened for reading */ + public static final int APR_MMAP_READ = 1; + /** MMap opened for writing */ + public static final int APR_MMAP_WRITE = 2; + + + /** + * Create a new mmap'ed file out of an existing APR file. + * @param file The file turn into an mmap. + * @param offset The offset into the file to start the data pointer at. + * @param size The size of the file + * @param flag bit-wise or of: + *
        +     * APR_MMAP_READ       MMap opened for reading
        +     * APR_MMAP_WRITE      MMap opened for writing
        +     * 
        + * @param pool The pool to use when creating the mmap. + * @return The newly created mmap'ed file. + */ + public static native long create(long file, long offset, long size, int flag, long pool) + throws Error; + + /** + * Duplicate the specified MMAP. + * @param mmap The mmap to duplicate. + * @param pool The pool to use for new_mmap. + * @return Duplicated mmap'ed file. + */ + public static native long dup(long mmap, long pool) + throws Error; + + /** + * Remove a mmap'ed. + * @param mm The mmap'ed file. + */ + public static native int delete(long mm); + + /** + * Move the pointer into the mmap'ed file to the specified offset. + * @param mm The mmap'ed file. + * @param offset The offset to move to. + * @return The pointer to the offset specified. + */ + public static native long offset(long mm, long offset) + throws Error; + +} diff --git a/java/org/apache/tomcat/jni/Multicast.java b/java/org/apache/tomcat/jni/Multicast.java index d4fde406a..43b2b3a85 100644 --- a/java/org/apache/tomcat/jni/Multicast.java +++ b/java/org/apache/tomcat/jni/Multicast.java @@ -1,77 +1,77 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Multicast - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Multicast { - - /** - * Join a Multicast Group - * @param sock The socket to join a multicast group - * @param join The address of the multicast group to join - * @param iface Address of the interface to use. If NULL is passed, the - * default multicast interface will be used. (OS Dependent) - * @param source Source Address to accept transmissions from (non-NULL - * implies Source-Specific Multicast) - */ - public static native int join(long sock, long join, - long iface, long source); - - /** - * Leave a Multicast Group. All arguments must be the same as - * apr_mcast_join. - * @param sock The socket to leave a multicast group - * @param addr The address of the multicast group to leave - * @param iface Address of the interface to use. If NULL is passed, the - * default multicast interface will be used. (OS Dependent) - * @param source Source Address to accept transmissions from (non-NULL - * implies Source-Specific Multicast) - */ - public static native int leave(long sock, long addr, - long iface, long source); - - /** - * Set the Multicast Time to Live (ttl) for a multicast transmission. - * @param sock The socket to set the multicast ttl - * @param ttl Time to live to Assign. 0-255, default=1 - *
        Remark : If the TTL is 0, packets will only be seen - * by sockets on the local machine, - * and only when multicast loopback is enabled. - */ - public static native int hops(long sock, int ttl); - - /** - * Toggle IP Multicast Loopback - * @param sock The socket to set multicast loopback - * @param opt false=disable, true=enable - */ - public static native int loopback(long sock, boolean opt); - - - /** - * Set the Interface to be used for outgoing Multicast Transmissions. - * @param sock The socket to set the multicast interface on - * @param iface Address of the interface to use for Multicast - */ - public static native int ointerface(long sock, long iface); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Multicast + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Multicast { + + /** + * Join a Multicast Group + * @param sock The socket to join a multicast group + * @param join The address of the multicast group to join + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ + public static native int join(long sock, long join, + long iface, long source); + + /** + * Leave a Multicast Group. All arguments must be the same as + * apr_mcast_join. + * @param sock The socket to leave a multicast group + * @param addr The address of the multicast group to leave + * @param iface Address of the interface to use. If NULL is passed, the + * default multicast interface will be used. (OS Dependent) + * @param source Source Address to accept transmissions from (non-NULL + * implies Source-Specific Multicast) + */ + public static native int leave(long sock, long addr, + long iface, long source); + + /** + * Set the Multicast Time to Live (ttl) for a multicast transmission. + * @param sock The socket to set the multicast ttl + * @param ttl Time to live to Assign. 0-255, default=1 + *
        Remark : If the TTL is 0, packets will only be seen + * by sockets on the local machine, + * and only when multicast loopback is enabled. + */ + public static native int hops(long sock, int ttl); + + /** + * Toggle IP Multicast Loopback + * @param sock The socket to set multicast loopback + * @param opt false=disable, true=enable + */ + public static native int loopback(long sock, boolean opt); + + + /** + * Set the Interface to be used for outgoing Multicast Transmissions. + * @param sock The socket to set the multicast interface on + * @param iface Address of the interface to use for Multicast + */ + public static native int ointerface(long sock, long iface); + +} diff --git a/java/org/apache/tomcat/jni/OS.java b/java/org/apache/tomcat/jni/OS.java index 068c63c9f..a184409a9 100644 --- a/java/org/apache/tomcat/jni/OS.java +++ b/java/org/apache/tomcat/jni/OS.java @@ -1,127 +1,127 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** OS - * - * @author Mladen Turk - * @version $Revision: 386278 $, $Date: 2006-03-16 08:15:58 +0100 (jeu., 16 mars 2006) $ - */ - -public class OS { - - /* OS Enums */ - private static final int UNIX = 1; - private static final int NETWARE = 2; - private static final int WIN32 = 3; - private static final int WIN64 = 4; - private static final int LINUX = 5; - private static final int SOLARIS = 6; - private static final int BSD = 7; - - public static final int LOG_EMERG = 1; - public static final int LOG_ERROR = 2; - public static final int LOG_NOTICE = 3; - public static final int LOG_WARN = 4; - public static final int LOG_INFO = 5; - public static final int LOG_DEBUG = 6; - - /** - * Check for OS type. - * @param type OS type to test. - */ - private static native boolean is(int type); - - public static final boolean IS_UNIX = is(UNIX); - public static final boolean IS_NETWARE = is(NETWARE); - public static final boolean IS_WIN32 = is(WIN32); - public static final boolean IS_WIN64 = is(WIN64); - public static final boolean IS_LINUX = is(LINUX); - public static final boolean IS_SOLARIS = is(SOLARIS); - public static final boolean IS_BSD = is(BSD); - - /** - * Get the name of the system default characer set. - * @param pool the pool to allocate the name from, if needed - */ - public static native String defaultEncoding(long pool); - - /** - * Get the name of the current locale character set. - * Defers to apr_os_default_encoding if the current locale's - * data can't be retreved on this system. - * @param pool the pool to allocate the name from, if needed - */ - public static native String localeEncoding(long pool); - - /** - * Generate random bytes. - * @param buf Buffer to fill with random bytes - * @param len Length of buffer in bytes - */ - public static native int random(byte [] buf, int len); - - /** - * Gather system info. - *
        -     * On exit the inf array will be filled with:
        -     * inf[0]  - Total usable main memory size
        -     * inf[1]  - Available memory size
        -     * inf[2]  - Total page file/swap space size
        -     * inf[3]  - Page file/swap space still available
        -     * inf[4]  - Amount of shared memory
        -     * inf[5]  - Memory used by buffers
        -     * inf[6]  - Memory Load
        -     *
        -     * inf[7]  - Idle Time in microseconds
        -     * inf[8]  - Kernel Time in microseconds
        -     * inf[9]  - User Time in microseconds
        -     *
        -     * inf[10] - Process creation time (apr_time_t)
        -     * inf[11] - Process Kernel Time in microseconds
        -     * inf[12] - Process User Time in microseconds
        -     *
        -     * inf[13] - Current working set size.
        -     * inf[14] - Peak working set size.
        -     * inf[15] - Number of page faults.
        -     * 
        - * @param inf array that will be filled with system information. - * Array length must be at least 16. - */ - public static native int info(long [] inf); - - /** - * Expand environment variables. - * @param str String to expand - * @return Expanded string with replaced environment variables. - */ - public static native String expand(String str); - - /** - * Initialize system logging. - * @param domain String that will be prepended to every message - */ - public static native void sysloginit(String domain); - - /** - * Log message. - * @param level Log message severity. See LOG_XXX enums. - * @param message Message to log - */ - public static native void syslog(int level, String message); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** OS + * + * @author Mladen Turk + * @version $Revision: 386278 $, $Date: 2006-03-16 08:15:58 +0100 (jeu., 16 mars 2006) $ + */ + +public class OS { + + /* OS Enums */ + private static final int UNIX = 1; + private static final int NETWARE = 2; + private static final int WIN32 = 3; + private static final int WIN64 = 4; + private static final int LINUX = 5; + private static final int SOLARIS = 6; + private static final int BSD = 7; + + public static final int LOG_EMERG = 1; + public static final int LOG_ERROR = 2; + public static final int LOG_NOTICE = 3; + public static final int LOG_WARN = 4; + public static final int LOG_INFO = 5; + public static final int LOG_DEBUG = 6; + + /** + * Check for OS type. + * @param type OS type to test. + */ + private static native boolean is(int type); + + public static final boolean IS_UNIX = is(UNIX); + public static final boolean IS_NETWARE = is(NETWARE); + public static final boolean IS_WIN32 = is(WIN32); + public static final boolean IS_WIN64 = is(WIN64); + public static final boolean IS_LINUX = is(LINUX); + public static final boolean IS_SOLARIS = is(SOLARIS); + public static final boolean IS_BSD = is(BSD); + + /** + * Get the name of the system default characer set. + * @param pool the pool to allocate the name from, if needed + */ + public static native String defaultEncoding(long pool); + + /** + * Get the name of the current locale character set. + * Defers to apr_os_default_encoding if the current locale's + * data can't be retreved on this system. + * @param pool the pool to allocate the name from, if needed + */ + public static native String localeEncoding(long pool); + + /** + * Generate random bytes. + * @param buf Buffer to fill with random bytes + * @param len Length of buffer in bytes + */ + public static native int random(byte [] buf, int len); + + /** + * Gather system info. + *
        +     * On exit the inf array will be filled with:
        +     * inf[0]  - Total usable main memory size
        +     * inf[1]  - Available memory size
        +     * inf[2]  - Total page file/swap space size
        +     * inf[3]  - Page file/swap space still available
        +     * inf[4]  - Amount of shared memory
        +     * inf[5]  - Memory used by buffers
        +     * inf[6]  - Memory Load
        +     *
        +     * inf[7]  - Idle Time in microseconds
        +     * inf[8]  - Kernel Time in microseconds
        +     * inf[9]  - User Time in microseconds
        +     *
        +     * inf[10] - Process creation time (apr_time_t)
        +     * inf[11] - Process Kernel Time in microseconds
        +     * inf[12] - Process User Time in microseconds
        +     *
        +     * inf[13] - Current working set size.
        +     * inf[14] - Peak working set size.
        +     * inf[15] - Number of page faults.
        +     * 
        + * @param inf array that will be filled with system information. + * Array length must be at least 16. + */ + public static native int info(long [] inf); + + /** + * Expand environment variables. + * @param str String to expand + * @return Expanded string with replaced environment variables. + */ + public static native String expand(String str); + + /** + * Initialize system logging. + * @param domain String that will be prepended to every message + */ + public static native void sysloginit(String domain); + + /** + * Log message. + * @param level Log message severity. See LOG_XXX enums. + * @param message Message to log + */ + public static native void syslog(int level, String message); + +} diff --git a/java/org/apache/tomcat/jni/PasswordCallback.java b/java/org/apache/tomcat/jni/PasswordCallback.java index c023d1eec..b0d6450e8 100644 --- a/java/org/apache/tomcat/jni/PasswordCallback.java +++ b/java/org/apache/tomcat/jni/PasswordCallback.java @@ -1,33 +1,33 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** PasswordCallback Interface - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public interface PasswordCallback { - - /** - * Called when the password is required - * @param prompt Password prompt - * @return Valid password or null - */ - public String callback(String prompt); -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** PasswordCallback Interface + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public interface PasswordCallback { + + /** + * Called when the password is required + * @param prompt Password prompt + * @return Valid password or null + */ + public String callback(String prompt); +} diff --git a/java/org/apache/tomcat/jni/Poll.java b/java/org/apache/tomcat/jni/Poll.java index faff80d37..3a903b46a 100644 --- a/java/org/apache/tomcat/jni/Poll.java +++ b/java/org/apache/tomcat/jni/Poll.java @@ -1,157 +1,157 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Poll - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Poll { - - /** - * Poll options - */ - public static final int APR_POLLIN = 0x001; /** Can read without blocking */ - public static final int APR_POLLPRI = 0x002; /** Priority data available */ - public static final int APR_POLLOUT = 0x004; /** Can write without blocking */ - public static final int APR_POLLERR = 0x010; /** Pending error */ - public static final int APR_POLLHUP = 0x020; /** Hangup occurred */ - public static final int APR_POLLNVAL = 0x040; /** Descriptior invalid */ - - /** - * Pollset Flags - */ - /** Adding or Removing a Descriptor is thread safe */ - public static final int APR_POLLSET_THREADSAFE = 0x001; - - - /** Used in apr_pollfd_t to determine what the apr_descriptor is - * apr_datatype_e enum - */ - public static final int APR_NO_DESC = 0; /** nothing here */ - public static final int APR_POLL_SOCKET = 1; /** descriptor refers to a socket */ - public static final int APR_POLL_FILE = 2; /** descriptor refers to a file */ - public static final int APR_POLL_LASTDESC = 3; /** descriptor is the last one in the list */ - - /** - * Setup a pollset object. - * If flags equals APR_POLLSET_THREADSAFE, then a pollset is - * created on which it is safe to make concurrent calls to - * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from - * separate threads. This feature is only supported on some - * platforms; the apr_pollset_create() call will fail with - * APR_ENOTIMPL on platforms where it is not supported. - * @param size The maximum number of descriptors that this pollset can hold - * @param p The pool from which to allocate the pollset - * @param flags Optional flags to modify the operation of the pollset. - * @param ttl Maximum time to live for a particular socket. - * @return The pointer in which to return the newly created object - */ - public static native long create(int size, long p, int flags, long ttl) - throws Error; - /** - * Destroy a pollset object - * @param pollset The pollset to destroy - */ - public static native int destroy(long pollset); - - /** - * Add a socket or to a pollset - * If you set client_data in the descriptor, that value - * will be returned in the client_data field whenever this - * descriptor is signalled in apr_pollset_poll(). - * @param pollset The pollset to which to add the descriptor - * @param sock The sockets to add - * @param data Client data to add - * @param reqevents requested events - */ - public static native int add(long pollset, long sock, - int reqevents); - - /** - * Remove a descriptor from a pollset - * @param pollset The pollset from which to remove the descriptor - * @param sock The socket to remove - */ - public static native int remove(long pollset, long sock); - - /** - * Block for activity on the descriptor(s) in a pollset - * @param pollset The pollset to use - * @param timeout Timeout in microseconds - * @param descriptors Array of signalled descriptors (output parameter) - * The desctiptor array must be two times the size of pollset. - * and are populated as follows: - *
        -     * descriptors[n + 0] -> returned events
        -     * descriptors[n + 1] -> socket
        -     * 
        - * @param remove Remove signaled descriptors from pollset - * @return Number of signalled descriptors (output parameter) - * or negative APR error code. - */ - public static native int poll(long pollset, long timeout, - long [] descriptors, boolean remove); - - /** - * Maintain on the descriptor(s) in a pollset - * @param pollset The pollset to use - * @param descriptors Array of signalled descriptors (output parameter) - * The desctiptor array must be the size of pollset. - * and are populated as follows: - *
        -     * descriptors[n] -> socket
        -     * 
        - * @param remove Remove signaled descriptors from pollset - * @return Number of signalled descriptors (output parameter) - * or negative APR error code. - */ - public static native int maintain(long pollset, long [] descriptors, - boolean remove); - - /** - * Set the socket time to live. - * @param pollset The pollset to use - * @param ttl Timeout in microseconds - */ - public static native void setTtl(long pollset, long ttl); - - /** - * Get the socket time to live. - * @param pollset The pollset to use - * @return Timeout in microseconds - */ - public static native long getTtl(long pollset); - - /** - * Return all descriptor(s) in a pollset - * @param pollset The pollset to use - * @param descriptors Array of descriptors (output parameter) - * The desctiptor array must be two times the size of pollset. - * and are populated as follows: - *
        -     * descriptors[n + 0] -> returned events
        -     * descriptors[n + 1] -> socket
        -     * 
        - * @return Number of descriptors (output parameter) in the Poll - * or negative APR error code. - */ - public static native int pollset(long pollset, long [] descriptors); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Poll + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Poll { + + /** + * Poll options + */ + public static final int APR_POLLIN = 0x001; /** Can read without blocking */ + public static final int APR_POLLPRI = 0x002; /** Priority data available */ + public static final int APR_POLLOUT = 0x004; /** Can write without blocking */ + public static final int APR_POLLERR = 0x010; /** Pending error */ + public static final int APR_POLLHUP = 0x020; /** Hangup occurred */ + public static final int APR_POLLNVAL = 0x040; /** Descriptior invalid */ + + /** + * Pollset Flags + */ + /** Adding or Removing a Descriptor is thread safe */ + public static final int APR_POLLSET_THREADSAFE = 0x001; + + + /** Used in apr_pollfd_t to determine what the apr_descriptor is + * apr_datatype_e enum + */ + public static final int APR_NO_DESC = 0; /** nothing here */ + public static final int APR_POLL_SOCKET = 1; /** descriptor refers to a socket */ + public static final int APR_POLL_FILE = 2; /** descriptor refers to a file */ + public static final int APR_POLL_LASTDESC = 3; /** descriptor is the last one in the list */ + + /** + * Setup a pollset object. + * If flags equals APR_POLLSET_THREADSAFE, then a pollset is + * created on which it is safe to make concurrent calls to + * apr_pollset_add(), apr_pollset_remove() and apr_pollset_poll() from + * separate threads. This feature is only supported on some + * platforms; the apr_pollset_create() call will fail with + * APR_ENOTIMPL on platforms where it is not supported. + * @param size The maximum number of descriptors that this pollset can hold + * @param p The pool from which to allocate the pollset + * @param flags Optional flags to modify the operation of the pollset. + * @param ttl Maximum time to live for a particular socket. + * @return The pointer in which to return the newly created object + */ + public static native long create(int size, long p, int flags, long ttl) + throws Error; + /** + * Destroy a pollset object + * @param pollset The pollset to destroy + */ + public static native int destroy(long pollset); + + /** + * Add a socket or to a pollset + * If you set client_data in the descriptor, that value + * will be returned in the client_data field whenever this + * descriptor is signalled in apr_pollset_poll(). + * @param pollset The pollset to which to add the descriptor + * @param sock The sockets to add + * @param data Client data to add + * @param reqevents requested events + */ + public static native int add(long pollset, long sock, + int reqevents); + + /** + * Remove a descriptor from a pollset + * @param pollset The pollset from which to remove the descriptor + * @param sock The socket to remove + */ + public static native int remove(long pollset, long sock); + + /** + * Block for activity on the descriptor(s) in a pollset + * @param pollset The pollset to use + * @param timeout Timeout in microseconds + * @param descriptors Array of signalled descriptors (output parameter) + * The desctiptor array must be two times the size of pollset. + * and are populated as follows: + *
        +     * descriptors[n + 0] -> returned events
        +     * descriptors[n + 1] -> socket
        +     * 
        + * @param remove Remove signaled descriptors from pollset + * @return Number of signalled descriptors (output parameter) + * or negative APR error code. + */ + public static native int poll(long pollset, long timeout, + long [] descriptors, boolean remove); + + /** + * Maintain on the descriptor(s) in a pollset + * @param pollset The pollset to use + * @param descriptors Array of signalled descriptors (output parameter) + * The desctiptor array must be the size of pollset. + * and are populated as follows: + *
        +     * descriptors[n] -> socket
        +     * 
        + * @param remove Remove signaled descriptors from pollset + * @return Number of signalled descriptors (output parameter) + * or negative APR error code. + */ + public static native int maintain(long pollset, long [] descriptors, + boolean remove); + + /** + * Set the socket time to live. + * @param pollset The pollset to use + * @param ttl Timeout in microseconds + */ + public static native void setTtl(long pollset, long ttl); + + /** + * Get the socket time to live. + * @param pollset The pollset to use + * @return Timeout in microseconds + */ + public static native long getTtl(long pollset); + + /** + * Return all descriptor(s) in a pollset + * @param pollset The pollset to use + * @param descriptors Array of descriptors (output parameter) + * The desctiptor array must be two times the size of pollset. + * and are populated as follows: + *
        +     * descriptors[n + 0] -> returned events
        +     * descriptors[n + 1] -> socket
        +     * 
        + * @return Number of descriptors (output parameter) in the Poll + * or negative APR error code. + */ + public static native int pollset(long pollset, long [] descriptors); + +} diff --git a/java/org/apache/tomcat/jni/Pool.java b/java/org/apache/tomcat/jni/Pool.java index 63c2164d4..3d3b43f7f 100644 --- a/java/org/apache/tomcat/jni/Pool.java +++ b/java/org/apache/tomcat/jni/Pool.java @@ -1,163 +1,163 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -import java.nio.ByteBuffer; - -/** Pool - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Pool { - - /** - * Create a new pool. - * @param parent The parent pool. If this is 0, the new pool is a root - * pool. If it is non-zero, the new pool will inherit all - * of its parent pool's attributes, except the apr_pool_t will - * be a sub-pool. - * @return The pool we have just created. - */ - public static native long create(long parent); - - /** - * Clear all memory in the pool and run all the cleanups. This also destroys all - * subpools. - * @param pool The pool to clear - * This does not actually free the memory, it just allows the pool - * to re-use this memory for the next allocation. - */ - public static native void clear(long pool); - - /** - * Destroy the pool. This takes similar action as apr_pool_clear() and then - * frees all the memory. - * This will actually free the memory - * @param pool The pool to destroy - */ - public static native void destroy(long pool); - - /** - * Get the parent pool of the specified pool. - * @param pool The pool for retrieving the parent pool. - * @return The parent of the given pool. - */ - public static native long parentGet(long pool); - - /** - * Determine if pool a is an ancestor of pool b - * @param a The pool to search - * @param b The pool to search for - * @return True if a is an ancestor of b, NULL is considered an ancestor - * of all pools. - */ - public static native boolean isAncestor(long a, long b); - - - /* - * Cleanup - * - * Cleanups are performed in the reverse order they were registered. That is: - * Last In, First Out. A cleanup function can safely allocate memory from - * the pool that is being cleaned up. It can also safely register additional - * cleanups which will be run LIFO, directly after the current cleanup - * terminates. Cleanups have to take caution in calling functions that - * create subpools. Subpools, created during cleanup will NOT automatically - * be cleaned up. In other words, cleanups are to clean up after themselves. - */ - - /** - * Register a function to be called when a pool is cleared or destroyed - * @param pool The pool register the cleanup with - * @param o The object to call when the pool is cleared - * or destroyed - * @return The cleanup handler. - */ - public static native long cleanupRegister(long pool, Object o); - - /** - * Remove a previously registered cleanup function - * @param pool The pool remove the cleanup from - * @param data The cleanup handler to remove from cleanup - */ - public static native void cleanupKill(long pool, long data); - - /** - * Register a process to be killed when a pool dies. - * @param a The pool to use to define the processes lifetime - * @param proc The process to register - * @param how How to kill the process, one of: - *
        -     * APR_KILL_NEVER         -- process is never sent any signals
        -     * APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
        -     * APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
        -     * APR_JUST_WAIT          -- wait forever for the process to complete
        -     * APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
        -     * 
        - */ - public static native void noteSubprocess(long a, long proc, int how); - - /** - * Allocate a block of memory from a pool - * @param p The pool to allocate from - * @param size The amount of memory to allocate - * @return The ByteBuffer with allocated memory - */ - public static native ByteBuffer alloc(long p, int size); - - /** - * Allocate a block of memory from a pool and set all of the memory to 0 - * @param p The pool to allocate from - * @param size The amount of memory to allocate - * @return The ByteBuffer with allocated memory - */ - public static native ByteBuffer calloc(long p, int size); - - /* - * User data management - */ - - /** - * Set the data associated with the current pool - * @param data The user data associated with the pool. - * @param key The key to use for association - * @param pool The current pool - *
        Warning : - * The data to be attached to the pool should have a life span - * at least as long as the pool it is being attached to. - * Object attached to the pool will be globaly referenced - * untill the pool is cleared or dataSet is called with the null data. - * @return APR Status code. - */ - public static native int dataSet(long pool, String key, Object data); - - /** - * Return the data associated with the current pool. - * @param key The key for the data to retrieve - * @param pool The current pool. - */ - public static native Object dataGet(long pool, String key); - - /** - * Run all of the child_cleanups, so that any unnecessary files are - * closed because we are about to exec a new program - */ - public static native void cleanupForExec(); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +import java.nio.ByteBuffer; + +/** Pool + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Pool { + + /** + * Create a new pool. + * @param parent The parent pool. If this is 0, the new pool is a root + * pool. If it is non-zero, the new pool will inherit all + * of its parent pool's attributes, except the apr_pool_t will + * be a sub-pool. + * @return The pool we have just created. + */ + public static native long create(long parent); + + /** + * Clear all memory in the pool and run all the cleanups. This also destroys all + * subpools. + * @param pool The pool to clear + * This does not actually free the memory, it just allows the pool + * to re-use this memory for the next allocation. + */ + public static native void clear(long pool); + + /** + * Destroy the pool. This takes similar action as apr_pool_clear() and then + * frees all the memory. + * This will actually free the memory + * @param pool The pool to destroy + */ + public static native void destroy(long pool); + + /** + * Get the parent pool of the specified pool. + * @param pool The pool for retrieving the parent pool. + * @return The parent of the given pool. + */ + public static native long parentGet(long pool); + + /** + * Determine if pool a is an ancestor of pool b + * @param a The pool to search + * @param b The pool to search for + * @return True if a is an ancestor of b, NULL is considered an ancestor + * of all pools. + */ + public static native boolean isAncestor(long a, long b); + + + /* + * Cleanup + * + * Cleanups are performed in the reverse order they were registered. That is: + * Last In, First Out. A cleanup function can safely allocate memory from + * the pool that is being cleaned up. It can also safely register additional + * cleanups which will be run LIFO, directly after the current cleanup + * terminates. Cleanups have to take caution in calling functions that + * create subpools. Subpools, created during cleanup will NOT automatically + * be cleaned up. In other words, cleanups are to clean up after themselves. + */ + + /** + * Register a function to be called when a pool is cleared or destroyed + * @param pool The pool register the cleanup with + * @param o The object to call when the pool is cleared + * or destroyed + * @return The cleanup handler. + */ + public static native long cleanupRegister(long pool, Object o); + + /** + * Remove a previously registered cleanup function + * @param pool The pool remove the cleanup from + * @param data The cleanup handler to remove from cleanup + */ + public static native void cleanupKill(long pool, long data); + + /** + * Register a process to be killed when a pool dies. + * @param a The pool to use to define the processes lifetime + * @param proc The process to register + * @param how How to kill the process, one of: + *
        +     * APR_KILL_NEVER         -- process is never sent any signals
        +     * APR_KILL_ALWAYS        -- process is sent SIGKILL on apr_pool_t cleanup
        +     * APR_KILL_AFTER_TIMEOUT -- SIGTERM, wait 3 seconds, SIGKILL
        +     * APR_JUST_WAIT          -- wait forever for the process to complete
        +     * APR_KILL_ONLY_ONCE     -- send SIGTERM and then wait
        +     * 
        + */ + public static native void noteSubprocess(long a, long proc, int how); + + /** + * Allocate a block of memory from a pool + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The ByteBuffer with allocated memory + */ + public static native ByteBuffer alloc(long p, int size); + + /** + * Allocate a block of memory from a pool and set all of the memory to 0 + * @param p The pool to allocate from + * @param size The amount of memory to allocate + * @return The ByteBuffer with allocated memory + */ + public static native ByteBuffer calloc(long p, int size); + + /* + * User data management + */ + + /** + * Set the data associated with the current pool + * @param data The user data associated with the pool. + * @param key The key to use for association + * @param pool The current pool + *
        Warning : + * The data to be attached to the pool should have a life span + * at least as long as the pool it is being attached to. + * Object attached to the pool will be globaly referenced + * untill the pool is cleared or dataSet is called with the null data. + * @return APR Status code. + */ + public static native int dataSet(long pool, String key, Object data); + + /** + * Return the data associated with the current pool. + * @param key The key for the data to retrieve + * @param pool The current pool. + */ + public static native Object dataGet(long pool, String key); + + /** + * Run all of the child_cleanups, so that any unnecessary files are + * closed because we are about to exec a new program + */ + public static native void cleanupForExec(); + +} diff --git a/java/org/apache/tomcat/jni/PoolCallback.java b/java/org/apache/tomcat/jni/PoolCallback.java index ec4c0add2..d88b15a24 100644 --- a/java/org/apache/tomcat/jni/PoolCallback.java +++ b/java/org/apache/tomcat/jni/PoolCallback.java @@ -1,32 +1,32 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** PoolCallback Interface - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public interface PoolCallback { - - /** - * Called when the pool is destroyed or cleared - * @return Function must return APR_SUCCESS - */ - public int callback(); -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** PoolCallback Interface + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public interface PoolCallback { + + /** + * Called when the pool is destroyed or cleared + * @return Function must return APR_SUCCESS + */ + public int callback(); +} diff --git a/java/org/apache/tomcat/jni/Proc.java b/java/org/apache/tomcat/jni/Proc.java index a67a562db..38cc3b4a1 100644 --- a/java/org/apache/tomcat/jni/Proc.java +++ b/java/org/apache/tomcat/jni/Proc.java @@ -1,209 +1,209 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Proc - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Proc { - - /* - * apr_cmdtype_e enum - */ - public static final int APR_SHELLCM = 0; /** use the shell to invoke the program */ - public static final int APR_PROGRAM = 1; /** invoke the program directly, no copied env */ - public static final int APR_PROGRAM_ENV = 2; /** invoke the program, replicating our environment */ - public static final int APR_PROGRAM_PATH = 3; /** find program on PATH, use our environment */ - public static final int APR_SHELLCMD_ENV = 4; /** use the shell to invoke the program, - * replicating our environment - */ - - /* - * apr_wait_how_e enum - */ - public static final int APR_WAIT = 0; /** wait for the specified process to finish */ - public static final int APR_NOWAIT = 1; /** do not wait -- just see if it has finished */ - - /* - * apr_exit_why_e enum - */ - public static final int APR_PROC_EXIT = 1; /** process exited normally */ - public static final int APR_PROC_SIGNAL = 2; /** process exited due to a signal */ - public static final int APR_PROC_SIGNAL_CORE = 4; /** process exited and dumped a core file */ - - public static final int APR_NO_PIPE = 0; - public static final int APR_FULL_BLOCK = 1; - public static final int APR_FULL_NONBLOCK = 2; - public static final int APR_PARENT_BLOCK = 3; - public static final int APR_CHILD_BLOCK = 4; - - public static final int APR_LIMIT_CPU = 0; - public static final int APR_LIMIT_MEM = 1; - public static final int APR_LIMIT_NPROC = 2; - public static final int APR_LIMIT_NOFILE = 3; - - - /** child has died, caller must call unregister still */ - public static final int APR_OC_REASON_DEATH = 0; - /** write_fd is unwritable */ - public static final int APR_OC_REASON_UNWRITABLE = 1; - /** a restart is occuring, perform any necessary cleanup (including - * sending a special signal to child) - */ - public static final int APR_OC_REASON_RESTART = 2; - /** unregister has been called, do whatever is necessary (including - * kill the child) - */ - public static final int APR_OC_REASON_UNREGISTER = 3; - /** somehow the child exited without us knowing ... buggy os? */ - public static final int APR_OC_REASON_LOST = 4; - /** a health check is occuring, for most maintainence functions - * this is a no-op. - */ - public static final int APR_OC_REASON_RUNNING = 5; - - /* apr_kill_conditions_e enumeration */ - /** process is never sent any signals */ - public static final int APR_KILL_NEVER = 0; - /** process is sent SIGKILL on apr_pool_t cleanup */ - public static final int APR_KILL_ALWAYS = 1; - /** SIGTERM, wait 3 seconds, SIGKILL */ - public static final int APR_KILL_AFTER_TIMEOUT = 2; - /** wait forever for the process to complete */ - public static final int APR_JUST_WAIT = 3; - /** send SIGTERM and then wait */ - public static final int APR_KILL_ONLY_ONCE = 4; - - public static final int APR_PROC_DETACH_FOREGROUND = 0; /** Do not detach */ - public static final int APR_PROC_DETACH_DAEMONIZE = 1; /** Detach */ - - /* Maximum number of arguments for create process call */ - public static final int MAX_ARGS_SIZE = 1024; - /* Maximum number of environment variables for create process call */ - public static final int MAX_ENV_SIZE = 1024; - - /** - * Allocate apr_proc_t stucture from pool - * This is not an apr function. - * @param cont The pool to use. - */ - public static native long alloc(long cont); - - /** - * This is currently the only non-portable call in APR. This executes - * a standard unix fork. - * @param proc The resulting process handle. - * @param cont The pool to use. - * @return APR_INCHILD for the child, and APR_INPARENT for the parent - * or an error. - */ - public static native int fork(long [] proc, long cont); - - /** - * Create a new process and execute a new program within that process. - * This function returns without waiting for the new process to terminate; - * use apr_proc_wait for that. - * @param progname The program to run - * @param args The arguments to pass to the new program. The first - * one should be the program name. - * @param env The new environment table for the new process. This - * should be a list of NULL-terminated strings. This argument - * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and - * APR_SHELLCMD_ENV types of commands. - * @param attr The procattr we should use to determine how to create the new - * process - * @param pool The pool to use. - * @return The resulting process handle. - */ - public static native int create(long proc, String progname, - String [] args, String [] env, - long attr, long pool); - - /** - * Wait for a child process to die - * @param proc The process handle that corresponds to the desired child process - * @param exit exit[0] The returned exit status of the child, if a child process - * dies, or the signal that caused the child to die. - * On platforms that don't support obtaining this information, - * the status parameter will be returned as APR_ENOTIMPL. - * exit[1] Why the child died, the bitwise or of: - *
        -     * APR_PROC_EXIT         -- process terminated normally
        -     * APR_PROC_SIGNAL       -- process was killed by a signal
        -     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
        -     *                          generated a core dump.
        -     * 
        - * @param waithow How should we wait. One of: - *
        -     * APR_WAIT   -- block until the child process dies.
        -     * APR_NOWAIT -- return immediately regardless of if the
        -     *               child is dead or not.
        -     * 
        - * @return The childs status is in the return code to this process. It is one of: - *
        -     * APR_CHILD_DONE     -- child is no longer running.
        -     * APR_CHILD_NOTDONE  -- child is still running.
        -     * 
        - */ - public static native int wait(long proc, int [] exit, int waithow); - - /** - * Wait for any current child process to die and return information - * about that child. - * @param proc Pointer to NULL on entry, will be filled out with child's - * information - * @param exit exit[0] The returned exit status of the child, if a child process - * dies, or the signal that caused the child to die. - * On platforms that don't support obtaining this information, - * the status parameter will be returned as APR_ENOTIMPL. - * exit[1] Why the child died, the bitwise or of: - *
        -     * APR_PROC_EXIT         -- process terminated normally
        -     * APR_PROC_SIGNAL       -- process was killed by a signal
        -     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
        -     *                          generated a core dump.
        -     * 
        - * @param waithow How should we wait. One of: - *
        -     * APR_WAIT   -- block until the child process dies.
        -     * APR_NOWAIT -- return immediately regardless of if the
        -     *               child is dead or not.
        -     * 
        - * @param pool Pool to allocate child information out of. - */ - public static native int waitAllProcs(long proc, int [] exit, - int waithow, long pool); - - /** - * Detach the process from the controlling terminal. - * @param daemonize set to non-zero if the process should daemonize - * and become a background process, else it will - * stay in the foreground. - */ - public static native int detach(int daemonize); - - /** - * Terminate a process. - * @param proc The process to terminate. - * @param sig How to kill the process. - */ - public static native int kill(long proc, int sig); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Proc + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Proc { + + /* + * apr_cmdtype_e enum + */ + public static final int APR_SHELLCM = 0; /** use the shell to invoke the program */ + public static final int APR_PROGRAM = 1; /** invoke the program directly, no copied env */ + public static final int APR_PROGRAM_ENV = 2; /** invoke the program, replicating our environment */ + public static final int APR_PROGRAM_PATH = 3; /** find program on PATH, use our environment */ + public static final int APR_SHELLCMD_ENV = 4; /** use the shell to invoke the program, + * replicating our environment + */ + + /* + * apr_wait_how_e enum + */ + public static final int APR_WAIT = 0; /** wait for the specified process to finish */ + public static final int APR_NOWAIT = 1; /** do not wait -- just see if it has finished */ + + /* + * apr_exit_why_e enum + */ + public static final int APR_PROC_EXIT = 1; /** process exited normally */ + public static final int APR_PROC_SIGNAL = 2; /** process exited due to a signal */ + public static final int APR_PROC_SIGNAL_CORE = 4; /** process exited and dumped a core file */ + + public static final int APR_NO_PIPE = 0; + public static final int APR_FULL_BLOCK = 1; + public static final int APR_FULL_NONBLOCK = 2; + public static final int APR_PARENT_BLOCK = 3; + public static final int APR_CHILD_BLOCK = 4; + + public static final int APR_LIMIT_CPU = 0; + public static final int APR_LIMIT_MEM = 1; + public static final int APR_LIMIT_NPROC = 2; + public static final int APR_LIMIT_NOFILE = 3; + + + /** child has died, caller must call unregister still */ + public static final int APR_OC_REASON_DEATH = 0; + /** write_fd is unwritable */ + public static final int APR_OC_REASON_UNWRITABLE = 1; + /** a restart is occuring, perform any necessary cleanup (including + * sending a special signal to child) + */ + public static final int APR_OC_REASON_RESTART = 2; + /** unregister has been called, do whatever is necessary (including + * kill the child) + */ + public static final int APR_OC_REASON_UNREGISTER = 3; + /** somehow the child exited without us knowing ... buggy os? */ + public static final int APR_OC_REASON_LOST = 4; + /** a health check is occuring, for most maintainence functions + * this is a no-op. + */ + public static final int APR_OC_REASON_RUNNING = 5; + + /* apr_kill_conditions_e enumeration */ + /** process is never sent any signals */ + public static final int APR_KILL_NEVER = 0; + /** process is sent SIGKILL on apr_pool_t cleanup */ + public static final int APR_KILL_ALWAYS = 1; + /** SIGTERM, wait 3 seconds, SIGKILL */ + public static final int APR_KILL_AFTER_TIMEOUT = 2; + /** wait forever for the process to complete */ + public static final int APR_JUST_WAIT = 3; + /** send SIGTERM and then wait */ + public static final int APR_KILL_ONLY_ONCE = 4; + + public static final int APR_PROC_DETACH_FOREGROUND = 0; /** Do not detach */ + public static final int APR_PROC_DETACH_DAEMONIZE = 1; /** Detach */ + + /* Maximum number of arguments for create process call */ + public static final int MAX_ARGS_SIZE = 1024; + /* Maximum number of environment variables for create process call */ + public static final int MAX_ENV_SIZE = 1024; + + /** + * Allocate apr_proc_t stucture from pool + * This is not an apr function. + * @param cont The pool to use. + */ + public static native long alloc(long cont); + + /** + * This is currently the only non-portable call in APR. This executes + * a standard unix fork. + * @param proc The resulting process handle. + * @param cont The pool to use. + * @return APR_INCHILD for the child, and APR_INPARENT for the parent + * or an error. + */ + public static native int fork(long [] proc, long cont); + + /** + * Create a new process and execute a new program within that process. + * This function returns without waiting for the new process to terminate; + * use apr_proc_wait for that. + * @param progname The program to run + * @param args The arguments to pass to the new program. The first + * one should be the program name. + * @param env The new environment table for the new process. This + * should be a list of NULL-terminated strings. This argument + * is ignored for APR_PROGRAM_ENV, APR_PROGRAM_PATH, and + * APR_SHELLCMD_ENV types of commands. + * @param attr The procattr we should use to determine how to create the new + * process + * @param pool The pool to use. + * @return The resulting process handle. + */ + public static native int create(long proc, String progname, + String [] args, String [] env, + long attr, long pool); + + /** + * Wait for a child process to die + * @param proc The process handle that corresponds to the desired child process + * @param exit exit[0] The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * exit[1] Why the child died, the bitwise or of: + *
        +     * APR_PROC_EXIT         -- process terminated normally
        +     * APR_PROC_SIGNAL       -- process was killed by a signal
        +     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
        +     *                          generated a core dump.
        +     * 
        + * @param waithow How should we wait. One of: + *
        +     * APR_WAIT   -- block until the child process dies.
        +     * APR_NOWAIT -- return immediately regardless of if the
        +     *               child is dead or not.
        +     * 
        + * @return The childs status is in the return code to this process. It is one of: + *
        +     * APR_CHILD_DONE     -- child is no longer running.
        +     * APR_CHILD_NOTDONE  -- child is still running.
        +     * 
        + */ + public static native int wait(long proc, int [] exit, int waithow); + + /** + * Wait for any current child process to die and return information + * about that child. + * @param proc Pointer to NULL on entry, will be filled out with child's + * information + * @param exit exit[0] The returned exit status of the child, if a child process + * dies, or the signal that caused the child to die. + * On platforms that don't support obtaining this information, + * the status parameter will be returned as APR_ENOTIMPL. + * exit[1] Why the child died, the bitwise or of: + *
        +     * APR_PROC_EXIT         -- process terminated normally
        +     * APR_PROC_SIGNAL       -- process was killed by a signal
        +     * APR_PROC_SIGNAL_CORE  -- process was killed by a signal, and
        +     *                          generated a core dump.
        +     * 
        + * @param waithow How should we wait. One of: + *
        +     * APR_WAIT   -- block until the child process dies.
        +     * APR_NOWAIT -- return immediately regardless of if the
        +     *               child is dead or not.
        +     * 
        + * @param pool Pool to allocate child information out of. + */ + public static native int waitAllProcs(long proc, int [] exit, + int waithow, long pool); + + /** + * Detach the process from the controlling terminal. + * @param daemonize set to non-zero if the process should daemonize + * and become a background process, else it will + * stay in the foreground. + */ + public static native int detach(int daemonize); + + /** + * Terminate a process. + * @param proc The process to terminate. + * @param sig How to kill the process. + */ + public static native int kill(long proc, int sig); + +} diff --git a/java/org/apache/tomcat/jni/ProcErrorCallback.java b/java/org/apache/tomcat/jni/ProcErrorCallback.java index aeb9a535d..7ba54e8fa 100644 --- a/java/org/apache/tomcat/jni/ProcErrorCallback.java +++ b/java/org/apache/tomcat/jni/ProcErrorCallback.java @@ -1,37 +1,37 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** ProcErrorCallback Interface - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public interface ProcErrorCallback { - - /** - * Called in the child process if APR encounters an error - * in the child prior to running the specified program. - * @param pool Pool associated with the apr_proc_t. If your child - * error function needs user data, associate it with this - * pool. - * @param err APR error code describing the error - * @param description Text description of type of processing which failed - */ - public void callback(long pool, int err, String description); -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** ProcErrorCallback Interface + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public interface ProcErrorCallback { + + /** + * Called in the child process if APR encounters an error + * in the child prior to running the specified program. + * @param pool Pool associated with the apr_proc_t. If your child + * error function needs user data, associate it with this + * pool. + * @param err APR error code describing the error + * @param description Text description of type of processing which failed + */ + public void callback(long pool, int err, String description); +} diff --git a/java/org/apache/tomcat/jni/Procattr.java b/java/org/apache/tomcat/jni/Procattr.java index b21e213ca..9d9e5d936 100644 --- a/java/org/apache/tomcat/jni/Procattr.java +++ b/java/org/apache/tomcat/jni/Procattr.java @@ -1,171 +1,171 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Procattr - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Procattr { - - /** - * Create and initialize a new procattr variable - * @param cont The pool to use - * @return The newly created procattr. - */ - public static native long create(long cont) - throws Error; - - /** - * Determine if any of stdin, stdout, or stderr should be linked to pipes - * when starting a child process. - * @param attr The procattr we care about. - * @param in Should stdin be a pipe back to the parent? - * @param out Should stdout be a pipe back to the parent? - * @param err Should stderr be a pipe back to the parent? - */ - public static native int ioSet(long attr, int in, int out, int err); - /** - * Set the child_in and/or parent_in values to existing apr_file_t values. - *
        - * This is NOT a required initializer function. This is - * useful if you have already opened a pipe (or multiple files) - * that you wish to use, perhaps persistently across multiple - * process invocations - such as a log file. You can save some - * extra function calls by not creating your own pipe since this - * creates one in the process space for you. - * @param attr The procattr we care about. - * @param in apr_file_t value to use as child_in. Must be a valid file. - * @param parent apr_file_t value to use as parent_in. Must be a valid file. - */ - public static native int childInSet(long attr, long in, long parent); - - /** - * Set the child_out and parent_out values to existing apr_file_t values. - *
        - * This is NOT a required initializer function. This is - * useful if you have already opened a pipe (or multiple files) - * that you wish to use, perhaps persistently across multiple - * process invocations - such as a log file. - * @param attr The procattr we care about. - * @param out apr_file_t value to use as child_out. Must be a valid file. - * @param parent apr_file_t value to use as parent_out. Must be a valid file. - */ - public static native int childOutSet(long attr, long out, long parent); - - /** - * Set the child_err and parent_err values to existing apr_file_t values. - *
        - * This is NOT a required initializer function. This is - * useful if you have already opened a pipe (or multiple files) - * that you wish to use, perhaps persistently across multiple - * process invocations - such as a log file. - * @param attr The procattr we care about. - * @param err apr_file_t value to use as child_err. Must be a valid file. - * @param parent apr_file_t value to use as parent_err. Must be a valid file. - */ - public static native int childErrSet(long attr, long err, long parent); - - /** - * Set which directory the child process should start executing in. - * @param attr The procattr we care about. - * @param dir Which dir to start in. By default, this is the same dir as - * the parent currently resides in, when the createprocess call - * is made. - */ - public static native int dirSet(long attr, String dir); - - /** - * Set what type of command the child process will call. - * @param attr The procattr we care about. - * @param cmd The type of command. One of: - *
        -     * APR_SHELLCMD     --  Anything that the shell can handle
        -     * APR_PROGRAM      --  Executable program   (default)
        -     * APR_PROGRAM_ENV  --  Executable program, copy environment
        -     * APR_PROGRAM_PATH --  Executable program on PATH, copy env
        -     * 
        - */ - public static native int cmdtypeSet(long attr, int cmd); - - /** - * Determine if the child should start in detached state. - * @param attr The procattr we care about. - * @param detach Should the child start in detached state? Default is no. - */ - public static native int detachSet(long attr, int detach); - - /** - * Specify that apr_proc_create() should do whatever it can to report - * failures to the caller of apr_proc_create(), rather than find out in - * the child. - * @param attr The procattr describing the child process to be created. - * @param chk Flag to indicate whether or not extra work should be done - * to try to report failures to the caller. - *
        - * This flag only affects apr_proc_create() on platforms where - * fork() is used. This leads to extra overhead in the calling - * process, but that may help the application handle such - * errors more gracefully. - */ - public static native int errorCheckSet(long attr, int chk); - - /** - * Determine if the child should start in its own address space or using the - * current one from its parent - * @param attr The procattr we care about. - * @param addrspace Should the child start in its own address space? Default - * is no on NetWare and yes on other platforms. - */ - public static native int addrspaceSet(long attr, int addrspace); - - /** - * Specify an error function to be called in the child process if APR - * encounters an error in the child prior to running the specified program. - * @param attr The procattr describing the child process to be created. - * @param pool The the pool to use. - * @param o The Object to call in the child process. - *
        - * At the present time, it will only be called from apr_proc_create() - * on platforms where fork() is used. It will never be called on other - * platforms, on those platforms apr_proc_create() will return the error - * in the parent process rather than invoke the callback in the now-forked - * child process. - */ - public static native void errfnSet(long attr, long pool, Object o); - - /** - * Set the username used for running process - * @param attr The procattr we care about. - * @param username The username used - * @param password User password if needed. Password is needed on WIN32 - * or any other platform having - * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. - */ - public static native int userSet(long attr, String username, String password); - - /** - * Set the group used for running process - * @param attr The procattr we care about. - * @param groupname The group name used - */ - public static native int groupSet(long attr, String groupname); - - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Procattr + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Procattr { + + /** + * Create and initialize a new procattr variable + * @param cont The pool to use + * @return The newly created procattr. + */ + public static native long create(long cont) + throws Error; + + /** + * Determine if any of stdin, stdout, or stderr should be linked to pipes + * when starting a child process. + * @param attr The procattr we care about. + * @param in Should stdin be a pipe back to the parent? + * @param out Should stdout be a pipe back to the parent? + * @param err Should stderr be a pipe back to the parent? + */ + public static native int ioSet(long attr, int in, int out, int err); + /** + * Set the child_in and/or parent_in values to existing apr_file_t values. + *
        + * This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. You can save some + * extra function calls by not creating your own pipe since this + * creates one in the process space for you. + * @param attr The procattr we care about. + * @param in apr_file_t value to use as child_in. Must be a valid file. + * @param parent apr_file_t value to use as parent_in. Must be a valid file. + */ + public static native int childInSet(long attr, long in, long parent); + + /** + * Set the child_out and parent_out values to existing apr_file_t values. + *
        + * This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @param attr The procattr we care about. + * @param out apr_file_t value to use as child_out. Must be a valid file. + * @param parent apr_file_t value to use as parent_out. Must be a valid file. + */ + public static native int childOutSet(long attr, long out, long parent); + + /** + * Set the child_err and parent_err values to existing apr_file_t values. + *
        + * This is NOT a required initializer function. This is + * useful if you have already opened a pipe (or multiple files) + * that you wish to use, perhaps persistently across multiple + * process invocations - such as a log file. + * @param attr The procattr we care about. + * @param err apr_file_t value to use as child_err. Must be a valid file. + * @param parent apr_file_t value to use as parent_err. Must be a valid file. + */ + public static native int childErrSet(long attr, long err, long parent); + + /** + * Set which directory the child process should start executing in. + * @param attr The procattr we care about. + * @param dir Which dir to start in. By default, this is the same dir as + * the parent currently resides in, when the createprocess call + * is made. + */ + public static native int dirSet(long attr, String dir); + + /** + * Set what type of command the child process will call. + * @param attr The procattr we care about. + * @param cmd The type of command. One of: + *
        +     * APR_SHELLCMD     --  Anything that the shell can handle
        +     * APR_PROGRAM      --  Executable program   (default)
        +     * APR_PROGRAM_ENV  --  Executable program, copy environment
        +     * APR_PROGRAM_PATH --  Executable program on PATH, copy env
        +     * 
        + */ + public static native int cmdtypeSet(long attr, int cmd); + + /** + * Determine if the child should start in detached state. + * @param attr The procattr we care about. + * @param detach Should the child start in detached state? Default is no. + */ + public static native int detachSet(long attr, int detach); + + /** + * Specify that apr_proc_create() should do whatever it can to report + * failures to the caller of apr_proc_create(), rather than find out in + * the child. + * @param attr The procattr describing the child process to be created. + * @param chk Flag to indicate whether or not extra work should be done + * to try to report failures to the caller. + *
        + * This flag only affects apr_proc_create() on platforms where + * fork() is used. This leads to extra overhead in the calling + * process, but that may help the application handle such + * errors more gracefully. + */ + public static native int errorCheckSet(long attr, int chk); + + /** + * Determine if the child should start in its own address space or using the + * current one from its parent + * @param attr The procattr we care about. + * @param addrspace Should the child start in its own address space? Default + * is no on NetWare and yes on other platforms. + */ + public static native int addrspaceSet(long attr, int addrspace); + + /** + * Specify an error function to be called in the child process if APR + * encounters an error in the child prior to running the specified program. + * @param attr The procattr describing the child process to be created. + * @param pool The the pool to use. + * @param o The Object to call in the child process. + *
        + * At the present time, it will only be called from apr_proc_create() + * on platforms where fork() is used. It will never be called on other + * platforms, on those platforms apr_proc_create() will return the error + * in the parent process rather than invoke the callback in the now-forked + * child process. + */ + public static native void errfnSet(long attr, long pool, Object o); + + /** + * Set the username used for running process + * @param attr The procattr we care about. + * @param username The username used + * @param password User password if needed. Password is needed on WIN32 + * or any other platform having + * APR_PROCATTR_USER_SET_REQUIRES_PASSWORD set. + */ + public static native int userSet(long attr, String username, String password); + + /** + * Set the group used for running process + * @param attr The procattr we care about. + * @param groupname The group name used + */ + public static native int groupSet(long attr, String groupname); + + +} diff --git a/java/org/apache/tomcat/jni/Registry.java b/java/org/apache/tomcat/jni/Registry.java index 6f7d65de4..399b8b55c 100644 --- a/java/org/apache/tomcat/jni/Registry.java +++ b/java/org/apache/tomcat/jni/Registry.java @@ -1,234 +1,234 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Windows Registy support - * - * @author Mladen Turk - * @version $Revision: 301076 $, $Date: 2005-09-29 14:07:39 +0200 (jeu., 29 sept. 2005) $ - */ - -public class Registry { - - /* Registry Enums */ - public static final int HKEY_CLASSES_ROOT = 1; - public static final int HKEY_CURRENT_CONFIG = 2; - public static final int HKEY_CURRENT_USER = 3; - public static final int HKEY_LOCAL_MACHINE = 4; - public static final int HKEY_USERS = 5; - - public static final int KEY_ALL_ACCESS = 0x0001; - public static final int KEY_CREATE_LINK = 0x0002; - public static final int KEY_CREATE_SUB_KEY = 0x0004; - public static final int KEY_ENUMERATE_SUB_KEYS = 0x0008; - public static final int KEY_EXECUTE = 0x0010; - public static final int KEY_NOTIFY = 0x0020; - public static final int KEY_QUERY_VALUE = 0x0040; - public static final int KEY_READ = 0x0080; - public static final int KEY_SET_VALUE = 0x0100; - public static final int KEY_WOW64_64KEY = 0x0200; - public static final int KEY_WOW64_32KEY = 0x0400; - public static final int KEY_WRITE = 0x0800; - - public static final int REG_BINARY = 1; - public static final int REG_DWORD = 2; - public static final int REG_EXPAND_SZ = 3; - public static final int REG_MULTI_SZ = 4; - public static final int REG_QWORD = 5; - public static final int REG_SZ = 6; - - /** - * Create or open a Registry Key. - * @param name Registry Subkey to open - * @param root Root key, one of HKEY_* - * @param som Access mask that specifies the access rights for the key. - * @return Opened Registry key - */ - public static native long create(int root, String name, int sam, long pool) - throws Error; - - /** - * Opens the specified Registry Key. - * @param name Registry Subkey to open - * @param root Root key, one of HKEY_* - * @param som Access mask that specifies the access rights for the key. - * @return Opened Registry key - */ - public static native long open(int root, String name, int sam, long pool) - throws Error; - - /** - * Close the specified Registry key. - * @param key The Registry key descriptor to close. - */ - public static native int close(long key); - - /** - * Get the Registry key type. - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Value type or negative error value - */ - public static native int getType(long key, String name); - - /** - * Get the Registry value for REG_DWORD - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Registry key value - */ - public static native int getValueI(long key, String name) - throws Error; - - /** - * Get the Registry value for REG_QWORD or REG_DWORD - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Registry key value - */ - public static native long getValueJ(long key, String name) - throws Error; - - /** - * Get the Registry key length. - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Value size or negative error value - */ - public static native int getSize(long key, String name); - - /** - * Get the Registry value for REG_SZ or REG_EXPAND_SZ - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Registry key value - */ - public static native String getValueS(long key, String name) - throws Error; - - /** - * Get the Registry value for REG_MULTI_SZ - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Registry key value - */ - public static native String[] getValueA(long key, String name) - throws Error; - - /** - * Get the Registry value for REG_BINARY - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Registry key value - */ - public static native byte[] getValueB(long key, String name) - throws Error; - - - /** - * Set the Registry value for REG_DWORD - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueI(long key, String name, int val); - - /** - * Set the Registry value for REG_QWORD - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueJ(long key, String name, int val); - - /** - * Set the Registry value for REG_SZ - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueS(long key, String name, String val); - - /** - * Set the Registry value for REG_EXPAND_SZ - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueE(long key, String name, String val); - - /** - * Set the Registry value for REG_MULTI_SZ - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueA(long key, String name, String[] val); - - /** - * Set the Registry value for REG_BINARY - * @param key The Registry key descriptor to use. - * @param name The name of the value to set - * @param val The the value to set - * @return If the function succeeds, the return value is 0 - */ - public static native int setValueB(long key, String name, byte[] val); - - /** - * Enumerate the Registry subkeys - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Array of all subkey names - */ - public static native String[] enumKeys(long key) - throws Error; - - /** - * Enumerate the Registry values - * @param key The Registry key descriptor to use. - * @param name The name of the value to query - * @return Array of all value names - */ - public static native String[] enumValues(long key) - throws Error; - - /** - * Delete the Registry value - * @param key The Registry key descriptor to use. - * @param name The name of the value to delete - * @return If the function succeeds, the return value is 0 - */ - public static native int deleteValue(long key, String name); - - /** - * Delete the Registry subkey - * @param root Root key, one of HKEY_* - * @param name Subkey to delete - * @param onlyIfEmpty If true will not delete a key if - * it contains any subkeys or values - * @return If the function succeeds, the return value is 0 - */ - public static native int deleteKey(int root, String name, - boolean onlyIfEmpty); - - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Windows Registy support + * + * @author Mladen Turk + * @version $Revision: 301076 $, $Date: 2005-09-29 14:07:39 +0200 (jeu., 29 sept. 2005) $ + */ + +public class Registry { + + /* Registry Enums */ + public static final int HKEY_CLASSES_ROOT = 1; + public static final int HKEY_CURRENT_CONFIG = 2; + public static final int HKEY_CURRENT_USER = 3; + public static final int HKEY_LOCAL_MACHINE = 4; + public static final int HKEY_USERS = 5; + + public static final int KEY_ALL_ACCESS = 0x0001; + public static final int KEY_CREATE_LINK = 0x0002; + public static final int KEY_CREATE_SUB_KEY = 0x0004; + public static final int KEY_ENUMERATE_SUB_KEYS = 0x0008; + public static final int KEY_EXECUTE = 0x0010; + public static final int KEY_NOTIFY = 0x0020; + public static final int KEY_QUERY_VALUE = 0x0040; + public static final int KEY_READ = 0x0080; + public static final int KEY_SET_VALUE = 0x0100; + public static final int KEY_WOW64_64KEY = 0x0200; + public static final int KEY_WOW64_32KEY = 0x0400; + public static final int KEY_WRITE = 0x0800; + + public static final int REG_BINARY = 1; + public static final int REG_DWORD = 2; + public static final int REG_EXPAND_SZ = 3; + public static final int REG_MULTI_SZ = 4; + public static final int REG_QWORD = 5; + public static final int REG_SZ = 6; + + /** + * Create or open a Registry Key. + * @param name Registry Subkey to open + * @param root Root key, one of HKEY_* + * @param som Access mask that specifies the access rights for the key. + * @return Opened Registry key + */ + public static native long create(int root, String name, int sam, long pool) + throws Error; + + /** + * Opens the specified Registry Key. + * @param name Registry Subkey to open + * @param root Root key, one of HKEY_* + * @param som Access mask that specifies the access rights for the key. + * @return Opened Registry key + */ + public static native long open(int root, String name, int sam, long pool) + throws Error; + + /** + * Close the specified Registry key. + * @param key The Registry key descriptor to close. + */ + public static native int close(long key); + + /** + * Get the Registry key type. + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Value type or negative error value + */ + public static native int getType(long key, String name); + + /** + * Get the Registry value for REG_DWORD + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Registry key value + */ + public static native int getValueI(long key, String name) + throws Error; + + /** + * Get the Registry value for REG_QWORD or REG_DWORD + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Registry key value + */ + public static native long getValueJ(long key, String name) + throws Error; + + /** + * Get the Registry key length. + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Value size or negative error value + */ + public static native int getSize(long key, String name); + + /** + * Get the Registry value for REG_SZ or REG_EXPAND_SZ + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Registry key value + */ + public static native String getValueS(long key, String name) + throws Error; + + /** + * Get the Registry value for REG_MULTI_SZ + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Registry key value + */ + public static native String[] getValueA(long key, String name) + throws Error; + + /** + * Get the Registry value for REG_BINARY + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Registry key value + */ + public static native byte[] getValueB(long key, String name) + throws Error; + + + /** + * Set the Registry value for REG_DWORD + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueI(long key, String name, int val); + + /** + * Set the Registry value for REG_QWORD + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueJ(long key, String name, int val); + + /** + * Set the Registry value for REG_SZ + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueS(long key, String name, String val); + + /** + * Set the Registry value for REG_EXPAND_SZ + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueE(long key, String name, String val); + + /** + * Set the Registry value for REG_MULTI_SZ + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueA(long key, String name, String[] val); + + /** + * Set the Registry value for REG_BINARY + * @param key The Registry key descriptor to use. + * @param name The name of the value to set + * @param val The the value to set + * @return If the function succeeds, the return value is 0 + */ + public static native int setValueB(long key, String name, byte[] val); + + /** + * Enumerate the Registry subkeys + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Array of all subkey names + */ + public static native String[] enumKeys(long key) + throws Error; + + /** + * Enumerate the Registry values + * @param key The Registry key descriptor to use. + * @param name The name of the value to query + * @return Array of all value names + */ + public static native String[] enumValues(long key) + throws Error; + + /** + * Delete the Registry value + * @param key The Registry key descriptor to use. + * @param name The name of the value to delete + * @return If the function succeeds, the return value is 0 + */ + public static native int deleteValue(long key, String name); + + /** + * Delete the Registry subkey + * @param root Root key, one of HKEY_* + * @param name Subkey to delete + * @param onlyIfEmpty If true will not delete a key if + * it contains any subkeys or values + * @return If the function succeeds, the return value is 0 + */ + public static native int deleteKey(int root, String name, + boolean onlyIfEmpty); + + +} diff --git a/java/org/apache/tomcat/jni/SSL.java b/java/org/apache/tomcat/jni/SSL.java index c4fddd08a..966df743b 100644 --- a/java/org/apache/tomcat/jni/SSL.java +++ b/java/org/apache/tomcat/jni/SSL.java @@ -1,319 +1,319 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** SSL - * - * @author Mladen Turk - * @version $Revision: 301018 $, $Date: 2005-08-01 09:23:09 +0200 (lun., 01 août 2005) $ - */ - -public final class SSL { - - /* - * Type definitions mostly from mod_ssl - */ - public static final int UNSET = -1; - /* - * Define the certificate algorithm types - */ - public static final int SSL_ALGO_UNKNOWN = 0; - public static final int SSL_ALGO_RSA = (1<<0); - public static final int SSL_ALGO_DSA = (1<<1); - public static final int SSL_ALGO_ALL = (SSL_ALGO_RSA|SSL_ALGO_DSA); - - public static final int SSL_AIDX_RSA = 0; - public static final int SSL_AIDX_DSA = 1; - public static final int SSL_AIDX_MAX = 2; - /* - * Define IDs for the temporary RSA keys and DH params - */ - - public static final int SSL_TMP_KEY_RSA_512 = 0; - public static final int SSL_TMP_KEY_RSA_1024 = 1; - public static final int SSL_TMP_KEY_RSA_2048 = 2; - public static final int SSL_TMP_KEY_RSA_4096 = 3; - public static final int SSL_TMP_KEY_DH_512 = 4; - public static final int SSL_TMP_KEY_DH_1024 = 5; - public static final int SSL_TMP_KEY_DH_2048 = 6; - public static final int SSL_TMP_KEY_DH_4096 = 7; - public static final int SSL_TMP_KEY_MAX = 8; - - /* - * Define the SSL options - */ - public static final int SSL_OPT_NONE = 0; - public static final int SSL_OPT_RELSET = (1<<0); - public static final int SSL_OPT_STDENVVARS = (1<<1); - public static final int SSL_OPT_EXPORTCERTDATA = (1<<3); - public static final int SSL_OPT_FAKEBASICAUTH = (1<<4); - public static final int SSL_OPT_STRICTREQUIRE = (1<<5); - public static final int SSL_OPT_OPTRENEGOTIATE = (1<<6); - public static final int SSL_OPT_ALL = (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE); - - /* - * Define the SSL Protocol options - */ - public static final int SSL_PROTOCOL_NONE = 0; - public static final int SSL_PROTOCOL_SSLV2 = (1<<0); - public static final int SSL_PROTOCOL_SSLV3 = (1<<1); - public static final int SSL_PROTOCOL_TLSV1 = (1<<2); - public static final int SSL_PROTOCOL_ALL = (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1); - - /* - * Define the SSL verify levels - */ - public static final int SSL_CVERIFY_UNSET = UNSET; - public static final int SSL_CVERIFY_NONE = 0; - public static final int SSL_CVERIFY_OPTIONAL = 1; - public static final int SSL_CVERIFY_REQUIRE = 2; - public static final int SSL_CVERIFY_OPTIONAL_NO_CA = 3; - - /* Use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options - * are 'ored' with SSL_VERIFY_PEER if they are desired - */ - public static final int SSL_VERIFY_NONE = 0; - public static final int SSL_VERIFY_PEER = 1; - public static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2; - public static final int SSL_VERIFY_CLIENT_ONCE = 4; - public static final int SSL_VERIFY_PEER_STRICT = (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT); - - public static final int SSL_OP_MICROSOFT_SESS_ID_BUG = 0x00000001; - public static final int SSL_OP_NETSCAPE_CHALLENGE_BUG = 0x00000002; - public static final int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008; - public static final int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 0x00000010; - public static final int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020; - public static final int SSL_OP_MSIE_SSLV2_RSA_PADDING = 0x00000040; - public static final int SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080; - public static final int SSL_OP_TLS_D5_BUG = 0x00000100; - public static final int SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200; - - /* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added - * in OpenSSL 0.9.6d. Usually (depending on the application protocol) - * the workaround is not needed. Unfortunately some broken SSL/TLS - * implementations cannot handle it at all, which is why we include - * it in SSL_OP_ALL. */ - public static final int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800; - - /* SSL_OP_ALL: various bug workarounds that should be rather harmless. - * This used to be 0x000FFFFFL before 0.9.7. */ - public static final int SSL_OP_ALL = 0x00000FFF; - - /* As server, disallow session resumption on renegotiation */ - public static final int SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000; - /* If set, always create a new key when using tmp_dh parameters */ - public static final int SSL_OP_SINGLE_DH_USE = 0x00100000; - /* Set to always use the tmp_rsa key when doing RSA operations, - * even when this violates protocol specs */ - public static final int SSL_OP_EPHEMERAL_RSA = 0x00200000; - /* Set on servers to choose the cipher according to the server's - * preferences */ - public static final int SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000; - /* If set, a server will allow a client to issue a SSLv3.0 version number - * as latest version supported in the premaster secret, even when TLSv1.0 - * (version 3.1) was announced in the client hello. Normally this is - * forbidden to prevent version rollback attacks. */ - public static final int SSL_OP_TLS_ROLLBACK_BUG = 0x00800000; - - public static final int SSL_OP_NO_SSLv2 = 0x01000000; - public static final int SSL_OP_NO_SSLv3 = 0x02000000; - public static final int SSL_OP_NO_TLSv1 = 0x04000000; - - /* The next flag deliberately changes the ciphertest, this is a check - * for the PKCS#1 attack */ - public static final int SSL_OP_PKCS1_CHECK_1 = 0x08000000; - public static final int SSL_OP_PKCS1_CHECK_2 = 0x10000000; - public static final int SSL_OP_NETSCAPE_CA_DN_BUG = 0x20000000; - public static final int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 0x40000000; - - public static final int SSL_CRT_FORMAT_UNDEF = 0; - public static final int SSL_CRT_FORMAT_ASN1 = 1; - public static final int SSL_CRT_FORMAT_TEXT = 2; - public static final int SSL_CRT_FORMAT_PEM = 3; - public static final int SSL_CRT_FORMAT_NETSCAPE = 4; - public static final int SSL_CRT_FORMAT_PKCS12 = 5; - public static final int SSL_CRT_FORMAT_SMIME = 6; - public static final int SSL_CRT_FORMAT_ENGINE = 7; - - public static final int SSL_MODE_CLIENT = 0; - public static final int SSL_MODE_SERVER = 1; - public static final int SSL_MODE_COMBINED = 2; - - public static final int SSL_SHUTDOWN_TYPE_UNSET = 0; - public static final int SSL_SHUTDOWN_TYPE_STANDARD = 1; - public static final int SSL_SHUTDOWN_TYPE_UNCLEAN = 2; - public static final int SSL_SHUTDOWN_TYPE_ACCURATE = 3; - - public static final int SSL_INFO_SESSION_ID = 0x0001; - public static final int SSL_INFO_CIPHER = 0x0002; - public static final int SSL_INFO_CIPHER_USEKEYSIZE = 0x0003; - public static final int SSL_INFO_CIPHER_ALGKEYSIZE = 0x0004; - public static final int SSL_INFO_CIPHER_VERSION = 0x0005; - public static final int SSL_INFO_CIPHER_DESCRIPTION = 0x0006; - public static final int SSL_INFO_PROTOCOL = 0x0007; - - /* To obtain the CountryName of the Client Certificate Issuer - * use the SSL_INFO_CLIENT_I_DN + SSL_INFO_DN_COUNTRYNAME - */ - public static final int SSL_INFO_CLIENT_S_DN = 0x0010; - public static final int SSL_INFO_CLIENT_I_DN = 0x0020; - public static final int SSL_INFO_SERVER_S_DN = 0x0040; - public static final int SSL_INFO_SERVER_I_DN = 0x0080; - - public static final int SSL_INFO_DN_COUNTRYNAME = 0x0001; - public static final int SSL_INFO_DN_STATEORPROVINCENAME = 0x0002; - public static final int SSL_INFO_DN_LOCALITYNAME = 0x0003; - public static final int SSL_INFO_DN_ORGANIZATIONNAME = 0x0004; - public static final int SSL_INFO_DN_ORGANIZATIONALUNITNAME = 0x0005; - public static final int SSL_INFO_DN_COMMONNAME = 0x0006; - public static final int SSL_INFO_DN_TITLE = 0x0007; - public static final int SSL_INFO_DN_INITIALS = 0x0008; - public static final int SSL_INFO_DN_GIVENNAME = 0x0009; - public static final int SSL_INFO_DN_SURNAME = 0x000A; - public static final int SSL_INFO_DN_DESCRIPTION = 0x000B; - public static final int SSL_INFO_DN_UNIQUEIDENTIFIER = 0x000C; - public static final int SSL_INFO_DN_EMAILADDRESS = 0x000D; - - public static final int SSL_INFO_CLIENT_M_VERSION = 0x0101; - public static final int SSL_INFO_CLIENT_M_SERIAL = 0x0102; - public static final int SSL_INFO_CLIENT_V_START = 0x0103; - public static final int SSL_INFO_CLIENT_V_END = 0x0104; - public static final int SSL_INFO_CLIENT_A_SIG = 0x0105; - public static final int SSL_INFO_CLIENT_A_KEY = 0x0106; - public static final int SSL_INFO_CLIENT_CERT = 0x0107; - public static final int SSL_INFO_CLIENT_V_REMAIN = 0x0108; - - public static final int SSL_INFO_SERVER_M_VERSION = 0x0201; - public static final int SSL_INFO_SERVER_M_SERIAL = 0x0202; - public static final int SSL_INFO_SERVER_V_START = 0x0203; - public static final int SSL_INFO_SERVER_V_END = 0x0204; - public static final int SSL_INFO_SERVER_A_SIG = 0x0205; - public static final int SSL_INFO_SERVER_A_KEY = 0x0206; - public static final int SSL_INFO_SERVER_CERT = 0x0207; - /* Return client certificate chain. - * Add certificate chain number to that flag (0 ... verify depth) - */ - public static final int SSL_INFO_CLIENT_CERT_CHAIN = 0x0400; - /* Return OpenSSL version number */ - public static native int version(); - - /* Return OpenSSL version string */ - public static native String versionString(); - - /** - * Initialize OpenSSL support. - * This function needs to be called once for the - * lifetime of JVM. Library.init() has to be called before. - * @param engine Support for external a Crypto Device ("engine"), - * usually - * a hardware accellerator card for crypto operations. - * @return APR status code - */ - public static native int initialize(String engine); - - /** - * Add content of the file to the PRNG - * @param filename Filename containing random data. - * If null the default file will be tested. - * The seed file is $RANDFILE if that environment variable is - * set, $HOME/.rnd otherwise. - * In case both files are unavailable builtin - * random seed generator is used. - */ - public static native boolean randLoad(String filename); - - /** - * Writes a number of random bytes (currently 1024) to - * file filename which can be used to initialize the PRNG - * by calling randLoad in a later session. - * @param filename Filename to save the data - */ - public static native boolean randSave(String filename); - - /** - * Creates random data to filename - * @param filename Filename to save the data - * @param len The length of random sequence in bytes - * @param base64 Output the data in Base64 encoded format - */ - public static native boolean randMake(String filename, int len, - boolean base64); - - /** - * Initialize new BIO - * @param pool The pool to use. - * @param callback BIOCallback to use - * @return New BIO handle - */ - public static native long newBIO(long pool, BIOCallback callback) - throws Exception; - - /** - * Close BIO and derefrence callback object - * @param bio BIO to close and destroy. - * @return APR Status code - */ - public static native int closeBIO(long bio); - - /** - * Set global Password callback for obtaining passwords. - * @param callback PasswordCallback implementation to use. - */ - public static native void setPasswordCallback(PasswordCallback callback); - - /** - * Set global Password for decrypting certificates and keys. - * @param password Password to use. - */ - public static native void setPassword(String password); - - /** - * Generate temporary RSA key. - *
        - * Index can be one of: - *
        -     * SSL_TMP_KEY_RSA_512
        -     * SSL_TMP_KEY_RSA_1024
        -     * SSL_TMP_KEY_RSA_2048
        -     * SSL_TMP_KEY_RSA_4096
        -     * 
        - * By default 512 and 1024 keys are generated on startup. - * You can use a low priority thread to generate them on the fly. - * @param idx temporary key index. - */ - public static native boolean generateRSATempKey(int idx); - - /** - * Load temporary DSA key from file - *
        - * Index can be one of: - *
        -     * SSL_TMP_KEY_DH_512
        -     * SSL_TMP_KEY_DH_1024
        -     * SSL_TMP_KEY_DH_2048
        -     * SSL_TMP_KEY_DH_4096
        -     * 
        - * @param idx temporary key index. - * @param file File contatining DH params. - */ - public static native boolean loadDSATempKey(int idx, String file); - - /** - * Return last SSL error string - */ - public static native String getLastError(); -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** SSL + * + * @author Mladen Turk + * @version $Revision: 301018 $, $Date: 2005-08-01 09:23:09 +0200 (lun., 01 août 2005) $ + */ + +public final class SSL { + + /* + * Type definitions mostly from mod_ssl + */ + public static final int UNSET = -1; + /* + * Define the certificate algorithm types + */ + public static final int SSL_ALGO_UNKNOWN = 0; + public static final int SSL_ALGO_RSA = (1<<0); + public static final int SSL_ALGO_DSA = (1<<1); + public static final int SSL_ALGO_ALL = (SSL_ALGO_RSA|SSL_ALGO_DSA); + + public static final int SSL_AIDX_RSA = 0; + public static final int SSL_AIDX_DSA = 1; + public static final int SSL_AIDX_MAX = 2; + /* + * Define IDs for the temporary RSA keys and DH params + */ + + public static final int SSL_TMP_KEY_RSA_512 = 0; + public static final int SSL_TMP_KEY_RSA_1024 = 1; + public static final int SSL_TMP_KEY_RSA_2048 = 2; + public static final int SSL_TMP_KEY_RSA_4096 = 3; + public static final int SSL_TMP_KEY_DH_512 = 4; + public static final int SSL_TMP_KEY_DH_1024 = 5; + public static final int SSL_TMP_KEY_DH_2048 = 6; + public static final int SSL_TMP_KEY_DH_4096 = 7; + public static final int SSL_TMP_KEY_MAX = 8; + + /* + * Define the SSL options + */ + public static final int SSL_OPT_NONE = 0; + public static final int SSL_OPT_RELSET = (1<<0); + public static final int SSL_OPT_STDENVVARS = (1<<1); + public static final int SSL_OPT_EXPORTCERTDATA = (1<<3); + public static final int SSL_OPT_FAKEBASICAUTH = (1<<4); + public static final int SSL_OPT_STRICTREQUIRE = (1<<5); + public static final int SSL_OPT_OPTRENEGOTIATE = (1<<6); + public static final int SSL_OPT_ALL = (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE); + + /* + * Define the SSL Protocol options + */ + public static final int SSL_PROTOCOL_NONE = 0; + public static final int SSL_PROTOCOL_SSLV2 = (1<<0); + public static final int SSL_PROTOCOL_SSLV3 = (1<<1); + public static final int SSL_PROTOCOL_TLSV1 = (1<<2); + public static final int SSL_PROTOCOL_ALL = (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1); + + /* + * Define the SSL verify levels + */ + public static final int SSL_CVERIFY_UNSET = UNSET; + public static final int SSL_CVERIFY_NONE = 0; + public static final int SSL_CVERIFY_OPTIONAL = 1; + public static final int SSL_CVERIFY_REQUIRE = 2; + public static final int SSL_CVERIFY_OPTIONAL_NO_CA = 3; + + /* Use either SSL_VERIFY_NONE or SSL_VERIFY_PEER, the last 2 options + * are 'ored' with SSL_VERIFY_PEER if they are desired + */ + public static final int SSL_VERIFY_NONE = 0; + public static final int SSL_VERIFY_PEER = 1; + public static final int SSL_VERIFY_FAIL_IF_NO_PEER_CERT = 2; + public static final int SSL_VERIFY_CLIENT_ONCE = 4; + public static final int SSL_VERIFY_PEER_STRICT = (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT); + + public static final int SSL_OP_MICROSOFT_SESS_ID_BUG = 0x00000001; + public static final int SSL_OP_NETSCAPE_CHALLENGE_BUG = 0x00000002; + public static final int SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG = 0x00000008; + public static final int SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG = 0x00000010; + public static final int SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = 0x00000020; + public static final int SSL_OP_MSIE_SSLV2_RSA_PADDING = 0x00000040; + public static final int SSL_OP_SSLEAY_080_CLIENT_DH_BUG = 0x00000080; + public static final int SSL_OP_TLS_D5_BUG = 0x00000100; + public static final int SSL_OP_TLS_BLOCK_PADDING_BUG = 0x00000200; + + /* Disable SSL 3.0/TLS 1.0 CBC vulnerability workaround that was added + * in OpenSSL 0.9.6d. Usually (depending on the application protocol) + * the workaround is not needed. Unfortunately some broken SSL/TLS + * implementations cannot handle it at all, which is why we include + * it in SSL_OP_ALL. */ + public static final int SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = 0x00000800; + + /* SSL_OP_ALL: various bug workarounds that should be rather harmless. + * This used to be 0x000FFFFFL before 0.9.7. */ + public static final int SSL_OP_ALL = 0x00000FFF; + + /* As server, disallow session resumption on renegotiation */ + public static final int SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION = 0x00010000; + /* If set, always create a new key when using tmp_dh parameters */ + public static final int SSL_OP_SINGLE_DH_USE = 0x00100000; + /* Set to always use the tmp_rsa key when doing RSA operations, + * even when this violates protocol specs */ + public static final int SSL_OP_EPHEMERAL_RSA = 0x00200000; + /* Set on servers to choose the cipher according to the server's + * preferences */ + public static final int SSL_OP_CIPHER_SERVER_PREFERENCE = 0x00400000; + /* If set, a server will allow a client to issue a SSLv3.0 version number + * as latest version supported in the premaster secret, even when TLSv1.0 + * (version 3.1) was announced in the client hello. Normally this is + * forbidden to prevent version rollback attacks. */ + public static final int SSL_OP_TLS_ROLLBACK_BUG = 0x00800000; + + public static final int SSL_OP_NO_SSLv2 = 0x01000000; + public static final int SSL_OP_NO_SSLv3 = 0x02000000; + public static final int SSL_OP_NO_TLSv1 = 0x04000000; + + /* The next flag deliberately changes the ciphertest, this is a check + * for the PKCS#1 attack */ + public static final int SSL_OP_PKCS1_CHECK_1 = 0x08000000; + public static final int SSL_OP_PKCS1_CHECK_2 = 0x10000000; + public static final int SSL_OP_NETSCAPE_CA_DN_BUG = 0x20000000; + public static final int SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG = 0x40000000; + + public static final int SSL_CRT_FORMAT_UNDEF = 0; + public static final int SSL_CRT_FORMAT_ASN1 = 1; + public static final int SSL_CRT_FORMAT_TEXT = 2; + public static final int SSL_CRT_FORMAT_PEM = 3; + public static final int SSL_CRT_FORMAT_NETSCAPE = 4; + public static final int SSL_CRT_FORMAT_PKCS12 = 5; + public static final int SSL_CRT_FORMAT_SMIME = 6; + public static final int SSL_CRT_FORMAT_ENGINE = 7; + + public static final int SSL_MODE_CLIENT = 0; + public static final int SSL_MODE_SERVER = 1; + public static final int SSL_MODE_COMBINED = 2; + + public static final int SSL_SHUTDOWN_TYPE_UNSET = 0; + public static final int SSL_SHUTDOWN_TYPE_STANDARD = 1; + public static final int SSL_SHUTDOWN_TYPE_UNCLEAN = 2; + public static final int SSL_SHUTDOWN_TYPE_ACCURATE = 3; + + public static final int SSL_INFO_SESSION_ID = 0x0001; + public static final int SSL_INFO_CIPHER = 0x0002; + public static final int SSL_INFO_CIPHER_USEKEYSIZE = 0x0003; + public static final int SSL_INFO_CIPHER_ALGKEYSIZE = 0x0004; + public static final int SSL_INFO_CIPHER_VERSION = 0x0005; + public static final int SSL_INFO_CIPHER_DESCRIPTION = 0x0006; + public static final int SSL_INFO_PROTOCOL = 0x0007; + + /* To obtain the CountryName of the Client Certificate Issuer + * use the SSL_INFO_CLIENT_I_DN + SSL_INFO_DN_COUNTRYNAME + */ + public static final int SSL_INFO_CLIENT_S_DN = 0x0010; + public static final int SSL_INFO_CLIENT_I_DN = 0x0020; + public static final int SSL_INFO_SERVER_S_DN = 0x0040; + public static final int SSL_INFO_SERVER_I_DN = 0x0080; + + public static final int SSL_INFO_DN_COUNTRYNAME = 0x0001; + public static final int SSL_INFO_DN_STATEORPROVINCENAME = 0x0002; + public static final int SSL_INFO_DN_LOCALITYNAME = 0x0003; + public static final int SSL_INFO_DN_ORGANIZATIONNAME = 0x0004; + public static final int SSL_INFO_DN_ORGANIZATIONALUNITNAME = 0x0005; + public static final int SSL_INFO_DN_COMMONNAME = 0x0006; + public static final int SSL_INFO_DN_TITLE = 0x0007; + public static final int SSL_INFO_DN_INITIALS = 0x0008; + public static final int SSL_INFO_DN_GIVENNAME = 0x0009; + public static final int SSL_INFO_DN_SURNAME = 0x000A; + public static final int SSL_INFO_DN_DESCRIPTION = 0x000B; + public static final int SSL_INFO_DN_UNIQUEIDENTIFIER = 0x000C; + public static final int SSL_INFO_DN_EMAILADDRESS = 0x000D; + + public static final int SSL_INFO_CLIENT_M_VERSION = 0x0101; + public static final int SSL_INFO_CLIENT_M_SERIAL = 0x0102; + public static final int SSL_INFO_CLIENT_V_START = 0x0103; + public static final int SSL_INFO_CLIENT_V_END = 0x0104; + public static final int SSL_INFO_CLIENT_A_SIG = 0x0105; + public static final int SSL_INFO_CLIENT_A_KEY = 0x0106; + public static final int SSL_INFO_CLIENT_CERT = 0x0107; + public static final int SSL_INFO_CLIENT_V_REMAIN = 0x0108; + + public static final int SSL_INFO_SERVER_M_VERSION = 0x0201; + public static final int SSL_INFO_SERVER_M_SERIAL = 0x0202; + public static final int SSL_INFO_SERVER_V_START = 0x0203; + public static final int SSL_INFO_SERVER_V_END = 0x0204; + public static final int SSL_INFO_SERVER_A_SIG = 0x0205; + public static final int SSL_INFO_SERVER_A_KEY = 0x0206; + public static final int SSL_INFO_SERVER_CERT = 0x0207; + /* Return client certificate chain. + * Add certificate chain number to that flag (0 ... verify depth) + */ + public static final int SSL_INFO_CLIENT_CERT_CHAIN = 0x0400; + /* Return OpenSSL version number */ + public static native int version(); + + /* Return OpenSSL version string */ + public static native String versionString(); + + /** + * Initialize OpenSSL support. + * This function needs to be called once for the + * lifetime of JVM. Library.init() has to be called before. + * @param engine Support for external a Crypto Device ("engine"), + * usually + * a hardware accellerator card for crypto operations. + * @return APR status code + */ + public static native int initialize(String engine); + + /** + * Add content of the file to the PRNG + * @param filename Filename containing random data. + * If null the default file will be tested. + * The seed file is $RANDFILE if that environment variable is + * set, $HOME/.rnd otherwise. + * In case both files are unavailable builtin + * random seed generator is used. + */ + public static native boolean randLoad(String filename); + + /** + * Writes a number of random bytes (currently 1024) to + * file filename which can be used to initialize the PRNG + * by calling randLoad in a later session. + * @param filename Filename to save the data + */ + public static native boolean randSave(String filename); + + /** + * Creates random data to filename + * @param filename Filename to save the data + * @param len The length of random sequence in bytes + * @param base64 Output the data in Base64 encoded format + */ + public static native boolean randMake(String filename, int len, + boolean base64); + + /** + * Initialize new BIO + * @param pool The pool to use. + * @param callback BIOCallback to use + * @return New BIO handle + */ + public static native long newBIO(long pool, BIOCallback callback) + throws Exception; + + /** + * Close BIO and derefrence callback object + * @param bio BIO to close and destroy. + * @return APR Status code + */ + public static native int closeBIO(long bio); + + /** + * Set global Password callback for obtaining passwords. + * @param callback PasswordCallback implementation to use. + */ + public static native void setPasswordCallback(PasswordCallback callback); + + /** + * Set global Password for decrypting certificates and keys. + * @param password Password to use. + */ + public static native void setPassword(String password); + + /** + * Generate temporary RSA key. + *
        + * Index can be one of: + *
        +     * SSL_TMP_KEY_RSA_512
        +     * SSL_TMP_KEY_RSA_1024
        +     * SSL_TMP_KEY_RSA_2048
        +     * SSL_TMP_KEY_RSA_4096
        +     * 
        + * By default 512 and 1024 keys are generated on startup. + * You can use a low priority thread to generate them on the fly. + * @param idx temporary key index. + */ + public static native boolean generateRSATempKey(int idx); + + /** + * Load temporary DSA key from file + *
        + * Index can be one of: + *
        +     * SSL_TMP_KEY_DH_512
        +     * SSL_TMP_KEY_DH_1024
        +     * SSL_TMP_KEY_DH_2048
        +     * SSL_TMP_KEY_DH_4096
        +     * 
        + * @param idx temporary key index. + * @param file File contatining DH params. + */ + public static native boolean loadDSATempKey(int idx, String file); + + /** + * Return last SSL error string + */ + public static native String getLastError(); +} diff --git a/java/org/apache/tomcat/jni/SSLContext.java b/java/org/apache/tomcat/jni/SSLContext.java index 5fbe748f1..36903b785 100644 --- a/java/org/apache/tomcat/jni/SSLContext.java +++ b/java/org/apache/tomcat/jni/SSLContext.java @@ -1,276 +1,276 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** SSL Context - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public final class SSLContext { - - - /** - * Initialize new SSL context - * @param pool The pool to use. - * @param protocol The SSL protocol to use. It can be one of: - *
        -     * SSL_PROTOCOL_SSLV2
        -     * SSL_PROTOCOL_SSLV3
        -     * SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3
        -     * SSL_PROTOCOL_TLSV1
        -     * SSL_PROTOCOL_ALL
        -     * 
        - * @param mode SSL mode to use - *
        -     * SSL_MODE_CLIENT
        -     * SSL_MODE_SERVER
        -     * SSL_MODE_COMBINED
        -     * 
        - */ - public static native long make(long pool, int protocol, int mode) - throws Exception; - - /** - * Free the resources used by the Context - * @param ctx Server or Client context to free. - * @return APR Status code. - */ - public static native int free(long ctx); - - /** - * Set Session context id. Usually host:port combination. - * @param ctx Context to use. - * @param id String that uniquely identifies this context. - */ - public static native void setContextId(long ctx, String id); - - /** - * Asssociate BIOCallback for input or output data capture. - *
        - * First word in the output string will contain error - * level in the form: - *
        -     * [ERROR]  -- Critical error messages
        -     * [WARN]   -- Varning messages
        -     * [INFO]   -- Informational messages
        -     * [DEBUG]  -- Debugging messaged
        -     * 
        - * Callback can use that word to determine application logging level - * by intercepting write call. - * If the bio is set to 0 no error messages will be displayed. - * Default is to use the stderr output stream. - * @param ctx Server or Client context to use. - * @param bio BIO handle to use, created with SSL.newBIO - * @param dir BIO direction (1 for input 0 for output). - */ - public static native void setBIO(long ctx, long bio, int dir); - - /** - * Set OpenSSL Option. - * @param ctx Server or Client context to use. - * @param options See SSL.SSL_OP_* for option flags. - */ - public static native void setOptions(long ctx, int options); - - /** - * Sets the "quiet shutdown" flag for ctx to be - * mode. SSL objects created from ctx inherit the - * mode valid at the time and may be 0 or 1. - *
        - * Normally when a SSL connection is finished, the parties must send out - * "close notify" alert messages using L - * for a clean shutdown. - *
        - * When setting the "quiet shutdown" flag to 1, SSL.shutdown - * will set the internal flags to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN. - * (SSL_shutdown then behaves like called with - * SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.) - * The session is thus considered to be shutdown, but no "close notify" alert - * is sent to the peer. This behaviour violates the TLS standard. - * The default is normal shutdown behaviour as described by the TLS standard. - * @param ctx Server or Client context to use. - * @param mode True to set the quiet shutdown. - */ - public static native void setQuietShutdown(long ctx, boolean mode); - - /** - * Cipher Suite available for negotiation in SSL handshake. - *
        - * This complex directive uses a colon-separated cipher-spec string consisting - * of OpenSSL cipher specifications to configure the Cipher Suite the client - * is permitted to negotiate in the SSL handshake phase. Notice that this - * directive can be used both in per-server and per-directory context. - * In per-server context it applies to the standard SSL handshake when a - * connection is established. In per-directory context it forces a SSL - * renegotation with the reconfigured Cipher Suite after the HTTP request - * was read but before the HTTP response is sent. - * @param ctx Server or Client context to use. - * @param ciphers An SSL cipher specification. - */ - public static native boolean setCipherSuite(long ctx, String ciphers) - throws Exception; - - /** - * Set File of concatenated PEM-encoded CA CRLs or - * directory of PEM-encoded CA Certificates for Client Auth - *
        - * This directive sets the all-in-one file where you can assemble the - * Certificate Revocation Lists (CRL) of Certification Authorities (CA) - * whose clients you deal with. These are used for Client Authentication. - * Such a file is simply the concatenation of the various PEM-encoded CRL - * files, in order of preference. - *
        - * The files in this directory have to be PEM-encoded and are accessed through - * hash filenames. So usually you can't just place the Certificate files there: - * you also have to create symbolic links named hash-value.N. And you should - * always make sure this directory contains the appropriate symbolic links. - * Use the Makefile which comes with mod_ssl to accomplish this task. - * @param ctx Server or Client context to use. - * @param file File of concatenated PEM-encoded CA CRLs for Client Auth. - * @param path Directory of PEM-encoded CA Certificates for Client Auth. - */ - public static native boolean setCARevocation(long ctx, String file, - String path) - throws Exception; - - /** - * Set File of PEM-encoded Server CA Certificates - *
        - * This directive sets the optional all-in-one file where you can assemble the - * certificates of Certification Authorities (CA) which form the certificate - * chain of the server certificate. This starts with the issuing CA certificate - * of of the server certificate and can range up to the root CA certificate. - * Such a file is simply the concatenation of the various PEM-encoded CA - * Certificate files, usually in certificate chain order. - *
        - * But be careful: Providing the certificate chain works only if you are using - * a single (either RSA or DSA) based server certificate. If you are using a - * coupled RSA+DSA certificate pair, this will work only if actually both - * certificates use the same certificate chain. Else the browsers will be - * confused in this situation. - * @param ctx Server or Client context to use. - * @param file File of PEM-encoded Server CA Certificates. - * @param skipfirst Skip first certificate if chain file is inside - * certificate file. - */ - public static native boolean setCertificateChainFile(long ctx, String file, - boolean skipfirst); - - /** - * Set Certificate - *
        - * Point setCertificateFile at a PEM encoded certificate. If - * the certificate is encrypted, then you will be prompted for a - * pass phrase. Note that a kill -HUP will prompt again. A test - * certificate can be generated with `make certificate' under - * built time. Keep in mind that if you've both a RSA and a DSA - * certificate you can configure both in parallel (to also allow - * the use of DSA ciphers, etc.) - *
        - * If the key is not combined with the certificate, use key param - * to point at the key file. Keep in mind that if - * you've both a RSA and a DSA private key you can configure - * both in parallel (to also allow the use of DSA ciphers, etc.) - * @param ctx Server or Client context to use. - * @param cert Certificate file. - * @param key Private Key file to use if not in cert. - * @param password Certificate password. If null and certificate - * is encrypted, password prompt will be dispayed. - * @param idx Certificate index SSL_AIDX_RSA or SSL_AIDX_DSA. - */ - public static native boolean setCertificate(long ctx, String cert, - String key, String password, - int idx) - throws Exception; - - /** - * Set File and Directory of concatenated PEM-encoded CA Certificates - * for Client Auth - *
        - * This directive sets the all-in-one file where you can assemble the - * Certificates of Certification Authorities (CA) whose clients you deal with. - * These are used for Client Authentication. Such a file is simply the - * concatenation of the various PEM-encoded Certificate files, in order of - * preference. This can be used alternatively and/or additionally to - * path. - *
        - * The files in this directory have to be PEM-encoded and are accessed through - * hash filenames. So usually you can't just place the Certificate files there: - * you also have to create symbolic links named hash-value.N. And you should - * always make sure this directory contains the appropriate symbolic links. - * Use the Makefile which comes with mod_ssl to accomplish this task. - * @param ctx Server or Client context to use. - * @param file File of concatenated PEM-encoded CA Certificates for - * Client Auth. - * @param path Directory of PEM-encoded CA Certificates for Client Auth. - */ - public static native boolean setCACertificate(long ctx, String file, - String path) - throws Exception; - - /** - * Set SSL connection shutdown type - *
        - * The following levels are available for level: - *
        -     * SSL_SHUTDOWN_TYPE_STANDARD
        -     * SSL_SHUTDOWN_TYPE_UNCLEAN
        -     * SSL_SHUTDOWN_TYPE_ACCURATE
        -     * 
        - * @param ctx Server or Client context to use. - * @param type Shutdown type to use. - */ - public static native void setShutdowType(long ctx, int type); - - /** - * Set Type of Client Certificate verification and Maximum depth of CA Certificates - * in Client Certificate verification. - *
        - * This directive sets the Certificate verification level for the Client - * Authentication. Notice that this directive can be used both in per-server - * and per-directory context. In per-server context it applies to the client - * authentication process used in the standard SSL handshake when a connection - * is established. In per-directory context it forces a SSL renegotation with - * the reconfigured client verification level after the HTTP request was read - * but before the HTTP response is sent. - *
        - * The following levels are available for level: - *
        -     * SSL_CVERIFY_NONE           - No client Certificate is required at all
        -     * SSL_CVERIFY_OPTIONAL       - The client may present a valid Certificate
        -     * SSL_CVERIFY_REQUIRE        - The client has to present a valid Certificate
        -     * SSL_CVERIFY_OPTIONAL_NO_CA - The client may present a valid Certificate
        -     *                              but it need not to be (successfully) verifiable
        -     * 
        - *
        - * The depth actually is the maximum number of intermediate certificate issuers, - * i.e. the number of CA certificates which are max allowed to be followed while - * verifying the client certificate. A depth of 0 means that self-signed client - * certificates are accepted only, the default depth of 1 means the client - * certificate can be self-signed or has to be signed by a CA which is directly - * known to the server (i.e. the CA's certificate is under - * setCACertificatePath), etc. - * @param ctx Server or Client context to use. - * @param level Type of Client Certificate verification. - * @param depth Maximum depth of CA Certificates in Client Certificate - * verification. - */ - public static native void setVerify(long ctx, int level, int depth); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** SSL Context + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public final class SSLContext { + + + /** + * Initialize new SSL context + * @param pool The pool to use. + * @param protocol The SSL protocol to use. It can be one of: + *
        +     * SSL_PROTOCOL_SSLV2
        +     * SSL_PROTOCOL_SSLV3
        +     * SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3
        +     * SSL_PROTOCOL_TLSV1
        +     * SSL_PROTOCOL_ALL
        +     * 
        + * @param mode SSL mode to use + *
        +     * SSL_MODE_CLIENT
        +     * SSL_MODE_SERVER
        +     * SSL_MODE_COMBINED
        +     * 
        + */ + public static native long make(long pool, int protocol, int mode) + throws Exception; + + /** + * Free the resources used by the Context + * @param ctx Server or Client context to free. + * @return APR Status code. + */ + public static native int free(long ctx); + + /** + * Set Session context id. Usually host:port combination. + * @param ctx Context to use. + * @param id String that uniquely identifies this context. + */ + public static native void setContextId(long ctx, String id); + + /** + * Asssociate BIOCallback for input or output data capture. + *
        + * First word in the output string will contain error + * level in the form: + *
        +     * [ERROR]  -- Critical error messages
        +     * [WARN]   -- Varning messages
        +     * [INFO]   -- Informational messages
        +     * [DEBUG]  -- Debugging messaged
        +     * 
        + * Callback can use that word to determine application logging level + * by intercepting write call. + * If the bio is set to 0 no error messages will be displayed. + * Default is to use the stderr output stream. + * @param ctx Server or Client context to use. + * @param bio BIO handle to use, created with SSL.newBIO + * @param dir BIO direction (1 for input 0 for output). + */ + public static native void setBIO(long ctx, long bio, int dir); + + /** + * Set OpenSSL Option. + * @param ctx Server or Client context to use. + * @param options See SSL.SSL_OP_* for option flags. + */ + public static native void setOptions(long ctx, int options); + + /** + * Sets the "quiet shutdown" flag for ctx to be + * mode. SSL objects created from ctx inherit the + * mode valid at the time and may be 0 or 1. + *
        + * Normally when a SSL connection is finished, the parties must send out + * "close notify" alert messages using L + * for a clean shutdown. + *
        + * When setting the "quiet shutdown" flag to 1, SSL.shutdown + * will set the internal flags to SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN. + * (SSL_shutdown then behaves like called with + * SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN.) + * The session is thus considered to be shutdown, but no "close notify" alert + * is sent to the peer. This behaviour violates the TLS standard. + * The default is normal shutdown behaviour as described by the TLS standard. + * @param ctx Server or Client context to use. + * @param mode True to set the quiet shutdown. + */ + public static native void setQuietShutdown(long ctx, boolean mode); + + /** + * Cipher Suite available for negotiation in SSL handshake. + *
        + * This complex directive uses a colon-separated cipher-spec string consisting + * of OpenSSL cipher specifications to configure the Cipher Suite the client + * is permitted to negotiate in the SSL handshake phase. Notice that this + * directive can be used both in per-server and per-directory context. + * In per-server context it applies to the standard SSL handshake when a + * connection is established. In per-directory context it forces a SSL + * renegotation with the reconfigured Cipher Suite after the HTTP request + * was read but before the HTTP response is sent. + * @param ctx Server or Client context to use. + * @param ciphers An SSL cipher specification. + */ + public static native boolean setCipherSuite(long ctx, String ciphers) + throws Exception; + + /** + * Set File of concatenated PEM-encoded CA CRLs or + * directory of PEM-encoded CA Certificates for Client Auth + *
        + * This directive sets the all-in-one file where you can assemble the + * Certificate Revocation Lists (CRL) of Certification Authorities (CA) + * whose clients you deal with. These are used for Client Authentication. + * Such a file is simply the concatenation of the various PEM-encoded CRL + * files, in order of preference. + *
        + * The files in this directory have to be PEM-encoded and are accessed through + * hash filenames. So usually you can't just place the Certificate files there: + * you also have to create symbolic links named hash-value.N. And you should + * always make sure this directory contains the appropriate symbolic links. + * Use the Makefile which comes with mod_ssl to accomplish this task. + * @param ctx Server or Client context to use. + * @param file File of concatenated PEM-encoded CA CRLs for Client Auth. + * @param path Directory of PEM-encoded CA Certificates for Client Auth. + */ + public static native boolean setCARevocation(long ctx, String file, + String path) + throws Exception; + + /** + * Set File of PEM-encoded Server CA Certificates + *
        + * This directive sets the optional all-in-one file where you can assemble the + * certificates of Certification Authorities (CA) which form the certificate + * chain of the server certificate. This starts with the issuing CA certificate + * of of the server certificate and can range up to the root CA certificate. + * Such a file is simply the concatenation of the various PEM-encoded CA + * Certificate files, usually in certificate chain order. + *
        + * But be careful: Providing the certificate chain works only if you are using + * a single (either RSA or DSA) based server certificate. If you are using a + * coupled RSA+DSA certificate pair, this will work only if actually both + * certificates use the same certificate chain. Else the browsers will be + * confused in this situation. + * @param ctx Server or Client context to use. + * @param file File of PEM-encoded Server CA Certificates. + * @param skipfirst Skip first certificate if chain file is inside + * certificate file. + */ + public static native boolean setCertificateChainFile(long ctx, String file, + boolean skipfirst); + + /** + * Set Certificate + *
        + * Point setCertificateFile at a PEM encoded certificate. If + * the certificate is encrypted, then you will be prompted for a + * pass phrase. Note that a kill -HUP will prompt again. A test + * certificate can be generated with `make certificate' under + * built time. Keep in mind that if you've both a RSA and a DSA + * certificate you can configure both in parallel (to also allow + * the use of DSA ciphers, etc.) + *
        + * If the key is not combined with the certificate, use key param + * to point at the key file. Keep in mind that if + * you've both a RSA and a DSA private key you can configure + * both in parallel (to also allow the use of DSA ciphers, etc.) + * @param ctx Server or Client context to use. + * @param cert Certificate file. + * @param key Private Key file to use if not in cert. + * @param password Certificate password. If null and certificate + * is encrypted, password prompt will be dispayed. + * @param idx Certificate index SSL_AIDX_RSA or SSL_AIDX_DSA. + */ + public static native boolean setCertificate(long ctx, String cert, + String key, String password, + int idx) + throws Exception; + + /** + * Set File and Directory of concatenated PEM-encoded CA Certificates + * for Client Auth + *
        + * This directive sets the all-in-one file where you can assemble the + * Certificates of Certification Authorities (CA) whose clients you deal with. + * These are used for Client Authentication. Such a file is simply the + * concatenation of the various PEM-encoded Certificate files, in order of + * preference. This can be used alternatively and/or additionally to + * path. + *
        + * The files in this directory have to be PEM-encoded and are accessed through + * hash filenames. So usually you can't just place the Certificate files there: + * you also have to create symbolic links named hash-value.N. And you should + * always make sure this directory contains the appropriate symbolic links. + * Use the Makefile which comes with mod_ssl to accomplish this task. + * @param ctx Server or Client context to use. + * @param file File of concatenated PEM-encoded CA Certificates for + * Client Auth. + * @param path Directory of PEM-encoded CA Certificates for Client Auth. + */ + public static native boolean setCACertificate(long ctx, String file, + String path) + throws Exception; + + /** + * Set SSL connection shutdown type + *
        + * The following levels are available for level: + *
        +     * SSL_SHUTDOWN_TYPE_STANDARD
        +     * SSL_SHUTDOWN_TYPE_UNCLEAN
        +     * SSL_SHUTDOWN_TYPE_ACCURATE
        +     * 
        + * @param ctx Server or Client context to use. + * @param type Shutdown type to use. + */ + public static native void setShutdowType(long ctx, int type); + + /** + * Set Type of Client Certificate verification and Maximum depth of CA Certificates + * in Client Certificate verification. + *
        + * This directive sets the Certificate verification level for the Client + * Authentication. Notice that this directive can be used both in per-server + * and per-directory context. In per-server context it applies to the client + * authentication process used in the standard SSL handshake when a connection + * is established. In per-directory context it forces a SSL renegotation with + * the reconfigured client verification level after the HTTP request was read + * but before the HTTP response is sent. + *
        + * The following levels are available for level: + *
        +     * SSL_CVERIFY_NONE           - No client Certificate is required at all
        +     * SSL_CVERIFY_OPTIONAL       - The client may present a valid Certificate
        +     * SSL_CVERIFY_REQUIRE        - The client has to present a valid Certificate
        +     * SSL_CVERIFY_OPTIONAL_NO_CA - The client may present a valid Certificate
        +     *                              but it need not to be (successfully) verifiable
        +     * 
        + *
        + * The depth actually is the maximum number of intermediate certificate issuers, + * i.e. the number of CA certificates which are max allowed to be followed while + * verifying the client certificate. A depth of 0 means that self-signed client + * certificates are accepted only, the default depth of 1 means the client + * certificate can be self-signed or has to be signed by a CA which is directly + * known to the server (i.e. the CA's certificate is under + * setCACertificatePath), etc. + * @param ctx Server or Client context to use. + * @param level Type of Client Certificate verification. + * @param depth Maximum depth of CA Certificates in Client Certificate + * verification. + */ + public static native void setVerify(long ctx, int level, int depth); + +} diff --git a/java/org/apache/tomcat/jni/SSLSocket.java b/java/org/apache/tomcat/jni/SSLSocket.java index 6a6bb1120..79a8bd495 100644 --- a/java/org/apache/tomcat/jni/SSLSocket.java +++ b/java/org/apache/tomcat/jni/SSLSocket.java @@ -1,88 +1,88 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** SSL Socket - * - * @author Mladen Turk - * @version $Revision: 300970 $, $Date: 2005-07-12 19:01:42 +0200 (mar., 12 juil. 2005) $ - */ - -public class SSLSocket { - - /** - * Attach APR socket on a SSL connection. - * @param ctx SSLContext to use. - * @param sock APR Socket that already did physical connect or accept. - * @return APR_STATUS code. - */ - public static native int attach(long ctx, long sock) - throws Exception; - - /** - * Do a SSL handshake. - * @param thesocket The socket to use - */ - public static native int handshake(long thesocket); - - /** - * Do a SSL renegotiation. - * SSL supports per-directory re-configuration of SSL parameters. - * This is implemented by performing an SSL renegotiation of the - * re-configured parameters after the request is read, but before the - * response is sent. In more detail: the renegotiation happens after the - * request line and MIME headers were read, but _before_ the attached - * request body is read. The reason simply is that in the HTTP protocol - * usually there is no acknowledgment step between the headers and the - * body (there is the 100-continue feature and the chunking facility - * only), so Apache has no API hook for this step. - * - * @param thesocket The socket to use - */ - public static native int renegotiate(long thesocket); - - /** - * Retrun SSL Info parameter as byte array. - * - * @param sock The socket to read the data from. - * @param id Parameter id. - * @return Byte array containing info id value. - */ - public static native byte[] getInfoB(long sock, int id) - throws Exception; - - /** - * Retrun SSL Info parameter as String. - * - * @param sock The socket to read the data from. - * @param id Parameter id. - * @return String containing info id value. - */ - public static native String getInfoS(long sock, int id) - throws Exception; - - /** - * Retrun SSL Info parameter as integer. - * - * @param sock The socket to read the data from. - * @param id Parameter id. - * @return Integer containing info id value or -1 on error. - */ - public static native int getInfoI(long sock, int id) - throws Exception; - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** SSL Socket + * + * @author Mladen Turk + * @version $Revision: 300970 $, $Date: 2005-07-12 19:01:42 +0200 (mar., 12 juil. 2005) $ + */ + +public class SSLSocket { + + /** + * Attach APR socket on a SSL connection. + * @param ctx SSLContext to use. + * @param sock APR Socket that already did physical connect or accept. + * @return APR_STATUS code. + */ + public static native int attach(long ctx, long sock) + throws Exception; + + /** + * Do a SSL handshake. + * @param thesocket The socket to use + */ + public static native int handshake(long thesocket); + + /** + * Do a SSL renegotiation. + * SSL supports per-directory re-configuration of SSL parameters. + * This is implemented by performing an SSL renegotiation of the + * re-configured parameters after the request is read, but before the + * response is sent. In more detail: the renegotiation happens after the + * request line and MIME headers were read, but _before_ the attached + * request body is read. The reason simply is that in the HTTP protocol + * usually there is no acknowledgment step between the headers and the + * body (there is the 100-continue feature and the chunking facility + * only), so Apache has no API hook for this step. + * + * @param thesocket The socket to use + */ + public static native int renegotiate(long thesocket); + + /** + * Retrun SSL Info parameter as byte array. + * + * @param sock The socket to read the data from. + * @param id Parameter id. + * @return Byte array containing info id value. + */ + public static native byte[] getInfoB(long sock, int id) + throws Exception; + + /** + * Retrun SSL Info parameter as String. + * + * @param sock The socket to read the data from. + * @param id Parameter id. + * @return String containing info id value. + */ + public static native String getInfoS(long sock, int id) + throws Exception; + + /** + * Retrun SSL Info parameter as integer. + * + * @param sock The socket to read the data from. + * @param id Parameter id. + * @return Integer containing info id value or -1 on error. + */ + public static native int getInfoI(long sock, int id) + throws Exception; + +} diff --git a/java/org/apache/tomcat/jni/Shm.java b/java/org/apache/tomcat/jni/Shm.java index 7366d6b55..ffbdb7f28 100644 --- a/java/org/apache/tomcat/jni/Shm.java +++ b/java/org/apache/tomcat/jni/Shm.java @@ -1,123 +1,123 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -import java.nio.ByteBuffer; - -/** Shm - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Shm { - - /** - * Create and make accessable a shared memory segment. - *
        - * A note about Anonymous vs. Named shared memory segments:
        - * Not all plaforms support anonymous shared memory segments, but in - * some cases it is prefered over other types of shared memory - * implementations. Passing a NULL 'file' parameter to this function - * will cause the subsystem to use anonymous shared memory segments. - * If such a system is not available, APR_ENOTIMPL is returned. - *
        - * A note about allocation sizes:
        - * On some platforms it is necessary to store some metainformation - * about the segment within the actual segment. In order to supply - * the caller with the requested size it may be necessary for the - * implementation to request a slightly greater segment length - * from the subsystem. In all cases, the apr_shm_baseaddr_get() - * function will return the first usable byte of memory. - * @param reqsize The desired size of the segment. - * @param filename The file to use for shared memory on platforms that - * require it. - * @param pool the pool from which to allocate the shared memory - * structure. - * @return The created shared memory structure. - * - */ - public static native long create(long reqsize, String filename, long pool) - throws Error; - - /** - * Remove shared memory segment associated with a filename. - *
        - * This function is only supported on platforms which support - * name-based shared memory segments, and will return APR_ENOTIMPL on - * platforms without such support. - * @param filename The filename associated with shared-memory segment which - * needs to be removed - * @param pool The pool used for file operations - */ - public static native int remove(String filename, long pool); - - /** - * Destroy a shared memory segment and associated memory. - * @param m The shared memory segment structure to destroy. - */ - public static native int destroy(long m); - - /** - * Attach to a shared memory segment that was created - * by another process. - * @param filename The file used to create the original segment. - * (This MUST match the original filename.) - * @param pool the pool from which to allocate the shared memory - * structure for this process. - * @return The created shared memory structure. - */ - public static native long attach(String filename, long pool) - throws Error; - - /** - * Detach from a shared memory segment without destroying it. - * @param m The shared memory structure representing the segment - * to detach from. - */ - public static native int detach(long m); - - /** - * Retrieve the base address of the shared memory segment. - * NOTE: This address is only usable within the callers address - * space, since this API does not guarantee that other attaching - * processes will maintain the same address mapping. - * @param m The shared memory segment from which to retrieve - * the base address. - * @return address, aligned by APR_ALIGN_DEFAULT. - */ - public static native long baseaddr(long m); - - /** - * Retrieve the length of a shared memory segment in bytes. - * @param m The shared memory segment from which to retrieve - * the segment length. - */ - public static native long size(long m); - - /** - * Retrieve new ByteBuffer base address of the shared memory segment. - * NOTE: This address is only usable within the callers address - * space, since this API does not guarantee that other attaching - * processes will maintain the same address mapping. - * @param m The shared memory segment from which to retrieve - * the base address. - * @return address, aligned by APR_ALIGN_DEFAULT. - */ - public static native ByteBuffer buffer(long m); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +import java.nio.ByteBuffer; + +/** Shm + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Shm { + + /** + * Create and make accessable a shared memory segment. + *
        + * A note about Anonymous vs. Named shared memory segments:
        + * Not all plaforms support anonymous shared memory segments, but in + * some cases it is prefered over other types of shared memory + * implementations. Passing a NULL 'file' parameter to this function + * will cause the subsystem to use anonymous shared memory segments. + * If such a system is not available, APR_ENOTIMPL is returned. + *
        + * A note about allocation sizes:
        + * On some platforms it is necessary to store some metainformation + * about the segment within the actual segment. In order to supply + * the caller with the requested size it may be necessary for the + * implementation to request a slightly greater segment length + * from the subsystem. In all cases, the apr_shm_baseaddr_get() + * function will return the first usable byte of memory. + * @param reqsize The desired size of the segment. + * @param filename The file to use for shared memory on platforms that + * require it. + * @param pool the pool from which to allocate the shared memory + * structure. + * @return The created shared memory structure. + * + */ + public static native long create(long reqsize, String filename, long pool) + throws Error; + + /** + * Remove shared memory segment associated with a filename. + *
        + * This function is only supported on platforms which support + * name-based shared memory segments, and will return APR_ENOTIMPL on + * platforms without such support. + * @param filename The filename associated with shared-memory segment which + * needs to be removed + * @param pool The pool used for file operations + */ + public static native int remove(String filename, long pool); + + /** + * Destroy a shared memory segment and associated memory. + * @param m The shared memory segment structure to destroy. + */ + public static native int destroy(long m); + + /** + * Attach to a shared memory segment that was created + * by another process. + * @param filename The file used to create the original segment. + * (This MUST match the original filename.) + * @param pool the pool from which to allocate the shared memory + * structure for this process. + * @return The created shared memory structure. + */ + public static native long attach(String filename, long pool) + throws Error; + + /** + * Detach from a shared memory segment without destroying it. + * @param m The shared memory structure representing the segment + * to detach from. + */ + public static native int detach(long m); + + /** + * Retrieve the base address of the shared memory segment. + * NOTE: This address is only usable within the callers address + * space, since this API does not guarantee that other attaching + * processes will maintain the same address mapping. + * @param m The shared memory segment from which to retrieve + * the base address. + * @return address, aligned by APR_ALIGN_DEFAULT. + */ + public static native long baseaddr(long m); + + /** + * Retrieve the length of a shared memory segment in bytes. + * @param m The shared memory segment from which to retrieve + * the segment length. + */ + public static native long size(long m); + + /** + * Retrieve new ByteBuffer base address of the shared memory segment. + * NOTE: This address is only usable within the callers address + * space, since this API does not guarantee that other attaching + * processes will maintain the same address mapping. + * @param m The shared memory segment from which to retrieve + * the base address. + * @return address, aligned by APR_ALIGN_DEFAULT. + */ + public static native ByteBuffer buffer(long m); + +} diff --git a/java/org/apache/tomcat/jni/Sockaddr.java b/java/org/apache/tomcat/jni/Sockaddr.java index e8c57c84b..105756688 100644 --- a/java/org/apache/tomcat/jni/Sockaddr.java +++ b/java/org/apache/tomcat/jni/Sockaddr.java @@ -1,41 +1,41 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Sockaddr - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Sockaddr { - - /** The pool to use... */ - public long pool; - /** The hostname */ - public String hostname; - /** Either a string of the port number or the service name for the port */ - public String servname; - /** The numeric port */ - public int port; - /** The family */ - public int family; - /** If multiple addresses were found by apr_sockaddr_info_get(), this - * points to a representation of the next address. */ - public long next; - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Sockaddr + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Sockaddr { + + /** The pool to use... */ + public long pool; + /** The hostname */ + public String hostname; + /** Either a string of the port number or the service name for the port */ + public String servname; + /** The numeric port */ + public int port; + /** The family */ + public int family; + /** If multiple addresses were found by apr_sockaddr_info_get(), this + * points to a representation of the next address. */ + public long next; + +} diff --git a/java/org/apache/tomcat/jni/Socket.java b/java/org/apache/tomcat/jni/Socket.java index 756fc1ba7..b0c96559a 100644 --- a/java/org/apache/tomcat/jni/Socket.java +++ b/java/org/apache/tomcat/jni/Socket.java @@ -1,528 +1,528 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/* Import needed classes */ -import java.nio.ByteBuffer; - -/** Socket - * - * @author Mladen Turk - * @version $Revision: 327657 $, $Date: 2005-10-22 14:32:32 +0200 (sam., 22 oct. 2005) $ - */ - -public class Socket { - - /* Standard socket defines */ - public static final int SOCK_STREAM = 0; - public static final int SOCK_DGRAM = 1; - /* - * apr_sockopt Socket option definitions - */ - public static final int APR_SO_LINGER = 1; /** Linger */ - public static final int APR_SO_KEEPALIVE = 2; /** Keepalive */ - public static final int APR_SO_DEBUG = 4; /** Debug */ - public static final int APR_SO_NONBLOCK = 8; /** Non-blocking IO */ - public static final int APR_SO_REUSEADDR = 16; /** Reuse addresses */ - public static final int APR_SO_SNDBUF = 64; /** Send buffer */ - public static final int APR_SO_RCVBUF = 128; /** Receive buffer */ - public static final int APR_SO_DISCONNECTED = 256; /** Disconnected */ - /** For SCTP sockets, this is mapped to STCP_NODELAY internally. */ - public static final int APR_TCP_NODELAY = 512; - public static final int APR_TCP_NOPUSH = 1024; /** No push */ - /** This flag is ONLY set internally when we set APR_TCP_NOPUSH with - * APR_TCP_NODELAY set to tell us that APR_TCP_NODELAY should be turned on - * again when NOPUSH is turned off - */ - public static final int APR_RESET_NODELAY = 2048; - /** Set on non-blocking sockets (timeout != 0) on which the - * previous read() did not fill a buffer completely. the next - * apr_socket_recv() will first call select()/poll() rather than - * going straight into read(). (Can also be set by an application to - * force a select()/poll() call before the next read, in cases where - * the app expects that an immediate read would fail.) - */ - public static final int APR_INCOMPLETE_READ = 4096; - /** like APR_INCOMPLETE_READ, but for write - */ - public static final int APR_INCOMPLETE_WRITE = 8192; - /** Don't accept IPv4 connections on an IPv6 listening socket. - */ - public static final int APR_IPV6_V6ONLY = 16384; - /** Delay accepting of new connections until data is available. - */ - public static final int APR_TCP_DEFER_ACCEPT = 32768; - - /** Define what type of socket shutdown should occur. - * apr_shutdown_how_e enum - */ - public static final int APR_SHUTDOWN_READ = 0; /** no longer allow read request */ - public static final int APR_SHUTDOWN_WRITE = 1; /** no longer allow write requests */ - public static final int APR_SHUTDOWN_READWRITE = 2; /** no longer allow read or write requests */ - - public static final int APR_IPV4_ADDR_OK = 0x01; - public static final int APR_IPV6_ADDR_OK = 0x02; - - /* TODO: Missing: - * APR_INET - * APR_UNSPEC - * APR_INET6 - */ - public static final int APR_UNSPEC = 0; - public static final int APR_INET = 1; - public static final int APR_INET6 = 2; - - public static final int APR_PROTO_TCP = 6; /** TCP */ - public static final int APR_PROTO_UDP = 17; /** UDP */ - public static final int APR_PROTO_SCTP = 132; /** SCTP */ - - /** - * Enum to tell us if we're interested in remote or local socket - * apr_interface_e - */ - public static final int APR_LOCAL = 0; - public static final int APR_REMOTE = 1; - - /* Socket.get types */ - public static final int SOCKET_GET_POOL = 0; - public static final int SOCKET_GET_IMPL = 1; - public static final int SOCKET_GET_APRS = 2; - public static final int SOCKET_GET_TYPE = 3; - - /** - * Create a socket. - * @param family The address family of the socket (e.g., APR_INET). - * @param type The type of the socket (e.g., SOCK_STREAM). - * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). - * @param cont The parent pool to use - * @return The new socket that has been set up. - */ - public static native long create(int family, int type, - int protocol, long cont) - throws Exception; - - - /** - * Shutdown either reading, writing, or both sides of a socket. - *
        - * This does not actually close the socket descriptor, it just - * controls which calls are still valid on the socket. - * @param thesocket The socket to close - * @param how How to shutdown the socket. One of: - *
        -     * APR_SHUTDOWN_READ         no longer allow read requests
        -     * APR_SHUTDOWN_WRITE        no longer allow write requests
        -     * APR_SHUTDOWN_READWRITE    no longer allow read or write requests
        -     * 
        - */ - public static native int shutdown(long thesocket, int how); - - /** - * Close a socket. - * @param thesocket The socket to close - */ - public static native int close(long thesocket); - - /** - * Destroy a pool associated with socket - * @param thesocket The destroy - */ - public static native void destroy(long thesocket); - - /** - * Bind the socket to its associated port - * @param sock The socket to bind - * @param sa The socket address to bind to - * This may be where we will find out if there is any other process - * using the selected port. - */ - public static native int bind(long sock, long sa); - - /** - * Listen to a bound socket for connections. - * @param sock The socket to listen on - * @param backlog The number of outstanding connections allowed in the sockets - * listen queue. If this value is less than zero, the listen - * queue size is set to zero. - */ - public static native int listen(long sock, int backlog); - - /** - * Accept a new connection request - * @param sock The socket we are listening on. - * @param pool The pool for the new socket. - * @return A copy of the socket that is connected to the socket that - * made the connection request. This is the socket which should - * be used for all future communication. - */ - public static native long accept(long sock) - throws Exception; - - /** - * Set an OS level accept filter. - * @param sock The socket to put the accept filter on. - * @param name The accept filter - * @param args Any extra args to the accept filter. Passing NULL here removes - * the accept filter. - */ - public static native int acceptfilter(long sock, String name, String args); - - /** - * Query the specified socket if at the OOB/Urgent data mark - * @param sock The socket to query - * @return True if socket is at the OOB/urgent mark, - * otherwise return false. - */ - public static native boolean atmark(long sock); - - /** - * Issue a connection request to a socket either on the same machine - * or a different one. - * @param sock The socket we wish to use for our side of the connection - * @param sa The address of the machine we wish to connect to. - */ - public static native int connect(long sock, long sa); - - /** - * Send data over a network. - *
        -     * This functions acts like a blocking write by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     *
        -     * It is possible for both bytes to be sent and an error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to send the data over. - * @param buf The buffer which contains the data to be sent. - * @param offset Offset in the byte buffer. - * @param len The number of bytes to write; (-1) for full array. - * @return The number of bytes send. - * - */ - public static native int send(long sock, byte[] buf, int offset, int len); - - /** - * Send data over a network. - *
        -     * This functions acts like a blocking write by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     *
        -     * It is possible for both bytes to be sent and an error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to send the data over. - * @param buf The Byte buffer which contains the data to be sent. - * @param offset The offset within the buffer array of the first buffer from - * which bytes are to be retrieved; must be non-negative - * and no larger than buf.length - * @param len The maximum number of buffers to be accessed; must be non-negative - * and no larger than buf.length - offset - * @return The number of bytes send. - * - */ - public static native int sendb(long sock, ByteBuffer buf, - int offset, int len); - /** - * Send data over a network using internally set ByteBuffer - */ - public static native int sendbb(long sock, - int offset, int len); - - /** - * Send multiple packets of data over a network. - *
        -     * This functions acts like a blocking write by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     * The number of bytes actually sent is stored in argument 3.
        -     *
        -     * It is possible for both bytes to be sent and an error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to send the data over. - * @param vec The array from which to get the data to send. - * - */ - public static native int sendv(long sock, byte[][] vec); - - /** - * @param sock The socket to send from - * @param where The apr_sockaddr_t describing where to send the data - * @param flags The flags to use - * @param buf The data to send - * @param offset Offset in the byte buffer. - * @param len The length of the data to send - */ - public static native int sendto(long sock, long where, int flags, - byte[] buf, int offset, int len); - - /** - * Read data from a network. - * - *
        -     * This functions acts like a blocking read by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     * The number of bytes actually received is stored in argument 3.
        -     *
        -     * It is possible for both bytes to be received and an APR_EOF or
        -     * other error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to read the data from. - * @param buf The buffer to store the data in. - * @param offset Offset in the byte buffer. - * @param nbytes The number of bytes to read (-1) for full array. - * @return the number of bytes received. - */ - public static native int recv(long sock, byte[] buf, int offset, int nbytes); - - /** - * Read data from a network with timeout. - * - *
        -     * This functions acts like a blocking read by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     * The number of bytes actually received is stored in argument 3.
        -     *
        -     * It is possible for both bytes to be received and an APR_EOF or
        -     * other error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to read the data from. - * @param buf The buffer to store the data in. - * @param offset Offset in the byte buffer. - * @param nbytes The number of bytes to read (-1) for full array. - * @param timeout The socket timeout in microseconds. - * @return the number of bytes received. - */ - public static native int recvt(long sock, byte[] buf, int offset, - int nbytes, long timeout); - - /** - * Read data from a network. - * - *
        -     * This functions acts like a blocking read by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     * The number of bytes actually received is stored in argument 3.
        -     *
        -     * It is possible for both bytes to be received and an APR_EOF or
        -     * other error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to read the data from. - * @param buf The buffer to store the data in. - * @param offset Offset in the byte buffer. - * @param nbytes The number of bytes to read (-1) for full array. - * @return the number of bytes received. - */ - public static native int recvb(long sock, ByteBuffer buf, - int offset, int nbytes); - /** - * Read data from a network using internally set ByteBuffer - */ - public static native int recvbb(long sock, - int offset, int nbytes); - /** - * Read data from a network with timeout. - * - *
        -     * This functions acts like a blocking read by default.  To change
        -     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        -     * socket option.
        -     * The number of bytes actually received is stored in argument 3.
        -     *
        -     * It is possible for both bytes to be received and an APR_EOF or
        -     * other error to be returned.
        -     *
        -     * APR_EINTR is never returned.
        -     * 
        - * @param sock The socket to read the data from. - * @param buf The buffer to store the data in. - * @param offset Offset in the byte buffer. - * @param nbytes The number of bytes to read (-1) for full array. - * @param timeout The socket timeout in microseconds. - * @return the number of bytes received. - */ - public static native int recvbt(long sock, ByteBuffer buf, - int offset, int nbytes, long timeout); - /** - * Read data from a network with timeout using internally set ByteBuffer - */ - public static native int recvbbt(long sock, - int offset, int nbytes, long timeout); - - /** - * @param from The apr_sockaddr_t to fill in the recipient info - * @param sock The socket to use - * @param flags The flags to use - * @param buf The buffer to use - * @param offset Offset in the byte buffer. - * @param nbytes The number of bytes to read (-1) for full array. - * @return the number of bytes received. - */ - public static native int recvFrom(long from, long sock, int flags, - byte[] buf, int offset, int nbytes); - - /** - * Setup socket options for the specified socket - * @param sock The socket to set up. - * @param opt The option we would like to configure. One of: - *
        -     * APR_SO_DEBUG      --  turn on debugging information
        -     * APR_SO_KEEPALIVE  --  keep connections active
        -     * APR_SO_LINGER     --  lingers on close if data is present
        -     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
        -     *                       When this option is enabled, use
        -     *                       the APR_STATUS_IS_EAGAIN() macro to
        -     *                       see if a send or receive function
        -     *                       could not transfer data without
        -     *                       blocking.
        -     * APR_SO_REUSEADDR  --  The rules used in validating addresses
        -     *                       supplied to bind should allow reuse
        -     *                       of local addresses.
        -     * APR_SO_SNDBUF     --  Set the SendBufferSize
        -     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
        -     * 
        - * @param on Value for the option. - */ - public static native int optSet(long sock, int opt, int on); - - /** - * Query socket options for the specified socket - * @param sock The socket to query - * @param opt The option we would like to query. One of: - *
        -     * APR_SO_DEBUG      --  turn on debugging information
        -     * APR_SO_KEEPALIVE  --  keep connections active
        -     * APR_SO_LINGER     --  lingers on close if data is present
        -     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
        -     * APR_SO_REUSEADDR  --  The rules used in validating addresses
        -     *                       supplied to bind should allow reuse
        -     *                       of local addresses.
        -     * APR_SO_SNDBUF     --  Set the SendBufferSize
        -     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
        -     * APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
        -     *                       (Currently only used on Windows)
        -     * 
        - * @return Socket option returned on the call. - */ - public static native int optGet(long sock, int opt) - throws Exception; - - /** - * Setup socket timeout for the specified socket - * @param sock The socket to set up. - * @param t Value for the timeout in microseconds. - *
        -     * t > 0  -- read and write calls return APR_TIMEUP if specified time
        -     *           elapsess with no data read or written
        -     * t == 0 -- read and write calls never block
        -     * t < 0  -- read and write calls block
        -     * 
        - */ - public static native int timeoutSet(long sock, long t); - - /** - * Query socket timeout for the specified socket - * @param sock The socket to query - * @return Socket timeout returned from the query. - */ - public static native long timeoutGet(long sock) - throws Exception; - - /** - * Send a file from an open file descriptor to a socket, along with - * optional headers and trailers. - *
        - * This functions acts like a blocking write by default. To change - * this behavior, use apr_socket_timeout_set() or the - * APR_SO_NONBLOCK socket option. - * The number of bytes actually sent is stored in the len parameter. - * The offset parameter is passed by reference for no reason; its - * value will never be modified by the apr_socket_sendfile() function. - * @param sock The socket to which we're writing - * @param file The open file from which to read - * @param headers Array containing the headers to send - * @param trailers Array containing the trailers to send - * @param offset Offset into the file where we should begin writing - * @param len Number of bytes to send from the file - * @param flags APR flags that are mapped to OS specific flags - * @return Number of bytes actually sent, including headers, - * file, and trailers - * - */ - public static native long sendfile(long sock, long file, byte [][] headers, - byte[][] trailers, long offset, - long len, int flags); - - /** - * Send a file without header and trailer arrays. - */ - public static native long sendfilen(long sock, long file, long offset, - long len, int flags); - - /** - * Create a child pool from associated socket pool. - * @param thesocket The socket to use - */ - public static native long pool(long thesocket) - throws Exception; - - /** - * Private method for geting the socket struct members - * @param socket The soocket to use - * @param what Struct member to obtain - *
        -     * SOCKET_GET_POOL  - The socket pool
        -     * SOCKET_GET_IMPL  - The socket implementation object
        -     * SOCKET_GET_APRS  - APR socket
        -     * SOCKET_GET_TYPE  - Socket type
        -     * 
        - * @return The stucture member address - */ - private static native long get(long socket, int what); - - /** - * Set internal send ByteBuffer. - * This function will preset internal Java ByteBuffer for - * consecutive sendbb calls. - * @param thesocket The socket to use - * @param buf The ByteBuffer - */ - public static native void setsbb(long sock, ByteBuffer buf); - - /** - * Set internal receive ByteBuffer. - * This function will preset internal Java ByteBuffer for - * consecutive revcvbb/recvbbt calls. - * @param thesocket The socket to use - * @param buf The ByteBuffer - */ - public static native void setrbb(long sock, ByteBuffer buf); -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/* Import needed classes */ +import java.nio.ByteBuffer; + +/** Socket + * + * @author Mladen Turk + * @version $Revision: 327657 $, $Date: 2005-10-22 14:32:32 +0200 (sam., 22 oct. 2005) $ + */ + +public class Socket { + + /* Standard socket defines */ + public static final int SOCK_STREAM = 0; + public static final int SOCK_DGRAM = 1; + /* + * apr_sockopt Socket option definitions + */ + public static final int APR_SO_LINGER = 1; /** Linger */ + public static final int APR_SO_KEEPALIVE = 2; /** Keepalive */ + public static final int APR_SO_DEBUG = 4; /** Debug */ + public static final int APR_SO_NONBLOCK = 8; /** Non-blocking IO */ + public static final int APR_SO_REUSEADDR = 16; /** Reuse addresses */ + public static final int APR_SO_SNDBUF = 64; /** Send buffer */ + public static final int APR_SO_RCVBUF = 128; /** Receive buffer */ + public static final int APR_SO_DISCONNECTED = 256; /** Disconnected */ + /** For SCTP sockets, this is mapped to STCP_NODELAY internally. */ + public static final int APR_TCP_NODELAY = 512; + public static final int APR_TCP_NOPUSH = 1024; /** No push */ + /** This flag is ONLY set internally when we set APR_TCP_NOPUSH with + * APR_TCP_NODELAY set to tell us that APR_TCP_NODELAY should be turned on + * again when NOPUSH is turned off + */ + public static final int APR_RESET_NODELAY = 2048; + /** Set on non-blocking sockets (timeout != 0) on which the + * previous read() did not fill a buffer completely. the next + * apr_socket_recv() will first call select()/poll() rather than + * going straight into read(). (Can also be set by an application to + * force a select()/poll() call before the next read, in cases where + * the app expects that an immediate read would fail.) + */ + public static final int APR_INCOMPLETE_READ = 4096; + /** like APR_INCOMPLETE_READ, but for write + */ + public static final int APR_INCOMPLETE_WRITE = 8192; + /** Don't accept IPv4 connections on an IPv6 listening socket. + */ + public static final int APR_IPV6_V6ONLY = 16384; + /** Delay accepting of new connections until data is available. + */ + public static final int APR_TCP_DEFER_ACCEPT = 32768; + + /** Define what type of socket shutdown should occur. + * apr_shutdown_how_e enum + */ + public static final int APR_SHUTDOWN_READ = 0; /** no longer allow read request */ + public static final int APR_SHUTDOWN_WRITE = 1; /** no longer allow write requests */ + public static final int APR_SHUTDOWN_READWRITE = 2; /** no longer allow read or write requests */ + + public static final int APR_IPV4_ADDR_OK = 0x01; + public static final int APR_IPV6_ADDR_OK = 0x02; + + /* TODO: Missing: + * APR_INET + * APR_UNSPEC + * APR_INET6 + */ + public static final int APR_UNSPEC = 0; + public static final int APR_INET = 1; + public static final int APR_INET6 = 2; + + public static final int APR_PROTO_TCP = 6; /** TCP */ + public static final int APR_PROTO_UDP = 17; /** UDP */ + public static final int APR_PROTO_SCTP = 132; /** SCTP */ + + /** + * Enum to tell us if we're interested in remote or local socket + * apr_interface_e + */ + public static final int APR_LOCAL = 0; + public static final int APR_REMOTE = 1; + + /* Socket.get types */ + public static final int SOCKET_GET_POOL = 0; + public static final int SOCKET_GET_IMPL = 1; + public static final int SOCKET_GET_APRS = 2; + public static final int SOCKET_GET_TYPE = 3; + + /** + * Create a socket. + * @param family The address family of the socket (e.g., APR_INET). + * @param type The type of the socket (e.g., SOCK_STREAM). + * @param protocol The protocol of the socket (e.g., APR_PROTO_TCP). + * @param cont The parent pool to use + * @return The new socket that has been set up. + */ + public static native long create(int family, int type, + int protocol, long cont) + throws Exception; + + + /** + * Shutdown either reading, writing, or both sides of a socket. + *
        + * This does not actually close the socket descriptor, it just + * controls which calls are still valid on the socket. + * @param thesocket The socket to close + * @param how How to shutdown the socket. One of: + *
        +     * APR_SHUTDOWN_READ         no longer allow read requests
        +     * APR_SHUTDOWN_WRITE        no longer allow write requests
        +     * APR_SHUTDOWN_READWRITE    no longer allow read or write requests
        +     * 
        + */ + public static native int shutdown(long thesocket, int how); + + /** + * Close a socket. + * @param thesocket The socket to close + */ + public static native int close(long thesocket); + + /** + * Destroy a pool associated with socket + * @param thesocket The destroy + */ + public static native void destroy(long thesocket); + + /** + * Bind the socket to its associated port + * @param sock The socket to bind + * @param sa The socket address to bind to + * This may be where we will find out if there is any other process + * using the selected port. + */ + public static native int bind(long sock, long sa); + + /** + * Listen to a bound socket for connections. + * @param sock The socket to listen on + * @param backlog The number of outstanding connections allowed in the sockets + * listen queue. If this value is less than zero, the listen + * queue size is set to zero. + */ + public static native int listen(long sock, int backlog); + + /** + * Accept a new connection request + * @param sock The socket we are listening on. + * @param pool The pool for the new socket. + * @return A copy of the socket that is connected to the socket that + * made the connection request. This is the socket which should + * be used for all future communication. + */ + public static native long accept(long sock) + throws Exception; + + /** + * Set an OS level accept filter. + * @param sock The socket to put the accept filter on. + * @param name The accept filter + * @param args Any extra args to the accept filter. Passing NULL here removes + * the accept filter. + */ + public static native int acceptfilter(long sock, String name, String args); + + /** + * Query the specified socket if at the OOB/Urgent data mark + * @param sock The socket to query + * @return True if socket is at the OOB/urgent mark, + * otherwise return false. + */ + public static native boolean atmark(long sock); + + /** + * Issue a connection request to a socket either on the same machine + * or a different one. + * @param sock The socket we wish to use for our side of the connection + * @param sa The address of the machine we wish to connect to. + */ + public static native int connect(long sock, long sa); + + /** + * Send data over a network. + *
        +     * This functions acts like a blocking write by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     *
        +     * It is possible for both bytes to be sent and an error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to send the data over. + * @param buf The buffer which contains the data to be sent. + * @param offset Offset in the byte buffer. + * @param len The number of bytes to write; (-1) for full array. + * @return The number of bytes send. + * + */ + public static native int send(long sock, byte[] buf, int offset, int len); + + /** + * Send data over a network. + *
        +     * This functions acts like a blocking write by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     *
        +     * It is possible for both bytes to be sent and an error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to send the data over. + * @param buf The Byte buffer which contains the data to be sent. + * @param offset The offset within the buffer array of the first buffer from + * which bytes are to be retrieved; must be non-negative + * and no larger than buf.length + * @param len The maximum number of buffers to be accessed; must be non-negative + * and no larger than buf.length - offset + * @return The number of bytes send. + * + */ + public static native int sendb(long sock, ByteBuffer buf, + int offset, int len); + /** + * Send data over a network using internally set ByteBuffer + */ + public static native int sendbb(long sock, + int offset, int len); + + /** + * Send multiple packets of data over a network. + *
        +     * This functions acts like a blocking write by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     * The number of bytes actually sent is stored in argument 3.
        +     *
        +     * It is possible for both bytes to be sent and an error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to send the data over. + * @param vec The array from which to get the data to send. + * + */ + public static native int sendv(long sock, byte[][] vec); + + /** + * @param sock The socket to send from + * @param where The apr_sockaddr_t describing where to send the data + * @param flags The flags to use + * @param buf The data to send + * @param offset Offset in the byte buffer. + * @param len The length of the data to send + */ + public static native int sendto(long sock, long where, int flags, + byte[] buf, int offset, int len); + + /** + * Read data from a network. + * + *
        +     * This functions acts like a blocking read by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     * The number of bytes actually received is stored in argument 3.
        +     *
        +     * It is possible for both bytes to be received and an APR_EOF or
        +     * other error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes received. + */ + public static native int recv(long sock, byte[] buf, int offset, int nbytes); + + /** + * Read data from a network with timeout. + * + *
        +     * This functions acts like a blocking read by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     * The number of bytes actually received is stored in argument 3.
        +     *
        +     * It is possible for both bytes to be received and an APR_EOF or
        +     * other error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @param timeout The socket timeout in microseconds. + * @return the number of bytes received. + */ + public static native int recvt(long sock, byte[] buf, int offset, + int nbytes, long timeout); + + /** + * Read data from a network. + * + *
        +     * This functions acts like a blocking read by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     * The number of bytes actually received is stored in argument 3.
        +     *
        +     * It is possible for both bytes to be received and an APR_EOF or
        +     * other error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes received. + */ + public static native int recvb(long sock, ByteBuffer buf, + int offset, int nbytes); + /** + * Read data from a network using internally set ByteBuffer + */ + public static native int recvbb(long sock, + int offset, int nbytes); + /** + * Read data from a network with timeout. + * + *
        +     * This functions acts like a blocking read by default.  To change
        +     * this behavior, use apr_socket_timeout_set() or the APR_SO_NONBLOCK
        +     * socket option.
        +     * The number of bytes actually received is stored in argument 3.
        +     *
        +     * It is possible for both bytes to be received and an APR_EOF or
        +     * other error to be returned.
        +     *
        +     * APR_EINTR is never returned.
        +     * 
        + * @param sock The socket to read the data from. + * @param buf The buffer to store the data in. + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @param timeout The socket timeout in microseconds. + * @return the number of bytes received. + */ + public static native int recvbt(long sock, ByteBuffer buf, + int offset, int nbytes, long timeout); + /** + * Read data from a network with timeout using internally set ByteBuffer + */ + public static native int recvbbt(long sock, + int offset, int nbytes, long timeout); + + /** + * @param from The apr_sockaddr_t to fill in the recipient info + * @param sock The socket to use + * @param flags The flags to use + * @param buf The buffer to use + * @param offset Offset in the byte buffer. + * @param nbytes The number of bytes to read (-1) for full array. + * @return the number of bytes received. + */ + public static native int recvFrom(long from, long sock, int flags, + byte[] buf, int offset, int nbytes); + + /** + * Setup socket options for the specified socket + * @param sock The socket to set up. + * @param opt The option we would like to configure. One of: + *
        +     * APR_SO_DEBUG      --  turn on debugging information
        +     * APR_SO_KEEPALIVE  --  keep connections active
        +     * APR_SO_LINGER     --  lingers on close if data is present
        +     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
        +     *                       When this option is enabled, use
        +     *                       the APR_STATUS_IS_EAGAIN() macro to
        +     *                       see if a send or receive function
        +     *                       could not transfer data without
        +     *                       blocking.
        +     * APR_SO_REUSEADDR  --  The rules used in validating addresses
        +     *                       supplied to bind should allow reuse
        +     *                       of local addresses.
        +     * APR_SO_SNDBUF     --  Set the SendBufferSize
        +     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
        +     * 
        + * @param on Value for the option. + */ + public static native int optSet(long sock, int opt, int on); + + /** + * Query socket options for the specified socket + * @param sock The socket to query + * @param opt The option we would like to query. One of: + *
        +     * APR_SO_DEBUG      --  turn on debugging information
        +     * APR_SO_KEEPALIVE  --  keep connections active
        +     * APR_SO_LINGER     --  lingers on close if data is present
        +     * APR_SO_NONBLOCK   --  Turns blocking on/off for socket
        +     * APR_SO_REUSEADDR  --  The rules used in validating addresses
        +     *                       supplied to bind should allow reuse
        +     *                       of local addresses.
        +     * APR_SO_SNDBUF     --  Set the SendBufferSize
        +     * APR_SO_RCVBUF     --  Set the ReceiveBufferSize
        +     * APR_SO_DISCONNECTED -- Query the disconnected state of the socket.
        +     *                       (Currently only used on Windows)
        +     * 
        + * @return Socket option returned on the call. + */ + public static native int optGet(long sock, int opt) + throws Exception; + + /** + * Setup socket timeout for the specified socket + * @param sock The socket to set up. + * @param t Value for the timeout in microseconds. + *
        +     * t > 0  -- read and write calls return APR_TIMEUP if specified time
        +     *           elapsess with no data read or written
        +     * t == 0 -- read and write calls never block
        +     * t < 0  -- read and write calls block
        +     * 
        + */ + public static native int timeoutSet(long sock, long t); + + /** + * Query socket timeout for the specified socket + * @param sock The socket to query + * @return Socket timeout returned from the query. + */ + public static native long timeoutGet(long sock) + throws Exception; + + /** + * Send a file from an open file descriptor to a socket, along with + * optional headers and trailers. + *
        + * This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * The offset parameter is passed by reference for no reason; its + * value will never be modified by the apr_socket_sendfile() function. + * @param sock The socket to which we're writing + * @param file The open file from which to read + * @param headers Array containing the headers to send + * @param trailers Array containing the trailers to send + * @param offset Offset into the file where we should begin writing + * @param len Number of bytes to send from the file + * @param flags APR flags that are mapped to OS specific flags + * @return Number of bytes actually sent, including headers, + * file, and trailers + * + */ + public static native long sendfile(long sock, long file, byte [][] headers, + byte[][] trailers, long offset, + long len, int flags); + + /** + * Send a file without header and trailer arrays. + */ + public static native long sendfilen(long sock, long file, long offset, + long len, int flags); + + /** + * Create a child pool from associated socket pool. + * @param thesocket The socket to use + */ + public static native long pool(long thesocket) + throws Exception; + + /** + * Private method for geting the socket struct members + * @param socket The soocket to use + * @param what Struct member to obtain + *
        +     * SOCKET_GET_POOL  - The socket pool
        +     * SOCKET_GET_IMPL  - The socket implementation object
        +     * SOCKET_GET_APRS  - APR socket
        +     * SOCKET_GET_TYPE  - Socket type
        +     * 
        + * @return The stucture member address + */ + private static native long get(long socket, int what); + + /** + * Set internal send ByteBuffer. + * This function will preset internal Java ByteBuffer for + * consecutive sendbb calls. + * @param thesocket The socket to use + * @param buf The ByteBuffer + */ + public static native void setsbb(long sock, ByteBuffer buf); + + /** + * Set internal receive ByteBuffer. + * This function will preset internal Java ByteBuffer for + * consecutive revcvbb/recvbbt calls. + * @param thesocket The socket to use + * @param buf The ByteBuffer + */ + public static native void setrbb(long sock, ByteBuffer buf); +} diff --git a/java/org/apache/tomcat/jni/Status.java b/java/org/apache/tomcat/jni/Status.java index 375dc74e2..d2d272184 100644 --- a/java/org/apache/tomcat/jni/Status.java +++ b/java/org/apache/tomcat/jni/Status.java @@ -1,264 +1,264 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Status - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Status { - - /** - * APR_OS_START_ERROR is where the APR specific error values start. - */ - public static final int APR_OS_START_ERROR = 20000; - /** - * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit - * into one of the error/status ranges below -- except for - * APR_OS_START_USERERR, which see. - */ - public static final int APR_OS_ERRSPACE_SIZE = 50000; - /** - * APR_OS_START_STATUS is where the APR specific status codes start. - */ - public static final int APR_OS_START_STATUS = (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE); - - /** - * APR_OS_START_USERERR are reserved for applications that use APR that - * layer their own error codes along with APR's. Note that the - * error immediately following this one is set ten times farther - * away than usual, so that users of apr have a lot of room in - * which to declare custom error codes. - */ - public static final int APR_OS_START_USERERR = (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE); - /** - * APR_OS_START_USEERR is obsolete, defined for compatibility only. - * Use APR_OS_START_USERERR instead. - */ - public static final int APR_OS_START_USEERR = APR_OS_START_USERERR; - /** - * APR_OS_START_CANONERR is where APR versions of errno values are defined - * on systems which don't have the corresponding errno. - */ - public static final int APR_OS_START_CANONERR = (APR_OS_START_USERERR + (APR_OS_ERRSPACE_SIZE * 10)); - - /** - * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into - * apr_status_t values. - */ - public static final int APR_OS_START_EAIERR = (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE); - /** - * APR_OS_START_SYSERR folds platform-specific system error values into - * apr_status_t values. - */ - public static final int APR_OS_START_SYSERR = (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE); - - /** no error. */ - public static final int APR_SUCCESS = 0; - - /** - * APR Error Values - *
        -     * APR ERROR VALUES
        -     * APR_ENOSTAT      APR was unable to perform a stat on the file
        -     * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
        -     * APR_EBADDATE     APR was given an invalid date
        -     * APR_EINVALSOCK   APR was given an invalid socket
        -     * APR_ENOPROC      APR was not given a process structure
        -     * APR_ENOTIME      APR was not given a time structure
        -     * APR_ENODIR       APR was not given a directory structure
        -     * APR_ENOLOCK      APR was not given a lock structure
        -     * APR_ENOPOLL      APR was not given a poll structure
        -     * APR_ENOSOCKET    APR was not given a socket
        -     * APR_ENOTHREAD    APR was not given a thread structure
        -     * APR_ENOTHDKEY    APR was not given a thread key structure
        -     * APR_ENOSHMAVAIL  There is no more shared memory available
        -     * APR_EDSOOPEN     APR was unable to open the dso object.  For more
        -     *                  information call apr_dso_error().
        -     * APR_EGENERAL     General failure (specific information not available)
        -     * APR_EBADIP       The specified IP address is invalid
        -     * APR_EBADMASK     The specified netmask is invalid
        -     * APR_ESYMNOTFOUND Could not find the requested symbol
        -     * 
        - * - */ - public static final int APR_ENOSTAT = (APR_OS_START_ERROR + 1); - public static final int APR_ENOPOOL = (APR_OS_START_ERROR + 2); - public static final int APR_EBADDATE = (APR_OS_START_ERROR + 4); - public static final int APR_EINVALSOCK = (APR_OS_START_ERROR + 5); - public static final int APR_ENOPROC = (APR_OS_START_ERROR + 6); - public static final int APR_ENOTIME = (APR_OS_START_ERROR + 7); - public static final int APR_ENODIR = (APR_OS_START_ERROR + 8); - public static final int APR_ENOLOCK = (APR_OS_START_ERROR + 9); - public static final int APR_ENOPOLL = (APR_OS_START_ERROR + 10); - public static final int APR_ENOSOCKET = (APR_OS_START_ERROR + 11); - public static final int APR_ENOTHREAD = (APR_OS_START_ERROR + 12); - public static final int APR_ENOTHDKEY = (APR_OS_START_ERROR + 13); - public static final int APR_EGENERAL = (APR_OS_START_ERROR + 14); - public static final int APR_ENOSHMAVAIL = (APR_OS_START_ERROR + 15); - public static final int APR_EBADIP = (APR_OS_START_ERROR + 16); - public static final int APR_EBADMASK = (APR_OS_START_ERROR + 17); - public static final int APR_EDSOOPEN = (APR_OS_START_ERROR + 19); - public static final int APR_EABSOLUTE = (APR_OS_START_ERROR + 20); - public static final int APR_ERELATIVE = (APR_OS_START_ERROR + 21); - public static final int APR_EINCOMPLETE = (APR_OS_START_ERROR + 22); - public static final int APR_EABOVEROOT = (APR_OS_START_ERROR + 23); - public static final int APR_EBADPATH = (APR_OS_START_ERROR + 24); - public static final int APR_EPATHWILD = (APR_OS_START_ERROR + 25); - public static final int APR_ESYMNOTFOUND = (APR_OS_START_ERROR + 26); - public static final int APR_EPROC_UNKNOWN = (APR_OS_START_ERROR + 27); - public static final int APR_ENOTENOUGHENTROPY = (APR_OS_START_ERROR + 28); - - /** APR Status Values - *
        -     * APR STATUS VALUES
        -     * APR_INCHILD        Program is currently executing in the child
        -     * APR_INPARENT       Program is currently executing in the parent
        -     * APR_DETACH         The thread is detached
        -     * APR_NOTDETACH      The thread is not detached
        -     * APR_CHILD_DONE     The child has finished executing
        -     * APR_CHILD_NOTDONE  The child has not finished executing
        -     * APR_TIMEUP         The operation did not finish before the timeout
        -     * APR_INCOMPLETE     The operation was incomplete although some processing
        -     *                    was performed and the results are partially valid
        -     * APR_BADCH          Getopt found an option not in the option string
        -     * APR_BADARG         Getopt found an option that is missing an argument
        -     *                    and an argument was specified in the option string
        -     * APR_EOF            APR has encountered the end of the file
        -     * APR_NOTFOUND       APR was unable to find the socket in the poll structure
        -     * APR_ANONYMOUS      APR is using anonymous shared memory
        -     * APR_FILEBASED      APR is using a file name as the key to the shared memory
        -     * APR_KEYBASED       APR is using a shared key as the key to the shared memory
        -     * APR_EINIT          Ininitalizer value.  If no option has been found, but
        -     *                    the status variable requires a value, this should be used
        -     * APR_ENOTIMPL       The APR function has not been implemented on this
        -     *                    platform, either because nobody has gotten to it yet,
        -     *                    or the function is impossible on this platform.
        -     * APR_EMISMATCH      Two passwords do not match.
        -     * APR_EBUSY          The given lock was busy.
        -     * 
        - * - */ - public static final int APR_INCHILD = (APR_OS_START_STATUS + 1); - public static final int APR_INPARENT = (APR_OS_START_STATUS + 2); - public static final int APR_DETACH = (APR_OS_START_STATUS + 3); - public static final int APR_NOTDETACH = (APR_OS_START_STATUS + 4); - public static final int APR_CHILD_DONE = (APR_OS_START_STATUS + 5); - public static final int APR_CHILD_NOTDONE = (APR_OS_START_STATUS + 6); - public static final int APR_TIMEUP = (APR_OS_START_STATUS + 7); - public static final int APR_INCOMPLETE = (APR_OS_START_STATUS + 8); - public static final int APR_BADCH = (APR_OS_START_STATUS + 12); - public static final int APR_BADARG = (APR_OS_START_STATUS + 13); - public static final int APR_EOF = (APR_OS_START_STATUS + 14); - public static final int APR_NOTFOUND = (APR_OS_START_STATUS + 15); - public static final int APR_ANONYMOUS = (APR_OS_START_STATUS + 19); - public static final int APR_FILEBASED = (APR_OS_START_STATUS + 20); - public static final int APR_KEYBASED = (APR_OS_START_STATUS + 21); - public static final int APR_EINIT = (APR_OS_START_STATUS + 22); - public static final int APR_ENOTIMPL = (APR_OS_START_STATUS + 23); - public static final int APR_EMISMATCH = (APR_OS_START_STATUS + 24); - public static final int APR_EBUSY = (APR_OS_START_STATUS + 25); - - public static final int TIMEUP = (APR_OS_START_USERERR + 1); - public static final int EAGAIN = (APR_OS_START_USERERR + 2); - public static final int EINTR = (APR_OS_START_USERERR + 3); - public static final int EINPROGRESS = (APR_OS_START_USERERR + 4); - public static final int ETIMEDOUT = (APR_OS_START_USERERR + 5); - - private static native boolean is(int err, int idx); - /** - * APR_STATUS_IS Status Value Tests - *
        Warning : For any particular error condition, more than one of these tests - * may match. This is because platform-specific error codes may not - * always match the semantics of the POSIX codes these tests (and the - * corresponding APR error codes) are named after. A notable example - * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on - * Win32 platforms. The programmer should always be aware of this and - * adjust the order of the tests accordingly. - * - */ - public static final boolean APR_STATUS_IS_ENOSTAT(int s) { return is(s, 1); } - public static final boolean APR_STATUS_IS_ENOPOOL(int s) { return is(s, 2); } - /* empty slot: +3 */ - public static final boolean APR_STATUS_IS_EBADDATE(int s) { return is(s, 4); } - public static final boolean APR_STATUS_IS_EINVALSOCK(int s) { return is(s, 5); } - public static final boolean APR_STATUS_IS_ENOPROC(int s) { return is(s, 6); } - public static final boolean APR_STATUS_IS_ENOTIME(int s) { return is(s, 7); } - public static final boolean APR_STATUS_IS_ENODIR(int s) { return is(s, 8); } - public static final boolean APR_STATUS_IS_ENOLOCK(int s) { return is(s, 9); } - public static final boolean APR_STATUS_IS_ENOPOLL(int s) { return is(s, 10); } - public static final boolean APR_STATUS_IS_ENOSOCKET(int s) { return is(s, 11); } - public static final boolean APR_STATUS_IS_ENOTHREAD(int s) { return is(s, 12); } - public static final boolean APR_STATUS_IS_ENOTHDKEY(int s) { return is(s, 13); } - public static final boolean APR_STATUS_IS_EGENERAL(int s) { return is(s, 14); } - public static final boolean APR_STATUS_IS_ENOSHMAVAIL(int s){ return is(s, 15); } - public static final boolean APR_STATUS_IS_EBADIP(int s) { return is(s, 16); } - public static final boolean APR_STATUS_IS_EBADMASK(int s) { return is(s, 17); } - /* empty slot: +18 */ - public static final boolean APR_STATUS_IS_EDSOPEN(int s) { return is(s, 19); } - public static final boolean APR_STATUS_IS_EABSOLUTE(int s) { return is(s, 20); } - public static final boolean APR_STATUS_IS_ERELATIVE(int s) { return is(s, 21); } - public static final boolean APR_STATUS_IS_EINCOMPLETE(int s){ return is(s, 22); } - public static final boolean APR_STATUS_IS_EABOVEROOT(int s) { return is(s, 23); } - public static final boolean APR_STATUS_IS_EBADPATH(int s) { return is(s, 24); } - public static final boolean APR_STATUS_IS_EPATHWILD(int s) { return is(s, 25); } - public static final boolean APR_STATUS_IS_ESYMNOTFOUND(int s) { return is(s, 26); } - public static final boolean APR_STATUS_IS_EPROC_UNKNOWN(int s) { return is(s, 27); } - public static final boolean APR_STATUS_IS_ENOTENOUGHENTROPY(int s) { return is(s, 28); } - - /* - * APR_Error - */ - public static final boolean APR_STATUS_IS_INCHILD(int s) { return is(s, 51); } - public static final boolean APR_STATUS_IS_INPARENT(int s) { return is(s, 52); } - public static final boolean APR_STATUS_IS_DETACH(int s) { return is(s, 53); } - public static final boolean APR_STATUS_IS_NOTDETACH(int s) { return is(s, 54); } - public static final boolean APR_STATUS_IS_CHILD_DONE(int s) { return is(s, 55); } - public static final boolean APR_STATUS_IS_CHILD_NOTDONE(int s) { return is(s, 56); } - public static final boolean APR_STATUS_IS_TIMEUP(int s) { return is(s, 57); } - public static final boolean APR_STATUS_IS_INCOMPLETE(int s) { return is(s, 58); } - /* empty slot: +9 */ - /* empty slot: +10 */ - /* empty slot: +11 */ - public static final boolean APR_STATUS_IS_BADCH(int s) { return is(s, 62); } - public static final boolean APR_STATUS_IS_BADARG(int s) { return is(s, 63); } - public static final boolean APR_STATUS_IS_EOF(int s) { return is(s, 64); } - public static final boolean APR_STATUS_IS_NOTFOUND(int s) { return is(s, 65); } - /* empty slot: +16 */ - /* empty slot: +17 */ - /* empty slot: +18 */ - public static final boolean APR_STATUS_IS_ANONYMOUS(int s) { return is(s, 69); } - public static final boolean APR_STATUS_IS_FILEBASED(int s) { return is(s, 70); } - public static final boolean APR_STATUS_IS_KEYBASED(int s) { return is(s, 71); } - public static final boolean APR_STATUS_IS_EINIT(int s) { return is(s, 72); } - public static final boolean APR_STATUS_IS_ENOTIMPL(int s) { return is(s, 73); } - public static final boolean APR_STATUS_IS_EMISMATCH(int s) { return is(s, 74); } - public static final boolean APR_STATUS_IS_EBUSY(int s) { return is(s, 75); } - - /* Socket errors */ - public static final boolean APR_STATUS_IS_EAGAIN(int s) { return is(s, 90); } - public static final boolean APR_STATUS_IS_ETIMEDOUT(int s) { return is(s, 91); } - public static final boolean APR_STATUS_IS_ECONNABORTED(int s) { return is(s, 92); } - public static final boolean APR_STATUS_IS_ECONNRESET(int s) { return is(s, 93); } - public static final boolean APR_STATUS_IS_EINPROGRESS(int s) { return is(s, 94); } - public static final boolean APR_STATUS_IS_EINTR(int s) { return is(s, 95); } - public static final boolean APR_STATUS_IS_ENOTSOCK(int s) { return is(s, 96); } - public static final boolean APR_STATUS_IS_EINVAL(int s) { return is(s, 97); } - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Status + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Status { + + /** + * APR_OS_START_ERROR is where the APR specific error values start. + */ + public static final int APR_OS_START_ERROR = 20000; + /** + * APR_OS_ERRSPACE_SIZE is the maximum number of errors you can fit + * into one of the error/status ranges below -- except for + * APR_OS_START_USERERR, which see. + */ + public static final int APR_OS_ERRSPACE_SIZE = 50000; + /** + * APR_OS_START_STATUS is where the APR specific status codes start. + */ + public static final int APR_OS_START_STATUS = (APR_OS_START_ERROR + APR_OS_ERRSPACE_SIZE); + + /** + * APR_OS_START_USERERR are reserved for applications that use APR that + * layer their own error codes along with APR's. Note that the + * error immediately following this one is set ten times farther + * away than usual, so that users of apr have a lot of room in + * which to declare custom error codes. + */ + public static final int APR_OS_START_USERERR = (APR_OS_START_STATUS + APR_OS_ERRSPACE_SIZE); + /** + * APR_OS_START_USEERR is obsolete, defined for compatibility only. + * Use APR_OS_START_USERERR instead. + */ + public static final int APR_OS_START_USEERR = APR_OS_START_USERERR; + /** + * APR_OS_START_CANONERR is where APR versions of errno values are defined + * on systems which don't have the corresponding errno. + */ + public static final int APR_OS_START_CANONERR = (APR_OS_START_USERERR + (APR_OS_ERRSPACE_SIZE * 10)); + + /** + * APR_OS_START_EAIERR folds EAI_ error codes from getaddrinfo() into + * apr_status_t values. + */ + public static final int APR_OS_START_EAIERR = (APR_OS_START_CANONERR + APR_OS_ERRSPACE_SIZE); + /** + * APR_OS_START_SYSERR folds platform-specific system error values into + * apr_status_t values. + */ + public static final int APR_OS_START_SYSERR = (APR_OS_START_EAIERR + APR_OS_ERRSPACE_SIZE); + + /** no error. */ + public static final int APR_SUCCESS = 0; + + /** + * APR Error Values + *
        +     * APR ERROR VALUES
        +     * APR_ENOSTAT      APR was unable to perform a stat on the file
        +     * APR_ENOPOOL      APR was not provided a pool with which to allocate memory
        +     * APR_EBADDATE     APR was given an invalid date
        +     * APR_EINVALSOCK   APR was given an invalid socket
        +     * APR_ENOPROC      APR was not given a process structure
        +     * APR_ENOTIME      APR was not given a time structure
        +     * APR_ENODIR       APR was not given a directory structure
        +     * APR_ENOLOCK      APR was not given a lock structure
        +     * APR_ENOPOLL      APR was not given a poll structure
        +     * APR_ENOSOCKET    APR was not given a socket
        +     * APR_ENOTHREAD    APR was not given a thread structure
        +     * APR_ENOTHDKEY    APR was not given a thread key structure
        +     * APR_ENOSHMAVAIL  There is no more shared memory available
        +     * APR_EDSOOPEN     APR was unable to open the dso object.  For more
        +     *                  information call apr_dso_error().
        +     * APR_EGENERAL     General failure (specific information not available)
        +     * APR_EBADIP       The specified IP address is invalid
        +     * APR_EBADMASK     The specified netmask is invalid
        +     * APR_ESYMNOTFOUND Could not find the requested symbol
        +     * 
        + * + */ + public static final int APR_ENOSTAT = (APR_OS_START_ERROR + 1); + public static final int APR_ENOPOOL = (APR_OS_START_ERROR + 2); + public static final int APR_EBADDATE = (APR_OS_START_ERROR + 4); + public static final int APR_EINVALSOCK = (APR_OS_START_ERROR + 5); + public static final int APR_ENOPROC = (APR_OS_START_ERROR + 6); + public static final int APR_ENOTIME = (APR_OS_START_ERROR + 7); + public static final int APR_ENODIR = (APR_OS_START_ERROR + 8); + public static final int APR_ENOLOCK = (APR_OS_START_ERROR + 9); + public static final int APR_ENOPOLL = (APR_OS_START_ERROR + 10); + public static final int APR_ENOSOCKET = (APR_OS_START_ERROR + 11); + public static final int APR_ENOTHREAD = (APR_OS_START_ERROR + 12); + public static final int APR_ENOTHDKEY = (APR_OS_START_ERROR + 13); + public static final int APR_EGENERAL = (APR_OS_START_ERROR + 14); + public static final int APR_ENOSHMAVAIL = (APR_OS_START_ERROR + 15); + public static final int APR_EBADIP = (APR_OS_START_ERROR + 16); + public static final int APR_EBADMASK = (APR_OS_START_ERROR + 17); + public static final int APR_EDSOOPEN = (APR_OS_START_ERROR + 19); + public static final int APR_EABSOLUTE = (APR_OS_START_ERROR + 20); + public static final int APR_ERELATIVE = (APR_OS_START_ERROR + 21); + public static final int APR_EINCOMPLETE = (APR_OS_START_ERROR + 22); + public static final int APR_EABOVEROOT = (APR_OS_START_ERROR + 23); + public static final int APR_EBADPATH = (APR_OS_START_ERROR + 24); + public static final int APR_EPATHWILD = (APR_OS_START_ERROR + 25); + public static final int APR_ESYMNOTFOUND = (APR_OS_START_ERROR + 26); + public static final int APR_EPROC_UNKNOWN = (APR_OS_START_ERROR + 27); + public static final int APR_ENOTENOUGHENTROPY = (APR_OS_START_ERROR + 28); + + /** APR Status Values + *
        +     * APR STATUS VALUES
        +     * APR_INCHILD        Program is currently executing in the child
        +     * APR_INPARENT       Program is currently executing in the parent
        +     * APR_DETACH         The thread is detached
        +     * APR_NOTDETACH      The thread is not detached
        +     * APR_CHILD_DONE     The child has finished executing
        +     * APR_CHILD_NOTDONE  The child has not finished executing
        +     * APR_TIMEUP         The operation did not finish before the timeout
        +     * APR_INCOMPLETE     The operation was incomplete although some processing
        +     *                    was performed and the results are partially valid
        +     * APR_BADCH          Getopt found an option not in the option string
        +     * APR_BADARG         Getopt found an option that is missing an argument
        +     *                    and an argument was specified in the option string
        +     * APR_EOF            APR has encountered the end of the file
        +     * APR_NOTFOUND       APR was unable to find the socket in the poll structure
        +     * APR_ANONYMOUS      APR is using anonymous shared memory
        +     * APR_FILEBASED      APR is using a file name as the key to the shared memory
        +     * APR_KEYBASED       APR is using a shared key as the key to the shared memory
        +     * APR_EINIT          Ininitalizer value.  If no option has been found, but
        +     *                    the status variable requires a value, this should be used
        +     * APR_ENOTIMPL       The APR function has not been implemented on this
        +     *                    platform, either because nobody has gotten to it yet,
        +     *                    or the function is impossible on this platform.
        +     * APR_EMISMATCH      Two passwords do not match.
        +     * APR_EBUSY          The given lock was busy.
        +     * 
        + * + */ + public static final int APR_INCHILD = (APR_OS_START_STATUS + 1); + public static final int APR_INPARENT = (APR_OS_START_STATUS + 2); + public static final int APR_DETACH = (APR_OS_START_STATUS + 3); + public static final int APR_NOTDETACH = (APR_OS_START_STATUS + 4); + public static final int APR_CHILD_DONE = (APR_OS_START_STATUS + 5); + public static final int APR_CHILD_NOTDONE = (APR_OS_START_STATUS + 6); + public static final int APR_TIMEUP = (APR_OS_START_STATUS + 7); + public static final int APR_INCOMPLETE = (APR_OS_START_STATUS + 8); + public static final int APR_BADCH = (APR_OS_START_STATUS + 12); + public static final int APR_BADARG = (APR_OS_START_STATUS + 13); + public static final int APR_EOF = (APR_OS_START_STATUS + 14); + public static final int APR_NOTFOUND = (APR_OS_START_STATUS + 15); + public static final int APR_ANONYMOUS = (APR_OS_START_STATUS + 19); + public static final int APR_FILEBASED = (APR_OS_START_STATUS + 20); + public static final int APR_KEYBASED = (APR_OS_START_STATUS + 21); + public static final int APR_EINIT = (APR_OS_START_STATUS + 22); + public static final int APR_ENOTIMPL = (APR_OS_START_STATUS + 23); + public static final int APR_EMISMATCH = (APR_OS_START_STATUS + 24); + public static final int APR_EBUSY = (APR_OS_START_STATUS + 25); + + public static final int TIMEUP = (APR_OS_START_USERERR + 1); + public static final int EAGAIN = (APR_OS_START_USERERR + 2); + public static final int EINTR = (APR_OS_START_USERERR + 3); + public static final int EINPROGRESS = (APR_OS_START_USERERR + 4); + public static final int ETIMEDOUT = (APR_OS_START_USERERR + 5); + + private static native boolean is(int err, int idx); + /** + * APR_STATUS_IS Status Value Tests + *
        Warning : For any particular error condition, more than one of these tests + * may match. This is because platform-specific error codes may not + * always match the semantics of the POSIX codes these tests (and the + * corresponding APR error codes) are named after. A notable example + * are the APR_STATUS_IS_ENOENT and APR_STATUS_IS_ENOTDIR tests on + * Win32 platforms. The programmer should always be aware of this and + * adjust the order of the tests accordingly. + * + */ + public static final boolean APR_STATUS_IS_ENOSTAT(int s) { return is(s, 1); } + public static final boolean APR_STATUS_IS_ENOPOOL(int s) { return is(s, 2); } + /* empty slot: +3 */ + public static final boolean APR_STATUS_IS_EBADDATE(int s) { return is(s, 4); } + public static final boolean APR_STATUS_IS_EINVALSOCK(int s) { return is(s, 5); } + public static final boolean APR_STATUS_IS_ENOPROC(int s) { return is(s, 6); } + public static final boolean APR_STATUS_IS_ENOTIME(int s) { return is(s, 7); } + public static final boolean APR_STATUS_IS_ENODIR(int s) { return is(s, 8); } + public static final boolean APR_STATUS_IS_ENOLOCK(int s) { return is(s, 9); } + public static final boolean APR_STATUS_IS_ENOPOLL(int s) { return is(s, 10); } + public static final boolean APR_STATUS_IS_ENOSOCKET(int s) { return is(s, 11); } + public static final boolean APR_STATUS_IS_ENOTHREAD(int s) { return is(s, 12); } + public static final boolean APR_STATUS_IS_ENOTHDKEY(int s) { return is(s, 13); } + public static final boolean APR_STATUS_IS_EGENERAL(int s) { return is(s, 14); } + public static final boolean APR_STATUS_IS_ENOSHMAVAIL(int s){ return is(s, 15); } + public static final boolean APR_STATUS_IS_EBADIP(int s) { return is(s, 16); } + public static final boolean APR_STATUS_IS_EBADMASK(int s) { return is(s, 17); } + /* empty slot: +18 */ + public static final boolean APR_STATUS_IS_EDSOPEN(int s) { return is(s, 19); } + public static final boolean APR_STATUS_IS_EABSOLUTE(int s) { return is(s, 20); } + public static final boolean APR_STATUS_IS_ERELATIVE(int s) { return is(s, 21); } + public static final boolean APR_STATUS_IS_EINCOMPLETE(int s){ return is(s, 22); } + public static final boolean APR_STATUS_IS_EABOVEROOT(int s) { return is(s, 23); } + public static final boolean APR_STATUS_IS_EBADPATH(int s) { return is(s, 24); } + public static final boolean APR_STATUS_IS_EPATHWILD(int s) { return is(s, 25); } + public static final boolean APR_STATUS_IS_ESYMNOTFOUND(int s) { return is(s, 26); } + public static final boolean APR_STATUS_IS_EPROC_UNKNOWN(int s) { return is(s, 27); } + public static final boolean APR_STATUS_IS_ENOTENOUGHENTROPY(int s) { return is(s, 28); } + + /* + * APR_Error + */ + public static final boolean APR_STATUS_IS_INCHILD(int s) { return is(s, 51); } + public static final boolean APR_STATUS_IS_INPARENT(int s) { return is(s, 52); } + public static final boolean APR_STATUS_IS_DETACH(int s) { return is(s, 53); } + public static final boolean APR_STATUS_IS_NOTDETACH(int s) { return is(s, 54); } + public static final boolean APR_STATUS_IS_CHILD_DONE(int s) { return is(s, 55); } + public static final boolean APR_STATUS_IS_CHILD_NOTDONE(int s) { return is(s, 56); } + public static final boolean APR_STATUS_IS_TIMEUP(int s) { return is(s, 57); } + public static final boolean APR_STATUS_IS_INCOMPLETE(int s) { return is(s, 58); } + /* empty slot: +9 */ + /* empty slot: +10 */ + /* empty slot: +11 */ + public static final boolean APR_STATUS_IS_BADCH(int s) { return is(s, 62); } + public static final boolean APR_STATUS_IS_BADARG(int s) { return is(s, 63); } + public static final boolean APR_STATUS_IS_EOF(int s) { return is(s, 64); } + public static final boolean APR_STATUS_IS_NOTFOUND(int s) { return is(s, 65); } + /* empty slot: +16 */ + /* empty slot: +17 */ + /* empty slot: +18 */ + public static final boolean APR_STATUS_IS_ANONYMOUS(int s) { return is(s, 69); } + public static final boolean APR_STATUS_IS_FILEBASED(int s) { return is(s, 70); } + public static final boolean APR_STATUS_IS_KEYBASED(int s) { return is(s, 71); } + public static final boolean APR_STATUS_IS_EINIT(int s) { return is(s, 72); } + public static final boolean APR_STATUS_IS_ENOTIMPL(int s) { return is(s, 73); } + public static final boolean APR_STATUS_IS_EMISMATCH(int s) { return is(s, 74); } + public static final boolean APR_STATUS_IS_EBUSY(int s) { return is(s, 75); } + + /* Socket errors */ + public static final boolean APR_STATUS_IS_EAGAIN(int s) { return is(s, 90); } + public static final boolean APR_STATUS_IS_ETIMEDOUT(int s) { return is(s, 91); } + public static final boolean APR_STATUS_IS_ECONNABORTED(int s) { return is(s, 92); } + public static final boolean APR_STATUS_IS_ECONNRESET(int s) { return is(s, 93); } + public static final boolean APR_STATUS_IS_EINPROGRESS(int s) { return is(s, 94); } + public static final boolean APR_STATUS_IS_EINTR(int s) { return is(s, 95); } + public static final boolean APR_STATUS_IS_ENOTSOCK(int s) { return is(s, 96); } + public static final boolean APR_STATUS_IS_EINVAL(int s) { return is(s, 97); } + +} diff --git a/java/org/apache/tomcat/jni/Stdlib.java b/java/org/apache/tomcat/jni/Stdlib.java index 5e0ac17ff..d5734fbd0 100644 --- a/java/org/apache/tomcat/jni/Stdlib.java +++ b/java/org/apache/tomcat/jni/Stdlib.java @@ -1,89 +1,89 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Stdlib - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Stdlib { - - /** - * Read from plain memory - * @param dst Destination byte array - * @param src Source memory address - * @param sz Number of bytes to copy. - */ - public static native boolean memread(byte [] dst, long src, int sz); - - /** - * Write to plain memory - * @param dst Destination memory address - * @param src Source byte array - * @param sz Number of bytes to copy. - */ - public static native boolean memwrite(long dst, byte [] src, int sz); - - /** - * Sets buffers to a specified character - * @param dst Destination memory address - * @param c Character to set. - * @param sz Number of characters. - */ - public static native boolean memset(long dst, int c, int sz); - - /** - * Allocates memory blocks. - * @param sz Bytes to allocate. - */ - public static native long malloc(int sz); - - /** - * Reallocate memory blocks. - * @param mem Pointer to previously allocated memory block. - * @param sz New size in bytes. - */ - public static native long realloc(long mem, int sz); - - /** - * Allocates an array in memory with elements initialized to 0. - * @param num Number of elements. - * @param sz Length in bytes of each element. - */ - public static native long calloc(long num, int sz); - - /** - * Deallocates or frees a memory block. - * @param mem Previously allocated memory block to be freed. - */ - public static native void free(long mem); - - /** - * Get current process pid. - * @return current pid or < 1 in case of error. - */ - public static native int getpid(); - - /** - * Get current process parent pid. - * @return parent pid or < 1 in case of error. - */ - public static native int getppid(); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Stdlib + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Stdlib { + + /** + * Read from plain memory + * @param dst Destination byte array + * @param src Source memory address + * @param sz Number of bytes to copy. + */ + public static native boolean memread(byte [] dst, long src, int sz); + + /** + * Write to plain memory + * @param dst Destination memory address + * @param src Source byte array + * @param sz Number of bytes to copy. + */ + public static native boolean memwrite(long dst, byte [] src, int sz); + + /** + * Sets buffers to a specified character + * @param dst Destination memory address + * @param c Character to set. + * @param sz Number of characters. + */ + public static native boolean memset(long dst, int c, int sz); + + /** + * Allocates memory blocks. + * @param sz Bytes to allocate. + */ + public static native long malloc(int sz); + + /** + * Reallocate memory blocks. + * @param mem Pointer to previously allocated memory block. + * @param sz New size in bytes. + */ + public static native long realloc(long mem, int sz); + + /** + * Allocates an array in memory with elements initialized to 0. + * @param num Number of elements. + * @param sz Length in bytes of each element. + */ + public static native long calloc(long num, int sz); + + /** + * Deallocates or frees a memory block. + * @param mem Previously allocated memory block to be freed. + */ + public static native void free(long mem); + + /** + * Get current process pid. + * @return current pid or < 1 in case of error. + */ + public static native int getpid(); + + /** + * Get current process parent pid. + * @return parent pid or < 1 in case of error. + */ + public static native int getppid(); + +} diff --git a/java/org/apache/tomcat/jni/Time.java b/java/org/apache/tomcat/jni/Time.java index bf09306a3..15999dce1 100644 --- a/java/org/apache/tomcat/jni/Time.java +++ b/java/org/apache/tomcat/jni/Time.java @@ -1,73 +1,73 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** Time - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class Time { - - /** number of microseconds per second */ - public static final long APR_USEC_PER_SEC = 1000000L; - /** number of miliseconds per microsecond */ - public static final long APR_MSEC_PER_USEC = 1000L; - - /** @return apr_time_t as a second */ - public static long sec(long t) - { - return t / APR_USEC_PER_SEC; - } - - /** @return apr_time_t as a msec */ - public static long msec(long t) - { - return t / APR_MSEC_PER_USEC; - } - - /** - * number of microseconds since 00:00:00 january 1, 1970 UTC - * @return the current time - */ - public static native long now(); - - /** - * Formats dates in the RFC822 - * format in an efficient manner. - * @param t the time to convert - */ - public static native String rfc822(long t); - - /** - * Formats dates in the ctime() format - * in an efficient manner. - * Unlike ANSI/ISO C ctime(), apr_ctime() does not include - * a \n at the end of the string. - * @param t the time to convert - */ - public static native String ctime(long t); - - /** - * Sleep for the specified number of micro-seconds. - *
        Warning : May sleep for longer than the specified time. - * @param t desired amount of time to sleep. - */ - public static native void sleep(long t); - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** Time + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class Time { + + /** number of microseconds per second */ + public static final long APR_USEC_PER_SEC = 1000000L; + /** number of miliseconds per microsecond */ + public static final long APR_MSEC_PER_USEC = 1000L; + + /** @return apr_time_t as a second */ + public static long sec(long t) + { + return t / APR_USEC_PER_SEC; + } + + /** @return apr_time_t as a msec */ + public static long msec(long t) + { + return t / APR_MSEC_PER_USEC; + } + + /** + * number of microseconds since 00:00:00 january 1, 1970 UTC + * @return the current time + */ + public static native long now(); + + /** + * Formats dates in the RFC822 + * format in an efficient manner. + * @param t the time to convert + */ + public static native String rfc822(long t); + + /** + * Formats dates in the ctime() format + * in an efficient manner. + * Unlike ANSI/ISO C ctime(), apr_ctime() does not include + * a \n at the end of the string. + * @param t the time to convert + */ + public static native String ctime(long t); + + /** + * Sleep for the specified number of micro-seconds. + *
        Warning : May sleep for longer than the specified time. + * @param t desired amount of time to sleep. + */ + public static native void sleep(long t); + +} diff --git a/java/org/apache/tomcat/jni/User.java b/java/org/apache/tomcat/jni/User.java index e573eda5e..f04fcedf6 100644 --- a/java/org/apache/tomcat/jni/User.java +++ b/java/org/apache/tomcat/jni/User.java @@ -1,126 +1,126 @@ -/* - * Copyright 2000-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.jni; - -/** User - * - * @author Mladen Turk - * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ - */ - -public class User { - - /** - * Get the userid (and groupid) of the calling process - * This function is available only if APR_HAS_USER is defined. - * @param p The pool from which to allocate working space - * @return Returns the user id - */ - public static native long uidCurrent(long p) - throws Error; - - /** - * Get the groupid of the calling process - * This function is available only if APR_HAS_USER is defined. - * @param p The pool from which to allocate working space - * @return Returns the group id - */ - public static native long gidCurrent(long p) - throws Error; - - - /** - * Get the userid for the specified username - * This function is available only if APR_HAS_USER is defined. - * @param username The username to lookup - * @param p The pool from which to allocate working space - * @return Returns the user id - */ - public static native long uid(String username, long p) - throws Error; - - /** - * Get the groupid for the specified username - * This function is available only if APR_HAS_USER is defined. - * @param username The username to lookup - * @param p The pool from which to allocate working space - * @return Returns the user's group id - */ - public static native long usergid(String username, long p) - throws Error; - - /** - * Get the groupid for a specified group name - * This function is available only if APR_HAS_USER is defined. - * @param groupname The group name to look up - * @param p The pool from which to allocate working space - * @return Returns the user's group id - */ - public static native long gid(String groupname, long p) - throws Error; - - /** - * Get the user name for a specified userid - * This function is available only if APR_HAS_USER is defined. - * @param userid The userid - * @param p The pool from which to allocate the string - * @return New string containing user name - */ - public static native String username(long userid, long p) - throws Error; - - /** - * Get the group name for a specified groupid - * This function is available only if APR_HAS_USER is defined. - * @param groupid The groupid - * @param p The pool from which to allocate the string - * @return New string containing group name - */ - public static native String groupname(long groupid, long p) - throws Error; - - /** - * Compare two user identifiers for equality. - * This function is available only if APR_HAS_USER is defined. - * @param left One uid to test - * @param right Another uid to test - * @return APR_SUCCESS if the apr_uid_t strutures identify the same user, - * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. - */ - public static native int uidcompare(long left, long right); - - /** - * Compare two group identifiers for equality. - * This function is available only if APR_HAS_USER is defined. - * @param left One gid to test - * @param right Another gid to test - * @return APR_SUCCESS if the apr_gid_t strutures identify the same group, - * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. - */ - public static native int gidcompare(long left, long right); - - /** - * Get the home directory for the named user - * This function is available only if APR_HAS_USER is defined. - * @param username The named user - * @param p The pool from which to allocate the string - * @return New string containing directory name - */ - public static native String homepath(String username, long p) - throws Error; - -} +/* + * Copyright 2000-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.jni; + +/** User + * + * @author Mladen Turk + * @version $Revision: 300969 $, $Date: 2005-07-12 16:56:11 +0200 (mar., 12 juil. 2005) $ + */ + +public class User { + + /** + * Get the userid (and groupid) of the calling process + * This function is available only if APR_HAS_USER is defined. + * @param p The pool from which to allocate working space + * @return Returns the user id + */ + public static native long uidCurrent(long p) + throws Error; + + /** + * Get the groupid of the calling process + * This function is available only if APR_HAS_USER is defined. + * @param p The pool from which to allocate working space + * @return Returns the group id + */ + public static native long gidCurrent(long p) + throws Error; + + + /** + * Get the userid for the specified username + * This function is available only if APR_HAS_USER is defined. + * @param username The username to lookup + * @param p The pool from which to allocate working space + * @return Returns the user id + */ + public static native long uid(String username, long p) + throws Error; + + /** + * Get the groupid for the specified username + * This function is available only if APR_HAS_USER is defined. + * @param username The username to lookup + * @param p The pool from which to allocate working space + * @return Returns the user's group id + */ + public static native long usergid(String username, long p) + throws Error; + + /** + * Get the groupid for a specified group name + * This function is available only if APR_HAS_USER is defined. + * @param groupname The group name to look up + * @param p The pool from which to allocate working space + * @return Returns the user's group id + */ + public static native long gid(String groupname, long p) + throws Error; + + /** + * Get the user name for a specified userid + * This function is available only if APR_HAS_USER is defined. + * @param userid The userid + * @param p The pool from which to allocate the string + * @return New string containing user name + */ + public static native String username(long userid, long p) + throws Error; + + /** + * Get the group name for a specified groupid + * This function is available only if APR_HAS_USER is defined. + * @param groupid The groupid + * @param p The pool from which to allocate the string + * @return New string containing group name + */ + public static native String groupname(long groupid, long p) + throws Error; + + /** + * Compare two user identifiers for equality. + * This function is available only if APR_HAS_USER is defined. + * @param left One uid to test + * @param right Another uid to test + * @return APR_SUCCESS if the apr_uid_t strutures identify the same user, + * APR_EMISMATCH if not, APR_BADARG if an apr_uid_t is invalid. + */ + public static native int uidcompare(long left, long right); + + /** + * Compare two group identifiers for equality. + * This function is available only if APR_HAS_USER is defined. + * @param left One gid to test + * @param right Another gid to test + * @return APR_SUCCESS if the apr_gid_t strutures identify the same group, + * APR_EMISMATCH if not, APR_BADARG if an apr_gid_t is invalid. + */ + public static native int gidcompare(long left, long right); + + /** + * Get the home directory for the named user + * This function is available only if APR_HAS_USER is defined. + * @param username The named user + * @param p The pool from which to allocate the string + * @return New string containing directory name + */ + public static native String homepath(String username, long p) + throws Error; + +} diff --git a/java/org/apache/tomcat/util/DomUtil.java b/java/org/apache/tomcat/util/DomUtil.java index 3cac8a706..402952da5 100644 --- a/java/org/apache/tomcat/util/DomUtil.java +++ b/java/org/apache/tomcat/util/DomUtil.java @@ -1,269 +1,269 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.util; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.StringReader; - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerException; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; - -import org.w3c.dom.Document; -import org.w3c.dom.NamedNodeMap; -import org.w3c.dom.Node; -import org.xml.sax.EntityResolver; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; - - -/** - * Few simple utils to read DOM - * - * @author Costin Manolache - */ -public class DomUtil { - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( DomUtil.class ); - - // -------------------- DOM utils -------------------- - - /** Get the trimed text content of a node or null if there is no text - */ - public static String getContent(Node n ) { - if( n==null ) return null; - Node n1=DomUtil.getChild(n, Node.TEXT_NODE); - - if( n1==null ) return null; - - String s1=n1.getNodeValue(); - return s1.trim(); - } - - /** Get the first element child. - * @param parent lookup direct childs - * @param name name of the element. If null return the first element. - */ - public static Node getChild( Node parent, String name ) { - if( parent==null ) return null; - Node first=parent.getFirstChild(); - if( first==null ) return null; - - for (Node node = first; node != null; - node = node.getNextSibling()) { - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( node.getNodeType()!=Node.ELEMENT_NODE) - continue; - if( name != null && - name.equals( node.getNodeName() ) ) { - return node; - } - if( name == null ) { - return node; - } - } - return null; - } - - public static String getAttribute(Node element, String attName ) { - NamedNodeMap attrs=element.getAttributes(); - if( attrs==null ) return null; - Node attN=attrs.getNamedItem(attName); - if( attN==null ) return null; - return attN.getNodeValue(); - } - - public static void setAttribute(Node node, String attName, String val) { - NamedNodeMap attributes=node.getAttributes(); - Node attNode=node.getOwnerDocument().createAttribute(attName); - attNode.setNodeValue( val ); - attributes.setNamedItem(attNode); - } - - public static void removeAttribute( Node node, String attName ) { - NamedNodeMap attributes=node.getAttributes(); - attributes.removeNamedItem(attName); - } - - - /** Set or replace the text value - */ - public static void setText(Node node, String val) { - Node chld=DomUtil.getChild(node, Node.TEXT_NODE); - if( chld == null ) { - Node textN=node.getOwnerDocument().createTextNode(val); - node.appendChild(textN); - return; - } - // change the value - chld.setNodeValue(val); - } - - /** Find the first direct child with a given attribute. - * @param parent - * @param elemName name of the element, or null for any - * @param attName attribute we're looking for - * @param attVal attribute value or null if we just want any - */ - public static Node findChildWithAtt(Node parent, String elemName, - String attName, String attVal) { - - Node child=DomUtil.getChild(parent, Node.ELEMENT_NODE); - if( attVal== null ) { - while( child!= null && - ( elemName==null || elemName.equals( child.getNodeName())) && - DomUtil.getAttribute(child, attName) != null ) { - child=getNext(child, elemName, Node.ELEMENT_NODE ); - } - } else { - while( child!= null && - ( elemName==null || elemName.equals( child.getNodeName())) && - ! attVal.equals( DomUtil.getAttribute(child, attName)) ) { - child=getNext(child, elemName, Node.ELEMENT_NODE ); - } - } - return child; - } - - - /** Get the first child's content ( ie it's included TEXT node ). - */ - public static String getChildContent( Node parent, String name ) { - Node first=parent.getFirstChild(); - if( first==null ) return null; - for (Node node = first; node != null; - node = node.getNextSibling()) { - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( name.equals( node.getNodeName() ) ) { - return getContent( node ); - } - } - return null; - } - - /** Get the first direct child with a given type - */ - public static Node getChild( Node parent, int type ) { - Node n=parent.getFirstChild(); - while( n!=null && type != n.getNodeType() ) { - n=n.getNextSibling(); - } - if( n==null ) return null; - return n; - } - - /** Get the next sibling with the same name and type - */ - public static Node getNext( Node current ) { - String name=current.getNodeName(); - int type=current.getNodeType(); - return getNext( current, name, type); - } - - /** Return the next sibling with a given name and type - */ - public static Node getNext( Node current, String name, int type) { - Node first=current.getNextSibling(); - if( first==null ) return null; - - for (Node node = first; node != null; - node = node.getNextSibling()) { - - if( type >= 0 && node.getNodeType() != type ) continue; - //System.out.println("getNode: " + name + " " + node.getNodeName()); - if( name==null ) - return node; - if( name.equals( node.getNodeName() ) ) { - return node; - } - } - return null; - } - - public static class NullResolver implements EntityResolver { - public InputSource resolveEntity (String publicId, - String systemId) - throws SAXException, IOException - { - if( log.isTraceEnabled()) - log.trace("ResolveEntity: " + publicId + " " + systemId); - return new InputSource(new StringReader("")); - } - } - - public static void setAttributes( Object o, Node parent) - { - NamedNodeMap attrs=parent.getAttributes(); - if( attrs==null ) return; - - for (int i=0; i= 0 && node.getNodeType() != type ) continue; + //System.out.println("getNode: " + name + " " + node.getNodeName()); + if( name==null ) + return node; + if( name.equals( node.getNodeName() ) ) { + return node; + } + } + return null; + } + + public static class NullResolver implements EntityResolver { + public InputSource resolveEntity (String publicId, + String systemId) + throws SAXException, IOException + { + if( log.isTraceEnabled()) + log.trace("ResolveEntity: " + publicId + " " + systemId); + return new InputSource(new StringReader("")); + } + } + + public static void setAttributes( Object o, Node parent) + { + NamedNodeMap attrs=parent.getAttributes(); + if( attrs==null ) return; + + for (int i=0; i 1) - d("setProperty(" + o.getClass() + " " + name + "=" + value + ")"); - - String setter = "set" + capitalize(name); - - try { - Method methods[] = findMethods(o.getClass()); - Method setPropertyMethod = null; - - // First, the ideal case - a setFoo( String ) method - for (int i = 0; i < methods.length; i++) { - Class paramT[] = methods[i].getParameterTypes(); - if (setter.equals(methods[i].getName()) && paramT.length == 1 - && "java.lang.String".equals(paramT[0].getName())) { - - methods[i].invoke(o, new Object[] { value }); - return; - } - } - - // Try a setFoo ( int ) or ( boolean ) - for (int i = 0; i < methods.length; i++) { - boolean ok = true; - if (setter.equals(methods[i].getName()) - && methods[i].getParameterTypes().length == 1) { - - // match - find the type and invoke it - Class paramType = methods[i].getParameterTypes()[0]; - Object params[] = new Object[1]; - - // Try a setFoo ( int ) - if ("java.lang.Integer".equals(paramType.getName()) - || "int".equals(paramType.getName())) { - try { - params[0] = new Integer(value); - } catch (NumberFormatException ex) { - ok = false; - } - // Try a setFoo ( long ) - }else if ("java.lang.Long".equals(paramType.getName()) - || "long".equals(paramType.getName())) { - try { - params[0] = new Long(value); - } catch (NumberFormatException ex) { - ok = false; - } - - // Try a setFoo ( boolean ) - } else if ("java.lang.Boolean".equals(paramType.getName()) - || "boolean".equals(paramType.getName())) { - params[0] = new Boolean(value); - - // Try a setFoo ( InetAddress ) - } else if ("java.net.InetAddress".equals(paramType - .getName())) { - try { - params[0] = InetAddress.getByName(value); - } catch (UnknownHostException exc) { - d("Unable to resolve host name:" + value); - ok = false; - } - - // Unknown type - } else { - d("Unknown type " + paramType.getName()); - } - - if (ok) { - methods[i].invoke(o, params); - return; - } - } - - // save "setProperty" for later - if ("setProperty".equals(methods[i].getName())) { - setPropertyMethod = methods[i]; - } - } - - // Ok, no setXXX found, try a setProperty("name", "value") - if (setPropertyMethod != null) { - Object params[] = new Object[2]; - params[0] = name; - params[1] = value; - setPropertyMethod.invoke(o, params); - } - - } catch (IllegalArgumentException ex2) { - log.warn("IAE " + o + " " + name + " " + value, ex2); - } catch (SecurityException ex1) { - if (dbg > 0) - d("SecurityException for " + o.getClass() + " " + name + "=" - + value + ")"); - if (dbg > 1) - ex1.printStackTrace(); - } catch (IllegalAccessException iae) { - if (dbg > 0) - d("IllegalAccessException for " + o.getClass() + " " + name - + "=" + value + ")"); - if (dbg > 1) - iae.printStackTrace(); - } catch (InvocationTargetException ie) { - if (dbg > 0) - d("InvocationTargetException for " + o.getClass() + " " + name - + "=" + value + ")"); - if (dbg > 1) - ie.printStackTrace(); - } - } - - public static Object getProperty(Object o, String name) { - String getter = "get" + capitalize(name); - String isGetter = "is" + capitalize(name); - - try { - Method methods[] = findMethods(o.getClass()); - Method getPropertyMethod = null; - - // First, the ideal case - a getFoo() method - for (int i = 0; i < methods.length; i++) { - Class paramT[] = methods[i].getParameterTypes(); - if (getter.equals(methods[i].getName()) && paramT.length == 0) { - return methods[i].invoke(o, (Object[]) null); - } - if (isGetter.equals(methods[i].getName()) && paramT.length == 0) { - return methods[i].invoke(o, (Object[]) null); - } - - if ("getProperty".equals(methods[i].getName())) { - getPropertyMethod = methods[i]; - } - } - - // Ok, no setXXX found, try a getProperty("name") - if (getPropertyMethod != null) { - Object params[] = new Object[1]; - params[0] = name; - return getPropertyMethod.invoke(o, params); - } - - } catch (IllegalArgumentException ex2) { - log.warn("IAE " + o + " " + name, ex2); - } catch (SecurityException ex1) { - if (dbg > 0) - d("SecurityException for " + o.getClass() + " " + name + ")"); - if (dbg > 1) - ex1.printStackTrace(); - } catch (IllegalAccessException iae) { - if (dbg > 0) - d("IllegalAccessException for " + o.getClass() + " " + name - + ")"); - if (dbg > 1) - iae.printStackTrace(); - } catch (InvocationTargetException ie) { - if (dbg > 0) - d("InvocationTargetException for " + o.getClass() + " " + name - + ")"); - if (dbg > 1) - ie.printStackTrace(); - } - return null; - } - - /** - */ - public static void setProperty(Object o, String name) { - String setter = "set" + capitalize(name); - try { - Method methods[] = findMethods(o.getClass()); - Method setPropertyMethod = null; - // find setFoo() method - for (int i = 0; i < methods.length; i++) { - Class paramT[] = methods[i].getParameterTypes(); - if (setter.equals(methods[i].getName()) && paramT.length == 0) { - methods[i].invoke(o, new Object[] {}); - return; - } - } - } catch (Exception ex1) { - if (dbg > 0) - d("Exception for " + o.getClass() + " " + name); - if (dbg > 1) - ex1.printStackTrace(); - } - } - - /** - * Replace ${NAME} with the property value - * - * @deprecated Use the explicit method - */ - public static String replaceProperties(String value, Object getter) { - if (getter instanceof Hashtable) - return replaceProperties(value, (Hashtable) getter, null); - - if (getter instanceof PropertySource) { - PropertySource src[] = new PropertySource[] { (PropertySource) getter }; - return replaceProperties(value, null, src); - } - return value; - } - - /** - * Replace ${NAME} with the property value - */ - public static String replaceProperties(String value, Hashtable staticProp, - PropertySource dynamicProp[]) { - StringBuffer sb = new StringBuffer(); - int prev = 0; - // assert value!=nil - int pos; - while ((pos = value.indexOf("$", prev)) >= 0) { - if (pos > 0) { - sb.append(value.substring(prev, pos)); - } - if (pos == (value.length() - 1)) { - sb.append('$'); - prev = pos + 1; - } else if (value.charAt(pos + 1) != '{') { - sb.append('$'); - prev = pos + 1; // XXX - } else { - int endName = value.indexOf('}', pos); - if (endName < 0) { - sb.append(value.substring(pos)); - prev = value.length(); - continue; - } - String n = value.substring(pos + 2, endName); - String v = null; - if (staticProp != null) { - v = (String) ((Hashtable) staticProp).get(n); - } - if (v == null && dynamicProp != null) { - for (int i = 0; i < dynamicProp.length; i++) { - v = dynamicProp[i].getProperty(n); - if (v != null) { - break; - } - } - } - if (v == null) - v = "${" + n + "}"; - - sb.append(v); - prev = endName + 1; - } - } - if (prev < value.length()) - sb.append(value.substring(prev)); - return sb.toString(); - } - - /** - * Reverse of Introspector.decapitalize - */ - public static String capitalize(String name) { - if (name == null || name.length() == 0) { - return name; - } - char chars[] = name.toCharArray(); - chars[0] = Character.toUpperCase(chars[0]); - return new String(chars); - } - - public static String unCapitalize(String name) { - if (name == null || name.length() == 0) { - return name; - } - char chars[] = name.toCharArray(); - chars[0] = Character.toLowerCase(chars[0]); - return new String(chars); - } - - // -------------------- Class path tools -------------------- - - /** - * Add all the jar files in a dir to the classpath, represented as a Vector - * of URLs. - */ - public static void addToClassPath(Vector cpV, String dir) { - try { - String cpComp[] = getFilesByExt(dir, ".jar"); - if (cpComp != null) { - int jarCount = cpComp.length; - for (int i = 0; i < jarCount; i++) { - URL url = getURL(dir, cpComp[i]); - if (url != null) - cpV.addElement(url); - } - } - } catch (Exception ex) { - ex.printStackTrace(); - } - } - - public static void addToolsJar(Vector v) { - try { - // Add tools.jar in any case - File f = new File(System.getProperty("java.home") - + "/../lib/tools.jar"); - - if (!f.exists()) { - // On some systems java.home gets set to the root of jdk. - // That's a bug, but we can work around and be nice. - f = new File(System.getProperty("java.home") + "/lib/tools.jar"); - if (f.exists()) { - if (log.isDebugEnabled()) - log.debug("Detected strange java.home value " - + System.getProperty("java.home") - + ", it should point to jre"); - } - } - URL url = new URL("file", "", f.getAbsolutePath()); - - v.addElement(url); - } catch (MalformedURLException ex) { - ex.printStackTrace(); - } - } - - /** - * Return all files with a given extension in a dir - */ - public static String[] getFilesByExt(String ld, String ext) { - File dir = new File(ld); - String[] names = null; - final String lext = ext; - if (dir.isDirectory()) { - names = dir.list(new FilenameFilter() { - public boolean accept(File d, String name) { - if (name.endsWith(lext)) { - return true; - } - return false; - } - }); - } - return names; - } - - /** - * Construct a file url from a file, using a base dir - */ - public static URL getURL(String base, String file) { - try { - File baseF = new File(base); - File f = new File(baseF, file); - String path = f.getCanonicalPath(); - if (f.isDirectory()) { - path += "/"; - } - if (!f.exists()) - return null; - return new URL("file", "", path); - } catch (Exception ex) { - ex.printStackTrace(); - return null; - } - } - - /** - * Add elements from the classpath cp to a Vector jars as - * file URLs (We use Vector for JDK 1.1 compat). - *

        - * - * @param jars The jar list - * @param cp a String classpath of directory or jar file elements - * separated by path.separator delimiters. - * @throws IOException If an I/O error occurs - * @throws MalformedURLException Doh ;) - */ - public static void addJarsFromClassPath(Vector jars, String cp) - throws IOException, MalformedURLException { - String sep = System.getProperty("path.separator"); - String token; - StringTokenizer st; - if (cp != null) { - st = new StringTokenizer(cp, sep); - while (st.hasMoreTokens()) { - File f = new File(st.nextToken()); - String path = f.getCanonicalPath(); - if (f.isDirectory()) { - path += "/"; - } - URL url = new URL("file", "", path); - if (!jars.contains(url)) { - jars.addElement(url); - } - } - } - } - - /** - * Return a URL[] that can be used to construct a class loader - */ - public static URL[] getClassPath(Vector v) { - URL[] urls = new URL[v.size()]; - for (int i = 0; i < v.size(); i++) { - urls[i] = (URL) v.elementAt(i); - } - return urls; - } - - /** - * Construct a URL classpath from files in a directory, a cpath property, - * and tools.jar. - */ - public static URL[] getClassPath(String dir, String cpath, - String cpathProp, boolean addTools) throws IOException, - MalformedURLException { - Vector jarsV = new Vector(); - if (dir != null) { - // Add dir/classes first, if it exists - URL url = getURL(dir, "classes"); - if (url != null) - jarsV.addElement(url); - addToClassPath(jarsV, dir); - } - - if (cpath != null) - addJarsFromClassPath(jarsV, cpath); - - if (cpathProp != null) { - String cpath1 = System.getProperty(cpathProp); - addJarsFromClassPath(jarsV, cpath1); - } - - if (addTools) - addToolsJar(jarsV); - - return getClassPath(jarsV); - } - - // -------------------- Mapping command line params to setters - - public static boolean processArgs(Object proxy, String args[]) - throws Exception { - String args0[] = null; - if (null != findMethod(proxy.getClass(), "getOptions1", new Class[] {})) { - args0 = (String[]) callMethod0(proxy, "getOptions1"); - } - - if (args0 == null) { - //args0=findVoidSetters(proxy.getClass()); - args0 = findBooleanSetters(proxy.getClass()); - } - Hashtable h = null; - if (null != findMethod(proxy.getClass(), "getOptionAliases", - new Class[] {})) { - h = (Hashtable) callMethod0(proxy, "getOptionAliases"); - } - return processArgs(proxy, args, args0, null, h); - } - - public static boolean processArgs(Object proxy, String args[], - String args0[], String args1[], Hashtable aliases) throws Exception { - for (int i = 0; i < args.length; i++) { - String arg = args[i]; - if (arg.startsWith("-")) - arg = arg.substring(1); - if (aliases != null && aliases.get(arg) != null) - arg = (String) aliases.get(arg); - - if (args0 != null) { - boolean set = false; - for (int j = 0; j < args0.length; j++) { - if (args0[j].equalsIgnoreCase(arg)) { - setProperty(proxy, args0[j], "true"); - set = true; - break; - } - } - if (set) - continue; - } - if (args1 != null) { - for (int j = 0; j < args1.length; j++) { - if (args1[j].equalsIgnoreCase(arg)) { - i++; - if (i >= args.length) - return false; - setProperty(proxy, arg, args[i]); - break; - } - } - } else { - // if args1 is not specified,assume all other options have param - i++; - if (i >= args.length) - return false; - setProperty(proxy, arg, args[i]); - } - - } - return true; - } - - // -------------------- other utils -------------------- - public static void clear() { - objectMethods.clear(); - } - - public static String[] findVoidSetters(Class c) { - Method m[] = findMethods(c); - if (m == null) - return null; - Vector v = new Vector(); - for (int i = 0; i < m.length; i++) { - if (m[i].getName().startsWith("set") - && m[i].getParameterTypes().length == 0) { - String arg = m[i].getName().substring(3); - v.addElement(unCapitalize(arg)); - } - } - String s[] = new String[v.size()]; - for (int i = 0; i < s.length; i++) { - s[i] = (String) v.elementAt(i); - } - return s; - } - - public static String[] findBooleanSetters(Class c) { - Method m[] = findMethods(c); - if (m == null) - return null; - Vector v = new Vector(); - for (int i = 0; i < m.length; i++) { - if (m[i].getName().startsWith("set") - && m[i].getParameterTypes().length == 1 - && "boolean".equalsIgnoreCase(m[i].getParameterTypes()[0] - .getName())) { - String arg = m[i].getName().substring(3); - v.addElement(unCapitalize(arg)); - } - } - String s[] = new String[v.size()]; - for (int i = 0; i < s.length; i++) { - s[i] = (String) v.elementAt(i); - } - return s; - } - - static Hashtable objectMethods = new Hashtable(); - - public static Method[] findMethods(Class c) { - Method methods[] = (Method[]) objectMethods.get(c); - if (methods != null) - return methods; - - methods = c.getMethods(); - objectMethods.put(c, methods); - return methods; - } - - public static Method findMethod(Class c, String name, Class params[]) { - Method methods[] = findMethods(c); - if (methods == null) - return null; - for (int i = 0; i < methods.length; i++) { - if (methods[i].getName().equals(name)) { - Class methodParams[] = methods[i].getParameterTypes(); - if (methodParams == null) - if (params == null || params.length == 0) - return methods[i]; - if (params == null) - if (methodParams == null || methodParams.length == 0) - return methods[i]; - if (params.length != methodParams.length) - continue; - boolean found = true; - for (int j = 0; j < params.length; j++) { - if (params[j] != methodParams[j]) { - found = false; - break; - } - } - if (found) - return methods[i]; - } - } - return null; - } - - /** Test if the object implements a particular - * method - */ - public static boolean hasHook(Object obj, String methodN) { - try { - Method myMethods[] = findMethods(obj.getClass()); - for (int i = 0; i < myMethods.length; i++) { - if (methodN.equals(myMethods[i].getName())) { - // check if it's overriden - Class declaring = myMethods[i].getDeclaringClass(); - Class parentOfDeclaring = declaring.getSuperclass(); - // this works only if the base class doesn't extend - // another class. - - // if the method is declared in a top level class - // like BaseInterceptor parent is Object, otherwise - // parent is BaseInterceptor or an intermediate class - if (!"java.lang.Object".equals(parentOfDeclaring.getName())) { - return true; - } - } - } - } catch (Exception ex) { - ex.printStackTrace(); - } - return false; - } - - public static void callMain(Class c, String args[]) throws Exception { - Class p[] = new Class[1]; - p[0] = args.getClass(); - Method m = c.getMethod("main", p); - m.invoke(c, new Object[] { args }); - } - - public static Object callMethod1(Object target, String methodN, - Object param1, String typeParam1, ClassLoader cl) throws Exception { - if (target == null || param1 == null) { - d("Assert: Illegal params " + target + " " + param1); - } - if (dbg > 0) - d("callMethod1 " + target.getClass().getName() + " " - + param1.getClass().getName() + " " + typeParam1); - - Class params[] = new Class[1]; - if (typeParam1 == null) - params[0] = param1.getClass(); - else - params[0] = cl.loadClass(typeParam1); - Method m = findMethod(target.getClass(), methodN, params); - if (m == null) - throw new NoSuchMethodException(target.getClass().getName() + " " - + methodN); - return m.invoke(target, new Object[] { param1 }); - } - - public static Object callMethod0(Object target, String methodN) - throws Exception { - if (target == null) { - d("Assert: Illegal params " + target); - return null; - } - if (dbg > 0) - d("callMethod0 " + target.getClass().getName() + "." + methodN); - - Class params[] = new Class[0]; - Method m = findMethod(target.getClass(), methodN, params); - if (m == null) - throw new NoSuchMethodException(target.getClass().getName() + " " - + methodN); - return m.invoke(target, emptyArray); - } - - static Object[] emptyArray = new Object[] {}; - - public static Object callMethodN(Object target, String methodN, - Object params[], Class typeParams[]) throws Exception { - Method m = null; - m = findMethod(target.getClass(), methodN, typeParams); - if (m == null) { - d("Can't find method " + methodN + " in " + target + " CLASS " - + target.getClass()); - return null; - } - Object o = m.invoke(target, params); - - if (dbg > 0) { - // debug - StringBuffer sb = new StringBuffer(); - sb.append("" + target.getClass().getName() + "." + methodN + "( "); - for (int i = 0; i < params.length; i++) { - if (i > 0) - sb.append(", "); - sb.append(params[i]); - } - sb.append(")"); - d(sb.toString()); - } - return o; - } - - public static Object convert(String object, Class paramType) { - Object result = null; - if ("java.lang.String".equals(paramType.getName())) { - result = object; - } else if ("java.lang.Integer".equals(paramType.getName()) - || "int".equals(paramType.getName())) { - try { - result = new Integer(object); - } catch (NumberFormatException ex) { - } - // Try a setFoo ( boolean ) - } else if ("java.lang.Boolean".equals(paramType.getName()) - || "boolean".equals(paramType.getName())) { - result = new Boolean(object); - - // Try a setFoo ( InetAddress ) - } else if ("java.net.InetAddress".equals(paramType - .getName())) { - try { - result = InetAddress.getByName(object); - } catch (UnknownHostException exc) { - d("Unable to resolve host name:" + object); - } - - // Unknown type - } else { - d("Unknown type " + paramType.getName()); - } - if (result == null) { - throw new IllegalArgumentException("Can't convert argument: " + object); - } - return result; - } - - // -------------------- Get property -------------------- - // This provides a layer of abstraction - - public static interface PropertySource { - - public String getProperty(String key); - - } - - public static interface AttributeHolder { - - public void setAttribute(String key, Object o); - - } - - // debug -------------------- - static final int dbg = 0; - - static void d(String s) { - if (log.isDebugEnabled()) - log.debug("IntrospectionUtils: " + s); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.Hashtable; +import java.util.StringTokenizer; +import java.util.Vector; + +// Depends: JDK1.1 + +/** + * Utils for introspection and reflection + */ +public final class IntrospectionUtils { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( IntrospectionUtils.class ); + + /** + * Call execute() - any ant-like task should work + */ + public static void execute(Object proxy, String method) throws Exception { + Method executeM = null; + Class c = proxy.getClass(); + Class params[] = new Class[0]; + // params[0]=args.getClass(); + executeM = findMethod(c, method, params); + if (executeM == null) { + throw new RuntimeException("No execute in " + proxy.getClass()); + } + executeM.invoke(proxy, (Object[]) null);//new Object[] { args }); + } + + /** + * Call void setAttribute( String ,Object ) + */ + public static void setAttribute(Object proxy, String n, Object v) + throws Exception { + if (proxy instanceof AttributeHolder) { + ((AttributeHolder) proxy).setAttribute(n, v); + return; + } + + Method executeM = null; + Class c = proxy.getClass(); + Class params[] = new Class[2]; + params[0] = String.class; + params[1] = Object.class; + executeM = findMethod(c, "setAttribute", params); + if (executeM == null) { + if (log.isDebugEnabled()) + log.debug("No setAttribute in " + proxy.getClass()); + return; + } + if (false) + if (log.isDebugEnabled()) + log.debug("Setting " + n + "=" + v + " in " + proxy); + executeM.invoke(proxy, new Object[] { n, v }); + return; + } + + /** + * Call void getAttribute( String ) + */ + public static Object getAttribute(Object proxy, String n) throws Exception { + Method executeM = null; + Class c = proxy.getClass(); + Class params[] = new Class[1]; + params[0] = String.class; + executeM = findMethod(c, "getAttribute", params); + if (executeM == null) { + if (log.isDebugEnabled()) + log.debug("No getAttribute in " + proxy.getClass()); + return null; + } + return executeM.invoke(proxy, new Object[] { n }); + } + + /** + * Construct a URLClassLoader. Will compile and work in JDK1.1 too. + */ + public static ClassLoader getURLClassLoader(URL urls[], ClassLoader parent) { + try { + Class urlCL = Class.forName("java.net.URLClassLoader"); + Class paramT[] = new Class[2]; + paramT[0] = urls.getClass(); + paramT[1] = ClassLoader.class; + Method m = findMethod(urlCL, "newInstance", paramT); + if (m == null) + return null; + + ClassLoader cl = (ClassLoader) m.invoke(urlCL, new Object[] { urls, + parent }); + return cl; + } catch (ClassNotFoundException ex) { + // jdk1.1 + return null; + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + public static String guessInstall(String installSysProp, + String homeSysProp, String jarName) { + return guessInstall(installSysProp, homeSysProp, jarName, null); + } + + /** + * Guess a product install/home by analyzing the class path. It works for + * product using the pattern: lib/executable.jar or if executable.jar is + * included in classpath by a shell script. ( java -jar also works ) + * + * Insures both "install" and "home" System properties are set. If either or + * both System properties are unset, "install" and "home" will be set to the + * same value. This value will be the other System property that is set, or + * the guessed value if neither is set. + */ + public static String guessInstall(String installSysProp, + String homeSysProp, String jarName, String classFile) { + String install = null; + String home = null; + + if (installSysProp != null) + install = System.getProperty(installSysProp); + + if (homeSysProp != null) + home = System.getProperty(homeSysProp); + + if (install != null) { + if (home == null) + System.getProperties().put(homeSysProp, install); + return install; + } + + // Find the directory where jarName.jar is located + + String cpath = System.getProperty("java.class.path"); + String pathSep = System.getProperty("path.separator"); + StringTokenizer st = new StringTokenizer(cpath, pathSep); + while (st.hasMoreTokens()) { + String path = st.nextToken(); + // log( "path " + path ); + if (path.endsWith(jarName)) { + home = path.substring(0, path.length() - jarName.length()); + try { + if ("".equals(home)) { + home = new File("./").getCanonicalPath(); + } else if (home.endsWith(File.separator)) { + home = home.substring(0, home.length() - 1); + } + File f = new File(home); + String parentDir = f.getParent(); + if (parentDir == null) + parentDir = home; // unix style + File f1 = new File(parentDir); + install = f1.getCanonicalPath(); + if (installSysProp != null) + System.getProperties().put(installSysProp, install); + if (home == null && homeSysProp != null) + System.getProperties().put(homeSysProp, install); + return install; + } catch (Exception ex) { + ex.printStackTrace(); + } + } else { + String fname = path + (path.endsWith("/") ? "" : "/") + + classFile; + if (new File(fname).exists()) { + try { + File f = new File(path); + String parentDir = f.getParent(); + if (parentDir == null) + parentDir = path; // unix style + File f1 = new File(parentDir); + install = f1.getCanonicalPath(); + if (installSysProp != null) + System.getProperties().put(installSysProp, install); + if (home == null && homeSysProp != null) + System.getProperties().put(homeSysProp, install); + return install; + } catch (Exception ex) { + ex.printStackTrace(); + } + } + } + } + + // if install directory can't be found, use home as the default + if (home != null) { + System.getProperties().put(installSysProp, home); + return home; + } + + return null; + } + + /** + * Debug method, display the classpath + */ + public static void displayClassPath(String msg, URL[] cp) { + if (log.isDebugEnabled()) { + log.debug(msg); + for (int i = 0; i < cp.length; i++) { + log.debug(cp[i].getFile()); + } + } + } + + public static String PATH_SEPARATOR = System.getProperty("path.separator"); + + /** + * Adds classpath entries from a vector of URL's to the "tc_path_add" System + * property. This System property lists the classpath entries common to web + * applications. This System property is currently used by Jasper when its + * JSP servlet compiles the Java file for a JSP. + */ + public static String classPathAdd(URL urls[], String cp) { + if (urls == null) + return cp; + + for (int i = 0; i < urls.length; i++) { + if (cp != null) + cp += PATH_SEPARATOR + urls[i].getFile(); + else + cp = urls[i].getFile(); + } + return cp; + } + + /** + * Find a method with the right name If found, call the method ( if param is + * int or boolean we'll convert value to the right type before) - that means + * you can have setDebug(1). + */ + public static void setProperty(Object o, String name, String value) { + if (dbg > 1) + d("setProperty(" + o.getClass() + " " + name + "=" + value + ")"); + + String setter = "set" + capitalize(name); + + try { + Method methods[] = findMethods(o.getClass()); + Method setPropertyMethod = null; + + // First, the ideal case - a setFoo( String ) method + for (int i = 0; i < methods.length; i++) { + Class paramT[] = methods[i].getParameterTypes(); + if (setter.equals(methods[i].getName()) && paramT.length == 1 + && "java.lang.String".equals(paramT[0].getName())) { + + methods[i].invoke(o, new Object[] { value }); + return; + } + } + + // Try a setFoo ( int ) or ( boolean ) + for (int i = 0; i < methods.length; i++) { + boolean ok = true; + if (setter.equals(methods[i].getName()) + && methods[i].getParameterTypes().length == 1) { + + // match - find the type and invoke it + Class paramType = methods[i].getParameterTypes()[0]; + Object params[] = new Object[1]; + + // Try a setFoo ( int ) + if ("java.lang.Integer".equals(paramType.getName()) + || "int".equals(paramType.getName())) { + try { + params[0] = new Integer(value); + } catch (NumberFormatException ex) { + ok = false; + } + // Try a setFoo ( long ) + }else if ("java.lang.Long".equals(paramType.getName()) + || "long".equals(paramType.getName())) { + try { + params[0] = new Long(value); + } catch (NumberFormatException ex) { + ok = false; + } + + // Try a setFoo ( boolean ) + } else if ("java.lang.Boolean".equals(paramType.getName()) + || "boolean".equals(paramType.getName())) { + params[0] = new Boolean(value); + + // Try a setFoo ( InetAddress ) + } else if ("java.net.InetAddress".equals(paramType + .getName())) { + try { + params[0] = InetAddress.getByName(value); + } catch (UnknownHostException exc) { + d("Unable to resolve host name:" + value); + ok = false; + } + + // Unknown type + } else { + d("Unknown type " + paramType.getName()); + } + + if (ok) { + methods[i].invoke(o, params); + return; + } + } + + // save "setProperty" for later + if ("setProperty".equals(methods[i].getName())) { + setPropertyMethod = methods[i]; + } + } + + // Ok, no setXXX found, try a setProperty("name", "value") + if (setPropertyMethod != null) { + Object params[] = new Object[2]; + params[0] = name; + params[1] = value; + setPropertyMethod.invoke(o, params); + } + + } catch (IllegalArgumentException ex2) { + log.warn("IAE " + o + " " + name + " " + value, ex2); + } catch (SecurityException ex1) { + if (dbg > 0) + d("SecurityException for " + o.getClass() + " " + name + "=" + + value + ")"); + if (dbg > 1) + ex1.printStackTrace(); + } catch (IllegalAccessException iae) { + if (dbg > 0) + d("IllegalAccessException for " + o.getClass() + " " + name + + "=" + value + ")"); + if (dbg > 1) + iae.printStackTrace(); + } catch (InvocationTargetException ie) { + if (dbg > 0) + d("InvocationTargetException for " + o.getClass() + " " + name + + "=" + value + ")"); + if (dbg > 1) + ie.printStackTrace(); + } + } + + public static Object getProperty(Object o, String name) { + String getter = "get" + capitalize(name); + String isGetter = "is" + capitalize(name); + + try { + Method methods[] = findMethods(o.getClass()); + Method getPropertyMethod = null; + + // First, the ideal case - a getFoo() method + for (int i = 0; i < methods.length; i++) { + Class paramT[] = methods[i].getParameterTypes(); + if (getter.equals(methods[i].getName()) && paramT.length == 0) { + return methods[i].invoke(o, (Object[]) null); + } + if (isGetter.equals(methods[i].getName()) && paramT.length == 0) { + return methods[i].invoke(o, (Object[]) null); + } + + if ("getProperty".equals(methods[i].getName())) { + getPropertyMethod = methods[i]; + } + } + + // Ok, no setXXX found, try a getProperty("name") + if (getPropertyMethod != null) { + Object params[] = new Object[1]; + params[0] = name; + return getPropertyMethod.invoke(o, params); + } + + } catch (IllegalArgumentException ex2) { + log.warn("IAE " + o + " " + name, ex2); + } catch (SecurityException ex1) { + if (dbg > 0) + d("SecurityException for " + o.getClass() + " " + name + ")"); + if (dbg > 1) + ex1.printStackTrace(); + } catch (IllegalAccessException iae) { + if (dbg > 0) + d("IllegalAccessException for " + o.getClass() + " " + name + + ")"); + if (dbg > 1) + iae.printStackTrace(); + } catch (InvocationTargetException ie) { + if (dbg > 0) + d("InvocationTargetException for " + o.getClass() + " " + name + + ")"); + if (dbg > 1) + ie.printStackTrace(); + } + return null; + } + + /** + */ + public static void setProperty(Object o, String name) { + String setter = "set" + capitalize(name); + try { + Method methods[] = findMethods(o.getClass()); + Method setPropertyMethod = null; + // find setFoo() method + for (int i = 0; i < methods.length; i++) { + Class paramT[] = methods[i].getParameterTypes(); + if (setter.equals(methods[i].getName()) && paramT.length == 0) { + methods[i].invoke(o, new Object[] {}); + return; + } + } + } catch (Exception ex1) { + if (dbg > 0) + d("Exception for " + o.getClass() + " " + name); + if (dbg > 1) + ex1.printStackTrace(); + } + } + + /** + * Replace ${NAME} with the property value + * + * @deprecated Use the explicit method + */ + public static String replaceProperties(String value, Object getter) { + if (getter instanceof Hashtable) + return replaceProperties(value, (Hashtable) getter, null); + + if (getter instanceof PropertySource) { + PropertySource src[] = new PropertySource[] { (PropertySource) getter }; + return replaceProperties(value, null, src); + } + return value; + } + + /** + * Replace ${NAME} with the property value + */ + public static String replaceProperties(String value, Hashtable staticProp, + PropertySource dynamicProp[]) { + StringBuffer sb = new StringBuffer(); + int prev = 0; + // assert value!=nil + int pos; + while ((pos = value.indexOf("$", prev)) >= 0) { + if (pos > 0) { + sb.append(value.substring(prev, pos)); + } + if (pos == (value.length() - 1)) { + sb.append('$'); + prev = pos + 1; + } else if (value.charAt(pos + 1) != '{') { + sb.append('$'); + prev = pos + 1; // XXX + } else { + int endName = value.indexOf('}', pos); + if (endName < 0) { + sb.append(value.substring(pos)); + prev = value.length(); + continue; + } + String n = value.substring(pos + 2, endName); + String v = null; + if (staticProp != null) { + v = (String) ((Hashtable) staticProp).get(n); + } + if (v == null && dynamicProp != null) { + for (int i = 0; i < dynamicProp.length; i++) { + v = dynamicProp[i].getProperty(n); + if (v != null) { + break; + } + } + } + if (v == null) + v = "${" + n + "}"; + + sb.append(v); + prev = endName + 1; + } + } + if (prev < value.length()) + sb.append(value.substring(prev)); + return sb.toString(); + } + + /** + * Reverse of Introspector.decapitalize + */ + public static String capitalize(String name) { + if (name == null || name.length() == 0) { + return name; + } + char chars[] = name.toCharArray(); + chars[0] = Character.toUpperCase(chars[0]); + return new String(chars); + } + + public static String unCapitalize(String name) { + if (name == null || name.length() == 0) { + return name; + } + char chars[] = name.toCharArray(); + chars[0] = Character.toLowerCase(chars[0]); + return new String(chars); + } + + // -------------------- Class path tools -------------------- + + /** + * Add all the jar files in a dir to the classpath, represented as a Vector + * of URLs. + */ + public static void addToClassPath(Vector cpV, String dir) { + try { + String cpComp[] = getFilesByExt(dir, ".jar"); + if (cpComp != null) { + int jarCount = cpComp.length; + for (int i = 0; i < jarCount; i++) { + URL url = getURL(dir, cpComp[i]); + if (url != null) + cpV.addElement(url); + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + } + + public static void addToolsJar(Vector v) { + try { + // Add tools.jar in any case + File f = new File(System.getProperty("java.home") + + "/../lib/tools.jar"); + + if (!f.exists()) { + // On some systems java.home gets set to the root of jdk. + // That's a bug, but we can work around and be nice. + f = new File(System.getProperty("java.home") + "/lib/tools.jar"); + if (f.exists()) { + if (log.isDebugEnabled()) + log.debug("Detected strange java.home value " + + System.getProperty("java.home") + + ", it should point to jre"); + } + } + URL url = new URL("file", "", f.getAbsolutePath()); + + v.addElement(url); + } catch (MalformedURLException ex) { + ex.printStackTrace(); + } + } + + /** + * Return all files with a given extension in a dir + */ + public static String[] getFilesByExt(String ld, String ext) { + File dir = new File(ld); + String[] names = null; + final String lext = ext; + if (dir.isDirectory()) { + names = dir.list(new FilenameFilter() { + public boolean accept(File d, String name) { + if (name.endsWith(lext)) { + return true; + } + return false; + } + }); + } + return names; + } + + /** + * Construct a file url from a file, using a base dir + */ + public static URL getURL(String base, String file) { + try { + File baseF = new File(base); + File f = new File(baseF, file); + String path = f.getCanonicalPath(); + if (f.isDirectory()) { + path += "/"; + } + if (!f.exists()) + return null; + return new URL("file", "", path); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + /** + * Add elements from the classpath cp to a Vector jars as + * file URLs (We use Vector for JDK 1.1 compat). + *

        + * + * @param jars The jar list + * @param cp a String classpath of directory or jar file elements + * separated by path.separator delimiters. + * @throws IOException If an I/O error occurs + * @throws MalformedURLException Doh ;) + */ + public static void addJarsFromClassPath(Vector jars, String cp) + throws IOException, MalformedURLException { + String sep = System.getProperty("path.separator"); + String token; + StringTokenizer st; + if (cp != null) { + st = new StringTokenizer(cp, sep); + while (st.hasMoreTokens()) { + File f = new File(st.nextToken()); + String path = f.getCanonicalPath(); + if (f.isDirectory()) { + path += "/"; + } + URL url = new URL("file", "", path); + if (!jars.contains(url)) { + jars.addElement(url); + } + } + } + } + + /** + * Return a URL[] that can be used to construct a class loader + */ + public static URL[] getClassPath(Vector v) { + URL[] urls = new URL[v.size()]; + for (int i = 0; i < v.size(); i++) { + urls[i] = (URL) v.elementAt(i); + } + return urls; + } + + /** + * Construct a URL classpath from files in a directory, a cpath property, + * and tools.jar. + */ + public static URL[] getClassPath(String dir, String cpath, + String cpathProp, boolean addTools) throws IOException, + MalformedURLException { + Vector jarsV = new Vector(); + if (dir != null) { + // Add dir/classes first, if it exists + URL url = getURL(dir, "classes"); + if (url != null) + jarsV.addElement(url); + addToClassPath(jarsV, dir); + } + + if (cpath != null) + addJarsFromClassPath(jarsV, cpath); + + if (cpathProp != null) { + String cpath1 = System.getProperty(cpathProp); + addJarsFromClassPath(jarsV, cpath1); + } + + if (addTools) + addToolsJar(jarsV); + + return getClassPath(jarsV); + } + + // -------------------- Mapping command line params to setters + + public static boolean processArgs(Object proxy, String args[]) + throws Exception { + String args0[] = null; + if (null != findMethod(proxy.getClass(), "getOptions1", new Class[] {})) { + args0 = (String[]) callMethod0(proxy, "getOptions1"); + } + + if (args0 == null) { + //args0=findVoidSetters(proxy.getClass()); + args0 = findBooleanSetters(proxy.getClass()); + } + Hashtable h = null; + if (null != findMethod(proxy.getClass(), "getOptionAliases", + new Class[] {})) { + h = (Hashtable) callMethod0(proxy, "getOptionAliases"); + } + return processArgs(proxy, args, args0, null, h); + } + + public static boolean processArgs(Object proxy, String args[], + String args0[], String args1[], Hashtable aliases) throws Exception { + for (int i = 0; i < args.length; i++) { + String arg = args[i]; + if (arg.startsWith("-")) + arg = arg.substring(1); + if (aliases != null && aliases.get(arg) != null) + arg = (String) aliases.get(arg); + + if (args0 != null) { + boolean set = false; + for (int j = 0; j < args0.length; j++) { + if (args0[j].equalsIgnoreCase(arg)) { + setProperty(proxy, args0[j], "true"); + set = true; + break; + } + } + if (set) + continue; + } + if (args1 != null) { + for (int j = 0; j < args1.length; j++) { + if (args1[j].equalsIgnoreCase(arg)) { + i++; + if (i >= args.length) + return false; + setProperty(proxy, arg, args[i]); + break; + } + } + } else { + // if args1 is not specified,assume all other options have param + i++; + if (i >= args.length) + return false; + setProperty(proxy, arg, args[i]); + } + + } + return true; + } + + // -------------------- other utils -------------------- + public static void clear() { + objectMethods.clear(); + } + + public static String[] findVoidSetters(Class c) { + Method m[] = findMethods(c); + if (m == null) + return null; + Vector v = new Vector(); + for (int i = 0; i < m.length; i++) { + if (m[i].getName().startsWith("set") + && m[i].getParameterTypes().length == 0) { + String arg = m[i].getName().substring(3); + v.addElement(unCapitalize(arg)); + } + } + String s[] = new String[v.size()]; + for (int i = 0; i < s.length; i++) { + s[i] = (String) v.elementAt(i); + } + return s; + } + + public static String[] findBooleanSetters(Class c) { + Method m[] = findMethods(c); + if (m == null) + return null; + Vector v = new Vector(); + for (int i = 0; i < m.length; i++) { + if (m[i].getName().startsWith("set") + && m[i].getParameterTypes().length == 1 + && "boolean".equalsIgnoreCase(m[i].getParameterTypes()[0] + .getName())) { + String arg = m[i].getName().substring(3); + v.addElement(unCapitalize(arg)); + } + } + String s[] = new String[v.size()]; + for (int i = 0; i < s.length; i++) { + s[i] = (String) v.elementAt(i); + } + return s; + } + + static Hashtable objectMethods = new Hashtable(); + + public static Method[] findMethods(Class c) { + Method methods[] = (Method[]) objectMethods.get(c); + if (methods != null) + return methods; + + methods = c.getMethods(); + objectMethods.put(c, methods); + return methods; + } + + public static Method findMethod(Class c, String name, Class params[]) { + Method methods[] = findMethods(c); + if (methods == null) + return null; + for (int i = 0; i < methods.length; i++) { + if (methods[i].getName().equals(name)) { + Class methodParams[] = methods[i].getParameterTypes(); + if (methodParams == null) + if (params == null || params.length == 0) + return methods[i]; + if (params == null) + if (methodParams == null || methodParams.length == 0) + return methods[i]; + if (params.length != methodParams.length) + continue; + boolean found = true; + for (int j = 0; j < params.length; j++) { + if (params[j] != methodParams[j]) { + found = false; + break; + } + } + if (found) + return methods[i]; + } + } + return null; + } + + /** Test if the object implements a particular + * method + */ + public static boolean hasHook(Object obj, String methodN) { + try { + Method myMethods[] = findMethods(obj.getClass()); + for (int i = 0; i < myMethods.length; i++) { + if (methodN.equals(myMethods[i].getName())) { + // check if it's overriden + Class declaring = myMethods[i].getDeclaringClass(); + Class parentOfDeclaring = declaring.getSuperclass(); + // this works only if the base class doesn't extend + // another class. + + // if the method is declared in a top level class + // like BaseInterceptor parent is Object, otherwise + // parent is BaseInterceptor or an intermediate class + if (!"java.lang.Object".equals(parentOfDeclaring.getName())) { + return true; + } + } + } + } catch (Exception ex) { + ex.printStackTrace(); + } + return false; + } + + public static void callMain(Class c, String args[]) throws Exception { + Class p[] = new Class[1]; + p[0] = args.getClass(); + Method m = c.getMethod("main", p); + m.invoke(c, new Object[] { args }); + } + + public static Object callMethod1(Object target, String methodN, + Object param1, String typeParam1, ClassLoader cl) throws Exception { + if (target == null || param1 == null) { + d("Assert: Illegal params " + target + " " + param1); + } + if (dbg > 0) + d("callMethod1 " + target.getClass().getName() + " " + + param1.getClass().getName() + " " + typeParam1); + + Class params[] = new Class[1]; + if (typeParam1 == null) + params[0] = param1.getClass(); + else + params[0] = cl.loadClass(typeParam1); + Method m = findMethod(target.getClass(), methodN, params); + if (m == null) + throw new NoSuchMethodException(target.getClass().getName() + " " + + methodN); + return m.invoke(target, new Object[] { param1 }); + } + + public static Object callMethod0(Object target, String methodN) + throws Exception { + if (target == null) { + d("Assert: Illegal params " + target); + return null; + } + if (dbg > 0) + d("callMethod0 " + target.getClass().getName() + "." + methodN); + + Class params[] = new Class[0]; + Method m = findMethod(target.getClass(), methodN, params); + if (m == null) + throw new NoSuchMethodException(target.getClass().getName() + " " + + methodN); + return m.invoke(target, emptyArray); + } + + static Object[] emptyArray = new Object[] {}; + + public static Object callMethodN(Object target, String methodN, + Object params[], Class typeParams[]) throws Exception { + Method m = null; + m = findMethod(target.getClass(), methodN, typeParams); + if (m == null) { + d("Can't find method " + methodN + " in " + target + " CLASS " + + target.getClass()); + return null; + } + Object o = m.invoke(target, params); + + if (dbg > 0) { + // debug + StringBuffer sb = new StringBuffer(); + sb.append("" + target.getClass().getName() + "." + methodN + "( "); + for (int i = 0; i < params.length; i++) { + if (i > 0) + sb.append(", "); + sb.append(params[i]); + } + sb.append(")"); + d(sb.toString()); + } + return o; + } + + public static Object convert(String object, Class paramType) { + Object result = null; + if ("java.lang.String".equals(paramType.getName())) { + result = object; + } else if ("java.lang.Integer".equals(paramType.getName()) + || "int".equals(paramType.getName())) { + try { + result = new Integer(object); + } catch (NumberFormatException ex) { + } + // Try a setFoo ( boolean ) + } else if ("java.lang.Boolean".equals(paramType.getName()) + || "boolean".equals(paramType.getName())) { + result = new Boolean(object); + + // Try a setFoo ( InetAddress ) + } else if ("java.net.InetAddress".equals(paramType + .getName())) { + try { + result = InetAddress.getByName(object); + } catch (UnknownHostException exc) { + d("Unable to resolve host name:" + object); + } + + // Unknown type + } else { + d("Unknown type " + paramType.getName()); + } + if (result == null) { + throw new IllegalArgumentException("Can't convert argument: " + object); + } + return result; + } + + // -------------------- Get property -------------------- + // This provides a layer of abstraction + + public static interface PropertySource { + + public String getProperty(String key); + + } + + public static interface AttributeHolder { + + public void setAttribute(String key, Object o); + + } + + // debug -------------------- + static final int dbg = 0; + + static void d(String s) { + if (log.isDebugEnabled()) + log.debug("IntrospectionUtils: " + s); + } +} diff --git a/java/org/apache/tomcat/util/buf/Ascii.java b/java/org/apache/tomcat/util/buf/Ascii.java index c93dd588a..1c6750eef 100644 --- a/java/org/apache/tomcat/util/buf/Ascii.java +++ b/java/org/apache/tomcat/util/buf/Ascii.java @@ -1,246 +1,246 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -/** - * This class implements some basic ASCII character handling functions. - * - * @author dac@eng.sun.com - * @author James Todd [gonzo@eng.sun.com] - */ -public final class Ascii { - /* - * Character translation tables. - */ - - private static final byte[] toUpper = new byte[256]; - private static final byte[] toLower = new byte[256]; - - /* - * Character type tables. - */ - - private static final boolean[] isAlpha = new boolean[256]; - private static final boolean[] isUpper = new boolean[256]; - private static final boolean[] isLower = new boolean[256]; - private static final boolean[] isWhite = new boolean[256]; - private static final boolean[] isDigit = new boolean[256]; - - /* - * Initialize character translation and type tables. - */ - - static { - for (int i = 0; i < 256; i++) { - toUpper[i] = (byte)i; - toLower[i] = (byte)i; - } - - for (int lc = 'a'; lc <= 'z'; lc++) { - int uc = lc + 'A' - 'a'; - - toUpper[lc] = (byte)uc; - toLower[uc] = (byte)lc; - isAlpha[lc] = true; - isAlpha[uc] = true; - isLower[lc] = true; - isUpper[uc] = true; - } - - isWhite[ ' '] = true; - isWhite['\t'] = true; - isWhite['\r'] = true; - isWhite['\n'] = true; - isWhite['\f'] = true; - isWhite['\b'] = true; - - for (int d = '0'; d <= '9'; d++) { - isDigit[d] = true; - } - } - - /** - * Returns the upper case equivalent of the specified ASCII character. - */ - - public static int toUpper(int c) { - return toUpper[c & 0xff] & 0xff; - } - - /** - * Returns the lower case equivalent of the specified ASCII character. - */ - - public static int toLower(int c) { - return toLower[c & 0xff] & 0xff; - } - - /** - * Returns true if the specified ASCII character is upper or lower case. - */ - - public static boolean isAlpha(int c) { - return isAlpha[c & 0xff]; - } - - /** - * Returns true if the specified ASCII character is upper case. - */ - - public static boolean isUpper(int c) { - return isUpper[c & 0xff]; - } - - /** - * Returns true if the specified ASCII character is lower case. - */ - - public static boolean isLower(int c) { - return isLower[c & 0xff]; - } - - /** - * Returns true if the specified ASCII character is white space. - */ - - public static boolean isWhite(int c) { - return isWhite[c & 0xff]; - } - - /** - * Returns true if the specified ASCII character is a digit. - */ - - public static boolean isDigit(int c) { - return isDigit[c & 0xff]; - } - - /** - * Parses an unsigned integer from the specified subarray of bytes. - * @param b the bytes to parse - * @param off the start offset of the bytes - * @param len the length of the bytes - * @exception NumberFormatException if the integer format was invalid - */ - public static int parseInt(byte[] b, int off, int len) - throws NumberFormatException - { - int c; - - if (b == null || len <= 0 || !isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - - int n = c - '0'; - - while (--len > 0) { - if (!isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - n = n * 10 + c - '0'; - } - - return n; - } - - public static int parseInt(char[] b, int off, int len) - throws NumberFormatException - { - int c; - - if (b == null || len <= 0 || !isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - - int n = c - '0'; - - while (--len > 0) { - if (!isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - n = n * 10 + c - '0'; - } - - return n; - } - - /** - * Parses an unsigned long from the specified subarray of bytes. - * @param b the bytes to parse - * @param off the start offset of the bytes - * @param len the length of the bytes - * @exception NumberFormatException if the long format was invalid - */ - public static long parseLong(byte[] b, int off, int len) - throws NumberFormatException - { - int c; - - if (b == null || len <= 0 || !isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - - long n = c - '0'; - long m; - - while (--len > 0) { - if (!isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - m = n * 10 + c - '0'; - - if (m < n) { - // Overflow - throw new NumberFormatException(); - } else { - n = m; - } - } - - return n; - } - - public static long parseLong(char[] b, int off, int len) - throws NumberFormatException - { - int c; - - if (b == null || len <= 0 || !isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - - long n = c - '0'; - long m; - - while (--len > 0) { - if (!isDigit(c = b[off++])) { - throw new NumberFormatException(); - } - m = n * 10 + c - '0'; - - if (m < n) { - // Overflow - throw new NumberFormatException(); - } else { - n = m; - } - } - - return n; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +/** + * This class implements some basic ASCII character handling functions. + * + * @author dac@eng.sun.com + * @author James Todd [gonzo@eng.sun.com] + */ +public final class Ascii { + /* + * Character translation tables. + */ + + private static final byte[] toUpper = new byte[256]; + private static final byte[] toLower = new byte[256]; + + /* + * Character type tables. + */ + + private static final boolean[] isAlpha = new boolean[256]; + private static final boolean[] isUpper = new boolean[256]; + private static final boolean[] isLower = new boolean[256]; + private static final boolean[] isWhite = new boolean[256]; + private static final boolean[] isDigit = new boolean[256]; + + /* + * Initialize character translation and type tables. + */ + + static { + for (int i = 0; i < 256; i++) { + toUpper[i] = (byte)i; + toLower[i] = (byte)i; + } + + for (int lc = 'a'; lc <= 'z'; lc++) { + int uc = lc + 'A' - 'a'; + + toUpper[lc] = (byte)uc; + toLower[uc] = (byte)lc; + isAlpha[lc] = true; + isAlpha[uc] = true; + isLower[lc] = true; + isUpper[uc] = true; + } + + isWhite[ ' '] = true; + isWhite['\t'] = true; + isWhite['\r'] = true; + isWhite['\n'] = true; + isWhite['\f'] = true; + isWhite['\b'] = true; + + for (int d = '0'; d <= '9'; d++) { + isDigit[d] = true; + } + } + + /** + * Returns the upper case equivalent of the specified ASCII character. + */ + + public static int toUpper(int c) { + return toUpper[c & 0xff] & 0xff; + } + + /** + * Returns the lower case equivalent of the specified ASCII character. + */ + + public static int toLower(int c) { + return toLower[c & 0xff] & 0xff; + } + + /** + * Returns true if the specified ASCII character is upper or lower case. + */ + + public static boolean isAlpha(int c) { + return isAlpha[c & 0xff]; + } + + /** + * Returns true if the specified ASCII character is upper case. + */ + + public static boolean isUpper(int c) { + return isUpper[c & 0xff]; + } + + /** + * Returns true if the specified ASCII character is lower case. + */ + + public static boolean isLower(int c) { + return isLower[c & 0xff]; + } + + /** + * Returns true if the specified ASCII character is white space. + */ + + public static boolean isWhite(int c) { + return isWhite[c & 0xff]; + } + + /** + * Returns true if the specified ASCII character is a digit. + */ + + public static boolean isDigit(int c) { + return isDigit[c & 0xff]; + } + + /** + * Parses an unsigned integer from the specified subarray of bytes. + * @param b the bytes to parse + * @param off the start offset of the bytes + * @param len the length of the bytes + * @exception NumberFormatException if the integer format was invalid + */ + public static int parseInt(byte[] b, int off, int len) + throws NumberFormatException + { + int c; + + if (b == null || len <= 0 || !isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + + int n = c - '0'; + + while (--len > 0) { + if (!isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + n = n * 10 + c - '0'; + } + + return n; + } + + public static int parseInt(char[] b, int off, int len) + throws NumberFormatException + { + int c; + + if (b == null || len <= 0 || !isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + + int n = c - '0'; + + while (--len > 0) { + if (!isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + n = n * 10 + c - '0'; + } + + return n; + } + + /** + * Parses an unsigned long from the specified subarray of bytes. + * @param b the bytes to parse + * @param off the start offset of the bytes + * @param len the length of the bytes + * @exception NumberFormatException if the long format was invalid + */ + public static long parseLong(byte[] b, int off, int len) + throws NumberFormatException + { + int c; + + if (b == null || len <= 0 || !isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + + long n = c - '0'; + long m; + + while (--len > 0) { + if (!isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + m = n * 10 + c - '0'; + + if (m < n) { + // Overflow + throw new NumberFormatException(); + } else { + n = m; + } + } + + return n; + } + + public static long parseLong(char[] b, int off, int len) + throws NumberFormatException + { + int c; + + if (b == null || len <= 0 || !isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + + long n = c - '0'; + long m; + + while (--len > 0) { + if (!isDigit(c = b[off++])) { + throw new NumberFormatException(); + } + m = n * 10 + c - '0'; + + if (m < n) { + // Overflow + throw new NumberFormatException(); + } else { + n = m; + } + } + + return n; + } + +} diff --git a/java/org/apache/tomcat/util/buf/B2CConverter.java b/java/org/apache/tomcat/util/buf/B2CConverter.java index 85a5b3256..dd2cb3370 100644 --- a/java/org/apache/tomcat/util/buf/B2CConverter.java +++ b/java/org/apache/tomcat/util/buf/B2CConverter.java @@ -1,273 +1,273 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.buf; - -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; - -/** Efficient conversion of bytes to character . - * - * This uses the standard JDK mechansim - a reader - but provides mechanisms - * to recycle all the objects that are used. It is compatible with JDK1.1 - * and up, - * ( nio is better, but it's not available even in 1.2 or 1.3 ) - * - * Not used in the current code, the performance gain is not very big - * in the current case ( since String is created anyway ), but it will - * be used in a later version or after the remaining optimizations. - */ -public class B2CConverter { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( B2CConverter.class ); - - private IntermediateInputStream iis; - private ReadConvertor conv; - private String encoding; - - protected B2CConverter() { - } - - /** Create a converter, with bytes going to a byte buffer - */ - public B2CConverter(String encoding) - throws IOException - { - this.encoding=encoding; - reset(); - } - - - /** Reset the internal state, empty the buffers. - * The encoding remain in effect, the internal buffers remain allocated. - */ - public void recycle() { - conv.recycle(); - } - - static final int BUFFER_SIZE=8192; - char result[]=new char[BUFFER_SIZE]; - - /** Convert a buffer of bytes into a chars - */ - public void convert( ByteChunk bb, CharChunk cb ) - throws IOException - { - // Set the ByteChunk as input to the Intermediate reader - iis.setByteChunk( bb ); - convert(cb); - } - - private void convert(CharChunk cb) - throws IOException - { - try { - // read from the reader - while( true ) { // conv.ready() ) { - int cnt=conv.read( result, 0, BUFFER_SIZE ); - if( cnt <= 0 ) { - // End of stream ! - we may be in a bad state - if( debug>0) - log( "EOF" ); - // reset(); - return; - } - if( debug > 1 ) - log("Converted: " + new String( result, 0, cnt )); - - // XXX go directly - cb.append( result, 0, cnt ); - } - } catch( IOException ex) { - if( debug>0) - log( "Reseting the converter " + ex.toString() ); - reset(); - throw ex; - } - } - - public void reset() - throws IOException - { - // destroy the reader/iis - iis=new IntermediateInputStream(); - conv=new ReadConvertor( iis, encoding ); - } - - private final int debug=0; - void log( String s ) { - if (log.isDebugEnabled()) - log.debug("B2CConverter: " + s ); - } - - // -------------------- Not used - the speed improvemnt is quite small - - /* - private Hashtable decoders; - public static final boolean useNewString=false; - public static final boolean useSpecialDecoders=true; - private UTF8Decoder utfD; - // private char[] conversionBuff; - CharChunk conversionBuf; - - - private static String decodeString(ByteChunk mb, String enc) - throws IOException - { - byte buff=mb.getBuffer(); - int start=mb.getStart(); - int end=mb.getEnd(); - if( useNewString ) { - if( enc==null) enc="UTF8"; - return new String( buff, start, end-start, enc ); - } - B2CConverter b2c=null; - if( useSpecialDecoders && - (enc==null || "UTF8".equalsIgnoreCase(enc))) { - if( utfD==null ) utfD=new UTF8Decoder(); - b2c=utfD; - } - if(decoders == null ) decoders=new Hashtable(); - if( enc==null ) enc="UTF8"; - b2c=(B2CConverter)decoders.get( enc ); - if( b2c==null ) { - if( useSpecialDecoders ) { - if( "UTF8".equalsIgnoreCase( enc ) ) { - b2c=new UTF8Decoder(); - } - } - if( b2c==null ) - b2c=new B2CConverter( enc ); - decoders.put( enc, b2c ); - } - if( conversionBuf==null ) conversionBuf=new CharChunk(1024); - - try { - conversionBuf.recycle(); - b2c.convert( this, conversionBuf ); - //System.out.println("XXX 1 " + conversionBuf ); - return conversionBuf.toString(); - } catch( IOException ex ) { - ex.printStackTrace(); - return null; - } - } - - */ -} - -// -------------------- Private implementation -------------------- - - - -/** - * - */ -final class ReadConvertor extends InputStreamReader { - // stream with flush() and close(). overriden. - private IntermediateInputStream iis; - - // Has a private, internal byte[8192] - - /** Create a converter. - */ - public ReadConvertor( IntermediateInputStream in, String enc ) - throws UnsupportedEncodingException - { - super( in, enc ); - iis=in; - } - - /** Overriden - will do nothing but reset internal state. - */ - public final void close() throws IOException { - // NOTHING - // Calling super.close() would reset out and cb. - } - - public final int read(char cbuf[], int off, int len) - throws IOException - { - // will do the conversion and call write on the output stream - return super.read( cbuf, off, len ); - } - - /** Reset the buffer - */ - public final void recycle() { - } -} - - -/** Special output stream where close() is overriden, so super.close() - is never called. - - This allows recycling. It can also be disabled, so callbacks will - not be called if recycling the converter and if data was not flushed. -*/ -final class IntermediateInputStream extends InputStream { - byte buf[]; - int pos; - int len; - int end; - - public IntermediateInputStream() { - } - - public final void close() throws IOException { - // shouldn't be called - we filter it out in writer - throw new IOException("close() called - shouldn't happen "); - } - - public final int read(byte cbuf[], int off, int len) throws IOException { - if( pos >= end ) return -1; - if (pos + len > end) { - len = end - pos; - } - if (len <= 0) { - return 0; - } - System.arraycopy(buf, pos, cbuf, off, len); - pos += len; - return len; - } - - public final int read() throws IOException { - return (pos < end ) ? (buf[pos++] & 0xff) : -1; - } - - // -------------------- Internal methods -------------------- - - void setBuffer( byte b[], int p, int l ) { - buf=b; - pos=p; - len=l; - end=pos+len; - } - - void setByteChunk( ByteChunk mb ) { - buf=mb.getBytes(); - pos=mb.getStart(); - len=mb.getLength(); - end=pos+len; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.buf; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; + +/** Efficient conversion of bytes to character . + * + * This uses the standard JDK mechansim - a reader - but provides mechanisms + * to recycle all the objects that are used. It is compatible with JDK1.1 + * and up, + * ( nio is better, but it's not available even in 1.2 or 1.3 ) + * + * Not used in the current code, the performance gain is not very big + * in the current case ( since String is created anyway ), but it will + * be used in a later version or after the remaining optimizations. + */ +public class B2CConverter { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( B2CConverter.class ); + + private IntermediateInputStream iis; + private ReadConvertor conv; + private String encoding; + + protected B2CConverter() { + } + + /** Create a converter, with bytes going to a byte buffer + */ + public B2CConverter(String encoding) + throws IOException + { + this.encoding=encoding; + reset(); + } + + + /** Reset the internal state, empty the buffers. + * The encoding remain in effect, the internal buffers remain allocated. + */ + public void recycle() { + conv.recycle(); + } + + static final int BUFFER_SIZE=8192; + char result[]=new char[BUFFER_SIZE]; + + /** Convert a buffer of bytes into a chars + */ + public void convert( ByteChunk bb, CharChunk cb ) + throws IOException + { + // Set the ByteChunk as input to the Intermediate reader + iis.setByteChunk( bb ); + convert(cb); + } + + private void convert(CharChunk cb) + throws IOException + { + try { + // read from the reader + while( true ) { // conv.ready() ) { + int cnt=conv.read( result, 0, BUFFER_SIZE ); + if( cnt <= 0 ) { + // End of stream ! - we may be in a bad state + if( debug>0) + log( "EOF" ); + // reset(); + return; + } + if( debug > 1 ) + log("Converted: " + new String( result, 0, cnt )); + + // XXX go directly + cb.append( result, 0, cnt ); + } + } catch( IOException ex) { + if( debug>0) + log( "Reseting the converter " + ex.toString() ); + reset(); + throw ex; + } + } + + public void reset() + throws IOException + { + // destroy the reader/iis + iis=new IntermediateInputStream(); + conv=new ReadConvertor( iis, encoding ); + } + + private final int debug=0; + void log( String s ) { + if (log.isDebugEnabled()) + log.debug("B2CConverter: " + s ); + } + + // -------------------- Not used - the speed improvemnt is quite small + + /* + private Hashtable decoders; + public static final boolean useNewString=false; + public static final boolean useSpecialDecoders=true; + private UTF8Decoder utfD; + // private char[] conversionBuff; + CharChunk conversionBuf; + + + private static String decodeString(ByteChunk mb, String enc) + throws IOException + { + byte buff=mb.getBuffer(); + int start=mb.getStart(); + int end=mb.getEnd(); + if( useNewString ) { + if( enc==null) enc="UTF8"; + return new String( buff, start, end-start, enc ); + } + B2CConverter b2c=null; + if( useSpecialDecoders && + (enc==null || "UTF8".equalsIgnoreCase(enc))) { + if( utfD==null ) utfD=new UTF8Decoder(); + b2c=utfD; + } + if(decoders == null ) decoders=new Hashtable(); + if( enc==null ) enc="UTF8"; + b2c=(B2CConverter)decoders.get( enc ); + if( b2c==null ) { + if( useSpecialDecoders ) { + if( "UTF8".equalsIgnoreCase( enc ) ) { + b2c=new UTF8Decoder(); + } + } + if( b2c==null ) + b2c=new B2CConverter( enc ); + decoders.put( enc, b2c ); + } + if( conversionBuf==null ) conversionBuf=new CharChunk(1024); + + try { + conversionBuf.recycle(); + b2c.convert( this, conversionBuf ); + //System.out.println("XXX 1 " + conversionBuf ); + return conversionBuf.toString(); + } catch( IOException ex ) { + ex.printStackTrace(); + return null; + } + } + + */ +} + +// -------------------- Private implementation -------------------- + + + +/** + * + */ +final class ReadConvertor extends InputStreamReader { + // stream with flush() and close(). overriden. + private IntermediateInputStream iis; + + // Has a private, internal byte[8192] + + /** Create a converter. + */ + public ReadConvertor( IntermediateInputStream in, String enc ) + throws UnsupportedEncodingException + { + super( in, enc ); + iis=in; + } + + /** Overriden - will do nothing but reset internal state. + */ + public final void close() throws IOException { + // NOTHING + // Calling super.close() would reset out and cb. + } + + public final int read(char cbuf[], int off, int len) + throws IOException + { + // will do the conversion and call write on the output stream + return super.read( cbuf, off, len ); + } + + /** Reset the buffer + */ + public final void recycle() { + } +} + + +/** Special output stream where close() is overriden, so super.close() + is never called. + + This allows recycling. It can also be disabled, so callbacks will + not be called if recycling the converter and if data was not flushed. +*/ +final class IntermediateInputStream extends InputStream { + byte buf[]; + int pos; + int len; + int end; + + public IntermediateInputStream() { + } + + public final void close() throws IOException { + // shouldn't be called - we filter it out in writer + throw new IOException("close() called - shouldn't happen "); + } + + public final int read(byte cbuf[], int off, int len) throws IOException { + if( pos >= end ) return -1; + if (pos + len > end) { + len = end - pos; + } + if (len <= 0) { + return 0; + } + System.arraycopy(buf, pos, cbuf, off, len); + pos += len; + return len; + } + + public final int read() throws IOException { + return (pos < end ) ? (buf[pos++] & 0xff) : -1; + } + + // -------------------- Internal methods -------------------- + + void setBuffer( byte b[], int p, int l ) { + buf=b; + pos=p; + len=l; + end=pos+len; + } + + void setByteChunk( ByteChunk mb ) { + buf=mb.getBytes(); + pos=mb.getStart(); + len=mb.getLength(); + end=pos+len; + } + +} diff --git a/java/org/apache/tomcat/util/buf/Base64.java b/java/org/apache/tomcat/util/buf/Base64.java index d91a75797..6a3433617 100644 --- a/java/org/apache/tomcat/util/buf/Base64.java +++ b/java/org/apache/tomcat/util/buf/Base64.java @@ -1,268 +1,268 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.buf; - - -/** - * This class provides encode/decode for RFC 2045 Base64 as - * defined by RFC 2045, N. Freed and N. Borenstein. - * RFC 2045: Multipurpose Internet Mail Extensions (MIME) - * Part One: Format of Internet Message Bodies. Reference - * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt - * This class is used by XML Schema binary format validation - * - * @author Jeffrey Rodriguez - * @version $Revision: 299789 $ $Date: 2004-09-17 20:34:19 +0200 (ven., 17 sept. 2004) $ - */ - -public final class Base64 { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( Base64.class ); - - static private final int BASELENGTH = 255; - static private final int LOOKUPLENGTH = 63; - static private final int TWENTYFOURBITGROUP = 24; - static private final int EIGHTBIT = 8; - static private final int SIXTEENBIT = 16; - static private final int SIXBIT = 6; - static private final int FOURBYTE = 4; - - - static private final byte PAD = ( byte ) '='; - static private byte [] base64Alphabet = new byte[BASELENGTH]; - static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; - - static { - - for (int i = 0; i= 'A'; i-- ) { - base64Alphabet[i] = (byte) (i-'A'); - } - for ( int i = 'z'; i>= 'a'; i--) { - base64Alphabet[i] = (byte) ( i-'a' + 26); - } - - for ( int i = '9'; i >= '0'; i--) { - base64Alphabet[i] = (byte) (i-'0' + 52); - } - - base64Alphabet['+'] = 62; - base64Alphabet['/'] = 63; - - for (int i = 0; i<=25; i++ ) - lookUpBase64Alphabet[i] = (byte) ('A'+i ); - - for (int i = 26, j = 0; i<=51; i++, j++ ) - lookUpBase64Alphabet[i] = (byte) ('a'+ j ); - - for (int i = 52, j = 0; i<=61; i++, j++ ) - lookUpBase64Alphabet[i] = (byte) ('0' + j ); - - } - - - static boolean isBase64( byte octect ) { - //shall we ignore white space? JEFF?? - return(octect == PAD || base64Alphabet[octect] != -1 ); - } - - - static boolean isArrayByteBase64( byte[] arrayOctect ) { - int length = arrayOctect.length; - if ( length == 0 ) - return false; - for ( int i=0; i < length; i++ ) { - if ( Base64.isBase64( arrayOctect[i] ) == false) - return false; - } - return true; - } - - /** - * Encodes hex octects into Base64 - * - * @param binaryData Array containing binaryData - * @return Encoded Base64 array - */ - public static byte[] encode( byte[] binaryData ) { - int lengthDataBits = binaryData.length*EIGHTBIT; - int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; - int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; - byte encodedData[] = null; - - - if ( fewerThan24bits != 0 ) //data not divisible by 24 bit - encodedData = new byte[ (numberTriplets + 1 )*4 ]; - else // 16 or 8 bit - encodedData = new byte[ numberTriplets*4 ]; - - byte k=0, l=0, b1=0,b2=0,b3=0; - - int encodedIndex = 0; - int dataIndex = 0; - int i = 0; - for ( i = 0; i>2 ]; - encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) | -( k<<4 )]; - encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | -( b3>>6)]; - encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ]; - } - - // form integral number of 6-bit groups - dataIndex = i*3; - encodedIndex = i*4; - if (fewerThan24bits == EIGHTBIT ) { - b1 = binaryData[dataIndex]; - k = (byte) ( b1 &0x03 ); - encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; - encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ]; - encodedData[encodedIndex + 2] = PAD; - encodedData[encodedIndex + 3] = PAD; - } else if ( fewerThan24bits == SIXTEENBIT ) { - - b1 = binaryData[dataIndex]; - b2 = binaryData[dataIndex +1 ]; - l = ( byte ) ( b2 &0x0f ); - k = ( byte ) ( b1 &0x03 ); - encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; - encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 ) -| ( k<<4 )]; - encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ]; - encodedData[encodedIndex + 3] = PAD; - } - return encodedData; - } - - - /** - * Decodes Base64 data into octects - * - * @param base64Data Byte array containing Base64 data - * @return Array containind decoded data. - */ - public byte[] decode( byte[] base64Data ) { - int numberQuadruple = base64Data.length/FOURBYTE; - byte decodedData[] = null; - byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0; - - // Throw away anything not in base64Data - // Adjust size - - int encodedIndex = 0; - int dataIndex = 0; - decodedData = new byte[ numberQuadruple*3 + 1 ]; - - for (int i = 0; i>4 ) ; - decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( -(b3>>2) & 0xf) ); - decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 ); - } else if ( marker0 == PAD ) { //Two PAD e.g. 3c[Pad][Pad] - decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; - decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 ); - decodedData[encodedIndex+2] = (byte) 0; - } else if ( marker1 == PAD ) { //One PAD e.g. 3cQ[Pad] - b3 = base64Alphabet[ marker0 ]; - - decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ); - decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( -(b3>>2) & 0xf) ); - decodedData[encodedIndex+2] = (byte)( b3<<6); - } - encodedIndex += 3; - } - return decodedData; - - } - - static final int base64[]= { - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, - 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, - 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, - 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 - }; - - public static String base64Decode( String orig ) { - char chars[]=orig.toCharArray(); - StringBuffer sb=new StringBuffer(); - int i=0; - - int shift = 0; // # of excess bits stored in accum - int acc = 0; - - for (i=0; i= 64 ) { - if( chars[i] != '=' ) - if (log.isDebugEnabled()) - log.debug("Wrong char in base64: " + chars[i]); - } else { - acc= ( acc << 6 ) | v; - shift += 6; - if ( shift >= 8 ) { - shift -= 8; - sb.append( (char) ((acc >> shift) & 0xff)); - } - } - } - return sb.toString(); - } - - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.buf; + + +/** + * This class provides encode/decode for RFC 2045 Base64 as + * defined by RFC 2045, N. Freed and N. Borenstein. + * RFC 2045: Multipurpose Internet Mail Extensions (MIME) + * Part One: Format of Internet Message Bodies. Reference + * 1996 Available at: http://www.ietf.org/rfc/rfc2045.txt + * This class is used by XML Schema binary format validation + * + * @author Jeffrey Rodriguez + * @version $Revision: 299789 $ $Date: 2004-09-17 20:34:19 +0200 (ven., 17 sept. 2004) $ + */ + +public final class Base64 { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( Base64.class ); + + static private final int BASELENGTH = 255; + static private final int LOOKUPLENGTH = 63; + static private final int TWENTYFOURBITGROUP = 24; + static private final int EIGHTBIT = 8; + static private final int SIXTEENBIT = 16; + static private final int SIXBIT = 6; + static private final int FOURBYTE = 4; + + + static private final byte PAD = ( byte ) '='; + static private byte [] base64Alphabet = new byte[BASELENGTH]; + static private byte [] lookUpBase64Alphabet = new byte[LOOKUPLENGTH]; + + static { + + for (int i = 0; i= 'A'; i-- ) { + base64Alphabet[i] = (byte) (i-'A'); + } + for ( int i = 'z'; i>= 'a'; i--) { + base64Alphabet[i] = (byte) ( i-'a' + 26); + } + + for ( int i = '9'; i >= '0'; i--) { + base64Alphabet[i] = (byte) (i-'0' + 52); + } + + base64Alphabet['+'] = 62; + base64Alphabet['/'] = 63; + + for (int i = 0; i<=25; i++ ) + lookUpBase64Alphabet[i] = (byte) ('A'+i ); + + for (int i = 26, j = 0; i<=51; i++, j++ ) + lookUpBase64Alphabet[i] = (byte) ('a'+ j ); + + for (int i = 52, j = 0; i<=61; i++, j++ ) + lookUpBase64Alphabet[i] = (byte) ('0' + j ); + + } + + + static boolean isBase64( byte octect ) { + //shall we ignore white space? JEFF?? + return(octect == PAD || base64Alphabet[octect] != -1 ); + } + + + static boolean isArrayByteBase64( byte[] arrayOctect ) { + int length = arrayOctect.length; + if ( length == 0 ) + return false; + for ( int i=0; i < length; i++ ) { + if ( Base64.isBase64( arrayOctect[i] ) == false) + return false; + } + return true; + } + + /** + * Encodes hex octects into Base64 + * + * @param binaryData Array containing binaryData + * @return Encoded Base64 array + */ + public static byte[] encode( byte[] binaryData ) { + int lengthDataBits = binaryData.length*EIGHTBIT; + int fewerThan24bits = lengthDataBits%TWENTYFOURBITGROUP; + int numberTriplets = lengthDataBits/TWENTYFOURBITGROUP; + byte encodedData[] = null; + + + if ( fewerThan24bits != 0 ) //data not divisible by 24 bit + encodedData = new byte[ (numberTriplets + 1 )*4 ]; + else // 16 or 8 bit + encodedData = new byte[ numberTriplets*4 ]; + + byte k=0, l=0, b1=0,b2=0,b3=0; + + int encodedIndex = 0; + int dataIndex = 0; + int i = 0; + for ( i = 0; i>2 ]; + encodedData[encodedIndex+1] = lookUpBase64Alphabet[(b2 >>4 ) | +( k<<4 )]; + encodedData[encodedIndex+2] = lookUpBase64Alphabet[ (l <<2 ) | +( b3>>6)]; + encodedData[encodedIndex+3] = lookUpBase64Alphabet[ b3 & 0x3f ]; + } + + // form integral number of 6-bit groups + dataIndex = i*3; + encodedIndex = i*4; + if (fewerThan24bits == EIGHTBIT ) { + b1 = binaryData[dataIndex]; + k = (byte) ( b1 &0x03 ); + encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; + encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ k<<4 ]; + encodedData[encodedIndex + 2] = PAD; + encodedData[encodedIndex + 3] = PAD; + } else if ( fewerThan24bits == SIXTEENBIT ) { + + b1 = binaryData[dataIndex]; + b2 = binaryData[dataIndex +1 ]; + l = ( byte ) ( b2 &0x0f ); + k = ( byte ) ( b1 &0x03 ); + encodedData[encodedIndex] = lookUpBase64Alphabet[ b1 >>2 ]; + encodedData[encodedIndex + 1] = lookUpBase64Alphabet[ (b2 >>4 ) +| ( k<<4 )]; + encodedData[encodedIndex + 2] = lookUpBase64Alphabet[ l<<2 ]; + encodedData[encodedIndex + 3] = PAD; + } + return encodedData; + } + + + /** + * Decodes Base64 data into octects + * + * @param base64Data Byte array containing Base64 data + * @return Array containind decoded data. + */ + public byte[] decode( byte[] base64Data ) { + int numberQuadruple = base64Data.length/FOURBYTE; + byte decodedData[] = null; + byte b1=0,b2=0,b3=0, b4=0, marker0=0, marker1=0; + + // Throw away anything not in base64Data + // Adjust size + + int encodedIndex = 0; + int dataIndex = 0; + decodedData = new byte[ numberQuadruple*3 + 1 ]; + + for (int i = 0; i>4 ) ; + decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( +(b3>>2) & 0xf) ); + decodedData[encodedIndex+2] = (byte)( b3<<6 | b4 ); + } else if ( marker0 == PAD ) { //Two PAD e.g. 3c[Pad][Pad] + decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ) ; + decodedData[encodedIndex+1] = (byte)((b2 & 0xf)<<4 ); + decodedData[encodedIndex+2] = (byte) 0; + } else if ( marker1 == PAD ) { //One PAD e.g. 3cQ[Pad] + b3 = base64Alphabet[ marker0 ]; + + decodedData[encodedIndex] = (byte)( b1 <<2 | b2>>4 ); + decodedData[encodedIndex+1] = (byte)(((b2 & 0xf)<<4 ) |( +(b3>>2) & 0xf) ); + decodedData[encodedIndex+2] = (byte)( b3<<6); + } + encodedIndex += 3; + } + return decodedData; + + } + + static final int base64[]= { + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, + 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64, + 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, + 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 + }; + + public static String base64Decode( String orig ) { + char chars[]=orig.toCharArray(); + StringBuffer sb=new StringBuffer(); + int i=0; + + int shift = 0; // # of excess bits stored in accum + int acc = 0; + + for (i=0; i= 64 ) { + if( chars[i] != '=' ) + if (log.isDebugEnabled()) + log.debug("Wrong char in base64: " + chars[i]); + } else { + acc= ( acc << 6 ) | v; + shift += 6; + if ( shift >= 8 ) { + shift -= 8; + sb.append( (char) ((acc >> shift) & 0xff)); + } + } + } + return sb.toString(); + } + + +} + diff --git a/java/org/apache/tomcat/util/buf/ByteChunk.java b/java/org/apache/tomcat/util/buf/ByteChunk.java index 81f5aca76..71678228d 100644 --- a/java/org/apache/tomcat/util/buf/ByteChunk.java +++ b/java/org/apache/tomcat/util/buf/ByteChunk.java @@ -1,824 +1,824 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.IOException; -import java.io.Serializable; - -/* - * In a server it is very important to be able to operate on - * the original byte[] without converting everything to chars. - * Some protocols are ASCII only, and some allow different - * non-UNICODE encodings. The encoding is not known beforehand, - * and can even change during the execution of the protocol. - * ( for example a multipart message may have parts with different - * encoding ) - * - * For HTTP it is not very clear how the encoding of RequestURI - * and mime values can be determined, but it is a great advantage - * to be able to parse the request without converting to string. - */ - -// TODO: This class could either extend ByteBuffer, or better a ByteBuffer inside -// this way it could provide the search/etc on ByteBuffer, as a helper. - -/** - * This class is used to represent a chunk of bytes, and - * utilities to manipulate byte[]. - * - * The buffer can be modified and used for both input and output. - * - * There are 2 modes: The chunk can be associated with a sink - ByteInputChannel or ByteOutputChannel, - * which will be used when the buffer is empty ( on input ) or filled ( on output ). - * For output, it can also grow. This operating mode is selected by calling setLimit() or - * allocate(initial, limit) with limit != -1. - * - * Various search and append method are defined - similar with String and StringBuffer, but - * operating on bytes. - * - * This is important because it allows processing the http headers directly on the received bytes, - * without converting to chars and Strings until the strings are needed. In addition, the charset - * is determined later, from headers or user code. - * - * - * @author dac@sun.com - * @author James Todd [gonzo@sun.com] - * @author Costin Manolache - * @author Remy Maucherat - */ -public final class ByteChunk implements Cloneable, Serializable { - - /** Input interface, used when the buffer is emptiy - * - * Same as java.nio.channel.ReadableByteChannel - */ - public static interface ByteInputChannel { - /** - * Read new bytes ( usually the internal conversion buffer ). - * The implementation is allowed to ignore the parameters, - * and mutate the chunk if it wishes to implement its own buffering. - */ - public int realReadBytes(byte cbuf[], int off, int len) - throws IOException; - } - - /** Same as java.nio.channel.WrittableByteChannel. - */ - public static interface ByteOutputChannel { - /** - * Send the bytes ( usually the internal conversion buffer ). - * Expect 8k output if the buffer is full. - */ - public void realWriteBytes(byte cbuf[], int off, int len) - throws IOException; - } - - // -------------------- - - /** Default encoding used to convert to strings. It should be UTF8, - as most standards seem to converge, but the servlet API requires - 8859_1, and this object is used mostly for servlets. - */ - public static final String DEFAULT_CHARACTER_ENCODING="ISO-8859-1"; - - // byte[] - private byte[] buff; - - private int start=0; - private int end; - - private String enc; - - private boolean isSet=false; // XXX - - // How much can it grow, when data is added - private int limit=-1; - - private ByteInputChannel in = null; - private ByteOutputChannel out = null; - - private boolean isOutput=false; - private boolean optimizedWrite=true; - - /** - * Creates a new, uninitialized ByteChunk object. - */ - public ByteChunk() { - } - - public ByteChunk( int initial ) { - allocate( initial, -1 ); - } - - //-------------------- - public ByteChunk getClone() { - try { - return (ByteChunk)this.clone(); - } catch( Exception ex) { - return null; - } - } - - public boolean isNull() { - return ! isSet; // buff==null; - } - - /** - * Resets the message buff to an uninitialized state. - */ - public void recycle() { - // buff = null; - enc=null; - start=0; - end=0; - isSet=false; - } - - public void reset() { - buff=null; - } - - // -------------------- Setup -------------------- - - public void allocate( int initial, int limit ) { - isOutput=true; - if( buff==null || buff.length < initial ) { - buff=new byte[initial]; - } - this.limit=limit; - start=0; - end=0; - isSet=true; - } - - /** - * Sets the message bytes to the specified subarray of bytes. - * - * @param b the ascii bytes - * @param off the start offset of the bytes - * @param len the length of the bytes - */ - public void setBytes(byte[] b, int off, int len) { - buff = b; - start = off; - end = start+ len; - isSet=true; - } - - public void setOptimizedWrite(boolean optimizedWrite) { - this.optimizedWrite = optimizedWrite; - } - - public void setEncoding( String enc ) { - this.enc=enc; - } - public String getEncoding() { - if (enc == null) - enc=DEFAULT_CHARACTER_ENCODING; - return enc; - } - - /** - * Returns the message bytes. - */ - public byte[] getBytes() { - return getBuffer(); - } - - /** - * Returns the message bytes. - */ - public byte[] getBuffer() { - return buff; - } - - /** - * Returns the start offset of the bytes. - * For output this is the end of the buffer. - */ - public int getStart() { - return start; - } - - public int getOffset() { - return start; - } - - public void setOffset(int off) { - if (end < off ) end=off; - start=off; - } - - /** - * Returns the length of the bytes. - * XXX need to clean this up - */ - public int getLength() { - return end-start; - } - - /** Maximum amount of data in this buffer. - * - * If -1 or not set, the buffer will grow undefinitely. - * Can be smaller than the current buffer size ( which will not shrink ). - * When the limit is reached, the buffer will be flushed ( if out is set ) - * or throw exception. - */ - public void setLimit(int limit) { - this.limit=limit; - } - - public int getLimit() { - return limit; - } - - /** - * When the buffer is empty, read the data from the input channel. - */ - public void setByteInputChannel(ByteInputChannel in) { - this.in = in; - } - - /** When the buffer is full, write the data to the output channel. - * Also used when large amount of data is appended. - * - * If not set, the buffer will grow to the limit. - */ - public void setByteOutputChannel(ByteOutputChannel out) { - this.out=out; - } - - public int getEnd() { - return end; - } - - public void setEnd( int i ) { - end=i; - } - - // -------------------- Adding data to the buffer -------------------- - /** Append a char, by casting it to byte. This IS NOT intended for unicode. - * - * @param c - * @throws IOException - */ - public void append( char c ) - throws IOException - { - append( (byte)c); - } - - public void append( byte b ) - throws IOException - { - makeSpace( 1 ); - - // couldn't make space - if( limit >0 && end >= limit ) { - flushBuffer(); - } - buff[end++]=b; - } - - public void append( ByteChunk src ) - throws IOException - { - append( src.getBytes(), src.getStart(), src.getLength()); - } - - /** Add data to the buffer - */ - public void append( byte src[], int off, int len ) - throws IOException - { - // will grow, up to limit - makeSpace( len ); - - // if we don't have limit: makeSpace can grow as it wants - if( limit < 0 ) { - // assert: makeSpace made enough space - System.arraycopy( src, off, buff, end, len ); - end+=len; - return; - } - - // Optimize on a common case. - // If the buffer is empty and the source is going to fill up all the - // space in buffer, may as well write it directly to the output, - // and avoid an extra copy - if ( optimizedWrite && len == limit && end == start && out != null ) { - out.realWriteBytes( src, off, len ); - return; - } - // if we have limit and we're below - if( len <= limit - end ) { - // makeSpace will grow the buffer to the limit, - // so we have space - System.arraycopy( src, off, buff, end, len ); - end+=len; - return; - } - - // need more space than we can afford, need to flush - // buffer - - // the buffer is already at ( or bigger than ) limit - - // We chunk the data into slices fitting in the buffer limit, although - // if the data is written directly if it doesn't fit - - int avail=limit-end; - System.arraycopy(src, off, buff, end, avail); - end += avail; - - flushBuffer(); - - int remain = len - avail; - - while (remain > (limit - end)) { - out.realWriteBytes( src, (off + len) - remain, limit - end ); - remain = remain - (limit - end); - } - - System.arraycopy(src, (off + len) - remain, buff, end, remain); - end += remain; - - } - - - // -------------------- Removing data from the buffer -------------------- - - public int substract() - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadBytes( buff, 0, buff.length ); - if (n < 0) - return -1; - } - - return (buff[start++] & 0xFF); - - } - - public int substract(ByteChunk src) - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadBytes( buff, 0, buff.length ); - if (n < 0) - return -1; - } - - int len = getLength(); - src.append(buff, start, len); - start = end; - return len; - - } - - public int substract( byte src[], int off, int len ) - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadBytes( buff, 0, buff.length ); - if (n < 0) - return -1; - } - - int n = len; - if (len > getLength()) { - n = getLength(); - } - System.arraycopy(buff, start, src, off, n); - start += n; - return n; - - } - - - /** Send the buffer to the sink. Called by append() when the limit is reached. - * You can also call it explicitely to force the data to be written. - * - * @throws IOException - */ - public void flushBuffer() - throws IOException - { - //assert out!=null - if( out==null ) { - throw new IOException( "Buffer overflow, no sink " + limit + " " + - buff.length ); - } - out.realWriteBytes( buff, start, end-start ); - end=start; - } - - /** Make space for len chars. If len is small, allocate - * a reserve space too. Never grow bigger than limit. - */ - private void makeSpace(int count) - { - byte[] tmp = null; - - int newSize; - int desiredSize=end + count; - - // Can't grow above the limit - if( limit > 0 && - desiredSize > limit) { - desiredSize=limit; - } - - if( buff==null ) { - if( desiredSize < 256 ) desiredSize=256; // take a minimum - buff=new byte[desiredSize]; - } - - // limit < buf.length ( the buffer is already big ) - // or we already have space XXX - if( desiredSize <= buff.length ) { - return; - } - // grow in larger chunks - if( desiredSize < 2 * buff.length ) { - newSize= buff.length * 2; - if( limit >0 && - newSize > limit ) newSize=limit; - tmp=new byte[newSize]; - } else { - newSize= buff.length * 2 + count ; - if( limit > 0 && - newSize > limit ) newSize=limit; - tmp=new byte[newSize]; - } - - System.arraycopy(buff, start, tmp, 0, end-start); - buff = tmp; - tmp = null; - end=end-start; - start=0; - } - - // -------------------- Conversion and getters -------------------- - - public String toString() { - if (null == buff) { - return null; - } else if (end-start == 0) { - return ""; - } - return StringCache.toString(this); - } - - public String toStringInternal() { - String strValue=null; - try { - if( enc==null ) enc=DEFAULT_CHARACTER_ENCODING; - strValue = new String( buff, start, end-start, enc ); - /* - Does not improve the speed too much on most systems, - it's safer to use the "clasical" new String(). - - Most overhead is in creating char[] and copying, - the internal implementation of new String() is very close to - what we do. The decoder is nice for large buffers and if - we don't go to String ( so we can take advantage of reduced GC) - - // Method is commented out, in: - return B2CConverter.decodeString( enc ); - */ - } catch (java.io.UnsupportedEncodingException e) { - // Use the platform encoding in that case; the usage of a bad - // encoding will have been logged elsewhere already - strValue = new String(buff, start, end-start); - } - return strValue; - } - - public int getInt() - { - return Ascii.parseInt(buff, start,end-start); - } - - public long getLong() { - return Ascii.parseLong(buff, start,end-start); - } - - - // -------------------- equals -------------------- - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equals(String s) { - // XXX ENCODING - this only works if encoding is UTF8-compat - // ( ok for tomcat, where we compare ascii - header names, etc )!!! - - byte[] b = buff; - int blen = end-start; - if (b == null || blen != s.length()) { - return false; - } - int boff = start; - for (int i = 0; i < blen; i++) { - if (b[boff++] != s.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equalsIgnoreCase(String s) { - byte[] b = buff; - int blen = end-start; - if (b == null || blen != s.length()) { - return false; - } - int boff = start; - for (int i = 0; i < blen; i++) { - if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) { - return false; - } - } - return true; - } - - public boolean equals( ByteChunk bb ) { - return equals( bb.getBytes(), bb.getStart(), bb.getLength()); - } - - public boolean equals( byte b2[], int off2, int len2) { - byte b1[]=buff; - if( b1==null && b2==null ) return true; - - int len=end-start; - if ( len2 != len || b1==null || b2==null ) - return false; - - int off1 = start; - - while ( len-- > 0) { - if (b1[off1++] != b2[off2++]) { - return false; - } - } - return true; - } - - public boolean equals( CharChunk cc ) { - return equals( cc.getChars(), cc.getStart(), cc.getLength()); - } - - public boolean equals( char c2[], int off2, int len2) { - // XXX works only for enc compatible with ASCII/UTF !!! - byte b1[]=buff; - if( c2==null && b1==null ) return true; - - if (b1== null || c2==null || end-start != len2 ) { - return false; - } - int off1 = start; - int len=end-start; - - while ( len-- > 0) { - if ( (char)b1[off1++] != c2[off2++]) { - return false; - } - } - return true; - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - */ - public boolean startsWith(String s) { - // Works only if enc==UTF - byte[] b = buff; - int blen = s.length(); - if (b == null || blen > end-start) { - return false; - } - int boff = start; - for (int i = 0; i < blen; i++) { - if (b[boff++] != s.charAt(i)) { - return false; - } - } - return true; - } - - /* Returns true if the message bytes start with the specified byte array */ - public boolean startsWith(byte[] b2) { - byte[] b1 = buff; - if (b1 == null && b2 == null) { - return true; - } - - int len = end - start; - if (b1 == null || b2 == null || b2.length > len) { - return false; - } - for (int i = start, j = 0; i < end && j < b2.length; ) { - if (b1[i++] != b2[j++]) - return false; - } - return true; - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - * @param pos The position - */ - public boolean startsWithIgnoreCase(String s, int pos) { - byte[] b = buff; - int len = s.length(); - if (b == null || len+pos > end-start) { - return false; - } - int off = start+pos; - for (int i = 0; i < len; i++) { - if (Ascii.toLower( b[off++] ) != Ascii.toLower( s.charAt(i))) { - return false; - } - } - return true; - } - - public int indexOf( String src, int srcOff, int srcLen, int myOff ) { - char first=src.charAt( srcOff ); - - // Look for first char - int srcEnd = srcOff + srcLen; - - for( int i=myOff+start; i <= (end - srcLen); i++ ) { - if( buff[i] != first ) continue; - // found first char, now look for a match - int myPos=i+1; - for( int srcPos=srcOff + 1; srcPos< srcEnd; ) { - if( buff[myPos++] != src.charAt( srcPos++ )) - break; - if( srcPos==srcEnd ) return i-start; // found it - } - } - return -1; - } - - // -------------------- Hash code -------------------- - - // normal hash. - public int hash() { - return hashBytes( buff, start, end-start); - } - - // hash ignoring case - public int hashIgnoreCase() { - return hashBytesIC( buff, start, end-start ); - } - - private static int hashBytes( byte buff[], int start, int bytesLen ) { - int max=start+bytesLen; - byte bb[]=buff; - int code=0; - for (int i = start; i < max ; i++) { - code = code * 37 + bb[i]; - } - return code; - } - - private static int hashBytesIC( byte bytes[], int start, - int bytesLen ) - { - int max=start+bytesLen; - byte bb[]=bytes; - int code=0; - for (int i = start; i < max ; i++) { - code = code * 37 + Ascii.toLower(bb[i]); - } - return code; - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param c the character - * @param starting The start position - */ - public int indexOf(char c, int starting) { - int ret = indexOf( buff, start+starting, end, c); - return (ret >= start) ? ret - start : -1; - } - - public static int indexOf( byte bytes[], int off, int end, char qq ) - { - // Works only for UTF - while( off < end ) { - byte b=bytes[off]; - if( b==qq ) - return off; - off++; - } - return -1; - } - - /** Find a character, no side effects. - * @return index of char if found, -1 if not - */ - public static int findChar( byte buf[], int start, int end, char c ) { - byte b=(byte)c; - int offset = start; - while (offset < end) { - if (buf[offset] == b) { - return offset; - } - offset++; - } - return -1; - } - - /** Find a character, no side effects. - * @return index of char if found, -1 if not - */ - public static int findChars( byte buf[], int start, int end, byte c[] ) { - int clen=c.length; - int offset = start; - while (offset < end) { - for( int i=0; i0 && end >= limit ) { + flushBuffer(); + } + buff[end++]=b; + } + + public void append( ByteChunk src ) + throws IOException + { + append( src.getBytes(), src.getStart(), src.getLength()); + } + + /** Add data to the buffer + */ + public void append( byte src[], int off, int len ) + throws IOException + { + // will grow, up to limit + makeSpace( len ); + + // if we don't have limit: makeSpace can grow as it wants + if( limit < 0 ) { + // assert: makeSpace made enough space + System.arraycopy( src, off, buff, end, len ); + end+=len; + return; + } + + // Optimize on a common case. + // If the buffer is empty and the source is going to fill up all the + // space in buffer, may as well write it directly to the output, + // and avoid an extra copy + if ( optimizedWrite && len == limit && end == start && out != null ) { + out.realWriteBytes( src, off, len ); + return; + } + // if we have limit and we're below + if( len <= limit - end ) { + // makeSpace will grow the buffer to the limit, + // so we have space + System.arraycopy( src, off, buff, end, len ); + end+=len; + return; + } + + // need more space than we can afford, need to flush + // buffer + + // the buffer is already at ( or bigger than ) limit + + // We chunk the data into slices fitting in the buffer limit, although + // if the data is written directly if it doesn't fit + + int avail=limit-end; + System.arraycopy(src, off, buff, end, avail); + end += avail; + + flushBuffer(); + + int remain = len - avail; + + while (remain > (limit - end)) { + out.realWriteBytes( src, (off + len) - remain, limit - end ); + remain = remain - (limit - end); + } + + System.arraycopy(src, (off + len) - remain, buff, end, remain); + end += remain; + + } + + + // -------------------- Removing data from the buffer -------------------- + + public int substract() + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadBytes( buff, 0, buff.length ); + if (n < 0) + return -1; + } + + return (buff[start++] & 0xFF); + + } + + public int substract(ByteChunk src) + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadBytes( buff, 0, buff.length ); + if (n < 0) + return -1; + } + + int len = getLength(); + src.append(buff, start, len); + start = end; + return len; + + } + + public int substract( byte src[], int off, int len ) + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadBytes( buff, 0, buff.length ); + if (n < 0) + return -1; + } + + int n = len; + if (len > getLength()) { + n = getLength(); + } + System.arraycopy(buff, start, src, off, n); + start += n; + return n; + + } + + + /** Send the buffer to the sink. Called by append() when the limit is reached. + * You can also call it explicitely to force the data to be written. + * + * @throws IOException + */ + public void flushBuffer() + throws IOException + { + //assert out!=null + if( out==null ) { + throw new IOException( "Buffer overflow, no sink " + limit + " " + + buff.length ); + } + out.realWriteBytes( buff, start, end-start ); + end=start; + } + + /** Make space for len chars. If len is small, allocate + * a reserve space too. Never grow bigger than limit. + */ + private void makeSpace(int count) + { + byte[] tmp = null; + + int newSize; + int desiredSize=end + count; + + // Can't grow above the limit + if( limit > 0 && + desiredSize > limit) { + desiredSize=limit; + } + + if( buff==null ) { + if( desiredSize < 256 ) desiredSize=256; // take a minimum + buff=new byte[desiredSize]; + } + + // limit < buf.length ( the buffer is already big ) + // or we already have space XXX + if( desiredSize <= buff.length ) { + return; + } + // grow in larger chunks + if( desiredSize < 2 * buff.length ) { + newSize= buff.length * 2; + if( limit >0 && + newSize > limit ) newSize=limit; + tmp=new byte[newSize]; + } else { + newSize= buff.length * 2 + count ; + if( limit > 0 && + newSize > limit ) newSize=limit; + tmp=new byte[newSize]; + } + + System.arraycopy(buff, start, tmp, 0, end-start); + buff = tmp; + tmp = null; + end=end-start; + start=0; + } + + // -------------------- Conversion and getters -------------------- + + public String toString() { + if (null == buff) { + return null; + } else if (end-start == 0) { + return ""; + } + return StringCache.toString(this); + } + + public String toStringInternal() { + String strValue=null; + try { + if( enc==null ) enc=DEFAULT_CHARACTER_ENCODING; + strValue = new String( buff, start, end-start, enc ); + /* + Does not improve the speed too much on most systems, + it's safer to use the "clasical" new String(). + + Most overhead is in creating char[] and copying, + the internal implementation of new String() is very close to + what we do. The decoder is nice for large buffers and if + we don't go to String ( so we can take advantage of reduced GC) + + // Method is commented out, in: + return B2CConverter.decodeString( enc ); + */ + } catch (java.io.UnsupportedEncodingException e) { + // Use the platform encoding in that case; the usage of a bad + // encoding will have been logged elsewhere already + strValue = new String(buff, start, end-start); + } + return strValue; + } + + public int getInt() + { + return Ascii.parseInt(buff, start,end-start); + } + + public long getLong() { + return Ascii.parseLong(buff, start,end-start); + } + + + // -------------------- equals -------------------- + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equals(String s) { + // XXX ENCODING - this only works if encoding is UTF8-compat + // ( ok for tomcat, where we compare ascii - header names, etc )!!! + + byte[] b = buff; + int blen = end-start; + if (b == null || blen != s.length()) { + return false; + } + int boff = start; + for (int i = 0; i < blen; i++) { + if (b[boff++] != s.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equalsIgnoreCase(String s) { + byte[] b = buff; + int blen = end-start; + if (b == null || blen != s.length()) { + return false; + } + int boff = start; + for (int i = 0; i < blen; i++) { + if (Ascii.toLower(b[boff++]) != Ascii.toLower(s.charAt(i))) { + return false; + } + } + return true; + } + + public boolean equals( ByteChunk bb ) { + return equals( bb.getBytes(), bb.getStart(), bb.getLength()); + } + + public boolean equals( byte b2[], int off2, int len2) { + byte b1[]=buff; + if( b1==null && b2==null ) return true; + + int len=end-start; + if ( len2 != len || b1==null || b2==null ) + return false; + + int off1 = start; + + while ( len-- > 0) { + if (b1[off1++] != b2[off2++]) { + return false; + } + } + return true; + } + + public boolean equals( CharChunk cc ) { + return equals( cc.getChars(), cc.getStart(), cc.getLength()); + } + + public boolean equals( char c2[], int off2, int len2) { + // XXX works only for enc compatible with ASCII/UTF !!! + byte b1[]=buff; + if( c2==null && b1==null ) return true; + + if (b1== null || c2==null || end-start != len2 ) { + return false; + } + int off1 = start; + int len=end-start; + + while ( len-- > 0) { + if ( (char)b1[off1++] != c2[off2++]) { + return false; + } + } + return true; + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + */ + public boolean startsWith(String s) { + // Works only if enc==UTF + byte[] b = buff; + int blen = s.length(); + if (b == null || blen > end-start) { + return false; + } + int boff = start; + for (int i = 0; i < blen; i++) { + if (b[boff++] != s.charAt(i)) { + return false; + } + } + return true; + } + + /* Returns true if the message bytes start with the specified byte array */ + public boolean startsWith(byte[] b2) { + byte[] b1 = buff; + if (b1 == null && b2 == null) { + return true; + } + + int len = end - start; + if (b1 == null || b2 == null || b2.length > len) { + return false; + } + for (int i = start, j = 0; i < end && j < b2.length; ) { + if (b1[i++] != b2[j++]) + return false; + } + return true; + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + * @param pos The position + */ + public boolean startsWithIgnoreCase(String s, int pos) { + byte[] b = buff; + int len = s.length(); + if (b == null || len+pos > end-start) { + return false; + } + int off = start+pos; + for (int i = 0; i < len; i++) { + if (Ascii.toLower( b[off++] ) != Ascii.toLower( s.charAt(i))) { + return false; + } + } + return true; + } + + public int indexOf( String src, int srcOff, int srcLen, int myOff ) { + char first=src.charAt( srcOff ); + + // Look for first char + int srcEnd = srcOff + srcLen; + + for( int i=myOff+start; i <= (end - srcLen); i++ ) { + if( buff[i] != first ) continue; + // found first char, now look for a match + int myPos=i+1; + for( int srcPos=srcOff + 1; srcPos< srcEnd; ) { + if( buff[myPos++] != src.charAt( srcPos++ )) + break; + if( srcPos==srcEnd ) return i-start; // found it + } + } + return -1; + } + + // -------------------- Hash code -------------------- + + // normal hash. + public int hash() { + return hashBytes( buff, start, end-start); + } + + // hash ignoring case + public int hashIgnoreCase() { + return hashBytesIC( buff, start, end-start ); + } + + private static int hashBytes( byte buff[], int start, int bytesLen ) { + int max=start+bytesLen; + byte bb[]=buff; + int code=0; + for (int i = start; i < max ; i++) { + code = code * 37 + bb[i]; + } + return code; + } + + private static int hashBytesIC( byte bytes[], int start, + int bytesLen ) + { + int max=start+bytesLen; + byte bb[]=bytes; + int code=0; + for (int i = start; i < max ; i++) { + code = code * 37 + Ascii.toLower(bb[i]); + } + return code; + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param c the character + * @param starting The start position + */ + public int indexOf(char c, int starting) { + int ret = indexOf( buff, start+starting, end, c); + return (ret >= start) ? ret - start : -1; + } + + public static int indexOf( byte bytes[], int off, int end, char qq ) + { + // Works only for UTF + while( off < end ) { + byte b=bytes[off]; + if( b==qq ) + return off; + off++; + } + return -1; + } + + /** Find a character, no side effects. + * @return index of char if found, -1 if not + */ + public static int findChar( byte buf[], int start, int end, char c ) { + byte b=(byte)c; + int offset = start; + while (offset < end) { + if (buf[offset] == b) { + return offset; + } + offset++; + } + return -1; + } + + /** Find a character, no side effects. + * @return index of char if found, -1 if not + */ + public static int findChars( byte buf[], int start, int end, byte c[] ) { + int clen=c.length; + int offset = start; + while (offset < end) { + for( int i=0; ibyte converter should be independent of flushing the OutputStream. - * - * When a WriteConverter is created, it'll allocate one or 2 byte buffers, - * with a 8k size that can't be changed ( at least in JDK1.1 -> 1.4 ). It would - * also allocate a ByteOutputter or equivalent - again some internal buffers. - * - * It is essential to keep this object around and reuse it. You can use either - * pools or per thread data - but given that in most cases a converter will be - * needed for every thread and most of the time only 1 ( or 2 ) encodings will - * be used, it is far better to keep it per thread and eliminate the pool - * overhead too. - * - */ - final class WriteConvertor extends OutputStreamWriter { - // stream with flush() and close(). overriden. - private IntermediateOutputStream ios; - - // Has a private, internal byte[8192] - - /** Create a converter. - */ - public WriteConvertor( IntermediateOutputStream out, String enc ) - throws UnsupportedEncodingException - { - super( out, enc ); - ios=out; - } - - /** Overriden - will do nothing but reset internal state. - */ - public final void close() throws IOException { - // NOTHING - // Calling super.close() would reset out and cb. - } - - /** - * Flush the characters only - */ - public final void flush() throws IOException { - // Will flushBuffer and out() - // flushBuffer put any remaining chars in the byte[] - super.flush(); - } - - public final void write(char cbuf[], int off, int len) throws IOException { - // will do the conversion and call write on the output stream - super.write( cbuf, off, len ); - } - - /** Reset the buffer - */ - public final void recycle() { - ios.disable(); - try { - // System.out.println("Reseting writer"); - flush(); - } catch( Exception ex ) { - ex.printStackTrace(); - } - ios.enable(); - } - -} - - -/** Special output stream where close() is overriden, so super.close() - is never called. - - This allows recycling. It can also be disabled, so callbacks will - not be called if recycling the converter and if data was not flushed. -*/ -final class IntermediateOutputStream extends OutputStream { - private ByteChunk tbuff; - private boolean enabled=true; - - public IntermediateOutputStream(ByteChunk tbuff) { - this.tbuff=tbuff; - } - - public final void close() throws IOException { - // shouldn't be called - we filter it out in writer - throw new IOException("close() called - shouldn't happen "); - } - - public final void flush() throws IOException { - // nothing - write will go directly to the buffer, - // we don't keep any state - } - - public final void write(byte cbuf[], int off, int len) throws IOException { - // will do the conversion and call write on the output stream - if( enabled ) { - tbuff.append( cbuf, off, len ); - } - } - - public final void write( int i ) throws IOException { - throw new IOException("write( int ) called - shouldn't happen "); - } - - // -------------------- Internal methods -------------------- - - void setByteChunk( ByteChunk bb ) { - tbuff=bb; - } - - /** Temporary disable - this is used to recycle the converter without - * generating an output if the buffers were not flushed - */ - final void disable() { - enabled=false; - } - - /** Reenable - used to recycle the converter - */ - final void enable() { - enabled=true; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.IOException; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.UnsupportedEncodingException; + +/** Efficient conversion of character to bytes. + * + * This uses the standard JDK mechansim - a writer - but provides mechanisms + * to recycle all the objects that are used. It is compatible with JDK1.1 and up, + * ( nio is better, but it's not available even in 1.2 or 1.3 ) + * + */ +public final class C2BConverter { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(C2BConverter.class ); + + private IntermediateOutputStream ios; + private WriteConvertor conv; + private ByteChunk bb; + private String enc; + + /** Create a converter, with bytes going to a byte buffer + */ + public C2BConverter(ByteChunk output, String encoding) throws IOException { + this.bb=output; + ios=new IntermediateOutputStream( output ); + conv=new WriteConvertor( ios, encoding ); + this.enc=encoding; + } + + /** Create a converter + */ + public C2BConverter(String encoding) throws IOException { + this( new ByteChunk(1024), encoding ); + } + + public ByteChunk getByteChunk() { + return bb; + } + + public String getEncoding() { + return enc; + } + + public void setByteChunk(ByteChunk bb) { + this.bb=bb; + ios.setByteChunk( bb ); + } + + /** Reset the internal state, empty the buffers. + * The encoding remain in effect, the internal buffers remain allocated. + */ + public final void recycle() { + conv.recycle(); + bb.recycle(); + } + + /** Generate the bytes using the specified encoding + */ + public final void convert(char c[], int off, int len ) throws IOException { + conv.write( c, off, len ); + } + + /** Generate the bytes using the specified encoding + */ + public final void convert(String s, int off, int len ) throws IOException { + conv.write( s, off, len ); + } + + /** Generate the bytes using the specified encoding + */ + public final void convert(String s ) throws IOException { + conv.write( s ); + } + + /** Generate the bytes using the specified encoding + */ + public final void convert(char c ) throws IOException { + conv.write( c ); + } + + /** Convert a message bytes chars to bytes + */ + public final void convert(MessageBytes mb ) throws IOException { + int type=mb.getType(); + if( type==MessageBytes.T_BYTES ) + return; + ByteChunk orig=bb; + setByteChunk( mb.getByteChunk()); + bb.recycle(); + bb.allocate( 32, -1 ); + + if( type==MessageBytes.T_STR ) { + convert( mb.getString() ); + // System.out.println("XXX Converting " + mb.getString() ); + } else if( type==MessageBytes.T_CHARS ) { + CharChunk charC=mb.getCharChunk(); + convert( charC.getBuffer(), + charC.getOffset(), charC.getLength()); + //System.out.println("XXX Converting " + mb.getCharChunk() ); + } else { + if (log.isDebugEnabled()) + log.debug("XXX unknowon type " + type ); + } + flushBuffer(); + //System.out.println("C2B: XXX " + bb.getBuffer() + bb.getLength()); + setByteChunk(orig); + } + + /** Flush any internal buffers into the ByteOutput or the internal + * byte[] + */ + public final void flushBuffer() throws IOException { + conv.flush(); + } + +} + +// -------------------- Private implementation -------------------- + + + +/** + * Special writer class, where close() is overritten. The default implementation + * would set byteOutputter to null, and the writter can't be recycled. + * + * Note that the flush method will empty the internal buffers _and_ call + * flush on the output stream - that's why we use an intermediary output stream + * that overrides flush(). The idea is to have full control: flushing the + * char->byte converter should be independent of flushing the OutputStream. + * + * When a WriteConverter is created, it'll allocate one or 2 byte buffers, + * with a 8k size that can't be changed ( at least in JDK1.1 -> 1.4 ). It would + * also allocate a ByteOutputter or equivalent - again some internal buffers. + * + * It is essential to keep this object around and reuse it. You can use either + * pools or per thread data - but given that in most cases a converter will be + * needed for every thread and most of the time only 1 ( or 2 ) encodings will + * be used, it is far better to keep it per thread and eliminate the pool + * overhead too. + * + */ + final class WriteConvertor extends OutputStreamWriter { + // stream with flush() and close(). overriden. + private IntermediateOutputStream ios; + + // Has a private, internal byte[8192] + + /** Create a converter. + */ + public WriteConvertor( IntermediateOutputStream out, String enc ) + throws UnsupportedEncodingException + { + super( out, enc ); + ios=out; + } + + /** Overriden - will do nothing but reset internal state. + */ + public final void close() throws IOException { + // NOTHING + // Calling super.close() would reset out and cb. + } + + /** + * Flush the characters only + */ + public final void flush() throws IOException { + // Will flushBuffer and out() + // flushBuffer put any remaining chars in the byte[] + super.flush(); + } + + public final void write(char cbuf[], int off, int len) throws IOException { + // will do the conversion and call write on the output stream + super.write( cbuf, off, len ); + } + + /** Reset the buffer + */ + public final void recycle() { + ios.disable(); + try { + // System.out.println("Reseting writer"); + flush(); + } catch( Exception ex ) { + ex.printStackTrace(); + } + ios.enable(); + } + +} + + +/** Special output stream where close() is overriden, so super.close() + is never called. + + This allows recycling. It can also be disabled, so callbacks will + not be called if recycling the converter and if data was not flushed. +*/ +final class IntermediateOutputStream extends OutputStream { + private ByteChunk tbuff; + private boolean enabled=true; + + public IntermediateOutputStream(ByteChunk tbuff) { + this.tbuff=tbuff; + } + + public final void close() throws IOException { + // shouldn't be called - we filter it out in writer + throw new IOException("close() called - shouldn't happen "); + } + + public final void flush() throws IOException { + // nothing - write will go directly to the buffer, + // we don't keep any state + } + + public final void write(byte cbuf[], int off, int len) throws IOException { + // will do the conversion and call write on the output stream + if( enabled ) { + tbuff.append( cbuf, off, len ); + } + } + + public final void write( int i ) throws IOException { + throw new IOException("write( int ) called - shouldn't happen "); + } + + // -------------------- Internal methods -------------------- + + void setByteChunk( ByteChunk bb ) { + tbuff=bb; + } + + /** Temporary disable - this is used to recycle the converter without + * generating an output if the buffers were not flushed + */ + final void disable() { + enabled=false; + } + + /** Reenable - used to recycle the converter + */ + final void enable() { + enabled=true; + } +} diff --git a/java/org/apache/tomcat/util/buf/CharChunk.java b/java/org/apache/tomcat/util/buf/CharChunk.java index 29bc6400a..6a542a92e 100644 --- a/java/org/apache/tomcat/util/buf/CharChunk.java +++ b/java/org/apache/tomcat/util/buf/CharChunk.java @@ -1,720 +1,720 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.IOException; -import java.io.Serializable; - -/** - * Utilities to manipluate char chunks. While String is - * the easiest way to manipulate chars ( search, substrings, etc), - * it is known to not be the most efficient solution - Strings are - * designed as imutable and secure objects. - * - * @author dac@sun.com - * @author James Todd [gonzo@sun.com] - * @author Costin Manolache - * @author Remy Maucherat - */ -public final class CharChunk implements Cloneable, Serializable, CharSequence { - - // Input interface, used when the buffer is emptied. - public static interface CharInputChannel { - /** - * Read new bytes ( usually the internal conversion buffer ). - * The implementation is allowed to ignore the parameters, - * and mutate the chunk if it wishes to implement its own buffering. - */ - public int realReadChars(char cbuf[], int off, int len) - throws IOException; - } - /** - * When we need more space we'll either - * grow the buffer ( up to the limit ) or send it to a channel. - */ - public static interface CharOutputChannel { - /** Send the bytes ( usually the internal conversion buffer ). - * Expect 8k output if the buffer is full. - */ - public void realWriteChars(char cbuf[], int off, int len) - throws IOException; - } - - // -------------------- - // char[] - private char buff[]; - - private int start; - private int end; - - private boolean isSet=false; // XXX - - private boolean isOutput=false; - - // -1: grow undefinitely - // maximum amount to be cached - private int limit=-1; - - private CharInputChannel in = null; - private CharOutputChannel out = null; - - private boolean optimizedWrite=true; - - /** - * Creates a new, uninitialized CharChunk object. - */ - public CharChunk() { - } - - public CharChunk(int size) { - allocate( size, -1 ); - } - - // -------------------- - - public CharChunk getClone() { - try { - return (CharChunk)this.clone(); - } catch( Exception ex) { - return null; - } - } - - public boolean isNull() { - if( end > 0 ) return false; - return !isSet; //XXX - } - - /** - * Resets the message bytes to an uninitialized state. - */ - public void recycle() { - // buff=null; - isSet=false; // XXX - start=0; - end=0; - } - - public void reset() { - buff=null; - } - - // -------------------- Setup -------------------- - - public void allocate( int initial, int limit ) { - isOutput=true; - if( buff==null || buff.length < initial ) { - buff=new char[initial]; - } - this.limit=limit; - start=0; - end=0; - isOutput=true; - isSet=true; - } - - - public void setOptimizedWrite(boolean optimizedWrite) { - this.optimizedWrite = optimizedWrite; - } - - public void setChars( char[] c, int off, int len ) { - buff=c; - start=off; - end=start + len; - isSet=true; - } - - /** Maximum amount of data in this buffer. - * - * If -1 or not set, the buffer will grow undefinitely. - * Can be smaller than the current buffer size ( which will not shrink ). - * When the limit is reached, the buffer will be flushed ( if out is set ) - * or throw exception. - */ - public void setLimit(int limit) { - this.limit=limit; - } - - public int getLimit() { - return limit; - } - - /** - * When the buffer is empty, read the data from the input channel. - */ - public void setCharInputChannel(CharInputChannel in) { - this.in = in; - } - - /** When the buffer is full, write the data to the output channel. - * Also used when large amount of data is appended. - * - * If not set, the buffer will grow to the limit. - */ - public void setCharOutputChannel(CharOutputChannel out) { - this.out=out; - } - - // compat - public char[] getChars() - { - return getBuffer(); - } - - public char[] getBuffer() - { - return buff; - } - - /** - * Returns the start offset of the bytes. - * For output this is the end of the buffer. - */ - public int getStart() { - return start; - } - - public int getOffset() { - return start; - } - - /** - * Returns the start offset of the bytes. - */ - public void setOffset(int off) { - start=off; - } - - /** - * Returns the length of the bytes. - */ - public int getLength() { - return end-start; - } - - - public int getEnd() { - return end; - } - - public void setEnd( int i ) { - end=i; - } - - // -------------------- Adding data -------------------- - - public void append( char b ) - throws IOException - { - makeSpace( 1 ); - - // couldn't make space - if( limit >0 && end >= limit ) { - flushBuffer(); - } - buff[end++]=b; - } - - public void append( CharChunk src ) - throws IOException - { - append( src.getBuffer(), src.getOffset(), src.getLength()); - } - - /** Add data to the buffer - */ - public void append( char src[], int off, int len ) - throws IOException - { - // will grow, up to limit - makeSpace( len ); - - // if we don't have limit: makeSpace can grow as it wants - if( limit < 0 ) { - // assert: makeSpace made enough space - System.arraycopy( src, off, buff, end, len ); - end+=len; - return; - } - - // Optimize on a common case. - // If the source is going to fill up all the space in buffer, may - // as well write it directly to the output, and avoid an extra copy - if ( optimizedWrite && len == limit && end == start && out != null ) { - out.realWriteChars( src, off, len ); - return; - } - - // if we have limit and we're below - if( len <= limit - end ) { - // makeSpace will grow the buffer to the limit, - // so we have space - System.arraycopy( src, off, buff, end, len ); - - end+=len; - return; - } - - // need more space than we can afford, need to flush - // buffer - - // the buffer is already at ( or bigger than ) limit - - // Optimization: - // If len-avail < length ( i.e. after we fill the buffer with - // what we can, the remaining will fit in the buffer ) we'll just - // copy the first part, flush, then copy the second part - 1 write - // and still have some space for more. We'll still have 2 writes, but - // we write more on the first. - - if( len + end < 2 * limit ) { - /* If the request length exceeds the size of the output buffer, - flush the output buffer and then write the data directly. - We can't avoid 2 writes, but we can write more on the second - */ - int avail=limit-end; - System.arraycopy(src, off, buff, end, avail); - end += avail; - - flushBuffer(); - - System.arraycopy(src, off+avail, buff, end, len - avail); - end+= len - avail; - - } else { // len > buf.length + avail - // long write - flush the buffer and write the rest - // directly from source - flushBuffer(); - - out.realWriteChars( src, off, len ); - } - } - - - /** Add data to the buffer - */ - public void append( StringBuffer sb ) - throws IOException - { - int len=sb.length(); - - // will grow, up to limit - makeSpace( len ); - - // if we don't have limit: makeSpace can grow as it wants - if( limit < 0 ) { - // assert: makeSpace made enough space - sb.getChars(0, len, buff, end ); - end+=len; - return; - } - - int off=0; - int sbOff = off; - int sbEnd = off + len; - while (sbOff < sbEnd) { - int d = min(limit - end, sbEnd - sbOff); - sb.getChars( sbOff, sbOff+d, buff, end); - sbOff += d; - end += d; - if (end >= limit) - flushBuffer(); - } - } - - /** Append a string to the buffer - */ - public void append(String s) throws IOException { - append(s, 0, s.length()); - } - - /** Append a string to the buffer - */ - public void append(String s, int off, int len) throws IOException { - if (s==null) return; - - // will grow, up to limit - makeSpace( len ); - - // if we don't have limit: makeSpace can grow as it wants - if( limit < 0 ) { - // assert: makeSpace made enough space - s.getChars(off, off+len, buff, end ); - end+=len; - return; - } - - int sOff = off; - int sEnd = off + len; - while (sOff < sEnd) { - int d = min(limit - end, sEnd - sOff); - s.getChars( sOff, sOff+d, buff, end); - sOff += d; - end += d; - if (end >= limit) - flushBuffer(); - } - } - - // -------------------- Removing data from the buffer -------------------- - - public int substract() - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadChars(buff, end, buff.length - end); - if (n < 0) - return -1; - } - - return (buff[start++]); - - } - - public int substract(CharChunk src) - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadChars( buff, end, buff.length - end); - if (n < 0) - return -1; - } - - int len = getLength(); - src.append(buff, start, len); - start = end; - return len; - - } - - public int substract( char src[], int off, int len ) - throws IOException { - - if ((end - start) == 0) { - if (in == null) - return -1; - int n = in.realReadChars( buff, end, buff.length - end); - if (n < 0) - return -1; - } - - int n = len; - if (len > getLength()) { - n = getLength(); - } - System.arraycopy(buff, start, src, off, n); - start += n; - return n; - - } - - - public void flushBuffer() - throws IOException - { - //assert out!=null - if( out==null ) { - throw new IOException( "Buffer overflow, no sink " + limit + " " + - buff.length ); - } - out.realWriteChars( buff, start, end - start ); - end=start; - } - - /** Make space for len chars. If len is small, allocate - * a reserve space too. Never grow bigger than limit. - */ - private void makeSpace(int count) - { - char[] tmp = null; - - int newSize; - int desiredSize=end + count; - - // Can't grow above the limit - if( limit > 0 && - desiredSize > limit) { - desiredSize=limit; - } - - if( buff==null ) { - if( desiredSize < 256 ) desiredSize=256; // take a minimum - buff=new char[desiredSize]; - } - - // limit < buf.length ( the buffer is already big ) - // or we already have space XXX - if( desiredSize <= buff.length) { - return; - } - // grow in larger chunks - if( desiredSize < 2 * buff.length ) { - newSize= buff.length * 2; - if( limit >0 && - newSize > limit ) newSize=limit; - tmp=new char[newSize]; - } else { - newSize= buff.length * 2 + count ; - if( limit > 0 && - newSize > limit ) newSize=limit; - tmp=new char[newSize]; - } - - System.arraycopy(buff, start, tmp, start, end-start); - buff = tmp; - tmp = null; - } - - // -------------------- Conversion and getters -------------------- - - public String toString() { - if (null == buff) { - return null; - } else if (end-start == 0) { - return ""; - } - return StringCache.toString(this); - } - - public String toStringInternal() { - return new String(buff, start, end-start); - } - - public int getInt() - { - return Ascii.parseInt(buff, start, - end-start); - } - - // -------------------- equals -------------------- - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equals(String s) { - char[] c = buff; - int len = end-start; - if (c == null || len != s.length()) { - return false; - } - int off = start; - for (int i = 0; i < len; i++) { - if (c[off++] != s.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equalsIgnoreCase(String s) { - char[] c = buff; - int len = end-start; - if (c == null || len != s.length()) { - return false; - } - int off = start; - for (int i = 0; i < len; i++) { - if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { - return false; - } - } - return true; - } - - public boolean equals(CharChunk cc) { - return equals( cc.getChars(), cc.getOffset(), cc.getLength()); - } - - public boolean equals(char b2[], int off2, int len2) { - char b1[]=buff; - if( b1==null && b2==null ) return true; - - if (b1== null || b2==null || end-start != len2) { - return false; - } - int off1 = start; - int len=end-start; - while ( len-- > 0) { - if (b1[off1++] != b2[off2++]) { - return false; - } - } - return true; - } - - public boolean equals(byte b2[], int off2, int len2) { - char b1[]=buff; - if( b2==null && b1==null ) return true; - - if (b1== null || b2==null || end-start != len2) { - return false; - } - int off1 = start; - int len=end-start; - - while ( len-- > 0) { - if ( b1[off1++] != (char)b2[off2++]) { - return false; - } - } - return true; - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - */ - public boolean startsWith(String s) { - char[] c = buff; - int len = s.length(); - if (c == null || len > end-start) { - return false; - } - int off = start; - for (int i = 0; i < len; i++) { - if (c[off++] != s.charAt(i)) { - return false; - } - } - return true; - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - */ - public boolean startsWithIgnoreCase(String s, int pos) { - char[] c = buff; - int len = s.length(); - if (c == null || len+pos > end-start) { - return false; - } - int off = start+pos; - for (int i = 0; i < len; i++) { - if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { - return false; - } - } - return true; - } - - - // -------------------- Hash code -------------------- - - // normal hash. - public int hash() { - int code=0; - for (int i = start; i < start + end-start; i++) { - code = code * 37 + buff[i]; - } - return code; - } - - // hash ignoring case - public int hashIgnoreCase() { - int code=0; - for (int i = start; i < end; i++) { - code = code * 37 + Ascii.toLower(buff[i]); - } - return code; - } - - public int indexOf(char c) { - return indexOf( c, start); - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param c the character - */ - public int indexOf(char c, int starting) { - int ret = indexOf( buff, start+starting, end, c ); - return (ret >= start) ? ret - start : -1; - } - - public static int indexOf( char chars[], int off, int cend, char qq ) - { - while( off < cend ) { - char b=chars[off]; - if( b==qq ) - return off; - off++; - } - return -1; - } - - - public int indexOf( String src, int srcOff, int srcLen, int myOff ) { - char first=src.charAt( srcOff ); - - // Look for first char - int srcEnd = srcOff + srcLen; - - for( int i=myOff+start; i <= (end - srcLen); i++ ) { - if( buff[i] != first ) continue; - // found first char, now look for a match - int myPos=i+1; - for( int srcPos=srcOff + 1; srcPos< srcEnd; ) { - if( buff[myPos++] != src.charAt( srcPos++ )) - break; - if( srcPos==srcEnd ) return i-start; // found it - } - } - return -1; - } - - // -------------------- utils - private int min(int a, int b) { - if (a < b) return a; - return b; - } - - // Char sequence impl - - public char charAt(int index) { - return buff[index + start]; - } - - public CharSequence subSequence(int start, int end) { - try { - CharChunk result = (CharChunk) this.clone(); - result.setOffset(this.start + start); - result.setEnd(this.start + end); - return result; - } catch (CloneNotSupportedException e) { - // Cannot happen - return null; - } - } - - public int length() { - return end - start; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.IOException; +import java.io.Serializable; + +/** + * Utilities to manipluate char chunks. While String is + * the easiest way to manipulate chars ( search, substrings, etc), + * it is known to not be the most efficient solution - Strings are + * designed as imutable and secure objects. + * + * @author dac@sun.com + * @author James Todd [gonzo@sun.com] + * @author Costin Manolache + * @author Remy Maucherat + */ +public final class CharChunk implements Cloneable, Serializable, CharSequence { + + // Input interface, used when the buffer is emptied. + public static interface CharInputChannel { + /** + * Read new bytes ( usually the internal conversion buffer ). + * The implementation is allowed to ignore the parameters, + * and mutate the chunk if it wishes to implement its own buffering. + */ + public int realReadChars(char cbuf[], int off, int len) + throws IOException; + } + /** + * When we need more space we'll either + * grow the buffer ( up to the limit ) or send it to a channel. + */ + public static interface CharOutputChannel { + /** Send the bytes ( usually the internal conversion buffer ). + * Expect 8k output if the buffer is full. + */ + public void realWriteChars(char cbuf[], int off, int len) + throws IOException; + } + + // -------------------- + // char[] + private char buff[]; + + private int start; + private int end; + + private boolean isSet=false; // XXX + + private boolean isOutput=false; + + // -1: grow undefinitely + // maximum amount to be cached + private int limit=-1; + + private CharInputChannel in = null; + private CharOutputChannel out = null; + + private boolean optimizedWrite=true; + + /** + * Creates a new, uninitialized CharChunk object. + */ + public CharChunk() { + } + + public CharChunk(int size) { + allocate( size, -1 ); + } + + // -------------------- + + public CharChunk getClone() { + try { + return (CharChunk)this.clone(); + } catch( Exception ex) { + return null; + } + } + + public boolean isNull() { + if( end > 0 ) return false; + return !isSet; //XXX + } + + /** + * Resets the message bytes to an uninitialized state. + */ + public void recycle() { + // buff=null; + isSet=false; // XXX + start=0; + end=0; + } + + public void reset() { + buff=null; + } + + // -------------------- Setup -------------------- + + public void allocate( int initial, int limit ) { + isOutput=true; + if( buff==null || buff.length < initial ) { + buff=new char[initial]; + } + this.limit=limit; + start=0; + end=0; + isOutput=true; + isSet=true; + } + + + public void setOptimizedWrite(boolean optimizedWrite) { + this.optimizedWrite = optimizedWrite; + } + + public void setChars( char[] c, int off, int len ) { + buff=c; + start=off; + end=start + len; + isSet=true; + } + + /** Maximum amount of data in this buffer. + * + * If -1 or not set, the buffer will grow undefinitely. + * Can be smaller than the current buffer size ( which will not shrink ). + * When the limit is reached, the buffer will be flushed ( if out is set ) + * or throw exception. + */ + public void setLimit(int limit) { + this.limit=limit; + } + + public int getLimit() { + return limit; + } + + /** + * When the buffer is empty, read the data from the input channel. + */ + public void setCharInputChannel(CharInputChannel in) { + this.in = in; + } + + /** When the buffer is full, write the data to the output channel. + * Also used when large amount of data is appended. + * + * If not set, the buffer will grow to the limit. + */ + public void setCharOutputChannel(CharOutputChannel out) { + this.out=out; + } + + // compat + public char[] getChars() + { + return getBuffer(); + } + + public char[] getBuffer() + { + return buff; + } + + /** + * Returns the start offset of the bytes. + * For output this is the end of the buffer. + */ + public int getStart() { + return start; + } + + public int getOffset() { + return start; + } + + /** + * Returns the start offset of the bytes. + */ + public void setOffset(int off) { + start=off; + } + + /** + * Returns the length of the bytes. + */ + public int getLength() { + return end-start; + } + + + public int getEnd() { + return end; + } + + public void setEnd( int i ) { + end=i; + } + + // -------------------- Adding data -------------------- + + public void append( char b ) + throws IOException + { + makeSpace( 1 ); + + // couldn't make space + if( limit >0 && end >= limit ) { + flushBuffer(); + } + buff[end++]=b; + } + + public void append( CharChunk src ) + throws IOException + { + append( src.getBuffer(), src.getOffset(), src.getLength()); + } + + /** Add data to the buffer + */ + public void append( char src[], int off, int len ) + throws IOException + { + // will grow, up to limit + makeSpace( len ); + + // if we don't have limit: makeSpace can grow as it wants + if( limit < 0 ) { + // assert: makeSpace made enough space + System.arraycopy( src, off, buff, end, len ); + end+=len; + return; + } + + // Optimize on a common case. + // If the source is going to fill up all the space in buffer, may + // as well write it directly to the output, and avoid an extra copy + if ( optimizedWrite && len == limit && end == start && out != null ) { + out.realWriteChars( src, off, len ); + return; + } + + // if we have limit and we're below + if( len <= limit - end ) { + // makeSpace will grow the buffer to the limit, + // so we have space + System.arraycopy( src, off, buff, end, len ); + + end+=len; + return; + } + + // need more space than we can afford, need to flush + // buffer + + // the buffer is already at ( or bigger than ) limit + + // Optimization: + // If len-avail < length ( i.e. after we fill the buffer with + // what we can, the remaining will fit in the buffer ) we'll just + // copy the first part, flush, then copy the second part - 1 write + // and still have some space for more. We'll still have 2 writes, but + // we write more on the first. + + if( len + end < 2 * limit ) { + /* If the request length exceeds the size of the output buffer, + flush the output buffer and then write the data directly. + We can't avoid 2 writes, but we can write more on the second + */ + int avail=limit-end; + System.arraycopy(src, off, buff, end, avail); + end += avail; + + flushBuffer(); + + System.arraycopy(src, off+avail, buff, end, len - avail); + end+= len - avail; + + } else { // len > buf.length + avail + // long write - flush the buffer and write the rest + // directly from source + flushBuffer(); + + out.realWriteChars( src, off, len ); + } + } + + + /** Add data to the buffer + */ + public void append( StringBuffer sb ) + throws IOException + { + int len=sb.length(); + + // will grow, up to limit + makeSpace( len ); + + // if we don't have limit: makeSpace can grow as it wants + if( limit < 0 ) { + // assert: makeSpace made enough space + sb.getChars(0, len, buff, end ); + end+=len; + return; + } + + int off=0; + int sbOff = off; + int sbEnd = off + len; + while (sbOff < sbEnd) { + int d = min(limit - end, sbEnd - sbOff); + sb.getChars( sbOff, sbOff+d, buff, end); + sbOff += d; + end += d; + if (end >= limit) + flushBuffer(); + } + } + + /** Append a string to the buffer + */ + public void append(String s) throws IOException { + append(s, 0, s.length()); + } + + /** Append a string to the buffer + */ + public void append(String s, int off, int len) throws IOException { + if (s==null) return; + + // will grow, up to limit + makeSpace( len ); + + // if we don't have limit: makeSpace can grow as it wants + if( limit < 0 ) { + // assert: makeSpace made enough space + s.getChars(off, off+len, buff, end ); + end+=len; + return; + } + + int sOff = off; + int sEnd = off + len; + while (sOff < sEnd) { + int d = min(limit - end, sEnd - sOff); + s.getChars( sOff, sOff+d, buff, end); + sOff += d; + end += d; + if (end >= limit) + flushBuffer(); + } + } + + // -------------------- Removing data from the buffer -------------------- + + public int substract() + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadChars(buff, end, buff.length - end); + if (n < 0) + return -1; + } + + return (buff[start++]); + + } + + public int substract(CharChunk src) + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadChars( buff, end, buff.length - end); + if (n < 0) + return -1; + } + + int len = getLength(); + src.append(buff, start, len); + start = end; + return len; + + } + + public int substract( char src[], int off, int len ) + throws IOException { + + if ((end - start) == 0) { + if (in == null) + return -1; + int n = in.realReadChars( buff, end, buff.length - end); + if (n < 0) + return -1; + } + + int n = len; + if (len > getLength()) { + n = getLength(); + } + System.arraycopy(buff, start, src, off, n); + start += n; + return n; + + } + + + public void flushBuffer() + throws IOException + { + //assert out!=null + if( out==null ) { + throw new IOException( "Buffer overflow, no sink " + limit + " " + + buff.length ); + } + out.realWriteChars( buff, start, end - start ); + end=start; + } + + /** Make space for len chars. If len is small, allocate + * a reserve space too. Never grow bigger than limit. + */ + private void makeSpace(int count) + { + char[] tmp = null; + + int newSize; + int desiredSize=end + count; + + // Can't grow above the limit + if( limit > 0 && + desiredSize > limit) { + desiredSize=limit; + } + + if( buff==null ) { + if( desiredSize < 256 ) desiredSize=256; // take a minimum + buff=new char[desiredSize]; + } + + // limit < buf.length ( the buffer is already big ) + // or we already have space XXX + if( desiredSize <= buff.length) { + return; + } + // grow in larger chunks + if( desiredSize < 2 * buff.length ) { + newSize= buff.length * 2; + if( limit >0 && + newSize > limit ) newSize=limit; + tmp=new char[newSize]; + } else { + newSize= buff.length * 2 + count ; + if( limit > 0 && + newSize > limit ) newSize=limit; + tmp=new char[newSize]; + } + + System.arraycopy(buff, start, tmp, start, end-start); + buff = tmp; + tmp = null; + } + + // -------------------- Conversion and getters -------------------- + + public String toString() { + if (null == buff) { + return null; + } else if (end-start == 0) { + return ""; + } + return StringCache.toString(this); + } + + public String toStringInternal() { + return new String(buff, start, end-start); + } + + public int getInt() + { + return Ascii.parseInt(buff, start, + end-start); + } + + // -------------------- equals -------------------- + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equals(String s) { + char[] c = buff; + int len = end-start; + if (c == null || len != s.length()) { + return false; + } + int off = start; + for (int i = 0; i < len; i++) { + if (c[off++] != s.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equalsIgnoreCase(String s) { + char[] c = buff; + int len = end-start; + if (c == null || len != s.length()) { + return false; + } + int off = start; + for (int i = 0; i < len; i++) { + if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { + return false; + } + } + return true; + } + + public boolean equals(CharChunk cc) { + return equals( cc.getChars(), cc.getOffset(), cc.getLength()); + } + + public boolean equals(char b2[], int off2, int len2) { + char b1[]=buff; + if( b1==null && b2==null ) return true; + + if (b1== null || b2==null || end-start != len2) { + return false; + } + int off1 = start; + int len=end-start; + while ( len-- > 0) { + if (b1[off1++] != b2[off2++]) { + return false; + } + } + return true; + } + + public boolean equals(byte b2[], int off2, int len2) { + char b1[]=buff; + if( b2==null && b1==null ) return true; + + if (b1== null || b2==null || end-start != len2) { + return false; + } + int off1 = start; + int len=end-start; + + while ( len-- > 0) { + if ( b1[off1++] != (char)b2[off2++]) { + return false; + } + } + return true; + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + */ + public boolean startsWith(String s) { + char[] c = buff; + int len = s.length(); + if (c == null || len > end-start) { + return false; + } + int off = start; + for (int i = 0; i < len; i++) { + if (c[off++] != s.charAt(i)) { + return false; + } + } + return true; + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + */ + public boolean startsWithIgnoreCase(String s, int pos) { + char[] c = buff; + int len = s.length(); + if (c == null || len+pos > end-start) { + return false; + } + int off = start+pos; + for (int i = 0; i < len; i++) { + if (Ascii.toLower( c[off++] ) != Ascii.toLower( s.charAt(i))) { + return false; + } + } + return true; + } + + + // -------------------- Hash code -------------------- + + // normal hash. + public int hash() { + int code=0; + for (int i = start; i < start + end-start; i++) { + code = code * 37 + buff[i]; + } + return code; + } + + // hash ignoring case + public int hashIgnoreCase() { + int code=0; + for (int i = start; i < end; i++) { + code = code * 37 + Ascii.toLower(buff[i]); + } + return code; + } + + public int indexOf(char c) { + return indexOf( c, start); + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param c the character + */ + public int indexOf(char c, int starting) { + int ret = indexOf( buff, start+starting, end, c ); + return (ret >= start) ? ret - start : -1; + } + + public static int indexOf( char chars[], int off, int cend, char qq ) + { + while( off < cend ) { + char b=chars[off]; + if( b==qq ) + return off; + off++; + } + return -1; + } + + + public int indexOf( String src, int srcOff, int srcLen, int myOff ) { + char first=src.charAt( srcOff ); + + // Look for first char + int srcEnd = srcOff + srcLen; + + for( int i=myOff+start; i <= (end - srcLen); i++ ) { + if( buff[i] != first ) continue; + // found first char, now look for a match + int myPos=i+1; + for( int srcPos=srcOff + 1; srcPos< srcEnd; ) { + if( buff[myPos++] != src.charAt( srcPos++ )) + break; + if( srcPos==srcEnd ) return i-start; // found it + } + } + return -1; + } + + // -------------------- utils + private int min(int a, int b) { + if (a < b) return a; + return b; + } + + // Char sequence impl + + public char charAt(int index) { + return buff[index + start]; + } + + public CharSequence subSequence(int start, int end) { + try { + CharChunk result = (CharChunk) this.clone(); + result.setOffset(this.start + start); + result.setEnd(this.start + end); + return result; + } catch (CloneNotSupportedException e) { + // Cannot happen + return null; + } + } + + public int length() { + return end - start; + } + +} diff --git a/java/org/apache/tomcat/util/buf/DateTool.java b/java/org/apache/tomcat/util/buf/DateTool.java index 5d79d46c1..4599963bd 100644 --- a/java/org/apache/tomcat/util/buf/DateTool.java +++ b/java/org/apache/tomcat/util/buf/DateTool.java @@ -1,164 +1,164 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.text.DateFormat; -import java.text.FieldPosition; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.Locale; -import java.util.TimeZone; - -import org.apache.tomcat.util.res.StringManager; - -/** - * Common place for date utils. - * - * @deprecated Will be replaced with a more efficient impl, based on - * FastDateFormat, with an API using less objects. - * @author dac@eng.sun.com - * @author Jason Hunter [jch@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Costin Manolache - */ -public class DateTool { - - /** US locale - all HTTP dates are in english - */ - private final static Locale LOCALE_US = Locale.US; - - /** GMT timezone - all HTTP dates are on GMT - */ - public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); - - /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" - */ - public final static String RFC1123_PATTERN = - "EEE, dd MMM yyyy HH:mm:ss z"; - - // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT" - public final static String rfc1036Pattern = - "EEEEEEEEE, dd-MMM-yy HH:mm:ss z"; - - // format for C asctime() date string -- "Sun Nov 6 08:49:37 1994" - public final static String asctimePattern = - "EEE MMM d HH:mm:ss yyyy"; - - /** Pattern used for old cookies - */ - private final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; - - /** DateFormat to be used to format dates. Called from MessageBytes - */ - private final static DateFormat rfc1123Format = - new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US); - - /** DateFormat to be used to format old netscape cookies - Called from ServerCookie - */ - private final static DateFormat oldCookieFormat = - new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US); - - private final static DateFormat rfc1036Format = - new SimpleDateFormat(rfc1036Pattern, LOCALE_US); - - private final static DateFormat asctimeFormat = - new SimpleDateFormat(asctimePattern, LOCALE_US); - - static { - rfc1123Format.setTimeZone(GMT_ZONE); - oldCookieFormat.setTimeZone(GMT_ZONE); - rfc1036Format.setTimeZone(GMT_ZONE); - asctimeFormat.setTimeZone(GMT_ZONE); - } - - private static String rfc1123DS; - private static long rfc1123Sec; - - private static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.buf.res"); - - // Called from MessageBytes.getTime() - static long parseDate( MessageBytes value ) { - return parseDate( value.toString()); - } - - // Called from MessageBytes.setTime - /** - */ - public static String format1123( Date d ) { - String dstr=null; - synchronized(rfc1123Format) { - dstr = format1123(d, rfc1123Format); - } - return dstr; - } - - public static String format1123( Date d,DateFormat df ) { - long dt = d.getTime() / 1000; - if ((rfc1123DS != null) && (dt == rfc1123Sec)) - return rfc1123DS; - rfc1123DS = df.format( d ); - rfc1123Sec = dt; - return rfc1123DS; - } - - - // Called from ServerCookie - /** - */ - public static void formatOldCookie( Date d, StringBuffer sb, - FieldPosition fp ) - { - synchronized(oldCookieFormat) { - oldCookieFormat.format( d, sb, fp ); - } - } - - // Called from ServerCookie - public static String formatOldCookie( Date d ) - { - String ocf=null; - synchronized(oldCookieFormat) { - ocf= oldCookieFormat.format( d ); - } - return ocf; - } - - - /** Called from HttpServletRequest.getDateHeader(). - Not efficient - but not very used. - */ - public static long parseDate( String dateString ) { - DateFormat [] format = {rfc1123Format,rfc1036Format,asctimeFormat}; - return parseDate(dateString,format); - } - public static long parseDate( String dateString, DateFormat []format ) { - Date date=null; - for(int i=0; i < format.length; i++) { - try { - date = format[i].parse(dateString); - return date.getTime(); - } catch (ParseException e) { } - catch (StringIndexOutOfBoundsException e) { } - } - String msg = sm.getString("httpDate.pe", dateString); - throw new IllegalArgumentException(msg); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.text.DateFormat; +import java.text.FieldPosition; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.util.TimeZone; + +import org.apache.tomcat.util.res.StringManager; + +/** + * Common place for date utils. + * + * @deprecated Will be replaced with a more efficient impl, based on + * FastDateFormat, with an API using less objects. + * @author dac@eng.sun.com + * @author Jason Hunter [jch@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Costin Manolache + */ +public class DateTool { + + /** US locale - all HTTP dates are in english + */ + private final static Locale LOCALE_US = Locale.US; + + /** GMT timezone - all HTTP dates are on GMT + */ + public final static TimeZone GMT_ZONE = TimeZone.getTimeZone("GMT"); + + /** format for RFC 1123 date string -- "Sun, 06 Nov 1994 08:49:37 GMT" + */ + public final static String RFC1123_PATTERN = + "EEE, dd MMM yyyy HH:mm:ss z"; + + // format for RFC 1036 date string -- "Sunday, 06-Nov-94 08:49:37 GMT" + public final static String rfc1036Pattern = + "EEEEEEEEE, dd-MMM-yy HH:mm:ss z"; + + // format for C asctime() date string -- "Sun Nov 6 08:49:37 1994" + public final static String asctimePattern = + "EEE MMM d HH:mm:ss yyyy"; + + /** Pattern used for old cookies + */ + private final static String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; + + /** DateFormat to be used to format dates. Called from MessageBytes + */ + private final static DateFormat rfc1123Format = + new SimpleDateFormat(RFC1123_PATTERN, LOCALE_US); + + /** DateFormat to be used to format old netscape cookies + Called from ServerCookie + */ + private final static DateFormat oldCookieFormat = + new SimpleDateFormat(OLD_COOKIE_PATTERN, LOCALE_US); + + private final static DateFormat rfc1036Format = + new SimpleDateFormat(rfc1036Pattern, LOCALE_US); + + private final static DateFormat asctimeFormat = + new SimpleDateFormat(asctimePattern, LOCALE_US); + + static { + rfc1123Format.setTimeZone(GMT_ZONE); + oldCookieFormat.setTimeZone(GMT_ZONE); + rfc1036Format.setTimeZone(GMT_ZONE); + asctimeFormat.setTimeZone(GMT_ZONE); + } + + private static String rfc1123DS; + private static long rfc1123Sec; + + private static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.buf.res"); + + // Called from MessageBytes.getTime() + static long parseDate( MessageBytes value ) { + return parseDate( value.toString()); + } + + // Called from MessageBytes.setTime + /** + */ + public static String format1123( Date d ) { + String dstr=null; + synchronized(rfc1123Format) { + dstr = format1123(d, rfc1123Format); + } + return dstr; + } + + public static String format1123( Date d,DateFormat df ) { + long dt = d.getTime() / 1000; + if ((rfc1123DS != null) && (dt == rfc1123Sec)) + return rfc1123DS; + rfc1123DS = df.format( d ); + rfc1123Sec = dt; + return rfc1123DS; + } + + + // Called from ServerCookie + /** + */ + public static void formatOldCookie( Date d, StringBuffer sb, + FieldPosition fp ) + { + synchronized(oldCookieFormat) { + oldCookieFormat.format( d, sb, fp ); + } + } + + // Called from ServerCookie + public static String formatOldCookie( Date d ) + { + String ocf=null; + synchronized(oldCookieFormat) { + ocf= oldCookieFormat.format( d ); + } + return ocf; + } + + + /** Called from HttpServletRequest.getDateHeader(). + Not efficient - but not very used. + */ + public static long parseDate( String dateString ) { + DateFormat [] format = {rfc1123Format,rfc1036Format,asctimeFormat}; + return parseDate(dateString,format); + } + public static long parseDate( String dateString, DateFormat []format ) { + Date date=null; + for(int i=0; i < format.length; i++) { + try { + date = format[i].parse(dateString); + return date.getTime(); + } catch (ParseException e) { } + catch (StringIndexOutOfBoundsException e) { } + } + String msg = sm.getString("httpDate.pe", dateString); + throw new IllegalArgumentException(msg); + } + +} diff --git a/java/org/apache/tomcat/util/buf/HexUtils.java b/java/org/apache/tomcat/util/buf/HexUtils.java index f7eab3911..2ad9ae0f0 100644 --- a/java/org/apache/tomcat/util/buf/HexUtils.java +++ b/java/org/apache/tomcat/util/buf/HexUtils.java @@ -1,193 +1,193 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.ByteArrayOutputStream; -import org.apache.tomcat.util.res.StringManager; - -/** - * Library of utility methods useful in dealing with converting byte arrays - * to and from strings of hexadecimal digits. - * Code from Ajp11, from Apache's JServ. - * - * @author Craig R. McClanahan - */ - -public final class HexUtils { - - - // -------------------------------------------------------------- Constants - - - /** - * Table for HEX to DEC byte translation. - */ - public static final int[] DEC = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - }; - - - /** - * Table for DEC to HEX byte translation. - */ - public static final byte[] HEX = - { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', - (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', - (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' }; - - - /** - * The string manager for this package. - */ - private static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.buf.res"); - - - // --------------------------------------------------------- Static Methods - - - /** - * Convert a String of hexadecimal digits into the corresponding - * byte array by encoding each two hexadecimal digits as a byte. - * - * @param digits Hexadecimal digits representation - * - * @exception IllegalArgumentException if an invalid hexadecimal digit - * is found, or the input string contains an odd number of hexadecimal - * digits - */ - public static byte[] convert(String digits) { - - ByteArrayOutputStream baos = new ByteArrayOutputStream(); - for (int i = 0; i < digits.length(); i += 2) { - char c1 = digits.charAt(i); - if ((i+1) >= digits.length()) - throw new IllegalArgumentException - (sm.getString("hexUtil.odd")); - char c2 = digits.charAt(i + 1); - byte b = 0; - if ((c1 >= '0') && (c1 <= '9')) - b += ((c1 - '0') * 16); - else if ((c1 >= 'a') && (c1 <= 'f')) - b += ((c1 - 'a' + 10) * 16); - else if ((c1 >= 'A') && (c1 <= 'F')) - b += ((c1 - 'A' + 10) * 16); - else - throw new IllegalArgumentException - (sm.getString("hexUtil.bad")); - if ((c2 >= '0') && (c2 <= '9')) - b += (c2 - '0'); - else if ((c2 >= 'a') && (c2 <= 'f')) - b += (c2 - 'a' + 10); - else if ((c2 >= 'A') && (c2 <= 'F')) - b += (c2 - 'A' + 10); - else - throw new IllegalArgumentException - (sm.getString("hexUtil.bad")); - baos.write(b); - } - return (baos.toByteArray()); - - } - - - /** - * Convert a byte array into a printable format containing a - * String of hexadecimal digit characters (two per byte). - * - * @param bytes Byte array representation - */ - public static String convert(byte bytes[]) { - - StringBuffer sb = new StringBuffer(bytes.length * 2); - for (int i = 0; i < bytes.length; i++) { - sb.append(convertDigit((int) (bytes[i] >> 4))); - sb.append(convertDigit((int) (bytes[i] & 0x0f))); - } - return (sb.toString()); - - } - - /** - * Convert 4 hex digits to an int, and return the number of converted - * bytes. - * - * @param hex Byte array containing exactly four hexadecimal digits - * - * @exception IllegalArgumentException if an invalid hexadecimal digit - * is included - */ - public static int convert2Int( byte[] hex ) { - // Code from Ajp11, from Apache's JServ - - // assert b.length==4 - // assert valid data - int len; - if(hex.length < 4 ) return 0; - if( DEC[hex[0]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len = DEC[hex[0]]; - len = len << 4; - if( DEC[hex[1]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[1]]; - len = len << 4; - if( DEC[hex[2]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[2]]; - len = len << 4; - if( DEC[hex[3]]<0 ) - throw new IllegalArgumentException(sm.getString("hexUtil.bad")); - len += DEC[hex[3]]; - return len; - } - - - - /** - * [Private] Convert the specified value (0 .. 15) to the corresponding - * hexadecimal digit. - * - * @param value Value to be converted - */ - private static char convertDigit(int value) { - - value &= 0x0f; - if (value >= 10) - return ((char) (value - 10 + 'a')); - else - return ((char) (value + '0')); - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.ByteArrayOutputStream; +import org.apache.tomcat.util.res.StringManager; + +/** + * Library of utility methods useful in dealing with converting byte arrays + * to and from strings of hexadecimal digits. + * Code from Ajp11, from Apache's JServ. + * + * @author Craig R. McClanahan + */ + +public final class HexUtils { + + + // -------------------------------------------------------------- Constants + + + /** + * Table for HEX to DEC byte translation. + */ + public static final int[] DEC = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 00, 01, 02, 03, 04, 05, 06, 07, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + }; + + + /** + * Table for DEC to HEX byte translation. + */ + public static final byte[] HEX = + { (byte) '0', (byte) '1', (byte) '2', (byte) '3', (byte) '4', (byte) '5', + (byte) '6', (byte) '7', (byte) '8', (byte) '9', (byte) 'a', (byte) 'b', + (byte) 'c', (byte) 'd', (byte) 'e', (byte) 'f' }; + + + /** + * The string manager for this package. + */ + private static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.buf.res"); + + + // --------------------------------------------------------- Static Methods + + + /** + * Convert a String of hexadecimal digits into the corresponding + * byte array by encoding each two hexadecimal digits as a byte. + * + * @param digits Hexadecimal digits representation + * + * @exception IllegalArgumentException if an invalid hexadecimal digit + * is found, or the input string contains an odd number of hexadecimal + * digits + */ + public static byte[] convert(String digits) { + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + for (int i = 0; i < digits.length(); i += 2) { + char c1 = digits.charAt(i); + if ((i+1) >= digits.length()) + throw new IllegalArgumentException + (sm.getString("hexUtil.odd")); + char c2 = digits.charAt(i + 1); + byte b = 0; + if ((c1 >= '0') && (c1 <= '9')) + b += ((c1 - '0') * 16); + else if ((c1 >= 'a') && (c1 <= 'f')) + b += ((c1 - 'a' + 10) * 16); + else if ((c1 >= 'A') && (c1 <= 'F')) + b += ((c1 - 'A' + 10) * 16); + else + throw new IllegalArgumentException + (sm.getString("hexUtil.bad")); + if ((c2 >= '0') && (c2 <= '9')) + b += (c2 - '0'); + else if ((c2 >= 'a') && (c2 <= 'f')) + b += (c2 - 'a' + 10); + else if ((c2 >= 'A') && (c2 <= 'F')) + b += (c2 - 'A' + 10); + else + throw new IllegalArgumentException + (sm.getString("hexUtil.bad")); + baos.write(b); + } + return (baos.toByteArray()); + + } + + + /** + * Convert a byte array into a printable format containing a + * String of hexadecimal digit characters (two per byte). + * + * @param bytes Byte array representation + */ + public static String convert(byte bytes[]) { + + StringBuffer sb = new StringBuffer(bytes.length * 2); + for (int i = 0; i < bytes.length; i++) { + sb.append(convertDigit((int) (bytes[i] >> 4))); + sb.append(convertDigit((int) (bytes[i] & 0x0f))); + } + return (sb.toString()); + + } + + /** + * Convert 4 hex digits to an int, and return the number of converted + * bytes. + * + * @param hex Byte array containing exactly four hexadecimal digits + * + * @exception IllegalArgumentException if an invalid hexadecimal digit + * is included + */ + public static int convert2Int( byte[] hex ) { + // Code from Ajp11, from Apache's JServ + + // assert b.length==4 + // assert valid data + int len; + if(hex.length < 4 ) return 0; + if( DEC[hex[0]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len = DEC[hex[0]]; + len = len << 4; + if( DEC[hex[1]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[1]]; + len = len << 4; + if( DEC[hex[2]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[2]]; + len = len << 4; + if( DEC[hex[3]]<0 ) + throw new IllegalArgumentException(sm.getString("hexUtil.bad")); + len += DEC[hex[3]]; + return len; + } + + + + /** + * [Private] Convert the specified value (0 .. 15) to the corresponding + * hexadecimal digit. + * + * @param value Value to be converted + */ + private static char convertDigit(int value) { + + value &= 0x0f; + if (value >= 10) + return ((char) (value - 10 + 'a')); + else + return ((char) (value + '0')); + + } + + +} diff --git a/java/org/apache/tomcat/util/buf/MessageBytes.java b/java/org/apache/tomcat/util/buf/MessageBytes.java index 0d5bb3086..2693147b7 100644 --- a/java/org/apache/tomcat/util/buf/MessageBytes.java +++ b/java/org/apache/tomcat/util/buf/MessageBytes.java @@ -1,732 +1,732 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.text.*; -import java.util.*; -import java.io.Serializable; -import java.io.IOException; - -/** - * This class is used to represent a subarray of bytes in an HTTP message. - * It represents all request/response elements. The byte/char conversions are - * delayed and cached. Everything is recyclable. - * - * The object can represent a byte[], a char[], or a (sub) String. All - * operations can be made in case sensitive mode or not. - * - * @author dac@eng.sun.com - * @author James Todd [gonzo@eng.sun.com] - * @author Costin Manolache - */ -public final class MessageBytes implements Cloneable, Serializable { - // primary type ( whatever is set as original value ) - private int type = T_NULL; - - public static final int T_NULL = 0; - /** getType() is T_STR if the the object used to create the MessageBytes - was a String */ - public static final int T_STR = 1; - /** getType() is T_STR if the the object used to create the MessageBytes - was a byte[] */ - public static final int T_BYTES = 2; - /** getType() is T_STR if the the object used to create the MessageBytes - was a char[] */ - public static final int T_CHARS = 3; - - private int hashCode=0; - // did we computed the hashcode ? - private boolean hasHashCode=false; - - // Is the represented object case sensitive ? - private boolean caseSensitive=true; - - // Internal objects to represent array + offset, and specific methods - private ByteChunk byteC=new ByteChunk(); - private CharChunk charC=new CharChunk(); - - // String - private String strValue; - // true if a String value was computed. Probably not needed, - // strValue!=null is the same - private boolean hasStrValue=false; - - /** - * Creates a new, uninitialized MessageBytes object. - * @deprecated Use static newInstance() in order to allow - * future hooks. - */ - public MessageBytes() { - } - - /** Construct a new MessageBytes instance - */ - public static MessageBytes newInstance() { - return factory.newInstance(); - } - - /** Configure the case sensitivity - */ - public void setCaseSenitive( boolean b ) { - caseSensitive=b; - } - - public MessageBytes getClone() { - try { - return (MessageBytes)this.clone(); - } catch( Exception ex) { - return null; - } - } - - public boolean isNull() { -// should we check also hasStrValue ??? - return byteC.isNull() && charC.isNull() && ! hasStrValue; - // bytes==null && strValue==null; - } - - /** - * Resets the message bytes to an uninitialized (NULL) state. - */ - public void recycle() { - type=T_NULL; - byteC.recycle(); - charC.recycle(); - - strValue=null; - caseSensitive=true; - - hasStrValue=false; - hasHashCode=false; - hasIntValue=false; - hasLongValue=false; - hasDateValue=false; - } - - - /** - * Sets the content to the specified subarray of bytes. - * - * @param b the bytes - * @param off the start offset of the bytes - * @param len the length of the bytes - */ - public void setBytes(byte[] b, int off, int len) { - byteC.setBytes( b, off, len ); - type=T_BYTES; - hasStrValue=false; - hasHashCode=false; - hasIntValue=false; - hasLongValue=false; - hasDateValue=false; - } - - /** Set the encoding. If the object was constructed from bytes[]. any - * previous conversion is reset. - * If no encoding is set, we'll use 8859-1. - */ - public void setEncoding( String enc ) { - if( !byteC.isNull() ) { - // if the encoding changes we need to reset the converion results - charC.recycle(); - hasStrValue=false; - } - byteC.setEncoding(enc); - } - - /** - * Sets the content to be a char[] - * - * @param c the bytes - * @param off the start offset of the bytes - * @param len the length of the bytes - */ - public void setChars( char[] c, int off, int len ) { - charC.setChars( c, off, len ); - type=T_CHARS; - hasStrValue=false; - hasHashCode=false; - hasIntValue=false; - hasLongValue=false; - hasDateValue=false; - } - - /** Remove the cached string value. Use it after a conversion on the - * byte[] or after the encoding is changed - * XXX Is this needed ? - */ - public void resetStringValue() { - if( type != T_STR ) { - // If this was cread as a byte[] or char[], we remove - // the old string value - hasStrValue=false; - strValue=null; - } - } - - /** - * Set the content to be a string - */ - public void setString( String s ) { - if (s == null) - return; - strValue=s; - hasStrValue=true; - hasHashCode=false; - hasIntValue=false; - hasLongValue=false; - hasDateValue=false; - type=T_STR; - } - - // -------------------- Conversion and getters -------------------- - - /** Compute the string value - */ - public String toString() { - if( hasStrValue ) return strValue; - - switch (type) { - case T_CHARS: - strValue=charC.toString(); - hasStrValue=true; - return strValue; - case T_BYTES: - strValue=byteC.toString(); - hasStrValue=true; - return strValue; - } - return null; - } - - //---------------------------------------- - /** Return the type of the original content. Can be - * T_STR, T_BYTES, T_CHARS or T_NULL - */ - public int getType() { - return type; - } - - /** - * Returns the byte chunk, representing the byte[] and offset/length. - * Valid only if T_BYTES or after a conversion was made. - */ - public ByteChunk getByteChunk() { - return byteC; - } - - /** - * Returns the char chunk, representing the char[] and offset/length. - * Valid only if T_CHARS or after a conversion was made. - */ - public CharChunk getCharChunk() { - return charC; - } - - /** - * Returns the string value. - * Valid only if T_STR or after a conversion was made. - */ - public String getString() { - return strValue; - } - - /** Unimplemented yet. Do a char->byte conversion. - */ - public void toBytes() { - if( ! byteC.isNull() ) { - type=T_BYTES; - return; - } - toString(); - type=T_BYTES; - byte bb[] = strValue.getBytes(); - byteC.setBytes(bb, 0, bb.length); - } - - /** Convert to char[] and fill the CharChunk. - * XXX Not optimized - it converts to String first. - */ - public void toChars() { - if( ! charC.isNull() ) { - type=T_CHARS; - return; - } - // inefficient - toString(); - type=T_CHARS; - char cc[]=strValue.toCharArray(); - charC.setChars(cc, 0, cc.length); - } - - - /** - * Returns the length of the original buffer. - * Note that the length in bytes may be different from the length - * in chars. - */ - public int getLength() { - if(type==T_BYTES) - return byteC.getLength(); - if(type==T_CHARS) { - return charC.getLength(); - } - if(type==T_STR) - return strValue.length(); - toString(); - if( strValue==null ) return 0; - return strValue.length(); - } - - // -------------------- equals -------------------- - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equals(String s) { - if( ! caseSensitive ) - return equalsIgnoreCase( s ); - switch (type) { - case T_STR: - if( strValue==null && s!=null) return false; - return strValue.equals( s ); - case T_CHARS: - return charC.equals( s ); - case T_BYTES: - return byteC.equals( s ); - default: - return false; - } - } - - /** - * Compares the message bytes to the specified String object. - * @param s the String to compare - * @return true if the comparison succeeded, false otherwise - */ - public boolean equalsIgnoreCase(String s) { - switch (type) { - case T_STR: - if( strValue==null && s!=null) return false; - return strValue.equalsIgnoreCase( s ); - case T_CHARS: - return charC.equalsIgnoreCase( s ); - case T_BYTES: - return byteC.equalsIgnoreCase( s ); - default: - return false; - } - } - - public boolean equals(MessageBytes mb) { - switch (type) { - case T_STR: - return mb.equals( strValue ); - } - - if( mb.type != T_CHARS && - mb.type!= T_BYTES ) { - // it's a string or int/date string value - return equals( mb.toString() ); - } - - // mb is either CHARS or BYTES. - // this is either CHARS or BYTES - // Deal with the 4 cases ( in fact 3, one is simetric) - - if( mb.type == T_CHARS && type==T_CHARS ) { - return charC.equals( mb.charC ); - } - if( mb.type==T_BYTES && type== T_BYTES ) { - return byteC.equals( mb.byteC ); - } - if( mb.type== T_CHARS && type== T_BYTES ) { - return byteC.equals( mb.charC ); - } - if( mb.type== T_BYTES && type== T_CHARS ) { - return mb.byteC.equals( charC ); - } - // can't happen - return true; - } - - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - */ - public boolean startsWith(String s) { - switch (type) { - case T_STR: - return strValue.startsWith( s ); - case T_CHARS: - return charC.startsWith( s ); - case T_BYTES: - return byteC.startsWith( s ); - default: - return false; - } - } - - /** - * Returns true if the message bytes starts with the specified string. - * @param s the string - * @param pos The start position - */ - public boolean startsWithIgnoreCase(String s, int pos) { - switch (type) { - case T_STR: - if( strValue==null ) return false; - if( strValue.length() < pos + s.length() ) return false; - - for( int i=0; i 0) { - int digit = current % 10; - current = current / 10; - buf[end++] = HexUtils.HEX[digit]; - } - byteC.setOffset(0); - byteC.setEnd(end); - // Inverting buffer - end--; - if (i < 0) { - start++; - } - while (end > start) { - byte temp = buf[start]; - buf[start] = buf[end]; - buf[end] = temp; - start++; - end--; - } - intValue=i; - hasStrValue=false; - hasHashCode=false; - hasIntValue=true; - hasLongValue=false; - hasDateValue=false; - type=T_BYTES; - } - - /** Set the buffer to the representation of an long - */ - public void setLong(long l) { - byteC.allocate(32, 64); - long current = l; - byte[] buf = byteC.getBuffer(); - int start = 0; - int end = 0; - if (l == 0) { - buf[end++] = (byte) '0'; - } - if (l < 0) { - current = -l; - buf[end++] = (byte) '-'; - } - while (current > 0) { - int digit = (int) (current % 10); - current = current / 10; - buf[end++] = HexUtils.HEX[digit]; - } - byteC.setOffset(0); - byteC.setEnd(end); - // Inverting buffer - end--; - if (l < 0) { - start++; - } - while (end > start) { - byte temp = buf[start]; - buf[start] = buf[end]; - buf[end] = temp; - start++; - end--; - } - longValue=l; - hasStrValue=false; - hasHashCode=false; - hasIntValue=false; - hasLongValue=true; - hasDateValue=false; - type=T_BYTES; - } - - /** - * @deprecated The buffer are general purpose, caching for headers should - * be done in headers - */ - public long getTime() - { - if( hasDateValue ) { - if( dateValue==null) return -1; - return dateValue.getTime(); - } - - long l=DateTool.parseDate( this ); - if( dateValue==null) - dateValue=new Date(l); - else - dateValue.setTime(l); - hasDateValue=true; - return l; - } - - - // Used for headers conversion - /** Convert the buffer to an int, cache the value - */ - public int getInt() - { - if( hasIntValue ) - return intValue; - - switch (type) { - case T_BYTES: - intValue=byteC.getInt(); - break; - default: - intValue=Integer.parseInt(toString()); - } - hasIntValue=true; - return intValue; - } - - // Used for headers conversion - /** Convert the buffer to an long, cache the value - */ - public long getLong() { - if( hasLongValue ) - return longValue; - - switch (type) { - case T_BYTES: - longValue=byteC.getLong(); - break; - default: - longValue=Long.parseLong(toString()); - } - - hasLongValue=true; - return longValue; - - } - - // -------------------- Future may be different -------------------- - - private static MessageBytesFactory factory=new MessageBytesFactory(); - - public static void setFactory( MessageBytesFactory mbf ) { - factory=mbf; - } - - public static class MessageBytesFactory { - protected MessageBytesFactory() { - } - public MessageBytes newInstance() { - return new MessageBytes(); - } - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.text.*; +import java.util.*; +import java.io.Serializable; +import java.io.IOException; + +/** + * This class is used to represent a subarray of bytes in an HTTP message. + * It represents all request/response elements. The byte/char conversions are + * delayed and cached. Everything is recyclable. + * + * The object can represent a byte[], a char[], or a (sub) String. All + * operations can be made in case sensitive mode or not. + * + * @author dac@eng.sun.com + * @author James Todd [gonzo@eng.sun.com] + * @author Costin Manolache + */ +public final class MessageBytes implements Cloneable, Serializable { + // primary type ( whatever is set as original value ) + private int type = T_NULL; + + public static final int T_NULL = 0; + /** getType() is T_STR if the the object used to create the MessageBytes + was a String */ + public static final int T_STR = 1; + /** getType() is T_STR if the the object used to create the MessageBytes + was a byte[] */ + public static final int T_BYTES = 2; + /** getType() is T_STR if the the object used to create the MessageBytes + was a char[] */ + public static final int T_CHARS = 3; + + private int hashCode=0; + // did we computed the hashcode ? + private boolean hasHashCode=false; + + // Is the represented object case sensitive ? + private boolean caseSensitive=true; + + // Internal objects to represent array + offset, and specific methods + private ByteChunk byteC=new ByteChunk(); + private CharChunk charC=new CharChunk(); + + // String + private String strValue; + // true if a String value was computed. Probably not needed, + // strValue!=null is the same + private boolean hasStrValue=false; + + /** + * Creates a new, uninitialized MessageBytes object. + * @deprecated Use static newInstance() in order to allow + * future hooks. + */ + public MessageBytes() { + } + + /** Construct a new MessageBytes instance + */ + public static MessageBytes newInstance() { + return factory.newInstance(); + } + + /** Configure the case sensitivity + */ + public void setCaseSenitive( boolean b ) { + caseSensitive=b; + } + + public MessageBytes getClone() { + try { + return (MessageBytes)this.clone(); + } catch( Exception ex) { + return null; + } + } + + public boolean isNull() { +// should we check also hasStrValue ??? + return byteC.isNull() && charC.isNull() && ! hasStrValue; + // bytes==null && strValue==null; + } + + /** + * Resets the message bytes to an uninitialized (NULL) state. + */ + public void recycle() { + type=T_NULL; + byteC.recycle(); + charC.recycle(); + + strValue=null; + caseSensitive=true; + + hasStrValue=false; + hasHashCode=false; + hasIntValue=false; + hasLongValue=false; + hasDateValue=false; + } + + + /** + * Sets the content to the specified subarray of bytes. + * + * @param b the bytes + * @param off the start offset of the bytes + * @param len the length of the bytes + */ + public void setBytes(byte[] b, int off, int len) { + byteC.setBytes( b, off, len ); + type=T_BYTES; + hasStrValue=false; + hasHashCode=false; + hasIntValue=false; + hasLongValue=false; + hasDateValue=false; + } + + /** Set the encoding. If the object was constructed from bytes[]. any + * previous conversion is reset. + * If no encoding is set, we'll use 8859-1. + */ + public void setEncoding( String enc ) { + if( !byteC.isNull() ) { + // if the encoding changes we need to reset the converion results + charC.recycle(); + hasStrValue=false; + } + byteC.setEncoding(enc); + } + + /** + * Sets the content to be a char[] + * + * @param c the bytes + * @param off the start offset of the bytes + * @param len the length of the bytes + */ + public void setChars( char[] c, int off, int len ) { + charC.setChars( c, off, len ); + type=T_CHARS; + hasStrValue=false; + hasHashCode=false; + hasIntValue=false; + hasLongValue=false; + hasDateValue=false; + } + + /** Remove the cached string value. Use it after a conversion on the + * byte[] or after the encoding is changed + * XXX Is this needed ? + */ + public void resetStringValue() { + if( type != T_STR ) { + // If this was cread as a byte[] or char[], we remove + // the old string value + hasStrValue=false; + strValue=null; + } + } + + /** + * Set the content to be a string + */ + public void setString( String s ) { + if (s == null) + return; + strValue=s; + hasStrValue=true; + hasHashCode=false; + hasIntValue=false; + hasLongValue=false; + hasDateValue=false; + type=T_STR; + } + + // -------------------- Conversion and getters -------------------- + + /** Compute the string value + */ + public String toString() { + if( hasStrValue ) return strValue; + + switch (type) { + case T_CHARS: + strValue=charC.toString(); + hasStrValue=true; + return strValue; + case T_BYTES: + strValue=byteC.toString(); + hasStrValue=true; + return strValue; + } + return null; + } + + //---------------------------------------- + /** Return the type of the original content. Can be + * T_STR, T_BYTES, T_CHARS or T_NULL + */ + public int getType() { + return type; + } + + /** + * Returns the byte chunk, representing the byte[] and offset/length. + * Valid only if T_BYTES or after a conversion was made. + */ + public ByteChunk getByteChunk() { + return byteC; + } + + /** + * Returns the char chunk, representing the char[] and offset/length. + * Valid only if T_CHARS or after a conversion was made. + */ + public CharChunk getCharChunk() { + return charC; + } + + /** + * Returns the string value. + * Valid only if T_STR or after a conversion was made. + */ + public String getString() { + return strValue; + } + + /** Unimplemented yet. Do a char->byte conversion. + */ + public void toBytes() { + if( ! byteC.isNull() ) { + type=T_BYTES; + return; + } + toString(); + type=T_BYTES; + byte bb[] = strValue.getBytes(); + byteC.setBytes(bb, 0, bb.length); + } + + /** Convert to char[] and fill the CharChunk. + * XXX Not optimized - it converts to String first. + */ + public void toChars() { + if( ! charC.isNull() ) { + type=T_CHARS; + return; + } + // inefficient + toString(); + type=T_CHARS; + char cc[]=strValue.toCharArray(); + charC.setChars(cc, 0, cc.length); + } + + + /** + * Returns the length of the original buffer. + * Note that the length in bytes may be different from the length + * in chars. + */ + public int getLength() { + if(type==T_BYTES) + return byteC.getLength(); + if(type==T_CHARS) { + return charC.getLength(); + } + if(type==T_STR) + return strValue.length(); + toString(); + if( strValue==null ) return 0; + return strValue.length(); + } + + // -------------------- equals -------------------- + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equals(String s) { + if( ! caseSensitive ) + return equalsIgnoreCase( s ); + switch (type) { + case T_STR: + if( strValue==null && s!=null) return false; + return strValue.equals( s ); + case T_CHARS: + return charC.equals( s ); + case T_BYTES: + return byteC.equals( s ); + default: + return false; + } + } + + /** + * Compares the message bytes to the specified String object. + * @param s the String to compare + * @return true if the comparison succeeded, false otherwise + */ + public boolean equalsIgnoreCase(String s) { + switch (type) { + case T_STR: + if( strValue==null && s!=null) return false; + return strValue.equalsIgnoreCase( s ); + case T_CHARS: + return charC.equalsIgnoreCase( s ); + case T_BYTES: + return byteC.equalsIgnoreCase( s ); + default: + return false; + } + } + + public boolean equals(MessageBytes mb) { + switch (type) { + case T_STR: + return mb.equals( strValue ); + } + + if( mb.type != T_CHARS && + mb.type!= T_BYTES ) { + // it's a string or int/date string value + return equals( mb.toString() ); + } + + // mb is either CHARS or BYTES. + // this is either CHARS or BYTES + // Deal with the 4 cases ( in fact 3, one is simetric) + + if( mb.type == T_CHARS && type==T_CHARS ) { + return charC.equals( mb.charC ); + } + if( mb.type==T_BYTES && type== T_BYTES ) { + return byteC.equals( mb.byteC ); + } + if( mb.type== T_CHARS && type== T_BYTES ) { + return byteC.equals( mb.charC ); + } + if( mb.type== T_BYTES && type== T_CHARS ) { + return mb.byteC.equals( charC ); + } + // can't happen + return true; + } + + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + */ + public boolean startsWith(String s) { + switch (type) { + case T_STR: + return strValue.startsWith( s ); + case T_CHARS: + return charC.startsWith( s ); + case T_BYTES: + return byteC.startsWith( s ); + default: + return false; + } + } + + /** + * Returns true if the message bytes starts with the specified string. + * @param s the string + * @param pos The start position + */ + public boolean startsWithIgnoreCase(String s, int pos) { + switch (type) { + case T_STR: + if( strValue==null ) return false; + if( strValue.length() < pos + s.length() ) return false; + + for( int i=0; i 0) { + int digit = current % 10; + current = current / 10; + buf[end++] = HexUtils.HEX[digit]; + } + byteC.setOffset(0); + byteC.setEnd(end); + // Inverting buffer + end--; + if (i < 0) { + start++; + } + while (end > start) { + byte temp = buf[start]; + buf[start] = buf[end]; + buf[end] = temp; + start++; + end--; + } + intValue=i; + hasStrValue=false; + hasHashCode=false; + hasIntValue=true; + hasLongValue=false; + hasDateValue=false; + type=T_BYTES; + } + + /** Set the buffer to the representation of an long + */ + public void setLong(long l) { + byteC.allocate(32, 64); + long current = l; + byte[] buf = byteC.getBuffer(); + int start = 0; + int end = 0; + if (l == 0) { + buf[end++] = (byte) '0'; + } + if (l < 0) { + current = -l; + buf[end++] = (byte) '-'; + } + while (current > 0) { + int digit = (int) (current % 10); + current = current / 10; + buf[end++] = HexUtils.HEX[digit]; + } + byteC.setOffset(0); + byteC.setEnd(end); + // Inverting buffer + end--; + if (l < 0) { + start++; + } + while (end > start) { + byte temp = buf[start]; + buf[start] = buf[end]; + buf[end] = temp; + start++; + end--; + } + longValue=l; + hasStrValue=false; + hasHashCode=false; + hasIntValue=false; + hasLongValue=true; + hasDateValue=false; + type=T_BYTES; + } + + /** + * @deprecated The buffer are general purpose, caching for headers should + * be done in headers + */ + public long getTime() + { + if( hasDateValue ) { + if( dateValue==null) return -1; + return dateValue.getTime(); + } + + long l=DateTool.parseDate( this ); + if( dateValue==null) + dateValue=new Date(l); + else + dateValue.setTime(l); + hasDateValue=true; + return l; + } + + + // Used for headers conversion + /** Convert the buffer to an int, cache the value + */ + public int getInt() + { + if( hasIntValue ) + return intValue; + + switch (type) { + case T_BYTES: + intValue=byteC.getInt(); + break; + default: + intValue=Integer.parseInt(toString()); + } + hasIntValue=true; + return intValue; + } + + // Used for headers conversion + /** Convert the buffer to an long, cache the value + */ + public long getLong() { + if( hasLongValue ) + return longValue; + + switch (type) { + case T_BYTES: + longValue=byteC.getLong(); + break; + default: + longValue=Long.parseLong(toString()); + } + + hasLongValue=true; + return longValue; + + } + + // -------------------- Future may be different -------------------- + + private static MessageBytesFactory factory=new MessageBytesFactory(); + + public static void setFactory( MessageBytesFactory mbf ) { + factory=mbf; + } + + public static class MessageBytesFactory { + protected MessageBytesFactory() { + } + public MessageBytes newInstance() { + return new MessageBytes(); + } + } +} diff --git a/java/org/apache/tomcat/util/buf/StringCache.java b/java/org/apache/tomcat/util/buf/StringCache.java index 655d44f70..0ee27aa2c 100644 --- a/java/org/apache/tomcat/util/buf/StringCache.java +++ b/java/org/apache/tomcat/util/buf/StringCache.java @@ -1,669 +1,669 @@ -/* - * Copyright 1999-2005 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.TreeMap; - -/** - * This class implements a String cache for ByteChunk and CharChunk. - * - * @author Remy Maucherat - */ -public class StringCache { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( StringCache.class ); - - - // ------------------------------------------------------- Static Variables - - - /** - * Enabled ? - */ - protected static boolean byteEnabled = - ("true".equals(System.getProperty("tomcat.util.buf.StringCache.byte.enabled", "false"))); - - - protected static boolean charEnabled = - ("true".equals(System.getProperty("tomcat.util.buf.StringCache.char.enabled", "false"))); - - - protected static int trainThreshold = - Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.trainThreshold", "20000")); - - - protected static int cacheSize = - Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.cacheSize", "200")); - - - /** - * Statistics hash map for byte chunk. - */ - protected static HashMap bcStats = new HashMap(cacheSize); - - - /** - * toString count for byte chunk. - */ - protected static int bcCount = 0; - - - /** - * Cache for byte chunk. - */ - protected static ByteEntry[] bcCache = null; - - - /** - * Statistics hash map for char chunk. - */ - protected static HashMap ccStats = new HashMap(cacheSize); - - - /** - * toString count for char chunk. - */ - protected static int ccCount = 0; - - - /** - * Cache for char chunk. - */ - protected static CharEntry[] ccCache = null; - - - /** - * Access count. - */ - protected static int accessCount = 0; - - - /** - * Hit count. - */ - protected static int hitCount = 0; - - - // ------------------------------------------------------------ Properties - - - /** - * @return Returns the cacheSize. - */ - public int getCacheSize() { - return cacheSize; - } - - - /** - * @param cacheSize The cacheSize to set. - */ - public void setCacheSize(int cacheSize) { - StringCache.cacheSize = cacheSize; - } - - - /** - * @return Returns the enabled. - */ - public boolean getByteEnabled() { - return byteEnabled; - } - - - /** - * @param byteEnabled The enabled to set. - */ - public void setByteEnabled(boolean byteEnabled) { - StringCache.byteEnabled = byteEnabled; - } - - - /** - * @return Returns the enabled. - */ - public boolean getCharEnabled() { - return charEnabled; - } - - - /** - * @param charEnabled The enabled to set. - */ - public void setCharEnabled(boolean charEnabled) { - StringCache.charEnabled = charEnabled; - } - - - /** - * @return Returns the trainThreshold. - */ - public int getTrainThreshold() { - return trainThreshold; - } - - - /** - * @param trainThreshold The trainThreshold to set. - */ - public void setTrainThreshold(int trainThreshold) { - StringCache.trainThreshold = trainThreshold; - } - - - /** - * @return Returns the accessCount. - */ - public int getAccessCount() { - return accessCount; - } - - - /** - * @return Returns the hitCount. - */ - public int getHitCount() { - return hitCount; - } - - - // -------------------------------------------------- Public Static Methods - - - public void reset() { - hitCount = 0; - accessCount = 0; - synchronized (bcStats) { - bcCache = null; - bcCount = 0; - } - synchronized (ccStats) { - ccCache = null; - ccCount = 0; - } - } - - - public static String toString(ByteChunk bc) { - - // If the cache is null, then either caching is disabled, or we're - // still training - if (bcCache == null) { - String value = bc.toStringInternal(); - if (byteEnabled) { - // If training, everything is synced - synchronized (bcStats) { - // If the cache has been generated on a previous invocation - // while waiting fot the lock, just return the toString value - // we just calculated - if (bcCache != null) { - return value; - } - // Two cases: either we just exceeded the train count, in which - // case the cache must be created, or we just update the count for - // the string - if (bcCount > trainThreshold) { - long t1 = System.currentTimeMillis(); - // Sort the entries according to occurrence - TreeMap tempMap = new TreeMap(); - Iterator entries = bcStats.keySet().iterator(); - while (entries.hasNext()) { - ByteEntry entry = (ByteEntry) entries.next(); - int[] countA = (int[]) bcStats.get(entry); - Integer count = new Integer(countA[0]); - // Add to the list for that count - ArrayList list = (ArrayList) tempMap.get(count); - if (list == null) { - // Create list - list = new ArrayList(); - tempMap.put(count, list); - } - list.add(entry); - } - // Allocate array of the right size - int size = bcStats.size(); - if (size > cacheSize) { - size = cacheSize; - } - ByteEntry[] tempbcCache = new ByteEntry[size]; - // Fill it up using an alphabetical order - // and a dumb insert sort - ByteChunk tempChunk = new ByteChunk(); - int n = 0; - while (n < size) { - Object key = tempMap.lastKey(); - ArrayList list = (ArrayList) tempMap.get(key); - ByteEntry[] list2 = - (ByteEntry[]) list.toArray(new ByteEntry[list.size()]); - for (int i = 0; i < list.size() && n < size; i++) { - ByteEntry entry = (ByteEntry) list.get(i); - tempChunk.setBytes(entry.name, 0, entry.name.length); - int insertPos = findClosest(tempChunk, tempbcCache, n); - if (insertPos == n) { - tempbcCache[n + 1] = entry; - } else { - System.arraycopy(tempbcCache, insertPos + 1, tempbcCache, - insertPos + 2, n - insertPos - 1); - tempbcCache[insertPos + 1] = entry; - } - n++; - } - tempMap.remove(key); - } - bcCount = 0; - bcStats.clear(); - bcCache = tempbcCache; - if (log.isDebugEnabled()) { - long t2 = System.currentTimeMillis(); - log.debug("ByteCache generation time: " + (t2 - t1) + "ms"); - } - } else { - bcCount++; - // Allocate new ByteEntry for the lookup - ByteEntry entry = new ByteEntry(); - entry.value = value; - int[] count = (int[]) bcStats.get(entry); - if (count == null) { - int end = bc.getEnd(); - int start = bc.getStart(); - // Create byte array and copy bytes - entry.name = new byte[bc.getLength()]; - System.arraycopy(bc.getBuffer(), start, entry.name, 0, end - start); - // Set encoding - entry.enc = bc.getEncoding(); - // Initialize occurrence count to one - count = new int[1]; - count[0] = 1; - // Set in the stats hash map - bcStats.put(entry, count); - } else { - count[0] = count[0] + 1; - } - } - } - } - return value; - } else { - accessCount++; - // Find the corresponding String - String result = find(bc); - if (result == null) { - return bc.toStringInternal(); - } - // Note: We don't care about safety for the stats - hitCount++; - return result; - } - - } - - - public static String toString(CharChunk cc) { - - // If the cache is null, then either caching is disabled, or we're - // still training - if (ccCache == null) { - String value = cc.toStringInternal(); - if (charEnabled) { - // If training, everything is synced - synchronized (ccStats) { - // If the cache has been generated on a previous invocation - // while waiting fot the lock, just return the toString value - // we just calculated - if (ccCache != null) { - return value; - } - // Two cases: either we just exceeded the train count, in which - // case the cache must be created, or we just update the count for - // the string - if (ccCount > trainThreshold) { - long t1 = System.currentTimeMillis(); - // Sort the entries according to occurrence - TreeMap tempMap = new TreeMap(); - Iterator entries = ccStats.keySet().iterator(); - while (entries.hasNext()) { - CharEntry entry = (CharEntry) entries.next(); - int[] countA = (int[]) ccStats.get(entry); - Integer count = new Integer(countA[0]); - // Add to the list for that count - ArrayList list = (ArrayList) tempMap.get(count); - if (list == null) { - // Create list - list = new ArrayList(); - tempMap.put(count, list); - } - list.add(entry); - } - // Allocate array of the right size - int size = ccStats.size(); - if (size > cacheSize) { - size = cacheSize; - } - CharEntry[] tempccCache = new CharEntry[size]; - // Fill it up using an alphabetical order - // and a dumb insert sort - CharChunk tempChunk = new CharChunk(); - int n = 0; - while (n < size) { - Object key = tempMap.lastKey(); - ArrayList list = (ArrayList) tempMap.get(key); - CharEntry[] list2 = - (CharEntry[]) list.toArray(new CharEntry[list.size()]); - for (int i = 0; i < list.size() && n < size; i++) { - CharEntry entry = (CharEntry) list.get(i); - tempChunk.setChars(entry.name, 0, entry.name.length); - int insertPos = findClosest(tempChunk, tempccCache, n); - if (insertPos == n) { - tempccCache[n + 1] = entry; - } else { - System.arraycopy(tempccCache, insertPos + 1, tempccCache, - insertPos + 2, n - insertPos - 1); - tempccCache[insertPos + 1] = entry; - } - n++; - } - tempMap.remove(key); - } - ccCount = 0; - ccStats.clear(); - ccCache = tempccCache; - if (log.isDebugEnabled()) { - long t2 = System.currentTimeMillis(); - log.debug("CharCache generation time: " + (t2 - t1) + "ms"); - } - } else { - ccCount++; - // Allocate new CharEntry for the lookup - CharEntry entry = new CharEntry(); - entry.value = value; - int[] count = (int[]) ccStats.get(entry); - if (count == null) { - int end = cc.getEnd(); - int start = cc.getStart(); - // Create char array and copy chars - entry.name = new char[cc.getLength()]; - System.arraycopy(cc.getBuffer(), start, entry.name, 0, end - start); - // Initialize occurrence count to one - count = new int[1]; - count[0] = 1; - // Set in the stats hash map - ccStats.put(entry, count); - } else { - count[0] = count[0] + 1; - } - } - } - } - return value; - } else { - accessCount++; - // Find the corresponding String - String result = find(cc); - if (result == null) { - return cc.toStringInternal(); - } - // Note: We don't care about safety for the stats - hitCount++; - return result; - } - - } - - - // ----------------------------------------------------- Protected Methods - - - /** - * Compare given byte chunk with byte array. - * Return -1, 0 or +1 if inferior, equal, or superior to the String. - */ - protected static final int compare(ByteChunk name, byte[] compareTo) { - int result = 0; - - byte[] b = name.getBuffer(); - int start = name.getStart(); - int end = name.getEnd(); - int len = compareTo.length; - - if ((end - start) < len) { - len = end - start; - } - for (int i = 0; (i < len) && (result == 0); i++) { - if (b[i + start] > compareTo[i]) { - result = 1; - } else if (b[i + start] < compareTo[i]) { - result = -1; - } - } - if (result == 0) { - if (compareTo.length > (end - start)) { - result = -1; - } else if (compareTo.length < (end - start)) { - result = 1; - } - } - return result; - } - - - /** - * Find an entry given its name in the cache and return the associated String. - */ - protected static final String find(ByteChunk name) { - int pos = findClosest(name, bcCache, bcCache.length); - if ((pos < 0) || (compare(name, bcCache[pos].name) != 0) - || !(name.getEncoding().equals(bcCache[pos].enc))) { - return null; - } else { - return bcCache[pos].value; - } - } - - - /** - * Find an entry given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - protected static final int findClosest(ByteChunk name, ByteEntry[] array, int len) { - - int a = 0; - int b = len - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - - if (compare(name, array[0].name) < 0) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = compare(name, array[i].name); - if (result == 1) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = compare(name, array[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - - /** - * Compare given char chunk with char array. - * Return -1, 0 or +1 if inferior, equal, or superior to the String. - */ - protected static final int compare(CharChunk name, char[] compareTo) { - int result = 0; - - char[] c = name.getBuffer(); - int start = name.getStart(); - int end = name.getEnd(); - int len = compareTo.length; - - if ((end - start) < len) { - len = end - start; - } - for (int i = 0; (i < len) && (result == 0); i++) { - if (c[i + start] > compareTo[i]) { - result = 1; - } else if (c[i + start] < compareTo[i]) { - result = -1; - } - } - if (result == 0) { - if (compareTo.length > (end - start)) { - result = -1; - } else if (compareTo.length < (end - start)) { - result = 1; - } - } - return result; - } - - - /** - * Find an entry given its name in the cache and return the associated String. - */ - protected static final String find(CharChunk name) { - int pos = findClosest(name, ccCache, ccCache.length); - if ((pos < 0) || (compare(name, ccCache[pos].name) != 0)) { - return null; - } else { - return ccCache[pos].value; - } - } - - - /** - * Find an entry given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - protected static final int findClosest(CharChunk name, CharEntry[] array, int len) { - - int a = 0; - int b = len - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - - if (compare(name, array[0].name) < 0 ) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = compare(name, array[i].name); - if (result == 1) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = compare(name, array[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - - // -------------------------------------------------- ByteEntry Inner Class - - - public static class ByteEntry { - - public byte[] name = null; - public String enc = null; - public String value = null; - - public String toString() { - return value; - } - public int hashCode() { - return value.hashCode(); - } - public boolean equals(Object obj) { - if (obj instanceof ByteEntry) { - return value.equals(((ByteEntry) obj).value); - } - return false; - } - - } - - - // -------------------------------------------------- CharEntry Inner Class - - - public static class CharEntry { - - public char[] name = null; - public String value = null; - - public String toString() { - return value; - } - public int hashCode() { - return value.hashCode(); - } - public boolean equals(Object obj) { - if (obj instanceof CharEntry) { - return value.equals(((CharEntry) obj).value); - } - return false; - } - - } - - -} +/* + * Copyright 1999-2005 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.TreeMap; + +/** + * This class implements a String cache for ByteChunk and CharChunk. + * + * @author Remy Maucherat + */ +public class StringCache { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( StringCache.class ); + + + // ------------------------------------------------------- Static Variables + + + /** + * Enabled ? + */ + protected static boolean byteEnabled = + ("true".equals(System.getProperty("tomcat.util.buf.StringCache.byte.enabled", "false"))); + + + protected static boolean charEnabled = + ("true".equals(System.getProperty("tomcat.util.buf.StringCache.char.enabled", "false"))); + + + protected static int trainThreshold = + Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.trainThreshold", "20000")); + + + protected static int cacheSize = + Integer.parseInt(System.getProperty("tomcat.util.buf.StringCache.cacheSize", "200")); + + + /** + * Statistics hash map for byte chunk. + */ + protected static HashMap bcStats = new HashMap(cacheSize); + + + /** + * toString count for byte chunk. + */ + protected static int bcCount = 0; + + + /** + * Cache for byte chunk. + */ + protected static ByteEntry[] bcCache = null; + + + /** + * Statistics hash map for char chunk. + */ + protected static HashMap ccStats = new HashMap(cacheSize); + + + /** + * toString count for char chunk. + */ + protected static int ccCount = 0; + + + /** + * Cache for char chunk. + */ + protected static CharEntry[] ccCache = null; + + + /** + * Access count. + */ + protected static int accessCount = 0; + + + /** + * Hit count. + */ + protected static int hitCount = 0; + + + // ------------------------------------------------------------ Properties + + + /** + * @return Returns the cacheSize. + */ + public int getCacheSize() { + return cacheSize; + } + + + /** + * @param cacheSize The cacheSize to set. + */ + public void setCacheSize(int cacheSize) { + StringCache.cacheSize = cacheSize; + } + + + /** + * @return Returns the enabled. + */ + public boolean getByteEnabled() { + return byteEnabled; + } + + + /** + * @param byteEnabled The enabled to set. + */ + public void setByteEnabled(boolean byteEnabled) { + StringCache.byteEnabled = byteEnabled; + } + + + /** + * @return Returns the enabled. + */ + public boolean getCharEnabled() { + return charEnabled; + } + + + /** + * @param charEnabled The enabled to set. + */ + public void setCharEnabled(boolean charEnabled) { + StringCache.charEnabled = charEnabled; + } + + + /** + * @return Returns the trainThreshold. + */ + public int getTrainThreshold() { + return trainThreshold; + } + + + /** + * @param trainThreshold The trainThreshold to set. + */ + public void setTrainThreshold(int trainThreshold) { + StringCache.trainThreshold = trainThreshold; + } + + + /** + * @return Returns the accessCount. + */ + public int getAccessCount() { + return accessCount; + } + + + /** + * @return Returns the hitCount. + */ + public int getHitCount() { + return hitCount; + } + + + // -------------------------------------------------- Public Static Methods + + + public void reset() { + hitCount = 0; + accessCount = 0; + synchronized (bcStats) { + bcCache = null; + bcCount = 0; + } + synchronized (ccStats) { + ccCache = null; + ccCount = 0; + } + } + + + public static String toString(ByteChunk bc) { + + // If the cache is null, then either caching is disabled, or we're + // still training + if (bcCache == null) { + String value = bc.toStringInternal(); + if (byteEnabled) { + // If training, everything is synced + synchronized (bcStats) { + // If the cache has been generated on a previous invocation + // while waiting fot the lock, just return the toString value + // we just calculated + if (bcCache != null) { + return value; + } + // Two cases: either we just exceeded the train count, in which + // case the cache must be created, or we just update the count for + // the string + if (bcCount > trainThreshold) { + long t1 = System.currentTimeMillis(); + // Sort the entries according to occurrence + TreeMap tempMap = new TreeMap(); + Iterator entries = bcStats.keySet().iterator(); + while (entries.hasNext()) { + ByteEntry entry = (ByteEntry) entries.next(); + int[] countA = (int[]) bcStats.get(entry); + Integer count = new Integer(countA[0]); + // Add to the list for that count + ArrayList list = (ArrayList) tempMap.get(count); + if (list == null) { + // Create list + list = new ArrayList(); + tempMap.put(count, list); + } + list.add(entry); + } + // Allocate array of the right size + int size = bcStats.size(); + if (size > cacheSize) { + size = cacheSize; + } + ByteEntry[] tempbcCache = new ByteEntry[size]; + // Fill it up using an alphabetical order + // and a dumb insert sort + ByteChunk tempChunk = new ByteChunk(); + int n = 0; + while (n < size) { + Object key = tempMap.lastKey(); + ArrayList list = (ArrayList) tempMap.get(key); + ByteEntry[] list2 = + (ByteEntry[]) list.toArray(new ByteEntry[list.size()]); + for (int i = 0; i < list.size() && n < size; i++) { + ByteEntry entry = (ByteEntry) list.get(i); + tempChunk.setBytes(entry.name, 0, entry.name.length); + int insertPos = findClosest(tempChunk, tempbcCache, n); + if (insertPos == n) { + tempbcCache[n + 1] = entry; + } else { + System.arraycopy(tempbcCache, insertPos + 1, tempbcCache, + insertPos + 2, n - insertPos - 1); + tempbcCache[insertPos + 1] = entry; + } + n++; + } + tempMap.remove(key); + } + bcCount = 0; + bcStats.clear(); + bcCache = tempbcCache; + if (log.isDebugEnabled()) { + long t2 = System.currentTimeMillis(); + log.debug("ByteCache generation time: " + (t2 - t1) + "ms"); + } + } else { + bcCount++; + // Allocate new ByteEntry for the lookup + ByteEntry entry = new ByteEntry(); + entry.value = value; + int[] count = (int[]) bcStats.get(entry); + if (count == null) { + int end = bc.getEnd(); + int start = bc.getStart(); + // Create byte array and copy bytes + entry.name = new byte[bc.getLength()]; + System.arraycopy(bc.getBuffer(), start, entry.name, 0, end - start); + // Set encoding + entry.enc = bc.getEncoding(); + // Initialize occurrence count to one + count = new int[1]; + count[0] = 1; + // Set in the stats hash map + bcStats.put(entry, count); + } else { + count[0] = count[0] + 1; + } + } + } + } + return value; + } else { + accessCount++; + // Find the corresponding String + String result = find(bc); + if (result == null) { + return bc.toStringInternal(); + } + // Note: We don't care about safety for the stats + hitCount++; + return result; + } + + } + + + public static String toString(CharChunk cc) { + + // If the cache is null, then either caching is disabled, or we're + // still training + if (ccCache == null) { + String value = cc.toStringInternal(); + if (charEnabled) { + // If training, everything is synced + synchronized (ccStats) { + // If the cache has been generated on a previous invocation + // while waiting fot the lock, just return the toString value + // we just calculated + if (ccCache != null) { + return value; + } + // Two cases: either we just exceeded the train count, in which + // case the cache must be created, or we just update the count for + // the string + if (ccCount > trainThreshold) { + long t1 = System.currentTimeMillis(); + // Sort the entries according to occurrence + TreeMap tempMap = new TreeMap(); + Iterator entries = ccStats.keySet().iterator(); + while (entries.hasNext()) { + CharEntry entry = (CharEntry) entries.next(); + int[] countA = (int[]) ccStats.get(entry); + Integer count = new Integer(countA[0]); + // Add to the list for that count + ArrayList list = (ArrayList) tempMap.get(count); + if (list == null) { + // Create list + list = new ArrayList(); + tempMap.put(count, list); + } + list.add(entry); + } + // Allocate array of the right size + int size = ccStats.size(); + if (size > cacheSize) { + size = cacheSize; + } + CharEntry[] tempccCache = new CharEntry[size]; + // Fill it up using an alphabetical order + // and a dumb insert sort + CharChunk tempChunk = new CharChunk(); + int n = 0; + while (n < size) { + Object key = tempMap.lastKey(); + ArrayList list = (ArrayList) tempMap.get(key); + CharEntry[] list2 = + (CharEntry[]) list.toArray(new CharEntry[list.size()]); + for (int i = 0; i < list.size() && n < size; i++) { + CharEntry entry = (CharEntry) list.get(i); + tempChunk.setChars(entry.name, 0, entry.name.length); + int insertPos = findClosest(tempChunk, tempccCache, n); + if (insertPos == n) { + tempccCache[n + 1] = entry; + } else { + System.arraycopy(tempccCache, insertPos + 1, tempccCache, + insertPos + 2, n - insertPos - 1); + tempccCache[insertPos + 1] = entry; + } + n++; + } + tempMap.remove(key); + } + ccCount = 0; + ccStats.clear(); + ccCache = tempccCache; + if (log.isDebugEnabled()) { + long t2 = System.currentTimeMillis(); + log.debug("CharCache generation time: " + (t2 - t1) + "ms"); + } + } else { + ccCount++; + // Allocate new CharEntry for the lookup + CharEntry entry = new CharEntry(); + entry.value = value; + int[] count = (int[]) ccStats.get(entry); + if (count == null) { + int end = cc.getEnd(); + int start = cc.getStart(); + // Create char array and copy chars + entry.name = new char[cc.getLength()]; + System.arraycopy(cc.getBuffer(), start, entry.name, 0, end - start); + // Initialize occurrence count to one + count = new int[1]; + count[0] = 1; + // Set in the stats hash map + ccStats.put(entry, count); + } else { + count[0] = count[0] + 1; + } + } + } + } + return value; + } else { + accessCount++; + // Find the corresponding String + String result = find(cc); + if (result == null) { + return cc.toStringInternal(); + } + // Note: We don't care about safety for the stats + hitCount++; + return result; + } + + } + + + // ----------------------------------------------------- Protected Methods + + + /** + * Compare given byte chunk with byte array. + * Return -1, 0 or +1 if inferior, equal, or superior to the String. + */ + protected static final int compare(ByteChunk name, byte[] compareTo) { + int result = 0; + + byte[] b = name.getBuffer(); + int start = name.getStart(); + int end = name.getEnd(); + int len = compareTo.length; + + if ((end - start) < len) { + len = end - start; + } + for (int i = 0; (i < len) && (result == 0); i++) { + if (b[i + start] > compareTo[i]) { + result = 1; + } else if (b[i + start] < compareTo[i]) { + result = -1; + } + } + if (result == 0) { + if (compareTo.length > (end - start)) { + result = -1; + } else if (compareTo.length < (end - start)) { + result = 1; + } + } + return result; + } + + + /** + * Find an entry given its name in the cache and return the associated String. + */ + protected static final String find(ByteChunk name) { + int pos = findClosest(name, bcCache, bcCache.length); + if ((pos < 0) || (compare(name, bcCache[pos].name) != 0) + || !(name.getEncoding().equals(bcCache[pos].enc))) { + return null; + } else { + return bcCache[pos].value; + } + } + + + /** + * Find an entry given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + protected static final int findClosest(ByteChunk name, ByteEntry[] array, int len) { + + int a = 0; + int b = len - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + + if (compare(name, array[0].name) < 0) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = compare(name, array[i].name); + if (result == 1) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = compare(name, array[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + + /** + * Compare given char chunk with char array. + * Return -1, 0 or +1 if inferior, equal, or superior to the String. + */ + protected static final int compare(CharChunk name, char[] compareTo) { + int result = 0; + + char[] c = name.getBuffer(); + int start = name.getStart(); + int end = name.getEnd(); + int len = compareTo.length; + + if ((end - start) < len) { + len = end - start; + } + for (int i = 0; (i < len) && (result == 0); i++) { + if (c[i + start] > compareTo[i]) { + result = 1; + } else if (c[i + start] < compareTo[i]) { + result = -1; + } + } + if (result == 0) { + if (compareTo.length > (end - start)) { + result = -1; + } else if (compareTo.length < (end - start)) { + result = 1; + } + } + return result; + } + + + /** + * Find an entry given its name in the cache and return the associated String. + */ + protected static final String find(CharChunk name) { + int pos = findClosest(name, ccCache, ccCache.length); + if ((pos < 0) || (compare(name, ccCache[pos].name) != 0)) { + return null; + } else { + return ccCache[pos].value; + } + } + + + /** + * Find an entry given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + protected static final int findClosest(CharChunk name, CharEntry[] array, int len) { + + int a = 0; + int b = len - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + + if (compare(name, array[0].name) < 0 ) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = compare(name, array[i].name); + if (result == 1) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = compare(name, array[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + + // -------------------------------------------------- ByteEntry Inner Class + + + public static class ByteEntry { + + public byte[] name = null; + public String enc = null; + public String value = null; + + public String toString() { + return value; + } + public int hashCode() { + return value.hashCode(); + } + public boolean equals(Object obj) { + if (obj instanceof ByteEntry) { + return value.equals(((ByteEntry) obj).value); + } + return false; + } + + } + + + // -------------------------------------------------- CharEntry Inner Class + + + public static class CharEntry { + + public char[] name = null; + public String value = null; + + public String toString() { + return value; + } + public int hashCode() { + return value.hashCode(); + } + public boolean equals(Object obj) { + if (obj instanceof CharEntry) { + return value.equals(((CharEntry) obj).value); + } + return false; + } + + } + + +} diff --git a/java/org/apache/tomcat/util/buf/TimeStamp.java b/java/org/apache/tomcat/util/buf/TimeStamp.java index adaa2e77e..90bab825e 100644 --- a/java/org/apache/tomcat/util/buf/TimeStamp.java +++ b/java/org/apache/tomcat/util/buf/TimeStamp.java @@ -1,155 +1,155 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.Serializable; - -// XXX Shouldn't be here - has nothing to do with buffers. - -/** - * Main tool for object expiry. - * Marks creation and access time of an "expirable" object, - * and extra properties like "id", "valid", etc. - * - * Used for objects that expire - originally Sessions, but - * also Contexts, Servlets, cache - or any other object that - * expires. - * - * @author Costin Manolache - */ -public final class TimeStamp implements Serializable { - private long creationTime = 0L; - private long lastAccessedTime = creationTime; - private long thisAccessedTime = creationTime; - private boolean isNew = true; - private long maxInactiveInterval = -1; - private boolean isValid = false; - MessageBytes name; - int id=-1; - - Object parent; - - public TimeStamp() { - } - - // -------------------- Active methods -------------------- - - /** - * Access notification. This method takes a time parameter in order - * to allow callers to efficiently manage expensive calls to - * System.currentTimeMillis() - */ - public void touch(long time) { - this.lastAccessedTime = this.thisAccessedTime; - this.thisAccessedTime = time; - this.isNew=false; - } - - // -------------------- Property access -------------------- - - /** Return the "name" of the timestamp. This can be used - * to associate unique identifier with each timestamped object. - * The name is a MessageBytes - i.e. a modifiable byte[] or char[]. - */ - public MessageBytes getName() { - if( name==null ) name=MessageBytes.newInstance();//lazy - return name; - } - - /** Each object can have an unique id, similar with name but - * providing faster access ( array vs. hashtable lookup ) - */ - public int getId() { - return id; - } - - public void setId( int id ) { - this.id=id; - } - - /** Returns the owner of this stamp ( the object that is - * time-stamped ). - * For a - */ - public void setParent( Object o ) { - parent=o; - } - - public Object getParent() { - return parent; - } - - public void setCreationTime(long time) { - this.creationTime = time; - this.lastAccessedTime = time; - this.thisAccessedTime = time; - } - - - public long getLastAccessedTime() { - return lastAccessedTime; - } - - public long getThisAccessedTime() { - return thisAccessedTime; - } - - /** Inactive interval in millis - the time is computed - * in millis, convert to secs in the upper layer - */ - public long getMaxInactiveInterval() { - return maxInactiveInterval; - } - - public void setMaxInactiveInterval(long interval) { - maxInactiveInterval = interval; - } - - public boolean isValid() { - return isValid; - } - - public void setValid(boolean isValid) { - this.isValid = isValid; - } - - public boolean isNew() { - return isNew; - } - - public void setNew(boolean isNew) { - this.isNew = isNew; - } - - public long getCreationTime() { - return creationTime; - } - - // -------------------- Maintainance -------------------- - - public void recycle() { - creationTime = 0L; - lastAccessedTime = 0L; - maxInactiveInterval = -1; - isNew = true; - isValid = false; - id=-1; - if( name!=null) name.recycle(); - } - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.Serializable; + +// XXX Shouldn't be here - has nothing to do with buffers. + +/** + * Main tool for object expiry. + * Marks creation and access time of an "expirable" object, + * and extra properties like "id", "valid", etc. + * + * Used for objects that expire - originally Sessions, but + * also Contexts, Servlets, cache - or any other object that + * expires. + * + * @author Costin Manolache + */ +public final class TimeStamp implements Serializable { + private long creationTime = 0L; + private long lastAccessedTime = creationTime; + private long thisAccessedTime = creationTime; + private boolean isNew = true; + private long maxInactiveInterval = -1; + private boolean isValid = false; + MessageBytes name; + int id=-1; + + Object parent; + + public TimeStamp() { + } + + // -------------------- Active methods -------------------- + + /** + * Access notification. This method takes a time parameter in order + * to allow callers to efficiently manage expensive calls to + * System.currentTimeMillis() + */ + public void touch(long time) { + this.lastAccessedTime = this.thisAccessedTime; + this.thisAccessedTime = time; + this.isNew=false; + } + + // -------------------- Property access -------------------- + + /** Return the "name" of the timestamp. This can be used + * to associate unique identifier with each timestamped object. + * The name is a MessageBytes - i.e. a modifiable byte[] or char[]. + */ + public MessageBytes getName() { + if( name==null ) name=MessageBytes.newInstance();//lazy + return name; + } + + /** Each object can have an unique id, similar with name but + * providing faster access ( array vs. hashtable lookup ) + */ + public int getId() { + return id; + } + + public void setId( int id ) { + this.id=id; + } + + /** Returns the owner of this stamp ( the object that is + * time-stamped ). + * For a + */ + public void setParent( Object o ) { + parent=o; + } + + public Object getParent() { + return parent; + } + + public void setCreationTime(long time) { + this.creationTime = time; + this.lastAccessedTime = time; + this.thisAccessedTime = time; + } + + + public long getLastAccessedTime() { + return lastAccessedTime; + } + + public long getThisAccessedTime() { + return thisAccessedTime; + } + + /** Inactive interval in millis - the time is computed + * in millis, convert to secs in the upper layer + */ + public long getMaxInactiveInterval() { + return maxInactiveInterval; + } + + public void setMaxInactiveInterval(long interval) { + maxInactiveInterval = interval; + } + + public boolean isValid() { + return isValid; + } + + public void setValid(boolean isValid) { + this.isValid = isValid; + } + + public boolean isNew() { + return isNew; + } + + public void setNew(boolean isNew) { + this.isNew = isNew; + } + + public long getCreationTime() { + return creationTime; + } + + // -------------------- Maintainance -------------------- + + public void recycle() { + creationTime = 0L; + lastAccessedTime = 0L; + maxInactiveInterval = -1; + isNew = true; + isValid = false; + id=-1; + if( name!=null) name.recycle(); + } + +} + diff --git a/java/org/apache/tomcat/util/buf/UDecoder.java b/java/org/apache/tomcat/util/buf/UDecoder.java index 44141bcf9..950d0771e 100644 --- a/java/org/apache/tomcat/util/buf/UDecoder.java +++ b/java/org/apache/tomcat/util/buf/UDecoder.java @@ -1,276 +1,276 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.CharConversionException; -import java.io.IOException; - -/** - * All URL decoding happens here. This way we can reuse, review, optimize - * without adding complexity to the buffers. - * - * The conversion will modify the original buffer. - * - * @author Costin Manolache - */ -public final class UDecoder { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(UDecoder.class ); - - public UDecoder() - { - } - - /** URLDecode, will modify the source. Includes converting - * '+' to ' '. - */ - public void convert( ByteChunk mb ) - throws IOException - { - convert(mb, true); - } - - /** URLDecode, will modify the source. - */ - public void convert( ByteChunk mb, boolean query ) - throws IOException - { - int start=mb.getOffset(); - byte buff[]=mb.getBytes(); - int end=mb.getEnd(); - - int idx= ByteChunk.indexOf( buff, start, end, '%' ); - int idx2=-1; - if( query ) - idx2= ByteChunk.indexOf( buff, start, end, '+' ); - if( idx<0 && idx2<0 ) { - return; - } - - // idx will be the smallest positive inxes ( first % or + ) - if( idx2 >= 0 && idx2 < idx ) idx=idx2; - if( idx < 0 ) idx=idx2; - - for( int j=idx; j= end ) { - throw new CharConversionException("EOF"); - } - byte b1= buff[j+1]; - byte b2=buff[j+2]; - if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) - throw new CharConversionException( "isHexDigit"); - - j+=2; - int res=x2c( b1, b2 ); - buff[idx]=(byte)res; - } - } - - mb.setEnd( idx ); - - return; - } - - // -------------------- Additional methods -------------------- - // XXX What do we do about charset ???? - - /** In-buffer processing - the buffer will be modified - * Includes converting '+' to ' '. - */ - public void convert( CharChunk mb ) - throws IOException - { - convert(mb, true); - } - - /** In-buffer processing - the buffer will be modified - */ - public void convert( CharChunk mb, boolean query ) - throws IOException - { - // log( "Converting a char chunk "); - int start=mb.getOffset(); - char buff[]=mb.getBuffer(); - int cend=mb.getEnd(); - - int idx= CharChunk.indexOf( buff, start, cend, '%' ); - int idx2=-1; - if( query ) - idx2= CharChunk.indexOf( buff, start, cend, '+' ); - if( idx<0 && idx2<0 ) { - return; - } - - if( idx2 >= 0 && idx2 < idx ) idx=idx2; - if( idx < 0 ) idx=idx2; - - for( int j=idx; j= cend ) { - // invalid - throw new CharConversionException("EOF"); - } - char b1= buff[j+1]; - char b2=buff[j+2]; - if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) - throw new CharConversionException("isHexDigit"); - - j+=2; - int res=x2c( b1, b2 ); - buff[idx]=(char)res; - } - } - mb.setEnd( idx ); - } - - /** URLDecode, will modify the source - * Includes converting '+' to ' '. - */ - public void convert(MessageBytes mb) - throws IOException - { - convert(mb, true); - } - - /** URLDecode, will modify the source - */ - public void convert(MessageBytes mb, boolean query) - throws IOException - { - - switch (mb.getType()) { - case MessageBytes.T_STR: - String strValue=mb.toString(); - if( strValue==null ) return; - mb.setString( convert( strValue, query )); - break; - case MessageBytes.T_CHARS: - CharChunk charC=mb.getCharChunk(); - convert( charC, query ); - break; - case MessageBytes.T_BYTES: - ByteChunk bytesC=mb.getByteChunk(); - convert( bytesC, query ); - break; - } - } - - // XXX Old code, needs to be replaced !!!! - // - public final String convert(String str) - { - return convert(str, true); - } - - public final String convert(String str, boolean query) - { - if (str == null) return null; - - if( (!query || str.indexOf( '+' ) < 0) && str.indexOf( '%' ) < 0 ) - return str; - - StringBuffer dec = new StringBuffer(); // decoded string output - int strPos = 0; - int strLen = str.length(); - - dec.ensureCapacity(str.length()); - while (strPos < strLen) { - int laPos; // lookahead position - - // look ahead to next URLencoded metacharacter, if any - for (laPos = strPos; laPos < strLen; laPos++) { - char laChar = str.charAt(laPos); - if ((laChar == '+' && query) || (laChar == '%')) { - break; - } - } - - // if there were non-metacharacters, copy them all as a block - if (laPos > strPos) { - dec.append(str.substring(strPos,laPos)); - strPos = laPos; - } - - // shortcut out of here if we're at the end of the string - if (strPos >= strLen) { - break; - } - - // process next metacharacter - char metaChar = str.charAt(strPos); - if (metaChar == '+') { - dec.append(' '); - strPos++; - continue; - } else if (metaChar == '%') { - // We throw the original exception - the super will deal with - // it - // try { - dec.append((char)Integer. - parseInt(str.substring(strPos + 1, strPos + 3),16)); - strPos += 3; - } - } - - return dec.toString(); - } - - - - private static boolean isHexDigit( int c ) { - return ( ( c>='0' && c<='9' ) || - ( c>='a' && c<='f' ) || - ( c>='A' && c<='F' )); - } - - private static int x2c( byte b1, byte b2 ) { - int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : - (b1 -'0'); - digit*=16; - digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : - (b2 -'0'); - return digit; - } - - private static int x2c( char b1, char b2 ) { - int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : - (b1 -'0'); - digit*=16; - digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : - (b2 -'0'); - return digit; - } - - private final static int debug=0; - private static void log( String s ) { - if (log.isDebugEnabled()) - log.debug("URLDecoder: " + s ); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.CharConversionException; +import java.io.IOException; + +/** + * All URL decoding happens here. This way we can reuse, review, optimize + * without adding complexity to the buffers. + * + * The conversion will modify the original buffer. + * + * @author Costin Manolache + */ +public final class UDecoder { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(UDecoder.class ); + + public UDecoder() + { + } + + /** URLDecode, will modify the source. Includes converting + * '+' to ' '. + */ + public void convert( ByteChunk mb ) + throws IOException + { + convert(mb, true); + } + + /** URLDecode, will modify the source. + */ + public void convert( ByteChunk mb, boolean query ) + throws IOException + { + int start=mb.getOffset(); + byte buff[]=mb.getBytes(); + int end=mb.getEnd(); + + int idx= ByteChunk.indexOf( buff, start, end, '%' ); + int idx2=-1; + if( query ) + idx2= ByteChunk.indexOf( buff, start, end, '+' ); + if( idx<0 && idx2<0 ) { + return; + } + + // idx will be the smallest positive inxes ( first % or + ) + if( idx2 >= 0 && idx2 < idx ) idx=idx2; + if( idx < 0 ) idx=idx2; + + for( int j=idx; j= end ) { + throw new CharConversionException("EOF"); + } + byte b1= buff[j+1]; + byte b2=buff[j+2]; + if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) + throw new CharConversionException( "isHexDigit"); + + j+=2; + int res=x2c( b1, b2 ); + buff[idx]=(byte)res; + } + } + + mb.setEnd( idx ); + + return; + } + + // -------------------- Additional methods -------------------- + // XXX What do we do about charset ???? + + /** In-buffer processing - the buffer will be modified + * Includes converting '+' to ' '. + */ + public void convert( CharChunk mb ) + throws IOException + { + convert(mb, true); + } + + /** In-buffer processing - the buffer will be modified + */ + public void convert( CharChunk mb, boolean query ) + throws IOException + { + // log( "Converting a char chunk "); + int start=mb.getOffset(); + char buff[]=mb.getBuffer(); + int cend=mb.getEnd(); + + int idx= CharChunk.indexOf( buff, start, cend, '%' ); + int idx2=-1; + if( query ) + idx2= CharChunk.indexOf( buff, start, cend, '+' ); + if( idx<0 && idx2<0 ) { + return; + } + + if( idx2 >= 0 && idx2 < idx ) idx=idx2; + if( idx < 0 ) idx=idx2; + + for( int j=idx; j= cend ) { + // invalid + throw new CharConversionException("EOF"); + } + char b1= buff[j+1]; + char b2=buff[j+2]; + if( !isHexDigit( b1 ) || ! isHexDigit(b2 )) + throw new CharConversionException("isHexDigit"); + + j+=2; + int res=x2c( b1, b2 ); + buff[idx]=(char)res; + } + } + mb.setEnd( idx ); + } + + /** URLDecode, will modify the source + * Includes converting '+' to ' '. + */ + public void convert(MessageBytes mb) + throws IOException + { + convert(mb, true); + } + + /** URLDecode, will modify the source + */ + public void convert(MessageBytes mb, boolean query) + throws IOException + { + + switch (mb.getType()) { + case MessageBytes.T_STR: + String strValue=mb.toString(); + if( strValue==null ) return; + mb.setString( convert( strValue, query )); + break; + case MessageBytes.T_CHARS: + CharChunk charC=mb.getCharChunk(); + convert( charC, query ); + break; + case MessageBytes.T_BYTES: + ByteChunk bytesC=mb.getByteChunk(); + convert( bytesC, query ); + break; + } + } + + // XXX Old code, needs to be replaced !!!! + // + public final String convert(String str) + { + return convert(str, true); + } + + public final String convert(String str, boolean query) + { + if (str == null) return null; + + if( (!query || str.indexOf( '+' ) < 0) && str.indexOf( '%' ) < 0 ) + return str; + + StringBuffer dec = new StringBuffer(); // decoded string output + int strPos = 0; + int strLen = str.length(); + + dec.ensureCapacity(str.length()); + while (strPos < strLen) { + int laPos; // lookahead position + + // look ahead to next URLencoded metacharacter, if any + for (laPos = strPos; laPos < strLen; laPos++) { + char laChar = str.charAt(laPos); + if ((laChar == '+' && query) || (laChar == '%')) { + break; + } + } + + // if there were non-metacharacters, copy them all as a block + if (laPos > strPos) { + dec.append(str.substring(strPos,laPos)); + strPos = laPos; + } + + // shortcut out of here if we're at the end of the string + if (strPos >= strLen) { + break; + } + + // process next metacharacter + char metaChar = str.charAt(strPos); + if (metaChar == '+') { + dec.append(' '); + strPos++; + continue; + } else if (metaChar == '%') { + // We throw the original exception - the super will deal with + // it + // try { + dec.append((char)Integer. + parseInt(str.substring(strPos + 1, strPos + 3),16)); + strPos += 3; + } + } + + return dec.toString(); + } + + + + private static boolean isHexDigit( int c ) { + return ( ( c>='0' && c<='9' ) || + ( c>='a' && c<='f' ) || + ( c>='A' && c<='F' )); + } + + private static int x2c( byte b1, byte b2 ) { + int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : + (b1 -'0'); + digit*=16; + digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : + (b2 -'0'); + return digit; + } + + private static int x2c( char b1, char b2 ) { + int digit= (b1>='A') ? ( (b1 & 0xDF)-'A') + 10 : + (b1 -'0'); + digit*=16; + digit +=(b2>='A') ? ( (b2 & 0xDF)-'A') + 10 : + (b2 -'0'); + return digit; + } + + private final static int debug=0; + private static void log( String s ) { + if (log.isDebugEnabled()) + log.debug("URLDecoder: " + s ); + } + +} diff --git a/java/org/apache/tomcat/util/buf/UEncoder.java b/java/org/apache/tomcat/util/buf/UEncoder.java index 71d6c8b59..627bc96f6 100644 --- a/java/org/apache/tomcat/util/buf/UEncoder.java +++ b/java/org/apache/tomcat/util/buf/UEncoder.java @@ -1,181 +1,181 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.CharArrayWriter; -import java.io.IOException; -import java.io.Writer; -import java.util.BitSet; - -/** Efficient implementation for encoders. - * This class is not thread safe - you need one encoder per thread. - * The encoder will save and recycle the internal objects, avoiding - * garbage. - * - * You can add extra characters that you want preserved, for example - * while encoding a URL you can add "/". - * - * @author Costin Manolache - */ -public final class UEncoder { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(UEncoder.class ); - - // Not static - the set may differ ( it's better than adding - // an extra check for "/", "+", etc - private BitSet safeChars=null; - private C2BConverter c2b=null; - private ByteChunk bb=null; - - private String encoding="UTF8"; - private static final int debug=0; - - public UEncoder() { - initSafeChars(); - } - - public void setEncoding( String s ) { - encoding=s; - } - - public void addSafeCharacter( char c ) { - safeChars.set( c ); - } - - - /** URL Encode string, using a specified encoding. - * - * @param buf The writer - * @param s string to be encoded - * @throws IOException If an I/O error occurs - */ - public void urlEncode( Writer buf, String s ) - throws IOException - { - if( c2b==null ) { - bb=new ByteChunk(16); // small enough. - c2b=new C2BConverter( bb, encoding ); - } - - for (int i = 0; i < s.length(); i++) { - int c = (int) s.charAt(i); - if( safeChars.get( c ) ) { - if( debug > 0 ) log("Safe: " + (char)c); - buf.write((char)c); - } else { - if( debug > 0 ) log("Unsafe: " + (char)c); - c2b.convert( (char)c ); - - // "surrogate" - UTF is _not_ 16 bit, but 21 !!!! - // ( while UCS is 31 ). Amazing... - if (c >= 0xD800 && c <= 0xDBFF) { - if ( (i+1) < s.length()) { - int d = (int) s.charAt(i+1); - if (d >= 0xDC00 && d <= 0xDFFF) { - if( debug > 0 ) log("Unsafe: " + c); - c2b.convert( (char)d); - i++; - } - } - } - - c2b.flushBuffer(); - - urlEncode( buf, bb.getBuffer(), bb.getOffset(), - bb.getLength() ); - bb.recycle(); - } - } - } - - /** - */ - public void urlEncode( Writer buf, byte bytes[], int off, int len) - throws IOException - { - for( int j=off; j< len; j++ ) { - buf.write( '%' ); - char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16); - if( debug > 0 ) log("Encode: " + ch); - buf.write(ch); - ch = Character.forDigit(bytes[j] & 0xF, 16); - if( debug > 0 ) log("Encode: " + ch); - buf.write(ch); - } - } - - /** - * Utility funtion to re-encode the URL. - * Still has problems with charset, since UEncoder mostly - * ignores it. - */ - public String encodeURL(String uri) { - String outUri=null; - try { - // XXX optimize - recycle, etc - CharArrayWriter out = new CharArrayWriter(); - urlEncode(out, uri); - outUri=out.toString(); - } catch (IOException iex) { - } - return outUri; - } - - - // -------------------- Internal implementation -------------------- - - // - private void init() { - - } - - private void initSafeChars() { - safeChars=new BitSet(128); - int i; - for (i = 'a'; i <= 'z'; i++) { - safeChars.set(i); - } - for (i = 'A'; i <= 'Z'; i++) { - safeChars.set(i); - } - for (i = '0'; i <= '9'; i++) { - safeChars.set(i); - } - //safe - safeChars.set('$'); - safeChars.set('-'); - safeChars.set('_'); - safeChars.set('.'); - - // Dangerous: someone may treat this as " " - // RFC1738 does allow it, it's not reserved - // safeChars.set('+'); - //extra - safeChars.set('!'); - safeChars.set('*'); - safeChars.set('\''); - safeChars.set('('); - safeChars.set(')'); - safeChars.set(','); - } - - private static void log( String s ) { - if (log.isDebugEnabled()) - log.debug("Encoder: " + s ); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.Writer; +import java.util.BitSet; + +/** Efficient implementation for encoders. + * This class is not thread safe - you need one encoder per thread. + * The encoder will save and recycle the internal objects, avoiding + * garbage. + * + * You can add extra characters that you want preserved, for example + * while encoding a URL you can add "/". + * + * @author Costin Manolache + */ +public final class UEncoder { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(UEncoder.class ); + + // Not static - the set may differ ( it's better than adding + // an extra check for "/", "+", etc + private BitSet safeChars=null; + private C2BConverter c2b=null; + private ByteChunk bb=null; + + private String encoding="UTF8"; + private static final int debug=0; + + public UEncoder() { + initSafeChars(); + } + + public void setEncoding( String s ) { + encoding=s; + } + + public void addSafeCharacter( char c ) { + safeChars.set( c ); + } + + + /** URL Encode string, using a specified encoding. + * + * @param buf The writer + * @param s string to be encoded + * @throws IOException If an I/O error occurs + */ + public void urlEncode( Writer buf, String s ) + throws IOException + { + if( c2b==null ) { + bb=new ByteChunk(16); // small enough. + c2b=new C2BConverter( bb, encoding ); + } + + for (int i = 0; i < s.length(); i++) { + int c = (int) s.charAt(i); + if( safeChars.get( c ) ) { + if( debug > 0 ) log("Safe: " + (char)c); + buf.write((char)c); + } else { + if( debug > 0 ) log("Unsafe: " + (char)c); + c2b.convert( (char)c ); + + // "surrogate" - UTF is _not_ 16 bit, but 21 !!!! + // ( while UCS is 31 ). Amazing... + if (c >= 0xD800 && c <= 0xDBFF) { + if ( (i+1) < s.length()) { + int d = (int) s.charAt(i+1); + if (d >= 0xDC00 && d <= 0xDFFF) { + if( debug > 0 ) log("Unsafe: " + c); + c2b.convert( (char)d); + i++; + } + } + } + + c2b.flushBuffer(); + + urlEncode( buf, bb.getBuffer(), bb.getOffset(), + bb.getLength() ); + bb.recycle(); + } + } + } + + /** + */ + public void urlEncode( Writer buf, byte bytes[], int off, int len) + throws IOException + { + for( int j=off; j< len; j++ ) { + buf.write( '%' ); + char ch = Character.forDigit((bytes[j] >> 4) & 0xF, 16); + if( debug > 0 ) log("Encode: " + ch); + buf.write(ch); + ch = Character.forDigit(bytes[j] & 0xF, 16); + if( debug > 0 ) log("Encode: " + ch); + buf.write(ch); + } + } + + /** + * Utility funtion to re-encode the URL. + * Still has problems with charset, since UEncoder mostly + * ignores it. + */ + public String encodeURL(String uri) { + String outUri=null; + try { + // XXX optimize - recycle, etc + CharArrayWriter out = new CharArrayWriter(); + urlEncode(out, uri); + outUri=out.toString(); + } catch (IOException iex) { + } + return outUri; + } + + + // -------------------- Internal implementation -------------------- + + // + private void init() { + + } + + private void initSafeChars() { + safeChars=new BitSet(128); + int i; + for (i = 'a'; i <= 'z'; i++) { + safeChars.set(i); + } + for (i = 'A'; i <= 'Z'; i++) { + safeChars.set(i); + } + for (i = '0'; i <= '9'; i++) { + safeChars.set(i); + } + //safe + safeChars.set('$'); + safeChars.set('-'); + safeChars.set('_'); + safeChars.set('.'); + + // Dangerous: someone may treat this as " " + // RFC1738 does allow it, it's not reserved + // safeChars.set('+'); + //extra + safeChars.set('!'); + safeChars.set('*'); + safeChars.set('\''); + safeChars.set('('); + safeChars.set(')'); + safeChars.set(','); + } + + private static void log( String s ) { + if (log.isDebugEnabled()) + log.debug("Encoder: " + s ); + } +} diff --git a/java/org/apache/tomcat/util/buf/UTF8Decoder.java b/java/org/apache/tomcat/util/buf/UTF8Decoder.java index b2d4f938d..f189176ae 100644 --- a/java/org/apache/tomcat/util/buf/UTF8Decoder.java +++ b/java/org/apache/tomcat/util/buf/UTF8Decoder.java @@ -1,149 +1,149 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.buf; - -import java.io.IOException; - -/** - * Moved from ByteChunk - code to convert from UTF8 bytes to chars. - * Not used in the current tomcat3.3 : the performance gain is not very - * big if the String is created, only if we avoid that and work only - * on char[]. Until than, it's better to be safe. ( I tested this code - * with 2 and 3 bytes chars, and it works fine in xerces ) - * - * Cut from xerces' UTF8Reader.copyMultiByteCharData() - * - * @author Costin Manolache - * @author ( Xml-Xerces ) - */ -public final class UTF8Decoder extends B2CConverter { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(UTF8Decoder.class ); - - // may have state !! - - public UTF8Decoder() { - - } - - public void recycle() { - } - - public void convert(ByteChunk mb, CharChunk cb ) - throws IOException - { - int bytesOff=mb.getOffset(); - int bytesLen=mb.getLength(); - byte bytes[]=mb.getBytes(); - - int j=bytesOff; - int end=j+bytesLen; - - while( j< end ) { - int b0=0xff & bytes[j]; - - if( (b0 & 0x80) == 0 ) { - cb.append((char)b0); - j++; - continue; - } - - // 2 byte ? - if( j++ >= end ) { - // ok, just ignore - we could throw exception - throw new IOException( "Conversion error - EOF " ); - } - int b1=0xff & bytes[j]; - - // ok, let's the fun begin - we're handling UTF8 - if ((0xe0 & b0) == 0xc0) { // 110yyyyy 10xxxxxx (0x80 to 0x7ff) - int ch = ((0x1f & b0)<<6) + (0x3f & b1); - if(debug>0) - log("Convert " + b0 + " " + b1 + " " + ch + ((char)ch)); - - cb.append((char)ch); - j++; - continue; - } - - if( j++ >= end ) - return ; - int b2=0xff & bytes[j]; - - if( (b0 & 0xf0 ) == 0xe0 ) { - if ((b0 == 0xED && b1 >= 0xA0) || - (b0 == 0xEF && b1 == 0xBF && b2 >= 0xBE)) { - if(debug>0) - log("Error " + b0 + " " + b1+ " " + b2 ); - - throw new IOException( "Conversion error 2"); - } - - int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); - cb.append((char)ch); - if(debug>0) - log("Convert " + b0 + " " + b1+ " " + b2 + " " + ch + - ((char)ch)); - j++; - continue; - } - - if( j++ >= end ) - return ; - int b3=0xff & bytes[j]; - - if (( 0xf8 & b0 ) == 0xf0 ) { - if (b0 > 0xF4 || (b0 == 0xF4 && b1 >= 0x90)) { - if(debug>0) - log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3); - throw new IOException( "Conversion error "); - } - int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) + - ((0x3f & b2)<<6) + (0x3f & b3); - - if(debug>0) - log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3 + " " + - ch + ((char)ch)); - - if (ch < 0x10000) { - cb.append( (char)ch ); - } else { - cb.append((char)(((ch-0x00010000)>>10)+ - 0xd800)); - cb.append((char)(((ch-0x00010000)&0x3ff)+ - 0xdc00)); - } - j++; - continue; - } else { - // XXX Throw conversion exception !!! - if(debug>0) - log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3); - throw new IOException( "Conversion error 4" ); - } - } - } - - private static int debug=1; - void log(String s ) { - if (log.isDebugEnabled()) - log.debug("UTF8Decoder: " + s ); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.buf; + +import java.io.IOException; + +/** + * Moved from ByteChunk - code to convert from UTF8 bytes to chars. + * Not used in the current tomcat3.3 : the performance gain is not very + * big if the String is created, only if we avoid that and work only + * on char[]. Until than, it's better to be safe. ( I tested this code + * with 2 and 3 bytes chars, and it works fine in xerces ) + * + * Cut from xerces' UTF8Reader.copyMultiByteCharData() + * + * @author Costin Manolache + * @author ( Xml-Xerces ) + */ +public final class UTF8Decoder extends B2CConverter { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(UTF8Decoder.class ); + + // may have state !! + + public UTF8Decoder() { + + } + + public void recycle() { + } + + public void convert(ByteChunk mb, CharChunk cb ) + throws IOException + { + int bytesOff=mb.getOffset(); + int bytesLen=mb.getLength(); + byte bytes[]=mb.getBytes(); + + int j=bytesOff; + int end=j+bytesLen; + + while( j< end ) { + int b0=0xff & bytes[j]; + + if( (b0 & 0x80) == 0 ) { + cb.append((char)b0); + j++; + continue; + } + + // 2 byte ? + if( j++ >= end ) { + // ok, just ignore - we could throw exception + throw new IOException( "Conversion error - EOF " ); + } + int b1=0xff & bytes[j]; + + // ok, let's the fun begin - we're handling UTF8 + if ((0xe0 & b0) == 0xc0) { // 110yyyyy 10xxxxxx (0x80 to 0x7ff) + int ch = ((0x1f & b0)<<6) + (0x3f & b1); + if(debug>0) + log("Convert " + b0 + " " + b1 + " " + ch + ((char)ch)); + + cb.append((char)ch); + j++; + continue; + } + + if( j++ >= end ) + return ; + int b2=0xff & bytes[j]; + + if( (b0 & 0xf0 ) == 0xe0 ) { + if ((b0 == 0xED && b1 >= 0xA0) || + (b0 == 0xEF && b1 == 0xBF && b2 >= 0xBE)) { + if(debug>0) + log("Error " + b0 + " " + b1+ " " + b2 ); + + throw new IOException( "Conversion error 2"); + } + + int ch = ((0x0f & b0)<<12) + ((0x3f & b1)<<6) + (0x3f & b2); + cb.append((char)ch); + if(debug>0) + log("Convert " + b0 + " " + b1+ " " + b2 + " " + ch + + ((char)ch)); + j++; + continue; + } + + if( j++ >= end ) + return ; + int b3=0xff & bytes[j]; + + if (( 0xf8 & b0 ) == 0xf0 ) { + if (b0 > 0xF4 || (b0 == 0xF4 && b1 >= 0x90)) { + if(debug>0) + log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3); + throw new IOException( "Conversion error "); + } + int ch = ((0x0f & b0)<<18) + ((0x3f & b1)<<12) + + ((0x3f & b2)<<6) + (0x3f & b3); + + if(debug>0) + log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3 + " " + + ch + ((char)ch)); + + if (ch < 0x10000) { + cb.append( (char)ch ); + } else { + cb.append((char)(((ch-0x00010000)>>10)+ + 0xd800)); + cb.append((char)(((ch-0x00010000)&0x3ff)+ + 0xdc00)); + } + j++; + continue; + } else { + // XXX Throw conversion exception !!! + if(debug>0) + log("Convert " + b0 + " " + b1+ " " + b2 + " " + b3); + throw new IOException( "Conversion error 4" ); + } + } + } + + private static int debug=1; + void log(String s ) { + if (log.isDebugEnabled()) + log.debug("UTF8Decoder: " + s ); + } + +} diff --git a/java/org/apache/tomcat/util/buf/package.html b/java/org/apache/tomcat/util/buf/package.html index 04e9398b2..0806d3cbe 100644 --- a/java/org/apache/tomcat/util/buf/package.html +++ b/java/org/apache/tomcat/util/buf/package.html @@ -1,22 +1,22 @@ - -

        Buffers and Encodings

        - -This package contains buffers and utils to perform encoding/decoding of buffers. That includes byte to char -conversions, URL encodings, etc. - -

        -Encoding is a critical operation for performance. There are few tricks in this package - the C2B and -B2C converters are caching a ISReader/OSWriter and keep everything allocated to do the conversions -in any VM without any garbage. - -

        -This package must accomodate future extensions and additional converters ( most imporant: the nio.charset, -which should be detected and used if available ). Also, we do have one hand-written UTF8Decoder, and -other tuned encoders could be added. - -

        -My benchmarks ( I'm costin :-) show only small differences between C2B, B2C and hand-written codders/decoders, -so UTF8Decoder may be disabled. - -

        - + +

        Buffers and Encodings

        + +This package contains buffers and utils to perform encoding/decoding of buffers. That includes byte to char +conversions, URL encodings, etc. + +

        +Encoding is a critical operation for performance. There are few tricks in this package - the C2B and +B2C converters are caching a ISReader/OSWriter and keep everything allocated to do the conversions +in any VM without any garbage. + +

        +This package must accomodate future extensions and additional converters ( most imporant: the nio.charset, +which should be detected and used if available ). Also, we do have one hand-written UTF8Decoder, and +other tuned encoders could be added. + +

        +My benchmarks ( I'm costin :-) show only small differences between C2B, B2C and hand-written codders/decoders, +so UTF8Decoder may be disabled. + +

        + diff --git a/java/org/apache/tomcat/util/buf/res/LocalStrings.properties b/java/org/apache/tomcat/util/buf/res/LocalStrings.properties index 86293b302..b73ad24aa 100644 --- a/java/org/apache/tomcat/util/buf/res/LocalStrings.properties +++ b/java/org/apache/tomcat/util/buf/res/LocalStrings.properties @@ -1,3 +1,3 @@ -hexUtil.bad=Bad hexadecimal digit -hexUtil.odd=Odd number of hexadecimal digits -httpDate.pe=invalid date format: {0} +hexUtil.bad=Bad hexadecimal digit +hexUtil.odd=Odd number of hexadecimal digits +httpDate.pe=invalid date format: {0} diff --git a/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties b/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties index 20666b0b1..064ad76fc 100644 --- a/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties +++ b/java/org/apache/tomcat/util/buf/res/LocalStrings_es.properties @@ -1,4 +1,4 @@ -hexUtil.bad=Dígito hexadecimal incorrecto -hexUtil.odd=Número de dígitos hexadecimales incorrecto -httpDate.pe=formato de fecha no válido: {0} - +hexUtil.bad=Dígito hexadecimal incorrecto +hexUtil.odd=Número de dígitos hexadecimales incorrecto +httpDate.pe=formato de fecha no válido: {0} + diff --git a/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties b/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties index fbc1c915e..8930be1f6 100644 --- a/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties +++ b/java/org/apache/tomcat/util/buf/res/LocalStrings_fr.properties @@ -1,3 +1,3 @@ -hexUtil.bad=Mauvais digit hexadécimal -hexUtil.odd=Nombre impair de digits hexadécimaux -httpDate.pe=Format de date invalide: {0} +hexUtil.bad=Mauvais digit hexadécimal +hexUtil.odd=Nombre impair de digits hexadécimaux +httpDate.pe=Format de date invalide: {0} diff --git a/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties b/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties index 59dca485d..8c03dec65 100644 --- a/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties +++ b/java/org/apache/tomcat/util/buf/res/LocalStrings_ja.properties @@ -1,3 +1,3 @@ -hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059 -hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059 -httpDate.pe=\u7121\u52b9\u306a\u65e5\u4ed8\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059: {0} +hexUtil.bad=\u7121\u52b9\u306a16\u9032\u6570\u5024\u3067\u3059 +hexUtil.odd=\u5947\u6570\u6841\u306e16\u9032\u6570\u5024\u3067\u3059 +httpDate.pe=\u7121\u52b9\u306a\u65e5\u4ed8\u30d5\u30a9\u30fc\u30de\u30c3\u30c8\u3067\u3059: {0} diff --git a/java/org/apache/tomcat/util/collections/EmptyEnumeration.java b/java/org/apache/tomcat/util/collections/EmptyEnumeration.java index 3bae7c6c4..7154488ea 100644 --- a/java/org/apache/tomcat/util/collections/EmptyEnumeration.java +++ b/java/org/apache/tomcat/util/collections/EmptyEnumeration.java @@ -1,41 +1,41 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.collections; - -import java.util.Enumeration; -import java.util.NoSuchElementException; - -public class EmptyEnumeration implements Enumeration { - - static EmptyEnumeration staticInstance=new EmptyEnumeration(); - - public EmptyEnumeration() { - } - - public static Enumeration getEmptyEnumeration() { - return staticInstance; - } - - public Object nextElement( ) { - throw new NoSuchElementException( "EmptyEnumeration"); - } - - public boolean hasMoreElements() { - return false; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.collections; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + +public class EmptyEnumeration implements Enumeration { + + static EmptyEnumeration staticInstance=new EmptyEnumeration(); + + public EmptyEnumeration() { + } + + public static Enumeration getEmptyEnumeration() { + return staticInstance; + } + + public Object nextElement( ) { + throw new NoSuchElementException( "EmptyEnumeration"); + } + + public boolean hasMoreElements() { + return false; + } + +} diff --git a/java/org/apache/tomcat/util/collections/LRUCache.java b/java/org/apache/tomcat/util/collections/LRUCache.java index a45ec7be4..f0896dc2c 100644 --- a/java/org/apache/tomcat/util/collections/LRUCache.java +++ b/java/org/apache/tomcat/util/collections/LRUCache.java @@ -1,150 +1,150 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.collections; - -import java.util.Hashtable; - -/** - * This class implements a Generic LRU Cache - * - * - * @author Ignacio J. Ortega - * - */ - -public class LRUCache -{ - class CacheNode - { - - CacheNode prev; - CacheNode next; - Object value; - Object key; - - CacheNode() - { - } - } - - - public LRUCache(int i) - { - currentSize = 0; - cacheSize = i; - nodes = new Hashtable(i); - } - - public Object get(Object key) - { - CacheNode node = (CacheNode)nodes.get(key); - if(node != null) - { - moveToHead(node); - return node.value; - } - else - { - return null; - } - } - - public void put(Object key, Object value) - { - CacheNode node = (CacheNode)nodes.get(key); - if(node == null) - { - if(currentSize >= cacheSize) - { - if(last != null) - nodes.remove(last.key); - removeLast(); - } - else - { - currentSize++; - } - node = new CacheNode(); - } - node.value = value; - node.key = key; - moveToHead(node); - nodes.put(key, node); - } - - public Object remove(Object key) { - CacheNode node = (CacheNode)nodes.get(key); - if (node != null) { - if (node.prev != null) { - node.prev.next = node.next; - } - if (node.next != null) { - node.next.prev = node.prev; - } - if (last == node) - last = node.prev; - if (first == node) - first = node.next; - } - return node; - } - - public void clear() - { - first = null; - last = null; - } - - private void removeLast() - { - if(last != null) - { - if(last.prev != null) - last.prev.next = null; - else - first = null; - last = last.prev; - } - } - - private void moveToHead(CacheNode node) - { - if(node == first) - return; - if(node.prev != null) - node.prev.next = node.next; - if(node.next != null) - node.next.prev = node.prev; - if(last == node) - last = node.prev; - if(first != null) - { - node.next = first; - first.prev = node; - } - first = node; - node.prev = null; - if(last == null) - last = first; - } - - private int cacheSize; - private Hashtable nodes; - private int currentSize; - private CacheNode first; - private CacheNode last; -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.collections; + +import java.util.Hashtable; + +/** + * This class implements a Generic LRU Cache + * + * + * @author Ignacio J. Ortega + * + */ + +public class LRUCache +{ + class CacheNode + { + + CacheNode prev; + CacheNode next; + Object value; + Object key; + + CacheNode() + { + } + } + + + public LRUCache(int i) + { + currentSize = 0; + cacheSize = i; + nodes = new Hashtable(i); + } + + public Object get(Object key) + { + CacheNode node = (CacheNode)nodes.get(key); + if(node != null) + { + moveToHead(node); + return node.value; + } + else + { + return null; + } + } + + public void put(Object key, Object value) + { + CacheNode node = (CacheNode)nodes.get(key); + if(node == null) + { + if(currentSize >= cacheSize) + { + if(last != null) + nodes.remove(last.key); + removeLast(); + } + else + { + currentSize++; + } + node = new CacheNode(); + } + node.value = value; + node.key = key; + moveToHead(node); + nodes.put(key, node); + } + + public Object remove(Object key) { + CacheNode node = (CacheNode)nodes.get(key); + if (node != null) { + if (node.prev != null) { + node.prev.next = node.next; + } + if (node.next != null) { + node.next.prev = node.prev; + } + if (last == node) + last = node.prev; + if (first == node) + first = node.next; + } + return node; + } + + public void clear() + { + first = null; + last = null; + } + + private void removeLast() + { + if(last != null) + { + if(last.prev != null) + last.prev.next = null; + else + first = null; + last = last.prev; + } + } + + private void moveToHead(CacheNode node) + { + if(node == first) + return; + if(node.prev != null) + node.prev.next = node.next; + if(node.next != null) + node.next.prev = node.prev; + if(last == node) + last = node.prev; + if(first != null) + { + node.next = first; + first.prev = node; + } + first = node; + node.prev = null; + if(last == null) + last = first; + } + + private int cacheSize; + private Hashtable nodes; + private int currentSize; + private CacheNode first; + private CacheNode last; +} diff --git a/java/org/apache/tomcat/util/collections/MultiMap.java b/java/org/apache/tomcat/util/collections/MultiMap.java index 5b8af7caa..3e60dbd9f 100644 --- a/java/org/apache/tomcat/util/collections/MultiMap.java +++ b/java/org/apache/tomcat/util/collections/MultiMap.java @@ -1,235 +1,235 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.collections; - -import org.apache.tomcat.util.buf.MessageBytes; - -// Originally MimeHeaders - -/** - * An efficient representation for certain type of map. The keys - * can have a single or multi values, but most of the time there are - * single values. - * - * The data is of "MessageBytes" type, meaning bytes[] that can be - * converted to Strings ( if needed, and encoding is lazy-binded ). - * - * This is a base class for MimeHeaders, Parameters and Cookies. - * - * Data structures: each field is a single-valued key/value. - * The fields are allocated when needed, and are recycled. - * The current implementation does linear search, in future we'll - * also use the hashkey. - * - * @author dac@eng.sun.com - * @author James Todd [gonzo@eng.sun.com] - * @author Costin Manolache - */ -public class MultiMap { - - protected Field[] fields; - // fields in use - protected int count; - - /** - * - */ - public MultiMap(int initial_size) { - fields=new Field[initial_size]; - } - - /** - * Clears all header fields. - */ - public void recycle() { - for (int i = 0; i < count; i++) { - fields[i].recycle(); - } - count = 0; - } - - // -------------------- Idx access to headers ---------- - // This allows external iterators. - - /** - * Returns the current number of header fields. - */ - public int size() { - return count; - } - - /** - * Returns the Nth header name - * This may be used to iterate through all header fields. - * - * An exception is thrown if the index is not valid ( <0 or >size ) - */ - public MessageBytes getName(int n) { - // n >= 0 && n < count ? headers[n].getName() : null - return fields[n].name; - } - - /** - * Returns the Nth header value - * This may be used to iterate through all header fields. - */ - public MessageBytes getValue(int n) { - return fields[n].value; - } - - /** Find the index of a field with the given name. - */ - public int find( String name, int starting ) { - // We can use a hash - but it's not clear how much - // benefit you can get - there is an overhead - // and the number of headers is small (4-5 ?) - // Another problem is that we'll pay the overhead - // of constructing the hashtable - - // A custom search tree may be better - for (int i = starting; i < count; i++) { - if (fields[i].name.equals(name)) { - return i; - } - } - return -1; - } - - /** Find the index of a field with the given name. - */ - public int findIgnoreCase( String name, int starting ) { - // We can use a hash - but it's not clear how much - // benefit you can get - there is an overhead - // and the number of headers is small (4-5 ?) - // Another problem is that we'll pay the overhead - // of constructing the hashtable - - // A custom search tree may be better - for (int i = starting; i < count; i++) { - if (fields[i].name.equalsIgnoreCase(name)) { - return i; - } - } - return -1; - } - - /** - * Removes the field at the specified position. - * - * MultiMap will preserve the order of field add unless remove() - * is called. This is not thread-safe, and will invalidate all - * iterators. - * - * This is not a frequent operation for Headers and Parameters - - * there are better ways ( like adding a "isValid" field ) - */ - public void remove( int i ) { - // reset and swap with last header - Field mh = fields[i]; - // reset the field - mh.recycle(); - - fields[i] = fields[count - 1]; - fields[count - 1] = mh; - count--; - } - - /** Create a new, unitialized entry. - */ - public int addField() { - int len = fields.length; - int pos=count; - if (count >= len) { - // expand header list array - Field tmp[] = new Field[pos * 2]; - System.arraycopy(fields, 0, tmp, 0, len); - fields = tmp; - } - if (fields[pos] == null) { - fields[pos] = new Field(); - } - count++; - return pos; - } - - public MessageBytes get( String name) { - for (int i = 0; i < count; i++) { - if (fields[i].name.equals(name)) { - return fields[i].value; - } - } - return null; - } - - public int findFirst( String name ) { - for (int i = 0; i < count; i++) { - if (fields[i].name.equals(name)) { - return i; - } - } - return -1; - } - - public int findNext( int startPos ) { - int next= fields[startPos].nextPos; - if( next != MultiMap.NEED_NEXT ) { - return next; - } - - // next==NEED_NEXT, we never searched for this header - MessageBytes name=fields[startPos].name; - for (int i = startPos; i < count; i++) { - if (fields[i].name.equals(name)) { - // cache the search result - fields[startPos].nextPos=i; - return i; - } - } - fields[startPos].nextPos= MultiMap.LAST; - return -1; - } - - // workaround for JDK1.1.8/solaris - static final int NEED_NEXT=-2; - static final int LAST=-1; - - // -------------------- Internal representation -------------------- - final class Field { - MessageBytes name; - MessageBytes value; - - // Extra info for speed - - // multiple fields with same name - a linked list will - // speed up multiple name enumerations and search. - int nextPos; - - // hashkey - int hash; - Field nextSameHash; - - Field() { - nextPos=MultiMap.NEED_NEXT; - } - - void recycle() { - name.recycle(); - value.recycle(); - nextPos=MultiMap.NEED_NEXT; - } - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.collections; + +import org.apache.tomcat.util.buf.MessageBytes; + +// Originally MimeHeaders + +/** + * An efficient representation for certain type of map. The keys + * can have a single or multi values, but most of the time there are + * single values. + * + * The data is of "MessageBytes" type, meaning bytes[] that can be + * converted to Strings ( if needed, and encoding is lazy-binded ). + * + * This is a base class for MimeHeaders, Parameters and Cookies. + * + * Data structures: each field is a single-valued key/value. + * The fields are allocated when needed, and are recycled. + * The current implementation does linear search, in future we'll + * also use the hashkey. + * + * @author dac@eng.sun.com + * @author James Todd [gonzo@eng.sun.com] + * @author Costin Manolache + */ +public class MultiMap { + + protected Field[] fields; + // fields in use + protected int count; + + /** + * + */ + public MultiMap(int initial_size) { + fields=new Field[initial_size]; + } + + /** + * Clears all header fields. + */ + public void recycle() { + for (int i = 0; i < count; i++) { + fields[i].recycle(); + } + count = 0; + } + + // -------------------- Idx access to headers ---------- + // This allows external iterators. + + /** + * Returns the current number of header fields. + */ + public int size() { + return count; + } + + /** + * Returns the Nth header name + * This may be used to iterate through all header fields. + * + * An exception is thrown if the index is not valid ( <0 or >size ) + */ + public MessageBytes getName(int n) { + // n >= 0 && n < count ? headers[n].getName() : null + return fields[n].name; + } + + /** + * Returns the Nth header value + * This may be used to iterate through all header fields. + */ + public MessageBytes getValue(int n) { + return fields[n].value; + } + + /** Find the index of a field with the given name. + */ + public int find( String name, int starting ) { + // We can use a hash - but it's not clear how much + // benefit you can get - there is an overhead + // and the number of headers is small (4-5 ?) + // Another problem is that we'll pay the overhead + // of constructing the hashtable + + // A custom search tree may be better + for (int i = starting; i < count; i++) { + if (fields[i].name.equals(name)) { + return i; + } + } + return -1; + } + + /** Find the index of a field with the given name. + */ + public int findIgnoreCase( String name, int starting ) { + // We can use a hash - but it's not clear how much + // benefit you can get - there is an overhead + // and the number of headers is small (4-5 ?) + // Another problem is that we'll pay the overhead + // of constructing the hashtable + + // A custom search tree may be better + for (int i = starting; i < count; i++) { + if (fields[i].name.equalsIgnoreCase(name)) { + return i; + } + } + return -1; + } + + /** + * Removes the field at the specified position. + * + * MultiMap will preserve the order of field add unless remove() + * is called. This is not thread-safe, and will invalidate all + * iterators. + * + * This is not a frequent operation for Headers and Parameters - + * there are better ways ( like adding a "isValid" field ) + */ + public void remove( int i ) { + // reset and swap with last header + Field mh = fields[i]; + // reset the field + mh.recycle(); + + fields[i] = fields[count - 1]; + fields[count - 1] = mh; + count--; + } + + /** Create a new, unitialized entry. + */ + public int addField() { + int len = fields.length; + int pos=count; + if (count >= len) { + // expand header list array + Field tmp[] = new Field[pos * 2]; + System.arraycopy(fields, 0, tmp, 0, len); + fields = tmp; + } + if (fields[pos] == null) { + fields[pos] = new Field(); + } + count++; + return pos; + } + + public MessageBytes get( String name) { + for (int i = 0; i < count; i++) { + if (fields[i].name.equals(name)) { + return fields[i].value; + } + } + return null; + } + + public int findFirst( String name ) { + for (int i = 0; i < count; i++) { + if (fields[i].name.equals(name)) { + return i; + } + } + return -1; + } + + public int findNext( int startPos ) { + int next= fields[startPos].nextPos; + if( next != MultiMap.NEED_NEXT ) { + return next; + } + + // next==NEED_NEXT, we never searched for this header + MessageBytes name=fields[startPos].name; + for (int i = startPos; i < count; i++) { + if (fields[i].name.equals(name)) { + // cache the search result + fields[startPos].nextPos=i; + return i; + } + } + fields[startPos].nextPos= MultiMap.LAST; + return -1; + } + + // workaround for JDK1.1.8/solaris + static final int NEED_NEXT=-2; + static final int LAST=-1; + + // -------------------- Internal representation -------------------- + final class Field { + MessageBytes name; + MessageBytes value; + + // Extra info for speed + + // multiple fields with same name - a linked list will + // speed up multiple name enumerations and search. + int nextPos; + + // hashkey + int hash; + Field nextSameHash; + + Field() { + nextPos=MultiMap.NEED_NEXT; + } + + void recycle() { + name.recycle(); + value.recycle(); + nextPos=MultiMap.NEED_NEXT; + } + } +} diff --git a/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java b/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java index 651c8aa45..aa9620d7f 100644 --- a/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java +++ b/java/org/apache/tomcat/util/collections/MultiMapNamesEnumeration.java @@ -1,80 +1,80 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.collections; - -import java.util.Enumeration; - -/** Enumerate the distinct header names. - Each nextElement() is O(n) ( a comparation is - done with all previous elements ). - - This is less frequesnt than add() - - we want to keep add O(1). -*/ -public final class MultiMapNamesEnumeration implements Enumeration { - int pos; - int size; - String next; - MultiMap headers; - - // toString and unique options are not implemented - - // we allways to toString and unique. - - /** Create a new multi-map enumeration. - * @param headers the collection to enumerate - * @param toString convert each name to string - * @param unique return only unique names - */ - MultiMapNamesEnumeration(MultiMap headers, boolean toString, - boolean unique) { - this.headers=headers; - pos=0; - size = headers.size(); - findNext(); - } - - private void findNext() { - next=null; - for( ; pos< size; pos++ ) { - next=headers.getName( pos ).toString(); - for( int j=0; jjava.util.Hashtable except that:

          - * - *
        1. Keys to "get" are strings which are known to be interned, - * so that "==" is used instead of "String.equals". (Interning - * could be document-relative instead of global.) - * - *
        2. It's not synchronized, since it's to be used only by - * one thread at a time. - * - *
        3. The keys () enumerator allocates no memory, with live - * updates to the data disallowed. - * - *
        4. It's got fewer bells and whistles: fixed threshold and - * load factor, no JDK 1.2 collection support, only keys can be - * enumerated, things can't be removed, simpler inheritance; more. - * - *
        - * - *

        The overall result is that it's less expensive to use these in - * performance-critical locations, in terms both of CPU and memory, - * than java.util.Hashtable instances. In this package - * it makes a significant difference when normalizing attributes, - * which is done for each start-element construct. - * - */ -public final class SimpleHashtable implements Enumeration -{ - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog( SimpleHashtable.class ); - - // entries ... - private Entry table[]; - - // currently enumerated key - private Entry current = null; - private int currentBucket = 0; - - // number of elements in hashtable - private int count; - private int threshold; - - private static final float loadFactor = 0.75f; - - - /** - * Constructs a new, empty hashtable with the specified initial - * capacity. - * - * @param initialCapacity the initial capacity of the hashtable. - */ - public SimpleHashtable(int initialCapacity) { - if (initialCapacity < 0) - throw new IllegalArgumentException("Illegal Capacity: "+ - initialCapacity); - if (initialCapacity==0) - initialCapacity = 1; - table = new Entry[initialCapacity]; - threshold = (int)(initialCapacity * loadFactor); - } - - /** - * Constructs a new, empty hashtable with a default capacity. - */ - public SimpleHashtable() { - this(11); - } - - /** - */ - public void clear () - { - count = 0; - currentBucket = 0; - current = null; - for (int i = 0; i < table.length; i++) - table [i] = null; - } - - /** - * Returns the number of keys in this hashtable. - * - * @return the number of keys in this hashtable. - */ - public int size() { - return count; - } - - /** - * Returns an enumeration of the keys in this hashtable. - * - * @return an enumeration of the keys in this hashtable. - * @see Enumeration - */ - public Enumeration keys() { - currentBucket = 0; - current = null; - hasMoreElements(); - return this; - } - - /** - * Used to view this as an enumeration; returns true if there - * are more keys to be enumerated. - */ - public boolean hasMoreElements () - { - if (current != null) - return true; - while (currentBucket < table.length) { - current = table [currentBucket++]; - if (current != null) - return true; - } - return false; - } - - /** - * Used to view this as an enumeration; returns the next key - * in the enumeration. - */ - public Object nextElement () - { - Object retval; - - if (current == null) - throw new IllegalStateException (); - retval = current.key; - current = current.next; - // Advance to the next position ( we may call next after next, - // without hasMore ) - hasMoreElements(); - return retval; - } - - - /** - * Returns the value to which the specified key is mapped in this hashtable. - */ - public Object getInterned (String key) { - Entry tab[] = table; - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % tab.length; - for (Entry e = tab[index] ; e != null ; e = e.next) { - if ((e.hash == hash) && (e.key == key)) - return e.value; - } - return null; - } - - /** - * Returns the value to which the specified key is mapped in this - * hashtable ... the key isn't necessarily interned, though. - */ - public Object get(String key) { - Entry tab[] = table; - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % tab.length; - for (Entry e = tab[index] ; e != null ; e = e.next) { - if ((e.hash == hash) && e.key.equals(key)) - return e.value; - } - return null; - } - - /** - * Increases the capacity of and internally reorganizes this - * hashtable, in order to accommodate and access its entries more - * efficiently. This method is called automatically when the - * number of keys in the hashtable exceeds this hashtable's capacity - * and load factor. - */ - private void rehash() { - int oldCapacity = table.length; - Entry oldMap[] = table; - - int newCapacity = oldCapacity * 2 + 1; - Entry newMap[] = new Entry[newCapacity]; - - threshold = (int)(newCapacity * loadFactor); - table = newMap; - - /* - System.out.pr intln("rehash old=" + oldCapacity - + ", new=" + newCapacity - + ", thresh=" + threshold - + ", count=" + count); - */ - - for (int i = oldCapacity ; i-- > 0 ;) { - for (Entry old = oldMap[i] ; old != null ; ) { - Entry e = old; - old = old.next; - - int index = (e.hash & 0x7FFFFFFF) % newCapacity; - e.next = newMap[index]; - newMap[index] = e; - } - } - } - - /** - * Maps the specified key to the specified - * value in this hashtable. Neither the key nor the - * value can be null. - * - *

        The value can be retrieved by calling the get method - * with a key that is equal to the original key. - */ - public Object put(Object key, Object value) { - // Make sure the value is not null - if (value == null) { - throw new NullPointerException(); - } - - // Makes sure the key is not already in the hashtable. - Entry tab[] = table; - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % tab.length; - for (Entry e = tab[index] ; e != null ; e = e.next) { - // if ((e.hash == hash) && e.key.equals(key)) { - if ((e.hash == hash) && (e.key == key)) { - Object old = e.value; - e.value = value; - return old; - } - } - - if (count >= threshold) { - // Rehash the table if the threshold is exceeded - rehash(); - - tab = table; - index = (hash & 0x7FFFFFFF) % tab.length; - } - - // Creates the new entry. - Entry e = new Entry(hash, key, value, tab[index]); - tab[index] = e; - count++; - return null; - } - - public Object remove(Object key) { - Entry tab[] = table; - Entry prev=null; - int hash = key.hashCode(); - int index = (hash & 0x7FFFFFFF) % tab.length; - if( dL > 0 ) d("Idx " + index + " " + tab[index] ); - for (Entry e = tab[index] ; e != null ; prev=e, e = e.next) { - if( dL > 0 ) d("> " + prev + " " + e.next + " " + e + " " + e.key); - if ((e.hash == hash) && e.key.equals(key)) { - if( prev!=null ) { - prev.next=e.next; - } else { - tab[index]=e.next; - } - if( dL > 0 ) d("Removing from list " + tab[index] + " " + prev + - " " + e.value); - count--; - Object res=e.value; - e.value=null; - return res; - } - } - return null; - } - - /** - * Hashtable collision list. - */ - private static class Entry { - int hash; - Object key; - Object value; - Entry next; - - protected Entry(int hash, Object key, Object value, Entry next) { - this.hash = hash; - this.key = key; - this.value = value; - this.next = next; - } - } - - private static final int dL=0; - private void d(String s ) { - if (log.isDebugEnabled()) - log.debug( "SimpleHashtable: " + s ); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.collections; + +import java.util.Enumeration; + +/* **************************************** Stolen from Crimson ******************** */ +/* From Crimson/Parser - in a perfect world we'll just have a common set of + utilities, and all apache project will just use those. + +*/ + +// can't be replaced using a Java 2 "Collections" API +// since this package must also run on JDK 1.1 + + +/** + * This class implements a special purpose hashtable. It works like a + * normal java.util.Hashtable except that:

          + * + *
        1. Keys to "get" are strings which are known to be interned, + * so that "==" is used instead of "String.equals". (Interning + * could be document-relative instead of global.) + * + *
        2. It's not synchronized, since it's to be used only by + * one thread at a time. + * + *
        3. The keys () enumerator allocates no memory, with live + * updates to the data disallowed. + * + *
        4. It's got fewer bells and whistles: fixed threshold and + * load factor, no JDK 1.2 collection support, only keys can be + * enumerated, things can't be removed, simpler inheritance; more. + * + *
        + * + *

        The overall result is that it's less expensive to use these in + * performance-critical locations, in terms both of CPU and memory, + * than java.util.Hashtable instances. In this package + * it makes a significant difference when normalizing attributes, + * which is done for each start-element construct. + * + */ +public final class SimpleHashtable implements Enumeration +{ + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog( SimpleHashtable.class ); + + // entries ... + private Entry table[]; + + // currently enumerated key + private Entry current = null; + private int currentBucket = 0; + + // number of elements in hashtable + private int count; + private int threshold; + + private static final float loadFactor = 0.75f; + + + /** + * Constructs a new, empty hashtable with the specified initial + * capacity. + * + * @param initialCapacity the initial capacity of the hashtable. + */ + public SimpleHashtable(int initialCapacity) { + if (initialCapacity < 0) + throw new IllegalArgumentException("Illegal Capacity: "+ + initialCapacity); + if (initialCapacity==0) + initialCapacity = 1; + table = new Entry[initialCapacity]; + threshold = (int)(initialCapacity * loadFactor); + } + + /** + * Constructs a new, empty hashtable with a default capacity. + */ + public SimpleHashtable() { + this(11); + } + + /** + */ + public void clear () + { + count = 0; + currentBucket = 0; + current = null; + for (int i = 0; i < table.length; i++) + table [i] = null; + } + + /** + * Returns the number of keys in this hashtable. + * + * @return the number of keys in this hashtable. + */ + public int size() { + return count; + } + + /** + * Returns an enumeration of the keys in this hashtable. + * + * @return an enumeration of the keys in this hashtable. + * @see Enumeration + */ + public Enumeration keys() { + currentBucket = 0; + current = null; + hasMoreElements(); + return this; + } + + /** + * Used to view this as an enumeration; returns true if there + * are more keys to be enumerated. + */ + public boolean hasMoreElements () + { + if (current != null) + return true; + while (currentBucket < table.length) { + current = table [currentBucket++]; + if (current != null) + return true; + } + return false; + } + + /** + * Used to view this as an enumeration; returns the next key + * in the enumeration. + */ + public Object nextElement () + { + Object retval; + + if (current == null) + throw new IllegalStateException (); + retval = current.key; + current = current.next; + // Advance to the next position ( we may call next after next, + // without hasMore ) + hasMoreElements(); + return retval; + } + + + /** + * Returns the value to which the specified key is mapped in this hashtable. + */ + public Object getInterned (String key) { + Entry tab[] = table; + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index] ; e != null ; e = e.next) { + if ((e.hash == hash) && (e.key == key)) + return e.value; + } + return null; + } + + /** + * Returns the value to which the specified key is mapped in this + * hashtable ... the key isn't necessarily interned, though. + */ + public Object get(String key) { + Entry tab[] = table; + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index] ; e != null ; e = e.next) { + if ((e.hash == hash) && e.key.equals(key)) + return e.value; + } + return null; + } + + /** + * Increases the capacity of and internally reorganizes this + * hashtable, in order to accommodate and access its entries more + * efficiently. This method is called automatically when the + * number of keys in the hashtable exceeds this hashtable's capacity + * and load factor. + */ + private void rehash() { + int oldCapacity = table.length; + Entry oldMap[] = table; + + int newCapacity = oldCapacity * 2 + 1; + Entry newMap[] = new Entry[newCapacity]; + + threshold = (int)(newCapacity * loadFactor); + table = newMap; + + /* + System.out.pr intln("rehash old=" + oldCapacity + + ", new=" + newCapacity + + ", thresh=" + threshold + + ", count=" + count); + */ + + for (int i = oldCapacity ; i-- > 0 ;) { + for (Entry old = oldMap[i] ; old != null ; ) { + Entry e = old; + old = old.next; + + int index = (e.hash & 0x7FFFFFFF) % newCapacity; + e.next = newMap[index]; + newMap[index] = e; + } + } + } + + /** + * Maps the specified key to the specified + * value in this hashtable. Neither the key nor the + * value can be null. + * + *

        The value can be retrieved by calling the get method + * with a key that is equal to the original key. + */ + public Object put(Object key, Object value) { + // Make sure the value is not null + if (value == null) { + throw new NullPointerException(); + } + + // Makes sure the key is not already in the hashtable. + Entry tab[] = table; + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % tab.length; + for (Entry e = tab[index] ; e != null ; e = e.next) { + // if ((e.hash == hash) && e.key.equals(key)) { + if ((e.hash == hash) && (e.key == key)) { + Object old = e.value; + e.value = value; + return old; + } + } + + if (count >= threshold) { + // Rehash the table if the threshold is exceeded + rehash(); + + tab = table; + index = (hash & 0x7FFFFFFF) % tab.length; + } + + // Creates the new entry. + Entry e = new Entry(hash, key, value, tab[index]); + tab[index] = e; + count++; + return null; + } + + public Object remove(Object key) { + Entry tab[] = table; + Entry prev=null; + int hash = key.hashCode(); + int index = (hash & 0x7FFFFFFF) % tab.length; + if( dL > 0 ) d("Idx " + index + " " + tab[index] ); + for (Entry e = tab[index] ; e != null ; prev=e, e = e.next) { + if( dL > 0 ) d("> " + prev + " " + e.next + " " + e + " " + e.key); + if ((e.hash == hash) && e.key.equals(key)) { + if( prev!=null ) { + prev.next=e.next; + } else { + tab[index]=e.next; + } + if( dL > 0 ) d("Removing from list " + tab[index] + " " + prev + + " " + e.value); + count--; + Object res=e.value; + e.value=null; + return res; + } + } + return null; + } + + /** + * Hashtable collision list. + */ + private static class Entry { + int hash; + Object key; + Object value; + Entry next; + + protected Entry(int hash, Object key, Object value, Entry next) { + this.hash = hash; + this.key = key; + this.value = value; + this.next = next; + } + } + + private static final int dL=0; + private void d(String s ) { + if (log.isDebugEnabled()) + log.debug( "SimpleHashtable: " + s ); + } +} diff --git a/java/org/apache/tomcat/util/collections/SimplePool.java b/java/org/apache/tomcat/util/collections/SimplePool.java index 6bc29e4ee..fcd621262 100644 --- a/java/org/apache/tomcat/util/collections/SimplePool.java +++ b/java/org/apache/tomcat/util/collections/SimplePool.java @@ -1,127 +1,127 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.collections; - -/** - * Simple object pool. Based on ThreadPool and few other classes - * - * The pool will ignore overflow and return null if empty. - * - * @author Gal Shachor - * @author Costin Manolache - */ -public final class SimplePool { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(SimplePool.class ); - - /* - * Where the threads are held. - */ - private Object pool[]; - - private int max; - private int last; - private int current=-1; - - private Object lock; - public static final int DEFAULT_SIZE=32; - static final int debug=0; - - public SimplePool() { - this(DEFAULT_SIZE,DEFAULT_SIZE); - } - - public SimplePool(int size) { - this(size, size); - } - - public SimplePool(int size, int max) { - this.max=max; - pool=new Object[size]; - this.last=size-1; - lock=new Object(); - } - - public void set(Object o) { - put(o); - } - - /** - * Add the object to the pool, silent nothing if the pool is full - */ - public void put(Object o) { - synchronized( lock ) { - if( current < last ) { - current++; - pool[current] = o; - } else if( current < max ) { - // realocate - int newSize=pool.length*2; - if( newSize > max ) newSize=max+1; - Object tmp[]=new Object[newSize]; - last=newSize-1; - System.arraycopy( pool, 0, tmp, 0, pool.length); - pool=tmp; - current++; - pool[current] = o; - } - if( debug > 0 ) log("put " + o + " " + current + " " + max ); - } - } - - /** - * Get an object from the pool, null if the pool is empty. - */ - public Object get() { - Object item = null; - synchronized( lock ) { - if( current >= 0 ) { - item = pool[current]; - pool[current] = null; - current -= 1; - } - if( debug > 0 ) - log("get " + item + " " + current + " " + max); - } - return item; - } - - /** - * Return the size of the pool - */ - public int getMax() { - return max; - } - - /** - * Number of object in the pool - */ - public int getCount() { - return current+1; - } - - - public void shutdown() { - } - - private void log( String s ) { - if (log.isDebugEnabled()) - log.debug("SimplePool: " + s ); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.collections; + +/** + * Simple object pool. Based on ThreadPool and few other classes + * + * The pool will ignore overflow and return null if empty. + * + * @author Gal Shachor + * @author Costin Manolache + */ +public final class SimplePool { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(SimplePool.class ); + + /* + * Where the threads are held. + */ + private Object pool[]; + + private int max; + private int last; + private int current=-1; + + private Object lock; + public static final int DEFAULT_SIZE=32; + static final int debug=0; + + public SimplePool() { + this(DEFAULT_SIZE,DEFAULT_SIZE); + } + + public SimplePool(int size) { + this(size, size); + } + + public SimplePool(int size, int max) { + this.max=max; + pool=new Object[size]; + this.last=size-1; + lock=new Object(); + } + + public void set(Object o) { + put(o); + } + + /** + * Add the object to the pool, silent nothing if the pool is full + */ + public void put(Object o) { + synchronized( lock ) { + if( current < last ) { + current++; + pool[current] = o; + } else if( current < max ) { + // realocate + int newSize=pool.length*2; + if( newSize > max ) newSize=max+1; + Object tmp[]=new Object[newSize]; + last=newSize-1; + System.arraycopy( pool, 0, tmp, 0, pool.length); + pool=tmp; + current++; + pool[current] = o; + } + if( debug > 0 ) log("put " + o + " " + current + " " + max ); + } + } + + /** + * Get an object from the pool, null if the pool is empty. + */ + public Object get() { + Object item = null; + synchronized( lock ) { + if( current >= 0 ) { + item = pool[current]; + pool[current] = null; + current -= 1; + } + if( debug > 0 ) + log("get " + item + " " + current + " " + max); + } + return item; + } + + /** + * Return the size of the pool + */ + public int getMax() { + return max; + } + + /** + * Number of object in the pool + */ + public int getCount() { + return current+1; + } + + + public void shutdown() { + } + + private void log( String s ) { + if (log.isDebugEnabled()) + log.debug("SimplePool: " + s ); + } +} diff --git a/java/org/apache/tomcat/util/collections/package.html b/java/org/apache/tomcat/util/collections/package.html index 7cdab2f96..88c6bdb88 100644 --- a/java/org/apache/tomcat/util/collections/package.html +++ b/java/org/apache/tomcat/util/collections/package.html @@ -1,17 +1,17 @@ - - -util.collections - - - - -

        Specialized collections

        - -This package includes a number of special collections, tunned for server-side -applications. - -The utils are not tomcat specific, but use MessageBytes and few other -top-level utils. - - - + + +util.collections + + + + +

        Specialized collections

        + +This package includes a number of special collections, tunned for server-side +applications. + +The utils are not tomcat specific, but use MessageBytes and few other +top-level utils. + + + diff --git a/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java b/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java index 77f15d84f..4cddfddd4 100644 --- a/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java +++ b/java/org/apache/tomcat/util/digester/AbstractObjectCreationFactory.java @@ -1,78 +1,78 @@ -/* $Id: AbstractObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - - -/** - *

        Abstract base class for ObjectCreationFactory - * implementations.

        - */ -abstract public class AbstractObjectCreationFactory implements ObjectCreationFactory { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The associated Digester instance that was set up by - * {@link FactoryCreateRule} upon initialization. - */ - protected Digester digester = null; - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Factory method called by {@link FactoryCreateRule} to supply an - * object based on the element's attributes. - * - * @param attributes the element's attributes - * - * @throws Exception any exception thrown will be propagated upwards - */ - public abstract Object createObject(Attributes attributes) throws Exception; - - - /** - *

        Returns the {@link Digester} that was set by the - * {@link FactoryCreateRule} upon initialization. - */ - public Digester getDigester() { - - return (this.digester); - - } - - - /** - *

        Set the {@link Digester} to allow the implementation to do logging, - * classloading based on the digester's classloader, etc. - * - * @param digester parent Digester object - */ - public void setDigester(Digester digester) { - - this.digester = digester; - - } - - -} +/* $Id: AbstractObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + + +/** + *

        Abstract base class for ObjectCreationFactory + * implementations.

        + */ +abstract public class AbstractObjectCreationFactory implements ObjectCreationFactory { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The associated Digester instance that was set up by + * {@link FactoryCreateRule} upon initialization. + */ + protected Digester digester = null; + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Factory method called by {@link FactoryCreateRule} to supply an + * object based on the element's attributes. + * + * @param attributes the element's attributes + * + * @throws Exception any exception thrown will be propagated upwards + */ + public abstract Object createObject(Attributes attributes) throws Exception; + + + /** + *

        Returns the {@link Digester} that was set by the + * {@link FactoryCreateRule} upon initialization. + */ + public Digester getDigester() { + + return (this.digester); + + } + + + /** + *

        Set the {@link Digester} to allow the implementation to do logging, + * classloading based on the digester's classloader, etc. + * + * @param digester parent Digester object + */ + public void setDigester(Digester digester) { + + this.digester = digester; + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java b/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java index 9e2aa4bee..f934022b0 100644 --- a/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java +++ b/java/org/apache/tomcat/util/digester/AbstractRulesImpl.java @@ -1,166 +1,166 @@ -/* $Id: AbstractRulesImpl.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import java.util.List; - - -/** - *

        AbstractRuleImpl provides basic services for Rules implementations. - * Extending this class should make it easier to create a Rules implementation.

        - * - *

        AbstractRuleImpl manages the Digester - * and namespaceUri properties. - * If the subclass overrides {@link #registerRule} (rather than {@link #add}), - * then the Digester and namespaceURI of the Rule - * will be set correctly before it is passed to registerRule. - * The subclass can then perform whatever it needs to do to register the rule.

        - * - * @since 1.5 - */ - -abstract public class AbstractRulesImpl implements Rules { - - // ------------------------------------------------------------- Fields - - /** Digester using this Rules implementation */ - private Digester digester; - /** Namespace uri to assoicate with subsequent Rule's */ - private String namespaceURI; - - // ------------------------------------------------------------- Properties - - /** - * Return the Digester instance with which this Rules instance is - * associated. - */ - public Digester getDigester() { - return digester; - } - - /** - * Set the Digester instance with which this Rules instance is associated. - * - * @param digester The newly associated Digester instance - */ - public void setDigester(Digester digester) { - this.digester = digester; - } - - /** - * Return the namespace URI that will be applied to all subsequently - * added Rule objects. - */ - public String getNamespaceURI() { - return namespaceURI; - } - - /** - * Set the namespace URI that will be applied to all subsequently - * added Rule objects. - * - * @param namespaceURI Namespace URI that must match on all - * subsequently added rules, or null for matching - * regardless of the current namespace URI - */ - public void setNamespaceURI(String namespaceURI) { - this.namespaceURI = namespaceURI; - } - - // --------------------------------------------------------- Public Methods - - /** - * Registers a new Rule instance matching the specified pattern. - * This implementation sets the Digester and the - * namespaceURI on the Rule before calling {@link #registerRule}. - * - * @param pattern Nesting pattern to be matched for this Rule - * @param rule Rule instance to be registered - */ - public void add(String pattern, Rule rule) { - // set up rule - if (this.digester != null) { - rule.setDigester(this.digester); - } - - if (this.namespaceURI != null) { - rule.setNamespaceURI(this.namespaceURI); - } - - registerRule(pattern, rule); - - } - - /** - * Register rule at given pattern. - * The the Digester and namespaceURI properties of the given Rule - * can be assumed to have been set properly before this method is called. - * - * @param pattern Nesting pattern to be matched for this Rule - * @param rule Rule instance to be registered - */ - abstract protected void registerRule(String pattern, Rule rule); - - /** - * Clear all existing Rule instance registrations. - */ - abstract public void clear(); - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param pattern Nesting pattern to be matched - * - * @deprecated Call match(namespaceURI,pattern) instead. - */ - public List match(String pattern) { - return match(namespaceURI, pattern); - } - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param namespaceURI Namespace URI for which to select matching rules, - * or null to match regardless of namespace URI - * @param pattern Nesting pattern to be matched - */ - abstract public List match(String namespaceURI, String pattern); - - - /** - * Return a List of all registered Rule instances, or a zero-length List - * if there are no registered Rule instances. If more than one Rule - * instance has been registered, they must be returned - * in the order originally registered through the add() - * method. - */ - abstract public List rules(); - -} +/* $Id: AbstractRulesImpl.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import java.util.List; + + +/** + *

        AbstractRuleImpl provides basic services for Rules implementations. + * Extending this class should make it easier to create a Rules implementation.

        + * + *

        AbstractRuleImpl manages the Digester + * and namespaceUri properties. + * If the subclass overrides {@link #registerRule} (rather than {@link #add}), + * then the Digester and namespaceURI of the Rule + * will be set correctly before it is passed to registerRule. + * The subclass can then perform whatever it needs to do to register the rule.

        + * + * @since 1.5 + */ + +abstract public class AbstractRulesImpl implements Rules { + + // ------------------------------------------------------------- Fields + + /** Digester using this Rules implementation */ + private Digester digester; + /** Namespace uri to assoicate with subsequent Rule's */ + private String namespaceURI; + + // ------------------------------------------------------------- Properties + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester() { + return digester; + } + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester) { + this.digester = digester; + } + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI() { + return namespaceURI; + } + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI) { + this.namespaceURI = namespaceURI; + } + + // --------------------------------------------------------- Public Methods + + /** + * Registers a new Rule instance matching the specified pattern. + * This implementation sets the Digester and the + * namespaceURI on the Rule before calling {@link #registerRule}. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule) { + // set up rule + if (this.digester != null) { + rule.setDigester(this.digester); + } + + if (this.namespaceURI != null) { + rule.setNamespaceURI(this.namespaceURI); + } + + registerRule(pattern, rule); + + } + + /** + * Register rule at given pattern. + * The the Digester and namespaceURI properties of the given Rule + * can be assumed to have been set properly before this method is called. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + abstract protected void registerRule(String pattern, Rule rule); + + /** + * Clear all existing Rule instance registrations. + */ + abstract public void clear(); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + public List match(String pattern) { + return match(namespaceURI, pattern); + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + abstract public List match(String namespaceURI, String pattern); + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + abstract public List rules(); + +} diff --git a/java/org/apache/tomcat/util/digester/ArrayStack.java b/java/org/apache/tomcat/util/digester/ArrayStack.java index 5581f09dd..3410263ab 100644 --- a/java/org/apache/tomcat/util/digester/ArrayStack.java +++ b/java/org/apache/tomcat/util/digester/ArrayStack.java @@ -1,168 +1,168 @@ -/* $Id: ArrayStack.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.tomcat.util.digester; - -import java.util.ArrayList; -import java.util.EmptyStackException; - -/** - *

        Imported copy of the ArrayStack class from - * Commons Collections, which was the only direct dependency from Digester.

        - * - *

        WARNNG - This class is public solely to allow it to be - * used from subpackages of org.apache.commons.digester. - * It should not be considered part of the public API of Commons Digester. - * If you want to use such a class yourself, you should use the one from - * Commons Collections directly.

        - * - *

        An implementation of the {@link java.util.Stack} API that is based on an - * ArrayList instead of a Vector, so it is not - * synchronized to protect against multi-threaded access. The implementation - * is therefore operates faster in environments where you do not need to - * worry about multiple thread contention.

        - * - *

        Unlike Stack, ArrayStack accepts null entries. - *

        - * - * @see java.util.Stack - * @since Digester 1.6 (from Commons Collections 1.0) - */ -public class ArrayStack extends ArrayList { - - /** Ensure serialization compatibility */ - private static final long serialVersionUID = 2130079159931574599L; - - /** - * Constructs a new empty ArrayStack. The initial size - * is controlled by ArrayList and is currently 10. - */ - public ArrayStack() { - super(); - } - - /** - * Constructs a new empty ArrayStack with an initial size. - * - * @param initialSize the initial size to use - * @throws IllegalArgumentException if the specified initial size - * is negative - */ - public ArrayStack(int initialSize) { - super(initialSize); - } - - /** - * Return true if this stack is currently empty. - *

        - * This method exists for compatibility with java.util.Stack. - * New users of this class should use isEmpty instead. - * - * @return true if the stack is currently empty - */ - public boolean empty() { - return isEmpty(); - } - - /** - * Returns the top item off of this stack without removing it. - * - * @return the top item on the stack - * @throws EmptyStackException if the stack is empty - */ - public Object peek() throws EmptyStackException { - int n = size(); - if (n <= 0) { - throw new EmptyStackException(); - } else { - return get(n - 1); - } - } - - /** - * Returns the n'th item down (zero-relative) from the top of this - * stack without removing it. - * - * @param n the number of items down to go - * @return the n'th item on the stack, zero relative - * @throws EmptyStackException if there are not enough items on the - * stack to satisfy this request - */ - public Object peek(int n) throws EmptyStackException { - int m = (size() - n) - 1; - if (m < 0) { - throw new EmptyStackException(); - } else { - return get(m); - } - } - - /** - * Pops the top item off of this stack and return it. - * - * @return the top item on the stack - * @throws EmptyStackException if the stack is empty - */ - public Object pop() throws EmptyStackException { - int n = size(); - if (n <= 0) { - throw new EmptyStackException(); - } else { - return remove(n - 1); - } - } - - /** - * Pushes a new item onto the top of this stack. The pushed item is also - * returned. This is equivalent to calling add. - * - * @param item the item to be added - * @return the item just pushed - */ - public Object push(Object item) { - add(item); - return item; - } - - - /** - * Returns the one-based position of the distance from the top that the - * specified object exists on this stack, where the top-most element is - * considered to be at distance 1. If the object is not - * present on the stack, return -1 instead. The - * equals() method is used to compare to the items - * in this stack. - * - * @param object the object to be searched for - * @return the 1-based depth into the stack of the object, or -1 if not found - */ - public int search(Object object) { - int i = size() - 1; // Current index - int n = 1; // Current distance - while (i >= 0) { - Object current = get(i); - if ((object == null && current == null) || - (object != null && object.equals(current))) { - return n; - } - i--; - n++; - } - return -1; - } - - -} +/* $Id: ArrayStack.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.tomcat.util.digester; + +import java.util.ArrayList; +import java.util.EmptyStackException; + +/** + *

        Imported copy of the ArrayStack class from + * Commons Collections, which was the only direct dependency from Digester.

        + * + *

        WARNNG - This class is public solely to allow it to be + * used from subpackages of org.apache.commons.digester. + * It should not be considered part of the public API of Commons Digester. + * If you want to use such a class yourself, you should use the one from + * Commons Collections directly.

        + * + *

        An implementation of the {@link java.util.Stack} API that is based on an + * ArrayList instead of a Vector, so it is not + * synchronized to protect against multi-threaded access. The implementation + * is therefore operates faster in environments where you do not need to + * worry about multiple thread contention.

        + * + *

        Unlike Stack, ArrayStack accepts null entries. + *

        + * + * @see java.util.Stack + * @since Digester 1.6 (from Commons Collections 1.0) + */ +public class ArrayStack extends ArrayList { + + /** Ensure serialization compatibility */ + private static final long serialVersionUID = 2130079159931574599L; + + /** + * Constructs a new empty ArrayStack. The initial size + * is controlled by ArrayList and is currently 10. + */ + public ArrayStack() { + super(); + } + + /** + * Constructs a new empty ArrayStack with an initial size. + * + * @param initialSize the initial size to use + * @throws IllegalArgumentException if the specified initial size + * is negative + */ + public ArrayStack(int initialSize) { + super(initialSize); + } + + /** + * Return true if this stack is currently empty. + *

        + * This method exists for compatibility with java.util.Stack. + * New users of this class should use isEmpty instead. + * + * @return true if the stack is currently empty + */ + public boolean empty() { + return isEmpty(); + } + + /** + * Returns the top item off of this stack without removing it. + * + * @return the top item on the stack + * @throws EmptyStackException if the stack is empty + */ + public Object peek() throws EmptyStackException { + int n = size(); + if (n <= 0) { + throw new EmptyStackException(); + } else { + return get(n - 1); + } + } + + /** + * Returns the n'th item down (zero-relative) from the top of this + * stack without removing it. + * + * @param n the number of items down to go + * @return the n'th item on the stack, zero relative + * @throws EmptyStackException if there are not enough items on the + * stack to satisfy this request + */ + public Object peek(int n) throws EmptyStackException { + int m = (size() - n) - 1; + if (m < 0) { + throw new EmptyStackException(); + } else { + return get(m); + } + } + + /** + * Pops the top item off of this stack and return it. + * + * @return the top item on the stack + * @throws EmptyStackException if the stack is empty + */ + public Object pop() throws EmptyStackException { + int n = size(); + if (n <= 0) { + throw new EmptyStackException(); + } else { + return remove(n - 1); + } + } + + /** + * Pushes a new item onto the top of this stack. The pushed item is also + * returned. This is equivalent to calling add. + * + * @param item the item to be added + * @return the item just pushed + */ + public Object push(Object item) { + add(item); + return item; + } + + + /** + * Returns the one-based position of the distance from the top that the + * specified object exists on this stack, where the top-most element is + * considered to be at distance 1. If the object is not + * present on the stack, return -1 instead. The + * equals() method is used to compare to the items + * in this stack. + * + * @param object the object to be searched for + * @return the 1-based depth into the stack of the object, or -1 if not found + */ + public int search(Object object) { + int i = size() - 1; // Current index + int n = 1; // Current distance + while (i >= 0) { + Object current = get(i); + if ((object == null && current == null) || + (object != null && object.equals(current))) { + return n; + } + i--; + n++; + } + return -1; + } + + +} diff --git a/java/org/apache/tomcat/util/digester/CallMethodRule.java b/java/org/apache/tomcat/util/digester/CallMethodRule.java index 2bb059090..08cdd5957 100644 --- a/java/org/apache/tomcat/util/digester/CallMethodRule.java +++ b/java/org/apache/tomcat/util/digester/CallMethodRule.java @@ -1,629 +1,629 @@ -/* $Id: CallMethodRule.java 299765 2004-08-31 23:52:52Z yoavs $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.apache.tomcat.util.IntrospectionUtils; -import org.xml.sax.Attributes; - - -/** - *

        Rule implementation that calls a method on an object on the stack - * (normally the top/parent object), passing arguments collected from - * subsequent CallParamRule rules or from the body of this - * element.

        - * - *

        By using {@link #CallMethodRule(String methodName)} - * a method call can be made to a method which accepts no - * arguments.

        - * - *

        Incompatible method parameter types are converted - * using org.apache.commons.beanutils.ConvertUtils. - *

        - * - *

        This rule now uses - * - * org.apache.commons.beanutils.MethodUtils#invokeMethod - * by default. - * This increases the kinds of methods successfully and allows primitives - * to be matched by passing in wrapper classes. - * There are rare cases when org.apache.commons.beanutils.MethodUtils#invokeExactMethod - * (the old default) is required. - * This method is much stricter in its reflection. - * Setting the UseExactMatch to true reverts to the use of this - * method.

        - * - *

        Note that the target method is invoked when the end of - * the tag the CallMethodRule fired on is encountered, not when the - * last parameter becomes available. This implies that rules which fire on - * tags nested within the one associated with the CallMethodRule will - * fire before the CallMethodRule invokes the target method. This behaviour is - * not configurable.

        - * - *

        Note also that if a CallMethodRule is expecting exactly one parameter - * and that parameter is not available (eg CallParamRule is used with an - * attribute name but the attribute does not exist) then the method will - * not be invoked. If a CallMethodRule is expecting more than one parameter, - * then it is always invoked, regardless of whether the parameters were - * available or not (missing parameters are passed as null values).

        - */ - -public class CallMethodRule extends Rule { - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "call method" rule with the specified method name. The - * parameter types (if any) default to java.lang.String. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of this element. - * - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #CallMethodRule(String methodName,int paramCount)} instead. - */ - public CallMethodRule(Digester digester, String methodName, - int paramCount) { - - this(methodName, paramCount); - - } - - - /** - * Construct a "call method" rule with the specified method name. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java class names of the arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #CallMethodRule(String methodName,int paramCount, String [] paramTypes)} instead. - */ - public CallMethodRule(Digester digester, String methodName, - int paramCount, String paramTypes[]) { - - this(methodName, paramCount, paramTypes); - - } - - - /** - * Construct a "call method" rule with the specified method name. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java classes that represent the - * parameter types of the method arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean.TYPE - * for a boolean parameter) - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #CallMethodRule(String methodName,int paramCount, Class [] paramTypes)} instead. - */ - public CallMethodRule(Digester digester, String methodName, - int paramCount, Class paramTypes[]) { - - this(methodName, paramCount, paramTypes); - } - - - /** - * Construct a "call method" rule with the specified method name. The - * parameter types (if any) default to java.lang.String. - * - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of this element. - */ - public CallMethodRule(String methodName, - int paramCount) { - this(0, methodName, paramCount); - } - - /** - * Construct a "call method" rule with the specified method name. The - * parameter types (if any) default to java.lang.String. - * - * @param targetOffset location of the target object. Positive numbers are - * relative to the top of the digester object stack. Negative numbers - * are relative to the bottom of the stack. Zero implies the top - * object on the stack. - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of this element. - */ - public CallMethodRule(int targetOffset, - String methodName, - int paramCount) { - - this.targetOffset = targetOffset; - this.methodName = methodName; - this.paramCount = paramCount; - if (paramCount == 0) { - this.paramTypes = new Class[] { String.class }; - } else { - this.paramTypes = new Class[paramCount]; - for (int i = 0; i < this.paramTypes.length; i++) { - this.paramTypes[i] = String.class; - } - } - - } - - /** - * Construct a "call method" rule with the specified method name. - * The method should accept no parameters. - * - * @param methodName Method name of the parent method to call - */ - public CallMethodRule(String methodName) { - - this(0, methodName, 0, (Class[]) null); - - } - - - /** - * Construct a "call method" rule with the specified method name. - * The method should accept no parameters. - * - * @param targetOffset location of the target object. Positive numbers are - * relative to the top of the digester object stack. Negative numbers - * are relative to the bottom of the stack. Zero implies the top - * object on the stack. - * @param methodName Method name of the parent method to call - */ - public CallMethodRule(int targetOffset, String methodName) { - - this(targetOffset, methodName, 0, (Class[]) null); - - } - - - /** - * Construct a "call method" rule with the specified method name and - * parameter types. If paramCount is set to zero the rule - * will use the body of this element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java class names of the arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public CallMethodRule( - String methodName, - int paramCount, - String paramTypes[]) { - this(0, methodName, paramCount, paramTypes); - } - - /** - * Construct a "call method" rule with the specified method name and - * parameter types. If paramCount is set to zero the rule - * will use the body of this element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param targetOffset location of the target object. Positive numbers are - * relative to the top of the digester object stack. Negative numbers - * are relative to the bottom of the stack. Zero implies the top - * object on the stack. - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java class names of the arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public CallMethodRule( int targetOffset, - String methodName, - int paramCount, - String paramTypes[]) { - - this.targetOffset = targetOffset; - this.methodName = methodName; - this.paramCount = paramCount; - if (paramTypes == null) { - this.paramTypes = new Class[paramCount]; - for (int i = 0; i < this.paramTypes.length; i++) { - this.paramTypes[i] = "abc".getClass(); - } - } else { - // copy the parameter class names into an array - // the classes will be loaded when the digester is set - this.paramClassNames = new String[paramTypes.length]; - for (int i = 0; i < this.paramClassNames.length; i++) { - this.paramClassNames[i] = paramTypes[i]; - } - } - - } - - - /** - * Construct a "call method" rule with the specified method name and - * parameter types. If paramCount is set to zero the rule - * will use the body of this element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java classes that represent the - * parameter types of the method arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean.TYPE - * for a boolean parameter) - */ - public CallMethodRule( - String methodName, - int paramCount, - Class paramTypes[]) { - this(0, methodName, paramCount, paramTypes); - } - - /** - * Construct a "call method" rule with the specified method name and - * parameter types. If paramCount is set to zero the rule - * will use the body of this element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param targetOffset location of the target object. Positive numbers are - * relative to the top of the digester object stack. Negative numbers - * are relative to the bottom of the stack. Zero implies the top - * object on the stack. - * @param methodName Method name of the parent method to call - * @param paramCount The number of parameters to collect, or - * zero for a single argument from the body of ths element - * @param paramTypes The Java classes that represent the - * parameter types of the method arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean.TYPE - * for a boolean parameter) - */ - public CallMethodRule( int targetOffset, - String methodName, - int paramCount, - Class paramTypes[]) { - - this.targetOffset = targetOffset; - this.methodName = methodName; - this.paramCount = paramCount; - if (paramTypes == null) { - this.paramTypes = new Class[paramCount]; - for (int i = 0; i < this.paramTypes.length; i++) { - this.paramTypes[i] = "abc".getClass(); - } - } else { - this.paramTypes = new Class[paramTypes.length]; - for (int i = 0; i < this.paramTypes.length; i++) { - this.paramTypes[i] = paramTypes[i]; - } - } - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The body text collected from this element. - */ - protected String bodyText = null; - - - /** - * location of the target object for the call, relative to the - * top of the digester object stack. The default value of zero - * means the target object is the one on top of the stack. - */ - protected int targetOffset = 0; - - /** - * The method name to call on the parent object. - */ - protected String methodName = null; - - - /** - * The number of parameters to collect from MethodParam rules. - * If this value is zero, a single parameter will be collected from the - * body of this element. - */ - protected int paramCount = 0; - - - /** - * The parameter types of the parameters to be collected. - */ - protected Class paramTypes[] = null; - - /** - * The names of the classes of the parameters to be collected. - * This attribute allows creation of the classes to be postponed until the digester is set. - */ - protected String paramClassNames[] = null; - - /** - * Should MethodUtils.invokeExactMethod be used for reflection. - */ - protected boolean useExactMatch = false; - - // --------------------------------------------------------- Public Methods - - /** - * Should MethodUtils.invokeExactMethod - * be used for the reflection. - */ - public boolean getUseExactMatch() { - return useExactMatch; - } - - /** - * Set whether MethodUtils.invokeExactMethod - * should be used for the reflection. - */ - public void setUseExactMatch(boolean useExactMatch) - { - this.useExactMatch = useExactMatch; - } - - /** - * Set the associated digester. - * If needed, this class loads the parameter classes from their names. - */ - public void setDigester(Digester digester) - { - // call superclass - super.setDigester(digester); - // if necessary, load parameter classes - if (this.paramClassNames != null) { - this.paramTypes = new Class[paramClassNames.length]; - for (int i = 0; i < this.paramClassNames.length; i++) { - try { - this.paramTypes[i] = - digester.getClassLoader().loadClass(this.paramClassNames[i]); - } catch (ClassNotFoundException e) { - // use the digester log - digester.getLogger().error("(CallMethodRule) Cannot load class " + this.paramClassNames[i], e); - this.paramTypes[i] = null; // Will cause NPE later - } - } - } - } - - /** - * Process the start of this element. - * - * @param attributes The attribute list for this element - */ - public void begin(Attributes attributes) throws Exception { - - // Push an array to capture the parameter values if necessary - if (paramCount > 0) { - Object parameters[] = new Object[paramCount]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = null; - } - digester.pushParams(parameters); - } - - } - - - /** - * Process the body text of this element. - * - * @param bodyText The body text of this element - */ - public void body(String bodyText) throws Exception { - - if (paramCount == 0) { - this.bodyText = bodyText.trim(); - } - - } - - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - // Retrieve or construct the parameter values array - Object parameters[] = null; - if (paramCount > 0) { - - parameters = (Object[]) digester.popParams(); - - if (digester.log.isTraceEnabled()) { - for (int i=0,size=parameters.length;i= 0) { - target = digester.peek(targetOffset); - } else { - target = digester.peek( digester.getCount() + targetOffset ); - } - - if (target == null) { - StringBuffer sb = new StringBuffer(); - sb.append("[CallMethodRule]{"); - sb.append(digester.match); - sb.append("} Call target is null ("); - sb.append("targetOffset="); - sb.append(targetOffset); - sb.append(",stackdepth="); - sb.append(digester.getCount()); - sb.append(")"); - throw new org.xml.sax.SAXException(sb.toString()); - } - - // Invoke the required method on the top object - if (digester.log.isDebugEnabled()) { - StringBuffer sb = new StringBuffer("[CallMethodRule]{"); - sb.append(digester.match); - sb.append("} Call "); - sb.append(target.getClass().getName()); - sb.append("."); - sb.append(methodName); - sb.append("("); - for (int i = 0; i < paramValues.length; i++) { - if (i > 0) { - sb.append(","); - } - if (paramValues[i] == null) { - sb.append("null"); - } else { - sb.append(paramValues[i].toString()); - } - sb.append("/"); - if (paramTypes[i] == null) { - sb.append("null"); - } else { - sb.append(paramTypes[i].getName()); - } - } - sb.append(")"); - digester.log.debug(sb.toString()); - } - Object result = IntrospectionUtils.callMethodN(target, methodName, - paramValues, paramTypes); - processMethodCallResult(result); - } - - - /** - * Clean up after parsing is complete. - */ - public void finish() throws Exception { - - bodyText = null; - - } - - /** - * Subclasses may override this method to perform additional processing of the - * invoked method's result. - * - * @param result the Object returned by the method invoked, possibly null - */ - protected void processMethodCallResult(Object result) { - // do nothing - } - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("CallMethodRule["); - sb.append("methodName="); - sb.append(methodName); - sb.append(", paramCount="); - sb.append(paramCount); - sb.append(", paramTypes={"); - if (paramTypes != null) { - for (int i = 0; i < paramTypes.length; i++) { - if (i > 0) { - sb.append(", "); - } - sb.append(paramTypes[i].getName()); - } - } - sb.append("}"); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: CallMethodRule.java 299765 2004-08-31 23:52:52Z yoavs $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.apache.tomcat.util.IntrospectionUtils; +import org.xml.sax.Attributes; + + +/** + *

        Rule implementation that calls a method on an object on the stack + * (normally the top/parent object), passing arguments collected from + * subsequent CallParamRule rules or from the body of this + * element.

        + * + *

        By using {@link #CallMethodRule(String methodName)} + * a method call can be made to a method which accepts no + * arguments.

        + * + *

        Incompatible method parameter types are converted + * using org.apache.commons.beanutils.ConvertUtils. + *

        + * + *

        This rule now uses + * + * org.apache.commons.beanutils.MethodUtils#invokeMethod + * by default. + * This increases the kinds of methods successfully and allows primitives + * to be matched by passing in wrapper classes. + * There are rare cases when org.apache.commons.beanutils.MethodUtils#invokeExactMethod + * (the old default) is required. + * This method is much stricter in its reflection. + * Setting the UseExactMatch to true reverts to the use of this + * method.

        + * + *

        Note that the target method is invoked when the end of + * the tag the CallMethodRule fired on is encountered, not when the + * last parameter becomes available. This implies that rules which fire on + * tags nested within the one associated with the CallMethodRule will + * fire before the CallMethodRule invokes the target method. This behaviour is + * not configurable.

        + * + *

        Note also that if a CallMethodRule is expecting exactly one parameter + * and that parameter is not available (eg CallParamRule is used with an + * attribute name but the attribute does not exist) then the method will + * not be invoked. If a CallMethodRule is expecting more than one parameter, + * then it is always invoked, regardless of whether the parameters were + * available or not (missing parameters are passed as null values).

        + */ + +public class CallMethodRule extends Rule { + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + * + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount)} instead. + */ + public CallMethodRule(Digester digester, String methodName, + int paramCount) { + + this(methodName, paramCount); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount, String [] paramTypes)} instead. + */ + public CallMethodRule(Digester digester, String methodName, + int paramCount, String paramTypes[]) { + + this(methodName, paramCount, paramTypes); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallMethodRule(String methodName,int paramCount, Class [] paramTypes)} instead. + */ + public CallMethodRule(Digester digester, String methodName, + int paramCount, Class paramTypes[]) { + + this(methodName, paramCount, paramTypes); + } + + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + */ + public CallMethodRule(String methodName, + int paramCount) { + this(0, methodName, paramCount); + } + + /** + * Construct a "call method" rule with the specified method name. The + * parameter types (if any) default to java.lang.String. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of this element. + */ + public CallMethodRule(int targetOffset, + String methodName, + int paramCount) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramCount == 0) { + this.paramTypes = new Class[] { String.class }; + } else { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = String.class; + } + } + + } + + /** + * Construct a "call method" rule with the specified method name. + * The method should accept no parameters. + * + * @param methodName Method name of the parent method to call + */ + public CallMethodRule(String methodName) { + + this(0, methodName, 0, (Class[]) null); + + } + + + /** + * Construct a "call method" rule with the specified method name. + * The method should accept no parameters. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + */ + public CallMethodRule(int targetOffset, String methodName) { + + this(targetOffset, methodName, 0, (Class[]) null); + + } + + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public CallMethodRule( + String methodName, + int paramCount, + String paramTypes[]) { + this(0, methodName, paramCount, paramTypes); + } + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public CallMethodRule( int targetOffset, + String methodName, + int paramCount, + String paramTypes[]) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramTypes == null) { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = "abc".getClass(); + } + } else { + // copy the parameter class names into an array + // the classes will be loaded when the digester is set + this.paramClassNames = new String[paramTypes.length]; + for (int i = 0; i < this.paramClassNames.length; i++) { + this.paramClassNames[i] = paramTypes[i]; + } + } + + } + + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + */ + public CallMethodRule( + String methodName, + int paramCount, + Class paramTypes[]) { + this(0, methodName, paramCount, paramTypes); + } + + /** + * Construct a "call method" rule with the specified method name and + * parameter types. If paramCount is set to zero the rule + * will use the body of this element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param targetOffset location of the target object. Positive numbers are + * relative to the top of the digester object stack. Negative numbers + * are relative to the bottom of the stack. Zero implies the top + * object on the stack. + * @param methodName Method name of the parent method to call + * @param paramCount The number of parameters to collect, or + * zero for a single argument from the body of ths element + * @param paramTypes The Java classes that represent the + * parameter types of the method arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean.TYPE + * for a boolean parameter) + */ + public CallMethodRule( int targetOffset, + String methodName, + int paramCount, + Class paramTypes[]) { + + this.targetOffset = targetOffset; + this.methodName = methodName; + this.paramCount = paramCount; + if (paramTypes == null) { + this.paramTypes = new Class[paramCount]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = "abc".getClass(); + } + } else { + this.paramTypes = new Class[paramTypes.length]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypes[i] = paramTypes[i]; + } + } + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The body text collected from this element. + */ + protected String bodyText = null; + + + /** + * location of the target object for the call, relative to the + * top of the digester object stack. The default value of zero + * means the target object is the one on top of the stack. + */ + protected int targetOffset = 0; + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The number of parameters to collect from MethodParam rules. + * If this value is zero, a single parameter will be collected from the + * body of this element. + */ + protected int paramCount = 0; + + + /** + * The parameter types of the parameters to be collected. + */ + protected Class paramTypes[] = null; + + /** + * The names of the classes of the parameters to be collected. + * This attribute allows creation of the classes to be postponed until the digester is set. + */ + protected String paramClassNames[] = null; + + /** + * Should MethodUtils.invokeExactMethod be used for reflection. + */ + protected boolean useExactMatch = false; + + // --------------------------------------------------------- Public Methods + + /** + * Should MethodUtils.invokeExactMethod + * be used for the reflection. + */ + public boolean getUseExactMatch() { + return useExactMatch; + } + + /** + * Set whether MethodUtils.invokeExactMethod + * should be used for the reflection. + */ + public void setUseExactMatch(boolean useExactMatch) + { + this.useExactMatch = useExactMatch; + } + + /** + * Set the associated digester. + * If needed, this class loads the parameter classes from their names. + */ + public void setDigester(Digester digester) + { + // call superclass + super.setDigester(digester); + // if necessary, load parameter classes + if (this.paramClassNames != null) { + this.paramTypes = new Class[paramClassNames.length]; + for (int i = 0; i < this.paramClassNames.length; i++) { + try { + this.paramTypes[i] = + digester.getClassLoader().loadClass(this.paramClassNames[i]); + } catch (ClassNotFoundException e) { + // use the digester log + digester.getLogger().error("(CallMethodRule) Cannot load class " + this.paramClassNames[i], e); + this.paramTypes[i] = null; // Will cause NPE later + } + } + } + } + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + public void begin(Attributes attributes) throws Exception { + + // Push an array to capture the parameter values if necessary + if (paramCount > 0) { + Object parameters[] = new Object[paramCount]; + for (int i = 0; i < parameters.length; i++) { + parameters[i] = null; + } + digester.pushParams(parameters); + } + + } + + + /** + * Process the body text of this element. + * + * @param bodyText The body text of this element + */ + public void body(String bodyText) throws Exception { + + if (paramCount == 0) { + this.bodyText = bodyText.trim(); + } + + } + + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + // Retrieve or construct the parameter values array + Object parameters[] = null; + if (paramCount > 0) { + + parameters = (Object[]) digester.popParams(); + + if (digester.log.isTraceEnabled()) { + for (int i=0,size=parameters.length;i= 0) { + target = digester.peek(targetOffset); + } else { + target = digester.peek( digester.getCount() + targetOffset ); + } + + if (target == null) { + StringBuffer sb = new StringBuffer(); + sb.append("[CallMethodRule]{"); + sb.append(digester.match); + sb.append("} Call target is null ("); + sb.append("targetOffset="); + sb.append(targetOffset); + sb.append(",stackdepth="); + sb.append(digester.getCount()); + sb.append(")"); + throw new org.xml.sax.SAXException(sb.toString()); + } + + // Invoke the required method on the top object + if (digester.log.isDebugEnabled()) { + StringBuffer sb = new StringBuffer("[CallMethodRule]{"); + sb.append(digester.match); + sb.append("} Call "); + sb.append(target.getClass().getName()); + sb.append("."); + sb.append(methodName); + sb.append("("); + for (int i = 0; i < paramValues.length; i++) { + if (i > 0) { + sb.append(","); + } + if (paramValues[i] == null) { + sb.append("null"); + } else { + sb.append(paramValues[i].toString()); + } + sb.append("/"); + if (paramTypes[i] == null) { + sb.append("null"); + } else { + sb.append(paramTypes[i].getName()); + } + } + sb.append(")"); + digester.log.debug(sb.toString()); + } + Object result = IntrospectionUtils.callMethodN(target, methodName, + paramValues, paramTypes); + processMethodCallResult(result); + } + + + /** + * Clean up after parsing is complete. + */ + public void finish() throws Exception { + + bodyText = null; + + } + + /** + * Subclasses may override this method to perform additional processing of the + * invoked method's result. + * + * @param result the Object returned by the method invoked, possibly null + */ + protected void processMethodCallResult(Object result) { + // do nothing + } + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("CallMethodRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramCount="); + sb.append(paramCount); + sb.append(", paramTypes={"); + if (paramTypes != null) { + for (int i = 0; i < paramTypes.length; i++) { + if (i > 0) { + sb.append(", "); + } + sb.append(paramTypes[i].getName()); + } + } + sb.append("}"); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/CallParamRule.java b/java/org/apache/tomcat/util/digester/CallParamRule.java index e674bc5eb..37ce5b4b8 100644 --- a/java/org/apache/tomcat/util/digester/CallParamRule.java +++ b/java/org/apache/tomcat/util/digester/CallParamRule.java @@ -1,262 +1,262 @@ -/* $Id: CallParamRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - - -/** - *

        Rule implementation that saves a parameter for use by a surrounding - * CallMethodRule.

        - * - *

        This parameter may be: - *

          - *
        • from an attribute of the current element - * See {@link #CallParamRule(int paramIndex, String attributeName)} - *
        • from current the element body - * See {@link #CallParamRule(int paramIndex)} - *
        • from the top object on the stack. - * See {@link #CallParamRule(int paramIndex, boolean fromStack)} - *
        • the current path being processed (separate Rule). - * See {@link PathCallParamRule} - *
        - *

        - */ - -public class CallParamRule extends Rule { - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "call parameter" rule that will save the body text of this - * element as the parameter value. - * - * @param digester The associated Digester - * @param paramIndex The zero-relative parameter number - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #CallParamRule(int paramIndex)} instead. - */ - public CallParamRule(Digester digester, int paramIndex) { - - this(paramIndex); - - } - - - /** - * Construct a "call parameter" rule that will save the value of the - * specified attribute as the parameter value. - * - * @param digester The associated Digester - * @param paramIndex The zero-relative parameter number - * @param attributeName The name of the attribute to save - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead. - */ - public CallParamRule(Digester digester, int paramIndex, - String attributeName) { - - this(paramIndex, attributeName); - - } - - /** - * Construct a "call parameter" rule that will save the body text of this - * element as the parameter value. - * - * @param paramIndex The zero-relative parameter number - */ - public CallParamRule(int paramIndex) { - - this(paramIndex, null); - - } - - - /** - * Construct a "call parameter" rule that will save the value of the - * specified attribute as the parameter value. - * - * @param paramIndex The zero-relative parameter number - * @param attributeName The name of the attribute to save - */ - public CallParamRule(int paramIndex, - String attributeName) { - - this.paramIndex = paramIndex; - this.attributeName = attributeName; - - } - - - /** - * Construct a "call parameter" rule. - * - * @param paramIndex The zero-relative parameter number - * @param fromStack should this parameter be taken from the top of the stack? - */ - public CallParamRule(int paramIndex, boolean fromStack) { - - this.paramIndex = paramIndex; - this.fromStack = fromStack; - - } - - /** - * Constructs a "call parameter" rule which sets a parameter from the stack. - * If the stack contains too few objects, then the parameter will be set to null. - * - * @param paramIndex The zero-relative parameter number - * @param stackIndex the index of the object which will be passed as a parameter. - * The zeroth object is the top of the stack, 1 is the next object down and so on. - */ - public CallParamRule(int paramIndex, int stackIndex) { - - this.paramIndex = paramIndex; - this.fromStack = true; - this.stackIndex = stackIndex; - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The attribute from which to save the parameter value - */ - protected String attributeName = null; - - - /** - * The zero-relative index of the parameter we are saving. - */ - protected int paramIndex = 0; - - - /** - * Is the parameter to be set from the stack? - */ - protected boolean fromStack = false; - - /** - * The position of the object from the top of the stack - */ - protected int stackIndex = 0; - - /** - * Stack is used to allow nested body text to be processed. - * Lazy creation. - */ - protected ArrayStack bodyTextStack; - - // --------------------------------------------------------- Public Methods - - - /** - * Process the start of this element. - * - * @param attributes The attribute list for this element - */ - public void begin(Attributes attributes) throws Exception { - - Object param = null; - - if (attributeName != null) { - - param = attributes.getValue(attributeName); - - } else if(fromStack) { - - param = digester.peek(stackIndex); - - if (digester.log.isDebugEnabled()) { - - StringBuffer sb = new StringBuffer("[CallParamRule]{"); - sb.append(digester.match); - sb.append("} Save from stack; from stack?").append(fromStack); - sb.append("; object=").append(param); - digester.log.debug(sb.toString()); - } - } - - // Have to save the param object to the param stack frame here. - // Can't wait until end(). Otherwise, the object will be lost. - // We can't save the object as instance variables, as - // the instance variables will be overwritten - // if this CallParamRule is reused in subsequent nesting. - - if(param != null) { - Object parameters[] = (Object[]) digester.peekParams(); - parameters[paramIndex] = param; - } - } - - - /** - * Process the body text of this element. - * - * @param bodyText The body text of this element - */ - public void body(String bodyText) throws Exception { - - if (attributeName == null && !fromStack) { - // We must wait to set the parameter until end - // so that we can make sure that the right set of parameters - // is at the top of the stack - if (bodyTextStack == null) { - bodyTextStack = new ArrayStack(); - } - bodyTextStack.push(bodyText.trim()); - } - - } - - /** - * Process any body texts now. - */ - public void end(String namespace, String name) { - if (bodyTextStack != null && !bodyTextStack.empty()) { - // what we do now is push one parameter onto the top set of parameters - Object parameters[] = (Object[]) digester.peekParams(); - parameters[paramIndex] = bodyTextStack.pop(); - } - } - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("CallParamRule["); - sb.append("paramIndex="); - sb.append(paramIndex); - sb.append(", attributeName="); - sb.append(attributeName); - sb.append(", from stack="); - sb.append(fromStack); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: CallParamRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + + +/** + *

        Rule implementation that saves a parameter for use by a surrounding + * CallMethodRule.

        + * + *

        This parameter may be: + *

          + *
        • from an attribute of the current element + * See {@link #CallParamRule(int paramIndex, String attributeName)} + *
        • from current the element body + * See {@link #CallParamRule(int paramIndex)} + *
        • from the top object on the stack. + * See {@link #CallParamRule(int paramIndex, boolean fromStack)} + *
        • the current path being processed (separate Rule). + * See {@link PathCallParamRule} + *
        + *

        + */ + +public class CallParamRule extends Rule { + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + * @param digester The associated Digester + * @param paramIndex The zero-relative parameter number + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallParamRule(int paramIndex)} instead. + */ + public CallParamRule(Digester digester, int paramIndex) { + + this(paramIndex); + + } + + + /** + * Construct a "call parameter" rule that will save the value of the + * specified attribute as the parameter value. + * + * @param digester The associated Digester + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to save + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #CallParamRule(int paramIndex, String attributeName)} instead. + */ + public CallParamRule(Digester digester, int paramIndex, + String attributeName) { + + this(paramIndex, attributeName); + + } + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + * @param paramIndex The zero-relative parameter number + */ + public CallParamRule(int paramIndex) { + + this(paramIndex, null); + + } + + + /** + * Construct a "call parameter" rule that will save the value of the + * specified attribute as the parameter value. + * + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to save + */ + public CallParamRule(int paramIndex, + String attributeName) { + + this.paramIndex = paramIndex; + this.attributeName = attributeName; + + } + + + /** + * Construct a "call parameter" rule. + * + * @param paramIndex The zero-relative parameter number + * @param fromStack should this parameter be taken from the top of the stack? + */ + public CallParamRule(int paramIndex, boolean fromStack) { + + this.paramIndex = paramIndex; + this.fromStack = fromStack; + + } + + /** + * Constructs a "call parameter" rule which sets a parameter from the stack. + * If the stack contains too few objects, then the parameter will be set to null. + * + * @param paramIndex The zero-relative parameter number + * @param stackIndex the index of the object which will be passed as a parameter. + * The zeroth object is the top of the stack, 1 is the next object down and so on. + */ + public CallParamRule(int paramIndex, int stackIndex) { + + this.paramIndex = paramIndex; + this.fromStack = true; + this.stackIndex = stackIndex; + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute from which to save the parameter value + */ + protected String attributeName = null; + + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + + /** + * Is the parameter to be set from the stack? + */ + protected boolean fromStack = false; + + /** + * The position of the object from the top of the stack + */ + protected int stackIndex = 0; + + /** + * Stack is used to allow nested body text to be processed. + * Lazy creation. + */ + protected ArrayStack bodyTextStack; + + // --------------------------------------------------------- Public Methods + + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + public void begin(Attributes attributes) throws Exception { + + Object param = null; + + if (attributeName != null) { + + param = attributes.getValue(attributeName); + + } else if(fromStack) { + + param = digester.peek(stackIndex); + + if (digester.log.isDebugEnabled()) { + + StringBuffer sb = new StringBuffer("[CallParamRule]{"); + sb.append(digester.match); + sb.append("} Save from stack; from stack?").append(fromStack); + sb.append("; object=").append(param); + digester.log.debug(sb.toString()); + } + } + + // Have to save the param object to the param stack frame here. + // Can't wait until end(). Otherwise, the object will be lost. + // We can't save the object as instance variables, as + // the instance variables will be overwritten + // if this CallParamRule is reused in subsequent nesting. + + if(param != null) { + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = param; + } + } + + + /** + * Process the body text of this element. + * + * @param bodyText The body text of this element + */ + public void body(String bodyText) throws Exception { + + if (attributeName == null && !fromStack) { + // We must wait to set the parameter until end + // so that we can make sure that the right set of parameters + // is at the top of the stack + if (bodyTextStack == null) { + bodyTextStack = new ArrayStack(); + } + bodyTextStack.push(bodyText.trim()); + } + + } + + /** + * Process any body texts now. + */ + public void end(String namespace, String name) { + if (bodyTextStack != null && !bodyTextStack.empty()) { + // what we do now is push one parameter onto the top set of parameters + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = bodyTextStack.pop(); + } + } + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("CallParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append(", from stack="); + sb.append(fromStack); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/Digester.java b/java/org/apache/tomcat/util/digester/Digester.java index 5144e4e50..2b857a787 100644 --- a/java/org/apache/tomcat/util/digester/Digester.java +++ b/java/org/apache/tomcat/util/digester/Digester.java @@ -1,2824 +1,2824 @@ -/* $Id: Digester.java 380645 2006-02-24 11:37:46Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.digester; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.lang.reflect.InvocationTargetException; -import java.util.EmptyStackException; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.IntrospectionUtils; -import org.xml.sax.Attributes; -import org.xml.sax.EntityResolver; -import org.xml.sax.ErrorHandler; -import org.xml.sax.InputSource; -import org.xml.sax.Locator; -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotRecognizedException; -import org.xml.sax.SAXNotSupportedException; -import org.xml.sax.SAXParseException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.AttributesImpl; -import org.xml.sax.helpers.DefaultHandler; - - - - -/** - *

        A Digester processes an XML input stream by matching a - * series of element nesting patterns to execute Rules that have been added - * prior to the start of parsing. This package was inspired by the - * XmlMapper class that was part of Tomcat 3.0 and 3.1, - * but is organized somewhat differently.

        - * - *

        See the Digester - * Developer Guide for more information.

        - * - *

        IMPLEMENTATION NOTE - A single Digester instance may - * only be used within the context of a single thread at a time, and a call - * to parse() must be completed before another can be initiated - * even from the same thread.

        - * - *

        IMPLEMENTATION NOTE - A bug in Xerces 2.0.2 prevents - * the support of XML schema. You need Xerces 2.1/2.3 and up to make - * this class working with XML schema

        - */ - -public class Digester extends DefaultHandler { - - - // ---------------------------------------------------------- Static Fields - - - private static class SystemPropertySource - implements IntrospectionUtils.PropertySource { - public String getProperty( String key ) { - return System.getProperty(key); - } - } - - protected static IntrospectionUtils.PropertySource source[] = - new IntrospectionUtils.PropertySource[] { new SystemPropertySource() }; - - - // --------------------------------------------------------- Constructors - - - /** - * Construct a new Digester with default properties. - */ - public Digester() { - - super(); - - } - - - /** - * Construct a new Digester, allowing a SAXParser to be passed in. This - * allows Digester to be used in environments which are unfriendly to - * JAXP1.1 (such as WebLogic 6.0). Thanks for the request to change go to - * James House (james@interobjective.com). This may help in places where - * you are able to load JAXP 1.1 classes yourself. - */ - public Digester(SAXParser parser) { - - super(); - - this.parser = parser; - - } - - - /** - * Construct a new Digester, allowing an XMLReader to be passed in. This - * allows Digester to be used in environments which are unfriendly to - * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you - * have to configure namespace and validation support yourself, as these - * properties only affect the SAXParser and emtpy constructor. - */ - public Digester(XMLReader reader) { - - super(); - - this.reader = reader; - - } - - - // --------------------------------------------------- Instance Variables - - - /** - * The body text of the current element. - */ - protected StringBuffer bodyText = new StringBuffer(); - - - /** - * The stack of body text string buffers for surrounding elements. - */ - protected ArrayStack bodyTexts = new ArrayStack(); - - - /** - * Stack whose elements are List objects, each containing a list of - * Rule objects as returned from Rules.getMatch(). As each xml element - * in the input is entered, the matching rules are pushed onto this - * stack. After the end tag is reached, the matches are popped again. - * The depth of is stack is therefore exactly the same as the current - * "nesting" level of the input xml. - * - * @since 1.6 - */ - protected ArrayStack matches = new ArrayStack(10); - - /** - * The class loader to use for instantiating application objects. - * If not specified, the context class loader, or the class loader - * used to load Digester itself, is used, based on the value of the - * useContextClassLoader variable. - */ - protected ClassLoader classLoader = null; - - - /** - * Has this Digester been configured yet. - */ - protected boolean configured = false; - - - /** - * The EntityResolver used by the SAX parser. By default it use this class - */ - protected EntityResolver entityResolver; - - /** - * The URLs of entityValidator that have been registered, keyed by the public - * identifier that corresponds. - */ - protected HashMap entityValidator = new HashMap(); - - - /** - * The application-supplied error handler that is notified when parsing - * warnings, errors, or fatal errors occur. - */ - protected ErrorHandler errorHandler = null; - - - /** - * The SAXParserFactory that is created the first time we need it. - */ - protected SAXParserFactory factory = null; - - /** - * @deprecated This is now managed by {@link ParserFeatureSetterFactory} - */ - protected String JAXP_SCHEMA_LANGUAGE = - "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; - - - /** - * The Locator associated with our parser. - */ - protected Locator locator = null; - - - /** - * The current match pattern for nested element processing. - */ - protected String match = ""; - - - /** - * Do we want a "namespace aware" parser. - */ - protected boolean namespaceAware = false; - - - /** - * Registered namespaces we are currently processing. The key is the - * namespace prefix that was declared in the document. The value is an - * ArrayStack of the namespace URIs this prefix has been mapped to -- - * the top Stack element is the most current one. (This architecture - * is required because documents can declare nested uses of the same - * prefix for different Namespace URIs). - */ - protected HashMap namespaces = new HashMap(); - - - /** - * The parameters stack being utilized by CallMethodRule and - * CallParamRule rules. - */ - protected ArrayStack params = new ArrayStack(); - - - /** - * The SAXParser we will use to parse the input stream. - */ - protected SAXParser parser = null; - - - /** - * The public identifier of the DTD we are currently parsing under - * (if any). - */ - protected String publicId = null; - - - /** - * The XMLReader used to parse digester rules. - */ - protected XMLReader reader = null; - - - /** - * The "root" element of the stack (in other words, the last object - * that was popped. - */ - protected Object root = null; - - - /** - * The Rules implementation containing our collection of - * Rule instances and associated matching policy. If not - * established before the first rule is added, a default implementation - * will be provided. - */ - protected Rules rules = null; - - /** - * The XML schema language to use for validating an XML instance. By - * default this value is set to W3C_XML_SCHEMA - */ - protected String schemaLanguage = W3C_XML_SCHEMA; - - - /** - * The XML schema to use for validating an XML instance. - */ - protected String schemaLocation = null; - - - /** - * The object stack being constructed. - */ - protected ArrayStack stack = new ArrayStack(); - - - /** - * Do we want to use the Context ClassLoader when loading classes - * for instantiating new objects. Default is false. - */ - protected boolean useContextClassLoader = false; - - - /** - * Do we want to use a validating parser. - */ - protected boolean validating = false; - - - /** - * The Log to which most logging calls will be made. - */ - protected Log log = - LogFactory.getLog("org.apache.commons.digester.Digester"); - - - /** - * The Log to which all SAX event related logging calls will be made. - */ - protected Log saxLog = - LogFactory.getLog("org.apache.commons.digester.Digester.sax"); - - - /** - * The schema language supported. By default, we use this one. - */ - protected static final String W3C_XML_SCHEMA = - "http://www.w3.org/2001/XMLSchema"; - - /** Stacks used for interrule communication, indexed by name String */ - private HashMap stacksByName = new HashMap(); - - // ------------------------------------------------------------- Properties - - /** - * Return the currently mapped namespace URI for the specified prefix, - * if any; otherwise return null. These mappings come and - * go dynamically as the document is parsed. - * - * @param prefix Prefix to look up - */ - public String findNamespaceURI(String prefix) { - - ArrayStack stack = (ArrayStack) namespaces.get(prefix); - if (stack == null) { - return (null); - } - try { - return ((String) stack.peek()); - } catch (EmptyStackException e) { - return (null); - } - - } - - - /** - * Return the class loader to be used for instantiating application objects - * when required. This is determined based upon the following rules: - *
          - *
        • The class loader set by setClassLoader(), if any
        • - *
        • The thread context class loader, if it exists and the - * useContextClassLoader property is set to true
        • - *
        • The class loader used to load the Digester class itself. - *
        - */ - public ClassLoader getClassLoader() { - - if (this.classLoader != null) { - return (this.classLoader); - } - if (this.useContextClassLoader) { - ClassLoader classLoader = - Thread.currentThread().getContextClassLoader(); - if (classLoader != null) { - return (classLoader); - } - } - return (this.getClass().getClassLoader()); - - } - - - /** - * Set the class loader to be used for instantiating application objects - * when required. - * - * @param classLoader The new class loader to use, or null - * to revert to the standard rules - */ - public void setClassLoader(ClassLoader classLoader) { - - this.classLoader = classLoader; - - } - - - /** - * Return the current depth of the element stack. - */ - public int getCount() { - - return (stack.size()); - - } - - - /** - * Return the name of the XML element that is currently being processed. - */ - public String getCurrentElementName() { - - String elementName = match; - int lastSlash = elementName.lastIndexOf('/'); - if (lastSlash >= 0) { - elementName = elementName.substring(lastSlash + 1); - } - return (elementName); - - } - - - /** - * Return the debugging detail level of our currently enabled logger. - * - * @deprecated This method now always returns 0. Digester uses the apache - * jakarta commons-logging library; see the documentation for that library - * for more information. - */ - public int getDebug() { - - return (0); - - } - - - /** - * Set the debugging detail level of our currently enabled logger. - * - * @param debug New debugging detail level (0=off, increasing integers - * for more detail) - * - * @deprecated This method now has no effect at all. Digester uses - * the apache jakarta comons-logging library; see the documentation - * for that library for more information. - */ - public void setDebug(int debug) { - - ; // No action is taken - - } - - - /** - * Return the error handler for this Digester. - */ - public ErrorHandler getErrorHandler() { - - return (this.errorHandler); - - } - - - /** - * Set the error handler for this Digester. - * - * @param errorHandler The new error handler - */ - public void setErrorHandler(ErrorHandler errorHandler) { - - this.errorHandler = errorHandler; - - } - - - /** - * Return the SAXParserFactory we will use, creating one if necessary. - */ - public SAXParserFactory getFactory() { - - if (factory == null) { - factory = SAXParserFactory.newInstance(); - factory.setNamespaceAware(namespaceAware); - factory.setValidating(validating); - } - return (factory); - - } - - - /** - * Returns a flag indicating whether the requested feature is supported - * by the underlying implementation of org.xml.sax.XMLReader. - * See - * for information about the standard SAX2 feature flags. - * - * @param feature Name of the feature to inquire about - * - * @exception ParserConfigurationException if a parser configuration error - * occurs - * @exception SAXNotRecognizedException if the property name is - * not recognized - * @exception SAXNotSupportedException if the property name is - * recognized but not supported - */ - public boolean getFeature(String feature) - throws ParserConfigurationException, SAXNotRecognizedException, - SAXNotSupportedException { - - return (getFactory().getFeature(feature)); - - } - - - /** - * Sets a flag indicating whether the requested feature is supported - * by the underlying implementation of org.xml.sax.XMLReader. - * See - * for information about the standard SAX2 feature flags. In order to be - * effective, this method must be called before the - * getParser() method is called for the first time, either - * directly or indirectly. - * - * @param feature Name of the feature to set the status for - * @param value The new value for this feature - * - * @exception ParserConfigurationException if a parser configuration error - * occurs - * @exception SAXNotRecognizedException if the property name is - * not recognized - * @exception SAXNotSupportedException if the property name is - * recognized but not supported - */ - public void setFeature(String feature, boolean value) - throws ParserConfigurationException, SAXNotRecognizedException, - SAXNotSupportedException { - - getFactory().setFeature(feature, value); - - } - - - /** - * Return the current Logger associated with this instance of the Digester - */ - public Log getLogger() { - - return log; - - } - - - /** - * Set the current logger for this Digester. - */ - public void setLogger(Log log) { - - this.log = log; - - } - - /** - * Gets the logger used for logging SAX-related information. - * Note the output is finely grained. - * - * @since 1.6 - */ - public Log getSAXLogger() { - - return saxLog; - } - - - /** - * Sets the logger used for logging SAX-related information. - * Note the output is finely grained. - * @param saxLog Log, not null - * - * @since 1.6 - */ - public void setSAXLogger(Log saxLog) { - - this.saxLog = saxLog; - } - - /** - * Return the current rule match path - */ - public String getMatch() { - - return match; - - } - - - /** - * Return the "namespace aware" flag for parsers we create. - */ - public boolean getNamespaceAware() { - - return (this.namespaceAware); - - } - - - /** - * Set the "namespace aware" flag for parsers we create. - * - * @param namespaceAware The new "namespace aware" flag - */ - public void setNamespaceAware(boolean namespaceAware) { - - this.namespaceAware = namespaceAware; - - } - - - /** - * Set the publid id of the current file being parse. - * @param publicId the DTD/Schema public's id. - */ - public void setPublicId(String publicId){ - this.publicId = publicId; - } - - - /** - * Return the public identifier of the DTD we are currently - * parsing under, if any. - */ - public String getPublicId() { - - return (this.publicId); - - } - - - /** - * Return the namespace URI that will be applied to all subsequently - * added Rule objects. - */ - public String getRuleNamespaceURI() { - - return (getRules().getNamespaceURI()); - - } - - - /** - * Set the namespace URI that will be applied to all subsequently - * added Rule objects. - * - * @param ruleNamespaceURI Namespace URI that must match on all - * subsequently added rules, or null for matching - * regardless of the current namespace URI - */ - public void setRuleNamespaceURI(String ruleNamespaceURI) { - - getRules().setNamespaceURI(ruleNamespaceURI); - - } - - - /** - * Return the SAXParser we will use to parse the input stream. If there - * is a problem creating the parser, return null. - */ - public SAXParser getParser() { - - // Return the parser we already created (if any) - if (parser != null) { - return (parser); - } - - // Create a new parser - try { - if (validating) { - Properties properties = new Properties(); - properties.put("SAXParserFactory", getFactory()); - if (schemaLocation != null) { - properties.put("schemaLocation", schemaLocation); - properties.put("schemaLanguage", schemaLanguage); - } - parser = ParserFeatureSetterFactory.newSAXParser(properties); } else { - parser = getFactory().newSAXParser(); - } - } catch (Exception e) { - log.error("Digester.getParser: ", e); - return (null); - } - - return (parser); - - } - - - /** - * Return the current value of the specified property for the underlying - * XMLReader implementation. - * See - * for information about the standard SAX2 properties. - * - * @param property Property name to be retrieved - * - * @exception SAXNotRecognizedException if the property name is - * not recognized - * @exception SAXNotSupportedException if the property name is - * recognized but not supported - */ - public Object getProperty(String property) - throws SAXNotRecognizedException, SAXNotSupportedException { - - return (getParser().getProperty(property)); - - } - - - /** - * Set the current value of the specified property for the underlying - * XMLReader implementation. - * See - * for information about the standard SAX2 properties. - * - * @param property Property name to be set - * @param value Property value to be set - * - * @exception SAXNotRecognizedException if the property name is - * not recognized - * @exception SAXNotSupportedException if the property name is - * recognized but not supported - */ - public void setProperty(String property, Object value) - throws SAXNotRecognizedException, SAXNotSupportedException { - - getParser().setProperty(property, value); - - } - - - /** - * By setting the reader in the constructor, you can bypass JAXP and - * be able to use digester in Weblogic 6.0. - * - * @deprecated Use getXMLReader() instead, which can throw a - * SAXException if the reader cannot be instantiated - */ - public XMLReader getReader() { - - try { - return (getXMLReader()); - } catch (SAXException e) { - log.error("Cannot get XMLReader", e); - return (null); - } - - } - - - /** - * Return the Rules implementation object containing our - * rules collection and associated matching policy. If none has been - * established, a default implementation will be created and returned. - */ - public Rules getRules() { - - if (this.rules == null) { - this.rules = new RulesBase(); - this.rules.setDigester(this); - } - return (this.rules); - - } - - - /** - * Set the Rules implementation object containing our - * rules collection and associated matching policy. - * - * @param rules New Rules implementation - */ - public void setRules(Rules rules) { - - this.rules = rules; - this.rules.setDigester(this); - - } - - - /** - * Return the XML Schema URI used for validating an XML instance. - */ - public String getSchema() { - - return (this.schemaLocation); - - } - - - /** - * Set the XML Schema URI used for validating a XML Instance. - * - * @param schemaLocation a URI to the schema. - */ - public void setSchema(String schemaLocation){ - - this.schemaLocation = schemaLocation; - - } - - - /** - * Return the XML Schema language used when parsing. - */ - public String getSchemaLanguage() { - - return (this.schemaLanguage); - - } - - - /** - * Set the XML Schema language used when parsing. By default, we use W3C. - * - * @param schemaLanguage a URI to the schema language. - */ - public void setSchemaLanguage(String schemaLanguage){ - - this.schemaLanguage = schemaLanguage; - - } - - - /** - * Return the boolean as to whether the context classloader should be used. - */ - public boolean getUseContextClassLoader() { - - return useContextClassLoader; - - } - - - /** - * Determine whether to use the Context ClassLoader (the one found by - * calling Thread.currentThread().getContextClassLoader()) - * to resolve/load classes that are defined in various rules. If not - * using Context ClassLoader, then the class-loading defaults to - * using the calling-class' ClassLoader. - * - * @param use determines whether to use Context ClassLoader. - */ - public void setUseContextClassLoader(boolean use) { - - useContextClassLoader = use; - - } - - - /** - * Return the validating parser flag. - */ - public boolean getValidating() { - - return (this.validating); - - } - - - /** - * Set the validating parser flag. This must be called before - * parse() is called the first time. - * - * @param validating The new validating parser flag. - */ - public void setValidating(boolean validating) { - - this.validating = validating; - - } - - - /** - * Return the XMLReader to be used for parsing the input document. - * - * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a - * parser that contains a schema with a DTD. - * @exception SAXException if no XMLReader can be instantiated - */ - public XMLReader getXMLReader() throws SAXException { - if (reader == null){ - reader = getParser().getXMLReader(); - } - - reader.setDTDHandler(this); - reader.setContentHandler(this); - - if (entityResolver == null){ - reader.setEntityResolver(this); - } else { - reader.setEntityResolver(entityResolver); - } - - reader.setErrorHandler(this); - return reader; - } - - // ------------------------------------------------- ContentHandler Methods - - - /** - * Process notification of character data received from the body of - * an XML element. - * - * @param buffer The characters from the XML document - * @param start Starting offset into the buffer - * @param length Number of characters from the buffer - * - * @exception SAXException if a parsing error is to be reported - */ - public void characters(char buffer[], int start, int length) - throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("characters(" + new String(buffer, start, length) + ")"); - } - - bodyText.append(buffer, start, length); - - } - - - /** - * Process notification of the end of the document being reached. - * - * @exception SAXException if a parsing error is to be reported - */ - public void endDocument() throws SAXException { - - if (saxLog.isDebugEnabled()) { - if (getCount() > 1) { - saxLog.debug("endDocument(): " + getCount() + - " elements left"); - } else { - saxLog.debug("endDocument()"); - } - } - - while (getCount() > 1) { - pop(); - } - - // Fire "finish" events for all defined rules - Iterator rules = getRules().rules().iterator(); - while (rules.hasNext()) { - Rule rule = (Rule) rules.next(); - try { - rule.finish(); - } catch (Exception e) { - log.error("Finish event threw exception", e); - throw createSAXException(e); - } catch (Error e) { - log.error("Finish event threw error", e); - throw e; - } - } - - // Perform final cleanup - clear(); - - } - - - /** - * Process notification of the end of an XML element being reached. - * - * @param namespaceURI - The Namespace URI, or the empty string if the - * element has no Namespace URI or if Namespace processing is not - * being performed. - * @param localName - The local name (without prefix), or the empty - * string if Namespace processing is not being performed. - * @param qName - The qualified XML 1.0 name (with prefix), or the - * empty string if qualified names are not available. - * @exception SAXException if a parsing error is to be reported - */ - public void endElement(String namespaceURI, String localName, - String qName) throws SAXException { - - boolean debug = log.isDebugEnabled(); - - if (debug) { - if (saxLog.isDebugEnabled()) { - saxLog.debug("endElement(" + namespaceURI + "," + localName + - "," + qName + ")"); - } - log.debug(" match='" + match + "'"); - log.debug(" bodyText='" + bodyText + "'"); - } - - // Parse system properties - bodyText = updateBodyText(bodyText); - - // the actual element name is either in localName or qName, depending - // on whether the parser is namespace aware - String name = localName; - if ((name == null) || (name.length() < 1)) { - name = qName; - } - - // Fire "body" events for all relevant rules - List rules = (List) matches.pop(); - if ((rules != null) && (rules.size() > 0)) { - String bodyText = this.bodyText.toString(); - for (int i = 0; i < rules.size(); i++) { - try { - Rule rule = (Rule) rules.get(i); - if (debug) { - log.debug(" Fire body() for " + rule); - } - rule.body(namespaceURI, name, bodyText); - } catch (Exception e) { - log.error("Body event threw exception", e); - throw createSAXException(e); - } catch (Error e) { - log.error("Body event threw error", e); - throw e; - } - } - } else { - if (debug) { - log.debug(" No rules found matching '" + match + "'."); - } - } - - // Recover the body text from the surrounding element - bodyText = (StringBuffer) bodyTexts.pop(); - if (debug) { - log.debug(" Popping body text '" + bodyText.toString() + "'"); - } - - // Fire "end" events for all relevant rules in reverse order - if (rules != null) { - for (int i = 0; i < rules.size(); i++) { - int j = (rules.size() - i) - 1; - try { - Rule rule = (Rule) rules.get(j); - if (debug) { - log.debug(" Fire end() for " + rule); - } - rule.end(namespaceURI, name); - } catch (Exception e) { - log.error("End event threw exception", e); - throw createSAXException(e); - } catch (Error e) { - log.error("End event threw error", e); - throw e; - } - } - } - - // Recover the previous match expression - int slash = match.lastIndexOf('/'); - if (slash >= 0) { - match = match.substring(0, slash); - } else { - match = ""; - } - - } - - - /** - * Process notification that a namespace prefix is going out of scope. - * - * @param prefix Prefix that is going out of scope - * - * @exception SAXException if a parsing error is to be reported - */ - public void endPrefixMapping(String prefix) throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("endPrefixMapping(" + prefix + ")"); - } - - // Deregister this prefix mapping - ArrayStack stack = (ArrayStack) namespaces.get(prefix); - if (stack == null) { - return; - } - try { - stack.pop(); - if (stack.empty()) - namespaces.remove(prefix); - } catch (EmptyStackException e) { - throw createSAXException("endPrefixMapping popped too many times"); - } - - } - - - /** - * Process notification of ignorable whitespace received from the body of - * an XML element. - * - * @param buffer The characters from the XML document - * @param start Starting offset into the buffer - * @param len Number of characters from the buffer - * - * @exception SAXException if a parsing error is to be reported - */ - public void ignorableWhitespace(char buffer[], int start, int len) - throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("ignorableWhitespace(" + - new String(buffer, start, len) + ")"); - } - - ; // No processing required - - } - - - /** - * Process notification of a processing instruction that was encountered. - * - * @param target The processing instruction target - * @param data The processing instruction data (if any) - * - * @exception SAXException if a parsing error is to be reported - */ - public void processingInstruction(String target, String data) - throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("processingInstruction('" + target + "','" + data + "')"); - } - - ; // No processing is required - - } - - - /** - * Gets the document locator associated with our parser. - * - * @return the Locator supplied by the document parser - */ - public Locator getDocumentLocator() { - - return locator; - - } - - /** - * Sets the document locator associated with our parser. - * - * @param locator The new locator - */ - public void setDocumentLocator(Locator locator) { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("setDocumentLocator(" + locator + ")"); - } - - this.locator = locator; - - } - - - /** - * Process notification of a skipped entity. - * - * @param name Name of the skipped entity - * - * @exception SAXException if a parsing error is to be reported - */ - public void skippedEntity(String name) throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("skippedEntity(" + name + ")"); - } - - ; // No processing required - - } - - - /** - * Process notification of the beginning of the document being reached. - * - * @exception SAXException if a parsing error is to be reported - */ - public void startDocument() throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("startDocument()"); - } - - // ensure that the digester is properly configured, as - // the digester could be used as a SAX ContentHandler - // rather than via the parse() methods. - configure(); - } - - - /** - * Process notification of the start of an XML element being reached. - * - * @param namespaceURI The Namespace URI, or the empty string if the element - * has no Namespace URI or if Namespace processing is not being performed. - * @param localName The local name (without prefix), or the empty - * string if Namespace processing is not being performed. - * @param qName The qualified name (with prefix), or the empty - * string if qualified names are not available.\ - * @param list The attributes attached to the element. If there are - * no attributes, it shall be an empty Attributes object. - * @exception SAXException if a parsing error is to be reported - */ - public void startElement(String namespaceURI, String localName, - String qName, Attributes list) - throws SAXException { - boolean debug = log.isDebugEnabled(); - - if (saxLog.isDebugEnabled()) { - saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + - qName + ")"); - } - - // Parse system properties - list = updateAttributes(list); - - // Save the body text accumulated for our surrounding element - bodyTexts.push(bodyText); - if (debug) { - log.debug(" Pushing body text '" + bodyText.toString() + "'"); - } - bodyText = new StringBuffer(); - - // the actual element name is either in localName or qName, depending - // on whether the parser is namespace aware - String name = localName; - if ((name == null) || (name.length() < 1)) { - name = qName; - } - - // Compute the current matching rule - StringBuffer sb = new StringBuffer(match); - if (match.length() > 0) { - sb.append('/'); - } - sb.append(name); - match = sb.toString(); - if (debug) { - log.debug(" New match='" + match + "'"); - } - - // Fire "begin" events for all relevant rules - List rules = getRules().match(namespaceURI, match); - matches.push(rules); - if ((rules != null) && (rules.size() > 0)) { - for (int i = 0; i < rules.size(); i++) { - try { - Rule rule = (Rule) rules.get(i); - if (debug) { - log.debug(" Fire begin() for " + rule); - } - rule.begin(namespaceURI, name, list); - } catch (Exception e) { - log.error("Begin event threw exception", e); - throw createSAXException(e); - } catch (Error e) { - log.error("Begin event threw error", e); - throw e; - } - } - } else { - if (debug) { - log.debug(" No rules found matching '" + match + "'."); - } - } - - } - - - /** - * Process notification that a namespace prefix is coming in to scope. - * - * @param prefix Prefix that is being declared - * @param namespaceURI Corresponding namespace URI being mapped to - * - * @exception SAXException if a parsing error is to be reported - */ - public void startPrefixMapping(String prefix, String namespaceURI) - throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("startPrefixMapping(" + prefix + "," + namespaceURI + ")"); - } - - // Register this prefix mapping - ArrayStack stack = (ArrayStack) namespaces.get(prefix); - if (stack == null) { - stack = new ArrayStack(); - namespaces.put(prefix, stack); - } - stack.push(namespaceURI); - - } - - - // ----------------------------------------------------- DTDHandler Methods - - - /** - * Receive notification of a notation declaration event. - * - * @param name The notation name - * @param publicId The public identifier (if any) - * @param systemId The system identifier (if any) - */ - public void notationDecl(String name, String publicId, String systemId) { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("notationDecl(" + name + "," + publicId + "," + - systemId + ")"); - } - - } - - - /** - * Receive notification of an unparsed entity declaration event. - * - * @param name The unparsed entity name - * @param publicId The public identifier (if any) - * @param systemId The system identifier (if any) - * @param notation The name of the associated notation - */ - public void unparsedEntityDecl(String name, String publicId, - String systemId, String notation) { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("unparsedEntityDecl(" + name + "," + publicId + "," + - systemId + "," + notation + ")"); - } - - } - - - // ----------------------------------------------- EntityResolver Methods - - /** - * Set the EntityResolver used by SAX when resolving - * public id and system id. - * This must be called before the first call to parse(). - * @param entityResolver a class that implement the EntityResolver interface. - */ - public void setEntityResolver(EntityResolver entityResolver){ - this.entityResolver = entityResolver; - } - - - /** - * Return the Entity Resolver used by the SAX parser. - * @return Return the Entity Resolver used by the SAX parser. - */ - public EntityResolver getEntityResolver(){ - return entityResolver; - } - - /** - * Resolve the requested external entity. - * - * @param publicId The public identifier of the entity being referenced - * @param systemId The system identifier of the entity being referenced - * - * @exception SAXException if a parsing exception occurs - * - */ - public InputSource resolveEntity(String publicId, String systemId) - throws SAXException { - - if (saxLog.isDebugEnabled()) { - saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "')"); - } - - if (publicId != null) - this.publicId = publicId; - - // Has this system identifier been registered? - String entityURL = null; - if (publicId != null) { - entityURL = (String) entityValidator.get(publicId); - } - - // Redirect the schema location to a local destination - if (schemaLocation != null && entityURL == null && systemId != null){ - entityURL = (String)entityValidator.get(systemId); - } - - if (entityURL == null) { - if (systemId == null) { - // cannot resolve - if (log.isDebugEnabled()) { - log.debug(" Cannot resolve entity: '" + entityURL + "'"); - } - return (null); - - } else { - // try to resolve using system ID - if (log.isDebugEnabled()) { - log.debug(" Trying to resolve using system ID '" + systemId + "'"); - } - entityURL = systemId; - } - } - - // Return an input source to our alternative URL - if (log.isDebugEnabled()) { - log.debug(" Resolving to alternate DTD '" + entityURL + "'"); - } - - try { - return (new InputSource(entityURL)); - } catch (Exception e) { - throw createSAXException(e); - } - } - - - // ------------------------------------------------- ErrorHandler Methods - - - /** - * Forward notification of a parsing error to the application supplied - * error handler (if any). - * - * @param exception The error information - * - * @exception SAXException if a parsing exception occurs - */ - public void error(SAXParseException exception) throws SAXException { - - log.error("Parse Error at line " + exception.getLineNumber() + - " column " + exception.getColumnNumber() + ": " + - exception.getMessage(), exception); - if (errorHandler != null) { - errorHandler.error(exception); - } - - } - - - /** - * Forward notification of a fatal parsing error to the application - * supplied error handler (if any). - * - * @param exception The fatal error information - * - * @exception SAXException if a parsing exception occurs - */ - public void fatalError(SAXParseException exception) throws SAXException { - - log.error("Parse Fatal Error at line " + exception.getLineNumber() + - " column " + exception.getColumnNumber() + ": " + - exception.getMessage(), exception); - if (errorHandler != null) { - errorHandler.fatalError(exception); - } - - } - - - /** - * Forward notification of a parse warning to the application supplied - * error handler (if any). - * - * @param exception The warning information - * - * @exception SAXException if a parsing exception occurs - */ - public void warning(SAXParseException exception) throws SAXException { - if (errorHandler != null) { - log.warn("Parse Warning Error at line " + exception.getLineNumber() + - " column " + exception.getColumnNumber() + ": " + - exception.getMessage(), exception); - - errorHandler.warning(exception); - } - - } - - - // ------------------------------------------------------- Public Methods - - - /** - * Log a message to our associated logger. - * - * @param message The message to be logged - * @deprecated Call getLogger() and use it's logging methods - */ - public void log(String message) { - - log.info(message); - - } - - - /** - * Log a message and exception to our associated logger. - * - * @param message The message to be logged - * @deprecated Call getLogger() and use it's logging methods - */ - public void log(String message, Throwable exception) { - - log.error(message, exception); - - } - - - /** - * Parse the content of the specified file using this Digester. Returns - * the root element from the object stack (if any). - * - * @param file File containing the XML data to be parsed - * - * @exception IOException if an input/output error occurs - * @exception SAXException if a parsing exception occurs - */ - public Object parse(File file) throws IOException, SAXException { - - configure(); - InputSource input = new InputSource(new FileInputStream(file)); - input.setSystemId("file://" + file.getAbsolutePath()); - getXMLReader().parse(input); - return (root); - - } - /** - * Parse the content of the specified input source using this Digester. - * Returns the root element from the object stack (if any). - * - * @param input Input source containing the XML data to be parsed - * - * @exception IOException if an input/output error occurs - * @exception SAXException if a parsing exception occurs - */ - public Object parse(InputSource input) throws IOException, SAXException { - - configure(); - getXMLReader().parse(input); - return (root); - - } - - - /** - * Parse the content of the specified input stream using this Digester. - * Returns the root element from the object stack (if any). - * - * @param input Input stream containing the XML data to be parsed - * - * @exception IOException if an input/output error occurs - * @exception SAXException if a parsing exception occurs - */ - public Object parse(InputStream input) throws IOException, SAXException { - - configure(); - InputSource is = new InputSource(input); - getXMLReader().parse(is); - return (root); - - } - - - /** - * Parse the content of the specified reader using this Digester. - * Returns the root element from the object stack (if any). - * - * @param reader Reader containing the XML data to be parsed - * - * @exception IOException if an input/output error occurs - * @exception SAXException if a parsing exception occurs - */ - public Object parse(Reader reader) throws IOException, SAXException { - - configure(); - InputSource is = new InputSource(reader); - getXMLReader().parse(is); - return (root); - - } - - - /** - * Parse the content of the specified URI using this Digester. - * Returns the root element from the object stack (if any). - * - * @param uri URI containing the XML data to be parsed - * - * @exception IOException if an input/output error occurs - * @exception SAXException if a parsing exception occurs - */ - public Object parse(String uri) throws IOException, SAXException { - - configure(); - InputSource is = new InputSource(uri); - getXMLReader().parse(is); - return (root); - - } - - - /** - *

        Register the specified DTD URL for the specified public identifier. - * This must be called before the first call to parse(). - *

        - * Digester contains an internal EntityResolver - * implementation. This maps PUBLICID's to URLs - * (from which the resource will be loaded). A common use case for this - * method is to register local URLs (possibly computed at runtime by a - * classloader) for DTDs. This allows the performance advantage of using - * a local version without having to ensure every SYSTEM - * URI on every processed xml document is local. This implementation provides - * only basic functionality. If more sophisticated features are required, - * using {@link #setEntityResolver} to set a custom resolver is recommended. - *

        - * Note: This method will have no effect when a custom - * EntityResolver has been set. (Setting a custom - * EntityResolver overrides the internal implementation.) - *

        - * @param publicId Public identifier of the DTD to be resolved - * @param entityURL The URL to use for reading this DTD - */ - public void register(String publicId, String entityURL) { - - if (log.isDebugEnabled()) { - log.debug("register('" + publicId + "', '" + entityURL + "'"); - } - entityValidator.put(publicId, entityURL); - - } - - - // --------------------------------------------------------- Rule Methods - - - /** - *

        Register a new Rule matching the specified pattern. - * This method sets the Digester property on the rule.

        - * - * @param pattern Element matching pattern - * @param rule Rule to be registered - */ - public void addRule(String pattern, Rule rule) { - - rule.setDigester(this); - getRules().add(pattern, rule); - - } - - - /** - * Register a set of Rule instances defined in a RuleSet. - * - * @param ruleSet The RuleSet instance to configure from - */ - public void addRuleSet(RuleSet ruleSet) { - - String oldNamespaceURI = getRuleNamespaceURI(); - String newNamespaceURI = ruleSet.getNamespaceURI(); - if (log.isDebugEnabled()) { - if (newNamespaceURI == null) { - log.debug("addRuleSet() with no namespace URI"); - } else { - log.debug("addRuleSet() with namespace URI " + newNamespaceURI); - } - } - setRuleNamespaceURI(newNamespaceURI); - ruleSet.addRuleInstances(this); - setRuleNamespaceURI(oldNamespaceURI); - - } - - - /** - * Add an "call method" rule for a method which accepts no arguments. - * - * @param pattern Element matching pattern - * @param methodName Method name to be called - * @see CallMethodRule - */ - public void addCallMethod(String pattern, String methodName) { - - addRule( - pattern, - new CallMethodRule(methodName)); - - } - - /** - * Add an "call method" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to be called - * @param paramCount Number of expected parameters (or zero - * for a single parameter from the body of this element) - * @see CallMethodRule - */ - public void addCallMethod(String pattern, String methodName, - int paramCount) { - - addRule(pattern, - new CallMethodRule(methodName, paramCount)); - - } - - - /** - * Add an "call method" rule for the specified parameters. - * If paramCount is set to zero the rule will use - * the body of the matched element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param pattern Element matching pattern - * @param methodName Method name to be called - * @param paramCount Number of expected parameters (or zero - * for a single parameter from the body of this element) - * @param paramTypes Set of Java class names for the types - * of the expected parameters - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * @see CallMethodRule - */ - public void addCallMethod(String pattern, String methodName, - int paramCount, String paramTypes[]) { - - addRule(pattern, - new CallMethodRule( - methodName, - paramCount, - paramTypes)); - - } - - - /** - * Add an "call method" rule for the specified parameters. - * If paramCount is set to zero the rule will use - * the body of the matched element as the single argument of the - * method, unless paramTypes is null or empty, in this - * case the rule will call the specified method with no arguments. - * - * @param pattern Element matching pattern - * @param methodName Method name to be called - * @param paramCount Number of expected parameters (or zero - * for a single parameter from the body of this element) - * @param paramTypes The Java class names of the arguments - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * @see CallMethodRule - */ - public void addCallMethod(String pattern, String methodName, - int paramCount, Class paramTypes[]) { - - addRule(pattern, - new CallMethodRule( - methodName, - paramCount, - paramTypes)); - - } - - - /** - * Add a "call parameter" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param paramIndex Zero-relative parameter index to set - * (from the body of this element) - * @see CallParamRule - */ - public void addCallParam(String pattern, int paramIndex) { - - addRule(pattern, - new CallParamRule(paramIndex)); - - } - - - /** - * Add a "call parameter" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param paramIndex Zero-relative parameter index to set - * (from the specified attribute) - * @param attributeName Attribute whose value is used as the - * parameter value - * @see CallParamRule - */ - public void addCallParam(String pattern, int paramIndex, - String attributeName) { - - addRule(pattern, - new CallParamRule(paramIndex, attributeName)); - - } - - - /** - * Add a "call parameter" rule. - * This will either take a parameter from the stack - * or from the current element body text. - * - * @param paramIndex The zero-relative parameter number - * @param fromStack Should the call parameter be taken from the top of the stack? - * @see CallParamRule - */ - public void addCallParam(String pattern, int paramIndex, boolean fromStack) { - - addRule(pattern, - new CallParamRule(paramIndex, fromStack)); - - } - - /** - * Add a "call parameter" rule that sets a parameter from the stack. - * This takes a parameter from the given position on the stack. - * - * @param paramIndex The zero-relative parameter number - * @param stackIndex set the call parameter to the stackIndex'th object down the stack, - * where 0 is the top of the stack, 1 the next element down and so on - * @see CallMethodRule - */ - public void addCallParam(String pattern, int paramIndex, int stackIndex) { - - addRule(pattern, - new CallParamRule(paramIndex, stackIndex)); - - } - - /** - * Add a "call parameter" rule that sets a parameter from the current - * Digester matching path. - * This is sometimes useful when using rules that support wildcards. - * - * @param pattern the pattern that this rule should match - * @param paramIndex The zero-relative parameter number - * @see CallMethodRule - */ - public void addCallParamPath(String pattern,int paramIndex) { - addRule(pattern, new PathCallParamRule(paramIndex)); - } - - /** - * Add a "call parameter" rule that sets a parameter from a - * caller-provided object. This can be used to pass constants such as - * strings to methods; it can also be used to pass mutable objects, - * providing ways for objects to do things like "register" themselves - * with some shared object. - *

        - * Note that when attempting to locate a matching method to invoke, - * the true type of the paramObj is used, so that despite the paramObj - * being passed in here as type Object, the target method can declare - * its parameters as being the true type of the object (or some ancestor - * type, according to the usual type-conversion rules). - * - * @param paramIndex The zero-relative parameter number - * @param paramObj Any arbitrary object to be passed to the target - * method. - * @see CallMethodRule - * - * @since 1.6 - */ - public void addObjectParam(String pattern, int paramIndex, - Object paramObj) { - - addRule(pattern, - new ObjectParamRule(paramIndex, paramObj)); - - } - - /** - * Add a "factory create" rule for the specified parameters. - * Exceptions thrown during the object creation process will be propagated. - * - * @param pattern Element matching pattern - * @param className Java class name of the object creation factory class - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, String className) { - - addFactoryCreate(pattern, className, false); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * Exceptions thrown during the object creation process will be propagated. - * - * @param pattern Element matching pattern - * @param clazz Java class of the object creation factory class - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, Class clazz) { - - addFactoryCreate(pattern, clazz, false); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * Exceptions thrown during the object creation process will be propagated. - * - * @param pattern Element matching pattern - * @param className Java class name of the object creation factory class - * @param attributeName Attribute name which, if present, overrides the - * value specified by className - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, String className, - String attributeName) { - - addFactoryCreate(pattern, className, attributeName, false); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * Exceptions thrown during the object creation process will be propagated. - * - * @param pattern Element matching pattern - * @param clazz Java class of the object creation factory class - * @param attributeName Attribute name which, if present, overrides the - * value specified by className - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, Class clazz, - String attributeName) { - - addFactoryCreate(pattern, clazz, attributeName, false); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * Exceptions thrown during the object creation process will be propagated. - * - * @param pattern Element matching pattern - * @param creationFactory Previously instantiated ObjectCreationFactory - * to be utilized - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, - ObjectCreationFactory creationFactory) { - - addFactoryCreate(pattern, creationFactory, false); - - } - - /** - * Add a "factory create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param className Java class name of the object creation factory class - * @param ignoreCreateExceptions when true any exceptions thrown during - * object creation will be ignored. - * @see FactoryCreateRule - */ - public void addFactoryCreate( - String pattern, - String className, - boolean ignoreCreateExceptions) { - - addRule( - pattern, - new FactoryCreateRule(className, ignoreCreateExceptions)); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param clazz Java class of the object creation factory class - * @param ignoreCreateExceptions when true any exceptions thrown during - * object creation will be ignored. - * @see FactoryCreateRule - */ - public void addFactoryCreate( - String pattern, - Class clazz, - boolean ignoreCreateExceptions) { - - addRule( - pattern, - new FactoryCreateRule(clazz, ignoreCreateExceptions)); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param className Java class name of the object creation factory class - * @param attributeName Attribute name which, if present, overrides the - * value specified by className - * @param ignoreCreateExceptions when true any exceptions thrown during - * object creation will be ignored. - * @see FactoryCreateRule - */ - public void addFactoryCreate( - String pattern, - String className, - String attributeName, - boolean ignoreCreateExceptions) { - - addRule( - pattern, - new FactoryCreateRule(className, attributeName, ignoreCreateExceptions)); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param clazz Java class of the object creation factory class - * @param attributeName Attribute name which, if present, overrides the - * value specified by className - * @param ignoreCreateExceptions when true any exceptions thrown during - * object creation will be ignored. - * @see FactoryCreateRule - */ - public void addFactoryCreate( - String pattern, - Class clazz, - String attributeName, - boolean ignoreCreateExceptions) { - - addRule( - pattern, - new FactoryCreateRule(clazz, attributeName, ignoreCreateExceptions)); - - } - - - /** - * Add a "factory create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param creationFactory Previously instantiated ObjectCreationFactory - * to be utilized - * @param ignoreCreateExceptions when true any exceptions thrown during - * object creation will be ignored. - * @see FactoryCreateRule - */ - public void addFactoryCreate(String pattern, - ObjectCreationFactory creationFactory, - boolean ignoreCreateExceptions) { - - creationFactory.setDigester(this); - addRule(pattern, - new FactoryCreateRule(creationFactory, ignoreCreateExceptions)); - - } - - /** - * Add an "object create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param className Java class name to be created - * @see ObjectCreateRule - */ - public void addObjectCreate(String pattern, String className) { - - addRule(pattern, - new ObjectCreateRule(className)); - - } - - - /** - * Add an "object create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param clazz Java class to be created - * @see ObjectCreateRule - */ - public void addObjectCreate(String pattern, Class clazz) { - - addRule(pattern, - new ObjectCreateRule(clazz)); - - } - - - /** - * Add an "object create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param className Default Java class name to be created - * @param attributeName Attribute name that optionally overrides - * the default Java class name to be created - * @see ObjectCreateRule - */ - public void addObjectCreate(String pattern, String className, - String attributeName) { - - addRule(pattern, - new ObjectCreateRule(className, attributeName)); - - } - - - /** - * Add an "object create" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param attributeName Attribute name that optionally overrides - * @param clazz Default Java class to be created - * the default Java class name to be created - * @see ObjectCreateRule - */ - public void addObjectCreate(String pattern, - String attributeName, - Class clazz) { - - addRule(pattern, - new ObjectCreateRule(attributeName, clazz)); - - } - - /** - * Add a "set next" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the parent element - * @see SetNextRule - */ - public void addSetNext(String pattern, String methodName) { - - addRule(pattern, - new SetNextRule(methodName)); - - } - - - /** - * Add a "set next" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the parent element - * @param paramType Java class name of the expected parameter type - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * @see SetNextRule - */ - public void addSetNext(String pattern, String methodName, - String paramType) { - - addRule(pattern, - new SetNextRule(methodName, paramType)); - - } - - - /** - * Add {@link SetRootRule} with the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the root object - * @see SetRootRule - */ - public void addSetRoot(String pattern, String methodName) { - - addRule(pattern, - new SetRootRule(methodName)); - - } - - - /** - * Add {@link SetRootRule} with the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the root object - * @param paramType Java class name of the expected parameter type - * @see SetRootRule - */ - public void addSetRoot(String pattern, String methodName, - String paramType) { - - addRule(pattern, - new SetRootRule(methodName, paramType)); - - } - - /** - * Add a "set properties" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @see SetPropertiesRule - */ - public void addSetProperties(String pattern) { - - addRule(pattern, - new SetPropertiesRule()); - - } - - /** - * Add a "set properties" rule with a single overridden parameter. - * See {@link SetPropertiesRule#SetPropertiesRule(String attributeName, String propertyName)} - * - * @param pattern Element matching pattern - * @param attributeName map this attribute - * @param propertyName to this property - * @see SetPropertiesRule - */ - public void addSetProperties( - String pattern, - String attributeName, - String propertyName) { - - addRule(pattern, - new SetPropertiesRule(attributeName, propertyName)); - - } - - /** - * Add a "set properties" rule with overridden parameters. - * See {@link SetPropertiesRule#SetPropertiesRule(String [] attributeNames, String [] propertyNames)} - * - * @param pattern Element matching pattern - * @param attributeNames names of attributes with custom mappings - * @param propertyNames property names these attributes map to - * @see SetPropertiesRule - */ - public void addSetProperties( - String pattern, - String [] attributeNames, - String [] propertyNames) { - - addRule(pattern, - new SetPropertiesRule(attributeNames, propertyNames)); - - } - - - /** - * Add a "set property" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param name Attribute name containing the property name to be set - * @param value Attribute name containing the property value to set - * @see SetPropertyRule - */ - public void addSetProperty(String pattern, String name, String value) { - - addRule(pattern, - new SetPropertyRule(name, value)); - - } - - - /** - * Add a "set top" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the parent element - * @see SetTopRule - */ - public void addSetTop(String pattern, String methodName) { - - addRule(pattern, - new SetTopRule(methodName)); - - } - - - /** - * Add a "set top" rule for the specified parameters. - * - * @param pattern Element matching pattern - * @param methodName Method name to call on the parent element - * @param paramType Java class name of the expected parameter type - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * @see SetTopRule - */ - public void addSetTop(String pattern, String methodName, - String paramType) { - - addRule(pattern, - new SetTopRule(methodName, paramType)); - - } - - - // --------------------------------------------------- Object Stack Methods - - - /** - * Clear the current contents of the object stack. - *

        - * Calling this method might allow another document of the same type - * to be correctly parsed. However this method was not intended for this - * purpose. In general, a separate Digester object should be created for - * each document to be parsed. - */ - public void clear() { - - match = ""; - bodyTexts.clear(); - params.clear(); - publicId = null; - stack.clear(); - log = null; - saxLog = null; - configured = false; - - } - - - public void reset() { - root = null; - setErrorHandler(null); - clear(); - } - - - /** - * Return the top object on the stack without removing it. If there are - * no objects on the stack, return null. - */ - public Object peek() { - - try { - return (stack.peek()); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - * Return the n'th object down the stack, where 0 is the top element - * and [getCount()-1] is the bottom element. If the specified index - * is out of range, return null. - * - * @param n Index of the desired element, where 0 is the top of the stack, - * 1 is the next element down, and so on. - */ - public Object peek(int n) { - - try { - return (stack.peek(n)); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - * Pop the top object off of the stack, and return it. If there are - * no objects on the stack, return null. - */ - public Object pop() { - - try { - return (stack.pop()); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - * Push a new object onto the top of the object stack. - * - * @param object The new object - */ - public void push(Object object) { - - if (stack.size() == 0) { - root = object; - } - stack.push(object); - - } - - /** - * Pushes the given object onto the stack with the given name. - * If no stack already exists with the given name then one will be created. - * - * @param stackName the name of the stack onto which the object should be pushed - * @param value the Object to be pushed onto the named stack. - * - * @since 1.6 - */ - public void push(String stackName, Object value) { - ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); - if (namedStack == null) { - namedStack = new ArrayStack(); - stacksByName.put(stackName, namedStack); - } - namedStack.push(value); - } - - /** - *

        Pops (gets and removes) the top object from the stack with the given name.

        - * - *

        Note: a stack is considered empty - * if no objects have been pushed onto it yet.

        - * - * @param stackName the name of the stack from which the top value is to be popped - * @return the top Object on the stack or or null if the stack is either - * empty or has not been created yet - * @throws EmptyStackException if the named stack is empty - * - * @since 1.6 - */ - public Object pop(String stackName) { - Object result = null; - ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); - if (namedStack == null) { - if (log.isDebugEnabled()) { - log.debug("Stack '" + stackName + "' is empty"); - } - throw new EmptyStackException(); - - } else { - - result = namedStack.pop(); - } - return result; - } - - /** - *

        Gets the top object from the stack with the given name. - * This method does not remove the object from the stack. - *

        - *

        Note: a stack is considered empty - * if no objects have been pushed onto it yet.

        - * - * @param stackName the name of the stack to be peeked - * @return the top Object on the stack or null if the stack is either - * empty or has not been created yet - * @throws EmptyStackException if the named stack is empty - * - * @since 1.6 - */ - public Object peek(String stackName) { - Object result = null; - ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); - if (namedStack == null ) { - if (log.isDebugEnabled()) { - log.debug("Stack '" + stackName + "' is empty"); - } - throw new EmptyStackException(); - - } else { - - result = namedStack.peek(); - } - return result; - } - - /** - *

        Is the stack with the given name empty?

        - *

        Note: a stack is considered empty - * if no objects have been pushed onto it yet.

        - * @param stackName the name of the stack whose emptiness - * should be evaluated - * @return true if the given stack if empty - * - * @since 1.6 - */ - public boolean isEmpty(String stackName) { - boolean result = true; - ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); - if (namedStack != null ) { - result = namedStack.isEmpty(); - } - return result; - } - - /** - * When the Digester is being used as a SAXContentHandler, - * this method allows you to access the root object that has been - * created after parsing. - * - * @return the root object that has been created after parsing - * or null if the digester has not parsed any XML yet. - */ - public Object getRoot() { - return root; - } - - - // ------------------------------------------------ Parameter Stack Methods - - - // ------------------------------------------------------ Protected Methods - - - /** - *

        - * Provide a hook for lazy configuration of this Digester - * instance. The default implementation does nothing, but subclasses - * can override as needed. - *

        - * - *

        - * Note This method may be called more than once. - * Once only initialization code should be placed in {@link #initialize} - * or the code should take responsibility by checking and setting the - * {@link #configured} flag. - *

        - */ - protected void configure() { - - // Do not configure more than once - if (configured) { - return; - } - - log = LogFactory.getLog("org.apache.commons.digester.Digester"); - saxLog = LogFactory.getLog("org.apache.commons.digester.Digester.sax"); - - // Perform lazy configuration as needed - initialize(); // call hook method for subclasses that want to be initialized once only - // Nothing else required by default - - // Set the configuration flag to avoid repeating - configured = true; - - } - - /** - *

        - * Provides a hook for lazy initialization of this Digester - * instance. - * The default implementation does nothing, but subclasses - * can override as needed. - * Digester (by default) only calls this method once. - *

        - * - *

        - * Note This method will be called by {@link #configure} - * only when the {@link #configured} flag is false. - * Subclasses that override configure or who set configured - * may find that this method may be called more than once. - *

        - * - * @since 1.6 - */ - protected void initialize() { - - // Perform lazy initialization as needed - ; // Nothing required by default - - } - - // -------------------------------------------------------- Package Methods - - - /** - * Return the set of DTD URL registrations, keyed by public identifier. - */ - Map getRegistrations() { - - return (entityValidator); - - } - - - /** - * Return the set of rules that apply to the specified match position. - * The selected rules are those that match exactly, or those rules - * that specify a suffix match and the tail of the rule matches the - * current match position. Exact matches have precedence over - * suffix matches, then (among suffix matches) the longest match - * is preferred. - * - * @param match The current match position - * - * @deprecated Call match() on the Rules - * implementation returned by getRules() - */ - List getRules(String match) { - - return (getRules().match(match)); - - } - - - /** - *

        Return the top object on the parameters stack without removing it. If there are - * no objects on the stack, return null.

        - * - *

        The parameters stack is used to store CallMethodRule parameters. - * See {@link #params}.

        - */ - public Object peekParams() { - - try { - return (params.peek()); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - *

        Return the n'th object down the parameters stack, where 0 is the top element - * and [getCount()-1] is the bottom element. If the specified index - * is out of range, return null.

        - * - *

        The parameters stack is used to store CallMethodRule parameters. - * See {@link #params}.

        - * - * @param n Index of the desired element, where 0 is the top of the stack, - * 1 is the next element down, and so on. - */ - public Object peekParams(int n) { - - try { - return (params.peek(n)); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - *

        Pop the top object off of the parameters stack, and return it. If there are - * no objects on the stack, return null.

        - * - *

        The parameters stack is used to store CallMethodRule parameters. - * See {@link #params}.

        - */ - public Object popParams() { - - try { - if (log.isTraceEnabled()) { - log.trace("Popping params"); - } - return (params.pop()); - } catch (EmptyStackException e) { - log.warn("Empty stack (returning null)"); - return (null); - } - - } - - - /** - *

        Push a new object onto the top of the parameters stack.

        - * - *

        The parameters stack is used to store CallMethodRule parameters. - * See {@link #params}.

        - * - * @param object The new object - */ - public void pushParams(Object object) { - if (log.isTraceEnabled()) { - log.trace("Pushing params"); - } - params.push(object); - - } - - /** - * Create a SAX exception which also understands about the location in - * the digester file where the exception occurs - * - * @return the new exception - */ - public SAXException createSAXException(String message, Exception e) { - if ((e != null) && - (e instanceof InvocationTargetException)) { - Throwable t = ((InvocationTargetException) e).getTargetException(); - if ((t != null) && (t instanceof Exception)) { - e = (Exception) t; - } - } - if (locator != null) { - String error = "Error at (" + locator.getLineNumber() + ", " + - locator.getColumnNumber() + ": " + message; - if (e != null) { - return new SAXParseException(error, locator, e); - } else { - return new SAXParseException(error, locator); - } - } - log.error("No Locator!"); - if (e != null) { - return new SAXException(message, e); - } else { - return new SAXException(message); - } - } - - /** - * Create a SAX exception which also understands about the location in - * the digester file where the exception occurs - * - * @return the new exception - */ - public SAXException createSAXException(Exception e) { - if (e instanceof InvocationTargetException) { - Throwable t = ((InvocationTargetException) e).getTargetException(); - if ((t != null) && (t instanceof Exception)) { - e = (Exception) t; - } - } - return createSAXException(e.getMessage(), e); - } - - /** - * Create a SAX exception which also understands about the location in - * the digester file where the exception occurs - * - * @return the new exception - */ - public SAXException createSAXException(String message) { - return createSAXException(message, null); - } - - - // ------------------------------------------------------- Private Methods - - - /** - * Returns an attributes list which contains all the attributes - * passed in, with any text of form "${xxx}" in an attribute value - * replaced by the appropriate value from the system property. - */ - private Attributes updateAttributes(Attributes list) { - - if (list.getLength() == 0) { - return list; - } - - AttributesImpl newAttrs = new AttributesImpl(list); - int nAttributes = newAttrs.getLength(); - for (int i = 0; i < nAttributes; ++i) { - String value = newAttrs.getValue(i); - try { - String newValue = - IntrospectionUtils.replaceProperties(value, null, source); - if (value != newValue) { - newAttrs.setValue(i, newValue); - } - } - catch (Exception e) { - // ignore - let the attribute have its original value - } - } - - return newAttrs; - - } - - - /** - * Return a new StringBuffer containing the same contents as the - * input buffer, except that data of form ${varname} have been - * replaced by the value of that var as defined in the system property. - */ - private StringBuffer updateBodyText(StringBuffer bodyText) { - String in = bodyText.toString(); - String out; - try { - out = IntrospectionUtils.replaceProperties(in, null, source); - } catch(Exception e) { - return bodyText; // return unchanged data - } - - if (out == in) { - // No substitutions required. Don't waste memory creating - // a new buffer - return bodyText; - } else { - return new StringBuffer(out); - } - } - - -} +/* $Id: Digester.java 380645 2006-02-24 11:37:46Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.digester; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; +import java.lang.reflect.InvocationTargetException; +import java.util.EmptyStackException; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.IntrospectionUtils; +import org.xml.sax.Attributes; +import org.xml.sax.EntityResolver; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; +import org.xml.sax.SAXParseException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.helpers.DefaultHandler; + + + + +/** + *

        A Digester processes an XML input stream by matching a + * series of element nesting patterns to execute Rules that have been added + * prior to the start of parsing. This package was inspired by the + * XmlMapper class that was part of Tomcat 3.0 and 3.1, + * but is organized somewhat differently.

        + * + *

        See the Digester + * Developer Guide for more information.

        + * + *

        IMPLEMENTATION NOTE - A single Digester instance may + * only be used within the context of a single thread at a time, and a call + * to parse() must be completed before another can be initiated + * even from the same thread.

        + * + *

        IMPLEMENTATION NOTE - A bug in Xerces 2.0.2 prevents + * the support of XML schema. You need Xerces 2.1/2.3 and up to make + * this class working with XML schema

        + */ + +public class Digester extends DefaultHandler { + + + // ---------------------------------------------------------- Static Fields + + + private static class SystemPropertySource + implements IntrospectionUtils.PropertySource { + public String getProperty( String key ) { + return System.getProperty(key); + } + } + + protected static IntrospectionUtils.PropertySource source[] = + new IntrospectionUtils.PropertySource[] { new SystemPropertySource() }; + + + // --------------------------------------------------------- Constructors + + + /** + * Construct a new Digester with default properties. + */ + public Digester() { + + super(); + + } + + + /** + * Construct a new Digester, allowing a SAXParser to be passed in. This + * allows Digester to be used in environments which are unfriendly to + * JAXP1.1 (such as WebLogic 6.0). Thanks for the request to change go to + * James House (james@interobjective.com). This may help in places where + * you are able to load JAXP 1.1 classes yourself. + */ + public Digester(SAXParser parser) { + + super(); + + this.parser = parser; + + } + + + /** + * Construct a new Digester, allowing an XMLReader to be passed in. This + * allows Digester to be used in environments which are unfriendly to + * JAXP1.1 (such as WebLogic 6.0). Note that if you use this option you + * have to configure namespace and validation support yourself, as these + * properties only affect the SAXParser and emtpy constructor. + */ + public Digester(XMLReader reader) { + + super(); + + this.reader = reader; + + } + + + // --------------------------------------------------- Instance Variables + + + /** + * The body text of the current element. + */ + protected StringBuffer bodyText = new StringBuffer(); + + + /** + * The stack of body text string buffers for surrounding elements. + */ + protected ArrayStack bodyTexts = new ArrayStack(); + + + /** + * Stack whose elements are List objects, each containing a list of + * Rule objects as returned from Rules.getMatch(). As each xml element + * in the input is entered, the matching rules are pushed onto this + * stack. After the end tag is reached, the matches are popped again. + * The depth of is stack is therefore exactly the same as the current + * "nesting" level of the input xml. + * + * @since 1.6 + */ + protected ArrayStack matches = new ArrayStack(10); + + /** + * The class loader to use for instantiating application objects. + * If not specified, the context class loader, or the class loader + * used to load Digester itself, is used, based on the value of the + * useContextClassLoader variable. + */ + protected ClassLoader classLoader = null; + + + /** + * Has this Digester been configured yet. + */ + protected boolean configured = false; + + + /** + * The EntityResolver used by the SAX parser. By default it use this class + */ + protected EntityResolver entityResolver; + + /** + * The URLs of entityValidator that have been registered, keyed by the public + * identifier that corresponds. + */ + protected HashMap entityValidator = new HashMap(); + + + /** + * The application-supplied error handler that is notified when parsing + * warnings, errors, or fatal errors occur. + */ + protected ErrorHandler errorHandler = null; + + + /** + * The SAXParserFactory that is created the first time we need it. + */ + protected SAXParserFactory factory = null; + + /** + * @deprecated This is now managed by {@link ParserFeatureSetterFactory} + */ + protected String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + + /** + * The Locator associated with our parser. + */ + protected Locator locator = null; + + + /** + * The current match pattern for nested element processing. + */ + protected String match = ""; + + + /** + * Do we want a "namespace aware" parser. + */ + protected boolean namespaceAware = false; + + + /** + * Registered namespaces we are currently processing. The key is the + * namespace prefix that was declared in the document. The value is an + * ArrayStack of the namespace URIs this prefix has been mapped to -- + * the top Stack element is the most current one. (This architecture + * is required because documents can declare nested uses of the same + * prefix for different Namespace URIs). + */ + protected HashMap namespaces = new HashMap(); + + + /** + * The parameters stack being utilized by CallMethodRule and + * CallParamRule rules. + */ + protected ArrayStack params = new ArrayStack(); + + + /** + * The SAXParser we will use to parse the input stream. + */ + protected SAXParser parser = null; + + + /** + * The public identifier of the DTD we are currently parsing under + * (if any). + */ + protected String publicId = null; + + + /** + * The XMLReader used to parse digester rules. + */ + protected XMLReader reader = null; + + + /** + * The "root" element of the stack (in other words, the last object + * that was popped. + */ + protected Object root = null; + + + /** + * The Rules implementation containing our collection of + * Rule instances and associated matching policy. If not + * established before the first rule is added, a default implementation + * will be provided. + */ + protected Rules rules = null; + + /** + * The XML schema language to use for validating an XML instance. By + * default this value is set to W3C_XML_SCHEMA + */ + protected String schemaLanguage = W3C_XML_SCHEMA; + + + /** + * The XML schema to use for validating an XML instance. + */ + protected String schemaLocation = null; + + + /** + * The object stack being constructed. + */ + protected ArrayStack stack = new ArrayStack(); + + + /** + * Do we want to use the Context ClassLoader when loading classes + * for instantiating new objects. Default is false. + */ + protected boolean useContextClassLoader = false; + + + /** + * Do we want to use a validating parser. + */ + protected boolean validating = false; + + + /** + * The Log to which most logging calls will be made. + */ + protected Log log = + LogFactory.getLog("org.apache.commons.digester.Digester"); + + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected Log saxLog = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + + /** + * The schema language supported. By default, we use this one. + */ + protected static final String W3C_XML_SCHEMA = + "http://www.w3.org/2001/XMLSchema"; + + /** Stacks used for interrule communication, indexed by name String */ + private HashMap stacksByName = new HashMap(); + + // ------------------------------------------------------------- Properties + + /** + * Return the currently mapped namespace URI for the specified prefix, + * if any; otherwise return null. These mappings come and + * go dynamically as the document is parsed. + * + * @param prefix Prefix to look up + */ + public String findNamespaceURI(String prefix) { + + ArrayStack stack = (ArrayStack) namespaces.get(prefix); + if (stack == null) { + return (null); + } + try { + return ((String) stack.peek()); + } catch (EmptyStackException e) { + return (null); + } + + } + + + /** + * Return the class loader to be used for instantiating application objects + * when required. This is determined based upon the following rules: + *
          + *
        • The class loader set by setClassLoader(), if any
        • + *
        • The thread context class loader, if it exists and the + * useContextClassLoader property is set to true
        • + *
        • The class loader used to load the Digester class itself. + *
        + */ + public ClassLoader getClassLoader() { + + if (this.classLoader != null) { + return (this.classLoader); + } + if (this.useContextClassLoader) { + ClassLoader classLoader = + Thread.currentThread().getContextClassLoader(); + if (classLoader != null) { + return (classLoader); + } + } + return (this.getClass().getClassLoader()); + + } + + + /** + * Set the class loader to be used for instantiating application objects + * when required. + * + * @param classLoader The new class loader to use, or null + * to revert to the standard rules + */ + public void setClassLoader(ClassLoader classLoader) { + + this.classLoader = classLoader; + + } + + + /** + * Return the current depth of the element stack. + */ + public int getCount() { + + return (stack.size()); + + } + + + /** + * Return the name of the XML element that is currently being processed. + */ + public String getCurrentElementName() { + + String elementName = match; + int lastSlash = elementName.lastIndexOf('/'); + if (lastSlash >= 0) { + elementName = elementName.substring(lastSlash + 1); + } + return (elementName); + + } + + + /** + * Return the debugging detail level of our currently enabled logger. + * + * @deprecated This method now always returns 0. Digester uses the apache + * jakarta commons-logging library; see the documentation for that library + * for more information. + */ + public int getDebug() { + + return (0); + + } + + + /** + * Set the debugging detail level of our currently enabled logger. + * + * @param debug New debugging detail level (0=off, increasing integers + * for more detail) + * + * @deprecated This method now has no effect at all. Digester uses + * the apache jakarta comons-logging library; see the documentation + * for that library for more information. + */ + public void setDebug(int debug) { + + ; // No action is taken + + } + + + /** + * Return the error handler for this Digester. + */ + public ErrorHandler getErrorHandler() { + + return (this.errorHandler); + + } + + + /** + * Set the error handler for this Digester. + * + * @param errorHandler The new error handler + */ + public void setErrorHandler(ErrorHandler errorHandler) { + + this.errorHandler = errorHandler; + + } + + + /** + * Return the SAXParserFactory we will use, creating one if necessary. + */ + public SAXParserFactory getFactory() { + + if (factory == null) { + factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(namespaceAware); + factory.setValidating(validating); + } + return (factory); + + } + + + /** + * Returns a flag indicating whether the requested feature is supported + * by the underlying implementation of org.xml.sax.XMLReader. + * See + * for information about the standard SAX2 feature flags. + * + * @param feature Name of the feature to inquire about + * + * @exception ParserConfigurationException if a parser configuration error + * occurs + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public boolean getFeature(String feature) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + + return (getFactory().getFeature(feature)); + + } + + + /** + * Sets a flag indicating whether the requested feature is supported + * by the underlying implementation of org.xml.sax.XMLReader. + * See + * for information about the standard SAX2 feature flags. In order to be + * effective, this method must be called before the + * getParser() method is called for the first time, either + * directly or indirectly. + * + * @param feature Name of the feature to set the status for + * @param value The new value for this feature + * + * @exception ParserConfigurationException if a parser configuration error + * occurs + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public void setFeature(String feature, boolean value) + throws ParserConfigurationException, SAXNotRecognizedException, + SAXNotSupportedException { + + getFactory().setFeature(feature, value); + + } + + + /** + * Return the current Logger associated with this instance of the Digester + */ + public Log getLogger() { + + return log; + + } + + + /** + * Set the current logger for this Digester. + */ + public void setLogger(Log log) { + + this.log = log; + + } + + /** + * Gets the logger used for logging SAX-related information. + * Note the output is finely grained. + * + * @since 1.6 + */ + public Log getSAXLogger() { + + return saxLog; + } + + + /** + * Sets the logger used for logging SAX-related information. + * Note the output is finely grained. + * @param saxLog Log, not null + * + * @since 1.6 + */ + public void setSAXLogger(Log saxLog) { + + this.saxLog = saxLog; + } + + /** + * Return the current rule match path + */ + public String getMatch() { + + return match; + + } + + + /** + * Return the "namespace aware" flag for parsers we create. + */ + public boolean getNamespaceAware() { + + return (this.namespaceAware); + + } + + + /** + * Set the "namespace aware" flag for parsers we create. + * + * @param namespaceAware The new "namespace aware" flag + */ + public void setNamespaceAware(boolean namespaceAware) { + + this.namespaceAware = namespaceAware; + + } + + + /** + * Set the publid id of the current file being parse. + * @param publicId the DTD/Schema public's id. + */ + public void setPublicId(String publicId){ + this.publicId = publicId; + } + + + /** + * Return the public identifier of the DTD we are currently + * parsing under, if any. + */ + public String getPublicId() { + + return (this.publicId); + + } + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getRuleNamespaceURI() { + + return (getRules().getNamespaceURI()); + + } + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param ruleNamespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setRuleNamespaceURI(String ruleNamespaceURI) { + + getRules().setNamespaceURI(ruleNamespaceURI); + + } + + + /** + * Return the SAXParser we will use to parse the input stream. If there + * is a problem creating the parser, return null. + */ + public SAXParser getParser() { + + // Return the parser we already created (if any) + if (parser != null) { + return (parser); + } + + // Create a new parser + try { + if (validating) { + Properties properties = new Properties(); + properties.put("SAXParserFactory", getFactory()); + if (schemaLocation != null) { + properties.put("schemaLocation", schemaLocation); + properties.put("schemaLanguage", schemaLanguage); + } + parser = ParserFeatureSetterFactory.newSAXParser(properties); } else { + parser = getFactory().newSAXParser(); + } + } catch (Exception e) { + log.error("Digester.getParser: ", e); + return (null); + } + + return (parser); + + } + + + /** + * Return the current value of the specified property for the underlying + * XMLReader implementation. + * See + * for information about the standard SAX2 properties. + * + * @param property Property name to be retrieved + * + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public Object getProperty(String property) + throws SAXNotRecognizedException, SAXNotSupportedException { + + return (getParser().getProperty(property)); + + } + + + /** + * Set the current value of the specified property for the underlying + * XMLReader implementation. + * See + * for information about the standard SAX2 properties. + * + * @param property Property name to be set + * @param value Property value to be set + * + * @exception SAXNotRecognizedException if the property name is + * not recognized + * @exception SAXNotSupportedException if the property name is + * recognized but not supported + */ + public void setProperty(String property, Object value) + throws SAXNotRecognizedException, SAXNotSupportedException { + + getParser().setProperty(property, value); + + } + + + /** + * By setting the reader in the constructor, you can bypass JAXP and + * be able to use digester in Weblogic 6.0. + * + * @deprecated Use getXMLReader() instead, which can throw a + * SAXException if the reader cannot be instantiated + */ + public XMLReader getReader() { + + try { + return (getXMLReader()); + } catch (SAXException e) { + log.error("Cannot get XMLReader", e); + return (null); + } + + } + + + /** + * Return the Rules implementation object containing our + * rules collection and associated matching policy. If none has been + * established, a default implementation will be created and returned. + */ + public Rules getRules() { + + if (this.rules == null) { + this.rules = new RulesBase(); + this.rules.setDigester(this); + } + return (this.rules); + + } + + + /** + * Set the Rules implementation object containing our + * rules collection and associated matching policy. + * + * @param rules New Rules implementation + */ + public void setRules(Rules rules) { + + this.rules = rules; + this.rules.setDigester(this); + + } + + + /** + * Return the XML Schema URI used for validating an XML instance. + */ + public String getSchema() { + + return (this.schemaLocation); + + } + + + /** + * Set the XML Schema URI used for validating a XML Instance. + * + * @param schemaLocation a URI to the schema. + */ + public void setSchema(String schemaLocation){ + + this.schemaLocation = schemaLocation; + + } + + + /** + * Return the XML Schema language used when parsing. + */ + public String getSchemaLanguage() { + + return (this.schemaLanguage); + + } + + + /** + * Set the XML Schema language used when parsing. By default, we use W3C. + * + * @param schemaLanguage a URI to the schema language. + */ + public void setSchemaLanguage(String schemaLanguage){ + + this.schemaLanguage = schemaLanguage; + + } + + + /** + * Return the boolean as to whether the context classloader should be used. + */ + public boolean getUseContextClassLoader() { + + return useContextClassLoader; + + } + + + /** + * Determine whether to use the Context ClassLoader (the one found by + * calling Thread.currentThread().getContextClassLoader()) + * to resolve/load classes that are defined in various rules. If not + * using Context ClassLoader, then the class-loading defaults to + * using the calling-class' ClassLoader. + * + * @param use determines whether to use Context ClassLoader. + */ + public void setUseContextClassLoader(boolean use) { + + useContextClassLoader = use; + + } + + + /** + * Return the validating parser flag. + */ + public boolean getValidating() { + + return (this.validating); + + } + + + /** + * Set the validating parser flag. This must be called before + * parse() is called the first time. + * + * @param validating The new validating parser flag. + */ + public void setValidating(boolean validating) { + + this.validating = validating; + + } + + + /** + * Return the XMLReader to be used for parsing the input document. + * + * FIX ME: there is a bug in JAXP/XERCES that prevent the use of a + * parser that contains a schema with a DTD. + * @exception SAXException if no XMLReader can be instantiated + */ + public XMLReader getXMLReader() throws SAXException { + if (reader == null){ + reader = getParser().getXMLReader(); + } + + reader.setDTDHandler(this); + reader.setContentHandler(this); + + if (entityResolver == null){ + reader.setEntityResolver(this); + } else { + reader.setEntityResolver(entityResolver); + } + + reader.setErrorHandler(this); + return reader; + } + + // ------------------------------------------------- ContentHandler Methods + + + /** + * Process notification of character data received from the body of + * an XML element. + * + * @param buffer The characters from the XML document + * @param start Starting offset into the buffer + * @param length Number of characters from the buffer + * + * @exception SAXException if a parsing error is to be reported + */ + public void characters(char buffer[], int start, int length) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("characters(" + new String(buffer, start, length) + ")"); + } + + bodyText.append(buffer, start, length); + + } + + + /** + * Process notification of the end of the document being reached. + * + * @exception SAXException if a parsing error is to be reported + */ + public void endDocument() throws SAXException { + + if (saxLog.isDebugEnabled()) { + if (getCount() > 1) { + saxLog.debug("endDocument(): " + getCount() + + " elements left"); + } else { + saxLog.debug("endDocument()"); + } + } + + while (getCount() > 1) { + pop(); + } + + // Fire "finish" events for all defined rules + Iterator rules = getRules().rules().iterator(); + while (rules.hasNext()) { + Rule rule = (Rule) rules.next(); + try { + rule.finish(); + } catch (Exception e) { + log.error("Finish event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Finish event threw error", e); + throw e; + } + } + + // Perform final cleanup + clear(); + + } + + + /** + * Process notification of the end of an XML element being reached. + * + * @param namespaceURI - The Namespace URI, or the empty string if the + * element has no Namespace URI or if Namespace processing is not + * being performed. + * @param localName - The local name (without prefix), or the empty + * string if Namespace processing is not being performed. + * @param qName - The qualified XML 1.0 name (with prefix), or the + * empty string if qualified names are not available. + * @exception SAXException if a parsing error is to be reported + */ + public void endElement(String namespaceURI, String localName, + String qName) throws SAXException { + + boolean debug = log.isDebugEnabled(); + + if (debug) { + if (saxLog.isDebugEnabled()) { + saxLog.debug("endElement(" + namespaceURI + "," + localName + + "," + qName + ")"); + } + log.debug(" match='" + match + "'"); + log.debug(" bodyText='" + bodyText + "'"); + } + + // Parse system properties + bodyText = updateBodyText(bodyText); + + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if ((name == null) || (name.length() < 1)) { + name = qName; + } + + // Fire "body" events for all relevant rules + List rules = (List) matches.pop(); + if ((rules != null) && (rules.size() > 0)) { + String bodyText = this.bodyText.toString(); + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = (Rule) rules.get(i); + if (debug) { + log.debug(" Fire body() for " + rule); + } + rule.body(namespaceURI, name, bodyText); + } catch (Exception e) { + log.error("Body event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Body event threw error", e); + throw e; + } + } + } else { + if (debug) { + log.debug(" No rules found matching '" + match + "'."); + } + } + + // Recover the body text from the surrounding element + bodyText = (StringBuffer) bodyTexts.pop(); + if (debug) { + log.debug(" Popping body text '" + bodyText.toString() + "'"); + } + + // Fire "end" events for all relevant rules in reverse order + if (rules != null) { + for (int i = 0; i < rules.size(); i++) { + int j = (rules.size() - i) - 1; + try { + Rule rule = (Rule) rules.get(j); + if (debug) { + log.debug(" Fire end() for " + rule); + } + rule.end(namespaceURI, name); + } catch (Exception e) { + log.error("End event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("End event threw error", e); + throw e; + } + } + } + + // Recover the previous match expression + int slash = match.lastIndexOf('/'); + if (slash >= 0) { + match = match.substring(0, slash); + } else { + match = ""; + } + + } + + + /** + * Process notification that a namespace prefix is going out of scope. + * + * @param prefix Prefix that is going out of scope + * + * @exception SAXException if a parsing error is to be reported + */ + public void endPrefixMapping(String prefix) throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("endPrefixMapping(" + prefix + ")"); + } + + // Deregister this prefix mapping + ArrayStack stack = (ArrayStack) namespaces.get(prefix); + if (stack == null) { + return; + } + try { + stack.pop(); + if (stack.empty()) + namespaces.remove(prefix); + } catch (EmptyStackException e) { + throw createSAXException("endPrefixMapping popped too many times"); + } + + } + + + /** + * Process notification of ignorable whitespace received from the body of + * an XML element. + * + * @param buffer The characters from the XML document + * @param start Starting offset into the buffer + * @param len Number of characters from the buffer + * + * @exception SAXException if a parsing error is to be reported + */ + public void ignorableWhitespace(char buffer[], int start, int len) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("ignorableWhitespace(" + + new String(buffer, start, len) + ")"); + } + + ; // No processing required + + } + + + /** + * Process notification of a processing instruction that was encountered. + * + * @param target The processing instruction target + * @param data The processing instruction data (if any) + * + * @exception SAXException if a parsing error is to be reported + */ + public void processingInstruction(String target, String data) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("processingInstruction('" + target + "','" + data + "')"); + } + + ; // No processing is required + + } + + + /** + * Gets the document locator associated with our parser. + * + * @return the Locator supplied by the document parser + */ + public Locator getDocumentLocator() { + + return locator; + + } + + /** + * Sets the document locator associated with our parser. + * + * @param locator The new locator + */ + public void setDocumentLocator(Locator locator) { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("setDocumentLocator(" + locator + ")"); + } + + this.locator = locator; + + } + + + /** + * Process notification of a skipped entity. + * + * @param name Name of the skipped entity + * + * @exception SAXException if a parsing error is to be reported + */ + public void skippedEntity(String name) throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("skippedEntity(" + name + ")"); + } + + ; // No processing required + + } + + + /** + * Process notification of the beginning of the document being reached. + * + * @exception SAXException if a parsing error is to be reported + */ + public void startDocument() throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startDocument()"); + } + + // ensure that the digester is properly configured, as + // the digester could be used as a SAX ContentHandler + // rather than via the parse() methods. + configure(); + } + + + /** + * Process notification of the start of an XML element being reached. + * + * @param namespaceURI The Namespace URI, or the empty string if the element + * has no Namespace URI or if Namespace processing is not being performed. + * @param localName The local name (without prefix), or the empty + * string if Namespace processing is not being performed. + * @param qName The qualified name (with prefix), or the empty + * string if qualified names are not available.\ + * @param list The attributes attached to the element. If there are + * no attributes, it shall be an empty Attributes object. + * @exception SAXException if a parsing error is to be reported + */ + public void startElement(String namespaceURI, String localName, + String qName, Attributes list) + throws SAXException { + boolean debug = log.isDebugEnabled(); + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + + qName + ")"); + } + + // Parse system properties + list = updateAttributes(list); + + // Save the body text accumulated for our surrounding element + bodyTexts.push(bodyText); + if (debug) { + log.debug(" Pushing body text '" + bodyText.toString() + "'"); + } + bodyText = new StringBuffer(); + + // the actual element name is either in localName or qName, depending + // on whether the parser is namespace aware + String name = localName; + if ((name == null) || (name.length() < 1)) { + name = qName; + } + + // Compute the current matching rule + StringBuffer sb = new StringBuffer(match); + if (match.length() > 0) { + sb.append('/'); + } + sb.append(name); + match = sb.toString(); + if (debug) { + log.debug(" New match='" + match + "'"); + } + + // Fire "begin" events for all relevant rules + List rules = getRules().match(namespaceURI, match); + matches.push(rules); + if ((rules != null) && (rules.size() > 0)) { + for (int i = 0; i < rules.size(); i++) { + try { + Rule rule = (Rule) rules.get(i); + if (debug) { + log.debug(" Fire begin() for " + rule); + } + rule.begin(namespaceURI, name, list); + } catch (Exception e) { + log.error("Begin event threw exception", e); + throw createSAXException(e); + } catch (Error e) { + log.error("Begin event threw error", e); + throw e; + } + } + } else { + if (debug) { + log.debug(" No rules found matching '" + match + "'."); + } + } + + } + + + /** + * Process notification that a namespace prefix is coming in to scope. + * + * @param prefix Prefix that is being declared + * @param namespaceURI Corresponding namespace URI being mapped to + * + * @exception SAXException if a parsing error is to be reported + */ + public void startPrefixMapping(String prefix, String namespaceURI) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("startPrefixMapping(" + prefix + "," + namespaceURI + ")"); + } + + // Register this prefix mapping + ArrayStack stack = (ArrayStack) namespaces.get(prefix); + if (stack == null) { + stack = new ArrayStack(); + namespaces.put(prefix, stack); + } + stack.push(namespaceURI); + + } + + + // ----------------------------------------------------- DTDHandler Methods + + + /** + * Receive notification of a notation declaration event. + * + * @param name The notation name + * @param publicId The public identifier (if any) + * @param systemId The system identifier (if any) + */ + public void notationDecl(String name, String publicId, String systemId) { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("notationDecl(" + name + "," + publicId + "," + + systemId + ")"); + } + + } + + + /** + * Receive notification of an unparsed entity declaration event. + * + * @param name The unparsed entity name + * @param publicId The public identifier (if any) + * @param systemId The system identifier (if any) + * @param notation The name of the associated notation + */ + public void unparsedEntityDecl(String name, String publicId, + String systemId, String notation) { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("unparsedEntityDecl(" + name + "," + publicId + "," + + systemId + "," + notation + ")"); + } + + } + + + // ----------------------------------------------- EntityResolver Methods + + /** + * Set the EntityResolver used by SAX when resolving + * public id and system id. + * This must be called before the first call to parse(). + * @param entityResolver a class that implement the EntityResolver interface. + */ + public void setEntityResolver(EntityResolver entityResolver){ + this.entityResolver = entityResolver; + } + + + /** + * Return the Entity Resolver used by the SAX parser. + * @return Return the Entity Resolver used by the SAX parser. + */ + public EntityResolver getEntityResolver(){ + return entityResolver; + } + + /** + * Resolve the requested external entity. + * + * @param publicId The public identifier of the entity being referenced + * @param systemId The system identifier of the entity being referenced + * + * @exception SAXException if a parsing exception occurs + * + */ + public InputSource resolveEntity(String publicId, String systemId) + throws SAXException { + + if (saxLog.isDebugEnabled()) { + saxLog.debug("resolveEntity('" + publicId + "', '" + systemId + "')"); + } + + if (publicId != null) + this.publicId = publicId; + + // Has this system identifier been registered? + String entityURL = null; + if (publicId != null) { + entityURL = (String) entityValidator.get(publicId); + } + + // Redirect the schema location to a local destination + if (schemaLocation != null && entityURL == null && systemId != null){ + entityURL = (String)entityValidator.get(systemId); + } + + if (entityURL == null) { + if (systemId == null) { + // cannot resolve + if (log.isDebugEnabled()) { + log.debug(" Cannot resolve entity: '" + entityURL + "'"); + } + return (null); + + } else { + // try to resolve using system ID + if (log.isDebugEnabled()) { + log.debug(" Trying to resolve using system ID '" + systemId + "'"); + } + entityURL = systemId; + } + } + + // Return an input source to our alternative URL + if (log.isDebugEnabled()) { + log.debug(" Resolving to alternate DTD '" + entityURL + "'"); + } + + try { + return (new InputSource(entityURL)); + } catch (Exception e) { + throw createSAXException(e); + } + } + + + // ------------------------------------------------- ErrorHandler Methods + + + /** + * Forward notification of a parsing error to the application supplied + * error handler (if any). + * + * @param exception The error information + * + * @exception SAXException if a parsing exception occurs + */ + public void error(SAXParseException exception) throws SAXException { + + log.error("Parse Error at line " + exception.getLineNumber() + + " column " + exception.getColumnNumber() + ": " + + exception.getMessage(), exception); + if (errorHandler != null) { + errorHandler.error(exception); + } + + } + + + /** + * Forward notification of a fatal parsing error to the application + * supplied error handler (if any). + * + * @param exception The fatal error information + * + * @exception SAXException if a parsing exception occurs + */ + public void fatalError(SAXParseException exception) throws SAXException { + + log.error("Parse Fatal Error at line " + exception.getLineNumber() + + " column " + exception.getColumnNumber() + ": " + + exception.getMessage(), exception); + if (errorHandler != null) { + errorHandler.fatalError(exception); + } + + } + + + /** + * Forward notification of a parse warning to the application supplied + * error handler (if any). + * + * @param exception The warning information + * + * @exception SAXException if a parsing exception occurs + */ + public void warning(SAXParseException exception) throws SAXException { + if (errorHandler != null) { + log.warn("Parse Warning Error at line " + exception.getLineNumber() + + " column " + exception.getColumnNumber() + ": " + + exception.getMessage(), exception); + + errorHandler.warning(exception); + } + + } + + + // ------------------------------------------------------- Public Methods + + + /** + * Log a message to our associated logger. + * + * @param message The message to be logged + * @deprecated Call getLogger() and use it's logging methods + */ + public void log(String message) { + + log.info(message); + + } + + + /** + * Log a message and exception to our associated logger. + * + * @param message The message to be logged + * @deprecated Call getLogger() and use it's logging methods + */ + public void log(String message, Throwable exception) { + + log.error(message, exception); + + } + + + /** + * Parse the content of the specified file using this Digester. Returns + * the root element from the object stack (if any). + * + * @param file File containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + */ + public Object parse(File file) throws IOException, SAXException { + + configure(); + InputSource input = new InputSource(new FileInputStream(file)); + input.setSystemId("file://" + file.getAbsolutePath()); + getXMLReader().parse(input); + return (root); + + } + /** + * Parse the content of the specified input source using this Digester. + * Returns the root element from the object stack (if any). + * + * @param input Input source containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + */ + public Object parse(InputSource input) throws IOException, SAXException { + + configure(); + getXMLReader().parse(input); + return (root); + + } + + + /** + * Parse the content of the specified input stream using this Digester. + * Returns the root element from the object stack (if any). + * + * @param input Input stream containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + */ + public Object parse(InputStream input) throws IOException, SAXException { + + configure(); + InputSource is = new InputSource(input); + getXMLReader().parse(is); + return (root); + + } + + + /** + * Parse the content of the specified reader using this Digester. + * Returns the root element from the object stack (if any). + * + * @param reader Reader containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + */ + public Object parse(Reader reader) throws IOException, SAXException { + + configure(); + InputSource is = new InputSource(reader); + getXMLReader().parse(is); + return (root); + + } + + + /** + * Parse the content of the specified URI using this Digester. + * Returns the root element from the object stack (if any). + * + * @param uri URI containing the XML data to be parsed + * + * @exception IOException if an input/output error occurs + * @exception SAXException if a parsing exception occurs + */ + public Object parse(String uri) throws IOException, SAXException { + + configure(); + InputSource is = new InputSource(uri); + getXMLReader().parse(is); + return (root); + + } + + + /** + *

        Register the specified DTD URL for the specified public identifier. + * This must be called before the first call to parse(). + *

        + * Digester contains an internal EntityResolver + * implementation. This maps PUBLICID's to URLs + * (from which the resource will be loaded). A common use case for this + * method is to register local URLs (possibly computed at runtime by a + * classloader) for DTDs. This allows the performance advantage of using + * a local version without having to ensure every SYSTEM + * URI on every processed xml document is local. This implementation provides + * only basic functionality. If more sophisticated features are required, + * using {@link #setEntityResolver} to set a custom resolver is recommended. + *

        + * Note: This method will have no effect when a custom + * EntityResolver has been set. (Setting a custom + * EntityResolver overrides the internal implementation.) + *

        + * @param publicId Public identifier of the DTD to be resolved + * @param entityURL The URL to use for reading this DTD + */ + public void register(String publicId, String entityURL) { + + if (log.isDebugEnabled()) { + log.debug("register('" + publicId + "', '" + entityURL + "'"); + } + entityValidator.put(publicId, entityURL); + + } + + + // --------------------------------------------------------- Rule Methods + + + /** + *

        Register a new Rule matching the specified pattern. + * This method sets the Digester property on the rule.

        + * + * @param pattern Element matching pattern + * @param rule Rule to be registered + */ + public void addRule(String pattern, Rule rule) { + + rule.setDigester(this); + getRules().add(pattern, rule); + + } + + + /** + * Register a set of Rule instances defined in a RuleSet. + * + * @param ruleSet The RuleSet instance to configure from + */ + public void addRuleSet(RuleSet ruleSet) { + + String oldNamespaceURI = getRuleNamespaceURI(); + String newNamespaceURI = ruleSet.getNamespaceURI(); + if (log.isDebugEnabled()) { + if (newNamespaceURI == null) { + log.debug("addRuleSet() with no namespace URI"); + } else { + log.debug("addRuleSet() with namespace URI " + newNamespaceURI); + } + } + setRuleNamespaceURI(newNamespaceURI); + ruleSet.addRuleInstances(this); + setRuleNamespaceURI(oldNamespaceURI); + + } + + + /** + * Add an "call method" rule for a method which accepts no arguments. + * + * @param pattern Element matching pattern + * @param methodName Method name to be called + * @see CallMethodRule + */ + public void addCallMethod(String pattern, String methodName) { + + addRule( + pattern, + new CallMethodRule(methodName)); + + } + + /** + * Add an "call method" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to be called + * @param paramCount Number of expected parameters (or zero + * for a single parameter from the body of this element) + * @see CallMethodRule + */ + public void addCallMethod(String pattern, String methodName, + int paramCount) { + + addRule(pattern, + new CallMethodRule(methodName, paramCount)); + + } + + + /** + * Add an "call method" rule for the specified parameters. + * If paramCount is set to zero the rule will use + * the body of the matched element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param pattern Element matching pattern + * @param methodName Method name to be called + * @param paramCount Number of expected parameters (or zero + * for a single parameter from the body of this element) + * @param paramTypes Set of Java class names for the types + * of the expected parameters + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * @see CallMethodRule + */ + public void addCallMethod(String pattern, String methodName, + int paramCount, String paramTypes[]) { + + addRule(pattern, + new CallMethodRule( + methodName, + paramCount, + paramTypes)); + + } + + + /** + * Add an "call method" rule for the specified parameters. + * If paramCount is set to zero the rule will use + * the body of the matched element as the single argument of the + * method, unless paramTypes is null or empty, in this + * case the rule will call the specified method with no arguments. + * + * @param pattern Element matching pattern + * @param methodName Method name to be called + * @param paramCount Number of expected parameters (or zero + * for a single parameter from the body of this element) + * @param paramTypes The Java class names of the arguments + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * @see CallMethodRule + */ + public void addCallMethod(String pattern, String methodName, + int paramCount, Class paramTypes[]) { + + addRule(pattern, + new CallMethodRule( + methodName, + paramCount, + paramTypes)); + + } + + + /** + * Add a "call parameter" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param paramIndex Zero-relative parameter index to set + * (from the body of this element) + * @see CallParamRule + */ + public void addCallParam(String pattern, int paramIndex) { + + addRule(pattern, + new CallParamRule(paramIndex)); + + } + + + /** + * Add a "call parameter" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param paramIndex Zero-relative parameter index to set + * (from the specified attribute) + * @param attributeName Attribute whose value is used as the + * parameter value + * @see CallParamRule + */ + public void addCallParam(String pattern, int paramIndex, + String attributeName) { + + addRule(pattern, + new CallParamRule(paramIndex, attributeName)); + + } + + + /** + * Add a "call parameter" rule. + * This will either take a parameter from the stack + * or from the current element body text. + * + * @param paramIndex The zero-relative parameter number + * @param fromStack Should the call parameter be taken from the top of the stack? + * @see CallParamRule + */ + public void addCallParam(String pattern, int paramIndex, boolean fromStack) { + + addRule(pattern, + new CallParamRule(paramIndex, fromStack)); + + } + + /** + * Add a "call parameter" rule that sets a parameter from the stack. + * This takes a parameter from the given position on the stack. + * + * @param paramIndex The zero-relative parameter number + * @param stackIndex set the call parameter to the stackIndex'th object down the stack, + * where 0 is the top of the stack, 1 the next element down and so on + * @see CallMethodRule + */ + public void addCallParam(String pattern, int paramIndex, int stackIndex) { + + addRule(pattern, + new CallParamRule(paramIndex, stackIndex)); + + } + + /** + * Add a "call parameter" rule that sets a parameter from the current + * Digester matching path. + * This is sometimes useful when using rules that support wildcards. + * + * @param pattern the pattern that this rule should match + * @param paramIndex The zero-relative parameter number + * @see CallMethodRule + */ + public void addCallParamPath(String pattern,int paramIndex) { + addRule(pattern, new PathCallParamRule(paramIndex)); + } + + /** + * Add a "call parameter" rule that sets a parameter from a + * caller-provided object. This can be used to pass constants such as + * strings to methods; it can also be used to pass mutable objects, + * providing ways for objects to do things like "register" themselves + * with some shared object. + *

        + * Note that when attempting to locate a matching method to invoke, + * the true type of the paramObj is used, so that despite the paramObj + * being passed in here as type Object, the target method can declare + * its parameters as being the true type of the object (or some ancestor + * type, according to the usual type-conversion rules). + * + * @param paramIndex The zero-relative parameter number + * @param paramObj Any arbitrary object to be passed to the target + * method. + * @see CallMethodRule + * + * @since 1.6 + */ + public void addObjectParam(String pattern, int paramIndex, + Object paramObj) { + + addRule(pattern, + new ObjectParamRule(paramIndex, paramObj)); + + } + + /** + * Add a "factory create" rule for the specified parameters. + * Exceptions thrown during the object creation process will be propagated. + * + * @param pattern Element matching pattern + * @param className Java class name of the object creation factory class + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, String className) { + + addFactoryCreate(pattern, className, false); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * Exceptions thrown during the object creation process will be propagated. + * + * @param pattern Element matching pattern + * @param clazz Java class of the object creation factory class + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, Class clazz) { + + addFactoryCreate(pattern, clazz, false); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * Exceptions thrown during the object creation process will be propagated. + * + * @param pattern Element matching pattern + * @param className Java class name of the object creation factory class + * @param attributeName Attribute name which, if present, overrides the + * value specified by className + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, String className, + String attributeName) { + + addFactoryCreate(pattern, className, attributeName, false); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * Exceptions thrown during the object creation process will be propagated. + * + * @param pattern Element matching pattern + * @param clazz Java class of the object creation factory class + * @param attributeName Attribute name which, if present, overrides the + * value specified by className + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, Class clazz, + String attributeName) { + + addFactoryCreate(pattern, clazz, attributeName, false); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * Exceptions thrown during the object creation process will be propagated. + * + * @param pattern Element matching pattern + * @param creationFactory Previously instantiated ObjectCreationFactory + * to be utilized + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, + ObjectCreationFactory creationFactory) { + + addFactoryCreate(pattern, creationFactory, false); + + } + + /** + * Add a "factory create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param className Java class name of the object creation factory class + * @param ignoreCreateExceptions when true any exceptions thrown during + * object creation will be ignored. + * @see FactoryCreateRule + */ + public void addFactoryCreate( + String pattern, + String className, + boolean ignoreCreateExceptions) { + + addRule( + pattern, + new FactoryCreateRule(className, ignoreCreateExceptions)); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param clazz Java class of the object creation factory class + * @param ignoreCreateExceptions when true any exceptions thrown during + * object creation will be ignored. + * @see FactoryCreateRule + */ + public void addFactoryCreate( + String pattern, + Class clazz, + boolean ignoreCreateExceptions) { + + addRule( + pattern, + new FactoryCreateRule(clazz, ignoreCreateExceptions)); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param className Java class name of the object creation factory class + * @param attributeName Attribute name which, if present, overrides the + * value specified by className + * @param ignoreCreateExceptions when true any exceptions thrown during + * object creation will be ignored. + * @see FactoryCreateRule + */ + public void addFactoryCreate( + String pattern, + String className, + String attributeName, + boolean ignoreCreateExceptions) { + + addRule( + pattern, + new FactoryCreateRule(className, attributeName, ignoreCreateExceptions)); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param clazz Java class of the object creation factory class + * @param attributeName Attribute name which, if present, overrides the + * value specified by className + * @param ignoreCreateExceptions when true any exceptions thrown during + * object creation will be ignored. + * @see FactoryCreateRule + */ + public void addFactoryCreate( + String pattern, + Class clazz, + String attributeName, + boolean ignoreCreateExceptions) { + + addRule( + pattern, + new FactoryCreateRule(clazz, attributeName, ignoreCreateExceptions)); + + } + + + /** + * Add a "factory create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param creationFactory Previously instantiated ObjectCreationFactory + * to be utilized + * @param ignoreCreateExceptions when true any exceptions thrown during + * object creation will be ignored. + * @see FactoryCreateRule + */ + public void addFactoryCreate(String pattern, + ObjectCreationFactory creationFactory, + boolean ignoreCreateExceptions) { + + creationFactory.setDigester(this); + addRule(pattern, + new FactoryCreateRule(creationFactory, ignoreCreateExceptions)); + + } + + /** + * Add an "object create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param className Java class name to be created + * @see ObjectCreateRule + */ + public void addObjectCreate(String pattern, String className) { + + addRule(pattern, + new ObjectCreateRule(className)); + + } + + + /** + * Add an "object create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param clazz Java class to be created + * @see ObjectCreateRule + */ + public void addObjectCreate(String pattern, Class clazz) { + + addRule(pattern, + new ObjectCreateRule(clazz)); + + } + + + /** + * Add an "object create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param className Default Java class name to be created + * @param attributeName Attribute name that optionally overrides + * the default Java class name to be created + * @see ObjectCreateRule + */ + public void addObjectCreate(String pattern, String className, + String attributeName) { + + addRule(pattern, + new ObjectCreateRule(className, attributeName)); + + } + + + /** + * Add an "object create" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param attributeName Attribute name that optionally overrides + * @param clazz Default Java class to be created + * the default Java class name to be created + * @see ObjectCreateRule + */ + public void addObjectCreate(String pattern, + String attributeName, + Class clazz) { + + addRule(pattern, + new ObjectCreateRule(attributeName, clazz)); + + } + + /** + * Add a "set next" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the parent element + * @see SetNextRule + */ + public void addSetNext(String pattern, String methodName) { + + addRule(pattern, + new SetNextRule(methodName)); + + } + + + /** + * Add a "set next" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the parent element + * @param paramType Java class name of the expected parameter type + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * @see SetNextRule + */ + public void addSetNext(String pattern, String methodName, + String paramType) { + + addRule(pattern, + new SetNextRule(methodName, paramType)); + + } + + + /** + * Add {@link SetRootRule} with the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the root object + * @see SetRootRule + */ + public void addSetRoot(String pattern, String methodName) { + + addRule(pattern, + new SetRootRule(methodName)); + + } + + + /** + * Add {@link SetRootRule} with the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the root object + * @param paramType Java class name of the expected parameter type + * @see SetRootRule + */ + public void addSetRoot(String pattern, String methodName, + String paramType) { + + addRule(pattern, + new SetRootRule(methodName, paramType)); + + } + + /** + * Add a "set properties" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @see SetPropertiesRule + */ + public void addSetProperties(String pattern) { + + addRule(pattern, + new SetPropertiesRule()); + + } + + /** + * Add a "set properties" rule with a single overridden parameter. + * See {@link SetPropertiesRule#SetPropertiesRule(String attributeName, String propertyName)} + * + * @param pattern Element matching pattern + * @param attributeName map this attribute + * @param propertyName to this property + * @see SetPropertiesRule + */ + public void addSetProperties( + String pattern, + String attributeName, + String propertyName) { + + addRule(pattern, + new SetPropertiesRule(attributeName, propertyName)); + + } + + /** + * Add a "set properties" rule with overridden parameters. + * See {@link SetPropertiesRule#SetPropertiesRule(String [] attributeNames, String [] propertyNames)} + * + * @param pattern Element matching pattern + * @param attributeNames names of attributes with custom mappings + * @param propertyNames property names these attributes map to + * @see SetPropertiesRule + */ + public void addSetProperties( + String pattern, + String [] attributeNames, + String [] propertyNames) { + + addRule(pattern, + new SetPropertiesRule(attributeNames, propertyNames)); + + } + + + /** + * Add a "set property" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param name Attribute name containing the property name to be set + * @param value Attribute name containing the property value to set + * @see SetPropertyRule + */ + public void addSetProperty(String pattern, String name, String value) { + + addRule(pattern, + new SetPropertyRule(name, value)); + + } + + + /** + * Add a "set top" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the parent element + * @see SetTopRule + */ + public void addSetTop(String pattern, String methodName) { + + addRule(pattern, + new SetTopRule(methodName)); + + } + + + /** + * Add a "set top" rule for the specified parameters. + * + * @param pattern Element matching pattern + * @param methodName Method name to call on the parent element + * @param paramType Java class name of the expected parameter type + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * @see SetTopRule + */ + public void addSetTop(String pattern, String methodName, + String paramType) { + + addRule(pattern, + new SetTopRule(methodName, paramType)); + + } + + + // --------------------------------------------------- Object Stack Methods + + + /** + * Clear the current contents of the object stack. + *

        + * Calling this method might allow another document of the same type + * to be correctly parsed. However this method was not intended for this + * purpose. In general, a separate Digester object should be created for + * each document to be parsed. + */ + public void clear() { + + match = ""; + bodyTexts.clear(); + params.clear(); + publicId = null; + stack.clear(); + log = null; + saxLog = null; + configured = false; + + } + + + public void reset() { + root = null; + setErrorHandler(null); + clear(); + } + + + /** + * Return the top object on the stack without removing it. If there are + * no objects on the stack, return null. + */ + public Object peek() { + + try { + return (stack.peek()); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + * Return the n'th object down the stack, where 0 is the top element + * and [getCount()-1] is the bottom element. If the specified index + * is out of range, return null. + * + * @param n Index of the desired element, where 0 is the top of the stack, + * 1 is the next element down, and so on. + */ + public Object peek(int n) { + + try { + return (stack.peek(n)); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + * Pop the top object off of the stack, and return it. If there are + * no objects on the stack, return null. + */ + public Object pop() { + + try { + return (stack.pop()); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + * Push a new object onto the top of the object stack. + * + * @param object The new object + */ + public void push(Object object) { + + if (stack.size() == 0) { + root = object; + } + stack.push(object); + + } + + /** + * Pushes the given object onto the stack with the given name. + * If no stack already exists with the given name then one will be created. + * + * @param stackName the name of the stack onto which the object should be pushed + * @param value the Object to be pushed onto the named stack. + * + * @since 1.6 + */ + public void push(String stackName, Object value) { + ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); + if (namedStack == null) { + namedStack = new ArrayStack(); + stacksByName.put(stackName, namedStack); + } + namedStack.push(value); + } + + /** + *

        Pops (gets and removes) the top object from the stack with the given name.

        + * + *

        Note: a stack is considered empty + * if no objects have been pushed onto it yet.

        + * + * @param stackName the name of the stack from which the top value is to be popped + * @return the top Object on the stack or or null if the stack is either + * empty or has not been created yet + * @throws EmptyStackException if the named stack is empty + * + * @since 1.6 + */ + public Object pop(String stackName) { + Object result = null; + ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); + if (namedStack == null) { + if (log.isDebugEnabled()) { + log.debug("Stack '" + stackName + "' is empty"); + } + throw new EmptyStackException(); + + } else { + + result = namedStack.pop(); + } + return result; + } + + /** + *

        Gets the top object from the stack with the given name. + * This method does not remove the object from the stack. + *

        + *

        Note: a stack is considered empty + * if no objects have been pushed onto it yet.

        + * + * @param stackName the name of the stack to be peeked + * @return the top Object on the stack or null if the stack is either + * empty or has not been created yet + * @throws EmptyStackException if the named stack is empty + * + * @since 1.6 + */ + public Object peek(String stackName) { + Object result = null; + ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); + if (namedStack == null ) { + if (log.isDebugEnabled()) { + log.debug("Stack '" + stackName + "' is empty"); + } + throw new EmptyStackException(); + + } else { + + result = namedStack.peek(); + } + return result; + } + + /** + *

        Is the stack with the given name empty?

        + *

        Note: a stack is considered empty + * if no objects have been pushed onto it yet.

        + * @param stackName the name of the stack whose emptiness + * should be evaluated + * @return true if the given stack if empty + * + * @since 1.6 + */ + public boolean isEmpty(String stackName) { + boolean result = true; + ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName); + if (namedStack != null ) { + result = namedStack.isEmpty(); + } + return result; + } + + /** + * When the Digester is being used as a SAXContentHandler, + * this method allows you to access the root object that has been + * created after parsing. + * + * @return the root object that has been created after parsing + * or null if the digester has not parsed any XML yet. + */ + public Object getRoot() { + return root; + } + + + // ------------------------------------------------ Parameter Stack Methods + + + // ------------------------------------------------------ Protected Methods + + + /** + *

        + * Provide a hook for lazy configuration of this Digester + * instance. The default implementation does nothing, but subclasses + * can override as needed. + *

        + * + *

        + * Note This method may be called more than once. + * Once only initialization code should be placed in {@link #initialize} + * or the code should take responsibility by checking and setting the + * {@link #configured} flag. + *

        + */ + protected void configure() { + + // Do not configure more than once + if (configured) { + return; + } + + log = LogFactory.getLog("org.apache.commons.digester.Digester"); + saxLog = LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + // Perform lazy configuration as needed + initialize(); // call hook method for subclasses that want to be initialized once only + // Nothing else required by default + + // Set the configuration flag to avoid repeating + configured = true; + + } + + /** + *

        + * Provides a hook for lazy initialization of this Digester + * instance. + * The default implementation does nothing, but subclasses + * can override as needed. + * Digester (by default) only calls this method once. + *

        + * + *

        + * Note This method will be called by {@link #configure} + * only when the {@link #configured} flag is false. + * Subclasses that override configure or who set configured + * may find that this method may be called more than once. + *

        + * + * @since 1.6 + */ + protected void initialize() { + + // Perform lazy initialization as needed + ; // Nothing required by default + + } + + // -------------------------------------------------------- Package Methods + + + /** + * Return the set of DTD URL registrations, keyed by public identifier. + */ + Map getRegistrations() { + + return (entityValidator); + + } + + + /** + * Return the set of rules that apply to the specified match position. + * The selected rules are those that match exactly, or those rules + * that specify a suffix match and the tail of the rule matches the + * current match position. Exact matches have precedence over + * suffix matches, then (among suffix matches) the longest match + * is preferred. + * + * @param match The current match position + * + * @deprecated Call match() on the Rules + * implementation returned by getRules() + */ + List getRules(String match) { + + return (getRules().match(match)); + + } + + + /** + *

        Return the top object on the parameters stack without removing it. If there are + * no objects on the stack, return null.

        + * + *

        The parameters stack is used to store CallMethodRule parameters. + * See {@link #params}.

        + */ + public Object peekParams() { + + try { + return (params.peek()); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + *

        Return the n'th object down the parameters stack, where 0 is the top element + * and [getCount()-1] is the bottom element. If the specified index + * is out of range, return null.

        + * + *

        The parameters stack is used to store CallMethodRule parameters. + * See {@link #params}.

        + * + * @param n Index of the desired element, where 0 is the top of the stack, + * 1 is the next element down, and so on. + */ + public Object peekParams(int n) { + + try { + return (params.peek(n)); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + *

        Pop the top object off of the parameters stack, and return it. If there are + * no objects on the stack, return null.

        + * + *

        The parameters stack is used to store CallMethodRule parameters. + * See {@link #params}.

        + */ + public Object popParams() { + + try { + if (log.isTraceEnabled()) { + log.trace("Popping params"); + } + return (params.pop()); + } catch (EmptyStackException e) { + log.warn("Empty stack (returning null)"); + return (null); + } + + } + + + /** + *

        Push a new object onto the top of the parameters stack.

        + * + *

        The parameters stack is used to store CallMethodRule parameters. + * See {@link #params}.

        + * + * @param object The new object + */ + public void pushParams(Object object) { + if (log.isTraceEnabled()) { + log.trace("Pushing params"); + } + params.push(object); + + } + + /** + * Create a SAX exception which also understands about the location in + * the digester file where the exception occurs + * + * @return the new exception + */ + public SAXException createSAXException(String message, Exception e) { + if ((e != null) && + (e instanceof InvocationTargetException)) { + Throwable t = ((InvocationTargetException) e).getTargetException(); + if ((t != null) && (t instanceof Exception)) { + e = (Exception) t; + } + } + if (locator != null) { + String error = "Error at (" + locator.getLineNumber() + ", " + + locator.getColumnNumber() + ": " + message; + if (e != null) { + return new SAXParseException(error, locator, e); + } else { + return new SAXParseException(error, locator); + } + } + log.error("No Locator!"); + if (e != null) { + return new SAXException(message, e); + } else { + return new SAXException(message); + } + } + + /** + * Create a SAX exception which also understands about the location in + * the digester file where the exception occurs + * + * @return the new exception + */ + public SAXException createSAXException(Exception e) { + if (e instanceof InvocationTargetException) { + Throwable t = ((InvocationTargetException) e).getTargetException(); + if ((t != null) && (t instanceof Exception)) { + e = (Exception) t; + } + } + return createSAXException(e.getMessage(), e); + } + + /** + * Create a SAX exception which also understands about the location in + * the digester file where the exception occurs + * + * @return the new exception + */ + public SAXException createSAXException(String message) { + return createSAXException(message, null); + } + + + // ------------------------------------------------------- Private Methods + + + /** + * Returns an attributes list which contains all the attributes + * passed in, with any text of form "${xxx}" in an attribute value + * replaced by the appropriate value from the system property. + */ + private Attributes updateAttributes(Attributes list) { + + if (list.getLength() == 0) { + return list; + } + + AttributesImpl newAttrs = new AttributesImpl(list); + int nAttributes = newAttrs.getLength(); + for (int i = 0; i < nAttributes; ++i) { + String value = newAttrs.getValue(i); + try { + String newValue = + IntrospectionUtils.replaceProperties(value, null, source); + if (value != newValue) { + newAttrs.setValue(i, newValue); + } + } + catch (Exception e) { + // ignore - let the attribute have its original value + } + } + + return newAttrs; + + } + + + /** + * Return a new StringBuffer containing the same contents as the + * input buffer, except that data of form ${varname} have been + * replaced by the value of that var as defined in the system property. + */ + private StringBuffer updateBodyText(StringBuffer bodyText) { + String in = bodyText.toString(); + String out; + try { + out = IntrospectionUtils.replaceProperties(in, null, source); + } catch(Exception e) { + return bodyText; // return unchanged data + } + + if (out == in) { + // No substitutions required. Don't waste memory creating + // a new buffer + return bodyText; + } else { + return new StringBuffer(out); + } + } + + +} diff --git a/java/org/apache/tomcat/util/digester/FactoryCreateRule.java b/java/org/apache/tomcat/util/digester/FactoryCreateRule.java index 407aac0fa..5d246cc60 100644 --- a/java/org/apache/tomcat/util/digester/FactoryCreateRule.java +++ b/java/org/apache/tomcat/util/digester/FactoryCreateRule.java @@ -1,495 +1,495 @@ -/* $Id: FactoryCreateRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import org.xml.sax.Attributes; - - -/** - *

        Rule implementation that uses an {@link ObjectCreationFactory} to create - * a new object which it pushes onto the object stack. When the element is - * complete, the object will be popped.

        - * - *

        This rule is intended in situations where the element's attributes are - * needed before the object can be created. A common senario is for the - * ObjectCreationFactory implementation to use the attributes as parameters - * in a call to either a factory method or to a non-empty constructor. - */ - -public class FactoryCreateRule extends Rule { - - // ----------------------------------------------------------- Fields - - /** Should exceptions thrown by the factory be ignored? */ - private boolean ignoreCreateExceptions; - /** Stock to manage */ - private ArrayStack exceptionIgnoredStack; - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a factory create rule that will use the specified - * class name to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param digester The associated Digester - * @param className Java class name of the object creation factory class - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #FactoryCreateRule(String className)} instead. - */ - public FactoryCreateRule(Digester digester, String className) { - - this(className); - - } - - - /** - * Construct a factory create rule that will use the specified - * class to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param digester The associated Digester - * @param clazz Java class name of the object creation factory class - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #FactoryCreateRule(Class clazz)} instead. - */ - public FactoryCreateRule(Digester digester, Class clazz) { - - this(clazz); - - } - - - /** - * Construct a factory create rule that will use the specified - * class name (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param digester The associated Digester - * @param className Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #FactoryCreateRule(String className, String attributeName)} instead. - */ - public FactoryCreateRule(Digester digester, - String className, String attributeName) { - - this(className, attributeName); - - } - - - /** - * Construct a factory create rule that will use the specified - * class (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param digester The associated Digester - * @param clazz Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead. - */ - public FactoryCreateRule(Digester digester, - Class clazz, String attributeName) { - - this(clazz, attributeName); - - } - - - /** - * Construct a factory create rule using the given, already instantiated, - * {@link ObjectCreationFactory}. - * - * @param digester The associated Digester - * @param creationFactory called on to create the object. - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead. - */ - public FactoryCreateRule(Digester digester, - ObjectCreationFactory creationFactory) { - - this(creationFactory); - - } - - /** - *

        Construct a factory create rule that will use the specified - * class name to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack.

        - * - *

        Exceptions thrown during the object creation process will be propagated.

        - * - * @param className Java class name of the object creation factory class - */ - public FactoryCreateRule(String className) { - - this(className, false); - - } - - - /** - *

        Construct a factory create rule that will use the specified - * class to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack.

        - * - *

        Exceptions thrown during the object creation process will be propagated.

        - * - * @param clazz Java class name of the object creation factory class - */ - public FactoryCreateRule(Class clazz) { - - this(clazz, false); - - } - - - /** - *

        Construct a factory create rule that will use the specified - * class name (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack.

        - * - *

        Exceptions thrown during the object creation process will be propagated.

        - * - * @param className Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - */ - public FactoryCreateRule(String className, String attributeName) { - - this(className, attributeName, false); - - } - - - /** - *

        Construct a factory create rule that will use the specified - * class (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack.

        - * - *

        Exceptions thrown during the object creation process will be propagated.

        - * - * @param clazz Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - */ - public FactoryCreateRule(Class clazz, String attributeName) { - - this(clazz, attributeName, false); - - } - - - /** - *

        Construct a factory create rule using the given, already instantiated, - * {@link ObjectCreationFactory}.

        - * - *

        Exceptions thrown during the object creation process will be propagated.

        - * - * @param creationFactory called on to create the object. - */ - public FactoryCreateRule(ObjectCreationFactory creationFactory) { - - this(creationFactory, false); - - } - - /** - * Construct a factory create rule that will use the specified - * class name to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param className Java class name of the object creation factory class - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory - * will be ignored. - */ - public FactoryCreateRule(String className, boolean ignoreCreateExceptions) { - - this(className, null, ignoreCreateExceptions); - - } - - - /** - * Construct a factory create rule that will use the specified - * class to create an {@link ObjectCreationFactory} which will - * then be used to create an object and push it on the stack. - * - * @param clazz Java class name of the object creation factory class - * @param ignoreCreateExceptions if true, exceptions thrown by the - * object creation factory - * will be ignored. - */ - public FactoryCreateRule(Class clazz, boolean ignoreCreateExceptions) { - - this(clazz, null, ignoreCreateExceptions); - - } - - - /** - * Construct a factory create rule that will use the specified - * class name (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param className Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public FactoryCreateRule( - String className, - String attributeName, - boolean ignoreCreateExceptions) { - - this.className = className; - this.attributeName = attributeName; - this.ignoreCreateExceptions = ignoreCreateExceptions; - - } - - - /** - * Construct a factory create rule that will use the specified - * class (possibly overridden by the specified attribute if present) - * to create an {@link ObjectCreationFactory}, which will then be used - * to instantiate an object instance and push it onto the stack. - * - * @param clazz Default Java class name of the factory class - * @param attributeName Attribute name which, if present, contains an - * override of the class name of the object creation factory to create. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public FactoryCreateRule( - Class clazz, - String attributeName, - boolean ignoreCreateExceptions) { - - this(clazz.getName(), attributeName, ignoreCreateExceptions); - - } - - - /** - * Construct a factory create rule using the given, already instantiated, - * {@link ObjectCreationFactory}. - * - * @param creationFactory called on to create the object. - * @param ignoreCreateExceptions if true, exceptions thrown by the object - * creation factory will be ignored. - */ - public FactoryCreateRule( - ObjectCreationFactory creationFactory, - boolean ignoreCreateExceptions) { - - this.creationFactory = creationFactory; - this.ignoreCreateExceptions = ignoreCreateExceptions; - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The attribute containing an override class name if it is present. - */ - protected String attributeName = null; - - - /** - * The Java class name of the ObjectCreationFactory to be created. - * This class must have a no-arguments constructor. - */ - protected String className = null; - - - /** - * The object creation factory we will use to instantiate objects - * as required based on the attributes specified in the matched XML - * element. - */ - protected ObjectCreationFactory creationFactory = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the beginning of this element. - * - * @param attributes The attribute list of this element - */ - public void begin(String namespace, String name, Attributes attributes) throws Exception { - - if (ignoreCreateExceptions) { - - if (exceptionIgnoredStack == null) { - exceptionIgnoredStack = new ArrayStack(); - } - - try { - Object instance = getFactory(attributes).createObject(attributes); - - if (digester.log.isDebugEnabled()) { - digester.log.debug("[FactoryCreateRule]{" + digester.match + - "} New " + instance.getClass().getName()); - } - digester.push(instance); - exceptionIgnoredStack.push(Boolean.FALSE); - - } catch (Exception e) { - // log message and error - if (digester.log.isInfoEnabled()) { - digester.log.info("[FactoryCreateRule] Create exception ignored: " + - ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); - if (digester.log.isDebugEnabled()) { - digester.log.debug("[FactoryCreateRule] Ignored exception:", e); - } - } - exceptionIgnoredStack.push(Boolean.TRUE); - } - - } else { - Object instance = getFactory(attributes).createObject(attributes); - - if (digester.log.isDebugEnabled()) { - digester.log.debug("[FactoryCreateRule]{" + digester.match + - "} New " + instance.getClass().getName()); - } - digester.push(instance); - } - } - - - /** - * Process the end of this element. - */ - public void end(String namespace, String name) throws Exception { - - // check if object was created - // this only happens if an exception was thrown and we're ignoring them - if ( - ignoreCreateExceptions && - exceptionIgnoredStack != null && - !(exceptionIgnoredStack.empty())) { - - if (((Boolean) exceptionIgnoredStack.pop()).booleanValue()) { - // creation exception was ignored - // nothing was put onto the stack - if (digester.log.isTraceEnabled()) { - digester.log.trace("[FactoryCreateRule] No creation so no push so no pop"); - } - return; - } - } - - Object top = digester.pop(); - if (digester.log.isDebugEnabled()) { - digester.log.debug("[FactoryCreateRule]{" + digester.match + - "} Pop " + top.getClass().getName()); - } - - } - - - /** - * Clean up after parsing is complete. - */ - public void finish() throws Exception { - - if (attributeName != null) { - creationFactory = null; - } - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("FactoryCreateRule["); - sb.append("className="); - sb.append(className); - sb.append(", attributeName="); - sb.append(attributeName); - if (creationFactory != null) { - sb.append(", creationFactory="); - sb.append(creationFactory); - } - sb.append("]"); - return (sb.toString()); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return an instance of our associated object creation factory, - * creating one if necessary. - * - * @param attributes Attributes passed to our factory creation element - * - * @exception Exception if any error occurs - */ - protected ObjectCreationFactory getFactory(Attributes attributes) - throws Exception { - - if (creationFactory == null) { - String realClassName = className; - if (attributeName != null) { - String value = attributes.getValue(attributeName); - if (value != null) { - realClassName = value; - } - } - if (digester.log.isDebugEnabled()) { - digester.log.debug("[FactoryCreateRule]{" + digester.match + - "} New factory " + realClassName); - } - Class clazz = digester.getClassLoader().loadClass(realClassName); - creationFactory = (ObjectCreationFactory) - clazz.newInstance(); - creationFactory.setDigester(digester); - } - return (creationFactory); - - } -} +/* $Id: FactoryCreateRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import org.xml.sax.Attributes; + + +/** + *

        Rule implementation that uses an {@link ObjectCreationFactory} to create + * a new object which it pushes onto the object stack. When the element is + * complete, the object will be popped.

        + * + *

        This rule is intended in situations where the element's attributes are + * needed before the object can be created. A common senario is for the + * ObjectCreationFactory implementation to use the attributes as parameters + * in a call to either a factory method or to a non-empty constructor. + */ + +public class FactoryCreateRule extends Rule { + + // ----------------------------------------------------------- Fields + + /** Should exceptions thrown by the factory be ignored? */ + private boolean ignoreCreateExceptions; + /** Stock to manage */ + private ArrayStack exceptionIgnoredStack; + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param digester The associated Digester + * @param className Java class name of the object creation factory class + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(String className)} instead. + */ + public FactoryCreateRule(Digester digester, String className) { + + this(className); + + } + + + /** + * Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param digester The associated Digester + * @param clazz Java class name of the object creation factory class + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(Class clazz)} instead. + */ + public FactoryCreateRule(Digester digester, Class clazz) { + + this(clazz); + + } + + + /** + * Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param digester The associated Digester + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(String className, String attributeName)} instead. + */ + public FactoryCreateRule(Digester digester, + String className, String attributeName) { + + this(className, attributeName); + + } + + + /** + * Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param digester The associated Digester + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(Class clazz, String attributeName)} instead. + */ + public FactoryCreateRule(Digester digester, + Class clazz, String attributeName) { + + this(clazz, attributeName); + + } + + + /** + * Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}. + * + * @param digester The associated Digester + * @param creationFactory called on to create the object. + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #FactoryCreateRule(ObjectCreationFactory creationFactory)} instead. + */ + public FactoryCreateRule(Digester digester, + ObjectCreationFactory creationFactory) { + + this(creationFactory); + + } + + /** + *

        Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack.

        + * + *

        Exceptions thrown during the object creation process will be propagated.

        + * + * @param className Java class name of the object creation factory class + */ + public FactoryCreateRule(String className) { + + this(className, false); + + } + + + /** + *

        Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack.

        + * + *

        Exceptions thrown during the object creation process will be propagated.

        + * + * @param clazz Java class name of the object creation factory class + */ + public FactoryCreateRule(Class clazz) { + + this(clazz, false); + + } + + + /** + *

        Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack.

        + * + *

        Exceptions thrown during the object creation process will be propagated.

        + * + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + */ + public FactoryCreateRule(String className, String attributeName) { + + this(className, attributeName, false); + + } + + + /** + *

        Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack.

        + * + *

        Exceptions thrown during the object creation process will be propagated.

        + * + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + */ + public FactoryCreateRule(Class clazz, String attributeName) { + + this(clazz, attributeName, false); + + } + + + /** + *

        Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}.

        + * + *

        Exceptions thrown during the object creation process will be propagated.

        + * + * @param creationFactory called on to create the object. + */ + public FactoryCreateRule(ObjectCreationFactory creationFactory) { + + this(creationFactory, false); + + } + + /** + * Construct a factory create rule that will use the specified + * class name to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param className Java class name of the object creation factory class + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory + * will be ignored. + */ + public FactoryCreateRule(String className, boolean ignoreCreateExceptions) { + + this(className, null, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule that will use the specified + * class to create an {@link ObjectCreationFactory} which will + * then be used to create an object and push it on the stack. + * + * @param clazz Java class name of the object creation factory class + * @param ignoreCreateExceptions if true, exceptions thrown by the + * object creation factory + * will be ignored. + */ + public FactoryCreateRule(Class clazz, boolean ignoreCreateExceptions) { + + this(clazz, null, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule that will use the specified + * class name (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param className Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + String className, + String attributeName, + boolean ignoreCreateExceptions) { + + this.className = className; + this.attributeName = attributeName; + this.ignoreCreateExceptions = ignoreCreateExceptions; + + } + + + /** + * Construct a factory create rule that will use the specified + * class (possibly overridden by the specified attribute if present) + * to create an {@link ObjectCreationFactory}, which will then be used + * to instantiate an object instance and push it onto the stack. + * + * @param clazz Default Java class name of the factory class + * @param attributeName Attribute name which, if present, contains an + * override of the class name of the object creation factory to create. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + Class clazz, + String attributeName, + boolean ignoreCreateExceptions) { + + this(clazz.getName(), attributeName, ignoreCreateExceptions); + + } + + + /** + * Construct a factory create rule using the given, already instantiated, + * {@link ObjectCreationFactory}. + * + * @param creationFactory called on to create the object. + * @param ignoreCreateExceptions if true, exceptions thrown by the object + * creation factory will be ignored. + */ + public FactoryCreateRule( + ObjectCreationFactory creationFactory, + boolean ignoreCreateExceptions) { + + this.creationFactory = creationFactory; + this.ignoreCreateExceptions = ignoreCreateExceptions; + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute containing an override class name if it is present. + */ + protected String attributeName = null; + + + /** + * The Java class name of the ObjectCreationFactory to be created. + * This class must have a no-arguments constructor. + */ + protected String className = null; + + + /** + * The object creation factory we will use to instantiate objects + * as required based on the attributes specified in the matched XML + * element. + */ + protected ObjectCreationFactory creationFactory = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + public void begin(String namespace, String name, Attributes attributes) throws Exception { + + if (ignoreCreateExceptions) { + + if (exceptionIgnoredStack == null) { + exceptionIgnoredStack = new ArrayStack(); + } + + try { + Object instance = getFactory(attributes).createObject(attributes); + + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New " + instance.getClass().getName()); + } + digester.push(instance); + exceptionIgnoredStack.push(Boolean.FALSE); + + } catch (Exception e) { + // log message and error + if (digester.log.isInfoEnabled()) { + digester.log.info("[FactoryCreateRule] Create exception ignored: " + + ((e.getMessage() == null) ? e.getClass().getName() : e.getMessage())); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule] Ignored exception:", e); + } + } + exceptionIgnoredStack.push(Boolean.TRUE); + } + + } else { + Object instance = getFactory(attributes).createObject(attributes); + + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New " + instance.getClass().getName()); + } + digester.push(instance); + } + } + + + /** + * Process the end of this element. + */ + public void end(String namespace, String name) throws Exception { + + // check if object was created + // this only happens if an exception was thrown and we're ignoring them + if ( + ignoreCreateExceptions && + exceptionIgnoredStack != null && + !(exceptionIgnoredStack.empty())) { + + if (((Boolean) exceptionIgnoredStack.pop()).booleanValue()) { + // creation exception was ignored + // nothing was put onto the stack + if (digester.log.isTraceEnabled()) { + digester.log.trace("[FactoryCreateRule] No creation so no push so no pop"); + } + return; + } + } + + Object top = digester.pop(); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} Pop " + top.getClass().getName()); + } + + } + + + /** + * Clean up after parsing is complete. + */ + public void finish() throws Exception { + + if (attributeName != null) { + creationFactory = null; + } + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("FactoryCreateRule["); + sb.append("className="); + sb.append(className); + sb.append(", attributeName="); + sb.append(attributeName); + if (creationFactory != null) { + sb.append(", creationFactory="); + sb.append(creationFactory); + } + sb.append("]"); + return (sb.toString()); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return an instance of our associated object creation factory, + * creating one if necessary. + * + * @param attributes Attributes passed to our factory creation element + * + * @exception Exception if any error occurs + */ + protected ObjectCreationFactory getFactory(Attributes attributes) + throws Exception { + + if (creationFactory == null) { + String realClassName = className; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) { + realClassName = value; + } + } + if (digester.log.isDebugEnabled()) { + digester.log.debug("[FactoryCreateRule]{" + digester.match + + "} New factory " + realClassName); + } + Class clazz = digester.getClassLoader().loadClass(realClassName); + creationFactory = (ObjectCreationFactory) + clazz.newInstance(); + creationFactory.setDigester(digester); + } + return (creationFactory); + + } +} diff --git a/java/org/apache/tomcat/util/digester/GenericParser.java b/java/org/apache/tomcat/util/digester/GenericParser.java index 9beec2a6a..6b29afb09 100644 --- a/java/org/apache/tomcat/util/digester/GenericParser.java +++ b/java/org/apache/tomcat/util/digester/GenericParser.java @@ -1,86 +1,86 @@ -/* $Id: GenericParser.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import java.util.Properties; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotRecognizedException; - -/** - * Create a SAXParser configured to support XML Schema and DTD. - * - * @since 1.6 - */ - -public class GenericParser{ - - /** - * The Log to which all SAX event related logging calls will be made. - */ - protected static Log log = - LogFactory.getLog("org.apache.commons.digester.Digester.sax"); - - /** - * The JAXP 1.2 property required to set up the schema location. - */ - private static final String JAXP_SCHEMA_SOURCE = - "http://java.sun.com/xml/jaxp/properties/schemaSource"; - - /** - * The JAXP 1.2 property to set up the schemaLanguage used. - */ - protected static String JAXP_SCHEMA_LANGUAGE = - "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; - - /** - * Create a SAXParser configured to support XML Scheman and DTD - * @param properties parser specific properties/features - * @return an XML Schema/DTD enabled SAXParser - */ - public static SAXParser newSAXParser(Properties properties) - throws ParserConfigurationException, - SAXException, - SAXNotRecognizedException{ - - SAXParserFactory factory = - (SAXParserFactory)properties.get("SAXParserFactory"); - SAXParser parser = factory.newSAXParser(); - String schemaLocation = (String)properties.get("schemaLocation"); - String schemaLanguage = (String)properties.get("schemaLanguage"); - - try{ - if (schemaLocation != null) { - parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); - parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); - } - } catch (SAXNotRecognizedException e){ - log.info(parser.getClass().getName() + ": " - + e.getMessage() + " not supported."); - } - return parser; - } - +/* $Id: GenericParser.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; + +/** + * Create a SAXParser configured to support XML Schema and DTD. + * + * @since 1.6 + */ + +public class GenericParser{ + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected static Log log = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + /** + * The JAXP 1.2 property required to set up the schema location. + */ + private static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + /** + * The JAXP 1.2 property to set up the schemaLanguage used. + */ + protected static String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + /** + * Create a SAXParser configured to support XML Scheman and DTD + * @param properties parser specific properties/features + * @return an XML Schema/DTD enabled SAXParser + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotRecognizedException{ + + SAXParserFactory factory = + (SAXParserFactory)properties.get("SAXParserFactory"); + SAXParser parser = factory.newSAXParser(); + String schemaLocation = (String)properties.get("schemaLocation"); + String schemaLanguage = (String)properties.get("schemaLanguage"); + + try{ + if (schemaLocation != null) { + parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); + } + } catch (SAXNotRecognizedException e){ + log.info(parser.getClass().getName() + ": " + + e.getMessage() + " not supported."); + } + return parser; + } + } \ No newline at end of file diff --git a/java/org/apache/tomcat/util/digester/NodeCreateRule.java b/java/org/apache/tomcat/util/digester/NodeCreateRule.java index cfff3d004..33a63bedf 100644 --- a/java/org/apache/tomcat/util/digester/NodeCreateRule.java +++ b/java/org/apache/tomcat/util/digester/NodeCreateRule.java @@ -1,428 +1,428 @@ -/* $Id: NodeCreateRule.java 299765 2004-08-31 23:52:52Z yoavs $ - * - * Copyright 2002-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.w3c.dom.Attr; -import org.w3c.dom.DOMException; -import org.w3c.dom.Document; -import org.w3c.dom.Element; -import org.w3c.dom.Node; -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; -import org.xml.sax.XMLReader; -import org.xml.sax.helpers.DefaultHandler; - - -/** - * A rule implementation that creates a DOM - * {@link org.w3c.dom.Node Node} containing the XML at the element that matched - * the rule. Two concrete types of nodes can be created by this rule: - *
          - *
        • the default is to create an {@link org.w3c.dom.Element Element} node. - * The created element will correspond to the element that matched the rule, - * containing all XML content underneath that element.
        • - *
        • alternatively, this rule can create nodes of type - * {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain - * only the XML content under the element the rule was trigged on.
        • - *
        - * The created node will be normalized, meaning it will not contain text nodes - * that only contain white space characters. - * - - * - *

        The created Node will be pushed on Digester's object stack - * when done. To use it in the context of another DOM - * {@link org.w3c.dom.Document Document}, it must be imported first, using the - * Document method - * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}. - *

        - * - *

        Important Note: This is implemented by replacing the SAX - * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by - * Digester, and resetting it when the matched element is closed. As a side - * effect, rules that would match XML nodes under the element that matches - * a NodeCreateRule will never be triggered by Digester, which - * usually is the behavior one would expect.

        - * - *

        Note that the current implementation does not set the namespace prefixes - * in the exported nodes. The (usually more important) namespace URIs are set, - * of course.

        - * - * @since Digester 1.4 - */ - -public class NodeCreateRule extends Rule { - - - // ---------------------------------------------------------- Inner Classes - - - /** - * The SAX content handler that does all the actual work of assembling the - * DOM node tree from the SAX events. - */ - private class NodeBuilder - extends DefaultHandler { - - - // ------------------------------------------------------- Constructors - - - /** - * Constructor. - * - *

        Stores the content handler currently used by Digester so it can - * be reset when done, and initializes the DOM objects needed to - * build the node.

        - * - * @param doc the document to use to create nodes - * @param root the root node - * @throws ParserConfigurationException if the DocumentBuilderFactory - * could not be instantiated - * @throws SAXException if the XMLReader could not be instantiated by - * Digester (should not happen) - */ - public NodeBuilder(Document doc, Node root) - throws ParserConfigurationException, SAXException { - - this.doc = doc; - this.root = root; - this.top = root; - - oldContentHandler = digester.getXMLReader().getContentHandler(); - - } - - - // ------------------------------------------------- Instance Variables - - - /** - * The content handler used by Digester before it was set to this - * content handler. - */ - protected ContentHandler oldContentHandler = null; - - - /** - * Depth of the current node, relative to the element where the content - * handler was put into action. - */ - protected int depth = 0; - - - /** - * A DOM Document used to create the various Node instances. - */ - protected Document doc = null; - - - /** - * The DOM node that will be pushed on Digester's stack. - */ - protected Node root = null; - - - /** - * The current top DOM mode. - */ - protected Node top = null; - - - // --------------------------------------------- ContentHandler Methods - - - /** - * Appends a {@link org.w3c.dom.Text Text} node to the current node. - * - * @param ch the characters from the XML document - * @param start the start position in the array - * @param length the number of characters to read from the array - * @throws SAXException if the DOM implementation throws an exception - */ - public void characters(char[] ch, int start, int length) - throws SAXException { - - try { - String str = new String(ch, start, length); - if (str.trim().length() > 0) { - top.appendChild(doc.createTextNode(str)); - } - } catch (DOMException e) { - throw new SAXException(e.getMessage()); - } - - } - - - /** - * Checks whether control needs to be returned to Digester. - * - * @param namespaceURI the namespace URI - * @param localName the local name - * @param qName the qualified (prefixed) name - * @throws SAXException if the DOM implementation throws an exception - */ - public void endElement(String namespaceURI, String localName, - String qName) - throws SAXException { - - try { - if (depth == 0) { - getDigester().getXMLReader().setContentHandler( - oldContentHandler); - getDigester().push(root); - getDigester().endElement(namespaceURI, localName, qName); - } - - top = top.getParentNode(); - depth--; - } catch (DOMException e) { - throw new SAXException(e.getMessage()); - } - - } - - - /** - * Adds a new - * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to - * the current node. - * - * @param target the processing instruction target - * @param data the processing instruction data, or null if none was - * supplied - * @throws SAXException if the DOM implementation throws an exception - */ - public void processingInstruction(String target, String data) - throws SAXException { - - try { - top.appendChild(doc.createProcessingInstruction(target, data)); - } catch (DOMException e) { - throw new SAXException(e.getMessage()); - } - - } - - - /** - * Adds a new child {@link org.w3c.dom.Element Element} to the current - * node. - * - * @param namespaceURI the namespace URI - * @param localName the local name - * @param qName the qualified (prefixed) name - * @param atts the list of attributes - * @throws SAXException if the DOM implementation throws an exception - */ - public void startElement(String namespaceURI, String localName, - String qName, Attributes atts) - throws SAXException { - - try { - Node previousTop = top; - if ((localName == null) || (localName.length() == 0)) { - top = doc.createElement(qName); - } else { - top = doc.createElementNS(namespaceURI, localName); - } - for (int i = 0; i < atts.getLength(); i++) { - Attr attr = null; - if ((atts.getLocalName(i) == null) || - (atts.getLocalName(i).length() == 0)) { - attr = doc.createAttribute(atts.getQName(i)); - attr.setNodeValue(atts.getValue(i)); - ((Element)top).setAttributeNode(attr); - } else { - attr = doc.createAttributeNS(atts.getURI(i), - atts.getLocalName(i)); - attr.setNodeValue(atts.getValue(i)); - ((Element)top).setAttributeNodeNS(attr); - } - } - previousTop.appendChild(top); - depth++; - } catch (DOMException e) { - throw new SAXException(e.getMessage()); - } - - } - - } - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor. Creates an instance of this rule that will create a - * DOM {@link org.w3c.dom.Element Element}. - */ - public NodeCreateRule() throws ParserConfigurationException { - - this(Node.ELEMENT_NODE); - - } - - - /** - * Constructor. Creates an instance of this rule that will create a DOM - * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP - * DocumentBuilder that should be used when constructing the - * node tree. - * - * @param documentBuilder the JAXP DocumentBuilder to use - */ - public NodeCreateRule(DocumentBuilder documentBuilder) { - - this(Node.ELEMENT_NODE, documentBuilder); - - } - - - /** - * Constructor. Creates an instance of this rule that will create either a - * DOM {@link org.w3c.dom.Element Element} or a DOM - * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the - * value of the nodeType parameter. - * - * @param nodeType the type of node to create, which can be either - * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or - * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} - * @throws IllegalArgumentException if the node type is not supported - */ - public NodeCreateRule(int nodeType) throws ParserConfigurationException { - - this(nodeType, - DocumentBuilderFactory.newInstance().newDocumentBuilder()); - - } - - - /** - * Constructor. Creates an instance of this rule that will create either a - * DOM {@link org.w3c.dom.Element Element} or a DOM - * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the - * value of the nodeType parameter. This constructor lets you - * specify the JAXP DocumentBuilder that should be used when - * constructing the node tree. - * - * @param nodeType the type of node to create, which can be either - * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or - * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} - * @param documentBuilder the JAXP DocumentBuilder to use - * @throws IllegalArgumentException if the node type is not supported - */ - public NodeCreateRule(int nodeType, DocumentBuilder documentBuilder) { - - if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) || - (nodeType == Node.ELEMENT_NODE))) { - throw new IllegalArgumentException( - "Can only create nodes of type DocumentFragment and Element"); - } - this.nodeType = nodeType; - this.documentBuilder = documentBuilder; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The JAXP DocumentBuilder to use. - */ - private DocumentBuilder documentBuilder = null; - - - /** - * The type of the node that should be created. Must be one of the - * constants defined in {@link org.w3c.dom.Node Node}, but currently only - * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and - * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} - * are allowed values. - */ - private int nodeType = Node.ELEMENT_NODE; - - - // ----------------------------------------------------------- Rule Methods - - - /** - * Implemented to replace the content handler currently in use by a - * NodeBuilder. - * - * @param namespaceURI the namespace URI of the matching element, or an - * empty string if the parser is not namespace aware or the element has - * no namespace - * @param name the local name if the parser is namespace aware, or just - * the element name otherwise - * @param attributes The attribute list of this element - * @throws Exception indicates a JAXP configuration problem - */ - public void begin(String namespaceURI, String name, Attributes attributes) - throws Exception { - - XMLReader xmlReader = getDigester().getXMLReader(); - Document doc = documentBuilder.newDocument(); - NodeBuilder builder = null; - if (nodeType == Node.ELEMENT_NODE) { - Element element = null; - if (getDigester().getNamespaceAware()) { - element = - doc.createElementNS(namespaceURI, name); - for (int i = 0; i < attributes.getLength(); i++) { - element.setAttributeNS(attributes.getURI(i), - attributes.getLocalName(i), - attributes.getValue(i)); - } - } else { - element = doc.createElement(name); - for (int i = 0; i < attributes.getLength(); i++) { - element.setAttribute(attributes.getQName(i), - attributes.getValue(i)); - } - } - builder = new NodeBuilder(doc, element); - } else { - builder = new NodeBuilder(doc, doc.createDocumentFragment()); - } - xmlReader.setContentHandler(builder); - - } - - - /** - * Pop the Node off the top of the stack. - */ - public void end() throws Exception { - - Object top = digester.pop(); - - } - - -} +/* $Id: NodeCreateRule.java 299765 2004-08-31 23:52:52Z yoavs $ + * + * Copyright 2002-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Attr; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + + +/** + * A rule implementation that creates a DOM + * {@link org.w3c.dom.Node Node} containing the XML at the element that matched + * the rule. Two concrete types of nodes can be created by this rule: + *
          + *
        • the default is to create an {@link org.w3c.dom.Element Element} node. + * The created element will correspond to the element that matched the rule, + * containing all XML content underneath that element.
        • + *
        • alternatively, this rule can create nodes of type + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, which will contain + * only the XML content under the element the rule was trigged on.
        • + *
        + * The created node will be normalized, meaning it will not contain text nodes + * that only contain white space characters. + * + + * + *

        The created Node will be pushed on Digester's object stack + * when done. To use it in the context of another DOM + * {@link org.w3c.dom.Document Document}, it must be imported first, using the + * Document method + * {@link org.w3c.dom.Document#importNode(org.w3c.dom.Node, boolean) importNode()}. + *

        + * + *

        Important Note: This is implemented by replacing the SAX + * {@link org.xml.sax.ContentHandler ContentHandler} in the parser used by + * Digester, and resetting it when the matched element is closed. As a side + * effect, rules that would match XML nodes under the element that matches + * a NodeCreateRule will never be triggered by Digester, which + * usually is the behavior one would expect.

        + * + *

        Note that the current implementation does not set the namespace prefixes + * in the exported nodes. The (usually more important) namespace URIs are set, + * of course.

        + * + * @since Digester 1.4 + */ + +public class NodeCreateRule extends Rule { + + + // ---------------------------------------------------------- Inner Classes + + + /** + * The SAX content handler that does all the actual work of assembling the + * DOM node tree from the SAX events. + */ + private class NodeBuilder + extends DefaultHandler { + + + // ------------------------------------------------------- Constructors + + + /** + * Constructor. + * + *

        Stores the content handler currently used by Digester so it can + * be reset when done, and initializes the DOM objects needed to + * build the node.

        + * + * @param doc the document to use to create nodes + * @param root the root node + * @throws ParserConfigurationException if the DocumentBuilderFactory + * could not be instantiated + * @throws SAXException if the XMLReader could not be instantiated by + * Digester (should not happen) + */ + public NodeBuilder(Document doc, Node root) + throws ParserConfigurationException, SAXException { + + this.doc = doc; + this.root = root; + this.top = root; + + oldContentHandler = digester.getXMLReader().getContentHandler(); + + } + + + // ------------------------------------------------- Instance Variables + + + /** + * The content handler used by Digester before it was set to this + * content handler. + */ + protected ContentHandler oldContentHandler = null; + + + /** + * Depth of the current node, relative to the element where the content + * handler was put into action. + */ + protected int depth = 0; + + + /** + * A DOM Document used to create the various Node instances. + */ + protected Document doc = null; + + + /** + * The DOM node that will be pushed on Digester's stack. + */ + protected Node root = null; + + + /** + * The current top DOM mode. + */ + protected Node top = null; + + + // --------------------------------------------- ContentHandler Methods + + + /** + * Appends a {@link org.w3c.dom.Text Text} node to the current node. + * + * @param ch the characters from the XML document + * @param start the start position in the array + * @param length the number of characters to read from the array + * @throws SAXException if the DOM implementation throws an exception + */ + public void characters(char[] ch, int start, int length) + throws SAXException { + + try { + String str = new String(ch, start, length); + if (str.trim().length() > 0) { + top.appendChild(doc.createTextNode(str)); + } + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + + /** + * Checks whether control needs to be returned to Digester. + * + * @param namespaceURI the namespace URI + * @param localName the local name + * @param qName the qualified (prefixed) name + * @throws SAXException if the DOM implementation throws an exception + */ + public void endElement(String namespaceURI, String localName, + String qName) + throws SAXException { + + try { + if (depth == 0) { + getDigester().getXMLReader().setContentHandler( + oldContentHandler); + getDigester().push(root); + getDigester().endElement(namespaceURI, localName, qName); + } + + top = top.getParentNode(); + depth--; + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + + /** + * Adds a new + * {@link org.w3c.dom.ProcessingInstruction ProcessingInstruction} to + * the current node. + * + * @param target the processing instruction target + * @param data the processing instruction data, or null if none was + * supplied + * @throws SAXException if the DOM implementation throws an exception + */ + public void processingInstruction(String target, String data) + throws SAXException { + + try { + top.appendChild(doc.createProcessingInstruction(target, data)); + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + + /** + * Adds a new child {@link org.w3c.dom.Element Element} to the current + * node. + * + * @param namespaceURI the namespace URI + * @param localName the local name + * @param qName the qualified (prefixed) name + * @param atts the list of attributes + * @throws SAXException if the DOM implementation throws an exception + */ + public void startElement(String namespaceURI, String localName, + String qName, Attributes atts) + throws SAXException { + + try { + Node previousTop = top; + if ((localName == null) || (localName.length() == 0)) { + top = doc.createElement(qName); + } else { + top = doc.createElementNS(namespaceURI, localName); + } + for (int i = 0; i < atts.getLength(); i++) { + Attr attr = null; + if ((atts.getLocalName(i) == null) || + (atts.getLocalName(i).length() == 0)) { + attr = doc.createAttribute(atts.getQName(i)); + attr.setNodeValue(atts.getValue(i)); + ((Element)top).setAttributeNode(attr); + } else { + attr = doc.createAttributeNS(atts.getURI(i), + atts.getLocalName(i)); + attr.setNodeValue(atts.getValue(i)); + ((Element)top).setAttributeNodeNS(attr); + } + } + previousTop.appendChild(top); + depth++; + } catch (DOMException e) { + throw new SAXException(e.getMessage()); + } + + } + + } + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor. Creates an instance of this rule that will create a + * DOM {@link org.w3c.dom.Element Element}. + */ + public NodeCreateRule() throws ParserConfigurationException { + + this(Node.ELEMENT_NODE); + + } + + + /** + * Constructor. Creates an instance of this rule that will create a DOM + * {@link org.w3c.dom.Element Element}, but lets you specify the JAXP + * DocumentBuilder that should be used when constructing the + * node tree. + * + * @param documentBuilder the JAXP DocumentBuilder to use + */ + public NodeCreateRule(DocumentBuilder documentBuilder) { + + this(Node.ELEMENT_NODE, documentBuilder); + + } + + + /** + * Constructor. Creates an instance of this rule that will create either a + * DOM {@link org.w3c.dom.Element Element} or a DOM + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the + * value of the nodeType parameter. + * + * @param nodeType the type of node to create, which can be either + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * @throws IllegalArgumentException if the node type is not supported + */ + public NodeCreateRule(int nodeType) throws ParserConfigurationException { + + this(nodeType, + DocumentBuilderFactory.newInstance().newDocumentBuilder()); + + } + + + /** + * Constructor. Creates an instance of this rule that will create either a + * DOM {@link org.w3c.dom.Element Element} or a DOM + * {@link org.w3c.dom.DocumentFragment DocumentFragment}, depending on the + * value of the nodeType parameter. This constructor lets you + * specify the JAXP DocumentBuilder that should be used when + * constructing the node tree. + * + * @param nodeType the type of node to create, which can be either + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} or + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * @param documentBuilder the JAXP DocumentBuilder to use + * @throws IllegalArgumentException if the node type is not supported + */ + public NodeCreateRule(int nodeType, DocumentBuilder documentBuilder) { + + if (!((nodeType == Node.DOCUMENT_FRAGMENT_NODE) || + (nodeType == Node.ELEMENT_NODE))) { + throw new IllegalArgumentException( + "Can only create nodes of type DocumentFragment and Element"); + } + this.nodeType = nodeType; + this.documentBuilder = documentBuilder; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The JAXP DocumentBuilder to use. + */ + private DocumentBuilder documentBuilder = null; + + + /** + * The type of the node that should be created. Must be one of the + * constants defined in {@link org.w3c.dom.Node Node}, but currently only + * {@link org.w3c.dom.Node#ELEMENT_NODE Node.ELEMENT_NODE} and + * {@link org.w3c.dom.Node#DOCUMENT_FRAGMENT_NODE Node.DOCUMENT_FRAGMENT_NODE} + * are allowed values. + */ + private int nodeType = Node.ELEMENT_NODE; + + + // ----------------------------------------------------------- Rule Methods + + + /** + * Implemented to replace the content handler currently in use by a + * NodeBuilder. + * + * @param namespaceURI the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list of this element + * @throws Exception indicates a JAXP configuration problem + */ + public void begin(String namespaceURI, String name, Attributes attributes) + throws Exception { + + XMLReader xmlReader = getDigester().getXMLReader(); + Document doc = documentBuilder.newDocument(); + NodeBuilder builder = null; + if (nodeType == Node.ELEMENT_NODE) { + Element element = null; + if (getDigester().getNamespaceAware()) { + element = + doc.createElementNS(namespaceURI, name); + for (int i = 0; i < attributes.getLength(); i++) { + element.setAttributeNS(attributes.getURI(i), + attributes.getLocalName(i), + attributes.getValue(i)); + } + } else { + element = doc.createElement(name); + for (int i = 0; i < attributes.getLength(); i++) { + element.setAttribute(attributes.getQName(i), + attributes.getValue(i)); + } + } + builder = new NodeBuilder(doc, element); + } else { + builder = new NodeBuilder(doc, doc.createDocumentFragment()); + } + xmlReader.setContentHandler(builder); + + } + + + /** + * Pop the Node off the top of the stack. + */ + public void end() throws Exception { + + Object top = digester.pop(); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java index ae220b806..de8d2eeaf 100644 --- a/java/org/apache/tomcat/util/digester/ObjectCreateRule.java +++ b/java/org/apache/tomcat/util/digester/ObjectCreateRule.java @@ -1,241 +1,241 @@ -/* $Id: ObjectCreateRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - - -/** - * Rule implementation that creates a new object and pushes it - * onto the object stack. When the element is complete, the - * object will be popped - */ - -public class ObjectCreateRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct an object create rule with the specified class name. - * - * @param digester The associated Digester - * @param className Java class name of the object to be created - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #ObjectCreateRule(String className)} instead. - */ - public ObjectCreateRule(Digester digester, String className) { - - this(className); - - } - - - /** - * Construct an object create rule with the specified class. - * - * @param digester The associated Digester - * @param clazz Java class name of the object to be created - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #ObjectCreateRule(Class clazz)} instead. - */ - public ObjectCreateRule(Digester digester, Class clazz) { - - this(clazz); - - } - - - /** - * Construct an object create rule with the specified class name and an - * optional attribute name containing an override. - * - * @param digester The associated Digester - * @param className Java class name of the object to be created - * @param attributeName Attribute name which, if present, contains an - * override of the class name to create - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #ObjectCreateRule(String className, String attributeName)} instead. - */ - public ObjectCreateRule(Digester digester, String className, - String attributeName) { - - this (className, attributeName); - - } - - - /** - * Construct an object create rule with the specified class and an - * optional attribute name containing an override. - * - * @param digester The associated Digester - * @param attributeName Attribute name which, if present, contains an - * @param clazz Java class name of the object to be created - * override of the class name to create - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #ObjectCreateRule(String attributeName, Class clazz)} instead. - */ - public ObjectCreateRule(Digester digester, - String attributeName, - Class clazz) { - - this(attributeName, clazz); - - } - - /** - * Construct an object create rule with the specified class name. - * - * @param className Java class name of the object to be created - */ - public ObjectCreateRule(String className) { - - this(className, (String) null); - - } - - - /** - * Construct an object create rule with the specified class. - * - * @param clazz Java class name of the object to be created - */ - public ObjectCreateRule(Class clazz) { - - this(clazz.getName(), (String) null); - - } - - - /** - * Construct an object create rule with the specified class name and an - * optional attribute name containing an override. - * - * @param className Java class name of the object to be created - * @param attributeName Attribute name which, if present, contains an - * override of the class name to create - */ - public ObjectCreateRule(String className, - String attributeName) { - - this.className = className; - this.attributeName = attributeName; - - } - - - /** - * Construct an object create rule with the specified class and an - * optional attribute name containing an override. - * - * @param attributeName Attribute name which, if present, contains an - * @param clazz Java class name of the object to be created - * override of the class name to create - */ - public ObjectCreateRule(String attributeName, - Class clazz) { - - this(clazz.getName(), attributeName); - - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The attribute containing an override class name if it is present. - */ - protected String attributeName = null; - - - /** - * The Java class name of the object to be created. - */ - protected String className = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the beginning of this element. - * - * @param attributes The attribute list of this element - */ - public void begin(Attributes attributes) throws Exception { - - // Identify the name of the class to instantiate - String realClassName = className; - if (attributeName != null) { - String value = attributes.getValue(attributeName); - if (value != null) { - realClassName = value; - } - } - if (digester.log.isDebugEnabled()) { - digester.log.debug("[ObjectCreateRule]{" + digester.match + - "}New " + realClassName); - } - - // Instantiate the new object and push it on the context stack - Class clazz = digester.getClassLoader().loadClass(realClassName); - Object instance = clazz.newInstance(); - digester.push(instance); - - } - - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - Object top = digester.pop(); - if (digester.log.isDebugEnabled()) { - digester.log.debug("[ObjectCreateRule]{" + digester.match + - "} Pop " + top.getClass().getName()); - } - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ObjectCreateRule["); - sb.append("className="); - sb.append(className); - sb.append(", attributeName="); - sb.append(attributeName); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: ObjectCreateRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + + +/** + * Rule implementation that creates a new object and pushes it + * onto the object stack. When the element is complete, the + * object will be popped + */ + +public class ObjectCreateRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct an object create rule with the specified class name. + * + * @param digester The associated Digester + * @param className Java class name of the object to be created + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String className)} instead. + */ + public ObjectCreateRule(Digester digester, String className) { + + this(className); + + } + + + /** + * Construct an object create rule with the specified class. + * + * @param digester The associated Digester + * @param clazz Java class name of the object to be created + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(Class clazz)} instead. + */ + public ObjectCreateRule(Digester digester, Class clazz) { + + this(clazz); + + } + + + /** + * Construct an object create rule with the specified class name and an + * optional attribute name containing an override. + * + * @param digester The associated Digester + * @param className Java class name of the object to be created + * @param attributeName Attribute name which, if present, contains an + * override of the class name to create + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String className, String attributeName)} instead. + */ + public ObjectCreateRule(Digester digester, String className, + String attributeName) { + + this (className, attributeName); + + } + + + /** + * Construct an object create rule with the specified class and an + * optional attribute name containing an override. + * + * @param digester The associated Digester + * @param attributeName Attribute name which, if present, contains an + * @param clazz Java class name of the object to be created + * override of the class name to create + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #ObjectCreateRule(String attributeName, Class clazz)} instead. + */ + public ObjectCreateRule(Digester digester, + String attributeName, + Class clazz) { + + this(attributeName, clazz); + + } + + /** + * Construct an object create rule with the specified class name. + * + * @param className Java class name of the object to be created + */ + public ObjectCreateRule(String className) { + + this(className, (String) null); + + } + + + /** + * Construct an object create rule with the specified class. + * + * @param clazz Java class name of the object to be created + */ + public ObjectCreateRule(Class clazz) { + + this(clazz.getName(), (String) null); + + } + + + /** + * Construct an object create rule with the specified class name and an + * optional attribute name containing an override. + * + * @param className Java class name of the object to be created + * @param attributeName Attribute name which, if present, contains an + * override of the class name to create + */ + public ObjectCreateRule(String className, + String attributeName) { + + this.className = className; + this.attributeName = attributeName; + + } + + + /** + * Construct an object create rule with the specified class and an + * optional attribute name containing an override. + * + * @param attributeName Attribute name which, if present, contains an + * @param clazz Java class name of the object to be created + * override of the class name to create + */ + public ObjectCreateRule(String attributeName, + Class clazz) { + + this(clazz.getName(), attributeName); + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The attribute containing an override class name if it is present. + */ + protected String attributeName = null; + + + /** + * The Java class name of the object to be created. + */ + protected String className = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + public void begin(Attributes attributes) throws Exception { + + // Identify the name of the class to instantiate + String realClassName = className; + if (attributeName != null) { + String value = attributes.getValue(attributeName); + if (value != null) { + realClassName = value; + } + } + if (digester.log.isDebugEnabled()) { + digester.log.debug("[ObjectCreateRule]{" + digester.match + + "}New " + realClassName); + } + + // Instantiate the new object and push it on the context stack + Class clazz = digester.getClassLoader().loadClass(realClassName); + Object instance = clazz.newInstance(); + digester.push(instance); + + } + + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + Object top = digester.pop(); + if (digester.log.isDebugEnabled()) { + digester.log.debug("[ObjectCreateRule]{" + digester.match + + "} Pop " + top.getClass().getName()); + } + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ObjectCreateRule["); + sb.append("className="); + sb.append(className); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java b/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java index f008520c8..6600ab8ca 100644 --- a/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java +++ b/java/org/apache/tomcat/util/digester/ObjectCreationFactory.java @@ -1,59 +1,59 @@ -/* $Id: ObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - -/** - *

        Interface for use with {@link FactoryCreateRule}. - * The rule calls {@link #createObject} to create an object - * to be pushed onto the Digester stack - * whenever it is matched.

        - * - *

        {@link AbstractObjectCreationFactory} is an abstract - * implementation suitable for creating anonymous - * ObjectCreationFactory implementations. - */ -public interface ObjectCreationFactory { - - /** - *

        Factory method called by {@link FactoryCreateRule} to supply an - * object based on the element's attributes. - * - * @param attributes the element's attributes - * - * @throws Exception any exception thrown will be propagated upwards - */ - public Object createObject(Attributes attributes) throws Exception; - - /** - *

        Returns the {@link Digester} that was set by the - * {@link FactoryCreateRule} upon initialization. - */ - public Digester getDigester(); - - /** - *

        Set the {@link Digester} to allow the implementation to do logging, - * classloading based on the digester's classloader, etc. - * - * @param digester parent Digester object - */ - public void setDigester(Digester digester); - -} +/* $Id: ObjectCreationFactory.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + +/** + *

        Interface for use with {@link FactoryCreateRule}. + * The rule calls {@link #createObject} to create an object + * to be pushed onto the Digester stack + * whenever it is matched.

        + * + *

        {@link AbstractObjectCreationFactory} is an abstract + * implementation suitable for creating anonymous + * ObjectCreationFactory implementations. + */ +public interface ObjectCreationFactory { + + /** + *

        Factory method called by {@link FactoryCreateRule} to supply an + * object based on the element's attributes. + * + * @param attributes the element's attributes + * + * @throws Exception any exception thrown will be propagated upwards + */ + public Object createObject(Attributes attributes) throws Exception; + + /** + *

        Returns the {@link Digester} that was set by the + * {@link FactoryCreateRule} upon initialization. + */ + public Digester getDigester(); + + /** + *

        Set the {@link Digester} to allow the implementation to do logging, + * classloading based on the digester's classloader, etc. + * + * @param digester parent Digester object + */ + public void setDigester(Digester digester); + +} diff --git a/java/org/apache/tomcat/util/digester/ObjectParamRule.java b/java/org/apache/tomcat/util/digester/ObjectParamRule.java index 0866a78cc..a9f108cd0 100644 --- a/java/org/apache/tomcat/util/digester/ObjectParamRule.java +++ b/java/org/apache/tomcat/util/digester/ObjectParamRule.java @@ -1,124 +1,124 @@ -/* $Id: ObjectParamRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2002-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import org.xml.sax.Attributes; - -/** - *

        Rule implementation that saves a parameter for use by a surrounding - * CallMethodRule.

        - * - *

        This parameter may be: - *

          - *
        • an arbitrary Object defined programatically, assigned when the element pattern associated with the Rule is matched - * See {@link #ObjectParamRule(int paramIndex, Object param)} - *
        • an arbitrary Object defined programatically, assigned if the element pattern AND specified attribute name are matched - * See {@link #ObjectParamRule(int paramIndex, String attributeName, Object param)} - *
        - *

        - * - * @since 1.4 - */ - -public class ObjectParamRule extends Rule { - // ----------------------------------------------------------- Constructors - /** - * Construct a "call parameter" rule that will save the given Object as - * the parameter value. - * - * @param paramIndex The zero-relative parameter number - * @param param the parameter to pass along - */ - public ObjectParamRule(int paramIndex, Object param) { - this(paramIndex, null, param); - } - - - /** - * Construct a "call parameter" rule that will save the given Object as - * the parameter value, provided that the specified attribute exists. - * - * @param paramIndex The zero-relative parameter number - * @param attributeName The name of the attribute to match - * @param param the parameter to pass along - */ - public ObjectParamRule(int paramIndex, String attributeName, Object param) { - this.paramIndex = paramIndex; - this.attributeName = attributeName; - this.param = param; - } - - - // ----------------------------------------------------- Instance Variables - - /** - * The attribute which we are attempting to match - */ - protected String attributeName = null; - - /** - * The zero-relative index of the parameter we are saving. - */ - protected int paramIndex = 0; - - /** - * The parameter we wish to pass to the method call - */ - protected Object param = null; - - - // --------------------------------------------------------- Public Methods - - /** - * Process the start of this element. - * - * @param attributes The attribute list for this element - */ - public void begin(String namespace, String name, - Attributes attributes) throws Exception { - Object anAttribute = null; - Object parameters[] = (Object[]) digester.peekParams(); - - if (attributeName != null) { - anAttribute = attributes.getValue(attributeName); - if(anAttribute != null) { - parameters[paramIndex] = param; - } - // note -- if attributeName != null and anAttribute == null, this rule - // will pass null as its parameter! - }else{ - parameters[paramIndex] = param; - } - } - - /** - * Render a printable version of this Rule. - */ - public String toString() { - StringBuffer sb = new StringBuffer("ObjectParamRule["); - sb.append("paramIndex="); - sb.append(paramIndex); - sb.append(", attributeName="); - sb.append(attributeName); - sb.append(", param="); - sb.append(param); - sb.append("]"); - return (sb.toString()); - } -} +/* $Id: ObjectParamRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2002-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import org.xml.sax.Attributes; + +/** + *

        Rule implementation that saves a parameter for use by a surrounding + * CallMethodRule.

        + * + *

        This parameter may be: + *

          + *
        • an arbitrary Object defined programatically, assigned when the element pattern associated with the Rule is matched + * See {@link #ObjectParamRule(int paramIndex, Object param)} + *
        • an arbitrary Object defined programatically, assigned if the element pattern AND specified attribute name are matched + * See {@link #ObjectParamRule(int paramIndex, String attributeName, Object param)} + *
        + *

        + * + * @since 1.4 + */ + +public class ObjectParamRule extends Rule { + // ----------------------------------------------------------- Constructors + /** + * Construct a "call parameter" rule that will save the given Object as + * the parameter value. + * + * @param paramIndex The zero-relative parameter number + * @param param the parameter to pass along + */ + public ObjectParamRule(int paramIndex, Object param) { + this(paramIndex, null, param); + } + + + /** + * Construct a "call parameter" rule that will save the given Object as + * the parameter value, provided that the specified attribute exists. + * + * @param paramIndex The zero-relative parameter number + * @param attributeName The name of the attribute to match + * @param param the parameter to pass along + */ + public ObjectParamRule(int paramIndex, String attributeName, Object param) { + this.paramIndex = paramIndex; + this.attributeName = attributeName; + this.param = param; + } + + + // ----------------------------------------------------- Instance Variables + + /** + * The attribute which we are attempting to match + */ + protected String attributeName = null; + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + /** + * The parameter we wish to pass to the method call + */ + protected Object param = null; + + + // --------------------------------------------------------- Public Methods + + /** + * Process the start of this element. + * + * @param attributes The attribute list for this element + */ + public void begin(String namespace, String name, + Attributes attributes) throws Exception { + Object anAttribute = null; + Object parameters[] = (Object[]) digester.peekParams(); + + if (attributeName != null) { + anAttribute = attributes.getValue(attributeName); + if(anAttribute != null) { + parameters[paramIndex] = param; + } + // note -- if attributeName != null and anAttribute == null, this rule + // will pass null as its parameter! + }else{ + parameters[paramIndex] = param; + } + } + + /** + * Render a printable version of this Rule. + */ + public String toString() { + StringBuffer sb = new StringBuffer("ObjectParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append(", attributeName="); + sb.append(attributeName); + sb.append(", param="); + sb.append(param); + sb.append("]"); + return (sb.toString()); + } +} diff --git a/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java b/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java index 25242f2eb..ddfbbac27 100644 --- a/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java +++ b/java/org/apache/tomcat/util/digester/ParserFeatureSetterFactory.java @@ -1,74 +1,74 @@ -/* $Id: ParserFeatureSetterFactory.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import java.util.Properties; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; - -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotRecognizedException; -import org.xml.sax.SAXNotSupportedException; - -/** - * Creates a SAXParser based on the underlying parser. - * Allows logical properties depending on logical parser versions - * to be set. - * - * @since 1.6 - */ -public class ParserFeatureSetterFactory{ - - /** - * true is Xerces is used. - */ - private static boolean isXercesUsed; - - static { - try{ - // Use reflection to avoid a build dependency with Xerces. - Class versionClass = - Class.forName("org.apache.xerces.impl.Version"); - isXercesUsed = true; - } catch (Exception ex){ - isXercesUsed = false; - } - } - - /** - * Create a new SAXParser - * @param properties (logical) properties to be set on parser - * @return a SAXParser configured based on the underlying - * parser implementation. - */ - public static SAXParser newSAXParser(Properties properties) - throws ParserConfigurationException, - SAXException, - SAXNotRecognizedException, - SAXNotSupportedException { - - if (isXercesUsed){ - return XercesParser.newSAXParser(properties); - } else { - return GenericParser.newSAXParser(properties); - } - } - +/* $Id: ParserFeatureSetterFactory.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; + +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * Creates a SAXParser based on the underlying parser. + * Allows logical properties depending on logical parser versions + * to be set. + * + * @since 1.6 + */ +public class ParserFeatureSetterFactory{ + + /** + * true is Xerces is used. + */ + private static boolean isXercesUsed; + + static { + try{ + // Use reflection to avoid a build dependency with Xerces. + Class versionClass = + Class.forName("org.apache.xerces.impl.Version"); + isXercesUsed = true; + } catch (Exception ex){ + isXercesUsed = false; + } + } + + /** + * Create a new SAXParser + * @param properties (logical) properties to be set on parser + * @return a SAXParser configured based on the underlying + * parser implementation. + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotRecognizedException, + SAXNotSupportedException { + + if (isXercesUsed){ + return XercesParser.newSAXParser(properties); + } else { + return GenericParser.newSAXParser(properties); + } + } + } \ No newline at end of file diff --git a/java/org/apache/tomcat/util/digester/PathCallParamRule.java b/java/org/apache/tomcat/util/digester/PathCallParamRule.java index a2c831079..a29b80185 100644 --- a/java/org/apache/tomcat/util/digester/PathCallParamRule.java +++ b/java/org/apache/tomcat/util/digester/PathCallParamRule.java @@ -1,93 +1,93 @@ -/* $Id: PathCallParamRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - -/** - *

        Rule implementation that saves a parameter containing the - * Digester matching path for use by a surrounding - * CallMethodRule. This Rule is most useful when making - * extensive use of wildcards in rule patterns.

        - * - * @since 1.6 - */ - -public class PathCallParamRule extends Rule { - - // ----------------------------------------------------------- Constructors - - /** - * Construct a "call parameter" rule that will save the body text of this - * element as the parameter value. - * - * @param paramIndex The zero-relative parameter number - */ - public PathCallParamRule(int paramIndex) { - - this.paramIndex = paramIndex; - - } - - // ----------------------------------------------------- Instance Variables - - /** - * The zero-relative index of the parameter we are saving. - */ - protected int paramIndex = 0; - - // --------------------------------------------------------- Public Methods - - - /** - * Process the start of this element. - * - * @param namespace the namespace URI of the matching element, or an - * empty string if the parser is not namespace aware or the element has - * no namespace - * @param name the local name if the parser is namespace aware, or just - * the element name otherwise - * @param attributes The attribute list for this element - - */ - public void begin(String namespace, String name, Attributes attributes) throws Exception { - - String param = getDigester().getMatch(); - - if(param != null) { - Object parameters[] = (Object[]) digester.peekParams(); - parameters[paramIndex] = param; - } - - } - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("PathCallParamRule["); - sb.append("paramIndex="); - sb.append(paramIndex); - sb.append("]"); - return (sb.toString()); - - } -} +/* $Id: PathCallParamRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2003-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + +/** + *

        Rule implementation that saves a parameter containing the + * Digester matching path for use by a surrounding + * CallMethodRule. This Rule is most useful when making + * extensive use of wildcards in rule patterns.

        + * + * @since 1.6 + */ + +public class PathCallParamRule extends Rule { + + // ----------------------------------------------------------- Constructors + + /** + * Construct a "call parameter" rule that will save the body text of this + * element as the parameter value. + * + * @param paramIndex The zero-relative parameter number + */ + public PathCallParamRule(int paramIndex) { + + this.paramIndex = paramIndex; + + } + + // ----------------------------------------------------- Instance Variables + + /** + * The zero-relative index of the parameter we are saving. + */ + protected int paramIndex = 0; + + // --------------------------------------------------------- Public Methods + + + /** + * Process the start of this element. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list for this element + + */ + public void begin(String namespace, String name, Attributes attributes) throws Exception { + + String param = getDigester().getMatch(); + + if(param != null) { + Object parameters[] = (Object[]) digester.peekParams(); + parameters[paramIndex] = param; + } + + } + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("PathCallParamRule["); + sb.append("paramIndex="); + sb.append(paramIndex); + sb.append("]"); + return (sb.toString()); + + } +} diff --git a/java/org/apache/tomcat/util/digester/Rule.java b/java/org/apache/tomcat/util/digester/Rule.java index d512c036f..4e5dab0cf 100644 --- a/java/org/apache/tomcat/util/digester/Rule.java +++ b/java/org/apache/tomcat/util/digester/Rule.java @@ -1,244 +1,244 @@ -/* $Id: Rule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.xml.sax.Attributes; - - -/** - * Concrete implementations of this class implement actions to be taken when - * a corresponding nested pattern of XML elements has been matched. - */ - -public abstract class Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Constructor sets the associated Digester. - * - * @param digester The digester with which this rule is associated - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. Use {@link #Rule()} instead. - */ - public Rule(Digester digester) { - - super(); - setDigester(digester); - - } - - /** - *

        Base constructor. - * Now the digester will be set when the rule is added.

        - */ - public Rule() {} - - - // ----------------------------------------------------- Instance Variables - - - /** - * The Digester with which this Rule is associated. - */ - protected Digester digester = null; - - - /** - * The namespace URI for which this Rule is relevant, if any. - */ - protected String namespaceURI = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Digester with which this Rule is associated. - */ - public Digester getDigester() { - - return (this.digester); - - } - - /** - * Set the Digester with which this Rule is associated. - */ - public void setDigester(Digester digester) { - - this.digester = digester; - - } - - /** - * Return the namespace URI for which this Rule is relevant, if any. - */ - public String getNamespaceURI() { - - return (this.namespaceURI); - - } - - - /** - * Set the namespace URI for which this Rule is relevant, if any. - * - * @param namespaceURI Namespace URI for which this Rule is relevant, - * or null to match independent of namespace. - */ - public void setNamespaceURI(String namespaceURI) { - - this.namespaceURI = namespaceURI; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * This method is called when the beginning of a matching XML element - * is encountered. - * - * @param attributes The attribute list of this element - * @deprecated Use the {@link #begin(String,String,Attributes) begin} - * method with namespace and name - * parameters instead. - */ - public void begin(Attributes attributes) throws Exception { - - ; // The default implementation does nothing - - } - - - /** - * This method is called when the beginning of a matching XML element - * is encountered. The default implementation delegates to the deprecated - * method {@link #begin(Attributes) begin} without the - * namespace and name parameters, to retain - * backwards compatibility. - * - * @param namespace the namespace URI of the matching element, or an - * empty string if the parser is not namespace aware or the element has - * no namespace - * @param name the local name if the parser is namespace aware, or just - * the element name otherwise - * @param attributes The attribute list of this element - * @since Digester 1.4 - */ - public void begin(String namespace, String name, Attributes attributes) - throws Exception { - - begin(attributes); - - } - - - /** - * This method is called when the body of a matching XML element - * is encountered. If the element has no body, this method is - * not called at all. - * - * @param text The text of the body of this element - * @deprecated Use the {@link #body(String,String,String) body} method - * with namespace and name parameters - * instead. - */ - public void body(String text) throws Exception { - - ; // The default implementation does nothing - - } - - - /** - * This method is called when the body of a matching XML element is - * encountered. If the element has no body, this method is not called at - * all. The default implementation delegates to the deprecated method - * {@link #body(String) body} without the namespace and - * name parameters, to retain backwards compatibility. - * - * @param namespace the namespace URI of the matching element, or an - * empty string if the parser is not namespace aware or the element has - * no namespace - * @param name the local name if the parser is namespace aware, or just - * the element name otherwise - * @param text The text of the body of this element - * @since Digester 1.4 - */ - public void body(String namespace, String name, String text) - throws Exception { - - body(text); - - } - - - /** - * This method is called when the end of a matching XML element - * is encountered. - * - * @deprecated Use the {@link #end(String,String) end} method with - * namespace and name parameters instead. - */ - public void end() throws Exception { - - ; // The default implementation does nothing - - } - - - /** - * This method is called when the end of a matching XML element - * is encountered. The default implementation delegates to the deprecated - * method {@link #end end} without the - * namespace and name parameters, to retain - * backwards compatibility. - * - * @param namespace the namespace URI of the matching element, or an - * empty string if the parser is not namespace aware or the element has - * no namespace - * @param name the local name if the parser is namespace aware, or just - * the element name otherwise - * @since Digester 1.4 - */ - public void end(String namespace, String name) - throws Exception { - - end(); - - } - - - /** - * This method is called after all parsing methods have been - * called, to allow Rules to remove temporary data. - */ - public void finish() throws Exception { - - ; // The default implementation does nothing - - } - - -} +/* $Id: Rule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.xml.sax.Attributes; + + +/** + * Concrete implementations of this class implement actions to be taken when + * a corresponding nested pattern of XML elements has been matched. + */ + +public abstract class Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Constructor sets the associated Digester. + * + * @param digester The digester with which this rule is associated + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. Use {@link #Rule()} instead. + */ + public Rule(Digester digester) { + + super(); + setDigester(digester); + + } + + /** + *

        Base constructor. + * Now the digester will be set when the rule is added.

        + */ + public Rule() {} + + + // ----------------------------------------------------- Instance Variables + + + /** + * The Digester with which this Rule is associated. + */ + protected Digester digester = null; + + + /** + * The namespace URI for which this Rule is relevant, if any. + */ + protected String namespaceURI = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester with which this Rule is associated. + */ + public Digester getDigester() { + + return (this.digester); + + } + + /** + * Set the Digester with which this Rule is associated. + */ + public void setDigester(Digester digester) { + + this.digester = digester; + + } + + /** + * Return the namespace URI for which this Rule is relevant, if any. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + /** + * Set the namespace URI for which this Rule is relevant, if any. + * + * @param namespaceURI Namespace URI for which this Rule is relevant, + * or null to match independent of namespace. + */ + public void setNamespaceURI(String namespaceURI) { + + this.namespaceURI = namespaceURI; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * This method is called when the beginning of a matching XML element + * is encountered. + * + * @param attributes The attribute list of this element + * @deprecated Use the {@link #begin(String,String,Attributes) begin} + * method with namespace and name + * parameters instead. + */ + public void begin(Attributes attributes) throws Exception { + + ; // The default implementation does nothing + + } + + + /** + * This method is called when the beginning of a matching XML element + * is encountered. The default implementation delegates to the deprecated + * method {@link #begin(Attributes) begin} without the + * namespace and name parameters, to retain + * backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param attributes The attribute list of this element + * @since Digester 1.4 + */ + public void begin(String namespace, String name, Attributes attributes) + throws Exception { + + begin(attributes); + + } + + + /** + * This method is called when the body of a matching XML element + * is encountered. If the element has no body, this method is + * not called at all. + * + * @param text The text of the body of this element + * @deprecated Use the {@link #body(String,String,String) body} method + * with namespace and name parameters + * instead. + */ + public void body(String text) throws Exception { + + ; // The default implementation does nothing + + } + + + /** + * This method is called when the body of a matching XML element is + * encountered. If the element has no body, this method is not called at + * all. The default implementation delegates to the deprecated method + * {@link #body(String) body} without the namespace and + * name parameters, to retain backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @param text The text of the body of this element + * @since Digester 1.4 + */ + public void body(String namespace, String name, String text) + throws Exception { + + body(text); + + } + + + /** + * This method is called when the end of a matching XML element + * is encountered. + * + * @deprecated Use the {@link #end(String,String) end} method with + * namespace and name parameters instead. + */ + public void end() throws Exception { + + ; // The default implementation does nothing + + } + + + /** + * This method is called when the end of a matching XML element + * is encountered. The default implementation delegates to the deprecated + * method {@link #end end} without the + * namespace and name parameters, to retain + * backwards compatibility. + * + * @param namespace the namespace URI of the matching element, or an + * empty string if the parser is not namespace aware or the element has + * no namespace + * @param name the local name if the parser is namespace aware, or just + * the element name otherwise + * @since Digester 1.4 + */ + public void end(String namespace, String name) + throws Exception { + + end(); + + } + + + /** + * This method is called after all parsing methods have been + * called, to allow Rules to remove temporary data. + */ + public void finish() throws Exception { + + ; // The default implementation does nothing + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/RuleSet.java b/java/org/apache/tomcat/util/digester/RuleSet.java index 51e9fe1fe..9a024a7ac 100644 --- a/java/org/apache/tomcat/util/digester/RuleSet.java +++ b/java/org/apache/tomcat/util/digester/RuleSet.java @@ -1,66 +1,66 @@ -/* $Id: RuleSet.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.digester; - - -/** - *

        Public interface defining a shorthand means of configuring a complete - * set of related Rule definitions, possibly associated with - * a particular namespace URI, in one operation. To use an instance of a - * class that imlements this interface:

        - *
          - *
        • Create a concrete implementation of this interface.
        • - *
        • Optionally, you can configure a RuleSet to be relevant - * only for a particular namespace URI by configuring the value to be - * returned by getNamespaceURI().
        • - *
        • As you are configuring your Digester instance, call - * digester.addRuleSet() and pass the RuleSet instance.
        • - *
        • Digester will call the addRuleInstances() method of - * your RuleSet to configure the necessary rules.
        • - *
        - */ - -public interface RuleSet { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the namespace URI that will be applied to all Rule instances - * created from this RuleSet. - */ - public String getNamespaceURI(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance. - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public void addRuleInstances(Digester digester); - - -} +/* $Id: RuleSet.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.digester; + + +/** + *

        Public interface defining a shorthand means of configuring a complete + * set of related Rule definitions, possibly associated with + * a particular namespace URI, in one operation. To use an instance of a + * class that imlements this interface:

        + *
          + *
        • Create a concrete implementation of this interface.
        • + *
        • Optionally, you can configure a RuleSet to be relevant + * only for a particular namespace URI by configuring the value to be + * returned by getNamespaceURI().
        • + *
        • As you are configuring your Digester instance, call + * digester.addRuleSet() and pass the RuleSet instance.
        • + *
        • Digester will call the addRuleInstances() method of + * your RuleSet to configure the necessary rules.
        • + *
        + */ + +public interface RuleSet { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the namespace URI that will be applied to all Rule instances + * created from this RuleSet. + */ + public String getNamespaceURI(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance. + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public void addRuleInstances(Digester digester); + + +} diff --git a/java/org/apache/tomcat/util/digester/RuleSetBase.java b/java/org/apache/tomcat/util/digester/RuleSetBase.java index 2f899ca08..e83dab5be 100644 --- a/java/org/apache/tomcat/util/digester/RuleSetBase.java +++ b/java/org/apache/tomcat/util/digester/RuleSetBase.java @@ -1,70 +1,70 @@ -/* $Id: RuleSetBase.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -/** - *

        Convenience base class that implements the {@link RuleSet} interface. - * Concrete implementations should list all of their actual rule creation - * logic in the addRuleSet() implementation.

        - */ - -public abstract class RuleSetBase implements RuleSet { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The namespace URI that all Rule instances created by this RuleSet - * will be associated with. - */ - protected String namespaceURI = null; - - - // ------------------------------------------------------------- Properties - - - /** - * Return the namespace URI that will be applied to all Rule instances - * created from this RuleSet. - */ - public String getNamespaceURI() { - - return (this.namespaceURI); - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add the set of Rule instances defined in this RuleSet to the - * specified Digester instance, associating them with - * our namespace URI (if any). This method should only be called - * by a Digester instance. - * - * @param digester Digester instance to which the new Rule instances - * should be added. - */ - public abstract void addRuleInstances(Digester digester); - - -} +/* $Id: RuleSetBase.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +/** + *

        Convenience base class that implements the {@link RuleSet} interface. + * Concrete implementations should list all of their actual rule creation + * logic in the addRuleSet() implementation.

        + */ + +public abstract class RuleSetBase implements RuleSet { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The namespace URI that all Rule instances created by this RuleSet + * will be associated with. + */ + protected String namespaceURI = null; + + + // ------------------------------------------------------------- Properties + + + /** + * Return the namespace URI that will be applied to all Rule instances + * created from this RuleSet. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add the set of Rule instances defined in this RuleSet to the + * specified Digester instance, associating them with + * our namespace URI (if any). This method should only be called + * by a Digester instance. + * + * @param digester Digester instance to which the new Rule instances + * should be added. + */ + public abstract void addRuleInstances(Digester digester); + + +} diff --git a/java/org/apache/tomcat/util/digester/Rules.java b/java/org/apache/tomcat/util/digester/Rules.java index fc3ff49ca..03c7701ba 100644 --- a/java/org/apache/tomcat/util/digester/Rules.java +++ b/java/org/apache/tomcat/util/digester/Rules.java @@ -1,127 +1,127 @@ -/* $Id: Rules.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import java.util.List; - - -/** - * Public interface defining a collection of Rule instances (and corresponding - * matching patterns) plus an implementation of a matching policy that selects - * the rules that match a particular pattern of nested elements discovered - * during parsing. - */ - -public interface Rules { - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Digester instance with which this Rules instance is - * associated. - */ - public Digester getDigester(); - - - /** - * Set the Digester instance with which this Rules instance is associated. - * - * @param digester The newly associated Digester instance - */ - public void setDigester(Digester digester); - - - /** - * Return the namespace URI that will be applied to all subsequently - * added Rule objects. - */ - public String getNamespaceURI(); - - - /** - * Set the namespace URI that will be applied to all subsequently - * added Rule objects. - * - * @param namespaceURI Namespace URI that must match on all - * subsequently added rules, or null for matching - * regardless of the current namespace URI - */ - public void setNamespaceURI(String namespaceURI); - - - // --------------------------------------------------------- Public Methods - - - /** - * Register a new Rule instance matching the specified pattern. - * - * @param pattern Nesting pattern to be matched for this Rule - * @param rule Rule instance to be registered - */ - public void add(String pattern, Rule rule); - - - /** - * Clear all existing Rule instance registrations. - */ - public void clear(); - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param pattern Nesting pattern to be matched - * - * @deprecated Call match(namespaceURI,pattern) instead. - */ - public List match(String pattern); - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param namespaceURI Namespace URI for which to select matching rules, - * or null to match regardless of namespace URI - * @param pattern Nesting pattern to be matched - */ - public List match(String namespaceURI, String pattern); - - - /** - * Return a List of all registered Rule instances, or a zero-length List - * if there are no registered Rule instances. If more than one Rule - * instance has been registered, they must be returned - * in the order originally registered through the add() - * method. - */ - public List rules(); - - -} +/* $Id: Rules.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import java.util.List; + + +/** + * Public interface defining a collection of Rule instances (and corresponding + * matching patterns) plus an implementation of a matching policy that selects + * the rules that match a particular pattern of nested elements discovered + * during parsing. + */ + +public interface Rules { + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester(); + + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester); + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI(); + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI); + + + // --------------------------------------------------------- Public Methods + + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule); + + + /** + * Clear all existing Rule instance registrations. + */ + public void clear(); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + public List match(String pattern); + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + public List match(String namespaceURI, String pattern); + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + public List rules(); + + +} diff --git a/java/org/apache/tomcat/util/digester/RulesBase.java b/java/org/apache/tomcat/util/digester/RulesBase.java index 697d40685..3bbc18d97 100644 --- a/java/org/apache/tomcat/util/digester/RulesBase.java +++ b/java/org/apache/tomcat/util/digester/RulesBase.java @@ -1,293 +1,293 @@ -/* $Id: RulesBase.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; - - -/** - *

        Default implementation of the Rules interface that supports - * the standard rule matching behavior. This class can also be used as a - * base class for specialized Rules implementations.

        - * - *

        The matching policies implemented by this class support two different - * types of pattern matching rules:

        - *
          - *
        • Exact Match - A pattern "a/b/c" exactly matches a - * <c> element, nested inside a <b> - * element, which is nested inside an <a> element.
        • - *
        • Tail Match - A pattern "*/a/b" matches a - * <b> element, nested inside an <a> - * element, no matter how deeply the pair is nested.
        • - *
        - */ - -public class RulesBase implements Rules { - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of registered Rule instances, keyed by the matching pattern. - * Each value is a List containing the Rules for that pattern, in the - * order that they were orginally registered. - */ - protected HashMap cache = new HashMap(); - - - /** - * The Digester instance with which this Rules instance is associated. - */ - protected Digester digester = null; - - - /** - * The namespace URI for which subsequently added Rule - * objects are relevant, or null for matching independent - * of namespaces. - */ - protected String namespaceURI = null; - - - /** - * The set of registered Rule instances, in the order that they were - * originally registered. - */ - protected ArrayList rules = new ArrayList(); - - - // ------------------------------------------------------------- Properties - - - /** - * Return the Digester instance with which this Rules instance is - * associated. - */ - public Digester getDigester() { - - return (this.digester); - - } - - - /** - * Set the Digester instance with which this Rules instance is associated. - * - * @param digester The newly associated Digester instance - */ - public void setDigester(Digester digester) { - - this.digester = digester; - Iterator items = rules.iterator(); - while (items.hasNext()) { - Rule item = (Rule) items.next(); - item.setDigester(digester); - } - - } - - - /** - * Return the namespace URI that will be applied to all subsequently - * added Rule objects. - */ - public String getNamespaceURI() { - - return (this.namespaceURI); - - } - - - /** - * Set the namespace URI that will be applied to all subsequently - * added Rule objects. - * - * @param namespaceURI Namespace URI that must match on all - * subsequently added rules, or null for matching - * regardless of the current namespace URI - */ - public void setNamespaceURI(String namespaceURI) { - - this.namespaceURI = namespaceURI; - - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Register a new Rule instance matching the specified pattern. - * - * @param pattern Nesting pattern to be matched for this Rule - * @param rule Rule instance to be registered - */ - public void add(String pattern, Rule rule) { - // to help users who accidently add '/' to the end of their patterns - int patternLength = pattern.length(); - if (patternLength>1 && pattern.endsWith("/")) { - pattern = pattern.substring(0, patternLength-1); - } - - - List list = (List) cache.get(pattern); - if (list == null) { - list = new ArrayList(); - cache.put(pattern, list); - } - list.add(rule); - rules.add(rule); - if (this.digester != null) { - rule.setDigester(this.digester); - } - if (this.namespaceURI != null) { - rule.setNamespaceURI(this.namespaceURI); - } - - } - - - /** - * Clear all existing Rule instance registrations. - */ - public void clear() { - - cache.clear(); - rules.clear(); - - } - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param pattern Nesting pattern to be matched - * - * @deprecated Call match(namespaceURI,pattern) instead. - */ - public List match(String pattern) { - - return (match(null, pattern)); - - } - - - /** - * Return a List of all registered Rule instances that match the specified - * nesting pattern, or a zero-length List if there are no matches. If more - * than one Rule instance matches, they must be returned - * in the order originally registered through the add() - * method. - * - * @param namespaceURI Namespace URI for which to select matching rules, - * or null to match regardless of namespace URI - * @param pattern Nesting pattern to be matched - */ - public List match(String namespaceURI, String pattern) { - - // List rulesList = (List) this.cache.get(pattern); - List rulesList = lookup(namespaceURI, pattern); - if ((rulesList == null) || (rulesList.size() < 1)) { - // Find the longest key, ie more discriminant - String longKey = ""; - Iterator keys = this.cache.keySet().iterator(); - while (keys.hasNext()) { - String key = (String) keys.next(); - if (key.startsWith("*/")) { - if (pattern.equals(key.substring(2)) || - pattern.endsWith(key.substring(1))) { - if (key.length() > longKey.length()) { - // rulesList = (List) this.cache.get(key); - rulesList = lookup(namespaceURI, key); - longKey = key; - } - } - } - } - } - if (rulesList == null) { - rulesList = new ArrayList(); - } - return (rulesList); - - } - - - /** - * Return a List of all registered Rule instances, or a zero-length List - * if there are no registered Rule instances. If more than one Rule - * instance has been registered, they must be returned - * in the order originally registered through the add() - * method. - */ - public List rules() { - - return (this.rules); - - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Return a List of Rule instances for the specified pattern that also - * match the specified namespace URI (if any). If there are no such - * rules, return null. - * - * @param namespaceURI Namespace URI to match, or null to - * select matching rules regardless of namespace URI - * @param pattern Pattern to be matched - */ - protected List lookup(String namespaceURI, String pattern) { - - // Optimize when no namespace URI is specified - List list = (List) this.cache.get(pattern); - if (list == null) { - return (null); - } - if ((namespaceURI == null) || (namespaceURI.length() == 0)) { - return (list); - } - - // Select only Rules that match on the specified namespace URI - ArrayList results = new ArrayList(); - Iterator items = list.iterator(); - while (items.hasNext()) { - Rule item = (Rule) items.next(); - if ((namespaceURI.equals(item.getNamespaceURI())) || - (item.getNamespaceURI() == null)) { - results.add(item); - } - } - return (results); - - } - - -} +/* $Id: RulesBase.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; + + +/** + *

        Default implementation of the Rules interface that supports + * the standard rule matching behavior. This class can also be used as a + * base class for specialized Rules implementations.

        + * + *

        The matching policies implemented by this class support two different + * types of pattern matching rules:

        + *
          + *
        • Exact Match - A pattern "a/b/c" exactly matches a + * <c> element, nested inside a <b> + * element, which is nested inside an <a> element.
        • + *
        • Tail Match - A pattern "*/a/b" matches a + * <b> element, nested inside an <a> + * element, no matter how deeply the pair is nested.
        • + *
        + */ + +public class RulesBase implements Rules { + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of registered Rule instances, keyed by the matching pattern. + * Each value is a List containing the Rules for that pattern, in the + * order that they were orginally registered. + */ + protected HashMap cache = new HashMap(); + + + /** + * The Digester instance with which this Rules instance is associated. + */ + protected Digester digester = null; + + + /** + * The namespace URI for which subsequently added Rule + * objects are relevant, or null for matching independent + * of namespaces. + */ + protected String namespaceURI = null; + + + /** + * The set of registered Rule instances, in the order that they were + * originally registered. + */ + protected ArrayList rules = new ArrayList(); + + + // ------------------------------------------------------------- Properties + + + /** + * Return the Digester instance with which this Rules instance is + * associated. + */ + public Digester getDigester() { + + return (this.digester); + + } + + + /** + * Set the Digester instance with which this Rules instance is associated. + * + * @param digester The newly associated Digester instance + */ + public void setDigester(Digester digester) { + + this.digester = digester; + Iterator items = rules.iterator(); + while (items.hasNext()) { + Rule item = (Rule) items.next(); + item.setDigester(digester); + } + + } + + + /** + * Return the namespace URI that will be applied to all subsequently + * added Rule objects. + */ + public String getNamespaceURI() { + + return (this.namespaceURI); + + } + + + /** + * Set the namespace URI that will be applied to all subsequently + * added Rule objects. + * + * @param namespaceURI Namespace URI that must match on all + * subsequently added rules, or null for matching + * regardless of the current namespace URI + */ + public void setNamespaceURI(String namespaceURI) { + + this.namespaceURI = namespaceURI; + + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Register a new Rule instance matching the specified pattern. + * + * @param pattern Nesting pattern to be matched for this Rule + * @param rule Rule instance to be registered + */ + public void add(String pattern, Rule rule) { + // to help users who accidently add '/' to the end of their patterns + int patternLength = pattern.length(); + if (patternLength>1 && pattern.endsWith("/")) { + pattern = pattern.substring(0, patternLength-1); + } + + + List list = (List) cache.get(pattern); + if (list == null) { + list = new ArrayList(); + cache.put(pattern, list); + } + list.add(rule); + rules.add(rule); + if (this.digester != null) { + rule.setDigester(this.digester); + } + if (this.namespaceURI != null) { + rule.setNamespaceURI(this.namespaceURI); + } + + } + + + /** + * Clear all existing Rule instance registrations. + */ + public void clear() { + + cache.clear(); + rules.clear(); + + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param pattern Nesting pattern to be matched + * + * @deprecated Call match(namespaceURI,pattern) instead. + */ + public List match(String pattern) { + + return (match(null, pattern)); + + } + + + /** + * Return a List of all registered Rule instances that match the specified + * nesting pattern, or a zero-length List if there are no matches. If more + * than one Rule instance matches, they must be returned + * in the order originally registered through the add() + * method. + * + * @param namespaceURI Namespace URI for which to select matching rules, + * or null to match regardless of namespace URI + * @param pattern Nesting pattern to be matched + */ + public List match(String namespaceURI, String pattern) { + + // List rulesList = (List) this.cache.get(pattern); + List rulesList = lookup(namespaceURI, pattern); + if ((rulesList == null) || (rulesList.size() < 1)) { + // Find the longest key, ie more discriminant + String longKey = ""; + Iterator keys = this.cache.keySet().iterator(); + while (keys.hasNext()) { + String key = (String) keys.next(); + if (key.startsWith("*/")) { + if (pattern.equals(key.substring(2)) || + pattern.endsWith(key.substring(1))) { + if (key.length() > longKey.length()) { + // rulesList = (List) this.cache.get(key); + rulesList = lookup(namespaceURI, key); + longKey = key; + } + } + } + } + } + if (rulesList == null) { + rulesList = new ArrayList(); + } + return (rulesList); + + } + + + /** + * Return a List of all registered Rule instances, or a zero-length List + * if there are no registered Rule instances. If more than one Rule + * instance has been registered, they must be returned + * in the order originally registered through the add() + * method. + */ + public List rules() { + + return (this.rules); + + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Return a List of Rule instances for the specified pattern that also + * match the specified namespace URI (if any). If there are no such + * rules, return null. + * + * @param namespaceURI Namespace URI to match, or null to + * select matching rules regardless of namespace URI + * @param pattern Pattern to be matched + */ + protected List lookup(String namespaceURI, String pattern) { + + // Optimize when no namespace URI is specified + List list = (List) this.cache.get(pattern); + if (list == null) { + return (null); + } + if ((namespaceURI == null) || (namespaceURI.length() == 0)) { + return (list); + } + + // Select only Rules that match on the specified namespace URI + ArrayList results = new ArrayList(); + Iterator items = list.iterator(); + while (items.hasNext()) { + Rule item = (Rule) items.next(); + if ((namespaceURI.equals(item.getNamespaceURI())) || + (item.getNamespaceURI() == null)) { + results.add(item); + } + } + return (results); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/SetNextRule.java b/java/org/apache/tomcat/util/digester/SetNextRule.java index 6e3c2f4ae..cf9b8f64a 100644 --- a/java/org/apache/tomcat/util/digester/SetNextRule.java +++ b/java/org/apache/tomcat/util/digester/SetNextRule.java @@ -1,214 +1,214 @@ -/* $Id: SetNextRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import org.apache.tomcat.util.IntrospectionUtils; - - -/** - *

        Rule implementation that calls a method on the (top-1) (parent) - * object, passing the top object (child) as an argument. It is - * commonly used to establish parent-child relationships.

        - * - *

        This rule now supports more flexible method matching by default. - * It is possible that this may break (some) code - * written against release 1.1.1 or earlier. - * See {@link #isExactMatch()} for more details.

        - */ - -public class SetNextRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "set next" rule with the specified method name. The - * method's argument type is assumed to be the class of the - * child object. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetNextRule(String methodName)} instead. - */ - public SetNextRule(Digester digester, String methodName) { - - this(methodName); - - } - - - /** - * Construct a "set next" rule with the specified method name. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * @param paramType Java class of the parent method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetNextRule(String methodName,String paramType)} instead. - */ - public SetNextRule(Digester digester, String methodName, - String paramType) { - - this(methodName, paramType); - - } - - /** - * Construct a "set next" rule with the specified method name. The - * method's argument type is assumed to be the class of the - * child object. - * - * @param methodName Method name of the parent method to call - */ - public SetNextRule(String methodName) { - - this(methodName, null); - - } - - - /** - * Construct a "set next" rule with the specified method name. - * - * @param methodName Method name of the parent method to call - * @param paramType Java class of the parent method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public SetNextRule(String methodName, - String paramType) { - - this.methodName = methodName; - this.paramType = paramType; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The method name to call on the parent object. - */ - protected String methodName = null; - - - /** - * The Java class name of the parameter type expected by the method. - */ - protected String paramType = null; - - /** - * Should we use exact matching. Default is no. - */ - protected boolean useExactMatch = false; - - // --------------------------------------------------------- Public Methods - - - /** - *

        Is exact matching being used.

        - * - *

        This rule uses org.apache.commons.beanutils.MethodUtils - * to introspect the relevent objects so that the right method can be called. - * Originally, MethodUtils.invokeExactMethod was used. - * This matches methods very strictly - * and so may not find a matching method when one exists. - * This is still the behaviour when exact matching is enabled.

        - * - *

        When exact matching is disabled, MethodUtils.invokeMethod is used. - * This method finds more methods but is less precise when there are several methods - * with correct signatures. - * So, if you want to choose an exact signature you might need to enable this property.

        - * - *

        The default setting is to disable exact matches.

        - * - * @return true iff exact matching is enabled - * @since Digester Release 1.1.1 - */ - public boolean isExactMatch() { - - return useExactMatch; - } - - /** - *

        Set whether exact matching is enabled.

        - * - *

        See {@link #isExactMatch()}.

        - * - * @param useExactMatch should this rule use exact method matching - * @since Digester Release 1.1.1 - */ - public void setExactMatch(boolean useExactMatch) { - - this.useExactMatch = useExactMatch; - } - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - // Identify the objects to be used - Object child = digester.peek(0); - Object parent = digester.peek(1); - if (digester.log.isDebugEnabled()) { - if (parent == null) { - digester.log.debug("[SetNextRule]{" + digester.match + - "} Call [NULL PARENT]." + - methodName + "(" + child + ")"); - } else { - digester.log.debug("[SetNextRule]{" + digester.match + - "} Call " + parent.getClass().getName() + "." + - methodName + "(" + child + ")"); - } - } - - // Call the specified method - IntrospectionUtils.callMethod1(parent, methodName, - child, paramType, digester.getClassLoader()); - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SetNextRule["); - sb.append("methodName="); - sb.append(methodName); - sb.append(", paramType="); - sb.append(paramType); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: SetNextRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import org.apache.tomcat.util.IntrospectionUtils; + + +/** + *

        Rule implementation that calls a method on the (top-1) (parent) + * object, passing the top object (child) as an argument. It is + * commonly used to establish parent-child relationships.

        + * + *

        This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

        + */ + +public class SetNextRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set next" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetNextRule(String methodName)} instead. + */ + public SetNextRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set next" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetNextRule(String methodName,String paramType)} instead. + */ + public SetNextRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set next" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param methodName Method name of the parent method to call + */ + public SetNextRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set next" rule with the specified method name. + * + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetNextRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + // --------------------------------------------------------- Public Methods + + + /** + *

        Is exact matching being used.

        + * + *

        This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

        + * + *

        When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

        + * + *

        The default setting is to disable exact matches.

        + * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + /** + *

        Set whether exact matching is enabled.

        + * + *

        See {@link #isExactMatch()}.

        + * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.peek(1); + if (digester.log.isDebugEnabled()) { + if (parent == null) { + digester.log.debug("[SetNextRule]{" + digester.match + + "} Call [NULL PARENT]." + + methodName + "(" + child + ")"); + } else { + digester.log.debug("[SetNextRule]{" + digester.match + + "} Call " + parent.getClass().getName() + "." + + methodName + "(" + child + ")"); + } + } + + // Call the specified method + IntrospectionUtils.callMethod1(parent, methodName, + child, paramType, digester.getClassLoader()); + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SetNextRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/SetPropertiesRule.java b/java/org/apache/tomcat/util/digester/SetPropertiesRule.java index 6513ca0a6..e3b5c8e7b 100644 --- a/java/org/apache/tomcat/util/digester/SetPropertiesRule.java +++ b/java/org/apache/tomcat/util/digester/SetPropertiesRule.java @@ -1,261 +1,261 @@ -/* $Id: SetPropertiesRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.apache.tomcat.util.IntrospectionUtils; -import org.xml.sax.Attributes; - - -/** - *

        Rule implementation that sets properties on the object at the top of the - * stack, based on attributes with corresponding names.

        - * - *

        This rule supports custom mapping of attribute names to property names. - * The default mapping for particular attributes can be overridden by using - * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}. - * This allows attributes to be mapped to properties with different names. - * Certain attributes can also be marked to be ignored.

        - */ - -public class SetPropertiesRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Default constructor sets only the the associated Digester. - * - * @param digester The digester with which this rule is associated - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetPropertiesRule()} instead. - */ - public SetPropertiesRule(Digester digester) { - - this(); - - } - - - /** - * Base constructor. - */ - public SetPropertiesRule() { - - // nothing to set up - - } - - /** - *

        Convenience constructor overrides the mapping for just one property.

        - * - *

        For details about how this works, see - * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.

        - * - * @param attributeName map this attribute - * @param propertyName to a property with this name - */ - public SetPropertiesRule(String attributeName, String propertyName) { - - attributeNames = new String[1]; - attributeNames[0] = attributeName; - propertyNames = new String[1]; - propertyNames[0] = propertyName; - } - - /** - *

        Constructor allows attribute->property mapping to be overriden.

        - * - *

        Two arrays are passed in. - * One contains the attribute names and the other the property names. - * The attribute name / property name pairs are match by position - * In order words, the first string in the attribute name list matches - * to the first string in the property name list and so on.

        - * - *

        If a property name is null or the attribute name has no matching - * property name, then this indicates that the attibute should be ignored.

        - * - *
        Example One
        - *

        The following constructs a rule that maps the alt-city - * attribute to the city property and the alt-state - * to the state property. - * All other attributes are mapped as usual using exact name matching. - *

        -     *      SetPropertiesRule(
        -     *                new String[] {"alt-city", "alt-state"}, 
        -     *                new String[] {"city", "state"});
        -     * 
        - * - *
        Example Two
        - *

        The following constructs a rule that maps the class - * attribute to the className property. - * The attribute ignore-me is not mapped. - * All other attributes are mapped as usual using exact name matching. - *

        -     *      SetPropertiesRule(
        -     *                new String[] {"class", "ignore-me"}, 
        -     *                new String[] {"className"});
        -     * 
        - * - * @param attributeNames names of attributes to map - * @param propertyNames names of properties mapped to - */ - public SetPropertiesRule(String[] attributeNames, String[] propertyNames) { - // create local copies - this.attributeNames = new String[attributeNames.length]; - for (int i=0, size=attributeNames.length; iproperty mapping - */ - private String [] attributeNames; - /** - * Property names used to override natural attribute->property mapping - */ - private String [] propertyNames; - - - // --------------------------------------------------------- Public Methods - - - /** - * Process the beginning of this element. - * - * @param attributes The attribute list of this element - */ - public void begin(Attributes attributes) throws Exception { - - // Populate the corresponding properties of the top object - Object top = digester.peek(); - if (digester.log.isDebugEnabled()) { - if (top != null) { - digester.log.debug("[SetPropertiesRule]{" + digester.match + - "} Set " + top.getClass().getName() + - " properties"); - } else { - digester.log.debug("[SetPropertiesRule]{" + digester.match + - "} Set NULL properties"); - } - } - - // set up variables for custom names mappings - int attNamesLength = 0; - if (attributeNames != null) { - attNamesLength = attributeNames.length; - } - int propNamesLength = 0; - if (propertyNames != null) { - propNamesLength = propertyNames.length; - } - - for (int i = 0; i < attributes.getLength(); i++) { - String name = attributes.getLocalName(i); - if ("".equals(name)) { - name = attributes.getQName(i); - } - String value = attributes.getValue(i); - - // we'll now check for custom mappings - for (int n = 0; nAdd an additional attribute name to property name mapping. - * This is intended to be used from the xml rules. - */ - public void addAlias(String attributeName, String propertyName) { - - // this is a bit tricky. - // we'll need to resize the array. - // probably should be synchronized but digester's not thread safe anyway - if (attributeNames == null) { - - attributeNames = new String[1]; - attributeNames[0] = attributeName; - propertyNames = new String[1]; - propertyNames[0] = propertyName; - - } else { - int length = attributeNames.length; - String [] tempAttributes = new String[length + 1]; - for (int i=0; iRule implementation that sets properties on the object at the top of the + * stack, based on attributes with corresponding names.

        + * + *

        This rule supports custom mapping of attribute names to property names. + * The default mapping for particular attributes can be overridden by using + * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}. + * This allows attributes to be mapped to properties with different names. + * Certain attributes can also be marked to be ignored.

        + */ + +public class SetPropertiesRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Default constructor sets only the the associated Digester. + * + * @param digester The digester with which this rule is associated + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetPropertiesRule()} instead. + */ + public SetPropertiesRule(Digester digester) { + + this(); + + } + + + /** + * Base constructor. + */ + public SetPropertiesRule() { + + // nothing to set up + + } + + /** + *

        Convenience constructor overrides the mapping for just one property.

        + * + *

        For details about how this works, see + * {@link #SetPropertiesRule(String[] attributeNames, String[] propertyNames)}.

        + * + * @param attributeName map this attribute + * @param propertyName to a property with this name + */ + public SetPropertiesRule(String attributeName, String propertyName) { + + attributeNames = new String[1]; + attributeNames[0] = attributeName; + propertyNames = new String[1]; + propertyNames[0] = propertyName; + } + + /** + *

        Constructor allows attribute->property mapping to be overriden.

        + * + *

        Two arrays are passed in. + * One contains the attribute names and the other the property names. + * The attribute name / property name pairs are match by position + * In order words, the first string in the attribute name list matches + * to the first string in the property name list and so on.

        + * + *

        If a property name is null or the attribute name has no matching + * property name, then this indicates that the attibute should be ignored.

        + * + *
        Example One
        + *

        The following constructs a rule that maps the alt-city + * attribute to the city property and the alt-state + * to the state property. + * All other attributes are mapped as usual using exact name matching. + *

        +     *      SetPropertiesRule(
        +     *                new String[] {"alt-city", "alt-state"}, 
        +     *                new String[] {"city", "state"});
        +     * 
        + * + *
        Example Two
        + *

        The following constructs a rule that maps the class + * attribute to the className property. + * The attribute ignore-me is not mapped. + * All other attributes are mapped as usual using exact name matching. + *

        +     *      SetPropertiesRule(
        +     *                new String[] {"class", "ignore-me"}, 
        +     *                new String[] {"className"});
        +     * 
        + * + * @param attributeNames names of attributes to map + * @param propertyNames names of properties mapped to + */ + public SetPropertiesRule(String[] attributeNames, String[] propertyNames) { + // create local copies + this.attributeNames = new String[attributeNames.length]; + for (int i=0, size=attributeNames.length; iproperty mapping + */ + private String [] attributeNames; + /** + * Property names used to override natural attribute->property mapping + */ + private String [] propertyNames; + + + // --------------------------------------------------------- Public Methods + + + /** + * Process the beginning of this element. + * + * @param attributes The attribute list of this element + */ + public void begin(Attributes attributes) throws Exception { + + // Populate the corresponding properties of the top object + Object top = digester.peek(); + if (digester.log.isDebugEnabled()) { + if (top != null) { + digester.log.debug("[SetPropertiesRule]{" + digester.match + + "} Set " + top.getClass().getName() + + " properties"); + } else { + digester.log.debug("[SetPropertiesRule]{" + digester.match + + "} Set NULL properties"); + } + } + + // set up variables for custom names mappings + int attNamesLength = 0; + if (attributeNames != null) { + attNamesLength = attributeNames.length; + } + int propNamesLength = 0; + if (propertyNames != null) { + propNamesLength = propertyNames.length; + } + + for (int i = 0; i < attributes.getLength(); i++) { + String name = attributes.getLocalName(i); + if ("".equals(name)) { + name = attributes.getQName(i); + } + String value = attributes.getValue(i); + + // we'll now check for custom mappings + for (int n = 0; nAdd an additional attribute name to property name mapping. + * This is intended to be used from the xml rules. + */ + public void addAlias(String attributeName, String propertyName) { + + // this is a bit tricky. + // we'll need to resize the array. + // probably should be synchronized but digester's not thread safe anyway + if (attributeNames == null) { + + attributeNames = new String[1]; + attributeNames[0] = attributeName; + propertyNames = new String[1]; + propertyNames[0] = propertyName; + + } else { + int length = attributeNames.length; + String [] tempAttributes = new String[length + 1]; + for (int i=0; iRule implementation that calls a method on the root object on the stack, - * passing the top object (child) as an argument. - * It is important to remember that this rule acts on end.

        - * - *

        This rule now supports more flexible method matching by default. - * It is possible that this may break (some) code - * written against release 1.1.1 or earlier. - * See {@link #isExactMatch()} for more details.

        - */ - -public class SetRootRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "set root" rule with the specified method name. The - * method's argument type is assumed to be the class of the - * child object. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetRootRule(String methodName)} instead. - */ - public SetRootRule(Digester digester, String methodName) { - - this(methodName); - - } - - - /** - * Construct a "set root" rule with the specified method name. - * - * @param digester The associated Digester - * @param methodName Method name of the parent method to call - * @param paramType Java class of the parent method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetRootRule(String methodName,String paramType)} instead. - */ - public SetRootRule(Digester digester, String methodName, - String paramType) { - - this(methodName, paramType); - - } - - /** - * Construct a "set root" rule with the specified method name. The - * method's argument type is assumed to be the class of the - * child object. - * - * @param methodName Method name of the parent method to call - */ - public SetRootRule(String methodName) { - - this(methodName, null); - - } - - - /** - * Construct a "set root" rule with the specified method name. - * - * @param methodName Method name of the parent method to call - * @param paramType Java class of the parent method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public SetRootRule(String methodName, - String paramType) { - - this.methodName = methodName; - this.paramType = paramType; - - } - - // ----------------------------------------------------- Instance Variables - - - /** - * The method name to call on the parent object. - */ - protected String methodName = null; - - - /** - * The Java class name of the parameter type expected by the method. - */ - protected String paramType = null; - - /** - * Should we use exact matching. Default is no. - */ - protected boolean useExactMatch = false; - - - // --------------------------------------------------------- Public Methods - - - /** - *

        Is exact matching being used.

        - * - *

        This rule uses org.apache.commons.beanutils.MethodUtils - * to introspect the relevent objects so that the right method can be called. - * Originally, MethodUtils.invokeExactMethod was used. - * This matches methods very strictly - * and so may not find a matching method when one exists. - * This is still the behaviour when exact matching is enabled.

        - * - *

        When exact matching is disabled, MethodUtils.invokeMethod is used. - * This method finds more methods but is less precise when there are several methods - * with correct signatures. - * So, if you want to choose an exact signature you might need to enable this property.

        - * - *

        The default setting is to disable exact matches.

        - * - * @return true iff exact matching is enabled - * @since Digester Release 1.1.1 - */ - public boolean isExactMatch() { - - return useExactMatch; - } - - - /** - *

        Set whether exact matching is enabled.

        - * - *

        See {@link #isExactMatch()}.

        - * - * @param useExactMatch should this rule use exact method matching - * @since Digester Release 1.1.1 - */ - public void setExactMatch(boolean useExactMatch) { - - this.useExactMatch = useExactMatch; - } - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - // Identify the objects to be used - Object child = digester.peek(0); - Object parent = digester.root; - if (digester.log.isDebugEnabled()) { - if (parent == null) { - digester.log.debug("[SetRootRule]{" + digester.match + - "} Call [NULL ROOT]." + - methodName + "(" + child + ")"); - } else { - digester.log.debug("[SetRootRule]{" + digester.match + - "} Call " + parent.getClass().getName() + "." + - methodName + "(" + child + ")"); - } - } - - // Call the specified method - IntrospectionUtils.callMethod1(parent, methodName, - child, paramType, digester.getClassLoader()); - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SetRootRule["); - sb.append("methodName="); - sb.append(methodName); - sb.append(", paramType="); - sb.append(paramType); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: SetRootRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2002-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import org.apache.tomcat.util.IntrospectionUtils; + + +/** + *

        Rule implementation that calls a method on the root object on the stack, + * passing the top object (child) as an argument. + * It is important to remember that this rule acts on end.

        + * + *

        This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

        + */ + +public class SetRootRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set root" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetRootRule(String methodName)} instead. + */ + public SetRootRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set root" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetRootRule(String methodName,String paramType)} instead. + */ + public SetRootRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set root" rule with the specified method name. The + * method's argument type is assumed to be the class of the + * child object. + * + * @param methodName Method name of the parent method to call + */ + public SetRootRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set root" rule with the specified method name. + * + * @param methodName Method name of the parent method to call + * @param paramType Java class of the parent method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetRootRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the parent object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + + // --------------------------------------------------------- Public Methods + + + /** + *

        Is exact matching being used.

        + * + *

        This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

        + * + *

        When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

        + * + *

        The default setting is to disable exact matches.

        + * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + + /** + *

        Set whether exact matching is enabled.

        + * + *

        See {@link #isExactMatch()}.

        + * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.root; + if (digester.log.isDebugEnabled()) { + if (parent == null) { + digester.log.debug("[SetRootRule]{" + digester.match + + "} Call [NULL ROOT]." + + methodName + "(" + child + ")"); + } else { + digester.log.debug("[SetRootRule]{" + digester.match + + "} Call " + parent.getClass().getName() + "." + + methodName + "(" + child + ")"); + } + } + + // Call the specified method + IntrospectionUtils.callMethod1(parent, methodName, + child, paramType, digester.getClassLoader()); + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SetRootRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/SetTopRule.java b/java/org/apache/tomcat/util/digester/SetTopRule.java index fe52fb1fd..584c59aa7 100644 --- a/java/org/apache/tomcat/util/digester/SetTopRule.java +++ b/java/org/apache/tomcat/util/digester/SetTopRule.java @@ -1,215 +1,215 @@ -/* $Id: SetTopRule.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - - -import org.apache.tomcat.util.IntrospectionUtils; - - -/** - *

        Rule implementation that calls a "set parent" method on the top (child) - * object, passing the (top-1) (parent) object as an argument.

        - * - *

        This rule now supports more flexible method matching by default. - * It is possible that this may break (some) code - * written against release 1.1.1 or earlier. - * See {@link #isExactMatch()} for more details.

        - */ - -public class SetTopRule extends Rule { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a "set parent" rule with the specified method name. The - * "set parent" method's argument type is assumed to be the class of the - * parent object. - * - * @param digester The associated Digester - * @param methodName Method name of the "set parent" method to call - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetTopRule(String methodName)} instead. - */ - public SetTopRule(Digester digester, String methodName) { - - this(methodName); - - } - - - /** - * Construct a "set parent" rule with the specified method name. - * - * @param digester The associated Digester - * @param methodName Method name of the "set parent" method to call - * @param paramType Java class of the "set parent" method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - * - * @deprecated The digester instance is now set in the {@link Digester#addRule} method. - * Use {@link #SetTopRule(String methodName, String paramType)} instead. - */ - public SetTopRule(Digester digester, String methodName, - String paramType) { - - this(methodName, paramType); - - } - - /** - * Construct a "set parent" rule with the specified method name. The - * "set parent" method's argument type is assumed to be the class of the - * parent object. - * - * @param methodName Method name of the "set parent" method to call - */ - public SetTopRule(String methodName) { - - this(methodName, null); - - } - - - /** - * Construct a "set parent" rule with the specified method name. - * - * @param methodName Method name of the "set parent" method to call - * @param paramType Java class of the "set parent" method's argument - * (if you wish to use a primitive type, specify the corresonding - * Java wrapper class instead, such as java.lang.Boolean - * for a boolean parameter) - */ - public SetTopRule(String methodName, - String paramType) { - - this.methodName = methodName; - this.paramType = paramType; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The method name to call on the child object. - */ - protected String methodName = null; - - - /** - * The Java class name of the parameter type expected by the method. - */ - protected String paramType = null; - - /** - * Should we use exact matching. Default is no. - */ - protected boolean useExactMatch = false; - - - // --------------------------------------------------------- Public Methods - - /** - *

        Is exact matching being used.

        - * - *

        This rule uses org.apache.commons.beanutils.MethodUtils - * to introspect the relevent objects so that the right method can be called. - * Originally, MethodUtils.invokeExactMethod was used. - * This matches methods very strictly - * and so may not find a matching method when one exists. - * This is still the behaviour when exact matching is enabled.

        - * - *

        When exact matching is disabled, MethodUtils.invokeMethod is used. - * This method finds more methods but is less precise when there are several methods - * with correct signatures. - * So, if you want to choose an exact signature you might need to enable this property.

        - * - *

        The default setting is to disable exact matches.

        - * - * @return true iff exact matching is enabled - * @since Digester Release 1.1.1 - */ - public boolean isExactMatch() { - - return useExactMatch; - } - - /** - *

        Set whether exact matching is enabled.

        - * - *

        See {@link #isExactMatch()}.

        - * - * @param useExactMatch should this rule use exact method matching - * @since Digester Release 1.1.1 - */ - public void setExactMatch(boolean useExactMatch) { - - this.useExactMatch = useExactMatch; - } - - /** - * Process the end of this element. - */ - public void end() throws Exception { - - // Identify the objects to be used - Object child = digester.peek(0); - Object parent = digester.peek(1); - - if (digester.log.isDebugEnabled()) { - if (child == null) { - digester.log.debug("[SetTopRule]{" + digester.match + - "} Call [NULL CHILD]." + - methodName + "(" + parent + ")"); - } else { - digester.log.debug("[SetTopRule]{" + digester.match + - "} Call " + child.getClass().getName() + "." + - methodName + "(" + parent + ")"); - } - } - - // Call the specified method - IntrospectionUtils.callMethod1(child, methodName, - parent, paramType, digester.getClassLoader()); - - } - - - /** - * Render a printable version of this Rule. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("SetTopRule["); - sb.append("methodName="); - sb.append(methodName); - sb.append(", paramType="); - sb.append(paramType); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* $Id: SetTopRule.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + + +import org.apache.tomcat.util.IntrospectionUtils; + + +/** + *

        Rule implementation that calls a "set parent" method on the top (child) + * object, passing the (top-1) (parent) object as an argument.

        + * + *

        This rule now supports more flexible method matching by default. + * It is possible that this may break (some) code + * written against release 1.1.1 or earlier. + * See {@link #isExactMatch()} for more details.

        + */ + +public class SetTopRule extends Rule { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a "set parent" rule with the specified method name. The + * "set parent" method's argument type is assumed to be the class of the + * parent object. + * + * @param digester The associated Digester + * @param methodName Method name of the "set parent" method to call + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetTopRule(String methodName)} instead. + */ + public SetTopRule(Digester digester, String methodName) { + + this(methodName); + + } + + + /** + * Construct a "set parent" rule with the specified method name. + * + * @param digester The associated Digester + * @param methodName Method name of the "set parent" method to call + * @param paramType Java class of the "set parent" method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + * + * @deprecated The digester instance is now set in the {@link Digester#addRule} method. + * Use {@link #SetTopRule(String methodName, String paramType)} instead. + */ + public SetTopRule(Digester digester, String methodName, + String paramType) { + + this(methodName, paramType); + + } + + /** + * Construct a "set parent" rule with the specified method name. The + * "set parent" method's argument type is assumed to be the class of the + * parent object. + * + * @param methodName Method name of the "set parent" method to call + */ + public SetTopRule(String methodName) { + + this(methodName, null); + + } + + + /** + * Construct a "set parent" rule with the specified method name. + * + * @param methodName Method name of the "set parent" method to call + * @param paramType Java class of the "set parent" method's argument + * (if you wish to use a primitive type, specify the corresonding + * Java wrapper class instead, such as java.lang.Boolean + * for a boolean parameter) + */ + public SetTopRule(String methodName, + String paramType) { + + this.methodName = methodName; + this.paramType = paramType; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The method name to call on the child object. + */ + protected String methodName = null; + + + /** + * The Java class name of the parameter type expected by the method. + */ + protected String paramType = null; + + /** + * Should we use exact matching. Default is no. + */ + protected boolean useExactMatch = false; + + + // --------------------------------------------------------- Public Methods + + /** + *

        Is exact matching being used.

        + * + *

        This rule uses org.apache.commons.beanutils.MethodUtils + * to introspect the relevent objects so that the right method can be called. + * Originally, MethodUtils.invokeExactMethod was used. + * This matches methods very strictly + * and so may not find a matching method when one exists. + * This is still the behaviour when exact matching is enabled.

        + * + *

        When exact matching is disabled, MethodUtils.invokeMethod is used. + * This method finds more methods but is less precise when there are several methods + * with correct signatures. + * So, if you want to choose an exact signature you might need to enable this property.

        + * + *

        The default setting is to disable exact matches.

        + * + * @return true iff exact matching is enabled + * @since Digester Release 1.1.1 + */ + public boolean isExactMatch() { + + return useExactMatch; + } + + /** + *

        Set whether exact matching is enabled.

        + * + *

        See {@link #isExactMatch()}.

        + * + * @param useExactMatch should this rule use exact method matching + * @since Digester Release 1.1.1 + */ + public void setExactMatch(boolean useExactMatch) { + + this.useExactMatch = useExactMatch; + } + + /** + * Process the end of this element. + */ + public void end() throws Exception { + + // Identify the objects to be used + Object child = digester.peek(0); + Object parent = digester.peek(1); + + if (digester.log.isDebugEnabled()) { + if (child == null) { + digester.log.debug("[SetTopRule]{" + digester.match + + "} Call [NULL CHILD]." + + methodName + "(" + parent + ")"); + } else { + digester.log.debug("[SetTopRule]{" + digester.match + + "} Call " + child.getClass().getName() + "." + + methodName + "(" + parent + ")"); + } + } + + // Call the specified method + IntrospectionUtils.callMethod1(child, methodName, + parent, paramType, digester.getClassLoader()); + + } + + + /** + * Render a printable version of this Rule. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("SetTopRule["); + sb.append("methodName="); + sb.append(methodName); + sb.append(", paramType="); + sb.append(paramType); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java b/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java index 8e86fabcd..1cc304ff2 100644 --- a/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java +++ b/java/org/apache/tomcat/util/digester/WithDefaultsRulesWrapper.java @@ -1,163 +1,163 @@ -/* $Id: WithDefaultsRulesWrapper.java 299475 2004-06-26 17:41:32Z remm $ - * - * Copyright 2003-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.digester; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -/** - *

        Rules Decorator that returns default rules - * when no matches are returned by the wrapped implementation.

        - * - *

        This allows default Rule instances to be added to any - * existing Rules implementation. These default Rule - * instances will be returned for any match for which the wrapped - * implementation does not return any matches.

        - *

        For example, - *

        - *   Rule alpha;
        - *   ...
        - *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
        - *   rules.addDefault(alpha);
        - *   ...
        - *   digester.setRules(rules);
        - *   ...
        - * 
        - * when a pattern does not match any other rule, then rule alpha will be called. - *

        - *

        WithDefaultsRulesWrapper follows the Decorator pattern.

        - * - * @since 1.6 - */ - -public class WithDefaultsRulesWrapper implements Rules { - - // --------------------------------------------------------- Fields - - /** The Rules implementation that this class wraps. */ - private Rules wrappedRules; - /** Rules to be fired when the wrapped implementations returns none. */ - private List defaultRules = new ArrayList(); - /** All rules (preserves order in which they were originally added) */ - private List allRules = new ArrayList(); - - // --------------------------------------------------------- Constructor - - /** - * Base constructor. - * - * @param wrappedRules the wrapped Rules implementation, not null - * @throws IllegalArgumentException when wrappedRules is null - */ - public WithDefaultsRulesWrapper(Rules wrappedRules) { - if (wrappedRules == null) { - throw new IllegalArgumentException("Wrapped rules must not be null"); - } - this.wrappedRules = wrappedRules; - } - - // --------------------------------------------------------- Properties - - /** Gets digester using these Rules */ - public Digester getDigester() { - return wrappedRules.getDigester(); - } - - /** Sets digeseter using these Rules */ - public void setDigester(Digester digester) { - wrappedRules.setDigester(digester); - Iterator it = defaultRules.iterator(); - while (it.hasNext()) { - Rule rule = (Rule) it.next(); - rule.setDigester(digester); - } - } - - /** Gets namespace to apply to Rule's added */ - public String getNamespaceURI() { - return wrappedRules.getNamespaceURI(); - } - - /** Sets namespace to apply to Rule's added subsequently */ - public void setNamespaceURI(String namespaceURI) { - wrappedRules.setNamespaceURI(namespaceURI); - } - - /** Gets Rule's which will be fired when the wrapped implementation returns no matches */ - public List getDefaults() { - return defaultRules; - } - - // --------------------------------------------------------- Public Methods - - public List match(String pattern) { - return match("", pattern); - } - - /** - * Return list of rules matching given pattern. - * If wrapped implementation returns any matches return those. - * Otherwise, return default matches. - */ - public List match(String namespaceURI, String pattern) { - List matches = wrappedRules.match(namespaceURI, pattern); - if (matches == null || matches.isEmpty()) { - // a little bit of defensive programming - return new ArrayList(defaultRules); - } - // otherwise - return matches; - } - - /** Adds a rule to be fired when wrapped implementation returns no matches */ - public void addDefault(Rule rule) { - // set up rule - if (wrappedRules.getDigester() != null) { - rule.setDigester(wrappedRules.getDigester()); - } - - if (wrappedRules.getNamespaceURI() != null) { - rule.setNamespaceURI(wrappedRules.getNamespaceURI()); - } - - defaultRules.add(rule); - allRules.add(rule); - } - - /** Gets all rules */ - public List rules() { - return allRules; - } - - /** Clears all Rule's */ - public void clear() { - wrappedRules.clear(); - allRules.clear(); - defaultRules.clear(); - } - - /** - * Adds a Rule to be fired on given pattern. - * Pattern matching is delegated to wrapped implementation. - */ - public void add(String pattern, Rule rule) { - wrappedRules.add(pattern, rule); - allRules.add(rule); - } -} +/* $Id: WithDefaultsRulesWrapper.java 299475 2004-06-26 17:41:32Z remm $ + * + * Copyright 2003-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.digester; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + *

        Rules Decorator that returns default rules + * when no matches are returned by the wrapped implementation.

        + * + *

        This allows default Rule instances to be added to any + * existing Rules implementation. These default Rule + * instances will be returned for any match for which the wrapped + * implementation does not return any matches.

        + *

        For example, + *

        + *   Rule alpha;
        + *   ...
        + *   WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
        + *   rules.addDefault(alpha);
        + *   ...
        + *   digester.setRules(rules);
        + *   ...
        + * 
        + * when a pattern does not match any other rule, then rule alpha will be called. + *

        + *

        WithDefaultsRulesWrapper follows the Decorator pattern.

        + * + * @since 1.6 + */ + +public class WithDefaultsRulesWrapper implements Rules { + + // --------------------------------------------------------- Fields + + /** The Rules implementation that this class wraps. */ + private Rules wrappedRules; + /** Rules to be fired when the wrapped implementations returns none. */ + private List defaultRules = new ArrayList(); + /** All rules (preserves order in which they were originally added) */ + private List allRules = new ArrayList(); + + // --------------------------------------------------------- Constructor + + /** + * Base constructor. + * + * @param wrappedRules the wrapped Rules implementation, not null + * @throws IllegalArgumentException when wrappedRules is null + */ + public WithDefaultsRulesWrapper(Rules wrappedRules) { + if (wrappedRules == null) { + throw new IllegalArgumentException("Wrapped rules must not be null"); + } + this.wrappedRules = wrappedRules; + } + + // --------------------------------------------------------- Properties + + /** Gets digester using these Rules */ + public Digester getDigester() { + return wrappedRules.getDigester(); + } + + /** Sets digeseter using these Rules */ + public void setDigester(Digester digester) { + wrappedRules.setDigester(digester); + Iterator it = defaultRules.iterator(); + while (it.hasNext()) { + Rule rule = (Rule) it.next(); + rule.setDigester(digester); + } + } + + /** Gets namespace to apply to Rule's added */ + public String getNamespaceURI() { + return wrappedRules.getNamespaceURI(); + } + + /** Sets namespace to apply to Rule's added subsequently */ + public void setNamespaceURI(String namespaceURI) { + wrappedRules.setNamespaceURI(namespaceURI); + } + + /** Gets Rule's which will be fired when the wrapped implementation returns no matches */ + public List getDefaults() { + return defaultRules; + } + + // --------------------------------------------------------- Public Methods + + public List match(String pattern) { + return match("", pattern); + } + + /** + * Return list of rules matching given pattern. + * If wrapped implementation returns any matches return those. + * Otherwise, return default matches. + */ + public List match(String namespaceURI, String pattern) { + List matches = wrappedRules.match(namespaceURI, pattern); + if (matches == null || matches.isEmpty()) { + // a little bit of defensive programming + return new ArrayList(defaultRules); + } + // otherwise + return matches; + } + + /** Adds a rule to be fired when wrapped implementation returns no matches */ + public void addDefault(Rule rule) { + // set up rule + if (wrappedRules.getDigester() != null) { + rule.setDigester(wrappedRules.getDigester()); + } + + if (wrappedRules.getNamespaceURI() != null) { + rule.setNamespaceURI(wrappedRules.getNamespaceURI()); + } + + defaultRules.add(rule); + allRules.add(rule); + } + + /** Gets all rules */ + public List rules() { + return allRules; + } + + /** Clears all Rule's */ + public void clear() { + wrappedRules.clear(); + allRules.clear(); + defaultRules.clear(); + } + + /** + * Adds a Rule to be fired on given pattern. + * Pattern matching is delegated to wrapped implementation. + */ + public void add(String pattern, Rule rule) { + wrappedRules.add(pattern, rule); + allRules.add(rule); + } +} diff --git a/java/org/apache/tomcat/util/digester/XercesParser.java b/java/org/apache/tomcat/util/digester/XercesParser.java index 55c03ff63..d4eff02af 100644 --- a/java/org/apache/tomcat/util/digester/XercesParser.java +++ b/java/org/apache/tomcat/util/digester/XercesParser.java @@ -1,189 +1,189 @@ -/* $Id: XercesParser.java 299768 2004-09-02 00:48:12Z yoavs $ - * - * Copyright 2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.digester; - -import java.lang.reflect.Method; -import java.util.Properties; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotRecognizedException; -import org.xml.sax.SAXNotSupportedException; - -/** - * Create a SAXParser based on the underlying Xerces version. - * Currently, Xerces 2.3 and up doesn't implement schema validation the same way - * 2.1 was. In other to support schema validation in a portable way between - * parser, some features/properties need to be set. - * - * @since 1.6 - */ - -public class XercesParser{ - - /** - * The Log to which all SAX event related logging calls will be made. - */ - protected static Log log = - LogFactory.getLog("org.apache.commons.digester.Digester.sax"); - - - /** - * The JAXP 1.2 property required to set up the schema location. - */ - private static final String JAXP_SCHEMA_SOURCE = - "http://java.sun.com/xml/jaxp/properties/schemaSource"; - - - /** - * The JAXP 1.2 property to set up the schemaLanguage used. - */ - protected static String JAXP_SCHEMA_LANGUAGE = - "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; - - - /** - * Xerces dynamic validation property - */ - protected static String XERCES_DYNAMIC = - "http://apache.org/xml/features/validation/dynamic"; - - - /** - * Xerces schema validation property - */ - protected static String XERCES_SCHEMA = - "http://apache.org/xml/features/validation/schema"; - - - /** - * A float representing the underlying Xerces version - */ - protected static float version; - - - /** - * The current Xerces version. - */ - protected static String versionNumber = null; - - - /** - * Return the current Xerces version. - * @return the current Xerces version. - */ - private static String getXercesVersion() { - // If for some reason we can't get the version, set it to 1.0. - String versionNumber = "1.0"; - try{ - // Use reflection to avoid a build dependency with Xerces. - Class versionClass = - Class.forName("org.apache.xerces.impl.Version"); - // Will return Xerces-J 2.x.0 - Method method = - versionClass.getMethod("getVersion", (Class[]) null); - String version = (String)method.invoke(null, (Object[]) null); - versionNumber = version.substring( "Xerces-J".length() , - version.lastIndexOf(".") ); - } catch (Exception ex){ - // Do nothing. - } - return versionNumber; - } - - - /** - * Create a SAXParser based on the underlying - * Xerces version. - * @param properties parser specific properties/features - * @return an XML Schema/DTD enabled SAXParser - */ - public static SAXParser newSAXParser(Properties properties) - throws ParserConfigurationException, - SAXException, - SAXNotSupportedException { - - SAXParserFactory factory = - (SAXParserFactory)properties.get("SAXParserFactory"); - - if (versionNumber == null){ - versionNumber = getXercesVersion(); - version = new Float( versionNumber ).floatValue(); - } - - // Note: 2.2 is completely broken (with XML Schema). - if (version > 2.1) { - - configureXerces(factory); - return factory.newSAXParser(); - } else { - SAXParser parser = factory.newSAXParser(); - configureOldXerces(parser,properties); - return parser; - } - } - - - /** - * Configure schema validation as recommended by the JAXP 1.2 spec. - * The properties object may contains information about - * the schema local and language. - * @param properties parser optional info - */ - private static void configureOldXerces(SAXParser parser, - Properties properties) - throws ParserConfigurationException, - SAXNotSupportedException { - - String schemaLocation = (String)properties.get("schemaLocation"); - String schemaLanguage = (String)properties.get("schemaLanguage"); - - try{ - if (schemaLocation != null) { - parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); - parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); - } - } catch (SAXNotRecognizedException e){ - log.info(parser.getClass().getName() + ": " - + e.getMessage() + " not supported."); - } - - } - - - /** - * Configure schema validation as recommended by the Xerces spec. - * Both DTD and Schema validation will be enabled simultaneously. - * @param factory SAXParserFactory to be configured - */ - private static void configureXerces(SAXParserFactory factory) - throws ParserConfigurationException, - SAXNotRecognizedException, - SAXNotSupportedException { - - factory.setFeature(XERCES_DYNAMIC, true); - factory.setFeature(XERCES_SCHEMA, true); - - } -} +/* $Id: XercesParser.java 299768 2004-09-02 00:48:12Z yoavs $ + * + * Copyright 2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.digester; + +import java.lang.reflect.Method; +import java.util.Properties; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotRecognizedException; +import org.xml.sax.SAXNotSupportedException; + +/** + * Create a SAXParser based on the underlying Xerces version. + * Currently, Xerces 2.3 and up doesn't implement schema validation the same way + * 2.1 was. In other to support schema validation in a portable way between + * parser, some features/properties need to be set. + * + * @since 1.6 + */ + +public class XercesParser{ + + /** + * The Log to which all SAX event related logging calls will be made. + */ + protected static Log log = + LogFactory.getLog("org.apache.commons.digester.Digester.sax"); + + + /** + * The JAXP 1.2 property required to set up the schema location. + */ + private static final String JAXP_SCHEMA_SOURCE = + "http://java.sun.com/xml/jaxp/properties/schemaSource"; + + + /** + * The JAXP 1.2 property to set up the schemaLanguage used. + */ + protected static String JAXP_SCHEMA_LANGUAGE = + "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; + + + /** + * Xerces dynamic validation property + */ + protected static String XERCES_DYNAMIC = + "http://apache.org/xml/features/validation/dynamic"; + + + /** + * Xerces schema validation property + */ + protected static String XERCES_SCHEMA = + "http://apache.org/xml/features/validation/schema"; + + + /** + * A float representing the underlying Xerces version + */ + protected static float version; + + + /** + * The current Xerces version. + */ + protected static String versionNumber = null; + + + /** + * Return the current Xerces version. + * @return the current Xerces version. + */ + private static String getXercesVersion() { + // If for some reason we can't get the version, set it to 1.0. + String versionNumber = "1.0"; + try{ + // Use reflection to avoid a build dependency with Xerces. + Class versionClass = + Class.forName("org.apache.xerces.impl.Version"); + // Will return Xerces-J 2.x.0 + Method method = + versionClass.getMethod("getVersion", (Class[]) null); + String version = (String)method.invoke(null, (Object[]) null); + versionNumber = version.substring( "Xerces-J".length() , + version.lastIndexOf(".") ); + } catch (Exception ex){ + // Do nothing. + } + return versionNumber; + } + + + /** + * Create a SAXParser based on the underlying + * Xerces version. + * @param properties parser specific properties/features + * @return an XML Schema/DTD enabled SAXParser + */ + public static SAXParser newSAXParser(Properties properties) + throws ParserConfigurationException, + SAXException, + SAXNotSupportedException { + + SAXParserFactory factory = + (SAXParserFactory)properties.get("SAXParserFactory"); + + if (versionNumber == null){ + versionNumber = getXercesVersion(); + version = new Float( versionNumber ).floatValue(); + } + + // Note: 2.2 is completely broken (with XML Schema). + if (version > 2.1) { + + configureXerces(factory); + return factory.newSAXParser(); + } else { + SAXParser parser = factory.newSAXParser(); + configureOldXerces(parser,properties); + return parser; + } + } + + + /** + * Configure schema validation as recommended by the JAXP 1.2 spec. + * The properties object may contains information about + * the schema local and language. + * @param properties parser optional info + */ + private static void configureOldXerces(SAXParser parser, + Properties properties) + throws ParserConfigurationException, + SAXNotSupportedException { + + String schemaLocation = (String)properties.get("schemaLocation"); + String schemaLanguage = (String)properties.get("schemaLanguage"); + + try{ + if (schemaLocation != null) { + parser.setProperty(JAXP_SCHEMA_LANGUAGE, schemaLanguage); + parser.setProperty(JAXP_SCHEMA_SOURCE, schemaLocation); + } + } catch (SAXNotRecognizedException e){ + log.info(parser.getClass().getName() + ": " + + e.getMessage() + " not supported."); + } + + } + + + /** + * Configure schema validation as recommended by the Xerces spec. + * Both DTD and Schema validation will be enabled simultaneously. + * @param factory SAXParserFactory to be configured + */ + private static void configureXerces(SAXParserFactory factory) + throws ParserConfigurationException, + SAXNotRecognizedException, + SAXNotSupportedException { + + factory.setFeature(XERCES_DYNAMIC, true); + factory.setFeature(XERCES_SCHEMA, true); + + } +} diff --git a/java/org/apache/tomcat/util/digester/package.html b/java/org/apache/tomcat/util/digester/package.html index 7098378e4..c14e98ecc 100644 --- a/java/org/apache/tomcat/util/digester/package.html +++ b/java/org/apache/tomcat/util/digester/package.html @@ -1,1275 +1,1275 @@ - - -Package Documentation for org.apache.commons.digester Package - - -The Digester package provides for rules-based processing of arbitrary -XML documents. -

        -
        - - - -

        External Dependencies

        - - - - -

        Introduction

        - -

        In many application environments that deal with XML-formatted data, it is -useful to be able to process an XML document in an "event driven" manner, -where particular Java objects are created (or methods of existing objects -are invoked) when particular patterns of nested XML elements have been -recognized. Developers familiar with the Simple API for XML Parsing (SAX) -approach to processing XML documents will recognize that the Digester provides -a higher level, more developer-friendly interface to SAX events, because most -of the details of navigating the XML element hierarchy are hidden -- allowing -the developer to focus on the processing to be performed.

        - -

        In order to use a Digester, the following basic steps are required:

        -
          -
        • Create a new instance of the - org.apache.commons.digester.Digester class. Previously - created Digester instances may be safely reused, as long as you have - completed any previously requested parse, and you do not try to utilize - a particular Digester instance from more than one thread at a time.
        • -
        • Set any desired configuration properties - that will customize the operation of the Digester when you next initiate - a parse operation.
        • -
        • Optionally, push any desired initial object(s) onto the Digester's - object stack.
        • -
        • Register all of the element matching patterns - for which you wish to have processing rules - fired when this pattern is recognized in an input document. You may - register as many rules as you like for any particular pattern. If there - is more than one rule for a given pattern, the rules will be executed in - the order that they were listed.
        • -
        • Call the digester.parse() method, passing a reference to the - XML document to be parsed in one of a variety of forms. See the - Digester.parse() - documentation for details. Note that you will need to be prepared to - catch any IOException or SAXException that is - thrown by the parser, or any runtime expression that is thrown by one of - the processing rules.
        • -
        - -

        For example code, see the usage -examples, and the FAQ .

        - - -

        Digester Configuration Properties

        - -

        A org.apache.commons.digester.Digester instance contains several -configuration properties that can be used to customize its operation. These -properties must be configured before you call one of the -parse() variants, in order for them to take effect on that -parse.

        - -
        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        PropertyDescription
        classLoaderYou can optionally specify the class loader that will be used to - load classes when required by the ObjectCreateRule - and FactoryCreateRule rules. If not specified, - application classes will be loaded from the thread's context - class loader (if the useContextClassLoader property - is set to true) or the same class loader that was - used to load the Digester class itself.
        errorHandlerYou can optionally specify a SAX ErrorHandler that - is notified when parsing errors occur. By default, any parsing - errors that are encountered are logged, but Digester will continue - processing as well.
        namespaceAwareA boolean that is set to true to perform parsing in a - manner that is aware of XML namespaces. Among other things, this - setting affects how elements are matched to processing rules. See - Namespace Aware Parsing for more - information.
        ruleNamespaceURIThe public URI of the namespace for which all subsequently added - rules are associated, or null for adding rules that - are not associated with any namespace. See - Namespace Aware Parsing for more - information.
        rulesThe Rules component that actually performs matching of - Rule instances against the current element nesting - pattern is pluggable. By default, Digester includes a - Rules implementation that behaves as described in this - document. See - Pluggable Rules Processing for - more information.
        useContextClassLoader - A boolean that is set to true if you want application - classes required by FactoryCreateRule and - ObjectCreateRule to be loaded from the context class - loader of the current thread. By default, classes will be loaded - from the class loader that loaded this Digester class. - NOTE - This property is ignored if you set a - value for the classLoader property; that class loader - will be used unconditionally.
        validatingA boolean that is set to true if you wish to validate - the XML document against a Document Type Definition (DTD) that is - specified in its DOCTYPE declaration. The default - value of false requests a parse that only detects - "well formed" XML documents, rather than "valid" ones.
        -
        - -

        In addition to the scalar properties defined above, you can also register -a local copy of a Document Type Definition (DTD) that is referenced in a -DOCTYPE declaration. Such a registration tells the XML parser -that, whenever it encounters a DOCTYPE declaration with the -specified public identifier, it should utilize the actual DTD content at the -registered system identifier (a URL), rather than the one in the -DOCTYPE declaration.

        - -

        For example, the Struts framework controller servlet uses the following -registration in order to tell Struts to use a local copy of the DTD for the -Struts configuration file. This allows usage of Struts in environments that -are not connected to the Internet, and speeds up processing even at Internet -connected sites (because it avoids the need to go across the network).

        - -
        -    URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
        -    digester.register
        -      ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
        -       url.toString());
        -
        - -

        As a side note, the system identifier used in this example is the path -that would be passed to java.lang.ClassLoader.getResource() -or java.lang.ClassLoader.getResourceAsStream(). The actual DTD -resource is loaded through the same class loader that loads all of the Struts -classes -- typically from the struts.jar file.

        - - -

        The Object Stack

        - -

        One very common use of org.apache.commons.digester.Digester -technology is to dynamically construct a tree of Java objects, whose internal -organization, as well as the details of property settings on these objects, -are configured based on the contents of the XML document. In fact, the -primary reason that the Digester package was created (it was originally part -of Struts, and then moved to the Commons project because it was recognized -as being generally useful) was to facilitate the -way that the Struts controller servlet configures itself based on the contents -of your application's struts-config.xml file.

        - -

        To facilitate this usage, the Digester exposes a stack that can be -manipulated by processing rules that are fired when element matching patterns -are satisfied. The usual stack-related operations are made available, -including the following:

        -
          -
        • clear() - Clear the current contents - of the object stack.
        • -
        • peek() - Return a reference to the top - object on the stack, without removing it.
        • -
        • pop() - Remove the top object from the - stack and return it.
        • -
        • push() - Push a new - object onto the top of the stack.
        • -
        - -

        A typical design pattern, then, is to fire a rule that creates a new object -and pushes it on the stack when the beginning of a particular XML element is -encountered. The object will remain there while the nested content of this -element is processed, and it will be popped off when the end of the element -is encountered. As we will see, the standard "object create" processing rule -supports exactly this functionalility in a very convenient way.

        - -

        Several potential issues with this design pattern are addressed by other -features of the Digester functionality:

        -
          -
        • How do I relate the objects being created to each other? - The - Digester supports standard processing rules that pass the top object on - the stack as an argument to a named method on the next-to-top object on - the stack (or vice versa). This rule makes it easy to establish - parent-child relationships between these objects. One-to-one and - one-to-many relationships are both easy to construct.
        • -
        • How do I retain a reference to the first object that was created? - As you review the description of what the "object create" processing rule - does, it would appear that the first object you create (i.e. the object - created by the outermost XML element you process) will disappear from the - stack by the time that XML parsing is completed, because the end of the - element would have been encountered. However, Digester will maintain a - reference to the very first object ever pushed onto the object stack, - and will return it to you - as the return value from the parse() call. Alternatively, - you can push a reference to some application object onto the stack before - calling parse(), and arrange that a parent-child relationship - be created (by appropriate processing rules) between this manually pushed - object and the ones that are dynamically created. In this way, - the pushed object will retain a reference to the dynamically created objects - (and therefore all of their children), and will be returned to you after - the parse finishes as well.
        • -
        - - -

        Element Matching Patterns

        - -

        A primary feature of the org.apache.commons.digester.Digester -parser is that the Digester automatically navigates the element hierarchy of -the XML document you are parsing for you, without requiring any developer -attention to this process. Instead, you focus on deciding what functions you -would like to have performed whenver a certain arrangement of nested elements -is encountered in the XML document being parsed. The mechanism for specifying -such arrangements are called element matching patterns. - -

        A very simple element matching pattern is a simple string like "a". This -pattern is matched whenever an <a> top-level element is -encountered in the XML document, no matter how many times it occurs. Note that -nested <a> elements will not match this -pattern -- we will describe means to support this kind of matching later.

      • - -

        The next step up in matching pattern complexity is "a/b". This pattern will -be matched when a <b> element is found nested inside a -top-level <a> element. Again, this match can occur as many -times as desired, depending on the content of the XML document being parsed. -You can use multiple slashes to define a hierarchy of any desired depth that -will be matched appropriately.

        - -

        For example, assume you have registered processing rules that match patterns -"a", "a/b", and "a/b/c". For an input XML document with the following -contents, the indicated patterns will be matched when the corresponding element -is parsed:

        -
        -  <a>         -- Matches pattern "a"
        -    <b>       -- Matches pattern "a/b"
        -      <c/>    -- Matches pattern "a/b/c"
        -      <c/>    -- Matches pattern "a/b/c"
        -    </b>
        -    <b>       -- Matches pattern "a/b"
        -      <c/>    -- Matches pattern "a/b/c"
        -      <c/>    -- Matches pattern "a/b/c"
        -      <c/>    -- Matches pattern "a/b/c"
        -    </b>
        -  </a>
        -
        - -

        It is also possible to match a particular XML element, no matter how it is -nested (or not nested) in the XML document, by using the "*" wildcard character -in your matching pattern strings. For example, an element matching pattern -of "*/a" will match an <a> element at any nesting position -within the document.

        - -

        It is quite possible that, when a particular XML element is being parsed, -the pattern for more than one registered processing rule will be matched - either because you registered more than one processing rule with the same -matching pattern, or because one more more exact pattern matches and wildcard -pattern matches are satisfied by the same element.

        - -

        When this occurs, the corresponding processing rules will all be fired in order. -begin (and body) method calls are executed in the -order that the Rules where initially registered with the -Digester, whilst end method calls are execute in -reverse order. In other words - the order is first in, last out.

        - - -

        Processing Rules

        - -

        The previous section documented how you identify -when you wish to have certain actions take place. The purpose -of processing rules is to define what should happen when the -patterns are matched.

        - -

        Formally, a processing rule is a Java class that subclasses the -org.apache.commons.digester.Rule interface. Each Rule -implements one or more of the following event methods that are called at -well-defined times when the matching patterns corresponding to this rule -trigger it:

        -
          -
        • begin() - - Called when the beginning of the matched XML element is encountered. A - data structure containing all of the attributes corresponding to this - element are passed as well.
        • -
        • body() - - Called when nested content (that is not itself XML elements) of the - matched element is encountered. Any leading or trailing whitespace will - have been removed as part of the parsing process.
        • -
        • end() - Called when the ending of the matched - XML element is encountered. If nested XML elements that matched other - processing rules was included in the body of this element, the appropriate - processing rules for the matched rules will have already been completed - before this method is called.
        • -
        • finish() - Called when the parse has - been completed, to give each rule a chance to clean up any temporary data - they might have created and cached.
        • -
        - -

        As you are configuring your digester, you can call the -addRule() method to register a specific element matching pattern, -along with an instance of a Rule class that will have its event -handling methods called at the appropriate times, as described above. This -mechanism allows you to create Rule implementation classes -dynamically, to implement any desired application specific functionality.

        - -

        In addition, a set of processing rule implementation classes are provided, -which deal with many common programming scenarios. These classes include the -following:

        -
          -
        • ObjectCreateRule - When the - begin() method is called, this rule instantiates a new - instance of a specified Java class, and pushes it on the stack. The - class name to be used is defaulted according to a parameter passed to - this rule's constructor, but can optionally be overridden by a classname - passed via the specified attribute to the XML element being processed. - When the end() method is called, the top object on the stack - (presumably, the one we added in the begin() method) will - be popped, and any reference to it (within the Digester) will be - discarded.
        • -
        • FactoryCreateRule - A variation of - ObjectCreateRule that is useful when the Java class with - which you wish to create an object instance does not have a no-arguments - constructor, or where you wish to perform other setup processing before - the object is handed over to the Digester.
        • -
        • SetPropertiesRule - When the - begin() method is called, the digester uses the standard - Java Reflection API to identify any JavaBeans property setter methods - (on the object at the top of the digester's stack) - who have property names that match the attributes specified on this XML - element, and then call them individually, passing the corresponding - attribute values. These natural mappings can be overridden. This allows - (for example) a class attribute to be mapped correctly. - It is recommended that this feature should not be overused - in most cases, - it's better to use the standard BeanInfo mechanism. - A very common idiom is to define an object create - rule, followed by a set properties rule, with the same element matching - pattern. This causes the creation of a new Java object, followed by - "configuration" of that object's properties based on the attributes - of the same XML element that created this object.
        • -
        • SetPropertyRule - When the - begin() method is called, the digester calls a specified - property setter (where the property itself is named by an attribute) - with a specified value (where the value is named by another attribute), - on the object at the top of the digester's stack. - This is useful when your XML file conforms to a particular DTD, and - you wish to configure a particular property that does not have a - corresponding attribute in the DTD.
        • -
        • SetNextRule - When the - end() method is called, the digester analyzes the - next-to-top element on the stack, looking for a property setter method - for a specified property. It then calls this method, passing the object - at the top of the stack as an argument. This rule is commonly used to - establish one-to-many relationships between the two objects, with the - method name commonly being something like "addChild".
        • -
        • SetTopRule - When the - end() method is called, the digester analyzes the - top element on the stack, looking for a property setter method for a - specified property. It then calls this method, passing the next-to-top - object on the stack as an argument. This rule would be used as an - alternative to a SetNextRule, with a typical method name "setParent", - if the API supported by your object classes prefers this approach.
        • -
        • CallMethodRule - This rule sets up a - method call to a named method of the top object on the digester's stack, - which will actually take place when the end() method is - called. You configure this rule by specifying the name of the method - to be called, the number of arguments it takes, and (optionally) the - Java class name(s) defining the type(s) of the method's arguments. - The actual parameter values, if any, will typically be accumulated from - the body content of nested elements within the element that triggered - this rule, using the CallParamRule discussed next.
        • -
        • CallParamRule - This rule identifies - the source of a particular numbered (zero-relative) parameter for a - CallMethodRule within which we are nested. You can specify that the - parameter value be taken from a particular named attribute, or from the - nested body content of this element.
        • -
        • NodeCreateRule - A specialized rule - that converts part of the tree into a DOM Node and then - pushes it onto the stack.
        • -
        - -

        You can create instances of the standard Rule classes and -register them by calling digester.addRule(), as described above. -However, because their usage is so common, shorthand registration methods are -defined for each of the standard rules, directly on the Digester -class. For example, the following code sequence:

        -
        -    Rule rule = new SetNextRule(digester, "addChild",
        -                                "com.mycompany.mypackage.MyChildClass");
        -    digester.addRule("a/b/c", rule);
        -
        -

        can be replaced by:

        -
        -    digester.addSetNext("a/b/c", "addChild",
        -                        "com.mycompany.mypackage.MyChildClass");
        -
        - - -

        Logging

        - -

        Logging is a vital tool for debugging Digester rulesets. Digester can log -copious amounts of debugging information. So, you need to know how logging -works before you start using Digester seriously.

        - -

        Digester uses -Jakarta Commons -Logging. This component is not really a logging framework - rather -an extensible, configurable bridge. It can be configured to swallow all log -messages, to provide very basic logging by itself or to pass logging messages -on to more sophisticated logging frameworks. Commons-Logging comes with -connectors for many popular logging frameworks. Consult the commons-logging -documentation for more information.

        - -

        Two main logs are used by Digester:

        -
          -
        • SAX-related messages are logged to - org.apache.commons.digester.Digester.sax. - This log gives information about the basic SAX events received by - Digester.
        • -
        • org.apache.commons.digester.Digester is used - for everything else. You'll probably want to have this log turned up during - debugging but turned down during production due to the high message - volume.
        • -
        - -

        Complete documentation of how to configure Commons-Logging can be found -in the Commons Logging package documentation. However, as a simple example, -let's assume that you want to use the SimpleLog implementation -that is included in Commons-Logging, and set up Digester to log events from -the Digester logger at the DEBUG level, while you want to log -events from the Digester.log logger at the INFO level. You can -accomplish this by creating a commons-logging.properties file -in your classpath (or setting corresponding system properties on the command -line that starts your application) with the following contents:

        -
        -  org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
        -  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug
        -  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info
        -
        - - -

        Usage Examples

        - - -
        Creating a Simple Object Tree
        - -

        Let's assume that you have two simple JavaBeans, Foo and -Bar, with the following method signatures:

        -
        -  package mypackage;
        -  public class Foo {
        -    public void addBar(Bar bar);
        -    public Bar findBar(int id);
        -    public Iterator getBars();
        -    public String getName();
        -    public void setName(String name);
        -  }
        -
        -  public mypackage;
        -  public class Bar {
        -    public int getId();
        -    public void setId(int id);
        -    public String getTitle();
        -    public void setTitle(String title);
        -  }
        -
        - -

        and you wish to use Digester to parse the following XML document:

        - -
        -  <foo name="The Parent">
        -    <bar id="123" title="The First Child"/>
        -    <bar id="456" title="The Second Child"/>
        -  </foo>
        -
        - -

        A simple approach will be to use the following Digester in the following way -to set up the parsing rules, and then process an input file containing this -document:

        - -
        -  Digester digester = new Digester();
        -  digester.setValidating(false);
        -  digester.addObjectCreate("foo", "mypackage.Foo");
        -  digester.addSetProperties("foo");
        -  digester.addObjectCreate("foo/bar", "mypackage.Bar");
        -  digester.addSetProperties("foo/bar");
        -  digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");
        -  Foo foo = (Foo) digester.parse();
        -
        - -

        In order, these rules do the following tasks:

        -
          -
        1. When the outermost <foo> element is encountered, - create a new instance of mypackage.Foo and push it - on to the object stack. At the end of the <foo> - element, this object will be popped off of the stack.
        2. -
        3. Cause properties of the top object on the stack (i.e. the Foo - object that was just created and pushed) to be set based on the values - of the attributes of this XML element.
        4. -
        5. When a nested <bar> element is encountered, - create a new instance of mypackage.Bar and push it - on to the object stack. At the end of the <bar> - element, this object will be popped off of the stack (i.e. after the - remaining rules matching foo/bar are processed).
        6. -
        7. Cause properties of the top object on the stack (i.e. the Bar - object that was just created and pushed) to be set based on the values - of the attributes of this XML element. Note that type conversions - are automatically performed (such as String to int for the id - property), for all converters registered with the ConvertUtils - class from commons-beanutils package.
        8. -
        9. Cause the addBar method of the next-to-top element on the - object stack (which is why this is called the "set next" rule) - to be called, passing the element that is on the top of the stack, which - must be of type mypackage.Bar. This is the rule that causes - the parent/child relationship to be created.
        10. -
        - -

        Once the parse is completed, the first object that was ever pushed on to the -stack (the Foo object in this case) is returned to you. It will -have had its properties set, and all of its child Bar objects -created for you.

        - - -
        Processing A Struts Configuration File
        - -

        As stated earlier, the primary reason that the -Digester package was created is because the -Struts controller servlet itself needed a robust, flexible, easy to extend -mechanism for processing the contents of the struts-config.xml -configuration that describes nearly every aspect of a Struts-based application. -Because of this, the controller servlet contains a comprehensive, real world, -example of how the Digester can be employed for this type of a use case. -See the initDigester() method of class -org.apache.struts.action.ActionServlet for the code that creates -and configures the Digester to be used, and the initMapping() -method for where the parsing actually takes place.

        - -

        (Struts binary and source distributions can be acquired at -http://jakarta.apache.org/struts/.)

        - -

        The following discussion highlights a few of the matching patterns and -processing rules that are configured, to illustrate the use of some of the -Digester features. First, let's look at how the Digester instance is -created and initialized:

        -
        -    Digester digester = new Digester();
        -    digester.push(this); // Push controller servlet onto the stack
        -    digester.setValidating(true);
        -
        - -

        We see that a new Digester instance is created, and is configured to use -a validating parser. Validation will occur against the struts-config_1_0.dtd -DTD that is included with Struts (as discussed earlier). In order to provide -a means of tracking the configured objects, the controller servlet instance -itself will be added to the digester's stack.

        - -
        -    digester.addObjectCreate("struts-config/global-forwards/forward",
        -                             forwardClass, "className");
        -    digester.addSetProperties("struts-config/global-forwards/forward");
        -    digester.addSetNext("struts-config/global-forwards/forward",
        -                        "addForward",
        -                        "org.apache.struts.action.ActionForward");
        -    digester.addSetProperty
        -      ("struts-config/global-forwards/forward/set-property",
        -       "property", "value");
        -
        - -

        The rules created by these lines are used to process the global forward -declarations. When a <forward> element is encountered, -the following actions take place:

        -
          -
        • A new object instance is created -- the ActionForward - instance that will represent this definition. The Java class name - defaults to that specified as an initialization parameter (which - we have stored in the String variable forwardClass), but can - be overridden by using the "className" attribute (if it is present in the - XML element we are currently parsing). The new ActionForward - instance is pushed onto the stack.
        • -
        • The properties of the ActionForward instance (at the top of - the stack) are configured based on the attributes of the - <forward> element.
        • -
        • Nested occurrences of the <set-property> element - cause calls to additional property setter methods to occur. This is - required only if you have provided a custom implementation of the - ActionForward class with additional properties that are - not included in the DTD.
        • -
        • The addForward() method of the next-to-top object on - the stack (i.e. the controller servlet itself) will be called, passing - the object at the top of the stack (i.e. the ActionForward - instance) as an argument. This causes the global forward to be - registered, and as a result of this it will be remembered even after - the stack is popped.
        • -
        • At the end of the <forward> element, the top element - (i.e. the ActionForward instance) will be popped off the - stack.
        • -
        - -

        Later on, the digester is actually executed as follows:

        -
        -    InputStream input =
        -      getServletContext().getResourceAsStream(config);
        -    ...
        -    try {
        -        digester.parse(input);
        -        input.close();
        -    } catch (SAXException e) {
        -        ... deal with the problem ...
        -    }
        -
        - -

        As a result of the call to parse(), all of the configuration -information that was defined in the struts-config.xml file is -now represented as collections of objects cached within the Struts controller -servlet, as well as being exposed as servlet context attributes.

        - - -
        Parsing Body Text In XML Files
        - -

        The Digester module also allows you to process the nested body text in an -XML file, not just the elements and attributes that are encountered. The -following example is based on an assumed need to parse the web application -deployment descriptor (/WEB-INF/web.xml) for the current web -application, and record the configuration information for a particular -servlet. To record this information, assume the existence of a bean class -with the following method signatures (among others):

        -
        -  package com.mycompany;
        -  public class ServletBean {
        -    public void setServletName(String servletName);
        -    public void setServletClass(String servletClass);
        -    public void addInitParam(String name, String value);
        -  }
        -
        - -

        We are going to process the web.xml file that declares the -controller servlet in a typical Struts-based application (abridged for -brevity in this example):

        -
        -  <web-app>
        -    ...
        -    <servlet>
        -      <servlet-name>action</servlet-name>
        -      <servlet-class>org.apache.struts.action.ActionServlet<servlet-class>
        -      <init-param>
        -        <param-name>application</param-name>
        -        <param-value>org.apache.struts.example.ApplicationResources<param-value>
        -      </init-param>
        -      <init-param>
        -        <param-name>config</param-name>
        -        <param-value>/WEB-INF/struts-config.xml<param-value>
        -      </init-param>
        -    </servlet>
        -    ...
        -  </web-app>
        -
        - -

        Next, lets define some Digester processing rules for this input file:

        -
        -  digester.addObjectCreate("web-app/servlet",
        -                           "com.mycompany.ServletBean");
        -  digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
        -  digester.addCallMethod("web-app/servlet/servlet-class",
        -                         "setServletClass", 0);
        -  digester.addCallMethod("web-app/servlet/init-param",
        -                         "addInitParam", 2);
        -  digester.addCallParam("web-app/servlet/init-param/param-name", 0);
        -  digester.addCallParam("web-app/servlet/init-param/param-value", 1);
        -
        - -

        Now, as elements are parsed, the following processing occurs:

        -
          -
        • <servlet> - A new com.mycompany.ServletBean - object is created, and pushed on to the object stack.
        • -
        • <servlet-name> - The setServletName() method - of the top object on the stack (our ServletBean) is called, - passing the body content of this element as a single parameter.
        • -
        • <servlet-class> - The setServletClass() method - of the top object on the stack (our ServletBean) is called, - passing the body content of this element as a single parameter.
        • -
        • <init-param> - A call to the addInitParam - method of the top object on the stack (our ServletBean) is - set up, but it is not called yet. The call will be - expecting two String parameters, which must be set up by - subsequent call parameter rules.
        • -
        • <param-name> - The body content of this element is assigned - as the first (zero-relative) argument to the call we are setting up.
        • -
        • <param-value> - The body content of this element is assigned - as the second (zero-relative) argument to the call we are setting up.
        • -
        • </init-param> - The call to addInitParam() - that we have set up is now executed, which will cause a new name-value - combination to be recorded in our bean.
        • -
        • <init-param> - The same set of processing rules are fired - again, causing a second call to addInitParam() with the - second parameter's name and value.
        • -
        • </servlet> - The element on the top of the object stack - (which should be the ServletBean we pushed earlier) is - popped off the object stack.
        • -
        - - - -

        Namespace Aware Parsing

        - -

        For digesting XML documents that do not use XML namespaces, the default -behavior of Digester, as described above, is generally sufficient. -However, if the document you are processing uses namespaces, it is often -convenient to have sets of Rule instances that are only -matched on elements that use the prefix of a particular namespace. This -approach, for example, makes it possible to deal with element names that are -the same in different namespaces, but where you want to perform different -processing for each namespace.

        - -

        Digester does not provide full support for namespaces, but does provide -sufficient to accomplish most tasks. Enabling digester's namespace support -is done by following these steps:

        - -
          -
        1. Tell Digester that you will be doing namespace - aware parsing, by adding this statement in your initalization - of the Digester's properties: -
          -    digester.setNamespaceAware(true);
          -    
        2. -
        3. Declare the public namespace URI of the namespace with which - following rules will be associated. Note that you do not - make any assumptions about the prefix - the XML document author - is free to pick whatever prefix they want: -
          -    digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
          -    
        4. -
        5. Add the rules that correspond to this namespace, in the usual way, - by calling methods like addObjectCreate() or - addSetProperties(). In the matching patterns you specify, - use only the local name portion of the elements (i.e. the - part after the prefix and associated colon (":") character: -
          -    digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
          -    digester.addSetProperties("foo/bar");
          -    
        6. -
        7. Repeat the previous two steps for each additional public namespace URI - that should be recognized on this Digester run.
        8. -
        - -

        Now, consider that you might wish to digest the following document, using -the rules that were set up in the steps above:

        -
        -<m:foo
        -   xmlns:m="http://www.mycompany.com/MyNamespace"
        -   xmlns:y="http://www.yourcompany.com/YourNamespace">
        -
        -  <m:bar name="My Name" value="My Value"/>
        -
        -  <y:bar id="123" product="Product Description"/>L
        -
        -</x:foo>
        -
        - -

        Note that your object create and set properties rules will be fired for the -first occurrence of the bar element, but not the -second one. This is because we declared that our rules only matched -for the particular namespace we are interested in. Any elements in the -document that are associated with other namespaces (or no namespaces at all) -will not be processed. In this way, you can easily create rules that digest -only the portions of a compound document that they understand, without placing -any restrictions on what other content is present in the document.

        - -

        You might also want to look at Encapsulated -Rule Sets if you wish to reuse a particular set of rules, associated -with a particular namespace, in more than one application context.

        - -

        Using Namespace Prefixes In Pattern Matching

        - -

        Using rules with namespaces is very useful when you have orthogonal rulesets. -One ruleset applies to a namespace and is independent of other rulesets applying -to other namespaces. However, if your rule logic requires mixed namespaces, then -matching namespace prefix patterns might be a better strategy.

        - -

        When you set the NamespaceAware property to false, digester uses -the qualified element name (which includes the namespace prefix) rather than the -local name as the patten component for the element. This means that your pattern -matches can include namespace prefixes as well as element names. So, rather than -create namespace-aware rules, create pattern matches including the namespace -prefixes.

        - -

        For example, (with NamespaceAware false), the pattern -'foo:bar' will match a top level element named 'bar' in the -namespace with (local) prefix 'foo'.

        - -

        Limitations of Digester Namespace support

        -

        Digester does not provide general "xpath-compliant" matching; -only the namespace attached to the last element in the match path -is involved in the matching process. Namespaces attached to parent -elements are ignored for matching purposes.

        - - - -

        Pluggable Rules Processing

        - -

        By default, Digester selects the rules that match a particular -pattern of nested elements as described under -Element Matching Patterns. If you prefer to use -different selection policies, however, you can create your own implementation -of the org.apache.commons.digester.Rules interface, -or subclass the corresponding convenience base class -org.apache.commons.digester.RulesBase. -Your implementation of the match() method will be called when the -processing for a particular element is started or ended, and you must return -a List of the rules that are relevant for the current nesting -pattern. The order of the rules you return is significant, -and should match the order in which rules were initally added.

        - -

        Your policy for rule selection should generally be sensitive to whether -Namespace Aware Parsing is taking place. In -general, if namespaceAware is true, you should select only rules -that:

        -
          -
        • Are registered for the public namespace URI that corresponds to the - prefix being used on this element.
        • -
        • Match on the "local name" portion of the element (so that the document - creator can use any prefix that they like).
        • -
        - -

        ExtendedBaseRules

        -

        ExtendedBaseRules, -adds some additional expression syntax for pattern matching -to the default mechanism, but it also executes more slowly. See the -JavaDocs for more details on the new pattern matching syntax, and suggestions -on when this implementation should be used. To use it, simply do the -following as part of your Digester initialization:

        - -
        -  Digester digester = ...
        -  ...
        -  digester.setRules(new ExtendedBaseRules());
        -  ...
        -
        - -

        RegexRules

        -

        RegexRules is an advanced Rules -implementation which does not build on the default pattern matching rules. -It uses a pluggable RegexMatcher implementation to test -if a path matches the pattern for a Rule. All matching rules are returned -(note that this behaviour differs from longest matching rule of the default - pattern matching rules). See the Java Docs for more details. -

        -

        -Example usage: -

        - -
        -  Digester digester = ...
        -  ...
        -  digester.setRules(new RegexRules(new SimpleRegexMatcher()));
        -  ...
        -
        -
        RegexMatchers
        -

        -Digester ships only with one RegexMatcher -implementation: SimpleRegexMatcher. -This implementation is unsophisticated and lacks many good features -lacking in more power Regex libraries. There are some good reasons -why this approach was adopted. The first is that SimpleRegexMatcher -is simple, it is easy to write and runs quickly. The second has to do with -the way that RegexRules is intended to be used. -

        -

        -There are many good regex libraries available. (For example -Jakarta ORO, -Jakarta Regex, -GNU Regex and - -Java 1.4 Regex) -Not only do different people have different personal tastes when it comes to -regular expression matching but these products all offer different functionality -and different strengths. -

        -

        -The pluggable RegexMatcher is a thin bridge -designed to adapt other Regex systems. This allows any Regex library the user -desires to be plugged in and used just by creating one class. -Digester does not (currently) ship with bridges to the major -regex (to allow the dependencies required by Digester -to be kept to a minimum). -

        - -

        WithDefaultsRulesWrapper

        -

        - WithDefaultsRulesWrapper allows -default Rule instances to be added to any existing -Rules implementation. These default Rule instances -will be returned for any match for which the wrapped implementation does not -return any matches. -

        -

        -For example, -

        -    Rule alpha;
        -    ...
        -    WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
        -    rules.addDefault(alpha);
        -    ...
        -    digester.setRules(rules);
        -    ...
        -
        -when a pattern does not match any other rule, then rule alpha will be called. -

        -

        -WithDefaultsRulesWrapper follows the Decorator pattern. -

        - - -

        Encapsulated Rule Sets

        - -

        All of the examples above have described a scenario where the rules to be -processed are registered with a Digester instance immediately -after it is created. However, this approach makes it difficult to reuse the -same set of rules in more than one application environment. Ideally, one -could package a set of rules into a single class, which could be easily -loaded and registered with a Digester instance in one easy step. -

        - -

        The RuleSet interface (and the convenience base -class RuleSetBase) make it possible to do this. -In addition, the rule instances registered with a particular -RuleSet can optionally be associated with a particular namespace, -as described under Namespace Aware Processing.

        - -

        An example of creating a RuleSet might be something like this: -

        -
        -public class MyRuleSet extends RuleSetBase {
        -
        -  public MyRuleSet() {
        -    this("");
        -  }
        -
        -  public MyRuleSet(String prefix) {
        -    super();
        -    this.prefix = prefix;
        -    this.namespaceURI = "http://www.mycompany.com/MyNamespace";
        -  }
        -
        -  protected String prefix = null;
        -
        -  public void addRuleInstances(Digester digester) {
        -    digester.addObjectCreate(prefix + "foo/bar",
        -      "com.mycompany.MyFoo");
        -    digester.addSetProperties(prefix + "foo/bar");
        -  }
        -
        -}
        -
        - -

        You might use this RuleSet as follow to initialize a -Digester instance:

        -
        -  Digester digester = new Digester();
        -  ... configure Digester properties ...
        -  digester.addRuleSet(new MyRuleSet("baz/"));
        -
        - -

        A couple of interesting notes about this approach:

        -
          -
        • The application that is using these rules does not need to know anything - about the fact that the RuleSet being used is associated - with a particular namespace URI. That knowledge is emedded inside the - RuleSet class itself.
        • -
        • If desired, you could make a set of rules work for more than one - namespace URI by providing constructors on the RuleSet to - allow this to be specified dynamically.
        • -
        • The MyRuleSet example above illustrates another technique - that increases reusability -- you can specify (as an argument to the - constructor) the leading portion of the matching pattern to be used. - In this way, you can construct a Digester that recognizes - the same set of nested elements at different nesting levels within an - XML document.
        • -
        - -

        Using Named Stacks For Inter-Rule Communication

        -

        -Digester is based on Rule instances working together -to process xml. For anything other than the most trival processing, -communication between Rule instances is necessary. Since Rule -instances are processed in sequence, this usually means storing an Object -somewhere where later instances can retrieve it. -

        -

        -Digester is based on SAX. The most natural data structure to use with -SAX based xml processing is the stack. This allows more powerful processes to be -specified more simply since the pushing and popping of objects can mimic the -nested structure of the xml. -

        -

        -Digester uses two basic stacks: one for the main beans and the other -for parameters for method calls. These are inadequate for complex processing -where many different Rule instances need to communicate through -different channels. -

        -

        -In this case, it is recommended that named stacks are used. In addition to the -two basic stacks, Digester allows rules to use an unlimited number -of other stacks referred two by an identifying string (the name). (That's where -the term named stack comes from.) These stacks are -accessed through calls to: -

        - -

        -Note: all stack names beginning with org.apache.commons.digester -are reserved for future use by the Digester component. It is also recommended -that users choose stack names perfixed by the name of their own domain to avoid conflicts -with other Rule implementations. -

        - -

        Registering DTDs

        - -

        Brief (But Still Too Long) Introduction To System and Public Identifiers

        -

        A definition for an external entity comes in one of two forms: -

        -
          -
        1. SYSTEM system-identifier
        2. -
        3. PUBLIC public-identifier system-identifier
        4. -
        -

        -The system-identifier is an URI from which the resource can be obtained -(either directly or indirectly). Many valid URIs may identify the same resource. -The public-identifier is an additional free identifier which may be used -(by the parser) to locate the resource. -

        -

        -In practice, the weakness with a system-identifier is that most parsers -will attempt to interprete this URI as an URL, try to download the resource directly -from the URL and stop the parsing if this download fails. So, this means that -almost always the URI will have to be an URL from which the declaration -can be downloaded. -

        -

        -URLs may be local or remote but if the URL is chosen to be local, it is likely only -to function correctly on a small number of machines (which are configured precisely -to allow the xml to be parsed). This is usually unsatisfactory and so a universally -accessable URL is preferred. This usually means an internet URL. -

        -

        -To recap, in practice the system-identifier will (most likely) be an -internet URL. Unfortunately downloading from an internet URL is not only slow -but unreliable (since successfully downloading a document from the internet -relies on the client being connect to the internet and the server being -able to satisfy the request). -

        -

        -The public-identifier is a freely defined name but (in practice) it is -strongly recommended that a unique, readable and open format is used (for reasons -that should become clear later). A Formal Public Identifier (FPI) is a very -common choice. This public identifier is often used to provide a unique and location -independent key which can be used to subsistute local resources for remote ones -(hint: this is why ;). -

        -

        -By using the second (PUBLIC) form combined with some form of local -catalog (which matches public-identifiers to local resources) and where -the public-identifier is a unique name and the system-identifier -is an internet URL, the practical disadvantages of specifying just a -system-identifier can be avoided. Those external entities which have been -store locally (on the machine parsing the document) can be identified and used. -Only when no local copy exists is it necessary to download the document -from the internet URL. This naming scheme is recommended when using Digester. -

        - -

        External Entity Resolution Using Digester

        -

        -SAX factors out the resolution of external entities into an EntityResolver. -Digester supports the use of custom EntityResolver -but ships with a simple internal implementation. This implementation allows local URLs -to be easily associated with public-identifiers. -

        -

        For example:

        -
        -    digester.register("-//Example Dot Com //DTD Sample Example//EN", "assets/sample.dtd");
        -
        -

        -will make digester return the relative file path assets/sample.dtd -whenever an external entity with public id --//Example Dot Com //DTD Sample Example//EN is needed. -

        -

        Note: This is a simple (but useful) implementation. -Greater sophistication requires a custom EntityResolver.

        - - -

        Troubleshooting

        -

        Debugging Exceptions

        -

        -Digester is based on SAX. -Digestion throws two kinds of Exception: -

        -
          -
        • java.io.IOException
        • -
        • org.xml.sax.SAXException
        • -
        -

        -The first is rarely thrown and indicates the kind of fundemental IO exception -that developers know all about. The second is thrown by SAX parsers when the processing -of the XML cannot be completed. So, to diagnose the cause a certain familiarity with -the way that SAX error handling works is very useful. -

        -
        Diagnosing SAX Exceptions
        -

        -This is a short, potted guide to SAX error handling strategies. It's not intended as a -proper guide to error handling in SAX. -

        -

        -When a SAX parser encounters a problem with the xml (well, ok - sometime after it -encounters a problem) it will throw a - -SAXParseException. This is a subclass of SAXException and contains -a bit of extra information about what exactly when wrong - and more importantly, -where it went wrong. If you catch an exception of this sort, you can be sure that -the problem is with the XML and not Digester or your rules. -It is usually a good idea to catch this exception and log the extra information -to help with diagnosing the reason for the failure. -

        -

        -General -SAXException instances may wrap a causal exception. When exceptions are -throw by Digester each of these will be wrapped into a -SAXException and rethrown. So, catch these and examine the wrapped -exception to diagnose what went wrong. -

        - -

        Frequently Asked Questions

        -

        - -

        Known Limitations

        -

        Accessing Public Methods In A Default Access Superclass

        -

        There is an issue when invoking public methods contained in a default access superclass. -Reflection locates these methods fine and correctly assigns them as public. -However, an IllegalAccessException is thrown if the method is invoked.

        - -

        MethodUtils contains a workaround for this situation. -It will attempt to call setAccessible on this method. -If this call succeeds, then the method can be invoked as normal. -This call will only succeed when the application has sufficient security privilages. -If this call fails then a warning will be logged and the method may fail.

        - -

        Digester uses MethodUtils and so there may be an issue accessing methods -of this kind from a high security environment. If you think that you might be experiencing this -problem, please ask on the mailing list.

        - - + + +Package Documentation for org.apache.commons.digester Package + + +The Digester package provides for rules-based processing of arbitrary +XML documents. +

        + + + + +

        External Dependencies

        + + + + +

        Introduction

        + +

        In many application environments that deal with XML-formatted data, it is +useful to be able to process an XML document in an "event driven" manner, +where particular Java objects are created (or methods of existing objects +are invoked) when particular patterns of nested XML elements have been +recognized. Developers familiar with the Simple API for XML Parsing (SAX) +approach to processing XML documents will recognize that the Digester provides +a higher level, more developer-friendly interface to SAX events, because most +of the details of navigating the XML element hierarchy are hidden -- allowing +the developer to focus on the processing to be performed.

        + +

        In order to use a Digester, the following basic steps are required:

        +
          +
        • Create a new instance of the + org.apache.commons.digester.Digester class. Previously + created Digester instances may be safely reused, as long as you have + completed any previously requested parse, and you do not try to utilize + a particular Digester instance from more than one thread at a time.
        • +
        • Set any desired configuration properties + that will customize the operation of the Digester when you next initiate + a parse operation.
        • +
        • Optionally, push any desired initial object(s) onto the Digester's + object stack.
        • +
        • Register all of the element matching patterns + for which you wish to have processing rules + fired when this pattern is recognized in an input document. You may + register as many rules as you like for any particular pattern. If there + is more than one rule for a given pattern, the rules will be executed in + the order that they were listed.
        • +
        • Call the digester.parse() method, passing a reference to the + XML document to be parsed in one of a variety of forms. See the + Digester.parse() + documentation for details. Note that you will need to be prepared to + catch any IOException or SAXException that is + thrown by the parser, or any runtime expression that is thrown by one of + the processing rules.
        • +
        + +

        For example code, see the usage +examples, and the FAQ .

        + + +

        Digester Configuration Properties

        + +

        A org.apache.commons.digester.Digester instance contains several +configuration properties that can be used to customize its operation. These +properties must be configured before you call one of the +parse() variants, in order for them to take effect on that +parse.

        + +
        + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
        PropertyDescription
        classLoaderYou can optionally specify the class loader that will be used to + load classes when required by the ObjectCreateRule + and FactoryCreateRule rules. If not specified, + application classes will be loaded from the thread's context + class loader (if the useContextClassLoader property + is set to true) or the same class loader that was + used to load the Digester class itself.
        errorHandlerYou can optionally specify a SAX ErrorHandler that + is notified when parsing errors occur. By default, any parsing + errors that are encountered are logged, but Digester will continue + processing as well.
        namespaceAwareA boolean that is set to true to perform parsing in a + manner that is aware of XML namespaces. Among other things, this + setting affects how elements are matched to processing rules. See + Namespace Aware Parsing for more + information.
        ruleNamespaceURIThe public URI of the namespace for which all subsequently added + rules are associated, or null for adding rules that + are not associated with any namespace. See + Namespace Aware Parsing for more + information.
        rulesThe Rules component that actually performs matching of + Rule instances against the current element nesting + pattern is pluggable. By default, Digester includes a + Rules implementation that behaves as described in this + document. See + Pluggable Rules Processing for + more information.
        useContextClassLoader + A boolean that is set to true if you want application + classes required by FactoryCreateRule and + ObjectCreateRule to be loaded from the context class + loader of the current thread. By default, classes will be loaded + from the class loader that loaded this Digester class. + NOTE - This property is ignored if you set a + value for the classLoader property; that class loader + will be used unconditionally.
        validatingA boolean that is set to true if you wish to validate + the XML document against a Document Type Definition (DTD) that is + specified in its DOCTYPE declaration. The default + value of false requests a parse that only detects + "well formed" XML documents, rather than "valid" ones.
        +
        + +

        In addition to the scalar properties defined above, you can also register +a local copy of a Document Type Definition (DTD) that is referenced in a +DOCTYPE declaration. Such a registration tells the XML parser +that, whenever it encounters a DOCTYPE declaration with the +specified public identifier, it should utilize the actual DTD content at the +registered system identifier (a URL), rather than the one in the +DOCTYPE declaration.

        + +

        For example, the Struts framework controller servlet uses the following +registration in order to tell Struts to use a local copy of the DTD for the +Struts configuration file. This allows usage of Struts in environments that +are not connected to the Internet, and speeds up processing even at Internet +connected sites (because it avoids the need to go across the network).

        + +
        +    URL url = new URL("/org/apache/struts/resources/struts-config_1_0.dtd");
        +    digester.register
        +      ("-//Apache Software Foundation//DTD Struts Configuration 1.0//EN",
        +       url.toString());
        +
        + +

        As a side note, the system identifier used in this example is the path +that would be passed to java.lang.ClassLoader.getResource() +or java.lang.ClassLoader.getResourceAsStream(). The actual DTD +resource is loaded through the same class loader that loads all of the Struts +classes -- typically from the struts.jar file.

        + + +

        The Object Stack

        + +

        One very common use of org.apache.commons.digester.Digester +technology is to dynamically construct a tree of Java objects, whose internal +organization, as well as the details of property settings on these objects, +are configured based on the contents of the XML document. In fact, the +primary reason that the Digester package was created (it was originally part +of Struts, and then moved to the Commons project because it was recognized +as being generally useful) was to facilitate the +way that the Struts controller servlet configures itself based on the contents +of your application's struts-config.xml file.

        + +

        To facilitate this usage, the Digester exposes a stack that can be +manipulated by processing rules that are fired when element matching patterns +are satisfied. The usual stack-related operations are made available, +including the following:

        +
          +
        • clear() - Clear the current contents + of the object stack.
        • +
        • peek() - Return a reference to the top + object on the stack, without removing it.
        • +
        • pop() - Remove the top object from the + stack and return it.
        • +
        • push() - Push a new + object onto the top of the stack.
        • +
        + +

        A typical design pattern, then, is to fire a rule that creates a new object +and pushes it on the stack when the beginning of a particular XML element is +encountered. The object will remain there while the nested content of this +element is processed, and it will be popped off when the end of the element +is encountered. As we will see, the standard "object create" processing rule +supports exactly this functionalility in a very convenient way.

        + +

        Several potential issues with this design pattern are addressed by other +features of the Digester functionality:

        +
          +
        • How do I relate the objects being created to each other? - The + Digester supports standard processing rules that pass the top object on + the stack as an argument to a named method on the next-to-top object on + the stack (or vice versa). This rule makes it easy to establish + parent-child relationships between these objects. One-to-one and + one-to-many relationships are both easy to construct.
        • +
        • How do I retain a reference to the first object that was created? + As you review the description of what the "object create" processing rule + does, it would appear that the first object you create (i.e. the object + created by the outermost XML element you process) will disappear from the + stack by the time that XML parsing is completed, because the end of the + element would have been encountered. However, Digester will maintain a + reference to the very first object ever pushed onto the object stack, + and will return it to you + as the return value from the parse() call. Alternatively, + you can push a reference to some application object onto the stack before + calling parse(), and arrange that a parent-child relationship + be created (by appropriate processing rules) between this manually pushed + object and the ones that are dynamically created. In this way, + the pushed object will retain a reference to the dynamically created objects + (and therefore all of their children), and will be returned to you after + the parse finishes as well.
        • +
        + + +

        Element Matching Patterns

        + +

        A primary feature of the org.apache.commons.digester.Digester +parser is that the Digester automatically navigates the element hierarchy of +the XML document you are parsing for you, without requiring any developer +attention to this process. Instead, you focus on deciding what functions you +would like to have performed whenver a certain arrangement of nested elements +is encountered in the XML document being parsed. The mechanism for specifying +such arrangements are called element matching patterns. + +

        A very simple element matching pattern is a simple string like "a". This +pattern is matched whenever an <a> top-level element is +encountered in the XML document, no matter how many times it occurs. Note that +nested <a> elements will not match this +pattern -- we will describe means to support this kind of matching later. + +

        The next step up in matching pattern complexity is "a/b". This pattern will +be matched when a <b> element is found nested inside a +top-level <a> element. Again, this match can occur as many +times as desired, depending on the content of the XML document being parsed. +You can use multiple slashes to define a hierarchy of any desired depth that +will be matched appropriately.

        + +

        For example, assume you have registered processing rules that match patterns +"a", "a/b", and "a/b/c". For an input XML document with the following +contents, the indicated patterns will be matched when the corresponding element +is parsed:

        +
        +  <a>         -- Matches pattern "a"
        +    <b>       -- Matches pattern "a/b"
        +      <c/>    -- Matches pattern "a/b/c"
        +      <c/>    -- Matches pattern "a/b/c"
        +    </b>
        +    <b>       -- Matches pattern "a/b"
        +      <c/>    -- Matches pattern "a/b/c"
        +      <c/>    -- Matches pattern "a/b/c"
        +      <c/>    -- Matches pattern "a/b/c"
        +    </b>
        +  </a>
        +
        + +

        It is also possible to match a particular XML element, no matter how it is +nested (or not nested) in the XML document, by using the "*" wildcard character +in your matching pattern strings. For example, an element matching pattern +of "*/a" will match an <a> element at any nesting position +within the document.

        + +

        It is quite possible that, when a particular XML element is being parsed, +the pattern for more than one registered processing rule will be matched + either because you registered more than one processing rule with the same +matching pattern, or because one more more exact pattern matches and wildcard +pattern matches are satisfied by the same element.

        + +

        When this occurs, the corresponding processing rules will all be fired in order. +begin (and body) method calls are executed in the +order that the Rules where initially registered with the +Digester, whilst end method calls are execute in +reverse order. In other words - the order is first in, last out.

        + + +

        Processing Rules

        + +

        The previous section documented how you identify +when you wish to have certain actions take place. The purpose +of processing rules is to define what should happen when the +patterns are matched.

        + +

        Formally, a processing rule is a Java class that subclasses the +org.apache.commons.digester.Rule interface. Each Rule +implements one or more of the following event methods that are called at +well-defined times when the matching patterns corresponding to this rule +trigger it:

        +
          +
        • begin() - + Called when the beginning of the matched XML element is encountered. A + data structure containing all of the attributes corresponding to this + element are passed as well.
        • +
        • body() - + Called when nested content (that is not itself XML elements) of the + matched element is encountered. Any leading or trailing whitespace will + have been removed as part of the parsing process.
        • +
        • end() - Called when the ending of the matched + XML element is encountered. If nested XML elements that matched other + processing rules was included in the body of this element, the appropriate + processing rules for the matched rules will have already been completed + before this method is called.
        • +
        • finish() - Called when the parse has + been completed, to give each rule a chance to clean up any temporary data + they might have created and cached.
        • +
        + +

        As you are configuring your digester, you can call the +addRule() method to register a specific element matching pattern, +along with an instance of a Rule class that will have its event +handling methods called at the appropriate times, as described above. This +mechanism allows you to create Rule implementation classes +dynamically, to implement any desired application specific functionality.

        + +

        In addition, a set of processing rule implementation classes are provided, +which deal with many common programming scenarios. These classes include the +following:

        +
          +
        • ObjectCreateRule - When the + begin() method is called, this rule instantiates a new + instance of a specified Java class, and pushes it on the stack. The + class name to be used is defaulted according to a parameter passed to + this rule's constructor, but can optionally be overridden by a classname + passed via the specified attribute to the XML element being processed. + When the end() method is called, the top object on the stack + (presumably, the one we added in the begin() method) will + be popped, and any reference to it (within the Digester) will be + discarded.
        • +
        • FactoryCreateRule - A variation of + ObjectCreateRule that is useful when the Java class with + which you wish to create an object instance does not have a no-arguments + constructor, or where you wish to perform other setup processing before + the object is handed over to the Digester.
        • +
        • SetPropertiesRule - When the + begin() method is called, the digester uses the standard + Java Reflection API to identify any JavaBeans property setter methods + (on the object at the top of the digester's stack) + who have property names that match the attributes specified on this XML + element, and then call them individually, passing the corresponding + attribute values. These natural mappings can be overridden. This allows + (for example) a class attribute to be mapped correctly. + It is recommended that this feature should not be overused - in most cases, + it's better to use the standard BeanInfo mechanism. + A very common idiom is to define an object create + rule, followed by a set properties rule, with the same element matching + pattern. This causes the creation of a new Java object, followed by + "configuration" of that object's properties based on the attributes + of the same XML element that created this object.
        • +
        • SetPropertyRule - When the + begin() method is called, the digester calls a specified + property setter (where the property itself is named by an attribute) + with a specified value (where the value is named by another attribute), + on the object at the top of the digester's stack. + This is useful when your XML file conforms to a particular DTD, and + you wish to configure a particular property that does not have a + corresponding attribute in the DTD.
        • +
        • SetNextRule - When the + end() method is called, the digester analyzes the + next-to-top element on the stack, looking for a property setter method + for a specified property. It then calls this method, passing the object + at the top of the stack as an argument. This rule is commonly used to + establish one-to-many relationships between the two objects, with the + method name commonly being something like "addChild".
        • +
        • SetTopRule - When the + end() method is called, the digester analyzes the + top element on the stack, looking for a property setter method for a + specified property. It then calls this method, passing the next-to-top + object on the stack as an argument. This rule would be used as an + alternative to a SetNextRule, with a typical method name "setParent", + if the API supported by your object classes prefers this approach.
        • +
        • CallMethodRule - This rule sets up a + method call to a named method of the top object on the digester's stack, + which will actually take place when the end() method is + called. You configure this rule by specifying the name of the method + to be called, the number of arguments it takes, and (optionally) the + Java class name(s) defining the type(s) of the method's arguments. + The actual parameter values, if any, will typically be accumulated from + the body content of nested elements within the element that triggered + this rule, using the CallParamRule discussed next.
        • +
        • CallParamRule - This rule identifies + the source of a particular numbered (zero-relative) parameter for a + CallMethodRule within which we are nested. You can specify that the + parameter value be taken from a particular named attribute, or from the + nested body content of this element.
        • +
        • NodeCreateRule - A specialized rule + that converts part of the tree into a DOM Node and then + pushes it onto the stack.
        • +
        + +

        You can create instances of the standard Rule classes and +register them by calling digester.addRule(), as described above. +However, because their usage is so common, shorthand registration methods are +defined for each of the standard rules, directly on the Digester +class. For example, the following code sequence:

        +
        +    Rule rule = new SetNextRule(digester, "addChild",
        +                                "com.mycompany.mypackage.MyChildClass");
        +    digester.addRule("a/b/c", rule);
        +
        +

        can be replaced by:

        +
        +    digester.addSetNext("a/b/c", "addChild",
        +                        "com.mycompany.mypackage.MyChildClass");
        +
        + + +

        Logging

        + +

        Logging is a vital tool for debugging Digester rulesets. Digester can log +copious amounts of debugging information. So, you need to know how logging +works before you start using Digester seriously.

        + +

        Digester uses +Jakarta Commons +Logging. This component is not really a logging framework - rather +an extensible, configurable bridge. It can be configured to swallow all log +messages, to provide very basic logging by itself or to pass logging messages +on to more sophisticated logging frameworks. Commons-Logging comes with +connectors for many popular logging frameworks. Consult the commons-logging +documentation for more information.

        + +

        Two main logs are used by Digester:

        +
          +
        • SAX-related messages are logged to + org.apache.commons.digester.Digester.sax. + This log gives information about the basic SAX events received by + Digester.
        • +
        • org.apache.commons.digester.Digester is used + for everything else. You'll probably want to have this log turned up during + debugging but turned down during production due to the high message + volume.
        • +
        + +

        Complete documentation of how to configure Commons-Logging can be found +in the Commons Logging package documentation. However, as a simple example, +let's assume that you want to use the SimpleLog implementation +that is included in Commons-Logging, and set up Digester to log events from +the Digester logger at the DEBUG level, while you want to log +events from the Digester.log logger at the INFO level. You can +accomplish this by creating a commons-logging.properties file +in your classpath (or setting corresponding system properties on the command +line that starts your application) with the following contents:

        +
        +  org.apache.commons.logging.Log=org.apache.commons.logging.impl.SimpleLog
        +  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester=debug
        +  org.apache.commons.logging.simplelog.log.org.apache.commons.digester.Digester.sax=info
        +
        + + +

        Usage Examples

        + + +
        Creating a Simple Object Tree
        + +

        Let's assume that you have two simple JavaBeans, Foo and +Bar, with the following method signatures:

        +
        +  package mypackage;
        +  public class Foo {
        +    public void addBar(Bar bar);
        +    public Bar findBar(int id);
        +    public Iterator getBars();
        +    public String getName();
        +    public void setName(String name);
        +  }
        +
        +  public mypackage;
        +  public class Bar {
        +    public int getId();
        +    public void setId(int id);
        +    public String getTitle();
        +    public void setTitle(String title);
        +  }
        +
        + +

        and you wish to use Digester to parse the following XML document:

        + +
        +  <foo name="The Parent">
        +    <bar id="123" title="The First Child"/>
        +    <bar id="456" title="The Second Child"/>
        +  </foo>
        +
        + +

        A simple approach will be to use the following Digester in the following way +to set up the parsing rules, and then process an input file containing this +document:

        + +
        +  Digester digester = new Digester();
        +  digester.setValidating(false);
        +  digester.addObjectCreate("foo", "mypackage.Foo");
        +  digester.addSetProperties("foo");
        +  digester.addObjectCreate("foo/bar", "mypackage.Bar");
        +  digester.addSetProperties("foo/bar");
        +  digester.addSetNext("foo/bar", "addBar", "mypackage.Bar");
        +  Foo foo = (Foo) digester.parse();
        +
        + +

        In order, these rules do the following tasks:

        +
          +
        1. When the outermost <foo> element is encountered, + create a new instance of mypackage.Foo and push it + on to the object stack. At the end of the <foo> + element, this object will be popped off of the stack.
        2. +
        3. Cause properties of the top object on the stack (i.e. the Foo + object that was just created and pushed) to be set based on the values + of the attributes of this XML element.
        4. +
        5. When a nested <bar> element is encountered, + create a new instance of mypackage.Bar and push it + on to the object stack. At the end of the <bar> + element, this object will be popped off of the stack (i.e. after the + remaining rules matching foo/bar are processed).
        6. +
        7. Cause properties of the top object on the stack (i.e. the Bar + object that was just created and pushed) to be set based on the values + of the attributes of this XML element. Note that type conversions + are automatically performed (such as String to int for the id + property), for all converters registered with the ConvertUtils + class from commons-beanutils package.
        8. +
        9. Cause the addBar method of the next-to-top element on the + object stack (which is why this is called the "set next" rule) + to be called, passing the element that is on the top of the stack, which + must be of type mypackage.Bar. This is the rule that causes + the parent/child relationship to be created.
        10. +
        + +

        Once the parse is completed, the first object that was ever pushed on to the +stack (the Foo object in this case) is returned to you. It will +have had its properties set, and all of its child Bar objects +created for you.

        + + +
        Processing A Struts Configuration File
        + +

        As stated earlier, the primary reason that the +Digester package was created is because the +Struts controller servlet itself needed a robust, flexible, easy to extend +mechanism for processing the contents of the struts-config.xml +configuration that describes nearly every aspect of a Struts-based application. +Because of this, the controller servlet contains a comprehensive, real world, +example of how the Digester can be employed for this type of a use case. +See the initDigester() method of class +org.apache.struts.action.ActionServlet for the code that creates +and configures the Digester to be used, and the initMapping() +method for where the parsing actually takes place.

        + +

        (Struts binary and source distributions can be acquired at +http://jakarta.apache.org/struts/.)

        + +

        The following discussion highlights a few of the matching patterns and +processing rules that are configured, to illustrate the use of some of the +Digester features. First, let's look at how the Digester instance is +created and initialized:

        +
        +    Digester digester = new Digester();
        +    digester.push(this); // Push controller servlet onto the stack
        +    digester.setValidating(true);
        +
        + +

        We see that a new Digester instance is created, and is configured to use +a validating parser. Validation will occur against the struts-config_1_0.dtd +DTD that is included with Struts (as discussed earlier). In order to provide +a means of tracking the configured objects, the controller servlet instance +itself will be added to the digester's stack.

        + +
        +    digester.addObjectCreate("struts-config/global-forwards/forward",
        +                             forwardClass, "className");
        +    digester.addSetProperties("struts-config/global-forwards/forward");
        +    digester.addSetNext("struts-config/global-forwards/forward",
        +                        "addForward",
        +                        "org.apache.struts.action.ActionForward");
        +    digester.addSetProperty
        +      ("struts-config/global-forwards/forward/set-property",
        +       "property", "value");
        +
        + +

        The rules created by these lines are used to process the global forward +declarations. When a <forward> element is encountered, +the following actions take place:

        +
          +
        • A new object instance is created -- the ActionForward + instance that will represent this definition. The Java class name + defaults to that specified as an initialization parameter (which + we have stored in the String variable forwardClass), but can + be overridden by using the "className" attribute (if it is present in the + XML element we are currently parsing). The new ActionForward + instance is pushed onto the stack.
        • +
        • The properties of the ActionForward instance (at the top of + the stack) are configured based on the attributes of the + <forward> element.
        • +
        • Nested occurrences of the <set-property> element + cause calls to additional property setter methods to occur. This is + required only if you have provided a custom implementation of the + ActionForward class with additional properties that are + not included in the DTD.
        • +
        • The addForward() method of the next-to-top object on + the stack (i.e. the controller servlet itself) will be called, passing + the object at the top of the stack (i.e. the ActionForward + instance) as an argument. This causes the global forward to be + registered, and as a result of this it will be remembered even after + the stack is popped.
        • +
        • At the end of the <forward> element, the top element + (i.e. the ActionForward instance) will be popped off the + stack.
        • +
        + +

        Later on, the digester is actually executed as follows:

        +
        +    InputStream input =
        +      getServletContext().getResourceAsStream(config);
        +    ...
        +    try {
        +        digester.parse(input);
        +        input.close();
        +    } catch (SAXException e) {
        +        ... deal with the problem ...
        +    }
        +
        + +

        As a result of the call to parse(), all of the configuration +information that was defined in the struts-config.xml file is +now represented as collections of objects cached within the Struts controller +servlet, as well as being exposed as servlet context attributes.

        + + +
        Parsing Body Text In XML Files
        + +

        The Digester module also allows you to process the nested body text in an +XML file, not just the elements and attributes that are encountered. The +following example is based on an assumed need to parse the web application +deployment descriptor (/WEB-INF/web.xml) for the current web +application, and record the configuration information for a particular +servlet. To record this information, assume the existence of a bean class +with the following method signatures (among others):

        +
        +  package com.mycompany;
        +  public class ServletBean {
        +    public void setServletName(String servletName);
        +    public void setServletClass(String servletClass);
        +    public void addInitParam(String name, String value);
        +  }
        +
        + +

        We are going to process the web.xml file that declares the +controller servlet in a typical Struts-based application (abridged for +brevity in this example):

        +
        +  <web-app>
        +    ...
        +    <servlet>
        +      <servlet-name>action</servlet-name>
        +      <servlet-class>org.apache.struts.action.ActionServlet<servlet-class>
        +      <init-param>
        +        <param-name>application</param-name>
        +        <param-value>org.apache.struts.example.ApplicationResources<param-value>
        +      </init-param>
        +      <init-param>
        +        <param-name>config</param-name>
        +        <param-value>/WEB-INF/struts-config.xml<param-value>
        +      </init-param>
        +    </servlet>
        +    ...
        +  </web-app>
        +
        + +

        Next, lets define some Digester processing rules for this input file:

        +
        +  digester.addObjectCreate("web-app/servlet",
        +                           "com.mycompany.ServletBean");
        +  digester.addCallMethod("web-app/servlet/servlet-name", "setServletName", 0);
        +  digester.addCallMethod("web-app/servlet/servlet-class",
        +                         "setServletClass", 0);
        +  digester.addCallMethod("web-app/servlet/init-param",
        +                         "addInitParam", 2);
        +  digester.addCallParam("web-app/servlet/init-param/param-name", 0);
        +  digester.addCallParam("web-app/servlet/init-param/param-value", 1);
        +
        + +

        Now, as elements are parsed, the following processing occurs:

        +
          +
        • <servlet> - A new com.mycompany.ServletBean + object is created, and pushed on to the object stack.
        • +
        • <servlet-name> - The setServletName() method + of the top object on the stack (our ServletBean) is called, + passing the body content of this element as a single parameter.
        • +
        • <servlet-class> - The setServletClass() method + of the top object on the stack (our ServletBean) is called, + passing the body content of this element as a single parameter.
        • +
        • <init-param> - A call to the addInitParam + method of the top object on the stack (our ServletBean) is + set up, but it is not called yet. The call will be + expecting two String parameters, which must be set up by + subsequent call parameter rules.
        • +
        • <param-name> - The body content of this element is assigned + as the first (zero-relative) argument to the call we are setting up.
        • +
        • <param-value> - The body content of this element is assigned + as the second (zero-relative) argument to the call we are setting up.
        • +
        • </init-param> - The call to addInitParam() + that we have set up is now executed, which will cause a new name-value + combination to be recorded in our bean.
        • +
        • <init-param> - The same set of processing rules are fired + again, causing a second call to addInitParam() with the + second parameter's name and value.
        • +
        • </servlet> - The element on the top of the object stack + (which should be the ServletBean we pushed earlier) is + popped off the object stack.
        • +
        + + + +

        Namespace Aware Parsing

        + +

        For digesting XML documents that do not use XML namespaces, the default +behavior of Digester, as described above, is generally sufficient. +However, if the document you are processing uses namespaces, it is often +convenient to have sets of Rule instances that are only +matched on elements that use the prefix of a particular namespace. This +approach, for example, makes it possible to deal with element names that are +the same in different namespaces, but where you want to perform different +processing for each namespace.

        + +

        Digester does not provide full support for namespaces, but does provide +sufficient to accomplish most tasks. Enabling digester's namespace support +is done by following these steps:

        + +
          +
        1. Tell Digester that you will be doing namespace + aware parsing, by adding this statement in your initalization + of the Digester's properties: +
          +    digester.setNamespaceAware(true);
          +    
        2. +
        3. Declare the public namespace URI of the namespace with which + following rules will be associated. Note that you do not + make any assumptions about the prefix - the XML document author + is free to pick whatever prefix they want: +
          +    digester.setRuleNamespaceURI("http://www.mycompany.com/MyNamespace");
          +    
        4. +
        5. Add the rules that correspond to this namespace, in the usual way, + by calling methods like addObjectCreate() or + addSetProperties(). In the matching patterns you specify, + use only the local name portion of the elements (i.e. the + part after the prefix and associated colon (":") character: +
          +    digester.addObjectCreate("foo/bar", "com.mycompany.MyFoo");
          +    digester.addSetProperties("foo/bar");
          +    
        6. +
        7. Repeat the previous two steps for each additional public namespace URI + that should be recognized on this Digester run.
        8. +
        + +

        Now, consider that you might wish to digest the following document, using +the rules that were set up in the steps above:

        +
        +<m:foo
        +   xmlns:m="http://www.mycompany.com/MyNamespace"
        +   xmlns:y="http://www.yourcompany.com/YourNamespace">
        +
        +  <m:bar name="My Name" value="My Value"/>
        +
        +  <y:bar id="123" product="Product Description"/>L
        +
        +</x:foo>
        +
        + +

        Note that your object create and set properties rules will be fired for the +first occurrence of the bar element, but not the +second one. This is because we declared that our rules only matched +for the particular namespace we are interested in. Any elements in the +document that are associated with other namespaces (or no namespaces at all) +will not be processed. In this way, you can easily create rules that digest +only the portions of a compound document that they understand, without placing +any restrictions on what other content is present in the document.

        + +

        You might also want to look at Encapsulated +Rule Sets if you wish to reuse a particular set of rules, associated +with a particular namespace, in more than one application context.

        + +

        Using Namespace Prefixes In Pattern Matching

        + +

        Using rules with namespaces is very useful when you have orthogonal rulesets. +One ruleset applies to a namespace and is independent of other rulesets applying +to other namespaces. However, if your rule logic requires mixed namespaces, then +matching namespace prefix patterns might be a better strategy.

        + +

        When you set the NamespaceAware property to false, digester uses +the qualified element name (which includes the namespace prefix) rather than the +local name as the patten component for the element. This means that your pattern +matches can include namespace prefixes as well as element names. So, rather than +create namespace-aware rules, create pattern matches including the namespace +prefixes.

        + +

        For example, (with NamespaceAware false), the pattern +'foo:bar' will match a top level element named 'bar' in the +namespace with (local) prefix 'foo'.

        + +

        Limitations of Digester Namespace support

        +

        Digester does not provide general "xpath-compliant" matching; +only the namespace attached to the last element in the match path +is involved in the matching process. Namespaces attached to parent +elements are ignored for matching purposes.

        + + + +

        Pluggable Rules Processing

        + +

        By default, Digester selects the rules that match a particular +pattern of nested elements as described under +Element Matching Patterns. If you prefer to use +different selection policies, however, you can create your own implementation +of the org.apache.commons.digester.Rules interface, +or subclass the corresponding convenience base class +org.apache.commons.digester.RulesBase. +Your implementation of the match() method will be called when the +processing for a particular element is started or ended, and you must return +a List of the rules that are relevant for the current nesting +pattern. The order of the rules you return is significant, +and should match the order in which rules were initally added.

        + +

        Your policy for rule selection should generally be sensitive to whether +Namespace Aware Parsing is taking place. In +general, if namespaceAware is true, you should select only rules +that:

        +
          +
        • Are registered for the public namespace URI that corresponds to the + prefix being used on this element.
        • +
        • Match on the "local name" portion of the element (so that the document + creator can use any prefix that they like).
        • +
        + +

        ExtendedBaseRules

        +

        ExtendedBaseRules, +adds some additional expression syntax for pattern matching +to the default mechanism, but it also executes more slowly. See the +JavaDocs for more details on the new pattern matching syntax, and suggestions +on when this implementation should be used. To use it, simply do the +following as part of your Digester initialization:

        + +
        +  Digester digester = ...
        +  ...
        +  digester.setRules(new ExtendedBaseRules());
        +  ...
        +
        + +

        RegexRules

        +

        RegexRules is an advanced Rules +implementation which does not build on the default pattern matching rules. +It uses a pluggable RegexMatcher implementation to test +if a path matches the pattern for a Rule. All matching rules are returned +(note that this behaviour differs from longest matching rule of the default + pattern matching rules). See the Java Docs for more details. +

        +

        +Example usage: +

        + +
        +  Digester digester = ...
        +  ...
        +  digester.setRules(new RegexRules(new SimpleRegexMatcher()));
        +  ...
        +
        +
        RegexMatchers
        +

        +Digester ships only with one RegexMatcher +implementation: SimpleRegexMatcher. +This implementation is unsophisticated and lacks many good features +lacking in more power Regex libraries. There are some good reasons +why this approach was adopted. The first is that SimpleRegexMatcher +is simple, it is easy to write and runs quickly. The second has to do with +the way that RegexRules is intended to be used. +

        +

        +There are many good regex libraries available. (For example +Jakarta ORO, +Jakarta Regex, +GNU Regex and + +Java 1.4 Regex) +Not only do different people have different personal tastes when it comes to +regular expression matching but these products all offer different functionality +and different strengths. +

        +

        +The pluggable RegexMatcher is a thin bridge +designed to adapt other Regex systems. This allows any Regex library the user +desires to be plugged in and used just by creating one class. +Digester does not (currently) ship with bridges to the major +regex (to allow the dependencies required by Digester +to be kept to a minimum). +

        + +

        WithDefaultsRulesWrapper

        +

        + WithDefaultsRulesWrapper allows +default Rule instances to be added to any existing +Rules implementation. These default Rule instances +will be returned for any match for which the wrapped implementation does not +return any matches. +

        +

        +For example, +

        +    Rule alpha;
        +    ...
        +    WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new BaseRules());
        +    rules.addDefault(alpha);
        +    ...
        +    digester.setRules(rules);
        +    ...
        +
        +when a pattern does not match any other rule, then rule alpha will be called. +

        +

        +WithDefaultsRulesWrapper follows the Decorator pattern. +

        + + +

        Encapsulated Rule Sets

        + +

        All of the examples above have described a scenario where the rules to be +processed are registered with a Digester instance immediately +after it is created. However, this approach makes it difficult to reuse the +same set of rules in more than one application environment. Ideally, one +could package a set of rules into a single class, which could be easily +loaded and registered with a Digester instance in one easy step. +

        + +

        The RuleSet interface (and the convenience base +class RuleSetBase) make it possible to do this. +In addition, the rule instances registered with a particular +RuleSet can optionally be associated with a particular namespace, +as described under Namespace Aware Processing.

        + +

        An example of creating a RuleSet might be something like this: +

        +
        +public class MyRuleSet extends RuleSetBase {
        +
        +  public MyRuleSet() {
        +    this("");
        +  }
        +
        +  public MyRuleSet(String prefix) {
        +    super();
        +    this.prefix = prefix;
        +    this.namespaceURI = "http://www.mycompany.com/MyNamespace";
        +  }
        +
        +  protected String prefix = null;
        +
        +  public void addRuleInstances(Digester digester) {
        +    digester.addObjectCreate(prefix + "foo/bar",
        +      "com.mycompany.MyFoo");
        +    digester.addSetProperties(prefix + "foo/bar");
        +  }
        +
        +}
        +
        + +

        You might use this RuleSet as follow to initialize a +Digester instance:

        +
        +  Digester digester = new Digester();
        +  ... configure Digester properties ...
        +  digester.addRuleSet(new MyRuleSet("baz/"));
        +
        + +

        A couple of interesting notes about this approach:

        +
          +
        • The application that is using these rules does not need to know anything + about the fact that the RuleSet being used is associated + with a particular namespace URI. That knowledge is emedded inside the + RuleSet class itself.
        • +
        • If desired, you could make a set of rules work for more than one + namespace URI by providing constructors on the RuleSet to + allow this to be specified dynamically.
        • +
        • The MyRuleSet example above illustrates another technique + that increases reusability -- you can specify (as an argument to the + constructor) the leading portion of the matching pattern to be used. + In this way, you can construct a Digester that recognizes + the same set of nested elements at different nesting levels within an + XML document.
        • +
        + +

        Using Named Stacks For Inter-Rule Communication

        +

        +Digester is based on Rule instances working together +to process xml. For anything other than the most trival processing, +communication between Rule instances is necessary. Since Rule +instances are processed in sequence, this usually means storing an Object +somewhere where later instances can retrieve it. +

        +

        +Digester is based on SAX. The most natural data structure to use with +SAX based xml processing is the stack. This allows more powerful processes to be +specified more simply since the pushing and popping of objects can mimic the +nested structure of the xml. +

        +

        +Digester uses two basic stacks: one for the main beans and the other +for parameters for method calls. These are inadequate for complex processing +where many different Rule instances need to communicate through +different channels. +

        +

        +In this case, it is recommended that named stacks are used. In addition to the +two basic stacks, Digester allows rules to use an unlimited number +of other stacks referred two by an identifying string (the name). (That's where +the term named stack comes from.) These stacks are +accessed through calls to: +

        + +

        +Note: all stack names beginning with org.apache.commons.digester +are reserved for future use by the Digester component. It is also recommended +that users choose stack names perfixed by the name of their own domain to avoid conflicts +with other Rule implementations. +

        + +

        Registering DTDs

        + +

        Brief (But Still Too Long) Introduction To System and Public Identifiers

        +

        A definition for an external entity comes in one of two forms: +

        +
          +
        1. SYSTEM system-identifier
        2. +
        3. PUBLIC public-identifier system-identifier
        4. +
        +

        +The system-identifier is an URI from which the resource can be obtained +(either directly or indirectly). Many valid URIs may identify the same resource. +The public-identifier is an additional free identifier which may be used +(by the parser) to locate the resource. +

        +

        +In practice, the weakness with a system-identifier is that most parsers +will attempt to interprete this URI as an URL, try to download the resource directly +from the URL and stop the parsing if this download fails. So, this means that +almost always the URI will have to be an URL from which the declaration +can be downloaded. +

        +

        +URLs may be local or remote but if the URL is chosen to be local, it is likely only +to function correctly on a small number of machines (which are configured precisely +to allow the xml to be parsed). This is usually unsatisfactory and so a universally +accessable URL is preferred. This usually means an internet URL. +

        +

        +To recap, in practice the system-identifier will (most likely) be an +internet URL. Unfortunately downloading from an internet URL is not only slow +but unreliable (since successfully downloading a document from the internet +relies on the client being connect to the internet and the server being +able to satisfy the request). +

        +

        +The public-identifier is a freely defined name but (in practice) it is +strongly recommended that a unique, readable and open format is used (for reasons +that should become clear later). A Formal Public Identifier (FPI) is a very +common choice. This public identifier is often used to provide a unique and location +independent key which can be used to subsistute local resources for remote ones +(hint: this is why ;). +

        +

        +By using the second (PUBLIC) form combined with some form of local +catalog (which matches public-identifiers to local resources) and where +the public-identifier is a unique name and the system-identifier +is an internet URL, the practical disadvantages of specifying just a +system-identifier can be avoided. Those external entities which have been +store locally (on the machine parsing the document) can be identified and used. +Only when no local copy exists is it necessary to download the document +from the internet URL. This naming scheme is recommended when using Digester. +

        + +

        External Entity Resolution Using Digester

        +

        +SAX factors out the resolution of external entities into an EntityResolver. +Digester supports the use of custom EntityResolver +but ships with a simple internal implementation. This implementation allows local URLs +to be easily associated with public-identifiers. +

        +

        For example:

        +
        +    digester.register("-//Example Dot Com //DTD Sample Example//EN", "assets/sample.dtd");
        +
        +

        +will make digester return the relative file path assets/sample.dtd +whenever an external entity with public id +-//Example Dot Com //DTD Sample Example//EN is needed. +

        +

        Note: This is a simple (but useful) implementation. +Greater sophistication requires a custom EntityResolver.

        + + +

        Troubleshooting

        +

        Debugging Exceptions

        +

        +Digester is based on SAX. +Digestion throws two kinds of Exception: +

        +
          +
        • java.io.IOException
        • +
        • org.xml.sax.SAXException
        • +
        +

        +The first is rarely thrown and indicates the kind of fundemental IO exception +that developers know all about. The second is thrown by SAX parsers when the processing +of the XML cannot be completed. So, to diagnose the cause a certain familiarity with +the way that SAX error handling works is very useful. +

        +
        Diagnosing SAX Exceptions
        +

        +This is a short, potted guide to SAX error handling strategies. It's not intended as a +proper guide to error handling in SAX. +

        +

        +When a SAX parser encounters a problem with the xml (well, ok - sometime after it +encounters a problem) it will throw a + +SAXParseException. This is a subclass of SAXException and contains +a bit of extra information about what exactly when wrong - and more importantly, +where it went wrong. If you catch an exception of this sort, you can be sure that +the problem is with the XML and not Digester or your rules. +It is usually a good idea to catch this exception and log the extra information +to help with diagnosing the reason for the failure. +

        +

        +General +SAXException instances may wrap a causal exception. When exceptions are +throw by Digester each of these will be wrapped into a +SAXException and rethrown. So, catch these and examine the wrapped +exception to diagnose what went wrong. +

        + +

        Frequently Asked Questions

        +

        + +

        Known Limitations

        +

        Accessing Public Methods In A Default Access Superclass

        +

        There is an issue when invoking public methods contained in a default access superclass. +Reflection locates these methods fine and correctly assigns them as public. +However, an IllegalAccessException is thrown if the method is invoked.

        + +

        MethodUtils contains a workaround for this situation. +It will attempt to call setAccessible on this method. +If this call succeeds, then the method can be invoked as normal. +This call will only succeed when the application has sufficient security privilages. +If this call fails then a warning will be logged and the method may fail.

        + +

        Digester uses MethodUtils and so there may be an issue accessing methods +of this kind from a high security environment. If you think that you might be experiencing this +problem, please ask on the mailing list.

        + + diff --git a/java/org/apache/tomcat/util/http/AcceptLanguage.java b/java/org/apache/tomcat/util/http/AcceptLanguage.java index 2d2a1bf09..9b0243939 100644 --- a/java/org/apache/tomcat/util/http/AcceptLanguage.java +++ b/java/org/apache/tomcat/util/http/AcceptLanguage.java @@ -1,147 +1,147 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Locale; -import java.util.StringTokenizer; -import java.util.Vector; - -/** - * Util to process the "Accept-Language" header. Used by facade to implement - * getLocale() and by StaticInterceptor. - * - * Not optimized - it's very slow. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author Harish Prabandham - * @author costin@eng.sun.com - */ -public class AcceptLanguage { - - public static Locale getLocale(String acceptLanguage) { - if( acceptLanguage == null ) return Locale.getDefault(); - - Hashtable languages = new Hashtable(); - Vector quality=new Vector(); - processAcceptLanguage(acceptLanguage, languages,quality); - - if (languages.size() == 0) return Locale.getDefault(); - - Vector l = new Vector(); - extractLocales( languages,quality, l); - - return (Locale)l.elementAt(0); - } - - public static Enumeration getLocales(String acceptLanguage) { - // Short circuit with an empty enumeration if null header - if (acceptLanguage == null) { - Vector v = new Vector(); - v.addElement(Locale.getDefault()); - return v.elements(); - } - - Hashtable languages = new Hashtable(); - Vector quality=new Vector(); - processAcceptLanguage(acceptLanguage, languages , quality); - - if (languages.size() == 0) { - Vector v = new Vector(); - v.addElement(Locale.getDefault()); - return v.elements(); - } - Vector l = new Vector(); - extractLocales( languages, quality , l); - return l.elements(); - } - - private static void processAcceptLanguage( String acceptLanguage, - Hashtable languages, Vector q) - { - StringTokenizer languageTokenizer = - new StringTokenizer(acceptLanguage, ","); - - while (languageTokenizer.hasMoreTokens()) { - String language = languageTokenizer.nextToken().trim(); - int qValueIndex = language.indexOf(';'); - int qIndex = language.indexOf('q'); - int equalIndex = language.indexOf('='); - Double qValue = new Double(1); - - if (qValueIndex > -1 && - qValueIndex < qIndex && - qIndex < equalIndex) { - String qValueStr = language.substring(qValueIndex + 1); - language = language.substring(0, qValueIndex); - qValueStr = qValueStr.trim().toLowerCase(); - qValueIndex = qValueStr.indexOf('='); - qValue = new Double(0); - if (qValueStr.startsWith("q") && - qValueIndex > -1) { - qValueStr = qValueStr.substring(qValueIndex + 1); - try { - qValue = new Double(qValueStr.trim()); - } catch (NumberFormatException nfe) { - } - } - } - - // XXX - // may need to handle "*" at some point in time - - if (! language.equals("*")) { - String key = qValue.toString(); - Vector v; - if (languages.containsKey(key)) { - v = (Vector)languages.get(key) ; - } else { - v= new Vector(); - q.addElement(qValue); - } - v.addElement(language); - languages.put(key, v); - } - } - } - - private static void extractLocales(Hashtable languages, Vector q,Vector l) - { - // XXX We will need to order by q value Vector in the Future ? - Enumeration e = q.elements(); - while (e.hasMoreElements()) { - Vector v = - (Vector)languages.get(((Double)e.nextElement()).toString()); - Enumeration le = v.elements(); - while (le.hasMoreElements()) { - String language = (String)le.nextElement(); - String country = ""; - int countryIndex = language.indexOf("-"); - if (countryIndex > -1) { - country = language.substring(countryIndex + 1).trim(); - language = language.substring(0, countryIndex).trim(); - } - l.addElement(new Locale(language, country)); - } - } - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Locale; +import java.util.StringTokenizer; +import java.util.Vector; + +/** + * Util to process the "Accept-Language" header. Used by facade to implement + * getLocale() and by StaticInterceptor. + * + * Not optimized - it's very slow. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author Harish Prabandham + * @author costin@eng.sun.com + */ +public class AcceptLanguage { + + public static Locale getLocale(String acceptLanguage) { + if( acceptLanguage == null ) return Locale.getDefault(); + + Hashtable languages = new Hashtable(); + Vector quality=new Vector(); + processAcceptLanguage(acceptLanguage, languages,quality); + + if (languages.size() == 0) return Locale.getDefault(); + + Vector l = new Vector(); + extractLocales( languages,quality, l); + + return (Locale)l.elementAt(0); + } + + public static Enumeration getLocales(String acceptLanguage) { + // Short circuit with an empty enumeration if null header + if (acceptLanguage == null) { + Vector v = new Vector(); + v.addElement(Locale.getDefault()); + return v.elements(); + } + + Hashtable languages = new Hashtable(); + Vector quality=new Vector(); + processAcceptLanguage(acceptLanguage, languages , quality); + + if (languages.size() == 0) { + Vector v = new Vector(); + v.addElement(Locale.getDefault()); + return v.elements(); + } + Vector l = new Vector(); + extractLocales( languages, quality , l); + return l.elements(); + } + + private static void processAcceptLanguage( String acceptLanguage, + Hashtable languages, Vector q) + { + StringTokenizer languageTokenizer = + new StringTokenizer(acceptLanguage, ","); + + while (languageTokenizer.hasMoreTokens()) { + String language = languageTokenizer.nextToken().trim(); + int qValueIndex = language.indexOf(';'); + int qIndex = language.indexOf('q'); + int equalIndex = language.indexOf('='); + Double qValue = new Double(1); + + if (qValueIndex > -1 && + qValueIndex < qIndex && + qIndex < equalIndex) { + String qValueStr = language.substring(qValueIndex + 1); + language = language.substring(0, qValueIndex); + qValueStr = qValueStr.trim().toLowerCase(); + qValueIndex = qValueStr.indexOf('='); + qValue = new Double(0); + if (qValueStr.startsWith("q") && + qValueIndex > -1) { + qValueStr = qValueStr.substring(qValueIndex + 1); + try { + qValue = new Double(qValueStr.trim()); + } catch (NumberFormatException nfe) { + } + } + } + + // XXX + // may need to handle "*" at some point in time + + if (! language.equals("*")) { + String key = qValue.toString(); + Vector v; + if (languages.containsKey(key)) { + v = (Vector)languages.get(key) ; + } else { + v= new Vector(); + q.addElement(qValue); + } + v.addElement(language); + languages.put(key, v); + } + } + } + + private static void extractLocales(Hashtable languages, Vector q,Vector l) + { + // XXX We will need to order by q value Vector in the Future ? + Enumeration e = q.elements(); + while (e.hasMoreElements()) { + Vector v = + (Vector)languages.get(((Double)e.nextElement()).toString()); + Enumeration le = v.elements(); + while (le.hasMoreElements()) { + String language = (String)le.nextElement(); + String country = ""; + int countryIndex = language.indexOf("-"); + if (countryIndex > -1) { + country = language.substring(countryIndex + 1).trim(); + language = language.substring(0, countryIndex).trim(); + } + l.addElement(new Locale(language, country)); + } + } + } + + +} diff --git a/java/org/apache/tomcat/util/http/BaseRequest.java b/java/org/apache/tomcat/util/http/BaseRequest.java index c05651d06..86085d124 100644 --- a/java/org/apache/tomcat/util/http/BaseRequest.java +++ b/java/org/apache/tomcat/util/http/BaseRequest.java @@ -1,345 +1,345 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*************************************************************************** - * Description: Base http request object. * - * Author: Keving Seguin [seguin@apache.org] * - * Version: $Revision: 299484 $ * - ***************************************************************************/ - -package org.apache.tomcat.util.http; - -import java.io.PrintWriter; -import java.io.StringWriter; - -import java.util.HashMap; -import java.util.Iterator; - -import org.apache.tomcat.util.buf.MessageBytes; - -/** - * A general-purpose object for representing an HTTP - * request. - */ -public class BaseRequest { - - // scheme constants - public static final String SCHEME_HTTP = "http"; - public static final String SCHEME_HTTPS = "https"; - - // request attributes - MessageBytes method = MessageBytes.newInstance(); - MessageBytes protocol = MessageBytes.newInstance(); - MessageBytes requestURI = MessageBytes.newInstance(); - MessageBytes remoteAddr = MessageBytes.newInstance(); - MessageBytes remoteHost = MessageBytes.newInstance(); - MessageBytes serverName = MessageBytes.newInstance(); - int serverPort = 80; - MessageBytes remoteUser = MessageBytes.newInstance(); - MessageBytes authType = MessageBytes.newInstance(); - MessageBytes queryString = MessageBytes.newInstance(); - MessageBytes authorization = MessageBytes.newInstance(); - String scheme = SCHEME_HTTP; - boolean secure = false; - int contentLength = 0; - MessageBytes contentType = MessageBytes.newInstance(); - MimeHeaders headers = new MimeHeaders(); - Cookies cookies = new Cookies(); - HashMap attributes = new HashMap(); - - MessageBytes tomcatInstanceId = MessageBytes.newInstance(); - - /** - * Recycles this object and readies it further use. - */ - public void recycle() { - method.recycle(); - protocol.recycle(); - requestURI.recycle(); - remoteAddr.recycle(); - remoteHost.recycle(); - serverName.recycle(); - serverPort = 80; - remoteUser.recycle(); - authType.recycle(); - queryString.recycle(); - authorization.recycle(); - scheme = SCHEME_HTTP; - secure = false; - contentLength = 0; - contentType.recycle(); - headers.recycle(); - cookies.recycle(); - attributes.clear(); - tomcatInstanceId.recycle(); - } - - /** - * Get the method. - * @return the method - */ - public MessageBytes method() { - return method; - } - - /** - * Get the protocol - * @return the protocol - */ - public MessageBytes protocol() { - return protocol; - } - - /** - * Get the request uri - * @return the request uri - */ - public MessageBytes requestURI() { - return requestURI; - } - - /** - * Get the remote address - * @return the remote address - */ - public MessageBytes remoteAddr() { - return remoteAddr; - } - - /** - * Get the remote host - * @return the remote host - */ - public MessageBytes remoteHost() { - return remoteHost; - } - - /** - * Get the server name - * @return the server name - */ - public MessageBytes serverName() { - return serverName; - } - - /** - * Get the server port - * @return the server port - */ - public int getServerPort() { - return serverPort; - } - - /** - * Set the server port - * @param i the server port - */ - public void setServerPort(int i) { - serverPort = i; - } - - /** - * Get the remote user - * @return the remote user - */ - public MessageBytes remoteUser() { - return remoteUser; - } - - /** - * Get the auth type - * @return the auth type - */ - public MessageBytes authType() { - return authType; - } - - /** - * Get the query string - * @return the query string - */ - public MessageBytes queryString() { - return queryString; - } - - /** - * Get the authorization credentials - * @return the authorization credentials - */ - public MessageBytes authorization() { - return authorization; - } - - /** - * Get the scheme - * @return the scheme - */ - public String getScheme() { - return scheme; - } - - /** - * Set the scheme. - * @param s the scheme - */ - public void setScheme(String s) { - scheme = s; - } - - /** - * Get whether the request is secure or not. - * @return true if the request is secure. - */ - public boolean getSecure() { - return secure; - } - - /** - * Set whether the request is secure or not. - * @param b true if the request is secure. - */ - public void setSecure(boolean b) { - secure = b; - } - - /** - * Get the content length - * @return the content length - */ - public int getContentLength() { - return contentLength; - } - - /** - * Set the content length - * @param i the content length - */ - public void setContentLength(int i) { - contentLength = i; - } - - /** - * Get the content type - * @return the content type - */ - public MessageBytes contentType() { - return contentType; - } - - /** - * Get this request's headers - * @return request headers - */ - public MimeHeaders headers() { - return headers; - } - - /** - * Get cookies. - * @return request cookies. - */ - public Cookies cookies() { - return cookies; - } - - /** - * Set an attribute on the request - * @param name attribute name - * @param value attribute value - */ - public void setAttribute(String name, Object value) { - if (name == null || value == null) { - return; - } - attributes.put(name, value); - } - - /** - * Get an attribute on the request - * @param name attribute name - * @return attribute value - */ - public Object getAttribute(String name) { - if (name == null) { - return null; - } - - return attributes.get(name); - } - - /** - * Get iterator over attribute names - * @return iterator over attribute names - */ - public Iterator getAttributeNames() { - return attributes.keySet().iterator(); - } - - /** - * Get the host id ( or jvmRoute ) - * @return the jvm route - */ - public MessageBytes instanceId() { - return tomcatInstanceId; - } - - // backward compat - jvmRoute is the id of this tomcat instance, - // used by a load balancer on the server side to implement sticky - // sessions, and on the tomcat side to format the session ids. - public MessageBytes jvmRoute() { - return tomcatInstanceId; - } - - private Object notes[]=new Object[16]; - - public final Object getNote(int id) { - return notes[id]; - } - - public final void setNote(int id, Object cr) { - notes[id]=cr; - } - - /** - * ** SLOW ** for debugging only! - */ - public String toString() { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - - pw.println("=== BaseRequest ==="); - pw.println("method = " + method.toString()); - pw.println("protocol = " + protocol.toString()); - pw.println("requestURI = " + requestURI.toString()); - pw.println("remoteAddr = " + remoteAddr.toString()); - pw.println("remoteHost = " + remoteHost.toString()); - pw.println("serverName = " + serverName.toString()); - pw.println("serverPort = " + serverPort); - pw.println("remoteUser = " + remoteUser.toString()); - pw.println("authType = " + authType.toString()); - pw.println("queryString = " + queryString.toString()); - pw.println("scheme = " + scheme.toString()); - pw.println("secure = " + secure); - pw.println("contentLength = " + contentLength); - pw.println("contentType = " + contentType); - pw.println("attributes = " + attributes.toString()); - pw.println("headers = " + headers.toString()); - pw.println("cookies = " + cookies.toString()); - pw.println("jvmRoute = " + tomcatInstanceId.toString()); - return sw.toString(); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/*************************************************************************** + * Description: Base http request object. * + * Author: Keving Seguin [seguin@apache.org] * + * Version: $Revision: 299484 $ * + ***************************************************************************/ + +package org.apache.tomcat.util.http; + +import java.io.PrintWriter; +import java.io.StringWriter; + +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * A general-purpose object for representing an HTTP + * request. + */ +public class BaseRequest { + + // scheme constants + public static final String SCHEME_HTTP = "http"; + public static final String SCHEME_HTTPS = "https"; + + // request attributes + MessageBytes method = MessageBytes.newInstance(); + MessageBytes protocol = MessageBytes.newInstance(); + MessageBytes requestURI = MessageBytes.newInstance(); + MessageBytes remoteAddr = MessageBytes.newInstance(); + MessageBytes remoteHost = MessageBytes.newInstance(); + MessageBytes serverName = MessageBytes.newInstance(); + int serverPort = 80; + MessageBytes remoteUser = MessageBytes.newInstance(); + MessageBytes authType = MessageBytes.newInstance(); + MessageBytes queryString = MessageBytes.newInstance(); + MessageBytes authorization = MessageBytes.newInstance(); + String scheme = SCHEME_HTTP; + boolean secure = false; + int contentLength = 0; + MessageBytes contentType = MessageBytes.newInstance(); + MimeHeaders headers = new MimeHeaders(); + Cookies cookies = new Cookies(); + HashMap attributes = new HashMap(); + + MessageBytes tomcatInstanceId = MessageBytes.newInstance(); + + /** + * Recycles this object and readies it further use. + */ + public void recycle() { + method.recycle(); + protocol.recycle(); + requestURI.recycle(); + remoteAddr.recycle(); + remoteHost.recycle(); + serverName.recycle(); + serverPort = 80; + remoteUser.recycle(); + authType.recycle(); + queryString.recycle(); + authorization.recycle(); + scheme = SCHEME_HTTP; + secure = false; + contentLength = 0; + contentType.recycle(); + headers.recycle(); + cookies.recycle(); + attributes.clear(); + tomcatInstanceId.recycle(); + } + + /** + * Get the method. + * @return the method + */ + public MessageBytes method() { + return method; + } + + /** + * Get the protocol + * @return the protocol + */ + public MessageBytes protocol() { + return protocol; + } + + /** + * Get the request uri + * @return the request uri + */ + public MessageBytes requestURI() { + return requestURI; + } + + /** + * Get the remote address + * @return the remote address + */ + public MessageBytes remoteAddr() { + return remoteAddr; + } + + /** + * Get the remote host + * @return the remote host + */ + public MessageBytes remoteHost() { + return remoteHost; + } + + /** + * Get the server name + * @return the server name + */ + public MessageBytes serverName() { + return serverName; + } + + /** + * Get the server port + * @return the server port + */ + public int getServerPort() { + return serverPort; + } + + /** + * Set the server port + * @param i the server port + */ + public void setServerPort(int i) { + serverPort = i; + } + + /** + * Get the remote user + * @return the remote user + */ + public MessageBytes remoteUser() { + return remoteUser; + } + + /** + * Get the auth type + * @return the auth type + */ + public MessageBytes authType() { + return authType; + } + + /** + * Get the query string + * @return the query string + */ + public MessageBytes queryString() { + return queryString; + } + + /** + * Get the authorization credentials + * @return the authorization credentials + */ + public MessageBytes authorization() { + return authorization; + } + + /** + * Get the scheme + * @return the scheme + */ + public String getScheme() { + return scheme; + } + + /** + * Set the scheme. + * @param s the scheme + */ + public void setScheme(String s) { + scheme = s; + } + + /** + * Get whether the request is secure or not. + * @return true if the request is secure. + */ + public boolean getSecure() { + return secure; + } + + /** + * Set whether the request is secure or not. + * @param b true if the request is secure. + */ + public void setSecure(boolean b) { + secure = b; + } + + /** + * Get the content length + * @return the content length + */ + public int getContentLength() { + return contentLength; + } + + /** + * Set the content length + * @param i the content length + */ + public void setContentLength(int i) { + contentLength = i; + } + + /** + * Get the content type + * @return the content type + */ + public MessageBytes contentType() { + return contentType; + } + + /** + * Get this request's headers + * @return request headers + */ + public MimeHeaders headers() { + return headers; + } + + /** + * Get cookies. + * @return request cookies. + */ + public Cookies cookies() { + return cookies; + } + + /** + * Set an attribute on the request + * @param name attribute name + * @param value attribute value + */ + public void setAttribute(String name, Object value) { + if (name == null || value == null) { + return; + } + attributes.put(name, value); + } + + /** + * Get an attribute on the request + * @param name attribute name + * @return attribute value + */ + public Object getAttribute(String name) { + if (name == null) { + return null; + } + + return attributes.get(name); + } + + /** + * Get iterator over attribute names + * @return iterator over attribute names + */ + public Iterator getAttributeNames() { + return attributes.keySet().iterator(); + } + + /** + * Get the host id ( or jvmRoute ) + * @return the jvm route + */ + public MessageBytes instanceId() { + return tomcatInstanceId; + } + + // backward compat - jvmRoute is the id of this tomcat instance, + // used by a load balancer on the server side to implement sticky + // sessions, and on the tomcat side to format the session ids. + public MessageBytes jvmRoute() { + return tomcatInstanceId; + } + + private Object notes[]=new Object[16]; + + public final Object getNote(int id) { + return notes[id]; + } + + public final void setNote(int id, Object cr) { + notes[id]=cr; + } + + /** + * ** SLOW ** for debugging only! + */ + public String toString() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + + pw.println("=== BaseRequest ==="); + pw.println("method = " + method.toString()); + pw.println("protocol = " + protocol.toString()); + pw.println("requestURI = " + requestURI.toString()); + pw.println("remoteAddr = " + remoteAddr.toString()); + pw.println("remoteHost = " + remoteHost.toString()); + pw.println("serverName = " + serverName.toString()); + pw.println("serverPort = " + serverPort); + pw.println("remoteUser = " + remoteUser.toString()); + pw.println("authType = " + authType.toString()); + pw.println("queryString = " + queryString.toString()); + pw.println("scheme = " + scheme.toString()); + pw.println("secure = " + secure); + pw.println("contentLength = " + contentLength); + pw.println("contentType = " + contentType); + pw.println("attributes = " + attributes.toString()); + pw.println("headers = " + headers.toString()); + pw.println("cookies = " + cookies.toString()); + pw.println("jvmRoute = " + tomcatInstanceId.toString()); + return sw.toString(); + } + +} diff --git a/java/org/apache/tomcat/util/http/ContentType.java b/java/org/apache/tomcat/util/http/ContentType.java index b47f0c05b..b9018da95 100644 --- a/java/org/apache/tomcat/util/http/ContentType.java +++ b/java/org/apache/tomcat/util/http/ContentType.java @@ -1,92 +1,92 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - - -/** - * Usefull methods for Content-Type processing - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author Harish Prabandham - * @author costin@eng.sun.com - */ -public class ContentType { - - // Basically return everything after ";charset=" - // If no charset specified, use the HTTP default (ASCII) character set. - public static String getCharsetFromContentType(String type) { - if (type == null) { - return null; - } - int semi = type.indexOf(";"); - if (semi == -1) { - return null; - } - int charsetLocation = type.indexOf("charset=", semi); - if (charsetLocation == -1) { - return null; - } - String afterCharset = type.substring(charsetLocation + 8); - // The charset value in a Content-Type header is allowed to be quoted - // and charset values can't contain quotes. Just convert any quote - // chars into spaces and let trim clean things up. - afterCharset = afterCharset.replace('"', ' '); - String encoding = afterCharset.trim(); - return encoding; - } - - - /** - * Returns true if the given content type contains a charset component, - * false otherwise. - * - * @param type Content type - * @return true if the given content type contains a charset component, - * false otherwise - */ - public static boolean hasCharset(String type) { - - boolean hasCharset = false; - - int len = type.length(); - int index = type.indexOf(';'); - while (index != -1) { - index++; - while (index < len && Character.isSpace(type.charAt(index))) { - index++; - } - if (index+8 < len - && type.charAt(index) == 'c' - && type.charAt(index+1) == 'h' - && type.charAt(index+2) == 'a' - && type.charAt(index+3) == 'r' - && type.charAt(index+4) == 's' - && type.charAt(index+5) == 'e' - && type.charAt(index+6) == 't' - && type.charAt(index+7) == '=') { - hasCharset = true; - break; - } - index = type.indexOf(';', index); - } - - return hasCharset; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + + +/** + * Usefull methods for Content-Type processing + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author Harish Prabandham + * @author costin@eng.sun.com + */ +public class ContentType { + + // Basically return everything after ";charset=" + // If no charset specified, use the HTTP default (ASCII) character set. + public static String getCharsetFromContentType(String type) { + if (type == null) { + return null; + } + int semi = type.indexOf(";"); + if (semi == -1) { + return null; + } + int charsetLocation = type.indexOf("charset=", semi); + if (charsetLocation == -1) { + return null; + } + String afterCharset = type.substring(charsetLocation + 8); + // The charset value in a Content-Type header is allowed to be quoted + // and charset values can't contain quotes. Just convert any quote + // chars into spaces and let trim clean things up. + afterCharset = afterCharset.replace('"', ' '); + String encoding = afterCharset.trim(); + return encoding; + } + + + /** + * Returns true if the given content type contains a charset component, + * false otherwise. + * + * @param type Content type + * @return true if the given content type contains a charset component, + * false otherwise + */ + public static boolean hasCharset(String type) { + + boolean hasCharset = false; + + int len = type.length(); + int index = type.indexOf(';'); + while (index != -1) { + index++; + while (index < len && Character.isSpace(type.charAt(index))) { + index++; + } + if (index+8 < len + && type.charAt(index) == 'c' + && type.charAt(index+1) == 'h' + && type.charAt(index+2) == 'a' + && type.charAt(index+3) == 'r' + && type.charAt(index+4) == 's' + && type.charAt(index+5) == 'e' + && type.charAt(index+6) == 't' + && type.charAt(index+7) == '=') { + hasCharset = true; + break; + } + index = type.indexOf(';', index); + } + + return hasCharset; + } + +} diff --git a/java/org/apache/tomcat/util/http/Cookies.java b/java/org/apache/tomcat/util/http/Cookies.java index a071afc07..83253b81c 100644 --- a/java/org/apache/tomcat/util/http/Cookies.java +++ b/java/org/apache/tomcat/util/http/Cookies.java @@ -1,481 +1,481 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.StringTokenizer; - -import org.apache.tomcat.util.buf.ByteChunk; -import org.apache.tomcat.util.buf.MessageBytes; - -/** - * A collection of cookies - reusable and tuned for server side performance. - * Based on RFC2965 ( and 2109 ) - * - * This class is not synchronized. - * - * @author Costin Manolache - * @author kevin seguin - */ -public final class Cookies { // extends MultiMap { - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(Cookies.class ); - - // expected average number of cookies per request - public static final int INITIAL_SIZE=4; - ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE]; - int cookieCount=0; - boolean unprocessed=true; - - MimeHeaders headers; - - /** - * Construct a new cookie collection, that will extract - * the information from headers. - * - * @param headers Cookies are lazy-evaluated and will extract the - * information from the provided headers. - */ - public Cookies(MimeHeaders headers) { - this.headers=headers; - } - - /** - * Construct a new uninitialized cookie collection. - * Use {@link #setHeaders} to initialize. - */ - // [seguin] added so that an empty Cookies object could be - // created, have headers set, then recycled. - public Cookies() { - } - - /** - * Set the headers from which cookies will be pulled. - * This has the side effect of recycling the object. - * - * @param headers Cookies are lazy-evaluated and will extract the - * information from the provided headers. - */ - // [seguin] added so that an empty Cookies object could be - // created, have headers set, then recycled. - public void setHeaders(MimeHeaders headers) { - recycle(); - this.headers=headers; - } - - /** - * Recycle. - */ - public void recycle() { - for( int i=0; i< cookieCount; i++ ) { - if( scookies[i]!=null ) - scookies[i].recycle(); - } - cookieCount=0; - unprocessed=true; - } - - /** - * EXPENSIVE!!! only for debugging. - */ - public String toString() { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.println("=== Cookies ==="); - int count = getCookieCount(); - for (int i = 0; i < count; ++i) { - pw.println(getCookie(i).toString()); - } - return sw.toString(); - } - - // -------------------- Indexed access -------------------- - - public ServerCookie getCookie( int idx ) { - if( unprocessed ) { - getCookieCount(); // will also update the cookies - } - return scookies[idx]; - } - - public int getCookieCount() { - if( unprocessed ) { - unprocessed=false; - processCookies(headers); - } - return cookieCount; - } - - // -------------------- Adding cookies -------------------- - - /** Register a new, unitialized cookie. Cookies are recycled, and - * most of the time an existing ServerCookie object is returned. - * The caller can set the name/value and attributes for the cookie - */ - public ServerCookie addCookie() { - if( cookieCount >= scookies.length ) { - ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount]; - System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount); - scookies=scookiesTmp; - } - - ServerCookie c = scookies[cookieCount]; - if( c==null ) { - c= new ServerCookie(); - scookies[cookieCount]=c; - } - cookieCount++; - return c; - } - - - // code from CookieTools - - /** Add all Cookie found in the headers of a request. - */ - public void processCookies( MimeHeaders headers ) { - if( headers==null ) - return;// nothing to process - // process each "cookie" header - int pos=0; - while( pos>=0 ) { - // Cookie2: version ? not needed - pos=headers.findHeader( "Cookie", pos ); - // no more cookie headers headers - if( pos<0 ) break; - - MessageBytes cookieValue=headers.getValue( pos ); - if( cookieValue==null || cookieValue.isNull() ) { - pos++; - continue; - } - - // Uncomment to test the new parsing code - if( cookieValue.getType() == MessageBytes.T_BYTES ) { - if( dbg>0 ) log( "Parsing b[]: " + cookieValue.toString()); - ByteChunk bc=cookieValue.getByteChunk(); - processCookieHeader( bc.getBytes(), - bc.getOffset(), - bc.getLength()); - } else { - if( dbg>0 ) log( "Parsing S: " + cookieValue.toString()); - processCookieHeader( cookieValue.toString() ); - } - pos++;// search from the next position - } - } - - /** Process a byte[] header - allowing fast processing of the - * raw data - */ - void processCookieHeader( byte bytes[], int off, int len ) - { - if( len<=0 || bytes==null ) return; - int end=off+len; - int pos=off; - - int version=0; //sticky - ServerCookie sc=null; - - - while( pos=end ) - return; // only spaces - int startName=pos; - if( dbg>0 ) log( "SN: " + pos ); - - // Version should be the first token - boolean isSpecial=false; - if(bytes[pos]=='$') { pos++; isSpecial=true; } - - pos= findDelim1( bytes, startName, end); // " =;," - int endName=pos; - // current = "=" or " " or DELIM - pos= skipSpaces( bytes, endName, end ); - if( dbg>0 ) log( "DELIM: " + endName + " " + (char)bytes[pos]); - - if(pos >= end ) { - // it's a name-only cookie ( valid in RFC2109 ) - if( ! isSpecial ) { - sc=addCookie(); - sc.getName().setBytes( bytes, startName, - endName-startName ); - sc.getValue().setString(""); - sc.setVersion( version ); - if( dbg>0 ) log( "Name only, end: " + startName + " " + - endName); - } - return; - } - - cc=bytes[pos]; - pos++; - if( cc==';' || cc==',' || pos>=end ) { - if( ! isSpecial && startName!= endName ) { - sc=addCookie(); - sc.getName().setBytes( bytes, startName, - endName-startName ); - sc.getValue().setString(""); - sc.setVersion( version ); - if( dbg>0 ) log( "Name only: " + startName + " " + endName); - } - continue; - } - - // we should have "=" ( tested all other alternatives ) - int startValue=skipSpaces( bytes, pos, end); - int endValue=startValue; - - cc=bytes[pos]; - if( cc== '\'' || cc=='"' ) { - startValue++; - endValue=indexOf( bytes, startValue, end, cc ); - pos=endValue+1; // to skip to next cookie - } else { - endValue=findDelim2( bytes, startValue, end ); - pos=endValue+1; - } - - // if not $Version, etc - if( ! isSpecial ) { - sc=addCookie(); - sc.getName().setBytes( bytes, startName, endName-startName ); - sc.getValue().setBytes( bytes, startValue, endValue-startValue); - sc.setVersion( version ); - if( dbg>0 ) { - log( "New: " + sc.getName() + "X=X" + sc.getValue()); - } - continue; - } - - // special - Path, Version, Domain, Port - if( dbg>0 ) log( "Special: " + startName + " " + endName); - // XXX TODO - if( equals( "$Version", bytes, startName, endName ) ) { - if(dbg>0 ) log( "Found version " ); - if( bytes[startValue]=='1' && endValue==startValue+1 ) { - version=1; - if(dbg>0 ) log( "Found version=1" ); - } - continue; - } - if( sc==null ) { - // Path, etc without a previous cookie - continue; - } - if( equals( "$Path", bytes, startName, endName ) ) { - sc.getPath().setBytes( bytes, - startValue, - endValue-startValue ); - } - if( equals( "$Domain", bytes, startName, endName ) ) { - sc.getDomain().setBytes( bytes, - startValue, - endValue-startValue ); - } - if( equals( "$Port", bytes, startName, endName ) ) { - // sc.getPort().setBytes( bytes, - // startValue, - // endValue-startValue ); - } - } - } - - // -------------------- Utils -------------------- - public static int skipSpaces( byte bytes[], int off, int end ) { - while( off < end ) { - byte b=bytes[off]; - if( b!= ' ' ) return off; - off ++; - } - return off; - } - - public static int findDelim1( byte bytes[], int off, int end ) - { - while( off < end ) { - byte b=bytes[off]; - if( b==' ' || b=='=' || b==';' || b==',' ) - return off; - off++; - } - return off; - } - - public static int findDelim2( byte bytes[], int off, int end ) - { - while( off < end ) { - byte b=bytes[off]; - if( b==';' || b==',' ) - return off; - off++; - } - return off; - } - - public static int indexOf( byte bytes[], int off, int end, byte qq ) - { - while( off < end ) { - byte b=bytes[off]; - if( b==qq ) - return off; - off++; - } - return off; - } - - public static int indexOf( byte bytes[], int off, int end, char qq ) - { - while( off < end ) { - byte b=bytes[off]; - if( b==qq ) - return off; - off++; - } - return off; - } - - // XXX will be refactored soon! - public static boolean equals( String s, byte b[], int start, int end) { - int blen = end-start; - if (b == null || blen != s.length()) { - return false; - } - int boff = start; - for (int i = 0; i < blen; i++) { - if (b[boff++] != s.charAt(i)) { - return false; - } - } - return true; - } - - - // --------------------------------------------------------- - // -------------------- DEPRECATED, OLD -------------------- - - private void processCookieHeader( String cookieString ) - { - if( dbg>0 ) log( "Parsing cookie header " + cookieString ); - // normal cookie, with a string value. - // This is the original code, un-optimized - it shouldn't - // happen in normal case - - StringTokenizer tok = new StringTokenizer(cookieString, - ";", false); - while (tok.hasMoreTokens()) { - String token = tok.nextToken(); - int i = token.indexOf("="); - if (i > -1) { - - // XXX - // the trims here are a *hack* -- this should - // be more properly fixed to be spec compliant - - String name = token.substring(0, i).trim(); - String value = token.substring(i+1, token.length()).trim(); - // RFC 2109 and bug - value=stripQuote( value ); - ServerCookie cookie = addCookie(); - - cookie.getName().setString(name); - cookie.getValue().setString(value); - if( dbg > 0 ) log( "Add cookie " + name + "=" + value); - } else { - // we have a bad cookie.... just let it go - } - } - } - - /** - * - * Strips quotes from the start and end of the cookie string - * This conforms to RFC 2109 - * - * @param value a String specifying the cookie - * value (possibly quoted). - * - * @see #setValue - * - */ - private static String stripQuote( String value ) - { - // log("Strip quote from " + value ); - if (((value.startsWith("\"")) && (value.endsWith("\""))) || - ((value.startsWith("'") && (value.endsWith("'"))))) { - try { - return value.substring(1,value.length()-1); - } catch (Exception ex) { - } - } - return value; - } - - - // log - static final int dbg=0; - public void log(String s ) { - if (log.isDebugEnabled()) - log.debug("Cookies: " + s); - } - - /* - public static void main( String args[] ) { - test("foo=bar; a=b"); - test("foo=bar;a=b"); - test("foo=bar;a=b;"); - test("foo=bar;a=b; "); - test("foo=bar;a=b; ;"); - test("foo=;a=b; ;"); - test("foo;a=b; ;"); - // v1 - test("$Version=1; foo=bar;a=b"); - test("$Version=\"1\"; foo='bar'; $Path=/path; $Domain=\"localhost\""); - test("$Version=1;foo=bar;a=b; ; "); - test("$Version=1;foo=;a=b; ; "); - test("$Version=1;foo= ;a=b; ; "); - test("$Version=1;foo;a=b; ; "); - test("$Version=1;foo=\"bar\";a=b; ; "); - test("$Version=1;foo=\"bar\";$Path=/examples;a=b; ; "); - test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b"); - test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com"); - // rfc2965 - test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b"); - - // wrong - test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b"); - } - - public static void test( String s ) { - System.out.println("Processing " + s ); - Cookies cs=new Cookies(null); - cs.processCookieHeader( s.getBytes(), 0, s.length()); - for( int i=0; i< cs.getCookieCount() ; i++ ) { - System.out.println("Cookie: " + cs.getCookie( i )); - } - - } - */ - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.StringTokenizer; + +import org.apache.tomcat.util.buf.ByteChunk; +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * A collection of cookies - reusable and tuned for server side performance. + * Based on RFC2965 ( and 2109 ) + * + * This class is not synchronized. + * + * @author Costin Manolache + * @author kevin seguin + */ +public final class Cookies { // extends MultiMap { + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(Cookies.class ); + + // expected average number of cookies per request + public static final int INITIAL_SIZE=4; + ServerCookie scookies[]=new ServerCookie[INITIAL_SIZE]; + int cookieCount=0; + boolean unprocessed=true; + + MimeHeaders headers; + + /** + * Construct a new cookie collection, that will extract + * the information from headers. + * + * @param headers Cookies are lazy-evaluated and will extract the + * information from the provided headers. + */ + public Cookies(MimeHeaders headers) { + this.headers=headers; + } + + /** + * Construct a new uninitialized cookie collection. + * Use {@link #setHeaders} to initialize. + */ + // [seguin] added so that an empty Cookies object could be + // created, have headers set, then recycled. + public Cookies() { + } + + /** + * Set the headers from which cookies will be pulled. + * This has the side effect of recycling the object. + * + * @param headers Cookies are lazy-evaluated and will extract the + * information from the provided headers. + */ + // [seguin] added so that an empty Cookies object could be + // created, have headers set, then recycled. + public void setHeaders(MimeHeaders headers) { + recycle(); + this.headers=headers; + } + + /** + * Recycle. + */ + public void recycle() { + for( int i=0; i< cookieCount; i++ ) { + if( scookies[i]!=null ) + scookies[i].recycle(); + } + cookieCount=0; + unprocessed=true; + } + + /** + * EXPENSIVE!!! only for debugging. + */ + public String toString() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println("=== Cookies ==="); + int count = getCookieCount(); + for (int i = 0; i < count; ++i) { + pw.println(getCookie(i).toString()); + } + return sw.toString(); + } + + // -------------------- Indexed access -------------------- + + public ServerCookie getCookie( int idx ) { + if( unprocessed ) { + getCookieCount(); // will also update the cookies + } + return scookies[idx]; + } + + public int getCookieCount() { + if( unprocessed ) { + unprocessed=false; + processCookies(headers); + } + return cookieCount; + } + + // -------------------- Adding cookies -------------------- + + /** Register a new, unitialized cookie. Cookies are recycled, and + * most of the time an existing ServerCookie object is returned. + * The caller can set the name/value and attributes for the cookie + */ + public ServerCookie addCookie() { + if( cookieCount >= scookies.length ) { + ServerCookie scookiesTmp[]=new ServerCookie[2*cookieCount]; + System.arraycopy( scookies, 0, scookiesTmp, 0, cookieCount); + scookies=scookiesTmp; + } + + ServerCookie c = scookies[cookieCount]; + if( c==null ) { + c= new ServerCookie(); + scookies[cookieCount]=c; + } + cookieCount++; + return c; + } + + + // code from CookieTools + + /** Add all Cookie found in the headers of a request. + */ + public void processCookies( MimeHeaders headers ) { + if( headers==null ) + return;// nothing to process + // process each "cookie" header + int pos=0; + while( pos>=0 ) { + // Cookie2: version ? not needed + pos=headers.findHeader( "Cookie", pos ); + // no more cookie headers headers + if( pos<0 ) break; + + MessageBytes cookieValue=headers.getValue( pos ); + if( cookieValue==null || cookieValue.isNull() ) { + pos++; + continue; + } + + // Uncomment to test the new parsing code + if( cookieValue.getType() == MessageBytes.T_BYTES ) { + if( dbg>0 ) log( "Parsing b[]: " + cookieValue.toString()); + ByteChunk bc=cookieValue.getByteChunk(); + processCookieHeader( bc.getBytes(), + bc.getOffset(), + bc.getLength()); + } else { + if( dbg>0 ) log( "Parsing S: " + cookieValue.toString()); + processCookieHeader( cookieValue.toString() ); + } + pos++;// search from the next position + } + } + + /** Process a byte[] header - allowing fast processing of the + * raw data + */ + void processCookieHeader( byte bytes[], int off, int len ) + { + if( len<=0 || bytes==null ) return; + int end=off+len; + int pos=off; + + int version=0; //sticky + ServerCookie sc=null; + + + while( pos=end ) + return; // only spaces + int startName=pos; + if( dbg>0 ) log( "SN: " + pos ); + + // Version should be the first token + boolean isSpecial=false; + if(bytes[pos]=='$') { pos++; isSpecial=true; } + + pos= findDelim1( bytes, startName, end); // " =;," + int endName=pos; + // current = "=" or " " or DELIM + pos= skipSpaces( bytes, endName, end ); + if( dbg>0 ) log( "DELIM: " + endName + " " + (char)bytes[pos]); + + if(pos >= end ) { + // it's a name-only cookie ( valid in RFC2109 ) + if( ! isSpecial ) { + sc=addCookie(); + sc.getName().setBytes( bytes, startName, + endName-startName ); + sc.getValue().setString(""); + sc.setVersion( version ); + if( dbg>0 ) log( "Name only, end: " + startName + " " + + endName); + } + return; + } + + cc=bytes[pos]; + pos++; + if( cc==';' || cc==',' || pos>=end ) { + if( ! isSpecial && startName!= endName ) { + sc=addCookie(); + sc.getName().setBytes( bytes, startName, + endName-startName ); + sc.getValue().setString(""); + sc.setVersion( version ); + if( dbg>0 ) log( "Name only: " + startName + " " + endName); + } + continue; + } + + // we should have "=" ( tested all other alternatives ) + int startValue=skipSpaces( bytes, pos, end); + int endValue=startValue; + + cc=bytes[pos]; + if( cc== '\'' || cc=='"' ) { + startValue++; + endValue=indexOf( bytes, startValue, end, cc ); + pos=endValue+1; // to skip to next cookie + } else { + endValue=findDelim2( bytes, startValue, end ); + pos=endValue+1; + } + + // if not $Version, etc + if( ! isSpecial ) { + sc=addCookie(); + sc.getName().setBytes( bytes, startName, endName-startName ); + sc.getValue().setBytes( bytes, startValue, endValue-startValue); + sc.setVersion( version ); + if( dbg>0 ) { + log( "New: " + sc.getName() + "X=X" + sc.getValue()); + } + continue; + } + + // special - Path, Version, Domain, Port + if( dbg>0 ) log( "Special: " + startName + " " + endName); + // XXX TODO + if( equals( "$Version", bytes, startName, endName ) ) { + if(dbg>0 ) log( "Found version " ); + if( bytes[startValue]=='1' && endValue==startValue+1 ) { + version=1; + if(dbg>0 ) log( "Found version=1" ); + } + continue; + } + if( sc==null ) { + // Path, etc without a previous cookie + continue; + } + if( equals( "$Path", bytes, startName, endName ) ) { + sc.getPath().setBytes( bytes, + startValue, + endValue-startValue ); + } + if( equals( "$Domain", bytes, startName, endName ) ) { + sc.getDomain().setBytes( bytes, + startValue, + endValue-startValue ); + } + if( equals( "$Port", bytes, startName, endName ) ) { + // sc.getPort().setBytes( bytes, + // startValue, + // endValue-startValue ); + } + } + } + + // -------------------- Utils -------------------- + public static int skipSpaces( byte bytes[], int off, int end ) { + while( off < end ) { + byte b=bytes[off]; + if( b!= ' ' ) return off; + off ++; + } + return off; + } + + public static int findDelim1( byte bytes[], int off, int end ) + { + while( off < end ) { + byte b=bytes[off]; + if( b==' ' || b=='=' || b==';' || b==',' ) + return off; + off++; + } + return off; + } + + public static int findDelim2( byte bytes[], int off, int end ) + { + while( off < end ) { + byte b=bytes[off]; + if( b==';' || b==',' ) + return off; + off++; + } + return off; + } + + public static int indexOf( byte bytes[], int off, int end, byte qq ) + { + while( off < end ) { + byte b=bytes[off]; + if( b==qq ) + return off; + off++; + } + return off; + } + + public static int indexOf( byte bytes[], int off, int end, char qq ) + { + while( off < end ) { + byte b=bytes[off]; + if( b==qq ) + return off; + off++; + } + return off; + } + + // XXX will be refactored soon! + public static boolean equals( String s, byte b[], int start, int end) { + int blen = end-start; + if (b == null || blen != s.length()) { + return false; + } + int boff = start; + for (int i = 0; i < blen; i++) { + if (b[boff++] != s.charAt(i)) { + return false; + } + } + return true; + } + + + // --------------------------------------------------------- + // -------------------- DEPRECATED, OLD -------------------- + + private void processCookieHeader( String cookieString ) + { + if( dbg>0 ) log( "Parsing cookie header " + cookieString ); + // normal cookie, with a string value. + // This is the original code, un-optimized - it shouldn't + // happen in normal case + + StringTokenizer tok = new StringTokenizer(cookieString, + ";", false); + while (tok.hasMoreTokens()) { + String token = tok.nextToken(); + int i = token.indexOf("="); + if (i > -1) { + + // XXX + // the trims here are a *hack* -- this should + // be more properly fixed to be spec compliant + + String name = token.substring(0, i).trim(); + String value = token.substring(i+1, token.length()).trim(); + // RFC 2109 and bug + value=stripQuote( value ); + ServerCookie cookie = addCookie(); + + cookie.getName().setString(name); + cookie.getValue().setString(value); + if( dbg > 0 ) log( "Add cookie " + name + "=" + value); + } else { + // we have a bad cookie.... just let it go + } + } + } + + /** + * + * Strips quotes from the start and end of the cookie string + * This conforms to RFC 2109 + * + * @param value a String specifying the cookie + * value (possibly quoted). + * + * @see #setValue + * + */ + private static String stripQuote( String value ) + { + // log("Strip quote from " + value ); + if (((value.startsWith("\"")) && (value.endsWith("\""))) || + ((value.startsWith("'") && (value.endsWith("'"))))) { + try { + return value.substring(1,value.length()-1); + } catch (Exception ex) { + } + } + return value; + } + + + // log + static final int dbg=0; + public void log(String s ) { + if (log.isDebugEnabled()) + log.debug("Cookies: " + s); + } + + /* + public static void main( String args[] ) { + test("foo=bar; a=b"); + test("foo=bar;a=b"); + test("foo=bar;a=b;"); + test("foo=bar;a=b; "); + test("foo=bar;a=b; ;"); + test("foo=;a=b; ;"); + test("foo;a=b; ;"); + // v1 + test("$Version=1; foo=bar;a=b"); + test("$Version=\"1\"; foo='bar'; $Path=/path; $Domain=\"localhost\""); + test("$Version=1;foo=bar;a=b; ; "); + test("$Version=1;foo=;a=b; ; "); + test("$Version=1;foo= ;a=b; ; "); + test("$Version=1;foo;a=b; ; "); + test("$Version=1;foo=\"bar\";a=b; ; "); + test("$Version=1;foo=\"bar\";$Path=/examples;a=b; ; "); + test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b"); + test("$Version=1;foo=\"bar\";$Domain=apache.org;a=b;$Domain=yahoo.com"); + // rfc2965 + test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b"); + + // wrong + test("$Version=1;foo=\"bar\";$Domain=apache.org;$Port=8080;a=b"); + } + + public static void test( String s ) { + System.out.println("Processing " + s ); + Cookies cs=new Cookies(null); + cs.processCookieHeader( s.getBytes(), 0, s.length()); + for( int i=0; i< cs.getCookieCount() ; i++ ) { + System.out.println("Cookie: " + cs.getCookie( i )); + } + + } + */ + +} diff --git a/java/org/apache/tomcat/util/http/FastHttpDateFormat.java b/java/org/apache/tomcat/util/http/FastHttpDateFormat.java index 1772024f0..38bfe6f7d 100644 --- a/java/org/apache/tomcat/util/http/FastHttpDateFormat.java +++ b/java/org/apache/tomcat/util/http/FastHttpDateFormat.java @@ -1,223 +1,223 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.TimeZone; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; - -/** - * Utility class to generate HTTP dates. - * - * @author Remy Maucherat - */ -public final class FastHttpDateFormat { - - - // -------------------------------------------------------------- Variables - - - /** - * HTTP date format. - */ - protected static final SimpleDateFormat format = - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); - - - /** - * The set of SimpleDateFormat formats to use in getDateHeader(). - */ - protected static final SimpleDateFormat formats[] = { - new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), - new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) - }; - - - protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); - - - /** - * GMT timezone - all HTTP dates are on GMT - */ - static { - - format.setTimeZone(gmtZone); - - formats[0].setTimeZone(gmtZone); - formats[1].setTimeZone(gmtZone); - formats[2].setTimeZone(gmtZone); - - } - - - /** - * Instant on which the currentDate object was generated. - */ - protected static long currentDateGenerated = 0L; - - - /** - * Current formatted date. - */ - protected static String currentDate = null; - - - /** - * Formatter cache. - */ - protected static final HashMap formatCache = new HashMap(); - - - /** - * Parser cache. - */ - protected static final HashMap parseCache = new HashMap(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Get the current date in HTTP format. - */ - public static final String getCurrentDate() { - - long now = System.currentTimeMillis(); - if ((now - currentDateGenerated) > 1000) { - synchronized (format) { - if ((now - currentDateGenerated) > 1000) { - currentDateGenerated = now; - currentDate = format.format(new Date(now)); - } - } - } - return currentDate; - - } - - - /** - * Get the HTTP format of the specified date. - */ - public static final String formatDate - (long value, DateFormat threadLocalformat) { - - String cachedDate = null; - Long longValue = new Long(value); - try { - cachedDate = (String) formatCache.get(longValue); - } catch (Exception e) { - } - if (cachedDate != null) - return cachedDate; - - String newDate = null; - Date dateValue = new Date(value); - if (threadLocalformat != null) { - newDate = threadLocalformat.format(dateValue); - synchronized (formatCache) { - updateCache(formatCache, longValue, newDate); - } - } else { - synchronized (formatCache) { - synchronized (format) { - newDate = format.format(dateValue); - } - updateCache(formatCache, longValue, newDate); - } - } - return newDate; - - } - - - /** - * Try to parse the given date as a HTTP date. - */ - public static final long parseDate(String value, - DateFormat[] threadLocalformats) { - - Long cachedDate = null; - try { - cachedDate = (Long) parseCache.get(value); - } catch (Exception e) { - } - if (cachedDate != null) - return cachedDate.longValue(); - - Long date = null; - if (threadLocalformats != null) { - date = internalParseDate(value, threadLocalformats); - synchronized (parseCache) { - updateCache(parseCache, value, date); - } - } else { - synchronized (parseCache) { - date = internalParseDate(value, formats); - updateCache(parseCache, value, date); - } - } - if (date == null) { - return (-1L); - } else { - return date.longValue(); - } - - } - - - /** - * Parse date with given formatters. - */ - private static final Long internalParseDate - (String value, DateFormat[] formats) { - Date date = null; - for (int i = 0; (date == null) && (i < formats.length); i++) { - try { - date = formats[i].parse(value); - } catch (ParseException e) { - ; - } - } - if (date == null) { - return null; - } - return new Long(date.getTime()); - } - - - /** - * Update cache. - */ - private static final void updateCache(HashMap cache, Object key, - Object value) { - if (value == null) { - return; - } - if (cache.size() > 1000) { - cache.clear(); - } - cache.put(key, value); - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.TimeZone; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; + +/** + * Utility class to generate HTTP dates. + * + * @author Remy Maucherat + */ +public final class FastHttpDateFormat { + + + // -------------------------------------------------------------- Variables + + + /** + * HTTP date format. + */ + protected static final SimpleDateFormat format = + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US); + + + /** + * The set of SimpleDateFormat formats to use in getDateHeader(). + */ + protected static final SimpleDateFormat formats[] = { + new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US), + new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) + }; + + + protected final static TimeZone gmtZone = TimeZone.getTimeZone("GMT"); + + + /** + * GMT timezone - all HTTP dates are on GMT + */ + static { + + format.setTimeZone(gmtZone); + + formats[0].setTimeZone(gmtZone); + formats[1].setTimeZone(gmtZone); + formats[2].setTimeZone(gmtZone); + + } + + + /** + * Instant on which the currentDate object was generated. + */ + protected static long currentDateGenerated = 0L; + + + /** + * Current formatted date. + */ + protected static String currentDate = null; + + + /** + * Formatter cache. + */ + protected static final HashMap formatCache = new HashMap(); + + + /** + * Parser cache. + */ + protected static final HashMap parseCache = new HashMap(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Get the current date in HTTP format. + */ + public static final String getCurrentDate() { + + long now = System.currentTimeMillis(); + if ((now - currentDateGenerated) > 1000) { + synchronized (format) { + if ((now - currentDateGenerated) > 1000) { + currentDateGenerated = now; + currentDate = format.format(new Date(now)); + } + } + } + return currentDate; + + } + + + /** + * Get the HTTP format of the specified date. + */ + public static final String formatDate + (long value, DateFormat threadLocalformat) { + + String cachedDate = null; + Long longValue = new Long(value); + try { + cachedDate = (String) formatCache.get(longValue); + } catch (Exception e) { + } + if (cachedDate != null) + return cachedDate; + + String newDate = null; + Date dateValue = new Date(value); + if (threadLocalformat != null) { + newDate = threadLocalformat.format(dateValue); + synchronized (formatCache) { + updateCache(formatCache, longValue, newDate); + } + } else { + synchronized (formatCache) { + synchronized (format) { + newDate = format.format(dateValue); + } + updateCache(formatCache, longValue, newDate); + } + } + return newDate; + + } + + + /** + * Try to parse the given date as a HTTP date. + */ + public static final long parseDate(String value, + DateFormat[] threadLocalformats) { + + Long cachedDate = null; + try { + cachedDate = (Long) parseCache.get(value); + } catch (Exception e) { + } + if (cachedDate != null) + return cachedDate.longValue(); + + Long date = null; + if (threadLocalformats != null) { + date = internalParseDate(value, threadLocalformats); + synchronized (parseCache) { + updateCache(parseCache, value, date); + } + } else { + synchronized (parseCache) { + date = internalParseDate(value, formats); + updateCache(parseCache, value, date); + } + } + if (date == null) { + return (-1L); + } else { + return date.longValue(); + } + + } + + + /** + * Parse date with given formatters. + */ + private static final Long internalParseDate + (String value, DateFormat[] formats) { + Date date = null; + for (int i = 0; (date == null) && (i < formats.length); i++) { + try { + date = formats[i].parse(value); + } catch (ParseException e) { + ; + } + } + if (date == null) { + return null; + } + return new Long(date.getTime()); + } + + + /** + * Update cache. + */ + private static final void updateCache(HashMap cache, Object key, + Object value) { + if (value == null) { + return; + } + if (cache.size() > 1000) { + cache.clear(); + } + cache.put(key, value); + } + + +} diff --git a/java/org/apache/tomcat/util/http/HttpMessages.java b/java/org/apache/tomcat/util/http/HttpMessages.java index 9c8f28817..006a3abc7 100644 --- a/java/org/apache/tomcat/util/http/HttpMessages.java +++ b/java/org/apache/tomcat/util/http/HttpMessages.java @@ -1,106 +1,106 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - -import org.apache.tomcat.util.res.StringManager; - -/** - * Handle (internationalized) HTTP messages. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author Harish Prabandham - * @author costin@eng.sun.com - */ -public class HttpMessages { - // XXX move message resources in this package - protected static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.http.res"); - - static String st_200=null; - static String st_302=null; - static String st_400=null; - static String st_404=null; - - /** Get the status string associated with a status code. - * No I18N - return the messages defined in the HTTP spec. - * ( the user isn't supposed to see them, this is the last - * thing to translate) - * - * Common messages are cached. - * - */ - public static String getMessage( int status ) { - // method from Response. - - // Does HTTP requires/allow international messages or - // are pre-defined? The user doesn't see them most of the time - switch( status ) { - case 200: - if( st_200==null ) st_200=sm.getString( "sc.200"); - return st_200; - case 302: - if( st_302==null ) st_302=sm.getString( "sc.302"); - return st_302; - case 400: - if( st_400==null ) st_400=sm.getString( "sc.400"); - return st_400; - case 404: - if( st_404==null ) st_404=sm.getString( "sc.404"); - return st_404; - } - return sm.getString("sc."+ status); - } - - /** - * Filter the specified message string for characters that are sensitive - * in HTML. This avoids potential attacks caused by including JavaScript - * codes in the request URL that is often reported in error messages. - * - * @param message The message string to be filtered - */ - public static String filter(String message) { - - if (message == null) - return (null); - - char content[] = new char[message.length()]; - message.getChars(0, message.length(), content, 0); - StringBuffer result = new StringBuffer(content.length + 50); - for (int i = 0; i < content.length; i++) { - switch (content[i]) { - case '<': - result.append("<"); - break; - case '>': - result.append(">"); - break; - case '&': - result.append("&"); - break; - case '"': - result.append("""); - break; - default: - result.append(content[i]); - } - } - return (result.toString()); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + +import org.apache.tomcat.util.res.StringManager; + +/** + * Handle (internationalized) HTTP messages. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author Harish Prabandham + * @author costin@eng.sun.com + */ +public class HttpMessages { + // XXX move message resources in this package + protected static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.http.res"); + + static String st_200=null; + static String st_302=null; + static String st_400=null; + static String st_404=null; + + /** Get the status string associated with a status code. + * No I18N - return the messages defined in the HTTP spec. + * ( the user isn't supposed to see them, this is the last + * thing to translate) + * + * Common messages are cached. + * + */ + public static String getMessage( int status ) { + // method from Response. + + // Does HTTP requires/allow international messages or + // are pre-defined? The user doesn't see them most of the time + switch( status ) { + case 200: + if( st_200==null ) st_200=sm.getString( "sc.200"); + return st_200; + case 302: + if( st_302==null ) st_302=sm.getString( "sc.302"); + return st_302; + case 400: + if( st_400==null ) st_400=sm.getString( "sc.400"); + return st_400; + case 404: + if( st_404==null ) st_404=sm.getString( "sc.404"); + return st_404; + } + return sm.getString("sc."+ status); + } + + /** + * Filter the specified message string for characters that are sensitive + * in HTML. This avoids potential attacks caused by including JavaScript + * codes in the request URL that is often reported in error messages. + * + * @param message The message string to be filtered + */ + public static String filter(String message) { + + if (message == null) + return (null); + + char content[] = new char[message.length()]; + message.getChars(0, message.length(), content, 0); + StringBuffer result = new StringBuffer(content.length + 50); + for (int i = 0; i < content.length; i++) { + switch (content[i]) { + case '<': + result.append("<"); + break; + case '>': + result.append(">"); + break; + case '&': + result.append("&"); + break; + case '"': + result.append("""); + break; + default: + result.append(content[i]); + } + } + return (result.toString()); + } + +} diff --git a/java/org/apache/tomcat/util/http/MimeHeaders.java b/java/org/apache/tomcat/util/http/MimeHeaders.java index 5273ca8eb..bb0551b65 100644 --- a/java/org/apache/tomcat/util/http/MimeHeaders.java +++ b/java/org/apache/tomcat/util/http/MimeHeaders.java @@ -1,456 +1,456 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http; - -import java.io.PrintWriter; -import java.io.StringWriter; -import java.util.Enumeration; - -import org.apache.tomcat.util.buf.MessageBytes; - -/* XXX XXX XXX Need a major rewrite !!!! - */ - -/** - * This class is used to contain standard internet message headers, - * used for SMTP (RFC822) and HTTP (RFC2068) messages as well as for - * MIME (RFC 2045) applications such as transferring typed data and - * grouping related items in multipart message bodies. - * - *

        Message headers, as specified in RFC822, include a field name - * and a field body. Order has no semantic significance, and several - * fields with the same name may exist. However, most fields do not - * (and should not) exist more than once in a header. - * - *

        Many kinds of field body must conform to a specified syntax, - * including the standard parenthesized comment syntax. This class - * supports only two simple syntaxes, for dates and integers. - * - *

        When processing headers, care must be taken to handle the case of - * multiple same-name fields correctly. The values of such fields are - * only available as strings. They may be accessed by index (treating - * the header as an array of fields), or by name (returning an array - * of string values). - */ - -/* Headers are first parsed and stored in the order they are - received. This is based on the fact that most servlets will not - directly access all headers, and most headers are single-valued. - ( the alternative - a hash or similar data structure - will add - an overhead that is not needed in most cases ) - - Apache seems to be using a similar method for storing and manipulating - headers. - - Future enhancements: - - hash the headers the first time a header is requested ( i.e. if the - servlet needs direct access to headers). - - scan "common" values ( length, cookies, etc ) during the parse - ( addHeader hook ) - -*/ - - - -/** - * Memory-efficient repository for Mime Headers. When the object is recycled, it - * will keep the allocated headers[] and all the MimeHeaderField - no GC is generated. - * - * For input headers it is possible to use the MessageByte for Fileds - so no GC - * will be generated. - * - * The only garbage is generated when using the String for header names/values - - * this can't be avoided when the servlet calls header methods, but is easy - * to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields, - * and reduce to 0 the memory overhead of tomcat. - * - * TODO: - * XXX one-buffer parsing - for http ( other protocols don't need that ) - * XXX remove unused methods - * XXX External enumerations, with 0 GC. - * XXX use HeaderName ID - * - * - * @author dac@eng.sun.com - * @author James Todd [gonzo@eng.sun.com] - * @author Costin Manolache - * @author kevin seguin - */ -public class MimeHeaders { - /** Initial size - should be == average number of headers per request - * XXX make it configurable ( fine-tuning of web-apps ) - */ - public static final int DEFAULT_HEADER_SIZE=8; - - /** - * The header fields. - */ - private MimeHeaderField[] headers = new - MimeHeaderField[DEFAULT_HEADER_SIZE]; - - /** - * The current number of header fields. - */ - private int count; - - /** - * Creates a new MimeHeaders object using a default buffer size. - */ - public MimeHeaders() { - } - - /** - * Clears all header fields. - */ - // [seguin] added for consistency -- most other objects have recycle(). - public void recycle() { - clear(); - } - - /** - * Clears all header fields. - */ - public void clear() { - for (int i = 0; i < count; i++) { - headers[i].recycle(); - } - count = 0; - } - - /** - * EXPENSIVE!!! only for debugging. - */ - public String toString() { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - pw.println("=== MimeHeaders ==="); - Enumeration e = names(); - while (e.hasMoreElements()) { - String n = (String)e.nextElement(); - pw.println(n + " = " + getHeader(n)); - } - return sw.toString(); - } - - // -------------------- Idx access to headers ---------- - - /** - * Returns the current number of header fields. - */ - public int size() { - return count; - } - - /** - * Returns the Nth header name, or null if there is no such header. - * This may be used to iterate through all header fields. - */ - public MessageBytes getName(int n) { - return n >= 0 && n < count ? headers[n].getName() : null; - } - - /** - * Returns the Nth header value, or null if there is no such header. - * This may be used to iterate through all header fields. - */ - public MessageBytes getValue(int n) { - return n >= 0 && n < count ? headers[n].getValue() : null; - } - - /** Find the index of a header with the given name. - */ - public int findHeader( String name, int starting ) { - // We can use a hash - but it's not clear how much - // benefit you can get - there is an overhead - // and the number of headers is small (4-5 ?) - // Another problem is that we'll pay the overhead - // of constructing the hashtable - - // A custom search tree may be better - for (int i = starting; i < count; i++) { - if (headers[i].getName().equalsIgnoreCase(name)) { - return i; - } - } - return -1; - } - - // -------------------- -------------------- - - /** - * Returns an enumeration of strings representing the header field names. - * Field names may appear multiple times in this enumeration, indicating - * that multiple fields with that name exist in this header. - */ - public Enumeration names() { - return new NamesEnumerator(this); - } - - public Enumeration values(String name) { - return new ValuesEnumerator(this, name); - } - - // -------------------- Adding headers -------------------- - - - /** - * Adds a partially constructed field to the header. This - * field has not had its name or value initialized. - */ - private MimeHeaderField createHeader() { - MimeHeaderField mh; - int len = headers.length; - if (count >= len) { - // expand header list array - MimeHeaderField tmp[] = new MimeHeaderField[count * 2]; - System.arraycopy(headers, 0, tmp, 0, len); - headers = tmp; - } - if ((mh = headers[count]) == null) { - headers[count] = mh = new MimeHeaderField(); - } - count++; - return mh; - } - - /** Create a new named header , return the MessageBytes - container for the new value - */ - public MessageBytes addValue( String name ) { - MimeHeaderField mh = createHeader(); - mh.getName().setString(name); - return mh.getValue(); - } - - /** Create a new named header using un-translated byte[]. - The conversion to chars can be delayed until - encoding is known. - */ - public MessageBytes addValue(byte b[], int startN, int len) - { - MimeHeaderField mhf=createHeader(); - mhf.getName().setBytes(b, startN, len); - return mhf.getValue(); - } - - /** Create a new named header using translated char[]. - */ - public MessageBytes addValue(char c[], int startN, int len) - { - MimeHeaderField mhf=createHeader(); - mhf.getName().setChars(c, startN, len); - return mhf.getValue(); - } - - /** Allow "set" operations - - return a MessageBytes container for the - header value ( existing header or new - if this . - */ - public MessageBytes setValue( String name ) { - for ( int i = 0; i < count; i++ ) { - if(headers[i].getName().equalsIgnoreCase(name)) { - for ( int j=i+1; j < count; j++ ) { - if(headers[j].getName().equalsIgnoreCase(name)) { - removeHeader(j--); - } - } - return headers[i].getValue(); - } - } - MimeHeaderField mh = createHeader(); - mh.getName().setString(name); - return mh.getValue(); - } - - //-------------------- Getting headers -------------------- - /** - * Finds and returns a header field with the given name. If no such - * field exists, null is returned. If more than one such field is - * in the header, an arbitrary one is returned. - */ - public MessageBytes getValue(String name) { - for (int i = 0; i < count; i++) { - if (headers[i].getName().equalsIgnoreCase(name)) { - return headers[i].getValue(); - } - } - return null; - } - - // bad shortcut - it'll convert to string ( too early probably, - // encoding is guessed very late ) - public String getHeader(String name) { - MessageBytes mh = getValue(name); - return mh != null ? mh.toString() : null; - } - - // -------------------- Removing -------------------- - /** - * Removes a header field with the specified name. Does nothing - * if such a field could not be found. - * @param name the name of the header field to be removed - */ - public void removeHeader(String name) { - // XXX - // warning: rather sticky code; heavily tuned - - for (int i = 0; i < count; i++) { - if (headers[i].getName().equalsIgnoreCase(name)) { - removeHeader(i--); - } - } - } - - /** - * reset and swap with last header - * @param idx the index of the header to remove. - */ - private void removeHeader(int idx) { - MimeHeaderField mh = headers[idx]; - - mh.recycle(); - headers[idx] = headers[count - 1]; - headers[count - 1] = mh; - count--; - } - -} - -/** Enumerate the distinct header names. - Each nextElement() is O(n) ( a comparation is - done with all previous elements ). - - This is less frequesnt than add() - - we want to keep add O(1). -*/ -class NamesEnumerator implements Enumeration { - int pos; - int size; - String next; - MimeHeaders headers; - - NamesEnumerator(MimeHeaders headers) { - this.headers=headers; - pos=0; - size = headers.size(); - findNext(); - } - - private void findNext() { - next=null; - for( ; pos< size; pos++ ) { - next=headers.getName( pos ).toString(); - for( int j=0; j Message headers, as specified in RFC822, include a field name + * and a field body. Order has no semantic significance, and several + * fields with the same name may exist. However, most fields do not + * (and should not) exist more than once in a header. + * + *

        Many kinds of field body must conform to a specified syntax, + * including the standard parenthesized comment syntax. This class + * supports only two simple syntaxes, for dates and integers. + * + *

        When processing headers, care must be taken to handle the case of + * multiple same-name fields correctly. The values of such fields are + * only available as strings. They may be accessed by index (treating + * the header as an array of fields), or by name (returning an array + * of string values). + */ + +/* Headers are first parsed and stored in the order they are + received. This is based on the fact that most servlets will not + directly access all headers, and most headers are single-valued. + ( the alternative - a hash or similar data structure - will add + an overhead that is not needed in most cases ) + + Apache seems to be using a similar method for storing and manipulating + headers. + + Future enhancements: + - hash the headers the first time a header is requested ( i.e. if the + servlet needs direct access to headers). + - scan "common" values ( length, cookies, etc ) during the parse + ( addHeader hook ) + +*/ + + + +/** + * Memory-efficient repository for Mime Headers. When the object is recycled, it + * will keep the allocated headers[] and all the MimeHeaderField - no GC is generated. + * + * For input headers it is possible to use the MessageByte for Fileds - so no GC + * will be generated. + * + * The only garbage is generated when using the String for header names/values - + * this can't be avoided when the servlet calls header methods, but is easy + * to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields, + * and reduce to 0 the memory overhead of tomcat. + * + * TODO: + * XXX one-buffer parsing - for http ( other protocols don't need that ) + * XXX remove unused methods + * XXX External enumerations, with 0 GC. + * XXX use HeaderName ID + * + * + * @author dac@eng.sun.com + * @author James Todd [gonzo@eng.sun.com] + * @author Costin Manolache + * @author kevin seguin + */ +public class MimeHeaders { + /** Initial size - should be == average number of headers per request + * XXX make it configurable ( fine-tuning of web-apps ) + */ + public static final int DEFAULT_HEADER_SIZE=8; + + /** + * The header fields. + */ + private MimeHeaderField[] headers = new + MimeHeaderField[DEFAULT_HEADER_SIZE]; + + /** + * The current number of header fields. + */ + private int count; + + /** + * Creates a new MimeHeaders object using a default buffer size. + */ + public MimeHeaders() { + } + + /** + * Clears all header fields. + */ + // [seguin] added for consistency -- most other objects have recycle(). + public void recycle() { + clear(); + } + + /** + * Clears all header fields. + */ + public void clear() { + for (int i = 0; i < count; i++) { + headers[i].recycle(); + } + count = 0; + } + + /** + * EXPENSIVE!!! only for debugging. + */ + public String toString() { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + pw.println("=== MimeHeaders ==="); + Enumeration e = names(); + while (e.hasMoreElements()) { + String n = (String)e.nextElement(); + pw.println(n + " = " + getHeader(n)); + } + return sw.toString(); + } + + // -------------------- Idx access to headers ---------- + + /** + * Returns the current number of header fields. + */ + public int size() { + return count; + } + + /** + * Returns the Nth header name, or null if there is no such header. + * This may be used to iterate through all header fields. + */ + public MessageBytes getName(int n) { + return n >= 0 && n < count ? headers[n].getName() : null; + } + + /** + * Returns the Nth header value, or null if there is no such header. + * This may be used to iterate through all header fields. + */ + public MessageBytes getValue(int n) { + return n >= 0 && n < count ? headers[n].getValue() : null; + } + + /** Find the index of a header with the given name. + */ + public int findHeader( String name, int starting ) { + // We can use a hash - but it's not clear how much + // benefit you can get - there is an overhead + // and the number of headers is small (4-5 ?) + // Another problem is that we'll pay the overhead + // of constructing the hashtable + + // A custom search tree may be better + for (int i = starting; i < count; i++) { + if (headers[i].getName().equalsIgnoreCase(name)) { + return i; + } + } + return -1; + } + + // -------------------- -------------------- + + /** + * Returns an enumeration of strings representing the header field names. + * Field names may appear multiple times in this enumeration, indicating + * that multiple fields with that name exist in this header. + */ + public Enumeration names() { + return new NamesEnumerator(this); + } + + public Enumeration values(String name) { + return new ValuesEnumerator(this, name); + } + + // -------------------- Adding headers -------------------- + + + /** + * Adds a partially constructed field to the header. This + * field has not had its name or value initialized. + */ + private MimeHeaderField createHeader() { + MimeHeaderField mh; + int len = headers.length; + if (count >= len) { + // expand header list array + MimeHeaderField tmp[] = new MimeHeaderField[count * 2]; + System.arraycopy(headers, 0, tmp, 0, len); + headers = tmp; + } + if ((mh = headers[count]) == null) { + headers[count] = mh = new MimeHeaderField(); + } + count++; + return mh; + } + + /** Create a new named header , return the MessageBytes + container for the new value + */ + public MessageBytes addValue( String name ) { + MimeHeaderField mh = createHeader(); + mh.getName().setString(name); + return mh.getValue(); + } + + /** Create a new named header using un-translated byte[]. + The conversion to chars can be delayed until + encoding is known. + */ + public MessageBytes addValue(byte b[], int startN, int len) + { + MimeHeaderField mhf=createHeader(); + mhf.getName().setBytes(b, startN, len); + return mhf.getValue(); + } + + /** Create a new named header using translated char[]. + */ + public MessageBytes addValue(char c[], int startN, int len) + { + MimeHeaderField mhf=createHeader(); + mhf.getName().setChars(c, startN, len); + return mhf.getValue(); + } + + /** Allow "set" operations - + return a MessageBytes container for the + header value ( existing header or new + if this . + */ + public MessageBytes setValue( String name ) { + for ( int i = 0; i < count; i++ ) { + if(headers[i].getName().equalsIgnoreCase(name)) { + for ( int j=i+1; j < count; j++ ) { + if(headers[j].getName().equalsIgnoreCase(name)) { + removeHeader(j--); + } + } + return headers[i].getValue(); + } + } + MimeHeaderField mh = createHeader(); + mh.getName().setString(name); + return mh.getValue(); + } + + //-------------------- Getting headers -------------------- + /** + * Finds and returns a header field with the given name. If no such + * field exists, null is returned. If more than one such field is + * in the header, an arbitrary one is returned. + */ + public MessageBytes getValue(String name) { + for (int i = 0; i < count; i++) { + if (headers[i].getName().equalsIgnoreCase(name)) { + return headers[i].getValue(); + } + } + return null; + } + + // bad shortcut - it'll convert to string ( too early probably, + // encoding is guessed very late ) + public String getHeader(String name) { + MessageBytes mh = getValue(name); + return mh != null ? mh.toString() : null; + } + + // -------------------- Removing -------------------- + /** + * Removes a header field with the specified name. Does nothing + * if such a field could not be found. + * @param name the name of the header field to be removed + */ + public void removeHeader(String name) { + // XXX + // warning: rather sticky code; heavily tuned + + for (int i = 0; i < count; i++) { + if (headers[i].getName().equalsIgnoreCase(name)) { + removeHeader(i--); + } + } + } + + /** + * reset and swap with last header + * @param idx the index of the header to remove. + */ + private void removeHeader(int idx) { + MimeHeaderField mh = headers[idx]; + + mh.recycle(); + headers[idx] = headers[count - 1]; + headers[count - 1] = mh; + count--; + } + +} + +/** Enumerate the distinct header names. + Each nextElement() is O(n) ( a comparation is + done with all previous elements ). + + This is less frequesnt than add() - + we want to keep add O(1). +*/ +class NamesEnumerator implements Enumeration { + int pos; + int size; + String next; + MimeHeaders headers; + + NamesEnumerator(MimeHeaders headers) { + this.headers=headers; + pos=0; + size = headers.size(); + findNext(); + } + + private void findNext() { + next=null; + for( ; pos< size; pos++ ) { + next=headers.getName( pos ).toString(); + for( int j=0; jString[] ) - // for the beginning. When we are sure all accesses happen through - // this class - we can switch to MultiMap - private Hashtable paramHashStringArray=new Hashtable(); - private boolean didQueryParameters=false; - private boolean didMerge=false; - - MessageBytes queryMB; - MimeHeaders headers; - - UDecoder urlDec; - MessageBytes decodedQuery=MessageBytes.newInstance(); - - public static final int INITIAL_SIZE=4; - - // Garbage-less parameter merging. - // In a sub-request with parameters, the new parameters - // will be stored in child. When a getParameter happens, - // the 2 are merged togheter. The child will be altered - // to contain the merged values - the parent is allways the - // original request. - private Parameters child=null; - private Parameters parent=null; - private Parameters currentChild=null; - - String encoding=null; - String queryStringEncoding=null; - - /** - * - */ - public Parameters() { - super( INITIAL_SIZE ); - } - - public void setQuery( MessageBytes queryMB ) { - this.queryMB=queryMB; - } - - public void setHeaders( MimeHeaders headers ) { - this.headers=headers; - } - - public void setEncoding( String s ) { - encoding=s; - if(debug>0) log( "Set encoding to " + s ); - } - - public void setQueryStringEncoding( String s ) { - queryStringEncoding=s; - if(debug>0) log( "Set query string encoding to " + s ); - } - - public void recycle() { - super.recycle(); - paramHashStringArray.clear(); - didQueryParameters=false; - currentChild=null; - didMerge=false; - encoding=null; - decodedQuery.recycle(); - } - - // -------------------- Sub-request support -------------------- - - public Parameters getCurrentSet() { - if( currentChild==null ) - return this; - return currentChild; - } - - /** Create ( or reuse ) a child that will be used during a sub-request. - All future changes ( setting query string, adding parameters ) - will affect the child ( the parent request is never changed ). - Both setters and getters will return the data from the deepest - child, merged with data from parents. - */ - public void push() { - // We maintain a linked list, that will grow to the size of the - // longest include chain. - // The list has 2 points of interest: - // - request.parameters() is the original request and head, - // - request.parameters().currentChild() is the current set. - // The ->child and parent<- links are preserved ( currentChild is not - // the last in the list ) - - // create a new element in the linked list - // note that we reuse the child, if any - pop will not - // set child to null ! - if( currentChild==null ) { - currentChild=new Parameters(); - currentChild.setURLDecoder( urlDec ); - currentChild.parent=this; - return; - } - if( currentChild.child==null ) { - currentChild.child=new Parameters(); - currentChild.setURLDecoder( urlDec ); - currentChild.child.parent=currentChild; - } // it is not null if this object already had a child - // i.e. a deeper include() ( we keep it ) - - // the head will be the new element. - currentChild=currentChild.child; - currentChild.setEncoding( encoding ); - } - - /** Discard the last child. This happens when we return from a - sub-request and the parameters are locally modified. - */ - public void pop() { - if( currentChild==null ) { - throw new RuntimeException( "Attempt to pop without a push" ); - } - currentChild.recycle(); - currentChild=currentChild.parent; - // don't remove the top. - } - - // -------------------- Data access -------------------- - // Access to the current name/values, no side effect ( processing ). - // You must explicitely call handleQueryParameters and the post methods. - - // This is the original data representation ( hash of String->String[]) - - public void addParameterValues( String key, String[] newValues) { - if ( key==null ) return; - String values[]; - if (paramHashStringArray.containsKey(key)) { - String oldValues[] = (String[])paramHashStringArray.get(key); - values = new String[oldValues.length + newValues.length]; - for (int i = 0; i < oldValues.length; i++) { - values[i] = oldValues[i]; - } - for (int i = 0; i < newValues.length; i++) { - values[i+ oldValues.length] = newValues[i]; - } - } else { - values = newValues; - } - - paramHashStringArray.put(key, values); - } - - public String[] getParameterValues(String name) { - handleQueryParameters(); - // sub-request - if( currentChild!=null ) { - currentChild.merge(); - return (String[])currentChild.paramHashStringArray.get(name); - } - - // no "facade" - String values[]=(String[])paramHashStringArray.get(name); - return values; - } - - public Enumeration getParameterNames() { - handleQueryParameters(); - // Slow - the original code - if( currentChild!=null ) { - currentChild.merge(); - return currentChild.paramHashStringArray.keys(); - } - - // merge in child - return paramHashStringArray.keys(); - } - - /** Combine the parameters from parent with our local ones - */ - private void merge() { - // recursive - if( debug > 0 ) { - log("Before merging " + this + " " + parent + " " + didMerge ); - log( paramsAsString()); - } - // Local parameters first - they take precedence as in spec. - handleQueryParameters(); - - // we already merged with the parent - if( didMerge ) return; - - // we are the top level - if( parent==null ) return; - - // Add the parent props to the child ( lower precedence ) - parent.merge(); - Hashtable parentProps=parent.paramHashStringArray; - merge2( paramHashStringArray , parentProps); - didMerge=true; - if(debug > 0 ) - log("After " + paramsAsString()); - } - - - // Shortcut. - public String getParameter(String name ) { - String[] values = getParameterValues(name); - if (values != null) { - if( values.length==0 ) return ""; - return values[0]; - } else { - return null; - } - } - // -------------------- Processing -------------------- - /** Process the query string into parameters - */ - public void handleQueryParameters() { - if( didQueryParameters ) return; - - didQueryParameters=true; - - if( queryMB==null || queryMB.isNull() ) - return; - - if( debug > 0 ) - log( "Decoding query " + decodedQuery + " " + queryStringEncoding); - - try { - decodedQuery.duplicate( queryMB ); - } catch (IOException e) { - // Can't happen, as decodedQuery can't overflow - e.printStackTrace(); - } - processParameters( decodedQuery, queryStringEncoding ); - } - - // -------------------- - - /** Combine 2 hashtables into a new one. - * ( two will be added to one ). - * Used to combine child parameters ( RequestDispatcher's query ) - * with parent parameters ( original query or parent dispatcher ) - */ - private static void merge2(Hashtable one, Hashtable two ) { - Enumeration e = two.keys(); - - while (e.hasMoreElements()) { - String name = (String) e.nextElement(); - String[] oneValue = (String[]) one.get(name); - String[] twoValue = (String[]) two.get(name); - String[] combinedValue; - - if (twoValue == null) { - continue; - } else { - if( oneValue==null ) { - combinedValue = new String[twoValue.length]; - System.arraycopy(twoValue, 0, combinedValue, - 0, twoValue.length); - } else { - combinedValue = new String[oneValue.length + - twoValue.length]; - System.arraycopy(oneValue, 0, combinedValue, 0, - oneValue.length); - System.arraycopy(twoValue, 0, combinedValue, - oneValue.length, twoValue.length); - } - one.put(name, combinedValue); - } - } - } - - // incredibly inefficient data representation for parameters, - // until we test the new one - private void addParam( String key, String value ) { - if( key==null ) return; - String values[]; - if (paramHashStringArray.containsKey(key)) { - String oldValues[] = (String[])paramHashStringArray. - get(key); - values = new String[oldValues.length + 1]; - for (int i = 0; i < oldValues.length; i++) { - values[i] = oldValues[i]; - } - values[oldValues.length] = value; - } else { - values = new String[1]; - values[0] = value; - } - - - paramHashStringArray.put(key, values); - } - - public void setURLDecoder( UDecoder u ) { - urlDec=u; - } - - // -------------------- Parameter parsing -------------------- - - // This code is not used right now - it's the optimized version - // of the above. - - // we are called from a single thread - we can do it the hard way - // if needed - ByteChunk tmpName=new ByteChunk(); - ByteChunk tmpValue=new ByteChunk(); - CharChunk tmpNameC=new CharChunk(1024); - CharChunk tmpValueC=new CharChunk(1024); - - public void processParameters( byte bytes[], int start, int len ) { - processParameters(bytes, start, len, encoding); - } - - public void processParameters( byte bytes[], int start, int len, - String enc ) { - int end=start+len; - int pos=start; - - if( debug>0 ) - log( "Bytes: " + new String( bytes, start, len )); - - do { - boolean noEq=false; - int valStart=-1; - int valEnd=-1; - - int nameStart=pos; - int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '=' ); - // Workaround for a&b&c encoding - int nameEnd2=ByteChunk.indexOf(bytes, nameStart, end, '&' ); - if( (nameEnd2!=-1 ) && - ( nameEnd==-1 || nameEnd > nameEnd2) ) { - nameEnd=nameEnd2; - noEq=true; - valStart=nameEnd; - valEnd=nameEnd; - if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(bytes, nameStart, nameEnd-nameStart) ); - } - if( nameEnd== -1 ) - nameEnd=end; - - if( ! noEq ) { - valStart= (nameEnd < end) ? nameEnd+1 : end; - valEnd=ByteChunk.indexOf(bytes, valStart, end, '&'); - if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; - } - - pos=valEnd+1; - - if( nameEnd<=nameStart ) { - continue; - // invalid chunk - it's better to ignore - // XXX log it ? - } - tmpName.setBytes( bytes, nameStart, nameEnd-nameStart ); - tmpValue.setBytes( bytes, valStart, valEnd-valStart ); - - try { - addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) ); - } catch (IOException e) { - // Exception during character decoding: skip parameter - } - - tmpName.recycle(); - tmpValue.recycle(); - - } while( pos0 ) - log( "Chars: " + new String( chars, start, len )); - do { - boolean noEq=false; - int nameStart=pos; - int valStart=-1; - int valEnd=-1; - - int nameEnd=CharChunk.indexOf(chars, nameStart, end, '=' ); - int nameEnd2=CharChunk.indexOf(chars, nameStart, end, '&' ); - if( (nameEnd2!=-1 ) && - ( nameEnd==-1 || nameEnd > nameEnd2) ) { - nameEnd=nameEnd2; - noEq=true; - valStart=nameEnd; - valEnd=nameEnd; - if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(chars, nameStart, nameEnd-nameStart) ); - } - if( nameEnd== -1 ) nameEnd=end; - - if( ! noEq ) { - valStart= (nameEnd < end) ? nameEnd+1 : end; - valEnd=CharChunk.indexOf(chars, valStart, end, '&'); - if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; - } - - pos=valEnd+1; - - if( nameEnd<=nameStart ) { - continue; - // invalid chunk - no name, it's better to ignore - // XXX log it ? - } - - try { - tmpNameC.append( chars, nameStart, nameEnd-nameStart ); - tmpValueC.append( chars, valStart, valEnd-valStart ); - - if( debug > 0 ) - log( tmpNameC + "= " + tmpValueC); - - if( urlDec==null ) { - urlDec=new UDecoder(); - } - - urlDec.convert( tmpNameC ); - urlDec.convert( tmpValueC ); - - if( debug > 0 ) - log( tmpNameC + "= " + tmpValueC); - - addParam( tmpNameC.toString(), tmpValueC.toString() ); - } catch( IOException ex ) { - ex.printStackTrace(); - } - - tmpNameC.recycle(); - tmpValueC.recycle(); - - } while( pos 0) - log("String: " + str ); - - do { - boolean noEq=false; - int valStart=-1; - int valEnd=-1; - - int nameStart=pos; - int nameEnd=str.indexOf('=', nameStart ); - int nameEnd2=str.indexOf('&', nameStart ); - if( nameEnd2== -1 ) nameEnd2=end; - if( (nameEnd2!=-1 ) && - ( nameEnd==-1 || nameEnd > nameEnd2) ) { - nameEnd=nameEnd2; - noEq=true; - valStart=nameEnd; - valEnd=nameEnd; - if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStart, nameEnd) ); - } - - if( nameEnd== -1 ) nameEnd=end; - - if( ! noEq ) { - valStart=nameEnd+1; - valEnd=str.indexOf('&', valStart); - if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; - } - - pos=valEnd+1; - - if( nameEnd<=nameStart ) { - continue; - } - if( debug>0) - log( "XXX " + nameStart + " " + nameEnd + " " - + valStart + " " + valEnd ); - - try { - tmpNameC.append(str, nameStart, nameEnd-nameStart ); - tmpValueC.append(str, valStart, valEnd-valStart ); - - if( debug > 0 ) - log( tmpNameC + "= " + tmpValueC); - - if( urlDec==null ) { - urlDec=new UDecoder(); - } - - urlDec.convert( tmpNameC ); - urlDec.convert( tmpValueC ); - - if( debug > 0 ) - log( tmpNameC + "= " + tmpValueC); - - addParam( tmpNameC.toString(), tmpValueC.toString() ); - } catch( IOException ex ) { - ex.printStackTrace(); - } - - tmpNameC.recycle(); - tmpValueC.recycle(); - - } while( posString[] ) + // for the beginning. When we are sure all accesses happen through + // this class - we can switch to MultiMap + private Hashtable paramHashStringArray=new Hashtable(); + private boolean didQueryParameters=false; + private boolean didMerge=false; + + MessageBytes queryMB; + MimeHeaders headers; + + UDecoder urlDec; + MessageBytes decodedQuery=MessageBytes.newInstance(); + + public static final int INITIAL_SIZE=4; + + // Garbage-less parameter merging. + // In a sub-request with parameters, the new parameters + // will be stored in child. When a getParameter happens, + // the 2 are merged togheter. The child will be altered + // to contain the merged values - the parent is allways the + // original request. + private Parameters child=null; + private Parameters parent=null; + private Parameters currentChild=null; + + String encoding=null; + String queryStringEncoding=null; + + /** + * + */ + public Parameters() { + super( INITIAL_SIZE ); + } + + public void setQuery( MessageBytes queryMB ) { + this.queryMB=queryMB; + } + + public void setHeaders( MimeHeaders headers ) { + this.headers=headers; + } + + public void setEncoding( String s ) { + encoding=s; + if(debug>0) log( "Set encoding to " + s ); + } + + public void setQueryStringEncoding( String s ) { + queryStringEncoding=s; + if(debug>0) log( "Set query string encoding to " + s ); + } + + public void recycle() { + super.recycle(); + paramHashStringArray.clear(); + didQueryParameters=false; + currentChild=null; + didMerge=false; + encoding=null; + decodedQuery.recycle(); + } + + // -------------------- Sub-request support -------------------- + + public Parameters getCurrentSet() { + if( currentChild==null ) + return this; + return currentChild; + } + + /** Create ( or reuse ) a child that will be used during a sub-request. + All future changes ( setting query string, adding parameters ) + will affect the child ( the parent request is never changed ). + Both setters and getters will return the data from the deepest + child, merged with data from parents. + */ + public void push() { + // We maintain a linked list, that will grow to the size of the + // longest include chain. + // The list has 2 points of interest: + // - request.parameters() is the original request and head, + // - request.parameters().currentChild() is the current set. + // The ->child and parent<- links are preserved ( currentChild is not + // the last in the list ) + + // create a new element in the linked list + // note that we reuse the child, if any - pop will not + // set child to null ! + if( currentChild==null ) { + currentChild=new Parameters(); + currentChild.setURLDecoder( urlDec ); + currentChild.parent=this; + return; + } + if( currentChild.child==null ) { + currentChild.child=new Parameters(); + currentChild.setURLDecoder( urlDec ); + currentChild.child.parent=currentChild; + } // it is not null if this object already had a child + // i.e. a deeper include() ( we keep it ) + + // the head will be the new element. + currentChild=currentChild.child; + currentChild.setEncoding( encoding ); + } + + /** Discard the last child. This happens when we return from a + sub-request and the parameters are locally modified. + */ + public void pop() { + if( currentChild==null ) { + throw new RuntimeException( "Attempt to pop without a push" ); + } + currentChild.recycle(); + currentChild=currentChild.parent; + // don't remove the top. + } + + // -------------------- Data access -------------------- + // Access to the current name/values, no side effect ( processing ). + // You must explicitely call handleQueryParameters and the post methods. + + // This is the original data representation ( hash of String->String[]) + + public void addParameterValues( String key, String[] newValues) { + if ( key==null ) return; + String values[]; + if (paramHashStringArray.containsKey(key)) { + String oldValues[] = (String[])paramHashStringArray.get(key); + values = new String[oldValues.length + newValues.length]; + for (int i = 0; i < oldValues.length; i++) { + values[i] = oldValues[i]; + } + for (int i = 0; i < newValues.length; i++) { + values[i+ oldValues.length] = newValues[i]; + } + } else { + values = newValues; + } + + paramHashStringArray.put(key, values); + } + + public String[] getParameterValues(String name) { + handleQueryParameters(); + // sub-request + if( currentChild!=null ) { + currentChild.merge(); + return (String[])currentChild.paramHashStringArray.get(name); + } + + // no "facade" + String values[]=(String[])paramHashStringArray.get(name); + return values; + } + + public Enumeration getParameterNames() { + handleQueryParameters(); + // Slow - the original code + if( currentChild!=null ) { + currentChild.merge(); + return currentChild.paramHashStringArray.keys(); + } + + // merge in child + return paramHashStringArray.keys(); + } + + /** Combine the parameters from parent with our local ones + */ + private void merge() { + // recursive + if( debug > 0 ) { + log("Before merging " + this + " " + parent + " " + didMerge ); + log( paramsAsString()); + } + // Local parameters first - they take precedence as in spec. + handleQueryParameters(); + + // we already merged with the parent + if( didMerge ) return; + + // we are the top level + if( parent==null ) return; + + // Add the parent props to the child ( lower precedence ) + parent.merge(); + Hashtable parentProps=parent.paramHashStringArray; + merge2( paramHashStringArray , parentProps); + didMerge=true; + if(debug > 0 ) + log("After " + paramsAsString()); + } + + + // Shortcut. + public String getParameter(String name ) { + String[] values = getParameterValues(name); + if (values != null) { + if( values.length==0 ) return ""; + return values[0]; + } else { + return null; + } + } + // -------------------- Processing -------------------- + /** Process the query string into parameters + */ + public void handleQueryParameters() { + if( didQueryParameters ) return; + + didQueryParameters=true; + + if( queryMB==null || queryMB.isNull() ) + return; + + if( debug > 0 ) + log( "Decoding query " + decodedQuery + " " + queryStringEncoding); + + try { + decodedQuery.duplicate( queryMB ); + } catch (IOException e) { + // Can't happen, as decodedQuery can't overflow + e.printStackTrace(); + } + processParameters( decodedQuery, queryStringEncoding ); + } + + // -------------------- + + /** Combine 2 hashtables into a new one. + * ( two will be added to one ). + * Used to combine child parameters ( RequestDispatcher's query ) + * with parent parameters ( original query or parent dispatcher ) + */ + private static void merge2(Hashtable one, Hashtable two ) { + Enumeration e = two.keys(); + + while (e.hasMoreElements()) { + String name = (String) e.nextElement(); + String[] oneValue = (String[]) one.get(name); + String[] twoValue = (String[]) two.get(name); + String[] combinedValue; + + if (twoValue == null) { + continue; + } else { + if( oneValue==null ) { + combinedValue = new String[twoValue.length]; + System.arraycopy(twoValue, 0, combinedValue, + 0, twoValue.length); + } else { + combinedValue = new String[oneValue.length + + twoValue.length]; + System.arraycopy(oneValue, 0, combinedValue, 0, + oneValue.length); + System.arraycopy(twoValue, 0, combinedValue, + oneValue.length, twoValue.length); + } + one.put(name, combinedValue); + } + } + } + + // incredibly inefficient data representation for parameters, + // until we test the new one + private void addParam( String key, String value ) { + if( key==null ) return; + String values[]; + if (paramHashStringArray.containsKey(key)) { + String oldValues[] = (String[])paramHashStringArray. + get(key); + values = new String[oldValues.length + 1]; + for (int i = 0; i < oldValues.length; i++) { + values[i] = oldValues[i]; + } + values[oldValues.length] = value; + } else { + values = new String[1]; + values[0] = value; + } + + + paramHashStringArray.put(key, values); + } + + public void setURLDecoder( UDecoder u ) { + urlDec=u; + } + + // -------------------- Parameter parsing -------------------- + + // This code is not used right now - it's the optimized version + // of the above. + + // we are called from a single thread - we can do it the hard way + // if needed + ByteChunk tmpName=new ByteChunk(); + ByteChunk tmpValue=new ByteChunk(); + CharChunk tmpNameC=new CharChunk(1024); + CharChunk tmpValueC=new CharChunk(1024); + + public void processParameters( byte bytes[], int start, int len ) { + processParameters(bytes, start, len, encoding); + } + + public void processParameters( byte bytes[], int start, int len, + String enc ) { + int end=start+len; + int pos=start; + + if( debug>0 ) + log( "Bytes: " + new String( bytes, start, len )); + + do { + boolean noEq=false; + int valStart=-1; + int valEnd=-1; + + int nameStart=pos; + int nameEnd=ByteChunk.indexOf(bytes, nameStart, end, '=' ); + // Workaround for a&b&c encoding + int nameEnd2=ByteChunk.indexOf(bytes, nameStart, end, '&' ); + if( (nameEnd2!=-1 ) && + ( nameEnd==-1 || nameEnd > nameEnd2) ) { + nameEnd=nameEnd2; + noEq=true; + valStart=nameEnd; + valEnd=nameEnd; + if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(bytes, nameStart, nameEnd-nameStart) ); + } + if( nameEnd== -1 ) + nameEnd=end; + + if( ! noEq ) { + valStart= (nameEnd < end) ? nameEnd+1 : end; + valEnd=ByteChunk.indexOf(bytes, valStart, end, '&'); + if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; + } + + pos=valEnd+1; + + if( nameEnd<=nameStart ) { + continue; + // invalid chunk - it's better to ignore + // XXX log it ? + } + tmpName.setBytes( bytes, nameStart, nameEnd-nameStart ); + tmpValue.setBytes( bytes, valStart, valEnd-valStart ); + + try { + addParam( urlDecode(tmpName, enc), urlDecode(tmpValue, enc) ); + } catch (IOException e) { + // Exception during character decoding: skip parameter + } + + tmpName.recycle(); + tmpValue.recycle(); + + } while( pos0 ) + log( "Chars: " + new String( chars, start, len )); + do { + boolean noEq=false; + int nameStart=pos; + int valStart=-1; + int valEnd=-1; + + int nameEnd=CharChunk.indexOf(chars, nameStart, end, '=' ); + int nameEnd2=CharChunk.indexOf(chars, nameStart, end, '&' ); + if( (nameEnd2!=-1 ) && + ( nameEnd==-1 || nameEnd > nameEnd2) ) { + nameEnd=nameEnd2; + noEq=true; + valStart=nameEnd; + valEnd=nameEnd; + if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + new String(chars, nameStart, nameEnd-nameStart) ); + } + if( nameEnd== -1 ) nameEnd=end; + + if( ! noEq ) { + valStart= (nameEnd < end) ? nameEnd+1 : end; + valEnd=CharChunk.indexOf(chars, valStart, end, '&'); + if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; + } + + pos=valEnd+1; + + if( nameEnd<=nameStart ) { + continue; + // invalid chunk - no name, it's better to ignore + // XXX log it ? + } + + try { + tmpNameC.append( chars, nameStart, nameEnd-nameStart ); + tmpValueC.append( chars, valStart, valEnd-valStart ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + if( urlDec==null ) { + urlDec=new UDecoder(); + } + + urlDec.convert( tmpNameC ); + urlDec.convert( tmpValueC ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + addParam( tmpNameC.toString(), tmpValueC.toString() ); + } catch( IOException ex ) { + ex.printStackTrace(); + } + + tmpNameC.recycle(); + tmpValueC.recycle(); + + } while( pos 0) + log("String: " + str ); + + do { + boolean noEq=false; + int valStart=-1; + int valEnd=-1; + + int nameStart=pos; + int nameEnd=str.indexOf('=', nameStart ); + int nameEnd2=str.indexOf('&', nameStart ); + if( nameEnd2== -1 ) nameEnd2=end; + if( (nameEnd2!=-1 ) && + ( nameEnd==-1 || nameEnd > nameEnd2) ) { + nameEnd=nameEnd2; + noEq=true; + valStart=nameEnd; + valEnd=nameEnd; + if( debug>0) log("no equal " + nameStart + " " + nameEnd + " " + str.substring(nameStart, nameEnd) ); + } + + if( nameEnd== -1 ) nameEnd=end; + + if( ! noEq ) { + valStart=nameEnd+1; + valEnd=str.indexOf('&', valStart); + if( valEnd== -1 ) valEnd = (valStart < end) ? end : valStart; + } + + pos=valEnd+1; + + if( nameEnd<=nameStart ) { + continue; + } + if( debug>0) + log( "XXX " + nameStart + " " + nameEnd + " " + + valStart + " " + valEnd ); + + try { + tmpNameC.append(str, nameStart, nameEnd-nameStart ); + tmpValueC.append(str, valStart, valEnd-valStart ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + if( urlDec==null ) { + urlDec=new UDecoder(); + } + + urlDec.convert( tmpNameC ); + urlDec.convert( tmpValueC ); + + if( debug > 0 ) + log( tmpNameC + "= " + tmpValueC); + + addParam( tmpNameC.toString(), tmpValueC.toString() ); + } catch( IOException ex ) { + ex.printStackTrace(); + } + + tmpNameC.recycle(); + tmpValueC.recycle(); + + } while( pos char conversion can be delayed - * until we know the charset ). - * - * Tomcat.core uses this recyclable object to represent cookies, - * and the facade will convert it to the external representation. - */ -public class ServerCookie implements Serializable { - - - private static org.apache.commons.logging.Log log= - org.apache.commons.logging.LogFactory.getLog(ServerCookie.class ); - - private MessageBytes name=MessageBytes.newInstance(); - private MessageBytes value=MessageBytes.newInstance(); - - private MessageBytes comment=MessageBytes.newInstance(); // ;Comment=VALUE - private MessageBytes domain=MessageBytes.newInstance(); // ;Domain=VALUE ... - - private int maxAge = -1; // ;Max-Age=VALUE - // ;Discard ... implied by maxAge < 0 - // RFC2109: maxAge=0 will end a session - private MessageBytes path=MessageBytes.newInstance(); // ;Path=VALUE . - private boolean secure; // ;Secure - private int version = 0; // ;Version=1 - - //XXX CommentURL, Port -> use notes ? - - public ServerCookie() { - - } - - public void recycle() { - path.recycle(); - name.recycle(); - value.recycle(); - comment.recycle(); - maxAge=-1; - path.recycle(); - domain.recycle(); - version=0; - secure=false; - } - - public MessageBytes getComment() { - return comment; - } - - public MessageBytes getDomain() { - return domain; - } - - public void setMaxAge(int expiry) { - maxAge = expiry; - } - - public int getMaxAge() { - return maxAge; - } - - - public MessageBytes getPath() { - return path; - } - - public void setSecure(boolean flag) { - secure = flag; - } - - public boolean getSecure() { - return secure; - } - - public MessageBytes getName() { - return name; - } - - public MessageBytes getValue() { - return value; - } - - public int getVersion() { - return version; - } - - - public void setVersion(int v) { - version = v; - } - - - // -------------------- utils -------------------- - - public String toString() { - return "Cookie " + getName() + "=" + getValue() + " ; " - + getVersion() + " " + getPath() + " " + getDomain(); - } - - // Note -- disabled for now to allow full Netscape compatibility - // from RFC 2068, token special case characters - // - // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; - private static final String tspecials = ",; "; - - /* - * Tests a string and returns true if the string counts as a - * reserved token in the Java language. - * - * @param value the String to be tested - * - * @return true if the String is - * a reserved token; false - * if it is not - */ - public static boolean isToken(String value) { - if( value==null) return true; - int len = value.length(); - - for (int i = 0; i < len; i++) { - char c = value.charAt(i); - - if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) - return false; - } - return true; - } - - public static boolean checkName( String name ) { - if (!isToken(name) - || name.equalsIgnoreCase("Comment") // rfc2019 - || name.equalsIgnoreCase("Discard") // 2019++ - || name.equalsIgnoreCase("Domain") - || name.equalsIgnoreCase("Expires") // (old cookies) - || name.equalsIgnoreCase("Max-Age") // rfc2019 - || name.equalsIgnoreCase("Path") - || name.equalsIgnoreCase("Secure") - || name.equalsIgnoreCase("Version") - ) { - return false; - } - return true; - } - - // -------------------- Cookie parsing tools - - - /** Return the header name to set the cookie, based on cookie - * version - */ - public String getCookieHeaderName() { - return getCookieHeaderName(version); - } - - /** Return the header name to set the cookie, based on cookie - * version - */ - public static String getCookieHeaderName(int version) { - if( dbg>0 ) log( (version==1) ? "Set-Cookie2" : "Set-Cookie"); - if (version == 1) { - // RFC2109 - return "Set-Cookie"; - // XXX RFC2965 is not standard yet, and Set-Cookie2 - // is not supported by Netscape 4, 6, IE 3, 5 . - // It is supported by Lynx, and there is hope - // return "Set-Cookie2"; - } else { - // Old Netscape - return "Set-Cookie"; - } - } - - private static final String ancientDate=DateTool.formatOldCookie(new Date(10000)); - - public static void appendCookieValue( StringBuffer buf, - int version, - String name, - String value, - String path, - String domain, - String comment, - int maxAge, - boolean isSecure ) - { - // this part is the same for all cookies - buf.append( name ); - buf.append("="); - maybeQuote(version, buf, value); - - // XXX Netscape cookie: "; " - // add version 1 specific information - if (version == 1) { - // Version=1 ... required - buf.append ("; Version=1"); - - // Comment=comment - if ( comment!=null ) { - buf.append ("; Comment="); - maybeQuote (version, buf, comment); - } - } - - // add domain information, if present - - if (domain!=null) { - buf.append("; Domain="); - maybeQuote (version, buf, domain); - } - - // Max-Age=secs/Discard ... or use old "Expires" format - if (maxAge >= 0) { - if (version == 0) { - // XXX XXX XXX We need to send both, for - // interoperatibility (long word ) - buf.append ("; Expires="); - // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires netscape format ) - // To expire we need to set the time back in future - // ( pfrieden@dChain.com ) - if (maxAge == 0) - buf.append( ancientDate ); - else - DateTool.formatOldCookie - (new Date( System.currentTimeMillis() + - maxAge *1000L), buf, - new FieldPosition(0)); - - } else { - buf.append ("; Max-Age="); - buf.append (maxAge); - } - } - - // Path=path - if (path!=null) { - buf.append ("; Path="); - maybeQuote (version, buf, path); - } - - // Secure - if (isSecure) { - buf.append ("; Secure"); - } - - - } - - public static void maybeQuote (int version, StringBuffer buf, - String value) { - // special case - a \n or \r shouldn't happen in any case - if (isToken(value)) { - buf.append(value); - } else { - buf.append('"'); - buf.append(escapeDoubleQuotes(value)); - buf.append('"'); - } - } - - // log - static final int dbg=1; - public static void log(String s ) { - if (log.isDebugEnabled()) - log.debug("ServerCookie: " + s); - } - - - /** - * Escapes any double quotes in the given string. - * - * @param s the input string - * - * @return The (possibly) escaped string - */ - private static String escapeDoubleQuotes(String s) { - - if (s == null || s.length() == 0 || s.indexOf('"') == -1) { - return s; - } - - StringBuffer b = new StringBuffer(); - for (int i = 0; i < s.length(); i++) { - char c = s.charAt(i); - if (c == '"') - b.append('\\').append('"'); - else - b.append(c); - } - - return b.toString(); - } - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http; + +import java.io.Serializable; +import java.text.FieldPosition; +import java.util.Date; + +import org.apache.tomcat.util.buf.DateTool; +import org.apache.tomcat.util.buf.MessageBytes; + + +/** + * Server-side cookie representation. + * Allows recycling and uses MessageBytes as low-level + * representation ( and thus the byte-> char conversion can be delayed + * until we know the charset ). + * + * Tomcat.core uses this recyclable object to represent cookies, + * and the facade will convert it to the external representation. + */ +public class ServerCookie implements Serializable { + + + private static org.apache.commons.logging.Log log= + org.apache.commons.logging.LogFactory.getLog(ServerCookie.class ); + + private MessageBytes name=MessageBytes.newInstance(); + private MessageBytes value=MessageBytes.newInstance(); + + private MessageBytes comment=MessageBytes.newInstance(); // ;Comment=VALUE + private MessageBytes domain=MessageBytes.newInstance(); // ;Domain=VALUE ... + + private int maxAge = -1; // ;Max-Age=VALUE + // ;Discard ... implied by maxAge < 0 + // RFC2109: maxAge=0 will end a session + private MessageBytes path=MessageBytes.newInstance(); // ;Path=VALUE . + private boolean secure; // ;Secure + private int version = 0; // ;Version=1 + + //XXX CommentURL, Port -> use notes ? + + public ServerCookie() { + + } + + public void recycle() { + path.recycle(); + name.recycle(); + value.recycle(); + comment.recycle(); + maxAge=-1; + path.recycle(); + domain.recycle(); + version=0; + secure=false; + } + + public MessageBytes getComment() { + return comment; + } + + public MessageBytes getDomain() { + return domain; + } + + public void setMaxAge(int expiry) { + maxAge = expiry; + } + + public int getMaxAge() { + return maxAge; + } + + + public MessageBytes getPath() { + return path; + } + + public void setSecure(boolean flag) { + secure = flag; + } + + public boolean getSecure() { + return secure; + } + + public MessageBytes getName() { + return name; + } + + public MessageBytes getValue() { + return value; + } + + public int getVersion() { + return version; + } + + + public void setVersion(int v) { + version = v; + } + + + // -------------------- utils -------------------- + + public String toString() { + return "Cookie " + getName() + "=" + getValue() + " ; " + + getVersion() + " " + getPath() + " " + getDomain(); + } + + // Note -- disabled for now to allow full Netscape compatibility + // from RFC 2068, token special case characters + // + // private static final String tspecials = "()<>@,;:\\\"/[]?={} \t"; + private static final String tspecials = ",; "; + + /* + * Tests a string and returns true if the string counts as a + * reserved token in the Java language. + * + * @param value the String to be tested + * + * @return true if the String is + * a reserved token; false + * if it is not + */ + public static boolean isToken(String value) { + if( value==null) return true; + int len = value.length(); + + for (int i = 0; i < len; i++) { + char c = value.charAt(i); + + if (c < 0x20 || c >= 0x7f || tspecials.indexOf(c) != -1) + return false; + } + return true; + } + + public static boolean checkName( String name ) { + if (!isToken(name) + || name.equalsIgnoreCase("Comment") // rfc2019 + || name.equalsIgnoreCase("Discard") // 2019++ + || name.equalsIgnoreCase("Domain") + || name.equalsIgnoreCase("Expires") // (old cookies) + || name.equalsIgnoreCase("Max-Age") // rfc2019 + || name.equalsIgnoreCase("Path") + || name.equalsIgnoreCase("Secure") + || name.equalsIgnoreCase("Version") + ) { + return false; + } + return true; + } + + // -------------------- Cookie parsing tools + + + /** Return the header name to set the cookie, based on cookie + * version + */ + public String getCookieHeaderName() { + return getCookieHeaderName(version); + } + + /** Return the header name to set the cookie, based on cookie + * version + */ + public static String getCookieHeaderName(int version) { + if( dbg>0 ) log( (version==1) ? "Set-Cookie2" : "Set-Cookie"); + if (version == 1) { + // RFC2109 + return "Set-Cookie"; + // XXX RFC2965 is not standard yet, and Set-Cookie2 + // is not supported by Netscape 4, 6, IE 3, 5 . + // It is supported by Lynx, and there is hope + // return "Set-Cookie2"; + } else { + // Old Netscape + return "Set-Cookie"; + } + } + + private static final String ancientDate=DateTool.formatOldCookie(new Date(10000)); + + public static void appendCookieValue( StringBuffer buf, + int version, + String name, + String value, + String path, + String domain, + String comment, + int maxAge, + boolean isSecure ) + { + // this part is the same for all cookies + buf.append( name ); + buf.append("="); + maybeQuote(version, buf, value); + + // XXX Netscape cookie: "; " + // add version 1 specific information + if (version == 1) { + // Version=1 ... required + buf.append ("; Version=1"); + + // Comment=comment + if ( comment!=null ) { + buf.append ("; Comment="); + maybeQuote (version, buf, comment); + } + } + + // add domain information, if present + + if (domain!=null) { + buf.append("; Domain="); + maybeQuote (version, buf, domain); + } + + // Max-Age=secs/Discard ... or use old "Expires" format + if (maxAge >= 0) { + if (version == 0) { + // XXX XXX XXX We need to send both, for + // interoperatibility (long word ) + buf.append ("; Expires="); + // Wdy, DD-Mon-YY HH:MM:SS GMT ( Expires netscape format ) + // To expire we need to set the time back in future + // ( pfrieden@dChain.com ) + if (maxAge == 0) + buf.append( ancientDate ); + else + DateTool.formatOldCookie + (new Date( System.currentTimeMillis() + + maxAge *1000L), buf, + new FieldPosition(0)); + + } else { + buf.append ("; Max-Age="); + buf.append (maxAge); + } + } + + // Path=path + if (path!=null) { + buf.append ("; Path="); + maybeQuote (version, buf, path); + } + + // Secure + if (isSecure) { + buf.append ("; Secure"); + } + + + } + + public static void maybeQuote (int version, StringBuffer buf, + String value) { + // special case - a \n or \r shouldn't happen in any case + if (isToken(value)) { + buf.append(value); + } else { + buf.append('"'); + buf.append(escapeDoubleQuotes(value)); + buf.append('"'); + } + } + + // log + static final int dbg=1; + public static void log(String s ) { + if (log.isDebugEnabled()) + log.debug("ServerCookie: " + s); + } + + + /** + * Escapes any double quotes in the given string. + * + * @param s the input string + * + * @return The (possibly) escaped string + */ + private static String escapeDoubleQuotes(String s) { + + if (s == null || s.length() == 0 || s.indexOf('"') == -1) { + return s; + } + + StringBuffer b = new StringBuffer(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '"') + b.append('\\').append('"'); + else + b.append(c); + } + + return b.toString(); + } + +} + diff --git a/java/org/apache/tomcat/util/http/mapper/Mapper.java b/java/org/apache/tomcat/util/http/mapper/Mapper.java index 763ff7b8b..0a253e80f 100644 --- a/java/org/apache/tomcat/util/http/mapper/Mapper.java +++ b/java/org/apache/tomcat/util/http/mapper/Mapper.java @@ -1,1396 +1,1396 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http.mapper; - -import javax.naming.NamingException; -import javax.naming.directory.DirContext; - -import org.apache.tomcat.util.buf.CharChunk; -import org.apache.tomcat.util.buf.MessageBytes; -import org.apache.tomcat.util.buf.Ascii; -import java.util.List; -import java.util.ArrayList; - -/** - * Mapper, which implements the servlet API mapping rules (which are derived - * from the HTTP rules). - * - * @author Remy Maucherat - */ -public final class Mapper { - - - private static org.apache.commons.logging.Log logger = - org.apache.commons.logging.LogFactory.getLog(Mapper.class); - // ----------------------------------------------------- Instance Variables - - - /** - * Array containing the virtual hosts definitions. - */ - protected Host[] hosts = new Host[0]; - - - /** - * Default host name. - */ - protected String defaultHostName = null; - - /** - * Context associated with this wrapper, used for wrapper mapping. - */ - protected Context context = new Context(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Get default host. - * - * @return Default host name - */ - public String getDefaultHostName() { - return defaultHostName; - } - - - /** - * Set default host. - * - * @param defaultHostName Default host name - */ - public void setDefaultHostName(String defaultHostName) { - this.defaultHostName = defaultHostName; - } - - /** - * Add a new host to the mapper. - * - * @param name Virtual host name - * @param host Host object - */ - public synchronized void addHost(String name, String[] aliases, - Object host) { - Host[] newHosts = new Host[hosts.length + 1]; - Host newHost = new Host(); - ContextList contextList = new ContextList(); - newHost.name = name; - newHost.contextList = contextList; - newHost.object = host; - if (insertMap(hosts, newHosts, newHost)) { - hosts = newHosts; - } - for (int i = 0; i < aliases.length; i++) { - newHosts = new Host[hosts.length + 1]; - newHost = new Host(); - newHost.name = aliases[i]; - newHost.contextList = contextList; - newHost.object = host; - if (insertMap(hosts, newHosts, newHost)) { - hosts = newHosts; - } - } - } - - - /** - * Remove a host from the mapper. - * - * @param name Virtual host name - */ - public synchronized void removeHost(String name) { - // Find and remove the old host - int pos = find(hosts, name); - if (pos < 0) { - return; - } - Object host = hosts[pos].object; - Host[] newHosts = new Host[hosts.length - 1]; - if (removeMap(hosts, newHosts, name)) { - hosts = newHosts; - } - // Remove all aliases (they will map to the same host object) - for (int i = 0; i < newHosts.length; i++) { - if (newHosts[i].object == host) { - Host[] newHosts2 = new Host[hosts.length - 1]; - if (removeMap(hosts, newHosts2, newHosts[i].name)) { - hosts = newHosts2; - } - } - } - } - - public String[] getHosts() { - String hostN[] = new String[hosts.length]; - for( int i = 0; i < hosts.length; i++ ) { - hostN[i] = hosts[i].name; - } - return hostN; - } - - - /** - * Set context, used for wrapper mapping (request dispatcher). - * - * @param welcomeResources Welcome files defined for this context - * @param resources Static resources of the context - */ - public void setContext(String path, String[] welcomeResources, - javax.naming.Context resources) { - context.name = path; - context.welcomeResources = welcomeResources; - context.resources = resources; - } - - - /** - * Add a new Context to an existing Host. - * - * @param hostName Virtual host name this context belongs to - * @param path Context path - * @param context Context object - * @param welcomeResources Welcome files defined for this context - * @param resources Static resources of the context - */ - public void addContext - (String hostName, String path, Object context, - String[] welcomeResources, javax.naming.Context resources) { - - Host[] hosts = this.hosts; - int pos = find(hosts, hostName); - if( pos <0 ) { - addHost(hostName, new String[0], ""); - hosts = this.hosts; - pos = find(hosts, hostName); - } - if (pos < 0) { - logger.error("No host found: " + hostName); - } - Host host = hosts[pos]; - if (host.name.equals(hostName)) { - int slashCount = slashCount(path); - synchronized (host) { - Context[] contexts = host.contextList.contexts; - // Update nesting - if (slashCount > host.contextList.nesting) { - host.contextList.nesting = slashCount; - } - Context[] newContexts = new Context[contexts.length + 1]; - Context newContext = new Context(); - newContext.name = path; - newContext.object = context; - newContext.welcomeResources = welcomeResources; - newContext.resources = resources; - if (insertMap(contexts, newContexts, newContext)) { - host.contextList.contexts = newContexts; - } - } - } - - } - - - /** - * Remove a context from an existing host. - * - * @param hostName Virtual host name this context belongs to - * @param path Context path - */ - public void removeContext(String hostName, String path) { - Host[] hosts = this.hosts; - int pos = find(hosts, hostName); - if (pos < 0) { - return; - } - Host host = hosts[pos]; - if (host.name.equals(hostName)) { - synchronized (host) { - Context[] contexts = host.contextList.contexts; - if( contexts.length == 0 ){ - return; - } - Context[] newContexts = new Context[contexts.length - 1]; - if (removeMap(contexts, newContexts, path)) { - host.contextList.contexts = newContexts; - // Recalculate nesting - host.contextList.nesting = 0; - for (int i = 0; i < newContexts.length; i++) { - int slashCount = slashCount(newContexts[i].name); - if (slashCount > host.contextList.nesting) { - host.contextList.nesting = slashCount; - } - } - } - } - } - } - - - /** - * Return all contexts, in //HOST/PATH form - * - * @return The context names - */ - public String[] getContextNames() { - List list=new ArrayList(); - for( int i=0; i context.nesting) { - context.nesting = slashCount; - } - } - } else if (path.startsWith("*.")) { - // Extension wrapper - newWrapper.name = path.substring(2); - Wrapper[] oldWrappers = context.extensionWrappers; - Wrapper[] newWrappers = - new Wrapper[oldWrappers.length + 1]; - if (insertMap(oldWrappers, newWrappers, newWrapper)) { - context.extensionWrappers = newWrappers; - } - } else if (path.equals("/")) { - // Default wrapper - newWrapper.name = ""; - context.defaultWrapper = newWrapper; - } else { - // Exact wrapper - newWrapper.name = path; - Wrapper[] oldWrappers = context.exactWrappers; - Wrapper[] newWrappers = - new Wrapper[oldWrappers.length + 1]; - if (insertMap(oldWrappers, newWrappers, newWrapper)) { - context.exactWrappers = newWrappers; - } - } - } - } - - - /** - * Remove a wrapper from the context associated with this wrapper. - * - * @param path Wrapper mapping - */ - public void removeWrapper(String path) { - removeWrapper(context, path); - } - - - /** - * Remove a wrapper from an existing context. - * - * @param hostName Virtual host name this wrapper belongs to - * @param contextPath Context path this wrapper belongs to - * @param path Wrapper mapping - */ - public void removeWrapper - (String hostName, String contextPath, String path) { - Host[] hosts = this.hosts; - int pos = find(hosts, hostName); - if (pos < 0) { - return; - } - Host host = hosts[pos]; - if (host.name.equals(hostName)) { - Context[] contexts = host.contextList.contexts; - int pos2 = find(contexts, contextPath); - if (pos2 < 0) { - return; - } - Context context = contexts[pos2]; - if (context.name.equals(contextPath)) { - removeWrapper(context, path); - } - } - } - - protected void removeWrapper(Context context, String path) { - synchronized (context) { - if (path.endsWith("/*")) { - // Wildcard wrapper - String name = path.substring(0, path.length() - 2); - Wrapper[] oldWrappers = context.wildcardWrappers; - Wrapper[] newWrappers = - new Wrapper[oldWrappers.length - 1]; - if (removeMap(oldWrappers, newWrappers, name)) { - // Recalculate nesting - context.nesting = 0; - for (int i = 0; i < newWrappers.length; i++) { - int slashCount = slashCount(newWrappers[i].name); - if (slashCount > context.nesting) { - context.nesting = slashCount; - } - } - context.wildcardWrappers = newWrappers; - } - } else if (path.startsWith("*.")) { - // Extension wrapper - String name = path.substring(2); - Wrapper[] oldWrappers = context.extensionWrappers; - Wrapper[] newWrappers = - new Wrapper[oldWrappers.length - 1]; - if (removeMap(oldWrappers, newWrappers, name)) { - context.extensionWrappers = newWrappers; - } - } else if (path.equals("/")) { - // Default wrapper - context.defaultWrapper = null; - } else { - // Exact wrapper - String name = path; - Wrapper[] oldWrappers = context.exactWrappers; - Wrapper[] newWrappers = - new Wrapper[oldWrappers.length - 1]; - if (removeMap(oldWrappers, newWrappers, name)) { - context.exactWrappers = newWrappers; - } - } - } - } - - public String getWrappersString( String host, String context ) { - String names[]=getWrapperNames(host, context); - StringBuffer sb=new StringBuffer(); - for( int i=0; i= 0) { - if (uri.startsWith(contexts[pos].name)) { - length = contexts[pos].name.length(); - if (uri.getLength() == length) { - found = true; - break; - } else if (uri.startsWithIgnoreCase("/", length)) { - found = true; - break; - } - } - if (lastSlash == -1) { - lastSlash = nthSlash(uri, nesting + 1); - } else { - lastSlash = lastSlash(uri); - } - uri.setEnd(lastSlash); - pos = find(contexts, uri); - } - uri.setEnd(uriEnd); - - if (!found) { - if (contexts[0].name.equals("")) { - context = contexts[0]; - } - } else { - context = contexts[pos]; - } - if (context != null) { - mappingData.context = context.object; - mappingData.contextPath.setString(context.name); - } - } - - // Wrapper mapping - if ((context != null) && (mappingData.wrapper == null)) { - internalMapWrapper(context, uri, mappingData); - } - - } - - - /** - * Wrapper mapping. - */ - private final void internalMapWrapper(Context context, CharChunk path, - MappingData mappingData) - throws Exception { - - int pathOffset = path.getOffset(); - int pathEnd = path.getEnd(); - int servletPath = pathOffset; - boolean noServletPath = false; - - int length = context.name.length(); - if (length != (pathEnd - pathOffset)) { - servletPath = pathOffset + length; - } else { - noServletPath = true; - path.append('/'); - pathOffset = path.getOffset(); - pathEnd = path.getEnd(); - servletPath = pathOffset+length; - } - - path.setOffset(servletPath); - - // Rule 1 -- Exact Match - Wrapper[] exactWrappers = context.exactWrappers; - internalMapExactWrapper(exactWrappers, path, mappingData); - - // Rule 2 -- Prefix Match - boolean checkJspWelcomeFiles = false; - Wrapper[] wildcardWrappers = context.wildcardWrappers; - if (mappingData.wrapper == null) { - internalMapWildcardWrapper(wildcardWrappers, context.nesting, - path, mappingData); - if (mappingData.wrapper != null && mappingData.jspWildCard) { - char[] buf = path.getBuffer(); - if (buf[pathEnd - 1] == '/') { - /* - * Path ending in '/' was mapped to JSP servlet based on - * wildcard match (e.g., as specified in url-pattern of a - * jsp-property-group. - * Force the context's welcome files, which are interpreted - * as JSP files (since they match the url-pattern), to be - * considered. See Bugzilla 27664. - */ - mappingData.wrapper = null; - checkJspWelcomeFiles = true; - } else { - // See Bugzilla 27704 - mappingData.wrapperPath.setChars(buf, path.getStart(), - path.getLength()); - mappingData.pathInfo.recycle(); - } - } - } - - if(mappingData.wrapper == null && noServletPath) { - // The path is empty, redirect to "/" - mappingData.redirectPath.setChars - (path.getBuffer(), pathOffset, pathEnd); - path.setEnd(pathEnd - 1); - return; - } - - // Rule 3 -- Extension Match - Wrapper[] extensionWrappers = context.extensionWrappers; - if (mappingData.wrapper == null && !checkJspWelcomeFiles) { - internalMapExtensionWrapper(extensionWrappers, path, mappingData); - } - - // Rule 4 -- Welcome resources processing for servlets - if (mappingData.wrapper == null) { - boolean checkWelcomeFiles = checkJspWelcomeFiles; - if (!checkWelcomeFiles) { - char[] buf = path.getBuffer(); - checkWelcomeFiles = (buf[pathEnd - 1] == '/'); - } - if (checkWelcomeFiles) { - for (int i = 0; (i < context.welcomeResources.length) - && (mappingData.wrapper == null); i++) { - path.setOffset(pathOffset); - path.setEnd(pathEnd); - path.append(context.welcomeResources[i], 0, - context.welcomeResources[i].length()); - path.setOffset(servletPath); - - // Rule 4a -- Welcome resources processing for exact macth - internalMapExactWrapper(exactWrappers, path, mappingData); - - // Rule 4b -- Welcome resources processing for prefix match - if (mappingData.wrapper == null) { - internalMapWildcardWrapper - (wildcardWrappers, context.nesting, - path, mappingData); - } - - // Rule 4c -- Welcome resources processing - // for physical folder - if (mappingData.wrapper == null - && context.resources != null) { - Object file = null; - String pathStr = path.toString(); - try { - file = context.resources.lookup(pathStr); - } catch(NamingException nex) { - // Swallow not found, since this is normal - } - if (file != null && !(file instanceof DirContext) ) { - internalMapExtensionWrapper(extensionWrappers, - path, mappingData); - if (mappingData.wrapper == null - && context.defaultWrapper != null) { - mappingData.wrapper = - context.defaultWrapper.object; - mappingData.requestPath.setChars - (path.getBuffer(), path.getStart(), - path.getLength()); - mappingData.wrapperPath.setChars - (path.getBuffer(), path.getStart(), - path.getLength()); - mappingData.requestPath.setString(pathStr); - mappingData.wrapperPath.setString(pathStr); - } - } - } - } - - path.setOffset(servletPath); - path.setEnd(pathEnd); - } - - } - - - // Rule 7 -- Default servlet - if (mappingData.wrapper == null && !checkJspWelcomeFiles) { - if (context.defaultWrapper != null) { - mappingData.wrapper = context.defaultWrapper.object; - mappingData.requestPath.setChars - (path.getBuffer(), path.getStart(), path.getLength()); - mappingData.wrapperPath.setChars - (path.getBuffer(), path.getStart(), path.getLength()); - } - // Redirection to a folder - char[] buf = path.getBuffer(); - if (context.resources != null && buf[pathEnd -1 ] != '/') { - Object file = null; - String pathStr = path.toString(); - try { - file = context.resources.lookup(pathStr); - } catch(NamingException nex) { - // Swallow, since someone else handles the 404 - } - if (file != null && file instanceof DirContext) { - // Note: this mutates the path: do not do any processing - // after this (since we set the redirectPath, there - // shouldn't be any) - path.setOffset(pathOffset); - path.append('/'); - mappingData.redirectPath.setChars - (path.getBuffer(), path.getStart(), path.getLength()); - } else { - mappingData.requestPath.setString(pathStr); - mappingData.wrapperPath.setString(pathStr); - } - } - } - - path.setOffset(pathOffset); - path.setEnd(pathEnd); - - } - - - /** - * Exact mapping. - */ - private final void internalMapExactWrapper - (Wrapper[] wrappers, CharChunk path, MappingData mappingData) { - int pos = find(wrappers, path); - if ((pos != -1) && (path.equals(wrappers[pos].name))) { - mappingData.requestPath.setString(wrappers[pos].name); - mappingData.wrapperPath.setString(wrappers[pos].name); - mappingData.wrapper = wrappers[pos].object; - } - } - - - /** - * Wildcard mapping. - */ - private final void internalMapWildcardWrapper - (Wrapper[] wrappers, int nesting, CharChunk path, - MappingData mappingData) { - - int pathEnd = path.getEnd(); - int pathOffset = path.getOffset(); - - int lastSlash = -1; - int length = -1; - int pos = find(wrappers, path); - if (pos != -1) { - boolean found = false; - while (pos >= 0) { - if (path.startsWith(wrappers[pos].name)) { - length = wrappers[pos].name.length(); - if (path.getLength() == length) { - found = true; - break; - } else if (path.startsWithIgnoreCase("/", length)) { - found = true; - break; - } - } - if (lastSlash == -1) { - lastSlash = nthSlash(path, nesting + 1); - } else { - lastSlash = lastSlash(path); - } - path.setEnd(lastSlash); - pos = find(wrappers, path); - } - path.setEnd(pathEnd); - if (found) { - mappingData.wrapperPath.setString(wrappers[pos].name); - if (path.getLength() > length) { - mappingData.pathInfo.setChars - (path.getBuffer(), - path.getOffset() + length, - path.getLength() - length); - } - mappingData.requestPath.setChars - (path.getBuffer(), path.getOffset(), path.getLength()); - mappingData.wrapper = wrappers[pos].object; - mappingData.jspWildCard = wrappers[pos].jspWildCard; - } - } - } - - - /** - * Extension mappings. - */ - private final void internalMapExtensionWrapper - (Wrapper[] wrappers, CharChunk path, MappingData mappingData) { - char[] buf = path.getBuffer(); - int pathEnd = path.getEnd(); - int servletPath = path.getOffset(); - int slash = -1; - for (int i = pathEnd - 1; i >= servletPath; i--) { - if (buf[i] == '/') { - slash = i; - break; - } - } - if (slash >= 0) { - int period = -1; - for (int i = pathEnd - 1; i > slash; i--) { - if (buf[i] == '.') { - period = i; - break; - } - } - if (period >= 0) { - path.setOffset(period + 1); - path.setEnd(pathEnd); - int pos = find(wrappers, path); - if ((pos != -1) - && (path.equals(wrappers[pos].name))) { - mappingData.wrapperPath.setChars - (buf, servletPath, pathEnd - servletPath); - mappingData.requestPath.setChars - (buf, servletPath, pathEnd - servletPath); - mappingData.wrapper = wrappers[pos].object; - } - path.setOffset(servletPath); - path.setEnd(pathEnd); - } - } - } - - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int find(MapElement[] map, CharChunk name) { - return find(map, name, name.getStart(), name.getEnd()); - } - - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int find(MapElement[] map, CharChunk name, - int start, int end) { - - int a = 0; - int b = map.length - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - - if (compare(name, start, end, map[0].name) < 0 ) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = compare(name, start, end, map[i].name); - if (result == 1) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = compare(name, start, end, map[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int findIgnoreCase(MapElement[] map, CharChunk name) { - return findIgnoreCase(map, name, name.getStart(), name.getEnd()); - } - - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int findIgnoreCase(MapElement[] map, CharChunk name, - int start, int end) { - - int a = 0; - int b = map.length - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = compareIgnoreCase(name, start, end, map[i].name); - if (result == 1) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = compareIgnoreCase(name, start, end, map[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - - /** - * Find a map elemnt given its name in a sorted array of map elements. - * This will return the index for the closest inferior or equal item in the - * given array. - */ - private static final int find(MapElement[] map, String name) { - - int a = 0; - int b = map.length - 1; - - // Special cases: -1 and 0 - if (b == -1) { - return -1; - } - - if (name.compareTo(map[0].name) < 0) { - return -1; - } - if (b == 0) { - return 0; - } - - int i = 0; - while (true) { - i = (b + a) / 2; - int result = name.compareTo(map[i].name); - if (result > 0) { - a = i; - } else if (result == 0) { - return i; - } else { - b = i; - } - if ((b - a) == 1) { - int result2 = name.compareTo(map[b].name); - if (result2 < 0) { - return a; - } else { - return b; - } - } - } - - } - - - /** - * Compare given char chunk with String. - * Return -1, 0 or +1 if inferior, equal, or superior to the String. - */ - private static final int compare(CharChunk name, int start, int end, - String compareTo) { - int result = 0; - char[] c = name.getBuffer(); - int len = compareTo.length(); - if ((end - start) < len) { - len = end - start; - } - for (int i = 0; (i < len) && (result == 0); i++) { - if (c[i + start] > compareTo.charAt(i)) { - result = 1; - } else if (c[i + start] < compareTo.charAt(i)) { - result = -1; - } - } - if (result == 0) { - if (compareTo.length() > (end - start)) { - result = -1; - } else if (compareTo.length() < (end - start)) { - result = 1; - } - } - return result; - } - - - /** - * Compare given char chunk with String ignoring case. - * Return -1, 0 or +1 if inferior, equal, or superior to the String. - */ - private static final int compareIgnoreCase(CharChunk name, int start, int end, - String compareTo) { - int result = 0; - char[] c = name.getBuffer(); - int len = compareTo.length(); - if ((end - start) < len) { - len = end - start; - } - for (int i = 0; (i < len) && (result == 0); i++) { - if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) { - result = 1; - } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) { - result = -1; - } - } - if (result == 0) { - if (compareTo.length() > (end - start)) { - result = -1; - } else if (compareTo.length() < (end - start)) { - result = 1; - } - } - return result; - } - - - /** - * Find the position of the last slash in the given char chunk. - */ - private static final int lastSlash(CharChunk name) { - - char[] c = name.getBuffer(); - int end = name.getEnd(); - int start = name.getStart(); - int pos = end; - - while (pos > start) { - if (c[--pos] == '/') { - break; - } - } - - return (pos); - - } - - - /** - * Find the position of the nth slash, in the given char chunk. - */ - private static final int nthSlash(CharChunk name, int n) { - - char[] c = name.getBuffer(); - int end = name.getEnd(); - int start = name.getStart(); - int pos = start; - int count = 0; - - while (pos < end) { - if ((c[pos++] == '/') && ((++count) == n)) { - pos--; - break; - } - } - - return (pos); - - } - - - /** - * Return the slash count in a given string. - */ - private static final int slashCount(String name) { - int pos = -1; - int count = 0; - while ((pos = name.indexOf('/', pos + 1)) != -1) { - count++; - } - return count; - } - - - /** - * Insert into the right place in a sorted MapElement array, and prevent - * duplicates. - */ - private static final boolean insertMap - (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) { - int pos = find(oldMap, newElement.name); - if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) { - return false; - } - System.arraycopy(oldMap, 0, newMap, 0, pos + 1); - newMap[pos + 1] = newElement; - System.arraycopy - (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1); - return true; - } - - - /** - * Insert into the right place in a sorted MapElement array. - */ - private static final boolean removeMap - (MapElement[] oldMap, MapElement[] newMap, String name) { - int pos = find(oldMap, name); - if ((pos != -1) && (name.equals(oldMap[pos].name))) { - System.arraycopy(oldMap, 0, newMap, 0, pos); - System.arraycopy(oldMap, pos + 1, newMap, pos, - oldMap.length - pos - 1); - return true; - } - return false; - } - - - // ------------------------------------------------- MapElement Inner Class - - - protected static abstract class MapElement { - - public String name = null; - public Object object = null; - - } - - - // ------------------------------------------------------- Host Inner Class - - - protected static final class Host - extends MapElement { - - public ContextList contextList = null; - - } - - - // ------------------------------------------------ ContextList Inner Class - - - protected static final class ContextList { - - public Context[] contexts = new Context[0]; - public int nesting = 0; - - } - - - // ---------------------------------------------------- Context Inner Class - - - protected static final class Context - extends MapElement { - - public String path = null; - public String[] welcomeResources = new String[0]; - public javax.naming.Context resources = null; - public Wrapper defaultWrapper = null; - public Wrapper[] exactWrappers = new Wrapper[0]; - public Wrapper[] wildcardWrappers = new Wrapper[0]; - public Wrapper[] extensionWrappers = new Wrapper[0]; - public int nesting = 0; - - } - - - // ---------------------------------------------------- Wrapper Inner Class - - - protected static class Wrapper - extends MapElement { - - public String path = null; - public boolean jspWildCard = false; - } - - - // -------------------------------------------------------- Testing Methods - - // FIXME: Externalize this - /* - public static void main(String args[]) { - - try { - - Mapper mapper = new Mapper(); - System.out.println("Start"); - - mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1"); - mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1"); - mapper.addHost("wekhfewuifweuibf", new String[0], "blah2"); - mapper.addHost("ylwrehirkuewh", new String[0], "blah3"); - mapper.addHost("iohgeoihro", new String[0], "blah4"); - mapper.addHost("fwehoihoihwfeo", new String[0], "blah5"); - mapper.addHost("owefojiwefoi", new String[0], "blah6"); - mapper.addHost("iowejoiejfoiew", new String[0], "blah7"); - mapper.addHost("iowejoiejfoiew", new String[0], "blah17"); - mapper.addHost("ohewoihfewoih", new String[0], "blah8"); - mapper.addHost("fewohfoweoih", new String[0], "blah9"); - mapper.addHost("ttthtiuhwoih", new String[0], "blah10"); - mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11"); - mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12"); - mapper.addHost("xxxxgqwiwoih", new String[0], "blah13"); - mapper.addHost("qwigqwiwoih", new String[0], "blah14"); - - System.out.println("Map:"); - for (int i = 0; i < mapper.hosts.length; i++) { - System.out.println(mapper.hosts[i].name); - } - - mapper.setDefaultHostName("ylwrehirkuewh"); - - String[] welcomes = new String[2]; - welcomes[0] = "boo/baba"; - welcomes[1] = "bobou"; - - mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null); - mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null); - mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null); - mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null); - - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5"); - mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6"); - - MappingData mappingData = new MappingData(); - MessageBytes host = MessageBytes.newInstance(); - host.setString("iowejoiejfoiew"); - MessageBytes uri = MessageBytes.newInstance(); - uri.setString("/foo/bar/blah/bobou/foo"); - uri.toChars(); - uri.getCharChunk().setLimit(-1); - - mapper.map(host, uri, mappingData); - System.out.println("MD Host:" + mappingData.host); - System.out.println("MD Context:" + mappingData.context); - System.out.println("MD Wrapper:" + mappingData.wrapper); - - System.out.println("contextPath:" + mappingData.contextPath); - System.out.println("wrapperPath:" + mappingData.wrapperPath); - System.out.println("pathInfo:" + mappingData.pathInfo); - System.out.println("redirectPath:" + mappingData.redirectPath); - - mappingData.recycle(); - mapper.map(host, uri, mappingData); - System.out.println("MD Host:" + mappingData.host); - System.out.println("MD Context:" + mappingData.context); - System.out.println("MD Wrapper:" + mappingData.wrapper); - - System.out.println("contextPath:" + mappingData.contextPath); - System.out.println("wrapperPath:" + mappingData.wrapperPath); - System.out.println("pathInfo:" + mappingData.pathInfo); - System.out.println("redirectPath:" + mappingData.redirectPath); - - for (int i = 0; i < 1000000; i++) { - mappingData.recycle(); - mapper.map(host, uri, mappingData); - } - - long time = System.currentTimeMillis(); - for (int i = 0; i < 1000000; i++) { - mappingData.recycle(); - mapper.map(host, uri, mappingData); - } - System.out.println("Elapsed:" + (System.currentTimeMillis() - time)); - - System.out.println("MD Host:" + mappingData.host); - System.out.println("MD Context:" + mappingData.context); - System.out.println("MD Wrapper:" + mappingData.wrapper); - - System.out.println("contextPath:" + mappingData.contextPath); - System.out.println("wrapperPath:" + mappingData.wrapperPath); - System.out.println("requestPath:" + mappingData.requestPath); - System.out.println("pathInfo:" + mappingData.pathInfo); - System.out.println("redirectPath:" + mappingData.redirectPath); - - } catch (Exception e) { - e.printStackTrace(); - } - - } - */ - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http.mapper; + +import javax.naming.NamingException; +import javax.naming.directory.DirContext; + +import org.apache.tomcat.util.buf.CharChunk; +import org.apache.tomcat.util.buf.MessageBytes; +import org.apache.tomcat.util.buf.Ascii; +import java.util.List; +import java.util.ArrayList; + +/** + * Mapper, which implements the servlet API mapping rules (which are derived + * from the HTTP rules). + * + * @author Remy Maucherat + */ +public final class Mapper { + + + private static org.apache.commons.logging.Log logger = + org.apache.commons.logging.LogFactory.getLog(Mapper.class); + // ----------------------------------------------------- Instance Variables + + + /** + * Array containing the virtual hosts definitions. + */ + protected Host[] hosts = new Host[0]; + + + /** + * Default host name. + */ + protected String defaultHostName = null; + + /** + * Context associated with this wrapper, used for wrapper mapping. + */ + protected Context context = new Context(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Get default host. + * + * @return Default host name + */ + public String getDefaultHostName() { + return defaultHostName; + } + + + /** + * Set default host. + * + * @param defaultHostName Default host name + */ + public void setDefaultHostName(String defaultHostName) { + this.defaultHostName = defaultHostName; + } + + /** + * Add a new host to the mapper. + * + * @param name Virtual host name + * @param host Host object + */ + public synchronized void addHost(String name, String[] aliases, + Object host) { + Host[] newHosts = new Host[hosts.length + 1]; + Host newHost = new Host(); + ContextList contextList = new ContextList(); + newHost.name = name; + newHost.contextList = contextList; + newHost.object = host; + if (insertMap(hosts, newHosts, newHost)) { + hosts = newHosts; + } + for (int i = 0; i < aliases.length; i++) { + newHosts = new Host[hosts.length + 1]; + newHost = new Host(); + newHost.name = aliases[i]; + newHost.contextList = contextList; + newHost.object = host; + if (insertMap(hosts, newHosts, newHost)) { + hosts = newHosts; + } + } + } + + + /** + * Remove a host from the mapper. + * + * @param name Virtual host name + */ + public synchronized void removeHost(String name) { + // Find and remove the old host + int pos = find(hosts, name); + if (pos < 0) { + return; + } + Object host = hosts[pos].object; + Host[] newHosts = new Host[hosts.length - 1]; + if (removeMap(hosts, newHosts, name)) { + hosts = newHosts; + } + // Remove all aliases (they will map to the same host object) + for (int i = 0; i < newHosts.length; i++) { + if (newHosts[i].object == host) { + Host[] newHosts2 = new Host[hosts.length - 1]; + if (removeMap(hosts, newHosts2, newHosts[i].name)) { + hosts = newHosts2; + } + } + } + } + + public String[] getHosts() { + String hostN[] = new String[hosts.length]; + for( int i = 0; i < hosts.length; i++ ) { + hostN[i] = hosts[i].name; + } + return hostN; + } + + + /** + * Set context, used for wrapper mapping (request dispatcher). + * + * @param welcomeResources Welcome files defined for this context + * @param resources Static resources of the context + */ + public void setContext(String path, String[] welcomeResources, + javax.naming.Context resources) { + context.name = path; + context.welcomeResources = welcomeResources; + context.resources = resources; + } + + + /** + * Add a new Context to an existing Host. + * + * @param hostName Virtual host name this context belongs to + * @param path Context path + * @param context Context object + * @param welcomeResources Welcome files defined for this context + * @param resources Static resources of the context + */ + public void addContext + (String hostName, String path, Object context, + String[] welcomeResources, javax.naming.Context resources) { + + Host[] hosts = this.hosts; + int pos = find(hosts, hostName); + if( pos <0 ) { + addHost(hostName, new String[0], ""); + hosts = this.hosts; + pos = find(hosts, hostName); + } + if (pos < 0) { + logger.error("No host found: " + hostName); + } + Host host = hosts[pos]; + if (host.name.equals(hostName)) { + int slashCount = slashCount(path); + synchronized (host) { + Context[] contexts = host.contextList.contexts; + // Update nesting + if (slashCount > host.contextList.nesting) { + host.contextList.nesting = slashCount; + } + Context[] newContexts = new Context[contexts.length + 1]; + Context newContext = new Context(); + newContext.name = path; + newContext.object = context; + newContext.welcomeResources = welcomeResources; + newContext.resources = resources; + if (insertMap(contexts, newContexts, newContext)) { + host.contextList.contexts = newContexts; + } + } + } + + } + + + /** + * Remove a context from an existing host. + * + * @param hostName Virtual host name this context belongs to + * @param path Context path + */ + public void removeContext(String hostName, String path) { + Host[] hosts = this.hosts; + int pos = find(hosts, hostName); + if (pos < 0) { + return; + } + Host host = hosts[pos]; + if (host.name.equals(hostName)) { + synchronized (host) { + Context[] contexts = host.contextList.contexts; + if( contexts.length == 0 ){ + return; + } + Context[] newContexts = new Context[contexts.length - 1]; + if (removeMap(contexts, newContexts, path)) { + host.contextList.contexts = newContexts; + // Recalculate nesting + host.contextList.nesting = 0; + for (int i = 0; i < newContexts.length; i++) { + int slashCount = slashCount(newContexts[i].name); + if (slashCount > host.contextList.nesting) { + host.contextList.nesting = slashCount; + } + } + } + } + } + } + + + /** + * Return all contexts, in //HOST/PATH form + * + * @return The context names + */ + public String[] getContextNames() { + List list=new ArrayList(); + for( int i=0; i context.nesting) { + context.nesting = slashCount; + } + } + } else if (path.startsWith("*.")) { + // Extension wrapper + newWrapper.name = path.substring(2); + Wrapper[] oldWrappers = context.extensionWrappers; + Wrapper[] newWrappers = + new Wrapper[oldWrappers.length + 1]; + if (insertMap(oldWrappers, newWrappers, newWrapper)) { + context.extensionWrappers = newWrappers; + } + } else if (path.equals("/")) { + // Default wrapper + newWrapper.name = ""; + context.defaultWrapper = newWrapper; + } else { + // Exact wrapper + newWrapper.name = path; + Wrapper[] oldWrappers = context.exactWrappers; + Wrapper[] newWrappers = + new Wrapper[oldWrappers.length + 1]; + if (insertMap(oldWrappers, newWrappers, newWrapper)) { + context.exactWrappers = newWrappers; + } + } + } + } + + + /** + * Remove a wrapper from the context associated with this wrapper. + * + * @param path Wrapper mapping + */ + public void removeWrapper(String path) { + removeWrapper(context, path); + } + + + /** + * Remove a wrapper from an existing context. + * + * @param hostName Virtual host name this wrapper belongs to + * @param contextPath Context path this wrapper belongs to + * @param path Wrapper mapping + */ + public void removeWrapper + (String hostName, String contextPath, String path) { + Host[] hosts = this.hosts; + int pos = find(hosts, hostName); + if (pos < 0) { + return; + } + Host host = hosts[pos]; + if (host.name.equals(hostName)) { + Context[] contexts = host.contextList.contexts; + int pos2 = find(contexts, contextPath); + if (pos2 < 0) { + return; + } + Context context = contexts[pos2]; + if (context.name.equals(contextPath)) { + removeWrapper(context, path); + } + } + } + + protected void removeWrapper(Context context, String path) { + synchronized (context) { + if (path.endsWith("/*")) { + // Wildcard wrapper + String name = path.substring(0, path.length() - 2); + Wrapper[] oldWrappers = context.wildcardWrappers; + Wrapper[] newWrappers = + new Wrapper[oldWrappers.length - 1]; + if (removeMap(oldWrappers, newWrappers, name)) { + // Recalculate nesting + context.nesting = 0; + for (int i = 0; i < newWrappers.length; i++) { + int slashCount = slashCount(newWrappers[i].name); + if (slashCount > context.nesting) { + context.nesting = slashCount; + } + } + context.wildcardWrappers = newWrappers; + } + } else if (path.startsWith("*.")) { + // Extension wrapper + String name = path.substring(2); + Wrapper[] oldWrappers = context.extensionWrappers; + Wrapper[] newWrappers = + new Wrapper[oldWrappers.length - 1]; + if (removeMap(oldWrappers, newWrappers, name)) { + context.extensionWrappers = newWrappers; + } + } else if (path.equals("/")) { + // Default wrapper + context.defaultWrapper = null; + } else { + // Exact wrapper + String name = path; + Wrapper[] oldWrappers = context.exactWrappers; + Wrapper[] newWrappers = + new Wrapper[oldWrappers.length - 1]; + if (removeMap(oldWrappers, newWrappers, name)) { + context.exactWrappers = newWrappers; + } + } + } + } + + public String getWrappersString( String host, String context ) { + String names[]=getWrapperNames(host, context); + StringBuffer sb=new StringBuffer(); + for( int i=0; i= 0) { + if (uri.startsWith(contexts[pos].name)) { + length = contexts[pos].name.length(); + if (uri.getLength() == length) { + found = true; + break; + } else if (uri.startsWithIgnoreCase("/", length)) { + found = true; + break; + } + } + if (lastSlash == -1) { + lastSlash = nthSlash(uri, nesting + 1); + } else { + lastSlash = lastSlash(uri); + } + uri.setEnd(lastSlash); + pos = find(contexts, uri); + } + uri.setEnd(uriEnd); + + if (!found) { + if (contexts[0].name.equals("")) { + context = contexts[0]; + } + } else { + context = contexts[pos]; + } + if (context != null) { + mappingData.context = context.object; + mappingData.contextPath.setString(context.name); + } + } + + // Wrapper mapping + if ((context != null) && (mappingData.wrapper == null)) { + internalMapWrapper(context, uri, mappingData); + } + + } + + + /** + * Wrapper mapping. + */ + private final void internalMapWrapper(Context context, CharChunk path, + MappingData mappingData) + throws Exception { + + int pathOffset = path.getOffset(); + int pathEnd = path.getEnd(); + int servletPath = pathOffset; + boolean noServletPath = false; + + int length = context.name.length(); + if (length != (pathEnd - pathOffset)) { + servletPath = pathOffset + length; + } else { + noServletPath = true; + path.append('/'); + pathOffset = path.getOffset(); + pathEnd = path.getEnd(); + servletPath = pathOffset+length; + } + + path.setOffset(servletPath); + + // Rule 1 -- Exact Match + Wrapper[] exactWrappers = context.exactWrappers; + internalMapExactWrapper(exactWrappers, path, mappingData); + + // Rule 2 -- Prefix Match + boolean checkJspWelcomeFiles = false; + Wrapper[] wildcardWrappers = context.wildcardWrappers; + if (mappingData.wrapper == null) { + internalMapWildcardWrapper(wildcardWrappers, context.nesting, + path, mappingData); + if (mappingData.wrapper != null && mappingData.jspWildCard) { + char[] buf = path.getBuffer(); + if (buf[pathEnd - 1] == '/') { + /* + * Path ending in '/' was mapped to JSP servlet based on + * wildcard match (e.g., as specified in url-pattern of a + * jsp-property-group. + * Force the context's welcome files, which are interpreted + * as JSP files (since they match the url-pattern), to be + * considered. See Bugzilla 27664. + */ + mappingData.wrapper = null; + checkJspWelcomeFiles = true; + } else { + // See Bugzilla 27704 + mappingData.wrapperPath.setChars(buf, path.getStart(), + path.getLength()); + mappingData.pathInfo.recycle(); + } + } + } + + if(mappingData.wrapper == null && noServletPath) { + // The path is empty, redirect to "/" + mappingData.redirectPath.setChars + (path.getBuffer(), pathOffset, pathEnd); + path.setEnd(pathEnd - 1); + return; + } + + // Rule 3 -- Extension Match + Wrapper[] extensionWrappers = context.extensionWrappers; + if (mappingData.wrapper == null && !checkJspWelcomeFiles) { + internalMapExtensionWrapper(extensionWrappers, path, mappingData); + } + + // Rule 4 -- Welcome resources processing for servlets + if (mappingData.wrapper == null) { + boolean checkWelcomeFiles = checkJspWelcomeFiles; + if (!checkWelcomeFiles) { + char[] buf = path.getBuffer(); + checkWelcomeFiles = (buf[pathEnd - 1] == '/'); + } + if (checkWelcomeFiles) { + for (int i = 0; (i < context.welcomeResources.length) + && (mappingData.wrapper == null); i++) { + path.setOffset(pathOffset); + path.setEnd(pathEnd); + path.append(context.welcomeResources[i], 0, + context.welcomeResources[i].length()); + path.setOffset(servletPath); + + // Rule 4a -- Welcome resources processing for exact macth + internalMapExactWrapper(exactWrappers, path, mappingData); + + // Rule 4b -- Welcome resources processing for prefix match + if (mappingData.wrapper == null) { + internalMapWildcardWrapper + (wildcardWrappers, context.nesting, + path, mappingData); + } + + // Rule 4c -- Welcome resources processing + // for physical folder + if (mappingData.wrapper == null + && context.resources != null) { + Object file = null; + String pathStr = path.toString(); + try { + file = context.resources.lookup(pathStr); + } catch(NamingException nex) { + // Swallow not found, since this is normal + } + if (file != null && !(file instanceof DirContext) ) { + internalMapExtensionWrapper(extensionWrappers, + path, mappingData); + if (mappingData.wrapper == null + && context.defaultWrapper != null) { + mappingData.wrapper = + context.defaultWrapper.object; + mappingData.requestPath.setChars + (path.getBuffer(), path.getStart(), + path.getLength()); + mappingData.wrapperPath.setChars + (path.getBuffer(), path.getStart(), + path.getLength()); + mappingData.requestPath.setString(pathStr); + mappingData.wrapperPath.setString(pathStr); + } + } + } + } + + path.setOffset(servletPath); + path.setEnd(pathEnd); + } + + } + + + // Rule 7 -- Default servlet + if (mappingData.wrapper == null && !checkJspWelcomeFiles) { + if (context.defaultWrapper != null) { + mappingData.wrapper = context.defaultWrapper.object; + mappingData.requestPath.setChars + (path.getBuffer(), path.getStart(), path.getLength()); + mappingData.wrapperPath.setChars + (path.getBuffer(), path.getStart(), path.getLength()); + } + // Redirection to a folder + char[] buf = path.getBuffer(); + if (context.resources != null && buf[pathEnd -1 ] != '/') { + Object file = null; + String pathStr = path.toString(); + try { + file = context.resources.lookup(pathStr); + } catch(NamingException nex) { + // Swallow, since someone else handles the 404 + } + if (file != null && file instanceof DirContext) { + // Note: this mutates the path: do not do any processing + // after this (since we set the redirectPath, there + // shouldn't be any) + path.setOffset(pathOffset); + path.append('/'); + mappingData.redirectPath.setChars + (path.getBuffer(), path.getStart(), path.getLength()); + } else { + mappingData.requestPath.setString(pathStr); + mappingData.wrapperPath.setString(pathStr); + } + } + } + + path.setOffset(pathOffset); + path.setEnd(pathEnd); + + } + + + /** + * Exact mapping. + */ + private final void internalMapExactWrapper + (Wrapper[] wrappers, CharChunk path, MappingData mappingData) { + int pos = find(wrappers, path); + if ((pos != -1) && (path.equals(wrappers[pos].name))) { + mappingData.requestPath.setString(wrappers[pos].name); + mappingData.wrapperPath.setString(wrappers[pos].name); + mappingData.wrapper = wrappers[pos].object; + } + } + + + /** + * Wildcard mapping. + */ + private final void internalMapWildcardWrapper + (Wrapper[] wrappers, int nesting, CharChunk path, + MappingData mappingData) { + + int pathEnd = path.getEnd(); + int pathOffset = path.getOffset(); + + int lastSlash = -1; + int length = -1; + int pos = find(wrappers, path); + if (pos != -1) { + boolean found = false; + while (pos >= 0) { + if (path.startsWith(wrappers[pos].name)) { + length = wrappers[pos].name.length(); + if (path.getLength() == length) { + found = true; + break; + } else if (path.startsWithIgnoreCase("/", length)) { + found = true; + break; + } + } + if (lastSlash == -1) { + lastSlash = nthSlash(path, nesting + 1); + } else { + lastSlash = lastSlash(path); + } + path.setEnd(lastSlash); + pos = find(wrappers, path); + } + path.setEnd(pathEnd); + if (found) { + mappingData.wrapperPath.setString(wrappers[pos].name); + if (path.getLength() > length) { + mappingData.pathInfo.setChars + (path.getBuffer(), + path.getOffset() + length, + path.getLength() - length); + } + mappingData.requestPath.setChars + (path.getBuffer(), path.getOffset(), path.getLength()); + mappingData.wrapper = wrappers[pos].object; + mappingData.jspWildCard = wrappers[pos].jspWildCard; + } + } + } + + + /** + * Extension mappings. + */ + private final void internalMapExtensionWrapper + (Wrapper[] wrappers, CharChunk path, MappingData mappingData) { + char[] buf = path.getBuffer(); + int pathEnd = path.getEnd(); + int servletPath = path.getOffset(); + int slash = -1; + for (int i = pathEnd - 1; i >= servletPath; i--) { + if (buf[i] == '/') { + slash = i; + break; + } + } + if (slash >= 0) { + int period = -1; + for (int i = pathEnd - 1; i > slash; i--) { + if (buf[i] == '.') { + period = i; + break; + } + } + if (period >= 0) { + path.setOffset(period + 1); + path.setEnd(pathEnd); + int pos = find(wrappers, path); + if ((pos != -1) + && (path.equals(wrappers[pos].name))) { + mappingData.wrapperPath.setChars + (buf, servletPath, pathEnd - servletPath); + mappingData.requestPath.setChars + (buf, servletPath, pathEnd - servletPath); + mappingData.wrapper = wrappers[pos].object; + } + path.setOffset(servletPath); + path.setEnd(pathEnd); + } + } + } + + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int find(MapElement[] map, CharChunk name) { + return find(map, name, name.getStart(), name.getEnd()); + } + + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int find(MapElement[] map, CharChunk name, + int start, int end) { + + int a = 0; + int b = map.length - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + + if (compare(name, start, end, map[0].name) < 0 ) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = compare(name, start, end, map[i].name); + if (result == 1) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = compare(name, start, end, map[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int findIgnoreCase(MapElement[] map, CharChunk name) { + return findIgnoreCase(map, name, name.getStart(), name.getEnd()); + } + + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int findIgnoreCase(MapElement[] map, CharChunk name, + int start, int end) { + + int a = 0; + int b = map.length - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + if (compareIgnoreCase(name, start, end, map[0].name) < 0 ) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = compareIgnoreCase(name, start, end, map[i].name); + if (result == 1) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = compareIgnoreCase(name, start, end, map[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + + /** + * Find a map elemnt given its name in a sorted array of map elements. + * This will return the index for the closest inferior or equal item in the + * given array. + */ + private static final int find(MapElement[] map, String name) { + + int a = 0; + int b = map.length - 1; + + // Special cases: -1 and 0 + if (b == -1) { + return -1; + } + + if (name.compareTo(map[0].name) < 0) { + return -1; + } + if (b == 0) { + return 0; + } + + int i = 0; + while (true) { + i = (b + a) / 2; + int result = name.compareTo(map[i].name); + if (result > 0) { + a = i; + } else if (result == 0) { + return i; + } else { + b = i; + } + if ((b - a) == 1) { + int result2 = name.compareTo(map[b].name); + if (result2 < 0) { + return a; + } else { + return b; + } + } + } + + } + + + /** + * Compare given char chunk with String. + * Return -1, 0 or +1 if inferior, equal, or superior to the String. + */ + private static final int compare(CharChunk name, int start, int end, + String compareTo) { + int result = 0; + char[] c = name.getBuffer(); + int len = compareTo.length(); + if ((end - start) < len) { + len = end - start; + } + for (int i = 0; (i < len) && (result == 0); i++) { + if (c[i + start] > compareTo.charAt(i)) { + result = 1; + } else if (c[i + start] < compareTo.charAt(i)) { + result = -1; + } + } + if (result == 0) { + if (compareTo.length() > (end - start)) { + result = -1; + } else if (compareTo.length() < (end - start)) { + result = 1; + } + } + return result; + } + + + /** + * Compare given char chunk with String ignoring case. + * Return -1, 0 or +1 if inferior, equal, or superior to the String. + */ + private static final int compareIgnoreCase(CharChunk name, int start, int end, + String compareTo) { + int result = 0; + char[] c = name.getBuffer(); + int len = compareTo.length(); + if ((end - start) < len) { + len = end - start; + } + for (int i = 0; (i < len) && (result == 0); i++) { + if (Ascii.toLower(c[i + start]) > Ascii.toLower(compareTo.charAt(i))) { + result = 1; + } else if (Ascii.toLower(c[i + start]) < Ascii.toLower(compareTo.charAt(i))) { + result = -1; + } + } + if (result == 0) { + if (compareTo.length() > (end - start)) { + result = -1; + } else if (compareTo.length() < (end - start)) { + result = 1; + } + } + return result; + } + + + /** + * Find the position of the last slash in the given char chunk. + */ + private static final int lastSlash(CharChunk name) { + + char[] c = name.getBuffer(); + int end = name.getEnd(); + int start = name.getStart(); + int pos = end; + + while (pos > start) { + if (c[--pos] == '/') { + break; + } + } + + return (pos); + + } + + + /** + * Find the position of the nth slash, in the given char chunk. + */ + private static final int nthSlash(CharChunk name, int n) { + + char[] c = name.getBuffer(); + int end = name.getEnd(); + int start = name.getStart(); + int pos = start; + int count = 0; + + while (pos < end) { + if ((c[pos++] == '/') && ((++count) == n)) { + pos--; + break; + } + } + + return (pos); + + } + + + /** + * Return the slash count in a given string. + */ + private static final int slashCount(String name) { + int pos = -1; + int count = 0; + while ((pos = name.indexOf('/', pos + 1)) != -1) { + count++; + } + return count; + } + + + /** + * Insert into the right place in a sorted MapElement array, and prevent + * duplicates. + */ + private static final boolean insertMap + (MapElement[] oldMap, MapElement[] newMap, MapElement newElement) { + int pos = find(oldMap, newElement.name); + if ((pos != -1) && (newElement.name.equals(oldMap[pos].name))) { + return false; + } + System.arraycopy(oldMap, 0, newMap, 0, pos + 1); + newMap[pos + 1] = newElement; + System.arraycopy + (oldMap, pos + 1, newMap, pos + 2, oldMap.length - pos - 1); + return true; + } + + + /** + * Insert into the right place in a sorted MapElement array. + */ + private static final boolean removeMap + (MapElement[] oldMap, MapElement[] newMap, String name) { + int pos = find(oldMap, name); + if ((pos != -1) && (name.equals(oldMap[pos].name))) { + System.arraycopy(oldMap, 0, newMap, 0, pos); + System.arraycopy(oldMap, pos + 1, newMap, pos, + oldMap.length - pos - 1); + return true; + } + return false; + } + + + // ------------------------------------------------- MapElement Inner Class + + + protected static abstract class MapElement { + + public String name = null; + public Object object = null; + + } + + + // ------------------------------------------------------- Host Inner Class + + + protected static final class Host + extends MapElement { + + public ContextList contextList = null; + + } + + + // ------------------------------------------------ ContextList Inner Class + + + protected static final class ContextList { + + public Context[] contexts = new Context[0]; + public int nesting = 0; + + } + + + // ---------------------------------------------------- Context Inner Class + + + protected static final class Context + extends MapElement { + + public String path = null; + public String[] welcomeResources = new String[0]; + public javax.naming.Context resources = null; + public Wrapper defaultWrapper = null; + public Wrapper[] exactWrappers = new Wrapper[0]; + public Wrapper[] wildcardWrappers = new Wrapper[0]; + public Wrapper[] extensionWrappers = new Wrapper[0]; + public int nesting = 0; + + } + + + // ---------------------------------------------------- Wrapper Inner Class + + + protected static class Wrapper + extends MapElement { + + public String path = null; + public boolean jspWildCard = false; + } + + + // -------------------------------------------------------- Testing Methods + + // FIXME: Externalize this + /* + public static void main(String args[]) { + + try { + + Mapper mapper = new Mapper(); + System.out.println("Start"); + + mapper.addHost("sjbjdvwsbvhrb", new String[0], "blah1"); + mapper.addHost("sjbjdvwsbvhr/", new String[0], "blah1"); + mapper.addHost("wekhfewuifweuibf", new String[0], "blah2"); + mapper.addHost("ylwrehirkuewh", new String[0], "blah3"); + mapper.addHost("iohgeoihro", new String[0], "blah4"); + mapper.addHost("fwehoihoihwfeo", new String[0], "blah5"); + mapper.addHost("owefojiwefoi", new String[0], "blah6"); + mapper.addHost("iowejoiejfoiew", new String[0], "blah7"); + mapper.addHost("iowejoiejfoiew", new String[0], "blah17"); + mapper.addHost("ohewoihfewoih", new String[0], "blah8"); + mapper.addHost("fewohfoweoih", new String[0], "blah9"); + mapper.addHost("ttthtiuhwoih", new String[0], "blah10"); + mapper.addHost("lkwefjwojweffewoih", new String[0], "blah11"); + mapper.addHost("zzzuyopjvewpovewjhfewoih", new String[0], "blah12"); + mapper.addHost("xxxxgqwiwoih", new String[0], "blah13"); + mapper.addHost("qwigqwiwoih", new String[0], "blah14"); + + System.out.println("Map:"); + for (int i = 0; i < mapper.hosts.length; i++) { + System.out.println(mapper.hosts[i].name); + } + + mapper.setDefaultHostName("ylwrehirkuewh"); + + String[] welcomes = new String[2]; + welcomes[0] = "boo/baba"; + welcomes[1] = "bobou"; + + mapper.addContext("iowejoiejfoiew", "", "context0", new String[0], null); + mapper.addContext("iowejoiejfoiew", "/foo", "context1", new String[0], null); + mapper.addContext("iowejoiejfoiew", "/foo/bar", "context2", welcomes, null); + mapper.addContext("iowejoiejfoiew", "/foo/bar/bla", "context3", new String[0], null); + + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/fo/*", "wrapper0"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/", "wrapper1"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blh", "wrapper2"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.jsp", "wrapper3"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bou/*", "wrapper4"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "/blah/bobou/*", "wrapper5"); + mapper.addWrapper("iowejoiejfoiew", "/foo/bar", "*.htm", "wrapper6"); + + MappingData mappingData = new MappingData(); + MessageBytes host = MessageBytes.newInstance(); + host.setString("iowejoiejfoiew"); + MessageBytes uri = MessageBytes.newInstance(); + uri.setString("/foo/bar/blah/bobou/foo"); + uri.toChars(); + uri.getCharChunk().setLimit(-1); + + mapper.map(host, uri, mappingData); + System.out.println("MD Host:" + mappingData.host); + System.out.println("MD Context:" + mappingData.context); + System.out.println("MD Wrapper:" + mappingData.wrapper); + + System.out.println("contextPath:" + mappingData.contextPath); + System.out.println("wrapperPath:" + mappingData.wrapperPath); + System.out.println("pathInfo:" + mappingData.pathInfo); + System.out.println("redirectPath:" + mappingData.redirectPath); + + mappingData.recycle(); + mapper.map(host, uri, mappingData); + System.out.println("MD Host:" + mappingData.host); + System.out.println("MD Context:" + mappingData.context); + System.out.println("MD Wrapper:" + mappingData.wrapper); + + System.out.println("contextPath:" + mappingData.contextPath); + System.out.println("wrapperPath:" + mappingData.wrapperPath); + System.out.println("pathInfo:" + mappingData.pathInfo); + System.out.println("redirectPath:" + mappingData.redirectPath); + + for (int i = 0; i < 1000000; i++) { + mappingData.recycle(); + mapper.map(host, uri, mappingData); + } + + long time = System.currentTimeMillis(); + for (int i = 0; i < 1000000; i++) { + mappingData.recycle(); + mapper.map(host, uri, mappingData); + } + System.out.println("Elapsed:" + (System.currentTimeMillis() - time)); + + System.out.println("MD Host:" + mappingData.host); + System.out.println("MD Context:" + mappingData.context); + System.out.println("MD Wrapper:" + mappingData.wrapper); + + System.out.println("contextPath:" + mappingData.contextPath); + System.out.println("wrapperPath:" + mappingData.wrapperPath); + System.out.println("requestPath:" + mappingData.requestPath); + System.out.println("pathInfo:" + mappingData.pathInfo); + System.out.println("redirectPath:" + mappingData.redirectPath); + + } catch (Exception e) { + e.printStackTrace(); + } + + } + */ + + +} diff --git a/java/org/apache/tomcat/util/http/mapper/MappingData.java b/java/org/apache/tomcat/util/http/mapper/MappingData.java index cfec22537..13bf7a439 100644 --- a/java/org/apache/tomcat/util/http/mapper/MappingData.java +++ b/java/org/apache/tomcat/util/http/mapper/MappingData.java @@ -1,52 +1,52 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.http.mapper; - -import org.apache.tomcat.util.buf.MessageBytes; - -/** - * Mapping data. - * - * @author Remy Maucherat - */ -public class MappingData { - - public Object host = null; - public Object context = null; - public Object wrapper = null; - public boolean jspWildCard = false; - - public MessageBytes contextPath = MessageBytes.newInstance(); - public MessageBytes requestPath = MessageBytes.newInstance(); - public MessageBytes wrapperPath = MessageBytes.newInstance(); - public MessageBytes pathInfo = MessageBytes.newInstance(); - - public MessageBytes redirectPath = MessageBytes.newInstance(); - - public void recycle() { - host = null; - context = null; - wrapper = null; - pathInfo.recycle(); - requestPath.recycle(); - wrapperPath.recycle(); - contextPath.recycle(); - redirectPath.recycle(); - jspWildCard = false; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.http.mapper; + +import org.apache.tomcat.util.buf.MessageBytes; + +/** + * Mapping data. + * + * @author Remy Maucherat + */ +public class MappingData { + + public Object host = null; + public Object context = null; + public Object wrapper = null; + public boolean jspWildCard = false; + + public MessageBytes contextPath = MessageBytes.newInstance(); + public MessageBytes requestPath = MessageBytes.newInstance(); + public MessageBytes wrapperPath = MessageBytes.newInstance(); + public MessageBytes pathInfo = MessageBytes.newInstance(); + + public MessageBytes redirectPath = MessageBytes.newInstance(); + + public void recycle() { + host = null; + context = null; + wrapper = null; + pathInfo.recycle(); + requestPath.recycle(); + wrapperPath.recycle(); + contextPath.recycle(); + redirectPath.recycle(); + jspWildCard = false; + } + +} diff --git a/java/org/apache/tomcat/util/http/package.html b/java/org/apache/tomcat/util/http/package.html index 8130a4e96..dd8096066 100644 --- a/java/org/apache/tomcat/util/http/package.html +++ b/java/org/apache/tomcat/util/http/package.html @@ -1,14 +1,14 @@ - - -util.http - - - - -Special utils for handling HTTP-specific entities - headers, parameters, -cookies, etc. - -The utils are not specific to tomcat, but use util.MessageBytes. - - - + + +util.http + + + + +Special utils for handling HTTP-specific entities - headers, parameters, +cookies, etc. + +The utils are not specific to tomcat, but use util.MessageBytes. + + + diff --git a/java/org/apache/tomcat/util/http/res/LocalStrings.properties b/java/org/apache/tomcat/util/http/res/LocalStrings.properties index 8eb9cebb2..2ec1364d1 100644 --- a/java/org/apache/tomcat/util/http/res/LocalStrings.properties +++ b/java/org/apache/tomcat/util/http/res/LocalStrings.properties @@ -1,46 +1,46 @@ -# HttpMessages -sc.100=Continue -sc.101=Switching Protocols -sc.200=OK -sc.201=Created -sc.202=Accepted -sc.203=Non-Authoritative Information -sc.204=No Content -sc.205=Reset Content -sc.206=Partial Content -sc.207=Multi-Status -sc.300=Multiple Choices -sc.301=Moved Permanently -sc.302=Moved Temporarily -sc.303=See Other -sc.304=Not Modified -sc.305=Use Proxy -sc.307=Temporary Redirect -sc.400=Bad Request -sc.401=Unauthorized -sc.402=Payment Required -sc.403=Forbidden -sc.404=Not Found -sc.405=Method Not Allowed -sc.406=Not Acceptable -sc.407=Proxy Authentication Required -sc.408=Request Timeout -sc.409=Conflict -sc.410=Gone -sc.411=Length Required -sc.412=Precondition Failed -sc.413=Request Entity Too Large -sc.414=Request-URI Too Long -sc.415=Unsupported Media Type -sc.416=Requested Range Not Satisfiable -sc.417=Expectation Failed -sc.422=Unprocessable Entity -sc.423=Locked -sc.424=Failed Dependency -sc.500=Internal Server Error -sc.501=Not Implemented -sc.502=Bad Gateway -sc.503=Service Unavailable -sc.504=Gateway Timeout -sc.505=HTTP Version Not Supported -sc.507=Insufficient Storage +# HttpMessages +sc.100=Continue +sc.101=Switching Protocols +sc.200=OK +sc.201=Created +sc.202=Accepted +sc.203=Non-Authoritative Information +sc.204=No Content +sc.205=Reset Content +sc.206=Partial Content +sc.207=Multi-Status +sc.300=Multiple Choices +sc.301=Moved Permanently +sc.302=Moved Temporarily +sc.303=See Other +sc.304=Not Modified +sc.305=Use Proxy +sc.307=Temporary Redirect +sc.400=Bad Request +sc.401=Unauthorized +sc.402=Payment Required +sc.403=Forbidden +sc.404=Not Found +sc.405=Method Not Allowed +sc.406=Not Acceptable +sc.407=Proxy Authentication Required +sc.408=Request Timeout +sc.409=Conflict +sc.410=Gone +sc.411=Length Required +sc.412=Precondition Failed +sc.413=Request Entity Too Large +sc.414=Request-URI Too Long +sc.415=Unsupported Media Type +sc.416=Requested Range Not Satisfiable +sc.417=Expectation Failed +sc.422=Unprocessable Entity +sc.423=Locked +sc.424=Failed Dependency +sc.500=Internal Server Error +sc.501=Not Implemented +sc.502=Bad Gateway +sc.503=Service Unavailable +sc.504=Gateway Timeout +sc.505=HTTP Version Not Supported +sc.507=Insufficient Storage diff --git a/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties b/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties index 44dbb0cb8..03312fdee 100644 --- a/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties +++ b/java/org/apache/tomcat/util/http/res/LocalStrings_es.properties @@ -1,47 +1,47 @@ -# HttpMessages -sc.100=Continuar -sc.101=Cambiando Protocolos -sc.200=OK -sc.201=Creado -sc.202=Aceptado -sc.203=Información No-Autorizativa -sc.204=Sin Contenido -sc.205=Reset Contenido -sc.206=Contenido Parcial -sc.207=Multi-Estado -sc.300=Múltiples Elecciones -sc.301=Movido permanentemente -sc.302=Movido temporálmente -sc.303=Mirar Otro -sc.304=No Modificado -sc.305=Usar Proxy -sc.307=Redirección Temporal -sc.400=Petición incorrecta -sc.401=No Autorizado -sc.402=Pago requerido -sc.403=Prohibido -sc.404=No Encontrado -sc.405=Método No Permitido -sc.406=No Aceptable -sc.407=Autentificación Proxy Requerida -sc.408=Request Caducada -sc.409=Conflicto -sc.410=Ido -sc.411=Longitud Requerida -sc.412=Precondición Fallada -sc.413=Entidad de Request Demasiado Grande -sc.414=Request-URI Demasiado Larga -sc.415=Tipo de Medio No Soportado -sc.416=El Rango Pedido No Ser Satisfecho -sc.417=Expectativa Fallada -sc.422=Entidad Improcesable -sc.423=Bloqueado -sc.424=Dependencia Fallida -sc.500=Error Interno del Servidor -sc.501=No Implementado -sc.502=Pasarela Incorrecta -sc.503=Servicio no Disponible -sc.504=Pasarela Caducada -sc.505=Versión de HTTP No Soportada -sc.507=Almacenaje Insuficiente - +# HttpMessages +sc.100=Continuar +sc.101=Cambiando Protocolos +sc.200=OK +sc.201=Creado +sc.202=Aceptado +sc.203=Información No-Autorizativa +sc.204=Sin Contenido +sc.205=Reset Contenido +sc.206=Contenido Parcial +sc.207=Multi-Estado +sc.300=Múltiples Elecciones +sc.301=Movido permanentemente +sc.302=Movido temporálmente +sc.303=Mirar Otro +sc.304=No Modificado +sc.305=Usar Proxy +sc.307=Redirección Temporal +sc.400=Petición incorrecta +sc.401=No Autorizado +sc.402=Pago requerido +sc.403=Prohibido +sc.404=No Encontrado +sc.405=Método No Permitido +sc.406=No Aceptable +sc.407=Autentificación Proxy Requerida +sc.408=Request Caducada +sc.409=Conflicto +sc.410=Ido +sc.411=Longitud Requerida +sc.412=Precondición Fallada +sc.413=Entidad de Request Demasiado Grande +sc.414=Request-URI Demasiado Larga +sc.415=Tipo de Medio No Soportado +sc.416=El Rango Pedido No Ser Satisfecho +sc.417=Expectativa Fallada +sc.422=Entidad Improcesable +sc.423=Bloqueado +sc.424=Dependencia Fallida +sc.500=Error Interno del Servidor +sc.501=No Implementado +sc.502=Pasarela Incorrecta +sc.503=Servicio no Disponible +sc.504=Pasarela Caducada +sc.505=Versión de HTTP No Soportada +sc.507=Almacenaje Insuficiente + diff --git a/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties b/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties index 2c6f876a8..61399c982 100644 --- a/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties +++ b/java/org/apache/tomcat/util/http/res/LocalStrings_fr.properties @@ -1,44 +1,44 @@ -sc.100=Continuer -sc.101=Changement de Protocols -sc.200=OK -sc.201=Crée -sc.202=Accepté -sc.203=Information Sans-Autorité -sc.204=Pas de Contenu -sc.205=Remise à Zéro de Contenu -sc.206=Contenu Partiel -sc.207=Etat Multiple -sc.300=Choix Multiples -sc.301=Déplacé de façon Permanente -sc.302=Déplacé Temporairement -sc.303=Voir Autre -sc.304=Non Modifié -sc.305=Utilisation de Relais -sc.307=Redirection Temporaire -sc.400=Mauvaise Requête -sc.401=Non-Autorisé -sc.402=Paiement Nécessaire -sc.403=Interdit -sc.404=Introuvable -sc.405=Méthode Non Autorisée -sc.406=Inacceptable -sc.407=Authentification de Relais Nécessaire -sc.408=Dépassement de Délais pour la Requête -sc.409=Conflit -sc.410=Parti -sc.411=Taille Demandée -sc.412=Echec de Pré-condition -sc.413=Entité de Requête Trop Grande -sc.414=URI de Requête Trop Grande -sc.415=Type de Support Non Supporté -sc.416=Etendue de Requête Irréalisable -sc.417=Echec d'Attente -sc.422=Entité Ingérable -sc.424=Echec de Dépendance -sc.500=Erreur Interne de Servlet -sc.501=Non Implémenté -sc.502=Mauvaise Passerelle -sc.503=Service Indisponible -sc.504=Dépassement de Délais pour la Passerelle -sc.505=Version HTTP Non Supportée -sc.507=Stockage Insuffisant +sc.100=Continuer +sc.101=Changement de Protocols +sc.200=OK +sc.201=Crée +sc.202=Accepté +sc.203=Information Sans-Autorité +sc.204=Pas de Contenu +sc.205=Remise à Zéro de Contenu +sc.206=Contenu Partiel +sc.207=Etat Multiple +sc.300=Choix Multiples +sc.301=Déplacé de façon Permanente +sc.302=Déplacé Temporairement +sc.303=Voir Autre +sc.304=Non Modifié +sc.305=Utilisation de Relais +sc.307=Redirection Temporaire +sc.400=Mauvaise Requête +sc.401=Non-Autorisé +sc.402=Paiement Nécessaire +sc.403=Interdit +sc.404=Introuvable +sc.405=Méthode Non Autorisée +sc.406=Inacceptable +sc.407=Authentification de Relais Nécessaire +sc.408=Dépassement de Délais pour la Requête +sc.409=Conflit +sc.410=Parti +sc.411=Taille Demandée +sc.412=Echec de Pré-condition +sc.413=Entité de Requête Trop Grande +sc.414=URI de Requête Trop Grande +sc.415=Type de Support Non Supporté +sc.416=Etendue de Requête Irréalisable +sc.417=Echec d'Attente +sc.422=Entité Ingérable +sc.424=Echec de Dépendance +sc.500=Erreur Interne de Servlet +sc.501=Non Implémenté +sc.502=Mauvaise Passerelle +sc.503=Service Indisponible +sc.504=Dépassement de Délais pour la Passerelle +sc.505=Version HTTP Non Supportée +sc.507=Stockage Insuffisant diff --git a/java/org/apache/tomcat/util/log/CaptureLog.java b/java/org/apache/tomcat/util/log/CaptureLog.java index b1e0f679d..51dfee7dc 100644 --- a/java/org/apache/tomcat/util/log/CaptureLog.java +++ b/java/org/apache/tomcat/util/log/CaptureLog.java @@ -1,49 +1,49 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.log; - -import java.io.ByteArrayOutputStream; -import java.io.PrintStream; - -/** - * Per Thread System.err and System.out log capture data. - * - * @author Glenn L. Nielsen - */ - -class CaptureLog { - - protected CaptureLog() { - baos = new ByteArrayOutputStream(); - ps = new PrintStream(baos); - } - - private ByteArrayOutputStream baos; - private PrintStream ps; - - protected PrintStream getStream() { - return ps; - } - - protected void reset() { - baos.reset(); - } - - protected String getCapture() { - return baos.toString(); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.log; + +import java.io.ByteArrayOutputStream; +import java.io.PrintStream; + +/** + * Per Thread System.err and System.out log capture data. + * + * @author Glenn L. Nielsen + */ + +class CaptureLog { + + protected CaptureLog() { + baos = new ByteArrayOutputStream(); + ps = new PrintStream(baos); + } + + private ByteArrayOutputStream baos; + private PrintStream ps; + + protected PrintStream getStream() { + return ps; + } + + protected void reset() { + baos.reset(); + } + + protected String getCapture() { + return baos.toString(); + } +} diff --git a/java/org/apache/tomcat/util/log/SystemLogHandler.java b/java/org/apache/tomcat/util/log/SystemLogHandler.java index 4f05c74d9..255aacfd9 100644 --- a/java/org/apache/tomcat/util/log/SystemLogHandler.java +++ b/java/org/apache/tomcat/util/log/SystemLogHandler.java @@ -1,244 +1,244 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.log; - -import java.io.IOException; -import java.io.PrintStream; -import java.util.EmptyStackException; -import java.util.Stack; - -/** - * This helper class may be used to do sophisticated redirection of - * System.out and System.err on a per Thread basis. - * - * A stack is implemented per Thread so that nested startCapture - * and stopCapture can be used. - * - * @author Remy Maucherat - * @author Glenn L. Nielsen - */ -public class SystemLogHandler extends PrintStream { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct the handler to capture the output of the given steam. - */ - public SystemLogHandler(PrintStream wrapped) { - super(wrapped); - out = wrapped; - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * Wrapped PrintStream. - */ - protected PrintStream out = null; - - - /** - * Thread <-> CaptureLog associations. - */ - protected static ThreadLocal logs = new ThreadLocal(); - - - /** - * Spare CaptureLog ready for reuse. - */ - protected static Stack reuse = new Stack(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Start capturing thread's output. - */ - public static void startCapture() { - CaptureLog log = null; - if (!reuse.isEmpty()) { - try { - log = (CaptureLog)reuse.pop(); - } catch (EmptyStackException e) { - log = new CaptureLog(); - } - } else { - log = new CaptureLog(); - } - Stack stack = (Stack)logs.get(); - if (stack == null) { - stack = new Stack(); - logs.set(stack); - } - stack.push(log); - } - - - /** - * Stop capturing thread's output and return captured data as a String. - */ - public static String stopCapture() { - Stack stack = (Stack)logs.get(); - if (stack == null || stack.isEmpty()) { - return null; - } - CaptureLog log = (CaptureLog)stack.pop(); - if (log == null) { - return null; - } - String capture = log.getCapture(); - log.reset(); - reuse.push(log); - return capture; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Find PrintStream to which the output must be written to. - */ - protected PrintStream findStream() { - Stack stack = (Stack)logs.get(); - if (stack != null && !stack.isEmpty()) { - CaptureLog log = (CaptureLog)stack.peek(); - if (log != null) { - PrintStream ps = log.getStream(); - if (ps != null) { - return ps; - } - } - } - return out; - } - - - // ---------------------------------------------------- PrintStream Methods - - - public void flush() { - findStream().flush(); - } - - public void close() { - findStream().close(); - } - - public boolean checkError() { - return findStream().checkError(); - } - - protected void setError() { - //findStream().setError(); - } - - public void write(int b) { - findStream().write(b); - } - - public void write(byte[] b) - throws IOException { - findStream().write(b); - } - - public void write(byte[] buf, int off, int len) { - findStream().write(buf, off, len); - } - - public void print(boolean b) { - findStream().print(b); - } - - public void print(char c) { - findStream().print(c); - } - - public void print(int i) { - findStream().print(i); - } - - public void print(long l) { - findStream().print(l); - } - - public void print(float f) { - findStream().print(f); - } - - public void print(double d) { - findStream().print(d); - } - - public void print(char[] s) { - findStream().print(s); - } - - public void print(String s) { - findStream().print(s); - } - - public void print(Object obj) { - findStream().print(obj); - } - - public void println() { - findStream().println(); - } - - public void println(boolean x) { - findStream().println(x); - } - - public void println(char x) { - findStream().println(x); - } - - public void println(int x) { - findStream().println(x); - } - - public void println(long x) { - findStream().println(x); - } - - public void println(float x) { - findStream().println(x); - } - - public void println(double x) { - findStream().println(x); - } - - public void println(char[] x) { - findStream().println(x); - } - - public void println(String x) { - findStream().println(x); - } - - public void println(Object x) { - findStream().println(x); - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.log; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.EmptyStackException; +import java.util.Stack; + +/** + * This helper class may be used to do sophisticated redirection of + * System.out and System.err on a per Thread basis. + * + * A stack is implemented per Thread so that nested startCapture + * and stopCapture can be used. + * + * @author Remy Maucherat + * @author Glenn L. Nielsen + */ +public class SystemLogHandler extends PrintStream { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct the handler to capture the output of the given steam. + */ + public SystemLogHandler(PrintStream wrapped) { + super(wrapped); + out = wrapped; + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * Wrapped PrintStream. + */ + protected PrintStream out = null; + + + /** + * Thread <-> CaptureLog associations. + */ + protected static ThreadLocal logs = new ThreadLocal(); + + + /** + * Spare CaptureLog ready for reuse. + */ + protected static Stack reuse = new Stack(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Start capturing thread's output. + */ + public static void startCapture() { + CaptureLog log = null; + if (!reuse.isEmpty()) { + try { + log = (CaptureLog)reuse.pop(); + } catch (EmptyStackException e) { + log = new CaptureLog(); + } + } else { + log = new CaptureLog(); + } + Stack stack = (Stack)logs.get(); + if (stack == null) { + stack = new Stack(); + logs.set(stack); + } + stack.push(log); + } + + + /** + * Stop capturing thread's output and return captured data as a String. + */ + public static String stopCapture() { + Stack stack = (Stack)logs.get(); + if (stack == null || stack.isEmpty()) { + return null; + } + CaptureLog log = (CaptureLog)stack.pop(); + if (log == null) { + return null; + } + String capture = log.getCapture(); + log.reset(); + reuse.push(log); + return capture; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Find PrintStream to which the output must be written to. + */ + protected PrintStream findStream() { + Stack stack = (Stack)logs.get(); + if (stack != null && !stack.isEmpty()) { + CaptureLog log = (CaptureLog)stack.peek(); + if (log != null) { + PrintStream ps = log.getStream(); + if (ps != null) { + return ps; + } + } + } + return out; + } + + + // ---------------------------------------------------- PrintStream Methods + + + public void flush() { + findStream().flush(); + } + + public void close() { + findStream().close(); + } + + public boolean checkError() { + return findStream().checkError(); + } + + protected void setError() { + //findStream().setError(); + } + + public void write(int b) { + findStream().write(b); + } + + public void write(byte[] b) + throws IOException { + findStream().write(b); + } + + public void write(byte[] buf, int off, int len) { + findStream().write(buf, off, len); + } + + public void print(boolean b) { + findStream().print(b); + } + + public void print(char c) { + findStream().print(c); + } + + public void print(int i) { + findStream().print(i); + } + + public void print(long l) { + findStream().print(l); + } + + public void print(float f) { + findStream().print(f); + } + + public void print(double d) { + findStream().print(d); + } + + public void print(char[] s) { + findStream().print(s); + } + + public void print(String s) { + findStream().print(s); + } + + public void print(Object obj) { + findStream().print(obj); + } + + public void println() { + findStream().println(); + } + + public void println(boolean x) { + findStream().println(x); + } + + public void println(char x) { + findStream().println(x); + } + + public void println(int x) { + findStream().println(x); + } + + public void println(long x) { + findStream().println(x); + } + + public void println(float x) { + findStream().println(x); + } + + public void println(double x) { + findStream().println(x); + } + + public void println(char[] x) { + findStream().println(x); + } + + public void println(String x) { + findStream().println(x); + } + + public void println(Object x) { + findStream().println(x); + } + +} diff --git a/java/org/apache/tomcat/util/modeler/AttributeInfo.java b/java/org/apache/tomcat/util/modeler/AttributeInfo.java index b69c4e53f..8bd35adb4 100644 --- a/java/org/apache/tomcat/util/modeler/AttributeInfo.java +++ b/java/org/apache/tomcat/util/modeler/AttributeInfo.java @@ -1,163 +1,163 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.Serializable; - -import javax.management.MBeanAttributeInfo; - - -/** - *

        Internal configuration information for an Attribute - * descriptor.

        - * - * @author Craig R. McClanahan - */ -public class AttributeInfo extends FeatureInfo implements Serializable { - static final long serialVersionUID = -2511626862303972143L; - - // ----------------------------------------------------- Instance Variables - protected String displayName = null; - - // Information about the method to use - protected String getMethod = null; - protected String setMethod = null; - protected boolean readable = true; - protected boolean writeable = true; - protected boolean is = false; - - // ------------------------------------------------------------- Properties - - /** - * The display name of this attribute. - */ - public String getDisplayName() { - return (this.displayName); - } - - public void setDisplayName(String displayName) { - this.displayName = displayName; - } - - /** - * The name of the property getter method, if non-standard. - */ - public String getGetMethod() { - if(getMethod == null) - getMethod = getMethodName(getName(), true, isIs()); - return (this.getMethod); - } - - public void setGetMethod(String getMethod) { - this.getMethod = getMethod; - } - - /** - * Is this a boolean attribute with an "is" getter? - */ - public boolean isIs() { - return (this.is); - } - - public void setIs(boolean is) { - this.is = is; - } - - - /** - * Is this attribute readable by management applications? - */ - public boolean isReadable() { - return (this.readable); - } - - public void setReadable(boolean readable) { - this.readable = readable; - } - - - /** - * The name of the property setter method, if non-standard. - */ - public String getSetMethod() { - if( setMethod == null ) - setMethod = getMethodName(getName(), false, false); - return (this.setMethod); - } - - public void setSetMethod(String setMethod) { - this.setMethod = setMethod; - } - - /** - * Is this attribute writeable by management applications? - */ - public boolean isWriteable() { - return (this.writeable); - } - - public void setWriteable(boolean writeable) { - this.writeable = writeable; - } - - // --------------------------------------------------------- Public Methods - - - /** - * Create and return a ModelMBeanAttributeInfo object that - * corresponds to the attribute described by this instance. - */ - MBeanAttributeInfo createAttributeInfo() { - // Return our cached information (if any) - if (info == null) { - info = new MBeanAttributeInfo(getName(), getType(), getDescription(), - isReadable(), isWriteable(), false); - } - return (MBeanAttributeInfo)info; - } - - // -------------------------------------------------------- Private Methods - - - /** - * Create and return the name of a default property getter or setter - * method, according to the specified values. - * - * @param name Name of the property itself - * @param getter Do we want a get method (versus a set method)? - * @param is If returning a getter, do we want the "is" form? - */ - private String getMethodName(String name, boolean getter, boolean is) { - - StringBuffer sb = new StringBuffer(); - if (getter) { - if (is) - sb.append("is"); - else - sb.append("get"); - } else - sb.append("set"); - sb.append(Character.toUpperCase(name.charAt(0))); - sb.append(name.substring(1)); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanAttributeInfo; + + +/** + *

        Internal configuration information for an Attribute + * descriptor.

        + * + * @author Craig R. McClanahan + */ +public class AttributeInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = -2511626862303972143L; + + // ----------------------------------------------------- Instance Variables + protected String displayName = null; + + // Information about the method to use + protected String getMethod = null; + protected String setMethod = null; + protected boolean readable = true; + protected boolean writeable = true; + protected boolean is = false; + + // ------------------------------------------------------------- Properties + + /** + * The display name of this attribute. + */ + public String getDisplayName() { + return (this.displayName); + } + + public void setDisplayName(String displayName) { + this.displayName = displayName; + } + + /** + * The name of the property getter method, if non-standard. + */ + public String getGetMethod() { + if(getMethod == null) + getMethod = getMethodName(getName(), true, isIs()); + return (this.getMethod); + } + + public void setGetMethod(String getMethod) { + this.getMethod = getMethod; + } + + /** + * Is this a boolean attribute with an "is" getter? + */ + public boolean isIs() { + return (this.is); + } + + public void setIs(boolean is) { + this.is = is; + } + + + /** + * Is this attribute readable by management applications? + */ + public boolean isReadable() { + return (this.readable); + } + + public void setReadable(boolean readable) { + this.readable = readable; + } + + + /** + * The name of the property setter method, if non-standard. + */ + public String getSetMethod() { + if( setMethod == null ) + setMethod = getMethodName(getName(), false, false); + return (this.setMethod); + } + + public void setSetMethod(String setMethod) { + this.setMethod = setMethod; + } + + /** + * Is this attribute writeable by management applications? + */ + public boolean isWriteable() { + return (this.writeable); + } + + public void setWriteable(boolean writeable) { + this.writeable = writeable; + } + + // --------------------------------------------------------- Public Methods + + + /** + * Create and return a ModelMBeanAttributeInfo object that + * corresponds to the attribute described by this instance. + */ + MBeanAttributeInfo createAttributeInfo() { + // Return our cached information (if any) + if (info == null) { + info = new MBeanAttributeInfo(getName(), getType(), getDescription(), + isReadable(), isWriteable(), false); + } + return (MBeanAttributeInfo)info; + } + + // -------------------------------------------------------- Private Methods + + + /** + * Create and return the name of a default property getter or setter + * method, according to the specified values. + * + * @param name Name of the property itself + * @param getter Do we want a get method (versus a set method)? + * @param is If returning a getter, do we want the "is" form? + */ + private String getMethodName(String name, boolean getter, boolean is) { + + StringBuffer sb = new StringBuffer(); + if (getter) { + if (is) + sb.append("is"); + else + sb.append("get"); + } else + sb.append("set"); + sb.append(Character.toUpperCase(name.charAt(0))); + sb.append(name.substring(1)); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java b/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java index 0701f6c70..c23a41d4b 100644 --- a/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java +++ b/java/org/apache/tomcat/util/modeler/BaseAttributeFilter.java @@ -1,159 +1,159 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.util.HashSet; - -import javax.management.AttributeChangeNotification; -import javax.management.Notification; -import javax.management.NotificationFilter; - - -/** - *

        Implementation of NotificationFilter for attribute change - * notifications. This class is used by BaseModelMBean to - * construct attribute change notification event filters when a filter is not - * supplied by the application.

        - * - * @author Craig R. McClanahan - * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ - */ - -public class BaseAttributeFilter implements NotificationFilter { - - - // ----------------------------------------------------------- Constructors - - - /** - * Construct a new filter that accepts only the specified attribute - * name. - * - * @param name Name of the attribute to be accepted by this filter, or - * null to accept all attribute names - */ - public BaseAttributeFilter(String name) { - - super(); - if (name != null) - addAttribute(name); - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of attribute names that are accepted by this filter. If this - * list is empty, all attribute names are accepted. - */ - private HashSet names = new HashSet(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new attribute name to the set of names accepted by this filter. - * - * @param name Name of the attribute to be accepted - */ - public void addAttribute(String name) { - - synchronized (names) { - names.add(name); - } - - } - - - /** - * Clear all accepted names from this filter, so that it will accept - * all attribute names. - */ - public void clear() { - - synchronized (names) { - names.clear(); - } - - } - - - /** - * Return the set of names that are accepted by this filter. If this - * filter accepts all attribute names, a zero length array will be - * returned. - */ - public String[] getNames() { - - synchronized (names) { - return ((String[]) names.toArray(new String[names.size()])); - } - - } - - - /** - *

        Test whether notification enabled for this event. - * Return true if:

        - *
          - *
        • This is an attribute change notification
        • - *
        • Either the set of accepted names is empty (implying that all - * attribute names are of interest) or the set of accepted names - * includes the name of the attribute in this notification
        • - *
        - */ - public boolean isNotificationEnabled(Notification notification) { - - if (notification == null) - return (false); - if (!(notification instanceof AttributeChangeNotification)) - return (false); - AttributeChangeNotification acn = - (AttributeChangeNotification) notification; - if (!AttributeChangeNotification.ATTRIBUTE_CHANGE.equals(acn.getType())) - return (false); - synchronized (names) { - if (names.size() < 1) - return (true); - else - return (names.contains(acn.getAttributeName())); - } - - } - - - /** - * Remove an attribute name from the set of names accepted by this - * filter. - * - * @param name Name of the attribute to be removed - */ - public void removeAttribute(String name) { - - synchronized (names) { - names.remove(name); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.util.HashSet; + +import javax.management.AttributeChangeNotification; +import javax.management.Notification; +import javax.management.NotificationFilter; + + +/** + *

        Implementation of NotificationFilter for attribute change + * notifications. This class is used by BaseModelMBean to + * construct attribute change notification event filters when a filter is not + * supplied by the application.

        + * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class BaseAttributeFilter implements NotificationFilter { + + + // ----------------------------------------------------------- Constructors + + + /** + * Construct a new filter that accepts only the specified attribute + * name. + * + * @param name Name of the attribute to be accepted by this filter, or + * null to accept all attribute names + */ + public BaseAttributeFilter(String name) { + + super(); + if (name != null) + addAttribute(name); + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of attribute names that are accepted by this filter. If this + * list is empty, all attribute names are accepted. + */ + private HashSet names = new HashSet(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new attribute name to the set of names accepted by this filter. + * + * @param name Name of the attribute to be accepted + */ + public void addAttribute(String name) { + + synchronized (names) { + names.add(name); + } + + } + + + /** + * Clear all accepted names from this filter, so that it will accept + * all attribute names. + */ + public void clear() { + + synchronized (names) { + names.clear(); + } + + } + + + /** + * Return the set of names that are accepted by this filter. If this + * filter accepts all attribute names, a zero length array will be + * returned. + */ + public String[] getNames() { + + synchronized (names) { + return ((String[]) names.toArray(new String[names.size()])); + } + + } + + + /** + *

        Test whether notification enabled for this event. + * Return true if:

        + *
          + *
        • This is an attribute change notification
        • + *
        • Either the set of accepted names is empty (implying that all + * attribute names are of interest) or the set of accepted names + * includes the name of the attribute in this notification
        • + *
        + */ + public boolean isNotificationEnabled(Notification notification) { + + if (notification == null) + return (false); + if (!(notification instanceof AttributeChangeNotification)) + return (false); + AttributeChangeNotification acn = + (AttributeChangeNotification) notification; + if (!AttributeChangeNotification.ATTRIBUTE_CHANGE.equals(acn.getType())) + return (false); + synchronized (names) { + if (names.size() < 1) + return (true); + else + return (names.contains(acn.getAttributeName())); + } + + } + + + /** + * Remove an attribute name from the set of names accepted by this + * filter. + * + * @param name Name of the attribute to be removed + */ + public void removeAttribute(String name) { + + synchronized (names) { + names.remove(name); + } + + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/BaseModelMBean.java b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java index 28b8c9c8b..f5284e5e7 100644 --- a/java/org/apache/tomcat/util/modeler/BaseModelMBean.java +++ b/java/org/apache/tomcat/util/modeler/BaseModelMBean.java @@ -1,1174 +1,1174 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.Iterator; - -import javax.management.Attribute; -import javax.management.AttributeChangeNotification; -import javax.management.AttributeList; -import javax.management.AttributeNotFoundException; -import javax.management.DynamicMBean; -import javax.management.InstanceNotFoundException; -import javax.management.InvalidAttributeValueException; -import javax.management.ListenerNotFoundException; -import javax.management.MBeanException; -import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.Notification; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.ReflectionException; -import javax.management.RuntimeErrorException; -import javax.management.RuntimeOperationsException; -import javax.management.modelmbean.InvalidTargetObjectTypeException; -import javax.management.modelmbean.ModelMBeanNotificationBroadcaster; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/* - * Changes from commons.modeler: - * - * - use DynamicMBean - * - remove methods not used in tomcat and redundant/not very generic - * - must be created from the ManagedBean - I don't think there were any direct - * uses, but now it is required. - * - some of the gratuituous flexibility removed - instead this is more predictive and - * strict with the use cases. - * - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act - * like Object and Class. - * - setModelMBean is no longer called on resources ( not used in tomcat ) - * - no caching of Methods for now - operations and setters are not called repeatedly in most - * management use cases. Getters should't be called very frequently either - and even if they - * are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ). - * We can add getter cache if needed. - * - removed unused constructor, fields - * - * TODO: - * - clean up catalina.mbeans, stop using weird inheritance - */ - -/** - *

        Basic implementation of the DynamicMBean interface, which - * supports the minimal requirements of the interface contract.

        - * - *

        This can be used directly to wrap an existing java bean, or inside - * an mlet or anywhere an MBean would be used. - * - * Limitations: - *

          - *
        • Only managed resources of type objectReference are - * supportd.
        • - *
        • Caching of attribute values and operation results is not supported. - * All calls to invoke() are immediately executed.
        • - *
        • Persistence of MBean attributes and operations is not supported.
        • - *
        • All classes referenced as attribute types, operation parameters, or - * operation return values must be one of the following: - *
            - *
          • One of the Java primitive types (boolean, byte, char, double, - * float, integer, long, short). Corresponding value will be wrapped - * in the appropriate wrapper class automatically.
          • - *
          • Operations that return no value should declare a return type of - * void.
          • - *
          - *
        • Attribute caching is not supported
        • - *
        - * - * @author Craig R. McClanahan - * @author Costin Manolache - */ -public class BaseModelMBean implements DynamicMBean, MBeanRegistration, ModelMBeanNotificationBroadcaster { - private static Log log = LogFactory.getLog(BaseModelMBean.class); - - // ----------------------------------------------------------- Constructors - - /** - * Construct a ModelMBean with default - * ModelMBeanInfo information. - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception RuntimeOperationsException if an IllegalArgumentException - * occurs - */ - protected BaseModelMBean() throws MBeanException, RuntimeOperationsException { - super(); - } - - // ----------------------------------------------------- Instance Variables - - protected ObjectName oname=null; - - /** - * Notification broadcaster for attribute changes. - */ - protected BaseNotificationBroadcaster attributeBroadcaster = null; - - /** - * Notification broadcaster for general notifications. - */ - protected BaseNotificationBroadcaster generalBroadcaster = null; - - /** Metadata for the mbean instance. - */ - protected ManagedBean managedBean = null; - - /** - * The managed resource this MBean is associated with (if any). - */ - protected Object resource = null; - - // --------------------------------------------------- DynamicMBean Methods - // TODO: move to ManagedBean - static final Object[] NO_ARGS_PARAM=new Object[0]; - static final Class[] NO_ARGS_PARAM_SIG=new Class[0]; - - protected String resourceType = null; - - // key: operation val: invoke method - //private Hashtable invokeAttMap=new Hashtable(); - - /** - * Obtain and return the value of a specific attribute of this MBean. - * - * @param name Name of the requested attribute - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public Object getAttribute(String name) - throws AttributeNotFoundException, MBeanException, - ReflectionException { - // Validate the input parameters - if (name == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute name is null"), - "Attribute name is null"); - - if( (resource instanceof DynamicMBean) && - ! ( resource instanceof BaseModelMBean )) { - return ((DynamicMBean)resource).getAttribute(name); - } - - Method m=managedBean.getGetter(name, this, resource); - Object result = null; - try { - Class declaring=m.getDeclaringClass(); - // workaround for catalina weird mbeans - the declaring class is BaseModelMBean. - // but this is the catalina class. - if( declaring.isAssignableFrom(this.getClass()) ) { - result = m.invoke(this, NO_ARGS_PARAM ); - } else { - result = m.invoke(resource, NO_ARGS_PARAM ); - } - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - if (t == null) - t = e; - if (t instanceof RuntimeException) - throw new RuntimeOperationsException - ((RuntimeException) t, "Exception invoking method " + name); - else if (t instanceof Error) - throw new RuntimeErrorException - ((Error) t, "Error invoking method " + name); - else - throw new MBeanException - (e, "Exception invoking method " + name); - } catch (Exception e) { - throw new MBeanException - (e, "Exception invoking method " + name); - } - - // Return the results of this method invocation - // FIXME - should we validate the return type? - return (result); - } - - - /** - * Obtain and return the values of several attributes of this MBean. - * - * @param names Names of the requested attributes - */ - public AttributeList getAttributes(String names[]) { - - // Validate the input parameters - if (names == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute names list is null"), - "Attribute names list is null"); - - // Prepare our response, eating all exceptions - AttributeList response = new AttributeList(); - for (int i = 0; i < names.length; i++) { - try { - response.add(new Attribute(names[i],getAttribute(names[i]))); - } catch (Exception e) { - ; // Not having a particular attribute in the response - ; // is the indication of a getter problem - } - } - return (response); - - } - - public void setManagedBean(ManagedBean managedBean) { - this.managedBean = managedBean; - } - - /** - * Return the MBeanInfo object for this MBean. - */ - public MBeanInfo getMBeanInfo() { - return managedBean.getMBeanInfo(); - } - - - /** - * Invoke a particular method on this MBean, and return any returned - * value. - * - *

        IMPLEMENTATION NOTE - This implementation will - * attempt to invoke this method on the MBean itself, or (if not - * available) on the managed resource object associated with this - * MBean.

        - * - * @param name Name of the operation to be invoked - * @param params Array containing the method parameters of this operation - * @param signature Array containing the class names representing - * the signature of this operation - * - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectioNException if a Java reflection exception - * occurs when invoking a method - */ - public Object invoke(String name, Object params[], String signature[]) - throws MBeanException, ReflectionException - { - if( (resource instanceof DynamicMBean) && - ! ( resource instanceof BaseModelMBean )) { - return ((DynamicMBean)resource).invoke(name, params, signature); - } - - // Validate the input parameters - if (name == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Method name is null"), - "Method name is null"); - - if( log.isDebugEnabled()) log.debug("Invoke " + name); - MethodKey mkey = new MethodKey(name, signature); - Method method= managedBean.getInvoke(name, params, signature, this, resource); - - // Invoke the selected method on the appropriate object - Object result = null; - try { - if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) { - result = method.invoke(this, params ); - } else { - result = method.invoke(resource, params); - } - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - log.error("Exception invoking method " + name , t ); - if (t == null) - t = e; - if (t instanceof RuntimeException) - throw new RuntimeOperationsException - ((RuntimeException) t, "Exception invoking method " + name); - else if (t instanceof Error) - throw new RuntimeErrorException - ((Error) t, "Error invoking method " + name); - else - throw new MBeanException - ((Exception)t, "Exception invoking method " + name); - } catch (Exception e) { - log.error("Exception invoking method " + name , e ); - throw new MBeanException - (e, "Exception invoking method " + name); - } - - // Return the results of this method invocation - // FIXME - should we validate the return type? - return (result); - - } - - static Class getAttributeClass(String signature) - throws ReflectionException - { - if (signature.equals(Boolean.TYPE.getName())) - return Boolean.TYPE; - else if (signature.equals(Byte.TYPE.getName())) - return Byte.TYPE; - else if (signature.equals(Character.TYPE.getName())) - return Character.TYPE; - else if (signature.equals(Double.TYPE.getName())) - return Double.TYPE; - else if (signature.equals(Float.TYPE.getName())) - return Float.TYPE; - else if (signature.equals(Integer.TYPE.getName())) - return Integer.TYPE; - else if (signature.equals(Long.TYPE.getName())) - return Long.TYPE; - else if (signature.equals(Short.TYPE.getName())) - return Short.TYPE; - else { - try { - ClassLoader cl=Thread.currentThread().getContextClassLoader(); - if( cl!=null ) - return cl.loadClass(signature); - } catch( ClassNotFoundException e ) { - } - try { - return Class.forName(signature); - } catch (ClassNotFoundException e) { - throw new ReflectionException - (e, "Cannot find Class for " + signature); - } - } - } - - /** - * Set the value of a specific attribute of this MBean. - * - * @param attribute The identification of the attribute to be set - * and the new value - * - * @exception AttributeNotFoundException if this attribute is not - * supported by this MBean - * @exception MBeanException if the initializer of an object - * throws an exception - * @exception ReflectionException if a Java reflection exception - * occurs when invoking the getter - */ - public void setAttribute(Attribute attribute) - throws AttributeNotFoundException, MBeanException, - ReflectionException - { - if( log.isDebugEnabled() ) - log.debug("Setting attribute " + this + " " + attribute ); - - if( (resource instanceof DynamicMBean) && - ! ( resource instanceof BaseModelMBean )) { - try { - ((DynamicMBean)resource).setAttribute(attribute); - } catch (InvalidAttributeValueException e) { - throw new MBeanException(e); - } - return; - } - - // Validate the input parameters - if (attribute == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute is null"), - "Attribute is null"); - - String name = attribute.getName(); - Object value = attribute.getValue(); - - if (name == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Attribute name is null"), - "Attribute name is null"); - - Object oldValue=null; - //if( getAttMap.get(name) != null ) - // oldValue=getAttribute( name ); - - Method m=managedBean.getSetter(name,this,resource); - - try { - if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) { - m.invoke(this, new Object[] { value }); - } else { - m.invoke(resource, new Object[] { value }); - } - } catch (InvocationTargetException e) { - Throwable t = e.getTargetException(); - if (t == null) - t = e; - if (t instanceof RuntimeException) - throw new RuntimeOperationsException - ((RuntimeException) t, "Exception invoking method " + name); - else if (t instanceof Error) - throw new RuntimeErrorException - ((Error) t, "Error invoking method " + name); - else - throw new MBeanException - (e, "Exception invoking method " + name); - } catch (Exception e) { - log.error("Exception invoking method " + name , e ); - throw new MBeanException - (e, "Exception invoking method " + name); - } - try { - sendAttributeChangeNotification(new Attribute( name, oldValue), - attribute); - } catch(Exception ex) { - log.error("Error sending notification " + name, ex); - } - //attributes.put( name, value ); -// if( source != null ) { -// // this mbean is asscoiated with a source - maybe we want to persist -// source.updateField(oname, name, value); -// } - } - - public String toString() { - if( resource==null ) - return "BaseModelMbean[" + resourceType + "]"; - return resource.toString(); - } - - /** - * Set the values of several attributes of this MBean. - * - * @param attributes THe names and values to be set - * - * @return The list of attributes that were set and their new values - */ - public AttributeList setAttributes(AttributeList attributes) { - AttributeList response = new AttributeList(); - - // Validate the input parameters - if (attributes == null) - return response; - - // Prepare and return our response, eating all exceptions - String names[] = new String[attributes.size()]; - int n = 0; - Iterator items = attributes.iterator(); - while (items.hasNext()) { - Attribute item = (Attribute) items.next(); - names[n++] = item.getName(); - try { - setAttribute(item); - } catch (Exception e) { - ; // Ignore all exceptions - } - } - - return (getAttributes(names)); - - } - - - // ----------------------------------------------------- ModelMBean Methods - - - /** - * Get the instance handle of the object against which we execute - * all methods in this ModelMBean management interface. - * - * @exception InstanceNotFoundException if the managed resource object - * cannot be found - * @exception MBeanException if the initializer of the object throws - * an exception - * @exception RuntimeOperationsException if the managed resource or the - * resource type is null or invalid - */ - public Object getManagedResource() - throws InstanceNotFoundException, InvalidTargetObjectTypeException, - MBeanException, RuntimeOperationsException { - - if (resource == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Managed resource is null"), - "Managed resource is null"); - - return resource; - - } - - - /** - * Set the instance handle of the object against which we will execute - * all methods in this ModelMBean management interface. - * - * This method will detect and call "setModelMbean" method. A resource - * can implement this method to get a reference to the model mbean. - * The reference can be used to send notification and access the - * registry. - * The caller can provide the mbean instance or the object name to - * the resource, if needed. - * - * @param resource The resource object to be managed - * @param type The type of reference for the managed resource - * ("ObjectReference", "Handle", "IOR", "EJBHandle", or - * "RMIReference") - * - * @exception InstanceNotFoundException if the managed resource object - * cannot be found - * @exception InvalidTargetObjectTypeException if this ModelMBean is - * asked to handle a reference type it cannot deal with - * @exception MBeanException if the initializer of the object throws - * an exception - * @exception RuntimeOperationsException if the managed resource or the - * resource type is null or invalid - */ - public void setManagedResource(Object resource, String type) - throws InstanceNotFoundException, - MBeanException, RuntimeOperationsException - { - if (resource == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Managed resource is null"), - "Managed resource is null"); - -// if (!"objectreference".equalsIgnoreCase(type)) -// throw new InvalidTargetObjectTypeException(type); - - this.resource = resource; - this.resourceType = resource.getClass().getName(); - -// // Make the resource aware of the model mbean. -// try { -// Method m=resource.getClass().getMethod("setModelMBean", -// new Class[] {ModelMBean.class}); -// if( m!= null ) { -// m.invoke(resource, new Object[] {this}); -// } -// } catch( NoSuchMethodException t ) { -// // ignore -// } catch( Throwable t ) { -// log.error( "Can't set model mbean ", t ); -// } - } - - - // ------------------------------ ModelMBeanNotificationBroadcaster Methods - - - /** - * Add an attribute change notification event listener to this MBean. - * - * @param listener Listener that will receive event notifications - * @param name Name of the attribute of interest, or null - * to indicate interest in all attributes - * @param handback Handback object to be sent along with event - * notifications - * - * @exception IllegalArgumentException if the listener parameter is null - */ - public void addAttributeChangeNotificationListener - (NotificationListener listener, String name, Object handback) - throws IllegalArgumentException { - - if (listener == null) - throw new IllegalArgumentException("Listener is null"); - if (attributeBroadcaster == null) - attributeBroadcaster = new BaseNotificationBroadcaster(); - - if( log.isDebugEnabled() ) - log.debug("addAttributeNotificationListener " + listener); - - BaseAttributeFilter filter = new BaseAttributeFilter(name); - attributeBroadcaster.addNotificationListener - (listener, filter, handback); - - } - - - /** - * Remove an attribute change notification event listener from - * this MBean. - * - * @param listener The listener to be removed - * @param name The attribute name for which no more events are required - * - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeAttributeChangeNotificationListener - (NotificationListener listener, String name) - throws ListenerNotFoundException { - - if (listener == null) - throw new IllegalArgumentException("Listener is null"); - if (attributeBroadcaster == null) - attributeBroadcaster = new BaseNotificationBroadcaster(); - - // FIXME - currently this removes *all* notifications for this listener - attributeBroadcaster.removeNotificationListener(listener); - - } - - - /** - * Remove an attribute change notification event listener from - * this MBean. - * - * @param listener The listener to be removed - * @param attributeName The attribute name for which no more events are required - * @param handback Handback object to be sent along with event - * notifications - * - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeAttributeChangeNotificationListener - (NotificationListener listener, String attributeName, Object handback) - throws ListenerNotFoundException { - - removeAttributeChangeNotificationListener(listener, attributeName); - - } - - - /** - * Send an AttributeChangeNotification to all registered - * listeners. - * - * @param notification The AttributeChangeNotification - * that will be passed - * - * @exception MBeanException if an object initializer throws an - * exception - * @exception RuntimeOperationsException wraps IllegalArgumentException - * when the specified notification is null or invalid - */ - public void sendAttributeChangeNotification - (AttributeChangeNotification notification) - throws MBeanException, RuntimeOperationsException { - - if (notification == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Notification is null"), - "Notification is null"); - if (attributeBroadcaster == null) - return; // This means there are no registered listeners - if( log.isDebugEnabled() ) - log.debug( "AttributeChangeNotification " + notification ); - attributeBroadcaster.sendNotification(notification); - - } - - - /** - * Send an AttributeChangeNotification to all registered - * listeners. - * - * @param oldValue The original value of the Attribute - * @param newValue The new value of the Attribute - * - * @exception MBeanException if an object initializer throws an - * exception - * @exception RuntimeOperationsException wraps IllegalArgumentException - * when the specified notification is null or invalid - */ - public void sendAttributeChangeNotification - (Attribute oldValue, Attribute newValue) - throws MBeanException, RuntimeOperationsException { - - // Calculate the class name for the change notification - String type = null; - if (newValue.getValue() != null) - type = newValue.getValue().getClass().getName(); - else if (oldValue.getValue() != null) - type = oldValue.getValue().getClass().getName(); - else - return; // Old and new are both null == no change - - AttributeChangeNotification notification = - new AttributeChangeNotification - (this, 1, System.currentTimeMillis(), - "Attribute value has changed", - oldValue.getName(), type, - oldValue.getValue(), newValue.getValue()); - sendAttributeChangeNotification(notification); - - } - - - - - /** - * Send a Notification to all registered listeners as a - * jmx.modelmbean.general notification. - * - * @param notification The Notification that will be passed - * - * @exception MBeanException if an object initializer throws an - * exception - * @exception RuntimeOperationsException wraps IllegalArgumentException - * when the specified notification is null or invalid - */ - public void sendNotification(Notification notification) - throws MBeanException, RuntimeOperationsException { - - if (notification == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Notification is null"), - "Notification is null"); - if (generalBroadcaster == null) - return; // This means there are no registered listeners - generalBroadcaster.sendNotification(notification); - - } - - - /** - * Send a Notification which contains the specified string - * as a jmx.modelmbean.generic notification. - * - * @param message The message string to be passed - * - * @exception MBeanException if an object initializer throws an - * exception - * @exception RuntimeOperationsException wraps IllegalArgumentException - * when the specified notification is null or invalid - */ - public void sendNotification(String message) - throws MBeanException, RuntimeOperationsException { - - if (message == null) - throw new RuntimeOperationsException - (new IllegalArgumentException("Message is null"), - "Message is null"); - Notification notification = new Notification - ("jmx.modelmbean.generic", this, 1, message); - sendNotification(notification); - - } - - - - - // ---------------------------------------- NotificationBroadcaster Methods - - - /** - * Add a notification event listener to this MBean. - * - * @param listener Listener that will receive event notifications - * @param filter Filter object used to filter event notifications - * actually delivered, or null for no filtering - * @param handback Handback object to be sent along with event - * notifications - * - * @exception IllegalArgumentException if the listener parameter is null - */ - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws IllegalArgumentException { - - if (listener == null) - throw new IllegalArgumentException("Listener is null"); - - if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener); - - if (generalBroadcaster == null) - generalBroadcaster = new BaseNotificationBroadcaster(); - generalBroadcaster.addNotificationListener - (listener, filter, handback); - - // We'll send the attribute change notifications to all listeners ( who care ) - // The normal filtering can be used. - // The problem is that there is no other way to add attribute change listeners - // to a model mbean ( AFAIK ). I suppose the spec should be fixed. - if (attributeBroadcaster == null) - attributeBroadcaster = new BaseNotificationBroadcaster(); - - if( log.isDebugEnabled() ) - log.debug("addAttributeNotificationListener " + listener); - - attributeBroadcaster.addNotificationListener - (listener, filter, handback); - } - - - /** - * Return an MBeanNotificationInfo object describing the - * notifications sent by this MBean. - */ - public MBeanNotificationInfo[] getNotificationInfo() { - - // Acquire the set of application notifications - MBeanNotificationInfo current[] = getMBeanInfo().getNotifications(); - if (current == null) - current = new MBeanNotificationInfo[0]; - MBeanNotificationInfo response[] = - new MBeanNotificationInfo[current.length + 2]; - // Descriptor descriptor = null; - - // Fill in entry for general notifications -// descriptor = new DescriptorSupport -// (new String[] { "name=GENERIC", -// "descriptorType=notification", -// "log=T", -// "severity=5", -// "displayName=jmx.modelmbean.generic" }); - response[0] = new MBeanNotificationInfo - (new String[] { "jmx.modelmbean.generic" }, - "GENERIC", - "Text message notification from the managed resource"); - //descriptor); - - // Fill in entry for attribute change notifications -// descriptor = new DescriptorSupport -// (new String[] { "name=ATTRIBUTE_CHANGE", -// "descriptorType=notification", -// "log=T", -// "severity=5", -// "displayName=jmx.attribute.change" }); - response[1] = new MBeanNotificationInfo - (new String[] { "jmx.attribute.change" }, - "ATTRIBUTE_CHANGE", - "Observed MBean attribute value has changed"); - //descriptor); - - // Copy remaining notifications as reported by the application - System.arraycopy(current, 0, response, 2, current.length); - return (response); - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException { - - if (listener == null) - throw new IllegalArgumentException("Listener is null"); - if (generalBroadcaster == null) - generalBroadcaster = new BaseNotificationBroadcaster(); - generalBroadcaster.removeNotificationListener(listener); - - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * @param handback Handback object to be sent along with event - * notifications - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener, - Object handback) - throws ListenerNotFoundException { - - removeNotificationListener(listener); - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * @param filter Filter object used to filter event notifications - * actually delivered, or null for no filtering - * @param handback Handback object to be sent along with event - * notifications - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws ListenerNotFoundException { - - removeNotificationListener(listener); - - } - - - // ------------------------------------------------ PersistentMBean Methods - - - /** - * Instantiates this MBean instance from data found in the persistent - * store. The data loaded could include attribute and operation values. - * This method should be called during construction or initialization - * of the instance, and before the MBean is registered with the - * MBeanServer. - * - *

        IMPLEMENTATION NOTE - This implementation does - * not support persistence.

        - * - * @exception InstanceNotFoundException if the managed resource object - * cannot be found - * @exception MBeanException if the initializer of the object throws - * an exception - * @exception RuntimeOperationsException if an exception is reported - * by the persistence mechanism - */ -// public void load() throws InstanceNotFoundException, -// MBeanException, RuntimeOperationsException { -// // XXX If a context was set, use it to load the data -// throw new MBeanException -// (new IllegalStateException("Persistence is not supported"), -// "Persistence is not supported"); -// -// } - - - /** - * Capture the current state of this MBean instance and write it out - * to the persistent store. The state stored could include attribute - * and operation values. If one of these methods of persistence is not - * supported, a "service not found" exception will be thrown. - * - *

        IMPLEMENTATION NOTE - This implementation does - * not support persistence.

        - * - * @exception InstanceNotFoundException if the managed resource object - * cannot be found - * @exception MBeanException if the initializer of the object throws - * an exception, or persistence is not supported - * @exception RuntimeOperationsException if an exception is reported - * by the persistence mechanism - */ -// public void store() throws InstanceNotFoundException, -// MBeanException, RuntimeOperationsException { -// -// // XXX if a context was set, use it to store the data -// throw new MBeanException -// (new IllegalStateException("Persistence is not supported"), -// "Persistence is not supported"); -// -// } - - // -------------------- BaseModelMBean methods -------------------- - - /** Set the type of the mbean. This is used as a key to locate - * the description in the Registry. - * - * @param type the type of classname of the modeled object - */ -// void setModeledType( String type ) { -// initModelInfo(type); -// createResource(); -// } - /** Set the type of the mbean. This is used as a key to locate - * the description in the Registry. - * - * @param type the type of classname of the modeled object - */ -// void initModelInfo( String type ) { -// try { -// if( log.isDebugEnabled()) -// log.debug("setModeledType " + type); -// -// log.debug( "Set model Info " + type); -// if(type==null) { -// return; -// } -// resourceType=type; -// //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); -// Class c=null; -// try { -// c=Class.forName( type); -// } catch( Throwable t ) { -// log.debug( "Error creating class " + t); -// } -// -// // The class c doesn't need to exist -// ManagedBean descriptor=getRegistry().findManagedBean(c, type); -// if( descriptor==null ) -// return; -// this.setModelMBeanInfo(descriptor.createMBeanInfo()); -// } catch( Throwable ex) { -// log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), -// ex); -// } -// } - - /** Set the type of the mbean. This is used as a key to locate - * the description in the Registry. - */ -// protected void createResource() { -// try { -// //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); -// Class c=null; -// try { -// c=Class.forName( resourceType ); -// resource = c.newInstance(); -// } catch( Throwable t ) { -// log.error( "Error creating class " + t); -// } -// } catch( Throwable ex) { -// log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), -// ex); -// } -// } - - - public String getModelerType() { - return resourceType; - } - - public String getClassName() { - return getModelerType(); - } - - public ObjectName getJmxName() { - return oname; - } - - public String getObjectName() { - if (oname != null) { - return oname.toString(); - } else { - return null; - } - } - -// public void setRegistry(Registry registry) { -// this.registry = registry; -// } -// -// public Registry getRegistry() { -// // XXX Need a better solution - to avoid the static -// if( registry == null ) -// registry=Registry.getRegistry(); -// -// return registry; -// } - - // ------------------------------------------------------ Protected Methods - - - /** - * Create and return a default ModelMBeanInfo object. - */ -// protected ModelMBeanInfo createDefaultModelMBeanInfo() { -// -// return (new ModelMBeanInfoSupport(this.getClass().getName(), -// "Default ModelMBean", -// null, null, null, null)); -// -// } - - /** - * Is the specified ModelMBeanInfo instance valid? - * - *

        IMPLEMENTATION NOTE - This implementation - * does not check anything, but this method can be overridden - * as required.

        - * - * @param info The ModelMBeanInfo object to check - */ -// protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) { -// return (true); -// } - - // -------------------- Registration -------------------- - // XXX We can add some method patterns here- like setName() and - // setDomain() for code that doesn't implement the Registration - - public ObjectName preRegister(MBeanServer server, - ObjectName name) - throws Exception - { - if( log.isDebugEnabled()) - log.debug("preRegister " + resource + " " + name ); - oname=name; - if( resource instanceof MBeanRegistration ) { - oname = ((MBeanRegistration)resource).preRegister(server, name ); - } - return oname; - } - - public void postRegister(Boolean registrationDone) { - if( resource instanceof MBeanRegistration ) { - ((MBeanRegistration)resource).postRegister(registrationDone); - } - } - - public void preDeregister() throws Exception { - if( resource instanceof MBeanRegistration ) { - ((MBeanRegistration)resource).preDeregister(); - } - } - - public void postDeregister() { - if( resource instanceof MBeanRegistration ) { - ((MBeanRegistration)resource).postDeregister(); - } - } - - static class MethodKey { - private String name; - private String[] signature; - - MethodKey(String name, String[] signature) { - this.name = name; - if(signature == null) { - signature = new String[0]; - } - this.signature = signature; - } - - public boolean equals(Object other) { - if(!(other instanceof MethodKey)) { - return false; - } - MethodKey omk = (MethodKey)other; - if(!name.equals(omk.name)) { - return false; - } - if(signature.length != omk.signature.length) { - return false; - } - for(int i=0; i < signature.length; i++) { - if(!signature[i].equals(omk.signature[i])) { - return false; - } - } - return true; - } - - public int hashCode() { - return name.hashCode(); - } - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Iterator; + +import javax.management.Attribute; +import javax.management.AttributeChangeNotification; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.Notification; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.management.RuntimeErrorException; +import javax.management.RuntimeOperationsException; +import javax.management.modelmbean.InvalidTargetObjectTypeException; +import javax.management.modelmbean.ModelMBeanNotificationBroadcaster; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/* + * Changes from commons.modeler: + * + * - use DynamicMBean + * - remove methods not used in tomcat and redundant/not very generic + * - must be created from the ManagedBean - I don't think there were any direct + * uses, but now it is required. + * - some of the gratuituous flexibility removed - instead this is more predictive and + * strict with the use cases. + * - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act + * like Object and Class. + * - setModelMBean is no longer called on resources ( not used in tomcat ) + * - no caching of Methods for now - operations and setters are not called repeatedly in most + * management use cases. Getters should't be called very frequently either - and even if they + * are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ). + * We can add getter cache if needed. + * - removed unused constructor, fields + * + * TODO: + * - clean up catalina.mbeans, stop using weird inheritance + */ + +/** + *

        Basic implementation of the DynamicMBean interface, which + * supports the minimal requirements of the interface contract.

        + * + *

        This can be used directly to wrap an existing java bean, or inside + * an mlet or anywhere an MBean would be used. + * + * Limitations: + *

          + *
        • Only managed resources of type objectReference are + * supportd.
        • + *
        • Caching of attribute values and operation results is not supported. + * All calls to invoke() are immediately executed.
        • + *
        • Persistence of MBean attributes and operations is not supported.
        • + *
        • All classes referenced as attribute types, operation parameters, or + * operation return values must be one of the following: + *
            + *
          • One of the Java primitive types (boolean, byte, char, double, + * float, integer, long, short). Corresponding value will be wrapped + * in the appropriate wrapper class automatically.
          • + *
          • Operations that return no value should declare a return type of + * void.
          • + *
          + *
        • Attribute caching is not supported
        • + *
        + * + * @author Craig R. McClanahan + * @author Costin Manolache + */ +public class BaseModelMBean implements DynamicMBean, MBeanRegistration, ModelMBeanNotificationBroadcaster { + private static Log log = LogFactory.getLog(BaseModelMBean.class); + + // ----------------------------------------------------------- Constructors + + /** + * Construct a ModelMBean with default + * ModelMBeanInfo information. + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception RuntimeOperationsException if an IllegalArgumentException + * occurs + */ + protected BaseModelMBean() throws MBeanException, RuntimeOperationsException { + super(); + } + + // ----------------------------------------------------- Instance Variables + + protected ObjectName oname=null; + + /** + * Notification broadcaster for attribute changes. + */ + protected BaseNotificationBroadcaster attributeBroadcaster = null; + + /** + * Notification broadcaster for general notifications. + */ + protected BaseNotificationBroadcaster generalBroadcaster = null; + + /** Metadata for the mbean instance. + */ + protected ManagedBean managedBean = null; + + /** + * The managed resource this MBean is associated with (if any). + */ + protected Object resource = null; + + // --------------------------------------------------- DynamicMBean Methods + // TODO: move to ManagedBean + static final Object[] NO_ARGS_PARAM=new Object[0]; + static final Class[] NO_ARGS_PARAM_SIG=new Class[0]; + + protected String resourceType = null; + + // key: operation val: invoke method + //private Hashtable invokeAttMap=new Hashtable(); + + /** + * Obtain and return the value of a specific attribute of this MBean. + * + * @param name Name of the requested attribute + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public Object getAttribute(String name) + throws AttributeNotFoundException, MBeanException, + ReflectionException { + // Validate the input parameters + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute name is null"), + "Attribute name is null"); + + if( (resource instanceof DynamicMBean) && + ! ( resource instanceof BaseModelMBean )) { + return ((DynamicMBean)resource).getAttribute(name); + } + + Method m=managedBean.getGetter(name, this, resource); + Object result = null; + try { + Class declaring=m.getDeclaringClass(); + // workaround for catalina weird mbeans - the declaring class is BaseModelMBean. + // but this is the catalina class. + if( declaring.isAssignableFrom(this.getClass()) ) { + result = m.invoke(this, NO_ARGS_PARAM ); + } else { + result = m.invoke(resource, NO_ARGS_PARAM ); + } + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t == null) + t = e; + if (t instanceof RuntimeException) + throw new RuntimeOperationsException + ((RuntimeException) t, "Exception invoking method " + name); + else if (t instanceof Error) + throw new RuntimeErrorException + ((Error) t, "Error invoking method " + name); + else + throw new MBeanException + (e, "Exception invoking method " + name); + } catch (Exception e) { + throw new MBeanException + (e, "Exception invoking method " + name); + } + + // Return the results of this method invocation + // FIXME - should we validate the return type? + return (result); + } + + + /** + * Obtain and return the values of several attributes of this MBean. + * + * @param names Names of the requested attributes + */ + public AttributeList getAttributes(String names[]) { + + // Validate the input parameters + if (names == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute names list is null"), + "Attribute names list is null"); + + // Prepare our response, eating all exceptions + AttributeList response = new AttributeList(); + for (int i = 0; i < names.length; i++) { + try { + response.add(new Attribute(names[i],getAttribute(names[i]))); + } catch (Exception e) { + ; // Not having a particular attribute in the response + ; // is the indication of a getter problem + } + } + return (response); + + } + + public void setManagedBean(ManagedBean managedBean) { + this.managedBean = managedBean; + } + + /** + * Return the MBeanInfo object for this MBean. + */ + public MBeanInfo getMBeanInfo() { + return managedBean.getMBeanInfo(); + } + + + /** + * Invoke a particular method on this MBean, and return any returned + * value. + * + *

        IMPLEMENTATION NOTE - This implementation will + * attempt to invoke this method on the MBean itself, or (if not + * available) on the managed resource object associated with this + * MBean.

        + * + * @param name Name of the operation to be invoked + * @param params Array containing the method parameters of this operation + * @param signature Array containing the class names representing + * the signature of this operation + * + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectioNException if a Java reflection exception + * occurs when invoking a method + */ + public Object invoke(String name, Object params[], String signature[]) + throws MBeanException, ReflectionException + { + if( (resource instanceof DynamicMBean) && + ! ( resource instanceof BaseModelMBean )) { + return ((DynamicMBean)resource).invoke(name, params, signature); + } + + // Validate the input parameters + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Method name is null"), + "Method name is null"); + + if( log.isDebugEnabled()) log.debug("Invoke " + name); + MethodKey mkey = new MethodKey(name, signature); + Method method= managedBean.getInvoke(name, params, signature, this, resource); + + // Invoke the selected method on the appropriate object + Object result = null; + try { + if( method.getDeclaringClass().isAssignableFrom( this.getClass()) ) { + result = method.invoke(this, params ); + } else { + result = method.invoke(resource, params); + } + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + log.error("Exception invoking method " + name , t ); + if (t == null) + t = e; + if (t instanceof RuntimeException) + throw new RuntimeOperationsException + ((RuntimeException) t, "Exception invoking method " + name); + else if (t instanceof Error) + throw new RuntimeErrorException + ((Error) t, "Error invoking method " + name); + else + throw new MBeanException + ((Exception)t, "Exception invoking method " + name); + } catch (Exception e) { + log.error("Exception invoking method " + name , e ); + throw new MBeanException + (e, "Exception invoking method " + name); + } + + // Return the results of this method invocation + // FIXME - should we validate the return type? + return (result); + + } + + static Class getAttributeClass(String signature) + throws ReflectionException + { + if (signature.equals(Boolean.TYPE.getName())) + return Boolean.TYPE; + else if (signature.equals(Byte.TYPE.getName())) + return Byte.TYPE; + else if (signature.equals(Character.TYPE.getName())) + return Character.TYPE; + else if (signature.equals(Double.TYPE.getName())) + return Double.TYPE; + else if (signature.equals(Float.TYPE.getName())) + return Float.TYPE; + else if (signature.equals(Integer.TYPE.getName())) + return Integer.TYPE; + else if (signature.equals(Long.TYPE.getName())) + return Long.TYPE; + else if (signature.equals(Short.TYPE.getName())) + return Short.TYPE; + else { + try { + ClassLoader cl=Thread.currentThread().getContextClassLoader(); + if( cl!=null ) + return cl.loadClass(signature); + } catch( ClassNotFoundException e ) { + } + try { + return Class.forName(signature); + } catch (ClassNotFoundException e) { + throw new ReflectionException + (e, "Cannot find Class for " + signature); + } + } + } + + /** + * Set the value of a specific attribute of this MBean. + * + * @param attribute The identification of the attribute to be set + * and the new value + * + * @exception AttributeNotFoundException if this attribute is not + * supported by this MBean + * @exception MBeanException if the initializer of an object + * throws an exception + * @exception ReflectionException if a Java reflection exception + * occurs when invoking the getter + */ + public void setAttribute(Attribute attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException + { + if( log.isDebugEnabled() ) + log.debug("Setting attribute " + this + " " + attribute ); + + if( (resource instanceof DynamicMBean) && + ! ( resource instanceof BaseModelMBean )) { + try { + ((DynamicMBean)resource).setAttribute(attribute); + } catch (InvalidAttributeValueException e) { + throw new MBeanException(e); + } + return; + } + + // Validate the input parameters + if (attribute == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute is null"), + "Attribute is null"); + + String name = attribute.getName(); + Object value = attribute.getValue(); + + if (name == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Attribute name is null"), + "Attribute name is null"); + + Object oldValue=null; + //if( getAttMap.get(name) != null ) + // oldValue=getAttribute( name ); + + Method m=managedBean.getSetter(name,this,resource); + + try { + if( m.getDeclaringClass().isAssignableFrom( this.getClass()) ) { + m.invoke(this, new Object[] { value }); + } else { + m.invoke(resource, new Object[] { value }); + } + } catch (InvocationTargetException e) { + Throwable t = e.getTargetException(); + if (t == null) + t = e; + if (t instanceof RuntimeException) + throw new RuntimeOperationsException + ((RuntimeException) t, "Exception invoking method " + name); + else if (t instanceof Error) + throw new RuntimeErrorException + ((Error) t, "Error invoking method " + name); + else + throw new MBeanException + (e, "Exception invoking method " + name); + } catch (Exception e) { + log.error("Exception invoking method " + name , e ); + throw new MBeanException + (e, "Exception invoking method " + name); + } + try { + sendAttributeChangeNotification(new Attribute( name, oldValue), + attribute); + } catch(Exception ex) { + log.error("Error sending notification " + name, ex); + } + //attributes.put( name, value ); +// if( source != null ) { +// // this mbean is asscoiated with a source - maybe we want to persist +// source.updateField(oname, name, value); +// } + } + + public String toString() { + if( resource==null ) + return "BaseModelMbean[" + resourceType + "]"; + return resource.toString(); + } + + /** + * Set the values of several attributes of this MBean. + * + * @param attributes THe names and values to be set + * + * @return The list of attributes that were set and their new values + */ + public AttributeList setAttributes(AttributeList attributes) { + AttributeList response = new AttributeList(); + + // Validate the input parameters + if (attributes == null) + return response; + + // Prepare and return our response, eating all exceptions + String names[] = new String[attributes.size()]; + int n = 0; + Iterator items = attributes.iterator(); + while (items.hasNext()) { + Attribute item = (Attribute) items.next(); + names[n++] = item.getName(); + try { + setAttribute(item); + } catch (Exception e) { + ; // Ignore all exceptions + } + } + + return (getAttributes(names)); + + } + + + // ----------------------------------------------------- ModelMBean Methods + + + /** + * Get the instance handle of the object against which we execute + * all methods in this ModelMBean management interface. + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception + * @exception RuntimeOperationsException if the managed resource or the + * resource type is null or invalid + */ + public Object getManagedResource() + throws InstanceNotFoundException, InvalidTargetObjectTypeException, + MBeanException, RuntimeOperationsException { + + if (resource == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Managed resource is null"), + "Managed resource is null"); + + return resource; + + } + + + /** + * Set the instance handle of the object against which we will execute + * all methods in this ModelMBean management interface. + * + * This method will detect and call "setModelMbean" method. A resource + * can implement this method to get a reference to the model mbean. + * The reference can be used to send notification and access the + * registry. + * The caller can provide the mbean instance or the object name to + * the resource, if needed. + * + * @param resource The resource object to be managed + * @param type The type of reference for the managed resource + * ("ObjectReference", "Handle", "IOR", "EJBHandle", or + * "RMIReference") + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception InvalidTargetObjectTypeException if this ModelMBean is + * asked to handle a reference type it cannot deal with + * @exception MBeanException if the initializer of the object throws + * an exception + * @exception RuntimeOperationsException if the managed resource or the + * resource type is null or invalid + */ + public void setManagedResource(Object resource, String type) + throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException + { + if (resource == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Managed resource is null"), + "Managed resource is null"); + +// if (!"objectreference".equalsIgnoreCase(type)) +// throw new InvalidTargetObjectTypeException(type); + + this.resource = resource; + this.resourceType = resource.getClass().getName(); + +// // Make the resource aware of the model mbean. +// try { +// Method m=resource.getClass().getMethod("setModelMBean", +// new Class[] {ModelMBean.class}); +// if( m!= null ) { +// m.invoke(resource, new Object[] {this}); +// } +// } catch( NoSuchMethodException t ) { +// // ignore +// } catch( Throwable t ) { +// log.error( "Can't set model mbean ", t ); +// } + } + + + // ------------------------------ ModelMBeanNotificationBroadcaster Methods + + + /** + * Add an attribute change notification event listener to this MBean. + * + * @param listener Listener that will receive event notifications + * @param name Name of the attribute of interest, or null + * to indicate interest in all attributes + * @param handback Handback object to be sent along with event + * notifications + * + * @exception IllegalArgumentException if the listener parameter is null + */ + public void addAttributeChangeNotificationListener + (NotificationListener listener, String name, Object handback) + throws IllegalArgumentException { + + if (listener == null) + throw new IllegalArgumentException("Listener is null"); + if (attributeBroadcaster == null) + attributeBroadcaster = new BaseNotificationBroadcaster(); + + if( log.isDebugEnabled() ) + log.debug("addAttributeNotificationListener " + listener); + + BaseAttributeFilter filter = new BaseAttributeFilter(name); + attributeBroadcaster.addNotificationListener + (listener, filter, handback); + + } + + + /** + * Remove an attribute change notification event listener from + * this MBean. + * + * @param listener The listener to be removed + * @param name The attribute name for which no more events are required + * + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeAttributeChangeNotificationListener + (NotificationListener listener, String name) + throws ListenerNotFoundException { + + if (listener == null) + throw new IllegalArgumentException("Listener is null"); + if (attributeBroadcaster == null) + attributeBroadcaster = new BaseNotificationBroadcaster(); + + // FIXME - currently this removes *all* notifications for this listener + attributeBroadcaster.removeNotificationListener(listener); + + } + + + /** + * Remove an attribute change notification event listener from + * this MBean. + * + * @param listener The listener to be removed + * @param attributeName The attribute name for which no more events are required + * @param handback Handback object to be sent along with event + * notifications + * + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeAttributeChangeNotificationListener + (NotificationListener listener, String attributeName, Object handback) + throws ListenerNotFoundException { + + removeAttributeChangeNotificationListener(listener, attributeName); + + } + + + /** + * Send an AttributeChangeNotification to all registered + * listeners. + * + * @param notification The AttributeChangeNotification + * that will be passed + * + * @exception MBeanException if an object initializer throws an + * exception + * @exception RuntimeOperationsException wraps IllegalArgumentException + * when the specified notification is null or invalid + */ + public void sendAttributeChangeNotification + (AttributeChangeNotification notification) + throws MBeanException, RuntimeOperationsException { + + if (notification == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Notification is null"), + "Notification is null"); + if (attributeBroadcaster == null) + return; // This means there are no registered listeners + if( log.isDebugEnabled() ) + log.debug( "AttributeChangeNotification " + notification ); + attributeBroadcaster.sendNotification(notification); + + } + + + /** + * Send an AttributeChangeNotification to all registered + * listeners. + * + * @param oldValue The original value of the Attribute + * @param newValue The new value of the Attribute + * + * @exception MBeanException if an object initializer throws an + * exception + * @exception RuntimeOperationsException wraps IllegalArgumentException + * when the specified notification is null or invalid + */ + public void sendAttributeChangeNotification + (Attribute oldValue, Attribute newValue) + throws MBeanException, RuntimeOperationsException { + + // Calculate the class name for the change notification + String type = null; + if (newValue.getValue() != null) + type = newValue.getValue().getClass().getName(); + else if (oldValue.getValue() != null) + type = oldValue.getValue().getClass().getName(); + else + return; // Old and new are both null == no change + + AttributeChangeNotification notification = + new AttributeChangeNotification + (this, 1, System.currentTimeMillis(), + "Attribute value has changed", + oldValue.getName(), type, + oldValue.getValue(), newValue.getValue()); + sendAttributeChangeNotification(notification); + + } + + + + + /** + * Send a Notification to all registered listeners as a + * jmx.modelmbean.general notification. + * + * @param notification The Notification that will be passed + * + * @exception MBeanException if an object initializer throws an + * exception + * @exception RuntimeOperationsException wraps IllegalArgumentException + * when the specified notification is null or invalid + */ + public void sendNotification(Notification notification) + throws MBeanException, RuntimeOperationsException { + + if (notification == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Notification is null"), + "Notification is null"); + if (generalBroadcaster == null) + return; // This means there are no registered listeners + generalBroadcaster.sendNotification(notification); + + } + + + /** + * Send a Notification which contains the specified string + * as a jmx.modelmbean.generic notification. + * + * @param message The message string to be passed + * + * @exception MBeanException if an object initializer throws an + * exception + * @exception RuntimeOperationsException wraps IllegalArgumentException + * when the specified notification is null or invalid + */ + public void sendNotification(String message) + throws MBeanException, RuntimeOperationsException { + + if (message == null) + throw new RuntimeOperationsException + (new IllegalArgumentException("Message is null"), + "Message is null"); + Notification notification = new Notification + ("jmx.modelmbean.generic", this, 1, message); + sendNotification(notification); + + } + + + + + // ---------------------------------------- NotificationBroadcaster Methods + + + /** + * Add a notification event listener to this MBean. + * + * @param listener Listener that will receive event notifications + * @param filter Filter object used to filter event notifications + * actually delivered, or null for no filtering + * @param handback Handback object to be sent along with event + * notifications + * + * @exception IllegalArgumentException if the listener parameter is null + */ + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IllegalArgumentException { + + if (listener == null) + throw new IllegalArgumentException("Listener is null"); + + if( log.isDebugEnabled() ) log.debug("addNotificationListener " + listener); + + if (generalBroadcaster == null) + generalBroadcaster = new BaseNotificationBroadcaster(); + generalBroadcaster.addNotificationListener + (listener, filter, handback); + + // We'll send the attribute change notifications to all listeners ( who care ) + // The normal filtering can be used. + // The problem is that there is no other way to add attribute change listeners + // to a model mbean ( AFAIK ). I suppose the spec should be fixed. + if (attributeBroadcaster == null) + attributeBroadcaster = new BaseNotificationBroadcaster(); + + if( log.isDebugEnabled() ) + log.debug("addAttributeNotificationListener " + listener); + + attributeBroadcaster.addNotificationListener + (listener, filter, handback); + } + + + /** + * Return an MBeanNotificationInfo object describing the + * notifications sent by this MBean. + */ + public MBeanNotificationInfo[] getNotificationInfo() { + + // Acquire the set of application notifications + MBeanNotificationInfo current[] = getMBeanInfo().getNotifications(); + if (current == null) + current = new MBeanNotificationInfo[0]; + MBeanNotificationInfo response[] = + new MBeanNotificationInfo[current.length + 2]; + // Descriptor descriptor = null; + + // Fill in entry for general notifications +// descriptor = new DescriptorSupport +// (new String[] { "name=GENERIC", +// "descriptorType=notification", +// "log=T", +// "severity=5", +// "displayName=jmx.modelmbean.generic" }); + response[0] = new MBeanNotificationInfo + (new String[] { "jmx.modelmbean.generic" }, + "GENERIC", + "Text message notification from the managed resource"); + //descriptor); + + // Fill in entry for attribute change notifications +// descriptor = new DescriptorSupport +// (new String[] { "name=ATTRIBUTE_CHANGE", +// "descriptorType=notification", +// "log=T", +// "severity=5", +// "displayName=jmx.attribute.change" }); + response[1] = new MBeanNotificationInfo + (new String[] { "jmx.attribute.change" }, + "ATTRIBUTE_CHANGE", + "Observed MBean attribute value has changed"); + //descriptor); + + // Copy remaining notifications as reported by the application + System.arraycopy(current, 0, response, 2, current.length); + return (response); + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + + if (listener == null) + throw new IllegalArgumentException("Listener is null"); + if (generalBroadcaster == null) + generalBroadcaster = new BaseNotificationBroadcaster(); + generalBroadcaster.removeNotificationListener(listener); + + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * @param handback Handback object to be sent along with event + * notifications + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener, + Object handback) + throws ListenerNotFoundException { + + removeNotificationListener(listener); + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * @param filter Filter object used to filter event notifications + * actually delivered, or null for no filtering + * @param handback Handback object to be sent along with event + * notifications + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws ListenerNotFoundException { + + removeNotificationListener(listener); + + } + + + // ------------------------------------------------ PersistentMBean Methods + + + /** + * Instantiates this MBean instance from data found in the persistent + * store. The data loaded could include attribute and operation values. + * This method should be called during construction or initialization + * of the instance, and before the MBean is registered with the + * MBeanServer. + * + *

        IMPLEMENTATION NOTE - This implementation does + * not support persistence.

        + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception + * @exception RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ +// public void load() throws InstanceNotFoundException, +// MBeanException, RuntimeOperationsException { +// // XXX If a context was set, use it to load the data +// throw new MBeanException +// (new IllegalStateException("Persistence is not supported"), +// "Persistence is not supported"); +// +// } + + + /** + * Capture the current state of this MBean instance and write it out + * to the persistent store. The state stored could include attribute + * and operation values. If one of these methods of persistence is not + * supported, a "service not found" exception will be thrown. + * + *

        IMPLEMENTATION NOTE - This implementation does + * not support persistence.

        + * + * @exception InstanceNotFoundException if the managed resource object + * cannot be found + * @exception MBeanException if the initializer of the object throws + * an exception, or persistence is not supported + * @exception RuntimeOperationsException if an exception is reported + * by the persistence mechanism + */ +// public void store() throws InstanceNotFoundException, +// MBeanException, RuntimeOperationsException { +// +// // XXX if a context was set, use it to store the data +// throw new MBeanException +// (new IllegalStateException("Persistence is not supported"), +// "Persistence is not supported"); +// +// } + + // -------------------- BaseModelMBean methods -------------------- + + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + * + * @param type the type of classname of the modeled object + */ +// void setModeledType( String type ) { +// initModelInfo(type); +// createResource(); +// } + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + * + * @param type the type of classname of the modeled object + */ +// void initModelInfo( String type ) { +// try { +// if( log.isDebugEnabled()) +// log.debug("setModeledType " + type); +// +// log.debug( "Set model Info " + type); +// if(type==null) { +// return; +// } +// resourceType=type; +// //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); +// Class c=null; +// try { +// c=Class.forName( type); +// } catch( Throwable t ) { +// log.debug( "Error creating class " + t); +// } +// +// // The class c doesn't need to exist +// ManagedBean descriptor=getRegistry().findManagedBean(c, type); +// if( descriptor==null ) +// return; +// this.setModelMBeanInfo(descriptor.createMBeanInfo()); +// } catch( Throwable ex) { +// log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), +// ex); +// } +// } + + /** Set the type of the mbean. This is used as a key to locate + * the description in the Registry. + */ +// protected void createResource() { +// try { +// //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader()); +// Class c=null; +// try { +// c=Class.forName( resourceType ); +// resource = c.newInstance(); +// } catch( Throwable t ) { +// log.error( "Error creating class " + t); +// } +// } catch( Throwable ex) { +// log.error( "TCL: " + Thread.currentThread().getContextClassLoader(), +// ex); +// } +// } + + + public String getModelerType() { + return resourceType; + } + + public String getClassName() { + return getModelerType(); + } + + public ObjectName getJmxName() { + return oname; + } + + public String getObjectName() { + if (oname != null) { + return oname.toString(); + } else { + return null; + } + } + +// public void setRegistry(Registry registry) { +// this.registry = registry; +// } +// +// public Registry getRegistry() { +// // XXX Need a better solution - to avoid the static +// if( registry == null ) +// registry=Registry.getRegistry(); +// +// return registry; +// } + + // ------------------------------------------------------ Protected Methods + + + /** + * Create and return a default ModelMBeanInfo object. + */ +// protected ModelMBeanInfo createDefaultModelMBeanInfo() { +// +// return (new ModelMBeanInfoSupport(this.getClass().getName(), +// "Default ModelMBean", +// null, null, null, null)); +// +// } + + /** + * Is the specified ModelMBeanInfo instance valid? + * + *

        IMPLEMENTATION NOTE - This implementation + * does not check anything, but this method can be overridden + * as required.

        + * + * @param info The ModelMBeanInfo object to check + */ +// protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) { +// return (true); +// } + + // -------------------- Registration -------------------- + // XXX We can add some method patterns here- like setName() and + // setDomain() for code that doesn't implement the Registration + + public ObjectName preRegister(MBeanServer server, + ObjectName name) + throws Exception + { + if( log.isDebugEnabled()) + log.debug("preRegister " + resource + " " + name ); + oname=name; + if( resource instanceof MBeanRegistration ) { + oname = ((MBeanRegistration)resource).preRegister(server, name ); + } + return oname; + } + + public void postRegister(Boolean registrationDone) { + if( resource instanceof MBeanRegistration ) { + ((MBeanRegistration)resource).postRegister(registrationDone); + } + } + + public void preDeregister() throws Exception { + if( resource instanceof MBeanRegistration ) { + ((MBeanRegistration)resource).preDeregister(); + } + } + + public void postDeregister() { + if( resource instanceof MBeanRegistration ) { + ((MBeanRegistration)resource).postDeregister(); + } + } + + static class MethodKey { + private String name; + private String[] signature; + + MethodKey(String name, String[] signature) { + this.name = name; + if(signature == null) { + signature = new String[0]; + } + this.signature = signature; + } + + public boolean equals(Object other) { + if(!(other instanceof MethodKey)) { + return false; + } + MethodKey omk = (MethodKey)other; + if(!name.equals(omk.name)) { + return false; + } + if(signature.length != omk.signature.length) { + return false; + } + for(int i=0; i < signature.length; i++) { + if(!signature[i].equals(omk.signature[i])) { + return false; + } + } + return true; + } + + public int hashCode() { + return name.hashCode(); + } + } +} diff --git a/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java b/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java index 197b9e69a..e475896a8 100644 --- a/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java +++ b/java/org/apache/tomcat/util/modeler/BaseNotificationBroadcaster.java @@ -1,264 +1,264 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.util.ArrayList; -import java.util.Iterator; - -import javax.management.ListenerNotFoundException; -import javax.management.MBeanNotificationInfo; -import javax.management.Notification; -import javax.management.NotificationBroadcaster; -import javax.management.NotificationFilter; -import javax.management.NotificationListener; - - -/** - *

        Implementation of NotificationBroadcaster for attribute - * change notifications. This class is used by BaseModelMBean to - * handle notifications of attribute change events to interested listeners. - *

        - * - * @author Craig R. McClanahan - * @author Costin Manolache - */ - -public class BaseNotificationBroadcaster implements NotificationBroadcaster { - - - // ----------------------------------------------------------- Constructors - - - // ----------------------------------------------------- Instance Variables - - - /** - * The set of registered BaseNotificationBroadcasterEntry - * entries. - */ - protected ArrayList entries = new ArrayList(); - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a notification event listener to this MBean. - * - * @param listener Listener that will receive event notifications - * @param filter Filter object used to filter event notifications - * actually delivered, or null for no filtering - * @param handback Handback object to be sent along with event - * notifications - * - * @exception IllegalArgumentException if the listener parameter is null - */ - public void addNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws IllegalArgumentException { - - synchronized (entries) { - - // Optimization to coalesce attribute name filters - if (filter instanceof BaseAttributeFilter) { - BaseAttributeFilter newFilter = (BaseAttributeFilter) filter; - Iterator items = entries.iterator(); - while (items.hasNext()) { - BaseNotificationBroadcasterEntry item = - (BaseNotificationBroadcasterEntry) items.next(); - if ((item.listener == listener) && - (item.filter != null) && - (item.filter instanceof BaseAttributeFilter) && - (item.handback == handback)) { - BaseAttributeFilter oldFilter = - (BaseAttributeFilter) item.filter; - String newNames[] = newFilter.getNames(); - String oldNames[] = oldFilter.getNames(); - if (newNames.length == 0) { - oldFilter.clear(); - } else { - if (oldNames.length != 0) { - for (int i = 0; i < newNames.length; i++) - oldFilter.addAttribute(newNames[i]); - } - } - return; - } - } - } - - // General purpose addition of a new entry - entries.add(new BaseNotificationBroadcasterEntry - (listener, filter, handback)); - } - - } - - - /** - * Return an MBeanNotificationInfo object describing the - * notifications sent by this MBean. - */ - public MBeanNotificationInfo[] getNotificationInfo() { - - return (new MBeanNotificationInfo[0]); - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener) - throws ListenerNotFoundException { - - synchronized (entries) { - Iterator items = entries.iterator(); - while (items.hasNext()) { - BaseNotificationBroadcasterEntry item = - (BaseNotificationBroadcasterEntry) items.next(); - if (item.listener == listener) - items.remove(); - } - } - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * @param handback Handback object to be sent along with event - * notifications - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener, - Object handback) - throws ListenerNotFoundException { - - removeNotificationListener(listener); - - } - - - /** - * Remove a notification event listener from this MBean. - * - * @param listener The listener to be removed (any and all registrations - * for this listener will be eliminated) - * @param filter Filter object used to filter event notifications - * actually delivered, or null for no filtering - * @param handback Handback object to be sent along with event - * notifications - * - * @exception ListenerNotFoundException if this listener is not - * registered in the MBean - */ - public void removeNotificationListener(NotificationListener listener, - NotificationFilter filter, - Object handback) - throws ListenerNotFoundException { - - removeNotificationListener(listener); - - } - - - /** - * Send the specified notification to all interested listeners. - * - * @param notification The notification to be sent - */ - public void sendNotification(Notification notification) { - - synchronized (entries) { - Iterator items = entries.iterator(); - while (items.hasNext()) { - BaseNotificationBroadcasterEntry item = - (BaseNotificationBroadcasterEntry) items.next(); - if ((item.filter != null) && - (!item.filter.isNotificationEnabled(notification))) - continue; - item.listener.handleNotification(notification, item.handback); - } - } - - } - - - // -------------------- Internal Extensions -------------------- - - // Fast access. First index is the hook type - // ( FixedNotificationFilter.getType() ). - NotificationListener hooks[][]=new NotificationListener[20][]; - int hookCount[]=new int[20]; - - private synchronized void registerNotifications( FixedNotificationFilter filter ) { - String names[]=filter.getNames(); - Registry reg=Registry.getRegistry(); - for( int i=0; iImplementation of NotificationBroadcaster for attribute + * change notifications. This class is used by BaseModelMBean to + * handle notifications of attribute change events to interested listeners. + *

        + * + * @author Craig R. McClanahan + * @author Costin Manolache + */ + +public class BaseNotificationBroadcaster implements NotificationBroadcaster { + + + // ----------------------------------------------------------- Constructors + + + // ----------------------------------------------------- Instance Variables + + + /** + * The set of registered BaseNotificationBroadcasterEntry + * entries. + */ + protected ArrayList entries = new ArrayList(); + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a notification event listener to this MBean. + * + * @param listener Listener that will receive event notifications + * @param filter Filter object used to filter event notifications + * actually delivered, or null for no filtering + * @param handback Handback object to be sent along with event + * notifications + * + * @exception IllegalArgumentException if the listener parameter is null + */ + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws IllegalArgumentException { + + synchronized (entries) { + + // Optimization to coalesce attribute name filters + if (filter instanceof BaseAttributeFilter) { + BaseAttributeFilter newFilter = (BaseAttributeFilter) filter; + Iterator items = entries.iterator(); + while (items.hasNext()) { + BaseNotificationBroadcasterEntry item = + (BaseNotificationBroadcasterEntry) items.next(); + if ((item.listener == listener) && + (item.filter != null) && + (item.filter instanceof BaseAttributeFilter) && + (item.handback == handback)) { + BaseAttributeFilter oldFilter = + (BaseAttributeFilter) item.filter; + String newNames[] = newFilter.getNames(); + String oldNames[] = oldFilter.getNames(); + if (newNames.length == 0) { + oldFilter.clear(); + } else { + if (oldNames.length != 0) { + for (int i = 0; i < newNames.length; i++) + oldFilter.addAttribute(newNames[i]); + } + } + return; + } + } + } + + // General purpose addition of a new entry + entries.add(new BaseNotificationBroadcasterEntry + (listener, filter, handback)); + } + + } + + + /** + * Return an MBeanNotificationInfo object describing the + * notifications sent by this MBean. + */ + public MBeanNotificationInfo[] getNotificationInfo() { + + return (new MBeanNotificationInfo[0]); + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException { + + synchronized (entries) { + Iterator items = entries.iterator(); + while (items.hasNext()) { + BaseNotificationBroadcasterEntry item = + (BaseNotificationBroadcasterEntry) items.next(); + if (item.listener == listener) + items.remove(); + } + } + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * @param handback Handback object to be sent along with event + * notifications + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener, + Object handback) + throws ListenerNotFoundException { + + removeNotificationListener(listener); + + } + + + /** + * Remove a notification event listener from this MBean. + * + * @param listener The listener to be removed (any and all registrations + * for this listener will be eliminated) + * @param filter Filter object used to filter event notifications + * actually delivered, or null for no filtering + * @param handback Handback object to be sent along with event + * notifications + * + * @exception ListenerNotFoundException if this listener is not + * registered in the MBean + */ + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object handback) + throws ListenerNotFoundException { + + removeNotificationListener(listener); + + } + + + /** + * Send the specified notification to all interested listeners. + * + * @param notification The notification to be sent + */ + public void sendNotification(Notification notification) { + + synchronized (entries) { + Iterator items = entries.iterator(); + while (items.hasNext()) { + BaseNotificationBroadcasterEntry item = + (BaseNotificationBroadcasterEntry) items.next(); + if ((item.filter != null) && + (!item.filter.isNotificationEnabled(notification))) + continue; + item.listener.handleNotification(notification, item.handback); + } + } + + } + + + // -------------------- Internal Extensions -------------------- + + // Fast access. First index is the hook type + // ( FixedNotificationFilter.getType() ). + NotificationListener hooks[][]=new NotificationListener[20][]; + int hookCount[]=new int[20]; + + private synchronized void registerNotifications( FixedNotificationFilter filter ) { + String names[]=filter.getNames(); + Registry reg=Registry.getRegistry(); + for( int i=0; iInternal configuration information for a Constructor - * descriptor.

        - * - * @author Craig R. McClanahan - */ -public class ConstructorInfo extends OperationInfo implements Serializable { - static final long serialVersionUID = -5735336213417238238L; - // ------------------------------------------------------------- Properties - - public ConstructorInfo() { - } - - // --------------------------------------------------------- Public Methods - - - /** - * Create and return a ModelMBeanConstructorInfo object that - * corresponds to the attribute described by this instance. - */ - public MBeanConstructorInfo createConstructorInfo() { - // Return our cached information (if any) - if (info == null) { - info = new MBeanConstructorInfo(getName(), getDescription(), - getMBeanParameterInfo()); - } - return (MBeanConstructorInfo)info; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanConstructorInfo; + + +/** + *

        Internal configuration information for a Constructor + * descriptor.

        + * + * @author Craig R. McClanahan + */ +public class ConstructorInfo extends OperationInfo implements Serializable { + static final long serialVersionUID = -5735336213417238238L; + // ------------------------------------------------------------- Properties + + public ConstructorInfo() { + } + + // --------------------------------------------------------- Public Methods + + + /** + * Create and return a ModelMBeanConstructorInfo object that + * corresponds to the attribute described by this instance. + */ + public MBeanConstructorInfo createConstructorInfo() { + // Return our cached information (if any) + if (info == null) { + info = new MBeanConstructorInfo(getName(), getDescription(), + getMBeanParameterInfo()); + } + return (MBeanConstructorInfo)info; + } + +} diff --git a/java/org/apache/tomcat/util/modeler/FeatureInfo.java b/java/org/apache/tomcat/util/modeler/FeatureInfo.java index 75e149c3b..2d17ae862 100644 --- a/java/org/apache/tomcat/util/modeler/FeatureInfo.java +++ b/java/org/apache/tomcat/util/modeler/FeatureInfo.java @@ -1,85 +1,85 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.Serializable; - -import javax.management.MBeanFeatureInfo; - - -/** - *

        Convenience base class for AttributeInfo, - * ConstructorInfo, and OperationInfo classes - * that will be used to collect configuration information for the - * ModelMBean beans exposed for management.

        - * - * @author Craig R. McClanahan - * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ - */ - -public class FeatureInfo implements Serializable { - static final long serialVersionUID = -911529176124712296L; - - protected String description = null; - protected String name = null; - protected MBeanFeatureInfo info = null; - - // all have type except Constructor - protected String type = null; - - - // ------------------------------------------------------------- Properties - - /** - * The human-readable description of this feature. - */ - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - } - - - /** - * The name of this feature, which must be unique among features in the - * same collection. - */ - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - } - - /** - * The fully qualified Java class name of this element. - */ - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanFeatureInfo; + + +/** + *

        Convenience base class for AttributeInfo, + * ConstructorInfo, and OperationInfo classes + * that will be used to collect configuration information for the + * ModelMBean beans exposed for management.

        + * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class FeatureInfo implements Serializable { + static final long serialVersionUID = -911529176124712296L; + + protected String description = null; + protected String name = null; + protected MBeanFeatureInfo info = null; + + // all have type except Constructor + protected String type = null; + + + // ------------------------------------------------------------- Properties + + /** + * The human-readable description of this feature. + */ + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + } + + + /** + * The name of this feature, which must be unique among features in the + * same collection. + */ + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + } + + /** + * The fully qualified Java class name of this element. + */ + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java b/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java index 6fb1836c4..50c1ec41a 100644 --- a/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java +++ b/java/org/apache/tomcat/util/modeler/FixedNotificationFilter.java @@ -1,94 +1,94 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.util.HashSet; - -import javax.management.Notification; -import javax.management.NotificationFilter; - - -/** - * Special NotificationFilter that allows modeler to optimize its notifications. - * - * This class is immutable - after you construct it it'll filter based on - * a fixed set of notification names. - * - * The JMX specification requires the filters to be called before the - * notifications are sent. We can call this filter well in advance, when - * the listener is added. Based on the result we can maintain separate - * channels for each notification - and reduce the overhead. - * - * @author Costin Manolache - */ -public class FixedNotificationFilter implements NotificationFilter { - - /** - * The set of attribute names that are accepted by this filter. If this - * list is empty, all attribute names are accepted. - */ - private HashSet names = new HashSet(); - String namesA[]=null; - - /** - * Construct a new filter that accepts only the specified notification - * names. - * - * @param names Names of the notification types - */ - public FixedNotificationFilter(String names[]) { - super(); - } - - /** - * Return the set of names that are accepted by this filter. If this - * filter accepts all attribute names, a zero length array will be - * returned. - */ - public String[] getNames() { - synchronized (names) { - return ((String[]) names.toArray(new String[names.size()])); - } - } - - - /** - *

        Test whether notification enabled for this event. - * Return true if:

        - *
          - *
        • Either the set of accepted names is empty (implying that all - * attribute names are of interest) or the set of accepted names - * includes the name of the attribute in this notification
        • - *
        - */ - public boolean isNotificationEnabled(Notification notification) { - - if (notification == null) - return (false); - synchronized (names) { - if (names.size() < 1) - return (true); - else - return (names.contains(notification.getType())); - } - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.util.HashSet; + +import javax.management.Notification; +import javax.management.NotificationFilter; + + +/** + * Special NotificationFilter that allows modeler to optimize its notifications. + * + * This class is immutable - after you construct it it'll filter based on + * a fixed set of notification names. + * + * The JMX specification requires the filters to be called before the + * notifications are sent. We can call this filter well in advance, when + * the listener is added. Based on the result we can maintain separate + * channels for each notification - and reduce the overhead. + * + * @author Costin Manolache + */ +public class FixedNotificationFilter implements NotificationFilter { + + /** + * The set of attribute names that are accepted by this filter. If this + * list is empty, all attribute names are accepted. + */ + private HashSet names = new HashSet(); + String namesA[]=null; + + /** + * Construct a new filter that accepts only the specified notification + * names. + * + * @param names Names of the notification types + */ + public FixedNotificationFilter(String names[]) { + super(); + } + + /** + * Return the set of names that are accepted by this filter. If this + * filter accepts all attribute names, a zero length array will be + * returned. + */ + public String[] getNames() { + synchronized (names) { + return ((String[]) names.toArray(new String[names.size()])); + } + } + + + /** + *

        Test whether notification enabled for this event. + * Return true if:

        + *
          + *
        • Either the set of accepted names is empty (implying that all + * attribute names are of interest) or the set of accepted names + * includes the name of the attribute in this notification
        • + *
        + */ + public boolean isNotificationEnabled(Notification notification) { + + if (notification == null) + return (false); + synchronized (names) { + if (names.size() < 1) + return (true); + else + return (names.contains(notification.getType())); + } + + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/ManagedBean.java b/java/org/apache/tomcat/util/modeler/ManagedBean.java index 14704469f..85246ad26 100644 --- a/java/org/apache/tomcat/util/modeler/ManagedBean.java +++ b/java/org/apache/tomcat/util/modeler/ManagedBean.java @@ -1,627 +1,627 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.Map; - -import javax.management.AttributeNotFoundException; -import javax.management.DynamicMBean; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanConstructorInfo; -import javax.management.MBeanException; -import javax.management.MBeanInfo; -import javax.management.MBeanNotificationInfo; -import javax.management.MBeanOperationInfo; -import javax.management.ReflectionException; -import javax.management.RuntimeOperationsException; -import javax.management.ServiceNotFoundException; -//import javax.management.modelmbean.InvalidTargetObjectTypeException; - - -/** - *

        Internal configuration information for a managed bean (MBean) - * descriptor.

        - * - * @author Craig R. McClanahan - * @version $Revision: 383268 $ $Date: 2006-03-05 03:02:01 +0100 (dim., 05 mars 2006) $ - */ - -public class ManagedBean implements java.io.Serializable -{ - private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean"; - // ----------------------------------------------------- Instance Variables - static final Object[] NO_ARGS_PARAM=new Object[0]; - static final Class[] NO_ARGS_PARAM_SIG=new Class[0]; - - - /** - * The ModelMBeanInfo object that corresponds - * to this ManagedBean instance. - */ - transient MBeanInfo info = null; - // Map - private Map attributes = new HashMap(); - //Map - private Map operations = new HashMap(); - - protected String className = BASE_MBEAN; - //protected ConstructorInfo constructors[] = new ConstructorInfo[0]; - protected String description = null; - protected String domain = null; - protected String group = null; - protected String name = null; - - //protected List fields = new ArrayList(); - protected NotificationInfo notifications[] = new NotificationInfo[0]; - protected String type = null; - - /** Constructor. Will add default attributes. - * - */ - public ManagedBean() { - AttributeInfo ai=new AttributeInfo(); - ai.setName("modelerType"); - ai.setDescription("Type of the modeled resource. Can be set only once"); - ai.setType("java.lang.String"); - ai.setWriteable(false); - addAttribute(ai); - } - - // ------------------------------------------------------------- Properties - - - /** - * The collection of attributes for this MBean. - */ - public AttributeInfo[] getAttributes() { - AttributeInfo result[] = new AttributeInfo[attributes.size()]; - attributes.values().toArray(result); - return result; - } - - - /** - * The fully qualified name of the Java class of the MBean - * described by this descriptor. If not specified, the standard JMX - * class (javax.management.modelmbean.RequiredModeLMBean) - * will be utilized. - */ - public String getClassName() { - return (this.className); - } - - public void setClassName(String className) { - this.className = className; - this.info = null; - } - - -// /** -// * The collection of constructors for this MBean. -// */ -// public ConstructorInfo[] getConstructors() { -// return (this.constructors); -// } - - - /** - * The human-readable description of this MBean. - */ - public String getDescription() { - return (this.description); - } - - public void setDescription(String description) { - this.description = description; - this.info = null; - } - - - /** - * The (optional) ObjectName domain in which this MBean - * should be registered in the MBeanServer. - */ - public String getDomain() { - return (this.domain); - } - - public void setDomain(String domain) { - this.domain = domain; - } - - - /** - *

        Return a List of the {@link FieldInfo} objects for - * the name/value pairs that should be - * added to the Descriptor created from this metadata.

        - */ -// public List getFields() { -// return (this.fields); -// } -// - - /** - * The (optional) group to which this MBean belongs. - */ - public String getGroup() { - return (this.group); - } - - public void setGroup(String group) { - this.group = group; - } - - - /** - * The name of this managed bean, which must be unique among all - * MBeans managed by a particular MBeans server. - */ - public String getName() { - return (this.name); - } - - public void setName(String name) { - this.name = name; - this.info = null; - } - - - /** - * The collection of notifications for this MBean. - */ - public NotificationInfo[] getNotifications() { - return (this.notifications); - } - - - /** - * The collection of operations for this MBean. - */ - public OperationInfo[] getOperations() { - OperationInfo[] result = new OperationInfo[operations.size()]; - operations.values().toArray(result); - return result; - } - - - /** - * The fully qualified name of the Java class of the resource - * implementation class described by the managed bean described - * by this descriptor. - */ - public String getType() { - return (this.type); - } - - public void setType(String type) { - this.type = type; - this.info = null; - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new attribute to the set of attributes for this MBean. - * - * @param attribute The new attribute descriptor - */ - public void addAttribute(AttributeInfo attribute) { - attributes.put(attribute.getName(), attribute); - } - - - /** - * Add a new constructor to the set of constructors for this MBean. - * - * @param constructor The new constructor descriptor - */ -// public void addConstructor(ConstructorInfo constructor) { -// -// synchronized (constructors) { -// ConstructorInfo results[] = -// new ConstructorInfo[constructors.length + 1]; -// System.arraycopy(constructors, 0, results, 0, constructors.length); -// results[constructors.length] = constructor; -// constructors = results; -// this.info = null; -// } -// -// } - - - /** - *

        Add a new field to the fields associated with the - * Descriptor that will be created from this metadata.

        - * - * @param field The field to be added - */ -// public void addField(FieldInfo field) { -// fields.add(field); -// } - - - /** - * Add a new notification to the set of notifications for this MBean. - * - * @param notification The new notification descriptor - */ - public void addNotification(NotificationInfo notification) { - - synchronized (notifications) { - NotificationInfo results[] = - new NotificationInfo[notifications.length + 1]; - System.arraycopy(notifications, 0, results, 0, - notifications.length); - results[notifications.length] = notification; - notifications = results; - this.info = null; - } - - } - - - /** - * Add a new operation to the set of operations for this MBean. - * - * @param operation The new operation descriptor - */ - public void addOperation(OperationInfo operation) { - operations.put(operation.getName(), operation); - } - - - /** - * Create and return a ModelMBean that has been - * preconfigured with the ModelMBeanInfo information - * for this managed bean, but is not associated with any particular - * managed resource. The returned ModelMBean will - * NOT have been registered with our - * MBeanServer. - * - * @exception InstanceNotFoundException if the managed resource - * object cannot be found - * @exception InvalidTargetObjectTypeException if our MBean cannot - * handle object references (should never happen) - * @exception MBeanException if a problem occurs instantiating the - * ModelMBean instance - * @exception RuntimeOperationsException if a JMX runtime error occurs - */ - public DynamicMBean createMBean() - throws InstanceNotFoundException, - MBeanException, RuntimeOperationsException { - - return (createMBean(null)); - - } - - - /** - * Create and return a ModelMBean that has been - * preconfigured with the ModelMBeanInfo information - * for this managed bean, and is associated with the specified - * managed object instance. The returned ModelMBean - * will NOT have been registered with our - * MBeanServer. - * - * @param instance Instanced of the managed object, or null - * for no associated instance - * - * @exception InstanceNotFoundException if the managed resource - * object cannot be found - * @exception InvalidTargetObjectTypeException if our MBean cannot - * handle object references (should never happen) - * @exception MBeanException if a problem occurs instantiating the - * ModelMBean instance - * @exception RuntimeOperationsException if a JMX runtime error occurs - */ - public DynamicMBean createMBean(Object instance) - throws InstanceNotFoundException, - MBeanException, RuntimeOperationsException { - - BaseModelMBean mbean = null; - - // Load the ModelMBean implementation class - if(getClassName().equals(BASE_MBEAN)) { - // Skip introspection - mbean = new BaseModelMBean(); - } else { - Class clazz = null; - Exception ex = null; - try { - clazz = Class.forName(getClassName()); - } catch (Exception e) { - } - - if( clazz==null ) { - try { - ClassLoader cl= Thread.currentThread().getContextClassLoader(); - if ( cl != null) - clazz= cl.loadClass(getClassName()); - } catch (Exception e) { - ex=e; - } - } - - if( clazz==null) { - throw new MBeanException - (ex, "Cannot load ModelMBean class " + getClassName()); - } - try { - // Stupid - this will set the default minfo first.... - mbean = (BaseModelMBean) clazz.newInstance(); - } catch (RuntimeOperationsException e) { - throw e; - } catch (Exception e) { - throw new MBeanException - (e, "Cannot instantiate ModelMBean of class " + - getClassName()); - } - } - - mbean.setManagedBean(this); - - // Set the managed resource (if any) - try { - if (instance != null) - mbean.setManagedResource(instance, "ObjectReference"); - } catch (InstanceNotFoundException e) { - throw e; - } - return (mbean); - - } - - - /** - * Create and return a ModelMBeanInfo object that - * describes this entire managed bean. - */ - MBeanInfo getMBeanInfo() { - - // Return our cached information (if any) - if (info != null) - return (info); - - // Create subordinate information descriptors as required - AttributeInfo attrs[] = getAttributes(); - MBeanAttributeInfo attributes[] = - new MBeanAttributeInfo[attrs.length]; - for (int i = 0; i < attrs.length; i++) - attributes[i] = attrs[i].createAttributeInfo(); - - OperationInfo opers[] = getOperations(); - MBeanOperationInfo operations[] = - new MBeanOperationInfo[opers.length]; - for (int i = 0; i < opers.length; i++) - operations[i] = opers[i].createOperationInfo(); - - -// ConstructorInfo consts[] = getConstructors(); -// ModelMBeanConstructorInfo constructors[] = -// new ModelMBeanConstructorInfo[consts.length]; -// for (int i = 0; i < consts.length; i++) -// constructors[i] = consts[i].createConstructorInfo(); - - NotificationInfo notifs[] = getNotifications(); - MBeanNotificationInfo notifications[] = - new MBeanNotificationInfo[notifs.length]; - for (int i = 0; i < notifs.length; i++) - notifications[i] = notifs[i].createNotificationInfo(); - - - // Construct and return a new ModelMBeanInfo object - info = new MBeanInfo(getClassName(), - getDescription(), - attributes, - new MBeanConstructorInfo[] {}, - operations, - notifications); -// try { -// Descriptor descriptor = info.getMBeanDescriptor(); -// Iterator fields = getFields().iterator(); -// while (fields.hasNext()) { -// FieldInfo field = (FieldInfo) fields.next(); -// descriptor.setField(field.getName(), field.getValue()); -// } -// info.setMBeanDescriptor(descriptor); -// } catch (MBeanException e) { -// ; -// } - - return (info); - - } - - - /** - * Return a string representation of this managed bean. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("ManagedBean["); - sb.append("name="); - sb.append(name); - sb.append(", className="); - sb.append(className); - sb.append(", description="); - sb.append(description); - if (group != null) { - sb.append(", group="); - sb.append(group); - } - sb.append(", type="); - sb.append(type); - sb.append("]"); - return (sb.toString()); - - } - - Method getGetter(String aname, BaseModelMBean mbean, Object resource) - throws AttributeNotFoundException, MBeanException, ReflectionException { - // TODO: do we need caching ? JMX is for management, it's not supposed to require lots of performance. - Method m=null; // (Method)getAttMap.get( name ); - - if( m==null ) { - AttributeInfo attrInfo = (AttributeInfo)attributes.get(aname); - // Look up the actual operation to be used - if (attrInfo == null) - throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource); - - String getMethod = attrInfo.getGetMethod(); - if (getMethod == null) - throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name"); - - Object object = null; - NoSuchMethodException exception = null; - try { - object = mbean; - m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); - } catch (NoSuchMethodException e) { - exception = e;; - } - if( m== null && resource != null ) { - try { - object = resource; - m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); - exception=null; - } catch (NoSuchMethodException e) { - exception = e; - } - } - if( exception != null ) - throw new ReflectionException(exception, - "Cannot find getter method " + getMethod); - //getAttMap.put( name, m ); - } - - return m; - } - - public Method getSetter(String aname, BaseModelMBean bean, Object resource) - throws AttributeNotFoundException, MBeanException, ReflectionException { - // Cache may be needed for getters, but it is a really bad idea for setters, this is far - // less frequent. - Method m=null;//(Method)setAttMap.get( name ); - - if( m==null ) { - AttributeInfo attrInfo = (AttributeInfo)attributes.get(aname); - if (attrInfo == null) - throw new AttributeNotFoundException(" Cannot find attribute " + aname); - - // Look up the actual operation to be used - String setMethod = attrInfo.getSetMethod(); - if (setMethod == null) - throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name"); - - String argType=attrInfo.getType(); - - Class signature[] = new Class[] { BaseModelMBean.getAttributeClass( argType ) }; - - Object object = null; - NoSuchMethodException exception = null; - try { - object = this; - m = object.getClass().getMethod(setMethod, signature); - } catch (NoSuchMethodException e) { - exception = e;; - } - if( m== null && resource != null ) { - try { - object = resource; - m = object.getClass().getMethod(setMethod, signature); - exception=null; - } catch (NoSuchMethodException e) { - exception = e; - } - } - if( exception != null ) - throw new ReflectionException(exception, - "Cannot find setter method " + setMethod + - " " + resource); - //setAttMap.put( name, m ); - } - - return m; - } - - public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) - throws MBeanException, ReflectionException { - Method method = null; - if (method == null) { - if (params == null) - params = new Object[0]; - if (signature == null) - signature = new String[0]; - if (params.length != signature.length) - throw new RuntimeOperationsException( - new IllegalArgumentException( - "Inconsistent arguments and signature"), - "Inconsistent arguments and signature"); - - // Acquire the ModelMBeanOperationInfo information for - // the requested operation - OperationInfo opInfo = (OperationInfo)operations.get(aname); - if (opInfo == null) - throw new MBeanException(new ServiceNotFoundException( - "Cannot find operation " + aname), - "Cannot find operation " + aname); - - // Prepare the signature required by Java reflection APIs - // FIXME - should we use the signature from opInfo? - Class types[] = new Class[signature.length]; - for (int i = 0; i < signature.length; i++) { - types[i] = BaseModelMBean.getAttributeClass(signature[i]); - } - - // Locate the method to be invoked, either in this MBean itself - // or in the corresponding managed resource - // FIXME - Accessible methods in superinterfaces? - Object object = null; - Exception exception = null; - try { - object = this; - method = object.getClass().getMethod(aname, types); - } catch (NoSuchMethodException e) { - exception = e; - ; - } - try { - if ((method == null) && (resource != null)) { - object = resource; - method = object.getClass().getMethod(aname, types); - } - } catch (NoSuchMethodException e) { - exception = e; - } - if (method == null) { - throw new ReflectionException(exception, "Cannot find method " - + aname + " with this signature"); - } - // invokeAttMap.put(mkey, method); - } - return method; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; + +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.ServiceNotFoundException; +//import javax.management.modelmbean.InvalidTargetObjectTypeException; + + +/** + *

        Internal configuration information for a managed bean (MBean) + * descriptor.

        + * + * @author Craig R. McClanahan + * @version $Revision: 383268 $ $Date: 2006-03-05 03:02:01 +0100 (dim., 05 mars 2006) $ + */ + +public class ManagedBean implements java.io.Serializable +{ + private static final String BASE_MBEAN = "org.apache.tomcat.util.modeler.BaseModelMBean"; + // ----------------------------------------------------- Instance Variables + static final Object[] NO_ARGS_PARAM=new Object[0]; + static final Class[] NO_ARGS_PARAM_SIG=new Class[0]; + + + /** + * The ModelMBeanInfo object that corresponds + * to this ManagedBean instance. + */ + transient MBeanInfo info = null; + // Map + private Map attributes = new HashMap(); + //Map + private Map operations = new HashMap(); + + protected String className = BASE_MBEAN; + //protected ConstructorInfo constructors[] = new ConstructorInfo[0]; + protected String description = null; + protected String domain = null; + protected String group = null; + protected String name = null; + + //protected List fields = new ArrayList(); + protected NotificationInfo notifications[] = new NotificationInfo[0]; + protected String type = null; + + /** Constructor. Will add default attributes. + * + */ + public ManagedBean() { + AttributeInfo ai=new AttributeInfo(); + ai.setName("modelerType"); + ai.setDescription("Type of the modeled resource. Can be set only once"); + ai.setType("java.lang.String"); + ai.setWriteable(false); + addAttribute(ai); + } + + // ------------------------------------------------------------- Properties + + + /** + * The collection of attributes for this MBean. + */ + public AttributeInfo[] getAttributes() { + AttributeInfo result[] = new AttributeInfo[attributes.size()]; + attributes.values().toArray(result); + return result; + } + + + /** + * The fully qualified name of the Java class of the MBean + * described by this descriptor. If not specified, the standard JMX + * class (javax.management.modelmbean.RequiredModeLMBean) + * will be utilized. + */ + public String getClassName() { + return (this.className); + } + + public void setClassName(String className) { + this.className = className; + this.info = null; + } + + +// /** +// * The collection of constructors for this MBean. +// */ +// public ConstructorInfo[] getConstructors() { +// return (this.constructors); +// } + + + /** + * The human-readable description of this MBean. + */ + public String getDescription() { + return (this.description); + } + + public void setDescription(String description) { + this.description = description; + this.info = null; + } + + + /** + * The (optional) ObjectName domain in which this MBean + * should be registered in the MBeanServer. + */ + public String getDomain() { + return (this.domain); + } + + public void setDomain(String domain) { + this.domain = domain; + } + + + /** + *

        Return a List of the {@link FieldInfo} objects for + * the name/value pairs that should be + * added to the Descriptor created from this metadata.

        + */ +// public List getFields() { +// return (this.fields); +// } +// + + /** + * The (optional) group to which this MBean belongs. + */ + public String getGroup() { + return (this.group); + } + + public void setGroup(String group) { + this.group = group; + } + + + /** + * The name of this managed bean, which must be unique among all + * MBeans managed by a particular MBeans server. + */ + public String getName() { + return (this.name); + } + + public void setName(String name) { + this.name = name; + this.info = null; + } + + + /** + * The collection of notifications for this MBean. + */ + public NotificationInfo[] getNotifications() { + return (this.notifications); + } + + + /** + * The collection of operations for this MBean. + */ + public OperationInfo[] getOperations() { + OperationInfo[] result = new OperationInfo[operations.size()]; + operations.values().toArray(result); + return result; + } + + + /** + * The fully qualified name of the Java class of the resource + * implementation class described by the managed bean described + * by this descriptor. + */ + public String getType() { + return (this.type); + } + + public void setType(String type) { + this.type = type; + this.info = null; + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new attribute to the set of attributes for this MBean. + * + * @param attribute The new attribute descriptor + */ + public void addAttribute(AttributeInfo attribute) { + attributes.put(attribute.getName(), attribute); + } + + + /** + * Add a new constructor to the set of constructors for this MBean. + * + * @param constructor The new constructor descriptor + */ +// public void addConstructor(ConstructorInfo constructor) { +// +// synchronized (constructors) { +// ConstructorInfo results[] = +// new ConstructorInfo[constructors.length + 1]; +// System.arraycopy(constructors, 0, results, 0, constructors.length); +// results[constructors.length] = constructor; +// constructors = results; +// this.info = null; +// } +// +// } + + + /** + *

        Add a new field to the fields associated with the + * Descriptor that will be created from this metadata.

        + * + * @param field The field to be added + */ +// public void addField(FieldInfo field) { +// fields.add(field); +// } + + + /** + * Add a new notification to the set of notifications for this MBean. + * + * @param notification The new notification descriptor + */ + public void addNotification(NotificationInfo notification) { + + synchronized (notifications) { + NotificationInfo results[] = + new NotificationInfo[notifications.length + 1]; + System.arraycopy(notifications, 0, results, 0, + notifications.length); + results[notifications.length] = notification; + notifications = results; + this.info = null; + } + + } + + + /** + * Add a new operation to the set of operations for this MBean. + * + * @param operation The new operation descriptor + */ + public void addOperation(OperationInfo operation) { + operations.put(operation.getName(), operation); + } + + + /** + * Create and return a ModelMBean that has been + * preconfigured with the ModelMBeanInfo information + * for this managed bean, but is not associated with any particular + * managed resource. The returned ModelMBean will + * NOT have been registered with our + * MBeanServer. + * + * @exception InstanceNotFoundException if the managed resource + * object cannot be found + * @exception InvalidTargetObjectTypeException if our MBean cannot + * handle object references (should never happen) + * @exception MBeanException if a problem occurs instantiating the + * ModelMBean instance + * @exception RuntimeOperationsException if a JMX runtime error occurs + */ + public DynamicMBean createMBean() + throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException { + + return (createMBean(null)); + + } + + + /** + * Create and return a ModelMBean that has been + * preconfigured with the ModelMBeanInfo information + * for this managed bean, and is associated with the specified + * managed object instance. The returned ModelMBean + * will NOT have been registered with our + * MBeanServer. + * + * @param instance Instanced of the managed object, or null + * for no associated instance + * + * @exception InstanceNotFoundException if the managed resource + * object cannot be found + * @exception InvalidTargetObjectTypeException if our MBean cannot + * handle object references (should never happen) + * @exception MBeanException if a problem occurs instantiating the + * ModelMBean instance + * @exception RuntimeOperationsException if a JMX runtime error occurs + */ + public DynamicMBean createMBean(Object instance) + throws InstanceNotFoundException, + MBeanException, RuntimeOperationsException { + + BaseModelMBean mbean = null; + + // Load the ModelMBean implementation class + if(getClassName().equals(BASE_MBEAN)) { + // Skip introspection + mbean = new BaseModelMBean(); + } else { + Class clazz = null; + Exception ex = null; + try { + clazz = Class.forName(getClassName()); + } catch (Exception e) { + } + + if( clazz==null ) { + try { + ClassLoader cl= Thread.currentThread().getContextClassLoader(); + if ( cl != null) + clazz= cl.loadClass(getClassName()); + } catch (Exception e) { + ex=e; + } + } + + if( clazz==null) { + throw new MBeanException + (ex, "Cannot load ModelMBean class " + getClassName()); + } + try { + // Stupid - this will set the default minfo first.... + mbean = (BaseModelMBean) clazz.newInstance(); + } catch (RuntimeOperationsException e) { + throw e; + } catch (Exception e) { + throw new MBeanException + (e, "Cannot instantiate ModelMBean of class " + + getClassName()); + } + } + + mbean.setManagedBean(this); + + // Set the managed resource (if any) + try { + if (instance != null) + mbean.setManagedResource(instance, "ObjectReference"); + } catch (InstanceNotFoundException e) { + throw e; + } + return (mbean); + + } + + + /** + * Create and return a ModelMBeanInfo object that + * describes this entire managed bean. + */ + MBeanInfo getMBeanInfo() { + + // Return our cached information (if any) + if (info != null) + return (info); + + // Create subordinate information descriptors as required + AttributeInfo attrs[] = getAttributes(); + MBeanAttributeInfo attributes[] = + new MBeanAttributeInfo[attrs.length]; + for (int i = 0; i < attrs.length; i++) + attributes[i] = attrs[i].createAttributeInfo(); + + OperationInfo opers[] = getOperations(); + MBeanOperationInfo operations[] = + new MBeanOperationInfo[opers.length]; + for (int i = 0; i < opers.length; i++) + operations[i] = opers[i].createOperationInfo(); + + +// ConstructorInfo consts[] = getConstructors(); +// ModelMBeanConstructorInfo constructors[] = +// new ModelMBeanConstructorInfo[consts.length]; +// for (int i = 0; i < consts.length; i++) +// constructors[i] = consts[i].createConstructorInfo(); + + NotificationInfo notifs[] = getNotifications(); + MBeanNotificationInfo notifications[] = + new MBeanNotificationInfo[notifs.length]; + for (int i = 0; i < notifs.length; i++) + notifications[i] = notifs[i].createNotificationInfo(); + + + // Construct and return a new ModelMBeanInfo object + info = new MBeanInfo(getClassName(), + getDescription(), + attributes, + new MBeanConstructorInfo[] {}, + operations, + notifications); +// try { +// Descriptor descriptor = info.getMBeanDescriptor(); +// Iterator fields = getFields().iterator(); +// while (fields.hasNext()) { +// FieldInfo field = (FieldInfo) fields.next(); +// descriptor.setField(field.getName(), field.getValue()); +// } +// info.setMBeanDescriptor(descriptor); +// } catch (MBeanException e) { +// ; +// } + + return (info); + + } + + + /** + * Return a string representation of this managed bean. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("ManagedBean["); + sb.append("name="); + sb.append(name); + sb.append(", className="); + sb.append(className); + sb.append(", description="); + sb.append(description); + if (group != null) { + sb.append(", group="); + sb.append(group); + } + sb.append(", type="); + sb.append(type); + sb.append("]"); + return (sb.toString()); + + } + + Method getGetter(String aname, BaseModelMBean mbean, Object resource) + throws AttributeNotFoundException, MBeanException, ReflectionException { + // TODO: do we need caching ? JMX is for management, it's not supposed to require lots of performance. + Method m=null; // (Method)getAttMap.get( name ); + + if( m==null ) { + AttributeInfo attrInfo = (AttributeInfo)attributes.get(aname); + // Look up the actual operation to be used + if (attrInfo == null) + throw new AttributeNotFoundException(" Cannot find attribute " + aname + " for " + resource); + + String getMethod = attrInfo.getGetMethod(); + if (getMethod == null) + throw new AttributeNotFoundException("Cannot find attribute " + aname + " get method name"); + + Object object = null; + NoSuchMethodException exception = null; + try { + object = mbean; + m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); + } catch (NoSuchMethodException e) { + exception = e;; + } + if( m== null && resource != null ) { + try { + object = resource; + m = object.getClass().getMethod(getMethod, NO_ARGS_PARAM_SIG); + exception=null; + } catch (NoSuchMethodException e) { + exception = e; + } + } + if( exception != null ) + throw new ReflectionException(exception, + "Cannot find getter method " + getMethod); + //getAttMap.put( name, m ); + } + + return m; + } + + public Method getSetter(String aname, BaseModelMBean bean, Object resource) + throws AttributeNotFoundException, MBeanException, ReflectionException { + // Cache may be needed for getters, but it is a really bad idea for setters, this is far + // less frequent. + Method m=null;//(Method)setAttMap.get( name ); + + if( m==null ) { + AttributeInfo attrInfo = (AttributeInfo)attributes.get(aname); + if (attrInfo == null) + throw new AttributeNotFoundException(" Cannot find attribute " + aname); + + // Look up the actual operation to be used + String setMethod = attrInfo.getSetMethod(); + if (setMethod == null) + throw new AttributeNotFoundException("Cannot find attribute " + aname + " set method name"); + + String argType=attrInfo.getType(); + + Class signature[] = new Class[] { BaseModelMBean.getAttributeClass( argType ) }; + + Object object = null; + NoSuchMethodException exception = null; + try { + object = this; + m = object.getClass().getMethod(setMethod, signature); + } catch (NoSuchMethodException e) { + exception = e;; + } + if( m== null && resource != null ) { + try { + object = resource; + m = object.getClass().getMethod(setMethod, signature); + exception=null; + } catch (NoSuchMethodException e) { + exception = e; + } + } + if( exception != null ) + throw new ReflectionException(exception, + "Cannot find setter method " + setMethod + + " " + resource); + //setAttMap.put( name, m ); + } + + return m; + } + + public Method getInvoke(String aname, Object[] params, String[] signature, BaseModelMBean bean, Object resource) + throws MBeanException, ReflectionException { + Method method = null; + if (method == null) { + if (params == null) + params = new Object[0]; + if (signature == null) + signature = new String[0]; + if (params.length != signature.length) + throw new RuntimeOperationsException( + new IllegalArgumentException( + "Inconsistent arguments and signature"), + "Inconsistent arguments and signature"); + + // Acquire the ModelMBeanOperationInfo information for + // the requested operation + OperationInfo opInfo = (OperationInfo)operations.get(aname); + if (opInfo == null) + throw new MBeanException(new ServiceNotFoundException( + "Cannot find operation " + aname), + "Cannot find operation " + aname); + + // Prepare the signature required by Java reflection APIs + // FIXME - should we use the signature from opInfo? + Class types[] = new Class[signature.length]; + for (int i = 0; i < signature.length; i++) { + types[i] = BaseModelMBean.getAttributeClass(signature[i]); + } + + // Locate the method to be invoked, either in this MBean itself + // or in the corresponding managed resource + // FIXME - Accessible methods in superinterfaces? + Object object = null; + Exception exception = null; + try { + object = this; + method = object.getClass().getMethod(aname, types); + } catch (NoSuchMethodException e) { + exception = e; + ; + } + try { + if ((method == null) && (resource != null)) { + object = resource; + method = object.getClass().getMethod(aname, types); + } + } catch (NoSuchMethodException e) { + exception = e; + } + if (method == null) { + throw new ReflectionException(exception, "Cannot find method " + + aname + " with this signature"); + } + // invokeAttMap.put(mkey, method); + } + return method; + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/NotificationInfo.java b/java/org/apache/tomcat/util/modeler/NotificationInfo.java index f6c66f19e..e6b026f46 100644 --- a/java/org/apache/tomcat/util/modeler/NotificationInfo.java +++ b/java/org/apache/tomcat/util/modeler/NotificationInfo.java @@ -1,140 +1,140 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.Serializable; - -import javax.management.MBeanNotificationInfo; - - -/** - *

        Internal configuration information for a Notification - * descriptor.

        - * - * @author Craig R. McClanahan - * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ - */ - -public class NotificationInfo extends FeatureInfo implements Serializable { - static final long serialVersionUID = -6319885418912650856L; - - // ----------------------------------------------------- Instance Variables - - - /** - * The ModelMBeanNotificationInfo object that corresponds - * to this NotificationInfo instance. - */ - transient MBeanNotificationInfo info = null; - protected String notifTypes[] = new String[0]; - - // ------------------------------------------------------------- Properties - - - /** - * Override the description property setter. - * - * @param description The new description - */ - public void setDescription(String description) { - super.setDescription(description); - this.info = null; - } - - - /** - * Override the name property setter. - * - * @param name The new name - */ - public void setName(String name) { - super.setName(name); - this.info = null; - } - - - /** - * The set of notification types for this MBean. - */ - public String[] getNotifTypes() { - return (this.notifTypes); - } - - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new notification type to the set managed by an MBean. - * - * @param notifType The new notification type - */ - public void addNotifType(String notifType) { - - synchronized (notifTypes) { - String results[] = new String[notifTypes.length + 1]; - System.arraycopy(notifTypes, 0, results, 0, notifTypes.length); - results[notifTypes.length] = notifType; - notifTypes = results; - this.info = null; - } - - } - - - /** - * Create and return a ModelMBeanNotificationInfo object that - * corresponds to the attribute described by this instance. - */ - public MBeanNotificationInfo createNotificationInfo() { - - // Return our cached information (if any) - if (info != null) - return (info); - - // Create and return a new information object - info = new MBeanNotificationInfo - (getNotifTypes(), getName(), getDescription()); - //Descriptor descriptor = info.getDescriptor(); - //addFields(descriptor); - //info.setDescriptor(descriptor); - return (info); - - } - - - /** - * Return a string representation of this notification descriptor. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("NotificationInfo["); - sb.append("name="); - sb.append(name); - sb.append(", description="); - sb.append(description); - sb.append(", notifTypes="); - sb.append(notifTypes.length); - sb.append("]"); - return (sb.toString()); - - } - - -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanNotificationInfo; + + +/** + *

        Internal configuration information for a Notification + * descriptor.

        + * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class NotificationInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = -6319885418912650856L; + + // ----------------------------------------------------- Instance Variables + + + /** + * The ModelMBeanNotificationInfo object that corresponds + * to this NotificationInfo instance. + */ + transient MBeanNotificationInfo info = null; + protected String notifTypes[] = new String[0]; + + // ------------------------------------------------------------- Properties + + + /** + * Override the description property setter. + * + * @param description The new description + */ + public void setDescription(String description) { + super.setDescription(description); + this.info = null; + } + + + /** + * Override the name property setter. + * + * @param name The new name + */ + public void setName(String name) { + super.setName(name); + this.info = null; + } + + + /** + * The set of notification types for this MBean. + */ + public String[] getNotifTypes() { + return (this.notifTypes); + } + + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new notification type to the set managed by an MBean. + * + * @param notifType The new notification type + */ + public void addNotifType(String notifType) { + + synchronized (notifTypes) { + String results[] = new String[notifTypes.length + 1]; + System.arraycopy(notifTypes, 0, results, 0, notifTypes.length); + results[notifTypes.length] = notifType; + notifTypes = results; + this.info = null; + } + + } + + + /** + * Create and return a ModelMBeanNotificationInfo object that + * corresponds to the attribute described by this instance. + */ + public MBeanNotificationInfo createNotificationInfo() { + + // Return our cached information (if any) + if (info != null) + return (info); + + // Create and return a new information object + info = new MBeanNotificationInfo + (getNotifTypes(), getName(), getDescription()); + //Descriptor descriptor = info.getDescriptor(); + //addFields(descriptor); + //info.setDescriptor(descriptor); + return (info); + + } + + + /** + * Return a string representation of this notification descriptor. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("NotificationInfo["); + sb.append("name="); + sb.append(name); + sb.append(", description="); + sb.append(description); + sb.append(", notifTypes="); + sb.append(notifTypes.length); + sb.append("]"); + return (sb.toString()); + + } + + +} diff --git a/java/org/apache/tomcat/util/modeler/OperationInfo.java b/java/org/apache/tomcat/util/modeler/OperationInfo.java index 6874d2207..db2da015c 100644 --- a/java/org/apache/tomcat/util/modeler/OperationInfo.java +++ b/java/org/apache/tomcat/util/modeler/OperationInfo.java @@ -1,160 +1,160 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.Serializable; - -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; - - -/** - *

        Internal configuration information for an Operation - * descriptor.

        - * - * @author Craig R. McClanahan - */ -public class OperationInfo extends FeatureInfo implements Serializable { - static final long serialVersionUID = 4418342922072614875L; - // ----------------------------------------------------------- Constructors - - - /** - * Standard zero-arguments constructor. - */ - public OperationInfo() { - - super(); - - } - - // ----------------------------------------------------- Instance Variables - - protected String impact = "UNKNOWN"; - protected String role = "operation"; - protected ParameterInfo parameters[] = new ParameterInfo[0]; - - - // ------------------------------------------------------------- Properties - - /** - * The "impact" of this operation, which should be a (case-insensitive) - * string value "ACTION", "ACTION_INFO", "INFO", or "UNKNOWN". - */ - public String getImpact() { - return (this.impact); - } - - public void setImpact(String impact) { - if (impact == null) - this.impact = null; - else - this.impact = impact.toUpperCase(); - } - - - /** - * The role of this operation ("getter", "setter", "operation", or - * "constructor"). - */ - public String getRole() { - return (this.role); - } - - public void setRole(String role) { - this.role = role; - } - - - /** - * The fully qualified Java class name of the return type for this - * operation. - */ - public String getReturnType() { - if(type == null) { - type = "void"; - } - return type; - } - - public void setReturnType(String returnType) { - this.type = returnType; - } - - /** - * The set of parameters for this operation. - */ - public ParameterInfo[] getSignature() { - return (this.parameters); - } - - // --------------------------------------------------------- Public Methods - - - /** - * Add a new parameter to the set of arguments for this operation. - * - * @param parameter The new parameter descriptor - */ - public void addParameter(ParameterInfo parameter) { - - synchronized (parameters) { - ParameterInfo results[] = new ParameterInfo[parameters.length + 1]; - System.arraycopy(parameters, 0, results, 0, parameters.length); - results[parameters.length] = parameter; - parameters = results; - this.info = null; - } - - } - - - /** - * Create and return a ModelMBeanOperationInfo object that - * corresponds to the attribute described by this instance. - */ - MBeanOperationInfo createOperationInfo() { - - // Return our cached information (if any) - if (info == null) { - // Create and return a new information object - int impact = MBeanOperationInfo.UNKNOWN; - if ("ACTION".equals(getImpact())) - impact = MBeanOperationInfo.ACTION; - else if ("ACTION_INFO".equals(getImpact())) - impact = MBeanOperationInfo.ACTION_INFO; - else if ("INFO".equals(getImpact())) - impact = MBeanOperationInfo.INFO; - - info = new MBeanOperationInfo(getName(), getDescription(), - getMBeanParameterInfo(), - getReturnType(), impact); - } - return (MBeanOperationInfo)info; - } - - protected MBeanParameterInfo[] getMBeanParameterInfo() { - ParameterInfo params[] = getSignature(); - MBeanParameterInfo parameters[] = - new MBeanParameterInfo[params.length]; - for (int i = 0; i < params.length; i++) - parameters[i] = params[i].createParameterInfo(); - return parameters; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; + + +/** + *

        Internal configuration information for an Operation + * descriptor.

        + * + * @author Craig R. McClanahan + */ +public class OperationInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = 4418342922072614875L; + // ----------------------------------------------------------- Constructors + + + /** + * Standard zero-arguments constructor. + */ + public OperationInfo() { + + super(); + + } + + // ----------------------------------------------------- Instance Variables + + protected String impact = "UNKNOWN"; + protected String role = "operation"; + protected ParameterInfo parameters[] = new ParameterInfo[0]; + + + // ------------------------------------------------------------- Properties + + /** + * The "impact" of this operation, which should be a (case-insensitive) + * string value "ACTION", "ACTION_INFO", "INFO", or "UNKNOWN". + */ + public String getImpact() { + return (this.impact); + } + + public void setImpact(String impact) { + if (impact == null) + this.impact = null; + else + this.impact = impact.toUpperCase(); + } + + + /** + * The role of this operation ("getter", "setter", "operation", or + * "constructor"). + */ + public String getRole() { + return (this.role); + } + + public void setRole(String role) { + this.role = role; + } + + + /** + * The fully qualified Java class name of the return type for this + * operation. + */ + public String getReturnType() { + if(type == null) { + type = "void"; + } + return type; + } + + public void setReturnType(String returnType) { + this.type = returnType; + } + + /** + * The set of parameters for this operation. + */ + public ParameterInfo[] getSignature() { + return (this.parameters); + } + + // --------------------------------------------------------- Public Methods + + + /** + * Add a new parameter to the set of arguments for this operation. + * + * @param parameter The new parameter descriptor + */ + public void addParameter(ParameterInfo parameter) { + + synchronized (parameters) { + ParameterInfo results[] = new ParameterInfo[parameters.length + 1]; + System.arraycopy(parameters, 0, results, 0, parameters.length); + results[parameters.length] = parameter; + parameters = results; + this.info = null; + } + + } + + + /** + * Create and return a ModelMBeanOperationInfo object that + * corresponds to the attribute described by this instance. + */ + MBeanOperationInfo createOperationInfo() { + + // Return our cached information (if any) + if (info == null) { + // Create and return a new information object + int impact = MBeanOperationInfo.UNKNOWN; + if ("ACTION".equals(getImpact())) + impact = MBeanOperationInfo.ACTION; + else if ("ACTION_INFO".equals(getImpact())) + impact = MBeanOperationInfo.ACTION_INFO; + else if ("INFO".equals(getImpact())) + impact = MBeanOperationInfo.INFO; + + info = new MBeanOperationInfo(getName(), getDescription(), + getMBeanParameterInfo(), + getReturnType(), impact); + } + return (MBeanOperationInfo)info; + } + + protected MBeanParameterInfo[] getMBeanParameterInfo() { + ParameterInfo params[] = getSignature(); + MBeanParameterInfo parameters[] = + new MBeanParameterInfo[params.length]; + for (int i = 0; i < params.length; i++) + parameters[i] = params[i].createParameterInfo(); + return parameters; + } +} diff --git a/java/org/apache/tomcat/util/modeler/ParameterInfo.java b/java/org/apache/tomcat/util/modeler/ParameterInfo.java index f5c7cd942..c8e987190 100644 --- a/java/org/apache/tomcat/util/modeler/ParameterInfo.java +++ b/java/org/apache/tomcat/util/modeler/ParameterInfo.java @@ -1,59 +1,59 @@ -/* - * Copyright 1999,2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.Serializable; - -import javax.management.MBeanParameterInfo; - - -/** - *

        Internal configuration information for a Parameter - * descriptor.

        - * - * @author Craig R. McClanahan - * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ - */ - -public class ParameterInfo extends FeatureInfo implements Serializable { - static final long serialVersionUID = 2222796006787664020L; - // ----------------------------------------------------------- Constructors - - - /** - * Standard zero-arguments constructor. - */ - public ParameterInfo() { - super(); - } - - /** - * Create and return a MBeanParameterInfo object that - * corresponds to the parameter described by this instance. - */ - public MBeanParameterInfo createParameterInfo() { - - // Return our cached information (if any) - if (info == null) { - info = new MBeanParameterInfo - (getName(), getType(), getDescription()); - } - return (MBeanParameterInfo)info; - } -} +/* + * Copyright 1999,2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.Serializable; + +import javax.management.MBeanParameterInfo; + + +/** + *

        Internal configuration information for a Parameter + * descriptor.

        + * + * @author Craig R. McClanahan + * @version $Revision: 155428 $ $Date: 2005-02-26 14:12:25 +0100 (sam., 26 févr. 2005) $ + */ + +public class ParameterInfo extends FeatureInfo implements Serializable { + static final long serialVersionUID = 2222796006787664020L; + // ----------------------------------------------------------- Constructors + + + /** + * Standard zero-arguments constructor. + */ + public ParameterInfo() { + super(); + } + + /** + * Create and return a MBeanParameterInfo object that + * corresponds to the parameter described by this instance. + */ + public MBeanParameterInfo createParameterInfo() { + + // Return our cached information (if any) + if (info == null) { + info = new MBeanParameterInfo + (getName(), getType(), getDescription()); + } + return (MBeanParameterInfo)info; + } +} diff --git a/java/org/apache/tomcat/util/modeler/Registry.java b/java/org/apache/tomcat/util/modeler/Registry.java index 55de2dd55..42b896f1d 100644 --- a/java/org/apache/tomcat/util/modeler/Registry.java +++ b/java/org/apache/tomcat/util/modeler/Registry.java @@ -1,1034 +1,1034 @@ -/* - * Copyright 2001-2006 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.io.File; -import java.io.FileInputStream; -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Hashtable; -import java.util.Iterator; -import java.util.List; - -import javax.management.DynamicMBean; -import javax.management.MBeanAttributeInfo; -import javax.management.MBeanInfo; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanRegistration; -import javax.management.MBeanServer; -import javax.management.MBeanServerFactory; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.modules.ModelerSource; - -/* - Issues: - - exceptions - too many "throws Exception" - - double check the interfaces - - start removing the use of the experimental methods in tomcat, then remove - the methods ( before 1.1 final ) - - is the security enough to prevent Registry beeing used to avoid the permission - checks in the mbean server ? -*/ - -/** - * Registry for modeler MBeans. - * - * This is the main entry point into modeler. It provides methods to create - * and manipulate model mbeans and simplify their use. - * - * Starting with version 1.1, this is no longer a singleton and the static - * methods are strongly deprecated. In a container environment we can expect - * different applications to use different registries. - * - * This class is itself an mbean. - * - * IMPORTANT: public methods not marked with @since x.x are experimental or - * internal. Should not be used. - * - * @author Craig R. McClanahan - * @author Costin Manolache - */ -public class Registry implements RegistryMBean, MBeanRegistration { - /** - * The Log instance to which we will write our log messages. - */ - private static Log log = LogFactory.getLog(Registry.class); - - // Support for the factory methods - - /** Will be used to isolate different apps and enhance security. - */ - private static HashMap perLoaderRegistries=null; - - /** - * The registry instance created by our factory method the first time - * it is called. - */ - private static Registry registry = null; - - // Per registy fields - - /** - * The MBeanServer instance that we will use to register - * management beans. - */ - private MBeanServer server = null; - - /** - * The set of ManagedBean instances for the beans this registry - * knows about, keyed by name. - */ - private HashMap descriptors = new HashMap(); - - /** List of managed byeans, keyed by class name - */ - private HashMap descriptorsByClass = new HashMap(); - - // map to avoid duplicated searching or loading descriptors - private HashMap searchedPaths=new HashMap(); - - private Object guard; - - // Id - small ints to use array access. No reset on stop() - // Used for notifications - private Hashtable idDomains=new Hashtable(); - private Hashtable ids=new Hashtable(); - - - // ----------------------------------------------------------- Constructors - - /** - */ - public Registry() { - super(); - } - - // -------------------- Static methods -------------------- - // Factories - - /** - * Factory method to create (if necessary) and return our - * Registry instance. - * - * Use this method to obtain a Registry - all other static methods - * are deprecated and shouldn't be used. - * - * The current version uses a static - future versions could use - * the thread class loader. - * - * @param key Support for application isolation. If null, the context class - * loader will be used ( if setUseContextClassLoader is called ) or the - * default registry is returned. - * @param guard Prevent access to the registry by untrusted components - * - * @since 1.1 - */ - public synchronized static Registry getRegistry(Object key, Object guard) { - Registry localRegistry; - if( perLoaderRegistries!=null ) { - if( key==null ) - key=Thread.currentThread().getContextClassLoader(); - if( key != null ) { - localRegistry=(Registry)perLoaderRegistries.get(key); - if( localRegistry == null ) { - localRegistry=new Registry(); -// localRegistry.key=key; - localRegistry.guard=guard; - perLoaderRegistries.put( key, localRegistry ); - return localRegistry; - } - if( localRegistry.guard != null && - localRegistry.guard != guard ) { - return null; // XXX Should I throw a permission ex ? - } - return localRegistry; - } - } - - // static - if (registry == null) { - registry = new Registry(); - } - if( registry.guard != null && - registry.guard != guard ) { - return null; - } - return (registry); - } - - /** - * Allow containers to isolate apps. Can be called only once. - * It is highly recommended you call this method if using Registry in - * a container environment. The default is false for backward compatibility - * - * @param enable - * @since 1.1 - */ - public static void setUseContextClassLoader( boolean enable ) { - if( enable ) { - perLoaderRegistries=new HashMap(); - } - } - - // -------------------- Generic methods -------------------- - - /** Lifecycle method - clean up the registry metadata. - * Called from resetMetadata(). - * - * @since 1.1 - */ - public void stop() { - descriptorsByClass = new HashMap(); - descriptors = new HashMap(); - searchedPaths=new HashMap(); - } - - /** - * Load an extended mlet file. The source can be an URL, File or - * InputStream. - * - * All mbeans will be instantiated, registered and the attributes will be - * set. The result is a list of ObjectNames. - * - * @param source InputStream or URL of the file - * @param cl ClassLoader to be used to load the mbeans, or null to use the - * default JMX mechanism ( i.e. all registered loaders ) - * @return List of ObjectName for the loaded mbeans - * @throws Exception - * - * @since 1.1 - */ - public List loadMBeans( Object source, ClassLoader cl ) - throws Exception - { - return load("MbeansSource", source, null ); - } - - - /** Load descriptors. The source can be a File or URL or InputStream for the - * descriptors file. In the case of File and URL, if the extension is ".ser" - * a serialized version will be loaded. - * - * This method should be used to explicitely load metadata - but this is not - * required in most cases. The registerComponent() method will find metadata - * in the same pacakge. - * - * @param source - */ - public void loadMetadata(Object source ) throws Exception { - loadDescriptors( null, source, null ); - } - - /** Register a bean by creating a modeler mbean and adding it to the - * MBeanServer. - * - * If metadata is not loaded, we'll look up and read a file named - * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package - * or parent. - * - * If the bean is an instance of DynamicMBean. it's metadata will be converted - * to a model mbean and we'll wrap it - so modeler services will be supported - * - * If the metadata is still not found, introspection will be used to extract - * it automatically. - * - * If an mbean is already registered under this name, it'll be first - * unregistered. - * - * If the component implements MBeanRegistration, the methods will be called. - * If the method has a method "setRegistry" that takes a RegistryMBean as - * parameter, it'll be called with the current registry. - * - * - * @param bean Object to be registered - * @param oname Name used for registration - * @param type The type of the mbean, as declared in mbeans-descriptors. If - * null, the name of the class will be used. This can be used as a hint or - * by subclasses. - * - * @since 1.1 - */ - public void registerComponent(Object bean, String oname, String type) - throws Exception - { - registerComponent(bean, new ObjectName(oname), type); - } - - /** Unregister a component. We'll first check if it is registered, - * and mask all errors. This is mostly a helper. - * - * @param oname - * - * @since 1.1 - */ - public void unregisterComponent( String oname ) { - try { - unregisterComponent(new ObjectName(oname)); - } catch (MalformedObjectNameException e) { - log.info("Error creating object name " + e ); - } - } - - - /** Invoke a operation on a list of mbeans. Can be used to implement - * lifecycle operations. - * - * @param mbeans list of ObjectName on which we'll invoke the operations - * @param operation Name of the operation ( init, start, stop, etc) - * @param failFirst If false, exceptions will be ignored - * @throws Exception - * @since 1.1 - */ - public void invoke( List mbeans, String operation, boolean failFirst ) - throws Exception - { - if( mbeans==null ) { - return; - } - Iterator itr=mbeans.iterator(); - while(itr.hasNext()) { - Object current=itr.next(); - ObjectName oN=null; - try { - if( current instanceof ObjectName) { - oN=(ObjectName)current; - } - if( current instanceof String ) { - oN=new ObjectName( (String)current ); - } - if( oN==null ) { - continue; - } - if( getMethodInfo(oN, operation) == null) { - continue; - } - getMBeanServer().invoke(oN, operation, - new Object[] {}, new String[] {}); - - } catch( Exception t ) { - if( failFirst ) throw t; - log.info("Error initializing " + current + " " + t.toString()); - } - } - } - - // -------------------- ID registry -------------------- - - /** Return an int ID for faster access. Will be used for notifications - * and for other operations we want to optimize. - * - * @param domain Namespace - * @param name Type of the notification - * @return An unique id for the domain:name combination - * @since 1.1 - */ - public synchronized int getId( String domain, String name) { - if( domain==null) { - domain=""; - } - Hashtable domainTable=(Hashtable)idDomains.get( domain ); - if( domainTable == null ) { - domainTable=new Hashtable(); - idDomains.put( domain, domainTable); - } - if( name==null ) { - name=""; - } - Integer i=(Integer)domainTable.get(name); - - if( i!= null ) { - return i.intValue(); - } - - int id[]=(int [])ids.get( domain ); - if( id == null ) { - id=new int[1]; - ids.put( domain, id); - } - int code=id[0]++; - domainTable.put( name, new Integer( code )); - return code; - } - - // -------------------- Metadata -------------------- - // methods from 1.0 - - /** - * Add a new bean metadata to the set of beans known to this registry. - * This is used by internal components. - * - * @param bean The managed bean to be added - * @since 1.0 - */ - public void addManagedBean(ManagedBean bean) { - // XXX Use group + name - descriptors.put(bean.getName(), bean); - if( bean.getType() != null ) { - descriptorsByClass.put( bean.getType(), bean ); - } - } - - - /** - * Find and return the managed bean definition for the specified - * bean name, if any; otherwise return null. - * - * @param name Name of the managed bean to be returned. Since 1.1, both - * short names or the full name of the class can be used. - * @since 1.0 - */ - public ManagedBean findManagedBean(String name) { - // XXX Group ?? Use Group + Type - ManagedBean mb=((ManagedBean) descriptors.get(name)); - if( mb==null ) - mb=(ManagedBean)descriptorsByClass.get(name); - return mb; - } - - /** - * Return the set of bean names for all managed beans known to - * this registry. - * - * @since 1.0 - */ - public String[] findManagedBeans() { - return ((String[]) descriptors.keySet().toArray(new String[0])); - } - - - /** - * Return the set of bean names for all managed beans known to - * this registry that belong to the specified group. - * - * @param group Name of the group of interest, or null - * to select beans that do not belong to a group - * @since 1.0 - */ - public String[] findManagedBeans(String group) { - - ArrayList results = new ArrayList(); - Iterator items = descriptors.values().iterator(); - while (items.hasNext()) { - ManagedBean item = (ManagedBean) items.next(); - if ((group == null) && (item.getGroup() == null)) { - results.add(item.getName()); - } else if (group.equals(item.getGroup())) { - results.add(item.getName()); - } - } - String values[] = new String[results.size()]; - return ((String[]) results.toArray(values)); - - } - - - /** - * Remove an existing bean from the set of beans known to this registry. - * - * @param bean The managed bean to be removed - * @since 1.0 - */ - public void removeManagedBean(ManagedBean bean) { - // TODO: change this to use group/name - descriptors.remove(bean.getName()); - descriptorsByClass.remove( bean.getType()); - } - - // -------------------- Deprecated 1.0 methods -------------------- - - /** - * Factory method to create (if necessary) and return our - * MBeanServer instance. - * - * @since 1.0 - * @deprecated Use the instance method - */ - public static MBeanServer getServer() { - return Registry.getRegistry().getMBeanServer(); - } - - /** - * Set the MBeanServer to be utilized for our - * registered management beans. - * - * @param mbeanServer The new MBeanServer instance - * @since 1.0 - * @deprecated Use the instance method - */ - public static void setServer(MBeanServer mbeanServer) { - Registry.getRegistry().setMBeanServer(mbeanServer); - } - - /** - * Load the registry from the XML input found in the specified input - * stream. - * - * @param stream InputStream containing the registry configuration - * information - * - * @exception Exception if any parsing or processing error occurs - * @deprecated use normal class method instead - * @since 1.0 - */ - public static void loadRegistry(InputStream stream) throws Exception { - Registry registry = getRegistry(); - registry.loadMetadata(stream); - } - - /** Get a "singelton" registry, or one per thread if setUseContextLoader - * was called - * - * @deprecated Not enough info - use the method that takes CL and domain - * @since 1.0 - */ - public synchronized static Registry getRegistry() { - return getRegistry(null, null); - } - - // -------------------- Helpers -------------------- - - /** Get the type of an attribute of the object, from the metadata. - * - * @param oname - * @param attName - * @return null if metadata about the attribute is not found - * @since 1.1 - */ - public String getType( ObjectName oname, String attName ) - { - String type=null; - MBeanInfo info=null; - try { - info=server.getMBeanInfo(oname); - } catch (Exception e) { - log.info( "Can't find metadata for object" + oname ); - return null; - } - - MBeanAttributeInfo attInfo[]=info.getAttributes(); - for( int i=0; iMBeanServer
        instance. - * - */ - public synchronized MBeanServer getMBeanServer() { - long t1=System.currentTimeMillis(); - - if (server == null) { - if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { - server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); - if( log.isDebugEnabled() ) { - log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1 )); - } - } else { - server=MBeanServerFactory.createMBeanServer(); - if( log.isDebugEnabled() ) { - log.debug("Creating MBeanServer"+ (System.currentTimeMillis() - t1 )); - } - } - } - return (server); - } - - /** Find or load metadata. - */ - public ManagedBean findManagedBean(Object bean, Class beanClass, String type) - throws Exception - { - if( bean!=null && beanClass==null ) { - beanClass=bean.getClass(); - } - - if( type==null ) { - type=beanClass.getName(); - } - - // first look for existing descriptor - ManagedBean managed = findManagedBean(type); - - // Search for a descriptor in the same package - if( managed==null ) { - // check package and parent packages - if( log.isDebugEnabled() ) { - log.debug( "Looking for descriptor "); - } - findDescriptor( beanClass, type ); - - managed=findManagedBean(type); - } - - if( bean instanceof DynamicMBean ) { - if( log.isDebugEnabled() ) { - log.debug( "Dynamic mbean support "); - } - // Dynamic mbean - loadDescriptors("MbeansDescriptorsDynamicMBeanSource", - bean, type); - - managed=findManagedBean(type); - } - - // Still not found - use introspection - if( managed==null ) { - if( log.isDebugEnabled() ) { - log.debug( "Introspecting "); - } - - // introspection - loadDescriptors("MbeansDescriptorsIntrospectionSource", - beanClass, type); - - managed=findManagedBean(type); - if( managed==null ) { - log.warn( "No metadata found for " + type ); - return null; - } - managed.setName( type ); - addManagedBean(managed); - } - return managed; - } - - - /** EXPERIMENTAL Convert a string to object, based on type. Used by several - * components. We could provide some pluggability. It is here to keep - * things consistent and avoid duplication in other tasks - * - * @param type Fully qualified class name of the resulting value - * @param value String value to be converted - * @return Converted value - */ - public Object convertValue(String type, String value) - { - Object objValue=value; - - if( type==null || "java.lang.String".equals( type )) { - // string is default - objValue=value; - } else if( "javax.management.ObjectName".equals( type ) || - "ObjectName".equals( type )) { - try { - objValue=new ObjectName( value ); - } catch (MalformedObjectNameException e) { - return null; - } - } else if( "java.lang.Integer".equals( type ) || - "int".equals( type )) { - objValue=new Integer( value ); - } else if( "java.lang.Long".equals( type ) || - "long".equals( type )) { - objValue=new Long( value ); - } else if( "java.lang.Boolean".equals( type ) || - "boolean".equals( type )) { - objValue=new Boolean( value ); - } - return objValue; - } - - /** Experimental. - * - * @param sourceType - * @param source - * @param param - * @return List of descriptors - * @throws Exception - * @deprecated bad interface, mixing of metadata and mbeans - */ - public List load( String sourceType, Object source, String param) - throws Exception - { - if( log.isTraceEnabled()) { - log.trace("load " + source ); - } - String location=null; - String type=null; - Object inputsource=null; - - if( source instanceof DynamicMBean ) { - sourceType="MbeansDescriptorsDynamicMBeanSource"; - inputsource=source; - } else if( source instanceof URL ) { - URL url=(URL)source; - location=url.toString(); - type=param; - inputsource=url.openStream(); - if( sourceType == null ) { - sourceType = sourceTypeFromExt(location); - } - } else if( source instanceof File ) { - location=((File)source).getAbsolutePath(); - inputsource=new FileInputStream((File)source); - type=param; - if( sourceType == null ) { - sourceType = sourceTypeFromExt(location); - } - } else if( source instanceof InputStream ) { - type=param; - inputsource=source; - } else if( source instanceof Class ) { - location=((Class)source).getName(); - type=param; - inputsource=source; - if( sourceType== null ) { - sourceType="MbeansDescriptorsIntrospectionSource"; - } - } - - if( sourceType==null ) { - sourceType="MbeansDescriptorsDigesterSource"; - } - ModelerSource ds=getModelerSource(sourceType); - List mbeans=ds.loadDescriptors(this, location, type, inputsource); - - return mbeans; - } - - private String sourceTypeFromExt( String s ) { - if( s.endsWith( ".ser")) { - return "MbeansDescriptorsSerSource"; - } - else if( s.endsWith(".xml")) { - return "MbeansDescriptorsDigesterSource"; - } - return null; - } - - /** Register a component - * XXX make it private - * - * @param bean - * @param oname - * @param type - * @throws Exception - */ - public void registerComponent(Object bean, ObjectName oname, String type) - throws Exception - { - if( log.isDebugEnabled() ) { - log.debug( "Managed= "+ oname); - } - - if( bean ==null ) { - log.error("Null component " + oname ); - return; - } - - try { - if( type==null ) { - type=bean.getClass().getName(); - } - - ManagedBean managed = findManagedBean(bean.getClass(), type); - - // The real mbean is created and registered - DynamicMBean mbean = managed.createMBean(bean); - - if( getMBeanServer().isRegistered( oname )) { - if( log.isDebugEnabled()) { - log.debug("Unregistering existing component " + oname ); - } - getMBeanServer().unregisterMBean( oname ); - } - - getMBeanServer().registerMBean( mbean, oname); - } catch( Exception ex) { - log.error("Error registering " + oname, ex ); - throw ex; - } - } - - /** Lookup the component descriptor in the package and - * in the parent packages. - * - * @param packageName - */ - public void loadDescriptors( String packageName, ClassLoader classLoader ) { - String res=packageName.replace( '.', '/'); - - if( log.isTraceEnabled() ) { - log.trace("Finding descriptor " + res ); - } - - if( searchedPaths.get( packageName ) != null ) { - return; - } - String descriptors=res + "/mbeans-descriptors.ser"; - - URL dURL=classLoader.getResource( descriptors ); - - if( dURL == null ) { - descriptors=res + "/mbeans-descriptors.xml"; - dURL=classLoader.getResource( descriptors ); - } - if( dURL == null ) { - return; - } - - log.debug( "Found " + dURL); - searchedPaths.put( packageName, dURL ); - try { - if( descriptors.endsWith(".xml" )) - loadDescriptors("MbeansDescriptorsDigesterSource", dURL, null); - else - loadDescriptors("MbeansDescriptorsSerSource", dURL, null); - return; - } catch(Exception ex ) { - log.error("Error loading " + dURL); - } - - return; - } - - /** Experimental. Will become private, some code may still use it - * - * @param sourceType - * @param source - * @param param - * @throws Exception - * @deprecated - */ - public void loadDescriptors( String sourceType, Object source, String param) - throws Exception - { - List mbeans=load( sourceType, source, param ); - if( mbeans == null) return; - - Iterator itr=mbeans.iterator(); - while( itr.hasNext() ) { - Object mb=itr.next(); - if( mb instanceof ManagedBean) { - addManagedBean((ManagedBean)mb); - } - } - } - - /** Lookup the component descriptor in the package and - * in the parent packages. - * - * @param beanClass - * @param type - */ - private void findDescriptor( Class beanClass, String type ) { - if( type==null ) { - type=beanClass.getName(); - } - ClassLoader classLoader=null; - if( beanClass!=null ) { - classLoader=beanClass.getClassLoader(); - } - if( classLoader==null ) { - classLoader=Thread.currentThread().getContextClassLoader(); - } - if( classLoader==null ) { - classLoader=this.getClass().getClassLoader(); - } - - String className=type; - String pkg=className; - while( pkg.indexOf( ".") > 0 ) { - int lastComp=pkg.lastIndexOf( "."); - if( lastComp <= 0 ) return; - pkg=pkg.substring(0, lastComp); - if( searchedPaths.get( pkg ) != null ) { - return; - } - loadDescriptors(pkg, classLoader); - } - return; - } - - private ModelerSource getModelerSource( String type ) - throws Exception - { - if( type==null ) type="MbeansDescriptorsDigesterSource"; - if( type.indexOf( ".") < 0 ) { - type="org.apache.tomcat.util.modeler.modules." + type; - } - - Class c=Class.forName( type ); - ModelerSource ds=(ModelerSource)c.newInstance(); - return ds; - } - - - // -------------------- Registration -------------------- - - public ObjectName preRegister(MBeanServer server, - ObjectName name) throws Exception - { - this.server=server; - return name; - } - - public void postRegister(Boolean registrationDone) { - } - - public void preDeregister() throws Exception { - } - - public void postDeregister() { - } - - - - - // -------------------- DEPRECATED METHODS -------------------- - // May still be used in tomcat - // Never part of an official release - - /** Called by a registry or by the container to unload a loader - * @param loader - */ - public void unregisterRegistry(ClassLoader loader ) { - // XXX Cleanup ? - perLoaderRegistries.remove(loader); - } - - public ManagedBean findManagedBean(Class beanClass, String type) - throws Exception - { - return findManagedBean(null, beanClass, type); - } - - /** - * Set the MBeanServer to be utilized for our - * registered management beans. - * - * @param server The new MBeanServer instance - */ - public void setMBeanServer( MBeanServer server ) { - this.server=server; - } - - public void resetMetadata() { - stop(); - } - /** - * Load the registry from the XML input found in the specified input - * stream. - * - * @param source Source to be used to load. Can be an InputStream or URL. - * - * @exception Exception if any parsing or processing error occurs - */ - public void loadDescriptors( Object source ) - throws Exception - { - loadDescriptors("MbeansDescriptorsDigesterSource", source, null ); - } - - /** @deprecated - may still be used in code using pre-1.1 builds - */ - public void registerComponent(Object bean, String domain, String type, - String name) - throws Exception - { - StringBuffer sb=new StringBuffer(); - sb.append( domain ).append(":"); - sb.append( name ); - String nameStr=sb.toString(); - ObjectName oname=new ObjectName( nameStr ); - registerComponent(bean, oname, type ); - } - - - - // should be removed - public void unregisterComponent( String domain, String name ) { - try { - ObjectName oname=new ObjectName( domain + ":" + name ); - - // XXX remove from our tables. - getMBeanServer().unregisterMBean( oname ); - } catch( Throwable t ) { - log.error( "Error unregistering mbean ", t ); - } - } - - - /** - * Load the registry from a cached .ser file. This is typically 2-3 times - * faster than parsing the XML. - * - * @param source Source to be used to load. Can be an InputStream or URL. - * - * @exception Exception if any parsing or processing error occurs - * @deprecated Loaded automatically or using a File or Url ending in .ser - */ - public void loadCachedDescriptors( Object source ) - throws Exception - { - loadDescriptors("MbeansDescriptorsSerSource", source, null ); - } -} +/* + * Copyright 2001-2006 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.List; + +import javax.management.DynamicMBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanRegistration; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.ObjectName; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.modeler.modules.ModelerSource; + +/* + Issues: + - exceptions - too many "throws Exception" + - double check the interfaces + - start removing the use of the experimental methods in tomcat, then remove + the methods ( before 1.1 final ) + - is the security enough to prevent Registry beeing used to avoid the permission + checks in the mbean server ? +*/ + +/** + * Registry for modeler MBeans. + * + * This is the main entry point into modeler. It provides methods to create + * and manipulate model mbeans and simplify their use. + * + * Starting with version 1.1, this is no longer a singleton and the static + * methods are strongly deprecated. In a container environment we can expect + * different applications to use different registries. + * + * This class is itself an mbean. + * + * IMPORTANT: public methods not marked with @since x.x are experimental or + * internal. Should not be used. + * + * @author Craig R. McClanahan + * @author Costin Manolache + */ +public class Registry implements RegistryMBean, MBeanRegistration { + /** + * The Log instance to which we will write our log messages. + */ + private static Log log = LogFactory.getLog(Registry.class); + + // Support for the factory methods + + /** Will be used to isolate different apps and enhance security. + */ + private static HashMap perLoaderRegistries=null; + + /** + * The registry instance created by our factory method the first time + * it is called. + */ + private static Registry registry = null; + + // Per registy fields + + /** + * The MBeanServer instance that we will use to register + * management beans. + */ + private MBeanServer server = null; + + /** + * The set of ManagedBean instances for the beans this registry + * knows about, keyed by name. + */ + private HashMap descriptors = new HashMap(); + + /** List of managed byeans, keyed by class name + */ + private HashMap descriptorsByClass = new HashMap(); + + // map to avoid duplicated searching or loading descriptors + private HashMap searchedPaths=new HashMap(); + + private Object guard; + + // Id - small ints to use array access. No reset on stop() + // Used for notifications + private Hashtable idDomains=new Hashtable(); + private Hashtable ids=new Hashtable(); + + + // ----------------------------------------------------------- Constructors + + /** + */ + public Registry() { + super(); + } + + // -------------------- Static methods -------------------- + // Factories + + /** + * Factory method to create (if necessary) and return our + * Registry instance. + * + * Use this method to obtain a Registry - all other static methods + * are deprecated and shouldn't be used. + * + * The current version uses a static - future versions could use + * the thread class loader. + * + * @param key Support for application isolation. If null, the context class + * loader will be used ( if setUseContextClassLoader is called ) or the + * default registry is returned. + * @param guard Prevent access to the registry by untrusted components + * + * @since 1.1 + */ + public synchronized static Registry getRegistry(Object key, Object guard) { + Registry localRegistry; + if( perLoaderRegistries!=null ) { + if( key==null ) + key=Thread.currentThread().getContextClassLoader(); + if( key != null ) { + localRegistry=(Registry)perLoaderRegistries.get(key); + if( localRegistry == null ) { + localRegistry=new Registry(); +// localRegistry.key=key; + localRegistry.guard=guard; + perLoaderRegistries.put( key, localRegistry ); + return localRegistry; + } + if( localRegistry.guard != null && + localRegistry.guard != guard ) { + return null; // XXX Should I throw a permission ex ? + } + return localRegistry; + } + } + + // static + if (registry == null) { + registry = new Registry(); + } + if( registry.guard != null && + registry.guard != guard ) { + return null; + } + return (registry); + } + + /** + * Allow containers to isolate apps. Can be called only once. + * It is highly recommended you call this method if using Registry in + * a container environment. The default is false for backward compatibility + * + * @param enable + * @since 1.1 + */ + public static void setUseContextClassLoader( boolean enable ) { + if( enable ) { + perLoaderRegistries=new HashMap(); + } + } + + // -------------------- Generic methods -------------------- + + /** Lifecycle method - clean up the registry metadata. + * Called from resetMetadata(). + * + * @since 1.1 + */ + public void stop() { + descriptorsByClass = new HashMap(); + descriptors = new HashMap(); + searchedPaths=new HashMap(); + } + + /** + * Load an extended mlet file. The source can be an URL, File or + * InputStream. + * + * All mbeans will be instantiated, registered and the attributes will be + * set. The result is a list of ObjectNames. + * + * @param source InputStream or URL of the file + * @param cl ClassLoader to be used to load the mbeans, or null to use the + * default JMX mechanism ( i.e. all registered loaders ) + * @return List of ObjectName for the loaded mbeans + * @throws Exception + * + * @since 1.1 + */ + public List loadMBeans( Object source, ClassLoader cl ) + throws Exception + { + return load("MbeansSource", source, null ); + } + + + /** Load descriptors. The source can be a File or URL or InputStream for the + * descriptors file. In the case of File and URL, if the extension is ".ser" + * a serialized version will be loaded. + * + * This method should be used to explicitely load metadata - but this is not + * required in most cases. The registerComponent() method will find metadata + * in the same pacakge. + * + * @param source + */ + public void loadMetadata(Object source ) throws Exception { + loadDescriptors( null, source, null ); + } + + /** Register a bean by creating a modeler mbean and adding it to the + * MBeanServer. + * + * If metadata is not loaded, we'll look up and read a file named + * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package + * or parent. + * + * If the bean is an instance of DynamicMBean. it's metadata will be converted + * to a model mbean and we'll wrap it - so modeler services will be supported + * + * If the metadata is still not found, introspection will be used to extract + * it automatically. + * + * If an mbean is already registered under this name, it'll be first + * unregistered. + * + * If the component implements MBeanRegistration, the methods will be called. + * If the method has a method "setRegistry" that takes a RegistryMBean as + * parameter, it'll be called with the current registry. + * + * + * @param bean Object to be registered + * @param oname Name used for registration + * @param type The type of the mbean, as declared in mbeans-descriptors. If + * null, the name of the class will be used. This can be used as a hint or + * by subclasses. + * + * @since 1.1 + */ + public void registerComponent(Object bean, String oname, String type) + throws Exception + { + registerComponent(bean, new ObjectName(oname), type); + } + + /** Unregister a component. We'll first check if it is registered, + * and mask all errors. This is mostly a helper. + * + * @param oname + * + * @since 1.1 + */ + public void unregisterComponent( String oname ) { + try { + unregisterComponent(new ObjectName(oname)); + } catch (MalformedObjectNameException e) { + log.info("Error creating object name " + e ); + } + } + + + /** Invoke a operation on a list of mbeans. Can be used to implement + * lifecycle operations. + * + * @param mbeans list of ObjectName on which we'll invoke the operations + * @param operation Name of the operation ( init, start, stop, etc) + * @param failFirst If false, exceptions will be ignored + * @throws Exception + * @since 1.1 + */ + public void invoke( List mbeans, String operation, boolean failFirst ) + throws Exception + { + if( mbeans==null ) { + return; + } + Iterator itr=mbeans.iterator(); + while(itr.hasNext()) { + Object current=itr.next(); + ObjectName oN=null; + try { + if( current instanceof ObjectName) { + oN=(ObjectName)current; + } + if( current instanceof String ) { + oN=new ObjectName( (String)current ); + } + if( oN==null ) { + continue; + } + if( getMethodInfo(oN, operation) == null) { + continue; + } + getMBeanServer().invoke(oN, operation, + new Object[] {}, new String[] {}); + + } catch( Exception t ) { + if( failFirst ) throw t; + log.info("Error initializing " + current + " " + t.toString()); + } + } + } + + // -------------------- ID registry -------------------- + + /** Return an int ID for faster access. Will be used for notifications + * and for other operations we want to optimize. + * + * @param domain Namespace + * @param name Type of the notification + * @return An unique id for the domain:name combination + * @since 1.1 + */ + public synchronized int getId( String domain, String name) { + if( domain==null) { + domain=""; + } + Hashtable domainTable=(Hashtable)idDomains.get( domain ); + if( domainTable == null ) { + domainTable=new Hashtable(); + idDomains.put( domain, domainTable); + } + if( name==null ) { + name=""; + } + Integer i=(Integer)domainTable.get(name); + + if( i!= null ) { + return i.intValue(); + } + + int id[]=(int [])ids.get( domain ); + if( id == null ) { + id=new int[1]; + ids.put( domain, id); + } + int code=id[0]++; + domainTable.put( name, new Integer( code )); + return code; + } + + // -------------------- Metadata -------------------- + // methods from 1.0 + + /** + * Add a new bean metadata to the set of beans known to this registry. + * This is used by internal components. + * + * @param bean The managed bean to be added + * @since 1.0 + */ + public void addManagedBean(ManagedBean bean) { + // XXX Use group + name + descriptors.put(bean.getName(), bean); + if( bean.getType() != null ) { + descriptorsByClass.put( bean.getType(), bean ); + } + } + + + /** + * Find and return the managed bean definition for the specified + * bean name, if any; otherwise return null. + * + * @param name Name of the managed bean to be returned. Since 1.1, both + * short names or the full name of the class can be used. + * @since 1.0 + */ + public ManagedBean findManagedBean(String name) { + // XXX Group ?? Use Group + Type + ManagedBean mb=((ManagedBean) descriptors.get(name)); + if( mb==null ) + mb=(ManagedBean)descriptorsByClass.get(name); + return mb; + } + + /** + * Return the set of bean names for all managed beans known to + * this registry. + * + * @since 1.0 + */ + public String[] findManagedBeans() { + return ((String[]) descriptors.keySet().toArray(new String[0])); + } + + + /** + * Return the set of bean names for all managed beans known to + * this registry that belong to the specified group. + * + * @param group Name of the group of interest, or null + * to select beans that do not belong to a group + * @since 1.0 + */ + public String[] findManagedBeans(String group) { + + ArrayList results = new ArrayList(); + Iterator items = descriptors.values().iterator(); + while (items.hasNext()) { + ManagedBean item = (ManagedBean) items.next(); + if ((group == null) && (item.getGroup() == null)) { + results.add(item.getName()); + } else if (group.equals(item.getGroup())) { + results.add(item.getName()); + } + } + String values[] = new String[results.size()]; + return ((String[]) results.toArray(values)); + + } + + + /** + * Remove an existing bean from the set of beans known to this registry. + * + * @param bean The managed bean to be removed + * @since 1.0 + */ + public void removeManagedBean(ManagedBean bean) { + // TODO: change this to use group/name + descriptors.remove(bean.getName()); + descriptorsByClass.remove( bean.getType()); + } + + // -------------------- Deprecated 1.0 methods -------------------- + + /** + * Factory method to create (if necessary) and return our + * MBeanServer instance. + * + * @since 1.0 + * @deprecated Use the instance method + */ + public static MBeanServer getServer() { + return Registry.getRegistry().getMBeanServer(); + } + + /** + * Set the MBeanServer to be utilized for our + * registered management beans. + * + * @param mbeanServer The new MBeanServer instance + * @since 1.0 + * @deprecated Use the instance method + */ + public static void setServer(MBeanServer mbeanServer) { + Registry.getRegistry().setMBeanServer(mbeanServer); + } + + /** + * Load the registry from the XML input found in the specified input + * stream. + * + * @param stream InputStream containing the registry configuration + * information + * + * @exception Exception if any parsing or processing error occurs + * @deprecated use normal class method instead + * @since 1.0 + */ + public static void loadRegistry(InputStream stream) throws Exception { + Registry registry = getRegistry(); + registry.loadMetadata(stream); + } + + /** Get a "singelton" registry, or one per thread if setUseContextLoader + * was called + * + * @deprecated Not enough info - use the method that takes CL and domain + * @since 1.0 + */ + public synchronized static Registry getRegistry() { + return getRegistry(null, null); + } + + // -------------------- Helpers -------------------- + + /** Get the type of an attribute of the object, from the metadata. + * + * @param oname + * @param attName + * @return null if metadata about the attribute is not found + * @since 1.1 + */ + public String getType( ObjectName oname, String attName ) + { + String type=null; + MBeanInfo info=null; + try { + info=server.getMBeanInfo(oname); + } catch (Exception e) { + log.info( "Can't find metadata for object" + oname ); + return null; + } + + MBeanAttributeInfo attInfo[]=info.getAttributes(); + for( int i=0; iMBeanServer
        instance. + * + */ + public synchronized MBeanServer getMBeanServer() { + long t1=System.currentTimeMillis(); + + if (server == null) { + if( MBeanServerFactory.findMBeanServer(null).size() > 0 ) { + server=(MBeanServer)MBeanServerFactory.findMBeanServer(null).get(0); + if( log.isDebugEnabled() ) { + log.debug("Using existing MBeanServer " + (System.currentTimeMillis() - t1 )); + } + } else { + server=MBeanServerFactory.createMBeanServer(); + if( log.isDebugEnabled() ) { + log.debug("Creating MBeanServer"+ (System.currentTimeMillis() - t1 )); + } + } + } + return (server); + } + + /** Find or load metadata. + */ + public ManagedBean findManagedBean(Object bean, Class beanClass, String type) + throws Exception + { + if( bean!=null && beanClass==null ) { + beanClass=bean.getClass(); + } + + if( type==null ) { + type=beanClass.getName(); + } + + // first look for existing descriptor + ManagedBean managed = findManagedBean(type); + + // Search for a descriptor in the same package + if( managed==null ) { + // check package and parent packages + if( log.isDebugEnabled() ) { + log.debug( "Looking for descriptor "); + } + findDescriptor( beanClass, type ); + + managed=findManagedBean(type); + } + + if( bean instanceof DynamicMBean ) { + if( log.isDebugEnabled() ) { + log.debug( "Dynamic mbean support "); + } + // Dynamic mbean + loadDescriptors("MbeansDescriptorsDynamicMBeanSource", + bean, type); + + managed=findManagedBean(type); + } + + // Still not found - use introspection + if( managed==null ) { + if( log.isDebugEnabled() ) { + log.debug( "Introspecting "); + } + + // introspection + loadDescriptors("MbeansDescriptorsIntrospectionSource", + beanClass, type); + + managed=findManagedBean(type); + if( managed==null ) { + log.warn( "No metadata found for " + type ); + return null; + } + managed.setName( type ); + addManagedBean(managed); + } + return managed; + } + + + /** EXPERIMENTAL Convert a string to object, based on type. Used by several + * components. We could provide some pluggability. It is here to keep + * things consistent and avoid duplication in other tasks + * + * @param type Fully qualified class name of the resulting value + * @param value String value to be converted + * @return Converted value + */ + public Object convertValue(String type, String value) + { + Object objValue=value; + + if( type==null || "java.lang.String".equals( type )) { + // string is default + objValue=value; + } else if( "javax.management.ObjectName".equals( type ) || + "ObjectName".equals( type )) { + try { + objValue=new ObjectName( value ); + } catch (MalformedObjectNameException e) { + return null; + } + } else if( "java.lang.Integer".equals( type ) || + "int".equals( type )) { + objValue=new Integer( value ); + } else if( "java.lang.Long".equals( type ) || + "long".equals( type )) { + objValue=new Long( value ); + } else if( "java.lang.Boolean".equals( type ) || + "boolean".equals( type )) { + objValue=new Boolean( value ); + } + return objValue; + } + + /** Experimental. + * + * @param sourceType + * @param source + * @param param + * @return List of descriptors + * @throws Exception + * @deprecated bad interface, mixing of metadata and mbeans + */ + public List load( String sourceType, Object source, String param) + throws Exception + { + if( log.isTraceEnabled()) { + log.trace("load " + source ); + } + String location=null; + String type=null; + Object inputsource=null; + + if( source instanceof DynamicMBean ) { + sourceType="MbeansDescriptorsDynamicMBeanSource"; + inputsource=source; + } else if( source instanceof URL ) { + URL url=(URL)source; + location=url.toString(); + type=param; + inputsource=url.openStream(); + if( sourceType == null ) { + sourceType = sourceTypeFromExt(location); + } + } else if( source instanceof File ) { + location=((File)source).getAbsolutePath(); + inputsource=new FileInputStream((File)source); + type=param; + if( sourceType == null ) { + sourceType = sourceTypeFromExt(location); + } + } else if( source instanceof InputStream ) { + type=param; + inputsource=source; + } else if( source instanceof Class ) { + location=((Class)source).getName(); + type=param; + inputsource=source; + if( sourceType== null ) { + sourceType="MbeansDescriptorsIntrospectionSource"; + } + } + + if( sourceType==null ) { + sourceType="MbeansDescriptorsDigesterSource"; + } + ModelerSource ds=getModelerSource(sourceType); + List mbeans=ds.loadDescriptors(this, location, type, inputsource); + + return mbeans; + } + + private String sourceTypeFromExt( String s ) { + if( s.endsWith( ".ser")) { + return "MbeansDescriptorsSerSource"; + } + else if( s.endsWith(".xml")) { + return "MbeansDescriptorsDigesterSource"; + } + return null; + } + + /** Register a component + * XXX make it private + * + * @param bean + * @param oname + * @param type + * @throws Exception + */ + public void registerComponent(Object bean, ObjectName oname, String type) + throws Exception + { + if( log.isDebugEnabled() ) { + log.debug( "Managed= "+ oname); + } + + if( bean ==null ) { + log.error("Null component " + oname ); + return; + } + + try { + if( type==null ) { + type=bean.getClass().getName(); + } + + ManagedBean managed = findManagedBean(bean.getClass(), type); + + // The real mbean is created and registered + DynamicMBean mbean = managed.createMBean(bean); + + if( getMBeanServer().isRegistered( oname )) { + if( log.isDebugEnabled()) { + log.debug("Unregistering existing component " + oname ); + } + getMBeanServer().unregisterMBean( oname ); + } + + getMBeanServer().registerMBean( mbean, oname); + } catch( Exception ex) { + log.error("Error registering " + oname, ex ); + throw ex; + } + } + + /** Lookup the component descriptor in the package and + * in the parent packages. + * + * @param packageName + */ + public void loadDescriptors( String packageName, ClassLoader classLoader ) { + String res=packageName.replace( '.', '/'); + + if( log.isTraceEnabled() ) { + log.trace("Finding descriptor " + res ); + } + + if( searchedPaths.get( packageName ) != null ) { + return; + } + String descriptors=res + "/mbeans-descriptors.ser"; + + URL dURL=classLoader.getResource( descriptors ); + + if( dURL == null ) { + descriptors=res + "/mbeans-descriptors.xml"; + dURL=classLoader.getResource( descriptors ); + } + if( dURL == null ) { + return; + } + + log.debug( "Found " + dURL); + searchedPaths.put( packageName, dURL ); + try { + if( descriptors.endsWith(".xml" )) + loadDescriptors("MbeansDescriptorsDigesterSource", dURL, null); + else + loadDescriptors("MbeansDescriptorsSerSource", dURL, null); + return; + } catch(Exception ex ) { + log.error("Error loading " + dURL); + } + + return; + } + + /** Experimental. Will become private, some code may still use it + * + * @param sourceType + * @param source + * @param param + * @throws Exception + * @deprecated + */ + public void loadDescriptors( String sourceType, Object source, String param) + throws Exception + { + List mbeans=load( sourceType, source, param ); + if( mbeans == null) return; + + Iterator itr=mbeans.iterator(); + while( itr.hasNext() ) { + Object mb=itr.next(); + if( mb instanceof ManagedBean) { + addManagedBean((ManagedBean)mb); + } + } + } + + /** Lookup the component descriptor in the package and + * in the parent packages. + * + * @param beanClass + * @param type + */ + private void findDescriptor( Class beanClass, String type ) { + if( type==null ) { + type=beanClass.getName(); + } + ClassLoader classLoader=null; + if( beanClass!=null ) { + classLoader=beanClass.getClassLoader(); + } + if( classLoader==null ) { + classLoader=Thread.currentThread().getContextClassLoader(); + } + if( classLoader==null ) { + classLoader=this.getClass().getClassLoader(); + } + + String className=type; + String pkg=className; + while( pkg.indexOf( ".") > 0 ) { + int lastComp=pkg.lastIndexOf( "."); + if( lastComp <= 0 ) return; + pkg=pkg.substring(0, lastComp); + if( searchedPaths.get( pkg ) != null ) { + return; + } + loadDescriptors(pkg, classLoader); + } + return; + } + + private ModelerSource getModelerSource( String type ) + throws Exception + { + if( type==null ) type="MbeansDescriptorsDigesterSource"; + if( type.indexOf( ".") < 0 ) { + type="org.apache.tomcat.util.modeler.modules." + type; + } + + Class c=Class.forName( type ); + ModelerSource ds=(ModelerSource)c.newInstance(); + return ds; + } + + + // -------------------- Registration -------------------- + + public ObjectName preRegister(MBeanServer server, + ObjectName name) throws Exception + { + this.server=server; + return name; + } + + public void postRegister(Boolean registrationDone) { + } + + public void preDeregister() throws Exception { + } + + public void postDeregister() { + } + + + + + // -------------------- DEPRECATED METHODS -------------------- + // May still be used in tomcat + // Never part of an official release + + /** Called by a registry or by the container to unload a loader + * @param loader + */ + public void unregisterRegistry(ClassLoader loader ) { + // XXX Cleanup ? + perLoaderRegistries.remove(loader); + } + + public ManagedBean findManagedBean(Class beanClass, String type) + throws Exception + { + return findManagedBean(null, beanClass, type); + } + + /** + * Set the MBeanServer to be utilized for our + * registered management beans. + * + * @param server The new MBeanServer instance + */ + public void setMBeanServer( MBeanServer server ) { + this.server=server; + } + + public void resetMetadata() { + stop(); + } + /** + * Load the registry from the XML input found in the specified input + * stream. + * + * @param source Source to be used to load. Can be an InputStream or URL. + * + * @exception Exception if any parsing or processing error occurs + */ + public void loadDescriptors( Object source ) + throws Exception + { + loadDescriptors("MbeansDescriptorsDigesterSource", source, null ); + } + + /** @deprecated - may still be used in code using pre-1.1 builds + */ + public void registerComponent(Object bean, String domain, String type, + String name) + throws Exception + { + StringBuffer sb=new StringBuffer(); + sb.append( domain ).append(":"); + sb.append( name ); + String nameStr=sb.toString(); + ObjectName oname=new ObjectName( nameStr ); + registerComponent(bean, oname, type ); + } + + + + // should be removed + public void unregisterComponent( String domain, String name ) { + try { + ObjectName oname=new ObjectName( domain + ":" + name ); + + // XXX remove from our tables. + getMBeanServer().unregisterMBean( oname ); + } catch( Throwable t ) { + log.error( "Error unregistering mbean ", t ); + } + } + + + /** + * Load the registry from a cached .ser file. This is typically 2-3 times + * faster than parsing the XML. + * + * @param source Source to be used to load. Can be an InputStream or URL. + * + * @exception Exception if any parsing or processing error occurs + * @deprecated Loaded automatically or using a File or Url ending in .ser + */ + public void loadCachedDescriptors( Object source ) + throws Exception + { + loadDescriptors("MbeansDescriptorsSerSource", source, null ); + } +} diff --git a/java/org/apache/tomcat/util/modeler/RegistryMBean.java b/java/org/apache/tomcat/util/modeler/RegistryMBean.java index b77430135..35c971b91 100644 --- a/java/org/apache/tomcat/util/modeler/RegistryMBean.java +++ b/java/org/apache/tomcat/util/modeler/RegistryMBean.java @@ -1,138 +1,138 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler; - - -import java.util.List; - -/** - * Interface for modeler MBeans. - * - * This is the main entry point into modeler. It provides methods to create - * and manipulate model mbeans and simplify their use. - * - * Starting with version 1.1, this is no longer a singleton and the static - * methods are strongly deprecated. In a container environment we can expect - * different applications to use different registries. - * - * @author Craig R. McClanahan - * @author Costin Manolache - * - * @since 1.1 - */ -public interface RegistryMBean { - - /** - * Load an extended mlet file. The source can be an URL, File or - * InputStream. - * - * All mbeans will be instantiated, registered and the attributes will be - * set. The result is a list of ObjectNames. - * - * @param source InputStream or URL of the file - * @param cl ClassLoader to be used to load the mbeans, or null to use the - * default JMX mechanism ( i.e. all registered loaders ) - * @return List of ObjectName for the loaded mbeans - * @throws Exception - * - * @since 1.1 - */ - public List loadMBeans( Object source, ClassLoader cl ) throws Exception; - - /** Invoke an operation on a set of mbeans. - * - * @param mbeans List of ObjectNames - * @param operation Operation to perform. Typically "init" "start" "stop" or "destroy" - * @param failFirst Behavior in case of exceptions - if false we'll ignore - * errors - * @throws Exception - */ - public void invoke( List mbeans, String operation, boolean failFirst ) - throws Exception; - - /** Register a bean by creating a modeler mbean and adding it to the - * MBeanServer. - * - * If metadata is not loaded, we'll look up and read a file named - * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package - * or parent. - * - * If the bean is an instance of DynamicMBean. it's metadata will be converted - * to a model mbean and we'll wrap it - so modeler services will be supported - * - * If the metadata is still not found, introspection will be used to extract - * it automatically. - * - * If an mbean is already registered under this name, it'll be first - * unregistered. - * - * If the component implements MBeanRegistration, the methods will be called. - * If the method has a method "setRegistry" that takes a RegistryMBean as - * parameter, it'll be called with the current registry. - * - * - * @param bean Object to be registered - * @param oname Name used for registration - * @param type The type of the mbean, as declared in mbeans-descriptors. If - * null, the name of the class will be used. This can be used as a hint or - * by subclasses. - * - * @since 1.1 - */ - public void registerComponent(Object bean, String oname, String type) - throws Exception; - - /** Unregister a component. We'll first check if it is registered, - * and mask all errors. This is mostly a helper. - * - * @param oname - * - * @since 1.1 - */ - public void unregisterComponent( String oname ); - - - /** Return an int ID for faster access. Will be used for notifications - * and for other operations we want to optimize. - * - * @param domain Namespace - * @param name Type of the notification - * @return An unique id for the domain:name combination - * @since 1.1 - */ - public int getId( String domain, String name); - - - /** Reset all metadata cached by this registry. Should be called - * to support reloading. Existing mbeans will not be affected or modified. - * - * It will be called automatically if the Registry is unregistered. - * @since 1.1 - */ - public void stop(); - - /** Load descriptors. The source can be a File, URL pointing to an - * mbeans-descriptors.xml. - * - * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will - * be used. - * - * @param source - */ - public void loadMetadata(Object source ) throws Exception; -} +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler; + + +import java.util.List; + +/** + * Interface for modeler MBeans. + * + * This is the main entry point into modeler. It provides methods to create + * and manipulate model mbeans and simplify their use. + * + * Starting with version 1.1, this is no longer a singleton and the static + * methods are strongly deprecated. In a container environment we can expect + * different applications to use different registries. + * + * @author Craig R. McClanahan + * @author Costin Manolache + * + * @since 1.1 + */ +public interface RegistryMBean { + + /** + * Load an extended mlet file. The source can be an URL, File or + * InputStream. + * + * All mbeans will be instantiated, registered and the attributes will be + * set. The result is a list of ObjectNames. + * + * @param source InputStream or URL of the file + * @param cl ClassLoader to be used to load the mbeans, or null to use the + * default JMX mechanism ( i.e. all registered loaders ) + * @return List of ObjectName for the loaded mbeans + * @throws Exception + * + * @since 1.1 + */ + public List loadMBeans( Object source, ClassLoader cl ) throws Exception; + + /** Invoke an operation on a set of mbeans. + * + * @param mbeans List of ObjectNames + * @param operation Operation to perform. Typically "init" "start" "stop" or "destroy" + * @param failFirst Behavior in case of exceptions - if false we'll ignore + * errors + * @throws Exception + */ + public void invoke( List mbeans, String operation, boolean failFirst ) + throws Exception; + + /** Register a bean by creating a modeler mbean and adding it to the + * MBeanServer. + * + * If metadata is not loaded, we'll look up and read a file named + * "mbeans-descriptors.ser" or "mbeans-descriptors.xml" in the same package + * or parent. + * + * If the bean is an instance of DynamicMBean. it's metadata will be converted + * to a model mbean and we'll wrap it - so modeler services will be supported + * + * If the metadata is still not found, introspection will be used to extract + * it automatically. + * + * If an mbean is already registered under this name, it'll be first + * unregistered. + * + * If the component implements MBeanRegistration, the methods will be called. + * If the method has a method "setRegistry" that takes a RegistryMBean as + * parameter, it'll be called with the current registry. + * + * + * @param bean Object to be registered + * @param oname Name used for registration + * @param type The type of the mbean, as declared in mbeans-descriptors. If + * null, the name of the class will be used. This can be used as a hint or + * by subclasses. + * + * @since 1.1 + */ + public void registerComponent(Object bean, String oname, String type) + throws Exception; + + /** Unregister a component. We'll first check if it is registered, + * and mask all errors. This is mostly a helper. + * + * @param oname + * + * @since 1.1 + */ + public void unregisterComponent( String oname ); + + + /** Return an int ID for faster access. Will be used for notifications + * and for other operations we want to optimize. + * + * @param domain Namespace + * @param name Type of the notification + * @return An unique id for the domain:name combination + * @since 1.1 + */ + public int getId( String domain, String name); + + + /** Reset all metadata cached by this registry. Should be called + * to support reloading. Existing mbeans will not be affected or modified. + * + * It will be called automatically if the Registry is unregistered. + * @since 1.1 + */ + public void stop(); + + /** Load descriptors. The source can be a File, URL pointing to an + * mbeans-descriptors.xml. + * + * Also ( experimental for now ) a ClassLoader - in which case META-INF/ will + * be used. + * + * @param source + */ + public void loadMetadata(Object source ) throws Exception; +} diff --git a/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd b/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd index 231203e8f..f2d9c61b6 100644 --- a/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd +++ b/java/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd @@ -1,233 +1,233 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java index 508ea8df4..1228a7b44 100644 --- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDOMSource.java @@ -1,302 +1,302 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler.modules; - -import java.io.InputStream; -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.DomUtil; -import org.apache.tomcat.util.modeler.AttributeInfo; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.NotificationInfo; -import org.apache.tomcat.util.modeler.OperationInfo; -import org.apache.tomcat.util.modeler.ParameterInfo; -import org.apache.tomcat.util.modeler.Registry; -import org.w3c.dom.Document; -import org.w3c.dom.Node; - - -public class MbeansDescriptorsDOMSource extends ModelerSource -{ - private static Log log = LogFactory.getLog(MbeansDescriptorsDOMSource.class); - - Registry registry; - String location; - String type; - Object source; - List mbeans=new ArrayList(); - - public void setRegistry(Registry reg) { - this.registry=reg; - } - - public void setLocation( String loc ) { - this.location=loc; - } - - /** Used if a single component is loaded - * - * @param type - */ - public void setType( String type ) { - this.type=type; - } - - public void setSource( Object source ) { - this.source=source; - } - - public List loadDescriptors( Registry registry, String location, - String type, Object source) - throws Exception - { - setRegistry(registry); - setLocation(location); - setType(type); - setSource(source); - execute(); - return mbeans; - } - - public void execute() throws Exception { - if( registry==null ) registry=Registry.getRegistry(); - - try { - InputStream stream=(InputStream)source; - long t1=System.currentTimeMillis(); - Document doc=DomUtil.readXml(stream); - // Ignore for now the name of the root element - Node descriptorsN=doc.getDocumentElement(); - //Node descriptorsN=DomUtil.getChild(doc, "mbeans-descriptors"); - if( descriptorsN == null ) { - log.error("No descriptors found"); - return; - } - - Node firstMbeanN=null; - if( "mbean".equals( descriptorsN.getNodeName() ) ) { - firstMbeanN=descriptorsN; - } else { - firstMbeanN=DomUtil.getChild(descriptorsN, "mbean"); - } - - if( firstMbeanN==null ) { - log.error(" No mbean tags "); - return; - } - - // Process each element - for (Node mbeanN = firstMbeanN; mbeanN != null; - mbeanN= DomUtil.getNext(mbeanN)) - { - - // Create a new managed bean info - ManagedBean managed=new ManagedBean(); - DomUtil.setAttributes(managed, mbeanN); - Node firstN; - - // Process descriptor subnode - /*Node mbeanDescriptorN = - DomUtil.getChild(mbeanN, "descriptor"); - if (mbeanDescriptorN != null) { - Node firstFieldN = - DomUtil.getChild(mbeanDescriptorN, "field"); - for (Node fieldN = firstFieldN; fieldN != null; - fieldN = DomUtil.getNext(fieldN)) { - FieldInfo fi = new FieldInfo(); - DomUtil.setAttributes(fi, fieldN); - managed.addField(fi); - } - }*/ - - // process attribute nodes - firstN=DomUtil.getChild( mbeanN, "attribute"); - for (Node descN = firstN; descN != null; - descN = DomUtil.getNext( descN )) - { - - // Create new attribute info - AttributeInfo ai=new AttributeInfo(); - DomUtil.setAttributes(ai, descN); - - // Process descriptor subnode - /*Node descriptorN = - DomUtil.getChild(descN, "descriptor"); - if (descriptorN != null) { - Node firstFieldN = - DomUtil.getChild(descriptorN, "field"); - for (Node fieldN = firstFieldN; fieldN != null; - fieldN = DomUtil.getNext(fieldN)) { - FieldInfo fi = new FieldInfo(); - DomUtil.setAttributes(fi, fieldN); - ai.addField(fi); - } - } - */ - - // Add this info to our managed bean info - managed.addAttribute( ai ); - if (log.isTraceEnabled()) { - log.trace("Create attribute " + ai); - } - - } - - // process constructor nodes - /* - firstN=DomUtil.getChild( mbeanN, "constructor"); - for (Node descN = firstN; descN != null; - descN = DomUtil.getNext( descN )) { - - // Create new constructor info - ConstructorInfo ci=new ConstructorInfo(); - DomUtil.setAttributes(ci, descN); - - // Process descriptor subnode - Node firstDescriptorN = - DomUtil.getChild(descN, "descriptor"); - if (firstDescriptorN != null) { - Node firstFieldN = - DomUtil.getChild(firstDescriptorN, "field"); - for (Node fieldN = firstFieldN; fieldN != null; - fieldN = DomUtil.getNext(fieldN)) { - FieldInfo fi = new FieldInfo(); - DomUtil.setAttributes(fi, fieldN); - ci.addField(fi); - } - } - - // Process parameter subnodes - Node firstParamN=DomUtil.getChild( descN, "parameter"); - for (Node paramN = firstParamN; paramN != null; - paramN = DomUtil.getNext(paramN)) - { - ParameterInfo pi=new ParameterInfo(); - DomUtil.setAttributes(pi, paramN); - ci.addParameter( pi ); - } - - // Add this info to our managed bean info - managed.addConstructor( ci ); - if (log.isTraceEnabled()) { - log.trace("Create constructor " + ci); - } - - }*/ - - // process notification nodes - firstN=DomUtil.getChild( mbeanN, "notification"); - for (Node descN = firstN; descN != null; - descN = DomUtil.getNext( descN )) - { - - // Create new notification info - NotificationInfo ni=new NotificationInfo(); - DomUtil.setAttributes(ni, descN); - - // Process descriptor subnode - /*Node firstDescriptorN = - DomUtil.getChild(descN, "descriptor"); - if (firstDescriptorN != null) { - Node firstFieldN = - DomUtil.getChild(firstDescriptorN, "field"); - for (Node fieldN = firstFieldN; fieldN != null; - fieldN = DomUtil.getNext(fieldN)) { - FieldInfo fi = new FieldInfo(); - DomUtil.setAttributes(fi, fieldN); - ni.addField(fi); - } - }*/ - - // Process notification-type subnodes - Node firstParamN=DomUtil.getChild( descN, "notification-type"); - for (Node paramN = firstParamN; paramN != null; - paramN = DomUtil.getNext(paramN)) - { - ni.addNotifType( DomUtil.getContent(paramN) ); - } - - // Add this info to our managed bean info - managed.addNotification( ni ); - if (log.isTraceEnabled()) { - log.trace("Created notification " + ni); - } - - } - - // process operation nodes - firstN=DomUtil.getChild( mbeanN, "operation"); - for (Node descN = firstN; descN != null; - descN = DomUtil.getNext( descN )) - - { - - // Create new operation info - OperationInfo oi=new OperationInfo(); - DomUtil.setAttributes(oi, descN); - - // Process descriptor subnode - /*Node firstDescriptorN = - DomUtil.getChild(descN, "descriptor"); - if (firstDescriptorN != null) { - Node firstFieldN = - DomUtil.getChild(firstDescriptorN, "field"); - for (Node fieldN = firstFieldN; fieldN != null; - fieldN = DomUtil.getNext(fieldN)) { - FieldInfo fi = new FieldInfo(); - DomUtil.setAttributes(fi, fieldN); - oi.addField(fi); - } - }*/ - - // Process parameter subnodes - Node firstParamN=DomUtil.getChild( descN, "parameter"); - for (Node paramN = firstParamN; paramN != null; - paramN = DomUtil.getNext(paramN)) - { - ParameterInfo pi=new ParameterInfo(); - DomUtil.setAttributes(pi, paramN); - if( log.isTraceEnabled()) - log.trace("Add param " + pi.getName()); - oi.addParameter( pi ); - } - - // Add this info to our managed bean info - managed.addOperation( oi ); - if( log.isTraceEnabled()) { - log.trace("Create operation " + oi); - } - - } - - // Add the completed managed bean info to the registry - //registry.addManagedBean(managed); - mbeans.add( managed ); - - } - - long t2=System.currentTimeMillis(); - log.debug( "Reading descriptors ( dom ) " + (t2-t1)); - } catch( Exception ex ) { - log.error( "Error reading descriptors ", ex); - } - } -} +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler.modules; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.DomUtil; +import org.apache.tomcat.util.modeler.AttributeInfo; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.NotificationInfo; +import org.apache.tomcat.util.modeler.OperationInfo; +import org.apache.tomcat.util.modeler.ParameterInfo; +import org.apache.tomcat.util.modeler.Registry; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + + +public class MbeansDescriptorsDOMSource extends ModelerSource +{ + private static Log log = LogFactory.getLog(MbeansDescriptorsDOMSource.class); + + Registry registry; + String location; + String type; + Object source; + List mbeans=new ArrayList(); + + public void setRegistry(Registry reg) { + this.registry=reg; + } + + public void setLocation( String loc ) { + this.location=loc; + } + + /** Used if a single component is loaded + * + * @param type + */ + public void setType( String type ) { + this.type=type; + } + + public void setSource( Object source ) { + this.source=source; + } + + public List loadDescriptors( Registry registry, String location, + String type, Object source) + throws Exception + { + setRegistry(registry); + setLocation(location); + setType(type); + setSource(source); + execute(); + return mbeans; + } + + public void execute() throws Exception { + if( registry==null ) registry=Registry.getRegistry(); + + try { + InputStream stream=(InputStream)source; + long t1=System.currentTimeMillis(); + Document doc=DomUtil.readXml(stream); + // Ignore for now the name of the root element + Node descriptorsN=doc.getDocumentElement(); + //Node descriptorsN=DomUtil.getChild(doc, "mbeans-descriptors"); + if( descriptorsN == null ) { + log.error("No descriptors found"); + return; + } + + Node firstMbeanN=null; + if( "mbean".equals( descriptorsN.getNodeName() ) ) { + firstMbeanN=descriptorsN; + } else { + firstMbeanN=DomUtil.getChild(descriptorsN, "mbean"); + } + + if( firstMbeanN==null ) { + log.error(" No mbean tags "); + return; + } + + // Process each element + for (Node mbeanN = firstMbeanN; mbeanN != null; + mbeanN= DomUtil.getNext(mbeanN)) + { + + // Create a new managed bean info + ManagedBean managed=new ManagedBean(); + DomUtil.setAttributes(managed, mbeanN); + Node firstN; + + // Process descriptor subnode + /*Node mbeanDescriptorN = + DomUtil.getChild(mbeanN, "descriptor"); + if (mbeanDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(mbeanDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + managed.addField(fi); + } + }*/ + + // process attribute nodes + firstN=DomUtil.getChild( mbeanN, "attribute"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + { + + // Create new attribute info + AttributeInfo ai=new AttributeInfo(); + DomUtil.setAttributes(ai, descN); + + // Process descriptor subnode + /*Node descriptorN = + DomUtil.getChild(descN, "descriptor"); + if (descriptorN != null) { + Node firstFieldN = + DomUtil.getChild(descriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ai.addField(fi); + } + } + */ + + // Add this info to our managed bean info + managed.addAttribute( ai ); + if (log.isTraceEnabled()) { + log.trace("Create attribute " + ai); + } + + } + + // process constructor nodes + /* + firstN=DomUtil.getChild( mbeanN, "constructor"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) { + + // Create new constructor info + ConstructorInfo ci=new ConstructorInfo(); + DomUtil.setAttributes(ci, descN); + + // Process descriptor subnode + Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ci.addField(fi); + } + } + + // Process parameter subnodes + Node firstParamN=DomUtil.getChild( descN, "parameter"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ParameterInfo pi=new ParameterInfo(); + DomUtil.setAttributes(pi, paramN); + ci.addParameter( pi ); + } + + // Add this info to our managed bean info + managed.addConstructor( ci ); + if (log.isTraceEnabled()) { + log.trace("Create constructor " + ci); + } + + }*/ + + // process notification nodes + firstN=DomUtil.getChild( mbeanN, "notification"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + { + + // Create new notification info + NotificationInfo ni=new NotificationInfo(); + DomUtil.setAttributes(ni, descN); + + // Process descriptor subnode + /*Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + ni.addField(fi); + } + }*/ + + // Process notification-type subnodes + Node firstParamN=DomUtil.getChild( descN, "notification-type"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ni.addNotifType( DomUtil.getContent(paramN) ); + } + + // Add this info to our managed bean info + managed.addNotification( ni ); + if (log.isTraceEnabled()) { + log.trace("Created notification " + ni); + } + + } + + // process operation nodes + firstN=DomUtil.getChild( mbeanN, "operation"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + + { + + // Create new operation info + OperationInfo oi=new OperationInfo(); + DomUtil.setAttributes(oi, descN); + + // Process descriptor subnode + /*Node firstDescriptorN = + DomUtil.getChild(descN, "descriptor"); + if (firstDescriptorN != null) { + Node firstFieldN = + DomUtil.getChild(firstDescriptorN, "field"); + for (Node fieldN = firstFieldN; fieldN != null; + fieldN = DomUtil.getNext(fieldN)) { + FieldInfo fi = new FieldInfo(); + DomUtil.setAttributes(fi, fieldN); + oi.addField(fi); + } + }*/ + + // Process parameter subnodes + Node firstParamN=DomUtil.getChild( descN, "parameter"); + for (Node paramN = firstParamN; paramN != null; + paramN = DomUtil.getNext(paramN)) + { + ParameterInfo pi=new ParameterInfo(); + DomUtil.setAttributes(pi, paramN); + if( log.isTraceEnabled()) + log.trace("Add param " + pi.getName()); + oi.addParameter( pi ); + } + + // Add this info to our managed bean info + managed.addOperation( oi ); + if( log.isTraceEnabled()) { + log.trace("Create operation " + oi); + } + + } + + // Add the completed managed bean info to the registry + //registry.addManagedBean(managed); + mbeans.add( managed ); + + } + + long t2=System.currentTimeMillis(); + log.debug( "Reading descriptors ( dom ) " + (t2-t1)); + } catch( Exception ex ) { + log.error( "Error reading descriptors ", ex); + } + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java index c7645ef01..ce760922e 100644 --- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsDigesterSource.java @@ -1,235 +1,235 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.apache.tomcat.util.modeler.modules; - -import java.io.InputStream; -import java.net.URL; -import java.util.ArrayList; -import java.util.List; - -import org.apache.tomcat.util.digester.Digester; -import org.apache.tomcat.util.modeler.Registry; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -public class MbeansDescriptorsDigesterSource extends ModelerSource -{ - private static Log log = - LogFactory.getLog(MbeansDescriptorsDigesterSource.class); - - Registry registry; - String location; - String type; - Object source; - List mbeans=new ArrayList(); - - protected static Digester createDigester(Registry registry) { - - Digester digester = new Digester(); - digester.setNamespaceAware(false); - digester.setValidating(false); - URL url = Registry.getRegistry(null, null).getClass().getResource - ("/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd"); - digester.register - ("-//Apache Software Foundation//DTD Model MBeans Configuration File", - url.toString()); - - // Configure the parsing rules - digester.addObjectCreate - ("mbeans-descriptors/mbean", - "org.apache.tomcat.util.modeler.ManagedBean"); - digester.addSetProperties - ("mbeans-descriptors/mbean"); - digester.addSetNext - ("mbeans-descriptors/mbean", - "add", - "java.lang.Object"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/attribute", - "org.apache.tomcat.util.modeler.AttributeInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/attribute"); - digester.addSetNext - ("mbeans-descriptors/mbean/attribute", - "addAttribute", - "org.apache.tomcat.util.modeler.AttributeInfo"); - - /*digester.addObjectCreate - ("mbeans-descriptors/mbean/attribute/descriptor/field", - "org.apache.tomcat.util.modeler.FieldInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/attribute/descriptor/field"); - digester.addSetNext - ("mbeans-descriptors/mbean/attribute/descriptor/field", - "addField", - "org.apache.tomcat.util.modeler.FieldInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/constructor", - "org.apache.tomcat.util.modeler.ConstructorInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/constructor"); - digester.addSetNext - ("mbeans-descriptors/mbean/constructor", - "addConstructor", - "org.apache.tomcat.util.modeler.ConstructorInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/constructor/descriptor/field", - "org.apache.tomcat.util.modeler.FieldInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/constructor/descriptor/field"); - digester.addSetNext - ("mbeans-descriptors/mbean/constructor/descriptor/field", - "addField", - "org.apache.tomcat.util.modeler.FieldInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/constructor/parameter", - "org.apache.tomcat.util.modeler.ParameterInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/constructor/parameter"); - digester.addSetNext - ("mbeans-descriptors/mbean/constructor/parameter", - "addParameter", - "org.apache.tomcat.util.modeler.ParameterInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/descriptor/field", - "org.apache.tomcat.util.modeler.FieldInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/descriptor/field"); - digester.addSetNext - ("mbeans-descriptors/mbean/descriptor/field", - "addField", - "org.apache.tomcat.util.modeler.FieldInfo"); - */ - digester.addObjectCreate - ("mbeans-descriptors/mbean/notification", - "org.apache.tomcat.util.modeler.NotificationInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/notification"); - digester.addSetNext - ("mbeans-descriptors/mbean/notification", - "addNotification", - "org.apache.tomcat.util.modeler.NotificationInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/notification/descriptor/field", - "org.apache.tomcat.util.modeler.FieldInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/notification/descriptor/field"); - digester.addSetNext - ("mbeans-descriptors/mbean/notification/descriptor/field", - "addField", - "org.apache.tomcat.util.modeler.FieldInfo"); - - digester.addCallMethod - ("mbeans-descriptors/mbean/notification/notification-type", - "addNotifType", 0); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/operation", - "org.apache.tomcat.util.modeler.OperationInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/operation"); - digester.addSetNext - ("mbeans-descriptors/mbean/operation", - "addOperation", - "org.apache.tomcat.util.modeler.OperationInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/operation/descriptor/field", - "org.apache.tomcat.util.modeler.FieldInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/operation/descriptor/field"); - digester.addSetNext - ("mbeans-descriptors/mbean/operation/descriptor/field", - "addField", - "org.apache.tomcat.util.modeler.FieldInfo"); - - digester.addObjectCreate - ("mbeans-descriptors/mbean/operation/parameter", - "org.apache.tomcat.util.modeler.ParameterInfo"); - digester.addSetProperties - ("mbeans-descriptors/mbean/operation/parameter"); - digester.addSetNext - ("mbeans-descriptors/mbean/operation/parameter", - "addParameter", - "org.apache.tomcat.util.modeler.ParameterInfo"); - - return digester; - - } - - public void setRegistry(Registry reg) { - this.registry=reg; - } - - public void setLocation( String loc ) { - this.location=loc; - } - - /** Used if a single component is loaded - * - * @param type - */ - public void setType( String type ) { - this.type=type; - } - - public void setSource( Object source ) { - this.source=source; - } - - public List loadDescriptors( Registry registry, String location, - String type, Object source) - throws Exception - { - setRegistry(registry); - setLocation(location); - setType(type); - setSource(source); - execute(); - return mbeans; - } - - public void execute() throws Exception { - if (registry == null) { - registry = Registry.getRegistry(null, null); - } - - InputStream stream = (InputStream) source; - - Digester digester = createDigester(registry); - // Push our registry object onto the stack - digester.push(mbeans); - - // Process the input file to configure our registry - try { - digester.parse(stream); - } catch (Exception e) { - log.error("Error digesting Registry data", e); - throw e; - } finally { - digester.reset(); - } - - } -} +/* + * Copyright 2001-2004 The Apache Software Foundation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package org.apache.tomcat.util.modeler.modules; + +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.apache.tomcat.util.digester.Digester; +import org.apache.tomcat.util.modeler.Registry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +public class MbeansDescriptorsDigesterSource extends ModelerSource +{ + private static Log log = + LogFactory.getLog(MbeansDescriptorsDigesterSource.class); + + Registry registry; + String location; + String type; + Object source; + List mbeans=new ArrayList(); + + protected static Digester createDigester(Registry registry) { + + Digester digester = new Digester(); + digester.setNamespaceAware(false); + digester.setValidating(false); + URL url = Registry.getRegistry(null, null).getClass().getResource + ("/org/apache/tomcat/util/modeler/mbeans-descriptors.dtd"); + digester.register + ("-//Apache Software Foundation//DTD Model MBeans Configuration File", + url.toString()); + + // Configure the parsing rules + digester.addObjectCreate + ("mbeans-descriptors/mbean", + "org.apache.tomcat.util.modeler.ManagedBean"); + digester.addSetProperties + ("mbeans-descriptors/mbean"); + digester.addSetNext + ("mbeans-descriptors/mbean", + "add", + "java.lang.Object"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/attribute", + "org.apache.tomcat.util.modeler.AttributeInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/attribute"); + digester.addSetNext + ("mbeans-descriptors/mbean/attribute", + "addAttribute", + "org.apache.tomcat.util.modeler.AttributeInfo"); + + /*digester.addObjectCreate + ("mbeans-descriptors/mbean/attribute/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/attribute/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/attribute/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor", + "org.apache.tomcat.util.modeler.ConstructorInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor", + "addConstructor", + "org.apache.tomcat.util.modeler.ConstructorInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/constructor/parameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/constructor/parameter"); + digester.addSetNext + ("mbeans-descriptors/mbean/constructor/parameter", + "addParameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + */ + digester.addObjectCreate + ("mbeans-descriptors/mbean/notification", + "org.apache.tomcat.util.modeler.NotificationInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/notification"); + digester.addSetNext + ("mbeans-descriptors/mbean/notification", + "addNotification", + "org.apache.tomcat.util.modeler.NotificationInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/notification/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/notification/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/notification/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addCallMethod + ("mbeans-descriptors/mbean/notification/notification-type", + "addNotifType", 0); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation", + "org.apache.tomcat.util.modeler.OperationInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation", + "addOperation", + "org.apache.tomcat.util.modeler.OperationInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation/descriptor/field", + "org.apache.tomcat.util.modeler.FieldInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation/descriptor/field"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation/descriptor/field", + "addField", + "org.apache.tomcat.util.modeler.FieldInfo"); + + digester.addObjectCreate + ("mbeans-descriptors/mbean/operation/parameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + digester.addSetProperties + ("mbeans-descriptors/mbean/operation/parameter"); + digester.addSetNext + ("mbeans-descriptors/mbean/operation/parameter", + "addParameter", + "org.apache.tomcat.util.modeler.ParameterInfo"); + + return digester; + + } + + public void setRegistry(Registry reg) { + this.registry=reg; + } + + public void setLocation( String loc ) { + this.location=loc; + } + + /** Used if a single component is loaded + * + * @param type + */ + public void setType( String type ) { + this.type=type; + } + + public void setSource( Object source ) { + this.source=source; + } + + public List loadDescriptors( Registry registry, String location, + String type, Object source) + throws Exception + { + setRegistry(registry); + setLocation(location); + setType(type); + setSource(source); + execute(); + return mbeans; + } + + public void execute() throws Exception { + if (registry == null) { + registry = Registry.getRegistry(null, null); + } + + InputStream stream = (InputStream) source; + + Digester digester = createDigester(registry); + // Push our registry object onto the stack + digester.push(mbeans); + + // Process the input file to configure our registry + try { + digester.parse(stream); + } catch (Exception e) { + log.error("Error digesting Registry data", e); + throw e; + } finally { + digester.reset(); + } + + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java index 4a21e222a..ca70ba6fd 100644 --- a/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansDescriptorsIntrospectionSource.java @@ -1,417 +1,417 @@ -/* - * Copyright 2001-2004 The Apache Software Foundation. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.modeler.modules; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.math.BigDecimal; -import java.math.BigInteger; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.List; - -import javax.management.ObjectName; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.modeler.AttributeInfo; -import org.apache.tomcat.util.modeler.ManagedBean; -import org.apache.tomcat.util.modeler.OperationInfo; -import org.apache.tomcat.util.modeler.ParameterInfo; -import org.apache.tomcat.util.modeler.Registry; - -public class MbeansDescriptorsIntrospectionSource extends ModelerSource -{ - private static Log log = LogFactory.getLog(MbeansDescriptorsIntrospectionSource.class); - - Registry registry; - String location; - String type; - Object source; - List mbeans=new ArrayList(); - - public void setRegistry(Registry reg) { - this.registry=reg; - } - - public void setLocation( String loc ) { - this.location=loc; - } - - /** Used if a single component is loaded - * - * @param type - */ - public void setType( String type ) { - this.type=type; - } - - public void setSource( Object source ) { - this.source=source; - } - - public List loadDescriptors( Registry registry, String location, - String type, Object source) - throws Exception - { - setRegistry(registry); - setLocation(location); - setType(type); - setSource(source); - execute(); - return mbeans; - } - - public void execute() throws Exception { - if( registry==null ) registry=Registry.getRegistry(); - try { - ManagedBean managed=createManagedBean(registry, null, (Class)source, type); - if( managed==null ) return; - managed.setName( type ); - - mbeans.add(managed); - - } catch( Exception ex ) { - log.error( "Error reading descriptors ", ex); - } - } - - - - // ------------ Implementation for non-declared introspection classes - - static Hashtable specialMethods=new Hashtable(); - static { - specialMethods.put( "preDeregister", ""); - specialMethods.put( "postDeregister", ""); - } - - private static String strArray[]=new String[0]; - private static ObjectName objNameArray[]=new ObjectName[0]; - // createMBean == registerClass + registerMBean - - private static Class[] supportedTypes = new Class[] { - Boolean.class, - Boolean.TYPE, - Byte.class, - Byte.TYPE, - Character.class, - Character.TYPE, - Short.class, - Short.TYPE, - Integer.class, - Integer.TYPE, - Long.class, - Long.TYPE, - Float.class, - Float.TYPE, - Double.class, - Double.TYPE, - String.class, - strArray.getClass(), - BigDecimal.class, - BigInteger.class, - ObjectName.class, - objNameArray.getClass(), - java.io.File.class, - }; - - /** - * Check if this class is one of the supported types. - * If the class is supported, returns true. Otherwise, - * returns false. - * @param ret The class to check - * @return boolean True if class is supported - */ - private boolean supportedType(Class ret) { - for (int i = 0; i < supportedTypes.length; i++) { - if (ret == supportedTypes[i]) { - return true; - } - } - if (isBeanCompatible(ret)) { - return true; - } - return false; - } - - /** - * Check if this class conforms to JavaBeans specifications. - * If the class is conformant, returns true. - * - * @param javaType The class to check - * @return boolean True if the class is compatible. - */ - protected boolean isBeanCompatible(Class javaType) { - // Must be a non-primitive and non array - if (javaType.isArray() || javaType.isPrimitive()) { - return false; - } - - // Anything in the java or javax package that - // does not have a defined mapping is excluded. - if (javaType.getName().startsWith("java.") || - javaType.getName().startsWith("javax.")) { - return false; - } - - try { - javaType.getConstructor(new Class[]{}); - } catch (java.lang.NoSuchMethodException e) { - return false; - } - - // Make sure superclass is compatible - Class superClass = javaType.getSuperclass(); - if (superClass != null && - superClass != java.lang.Object.class && - superClass != java.lang.Exception.class && - superClass != java.lang.Throwable.class) { - if (!isBeanCompatible(superClass)) { - return false; - } - } - return true; - } - - /** - * Process the methods and extract 'attributes', methods, etc - * - * @param realClass The class to process - * @param methods The methods to process - * @param attMap The attribute map (complete) - * @param getAttMap The readable attributess map - * @param setAttMap The settable attributes map - * @param invokeAttMap The invokable attributes map - */ - private void initMethods(Class realClass, - Method methods[], - Hashtable attMap, Hashtable getAttMap, - Hashtable setAttMap, Hashtable invokeAttMap) - { - for (int j = 0; j < methods.length; ++j) { - String name=methods[j].getName(); - - if( Modifier.isStatic(methods[j].getModifiers())) - continue; - if( ! Modifier.isPublic( methods[j].getModifiers() ) ) { - if( log.isDebugEnabled()) - log.debug("Not public " + methods[j] ); - continue; - } - if( methods[j].getDeclaringClass() == Object.class ) - continue; - Class params[]=methods[j].getParameterTypes(); - - if( name.startsWith( "get" ) && params.length==0) { - Class ret=methods[j].getReturnType(); - if( ! supportedType( ret ) ) { - if( log.isDebugEnabled() ) - log.debug("Unsupported type " + methods[j]); - continue; - } - name=unCapitalize( name.substring(3)); - - getAttMap.put( name, methods[j] ); - // just a marker, we don't use the value - attMap.put( name, methods[j] ); - } else if( name.startsWith( "is" ) && params.length==0) { - Class ret=methods[j].getReturnType(); - if( Boolean.TYPE != ret ) { - if( log.isDebugEnabled() ) - log.debug("Unsupported type " + methods[j] + " " + ret ); - continue; - } - name=unCapitalize( name.substring(2)); - - getAttMap.put( name, methods[j] ); - // just a marker, we don't use the value - attMap.put( name, methods[j] ); - - } else if( name.startsWith( "set" ) && params.length==1) { - if( ! supportedType( params[0] ) ) { - if( log.isDebugEnabled() ) - log.debug("Unsupported type " + methods[j] + " " + params[0]); - continue; - } - name=unCapitalize( name.substring(3)); - setAttMap.put( name, methods[j] ); - attMap.put( name, methods[j] ); - } else { - if( params.length == 0 ) { - if( specialMethods.get( methods[j].getName() ) != null ) - continue; - invokeAttMap.put( name, methods[j]); - } else { - boolean supported=true; - for( int i=0; i updateInterval ) { - lastUpdate=time; - try { - FileOutputStream fos=new FileOutputStream(location); - DomUtil.writeXml(document, fos); - } catch (TransformerException e) { - log.error( "Error writing"); - } catch (FileNotFoundException e) { - log.error( "Error writing" ,e ); - } - } - } - - private void processAttribute(MBeanServer server, - Node descN, String objectName ) { - String attName=DomUtil.getAttribute(descN, "name"); - String value=DomUtil.getAttribute(descN, "value"); - String type=null; // DomUtil.getAttribute(descN, "type"); - if( value==null ) { - // The value may be specified as CDATA - value=DomUtil.getContent(descN); - } - try { - if( log.isDebugEnabled()) - log.debug("Set attribute " + objectName + " " + attName + - " " + value); - ObjectName oname=new ObjectName(objectName); - // find the type - if( type==null ) - type=registry.getType( oname, attName ); - - if( type==null ) { - log.info("Can't find attribute " + objectName + " " + attName ); - - } else { - Object valueO=registry.convertValue( type, value); - server.setAttribute(oname, new Attribute(attName, valueO)); - } - } catch( Exception ex) { - log.error("Error processing attribute " + objectName + " " + - attName + " " + value, ex); - } - - } - - private void processArg(Node mbeanN) { - Node firstArgN=DomUtil.getChild(mbeanN, "arg" ); - // process all args - for (Node argN = firstArgN; argN != null; - argN = DomUtil.getNext( argN )) - { - String type=DomUtil.getAttribute(argN, "type"); - String value=DomUtil.getAttribute(argN, "value"); - if( value==null ) { - // The value may be specified as CDATA - value=DomUtil.getContent(argN); - } - } - } -} +package org.apache.tomcat.util.modeler.modules; + +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.management.Attribute; +import javax.management.MBeanServer; +import javax.management.ObjectName; +import javax.management.loading.MLet; +import javax.xml.transform.TransformerException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.DomUtil; +import org.apache.tomcat.util.modeler.AttributeInfo; +import org.apache.tomcat.util.modeler.BaseModelMBean; +import org.apache.tomcat.util.modeler.ManagedBean; +import org.apache.tomcat.util.modeler.Registry; +import org.w3c.dom.Document; +import org.w3c.dom.Node; + + +/** This will create mbeans based on a config file. + * The format is an extended version of MLET. + * + * Classloading. We don't support any explicit classloader tag. + * A ClassLoader is just an mbean ( it can be the standard MLetMBean or + * a custom one ). + * + * XXX add a special attribute to reference the loader mbean, + * XXX figure out how to deal with private loaders + */ +public class MbeansSource extends ModelerSource implements MbeansSourceMBean +{ + private static Log log = LogFactory.getLog(MbeansSource.class); + Registry registry; + String type; + + // true if we are during the original loading + boolean loading=true; + List mbeans=new ArrayList(); + static boolean loaderLoaded=false; + private Document document; + private HashMap object2Node = new HashMap(); + + long lastUpdate; + long updateInterval=10000; // 10s + + public void setRegistry(Registry reg) { + this.registry=reg; + } + + public void setLocation( String loc ) { + this.location=loc; + } + + /** Used if a single component is loaded + * + * @param type + */ + public void setType( String type ) { + this.type=type; + } + + public void setSource( Object source ) { + this.source=source; + } + + public Object getSource() { + return source; + } + + public String getLocation() { + return location; + } + + /** Return the list of mbeans created by this source. + * It can be used to implement runtime services. + */ + public List getMBeans() { + return mbeans; + } + + public List loadDescriptors( Registry registry, String location, + String type, Object source) + throws Exception + { + setRegistry(registry); + setLocation(location); + setType(type); + setSource(source); + execute(); + return mbeans; + } + + public void start() throws Exception { + registry.invoke(mbeans, "start", false); + } + + public void stop() throws Exception { + registry.invoke(mbeans, "stop", false); + } + + public void init() throws Exception { + if( mbeans==null) execute(); + if( registry==null ) registry=Registry.getRegistry(); + + registry.invoke(mbeans, "init", false); + } + + public void destroy() throws Exception { + registry.invoke(mbeans, "destroy", false); + } + + public void load() throws Exception { + execute(); // backward compat + } + + public void execute() throws Exception { + if( registry==null ) registry=Registry.getRegistry(); + try { + InputStream stream=getInputStream(); + long t1=System.currentTimeMillis(); + document = DomUtil.readXml(stream); + + // We don't care what the root node is. + Node descriptorsN=document.getDocumentElement(); + + if( descriptorsN == null ) { + log.error("No descriptors found"); + return; + } + + Node firstMbeanN=DomUtil.getChild(descriptorsN, null); + + if( firstMbeanN==null ) { + // maybe we have a single mlet + if( log.isDebugEnabled() ) + log.debug("No child " + descriptorsN); + firstMbeanN=descriptorsN; + } + + MBeanServer server=(MBeanServer)Registry.getServer(); + + // XXX Not very clean... Just a workaround + if( ! loaderLoaded ) { + // Register a loader that will be find ant classes. + ObjectName defaultLoader= new ObjectName("modeler", + "loader", "modeler"); + MLet mlet=new MLet( new URL[0], this.getClass().getClassLoader()); + server.registerMBean(mlet, defaultLoader); + loaderLoaded=true; + } + + // Process nodes + for (Node mbeanN = firstMbeanN; mbeanN != null; + mbeanN= DomUtil.getNext(mbeanN, null, Node.ELEMENT_NODE)) + { + String nodeName=mbeanN.getNodeName(); + + // mbean is the "official" name + if( "mbean".equals(nodeName) || "MLET".equals(nodeName) ) + { + String code=DomUtil.getAttribute( mbeanN, "code" ); + String objectName=DomUtil.getAttribute( mbeanN, "objectName" ); + if( objectName==null ) { + objectName=DomUtil.getAttribute( mbeanN, "name" ); + } + + if( log.isDebugEnabled()) + log.debug( "Processing mbean objectName=" + objectName + + " code=" + code); + + // args can be grouped in constructor or direct childs + Node constructorN=DomUtil.getChild(mbeanN, "constructor"); + if( constructorN == null ) constructorN=mbeanN; + + processArg(constructorN); + + try { + ObjectName oname=new ObjectName(objectName); + if( ! server.isRegistered( oname )) { + // We wrap everything in a model mbean. + // XXX need to support "StandardMBeanDescriptorsSource" + String modelMBean=BaseModelMBean.class.getName(); + server.createMBean(modelMBean, oname, + new Object[] { code, this}, + new String[] { String.class.getName(), + ModelerSource.class.getName() } + ); + mbeans.add(oname); + } + object2Node.put( oname, mbeanN ); + // XXX Arguments, loader !!! + } catch( Exception ex ) { + log.error( "Error creating mbean " + objectName, ex); + } + + Node firstAttN=DomUtil.getChild(mbeanN, "attribute"); + for (Node descN = firstAttN; descN != null; + descN = DomUtil.getNext( descN )) + { + processAttribute(server, descN, objectName); + } + } else if("jmx-operation".equals(nodeName) ) { + String name=DomUtil.getAttribute(mbeanN, "objectName"); + if( name==null ) + name=DomUtil.getAttribute(mbeanN, "name"); + + String operation=DomUtil.getAttribute(mbeanN, "operation"); + + if( log.isDebugEnabled()) + log.debug( "Processing invoke objectName=" + name + + " code=" + operation); + try { + ObjectName oname=new ObjectName(name); + + processArg( mbeanN ); + server.invoke( oname, operation, null, null); + } catch (Exception e) { + log.error( "Error in invoke " + name + " " + operation); + } + } + + ManagedBean managed=new ManagedBean(); + DomUtil.setAttributes(managed, mbeanN); + Node firstN; + + // process attribute info + firstN=DomUtil.getChild( mbeanN, "attribute"); + for (Node descN = firstN; descN != null; + descN = DomUtil.getNext( descN )) + { + AttributeInfo ci=new AttributeInfo(); + DomUtil.setAttributes(ci, descN); + managed.addAttribute( ci ); + } + + } + + long t2=System.currentTimeMillis(); + log.info( "Reading mbeans " + (t2-t1)); + loading=false; + } catch( Exception ex ) { + log.error( "Error reading mbeans ", ex); + } + } + + public void updateField( ObjectName oname, String name, + Object value ) + { + if( loading ) return; + // nothing by default + //log.info( "XXX UpdateField " + oname + " " + name + " " + value); + Node n=(Node)object2Node.get( oname ); + if( n == null ) { + log.info( "Node not found " + oname ); + return; + } + Node attNode=DomUtil.findChildWithAtt(n, "attribute", "name", name); + if( attNode == null ) { + // found no existing attribute with this name + attNode=n.getOwnerDocument().createElement("attribute"); + DomUtil.setAttribute(attNode, "name", name); + n.appendChild(attNode); + } + String oldValue=DomUtil.getAttribute(attNode, "value"); + if( oldValue != null ) { + // we'll convert all values to text content + DomUtil.removeAttribute( attNode, "value"); + } + DomUtil.setText(attNode, value.toString()); + + //store(); + } + + /** Store the mbeans. + * XXX add a background thread to store it periodically + */ + public void save() { + // XXX customize no often than ( based on standard descriptor ), etc. + // It doesn't work very well if we call this on each set att - + // the triger will work for the first att, but all others will be delayed + long time=System.currentTimeMillis(); + if( location!=null && + time - lastUpdate > updateInterval ) { + lastUpdate=time; + try { + FileOutputStream fos=new FileOutputStream(location); + DomUtil.writeXml(document, fos); + } catch (TransformerException e) { + log.error( "Error writing"); + } catch (FileNotFoundException e) { + log.error( "Error writing" ,e ); + } + } + } + + private void processAttribute(MBeanServer server, + Node descN, String objectName ) { + String attName=DomUtil.getAttribute(descN, "name"); + String value=DomUtil.getAttribute(descN, "value"); + String type=null; // DomUtil.getAttribute(descN, "type"); + if( value==null ) { + // The value may be specified as CDATA + value=DomUtil.getContent(descN); + } + try { + if( log.isDebugEnabled()) + log.debug("Set attribute " + objectName + " " + attName + + " " + value); + ObjectName oname=new ObjectName(objectName); + // find the type + if( type==null ) + type=registry.getType( oname, attName ); + + if( type==null ) { + log.info("Can't find attribute " + objectName + " " + attName ); + + } else { + Object valueO=registry.convertValue( type, value); + server.setAttribute(oname, new Attribute(attName, valueO)); + } + } catch( Exception ex) { + log.error("Error processing attribute " + objectName + " " + + attName + " " + value, ex); + } + + } + + private void processArg(Node mbeanN) { + Node firstArgN=DomUtil.getChild(mbeanN, "arg" ); + // process all args + for (Node argN = firstArgN; argN != null; + argN = DomUtil.getNext( argN )) + { + String type=DomUtil.getAttribute(argN, "type"); + String value=DomUtil.getAttribute(argN, "value"); + if( value==null ) { + // The value may be specified as CDATA + value=DomUtil.getContent(argN); + } + } + } +} diff --git a/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java b/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java index c577d842c..97923bedd 100644 --- a/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java +++ b/java/org/apache/tomcat/util/modeler/modules/MbeansSourceMBean.java @@ -1,42 +1,42 @@ -package org.apache.tomcat.util.modeler.modules; - -import java.util.List; - - -/** - * This mbean will load an extended mlet file ( similar in syntax with jboss ). - * It'll keep track of all attribute changes and update the file when attributes - * change. - */ -public interface MbeansSourceMBean -{ - /** Set the source to be used to load the mbeans - * - * @param source File or URL - */ - public void setSource( Object source ); - - public Object getSource(); - - /** Return the list of loaded mbeans names - * - * @return List of ObjectName - */ - public List getMBeans(); - - /** Load the mbeans from the source. Called automatically on init() - * - * @throws Exception - */ - public void load() throws Exception; - - /** Call the init method on all mbeans. Will call load if not done already - * - * @throws Exception - */ - public void init() throws Exception; - - /** Save the file. - */ - public void save(); -} +package org.apache.tomcat.util.modeler.modules; + +import java.util.List; + + +/** + * This mbean will load an extended mlet file ( similar in syntax with jboss ). + * It'll keep track of all attribute changes and update the file when attributes + * change. + */ +public interface MbeansSourceMBean +{ + /** Set the source to be used to load the mbeans + * + * @param source File or URL + */ + public void setSource( Object source ); + + public Object getSource(); + + /** Return the list of loaded mbeans names + * + * @return List of ObjectName + */ + public List getMBeans(); + + /** Load the mbeans from the source. Called automatically on init() + * + * @throws Exception + */ + public void load() throws Exception; + + /** Call the init method on all mbeans. Will call load if not done already + * + * @throws Exception + */ + public void init() throws Exception; + + /** Save the file. + */ + public void save(); +} diff --git a/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java b/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java index 35f21c891..7b8885fe5 100644 --- a/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java +++ b/java/org/apache/tomcat/util/modeler/modules/ModelerSource.java @@ -1,70 +1,70 @@ -package org.apache.tomcat.util.modeler.modules; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.net.URL; -import java.util.List; - -import javax.management.ObjectName; - -import org.apache.tomcat.util.modeler.Registry; - -/** Source for descriptor data. More sources can be added. - * - */ -public class ModelerSource { - protected Object source; - protected String location; - - /** Load data, returns a list of items. - * - * @param registry - * @param location - * @param type - * @param source Introspected object or some other source - * @throws Exception - */ - public List loadDescriptors( Registry registry, String location, - String type, Object source) - throws Exception - { - // TODO - return null; - } - - /** Callback from the BaseMBean to notify that an attribute has changed. - * Can be used to implement persistence. - * - * @param oname - * @param name - * @param value - */ - public void updateField( ObjectName oname, String name, - Object value ) { - // nothing by default - } - - public void store() { - // nothing - } - - protected InputStream getInputStream() throws IOException { - if( source instanceof URL ) { - URL url=(URL)source; - location=url.toString(); - return url.openStream(); - } else if( source instanceof File ) { - location=((File)source).getAbsolutePath(); - return new FileInputStream((File)source); - } else if( source instanceof String) { - location=(String)source; - return new FileInputStream((String)source); - } else if( source instanceof InputStream ) { - return (InputStream)source; - } - return null; - } - -} +package org.apache.tomcat.util.modeler.modules; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.List; + +import javax.management.ObjectName; + +import org.apache.tomcat.util.modeler.Registry; + +/** Source for descriptor data. More sources can be added. + * + */ +public class ModelerSource { + protected Object source; + protected String location; + + /** Load data, returns a list of items. + * + * @param registry + * @param location + * @param type + * @param source Introspected object or some other source + * @throws Exception + */ + public List loadDescriptors( Registry registry, String location, + String type, Object source) + throws Exception + { + // TODO + return null; + } + + /** Callback from the BaseMBean to notify that an attribute has changed. + * Can be used to implement persistence. + * + * @param oname + * @param name + * @param value + */ + public void updateField( ObjectName oname, String name, + Object value ) { + // nothing by default + } + + public void store() { + // nothing + } + + protected InputStream getInputStream() throws IOException { + if( source instanceof URL ) { + URL url=(URL)source; + location=url.toString(); + return url.openStream(); + } else if( source instanceof File ) { + location=((File)source).getAbsolutePath(); + return new FileInputStream((File)source); + } else if( source instanceof String) { + location=(String)source; + return new FileInputStream((String)source); + } else if( source instanceof InputStream ) { + return (InputStream)source; + } + return null; + } + +} diff --git a/java/org/apache/tomcat/util/modeler/modules/package.html b/java/org/apache/tomcat/util/modeler/modules/package.html index 7f1574d42..4a0f8616e 100644 --- a/java/org/apache/tomcat/util/modeler/modules/package.html +++ b/java/org/apache/tomcat/util/modeler/modules/package.html @@ -1,43 +1,43 @@ - - -org.apache.commons.modeler.modules - - -

        Implementation classes - should not be used directly. The API is not stable -but eventually the code will be refactored as a collection of mbeans that will be useable -( more or less ) indepedently.

        - -

        The MbeanDescriptors* classes are used to extract metadata from different sources. They -are result of few stages of refactoring - now they look very similar with ant tasks and are -close to normal mbeans, with an execute() method. DOM, SER, Introspection and Dynamic mbean -will load metadata from the corresponding sources. -

        - -

        MbeansSource will load an extended MLET file, similar with jboss. It is not completely -implemented - only modeler mbeans and dynamic mbeans are loaded. The important characteristic -is that all declared mbeans will be registered in the mbean server as model mbeans. For -regular java classes, the description will be used to construct the model mbean. DynamicMbeans -metadata will be converted to model mbean and the model mbean wrapper will be loaded.

        - -

        The goal of MbeansSource is to implement a simple persistence mechanism. Since all components -are model mbeans, we can detect all changes. The source will be loaded as DOM and modifications -will be made to the tree. The save() method will save the DOM tree - preserving all comments -and having only the changes that are needed.

        - -

        There are few remaining issues. First, we need to use the persistence metadata to avoid -saving transient fields ( we save an attribute when we detect a change - but we don't know -if this attribute should be saved ). The solution is to use the persistence fields in the -spec - with some reasonable defaults or patterns for introspection or backward compat. -

        - -

        Another problem is implementing adding and removing components. In catalina, a -factory is used to create the components, and save will operate on all mbeans. -For creation we need to also use a factory - using the "Type" as a parameter. This -will also work very well with Ant1.6 where we can use the component factory to -do a "natural" mapping ( i.e. mbeans can be treated as tasks, with attributes as -task attributes ). The second part can be solve by either using a parameter on -the factory method ( saveTo ? ), or by having a single mbeans source per domain. -

        - - - + + +org.apache.commons.modeler.modules + + +

        Implementation classes - should not be used directly. The API is not stable +but eventually the code will be refactored as a collection of mbeans that will be useable +( more or less ) indepedently.

        + +

        The MbeanDescriptors* classes are used to extract metadata from different sources. They +are result of few stages of refactoring - now they look very similar with ant tasks and are +close to normal mbeans, with an execute() method. DOM, SER, Introspection and Dynamic mbean +will load metadata from the corresponding sources. +

        + +

        MbeansSource will load an extended MLET file, similar with jboss. It is not completely +implemented - only modeler mbeans and dynamic mbeans are loaded. The important characteristic +is that all declared mbeans will be registered in the mbean server as model mbeans. For +regular java classes, the description will be used to construct the model mbean. DynamicMbeans +metadata will be converted to model mbean and the model mbean wrapper will be loaded.

        + +

        The goal of MbeansSource is to implement a simple persistence mechanism. Since all components +are model mbeans, we can detect all changes. The source will be loaded as DOM and modifications +will be made to the tree. The save() method will save the DOM tree - preserving all comments +and having only the changes that are needed.

        + +

        There are few remaining issues. First, we need to use the persistence metadata to avoid +saving transient fields ( we save an attribute when we detect a change - but we don't know +if this attribute should be saved ). The solution is to use the persistence fields in the +spec - with some reasonable defaults or patterns for introspection or backward compat. +

        + +

        Another problem is implementing adding and removing components. In catalina, a +factory is used to create the components, and save will operate on all mbeans. +For creation we need to also use a factory - using the "Type" as a parameter. This +will also work very well with Ant1.6 where we can use the component factory to +do a "natural" mapping ( i.e. mbeans can be treated as tasks, with attributes as +task attributes ). The second part can be solve by either using a parameter on +the factory method ( saveTo ? ), or by having a single mbeans source per domain. +

        + + + diff --git a/java/org/apache/tomcat/util/modeler/package.html b/java/org/apache/tomcat/util/modeler/package.html index 4d5aa6818..1f4c2bfc9 100644 --- a/java/org/apache/tomcat/util/modeler/package.html +++ b/java/org/apache/tomcat/util/modeler/package.html @@ -1,232 +1,232 @@ - - -Package Documentation for COMMONS-MODELER - - -

        The Modeler component of the Jakarta Commons subproject -offers convenient support for configuring and instantiating Model MBeans -(management beans), as described in the JMX Specification. It is typically -used within a server-based application that wants to expose management -features via JMX. See the - -JMX Specification (Version 1.1) for more information about Model MBeans -and other JMX concepts.

        - -

        Model MBeans are very powerful - and the JMX specification includes a -mechanism to use a standard JMX-provided base class to satisfy many of the -requirements, without having to create custom Model MBean implementation -classes yourself. However, one of the requirements in creating such a -Model MBean is to create the corresponding metadata information (i.e. an -implementation of the -javax.management.modelmbean.ModelMBeanInfo interface and its -corresponding subordinate interfaces). Creating this information can be -tedious and error prone. The Modeler package makes the process -much simpler, because the required information is constructed dynamically -from an easy-to-understand XML description of the metadata. Once you have -the metadata defined, and registered at runtime in the provided -Registry, Modeler also supports -convenient factory methods to instantiate new Model MBean instances for you. -

        - -

        The steps required to use Modeler in your server-based application are -described in detail below. You can find some simple usage code in the unit -tests that come with Modeler (in the src/test subdirectory of the -source distribution), and much more complex usage code in Tomcat 4.1 (in the -org.apache.catalina.mbeans package).

        . More advanced uses can -be found in Tomcat 5 and jakarta-tomcat-connectors. - - -

        1. Acquire a JMX Implementation

        - -

        Modeler has been tested with different JMX implementations: -

        - -

        After unpacking the release, you will need to ensure that the appropriate -JAR file (jmxri.jar or mx4j.jar) is included on your -compilation classpath, and in the classpath of your server application when it -is executed.

        - - -

        2. Create a Modeler Configuration File

        - -

        Modeler requires that you construct a configuration file that -describes the metadata ultimately need to construct the -javax.management.modelmbean.ModelMBeanInfo structure that is -required by JMX. Your XML file must conform to the -mbeans-descriptors.dtd -DTD that defines the acceptable structure.

        - -

        Fundamentally, you will be constructing an <mbean> -element for each type of Model MBean that a registry will know how to create. -Nested within this element will be other elements describing the constructors, -attributes, operations, and notifications associated with this MBean. See -the comments in the DTD for detailed information about the valid attributes -and their meanings.

        - -

        A simple example configuration file might include the following components -(abstracted from the real definitions found in Tomcat 4.1's use of Modeler): -

        -
        -
        -  <?xml version="1.0"?>
        -  <!DOCTYPE mbeans-descriptors PUBLIC
        -   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
        -   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
        -
        -  <mbeans-descriptors>
        -
        -    <!-- ... other MBean definitions ... -->
        -
        -    <mbean         name="Group"
        -              className="org.apache.catalina.mbeans.GroupMBean"
        -            description="Group from a user database"
        -                 domain="Users"
        -                  group="Group"
        -                   type="org.apache.catalina.Group">
        -
        -      <attribute   name="description"
        -            description="Description of this group"
        -                   type="java.lang.String"/>
        -
        -      <attribute   name="groupname"
        -            description="Group name of this group"
        -                   type="java.lang.String"/>
        -
        -      <attribute   name="roles"
        -            description="MBean Names of roles for this group"
        -                   type="java.lang.String[]"
        -              writeable="false"/>
        -
        -      <attribute   name="users"
        -            description="MBean Names of user members of this group"
        -                   type="java.lang.String[]"
        -              writeable="false"/>
        -
        -      <operation   name="addRole"
        -            description="Add a new authorized role for this group"
        -                 impact="ACTION"
        -             returnType="void">
        -        <parameter name="role"
        -            description="Role to be added"
        -                   type="java.lang.String"/>
        -      </operation>
        -
        -      <operation   name="removeRole"
        -            description="Remove an old authorized role for this group"
        -                 impact="ACTION"
        -             returnType="void">
        -        <parameter name="role"
        -            description="Role to be removed"
        -                   type="java.lang.String"/>
        -      </operation>
        -
        -      <operation   name="removeRoles"
        -            description="Remove all authorized roles for this group"
        -                 impact="ACTION"
        -             returnType="void">
        -      </operation>
        -
        -    </mbean>
        -
        -    <!-- ... other MBean definitions ... -->
        -
        -  </mbeans-descriptors>
        -
        -
        - -

        This MBean represents an instance of org.apache.catalina.Group, -which is an entity representing a group of users (with a shared set of security -roles that all users in the group inherit) in a user database. This MBean -advertises support for four attributes (description, groupname, roles, and -users) that roughly correspond to JavaBean properties. By default, attributes -are assumed to have read/write access. For this particular MBean, the roles -and users attributes are read-only (writeable="false"). Finally, -this MBean supports three operations (addRole, removeRole, and -removeRoles) that roughly correspond to JavaBean methods on the underlying -component.

        - -

        In general, Modeler provides a standard ModelMBean implementation -that simply passes on JMX calls on attributes and operations directly through -to the managed component that the ModelMBean is associated with. For special -case requirements, you can define a subclass of -BaseModelMBean that provides override -methods for one or more of these attributes (i.e. the property getter and/or -setter methods) and operations (i.e. direct method calls). - -

        For this particular MBean, a custom BaseModelMBean implementation subclass -is described (org.apache.catalina.mbeans.GroupMBean) is -configured. It was necessary in this particular case because several of the -underlying Catalina component's methods deal with internal objects or arrays of -objects, rather than just the Strings and primitives that are supported by all -JMX clients. Thus, the following method on the Group interface: -

        -
        -    public void addRole(Role role);
        -
        -

        is represented, in the MBean, by an addRole method that takes -a String argument representing the role name of the required role. The MBean's -implementation class acts as an adapter, and looks up the required Role -object (by name) before calling the addRole method on the -underlying Group instance within the Server.

        - - -

        3. Create Modeler Registry at Startup Time

        - -

        The metadata information, and the corresponding Model MBean factory, is -represented at runtime in an instance of Registry -whose contents are initialized from the configuration file prepared as was -described above. Typically, such a file will be included in the JAR file -containing the MBean implementation classes themselves, and loaded as follows: -

        -
        -    URL url= this.getClass().getResource
        -      ("/com/mycompany/mypackage/mbeans-descriptors.xml");
        -    Registry registry = Registry.getRegistry();
        -    registry.loadMetadata(url);
        -
        - -

        Besides using the configuration file, it is possible to configure the -registry metadata by hand, using the addManagedBean() and -removeManagedBean() methods. However, most users will find -the standard support for loading a configuration file to be convenient -and sufficient.

        - -

        Modeler will also look for a mbeans-descriptors.xml in the same package -with the class beeing registered and in its parent. If no metadata is found, -modeler will use a number of simple patterns, similar with the ones used by -ant, to determine a reasonable metadata

        - -

        In a future version we should also support xdoclet-based generation of the -descriptors

        - - -

        4. Instantiate Model MBeans As Needed

        - -

        When your server application needs to instantiate a new MBean and register -it with the corresponding MBeanServer, it can execute code like -this:

        - -
        -  Group group = ... managed component instance ...;
        -
        -  MBeanServer mserver = registry.getMBeanServer();
        -
        -  String oname="myDomain:type=Group,name=myGroup";
        -
        -  registry.registerComponent( group, oname, "Group" );
        -
        - -

        After the Model MBean has been created and registered, it is accessible to -JMX clients through the standard JMX client APIs. -

        - - - + + +Package Documentation for COMMONS-MODELER + + +

        The Modeler component of the Jakarta Commons subproject +offers convenient support for configuring and instantiating Model MBeans +(management beans), as described in the JMX Specification. It is typically +used within a server-based application that wants to expose management +features via JMX. See the + +JMX Specification (Version 1.1) for more information about Model MBeans +and other JMX concepts.

        + +

        Model MBeans are very powerful - and the JMX specification includes a +mechanism to use a standard JMX-provided base class to satisfy many of the +requirements, without having to create custom Model MBean implementation +classes yourself. However, one of the requirements in creating such a +Model MBean is to create the corresponding metadata information (i.e. an +implementation of the +javax.management.modelmbean.ModelMBeanInfo interface and its +corresponding subordinate interfaces). Creating this information can be +tedious and error prone. The Modeler package makes the process +much simpler, because the required information is constructed dynamically +from an easy-to-understand XML description of the metadata. Once you have +the metadata defined, and registered at runtime in the provided +Registry, Modeler also supports +convenient factory methods to instantiate new Model MBean instances for you. +

        + +

        The steps required to use Modeler in your server-based application are +described in detail below. You can find some simple usage code in the unit +tests that come with Modeler (in the src/test subdirectory of the +source distribution), and much more complex usage code in Tomcat 4.1 (in the +org.apache.catalina.mbeans package).

        . More advanced uses can +be found in Tomcat 5 and jakarta-tomcat-connectors. + + +

        1. Acquire a JMX Implementation

        + +

        Modeler has been tested with different JMX implementations: +

        + +

        After unpacking the release, you will need to ensure that the appropriate +JAR file (jmxri.jar or mx4j.jar) is included on your +compilation classpath, and in the classpath of your server application when it +is executed.

        + + +

        2. Create a Modeler Configuration File

        + +

        Modeler requires that you construct a configuration file that +describes the metadata ultimately need to construct the +javax.management.modelmbean.ModelMBeanInfo structure that is +required by JMX. Your XML file must conform to the +mbeans-descriptors.dtd +DTD that defines the acceptable structure.

        + +

        Fundamentally, you will be constructing an <mbean> +element for each type of Model MBean that a registry will know how to create. +Nested within this element will be other elements describing the constructors, +attributes, operations, and notifications associated with this MBean. See +the comments in the DTD for detailed information about the valid attributes +and their meanings.

        + +

        A simple example configuration file might include the following components +(abstracted from the real definitions found in Tomcat 4.1's use of Modeler): +

        +
        +
        +  <?xml version="1.0"?>
        +  <!DOCTYPE mbeans-descriptors PUBLIC
        +   "-//Apache Software Foundation//DTD Model MBeans Configuration File"
        +   "http://jakarta.apache.org/commons/dtds/mbeans-descriptors.dtd">
        +
        +  <mbeans-descriptors>
        +
        +    <!-- ... other MBean definitions ... -->
        +
        +    <mbean         name="Group"
        +              className="org.apache.catalina.mbeans.GroupMBean"
        +            description="Group from a user database"
        +                 domain="Users"
        +                  group="Group"
        +                   type="org.apache.catalina.Group">
        +
        +      <attribute   name="description"
        +            description="Description of this group"
        +                   type="java.lang.String"/>
        +
        +      <attribute   name="groupname"
        +            description="Group name of this group"
        +                   type="java.lang.String"/>
        +
        +      <attribute   name="roles"
        +            description="MBean Names of roles for this group"
        +                   type="java.lang.String[]"
        +              writeable="false"/>
        +
        +      <attribute   name="users"
        +            description="MBean Names of user members of this group"
        +                   type="java.lang.String[]"
        +              writeable="false"/>
        +
        +      <operation   name="addRole"
        +            description="Add a new authorized role for this group"
        +                 impact="ACTION"
        +             returnType="void">
        +        <parameter name="role"
        +            description="Role to be added"
        +                   type="java.lang.String"/>
        +      </operation>
        +
        +      <operation   name="removeRole"
        +            description="Remove an old authorized role for this group"
        +                 impact="ACTION"
        +             returnType="void">
        +        <parameter name="role"
        +            description="Role to be removed"
        +                   type="java.lang.String"/>
        +      </operation>
        +
        +      <operation   name="removeRoles"
        +            description="Remove all authorized roles for this group"
        +                 impact="ACTION"
        +             returnType="void">
        +      </operation>
        +
        +    </mbean>
        +
        +    <!-- ... other MBean definitions ... -->
        +
        +  </mbeans-descriptors>
        +
        +
        + +

        This MBean represents an instance of org.apache.catalina.Group, +which is an entity representing a group of users (with a shared set of security +roles that all users in the group inherit) in a user database. This MBean +advertises support for four attributes (description, groupname, roles, and +users) that roughly correspond to JavaBean properties. By default, attributes +are assumed to have read/write access. For this particular MBean, the roles +and users attributes are read-only (writeable="false"). Finally, +this MBean supports three operations (addRole, removeRole, and +removeRoles) that roughly correspond to JavaBean methods on the underlying +component.

        + +

        In general, Modeler provides a standard ModelMBean implementation +that simply passes on JMX calls on attributes and operations directly through +to the managed component that the ModelMBean is associated with. For special +case requirements, you can define a subclass of +BaseModelMBean that provides override +methods for one or more of these attributes (i.e. the property getter and/or +setter methods) and operations (i.e. direct method calls). + +

        For this particular MBean, a custom BaseModelMBean implementation subclass +is described (org.apache.catalina.mbeans.GroupMBean) is +configured. It was necessary in this particular case because several of the +underlying Catalina component's methods deal with internal objects or arrays of +objects, rather than just the Strings and primitives that are supported by all +JMX clients. Thus, the following method on the Group interface: +

        +
        +    public void addRole(Role role);
        +
        +

        is represented, in the MBean, by an addRole method that takes +a String argument representing the role name of the required role. The MBean's +implementation class acts as an adapter, and looks up the required Role +object (by name) before calling the addRole method on the +underlying Group instance within the Server.

        + + +

        3. Create Modeler Registry at Startup Time

        + +

        The metadata information, and the corresponding Model MBean factory, is +represented at runtime in an instance of Registry +whose contents are initialized from the configuration file prepared as was +described above. Typically, such a file will be included in the JAR file +containing the MBean implementation classes themselves, and loaded as follows: +

        +
        +    URL url= this.getClass().getResource
        +      ("/com/mycompany/mypackage/mbeans-descriptors.xml");
        +    Registry registry = Registry.getRegistry();
        +    registry.loadMetadata(url);
        +
        + +

        Besides using the configuration file, it is possible to configure the +registry metadata by hand, using the addManagedBean() and +removeManagedBean() methods. However, most users will find +the standard support for loading a configuration file to be convenient +and sufficient.

        + +

        Modeler will also look for a mbeans-descriptors.xml in the same package +with the class beeing registered and in its parent. If no metadata is found, +modeler will use a number of simple patterns, similar with the ones used by +ant, to determine a reasonable metadata

        + +

        In a future version we should also support xdoclet-based generation of the +descriptors

        + + +

        4. Instantiate Model MBeans As Needed

        + +

        When your server application needs to instantiate a new MBean and register +it with the corresponding MBeanServer, it can execute code like +this:

        + +
        +  Group group = ... managed component instance ...;
        +
        +  MBeanServer mserver = registry.getMBeanServer();
        +
        +  String oname="myDomain:type=Group,name=myGroup";
        +
        +  registry.registerComponent( group, oname, "Group" );
        +
        + +

        After the Model MBean has been created and registered, it is accessible to +JMX clients through the standard JMX client APIs. +

        + + + diff --git a/java/org/apache/tomcat/util/net/AprEndpoint.java b/java/org/apache/tomcat/util/net/AprEndpoint.java index 20745dbcd..340e27d62 100644 --- a/java/org/apache/tomcat/util/net/AprEndpoint.java +++ b/java/org/apache/tomcat/util/net/AprEndpoint.java @@ -1,1893 +1,1893 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.concurrent.Executor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.jni.Address; -import org.apache.tomcat.jni.Error; -import org.apache.tomcat.jni.File; -import org.apache.tomcat.jni.Library; -import org.apache.tomcat.jni.OS; -import org.apache.tomcat.jni.Poll; -import org.apache.tomcat.jni.Pool; -import org.apache.tomcat.jni.SSL; -import org.apache.tomcat.jni.SSLContext; -import org.apache.tomcat.jni.SSLSocket; -import org.apache.tomcat.jni.Socket; -import org.apache.tomcat.jni.Status; -import org.apache.tomcat.util.res.StringManager; - -/** - * APR tailored thread pool, providing the following services: - *
          - *
        • Socket acceptor thread
        • - *
        • Socket poller thread
        • - *
        • Sendfile thread
        • - *
        • Worker threads pool
        • - *
        - * - * When switching to Java 5, there's an opportunity to use the virtual - * machine's thread pool. - * - * @author Mladen Turk - * @author Remy Maucherat - */ -public class AprEndpoint { - - - // -------------------------------------------------------------- Constants - - - protected static Log log = LogFactory.getLog(AprEndpoint.class); - - protected static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.net.res"); - - - /** - * The Request attribute key for the cipher suite. - */ - public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; - - /** - * The Request attribute key for the key size. - */ - public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; - - /** - * The Request attribute key for the client certificate chain. - */ - public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; - - /** - * The Request attribute key for the session id. - * This one is a Tomcat extension to the Servlet spec. - */ - public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; - - - // ----------------------------------------------------------------- Fields - - - /** - * Available workers. - */ - protected WorkerStack workers = null; - - - /** - * Running state of the endpoint. - */ - protected volatile boolean running = false; - - - /** - * Will be set to true whenever the endpoint is paused. - */ - protected volatile boolean paused = false; - - - /** - * Track the initialization state of the endpoint. - */ - protected boolean initialized = false; - - - /** - * Current worker threads busy count. - */ - protected int curThreadsBusy = 0; - - - /** - * Current worker threads count. - */ - protected int curThreads = 0; - - - /** - * Sequence number used to generate thread names. - */ - protected int sequence = 0; - - - /** - * Root APR memory pool. - */ - protected long rootPool = 0; - - - /** - * Server socket "pointer". - */ - protected long serverSock = 0; - - - /** - * APR memory pool for the server socket. - */ - protected long serverSockPool = 0; - - - /** - * SSL context. - */ - protected long sslContext = 0; - - - // ------------------------------------------------------------- Properties - - - /** - * External Executor based thread pool. - */ - protected Executor executor = null; - public void setExecutor(Executor executor) { this.executor = executor; } - public Executor getExecutor() { return executor; } - - - /** - * Maximum amount of worker threads. - */ - protected int maxThreads = 40; - public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } - public int getMaxThreads() { return maxThreads; } - - - /** - * Priority of the acceptor and poller threads. - */ - protected int threadPriority = Thread.NORM_PRIORITY; - public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } - public int getThreadPriority() { return threadPriority; } - - - /** - * Size of the socket poller. - */ - protected int pollerSize = 8 * 1024; - public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } - public int getPollerSize() { return pollerSize; } - - - /** - * Size of the sendfile (= concurrent files which can be served). - */ - protected int sendfileSize = 1 * 1024; - public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; } - public int getSendfileSize() { return sendfileSize; } - - - /** - * Server socket port. - */ - protected int port; - public int getPort() { return port; } - public void setPort(int port ) { this.port=port; } - - - /** - * Address for the server socket. - */ - protected InetAddress address; - public InetAddress getAddress() { return address; } - public void setAddress(InetAddress address) { this.address = address; } - - - /** - * Handling of accepted sockets. - */ - protected Handler handler = null; - public void setHandler(Handler handler ) { this.handler = handler; } - public Handler getHandler() { return handler; } - - - /** - * Allows the server developer to specify the backlog that - * should be used for server sockets. By default, this value - * is 100. - */ - protected int backlog = 100; - public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } - public int getBacklog() { return backlog; } - - - /** - * Socket TCP no delay. - */ - protected boolean tcpNoDelay = false; - public boolean getTcpNoDelay() { return tcpNoDelay; } - public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } - - - /** - * Socket linger. - */ - protected int soLinger = 100; - public int getSoLinger() { return soLinger; } - public void setSoLinger(int soLinger) { this.soLinger = soLinger; } - - - /** - * Socket timeout. - */ - protected int soTimeout = -1; - public int getSoTimeout() { return soTimeout; } - public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } - - - /** - * Timeout on first request read before going to the poller, in ms. - */ - protected int firstReadTimeout = -1; - public int getFirstReadTimeout() { return firstReadTimeout; } - public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; } - - - /** - * Poll interval, in microseconds. The smaller the value, the more CPU the poller - * will use, but the more responsive to activity it will be. - */ - protected int pollTime = 2000; - public int getPollTime() { return pollTime; } - public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } - - - /** - * The default is true - the created threads will be - * in daemon mode. If set to false, the control thread - * will not be daemon - and will keep the process alive. - */ - protected boolean daemon = true; - public void setDaemon(boolean b) { daemon = b; } - public boolean getDaemon() { return daemon; } - - - /** - * Name of the thread pool, which will be used for naming child threads. - */ - protected String name = "TP"; - public void setName(String name) { this.name = name; } - public String getName() { return name; } - - - /** - * Use endfile for sending static files. - */ - protected boolean useSendfile = Library.APR_HAS_SENDFILE; - public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; } - public boolean getUseSendfile() { return useSendfile; } - - - /** - * Allow comet request handling. - */ - protected boolean useComet = true; - public void setUseComet(boolean useComet) { this.useComet = useComet; } - public boolean getUseComet() { return useComet; } - - - /** - * Acceptor thread count. - */ - protected int acceptorThreadCount = 0; - public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } - public int getAcceptorThreadCount() { return acceptorThreadCount; } - - - /** - * Sendfile thread count. - */ - protected int sendfileThreadCount = 0; - public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; } - public int getSendfileThreadCount() { return sendfileThreadCount; } - - - /** - * Poller thread count. - */ - protected int pollerThreadCount = 0; - public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } - public int getPollerThreadCount() { return pollerThreadCount; } - - - /** - * The socket poller. - */ - protected Poller[] pollers = null; - protected int pollerRoundRobin = 0; - public Poller getPoller() { - pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length; - return pollers[pollerRoundRobin]; - } - - - /** - * The socket poller used for Comet support. - */ - protected Poller[] cometPollers = null; - protected int cometPollerRoundRobin = 0; - public Poller getCometPoller() { - cometPollerRoundRobin = (cometPollerRoundRobin + 1) % cometPollers.length; - return cometPollers[cometPollerRoundRobin]; - } - - - /** - * The static file sender. - */ - protected Sendfile[] sendfiles = null; - protected int sendfileRoundRobin = 0; - public Sendfile getSendfile() { - sendfileRoundRobin = (sendfileRoundRobin + 1) % sendfiles.length; - return sendfiles[sendfileRoundRobin]; - } - - - /** - * Dummy maxSpareThreads property. - */ - public int getMaxSpareThreads() { return 0; } - - - /** - * Dummy minSpareThreads property. - */ - public int getMinSpareThreads() { return 0; } - - - /** - * SSL engine. - */ - protected String SSLEngine = "off"; - public String getSSLEngine() { return SSLEngine; } - public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; } - - - /** - * SSL protocols. - */ - protected String SSLProtocol = "all"; - public String getSSLProtocol() { return SSLProtocol; } - public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - protected String SSLPassword = null; - public String getSSLPassword() { return SSLPassword; } - public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } - - - /** - * SSL cipher suite. - */ - protected String SSLCipherSuite = "ALL"; - public String getSSLCipherSuite() { return SSLCipherSuite; } - public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } - - - /** - * SSL certificate file. - */ - protected String SSLCertificateFile = null; - public String getSSLCertificateFile() { return SSLCertificateFile; } - public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } - - - /** - * SSL certificate key file. - */ - protected String SSLCertificateKeyFile = null; - public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } - - - /** - * SSL certificate chain file. - */ - protected String SSLCertificateChainFile = null; - public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } - - - /** - * SSL CA certificate path. - */ - protected String SSLCACertificatePath = null; - public String getSSLCACertificatePath() { return SSLCACertificatePath; } - public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } - - - /** - * SSL CA certificate file. - */ - protected String SSLCACertificateFile = null; - public String getSSLCACertificateFile() { return SSLCACertificateFile; } - public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } - - - /** - * SSL CA revocation path. - */ - protected String SSLCARevocationPath = null; - public String getSSLCARevocationPath() { return SSLCARevocationPath; } - public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } - - - /** - * SSL CA revocation file. - */ - protected String SSLCARevocationFile = null; - public String getSSLCARevocationFile() { return SSLCARevocationFile; } - public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } - - - /** - * SSL verify client. - */ - protected String SSLVerifyClient = "none"; - public String getSSLVerifyClient() { return SSLVerifyClient; } - public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } - - - /** - * SSL verify depth. - */ - protected int SSLVerifyDepth = 10; - public int getSSLVerifyDepth() { return SSLVerifyDepth; } - public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } - - - // --------------------------------------------------------- Public Methods - - - /** - * Number of keepalive sockets. - */ - public int getKeepAliveCount() { - if (pollers == null) { - return 0; - } else { - int keepAliveCount = 0; - for (int i = 0; i < pollers.length; i++) { - keepAliveCount += pollers[i].getKeepAliveCount(); - } - return keepAliveCount; - } - } - - - /** - * Number of sendfile sockets. - */ - public int getSendfileCount() { - if (sendfiles == null) { - return 0; - } else { - int sendfileCount = 0; - for (int i = 0; i < sendfiles.length; i++) { - sendfileCount += sendfiles[i].getSendfileCount(); - } - return sendfileCount; - } - } - - - /** - * Return the amount of threads that are managed by the pool. - * - * @return the amount of threads that are managed by the pool - */ - public int getCurrentThreadCount() { - return curThreads; - } - - - /** - * Return the amount of threads currently busy. - * - * @return the amount of threads currently busy - */ - public int getCurrentThreadsBusy() { - return curThreadsBusy; - } - - - /** - * Return the state of the endpoint. - * - * @return true if the endpoint is running, false otherwise - */ - public boolean isRunning() { - return running; - } - - - /** - * Return the state of the endpoint. - * - * @return true if the endpoint is paused, false otherwise - */ - public boolean isPaused() { - return paused; - } - - - // ----------------------------------------------- Public Lifecycle Methods - - - /** - * Initialize the endpoint. - */ - public void init() - throws Exception { - - if (initialized) - return; - - // Create the root APR memory pool - rootPool = Pool.create(0); - // Create the pool for the server socket - serverSockPool = Pool.create(rootPool); - // Create the APR address that will be bound - String addressStr = null; - if (address == null) { - addressStr = null; - } else { - addressStr = address.getHostAddress(); - } - int family = Socket.APR_INET; - if (Library.APR_HAVE_IPV6 && (addressStr == null || addressStr.indexOf(':') >= 0)) { - family = Socket.APR_UNSPEC; - } - long inetAddress = Address.info(addressStr, family, - port, 0, rootPool); - // Create the APR server socket - serverSock = Socket.create(family, Socket.SOCK_STREAM, - Socket.APR_PROTO_TCP, rootPool); - if (OS.IS_UNIX) { - Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); - } - // Deal with the firewalls that tend to drop the inactive sockets - Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); - // Bind the server socket - int ret = Socket.bind(serverSock, inetAddress); - if (ret != 0) { - throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret))); - } - // Start listening on the server socket - ret = Socket.listen(serverSock, backlog); - if (ret != 0) { - throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret))); - } - if (OS.IS_WIN32 || OS.IS_WIN64) { - // On Windows set the reuseaddr flag after the bind/listen - Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); - } - - // Sendfile usage on systems which don't support it cause major problems - if (useSendfile && !Library.APR_HAS_SENDFILE) { - log.warn(sm.getString("endpoint.sendfile.nosupport")); - useSendfile = false; - } - - // Initialize thread count defaults for acceptor, poller and sendfile - if (acceptorThreadCount == 0) { - // FIXME: Doesn't seem to work that well with multiple accept threads - acceptorThreadCount = 1; - } - if (pollerThreadCount == 0) { - if ((OS.IS_WIN32 || OS.IS_WIN64) && (pollerSize > 1024)) { - // The maximum per poller to get reasonable performance is 1024 - pollerThreadCount = pollerSize / 1024; - // Adjust poller size so that it won't reach the limit - pollerSize = pollerSize - (pollerSize % 1024); - } else { - // No explicit poller size limitation - pollerThreadCount = 1; - } - } - if (sendfileThreadCount == 0) { - if ((OS.IS_WIN32 || OS.IS_WIN64) && (sendfileSize > 1024)) { - // The maximum per poller to get reasonable performance is 1024 - sendfileThreadCount = sendfileSize / 1024; - // Adjust poller size so that it won't reach the limit - sendfileSize = sendfileSize - (sendfileSize % 1024); - } else { - // No explicit poller size limitation - // FIXME: Default to one per CPU ? - sendfileThreadCount = 1; - } - } - - // Delay accepting of new connections until data is available - // Only Linux kernels 2.4 + have that implemented - // on other platforms this call is noop and will return APR_ENOTIMPL. - Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1); - - // Initialize SSL if needed - if (!"off".equalsIgnoreCase(SSLEngine)) { - // Initialize SSL - // FIXME: one per VM call ? - if ("on".equalsIgnoreCase(SSLEngine)) { - SSL.initialize(null); - } else { - SSL.initialize(SSLEngine); - } - // SSL protocol - int value = SSL.SSL_PROTOCOL_ALL; - if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2; - } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV3; - } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_TLSV1; - } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; - } - // Create SSL Context - sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); - // List the ciphers that the client is permitted to negotiate - SSLContext.setCipherSuite(sslContext, SSLCipherSuite); - // Load Server key and certificate - SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); - // Set certificate chain file - SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); - // Support Client Certificates - SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); - // Set revocation - SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); - // Client certificate verification - value = SSL.SSL_CVERIFY_NONE; - if ("optional".equalsIgnoreCase(SSLVerifyClient)) { - value = SSL.SSL_CVERIFY_OPTIONAL; - } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { - value = SSL.SSL_CVERIFY_REQUIRE; - } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { - value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; - } - SSLContext.setVerify(sslContext, value, SSLVerifyDepth); - // For now, sendfile is not supported with SSL - useSendfile = false; - } - - initialized = true; - - } - - - /** - * Start the APR endpoint, creating acceptor, poller and sendfile threads. - */ - public void start() - throws Exception { - // Initialize socket if not done before - if (!initialized) { - init(); - } - if (!running) { - running = true; - paused = false; - - // Create worker collection - if (executor == null) { - workers = new WorkerStack(maxThreads); - } - - // Start acceptor threads - for (int i = 0; i < acceptorThreadCount; i++) { - Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); - acceptorThread.setPriority(threadPriority); - acceptorThread.setDaemon(daemon); - acceptorThread.start(); - } - - // Start poller threads - pollers = new Poller[pollerThreadCount]; - for (int i = 0; i < pollerThreadCount; i++) { - pollers[i] = new Poller(false); - pollers[i].init(); - Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i); - pollerThread.setPriority(threadPriority); - pollerThread.setDaemon(true); - pollerThread.start(); - } - - // Start comet poller threads - cometPollers = new Poller[pollerThreadCount]; - for (int i = 0; i < pollerThreadCount; i++) { - cometPollers[i] = new Poller(true); - cometPollers[i].init(); - Thread pollerThread = new Thread(cometPollers[i], getName() + "-CometPoller-" + i); - pollerThread.setPriority(threadPriority); - pollerThread.setDaemon(true); - pollerThread.start(); - } - - // Start sendfile threads - if (useSendfile) { - sendfiles = new Sendfile[sendfileThreadCount]; - for (int i = 0; i < sendfileThreadCount; i++) { - sendfiles[i] = new Sendfile(); - sendfiles[i].init(); - Thread sendfileThread = new Thread(sendfiles[i], getName() + "-Sendfile-" + i); - sendfileThread.setPriority(threadPriority); - sendfileThread.setDaemon(true); - sendfileThread.start(); - } - } - } - } - - - /** - * Pause the endpoint, which will make it stop accepting new sockets. - */ - public void pause() { - if (running && !paused) { - paused = true; - unlockAccept(); - } - } - - - /** - * Resume the endpoint, which will make it start accepting new sockets - * again. - */ - public void resume() { - if (running) { - paused = false; - } - } - - - /** - * Stop the endpoint. This will cause all processing threads to stop. - */ - public void stop() { - if (running) { - running = false; - unlockAccept(); - for (int i = 0; i < pollers.length; i++) { - pollers[i].destroy(); - } - pollers = null; - for (int i = 0; i < cometPollers.length; i++) { - cometPollers[i].destroy(); - } - cometPollers = null; - if (useSendfile) { - for (int i = 0; i < sendfiles.length; i++) { - sendfiles[i].destroy(); - } - sendfiles = null; - } - } - } - - - /** - * Deallocate APR memory pools, and close server socket. - */ - public void destroy() throws Exception { - if (running) { - stop(); - } - Pool.destroy(serverSockPool); - serverSockPool = 0; - // Close server socket - Socket.close(serverSock); - serverSock = 0; - sslContext = 0; - // Close all APR memory pools and resources - Pool.destroy(rootPool); - rootPool = 0; - initialized = false; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Get a sequence number used for thread naming. - */ - protected int getSequence() { - return sequence++; - } - - - /** - * Unlock the server socket accept using a bugus connection. - */ - protected void unlockAccept() { - java.net.Socket s = null; - try { - // Need to create a connection to unlock the accept(); - if (address == null) { - s = new java.net.Socket("127.0.0.1", port); - } else { - s = new java.net.Socket(address, port); - // setting soLinger to a small value will help shutdown the - // connection quicker - s.setSoLinger(true, 0); - } - } catch(Exception e) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); - } - } finally { - if (s != null) { - try { - s.close(); - } catch (Exception e) { - // Ignore - } - } - } - } - - - /** - * Process the specified connection. - */ - protected boolean setSocketOptions(long socket) { - // Process the connection - int step = 1; - try { - - // 1: Set socket options: timeout, linger, etc - if (soLinger >= 0) - Socket.optSet(socket, Socket.APR_SO_LINGER, soLinger); - if (tcpNoDelay) - Socket.optSet(socket, Socket.APR_TCP_NODELAY, (tcpNoDelay ? 1 : 0)); - if (soTimeout > 0) - Socket.timeoutSet(socket, soTimeout * 1000); - - // 2: SSL handshake - step = 2; - if (sslContext != 0) { - SSLSocket.attach(sslContext, socket); - if (SSLSocket.handshake(socket) != 0) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); - } - return false; - } - } - - } catch (Throwable t) { - if (log.isDebugEnabled()) { - if (step == 2) { - log.debug(sm.getString("endpoint.err.handshake"), t); - } else { - log.debug(sm.getString("endpoint.err.unexpected"), t); - } - } - // Tell to close the socket - return false; - } - return true; - } - - - /** - * Create (or allocate) and return an available processor for use in - * processing a specific HTTP request, if possible. If the maximum - * allowed processors have already been created and are in use, return - * null instead. - */ - protected Worker createWorkerThread() { - - synchronized (workers) { - if (workers.size() > 0) { - curThreadsBusy++; - return (workers.pop()); - } - if ((maxThreads > 0) && (curThreads < maxThreads)) { - curThreadsBusy++; - return (newWorkerThread()); - } else { - if (maxThreads < 0) { - curThreadsBusy++; - return (newWorkerThread()); - } else { - return (null); - } - } - } - - } - - - /** - * Create and return a new processor suitable for processing HTTP - * requests and returning the corresponding responses. - */ - protected Worker newWorkerThread() { - - Worker workerThread = new Worker(); - workerThread.start(); - return (workerThread); - - } - - - /** - * Return a new worker thread, and block while to worker is available. - */ - protected Worker getWorkerThread() { - // Allocate a new worker thread - Worker workerThread = createWorkerThread(); - while (workerThread == null) { - try { - synchronized (workers) { - workers.wait(); - } - } catch (InterruptedException e) { - // Ignore - } - workerThread = createWorkerThread(); - } - return workerThread; - } - - - /** - * Recycle the specified Processor so that it can be used again. - * - * @param workerThread The processor to be recycled - */ - protected void recycleWorkerThread(Worker workerThread) { - synchronized (workers) { - workers.push(workerThread); - curThreadsBusy--; - workers.notify(); - } - } - - - /** - * Allocate a new poller of the specified size. - */ - protected long allocatePoller(int size, long pool, int timeout) { - try { - return Poll.create(size, pool, 0, timeout * 1000); - } catch (Error e) { - if (Status.APR_STATUS_IS_EINVAL(e.getError())) { - log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); - return 0; - } else { - log.error(sm.getString("endpoint.poll.initfail"), e); - return -1; - } - } - } - - - /** - * Process given socket. - */ - protected boolean processSocket(long socket) { - try { - if (executor == null) { - getWorkerThread().assign(socket); - } else { - executor.execute(new SocketProcessor(socket)); - } - } catch (Throwable t) { - // This means we got an OOM or similar creating a thread, or that - // the pool and its queue are full - log.error(sm.getString("endpoint.process.fail"), t); - return false; - } - return true; - } - - - /** - * Process given socket for an event. - */ - protected boolean processSocket(long socket, boolean error) { - try { - if (executor == null) { - getWorkerThread().assign(socket, error); - } else { - executor.execute(new SocketEventProcessor(socket, error)); - } - } catch (Throwable t) { - // This means we got an OOM or similar creating a thread, or that - // the pool and its queue are full - log.error(sm.getString("endpoint.process.fail"), t); - return false; - } - return true; - } - - - // --------------------------------------------------- Acceptor Inner Class - - - /** - * Server socket acceptor thread. - */ - protected class Acceptor implements Runnable { - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Loop until we receive a shutdown command - while (running) { - - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - try { - // Accept the next incoming connection from the server socket - long socket = Socket.accept(serverSock); - // Hand this socket off to an appropriate processor - if (!setSocketOptions(socket) || !processSocket(socket)) { - // Close socket and pool right away - Socket.destroy(socket); - } - } catch (Throwable t) { - log.error(sm.getString("endpoint.accept.fail"), t); - } - - // The processor will recycle itself when it finishes - - } - - } - - } - - - // ----------------------------------------------------- Poller Inner Class - - - /** - * Poller class. - */ - public class Poller implements Runnable { - - protected long serverPollset = 0; - protected long pool = 0; - protected long[] desc; - - protected long[] addS; - protected int addCount = 0; - - protected boolean comet = true; - - protected int keepAliveCount = 0; - public int getKeepAliveCount() { return keepAliveCount; } - - public Poller(boolean comet) { - this.comet = comet; - } - - /** - * Create the poller. With some versions of APR, the maximum poller size will - * be 62 (reocmpiling APR is necessary to remove this limitation). - */ - protected void init() { - pool = Pool.create(serverSockPool); - int size = pollerSize / pollerThreadCount; - int timeout = soTimeout; - if (comet) { - // FIXME: Find an appropriate timeout value, for now, "longer than usual" - // semms appropriate - timeout = soTimeout * 50; - } - serverPollset = allocatePoller(size, pool, timeout); - if (serverPollset == 0 && size > 1024) { - size = 1024; - serverPollset = allocatePoller(size, pool, timeout); - } - if (serverPollset == 0) { - size = 62; - serverPollset = allocatePoller(size, pool, timeout); - } - desc = new long[size * 2]; - keepAliveCount = 0; - addS = new long[size]; - addCount = 0; - } - - /** - * Destroy the poller. - */ - protected void destroy() { - // Wait for polltime before doing anything, so that the poller threads - // exit, otherwise parallel descturction of sockets which are still - // in the poller can cause problems - try { - synchronized (this) { - this.wait(pollTime / 1000); - } - } catch (InterruptedException e) { - // Ignore - } - // Close all sockets in the add queue - for (int i = 0; i < addCount; i++) { - if (comet) { - processSocket(addS[i], true); - } else { - Socket.destroy(addS[i]); - } - } - // Close all sockets still in the poller - int rv = Poll.pollset(serverPollset, desc); - if (rv > 0) { - for (int n = 0; n < rv; n++) { - if (comet) { - processSocket(desc[n*2+1], true); - } else { - Socket.destroy(desc[n*2+1]); - } - } - } - Pool.destroy(pool); - keepAliveCount = 0; - addCount = 0; - } - - /** - * Add specified socket and associated pool to the poller. The socket will - * be added to a temporary array, and polled first after a maximum amount - * of time equal to pollTime (in most cases, latency will be much lower, - * however). - * - * @param socket to add to the poller - */ - public void add(long socket) { - synchronized (this) { - // Add socket to the list. Newly added sockets will wait - // at most for pollTime before being polled - if (addCount >= addS.length) { - // Can't do anything: close the socket right away - if (comet) { - processSocket(socket, true); - } else { - Socket.destroy(socket); - } - return; - } - addS[addCount] = socket; - addCount++; - this.notify(); - } - } - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - long maintainTime = 0; - // Loop until we receive a shutdown command - while (running) { - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - while (keepAliveCount < 1 && addCount < 1) { - // Reset maintain time. - maintainTime = 0; - try { - synchronized (this) { - this.wait(); - } - } catch (InterruptedException e) { - // Ignore - } - } - - try { - // Add sockets which are waiting to the poller - if (addCount > 0) { - synchronized (this) { - for (int i = (addCount - 1); i >= 0; i--) { - int rv = Poll.add - (serverPollset, addS[i], Poll.APR_POLLIN); - if (rv == Status.APR_SUCCESS) { - keepAliveCount++; - } else { - // Can't do anything: close the socket right away - if (comet) { - processSocket(addS[i], true); - } else { - Socket.destroy(addS[i]); - } - } - } - addCount = 0; - } - } - - maintainTime += pollTime; - // Pool for the specified interval - int rv = Poll.poll(serverPollset, pollTime, desc, true); - if (rv > 0) { - keepAliveCount -= rv; - for (int n = 0; n < rv; n++) { - // Check for failed sockets and hand this socket off to a worker - if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) - || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) - || (comet && (!processSocket(desc[n*2+1], false))) - || (!comet && (!processSocket(desc[n*2+1])))) { - // Close socket and clear pool - if (comet) { - processSocket(desc[n*2+1], true); - } else { - Socket.destroy(desc[n*2+1]); - } - continue; - } - } - } else if (rv < 0) { - int errn = -rv; - /* Any non timeup or interrupted error is critical */ - if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { - if (errn > Status.APR_OS_START_USERERR) { - errn -= Status.APR_OS_START_USERERR; - } - log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); - // Handle poll critical failure - synchronized (this) { - destroy(); - init(); - } - continue; - } - } - if (soTimeout > 0 && maintainTime > 1000000L && running) { - rv = Poll.maintain(serverPollset, desc, true); - maintainTime = 0; - if (rv > 0) { - keepAliveCount -= rv; - for (int n = 0; n < rv; n++) { - // Close socket and clear pool - if (comet) { - processSocket(desc[n], true); - } else { - Socket.destroy(desc[n]); - } - } - } - } - } catch (Throwable t) { - log.error(sm.getString("endpoint.poll.error"), t); - } - - } - - synchronized (this) { - this.notifyAll(); - } - - } - - } - - - // ----------------------------------------------------- Worker Inner Class - - - /** - * Server processor class. - */ - protected class Worker implements Runnable { - - - protected Thread thread = null; - protected boolean available = false; - protected long socket = 0; - protected boolean event = false; - protected boolean error = false; - - - /** - * Process an incoming TCP/IP connection on the specified socket. Any - * exception that occurs during processing must be logged and swallowed. - * NOTE: This method is called from our Connector's thread. We - * must assign it to our own thread so that multiple simultaneous - * requests can be handled. - * - * @param socket TCP socket to process - */ - protected synchronized void assign(long socket) { - - // Wait for the Processor to get the previous Socket - while (available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Store the newly available Socket and notify our thread - this.socket = socket; - event = false; - error = false; - available = true; - notifyAll(); - - } - - - protected synchronized void assign(long socket, boolean error) { - - // Wait for the Processor to get the previous Socket - while (available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Store the newly available Socket and notify our thread - this.socket = socket; - event = true; - this.error = error; - available = true; - notifyAll(); - - } - - - /** - * Await a newly assigned Socket from our Connector, or null - * if we are supposed to shut down. - */ - protected synchronized long await() { - - // Wait for the Connector to provide a new Socket - while (!available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Notify the Connector that we have received this Socket - long socket = this.socket; - available = false; - notifyAll(); - - return (socket); - - } - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Process requests until we receive a shutdown signal - while (running) { - - // Wait for the next socket to be assigned - long socket = await(); - if (socket == 0) - continue; - - // Process the request from this socket - if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { - // Close socket and pool - Socket.destroy(socket); - socket = 0; - } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { - // Close socket and pool - Socket.destroy(socket); - socket = 0; - } - - // Finish up this request - recycleWorkerThread(this); - - } - - } - - - /** - * Start the background processing thread. - */ - public void start() { - thread = new Thread(this); - thread.setName(getName() + "-" + (++curThreads)); - thread.setDaemon(true); - thread.start(); - } - - - } - - - // ----------------------------------------------- SendfileData Inner Class - - - /** - * SendfileData class. - */ - public static class SendfileData { - // File - public String fileName; - public long fd; - public long fdpool; - // Range information - public long start; - public long end; - // Socket and socket pool - public long socket; - // Position - public long pos; - // KeepAlive flag - public boolean keepAlive; - } - - - // --------------------------------------------------- Sendfile Inner Class - - - /** - * Sendfile class. - */ - public class Sendfile implements Runnable { - - protected long sendfilePollset = 0; - protected long pool = 0; - protected long[] desc; - protected HashMap sendfileData; - - protected int sendfileCount; - public int getSendfileCount() { return sendfileCount; } - - protected ArrayList addS; - - /** - * Create the sendfile poller. With some versions of APR, the maximum poller size will - * be 62 (reocmpiling APR is necessary to remove this limitation). - */ - protected void init() { - pool = Pool.create(serverSockPool); - int size = sendfileSize / sendfileThreadCount; - sendfilePollset = allocatePoller(size, pool, soTimeout); - if (sendfilePollset == 0 && size > 1024) { - size = 1024; - sendfilePollset = allocatePoller(size, pool, soTimeout); - } - if (sendfilePollset == 0) { - size = 62; - sendfilePollset = allocatePoller(size, pool, soTimeout); - } - desc = new long[size * 2]; - sendfileData = new HashMap(size); - addS = new ArrayList(); - } - - /** - * Destroy the poller. - */ - protected void destroy() { - // Wait for polltime before doing anything, so that the poller threads - // exit, otherwise parallel descturction of sockets which are still - // in the poller can cause problems - try { - synchronized (this) { - this.wait(pollTime / 1000); - } - } catch (InterruptedException e) { - // Ignore - } - // Close any socket remaining in the add queue - for (int i = (addS.size() - 1); i >= 0; i--) { - SendfileData data = addS.get(i); - Socket.destroy(data.socket); - } - // Close all sockets still in the poller - int rv = Poll.pollset(sendfilePollset, desc); - if (rv > 0) { - for (int n = 0; n < rv; n++) { - Socket.destroy(desc[n*2+1]); - } - } - Pool.destroy(pool); - sendfileData.clear(); - } - - /** - * Add the sendfile data to the sendfile poller. Note that in most cases, - * the initial non blocking calls to sendfile will return right away, and - * will be handled asynchronously inside the kernel. As a result, - * the poller will never be used. - * - * @param data containing the reference to the data which should be snet - * @return true if all the data has been sent right away, and false - * otherwise - */ - public boolean add(SendfileData data) { - // Initialize fd from data given - try { - data.fdpool = Socket.pool(data.socket); - data.fd = File.open - (data.fileName, File.APR_FOPEN_READ - | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY, - 0, data.fdpool); - data.pos = data.start; - // Set the socket to nonblocking mode - Socket.timeoutSet(data.socket, 0); - while (true) { - long nw = Socket.sendfilen(data.socket, data.fd, - data.pos, data.end - data.pos, 0); - if (nw < 0) { - if (!(-nw == Status.EAGAIN)) { - Socket.destroy(data.socket); - data.socket = 0; - return false; - } else { - // Break the loop and add the socket to poller. - break; - } - } else { - data.pos = data.pos + nw; - if (data.pos >= data.end) { - // Entire file has been sent - Pool.destroy(data.fdpool); - // Set back socket to blocking mode - Socket.timeoutSet(data.socket, soTimeout * 1000); - return true; - } - } - } - } catch (Exception e) { - log.error(sm.getString("endpoint.sendfile.error"), e); - return false; - } - // Add socket to the list. Newly added sockets will wait - // at most for pollTime before being polled - synchronized (this) { - addS.add(data); - this.notify(); - } - return false; - } - - /** - * Remove socket from the poller. - * - * @param data the sendfile data which should be removed - */ - protected void remove(SendfileData data) { - int rv = Poll.remove(sendfilePollset, data.socket); - if (rv == Status.APR_SUCCESS) { - sendfileCount--; - } - sendfileData.remove(data); - } - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Loop until we receive a shutdown command - while (running) { - - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - while (sendfileCount < 1 && addS.size() < 1) { - try { - synchronized (this) { - this.wait(); - } - } catch (InterruptedException e) { - // Ignore - } - } - - try { - // Add socket to the poller - if (addS.size() > 0) { - synchronized (this) { - for (int i = (addS.size() - 1); i >= 0; i--) { - SendfileData data = addS.get(i); - int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT); - if (rv == Status.APR_SUCCESS) { - sendfileData.put(new Long(data.socket), data); - sendfileCount++; - } else { - log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, Error.strerror(rv))); - // Can't do anything: close the socket right away - Socket.destroy(data.socket); - } - } - addS.clear(); - } - } - // Pool for the specified interval - int rv = Poll.poll(sendfilePollset, pollTime, desc, false); - if (rv > 0) { - for (int n = 0; n < rv; n++) { - // Get the sendfile state - SendfileData state = - sendfileData.get(new Long(desc[n*2+1])); - // Problem events - if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) - || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) { - // Close socket and clear pool - remove(state); - // Destroy file descriptor pool, which should close the file - // Close the socket, as the reponse would be incomplete - Socket.destroy(state.socket); - continue; - } - // Write some data using sendfile - long nw = Socket.sendfilen(state.socket, state.fd, - state.pos, - state.end - state.pos, 0); - if (nw < 0) { - // Close socket and clear pool - remove(state); - // Close the socket, as the reponse would be incomplete - // This will close the file too. - Socket.destroy(state.socket); - continue; - } - - state.pos = state.pos + nw; - if (state.pos >= state.end) { - remove(state); - if (state.keepAlive) { - // Destroy file descriptor pool, which should close the file - Pool.destroy(state.fdpool); - Socket.timeoutSet(state.socket, soTimeout * 1000); - // If all done hand this socket off to a worker for - // processing of further requests - if (!processSocket(state.socket)) { - Socket.destroy(state.socket); - } - } else { - // Close the socket since this is - // the end of not keep-alive request. - Socket.destroy(state.socket); - } - } - } - } else if (rv < 0) { - int errn = -rv; - /* Any non timeup or interrupted error is critical */ - if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { - if (errn > Status.APR_OS_START_USERERR) { - errn -= Status.APR_OS_START_USERERR; - } - log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); - // Handle poll critical failure - synchronized (this) { - destroy(); - init(); - } - continue; - } - } - /* TODO: See if we need to call the maintain for sendfile poller */ - } catch (Throwable t) { - log.error(sm.getString("endpoint.poll.error"), t); - } - } - - synchronized (this) { - this.notifyAll(); - } - - } - - } - - - // ------------------------------------------------ Handler Inner Interface - - - /** - * Bare bones interface used for socket processing. Per thread data is to be - * stored in the ThreadWithAttributes extra folders, or alternately in - * thread local fields. - */ - public interface Handler { - public enum SocketState { - OPEN, CLOSED, LONG - } - public SocketState process(long socket); - public SocketState event(long socket, boolean error); - } - - - // ------------------------------------------------- WorkerStack Inner Class - - - public class WorkerStack { - - protected Worker[] workers = null; - protected int end = 0; - - public WorkerStack(int size) { - workers = new Worker[size]; - } - - /** - * Put the object into the queue. - * - * @param object the object to be appended to the queue (first element). - */ - public void push(Worker worker) { - workers[end++] = worker; - } - - /** - * Get the first object out of the queue. Return null if the queue - * is empty. - */ - public Worker pop() { - if (end > 0) { - return workers[--end]; - } - return null; - } - - /** - * Get the first object out of the queue, Return null if the queue - * is empty. - */ - public Worker peek() { - return workers[end]; - } - - /** - * Is the queue empty? - */ - public boolean isEmpty() { - return (end == 0); - } - - /** - * How many elements are there in this queue? - */ - public int size() { - return (end); - } - } - - - // ---------------------------------------------- SocketProcessor Inner Class - - - /** - * This class is the equivalent of the Worker, but will simply use in an - * external Executor thread pool. - */ - protected class SocketProcessor implements Runnable { - - protected long socket = 0; - - public SocketProcessor(long socket) { - this.socket = socket; - } - - public void run() { - - // Process the request from this socket - if (handler.process(socket) == Handler.SocketState.CLOSED) { - // Close socket and pool - Socket.destroy(socket); - socket = 0; - } - - } - - } - - - // --------------------------------------- SocketEventProcessor Inner Class - - - /** - * This class is the equivalent of the Worker, but will simply use in an - * external Executor thread pool. - */ - protected class SocketEventProcessor implements Runnable { - - protected long socket = 0; - protected boolean error = false; - - public SocketEventProcessor(long socket, boolean error) { - this.socket = socket; - this.error = error; - } - - public void run() { - - // Process the request from this socket - if (handler.event(socket, error) == Handler.SocketState.CLOSED) { - // Close socket and pool - Socket.destroy(socket); - socket = 0; - } - - } - - } - - -} +/* + * Copyright 2005-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.concurrent.Executor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.jni.Address; +import org.apache.tomcat.jni.Error; +import org.apache.tomcat.jni.File; +import org.apache.tomcat.jni.Library; +import org.apache.tomcat.jni.OS; +import org.apache.tomcat.jni.Poll; +import org.apache.tomcat.jni.Pool; +import org.apache.tomcat.jni.SSL; +import org.apache.tomcat.jni.SSLContext; +import org.apache.tomcat.jni.SSLSocket; +import org.apache.tomcat.jni.Socket; +import org.apache.tomcat.jni.Status; +import org.apache.tomcat.util.res.StringManager; + +/** + * APR tailored thread pool, providing the following services: + *
          + *
        • Socket acceptor thread
        • + *
        • Socket poller thread
        • + *
        • Sendfile thread
        • + *
        • Worker threads pool
        • + *
        + * + * When switching to Java 5, there's an opportunity to use the virtual + * machine's thread pool. + * + * @author Mladen Turk + * @author Remy Maucherat + */ +public class AprEndpoint { + + + // -------------------------------------------------------------- Constants + + + protected static Log log = LogFactory.getLog(AprEndpoint.class); + + protected static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.net.res"); + + + /** + * The Request attribute key for the cipher suite. + */ + public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; + + /** + * The Request attribute key for the key size. + */ + public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; + + /** + * The Request attribute key for the client certificate chain. + */ + public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; + + /** + * The Request attribute key for the session id. + * This one is a Tomcat extension to the Servlet spec. + */ + public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; + + + // ----------------------------------------------------------------- Fields + + + /** + * Available workers. + */ + protected WorkerStack workers = null; + + + /** + * Running state of the endpoint. + */ + protected volatile boolean running = false; + + + /** + * Will be set to true whenever the endpoint is paused. + */ + protected volatile boolean paused = false; + + + /** + * Track the initialization state of the endpoint. + */ + protected boolean initialized = false; + + + /** + * Current worker threads busy count. + */ + protected int curThreadsBusy = 0; + + + /** + * Current worker threads count. + */ + protected int curThreads = 0; + + + /** + * Sequence number used to generate thread names. + */ + protected int sequence = 0; + + + /** + * Root APR memory pool. + */ + protected long rootPool = 0; + + + /** + * Server socket "pointer". + */ + protected long serverSock = 0; + + + /** + * APR memory pool for the server socket. + */ + protected long serverSockPool = 0; + + + /** + * SSL context. + */ + protected long sslContext = 0; + + + // ------------------------------------------------------------- Properties + + + /** + * External Executor based thread pool. + */ + protected Executor executor = null; + public void setExecutor(Executor executor) { this.executor = executor; } + public Executor getExecutor() { return executor; } + + + /** + * Maximum amount of worker threads. + */ + protected int maxThreads = 40; + public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } + public int getMaxThreads() { return maxThreads; } + + + /** + * Priority of the acceptor and poller threads. + */ + protected int threadPriority = Thread.NORM_PRIORITY; + public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } + public int getThreadPriority() { return threadPriority; } + + + /** + * Size of the socket poller. + */ + protected int pollerSize = 8 * 1024; + public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } + public int getPollerSize() { return pollerSize; } + + + /** + * Size of the sendfile (= concurrent files which can be served). + */ + protected int sendfileSize = 1 * 1024; + public void setSendfileSize(int sendfileSize) { this.sendfileSize = sendfileSize; } + public int getSendfileSize() { return sendfileSize; } + + + /** + * Server socket port. + */ + protected int port; + public int getPort() { return port; } + public void setPort(int port ) { this.port=port; } + + + /** + * Address for the server socket. + */ + protected InetAddress address; + public InetAddress getAddress() { return address; } + public void setAddress(InetAddress address) { this.address = address; } + + + /** + * Handling of accepted sockets. + */ + protected Handler handler = null; + public void setHandler(Handler handler ) { this.handler = handler; } + public Handler getHandler() { return handler; } + + + /** + * Allows the server developer to specify the backlog that + * should be used for server sockets. By default, this value + * is 100. + */ + protected int backlog = 100; + public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } + public int getBacklog() { return backlog; } + + + /** + * Socket TCP no delay. + */ + protected boolean tcpNoDelay = false; + public boolean getTcpNoDelay() { return tcpNoDelay; } + public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } + + + /** + * Socket linger. + */ + protected int soLinger = 100; + public int getSoLinger() { return soLinger; } + public void setSoLinger(int soLinger) { this.soLinger = soLinger; } + + + /** + * Socket timeout. + */ + protected int soTimeout = -1; + public int getSoTimeout() { return soTimeout; } + public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } + + + /** + * Timeout on first request read before going to the poller, in ms. + */ + protected int firstReadTimeout = -1; + public int getFirstReadTimeout() { return firstReadTimeout; } + public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; } + + + /** + * Poll interval, in microseconds. The smaller the value, the more CPU the poller + * will use, but the more responsive to activity it will be. + */ + protected int pollTime = 2000; + public int getPollTime() { return pollTime; } + public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } + + + /** + * The default is true - the created threads will be + * in daemon mode. If set to false, the control thread + * will not be daemon - and will keep the process alive. + */ + protected boolean daemon = true; + public void setDaemon(boolean b) { daemon = b; } + public boolean getDaemon() { return daemon; } + + + /** + * Name of the thread pool, which will be used for naming child threads. + */ + protected String name = "TP"; + public void setName(String name) { this.name = name; } + public String getName() { return name; } + + + /** + * Use endfile for sending static files. + */ + protected boolean useSendfile = Library.APR_HAS_SENDFILE; + public void setUseSendfile(boolean useSendfile) { this.useSendfile = useSendfile; } + public boolean getUseSendfile() { return useSendfile; } + + + /** + * Allow comet request handling. + */ + protected boolean useComet = true; + public void setUseComet(boolean useComet) { this.useComet = useComet; } + public boolean getUseComet() { return useComet; } + + + /** + * Acceptor thread count. + */ + protected int acceptorThreadCount = 0; + public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } + public int getAcceptorThreadCount() { return acceptorThreadCount; } + + + /** + * Sendfile thread count. + */ + protected int sendfileThreadCount = 0; + public void setSendfileThreadCount(int sendfileThreadCount) { this.sendfileThreadCount = sendfileThreadCount; } + public int getSendfileThreadCount() { return sendfileThreadCount; } + + + /** + * Poller thread count. + */ + protected int pollerThreadCount = 0; + public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } + public int getPollerThreadCount() { return pollerThreadCount; } + + + /** + * The socket poller. + */ + protected Poller[] pollers = null; + protected int pollerRoundRobin = 0; + public Poller getPoller() { + pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length; + return pollers[pollerRoundRobin]; + } + + + /** + * The socket poller used for Comet support. + */ + protected Poller[] cometPollers = null; + protected int cometPollerRoundRobin = 0; + public Poller getCometPoller() { + cometPollerRoundRobin = (cometPollerRoundRobin + 1) % cometPollers.length; + return cometPollers[cometPollerRoundRobin]; + } + + + /** + * The static file sender. + */ + protected Sendfile[] sendfiles = null; + protected int sendfileRoundRobin = 0; + public Sendfile getSendfile() { + sendfileRoundRobin = (sendfileRoundRobin + 1) % sendfiles.length; + return sendfiles[sendfileRoundRobin]; + } + + + /** + * Dummy maxSpareThreads property. + */ + public int getMaxSpareThreads() { return 0; } + + + /** + * Dummy minSpareThreads property. + */ + public int getMinSpareThreads() { return 0; } + + + /** + * SSL engine. + */ + protected String SSLEngine = "off"; + public String getSSLEngine() { return SSLEngine; } + public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; } + + + /** + * SSL protocols. + */ + protected String SSLProtocol = "all"; + public String getSSLProtocol() { return SSLProtocol; } + public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } + + + /** + * SSL password (if a cert is encrypted, and no password has been provided, a callback + * will ask for a password). + */ + protected String SSLPassword = null; + public String getSSLPassword() { return SSLPassword; } + public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } + + + /** + * SSL cipher suite. + */ + protected String SSLCipherSuite = "ALL"; + public String getSSLCipherSuite() { return SSLCipherSuite; } + public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } + + + /** + * SSL certificate file. + */ + protected String SSLCertificateFile = null; + public String getSSLCertificateFile() { return SSLCertificateFile; } + public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } + + + /** + * SSL certificate key file. + */ + protected String SSLCertificateKeyFile = null; + public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } + public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } + + + /** + * SSL certificate chain file. + */ + protected String SSLCertificateChainFile = null; + public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } + public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } + + + /** + * SSL CA certificate path. + */ + protected String SSLCACertificatePath = null; + public String getSSLCACertificatePath() { return SSLCACertificatePath; } + public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } + + + /** + * SSL CA certificate file. + */ + protected String SSLCACertificateFile = null; + public String getSSLCACertificateFile() { return SSLCACertificateFile; } + public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } + + + /** + * SSL CA revocation path. + */ + protected String SSLCARevocationPath = null; + public String getSSLCARevocationPath() { return SSLCARevocationPath; } + public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } + + + /** + * SSL CA revocation file. + */ + protected String SSLCARevocationFile = null; + public String getSSLCARevocationFile() { return SSLCARevocationFile; } + public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } + + + /** + * SSL verify client. + */ + protected String SSLVerifyClient = "none"; + public String getSSLVerifyClient() { return SSLVerifyClient; } + public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } + + + /** + * SSL verify depth. + */ + protected int SSLVerifyDepth = 10; + public int getSSLVerifyDepth() { return SSLVerifyDepth; } + public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } + + + // --------------------------------------------------------- Public Methods + + + /** + * Number of keepalive sockets. + */ + public int getKeepAliveCount() { + if (pollers == null) { + return 0; + } else { + int keepAliveCount = 0; + for (int i = 0; i < pollers.length; i++) { + keepAliveCount += pollers[i].getKeepAliveCount(); + } + return keepAliveCount; + } + } + + + /** + * Number of sendfile sockets. + */ + public int getSendfileCount() { + if (sendfiles == null) { + return 0; + } else { + int sendfileCount = 0; + for (int i = 0; i < sendfiles.length; i++) { + sendfileCount += sendfiles[i].getSendfileCount(); + } + return sendfileCount; + } + } + + + /** + * Return the amount of threads that are managed by the pool. + * + * @return the amount of threads that are managed by the pool + */ + public int getCurrentThreadCount() { + return curThreads; + } + + + /** + * Return the amount of threads currently busy. + * + * @return the amount of threads currently busy + */ + public int getCurrentThreadsBusy() { + return curThreadsBusy; + } + + + /** + * Return the state of the endpoint. + * + * @return true if the endpoint is running, false otherwise + */ + public boolean isRunning() { + return running; + } + + + /** + * Return the state of the endpoint. + * + * @return true if the endpoint is paused, false otherwise + */ + public boolean isPaused() { + return paused; + } + + + // ----------------------------------------------- Public Lifecycle Methods + + + /** + * Initialize the endpoint. + */ + public void init() + throws Exception { + + if (initialized) + return; + + // Create the root APR memory pool + rootPool = Pool.create(0); + // Create the pool for the server socket + serverSockPool = Pool.create(rootPool); + // Create the APR address that will be bound + String addressStr = null; + if (address == null) { + addressStr = null; + } else { + addressStr = address.getHostAddress(); + } + int family = Socket.APR_INET; + if (Library.APR_HAVE_IPV6 && (addressStr == null || addressStr.indexOf(':') >= 0)) { + family = Socket.APR_UNSPEC; + } + long inetAddress = Address.info(addressStr, family, + port, 0, rootPool); + // Create the APR server socket + serverSock = Socket.create(family, Socket.SOCK_STREAM, + Socket.APR_PROTO_TCP, rootPool); + if (OS.IS_UNIX) { + Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); + } + // Deal with the firewalls that tend to drop the inactive sockets + Socket.optSet(serverSock, Socket.APR_SO_KEEPALIVE, 1); + // Bind the server socket + int ret = Socket.bind(serverSock, inetAddress); + if (ret != 0) { + throw new Exception(sm.getString("endpoint.init.bind", "" + ret, Error.strerror(ret))); + } + // Start listening on the server socket + ret = Socket.listen(serverSock, backlog); + if (ret != 0) { + throw new Exception(sm.getString("endpoint.init.listen", "" + ret, Error.strerror(ret))); + } + if (OS.IS_WIN32 || OS.IS_WIN64) { + // On Windows set the reuseaddr flag after the bind/listen + Socket.optSet(serverSock, Socket.APR_SO_REUSEADDR, 1); + } + + // Sendfile usage on systems which don't support it cause major problems + if (useSendfile && !Library.APR_HAS_SENDFILE) { + log.warn(sm.getString("endpoint.sendfile.nosupport")); + useSendfile = false; + } + + // Initialize thread count defaults for acceptor, poller and sendfile + if (acceptorThreadCount == 0) { + // FIXME: Doesn't seem to work that well with multiple accept threads + acceptorThreadCount = 1; + } + if (pollerThreadCount == 0) { + if ((OS.IS_WIN32 || OS.IS_WIN64) && (pollerSize > 1024)) { + // The maximum per poller to get reasonable performance is 1024 + pollerThreadCount = pollerSize / 1024; + // Adjust poller size so that it won't reach the limit + pollerSize = pollerSize - (pollerSize % 1024); + } else { + // No explicit poller size limitation + pollerThreadCount = 1; + } + } + if (sendfileThreadCount == 0) { + if ((OS.IS_WIN32 || OS.IS_WIN64) && (sendfileSize > 1024)) { + // The maximum per poller to get reasonable performance is 1024 + sendfileThreadCount = sendfileSize / 1024; + // Adjust poller size so that it won't reach the limit + sendfileSize = sendfileSize - (sendfileSize % 1024); + } else { + // No explicit poller size limitation + // FIXME: Default to one per CPU ? + sendfileThreadCount = 1; + } + } + + // Delay accepting of new connections until data is available + // Only Linux kernels 2.4 + have that implemented + // on other platforms this call is noop and will return APR_ENOTIMPL. + Socket.optSet(serverSock, Socket.APR_TCP_DEFER_ACCEPT, 1); + + // Initialize SSL if needed + if (!"off".equalsIgnoreCase(SSLEngine)) { + // Initialize SSL + // FIXME: one per VM call ? + if ("on".equalsIgnoreCase(SSLEngine)) { + SSL.initialize(null); + } else { + SSL.initialize(SSLEngine); + } + // SSL protocol + int value = SSL.SSL_PROTOCOL_ALL; + if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV2; + } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV3; + } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_TLSV1; + } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; + } + // Create SSL Context + sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); + // List the ciphers that the client is permitted to negotiate + SSLContext.setCipherSuite(sslContext, SSLCipherSuite); + // Load Server key and certificate + SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); + // Set certificate chain file + SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); + // Support Client Certificates + SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); + // Set revocation + SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); + // Client certificate verification + value = SSL.SSL_CVERIFY_NONE; + if ("optional".equalsIgnoreCase(SSLVerifyClient)) { + value = SSL.SSL_CVERIFY_OPTIONAL; + } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { + value = SSL.SSL_CVERIFY_REQUIRE; + } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { + value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; + } + SSLContext.setVerify(sslContext, value, SSLVerifyDepth); + // For now, sendfile is not supported with SSL + useSendfile = false; + } + + initialized = true; + + } + + + /** + * Start the APR endpoint, creating acceptor, poller and sendfile threads. + */ + public void start() + throws Exception { + // Initialize socket if not done before + if (!initialized) { + init(); + } + if (!running) { + running = true; + paused = false; + + // Create worker collection + if (executor == null) { + workers = new WorkerStack(maxThreads); + } + + // Start acceptor threads + for (int i = 0; i < acceptorThreadCount; i++) { + Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); + acceptorThread.setPriority(threadPriority); + acceptorThread.setDaemon(daemon); + acceptorThread.start(); + } + + // Start poller threads + pollers = new Poller[pollerThreadCount]; + for (int i = 0; i < pollerThreadCount; i++) { + pollers[i] = new Poller(false); + pollers[i].init(); + Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i); + pollerThread.setPriority(threadPriority); + pollerThread.setDaemon(true); + pollerThread.start(); + } + + // Start comet poller threads + cometPollers = new Poller[pollerThreadCount]; + for (int i = 0; i < pollerThreadCount; i++) { + cometPollers[i] = new Poller(true); + cometPollers[i].init(); + Thread pollerThread = new Thread(cometPollers[i], getName() + "-CometPoller-" + i); + pollerThread.setPriority(threadPriority); + pollerThread.setDaemon(true); + pollerThread.start(); + } + + // Start sendfile threads + if (useSendfile) { + sendfiles = new Sendfile[sendfileThreadCount]; + for (int i = 0; i < sendfileThreadCount; i++) { + sendfiles[i] = new Sendfile(); + sendfiles[i].init(); + Thread sendfileThread = new Thread(sendfiles[i], getName() + "-Sendfile-" + i); + sendfileThread.setPriority(threadPriority); + sendfileThread.setDaemon(true); + sendfileThread.start(); + } + } + } + } + + + /** + * Pause the endpoint, which will make it stop accepting new sockets. + */ + public void pause() { + if (running && !paused) { + paused = true; + unlockAccept(); + } + } + + + /** + * Resume the endpoint, which will make it start accepting new sockets + * again. + */ + public void resume() { + if (running) { + paused = false; + } + } + + + /** + * Stop the endpoint. This will cause all processing threads to stop. + */ + public void stop() { + if (running) { + running = false; + unlockAccept(); + for (int i = 0; i < pollers.length; i++) { + pollers[i].destroy(); + } + pollers = null; + for (int i = 0; i < cometPollers.length; i++) { + cometPollers[i].destroy(); + } + cometPollers = null; + if (useSendfile) { + for (int i = 0; i < sendfiles.length; i++) { + sendfiles[i].destroy(); + } + sendfiles = null; + } + } + } + + + /** + * Deallocate APR memory pools, and close server socket. + */ + public void destroy() throws Exception { + if (running) { + stop(); + } + Pool.destroy(serverSockPool); + serverSockPool = 0; + // Close server socket + Socket.close(serverSock); + serverSock = 0; + sslContext = 0; + // Close all APR memory pools and resources + Pool.destroy(rootPool); + rootPool = 0; + initialized = false; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Get a sequence number used for thread naming. + */ + protected int getSequence() { + return sequence++; + } + + + /** + * Unlock the server socket accept using a bugus connection. + */ + protected void unlockAccept() { + java.net.Socket s = null; + try { + // Need to create a connection to unlock the accept(); + if (address == null) { + s = new java.net.Socket("127.0.0.1", port); + } else { + s = new java.net.Socket(address, port); + // setting soLinger to a small value will help shutdown the + // connection quicker + s.setSoLinger(true, 0); + } + } catch(Exception e) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + } + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e) { + // Ignore + } + } + } + } + + + /** + * Process the specified connection. + */ + protected boolean setSocketOptions(long socket) { + // Process the connection + int step = 1; + try { + + // 1: Set socket options: timeout, linger, etc + if (soLinger >= 0) + Socket.optSet(socket, Socket.APR_SO_LINGER, soLinger); + if (tcpNoDelay) + Socket.optSet(socket, Socket.APR_TCP_NODELAY, (tcpNoDelay ? 1 : 0)); + if (soTimeout > 0) + Socket.timeoutSet(socket, soTimeout * 1000); + + // 2: SSL handshake + step = 2; + if (sslContext != 0) { + SSLSocket.attach(sslContext, socket); + if (SSLSocket.handshake(socket) != 0) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); + } + return false; + } + } + + } catch (Throwable t) { + if (log.isDebugEnabled()) { + if (step == 2) { + log.debug(sm.getString("endpoint.err.handshake"), t); + } else { + log.debug(sm.getString("endpoint.err.unexpected"), t); + } + } + // Tell to close the socket + return false; + } + return true; + } + + + /** + * Create (or allocate) and return an available processor for use in + * processing a specific HTTP request, if possible. If the maximum + * allowed processors have already been created and are in use, return + * null instead. + */ + protected Worker createWorkerThread() { + + synchronized (workers) { + if (workers.size() > 0) { + curThreadsBusy++; + return (workers.pop()); + } + if ((maxThreads > 0) && (curThreads < maxThreads)) { + curThreadsBusy++; + return (newWorkerThread()); + } else { + if (maxThreads < 0) { + curThreadsBusy++; + return (newWorkerThread()); + } else { + return (null); + } + } + } + + } + + + /** + * Create and return a new processor suitable for processing HTTP + * requests and returning the corresponding responses. + */ + protected Worker newWorkerThread() { + + Worker workerThread = new Worker(); + workerThread.start(); + return (workerThread); + + } + + + /** + * Return a new worker thread, and block while to worker is available. + */ + protected Worker getWorkerThread() { + // Allocate a new worker thread + Worker workerThread = createWorkerThread(); + while (workerThread == null) { + try { + synchronized (workers) { + workers.wait(); + } + } catch (InterruptedException e) { + // Ignore + } + workerThread = createWorkerThread(); + } + return workerThread; + } + + + /** + * Recycle the specified Processor so that it can be used again. + * + * @param workerThread The processor to be recycled + */ + protected void recycleWorkerThread(Worker workerThread) { + synchronized (workers) { + workers.push(workerThread); + curThreadsBusy--; + workers.notify(); + } + } + + + /** + * Allocate a new poller of the specified size. + */ + protected long allocatePoller(int size, long pool, int timeout) { + try { + return Poll.create(size, pool, 0, timeout * 1000); + } catch (Error e) { + if (Status.APR_STATUS_IS_EINVAL(e.getError())) { + log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); + return 0; + } else { + log.error(sm.getString("endpoint.poll.initfail"), e); + return -1; + } + } + } + + + /** + * Process given socket. + */ + protected boolean processSocket(long socket) { + try { + if (executor == null) { + getWorkerThread().assign(socket); + } else { + executor.execute(new SocketProcessor(socket)); + } + } catch (Throwable t) { + // This means we got an OOM or similar creating a thread, or that + // the pool and its queue are full + log.error(sm.getString("endpoint.process.fail"), t); + return false; + } + return true; + } + + + /** + * Process given socket for an event. + */ + protected boolean processSocket(long socket, boolean error) { + try { + if (executor == null) { + getWorkerThread().assign(socket, error); + } else { + executor.execute(new SocketEventProcessor(socket, error)); + } + } catch (Throwable t) { + // This means we got an OOM or similar creating a thread, or that + // the pool and its queue are full + log.error(sm.getString("endpoint.process.fail"), t); + return false; + } + return true; + } + + + // --------------------------------------------------- Acceptor Inner Class + + + /** + * Server socket acceptor thread. + */ + protected class Acceptor implements Runnable { + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Loop until we receive a shutdown command + while (running) { + + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + try { + // Accept the next incoming connection from the server socket + long socket = Socket.accept(serverSock); + // Hand this socket off to an appropriate processor + if (!setSocketOptions(socket) || !processSocket(socket)) { + // Close socket and pool right away + Socket.destroy(socket); + } + } catch (Throwable t) { + log.error(sm.getString("endpoint.accept.fail"), t); + } + + // The processor will recycle itself when it finishes + + } + + } + + } + + + // ----------------------------------------------------- Poller Inner Class + + + /** + * Poller class. + */ + public class Poller implements Runnable { + + protected long serverPollset = 0; + protected long pool = 0; + protected long[] desc; + + protected long[] addS; + protected int addCount = 0; + + protected boolean comet = true; + + protected int keepAliveCount = 0; + public int getKeepAliveCount() { return keepAliveCount; } + + public Poller(boolean comet) { + this.comet = comet; + } + + /** + * Create the poller. With some versions of APR, the maximum poller size will + * be 62 (reocmpiling APR is necessary to remove this limitation). + */ + protected void init() { + pool = Pool.create(serverSockPool); + int size = pollerSize / pollerThreadCount; + int timeout = soTimeout; + if (comet) { + // FIXME: Find an appropriate timeout value, for now, "longer than usual" + // semms appropriate + timeout = soTimeout * 50; + } + serverPollset = allocatePoller(size, pool, timeout); + if (serverPollset == 0 && size > 1024) { + size = 1024; + serverPollset = allocatePoller(size, pool, timeout); + } + if (serverPollset == 0) { + size = 62; + serverPollset = allocatePoller(size, pool, timeout); + } + desc = new long[size * 2]; + keepAliveCount = 0; + addS = new long[size]; + addCount = 0; + } + + /** + * Destroy the poller. + */ + protected void destroy() { + // Wait for polltime before doing anything, so that the poller threads + // exit, otherwise parallel descturction of sockets which are still + // in the poller can cause problems + try { + synchronized (this) { + this.wait(pollTime / 1000); + } + } catch (InterruptedException e) { + // Ignore + } + // Close all sockets in the add queue + for (int i = 0; i < addCount; i++) { + if (comet) { + processSocket(addS[i], true); + } else { + Socket.destroy(addS[i]); + } + } + // Close all sockets still in the poller + int rv = Poll.pollset(serverPollset, desc); + if (rv > 0) { + for (int n = 0; n < rv; n++) { + if (comet) { + processSocket(desc[n*2+1], true); + } else { + Socket.destroy(desc[n*2+1]); + } + } + } + Pool.destroy(pool); + keepAliveCount = 0; + addCount = 0; + } + + /** + * Add specified socket and associated pool to the poller. The socket will + * be added to a temporary array, and polled first after a maximum amount + * of time equal to pollTime (in most cases, latency will be much lower, + * however). + * + * @param socket to add to the poller + */ + public void add(long socket) { + synchronized (this) { + // Add socket to the list. Newly added sockets will wait + // at most for pollTime before being polled + if (addCount >= addS.length) { + // Can't do anything: close the socket right away + if (comet) { + processSocket(socket, true); + } else { + Socket.destroy(socket); + } + return; + } + addS[addCount] = socket; + addCount++; + this.notify(); + } + } + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + long maintainTime = 0; + // Loop until we receive a shutdown command + while (running) { + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + while (keepAliveCount < 1 && addCount < 1) { + // Reset maintain time. + maintainTime = 0; + try { + synchronized (this) { + this.wait(); + } + } catch (InterruptedException e) { + // Ignore + } + } + + try { + // Add sockets which are waiting to the poller + if (addCount > 0) { + synchronized (this) { + for (int i = (addCount - 1); i >= 0; i--) { + int rv = Poll.add + (serverPollset, addS[i], Poll.APR_POLLIN); + if (rv == Status.APR_SUCCESS) { + keepAliveCount++; + } else { + // Can't do anything: close the socket right away + if (comet) { + processSocket(addS[i], true); + } else { + Socket.destroy(addS[i]); + } + } + } + addCount = 0; + } + } + + maintainTime += pollTime; + // Pool for the specified interval + int rv = Poll.poll(serverPollset, pollTime, desc, true); + if (rv > 0) { + keepAliveCount -= rv; + for (int n = 0; n < rv; n++) { + // Check for failed sockets and hand this socket off to a worker + if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) + || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR) + || (comet && (!processSocket(desc[n*2+1], false))) + || (!comet && (!processSocket(desc[n*2+1])))) { + // Close socket and clear pool + if (comet) { + processSocket(desc[n*2+1], true); + } else { + Socket.destroy(desc[n*2+1]); + } + continue; + } + } + } else if (rv < 0) { + int errn = -rv; + /* Any non timeup or interrupted error is critical */ + if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { + if (errn > Status.APR_OS_START_USERERR) { + errn -= Status.APR_OS_START_USERERR; + } + log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); + // Handle poll critical failure + synchronized (this) { + destroy(); + init(); + } + continue; + } + } + if (soTimeout > 0 && maintainTime > 1000000L && running) { + rv = Poll.maintain(serverPollset, desc, true); + maintainTime = 0; + if (rv > 0) { + keepAliveCount -= rv; + for (int n = 0; n < rv; n++) { + // Close socket and clear pool + if (comet) { + processSocket(desc[n], true); + } else { + Socket.destroy(desc[n]); + } + } + } + } + } catch (Throwable t) { + log.error(sm.getString("endpoint.poll.error"), t); + } + + } + + synchronized (this) { + this.notifyAll(); + } + + } + + } + + + // ----------------------------------------------------- Worker Inner Class + + + /** + * Server processor class. + */ + protected class Worker implements Runnable { + + + protected Thread thread = null; + protected boolean available = false; + protected long socket = 0; + protected boolean event = false; + protected boolean error = false; + + + /** + * Process an incoming TCP/IP connection on the specified socket. Any + * exception that occurs during processing must be logged and swallowed. + * NOTE: This method is called from our Connector's thread. We + * must assign it to our own thread so that multiple simultaneous + * requests can be handled. + * + * @param socket TCP socket to process + */ + protected synchronized void assign(long socket) { + + // Wait for the Processor to get the previous Socket + while (available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Store the newly available Socket and notify our thread + this.socket = socket; + event = false; + error = false; + available = true; + notifyAll(); + + } + + + protected synchronized void assign(long socket, boolean error) { + + // Wait for the Processor to get the previous Socket + while (available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Store the newly available Socket and notify our thread + this.socket = socket; + event = true; + this.error = error; + available = true; + notifyAll(); + + } + + + /** + * Await a newly assigned Socket from our Connector, or null + * if we are supposed to shut down. + */ + protected synchronized long await() { + + // Wait for the Connector to provide a new Socket + while (!available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Notify the Connector that we have received this Socket + long socket = this.socket; + available = false; + notifyAll(); + + return (socket); + + } + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Process requests until we receive a shutdown signal + while (running) { + + // Wait for the next socket to be assigned + long socket = await(); + if (socket == 0) + continue; + + // Process the request from this socket + if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { + // Close socket and pool + Socket.destroy(socket); + socket = 0; + } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { + // Close socket and pool + Socket.destroy(socket); + socket = 0; + } + + // Finish up this request + recycleWorkerThread(this); + + } + + } + + + /** + * Start the background processing thread. + */ + public void start() { + thread = new Thread(this); + thread.setName(getName() + "-" + (++curThreads)); + thread.setDaemon(true); + thread.start(); + } + + + } + + + // ----------------------------------------------- SendfileData Inner Class + + + /** + * SendfileData class. + */ + public static class SendfileData { + // File + public String fileName; + public long fd; + public long fdpool; + // Range information + public long start; + public long end; + // Socket and socket pool + public long socket; + // Position + public long pos; + // KeepAlive flag + public boolean keepAlive; + } + + + // --------------------------------------------------- Sendfile Inner Class + + + /** + * Sendfile class. + */ + public class Sendfile implements Runnable { + + protected long sendfilePollset = 0; + protected long pool = 0; + protected long[] desc; + protected HashMap sendfileData; + + protected int sendfileCount; + public int getSendfileCount() { return sendfileCount; } + + protected ArrayList addS; + + /** + * Create the sendfile poller. With some versions of APR, the maximum poller size will + * be 62 (reocmpiling APR is necessary to remove this limitation). + */ + protected void init() { + pool = Pool.create(serverSockPool); + int size = sendfileSize / sendfileThreadCount; + sendfilePollset = allocatePoller(size, pool, soTimeout); + if (sendfilePollset == 0 && size > 1024) { + size = 1024; + sendfilePollset = allocatePoller(size, pool, soTimeout); + } + if (sendfilePollset == 0) { + size = 62; + sendfilePollset = allocatePoller(size, pool, soTimeout); + } + desc = new long[size * 2]; + sendfileData = new HashMap(size); + addS = new ArrayList(); + } + + /** + * Destroy the poller. + */ + protected void destroy() { + // Wait for polltime before doing anything, so that the poller threads + // exit, otherwise parallel descturction of sockets which are still + // in the poller can cause problems + try { + synchronized (this) { + this.wait(pollTime / 1000); + } + } catch (InterruptedException e) { + // Ignore + } + // Close any socket remaining in the add queue + for (int i = (addS.size() - 1); i >= 0; i--) { + SendfileData data = addS.get(i); + Socket.destroy(data.socket); + } + // Close all sockets still in the poller + int rv = Poll.pollset(sendfilePollset, desc); + if (rv > 0) { + for (int n = 0; n < rv; n++) { + Socket.destroy(desc[n*2+1]); + } + } + Pool.destroy(pool); + sendfileData.clear(); + } + + /** + * Add the sendfile data to the sendfile poller. Note that in most cases, + * the initial non blocking calls to sendfile will return right away, and + * will be handled asynchronously inside the kernel. As a result, + * the poller will never be used. + * + * @param data containing the reference to the data which should be snet + * @return true if all the data has been sent right away, and false + * otherwise + */ + public boolean add(SendfileData data) { + // Initialize fd from data given + try { + data.fdpool = Socket.pool(data.socket); + data.fd = File.open + (data.fileName, File.APR_FOPEN_READ + | File.APR_FOPEN_SENDFILE_ENABLED | File.APR_FOPEN_BINARY, + 0, data.fdpool); + data.pos = data.start; + // Set the socket to nonblocking mode + Socket.timeoutSet(data.socket, 0); + while (true) { + long nw = Socket.sendfilen(data.socket, data.fd, + data.pos, data.end - data.pos, 0); + if (nw < 0) { + if (!(-nw == Status.EAGAIN)) { + Socket.destroy(data.socket); + data.socket = 0; + return false; + } else { + // Break the loop and add the socket to poller. + break; + } + } else { + data.pos = data.pos + nw; + if (data.pos >= data.end) { + // Entire file has been sent + Pool.destroy(data.fdpool); + // Set back socket to blocking mode + Socket.timeoutSet(data.socket, soTimeout * 1000); + return true; + } + } + } + } catch (Exception e) { + log.error(sm.getString("endpoint.sendfile.error"), e); + return false; + } + // Add socket to the list. Newly added sockets will wait + // at most for pollTime before being polled + synchronized (this) { + addS.add(data); + this.notify(); + } + return false; + } + + /** + * Remove socket from the poller. + * + * @param data the sendfile data which should be removed + */ + protected void remove(SendfileData data) { + int rv = Poll.remove(sendfilePollset, data.socket); + if (rv == Status.APR_SUCCESS) { + sendfileCount--; + } + sendfileData.remove(data); + } + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Loop until we receive a shutdown command + while (running) { + + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + while (sendfileCount < 1 && addS.size() < 1) { + try { + synchronized (this) { + this.wait(); + } + } catch (InterruptedException e) { + // Ignore + } + } + + try { + // Add socket to the poller + if (addS.size() > 0) { + synchronized (this) { + for (int i = (addS.size() - 1); i >= 0; i--) { + SendfileData data = addS.get(i); + int rv = Poll.add(sendfilePollset, data.socket, Poll.APR_POLLOUT); + if (rv == Status.APR_SUCCESS) { + sendfileData.put(new Long(data.socket), data); + sendfileCount++; + } else { + log.warn(sm.getString("endpoint.sendfile.addfail", "" + rv, Error.strerror(rv))); + // Can't do anything: close the socket right away + Socket.destroy(data.socket); + } + } + addS.clear(); + } + } + // Pool for the specified interval + int rv = Poll.poll(sendfilePollset, pollTime, desc, false); + if (rv > 0) { + for (int n = 0; n < rv; n++) { + // Get the sendfile state + SendfileData state = + sendfileData.get(new Long(desc[n*2+1])); + // Problem events + if (((desc[n*2] & Poll.APR_POLLHUP) == Poll.APR_POLLHUP) + || ((desc[n*2] & Poll.APR_POLLERR) == Poll.APR_POLLERR)) { + // Close socket and clear pool + remove(state); + // Destroy file descriptor pool, which should close the file + // Close the socket, as the reponse would be incomplete + Socket.destroy(state.socket); + continue; + } + // Write some data using sendfile + long nw = Socket.sendfilen(state.socket, state.fd, + state.pos, + state.end - state.pos, 0); + if (nw < 0) { + // Close socket and clear pool + remove(state); + // Close the socket, as the reponse would be incomplete + // This will close the file too. + Socket.destroy(state.socket); + continue; + } + + state.pos = state.pos + nw; + if (state.pos >= state.end) { + remove(state); + if (state.keepAlive) { + // Destroy file descriptor pool, which should close the file + Pool.destroy(state.fdpool); + Socket.timeoutSet(state.socket, soTimeout * 1000); + // If all done hand this socket off to a worker for + // processing of further requests + if (!processSocket(state.socket)) { + Socket.destroy(state.socket); + } + } else { + // Close the socket since this is + // the end of not keep-alive request. + Socket.destroy(state.socket); + } + } + } + } else if (rv < 0) { + int errn = -rv; + /* Any non timeup or interrupted error is critical */ + if ((errn != Status.TIMEUP) && (errn != Status.EINTR)) { + if (errn > Status.APR_OS_START_USERERR) { + errn -= Status.APR_OS_START_USERERR; + } + log.error(sm.getString("endpoint.poll.fail", "" + errn, Error.strerror(errn))); + // Handle poll critical failure + synchronized (this) { + destroy(); + init(); + } + continue; + } + } + /* TODO: See if we need to call the maintain for sendfile poller */ + } catch (Throwable t) { + log.error(sm.getString("endpoint.poll.error"), t); + } + } + + synchronized (this) { + this.notifyAll(); + } + + } + + } + + + // ------------------------------------------------ Handler Inner Interface + + + /** + * Bare bones interface used for socket processing. Per thread data is to be + * stored in the ThreadWithAttributes extra folders, or alternately in + * thread local fields. + */ + public interface Handler { + public enum SocketState { + OPEN, CLOSED, LONG + } + public SocketState process(long socket); + public SocketState event(long socket, boolean error); + } + + + // ------------------------------------------------- WorkerStack Inner Class + + + public class WorkerStack { + + protected Worker[] workers = null; + protected int end = 0; + + public WorkerStack(int size) { + workers = new Worker[size]; + } + + /** + * Put the object into the queue. + * + * @param object the object to be appended to the queue (first element). + */ + public void push(Worker worker) { + workers[end++] = worker; + } + + /** + * Get the first object out of the queue. Return null if the queue + * is empty. + */ + public Worker pop() { + if (end > 0) { + return workers[--end]; + } + return null; + } + + /** + * Get the first object out of the queue, Return null if the queue + * is empty. + */ + public Worker peek() { + return workers[end]; + } + + /** + * Is the queue empty? + */ + public boolean isEmpty() { + return (end == 0); + } + + /** + * How many elements are there in this queue? + */ + public int size() { + return (end); + } + } + + + // ---------------------------------------------- SocketProcessor Inner Class + + + /** + * This class is the equivalent of the Worker, but will simply use in an + * external Executor thread pool. + */ + protected class SocketProcessor implements Runnable { + + protected long socket = 0; + + public SocketProcessor(long socket) { + this.socket = socket; + } + + public void run() { + + // Process the request from this socket + if (handler.process(socket) == Handler.SocketState.CLOSED) { + // Close socket and pool + Socket.destroy(socket); + socket = 0; + } + + } + + } + + + // --------------------------------------- SocketEventProcessor Inner Class + + + /** + * This class is the equivalent of the Worker, but will simply use in an + * external Executor thread pool. + */ + protected class SocketEventProcessor implements Runnable { + + protected long socket = 0; + protected boolean error = false; + + public SocketEventProcessor(long socket, boolean error) { + this.socket = socket; + this.error = error; + } + + public void run() { + + // Process the request from this socket + if (handler.event(socket, error) == Handler.SocketState.CLOSED) { + // Close socket and pool + Socket.destroy(socket); + socket = 0; + } + + } + + } + + +} diff --git a/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java b/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java index b677e9899..d6c56c1a9 100644 --- a/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java +++ b/java/org/apache/tomcat/util/net/DefaultServerSocketFactory.java @@ -1,69 +1,69 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.io.*; -import java.net.*; - -/** - * Default server socket factory. Doesn't do much except give us - * plain ol' server sockets. - * - * @author db@eng.sun.com - * @author Harish Prabandham - */ - -// Default implementation of server sockets. - -// -// WARNING: Some of the APIs in this class are used by J2EE. -// Please talk to harishp@eng.sun.com before making any changes. -// -class DefaultServerSocketFactory extends ServerSocketFactory { - - DefaultServerSocketFactory () { - /* NOTHING */ - } - - public ServerSocket createSocket (int port) - throws IOException { - return new ServerSocket (port); - } - - public ServerSocket createSocket (int port, int backlog) - throws IOException { - return new ServerSocket (port, backlog); - } - - public ServerSocket createSocket (int port, int backlog, - InetAddress ifAddress) - throws IOException { - return new ServerSocket (port, backlog, ifAddress); - } - - public Socket acceptSocket(ServerSocket socket) - throws IOException { - return socket.accept(); - } - - public void handshake(Socket sock) - throws IOException { - ; // NOOP - } - - - } +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.*; +import java.net.*; + +/** + * Default server socket factory. Doesn't do much except give us + * plain ol' server sockets. + * + * @author db@eng.sun.com + * @author Harish Prabandham + */ + +// Default implementation of server sockets. + +// +// WARNING: Some of the APIs in this class are used by J2EE. +// Please talk to harishp@eng.sun.com before making any changes. +// +class DefaultServerSocketFactory extends ServerSocketFactory { + + DefaultServerSocketFactory () { + /* NOTHING */ + } + + public ServerSocket createSocket (int port) + throws IOException { + return new ServerSocket (port); + } + + public ServerSocket createSocket (int port, int backlog) + throws IOException { + return new ServerSocket (port, backlog); + } + + public ServerSocket createSocket (int port, int backlog, + InetAddress ifAddress) + throws IOException { + return new ServerSocket (port, backlog, ifAddress); + } + + public Socket acceptSocket(ServerSocket socket) + throws IOException { + return socket.accept(); + } + + public void handshake(Socket sock) + throws IOException { + ; // NOOP + } + + + } diff --git a/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java b/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java index ea0761f0a..386e43fcd 100644 --- a/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java +++ b/java/org/apache/tomcat/util/net/LeaderFollowerWorkerThread.java @@ -1,86 +1,86 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.net.Socket; -import org.apache.tomcat.util.threads.ThreadPoolRunnable; - -/* - * I switched the threading model here. - * - * We used to have a "listener" thread and a "connection" - * thread, this results in code simplicity but also a needless - * thread switch. - * - * Instead I am now using a pool of threads, all the threads are - * simmetric in their execution and no thread switch is needed. - */ -class LeaderFollowerWorkerThread implements ThreadPoolRunnable { - /* This is not a normal Runnable - it gets attached to an existing - thread, runs and when run() ends - the thread keeps running. - - It's better to keep the name ThreadPoolRunnable - avoid confusion. - We also want to use per/thread data and avoid sync wherever possible. - */ - PoolTcpEndpoint endpoint; - - public LeaderFollowerWorkerThread(PoolTcpEndpoint endpoint) { - this.endpoint = endpoint; - } - - public Object[] getInitData() { - // no synchronization overhead, but 2 array access - Object obj[]=new Object[2]; - obj[1]= endpoint.getConnectionHandler().init(); - obj[0]=new TcpConnection(); - return obj; - } - - public void runIt(Object perThrData[]) { - - // Create per-thread cache - if (endpoint.isRunning()) { - - // Loop if endpoint is paused - while (endpoint.isPaused()) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - // Accept a new connection - Socket s = null; - try { - s = endpoint.acceptSocket(); - } finally { - // Continue accepting on another thread... - if (endpoint.isRunning()) { - endpoint.tp.runIt(this); - } - } - - // Process the connection - if (null != s) { - endpoint.processSocket(s, (TcpConnection) perThrData[0], (Object[]) perThrData[1]); - } - - } - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.net.Socket; +import org.apache.tomcat.util.threads.ThreadPoolRunnable; + +/* + * I switched the threading model here. + * + * We used to have a "listener" thread and a "connection" + * thread, this results in code simplicity but also a needless + * thread switch. + * + * Instead I am now using a pool of threads, all the threads are + * simmetric in their execution and no thread switch is needed. + */ +class LeaderFollowerWorkerThread implements ThreadPoolRunnable { + /* This is not a normal Runnable - it gets attached to an existing + thread, runs and when run() ends - the thread keeps running. + + It's better to keep the name ThreadPoolRunnable - avoid confusion. + We also want to use per/thread data and avoid sync wherever possible. + */ + PoolTcpEndpoint endpoint; + + public LeaderFollowerWorkerThread(PoolTcpEndpoint endpoint) { + this.endpoint = endpoint; + } + + public Object[] getInitData() { + // no synchronization overhead, but 2 array access + Object obj[]=new Object[2]; + obj[1]= endpoint.getConnectionHandler().init(); + obj[0]=new TcpConnection(); + return obj; + } + + public void runIt(Object perThrData[]) { + + // Create per-thread cache + if (endpoint.isRunning()) { + + // Loop if endpoint is paused + while (endpoint.isPaused()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + // Accept a new connection + Socket s = null; + try { + s = endpoint.acceptSocket(); + } finally { + // Continue accepting on another thread... + if (endpoint.isRunning()) { + endpoint.tp.runIt(this); + } + } + + // Process the connection + if (null != s) { + endpoint.processSocket(s, (TcpConnection) perThrData[0], (Object[]) perThrData[1]); + } + + } + } + +} diff --git a/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java b/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java index 4c08a46a9..9d35fa7cc 100644 --- a/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java +++ b/java/org/apache/tomcat/util/net/MasterSlaveWorkerThread.java @@ -1,150 +1,150 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.net.Socket; - -import org.apache.tomcat.util.threads.ThreadWithAttributes; - -/** - * Regular master slave thread pool. Slave threads will wait for work. - */ -class MasterSlaveWorkerThread implements Runnable { - - protected PoolTcpEndpoint endpoint; - protected String threadName; - protected boolean stopped = false; - private Object threadSync = new Object(); - private Thread thread = null; - private boolean available = false; - private Socket socket = null; - private TcpConnection con = new TcpConnection(); - private Object[] threadData = null; - - - public MasterSlaveWorkerThread(PoolTcpEndpoint endpoint, String threadName) { - this.endpoint = endpoint; - this.threadName = threadName; - } - - - /** - * Process an incoming TCP/IP connection on the specified socket. Any - * exception that occurs during processing must be logged and swallowed. - * NOTE: This method is called from our Connector's thread. We - * must assign it to our own thread so that multiple simultaneous - * requests can be handled. - * - * @param socket TCP socket to process - */ - synchronized void assign(Socket socket) { - - // Wait for the Processor to get the previous Socket - while (available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Store the newly available Socket and notify our thread - this.socket = socket; - available = true; - notifyAll(); - - } - - - /** - * Await a newly assigned Socket from our Connector, or null - * if we are supposed to shut down. - */ - private synchronized Socket await() { - - // Wait for the Connector to provide a new Socket - while (!available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Notify the Connector that we have received this Socket - Socket socket = this.socket; - available = false; - notifyAll(); - - return (socket); - - } - - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Process requests until we receive a shutdown signal - while (!stopped) { - - // Wait for the next socket to be assigned - Socket socket = await(); - if (socket == null) - continue; - - // Process the request from this socket - endpoint.processSocket(socket, con, threadData); - - // Finish up this request - endpoint.recycleWorkerThread(this); - - } - - // Tell threadStop() we have shut ourselves down successfully - synchronized (threadSync) { - threadSync.notifyAll(); - } - - } - - - /** - * Start the background processing thread. - */ - public void start() { - threadData = endpoint.getConnectionHandler().init(); - thread = new ThreadWithAttributes(null, this); - thread.setName(threadName); - thread.setDaemon(true); - thread.start(); - } - - - /** - * Stop the background processing thread. - */ - public void stop() { - stopped = true; - assign(null); - thread = null; - threadData = null; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.net.Socket; + +import org.apache.tomcat.util.threads.ThreadWithAttributes; + +/** + * Regular master slave thread pool. Slave threads will wait for work. + */ +class MasterSlaveWorkerThread implements Runnable { + + protected PoolTcpEndpoint endpoint; + protected String threadName; + protected boolean stopped = false; + private Object threadSync = new Object(); + private Thread thread = null; + private boolean available = false; + private Socket socket = null; + private TcpConnection con = new TcpConnection(); + private Object[] threadData = null; + + + public MasterSlaveWorkerThread(PoolTcpEndpoint endpoint, String threadName) { + this.endpoint = endpoint; + this.threadName = threadName; + } + + + /** + * Process an incoming TCP/IP connection on the specified socket. Any + * exception that occurs during processing must be logged and swallowed. + * NOTE: This method is called from our Connector's thread. We + * must assign it to our own thread so that multiple simultaneous + * requests can be handled. + * + * @param socket TCP socket to process + */ + synchronized void assign(Socket socket) { + + // Wait for the Processor to get the previous Socket + while (available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Store the newly available Socket and notify our thread + this.socket = socket; + available = true; + notifyAll(); + + } + + + /** + * Await a newly assigned Socket from our Connector, or null + * if we are supposed to shut down. + */ + private synchronized Socket await() { + + // Wait for the Connector to provide a new Socket + while (!available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Notify the Connector that we have received this Socket + Socket socket = this.socket; + available = false; + notifyAll(); + + return (socket); + + } + + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Process requests until we receive a shutdown signal + while (!stopped) { + + // Wait for the next socket to be assigned + Socket socket = await(); + if (socket == null) + continue; + + // Process the request from this socket + endpoint.processSocket(socket, con, threadData); + + // Finish up this request + endpoint.recycleWorkerThread(this); + + } + + // Tell threadStop() we have shut ourselves down successfully + synchronized (threadSync) { + threadSync.notifyAll(); + } + + } + + + /** + * Start the background processing thread. + */ + public void start() { + threadData = endpoint.getConnectionHandler().init(); + thread = new ThreadWithAttributes(null, this); + thread.setName(threadName); + thread.setDaemon(true); + thread.start(); + } + + + /** + * Stop the background processing thread. + */ + public void stop() { + stopped = true; + assign(null); + thread = null; + threadData = null; + } + + +} diff --git a/java/org/apache/tomcat/util/net/NioEndpoint.java b/java/org/apache/tomcat/util/net/NioEndpoint.java index abb8e8eaa..f5ee33349 100644 --- a/java/org/apache/tomcat/util/net/NioEndpoint.java +++ b/java/org/apache/tomcat/util/net/NioEndpoint.java @@ -1,1527 +1,1527 @@ -/* - * Copyright 2005-2006 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.nio.channels.CancelledKeyException; -import java.nio.channels.SelectionKey; -import java.nio.channels.Selector; -import java.nio.channels.ServerSocketChannel; -import java.nio.channels.SocketChannel; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.Set; -import java.util.concurrent.Executor; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.jni.Error; -import org.apache.tomcat.jni.Library; -import org.apache.tomcat.jni.Poll; -import org.apache.tomcat.jni.SSL; -import org.apache.tomcat.jni.Status; -import org.apache.tomcat.util.res.StringManager; - -/** - * NIO tailored thread pool, providing the following services: - *
          - *
        • Socket acceptor thread
        • - *
        • Socket poller thread
        • - *
        • Worker threads pool
        • - *
        - * - * When switching to Java 5, there's an opportunity to use the virtual - * machine's thread pool. - * - * @author Mladen Turk - * @author Remy Maucherat - * @author Filip Hanik - */ -public class NioEndpoint { - - - // -------------------------------------------------------------- Constants - - - protected static Log log = LogFactory.getLog(NioEndpoint.class); - - protected static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.net.res"); - - - /** - * The Request attribute key for the cipher suite. - */ - public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; - - /** - * The Request attribute key for the key size. - */ - public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; - - /** - * The Request attribute key for the client certificate chain. - */ - public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; - - /** - * The Request attribute key for the session id. - * This one is a Tomcat extension to the Servlet spec. - */ - public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; - - - // ----------------------------------------------------------------- Fields - - - /** - * Available workers. - */ - protected WorkerStack workers = null; - - - /** - * Running state of the endpoint. - */ - protected volatile boolean running = false; - - - /** - * Will be set to true whenever the endpoint is paused. - */ - protected volatile boolean paused = false; - - - /** - * Track the initialization state of the endpoint. - */ - protected boolean initialized = false; - - - /** - * Current worker threads busy count. - */ - protected int curThreadsBusy = 0; - - - /** - * Current worker threads count. - */ - protected int curThreads = 0; - - - /** - * Sequence number used to generate thread names. - */ - protected int sequence = 0; - - - /** - * Root APR memory pool. - */ - protected long rootPool = 0; - - - /** - * Server socket "pointer". - */ - protected ServerSocketChannel serverSock = null; - - - /** - * APR memory pool for the server socket. - */ - protected long serverSockPool = 0; - - - /** - * SSL context. - */ - protected long sslContext = 0; - - - // ------------------------------------------------------------- Properties - - - /** - * External Executor based thread pool. - */ - protected Executor executor = null; - public void setExecutor(Executor executor) { this.executor = executor; } - public Executor getExecutor() { return executor; } - - - /** - * Maximum amount of worker threads. - */ - protected int maxThreads = 40; - public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } - public int getMaxThreads() { return maxThreads; } - - - /** - * Priority of the acceptor and poller threads. - */ - protected int threadPriority = Thread.NORM_PRIORITY; - public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } - public int getThreadPriority() { return threadPriority; } - - - /** - * Size of the socket poller. - */ - protected int pollerSize = 8 * 1024; - public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } - public int getPollerSize() { return pollerSize; } - - - - /** - * Server socket port. - */ - protected int port; - public int getPort() { return port; } - public void setPort(int port ) { this.port=port; } - - - /** - * Address for the server socket. - */ - protected InetAddress address; - public InetAddress getAddress() { return address; } - public void setAddress(InetAddress address) { this.address = address; } - - - /** - * Handling of accepted sockets. - */ - protected Handler handler = null; - public void setHandler(Handler handler ) { this.handler = handler; } - public Handler getHandler() { return handler; } - - - /** - * Allows the server developer to specify the backlog that - * should be used for server sockets. By default, this value - * is 100. - */ - protected int backlog = 100; - public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } - public int getBacklog() { return backlog; } - - - /** - * Socket TCP no delay. - */ - protected boolean tcpNoDelay = false; - public boolean getTcpNoDelay() { return tcpNoDelay; } - public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } - - - /** - * Socket linger. - */ - protected int soLinger = 100; - public int getSoLinger() { return soLinger; } - public void setSoLinger(int soLinger) { this.soLinger = soLinger; } - - - /** - * Socket timeout. - */ - protected int soTimeout = -1; - public int getSoTimeout() { return soTimeout; } - public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } - - - /** - * Timeout on first request read before going to the poller, in ms. - */ - protected int firstReadTimeout = 60000; - public int getFirstReadTimeout() { return firstReadTimeout; } - public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; } - - - /** - * Poll interval, in microseconds. The smaller the value, the more CPU the poller - * will use, but the more responsive to activity it will be. - */ - protected int pollTime = 2000; - public int getPollTime() { return pollTime; } - public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } - - - /** - * The default is true - the created threads will be - * in daemon mode. If set to false, the control thread - * will not be daemon - and will keep the process alive. - */ - protected boolean daemon = true; - public void setDaemon(boolean b) { daemon = b; } - public boolean getDaemon() { return daemon; } - - - /** - * Name of the thread pool, which will be used for naming child threads. - */ - protected String name = "TP"; - public void setName(String name) { this.name = name; } - public String getName() { return name; } - - - - /** - * Allow comet request handling. - */ - protected boolean useComet = true; - public void setUseComet(boolean useComet) { this.useComet = useComet; } - public boolean getUseComet() { return useComet; } - - - /** - * Acceptor thread count. - */ - protected int acceptorThreadCount = 0; - public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } - public int getAcceptorThreadCount() { return acceptorThreadCount; } - - - - /** - * Poller thread count. - */ - protected int pollerThreadCount = 0; - public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } - public int getPollerThreadCount() { return pollerThreadCount; } - - protected long selectorTimeout = 1000; - public void setSelectorTimeout(long timeout){ this.selectorTimeout = timeout;} - public long getSelectorTimeout(){ return this.selectorTimeout; } - /** - * The socket poller. - */ - protected Poller[] pollers = null; - protected int pollerRoundRobin = 0; - public Poller getPoller() { - pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length; - Poller poller = pollers[pollerRoundRobin]; - return poller; - } - - - /** - * The socket poller used for Comet support. - */ - public Poller getCometPoller() { - Poller poller = getPoller(); - return poller; - } - - - /** - * Dummy maxSpareThreads property. - */ - public int getMaxSpareThreads() { return 0; } - - - /** - * Dummy minSpareThreads property. - */ - public int getMinSpareThreads() { return 0; } - - - /** - * SSL engine. - */ - protected String SSLEngine = "off"; - public String getSSLEngine() { return SSLEngine; } - public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; } - - - /** - * SSL protocols. - */ - protected String SSLProtocol = "all"; - public String getSSLProtocol() { return SSLProtocol; } - public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } - - - /** - * SSL password (if a cert is encrypted, and no password has been provided, a callback - * will ask for a password). - */ - protected String SSLPassword = null; - public String getSSLPassword() { return SSLPassword; } - public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } - - - /** - * SSL cipher suite. - */ - protected String SSLCipherSuite = "ALL"; - public String getSSLCipherSuite() { return SSLCipherSuite; } - public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } - - - /** - * SSL certificate file. - */ - protected String SSLCertificateFile = null; - public String getSSLCertificateFile() { return SSLCertificateFile; } - public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } - - - /** - * SSL certificate key file. - */ - protected String SSLCertificateKeyFile = null; - public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } - public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } - - - /** - * SSL certificate chain file. - */ - protected String SSLCertificateChainFile = null; - public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } - public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } - - - /** - * SSL CA certificate path. - */ - protected String SSLCACertificatePath = null; - public String getSSLCACertificatePath() { return SSLCACertificatePath; } - public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } - - - /** - * SSL CA certificate file. - */ - protected String SSLCACertificateFile = null; - public String getSSLCACertificateFile() { return SSLCACertificateFile; } - public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } - - - /** - * SSL CA revocation path. - */ - protected String SSLCARevocationPath = null; - public String getSSLCARevocationPath() { return SSLCARevocationPath; } - public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } - - - /** - * SSL CA revocation file. - */ - protected String SSLCARevocationFile = null; - public String getSSLCARevocationFile() { return SSLCARevocationFile; } - public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } - - - /** - * SSL verify client. - */ - protected String SSLVerifyClient = "none"; - public String getSSLVerifyClient() { return SSLVerifyClient; } - public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } - - - /** - * SSL verify depth. - */ - protected int SSLVerifyDepth = 10; - public int getSSLVerifyDepth() { return SSLVerifyDepth; } - public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } - - - // --------------------------------------------------------- Public Methods - - - /** - * Number of keepalive sockets. - */ - public int getKeepAliveCount() { - if (pollers == null) { - return 0; - } else { - int keepAliveCount = 0; - for (int i = 0; i < pollers.length; i++) { - keepAliveCount += pollers[i].getKeepAliveCount(); - } - return keepAliveCount; - } - } - - - - /** - * Return the amount of threads that are managed by the pool. - * - * @return the amount of threads that are managed by the pool - */ - public int getCurrentThreadCount() { - return curThreads; - } - - - /** - * Return the amount of threads currently busy. - * - * @return the amount of threads currently busy - */ - public int getCurrentThreadsBusy() { - return curThreadsBusy; - } - - - /** - * Return the state of the endpoint. - * - * @return true if the endpoint is running, false otherwise - */ - public boolean isRunning() { - return running; - } - - - /** - * Return the state of the endpoint. - * - * @return true if the endpoint is paused, false otherwise - */ - public boolean isPaused() { - return paused; - } - - - // ----------------------------------------------- Public Lifecycle Methods - - - /** - * Initialize the endpoint. - */ - public void init() - throws Exception { - - if (initialized) - return; - - serverSock = ServerSocketChannel.open(); - InetSocketAddress addr = (address!=null?new InetSocketAddress(address,port):new InetSocketAddress(port)); - serverSock.socket().bind(addr,100); //todo, set backlog value - serverSock.configureBlocking(true); //mimic APR behavior - - // Initialize thread count defaults for acceptor, poller and sendfile - if (acceptorThreadCount == 0) { - // FIXME: Doesn't seem to work that well with multiple accept threads - acceptorThreadCount = 1; - } - if (pollerThreadCount != 1) { - // limit to one poller, no need for others - pollerThreadCount = 1; - } - - // Initialize SSL if needed - if (!"off".equalsIgnoreCase(SSLEngine)) { - // Initialize SSL - // FIXME: one per VM call ? - if ("on".equalsIgnoreCase(SSLEngine)) { - SSL.initialize(null); - } else { - SSL.initialize(SSLEngine); - } - // SSL protocol - int value = SSL.SSL_PROTOCOL_ALL; - if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2; - } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV3; - } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_TLSV1; - } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { - value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; - } -// // Create SSL Context -// sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); -// // List the ciphers that the client is permitted to negotiate -// SSLContext.setCipherSuite(sslContext, SSLCipherSuite); -// // Load Server key and certificate -// SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); -// // Set certificate chain file -// SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); -// // Support Client Certificates -// SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); -// // Set revocation -// SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); -// // Client certificate verification -// value = SSL.SSL_CVERIFY_NONE; -// if ("optional".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_OPTIONAL; -// } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_REQUIRE; -// } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { -// value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; -// } -// SSLContext.setVerify(sslContext, value, SSLVerifyDepth); - } - - initialized = true; - - } - - - /** - * Start the APR endpoint, creating acceptor, poller threads. - */ - public void start() - throws Exception { - // Initialize socket if not done before - if (!initialized) { - init(); - } - if (!running) { - running = true; - paused = false; - - // Create worker collection - if (executor == null) { - workers = new WorkerStack(maxThreads); - } - - // Start acceptor threads - for (int i = 0; i < acceptorThreadCount; i++) { - Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); - acceptorThread.setPriority(threadPriority); - acceptorThread.setDaemon(daemon); - acceptorThread.start(); - } - - // Start poller threads - pollers = new Poller[pollerThreadCount]; - for (int i = 0; i < pollerThreadCount; i++) { - pollers[i] = new Poller(); - pollers[i].init(); - Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i); - pollerThread.setPriority(threadPriority); - pollerThread.setDaemon(true); - pollerThread.start(); - } - } - } - - - /** - * Pause the endpoint, which will make it stop accepting new sockets. - */ - public void pause() { - if (running && !paused) { - paused = true; - unlockAccept(); - } - } - - - /** - * Resume the endpoint, which will make it start accepting new sockets - * again. - */ - public void resume() { - if (running) { - paused = false; - } - } - - - /** - * Stop the endpoint. This will cause all processing threads to stop. - */ - public void stop() { - if (running) { - running = false; - unlockAccept(); - for (int i = 0; i < pollers.length; i++) { - pollers[i].destroy(); - } - pollers = null; - } - } - - - /** - * Deallocate APR memory pools, and close server socket. - */ - public void destroy() throws Exception { - if (running) { - stop(); - } - // Close server socket - serverSock.socket().close(); - serverSock.close(); - serverSock = null; - sslContext = 0; - initialized = false; - } - - - // ------------------------------------------------------ Protected Methods - - - /** - * Get a sequence number used for thread naming. - */ - protected int getSequence() { - return sequence++; - } - - - /** - * Unlock the server socket accept using a bugus connection. - */ - protected void unlockAccept() { - java.net.Socket s = null; - try { - // Need to create a connection to unlock the accept(); - if (address == null) { - s = new java.net.Socket("127.0.0.1", port); - } else { - s = new java.net.Socket(address, port); - // setting soLinger to a small value will help shutdown the - // connection quicker - s.setSoLinger(true, 0); - } - } catch(Exception e) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); - } - } finally { - if (s != null) { - try { - s.close(); - } catch (Exception e) { - // Ignore - } - } - } - } - - - /** - * Process the specified connection. - */ - protected boolean setSocketOptions(SocketChannel socket) { - // Process the connection - int step = 1; - try { - //disable blocking, APR style, we are gonna be polling it - socket.configureBlocking(false); - - // 1: Set socket options: timeout, linger, etc - if (soLinger >= 0) - socket.socket().setSoLinger(true,soLinger); - if (tcpNoDelay) - socket.socket().setTcpNoDelay(true); - if (soTimeout > 0) - socket.socket().setSoTimeout(soTimeout); - - - // 2: SSL handshake - step = 2; - if (sslContext != 0) { -// SSLSocket.attach(sslContext, socket); -// if (SSLSocket.handshake(socket) != 0) { -// if (log.isDebugEnabled()) { -// log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); -// } -// return false; -// } - } - - getPoller().register(socket); - - } catch (Throwable t) { - if (log.isDebugEnabled()) { - if (step == 2) { - log.debug(sm.getString("endpoint.err.handshake"), t); - } else { - log.debug(sm.getString("endpoint.err.unexpected"), t); - } - } - // Tell to close the socket - return false; - } - return true; - } - - - /** - * Create (or allocate) and return an available processor for use in - * processing a specific HTTP request, if possible. If the maximum - * allowed processors have already been created and are in use, return - * null instead. - */ - protected Worker createWorkerThread() { - - synchronized (workers) { - if (workers.size() > 0) { - curThreadsBusy++; - return (workers.pop()); - } - if ((maxThreads > 0) && (curThreads < maxThreads)) { - curThreadsBusy++; - return (newWorkerThread()); - } else { - if (maxThreads < 0) { - curThreadsBusy++; - return (newWorkerThread()); - } else { - return (null); - } - } - } - - } - - - /** - * Create and return a new processor suitable for processing HTTP - * requests and returning the corresponding responses. - */ - protected Worker newWorkerThread() { - - Worker workerThread = new Worker(); - workerThread.start(); - return (workerThread); - - } - - - /** - * Return a new worker thread, and block while to worker is available. - */ - protected Worker getWorkerThread() { - // Allocate a new worker thread - Worker workerThread = createWorkerThread(); - while (workerThread == null) { - try { - synchronized (workers) { - workers.wait(); - } - } catch (InterruptedException e) { - // Ignore - } - workerThread = createWorkerThread(); - } - return workerThread; - } - - - /** - * Recycle the specified Processor so that it can be used again. - * - * @param workerThread The processor to be recycled - */ - protected void recycleWorkerThread(Worker workerThread) { - synchronized (workers) { - workers.push(workerThread); - curThreadsBusy--; - workers.notify(); - } - } - - - /** - * Allocate a new poller of the specified size. - */ - protected long allocatePoller(int size, long pool, int timeout) { - try { - return Poll.create(size, pool, 0, timeout * 1000); - } catch (Error e) { - if (Status.APR_STATUS_IS_EINVAL(e.getError())) { - log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); - return 0; - } else { - log.error(sm.getString("endpoint.poll.initfail"), e); - return -1; - } - } - } - - - /** - * Process given socket. - */ - protected boolean processSocket(SocketChannel socket) { - try { - if (executor == null) { - getWorkerThread().assign(socket); - } else { - executor.execute(new SocketProcessor(socket)); - } - } catch (Throwable t) { - // This means we got an OOM or similar creating a thread, or that - // the pool and its queue are full - log.error(sm.getString("endpoint.process.fail"), t); - return false; - } - return true; - } - - - /** - * Process given socket for an event. - */ - protected boolean processSocket(SocketChannel socket, boolean error) { - try { - if (executor == null) { - getWorkerThread().assign(socket, error); - } else { - executor.execute(new SocketEventProcessor(socket, error)); - } - } catch (Throwable t) { - // This means we got an OOM or similar creating a thread, or that - // the pool and its queue are full - log.error(sm.getString("endpoint.process.fail"), t); - return false; - } - return true; - } - - - // --------------------------------------------------- Acceptor Inner Class - - - /** - * Server socket acceptor thread. - */ - protected class Acceptor implements Runnable { - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Loop until we receive a shutdown command - while (running) { - - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - try { - // Accept the next incoming connection from the server socket - SocketChannel socket = serverSock.accept(); - // Hand this socket off to an appropriate processor - if(!setSocketOptions(socket)) - { - // Close socket right away - socket.socket().close(); - socket.close(); - } - } catch (Throwable t) { - log.error(sm.getString("endpoint.accept.fail"), t); - } - - // The processor will recycle itself when it finishes - - } - - } - - } - - - // ----------------------------------------------------- Poller Inner Class - - - /** - * Poller class. - */ - public class Poller implements Runnable { - - protected Selector selector; - protected LinkedList events = new LinkedList(); - protected boolean close = false; - protected long nextExpiration = 0;//optimize expiration handling - - protected int keepAliveCount = 0; - public int getKeepAliveCount() { return keepAliveCount; } - - - - public Poller() throws IOException { - this.selector = Selector.open(); - } - - public Selector getSelector() { return selector;} - - /** - * Create the poller. With some versions of APR, the maximum poller size will - * be 62 (reocmpiling APR is necessary to remove this limitation). - */ - protected void init() { - keepAliveCount = 0; - } - - /** - * Destroy the poller. - */ - protected void destroy() { - // Wait for polltime before doing anything, so that the poller threads - // exit, otherwise parallel descturction of sockets which are still - // in the poller can cause problems - try { - synchronized (this) { - this.wait(pollTime / 1000); - } - } catch (InterruptedException e) { - // Ignore - } - close = true; - } - - public void addEvent(Runnable event) { - synchronized (events) { - events.add(event); - } - selector.wakeup(); - } - - /** - * Add specified socket and associated pool to the poller. The socket will - * be added to a temporary array, and polled first after a maximum amount - * of time equal to pollTime (in most cases, latency will be much lower, - * however). - * - * @param socket to add to the poller - */ - public void add(final SocketChannel socket) { - final SelectionKey key = socket.keyFor(selector); - KeyAttachment att = (KeyAttachment)key.attachment(); - if ( att != null ) att.setWakeUp(false); - Runnable r = new Runnable() { - public void run() { - try { - if (key != null) key.interestOps(SelectionKey.OP_READ); - }catch ( CancelledKeyException ckx ) { - try { - if ( key != null && key.attachment() != null ) { - KeyAttachment ka = (KeyAttachment)key.attachment(); - ka.setError(true); //set to collect this socket immediately - } - socket.socket().close(); - socket.close(); - } catch ( Exception ignore ) {} - } - } - }; - addEvent(r); - } - - public boolean events() { - boolean result = false; - synchronized (events) { - Runnable r = null; - result = (events.size() > 0); - while ( (events.size() > 0) && (r = events.removeFirst()) != null ) { - try { - r.run(); - } catch ( Exception x ) { - log.error("",x); - } - } - events.clear(); - } - return result; - } - - public void register(final SocketChannel socket) - { - SelectionKey key = socket.keyFor(selector); - Runnable r = new Runnable() { - public void run() { - try { - socket.register(selector, SelectionKey.OP_READ, new KeyAttachment()); - } catch (Exception x) { - log.error("", x); - } - } - - }; - synchronized (events) { - events.add(r); - } - selector.wakeup(); - } - - public void cancelledKey(SelectionKey key) { - try { - KeyAttachment ka = (KeyAttachment) key.attachment(); - key.cancel(); - if (ka != null && ka.getComet()) processSocket( (SocketChannel) key.channel(), true); - key.channel().close(); - } catch (IOException e) { - if ( log.isDebugEnabled() ) log.debug("",e); - // Ignore - } - } - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Loop until we receive a shutdown command - while (running) { - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - boolean hasEvents = false; - - hasEvents = (hasEvents | events()); - // Time to terminate? - if (close) return; - - int keyCount = 0; - try { - keyCount = selector.select(selectorTimeout); - } catch (Throwable x) { - log.error("",x); - continue; - } - - //either we timed out or we woke up, process events first - if ( keyCount == 0 ) hasEvents = (hasEvents | events()); - - //if (keyCount == 0) continue; - - Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; - // Walk through the collection of ready keys and dispatch - // any active event. - while (iterator != null && iterator.hasNext()) { - SelectionKey sk = (SelectionKey) iterator.next(); - iterator.remove(); - KeyAttachment attachment = (KeyAttachment)sk.attachment(); - try { - if(attachment == null) attachment = new KeyAttachment(); - attachment.access(); - sk.attach(attachment); - - int readyOps = sk.readyOps(); - sk.interestOps(sk.interestOps() & ~readyOps); - SocketChannel channel = (SocketChannel)sk.channel(); - boolean read = sk.isReadable(); - if (read) { - if ( attachment.getWakeUp() ) { - attachment.setWakeUp(false); - synchronized (attachment.getMutex()) {attachment.getMutex().notifyAll();} - } else if ( attachment.getComet() ) { - if (!processSocket(channel,false)) processSocket(channel,true); - } else { - boolean close = (!processSocket(channel)); - if ( close ) { - channel.socket().close(); - channel.close(); - } - } - } - if (sk.isValid() && sk.isWritable()) { - } - } catch ( CancelledKeyException ckx ) { - if (attachment!=null && attachment.getComet()) processSocket( (SocketChannel) sk.channel(), true); - try { - sk.channel().close(); - }catch ( Exception ignore){} - } catch (Throwable t) { - log.error("",t); - } - }//while - //process timeouts - timeout(keyCount,hasEvents); - }//while - synchronized (this) { - this.notifyAll(); - } - - } - protected void timeout(int keyCount, boolean hasEvents) { - long now = System.currentTimeMillis(); - //don't process timeouts too frequently, but if the selector simply timed out - //then we can check timeouts to avoid gaps - if ( (now < nextExpiration) && (keyCount>0 || hasEvents) ) return; - nextExpiration = now + (long)soTimeout; - //timeout - Set keys = selector.keys(); - for (Iterator iter = keys.iterator(); iter.hasNext(); ) { - SelectionKey key = iter.next(); - try { - KeyAttachment ka = (KeyAttachment) key.attachment(); - if ( ka == null ) { - cancelledKey(key); //we don't support any keys without attachments - } else if ( ka.getError() ) { - cancelledKey(key); - }else if ((key.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ) { - //only timeout sockets that we are waiting for a read from - long delta = now - ka.getLastAccess(); - long timeout = (ka.getTimeout()==-1)?((long) soTimeout):(ka.getTimeout()); - boolean isTimedout = delta > timeout; - if (isTimedout) { - cancelledKey(key); - } else { - long nextTime = now+(timeout-delta); - nextExpiration = (nextTime < nextExpiration)?nextTime:nextExpiration; - } - }//end if - }catch ( CancelledKeyException ckx ) { - cancelledKey(key); - } - }//for - } - } - - public static class KeyAttachment { - - public long getLastAccess() { return lastAccess; } - public void access() { access(System.currentTimeMillis()); } - public void access(long access) { lastAccess = access; } - public void setComet(boolean comet) { this.comet = comet; } - public boolean getComet() { return comet; } - public boolean getCurrentAccess() { return currentAccess; } - public void setCurrentAccess(boolean access) { currentAccess = access; } - public boolean getWakeUp() { return wakeUp; } - public void setWakeUp(boolean wakeUp) { this.wakeUp = wakeUp; } - public Object getMutex() {return mutex;} - public void setTimeout(long timeout) {this.timeout = timeout;} - public long getTimeout() {return this.timeout;} - public boolean getError() { return error; } - public void setError(boolean error) { this.error = error; } - protected Object mutex = new Object(); - protected boolean wakeUp = false; - protected long lastAccess = System.currentTimeMillis(); - protected boolean currentAccess = false; - protected boolean comet = false; - protected long timeout = -1; - protected boolean error = false; - - } - - - - // ----------------------------------------------------- Worker Inner Class - - - /** - * Server processor class. - */ - protected class Worker implements Runnable { - - - protected Thread thread = null; - protected boolean available = false; - protected SocketChannel socket = null; - protected boolean event = false; - protected boolean error = false; - - - /** - * Process an incoming TCP/IP connection on the specified socket. Any - * exception that occurs during processing must be logged and swallowed. - * NOTE: This method is called from our Connector's thread. We - * must assign it to our own thread so that multiple simultaneous - * requests can be handled. - * - * @param socket TCP socket to process - */ - protected synchronized void assign(SocketChannel socket) { - - // Wait for the Processor to get the previous Socket - while (available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Store the newly available Socket and notify our thread - this.socket = socket; - event = false; - error = false; - available = true; - notifyAll(); - - } - - - protected synchronized void assign(SocketChannel socket, boolean error) { - - // Wait for the Processor to get the previous Socket - while (available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Store the newly available Socket and notify our thread - this.socket = socket; - event = true; - this.error = error; - available = true; - notifyAll(); - } - - - /** - * Await a newly assigned Socket from our Connector, or null - * if we are supposed to shut down. - */ - protected synchronized SocketChannel await() { - - // Wait for the Connector to provide a new Socket - while (!available) { - try { - wait(); - } catch (InterruptedException e) { - } - } - - // Notify the Connector that we have received this Socket - SocketChannel socket = this.socket; - available = false; - notifyAll(); - - return (socket); - - } - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Process requests until we receive a shutdown signal - while (running) { - - // Wait for the next socket to be assigned - SocketChannel socket = await(); - if (socket == null) - continue; - - // Process the request from this socket - if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - }catch ( Exception x ) { - log.error("",x); - } - } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - }catch ( Exception x ) { - log.error("",x); - } - } - - // Finish up this request - recycleWorkerThread(this); - - } - - } - - - /** - * Start the background processing thread. - */ - public void start() { - thread = new Thread(this); - thread.setName(getName() + "-" + (++curThreads)); - thread.setDaemon(true); - thread.start(); - } - - - } - - - - // ------------------------------------------------ Handler Inner Interface - - - /** - * Bare bones interface used for socket processing. Per thread data is to be - * stored in the ThreadWithAttributes extra folders, or alternately in - * thread local fields. - */ - public interface Handler { - public enum SocketState { - OPEN, CLOSED, LONG - } - public SocketState process(SocketChannel socket); - public SocketState event(SocketChannel socket, boolean error); - } - - - // ------------------------------------------------- WorkerStack Inner Class - - - public class WorkerStack { - - protected Worker[] workers = null; - protected int end = 0; - - public WorkerStack(int size) { - workers = new Worker[size]; - } - - /** - * Put the object into the queue. - * - * @param object the object to be appended to the queue (first element). - */ - public void push(Worker worker) { - workers[end++] = worker; - } - - /** - * Get the first object out of the queue. Return null if the queue - * is empty. - */ - public Worker pop() { - if (end > 0) { - return workers[--end]; - } - return null; - } - - /** - * Get the first object out of the queue, Return null if the queue - * is empty. - */ - public Worker peek() { - return workers[end]; - } - - /** - * Is the queue empty? - */ - public boolean isEmpty() { - return (end == 0); - } - - /** - * How many elements are there in this queue? - */ - public int size() { - return (end); - } - } - - - // ---------------------------------------------- SocketProcessor Inner Class - - - /** - * This class is the equivalent of the Worker, but will simply use in an - * external Executor thread pool. - */ - protected class SocketProcessor implements Runnable { - - protected SocketChannel socket = null; - - public SocketProcessor(SocketChannel socket) { - this.socket = socket; - } - - public void run() { - - // Process the request from this socket - if (handler.process(socket) == Handler.SocketState.CLOSED) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - } catch ( Exception x ) { - log.error("",x); - } - socket = null; - } - - } - - } - - - // --------------------------------------- SocketEventProcessor Inner Class - - - /** - * This class is the equivalent of the Worker, but will simply use in an - * external Executor thread pool. - */ - protected class SocketEventProcessor implements Runnable { - - protected SocketChannel socket = null; - protected boolean error = false; - - public SocketEventProcessor(SocketChannel socket, boolean error) { - this.socket = socket; - this.error = error; - } - - public void run() { - - // Process the request from this socket - if (handler.event(socket, error) == Handler.SocketState.CLOSED) { - // Close socket and pool - try { - socket.socket().close(); - socket.close(); - } catch ( Exception x ) { - log.error("",x); - } - socket = null; - } - - } - - } - - -} +/* + * Copyright 2005-2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.nio.channels.CancelledKeyException; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Set; +import java.util.concurrent.Executor; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.jni.Error; +import org.apache.tomcat.jni.Library; +import org.apache.tomcat.jni.Poll; +import org.apache.tomcat.jni.SSL; +import org.apache.tomcat.jni.Status; +import org.apache.tomcat.util.res.StringManager; + +/** + * NIO tailored thread pool, providing the following services: + *
          + *
        • Socket acceptor thread
        • + *
        • Socket poller thread
        • + *
        • Worker threads pool
        • + *
        + * + * When switching to Java 5, there's an opportunity to use the virtual + * machine's thread pool. + * + * @author Mladen Turk + * @author Remy Maucherat + * @author Filip Hanik + */ +public class NioEndpoint { + + + // -------------------------------------------------------------- Constants + + + protected static Log log = LogFactory.getLog(NioEndpoint.class); + + protected static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.net.res"); + + + /** + * The Request attribute key for the cipher suite. + */ + public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; + + /** + * The Request attribute key for the key size. + */ + public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; + + /** + * The Request attribute key for the client certificate chain. + */ + public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; + + /** + * The Request attribute key for the session id. + * This one is a Tomcat extension to the Servlet spec. + */ + public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; + + + // ----------------------------------------------------------------- Fields + + + /** + * Available workers. + */ + protected WorkerStack workers = null; + + + /** + * Running state of the endpoint. + */ + protected volatile boolean running = false; + + + /** + * Will be set to true whenever the endpoint is paused. + */ + protected volatile boolean paused = false; + + + /** + * Track the initialization state of the endpoint. + */ + protected boolean initialized = false; + + + /** + * Current worker threads busy count. + */ + protected int curThreadsBusy = 0; + + + /** + * Current worker threads count. + */ + protected int curThreads = 0; + + + /** + * Sequence number used to generate thread names. + */ + protected int sequence = 0; + + + /** + * Root APR memory pool. + */ + protected long rootPool = 0; + + + /** + * Server socket "pointer". + */ + protected ServerSocketChannel serverSock = null; + + + /** + * APR memory pool for the server socket. + */ + protected long serverSockPool = 0; + + + /** + * SSL context. + */ + protected long sslContext = 0; + + + // ------------------------------------------------------------- Properties + + + /** + * External Executor based thread pool. + */ + protected Executor executor = null; + public void setExecutor(Executor executor) { this.executor = executor; } + public Executor getExecutor() { return executor; } + + + /** + * Maximum amount of worker threads. + */ + protected int maxThreads = 40; + public void setMaxThreads(int maxThreads) { this.maxThreads = maxThreads; } + public int getMaxThreads() { return maxThreads; } + + + /** + * Priority of the acceptor and poller threads. + */ + protected int threadPriority = Thread.NORM_PRIORITY; + public void setThreadPriority(int threadPriority) { this.threadPriority = threadPriority; } + public int getThreadPriority() { return threadPriority; } + + + /** + * Size of the socket poller. + */ + protected int pollerSize = 8 * 1024; + public void setPollerSize(int pollerSize) { this.pollerSize = pollerSize; } + public int getPollerSize() { return pollerSize; } + + + + /** + * Server socket port. + */ + protected int port; + public int getPort() { return port; } + public void setPort(int port ) { this.port=port; } + + + /** + * Address for the server socket. + */ + protected InetAddress address; + public InetAddress getAddress() { return address; } + public void setAddress(InetAddress address) { this.address = address; } + + + /** + * Handling of accepted sockets. + */ + protected Handler handler = null; + public void setHandler(Handler handler ) { this.handler = handler; } + public Handler getHandler() { return handler; } + + + /** + * Allows the server developer to specify the backlog that + * should be used for server sockets. By default, this value + * is 100. + */ + protected int backlog = 100; + public void setBacklog(int backlog) { if (backlog > 0) this.backlog = backlog; } + public int getBacklog() { return backlog; } + + + /** + * Socket TCP no delay. + */ + protected boolean tcpNoDelay = false; + public boolean getTcpNoDelay() { return tcpNoDelay; } + public void setTcpNoDelay(boolean tcpNoDelay) { this.tcpNoDelay = tcpNoDelay; } + + + /** + * Socket linger. + */ + protected int soLinger = 100; + public int getSoLinger() { return soLinger; } + public void setSoLinger(int soLinger) { this.soLinger = soLinger; } + + + /** + * Socket timeout. + */ + protected int soTimeout = -1; + public int getSoTimeout() { return soTimeout; } + public void setSoTimeout(int soTimeout) { this.soTimeout = soTimeout; } + + + /** + * Timeout on first request read before going to the poller, in ms. + */ + protected int firstReadTimeout = 60000; + public int getFirstReadTimeout() { return firstReadTimeout; } + public void setFirstReadTimeout(int firstReadTimeout) { this.firstReadTimeout = firstReadTimeout; } + + + /** + * Poll interval, in microseconds. The smaller the value, the more CPU the poller + * will use, but the more responsive to activity it will be. + */ + protected int pollTime = 2000; + public int getPollTime() { return pollTime; } + public void setPollTime(int pollTime) { if (pollTime > 0) { this.pollTime = pollTime; } } + + + /** + * The default is true - the created threads will be + * in daemon mode. If set to false, the control thread + * will not be daemon - and will keep the process alive. + */ + protected boolean daemon = true; + public void setDaemon(boolean b) { daemon = b; } + public boolean getDaemon() { return daemon; } + + + /** + * Name of the thread pool, which will be used for naming child threads. + */ + protected String name = "TP"; + public void setName(String name) { this.name = name; } + public String getName() { return name; } + + + + /** + * Allow comet request handling. + */ + protected boolean useComet = true; + public void setUseComet(boolean useComet) { this.useComet = useComet; } + public boolean getUseComet() { return useComet; } + + + /** + * Acceptor thread count. + */ + protected int acceptorThreadCount = 0; + public void setAcceptorThreadCount(int acceptorThreadCount) { this.acceptorThreadCount = acceptorThreadCount; } + public int getAcceptorThreadCount() { return acceptorThreadCount; } + + + + /** + * Poller thread count. + */ + protected int pollerThreadCount = 0; + public void setPollerThreadCount(int pollerThreadCount) { this.pollerThreadCount = pollerThreadCount; } + public int getPollerThreadCount() { return pollerThreadCount; } + + protected long selectorTimeout = 1000; + public void setSelectorTimeout(long timeout){ this.selectorTimeout = timeout;} + public long getSelectorTimeout(){ return this.selectorTimeout; } + /** + * The socket poller. + */ + protected Poller[] pollers = null; + protected int pollerRoundRobin = 0; + public Poller getPoller() { + pollerRoundRobin = (pollerRoundRobin + 1) % pollers.length; + Poller poller = pollers[pollerRoundRobin]; + return poller; + } + + + /** + * The socket poller used for Comet support. + */ + public Poller getCometPoller() { + Poller poller = getPoller(); + return poller; + } + + + /** + * Dummy maxSpareThreads property. + */ + public int getMaxSpareThreads() { return 0; } + + + /** + * Dummy minSpareThreads property. + */ + public int getMinSpareThreads() { return 0; } + + + /** + * SSL engine. + */ + protected String SSLEngine = "off"; + public String getSSLEngine() { return SSLEngine; } + public void setSSLEngine(String SSLEngine) { this.SSLEngine = SSLEngine; } + + + /** + * SSL protocols. + */ + protected String SSLProtocol = "all"; + public String getSSLProtocol() { return SSLProtocol; } + public void setSSLProtocol(String SSLProtocol) { this.SSLProtocol = SSLProtocol; } + + + /** + * SSL password (if a cert is encrypted, and no password has been provided, a callback + * will ask for a password). + */ + protected String SSLPassword = null; + public String getSSLPassword() { return SSLPassword; } + public void setSSLPassword(String SSLPassword) { this.SSLPassword = SSLPassword; } + + + /** + * SSL cipher suite. + */ + protected String SSLCipherSuite = "ALL"; + public String getSSLCipherSuite() { return SSLCipherSuite; } + public void setSSLCipherSuite(String SSLCipherSuite) { this.SSLCipherSuite = SSLCipherSuite; } + + + /** + * SSL certificate file. + */ + protected String SSLCertificateFile = null; + public String getSSLCertificateFile() { return SSLCertificateFile; } + public void setSSLCertificateFile(String SSLCertificateFile) { this.SSLCertificateFile = SSLCertificateFile; } + + + /** + * SSL certificate key file. + */ + protected String SSLCertificateKeyFile = null; + public String getSSLCertificateKeyFile() { return SSLCertificateKeyFile; } + public void setSSLCertificateKeyFile(String SSLCertificateKeyFile) { this.SSLCertificateKeyFile = SSLCertificateKeyFile; } + + + /** + * SSL certificate chain file. + */ + protected String SSLCertificateChainFile = null; + public String getSSLCertificateChainFile() { return SSLCertificateChainFile; } + public void setSSLCertificateChainFile(String SSLCertificateChainFile) { this.SSLCertificateChainFile = SSLCertificateChainFile; } + + + /** + * SSL CA certificate path. + */ + protected String SSLCACertificatePath = null; + public String getSSLCACertificatePath() { return SSLCACertificatePath; } + public void setSSLCACertificatePath(String SSLCACertificatePath) { this.SSLCACertificatePath = SSLCACertificatePath; } + + + /** + * SSL CA certificate file. + */ + protected String SSLCACertificateFile = null; + public String getSSLCACertificateFile() { return SSLCACertificateFile; } + public void setSSLCACertificateFile(String SSLCACertificateFile) { this.SSLCACertificateFile = SSLCACertificateFile; } + + + /** + * SSL CA revocation path. + */ + protected String SSLCARevocationPath = null; + public String getSSLCARevocationPath() { return SSLCARevocationPath; } + public void setSSLCARevocationPath(String SSLCARevocationPath) { this.SSLCARevocationPath = SSLCARevocationPath; } + + + /** + * SSL CA revocation file. + */ + protected String SSLCARevocationFile = null; + public String getSSLCARevocationFile() { return SSLCARevocationFile; } + public void setSSLCARevocationFile(String SSLCARevocationFile) { this.SSLCARevocationFile = SSLCARevocationFile; } + + + /** + * SSL verify client. + */ + protected String SSLVerifyClient = "none"; + public String getSSLVerifyClient() { return SSLVerifyClient; } + public void setSSLVerifyClient(String SSLVerifyClient) { this.SSLVerifyClient = SSLVerifyClient; } + + + /** + * SSL verify depth. + */ + protected int SSLVerifyDepth = 10; + public int getSSLVerifyDepth() { return SSLVerifyDepth; } + public void setSSLVerifyDepth(int SSLVerifyDepth) { this.SSLVerifyDepth = SSLVerifyDepth; } + + + // --------------------------------------------------------- Public Methods + + + /** + * Number of keepalive sockets. + */ + public int getKeepAliveCount() { + if (pollers == null) { + return 0; + } else { + int keepAliveCount = 0; + for (int i = 0; i < pollers.length; i++) { + keepAliveCount += pollers[i].getKeepAliveCount(); + } + return keepAliveCount; + } + } + + + + /** + * Return the amount of threads that are managed by the pool. + * + * @return the amount of threads that are managed by the pool + */ + public int getCurrentThreadCount() { + return curThreads; + } + + + /** + * Return the amount of threads currently busy. + * + * @return the amount of threads currently busy + */ + public int getCurrentThreadsBusy() { + return curThreadsBusy; + } + + + /** + * Return the state of the endpoint. + * + * @return true if the endpoint is running, false otherwise + */ + public boolean isRunning() { + return running; + } + + + /** + * Return the state of the endpoint. + * + * @return true if the endpoint is paused, false otherwise + */ + public boolean isPaused() { + return paused; + } + + + // ----------------------------------------------- Public Lifecycle Methods + + + /** + * Initialize the endpoint. + */ + public void init() + throws Exception { + + if (initialized) + return; + + serverSock = ServerSocketChannel.open(); + InetSocketAddress addr = (address!=null?new InetSocketAddress(address,port):new InetSocketAddress(port)); + serverSock.socket().bind(addr,100); //todo, set backlog value + serverSock.configureBlocking(true); //mimic APR behavior + + // Initialize thread count defaults for acceptor, poller and sendfile + if (acceptorThreadCount == 0) { + // FIXME: Doesn't seem to work that well with multiple accept threads + acceptorThreadCount = 1; + } + if (pollerThreadCount != 1) { + // limit to one poller, no need for others + pollerThreadCount = 1; + } + + // Initialize SSL if needed + if (!"off".equalsIgnoreCase(SSLEngine)) { + // Initialize SSL + // FIXME: one per VM call ? + if ("on".equalsIgnoreCase(SSLEngine)) { + SSL.initialize(null); + } else { + SSL.initialize(SSLEngine); + } + // SSL protocol + int value = SSL.SSL_PROTOCOL_ALL; + if ("SSLv2".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV2; + } else if ("SSLv3".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV3; + } else if ("TLSv1".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_TLSV1; + } else if ("SSLv2+SSLv3".equalsIgnoreCase(SSLProtocol)) { + value = SSL.SSL_PROTOCOL_SSLV2 | SSL.SSL_PROTOCOL_SSLV3; + } +// // Create SSL Context +// sslContext = SSLContext.make(rootPool, value, SSL.SSL_MODE_SERVER); +// // List the ciphers that the client is permitted to negotiate +// SSLContext.setCipherSuite(sslContext, SSLCipherSuite); +// // Load Server key and certificate +// SSLContext.setCertificate(sslContext, SSLCertificateFile, SSLCertificateKeyFile, SSLPassword, SSL.SSL_AIDX_RSA); +// // Set certificate chain file +// SSLContext.setCertificateChainFile(sslContext, SSLCertificateChainFile, false); +// // Support Client Certificates +// SSLContext.setCACertificate(sslContext, SSLCACertificateFile, SSLCACertificatePath); +// // Set revocation +// SSLContext.setCARevocation(sslContext, SSLCARevocationFile, SSLCARevocationPath); +// // Client certificate verification +// value = SSL.SSL_CVERIFY_NONE; +// if ("optional".equalsIgnoreCase(SSLVerifyClient)) { +// value = SSL.SSL_CVERIFY_OPTIONAL; +// } else if ("require".equalsIgnoreCase(SSLVerifyClient)) { +// value = SSL.SSL_CVERIFY_REQUIRE; +// } else if ("optionalNoCA".equalsIgnoreCase(SSLVerifyClient)) { +// value = SSL.SSL_CVERIFY_OPTIONAL_NO_CA; +// } +// SSLContext.setVerify(sslContext, value, SSLVerifyDepth); + } + + initialized = true; + + } + + + /** + * Start the APR endpoint, creating acceptor, poller threads. + */ + public void start() + throws Exception { + // Initialize socket if not done before + if (!initialized) { + init(); + } + if (!running) { + running = true; + paused = false; + + // Create worker collection + if (executor == null) { + workers = new WorkerStack(maxThreads); + } + + // Start acceptor threads + for (int i = 0; i < acceptorThreadCount; i++) { + Thread acceptorThread = new Thread(new Acceptor(), getName() + "-Acceptor-" + i); + acceptorThread.setPriority(threadPriority); + acceptorThread.setDaemon(daemon); + acceptorThread.start(); + } + + // Start poller threads + pollers = new Poller[pollerThreadCount]; + for (int i = 0; i < pollerThreadCount; i++) { + pollers[i] = new Poller(); + pollers[i].init(); + Thread pollerThread = new Thread(pollers[i], getName() + "-Poller-" + i); + pollerThread.setPriority(threadPriority); + pollerThread.setDaemon(true); + pollerThread.start(); + } + } + } + + + /** + * Pause the endpoint, which will make it stop accepting new sockets. + */ + public void pause() { + if (running && !paused) { + paused = true; + unlockAccept(); + } + } + + + /** + * Resume the endpoint, which will make it start accepting new sockets + * again. + */ + public void resume() { + if (running) { + paused = false; + } + } + + + /** + * Stop the endpoint. This will cause all processing threads to stop. + */ + public void stop() { + if (running) { + running = false; + unlockAccept(); + for (int i = 0; i < pollers.length; i++) { + pollers[i].destroy(); + } + pollers = null; + } + } + + + /** + * Deallocate APR memory pools, and close server socket. + */ + public void destroy() throws Exception { + if (running) { + stop(); + } + // Close server socket + serverSock.socket().close(); + serverSock.close(); + serverSock = null; + sslContext = 0; + initialized = false; + } + + + // ------------------------------------------------------ Protected Methods + + + /** + * Get a sequence number used for thread naming. + */ + protected int getSequence() { + return sequence++; + } + + + /** + * Unlock the server socket accept using a bugus connection. + */ + protected void unlockAccept() { + java.net.Socket s = null; + try { + // Need to create a connection to unlock the accept(); + if (address == null) { + s = new java.net.Socket("127.0.0.1", port); + } else { + s = new java.net.Socket(address, port); + // setting soLinger to a small value will help shutdown the + // connection quicker + s.setSoLinger(true, 0); + } + } catch(Exception e) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + } + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e) { + // Ignore + } + } + } + } + + + /** + * Process the specified connection. + */ + protected boolean setSocketOptions(SocketChannel socket) { + // Process the connection + int step = 1; + try { + //disable blocking, APR style, we are gonna be polling it + socket.configureBlocking(false); + + // 1: Set socket options: timeout, linger, etc + if (soLinger >= 0) + socket.socket().setSoLinger(true,soLinger); + if (tcpNoDelay) + socket.socket().setTcpNoDelay(true); + if (soTimeout > 0) + socket.socket().setSoTimeout(soTimeout); + + + // 2: SSL handshake + step = 2; + if (sslContext != 0) { +// SSLSocket.attach(sslContext, socket); +// if (SSLSocket.handshake(socket) != 0) { +// if (log.isDebugEnabled()) { +// log.debug(sm.getString("endpoint.err.handshake") + ": " + SSL.getLastError()); +// } +// return false; +// } + } + + getPoller().register(socket); + + } catch (Throwable t) { + if (log.isDebugEnabled()) { + if (step == 2) { + log.debug(sm.getString("endpoint.err.handshake"), t); + } else { + log.debug(sm.getString("endpoint.err.unexpected"), t); + } + } + // Tell to close the socket + return false; + } + return true; + } + + + /** + * Create (or allocate) and return an available processor for use in + * processing a specific HTTP request, if possible. If the maximum + * allowed processors have already been created and are in use, return + * null instead. + */ + protected Worker createWorkerThread() { + + synchronized (workers) { + if (workers.size() > 0) { + curThreadsBusy++; + return (workers.pop()); + } + if ((maxThreads > 0) && (curThreads < maxThreads)) { + curThreadsBusy++; + return (newWorkerThread()); + } else { + if (maxThreads < 0) { + curThreadsBusy++; + return (newWorkerThread()); + } else { + return (null); + } + } + } + + } + + + /** + * Create and return a new processor suitable for processing HTTP + * requests and returning the corresponding responses. + */ + protected Worker newWorkerThread() { + + Worker workerThread = new Worker(); + workerThread.start(); + return (workerThread); + + } + + + /** + * Return a new worker thread, and block while to worker is available. + */ + protected Worker getWorkerThread() { + // Allocate a new worker thread + Worker workerThread = createWorkerThread(); + while (workerThread == null) { + try { + synchronized (workers) { + workers.wait(); + } + } catch (InterruptedException e) { + // Ignore + } + workerThread = createWorkerThread(); + } + return workerThread; + } + + + /** + * Recycle the specified Processor so that it can be used again. + * + * @param workerThread The processor to be recycled + */ + protected void recycleWorkerThread(Worker workerThread) { + synchronized (workers) { + workers.push(workerThread); + curThreadsBusy--; + workers.notify(); + } + } + + + /** + * Allocate a new poller of the specified size. + */ + protected long allocatePoller(int size, long pool, int timeout) { + try { + return Poll.create(size, pool, 0, timeout * 1000); + } catch (Error e) { + if (Status.APR_STATUS_IS_EINVAL(e.getError())) { + log.info(sm.getString("endpoint.poll.limitedpollsize", "" + size)); + return 0; + } else { + log.error(sm.getString("endpoint.poll.initfail"), e); + return -1; + } + } + } + + + /** + * Process given socket. + */ + protected boolean processSocket(SocketChannel socket) { + try { + if (executor == null) { + getWorkerThread().assign(socket); + } else { + executor.execute(new SocketProcessor(socket)); + } + } catch (Throwable t) { + // This means we got an OOM or similar creating a thread, or that + // the pool and its queue are full + log.error(sm.getString("endpoint.process.fail"), t); + return false; + } + return true; + } + + + /** + * Process given socket for an event. + */ + protected boolean processSocket(SocketChannel socket, boolean error) { + try { + if (executor == null) { + getWorkerThread().assign(socket, error); + } else { + executor.execute(new SocketEventProcessor(socket, error)); + } + } catch (Throwable t) { + // This means we got an OOM or similar creating a thread, or that + // the pool and its queue are full + log.error(sm.getString("endpoint.process.fail"), t); + return false; + } + return true; + } + + + // --------------------------------------------------- Acceptor Inner Class + + + /** + * Server socket acceptor thread. + */ + protected class Acceptor implements Runnable { + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Loop until we receive a shutdown command + while (running) { + + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + try { + // Accept the next incoming connection from the server socket + SocketChannel socket = serverSock.accept(); + // Hand this socket off to an appropriate processor + if(!setSocketOptions(socket)) + { + // Close socket right away + socket.socket().close(); + socket.close(); + } + } catch (Throwable t) { + log.error(sm.getString("endpoint.accept.fail"), t); + } + + // The processor will recycle itself when it finishes + + } + + } + + } + + + // ----------------------------------------------------- Poller Inner Class + + + /** + * Poller class. + */ + public class Poller implements Runnable { + + protected Selector selector; + protected LinkedList events = new LinkedList(); + protected boolean close = false; + protected long nextExpiration = 0;//optimize expiration handling + + protected int keepAliveCount = 0; + public int getKeepAliveCount() { return keepAliveCount; } + + + + public Poller() throws IOException { + this.selector = Selector.open(); + } + + public Selector getSelector() { return selector;} + + /** + * Create the poller. With some versions of APR, the maximum poller size will + * be 62 (reocmpiling APR is necessary to remove this limitation). + */ + protected void init() { + keepAliveCount = 0; + } + + /** + * Destroy the poller. + */ + protected void destroy() { + // Wait for polltime before doing anything, so that the poller threads + // exit, otherwise parallel descturction of sockets which are still + // in the poller can cause problems + try { + synchronized (this) { + this.wait(pollTime / 1000); + } + } catch (InterruptedException e) { + // Ignore + } + close = true; + } + + public void addEvent(Runnable event) { + synchronized (events) { + events.add(event); + } + selector.wakeup(); + } + + /** + * Add specified socket and associated pool to the poller. The socket will + * be added to a temporary array, and polled first after a maximum amount + * of time equal to pollTime (in most cases, latency will be much lower, + * however). + * + * @param socket to add to the poller + */ + public void add(final SocketChannel socket) { + final SelectionKey key = socket.keyFor(selector); + KeyAttachment att = (KeyAttachment)key.attachment(); + if ( att != null ) att.setWakeUp(false); + Runnable r = new Runnable() { + public void run() { + try { + if (key != null) key.interestOps(SelectionKey.OP_READ); + }catch ( CancelledKeyException ckx ) { + try { + if ( key != null && key.attachment() != null ) { + KeyAttachment ka = (KeyAttachment)key.attachment(); + ka.setError(true); //set to collect this socket immediately + } + socket.socket().close(); + socket.close(); + } catch ( Exception ignore ) {} + } + } + }; + addEvent(r); + } + + public boolean events() { + boolean result = false; + synchronized (events) { + Runnable r = null; + result = (events.size() > 0); + while ( (events.size() > 0) && (r = events.removeFirst()) != null ) { + try { + r.run(); + } catch ( Exception x ) { + log.error("",x); + } + } + events.clear(); + } + return result; + } + + public void register(final SocketChannel socket) + { + SelectionKey key = socket.keyFor(selector); + Runnable r = new Runnable() { + public void run() { + try { + socket.register(selector, SelectionKey.OP_READ, new KeyAttachment()); + } catch (Exception x) { + log.error("", x); + } + } + + }; + synchronized (events) { + events.add(r); + } + selector.wakeup(); + } + + public void cancelledKey(SelectionKey key) { + try { + KeyAttachment ka = (KeyAttachment) key.attachment(); + key.cancel(); + if (ka != null && ka.getComet()) processSocket( (SocketChannel) key.channel(), true); + key.channel().close(); + } catch (IOException e) { + if ( log.isDebugEnabled() ) log.debug("",e); + // Ignore + } + } + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Loop until we receive a shutdown command + while (running) { + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + boolean hasEvents = false; + + hasEvents = (hasEvents | events()); + // Time to terminate? + if (close) return; + + int keyCount = 0; + try { + keyCount = selector.select(selectorTimeout); + } catch (Throwable x) { + log.error("",x); + continue; + } + + //either we timed out or we woke up, process events first + if ( keyCount == 0 ) hasEvents = (hasEvents | events()); + + //if (keyCount == 0) continue; + + Iterator iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; + // Walk through the collection of ready keys and dispatch + // any active event. + while (iterator != null && iterator.hasNext()) { + SelectionKey sk = (SelectionKey) iterator.next(); + iterator.remove(); + KeyAttachment attachment = (KeyAttachment)sk.attachment(); + try { + if(attachment == null) attachment = new KeyAttachment(); + attachment.access(); + sk.attach(attachment); + + int readyOps = sk.readyOps(); + sk.interestOps(sk.interestOps() & ~readyOps); + SocketChannel channel = (SocketChannel)sk.channel(); + boolean read = sk.isReadable(); + if (read) { + if ( attachment.getWakeUp() ) { + attachment.setWakeUp(false); + synchronized (attachment.getMutex()) {attachment.getMutex().notifyAll();} + } else if ( attachment.getComet() ) { + if (!processSocket(channel,false)) processSocket(channel,true); + } else { + boolean close = (!processSocket(channel)); + if ( close ) { + channel.socket().close(); + channel.close(); + } + } + } + if (sk.isValid() && sk.isWritable()) { + } + } catch ( CancelledKeyException ckx ) { + if (attachment!=null && attachment.getComet()) processSocket( (SocketChannel) sk.channel(), true); + try { + sk.channel().close(); + }catch ( Exception ignore){} + } catch (Throwable t) { + log.error("",t); + } + }//while + //process timeouts + timeout(keyCount,hasEvents); + }//while + synchronized (this) { + this.notifyAll(); + } + + } + protected void timeout(int keyCount, boolean hasEvents) { + long now = System.currentTimeMillis(); + //don't process timeouts too frequently, but if the selector simply timed out + //then we can check timeouts to avoid gaps + if ( (now < nextExpiration) && (keyCount>0 || hasEvents) ) return; + nextExpiration = now + (long)soTimeout; + //timeout + Set keys = selector.keys(); + for (Iterator iter = keys.iterator(); iter.hasNext(); ) { + SelectionKey key = iter.next(); + try { + KeyAttachment ka = (KeyAttachment) key.attachment(); + if ( ka == null ) { + cancelledKey(key); //we don't support any keys without attachments + } else if ( ka.getError() ) { + cancelledKey(key); + }else if ((key.interestOps()&SelectionKey.OP_READ) == SelectionKey.OP_READ) { + //only timeout sockets that we are waiting for a read from + long delta = now - ka.getLastAccess(); + long timeout = (ka.getTimeout()==-1)?((long) soTimeout):(ka.getTimeout()); + boolean isTimedout = delta > timeout; + if (isTimedout) { + cancelledKey(key); + } else { + long nextTime = now+(timeout-delta); + nextExpiration = (nextTime < nextExpiration)?nextTime:nextExpiration; + } + }//end if + }catch ( CancelledKeyException ckx ) { + cancelledKey(key); + } + }//for + } + } + + public static class KeyAttachment { + + public long getLastAccess() { return lastAccess; } + public void access() { access(System.currentTimeMillis()); } + public void access(long access) { lastAccess = access; } + public void setComet(boolean comet) { this.comet = comet; } + public boolean getComet() { return comet; } + public boolean getCurrentAccess() { return currentAccess; } + public void setCurrentAccess(boolean access) { currentAccess = access; } + public boolean getWakeUp() { return wakeUp; } + public void setWakeUp(boolean wakeUp) { this.wakeUp = wakeUp; } + public Object getMutex() {return mutex;} + public void setTimeout(long timeout) {this.timeout = timeout;} + public long getTimeout() {return this.timeout;} + public boolean getError() { return error; } + public void setError(boolean error) { this.error = error; } + protected Object mutex = new Object(); + protected boolean wakeUp = false; + protected long lastAccess = System.currentTimeMillis(); + protected boolean currentAccess = false; + protected boolean comet = false; + protected long timeout = -1; + protected boolean error = false; + + } + + + + // ----------------------------------------------------- Worker Inner Class + + + /** + * Server processor class. + */ + protected class Worker implements Runnable { + + + protected Thread thread = null; + protected boolean available = false; + protected SocketChannel socket = null; + protected boolean event = false; + protected boolean error = false; + + + /** + * Process an incoming TCP/IP connection on the specified socket. Any + * exception that occurs during processing must be logged and swallowed. + * NOTE: This method is called from our Connector's thread. We + * must assign it to our own thread so that multiple simultaneous + * requests can be handled. + * + * @param socket TCP socket to process + */ + protected synchronized void assign(SocketChannel socket) { + + // Wait for the Processor to get the previous Socket + while (available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Store the newly available Socket and notify our thread + this.socket = socket; + event = false; + error = false; + available = true; + notifyAll(); + + } + + + protected synchronized void assign(SocketChannel socket, boolean error) { + + // Wait for the Processor to get the previous Socket + while (available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Store the newly available Socket and notify our thread + this.socket = socket; + event = true; + this.error = error; + available = true; + notifyAll(); + } + + + /** + * Await a newly assigned Socket from our Connector, or null + * if we are supposed to shut down. + */ + protected synchronized SocketChannel await() { + + // Wait for the Connector to provide a new Socket + while (!available) { + try { + wait(); + } catch (InterruptedException e) { + } + } + + // Notify the Connector that we have received this Socket + SocketChannel socket = this.socket; + available = false; + notifyAll(); + + return (socket); + + } + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Process requests until we receive a shutdown signal + while (running) { + + // Wait for the next socket to be assigned + SocketChannel socket = await(); + if (socket == null) + continue; + + // Process the request from this socket + if ((event) && (handler.event(socket, error) == Handler.SocketState.CLOSED)) { + // Close socket and pool + try { + socket.socket().close(); + socket.close(); + }catch ( Exception x ) { + log.error("",x); + } + } else if ((!event) && (handler.process(socket) == Handler.SocketState.CLOSED)) { + // Close socket and pool + try { + socket.socket().close(); + socket.close(); + }catch ( Exception x ) { + log.error("",x); + } + } + + // Finish up this request + recycleWorkerThread(this); + + } + + } + + + /** + * Start the background processing thread. + */ + public void start() { + thread = new Thread(this); + thread.setName(getName() + "-" + (++curThreads)); + thread.setDaemon(true); + thread.start(); + } + + + } + + + + // ------------------------------------------------ Handler Inner Interface + + + /** + * Bare bones interface used for socket processing. Per thread data is to be + * stored in the ThreadWithAttributes extra folders, or alternately in + * thread local fields. + */ + public interface Handler { + public enum SocketState { + OPEN, CLOSED, LONG + } + public SocketState process(SocketChannel socket); + public SocketState event(SocketChannel socket, boolean error); + } + + + // ------------------------------------------------- WorkerStack Inner Class + + + public class WorkerStack { + + protected Worker[] workers = null; + protected int end = 0; + + public WorkerStack(int size) { + workers = new Worker[size]; + } + + /** + * Put the object into the queue. + * + * @param object the object to be appended to the queue (first element). + */ + public void push(Worker worker) { + workers[end++] = worker; + } + + /** + * Get the first object out of the queue. Return null if the queue + * is empty. + */ + public Worker pop() { + if (end > 0) { + return workers[--end]; + } + return null; + } + + /** + * Get the first object out of the queue, Return null if the queue + * is empty. + */ + public Worker peek() { + return workers[end]; + } + + /** + * Is the queue empty? + */ + public boolean isEmpty() { + return (end == 0); + } + + /** + * How many elements are there in this queue? + */ + public int size() { + return (end); + } + } + + + // ---------------------------------------------- SocketProcessor Inner Class + + + /** + * This class is the equivalent of the Worker, but will simply use in an + * external Executor thread pool. + */ + protected class SocketProcessor implements Runnable { + + protected SocketChannel socket = null; + + public SocketProcessor(SocketChannel socket) { + this.socket = socket; + } + + public void run() { + + // Process the request from this socket + if (handler.process(socket) == Handler.SocketState.CLOSED) { + // Close socket and pool + try { + socket.socket().close(); + socket.close(); + } catch ( Exception x ) { + log.error("",x); + } + socket = null; + } + + } + + } + + + // --------------------------------------- SocketEventProcessor Inner Class + + + /** + * This class is the equivalent of the Worker, but will simply use in an + * external Executor thread pool. + */ + protected class SocketEventProcessor implements Runnable { + + protected SocketChannel socket = null; + protected boolean error = false; + + public SocketEventProcessor(SocketChannel socket, boolean error) { + this.socket = socket; + this.error = error; + } + + public void run() { + + // Process the request from this socket + if (handler.event(socket, error) == Handler.SocketState.CLOSED) { + // Close socket and pool + try { + socket.socket().close(); + socket.close(); + } catch ( Exception x ) { + log.error("",x); + } + socket = null; + } + + } + + } + + +} diff --git a/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java b/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java index 4d18cf898..d56f63391 100644 --- a/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java +++ b/java/org/apache/tomcat/util/net/PoolTcpEndpoint.java @@ -1,683 +1,683 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.io.IOException; -import java.io.InterruptedIOException; -import java.net.BindException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.security.AccessControlException; -import java.util.Stack; -import java.util.Vector; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.apache.tomcat.util.res.StringManager; -import org.apache.tomcat.util.threads.ThreadPool; -import org.apache.tomcat.util.threads.ThreadPoolRunnable; - -/* Similar with MPM module in Apache2.0. Handles all the details related with - "tcp server" functionality - thread management, accept policy, etc. - It should do nothing more - as soon as it get a socket ( and all socket options - are set, etc), it just handle the stream to ConnectionHandler.processConnection. (costin) -*/ - - - -/** - * Handle incoming TCP connections. - * - * This class implement a simple server model: one listener thread accepts on a socket and - * creates a new worker thread for each incoming connection. - * - * More advanced Endpoints will reuse the threads, use queues, etc. - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author Jason Hunter [jch@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Costin@eng.sun.com - * @author Gal Shachor [shachor@il.ibm.com] - * @author Yoav Shapira - */ -public class PoolTcpEndpoint implements Runnable { // implements Endpoint { - - static Log log=LogFactory.getLog(PoolTcpEndpoint.class ); - - private StringManager sm = - StringManager.getManager("org.apache.tomcat.util.net.res"); - - private static final int BACKLOG = 100; - private static final int TIMEOUT = 1000; - - private final Object threadSync = new Object(); - - private int backlog = BACKLOG; - private int serverTimeout = TIMEOUT; - - private InetAddress inet; - private int port; - - private ServerSocketFactory factory; - private ServerSocket serverSocket; - - private volatile boolean running = false; - private volatile boolean paused = false; - private boolean initialized = false; - private boolean reinitializing = false; - static final int debug=0; - - protected boolean tcpNoDelay=false; - protected int linger=100; - protected int socketTimeout=-1; - private boolean lf = true; - - - // ------ Leader follower fields - - - TcpConnectionHandler handler; - ThreadPoolRunnable listener; - ThreadPool tp; - - - // ------ Master slave fields - - /* The background thread. */ - private Thread thread = null; - /* Available processors. */ - private Stack workerThreads = new Stack(); - private int curThreads = 0; - private int maxThreads = 20; - /* All processors which have been created. */ - private Vector created = new Vector(); - - - public PoolTcpEndpoint() { - tp = new ThreadPool(); - } - - public PoolTcpEndpoint( ThreadPool tp ) { - this.tp=tp; - } - - // -------------------- Configuration -------------------- - - public void setMaxThreads(int maxThreads) { - if( maxThreads > 0) - tp.setMaxThreads(maxThreads); - } - - public int getMaxThreads() { - return tp.getMaxThreads(); - } - - public void setMaxSpareThreads(int maxThreads) { - if(maxThreads > 0) - tp.setMaxSpareThreads(maxThreads); - } - - public int getMaxSpareThreads() { - return tp.getMaxSpareThreads(); - } - - public void setMinSpareThreads(int minThreads) { - if(minThreads > 0) - tp.setMinSpareThreads(minThreads); - } - - public int getMinSpareThreads() { - return tp.getMinSpareThreads(); - } - - public void setThreadPriority(int threadPriority) { - tp.setThreadPriority(threadPriority); - } - - public int getThreadPriority() { - return tp.getThreadPriority(); - } - - public int getPort() { - return port; - } - - public void setPort(int port ) { - this.port=port; - } - - public InetAddress getAddress() { - return inet; - } - - public void setAddress(InetAddress inet) { - this.inet=inet; - } - - public void setServerSocket(ServerSocket ss) { - serverSocket = ss; - } - - public void setServerSocketFactory( ServerSocketFactory factory ) { - this.factory=factory; - } - - ServerSocketFactory getServerSocketFactory() { - return factory; - } - - public void setConnectionHandler( TcpConnectionHandler handler ) { - this.handler=handler; - } - - public TcpConnectionHandler getConnectionHandler() { - return handler; - } - - public boolean isRunning() { - return running; - } - - public boolean isPaused() { - return paused; - } - - /** - * Allows the server developer to specify the backlog that - * should be used for server sockets. By default, this value - * is 100. - */ - public void setBacklog(int backlog) { - if( backlog>0) - this.backlog = backlog; - } - - public int getBacklog() { - return backlog; - } - - /** - * Sets the timeout in ms of the server sockets created by this - * server. This method allows the developer to make servers - * more or less responsive to having their server sockets - * shut down. - * - *

        By default this value is 1000ms. - */ - public void setServerTimeout(int timeout) { - this.serverTimeout = timeout; - } - - public boolean getTcpNoDelay() { - return tcpNoDelay; - } - - public void setTcpNoDelay( boolean b ) { - tcpNoDelay=b; - } - - public int getSoLinger() { - return linger; - } - - public void setSoLinger( int i ) { - linger=i; - } - - public int getSoTimeout() { - return socketTimeout; - } - - public void setSoTimeout( int i ) { - socketTimeout=i; - } - - public int getServerSoTimeout() { - return serverTimeout; - } - - public void setServerSoTimeout( int i ) { - serverTimeout=i; - } - - public String getStrategy() { - if (lf) { - return "lf"; - } else { - return "ms"; - } - } - - public void setStrategy(String strategy) { - if ("ms".equals(strategy)) { - lf = false; - } else { - lf = true; - } - } - - public int getCurrentThreadCount() { - return curThreads; - } - - public int getCurrentThreadsBusy() { - return curThreads - workerThreads.size(); - } - - // -------------------- Public methods -------------------- - - public void initEndpoint() throws IOException, InstantiationException { - try { - if(factory==null) - factory=ServerSocketFactory.getDefault(); - if(serverSocket==null) { - try { - if (inet == null) { - serverSocket = factory.createSocket(port, backlog); - } else { - serverSocket = factory.createSocket(port, backlog, inet); - } - } catch ( BindException be ) { - throw new BindException(be.getMessage() + ":" + port); - } - } - if( serverTimeout >= 0 ) - serverSocket.setSoTimeout( serverTimeout ); - } catch( IOException ex ) { - throw ex; - } catch( InstantiationException ex1 ) { - throw ex1; - } - initialized = true; - } - - public void startEndpoint() throws IOException, InstantiationException { - if (!initialized) { - initEndpoint(); - } - if (lf) { - tp.start(); - } - running = true; - paused = false; - if (lf) { - listener = new LeaderFollowerWorkerThread(this); - tp.runIt(listener); - } else { - maxThreads = getMaxThreads(); - threadStart(); - } - } - - public void pauseEndpoint() { - if (running && !paused) { - paused = true; - unlockAccept(); - } - } - - public void resumeEndpoint() { - if (running) { - paused = false; - } - } - - public void stopEndpoint() { - if (running) { - if (lf) { - tp.shutdown(); - } - running = false; - if (serverSocket != null) { - closeServerSocket(); - } - if (!lf) { - threadStop(); - } - initialized=false ; - } - } - - protected void closeServerSocket() { - if (!paused) - unlockAccept(); - try { - if( serverSocket!=null) - serverSocket.close(); - } catch(Exception e) { - log.error(sm.getString("endpoint.err.close"), e); - } - serverSocket = null; - } - - protected void unlockAccept() { - Socket s = null; - try { - // Need to create a connection to unlock the accept(); - if (inet == null) { - s = new Socket("127.0.0.1", port); - } else { - s = new Socket(inet, port); - // setting soLinger to a small value will help shutdown the - // connection quicker - s.setSoLinger(true, 0); - } - } catch(Exception e) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); - } - } finally { - if (s != null) { - try { - s.close(); - } catch (Exception e) { - // Ignore - } - } - } - } - - // -------------------- Private methods - - Socket acceptSocket() { - if( !running || serverSocket==null ) return null; - - Socket accepted = null; - - try { - if(factory==null) { - accepted = serverSocket.accept(); - } else { - accepted = factory.acceptSocket(serverSocket); - } - if (null == accepted) { - log.warn(sm.getString("endpoint.warn.nullSocket")); - } else { - if (!running) { - accepted.close(); // rude, but unlikely! - accepted = null; - } else if (factory != null) { - factory.initSocket( accepted ); - } - } - } - catch(InterruptedIOException iioe) { - // normal part -- should happen regularly so - // that the endpoint can release if the server - // is shutdown. - } - catch (AccessControlException ace) { - // When using the Java SecurityManager this exception - // can be thrown if you are restricting access to the - // socket with SocketPermission's. - // Log the unauthorized access and continue - String msg = sm.getString("endpoint.warn.security", - serverSocket, ace); - log.warn(msg); - } - catch (IOException e) { - - String msg = null; - - if (running) { - msg = sm.getString("endpoint.err.nonfatal", - serverSocket, e); - log.error(msg, e); - } - - if (accepted != null) { - try { - accepted.close(); - } catch(Throwable ex) { - msg = sm.getString("endpoint.err.nonfatal", - accepted, ex); - log.warn(msg, ex); - } - accepted = null; - } - - if( ! running ) return null; - reinitializing = true; - // Restart endpoint when getting an IOException during accept - synchronized (threadSync) { - if (reinitializing) { - reinitializing = false; - // 1) Attempt to close server socket - closeServerSocket(); - initialized = false; - // 2) Reinit endpoint (recreate server socket) - try { - msg = sm.getString("endpoint.warn.reinit"); - log.warn(msg); - initEndpoint(); - } catch (Throwable t) { - msg = sm.getString("endpoint.err.nonfatal", - serverSocket, t); - log.error(msg, t); - } - // 3) If failed, attempt to restart endpoint - if (!initialized) { - msg = sm.getString("endpoint.warn.restart"); - log.warn(msg); - try { - stopEndpoint(); - initEndpoint(); - startEndpoint(); - } catch (Throwable t) { - msg = sm.getString("endpoint.err.fatal", - serverSocket, t); - log.error(msg, t); - } - // Current thread is now invalid: kill it - throw new ThreadDeath(); - } - } - } - - } - - return accepted; - } - - void setSocketOptions(Socket socket) - throws SocketException { - if(linger >= 0 ) - socket.setSoLinger( true, linger); - if( tcpNoDelay ) - socket.setTcpNoDelay(tcpNoDelay); - if( socketTimeout > 0 ) - socket.setSoTimeout( socketTimeout ); - } - - - void processSocket(Socket s, TcpConnection con, Object[] threadData) { - // Process the connection - int step = 1; - try { - - // 1: Set socket options: timeout, linger, etc - setSocketOptions(s); - - // 2: SSL handshake - step = 2; - if (getServerSocketFactory() != null) { - getServerSocketFactory().handshake(s); - } - - // 3: Process the connection - step = 3; - con.setEndpoint(this); - con.setSocket(s); - getConnectionHandler().processConnection(con, threadData); - - } catch (SocketException se) { - log.debug(sm.getString("endpoint.err.socket", s.getInetAddress()), - se); - // Try to close the socket - try { - s.close(); - } catch (IOException e) { - } - } catch (Throwable t) { - if (step == 2) { - if (log.isDebugEnabled()) { - log.debug(sm.getString("endpoint.err.handshake"), t); - } - } else { - log.error(sm.getString("endpoint.err.unexpected"), t); - } - // Try to close the socket - try { - s.close(); - } catch (IOException e) { - } - } finally { - if (con != null) { - con.recycle(); - } - } - } - - - // -------------------------------------------------- Master Slave Methods - - - /** - * Create (or allocate) and return an available processor for use in - * processing a specific HTTP request, if possible. If the maximum - * allowed processors have already been created and are in use, return - * null instead. - */ - private MasterSlaveWorkerThread createWorkerThread() { - - synchronized (workerThreads) { - if (workerThreads.size() > 0) { - return ((MasterSlaveWorkerThread) workerThreads.pop()); - } - if ((maxThreads > 0) && (curThreads < maxThreads)) { - return (newWorkerThread()); - } else { - if (maxThreads < 0) { - return (newWorkerThread()); - } else { - return (null); - } - } - } - - } - - - /** - * Create and return a new processor suitable for processing HTTP - * requests and returning the corresponding responses. - */ - private MasterSlaveWorkerThread newWorkerThread() { - - MasterSlaveWorkerThread workerThread = - new MasterSlaveWorkerThread(this, tp.getName() + "-" + (++curThreads)); - workerThread.start(); - created.addElement(workerThread); - return (workerThread); - - } - - - /** - * Recycle the specified Processor so that it can be used again. - * - * @param processor The processor to be recycled - */ - void recycleWorkerThread(MasterSlaveWorkerThread workerThread) { - workerThreads.push(workerThread); - } - - - /** - * The background thread that listens for incoming TCP/IP connections and - * hands them off to an appropriate processor. - */ - public void run() { - - // Loop until we receive a shutdown command - while (running) { - - // Loop if endpoint is paused - while (paused) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - // Ignore - } - } - - // Allocate a new worker thread - MasterSlaveWorkerThread workerThread = createWorkerThread(); - if (workerThread == null) { - try { - // Wait a little for load to go down: as a result, - // no accept will be made until the concurrency is - // lower than the specified maxThreads, and current - // connections will wait for a little bit instead of - // failing right away. - Thread.sleep(100); - } catch (InterruptedException e) { - // Ignore - } - continue; - } - - // Accept the next incoming connection from the server socket - Socket socket = acceptSocket(); - - // Hand this socket off to an appropriate processor - workerThread.assign(socket); - - // The processor will recycle itself when it finishes - - } - - // Notify the threadStop() method that we have shut ourselves down - synchronized (threadSync) { - threadSync.notifyAll(); - } - - } - - - /** - * Start the background processing thread. - */ - private void threadStart() { - thread = new Thread(this, tp.getName()); - thread.setPriority(getThreadPriority()); - thread.setDaemon(true); - thread.start(); - } - - - /** - * Stop the background processing thread. - */ - private void threadStop() { - thread = null; - } - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.BindException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketException; +import java.security.AccessControlException; +import java.util.Stack; +import java.util.Vector; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.tomcat.util.res.StringManager; +import org.apache.tomcat.util.threads.ThreadPool; +import org.apache.tomcat.util.threads.ThreadPoolRunnable; + +/* Similar with MPM module in Apache2.0. Handles all the details related with + "tcp server" functionality - thread management, accept policy, etc. + It should do nothing more - as soon as it get a socket ( and all socket options + are set, etc), it just handle the stream to ConnectionHandler.processConnection. (costin) +*/ + + + +/** + * Handle incoming TCP connections. + * + * This class implement a simple server model: one listener thread accepts on a socket and + * creates a new worker thread for each incoming connection. + * + * More advanced Endpoints will reuse the threads, use queues, etc. + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author Jason Hunter [jch@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Costin@eng.sun.com + * @author Gal Shachor [shachor@il.ibm.com] + * @author Yoav Shapira + */ +public class PoolTcpEndpoint implements Runnable { // implements Endpoint { + + static Log log=LogFactory.getLog(PoolTcpEndpoint.class ); + + private StringManager sm = + StringManager.getManager("org.apache.tomcat.util.net.res"); + + private static final int BACKLOG = 100; + private static final int TIMEOUT = 1000; + + private final Object threadSync = new Object(); + + private int backlog = BACKLOG; + private int serverTimeout = TIMEOUT; + + private InetAddress inet; + private int port; + + private ServerSocketFactory factory; + private ServerSocket serverSocket; + + private volatile boolean running = false; + private volatile boolean paused = false; + private boolean initialized = false; + private boolean reinitializing = false; + static final int debug=0; + + protected boolean tcpNoDelay=false; + protected int linger=100; + protected int socketTimeout=-1; + private boolean lf = true; + + + // ------ Leader follower fields + + + TcpConnectionHandler handler; + ThreadPoolRunnable listener; + ThreadPool tp; + + + // ------ Master slave fields + + /* The background thread. */ + private Thread thread = null; + /* Available processors. */ + private Stack workerThreads = new Stack(); + private int curThreads = 0; + private int maxThreads = 20; + /* All processors which have been created. */ + private Vector created = new Vector(); + + + public PoolTcpEndpoint() { + tp = new ThreadPool(); + } + + public PoolTcpEndpoint( ThreadPool tp ) { + this.tp=tp; + } + + // -------------------- Configuration -------------------- + + public void setMaxThreads(int maxThreads) { + if( maxThreads > 0) + tp.setMaxThreads(maxThreads); + } + + public int getMaxThreads() { + return tp.getMaxThreads(); + } + + public void setMaxSpareThreads(int maxThreads) { + if(maxThreads > 0) + tp.setMaxSpareThreads(maxThreads); + } + + public int getMaxSpareThreads() { + return tp.getMaxSpareThreads(); + } + + public void setMinSpareThreads(int minThreads) { + if(minThreads > 0) + tp.setMinSpareThreads(minThreads); + } + + public int getMinSpareThreads() { + return tp.getMinSpareThreads(); + } + + public void setThreadPriority(int threadPriority) { + tp.setThreadPriority(threadPriority); + } + + public int getThreadPriority() { + return tp.getThreadPriority(); + } + + public int getPort() { + return port; + } + + public void setPort(int port ) { + this.port=port; + } + + public InetAddress getAddress() { + return inet; + } + + public void setAddress(InetAddress inet) { + this.inet=inet; + } + + public void setServerSocket(ServerSocket ss) { + serverSocket = ss; + } + + public void setServerSocketFactory( ServerSocketFactory factory ) { + this.factory=factory; + } + + ServerSocketFactory getServerSocketFactory() { + return factory; + } + + public void setConnectionHandler( TcpConnectionHandler handler ) { + this.handler=handler; + } + + public TcpConnectionHandler getConnectionHandler() { + return handler; + } + + public boolean isRunning() { + return running; + } + + public boolean isPaused() { + return paused; + } + + /** + * Allows the server developer to specify the backlog that + * should be used for server sockets. By default, this value + * is 100. + */ + public void setBacklog(int backlog) { + if( backlog>0) + this.backlog = backlog; + } + + public int getBacklog() { + return backlog; + } + + /** + * Sets the timeout in ms of the server sockets created by this + * server. This method allows the developer to make servers + * more or less responsive to having their server sockets + * shut down. + * + *

        By default this value is 1000ms. + */ + public void setServerTimeout(int timeout) { + this.serverTimeout = timeout; + } + + public boolean getTcpNoDelay() { + return tcpNoDelay; + } + + public void setTcpNoDelay( boolean b ) { + tcpNoDelay=b; + } + + public int getSoLinger() { + return linger; + } + + public void setSoLinger( int i ) { + linger=i; + } + + public int getSoTimeout() { + return socketTimeout; + } + + public void setSoTimeout( int i ) { + socketTimeout=i; + } + + public int getServerSoTimeout() { + return serverTimeout; + } + + public void setServerSoTimeout( int i ) { + serverTimeout=i; + } + + public String getStrategy() { + if (lf) { + return "lf"; + } else { + return "ms"; + } + } + + public void setStrategy(String strategy) { + if ("ms".equals(strategy)) { + lf = false; + } else { + lf = true; + } + } + + public int getCurrentThreadCount() { + return curThreads; + } + + public int getCurrentThreadsBusy() { + return curThreads - workerThreads.size(); + } + + // -------------------- Public methods -------------------- + + public void initEndpoint() throws IOException, InstantiationException { + try { + if(factory==null) + factory=ServerSocketFactory.getDefault(); + if(serverSocket==null) { + try { + if (inet == null) { + serverSocket = factory.createSocket(port, backlog); + } else { + serverSocket = factory.createSocket(port, backlog, inet); + } + } catch ( BindException be ) { + throw new BindException(be.getMessage() + ":" + port); + } + } + if( serverTimeout >= 0 ) + serverSocket.setSoTimeout( serverTimeout ); + } catch( IOException ex ) { + throw ex; + } catch( InstantiationException ex1 ) { + throw ex1; + } + initialized = true; + } + + public void startEndpoint() throws IOException, InstantiationException { + if (!initialized) { + initEndpoint(); + } + if (lf) { + tp.start(); + } + running = true; + paused = false; + if (lf) { + listener = new LeaderFollowerWorkerThread(this); + tp.runIt(listener); + } else { + maxThreads = getMaxThreads(); + threadStart(); + } + } + + public void pauseEndpoint() { + if (running && !paused) { + paused = true; + unlockAccept(); + } + } + + public void resumeEndpoint() { + if (running) { + paused = false; + } + } + + public void stopEndpoint() { + if (running) { + if (lf) { + tp.shutdown(); + } + running = false; + if (serverSocket != null) { + closeServerSocket(); + } + if (!lf) { + threadStop(); + } + initialized=false ; + } + } + + protected void closeServerSocket() { + if (!paused) + unlockAccept(); + try { + if( serverSocket!=null) + serverSocket.close(); + } catch(Exception e) { + log.error(sm.getString("endpoint.err.close"), e); + } + serverSocket = null; + } + + protected void unlockAccept() { + Socket s = null; + try { + // Need to create a connection to unlock the accept(); + if (inet == null) { + s = new Socket("127.0.0.1", port); + } else { + s = new Socket(inet, port); + // setting soLinger to a small value will help shutdown the + // connection quicker + s.setSoLinger(true, 0); + } + } catch(Exception e) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("endpoint.debug.unlock", "" + port), e); + } + } finally { + if (s != null) { + try { + s.close(); + } catch (Exception e) { + // Ignore + } + } + } + } + + // -------------------- Private methods + + Socket acceptSocket() { + if( !running || serverSocket==null ) return null; + + Socket accepted = null; + + try { + if(factory==null) { + accepted = serverSocket.accept(); + } else { + accepted = factory.acceptSocket(serverSocket); + } + if (null == accepted) { + log.warn(sm.getString("endpoint.warn.nullSocket")); + } else { + if (!running) { + accepted.close(); // rude, but unlikely! + accepted = null; + } else if (factory != null) { + factory.initSocket( accepted ); + } + } + } + catch(InterruptedIOException iioe) { + // normal part -- should happen regularly so + // that the endpoint can release if the server + // is shutdown. + } + catch (AccessControlException ace) { + // When using the Java SecurityManager this exception + // can be thrown if you are restricting access to the + // socket with SocketPermission's. + // Log the unauthorized access and continue + String msg = sm.getString("endpoint.warn.security", + serverSocket, ace); + log.warn(msg); + } + catch (IOException e) { + + String msg = null; + + if (running) { + msg = sm.getString("endpoint.err.nonfatal", + serverSocket, e); + log.error(msg, e); + } + + if (accepted != null) { + try { + accepted.close(); + } catch(Throwable ex) { + msg = sm.getString("endpoint.err.nonfatal", + accepted, ex); + log.warn(msg, ex); + } + accepted = null; + } + + if( ! running ) return null; + reinitializing = true; + // Restart endpoint when getting an IOException during accept + synchronized (threadSync) { + if (reinitializing) { + reinitializing = false; + // 1) Attempt to close server socket + closeServerSocket(); + initialized = false; + // 2) Reinit endpoint (recreate server socket) + try { + msg = sm.getString("endpoint.warn.reinit"); + log.warn(msg); + initEndpoint(); + } catch (Throwable t) { + msg = sm.getString("endpoint.err.nonfatal", + serverSocket, t); + log.error(msg, t); + } + // 3) If failed, attempt to restart endpoint + if (!initialized) { + msg = sm.getString("endpoint.warn.restart"); + log.warn(msg); + try { + stopEndpoint(); + initEndpoint(); + startEndpoint(); + } catch (Throwable t) { + msg = sm.getString("endpoint.err.fatal", + serverSocket, t); + log.error(msg, t); + } + // Current thread is now invalid: kill it + throw new ThreadDeath(); + } + } + } + + } + + return accepted; + } + + void setSocketOptions(Socket socket) + throws SocketException { + if(linger >= 0 ) + socket.setSoLinger( true, linger); + if( tcpNoDelay ) + socket.setTcpNoDelay(tcpNoDelay); + if( socketTimeout > 0 ) + socket.setSoTimeout( socketTimeout ); + } + + + void processSocket(Socket s, TcpConnection con, Object[] threadData) { + // Process the connection + int step = 1; + try { + + // 1: Set socket options: timeout, linger, etc + setSocketOptions(s); + + // 2: SSL handshake + step = 2; + if (getServerSocketFactory() != null) { + getServerSocketFactory().handshake(s); + } + + // 3: Process the connection + step = 3; + con.setEndpoint(this); + con.setSocket(s); + getConnectionHandler().processConnection(con, threadData); + + } catch (SocketException se) { + log.debug(sm.getString("endpoint.err.socket", s.getInetAddress()), + se); + // Try to close the socket + try { + s.close(); + } catch (IOException e) { + } + } catch (Throwable t) { + if (step == 2) { + if (log.isDebugEnabled()) { + log.debug(sm.getString("endpoint.err.handshake"), t); + } + } else { + log.error(sm.getString("endpoint.err.unexpected"), t); + } + // Try to close the socket + try { + s.close(); + } catch (IOException e) { + } + } finally { + if (con != null) { + con.recycle(); + } + } + } + + + // -------------------------------------------------- Master Slave Methods + + + /** + * Create (or allocate) and return an available processor for use in + * processing a specific HTTP request, if possible. If the maximum + * allowed processors have already been created and are in use, return + * null instead. + */ + private MasterSlaveWorkerThread createWorkerThread() { + + synchronized (workerThreads) { + if (workerThreads.size() > 0) { + return ((MasterSlaveWorkerThread) workerThreads.pop()); + } + if ((maxThreads > 0) && (curThreads < maxThreads)) { + return (newWorkerThread()); + } else { + if (maxThreads < 0) { + return (newWorkerThread()); + } else { + return (null); + } + } + } + + } + + + /** + * Create and return a new processor suitable for processing HTTP + * requests and returning the corresponding responses. + */ + private MasterSlaveWorkerThread newWorkerThread() { + + MasterSlaveWorkerThread workerThread = + new MasterSlaveWorkerThread(this, tp.getName() + "-" + (++curThreads)); + workerThread.start(); + created.addElement(workerThread); + return (workerThread); + + } + + + /** + * Recycle the specified Processor so that it can be used again. + * + * @param processor The processor to be recycled + */ + void recycleWorkerThread(MasterSlaveWorkerThread workerThread) { + workerThreads.push(workerThread); + } + + + /** + * The background thread that listens for incoming TCP/IP connections and + * hands them off to an appropriate processor. + */ + public void run() { + + // Loop until we receive a shutdown command + while (running) { + + // Loop if endpoint is paused + while (paused) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore + } + } + + // Allocate a new worker thread + MasterSlaveWorkerThread workerThread = createWorkerThread(); + if (workerThread == null) { + try { + // Wait a little for load to go down: as a result, + // no accept will be made until the concurrency is + // lower than the specified maxThreads, and current + // connections will wait for a little bit instead of + // failing right away. + Thread.sleep(100); + } catch (InterruptedException e) { + // Ignore + } + continue; + } + + // Accept the next incoming connection from the server socket + Socket socket = acceptSocket(); + + // Hand this socket off to an appropriate processor + workerThread.assign(socket); + + // The processor will recycle itself when it finishes + + } + + // Notify the threadStop() method that we have shut ourselves down + synchronized (threadSync) { + threadSync.notifyAll(); + } + + } + + + /** + * Start the background processing thread. + */ + private void threadStart() { + thread = new Thread(this, tp.getName()); + thread.setPriority(getThreadPriority()); + thread.setDaemon(true); + thread.start(); + } + + + /** + * Stop the background processing thread. + */ + private void threadStop() { + thread = null; + } + + +} diff --git a/java/org/apache/tomcat/util/net/SSLImplementation.java b/java/org/apache/tomcat/util/net/SSLImplementation.java index a33f688ac..859cbd98d 100644 --- a/java/org/apache/tomcat/util/net/SSLImplementation.java +++ b/java/org/apache/tomcat/util/net/SSLImplementation.java @@ -1,86 +1,86 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.net.Socket; - -/* SSLImplementation: - - Abstract factory and base class for all SSL implementations. - - @author EKR -*/ -abstract public class SSLImplementation { - private static org.apache.commons.logging.Log logger = - org.apache.commons.logging.LogFactory.getLog(SSLImplementation.class); - - // The default implementations in our search path - private static final String PureTLSImplementationClass= - "org.apache.tomcat.util.net.puretls.PureTLSImplementation"; - private static final String JSSEImplementationClass= - "org.apache.tomcat.util.net.jsse.JSSEImplementation"; - - private static final String[] implementations= - { - PureTLSImplementationClass, - JSSEImplementationClass - }; - - public static SSLImplementation getInstance() throws ClassNotFoundException - { - for(int i=0;itrue, then re-negotiate the - * connection if necessary. - */ - public Object[] getPeerCertificateChain(boolean force) - throws IOException; - - /** - * Get the keysize. - * - * What we're supposed to put here is ill-defined by the - * Servlet spec (S 4.7 again). There are at least 4 potential - * values that might go here: - * - * (a) The size of the encryption key - * (b) The size of the MAC key - * (c) The size of the key-exchange key - * (d) The size of the signature key used by the server - * - * Unfortunately, all of these values are nonsensical. - **/ - public Integer getKeySize() - throws IOException; - - /** - * The current session Id. - */ - public String getSessionId() - throws IOException; - /** - * Simple data class that represents the cipher being used, along with the - * corresponding effective key size. The specified phrase must appear in the - * name of the cipher suite to be recognized. - */ - - final class CipherData { - - public String phrase = null; - - public int keySize = 0; - - public CipherData(String phrase, int keySize) { - this.phrase = phrase; - this.keySize = keySize; - } - - } - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.IOException; + +/* SSLSupport + + Interface for SSL-specific functions + + @author EKR +*/ + +public interface SSLSupport { + /** + * The Request attribute key for the cipher suite. + */ + public static final String CIPHER_SUITE_KEY = "javax.servlet.request.cipher_suite"; + + /** + * The Request attribute key for the key size. + */ + public static final String KEY_SIZE_KEY = "javax.servlet.request.key_size"; + + /** + * The Request attribute key for the client certificate chain. + */ + public static final String CERTIFICATE_KEY = "javax.servlet.request.X509Certificate"; + + /** + * The Request attribute key for the session id. + * This one is a Tomcat extension to the Servlet spec. + */ + public static final String SESSION_ID_KEY = "javax.servlet.request.ssl_session"; + + /** + * A mapping table to determine the number of effective bits in the key + * when using a cipher suite containing the specified cipher name. The + * underlying data came from the TLS Specification (RFC 2246), Appendix C. + */ + static final CipherData ciphers[] = { + new CipherData("_WITH_NULL_", 0), + new CipherData("_WITH_IDEA_CBC_", 128), + new CipherData("_WITH_RC2_CBC_40_", 40), + new CipherData("_WITH_RC4_40_", 40), + new CipherData("_WITH_RC4_128_", 128), + new CipherData("_WITH_DES40_CBC_", 40), + new CipherData("_WITH_DES_CBC_", 56), + new CipherData("_WITH_3DES_EDE_CBC_", 168) + }; + + /** + * The cipher suite being used on this connection. + */ + public String getCipherSuite() throws IOException; + + /** + * The client certificate chain (if any). + */ + public Object[] getPeerCertificateChain() + throws IOException; + + /** + * The client certificate chain (if any). + * @param force If true, then re-negotiate the + * connection if necessary. + */ + public Object[] getPeerCertificateChain(boolean force) + throws IOException; + + /** + * Get the keysize. + * + * What we're supposed to put here is ill-defined by the + * Servlet spec (S 4.7 again). There are at least 4 potential + * values that might go here: + * + * (a) The size of the encryption key + * (b) The size of the MAC key + * (c) The size of the key-exchange key + * (d) The size of the signature key used by the server + * + * Unfortunately, all of these values are nonsensical. + **/ + public Integer getKeySize() + throws IOException; + + /** + * The current session Id. + */ + public String getSessionId() + throws IOException; + /** + * Simple data class that represents the cipher being used, along with the + * corresponding effective key size. The specified phrase must appear in the + * name of the cipher suite to be recognized. + */ + + final class CipherData { + + public String phrase = null; + + public int keySize = 0; + + public CipherData(String phrase, int keySize) { + this.phrase = phrase; + this.keySize = keySize; + } + + } + +} + diff --git a/java/org/apache/tomcat/util/net/ServerSocketFactory.java b/java/org/apache/tomcat/util/net/ServerSocketFactory.java index c5d8dc4a9..bfb5d8064 100644 --- a/java/org/apache/tomcat/util/net/ServerSocketFactory.java +++ b/java/org/apache/tomcat/util/net/ServerSocketFactory.java @@ -1,172 +1,172 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.util.Hashtable; - -/** - * This class creates server sockets. It may be subclassed by other - * factories, which create particular types of server sockets. This - * provides a general framework for the addition of public socket-level - * functionality. It it is the server side analogue of a socket factory, - * and similarly provides a way to capture a variety of policies related - * to the sockets being constructed. - * - *

        Like socket factories, Server Socket factory instances have two - * categories of methods. First are methods used to create sockets. - * Second are methods which set properties used in the production of - * sockets, such as networking options. There is also an environment - * specific default server socket factory; frameworks will often use - * their own customized factory. - * - *


        It may be desirable to move this interface into the - * java.net package, so that is not an extension but the preferred - * interface. Should this be serializable, making it a JavaBean which can - * be saved along with its networking configuration? - * - * - * @author db@eng.sun.com - * @author Harish Prabandham - */ -public abstract class ServerSocketFactory implements Cloneable { - - // - // NOTE: JDK 1.1 bug in class GC, this can get collected - // even though it's always accessible via getDefault(). - // - - private static ServerSocketFactory theFactory; - protected Hashtable attributes=new Hashtable(); - - /** - * Constructor is used only by subclasses. - */ - - protected ServerSocketFactory () { - /* NOTHING */ - } - - /** General mechanism to pass attributes from the - * ServerConnector to the socket factory. - * - * Note that the "prefered" mechanism is to - * use bean setters and explicit methods, but - * this allows easy configuration via server.xml - * or simple Properties - */ - public void setAttribute( String name, Object value ) { - if( name!=null && value !=null) - attributes.put( name, value ); - } - - /** - * Returns a copy of the environment's default socket factory. - */ - public static synchronized ServerSocketFactory getDefault () { - // - // optimize typical case: no synch needed - // - - if (theFactory == null) { - // - // Different implementations of this method could - // work rather differently. For example, driving - // this from a system property, or using a different - // implementation than JavaSoft's. - // - - theFactory = new DefaultServerSocketFactory (); - } - - try { - return (ServerSocketFactory) theFactory.clone (); - } catch (CloneNotSupportedException e) { - throw new RuntimeException (e.getMessage ()); - } - } - - /** - * Returns a server socket which uses all network interfaces on - * the host, and is bound to a the specified port. The socket is - * configured with the socket options (such as accept timeout) - * given to this factory. - * - * @param port the port to listen to - * @exception IOException for networking errors - * @exception InstantiationException for construction errors - */ - public abstract ServerSocket createSocket (int port) - throws IOException, InstantiationException; - - /** - * Returns a server socket which uses all network interfaces on - * the host, is bound to a the specified port, and uses the - * specified connection backlog. The socket is configured with - * the socket options (such as accept timeout) given to this factory. - * - * @param port the port to listen to - * @param backlog how many connections are queued - * @exception IOException for networking errors - * @exception InstantiationException for construction errors - */ - - public abstract ServerSocket createSocket (int port, int backlog) - throws IOException, InstantiationException; - - /** - * Returns a server socket which uses only the specified network - * interface on the local host, is bound to a the specified port, - * and uses the specified connection backlog. The socket is configured - * with the socket options (such as accept timeout) given to this factory. - * - * @param port the port to listen to - * @param backlog how many connections are queued - * @param ifAddress the network interface address to use - * @exception IOException for networking errors - * @exception InstantiationException for construction errors - */ - - public abstract ServerSocket createSocket (int port, - int backlog, InetAddress ifAddress) - throws IOException, InstantiationException; - - public void initSocket( Socket s ) { - } - - /** - Wrapper function for accept(). This allows us to trap and - translate exceptions if necessary - - @exception IOException; - */ - public abstract Socket acceptSocket(ServerSocket socket) - throws IOException; - - /** - Extra function to initiate the handshake. Sometimes necessary - for SSL - - @exception IOException; - */ - public abstract void handshake(Socket sock) - throws IOException; -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.IOException; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Hashtable; + +/** + * This class creates server sockets. It may be subclassed by other + * factories, which create particular types of server sockets. This + * provides a general framework for the addition of public socket-level + * functionality. It it is the server side analogue of a socket factory, + * and similarly provides a way to capture a variety of policies related + * to the sockets being constructed. + * + *

        Like socket factories, Server Socket factory instances have two + * categories of methods. First are methods used to create sockets. + * Second are methods which set properties used in the production of + * sockets, such as networking options. There is also an environment + * specific default server socket factory; frameworks will often use + * their own customized factory. + * + *


        It may be desirable to move this interface into the + * java.net package, so that is not an extension but the preferred + * interface. Should this be serializable, making it a JavaBean which can + * be saved along with its networking configuration? + * + * + * @author db@eng.sun.com + * @author Harish Prabandham + */ +public abstract class ServerSocketFactory implements Cloneable { + + // + // NOTE: JDK 1.1 bug in class GC, this can get collected + // even though it's always accessible via getDefault(). + // + + private static ServerSocketFactory theFactory; + protected Hashtable attributes=new Hashtable(); + + /** + * Constructor is used only by subclasses. + */ + + protected ServerSocketFactory () { + /* NOTHING */ + } + + /** General mechanism to pass attributes from the + * ServerConnector to the socket factory. + * + * Note that the "prefered" mechanism is to + * use bean setters and explicit methods, but + * this allows easy configuration via server.xml + * or simple Properties + */ + public void setAttribute( String name, Object value ) { + if( name!=null && value !=null) + attributes.put( name, value ); + } + + /** + * Returns a copy of the environment's default socket factory. + */ + public static synchronized ServerSocketFactory getDefault () { + // + // optimize typical case: no synch needed + // + + if (theFactory == null) { + // + // Different implementations of this method could + // work rather differently. For example, driving + // this from a system property, or using a different + // implementation than JavaSoft's. + // + + theFactory = new DefaultServerSocketFactory (); + } + + try { + return (ServerSocketFactory) theFactory.clone (); + } catch (CloneNotSupportedException e) { + throw new RuntimeException (e.getMessage ()); + } + } + + /** + * Returns a server socket which uses all network interfaces on + * the host, and is bound to a the specified port. The socket is + * configured with the socket options (such as accept timeout) + * given to this factory. + * + * @param port the port to listen to + * @exception IOException for networking errors + * @exception InstantiationException for construction errors + */ + public abstract ServerSocket createSocket (int port) + throws IOException, InstantiationException; + + /** + * Returns a server socket which uses all network interfaces on + * the host, is bound to a the specified port, and uses the + * specified connection backlog. The socket is configured with + * the socket options (such as accept timeout) given to this factory. + * + * @param port the port to listen to + * @param backlog how many connections are queued + * @exception IOException for networking errors + * @exception InstantiationException for construction errors + */ + + public abstract ServerSocket createSocket (int port, int backlog) + throws IOException, InstantiationException; + + /** + * Returns a server socket which uses only the specified network + * interface on the local host, is bound to a the specified port, + * and uses the specified connection backlog. The socket is configured + * with the socket options (such as accept timeout) given to this factory. + * + * @param port the port to listen to + * @param backlog how many connections are queued + * @param ifAddress the network interface address to use + * @exception IOException for networking errors + * @exception InstantiationException for construction errors + */ + + public abstract ServerSocket createSocket (int port, + int backlog, InetAddress ifAddress) + throws IOException, InstantiationException; + + public void initSocket( Socket s ) { + } + + /** + Wrapper function for accept(). This allows us to trap and + translate exceptions if necessary + + @exception IOException; + */ + public abstract Socket acceptSocket(ServerSocket socket) + throws IOException; + + /** + Extra function to initiate the handshake. Sometimes necessary + for SSL + + @exception IOException; + */ + public abstract void handshake(Socket sock) + throws IOException; +} + diff --git a/java/org/apache/tomcat/util/net/TcpConnection.java b/java/org/apache/tomcat/util/net/TcpConnection.java index 0d319e30e..027e28f10 100644 --- a/java/org/apache/tomcat/util/net/TcpConnection.java +++ b/java/org/apache/tomcat/util/net/TcpConnection.java @@ -1,109 +1,109 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - -import java.io.IOException; -import java.io.InputStream; -import java.net.Socket; - -/** - * - */ -public class TcpConnection { // implements Endpoint { - /** - * Maxium number of times to clear the socket input buffer. - */ - static int MAX_SHUTDOWN_TRIES=20; - - public TcpConnection() { - } - - // -------------------- Properties -------------------- - - PoolTcpEndpoint endpoint; - Socket socket; - - public static void setMaxShutdownTries(int mst) { - MAX_SHUTDOWN_TRIES = mst; - } - public void setEndpoint(PoolTcpEndpoint endpoint) { - this.endpoint = endpoint; - } - - public PoolTcpEndpoint getEndpoint() { - return endpoint; - } - - public void setSocket(Socket socket) { - this.socket=socket; - } - - public Socket getSocket() { - return socket; - } - - public void recycle() { - endpoint = null; - socket = null; - } - - // Another frequent repetition - public static int readLine(InputStream in, byte[] b, int off, int len) - throws IOException - { - if (len <= 0) { - return 0; - } - int count = 0, c; - - while ((c = in.read()) != -1) { - b[off++] = (byte)c; - count++; - if (c == '\n' || count == len) { - break; - } - } - return count > 0 ? count : -1; - } - - - // Usefull stuff - avoid having it replicated everywhere - public static void shutdownInput(Socket socket) - throws IOException - { - try { - InputStream is = socket.getInputStream(); - int available = is.available (); - int count=0; - - // XXX on JDK 1.3 just socket.shutdownInput () which - // was added just to deal with such issues. - - // skip any unread (bogus) bytes - while (available > 0 && count++ < MAX_SHUTDOWN_TRIES) { - is.skip (available); - available = is.available(); - } - }catch(NullPointerException npe) { - // do nothing - we are just cleaning up, this is - // a workaround for Netscape \n\r in POST - it is supposed - // to be ignored - } - } -} - - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; + +/** + * + */ +public class TcpConnection { // implements Endpoint { + /** + * Maxium number of times to clear the socket input buffer. + */ + static int MAX_SHUTDOWN_TRIES=20; + + public TcpConnection() { + } + + // -------------------- Properties -------------------- + + PoolTcpEndpoint endpoint; + Socket socket; + + public static void setMaxShutdownTries(int mst) { + MAX_SHUTDOWN_TRIES = mst; + } + public void setEndpoint(PoolTcpEndpoint endpoint) { + this.endpoint = endpoint; + } + + public PoolTcpEndpoint getEndpoint() { + return endpoint; + } + + public void setSocket(Socket socket) { + this.socket=socket; + } + + public Socket getSocket() { + return socket; + } + + public void recycle() { + endpoint = null; + socket = null; + } + + // Another frequent repetition + public static int readLine(InputStream in, byte[] b, int off, int len) + throws IOException + { + if (len <= 0) { + return 0; + } + int count = 0, c; + + while ((c = in.read()) != -1) { + b[off++] = (byte)c; + count++; + if (c == '\n' || count == len) { + break; + } + } + return count > 0 ? count : -1; + } + + + // Usefull stuff - avoid having it replicated everywhere + public static void shutdownInput(Socket socket) + throws IOException + { + try { + InputStream is = socket.getInputStream(); + int available = is.available (); + int count=0; + + // XXX on JDK 1.3 just socket.shutdownInput () which + // was added just to deal with such issues. + + // skip any unread (bogus) bytes + while (available > 0 && count++ < MAX_SHUTDOWN_TRIES) { + is.skip (available); + available = is.available(); + } + }catch(NullPointerException npe) { + // do nothing - we are just cleaning up, this is + // a workaround for Netscape \n\r in POST - it is supposed + // to be ignored + } + } +} + + diff --git a/java/org/apache/tomcat/util/net/TcpConnectionHandler.java b/java/org/apache/tomcat/util/net/TcpConnectionHandler.java index 81ee0fae0..f2e6008b6 100644 --- a/java/org/apache/tomcat/util/net/TcpConnectionHandler.java +++ b/java/org/apache/tomcat/util/net/TcpConnectionHandler.java @@ -1,65 +1,65 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - - -/** - * This interface will be implemented by any object that - * uses TcpConnections. It is supported by the pool tcp - * connection manager and should be supported by future - * managers. - * The goal is to decouple the connection handler from - * the thread, socket and pooling complexity. - */ -public interface TcpConnectionHandler { - - /** Add informations about the a "controler" object - * specific to the server. In tomcat it will be a - * ContextManager. - * @deprecated This has nothing to do with TcpHandling, - * was used as a workaround - */ - public void setServer(Object manager); - - - /** Used to pass config informations to the handler. - * - * @deprecated This has nothing to do with Tcp, - * was used as a workaround. - */ - public void setAttribute(String name, Object value ); - - /** Called before the call to processConnection. - * If the thread is reused, init() should be called once per thread. - * - * It may look strange, but it's a _very_ good way to avoid synchronized - * methods and keep per thread data. - * - * Assert: the object returned from init() will be passed to - * all processConnection() methods happening in the same thread. - * - */ - public Object[] init( ); - - /** - * Assert: connection!=null - * Assert: connection.getSocket() != null - * Assert: thData != null and is the result of calling init() - * Assert: thData is preserved per Thread. - */ - public void processConnection(TcpConnection connection, Object thData[]); -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + + +/** + * This interface will be implemented by any object that + * uses TcpConnections. It is supported by the pool tcp + * connection manager and should be supported by future + * managers. + * The goal is to decouple the connection handler from + * the thread, socket and pooling complexity. + */ +public interface TcpConnectionHandler { + + /** Add informations about the a "controler" object + * specific to the server. In tomcat it will be a + * ContextManager. + * @deprecated This has nothing to do with TcpHandling, + * was used as a workaround + */ + public void setServer(Object manager); + + + /** Used to pass config informations to the handler. + * + * @deprecated This has nothing to do with Tcp, + * was used as a workaround. + */ + public void setAttribute(String name, Object value ); + + /** Called before the call to processConnection. + * If the thread is reused, init() should be called once per thread. + * + * It may look strange, but it's a _very_ good way to avoid synchronized + * methods and keep per thread data. + * + * Assert: the object returned from init() will be passed to + * all processConnection() methods happening in the same thread. + * + */ + public Object[] init( ); + + /** + * Assert: connection!=null + * Assert: connection.getSocket() != null + * Assert: thData != null and is the result of calling init() + * Assert: thData is preserved per Thread. + */ + public void processConnection(TcpConnection connection, Object thData[]); +} diff --git a/java/org/apache/tomcat/util/net/URL.java b/java/org/apache/tomcat/util/net/URL.java index 24e5ef077..f6e6f1837 100644 --- a/java/org/apache/tomcat/util/net/URL.java +++ b/java/org/apache/tomcat/util/net/URL.java @@ -1,731 +1,731 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net; - - -import java.io.Serializable; -import java.net.MalformedURLException; - - -/** - *

        URL is designed to provide public APIs for parsing - * and synthesizing Uniform Resource Locators as similar as possible to the - * APIs of java.net.URL, but without the ability to open a - * stream or connection. One of the consequences of this is that you can - * construct URLs for protocols for which a URLStreamHandler is not - * available (such as an "https" URL when JSSE is not installed).

        - * - *

        WARNING - This class assumes that the string - * representation of a URL conforms to the spec argument - * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax": - *

        - *   <scheme>//<authority><path>?<query>#<fragment>
        - * 

        - * - *

        FIXME - This class really ought to end up in a Commons - * package someplace.

        - * - * @author Craig R. McClanahan - * @version $Revision: 299472 $ $Date: 2004-06-20 02:08:15 +0200 (dim., 20 juin 2004) $ - */ - -public final class URL implements Serializable { - - - // ----------------------------------------------------------- Constructors - - - /** - * Create a URL object from the specified String representation. - * - * @param spec String representation of the URL - * - * @exception MalformedURLException if the string representation - * cannot be parsed successfully - */ - public URL(String spec) throws MalformedURLException { - - this(null, spec); - - } - - - /** - * Create a URL object by parsing a string representation relative - * to a specified context. Based on logic from JDK 1.3.1's - * java.net.URL. - * - * @param context URL against which the relative representation - * is resolved - * @param spec String representation of the URL (usually relative) - * - * @exception MalformedURLException if the string representation - * cannot be parsed successfully - */ - public URL(URL context, String spec) throws MalformedURLException { - - String original = spec; - int i, limit, c; - int start = 0; - String newProtocol = null; - boolean aRef = false; - - try { - - // Eliminate leading and trailing whitespace - limit = spec.length(); - while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { - limit--; - } - while ((start < limit) && (spec.charAt(start) <= ' ')) { - start++; - } - - // If the string representation starts with "url:", skip it - if (spec.regionMatches(true, start, "url:", 0, 4)) { - start += 4; - } - - // Is this a ref relative to the context URL? - if ((start < spec.length()) && (spec.charAt(start) == '#')) { - aRef = true; - } - - // Parse out the new protocol - for (i = start; !aRef && (i < limit) ; i++) { - c = spec.charAt(i); - if (c == ':') { - String s = spec.substring(start, i).toLowerCase(); - // Assume all protocols are valid - newProtocol = s; - start = i + 1; - break; - } else if( c == '#' ) { - aRef = true; - } else if( !isSchemeChar((char)c) ) { - break; - } - } - - // Only use our context if the protocols match - protocol = newProtocol; - if ((context != null) && ((newProtocol == null) || - newProtocol.equalsIgnoreCase(context.getProtocol()))) { - // If the context is a hierarchical URL scheme and the spec - // contains a matching scheme then maintain backwards - // compatibility and treat it as if the spec didn't contain - // the scheme; see 5.2.3 of RFC2396 - if ((context.getPath() != null) && - (context.getPath().startsWith("/"))) - newProtocol = null; - if (newProtocol == null) { - protocol = context.getProtocol(); - authority = context.getAuthority(); - userInfo = context.getUserInfo(); - host = context.getHost(); - port = context.getPort(); - file = context.getFile(); - int question = file.lastIndexOf("?"); - if (question < 0) - path = file; - else - path = file.substring(0, question); - } - } - - if (protocol == null) - throw new MalformedURLException("no protocol: " + original); - - // Parse out any ref portion of the spec - i = spec.indexOf('#', start); - if (i >= 0) { - ref = spec.substring(i + 1, limit); - limit = i; - } - - // Parse the remainder of the spec in a protocol-specific fashion - parse(spec, start, limit); - if (context != null) - normalize(); - - - } catch (MalformedURLException e) { - throw e; - } catch (Exception e) { - throw new MalformedURLException(e.toString()); - } - - } - - - - - - /** - * Create a URL object from the specified components. The default port - * number for the specified protocol will be used. - * - * @param protocol Name of the protocol to use - * @param host Name of the host addressed by this protocol - * @param file Filename on the specified host - * - * @exception MalformedURLException is never thrown, but present for - * compatible APIs - */ - public URL(String protocol, String host, String file) - throws MalformedURLException { - - this(protocol, host, -1, file); - - } - - - /** - * Create a URL object from the specified components. Specifying a port - * number of -1 indicates that the URL should use the default port for - * that protocol. Based on logic from JDK 1.3.1's - * java.net.URL. - * - * @param protocol Name of the protocol to use - * @param host Name of the host addressed by this protocol - * @param port Port number, or -1 for the default port for this protocol - * @param file Filename on the specified host - * - * @exception MalformedURLException is never thrown, but present for - * compatible APIs - */ - public URL(String protocol, String host, int port, String file) - throws MalformedURLException { - - this.protocol = protocol; - this.host = host; - this.port = port; - - int hash = file.indexOf('#'); - this.file = hash < 0 ? file : file.substring(0, hash); - this.ref = hash < 0 ? null : file.substring(hash + 1); - int question = file.lastIndexOf('?'); - if (question >= 0) { - query = file.substring(question + 1); - path = file.substring(0, question); - } else - path = file; - - if ((host != null) && (host.length() > 0)) - authority = (port == -1) ? host : host + ":" + port; - - } - - - // ----------------------------------------------------- Instance Variables - - - /** - * The authority part of the URL. - */ - private String authority = null; - - - /** - * The filename part of the URL. - */ - private String file = null; - - - /** - * The host name part of the URL. - */ - private String host = null; - - - /** - * The path part of the URL. - */ - private String path = null; - - - /** - * The port number part of the URL. - */ - private int port = -1; - - - /** - * The protocol name part of the URL. - */ - private String protocol = null; - - - /** - * The query part of the URL. - */ - private String query = null; - - - /** - * The reference part of the URL. - */ - private String ref = null; - - - /** - * The user info part of the URL. - */ - private String userInfo = null; - - - // --------------------------------------------------------- Public Methods - - - /** - * Compare two URLs for equality. The result is true if and - * only if the argument is not null, and is a URL object - * that represents the same URL as this object. Two - * URLs are equal if they have the same protocol and - * reference the same host, the same port number on the host, - * and the same file and anchor on the host. - * - * @param obj The URL to compare against - */ - public boolean equals(Object obj) { - - if (obj == null) - return (false); - if (!(obj instanceof URL)) - return (false); - URL other = (URL) obj; - if (!sameFile(other)) - return (false); - return (compare(ref, other.getRef())); - - } - - - /** - * Return the authority part of the URL. - */ - public String getAuthority() { - - return (this.authority); - - } - - - /** - * Return the filename part of the URL. NOTE - For - * compatibility with java.net.URL, this value includes - * the query string if there was one. For just the path portion, - * call getPath() instead. - */ - public String getFile() { - - if (file == null) - return (""); - return (this.file); - - } - - - /** - * Return the host name part of the URL. - */ - public String getHost() { - - return (this.host); - - } - - - /** - * Return the path part of the URL. - */ - public String getPath() { - - if (this.path == null) - return (""); - return (this.path); - - } - - - /** - * Return the port number part of the URL. - */ - public int getPort() { - - return (this.port); - - } - - - /** - * Return the protocol name part of the URL. - */ - public String getProtocol() { - - return (this.protocol); - - } - - - /** - * Return the query part of the URL. - */ - public String getQuery() { - - return (this.query); - - } - - - /** - * Return the reference part of the URL. - */ - public String getRef() { - - return (this.ref); - - } - - - /** - * Return the user info part of the URL. - */ - public String getUserInfo() { - - return (this.userInfo); - - } - - - /** - * Normalize the path (and therefore file) - * portions of this URL. - *

        - * NOTE - This method is not part of the public API - * of java.net.URL, but is provided as a value added - * service of this implementation. - * - * @exception MalformedURLException if a normalization error occurs, - * such as trying to move about the hierarchical root - */ - public void normalize() throws MalformedURLException { - - // Special case for null path - if (path == null) { - if (query != null) - file = "?" + query; - else - file = ""; - return; - } - - // Create a place for the normalized path - String normalized = path; - if (normalized.equals("/.")) { - path = "/"; - if (query != null) - file = path + "?" + query; - else - file = path; - return; - } - - // Normalize the slashes and add leading slash if necessary - if (normalized.indexOf('\\') >= 0) - normalized = normalized.replace('\\', '/'); - if (!normalized.startsWith("/")) - normalized = "/" + normalized; - - // Resolve occurrences of "//" in the normalized path - while (true) { - int index = normalized.indexOf("//"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 1); - } - - // Resolve occurrences of "/./" in the normalized path - while (true) { - int index = normalized.indexOf("/./"); - if (index < 0) - break; - normalized = normalized.substring(0, index) + - normalized.substring(index + 2); - } - - // Resolve occurrences of "/../" in the normalized path - while (true) { - int index = normalized.indexOf("/../"); - if (index < 0) - break; - if (index == 0) - throw new MalformedURLException - ("Invalid relative URL reference"); - int index2 = normalized.lastIndexOf('/', index - 1); - normalized = normalized.substring(0, index2) + - normalized.substring(index + 3); - } - - // Resolve occurrences of "/." at the end of the normalized path - if (normalized.endsWith("/.")) - normalized = normalized.substring(0, normalized.length() - 1); - - // Resolve occurrences of "/.." at the end of the normalized path - if (normalized.endsWith("/..")) { - int index = normalized.length() - 3; - int index2 = normalized.lastIndexOf('/', index - 1); - if (index2 < 0) - throw new MalformedURLException - ("Invalid relative URL reference"); - normalized = normalized.substring(0, index2 + 1); - } - - // Return the normalized path that we have completed - path = normalized; - if (query != null) - file = path + "?" + query; - else - file = path; - - } - - - /** - * Compare two URLs, excluding the "ref" fields. Returns true - * if this URL and the other argument both refer - * to the same resource. The two URLs might not both contain - * the same anchor. - */ - public boolean sameFile(URL other) { - - if (!compare(protocol, other.getProtocol())) - return (false); - if (!compare(host, other.getHost())) - return (false); - if (port != other.getPort()) - return (false); - if (!compare(file, other.getFile())) - return (false); - return (true); - - } - - - /** - * Return a string representation of this URL. This follow the rules in - * RFC 2396, Section 5.2, Step 7. - */ - public String toExternalForm() { - - StringBuffer sb = new StringBuffer(); - if (protocol != null) { - sb.append(protocol); - sb.append(":"); - } - if (authority != null) { - sb.append("//"); - sb.append(authority); - } - if (path != null) - sb.append(path); - if (query != null) { - sb.append('?'); - sb.append(query); - } - if (ref != null) { - sb.append('#'); - sb.append(ref); - } - return (sb.toString()); - - } - - - /** - * Return a string representation of this object. - */ - public String toString() { - - StringBuffer sb = new StringBuffer("URL["); - sb.append("authority="); - sb.append(authority); - sb.append(", file="); - sb.append(file); - sb.append(", host="); - sb.append(host); - sb.append(", port="); - sb.append(port); - sb.append(", protocol="); - sb.append(protocol); - sb.append(", query="); - sb.append(query); - sb.append(", ref="); - sb.append(ref); - sb.append(", userInfo="); - sb.append(userInfo); - sb.append("]"); - return (sb.toString()); - - // return (toExternalForm()); - - } - - - // -------------------------------------------------------- Private Methods - - - /** - * Compare to String values for equality, taking appropriate care if one - * or both of the values are null. - * - * @param first First string - * @param second Second string - */ - private boolean compare(String first, String second) { - - if (first == null) { - if (second == null) - return (true); - else - return (false); - } else { - if (second == null) - return (false); - else - return (first.equals(second)); - } - - } - - - /** - * Parse the specified portion of the string representation of a URL, - * assuming that it has a format similar to that for http. - * - *

        FIXME - This algorithm can undoubtedly be optimized - * for performance. However, that needs to wait until after sufficient - * unit tests are implemented to guarantee correct behavior with no - * regressions.

        - * - * @param spec String representation being parsed - * @param start Starting offset, which will be just after the ':' (if - * there is one) that determined the protocol name - * @param limit Ending position, which will be the position of the '#' - * (if there is one) that delimited the anchor - * - * @exception MalformedURLException if a parsing error occurs - */ - private void parse(String spec, int start, int limit) - throws MalformedURLException { - - // Trim the query string (if any) off the tail end - int question = spec.lastIndexOf('?', limit - 1); - if ((question >= 0) && (question < limit)) { - query = spec.substring(question + 1, limit); - limit = question; - } else { - query = null; - } - - // Parse the authority section - if (spec.indexOf("//", start) == start) { - int pathStart = spec.indexOf("/", start + 2); - if ((pathStart >= 0) && (pathStart < limit)) { - authority = spec.substring(start + 2, pathStart); - start = pathStart; - } else { - authority = spec.substring(start + 2, limit); - start = limit; - } - if (authority.length() > 0) { - int at = authority.indexOf('@'); - if( at >= 0 ) { - userInfo = authority.substring(0,at); - } - int ipv6 = authority.indexOf('[',at+1); - int hStart = at+1; - if( ipv6 >= 0 ) { - hStart = ipv6; - ipv6 = authority.indexOf(']', ipv6); - if( ipv6 < 0 ) { - throw new MalformedURLException( - "Closing ']' not found in IPV6 address: " + authority); - } else { - at = ipv6-1; - } - } - - int colon = authority.indexOf(':', at+1); - if (colon >= 0) { - try { - port = - Integer.parseInt(authority.substring(colon + 1)); - } catch (NumberFormatException e) { - throw new MalformedURLException(e.toString()); - } - host = authority.substring(hStart, colon); - } else { - host = authority.substring(hStart); - port = -1; - } - } - } - - // Parse the path section - if (spec.indexOf("/", start) == start) { // Absolute path - path = spec.substring(start, limit); - if (query != null) - file = path + "?" + query; - else - file = path; - return; - } - - // Resolve relative path against our context's file - if (path == null) { - if (query != null) - file = "?" + query; - else - file = null; - return; - } - if (!path.startsWith("/")) - throw new MalformedURLException - ("Base path does not start with '/'"); - if (!path.endsWith("/")) - path += "/../"; - path += spec.substring(start, limit); - if (query != null) - file = path + "?" + query; - else - file = path; - return; - - } - - /** - * Determine if the character is allowed in the scheme of a URI. - * See RFC 2396, Section 3.1 - */ - public static boolean isSchemeChar(char c) { - return Character.isLetterOrDigit(c) || - c == '+' || c == '-' || c == '.'; - } - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net; + + +import java.io.Serializable; +import java.net.MalformedURLException; + + +/** + *

        URL is designed to provide public APIs for parsing + * and synthesizing Uniform Resource Locators as similar as possible to the + * APIs of java.net.URL, but without the ability to open a + * stream or connection. One of the consequences of this is that you can + * construct URLs for protocols for which a URLStreamHandler is not + * available (such as an "https" URL when JSSE is not installed).

        + * + *

        WARNING - This class assumes that the string + * representation of a URL conforms to the spec argument + * as described in RFC 2396 "Uniform Resource Identifiers: Generic Syntax": + *

        + *   <scheme>//<authority><path>?<query>#<fragment>
        + * 

        + * + *

        FIXME - This class really ought to end up in a Commons + * package someplace.

        + * + * @author Craig R. McClanahan + * @version $Revision: 299472 $ $Date: 2004-06-20 02:08:15 +0200 (dim., 20 juin 2004) $ + */ + +public final class URL implements Serializable { + + + // ----------------------------------------------------------- Constructors + + + /** + * Create a URL object from the specified String representation. + * + * @param spec String representation of the URL + * + * @exception MalformedURLException if the string representation + * cannot be parsed successfully + */ + public URL(String spec) throws MalformedURLException { + + this(null, spec); + + } + + + /** + * Create a URL object by parsing a string representation relative + * to a specified context. Based on logic from JDK 1.3.1's + * java.net.URL. + * + * @param context URL against which the relative representation + * is resolved + * @param spec String representation of the URL (usually relative) + * + * @exception MalformedURLException if the string representation + * cannot be parsed successfully + */ + public URL(URL context, String spec) throws MalformedURLException { + + String original = spec; + int i, limit, c; + int start = 0; + String newProtocol = null; + boolean aRef = false; + + try { + + // Eliminate leading and trailing whitespace + limit = spec.length(); + while ((limit > 0) && (spec.charAt(limit - 1) <= ' ')) { + limit--; + } + while ((start < limit) && (spec.charAt(start) <= ' ')) { + start++; + } + + // If the string representation starts with "url:", skip it + if (spec.regionMatches(true, start, "url:", 0, 4)) { + start += 4; + } + + // Is this a ref relative to the context URL? + if ((start < spec.length()) && (spec.charAt(start) == '#')) { + aRef = true; + } + + // Parse out the new protocol + for (i = start; !aRef && (i < limit) ; i++) { + c = spec.charAt(i); + if (c == ':') { + String s = spec.substring(start, i).toLowerCase(); + // Assume all protocols are valid + newProtocol = s; + start = i + 1; + break; + } else if( c == '#' ) { + aRef = true; + } else if( !isSchemeChar((char)c) ) { + break; + } + } + + // Only use our context if the protocols match + protocol = newProtocol; + if ((context != null) && ((newProtocol == null) || + newProtocol.equalsIgnoreCase(context.getProtocol()))) { + // If the context is a hierarchical URL scheme and the spec + // contains a matching scheme then maintain backwards + // compatibility and treat it as if the spec didn't contain + // the scheme; see 5.2.3 of RFC2396 + if ((context.getPath() != null) && + (context.getPath().startsWith("/"))) + newProtocol = null; + if (newProtocol == null) { + protocol = context.getProtocol(); + authority = context.getAuthority(); + userInfo = context.getUserInfo(); + host = context.getHost(); + port = context.getPort(); + file = context.getFile(); + int question = file.lastIndexOf("?"); + if (question < 0) + path = file; + else + path = file.substring(0, question); + } + } + + if (protocol == null) + throw new MalformedURLException("no protocol: " + original); + + // Parse out any ref portion of the spec + i = spec.indexOf('#', start); + if (i >= 0) { + ref = spec.substring(i + 1, limit); + limit = i; + } + + // Parse the remainder of the spec in a protocol-specific fashion + parse(spec, start, limit); + if (context != null) + normalize(); + + + } catch (MalformedURLException e) { + throw e; + } catch (Exception e) { + throw new MalformedURLException(e.toString()); + } + + } + + + + + + /** + * Create a URL object from the specified components. The default port + * number for the specified protocol will be used. + * + * @param protocol Name of the protocol to use + * @param host Name of the host addressed by this protocol + * @param file Filename on the specified host + * + * @exception MalformedURLException is never thrown, but present for + * compatible APIs + */ + public URL(String protocol, String host, String file) + throws MalformedURLException { + + this(protocol, host, -1, file); + + } + + + /** + * Create a URL object from the specified components. Specifying a port + * number of -1 indicates that the URL should use the default port for + * that protocol. Based on logic from JDK 1.3.1's + * java.net.URL. + * + * @param protocol Name of the protocol to use + * @param host Name of the host addressed by this protocol + * @param port Port number, or -1 for the default port for this protocol + * @param file Filename on the specified host + * + * @exception MalformedURLException is never thrown, but present for + * compatible APIs + */ + public URL(String protocol, String host, int port, String file) + throws MalformedURLException { + + this.protocol = protocol; + this.host = host; + this.port = port; + + int hash = file.indexOf('#'); + this.file = hash < 0 ? file : file.substring(0, hash); + this.ref = hash < 0 ? null : file.substring(hash + 1); + int question = file.lastIndexOf('?'); + if (question >= 0) { + query = file.substring(question + 1); + path = file.substring(0, question); + } else + path = file; + + if ((host != null) && (host.length() > 0)) + authority = (port == -1) ? host : host + ":" + port; + + } + + + // ----------------------------------------------------- Instance Variables + + + /** + * The authority part of the URL. + */ + private String authority = null; + + + /** + * The filename part of the URL. + */ + private String file = null; + + + /** + * The host name part of the URL. + */ + private String host = null; + + + /** + * The path part of the URL. + */ + private String path = null; + + + /** + * The port number part of the URL. + */ + private int port = -1; + + + /** + * The protocol name part of the URL. + */ + private String protocol = null; + + + /** + * The query part of the URL. + */ + private String query = null; + + + /** + * The reference part of the URL. + */ + private String ref = null; + + + /** + * The user info part of the URL. + */ + private String userInfo = null; + + + // --------------------------------------------------------- Public Methods + + + /** + * Compare two URLs for equality. The result is true if and + * only if the argument is not null, and is a URL object + * that represents the same URL as this object. Two + * URLs are equal if they have the same protocol and + * reference the same host, the same port number on the host, + * and the same file and anchor on the host. + * + * @param obj The URL to compare against + */ + public boolean equals(Object obj) { + + if (obj == null) + return (false); + if (!(obj instanceof URL)) + return (false); + URL other = (URL) obj; + if (!sameFile(other)) + return (false); + return (compare(ref, other.getRef())); + + } + + + /** + * Return the authority part of the URL. + */ + public String getAuthority() { + + return (this.authority); + + } + + + /** + * Return the filename part of the URL. NOTE - For + * compatibility with java.net.URL, this value includes + * the query string if there was one. For just the path portion, + * call getPath() instead. + */ + public String getFile() { + + if (file == null) + return (""); + return (this.file); + + } + + + /** + * Return the host name part of the URL. + */ + public String getHost() { + + return (this.host); + + } + + + /** + * Return the path part of the URL. + */ + public String getPath() { + + if (this.path == null) + return (""); + return (this.path); + + } + + + /** + * Return the port number part of the URL. + */ + public int getPort() { + + return (this.port); + + } + + + /** + * Return the protocol name part of the URL. + */ + public String getProtocol() { + + return (this.protocol); + + } + + + /** + * Return the query part of the URL. + */ + public String getQuery() { + + return (this.query); + + } + + + /** + * Return the reference part of the URL. + */ + public String getRef() { + + return (this.ref); + + } + + + /** + * Return the user info part of the URL. + */ + public String getUserInfo() { + + return (this.userInfo); + + } + + + /** + * Normalize the path (and therefore file) + * portions of this URL. + *

        + * NOTE - This method is not part of the public API + * of java.net.URL, but is provided as a value added + * service of this implementation. + * + * @exception MalformedURLException if a normalization error occurs, + * such as trying to move about the hierarchical root + */ + public void normalize() throws MalformedURLException { + + // Special case for null path + if (path == null) { + if (query != null) + file = "?" + query; + else + file = ""; + return; + } + + // Create a place for the normalized path + String normalized = path; + if (normalized.equals("/.")) { + path = "/"; + if (query != null) + file = path + "?" + query; + else + file = path; + return; + } + + // Normalize the slashes and add leading slash if necessary + if (normalized.indexOf('\\') >= 0) + normalized = normalized.replace('\\', '/'); + if (!normalized.startsWith("/")) + normalized = "/" + normalized; + + // Resolve occurrences of "//" in the normalized path + while (true) { + int index = normalized.indexOf("//"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 1); + } + + // Resolve occurrences of "/./" in the normalized path + while (true) { + int index = normalized.indexOf("/./"); + if (index < 0) + break; + normalized = normalized.substring(0, index) + + normalized.substring(index + 2); + } + + // Resolve occurrences of "/../" in the normalized path + while (true) { + int index = normalized.indexOf("/../"); + if (index < 0) + break; + if (index == 0) + throw new MalformedURLException + ("Invalid relative URL reference"); + int index2 = normalized.lastIndexOf('/', index - 1); + normalized = normalized.substring(0, index2) + + normalized.substring(index + 3); + } + + // Resolve occurrences of "/." at the end of the normalized path + if (normalized.endsWith("/.")) + normalized = normalized.substring(0, normalized.length() - 1); + + // Resolve occurrences of "/.." at the end of the normalized path + if (normalized.endsWith("/..")) { + int index = normalized.length() - 3; + int index2 = normalized.lastIndexOf('/', index - 1); + if (index2 < 0) + throw new MalformedURLException + ("Invalid relative URL reference"); + normalized = normalized.substring(0, index2 + 1); + } + + // Return the normalized path that we have completed + path = normalized; + if (query != null) + file = path + "?" + query; + else + file = path; + + } + + + /** + * Compare two URLs, excluding the "ref" fields. Returns true + * if this URL and the other argument both refer + * to the same resource. The two URLs might not both contain + * the same anchor. + */ + public boolean sameFile(URL other) { + + if (!compare(protocol, other.getProtocol())) + return (false); + if (!compare(host, other.getHost())) + return (false); + if (port != other.getPort()) + return (false); + if (!compare(file, other.getFile())) + return (false); + return (true); + + } + + + /** + * Return a string representation of this URL. This follow the rules in + * RFC 2396, Section 5.2, Step 7. + */ + public String toExternalForm() { + + StringBuffer sb = new StringBuffer(); + if (protocol != null) { + sb.append(protocol); + sb.append(":"); + } + if (authority != null) { + sb.append("//"); + sb.append(authority); + } + if (path != null) + sb.append(path); + if (query != null) { + sb.append('?'); + sb.append(query); + } + if (ref != null) { + sb.append('#'); + sb.append(ref); + } + return (sb.toString()); + + } + + + /** + * Return a string representation of this object. + */ + public String toString() { + + StringBuffer sb = new StringBuffer("URL["); + sb.append("authority="); + sb.append(authority); + sb.append(", file="); + sb.append(file); + sb.append(", host="); + sb.append(host); + sb.append(", port="); + sb.append(port); + sb.append(", protocol="); + sb.append(protocol); + sb.append(", query="); + sb.append(query); + sb.append(", ref="); + sb.append(ref); + sb.append(", userInfo="); + sb.append(userInfo); + sb.append("]"); + return (sb.toString()); + + // return (toExternalForm()); + + } + + + // -------------------------------------------------------- Private Methods + + + /** + * Compare to String values for equality, taking appropriate care if one + * or both of the values are null. + * + * @param first First string + * @param second Second string + */ + private boolean compare(String first, String second) { + + if (first == null) { + if (second == null) + return (true); + else + return (false); + } else { + if (second == null) + return (false); + else + return (first.equals(second)); + } + + } + + + /** + * Parse the specified portion of the string representation of a URL, + * assuming that it has a format similar to that for http. + * + *

        FIXME - This algorithm can undoubtedly be optimized + * for performance. However, that needs to wait until after sufficient + * unit tests are implemented to guarantee correct behavior with no + * regressions.

        + * + * @param spec String representation being parsed + * @param start Starting offset, which will be just after the ':' (if + * there is one) that determined the protocol name + * @param limit Ending position, which will be the position of the '#' + * (if there is one) that delimited the anchor + * + * @exception MalformedURLException if a parsing error occurs + */ + private void parse(String spec, int start, int limit) + throws MalformedURLException { + + // Trim the query string (if any) off the tail end + int question = spec.lastIndexOf('?', limit - 1); + if ((question >= 0) && (question < limit)) { + query = spec.substring(question + 1, limit); + limit = question; + } else { + query = null; + } + + // Parse the authority section + if (spec.indexOf("//", start) == start) { + int pathStart = spec.indexOf("/", start + 2); + if ((pathStart >= 0) && (pathStart < limit)) { + authority = spec.substring(start + 2, pathStart); + start = pathStart; + } else { + authority = spec.substring(start + 2, limit); + start = limit; + } + if (authority.length() > 0) { + int at = authority.indexOf('@'); + if( at >= 0 ) { + userInfo = authority.substring(0,at); + } + int ipv6 = authority.indexOf('[',at+1); + int hStart = at+1; + if( ipv6 >= 0 ) { + hStart = ipv6; + ipv6 = authority.indexOf(']', ipv6); + if( ipv6 < 0 ) { + throw new MalformedURLException( + "Closing ']' not found in IPV6 address: " + authority); + } else { + at = ipv6-1; + } + } + + int colon = authority.indexOf(':', at+1); + if (colon >= 0) { + try { + port = + Integer.parseInt(authority.substring(colon + 1)); + } catch (NumberFormatException e) { + throw new MalformedURLException(e.toString()); + } + host = authority.substring(hStart, colon); + } else { + host = authority.substring(hStart); + port = -1; + } + } + } + + // Parse the path section + if (spec.indexOf("/", start) == start) { // Absolute path + path = spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + } + + // Resolve relative path against our context's file + if (path == null) { + if (query != null) + file = "?" + query; + else + file = null; + return; + } + if (!path.startsWith("/")) + throw new MalformedURLException + ("Base path does not start with '/'"); + if (!path.endsWith("/")) + path += "/../"; + path += spec.substring(start, limit); + if (query != null) + file = path + "?" + query; + else + file = path; + return; + + } + + /** + * Determine if the character is allowed in the scheme of a URI. + * See RFC 2396, Section 3.1 + */ + public static boolean isSchemeChar(char c) { + return Character.isLetterOrDigit(c) || + c == '+' || c == '-' || c == '.'; + } + +} diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java b/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java index 1d8aaf778..f648520b3 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEFactory.java @@ -1,49 +1,49 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.jsse; - -import java.net.Socket; - -import javax.net.ssl.SSLSocket; - -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.net.ServerSocketFactory; - -/** - * Factory interface to construct components based on the JSSE version - * in use. - * - * @author Bill Barker - */ - -public class JSSEFactory { - - /** - * Returns the ServerSocketFactory to use. - */ - public ServerSocketFactory getSocketFactory() { - return new JSSESocketFactory(); - } - - /** - * returns the SSLSupport attached to this socket. - */ - public SSLSupport getSSLSupport(Socket socket) { - return new JSSESupport((SSLSocket)socket); - } - -}; +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; + +import javax.net.ssl.SSLSocket; + +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.ServerSocketFactory; + +/** + * Factory interface to construct components based on the JSSE version + * in use. + * + * @author Bill Barker + */ + +public class JSSEFactory { + + /** + * Returns the ServerSocketFactory to use. + */ + public ServerSocketFactory getSocketFactory() { + return new JSSESocketFactory(); + } + + /** + * returns the SSLSupport attached to this socket. + */ + public SSLSupport getSSLSupport(Socket socket) { + return new JSSESupport((SSLSocket)socket); + } + +}; diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java index 1102ab4a5..d42162601 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEImplementation.java @@ -1,61 +1,61 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.jsse; - -import java.net.Socket; - -import org.apache.tomcat.util.net.SSLImplementation; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.net.ServerSocketFactory; - -/* JSSEImplementation: - - Concrete implementation class for JSSE - - @author EKR -*/ - -public class JSSEImplementation extends SSLImplementation -{ - static final String SSLSocketClass = "javax.net.ssl.SSLSocket"; - - static org.apache.commons.logging.Log logger = - org.apache.commons.logging.LogFactory.getLog(JSSEImplementation.class); - - private JSSEFactory factory = null; - - public JSSEImplementation() throws ClassNotFoundException { - // Check to see if JSSE is floating around somewhere - Class.forName(SSLSocketClass); - factory = new JSSEFactory(); - } - - - public String getImplementationName(){ - return "JSSE"; - } - - public ServerSocketFactory getServerSocketFactory() { - ServerSocketFactory ssf = factory.getSocketFactory(); - return ssf; - } - - public SSLSupport getSSLSupport(Socket s) { - SSLSupport ssls = factory.getSSLSupport(s); - return ssls; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; + +import org.apache.tomcat.util.net.SSLImplementation; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.ServerSocketFactory; + +/* JSSEImplementation: + + Concrete implementation class for JSSE + + @author EKR +*/ + +public class JSSEImplementation extends SSLImplementation +{ + static final String SSLSocketClass = "javax.net.ssl.SSLSocket"; + + static org.apache.commons.logging.Log logger = + org.apache.commons.logging.LogFactory.getLog(JSSEImplementation.class); + + private JSSEFactory factory = null; + + public JSSEImplementation() throws ClassNotFoundException { + // Check to see if JSSE is floating around somewhere + Class.forName(SSLSocketClass); + factory = new JSSEFactory(); + } + + + public String getImplementationName(){ + return "JSSE"; + } + + public ServerSocketFactory getServerSocketFactory() { + ServerSocketFactory ssf = factory.getSocketFactory(); + return ssf; + } + + public SSLSupport getSSLSupport(Socket s) { + SSLSupport ssls = factory.getSSLSupport(s); + return ssls; + } +} diff --git a/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java b/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java index 4c29c660f..5034f593b 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSEKeyManager.java @@ -1,143 +1,143 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.jsse; - -import java.net.Socket; -import java.security.Principal; -import java.security.PrivateKey; -import java.security.cert.X509Certificate; -import javax.net.ssl.X509KeyManager; - -/** - * X509KeyManager which allows selection of a specific keypair and certificate - * chain (identified by their keystore alias name) to be used by the server to - * authenticate itself to SSL clients. - * - * @author Jan Luehe - */ -public final class JSSEKeyManager implements X509KeyManager { - - private X509KeyManager delegate; - private String serverKeyAlias; - - /** - * Constructor. - * - * @param mgr The X509KeyManager used as a delegate - * @param serverKeyAlias The alias name of the server's keypair and - * supporting certificate chain - */ - public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) { - this.delegate = mgr; - this.serverKeyAlias = serverKeyAlias; - } - - /** - * Choose an alias to authenticate the client side of a secure socket, - * given the public key type and the list of certificate issuer authorities - * recognized by the peer (if any). - * - * @param keyType The key algorithm type name(s), ordered with the - * most-preferred key type first - * @param issuers The list of acceptable CA issuer subject names, or null - * if it does not matter which issuers are used - * @param socket The socket to be used for this connection. This parameter - * can be null, in which case this method will return the most generic - * alias to use - * - * @return The alias name for the desired key, or null if there are no - * matches - */ - public String chooseClientAlias(String[] keyType, Principal[] issuers, - Socket socket) { - return delegate.chooseClientAlias(keyType, issuers, socket); - } - - /** - * Returns this key manager's server key alias that was provided in the - * constructor. - * - * @param keyType The key algorithm type name (ignored) - * @param issuers The list of acceptable CA issuer subject names, or null - * if it does not matter which issuers are used (ignored) - * @param socket The socket to be used for this connection. This parameter - * can be null, in which case this method will return the most generic - * alias to use (ignored) - * - * @return Alias name for the desired key - */ - public String chooseServerAlias(String keyType, Principal[] issuers, - Socket socket) { - return serverKeyAlias; - } - - /** - * Returns the certificate chain associated with the given alias. - * - * @param alias The alias name - * - * @return Certificate chain (ordered with the user's certificate first - * and the root certificate authority last), or null if the alias can't be - * found - */ - public X509Certificate[] getCertificateChain(String alias) { - return delegate.getCertificateChain(alias); - } - - /** - * Get the matching aliases for authenticating the client side of a secure - * socket, given the public key type and the list of certificate issuer - * authorities recognized by the peer (if any). - * - * @param keyType The key algorithm type name - * @param issuers The list of acceptable CA issuer subject names, or null - * if it does not matter which issuers are used - * - * @return Array of the matching alias names, or null if there were no - * matches - */ - public String[] getClientAliases(String keyType, Principal[] issuers) { - return delegate.getClientAliases(keyType, issuers); - } - - /** - * Get the matching aliases for authenticating the server side of a secure - * socket, given the public key type and the list of certificate issuer - * authorities recognized by the peer (if any). - * - * @param keyType The key algorithm type name - * @param issuers The list of acceptable CA issuer subject names, or null - * if it does not matter which issuers are used - * - * @return Array of the matching alias names, or null if there were no - * matches - */ - public String[] getServerAliases(String keyType, Principal[] issuers) { - return delegate.getServerAliases(keyType, issuers); - } - - /** - * Returns the key associated with the given alias. - * - * @param alias The alias name - * - * @return The requested key, or null if the alias can't be found - */ - public PrivateKey getPrivateKey(String alias) { - return delegate.getPrivateKey(alias); - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.net.Socket; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.cert.X509Certificate; +import javax.net.ssl.X509KeyManager; + +/** + * X509KeyManager which allows selection of a specific keypair and certificate + * chain (identified by their keystore alias name) to be used by the server to + * authenticate itself to SSL clients. + * + * @author Jan Luehe + */ +public final class JSSEKeyManager implements X509KeyManager { + + private X509KeyManager delegate; + private String serverKeyAlias; + + /** + * Constructor. + * + * @param mgr The X509KeyManager used as a delegate + * @param serverKeyAlias The alias name of the server's keypair and + * supporting certificate chain + */ + public JSSEKeyManager(X509KeyManager mgr, String serverKeyAlias) { + this.delegate = mgr; + this.serverKeyAlias = serverKeyAlias; + } + + /** + * Choose an alias to authenticate the client side of a secure socket, + * given the public key type and the list of certificate issuer authorities + * recognized by the peer (if any). + * + * @param keyType The key algorithm type name(s), ordered with the + * most-preferred key type first + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * @param socket The socket to be used for this connection. This parameter + * can be null, in which case this method will return the most generic + * alias to use + * + * @return The alias name for the desired key, or null if there are no + * matches + */ + public String chooseClientAlias(String[] keyType, Principal[] issuers, + Socket socket) { + return delegate.chooseClientAlias(keyType, issuers, socket); + } + + /** + * Returns this key manager's server key alias that was provided in the + * constructor. + * + * @param keyType The key algorithm type name (ignored) + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used (ignored) + * @param socket The socket to be used for this connection. This parameter + * can be null, in which case this method will return the most generic + * alias to use (ignored) + * + * @return Alias name for the desired key + */ + public String chooseServerAlias(String keyType, Principal[] issuers, + Socket socket) { + return serverKeyAlias; + } + + /** + * Returns the certificate chain associated with the given alias. + * + * @param alias The alias name + * + * @return Certificate chain (ordered with the user's certificate first + * and the root certificate authority last), or null if the alias can't be + * found + */ + public X509Certificate[] getCertificateChain(String alias) { + return delegate.getCertificateChain(alias); + } + + /** + * Get the matching aliases for authenticating the client side of a secure + * socket, given the public key type and the list of certificate issuer + * authorities recognized by the peer (if any). + * + * @param keyType The key algorithm type name + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * + * @return Array of the matching alias names, or null if there were no + * matches + */ + public String[] getClientAliases(String keyType, Principal[] issuers) { + return delegate.getClientAliases(keyType, issuers); + } + + /** + * Get the matching aliases for authenticating the server side of a secure + * socket, given the public key type and the list of certificate issuer + * authorities recognized by the peer (if any). + * + * @param keyType The key algorithm type name + * @param issuers The list of acceptable CA issuer subject names, or null + * if it does not matter which issuers are used + * + * @return Array of the matching alias names, or null if there were no + * matches + */ + public String[] getServerAliases(String keyType, Principal[] issuers) { + return delegate.getServerAliases(keyType, issuers); + } + + /** + * Returns the key associated with the given alias. + * + * @param alias The alias name + * + * @return The requested key, or null if the alias can't be found + */ + public PrivateKey getPrivateKey(String alias) { + return delegate.getPrivateKey(alias); + } +} diff --git a/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java b/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java index e99733931..8d0faaef4 100644 --- a/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java +++ b/java/org/apache/tomcat/util/net/jsse/JSSESocketFactory.java @@ -1,666 +1,666 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.jsse; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.security.KeyStore; -import java.security.SecureRandom; -import java.security.cert.CRL; -import java.security.cert.CRLException; -import java.security.cert.CertPathParameters; -import java.security.cert.CertStore; -import java.security.cert.CertStoreParameters; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.CollectionCertStoreParameters; -import java.security.cert.PKIXBuilderParameters; -import java.security.cert.X509CertSelector; -import java.util.Collection; -import java.util.Vector; - -import javax.net.ssl.CertPathTrustManagerParameters; -import javax.net.ssl.KeyManager; -import javax.net.ssl.KeyManagerFactory; -import javax.net.ssl.ManagerFactoryParameters; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLServerSocket; -import javax.net.ssl.SSLServerSocketFactory; -import javax.net.ssl.SSLSocket; -import javax.net.ssl.TrustManager; -import javax.net.ssl.TrustManagerFactory; -import javax.net.ssl.X509KeyManager; - -import org.apache.tomcat.util.res.StringManager; - -/* - 1. Make the JSSE's jars available, either as an installed - extension (copy them into jre/lib/ext) or by adding - them to the Tomcat classpath. - 2. keytool -genkey -alias tomcat -keyalg RSA - Use "changeit" as password ( this is the default we use ) - */ - -/** - * SSL server socket factory. It _requires_ a valid RSA key and - * JSSE. - * - * @author Harish Prabandham - * @author Costin Manolache - * @author Stefan Freyr Stefansson - * @author EKR -- renamed to JSSESocketFactory - * @author Jan Luehe - * @author Bill Barker - */ -public class JSSESocketFactory - extends org.apache.tomcat.util.net.ServerSocketFactory { - - private static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.net.jsse.res"); - - // defaults - static String defaultProtocol = "TLS"; - static boolean defaultClientAuth = false; - static String defaultKeystoreType = "JKS"; - private static final String defaultKeystoreFile - = System.getProperty("user.home") + "/.keystore"; - private static final String defaultKeyPass = "changeit"; - static org.apache.commons.logging.Log log = - org.apache.commons.logging.LogFactory.getLog(JSSESocketFactory.class); - - protected boolean initialized; - protected String clientAuth = "false"; - protected SSLServerSocketFactory sslProxy = null; - protected String[] enabledCiphers; - - /** - * Flag to state that we require client authentication. - */ - protected boolean requireClientAuth = false; - - /** - * Flag to state that we would like client authentication. - */ - protected boolean wantClientAuth = false; - - - public JSSESocketFactory () { - } - - public ServerSocket createSocket (int port) - throws IOException - { - if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port); - initServerSocket(socket); - return socket; - } - - public ServerSocket createSocket (int port, int backlog) - throws IOException - { - if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port, backlog); - initServerSocket(socket); - return socket; - } - - public ServerSocket createSocket (int port, int backlog, - InetAddress ifAddress) - throws IOException - { - if (!initialized) init(); - ServerSocket socket = sslProxy.createServerSocket(port, backlog, - ifAddress); - initServerSocket(socket); - return socket; - } - - public Socket acceptSocket(ServerSocket socket) - throws IOException - { - SSLSocket asock = null; - try { - asock = (SSLSocket)socket.accept(); - configureClientAuth(asock); - } catch (SSLException e){ - throw new SocketException("SSL handshake error" + e.toString()); - } - return asock; - } - - public void handshake(Socket sock) throws IOException { - ((SSLSocket)sock).startHandshake(); - } - - /* - * Determines the SSL cipher suites to be enabled. - * - * @param requestedCiphers Comma-separated list of requested ciphers - * @param supportedCiphers Array of supported ciphers - * - * @return Array of SSL cipher suites to be enabled, or null if none of the - * requested ciphers are supported - */ - protected String[] getEnabledCiphers(String requestedCiphers, - String[] supportedCiphers) { - - String[] enabledCiphers = null; - - if (requestedCiphers != null) { - Vector vec = null; - String cipher = requestedCiphers; - int index = requestedCiphers.indexOf(','); - if (index != -1) { - int fromIndex = 0; - while (index != -1) { - cipher = requestedCiphers.substring(fromIndex, index).trim(); - if (cipher.length() > 0) { - /* - * Check to see if the requested cipher is among the - * supported ciphers, i.e., may be enabled - */ - for (int i=0; supportedCiphers != null - && i 0) { - /* - * Check to see if the requested cipher is among the - * supported ciphers, i.e., may be enabled - */ - for (int i=0; supportedCiphers != null - && iPKIX is supported. - * - * @param algorithm The algorithm to get parameters for. - * @param crlf The path to the CRL file. - * @param trustStore The configured TrustStore. - * @return The parameters including the CRLs and TrustStore. - */ - protected CertPathParameters getParameters(String algorithm, - String crlf, - KeyStore trustStore) - throws Exception { - CertPathParameters params = null; - if("PKIX".equalsIgnoreCase(algorithm)) { - PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, - new X509CertSelector()); - Collection crls = getCRLs(crlf); - CertStoreParameters csp = new CollectionCertStoreParameters(crls); - CertStore store = CertStore.getInstance("Collection", csp); - xparams.addCertStore(store); - xparams.setRevocationEnabled(true); - String trustLength = (String)attributes.get("trustMaxCertLength"); - if(trustLength != null) { - try { - xparams.setMaxPathLength(Integer.parseInt(trustLength)); - } catch(Exception ex) { - log.warn("Bad maxCertLength: "+trustLength); - } - } - - params = xparams; - } else { - throw new CRLException("CRLs not supported for type: "+algorithm); - } - return params; - } - - - /** - * Load the collection of CRLs. - * - */ - protected Collection getCRLs(String crlf) - throws IOException, CRLException, CertificateException { - - File crlFile = new File(crlf); - if( !crlFile.isAbsolute() ) { - crlFile = new File(System.getProperty("catalina.base"), crlf); - } - Collection crls = null; - InputStream is = null; - try { - CertificateFactory cf = CertificateFactory.getInstance("X.509"); - is = new FileInputStream(crlFile); - crls = cf.generateCRLs(is); - } catch(IOException iex) { - throw iex; - } catch(CRLException crle) { - throw crle; - } catch(CertificateException ce) { - throw ce; - } finally { - if(is != null) { - try{ - is.close(); - } catch(Exception ex) { - } - } - } - return crls; - } - - /** - * Set the SSL protocol variants to be enabled. - * @param socket the SSLServerSocket. - * @param protocols the protocols to use. - */ - protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){ - if (protocols != null) { - socket.setEnabledProtocols(protocols); - } - } - - /** - * Determines the SSL protocol variants to be enabled. - * - * @param socket The socket to get supported list from. - * @param requestedProtocols Comma-separated list of requested SSL - * protocol variants - * - * @return Array of SSL protocol variants to be enabled, or null if none of - * the requested protocol variants are supported - */ - protected String[] getEnabledProtocols(SSLServerSocket socket, - String requestedProtocols){ - String[] supportedProtocols = socket.getSupportedProtocols(); - - String[] enabledProtocols = null; - - if (requestedProtocols != null) { - Vector vec = null; - String protocol = requestedProtocols; - int index = requestedProtocols.indexOf(','); - if (index != -1) { - int fromIndex = 0; - while (index != -1) { - protocol = requestedProtocols.substring(fromIndex, index).trim(); - if (protocol.length() > 0) { - /* - * Check to see if the requested protocol is among the - * supported protocols, i.e., may be enabled - */ - for (int i=0; supportedProtocols != null - && i 0) { - /* - * Check to see if the requested protocol is among the - * supported protocols, i.e., may be enabled - */ - for (int i=0; supportedProtocols != null - && i 0) { + /* + * Check to see if the requested cipher is among the + * supported ciphers, i.e., may be enabled + */ + for (int i=0; supportedCiphers != null + && i 0) { + /* + * Check to see if the requested cipher is among the + * supported ciphers, i.e., may be enabled + */ + for (int i=0; supportedCiphers != null + && iPKIX is supported. + * + * @param algorithm The algorithm to get parameters for. + * @param crlf The path to the CRL file. + * @param trustStore The configured TrustStore. + * @return The parameters including the CRLs and TrustStore. + */ + protected CertPathParameters getParameters(String algorithm, + String crlf, + KeyStore trustStore) + throws Exception { + CertPathParameters params = null; + if("PKIX".equalsIgnoreCase(algorithm)) { + PKIXBuilderParameters xparams = new PKIXBuilderParameters(trustStore, + new X509CertSelector()); + Collection crls = getCRLs(crlf); + CertStoreParameters csp = new CollectionCertStoreParameters(crls); + CertStore store = CertStore.getInstance("Collection", csp); + xparams.addCertStore(store); + xparams.setRevocationEnabled(true); + String trustLength = (String)attributes.get("trustMaxCertLength"); + if(trustLength != null) { + try { + xparams.setMaxPathLength(Integer.parseInt(trustLength)); + } catch(Exception ex) { + log.warn("Bad maxCertLength: "+trustLength); + } + } + + params = xparams; + } else { + throw new CRLException("CRLs not supported for type: "+algorithm); + } + return params; + } + + + /** + * Load the collection of CRLs. + * + */ + protected Collection getCRLs(String crlf) + throws IOException, CRLException, CertificateException { + + File crlFile = new File(crlf); + if( !crlFile.isAbsolute() ) { + crlFile = new File(System.getProperty("catalina.base"), crlf); + } + Collection crls = null; + InputStream is = null; + try { + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + is = new FileInputStream(crlFile); + crls = cf.generateCRLs(is); + } catch(IOException iex) { + throw iex; + } catch(CRLException crle) { + throw crle; + } catch(CertificateException ce) { + throw ce; + } finally { + if(is != null) { + try{ + is.close(); + } catch(Exception ex) { + } + } + } + return crls; + } + + /** + * Set the SSL protocol variants to be enabled. + * @param socket the SSLServerSocket. + * @param protocols the protocols to use. + */ + protected void setEnabledProtocols(SSLServerSocket socket, String []protocols){ + if (protocols != null) { + socket.setEnabledProtocols(protocols); + } + } + + /** + * Determines the SSL protocol variants to be enabled. + * + * @param socket The socket to get supported list from. + * @param requestedProtocols Comma-separated list of requested SSL + * protocol variants + * + * @return Array of SSL protocol variants to be enabled, or null if none of + * the requested protocol variants are supported + */ + protected String[] getEnabledProtocols(SSLServerSocket socket, + String requestedProtocols){ + String[] supportedProtocols = socket.getSupportedProtocols(); + + String[] enabledProtocols = null; + + if (requestedProtocols != null) { + Vector vec = null; + String protocol = requestedProtocols; + int index = requestedProtocols.indexOf(','); + if (index != -1) { + int fromIndex = 0; + while (index != -1) { + protocol = requestedProtocols.substring(fromIndex, index).trim(); + if (protocol.length() > 0) { + /* + * Check to see if the requested protocol is among the + * supported protocols, i.e., may be enabled + */ + for (int i=0; supportedProtocols != null + && i 0) { + /* + * Check to see if the requested protocol is among the + * supported protocols, i.e., may be enabled + */ + for (int i=0; supportedProtocols != null + && iorg.apache.catalina.valves.CertificateValve - */ - public Integer getKeySize() - throws IOException { - // Look up the current SSLSession - SSLSession session = ssl.getSession(); - SSLSupport.CipherData c_aux[]=ciphers; - if (session == null) - return null; - Integer keySize = (Integer) session.getValue(KEY_SIZE_KEY); - if (keySize == null) { - int size = 0; - String cipherSuite = session.getCipherSuite(); - for (int i = 0; i < c_aux.length; i++) { - if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) { - size = c_aux[i].keySize; - break; - } - } - keySize = new Integer(size); - session.putValue(KEY_SIZE_KEY, keySize); - } - return keySize; - } - - public String getSessionId() - throws IOException { - // Look up the current SSLSession - SSLSession session = ssl.getSession(); - if (session == null) - return null; - // Expose ssl_session (getId) - byte [] ssl_session = session.getId(); - if ( ssl_session == null) - return null; - StringBuffer buf=new StringBuffer(""); - for(int x=0; x2) digit=digit.substring(digit.length()-2); - buf.append(digit); - } - return buf.toString(); - } - - - private static class Listener implements HandshakeCompletedListener { - volatile boolean completed = false; - public void handshakeCompleted(HandshakeCompletedEvent event) { - completed = true; - } - void reset() { - completed = false; - } - } - -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.jsse; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.SocketException; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLException; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.security.cert.X509Certificate; + +import org.apache.tomcat.util.net.SSLSupport; + +/* JSSESupport + + Concrete implementation class for JSSE + Support classes. + + This will only work with JDK 1.2 and up since it + depends on JDK 1.2's certificate support + + @author EKR + @author Craig R. McClanahan + Parts cribbed from JSSECertCompat + Parts cribbed from CertificatesValve +*/ + +class JSSESupport implements SSLSupport { + + private static org.apache.commons.logging.Log log = + org.apache.commons.logging.LogFactory.getLog(JSSESupport.class); + + protected SSLSocket ssl; + + Listener listener = new Listener(); + + JSSESupport(SSLSocket sock){ + ssl=sock; + sock.addHandshakeCompletedListener(listener); + } + + public String getCipherSuite() throws IOException { + // Look up the current SSLSession + SSLSession session = ssl.getSession(); + if (session == null) + return null; + return session.getCipherSuite(); + } + + public Object[] getPeerCertificateChain() + throws IOException { + return getPeerCertificateChain(false); + } + + protected java.security.cert.X509Certificate [] getX509Certificates(SSLSession session) + throws IOException { + Certificate [] certs=null; + try { + certs = session.getPeerCertificates(); + } catch( Throwable t ) { + log.debug("Error getting client certs",t); + return null; + } + if( certs==null ) return null; + + java.security.cert.X509Certificate [] x509Certs = + new java.security.cert.X509Certificate[certs.length]; + for(int i=0; i < certs.length; i++) { + if (certs[i] instanceof java.security.cert.X509Certificate ) { + // always currently true with the JSSE 1.1.x + x509Certs[i] = (java.security.cert.X509Certificate) certs[i]; + } else { + try { + byte [] buffer = certs[i].getEncoded(); + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + ByteArrayInputStream stream = + new ByteArrayInputStream(buffer); + x509Certs[i] = (java.security.cert.X509Certificate) cf.generateCertificate(stream); + } catch(Exception ex) { + log.info("Error translating cert " + certs[i], ex); + return null; + } + } + if(log.isTraceEnabled()) + log.trace("Cert #" + i + " = " + x509Certs[i]); + } + if(x509Certs.length < 1) + return null; + return x509Certs; + } + + public Object[] getPeerCertificateChain(boolean force) + throws IOException { + // Look up the current SSLSession + SSLSession session = ssl.getSession(); + if (session == null) + return null; + + // Convert JSSE's certificate format to the ones we need + X509Certificate [] jsseCerts = null; + try { + jsseCerts = session.getPeerCertificateChain(); + } catch(Exception bex) { + // ignore. + } + if (jsseCerts == null) + jsseCerts = new X509Certificate[0]; + if(jsseCerts.length <= 0 && force) { + session.invalidate(); + handShake(); + session = ssl.getSession(); + } + return getX509Certificates(session); + } + + protected void handShake() throws IOException { + if( ssl.getWantClientAuth() ) { + log.debug("No client cert sent for want"); + } else { + ssl.setNeedClientAuth(true); + } + + InputStream in = ssl.getInputStream(); + int oldTimeout = ssl.getSoTimeout(); + ssl.setSoTimeout(1000); + byte[] b = new byte[0]; + listener.reset(); + ssl.startHandshake(); + int maxTries = 60; // 60 * 1000 = example 1 minute time out + for (int i = 0; i < maxTries; i++) { + if(log.isTraceEnabled()) + log.trace("Reading for try #" +i); + try { + int x = in.read(b); + } catch(SSLException sslex) { + log.info("SSL Error getting client Certs",sslex); + throw sslex; + } catch (IOException e) { + // ignore - presumably the timeout + } + if (listener.completed) { + break; + } + } + ssl.setSoTimeout(oldTimeout); + if (listener.completed == false) { + throw new SocketException("SSL Cert handshake timeout"); + } + + } + + /** + * Copied from org.apache.catalina.valves.CertificateValve + */ + public Integer getKeySize() + throws IOException { + // Look up the current SSLSession + SSLSession session = ssl.getSession(); + SSLSupport.CipherData c_aux[]=ciphers; + if (session == null) + return null; + Integer keySize = (Integer) session.getValue(KEY_SIZE_KEY); + if (keySize == null) { + int size = 0; + String cipherSuite = session.getCipherSuite(); + for (int i = 0; i < c_aux.length; i++) { + if (cipherSuite.indexOf(c_aux[i].phrase) >= 0) { + size = c_aux[i].keySize; + break; + } + } + keySize = new Integer(size); + session.putValue(KEY_SIZE_KEY, keySize); + } + return keySize; + } + + public String getSessionId() + throws IOException { + // Look up the current SSLSession + SSLSession session = ssl.getSession(); + if (session == null) + return null; + // Expose ssl_session (getId) + byte [] ssl_session = session.getId(); + if ( ssl_session == null) + return null; + StringBuffer buf=new StringBuffer(""); + for(int x=0; x2) digit=digit.substring(digit.length()-2); + buf.append(digit); + } + return buf.toString(); + } + + + private static class Listener implements HandshakeCompletedListener { + volatile boolean completed = false; + public void handshakeCompleted(HandshakeCompletedEvent event) { + completed = true; + } + void reset() { + completed = false; + } + } + +} + diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties index acb858808..fbd5c4e24 100644 --- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties +++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings.properties @@ -1 +1 @@ -jsse.alias_no_key_entry=Alias name {0} does not identify a key entry +jsse.alias_no_key_entry=Alias name {0} does not identify a key entry diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties index 3e4457d03..75e5e0d8c 100644 --- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties +++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_es.properties @@ -1 +1 @@ -jsse.alias_no_key_entry=El nombre de Alias {0} no identifica una entrada de clave +jsse.alias_no_key_entry=El nombre de Alias {0} no identifica una entrada de clave diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties index 6e6e3ad08..04aa2dfd1 100644 --- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties +++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_fr.properties @@ -1 +1 @@ -jsse.alias_no_key_entry=Le nom alias {0} n''identifie pas une entrée de clef +jsse.alias_no_key_entry=Le nom alias {0} n''identifie pas une entrée de clef diff --git a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties index e43058713..cfb080b0c 100644 --- a/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties +++ b/java/org/apache/tomcat/util/net/jsse/res/LocalStrings_ja.properties @@ -1,2 +1,2 @@ -jsse.alias_no_key_entry=\u5225\u540d {0} \u306f\u30ad\u30fc\u30a8\u30f3\u30c8\u30ea\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093 - +jsse.alias_no_key_entry=\u5225\u540d {0} \u306f\u30ad\u30fc\u30a8\u30f3\u30c8\u30ea\u3092\u767a\u898b\u3067\u304d\u307e\u305b\u3093 + diff --git a/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java b/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java index f4c31abdb..2d88a2a2b 100644 --- a/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java +++ b/java/org/apache/tomcat/util/net/puretls/PureTLSImplementation.java @@ -1,57 +1,57 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.puretls; - -import java.net.Socket; - -import org.apache.tomcat.util.net.SSLImplementation; -import org.apache.tomcat.util.net.SSLSupport; -import org.apache.tomcat.util.net.ServerSocketFactory; - -import COM.claymoresystems.ptls.SSLSocket; - -/* PureTLSImplementation: - - Concrete implementation class for PureTLS - - @author EKR -*/ - -public class PureTLSImplementation extends SSLImplementation -{ - public PureTLSImplementation() throws ClassNotFoundException { - // Check to see if PureTLS is floating around somewhere - Class.forName("COM.claymoresystems.ptls.SSLContext"); - } - - public String getImplementationName(){ - return "PureTLS"; - } - - public ServerSocketFactory getServerSocketFactory() - { - return new PureTLSSocketFactory(); - } - - public SSLSupport getSSLSupport(Socket s) - { - return new PureTLSSupport((SSLSocket)s); - } - - - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.puretls; + +import java.net.Socket; + +import org.apache.tomcat.util.net.SSLImplementation; +import org.apache.tomcat.util.net.SSLSupport; +import org.apache.tomcat.util.net.ServerSocketFactory; + +import COM.claymoresystems.ptls.SSLSocket; + +/* PureTLSImplementation: + + Concrete implementation class for PureTLS + + @author EKR +*/ + +public class PureTLSImplementation extends SSLImplementation +{ + public PureTLSImplementation() throws ClassNotFoundException { + // Check to see if PureTLS is floating around somewhere + Class.forName("COM.claymoresystems.ptls.SSLContext"); + } + + public String getImplementationName(){ + return "PureTLS"; + } + + public ServerSocketFactory getServerSocketFactory() + { + return new PureTLSSocketFactory(); + } + + public SSLSupport getSSLSupport(Socket s) + { + return new PureTLSSupport((SSLSocket)s); + } + + + +} diff --git a/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java b/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java index 41a882b5a..bb5d6b9d0 100644 --- a/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java +++ b/java/org/apache/tomcat/util/net/puretls/PureTLSSocket.java @@ -1,42 +1,42 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.puretls; - -import java.io.IOException; - -/* - * PureTLSSocket.java - * - * Wraps COM.claymoresystems.ptls.SSLSocket - * - * This class translates PureTLS's interfaces into those - * expected by Tomcat - * - * @author Eric Rescorla - * - */ - -public class PureTLSSocket extends COM.claymoresystems.ptls.SSLSocket -{ - // The only constructor we need here is the no-arg - // constructor since this class is only used with - // implAccept - public PureTLSSocket() throws IOException { - super(); - } -} - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.puretls; + +import java.io.IOException; + +/* + * PureTLSSocket.java + * + * Wraps COM.claymoresystems.ptls.SSLSocket + * + * This class translates PureTLS's interfaces into those + * expected by Tomcat + * + * @author Eric Rescorla + * + */ + +public class PureTLSSocket extends COM.claymoresystems.ptls.SSLSocket +{ + // The only constructor we need here is the no-arg + // constructor since this class is only used with + // implAccept + public PureTLSSocket() throws IOException { + super(); + } +} + diff --git a/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java b/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java index 988483a83..ca503489a 100644 --- a/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java +++ b/java/org/apache/tomcat/util/net/puretls/PureTLSSocketFactory.java @@ -1,229 +1,229 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.net.puretls; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.ServerSocket; -import java.net.Socket; -import java.net.SocketException; -import java.util.Vector; - -import COM.claymoresystems.ptls.SSLContext; -import COM.claymoresystems.ptls.SSLException; -import COM.claymoresystems.ptls.SSLServerSocket; -import COM.claymoresystems.ptls.SSLSocket; -import COM.claymoresystems.sslg.SSLPolicyInt; - -/** - * SSL server socket factory--wraps PureTLS - * - * @author Eric Rescorla - * - * some sections of this file cribbed from SSLSocketFactory - * (the JSSE socket factory) - * - */ - -public class PureTLSSocketFactory - extends org.apache.tomcat.util.net.ServerSocketFactory -{ - static org.apache.commons.logging.Log logger = - org.apache.commons.logging.LogFactory.getLog(PureTLSSocketFactory.class); - static String defaultProtocol = "TLS"; - static boolean defaultClientAuth = false; - static String defaultKeyStoreFile = "server.pem"; - static String defaultKeyPass = "password"; - static String defaultRootFile = "root.pem"; - static String defaultRandomFile = "random.pem"; - - private COM.claymoresystems.ptls.SSLContext context=null; - - public PureTLSSocketFactory() { - } - - public ServerSocket createSocket(int port) - throws IOException - { - init(); - return new SSLServerSocket(context,port); - } - - public ServerSocket createSocket(int port, int backlog) - throws IOException - { - init(); - ServerSocket tmp; - - try { - tmp=new SSLServerSocket(context,port,backlog); - } - catch (IOException e){ - throw e; - } - return tmp; - } - - public ServerSocket createSocket(int port, int backlog, - InetAddress ifAddress) - throws IOException - { - init(); - return new SSLServerSocket(context,port,backlog,ifAddress); - } - - private void init() - throws IOException - { - if(context!=null) - return; - - boolean clientAuth=defaultClientAuth; - - try { - String keyStoreFile=(String)attributes.get("keystore"); - if(keyStoreFile==null) keyStoreFile=defaultKeyStoreFile; - - String keyPass=(String)attributes.get("keypass"); - if(keyPass==null) keyPass=defaultKeyPass; - - String rootFile=(String)attributes.get("rootfile"); - if(rootFile==null) rootFile=defaultRootFile; - - String randomFile=(String)attributes.get("randomfile"); - if(randomFile==null) randomFile=defaultRandomFile; - - String protocol=(String)attributes.get("protocol"); - if(protocol==null) protocol=defaultProtocol; - - String clientAuthStr=(String)attributes.get("clientauth"); - if(clientAuthStr != null){ - if(clientAuthStr.equals("true")){ - clientAuth=true; - } else if(clientAuthStr.equals("false")) { - clientAuth=false; - } else { - throw new IOException("Invalid value '" + - clientAuthStr + - "' for 'clientauth' parameter:"); - } - } - - SSLContext tmpContext=new SSLContext(); - try { - tmpContext.loadRootCertificates(rootFile); - } catch(IOException iex) { - if(logger.isDebugEnabled()) - logger.debug("Error loading Client Root Store: " + - rootFile,iex); - } - tmpContext.loadEAYKeyFile(keyStoreFile,keyPass); - tmpContext.useRandomnessFile(randomFile,keyPass); - - SSLPolicyInt policy=new SSLPolicyInt(); - policy.requireClientAuth(clientAuth); - policy.handshakeOnConnect(false); - policy.waitOnClose(false); - short [] enabledCiphers = getEnabledCiphers(policy.getCipherSuites()); - if( enabledCiphers != null ) { - policy.setCipherSuites(enabledCiphers); - } - tmpContext.setPolicy(policy); - context=tmpContext; - } catch (Exception e){ - logger.info("Error initializing SocketFactory",e); - throw new IOException(e.getMessage()); - } - } - - /* - * Determines the SSL cipher suites to be enabled. - * - * @return Array of SSL cipher suites to be enabled, or null if the - * cipherSuites property was not specified (meaning that all supported - * cipher suites are to be enabled) - */ - private short [] getEnabledCiphers(short [] supportedCiphers) { - - short [] enabledCiphers = null; - - String attrValue = (String)attributes.get("ciphers"); - if (attrValue != null) { - Vector vec = null; - int fromIndex = 0; - int index = attrValue.indexOf(',', fromIndex); - while (index != -1) { - String cipher = attrValue.substring(fromIndex, index).trim(); - int cipherValue = SSLPolicyInt.getCipherSuiteNumber(cipher); - /* - * Check to see if the requested cipher is among the supported - * ciphers, i.e., may be enabled - */ - if( cipherValue >= 0) { - for (int i=0; supportedCiphers != null - && i= 0) { + for (int i=0; supportedCiphers != null + && i= 0) { - size = ciphers[i].keySize; - break; - } - } - Integer keySize = new Integer(size); - return keySize; - } - - public String getSessionId() - throws IOException { - byte [] ssl_session = ssl.getSessionID(); - if(ssl_session == null) - return null; - return HexUtils.convert(ssl_session); - } - -} - - - - - - - +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.net.puretls; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.util.Vector; + +import org.apache.tomcat.util.buf.HexUtils; +import org.apache.tomcat.util.net.SSLSupport; + +import COM.claymoresystems.cert.X509Cert; +import COM.claymoresystems.ptls.SSLSocket; +import COM.claymoresystems.sslg.SSLPolicyInt; + + +/* PureTLSSupport + + Concrete implementation class for PureTLS + Support classes. + + This will only work with JDK 1.2 and up since it + depends on JDK 1.2's certificate support + + @author EKR +*/ + +class PureTLSSupport implements SSLSupport { + static org.apache.commons.logging.Log logger = + org.apache.commons.logging.LogFactory.getLog(PureTLSSupport.class); + + private COM.claymoresystems.ptls.SSLSocket ssl; + + PureTLSSupport(SSLSocket sock){ + ssl=sock; + } + + public String getCipherSuite() throws IOException { + int cs=ssl.getCipherSuite(); + return SSLPolicyInt.getCipherSuiteName(cs); + } + + public Object[] getPeerCertificateChain() + throws IOException { + return getPeerCertificateChain(false); + } + + public Object[] getPeerCertificateChain(boolean force) + throws IOException { + Vector v=ssl.getCertificateChain(); + + if(v == null && force) { + SSLPolicyInt policy=new SSLPolicyInt(); + policy.requireClientAuth(true); + policy.handshakeOnConnect(false); + policy.waitOnClose(false); + ssl.renegotiate(policy); + v = ssl.getCertificateChain(); + } + + if(v==null) + return null; + + java.security.cert.X509Certificate[] chain= + new java.security.cert.X509Certificate[v.size()]; + + try { + for(int i=1;i<=v.size();i++){ + // PureTLS provides cert chains with the peer + // cert last but the Servlet 2.3 spec (S 4.7) requires + // the opposite order so we reverse the chain as we go + byte buffer[]=((X509Cert)v.elementAt( + v.size()-i)).getDER(); + + CertificateFactory cf = + CertificateFactory.getInstance("X.509"); + ByteArrayInputStream stream = + new ByteArrayInputStream(buffer); + + X509Certificate xCert = (X509Certificate)cf.generateCertificate(stream); + chain[i-1]= xCert; + if(logger.isTraceEnabled()) { + logger.trace("Cert # " + i + " = " + xCert); + } + } + } catch (java.security.cert.CertificateException e) { + logger.info("JDK's broken cert handling can't parse this certificate (which PureTLS likes)",e); + throw new IOException("JDK's broken cert handling can't parse this certificate (which PureTLS likes)"); + } + return chain; + } + + /** + * Lookup the symmetric key size. + */ + public Integer getKeySize() + throws IOException { + + int cs=ssl.getCipherSuite(); + String cipherSuite = SSLPolicyInt.getCipherSuiteName(cs); + int size = 0; + for (int i = 0; i < ciphers.length; i++) { + if (cipherSuite.indexOf(ciphers[i].phrase) >= 0) { + size = ciphers[i].keySize; + break; + } + } + Integer keySize = new Integer(size); + return keySize; + } + + public String getSessionId() + throws IOException { + byte [] ssl_session = ssl.getSessionID(); + if(ssl_session == null) + return null; + return HexUtils.convert(ssl_session); + } + +} + + + + + + + diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings.properties b/java/org/apache/tomcat/util/net/res/LocalStrings.properties index 13f3f42a6..5844a18e3 100644 --- a/java/org/apache/tomcat/util/net/res/LocalStrings.properties +++ b/java/org/apache/tomcat/util/net/res/LocalStrings.properties @@ -1,25 +1,25 @@ -# net resources -endpoint.err.fatal=Endpoint {0} shutdown due to exception: {1} -endpoint.err.nonfatal=Endpoint {0} ignored exception: {1} -endpoint.warn.reinit=Reinitializing ServerSocket -endpoint.warn.restart=Restarting endpoint -endpoint.warn.security=Endpoint {0} security exception: {1} -endpoint.err.socket=Socket error caused by remote host {0} -endpoint.err.handshake=Handshake failed -endpoint.err.unexpected=Unexpected error processing socket -endpoint.warn.nullSocket=Null socket returned by accept -endpoint.debug.unlock=Caught exception trying to unlock accept on port {0} -endpoint.err.close=Caught exception trying to close socket -endpoint.noProcessor=No Processors - worker thread dead! - -endpoint.init.bind=Socket bind failed: [{0}] {1} -endpoint.init.listen=Socket listen failed: [{0}] {1} -endpoint.accept.fail=Socket accept failed -endpoint.poll.limitedpollsize=Failed to create poller with specified size of {0} -endpoint.poll.initfail=Poller creation failed -endpoint.poll.fail=Critical poller failure (restarting poller): [{0}] {1} -endpoint.poll.error=Unexpected poller error -endpoint.process.fail=Error allocating socket processor -endpoint.sendfile.error=Unexpected sendfile error -endpoint.sendfile.addfail=Sednfile failure: [{0}] {1} -endpoint.sendfile.nosupport=Disabling sendfile, since either the APR version or the system doesn't support it +# net resources +endpoint.err.fatal=Endpoint {0} shutdown due to exception: {1} +endpoint.err.nonfatal=Endpoint {0} ignored exception: {1} +endpoint.warn.reinit=Reinitializing ServerSocket +endpoint.warn.restart=Restarting endpoint +endpoint.warn.security=Endpoint {0} security exception: {1} +endpoint.err.socket=Socket error caused by remote host {0} +endpoint.err.handshake=Handshake failed +endpoint.err.unexpected=Unexpected error processing socket +endpoint.warn.nullSocket=Null socket returned by accept +endpoint.debug.unlock=Caught exception trying to unlock accept on port {0} +endpoint.err.close=Caught exception trying to close socket +endpoint.noProcessor=No Processors - worker thread dead! + +endpoint.init.bind=Socket bind failed: [{0}] {1} +endpoint.init.listen=Socket listen failed: [{0}] {1} +endpoint.accept.fail=Socket accept failed +endpoint.poll.limitedpollsize=Failed to create poller with specified size of {0} +endpoint.poll.initfail=Poller creation failed +endpoint.poll.fail=Critical poller failure (restarting poller): [{0}] {1} +endpoint.poll.error=Unexpected poller error +endpoint.process.fail=Error allocating socket processor +endpoint.sendfile.error=Unexpected sendfile error +endpoint.sendfile.addfail=Sednfile failure: [{0}] {1} +endpoint.sendfile.nosupport=Disabling sendfile, since either the APR version or the system doesn't support it diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties b/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties index 9b53fd7db..188fe99c4 100644 --- a/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties +++ b/java/org/apache/tomcat/util/net/res/LocalStrings_es.properties @@ -1,6 +1,6 @@ -# net resources -endpoint.err.fatal=Punto Final (Endpoint) {0} parado debido a excepción: {1} -endpoint.err.nonfatal=El Punto Final (Endpoint) {0} ignoró excepción: {1} -endpoint.warn.reinit=Reinicializando ServerSocket -endpoint.warn.restart=Rearrancando punto final (endpoint) -endpoint.warn.security=Punto Final (Endpoint) {0} con excepción de seguridad: {1} +# net resources +endpoint.err.fatal=Punto Final (Endpoint) {0} parado debido a excepción: {1} +endpoint.err.nonfatal=El Punto Final (Endpoint) {0} ignoró excepción: {1} +endpoint.warn.reinit=Reinicializando ServerSocket +endpoint.warn.restart=Rearrancando punto final (endpoint) +endpoint.warn.security=Punto Final (Endpoint) {0} con excepción de seguridad: {1} diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties b/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties index 6c0d3ab8c..35d0b2732 100644 --- a/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties +++ b/java/org/apache/tomcat/util/net/res/LocalStrings_fr.properties @@ -1,6 +1,6 @@ -# net resources -endpoint.err.fatal=Le point de contact {0} a été éteint suite à l''exception{1} -endpoint.err.nonfatal=Le point de contact {0} a ignoré l''exception: {1} -endpoint.warn.reinit=Réinitialisation du ServerSocket -endpoint.warn.restart=Redémarrage du point de contact - +# net resources +endpoint.err.fatal=Le point de contact {0} a été éteint suite à l''exception{1} +endpoint.err.nonfatal=Le point de contact {0} a ignoré l''exception: {1} +endpoint.warn.reinit=Réinitialisation du ServerSocket +endpoint.warn.restart=Redémarrage du point de contact + diff --git a/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties b/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties index 686915eb0..15611e3fd 100644 --- a/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties +++ b/java/org/apache/tomcat/util/net/res/LocalStrings_ja.properties @@ -1,6 +1,6 @@ -# net resources -endpoint.err.fatal=\u4f8b\u5916\u306e\u305f\u3081\u306b\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u307e\u3059: {1} -endpoint.err.nonfatal=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u4f8b\u5916\u3092\u7121\u8996\u3057\u307e\u3057\u305f: {1} -endpoint.warn.reinit=ServerSocket\u3092\u518d\u521d\u671f\u5316\u3057\u307e\u3059 -endpoint.warn.restart=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u518d\u8d77\u52d5\u3057\u307e\u3059 -endpoint.warn.security=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u4f8b\u5916\u3067\u3059: {1} +# net resources +endpoint.err.fatal=\u4f8b\u5916\u306e\u305f\u3081\u306b\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u30b7\u30e3\u30c3\u30c8\u30c0\u30a6\u30f3\u3057\u307e\u3059: {1} +endpoint.err.nonfatal=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306f\u4f8b\u5916\u3092\u7121\u8996\u3057\u307e\u3057\u305f: {1} +endpoint.warn.reinit=ServerSocket\u3092\u518d\u521d\u671f\u5316\u3057\u307e\u3059 +endpoint.warn.restart=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8\u3092\u518d\u8d77\u52d5\u3057\u307e\u3059 +endpoint.warn.security=\u30a8\u30f3\u30c9\u30dd\u30a4\u30f3\u30c8 {0} \u306e\u30bb\u30ad\u30e5\u30ea\u30c6\u30a3\u4f8b\u5916\u3067\u3059: {1} diff --git a/java/org/apache/tomcat/util/res/StringManager.java b/java/org/apache/tomcat/util/res/StringManager.java index 16d889904..626407e60 100644 --- a/java/org/apache/tomcat/util/res/StringManager.java +++ b/java/org/apache/tomcat/util/res/StringManager.java @@ -1,285 +1,285 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.res; - -import java.text.MessageFormat; -import java.util.Hashtable; -import java.util.Locale; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -/** - * An internationalization / localization helper class which reduces - * the bother of handling ResourceBundles and takes care of the - * common cases of message formating which otherwise require the - * creation of Object arrays and such. - * - *

        The StringManager operates on a package basis. One StringManager - * per package can be created and accessed via the getManager method - * call. - * - *

        The StringManager will look for a ResourceBundle named by - * the package name given plus the suffix of "LocalStrings". In - * practice, this means that the localized information will be contained - * in a LocalStrings.properties file located in the package - * directory of the classpath. - * - *

        Please see the documentation for java.util.ResourceBundle for - * more information. - * - * @version $Revision: 299753 $ $Date: 2004-08-29 19:14:42 +0200 (dim., 29 août 2004) $ - * - * @author James Duncan Davidson [duncan@eng.sun.com] - * @author James Todd [gonzo@eng.sun.com] - * @author Mel Martinez [mmartinez@g1440.com] - * @see java.util.ResourceBundle - */ - -public class StringManager { - - /** - * The ResourceBundle for this StringManager. - */ - - private ResourceBundle bundle; - private Locale locale; - - /** - * Creates a new StringManager for a given package. This is a - * private method and all access to it is arbitrated by the - * static getManager method call so that only one StringManager - * per package will be created. - * - * @param packageName Name of package to create StringManager for. - */ - - private StringManager(String packageName) { - this( packageName, Locale.getDefault() ); - } - - private StringManager(String packageName, Locale loc) { - String bundleName = packageName + ".LocalStrings"; - bundle = ResourceBundle.getBundle(bundleName, loc); - // Get the actual locale, which may be different from the requested one - locale = bundle.getLocale(); - } - - private StringManager(ResourceBundle bundle ) - { - this.bundle=bundle; - locale = bundle.getLocale(); - } - - /** - Get a string from the underlying resource bundle or return - null if the String is not found. - - @param key to desired resource String - @return resource String matching key from underlying - bundle or null if not found. - @throws IllegalArgumentException if key is null. - */ - - public String getString(String key) { - if(key == null){ - String msg = "key may not have a null value"; - - throw new IllegalArgumentException(msg); - } - - String str = null; - - try{ - str = bundle.getString(key); - }catch(MissingResourceException mre){ - //bad: shouldn't mask an exception the following way: - // str = "[cannot find message associated with key '" + key + "' due to " + mre + "]"; - // because it hides the fact that the String was missing - // from the calling code. - //good: could just throw the exception (or wrap it in another) - // but that would probably cause much havoc on existing - // code. - //better: consistent with container pattern to - // simply return null. Calling code can then do - // a null check. - str = null; - } - - return str; - } - - /** - * Get a string from the underlying resource bundle and format - * it with the given set of arguments. - * - * @param key - * @param args - */ - - public String getString(String key, Object[] args) { - String iString = null; - String value = getString(key); - - // this check for the runtime exception is some pre 1.1.6 - // VM's don't do an automatic toString() on the passed in - // objects and barf out - - try { - // ensure the arguments are not null so pre 1.2 VM's don't barf - if(args==null){ - args = new Object[1]; - } - - Object[] nonNullArgs = args; - for (int i=0; iThe StringManager operates on a package basis. One StringManager + * per package can be created and accessed via the getManager method + * call. + * + *

        The StringManager will look for a ResourceBundle named by + * the package name given plus the suffix of "LocalStrings". In + * practice, this means that the localized information will be contained + * in a LocalStrings.properties file located in the package + * directory of the classpath. + * + *

        Please see the documentation for java.util.ResourceBundle for + * more information. + * + * @version $Revision: 299753 $ $Date: 2004-08-29 19:14:42 +0200 (dim., 29 août 2004) $ + * + * @author James Duncan Davidson [duncan@eng.sun.com] + * @author James Todd [gonzo@eng.sun.com] + * @author Mel Martinez [mmartinez@g1440.com] + * @see java.util.ResourceBundle + */ + +public class StringManager { + + /** + * The ResourceBundle for this StringManager. + */ + + private ResourceBundle bundle; + private Locale locale; + + /** + * Creates a new StringManager for a given package. This is a + * private method and all access to it is arbitrated by the + * static getManager method call so that only one StringManager + * per package will be created. + * + * @param packageName Name of package to create StringManager for. + */ + + private StringManager(String packageName) { + this( packageName, Locale.getDefault() ); + } + + private StringManager(String packageName, Locale loc) { + String bundleName = packageName + ".LocalStrings"; + bundle = ResourceBundle.getBundle(bundleName, loc); + // Get the actual locale, which may be different from the requested one + locale = bundle.getLocale(); + } + + private StringManager(ResourceBundle bundle ) + { + this.bundle=bundle; + locale = bundle.getLocale(); + } + + /** + Get a string from the underlying resource bundle or return + null if the String is not found. + + @param key to desired resource String + @return resource String matching key from underlying + bundle or null if not found. + @throws IllegalArgumentException if key is null. + */ + + public String getString(String key) { + if(key == null){ + String msg = "key may not have a null value"; + + throw new IllegalArgumentException(msg); + } + + String str = null; + + try{ + str = bundle.getString(key); + }catch(MissingResourceException mre){ + //bad: shouldn't mask an exception the following way: + // str = "[cannot find message associated with key '" + key + "' due to " + mre + "]"; + // because it hides the fact that the String was missing + // from the calling code. + //good: could just throw the exception (or wrap it in another) + // but that would probably cause much havoc on existing + // code. + //better: consistent with container pattern to + // simply return null. Calling code can then do + // a null check. + str = null; + } + + return str; + } + + /** + * Get a string from the underlying resource bundle and format + * it with the given set of arguments. + * + * @param key + * @param args + */ + + public String getString(String key, Object[] args) { + String iString = null; + String value = getString(key); + + // this check for the runtime exception is some pre 1.1.6 + // VM's don't do an automatic toString() on the passed in + // objects and barf out + + try { + // ensure the arguments are not null so pre 1.2 VM's don't barf + if(args==null){ + args = new Object[1]; + } + + Object[] nonNullArgs = args; + for (int i=0; i - */ -public class ThreadPool { - - private static Log log = LogFactory.getLog(ThreadPool.class); - - private static StringManager sm = - StringManager.getManager("org.apache.tomcat.util.threads.res"); - - private static boolean logfull=true; - - /* - * Default values ... - */ - public static final int MAX_THREADS = 200; - public static final int MAX_THREADS_MIN = 10; - public static final int MAX_SPARE_THREADS = 50; - public static final int MIN_SPARE_THREADS = 4; - public static final int WORK_WAIT_TIMEOUT = 60*1000; - - /* - * Where the threads are held. - */ - protected ControlRunnable[] pool = null; - - /* - * A monitor thread that monitors the pool for idel threads. - */ - protected MonitorRunnable monitor; - - - /* - * Max number of threads that you can open in the pool. - */ - protected int maxThreads; - - /* - * Min number of idel threads that you can leave in the pool. - */ - protected int minSpareThreads; - - /* - * Max number of idel threads that you can leave in the pool. - */ - protected int maxSpareThreads; - - /* - * Number of threads in the pool. - */ - protected int currentThreadCount; - - /* - * Number of busy threads in the pool. - */ - protected int currentThreadsBusy; - - /* - * Flag that the pool should terminate all the threads and stop. - */ - protected boolean stopThePool; - - /* Flag to control if the main thread is 'daemon' */ - protected boolean isDaemon=true; - - /** The threads that are part of the pool. - * Key is Thread, value is the ControlRunnable - */ - protected Hashtable threads=new Hashtable(); - - protected Vector listeners=new Vector(); - - /** Name of the threadpool - */ - protected String name = "TP"; - - /** - * Sequence. - */ - protected int sequence = 1; - - /** - * Thread priority. - */ - protected int threadPriority = Thread.NORM_PRIORITY; - - - /** - * Constructor. - */ - public ThreadPool() { - maxThreads = MAX_THREADS; - maxSpareThreads = MAX_SPARE_THREADS; - minSpareThreads = MIN_SPARE_THREADS; - currentThreadCount = 0; - currentThreadsBusy = 0; - stopThePool = false; - } - - - /** Create a ThreadPool instance. - * - * @param jmx UNUSED - * @return ThreadPool instance. If JMX support is requested, you need to - * call register() in order to set a name. - */ - public static ThreadPool createThreadPool(boolean jmx) { - return new ThreadPool(); - } - - public synchronized void start() { - stopThePool=false; - currentThreadCount = 0; - currentThreadsBusy = 0; - - adjustLimits(); - - pool = new ControlRunnable[maxThreads]; - - openThreads(minSpareThreads); - if (maxSpareThreads < maxThreads) { - monitor = new MonitorRunnable(this); - } - } - - public MonitorRunnable getMonitor() { - return monitor; - } - - /** - * Sets the thread priority for current - * and future threads in this pool. - * - * @param threadPriority The new priority - * @throws IllegalArgumentException If the specified - * priority is less than Thread.MIN_PRIORITY or - * more than Thread.MAX_PRIORITY - */ - public synchronized void setThreadPriority(int threadPriority) { - if(log.isDebugEnabled()) - log.debug(getClass().getName() + - ": setPriority(" + threadPriority + "): here."); - - if (threadPriority < Thread.MIN_PRIORITY) { - throw new IllegalArgumentException("new priority < MIN_PRIORITY"); - } else if (threadPriority > Thread.MAX_PRIORITY) { - throw new IllegalArgumentException("new priority > MAX_PRIORITY"); - } - - // Set for future threads - this.threadPriority = threadPriority; - - Enumeration currentThreads = getThreads(); - Thread t = null; - while(currentThreads.hasMoreElements()) { - t = (Thread) currentThreads.nextElement(); - t.setPriority(threadPriority); - } - } - - /** - * Returns the priority level of current and - * future threads in this pool. - * - * @return The priority - */ - public int getThreadPriority() { - return threadPriority; - } - - - public void setMaxThreads(int maxThreads) { - this.maxThreads = maxThreads; - } - - public int getMaxThreads() { - return maxThreads; - } - - public void setMinSpareThreads(int minSpareThreads) { - this.minSpareThreads = minSpareThreads; - } - - public int getMinSpareThreads() { - return minSpareThreads; - } - - public void setMaxSpareThreads(int maxSpareThreads) { - this.maxSpareThreads = maxSpareThreads; - } - - public int getMaxSpareThreads() { - return maxSpareThreads; - } - - public int getCurrentThreadCount() { - return currentThreadCount; - } - - public int getCurrentThreadsBusy() { - return currentThreadsBusy; - } - - public boolean isDaemon() { - return isDaemon; - } - - public static int getDebug() { - return 0; - } - - /** The default is true - the created threads will be - * in daemon mode. If set to false, the control thread - * will not be daemon - and will keep the process alive. - */ - public void setDaemon( boolean b ) { - isDaemon=b; - } - - public boolean getDaemon() { - return isDaemon; - } - - public void setName(String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public int getSequence() { - return sequence++; - } - - public void addThread( Thread t, ControlRunnable cr ) { - threads.put( t, cr ); - for( int i=0; i maxSpareThreads) { - int toFree = currentThreadCount - - currentThreadsBusy - - maxSpareThreads; - - for(int i = 0 ; i < toFree ; i++) { - ControlRunnable c = pool[currentThreadCount - currentThreadsBusy - 1]; - c.terminate(); - pool[currentThreadCount - currentThreadsBusy - 1] = null; - currentThreadCount --; - } - - } - - } - - /** - * Returns the thread to the pool. - * Called by threads as they are becoming idel. - */ - protected synchronized void returnController(ControlRunnable c) { - - if(0 == currentThreadCount || stopThePool) { - c.terminate(); - return; - } - - // atomic - currentThreadsBusy--; - - pool[currentThreadCount - currentThreadsBusy - 1] = c; - notify(); - } - - /** - * Inform the pool that the specific thread finish. - * - * Called by the ControlRunnable.run() when the runnable - * throws an exception. - */ - protected synchronized void notifyThreadEnd(ControlRunnable c) { - currentThreadsBusy--; - currentThreadCount --; - notify(); - } - - - /* - * Checks for problematic configuration and fix it. - * The fix provides reasonable settings for a single CPU - * with medium load. - */ - protected void adjustLimits() { - if(maxThreads <= 0) { - maxThreads = MAX_THREADS; - } else if (maxThreads < MAX_THREADS_MIN) { - log.warn(sm.getString("threadpool.max_threads_too_low", - new Integer(maxThreads), - new Integer(MAX_THREADS_MIN))); - maxThreads = MAX_THREADS_MIN; - } - - if(maxSpareThreads >= maxThreads) { - maxSpareThreads = maxThreads; - } - - if(maxSpareThreads <= 0) { - if(1 == maxThreads) { - maxSpareThreads = 1; - } else { - maxSpareThreads = maxThreads/2; - } - } - - if(minSpareThreads > maxSpareThreads) { - minSpareThreads = maxSpareThreads; - } - - if(minSpareThreads <= 0) { - if(1 == maxSpareThreads) { - minSpareThreads = 1; - } else { - minSpareThreads = maxSpareThreads/2; - } - } - } - - /** Create missing threads. - * - * @param toOpen Total number of threads we'll have open - */ - protected void openThreads(int toOpen) { - - if(toOpen > maxThreads) { - toOpen = maxThreads; - } - - for(int i = currentThreadCount ; i < toOpen ; i++) { - pool[i - currentThreadsBusy] = new ControlRunnable(this); - } - - currentThreadCount = toOpen; - } - - /** @deprecated */ - void log( String s ) { - log.info(s); - //loghelper.flush(); - } - - /** - * Periodically execute an action - cleanup in this case - */ - public static class MonitorRunnable implements Runnable { - ThreadPool p; - Thread t; - int interval=WORK_WAIT_TIMEOUT; - boolean shouldTerminate; - - MonitorRunnable(ThreadPool p) { - this.p=p; - this.start(); - } - - public void start() { - shouldTerminate = false; - t = new Thread(this); - t.setDaemon(p.getDaemon() ); - t.setName(p.getName() + "-Monitor"); - t.start(); - } - - public void setInterval(int i ) { - this.interval=i; - } - - public void run() { - while(true) { - try { - - // Sleep for a while. - synchronized(this) { - this.wait(interval); - } - - // Check if should terminate. - // termination happens when the pool is shutting down. - if(shouldTerminate) { - break; - } - - // Harvest idle threads. - p.checkSpareControllers(); - - } catch(Throwable t) { - ThreadPool.log.error("Unexpected exception", t); - } - } - } - - public void stop() { - this.terminate(); - } - - /** Stop the monitor - */ - public synchronized void terminate() { - shouldTerminate = true; - this.notify(); - } - } - - /** - * A Thread object that executes various actions ( ThreadPoolRunnable ) - * under control of ThreadPool - */ - public static class ControlRunnable implements Runnable { - /** - * ThreadPool where this thread will be returned - */ - private ThreadPool p; - - /** - * The thread that executes the actions - */ - private ThreadWithAttributes t; - - /** - * The method that is executed in this thread - */ - - private ThreadPoolRunnable toRun; - private Runnable toRunRunnable; - - /** - * Stop this thread - */ - private boolean shouldTerminate; - - /** - * Activate the execution of the action - */ - private boolean shouldRun; - - /** - * Per thread data - can be used only if all actions are - * of the same type. - * A better mechanism is possible ( that would allow association of - * thread data with action type ), but right now it's enough. - */ - private boolean noThData; - - /** - * Start a new thread, with no method in it - */ - ControlRunnable(ThreadPool p) { - toRun = null; - shouldTerminate = false; - shouldRun = false; - this.p = p; - t = new ThreadWithAttributes(p, this); - t.setDaemon(true); - t.setName(p.getName() + "-Processor" + p.getSequence()); - t.setPriority(p.getThreadPriority()); - p.addThread( t, this ); - noThData=true; - t.start(); - } - - public void run() { - boolean _shouldRun = false; - boolean _shouldTerminate = false; - ThreadPoolRunnable _toRun = null; - try { - while (true) { - try { - /* Wait for work. */ - synchronized (this) { - while (!shouldRun && !shouldTerminate) { - this.wait(); - } - _shouldRun = shouldRun; - _shouldTerminate = shouldTerminate; - _toRun = toRun; - } - - if (_shouldTerminate) { - if (ThreadPool.log.isDebugEnabled()) - ThreadPool.log.debug("Terminate"); - break; - } - - /* Check if should execute a runnable. */ - try { - if (noThData) { - if (_toRun != null) { - Object thData[] = _toRun.getInitData(); - t.setThreadData(p, thData); - if (ThreadPool.log.isDebugEnabled()) - ThreadPool.log.debug( - "Getting new thread data"); - } - noThData = false; - } - - if (_shouldRun) { - if (_toRun != null) { - _toRun.runIt(t.getThreadData(p)); - } else if (toRunRunnable != null) { - toRunRunnable.run(); - } else { - if (ThreadPool.log.isDebugEnabled()) - ThreadPool.log.debug("No toRun ???"); - } - } - } catch (Throwable t) { - ThreadPool.log.error(sm.getString - ("threadpool.thread_error", t, toRun.toString())); - /* - * The runnable throw an exception (can be even a ThreadDeath), - * signalling that the thread die. - * - * The meaning is that we should release the thread from - * the pool. - */ - _shouldTerminate = true; - _shouldRun = false; - p.notifyThreadEnd(this); - } finally { - if (_shouldRun) { - shouldRun = false; - /* - * Notify the pool that the thread is now idle. - */ - p.returnController(this); - } - } - - /* - * Check if should terminate. - * termination happens when the pool is shutting down. - */ - if (_shouldTerminate) { - break; - } - } catch (InterruptedException ie) { /* for the wait operation */ - // can never happen, since we don't call interrupt - ThreadPool.log.error("Unexpected exception", ie); - } - } - } finally { - p.removeThread(Thread.currentThread()); - } - } - /** Run a task - * - * @param toRun - */ - public synchronized void runIt(Runnable toRun) { - this.toRunRunnable = toRun; - // Do not re-init, the whole idea is to run init only once per - // thread - the pool is supposed to run a single task, that is - // initialized once. - // noThData = true; - shouldRun = true; - this.notify(); - } - - /** Run a task - * - * @param toRun - */ - public synchronized void runIt(ThreadPoolRunnable toRun) { - this.toRun = toRun; - // Do not re-init, the whole idea is to run init only once per - // thread - the pool is supposed to run a single task, that is - // initialized once. - // noThData = true; - shouldRun = true; - this.notify(); - } - - public void stop() { - this.terminate(); - } - - public void kill() { - t.stop(); - } - - public synchronized void terminate() { - shouldTerminate = true; - this.notify(); - } - } - - /** - * Debug display of the stage of each thread. The return is html style, - * for display in the console ( it can be easily parsed too ). - * - * @return The thread status display - */ - public String threadStatusString() { - StringBuffer sb=new StringBuffer(); - Iterator it=threads.keySet().iterator(); - sb.append("

          "); - while( it.hasNext()) { - sb.append("
        • "); - ThreadWithAttributes twa=(ThreadWithAttributes) - it.next(); - sb.append(twa.getCurrentStage(this) ).append(" "); - sb.append( twa.getParam(this)); - sb.append( "
        • \n"); - } - sb.append("
        "); - return sb.toString(); - } - - /** Return an array with the status of each thread. The status - * indicates the current request processing stage ( for tomcat ) or - * whatever the thread is doing ( if the application using TP provide - * this info ) - * - * @return The status of all threads - */ - public String[] getThreadStatus() { - String status[]=new String[ threads.size()]; - Iterator it=threads.keySet().iterator(); - for( int i=0; ( i + */ +public class ThreadPool { + + private static Log log = LogFactory.getLog(ThreadPool.class); + + private static StringManager sm = + StringManager.getManager("org.apache.tomcat.util.threads.res"); + + private static boolean logfull=true; + + /* + * Default values ... + */ + public static final int MAX_THREADS = 200; + public static final int MAX_THREADS_MIN = 10; + public static final int MAX_SPARE_THREADS = 50; + public static final int MIN_SPARE_THREADS = 4; + public static final int WORK_WAIT_TIMEOUT = 60*1000; + + /* + * Where the threads are held. + */ + protected ControlRunnable[] pool = null; + + /* + * A monitor thread that monitors the pool for idel threads. + */ + protected MonitorRunnable monitor; + + + /* + * Max number of threads that you can open in the pool. + */ + protected int maxThreads; + + /* + * Min number of idel threads that you can leave in the pool. + */ + protected int minSpareThreads; + + /* + * Max number of idel threads that you can leave in the pool. + */ + protected int maxSpareThreads; + + /* + * Number of threads in the pool. + */ + protected int currentThreadCount; + + /* + * Number of busy threads in the pool. + */ + protected int currentThreadsBusy; + + /* + * Flag that the pool should terminate all the threads and stop. + */ + protected boolean stopThePool; + + /* Flag to control if the main thread is 'daemon' */ + protected boolean isDaemon=true; + + /** The threads that are part of the pool. + * Key is Thread, value is the ControlRunnable + */ + protected Hashtable threads=new Hashtable(); + + protected Vector listeners=new Vector(); + + /** Name of the threadpool + */ + protected String name = "TP"; + + /** + * Sequence. + */ + protected int sequence = 1; + + /** + * Thread priority. + */ + protected int threadPriority = Thread.NORM_PRIORITY; + + + /** + * Constructor. + */ + public ThreadPool() { + maxThreads = MAX_THREADS; + maxSpareThreads = MAX_SPARE_THREADS; + minSpareThreads = MIN_SPARE_THREADS; + currentThreadCount = 0; + currentThreadsBusy = 0; + stopThePool = false; + } + + + /** Create a ThreadPool instance. + * + * @param jmx UNUSED + * @return ThreadPool instance. If JMX support is requested, you need to + * call register() in order to set a name. + */ + public static ThreadPool createThreadPool(boolean jmx) { + return new ThreadPool(); + } + + public synchronized void start() { + stopThePool=false; + currentThreadCount = 0; + currentThreadsBusy = 0; + + adjustLimits(); + + pool = new ControlRunnable[maxThreads]; + + openThreads(minSpareThreads); + if (maxSpareThreads < maxThreads) { + monitor = new MonitorRunnable(this); + } + } + + public MonitorRunnable getMonitor() { + return monitor; + } + + /** + * Sets the thread priority for current + * and future threads in this pool. + * + * @param threadPriority The new priority + * @throws IllegalArgumentException If the specified + * priority is less than Thread.MIN_PRIORITY or + * more than Thread.MAX_PRIORITY + */ + public synchronized void setThreadPriority(int threadPriority) { + if(log.isDebugEnabled()) + log.debug(getClass().getName() + + ": setPriority(" + threadPriority + "): here."); + + if (threadPriority < Thread.MIN_PRIORITY) { + throw new IllegalArgumentException("new priority < MIN_PRIORITY"); + } else if (threadPriority > Thread.MAX_PRIORITY) { + throw new IllegalArgumentException("new priority > MAX_PRIORITY"); + } + + // Set for future threads + this.threadPriority = threadPriority; + + Enumeration currentThreads = getThreads(); + Thread t = null; + while(currentThreads.hasMoreElements()) { + t = (Thread) currentThreads.nextElement(); + t.setPriority(threadPriority); + } + } + + /** + * Returns the priority level of current and + * future threads in this pool. + * + * @return The priority + */ + public int getThreadPriority() { + return threadPriority; + } + + + public void setMaxThreads(int maxThreads) { + this.maxThreads = maxThreads; + } + + public int getMaxThreads() { + return maxThreads; + } + + public void setMinSpareThreads(int minSpareThreads) { + this.minSpareThreads = minSpareThreads; + } + + public int getMinSpareThreads() { + return minSpareThreads; + } + + public void setMaxSpareThreads(int maxSpareThreads) { + this.maxSpareThreads = maxSpareThreads; + } + + public int getMaxSpareThreads() { + return maxSpareThreads; + } + + public int getCurrentThreadCount() { + return currentThreadCount; + } + + public int getCurrentThreadsBusy() { + return currentThreadsBusy; + } + + public boolean isDaemon() { + return isDaemon; + } + + public static int getDebug() { + return 0; + } + + /** The default is true - the created threads will be + * in daemon mode. If set to false, the control thread + * will not be daemon - and will keep the process alive. + */ + public void setDaemon( boolean b ) { + isDaemon=b; + } + + public boolean getDaemon() { + return isDaemon; + } + + public void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public int getSequence() { + return sequence++; + } + + public void addThread( Thread t, ControlRunnable cr ) { + threads.put( t, cr ); + for( int i=0; i maxSpareThreads) { + int toFree = currentThreadCount - + currentThreadsBusy - + maxSpareThreads; + + for(int i = 0 ; i < toFree ; i++) { + ControlRunnable c = pool[currentThreadCount - currentThreadsBusy - 1]; + c.terminate(); + pool[currentThreadCount - currentThreadsBusy - 1] = null; + currentThreadCount --; + } + + } + + } + + /** + * Returns the thread to the pool. + * Called by threads as they are becoming idel. + */ + protected synchronized void returnController(ControlRunnable c) { + + if(0 == currentThreadCount || stopThePool) { + c.terminate(); + return; + } + + // atomic + currentThreadsBusy--; + + pool[currentThreadCount - currentThreadsBusy - 1] = c; + notify(); + } + + /** + * Inform the pool that the specific thread finish. + * + * Called by the ControlRunnable.run() when the runnable + * throws an exception. + */ + protected synchronized void notifyThreadEnd(ControlRunnable c) { + currentThreadsBusy--; + currentThreadCount --; + notify(); + } + + + /* + * Checks for problematic configuration and fix it. + * The fix provides reasonable settings for a single CPU + * with medium load. + */ + protected void adjustLimits() { + if(maxThreads <= 0) { + maxThreads = MAX_THREADS; + } else if (maxThreads < MAX_THREADS_MIN) { + log.warn(sm.getString("threadpool.max_threads_too_low", + new Integer(maxThreads), + new Integer(MAX_THREADS_MIN))); + maxThreads = MAX_THREADS_MIN; + } + + if(maxSpareThreads >= maxThreads) { + maxSpareThreads = maxThreads; + } + + if(maxSpareThreads <= 0) { + if(1 == maxThreads) { + maxSpareThreads = 1; + } else { + maxSpareThreads = maxThreads/2; + } + } + + if(minSpareThreads > maxSpareThreads) { + minSpareThreads = maxSpareThreads; + } + + if(minSpareThreads <= 0) { + if(1 == maxSpareThreads) { + minSpareThreads = 1; + } else { + minSpareThreads = maxSpareThreads/2; + } + } + } + + /** Create missing threads. + * + * @param toOpen Total number of threads we'll have open + */ + protected void openThreads(int toOpen) { + + if(toOpen > maxThreads) { + toOpen = maxThreads; + } + + for(int i = currentThreadCount ; i < toOpen ; i++) { + pool[i - currentThreadsBusy] = new ControlRunnable(this); + } + + currentThreadCount = toOpen; + } + + /** @deprecated */ + void log( String s ) { + log.info(s); + //loghelper.flush(); + } + + /** + * Periodically execute an action - cleanup in this case + */ + public static class MonitorRunnable implements Runnable { + ThreadPool p; + Thread t; + int interval=WORK_WAIT_TIMEOUT; + boolean shouldTerminate; + + MonitorRunnable(ThreadPool p) { + this.p=p; + this.start(); + } + + public void start() { + shouldTerminate = false; + t = new Thread(this); + t.setDaemon(p.getDaemon() ); + t.setName(p.getName() + "-Monitor"); + t.start(); + } + + public void setInterval(int i ) { + this.interval=i; + } + + public void run() { + while(true) { + try { + + // Sleep for a while. + synchronized(this) { + this.wait(interval); + } + + // Check if should terminate. + // termination happens when the pool is shutting down. + if(shouldTerminate) { + break; + } + + // Harvest idle threads. + p.checkSpareControllers(); + + } catch(Throwable t) { + ThreadPool.log.error("Unexpected exception", t); + } + } + } + + public void stop() { + this.terminate(); + } + + /** Stop the monitor + */ + public synchronized void terminate() { + shouldTerminate = true; + this.notify(); + } + } + + /** + * A Thread object that executes various actions ( ThreadPoolRunnable ) + * under control of ThreadPool + */ + public static class ControlRunnable implements Runnable { + /** + * ThreadPool where this thread will be returned + */ + private ThreadPool p; + + /** + * The thread that executes the actions + */ + private ThreadWithAttributes t; + + /** + * The method that is executed in this thread + */ + + private ThreadPoolRunnable toRun; + private Runnable toRunRunnable; + + /** + * Stop this thread + */ + private boolean shouldTerminate; + + /** + * Activate the execution of the action + */ + private boolean shouldRun; + + /** + * Per thread data - can be used only if all actions are + * of the same type. + * A better mechanism is possible ( that would allow association of + * thread data with action type ), but right now it's enough. + */ + private boolean noThData; + + /** + * Start a new thread, with no method in it + */ + ControlRunnable(ThreadPool p) { + toRun = null; + shouldTerminate = false; + shouldRun = false; + this.p = p; + t = new ThreadWithAttributes(p, this); + t.setDaemon(true); + t.setName(p.getName() + "-Processor" + p.getSequence()); + t.setPriority(p.getThreadPriority()); + p.addThread( t, this ); + noThData=true; + t.start(); + } + + public void run() { + boolean _shouldRun = false; + boolean _shouldTerminate = false; + ThreadPoolRunnable _toRun = null; + try { + while (true) { + try { + /* Wait for work. */ + synchronized (this) { + while (!shouldRun && !shouldTerminate) { + this.wait(); + } + _shouldRun = shouldRun; + _shouldTerminate = shouldTerminate; + _toRun = toRun; + } + + if (_shouldTerminate) { + if (ThreadPool.log.isDebugEnabled()) + ThreadPool.log.debug("Terminate"); + break; + } + + /* Check if should execute a runnable. */ + try { + if (noThData) { + if (_toRun != null) { + Object thData[] = _toRun.getInitData(); + t.setThreadData(p, thData); + if (ThreadPool.log.isDebugEnabled()) + ThreadPool.log.debug( + "Getting new thread data"); + } + noThData = false; + } + + if (_shouldRun) { + if (_toRun != null) { + _toRun.runIt(t.getThreadData(p)); + } else if (toRunRunnable != null) { + toRunRunnable.run(); + } else { + if (ThreadPool.log.isDebugEnabled()) + ThreadPool.log.debug("No toRun ???"); + } + } + } catch (Throwable t) { + ThreadPool.log.error(sm.getString + ("threadpool.thread_error", t, toRun.toString())); + /* + * The runnable throw an exception (can be even a ThreadDeath), + * signalling that the thread die. + * + * The meaning is that we should release the thread from + * the pool. + */ + _shouldTerminate = true; + _shouldRun = false; + p.notifyThreadEnd(this); + } finally { + if (_shouldRun) { + shouldRun = false; + /* + * Notify the pool that the thread is now idle. + */ + p.returnController(this); + } + } + + /* + * Check if should terminate. + * termination happens when the pool is shutting down. + */ + if (_shouldTerminate) { + break; + } + } catch (InterruptedException ie) { /* for the wait operation */ + // can never happen, since we don't call interrupt + ThreadPool.log.error("Unexpected exception", ie); + } + } + } finally { + p.removeThread(Thread.currentThread()); + } + } + /** Run a task + * + * @param toRun + */ + public synchronized void runIt(Runnable toRun) { + this.toRunRunnable = toRun; + // Do not re-init, the whole idea is to run init only once per + // thread - the pool is supposed to run a single task, that is + // initialized once. + // noThData = true; + shouldRun = true; + this.notify(); + } + + /** Run a task + * + * @param toRun + */ + public synchronized void runIt(ThreadPoolRunnable toRun) { + this.toRun = toRun; + // Do not re-init, the whole idea is to run init only once per + // thread - the pool is supposed to run a single task, that is + // initialized once. + // noThData = true; + shouldRun = true; + this.notify(); + } + + public void stop() { + this.terminate(); + } + + public void kill() { + t.stop(); + } + + public synchronized void terminate() { + shouldTerminate = true; + this.notify(); + } + } + + /** + * Debug display of the stage of each thread. The return is html style, + * for display in the console ( it can be easily parsed too ). + * + * @return The thread status display + */ + public String threadStatusString() { + StringBuffer sb=new StringBuffer(); + Iterator it=threads.keySet().iterator(); + sb.append("
          "); + while( it.hasNext()) { + sb.append("
        • "); + ThreadWithAttributes twa=(ThreadWithAttributes) + it.next(); + sb.append(twa.getCurrentStage(this) ).append(" "); + sb.append( twa.getParam(this)); + sb.append( "
        • \n"); + } + sb.append("
        "); + return sb.toString(); + } + + /** Return an array with the status of each thread. The status + * indicates the current request processing stage ( for tomcat ) or + * whatever the thread is doing ( if the application using TP provide + * this info ) + * + * @return The status of all threads + */ + public String[] getThreadStatus() { + String status[]=new String[ threads.size()]; + Iterator it=threads.keySet().iterator(); + for( int i=0; ( i object ), - // expensive. - - /** Called when this object is first loaded in the thread pool. - * Important: all workers in a pool must be of the same type, - * otherwise the mechanism becomes more complex. - */ - public Object[] getInitData(); - - /** This method will be executed in one of the pool's threads. The - * thread will be returned to the pool. - */ - public void runIt(Object thData[]); - -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.threads; + + +/** Implemented if you want to run a piece of code inside a thread pool. + */ +public interface ThreadPoolRunnable { + // XXX use notes or a hashtable-like + // Important: ThreadData in JDK1.2 is implemented as a Hashtable( Thread -> object ), + // expensive. + + /** Called when this object is first loaded in the thread pool. + * Important: all workers in a pool must be of the same type, + * otherwise the mechanism becomes more complex. + */ + public Object[] getInitData(); + + /** This method will be executed in one of the pool's threads. The + * thread will be returned to the pool. + */ + public void runIt(Object thData[]); + +} diff --git a/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java b/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java index 4408c9407..87e749df5 100644 --- a/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java +++ b/java/org/apache/tomcat/util/threads/ThreadWithAttributes.java @@ -1,100 +1,100 @@ -/* - * Copyright 1999-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.apache.tomcat.util.threads; - -import java.util.Hashtable; - -/** Special thread that allows storing of attributes and notes. - * A guard is used to prevent untrusted code from accessing the - * attributes. - * - * This avoids hash lookups and provide something very similar - * with ThreadLocal ( but compatible with JDK1.1 and faster on - * JDK < 1.4 ). - * - * The main use is to store 'state' for monitoring ( like "processing - * request 'GET /' "). - */ -public class ThreadWithAttributes extends Thread { - - private Object control; - public static int MAX_NOTES=16; - private Object notes[]=new Object[MAX_NOTES]; - private Hashtable attributes=new Hashtable(); - private String currentStage; - private Object param; - - private Object thData[]; - - public ThreadWithAttributes(Object control, Runnable r) { - super(r); - this.control=control; - } - - public final Object[] getThreadData(Object control ) { - return thData; - } - - public final void setThreadData(Object control, Object thData[] ) { - this.thData=thData; - } - - /** Notes - for attributes that need fast access ( array ) - * The application is responsible for id management - */ - public final void setNote( Object control, int id, Object value ) { - if( this.control != control ) return; - notes[id]=value; - } - - /** Information about the curent performed operation - */ - public final String getCurrentStage(Object control) { - if( this.control != control ) return null; - return currentStage; - } - - /** Information about the current request ( or the main object - * we are processing ) - */ - public final Object getParam(Object control) { - if( this.control != control ) return null; - return param; - } - - public final void setCurrentStage(Object control, String currentStage) { - if( this.control != control ) return; - this.currentStage = currentStage; - } - - public final void setParam( Object control, Object param ) { - if( this.control != control ) return; - this.param=param; - } - - public final Object getNote(Object control, int id ) { - if( this.control != control ) return null; - return notes[id]; - } - - /** Generic attributes. You'll need a hashtable lookup - - * you can use notes for array access. - */ - public final Hashtable getAttributes(Object control) { - return attributes; - } -} +/* + * Copyright 1999-2004 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.tomcat.util.threads; + +import java.util.Hashtable; + +/** Special thread that allows storing of attributes and notes. + * A guard is used to prevent untrusted code from accessing the + * attributes. + * + * This avoids hash lookups and provide something very similar + * with ThreadLocal ( but compatible with JDK1.1 and faster on + * JDK < 1.4 ). + * + * The main use is to store 'state' for monitoring ( like "processing + * request 'GET /' "). + */ +public class ThreadWithAttributes extends Thread { + + private Object control; + public static int MAX_NOTES=16; + private Object notes[]=new Object[MAX_NOTES]; + private Hashtable attributes=new Hashtable(); + private String currentStage; + private Object param; + + private Object thData[]; + + public ThreadWithAttributes(Object control, Runnable r) { + super(r); + this.control=control; + } + + public final Object[] getThreadData(Object control ) { + return thData; + } + + public final void setThreadData(Object control, Object thData[] ) { + this.thData=thData; + } + + /** Notes - for attributes that need fast access ( array ) + * The application is responsible for id management + */ + public final void setNote( Object control, int id, Object value ) { + if( this.control != control ) return; + notes[id]=value; + } + + /** Information about the curent performed operation + */ + public final String getCurrentStage(Object control) { + if( this.control != control ) return null; + return currentStage; + } + + /** Information about the current request ( or the main object + * we are processing ) + */ + public final Object getParam(Object control) { + if( this.control != control ) return null; + return param; + } + + public final void setCurrentStage(Object control, String currentStage) { + if( this.control != control ) return; + this.currentStage = currentStage; + } + + public final void setParam( Object control, Object param ) { + if( this.control != control ) return; + this.param=param; + } + + public final Object getNote(Object control, int id ) { + if( this.control != control ) return null; + return notes[id]; + } + + /** Generic attributes. You'll need a hashtable lookup - + * you can use notes for array access. + */ + public final Hashtable getAttributes(Object control) { + return attributes; + } +} diff --git a/java/org/apache/tomcat/util/threads/res/LocalStrings.properties b/java/org/apache/tomcat/util/threads/res/LocalStrings.properties index d4d5d7dcb..ede656176 100644 --- a/java/org/apache/tomcat/util/threads/res/LocalStrings.properties +++ b/java/org/apache/tomcat/util/threads/res/LocalStrings.properties @@ -1,3 +1,3 @@ -threadpool.busy=All threads ({0}) are currently busy, waiting. Increase maxThreads ({1}) or check the servlet status -threadpool.max_threads_too_low=maxThreads setting ({0}) too low, set to {1} -threadpool.thread_error=Caught exception ({0}) executing {1}, terminating thread +threadpool.busy=All threads ({0}) are currently busy, waiting. Increase maxThreads ({1}) or check the servlet status +threadpool.max_threads_too_low=maxThreads setting ({0}) too low, set to {1} +threadpool.thread_error=Caught exception ({0}) executing {1}, terminating thread diff --git a/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties b/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties index d80ee2023..400471422 100644 --- a/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties +++ b/java/org/apache/tomcat/util/threads/res/LocalStrings_es.properties @@ -1,3 +1,3 @@ -threadpool.busy=Todos los hilos ({0}) están ahora ocupados, esperando. Incremente maxThreads ({1}) o revise el estado del servlet -threadpool.max_threads_too_low=valor de maxThreads ({0}) demasiado bajo, puesto a {1} -threadpool.thread_error=Cogida excepción ({0}) ejecutando {1}, terminando hilo +threadpool.busy=Todos los hilos ({0}) están ahora ocupados, esperando. Incremente maxThreads ({1}) o revise el estado del servlet +threadpool.max_threads_too_low=valor de maxThreads ({0}) demasiado bajo, puesto a {1} +threadpool.thread_error=Cogida excepción ({0}) ejecutando {1}, terminando hilo diff --git a/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties b/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties index 9c178d197..7a144d979 100644 --- a/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties +++ b/java/org/apache/tomcat/util/threads/res/LocalStrings_fr.properties @@ -1,3 +1,3 @@ -threadpool.busy=Tous les threads ({0}) sont actuellement occupés, attente. Augmentez maxThreads ({1}) ou vérifiez le servlet status -threadpool.max_threads_too_low=le réglage maxThreads ({0}) est trop bas, mis à {1} -threadpool.thread_error=Réception d''une exception ({0}) en exécutant {1}, arrêt du thread +threadpool.busy=Tous les threads ({0}) sont actuellement occupés, attente. Augmentez maxThreads ({1}) ou vérifiez le servlet status +threadpool.max_threads_too_low=le réglage maxThreads ({0}) est trop bas, mis à {1} +threadpool.thread_error=Réception d''une exception ({0}) en exécutant {1}, arrêt du thread diff --git a/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties b/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties index c37af3030..ffff30ed4 100644 --- a/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties +++ b/java/org/apache/tomcat/util/threads/res/LocalStrings_ja.properties @@ -1,3 +1,3 @@ -threadpool.busy=\u3059\u3079\u3066\u306e\u30b9\u30ec\u30c3\u30c9 ({0}) \u304c\u73fe\u5728\u7a3c\u50cd\u4e2d\u3067\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059\u3002maxThreads ({1}) \u3092\u5897\u3084\u3059\u304b\u3001\u305d\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u30c1\u30a7\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044 -threadpool.max_threads_too_low=maxThreads\u306e\u8a2d\u5b9a ({0}) \u304c\u5c0f\u3055\u3059\u304e\u308b\u306e\u3067\u3001{1}\u306b\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044 -threadpool.thread_error={1} \u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916 ({0}) \u3092\u30ad\u30e3\u30c3\u30c1\u3057\u305f\u306e\u3067\u3001\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3057\u307e\u3059 +threadpool.busy=\u3059\u3079\u3066\u306e\u30b9\u30ec\u30c3\u30c9 ({0}) \u304c\u73fe\u5728\u7a3c\u50cd\u4e2d\u3067\u5f85\u6a5f\u3057\u3066\u3044\u307e\u3059\u3002maxThreads ({1}) \u3092\u5897\u3084\u3059\u304b\u3001\u305d\u306e\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8\u306e\u30b9\u30c6\u30fc\u30bf\u30b9\u3092\u30c1\u30a7\u30c3\u30af\u3057\u3066\u304f\u3060\u3055\u3044 +threadpool.max_threads_too_low=maxThreads\u306e\u8a2d\u5b9a ({0}) \u304c\u5c0f\u3055\u3059\u304e\u308b\u306e\u3067\u3001{1}\u306b\u8a2d\u5b9a\u3057\u3066\u304f\u3060\u3055\u3044 +threadpool.thread_error={1} \u3092\u5b9f\u884c\u4e2d\u306b\u4f8b\u5916 ({0}) \u3092\u30ad\u30e3\u30c3\u30c1\u3057\u305f\u306e\u3067\u3001\u30b9\u30ec\u30c3\u30c9\u3092\u7d42\u4e86\u3057\u307e\u3059 diff --git a/webapps/ROOT/WEB-INF/web.xml b/webapps/ROOT/WEB-INF/web.xml index 1bde9a52f..879ec87fb 100644 --- a/webapps/ROOT/WEB-INF/web.xml +++ b/webapps/ROOT/WEB-INF/web.xml @@ -1,28 +1,28 @@ - - - - - - Welcome to Tomcat - - Welcome to Tomcat - - - + + + + + + Welcome to Tomcat + + Welcome to Tomcat + + + diff --git a/webapps/ROOT/index.html b/webapps/ROOT/index.html index e62393908..503d9b620 100644 --- a/webapps/ROOT/index.html +++ b/webapps/ROOT/index.html @@ -1,198 +1,198 @@ - - - - - Apache Tomcat - - - - - - - - - - - - - - - - - - - - - - - - - - -
        - - - - - - - -
        Administration
        - -
        - - - - - - - -
        Documentation
        - -
        - - - - - - - -
        Tomcat Online
        - -
        - - - - - - - -
        Miscellaneous
        -
          -

        If you're seeing this page via a web browser, it means you've setup Tomcat successfully. Congratulations!

        - -

        As you may have guessed by now, this is the default Tomcat home page. It can be found on the local filesystem at:

        -

        $CATALINA_HOME/webapps/ROOT/index.html

        - -

        where "$CATALINA_HOME" is the root of the Tomcat installation directory. If you're seeing this page, and you don't think you should be, then either you're either a user who has arrived at new installation of Tomcat, or you're an administrator who hasn't got his/her setup quite right. Providing the latter is the case, please refer to the Tomcat Documentation for more detailed setup and administration information than is found in the INSTALL file.

        - -

        NOTE: For security reasons, using the administration webapp - is restricted to users with role "admin". The manager webapp - is restricted to users with role "manager". - Users are defined in $CATALINA_HOME/conf/tomcat-users.xml.

        - -

        Included with this release are a host of sample Servlets and JSPs (with associated source code), extensive documentation (including the Servlet 2.4 and JSP 2.0 API JavaDoc), and an introductory guide to developing web applications.

        - -

        Tomcat mailing lists are available at the Tomcat project web site:

        - - - -

        Thanks for using Tomcat!

        - - -
        - - - + + + + + Apache Tomcat + + + + + + + + + + + + + + + + + + + + + + + + + + +
        + + + + + + + +
        Administration
        + +
        + + + + + + + +
        Documentation
        + +
        + + + + + + + +
        Tomcat Online
        + +
        + + + + + + + +
        Miscellaneous
        +
          +

        If you're seeing this page via a web browser, it means you've setup Tomcat successfully. Congratulations!

        + +

        As you may have guessed by now, this is the default Tomcat home page. It can be found on the local filesystem at:

        +

        $CATALINA_HOME/webapps/ROOT/index.html

        + +

        where "$CATALINA_HOME" is the root of the Tomcat installation directory. If you're seeing this page, and you don't think you should be, then either you're either a user who has arrived at new installation of Tomcat, or you're an administrator who hasn't got his/her setup quite right. Providing the latter is the case, please refer to the Tomcat Documentation for more detailed setup and administration information than is found in the INSTALL file.

        + +

        NOTE: For security reasons, using the administration webapp + is restricted to users with role "admin". The manager webapp + is restricted to users with role "manager". + Users are defined in $CATALINA_HOME/conf/tomcat-users.xml.

        + +

        Included with this release are a host of sample Servlets and JSPs (with associated source code), extensive documentation (including the Servlet 2.4 and JSP 2.0 API JavaDoc), and an introductory guide to developing web applications.

        + +

        Tomcat mailing lists are available at the Tomcat project web site:

        + + + +

        Thanks for using Tomcat!

        + + +
        + + + diff --git a/webapps/examples/jsp/jsp2/jspx/basic.jspx b/webapps/examples/jsp/jsp2/jspx/basic.jspx index 75394fcbf..8a2f35b17 100644 --- a/webapps/examples/jsp/jsp2/jspx/basic.jspx +++ b/webapps/examples/jsp/jsp2/jspx/basic.jspx @@ -1,30 +1,30 @@ - - - - JSPX - XHTML Basic Example - - -

        JSPX - XHTML Basic Example

        -
        - This example illustrates how to use JSPX to produce an XHTML basic - document suitable for use with mobile phones, televisions, - PDAs, vending machines, pagers, car navigation systems, - mobile game machines, digital book readers, smart watches, etc. -

        - JSPX lets you create dynamic documents in a pure XML syntax compatible - with existing XML tools. The XML syntax in JSP 1.2 was awkward and - required &lt;jsp:root&gt; to be the root element of the document. - This is no longer the case in JSP 2.0. -

        - This particular example uses a tag file to produce the DOCTYPE and - namespace declarations to make the output of this page a valid XHTML - Basic document. -

        - Just to prove this is live, here's some dynamic content: - - - - + + + + JSPX - XHTML Basic Example + + +

        JSPX - XHTML Basic Example

        +
        + This example illustrates how to use JSPX to produce an XHTML basic + document suitable for use with mobile phones, televisions, + PDAs, vending machines, pagers, car navigation systems, + mobile game machines, digital book readers, smart watches, etc. +

        + JSPX lets you create dynamic documents in a pure XML syntax compatible + with existing XML tools. The XML syntax in JSP 1.2 was awkward and + required &lt;jsp:root&gt; to be the root element of the document. + This is no longer the case in JSP 2.0. +

        + This particular example uses a tag file to produce the DOCTYPE and + namespace declarations to make the output of this page a valid XHTML + Basic document. +

        + Just to prove this is live, here's some dynamic content: + + + + diff --git a/webapps/examples/jsp/jsp2/jspx/textRotate.jspx b/webapps/examples/jsp/jsp2/jspx/textRotate.jspx index 1d2c3e3ac..08f58903d 100644 --- a/webapps/examples/jsp/jsp2/jspx/textRotate.jspx +++ b/webapps/examples/jsp/jsp2/jspx/textRotate.jspx @@ -1,36 +1,36 @@ - - - - JSP 2.0 JSPX - - - - - JSP 2.0 XML Syntax (.jspx) Demo - - Try changing the name parameter! - - - - <g opacity="0.95" transform="scale(1.05) rotate(15)"> - - ${name} - - - </g> - - ${name} - - - + + + + JSP 2.0 JSPX + + + + + JSP 2.0 XML Syntax (.jspx) Demo + + Try changing the name parameter! + + + + <g opacity="0.95" transform="scale(1.05) rotate(15)"> + + ${name} + + + </g> + + ${name} + + + diff --git a/webapps/examples/jsp/jsp2/misc/coda.jspf b/webapps/examples/jsp/jsp2/misc/coda.jspf index edbf9e983..31faec358 100644 --- a/webapps/examples/jsp/jsp2/misc/coda.jspf +++ b/webapps/examples/jsp/jsp2/misc/coda.jspf @@ -1,5 +1,5 @@ -


        -
        -This banner included with <include-coda> -
        -
        +
        +
        +This banner included with <include-coda> +
        +
        diff --git a/webapps/examples/jsp/jsp2/misc/prelude.jspf b/webapps/examples/jsp/jsp2/misc/prelude.jspf index 1ff2be7a7..e30a8d883 100644 --- a/webapps/examples/jsp/jsp2/misc/prelude.jspf +++ b/webapps/examples/jsp/jsp2/misc/prelude.jspf @@ -1,5 +1,5 @@ -
        -
        -This banner included with <include-prelude> -
        -
        +
        +
        +This banner included with <include-prelude> +
        +
        -- 2.11.0